source: trunk/src/network/access/qhttp.cpp@ 440

Last change on this file since 440 was 2, checked in by Dmitry A. Kuminov, 16 years ago

Initially imported qt-all-opensource-src-4.5.1 from Trolltech.

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