1 /****************************************************************************
3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: Qt Software Information (qt-info@nokia.com)
6 ** This file is part of the QtNetwork module of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL$
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
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.
40 ****************************************************************************/
44 #include <qplatformdefs.h>
48 # include "private/qobject_p.h"
49 # include "qtcpsocket.h"
50 # include "qsslsocket.h"
51 # include "qtextstream.h"
55 # include "qstringlist.h"
57 # include "private/qringbuffer_p.h"
58 # include "qcoreevent.h"
60 # include "qnetworkproxy.h"
61 # include "qauthenticator.h"
62 # include "qauthenticator_p.h"
71 class QHttpNormalRequest
;
75 QHttpRequest() : finished(false)
76 { id
= idCounter
.fetchAndAddRelaxed(1); }
77 virtual ~QHttpRequest()
80 virtual void start(QHttp
*) = 0;
81 virtual bool hasRequestHeader();
82 virtual QHttpRequestHeader
requestHeader();
84 virtual QIODevice
*sourceDevice() = 0;
85 virtual QIODevice
*destinationDevice() = 0;
91 static QBasicAtomicInt idCounter
;
94 class QHttpPrivate
: public QObjectPrivate
97 Q_DECLARE_PUBLIC(QHttp
)
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();
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
);
136 void setSock(QTcpSocket
*sock
);
139 int reconnectAttempts
;
141 QList
<QHttpRequest
*> pending
;
149 QHttp::ConnectionMode mode
;
153 QIODevice
*postDevice
;
159 QHttpRequestHeader header
;
163 QHttpResponseHeader response
;
167 #ifndef QT_NO_NETWORKPROXY
169 QAuthenticator proxyAuthenticator
;
171 QAuthenticator authenticator
;
173 bool hasFinishedWithError
;
175 QTimer post100ContinueTimer
;
178 QBasicAtomicInt
QHttpRequest::idCounter
= Q_BASIC_ATOMIC_INITIALIZER(1);
180 bool QHttpRequest::hasRequestHeader()
185 QHttpRequestHeader
QHttpRequest::requestHeader()
187 return QHttpRequestHeader();
190 /****************************************************
194 ****************************************************/
196 class QHttpNormalRequest
: public QHttpRequest
199 QHttpNormalRequest(const QHttpRequestHeader
&h
, QIODevice
*d
, QIODevice
*t
) :
206 QHttpNormalRequest(const QHttpRequestHeader
&h
, QByteArray
*d
, QIODevice
*t
) :
213 ~QHttpNormalRequest()
220 bool hasRequestHeader();
221 QHttpRequestHeader
requestHeader();
222 inline void setRequestHeader(const QHttpRequestHeader
&h
) { header
= h
; }
224 QIODevice
*sourceDevice();
225 QIODevice
*destinationDevice();
228 QHttpRequestHeader header
;
239 void QHttpNormalRequest::start(QHttp
*http
)
241 if (!http
->d_func()->socket
)
242 http
->d_func()->setSock(0);
243 http
->d_func()->header
= header
;
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;
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());
259 http
->d_func()->postDevice
= 0;
263 if (to
&& (to
->isOpen() || to
->open(QIODevice::WriteOnly
)))
264 http
->d_func()->toDevice
= to
;
266 http
->d_func()->toDevice
= 0;
268 http
->d_func()->reconnectAttempts
= 2;
269 http
->d_func()->_q_slotSendRequest();
272 bool QHttpNormalRequest::hasRequestHeader()
277 QHttpRequestHeader
QHttpNormalRequest::requestHeader()
282 QIODevice
*QHttpNormalRequest::sourceDevice()
289 QIODevice
*QHttpNormalRequest::destinationDevice()
294 /****************************************************
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
302 ****************************************************/
304 class QHttpPGHRequest
: public QHttpNormalRequest
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
)
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
));
326 header
.setValue(QLatin1String("Host"), http
->d_func()->hostName
);
327 QHttpNormalRequest::start(http
);
330 /****************************************************
332 * QHttpSetHostRequest
334 ****************************************************/
336 class QHttpSetHostRequest
: public QHttpRequest
339 QHttpSetHostRequest(const QString
&h
, quint16 p
, QHttp::ConnectionMode m
)
340 : hostName(h
), port(p
), mode(m
)
345 QIODevice
*sourceDevice()
347 QIODevice
*destinationDevice()
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
;
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
);
371 http
->d_func()->finishedWithSuccess();
374 /****************************************************
376 * QHttpSetUserRequest
378 ****************************************************/
380 class QHttpSetUserRequest
: public QHttpRequest
383 QHttpSetUserRequest(const QString
&userName
, const QString
&password
) :
384 user(userName
), pass(password
)
389 QIODevice
*sourceDevice()
391 QIODevice
*destinationDevice()
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
417 inline QHttpSetProxyRequest(const QNetworkProxy
&proxy
)
422 inline void start(QHttp
*http
)
424 http
->d_func()->proxy
= proxy
;
425 QString user
= proxy
.user();
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()
436 inline QIODevice
*destinationDevice()
442 #endif // QT_NO_NETWORKPROXY
444 /****************************************************
446 * QHttpSetSocketRequest
448 ****************************************************/
450 class QHttpSetSocketRequest
: public QHttpRequest
453 QHttpSetSocketRequest(QTcpSocket
*s
) : socket(s
)
458 QIODevice
*sourceDevice()
460 QIODevice
*destinationDevice()
467 void QHttpSetSocketRequest::start(QHttp
*http
)
469 http
->d_func()->setSock(socket
);
470 http
->d_func()->finishedWithSuccess();
473 /****************************************************
477 ****************************************************/
479 class QHttpCloseRequest
: public QHttpRequest
486 QIODevice
*sourceDevice()
488 QIODevice
*destinationDevice()
492 void QHttpCloseRequest::start(QHttp
*http
)
494 http
->d_func()->closeConn();
497 class QHttpHeaderPrivate
499 Q_DECLARE_PUBLIC(QHttpHeader
)
501 inline virtual ~QHttpHeaderPrivate() {}
503 QList
<QPair
<QString
, QString
> > values
;
508 /****************************************************
512 ****************************************************/
516 \brief The QHttpHeader class contains header information for HTTP.
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
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
)
572 Constructs a copy of \a header.
574 QHttpHeader::QHttpHeader(const QHttpHeader
&header
)
575 : d_ptr(new QHttpHeaderPrivate
)
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
)
602 QHttpHeader::QHttpHeader(QHttpHeaderPrivate
&dd
, const QString
&str
)
614 QHttpHeader::QHttpHeader(QHttpHeaderPrivate
&dd
, const QHttpHeader
&header
)
619 d
->valid
= header
.d_func()->valid
;
620 d
->values
= header
.d_func()->values
;
625 QHttpHeader::~QHttpHeader()
631 Assigns \a h and returns a reference to this http header.
633 QHttpHeader
&QHttpHeader::operator=(const QHttpHeader
&h
)
636 d
->values
= h
.d_func()->values
;
637 d
->valid
= h
.d_func()->valid
;
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
);
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.
661 bool QHttpHeader::parse(const QString
&str
)
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"));
669 lst
= str
.trimmed().split(QLatin1String("\n"));
670 lst
.removeAll(QString()); // No empties
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();
692 for (; it
!= lines
.end(); ++it
) {
693 if (!parseLine(*it
, number
++)) {
703 void QHttpHeader::setValid(bool 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
)
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
);
747 Returns a list of the keys in the HTTP header.
751 QStringList
QHttpHeader::keys() const
753 Q_D(const QHttpHeader
);
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
)) {
762 seenKeys
.insert(lowercaseKey
);
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
)
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
796 \sa value() hasKey() removeValue()
798 void QHttpHeader::setValue(const QString
&key
, const QString
&value
)
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
;
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
)
824 Adds a new entry with the \a key and \a value.
826 void QHttpHeader::addValue(const QString
&key
, const QString
&value
)
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
);
842 Removes the entry with the key \a key from the HTTP header.
844 \sa value() setValue()
846 void QHttpHeader::removeValue(const QString
&key
)
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
) {
861 Removes all the entries with the key \a key from the HTTP header.
863 void QHttpHeader::removeAllValues(const QString
&key
)
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
);
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.
885 bool QHttpHeader::parseLine(const QString
&line
, int)
887 int i
= line
.indexOf(QLatin1Char(':'));
891 addValue(line
.left(i
).trimmed(), line
.mid(i
+ 1).trimmed());
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,
903 QString
QHttpHeader::toString() const
905 Q_D(const QHttpHeader
);
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");
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
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
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"));
974 int pos
= type
.indexOf(QLatin1Char(';'));
978 return type
.left(pos
).trimmed();
982 Sets the value of the special HTTP header field \c content-type to
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
)
1002 /****************************************************
1004 * QHttpResponseHeader
1006 ****************************************************/
1009 \class QHttpResponseHeader
1010 \brief The QHttpResponseHeader class contains response header information for HTTP.
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
)
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
;
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,
1072 QHttpResponseHeader::QHttpResponseHeader(const QString
&str
)
1073 : QHttpHeader(*new QHttpResponseHeaderPrivate
)
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
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
);
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
);
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
);
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
);
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
);
1157 bool QHttpResponseHeader::parseLine(const QString
&line
, int number
)
1159 Q_D(QHttpResponseHeader
);
1161 return QHttpHeader::parseLine(line
, number
);
1163 QString l
= line
.simplified();
1164 if (l
.length() < 10)
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);
1174 d
->reasonPhr
= l
.mid(pos
+ 1);
1175 d
->statCode
= l
.mid(9, pos
- 9).toInt();
1177 d
->statCode
= l
.mid(9).toInt();
1178 d
->reasonPhr
.clear();
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
)
1206 /****************************************************
1208 * QHttpRequestHeader
1210 ****************************************************/
1213 \class QHttpRequestHeader
1214 \brief The QHttpRequestHeader class contains request header information for HTTP.
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
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
)
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
1257 QHttpRequestHeader::QHttpRequestHeader(const QString
&method
, const QString
&path
, int majorVer
, int minorVer
)
1258 : QHttpHeader(*new QHttpRequestHeaderPrivate
)
1260 Q_D(QHttpRequestHeader
);
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
;
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
)
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
1313 \sa method() path() majorVersion() minorVersion()
1315 void QHttpRequestHeader::setRequest(const QString
&method
, const QString
&path
, int majorVer
, int minorVer
)
1317 Q_D(QHttpRequestHeader
);
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
);
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
);
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
);
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
);
1371 bool QHttpRequestHeader::parseLine(const QString
&line
, int number
)
1373 Q_D(QHttpRequestHeader
);
1375 return QHttpHeader::parseLine(line
, number
);
1377 QStringList lst
= line
.simplified().split(QLatin1String(" "));
1378 if (lst
.count() > 0) {
1380 if (lst
.count() > 1) {
1382 if (lst
.count() > 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';
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 /****************************************************
1413 ****************************************************/
1418 \brief The QHttp class provides an implementation of the HTTP protocol.
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
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
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
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
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
)
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.
1536 QHttp::QHttp(const QString
&hostName
, quint16 port
, QObject
*parent
)
1537 : QObject(*new QHttpPrivate
, parent
)
1542 d
->hostName
= hostName
;
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.
1558 QHttp::QHttp(const QString
&hostName
, ConnectionMode mode
, quint16 port
, QObject
*parent
)
1559 : QObject(*new QHttpPrivate
, parent
)
1564 d
->hostName
= hostName
;
1566 port
= (mode
== ConnectionModeHttp
) ? 80 : 443;
1571 void QHttpPrivate::init()
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
1590 \enum QHttp::ConnectionMode
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.
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
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
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
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
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)
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
1779 \fn void QHttp::authenticationRequired(const QString &hostname, quint16 port, QAuthenticator *authenticator)
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
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)
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
1818 \sa clearPendingRequests()
1823 if (d
->pending
.isEmpty())
1826 d
->finishedWithError(tr("Request aborted"), Aborted
);
1827 clearPendingRequests();
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
1842 #if defined(QHTTP_DEBUG)
1843 qDebug("QHttp::bytesAvailable(): %d bytes", (int)d
->rba
.size());
1845 return qint64(d
->rba
.size());
1848 /*! \fn qint64 QHttp::readBlock(char *data, quint64 maxlen)
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
)
1862 if (data
== 0 && maxlen
!= 0) {
1863 qWarning("QHttp::read: Null pointer error");
1866 if (maxlen
>= d
->rba
.size())
1867 maxlen
= d
->rba
.size();
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
);
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();
1893 tmp
.resize(int(avail
));
1894 qint64 got
= read(tmp
.data(), int(avail
));
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
1908 if (d
->pending
.isEmpty())
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.
1921 QHttpRequestHeader
QHttp::currentRequest() const
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
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
1958 if (d
->pending
.isEmpty())
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
1976 if (d
->pending
.isEmpty())
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
1988 \sa clearPendingRequests() currentId() currentRequest()
1990 bool QHttp::hasPendingRequests() const
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()
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
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
2024 \sa get() post() head() request() requestStarted() requestFinished() done()
2026 int QHttp::setHost(const QString
&hostName
, quint16 port
)
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
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");
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
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
)
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
2102 int QHttp::setUser(const QString
&userName
, const QString
&password
)
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.
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
)
2133 QNetworkProxy
proxy(QNetworkProxy::HttpProxy
, host
, port
, username
, password
);
2134 return d
->addRequest(new QHttpSetProxyRequest(proxy
));
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
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
2151 int QHttp::setProxy(const QNetworkProxy
&proxy
)
2154 return d
->addRequest(new QHttpSetProxyRequest(proxy
));
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
2187 \sa setHost(), post(), head(), request(), requestStarted(),
2188 requestFinished(), done()
2190 int QHttp::get(const QString
&path
, QIODevice
*to
)
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
2226 \sa setHost() get() head() request() requestStarted() requestFinished() done()
2228 int QHttp::post(const QString
&path
, QIODevice
*data
, QIODevice
*to
)
2231 QHttpRequestHeader
header(QLatin1String("POST"), path
);
2232 header
.setValue(QLatin1String("Connection"), QLatin1String("Keep-Alive"));
2233 return d
->addRequest(new QHttpPGHRequest(header
, data
, to
));
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
)
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
2265 \sa setHost() get() post() request() requestStarted() requestFinished() done()
2267 int QHttp::head(const QString
&path
)
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
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
2300 \sa setHost() get() post() head() requestStarted() requestFinished() done()
2302 int QHttp::request(const QHttpRequestHeader
&header
, QIODevice
*data
, QIODevice
*to
)
2305 return d
->addRequest(new QHttpNormalRequest(header
, data
, to
));
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
)
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
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
2338 If you want to close the connection immediately, you have to use
2341 \sa stateChanged() abort() requestStarted() requestFinished() done()
2346 return d
->addRequest(new QHttpCloseRequest());
2352 Behaves the same as close().
2354 int QHttp::closeConnection()
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
);
2371 return addRequest(static_cast<QHttpRequest
*>(req
));
2374 int QHttpPrivate::addRequest(QHttpRequest
*req
)
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
);
2386 void QHttpPrivate::_q_startNextRequest()
2389 if (pending
.isEmpty())
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
);
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
);
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()))
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
);
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;
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
) {
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
);
2474 // Username support. Insert the user and password into the query
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
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
))
2490 socket
->blockSignals(true);
2492 socket
->blockSignals(false);
2494 setState(QHttp::Connecting
);
2495 #ifndef QT_NO_OPENSSL
2496 if (sslSocket
&& mode
== QHttp::ConnectionModeHttps
) {
2497 sslSocket
->connectToHostEncrypted(hostName
, port
);
2501 socket
->connectToHost(connectionHost
, connectionPort
);
2509 void QHttpPrivate::finishedWithSuccess()
2512 if (pending
.isEmpty())
2514 QHttpRequest
*r
= pending
.first();
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.
2529 pending
.removeFirst();
2532 if (pending
.isEmpty()) {
2533 emit q
->done(false);
2535 _q_startNextRequest();
2539 void QHttpPrivate::finishedWithError(const QString
&detail
, int errorCode
)
2542 if (pending
.isEmpty())
2544 QHttpRequest
*r
= pending
.first();
2545 hasFinishedWithError
= true;
2547 error
= QHttp::Error(errorCode
);
2548 errorString
= detail
;
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()
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
);
2577 if (state
!= QHttp::Closing
)
2578 setState(QHttp::Closing
);
2579 QMetaObject::invokeMethod(q
, "_q_slotDoFinished", Qt::QueuedConnection
);
2582 void QHttpPrivate::_q_continuePost()
2585 pendingPost
= false;
2586 setState(QHttp::Sending
);
2587 _q_slotBytesWritten(0);
2591 void QHttpPrivate::_q_slotConnected()
2593 if (state
!= QHttp::Sending
) {
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());
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.
2612 post100ContinueTimer
.start(2000);
2615 bytesTotal
+= buffer
.size();
2616 socket
->write(buffer
, buffer
.size());
2620 void QHttpPrivate::_q_slotError(QAbstractSocket::SocketError err
)
2625 if (state
== QHttp::Connecting
|| state
== QHttp::Reading
|| state
== QHttp::Sending
) {
2627 case QTcpSocket::ConnectionRefusedError
:
2628 finishedWithError(QLatin1String(QT_TRANSLATE_NOOP("QHttp", "Connection refused (or timed out)")), QHttp::ConnectionRefused
);
2630 case QTcpSocket::HostNotFoundError
:
2631 finishedWithError(QString::fromLatin1(QT_TRANSLATE_NOOP("QHttp", "Host %1 not found"))
2632 .arg(socket
->peerName()), QHttp::HostNotFound
);
2634 case QTcpSocket::RemoteHostClosedError
:
2635 if (state
== QHttp::Sending
&& reconnectAttempts
--) {
2636 setState(QHttp::Closing
);
2637 setState(QHttp::Unconnected
);
2638 socket
->blockSignals(true);
2640 socket
->blockSignals(false);
2641 QMetaObject::invokeMethod(q
, "_q_slotSendRequest", Qt::QueuedConnection
);
2645 #ifndef QT_NO_NETWORKPROXY
2646 case QTcpSocket::ProxyAuthenticationRequiredError
:
2647 finishedWithError(socket
->errorString(), QHttp::ProxyAuthenticationRequiredError
);
2651 finishedWithError(QLatin1String(QT_TRANSLATE_NOOP("QHttp", "HTTP request failed")), QHttp::UnknownError
);
2659 void QHttpPrivate::_q_slotBytesWritten(qint64 written
)
2662 bytesDone
+= written
;
2663 emit q
->dataSendProgress(bytesDone
, bytesTotal
);
2671 if (socket
->bytesToWrite() == 0) {
2672 int max
= qMin
<qint64
>(4096, postDevice
->size() - postDevice
->pos());
2676 int n
= postDevice
->read(arr
.data(), max
);
2678 qWarning("Could not read enough bytes from the device");
2682 if (postDevice
->atEnd()) {
2686 socket
->write(arr
, n
);
2690 void QHttpPrivate::_q_slotReadyRead()
2693 QHttp::State oldState
= state
;
2694 if (state
!= QHttp::Reading
) {
2695 setState(QHttp::Reading
);
2697 headerStr
= QLatin1String("");
2703 while (readHeader
) {
2706 while (!end
&& socket
->canReadLine()) {
2707 tmp
= QString::fromAscii(socket
->readLine());
2708 if (tmp
== QLatin1String("\r\n") || tmp
== QLatin1String("\n") || tmp
.isEmpty())
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());
2723 if (!response
.isValid()) {
2724 finishedWithError(QLatin1String(QT_TRANSLATE_NOOP("QHttp", "Invalid HTTP response header")),
2725 QHttp::InvalidResponseHeader
);
2730 int statusCode
= response
.statusCode();
2731 if (statusCode
== 401 || statusCode
== 407) { // (Proxy) Authentication required
2732 QAuthenticator
*auth
=
2733 #ifndef QT_NO_NETWORKPROXY
2735 ? &proxyAuthenticator
:
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
);
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
);
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
);
2766 finishedWithError(QLatin1String(QT_TRANSLATE_NOOP("QHttp", "Authentication required")),
2767 QHttp::AuthenticationRequiredError
);
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"));
2776 setState(QHttp::Closing
);
2777 socket
->blockSignals(true);
2779 socket
->blockSignals(false);
2782 _q_slotSendRequest();
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
);
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
2802 if (response
.statusCode() != 100) {
2803 post100ContinueTimer
.stop();
2804 pendingPost
= false;
2806 if (response
.hasKey(QLatin1String("transfer-encoding")) &&
2807 response
.value(QLatin1String("transfer-encoding")).toLower().contains(QLatin1String("chunked")))
2811 emit q
->responseHeaderReceived(response
);
2812 if (state
== QHttp::Unconnected
|| state
== QHttp::Closing
)
2815 // Restore the state, the next incoming data will be treated as if
2816 // we never say the 100 response.
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:
2830 // 205 Reset Content
2831 everythingRead
= true;
2833 qint64 n
= socket
->bytesAvailable();
2834 QByteArray
*arr
= 0;
2835 if (chunkedSize
!= -1) {
2836 // transfer-encoding is chunked
2839 if (chunkedSize
== 0) {
2840 if (!socket
->canReadLine())
2842 QString sizeString
= QString::fromAscii(socket
->readLine());
2843 int tPos
= sizeString
.indexOf(QLatin1Char(';'));
2845 sizeString
.truncate(tPos
);
2847 chunkedSize
= sizeString
.toInt(&ok
, 16);
2849 finishedWithError(QLatin1String(QT_TRANSLATE_NOOP("QHttp", "Invalid HTTP chunked body")),
2850 QHttp::WrongContentLength
);
2855 if (chunkedSize
== 0) // last-chunk
2860 while (chunkedSize
== -2 && socket
->canReadLine()) {
2861 QString read
= QString::fromAscii(socket
->readLine());
2862 if (read
== QLatin1String("\r\n") || read
== QLatin1String("\n"))
2865 if (chunkedSize
== -1) {
2866 everythingRead
= true;
2870 // make sure that you can read the terminating CRLF,
2871 // otherwise wait until next time...
2872 n
= socket
->bytesAvailable();
2875 if (n
== chunkedSize
|| n
== chunkedSize
+1) {
2876 n
= chunkedSize
- 1;
2882 qint64 toRead
= chunkedSize
< 0 ? n
: qMin(n
, chunkedSize
);
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
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
);
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
2911 n
= qMin(qint64(response
.contentLength() - bytesDone
), n
);
2913 arr
= new QByteArray
;
2915 qint64 read
= socket
->read(arr
->data(), n
);
2918 if (bytesDone
+ q
->bytesAvailable() + n
== response
.contentLength())
2919 everythingRead
= true;
2921 // workaround for VC++ bug
2922 QByteArray temp
= socket
->readAll();
2923 arr
= new QByteArray(temp
);
2926 if (arr
&& !repost
) {
2929 qint64 bytesWritten
;
2930 bytesWritten
= toDevice
->write(*arr
, n
);
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
);
2937 bytesDone
+= bytesWritten
;
2938 #if defined(QHTTP_DEBUG)
2939 qDebug("QHttp::_q_slotReadyRead(): read %lld bytes (%lld bytes done)", n
, bytesDone
);
2942 if (response
.hasContentLength())
2943 emit q
->dataReadProgress(bytesDone
, response
.contentLength());
2945 emit q
->dataReadProgress(bytesDone
, 0);
2947 char *ptr
= rba
.reserve(arr
->size());
2948 memcpy(ptr
, arr
->data(), arr
->size());
2951 #if defined(QHTTP_DEBUG)
2952 qDebug("QHttp::_q_slotReadyRead(): read %lld bytes (%lld bytes done)", n
, bytesDone
+ q
->bytesAvailable());
2954 if (response
.hasContentLength())
2955 emit q
->dataReadProgress(bytesDone
+ q
->bytesAvailable(), response
.contentLength());
2957 emit q
->dataReadProgress(bytesDone
+ q
->bytesAvailable(), 0);
2958 emit q
->readyRead(response
);
2965 if (everythingRead
) {
2967 _q_slotSendRequest();
2970 // Handle "Connection: close"
2971 if (response
.value(QLatin1String("connection")).toLower() == QLatin1String("close")) {
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
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
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
3027 return d
->errorString
;
3030 void QHttpPrivate::setState(int s
)
3033 #if defined(QHTTP_DEBUG)
3034 qDebug("QHttp state changed %d -> %d", state
, s
);
3036 state
= QHttp::State(s
);
3037 emit q
->stateChanged(s
);
3040 void QHttpPrivate::closeConn()
3043 // If no connection is open -> ignore
3044 if (state
== QHttp::Closing
|| state
== QHttp::Unconnected
)
3048 setState(QHttp::Closing
);
3051 if (!socket
|| !socket
->isOpen()) {
3052 QMetaObject::invokeMethod(q
, "_q_slotDoFinished", Qt::QueuedConnection
);
3059 void QHttpPrivate::setSock(QTcpSocket
*sock
)
3063 // disconnect all existing signals
3065 socket
->disconnect();
3069 // use the new QTcpSocket socket, or create one if socket is 0.
3070 deleteSocket
= (sock
== 0);
3073 #ifndef QT_NO_OPENSSL
3074 if (QSslSocket::supportsSsl())
3075 socket
= new QSslSocket();
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
*)));
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
> &)));
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()
3114 QSslSocket
*sslSocket
= qobject_cast
<QSslSocket
*>(d
->socket
);
3116 sslSocket
->ignoreSslErrors();
3122 #include "moc_qhttp.cpp"