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 "qhttp2configuration.h"
44#include "private/qnoncontiguousbytedevice_p.h"
45
46#include <qpair.h>
47#include <qdebug.h>
48
49#include <private/qhttp2protocolhandler_p.h>
50#include <private/qhttpprotocolhandler_p.h>
51#include <private/http2protocol_p.h>
52
53#ifndef QT_NO_SSL
54# include <private/qsslsocket_p.h>
55# include <QtNetwork/qsslkey.h>
56# include <QtNetwork/qsslcipher.h>
57#endif
58
59#include "private/qnetconmonitor_p.h"
60
61QT_BEGIN_NAMESPACE
62
63namespace
64{
65
66class ProtocolHandlerDeleter : public QObject
67{
68public:
69 explicit ProtocolHandlerDeleter(QAbstractProtocolHandler *h) : handler(h) {}
70 ~ProtocolHandlerDeleter() { delete handler; }
71private:
72 QAbstractProtocolHandler *handler = nullptr;
73};
74
75}
76
77// TODO: Put channel specific stuff here so it does not polute qhttpnetworkconnection.cpp
78
79// Because in-flight when sending a request, the server might close our connection (because the persistent HTTP
80// connection times out)
81// We use 3 because we can get a _q_error 3 times depending on the timing:
82static const int reconnectAttemptsDefault = 3;
83
84QHttpNetworkConnectionChannel::QHttpNetworkConnectionChannel()
85 : socket(nullptr)
86 , ssl(false)
87 , isInitialized(false)
88 , state(IdleState)
89 , reply(nullptr)
90 , written(0)
91 , bytesTotal(0)
92 , resendCurrent(false)
93 , lastStatus(0)
94 , pendingEncrypt(false)
95 , reconnectAttempts(reconnectAttemptsDefault)
96 , authMethod(QAuthenticatorPrivate::None)
97 , proxyAuthMethod(QAuthenticatorPrivate::None)
98 , authenticationCredentialsSent(false)
99 , proxyCredentialsSent(false)
100 , protocolHandler(nullptr)
101#ifndef QT_NO_SSL
102 , ignoreAllSslErrors(false)
103#endif
104 , pipeliningSupported(PipeliningSupportUnknown)
105 , networkLayerPreference(QAbstractSocket::AnyIPProtocol)
106 , connection(nullptr)
107{
108 // Inlining this function in the header leads to compiler error on
109 // release-armv5, on at least timebox 9.2 and 10.1.
110}
111
112void QHttpNetworkConnectionChannel::init()
113{
114#ifndef QT_NO_SSL
115 if (connection->d_func()->encrypt)
116 socket = new QSslSocket;
117 else
118 socket = new QTcpSocket;
119#else
120 socket = new QTcpSocket;
121#endif
122#ifndef QT_NO_NETWORKPROXY
123 // Set by QNAM anyway, but let's be safe here
124 socket->setProxy(QNetworkProxy::NoProxy);
125#endif
126
127 // After some back and forth in all the last years, this is now a DirectConnection because otherwise
128 // the state inside the *Socket classes gets messed up, also in conjunction with the socket notifiers
129 // which behave slightly differently on Windows vs Linux
130 QObject::connect(socket, SIGNAL(bytesWritten(qint64)),
131 this, SLOT(_q_bytesWritten(qint64)),
132 Qt::DirectConnection);
133 QObject::connect(socket, SIGNAL(connected()),
134 this, SLOT(_q_connected()),
135 Qt::DirectConnection);
136 QObject::connect(socket, SIGNAL(readyRead()),
137 this, SLOT(_q_readyRead()),
138 Qt::DirectConnection);
139
140 // The disconnected() and error() signals may already come
141 // while calling connectToHost().
142 // In case of a cached hostname or an IP this
143 // will then emit a signal to the user of QNetworkReply
144 // but cannot be caught because the user did not have a chance yet
145 // to connect to QNetworkReply's signals.
146 qRegisterMetaType<QAbstractSocket::SocketError>();
147 QObject::connect(socket, SIGNAL(disconnected()),
148 this, SLOT(_q_disconnected()),
149 Qt::DirectConnection);
150 QObject::connect(socket, SIGNAL(errorOccurred(QAbstractSocket::SocketError)),
151 this, SLOT(_q_error(QAbstractSocket::SocketError)),
152 Qt::DirectConnection);
153
154
155#ifndef QT_NO_NETWORKPROXY
156 QObject::connect(socket, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)),
157 this, SLOT(_q_proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)),
158 Qt::DirectConnection);
159#endif
160
161#ifndef QT_NO_SSL
162 QSslSocket *sslSocket = qobject_cast<QSslSocket*>(socket);
163 if (sslSocket) {
164 // won't be a sslSocket if encrypt is false
165 QObject::connect(sslSocket, SIGNAL(encrypted()),
166 this, SLOT(_q_encrypted()),
167 Qt::DirectConnection);
168 QObject::connect(sslSocket, SIGNAL(sslErrors(QList<QSslError>)),
169 this, SLOT(_q_sslErrors(QList<QSslError>)),
170 Qt::DirectConnection);
171 QObject::connect(sslSocket, SIGNAL(preSharedKeyAuthenticationRequired(QSslPreSharedKeyAuthenticator*)),
172 this, SLOT(_q_preSharedKeyAuthenticationRequired(QSslPreSharedKeyAuthenticator*)),
173 Qt::DirectConnection);
174 QObject::connect(sslSocket, SIGNAL(encryptedBytesWritten(qint64)),
175 this, SLOT(_q_encryptedBytesWritten(qint64)),
176 Qt::DirectConnection);
177
178 if (ignoreAllSslErrors)
179 sslSocket->ignoreSslErrors();
180
181 if (!ignoreSslErrorsList.isEmpty())
182 sslSocket->ignoreSslErrors(ignoreSslErrorsList);
183
184 if (sslConfiguration.data() && !sslConfiguration->isNull())
185 sslSocket->setSslConfiguration(*sslConfiguration);
186 } else {
187#endif // !QT_NO_SSL
188 if (connection->connectionType() != QHttpNetworkConnection::ConnectionTypeHTTP2)
189 protocolHandler.reset(new QHttpProtocolHandler(this));
190#ifndef QT_NO_SSL
191 }
192#endif
193
194#ifndef QT_NO_NETWORKPROXY
195 if (proxy.type() != QNetworkProxy::NoProxy)
196 socket->setProxy(proxy);
197#endif
198 isInitialized = true;
199}
200
201
202void QHttpNetworkConnectionChannel::close()
203{
204 if (state == QHttpNetworkConnectionChannel::ClosingState)
205 return;
206
207 if (!socket)
208 state = QHttpNetworkConnectionChannel::IdleState;
209 else if (socket->state() == QAbstractSocket::UnconnectedState)
210 state = QHttpNetworkConnectionChannel::IdleState;
211 else
212 state = QHttpNetworkConnectionChannel::ClosingState;
213
214 // pendingEncrypt must only be true in between connected and encrypted states
215 pendingEncrypt = false;
216
217 if (socket) {
218 // socket can be 0 since the host lookup is done from qhttpnetworkconnection.cpp while
219 // there is no socket yet.
220 socket->close();
221 }
222}
223
224
225void QHttpNetworkConnectionChannel::abort()
226{
227 if (!socket)
228 state = QHttpNetworkConnectionChannel::IdleState;
229 else if (socket->state() == QAbstractSocket::UnconnectedState)
230 state = QHttpNetworkConnectionChannel::IdleState;
231 else
232 state = QHttpNetworkConnectionChannel::ClosingState;
233
234 // pendingEncrypt must only be true in between connected and encrypted states
235 pendingEncrypt = false;
236
237 if (socket) {
238 // socket can be 0 since the host lookup is done from qhttpnetworkconnection.cpp while
239 // there is no socket yet.
240 socket->abort();
241 }
242}
243
244
245bool QHttpNetworkConnectionChannel::sendRequest()
246{
247 Q_ASSERT(!protocolHandler.isNull());
248 return protocolHandler->sendRequest();
249}
250
251/*
252 * Invoke "protocolHandler->sendRequest" using a queued connection.
253 * It's used to return to the event loop before invoking sendRequest when
254 * there's a very real chance that the request could have been aborted
255 * (i.e. after having emitted 'encrypted').
256 */
257void QHttpNetworkConnectionChannel::sendRequestDelayed()
258{
259 QMetaObject::invokeMethod(this, [this] {
260 Q_ASSERT(!protocolHandler.isNull());
261 if (reply)
262 protocolHandler->sendRequest();
263 }, Qt::ConnectionType::QueuedConnection);
264}
265
266void QHttpNetworkConnectionChannel::_q_receiveReply()
267{
268 Q_ASSERT(!protocolHandler.isNull());
269 protocolHandler->_q_receiveReply();
270}
271
272void QHttpNetworkConnectionChannel::_q_readyRead()
273{
274 Q_ASSERT(!protocolHandler.isNull());
275 protocolHandler->_q_readyRead();
276}
277
278// called when unexpectedly reading a -1 or when data is expected but socket is closed
279void QHttpNetworkConnectionChannel::handleUnexpectedEOF()
280{
281 Q_ASSERT(reply);
282 if (reconnectAttempts <= 0) {
283 // too many errors reading/receiving/parsing the status, close the socket and emit error
284 requeueCurrentlyPipelinedRequests();
285 close();
286 reply->d_func()->errorString = connection->d_func()->errorDetail(QNetworkReply::RemoteHostClosedError, socket);
287 emit reply->finishedWithError(QNetworkReply::RemoteHostClosedError, reply->d_func()->errorString);
288 reply = nullptr;
289 if (protocolHandler)
290 protocolHandler->setReply(nullptr);
291 request = QHttpNetworkRequest();
292 QMetaObject::invokeMethod(connection, "_q_startNextRequest", Qt::QueuedConnection);
293 } else {
294 reconnectAttempts--;
295 reply->d_func()->clear();
296 reply->d_func()->connection = connection;
297 reply->d_func()->connectionChannel = this;
298 closeAndResendCurrentRequest();
299 }
300}
301
302bool QHttpNetworkConnectionChannel::ensureConnection()
303{
304 if (!isInitialized)
305 init();
306
307 QAbstractSocket::SocketState socketState = socket->state();
308
309 // resend this request after we receive the disconnected signal
310 // If !socket->isOpen() then we have already called close() on the socket, but there was still a
311 // pending connectToHost() for which we hadn't seen a connected() signal, yet. The connected()
312 // has now arrived (as indicated by socketState != ClosingState), but we cannot send anything on
313 // such a socket anymore.
314 if (socketState == QAbstractSocket::ClosingState ||
315 (socketState != QAbstractSocket::UnconnectedState && !socket->isOpen())) {
316 if (reply)
317 resendCurrent = true;
318 return false;
319 }
320
321 // already trying to connect?
322 if (socketState == QAbstractSocket::HostLookupState ||
323 socketState == QAbstractSocket::ConnectingState) {
324 return false;
325 }
326
327 // make sure that this socket is in a connected state, if not initiate
328 // connection to the host.
329 if (socketState != QAbstractSocket::ConnectedState) {
330 // connect to the host if not already connected.
331 state = QHttpNetworkConnectionChannel::ConnectingState;
332 pendingEncrypt = ssl;
333
334 // reset state
335 pipeliningSupported = PipeliningSupportUnknown;
336 authenticationCredentialsSent = false;
337 proxyCredentialsSent = false;
338 authenticator.detach();
339 QAuthenticatorPrivate *priv = QAuthenticatorPrivate::getPrivate(authenticator);
340 priv->hasFailed = false;
341 proxyAuthenticator.detach();
342 priv = QAuthenticatorPrivate::getPrivate(proxyAuthenticator);
343 priv->hasFailed = false;
344
345 // This workaround is needed since we use QAuthenticator for NTLM authentication. The "phase == Done"
346 // is the usual criteria for emitting authentication signals. The "phase" is set to "Done" when the
347 // last header for Authorization is generated by the QAuthenticator. Basic & Digest logic does not
348 // check the "phase" for generating the Authorization header. NTLM authentication is a two stage
349 // process & needs the "phase". To make sure the QAuthenticator uses the current username/password
350 // the phase is reset to Start.
351 priv = QAuthenticatorPrivate::getPrivate(authenticator);
352 if (priv && priv->phase == QAuthenticatorPrivate::Done)
353 priv->phase = QAuthenticatorPrivate::Start;
354 priv = QAuthenticatorPrivate::getPrivate(proxyAuthenticator);
355 if (priv && priv->phase == QAuthenticatorPrivate::Done)
356 priv->phase = QAuthenticatorPrivate::Start;
357
358 QString connectHost = connection->d_func()->hostName;
359 quint16 connectPort = connection->d_func()->port;
360
361#ifndef QT_NO_NETWORKPROXY
362 // HTTPS always use transparent proxy.
363 if (connection->d_func()->networkProxy.type() != QNetworkProxy::NoProxy && !ssl) {
364 connectHost = connection->d_func()->networkProxy.hostName();
365 connectPort = connection->d_func()->networkProxy.port();
366 }
367 if (socket->proxy().type() == QNetworkProxy::HttpProxy) {
368 // Make user-agent field available to HTTP proxy socket engine (QTBUG-17223)
369 QByteArray value;
370 // ensureConnection is called before any request has been assigned, but can also be
371 // called again if reconnecting
372 if (request.url().isEmpty()) {
373 if (connection->connectionType()
374 == QHttpNetworkConnection::ConnectionTypeHTTP2Direct
375 || (connection->connectionType() == QHttpNetworkConnection::ConnectionTypeHTTP2
376 && h2RequestsToSend.count() > 0)) {
377 value = h2RequestsToSend.first().first.headerField("user-agent");
378 } else {
379 value = connection->d_func()->predictNextRequest().headerField("user-agent");
380 }
381 } else {
382 value = request.headerField("user-agent");
383 }
384 if (!value.isEmpty()) {
385 QNetworkProxy proxy(socket->proxy());
386 proxy.setRawHeader("User-Agent", value); //detaches
387 socket->setProxy(proxy);
388 }
389 }
390#endif
391 if (ssl) {
392#ifndef QT_NO_SSL
393 QSslSocket *sslSocket = qobject_cast<QSslSocket*>(socket);
394
395 // check whether we can re-use an existing SSL session
396 // (meaning another socket in this connection has already
397 // performed a full handshake)
398 if (!connection->sslContext().isNull())
399 QSslSocketPrivate::checkSettingSslContext(sslSocket, connection->sslContext());
400
401 sslSocket->setPeerVerifyName(connection->d_func()->peerVerifyName);
402 sslSocket->connectToHostEncrypted(connectHost, connectPort, QIODevice::ReadWrite, networkLayerPreference);
403 if (ignoreAllSslErrors)
404 sslSocket->ignoreSslErrors();
405 sslSocket->ignoreSslErrors(ignoreSslErrorsList);
406
407 // limit the socket read buffer size. we will read everything into
408 // the QHttpNetworkReply anyway, so let's grow only that and not
409 // here and there.
410 socket->setReadBufferSize(64*1024);
411#else
412 // Need to dequeue the request so that we can emit the error.
413 if (!reply)
414 connection->d_func()->dequeueRequest(socket);
415 connection->d_func()->emitReplyError(socket, reply, QNetworkReply::ProtocolUnknownError);
416#endif
417 } else {
418 // In case of no proxy we can use the Unbuffered QTcpSocket
419#ifndef QT_NO_NETWORKPROXY
420 if (connection->d_func()->networkProxy.type() == QNetworkProxy::NoProxy
421 && connection->cacheProxy().type() == QNetworkProxy::NoProxy
422 && connection->transparentProxy().type() == QNetworkProxy::NoProxy) {
423#endif
424 socket->connectToHost(connectHost, connectPort, QIODevice::ReadWrite | QIODevice::Unbuffered, networkLayerPreference);
425 // For an Unbuffered QTcpSocket, the read buffer size has a special meaning.
426 socket->setReadBufferSize(1*1024);
427#ifndef QT_NO_NETWORKPROXY
428 } else {
429 socket->connectToHost(connectHost, connectPort, QIODevice::ReadWrite, networkLayerPreference);
430
431 // limit the socket read buffer size. we will read everything into
432 // the QHttpNetworkReply anyway, so let's grow only that and not
433 // here and there.
434 socket->setReadBufferSize(64*1024);
435 }
436#endif
437 }
438 return false;
439 }
440
441 // This code path for ConnectedState
442 if (pendingEncrypt) {
443 // Let's only be really connected when we have received the encrypted() signal. Else the state machine seems to mess up
444 // and corrupt the things sent to the server.
445 return false;
446 }
447
448 return true;
449}
450
451void QHttpNetworkConnectionChannel::allDone()
452{
453 Q_ASSERT(reply);
454
455 if (!reply) {
456 qWarning("QHttpNetworkConnectionChannel::allDone() called without reply. Please report at http://bugreports.qt.io/");
457 return;
458 }
459
460 // For clear text HTTP/2 we tried to upgrade from HTTP/1.1 to HTTP/2; for
461 // ConnectionTypeHTTP2Direct we can never be here in case of failure
462 // (after an attempt to read HTTP/1.1 as HTTP/2 frames) or we have a normal
463 // HTTP/2 response and thus can skip this test:
464 if (connection->connectionType() == QHttpNetworkConnection::ConnectionTypeHTTP2
465 && !ssl && !switchedToHttp2) {
466 if (Http2::is_protocol_upgraded(*reply)) {
467 switchedToHttp2 = true;
468 protocolHandler->setReply(nullptr);
469
470 // As allDone() gets called from the protocol handler, it's not yet
471 // safe to delete it. There is no 'deleteLater', since
472 // QAbstractProtocolHandler is not a QObject. Instead we do this
473 // trick with ProtocolHandlerDeleter, a QObject-derived class.
474 // These dances below just make it somewhat exception-safe.
475 // 1. Create a new owner:
476 QAbstractProtocolHandler *oldHandler = protocolHandler.data();
477 QScopedPointer<ProtocolHandlerDeleter> deleter(new ProtocolHandlerDeleter(oldHandler));
478 // 2. Retire the old one:
479 protocolHandler.take();
480 // 3. Call 'deleteLater':
481 deleter->deleteLater();
482 // 3. Give up the ownerthip:
483 deleter.take();
484
485 connection->fillHttp2Queue();
486 protocolHandler.reset(new QHttp2ProtocolHandler(this));
487 QHttp2ProtocolHandler *h2c = static_cast<QHttp2ProtocolHandler *>(protocolHandler.data());
488 QMetaObject::invokeMethod(h2c, "_q_receiveReply", Qt::QueuedConnection);
489 QMetaObject::invokeMethod(connection, "_q_startNextRequest", Qt::QueuedConnection);
490 // If we only had one request sent with H2 allowed, we may fail to send
491 // a client preface and SETTINGS, which is required by RFC 7540, 3.2.
492 QMetaObject::invokeMethod(h2c, "ensureClientPrefaceSent", Qt::QueuedConnection);
493 return;
494 } else {
495 // Ok, whatever happened, we do not try HTTP/2 anymore ...
496 connection->setConnectionType(QHttpNetworkConnection::ConnectionTypeHTTP);
497 connection->d_func()->activeChannelCount = connection->d_func()->channelCount;
498 }
499 }
500
501 // while handling 401 & 407, we might reset the status code, so save this.
502 bool emitFinished = reply->d_func()->shouldEmitSignals();
503 bool connectionCloseEnabled = reply->d_func()->isConnectionCloseEnabled();
504 detectPipeliningSupport();
505
506 handleStatus();
507 // handleStatus() might have removed the reply because it already called connection->emitReplyError()
508
509 // queue the finished signal, this is required since we might send new requests from
510 // slot connected to it. The socket will not fire readyRead signal, if we are already
511 // in the slot connected to readyRead
512 if (reply && emitFinished)
513 QMetaObject::invokeMethod(reply, "finished", Qt::QueuedConnection);
514
515
516 // reset the reconnection attempts after we receive a complete reply.
517 // in case of failures, each channel will attempt two reconnects before emitting error.
518 reconnectAttempts = reconnectAttemptsDefault;
519
520 // now the channel can be seen as free/idle again, all signal emissions for the reply have been done
521 if (state != QHttpNetworkConnectionChannel::ClosingState)
522 state = QHttpNetworkConnectionChannel::IdleState;
523
524 // if it does not need to be sent again we can set it to 0
525 // the previous code did not do that and we had problems with accidental re-sending of a
526 // finished request.
527 // Note that this may trigger a segfault at some other point. But then we can fix the underlying
528 // problem.
529 if (!resendCurrent) {
530 request = QHttpNetworkRequest();
531 reply = nullptr;
532 protocolHandler->setReply(nullptr);
533 }
534
535 // move next from pipeline to current request
536 if (!alreadyPipelinedRequests.isEmpty()) {
537 if (resendCurrent || connectionCloseEnabled || socket->state() != QAbstractSocket::ConnectedState) {
538 // move the pipelined ones back to the main queue
539 requeueCurrentlyPipelinedRequests();
540 close();
541 } else {
542 // there were requests pipelined in and we can continue
543 HttpMessagePair messagePair = alreadyPipelinedRequests.takeFirst();
544
545 request = messagePair.first;
546 reply = messagePair.second;
547 protocolHandler->setReply(messagePair.second);
548 state = QHttpNetworkConnectionChannel::ReadingState;
549 resendCurrent = false;
550
551 written = 0; // message body, excluding the header, irrelevant here
552 bytesTotal = 0; // message body total, excluding the header, irrelevant here
553
554 // pipeline even more
555 connection->d_func()->fillPipeline(socket);
556
557 // continue reading
558 //_q_receiveReply();
559 // this was wrong, allDone gets called from that function anyway.
560 }
561 } else if (alreadyPipelinedRequests.isEmpty() && socket->bytesAvailable() > 0) {
562 // this is weird. we had nothing pipelined but still bytes available. better close it.
563 close();
564
565 QMetaObject::invokeMethod(connection, "_q_startNextRequest", Qt::QueuedConnection);
566 } else if (alreadyPipelinedRequests.isEmpty()) {
567 if (connectionCloseEnabled)
568 if (socket->state() != QAbstractSocket::UnconnectedState)
569 close();
570 if (qobject_cast<QHttpNetworkConnection*>(connection))
571 QMetaObject::invokeMethod(connection, "_q_startNextRequest", Qt::QueuedConnection);
572 }
573}
574
575void QHttpNetworkConnectionChannel::detectPipeliningSupport()
576{
577 Q_ASSERT(reply);
578 // detect HTTP Pipelining support
579 QByteArray serverHeaderField;
580 if (
581 // check for HTTP/1.1
582 (reply->d_func()->majorVersion == 1 && reply->d_func()->minorVersion == 1)
583 // check for not having connection close
584 && (!reply->d_func()->isConnectionCloseEnabled())
585 // check if it is still connected
586 && (socket->state() == QAbstractSocket::ConnectedState)
587 // check for broken servers in server reply header
588 // this is adapted from http://mxr.mozilla.org/firefox/ident?i=SupportsPipelining
589 && (serverHeaderField = reply->headerField("Server"), !serverHeaderField.contains("Microsoft-IIS/4."))
590 && (!serverHeaderField.contains("Microsoft-IIS/5."))
591 && (!serverHeaderField.contains("Netscape-Enterprise/3."))
592 // this is adpoted from the knowledge of the Nokia 7.x browser team (DEF143319)
593 && (!serverHeaderField.contains("WebLogic"))
594 && (!serverHeaderField.startsWith("Rocket")) // a Python Web Server, see Web2py.com
595 ) {
596 pipeliningSupported = QHttpNetworkConnectionChannel::PipeliningProbablySupported;
597 } else {
598 pipeliningSupported = QHttpNetworkConnectionChannel::PipeliningSupportUnknown;
599 }
600}
601
602// called when the connection broke and we need to queue some pipelined requests again
603void QHttpNetworkConnectionChannel::requeueCurrentlyPipelinedRequests()
604{
605 for (int i = 0; i < alreadyPipelinedRequests.length(); i++)
606 connection->d_func()->requeueRequest(alreadyPipelinedRequests.at(i));
607 alreadyPipelinedRequests.clear();
608
609 // only run when the QHttpNetworkConnection is not currently being destructed, e.g.
610 // this function is called from _q_disconnected which is called because
611 // of ~QHttpNetworkConnectionPrivate
612 if (qobject_cast<QHttpNetworkConnection*>(connection))
613 QMetaObject::invokeMethod(connection, "_q_startNextRequest", Qt::QueuedConnection);
614}
615
616void QHttpNetworkConnectionChannel::handleStatus()
617{
618 Q_ASSERT(socket);
619 Q_ASSERT(reply);
620
621 int statusCode = reply->statusCode();
622 bool resend = false;
623
624 switch (statusCode) {
625 case 301:
626 case 302:
627 case 303:
628 case 305:
629 case 307:
630 case 308: {
631 // Parse the response headers and get the "location" url
632 QUrl redirectUrl = connection->d_func()->parseRedirectResponse(socket, reply);
633 if (redirectUrl.isValid())
634 reply->setRedirectUrl(redirectUrl);
635
636 if ((statusCode == 307 || statusCode == 308) && !resetUploadData()) {
637 // Couldn't reset the upload data, which means it will be unable to POST the data -
638 // this would lead to a long wait until it eventually failed and then retried.
639 // Instead of doing that we fail here instead, resetUploadData will already have emitted
640 // a ContentReSendError, so we're done.
641 } else if (qobject_cast<QHttpNetworkConnection *>(connection)) {
642 QMetaObject::invokeMethod(connection, "_q_startNextRequest", Qt::QueuedConnection);
643 }
644 break;
645 }
646 case 401: // auth required
647 case 407: // proxy auth required
648 if (connection->d_func()->handleAuthenticateChallenge(socket, reply, (statusCode == 407), resend)) {
649 if (resend) {
650 if (!resetUploadData())
651 break;
652
653 reply->d_func()->eraseData();
654
655 if (alreadyPipelinedRequests.isEmpty()) {
656 // this does a re-send without closing the connection
657 resendCurrent = true;
658 QMetaObject::invokeMethod(connection, "_q_startNextRequest", Qt::QueuedConnection);
659 } else {
660 // we had requests pipelined.. better close the connection in closeAndResendCurrentRequest
661 closeAndResendCurrentRequest();
662 QMetaObject::invokeMethod(connection, "_q_startNextRequest", Qt::QueuedConnection);
663 }
664 } else {
665 //authentication cancelled, close the channel.
666 close();
667 }
668 } else {
669 emit reply->headerChanged();
670 emit reply->readyRead();
671 QNetworkReply::NetworkError errorCode = (statusCode == 407)
672 ? QNetworkReply::ProxyAuthenticationRequiredError
673 : QNetworkReply::AuthenticationRequiredError;
674 reply->d_func()->errorString = connection->d_func()->errorDetail(errorCode, socket);
675 emit reply->finishedWithError(errorCode, reply->d_func()->errorString);
676 }
677 break;
678 default:
679 if (qobject_cast<QHttpNetworkConnection*>(connection))
680 QMetaObject::invokeMethod(connection, "_q_startNextRequest", Qt::QueuedConnection);
681 }
682}
683
684bool QHttpNetworkConnectionChannel::resetUploadData()
685{
686 if (!reply) {
687 //this happens if server closes connection while QHttpNetworkConnectionPrivate::_q_startNextRequest is pending
688 return false;
689 }
690 QNonContiguousByteDevice* uploadByteDevice = request.uploadByteDevice();
691 if (!uploadByteDevice)
692 return true;
693
694 if (uploadByteDevice->reset()) {
695 written = 0;
696 return true;
697 } else {
698 connection->d_func()->emitReplyError(socket, reply, QNetworkReply::ContentReSendError);
699 return false;
700 }
701}
702
703#ifndef QT_NO_NETWORKPROXY
704
705void QHttpNetworkConnectionChannel::setProxy(const QNetworkProxy &networkProxy)
706{
707 if (socket)
708 socket->setProxy(networkProxy);
709
710 proxy = networkProxy;
711}
712
713#endif
714
715#ifndef QT_NO_SSL
716
717void QHttpNetworkConnectionChannel::ignoreSslErrors()
718{
719 if (socket)
720 static_cast<QSslSocket *>(socket)->ignoreSslErrors();
721
722 ignoreAllSslErrors = true;
723}
724
725
726void QHttpNetworkConnectionChannel::ignoreSslErrors(const QList<QSslError> &errors)
727{
728 if (socket)
729 static_cast<QSslSocket *>(socket)->ignoreSslErrors(errors);
730
731 ignoreSslErrorsList = errors;
732}
733
734void QHttpNetworkConnectionChannel::setSslConfiguration(const QSslConfiguration &config)
735{
736 if (socket)
737 static_cast<QSslSocket *>(socket)->setSslConfiguration(config);
738
739 if (sslConfiguration.data())
740 *sslConfiguration = config;
741 else
742 sslConfiguration.reset(new QSslConfiguration(config));
743}
744
745#endif
746
747void QHttpNetworkConnectionChannel::pipelineInto(HttpMessagePair &pair)
748{
749 // this is only called for simple GET
750
751 QHttpNetworkRequest &request = pair.first;
752 QHttpNetworkReply *reply = pair.second;
753 reply->d_func()->clear();
754 reply->d_func()->connection = connection;
755 reply->d_func()->connectionChannel = this;
756 reply->d_func()->autoDecompress = request.d->autoDecompress;
757 reply->d_func()->pipeliningUsed = true;
758
759#ifndef QT_NO_NETWORKPROXY
760 pipeline.append(QHttpNetworkRequestPrivate::header(request,
761 (connection->d_func()->networkProxy.type() != QNetworkProxy::NoProxy)));
762#else
763 pipeline.append(QHttpNetworkRequestPrivate::header(request, false));
764#endif
765
766 alreadyPipelinedRequests.append(pair);
767
768 // pipelineFlush() needs to be called at some point afterwards
769}
770
771void QHttpNetworkConnectionChannel::pipelineFlush()
772{
773 if (pipeline.isEmpty())
774 return;
775
776 // The goal of this is so that we have everything in one TCP packet.
777 // For the Unbuffered QTcpSocket this is manually needed, the buffered
778 // QTcpSocket does it automatically.
779 // Also, sometimes the OS does it for us (Nagle's algorithm) but that
780 // happens only sometimes.
781 socket->write(pipeline);
782 pipeline.clear();
783}
784
785
786void QHttpNetworkConnectionChannel::closeAndResendCurrentRequest()
787{
788 requeueCurrentlyPipelinedRequests();
789 close();
790 if (reply)
791 resendCurrent = true;
792 if (qobject_cast<QHttpNetworkConnection*>(connection))
793 QMetaObject::invokeMethod(connection, "_q_startNextRequest", Qt::QueuedConnection);
794}
795
796void QHttpNetworkConnectionChannel::resendCurrentRequest()
797{
798 requeueCurrentlyPipelinedRequests();
799 if (reply)
800 resendCurrent = true;
801 if (qobject_cast<QHttpNetworkConnection*>(connection))
802 QMetaObject::invokeMethod(connection, "_q_startNextRequest", Qt::QueuedConnection);
803}
804
805bool QHttpNetworkConnectionChannel::isSocketBusy() const
806{
807 return (state & QHttpNetworkConnectionChannel::BusyState);
808}
809
810bool QHttpNetworkConnectionChannel::isSocketWriting() const
811{
812 return (state & QHttpNetworkConnectionChannel::WritingState);
813}
814
815bool QHttpNetworkConnectionChannel::isSocketWaiting() const
816{
817 return (state & QHttpNetworkConnectionChannel::WaitingState);
818}
819
820bool QHttpNetworkConnectionChannel::isSocketReading() const
821{
822 return (state & QHttpNetworkConnectionChannel::ReadingState);
823}
824
825void QHttpNetworkConnectionChannel::_q_bytesWritten(qint64 bytes)
826{
827 Q_UNUSED(bytes);
828 if (ssl) {
829 // In the SSL case we want to send data from encryptedBytesWritten signal since that one
830 // is the one going down to the actual network, not only into some SSL buffer.
831 return;
832 }
833
834 // bytes have been written to the socket. write even more of them :)
835 if (isSocketWriting())
836 sendRequest();
837 // otherwise we do nothing
838}
839
840void QHttpNetworkConnectionChannel::_q_disconnected()
841{
842 if (state == QHttpNetworkConnectionChannel::ClosingState) {
843 state = QHttpNetworkConnectionChannel::IdleState;
844 QMetaObject::invokeMethod(connection, "_q_startNextRequest", Qt::QueuedConnection);
845 return;
846 }
847
848 // read the available data before closing (also done in _q_error for other codepaths)
849 if ((isSocketWaiting() || isSocketReading()) && socket->bytesAvailable()) {
850 if (reply) {
851 state = QHttpNetworkConnectionChannel::ReadingState;
852 _q_receiveReply();
853 }
854 } else if (state == QHttpNetworkConnectionChannel::IdleState && resendCurrent) {
855 // re-sending request because the socket was in ClosingState
856 QMetaObject::invokeMethod(connection, "_q_startNextRequest", Qt::QueuedConnection);
857 }
858 state = QHttpNetworkConnectionChannel::IdleState;
859 if (alreadyPipelinedRequests.length()) {
860 // If nothing was in a pipeline, no need in calling
861 // _q_startNextRequest (which it does):
862 requeueCurrentlyPipelinedRequests();
863 }
864
865 pendingEncrypt = false;
866}
867
868
869void QHttpNetworkConnectionChannel::_q_connected()
870{
871 // For the Happy Eyeballs we need to check if this is the first channel to connect.
872 if (connection->d_func()->networkLayerState == QHttpNetworkConnectionPrivate::HostLookupPending || connection->d_func()->networkLayerState == QHttpNetworkConnectionPrivate::IPv4or6) {
873 if (connection->d_func()->delayedConnectionTimer.isActive())
874 connection->d_func()->delayedConnectionTimer.stop();
875 if (networkLayerPreference == QAbstractSocket::IPv4Protocol)
876 connection->d_func()->networkLayerState = QHttpNetworkConnectionPrivate::IPv4;
877 else if (networkLayerPreference == QAbstractSocket::IPv6Protocol)
878 connection->d_func()->networkLayerState = QHttpNetworkConnectionPrivate::IPv6;
879 else {
880 if (socket->peerAddress().protocol() == QAbstractSocket::IPv4Protocol)
881 connection->d_func()->networkLayerState = QHttpNetworkConnectionPrivate::IPv4;
882 else
883 connection->d_func()->networkLayerState = QHttpNetworkConnectionPrivate::IPv6;
884 }
885 connection->d_func()->networkLayerDetected(networkLayerPreference);
886 } else {
887 bool anyProtocol = networkLayerPreference == QAbstractSocket::AnyIPProtocol;
888 if (((connection->d_func()->networkLayerState == QHttpNetworkConnectionPrivate::IPv4)
889 && (networkLayerPreference != QAbstractSocket::IPv4Protocol && !anyProtocol))
890 || ((connection->d_func()->networkLayerState == QHttpNetworkConnectionPrivate::IPv6)
891 && (networkLayerPreference != QAbstractSocket::IPv6Protocol && !anyProtocol))) {
892 close();
893 // This is the second connection so it has to be closed and we can schedule it for another request.
894 QMetaObject::invokeMethod(connection, "_q_startNextRequest", Qt::QueuedConnection);
895 return;
896 }
897 //The connections networkLayerState had already been decided.
898 }
899
900 // improve performance since we get the request sent by the kernel ASAP
901 //socket->setSocketOption(QAbstractSocket::LowDelayOption, 1);
902 // We have this commented out now. It did not have the effect we wanted. If we want to
903 // do this properly, Qt has to combine multiple HTTP requests into one buffer
904 // and send this to the kernel in one syscall and then the kernel immediately sends
905 // it as one TCP packet because of TCP_NODELAY.
906 // However, this code is currently not in Qt, so we rely on the kernel combining
907 // the requests into one TCP packet.
908
909 // not sure yet if it helps, but it makes sense
910 socket->setSocketOption(QAbstractSocket::KeepAliveOption, 1);
911
912 pipeliningSupported = QHttpNetworkConnectionChannel::PipeliningSupportUnknown;
913
914 if (QNetworkStatusMonitor::isEnabled()) {
915 auto connectionPrivate = connection->d_func();
916 if (!connectionPrivate->connectionMonitor.isMonitoring()) {
917 // Now that we have a pair of addresses, we can start monitoring the
918 // connection status to handle its loss properly.
919 if (connectionPrivate->connectionMonitor.setTargets(socket->localAddress(), socket->peerAddress()))
920 connectionPrivate->connectionMonitor.startMonitoring();
921 }
922 }
923
924 // ### FIXME: if the server closes the connection unexpectedly, we shouldn't send the same broken request again!
925 //channels[i].reconnectAttempts = 2;
926 if (ssl || pendingEncrypt) { // FIXME: Didn't work properly with pendingEncrypt only, we should refactor this into an EncrypingState
927#ifndef QT_NO_SSL
928 if (connection->sslContext().isNull()) {
929 // this socket is making the 1st handshake for this connection,
930 // we need to set the SSL context so new sockets can reuse it
931 QSharedPointer<QSslContext> socketSslContext = QSslSocketPrivate::sslContext(static_cast<QSslSocket*>(socket));
932 if (!socketSslContext.isNull())
933 connection->setSslContext(socketSslContext);
934 }
935#endif
936 } else if (connection->connectionType() == QHttpNetworkConnection::ConnectionTypeHTTP2Direct) {
937 state = QHttpNetworkConnectionChannel::IdleState;
938 protocolHandler.reset(new QHttp2ProtocolHandler(this));
939 if (h2RequestsToSend.count() > 0) {
940 // In case our peer has sent us its settings (window size, max concurrent streams etc.)
941 // let's give _q_receiveReply a chance to read them first ('invokeMethod', QueuedConnection).
942 QMetaObject::invokeMethod(connection, "_q_startNextRequest", Qt::QueuedConnection);
943 }
944 } else {
945 state = QHttpNetworkConnectionChannel::IdleState;
946 const bool tryProtocolUpgrade = connection->connectionType() == QHttpNetworkConnection::ConnectionTypeHTTP2;
947 if (tryProtocolUpgrade) {
948 // For HTTP/1.1 it's already created and never reset.
949 protocolHandler.reset(new QHttpProtocolHandler(this));
950 }
951 switchedToHttp2 = false;
952
953 if (!reply)
954 connection->d_func()->dequeueRequest(socket);
955
956 if (reply) {
957 if (tryProtocolUpgrade) {
958 // Let's augment our request with some magic headers and try to
959 // switch to HTTP/2.
960 Http2::appendProtocolUpgradeHeaders(connection->http2Parameters(), &request);
961 }
962 sendRequest();
963 }
964 }
965}
966
967
968void QHttpNetworkConnectionChannel::_q_error(QAbstractSocket::SocketError socketError)
969{
970 if (!socket)
971 return;
972 QNetworkReply::NetworkError errorCode = QNetworkReply::UnknownNetworkError;
973
974 switch (socketError) {
975 case QAbstractSocket::HostNotFoundError:
976 errorCode = QNetworkReply::HostNotFoundError;
977 break;
978 case QAbstractSocket::ConnectionRefusedError:
979 errorCode = QNetworkReply::ConnectionRefusedError;
980 break;
981 case QAbstractSocket::RemoteHostClosedError:
982 // This error for SSL comes twice in a row, first from SSL layer ("The TLS/SSL connection has been closed") then from TCP layer.
983 // Depending on timing it can also come three times in a row (first time when we try to write into a closing QSslSocket).
984 // The reconnectAttempts handling catches the cases where we can re-send the request.
985 if (!reply && state == QHttpNetworkConnectionChannel::IdleState) {
986 // Not actually an error, it is normal for Keep-Alive connections to close after some time if no request
987 // is sent on them. No need to error the other replies below. Just bail out here.
988 // The _q_disconnected will handle the possibly pipelined replies. HTTP/2 is special for now,
989 // we do not resend, but must report errors if any request is in progress (note, while
990 // not in its sendRequest(), protocol handler switches the channel to IdleState, thus
991 // this check is under this condition in 'if'):
992 if (protocolHandler.data()) {
993 if (connection->connectionType() == QHttpNetworkConnection::ConnectionTypeHTTP2Direct
994 || (connection->connectionType() == QHttpNetworkConnection::ConnectionTypeHTTP2
995 && switchedToHttp2)) {
996 auto h2Handler = static_cast<QHttp2ProtocolHandler *>(protocolHandler.data());
997 h2Handler->handleConnectionClosure();
998 protocolHandler.reset();
999 }
1000 }
1001 return;
1002 } else if (state != QHttpNetworkConnectionChannel::IdleState && state != QHttpNetworkConnectionChannel::ReadingState) {
1003 // Try to reconnect/resend before sending an error.
1004 // While "Reading" the _q_disconnected() will handle this.
1005 // If we're using ssl then the protocolHandler is not initialized until
1006 // "encrypted" has been emitted, since retrying requires the protocolHandler (asserted)
1007 // we will not try if encryption is not done.
1008 if (!pendingEncrypt && reconnectAttempts-- > 0) {
1009 resendCurrentRequest();
1010 return;
1011 } else {
1012 errorCode = QNetworkReply::RemoteHostClosedError;
1013 }
1014 } else if (state == QHttpNetworkConnectionChannel::ReadingState) {
1015 if (!reply)
1016 break;
1017
1018 if (!reply->d_func()->expectContent()) {
1019 // No content expected, this is a valid way to have the connection closed by the server
1020 // We need to invoke this asynchronously to make sure the state() of the socket is on QAbstractSocket::UnconnectedState
1021 QMetaObject::invokeMethod(this, "_q_receiveReply", Qt::QueuedConnection);
1022 return;
1023 }
1024 if (reply->contentLength() == -1 && !reply->d_func()->isChunked()) {
1025 // There was no content-length header and it's not chunked encoding,
1026 // so this is a valid way to have the connection closed by the server
1027 // We need to invoke this asynchronously to make sure the state() of the socket is on QAbstractSocket::UnconnectedState
1028 QMetaObject::invokeMethod(this, "_q_receiveReply", Qt::QueuedConnection);
1029 return;
1030 }
1031 // ok, we got a disconnect even though we did not expect it
1032 // Try to read everything from the socket before we emit the error.
1033 if (socket->bytesAvailable()) {
1034 // Read everything from the socket into the reply buffer.
1035 // we can ignore the readbuffersize as the data is already
1036 // in memory and we will not receive more data on the socket.
1037 reply->setReadBufferSize(0);
1038 reply->setDownstreamLimited(false);
1039 _q_receiveReply();
1040 if (!reply) {
1041 // No more reply assigned after the previous call? Then it had been finished successfully.
1042 requeueCurrentlyPipelinedRequests();
1043 state = QHttpNetworkConnectionChannel::IdleState;
1044 QMetaObject::invokeMethod(connection, "_q_startNextRequest", Qt::QueuedConnection);
1045 return;
1046 }
1047 }
1048
1049 errorCode = QNetworkReply::RemoteHostClosedError;
1050 } else {
1051 errorCode = QNetworkReply::RemoteHostClosedError;
1052 }
1053 break;
1054 case QAbstractSocket::SocketTimeoutError:
1055 // try to reconnect/resend before sending an error.
1056 if (state == QHttpNetworkConnectionChannel::WritingState && (reconnectAttempts-- > 0)) {
1057 resendCurrentRequest();
1058 return;
1059 }
1060 errorCode = QNetworkReply::TimeoutError;
1061 break;
1062 case QAbstractSocket::ProxyAuthenticationRequiredError:
1063 errorCode = QNetworkReply::ProxyAuthenticationRequiredError;
1064 break;
1065 case QAbstractSocket::SslHandshakeFailedError:
1066 errorCode = QNetworkReply::SslHandshakeFailedError;
1067 break;
1068 case QAbstractSocket::ProxyConnectionClosedError:
1069 // try to reconnect/resend before sending an error.
1070 if (reconnectAttempts-- > 0) {
1071 resendCurrentRequest();
1072 return;
1073 }
1074 errorCode = QNetworkReply::ProxyConnectionClosedError;
1075 break;
1076 case QAbstractSocket::ProxyConnectionTimeoutError:
1077 // try to reconnect/resend before sending an error.
1078 if (reconnectAttempts-- > 0) {
1079 resendCurrentRequest();
1080 return;
1081 }
1082 errorCode = QNetworkReply::ProxyTimeoutError;
1083 break;
1084 default:
1085 // all other errors are treated as NetworkError
1086 errorCode = QNetworkReply::UnknownNetworkError;
1087 break;
1088 }
1089 QPointer<QHttpNetworkConnection> that = connection;
1090 QString errorString = connection->d_func()->errorDetail(errorCode, socket, socket->errorString());
1091
1092 // In the HostLookupPending state the channel should not emit the error.
1093 // This will instead be handled by the connection.
1094 if (!connection->d_func()->shouldEmitChannelError(socket))
1095 return;
1096
1097 // emit error for all waiting replies
1098 do {
1099 // First requeue the already pipelined requests for the current failed reply,
1100 // then dequeue pending requests so we can also mark them as finished with error
1101 if (reply)
1102 requeueCurrentlyPipelinedRequests();
1103 else
1104 connection->d_func()->dequeueRequest(socket);
1105
1106 if (reply) {
1107 reply->d_func()->errorString = errorString;
1108 reply->d_func()->httpErrorCode = errorCode;
1109 emit reply->finishedWithError(errorCode, errorString);
1110 reply = nullptr;
1111 if (protocolHandler)
1112 protocolHandler->setReply(nullptr);
1113 }
1114 } while (!connection->d_func()->highPriorityQueue.isEmpty()
1115 || !connection->d_func()->lowPriorityQueue.isEmpty());
1116
1117 if (connection->connectionType() == QHttpNetworkConnection::ConnectionTypeHTTP2
1118 || connection->connectionType() == QHttpNetworkConnection::ConnectionTypeHTTP2Direct) {
1119 QList<HttpMessagePair> h2Pairs = h2RequestsToSend.values();
1120 for (int a = 0; a < h2Pairs.count(); ++a) {
1121 // emit error for all replies
1122 QHttpNetworkReply *currentReply = h2Pairs.at(a).second;
1123 Q_ASSERT(currentReply);
1124 emit currentReply->finishedWithError(errorCode, errorString);
1125 }
1126 }
1127
1128 // send the next request
1129 QMetaObject::invokeMethod(that, "_q_startNextRequest", Qt::QueuedConnection);
1130
1131 if (that) {
1132 //signal emission triggered event loop
1133 if (!socket)
1134 state = QHttpNetworkConnectionChannel::IdleState;
1135 else if (socket->state() == QAbstractSocket::UnconnectedState)
1136 state = QHttpNetworkConnectionChannel::IdleState;
1137 else
1138 state = QHttpNetworkConnectionChannel::ClosingState;
1139
1140 // pendingEncrypt must only be true in between connected and encrypted states
1141 pendingEncrypt = false;
1142 }
1143}
1144
1145#ifndef QT_NO_NETWORKPROXY
1146void QHttpNetworkConnectionChannel::_q_proxyAuthenticationRequired(const QNetworkProxy &proxy, QAuthenticator* auth)
1147{
1148 if ((connection->connectionType() == QHttpNetworkConnection::ConnectionTypeHTTP2
1149 && (switchedToHttp2 || h2RequestsToSend.count() > 0))
1150 || connection->connectionType() == QHttpNetworkConnection::ConnectionTypeHTTP2Direct) {
1151 if (h2RequestsToSend.count() > 0)
1152 connection->d_func()->emitProxyAuthenticationRequired(this, proxy, auth);
1153 } else { // HTTP
1154 // Need to dequeue the request before we can emit the error.
1155 if (!reply)
1156 connection->d_func()->dequeueRequest(socket);
1157 if (reply)
1158 connection->d_func()->emitProxyAuthenticationRequired(this, proxy, auth);
1159 }
1160}
1161#endif
1162
1163void QHttpNetworkConnectionChannel::_q_uploadDataReadyRead()
1164{
1165 if (reply)
1166 sendRequest();
1167}
1168
1169void QHttpNetworkConnectionChannel::emitFinishedWithError(QNetworkReply::NetworkError error,
1170 const char *message)
1171{
1172 if (reply)
1173 emit reply->finishedWithError(error, QHttpNetworkConnectionChannel::tr(message));
1174 QList<HttpMessagePair> h2Pairs = h2RequestsToSend.values();
1175 for (int a = 0; a < h2Pairs.count(); ++a) {
1176 QHttpNetworkReply *currentReply = h2Pairs.at(a).second;
1177 Q_ASSERT(currentReply);
1178 emit currentReply->finishedWithError(error, QHttpNetworkConnectionChannel::tr(message));
1179 }
1180}
1181
1182#ifndef QT_NO_SSL
1183void QHttpNetworkConnectionChannel::_q_encrypted()
1184{
1185 QSslSocket *sslSocket = qobject_cast<QSslSocket *>(socket);
1186 Q_ASSERT(sslSocket);
1187
1188 if (!protocolHandler && connection->connectionType() != QHttpNetworkConnection::ConnectionTypeHTTP2Direct) {
1189 // ConnectionTypeHTTP2Direct does not rely on ALPN/NPN to negotiate HTTP/2,
1190 // after establishing a secure connection we immediately start sending
1191 // HTTP/2 frames.
1192 switch (sslSocket->sslConfiguration().nextProtocolNegotiationStatus()) {
1193 case QSslConfiguration::NextProtocolNegotiationNegotiated: {
1194 QByteArray nextProtocol = sslSocket->sslConfiguration().nextNegotiatedProtocol();
1195 if (nextProtocol == QSslConfiguration::NextProtocolHttp1_1) {
1196 // fall through to create a QHttpProtocolHandler
1197 } else if (nextProtocol == QSslConfiguration::ALPNProtocolHTTP2) {
1198 switchedToHttp2 = true;
1199 protocolHandler.reset(new QHttp2ProtocolHandler(this));
1200 connection->setConnectionType(QHttpNetworkConnection::ConnectionTypeHTTP2);
1201 break;
1202 } else {
1203 emitFinishedWithError(QNetworkReply::SslHandshakeFailedError,
1204 "detected unknown Next Protocol Negotiation protocol");
1205 break;
1206 }
1207 }
1208 Q_FALLTHROUGH();
1209 case QSslConfiguration::NextProtocolNegotiationUnsupported: // No agreement, try HTTP/1(.1)
1210 case QSslConfiguration::NextProtocolNegotiationNone: {
1211 protocolHandler.reset(new QHttpProtocolHandler(this));
1212
1213 QSslConfiguration newConfiguration = sslSocket->sslConfiguration();
1214 QList<QByteArray> protocols = newConfiguration.allowedNextProtocols();
1215 const int nProtocols = protocols.size();
1216 // Clear the protocol that we failed to negotiate, so we do not try
1217 // it again on other channels that our connection can create/open.
1218 if (connection->connectionType() == QHttpNetworkConnection::ConnectionTypeHTTP2)
1219 protocols.removeAll(QSslConfiguration::ALPNProtocolHTTP2);
1220
1221 if (nProtocols > protocols.size()) {
1222 newConfiguration.setAllowedNextProtocols(protocols);
1223 const int channelCount = connection->d_func()->channelCount;
1224 for (int i = 0; i < channelCount; ++i)
1225 connection->d_func()->channels[i].setSslConfiguration(newConfiguration);
1226 }
1227
1228 connection->setConnectionType(QHttpNetworkConnection::ConnectionTypeHTTP);
1229 // We use only one channel for HTTP/2, but normally six for
1230 // HTTP/1.1 - let's restore this number to the reserved number of
1231 // channels:
1232 if (connection->d_func()->activeChannelCount < connection->d_func()->channelCount) {
1233 connection->d_func()->activeChannelCount = connection->d_func()->channelCount;
1234 // re-queue requests from HTTP/2 queue to HTTP queue, if any
1235 requeueHttp2Requests();
1236 }
1237 break;
1238 }
1239 default:
1240 emitFinishedWithError(QNetworkReply::SslHandshakeFailedError,
1241 "detected unknown Next Protocol Negotiation protocol");
1242 }
1243 } else if (connection->connectionType() == QHttpNetworkConnection::ConnectionTypeHTTP2
1244 || connection->connectionType() == QHttpNetworkConnection::ConnectionTypeHTTP2Direct) {
1245 // We have to reset QHttp2ProtocolHandler's state machine, it's a new
1246 // connection and the handler's state is unique per connection.
1247 protocolHandler.reset(new QHttp2ProtocolHandler(this));
1248 }
1249
1250 if (!socket)
1251 return; // ### error
1252 state = QHttpNetworkConnectionChannel::IdleState;
1253 pendingEncrypt = false;
1254
1255 if (connection->connectionType() == QHttpNetworkConnection::ConnectionTypeHTTP2 ||
1256 connection->connectionType() == QHttpNetworkConnection::ConnectionTypeHTTP2Direct) {
1257 if (h2RequestsToSend.count() > 0) {
1258 // In case our peer has sent us its settings (window size, max concurrent streams etc.)
1259 // let's give _q_receiveReply a chance to read them first ('invokeMethod', QueuedConnection).
1260 QMetaObject::invokeMethod(connection, "_q_startNextRequest", Qt::QueuedConnection);
1261 }
1262 } else { // HTTP
1263 if (!reply)
1264 connection->d_func()->dequeueRequest(socket);
1265 if (reply) {
1266 reply->setHttp2WasUsed(false);
1267 Q_ASSERT(reply->d_func()->connectionChannel == this);
1268 emit reply->encrypted();
1269 }
1270 if (reply)
1271 sendRequestDelayed();
1272 }
1273}
1274
1275void QHttpNetworkConnectionChannel::requeueHttp2Requests()
1276{
1277 QList<HttpMessagePair> h2Pairs = h2RequestsToSend.values();
1278 for (int a = 0; a < h2Pairs.count(); ++a)
1279 connection->d_func()->requeueRequest(h2Pairs.at(a));
1280 h2RequestsToSend.clear();
1281}
1282
1283void QHttpNetworkConnectionChannel::_q_sslErrors(const QList<QSslError> &errors)
1284{
1285 if (!socket)
1286 return;
1287 //QNetworkReply::NetworkError errorCode = QNetworkReply::ProtocolFailure;
1288 // Also pause the connection because socket notifiers may fire while an user
1289 // dialog is displaying
1290 connection->d_func()->pauseConnection();
1291 if (pendingEncrypt && !reply)
1292 connection->d_func()->dequeueRequest(socket);
1293 if (connection->connectionType() == QHttpNetworkConnection::ConnectionTypeHTTP) {
1294 if (reply)
1295 emit reply->sslErrors(errors);
1296 }
1297#ifndef QT_NO_SSL
1298 else { // HTTP/2
1299 QList<HttpMessagePair> h2Pairs = h2RequestsToSend.values();
1300 for (int a = 0; a < h2Pairs.count(); ++a) {
1301 // emit SSL errors for all replies
1302 QHttpNetworkReply *currentReply = h2Pairs.at(a).second;
1303 Q_ASSERT(currentReply);
1304 emit currentReply->sslErrors(errors);
1305 }
1306 }
1307#endif // QT_NO_SSL
1308 connection->d_func()->resumeConnection();
1309}
1310
1311void QHttpNetworkConnectionChannel::_q_preSharedKeyAuthenticationRequired(QSslPreSharedKeyAuthenticator *authenticator)
1312{
1313 connection->d_func()->pauseConnection();
1314
1315 if (pendingEncrypt && !reply)
1316 connection->d_func()->dequeueRequest(socket);
1317
1318 if (connection->connectionType() == QHttpNetworkConnection::ConnectionTypeHTTP) {
1319 if (reply)
1320 emit reply->preSharedKeyAuthenticationRequired(authenticator);
1321 } else {
1322 QList<HttpMessagePair> h2Pairs = h2RequestsToSend.values();
1323 for (int a = 0; a < h2Pairs.count(); ++a) {
1324 // emit SSL errors for all replies
1325 QHttpNetworkReply *currentReply = h2Pairs.at(a).second;
1326 Q_ASSERT(currentReply);
1327 emit currentReply->preSharedKeyAuthenticationRequired(authenticator);
1328 }
1329 }
1330
1331 connection->d_func()->resumeConnection();
1332}
1333
1334void QHttpNetworkConnectionChannel::_q_encryptedBytesWritten(qint64 bytes)
1335{
1336 Q_UNUSED(bytes);
1337 // bytes have been written to the socket. write even more of them :)
1338 if (isSocketWriting())
1339 sendRequest();
1340 // otherwise we do nothing
1341}
1342
1343#endif
1344
1345void QHttpNetworkConnectionChannel::setConnection(QHttpNetworkConnection *c)
1346{
1347 // Inlining this function in the header leads to compiler error on
1348 // release-armv5, on at least timebox 9.2 and 10.1.
1349 connection = c;
1350}
1351
1352QT_END_NAMESPACE
1353
1354#include "moc_qhttpnetworkconnectionchannel_p.cpp"
1355