qhttpnetworkconnectionchannel.cpp

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

Generated by Squish Coco Non-Commercial 4.3.0-BETA-master-30-08-2018-4cb69e9