1/****************************************************************************
2**
3** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
4** Contact: http://www.qt-project.org/legal
5**
6** This file is part of the QtNetwork module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and Digia. For licensing terms and
14** conditions see http://qt.digia.com/licensing. For further information
15** use the contact form at http://qt.digia.com/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 2.1 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 2.1 requirements
23** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24**
25** In addition, as a special exception, Digia gives you certain additional
26** rights. These rights are described in the Digia Qt LGPL Exception
27** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28**
29** GNU General Public License Usage
30** Alternatively, this file may be used under the terms of the GNU
31** General Public License version 3.0 as published by the Free Software
32** Foundation and appearing in the file LICENSE.GPL included in the
33** packaging of this file. Please review the following information to
34** ensure the GNU General Public License version 3.0 requirements will be
35** met: http://www.gnu.org/copyleft/gpl.html.
36**
37**
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42//#define QHTTP_DEBUG
43
44#include <qplatformdefs.h>
45#include "qhttp.h"
46
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
66
67#ifndef QT_NO_HTTP
68
69QT_BEGIN_NAMESPACE
70
71class QHttpNormalRequest;
72class QHttpRequest
73{
74public:
75 QHttpRequest() : finished(false)
76 { id = idCounter.fetchAndAddRelaxed(1); }
77 virtual ~QHttpRequest()
78 { }
79
80 virtual void start(QHttp *) = 0;
81 virtual bool hasRequestHeader();
82 virtual QHttpRequestHeader requestHeader();
83
84 virtual QIODevice *sourceDevice() = 0;
85 virtual QIODevice *destinationDevice() = 0;
86
87 int id;
88 bool finished;
89
90private:
91 static QBasicAtomicInt idCounter;
92};
93
94class QHttpPrivate : public QObjectPrivate
95{
96public:
97 Q_DECLARE_PUBLIC(QHttp)
98
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)
105 {
106 }
107
108 inline ~QHttpPrivate()
109 {
110 while (!pending.isEmpty())
111 delete pending.takeFirst();
112
113 if (deleteSocket)
114 delete socket;
115 }
116
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#ifndef QT_NO_OPENSSL
125 void _q_slotEncryptedBytesWritten(qint64 numBytes);
126#endif
127 void _q_slotDoFinished();
128 void _q_slotSendRequest();
129 void _q_continuePost();
130
131 int addRequest(QHttpNormalRequest *);
132 int addRequest(QHttpRequest *);
133 void finishedWithSuccess();
134 void finishedWithError(const QString &detail, int errorCode);
135
136 void init();
137 void setState(int);
138 void closeConn();
139 void setSock(QTcpSocket *sock);
140
141 void postMoreData();
142
143 QTcpSocket *socket;
144 int reconnectAttempts;
145 bool deleteSocket;
146 QList<QHttpRequest *> pending;
147
148 QHttp::State state;
149 QHttp::Error error;
150 QString errorString;
151
152 QString hostName;
153 quint16 port;
154 QHttp::ConnectionMode mode;
155
156 QByteArray buffer;
157 QIODevice *toDevice;
158 QIODevice *postDevice;
159
160 qint64 bytesDone;
161 qint64 bytesTotal;
162 qint64 chunkedSize;
163
164 QHttpRequestHeader header;
165
166 bool readHeader;
167 QString headerStr;
168 QHttpResponseHeader response;
169
170 QRingBuffer rba;
171
172#ifndef QT_NO_NETWORKPROXY
173 QNetworkProxy proxy;
174 QAuthenticator proxyAuthenticator;
175#endif
176 QAuthenticator authenticator;
177 bool repost;
178 bool hasFinishedWithError;
179 bool pendingPost;
180 QTimer post100ContinueTimer;
181};
182
183QBasicAtomicInt QHttpRequest::idCounter = Q_BASIC_ATOMIC_INITIALIZER(1);
184
185bool QHttpRequest::hasRequestHeader()
186{
187 return false;
188}
189
190QHttpRequestHeader QHttpRequest::requestHeader()
191{
192 return QHttpRequestHeader();
193}
194
195/****************************************************
196 *
197 * QHttpNormalRequest
198 *
199 ****************************************************/
200
201class QHttpNormalRequest : public QHttpRequest
202{
203public:
204 QHttpNormalRequest(const QHttpRequestHeader &h, QIODevice *d, QIODevice *t) :
205 header(h), to(t)
206 {
207 is_ba = false;
208 data.dev = d;
209 }
210
211 QHttpNormalRequest(const QHttpRequestHeader &h, QByteArray *d, QIODevice *t) :
212 header(h), to(t)
213 {
214 is_ba = true;
215 data.ba = d;
216 }
217
218 ~QHttpNormalRequest()
219 {
220 if (is_ba)
221 delete data.ba;
222 }
223
224 void start(QHttp *);
225 bool hasRequestHeader();
226 QHttpRequestHeader requestHeader();
227 inline void setRequestHeader(const QHttpRequestHeader &h) { header = h; }
228
229 QIODevice *sourceDevice();
230 QIODevice *destinationDevice();
231
232protected:
233 QHttpRequestHeader header;
234
235private:
236 union {
237 QByteArray *ba;
238 QIODevice *dev;
239 } data;
240 bool is_ba;
241 QIODevice *to;
242};
243
244void QHttpNormalRequest::start(QHttp *http)
245{
246 if (!http->d_func()->socket)
247 http->d_func()->setSock(0);
248 http->d_func()->header = header;
249
250 if (is_ba) {
251 http->d_func()->buffer = *data.ba;
252 if (http->d_func()->buffer.size() >= 0)
253 http->d_func()->header.setContentLength(http->d_func()->buffer.size());
254
255 http->d_func()->postDevice = 0;
256 } else {
257 http->d_func()->buffer = QByteArray();
258
259 if (data.dev && (data.dev->isOpen() || data.dev->open(QIODevice::ReadOnly))) {
260 http->d_func()->postDevice = data.dev;
261 if (http->d_func()->postDevice->size() >= 0)
262 http->d_func()->header.setContentLength(http->d_func()->postDevice->size());
263 } else {
264 http->d_func()->postDevice = 0;
265 }
266 }
267
268 if (to && (to->isOpen() || to->open(QIODevice::WriteOnly)))
269 http->d_func()->toDevice = to;
270 else
271 http->d_func()->toDevice = 0;
272
273 http->d_func()->reconnectAttempts = 2;
274 http->d_func()->_q_slotSendRequest();
275}
276
277bool QHttpNormalRequest::hasRequestHeader()
278{
279 return true;
280}
281
282QHttpRequestHeader QHttpNormalRequest::requestHeader()
283{
284 return header;
285}
286
287QIODevice *QHttpNormalRequest::sourceDevice()
288{
289 if (is_ba)
290 return 0;
291 return data.dev;
292}
293
294QIODevice *QHttpNormalRequest::destinationDevice()
295{
296 return to;
297}
298
299/****************************************************
300 *
301 * QHttpPGHRequest
302 * (like a QHttpNormalRequest, but for the convenience
303 * functions put(), get() and head() -- i.e. set the
304 * host header field correctly before sending the
305 * request)
306 *
307 ****************************************************/
308
309class QHttpPGHRequest : public QHttpNormalRequest
310{
311public:
312 QHttpPGHRequest(const QHttpRequestHeader &h, QIODevice *d, QIODevice *t) :
313 QHttpNormalRequest(h, d, t)
314 { }
315
316 QHttpPGHRequest(const QHttpRequestHeader &h, QByteArray *d, QIODevice *t) :
317 QHttpNormalRequest(h, d, t)
318 { }
319
320 ~QHttpPGHRequest()
321 { }
322
323 void start(QHttp *);
324};
325
326void QHttpPGHRequest::start(QHttp *http)
327{
328 if (http->d_func()->port && http->d_func()->port != 80)
329 header.setValue(QLatin1String("Host"), http->d_func()->hostName + QLatin1Char(':') + QString::number(http->d_func()->port));
330 else
331 header.setValue(QLatin1String("Host"), http->d_func()->hostName);
332 QHttpNormalRequest::start(http);
333}
334
335/****************************************************
336 *
337 * QHttpSetHostRequest
338 *
339 ****************************************************/
340
341class QHttpSetHostRequest : public QHttpRequest
342{
343public:
344 QHttpSetHostRequest(const QString &h, quint16 p, QHttp::ConnectionMode m)
345 : hostName(h), port(p), mode(m)
346 { }
347
348 void start(QHttp *);
349
350 QIODevice *sourceDevice()
351 { return 0; }
352 QIODevice *destinationDevice()
353 { return 0; }
354
355private:
356 QString hostName;
357 quint16 port;
358 QHttp::ConnectionMode mode;
359};
360
361void QHttpSetHostRequest::start(QHttp *http)
362{
363 http->d_func()->hostName = hostName;
364 http->d_func()->port = port;
365 http->d_func()->mode = mode;
366
367#ifdef QT_NO_OPENSSL
368 if (mode == QHttp::ConnectionModeHttps) {
369 // SSL requested but no SSL support compiled in
370 http->d_func()->finishedWithError(QLatin1String(QT_TRANSLATE_NOOP("QHttp", "HTTPS connection requested but SSL support not compiled in")),
371 QHttp::UnknownError);
372 return;
373 }
374#endif
375
376 http->d_func()->finishedWithSuccess();
377}
378
379/****************************************************
380 *
381 * QHttpSetUserRequest
382 *
383 ****************************************************/
384
385class QHttpSetUserRequest : public QHttpRequest
386{
387public:
388 QHttpSetUserRequest(const QString &userName, const QString &password) :
389 user(userName), pass(password)
390 { }
391
392 void start(QHttp *);
393
394 QIODevice *sourceDevice()
395 { return 0; }
396 QIODevice *destinationDevice()
397 { return 0; }
398
399private:
400 QString user;
401 QString pass;
402};
403
404void QHttpSetUserRequest::start(QHttp *http)
405{
406 http->d_func()->authenticator.setUser(user);
407 http->d_func()->authenticator.setPassword(pass);
408 http->d_func()->finishedWithSuccess();
409}
410
411#ifndef QT_NO_NETWORKPROXY
412
413/****************************************************
414 *
415 * QHttpSetProxyRequest
416 *
417 ****************************************************/
418
419class QHttpSetProxyRequest : public QHttpRequest
420{
421public:
422 inline QHttpSetProxyRequest(const QNetworkProxy &proxy)
423 {
424 this->proxy = proxy;
425 }
426
427 inline void start(QHttp *http)
428 {
429 http->d_func()->proxy = proxy;
430 QString user = proxy.user();
431 if (!user.isEmpty())
432 http->d_func()->proxyAuthenticator.setUser(user);
433 QString password = proxy.password();
434 if (!password.isEmpty())
435 http->d_func()->proxyAuthenticator.setPassword(password);
436 http->d_func()->finishedWithSuccess();
437 }
438
439 inline QIODevice *sourceDevice()
440 { return 0; }
441 inline QIODevice *destinationDevice()
442 { return 0; }
443private:
444 QNetworkProxy proxy;
445};
446
447#endif // QT_NO_NETWORKPROXY
448
449/****************************************************
450 *
451 * QHttpSetSocketRequest
452 *
453 ****************************************************/
454
455class QHttpSetSocketRequest : public QHttpRequest
456{
457public:
458 QHttpSetSocketRequest(QTcpSocket *s) : socket(s)
459 { }
460
461 void start(QHttp *);
462
463 QIODevice *sourceDevice()
464 { return 0; }
465 QIODevice *destinationDevice()
466 { return 0; }
467
468private:
469 QTcpSocket *socket;
470};
471
472void QHttpSetSocketRequest::start(QHttp *http)
473{
474 http->d_func()->setSock(socket);
475 http->d_func()->finishedWithSuccess();
476}
477
478/****************************************************
479 *
480 * QHttpCloseRequest
481 *
482 ****************************************************/
483
484class QHttpCloseRequest : public QHttpRequest
485{
486public:
487 QHttpCloseRequest()
488 { }
489 void start(QHttp *);
490
491 QIODevice *sourceDevice()
492 { return 0; }
493 QIODevice *destinationDevice()
494 { return 0; }
495};
496
497void QHttpCloseRequest::start(QHttp *http)
498{
499 http->d_func()->closeConn();
500}
501
502class QHttpHeaderPrivate
503{
504 Q_DECLARE_PUBLIC(QHttpHeader)
505public:
506 inline virtual ~QHttpHeaderPrivate() {}
507
508 QList<QPair<QString, QString> > values;
509 bool valid;
510 QHttpHeader *q_ptr;
511};
512
513/****************************************************
514 *
515 * QHttpHeader
516 *
517 ****************************************************/
518
519/*!
520 \class QHttpHeader
521 \obsolete
522 \brief The QHttpHeader class contains header information for HTTP.
523
524 \ingroup network
525 \inmodule QtNetwork
526
527 In most cases you should use the more specialized derivatives of
528 this class, QHttpResponseHeader and QHttpRequestHeader, rather
529 than directly using QHttpHeader.
530
531 QHttpHeader provides the HTTP header fields. A HTTP header field
532 consists of a name followed by a colon, a single space, and the
533 field value. (See RFC 1945.) Field names are case-insensitive. A
534 typical header field looks like this:
535 \snippet doc/src/snippets/code/src_network_access_qhttp.cpp 0
536
537 In the API the header field name is called the "key" and the
538 content is called the "value". You can get and set a header
539 field's value by using its key with value() and setValue(), e.g.
540 \snippet doc/src/snippets/code/src_network_access_qhttp.cpp 1
541
542 Some fields are so common that getters and setters are provided
543 for them as a convenient alternative to using \l value() and
544 \l setValue(), e.g. contentLength() and contentType(),
545 setContentLength() and setContentType().
546
547 Each header key has a \e single value associated with it. If you
548 set the value for a key which already exists the previous value
549 will be discarded.
550
551 \sa QHttpRequestHeader QHttpResponseHeader
552*/
553
554/*!
555 \fn int QHttpHeader::majorVersion() const
556
557 Returns the major protocol-version of the HTTP header.
558*/
559
560/*!
561 \fn int QHttpHeader::minorVersion() const
562
563 Returns the minor protocol-version of the HTTP header.
564*/
565
566/*!
567 Constructs an empty HTTP header.
568*/
569QHttpHeader::QHttpHeader()
570 : d_ptr(new QHttpHeaderPrivate)
571{
572 Q_D(QHttpHeader);
573 d->q_ptr = this;
574 d->valid = true;
575}
576
577/*!
578 Constructs a copy of \a header.
579*/
580QHttpHeader::QHttpHeader(const QHttpHeader &header)
581 : d_ptr(new QHttpHeaderPrivate)
582{
583 Q_D(QHttpHeader);
584 d->q_ptr = this;
585 d->valid = header.d_func()->valid;
586 d->values = header.d_func()->values;
587}
588
589/*!
590 Constructs a HTTP header for \a str.
591
592 This constructor parses the string \a str for header fields and
593 adds this information. The \a str should consist of one or more
594 "\r\n" delimited lines; each of these lines should have the format
595 key, colon, space, value.
596*/
597QHttpHeader::QHttpHeader(const QString &str)
598 : d_ptr(new QHttpHeaderPrivate)
599{
600 Q_D(QHttpHeader);
601 d->q_ptr = this;
602 d->valid = true;
603 parse(str);
604}
605
606/*! \internal
607 */
608QHttpHeader::QHttpHeader(QHttpHeaderPrivate &dd, const QString &str)
609 : d_ptr(&dd)
610{
611 Q_D(QHttpHeader);
612 d->q_ptr = this;
613 d->valid = true;
614 if (!str.isEmpty())
615 parse(str);
616}
617
618/*! \internal
619 */
620QHttpHeader::QHttpHeader(QHttpHeaderPrivate &dd, const QHttpHeader &header)
621 : d_ptr(&dd)
622{
623 Q_D(QHttpHeader);
624 d->q_ptr = this;
625 d->valid = header.d_func()->valid;
626 d->values = header.d_func()->values;
627}
628/*!
629 Destructor.
630*/
631QHttpHeader::~QHttpHeader()
632{
633}
634
635/*!
636 Assigns \a h and returns a reference to this http header.
637*/
638QHttpHeader &QHttpHeader::operator=(const QHttpHeader &h)
639{
640 Q_D(QHttpHeader);
641 d->values = h.d_func()->values;
642 d->valid = h.d_func()->valid;
643 return *this;
644}
645
646/*!
647 Returns true if the HTTP header is valid; otherwise returns false.
648
649 A QHttpHeader is invalid if it was created by parsing a malformed string.
650*/
651bool QHttpHeader::isValid() const
652{
653 Q_D(const QHttpHeader);
654 return d->valid;
655}
656
657/*! \internal
658 Parses the HTTP header string \a str for header fields and adds
659 the keys/values it finds. If the string is not parsed successfully
660 the QHttpHeader becomes \link isValid() invalid\endlink.
661
662 Returns true if \a str was successfully parsed; otherwise returns false.
663
664 \sa toString()
665*/
666bool QHttpHeader::parse(const QString &str)
667{
668 Q_D(QHttpHeader);
669 QStringList lst;
670 int pos = str.indexOf(QLatin1Char('\n'));
671 if (pos > 0 && str.at(pos - 1) == QLatin1Char('\r'))
672 lst = str.trimmed().split(QLatin1String("\r\n"));
673 else
674 lst = str.trimmed().split(QLatin1String("\n"));
675 lst.removeAll(QString()); // No empties
676
677 if (lst.isEmpty())
678 return true;
679
680 QStringList lines;
681 QStringList::Iterator it = lst.begin();
682 for (; it != lst.end(); ++it) {
683 if (!(*it).isEmpty()) {
684 if ((*it)[0].isSpace()) {
685 if (!lines.isEmpty()) {
686 lines.last() += QLatin1Char(' ');
687 lines.last() += (*it).trimmed();
688 }
689 } else {
690 lines.append((*it));
691 }
692 }
693 }
694
695 int number = 0;
696 it = lines.begin();
697 for (; it != lines.end(); ++it) {
698 if (!parseLine(*it, number++)) {
699 d->valid = false;
700 return false;
701 }
702 }
703 return true;
704}
705
706/*! \internal
707*/
708void QHttpHeader::setValid(bool v)
709{
710 Q_D(QHttpHeader);
711 d->valid = v;
712}
713
714/*!
715 Returns the first value for the entry with the given \a key. If no entry
716 has this \a key, an empty string is returned.
717
718 \sa setValue() removeValue() hasKey() keys()
719*/
720QString QHttpHeader::value(const QString &key) const
721{
722 Q_D(const QHttpHeader);
723 QString lowercaseKey = key.toLower();
724 QList<QPair<QString, QString> >::ConstIterator it = d->values.constBegin();
725 while (it != d->values.constEnd()) {
726 if ((*it).first.toLower() == lowercaseKey)
727 return (*it).second;
728 ++it;
729 }
730 return QString();
731}
732
733/*!
734 Returns all the entries with the given \a key. If no entry
735 has this \a key, an empty string list is returned.
736*/
737QStringList QHttpHeader::allValues(const QString &key) const
738{
739 Q_D(const QHttpHeader);
740 QString lowercaseKey = key.toLower();
741 QStringList valueList;
742 QList<QPair<QString, QString> >::ConstIterator it = d->values.constBegin();
743 while (it != d->values.constEnd()) {
744 if ((*it).first.toLower() == lowercaseKey)
745 valueList.append((*it).second);
746 ++it;
747 }
748 return valueList;
749}
750
751/*!
752 Returns a list of the keys in the HTTP header.
753
754 \sa hasKey()
755*/
756QStringList QHttpHeader::keys() const
757{
758 Q_D(const QHttpHeader);
759 QStringList keyList;
760 QSet<QString> seenKeys;
761 QList<QPair<QString, QString> >::ConstIterator it = d->values.constBegin();
762 while (it != d->values.constEnd()) {
763 const QString &key = (*it).first;
764 QString lowercaseKey = key.toLower();
765 if (!seenKeys.contains(lowercaseKey)) {
766 keyList.append(key);
767 seenKeys.insert(lowercaseKey);
768 }
769 ++it;
770 }
771 return keyList;
772}
773
774/*!
775 Returns true if the HTTP header has an entry with the given \a
776 key; otherwise returns false.
777
778 \sa value() setValue() keys()
779*/
780bool QHttpHeader::hasKey(const QString &key) const
781{
782 Q_D(const QHttpHeader);
783 QString lowercaseKey = key.toLower();
784 QList<QPair<QString, QString> >::ConstIterator it = d->values.constBegin();
785 while (it != d->values.constEnd()) {
786 if ((*it).first.toLower() == lowercaseKey)
787 return true;
788 ++it;
789 }
790 return false;
791}
792
793/*!
794 Sets the value of the entry with the \a key to \a value.
795
796 If no entry with \a key exists, a new entry with the given \a key
797 and \a value is created. If an entry with the \a key already
798 exists, the first value is discarded and replaced with the given
799 \a value.
800
801 \sa value() hasKey() removeValue()
802*/
803void QHttpHeader::setValue(const QString &key, const QString &value)
804{
805 Q_D(QHttpHeader);
806 QString lowercaseKey = key.toLower();
807 QList<QPair<QString, QString> >::Iterator it = d->values.begin();
808 while (it != d->values.end()) {
809 if ((*it).first.toLower() == lowercaseKey) {
810 (*it).second = value;
811 return;
812 }
813 ++it;
814 }
815 // not found so add
816 addValue(key, value);
817}
818
819/*!
820 Sets the header entries to be the list of key value pairs in \a values.
821*/
822void QHttpHeader::setValues(const QList<QPair<QString, QString> > &values)
823{
824 Q_D(QHttpHeader);
825 d->values = values;
826}
827
828/*!
829 Adds a new entry with the \a key and \a value.
830*/
831void QHttpHeader::addValue(const QString &key, const QString &value)
832{
833 Q_D(QHttpHeader);
834 d->values.append(qMakePair(key, value));
835}
836
837/*!
838 Returns all the entries in the header.
839*/
840QList<QPair<QString, QString> > QHttpHeader::values() const
841{
842 Q_D(const QHttpHeader);
843 return d->values;
844}
845
846/*!
847 Removes the entry with the key \a key from the HTTP header.
848
849 \sa value() setValue()
850*/
851void QHttpHeader::removeValue(const QString &key)
852{
853 Q_D(QHttpHeader);
854 QString lowercaseKey = key.toLower();
855 QList<QPair<QString, QString> >::Iterator it = d->values.begin();
856 while (it != d->values.end()) {
857 if ((*it).first.toLower() == lowercaseKey) {
858 d->values.erase(it);
859 return;
860 }
861 ++it;
862 }
863}
864
865/*!
866 Removes all the entries with the key \a key from the HTTP header.
867*/
868void QHttpHeader::removeAllValues(const QString &key)
869{
870 Q_D(QHttpHeader);
871 QString lowercaseKey = key.toLower();
872 QList<QPair<QString, QString> >::Iterator it = d->values.begin();
873 while (it != d->values.end()) {
874 if ((*it).first.toLower() == lowercaseKey) {
875 it = d->values.erase(it);
876 continue;
877 }
878 ++it;
879 }
880}
881
882/*! \internal
883 Parses the single HTTP header line \a line which has the format
884 key, colon, space, value, and adds key/value to the headers. The
885 linenumber is \a number. Returns true if the line was successfully
886 parsed and the key/value added; otherwise returns false.
887
888 \sa parse()
889*/
890bool QHttpHeader::parseLine(const QString &line, int)
891{
892 int i = line.indexOf(QLatin1Char(':'));
893 if (i == -1)
894 return false;
895
896 addValue(line.left(i).trimmed(), line.mid(i + 1).trimmed());
897
898 return true;
899}
900
901/*!
902 Returns a string representation of the HTTP header.
903
904 The string is suitable for use by the constructor that takes a
905 QString. It consists of lines with the format: key, colon, space,
906 value, "\r\n".
907*/
908QString QHttpHeader::toString() const
909{
910 Q_D(const QHttpHeader);
911 if (!isValid())
912 return QLatin1String("");
913
914 QString ret = QLatin1String("");
915
916 QList<QPair<QString, QString> >::ConstIterator it = d->values.constBegin();
917 while (it != d->values.constEnd()) {
918 ret += (*it).first + QLatin1String(": ") + (*it).second + QLatin1String("\r\n");
919 ++it;
920 }
921 return ret;
922}
923
924/*!
925 Returns true if the header has an entry for the special HTTP
926 header field \c content-length; otherwise returns false.
927
928 \sa contentLength() setContentLength()
929*/
930bool QHttpHeader::hasContentLength() const
931{
932 return hasKey(QLatin1String("content-length"));
933}
934
935/*!
936 Returns the value of the special HTTP header field \c
937 content-length.
938
939 \sa setContentLength() hasContentLength()
940*/
941uint QHttpHeader::contentLength() const
942{
943 return value(QLatin1String("content-length")).toUInt();
944}
945
946/*!
947 Sets the value of the special HTTP header field \c content-length
948 to \a len.
949
950 \sa contentLength() hasContentLength()
951*/
952void QHttpHeader::setContentLength(int len)
953{
954 setValue(QLatin1String("content-length"), QString::number(len));
955}
956
957/*!
958 Returns true if the header has an entry for the special HTTP
959 header field \c content-type; otherwise returns false.
960
961 \sa contentType() setContentType()
962*/
963bool QHttpHeader::hasContentType() const
964{
965 return hasKey(QLatin1String("content-type"));
966}
967
968/*!
969 Returns the value of the special HTTP header field \c content-type.
970
971 \sa setContentType() hasContentType()
972*/
973QString QHttpHeader::contentType() const
974{
975 QString type = value(QLatin1String("content-type"));
976 if (type.isEmpty())
977 return QString();
978
979 int pos = type.indexOf(QLatin1Char(';'));
980 if (pos == -1)
981 return type;
982
983 return type.left(pos).trimmed();
984}
985
986/*!
987 Sets the value of the special HTTP header field \c content-type to
988 \a type.
989
990 \sa contentType() hasContentType()
991*/
992void QHttpHeader::setContentType(const QString &type)
993{
994 setValue(QLatin1String("content-type"), type);
995}
996
997class QHttpResponseHeaderPrivate : public QHttpHeaderPrivate
998{
999 Q_DECLARE_PUBLIC(QHttpResponseHeader)
1000public:
1001 int statCode;
1002 QString reasonPhr;
1003 int majVer;
1004 int minVer;
1005};
1006
1007/****************************************************
1008 *
1009 * QHttpResponseHeader
1010 *
1011 ****************************************************/
1012
1013/*!
1014 \class QHttpResponseHeader
1015 \obsolete
1016 \brief The QHttpResponseHeader class contains response header information for HTTP.
1017
1018 \ingroup network
1019 \inmodule QtNetwork
1020
1021 This class is used by the QHttp class to report the header
1022 information that the client received from the server.
1023
1024 HTTP responses have a status code that indicates the status of the
1025 response. This code is a 3-digit integer result code (for details
1026 see to RFC 1945). In addition to the status code, you can also
1027 specify a human-readable text that describes the reason for the
1028 code ("reason phrase"). This class allows you to get the status
1029 code and the reason phrase.
1030
1031 \sa QHttpRequestHeader, QHttp, {HTTP Example}
1032*/
1033
1034/*!
1035 Constructs an empty HTTP response header.
1036*/
1037QHttpResponseHeader::QHttpResponseHeader()
1038 : QHttpHeader(*new QHttpResponseHeaderPrivate)
1039{
1040 setValid(false);
1041}
1042
1043/*!
1044 Constructs a copy of \a header.
1045*/
1046QHttpResponseHeader::QHttpResponseHeader(const QHttpResponseHeader &header)
1047 : QHttpHeader(*new QHttpResponseHeaderPrivate, header)
1048{
1049 Q_D(QHttpResponseHeader);
1050 d->statCode = header.d_func()->statCode;
1051 d->reasonPhr = header.d_func()->reasonPhr;
1052 d->majVer = header.d_func()->majVer;
1053 d->minVer = header.d_func()->minVer;
1054}
1055
1056/*!
1057 Copies the contents of \a header into this QHttpResponseHeader.
1058*/
1059QHttpResponseHeader &QHttpResponseHeader::operator=(const QHttpResponseHeader &header)
1060{
1061 Q_D(QHttpResponseHeader);
1062 QHttpHeader::operator=(header);
1063 d->statCode = header.d_func()->statCode;
1064 d->reasonPhr = header.d_func()->reasonPhr;
1065 d->majVer = header.d_func()->majVer;
1066 d->minVer = header.d_func()->minVer;
1067 return *this;
1068}
1069
1070/*!
1071 Constructs a HTTP response header from the string \a str. The
1072 string is parsed and the information is set. The \a str should
1073 consist of one or more "\r\n" delimited lines; the first line should be the
1074 status-line (format: HTTP-version, space, status-code, space,
1075 reason-phrase); each of remaining lines should have the format key, colon,
1076 space, value.
1077*/
1078QHttpResponseHeader::QHttpResponseHeader(const QString &str)
1079 : QHttpHeader(*new QHttpResponseHeaderPrivate)
1080{
1081 parse(str);
1082}
1083
1084/*!
1085 \since 4.1
1086
1087 Constructs a QHttpResponseHeader, setting the status code to \a code, the
1088 reason phrase to \a text and the protocol-version to \a majorVer and \a
1089 minorVer.
1090
1091 \sa statusCode() reasonPhrase() majorVersion() minorVersion()
1092*/
1093QHttpResponseHeader::QHttpResponseHeader(int code, const QString &text, int majorVer, int minorVer)
1094 : QHttpHeader(*new QHttpResponseHeaderPrivate)
1095{
1096 setStatusLine(code, text, majorVer, minorVer);
1097}
1098
1099/*!
1100 \since 4.1
1101
1102 Sets the status code to \a code, the reason phrase to \a text and
1103 the protocol-version to \a majorVer and \a minorVer.
1104
1105 \sa statusCode() reasonPhrase() majorVersion() minorVersion()
1106*/
1107void QHttpResponseHeader::setStatusLine(int code, const QString &text, int majorVer, int minorVer)
1108{
1109 Q_D(QHttpResponseHeader);
1110 setValid(true);
1111 d->statCode = code;
1112 d->reasonPhr = text;
1113 d->majVer = majorVer;
1114 d->minVer = minorVer;
1115}
1116
1117/*!
1118 Returns the status code of the HTTP response header.
1119
1120 \sa reasonPhrase() majorVersion() minorVersion()
1121*/
1122int QHttpResponseHeader::statusCode() const
1123{
1124 Q_D(const QHttpResponseHeader);
1125 return d->statCode;
1126}
1127
1128/*!
1129 Returns the reason phrase of the HTTP response header.
1130
1131 \sa statusCode() majorVersion() minorVersion()
1132*/
1133QString QHttpResponseHeader::reasonPhrase() const
1134{
1135 Q_D(const QHttpResponseHeader);
1136 return d->reasonPhr;
1137}
1138
1139/*!
1140 Returns the major protocol-version of the HTTP response header.
1141
1142 \sa minorVersion() statusCode() reasonPhrase()
1143*/
1144int QHttpResponseHeader::majorVersion() const
1145{
1146 Q_D(const QHttpResponseHeader);
1147 return d->majVer;
1148}
1149
1150/*!
1151 Returns the minor protocol-version of the HTTP response header.
1152
1153 \sa majorVersion() statusCode() reasonPhrase()
1154*/
1155int QHttpResponseHeader::minorVersion() const
1156{
1157 Q_D(const QHttpResponseHeader);
1158 return d->minVer;
1159}
1160
1161/*! \internal
1162*/
1163bool QHttpResponseHeader::parseLine(const QString &line, int number)
1164{
1165 Q_D(QHttpResponseHeader);
1166 if (number != 0)
1167 return QHttpHeader::parseLine(line, number);
1168
1169 QString l = line.simplified();
1170 if (l.length() < 10)
1171 return false;
1172
1173 if (l.left(5) == QLatin1String("HTTP/") && l[5].isDigit() && l[6] == QLatin1Char('.') &&
1174 l[7].isDigit() && l[8] == QLatin1Char(' ') && l[9].isDigit()) {
1175 d->majVer = l[5].toLatin1() - '0';
1176 d->minVer = l[7].toLatin1() - '0';
1177
1178 int pos = l.indexOf(QLatin1Char(' '), 9);
1179 if (pos != -1) {
1180 d->reasonPhr = l.mid(pos + 1);
1181 d->statCode = l.mid(9, pos - 9).toInt();
1182 } else {
1183 d->statCode = l.mid(9).toInt();
1184 d->reasonPhr.clear();
1185 }
1186 } else {
1187 return false;
1188 }
1189
1190 return true;
1191}
1192
1193/*! \reimp
1194*/
1195QString QHttpResponseHeader::toString() const
1196{
1197 Q_D(const QHttpResponseHeader);
1198 QString ret(QLatin1String("HTTP/%1.%2 %3 %4\r\n%5\r\n"));
1199 return ret.arg(d->majVer).arg(d->minVer).arg(d->statCode).arg(d->reasonPhr).arg(QHttpHeader::toString());
1200}
1201
1202class QHttpRequestHeaderPrivate : public QHttpHeaderPrivate
1203{
1204 Q_DECLARE_PUBLIC(QHttpRequestHeader)
1205public:
1206 QString m;
1207 QString p;
1208 int majVer;
1209 int minVer;
1210};
1211
1212/****************************************************
1213 *
1214 * QHttpRequestHeader
1215 *
1216 ****************************************************/
1217
1218/*!
1219 \class QHttpRequestHeader
1220 \obsolete
1221 \brief The QHttpRequestHeader class contains request header information for HTTP.
1222
1223 \ingroup network
1224 \inmodule QtNetwork
1225
1226 This class is used in the QHttp class to report the header
1227 information if the client requests something from the server.
1228
1229 HTTP requests have a method which describes the request's action.
1230 The most common requests are "GET" and "POST". In addition to the
1231 request method the header also includes a request-URI to specify
1232 the location for the method to use.
1233
1234 The method, request-URI and protocol-version can be set using a
1235 constructor or later using setRequest(). The values can be
1236 obtained using method(), path(), majorVersion() and
1237 minorVersion().
1238
1239 Note that the request-URI must be in the format expected by the
1240 HTTP server. That is, all reserved characters must be encoded in
1241 %HH (where HH are two hexadecimal digits). See
1242 QUrl::toPercentEncoding() for more information.
1243
1244 Important inherited functions: setValue() and value().
1245
1246 \sa QHttpResponseHeader QHttp
1247*/
1248
1249/*!
1250 Constructs an empty HTTP request header.
1251*/
1252QHttpRequestHeader::QHttpRequestHeader()
1253 : QHttpHeader(*new QHttpRequestHeaderPrivate)
1254{
1255 setValid(false);
1256}
1257
1258/*!
1259 Constructs a HTTP request header for the method \a method, the
1260 request-URI \a path and the protocol-version \a majorVer and \a
1261 minorVer. The \a path argument must be properly encoded for an
1262 HTTP request.
1263*/
1264QHttpRequestHeader::QHttpRequestHeader(const QString &method, const QString &path, int majorVer, int minorVer)
1265 : QHttpHeader(*new QHttpRequestHeaderPrivate)
1266{
1267 Q_D(QHttpRequestHeader);
1268 d->m = method;
1269 d->p = path;
1270 d->majVer = majorVer;
1271 d->minVer = minorVer;
1272}
1273
1274/*!
1275 Constructs a copy of \a header.
1276*/
1277QHttpRequestHeader::QHttpRequestHeader(const QHttpRequestHeader &header)
1278 : QHttpHeader(*new QHttpRequestHeaderPrivate, header)
1279{
1280 Q_D(QHttpRequestHeader);
1281 d->m = header.d_func()->m;
1282 d->p = header.d_func()->p;
1283 d->majVer = header.d_func()->majVer;
1284 d->minVer = header.d_func()->minVer;
1285}
1286
1287/*!
1288 Copies the content of \a header into this QHttpRequestHeader
1289*/
1290QHttpRequestHeader &QHttpRequestHeader::operator=(const QHttpRequestHeader &header)
1291{
1292 Q_D(QHttpRequestHeader);
1293 QHttpHeader::operator=(header);
1294 d->m = header.d_func()->m;
1295 d->p = header.d_func()->p;
1296 d->majVer = header.d_func()->majVer;
1297 d->minVer = header.d_func()->minVer;
1298 return *this;
1299}
1300
1301/*!
1302 Constructs a HTTP request header from the string \a str. The \a
1303 str should consist of one or more "\r\n" delimited lines; the first line
1304 should be the request-line (format: method, space, request-URI, space
1305 HTTP-version); each of the remaining lines should have the format key,
1306 colon, space, value.
1307*/
1308QHttpRequestHeader::QHttpRequestHeader(const QString &str)
1309 : QHttpHeader(*new QHttpRequestHeaderPrivate)
1310{
1311 parse(str);
1312}
1313
1314/*!
1315 This function sets the request method to \a method, the
1316 request-URI to \a path and the protocol-version to \a majorVer and
1317 \a minorVer. The \a path argument must be properly encoded for an
1318 HTTP request.
1319
1320 \sa method() path() majorVersion() minorVersion()
1321*/
1322void QHttpRequestHeader::setRequest(const QString &method, const QString &path, int majorVer, int minorVer)
1323{
1324 Q_D(QHttpRequestHeader);
1325 setValid(true);
1326 d->m = method;
1327 d->p = path;
1328 d->majVer = majorVer;
1329 d->minVer = minorVer;
1330}
1331
1332/*!
1333 Returns the method of the HTTP request header.
1334
1335 \sa path() majorVersion() minorVersion() setRequest()
1336*/
1337QString QHttpRequestHeader::method() const
1338{
1339 Q_D(const QHttpRequestHeader);
1340 return d->m;
1341}
1342
1343/*!
1344 Returns the request-URI of the HTTP request header.
1345
1346 \sa method() majorVersion() minorVersion() setRequest()
1347*/
1348QString QHttpRequestHeader::path() const
1349{
1350 Q_D(const QHttpRequestHeader);
1351 return d->p;
1352}
1353
1354/*!
1355 Returns the major protocol-version of the HTTP request header.
1356
1357 \sa minorVersion() method() path() setRequest()
1358*/
1359int QHttpRequestHeader::majorVersion() const
1360{
1361 Q_D(const QHttpRequestHeader);
1362 return d->majVer;
1363}
1364
1365/*!
1366 Returns the minor protocol-version of the HTTP request header.
1367
1368 \sa majorVersion() method() path() setRequest()
1369*/
1370int QHttpRequestHeader::minorVersion() const
1371{
1372 Q_D(const QHttpRequestHeader);
1373 return d->minVer;
1374}
1375
1376/*! \internal
1377*/
1378bool QHttpRequestHeader::parseLine(const QString &line, int number)
1379{
1380 Q_D(QHttpRequestHeader);
1381 if (number != 0)
1382 return QHttpHeader::parseLine(line, number);
1383
1384 QStringList lst = line.simplified().split(QLatin1String(" "));
1385 if (lst.count() > 0) {
1386 d->m = lst[0];
1387 if (lst.count() > 1) {
1388 d->p = lst[1];
1389 if (lst.count() > 2) {
1390 QString v = lst[2];
1391 if (v.length() >= 8 && v.left(5) == QLatin1String("HTTP/") &&
1392 v[5].isDigit() && v[6] == QLatin1Char('.') && v[7].isDigit()) {
1393 d->majVer = v[5].toLatin1() - '0';
1394 d->minVer = v[7].toLatin1() - '0';
1395 return true;
1396 }
1397 }
1398 }
1399 }
1400
1401 return false;
1402}
1403
1404/*! \reimp
1405*/
1406QString QHttpRequestHeader::toString() const
1407{
1408 Q_D(const QHttpRequestHeader);
1409 QString first(QLatin1String("%1 %2"));
1410 QString last(QLatin1String(" HTTP/%3.%4\r\n%5\r\n"));
1411 return first.arg(d->m).arg(d->p) +
1412 last.arg(d->majVer).arg(d->minVer).arg(QHttpHeader::toString());
1413}
1414
1415
1416/****************************************************
1417 *
1418 * QHttp
1419 *
1420 ****************************************************/
1421/*!
1422 \class QHttp
1423 \obsolete
1424 \reentrant
1425
1426 \brief The QHttp class provides an implementation of the HTTP protocol.
1427
1428 \ingroup network
1429 \inmodule QtNetwork
1430
1431
1432 This class provides a direct interface to HTTP that allows you to
1433 download and upload data with the HTTP protocol.
1434 However, for new applications, it is
1435 recommended to use QNetworkAccessManager and QNetworkReply, as
1436 those classes possess a simpler, yet more powerful API
1437 and a more modern protocol implementation.
1438
1439 The class works asynchronously, so there are no blocking
1440 functions. If an operation cannot be executed immediately, the
1441 function will still return straight away and the operation will be
1442 scheduled for later execution. The results of scheduled operations
1443 are reported via signals. This approach depends on the event loop
1444 being in operation.
1445
1446 The operations that can be scheduled (they are called "requests"
1447 in the rest of the documentation) are the following: setHost(),
1448 get(), post(), head() and request().
1449
1450 All of these requests return a unique identifier that allows you
1451 to keep track of the request that is currently executed. When the
1452 execution of a request starts, the requestStarted() signal with
1453 the identifier is emitted and when the request is finished, the
1454 requestFinished() signal is emitted with the identifier and a bool
1455 that indicates if the request finished with an error.
1456
1457 To make an HTTP request you must set up suitable HTTP headers. The
1458 following example demonstrates how to request the main HTML page
1459 from the Qt website (i.e., the URL \c http://qt.nokia.com/index.html):
1460
1461 \snippet doc/src/snippets/code/src_network_access_qhttp.cpp 2
1462
1463 For the common HTTP requests \c GET, \c POST and \c HEAD, QHttp
1464 provides the convenience functions get(), post() and head(). They
1465 already use a reasonable header and if you don't have to set
1466 special header fields, they are easier to use. The above example
1467 can also be written as:
1468
1469 \snippet doc/src/snippets/code/src_network_access_qhttp.cpp 3
1470
1471 For this example the following sequence of signals is emitted
1472 (with small variations, depending on network traffic, etc.):
1473
1474 \snippet doc/src/snippets/code/src_network_access_qhttp.cpp 4
1475
1476 The dataSendProgress() and dataReadProgress() signals in the above
1477 example are useful if you want to show a \link QProgressBar
1478 progress bar\endlink to inform the user about the progress of the
1479 download. The second argument is the total size of data. In
1480 certain cases it is not possible to know the total amount in
1481 advance, in which case the second argument is 0. (If you connect
1482 to a QProgressBar a total of 0 results in a busy indicator.)
1483
1484 When the response header is read, it is reported with the
1485 responseHeaderReceived() signal.
1486
1487 The readyRead() signal tells you that there is data ready to be
1488 read. The amount of data can then be queried with the
1489 bytesAvailable() function and it can be read with the read()
1490 or readAll() functions.
1491
1492 If an error occurs during the execution of one of the commands in
1493 a sequence of commands, all the pending commands (i.e. scheduled,
1494 but not yet executed commands) are cleared and no signals are
1495 emitted for them.
1496
1497 For example, if you have the following sequence of requests
1498
1499 \snippet doc/src/snippets/code/src_network_access_qhttp.cpp 5
1500
1501 and the get() request fails because the host lookup fails, then
1502 the post() request is never executed and the signals would look
1503 like this:
1504
1505 \snippet doc/src/snippets/code/src_network_access_qhttp.cpp 6
1506
1507 You can then get details about the error with the error() and
1508 errorString() functions. Note that only unexpected behavior, like
1509 network failure is considered as an error. If the server response
1510 contains an error status, like a 404 response, this is reported as
1511 a normal response case. So you should always check the \link
1512 QHttpResponseHeader::statusCode() status code \endlink of the
1513 response header.
1514
1515 The functions currentId() and currentRequest() provide more
1516 information about the currently executing request.
1517
1518 The functions hasPendingRequests() and clearPendingRequests()
1519 allow you to query and clear the list of pending requests.
1520
1521 \sa QFtp, QNetworkAccessManager, QNetworkRequest, QNetworkReply,
1522 {HTTP Example}, {Torrent Example}
1523*/
1524
1525/*!
1526 Constructs a QHttp object. The \a parent parameter is passed on
1527 to the QObject constructor.
1528*/
1529QHttp::QHttp(QObject *parent)
1530 : QObject(*new QHttpPrivate, parent)
1531{
1532 Q_D(QHttp);
1533 d->init();
1534}
1535
1536/*!
1537 Constructs a QHttp object. Subsequent requests are done by
1538 connecting to the server \a hostName on port \a port.
1539
1540 The \a parent parameter is passed on to the QObject constructor.
1541
1542 \sa setHost()
1543*/
1544QHttp::QHttp(const QString &hostName, quint16 port, QObject *parent)
1545 : QObject(*new QHttpPrivate, parent)
1546{
1547 Q_D(QHttp);
1548 d->init();
1549
1550 d->hostName = hostName;
1551 d->port = port;
1552}
1553
1554/*!
1555 Constructs a QHttp object. Subsequent requests are done by
1556 connecting to the server \a hostName on port \a port using the
1557 connection mode \a mode.
1558
1559 If port is 0, it will use the default port for the \a mode used
1560 (80 for Http and 443 for Https).
1561
1562 The \a parent parameter is passed on to the QObject constructor.
1563
1564 \sa setHost()
1565*/
1566QHttp::QHttp(const QString &hostName, ConnectionMode mode, quint16 port, QObject *parent)
1567 : QObject(*new QHttpPrivate, parent)
1568{
1569 Q_D(QHttp);
1570 d->init();
1571
1572 d->hostName = hostName;
1573 if (port == 0)
1574 port = (mode == ConnectionModeHttp) ? 80 : 443;
1575 d->port = port;
1576 d->mode = mode;
1577}
1578
1579void QHttpPrivate::init()
1580{
1581 Q_Q(QHttp);
1582 errorString = QLatin1String(QT_TRANSLATE_NOOP("QHttp", "Unknown error"));
1583 QMetaObject::invokeMethod(q, "_q_slotDoFinished", Qt::QueuedConnection);
1584 post100ContinueTimer.setSingleShot(true);
1585 QObject::connect(&post100ContinueTimer, SIGNAL(timeout()), q, SLOT(_q_continuePost()));
1586}
1587
1588/*!
1589 Destroys the QHttp object. If there is an open connection, it is
1590 closed.
1591*/
1592QHttp::~QHttp()
1593{
1594 abort();
1595}
1596
1597/*!
1598 \enum QHttp::ConnectionMode
1599 \since 4.3
1600
1601 This enum is used to specify the mode of connection to use:
1602
1603 \value ConnectionModeHttp The connection is a regular HTTP connection to the server
1604 \value ConnectionModeHttps The HTTPS protocol is used and the connection is encrypted using SSL.
1605
1606 When using the HTTPS mode, care should be taken to connect to the sslErrors signal, and
1607 handle possible SSL errors.
1608
1609 \sa QSslSocket
1610*/
1611
1612/*!
1613 \enum QHttp::State
1614
1615 This enum is used to specify the state the client is in:
1616
1617 \value Unconnected There is no connection to the host.
1618 \value HostLookup A host name lookup is in progress.
1619 \value Connecting An attempt to connect to the host is in progress.
1620 \value Sending The client is sending its request to the server.
1621 \value Reading The client's request has been sent and the client
1622 is reading the server's response.
1623 \value Connected The connection to the host is open, but the client is
1624 neither sending a request, nor waiting for a response.
1625 \value Closing The connection is closing down, but is not yet
1626 closed. (The state will be \c Unconnected when the connection is
1627 closed.)
1628
1629 \sa stateChanged() state()
1630*/
1631
1632/*! \enum QHttp::Error
1633
1634 This enum identifies the error that occurred.
1635
1636 \value NoError No error occurred.
1637 \value HostNotFound The host name lookup failed.
1638 \value ConnectionRefused The server refused the connection.
1639 \value UnexpectedClose The server closed the connection unexpectedly.
1640 \value InvalidResponseHeader The server sent an invalid response header.
1641 \value WrongContentLength The client could not read the content correctly
1642 because an error with respect to the content length occurred.
1643 \value Aborted The request was aborted with abort().
1644 \value ProxyAuthenticationRequiredError QHttp is using a proxy, and the
1645 proxy server requires authentication to establish a connection.
1646 \value AuthenticationRequiredError The web server requires authentication
1647 to complete the request.
1648 \value UnknownError An error other than those specified above
1649 occurred.
1650
1651 \sa error()
1652*/
1653
1654/*!
1655 \fn void QHttp::stateChanged(int state)
1656
1657 This signal is emitted when the state of the QHttp object changes.
1658 The argument \a state is the new state of the connection; it is
1659 one of the \l State values.
1660
1661 This usually happens when a request is started, but it can also
1662 happen when the server closes the connection or when a call to
1663 close() succeeded.
1664
1665 \sa get() post() head() request() close() state() State
1666*/
1667
1668/*!
1669 \fn void QHttp::responseHeaderReceived(const QHttpResponseHeader &resp);
1670
1671 This signal is emitted when the HTTP header of a server response
1672 is available. The header is passed in \a resp.
1673
1674 \sa get() post() head() request() readyRead()
1675*/
1676
1677/*!
1678 \fn void QHttp::readyRead(const QHttpResponseHeader &resp)
1679
1680 This signal is emitted when there is new response data to read.
1681
1682 If you specified a device in the request where the data should be
1683 written to, then this signal is \e not emitted; instead the data
1684 is written directly to the device.
1685
1686 The response header is passed in \a resp.
1687
1688 You can read the data with the readAll() or read() functions
1689
1690 This signal is useful if you want to process the data in chunks as
1691 soon as it becomes available. If you are only interested in the
1692 complete data, just connect to the requestFinished() signal and
1693 read the data then instead.
1694
1695 \sa get() post() request() readAll() read() bytesAvailable()
1696*/
1697
1698/*!
1699 \fn void QHttp::dataSendProgress(int done, int total)
1700
1701 This signal is emitted when this object sends data to a HTTP
1702 server to inform it about the progress of the upload.
1703
1704 \a done is the amount of data that has already arrived and \a
1705 total is the total amount of data. It is possible that the total
1706 amount of data that should be transferred cannot be determined, in
1707 which case \a total is 0.(If you connect to a QProgressBar, the
1708 progress bar shows a busy indicator if the total is 0).
1709
1710 \warning \a done and \a total are not necessarily the size in
1711 bytes, since for large files these values might need to be
1712 "scaled" to avoid overflow.
1713
1714 \sa dataReadProgress(), post(), request(), QProgressBar
1715*/
1716
1717/*!
1718 \fn void QHttp::dataReadProgress(int done, int total)
1719
1720 This signal is emitted when this object reads data from a HTTP
1721 server to indicate the current progress of the download.
1722
1723 \a done is the amount of data that has already arrived and \a
1724 total is the total amount of data. It is possible that the total
1725 amount of data that should be transferred cannot be determined, in
1726 which case \a total is 0.(If you connect to a QProgressBar, the
1727 progress bar shows a busy indicator if the total is 0).
1728
1729 \warning \a done and \a total are not necessarily the size in
1730 bytes, since for large files these values might need to be
1731 "scaled" to avoid overflow.
1732
1733 \sa dataSendProgress() get() post() request() QProgressBar
1734*/
1735
1736/*!
1737 \fn void QHttp::requestStarted(int id)
1738
1739 This signal is emitted when processing the request identified by
1740 \a id starts.
1741
1742 \sa requestFinished() done()
1743*/
1744
1745/*!
1746 \fn void QHttp::requestFinished(int id, bool error)
1747
1748 This signal is emitted when processing the request identified by
1749 \a id has finished. \a error is true if an error occurred during
1750 the processing; otherwise \a error is false.
1751
1752 \sa requestStarted() done() error() errorString()
1753*/
1754
1755/*!
1756 \fn void QHttp::done(bool error)
1757
1758 This signal is emitted when the last pending request has finished;
1759 (it is emitted after the last request's requestFinished() signal).
1760 \a error is true if an error occurred during the processing;
1761 otherwise \a error is false.
1762
1763 \sa requestFinished() error() errorString()
1764*/
1765
1766#ifndef QT_NO_NETWORKPROXY
1767
1768/*!
1769 \fn void QHttp::proxyAuthenticationRequired(const QNetworkProxy &proxy, QAuthenticator *authenticator)
1770 \since 4.3
1771
1772 This signal can be emitted when a \a proxy that requires
1773 authentication is used. The \a authenticator object can then be
1774 filled in with the required details to allow authentication and
1775 continue the connection.
1776
1777 \note It is not possible to use a QueuedConnection to connect to
1778 this signal, as the connection will fail if the authenticator has
1779 not been filled in with new information when the signal returns.
1780
1781 \sa QAuthenticator, QNetworkProxy
1782*/
1783
1784#endif
1785
1786/*!
1787 \fn void QHttp::authenticationRequired(const QString &hostname, quint16 port, QAuthenticator *authenticator)
1788 \since 4.3
1789
1790 This signal can be emitted when a web server on a given \a hostname and \a
1791 port requires authentication. The \a authenticator object can then be
1792 filled in with the required details to allow authentication and continue
1793 the connection.
1794
1795 \note It is not possible to use a QueuedConnection to connect to
1796 this signal, as the connection will fail if the authenticator has
1797 not been filled in with new information when the signal returns.
1798
1799 \sa QAuthenticator, QNetworkProxy
1800*/
1801
1802/*!
1803 \fn void QHttp::sslErrors(const QList<QSslError> &errors)
1804 \since 4.3
1805
1806 Forwards the sslErrors signal from the QSslSocket used in QHttp. \a errors
1807 is the list of errors that occurred during the SSL handshake. Unless you
1808 call ignoreSslErrors() from within a slot connected to this signal when an
1809 error occurs, QHttp will tear down the connection immediately after
1810 emitting the signal.
1811
1812 \sa QSslSocket QSslSocket::ignoreSslErrors()
1813*/
1814
1815/*!
1816 Aborts the current request and deletes all scheduled requests.
1817
1818 For the current request, the requestFinished() signal with the \c
1819 error argument \c true is emitted. For all other requests that are
1820 affected by the abort(), no signals are emitted.
1821
1822 Since this slot also deletes the scheduled requests, there are no
1823 requests left and the done() signal is emitted (with the \c error
1824 argument \c true).
1825
1826 \sa clearPendingRequests()
1827*/
1828void QHttp::abort()
1829{
1830 Q_D(QHttp);
1831 if (d->pending.isEmpty())
1832 return;
1833
1834 d->finishedWithError(tr("Request aborted"), Aborted);
1835 clearPendingRequests();
1836 if (d->socket)
1837 d->socket->abort();
1838 d->closeConn();
1839}
1840
1841/*!
1842 Returns the number of bytes that can be read from the response
1843 content at the moment.
1844
1845 \sa get() post() request() readyRead() read() readAll()
1846*/
1847qint64 QHttp::bytesAvailable() const
1848{
1849 Q_D(const QHttp);
1850#if defined(QHTTP_DEBUG)
1851 qDebug("QHttp::bytesAvailable(): %d bytes", (int)d->rba.size());
1852#endif
1853 return qint64(d->rba.size());
1854}
1855
1856/*! \fn qint64 QHttp::readBlock(char *data, quint64 maxlen)
1857
1858 Use read() instead.
1859*/
1860
1861/*!
1862 Reads \a maxlen bytes from the response content into \a data and
1863 returns the number of bytes read. Returns -1 if an error occurred.
1864
1865 \sa get() post() request() readyRead() bytesAvailable() readAll()
1866*/
1867qint64 QHttp::read(char *data, qint64 maxlen)
1868{
1869 Q_D(QHttp);
1870 if (data == 0 && maxlen != 0) {
1871 qWarning("QHttp::read: Null pointer error");
1872 return -1;
1873 }
1874 if (maxlen >= d->rba.size())
1875 maxlen = d->rba.size();
1876 int readSoFar = 0;
1877 while (!d->rba.isEmpty() && readSoFar < maxlen) {
1878 int nextBlockSize = d->rba.nextDataBlockSize();
1879 int bytesToRead = qMin<qint64>(maxlen - readSoFar, nextBlockSize);
1880 memcpy(data + readSoFar, d->rba.readPointer(), bytesToRead);
1881 d->rba.free(bytesToRead);
1882 readSoFar += bytesToRead;
1883 }
1884
1885 d->bytesDone += maxlen;
1886#if defined(QHTTP_DEBUG)
1887 qDebug("QHttp::read(): read %lld bytes (%lld bytes done)", maxlen, d->bytesDone);
1888#endif
1889 return maxlen;
1890}
1891
1892/*!
1893 Reads all the bytes from the response content and returns them.
1894
1895 \sa get() post() request() readyRead() bytesAvailable() read()
1896*/
1897QByteArray QHttp::readAll()
1898{
1899 qint64 avail = bytesAvailable();
1900 QByteArray tmp;
1901 tmp.resize(int(avail));
1902 qint64 got = read(tmp.data(), int(avail));
1903 tmp.resize(got);
1904 return tmp;
1905}
1906
1907/*!
1908 Returns the identifier of the HTTP request being executed or 0 if
1909 there is no request being executed (i.e. they've all finished).
1910
1911 \sa currentRequest()
1912*/
1913int QHttp::currentId() const
1914{
1915 Q_D(const QHttp);
1916 if (d->pending.isEmpty())
1917 return 0;
1918 return d->pending.first()->id;
1919}
1920
1921/*!
1922 Returns the request header of the HTTP request being executed. If
1923 the request is one issued by setHost() or close(), it
1924 returns an invalid request header, i.e.
1925 QHttpRequestHeader::isValid() returns false.
1926
1927 \sa currentId()
1928*/
1929QHttpRequestHeader QHttp::currentRequest() const
1930{
1931 Q_D(const QHttp);
1932 if (!d->pending.isEmpty()) {
1933 QHttpRequest *r = d->pending.first();
1934 if (r->hasRequestHeader())
1935 return r->requestHeader();
1936 }
1937 return QHttpRequestHeader();
1938}
1939
1940/*!
1941 Returns the received response header of the most recently finished HTTP
1942 request. If no response has yet been received
1943 QHttpResponseHeader::isValid() will return false.
1944
1945 \sa currentRequest()
1946*/
1947QHttpResponseHeader QHttp::lastResponse() const
1948{
1949 Q_D(const QHttp);
1950 return d->response;
1951}
1952
1953/*!
1954 Returns the QIODevice pointer that is used as the data source of the HTTP
1955 request being executed. If there is no current request or if the request
1956 does not use an IO device as the data source, this function returns 0.
1957
1958 This function can be used to delete the QIODevice in the slot connected to
1959 the requestFinished() signal.
1960
1961 \sa currentDestinationDevice() post() request()
1962*/
1963QIODevice *QHttp::currentSourceDevice() const
1964{
1965 Q_D(const QHttp);
1966 if (d->pending.isEmpty())
1967 return 0;
1968 return d->pending.first()->sourceDevice();
1969}
1970
1971/*!
1972 Returns the QIODevice pointer that is used as to store the data of the HTTP
1973 request being executed. If there is no current request or if the request
1974 does not store the data to an IO device, this function returns 0.
1975
1976 This function can be used to delete the QIODevice in the slot connected to
1977 the requestFinished() signal.
1978
1979 \sa currentSourceDevice() get() post() request()
1980*/
1981QIODevice *QHttp::currentDestinationDevice() const
1982{
1983 Q_D(const QHttp);
1984 if (d->pending.isEmpty())
1985 return 0;
1986 return d->pending.first()->destinationDevice();
1987}
1988
1989/*!
1990 Returns true if there are any requests scheduled that have not yet
1991 been executed; otherwise returns false.
1992
1993 The request that is being executed is \e not considered as a
1994 scheduled request.
1995
1996 \sa clearPendingRequests() currentId() currentRequest()
1997*/
1998bool QHttp::hasPendingRequests() const
1999{
2000 Q_D(const QHttp);
2001 return d->pending.count() > 1;
2002}
2003
2004/*!
2005 Deletes all pending requests from the list of scheduled requests.
2006 This does not affect the request that is being executed. If
2007 you want to stop this as well, use abort().
2008
2009 \sa hasPendingRequests() abort()
2010*/
2011void QHttp::clearPendingRequests()
2012{
2013 Q_D(QHttp);
2014 // delete all entires except the first one
2015 while (d->pending.count() > 1)
2016 delete d->pending.takeLast();
2017}
2018
2019/*!
2020 Sets the HTTP server that is used for requests to \a hostName on
2021 port \a port.
2022
2023 The function does not block; instead, it returns immediately. The request
2024 is scheduled, and its execution is performed asynchronously. The
2025 function returns a unique identifier which is passed by
2026 requestStarted() and requestFinished().
2027
2028 When the request is started the requestStarted() signal is
2029 emitted. When it is finished the requestFinished() signal is
2030 emitted.
2031
2032 \sa get() post() head() request() requestStarted() requestFinished() done()
2033*/
2034int QHttp::setHost(const QString &hostName, quint16 port)
2035{
2036 Q_D(QHttp);
2037 return d->addRequest(new QHttpSetHostRequest(hostName, port, ConnectionModeHttp));
2038}
2039
2040/*!
2041 Sets the HTTP server that is used for requests to \a hostName on
2042 port \a port using the connection mode \a mode.
2043
2044 If port is 0, it will use the default port for the \a mode used
2045 (80 for HTTP and 443 for HTTPS).
2046
2047 The function does not block; instead, it returns immediately. The request
2048 is scheduled, and its execution is performed asynchronously. The
2049 function returns a unique identifier which is passed by
2050 requestStarted() and requestFinished().
2051
2052 When the request is started the requestStarted() signal is
2053 emitted. When it is finished the requestFinished() signal is
2054 emitted.
2055
2056 \sa get() post() head() request() requestStarted() requestFinished() done()
2057*/
2058int QHttp::setHost(const QString &hostName, ConnectionMode mode, quint16 port)
2059{
2060#ifdef QT_NO_OPENSSL
2061 if (mode == ConnectionModeHttps)
2062 qWarning("QHttp::setHost: HTTPS connection requested but SSL support not compiled in");
2063#endif
2064 Q_D(QHttp);
2065 if (port == 0)
2066 port = (mode == ConnectionModeHttp) ? 80 : 443;
2067 return d->addRequest(new QHttpSetHostRequest(hostName, port, mode));
2068}
2069
2070/*!
2071 Replaces the internal QTcpSocket that QHttp uses with \a
2072 socket. This is useful if you want to use your own custom QTcpSocket
2073 subclass instead of the plain QTcpSocket that QHttp uses by default.
2074 QHttp does not take ownership of the socket, and will not delete \a
2075 socket when destroyed.
2076
2077 The function does not block; instead, it returns immediately. The request
2078 is scheduled, and its execution is performed asynchronously. The
2079 function returns a unique identifier which is passed by
2080 requestStarted() and requestFinished().
2081
2082 When the request is started the requestStarted() signal is
2083 emitted. When it is finished the requestFinished() signal is
2084 emitted.
2085
2086 Note: If QHttp is used in a non-GUI thread that runs its own event
2087 loop, you must move \a socket to that thread before calling setSocket().
2088
2089 \sa QObject::moveToThread(), {Thread Support in Qt}
2090*/
2091int QHttp::setSocket(QTcpSocket *socket)
2092{
2093 Q_D(QHttp);
2094 return d->addRequest(new QHttpSetSocketRequest(socket));
2095}
2096
2097/*!
2098 This function sets the user name \a userName and password \a
2099 password for web pages that require authentication.
2100
2101 The function does not block; instead, it returns immediately. The request
2102 is scheduled, and its execution is performed asynchronously. The
2103 function returns a unique identifier which is passed by
2104 requestStarted() and requestFinished().
2105
2106 When the request is started the requestStarted() signal is
2107 emitted. When it is finished the requestFinished() signal is
2108 emitted.
2109*/
2110int QHttp::setUser(const QString &userName, const QString &password)
2111{
2112 Q_D(QHttp);
2113 return d->addRequest(new QHttpSetUserRequest(userName, password));
2114}
2115
2116#ifndef QT_NO_NETWORKPROXY
2117
2118/*!
2119 Enables HTTP proxy support, using the proxy server \a host on port \a
2120 port. \a username and \a password can be provided if the proxy server
2121 requires authentication.
2122
2123 Example:
2124
2125 \snippet doc/src/snippets/code/src_network_access_qhttp.cpp 7
2126
2127 QHttp supports non-transparent web proxy servers only, such as the Squid
2128 Web proxy cache server (from \l http://www.squid.org/). For transparent
2129 proxying, such as SOCKS5, use QNetworkProxy instead.
2130
2131 \note setProxy() has to be called before setHost() for it to take effect.
2132 If setProxy() is called after setHost(), then it will not apply until after
2133 setHost() is called again.
2134
2135 \sa QFtp::setProxy()
2136*/
2137int QHttp::setProxy(const QString &host, int port,
2138 const QString &username, const QString &password)
2139{
2140 Q_D(QHttp);
2141 QNetworkProxy proxy(QNetworkProxy::HttpProxy, host, port, username, password);
2142 return d->addRequest(new QHttpSetProxyRequest(proxy));
2143}
2144
2145/*!
2146 \overload
2147
2148 Enables HTTP proxy support using the proxy settings from \a
2149 proxy. If \a proxy is a transparent proxy, QHttp will call
2150 QAbstractSocket::setProxy() on the underlying socket. If the type
2151 is QNetworkProxy::HttpCachingProxy, QHttp will behave like the
2152 previous function.
2153
2154 \note for compatibility with Qt 4.3, if the proxy type is
2155 QNetworkProxy::HttpProxy and the request type is unencrypted (that
2156 is, ConnectionModeHttp), QHttp will treat the proxy as a caching
2157 proxy.
2158*/
2159int QHttp::setProxy(const QNetworkProxy &proxy)
2160{
2161 Q_D(QHttp);
2162 return d->addRequest(new QHttpSetProxyRequest(proxy));
2163}
2164
2165#endif
2166
2167/*!
2168 Sends a get request for \a path to the server set by setHost() or
2169 as specified in the constructor.
2170
2171 \a path must be a absolute path like \c /index.html or an
2172 absolute URI like \c http://example.com/index.html and
2173 must be encoded with either QUrl::toPercentEncoding() or
2174 QUrl::encodedPath().
2175
2176 If the IO device \a to is 0 the readyRead() signal is emitted
2177 every time new content data is available to read.
2178
2179 If the IO device \a to is not 0, the content data of the response
2180 is written directly to the device. Make sure that the \a to
2181 pointer is valid for the duration of the operation (it is safe to
2182 delete it when the requestFinished() signal is emitted).
2183
2184 \section1 Request Processing
2185
2186 The function does not block; instead, it returns immediately. The request
2187 is scheduled, and its execution is performed asynchronously. The
2188 function returns a unique identifier which is passed by
2189 requestStarted() and requestFinished().
2190
2191 When the request is started the requestStarted() signal is
2192 emitted. When it is finished the requestFinished() signal is
2193 emitted.
2194
2195 \sa setHost(), post(), head(), request(), requestStarted(),
2196 requestFinished(), done()
2197*/
2198int QHttp::get(const QString &path, QIODevice *to)
2199{
2200 Q_D(QHttp);
2201 QHttpRequestHeader header(QLatin1String("GET"), path);
2202 header.setValue(QLatin1String("Connection"), QLatin1String("Keep-Alive"));
2203 return d->addRequest(new QHttpPGHRequest(header, (QIODevice *) 0, to));
2204}
2205
2206/*!
2207 Sends a post request for \a path to the server set by setHost() or
2208 as specified in the constructor.
2209
2210 \a path must be an absolute path like \c /index.html or an
2211 absolute URI like \c http://example.com/index.html and
2212 must be encoded with either QUrl::toPercentEncoding() or
2213 QUrl::encodedPath().
2214
2215 The incoming data comes via the \a data IO device.
2216
2217 If the IO device \a to is 0 the readyRead() signal is emitted
2218 every time new content data is available to read.
2219
2220 If the IO device \a to is not 0, the content data of the response
2221 is written directly to the device. Make sure that the \a to
2222 pointer is valid for the duration of the operation (it is safe to
2223 delete it when the requestFinished() signal is emitted).
2224
2225 The function does not block; instead, it returns immediately. The request
2226 is scheduled, and its execution is performed asynchronously. The
2227 function returns a unique identifier which is passed by
2228 requestStarted() and requestFinished().
2229
2230 When the request is started the requestStarted() signal is
2231 emitted. When it is finished the requestFinished() signal is
2232 emitted.
2233
2234 \sa setHost() get() head() request() requestStarted() requestFinished() done()
2235*/
2236int QHttp::post(const QString &path, QIODevice *data, QIODevice *to )
2237{
2238 Q_D(QHttp);
2239 QHttpRequestHeader header(QLatin1String("POST"), path);
2240 header.setValue(QLatin1String("Connection"), QLatin1String("Keep-Alive"));
2241 return d->addRequest(new QHttpPGHRequest(header, data, to));
2242}
2243
2244/*!
2245 \overload
2246
2247 \a data is used as the content data of the HTTP request.
2248*/
2249int QHttp::post(const QString &path, const QByteArray &data, QIODevice *to)
2250{
2251 Q_D(QHttp);
2252 QHttpRequestHeader header(QLatin1String("POST"), path);
2253 header.setValue(QLatin1String("Connection"), QLatin1String("Keep-Alive"));
2254 return d->addRequest(new QHttpPGHRequest(header, new QByteArray(data), to));
2255}
2256
2257/*!
2258 Sends a header request for \a path to the server set by setHost()
2259 or as specified in the constructor.
2260
2261 \a path must be an absolute path like \c /index.html or an
2262 absolute URI like \c http://example.com/index.html.
2263
2264 The function does not block; instead, it returns immediately. The request
2265 is scheduled, and its execution is performed asynchronously. The
2266 function returns a unique identifier which is passed by
2267 requestStarted() and requestFinished().
2268
2269 When the request is started the requestStarted() signal is
2270 emitted. When it is finished the requestFinished() signal is
2271 emitted.
2272
2273 \sa setHost() get() post() request() requestStarted() requestFinished() done()
2274*/
2275int QHttp::head(const QString &path)
2276{
2277 Q_D(QHttp);
2278 QHttpRequestHeader header(QLatin1String("HEAD"), path);
2279 header.setValue(QLatin1String("Connection"), QLatin1String("Keep-Alive"));
2280 return d->addRequest(new QHttpPGHRequest(header, (QIODevice*)0, 0));
2281}
2282
2283/*!
2284 Sends a request to the server set by setHost() or as specified in
2285 the constructor. Uses the \a header as the HTTP request header.
2286 You are responsible for setting up a header that is appropriate
2287 for your request.
2288
2289 The incoming data comes via the \a data IO device.
2290
2291 If the IO device \a to is 0 the readyRead() signal is emitted
2292 every time new content data is available to read.
2293
2294 If the IO device \a to is not 0, the content data of the response
2295 is written directly to the device. Make sure that the \a to
2296 pointer is valid for the duration of the operation (it is safe to
2297 delete it when the requestFinished() signal is emitted).
2298
2299 The function does not block; instead, it returns immediately. The request
2300 is scheduled, and its execution is performed asynchronously. The
2301 function returns a unique identifier which is passed by
2302 requestStarted() and requestFinished().
2303
2304 When the request is started the requestStarted() signal is
2305 emitted. When it is finished the requestFinished() signal is
2306 emitted.
2307
2308 \sa setHost() get() post() head() requestStarted() requestFinished() done()
2309*/
2310int QHttp::request(const QHttpRequestHeader &header, QIODevice *data, QIODevice *to)
2311{
2312 Q_D(QHttp);
2313 return d->addRequest(new QHttpNormalRequest(header, data, to));
2314}
2315
2316/*!
2317 \overload
2318
2319 \a data is used as the content data of the HTTP request.
2320*/
2321int QHttp::request(const QHttpRequestHeader &header, const QByteArray &data, QIODevice *to )
2322{
2323 Q_D(QHttp);
2324 return d->addRequest(new QHttpNormalRequest(header, new QByteArray(data), to));
2325}
2326
2327/*!
2328 Closes the connection; this is useful if you have a keep-alive
2329 connection and want to close it.
2330
2331 For the requests issued with get(), post() and head(), QHttp sets
2332 the connection to be keep-alive. You can also do this using the
2333 header you pass to the request() function. QHttp only closes the
2334 connection to the HTTP server if the response header requires it
2335 to do so.
2336
2337 The function does not block; instead, it returns immediately. The request
2338 is scheduled, and its execution is performed asynchronously. The
2339 function returns a unique identifier which is passed by
2340 requestStarted() and requestFinished().
2341
2342 When the request is started the requestStarted() signal is
2343 emitted. When it is finished the requestFinished() signal is
2344 emitted.
2345
2346 If you want to close the connection immediately, you have to use
2347 abort() instead.
2348
2349 \sa stateChanged() abort() requestStarted() requestFinished() done()
2350*/
2351int QHttp::close()
2352{
2353 Q_D(QHttp);
2354 return d->addRequest(new QHttpCloseRequest());
2355}
2356
2357/*!
2358 \obsolete
2359
2360 Behaves the same as close().
2361*/
2362int QHttp::closeConnection()
2363{
2364 Q_D(QHttp);
2365 return d->addRequest(new QHttpCloseRequest());
2366}
2367
2368int QHttpPrivate::addRequest(QHttpNormalRequest *req)
2369{
2370 QHttpRequestHeader h = req->requestHeader();
2371 if (h.path().isEmpty()) {
2372 // note: the following qWarning is autotested. If you change it, change the test too.
2373 qWarning("QHttp: empty path requested is invalid -- using '/'");
2374 h.setRequest(h.method(), QLatin1String("/"), h.majorVersion(), h.minorVersion());
2375 req->setRequestHeader(h);
2376 }
2377
2378 // contine below
2379 return addRequest(static_cast<QHttpRequest *>(req));
2380}
2381
2382int QHttpPrivate::addRequest(QHttpRequest *req)
2383{
2384 Q_Q(QHttp);
2385 pending.append(req);
2386
2387 if (pending.count() == 1) {
2388 // don't emit the requestStarted() signal before the id is returned
2389 QMetaObject::invokeMethod(q, "_q_startNextRequest", Qt::QueuedConnection);
2390 }
2391 return req->id;
2392}
2393
2394void QHttpPrivate::_q_startNextRequest()
2395{
2396 Q_Q(QHttp);
2397 if (pending.isEmpty())
2398 return;
2399 QHttpRequest *r = pending.first();
2400
2401 error = QHttp::NoError;
2402 errorString = QLatin1String(QT_TRANSLATE_NOOP("QHttp", "Unknown error"));
2403
2404 if (q->bytesAvailable() != 0)
2405 q->readAll(); // clear the data
2406 emit q->requestStarted(r->id);
2407 r->start(q);
2408}
2409
2410void QHttpPrivate::_q_slotSendRequest()
2411{
2412 if (hostName.isNull()) {
2413 finishedWithError(QLatin1String(QT_TRANSLATE_NOOP("QHttp", "No server set to connect to")),
2414 QHttp::UnknownError);
2415 return;
2416 }
2417
2418 QString connectionHost = hostName;
2419 int connectionPort = port;
2420 bool sslInUse = false;
2421
2422#ifndef QT_NO_OPENSSL
2423 QSslSocket *sslSocket = qobject_cast<QSslSocket *>(socket);
2424 if (mode == QHttp::ConnectionModeHttps || (sslSocket && sslSocket->isEncrypted()))
2425 sslInUse = true;
2426#endif
2427
2428#ifndef QT_NO_NETWORKPROXY
2429 bool cachingProxyInUse = false;
2430 bool transparentProxyInUse = false;
2431 if (proxy.type() == QNetworkProxy::DefaultProxy)
2432 proxy = QNetworkProxy::applicationProxy();
2433
2434 if (proxy.type() == QNetworkProxy::HttpCachingProxy) {
2435 if (proxy.hostName().isEmpty())
2436 proxy.setType(QNetworkProxy::NoProxy);
2437 else
2438 cachingProxyInUse = true;
2439 } else if (proxy.type() == QNetworkProxy::HttpProxy) {
2440 // Compatibility behaviour: HttpProxy can be used to mean both
2441 // transparent and caching proxy
2442 if (proxy.hostName().isEmpty()) {
2443 proxy.setType(QNetworkProxy::NoProxy);
2444 } else if (sslInUse) {
2445 // Disallow use of caching proxy with HTTPS; instead fall back to
2446 // transparent HTTP CONNECT proxying.
2447 transparentProxyInUse = true;
2448 } else {
2449 proxy.setType(QNetworkProxy::HttpCachingProxy);
2450 cachingProxyInUse = true;
2451 }
2452 }
2453
2454 // Proxy support. Insert the Proxy-Authorization item into the
2455 // header before it's sent off to the proxy.
2456 if (cachingProxyInUse) {
2457 QUrl proxyUrl;
2458 proxyUrl.setScheme(QLatin1String("http"));
2459 proxyUrl.setHost(hostName);
2460 if (port && port != 80)
2461 proxyUrl.setPort(port);
2462 QString request = QString::fromAscii(proxyUrl.resolved(QUrl::fromEncoded(header.path().toLatin1())).toEncoded());
2463
2464 header.setRequest(header.method(), request, header.majorVersion(), header.minorVersion());
2465 header.setValue(QLatin1String("Proxy-Connection"), QLatin1String("keep-alive"));
2466
2467 QAuthenticatorPrivate *auth = QAuthenticatorPrivate::getPrivate(proxyAuthenticator);
2468 if (auth && auth->method != QAuthenticatorPrivate::None) {
2469 QByteArray response = auth->calculateResponse(header.method().toLatin1(), header.path().toLatin1());
2470 header.setValue(QLatin1String("Proxy-Authorization"), QString::fromLatin1(response));
2471 }
2472
2473 connectionHost = proxy.hostName();
2474 connectionPort = proxy.port();
2475 }
2476
2477 if (transparentProxyInUse || sslInUse) {
2478 socket->setProxy(proxy);
2479 }
2480#endif
2481
2482 // Username support. Insert the user and password into the query
2483 // string.
2484 QAuthenticatorPrivate *auth = QAuthenticatorPrivate::getPrivate(authenticator);
2485 if (auth && auth->method != QAuthenticatorPrivate::None) {
2486 QByteArray response = auth->calculateResponse(header.method().toLatin1(), header.path().toLatin1());
2487 header.setValue(QLatin1String("Authorization"), QString::fromLatin1(response));
2488 }
2489
2490 // Do we need to setup a new connection or can we reuse an
2491 // existing one?
2492 if (socket->peerName() != connectionHost || socket->peerPort() != connectionPort
2493 || socket->state() != QTcpSocket::ConnectedState
2494#ifndef QT_NO_OPENSSL
2495 || (sslSocket && sslSocket->isEncrypted() != (mode == QHttp::ConnectionModeHttps))
2496#endif
2497 ) {
2498 socket->blockSignals(true);
2499 socket->abort();
2500 socket->blockSignals(false);
2501
2502 setState(QHttp::Connecting);
2503#ifndef QT_NO_OPENSSL
2504 if (sslSocket && mode == QHttp::ConnectionModeHttps) {
2505 sslSocket->connectToHostEncrypted(hostName, port);
2506 } else
2507#endif
2508 {
2509 socket->connectToHost(connectionHost, connectionPort);
2510 }
2511 } else {
2512 _q_slotConnected();
2513 }
2514
2515}
2516
2517void QHttpPrivate::finishedWithSuccess()
2518{
2519 Q_Q(QHttp);
2520 if (pending.isEmpty())
2521 return;
2522 QHttpRequest *r = pending.first();
2523
2524 // did we recurse?
2525 if (r->finished)
2526 return;
2527 r->finished = true;
2528 hasFinishedWithError = false;
2529
2530 emit q->requestFinished(r->id, false);
2531 if (hasFinishedWithError) {
2532 // we recursed and changed into an error. The finishedWithError function
2533 // below has emitted the done(bool) signal and cleared the queue by now.
2534 return;
2535 }
2536
2537 pending.removeFirst();
2538 delete r;
2539
2540 if (pending.isEmpty()) {
2541 emit q->done(false);
2542 } else {
2543 _q_startNextRequest();
2544 }
2545}
2546
2547void QHttpPrivate::finishedWithError(const QString &detail, int errorCode)
2548{
2549 Q_Q(QHttp);
2550 if (pending.isEmpty())
2551 return;
2552 QHttpRequest *r = pending.first();
2553 hasFinishedWithError = true;
2554
2555 error = QHttp::Error(errorCode);
2556 errorString = detail;
2557
2558 // did we recurse?
2559 if (!r->finished) {
2560 r->finished = true;
2561 emit q->requestFinished(r->id, true);
2562 }
2563
2564 while (!pending.isEmpty())
2565 delete pending.takeFirst();
2566 emit q->done(hasFinishedWithError);
2567}
2568
2569void QHttpPrivate::_q_slotClosed()
2570{
2571 Q_Q(QHttp);
2572
2573 if (state == QHttp::Reading) {
2574 if (response.hasKey(QLatin1String("content-length"))) {
2575 // We got Content-Length, so did we get all bytes?
2576 if (bytesDone + q->bytesAvailable() != response.contentLength()) {
2577 finishedWithError(QLatin1String(QT_TRANSLATE_NOOP("QHttp", "Wrong content length")), QHttp::WrongContentLength);
2578 }
2579 }
2580 } else if (state == QHttp::Connecting || state == QHttp::Sending) {
2581 finishedWithError(QLatin1String(QT_TRANSLATE_NOOP("QHttp", "Server closed connection unexpectedly")), QHttp::UnexpectedClose);
2582 }
2583
2584 postDevice = 0;
2585 if (state != QHttp::Closing)
2586 setState(QHttp::Closing);
2587 QMetaObject::invokeMethod(q, "_q_slotDoFinished", Qt::QueuedConnection);
2588}
2589
2590void QHttpPrivate::_q_continuePost()
2591{
2592 if (pendingPost) {
2593 pendingPost = false;
2594 setState(QHttp::Sending);
2595 _q_slotBytesWritten(0);
2596 }
2597}
2598
2599void QHttpPrivate::_q_slotConnected()
2600{
2601 if (state != QHttp::Sending) {
2602 bytesDone = 0;
2603 setState(QHttp::Sending);
2604 }
2605
2606 QString str = header.toString();
2607 bytesTotal = str.length();
2608 socket->write(str.toLatin1(), bytesTotal);
2609#if defined(QHTTP_DEBUG)
2610 qDebug("QHttp: write request header %p:\n---{\n%s}---", &header, str.toLatin1().constData());
2611#endif
2612
2613 if (postDevice) {
2614 postDevice->seek(0); // reposition the device
2615 bytesTotal += postDevice->size();
2616 //check for 100-continue
2617 if (header.value(QLatin1String("expect")).contains(QLatin1String("100-continue"), Qt::CaseInsensitive)) {
2618 //create a time out for 2 secs.
2619 pendingPost = true;
2620 post100ContinueTimer.start(2000);
2621 }
2622 } else {
2623 bytesTotal += buffer.size();
2624 socket->write(buffer, buffer.size());
2625 }
2626}
2627
2628void QHttpPrivate::_q_slotError(QAbstractSocket::SocketError err)
2629{
2630 Q_Q(QHttp);
2631 postDevice = 0;
2632
2633 if (state == QHttp::Connecting || state == QHttp::Reading || state == QHttp::Sending) {
2634 switch (err) {
2635 case QTcpSocket::ConnectionRefusedError:
2636 finishedWithError(QLatin1String(QT_TRANSLATE_NOOP("QHttp", "Connection refused (or timed out)")), QHttp::ConnectionRefused);
2637 break;
2638 case QTcpSocket::HostNotFoundError:
2639 finishedWithError(QString::fromLatin1(QT_TRANSLATE_NOOP("QHttp", "Host %1 not found"))
2640 .arg(socket->peerName()), QHttp::HostNotFound);
2641 break;
2642 case QTcpSocket::RemoteHostClosedError:
2643 if (state == QHttp::Sending && reconnectAttempts--) {
2644 setState(QHttp::Closing);
2645 setState(QHttp::Unconnected);
2646 socket->blockSignals(true);
2647 socket->abort();
2648 socket->blockSignals(false);
2649 QMetaObject::invokeMethod(q, "_q_slotSendRequest", Qt::QueuedConnection);
2650 return;
2651 }
2652 break;
2653#ifndef QT_NO_NETWORKPROXY
2654 case QTcpSocket::ProxyAuthenticationRequiredError:
2655 finishedWithError(socket->errorString(), QHttp::ProxyAuthenticationRequiredError);
2656 break;
2657#endif
2658 default:
2659 finishedWithError(QLatin1String(QT_TRANSLATE_NOOP("QHttp", "HTTP request failed")), QHttp::UnknownError);
2660 break;
2661 }
2662 }
2663
2664 closeConn();
2665}
2666
2667#ifndef QT_NO_OPENSSL
2668void QHttpPrivate::_q_slotEncryptedBytesWritten(qint64 written)
2669{
2670 Q_UNUSED(written);
2671 postMoreData();
2672}
2673#endif
2674
2675void QHttpPrivate::_q_slotBytesWritten(qint64 written)
2676{
2677 Q_Q(QHttp);
2678 bytesDone += written;
2679 emit q->dataSendProgress(bytesDone, bytesTotal);
2680 postMoreData();
2681}
2682
2683// Send the POST data
2684void QHttpPrivate::postMoreData()
2685{
2686 if (pendingPost)
2687 return;
2688
2689 if (!postDevice)
2690 return;
2691
2692 // the following is backported code from Qt 4.6 QNetworkAccessManager.
2693 // We also have to check the encryptedBytesToWrite() if it is an SSL socket.
2694#ifndef QT_NO_OPENSSL
2695 QSslSocket *sslSocket = qobject_cast<QSslSocket*>(socket);
2696 // if it is really an ssl socket, check more than just bytesToWrite()
2697 if ((socket->bytesToWrite() + (sslSocket ? sslSocket->encryptedBytesToWrite() : 0)) == 0) {
2698#else
2699 if (socket->bytesToWrite() == 0) {
2700#endif
2701 int max = qMin<qint64>(4096, postDevice->size() - postDevice->pos());
2702 QByteArray arr;
2703 arr.resize(max);
2704
2705 int n = postDevice->read(arr.data(), max);
2706 if (n < 0) {
2707 qWarning("Could not read enough bytes from the device");
2708 closeConn();
2709 return;
2710 }
2711 if (postDevice->atEnd()) {
2712 postDevice = 0;
2713 }
2714
2715 socket->write(arr, n);
2716 }
2717}
2718
2719void QHttpPrivate::_q_slotReadyRead()
2720{
2721 Q_Q(QHttp);
2722 QHttp::State oldState = state;
2723 if (state != QHttp::Reading) {
2724 setState(QHttp::Reading);
2725 readHeader = true;
2726 headerStr = QLatin1String("");
2727 bytesDone = 0;
2728 chunkedSize = -1;
2729 repost = false;
2730 }
2731
2732 while (readHeader) {
2733 bool end = false;
2734 QString tmp;
2735 while (!end && socket->canReadLine()) {
2736 tmp = QString::fromAscii(socket->readLine());
2737 if (tmp == QLatin1String("\r\n") || tmp == QLatin1String("\n") || tmp.isEmpty())
2738 end = true;
2739 else
2740 headerStr += tmp;
2741 }
2742
2743 if (!end)
2744 return;
2745
2746 response = QHttpResponseHeader(headerStr);
2747 headerStr = QLatin1String("");
2748#if defined(QHTTP_DEBUG)
2749 qDebug("QHttp: read response header:\n---{\n%s}---", response.toString().toLatin1().constData());
2750#endif
2751 // Check header
2752 if (!response.isValid()) {
2753 finishedWithError(QLatin1String(QT_TRANSLATE_NOOP("QHttp", "Invalid HTTP response header")),
2754 QHttp::InvalidResponseHeader);
2755 closeConn();
2756 return;
2757 }
2758
2759 int statusCode = response.statusCode();
2760 if (statusCode == 401 || statusCode == 407) { // (Proxy) Authentication required
2761 QAuthenticator *auth =
2762#ifndef QT_NO_NETWORKPROXY
2763 statusCode == 407
2764 ? &proxyAuthenticator :
2765#endif
2766 &authenticator;
2767 if (auth->isNull())
2768 auth->detach();
2769 QAuthenticatorPrivate *priv = QAuthenticatorPrivate::getPrivate(*auth);
2770 priv->parseHttpResponse(response, (statusCode == 407));
2771 if (priv->phase == QAuthenticatorPrivate::Done) {
2772 socket->blockSignals(true);
2773#ifndef QT_NO_NETWORKPROXY
2774 if (statusCode == 407)
2775 emit q->proxyAuthenticationRequired(proxy, auth);
2776 else
2777#endif
2778 emit q->authenticationRequired(hostName, port, auth);
2779 socket->blockSignals(false);
2780 } else if (priv->phase == QAuthenticatorPrivate::Invalid) {
2781 finishedWithError(QLatin1String(QT_TRANSLATE_NOOP("QHttp", "Unknown authentication method")),
2782 QHttp::AuthenticationRequiredError);
2783 closeConn();
2784 return;
2785 }
2786
2787 // priv->phase will get reset to QAuthenticatorPrivate::Start if the authenticator got modified in the signal above.
2788 if (priv->phase == QAuthenticatorPrivate::Done) {
2789#ifndef QT_NO_NETWORKPROXY
2790 if (statusCode == 407)
2791 finishedWithError(QLatin1String(QT_TRANSLATE_NOOP("QHttp", "Proxy authentication required")),
2792 QHttp::ProxyAuthenticationRequiredError);
2793 else
2794#endif
2795 finishedWithError(QLatin1String(QT_TRANSLATE_NOOP("QHttp", "Authentication required")),
2796 QHttp::AuthenticationRequiredError);
2797 closeConn();
2798 return;
2799 } else {
2800 // close the connection if it isn't already and reconnect using the chosen authentication method
2801 bool willClose = (response.value(QLatin1String("proxy-connection")).toLower() == QLatin1String("close"))
2802 || (response.value(QLatin1String("connection")).toLower() == QLatin1String("close"));
2803 if (willClose) {
2804 if (socket) {
2805 setState(QHttp::Closing);
2806 socket->blockSignals(true);
2807 socket->close();
2808 socket->blockSignals(false);
2809 socket->readAll();
2810 }
2811 _q_slotSendRequest();
2812 return;
2813 } else {
2814 repost = true;
2815 }
2816 }
2817 } else {
2818 buffer.clear();
2819 }
2820
2821 if (response.statusCode() == 100 && pendingPost) {
2822 // if we have pending POST, start sending data otherwise ignore
2823 post100ContinueTimer.stop();
2824 QMetaObject::invokeMethod(q, "_q_continuePost", Qt::QueuedConnection);
2825 return;
2826 }
2827
2828 // The 100-continue header is ignored (in case of no 'expect:100-continue' header),
2829 // because when using the POST method, we send both the request header and data in
2830 // one chunk.
2831 if (response.statusCode() != 100) {
2832 post100ContinueTimer.stop();
2833 pendingPost = false;
2834 readHeader = false;
2835 if (response.hasKey(QLatin1String("transfer-encoding")) &&
2836 response.value(QLatin1String("transfer-encoding")).toLower().contains(QLatin1String("chunked")))
2837 chunkedSize = 0;
2838
2839 if (!repost)
2840 emit q->responseHeaderReceived(response);
2841 if (state == QHttp::Unconnected || state == QHttp::Closing)
2842 return;
2843 } else {
2844 // Restore the state, the next incoming data will be treated as if
2845 // we never say the 100 response.
2846 state = oldState;
2847 }
2848 }
2849
2850 bool everythingRead = false;
2851
2852 if (q->currentRequest().method() == QLatin1String("HEAD") ||
2853 response.statusCode() == 304 || response.statusCode() == 204 ||
2854 response.statusCode() == 205) {
2855 // HEAD requests have only headers as replies
2856 // These status codes never have a body:
2857 // 304 Not Modified
2858 // 204 No Content
2859 // 205 Reset Content
2860 everythingRead = true;
2861 } else {
2862 qint64 n = socket->bytesAvailable();
2863 QByteArray *arr = 0;
2864 if (chunkedSize != -1) {
2865 // transfer-encoding is chunked
2866 for (;;) {
2867 // get chunk size
2868 if (chunkedSize == 0) {
2869 if (!socket->canReadLine())
2870 break;
2871 QString sizeString = QString::fromAscii(socket->readLine());
2872 int tPos = sizeString.indexOf(QLatin1Char(';'));
2873 if (tPos != -1)
2874 sizeString.truncate(tPos);
2875 bool ok;
2876 chunkedSize = sizeString.toInt(&ok, 16);
2877 if (!ok) {
2878 finishedWithError(QLatin1String(QT_TRANSLATE_NOOP("QHttp", "Invalid HTTP chunked body")),
2879 QHttp::WrongContentLength);
2880 closeConn();
2881 delete arr;
2882 return;
2883 }
2884 if (chunkedSize == 0) // last-chunk
2885 chunkedSize = -2;
2886 }
2887
2888 // read trailer
2889 while (chunkedSize == -2 && socket->canReadLine()) {
2890 QString read = QString::fromAscii(socket->readLine());
2891 if (read == QLatin1String("\r\n") || read == QLatin1String("\n"))
2892 chunkedSize = -1;
2893 }
2894 if (chunkedSize == -1) {
2895 everythingRead = true;
2896 break;
2897 }
2898
2899 // make sure that you can read the terminating CRLF,
2900 // otherwise wait until next time...
2901 n = socket->bytesAvailable();
2902 if (n == 0)
2903 break;
2904 if (n == chunkedSize || n == chunkedSize+1) {
2905 n = chunkedSize - 1;
2906 if (n == 0)
2907 break;
2908 }
2909
2910 // read data
2911 qint64 toRead = chunkedSize < 0 ? n : qMin(n, chunkedSize);
2912 if (!arr)
2913 arr = new QByteArray;
2914 uint oldArrSize = arr->size();
2915 arr->resize(oldArrSize + toRead);
2916 qint64 read = socket->read(arr->data()+oldArrSize, toRead);
2917 arr->resize(oldArrSize + read);
2918
2919 chunkedSize -= read;
2920
2921 if (chunkedSize == 0 && n - read >= 2) {
2922 // read terminating CRLF
2923 char tmp[2];
2924 socket->read(tmp, 2);
2925 if (tmp[0] != '\r' || tmp[1] != '\n') {
2926 finishedWithError(QLatin1String(QT_TRANSLATE_NOOP("QHttp", "Invalid HTTP chunked body")),
2927 QHttp::WrongContentLength);
2928 closeConn();
2929 delete arr;
2930 return;
2931 }
2932 }
2933 }
2934 } else if (response.hasContentLength()) {
2935 if (repost && (n < response.contentLength())) {
2936 // wait for the content to be available fully
2937 // if repost is required, the content is ignored
2938 return;
2939 }
2940 n = qMin(qint64(response.contentLength() - bytesDone), n);
2941 if (n > 0) {
2942 arr = new QByteArray;
2943 arr->resize(n);
2944 qint64 read = socket->read(arr->data(), n);
2945 arr->resize(read);
2946 }
2947 if (bytesDone + q->bytesAvailable() + n == response.contentLength())
2948 everythingRead = true;
2949 } else if (n > 0) {
2950 // workaround for VC++ bug
2951 QByteArray temp = socket->readAll();
2952 arr = new QByteArray(temp);
2953 }
2954
2955 if (arr && !repost) {
2956 n = arr->size();
2957 if (toDevice) {
2958 qint64 bytesWritten;
2959 bytesWritten = toDevice->write(*arr, n);
2960 delete arr;
2961 arr = 0;
2962 // if writing to the device does not succeed, quit with error
2963 if (bytesWritten == -1 || bytesWritten < n) {
2964 finishedWithError(QLatin1String(QT_TRANSLATE_NOOP("QHttp", "Error writing response to device")), QHttp::UnknownError);
2965 } else {
2966 bytesDone += bytesWritten;
2967#if defined(QHTTP_DEBUG)
2968 qDebug("QHttp::_q_slotReadyRead(): read %lld bytes (%lld bytes done)", n, bytesDone);
2969#endif
2970 }
2971 if (response.hasContentLength())
2972 emit q->dataReadProgress(bytesDone, response.contentLength());
2973 else
2974 emit q->dataReadProgress(bytesDone, 0);
2975 } else {
2976 char *ptr = rba.reserve(arr->size());
2977 memcpy(ptr, arr->data(), arr->size());
2978 delete arr;
2979 arr = 0;
2980#if defined(QHTTP_DEBUG)
2981 qDebug("QHttp::_q_slotReadyRead(): read %lld bytes (%lld bytes done)", n, bytesDone + q->bytesAvailable());
2982#endif
2983 if (response.hasContentLength())
2984 emit q->dataReadProgress(bytesDone + q->bytesAvailable(), response.contentLength());
2985 else
2986 emit q->dataReadProgress(bytesDone + q->bytesAvailable(), 0);
2987 emit q->readyRead(response);
2988 }
2989 }
2990
2991 delete arr;
2992 }
2993
2994 if (everythingRead) {
2995 if (repost) {
2996 _q_slotSendRequest();
2997 return;
2998 }
2999 // Handle "Connection: close"
3000 if (response.value(QLatin1String("connection")).toLower() == QLatin1String("close")) {
3001 closeConn();
3002 } else {
3003 setState(QHttp::Connected);
3004 // Start a timer, so that we emit the keep alive signal
3005 // "after" this method returned.
3006 QMetaObject::invokeMethod(q, "_q_slotDoFinished", Qt::QueuedConnection);
3007 }
3008 }
3009}
3010
3011void QHttpPrivate::_q_slotDoFinished()
3012{
3013 if (state == QHttp::Connected) {
3014 finishedWithSuccess();
3015 } else if (state != QHttp::Unconnected) {
3016 setState(QHttp::Unconnected);
3017 finishedWithSuccess();
3018 }
3019}
3020
3021
3022/*!
3023 Returns the current state of the object. When the state changes,
3024 the stateChanged() signal is emitted.
3025
3026 \sa State stateChanged()
3027*/
3028QHttp::State QHttp::state() const
3029{
3030 Q_D(const QHttp);
3031 return d->state;
3032}
3033
3034/*!
3035 Returns the last error that occurred. This is useful to find out
3036 what happened when receiving a requestFinished() or a done()
3037 signal with the \c error argument \c true.
3038
3039 If you start a new request, the error status is reset to \c NoError.
3040*/
3041QHttp::Error QHttp::error() const
3042{
3043 Q_D(const QHttp);
3044 return d->error;
3045}
3046
3047/*!
3048 Returns a human-readable description of the last error that
3049 occurred. This is useful to present a error message to the user
3050 when receiving a requestFinished() or a done() signal with the \c
3051 error argument \c true.
3052*/
3053QString QHttp::errorString() const
3054{
3055 Q_D(const QHttp);
3056 return d->errorString;
3057}
3058
3059void QHttpPrivate::setState(int s)
3060{
3061 Q_Q(QHttp);
3062#if defined(QHTTP_DEBUG)
3063 qDebug("QHttp state changed %d -> %d", state, s);
3064#endif
3065 state = QHttp::State(s);
3066 emit q->stateChanged(s);
3067}
3068
3069void QHttpPrivate::closeConn()
3070{
3071 Q_Q(QHttp);
3072 // If no connection is open -> ignore
3073 if (state == QHttp::Closing || state == QHttp::Unconnected)
3074 return;
3075
3076 postDevice = 0;
3077 setState(QHttp::Closing);
3078
3079 // Already closed ?
3080 if (!socket || !socket->isOpen()) {
3081 QMetaObject::invokeMethod(q, "_q_slotDoFinished", Qt::QueuedConnection);
3082 } else {
3083 // Close now.
3084 socket->close();
3085 }
3086}
3087
3088void QHttpPrivate::setSock(QTcpSocket *sock)
3089{
3090 Q_Q(const QHttp);
3091
3092 // disconnect all existing signals
3093 if (socket)
3094 socket->disconnect();
3095 if (deleteSocket)
3096 delete socket;
3097
3098 // use the new QTcpSocket socket, or create one if socket is 0.
3099 deleteSocket = (sock == 0);
3100 socket = sock;
3101 if (!socket) {
3102#ifndef QT_NO_OPENSSL
3103 if (QSslSocket::supportsSsl())
3104 socket = new QSslSocket();
3105 else
3106#endif
3107 socket = new QTcpSocket();
3108 }
3109
3110 // connect all signals
3111 QObject::connect(socket, SIGNAL(connected()), q, SLOT(_q_slotConnected()));
3112 QObject::connect(socket, SIGNAL(disconnected()), q, SLOT(_q_slotClosed()));
3113 QObject::connect(socket, SIGNAL(readyRead()), q, SLOT(_q_slotReadyRead()));
3114 QObject::connect(socket, SIGNAL(error(QAbstractSocket::SocketError)), q, SLOT(_q_slotError(QAbstractSocket::SocketError)));
3115 QObject::connect(socket, SIGNAL(bytesWritten(qint64)),
3116 q, SLOT(_q_slotBytesWritten(qint64)));
3117#ifndef QT_NO_NETWORKPROXY
3118 QObject::connect(socket, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)),
3119 q, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
3120#endif
3121
3122#ifndef QT_NO_OPENSSL
3123 if (qobject_cast<QSslSocket *>(socket)) {
3124 QObject::connect(socket, SIGNAL(sslErrors(QList<QSslError>)),
3125 q, SIGNAL(sslErrors(QList<QSslError>)));
3126 QObject::connect(socket, SIGNAL(encryptedBytesWritten(qint64)),
3127 q, SLOT(_q_slotEncryptedBytesWritten(qint64)));
3128 }
3129#endif
3130}
3131
3132/*!
3133 Tells the QSslSocket used for the Http connection to ignore the errors
3134 reported in the sslErrors() signal.
3135
3136 Note that this function must be called from within a slot connected to the
3137 sslErrors() signal to have any effect.
3138
3139 \sa QSslSocket QSslSocket::sslErrors()
3140*/
3141#ifndef QT_NO_OPENSSL
3142void QHttp::ignoreSslErrors()
3143{
3144 Q_D(QHttp);
3145 QSslSocket *sslSocket = qobject_cast<QSslSocket *>(d->socket);
3146 if (sslSocket)
3147 sslSocket->ignoreSslErrors();
3148}
3149#endif
3150
3151QT_END_NAMESPACE
3152
3153#include "moc_qhttp.cpp"
3154
3155#endif
3156