Merge branch '4.5'
[qt-netbsd.git] / src / network / access / qhttp.cpp
blob49ce5a377b793b80d004453df3c31c6b6042a50a
1 /****************************************************************************
2 **
3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: Qt Software Information (qt-info@nokia.com)
5 **
6 ** This file is part of the QtNetwork module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** No Commercial Usage
10 ** This file contains pre-release code and may not be distributed.
11 ** You may use this file in accordance with the terms and conditions
12 ** contained in the either Technology Preview License Agreement or the
13 ** Beta Release License Agreement.
15 ** GNU Lesser General Public License Usage
16 ** Alternatively, this file may be used under the terms of the GNU Lesser
17 ** General Public License version 2.1 as published by the Free Software
18 ** Foundation and appearing in the file LICENSE.LGPL included in the
19 ** packaging of this file. Please review the following information to
20 ** ensure the GNU Lesser General Public License version 2.1 requirements
21 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23 ** In addition, as a special exception, Nokia gives you certain
24 ** additional rights. These rights are described in the Nokia Qt LGPL
25 ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
26 ** package.
28 ** GNU General Public License Usage
29 ** Alternatively, this file may be used under the terms of the GNU
30 ** General Public License version 3.0 as published by the Free Software
31 ** Foundation and appearing in the file LICENSE.GPL included in the
32 ** packaging of this file. Please review the following information to
33 ** ensure the GNU General Public License version 3.0 requirements will be
34 ** met: http://www.gnu.org/copyleft/gpl.html.
36 ** If you are unsure which license is appropriate for your use, please
37 ** contact the sales department at qt-sales@nokia.com.
38 ** $QT_END_LICENSE$
40 ****************************************************************************/
42 //#define QHTTP_DEBUG
44 #include <qplatformdefs.h>
45 #include "qhttp.h"
47 #ifndef QT_NO_HTTP
48 # include "private/qobject_p.h"
49 # include "qtcpsocket.h"
50 # include "qsslsocket.h"
51 # include "qtextstream.h"
52 # include "qmap.h"
53 # include "qlist.h"
54 # include "qstring.h"
55 # include "qstringlist.h"
56 # include "qbuffer.h"
57 # include "private/qringbuffer_p.h"
58 # include "qcoreevent.h"
59 # include "qurl.h"
60 # include "qnetworkproxy.h"
61 # include "qauthenticator.h"
62 # include "qauthenticator_p.h"
63 # include "qdebug.h"
64 # include "qtimer.h"
65 #endif
67 #ifndef QT_NO_HTTP
69 QT_BEGIN_NAMESPACE
71 class QHttpNormalRequest;
72 class QHttpRequest
74 public:
75 QHttpRequest() : finished(false)
76 { id = idCounter.fetchAndAddRelaxed(1); }
77 virtual ~QHttpRequest()
78 { }
80 virtual void start(QHttp *) = 0;
81 virtual bool hasRequestHeader();
82 virtual QHttpRequestHeader requestHeader();
84 virtual QIODevice *sourceDevice() = 0;
85 virtual QIODevice *destinationDevice() = 0;
87 int id;
88 bool finished;
90 private:
91 static QBasicAtomicInt idCounter;
94 class QHttpPrivate : public QObjectPrivate
96 public:
97 Q_DECLARE_PUBLIC(QHttp)
99 inline QHttpPrivate()
100 : socket(0), reconnectAttempts(2),
101 deleteSocket(0), state(QHttp::Unconnected),
102 error(QHttp::NoError), port(0), mode(QHttp::ConnectionModeHttp),
103 toDevice(0), postDevice(0), bytesDone(0), chunkedSize(-1),
104 repost(false), pendingPost(false)
108 inline ~QHttpPrivate()
110 while (!pending.isEmpty())
111 delete pending.takeFirst();
113 if (deleteSocket)
114 delete socket;
117 // private slots
118 void _q_startNextRequest();
119 void _q_slotReadyRead();
120 void _q_slotConnected();
121 void _q_slotError(QAbstractSocket::SocketError);
122 void _q_slotClosed();
123 void _q_slotBytesWritten(qint64 numBytes);
124 void _q_slotDoFinished();
125 void _q_slotSendRequest();
126 void _q_continuePost();
128 int addRequest(QHttpNormalRequest *);
129 int addRequest(QHttpRequest *);
130 void finishedWithSuccess();
131 void finishedWithError(const QString &detail, int errorCode);
133 void init();
134 void setState(int);
135 void closeConn();
136 void setSock(QTcpSocket *sock);
138 QTcpSocket *socket;
139 int reconnectAttempts;
140 bool deleteSocket;
141 QList<QHttpRequest *> pending;
143 QHttp::State state;
144 QHttp::Error error;
145 QString errorString;
147 QString hostName;
148 quint16 port;
149 QHttp::ConnectionMode mode;
151 QByteArray buffer;
152 QIODevice *toDevice;
153 QIODevice *postDevice;
155 qint64 bytesDone;
156 qint64 bytesTotal;
157 qint64 chunkedSize;
159 QHttpRequestHeader header;
161 bool readHeader;
162 QString headerStr;
163 QHttpResponseHeader response;
165 QRingBuffer rba;
167 #ifndef QT_NO_NETWORKPROXY
168 QNetworkProxy proxy;
169 QAuthenticator proxyAuthenticator;
170 #endif
171 QAuthenticator authenticator;
172 bool repost;
173 bool hasFinishedWithError;
174 bool pendingPost;
175 QTimer post100ContinueTimer;
178 QBasicAtomicInt QHttpRequest::idCounter = Q_BASIC_ATOMIC_INITIALIZER(1);
180 bool QHttpRequest::hasRequestHeader()
182 return false;
185 QHttpRequestHeader QHttpRequest::requestHeader()
187 return QHttpRequestHeader();
190 /****************************************************
192 * QHttpNormalRequest
194 ****************************************************/
196 class QHttpNormalRequest : public QHttpRequest
198 public:
199 QHttpNormalRequest(const QHttpRequestHeader &h, QIODevice *d, QIODevice *t) :
200 header(h), to(t)
202 is_ba = false;
203 data.dev = d;
206 QHttpNormalRequest(const QHttpRequestHeader &h, QByteArray *d, QIODevice *t) :
207 header(h), to(t)
209 is_ba = true;
210 data.ba = d;
213 ~QHttpNormalRequest()
215 if (is_ba)
216 delete data.ba;
219 void start(QHttp *);
220 bool hasRequestHeader();
221 QHttpRequestHeader requestHeader();
222 inline void setRequestHeader(const QHttpRequestHeader &h) { header = h; }
224 QIODevice *sourceDevice();
225 QIODevice *destinationDevice();
227 protected:
228 QHttpRequestHeader header;
230 private:
231 union {
232 QByteArray *ba;
233 QIODevice *dev;
234 } data;
235 bool is_ba;
236 QIODevice *to;
239 void QHttpNormalRequest::start(QHttp *http)
241 if (!http->d_func()->socket)
242 http->d_func()->setSock(0);
243 http->d_func()->header = header;
245 if (is_ba) {
246 http->d_func()->buffer = *data.ba;
247 if (http->d_func()->buffer.size() >= 0)
248 http->d_func()->header.setContentLength(http->d_func()->buffer.size());
250 http->d_func()->postDevice = 0;
251 } else {
252 http->d_func()->buffer = QByteArray();
254 if (data.dev && (data.dev->isOpen() || data.dev->open(QIODevice::ReadOnly))) {
255 http->d_func()->postDevice = data.dev;
256 if (http->d_func()->postDevice->size() >= 0)
257 http->d_func()->header.setContentLength(http->d_func()->postDevice->size());
258 } else {
259 http->d_func()->postDevice = 0;
263 if (to && (to->isOpen() || to->open(QIODevice::WriteOnly)))
264 http->d_func()->toDevice = to;
265 else
266 http->d_func()->toDevice = 0;
268 http->d_func()->reconnectAttempts = 2;
269 http->d_func()->_q_slotSendRequest();
272 bool QHttpNormalRequest::hasRequestHeader()
274 return true;
277 QHttpRequestHeader QHttpNormalRequest::requestHeader()
279 return header;
282 QIODevice *QHttpNormalRequest::sourceDevice()
284 if (is_ba)
285 return 0;
286 return data.dev;
289 QIODevice *QHttpNormalRequest::destinationDevice()
291 return to;
294 /****************************************************
296 * QHttpPGHRequest
297 * (like a QHttpNormalRequest, but for the convenience
298 * functions put(), get() and head() -- i.e. set the
299 * host header field correctly before sending the
300 * request)
302 ****************************************************/
304 class QHttpPGHRequest : public QHttpNormalRequest
306 public:
307 QHttpPGHRequest(const QHttpRequestHeader &h, QIODevice *d, QIODevice *t) :
308 QHttpNormalRequest(h, d, t)
311 QHttpPGHRequest(const QHttpRequestHeader &h, QByteArray *d, QIODevice *t) :
312 QHttpNormalRequest(h, d, t)
315 ~QHttpPGHRequest()
318 void start(QHttp *);
321 void QHttpPGHRequest::start(QHttp *http)
323 if (http->d_func()->port && http->d_func()->port != 80)
324 header.setValue(QLatin1String("Host"), http->d_func()->hostName + QLatin1Char(':') + QString::number(http->d_func()->port));
325 else
326 header.setValue(QLatin1String("Host"), http->d_func()->hostName);
327 QHttpNormalRequest::start(http);
330 /****************************************************
332 * QHttpSetHostRequest
334 ****************************************************/
336 class QHttpSetHostRequest : public QHttpRequest
338 public:
339 QHttpSetHostRequest(const QString &h, quint16 p, QHttp::ConnectionMode m)
340 : hostName(h), port(p), mode(m)
343 void start(QHttp *);
345 QIODevice *sourceDevice()
346 { return 0; }
347 QIODevice *destinationDevice()
348 { return 0; }
350 private:
351 QString hostName;
352 quint16 port;
353 QHttp::ConnectionMode mode;
356 void QHttpSetHostRequest::start(QHttp *http)
358 http->d_func()->hostName = hostName;
359 http->d_func()->port = port;
360 http->d_func()->mode = mode;
362 #ifdef QT_NO_OPENSSL
363 if (mode == QHttp::ConnectionModeHttps) {
364 // SSL requested but no SSL support compiled in
365 http->d_func()->finishedWithError(QLatin1String(QT_TRANSLATE_NOOP("QHttp", "HTTPS connection requested but SSL support not compiled in")),
366 QHttp::UnknownError);
367 return;
369 #endif
371 http->d_func()->finishedWithSuccess();
374 /****************************************************
376 * QHttpSetUserRequest
378 ****************************************************/
380 class QHttpSetUserRequest : public QHttpRequest
382 public:
383 QHttpSetUserRequest(const QString &userName, const QString &password) :
384 user(userName), pass(password)
387 void start(QHttp *);
389 QIODevice *sourceDevice()
390 { return 0; }
391 QIODevice *destinationDevice()
392 { return 0; }
394 private:
395 QString user;
396 QString pass;
399 void QHttpSetUserRequest::start(QHttp *http)
401 http->d_func()->authenticator.setUser(user);
402 http->d_func()->authenticator.setPassword(pass);
403 http->d_func()->finishedWithSuccess();
406 #ifndef QT_NO_NETWORKPROXY
408 /****************************************************
410 * QHttpSetProxyRequest
412 ****************************************************/
414 class QHttpSetProxyRequest : public QHttpRequest
416 public:
417 inline QHttpSetProxyRequest(const QNetworkProxy &proxy)
419 this->proxy = proxy;
422 inline void start(QHttp *http)
424 http->d_func()->proxy = proxy;
425 QString user = proxy.user();
426 if (!user.isEmpty())
427 http->d_func()->proxyAuthenticator.setUser(user);
428 QString password = proxy.password();
429 if (!password.isEmpty())
430 http->d_func()->proxyAuthenticator.setPassword(password);
431 http->d_func()->finishedWithSuccess();
434 inline QIODevice *sourceDevice()
435 { return 0; }
436 inline QIODevice *destinationDevice()
437 { return 0; }
438 private:
439 QNetworkProxy proxy;
442 #endif // QT_NO_NETWORKPROXY
444 /****************************************************
446 * QHttpSetSocketRequest
448 ****************************************************/
450 class QHttpSetSocketRequest : public QHttpRequest
452 public:
453 QHttpSetSocketRequest(QTcpSocket *s) : socket(s)
456 void start(QHttp *);
458 QIODevice *sourceDevice()
459 { return 0; }
460 QIODevice *destinationDevice()
461 { return 0; }
463 private:
464 QTcpSocket *socket;
467 void QHttpSetSocketRequest::start(QHttp *http)
469 http->d_func()->setSock(socket);
470 http->d_func()->finishedWithSuccess();
473 /****************************************************
475 * QHttpCloseRequest
477 ****************************************************/
479 class QHttpCloseRequest : public QHttpRequest
481 public:
482 QHttpCloseRequest()
484 void start(QHttp *);
486 QIODevice *sourceDevice()
487 { return 0; }
488 QIODevice *destinationDevice()
489 { return 0; }
492 void QHttpCloseRequest::start(QHttp *http)
494 http->d_func()->closeConn();
497 class QHttpHeaderPrivate
499 Q_DECLARE_PUBLIC(QHttpHeader)
500 public:
501 inline virtual ~QHttpHeaderPrivate() {}
503 QList<QPair<QString, QString> > values;
504 bool valid;
505 QHttpHeader *q_ptr;
508 /****************************************************
510 * QHttpHeader
512 ****************************************************/
515 \class QHttpHeader
516 \brief The QHttpHeader class contains header information for HTTP.
518 \ingroup io
519 \inmodule QtNetwork
521 In most cases you should use the more specialized derivatives of
522 this class, QHttpResponseHeader and QHttpRequestHeader, rather
523 than directly using QHttpHeader.
525 QHttpHeader provides the HTTP header fields. A HTTP header field
526 consists of a name followed by a colon, a single space, and the
527 field value. (See RFC 1945.) Field names are case-insensitive. A
528 typical header field looks like this:
529 \snippet doc/src/snippets/code/src_network_access_qhttp.cpp 0
531 In the API the header field name is called the "key" and the
532 content is called the "value". You can get and set a header
533 field's value by using its key with value() and setValue(), e.g.
534 \snippet doc/src/snippets/code/src_network_access_qhttp.cpp 1
536 Some fields are so common that getters and setters are provided
537 for them as a convenient alternative to using \l value() and
538 \l setValue(), e.g. contentLength() and contentType(),
539 setContentLength() and setContentType().
541 Each header key has a \e single value associated with it. If you
542 set the value for a key which already exists the previous value
543 will be discarded.
545 \sa QHttpRequestHeader QHttpResponseHeader
549 \fn int QHttpHeader::majorVersion() const
551 Returns the major protocol-version of the HTTP header.
555 \fn int QHttpHeader::minorVersion() const
557 Returns the minor protocol-version of the HTTP header.
561 Constructs an empty HTTP header.
563 QHttpHeader::QHttpHeader()
564 : d_ptr(new QHttpHeaderPrivate)
566 Q_D(QHttpHeader);
567 d->q_ptr = this;
568 d->valid = true;
572 Constructs a copy of \a header.
574 QHttpHeader::QHttpHeader(const QHttpHeader &header)
575 : d_ptr(new QHttpHeaderPrivate)
577 Q_D(QHttpHeader);
578 d->q_ptr = this;
579 d->valid = header.d_func()->valid;
580 d->values = header.d_func()->values;
584 Constructs a HTTP header for \a str.
586 This constructor parses the string \a str for header fields and
587 adds this information. The \a str should consist of one or more
588 "\r\n" delimited lines; each of these lines should have the format
589 key, colon, space, value.
591 QHttpHeader::QHttpHeader(const QString &str)
592 : d_ptr(new QHttpHeaderPrivate)
594 Q_D(QHttpHeader);
595 d->q_ptr = this;
596 d->valid = true;
597 parse(str);
600 /*! \internal
602 QHttpHeader::QHttpHeader(QHttpHeaderPrivate &dd, const QString &str)
603 : d_ptr(&dd)
605 Q_D(QHttpHeader);
606 d->q_ptr = this;
607 d->valid = true;
608 if (!str.isEmpty())
609 parse(str);
612 /*! \internal
614 QHttpHeader::QHttpHeader(QHttpHeaderPrivate &dd, const QHttpHeader &header)
615 : d_ptr(&dd)
617 Q_D(QHttpHeader);
618 d->q_ptr = this;
619 d->valid = header.d_func()->valid;
620 d->values = header.d_func()->values;
623 Destructor.
625 QHttpHeader::~QHttpHeader()
627 delete d_ptr;
631 Assigns \a h and returns a reference to this http header.
633 QHttpHeader &QHttpHeader::operator=(const QHttpHeader &h)
635 Q_D(QHttpHeader);
636 d->values = h.d_func()->values;
637 d->valid = h.d_func()->valid;
638 return *this;
642 Returns true if the HTTP header is valid; otherwise returns false.
644 A QHttpHeader is invalid if it was created by parsing a malformed string.
646 bool QHttpHeader::isValid() const
648 Q_D(const QHttpHeader);
649 return d->valid;
652 /*! \internal
653 Parses the HTTP header string \a str for header fields and adds
654 the keys/values it finds. If the string is not parsed successfully
655 the QHttpHeader becomes \link isValid() invalid\endlink.
657 Returns true if \a str was successfully parsed; otherwise returns false.
659 \sa toString()
661 bool QHttpHeader::parse(const QString &str)
663 Q_D(QHttpHeader);
664 QStringList lst;
665 int pos = str.indexOf(QLatin1Char('\n'));
666 if (pos > 0 && str.at(pos - 1) == QLatin1Char('\r'))
667 lst = str.trimmed().split(QLatin1String("\r\n"));
668 else
669 lst = str.trimmed().split(QLatin1String("\n"));
670 lst.removeAll(QString()); // No empties
672 if (lst.isEmpty())
673 return true;
675 QStringList lines;
676 QStringList::Iterator it = lst.begin();
677 for (; it != lst.end(); ++it) {
678 if (!(*it).isEmpty()) {
679 if ((*it)[0].isSpace()) {
680 if (!lines.isEmpty()) {
681 lines.last() += QLatin1Char(' ');
682 lines.last() += (*it).trimmed();
684 } else {
685 lines.append((*it));
690 int number = 0;
691 it = lines.begin();
692 for (; it != lines.end(); ++it) {
693 if (!parseLine(*it, number++)) {
694 d->valid = false;
695 return false;
698 return true;
701 /*! \internal
703 void QHttpHeader::setValid(bool v)
705 Q_D(QHttpHeader);
706 d->valid = v;
710 Returns the first value for the entry with the given \a key. If no entry
711 has this \a key, an empty string is returned.
713 \sa setValue() removeValue() hasKey() keys()
715 QString QHttpHeader::value(const QString &key) const
717 Q_D(const QHttpHeader);
718 QString lowercaseKey = key.toLower();
719 QList<QPair<QString, QString> >::ConstIterator it = d->values.constBegin();
720 while (it != d->values.constEnd()) {
721 if ((*it).first.toLower() == lowercaseKey)
722 return (*it).second;
723 ++it;
725 return QString();
729 Returns all the entries with the given \a key. If no entry
730 has this \a key, an empty string list is returned.
732 QStringList QHttpHeader::allValues(const QString &key) const
734 Q_D(const QHttpHeader);
735 QString lowercaseKey = key.toLower();
736 QStringList valueList;
737 QList<QPair<QString, QString> >::ConstIterator it = d->values.constBegin();
738 while (it != d->values.constEnd()) {
739 if ((*it).first.toLower() == lowercaseKey)
740 valueList.append((*it).second);
741 ++it;
743 return valueList;
747 Returns a list of the keys in the HTTP header.
749 \sa hasKey()
751 QStringList QHttpHeader::keys() const
753 Q_D(const QHttpHeader);
754 QStringList keyList;
755 QSet<QString> seenKeys;
756 QList<QPair<QString, QString> >::ConstIterator it = d->values.constBegin();
757 while (it != d->values.constEnd()) {
758 const QString &key = (*it).first;
759 QString lowercaseKey = key.toLower();
760 if (!seenKeys.contains(lowercaseKey)) {
761 keyList.append(key);
762 seenKeys.insert(lowercaseKey);
764 ++it;
766 return keyList;
770 Returns true if the HTTP header has an entry with the given \a
771 key; otherwise returns false.
773 \sa value() setValue() keys()
775 bool QHttpHeader::hasKey(const QString &key) const
777 Q_D(const QHttpHeader);
778 QString lowercaseKey = key.toLower();
779 QList<QPair<QString, QString> >::ConstIterator it = d->values.constBegin();
780 while (it != d->values.constEnd()) {
781 if ((*it).first.toLower() == lowercaseKey)
782 return true;
783 ++it;
785 return false;
789 Sets the value of the entry with the \a key to \a value.
791 If no entry with \a key exists, a new entry with the given \a key
792 and \a value is created. If an entry with the \a key already
793 exists, the first value is discarded and replaced with the given
794 \a value.
796 \sa value() hasKey() removeValue()
798 void QHttpHeader::setValue(const QString &key, const QString &value)
800 Q_D(QHttpHeader);
801 QString lowercaseKey = key.toLower();
802 QList<QPair<QString, QString> >::Iterator it = d->values.begin();
803 while (it != d->values.end()) {
804 if ((*it).first.toLower() == lowercaseKey) {
805 (*it).second = value;
806 return;
808 ++it;
810 // not found so add
811 addValue(key, value);
815 Sets the header entries to be the list of key value pairs in \a values.
817 void QHttpHeader::setValues(const QList<QPair<QString, QString> > &values)
819 Q_D(QHttpHeader);
820 d->values = values;
824 Adds a new entry with the \a key and \a value.
826 void QHttpHeader::addValue(const QString &key, const QString &value)
828 Q_D(QHttpHeader);
829 d->values.append(qMakePair(key, value));
833 Returns all the entries in the header.
835 QList<QPair<QString, QString> > QHttpHeader::values() const
837 Q_D(const QHttpHeader);
838 return d->values;
842 Removes the entry with the key \a key from the HTTP header.
844 \sa value() setValue()
846 void QHttpHeader::removeValue(const QString &key)
848 Q_D(QHttpHeader);
849 QString lowercaseKey = key.toLower();
850 QList<QPair<QString, QString> >::Iterator it = d->values.begin();
851 while (it != d->values.end()) {
852 if ((*it).first.toLower() == lowercaseKey) {
853 d->values.erase(it);
854 return;
856 ++it;
861 Removes all the entries with the key \a key from the HTTP header.
863 void QHttpHeader::removeAllValues(const QString &key)
865 Q_D(QHttpHeader);
866 QString lowercaseKey = key.toLower();
867 QList<QPair<QString, QString> >::Iterator it = d->values.begin();
868 while (it != d->values.end()) {
869 if ((*it).first.toLower() == lowercaseKey) {
870 it = d->values.erase(it);
871 continue;
873 ++it;
877 /*! \internal
878 Parses the single HTTP header line \a line which has the format
879 key, colon, space, value, and adds key/value to the headers. The
880 linenumber is \a number. Returns true if the line was successfully
881 parsed and the key/value added; otherwise returns false.
883 \sa parse()
885 bool QHttpHeader::parseLine(const QString &line, int)
887 int i = line.indexOf(QLatin1Char(':'));
888 if (i == -1)
889 return false;
891 addValue(line.left(i).trimmed(), line.mid(i + 1).trimmed());
893 return true;
897 Returns a string representation of the HTTP header.
899 The string is suitable for use by the constructor that takes a
900 QString. It consists of lines with the format: key, colon, space,
901 value, "\r\n".
903 QString QHttpHeader::toString() const
905 Q_D(const QHttpHeader);
906 if (!isValid())
907 return QLatin1String("");
909 QString ret = QLatin1String("");
911 QList<QPair<QString, QString> >::ConstIterator it = d->values.constBegin();
912 while (it != d->values.constEnd()) {
913 ret += (*it).first + QLatin1String(": ") + (*it).second + QLatin1String("\r\n");
914 ++it;
916 return ret;
920 Returns true if the header has an entry for the special HTTP
921 header field \c content-length; otherwise returns false.
923 \sa contentLength() setContentLength()
925 bool QHttpHeader::hasContentLength() const
927 return hasKey(QLatin1String("content-length"));
931 Returns the value of the special HTTP header field \c
932 content-length.
934 \sa setContentLength() hasContentLength()
936 uint QHttpHeader::contentLength() const
938 return value(QLatin1String("content-length")).toUInt();
942 Sets the value of the special HTTP header field \c content-length
943 to \a len.
945 \sa contentLength() hasContentLength()
947 void QHttpHeader::setContentLength(int len)
949 setValue(QLatin1String("content-length"), QString::number(len));
953 Returns true if the header has an entry for the special HTTP
954 header field \c content-type; otherwise returns false.
956 \sa contentType() setContentType()
958 bool QHttpHeader::hasContentType() const
960 return hasKey(QLatin1String("content-type"));
964 Returns the value of the special HTTP header field \c content-type.
966 \sa setContentType() hasContentType()
968 QString QHttpHeader::contentType() const
970 QString type = value(QLatin1String("content-type"));
971 if (type.isEmpty())
972 return QString();
974 int pos = type.indexOf(QLatin1Char(';'));
975 if (pos == -1)
976 return type;
978 return type.left(pos).trimmed();
982 Sets the value of the special HTTP header field \c content-type to
983 \a type.
985 \sa contentType() hasContentType()
987 void QHttpHeader::setContentType(const QString &type)
989 setValue(QLatin1String("content-type"), type);
992 class QHttpResponseHeaderPrivate : public QHttpHeaderPrivate
994 Q_DECLARE_PUBLIC(QHttpResponseHeader)
995 public:
996 int statCode;
997 QString reasonPhr;
998 int majVer;
999 int minVer;
1002 /****************************************************
1004 * QHttpResponseHeader
1006 ****************************************************/
1009 \class QHttpResponseHeader
1010 \brief The QHttpResponseHeader class contains response header information for HTTP.
1012 \ingroup io
1013 \inmodule QtNetwork
1015 This class is used by the QHttp class to report the header
1016 information that the client received from the server.
1018 HTTP responses have a status code that indicates the status of the
1019 response. This code is a 3-digit integer result code (for details
1020 see to RFC 1945). In addition to the status code, you can also
1021 specify a human-readable text that describes the reason for the
1022 code ("reason phrase"). This class allows you to get the status
1023 code and the reason phrase.
1025 \sa QHttpRequestHeader, QHttp, {HTTP Example}
1029 Constructs an empty HTTP response header.
1031 QHttpResponseHeader::QHttpResponseHeader()
1032 : QHttpHeader(*new QHttpResponseHeaderPrivate)
1034 setValid(false);
1038 Constructs a copy of \a header.
1040 QHttpResponseHeader::QHttpResponseHeader(const QHttpResponseHeader &header)
1041 : QHttpHeader(*new QHttpResponseHeaderPrivate, header)
1043 Q_D(QHttpResponseHeader);
1044 d->statCode = header.d_func()->statCode;
1045 d->reasonPhr = header.d_func()->reasonPhr;
1046 d->majVer = header.d_func()->majVer;
1047 d->minVer = header.d_func()->minVer;
1051 Copies the contents of \a header into this QHttpResponseHeader.
1053 QHttpResponseHeader &QHttpResponseHeader::operator=(const QHttpResponseHeader &header)
1055 Q_D(QHttpResponseHeader);
1056 QHttpHeader::operator=(header);
1057 d->statCode = header.d_func()->statCode;
1058 d->reasonPhr = header.d_func()->reasonPhr;
1059 d->majVer = header.d_func()->majVer;
1060 d->minVer = header.d_func()->minVer;
1061 return *this;
1065 Constructs a HTTP response header from the string \a str. The
1066 string is parsed and the information is set. The \a str should
1067 consist of one or more "\r\n" delimited lines; the first line should be the
1068 status-line (format: HTTP-version, space, status-code, space,
1069 reason-phrase); each of remaining lines should have the format key, colon,
1070 space, value.
1072 QHttpResponseHeader::QHttpResponseHeader(const QString &str)
1073 : QHttpHeader(*new QHttpResponseHeaderPrivate)
1075 parse(str);
1079 \since 4.1
1081 Constructs a QHttpResponseHeader, setting the status code to \a code, the
1082 reason phrase to \a text and the protocol-version to \a majorVer and \a
1083 minorVer.
1085 \sa statusCode() reasonPhrase() majorVersion() minorVersion()
1087 QHttpResponseHeader::QHttpResponseHeader(int code, const QString &text, int majorVer, int minorVer)
1088 : QHttpHeader(*new QHttpResponseHeaderPrivate)
1090 setStatusLine(code, text, majorVer, minorVer);
1094 \since 4.1
1096 Sets the status code to \a code, the reason phrase to \a text and
1097 the protocol-version to \a majorVer and \a minorVer.
1099 \sa statusCode() reasonPhrase() majorVersion() minorVersion()
1101 void QHttpResponseHeader::setStatusLine(int code, const QString &text, int majorVer, int minorVer)
1103 Q_D(QHttpResponseHeader);
1104 setValid(true);
1105 d->statCode = code;
1106 d->reasonPhr = text;
1107 d->majVer = majorVer;
1108 d->minVer = minorVer;
1112 Returns the status code of the HTTP response header.
1114 \sa reasonPhrase() majorVersion() minorVersion()
1116 int QHttpResponseHeader::statusCode() const
1118 Q_D(const QHttpResponseHeader);
1119 return d->statCode;
1123 Returns the reason phrase of the HTTP response header.
1125 \sa statusCode() majorVersion() minorVersion()
1127 QString QHttpResponseHeader::reasonPhrase() const
1129 Q_D(const QHttpResponseHeader);
1130 return d->reasonPhr;
1134 Returns the major protocol-version of the HTTP response header.
1136 \sa minorVersion() statusCode() reasonPhrase()
1138 int QHttpResponseHeader::majorVersion() const
1140 Q_D(const QHttpResponseHeader);
1141 return d->majVer;
1145 Returns the minor protocol-version of the HTTP response header.
1147 \sa majorVersion() statusCode() reasonPhrase()
1149 int QHttpResponseHeader::minorVersion() const
1151 Q_D(const QHttpResponseHeader);
1152 return d->minVer;
1155 /*! \reimp
1157 bool QHttpResponseHeader::parseLine(const QString &line, int number)
1159 Q_D(QHttpResponseHeader);
1160 if (number != 0)
1161 return QHttpHeader::parseLine(line, number);
1163 QString l = line.simplified();
1164 if (l.length() < 10)
1165 return false;
1167 if (l.left(5) == QLatin1String("HTTP/") && l[5].isDigit() && l[6] == QLatin1Char('.') &&
1168 l[7].isDigit() && l[8] == QLatin1Char(' ') && l[9].isDigit()) {
1169 d->majVer = l[5].toLatin1() - '0';
1170 d->minVer = l[7].toLatin1() - '0';
1172 int pos = l.indexOf(QLatin1Char(' '), 9);
1173 if (pos != -1) {
1174 d->reasonPhr = l.mid(pos + 1);
1175 d->statCode = l.mid(9, pos - 9).toInt();
1176 } else {
1177 d->statCode = l.mid(9).toInt();
1178 d->reasonPhr.clear();
1180 } else {
1181 return false;
1184 return true;
1187 /*! \reimp
1189 QString QHttpResponseHeader::toString() const
1191 Q_D(const QHttpResponseHeader);
1192 QString ret(QLatin1String("HTTP/%1.%2 %3 %4\r\n%5\r\n"));
1193 return ret.arg(d->majVer).arg(d->minVer).arg(d->statCode).arg(d->reasonPhr).arg(QHttpHeader::toString());
1196 class QHttpRequestHeaderPrivate : public QHttpHeaderPrivate
1198 Q_DECLARE_PUBLIC(QHttpRequestHeader)
1199 public:
1200 QString m;
1201 QString p;
1202 int majVer;
1203 int minVer;
1206 /****************************************************
1208 * QHttpRequestHeader
1210 ****************************************************/
1213 \class QHttpRequestHeader
1214 \brief The QHttpRequestHeader class contains request header information for HTTP.
1216 \ingroup io
1217 \inmodule QtNetwork
1219 This class is used in the QHttp class to report the header
1220 information if the client requests something from the server.
1222 HTTP requests have a method which describes the request's action.
1223 The most common requests are "GET" and "POST". In addition to the
1224 request method the header also includes a request-URI to specify
1225 the location for the method to use.
1227 The method, request-URI and protocol-version can be set using a
1228 constructor or later using setRequest(). The values can be
1229 obtained using method(), path(), majorVersion() and
1230 minorVersion().
1232 Note that the request-URI must be in the format expected by the
1233 HTTP server. That is, all reserved characters must be encoded in
1234 %HH (where HH are two hexadecimal digits). See
1235 QUrl::toPercentEncoding() for more information.
1237 Important inherited functions: setValue() and value().
1239 \sa QHttpResponseHeader QHttp
1243 Constructs an empty HTTP request header.
1245 QHttpRequestHeader::QHttpRequestHeader()
1246 : QHttpHeader(*new QHttpRequestHeaderPrivate)
1248 setValid(false);
1252 Constructs a HTTP request header for the method \a method, the
1253 request-URI \a path and the protocol-version \a majorVer and \a
1254 minorVer. The \a path argument must be properly encoded for an
1255 HTTP request.
1257 QHttpRequestHeader::QHttpRequestHeader(const QString &method, const QString &path, int majorVer, int minorVer)
1258 : QHttpHeader(*new QHttpRequestHeaderPrivate)
1260 Q_D(QHttpRequestHeader);
1261 d->m = method;
1262 d->p = path;
1263 d->majVer = majorVer;
1264 d->minVer = minorVer;
1268 Constructs a copy of \a header.
1270 QHttpRequestHeader::QHttpRequestHeader(const QHttpRequestHeader &header)
1271 : QHttpHeader(*new QHttpRequestHeaderPrivate, header)
1273 Q_D(QHttpRequestHeader);
1274 d->m = header.d_func()->m;
1275 d->p = header.d_func()->p;
1276 d->majVer = header.d_func()->majVer;
1277 d->minVer = header.d_func()->minVer;
1281 Copies the content of \a header into this QHttpRequestHeader
1283 QHttpRequestHeader &QHttpRequestHeader::operator=(const QHttpRequestHeader &header)
1285 Q_D(QHttpRequestHeader);
1286 QHttpHeader::operator=(header);
1287 d->m = header.d_func()->m;
1288 d->p = header.d_func()->p;
1289 d->majVer = header.d_func()->majVer;
1290 d->minVer = header.d_func()->minVer;
1291 return *this;
1295 Constructs a HTTP request header from the string \a str. The \a
1296 str should consist of one or more "\r\n" delimited lines; the first line
1297 should be the request-line (format: method, space, request-URI, space
1298 HTTP-version); each of the remaining lines should have the format key,
1299 colon, space, value.
1301 QHttpRequestHeader::QHttpRequestHeader(const QString &str)
1302 : QHttpHeader(*new QHttpRequestHeaderPrivate)
1304 parse(str);
1308 This function sets the request method to \a method, the
1309 request-URI to \a path and the protocol-version to \a majorVer and
1310 \a minorVer. The \a path argument must be properly encoded for an
1311 HTTP request.
1313 \sa method() path() majorVersion() minorVersion()
1315 void QHttpRequestHeader::setRequest(const QString &method, const QString &path, int majorVer, int minorVer)
1317 Q_D(QHttpRequestHeader);
1318 setValid(true);
1319 d->m = method;
1320 d->p = path;
1321 d->majVer = majorVer;
1322 d->minVer = minorVer;
1326 Returns the method of the HTTP request header.
1328 \sa path() majorVersion() minorVersion() setRequest()
1330 QString QHttpRequestHeader::method() const
1332 Q_D(const QHttpRequestHeader);
1333 return d->m;
1337 Returns the request-URI of the HTTP request header.
1339 \sa method() majorVersion() minorVersion() setRequest()
1341 QString QHttpRequestHeader::path() const
1343 Q_D(const QHttpRequestHeader);
1344 return d->p;
1348 Returns the major protocol-version of the HTTP request header.
1350 \sa minorVersion() method() path() setRequest()
1352 int QHttpRequestHeader::majorVersion() const
1354 Q_D(const QHttpRequestHeader);
1355 return d->majVer;
1359 Returns the minor protocol-version of the HTTP request header.
1361 \sa majorVersion() method() path() setRequest()
1363 int QHttpRequestHeader::minorVersion() const
1365 Q_D(const QHttpRequestHeader);
1366 return d->minVer;
1369 /*! \reimp
1371 bool QHttpRequestHeader::parseLine(const QString &line, int number)
1373 Q_D(QHttpRequestHeader);
1374 if (number != 0)
1375 return QHttpHeader::parseLine(line, number);
1377 QStringList lst = line.simplified().split(QLatin1String(" "));
1378 if (lst.count() > 0) {
1379 d->m = lst[0];
1380 if (lst.count() > 1) {
1381 d->p = lst[1];
1382 if (lst.count() > 2) {
1383 QString v = lst[2];
1384 if (v.length() >= 8 && v.left(5) == QLatin1String("HTTP/") &&
1385 v[5].isDigit() && v[6] == QLatin1Char('.') && v[7].isDigit()) {
1386 d->majVer = v[5].toLatin1() - '0';
1387 d->minVer = v[7].toLatin1() - '0';
1388 return true;
1394 return false;
1397 /*! \reimp
1399 QString QHttpRequestHeader::toString() const
1401 Q_D(const QHttpRequestHeader);
1402 QString first(QLatin1String("%1 %2"));
1403 QString last(QLatin1String(" HTTP/%3.%4\r\n%5\r\n"));
1404 return first.arg(d->m).arg(d->p) +
1405 last.arg(d->majVer).arg(d->minVer).arg(QHttpHeader::toString());
1409 /****************************************************
1411 * QHttp
1413 ****************************************************/
1415 \class QHttp
1416 \reentrant
1418 \brief The QHttp class provides an implementation of the HTTP protocol.
1420 \ingroup io
1421 \inmodule QtNetwork
1422 \mainclass
1424 This class provides a direct interface to HTTP that allows you to
1425 have more control over the requests and that allows you to access
1426 the response header fields. However, for new applications, it is
1427 recommended to use QNetworkAccessManager and QNetworkReply, as
1428 those classes possess a simpler, yet more powerful API.
1430 The class works asynchronously, so there are no blocking
1431 functions. If an operation cannot be executed immediately, the
1432 function will still return straight away and the operation will be
1433 scheduled for later execution. The results of scheduled operations
1434 are reported via signals. This approach depends on the event loop
1435 being in operation.
1437 The operations that can be scheduled (they are called "requests"
1438 in the rest of the documentation) are the following: setHost(),
1439 get(), post(), head() and request().
1441 All of these requests return a unique identifier that allows you
1442 to keep track of the request that is currently executed. When the
1443 execution of a request starts, the requestStarted() signal with
1444 the identifier is emitted and when the request is finished, the
1445 requestFinished() signal is emitted with the identifier and a bool
1446 that indicates if the request finished with an error.
1448 To make an HTTP request you must set up suitable HTTP headers. The
1449 following example demonstrates how to request the main HTML page
1450 from the Trolltech home page (i.e., the URL
1451 \c http://qtsoftware.com/index.html):
1453 \snippet doc/src/snippets/code/src_network_access_qhttp.cpp 2
1455 For the common HTTP requests \c GET, \c POST and \c HEAD, QHttp
1456 provides the convenience functions get(), post() and head(). They
1457 already use a reasonable header and if you don't have to set
1458 special header fields, they are easier to use. The above example
1459 can also be written as:
1461 \snippet doc/src/snippets/code/src_network_access_qhttp.cpp 3
1463 For this example the following sequence of signals is emitted
1464 (with small variations, depending on network traffic, etc.):
1466 \snippet doc/src/snippets/code/src_network_access_qhttp.cpp 4
1468 The dataSendProgress() and dataReadProgress() signals in the above
1469 example are useful if you want to show a \link QProgressBar
1470 progress bar\endlink to inform the user about the progress of the
1471 download. The second argument is the total size of data. In
1472 certain cases it is not possible to know the total amount in
1473 advance, in which case the second argument is 0. (If you connect
1474 to a QProgressBar a total of 0 results in a busy indicator.)
1476 When the response header is read, it is reported with the
1477 responseHeaderReceived() signal.
1479 The readyRead() signal tells you that there is data ready to be
1480 read. The amount of data can then be queried with the
1481 bytesAvailable() function and it can be read with the read()
1482 or readAll() functions.
1484 If an error occurs during the execution of one of the commands in
1485 a sequence of commands, all the pending commands (i.e. scheduled,
1486 but not yet executed commands) are cleared and no signals are
1487 emitted for them.
1489 For example, if you have the following sequence of requests
1491 \snippet doc/src/snippets/code/src_network_access_qhttp.cpp 5
1493 and the get() request fails because the host lookup fails, then
1494 the post() request is never executed and the signals would look
1495 like this:
1497 \snippet doc/src/snippets/code/src_network_access_qhttp.cpp 6
1499 You can then get details about the error with the error() and
1500 errorString() functions. Note that only unexpected behavior, like
1501 network failure is considered as an error. If the server response
1502 contains an error status, like a 404 response, this is reported as
1503 a normal response case. So you should always check the \link
1504 QHttpResponseHeader::statusCode() status code \endlink of the
1505 response header.
1507 The functions currentId() and currentRequest() provide more
1508 information about the currently executing request.
1510 The functions hasPendingRequests() and clearPendingRequests()
1511 allow you to query and clear the list of pending requests.
1513 \sa QFtp, QNetworkAccessManager, QNetworkRequest, QNetworkReply,
1514 {HTTP Example}, {Torrent Example}
1518 Constructs a QHttp object. The \a parent parameter is passed on
1519 to the QObject constructor.
1521 QHttp::QHttp(QObject *parent)
1522 : QObject(*new QHttpPrivate, parent)
1524 Q_D(QHttp);
1525 d->init();
1529 Constructs a QHttp object. Subsequent requests are done by
1530 connecting to the server \a hostName on port \a port.
1532 The \a parent parameter is passed on to the QObject constructor.
1534 \sa setHost()
1536 QHttp::QHttp(const QString &hostName, quint16 port, QObject *parent)
1537 : QObject(*new QHttpPrivate, parent)
1539 Q_D(QHttp);
1540 d->init();
1542 d->hostName = hostName;
1543 d->port = port;
1547 Constructs a QHttp object. Subsequent requests are done by
1548 connecting to the server \a hostName on port \a port using the
1549 connection mode \a mode.
1551 If port is 0, it will use the default port for the \a mode used
1552 (80 for Http and 443 for Https).
1554 The \a parent parameter is passed on to the QObject constructor.
1556 \sa setHost()
1558 QHttp::QHttp(const QString &hostName, ConnectionMode mode, quint16 port, QObject *parent)
1559 : QObject(*new QHttpPrivate, parent)
1561 Q_D(QHttp);
1562 d->init();
1564 d->hostName = hostName;
1565 if (port == 0)
1566 port = (mode == ConnectionModeHttp) ? 80 : 443;
1567 d->port = port;
1568 d->mode = mode;
1571 void QHttpPrivate::init()
1573 Q_Q(QHttp);
1574 errorString = QLatin1String(QT_TRANSLATE_NOOP("QHttp", "Unknown error"));
1575 QMetaObject::invokeMethod(q, "_q_slotDoFinished", Qt::QueuedConnection);
1576 post100ContinueTimer.setSingleShot(true);
1577 QObject::connect(&post100ContinueTimer, SIGNAL(timeout()), q, SLOT(_q_continuePost()));
1581 Destroys the QHttp object. If there is an open connection, it is
1582 closed.
1584 QHttp::~QHttp()
1586 abort();
1590 \enum QHttp::ConnectionMode
1591 \since 4.3
1593 This enum is used to specify the mode of connection to use:
1595 \value ConnectionModeHttp The connection is a regular Http connection to the server
1596 \value ConnectionModeHttps The Https protocol is used and the connection is encrypted using SSL.
1598 When using the Https mode, care should be taken to connect to the sslErrors signal, and
1599 handle possible Ssl errors.
1601 \sa QSslSocket
1605 \enum QHttp::State
1607 This enum is used to specify the state the client is in:
1609 \value Unconnected There is no connection to the host.
1610 \value HostLookup A host name lookup is in progress.
1611 \value Connecting An attempt to connect to the host is in progress.
1612 \value Sending The client is sending its request to the server.
1613 \value Reading The client's request has been sent and the client
1614 is reading the server's response.
1615 \value Connected The connection to the host is open, but the client is
1616 neither sending a request, nor waiting for a response.
1617 \value Closing The connection is closing down, but is not yet
1618 closed. (The state will be \c Unconnected when the connection is
1619 closed.)
1621 \sa stateChanged() state()
1624 /*! \enum QHttp::Error
1626 This enum identifies the error that occurred.
1628 \value NoError No error occurred.
1629 \value HostNotFound The host name lookup failed.
1630 \value ConnectionRefused The server refused the connection.
1631 \value UnexpectedClose The server closed the connection unexpectedly.
1632 \value InvalidResponseHeader The server sent an invalid response header.
1633 \value WrongContentLength The client could not read the content correctly
1634 because an error with respect to the content length occurred.
1635 \value Aborted The request was aborted with abort().
1636 \value ProxyAuthenticationRequiredError QHttp is using a proxy, and the
1637 proxy server requires authentication to establish a connection.
1638 \value AuthenticationRequiredError The web server requires authentication
1639 to complete the request.
1640 \value UnknownError An error other than those specified above
1641 occurred.
1643 \sa error()
1647 \fn void QHttp::stateChanged(int state)
1649 This signal is emitted when the state of the QHttp object changes.
1650 The argument \a state is the new state of the connection; it is
1651 one of the \l State values.
1653 This usually happens when a request is started, but it can also
1654 happen when the server closes the connection or when a call to
1655 close() succeeded.
1657 \sa get() post() head() request() close() state() State
1661 \fn void QHttp::responseHeaderReceived(const QHttpResponseHeader &resp);
1663 This signal is emitted when the HTTP header of a server response
1664 is available. The header is passed in \a resp.
1666 \sa get() post() head() request() readyRead()
1670 \fn void QHttp::readyRead(const QHttpResponseHeader &resp)
1672 This signal is emitted when there is new response data to read.
1674 If you specified a device in the request where the data should be
1675 written to, then this signal is \e not emitted; instead the data
1676 is written directly to the device.
1678 The response header is passed in \a resp.
1680 You can read the data with the readAll() or read() functions
1682 This signal is useful if you want to process the data in chunks as
1683 soon as it becomes available. If you are only interested in the
1684 complete data, just connect to the requestFinished() signal and
1685 read the data then instead.
1687 \sa get() post() request() readAll() read() bytesAvailable()
1691 \fn void QHttp::dataSendProgress(int done, int total)
1693 This signal is emitted when this object sends data to a HTTP
1694 server to inform it about the progress of the upload.
1696 \a done is the amount of data that has already arrived and \a
1697 total is the total amount of data. It is possible that the total
1698 amount of data that should be transferred cannot be determined, in
1699 which case \a total is 0.(If you connect to a QProgressBar, the
1700 progress bar shows a busy indicator if the total is 0).
1702 \warning \a done and \a total are not necessarily the size in
1703 bytes, since for large files these values might need to be
1704 "scaled" to avoid overflow.
1706 \sa dataReadProgress(), post(), request(), QProgressBar
1710 \fn void QHttp::dataReadProgress(int done, int total)
1712 This signal is emitted when this object reads data from a HTTP
1713 server to indicate the current progress of the download.
1715 \a done is the amount of data that has already arrived and \a
1716 total is the total amount of data. It is possible that the total
1717 amount of data that should be transferred cannot be determined, in
1718 which case \a total is 0.(If you connect to a QProgressBar, the
1719 progress bar shows a busy indicator if the total is 0).
1721 \warning \a done and \a total are not necessarily the size in
1722 bytes, since for large files these values might need to be
1723 "scaled" to avoid overflow.
1725 \sa dataSendProgress() get() post() request() QProgressBar
1729 \fn void QHttp::requestStarted(int id)
1731 This signal is emitted when processing the request identified by
1732 \a id starts.
1734 \sa requestFinished() done()
1738 \fn void QHttp::requestFinished(int id, bool error)
1740 This signal is emitted when processing the request identified by
1741 \a id has finished. \a error is true if an error occurred during
1742 the processing; otherwise \a error is false.
1744 \sa requestStarted() done() error() errorString()
1748 \fn void QHttp::done(bool error)
1750 This signal is emitted when the last pending request has finished;
1751 (it is emitted after the last request's requestFinished() signal).
1752 \a error is true if an error occurred during the processing;
1753 otherwise \a error is false.
1755 \sa requestFinished() error() errorString()
1758 #ifndef QT_NO_NETWORKPROXY
1761 \fn void QHttp::proxyAuthenticationRequired(const QNetworkProxy &proxy, QAuthenticator *authenticator)
1762 \since 4.3
1764 This signal can be emitted when a \a proxy that requires
1765 authentication is used. The \a authenticator object can then be
1766 filled in with the required details to allow authentication and
1767 continue the connection.
1769 \note It is not possible to use a QueuedConnection to connect to
1770 this signal, as the connection will fail if the authenticator has
1771 not been filled in with new information when the signal returns.
1773 \sa QAuthenticator, QNetworkProxy
1776 #endif
1779 \fn void QHttp::authenticationRequired(const QString &hostname, quint16 port, QAuthenticator *authenticator)
1780 \since 4.3
1782 This signal can be emitted when a web server on a given \a hostname and \a
1783 port requires authentication. The \a authenticator object can then be
1784 filled in with the required details to allow authentication and continue
1785 the connection.
1787 \note It is not possible to use a QueuedConnection to connect to
1788 this signal, as the connection will fail if the authenticator has
1789 not been filled in with new information when the signal returns.
1791 \sa QAuthenticator, QNetworkProxy
1795 \fn void QHttp::sslErrors(const QList<QSslError> &errors)
1796 \since 4.3
1798 Forwards the sslErrors signal from the QSslSocket used in QHttp. \a errors
1799 is the list of errors that occurred during the SSL handshake. Unless you
1800 call ignoreSslErrors() from within a slot connected to this signal when an
1801 error occurs, QHttp will tear down the connection immediately after
1802 emitting the signal.
1804 \sa QSslSocket QSslSocket::ignoreSslErrors()
1808 Aborts the current request and deletes all scheduled requests.
1810 For the current request, the requestFinished() signal with the \c
1811 error argument \c true is emitted. For all other requests that are
1812 affected by the abort(), no signals are emitted.
1814 Since this slot also deletes the scheduled requests, there are no
1815 requests left and the done() signal is emitted (with the \c error
1816 argument \c true).
1818 \sa clearPendingRequests()
1820 void QHttp::abort()
1822 Q_D(QHttp);
1823 if (d->pending.isEmpty())
1824 return;
1826 d->finishedWithError(tr("Request aborted"), Aborted);
1827 clearPendingRequests();
1828 if (d->socket)
1829 d->socket->abort();
1830 d->closeConn();
1834 Returns the number of bytes that can be read from the response
1835 content at the moment.
1837 \sa get() post() request() readyRead() read() readAll()
1839 qint64 QHttp::bytesAvailable() const
1841 Q_D(const QHttp);
1842 #if defined(QHTTP_DEBUG)
1843 qDebug("QHttp::bytesAvailable(): %d bytes", (int)d->rba.size());
1844 #endif
1845 return qint64(d->rba.size());
1848 /*! \fn qint64 QHttp::readBlock(char *data, quint64 maxlen)
1850 Use read() instead.
1854 Reads \a maxlen bytes from the response content into \a data and
1855 returns the number of bytes read. Returns -1 if an error occurred.
1857 \sa get() post() request() readyRead() bytesAvailable() readAll()
1859 qint64 QHttp::read(char *data, qint64 maxlen)
1861 Q_D(QHttp);
1862 if (data == 0 && maxlen != 0) {
1863 qWarning("QHttp::read: Null pointer error");
1864 return -1;
1866 if (maxlen >= d->rba.size())
1867 maxlen = d->rba.size();
1868 int readSoFar = 0;
1869 while (!d->rba.isEmpty() && readSoFar < maxlen) {
1870 int nextBlockSize = d->rba.nextDataBlockSize();
1871 int bytesToRead = qMin<qint64>(maxlen - readSoFar, nextBlockSize);
1872 memcpy(data + readSoFar, d->rba.readPointer(), bytesToRead);
1873 d->rba.free(bytesToRead);
1874 readSoFar += bytesToRead;
1877 d->bytesDone += maxlen;
1878 #if defined(QHTTP_DEBUG)
1879 qDebug("QHttp::read(): read %lld bytes (%lld bytes done)", maxlen, d->bytesDone);
1880 #endif
1881 return maxlen;
1885 Reads all the bytes from the response content and returns them.
1887 \sa get() post() request() readyRead() bytesAvailable() read()
1889 QByteArray QHttp::readAll()
1891 qint64 avail = bytesAvailable();
1892 QByteArray tmp;
1893 tmp.resize(int(avail));
1894 qint64 got = read(tmp.data(), int(avail));
1895 tmp.resize(got);
1896 return tmp;
1900 Returns the identifier of the HTTP request being executed or 0 if
1901 there is no request being executed (i.e. they've all finished).
1903 \sa currentRequest()
1905 int QHttp::currentId() const
1907 Q_D(const QHttp);
1908 if (d->pending.isEmpty())
1909 return 0;
1910 return d->pending.first()->id;
1914 Returns the request header of the HTTP request being executed. If
1915 the request is one issued by setHost() or close(), it
1916 returns an invalid request header, i.e.
1917 QHttpRequestHeader::isValid() returns false.
1919 \sa currentId()
1921 QHttpRequestHeader QHttp::currentRequest() const
1923 Q_D(const QHttp);
1924 if (!d->pending.isEmpty()) {
1925 QHttpRequest *r = d->pending.first();
1926 if (r->hasRequestHeader())
1927 return r->requestHeader();
1929 return QHttpRequestHeader();
1933 Returns the received response header of the most recently finished HTTP
1934 request. If no response has yet been received
1935 QHttpResponseHeader::isValid() will return false.
1937 \sa currentRequest()
1939 QHttpResponseHeader QHttp::lastResponse() const
1941 Q_D(const QHttp);
1942 return d->response;
1946 Returns the QIODevice pointer that is used as the data source of the HTTP
1947 request being executed. If there is no current request or if the request
1948 does not use an IO device as the data source, this function returns 0.
1950 This function can be used to delete the QIODevice in the slot connected to
1951 the requestFinished() signal.
1953 \sa currentDestinationDevice() post() request()
1955 QIODevice *QHttp::currentSourceDevice() const
1957 Q_D(const QHttp);
1958 if (d->pending.isEmpty())
1959 return 0;
1960 return d->pending.first()->sourceDevice();
1964 Returns the QIODevice pointer that is used as to store the data of the HTTP
1965 request being executed. If there is no current request or if the request
1966 does not store the data to an IO device, this function returns 0.
1968 This function can be used to delete the QIODevice in the slot connected to
1969 the requestFinished() signal.
1971 \sa currentSourceDevice() get() post() request()
1973 QIODevice *QHttp::currentDestinationDevice() const
1975 Q_D(const QHttp);
1976 if (d->pending.isEmpty())
1977 return 0;
1978 return d->pending.first()->destinationDevice();
1982 Returns true if there are any requests scheduled that have not yet
1983 been executed; otherwise returns false.
1985 The request that is being executed is \e not considered as a
1986 scheduled request.
1988 \sa clearPendingRequests() currentId() currentRequest()
1990 bool QHttp::hasPendingRequests() const
1992 Q_D(const QHttp);
1993 return d->pending.count() > 1;
1997 Deletes all pending requests from the list of scheduled requests.
1998 This does not affect the request that is being executed. If
1999 you want to stop this as well, use abort().
2001 \sa hasPendingRequests() abort()
2003 void QHttp::clearPendingRequests()
2005 Q_D(QHttp);
2006 // delete all entires except the first one
2007 while (d->pending.count() > 1)
2008 delete d->pending.takeLast();
2012 Sets the HTTP server that is used for requests to \a hostName on
2013 port \a port.
2015 The function does not block; instead, it returns immediately. The request
2016 is scheduled, and its execution is performed asynchronously. The
2017 function returns a unique identifier which is passed by
2018 requestStarted() and requestFinished().
2020 When the request is started the requestStarted() signal is
2021 emitted. When it is finished the requestFinished() signal is
2022 emitted.
2024 \sa get() post() head() request() requestStarted() requestFinished() done()
2026 int QHttp::setHost(const QString &hostName, quint16 port)
2028 Q_D(QHttp);
2029 return d->addRequest(new QHttpSetHostRequest(hostName, port, ConnectionModeHttp));
2033 Sets the HTTP server that is used for requests to \a hostName on
2034 port \a port using the connection mode \a mode.
2036 If port is 0, it will use the default port for the \a mode used
2037 (80 for Http and 443 fopr Https).
2039 The function does not block; instead, it returns immediately. The request
2040 is scheduled, and its execution is performed asynchronously. The
2041 function returns a unique identifier which is passed by
2042 requestStarted() and requestFinished().
2044 When the request is started the requestStarted() signal is
2045 emitted. When it is finished the requestFinished() signal is
2046 emitted.
2048 \sa get() post() head() request() requestStarted() requestFinished() done()
2050 int QHttp::setHost(const QString &hostName, ConnectionMode mode, quint16 port)
2052 #ifdef QT_NO_OPENSSL
2053 if (mode == ConnectionModeHttps)
2054 qWarning("QHttp::setHost: HTTPS connection requested but SSL support not compiled in");
2055 #endif
2056 Q_D(QHttp);
2057 if (port == 0)
2058 port = (mode == ConnectionModeHttp) ? 80 : 443;
2059 return d->addRequest(new QHttpSetHostRequest(hostName, port, mode));
2063 Replaces the internal QTcpSocket that QHttp uses with \a
2064 socket. This is useful if you want to use your own custom QTcpSocket
2065 subclass instead of the plain QTcpSocket that QHttp uses by default.
2066 QHttp does not take ownership of the socket, and will not delete \a
2067 socket when destroyed.
2069 The function does not block; instead, it returns immediately. The request
2070 is scheduled, and its execution is performed asynchronously. The
2071 function returns a unique identifier which is passed by
2072 requestStarted() and requestFinished().
2074 When the request is started the requestStarted() signal is
2075 emitted. When it is finished the requestFinished() signal is
2076 emitted.
2078 Note: If QHttp is used in a non-GUI thread that runs its own event
2079 loop, you must move \a socket to that thread before calling setSocket().
2081 \sa QObject::moveToThread(), {Thread Support in Qt}
2083 int QHttp::setSocket(QTcpSocket *socket)
2085 Q_D(QHttp);
2086 return d->addRequest(new QHttpSetSocketRequest(socket));
2090 This function sets the user name \a userName and password \a
2091 password for web pages that require authentication.
2093 The function does not block; instead, it returns immediately. The request
2094 is scheduled, and its execution is performed asynchronously. The
2095 function returns a unique identifier which is passed by
2096 requestStarted() and requestFinished().
2098 When the request is started the requestStarted() signal is
2099 emitted. When it is finished the requestFinished() signal is
2100 emitted.
2102 int QHttp::setUser(const QString &userName, const QString &password)
2104 Q_D(QHttp);
2105 return d->addRequest(new QHttpSetUserRequest(userName, password));
2108 #ifndef QT_NO_NETWORKPROXY
2111 Enables HTTP proxy support, using the proxy server \a host on port \a
2112 port. \a username and \a password can be provided if the proxy server
2113 requires authentication.
2115 Example:
2117 \snippet doc/src/snippets/code/src_network_access_qhttp.cpp 7
2119 QHttp supports non-transparent web proxy servers only, such as the Squid
2120 Web proxy cache server (from \l http://www.squid.org/). For transparent
2121 proxying, such as SOCKS5, use QNetworkProxy instead.
2123 \note setProxy() has to be called before setHost() for it to take effect.
2124 If setProxy() is called after setHost(), then it will not apply until after
2125 setHost() is called again.
2127 \sa QFtp::setProxy()
2129 int QHttp::setProxy(const QString &host, int port,
2130 const QString &username, const QString &password)
2132 Q_D(QHttp);
2133 QNetworkProxy proxy(QNetworkProxy::HttpProxy, host, port, username, password);
2134 return d->addRequest(new QHttpSetProxyRequest(proxy));
2138 \overload
2140 Enables HTTP proxy support using the proxy settings from \a
2141 proxy. If \a proxy is a transparent proxy, QHttp will call
2142 QAbstractSocket::setProxy() on the underlying socket. If the type
2143 is QNetworkProxy::HttpCachingProxy, QHttp will behave like the
2144 previous function.
2146 \note for compatibility with Qt 4.3, if the proxy type is
2147 QNetworkProxy::HttpProxy and the request type is unencrypted (that
2148 is, ConnectionModeHttp), QHttp will treat the proxy as a caching
2149 proxy.
2151 int QHttp::setProxy(const QNetworkProxy &proxy)
2153 Q_D(QHttp);
2154 return d->addRequest(new QHttpSetProxyRequest(proxy));
2157 #endif
2160 Sends a get request for \a path to the server set by setHost() or
2161 as specified in the constructor.
2163 \a path must be a absolute path like \c /index.html or an
2164 absolute URI like \c http://qtsoftware.com/index.html and
2165 must be encoded with either QUrl::toPercentEncoding() or
2166 QUrl::encodedPath().
2168 If the IO device \a to is 0 the readyRead() signal is emitted
2169 every time new content data is available to read.
2171 If the IO device \a to is not 0, the content data of the response
2172 is written directly to the device. Make sure that the \a to
2173 pointer is valid for the duration of the operation (it is safe to
2174 delete it when the requestFinished() signal is emitted).
2176 \section1 Request Processing
2178 The function does not block; instead, it returns immediately. The request
2179 is scheduled, and its execution is performed asynchronously. The
2180 function returns a unique identifier which is passed by
2181 requestStarted() and requestFinished().
2183 When the request is started the requestStarted() signal is
2184 emitted. When it is finished the requestFinished() signal is
2185 emitted.
2187 \sa setHost(), post(), head(), request(), requestStarted(),
2188 requestFinished(), done()
2190 int QHttp::get(const QString &path, QIODevice *to)
2192 Q_D(QHttp);
2193 QHttpRequestHeader header(QLatin1String("GET"), path);
2194 header.setValue(QLatin1String("Connection"), QLatin1String("Keep-Alive"));
2195 return d->addRequest(new QHttpPGHRequest(header, (QIODevice *) 0, to));
2199 Sends a post request for \a path to the server set by setHost() or
2200 as specified in the constructor.
2202 \a path must be an absolute path like \c /index.html or an
2203 absolute URI like \c http://qtsoftware.com/index.html and
2204 must be encoded with either QUrl::toPercentEncoding() or
2205 QUrl::encodedPath().
2207 The incoming data comes via the \a data IO device.
2209 If the IO device \a to is 0 the readyRead() signal is emitted
2210 every time new content data is available to read.
2212 If the IO device \a to is not 0, the content data of the response
2213 is written directly to the device. Make sure that the \a to
2214 pointer is valid for the duration of the operation (it is safe to
2215 delete it when the requestFinished() signal is emitted).
2217 The function does not block; instead, it returns immediately. The request
2218 is scheduled, and its execution is performed asynchronously. The
2219 function returns a unique identifier which is passed by
2220 requestStarted() and requestFinished().
2222 When the request is started the requestStarted() signal is
2223 emitted. When it is finished the requestFinished() signal is
2224 emitted.
2226 \sa setHost() get() head() request() requestStarted() requestFinished() done()
2228 int QHttp::post(const QString &path, QIODevice *data, QIODevice *to )
2230 Q_D(QHttp);
2231 QHttpRequestHeader header(QLatin1String("POST"), path);
2232 header.setValue(QLatin1String("Connection"), QLatin1String("Keep-Alive"));
2233 return d->addRequest(new QHttpPGHRequest(header, data, to));
2237 \overload
2239 \a data is used as the content data of the HTTP request.
2241 int QHttp::post(const QString &path, const QByteArray &data, QIODevice *to)
2243 Q_D(QHttp);
2244 QHttpRequestHeader header(QLatin1String("POST"), path);
2245 header.setValue(QLatin1String("Connection"), QLatin1String("Keep-Alive"));
2246 return d->addRequest(new QHttpPGHRequest(header, new QByteArray(data), to));
2250 Sends a header request for \a path to the server set by setHost()
2251 or as specified in the constructor.
2253 \a path must be an absolute path like \c /index.html or an
2254 absolute URI like \c http://qtsoftware.com/index.html.
2256 The function does not block; instead, it returns immediately. The request
2257 is scheduled, and its execution is performed asynchronously. The
2258 function returns a unique identifier which is passed by
2259 requestStarted() and requestFinished().
2261 When the request is started the requestStarted() signal is
2262 emitted. When it is finished the requestFinished() signal is
2263 emitted.
2265 \sa setHost() get() post() request() requestStarted() requestFinished() done()
2267 int QHttp::head(const QString &path)
2269 Q_D(QHttp);
2270 QHttpRequestHeader header(QLatin1String("HEAD"), path);
2271 header.setValue(QLatin1String("Connection"), QLatin1String("Keep-Alive"));
2272 return d->addRequest(new QHttpPGHRequest(header, (QIODevice*)0, 0));
2276 Sends a request to the server set by setHost() or as specified in
2277 the constructor. Uses the \a header as the HTTP request header.
2278 You are responsible for setting up a header that is appropriate
2279 for your request.
2281 The incoming data comes via the \a data IO device.
2283 If the IO device \a to is 0 the readyRead() signal is emitted
2284 every time new content data is available to read.
2286 If the IO device \a to is not 0, the content data of the response
2287 is written directly to the device. Make sure that the \a to
2288 pointer is valid for the duration of the operation (it is safe to
2289 delete it when the requestFinished() signal is emitted).
2291 The function does not block; instead, it returns immediately. The request
2292 is scheduled, and its execution is performed asynchronously. The
2293 function returns a unique identifier which is passed by
2294 requestStarted() and requestFinished().
2296 When the request is started the requestStarted() signal is
2297 emitted. When it is finished the requestFinished() signal is
2298 emitted.
2300 \sa setHost() get() post() head() requestStarted() requestFinished() done()
2302 int QHttp::request(const QHttpRequestHeader &header, QIODevice *data, QIODevice *to)
2304 Q_D(QHttp);
2305 return d->addRequest(new QHttpNormalRequest(header, data, to));
2309 \overload
2311 \a data is used as the content data of the HTTP request.
2313 int QHttp::request(const QHttpRequestHeader &header, const QByteArray &data, QIODevice *to )
2315 Q_D(QHttp);
2316 return d->addRequest(new QHttpNormalRequest(header, new QByteArray(data), to));
2320 Closes the connection; this is useful if you have a keep-alive
2321 connection and want to close it.
2323 For the requests issued with get(), post() and head(), QHttp sets
2324 the connection to be keep-alive. You can also do this using the
2325 header you pass to the request() function. QHttp only closes the
2326 connection to the HTTP server if the response header requires it
2327 to do so.
2329 The function does not block; instead, it returns immediately. The request
2330 is scheduled, and its execution is performed asynchronously. The
2331 function returns a unique identifier which is passed by
2332 requestStarted() and requestFinished().
2334 When the request is started the requestStarted() signal is
2335 emitted. When it is finished the requestFinished() signal is
2336 emitted.
2338 If you want to close the connection immediately, you have to use
2339 abort() instead.
2341 \sa stateChanged() abort() requestStarted() requestFinished() done()
2343 int QHttp::close()
2345 Q_D(QHttp);
2346 return d->addRequest(new QHttpCloseRequest());
2350 \obsolete
2352 Behaves the same as close().
2354 int QHttp::closeConnection()
2356 Q_D(QHttp);
2357 return d->addRequest(new QHttpCloseRequest());
2360 int QHttpPrivate::addRequest(QHttpNormalRequest *req)
2362 QHttpRequestHeader h = req->requestHeader();
2363 if (h.path().isEmpty()) {
2364 // note: the following qWarning is autotested. If you change it, change the test too.
2365 qWarning("QHttp: empty path requested is invalid -- using '/'");
2366 h.setRequest(h.method(), QLatin1String("/"), h.majorVersion(), h.minorVersion());
2367 req->setRequestHeader(h);
2370 // contine below
2371 return addRequest(static_cast<QHttpRequest *>(req));
2374 int QHttpPrivate::addRequest(QHttpRequest *req)
2376 Q_Q(QHttp);
2377 pending.append(req);
2379 if (pending.count() == 1) {
2380 // don't emit the requestStarted() signal before the id is returned
2381 QMetaObject::invokeMethod(q, "_q_startNextRequest", Qt::QueuedConnection);
2383 return req->id;
2386 void QHttpPrivate::_q_startNextRequest()
2388 Q_Q(QHttp);
2389 if (pending.isEmpty())
2390 return;
2391 QHttpRequest *r = pending.first();
2393 error = QHttp::NoError;
2394 errorString = QLatin1String(QT_TRANSLATE_NOOP("QHttp", "Unknown error"));
2396 if (q->bytesAvailable() != 0)
2397 q->readAll(); // clear the data
2398 emit q->requestStarted(r->id);
2399 r->start(q);
2402 void QHttpPrivate::_q_slotSendRequest()
2404 if (hostName.isNull()) {
2405 finishedWithError(QLatin1String(QT_TRANSLATE_NOOP("QHttp", "No server set to connect to")),
2406 QHttp::UnknownError);
2407 return;
2410 QString connectionHost = hostName;
2411 int connectionPort = port;
2412 bool sslInUse = false;
2414 #ifndef QT_NO_OPENSSL
2415 QSslSocket *sslSocket = qobject_cast<QSslSocket *>(socket);
2416 if (mode == QHttp::ConnectionModeHttps || (sslSocket && sslSocket->isEncrypted()))
2417 sslInUse = true;
2418 #endif
2420 #ifndef QT_NO_NETWORKPROXY
2421 bool cachingProxyInUse = false;
2422 bool transparentProxyInUse = false;
2423 if (proxy.type() == QNetworkProxy::DefaultProxy)
2424 proxy = QNetworkProxy::applicationProxy();
2426 if (proxy.type() == QNetworkProxy::HttpCachingProxy) {
2427 if (proxy.hostName().isEmpty())
2428 proxy.setType(QNetworkProxy::NoProxy);
2429 else
2430 cachingProxyInUse = true;
2431 } else if (proxy.type() == QNetworkProxy::HttpProxy) {
2432 // Compatibility behaviour: HttpProxy can be used to mean both
2433 // transparent and caching proxy
2434 if (proxy.hostName().isEmpty()) {
2435 proxy.setType(QNetworkProxy::NoProxy);
2436 } else if (sslInUse) {
2437 // Disallow use of cacheing proxy with HTTPS; instead fall back to
2438 // transparent HTTP CONNECT proxying.
2439 transparentProxyInUse = true;
2440 } else {
2441 proxy.setType(QNetworkProxy::HttpCachingProxy);
2442 cachingProxyInUse = true;
2446 // Proxy support. Insert the Proxy-Authorization item into the
2447 // header before it's sent off to the proxy.
2448 if (cachingProxyInUse) {
2449 QUrl proxyUrl;
2450 proxyUrl.setScheme(QLatin1String("http"));
2451 proxyUrl.setHost(hostName);
2452 if (port && port != 80)
2453 proxyUrl.setPort(port);
2454 QString request = QString::fromAscii(proxyUrl.resolved(QUrl::fromEncoded(header.path().toLatin1())).toEncoded());
2456 header.setRequest(header.method(), request, header.majorVersion(), header.minorVersion());
2457 header.setValue(QLatin1String("Proxy-Connection"), QLatin1String("keep-alive"));
2459 QAuthenticatorPrivate *auth = QAuthenticatorPrivate::getPrivate(proxyAuthenticator);
2460 if (auth && auth->method != QAuthenticatorPrivate::None) {
2461 QByteArray response = auth->calculateResponse(header.method().toLatin1(), header.path().toLatin1());
2462 header.setValue(QLatin1String("Proxy-Authorization"), QString::fromLatin1(response));
2465 connectionHost = proxy.hostName();
2466 connectionPort = proxy.port();
2469 if (transparentProxyInUse || sslInUse) {
2470 socket->setProxy(proxy);
2472 #endif
2474 // Username support. Insert the user and password into the query
2475 // string.
2476 QAuthenticatorPrivate *auth = QAuthenticatorPrivate::getPrivate(authenticator);
2477 if (auth && auth->method != QAuthenticatorPrivate::None) {
2478 QByteArray response = auth->calculateResponse(header.method().toLatin1(), header.path().toLatin1());
2479 header.setValue(QLatin1String("Authorization"), QString::fromLatin1(response));
2482 // Do we need to setup a new connection or can we reuse an
2483 // existing one?
2484 if (socket->peerName() != connectionHost || socket->peerPort() != connectionPort
2485 || socket->state() != QTcpSocket::ConnectedState
2486 #ifndef QT_NO_OPENSSL
2487 || (sslSocket && sslSocket->isEncrypted() != (mode == QHttp::ConnectionModeHttps))
2488 #endif
2490 socket->blockSignals(true);
2491 socket->abort();
2492 socket->blockSignals(false);
2494 setState(QHttp::Connecting);
2495 #ifndef QT_NO_OPENSSL
2496 if (sslSocket && mode == QHttp::ConnectionModeHttps) {
2497 sslSocket->connectToHostEncrypted(hostName, port);
2498 } else
2499 #endif
2501 socket->connectToHost(connectionHost, connectionPort);
2503 } else {
2504 _q_slotConnected();
2509 void QHttpPrivate::finishedWithSuccess()
2511 Q_Q(QHttp);
2512 if (pending.isEmpty())
2513 return;
2514 QHttpRequest *r = pending.first();
2516 // did we recurse?
2517 if (r->finished)
2518 return;
2519 r->finished = true;
2520 hasFinishedWithError = false;
2522 emit q->requestFinished(r->id, false);
2523 if (hasFinishedWithError) {
2524 // we recursed and changed into an error. The finishedWithError function
2525 // below has emitted the done(bool) signal and cleared the queue by now.
2526 return;
2529 pending.removeFirst();
2530 delete r;
2532 if (pending.isEmpty()) {
2533 emit q->done(false);
2534 } else {
2535 _q_startNextRequest();
2539 void QHttpPrivate::finishedWithError(const QString &detail, int errorCode)
2541 Q_Q(QHttp);
2542 if (pending.isEmpty())
2543 return;
2544 QHttpRequest *r = pending.first();
2545 hasFinishedWithError = true;
2547 error = QHttp::Error(errorCode);
2548 errorString = detail;
2550 // did we recurse?
2551 if (!r->finished) {
2552 r->finished = true;
2553 emit q->requestFinished(r->id, true);
2556 while (!pending.isEmpty())
2557 delete pending.takeFirst();
2558 emit q->done(hasFinishedWithError);
2561 void QHttpPrivate::_q_slotClosed()
2563 Q_Q(QHttp);
2565 if (state == QHttp::Reading) {
2566 if (response.hasKey(QLatin1String("content-length"))) {
2567 // We got Content-Length, so did we get all bytes?
2568 if (bytesDone + q->bytesAvailable() != response.contentLength()) {
2569 finishedWithError(QLatin1String(QT_TRANSLATE_NOOP("QHttp", "Wrong content length")), QHttp::WrongContentLength);
2572 } else if (state == QHttp::Connecting || state == QHttp::Sending) {
2573 finishedWithError(QLatin1String(QT_TRANSLATE_NOOP("QHttp", "Server closed connection unexpectedly")), QHttp::UnexpectedClose);
2576 postDevice = 0;
2577 if (state != QHttp::Closing)
2578 setState(QHttp::Closing);
2579 QMetaObject::invokeMethod(q, "_q_slotDoFinished", Qt::QueuedConnection);
2582 void QHttpPrivate::_q_continuePost()
2584 if (pendingPost) {
2585 pendingPost = false;
2586 setState(QHttp::Sending);
2587 _q_slotBytesWritten(0);
2591 void QHttpPrivate::_q_slotConnected()
2593 if (state != QHttp::Sending) {
2594 bytesDone = 0;
2595 setState(QHttp::Sending);
2598 QString str = header.toString();
2599 bytesTotal = str.length();
2600 socket->write(str.toLatin1(), bytesTotal);
2601 #if defined(QHTTP_DEBUG)
2602 qDebug("QHttp: write request header %p:\n---{\n%s}---", &header, str.toLatin1().constData());
2603 #endif
2605 if (postDevice) {
2606 postDevice->seek(0); // reposition the device
2607 bytesTotal += postDevice->size();
2608 //check for 100-continue
2609 if (header.value(QLatin1String("expect")).contains(QLatin1String("100-continue"), Qt::CaseInsensitive)) {
2610 //create a time out for 2 secs.
2611 pendingPost = true;
2612 post100ContinueTimer.start(2000);
2614 } else {
2615 bytesTotal += buffer.size();
2616 socket->write(buffer, buffer.size());
2620 void QHttpPrivate::_q_slotError(QAbstractSocket::SocketError err)
2622 Q_Q(QHttp);
2623 postDevice = 0;
2625 if (state == QHttp::Connecting || state == QHttp::Reading || state == QHttp::Sending) {
2626 switch (err) {
2627 case QTcpSocket::ConnectionRefusedError:
2628 finishedWithError(QLatin1String(QT_TRANSLATE_NOOP("QHttp", "Connection refused (or timed out)")), QHttp::ConnectionRefused);
2629 break;
2630 case QTcpSocket::HostNotFoundError:
2631 finishedWithError(QString::fromLatin1(QT_TRANSLATE_NOOP("QHttp", "Host %1 not found"))
2632 .arg(socket->peerName()), QHttp::HostNotFound);
2633 break;
2634 case QTcpSocket::RemoteHostClosedError:
2635 if (state == QHttp::Sending && reconnectAttempts--) {
2636 setState(QHttp::Closing);
2637 setState(QHttp::Unconnected);
2638 socket->blockSignals(true);
2639 socket->abort();
2640 socket->blockSignals(false);
2641 QMetaObject::invokeMethod(q, "_q_slotSendRequest", Qt::QueuedConnection);
2642 return;
2644 break;
2645 #ifndef QT_NO_NETWORKPROXY
2646 case QTcpSocket::ProxyAuthenticationRequiredError:
2647 finishedWithError(socket->errorString(), QHttp::ProxyAuthenticationRequiredError);
2648 break;
2649 #endif
2650 default:
2651 finishedWithError(QLatin1String(QT_TRANSLATE_NOOP("QHttp", "HTTP request failed")), QHttp::UnknownError);
2652 break;
2656 closeConn();
2659 void QHttpPrivate::_q_slotBytesWritten(qint64 written)
2661 Q_Q(QHttp);
2662 bytesDone += written;
2663 emit q->dataSendProgress(bytesDone, bytesTotal);
2665 if (pendingPost)
2666 return;
2668 if (!postDevice)
2669 return;
2671 if (socket->bytesToWrite() == 0) {
2672 int max = qMin<qint64>(4096, postDevice->size() - postDevice->pos());
2673 QByteArray arr;
2674 arr.resize(max);
2676 int n = postDevice->read(arr.data(), max);
2677 if (n < 0) {
2678 qWarning("Could not read enough bytes from the device");
2679 closeConn();
2680 return;
2682 if (postDevice->atEnd()) {
2683 postDevice = 0;
2686 socket->write(arr, n);
2690 void QHttpPrivate::_q_slotReadyRead()
2692 Q_Q(QHttp);
2693 QHttp::State oldState = state;
2694 if (state != QHttp::Reading) {
2695 setState(QHttp::Reading);
2696 readHeader = true;
2697 headerStr = QLatin1String("");
2698 bytesDone = 0;
2699 chunkedSize = -1;
2700 repost = false;
2703 while (readHeader) {
2704 bool end = false;
2705 QString tmp;
2706 while (!end && socket->canReadLine()) {
2707 tmp = QString::fromAscii(socket->readLine());
2708 if (tmp == QLatin1String("\r\n") || tmp == QLatin1String("\n") || tmp.isEmpty())
2709 end = true;
2710 else
2711 headerStr += tmp;
2714 if (!end)
2715 return;
2717 response = QHttpResponseHeader(headerStr);
2718 headerStr = QLatin1String("");
2719 #if defined(QHTTP_DEBUG)
2720 qDebug("QHttp: read response header:\n---{\n%s}---", response.toString().toLatin1().constData());
2721 #endif
2722 // Check header
2723 if (!response.isValid()) {
2724 finishedWithError(QLatin1String(QT_TRANSLATE_NOOP("QHttp", "Invalid HTTP response header")),
2725 QHttp::InvalidResponseHeader);
2726 closeConn();
2727 return;
2730 int statusCode = response.statusCode();
2731 if (statusCode == 401 || statusCode == 407) { // (Proxy) Authentication required
2732 QAuthenticator *auth =
2733 #ifndef QT_NO_NETWORKPROXY
2734 statusCode == 407
2735 ? &proxyAuthenticator :
2736 #endif
2737 &authenticator;
2738 if (auth->isNull())
2739 auth->detach();
2740 QAuthenticatorPrivate *priv = QAuthenticatorPrivate::getPrivate(*auth);
2741 priv->parseHttpResponse(response, (statusCode == 407));
2742 if (priv->phase == QAuthenticatorPrivate::Done) {
2743 socket->blockSignals(true);
2744 #ifndef QT_NO_NETWORKPROXY
2745 if (statusCode == 407)
2746 emit q->proxyAuthenticationRequired(proxy, auth);
2747 else
2748 #endif
2749 emit q->authenticationRequired(hostName, port, auth);
2750 socket->blockSignals(false);
2751 } else if (priv->phase == QAuthenticatorPrivate::Invalid) {
2752 finishedWithError(QLatin1String(QT_TRANSLATE_NOOP("QHttp", "Unknown authentication method")),
2753 QHttp::AuthenticationRequiredError);
2754 closeConn();
2755 return;
2758 // priv->phase will get reset to QAuthenticatorPrivate::Start if the authenticator got modified in the signal above.
2759 if (priv->phase == QAuthenticatorPrivate::Done) {
2760 #ifndef QT_NO_NETWORKPROXY
2761 if (statusCode == 407)
2762 finishedWithError(QLatin1String(QT_TRANSLATE_NOOP("QHttp", "Proxy authentication required")),
2763 QHttp::ProxyAuthenticationRequiredError);
2764 else
2765 #endif
2766 finishedWithError(QLatin1String(QT_TRANSLATE_NOOP("QHttp", "Authentication required")),
2767 QHttp::AuthenticationRequiredError);
2768 closeConn();
2769 return;
2770 } else {
2771 // close the connection if it isn't already and reconnect using the chosen authentication method
2772 bool willClose = (response.value(QLatin1String("proxy-connection")).toLower() == QLatin1String("close"))
2773 || (response.value(QLatin1String("connection")).toLower() == QLatin1String("close"));
2774 if (willClose) {
2775 if (socket) {
2776 setState(QHttp::Closing);
2777 socket->blockSignals(true);
2778 socket->close();
2779 socket->blockSignals(false);
2780 socket->readAll();
2782 _q_slotSendRequest();
2783 return;
2784 } else {
2785 repost = true;
2788 } else {
2789 buffer.clear();
2792 if (response.statusCode() == 100 && pendingPost) {
2793 // if we have pending POST, start sending data otherwise ignore
2794 post100ContinueTimer.stop();
2795 QMetaObject::invokeMethod(q, "_q_continuePost", Qt::QueuedConnection);
2796 return;
2799 // The 100-continue header is ignored (in case of no 'expect:100-continue' header),
2800 // because when using the POST method, we send both the request header and data in
2801 // one chunk.
2802 if (response.statusCode() != 100) {
2803 post100ContinueTimer.stop();
2804 pendingPost = false;
2805 readHeader = false;
2806 if (response.hasKey(QLatin1String("transfer-encoding")) &&
2807 response.value(QLatin1String("transfer-encoding")).toLower().contains(QLatin1String("chunked")))
2808 chunkedSize = 0;
2810 if (!repost)
2811 emit q->responseHeaderReceived(response);
2812 if (state == QHttp::Unconnected || state == QHttp::Closing)
2813 return;
2814 } else {
2815 // Restore the state, the next incoming data will be treated as if
2816 // we never say the 100 response.
2817 state = oldState;
2821 bool everythingRead = false;
2823 if (q->currentRequest().method() == QLatin1String("HEAD") ||
2824 response.statusCode() == 304 || response.statusCode() == 204 ||
2825 response.statusCode() == 205) {
2826 // HEAD requests have only headers as replies
2827 // These status codes never have a body:
2828 // 304 Not Modified
2829 // 204 No Content
2830 // 205 Reset Content
2831 everythingRead = true;
2832 } else {
2833 qint64 n = socket->bytesAvailable();
2834 QByteArray *arr = 0;
2835 if (chunkedSize != -1) {
2836 // transfer-encoding is chunked
2837 for (;;) {
2838 // get chunk size
2839 if (chunkedSize == 0) {
2840 if (!socket->canReadLine())
2841 break;
2842 QString sizeString = QString::fromAscii(socket->readLine());
2843 int tPos = sizeString.indexOf(QLatin1Char(';'));
2844 if (tPos != -1)
2845 sizeString.truncate(tPos);
2846 bool ok;
2847 chunkedSize = sizeString.toInt(&ok, 16);
2848 if (!ok) {
2849 finishedWithError(QLatin1String(QT_TRANSLATE_NOOP("QHttp", "Invalid HTTP chunked body")),
2850 QHttp::WrongContentLength);
2851 closeConn();
2852 delete arr;
2853 return;
2855 if (chunkedSize == 0) // last-chunk
2856 chunkedSize = -2;
2859 // read trailer
2860 while (chunkedSize == -2 && socket->canReadLine()) {
2861 QString read = QString::fromAscii(socket->readLine());
2862 if (read == QLatin1String("\r\n") || read == QLatin1String("\n"))
2863 chunkedSize = -1;
2865 if (chunkedSize == -1) {
2866 everythingRead = true;
2867 break;
2870 // make sure that you can read the terminating CRLF,
2871 // otherwise wait until next time...
2872 n = socket->bytesAvailable();
2873 if (n == 0)
2874 break;
2875 if (n == chunkedSize || n == chunkedSize+1) {
2876 n = chunkedSize - 1;
2877 if (n == 0)
2878 break;
2881 // read data
2882 qint64 toRead = chunkedSize < 0 ? n : qMin(n, chunkedSize);
2883 if (!arr)
2884 arr = new QByteArray;
2885 uint oldArrSize = arr->size();
2886 arr->resize(oldArrSize + toRead);
2887 qint64 read = socket->read(arr->data()+oldArrSize, toRead);
2888 arr->resize(oldArrSize + read);
2890 chunkedSize -= read;
2892 if (chunkedSize == 0 && n - read >= 2) {
2893 // read terminating CRLF
2894 char tmp[2];
2895 socket->read(tmp, 2);
2896 if (tmp[0] != '\r' || tmp[1] != '\n') {
2897 finishedWithError(QLatin1String(QT_TRANSLATE_NOOP("QHttp", "Invalid HTTP chunked body")),
2898 QHttp::WrongContentLength);
2899 closeConn();
2900 delete arr;
2901 return;
2905 } else if (response.hasContentLength()) {
2906 if (repost && (n < response.contentLength())) {
2907 // wait for the content to be available fully
2908 // if repost is required, the content is ignored
2909 return;
2911 n = qMin(qint64(response.contentLength() - bytesDone), n);
2912 if (n > 0) {
2913 arr = new QByteArray;
2914 arr->resize(n);
2915 qint64 read = socket->read(arr->data(), n);
2916 arr->resize(read);
2918 if (bytesDone + q->bytesAvailable() + n == response.contentLength())
2919 everythingRead = true;
2920 } else if (n > 0) {
2921 // workaround for VC++ bug
2922 QByteArray temp = socket->readAll();
2923 arr = new QByteArray(temp);
2926 if (arr && !repost) {
2927 n = arr->size();
2928 if (toDevice) {
2929 qint64 bytesWritten;
2930 bytesWritten = toDevice->write(*arr, n);
2931 delete arr;
2932 arr = 0;
2933 // if writing to the device does not succeed, quit with error
2934 if (bytesWritten == -1 || bytesWritten < n) {
2935 finishedWithError(QLatin1String(QT_TRANSLATE_NOOP("QHttp", "Error writing response to device")), QHttp::UnknownError);
2936 } else {
2937 bytesDone += bytesWritten;
2938 #if defined(QHTTP_DEBUG)
2939 qDebug("QHttp::_q_slotReadyRead(): read %lld bytes (%lld bytes done)", n, bytesDone);
2940 #endif
2942 if (response.hasContentLength())
2943 emit q->dataReadProgress(bytesDone, response.contentLength());
2944 else
2945 emit q->dataReadProgress(bytesDone, 0);
2946 } else {
2947 char *ptr = rba.reserve(arr->size());
2948 memcpy(ptr, arr->data(), arr->size());
2949 delete arr;
2950 arr = 0;
2951 #if defined(QHTTP_DEBUG)
2952 qDebug("QHttp::_q_slotReadyRead(): read %lld bytes (%lld bytes done)", n, bytesDone + q->bytesAvailable());
2953 #endif
2954 if (response.hasContentLength())
2955 emit q->dataReadProgress(bytesDone + q->bytesAvailable(), response.contentLength());
2956 else
2957 emit q->dataReadProgress(bytesDone + q->bytesAvailable(), 0);
2958 emit q->readyRead(response);
2962 delete arr;
2965 if (everythingRead) {
2966 if (repost) {
2967 _q_slotSendRequest();
2968 return;
2970 // Handle "Connection: close"
2971 if (response.value(QLatin1String("connection")).toLower() == QLatin1String("close")) {
2972 closeConn();
2973 } else {
2974 setState(QHttp::Connected);
2975 // Start a timer, so that we emit the keep alive signal
2976 // "after" this method returned.
2977 QMetaObject::invokeMethod(q, "_q_slotDoFinished", Qt::QueuedConnection);
2982 void QHttpPrivate::_q_slotDoFinished()
2984 if (state == QHttp::Connected) {
2985 finishedWithSuccess();
2986 } else if (state != QHttp::Unconnected) {
2987 setState(QHttp::Unconnected);
2988 finishedWithSuccess();
2994 Returns the current state of the object. When the state changes,
2995 the stateChanged() signal is emitted.
2997 \sa State stateChanged()
2999 QHttp::State QHttp::state() const
3001 Q_D(const QHttp);
3002 return d->state;
3006 Returns the last error that occurred. This is useful to find out
3007 what happened when receiving a requestFinished() or a done()
3008 signal with the \c error argument \c true.
3010 If you start a new request, the error status is reset to \c NoError.
3012 QHttp::Error QHttp::error() const
3014 Q_D(const QHttp);
3015 return d->error;
3019 Returns a human-readable description of the last error that
3020 occurred. This is useful to present a error message to the user
3021 when receiving a requestFinished() or a done() signal with the \c
3022 error argument \c true.
3024 QString QHttp::errorString() const
3026 Q_D(const QHttp);
3027 return d->errorString;
3030 void QHttpPrivate::setState(int s)
3032 Q_Q(QHttp);
3033 #if defined(QHTTP_DEBUG)
3034 qDebug("QHttp state changed %d -> %d", state, s);
3035 #endif
3036 state = QHttp::State(s);
3037 emit q->stateChanged(s);
3040 void QHttpPrivate::closeConn()
3042 Q_Q(QHttp);
3043 // If no connection is open -> ignore
3044 if (state == QHttp::Closing || state == QHttp::Unconnected)
3045 return;
3047 postDevice = 0;
3048 setState(QHttp::Closing);
3050 // Already closed ?
3051 if (!socket || !socket->isOpen()) {
3052 QMetaObject::invokeMethod(q, "_q_slotDoFinished", Qt::QueuedConnection);
3053 } else {
3054 // Close now.
3055 socket->close();
3059 void QHttpPrivate::setSock(QTcpSocket *sock)
3061 Q_Q(const QHttp);
3063 // disconnect all existing signals
3064 if (socket)
3065 socket->disconnect();
3066 if (deleteSocket)
3067 delete socket;
3069 // use the new QTcpSocket socket, or create one if socket is 0.
3070 deleteSocket = (sock == 0);
3071 socket = sock;
3072 if (!socket) {
3073 #ifndef QT_NO_OPENSSL
3074 if (QSslSocket::supportsSsl())
3075 socket = new QSslSocket();
3076 else
3077 #endif
3078 socket = new QTcpSocket();
3081 // connect all signals
3082 QObject::connect(socket, SIGNAL(connected()), q, SLOT(_q_slotConnected()));
3083 QObject::connect(socket, SIGNAL(disconnected()), q, SLOT(_q_slotClosed()));
3084 QObject::connect(socket, SIGNAL(readyRead()), q, SLOT(_q_slotReadyRead()));
3085 QObject::connect(socket, SIGNAL(error(QAbstractSocket::SocketError)), q, SLOT(_q_slotError(QAbstractSocket::SocketError)));
3086 QObject::connect(socket, SIGNAL(bytesWritten(qint64)),
3087 q, SLOT(_q_slotBytesWritten(qint64)));
3088 #ifndef QT_NO_NETWORKPROXY
3089 QObject::connect(socket, SIGNAL(proxyAuthenticationRequired(const QNetworkProxy &, QAuthenticator *)),
3090 q, SIGNAL(proxyAuthenticationRequired(const QNetworkProxy &, QAuthenticator *)));
3091 #endif
3093 #ifndef QT_NO_OPENSSL
3094 if (qobject_cast<QSslSocket *>(socket)) {
3095 QObject::connect(socket, SIGNAL(sslErrors(const QList<QSslError> &)),
3096 q, SIGNAL(sslErrors(const QList<QSslError> &)));
3098 #endif
3102 Tells the QSslSocket used for the Http connection to ignore the errors
3103 reported in the sslErrors() signal.
3105 Note that this function must be called from within a slot connected to the
3106 sslErrors() signal to have any effect.
3108 \sa QSslSocket QSslSocket::sslErrors()
3110 #ifndef QT_NO_OPENSSL
3111 void QHttp::ignoreSslErrors()
3113 Q_D(QHttp);
3114 QSslSocket *sslSocket = qobject_cast<QSslSocket *>(d->socket);
3115 if (sslSocket)
3116 sslSocket->ignoreSslErrors();
3118 #endif
3120 QT_END_NAMESPACE
3122 #include "moc_qhttp.cpp"
3124 #endif