e4ea62f093bdc57d4c386769a7de3a8b0a55eac4
[profile/ivi/qtbase.git] / src / network / access / qhttpnetworkconnectionchannel.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
5 **
6 ** This file is part of the QtNetwork module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
16 **
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
20 **
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
28 **
29 ** Other Usage
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "qhttpnetworkconnection_p.h"
43 #include "qhttpnetworkconnectionchannel_p.h"
44 #include "private/qnoncontiguousbytedevice_p.h"
45
46 #include <qpair.h>
47 #include <qdebug.h>
48
49 #ifndef QT_NO_HTTP
50
51 #ifndef QT_NO_SSL
52 #    include <QtNetwork/qsslkey.h>
53 #    include <QtNetwork/qsslcipher.h>
54 #    include <QtNetwork/qsslconfiguration.h>
55 #endif
56
57 #ifndef QT_NO_BEARERMANAGEMENT
58 #include "private/qnetworksession_p.h"
59 #endif
60
61 QT_BEGIN_NAMESPACE
62
63 // TODO: Put channel specific stuff here so it does not polute qhttpnetworkconnection.cpp
64
65 QHttpNetworkConnectionChannel::QHttpNetworkConnectionChannel()
66     : socket(0)
67     , ssl(false)
68     , state(IdleState)
69     , reply(0)
70     , written(0)
71     , bytesTotal(0)
72     , resendCurrent(false)
73     , lastStatus(0)
74     , pendingEncrypt(false)
75     , reconnectAttempts(2)
76     , authMethod(QAuthenticatorPrivate::None)
77     , proxyAuthMethod(QAuthenticatorPrivate::None)
78     , authenticationCredentialsSent(false)
79     , proxyCredentialsSent(false)
80 #ifndef QT_NO_SSL
81     , ignoreAllSslErrors(false)
82 #endif
83     , pipeliningSupported(PipeliningSupportUnknown)
84     , networkLayerPreference(QAbstractSocket::AnyIPProtocol)
85     , connection(0)
86 {
87     // Inlining this function in the header leads to compiler error on
88     // release-armv5, on at least timebox 9.2 and 10.1.
89 }
90
91 void QHttpNetworkConnectionChannel::init()
92 {
93 #ifndef QT_NO_SSL
94     if (connection->d_func()->encrypt)
95         socket = new QSslSocket;
96     else
97         socket = new QTcpSocket;
98 #else
99     socket = new QTcpSocket;
100 #endif
101 #ifndef QT_NO_BEARERMANAGEMENT
102     //push session down to socket
103     if (networkSession)
104         socket->setProperty("_q_networksession", QVariant::fromValue(networkSession));
105 #endif
106 #ifndef QT_NO_NETWORKPROXY
107     // Set by QNAM anyway, but let's be safe here
108     socket->setProxy(QNetworkProxy::NoProxy);
109 #endif
110
111     QObject::connect(socket, SIGNAL(bytesWritten(qint64)),
112                      this, SLOT(_q_bytesWritten(qint64)),
113                      Qt::DirectConnection);
114     QObject::connect(socket, SIGNAL(connected()),
115                      this, SLOT(_q_connected()),
116                      Qt::DirectConnection);
117     QObject::connect(socket, SIGNAL(readyRead()),
118                      this, SLOT(_q_readyRead()),
119                      Qt::DirectConnection);
120
121     // The disconnected() and error() signals may already come
122     // while calling connectToHost().
123     // In case of a cached hostname or an IP this
124     // will then emit a signal to the user of QNetworkReply
125     // but cannot be caught because the user did not have a chance yet
126     // to connect to QNetworkReply's signals.
127     qRegisterMetaType<QAbstractSocket::SocketError>("QAbstractSocket::SocketError");
128     QObject::connect(socket, SIGNAL(disconnected()),
129                      this, SLOT(_q_disconnected()),
130                      Qt::QueuedConnection);
131     QObject::connect(socket, SIGNAL(error(QAbstractSocket::SocketError)),
132                      this, SLOT(_q_error(QAbstractSocket::SocketError)),
133                      Qt::QueuedConnection);
134
135
136 #ifndef QT_NO_NETWORKPROXY
137     QObject::connect(socket, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)),
138                      this, SLOT(_q_proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)),
139                      Qt::DirectConnection);
140 #endif
141
142 #ifndef QT_NO_SSL
143     QSslSocket *sslSocket = qobject_cast<QSslSocket*>(socket);
144     if (sslSocket) {
145         // won't be a sslSocket if encrypt is false
146         QObject::connect(sslSocket, SIGNAL(encrypted()),
147                          this, SLOT(_q_encrypted()),
148                          Qt::DirectConnection);
149         QObject::connect(sslSocket, SIGNAL(sslErrors(QList<QSslError>)),
150                          this, SLOT(_q_sslErrors(QList<QSslError>)),
151                          Qt::DirectConnection);
152         QObject::connect(sslSocket, SIGNAL(encryptedBytesWritten(qint64)),
153                          this, SLOT(_q_encryptedBytesWritten(qint64)),
154                          Qt::DirectConnection);
155     }
156 #endif
157 }
158
159
160 void QHttpNetworkConnectionChannel::close()
161 {
162     if (socket->state() == QAbstractSocket::UnconnectedState)
163         state = QHttpNetworkConnectionChannel::IdleState;
164     else
165         state = QHttpNetworkConnectionChannel::ClosingState;
166
167     socket->close();
168 }
169
170
171 bool QHttpNetworkConnectionChannel::sendRequest()
172 {
173     if (!reply) {
174         // heh, how should that happen!
175         qWarning() << "QHttpNetworkConnectionChannel::sendRequest() called without QHttpNetworkReply";
176         state = QHttpNetworkConnectionChannel::IdleState;
177         return false;
178     }
179
180     switch (state) {
181     case QHttpNetworkConnectionChannel::IdleState: { // write the header
182         if (!ensureConnection()) {
183             // wait for the connection (and encryption) to be done
184             // sendRequest will be called again from either
185             // _q_connected or _q_encrypted
186             return false;
187         }
188         written = 0; // excluding the header
189         bytesTotal = 0;
190
191         QHttpNetworkReplyPrivate *replyPrivate = reply->d_func();
192         replyPrivate->clear();
193         replyPrivate->connection = connection;
194         replyPrivate->connectionChannel = this;
195         replyPrivate->autoDecompress = request.d->autoDecompress;
196         replyPrivate->pipeliningUsed = false;
197
198         // if the url contains authentication parameters, use the new ones
199         // both channels will use the new authentication parameters
200         if (!request.url().userInfo().isEmpty() && request.withCredentials()) {
201             QUrl url = request.url();
202             QAuthenticator &auth = authenticator;
203             if (url.userName() != auth.user()
204                 || (!url.password().isEmpty() && url.password() != auth.password())) {
205                 auth.setUser(url.userName());
206                 auth.setPassword(url.password());
207                 connection->d_func()->copyCredentials(connection->d_func()->indexOf(socket), &auth, false);
208             }
209             // clear the userinfo,  since we use the same request for resending
210             // userinfo in url can conflict with the one in the authenticator
211             url.setUserInfo(QString());
212             request.setUrl(url);
213         }
214         // Will only be false if QtWebKit is performing a cross-origin XMLHttpRequest
215         // and withCredentials has not been set to true.
216         if (request.withCredentials())
217             connection->d_func()->createAuthorization(socket, request);
218 #ifndef QT_NO_NETWORKPROXY
219         QByteArray header = QHttpNetworkRequestPrivate::header(request,
220             (connection->d_func()->networkProxy.type() != QNetworkProxy::NoProxy));
221 #else
222         QByteArray header = QHttpNetworkRequestPrivate::header(request, false);
223 #endif
224         socket->write(header);
225         // flushing is dangerous (QSslSocket calls transmit which might read or error)
226 //        socket->flush();
227         QNonContiguousByteDevice* uploadByteDevice = request.uploadByteDevice();
228         if (uploadByteDevice) {
229             // connect the signals so this function gets called again
230             QObject::connect(uploadByteDevice, SIGNAL(readyRead()),this, SLOT(_q_uploadDataReadyRead()));
231
232             bytesTotal = request.contentLength();
233
234             state = QHttpNetworkConnectionChannel::WritingState; // start writing data
235             sendRequest(); //recurse
236         } else {
237             state = QHttpNetworkConnectionChannel::WaitingState; // now wait for response
238             sendRequest(); //recurse
239         }
240
241         break;
242     }
243     case QHttpNetworkConnectionChannel::WritingState:
244     {
245         // write the data
246         QNonContiguousByteDevice* uploadByteDevice = request.uploadByteDevice();
247         if (!uploadByteDevice || bytesTotal == written) {
248             if (uploadByteDevice)
249                 emit reply->dataSendProgress(written, bytesTotal);
250             state = QHttpNetworkConnectionChannel::WaitingState; // now wait for response
251             sendRequest(); // recurse
252             break;
253         }
254
255         // only feed the QTcpSocket buffer when there is less than 32 kB in it
256         const qint64 socketBufferFill = 32*1024;
257         const qint64 socketWriteMaxSize = 16*1024;
258
259
260 #ifndef QT_NO_SSL
261         QSslSocket *sslSocket = qobject_cast<QSslSocket*>(socket);
262         // if it is really an ssl socket, check more than just bytesToWrite()
263         while ((socket->bytesToWrite() + (sslSocket ? sslSocket->encryptedBytesToWrite() : 0))
264                 <= socketBufferFill && bytesTotal != written)
265 #else
266         while (socket->bytesToWrite() <= socketBufferFill
267                && bytesTotal != written)
268 #endif
269         {
270             // get pointer to upload data
271             qint64 currentReadSize = 0;
272             qint64 desiredReadSize = qMin(socketWriteMaxSize, bytesTotal - written);
273             const char *readPointer = uploadByteDevice->readPointer(desiredReadSize, currentReadSize);
274
275             if (currentReadSize == -1) {
276                 // premature eof happened
277                 connection->d_func()->emitReplyError(socket, reply, QNetworkReply::UnknownNetworkError);
278                 return false;
279                 break;
280             } else if (readPointer == 0 || currentReadSize == 0) {
281                 // nothing to read currently, break the loop
282                 break;
283             } else {
284                 qint64 currentWriteSize = socket->write(readPointer, currentReadSize);
285                 if (currentWriteSize == -1 || currentWriteSize != currentReadSize) {
286                     // socket broke down
287                     connection->d_func()->emitReplyError(socket, reply, QNetworkReply::UnknownNetworkError);
288                     return false;
289                 } else {
290                     written += currentWriteSize;
291                     uploadByteDevice->advanceReadPointer(currentWriteSize);
292
293                     emit reply->dataSendProgress(written, bytesTotal);
294
295                     if (written == bytesTotal) {
296                         // make sure this function is called once again
297                         state = QHttpNetworkConnectionChannel::WaitingState;
298                         sendRequest();
299                         break;
300                     }
301                 }
302             }
303         }
304         break;
305     }
306
307     case QHttpNetworkConnectionChannel::WaitingState:
308     {
309         QNonContiguousByteDevice* uploadByteDevice = request.uploadByteDevice();
310         if (uploadByteDevice) {
311             QObject::disconnect(uploadByteDevice, SIGNAL(readyRead()), this, SLOT(_q_uploadDataReadyRead()));
312         }
313
314         // HTTP pipelining
315         //connection->d_func()->fillPipeline(socket);
316         //socket->flush();
317
318         // ensure we try to receive a reply in all cases, even if _q_readyRead_ hat not been called
319         // this is needed if the sends an reply before we have finished sending the request. In that
320         // case receiveReply had been called before but ignored the server reply
321         if (socket->bytesAvailable())
322             QMetaObject::invokeMethod(this, "_q_receiveReply", Qt::QueuedConnection);
323         break;
324     }
325     case QHttpNetworkConnectionChannel::ReadingState:
326         // ignore _q_bytesWritten in these states
327         // fall through
328     default:
329         break;
330     }
331     return true;
332 }
333
334
335 void QHttpNetworkConnectionChannel::_q_receiveReply()
336 {
337     Q_ASSERT(socket);
338
339     if (!reply) {
340         // heh, how should that happen!
341         qWarning() << "QHttpNetworkConnectionChannel::_q_receiveReply() called without QHttpNetworkReply,"
342                 << socket->bytesAvailable() << "bytes on socket.";
343         close();
344         return;
345     }
346
347     // only run when the QHttpNetworkConnection is not currently being destructed, e.g.
348     // this function is called from _q_disconnected which is called because
349     // of ~QHttpNetworkConnectionPrivate
350     if (!qobject_cast<QHttpNetworkConnection*>(connection)) {
351         return;
352     }
353
354     QAbstractSocket::SocketState socketState = socket->state();
355
356     // connection might be closed to signal the end of data
357     if (socketState == QAbstractSocket::UnconnectedState) {
358         if (socket->bytesAvailable() <= 0) {
359             if (reply->d_func()->state == QHttpNetworkReplyPrivate::ReadingDataState) {
360                 // finish this reply. this case happens when the server did not send a content length
361                 reply->d_func()->state = QHttpNetworkReplyPrivate::AllDoneState;
362                 allDone();
363                 return;
364             } else {
365                 handleUnexpectedEOF();
366                 return;
367             }
368         } else {
369             // socket not connected but still bytes for reading.. just continue in this function
370         }
371     }
372
373     // read loop for the response
374     qint64 bytes = 0;
375     qint64 lastBytes = bytes;
376     do {
377         lastBytes = bytes;
378
379         QHttpNetworkReplyPrivate::ReplyState state = reply->d_func()->state;
380         switch (state) {
381         case QHttpNetworkReplyPrivate::NothingDoneState: {
382             state = reply->d_func()->state = QHttpNetworkReplyPrivate::ReadingStatusState;
383             // fallthrough
384         }
385         case QHttpNetworkReplyPrivate::ReadingStatusState: {
386             qint64 statusBytes = reply->d_func()->readStatus(socket);
387             if (statusBytes == -1) {
388                 // connection broke while reading status. also handled if later _q_disconnected is called
389                 handleUnexpectedEOF();
390                 return;
391             }
392             bytes += statusBytes;
393             lastStatus = reply->d_func()->statusCode;
394             break;
395         }
396         case QHttpNetworkReplyPrivate::ReadingHeaderState: {
397             QHttpNetworkReplyPrivate *replyPrivate = reply->d_func();
398             qint64 headerBytes = replyPrivate->readHeader(socket);
399             if (headerBytes == -1) {
400                 // connection broke while reading headers. also handled if later _q_disconnected is called
401                 handleUnexpectedEOF();
402                 return;
403             }
404             bytes += headerBytes;
405             // If headers were parsed successfully now it is the ReadingDataState
406             if (replyPrivate->state == QHttpNetworkReplyPrivate::ReadingDataState) {
407                 if (replyPrivate->isCompressed() && replyPrivate->autoDecompress) {
408                     // remove the Content-Length from header
409                     replyPrivate->removeAutoDecompressHeader();
410                 } else {
411                     replyPrivate->autoDecompress = false;
412                 }
413                 if (replyPrivate->statusCode == 100) {
414                     replyPrivate->clearHttpLayerInformation();
415                     replyPrivate->state = QHttpNetworkReplyPrivate::ReadingStatusState;
416                     break; // ignore
417                 }
418                 if (replyPrivate->shouldEmitSignals())
419                     emit reply->headerChanged();
420                 // After headerChanged had been emitted
421                 // we can suddenly have a replyPrivate->userProvidedDownloadBuffer
422                 // this is handled in the ReadingDataState however
423
424                 if (!replyPrivate->expectContent()) {
425                     replyPrivate->state = QHttpNetworkReplyPrivate::AllDoneState;
426                     allDone();
427                     break;
428                 }
429             }
430             break;
431         }
432         case QHttpNetworkReplyPrivate::ReadingDataState: {
433            QHttpNetworkReplyPrivate *replyPrivate = reply->d_func();
434            if (socket->state() == QAbstractSocket::ConnectedState &&
435                replyPrivate->downstreamLimited && !replyPrivate->responseData.isEmpty() && replyPrivate->shouldEmitSignals()) {
436                // (only do the following when still connected, not when we have already been disconnected and there is still data)
437                // We already have some HTTP body data. We don't read more from the socket until
438                // this is fetched by QHttpNetworkAccessHttpBackend. If we would read more,
439                // we could not limit our read buffer usage.
440                // We only do this when shouldEmitSignals==true because our HTTP parsing
441                // always needs to parse the 401/407 replies. Therefore they don't really obey
442                // to the read buffer maximum size, but we don't care since they should be small.
443                return;
444            }
445
446            if (replyPrivate->userProvidedDownloadBuffer) {
447                // the user provided a direct buffer where we should put all our data in.
448                // this only works when we can tell the user the content length and he/she can allocate
449                // the buffer in that size.
450                // note that this call will read only from the still buffered data
451                qint64 haveRead = replyPrivate->readBodyVeryFast(socket, replyPrivate->userProvidedDownloadBuffer + replyPrivate->totalProgress);
452                if (haveRead > 0) {
453                    bytes += haveRead;
454                    replyPrivate->totalProgress += haveRead;
455                    // the user will get notified of it via progress signal
456                    emit reply->dataReadProgress(replyPrivate->totalProgress, replyPrivate->bodyLength);
457                } else if (haveRead == 0) {
458                    // Happens since this called in a loop. Currently no bytes available.
459                } else if (haveRead < 0) {
460                    connection->d_func()->emitReplyError(socket, reply, QNetworkReply::RemoteHostClosedError);
461                    break;
462                }
463            } else if (!replyPrivate->isChunked() && !replyPrivate->autoDecompress
464                  && replyPrivate->bodyLength > 0) {
465                  // bulk files like images should fulfill these properties and
466                  // we can therefore save on memory copying
467                 qint64 haveRead = replyPrivate->readBodyFast(socket, &replyPrivate->responseData);
468                 bytes += haveRead;
469                 replyPrivate->totalProgress += haveRead;
470                 if (replyPrivate->shouldEmitSignals()) {
471                     emit reply->readyRead();
472                     emit reply->dataReadProgress(replyPrivate->totalProgress, replyPrivate->bodyLength);
473                 }
474             }
475             else
476             {
477                 // use the traditional slower reading (for compressed encoding, chunked encoding,
478                 // no content-length etc)
479                 qint64 haveRead = replyPrivate->readBody(socket, &replyPrivate->responseData);
480                 if (haveRead > 0) {
481                     bytes += haveRead;
482                     replyPrivate->totalProgress += haveRead;
483                     if (replyPrivate->shouldEmitSignals()) {
484                         emit reply->readyRead();
485                         emit reply->dataReadProgress(replyPrivate->totalProgress, replyPrivate->bodyLength);
486                     }
487                 } else if (haveRead == -1) {
488                     // Some error occured
489                     connection->d_func()->emitReplyError(socket, reply, QNetworkReply::ProtocolFailure);
490                     break;
491                 }
492             }
493             // still in ReadingDataState? This function will be called again by the socket's readyRead
494             if (replyPrivate->state == QHttpNetworkReplyPrivate::ReadingDataState)
495                 break;
496
497             // everything done, fall through
498             }
499       case QHttpNetworkReplyPrivate::AllDoneState:
500             allDone();
501             break;
502         default:
503             break;
504         }
505     } while (bytes != lastBytes && reply);
506 }
507
508 // called when unexpectedly reading a -1 or when data is expected but socket is closed
509 void QHttpNetworkConnectionChannel::handleUnexpectedEOF()
510 {
511     Q_ASSERT(reply);
512     if (reconnectAttempts <= 0) {
513         // too many errors reading/receiving/parsing the status, close the socket and emit error
514         requeueCurrentlyPipelinedRequests();
515         close();
516         reply->d_func()->errorString = connection->d_func()->errorDetail(QNetworkReply::RemoteHostClosedError, socket);
517         emit reply->finishedWithError(QNetworkReply::RemoteHostClosedError, reply->d_func()->errorString);
518         QMetaObject::invokeMethod(connection, "_q_startNextRequest", Qt::QueuedConnection);
519     } else {
520         reconnectAttempts--;
521         reply->d_func()->clear();
522         reply->d_func()->connection = connection;
523         reply->d_func()->connectionChannel = this;
524         closeAndResendCurrentRequest();
525     }
526 }
527
528 bool QHttpNetworkConnectionChannel::ensureConnection()
529 {
530     QAbstractSocket::SocketState socketState = socket->state();
531
532     // resend this request after we receive the disconnected signal
533     if (socketState == QAbstractSocket::ClosingState) {
534         if (reply)
535             resendCurrent = true;
536         return false;
537     }
538
539     // already trying to connect?
540     if (socketState == QAbstractSocket::HostLookupState ||
541         socketState == QAbstractSocket::ConnectingState) {
542         return false;
543     }
544
545     // make sure that this socket is in a connected state, if not initiate
546     // connection to the host.
547     if (socketState != QAbstractSocket::ConnectedState) {
548         // connect to the host if not already connected.
549         state = QHttpNetworkConnectionChannel::ConnectingState;
550         pendingEncrypt = ssl;
551
552         // reset state
553         pipeliningSupported = PipeliningSupportUnknown;
554         authenticationCredentialsSent = false;
555         proxyCredentialsSent = false;
556         authenticator.detach();
557         QAuthenticatorPrivate *priv = QAuthenticatorPrivate::getPrivate(authenticator);
558         priv->hasFailed = false;
559         proxyAuthenticator.detach();
560         priv = QAuthenticatorPrivate::getPrivate(proxyAuthenticator);
561         priv->hasFailed = false;
562
563         // This workaround is needed since we use QAuthenticator for NTLM authentication. The "phase == Done"
564         // is the usual criteria for emitting authentication signals. The "phase" is set to "Done" when the
565         // last header for Authorization is generated by the QAuthenticator. Basic & Digest logic does not
566         // check the "phase" for generating the Authorization header. NTLM authentication is a two stage
567         // process & needs the "phase". To make sure the QAuthenticator uses the current username/password
568         // the phase is reset to Start.
569         priv = QAuthenticatorPrivate::getPrivate(authenticator);
570         if (priv && priv->phase == QAuthenticatorPrivate::Done)
571             priv->phase = QAuthenticatorPrivate::Start;
572         priv = QAuthenticatorPrivate::getPrivate(proxyAuthenticator);
573         if (priv && priv->phase == QAuthenticatorPrivate::Done)
574             priv->phase = QAuthenticatorPrivate::Start;
575
576         QString connectHost = connection->d_func()->hostName;
577         qint16 connectPort = connection->d_func()->port;
578
579 #ifndef QT_NO_NETWORKPROXY
580         // HTTPS always use transparent proxy.
581         if (connection->d_func()->networkProxy.type() != QNetworkProxy::NoProxy && !ssl) {
582             connectHost = connection->d_func()->networkProxy.hostName();
583             connectPort = connection->d_func()->networkProxy.port();
584         }
585         if (socket->proxy().type() == QNetworkProxy::HttpProxy) {
586             // Make user-agent field available to HTTP proxy socket engine (QTBUG-17223)
587             QByteArray value;
588             // ensureConnection is called before any request has been assigned, but can also be called again if reconnecting
589             if (request.url().isEmpty())
590                 value = connection->d_func()->predictNextRequest().headerField("user-agent");
591             else
592                 value = request.headerField("user-agent");
593             if (!value.isEmpty()) {
594                 QNetworkProxy proxy(socket->proxy());
595                 proxy.setRawHeader("User-Agent", value); //detaches
596                 socket->setProxy(proxy);
597             }
598         }
599 #endif
600         if (ssl) {
601 #ifndef QT_NO_SSL
602             QSslSocket *sslSocket = qobject_cast<QSslSocket*>(socket);
603             sslSocket->connectToHostEncrypted(connectHost, connectPort, QIODevice::ReadWrite, networkLayerPreference);
604             if (ignoreAllSslErrors)
605                 sslSocket->ignoreSslErrors();
606             sslSocket->ignoreSslErrors(ignoreSslErrorsList);
607
608             // limit the socket read buffer size. we will read everything into
609             // the QHttpNetworkReply anyway, so let's grow only that and not
610             // here and there.
611             socket->setReadBufferSize(64*1024);
612 #else
613             // Need to dequeue the request so that we can emit the error.
614             if (!reply)
615                 connection->d_func()->dequeueRequest(socket);
616             connection->d_func()->emitReplyError(socket, reply, QNetworkReply::ProtocolUnknownError);
617 #endif
618         } else {
619             // In case of no proxy we can use the Unbuffered QTcpSocket
620 #ifndef QT_NO_NETWORKPROXY
621             if (connection->d_func()->networkProxy.type() == QNetworkProxy::NoProxy
622                     && connection->cacheProxy().type() == QNetworkProxy::NoProxy
623                     && connection->transparentProxy().type() == QNetworkProxy::NoProxy) {
624 #endif
625                 socket->connectToHost(connectHost, connectPort, QIODevice::ReadWrite | QIODevice::Unbuffered, networkLayerPreference);
626                 // For an Unbuffered QTcpSocket, the read buffer size has a special meaning.
627                 socket->setReadBufferSize(1*1024);
628 #ifndef QT_NO_NETWORKPROXY
629             } else {
630                 socket->connectToHost(connectHost, connectPort, QIODevice::ReadWrite, networkLayerPreference);
631
632                 // limit the socket read buffer size. we will read everything into
633                 // the QHttpNetworkReply anyway, so let's grow only that and not
634                 // here and there.
635                 socket->setReadBufferSize(64*1024);
636             }
637 #endif
638         }
639         return false;
640     }
641     return true;
642 }
643
644 void QHttpNetworkConnectionChannel::allDone()
645 {
646     Q_ASSERT(reply);
647
648     if (!reply) {
649         qWarning() << "QHttpNetworkConnectionChannel::allDone() called without reply. Please report at http://bugreports.qt.nokia.com/";
650         return;
651     }
652
653     // while handling 401 & 407, we might reset the status code, so save this.
654     bool emitFinished = reply->d_func()->shouldEmitSignals();
655     bool connectionCloseEnabled = reply->d_func()->isConnectionCloseEnabled();
656     detectPipeliningSupport();
657
658     handleStatus();
659     // handleStatus() might have removed the reply because it already called connection->emitReplyError()
660
661     // queue the finished signal, this is required since we might send new requests from
662     // slot connected to it. The socket will not fire readyRead signal, if we are already
663     // in the slot connected to readyRead
664     if (reply && emitFinished)
665         QMetaObject::invokeMethod(reply, "finished", Qt::QueuedConnection);
666
667
668     // reset the reconnection attempts after we receive a complete reply.
669     // in case of failures, each channel will attempt two reconnects before emitting error.
670     reconnectAttempts = 2;
671
672     // now the channel can be seen as free/idle again, all signal emissions for the reply have been done
673     if (state != QHttpNetworkConnectionChannel::ClosingState)
674         state = QHttpNetworkConnectionChannel::IdleState;
675
676     // if it does not need to be sent again we can set it to 0
677     // the previous code did not do that and we had problems with accidental re-sending of a
678     // finished request.
679     // Note that this may trigger a segfault at some other point. But then we can fix the underlying
680     // problem.
681     if (!resendCurrent) {
682         request = QHttpNetworkRequest();
683         reply = 0;
684     }
685
686     // move next from pipeline to current request
687     if (!alreadyPipelinedRequests.isEmpty()) {
688         if (resendCurrent || connectionCloseEnabled || socket->state() != QAbstractSocket::ConnectedState) {
689             // move the pipelined ones back to the main queue
690             requeueCurrentlyPipelinedRequests();
691             close();
692         } else {
693             // there were requests pipelined in and we can continue
694             HttpMessagePair messagePair = alreadyPipelinedRequests.takeFirst();
695
696             request = messagePair.first;
697             reply = messagePair.second;
698             state = QHttpNetworkConnectionChannel::ReadingState;
699             resendCurrent = false;
700
701             written = 0; // message body, excluding the header, irrelevant here
702             bytesTotal = 0; // message body total, excluding the header, irrelevant here
703
704             // pipeline even more
705             connection->d_func()->fillPipeline(socket);
706
707             // continue reading
708             //_q_receiveReply();
709             // this was wrong, allDone gets called from that function anyway.
710         }
711     } else if (alreadyPipelinedRequests.isEmpty() && socket->bytesAvailable() > 0) {
712         // this is weird. we had nothing pipelined but still bytes available. better close it.
713         //if (socket->bytesAvailable() > 0)
714         //    close();
715         //
716         // FIXME
717         // We do not close it anymore now, but should introduce this again after having fixed
718         // the chunked decoder in QHttpNetworkReply to read the whitespace after the last chunk.
719         // (Currently this is worked around by readStatus in the QHttpNetworkReply ignoring
720         // leading whitespace.
721         QMetaObject::invokeMethod(connection, "_q_startNextRequest", Qt::QueuedConnection);
722     } else if (alreadyPipelinedRequests.isEmpty()) {
723         if (connectionCloseEnabled)
724             if (socket->state() != QAbstractSocket::UnconnectedState)
725                 close();
726         if (qobject_cast<QHttpNetworkConnection*>(connection))
727             QMetaObject::invokeMethod(connection, "_q_startNextRequest", Qt::QueuedConnection);
728     }
729 }
730
731 void QHttpNetworkConnectionChannel::detectPipeliningSupport()
732 {
733     Q_ASSERT(reply);
734     // detect HTTP Pipelining support
735     QByteArray serverHeaderField;
736     if (
737             // check for HTTP/1.1
738             (reply->d_func()->majorVersion == 1 && reply->d_func()->minorVersion == 1)
739             // check for not having connection close
740             && (!reply->d_func()->isConnectionCloseEnabled())
741             // check if it is still connected
742             && (socket->state() == QAbstractSocket::ConnectedState)
743             // check for broken servers in server reply header
744             // this is adapted from http://mxr.mozilla.org/firefox/ident?i=SupportsPipelining
745             && (serverHeaderField = reply->headerField("Server"), !serverHeaderField.contains("Microsoft-IIS/4."))
746             && (!serverHeaderField.contains("Microsoft-IIS/5."))
747             && (!serverHeaderField.contains("Netscape-Enterprise/3."))
748             // this is adpoted from the knowledge of the Nokia 7.x browser team (DEF143319)
749             && (!serverHeaderField.contains("WebLogic"))
750             && (!serverHeaderField.startsWith("Rocket")) // a Python Web Server, see Web2py.com
751             ) {
752         pipeliningSupported = QHttpNetworkConnectionChannel::PipeliningProbablySupported;
753     } else {
754         pipeliningSupported = QHttpNetworkConnectionChannel::PipeliningSupportUnknown;
755     }
756 }
757
758 // called when the connection broke and we need to queue some pipelined requests again
759 void QHttpNetworkConnectionChannel::requeueCurrentlyPipelinedRequests()
760 {
761     for (int i = 0; i < alreadyPipelinedRequests.length(); i++)
762         connection->d_func()->requeueRequest(alreadyPipelinedRequests.at(i));
763     alreadyPipelinedRequests.clear();
764
765     // only run when the QHttpNetworkConnection is not currently being destructed, e.g.
766     // this function is called from _q_disconnected which is called because
767     // of ~QHttpNetworkConnectionPrivate
768     if (qobject_cast<QHttpNetworkConnection*>(connection))
769         QMetaObject::invokeMethod(connection, "_q_startNextRequest", Qt::QueuedConnection);
770 }
771
772 void QHttpNetworkConnectionChannel::handleStatus()
773 {
774     Q_ASSERT(socket);
775     Q_ASSERT(reply);
776
777     int statusCode = reply->statusCode();
778     bool resend = false;
779
780     switch (statusCode) {
781     case 401: // auth required
782     case 407: // proxy auth required
783         if (connection->d_func()->handleAuthenticateChallenge(socket, reply, (statusCode == 407), resend)) {
784             if (resend) {
785                 if (!resetUploadData())
786                     break;
787
788                 reply->d_func()->eraseData();
789
790                 if (alreadyPipelinedRequests.isEmpty()) {
791                     // this does a re-send without closing the connection
792                     resendCurrent = true;
793                     QMetaObject::invokeMethod(connection, "_q_startNextRequest", Qt::QueuedConnection);
794                 } else {
795                     // we had requests pipelined.. better close the connection in closeAndResendCurrentRequest
796                     closeAndResendCurrentRequest();
797                     QMetaObject::invokeMethod(connection, "_q_startNextRequest", Qt::QueuedConnection);
798                 }
799             } else {
800                 //authentication cancelled, close the channel.
801                 close();
802             }
803         } else {
804             emit reply->headerChanged();
805             emit reply->readyRead();
806             QNetworkReply::NetworkError errorCode = (statusCode == 407)
807                 ? QNetworkReply::ProxyAuthenticationRequiredError
808                 : QNetworkReply::AuthenticationRequiredError;
809             reply->d_func()->errorString = connection->d_func()->errorDetail(errorCode, socket);
810             emit reply->finishedWithError(errorCode, reply->d_func()->errorString);
811         }
812         break;
813     default:
814         if (qobject_cast<QHttpNetworkConnection*>(connection))
815             QMetaObject::invokeMethod(connection, "_q_startNextRequest", Qt::QueuedConnection);
816     }
817 }
818
819 bool QHttpNetworkConnectionChannel::resetUploadData()
820 {
821     if (!reply) {
822         //this happens if server closes connection while QHttpNetworkConnectionPrivate::_q_startNextRequest is pending
823         return false;
824     }
825     QNonContiguousByteDevice* uploadByteDevice = request.uploadByteDevice();
826     if (!uploadByteDevice)
827         return true;
828
829     if (uploadByteDevice->reset()) {
830         written = 0;
831         return true;
832     } else {
833         connection->d_func()->emitReplyError(socket, reply, QNetworkReply::ContentReSendError);
834         return false;
835     }
836 }
837
838
839 void QHttpNetworkConnectionChannel::pipelineInto(HttpMessagePair &pair)
840 {
841     // this is only called for simple GET
842
843     QHttpNetworkRequest &request = pair.first;
844     QHttpNetworkReply *reply = pair.second;
845     reply->d_func()->clear();
846     reply->d_func()->connection = connection;
847     reply->d_func()->connectionChannel = this;
848     reply->d_func()->autoDecompress = request.d->autoDecompress;
849     reply->d_func()->pipeliningUsed = true;
850
851 #ifndef QT_NO_NETWORKPROXY
852     pipeline.append(QHttpNetworkRequestPrivate::header(request,
853                                                            (connection->d_func()->networkProxy.type() != QNetworkProxy::NoProxy)));
854 #else
855     pipeline.append(QHttpNetworkRequestPrivate::header(request, false));
856 #endif
857
858     alreadyPipelinedRequests.append(pair);
859
860     // pipelineFlush() needs to be called at some point afterwards
861 }
862
863 void QHttpNetworkConnectionChannel::pipelineFlush()
864 {
865     if (pipeline.isEmpty())
866         return;
867
868     // The goal of this is so that we have everything in one TCP packet.
869     // For the Unbuffered QTcpSocket this is manually needed, the buffered
870     // QTcpSocket does it automatically.
871     // Also, sometimes the OS does it for us (Nagle's algorithm) but that
872     // happens only sometimes.
873     socket->write(pipeline);
874     pipeline.clear();
875 }
876
877
878 void QHttpNetworkConnectionChannel::closeAndResendCurrentRequest()
879 {
880     requeueCurrentlyPipelinedRequests();
881     close();
882     if (reply)
883         resendCurrent = true;
884     if (qobject_cast<QHttpNetworkConnection*>(connection))
885         QMetaObject::invokeMethod(connection, "_q_startNextRequest", Qt::QueuedConnection);
886 }
887
888 bool QHttpNetworkConnectionChannel::isSocketBusy() const
889 {
890     return (state & QHttpNetworkConnectionChannel::BusyState);
891 }
892
893 bool QHttpNetworkConnectionChannel::isSocketWriting() const
894 {
895     return (state & QHttpNetworkConnectionChannel::WritingState);
896 }
897
898 bool QHttpNetworkConnectionChannel::isSocketWaiting() const
899 {
900     return (state & QHttpNetworkConnectionChannel::WaitingState);
901 }
902
903 bool QHttpNetworkConnectionChannel::isSocketReading() const
904 {
905     return (state & QHttpNetworkConnectionChannel::ReadingState);
906 }
907
908 //private slots
909 void QHttpNetworkConnectionChannel::_q_readyRead()
910 {
911     if (socket->state() == QAbstractSocket::ConnectedState && socket->bytesAvailable() == 0) {
912         // We got a readyRead but no bytes are available..
913         // This happens for the Unbuffered QTcpSocket
914         // Also check if socket is in ConnectedState since
915         // this function may also be invoked via the event loop.
916         char c;
917         qint64  ret = socket->peek(&c, 1);
918         if (ret < 0) {
919             _q_error(socket->error());
920             // We still need to handle the reply so it emits its signals etc.
921             if (reply)
922                 _q_receiveReply();
923             return;
924         }
925     }
926
927     if (isSocketWaiting() || isSocketReading()) {
928         state = QHttpNetworkConnectionChannel::ReadingState;
929         if (reply)
930             _q_receiveReply();
931     }
932 }
933
934 void QHttpNetworkConnectionChannel::_q_bytesWritten(qint64 bytes)
935 {
936     Q_UNUSED(bytes);
937     // bytes have been written to the socket. write even more of them :)
938     if (isSocketWriting())
939         sendRequest();
940     // otherwise we do nothing
941 }
942
943 void QHttpNetworkConnectionChannel::_q_disconnected()
944 {
945     if (state == QHttpNetworkConnectionChannel::ClosingState) {
946         state = QHttpNetworkConnectionChannel::IdleState;
947         QMetaObject::invokeMethod(connection, "_q_startNextRequest", Qt::QueuedConnection);
948         return;
949     }
950
951     // read the available data before closing
952     if (isSocketWaiting() || isSocketReading()) {
953         if (reply) {
954             state = QHttpNetworkConnectionChannel::ReadingState;
955             _q_receiveReply();
956         }
957     } else if (state == QHttpNetworkConnectionChannel::IdleState && resendCurrent) {
958         // re-sending request because the socket was in ClosingState
959         QMetaObject::invokeMethod(connection, "_q_startNextRequest", Qt::QueuedConnection);
960     }
961     state = QHttpNetworkConnectionChannel::IdleState;
962
963     requeueCurrentlyPipelinedRequests();
964     close();
965 }
966
967
968 void QHttpNetworkConnectionChannel::_q_connected()
969 {
970     // For the Happy Eyeballs we need to check if this is the first channel to connect.
971     if (!pendingEncrypt) {
972         if (connection->d_func()->networkLayerState == QHttpNetworkConnectionPrivate::InProgress) {
973             if (connection->d_func()->delayedConnectionTimer.isActive())
974                 connection->d_func()->delayedConnectionTimer.stop();
975             if (networkLayerPreference == QAbstractSocket::IPv4Protocol)
976                 connection->d_func()->networkLayerState = QHttpNetworkConnectionPrivate::IPv4;
977             else if (networkLayerPreference == QAbstractSocket::IPv6Protocol)
978                 connection->d_func()->networkLayerState = QHttpNetworkConnectionPrivate::IPv6;
979             else {
980                 if (socket->peerAddress().protocol() == QAbstractSocket::IPv4Protocol)
981                     connection->d_func()->networkLayerState = QHttpNetworkConnectionPrivate::IPv4;
982                 else
983                     connection->d_func()->networkLayerState = QHttpNetworkConnectionPrivate::IPv6;
984             }
985         } else {
986             if (((connection->d_func()->networkLayerState == QHttpNetworkConnectionPrivate::IPv4) && (networkLayerPreference != QAbstractSocket::IPv4Protocol))
987                 || ((connection->d_func()->networkLayerState == QHttpNetworkConnectionPrivate::IPv6) && (networkLayerPreference != QAbstractSocket::IPv6Protocol))) {
988                 close();
989                 // This is the second connection so it has to be closed and we can schedule it for another request.
990                 QMetaObject::invokeMethod(connection, "_q_startNextRequest", Qt::QueuedConnection);
991                 return;
992             }
993             //The connections networkLayerState had already been decided.
994         }
995     }
996
997     // improve performance since we get the request sent by the kernel ASAP
998     //socket->setSocketOption(QAbstractSocket::LowDelayOption, 1);
999     // We have this commented out now. It did not have the effect we wanted. If we want to
1000     // do this properly, Qt has to combine multiple HTTP requests into one buffer
1001     // and send this to the kernel in one syscall and then the kernel immediately sends
1002     // it as one TCP packet because of TCP_NODELAY.
1003     // However, this code is currently not in Qt, so we rely on the kernel combining
1004     // the requests into one TCP packet.
1005
1006     // not sure yet if it helps, but it makes sense
1007     socket->setSocketOption(QAbstractSocket::KeepAliveOption, 1);
1008
1009     pipeliningSupported = QHttpNetworkConnectionChannel::PipeliningSupportUnknown;
1010
1011     // ### FIXME: if the server closes the connection unexpectedly, we shouldn't send the same broken request again!
1012     //channels[i].reconnectAttempts = 2;
1013     if (!pendingEncrypt) {
1014         state = QHttpNetworkConnectionChannel::IdleState;
1015         if (!reply)
1016             connection->d_func()->dequeueRequest(socket);
1017         if (reply)
1018             sendRequest();
1019     }
1020 }
1021
1022
1023 void QHttpNetworkConnectionChannel::_q_error(QAbstractSocket::SocketError socketError)
1024 {
1025     if (!socket)
1026         return;
1027     QNetworkReply::NetworkError errorCode = QNetworkReply::UnknownNetworkError;
1028
1029     switch (socketError) {
1030     case QAbstractSocket::HostNotFoundError:
1031         errorCode = QNetworkReply::HostNotFoundError;
1032         break;
1033     case QAbstractSocket::ConnectionRefusedError:
1034         errorCode = QNetworkReply::ConnectionRefusedError;
1035         break;
1036     case QAbstractSocket::RemoteHostClosedError:
1037         // try to reconnect/resend before sending an error.
1038         // while "Reading" the _q_disconnected() will handle this.
1039         if (state != QHttpNetworkConnectionChannel::IdleState && state != QHttpNetworkConnectionChannel::ReadingState) {
1040             if (reconnectAttempts-- > 0) {
1041                 closeAndResendCurrentRequest();
1042                 return;
1043             } else {
1044                 errorCode = QNetworkReply::RemoteHostClosedError;
1045             }
1046         } else if (state == QHttpNetworkConnectionChannel::ReadingState) {
1047             if (!reply->d_func()->expectContent()) {
1048                 // No content expected, this is a valid way to have the connection closed by the server
1049                 return;
1050             }
1051             if (reply->contentLength() == -1 && !reply->d_func()->isChunked()) {
1052                 // There was no content-length header and it's not chunked encoding,
1053                 // so this is a valid way to have the connection closed by the server
1054                 return;
1055             }
1056             // ok, we got a disconnect even though we did not expect it
1057             errorCode = QNetworkReply::RemoteHostClosedError;
1058         } else {
1059             errorCode = QNetworkReply::RemoteHostClosedError;
1060         }
1061         break;
1062     case QAbstractSocket::SocketTimeoutError:
1063         // try to reconnect/resend before sending an error.
1064         if (state == QHttpNetworkConnectionChannel::WritingState && (reconnectAttempts-- > 0)) {
1065             closeAndResendCurrentRequest();
1066             return;
1067         }
1068         errorCode = QNetworkReply::TimeoutError;
1069         break;
1070     case QAbstractSocket::ProxyAuthenticationRequiredError:
1071         errorCode = QNetworkReply::ProxyAuthenticationRequiredError;
1072         break;
1073     case QAbstractSocket::SslHandshakeFailedError:
1074         errorCode = QNetworkReply::SslHandshakeFailedError;
1075         break;
1076     default:
1077         // all other errors are treated as NetworkError
1078         errorCode = QNetworkReply::UnknownNetworkError;
1079         break;
1080     }
1081     QPointer<QHttpNetworkConnection> that = connection;
1082     QString errorString = connection->d_func()->errorDetail(errorCode, socket, socket->errorString());
1083
1084     // In the InProgress state the channel should not emit the error.
1085     // This will instead be handled by the connection.
1086     if (!connection->d_func()->shouldEmitChannelError(socket))
1087         return;
1088
1089     // Need to dequeu the request so that we can emit the error.
1090     if (!reply)
1091         connection->d_func()->dequeueRequest(socket);
1092     if (reply) {
1093         reply->d_func()->errorString = errorString;
1094         emit reply->finishedWithError(errorCode, errorString);
1095         reply = 0;
1096     }
1097     // send the next request
1098     QMetaObject::invokeMethod(that, "_q_startNextRequest", Qt::QueuedConnection);
1099
1100     if (that) //signal emission triggered event loop
1101         close();
1102 }
1103
1104 #ifndef QT_NO_NETWORKPROXY
1105 void QHttpNetworkConnectionChannel::_q_proxyAuthenticationRequired(const QNetworkProxy &proxy, QAuthenticator* auth)
1106 {
1107     // Need to dequeue the request before we can emit the error.
1108     if (!reply)
1109         connection->d_func()->dequeueRequest(socket);
1110     if (reply)
1111         connection->d_func()->emitProxyAuthenticationRequired(this, proxy, auth);
1112 }
1113 #endif
1114
1115 void QHttpNetworkConnectionChannel::_q_uploadDataReadyRead()
1116 {
1117     sendRequest();
1118 }
1119
1120 #ifndef QT_NO_SSL
1121 void QHttpNetworkConnectionChannel::_q_encrypted()
1122 {
1123     if (!socket)
1124         return; // ### error
1125     state = QHttpNetworkConnectionChannel::IdleState;
1126     pendingEncrypt = false;
1127     if (!reply)
1128         connection->d_func()->dequeueRequest(socket);
1129     if (reply)
1130         sendRequest();
1131 }
1132
1133 void QHttpNetworkConnectionChannel::_q_sslErrors(const QList<QSslError> &errors)
1134 {
1135     if (!socket)
1136         return;
1137     //QNetworkReply::NetworkError errorCode = QNetworkReply::ProtocolFailure;
1138     // Also pause the connection because socket notifiers may fire while an user
1139     // dialog is displaying
1140     connection->d_func()->pauseConnection();
1141     if (pendingEncrypt && !reply)
1142         connection->d_func()->dequeueRequest(socket);
1143     if (reply)
1144         emit reply->sslErrors(errors);
1145     connection->d_func()->resumeConnection();
1146 }
1147
1148 void QHttpNetworkConnectionChannel::_q_encryptedBytesWritten(qint64 bytes)
1149 {
1150     Q_UNUSED(bytes);
1151     // bytes have been written to the socket. write even more of them :)
1152     if (isSocketWriting())
1153         sendRequest();
1154     // otherwise we do nothing
1155 }
1156
1157 #endif
1158
1159 void QHttpNetworkConnectionChannel::setConnection(QHttpNetworkConnection *c)
1160 {
1161     // Inlining this function in the header leads to compiler error on
1162     // release-armv5, on at least timebox 9.2 and 10.1.
1163     connection = c;
1164 }
1165
1166 QT_END_NAMESPACE
1167
1168 #include "moc_qhttpnetworkconnectionchannel_p.cpp"
1169
1170 #endif // QT_NO_HTTP