From b3ce4470ae2ece0c03c66684ca3d9dd13955786b Mon Sep 17 00:00:00 2001 From: "Jonas M. Gastal" Date: Thu, 22 Dec 2011 17:42:49 -0200 Subject: Removing QHttp class, its tests and its usage in examples. Task-number: QTBUG-22750 Change-Id: I161fad772bfb26797e6ee9d69da925b6747c371f Reviewed-by: Lars Knoll --- dist/changes-5.0.0 | 4 + examples/network/torrent/trackerclient.cpp | 37 +- examples/network/torrent/trackerclient.h | 13 +- src/network/access/access.pri | 4 +- src/network/access/qhttp.cpp | 3150 -------------------- src/network/access/qhttp.h | 311 -- src/network/access/qhttpheader.cpp | 770 +++++ src/network/access/qhttpheader_p.h | 147 + src/network/access/qhttpnetworkconnection.cpp | 1 - src/network/kernel/qauthenticator.cpp | 2 +- src/network/socket/qhttpsocketengine.cpp | 2 +- src/tools/uic/qclass_lib_map.h | 6 +- tests/auto/network/access/access.pro | 1 - tests/auto/network/access/qhttp/.gitattributes | 1 - tests/auto/network/access/qhttp/.gitignore | 1 - tests/auto/network/access/qhttp/dummyserver.h | 114 - tests/auto/network/access/qhttp/qhttp.pro | 23 - tests/auto/network/access/qhttp/rfc3252.txt | 899 ------ tests/auto/network/access/qhttp/testhtml | 8 - tests/auto/network/access/qhttp/tst_qhttp.cpp | 1565 ---------- .../qhttp/webserver/cgi-bin/retrieve_testfile.cgi | 6 - .../network/access/qhttp/webserver/cgi-bin/rfc.cgi | 5 - .../qhttp/webserver/cgi-bin/store_testfile.cgi | 6 - .../auto/network/access/qhttp/webserver/index.html | 899 ------ tests/auto/network/access/qhttp/webserver/rfc3252 | 899 ------ .../network/access/qhttp/webserver/rfc3252.txt | 899 ------ .../qhttpsocketengine/tst_qhttpsocketengine.cpp | 1 - .../tst_qsocks5socketengine.cpp | 1 - .../sax/qxmlinputsource/tst_qxmlinputsource.cpp | 63 +- 29 files changed, 999 insertions(+), 8839 deletions(-) delete mode 100644 src/network/access/qhttp.cpp delete mode 100644 src/network/access/qhttp.h create mode 100644 src/network/access/qhttpheader.cpp create mode 100644 src/network/access/qhttpheader_p.h delete mode 100644 tests/auto/network/access/qhttp/.gitattributes delete mode 100644 tests/auto/network/access/qhttp/.gitignore delete mode 100644 tests/auto/network/access/qhttp/dummyserver.h delete mode 100644 tests/auto/network/access/qhttp/qhttp.pro delete mode 100644 tests/auto/network/access/qhttp/rfc3252.txt delete mode 100644 tests/auto/network/access/qhttp/testhtml delete mode 100644 tests/auto/network/access/qhttp/tst_qhttp.cpp delete mode 100755 tests/auto/network/access/qhttp/webserver/cgi-bin/retrieve_testfile.cgi delete mode 100755 tests/auto/network/access/qhttp/webserver/cgi-bin/rfc.cgi delete mode 100755 tests/auto/network/access/qhttp/webserver/cgi-bin/store_testfile.cgi delete mode 100644 tests/auto/network/access/qhttp/webserver/index.html delete mode 100644 tests/auto/network/access/qhttp/webserver/rfc3252 delete mode 100644 tests/auto/network/access/qhttp/webserver/rfc3252.txt diff --git a/dist/changes-5.0.0 b/dist/changes-5.0.0 index e567021aa2..8855aa3852 100644 --- a/dist/changes-5.0.0 +++ b/dist/changes-5.0.0 @@ -141,6 +141,10 @@ information about a particular change. * Removed implicit conversion operator QUuid::operator QString(), instead QUuid::toString() function should be used. +- The QHttp, QHttpHeader, QHttpResponseHeader and QHttpRequestHeader classes have + been removed, QNetworkAccessManager should be used instead. + + **************************************************************************** * General * **************************************************************************** diff --git a/examples/network/torrent/trackerclient.cpp b/examples/network/torrent/trackerclient.cpp index c8525e983f..43c60ac9bd 100644 --- a/examples/network/torrent/trackerclient.cpp +++ b/examples/network/torrent/trackerclient.cpp @@ -45,6 +45,7 @@ #include "trackerclient.h" #include +#include TrackerClient::TrackerClient(TorrentClient *downloader, QObject *parent) : QObject(parent), torrentDownloader(downloader) @@ -56,7 +57,7 @@ TrackerClient::TrackerClient(TorrentClient *downloader, QObject *parent) lastTrackerRequest = false; firstSeeding = true; - connect(&http, SIGNAL(done(bool)), this, SLOT(httpRequestDone(bool))); + connect(&http, SIGNAL(finished(QNetworkReply*)), this, SLOT(httpRequestDone(QNetworkReply*))); } void TrackerClient::start(const MetaInfo &info) @@ -82,15 +83,13 @@ void TrackerClient::startSeeding() void TrackerClient::stop() { lastTrackerRequest = true; - http.abort(); fetchPeerList(); } void TrackerClient::timerEvent(QTimerEvent *event) { if (event->timerId() == requestIntervalTimer) { - if (http.state() == QHttp::Unconnected) - fetchPeerList(); + fetchPeerList(); } else { QObject::timerEvent(event); } @@ -148,32 +147,35 @@ void TrackerClient::fetchPeerList() if (!trackerId.isEmpty()) query += "&trackerid=" + trackerId; - http.setHost(url.host(), url.port() == -1 ? 80 : url.port()); - if (!url.userName().isEmpty()) - http.setUser(url.userName(), url.password()); - http.get(query); + QNetworkRequest req(url); + if (!url.userName().isEmpty()) { + uname = url.userName(); + pwd = url.password(); + connect(&http, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)), this, SLOT(provideAuthentication(QNetworkReply*,QAuthenticator*))); + } + http.get(req); } -void TrackerClient::httpRequestDone(bool error) +void TrackerClient::httpRequestDone(QNetworkReply *reply) { + reply->deleteLater(); if (lastTrackerRequest) { emit stopped(); return; } - if (error) { - emit connectionError(http.error()); + if (reply->error() != QNetworkReply::NoError) { + emit connectionError(reply->error()); return; } - QByteArray response = http.readAll(); - http.abort(); + QByteArray response = reply->readAll(); + reply->abort(); BencodeParser parser; if (!parser.parse(response)) { qWarning("Error parsing bencode response from tracker: %s", qPrintable(parser.errorString())); - http.abort(); return; } @@ -234,3 +236,10 @@ void TrackerClient::httpRequestDone(bool error) emit peerListUpdated(peers); } } + +void TrackerClient::provideAuthentication(QNetworkReply *reply, QAuthenticator *auth) +{ + Q_UNUSED(reply); + auth->setUser(uname); + auth->setPassword(pwd); +} diff --git a/examples/network/torrent/trackerclient.h b/examples/network/torrent/trackerclient.h index 02dd5f91e7..723b3aa4b7 100644 --- a/examples/network/torrent/trackerclient.h +++ b/examples/network/torrent/trackerclient.h @@ -45,7 +45,9 @@ #include #include #include -#include +#include +#include +#include #include "metainfo.h" #include "torrentclient.h" @@ -64,7 +66,7 @@ public: void startSeeding(); signals: - void connectionError(QHttp::Error error); + void connectionError(QNetworkReply::NetworkError error); void failure(const QString &reason); void warning(const QString &message); @@ -80,20 +82,23 @@ protected: private slots: void fetchPeerList(); - void httpRequestDone(bool error); + void httpRequestDone(QNetworkReply *reply); + void provideAuthentication(QNetworkReply *reply, QAuthenticator *auth); private: TorrentClient *torrentDownloader; int requestInterval; int requestIntervalTimer; - QHttp http; + QNetworkAccessManager http; MetaInfo metaInfo; QByteArray trackerId; QList peers; qint64 uploadedBytes; qint64 downloadedBytes; qint64 length; + QString uname; + QString pwd; bool firstTrackerRequest; bool lastTrackerRequest; diff --git a/src/network/access/access.pri b/src/network/access/access.pri index 3d5558d334..944855e9d1 100644 --- a/src/network/access/access.pri +++ b/src/network/access/access.pri @@ -2,7 +2,7 @@ HEADERS += \ access/qftp.h \ - access/qhttp.h \ + access/qhttpheader_p.h \ access/qhttpnetworkheader_p.h \ access/qhttpnetworkrequest_p.h \ access/qhttpnetworkreply_p.h \ @@ -39,7 +39,7 @@ HEADERS += \ SOURCES += \ access/qftp.cpp \ - access/qhttp.cpp \ + access/qhttpheader.cpp \ access/qhttpnetworkheader.cpp \ access/qhttpnetworkrequest.cpp \ access/qhttpnetworkreply.cpp \ diff --git a/src/network/access/qhttp.cpp b/src/network/access/qhttp.cpp deleted file mode 100644 index 067b7f95d7..0000000000 --- a/src/network/access/qhttp.cpp +++ /dev/null @@ -1,3150 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the QtNetwork module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** This file may be used under the terms of the GNU Lesser General Public -** License version 2.1 as published by the Free Software Foundation and -** appearing in the file LICENSE.LGPL included in the packaging of this -** file. Please review the following information to ensure the GNU Lesser -** General Public License version 2.1 requirements will be met: -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -//#define QHTTP_DEBUG - -#include -#include "qhttp.h" - -#ifndef QT_NO_HTTP -# include "private/qobject_p.h" -# include "qtcpsocket.h" -# include "qsslsocket.h" -# include "qtextstream.h" -# include "qmap.h" -# include "qlist.h" -# include "qstring.h" -# include "qstringlist.h" -# include "qbuffer.h" -# include "private/qringbuffer_p.h" -# include "qcoreevent.h" -# include "qurl.h" -# include "qnetworkproxy.h" -# include "qauthenticator.h" -# include "qauthenticator_p.h" -# include "qdebug.h" -# include "qtimer.h" -#endif - -#ifndef QT_NO_HTTP - -QT_BEGIN_NAMESPACE - -class QHttpNormalRequest; -class QHttpRequest -{ -public: - QHttpRequest() : finished(false) - { id = idCounter.fetchAndAddRelaxed(1); } - virtual ~QHttpRequest() - { } - - virtual void start(QHttp *) = 0; - virtual bool hasRequestHeader(); - virtual QHttpRequestHeader requestHeader(); - - virtual QIODevice *sourceDevice() = 0; - virtual QIODevice *destinationDevice() = 0; - - int id; - bool finished; - -private: - static QBasicAtomicInt idCounter; -}; - -class QHttpPrivate : public QObjectPrivate -{ -public: - Q_DECLARE_PUBLIC(QHttp) - - inline QHttpPrivate() - : socket(0), reconnectAttempts(2), - deleteSocket(0), state(QHttp::Unconnected), - error(QHttp::NoError), port(0), mode(QHttp::ConnectionModeHttp), - toDevice(0), postDevice(0), bytesDone(0), chunkedSize(-1), - repost(false), pendingPost(false) - { - } - - inline ~QHttpPrivate() - { - while (!pending.isEmpty()) - delete pending.takeFirst(); - - if (deleteSocket) - delete socket; - } - - // private slots - void _q_startNextRequest(); - void _q_slotReadyRead(); - void _q_slotConnected(); - void _q_slotError(QAbstractSocket::SocketError); - void _q_slotClosed(); - void _q_slotBytesWritten(qint64 numBytes); -#ifndef QT_NO_OPENSSL - void _q_slotEncryptedBytesWritten(qint64 numBytes); -#endif - void _q_slotDoFinished(); - void _q_slotSendRequest(); - void _q_continuePost(); - - int addRequest(QHttpNormalRequest *); - int addRequest(QHttpRequest *); - void finishedWithSuccess(); - void finishedWithError(const QString &detail, int errorCode); - - void init(); - void setState(int); - void closeConn(); - void setSock(QTcpSocket *sock); - - void postMoreData(); - - QTcpSocket *socket; - int reconnectAttempts; - bool deleteSocket; - QList pending; - - QHttp::State state; - QHttp::Error error; - QString errorString; - - QString hostName; - quint16 port; - QHttp::ConnectionMode mode; - - QByteArray buffer; - QIODevice *toDevice; - QIODevice *postDevice; - - qint64 bytesDone; - qint64 bytesTotal; - qint64 chunkedSize; - - QHttpRequestHeader header; - - bool readHeader; - QString headerStr; - QHttpResponseHeader response; - - QRingBuffer rba; - -#ifndef QT_NO_NETWORKPROXY - QNetworkProxy proxy; - QAuthenticator proxyAuthenticator; -#endif - QAuthenticator authenticator; - bool repost; - bool hasFinishedWithError; - bool pendingPost; - QTimer post100ContinueTimer; -}; - -QBasicAtomicInt QHttpRequest::idCounter = Q_BASIC_ATOMIC_INITIALIZER(1); - -bool QHttpRequest::hasRequestHeader() -{ - return false; -} - -QHttpRequestHeader QHttpRequest::requestHeader() -{ - return QHttpRequestHeader(); -} - -/**************************************************** - * - * QHttpNormalRequest - * - ****************************************************/ - -class QHttpNormalRequest : public QHttpRequest -{ -public: - QHttpNormalRequest(const QHttpRequestHeader &h, QIODevice *d, QIODevice *t) : - header(h), to(t) - { - is_ba = false; - data.dev = d; - } - - QHttpNormalRequest(const QHttpRequestHeader &h, QByteArray *d, QIODevice *t) : - header(h), to(t) - { - is_ba = true; - data.ba = d; - } - - ~QHttpNormalRequest() - { - if (is_ba) - delete data.ba; - } - - void start(QHttp *); - bool hasRequestHeader(); - QHttpRequestHeader requestHeader(); - inline void setRequestHeader(const QHttpRequestHeader &h) { header = h; } - - QIODevice *sourceDevice(); - QIODevice *destinationDevice(); - -protected: - QHttpRequestHeader header; - -private: - union { - QByteArray *ba; - QIODevice *dev; - } data; - bool is_ba; - QIODevice *to; -}; - -void QHttpNormalRequest::start(QHttp *http) -{ - if (!http->d_func()->socket) - http->d_func()->setSock(0); - http->d_func()->header = header; - - if (is_ba) { - http->d_func()->buffer = *data.ba; - if (http->d_func()->buffer.size() >= 0) - http->d_func()->header.setContentLength(http->d_func()->buffer.size()); - - http->d_func()->postDevice = 0; - } else { - http->d_func()->buffer = QByteArray(); - - if (data.dev && (data.dev->isOpen() || data.dev->open(QIODevice::ReadOnly))) { - http->d_func()->postDevice = data.dev; - if (http->d_func()->postDevice->size() >= 0) - http->d_func()->header.setContentLength(http->d_func()->postDevice->size()); - } else { - http->d_func()->postDevice = 0; - } - } - - if (to && (to->isOpen() || to->open(QIODevice::WriteOnly))) - http->d_func()->toDevice = to; - else - http->d_func()->toDevice = 0; - - http->d_func()->reconnectAttempts = 2; - http->d_func()->_q_slotSendRequest(); -} - -bool QHttpNormalRequest::hasRequestHeader() -{ - return true; -} - -QHttpRequestHeader QHttpNormalRequest::requestHeader() -{ - return header; -} - -QIODevice *QHttpNormalRequest::sourceDevice() -{ - if (is_ba) - return 0; - return data.dev; -} - -QIODevice *QHttpNormalRequest::destinationDevice() -{ - return to; -} - -/**************************************************** - * - * QHttpPGHRequest - * (like a QHttpNormalRequest, but for the convenience - * functions put(), get() and head() -- i.e. set the - * host header field correctly before sending the - * request) - * - ****************************************************/ - -class QHttpPGHRequest : public QHttpNormalRequest -{ -public: - QHttpPGHRequest(const QHttpRequestHeader &h, QIODevice *d, QIODevice *t) : - QHttpNormalRequest(h, d, t) - { } - - QHttpPGHRequest(const QHttpRequestHeader &h, QByteArray *d, QIODevice *t) : - QHttpNormalRequest(h, d, t) - { } - - ~QHttpPGHRequest() - { } - - void start(QHttp *); -}; - -void QHttpPGHRequest::start(QHttp *http) -{ - if (http->d_func()->port && http->d_func()->port != 80) - header.setValue(QLatin1String("Host"), http->d_func()->hostName + QLatin1Char(':') + QString::number(http->d_func()->port)); - else - header.setValue(QLatin1String("Host"), http->d_func()->hostName); - QHttpNormalRequest::start(http); -} - -/**************************************************** - * - * QHttpSetHostRequest - * - ****************************************************/ - -class QHttpSetHostRequest : public QHttpRequest -{ -public: - QHttpSetHostRequest(const QString &h, quint16 p, QHttp::ConnectionMode m) - : hostName(h), port(p), mode(m) - { } - - void start(QHttp *); - - QIODevice *sourceDevice() - { return 0; } - QIODevice *destinationDevice() - { return 0; } - -private: - QString hostName; - quint16 port; - QHttp::ConnectionMode mode; -}; - -void QHttpSetHostRequest::start(QHttp *http) -{ - http->d_func()->hostName = hostName; - http->d_func()->port = port; - http->d_func()->mode = mode; - -#ifdef QT_NO_OPENSSL - if (mode == QHttp::ConnectionModeHttps) { - // SSL requested but no SSL support compiled in - http->d_func()->finishedWithError(QLatin1String(QT_TRANSLATE_NOOP("QHttp", "HTTPS connection requested but SSL support not compiled in")), - QHttp::UnknownError); - return; - } -#endif - - http->d_func()->finishedWithSuccess(); -} - -/**************************************************** - * - * QHttpSetUserRequest - * - ****************************************************/ - -class QHttpSetUserRequest : public QHttpRequest -{ -public: - QHttpSetUserRequest(const QString &userName, const QString &password) : - user(userName), pass(password) - { } - - void start(QHttp *); - - QIODevice *sourceDevice() - { return 0; } - QIODevice *destinationDevice() - { return 0; } - -private: - QString user; - QString pass; -}; - -void QHttpSetUserRequest::start(QHttp *http) -{ - http->d_func()->authenticator.setUser(user); - http->d_func()->authenticator.setPassword(pass); - http->d_func()->finishedWithSuccess(); -} - -#ifndef QT_NO_NETWORKPROXY - -/**************************************************** - * - * QHttpSetProxyRequest - * - ****************************************************/ - -class QHttpSetProxyRequest : public QHttpRequest -{ -public: - inline QHttpSetProxyRequest(const QNetworkProxy &proxy) - { - this->proxy = proxy; - } - - inline void start(QHttp *http) - { - http->d_func()->proxy = proxy; - QString user = proxy.user(); - if (!user.isEmpty()) - http->d_func()->proxyAuthenticator.setUser(user); - QString password = proxy.password(); - if (!password.isEmpty()) - http->d_func()->proxyAuthenticator.setPassword(password); - http->d_func()->finishedWithSuccess(); - } - - inline QIODevice *sourceDevice() - { return 0; } - inline QIODevice *destinationDevice() - { return 0; } -private: - QNetworkProxy proxy; -}; - -#endif // QT_NO_NETWORKPROXY - -/**************************************************** - * - * QHttpSetSocketRequest - * - ****************************************************/ - -class QHttpSetSocketRequest : public QHttpRequest -{ -public: - QHttpSetSocketRequest(QTcpSocket *s) : socket(s) - { } - - void start(QHttp *); - - QIODevice *sourceDevice() - { return 0; } - QIODevice *destinationDevice() - { return 0; } - -private: - QTcpSocket *socket; -}; - -void QHttpSetSocketRequest::start(QHttp *http) -{ - http->d_func()->setSock(socket); - http->d_func()->finishedWithSuccess(); -} - -/**************************************************** - * - * QHttpCloseRequest - * - ****************************************************/ - -class QHttpCloseRequest : public QHttpRequest -{ -public: - QHttpCloseRequest() - { } - void start(QHttp *); - - QIODevice *sourceDevice() - { return 0; } - QIODevice *destinationDevice() - { return 0; } -}; - -void QHttpCloseRequest::start(QHttp *http) -{ - http->d_func()->closeConn(); -} - -class QHttpHeaderPrivate -{ - Q_DECLARE_PUBLIC(QHttpHeader) -public: - inline virtual ~QHttpHeaderPrivate() {} - - QList > values; - bool valid; - QHttpHeader *q_ptr; -}; - -/**************************************************** - * - * QHttpHeader - * - ****************************************************/ - -/*! - \class QHttpHeader - \obsolete - \brief The QHttpHeader class contains header information for HTTP. - - \ingroup network - \inmodule QtNetwork - - In most cases you should use the more specialized derivatives of - this class, QHttpResponseHeader and QHttpRequestHeader, rather - than directly using QHttpHeader. - - QHttpHeader provides the HTTP header fields. A HTTP header field - consists of a name followed by a colon, a single space, and the - field value. (See RFC 1945.) Field names are case-insensitive. A - typical header field looks like this: - \snippet doc/src/snippets/code/src_network_access_qhttp.cpp 0 - - In the API the header field name is called the "key" and the - content is called the "value". You can get and set a header - field's value by using its key with value() and setValue(), e.g. - \snippet doc/src/snippets/code/src_network_access_qhttp.cpp 1 - - Some fields are so common that getters and setters are provided - for them as a convenient alternative to using \l value() and - \l setValue(), e.g. contentLength() and contentType(), - setContentLength() and setContentType(). - - Each header key has a \e single value associated with it. If you - set the value for a key which already exists the previous value - will be discarded. - - \sa QHttpRequestHeader QHttpResponseHeader -*/ - -/*! - \fn int QHttpHeader::majorVersion() const - - Returns the major protocol-version of the HTTP header. -*/ - -/*! - \fn int QHttpHeader::minorVersion() const - - Returns the minor protocol-version of the HTTP header. -*/ - -/*! - Constructs an empty HTTP header. -*/ -QHttpHeader::QHttpHeader() - : d_ptr(new QHttpHeaderPrivate) -{ - Q_D(QHttpHeader); - d->q_ptr = this; - d->valid = true; -} - -/*! - Constructs a copy of \a header. -*/ -QHttpHeader::QHttpHeader(const QHttpHeader &header) - : d_ptr(new QHttpHeaderPrivate) -{ - Q_D(QHttpHeader); - d->q_ptr = this; - d->valid = header.d_func()->valid; - d->values = header.d_func()->values; -} - -/*! - Constructs a HTTP header for \a str. - - This constructor parses the string \a str for header fields and - adds this information. The \a str should consist of one or more - "\r\n" delimited lines; each of these lines should have the format - key, colon, space, value. -*/ -QHttpHeader::QHttpHeader(const QString &str) - : d_ptr(new QHttpHeaderPrivate) -{ - Q_D(QHttpHeader); - d->q_ptr = this; - d->valid = true; - parse(str); -} - -/*! \internal - */ -QHttpHeader::QHttpHeader(QHttpHeaderPrivate &dd, const QString &str) - : d_ptr(&dd) -{ - Q_D(QHttpHeader); - d->q_ptr = this; - d->valid = true; - if (!str.isEmpty()) - parse(str); -} - -/*! \internal - */ -QHttpHeader::QHttpHeader(QHttpHeaderPrivate &dd, const QHttpHeader &header) - : d_ptr(&dd) -{ - Q_D(QHttpHeader); - d->q_ptr = this; - d->valid = header.d_func()->valid; - d->values = header.d_func()->values; -} -/*! - Destructor. -*/ -QHttpHeader::~QHttpHeader() -{ -} - -/*! - Assigns \a h and returns a reference to this http header. -*/ -QHttpHeader &QHttpHeader::operator=(const QHttpHeader &h) -{ - Q_D(QHttpHeader); - d->values = h.d_func()->values; - d->valid = h.d_func()->valid; - return *this; -} - -/*! - Returns true if the HTTP header is valid; otherwise returns false. - - A QHttpHeader is invalid if it was created by parsing a malformed string. -*/ -bool QHttpHeader::isValid() const -{ - Q_D(const QHttpHeader); - return d->valid; -} - -/*! \internal - Parses the HTTP header string \a str for header fields and adds - the keys/values it finds. If the string is not parsed successfully - the QHttpHeader becomes \link isValid() invalid\endlink. - - Returns true if \a str was successfully parsed; otherwise returns false. - - \sa toString() -*/ -bool QHttpHeader::parse(const QString &str) -{ - Q_D(QHttpHeader); - QStringList lst; - int pos = str.indexOf(QLatin1Char('\n')); - if (pos > 0 && str.at(pos - 1) == QLatin1Char('\r')) - lst = str.trimmed().split(QLatin1String("\r\n")); - else - lst = str.trimmed().split(QLatin1String("\n")); - lst.removeAll(QString()); // No empties - - if (lst.isEmpty()) - return true; - - QStringList lines; - QStringList::Iterator it = lst.begin(); - for (; it != lst.end(); ++it) { - if (!(*it).isEmpty()) { - if ((*it)[0].isSpace()) { - if (!lines.isEmpty()) { - lines.last() += QLatin1Char(' '); - lines.last() += (*it).trimmed(); - } - } else { - lines.append((*it)); - } - } - } - - int number = 0; - it = lines.begin(); - for (; it != lines.end(); ++it) { - if (!parseLine(*it, number++)) { - d->valid = false; - return false; - } - } - return true; -} - -/*! \internal -*/ -void QHttpHeader::setValid(bool v) -{ - Q_D(QHttpHeader); - d->valid = v; -} - -/*! - Returns the first value for the entry with the given \a key. If no entry - has this \a key, an empty string is returned. - - \sa setValue() removeValue() hasKey() keys() -*/ -QString QHttpHeader::value(const QString &key) const -{ - Q_D(const QHttpHeader); - QString lowercaseKey = key.toLower(); - QList >::ConstIterator it = d->values.constBegin(); - while (it != d->values.constEnd()) { - if ((*it).first.toLower() == lowercaseKey) - return (*it).second; - ++it; - } - return QString(); -} - -/*! - Returns all the entries with the given \a key. If no entry - has this \a key, an empty string list is returned. -*/ -QStringList QHttpHeader::allValues(const QString &key) const -{ - Q_D(const QHttpHeader); - QString lowercaseKey = key.toLower(); - QStringList valueList; - QList >::ConstIterator it = d->values.constBegin(); - while (it != d->values.constEnd()) { - if ((*it).first.toLower() == lowercaseKey) - valueList.append((*it).second); - ++it; - } - return valueList; -} - -/*! - Returns a list of the keys in the HTTP header. - - \sa hasKey() -*/ -QStringList QHttpHeader::keys() const -{ - Q_D(const QHttpHeader); - QStringList keyList; - QSet seenKeys; - QList >::ConstIterator it = d->values.constBegin(); - while (it != d->values.constEnd()) { - const QString &key = (*it).first; - QString lowercaseKey = key.toLower(); - if (!seenKeys.contains(lowercaseKey)) { - keyList.append(key); - seenKeys.insert(lowercaseKey); - } - ++it; - } - return keyList; -} - -/*! - Returns true if the HTTP header has an entry with the given \a - key; otherwise returns false. - - \sa value() setValue() keys() -*/ -bool QHttpHeader::hasKey(const QString &key) const -{ - Q_D(const QHttpHeader); - QString lowercaseKey = key.toLower(); - QList >::ConstIterator it = d->values.constBegin(); - while (it != d->values.constEnd()) { - if ((*it).first.toLower() == lowercaseKey) - return true; - ++it; - } - return false; -} - -/*! - Sets the value of the entry with the \a key to \a value. - - If no entry with \a key exists, a new entry with the given \a key - and \a value is created. If an entry with the \a key already - exists, the first value is discarded and replaced with the given - \a value. - - \sa value() hasKey() removeValue() -*/ -void QHttpHeader::setValue(const QString &key, const QString &value) -{ - Q_D(QHttpHeader); - QString lowercaseKey = key.toLower(); - QList >::Iterator it = d->values.begin(); - while (it != d->values.end()) { - if ((*it).first.toLower() == lowercaseKey) { - (*it).second = value; - return; - } - ++it; - } - // not found so add - addValue(key, value); -} - -/*! - Sets the header entries to be the list of key value pairs in \a values. -*/ -void QHttpHeader::setValues(const QList > &values) -{ - Q_D(QHttpHeader); - d->values = values; -} - -/*! - Adds a new entry with the \a key and \a value. -*/ -void QHttpHeader::addValue(const QString &key, const QString &value) -{ - Q_D(QHttpHeader); - d->values.append(qMakePair(key, value)); -} - -/*! - Returns all the entries in the header. -*/ -QList > QHttpHeader::values() const -{ - Q_D(const QHttpHeader); - return d->values; -} - -/*! - Removes the entry with the key \a key from the HTTP header. - - \sa value() setValue() -*/ -void QHttpHeader::removeValue(const QString &key) -{ - Q_D(QHttpHeader); - QString lowercaseKey = key.toLower(); - QList >::Iterator it = d->values.begin(); - while (it != d->values.end()) { - if ((*it).first.toLower() == lowercaseKey) { - d->values.erase(it); - return; - } - ++it; - } -} - -/*! - Removes all the entries with the key \a key from the HTTP header. -*/ -void QHttpHeader::removeAllValues(const QString &key) -{ - Q_D(QHttpHeader); - QString lowercaseKey = key.toLower(); - QList >::Iterator it = d->values.begin(); - while (it != d->values.end()) { - if ((*it).first.toLower() == lowercaseKey) { - it = d->values.erase(it); - continue; - } - ++it; - } -} - -/*! \internal - Parses the single HTTP header line \a line which has the format - key, colon, space, value, and adds key/value to the headers. The - linenumber is \a number. Returns true if the line was successfully - parsed and the key/value added; otherwise returns false. - - \sa parse() -*/ -bool QHttpHeader::parseLine(const QString &line, int) -{ - int i = line.indexOf(QLatin1Char(':')); - if (i == -1) - return false; - - addValue(line.left(i).trimmed(), line.mid(i + 1).trimmed()); - - return true; -} - -/*! - Returns a string representation of the HTTP header. - - The string is suitable for use by the constructor that takes a - QString. It consists of lines with the format: key, colon, space, - value, "\r\n". -*/ -QString QHttpHeader::toString() const -{ - Q_D(const QHttpHeader); - if (!isValid()) - return QLatin1String(""); - - QString ret = QLatin1String(""); - - QList >::ConstIterator it = d->values.constBegin(); - while (it != d->values.constEnd()) { - ret += (*it).first + QLatin1String(": ") + (*it).second + QLatin1String("\r\n"); - ++it; - } - return ret; -} - -/*! - Returns true if the header has an entry for the special HTTP - header field \c content-length; otherwise returns false. - - \sa contentLength() setContentLength() -*/ -bool QHttpHeader::hasContentLength() const -{ - return hasKey(QLatin1String("content-length")); -} - -/*! - Returns the value of the special HTTP header field \c - content-length. - - \sa setContentLength() hasContentLength() -*/ -uint QHttpHeader::contentLength() const -{ - return value(QLatin1String("content-length")).toUInt(); -} - -/*! - Sets the value of the special HTTP header field \c content-length - to \a len. - - \sa contentLength() hasContentLength() -*/ -void QHttpHeader::setContentLength(int len) -{ - setValue(QLatin1String("content-length"), QString::number(len)); -} - -/*! - Returns true if the header has an entry for the special HTTP - header field \c content-type; otherwise returns false. - - \sa contentType() setContentType() -*/ -bool QHttpHeader::hasContentType() const -{ - return hasKey(QLatin1String("content-type")); -} - -/*! - Returns the value of the special HTTP header field \c content-type. - - \sa setContentType() hasContentType() -*/ -QString QHttpHeader::contentType() const -{ - QString type = value(QLatin1String("content-type")); - if (type.isEmpty()) - return QString(); - - int pos = type.indexOf(QLatin1Char(';')); - if (pos == -1) - return type; - - return type.left(pos).trimmed(); -} - -/*! - Sets the value of the special HTTP header field \c content-type to - \a type. - - \sa contentType() hasContentType() -*/ -void QHttpHeader::setContentType(const QString &type) -{ - setValue(QLatin1String("content-type"), type); -} - -class QHttpResponseHeaderPrivate : public QHttpHeaderPrivate -{ - Q_DECLARE_PUBLIC(QHttpResponseHeader) -public: - int statCode; - QString reasonPhr; - int majVer; - int minVer; -}; - -/**************************************************** - * - * QHttpResponseHeader - * - ****************************************************/ - -/*! - \class QHttpResponseHeader - \obsolete - \brief The QHttpResponseHeader class contains response header information for HTTP. - - \ingroup network - \inmodule QtNetwork - - This class is used by the QHttp class to report the header - information that the client received from the server. - - HTTP responses have a status code that indicates the status of the - response. This code is a 3-digit integer result code (for details - see to RFC 1945). In addition to the status code, you can also - specify a human-readable text that describes the reason for the - code ("reason phrase"). This class allows you to get the status - code and the reason phrase. - - \sa QHttpRequestHeader, QHttp, {HTTP Example} -*/ - -/*! - Constructs an empty HTTP response header. -*/ -QHttpResponseHeader::QHttpResponseHeader() - : QHttpHeader(*new QHttpResponseHeaderPrivate) -{ - setValid(false); -} - -/*! - Constructs a copy of \a header. -*/ -QHttpResponseHeader::QHttpResponseHeader(const QHttpResponseHeader &header) - : QHttpHeader(*new QHttpResponseHeaderPrivate, header) -{ - Q_D(QHttpResponseHeader); - d->statCode = header.d_func()->statCode; - d->reasonPhr = header.d_func()->reasonPhr; - d->majVer = header.d_func()->majVer; - d->minVer = header.d_func()->minVer; -} - -/*! - Copies the contents of \a header into this QHttpResponseHeader. -*/ -QHttpResponseHeader &QHttpResponseHeader::operator=(const QHttpResponseHeader &header) -{ - Q_D(QHttpResponseHeader); - QHttpHeader::operator=(header); - d->statCode = header.d_func()->statCode; - d->reasonPhr = header.d_func()->reasonPhr; - d->majVer = header.d_func()->majVer; - d->minVer = header.d_func()->minVer; - return *this; -} - -/*! - Constructs a HTTP response header from the string \a str. The - string is parsed and the information is set. The \a str should - consist of one or more "\r\n" delimited lines; the first line should be the - status-line (format: HTTP-version, space, status-code, space, - reason-phrase); each of remaining lines should have the format key, colon, - space, value. -*/ -QHttpResponseHeader::QHttpResponseHeader(const QString &str) - : QHttpHeader(*new QHttpResponseHeaderPrivate) -{ - parse(str); -} - -/*! - \since 4.1 - - Constructs a QHttpResponseHeader, setting the status code to \a code, the - reason phrase to \a text and the protocol-version to \a majorVer and \a - minorVer. - - \sa statusCode() reasonPhrase() majorVersion() minorVersion() -*/ -QHttpResponseHeader::QHttpResponseHeader(int code, const QString &text, int majorVer, int minorVer) - : QHttpHeader(*new QHttpResponseHeaderPrivate) -{ - setStatusLine(code, text, majorVer, minorVer); -} - -/*! - \since 4.1 - - Sets the status code to \a code, the reason phrase to \a text and - the protocol-version to \a majorVer and \a minorVer. - - \sa statusCode() reasonPhrase() majorVersion() minorVersion() -*/ -void QHttpResponseHeader::setStatusLine(int code, const QString &text, int majorVer, int minorVer) -{ - Q_D(QHttpResponseHeader); - setValid(true); - d->statCode = code; - d->reasonPhr = text; - d->majVer = majorVer; - d->minVer = minorVer; -} - -/*! - Returns the status code of the HTTP response header. - - \sa reasonPhrase() majorVersion() minorVersion() -*/ -int QHttpResponseHeader::statusCode() const -{ - Q_D(const QHttpResponseHeader); - return d->statCode; -} - -/*! - Returns the reason phrase of the HTTP response header. - - \sa statusCode() majorVersion() minorVersion() -*/ -QString QHttpResponseHeader::reasonPhrase() const -{ - Q_D(const QHttpResponseHeader); - return d->reasonPhr; -} - -/*! - Returns the major protocol-version of the HTTP response header. - - \sa minorVersion() statusCode() reasonPhrase() -*/ -int QHttpResponseHeader::majorVersion() const -{ - Q_D(const QHttpResponseHeader); - return d->majVer; -} - -/*! - Returns the minor protocol-version of the HTTP response header. - - \sa majorVersion() statusCode() reasonPhrase() -*/ -int QHttpResponseHeader::minorVersion() const -{ - Q_D(const QHttpResponseHeader); - return d->minVer; -} - -/*! \internal -*/ -bool QHttpResponseHeader::parseLine(const QString &line, int number) -{ - Q_D(QHttpResponseHeader); - if (number != 0) - return QHttpHeader::parseLine(line, number); - - QString l = line.simplified(); - if (l.length() < 10) - return false; - - if (l.left(5) == QLatin1String("HTTP/") && l[5].isDigit() && l[6] == QLatin1Char('.') && - l[7].isDigit() && l[8] == QLatin1Char(' ') && l[9].isDigit()) { - d->majVer = l[5].toLatin1() - '0'; - d->minVer = l[7].toLatin1() - '0'; - - int pos = l.indexOf(QLatin1Char(' '), 9); - if (pos != -1) { - d->reasonPhr = l.mid(pos + 1); - d->statCode = l.mid(9, pos - 9).toInt(); - } else { - d->statCode = l.mid(9).toInt(); - d->reasonPhr.clear(); - } - } else { - return false; - } - - return true; -} - -/*! \reimp -*/ -QString QHttpResponseHeader::toString() const -{ - Q_D(const QHttpResponseHeader); - QString ret(QLatin1String("HTTP/%1.%2 %3 %4\r\n%5\r\n")); - return ret.arg(d->majVer).arg(d->minVer).arg(d->statCode).arg(d->reasonPhr).arg(QHttpHeader::toString()); -} - -class QHttpRequestHeaderPrivate : public QHttpHeaderPrivate -{ - Q_DECLARE_PUBLIC(QHttpRequestHeader) -public: - QString m; - QString p; - int majVer; - int minVer; -}; - -/**************************************************** - * - * QHttpRequestHeader - * - ****************************************************/ - -/*! - \class QHttpRequestHeader - \obsolete - \brief The QHttpRequestHeader class contains request header information for HTTP. - - \ingroup network - \inmodule QtNetwork - - This class is used in the QHttp class to report the header - information if the client requests something from the server. - - HTTP requests have a method which describes the request's action. - The most common requests are "GET" and "POST". In addition to the - request method the header also includes a request-URI to specify - the location for the method to use. - - The method, request-URI and protocol-version can be set using a - constructor or later using setRequest(). The values can be - obtained using method(), path(), majorVersion() and - minorVersion(). - - Note that the request-URI must be in the format expected by the - HTTP server. That is, all reserved characters must be encoded in - %HH (where HH are two hexadecimal digits). See - QUrl::toPercentEncoding() for more information. - - Important inherited functions: setValue() and value(). - - \sa QHttpResponseHeader QHttp -*/ - -/*! - Constructs an empty HTTP request header. -*/ -QHttpRequestHeader::QHttpRequestHeader() - : QHttpHeader(*new QHttpRequestHeaderPrivate) -{ - setValid(false); -} - -/*! - Constructs a HTTP request header for the method \a method, the - request-URI \a path and the protocol-version \a majorVer and \a - minorVer. The \a path argument must be properly encoded for an - HTTP request. -*/ -QHttpRequestHeader::QHttpRequestHeader(const QString &method, const QString &path, int majorVer, int minorVer) - : QHttpHeader(*new QHttpRequestHeaderPrivate) -{ - Q_D(QHttpRequestHeader); - d->m = method; - d->p = path; - d->majVer = majorVer; - d->minVer = minorVer; -} - -/*! - Constructs a copy of \a header. -*/ -QHttpRequestHeader::QHttpRequestHeader(const QHttpRequestHeader &header) - : QHttpHeader(*new QHttpRequestHeaderPrivate, header) -{ - Q_D(QHttpRequestHeader); - d->m = header.d_func()->m; - d->p = header.d_func()->p; - d->majVer = header.d_func()->majVer; - d->minVer = header.d_func()->minVer; -} - -/*! - Copies the content of \a header into this QHttpRequestHeader -*/ -QHttpRequestHeader &QHttpRequestHeader::operator=(const QHttpRequestHeader &header) -{ - Q_D(QHttpRequestHeader); - QHttpHeader::operator=(header); - d->m = header.d_func()->m; - d->p = header.d_func()->p; - d->majVer = header.d_func()->majVer; - d->minVer = header.d_func()->minVer; - return *this; -} - -/*! - Constructs a HTTP request header from the string \a str. The \a - str should consist of one or more "\r\n" delimited lines; the first line - should be the request-line (format: method, space, request-URI, space - HTTP-version); each of the remaining lines should have the format key, - colon, space, value. -*/ -QHttpRequestHeader::QHttpRequestHeader(const QString &str) - : QHttpHeader(*new QHttpRequestHeaderPrivate) -{ - parse(str); -} - -/*! - This function sets the request method to \a method, the - request-URI to \a path and the protocol-version to \a majorVer and - \a minorVer. The \a path argument must be properly encoded for an - HTTP request. - - \sa method() path() majorVersion() minorVersion() -*/ -void QHttpRequestHeader::setRequest(const QString &method, const QString &path, int majorVer, int minorVer) -{ - Q_D(QHttpRequestHeader); - setValid(true); - d->m = method; - d->p = path; - d->majVer = majorVer; - d->minVer = minorVer; -} - -/*! - Returns the method of the HTTP request header. - - \sa path() majorVersion() minorVersion() setRequest() -*/ -QString QHttpRequestHeader::method() const -{ - Q_D(const QHttpRequestHeader); - return d->m; -} - -/*! - Returns the request-URI of the HTTP request header. - - \sa method() majorVersion() minorVersion() setRequest() -*/ -QString QHttpRequestHeader::path() const -{ - Q_D(const QHttpRequestHeader); - return d->p; -} - -/*! - Returns the major protocol-version of the HTTP request header. - - \sa minorVersion() method() path() setRequest() -*/ -int QHttpRequestHeader::majorVersion() const -{ - Q_D(const QHttpRequestHeader); - return d->majVer; -} - -/*! - Returns the minor protocol-version of the HTTP request header. - - \sa majorVersion() method() path() setRequest() -*/ -int QHttpRequestHeader::minorVersion() const -{ - Q_D(const QHttpRequestHeader); - return d->minVer; -} - -/*! \internal -*/ -bool QHttpRequestHeader::parseLine(const QString &line, int number) -{ - Q_D(QHttpRequestHeader); - if (number != 0) - return QHttpHeader::parseLine(line, number); - - QStringList lst = line.simplified().split(QLatin1String(" ")); - if (lst.count() > 0) { - d->m = lst[0]; - if (lst.count() > 1) { - d->p = lst[1]; - if (lst.count() > 2) { - QString v = lst[2]; - if (v.length() >= 8 && v.left(5) == QLatin1String("HTTP/") && - v[5].isDigit() && v[6] == QLatin1Char('.') && v[7].isDigit()) { - d->majVer = v[5].toLatin1() - '0'; - d->minVer = v[7].toLatin1() - '0'; - return true; - } - } - } - } - - return false; -} - -/*! \reimp -*/ -QString QHttpRequestHeader::toString() const -{ - Q_D(const QHttpRequestHeader); - QString first(QLatin1String("%1 %2")); - QString last(QLatin1String(" HTTP/%3.%4\r\n%5\r\n")); - return first.arg(d->m).arg(d->p) + - last.arg(d->majVer).arg(d->minVer).arg(QHttpHeader::toString()); -} - - -/**************************************************** - * - * QHttp - * - ****************************************************/ -/*! - \class QHttp - \obsolete - \reentrant - - \brief The QHttp class provides an implementation of the HTTP protocol. - - \ingroup network - \inmodule QtNetwork - - - This class provides a direct interface to HTTP that allows you to - download and upload data with the HTTP protocol. - However, for new applications, it is - recommended to use QNetworkAccessManager and QNetworkReply, as - those classes possess a simpler, yet more powerful API - and a more modern protocol implementation. - - The class works asynchronously, so there are no blocking - functions. If an operation cannot be executed immediately, the - function will still return straight away and the operation will be - scheduled for later execution. The results of scheduled operations - are reported via signals. This approach depends on the event loop - being in operation. - - The operations that can be scheduled (they are called "requests" - in the rest of the documentation) are the following: setHost(), - get(), post(), head() and request(). - - All of these requests return a unique identifier that allows you - to keep track of the request that is currently executed. When the - execution of a request starts, the requestStarted() signal with - the identifier is emitted and when the request is finished, the - requestFinished() signal is emitted with the identifier and a bool - that indicates if the request finished with an error. - - To make an HTTP request you must set up suitable HTTP headers. The - following example demonstrates how to request the main HTML page - from the Qt website (i.e., the URL \c http://qt.nokia.com/index.html): - - \snippet doc/src/snippets/code/src_network_access_qhttp.cpp 2 - - For the common HTTP requests \c GET, \c POST and \c HEAD, QHttp - provides the convenience functions get(), post() and head(). They - already use a reasonable header and if you don't have to set - special header fields, they are easier to use. The above example - can also be written as: - - \snippet doc/src/snippets/code/src_network_access_qhttp.cpp 3 - - For this example the following sequence of signals is emitted - (with small variations, depending on network traffic, etc.): - - \snippet doc/src/snippets/code/src_network_access_qhttp.cpp 4 - - The dataSendProgress() and dataReadProgress() signals in the above - example are useful if you want to show a \link QProgressBar - progress bar\endlink to inform the user about the progress of the - download. The second argument is the total size of data. In - certain cases it is not possible to know the total amount in - advance, in which case the second argument is 0. (If you connect - to a QProgressBar a total of 0 results in a busy indicator.) - - When the response header is read, it is reported with the - responseHeaderReceived() signal. - - The readyRead() signal tells you that there is data ready to be - read. The amount of data can then be queried with the - bytesAvailable() function and it can be read with the read() - or readAll() functions. - - If an error occurs during the execution of one of the commands in - a sequence of commands, all the pending commands (i.e. scheduled, - but not yet executed commands) are cleared and no signals are - emitted for them. - - For example, if you have the following sequence of requests - - \snippet doc/src/snippets/code/src_network_access_qhttp.cpp 5 - - and the get() request fails because the host lookup fails, then - the post() request is never executed and the signals would look - like this: - - \snippet doc/src/snippets/code/src_network_access_qhttp.cpp 6 - - You can then get details about the error with the error() and - errorString() functions. Note that only unexpected behavior, like - network failure is considered as an error. If the server response - contains an error status, like a 404 response, this is reported as - a normal response case. So you should always check the \link - QHttpResponseHeader::statusCode() status code \endlink of the - response header. - - The functions currentId() and currentRequest() provide more - information about the currently executing request. - - The functions hasPendingRequests() and clearPendingRequests() - allow you to query and clear the list of pending requests. - - \sa QFtp, QNetworkAccessManager, QNetworkRequest, QNetworkReply, - {HTTP Example}, {Torrent Example} -*/ - -/*! - Constructs a QHttp object. The \a parent parameter is passed on - to the QObject constructor. -*/ -QHttp::QHttp(QObject *parent) - : QObject(*new QHttpPrivate, parent) -{ - Q_D(QHttp); - d->init(); -} - -/*! - Constructs a QHttp object. Subsequent requests are done by - connecting to the server \a hostName on port \a port. - - The \a parent parameter is passed on to the QObject constructor. - - \sa setHost() -*/ -QHttp::QHttp(const QString &hostName, quint16 port, QObject *parent) - : QObject(*new QHttpPrivate, parent) -{ - Q_D(QHttp); - d->init(); - - d->hostName = hostName; - d->port = port; -} - -/*! - Constructs a QHttp object. Subsequent requests are done by - connecting to the server \a hostName on port \a port using the - connection mode \a mode. - - If port is 0, it will use the default port for the \a mode used - (80 for Http and 443 for Https). - - The \a parent parameter is passed on to the QObject constructor. - - \sa setHost() -*/ -QHttp::QHttp(const QString &hostName, ConnectionMode mode, quint16 port, QObject *parent) - : QObject(*new QHttpPrivate, parent) -{ - Q_D(QHttp); - d->init(); - - d->hostName = hostName; - if (port == 0) - port = (mode == ConnectionModeHttp) ? 80 : 443; - d->port = port; - d->mode = mode; -} - -void QHttpPrivate::init() -{ - Q_Q(QHttp); - errorString = QLatin1String(QT_TRANSLATE_NOOP("QHttp", "Unknown error")); - QMetaObject::invokeMethod(q, "_q_slotDoFinished", Qt::QueuedConnection); - post100ContinueTimer.setSingleShot(true); - QObject::connect(&post100ContinueTimer, SIGNAL(timeout()), q, SLOT(_q_continuePost())); -} - -/*! - Destroys the QHttp object. If there is an open connection, it is - closed. -*/ -QHttp::~QHttp() -{ - abort(); -} - -/*! - \enum QHttp::ConnectionMode - \since 4.3 - - This enum is used to specify the mode of connection to use: - - \value ConnectionModeHttp The connection is a regular HTTP connection to the server - \value ConnectionModeHttps The HTTPS protocol is used and the connection is encrypted using SSL. - - When using the HTTPS mode, care should be taken to connect to the sslErrors signal, and - handle possible SSL errors. - - \sa QSslSocket -*/ - -/*! - \enum QHttp::State - - This enum is used to specify the state the client is in: - - \value Unconnected There is no connection to the host. - \value HostLookup A host name lookup is in progress. - \value Connecting An attempt to connect to the host is in progress. - \value Sending The client is sending its request to the server. - \value Reading The client's request has been sent and the client - is reading the server's response. - \value Connected The connection to the host is open, but the client is - neither sending a request, nor waiting for a response. - \value Closing The connection is closing down, but is not yet - closed. (The state will be \c Unconnected when the connection is - closed.) - - \sa stateChanged() state() -*/ - -/*! \enum QHttp::Error - - This enum identifies the error that occurred. - - \value NoError No error occurred. - \value HostNotFound The host name lookup failed. - \value ConnectionRefused The server refused the connection. - \value UnexpectedClose The server closed the connection unexpectedly. - \value InvalidResponseHeader The server sent an invalid response header. - \value WrongContentLength The client could not read the content correctly - because an error with respect to the content length occurred. - \value Aborted The request was aborted with abort(). - \value ProxyAuthenticationRequiredError QHttp is using a proxy, and the - proxy server requires authentication to establish a connection. - \value AuthenticationRequiredError The web server requires authentication - to complete the request. - \value UnknownError An error other than those specified above - occurred. - - \sa error() -*/ - -/*! - \fn void QHttp::stateChanged(int state) - - This signal is emitted when the state of the QHttp object changes. - The argument \a state is the new state of the connection; it is - one of the \l State values. - - This usually happens when a request is started, but it can also - happen when the server closes the connection or when a call to - close() succeeded. - - \sa get() post() head() request() close() state() State -*/ - -/*! - \fn void QHttp::responseHeaderReceived(const QHttpResponseHeader &resp); - - This signal is emitted when the HTTP header of a server response - is available. The header is passed in \a resp. - - \sa get() post() head() request() readyRead() -*/ - -/*! - \fn void QHttp::readyRead(const QHttpResponseHeader &resp) - - This signal is emitted when there is new response data to read. - - If you specified a device in the request where the data should be - written to, then this signal is \e not emitted; instead the data - is written directly to the device. - - The response header is passed in \a resp. - - You can read the data with the readAll() or read() functions - - This signal is useful if you want to process the data in chunks as - soon as it becomes available. If you are only interested in the - complete data, just connect to the requestFinished() signal and - read the data then instead. - - \sa get() post() request() readAll() read() bytesAvailable() -*/ - -/*! - \fn void QHttp::dataSendProgress(int done, int total) - - This signal is emitted when this object sends data to a HTTP - server to inform it about the progress of the upload. - - \a done is the amount of data that has already arrived and \a - total is the total amount of data. It is possible that the total - amount of data that should be transferred cannot be determined, in - which case \a total is 0.(If you connect to a QProgressBar, the - progress bar shows a busy indicator if the total is 0). - - \warning \a done and \a total are not necessarily the size in - bytes, since for large files these values might need to be - "scaled" to avoid overflow. - - \sa dataReadProgress(), post(), request(), QProgressBar -*/ - -/*! - \fn void QHttp::dataReadProgress(int done, int total) - - This signal is emitted when this object reads data from a HTTP - server to indicate the current progress of the download. - - \a done is the amount of data that has already arrived and \a - total is the total amount of data. It is possible that the total - amount of data that should be transferred cannot be determined, in - which case \a total is 0.(If you connect to a QProgressBar, the - progress bar shows a busy indicator if the total is 0). - - \warning \a done and \a total are not necessarily the size in - bytes, since for large files these values might need to be - "scaled" to avoid overflow. - - \sa dataSendProgress() get() post() request() QProgressBar -*/ - -/*! - \fn void QHttp::requestStarted(int id) - - This signal is emitted when processing the request identified by - \a id starts. - - \sa requestFinished() done() -*/ - -/*! - \fn void QHttp::requestFinished(int id, bool error) - - This signal is emitted when processing the request identified by - \a id has finished. \a error is true if an error occurred during - the processing; otherwise \a error is false. - - \sa requestStarted() done() error() errorString() -*/ - -/*! - \fn void QHttp::done(bool error) - - This signal is emitted when the last pending request has finished; - (it is emitted after the last request's requestFinished() signal). - \a error is true if an error occurred during the processing; - otherwise \a error is false. - - \sa requestFinished() error() errorString() -*/ - -#ifndef QT_NO_NETWORKPROXY - -/*! - \fn void QHttp::proxyAuthenticationRequired(const QNetworkProxy &proxy, QAuthenticator *authenticator) - \since 4.3 - - This signal can be emitted when a \a proxy that requires - authentication is used. The \a authenticator object can then be - filled in with the required details to allow authentication and - continue the connection. - - \note It is not possible to use a QueuedConnection to connect to - this signal, as the connection will fail if the authenticator has - not been filled in with new information when the signal returns. - - \sa QAuthenticator, QNetworkProxy -*/ - -#endif - -/*! - \fn void QHttp::authenticationRequired(const QString &hostname, quint16 port, QAuthenticator *authenticator) - \since 4.3 - - This signal can be emitted when a web server on a given \a hostname and \a - port requires authentication. The \a authenticator object can then be - filled in with the required details to allow authentication and continue - the connection. - - \note It is not possible to use a QueuedConnection to connect to - this signal, as the connection will fail if the authenticator has - not been filled in with new information when the signal returns. - - \sa QAuthenticator, QNetworkProxy -*/ - -/*! - \fn void QHttp::sslErrors(const QList &errors) - \since 4.3 - - Forwards the sslErrors signal from the QSslSocket used in QHttp. \a errors - is the list of errors that occurred during the SSL handshake. Unless you - call ignoreSslErrors() from within a slot connected to this signal when an - error occurs, QHttp will tear down the connection immediately after - emitting the signal. - - \sa QSslSocket QSslSocket::ignoreSslErrors() -*/ - -/*! - Aborts the current request and deletes all scheduled requests. - - For the current request, the requestFinished() signal with the \c - error argument \c true is emitted. For all other requests that are - affected by the abort(), no signals are emitted. - - Since this slot also deletes the scheduled requests, there are no - requests left and the done() signal is emitted (with the \c error - argument \c true). - - \sa clearPendingRequests() -*/ -void QHttp::abort() -{ - Q_D(QHttp); - if (d->pending.isEmpty()) - return; - - d->finishedWithError(tr("Request aborted"), Aborted); - clearPendingRequests(); - if (d->socket) - d->socket->abort(); - d->closeConn(); -} - -/*! - Returns the number of bytes that can be read from the response - content at the moment. - - \sa get() post() request() readyRead() read() readAll() -*/ -qint64 QHttp::bytesAvailable() const -{ - Q_D(const QHttp); -#if defined(QHTTP_DEBUG) - qDebug("QHttp::bytesAvailable(): %d bytes", (int)d->rba.size()); -#endif - return qint64(d->rba.size()); -} - -/*! - Reads \a maxlen bytes from the response content into \a data and - returns the number of bytes read. Returns -1 if an error occurred. - - \sa get() post() request() readyRead() bytesAvailable() readAll() -*/ -qint64 QHttp::read(char *data, qint64 maxlen) -{ - Q_D(QHttp); - if (data == 0 && maxlen != 0) { - qWarning("QHttp::read: Null pointer error"); - return -1; - } - if (maxlen >= d->rba.size()) - maxlen = d->rba.size(); - int readSoFar = 0; - while (!d->rba.isEmpty() && readSoFar < maxlen) { - int nextBlockSize = d->rba.nextDataBlockSize(); - int bytesToRead = qMin(maxlen - readSoFar, nextBlockSize); - memcpy(data + readSoFar, d->rba.readPointer(), bytesToRead); - d->rba.free(bytesToRead); - readSoFar += bytesToRead; - } - - d->bytesDone += maxlen; -#if defined(QHTTP_DEBUG) - qDebug("QHttp::read(): read %lld bytes (%lld bytes done)", maxlen, d->bytesDone); -#endif - return maxlen; -} - -/*! - Reads all the bytes from the response content and returns them. - - \sa get() post() request() readyRead() bytesAvailable() read() -*/ -QByteArray QHttp::readAll() -{ - qint64 avail = bytesAvailable(); - QByteArray tmp; - tmp.resize(int(avail)); - qint64 got = read(tmp.data(), int(avail)); - tmp.resize(got); - return tmp; -} - -/*! - Returns the identifier of the HTTP request being executed or 0 if - there is no request being executed (i.e. they've all finished). - - \sa currentRequest() -*/ -int QHttp::currentId() const -{ - Q_D(const QHttp); - if (d->pending.isEmpty()) - return 0; - return d->pending.first()->id; -} - -/*! - Returns the request header of the HTTP request being executed. If - the request is one issued by setHost() or close(), it - returns an invalid request header, i.e. - QHttpRequestHeader::isValid() returns false. - - \sa currentId() -*/ -QHttpRequestHeader QHttp::currentRequest() const -{ - Q_D(const QHttp); - if (!d->pending.isEmpty()) { - QHttpRequest *r = d->pending.first(); - if (r->hasRequestHeader()) - return r->requestHeader(); - } - return QHttpRequestHeader(); -} - -/*! - Returns the received response header of the most recently finished HTTP - request. If no response has yet been received - QHttpResponseHeader::isValid() will return false. - - \sa currentRequest() -*/ -QHttpResponseHeader QHttp::lastResponse() const -{ - Q_D(const QHttp); - return d->response; -} - -/*! - Returns the QIODevice pointer that is used as the data source of the HTTP - request being executed. If there is no current request or if the request - does not use an IO device as the data source, this function returns 0. - - This function can be used to delete the QIODevice in the slot connected to - the requestFinished() signal. - - \sa currentDestinationDevice() post() request() -*/ -QIODevice *QHttp::currentSourceDevice() const -{ - Q_D(const QHttp); - if (d->pending.isEmpty()) - return 0; - return d->pending.first()->sourceDevice(); -} - -/*! - Returns the QIODevice pointer that is used as to store the data of the HTTP - request being executed. If there is no current request or if the request - does not store the data to an IO device, this function returns 0. - - This function can be used to delete the QIODevice in the slot connected to - the requestFinished() signal. - - \sa currentSourceDevice() get() post() request() -*/ -QIODevice *QHttp::currentDestinationDevice() const -{ - Q_D(const QHttp); - if (d->pending.isEmpty()) - return 0; - return d->pending.first()->destinationDevice(); -} - -/*! - Returns true if there are any requests scheduled that have not yet - been executed; otherwise returns false. - - The request that is being executed is \e not considered as a - scheduled request. - - \sa clearPendingRequests() currentId() currentRequest() -*/ -bool QHttp::hasPendingRequests() const -{ - Q_D(const QHttp); - return d->pending.count() > 1; -} - -/*! - Deletes all pending requests from the list of scheduled requests. - This does not affect the request that is being executed. If - you want to stop this as well, use abort(). - - \sa hasPendingRequests() abort() -*/ -void QHttp::clearPendingRequests() -{ - Q_D(QHttp); - // delete all entires except the first one - while (d->pending.count() > 1) - delete d->pending.takeLast(); -} - -/*! - Sets the HTTP server that is used for requests to \a hostName on - port \a port. - - The function does not block; instead, it returns immediately. The request - is scheduled, and its execution is performed asynchronously. The - function returns a unique identifier which is passed by - requestStarted() and requestFinished(). - - When the request is started the requestStarted() signal is - emitted. When it is finished the requestFinished() signal is - emitted. - - \sa get() post() head() request() requestStarted() requestFinished() done() -*/ -int QHttp::setHost(const QString &hostName, quint16 port) -{ - Q_D(QHttp); - return d->addRequest(new QHttpSetHostRequest(hostName, port, ConnectionModeHttp)); -} - -/*! - Sets the HTTP server that is used for requests to \a hostName on - port \a port using the connection mode \a mode. - - If port is 0, it will use the default port for the \a mode used - (80 for HTTP and 443 for HTTPS). - - The function does not block; instead, it returns immediately. The request - is scheduled, and its execution is performed asynchronously. The - function returns a unique identifier which is passed by - requestStarted() and requestFinished(). - - When the request is started the requestStarted() signal is - emitted. When it is finished the requestFinished() signal is - emitted. - - \sa get() post() head() request() requestStarted() requestFinished() done() -*/ -int QHttp::setHost(const QString &hostName, ConnectionMode mode, quint16 port) -{ -#ifdef QT_NO_OPENSSL - if (mode == ConnectionModeHttps) - qWarning("QHttp::setHost: HTTPS connection requested but SSL support not compiled in"); -#endif - Q_D(QHttp); - if (port == 0) - port = (mode == ConnectionModeHttp) ? 80 : 443; - return d->addRequest(new QHttpSetHostRequest(hostName, port, mode)); -} - -/*! - Replaces the internal QTcpSocket that QHttp uses with \a - socket. This is useful if you want to use your own custom QTcpSocket - subclass instead of the plain QTcpSocket that QHttp uses by default. - QHttp does not take ownership of the socket, and will not delete \a - socket when destroyed. - - The function does not block; instead, it returns immediately. The request - is scheduled, and its execution is performed asynchronously. The - function returns a unique identifier which is passed by - requestStarted() and requestFinished(). - - When the request is started the requestStarted() signal is - emitted. When it is finished the requestFinished() signal is - emitted. - - Note: If QHttp is used in a non-GUI thread that runs its own event - loop, you must move \a socket to that thread before calling setSocket(). - - \sa QObject::moveToThread(), {Thread Support in Qt} -*/ -int QHttp::setSocket(QTcpSocket *socket) -{ - Q_D(QHttp); - return d->addRequest(new QHttpSetSocketRequest(socket)); -} - -/*! - This function sets the user name \a userName and password \a - password for web pages that require authentication. - - The function does not block; instead, it returns immediately. The request - is scheduled, and its execution is performed asynchronously. The - function returns a unique identifier which is passed by - requestStarted() and requestFinished(). - - When the request is started the requestStarted() signal is - emitted. When it is finished the requestFinished() signal is - emitted. -*/ -int QHttp::setUser(const QString &userName, const QString &password) -{ - Q_D(QHttp); - return d->addRequest(new QHttpSetUserRequest(userName, password)); -} - -#ifndef QT_NO_NETWORKPROXY - -/*! - Enables HTTP proxy support, using the proxy server \a host on port \a - port. \a username and \a password can be provided if the proxy server - requires authentication. - - Example: - - \snippet doc/src/snippets/code/src_network_access_qhttp.cpp 7 - - QHttp supports non-transparent web proxy servers only, such as the Squid - Web proxy cache server (from \l http://www.squid.org/). For transparent - proxying, such as SOCKS5, use QNetworkProxy instead. - - \note setProxy() has to be called before setHost() for it to take effect. - If setProxy() is called after setHost(), then it will not apply until after - setHost() is called again. - - \sa QFtp::setProxy() -*/ -int QHttp::setProxy(const QString &host, int port, - const QString &username, const QString &password) -{ - Q_D(QHttp); - QNetworkProxy proxy(QNetworkProxy::HttpProxy, host, port, username, password); - return d->addRequest(new QHttpSetProxyRequest(proxy)); -} - -/*! - \overload - - Enables HTTP proxy support using the proxy settings from \a - proxy. If \a proxy is a transparent proxy, QHttp will call - QAbstractSocket::setProxy() on the underlying socket. If the type - is QNetworkProxy::HttpCachingProxy, QHttp will behave like the - previous function. - - \note for compatibility with Qt 4.3, if the proxy type is - QNetworkProxy::HttpProxy and the request type is unencrypted (that - is, ConnectionModeHttp), QHttp will treat the proxy as a caching - proxy. -*/ -int QHttp::setProxy(const QNetworkProxy &proxy) -{ - Q_D(QHttp); - return d->addRequest(new QHttpSetProxyRequest(proxy)); -} - -#endif - -/*! - Sends a get request for \a path to the server set by setHost() or - as specified in the constructor. - - \a path must be a absolute path like \c /index.html or an - absolute URI like \c http://example.com/index.html and - must be encoded with either QUrl::toPercentEncoding() or - QUrl::encodedPath(). - - If the IO device \a to is 0 the readyRead() signal is emitted - every time new content data is available to read. - - If the IO device \a to is not 0, the content data of the response - is written directly to the device. Make sure that the \a to - pointer is valid for the duration of the operation (it is safe to - delete it when the requestFinished() signal is emitted). - - \section1 Request Processing - - The function does not block; instead, it returns immediately. The request - is scheduled, and its execution is performed asynchronously. The - function returns a unique identifier which is passed by - requestStarted() and requestFinished(). - - When the request is started the requestStarted() signal is - emitted. When it is finished the requestFinished() signal is - emitted. - - \sa setHost(), post(), head(), request(), requestStarted(), - requestFinished(), done() -*/ -int QHttp::get(const QString &path, QIODevice *to) -{ - Q_D(QHttp); - QHttpRequestHeader header(QLatin1String("GET"), path); - header.setValue(QLatin1String("Connection"), QLatin1String("Keep-Alive")); - return d->addRequest(new QHttpPGHRequest(header, (QIODevice *) 0, to)); -} - -/*! - Sends a post request for \a path to the server set by setHost() or - as specified in the constructor. - - \a path must be an absolute path like \c /index.html or an - absolute URI like \c http://example.com/index.html and - must be encoded with either QUrl::toPercentEncoding() or - QUrl::encodedPath(). - - The incoming data comes via the \a data IO device. - - If the IO device \a to is 0 the readyRead() signal is emitted - every time new content data is available to read. - - If the IO device \a to is not 0, the content data of the response - is written directly to the device. Make sure that the \a to - pointer is valid for the duration of the operation (it is safe to - delete it when the requestFinished() signal is emitted). - - The function does not block; instead, it returns immediately. The request - is scheduled, and its execution is performed asynchronously. The - function returns a unique identifier which is passed by - requestStarted() and requestFinished(). - - When the request is started the requestStarted() signal is - emitted. When it is finished the requestFinished() signal is - emitted. - - \sa setHost() get() head() request() requestStarted() requestFinished() done() -*/ -int QHttp::post(const QString &path, QIODevice *data, QIODevice *to ) -{ - Q_D(QHttp); - QHttpRequestHeader header(QLatin1String("POST"), path); - header.setValue(QLatin1String("Connection"), QLatin1String("Keep-Alive")); - return d->addRequest(new QHttpPGHRequest(header, data, to)); -} - -/*! - \overload - - \a data is used as the content data of the HTTP request. -*/ -int QHttp::post(const QString &path, const QByteArray &data, QIODevice *to) -{ - Q_D(QHttp); - QHttpRequestHeader header(QLatin1String("POST"), path); - header.setValue(QLatin1String("Connection"), QLatin1String("Keep-Alive")); - return d->addRequest(new QHttpPGHRequest(header, new QByteArray(data), to)); -} - -/*! - Sends a header request for \a path to the server set by setHost() - or as specified in the constructor. - - \a path must be an absolute path like \c /index.html or an - absolute URI like \c http://example.com/index.html. - - The function does not block; instead, it returns immediately. The request - is scheduled, and its execution is performed asynchronously. The - function returns a unique identifier which is passed by - requestStarted() and requestFinished(). - - When the request is started the requestStarted() signal is - emitted. When it is finished the requestFinished() signal is - emitted. - - \sa setHost() get() post() request() requestStarted() requestFinished() done() -*/ -int QHttp::head(const QString &path) -{ - Q_D(QHttp); - QHttpRequestHeader header(QLatin1String("HEAD"), path); - header.setValue(QLatin1String("Connection"), QLatin1String("Keep-Alive")); - return d->addRequest(new QHttpPGHRequest(header, (QIODevice*)0, 0)); -} - -/*! - Sends a request to the server set by setHost() or as specified in - the constructor. Uses the \a header as the HTTP request header. - You are responsible for setting up a header that is appropriate - for your request. - - The incoming data comes via the \a data IO device. - - If the IO device \a to is 0 the readyRead() signal is emitted - every time new content data is available to read. - - If the IO device \a to is not 0, the content data of the response - is written directly to the device. Make sure that the \a to - pointer is valid for the duration of the operation (it is safe to - delete it when the requestFinished() signal is emitted). - - The function does not block; instead, it returns immediately. The request - is scheduled, and its execution is performed asynchronously. The - function returns a unique identifier which is passed by - requestStarted() and requestFinished(). - - When the request is started the requestStarted() signal is - emitted. When it is finished the requestFinished() signal is - emitted. - - \sa setHost() get() post() head() requestStarted() requestFinished() done() -*/ -int QHttp::request(const QHttpRequestHeader &header, QIODevice *data, QIODevice *to) -{ - Q_D(QHttp); - return d->addRequest(new QHttpNormalRequest(header, data, to)); -} - -/*! - \overload - - \a data is used as the content data of the HTTP request. -*/ -int QHttp::request(const QHttpRequestHeader &header, const QByteArray &data, QIODevice *to ) -{ - Q_D(QHttp); - return d->addRequest(new QHttpNormalRequest(header, new QByteArray(data), to)); -} - -/*! - Closes the connection; this is useful if you have a keep-alive - connection and want to close it. - - For the requests issued with get(), post() and head(), QHttp sets - the connection to be keep-alive. You can also do this using the - header you pass to the request() function. QHttp only closes the - connection to the HTTP server if the response header requires it - to do so. - - The function does not block; instead, it returns immediately. The request - is scheduled, and its execution is performed asynchronously. The - function returns a unique identifier which is passed by - requestStarted() and requestFinished(). - - When the request is started the requestStarted() signal is - emitted. When it is finished the requestFinished() signal is - emitted. - - If you want to close the connection immediately, you have to use - abort() instead. - - \sa stateChanged() abort() requestStarted() requestFinished() done() -*/ -int QHttp::close() -{ - Q_D(QHttp); - return d->addRequest(new QHttpCloseRequest()); -} - -/*! - \obsolete - - Behaves the same as close(). -*/ -int QHttp::closeConnection() -{ - Q_D(QHttp); - return d->addRequest(new QHttpCloseRequest()); -} - -int QHttpPrivate::addRequest(QHttpNormalRequest *req) -{ - QHttpRequestHeader h = req->requestHeader(); - if (h.path().isEmpty()) { - // note: the following qWarning is autotested. If you change it, change the test too. - qWarning("QHttp: empty path requested is invalid -- using '/'"); - h.setRequest(h.method(), QLatin1String("/"), h.majorVersion(), h.minorVersion()); - req->setRequestHeader(h); - } - - // contine below - return addRequest(static_cast(req)); -} - -int QHttpPrivate::addRequest(QHttpRequest *req) -{ - Q_Q(QHttp); - pending.append(req); - - if (pending.count() == 1) { - // don't emit the requestStarted() signal before the id is returned - QMetaObject::invokeMethod(q, "_q_startNextRequest", Qt::QueuedConnection); - } - return req->id; -} - -void QHttpPrivate::_q_startNextRequest() -{ - Q_Q(QHttp); - if (pending.isEmpty()) - return; - QHttpRequest *r = pending.first(); - - error = QHttp::NoError; - errorString = QLatin1String(QT_TRANSLATE_NOOP("QHttp", "Unknown error")); - - if (q->bytesAvailable() != 0) - q->readAll(); // clear the data - emit q->requestStarted(r->id); - r->start(q); -} - -void QHttpPrivate::_q_slotSendRequest() -{ - if (hostName.isNull()) { - finishedWithError(QLatin1String(QT_TRANSLATE_NOOP("QHttp", "No server set to connect to")), - QHttp::UnknownError); - return; - } - - QString connectionHost = hostName; - int connectionPort = port; - bool sslInUse = false; - -#ifndef QT_NO_OPENSSL - QSslSocket *sslSocket = qobject_cast(socket); - if (mode == QHttp::ConnectionModeHttps || (sslSocket && sslSocket->isEncrypted())) - sslInUse = true; -#endif - -#ifndef QT_NO_NETWORKPROXY - bool cachingProxyInUse = false; - bool transparentProxyInUse = false; - if (proxy.type() == QNetworkProxy::DefaultProxy) - proxy = QNetworkProxy::applicationProxy(); - - if (proxy.type() == QNetworkProxy::HttpCachingProxy) { - if (proxy.hostName().isEmpty()) - proxy.setType(QNetworkProxy::NoProxy); - else - cachingProxyInUse = true; - } else if (proxy.type() == QNetworkProxy::HttpProxy) { - // Compatibility behaviour: HttpProxy can be used to mean both - // transparent and caching proxy - if (proxy.hostName().isEmpty()) { - proxy.setType(QNetworkProxy::NoProxy); - } else if (sslInUse) { - // Disallow use of caching proxy with HTTPS; instead fall back to - // transparent HTTP CONNECT proxying. - transparentProxyInUse = true; - } else { - proxy.setType(QNetworkProxy::HttpCachingProxy); - cachingProxyInUse = true; - } - } - - // Proxy support. Insert the Proxy-Authorization item into the - // header before it's sent off to the proxy. - if (cachingProxyInUse) { - QUrl proxyUrl; - proxyUrl.setScheme(QLatin1String("http")); - proxyUrl.setHost(hostName); - if (port && port != 80) - proxyUrl.setPort(port); - QString request = QString::fromAscii(proxyUrl.resolved(QUrl::fromEncoded(header.path().toLatin1())).toEncoded()); - - header.setRequest(header.method(), request, header.majorVersion(), header.minorVersion()); - header.setValue(QLatin1String("Proxy-Connection"), QLatin1String("keep-alive")); - - QAuthenticatorPrivate *auth = QAuthenticatorPrivate::getPrivate(proxyAuthenticator); - if (auth && auth->method != QAuthenticatorPrivate::None) { - QByteArray response = auth->calculateResponse(header.method().toLatin1(), header.path().toLatin1()); - header.setValue(QLatin1String("Proxy-Authorization"), QString::fromLatin1(response)); - } - - connectionHost = proxy.hostName(); - connectionPort = proxy.port(); - } - - if (transparentProxyInUse || sslInUse) { - socket->setProxy(proxy); - } -#endif - - // Username support. Insert the user and password into the query - // string. - QAuthenticatorPrivate *auth = QAuthenticatorPrivate::getPrivate(authenticator); - if (auth && auth->method != QAuthenticatorPrivate::None) { - QByteArray response = auth->calculateResponse(header.method().toLatin1(), header.path().toLatin1()); - header.setValue(QLatin1String("Authorization"), QString::fromLatin1(response)); - } - - // Do we need to setup a new connection or can we reuse an - // existing one? - if (socket->peerName() != connectionHost || socket->peerPort() != connectionPort - || socket->state() != QTcpSocket::ConnectedState -#ifndef QT_NO_OPENSSL - || (sslSocket && sslSocket->isEncrypted() != (mode == QHttp::ConnectionModeHttps)) -#endif - ) { - socket->blockSignals(true); - socket->abort(); - socket->blockSignals(false); - - setState(QHttp::Connecting); -#ifndef QT_NO_OPENSSL - if (sslSocket && mode == QHttp::ConnectionModeHttps) { - sslSocket->connectToHostEncrypted(hostName, port); - } else -#endif - { - socket->connectToHost(connectionHost, connectionPort); - } - } else { - _q_slotConnected(); - } - -} - -void QHttpPrivate::finishedWithSuccess() -{ - Q_Q(QHttp); - if (pending.isEmpty()) - return; - QHttpRequest *r = pending.first(); - - // did we recurse? - if (r->finished) - return; - r->finished = true; - hasFinishedWithError = false; - - emit q->requestFinished(r->id, false); - if (hasFinishedWithError) { - // we recursed and changed into an error. The finishedWithError function - // below has emitted the done(bool) signal and cleared the queue by now. - return; - } - - pending.removeFirst(); - delete r; - - if (pending.isEmpty()) { - emit q->done(false); - } else { - _q_startNextRequest(); - } -} - -void QHttpPrivate::finishedWithError(const QString &detail, int errorCode) -{ - Q_Q(QHttp); - if (pending.isEmpty()) - return; - QHttpRequest *r = pending.first(); - hasFinishedWithError = true; - - error = QHttp::Error(errorCode); - errorString = detail; - - // did we recurse? - if (!r->finished) { - r->finished = true; - emit q->requestFinished(r->id, true); - } - - while (!pending.isEmpty()) - delete pending.takeFirst(); - emit q->done(hasFinishedWithError); -} - -void QHttpPrivate::_q_slotClosed() -{ - Q_Q(QHttp); - - if (state == QHttp::Reading) { - if (response.hasKey(QLatin1String("content-length"))) { - // We got Content-Length, so did we get all bytes? - if (bytesDone + q->bytesAvailable() != response.contentLength()) { - finishedWithError(QLatin1String(QT_TRANSLATE_NOOP("QHttp", "Wrong content length")), QHttp::WrongContentLength); - } - } - } else if (state == QHttp::Connecting || state == QHttp::Sending) { - finishedWithError(QLatin1String(QT_TRANSLATE_NOOP("QHttp", "Server closed connection unexpectedly")), QHttp::UnexpectedClose); - } - - postDevice = 0; - if (state != QHttp::Closing) - setState(QHttp::Closing); - QMetaObject::invokeMethod(q, "_q_slotDoFinished", Qt::QueuedConnection); -} - -void QHttpPrivate::_q_continuePost() -{ - if (pendingPost) { - pendingPost = false; - setState(QHttp::Sending); - _q_slotBytesWritten(0); - } -} - -void QHttpPrivate::_q_slotConnected() -{ - if (state != QHttp::Sending) { - bytesDone = 0; - setState(QHttp::Sending); - } - - QString str = header.toString(); - bytesTotal = str.length(); - socket->write(str.toLatin1(), bytesTotal); -#if defined(QHTTP_DEBUG) - qDebug("QHttp: write request header %p:\n---{\n%s}---", &header, str.toLatin1().constData()); -#endif - - if (postDevice) { - postDevice->seek(0); // reposition the device - bytesTotal += postDevice->size(); - //check for 100-continue - if (header.value(QLatin1String("expect")).contains(QLatin1String("100-continue"), Qt::CaseInsensitive)) { - //create a time out for 2 secs. - pendingPost = true; - post100ContinueTimer.start(2000); - } - } else { - bytesTotal += buffer.size(); - socket->write(buffer, buffer.size()); - } -} - -void QHttpPrivate::_q_slotError(QAbstractSocket::SocketError err) -{ - Q_Q(QHttp); - postDevice = 0; - - if (state == QHttp::Connecting || state == QHttp::Reading || state == QHttp::Sending) { - switch (err) { - case QTcpSocket::ConnectionRefusedError: - finishedWithError(QLatin1String(QT_TRANSLATE_NOOP("QHttp", "Connection refused (or timed out)")), QHttp::ConnectionRefused); - break; - case QTcpSocket::HostNotFoundError: - finishedWithError(QString::fromLatin1(QT_TRANSLATE_NOOP("QHttp", "Host %1 not found")) - .arg(socket->peerName()), QHttp::HostNotFound); - break; - case QTcpSocket::RemoteHostClosedError: - if (state == QHttp::Sending && reconnectAttempts--) { - setState(QHttp::Closing); - setState(QHttp::Unconnected); - socket->blockSignals(true); - socket->abort(); - socket->blockSignals(false); - QMetaObject::invokeMethod(q, "_q_slotSendRequest", Qt::QueuedConnection); - return; - } - break; -#ifndef QT_NO_NETWORKPROXY - case QTcpSocket::ProxyAuthenticationRequiredError: - finishedWithError(socket->errorString(), QHttp::ProxyAuthenticationRequiredError); - break; -#endif - default: - finishedWithError(QLatin1String(QT_TRANSLATE_NOOP("QHttp", "HTTP request failed")), QHttp::UnknownError); - break; - } - } - - closeConn(); -} - -#ifndef QT_NO_OPENSSL -void QHttpPrivate::_q_slotEncryptedBytesWritten(qint64 written) -{ - Q_UNUSED(written); - postMoreData(); -} -#endif - -void QHttpPrivate::_q_slotBytesWritten(qint64 written) -{ - Q_Q(QHttp); - bytesDone += written; - emit q->dataSendProgress(bytesDone, bytesTotal); - postMoreData(); -} - -// Send the POST data -void QHttpPrivate::postMoreData() -{ - if (pendingPost) - return; - - if (!postDevice) - return; - - // the following is backported code from Qt 4.6 QNetworkAccessManager. - // We also have to check the encryptedBytesToWrite() if it is an SSL socket. -#ifndef QT_NO_OPENSSL - QSslSocket *sslSocket = qobject_cast(socket); - // if it is really an ssl socket, check more than just bytesToWrite() - if ((socket->bytesToWrite() + (sslSocket ? sslSocket->encryptedBytesToWrite() : 0)) == 0) { -#else - if (socket->bytesToWrite() == 0) { -#endif - int max = qMin(4096, postDevice->size() - postDevice->pos()); - QByteArray arr; - arr.resize(max); - - int n = postDevice->read(arr.data(), max); - if (n < 0) { - qWarning("Could not read enough bytes from the device"); - closeConn(); - return; - } - if (postDevice->atEnd()) { - postDevice = 0; - } - - socket->write(arr, n); - } -} - -void QHttpPrivate::_q_slotReadyRead() -{ - Q_Q(QHttp); - QHttp::State oldState = state; - if (state != QHttp::Reading) { - setState(QHttp::Reading); - readHeader = true; - headerStr = QLatin1String(""); - bytesDone = 0; - chunkedSize = -1; - repost = false; - } - - while (readHeader) { - bool end = false; - QString tmp; - while (!end && socket->canReadLine()) { - tmp = QString::fromAscii(socket->readLine()); - if (tmp == QLatin1String("\r\n") || tmp == QLatin1String("\n") || tmp.isEmpty()) - end = true; - else - headerStr += tmp; - } - - if (!end) - return; - - response = QHttpResponseHeader(headerStr); - headerStr = QLatin1String(""); -#if defined(QHTTP_DEBUG) - qDebug("QHttp: read response header:\n---{\n%s}---", response.toString().toLatin1().constData()); -#endif - // Check header - if (!response.isValid()) { - finishedWithError(QLatin1String(QT_TRANSLATE_NOOP("QHttp", "Invalid HTTP response header")), - QHttp::InvalidResponseHeader); - closeConn(); - return; - } - - int statusCode = response.statusCode(); - if (statusCode == 401 || statusCode == 407) { // (Proxy) Authentication required - QAuthenticator *auth = -#ifndef QT_NO_NETWORKPROXY - statusCode == 407 - ? &proxyAuthenticator : -#endif - &authenticator; - if (auth->isNull()) - auth->detach(); - QAuthenticatorPrivate *priv = QAuthenticatorPrivate::getPrivate(*auth); - priv->parseHttpResponse(response, (statusCode == 407)); - if (priv->phase == QAuthenticatorPrivate::Done) { - socket->blockSignals(true); -#ifndef QT_NO_NETWORKPROXY - if (statusCode == 407) - emit q->proxyAuthenticationRequired(proxy, auth); - else -#endif - emit q->authenticationRequired(hostName, port, auth); - socket->blockSignals(false); - } else if (priv->phase == QAuthenticatorPrivate::Invalid) { - finishedWithError(QLatin1String(QT_TRANSLATE_NOOP("QHttp", "Unknown authentication method")), - QHttp::AuthenticationRequiredError); - closeConn(); - return; - } - - // priv->phase will get reset to QAuthenticatorPrivate::Start if the authenticator got modified in the signal above. - if (priv->phase == QAuthenticatorPrivate::Done) { -#ifndef QT_NO_NETWORKPROXY - if (statusCode == 407) - finishedWithError(QLatin1String(QT_TRANSLATE_NOOP("QHttp", "Proxy authentication required")), - QHttp::ProxyAuthenticationRequiredError); - else -#endif - finishedWithError(QLatin1String(QT_TRANSLATE_NOOP("QHttp", "Authentication required")), - QHttp::AuthenticationRequiredError); - closeConn(); - return; - } else { - // close the connection if it isn't already and reconnect using the chosen authentication method - bool willClose = (response.value(QLatin1String("proxy-connection")).toLower() == QLatin1String("close")) - || (response.value(QLatin1String("connection")).toLower() == QLatin1String("close")); - if (willClose) { - if (socket) { - setState(QHttp::Closing); - socket->blockSignals(true); - socket->close(); - socket->blockSignals(false); - socket->readAll(); - } - _q_slotSendRequest(); - return; - } else { - repost = true; - } - } - } else { - buffer.clear(); - } - - if (response.statusCode() == 100 && pendingPost) { - // if we have pending POST, start sending data otherwise ignore - post100ContinueTimer.stop(); - QMetaObject::invokeMethod(q, "_q_continuePost", Qt::QueuedConnection); - return; - } - - // The 100-continue header is ignored (in case of no 'expect:100-continue' header), - // because when using the POST method, we send both the request header and data in - // one chunk. - if (response.statusCode() != 100) { - post100ContinueTimer.stop(); - pendingPost = false; - readHeader = false; - if (response.hasKey(QLatin1String("transfer-encoding")) && - response.value(QLatin1String("transfer-encoding")).toLower().contains(QLatin1String("chunked"))) - chunkedSize = 0; - - if (!repost) - emit q->responseHeaderReceived(response); - if (state == QHttp::Unconnected || state == QHttp::Closing) - return; - } else { - // Restore the state, the next incoming data will be treated as if - // we never say the 100 response. - state = oldState; - } - } - - bool everythingRead = false; - - if (q->currentRequest().method() == QLatin1String("HEAD") || - response.statusCode() == 304 || response.statusCode() == 204 || - response.statusCode() == 205) { - // HEAD requests have only headers as replies - // These status codes never have a body: - // 304 Not Modified - // 204 No Content - // 205 Reset Content - everythingRead = true; - } else { - qint64 n = socket->bytesAvailable(); - QByteArray *arr = 0; - if (chunkedSize != -1) { - // transfer-encoding is chunked - for (;;) { - // get chunk size - if (chunkedSize == 0) { - if (!socket->canReadLine()) - break; - QString sizeString = QString::fromAscii(socket->readLine()); - int tPos = sizeString.indexOf(QLatin1Char(';')); - if (tPos != -1) - sizeString.truncate(tPos); - bool ok; - chunkedSize = sizeString.toInt(&ok, 16); - if (!ok) { - finishedWithError(QLatin1String(QT_TRANSLATE_NOOP("QHttp", "Invalid HTTP chunked body")), - QHttp::WrongContentLength); - closeConn(); - delete arr; - return; - } - if (chunkedSize == 0) // last-chunk - chunkedSize = -2; - } - - // read trailer - while (chunkedSize == -2 && socket->canReadLine()) { - QString read = QString::fromAscii(socket->readLine()); - if (read == QLatin1String("\r\n") || read == QLatin1String("\n")) - chunkedSize = -1; - } - if (chunkedSize == -1) { - everythingRead = true; - break; - } - - // make sure that you can read the terminating CRLF, - // otherwise wait until next time... - n = socket->bytesAvailable(); - if (n == 0) - break; - if (n == chunkedSize || n == chunkedSize+1) { - n = chunkedSize - 1; - if (n == 0) - break; - } - - // read data - qint64 toRead = chunkedSize < 0 ? n : qMin(n, chunkedSize); - if (!arr) - arr = new QByteArray; - uint oldArrSize = arr->size(); - arr->resize(oldArrSize + toRead); - qint64 read = socket->read(arr->data()+oldArrSize, toRead); - arr->resize(oldArrSize + read); - - chunkedSize -= read; - - if (chunkedSize == 0 && n - read >= 2) { - // read terminating CRLF - char tmp[2]; - socket->read(tmp, 2); - if (tmp[0] != '\r' || tmp[1] != '\n') { - finishedWithError(QLatin1String(QT_TRANSLATE_NOOP("QHttp", "Invalid HTTP chunked body")), - QHttp::WrongContentLength); - closeConn(); - delete arr; - return; - } - } - } - } else if (response.hasContentLength()) { - if (repost && (n < response.contentLength())) { - // wait for the content to be available fully - // if repost is required, the content is ignored - return; - } - n = qMin(qint64(response.contentLength() - bytesDone), n); - if (n > 0) { - arr = new QByteArray; - arr->resize(n); - qint64 read = socket->read(arr->data(), n); - arr->resize(read); - } - if (bytesDone + q->bytesAvailable() + n == response.contentLength()) - everythingRead = true; - } else if (n > 0) { - // workaround for VC++ bug - QByteArray temp = socket->readAll(); - arr = new QByteArray(temp); - } - - if (arr && !repost) { - n = arr->size(); - if (toDevice) { - qint64 bytesWritten; - bytesWritten = toDevice->write(*arr, n); - delete arr; - arr = 0; - // if writing to the device does not succeed, quit with error - if (bytesWritten == -1 || bytesWritten < n) { - finishedWithError(QLatin1String(QT_TRANSLATE_NOOP("QHttp", "Error writing response to device")), QHttp::UnknownError); - } else { - bytesDone += bytesWritten; -#if defined(QHTTP_DEBUG) - qDebug("QHttp::_q_slotReadyRead(): read %lld bytes (%lld bytes done)", n, bytesDone); -#endif - } - if (response.hasContentLength()) - emit q->dataReadProgress(bytesDone, response.contentLength()); - else - emit q->dataReadProgress(bytesDone, 0); - } else { - char *ptr = rba.reserve(arr->size()); - memcpy(ptr, arr->data(), arr->size()); - delete arr; - arr = 0; -#if defined(QHTTP_DEBUG) - qDebug("QHttp::_q_slotReadyRead(): read %lld bytes (%lld bytes done)", n, bytesDone + q->bytesAvailable()); -#endif - if (response.hasContentLength()) - emit q->dataReadProgress(bytesDone + q->bytesAvailable(), response.contentLength()); - else - emit q->dataReadProgress(bytesDone + q->bytesAvailable(), 0); - emit q->readyRead(response); - } - } - - delete arr; - } - - if (everythingRead) { - if (repost) { - _q_slotSendRequest(); - return; - } - // Handle "Connection: close" - if (response.value(QLatin1String("connection")).toLower() == QLatin1String("close")) { - closeConn(); - } else { - setState(QHttp::Connected); - // Start a timer, so that we emit the keep alive signal - // "after" this method returned. - QMetaObject::invokeMethod(q, "_q_slotDoFinished", Qt::QueuedConnection); - } - } -} - -void QHttpPrivate::_q_slotDoFinished() -{ - if (state == QHttp::Connected) { - finishedWithSuccess(); - } else if (state != QHttp::Unconnected) { - setState(QHttp::Unconnected); - finishedWithSuccess(); - } -} - - -/*! - Returns the current state of the object. When the state changes, - the stateChanged() signal is emitted. - - \sa State stateChanged() -*/ -QHttp::State QHttp::state() const -{ - Q_D(const QHttp); - return d->state; -} - -/*! - Returns the last error that occurred. This is useful to find out - what happened when receiving a requestFinished() or a done() - signal with the \c error argument \c true. - - If you start a new request, the error status is reset to \c NoError. -*/ -QHttp::Error QHttp::error() const -{ - Q_D(const QHttp); - return d->error; -} - -/*! - Returns a human-readable description of the last error that - occurred. This is useful to present a error message to the user - when receiving a requestFinished() or a done() signal with the \c - error argument \c true. -*/ -QString QHttp::errorString() const -{ - Q_D(const QHttp); - return d->errorString; -} - -void QHttpPrivate::setState(int s) -{ - Q_Q(QHttp); -#if defined(QHTTP_DEBUG) - qDebug("QHttp state changed %d -> %d", state, s); -#endif - state = QHttp::State(s); - emit q->stateChanged(s); -} - -void QHttpPrivate::closeConn() -{ - Q_Q(QHttp); - // If no connection is open -> ignore - if (state == QHttp::Closing || state == QHttp::Unconnected) - return; - - postDevice = 0; - setState(QHttp::Closing); - - // Already closed ? - if (!socket || !socket->isOpen()) { - QMetaObject::invokeMethod(q, "_q_slotDoFinished", Qt::QueuedConnection); - } else { - // Close now. - socket->close(); - } -} - -void QHttpPrivate::setSock(QTcpSocket *sock) -{ - Q_Q(const QHttp); - - // disconnect all existing signals - if (socket) - socket->disconnect(); - if (deleteSocket) - delete socket; - - // use the new QTcpSocket socket, or create one if socket is 0. - deleteSocket = (sock == 0); - socket = sock; - if (!socket) { -#ifndef QT_NO_OPENSSL - if (QSslSocket::supportsSsl()) - socket = new QSslSocket(); - else -#endif - socket = new QTcpSocket(); - } - - // connect all signals - QObject::connect(socket, SIGNAL(connected()), q, SLOT(_q_slotConnected())); - QObject::connect(socket, SIGNAL(disconnected()), q, SLOT(_q_slotClosed())); - QObject::connect(socket, SIGNAL(readyRead()), q, SLOT(_q_slotReadyRead())); - QObject::connect(socket, SIGNAL(error(QAbstractSocket::SocketError)), q, SLOT(_q_slotError(QAbstractSocket::SocketError))); - QObject::connect(socket, SIGNAL(bytesWritten(qint64)), - q, SLOT(_q_slotBytesWritten(qint64))); -#ifndef QT_NO_NETWORKPROXY - QObject::connect(socket, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)), - q, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*))); -#endif - -#ifndef QT_NO_OPENSSL - if (qobject_cast(socket)) { - QObject::connect(socket, SIGNAL(sslErrors(QList)), - q, SIGNAL(sslErrors(QList))); - QObject::connect(socket, SIGNAL(encryptedBytesWritten(qint64)), - q, SLOT(_q_slotEncryptedBytesWritten(qint64))); - } -#endif -} - -/*! - Tells the QSslSocket used for the Http connection to ignore the errors - reported in the sslErrors() signal. - - Note that this function must be called from within a slot connected to the - sslErrors() signal to have any effect. - - \sa QSslSocket QSslSocket::sslErrors() -*/ -#ifndef QT_NO_OPENSSL -void QHttp::ignoreSslErrors() -{ - Q_D(QHttp); - QSslSocket *sslSocket = qobject_cast(d->socket); - if (sslSocket) - sslSocket->ignoreSslErrors(); -} -#endif - -QT_END_NAMESPACE - -#include "moc_qhttp.cpp" - -#endif diff --git a/src/network/access/qhttp.h b/src/network/access/qhttp.h deleted file mode 100644 index 5dd3b5bc3d..0000000000 --- a/src/network/access/qhttp.h +++ /dev/null @@ -1,311 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the QtNetwork module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** This file may be used under the terms of the GNU Lesser General Public -** License version 2.1 as published by the Free Software Foundation and -** appearing in the file LICENSE.LGPL included in the packaging of this -** file. Please review the following information to ensure the GNU Lesser -** General Public License version 2.1 requirements will be met: -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QHTTP_H -#define QHTTP_H - -#include -#include -#include -#include -#include - -QT_BEGIN_HEADER - -QT_BEGIN_NAMESPACE - -QT_MODULE(Network) - -#ifndef QT_NO_HTTP - -class QTcpSocket; -class QTimerEvent; -class QIODevice; -class QAuthenticator; -class QNetworkProxy; -class QSslError; - -class QHttpPrivate; - -class QHttpHeaderPrivate; -class Q_NETWORK_EXPORT QHttpHeader -{ -public: - QHttpHeader(); - QHttpHeader(const QHttpHeader &header); - QHttpHeader(const QString &str); - virtual ~QHttpHeader(); - - QHttpHeader &operator=(const QHttpHeader &h); - - void setValue(const QString &key, const QString &value); - void setValues(const QList > &values); - void addValue(const QString &key, const QString &value); - QList > values() const; - bool hasKey(const QString &key) const; - QStringList keys() const; - QString value(const QString &key) const; - QStringList allValues(const QString &key) const; - void removeValue(const QString &key); - void removeAllValues(const QString &key); - - // ### Qt 5: change to qint64 - bool hasContentLength() const; - uint contentLength() const; - void setContentLength(int len); - - bool hasContentType() const; - QString contentType() const; - void setContentType(const QString &type); - - virtual QString toString() const; - bool isValid() const; - - virtual int majorVersion() const = 0; - virtual int minorVersion() const = 0; - -protected: - virtual bool parseLine(const QString &line, int number); - bool parse(const QString &str); - void setValid(bool); - - QHttpHeader(QHttpHeaderPrivate &dd, const QString &str = QString()); - QHttpHeader(QHttpHeaderPrivate &dd, const QHttpHeader &header); - QScopedPointer d_ptr; - -private: - Q_DECLARE_PRIVATE(QHttpHeader) -}; - -class QHttpResponseHeaderPrivate; -class Q_NETWORK_EXPORT QHttpResponseHeader : public QHttpHeader -{ -public: - QHttpResponseHeader(); - QHttpResponseHeader(const QHttpResponseHeader &header); - QHttpResponseHeader(const QString &str); - QHttpResponseHeader(int code, const QString &text = QString(), int majorVer = 1, int minorVer = 1); - QHttpResponseHeader &operator=(const QHttpResponseHeader &header); - - void setStatusLine(int code, const QString &text = QString(), int majorVer = 1, int minorVer = 1); - - int statusCode() const; - QString reasonPhrase() const; - - int majorVersion() const; - int minorVersion() const; - - QString toString() const; - -protected: - bool parseLine(const QString &line, int number); - -private: - Q_DECLARE_PRIVATE(QHttpResponseHeader) - friend class QHttpPrivate; -}; - -class QHttpRequestHeaderPrivate; -class Q_NETWORK_EXPORT QHttpRequestHeader : public QHttpHeader -{ -public: - QHttpRequestHeader(); - QHttpRequestHeader(const QString &method, const QString &path, int majorVer = 1, int minorVer = 1); - QHttpRequestHeader(const QHttpRequestHeader &header); - QHttpRequestHeader(const QString &str); - QHttpRequestHeader &operator=(const QHttpRequestHeader &header); - - void setRequest(const QString &method, const QString &path, int majorVer = 1, int minorVer = 1); - - QString method() const; - QString path() const; - - int majorVersion() const; - int minorVersion() const; - - QString toString() const; - -protected: - bool parseLine(const QString &line, int number); - -private: - Q_DECLARE_PRIVATE(QHttpRequestHeader) -}; - -class Q_NETWORK_EXPORT QHttp : public QObject -{ - Q_OBJECT - -public: - enum ConnectionMode { - ConnectionModeHttp, - ConnectionModeHttps - }; - - explicit QHttp(QObject *parent = 0); - QHttp(const QString &hostname, quint16 port = 80, QObject *parent = 0); - QHttp(const QString &hostname, ConnectionMode mode, quint16 port = 0, QObject *parent = 0); - virtual ~QHttp(); - - enum State { - Unconnected, - HostLookup, - Connecting, - Sending, - Reading, - Connected, - Closing - }; - enum Error { - NoError, - UnknownError, - HostNotFound, - ConnectionRefused, - UnexpectedClose, - InvalidResponseHeader, - WrongContentLength, - Aborted, - AuthenticationRequiredError, - ProxyAuthenticationRequiredError - }; - - int setHost(const QString &hostname, quint16 port = 80); - int setHost(const QString &hostname, ConnectionMode mode, quint16 port = 0); - - int setSocket(QTcpSocket *socket); - int setUser(const QString &username, const QString &password = QString()); - -#ifndef QT_NO_NETWORKPROXY - int setProxy(const QString &host, int port, - const QString &username = QString(), - const QString &password = QString()); - int setProxy(const QNetworkProxy &proxy); -#endif - - int get(const QString &path, QIODevice *to=0); - int post(const QString &path, QIODevice *data, QIODevice *to=0 ); - int post(const QString &path, const QByteArray &data, QIODevice *to=0); - int head(const QString &path); - int request(const QHttpRequestHeader &header, QIODevice *device=0, QIODevice *to=0); - int request(const QHttpRequestHeader &header, const QByteArray &data, QIODevice *to=0); - - int closeConnection(); - int close(); - - qint64 bytesAvailable() const; - qint64 read(char *data, qint64 maxlen); - QByteArray readAll(); - - int currentId() const; - QIODevice *currentSourceDevice() const; - QIODevice *currentDestinationDevice() const; - QHttpRequestHeader currentRequest() const; - QHttpResponseHeader lastResponse() const; - bool hasPendingRequests() const; - void clearPendingRequests(); - - State state() const; - - Error error() const; - QString errorString() const; - -public Q_SLOTS: - void abort(); - -#ifndef QT_NO_OPENSSL - void ignoreSslErrors(); -#endif - -Q_SIGNALS: - void stateChanged(int); - void responseHeaderReceived(const QHttpResponseHeader &resp); - void readyRead(const QHttpResponseHeader &resp); - - // ### Qt 5: change to qint64 - void dataSendProgress(int, int); - void dataReadProgress(int, int); - - void requestStarted(int); - void requestFinished(int, bool); - void done(bool); - -#ifndef QT_NO_NETWORKPROXY - void proxyAuthenticationRequired(const QNetworkProxy &proxy, QAuthenticator *); -#endif - void authenticationRequired(const QString &hostname, quint16 port, QAuthenticator *); - -#ifndef QT_NO_OPENSSL - void sslErrors(const QList &errors); -#endif - -private: - Q_DISABLE_COPY(QHttp) - Q_DECLARE_PRIVATE(QHttp) - - Q_PRIVATE_SLOT(d_func(), void _q_startNextRequest()) - Q_PRIVATE_SLOT(d_func(), void _q_slotReadyRead()) - Q_PRIVATE_SLOT(d_func(), void _q_slotConnected()) - Q_PRIVATE_SLOT(d_func(), void _q_slotError(QAbstractSocket::SocketError)) - Q_PRIVATE_SLOT(d_func(), void _q_slotClosed()) - Q_PRIVATE_SLOT(d_func(), void _q_slotBytesWritten(qint64 numBytes)) -#ifndef QT_NO_OPENSSL - Q_PRIVATE_SLOT(d_func(), void _q_slotEncryptedBytesWritten(qint64 numBytes)) -#endif - Q_PRIVATE_SLOT(d_func(), void _q_slotDoFinished()) - Q_PRIVATE_SLOT(d_func(), void _q_slotSendRequest()) - Q_PRIVATE_SLOT(d_func(), void _q_continuePost()) - - friend class QHttpNormalRequest; - friend class QHttpSetHostRequest; - friend class QHttpSetSocketRequest; - friend class QHttpSetUserRequest; - friend class QHttpSetProxyRequest; - friend class QHttpCloseRequest; - friend class QHttpPGHRequest; -}; - -#endif // QT_NO_HTTP - -QT_END_NAMESPACE - -QT_END_HEADER - -#endif // QHTTP_H diff --git a/src/network/access/qhttpheader.cpp b/src/network/access/qhttpheader.cpp new file mode 100644 index 0000000000..58c24cf3f5 --- /dev/null +++ b/src/network/access/qhttpheader.cpp @@ -0,0 +1,770 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtNetwork module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +//#define QHTTP_DEBUG + +#include +#include "qhttpheader_p.h" + +#ifndef QT_NO_HTTP +# include "private/qobject_p.h" +# include "qtcpsocket.h" +# include "qsslsocket.h" +# include "qtextstream.h" +# include "qmap.h" +# include "qlist.h" +# include "qstring.h" +# include "qstringlist.h" +# include "qbuffer.h" +# include "private/qringbuffer_p.h" +# include "qcoreevent.h" +# include "qurl.h" +# include "qnetworkproxy.h" +# include "qauthenticator.h" +# include "qauthenticator_p.h" +# include "qdebug.h" +# include "qtimer.h" +#endif + +#ifndef QT_NO_HTTP + +QT_BEGIN_NAMESPACE + +class QHttpHeaderPrivate +{ + Q_DECLARE_PUBLIC(QHttpHeader) +public: + inline virtual ~QHttpHeaderPrivate() {} + + QList > values; + bool valid; + QHttpHeader *q_ptr; +}; + +/**************************************************** + * + * QHttpHeader + * + ****************************************************/ + +/*! + \class QHttpHeader + \obsolete + \brief The QHttpHeader class contains header information for HTTP. + + \ingroup network + \inmodule QtNetwork + + In most cases you should use the more specialized derivatives of + this class, QHttpResponseHeader and QHttpRequestHeader, rather + than directly using QHttpHeader. + + QHttpHeader provides the HTTP header fields. A HTTP header field + consists of a name followed by a colon, a single space, and the + field value. (See RFC 1945.) Field names are case-insensitive. A + typical header field looks like this: + \snippet doc/src/snippets/code/src_network_access_qhttp.cpp 0 + + In the API the header field name is called the "key" and the + content is called the "value". You can get and set a header + field's value by using its key with value() and setValue(), e.g. + \snippet doc/src/snippets/code/src_network_access_qhttp.cpp 1 + + Some fields are so common that getters and setters are provided + for them as a convenient alternative to using \l value() and + \l setValue(), e.g. contentLength() and contentType(), + setContentLength() and setContentType(). + + Each header key has a \e single value associated with it. If you + set the value for a key which already exists the previous value + will be discarded. + + \sa QHttpRequestHeader QHttpResponseHeader +*/ + +/*! + \fn int QHttpHeader::majorVersion() const + + Returns the major protocol-version of the HTTP header. +*/ + +/*! + \fn int QHttpHeader::minorVersion() const + + Returns the minor protocol-version of the HTTP header. +*/ + +/*! + Constructs an empty HTTP header. +*/ +QHttpHeader::QHttpHeader() + : d_ptr(new QHttpHeaderPrivate) +{ + Q_D(QHttpHeader); + d->q_ptr = this; + d->valid = true; +} + +/*! + Constructs a copy of \a header. +*/ +QHttpHeader::QHttpHeader(const QHttpHeader &header) + : d_ptr(new QHttpHeaderPrivate) +{ + Q_D(QHttpHeader); + d->q_ptr = this; + d->valid = header.d_func()->valid; + d->values = header.d_func()->values; +} + +/*! + Constructs a HTTP header for \a str. + + This constructor parses the string \a str for header fields and + adds this information. The \a str should consist of one or more + "\r\n" delimited lines; each of these lines should have the format + key, colon, space, value. +*/ +QHttpHeader::QHttpHeader(const QString &str) + : d_ptr(new QHttpHeaderPrivate) +{ + Q_D(QHttpHeader); + d->q_ptr = this; + d->valid = true; + parse(str); +} + +/*! \internal + */ +QHttpHeader::QHttpHeader(QHttpHeaderPrivate &dd, const QString &str) + : d_ptr(&dd) +{ + Q_D(QHttpHeader); + d->q_ptr = this; + d->valid = true; + if (!str.isEmpty()) + parse(str); +} + +/*! \internal + */ +QHttpHeader::QHttpHeader(QHttpHeaderPrivate &dd, const QHttpHeader &header) + : d_ptr(&dd) +{ + Q_D(QHttpHeader); + d->q_ptr = this; + d->valid = header.d_func()->valid; + d->values = header.d_func()->values; +} +/*! + Destructor. +*/ +QHttpHeader::~QHttpHeader() +{ +} + +/*! + Assigns \a h and returns a reference to this http header. +*/ +QHttpHeader &QHttpHeader::operator=(const QHttpHeader &h) +{ + Q_D(QHttpHeader); + d->values = h.d_func()->values; + d->valid = h.d_func()->valid; + return *this; +} + +/*! + Returns true if the HTTP header is valid; otherwise returns false. + + A QHttpHeader is invalid if it was created by parsing a malformed string. +*/ +bool QHttpHeader::isValid() const +{ + Q_D(const QHttpHeader); + return d->valid; +} + +/*! \internal + Parses the HTTP header string \a str for header fields and adds + the keys/values it finds. If the string is not parsed successfully + the QHttpHeader becomes \link isValid() invalid\endlink. + + Returns true if \a str was successfully parsed; otherwise returns false. + + \sa toString() +*/ +bool QHttpHeader::parse(const QString &str) +{ + Q_D(QHttpHeader); + QStringList lst; + int pos = str.indexOf(QLatin1Char('\n')); + if (pos > 0 && str.at(pos - 1) == QLatin1Char('\r')) + lst = str.trimmed().split(QLatin1String("\r\n")); + else + lst = str.trimmed().split(QLatin1String("\n")); + lst.removeAll(QString()); // No empties + + if (lst.isEmpty()) + return true; + + QStringList lines; + QStringList::Iterator it = lst.begin(); + for (; it != lst.end(); ++it) { + if (!(*it).isEmpty()) { + if ((*it)[0].isSpace()) { + if (!lines.isEmpty()) { + lines.last() += QLatin1Char(' '); + lines.last() += (*it).trimmed(); + } + } else { + lines.append((*it)); + } + } + } + + int number = 0; + it = lines.begin(); + for (; it != lines.end(); ++it) { + if (!parseLine(*it, number++)) { + d->valid = false; + return false; + } + } + return true; +} + +/*! \internal +*/ +void QHttpHeader::setValid(bool v) +{ + Q_D(QHttpHeader); + d->valid = v; +} + +/*! + Returns the first value for the entry with the given \a key. If no entry + has this \a key, an empty string is returned. + + \sa setValue() removeValue() hasKey() keys() +*/ +QString QHttpHeader::value(const QString &key) const +{ + Q_D(const QHttpHeader); + QString lowercaseKey = key.toLower(); + QList >::ConstIterator it = d->values.constBegin(); + while (it != d->values.constEnd()) { + if ((*it).first.toLower() == lowercaseKey) + return (*it).second; + ++it; + } + return QString(); +} + +/*! + Returns all the entries with the given \a key. If no entry + has this \a key, an empty string list is returned. +*/ +QStringList QHttpHeader::allValues(const QString &key) const +{ + Q_D(const QHttpHeader); + QString lowercaseKey = key.toLower(); + QStringList valueList; + QList >::ConstIterator it = d->values.constBegin(); + while (it != d->values.constEnd()) { + if ((*it).first.toLower() == lowercaseKey) + valueList.append((*it).second); + ++it; + } + return valueList; +} + +/*! + Returns a list of the keys in the HTTP header. + + \sa hasKey() +*/ +QStringList QHttpHeader::keys() const +{ + Q_D(const QHttpHeader); + QStringList keyList; + QSet seenKeys; + QList >::ConstIterator it = d->values.constBegin(); + while (it != d->values.constEnd()) { + const QString &key = (*it).first; + QString lowercaseKey = key.toLower(); + if (!seenKeys.contains(lowercaseKey)) { + keyList.append(key); + seenKeys.insert(lowercaseKey); + } + ++it; + } + return keyList; +} + +/*! + Returns true if the HTTP header has an entry with the given \a + key; otherwise returns false. + + \sa value() setValue() keys() +*/ +bool QHttpHeader::hasKey(const QString &key) const +{ + Q_D(const QHttpHeader); + QString lowercaseKey = key.toLower(); + QList >::ConstIterator it = d->values.constBegin(); + while (it != d->values.constEnd()) { + if ((*it).first.toLower() == lowercaseKey) + return true; + ++it; + } + return false; +} + +/*! + Sets the value of the entry with the \a key to \a value. + + If no entry with \a key exists, a new entry with the given \a key + and \a value is created. If an entry with the \a key already + exists, the first value is discarded and replaced with the given + \a value. + + \sa value() hasKey() removeValue() +*/ +void QHttpHeader::setValue(const QString &key, const QString &value) +{ + Q_D(QHttpHeader); + QString lowercaseKey = key.toLower(); + QList >::Iterator it = d->values.begin(); + while (it != d->values.end()) { + if ((*it).first.toLower() == lowercaseKey) { + (*it).second = value; + return; + } + ++it; + } + // not found so add + addValue(key, value); +} + +/*! + Sets the header entries to be the list of key value pairs in \a values. +*/ +void QHttpHeader::setValues(const QList > &values) +{ + Q_D(QHttpHeader); + d->values = values; +} + +/*! + Adds a new entry with the \a key and \a value. +*/ +void QHttpHeader::addValue(const QString &key, const QString &value) +{ + Q_D(QHttpHeader); + d->values.append(qMakePair(key, value)); +} + +/*! + Returns all the entries in the header. +*/ +QList > QHttpHeader::values() const +{ + Q_D(const QHttpHeader); + return d->values; +} + +/*! + Removes the entry with the key \a key from the HTTP header. + + \sa value() setValue() +*/ +void QHttpHeader::removeValue(const QString &key) +{ + Q_D(QHttpHeader); + QString lowercaseKey = key.toLower(); + QList >::Iterator it = d->values.begin(); + while (it != d->values.end()) { + if ((*it).first.toLower() == lowercaseKey) { + d->values.erase(it); + return; + } + ++it; + } +} + +/*! + Removes all the entries with the key \a key from the HTTP header. +*/ +void QHttpHeader::removeAllValues(const QString &key) +{ + Q_D(QHttpHeader); + QString lowercaseKey = key.toLower(); + QList >::Iterator it = d->values.begin(); + while (it != d->values.end()) { + if ((*it).first.toLower() == lowercaseKey) { + it = d->values.erase(it); + continue; + } + ++it; + } +} + +/*! \internal + Parses the single HTTP header line \a line which has the format + key, colon, space, value, and adds key/value to the headers. The + linenumber is \a number. Returns true if the line was successfully + parsed and the key/value added; otherwise returns false. + + \sa parse() +*/ +bool QHttpHeader::parseLine(const QString &line, int) +{ + int i = line.indexOf(QLatin1Char(':')); + if (i == -1) + return false; + + addValue(line.left(i).trimmed(), line.mid(i + 1).trimmed()); + + return true; +} + +/*! + Returns a string representation of the HTTP header. + + The string is suitable for use by the constructor that takes a + QString. It consists of lines with the format: key, colon, space, + value, "\r\n". +*/ +QString QHttpHeader::toString() const +{ + Q_D(const QHttpHeader); + if (!isValid()) + return QLatin1String(""); + + QString ret = QLatin1String(""); + + QList >::ConstIterator it = d->values.constBegin(); + while (it != d->values.constEnd()) { + ret += (*it).first + QLatin1String(": ") + (*it).second + QLatin1String("\r\n"); + ++it; + } + return ret; +} + +/*! + Returns true if the header has an entry for the special HTTP + header field \c content-length; otherwise returns false. + + \sa contentLength() setContentLength() +*/ +bool QHttpHeader::hasContentLength() const +{ + return hasKey(QLatin1String("content-length")); +} + +/*! + Returns the value of the special HTTP header field \c + content-length. + + \sa setContentLength() hasContentLength() +*/ +uint QHttpHeader::contentLength() const +{ + return value(QLatin1String("content-length")).toUInt(); +} + +/*! + Sets the value of the special HTTP header field \c content-length + to \a len. + + \sa contentLength() hasContentLength() +*/ +void QHttpHeader::setContentLength(int len) +{ + setValue(QLatin1String("content-length"), QString::number(len)); +} + +/*! + Returns true if the header has an entry for the special HTTP + header field \c content-type; otherwise returns false. + + \sa contentType() setContentType() +*/ +bool QHttpHeader::hasContentType() const +{ + return hasKey(QLatin1String("content-type")); +} + +/*! + Returns the value of the special HTTP header field \c content-type. + + \sa setContentType() hasContentType() +*/ +QString QHttpHeader::contentType() const +{ + QString type = value(QLatin1String("content-type")); + if (type.isEmpty()) + return QString(); + + int pos = type.indexOf(QLatin1Char(';')); + if (pos == -1) + return type; + + return type.left(pos).trimmed(); +} + +/*! + Sets the value of the special HTTP header field \c content-type to + \a type. + + \sa contentType() hasContentType() +*/ +void QHttpHeader::setContentType(const QString &type) +{ + setValue(QLatin1String("content-type"), type); +} + +class QHttpResponseHeaderPrivate : public QHttpHeaderPrivate +{ + Q_DECLARE_PUBLIC(QHttpResponseHeader) +public: + int statCode; + QString reasonPhr; + int majVer; + int minVer; +}; + +/**************************************************** + * + * QHttpResponseHeader + * + ****************************************************/ + +/*! + \class QHttpResponseHeader + \obsolete + \brief The QHttpResponseHeader class contains response header information for HTTP. + + \ingroup network + \inmodule QtNetwork + + HTTP responses have a status code that indicates the status of the + response. This code is a 3-digit integer result code (for details + see to RFC 1945). In addition to the status code, you can also + specify a human-readable text that describes the reason for the + code ("reason phrase"). This class allows you to get the status + code and the reason phrase. + + \sa QHttpRequestHeader, {HTTP Example} +*/ + +/*! + Constructs an empty HTTP response header. +*/ +QHttpResponseHeader::QHttpResponseHeader() + : QHttpHeader(*new QHttpResponseHeaderPrivate) +{ + setValid(false); +} + +/*! + Constructs a copy of \a header. +*/ +QHttpResponseHeader::QHttpResponseHeader(const QHttpResponseHeader &header) + : QHttpHeader(*new QHttpResponseHeaderPrivate, header) +{ + Q_D(QHttpResponseHeader); + d->statCode = header.d_func()->statCode; + d->reasonPhr = header.d_func()->reasonPhr; + d->majVer = header.d_func()->majVer; + d->minVer = header.d_func()->minVer; +} + +/*! + Copies the contents of \a header into this QHttpResponseHeader. +*/ +QHttpResponseHeader &QHttpResponseHeader::operator=(const QHttpResponseHeader &header) +{ + Q_D(QHttpResponseHeader); + QHttpHeader::operator=(header); + d->statCode = header.d_func()->statCode; + d->reasonPhr = header.d_func()->reasonPhr; + d->majVer = header.d_func()->majVer; + d->minVer = header.d_func()->minVer; + return *this; +} + +/*! + Constructs a HTTP response header from the string \a str. The + string is parsed and the information is set. The \a str should + consist of one or more "\r\n" delimited lines; the first line should be the + status-line (format: HTTP-version, space, status-code, space, + reason-phrase); each of remaining lines should have the format key, colon, + space, value. +*/ +QHttpResponseHeader::QHttpResponseHeader(const QString &str) + : QHttpHeader(*new QHttpResponseHeaderPrivate) +{ + parse(str); +} + +/*! + \since 4.1 + + Constructs a QHttpResponseHeader, setting the status code to \a code, the + reason phrase to \a text and the protocol-version to \a majorVer and \a + minorVer. + + \sa statusCode() reasonPhrase() majorVersion() minorVersion() +*/ +QHttpResponseHeader::QHttpResponseHeader(int code, const QString &text, int majorVer, int minorVer) + : QHttpHeader(*new QHttpResponseHeaderPrivate) +{ + setStatusLine(code, text, majorVer, minorVer); +} + +/*! + \since 4.1 + + Sets the status code to \a code, the reason phrase to \a text and + the protocol-version to \a majorVer and \a minorVer. + + \sa statusCode() reasonPhrase() majorVersion() minorVersion() +*/ +void QHttpResponseHeader::setStatusLine(int code, const QString &text, int majorVer, int minorVer) +{ + Q_D(QHttpResponseHeader); + setValid(true); + d->statCode = code; + d->reasonPhr = text; + d->majVer = majorVer; + d->minVer = minorVer; +} + +/*! + Returns the status code of the HTTP response header. + + \sa reasonPhrase() majorVersion() minorVersion() +*/ +int QHttpResponseHeader::statusCode() const +{ + Q_D(const QHttpResponseHeader); + return d->statCode; +} + +/*! + Returns the reason phrase of the HTTP response header. + + \sa statusCode() majorVersion() minorVersion() +*/ +QString QHttpResponseHeader::reasonPhrase() const +{ + Q_D(const QHttpResponseHeader); + return d->reasonPhr; +} + +/*! + Returns the major protocol-version of the HTTP response header. + + \sa minorVersion() statusCode() reasonPhrase() +*/ +int QHttpResponseHeader::majorVersion() const +{ + Q_D(const QHttpResponseHeader); + return d->majVer; +} + +/*! + Returns the minor protocol-version of the HTTP response header. + + \sa majorVersion() statusCode() reasonPhrase() +*/ +int QHttpResponseHeader::minorVersion() const +{ + Q_D(const QHttpResponseHeader); + return d->minVer; +} + +/*! \internal +*/ +bool QHttpResponseHeader::parseLine(const QString &line, int number) +{ + Q_D(QHttpResponseHeader); + if (number != 0) + return QHttpHeader::parseLine(line, number); + + QString l = line.simplified(); + if (l.length() < 10) + return false; + + if (l.left(5) == QLatin1String("HTTP/") && l[5].isDigit() && l[6] == QLatin1Char('.') && + l[7].isDigit() && l[8] == QLatin1Char(' ') && l[9].isDigit()) { + d->majVer = l[5].toLatin1() - '0'; + d->minVer = l[7].toLatin1() - '0'; + + int pos = l.indexOf(QLatin1Char(' '), 9); + if (pos != -1) { + d->reasonPhr = l.mid(pos + 1); + d->statCode = l.mid(9, pos - 9).toInt(); + } else { + d->statCode = l.mid(9).toInt(); + d->reasonPhr.clear(); + } + } else { + return false; + } + + return true; +} + +/*! \reimp +*/ +QString QHttpResponseHeader::toString() const +{ + Q_D(const QHttpResponseHeader); + QString ret(QLatin1String("HTTP/%1.%2 %3 %4\r\n%5\r\n")); + return ret.arg(d->majVer).arg(d->minVer).arg(d->statCode).arg(d->reasonPhr).arg(QHttpHeader::toString()); +} + +QT_END_NAMESPACE + +#endif diff --git a/src/network/access/qhttpheader_p.h b/src/network/access/qhttpheader_p.h new file mode 100644 index 0000000000..0d8b4fca13 --- /dev/null +++ b/src/network/access/qhttpheader_p.h @@ -0,0 +1,147 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtNetwork module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QHTTP_H +#define QHTTP_H + +#include +#include +#include +#include +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Network) + +#ifndef QT_NO_HTTP + +#if 0 +#pragma qt_class(QHttp) +#endif + +class QHttpHeaderPrivate; +class QHttpHeader +{ +public: + QHttpHeader(); + QHttpHeader(const QHttpHeader &header); + QHttpHeader(const QString &str); + virtual ~QHttpHeader(); + + QHttpHeader &operator=(const QHttpHeader &h); + + void setValue(const QString &key, const QString &value); + void setValues(const QList > &values); + void addValue(const QString &key, const QString &value); + QList > values() const; + bool hasKey(const QString &key) const; + QStringList keys() const; + QString value(const QString &key) const; + QStringList allValues(const QString &key) const; + void removeValue(const QString &key); + void removeAllValues(const QString &key); + + // ### Qt 5: change to qint64 + bool hasContentLength() const; + uint contentLength() const; + void setContentLength(int len); + + bool hasContentType() const; + QString contentType() const; + void setContentType(const QString &type); + + virtual QString toString() const; + bool isValid() const; + + virtual int majorVersion() const = 0; + virtual int minorVersion() const = 0; + +protected: + virtual bool parseLine(const QString &line, int number); + bool parse(const QString &str); + void setValid(bool); + + QHttpHeader(QHttpHeaderPrivate &dd, const QString &str = QString()); + QHttpHeader(QHttpHeaderPrivate &dd, const QHttpHeader &header); + QScopedPointer d_ptr; + +private: + Q_DECLARE_PRIVATE(QHttpHeader) +}; + +class QHttpResponseHeaderPrivate; +class QHttpResponseHeader : public QHttpHeader +{ +public: + QHttpResponseHeader(); + QHttpResponseHeader(const QHttpResponseHeader &header); + QHttpResponseHeader(const QString &str); + QHttpResponseHeader(int code, const QString &text = QString(), int majorVer = 1, int minorVer = 1); + QHttpResponseHeader &operator=(const QHttpResponseHeader &header); + + void setStatusLine(int code, const QString &text = QString(), int majorVer = 1, int minorVer = 1); + + int statusCode() const; + QString reasonPhrase() const; + + int majorVersion() const; + int minorVersion() const; + + QString toString() const; + +protected: + bool parseLine(const QString &line, int number); + +private: + Q_DECLARE_PRIVATE(QHttpResponseHeader) + friend class QHttpPrivate; +}; + +#endif // QT_NO_HTTP + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QHTTP_H diff --git a/src/network/access/qhttpnetworkconnection.cpp b/src/network/access/qhttpnetworkconnection.cpp index c9a41176d6..104a21f591 100644 --- a/src/network/access/qhttpnetworkconnection.cpp +++ b/src/network/access/qhttpnetworkconnection.cpp @@ -53,7 +53,6 @@ #include #include -#include #include #ifndef QT_NO_HTTP diff --git a/src/network/kernel/qauthenticator.cpp b/src/network/kernel/qauthenticator.cpp index fa5906a3ed..0a3dddbe28 100644 --- a/src/network/kernel/qauthenticator.cpp +++ b/src/network/kernel/qauthenticator.cpp @@ -45,7 +45,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/network/socket/qhttpsocketengine.cpp b/src/network/socket/qhttpsocketengine.cpp index 70ae40307e..e882f77dcd 100644 --- a/src/network/socket/qhttpsocketengine.cpp +++ b/src/network/socket/qhttpsocketengine.cpp @@ -43,7 +43,7 @@ #include "qtcpsocket.h" #include "qhostaddress.h" #include "qurl.h" -#include "qhttp.h" +#include "private/qhttpheader_p.h" #include "qelapsedtimer.h" #include "qnetworkinterface.h" diff --git a/src/tools/uic/qclass_lib_map.h b/src/tools/uic/qclass_lib_map.h index d4a6c2c96c..030be12076 100644 --- a/src/tools/uic/qclass_lib_map.h +++ b/src/tools/uic/qclass_lib_map.h @@ -398,10 +398,8 @@ QT_CLASS_LIB(QXmlStreamWriter, QtXml, qxmlstream.h) QT_CLASS_LIB(QNetworkCacheMetaData, QtNetwork, qabstractnetworkcache.h) QT_CLASS_LIB(QAbstractNetworkCache, QtNetwork, qabstractnetworkcache.h) QT_CLASS_LIB(QFtp, QtNetwork, qftp.h) -QT_CLASS_LIB(QHttpHeader, QtNetwork, qhttp.h) -QT_CLASS_LIB(QHttpResponseHeader, QtNetwork, qhttp.h) -QT_CLASS_LIB(QHttpRequestHeader, QtNetwork, qhttp.h) -QT_CLASS_LIB(QHttp, QtNetwork, qhttp.h) +QT_CLASS_LIB(QHttpHeader, QtNetwork, qhttpheader_p.h) +QT_CLASS_LIB(QHttpResponseHeader, QtNetwork, qhttpheader_p.h) QT_CLASS_LIB(QNetworkAccessManager, QtNetwork, qnetworkaccessmanager.h) QT_CLASS_LIB(QNetworkCookie, QtNetwork, qnetworkcookie.h) QT_CLASS_LIB(QNetworkCookieJar, QtNetwork, qnetworkcookiejar.h) diff --git a/tests/auto/network/access/access.pro b/tests/auto/network/access/access.pro index 53b16f07b8..69ed189712 100644 --- a/tests/auto/network/access/access.pro +++ b/tests/auto/network/access/access.pro @@ -10,7 +10,6 @@ SUBDIRS=\ qnetworkcachemetadata \ qftp \ qhttpnetworkreply \ - qhttp \ qabstractnetworkcache \ !contains(QT_CONFIG, private_tests): SUBDIRS -= \ diff --git a/tests/auto/network/access/qhttp/.gitattributes b/tests/auto/network/access/qhttp/.gitattributes deleted file mode 100644 index e04709aa2e..0000000000 --- a/tests/auto/network/access/qhttp/.gitattributes +++ /dev/null @@ -1 +0,0 @@ -rfc3252.txt -crlf diff --git a/tests/auto/network/access/qhttp/.gitignore b/tests/auto/network/access/qhttp/.gitignore deleted file mode 100644 index 00c1f492cd..0000000000 --- a/tests/auto/network/access/qhttp/.gitignore +++ /dev/null @@ -1 +0,0 @@ -tst_qhttp diff --git a/tests/auto/network/access/qhttp/dummyserver.h b/tests/auto/network/access/qhttp/dummyserver.h deleted file mode 100644 index 644ae4a2ba..0000000000 --- a/tests/auto/network/access/qhttp/dummyserver.h +++ /dev/null @@ -1,114 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the test suite of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** This file may be used under the terms of the GNU Lesser General Public -** License version 2.1 as published by the Free Software Foundation and -** appearing in the file LICENSE.LGPL included in the packaging of this -** file. Please review the following information to ensure the GNU Lesser -** General Public License version 2.1 requirements will be met: -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ -// Use if you need - -class DummyHttpServer : public QTcpServer -{ - Q_OBJECT -public: - DummyHttpServer() : phase(Header) - { listen(); } - -protected: - enum { - Header, - Data1, - Data2, - Close - } phase; - void incomingConnection(int socketDescriptor) - { - QSslSocket *socket = new QSslSocket(this); - socket->setSocketDescriptor(socketDescriptor, QAbstractSocket::ConnectedState); - socket->ignoreSslErrors(); - socket->startServerEncryption(); - connect(socket, SIGNAL(readyRead()), SLOT(handleReadyRead())); - } - -public slots: - void handleReadyRead() - { - QTcpSocket *socket = static_cast(sender()); - socket->readAll(); - if (phase != Header) - return; - - phase = Data1; - static const char header[] = - "HTTP/1.0 200 OK\r\n" - "Date: Fri, 07 Sep 2007 12:33:18 GMT\r\n" - "Server: Apache\r\n" - "Expires:\r\n" - "Cache-Control:\r\n" - "Pragma:\r\n" - "Last-Modified: Thu, 06 Sep 2007 08:52:06 +0000\r\n" - "Etag: a700f59a6ccb1ad39af68d998aa36fb1\r\n" - "Vary: Accept-Encoding\r\n" - "Content-Length: 6560\r\n" - "Connection: close\r\n" - "Content-Type: text/html; charset=utf-8\r\n" - "\r\n"; - - - socket->write(header, sizeof header - 1); - connect(socket, SIGNAL(bytesWritten(qint64)), SLOT(handleBytesWritten()), Qt::QueuedConnection); - } - - void handleBytesWritten() - { - QTcpSocket *socket = static_cast(sender()); - if (socket->bytesToWrite() != 0) - return; - - if (phase == Data1) { - QByteArray data(4096, 'a'); - socket->write(data); - phase = Data2; - } else if (phase == Data2) { - QByteArray data(2464, 'a'); - socket->write(data); - phase = Close; - } else { - //socket->disconnectFromHost(); - //socket->deleteLater(); - } - } -}; diff --git a/tests/auto/network/access/qhttp/qhttp.pro b/tests/auto/network/access/qhttp/qhttp.pro deleted file mode 100644 index d672eb6009..0000000000 --- a/tests/auto/network/access/qhttp/qhttp.pro +++ /dev/null @@ -1,23 +0,0 @@ -CONFIG += testcase -TARGET = tst_qhttp -SOURCES += tst_qhttp.cpp - - -QT = core network testlib - -wince*: { - webFiles.files = webserver/* - webFiles.path = webserver - cgi.files = webserver/cgi-bin/* - cgi.path = webserver/cgi-bin - addFiles.files = rfc3252.txt testhtml - addFiles.path = . - DEPLOYMENT += addFiles webFiles cgi - DEFINES += SRCDIR=\\\"\\\" -} else:vxworks*: { - DEFINES += SRCDIR=\\\"\\\" -} else { - DEFINES += SRCDIR=\\\"$$PWD/\\\" -} - -CONFIG+=insignificant_test diff --git a/tests/auto/network/access/qhttp/rfc3252.txt b/tests/auto/network/access/qhttp/rfc3252.txt deleted file mode 100644 index b80c61bf0a..0000000000 --- a/tests/auto/network/access/qhttp/rfc3252.txt +++ /dev/null @@ -1,899 +0,0 @@ - - - - - - -Network Working Group H. Kennedy -Request for Comments: 3252 Mimezine -Category: Informational 1 April 2002 - - - Binary Lexical Octet Ad-hoc Transport - -Status of this Memo - - This memo provides information for the Internet community. It does - not specify an Internet standard of any kind. Distribution of this - memo is unlimited. - -Copyright Notice - - Copyright (C) The Internet Society (2002). All Rights Reserved. - -Abstract - - This document defines a reformulation of IP and two transport layer - protocols (TCP and UDP) as XML applications. - -1. Introduction - -1.1. Overview - - This document describes the Binary Lexical Octet Ad-hoc Transport - (BLOAT): a reformulation of a widely-deployed network-layer protocol - (IP [RFC791]), and two associated transport layer protocols (TCP - [RFC793] and UDP [RFC768]) as XML [XML] applications. It also - describes methods for transporting BLOAT over Ethernet and IEEE 802 - networks as well as encapsulating BLOAT in IP for gatewaying BLOAT - across the public Internet. - -1.2. Motivation - - The wild popularity of XML as a basis for application-level protocols - such as the Blocks Extensible Exchange Protocol [RFC3080], the Simple - Object Access Protocol [SOAP], and Jabber [JABBER] prompted - investigation into the possibility of extending the use of XML in the - protocol stack. Using XML at both the transport and network layer in - addition to the application layer would provide for an amazing amount - of power and flexibility while removing dependencies on proprietary - and hard-to-understand binary protocols. This protocol unification - would also allow applications to use a single XML parser for all - aspects of their operation, eliminating developer time spent figuring - out the intricacies of each new protocol, and moving the hard work of - - - - -Kennedy Informational [Page 1] - -RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 - - - parsing to the XML toolset. The use of XML also mitigates concerns - over "network vs. host" byte ordering which is at the root of many - network application bugs. - -1.3. Relation to Existing Protocols - - The reformulations specified in this RFC follow as closely as - possible the spirit of the RFCs on which they are based, and so MAY - contain elements or attributes that would not be needed in a pure - reworking (e.g. length attributes, which are implicit in XML.) - - The layering of network and transport protocols are maintained in - this RFC despite the optimizations that could be made if the line - were somewhat blurred (i.e. merging TCP and IP into a single, larger - element in the DTD) in order to foster future use of this protocol as - a basis for reformulating other protocols (such as ICMP.) - - Other than the encoding, the behavioral aspects of each of the - existing protocols remain unchanged. Routing, address spaces, TCP - congestion control, etc. behave as specified in the extant standards. - Adapting to new standards and experimental algorithm heuristics for - improving performance will become much easier once the move to BLOAT - has been completed. - -1.4. Requirement Levels - - The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", - "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this - document are to be interpreted as described in BCP 14, RFC 2119 - [RFC2119]. - -2. IPoXML - - This protocol MUST be implemented to be compliant with this RFC. - IPoXML is the root protocol REQUIRED for effective use of TCPoXML - (section 3.) and higher-level application protocols. - - The DTD for this document type can be found in section 7.1. - - The routing of IPoXML can be easily implemented on hosts with an XML - parser, as the regular structure lends itself handily to parsing and - validation of the document/datagram and then processing the - destination address, TTL, and checksum before sending it on to its - next-hop. - - The reformulation of IPv4 was chosen over IPv6 [RFC2460] due to the - wider deployment of IPv4 and the fact that implementing IPv6 as XML - would have exceeded the 1500 byte Ethernet MTU. - - - -Kennedy Informational [Page 2] - -RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 - - - All BLOAT implementations MUST use - and specify - the UTF-8 encoding - of RFC 2279 [RFC2279]. All BLOAT document/datagrams MUST be well- - formed and include the XMLDecl. - -2.1. IP Description - - A number of items have changed (for the better) from the original IP - specification. Bit-masks, where present have been converted into - human-readable values. IP addresses are listed in their dotted- - decimal notation [RFC1123]. Length and checksum values are present - as decimal integers. - - To calculate the length and checksum fields of the IP element, a - canonicalized form of the element MUST be used. The canonical form - SHALL have no whitespace (including newline characters) between - elements and only one space character between attributes. There - SHALL NOT be a space following the last attribute in an element. - - An iterative method SHOULD be used to calculate checksums, as the - length field will vary based on the size of the checksum. - - The payload element bears special attention. Due to the character - set restrictions of XML, the payload of IP datagrams (which MAY - contain arbitrary data) MUST be encoded for transport. This RFC - REQUIRES the contents of the payload to be encoded in the base-64 - encoding of RFC 2045 [RFC2045], but removes the requirement that the - encoded output MUST be wrapped on 76-character lines. - - - - - - - - - - - - - - - - - - - - - - - - -Kennedy Informational [Page 3] - -RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 - - -2.2. Example Datagram - - The following is an example IPoXML datagram with an empty payload: - - - - -
- - - - - - - - - - - - - - - -
- - -
- -3. TCPoXML - - This protocol MUST be implemented to be compliant with this RFC. The - DTD for this document type can be found in section 7.2. - -3.1. TCP Description - - A number of items have changed from the original TCP specification. - Bit-masks, where present have been converted into human-readable - values. Length and checksum and port values are present as decimal - integers. - - To calculate the length and checksum fields of the TCP element, a - canonicalized form of the element MUST be used as in section 2.1. - - An iterative method SHOULD be used to calculate checksums as in - section 2.1. - - The payload element MUST be encoded as in section 2.1. - - - -Kennedy Informational [Page 4] - -RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 - - - The TCP offset element was expanded to a maximum of 255 from 16 to - allow for the increased size of the header in XML. - - TCPoXML datagrams encapsulated by IPoXML MAY omit the header - as well as the declaration. - -3.2. Example Datagram - - The following is an example TCPoXML datagram with an empty payload: - - - - - - - - - - - - - - - - - - - - - - - - -4. UDPoXML - - This protocol MUST be implemented to be compliant with this RFC. The - DTD for this document type can be found in section 7.3. - -4.1. UDP Description - - A number of items have changed from the original UDP specification. - Bit-masks, where present have been converted into human-readable - values. Length and checksum and port values are present as decimal - integers. - - - - - - - -Kennedy Informational [Page 5] - -RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 - - - To calculate the length and checksum fields of the UDP element, a - canonicalized form of the element MUST be used as in section 2.1. An - iterative method SHOULD be used to calculate checksums as in section - 2.1. - - The payload element MUST be encoded as in section 2.1. - - UDPoXML datagrams encapsulated by IPoXML MAY omit the header - as well as the declaration. - -4.2. Example Datagram - - The following is an example UDPoXML datagram with an empty payload: - - - - - - - - - - - - - - -5. Network Transport - - This document provides for the transmission of BLOAT datagrams over - two common families of physical layer transport. Future RFCs will - address additional transports as routing vendors catch up to the - specification, and we begin to see BLOAT routed across the Internet - backbone. - -5.1. Ethernet - - BLOAT is encapsulated in Ethernet datagrams as in [RFC894] with the - exception that the type field of the Ethernet frame MUST contain the - value 0xBEEF. The first 5 octets of the Ethernet frame payload will - be 0x3c 3f 78 6d 6c (" - --> - - - - -Kennedy Informational [Page 7] - -RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Kennedy Informational [Page 9] - -RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 - - - - - - - - - - - - - - - - - - - - - - - - -Kennedy Informational [Page 10] - -RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 - - - - - - - - - - - - - -7.2. TCPoXML DTD - - - - - - - - - - - - - - - - - -Kennedy Informational [Page 11] - -RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Kennedy Informational [Page 12] - -RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 - - - - - - - - - - - - - - - - - - - - -7.3. UDPoXML DTD - - - - - - - - - - - - - - - -Kennedy Informational [Page 13] - -RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 - - -8. Security Considerations - - XML, as a subset of SGML, has the same security considerations as - specified in SGML Media Types [RFC1874]. Security considerations - that apply to IP, TCP and UDP also likely apply to BLOAT as it does - not attempt to correct for issues not related to message format. - -9. References - - [JABBER] Miller, J., "Jabber", draft-miller-jabber-00.txt, - February 2002. (Work in Progress) - - [RFC768] Postel, J., "User Datagram Protocol", STD 6, RFC 768, - August 1980. - - [RFC791] Postel, J., "Internet Protocol", STD 5, RFC 791, - September 1981. - - [RFC793] Postel, J., "Transmission Control Protocol", STD 7, RFC - 793, September 1981. - - [RFC894] Hornig, C., "Standard for the Transmission of IP - Datagrams over Ethernet Networks.", RFC 894, April 1984. - - [RFC1042] Postel, J. and J. Reynolds, "Standard for the - Transmission of IP Datagrams Over IEEE 802 Networks", STD - 43, RFC 1042, February 1988. - - [RFC1123] Braden, R., "Requirements for Internet Hosts - - Application and Support", RFC 1123, October 1989. - - [RFC1874] Levinson, E., "SGML Media Types", RFC 1874, December - 1995. - - [RFC2003] Perkins, C., "IP Encapsulation within IP", RFC 2003, - October 1996. - - [RFC2045] Freed, N. and N. Borenstein, "Multipurpose Internet Mail - Extensions (MIME) Part One: Format of Internet Message - Bodies", RFC 2045, November 1996. - - [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate - Requirement Levels", BCP 14, RFC 2119, March 1997. - - [RFC2279] Yergeau, F., "UTF-8, a transformation format of ISO - 10646", RFC 2279, January 1998. - - - - - -Kennedy Informational [Page 14] - -RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 - - - [RFC2460] Deering, S. and R. Hinden, "Internet Protocol, Version 6 - (IPv6) Specification", RFC 2460, December 1998. - - [RFC3080] Rose, M., "The Blocks Extensible Exchange Protocol Core", - RFC 3080, March 2001. - - [SOAP] Box, D., Ehnebuske, D., Kakivaya, G., Layman, A., - Mendelsohn, N., Nielsen, H. F., Thatte, S. Winer, D., - "Simple Object Access Protocol (SOAP) 1.1" World Wide Web - Consortium Note, May 2000 http://www.w3.org/TR/SOAP/ - - [XML] Bray, T., Paoli, J., Sperberg-McQueen, C. M., "Extensible - Markup Language (XML)" World Wide Web Consortium - Recommendation REC- xml-19980210. - http://www.w3.org/TR/1998/REC-xml-19980210 - -10. Author's Address - - Hugh Kennedy - Mimezine - 1060 West Addison - Chicago, IL 60613 - USA - - EMail: kennedyh@engin.umich.edu - - - - - - - - - - - - - - - - - - - - - - - - - - -Kennedy Informational [Page 15] - -RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 - - -11. Full Copyright Statement - - Copyright (C) The Internet Society (2002). All Rights Reserved. - - This document and translations of it may be copied and furnished to - others, and derivative works that comment on or otherwise explain it - or assist in its implementation may be prepared, copied, published - and distributed, in whole or in part, without restriction of any - kind, provided that the above copyright notice and this paragraph are - included on all such copies and derivative works. However, this - document itself may not be modified in any way, such as by removing - the copyright notice or references to the Internet Society or other - Internet organizations, except as needed for the purpose of - developing Internet standards in which case the procedures for - copyrights defined in the Internet Standards process must be - followed, or as required to translate it into languages other than - English. - - The limited permissions granted above are perpetual and will not be - revoked by the Internet Society or its successors or assigns. - - This document and the information contained herein is provided on an - "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING - TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING - BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION - HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF - MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. - -Acknowledgement - - Funding for the RFC Editor function is currently provided by the - Internet Society. - - - - - - - - - - - - - - - - - - - -Kennedy Informational [Page 16] - diff --git a/tests/auto/network/access/qhttp/testhtml b/tests/auto/network/access/qhttp/testhtml deleted file mode 100644 index c155360e8d..0000000000 --- a/tests/auto/network/access/qhttp/testhtml +++ /dev/null @@ -1,8 +0,0 @@ - - - Test - - -

Test

- - diff --git a/tests/auto/network/access/qhttp/tst_qhttp.cpp b/tests/auto/network/access/qhttp/tst_qhttp.cpp deleted file mode 100644 index dd57aba85c..0000000000 --- a/tests/auto/network/access/qhttp/tst_qhttp.cpp +++ /dev/null @@ -1,1565 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the test suite of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** This file may be used under the terms of the GNU Lesser General Public -** License version 2.1 as published by the Free Software Foundation and -** appearing in the file LICENSE.LGPL included in the packaging of this -** file. Please review the following information to ensure the GNU Lesser -** General Public License version 2.1 requirements will be met: -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifndef QT_NO_OPENSSL -# include -#endif - -#include "../../../network-settings.h" - -Q_DECLARE_METATYPE(QHttpResponseHeader) - -class tst_QHttp : public QObject -{ - Q_OBJECT - -public: - tst_QHttp(); - virtual ~tst_QHttp(); - - -public slots: - void initTestCase_data(); - void initTestCase(); - void cleanupTestCase(); - void init(); - void cleanup(); -private slots: - void constructing(); - void invalidRequests(); - void get_data(); - void get(); - void head_data(); - void head(); - void post_data(); - void post(); - void request_data(); - void request(); - void authorization_data(); - void authorization(); - void proxy_data(); - void proxy(); - void proxy2(); - void proxy3(); - void postAuthNtlm(); -#ifndef QT_NO_OPENSSL - void proxyAndSsl(); - void cachingProxyAndSsl(); -#endif - void reconnect(); - void setSocket(); - void unexpectedRemoteClose(); - void pctEncodedPath(); - void caseInsensitiveKeys(); - void emptyBodyInReply(); - void abortInReadyRead(); - void abortInResponseHeaderReceived(); - void nestedEventLoop(); - void connectionClose(); - -protected slots: - void stateChanged( int ); - void responseHeaderReceived( const QHttpResponseHeader & ); - void readyRead( const QHttpResponseHeader& ); - void dataSendProgress( int, int ); - void dataReadProgress( int , int ); - - void requestStarted( int ); - void requestFinished( int, bool ); - void done( bool ); - - void reconnect_state(int state); - void proxy2_slot(); - void nestedEventLoop_slot(int id); - - void abortSender(); - void proxyAuthenticationRequired(const QNetworkProxy &, QAuthenticator *auth); - -private: - QHttp *newHttp(bool withAuth = false); - void addRequest( QHttpRequestHeader, int ); - bool headerAreEqual( const QHttpHeader&, const QHttpHeader& ); - - QHttp *http; - - struct RequestResult - { - QHttpRequestHeader req; - QHttpResponseHeader resp; - int success; - }; - QMap< int, RequestResult > resultMap; - typedef QMap::Iterator ResMapIt; - QList ids; // helper to make sure that all expected signals are emitted - - int current_id; - int cur_state; - int done_success; - - QByteArray readyRead_ba; - - int bytesTotalSend; - int bytesDoneSend; - int bytesTotalRead; - int bytesDoneRead; - - int getId; - int headId; - int postId; - - int reconnect_state_connect_count; - - bool connectionWithAuth; - bool proxyAuthCalled; -}; - -class ClosingServer: public QTcpServer -{ - Q_OBJECT -public: - ClosingServer() - { - connect(this, SIGNAL(newConnection()), SLOT(handleConnection())); - listen(); - } - -public slots: - void handleConnection() - { - delete nextPendingConnection(); - } -}; - -//#define DUMP_SIGNALS - -const int bytesTotal_init = -10; -const int bytesDone_init = -10; - -tst_QHttp::tst_QHttp() -{ -} - -tst_QHttp::~tst_QHttp() -{ -} - -void tst_QHttp::initTestCase_data() -{ - QTest::addColumn("setProxy"); - QTest::addColumn("proxyType"); - - QTest::newRow("WithoutProxy") << false << 0; - QTest::newRow("WithSocks5Proxy") << true << int(QNetworkProxy::Socks5Proxy); -} - -void tst_QHttp::initTestCase() -{ - QVERIFY(QtNetworkSettings::verifyTestNetworkSettings()); -} - -void tst_QHttp::cleanupTestCase() -{ -} - -void tst_QHttp::init() -{ - QFETCH_GLOBAL(bool, setProxy); - if (setProxy) { - QFETCH_GLOBAL(int, proxyType); - if (proxyType == QNetworkProxy::Socks5Proxy) { - QNetworkProxy::setApplicationProxy(QNetworkProxy(QNetworkProxy::Socks5Proxy, QtNetworkSettings::serverName(), 1080)); - } - } - - http = 0; - - resultMap.clear(); - ids.clear(); - - current_id = 0; - cur_state = QHttp::Unconnected; - done_success = -1; - - readyRead_ba = QByteArray(); - - getId = -1; - headId = -1; - postId = -1; -} - -void tst_QHttp::cleanup() -{ - delete http; - http = 0; - - QCoreApplication::processEvents(); - - QFETCH_GLOBAL(bool, setProxy); - if (setProxy) { - QNetworkProxy::setApplicationProxy(QNetworkProxy::DefaultProxy); - } -} - -void tst_QHttp::constructing() -{ - //QHeader - { - QHttpRequestHeader header; - header.addValue("key1", "val1"); - header.addValue("key2", "val2"); - header.addValue("key1", "val3"); - QCOMPARE(header.values().size(), 3); - QCOMPARE(header.allValues("key1").size(), 2); - QVERIFY(header.hasKey("key2")); - QCOMPARE(header.keys().count(), 2); - - } - - { - QHttpResponseHeader header(200); - } -} - -void tst_QHttp::invalidRequests() -{ - QHttp http; - http.setHost("localhost"); // we will not actually connect - - QTest::ignoreMessage(QtWarningMsg, "QHttp: empty path requested is invalid -- using '/'"); - http.get(QString()); - - QTest::ignoreMessage(QtWarningMsg, "QHttp: empty path requested is invalid -- using '/'"); - http.head(QString()); - - QTest::ignoreMessage(QtWarningMsg, "QHttp: empty path requested is invalid -- using '/'"); - http.post(QString(), QByteArray()); - - QTest::ignoreMessage(QtWarningMsg, "QHttp: empty path requested is invalid -- using '/'"); - http.request(QHttpRequestHeader("PROPFIND", QString())); -} - -void tst_QHttp::get_data() -{ - QTest::addColumn("host"); - QTest::addColumn("port"); - QTest::addColumn("path"); - QTest::addColumn("success"); - QTest::addColumn("statusCode"); - QTest::addColumn("res"); - QTest::addColumn("useIODevice"); - - // ### move this into external testdata - QFile file( SRCDIR "rfc3252.txt" ); - QVERIFY( file.open( QIODevice::ReadOnly ) ); - QByteArray rfc3252 = file.readAll(); - file.close(); - - file.setFileName( SRCDIR "testhtml" ); - QVERIFY( file.open( QIODevice::ReadOnly ) ); - QByteArray testhtml = file.readAll(); - file.close(); - - // test the two get() modes in one routine - for ( int i=0; i<2; i++ ) { - QTest::newRow(QString("path_01_%1").arg(i).toLatin1()) << QtNetworkSettings::serverName() << 80u - << QString("/qtest/rfc3252.txt") << 1 << 200 << rfc3252 << (bool)(i==1); - QTest::newRow( QString("path_02_%1").arg(i).toLatin1() ) << QString("www.ietf.org") << 80u - << QString("/rfc/rfc3252.txt") << 1 << 200 << rfc3252 << (bool)(i==1); - - QTest::newRow( QString("uri_01_%1").arg(i).toLatin1() ) << QtNetworkSettings::serverName() << 80u - << QString("http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt") << 1 << 200 << rfc3252 << (bool)(i==1); - QTest::newRow( QString("uri_02_%1").arg(i).toLatin1() ) << "www.ietf.org" << 80u - << QString("http://www.ietf.org/rfc/rfc3252.txt") << 1 << 200 << rfc3252 << (bool)(i==1); - - QTest::newRow( QString("fail_01_%1").arg(i).toLatin1() ) << QString("this-host-will-not-exist.") << 80u - << QString("/qtest/rfc3252.txt") << 0 << 0 << QByteArray() << (bool)(i==1); - - QTest::newRow( QString("failprot_01_%1").arg(i).toLatin1() ) << QtNetworkSettings::serverName() << 80u - << QString("/t") << 1 << 404 << QByteArray() << (bool)(i==1); - QTest::newRow( QString("failprot_02_%1").arg(i).toLatin1() ) << QtNetworkSettings::serverName() << 80u - << QString("qtest/rfc3252.txt") << 1 << 400 << QByteArray() << (bool)(i==1); - - // qt.nokia.com/doc uses transfer-encoding=chunked - /* qt.nokia.com/doc no longer seams to be using chuncked encodig. - QTest::newRow( QString("chunked_01_%1").arg(i).toLatin1() ) << QString("test.troll.no") << 80u - << QString("/") << 1 << 200 << testhtml << (bool)(i==1); - */ - QTest::newRow( QString("chunked_02_%1").arg(i).toLatin1() ) << QtNetworkSettings::serverName() << 80u - << QString("/qtest/cgi-bin/rfc.cgi") << 1 << 200 << rfc3252 << (bool)(i==1); - } -} - -void tst_QHttp::get() -{ - // for the overload that takes a QIODevice - QByteArray buf_ba; - QBuffer buf( &buf_ba ); - - QFETCH( QString, host ); - QFETCH( uint, port ); - QFETCH( QString, path ); - QFETCH( bool, useIODevice ); - - http = newHttp(); - QCOMPARE( http->currentId(), 0 ); - QCOMPARE( (int)http->state(), (int)QHttp::Unconnected ); - - addRequest( QHttpRequestHeader(), http->setHost( host, port ) ); - if ( useIODevice ) { - buf.open( QIODevice::WriteOnly ); - getId = http->get( path, &buf ); - } else { - getId = http->get( path ); - } - addRequest( QHttpRequestHeader(), getId ); - - QTestEventLoop::instance().enterLoop( 50 ); - - if ( QTestEventLoop::instance().timeout() ) - QFAIL( "Network operation timed out" ); - - ResMapIt res = resultMap.find( getId ); - QVERIFY( res != resultMap.end() ); - if ( res.value().success!=1 && host=="www.ietf.org" ) { - // The nightly tests fail from time to time. In order to make them more - // stable, add some debug output that might help locate the problem (I - // can't reproduce the problem in the non-nightly builds). - qDebug( "Error %d: %s", http->error(), http->errorString().toLatin1().constData() ); - } - QTEST( res.value().success, "success" ); - if ( res.value().success ) { - QTEST( res.value().resp.statusCode(), "statusCode" ); - - QFETCH( QByteArray, res ); - if ( res.count() > 0 ) { - if ( useIODevice ) { - QCOMPARE(buf_ba, res); - if ( bytesDoneRead != bytesDone_init ) - QVERIFY( (int)buf_ba.size() == bytesDoneRead ); - } else { - QCOMPARE(readyRead_ba, res); - if ( bytesDoneRead != bytesDone_init ) - QVERIFY( (int)readyRead_ba.size() == bytesDoneRead ); - } - } - QVERIFY( bytesTotalRead != bytesTotal_init ); - if ( bytesTotalRead > 0 ) - QVERIFY( bytesDoneRead == bytesTotalRead ); - } else { - QVERIFY( !res.value().resp.isValid() ); - } -} - -void tst_QHttp::head_data() -{ - QTest::addColumn("host"); - QTest::addColumn("port"); - QTest::addColumn("path"); - QTest::addColumn("success"); - QTest::addColumn("statusCode"); - QTest::addColumn("contentLength"); - - QTest::newRow( "path_01" ) << QtNetworkSettings::serverName() << 80u - << QString("/qtest/rfc3252.txt") << 1 << 200 << 25962u; - - QTest::newRow( "path_02" ) << QString("www.ietf.org") << 80u - << QString("/rfc/rfc3252.txt") << 1 << 200 << 25962u; - - QTest::newRow( "uri_01" ) << QtNetworkSettings::serverName() << 80u - << QString("http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt") << 1 << 200 << 25962u; - - QTest::newRow( "uri_02" ) << QString("www.ietf.org") << 80u - << QString("http://www.ietf.org/rfc/rfc3252.txt") << 1 << 200 << 25962u; - - QTest::newRow( "fail_01" ) << QString("this-host-will-not-exist.") << 80u - << QString("/qtest/rfc3252.txt") << 0 << 0 << 0u; - - QTest::newRow( "failprot_01" ) << QtNetworkSettings::serverName() << 80u - << QString("/t") << 1 << 404 << 0u; - - QTest::newRow( "failprot_02" ) << QtNetworkSettings::serverName() << 80u - << QString("qtest/rfc3252.txt") << 1 << 400 << 0u; - - /* qt.nokia.com/doc no longer seams to be using chuncked encodig. - QTest::newRow( "chunked_01" ) << QString("qt.nokia.com/doc") << 80u - << QString("/index.html") << 1 << 200 << 0u; - */ - QTest::newRow( "chunked_02" ) << QtNetworkSettings::serverName() << 80u - << QString("/qtest/cgi-bin/rfc.cgi") << 1 << 200 << 0u; -} - -void tst_QHttp::head() -{ - QFETCH( QString, host ); - QFETCH( uint, port ); - QFETCH( QString, path ); - - http = newHttp(); - QCOMPARE( http->currentId(), 0 ); - QCOMPARE( (int)http->state(), (int)QHttp::Unconnected ); - - addRequest( QHttpRequestHeader(), http->setHost( host, port ) ); - headId = http->head( path ); - addRequest( QHttpRequestHeader(), headId ); - - QTestEventLoop::instance().enterLoop( 30 ); - if ( QTestEventLoop::instance().timeout() ) - QFAIL( "Network operation timed out" ); - - ResMapIt res = resultMap.find( headId ); - QVERIFY( res != resultMap.end() ); - if ( res.value().success!=1 && host=="www.ietf.org" ) { - // The nightly tests fail from time to time. In order to make them more - // stable, add some debug output that might help locate the problem (I - // can't reproduce the problem in the non-nightly builds). - qDebug( "Error %d: %s", http->error(), http->errorString().toLatin1().constData() ); - } - QTEST( res.value().success, "success" ); - if ( res.value().success ) { - QTEST( res.value().resp.statusCode(), "statusCode" ); - QTEST( res.value().resp.contentLength(), "contentLength" ); - - QCOMPARE( (uint)readyRead_ba.size(), 0u ); - QVERIFY( bytesTotalRead == bytesTotal_init ); - QVERIFY( bytesDoneRead == bytesDone_init ); - } else { - QVERIFY( !res.value().resp.isValid() ); - } -} - -void tst_QHttp::post_data() -{ - QTest::addColumn("source"); - QTest::addColumn("useIODevice"); - QTest::addColumn("useProxy"); - QTest::addColumn("host"); - QTest::addColumn("port"); - QTest::addColumn("ssl"); - QTest::addColumn("path"); - QTest::addColumn("result"); - - QByteArray md5sum; - md5sum = "d41d8cd98f00b204e9800998ecf8427e"; - QTest::newRow("empty-data") - << QString() << false << false - << QtNetworkSettings::serverName() << 80 << false << "/qtest/cgi-bin/md5sum.cgi" << md5sum; - QTest::newRow("empty-device") - << QString() << true << false - << QtNetworkSettings::serverName() << 80 << false << "/qtest/cgi-bin/md5sum.cgi" << md5sum; - QTest::newRow("proxy-empty-data") - << QString() << false << true - << QtNetworkSettings::serverName() << 80 << false << "/qtest/cgi-bin/md5sum.cgi" << md5sum; - - md5sum = "b3e32ac459b99d3f59318f3ac31e4bee"; - QTest::newRow("data") << "rfc3252.txt" << false << false - << QtNetworkSettings::serverName() << 80 << false << "/qtest/cgi-bin/md5sum.cgi" - << md5sum; - QTest::newRow("device") << "rfc3252.txt" << true << false - << QtNetworkSettings::serverName() << 80 << false << "/qtest/cgi-bin/md5sum.cgi" - << md5sum; - QTest::newRow("proxy-data") << "rfc3252.txt" << false << true - << QtNetworkSettings::serverName() << 80 << false << "/qtest/cgi-bin/md5sum.cgi" - << md5sum; - -#ifndef QT_NO_OPENSSL - md5sum = "d41d8cd98f00b204e9800998ecf8427e"; - QTest::newRow("empty-data-ssl") - << QString() << false << false - << QtNetworkSettings::serverName() << 443 << true << "/qtest/cgi-bin/md5sum.cgi" << md5sum; - QTest::newRow("empty-device-ssl") - << QString() << true << false - << QtNetworkSettings::serverName() << 443 << true << "/qtest/cgi-bin/md5sum.cgi" << md5sum; - QTest::newRow("proxy-empty-data-ssl") - << QString() << false << true - << QtNetworkSettings::serverName() << 443 << true << "/qtest/cgi-bin/md5sum.cgi" << md5sum; - md5sum = "b3e32ac459b99d3f59318f3ac31e4bee"; - QTest::newRow("data-ssl") << "rfc3252.txt" << false << false - << QtNetworkSettings::serverName() << 443 << true << "/qtest/cgi-bin/md5sum.cgi" - << md5sum; - QTest::newRow("device-ssl") << "rfc3252.txt" << true << false - << QtNetworkSettings::serverName() << 443 << true << "/qtest/cgi-bin/md5sum.cgi" - << md5sum; - QTest::newRow("proxy-data-ssl") << "rfc3252.txt" << false << true - << QtNetworkSettings::serverName() << 443 << true << "/qtest/cgi-bin/md5sum.cgi" - << md5sum; -#endif - - // the following test won't work. See task 185996 -/* - QTest::newRow("proxy-device") << "rfc3252.txt" << true << true - << QtNetworkSettings::serverName() << 80 << "/qtest/cgi-bin/md5sum.cgi" - << md5sum; -*/ -} - -void tst_QHttp::post() -{ - QFETCH(QString, source); - QFETCH(bool, useIODevice); - QFETCH(bool, useProxy); - QFETCH(QString, host); - QFETCH(int, port); - QFETCH(bool, ssl); - QFETCH(QString, path); - - http = newHttp(useProxy); -#ifndef QT_NO_OPENSSL - QObject::connect(http, SIGNAL(sslErrors(const QList &)), - http, SLOT(ignoreSslErrors())); -#endif - QCOMPARE(http->currentId(), 0); - QCOMPARE((int)http->state(), (int)QHttp::Unconnected); - if (useProxy) - addRequest(QHttpRequestHeader(), http->setProxy(QtNetworkSettings::serverName(), 3129)); - addRequest(QHttpRequestHeader(), http->setHost(host, (ssl ? QHttp::ConnectionModeHttps : QHttp::ConnectionModeHttp), port)); - - // add the POST request - QFile file(SRCDIR + source); - QBuffer emptyBuffer; - QIODevice *dev; - if (!source.isEmpty()) { - QVERIFY(file.open(QIODevice::ReadOnly)); - dev = &file; - } else { - emptyBuffer.open(QIODevice::ReadOnly); - dev = &emptyBuffer; - } - - if (useIODevice) - postId = http->post(path, dev); - else - postId = http->post(path, dev->readAll()); - addRequest(QHttpRequestHeader(), postId); - - // run request - connect(http, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)), - SLOT(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*))); - QTestEventLoop::instance().enterLoop( 30 ); - - if ( QTestEventLoop::instance().timeout() ) - QFAIL( "Network operation timed out" ); - - ResMapIt res = resultMap.find(postId); - QVERIFY(res != resultMap.end()); - QVERIFY(res.value().success); - QCOMPARE(res.value().resp.statusCode(), 200); - QTEST(readyRead_ba.trimmed(), "result"); -} - -void tst_QHttp::request_data() -{ - QTest::addColumn("source"); - QTest::addColumn("useIODevice"); - QTest::addColumn("useProxy"); - QTest::addColumn("host"); - QTest::addColumn("port"); - QTest::addColumn("method"); - QTest::addColumn("path"); - QTest::addColumn("result"); - - QFile source(SRCDIR "rfc3252.txt"); - if (!source.open(QIODevice::ReadOnly)) - return; - - QByteArray contents = source.readAll(); - QByteArray md5sum = QCryptographicHash::hash(contents, QCryptographicHash::Md5).toHex() + '\n'; - QByteArray emptyMd5sum = "d41d8cd98f00b204e9800998ecf8427e\n"; - - QTest::newRow("head") << QString() << false << false << QtNetworkSettings::serverName() << 80 - << "HEAD" << "/qtest/rfc3252.txt" - << QByteArray(); - QTest::newRow("get") << QString() << false << false << QtNetworkSettings::serverName() << 80 - << "GET" << "/qtest/rfc3252.txt" - << contents; - QTest::newRow("post-empty-data") << QString() << false << false - << QtNetworkSettings::serverName() << 80 << "POST" << "/qtest/cgi-bin/md5sum.cgi" - << emptyMd5sum; - QTest::newRow("post-empty-device") << QString() << true << false - << QtNetworkSettings::serverName() << 80 << "POST" << "/qtest/cgi-bin/md5sum.cgi" - << emptyMd5sum; - QTest::newRow("post-data") << "rfc3252.txt" << false << false - << QtNetworkSettings::serverName() << 80 << "POST" << "/qtest/cgi-bin/md5sum.cgi" - << md5sum; - QTest::newRow("post-device") << "rfc3252.txt" << true << false - << QtNetworkSettings::serverName() << 80 << "POST" << "/qtest/cgi-bin/md5sum.cgi" - << md5sum; - - QTest::newRow("proxy-head") << QString() << false << true << QtNetworkSettings::serverName() << 80 - << "HEAD" << "/qtest/rfc3252.txt" - << QByteArray(); - QTest::newRow("proxy-get") << QString() << false << true << QtNetworkSettings::serverName() << 80 - << "GET" << "/qtest/rfc3252.txt" - << contents; - QTest::newRow("proxy-post-empty-data") << QString() << false << true - << QtNetworkSettings::serverName() << 80 << "POST" << "/qtest/cgi-bin/md5sum.cgi" - << emptyMd5sum; - QTest::newRow("proxy-post-data") << "rfc3252.txt" << false << true - << QtNetworkSettings::serverName() << 80 << "POST" << "/qtest/cgi-bin/md5sum.cgi" - << md5sum; - // the following test won't work. See task 185996 -/* - QTest::newRow("proxy-post-device") << "rfc3252.txt" << true << true - << QtNetworkSettings::serverName() << 80 << "POST" << "/qtest/cgi-bin/md5sum.cgi" - << md5sum; -*/ -} - -void tst_QHttp::request() -{ - QFETCH(QString, source); - QFETCH(bool, useIODevice); - QFETCH(bool, useProxy); - QFETCH(QString, host); - QFETCH(int, port); - QFETCH(QString, method); - QFETCH(QString, path); - - http = newHttp(useProxy); - QCOMPARE(http->currentId(), 0); - QCOMPARE((int)http->state(), (int)QHttp::Unconnected); - if (useProxy) - addRequest(QHttpRequestHeader(), http->setProxy(QtNetworkSettings::serverName(), 3129)); - addRequest(QHttpRequestHeader(), http->setHost(host, port)); - - QFile file(SRCDIR + source); - QBuffer emptyBuffer; - QIODevice *dev; - if (!source.isEmpty()) { - QVERIFY(file.open(QIODevice::ReadOnly)); - dev = &file; - } else { - emptyBuffer.open(QIODevice::ReadOnly); - dev = &emptyBuffer; - } - - // prepare the request - QHttpRequestHeader request; - request.setRequest(method, path, 1,1); - request.addValue("Host", host); - int *theId; - - if (method == "POST") - theId = &postId; - else if (method == "GET") - theId = &getId; - else if (method == "HEAD") - theId = &headId; - else - QFAIL("You're lazy! Please implement your test!"); - - // now send the request - if (useIODevice) - *theId = http->request(request, dev); - else - *theId = http->request(request, dev->readAll()); - addRequest(QHttpRequestHeader(), *theId); - - // run request - connect(http, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)), - SLOT(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*))); - QTestEventLoop::instance().enterLoop( 30 ); - - if ( QTestEventLoop::instance().timeout() ) - QFAIL( "Network operation timed out" ); - - ResMapIt res = resultMap.find(*theId); - QVERIFY(res != resultMap.end()); - QVERIFY(res.value().success); - QCOMPARE(res.value().resp.statusCode(), 200); - QTEST(readyRead_ba, "result"); -} - -void tst_QHttp::authorization_data() -{ - QTest::addColumn("host"); - QTest::addColumn("path"); - QTest::addColumn("user"); - QTest::addColumn("pass"); - QTest::addColumn("result"); - - QTest::newRow("correct password") << QtNetworkSettings::serverName() - << QString::fromLatin1("/qtest/rfcs-auth/index.html") - << QString::fromLatin1("httptest") - << QString::fromLatin1("httptest") - << 200; - - QTest::newRow("no password") << QtNetworkSettings::serverName() - << QString::fromLatin1("/qtest/rfcs-auth/index.html") - << QString::fromLatin1("") - << QString::fromLatin1("") - << 401; - - QTest::newRow("wrong password") << QtNetworkSettings::serverName() - << QString::fromLatin1("/qtest/rfcs-auth/index.html") - << QString::fromLatin1("maliciu0s") - << QString::fromLatin1("h4X0r") - << 401; -} - -void tst_QHttp::authorization() -{ - QFETCH(QString, host); - QFETCH(QString, path); - QFETCH(QString, user); - QFETCH(QString, pass); - QFETCH(int, result); - - QEventLoop loop; - - QHttp http; - connect(&http, SIGNAL(done(bool)), &loop, SLOT(quit())); - - if (!user.isEmpty()) - http.setUser(user, pass); - http.setHost(host); - int id = http.get(path); - Q_UNUSED(id); - - QTimer::singleShot(5000, &loop, SLOT(quit())); - loop.exec(); - - QCOMPARE(http.lastResponse().statusCode(), result); -} - -void tst_QHttp::proxy_data() -{ - QTest::addColumn("proxyhost"); - QTest::addColumn("port"); - QTest::addColumn("host"); - QTest::addColumn("path"); - QTest::addColumn("proxyuser"); - QTest::addColumn("proxypass"); - - QTest::newRow("qt-test-server") << QtNetworkSettings::serverName() << 3128 - << QString::fromLatin1("qt.nokia.com") << QString::fromLatin1("/") - << QString::fromLatin1("") << QString::fromLatin1(""); - QTest::newRow("qt-test-server pct") << QtNetworkSettings::serverName() << 3128 - << QString::fromLatin1("qt.nokia.com") << QString::fromLatin1("/%64eveloper") - << QString::fromLatin1("") << QString::fromLatin1(""); - QTest::newRow("qt-test-server-basic") << QtNetworkSettings::serverName() << 3129 - << QString::fromLatin1("qt.nokia.com") << QString::fromLatin1("/") - << QString::fromLatin1("qsockstest") << QString::fromLatin1("password"); - -#if 0 - // NTLM requires sending the same request three times for it to work - // the tst_QHttp class is too strict to handle the byte counts sent by dataSendProgress - // So don't run this test: - QTest::newRow("qt-test-server-ntlm") << QtNetworkSettings::serverName() << 3130 - << QString::fromLatin1("qt.nokia.com") << QString::fromLatin1("/") - << QString::fromLatin1("qsockstest") << QString::fromLatin1("password"); -#endif -} - -void tst_QHttp::proxy() -{ - QFETCH(QString, proxyhost); - QFETCH(int, port); - QFETCH(QString, host); - QFETCH(QString, path); - QFETCH(QString, proxyuser); - QFETCH(QString, proxypass); - - http = newHttp(!proxyuser.isEmpty()); - - QCOMPARE(http->currentId(), 0); - QCOMPARE((int)http->state(), (int)QHttp::Unconnected); - - addRequest(QHttpRequestHeader(), http->setProxy(proxyhost, port, proxyuser, proxypass)); - addRequest(QHttpRequestHeader(), http->setHost(host)); - getId = http->get(path); - addRequest(QHttpRequestHeader(), getId); - - QTestEventLoop::instance().enterLoop(30); - if (QTestEventLoop::instance().timeout()) - QFAIL("Network operation timed out"); - - ResMapIt res = resultMap.find(getId); - QVERIFY(res != resultMap.end()); - QVERIFY(res.value().success); - QCOMPARE(res.value().resp.statusCode(), 200); -} - -void tst_QHttp::proxy2() -{ - QFETCH_GLOBAL(bool, setProxy); - if (setProxy) - return; - - readyRead_ba.clear(); - - QHttp http; - http.setProxy(QtNetworkSettings::serverName(), 3128); - http.setHost(QtNetworkSettings::serverName()); - http.get("/index.html"); - http.get("/index.html"); - - connect(&http, SIGNAL(requestFinished(int, bool)), - this, SLOT(proxy2_slot())); - QTestEventLoop::instance().enterLoop(30); - QVERIFY(!QTestEventLoop::instance().timeout()); - - QCOMPARE(readyRead_ba.count("Welcome to qt-test-server"), 2); - - readyRead_ba.clear(); -} - -void tst_QHttp::proxy2_slot() -{ - QHttp *http = static_cast(sender()); - readyRead_ba.append(http->readAll()); - if (!http->hasPendingRequests()) - QTestEventLoop::instance().exitLoop(); -} - -void tst_QHttp::proxy3() -{ - QFETCH_GLOBAL(bool, setProxy); - if (setProxy) - return; - - readyRead_ba.clear(); - - QTcpSocket socket; - socket.setProxy(QNetworkProxy(QNetworkProxy::HttpProxy, QtNetworkSettings::serverName(), 3128)); - - QHttp http; - http.setSocket(&socket); - http.setHost(QtNetworkSettings::serverName()); - http.get("/index.html"); - http.get("/index.html"); - - connect(&http, SIGNAL(requestFinished(int, bool)), - this, SLOT(proxy2_slot())); - QTestEventLoop::instance().enterLoop(30); - QVERIFY(!QTestEventLoop::instance().timeout()); - - QCOMPARE(readyRead_ba.count("Welcome to qt-test-server"), 2); - - readyRead_ba.clear(); -} - -// test QHttp::currentId() and QHttp::currentRequest() -#define CURRENTREQUEST_TEST \ - { \ - ResMapIt res = resultMap.find( http->currentId() ); \ - QVERIFY( res != resultMap.end() ); \ - if ( http->currentId() == getId ) { \ - QCOMPARE( http->currentRequest().method(), QString("GET") ); \ - } else if ( http->currentId() == headId ) { \ - QCOMPARE( http->currentRequest().method(), QString("HEAD") ); \ - } else if ( http->currentId() == postId ) { \ - QCOMPARE( http->currentRequest().method(), QString("POST") ); \ - } else { \ - QVERIFY( headerAreEqual( http->currentRequest(), res.value().req ) ); \ - } \ - } - -void tst_QHttp::requestStarted( int id ) -{ -#if defined( DUMP_SIGNALS ) - qDebug( "%d:requestStarted( %d )", http->currentId(), id ); -#endif - // make sure that the requestStarted and requestFinished are nested correctly - QVERIFY( current_id == 0 ); - current_id = id; - - QVERIFY( !ids.isEmpty() ); - QVERIFY( ids.first() == id ); - if ( ids.count() > 1 ) { - QVERIFY( http->hasPendingRequests() ); - } else { - QVERIFY( !http->hasPendingRequests() ); - } - - QVERIFY( http->currentId() == id ); - QVERIFY( cur_state == http->state() ); - - - - - CURRENTREQUEST_TEST; - - QVERIFY( http->error() == QHttp::NoError ); -} - -void tst_QHttp::requestFinished( int id, bool error ) -{ -#if defined( DUMP_SIGNALS ) - qDebug( "%d:requestFinished( %d, %d ) -- errorString: '%s'", - http->currentId(), id, (int)error, http->errorString().toAscii().data() ); -#endif - // make sure that the requestStarted and requestFinished are nested correctly - QVERIFY( current_id == id ); - current_id = 0; - - QVERIFY( !ids.isEmpty() ); - QVERIFY( ids.first() == id ); - if ( ids.count() > 1 ) { - QVERIFY( http->hasPendingRequests() ); - } else { - QVERIFY( !http->hasPendingRequests() ); - } - - if ( error ) { - QVERIFY( http->error() != QHttp::NoError ); - ids.clear(); - } else { - QVERIFY( http->error() == QHttp::NoError ); - ids.pop_front(); - } - - QVERIFY( http->currentId() == id ); - QVERIFY( cur_state == http->state() ); - CURRENTREQUEST_TEST; - - ResMapIt res = resultMap.find( http->currentId() ); - QVERIFY( res != resultMap.end() ); - QVERIFY( res.value().success == -1 ); - if ( error ) - res.value().success = 0; - else - res.value().success = 1; -} - -void tst_QHttp::done( bool error ) -{ -#if defined( DUMP_SIGNALS ) - qDebug( "%d:done( %d )", http->currentId(), (int)error ); -#endif - QVERIFY( http->currentId() == 0 ); - QVERIFY( current_id == 0 ); - QVERIFY( ids.isEmpty() ); - QVERIFY( cur_state == http->state() ); - QVERIFY( !http->hasPendingRequests() ); - - QVERIFY( done_success == -1 ); - if ( error ) { - QVERIFY( http->error() != QHttp::NoError ); - done_success = 0; - } else { - QVERIFY( http->error() == QHttp::NoError ); - done_success = 1; - } - QTestEventLoop::instance().exitLoop(); -} - -void tst_QHttp::stateChanged( int state ) -{ -#if defined( DUMP_SIGNALS ) - qDebug( "%d: stateChanged( %d )", http->currentId(), state ); -#endif - QCOMPARE( http->currentId(), current_id ); - if ( ids.count() > 0 ) - CURRENTREQUEST_TEST; - - QVERIFY( state != cur_state ); - QVERIFY( state == http->state() ); - if ( state != QHttp::Unconnected && !connectionWithAuth ) { - // make sure that the states are always emitted in the right order (for - // this, we assume an ordering on the enum values, which they have at - // the moment) - // connections with authentication will possibly reconnect, so ignore them - QVERIFY( cur_state < state ); - } - cur_state = state; - - if (state == QHttp::Connecting) { - bytesTotalSend = bytesTotal_init; - bytesDoneSend = bytesDone_init; - bytesTotalRead = bytesTotal_init; - bytesDoneRead = bytesDone_init; - } -} - -void tst_QHttp::responseHeaderReceived( const QHttpResponseHeader &header ) -{ -#if defined( DUMP_SIGNALS ) - qDebug( "%d: responseHeaderReceived(\n---{\n%s}---)", http->currentId(), header.toString().toAscii().data() ); -#endif - QCOMPARE( http->currentId(), current_id ); - if ( ids.count() > 1 ) { - QVERIFY( http->hasPendingRequests() ); - } else { - QVERIFY( !http->hasPendingRequests() ); - } - CURRENTREQUEST_TEST; - - resultMap[ http->currentId() ].resp = header; -} - -void tst_QHttp::readyRead( const QHttpResponseHeader & ) -{ -#if defined( DUMP_SIGNALS ) - qDebug( "%d: readyRead()", http->currentId() ); -#endif - QCOMPARE( http->currentId(), current_id ); - if ( ids.count() > 1 ) { - QVERIFY( http->hasPendingRequests() ); - } else { - QVERIFY( !http->hasPendingRequests() ); - } - QVERIFY( cur_state == http->state() ); - CURRENTREQUEST_TEST; - - if ( QTest::currentTestFunction() != QLatin1String("bytesAvailable") ) { - int oldSize = readyRead_ba.size(); - quint64 bytesAvail = http->bytesAvailable(); - QByteArray ba = http->readAll(); - QVERIFY( (quint64) ba.size() == bytesAvail ); - readyRead_ba.resize( oldSize + ba.size() ); - memcpy( readyRead_ba.data()+oldSize, ba.data(), ba.size() ); - - if ( bytesTotalRead > 0 ) { - QVERIFY( (int)readyRead_ba.size() <= bytesTotalRead ); - } - QVERIFY( (int)readyRead_ba.size() == bytesDoneRead ); - } -} - -void tst_QHttp::dataSendProgress( int done, int total ) -{ -#if defined( DUMP_SIGNALS ) - qDebug( "%d: dataSendProgress( %d, %d )", http->currentId(), done, total ); -#endif - QCOMPARE( http->currentId(), current_id ); - if ( ids.count() > 1 ) { - QVERIFY( http->hasPendingRequests() ); - } else { - QVERIFY( !http->hasPendingRequests() ); - } - QVERIFY( cur_state == http->state() ); - CURRENTREQUEST_TEST; - - if ( bytesTotalSend == bytesTotal_init ) { - bytesTotalSend = total; - } else { - QCOMPARE( bytesTotalSend, total ); - } - - QVERIFY( bytesTotalSend != bytesTotal_init ); - QVERIFY( bytesDoneSend <= done ); - bytesDoneSend = done; - if ( bytesTotalSend > 0 ) { - QVERIFY( bytesDoneSend <= bytesTotalSend ); - } - - if ( QTest::currentTestFunction() == QLatin1String("abort") ) { - // ### it would be nice if we could specify in our testdata when to do - // the abort - if ( done >= total/100000 ) { - if ( ids.count() != 1 ) { - // do abort only once - int tmpId = ids.first(); - ids.clear(); - ids << tmpId; - http->abort(); - } - } - } -} - -void tst_QHttp::dataReadProgress( int done, int total ) -{ -#if defined( DUMP_SIGNALS ) - qDebug( "%d: dataReadProgress( %d, %d )", http->currentId(), done, total ); -#endif - QCOMPARE( http->currentId(), current_id ); - if ( ids.count() > 1 ) { - QVERIFY( http->hasPendingRequests() ); - } else { - QVERIFY( !http->hasPendingRequests() ); - } - QVERIFY( cur_state == http->state() ); - CURRENTREQUEST_TEST; - - if ( bytesTotalRead == bytesTotal_init ) - bytesTotalRead = total; - else { - QVERIFY( bytesTotalRead == total ); - } - - QVERIFY( bytesTotalRead != bytesTotal_init ); - QVERIFY( bytesDoneRead <= done ); - bytesDoneRead = done; - if ( bytesTotalRead > 0 ) { - QVERIFY( bytesDoneRead <= bytesTotalRead ); - } - - if ( QTest::currentTestFunction() == QLatin1String("abort") ) { - // ### it would be nice if we could specify in our testdata when to do - // the abort - if ( done >= total/100000 ) { - if ( ids.count() != 1 ) { - // do abort only once - int tmpId = ids.first(); - ids.clear(); - ids << tmpId; - http->abort(); - } - } - } -} - - -QHttp *tst_QHttp::newHttp(bool withAuth) -{ - QHttp *nHttp = new QHttp( 0 ); - connect( nHttp, SIGNAL(requestStarted(int)), - SLOT(requestStarted(int)) ); - connect( nHttp, SIGNAL(requestFinished(int,bool)), - SLOT(requestFinished(int,bool)) ); - connect( nHttp, SIGNAL(done(bool)), - SLOT(done(bool)) ); - connect( nHttp, SIGNAL(stateChanged(int)), - SLOT(stateChanged(int)) ); - connect( nHttp, SIGNAL(responseHeaderReceived(const QHttpResponseHeader&)), - SLOT(responseHeaderReceived(const QHttpResponseHeader&)) ); - connect( nHttp, SIGNAL(readyRead(const QHttpResponseHeader&)), - SLOT(readyRead(const QHttpResponseHeader&)) ); - connect( nHttp, SIGNAL(dataSendProgress(int,int)), - SLOT(dataSendProgress(int,int)) ); - connect( nHttp, SIGNAL(dataReadProgress(int,int)), - SLOT(dataReadProgress(int,int)) ); - - connectionWithAuth = withAuth; - return nHttp; -} - -void tst_QHttp::addRequest( QHttpRequestHeader header, int id ) -{ - ids << id; - RequestResult res; - res.req = header; - res.success = -1; - resultMap[ id ] = res; -} - -bool tst_QHttp::headerAreEqual( const QHttpHeader &h1, const QHttpHeader &h2 ) -{ - if ( !h1.isValid() ) - return !h2.isValid(); - if ( !h2.isValid() ) - return !h1.isValid(); - - return h1.toString() == h2.toString(); -} - - -void tst_QHttp::reconnect() -{ - reconnect_state_connect_count = 0; - - QHttp http; - - QObject::connect(&http, SIGNAL(stateChanged(int)), this, SLOT(reconnect_state(int))); - http.setHost("trolltech.com", 80); - http.get("/company/index.html"); - http.setHost("trolltech.com", 8080); - http.get("/company/index.html"); - - QTestEventLoop::instance().enterLoop(60); - if (QTestEventLoop::instance().timeout()) - QFAIL("Network operation timed out"); - - QCOMPARE(reconnect_state_connect_count, 1); - - QTestEventLoop::instance().enterLoop(60); - if (QTestEventLoop::instance().timeout()) - QFAIL("Network operation timed out"); - - QCOMPARE(reconnect_state_connect_count, 2); -} - -void tst_QHttp::reconnect_state(int state) -{ - if (state == QHttp::Connecting) { - ++reconnect_state_connect_count; - QTestEventLoop::instance().exitLoop(); - } -} - -void tst_QHttp::setSocket() -{ - QHttp *http = new QHttp; - QPointer replacementSocket = new QTcpSocket; - http->setSocket(replacementSocket); - QCoreApplication::processEvents(); - delete http; - QVERIFY(replacementSocket); - delete replacementSocket; -} - -class Server : public QTcpServer -{ - Q_OBJECT -public: - Server() - { - connect(this, SIGNAL(newConnection()), - this, SLOT(serveConnection())); - } - -private slots: - void serveConnection() - { - QTcpSocket *socket = nextPendingConnection(); - socket->write("HTTP/1.1 404 Not found\r\n" - "content-length: 4\r\n\r\nabcd"); - socket->disconnectFromHost(); - }; -}; - -void tst_QHttp::unexpectedRemoteClose() -{ - QFETCH_GLOBAL(int, proxyType); - if (proxyType == QNetworkProxy::Socks5Proxy) { - // This test doesn't make sense for SOCKS5 - return; - } - - Server server; - server.listen(); - QCoreApplication::instance()->processEvents(); - - QEventLoop loop; - QTimer::singleShot(3000, &loop, SLOT(quit())); - - QHttp http; - QObject::connect(&http, SIGNAL(done(bool)), &loop, SLOT(quit())); - QSignalSpy finishedSpy(&http, SIGNAL(requestFinished(int, bool))); - QSignalSpy doneSpy(&http, SIGNAL(done(bool))); - - http.setHost("localhost", server.serverPort()); - http.get("/"); - http.get("/"); - http.get("/"); - - loop.exec(); - - QCOMPARE(finishedSpy.count(), 4); - QVERIFY(!finishedSpy.at(1).at(1).toBool()); - QVERIFY(!finishedSpy.at(2).at(1).toBool()); - QVERIFY(!finishedSpy.at(3).at(1).toBool()); - QCOMPARE(doneSpy.count(), 1); - QVERIFY(!doneSpy.at(0).at(0).toBool()); -} - -void tst_QHttp::pctEncodedPath() -{ - QHttpRequestHeader header; - header.setRequest("GET", "/index.asp/a=%20&b=%20&c=%20"); - QCOMPARE(header.toString(), QString("GET /index.asp/a=%20&b=%20&c=%20 HTTP/1.1\r\n\r\n")); -} - -void tst_QHttp::caseInsensitiveKeys() -{ - QHttpResponseHeader header("HTTP/1.1 200 OK\r\nContent-Length: 213\r\nX-Been-There: True\r\nLocation: http://www.TrollTech.com/\r\n\r\n"); - QVERIFY(header.hasKey("Content-Length")); - QVERIFY(header.hasKey("X-Been-There")); - QVERIFY(header.hasKey("Location")); - QVERIFY(header.hasKey("content-length")); - QVERIFY(header.hasKey("x-been-there")); - QVERIFY(header.hasKey("location")); - QCOMPARE(header.value("Content-Length"), QString("213")); - QCOMPARE(header.value("X-Been-There"), QString("True")); - QCOMPARE(header.value("Location"), QString("http://www.TrollTech.com/")); - QCOMPARE(header.value("content-length"), QString("213")); - QCOMPARE(header.value("x-been-there"), QString("True")); - QCOMPARE(header.value("location"), QString("http://www.TrollTech.com/")); - QCOMPARE(header.allValues("location"), QStringList("http://www.TrollTech.com/")); - - header.addValue("Content-Length", "213"); - header.addValue("Content-Length", "214"); - header.addValue("Content-Length", "215"); - qDebug() << header.toString(); -} - -void tst_QHttp::proxyAuthenticationRequired(const QNetworkProxy &, QAuthenticator *auth) -{ - proxyAuthCalled = true; - auth->setUser("qsockstest"); - auth->setPassword("password"); -} - -void tst_QHttp::postAuthNtlm() -{ - QSKIP("NTLM not working"); - - QHostInfo info = QHostInfo::fromName(QHostInfo::localHostName()); - QByteArray postData("Hello World"); - QHttp http; - - http.setHost(QtNetworkSettings::serverName()); - http.setProxy(QtNetworkSettings::serverName(), 3130); - http.post("/", postData); - - proxyAuthCalled = false; - connect(&http, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)), - SLOT(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*))); - - QObject::connect(&http, SIGNAL(done(bool)), &QTestEventLoop::instance(), SLOT(exitLoop())); - QTestEventLoop::instance().enterLoop(3); - QObject::disconnect(&http, SIGNAL(done(bool)), &QTestEventLoop::instance(), SLOT(exitLoop())); - - QVERIFY(proxyAuthCalled); - QVERIFY(!QTestEventLoop::instance().timeout()); -}; - -#ifndef QT_NO_OPENSSL -void tst_QHttp::proxyAndSsl() -{ - QFETCH_GLOBAL(bool, setProxy); - if (setProxy) - return; - - QHttp http; - - http.setHost(QtNetworkSettings::serverName(), QHttp::ConnectionModeHttps); - http.setProxy(QNetworkProxy(QNetworkProxy::HttpProxy, QtNetworkSettings::serverName(), 3129)); - http.get("/"); - - proxyAuthCalled = false; - connect(&http, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)), - SLOT(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*))); - connect(&http, SIGNAL(sslErrors(QList)), - &http, SLOT(ignoreSslErrors())); - - QObject::connect(&http, SIGNAL(done(bool)), &QTestEventLoop::instance(), SLOT(exitLoop())); - QTestEventLoop::instance().enterLoop(3); - QObject::disconnect(&http, SIGNAL(done(bool)), &QTestEventLoop::instance(), SLOT(exitLoop())); - - QVERIFY(!QTestEventLoop::instance().timeout()); - QVERIFY(proxyAuthCalled); - - QHttpResponseHeader header = http.lastResponse(); - QVERIFY(header.isValid()); - QVERIFY(header.statusCode() < 400); // Should be 200, but as long as it's not an error, we're happy -} -#endif - -#ifndef QT_NO_OPENSSL -void tst_QHttp::cachingProxyAndSsl() -{ - QFETCH_GLOBAL(bool, setProxy); - if (setProxy) - return; - - QHttp http; - - http.setHost(QtNetworkSettings::serverName(), QHttp::ConnectionModeHttps); - http.setProxy(QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::serverName(), 3129)); - http.get("/"); - - proxyAuthCalled = false; - connect(&http, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)), - SLOT(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*))); - - QObject::connect(&http, SIGNAL(done(bool)), &QTestEventLoop::instance(), SLOT(exitLoop())); - QTestEventLoop::instance().enterLoop(3); - QObject::disconnect(&http, SIGNAL(done(bool)), &QTestEventLoop::instance(), SLOT(exitLoop())); - - QVERIFY(!QTestEventLoop::instance().timeout()); - QVERIFY(!proxyAuthCalled); // NOT called! QHttp should get a socket error - QVERIFY(http.state() != QHttp::Connected); - - QHttpResponseHeader header = http.lastResponse(); - QVERIFY(!header.isValid()); -} -#endif - -void tst_QHttp::emptyBodyInReply() -{ - // Note: if this test starts failing, please verify the date on the file - // returned by Apache on http://netiks.troll.no/ - // It is right now hard-coded to the date below - QHttp http; - http.setHost(QtNetworkSettings::serverName()); - - QHttpRequestHeader headers("GET", "/"); - headers.addValue("If-Modified-Since", "Sun, 16 Nov 2008 12:29:51 GMT"); - headers.addValue("Host", QtNetworkSettings::serverName()); - http.request(headers); - - QObject::connect(&http, SIGNAL(done(bool)), &QTestEventLoop::instance(), SLOT(exitLoop())); - QTestEventLoop::instance().enterLoop(10); - QObject::disconnect(&http, SIGNAL(done(bool)), &QTestEventLoop::instance(), SLOT(exitLoop())); - - QVERIFY(!QTestEventLoop::instance().timeout()); - - // check the reply - if (http.lastResponse().statusCode() != 304) { - qWarning() << http.lastResponse().statusCode() << qPrintable(http.lastResponse().reasonPhrase()); - qWarning() << "Last-Modified:" << qPrintable(http.lastResponse().value("last-modified")); - QFAIL("Server replied with the wrong status code; see warning output"); - } -} - -void tst_QHttp::abortSender() -{ - QHttp *http = qobject_cast(sender()); - if (http) - http->abort(); -} - -void tst_QHttp::abortInReadyRead() -{ - QHttp http; - http.setHost(QtNetworkSettings::serverName()); - http.get("/qtest/bigfile"); - - qRegisterMetaType(); - QSignalSpy spy(&http, SIGNAL(readyRead(QHttpResponseHeader))); - - QObject::connect(&http, SIGNAL(readyRead(QHttpResponseHeader)), this, SLOT(abortSender())); - QObject::connect(&http, SIGNAL(done(bool)), &QTestEventLoop::instance(), SLOT(exitLoop())); - QTestEventLoop::instance().enterLoop(10); - QObject::disconnect(&http, SIGNAL(done(bool)), &QTestEventLoop::instance(), SLOT(exitLoop())); - - QVERIFY2(!QTestEventLoop::instance().timeout(), "Network timeout"); - QVERIFY(http.state() != QHttp::Connected); - - QCOMPARE(spy.count(), 1); -} - -void tst_QHttp::abortInResponseHeaderReceived() -{ - QHttp http; - http.setHost(QtNetworkSettings::serverName()); - http.get("/qtest/bigfile"); - - qRegisterMetaType(); - QSignalSpy spy(&http, SIGNAL(readyRead(QHttpResponseHeader))); - - QObject::connect(&http, SIGNAL(responseHeaderReceived(QHttpResponseHeader)), this, SLOT(abortSender())); - QObject::connect(&http, SIGNAL(done(bool)), &QTestEventLoop::instance(), SLOT(exitLoop())); - QTestEventLoop::instance().enterLoop(10); - QObject::disconnect(&http, SIGNAL(done(bool)), &QTestEventLoop::instance(), SLOT(exitLoop())); - - QVERIFY2(!QTestEventLoop::instance().timeout(), "Network timeout"); - QVERIFY(http.state() != QHttp::Connected); - - QCOMPARE(spy.count(), 0); -} - -void tst_QHttp::connectionClose() -{ - // This was added in response to bug 176822 - QFETCH_GLOBAL(bool, setProxy); - if (setProxy) - return; - - QHttp http; - ClosingServer server; - http.setHost("localhost", QHttp::ConnectionModeHttps, server.serverPort()); - http.get("/login/gateway/processLogin"); - - // another possibility: - //http.setHost("nexus.passport.com", QHttp::ConnectionModeHttps, 443); - //http.get("/rdr/pprdr.asp"); - - QObject::connect(&http, SIGNAL(done(bool)), &QTestEventLoop::instance(), SLOT(exitLoop())); - QTestEventLoop::instance().enterLoop(900); - QObject::disconnect(&http, SIGNAL(done(bool)), &QTestEventLoop::instance(), SLOT(exitLoop())); - - QVERIFY(!QTestEventLoop::instance().timeout()); -} - -void tst_QHttp::nestedEventLoop_slot(int id) -{ - if (!ids.contains(id)) - return; - QEventLoop subloop; - - // 16 seconds: fluke times out in 15 seconds, which triggers a QTcpSocket error - QTimer::singleShot(16000, &subloop, SLOT(quit())); - subloop.exec(); - - QTestEventLoop::instance().exitLoop(); -} - -void tst_QHttp::nestedEventLoop() -{ - QFETCH_GLOBAL(bool, setProxy); - if (setProxy) - return; - - http = new QHttp; - http->setHost(QtNetworkSettings::serverName()); - int getId = http->get("/"); - - ids.clear(); - ids << getId; - - QSignalSpy spy(http, SIGNAL(requestStarted(int))); - QSignalSpy spy2(http, SIGNAL(done(bool))); - - connect(http, SIGNAL(requestFinished(int,bool)), SLOT(nestedEventLoop_slot(int))); - QTestEventLoop::instance().enterLoop(20); - - QVERIFY2(!QTestEventLoop::instance().timeout(), "Network timeout"); - - // Find out how many signals with the first argument equalling our id were found - int spyCount = 0; - for (int i = 0; i < spy.count(); ++i) - if (spy.at(i).at(0).toInt() == getId) - ++spyCount; - - // each signal spied should have been emitted only once - QCOMPARE(spyCount, 1); - QCOMPARE(spy2.count(), 1); -} - -QTEST_MAIN(tst_QHttp) -#include "tst_qhttp.moc" diff --git a/tests/auto/network/access/qhttp/webserver/cgi-bin/retrieve_testfile.cgi b/tests/auto/network/access/qhttp/webserver/cgi-bin/retrieve_testfile.cgi deleted file mode 100755 index 7896c505ca..0000000000 --- a/tests/auto/network/access/qhttp/webserver/cgi-bin/retrieve_testfile.cgi +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/sh - -echo "Content-type: text/plain"; -echo -cat testfile -echo "no file retrieved" > testfile diff --git a/tests/auto/network/access/qhttp/webserver/cgi-bin/rfc.cgi b/tests/auto/network/access/qhttp/webserver/cgi-bin/rfc.cgi deleted file mode 100755 index c68688ea31..0000000000 --- a/tests/auto/network/access/qhttp/webserver/cgi-bin/rfc.cgi +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/sh - -echo "Content-type: text/plain"; -echo -cat ../rfc3252 diff --git a/tests/auto/network/access/qhttp/webserver/cgi-bin/store_testfile.cgi b/tests/auto/network/access/qhttp/webserver/cgi-bin/store_testfile.cgi deleted file mode 100755 index e950f2af04..0000000000 --- a/tests/auto/network/access/qhttp/webserver/cgi-bin/store_testfile.cgi +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/sh - -echo "Content-type: text/plain"; -echo -echo "file stored under 'testfile'" -cat > testfile diff --git a/tests/auto/network/access/qhttp/webserver/index.html b/tests/auto/network/access/qhttp/webserver/index.html deleted file mode 100644 index b80c61bf0a..0000000000 --- a/tests/auto/network/access/qhttp/webserver/index.html +++ /dev/null @@ -1,899 +0,0 @@ - - - - - - -Network Working Group H. Kennedy -Request for Comments: 3252 Mimezine -Category: Informational 1 April 2002 - - - Binary Lexical Octet Ad-hoc Transport - -Status of this Memo - - This memo provides information for the Internet community. It does - not specify an Internet standard of any kind. Distribution of this - memo is unlimited. - -Copyright Notice - - Copyright (C) The Internet Society (2002). All Rights Reserved. - -Abstract - - This document defines a reformulation of IP and two transport layer - protocols (TCP and UDP) as XML applications. - -1. Introduction - -1.1. Overview - - This document describes the Binary Lexical Octet Ad-hoc Transport - (BLOAT): a reformulation of a widely-deployed network-layer protocol - (IP [RFC791]), and two associated transport layer protocols (TCP - [RFC793] and UDP [RFC768]) as XML [XML] applications. It also - describes methods for transporting BLOAT over Ethernet and IEEE 802 - networks as well as encapsulating BLOAT in IP for gatewaying BLOAT - across the public Internet. - -1.2. Motivation - - The wild popularity of XML as a basis for application-level protocols - such as the Blocks Extensible Exchange Protocol [RFC3080], the Simple - Object Access Protocol [SOAP], and Jabber [JABBER] prompted - investigation into the possibility of extending the use of XML in the - protocol stack. Using XML at both the transport and network layer in - addition to the application layer would provide for an amazing amount - of power and flexibility while removing dependencies on proprietary - and hard-to-understand binary protocols. This protocol unification - would also allow applications to use a single XML parser for all - aspects of their operation, eliminating developer time spent figuring - out the intricacies of each new protocol, and moving the hard work of - - - - -Kennedy Informational [Page 1] - -RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 - - - parsing to the XML toolset. The use of XML also mitigates concerns - over "network vs. host" byte ordering which is at the root of many - network application bugs. - -1.3. Relation to Existing Protocols - - The reformulations specified in this RFC follow as closely as - possible the spirit of the RFCs on which they are based, and so MAY - contain elements or attributes that would not be needed in a pure - reworking (e.g. length attributes, which are implicit in XML.) - - The layering of network and transport protocols are maintained in - this RFC despite the optimizations that could be made if the line - were somewhat blurred (i.e. merging TCP and IP into a single, larger - element in the DTD) in order to foster future use of this protocol as - a basis for reformulating other protocols (such as ICMP.) - - Other than the encoding, the behavioral aspects of each of the - existing protocols remain unchanged. Routing, address spaces, TCP - congestion control, etc. behave as specified in the extant standards. - Adapting to new standards and experimental algorithm heuristics for - improving performance will become much easier once the move to BLOAT - has been completed. - -1.4. Requirement Levels - - The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", - "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this - document are to be interpreted as described in BCP 14, RFC 2119 - [RFC2119]. - -2. IPoXML - - This protocol MUST be implemented to be compliant with this RFC. - IPoXML is the root protocol REQUIRED for effective use of TCPoXML - (section 3.) and higher-level application protocols. - - The DTD for this document type can be found in section 7.1. - - The routing of IPoXML can be easily implemented on hosts with an XML - parser, as the regular structure lends itself handily to parsing and - validation of the document/datagram and then processing the - destination address, TTL, and checksum before sending it on to its - next-hop. - - The reformulation of IPv4 was chosen over IPv6 [RFC2460] due to the - wider deployment of IPv4 and the fact that implementing IPv6 as XML - would have exceeded the 1500 byte Ethernet MTU. - - - -Kennedy Informational [Page 2] - -RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 - - - All BLOAT implementations MUST use - and specify - the UTF-8 encoding - of RFC 2279 [RFC2279]. All BLOAT document/datagrams MUST be well- - formed and include the XMLDecl. - -2.1. IP Description - - A number of items have changed (for the better) from the original IP - specification. Bit-masks, where present have been converted into - human-readable values. IP addresses are listed in their dotted- - decimal notation [RFC1123]. Length and checksum values are present - as decimal integers. - - To calculate the length and checksum fields of the IP element, a - canonicalized form of the element MUST be used. The canonical form - SHALL have no whitespace (including newline characters) between - elements and only one space character between attributes. There - SHALL NOT be a space following the last attribute in an element. - - An iterative method SHOULD be used to calculate checksums, as the - length field will vary based on the size of the checksum. - - The payload element bears special attention. Due to the character - set restrictions of XML, the payload of IP datagrams (which MAY - contain arbitrary data) MUST be encoded for transport. This RFC - REQUIRES the contents of the payload to be encoded in the base-64 - encoding of RFC 2045 [RFC2045], but removes the requirement that the - encoded output MUST be wrapped on 76-character lines. - - - - - - - - - - - - - - - - - - - - - - - - -Kennedy Informational [Page 3] - -RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 - - -2.2. Example Datagram - - The following is an example IPoXML datagram with an empty payload: - - - - -
- - - - - - - - - - - - - - - -
- - -
- -3. TCPoXML - - This protocol MUST be implemented to be compliant with this RFC. The - DTD for this document type can be found in section 7.2. - -3.1. TCP Description - - A number of items have changed from the original TCP specification. - Bit-masks, where present have been converted into human-readable - values. Length and checksum and port values are present as decimal - integers. - - To calculate the length and checksum fields of the TCP element, a - canonicalized form of the element MUST be used as in section 2.1. - - An iterative method SHOULD be used to calculate checksums as in - section 2.1. - - The payload element MUST be encoded as in section 2.1. - - - -Kennedy Informational [Page 4] - -RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 - - - The TCP offset element was expanded to a maximum of 255 from 16 to - allow for the increased size of the header in XML. - - TCPoXML datagrams encapsulated by IPoXML MAY omit the header - as well as the declaration. - -3.2. Example Datagram - - The following is an example TCPoXML datagram with an empty payload: - - - - - - - - - - - - - - - - - - - - - - - - -4. UDPoXML - - This protocol MUST be implemented to be compliant with this RFC. The - DTD for this document type can be found in section 7.3. - -4.1. UDP Description - - A number of items have changed from the original UDP specification. - Bit-masks, where present have been converted into human-readable - values. Length and checksum and port values are present as decimal - integers. - - - - - - - -Kennedy Informational [Page 5] - -RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 - - - To calculate the length and checksum fields of the UDP element, a - canonicalized form of the element MUST be used as in section 2.1. An - iterative method SHOULD be used to calculate checksums as in section - 2.1. - - The payload element MUST be encoded as in section 2.1. - - UDPoXML datagrams encapsulated by IPoXML MAY omit the header - as well as the declaration. - -4.2. Example Datagram - - The following is an example UDPoXML datagram with an empty payload: - - - - - - - - - - - - - - -5. Network Transport - - This document provides for the transmission of BLOAT datagrams over - two common families of physical layer transport. Future RFCs will - address additional transports as routing vendors catch up to the - specification, and we begin to see BLOAT routed across the Internet - backbone. - -5.1. Ethernet - - BLOAT is encapsulated in Ethernet datagrams as in [RFC894] with the - exception that the type field of the Ethernet frame MUST contain the - value 0xBEEF. The first 5 octets of the Ethernet frame payload will - be 0x3c 3f 78 6d 6c (" - --> - - - - -Kennedy Informational [Page 7] - -RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Kennedy Informational [Page 9] - -RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 - - - - - - - - - - - - - - - - - - - - - - - - -Kennedy Informational [Page 10] - -RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 - - - - - - - - - - - - - -7.2. TCPoXML DTD - - - - - - - - - - - - - - - - - -Kennedy Informational [Page 11] - -RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Kennedy Informational [Page 12] - -RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 - - - - - - - - - - - - - - - - - - - - -7.3. UDPoXML DTD - - - - - - - - - - - - - - - -Kennedy Informational [Page 13] - -RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 - - -8. Security Considerations - - XML, as a subset of SGML, has the same security considerations as - specified in SGML Media Types [RFC1874]. Security considerations - that apply to IP, TCP and UDP also likely apply to BLOAT as it does - not attempt to correct for issues not related to message format. - -9. References - - [JABBER] Miller, J., "Jabber", draft-miller-jabber-00.txt, - February 2002. (Work in Progress) - - [RFC768] Postel, J., "User Datagram Protocol", STD 6, RFC 768, - August 1980. - - [RFC791] Postel, J., "Internet Protocol", STD 5, RFC 791, - September 1981. - - [RFC793] Postel, J., "Transmission Control Protocol", STD 7, RFC - 793, September 1981. - - [RFC894] Hornig, C., "Standard for the Transmission of IP - Datagrams over Ethernet Networks.", RFC 894, April 1984. - - [RFC1042] Postel, J. and J. Reynolds, "Standard for the - Transmission of IP Datagrams Over IEEE 802 Networks", STD - 43, RFC 1042, February 1988. - - [RFC1123] Braden, R., "Requirements for Internet Hosts - - Application and Support", RFC 1123, October 1989. - - [RFC1874] Levinson, E., "SGML Media Types", RFC 1874, December - 1995. - - [RFC2003] Perkins, C., "IP Encapsulation within IP", RFC 2003, - October 1996. - - [RFC2045] Freed, N. and N. Borenstein, "Multipurpose Internet Mail - Extensions (MIME) Part One: Format of Internet Message - Bodies", RFC 2045, November 1996. - - [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate - Requirement Levels", BCP 14, RFC 2119, March 1997. - - [RFC2279] Yergeau, F., "UTF-8, a transformation format of ISO - 10646", RFC 2279, January 1998. - - - - - -Kennedy Informational [Page 14] - -RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 - - - [RFC2460] Deering, S. and R. Hinden, "Internet Protocol, Version 6 - (IPv6) Specification", RFC 2460, December 1998. - - [RFC3080] Rose, M., "The Blocks Extensible Exchange Protocol Core", - RFC 3080, March 2001. - - [SOAP] Box, D., Ehnebuske, D., Kakivaya, G., Layman, A., - Mendelsohn, N., Nielsen, H. F., Thatte, S. Winer, D., - "Simple Object Access Protocol (SOAP) 1.1" World Wide Web - Consortium Note, May 2000 http://www.w3.org/TR/SOAP/ - - [XML] Bray, T., Paoli, J., Sperberg-McQueen, C. M., "Extensible - Markup Language (XML)" World Wide Web Consortium - Recommendation REC- xml-19980210. - http://www.w3.org/TR/1998/REC-xml-19980210 - -10. Author's Address - - Hugh Kennedy - Mimezine - 1060 West Addison - Chicago, IL 60613 - USA - - EMail: kennedyh@engin.umich.edu - - - - - - - - - - - - - - - - - - - - - - - - - - -Kennedy Informational [Page 15] - -RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 - - -11. Full Copyright Statement - - Copyright (C) The Internet Society (2002). All Rights Reserved. - - This document and translations of it may be copied and furnished to - others, and derivative works that comment on or otherwise explain it - or assist in its implementation may be prepared, copied, published - and distributed, in whole or in part, without restriction of any - kind, provided that the above copyright notice and this paragraph are - included on all such copies and derivative works. However, this - document itself may not be modified in any way, such as by removing - the copyright notice or references to the Internet Society or other - Internet organizations, except as needed for the purpose of - developing Internet standards in which case the procedures for - copyrights defined in the Internet Standards process must be - followed, or as required to translate it into languages other than - English. - - The limited permissions granted above are perpetual and will not be - revoked by the Internet Society or its successors or assigns. - - This document and the information contained herein is provided on an - "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING - TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING - BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION - HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF - MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. - -Acknowledgement - - Funding for the RFC Editor function is currently provided by the - Internet Society. - - - - - - - - - - - - - - - - - - - -Kennedy Informational [Page 16] - diff --git a/tests/auto/network/access/qhttp/webserver/rfc3252 b/tests/auto/network/access/qhttp/webserver/rfc3252 deleted file mode 100644 index b80c61bf0a..0000000000 --- a/tests/auto/network/access/qhttp/webserver/rfc3252 +++ /dev/null @@ -1,899 +0,0 @@ - - - - - - -Network Working Group H. Kennedy -Request for Comments: 3252 Mimezine -Category: Informational 1 April 2002 - - - Binary Lexical Octet Ad-hoc Transport - -Status of this Memo - - This memo provides information for the Internet community. It does - not specify an Internet standard of any kind. Distribution of this - memo is unlimited. - -Copyright Notice - - Copyright (C) The Internet Society (2002). All Rights Reserved. - -Abstract - - This document defines a reformulation of IP and two transport layer - protocols (TCP and UDP) as XML applications. - -1. Introduction - -1.1. Overview - - This document describes the Binary Lexical Octet Ad-hoc Transport - (BLOAT): a reformulation of a widely-deployed network-layer protocol - (IP [RFC791]), and two associated transport layer protocols (TCP - [RFC793] and UDP [RFC768]) as XML [XML] applications. It also - describes methods for transporting BLOAT over Ethernet and IEEE 802 - networks as well as encapsulating BLOAT in IP for gatewaying BLOAT - across the public Internet. - -1.2. Motivation - - The wild popularity of XML as a basis for application-level protocols - such as the Blocks Extensible Exchange Protocol [RFC3080], the Simple - Object Access Protocol [SOAP], and Jabber [JABBER] prompted - investigation into the possibility of extending the use of XML in the - protocol stack. Using XML at both the transport and network layer in - addition to the application layer would provide for an amazing amount - of power and flexibility while removing dependencies on proprietary - and hard-to-understand binary protocols. This protocol unification - would also allow applications to use a single XML parser for all - aspects of their operation, eliminating developer time spent figuring - out the intricacies of each new protocol, and moving the hard work of - - - - -Kennedy Informational [Page 1] - -RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 - - - parsing to the XML toolset. The use of XML also mitigates concerns - over "network vs. host" byte ordering which is at the root of many - network application bugs. - -1.3. Relation to Existing Protocols - - The reformulations specified in this RFC follow as closely as - possible the spirit of the RFCs on which they are based, and so MAY - contain elements or attributes that would not be needed in a pure - reworking (e.g. length attributes, which are implicit in XML.) - - The layering of network and transport protocols are maintained in - this RFC despite the optimizations that could be made if the line - were somewhat blurred (i.e. merging TCP and IP into a single, larger - element in the DTD) in order to foster future use of this protocol as - a basis for reformulating other protocols (such as ICMP.) - - Other than the encoding, the behavioral aspects of each of the - existing protocols remain unchanged. Routing, address spaces, TCP - congestion control, etc. behave as specified in the extant standards. - Adapting to new standards and experimental algorithm heuristics for - improving performance will become much easier once the move to BLOAT - has been completed. - -1.4. Requirement Levels - - The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", - "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this - document are to be interpreted as described in BCP 14, RFC 2119 - [RFC2119]. - -2. IPoXML - - This protocol MUST be implemented to be compliant with this RFC. - IPoXML is the root protocol REQUIRED for effective use of TCPoXML - (section 3.) and higher-level application protocols. - - The DTD for this document type can be found in section 7.1. - - The routing of IPoXML can be easily implemented on hosts with an XML - parser, as the regular structure lends itself handily to parsing and - validation of the document/datagram and then processing the - destination address, TTL, and checksum before sending it on to its - next-hop. - - The reformulation of IPv4 was chosen over IPv6 [RFC2460] due to the - wider deployment of IPv4 and the fact that implementing IPv6 as XML - would have exceeded the 1500 byte Ethernet MTU. - - - -Kennedy Informational [Page 2] - -RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 - - - All BLOAT implementations MUST use - and specify - the UTF-8 encoding - of RFC 2279 [RFC2279]. All BLOAT document/datagrams MUST be well- - formed and include the XMLDecl. - -2.1. IP Description - - A number of items have changed (for the better) from the original IP - specification. Bit-masks, where present have been converted into - human-readable values. IP addresses are listed in their dotted- - decimal notation [RFC1123]. Length and checksum values are present - as decimal integers. - - To calculate the length and checksum fields of the IP element, a - canonicalized form of the element MUST be used. The canonical form - SHALL have no whitespace (including newline characters) between - elements and only one space character between attributes. There - SHALL NOT be a space following the last attribute in an element. - - An iterative method SHOULD be used to calculate checksums, as the - length field will vary based on the size of the checksum. - - The payload element bears special attention. Due to the character - set restrictions of XML, the payload of IP datagrams (which MAY - contain arbitrary data) MUST be encoded for transport. This RFC - REQUIRES the contents of the payload to be encoded in the base-64 - encoding of RFC 2045 [RFC2045], but removes the requirement that the - encoded output MUST be wrapped on 76-character lines. - - - - - - - - - - - - - - - - - - - - - - - - -Kennedy Informational [Page 3] - -RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 - - -2.2. Example Datagram - - The following is an example IPoXML datagram with an empty payload: - - - - -
- - - - - - - - - - - - - - - -
- - -
- -3. TCPoXML - - This protocol MUST be implemented to be compliant with this RFC. The - DTD for this document type can be found in section 7.2. - -3.1. TCP Description - - A number of items have changed from the original TCP specification. - Bit-masks, where present have been converted into human-readable - values. Length and checksum and port values are present as decimal - integers. - - To calculate the length and checksum fields of the TCP element, a - canonicalized form of the element MUST be used as in section 2.1. - - An iterative method SHOULD be used to calculate checksums as in - section 2.1. - - The payload element MUST be encoded as in section 2.1. - - - -Kennedy Informational [Page 4] - -RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 - - - The TCP offset element was expanded to a maximum of 255 from 16 to - allow for the increased size of the header in XML. - - TCPoXML datagrams encapsulated by IPoXML MAY omit the header - as well as the declaration. - -3.2. Example Datagram - - The following is an example TCPoXML datagram with an empty payload: - - - - - - - - - - - - - - - - - - - - - - - - -4. UDPoXML - - This protocol MUST be implemented to be compliant with this RFC. The - DTD for this document type can be found in section 7.3. - -4.1. UDP Description - - A number of items have changed from the original UDP specification. - Bit-masks, where present have been converted into human-readable - values. Length and checksum and port values are present as decimal - integers. - - - - - - - -Kennedy Informational [Page 5] - -RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 - - - To calculate the length and checksum fields of the UDP element, a - canonicalized form of the element MUST be used as in section 2.1. An - iterative method SHOULD be used to calculate checksums as in section - 2.1. - - The payload element MUST be encoded as in section 2.1. - - UDPoXML datagrams encapsulated by IPoXML MAY omit the header - as well as the declaration. - -4.2. Example Datagram - - The following is an example UDPoXML datagram with an empty payload: - - - - - - - - - - - - - - -5. Network Transport - - This document provides for the transmission of BLOAT datagrams over - two common families of physical layer transport. Future RFCs will - address additional transports as routing vendors catch up to the - specification, and we begin to see BLOAT routed across the Internet - backbone. - -5.1. Ethernet - - BLOAT is encapsulated in Ethernet datagrams as in [RFC894] with the - exception that the type field of the Ethernet frame MUST contain the - value 0xBEEF. The first 5 octets of the Ethernet frame payload will - be 0x3c 3f 78 6d 6c (" - --> - - - - -Kennedy Informational [Page 7] - -RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Kennedy Informational [Page 9] - -RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 - - - - - - - - - - - - - - - - - - - - - - - - -Kennedy Informational [Page 10] - -RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 - - - - - - - - - - - - - -7.2. TCPoXML DTD - - - - - - - - - - - - - - - - - -Kennedy Informational [Page 11] - -RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Kennedy Informational [Page 12] - -RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 - - - - - - - - - - - - - - - - - - - - -7.3. UDPoXML DTD - - - - - - - - - - - - - - - -Kennedy Informational [Page 13] - -RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 - - -8. Security Considerations - - XML, as a subset of SGML, has the same security considerations as - specified in SGML Media Types [RFC1874]. Security considerations - that apply to IP, TCP and UDP also likely apply to BLOAT as it does - not attempt to correct for issues not related to message format. - -9. References - - [JABBER] Miller, J., "Jabber", draft-miller-jabber-00.txt, - February 2002. (Work in Progress) - - [RFC768] Postel, J., "User Datagram Protocol", STD 6, RFC 768, - August 1980. - - [RFC791] Postel, J., "Internet Protocol", STD 5, RFC 791, - September 1981. - - [RFC793] Postel, J., "Transmission Control Protocol", STD 7, RFC - 793, September 1981. - - [RFC894] Hornig, C., "Standard for the Transmission of IP - Datagrams over Ethernet Networks.", RFC 894, April 1984. - - [RFC1042] Postel, J. and J. Reynolds, "Standard for the - Transmission of IP Datagrams Over IEEE 802 Networks", STD - 43, RFC 1042, February 1988. - - [RFC1123] Braden, R., "Requirements for Internet Hosts - - Application and Support", RFC 1123, October 1989. - - [RFC1874] Levinson, E., "SGML Media Types", RFC 1874, December - 1995. - - [RFC2003] Perkins, C., "IP Encapsulation within IP", RFC 2003, - October 1996. - - [RFC2045] Freed, N. and N. Borenstein, "Multipurpose Internet Mail - Extensions (MIME) Part One: Format of Internet Message - Bodies", RFC 2045, November 1996. - - [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate - Requirement Levels", BCP 14, RFC 2119, March 1997. - - [RFC2279] Yergeau, F., "UTF-8, a transformation format of ISO - 10646", RFC 2279, January 1998. - - - - - -Kennedy Informational [Page 14] - -RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 - - - [RFC2460] Deering, S. and R. Hinden, "Internet Protocol, Version 6 - (IPv6) Specification", RFC 2460, December 1998. - - [RFC3080] Rose, M., "The Blocks Extensible Exchange Protocol Core", - RFC 3080, March 2001. - - [SOAP] Box, D., Ehnebuske, D., Kakivaya, G., Layman, A., - Mendelsohn, N., Nielsen, H. F., Thatte, S. Winer, D., - "Simple Object Access Protocol (SOAP) 1.1" World Wide Web - Consortium Note, May 2000 http://www.w3.org/TR/SOAP/ - - [XML] Bray, T., Paoli, J., Sperberg-McQueen, C. M., "Extensible - Markup Language (XML)" World Wide Web Consortium - Recommendation REC- xml-19980210. - http://www.w3.org/TR/1998/REC-xml-19980210 - -10. Author's Address - - Hugh Kennedy - Mimezine - 1060 West Addison - Chicago, IL 60613 - USA - - EMail: kennedyh@engin.umich.edu - - - - - - - - - - - - - - - - - - - - - - - - - - -Kennedy Informational [Page 15] - -RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 - - -11. Full Copyright Statement - - Copyright (C) The Internet Society (2002). All Rights Reserved. - - This document and translations of it may be copied and furnished to - others, and derivative works that comment on or otherwise explain it - or assist in its implementation may be prepared, copied, published - and distributed, in whole or in part, without restriction of any - kind, provided that the above copyright notice and this paragraph are - included on all such copies and derivative works. However, this - document itself may not be modified in any way, such as by removing - the copyright notice or references to the Internet Society or other - Internet organizations, except as needed for the purpose of - developing Internet standards in which case the procedures for - copyrights defined in the Internet Standards process must be - followed, or as required to translate it into languages other than - English. - - The limited permissions granted above are perpetual and will not be - revoked by the Internet Society or its successors or assigns. - - This document and the information contained herein is provided on an - "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING - TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING - BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION - HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF - MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. - -Acknowledgement - - Funding for the RFC Editor function is currently provided by the - Internet Society. - - - - - - - - - - - - - - - - - - - -Kennedy Informational [Page 16] - diff --git a/tests/auto/network/access/qhttp/webserver/rfc3252.txt b/tests/auto/network/access/qhttp/webserver/rfc3252.txt deleted file mode 100644 index b80c61bf0a..0000000000 --- a/tests/auto/network/access/qhttp/webserver/rfc3252.txt +++ /dev/null @@ -1,899 +0,0 @@ - - - - - - -Network Working Group H. Kennedy -Request for Comments: 3252 Mimezine -Category: Informational 1 April 2002 - - - Binary Lexical Octet Ad-hoc Transport - -Status of this Memo - - This memo provides information for the Internet community. It does - not specify an Internet standard of any kind. Distribution of this - memo is unlimited. - -Copyright Notice - - Copyright (C) The Internet Society (2002). All Rights Reserved. - -Abstract - - This document defines a reformulation of IP and two transport layer - protocols (TCP and UDP) as XML applications. - -1. Introduction - -1.1. Overview - - This document describes the Binary Lexical Octet Ad-hoc Transport - (BLOAT): a reformulation of a widely-deployed network-layer protocol - (IP [RFC791]), and two associated transport layer protocols (TCP - [RFC793] and UDP [RFC768]) as XML [XML] applications. It also - describes methods for transporting BLOAT over Ethernet and IEEE 802 - networks as well as encapsulating BLOAT in IP for gatewaying BLOAT - across the public Internet. - -1.2. Motivation - - The wild popularity of XML as a basis for application-level protocols - such as the Blocks Extensible Exchange Protocol [RFC3080], the Simple - Object Access Protocol [SOAP], and Jabber [JABBER] prompted - investigation into the possibility of extending the use of XML in the - protocol stack. Using XML at both the transport and network layer in - addition to the application layer would provide for an amazing amount - of power and flexibility while removing dependencies on proprietary - and hard-to-understand binary protocols. This protocol unification - would also allow applications to use a single XML parser for all - aspects of their operation, eliminating developer time spent figuring - out the intricacies of each new protocol, and moving the hard work of - - - - -Kennedy Informational [Page 1] - -RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 - - - parsing to the XML toolset. The use of XML also mitigates concerns - over "network vs. host" byte ordering which is at the root of many - network application bugs. - -1.3. Relation to Existing Protocols - - The reformulations specified in this RFC follow as closely as - possible the spirit of the RFCs on which they are based, and so MAY - contain elements or attributes that would not be needed in a pure - reworking (e.g. length attributes, which are implicit in XML.) - - The layering of network and transport protocols are maintained in - this RFC despite the optimizations that could be made if the line - were somewhat blurred (i.e. merging TCP and IP into a single, larger - element in the DTD) in order to foster future use of this protocol as - a basis for reformulating other protocols (such as ICMP.) - - Other than the encoding, the behavioral aspects of each of the - existing protocols remain unchanged. Routing, address spaces, TCP - congestion control, etc. behave as specified in the extant standards. - Adapting to new standards and experimental algorithm heuristics for - improving performance will become much easier once the move to BLOAT - has been completed. - -1.4. Requirement Levels - - The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", - "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this - document are to be interpreted as described in BCP 14, RFC 2119 - [RFC2119]. - -2. IPoXML - - This protocol MUST be implemented to be compliant with this RFC. - IPoXML is the root protocol REQUIRED for effective use of TCPoXML - (section 3.) and higher-level application protocols. - - The DTD for this document type can be found in section 7.1. - - The routing of IPoXML can be easily implemented on hosts with an XML - parser, as the regular structure lends itself handily to parsing and - validation of the document/datagram and then processing the - destination address, TTL, and checksum before sending it on to its - next-hop. - - The reformulation of IPv4 was chosen over IPv6 [RFC2460] due to the - wider deployment of IPv4 and the fact that implementing IPv6 as XML - would have exceeded the 1500 byte Ethernet MTU. - - - -Kennedy Informational [Page 2] - -RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 - - - All BLOAT implementations MUST use - and specify - the UTF-8 encoding - of RFC 2279 [RFC2279]. All BLOAT document/datagrams MUST be well- - formed and include the XMLDecl. - -2.1. IP Description - - A number of items have changed (for the better) from the original IP - specification. Bit-masks, where present have been converted into - human-readable values. IP addresses are listed in their dotted- - decimal notation [RFC1123]. Length and checksum values are present - as decimal integers. - - To calculate the length and checksum fields of the IP element, a - canonicalized form of the element MUST be used. The canonical form - SHALL have no whitespace (including newline characters) between - elements and only one space character between attributes. There - SHALL NOT be a space following the last attribute in an element. - - An iterative method SHOULD be used to calculate checksums, as the - length field will vary based on the size of the checksum. - - The payload element bears special attention. Due to the character - set restrictions of XML, the payload of IP datagrams (which MAY - contain arbitrary data) MUST be encoded for transport. This RFC - REQUIRES the contents of the payload to be encoded in the base-64 - encoding of RFC 2045 [RFC2045], but removes the requirement that the - encoded output MUST be wrapped on 76-character lines. - - - - - - - - - - - - - - - - - - - - - - - - -Kennedy Informational [Page 3] - -RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 - - -2.2. Example Datagram - - The following is an example IPoXML datagram with an empty payload: - - - - -
- - - - - - - - - - - - - - - -
- - -
- -3. TCPoXML - - This protocol MUST be implemented to be compliant with this RFC. The - DTD for this document type can be found in section 7.2. - -3.1. TCP Description - - A number of items have changed from the original TCP specification. - Bit-masks, where present have been converted into human-readable - values. Length and checksum and port values are present as decimal - integers. - - To calculate the length and checksum fields of the TCP element, a - canonicalized form of the element MUST be used as in section 2.1. - - An iterative method SHOULD be used to calculate checksums as in - section 2.1. - - The payload element MUST be encoded as in section 2.1. - - - -Kennedy Informational [Page 4] - -RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 - - - The TCP offset element was expanded to a maximum of 255 from 16 to - allow for the increased size of the header in XML. - - TCPoXML datagrams encapsulated by IPoXML MAY omit the header - as well as the declaration. - -3.2. Example Datagram - - The following is an example TCPoXML datagram with an empty payload: - - - - - - - - - - - - - - - - - - - - - - - - -4. UDPoXML - - This protocol MUST be implemented to be compliant with this RFC. The - DTD for this document type can be found in section 7.3. - -4.1. UDP Description - - A number of items have changed from the original UDP specification. - Bit-masks, where present have been converted into human-readable - values. Length and checksum and port values are present as decimal - integers. - - - - - - - -Kennedy Informational [Page 5] - -RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 - - - To calculate the length and checksum fields of the UDP element, a - canonicalized form of the element MUST be used as in section 2.1. An - iterative method SHOULD be used to calculate checksums as in section - 2.1. - - The payload element MUST be encoded as in section 2.1. - - UDPoXML datagrams encapsulated by IPoXML MAY omit the header - as well as the declaration. - -4.2. Example Datagram - - The following is an example UDPoXML datagram with an empty payload: - - - - - - - - - - - - - - -5. Network Transport - - This document provides for the transmission of BLOAT datagrams over - two common families of physical layer transport. Future RFCs will - address additional transports as routing vendors catch up to the - specification, and we begin to see BLOAT routed across the Internet - backbone. - -5.1. Ethernet - - BLOAT is encapsulated in Ethernet datagrams as in [RFC894] with the - exception that the type field of the Ethernet frame MUST contain the - value 0xBEEF. The first 5 octets of the Ethernet frame payload will - be 0x3c 3f 78 6d 6c (" - --> - - - - -Kennedy Informational [Page 7] - -RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Kennedy Informational [Page 9] - -RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 - - - - - - - - - - - - - - - - - - - - - - - - -Kennedy Informational [Page 10] - -RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 - - - - - - - - - - - - - -7.2. TCPoXML DTD - - - - - - - - - - - - - - - - - -Kennedy Informational [Page 11] - -RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Kennedy Informational [Page 12] - -RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 - - - - - - - - - - - - - - - - - - - - -7.3. UDPoXML DTD - - - - - - - - - - - - - - - -Kennedy Informational [Page 13] - -RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 - - -8. Security Considerations - - XML, as a subset of SGML, has the same security considerations as - specified in SGML Media Types [RFC1874]. Security considerations - that apply to IP, TCP and UDP also likely apply to BLOAT as it does - not attempt to correct for issues not related to message format. - -9. References - - [JABBER] Miller, J., "Jabber", draft-miller-jabber-00.txt, - February 2002. (Work in Progress) - - [RFC768] Postel, J., "User Datagram Protocol", STD 6, RFC 768, - August 1980. - - [RFC791] Postel, J., "Internet Protocol", STD 5, RFC 791, - September 1981. - - [RFC793] Postel, J., "Transmission Control Protocol", STD 7, RFC - 793, September 1981. - - [RFC894] Hornig, C., "Standard for the Transmission of IP - Datagrams over Ethernet Networks.", RFC 894, April 1984. - - [RFC1042] Postel, J. and J. Reynolds, "Standard for the - Transmission of IP Datagrams Over IEEE 802 Networks", STD - 43, RFC 1042, February 1988. - - [RFC1123] Braden, R., "Requirements for Internet Hosts - - Application and Support", RFC 1123, October 1989. - - [RFC1874] Levinson, E., "SGML Media Types", RFC 1874, December - 1995. - - [RFC2003] Perkins, C., "IP Encapsulation within IP", RFC 2003, - October 1996. - - [RFC2045] Freed, N. and N. Borenstein, "Multipurpose Internet Mail - Extensions (MIME) Part One: Format of Internet Message - Bodies", RFC 2045, November 1996. - - [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate - Requirement Levels", BCP 14, RFC 2119, March 1997. - - [RFC2279] Yergeau, F., "UTF-8, a transformation format of ISO - 10646", RFC 2279, January 1998. - - - - - -Kennedy Informational [Page 14] - -RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 - - - [RFC2460] Deering, S. and R. Hinden, "Internet Protocol, Version 6 - (IPv6) Specification", RFC 2460, December 1998. - - [RFC3080] Rose, M., "The Blocks Extensible Exchange Protocol Core", - RFC 3080, March 2001. - - [SOAP] Box, D., Ehnebuske, D., Kakivaya, G., Layman, A., - Mendelsohn, N., Nielsen, H. F., Thatte, S. Winer, D., - "Simple Object Access Protocol (SOAP) 1.1" World Wide Web - Consortium Note, May 2000 http://www.w3.org/TR/SOAP/ - - [XML] Bray, T., Paoli, J., Sperberg-McQueen, C. M., "Extensible - Markup Language (XML)" World Wide Web Consortium - Recommendation REC- xml-19980210. - http://www.w3.org/TR/1998/REC-xml-19980210 - -10. Author's Address - - Hugh Kennedy - Mimezine - 1060 West Addison - Chicago, IL 60613 - USA - - EMail: kennedyh@engin.umich.edu - - - - - - - - - - - - - - - - - - - - - - - - - - -Kennedy Informational [Page 15] - -RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 - - -11. Full Copyright Statement - - Copyright (C) The Internet Society (2002). All Rights Reserved. - - This document and translations of it may be copied and furnished to - others, and derivative works that comment on or otherwise explain it - or assist in its implementation may be prepared, copied, published - and distributed, in whole or in part, without restriction of any - kind, provided that the above copyright notice and this paragraph are - included on all such copies and derivative works. However, this - document itself may not be modified in any way, such as by removing - the copyright notice or references to the Internet Society or other - Internet organizations, except as needed for the purpose of - developing Internet standards in which case the procedures for - copyrights defined in the Internet Standards process must be - followed, or as required to translate it into languages other than - English. - - The limited permissions granted above are perpetual and will not be - revoked by the Internet Society or its successors or assigns. - - This document and the information contained herein is provided on an - "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING - TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING - BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION - HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF - MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. - -Acknowledgement - - Funding for the RFC Editor function is currently provided by the - Internet Society. - - - - - - - - - - - - - - - - - - - -Kennedy Informational [Page 16] - diff --git a/tests/auto/network/socket/qhttpsocketengine/tst_qhttpsocketengine.cpp b/tests/auto/network/socket/qhttpsocketengine/tst_qhttpsocketengine.cpp index e470f5778a..b411dd2651 100644 --- a/tests/auto/network/socket/qhttpsocketengine/tst_qhttpsocketengine.cpp +++ b/tests/auto/network/socket/qhttpsocketengine/tst_qhttpsocketengine.cpp @@ -50,7 +50,6 @@ #include #include #include -#include #include #include diff --git a/tests/auto/network/socket/qsocks5socketengine/tst_qsocks5socketengine.cpp b/tests/auto/network/socket/qsocks5socketengine/tst_qsocks5socketengine.cpp index d83555e61b..df677875e6 100644 --- a/tests/auto/network/socket/qsocks5socketengine/tst_qsocks5socketengine.cpp +++ b/tests/auto/network/socket/qsocks5socketengine/tst_qsocks5socketengine.cpp @@ -52,7 +52,6 @@ #include #include #include -#include #include #include #include diff --git a/tests/auto/xml/sax/qxmlinputsource/tst_qxmlinputsource.cpp b/tests/auto/xml/sax/qxmlinputsource/tst_qxmlinputsource.cpp index 865e6c4d9f..5bc3a09fc5 100644 --- a/tests/auto/xml/sax/qxmlinputsource/tst_qxmlinputsource.cpp +++ b/tests/auto/xml/sax/qxmlinputsource/tst_qxmlinputsource.cpp @@ -41,7 +41,9 @@ #include -#include +#include +#include +#include #include #include #include @@ -116,13 +118,16 @@ class ServerAndClient : public QObject public: ServerAndClient(QEventLoop &ev) : success(false) , eventLoop(ev) + , isBody(false) + , bodyBytesRead(0) + , bodyLength(-1) { setObjectName("serverAndClient"); tcpServer = new QTcpServer(this); connect(tcpServer, SIGNAL(newConnection()), this, SLOT(newConnection())); tcpServer->listen(QHostAddress::LocalHost, 1088); - httpClient = new QHttp(this); - connect(httpClient, SIGNAL(requestFinished(int, bool)), SLOT(requestFinished(int, bool))); + httpClient = new QNetworkAccessManager(this); + connect(httpClient, SIGNAL(finished(QNetworkReply*)), SLOT(requestFinished(QNetworkReply*))); } bool success; @@ -132,25 +137,26 @@ public slots: void doIt() { QUrl url("http://127.0.0.1:1088"); - httpClient->setHost( url.host(), 1088); - QHttpRequestHeader req_head("POST", url.path()); - req_head.setValue("host", url.host()); - req_head.setValue("user-agent", "xml-test"); - req_head.setValue("keep-alive", "false"); + QNetworkRequest req(url); + req.setRawHeader("POST", url.path().toAscii()); + req.setRawHeader("user-agent", "xml-test"); + req.setRawHeader("keep-alive", "false"); + req.setRawHeader("host", url.host().toAscii()); QByteArray xmlrpc("\r\n\ SFD.GetVersion\r\n\ \r\n\ "); - req_head.setContentLength(xmlrpc.size()); - req_head.setContentType("text/xml"); + req.setHeader(QNetworkRequest::ContentLengthHeader, xmlrpc.size()); + req.setHeader(QNetworkRequest::ContentTypeHeader, "text/xml"); - httpClient->request(req_head, xmlrpc); + httpClient->post(req, xmlrpc); } - void requestFinished(int, bool isError) + void requestFinished(QNetworkReply *reply) { - QVERIFY(!isError); + QVERIFY(reply->error() == QNetworkReply::NoError); + reply->deleteLater(); } private slots: @@ -165,32 +171,43 @@ private slots: void readyRead() { QTcpSocket *const s = static_cast(sender()); - int bodyLength = -1; - while(s->canReadLine()) + while (s->bytesAvailable()) { const QString line(s->readLine()); - if(line.startsWith("content-length:")) + if (line.startsWith("Content-Length:")) bodyLength = line.mid(15).toInt(); - if(line == "\r\n") + if (isBody) { - if(bodyLength == -1) + body.append(line); + bodyBytesRead += line.length(); + } + else if (line == "\r\n") + { + isBody = true; + if (bodyLength == -1) { qFatal("No length was specified in the header."); } - - QDomDocument domDoc; - success = domDoc.setContent(s->read(bodyLength)); - eventLoop.exit(); } } + + if (bodyBytesRead == bodyLength) + { + QDomDocument domDoc; + success = domDoc.setContent(body); + eventLoop.exit(); + } } private: + QByteArray body; + int bodyBytesRead, bodyLength; + bool isBody; QTcpServer *tcpServer; - QHttp* httpClient; + QNetworkAccessManager* httpClient; }; void tst_QXmlInputSource::waitForReadyIODevice() const -- cgit v1.2.3