1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the QtNetwork module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 3 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 3 requirements
23 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24 **
25 ** GNU General Public License Usage
26 ** Alternatively, this file may be used under the terms of the GNU
27 ** General Public License version 2.0 or (at your option) the GNU General
28 ** Public license version 3 or any later version approved by the KDE Free
29 ** Qt Foundation. The licenses are as published by the Free Software
30 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31 ** included in the packaging of this file. Please review the following
32 ** information to ensure the GNU General Public License requirements will
33 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34 ** https://www.gnu.org/licenses/gpl-3.0.html.
35 **
36 ** $QT_END_LICENSE$
37 **
38 ****************************************************************************/
39 
40 #include "qhttpnetworkconnection_p.h"
41 #include <private/qabstractsocket_p.h>
42 #include "qhttpnetworkconnectionchannel_p.h"
43 #include "private/qnoncontiguousbytedevice_p.h"
44 #include <private/qnetworkrequest_p.h>
45 #include <private/qobject_p.h>
46 #include <private/qauthenticator_p.h>
47 #include "private/qhostinfo_p.h"
48 #include <qnetworkproxy.h>
49 #include <qauthenticator.h>
50 #include <qcoreapplication.h>
51 
52 #include <qbuffer.h>
53 #include <qpair.h>
54 #include <qdebug.h>
55 
56 #ifndef QT_NO_SSL
57 #    include <private/qsslsocket_p.h>
58 #    include <QtNetwork/qsslkey.h>
59 #    include <QtNetwork/qsslcipher.h>
60 #    include <QtNetwork/qsslconfiguration.h>
61 #    include <QtNetwork/qsslerror.h>
62 #endif
63 
64 
65 
66 QT_BEGIN_NAMESPACE
67 
68 const int QHttpNetworkConnectionPrivate::defaultHttpChannelCount = 6;
69 
70 // The pipeline length. So there will be 4 requests in flight.
71 const int QHttpNetworkConnectionPrivate::defaultPipelineLength = 3;
72 // Only re-fill the pipeline if there's defaultRePipelineLength slots free in the pipeline.
73 // This means that there are 2 requests in flight and 2 slots free that will be re-filled.
74 const int QHttpNetworkConnectionPrivate::defaultRePipelineLength = 2;
75 
76 
QHttpNetworkConnectionPrivate(const QString & hostName,quint16 port,bool encrypt,QHttpNetworkConnection::ConnectionType type)77 QHttpNetworkConnectionPrivate::QHttpNetworkConnectionPrivate(const QString &hostName,
78                                                              quint16 port, bool encrypt,
79                                                              QHttpNetworkConnection::ConnectionType type)
80 : state(RunningState),
81   networkLayerState(Unknown),
82   hostName(hostName), port(port), encrypt(encrypt), delayIpv4(true)
83   , activeChannelCount(type == QHttpNetworkConnection::ConnectionTypeHTTP2
84                        || type == QHttpNetworkConnection::ConnectionTypeHTTP2Direct
85 #ifndef QT_NO_SSL
86                        || type == QHttpNetworkConnection::ConnectionTypeSPDY
87 #endif
88                        ? 1 : defaultHttpChannelCount)
89   , channelCount(defaultHttpChannelCount)
90 #ifndef QT_NO_NETWORKPROXY
91   , networkProxy(QNetworkProxy::NoProxy)
92 #endif
93   , preConnectRequests(0)
94   , connectionType(type)
95 {
96     // We allocate all 6 channels even if it's SPDY or HTTP/2 enabled
97     // connection: in case the protocol negotiation via NPN/ALPN fails,
98     // we will have normally working HTTP/1.1.
99     Q_ASSERT(channelCount >= activeChannelCount);
100     channels = new QHttpNetworkConnectionChannel[channelCount];
101 }
102 
QHttpNetworkConnectionPrivate(quint16 connectionCount,const QString & hostName,quint16 port,bool encrypt,QHttpNetworkConnection::ConnectionType type)103 QHttpNetworkConnectionPrivate::QHttpNetworkConnectionPrivate(quint16 connectionCount, const QString &hostName,
104                                                              quint16 port, bool encrypt,
105                                                              QHttpNetworkConnection::ConnectionType type)
106 : state(RunningState), networkLayerState(Unknown),
107   hostName(hostName), port(port), encrypt(encrypt), delayIpv4(true),
108   activeChannelCount(connectionCount), channelCount(connectionCount)
109 #ifndef QT_NO_NETWORKPROXY
110   , networkProxy(QNetworkProxy::NoProxy)
111 #endif
112   , preConnectRequests(0)
113   , connectionType(type)
114 {
115     channels = new QHttpNetworkConnectionChannel[channelCount];
116 }
117 
118 
119 
~QHttpNetworkConnectionPrivate()120 QHttpNetworkConnectionPrivate::~QHttpNetworkConnectionPrivate()
121 {
122     for (int i = 0; i < channelCount; ++i) {
123         if (channels[i].socket) {
124             QObject::disconnect(channels[i].socket, nullptr, &channels[i], nullptr);
125             channels[i].socket->close();
126             delete channels[i].socket;
127         }
128     }
129     delete []channels;
130 }
131 
init()132 void QHttpNetworkConnectionPrivate::init()
133 {
134     Q_Q(QHttpNetworkConnection);
135     for (int i = 0; i < channelCount; i++) {
136         channels[i].setConnection(this->q_func());
137         channels[i].ssl = encrypt;
138 #ifndef QT_NO_BEARERMANAGEMENT // ### Qt6: Remove section
139         //push session down to channels
140         channels[i].networkSession = networkSession;
141 #endif
142     }
143 
144     delayedConnectionTimer.setSingleShot(true);
145     QObject::connect(&delayedConnectionTimer, SIGNAL(timeout()), q, SLOT(_q_connectDelayedChannel()));
146 }
147 
pauseConnection()148 void QHttpNetworkConnectionPrivate::pauseConnection()
149 {
150     state = PausedState;
151 
152     // Disable all socket notifiers
153     for (int i = 0; i < activeChannelCount; i++) {
154         if (channels[i].socket) {
155 #ifndef QT_NO_SSL
156             if (encrypt)
157                 QSslSocketPrivate::pauseSocketNotifiers(static_cast<QSslSocket*>(channels[i].socket));
158             else
159 #endif
160                 QAbstractSocketPrivate::pauseSocketNotifiers(channels[i].socket);
161         }
162     }
163 }
164 
resumeConnection()165 void QHttpNetworkConnectionPrivate::resumeConnection()
166 {
167     state = RunningState;
168     // Enable all socket notifiers
169     for (int i = 0; i < activeChannelCount; i++) {
170         if (channels[i].socket) {
171 #ifndef QT_NO_SSL
172             if (encrypt)
173                 QSslSocketPrivate::resumeSocketNotifiers(static_cast<QSslSocket*>(channels[i].socket));
174             else
175 #endif
176                 QAbstractSocketPrivate::resumeSocketNotifiers(channels[i].socket);
177 
178             // Resume pending upload if needed
179             if (channels[i].state == QHttpNetworkConnectionChannel::WritingState)
180                 QMetaObject::invokeMethod(&channels[i], "_q_uploadDataReadyRead", Qt::QueuedConnection);
181         }
182     }
183 
184     // queue _q_startNextRequest
185     QMetaObject::invokeMethod(this->q_func(), "_q_startNextRequest", Qt::QueuedConnection);
186 }
187 
indexOf(QAbstractSocket * socket) const188 int QHttpNetworkConnectionPrivate::indexOf(QAbstractSocket *socket) const
189 {
190     for (int i = 0; i < activeChannelCount; ++i)
191         if (channels[i].socket == socket)
192             return i;
193 
194     qFatal("Called with unknown socket object.");
195     return 0;
196 }
197 
198 // If the connection is in the HostLookupPendening state channel errors should not always be
199 // emitted. This function will check the status of the connection channels if we
200 // have not decided the networkLayerState and will return true if the channel error
201 // should be emitted by the channel.
shouldEmitChannelError(QAbstractSocket * socket)202 bool QHttpNetworkConnectionPrivate::shouldEmitChannelError(QAbstractSocket *socket)
203 {
204     Q_Q(QHttpNetworkConnection);
205 
206     bool emitError = true;
207     int i = indexOf(socket);
208     int otherSocket = (i == 0 ? 1 : 0);
209 
210     // If the IPv4 connection still isn't started we need to start it now.
211     if (delayedConnectionTimer.isActive()) {
212         delayedConnectionTimer.stop();
213         channels[otherSocket].ensureConnection();
214     }
215 
216     if (activeChannelCount < channelCount) {
217         if (networkLayerState == HostLookupPending || networkLayerState == IPv4or6)
218             networkLayerState = QHttpNetworkConnectionPrivate::Unknown;
219         channels[0].close();
220         emitError = true;
221     } else {
222         if (networkLayerState == HostLookupPending || networkLayerState == IPv4or6) {
223             if (channels[otherSocket].isSocketBusy() && (channels[otherSocket].state != QHttpNetworkConnectionChannel::ClosingState)) {
224                 // this was the first socket to fail.
225                 channels[i].close();
226                 emitError = false;
227             }
228             else {
229                 // Both connection attempts has failed.
230                 networkLayerState = QHttpNetworkConnectionPrivate::Unknown;
231                 channels[i].close();
232                 emitError = true;
233             }
234         } else {
235             if (((networkLayerState == QHttpNetworkConnectionPrivate::IPv4) && (channels[i].networkLayerPreference != QAbstractSocket::IPv4Protocol))
236                 || ((networkLayerState == QHttpNetworkConnectionPrivate::IPv6) && (channels[i].networkLayerPreference != QAbstractSocket::IPv6Protocol))) {
237                 // First connection worked so this is the second one to complete and it failed.
238                 channels[i].close();
239                 QMetaObject::invokeMethod(q, "_q_startNextRequest", Qt::QueuedConnection);
240                 emitError = false;
241             }
242             if (networkLayerState == QHttpNetworkConnectionPrivate::Unknown)
243                 qWarning("We got a connection error when networkLayerState is Unknown");
244         }
245     }
246     return emitError;
247 }
248 
249 
uncompressedBytesAvailable(const QHttpNetworkReply & reply) const250 qint64 QHttpNetworkConnectionPrivate::uncompressedBytesAvailable(const QHttpNetworkReply &reply) const
251 {
252     return reply.d_func()->responseData.byteAmount();
253 }
254 
uncompressedBytesAvailableNextBlock(const QHttpNetworkReply & reply) const255 qint64 QHttpNetworkConnectionPrivate::uncompressedBytesAvailableNextBlock(const QHttpNetworkReply &reply) const
256 {
257     return reply.d_func()->responseData.sizeNextBlock();
258 }
259 
prepareRequest(HttpMessagePair & messagePair)260 void QHttpNetworkConnectionPrivate::prepareRequest(HttpMessagePair &messagePair)
261 {
262     QHttpNetworkRequest &request = messagePair.first;
263     QHttpNetworkReply *reply = messagePair.second;
264 
265     // add missing fields for the request
266     QByteArray value;
267     // check if Content-Length is provided
268     QNonContiguousByteDevice* uploadByteDevice = request.uploadByteDevice();
269     if (uploadByteDevice) {
270         const qint64 contentLength = request.contentLength();
271         const qint64 uploadDeviceSize = uploadByteDevice->size();
272         if (contentLength != -1 && uploadDeviceSize != -1) {
273             // both values known, take the smaller one.
274             request.setContentLength(qMin(uploadDeviceSize, contentLength));
275         } else if (contentLength == -1 && uploadDeviceSize != -1) {
276             // content length not supplied by user, but the upload device knows it
277             request.setContentLength(uploadDeviceSize);
278         } else if (contentLength != -1 && uploadDeviceSize == -1) {
279             // everything OK, the user supplied us the contentLength
280         } else if (Q_UNLIKELY(contentLength == -1 && uploadDeviceSize == -1)) {
281             qFatal("QHttpNetworkConnectionPrivate: Neither content-length nor upload device size were given");
282         }
283     }
284     // set the Connection/Proxy-Connection: Keep-Alive headers
285 #ifndef QT_NO_NETWORKPROXY
286     if (networkProxy.type() == QNetworkProxy::HttpCachingProxy)  {
287         value = request.headerField("proxy-connection");
288         if (value.isEmpty())
289             request.setHeaderField("Proxy-Connection", "Keep-Alive");
290     } else {
291 #endif
292         value = request.headerField("connection");
293         if (value.isEmpty())
294             request.setHeaderField("Connection", "Keep-Alive");
295 #ifndef QT_NO_NETWORKPROXY
296     }
297 #endif
298 
299     // If the request had a accept-encoding set, we better not mess
300     // with it. If it was not set, we announce that we understand gzip
301     // and remember this fact in request.d->autoDecompress so that
302     // we can later decompress the HTTP reply if it has such an
303     // encoding.
304     value = request.headerField("accept-encoding");
305     if (value.isEmpty()) {
306 #ifndef QT_NO_COMPRESS
307         request.setHeaderField("Accept-Encoding", "gzip, deflate");
308         request.d->autoDecompress = true;
309 #else
310         // if zlib is not available set this to false always
311         request.d->autoDecompress = false;
312 #endif
313     }
314 
315     // some websites mandate an accept-language header and fail
316     // if it is not sent. This is a problem with the website and
317     // not with us, but we work around this by setting
318     // one always.
319     value = request.headerField("accept-language");
320     if (value.isEmpty()) {
321         QString systemLocale = QLocale::system().name().replace(QChar::fromLatin1('_'),QChar::fromLatin1('-'));
322         QString acceptLanguage;
323         if (systemLocale == QLatin1String("C"))
324             acceptLanguage = QString::fromLatin1("en,*");
325         else if (systemLocale.startsWith(QLatin1String("en-")))
326             acceptLanguage = systemLocale + QLatin1String(",*");
327         else
328             acceptLanguage = systemLocale + QLatin1String(",en,*");
329         request.setHeaderField("Accept-Language", std::move(acceptLanguage).toLatin1());
330     }
331 
332     // set the User Agent
333     value = request.headerField("user-agent");
334     if (value.isEmpty())
335         request.setHeaderField("User-Agent", "Mozilla/5.0");
336     // set the host
337     value = request.headerField("host");
338     if (value.isEmpty()) {
339         QHostAddress add;
340         QByteArray host;
341         if (add.setAddress(hostName)) {
342             if (add.protocol() == QAbstractSocket::IPv6Protocol)
343                 host = '[' + hostName.toLatin1() + ']'; //format the ipv6 in the standard way
344             else
345                 host = hostName.toLatin1();
346 
347         } else {
348             host = QUrl::toAce(hostName);
349         }
350 
351         int port = request.url().port();
352         if (port != -1) {
353             host += ':';
354             host += QByteArray::number(port);
355         }
356 
357         request.prependHeaderField("Host", host);
358     }
359 
360     reply->d_func()->requestIsPrepared = true;
361 }
362 
363 
364 
365 
emitReplyError(QAbstractSocket * socket,QHttpNetworkReply * reply,QNetworkReply::NetworkError errorCode)366 void QHttpNetworkConnectionPrivate::emitReplyError(QAbstractSocket *socket,
367                                                    QHttpNetworkReply *reply,
368                                                    QNetworkReply::NetworkError errorCode)
369 {
370     Q_Q(QHttpNetworkConnection);
371 
372     int i = 0;
373     if (socket)
374         i = indexOf(socket);
375 
376     if (reply) {
377         // this error matters only to this reply
378         reply->d_func()->errorString = errorDetail(errorCode, socket);
379         emit reply->finishedWithError(errorCode, reply->d_func()->errorString);
380         // remove the corrupt data if any
381         reply->d_func()->eraseData();
382 
383         // Clean the channel
384         channels[i].close();
385         channels[i].reply = nullptr;
386         if (channels[i].protocolHandler)
387             channels[i].protocolHandler->setReply(nullptr);
388         channels[i].request = QHttpNetworkRequest();
389         if (socket)
390             channels[i].requeueCurrentlyPipelinedRequests();
391 
392         // send the next request
393         QMetaObject::invokeMethod(q, "_q_startNextRequest", Qt::QueuedConnection);
394     }
395 }
396 
copyCredentials(int fromChannel,QAuthenticator * auth,bool isProxy)397 void QHttpNetworkConnectionPrivate::copyCredentials(int fromChannel, QAuthenticator *auth, bool isProxy)
398 {
399     Q_ASSERT(auth);
400 
401     // NTLM and Negotiate do multi-phase authentication.
402     // Copying credentialsbetween authenticators would mess things up.
403     if (fromChannel >= 0) {
404         const QHttpNetworkConnectionChannel &channel = channels[fromChannel];
405         const QAuthenticatorPrivate::Method method = isProxy ? channel.proxyAuthMethod : channel.authMethod;
406         if (method == QAuthenticatorPrivate::Ntlm || method == QAuthenticatorPrivate::Negotiate)
407             return;
408     }
409 
410     // select another channel
411     QAuthenticator* otherAuth = nullptr;
412     for (int i = 0; i < activeChannelCount; ++i) {
413         if (i == fromChannel)
414             continue;
415         if (isProxy)
416             otherAuth = &channels[i].proxyAuthenticator;
417         else
418             otherAuth = &channels[i].authenticator;
419         // if the credentials are different, copy them
420         if (otherAuth->user().compare(auth->user()))
421             otherAuth->setUser(auth->user());
422         if (otherAuth->password().compare(auth->password()))
423             otherAuth->setPassword(auth->password());
424     }
425 }
426 
427 
428 // handles the authentication for one channel and eventually re-starts the other channels
handleAuthenticateChallenge(QAbstractSocket * socket,QHttpNetworkReply * reply,bool isProxy,bool & resend)429 bool QHttpNetworkConnectionPrivate::handleAuthenticateChallenge(QAbstractSocket *socket, QHttpNetworkReply *reply,
430                                                                 bool isProxy, bool &resend)
431 {
432     Q_ASSERT(socket);
433     Q_ASSERT(reply);
434 
435     resend = false;
436     //create the response header to be used with QAuthenticatorPrivate.
437     QList<QPair<QByteArray, QByteArray> > fields = reply->header();
438 
439     //find out the type of authentication protocol requested.
440     QAuthenticatorPrivate::Method authMethod = reply->d_func()->authenticationMethod(isProxy);
441     if (authMethod != QAuthenticatorPrivate::None) {
442         int i = indexOf(socket);
443         //Use a single authenticator for all domains. ### change later to use domain/realm
444         QAuthenticator* auth = nullptr;
445         if (isProxy) {
446             auth = &channels[i].proxyAuthenticator;
447             channels[i].proxyAuthMethod = authMethod;
448         } else {
449             auth = &channels[i].authenticator;
450             channels[i].authMethod = authMethod;
451         }
452         //proceed with the authentication.
453         if (auth->isNull())
454             auth->detach();
455         QAuthenticatorPrivate *priv = QAuthenticatorPrivate::getPrivate(*auth);
456         priv->parseHttpResponse(fields, isProxy, reply->url().host());
457         // Update method in case it changed
458         if (priv->method == QAuthenticatorPrivate::None)
459             return false;
460         if (isProxy)
461             channels[i].proxyAuthMethod = priv->method;
462         else
463             channels[i].authMethod = priv->method;
464 
465         if (priv->phase == QAuthenticatorPrivate::Done) {
466             pauseConnection();
467             if (!isProxy) {
468                 if (channels[i].authenticationCredentialsSent) {
469                     auth->detach();
470                     priv = QAuthenticatorPrivate::getPrivate(*auth);
471                     priv->hasFailed = true;
472                     priv->phase = QAuthenticatorPrivate::Done;
473                     channels[i].authenticationCredentialsSent = false;
474                 }
475                 emit reply->authenticationRequired(reply->request(), auth);
476 #ifndef QT_NO_NETWORKPROXY
477             } else {
478                 if (channels[i].proxyCredentialsSent) {
479                     auth->detach();
480                     priv = QAuthenticatorPrivate::getPrivate(*auth);
481                     priv->hasFailed = true;
482                     priv->phase = QAuthenticatorPrivate::Done;
483                     channels[i].proxyCredentialsSent = false;
484                 }
485                 emit reply->proxyAuthenticationRequired(networkProxy, auth);
486 #endif
487             }
488             resumeConnection();
489 
490             if (priv->phase != QAuthenticatorPrivate::Done) {
491                 // send any pending requests
492                 copyCredentials(i,  auth, isProxy);
493             }
494         } else if (priv->phase == QAuthenticatorPrivate::Start) {
495             // If the url's authenticator has a 'user' set we will end up here (phase is only set to 'Done' by
496             // parseHttpResponse above if 'user' is empty). So if credentials were supplied with the request,
497             // such as in the case of an XMLHttpRequest, this is our only opportunity to cache them.
498             emit reply->cacheCredentials(reply->request(), auth);
499         }
500         // - Changing values in QAuthenticator will reset the 'phase'. Therefore if it is still "Done"
501         //   then nothing was filled in by the user or the cache
502         // - If withCredentials has been set to false (e.g. by Qt WebKit for a cross-origin XMLHttpRequest) then
503         //   we need to bail out if authentication is required.
504         if (priv->phase == QAuthenticatorPrivate::Done || !reply->request().withCredentials()) {
505             // Reset authenticator so the next request on that channel does not get messed up
506             auth = nullptr;
507             if (isProxy)
508                 channels[i].proxyAuthenticator = QAuthenticator();
509             else
510                 channels[i].authenticator = QAuthenticator();
511 
512             // authentication is cancelled, send the current contents to the user.
513             emit channels[i].reply->headerChanged();
514             emit channels[i].reply->readyRead();
515             QNetworkReply::NetworkError errorCode =
516                 isProxy
517                 ? QNetworkReply::ProxyAuthenticationRequiredError
518                 : QNetworkReply::AuthenticationRequiredError;
519             reply->d_func()->errorString = errorDetail(errorCode, socket);
520             emit reply->finishedWithError(errorCode, reply->d_func()->errorString);
521             // ### at this point the reply could be deleted
522             return true;
523         }
524         //resend the request
525         resend = true;
526         return true;
527     }
528     return false;
529 }
530 
parseRedirectResponse(QAbstractSocket * socket,QHttpNetworkReply * reply)531 QUrl QHttpNetworkConnectionPrivate::parseRedirectResponse(QAbstractSocket *socket, QHttpNetworkReply *reply)
532 {
533     if (!reply->request().isFollowRedirects())
534         return QUrl();
535 
536     QUrl redirectUrl;
537     const QList<QPair<QByteArray, QByteArray> > fields = reply->header();
538     for (const QNetworkReply::RawHeaderPair &header : fields) {
539         if (header.first.compare("location", Qt::CaseInsensitive) == 0) {
540             redirectUrl = QUrl::fromEncoded(header.second);
541             break;
542         }
543     }
544 
545     // If the location url is invalid/empty, we emit ProtocolUnknownError
546     if (!redirectUrl.isValid()) {
547         emitReplyError(socket, reply, QNetworkReply::ProtocolUnknownError);
548         return QUrl();
549     }
550 
551     // Check if we have exceeded max redirects allowed
552     if (reply->request().redirectCount() <= 0) {
553         emitReplyError(socket, reply, QNetworkReply::TooManyRedirectsError);
554         return QUrl();
555     }
556 
557     // Resolve the URL if it's relative
558     if (redirectUrl.isRelative())
559         redirectUrl = reply->request().url().resolved(redirectUrl);
560 
561     // Check redirect url protocol
562     const QUrl priorUrl(reply->request().url());
563     if (redirectUrl.scheme() == QLatin1String("http") || redirectUrl.scheme() == QLatin1String("https")) {
564         switch (reply->request().redirectPolicy()) {
565         case QNetworkRequest::NoLessSafeRedirectPolicy:
566             // Here we could handle https->http redirects as InsecureProtocolError.
567             // However, if HSTS is enabled and redirectUrl.host() is a known STS
568             // host, then we'll replace its scheme and this won't downgrade protocol,
569             // after all.  We cannot access QNAM's STS cache from here, so delegate
570             // this check to QNetworkReplyHttpImpl.
571             break;
572         case QNetworkRequest::SameOriginRedirectPolicy:
573             if (priorUrl.host() != redirectUrl.host()
574                 || priorUrl.scheme() != redirectUrl.scheme()
575                 || priorUrl.port() != redirectUrl.port()) {
576                 emitReplyError(socket, reply, QNetworkReply::InsecureRedirectError);
577                 return QUrl();
578             }
579             break;
580         case QNetworkRequest::UserVerifiedRedirectPolicy:
581             break;
582         default:
583             Q_ASSERT(!"Unexpected redirect policy");
584         }
585     } else {
586         emitReplyError(socket, reply, QNetworkReply::ProtocolUnknownError);
587         return QUrl();
588     }
589     return redirectUrl;
590 }
591 
createAuthorization(QAbstractSocket * socket,QHttpNetworkRequest & request)592 void QHttpNetworkConnectionPrivate::createAuthorization(QAbstractSocket *socket, QHttpNetworkRequest &request)
593 {
594     Q_ASSERT(socket);
595 
596     int i = indexOf(socket);
597 
598     // Send "Authorization" header, but not if it's NTLM and the socket is already authenticated.
599     if (channels[i].authMethod != QAuthenticatorPrivate::None) {
600         if ((channels[i].authMethod != QAuthenticatorPrivate::Ntlm && request.headerField("Authorization").isEmpty()) || channels[i].lastStatus == 401) {
601             QAuthenticatorPrivate *priv = QAuthenticatorPrivate::getPrivate(channels[i].authenticator);
602             if (priv && priv->method != QAuthenticatorPrivate::None) {
603                 QByteArray response = priv->calculateResponse(request.methodName(), request.uri(false), request.url().host());
604                 request.setHeaderField("Authorization", response);
605                 channels[i].authenticationCredentialsSent = true;
606             }
607         }
608     }
609 
610 #if QT_CONFIG(networkproxy)
611     // Send "Proxy-Authorization" header, but not if it's NTLM and the socket is already authenticated.
612     if (channels[i].proxyAuthMethod != QAuthenticatorPrivate::None) {
613         if (!(channels[i].proxyAuthMethod == QAuthenticatorPrivate::Ntlm && channels[i].lastStatus != 407)) {
614             QAuthenticatorPrivate *priv = QAuthenticatorPrivate::getPrivate(channels[i].proxyAuthenticator);
615             if (priv && priv->method != QAuthenticatorPrivate::None) {
616                 QByteArray response = priv->calculateResponse(request.methodName(), request.uri(false), networkProxy.hostName());
617                 request.setHeaderField("Proxy-Authorization", response);
618                 channels[i].proxyCredentialsSent = true;
619             }
620         }
621     }
622 #endif // QT_CONFIG(networkproxy)
623 }
624 
queueRequest(const QHttpNetworkRequest & request)625 QHttpNetworkReply* QHttpNetworkConnectionPrivate::queueRequest(const QHttpNetworkRequest &request)
626 {
627     Q_Q(QHttpNetworkConnection);
628 
629     // The reply component of the pair is created initially.
630     QHttpNetworkReply *reply = new QHttpNetworkReply(request.url());
631     reply->setRequest(request);
632     reply->d_func()->connection = q;
633     reply->d_func()->connectionChannel = &channels[0]; // will have the correct one set later
634     HttpMessagePair pair = qMakePair(request, reply);
635 
636     if (request.isPreConnect())
637         preConnectRequests++;
638 
639     if (connectionType == QHttpNetworkConnection::ConnectionTypeHTTP
640         || (!encrypt && connectionType == QHttpNetworkConnection::ConnectionTypeHTTP2 && !channels[0].switchedToHttp2)) {
641         switch (request.priority()) {
642         case QHttpNetworkRequest::HighPriority:
643             highPriorityQueue.prepend(pair);
644             break;
645         case QHttpNetworkRequest::NormalPriority:
646         case QHttpNetworkRequest::LowPriority:
647             lowPriorityQueue.prepend(pair);
648             break;
649         }
650     }
651     else { // SPDY, HTTP/2 ('h2' mode)
652         if (!pair.second->d_func()->requestIsPrepared)
653             prepareRequest(pair);
654         channels[0].spdyRequestsToSend.insert(request.priority(), pair);
655     }
656 
657 #ifndef Q_OS_WINRT
658     // For Happy Eyeballs the networkLayerState is set to Unknown
659     // until we have started the first connection attempt. So no
660     // request will be started until we know if IPv4 or IPv6
661     // should be used.
662     if (networkLayerState == Unknown || networkLayerState == HostLookupPending) {
663         startHostInfoLookup();
664     } else if ( networkLayerState == IPv4 || networkLayerState == IPv6 ) {
665 #else // !Q_OS_WINRT
666     {
667         // Skip the host lookup part for winrt. Host lookup and proxy handling are done by Windows
668         // internally and networkLayerPreference is ignored on this platform. Instead of refactoring
669         // the whole approach we just pretend that everything important is known here.
670         networkLayerState = IPv4;
671 #endif
672         // this used to be called via invokeMethod and a QueuedConnection
673         // It is the only place _q_startNextRequest is called directly without going
674         // through the event loop using a QueuedConnection.
675         // This is dangerous because of recursion that might occur when emitting
676         // signals as DirectConnection from this code path. Therefore all signal
677         // emissions that can come out from this code path need to
678         // be QueuedConnection.
679         // We are currently trying to fine-tune this.
680         _q_startNextRequest();
681     }
682     return reply;
683 }
684 
685 void QHttpNetworkConnectionPrivate::fillHttp2Queue()
686 {
687     for (auto &pair : highPriorityQueue) {
688         if (!pair.second->d_func()->requestIsPrepared)
689             prepareRequest(pair);
690         channels[0].spdyRequestsToSend.insert(QHttpNetworkRequest::HighPriority, pair);
691     }
692 
693     highPriorityQueue.clear();
694 
695     for (auto &pair : lowPriorityQueue) {
696         if (!pair.second->d_func()->requestIsPrepared)
697             prepareRequest(pair);
698         channels[0].spdyRequestsToSend.insert(pair.first.priority(), pair);
699     }
700 
701     lowPriorityQueue.clear();
702 }
703 
704 void QHttpNetworkConnectionPrivate::requeueRequest(const HttpMessagePair &pair)
705 {
706     Q_Q(QHttpNetworkConnection);
707 
708     QHttpNetworkRequest request = pair.first;
709     switch (request.priority()) {
710     case QHttpNetworkRequest::HighPriority:
711         highPriorityQueue.prepend(pair);
712         break;
713     case QHttpNetworkRequest::NormalPriority:
714     case QHttpNetworkRequest::LowPriority:
715         lowPriorityQueue.prepend(pair);
716         break;
717     }
718 
719     QMetaObject::invokeMethod(q, "_q_startNextRequest", Qt::QueuedConnection);
720 }
721 
722 bool QHttpNetworkConnectionPrivate::dequeueRequest(QAbstractSocket *socket)
723 {
724     int i = 0;
725     if (socket)
726         i = indexOf(socket);
727 
728     if (!highPriorityQueue.isEmpty()) {
729         // remove from queue before sendRequest! else we might pipeline the same request again
730         HttpMessagePair messagePair = highPriorityQueue.takeLast();
731         if (!messagePair.second->d_func()->requestIsPrepared)
732             prepareRequest(messagePair);
733         updateChannel(i, messagePair);
734         return true;
735     }
736 
737     if (!lowPriorityQueue.isEmpty()) {
738         // remove from queue before sendRequest! else we might pipeline the same request again
739         HttpMessagePair messagePair = lowPriorityQueue.takeLast();
740         if (!messagePair.second->d_func()->requestIsPrepared)
741             prepareRequest(messagePair);
742         updateChannel(i, messagePair);
743         return true;
744     }
745     return false;
746 }
747 
748 void QHttpNetworkConnectionPrivate::updateChannel(int i, const HttpMessagePair &messagePair)
749 {
750     channels[i].request = messagePair.first;
751     channels[i].reply = messagePair.second;
752     // Now that reply is assigned a channel, correct reply to channel association
753     // previously set in queueRequest.
754     channels[i].reply->d_func()->connectionChannel = &channels[i];
755 }
756 
757 QHttpNetworkRequest QHttpNetworkConnectionPrivate::predictNextRequest() const
758 {
759     if (!highPriorityQueue.isEmpty())
760         return highPriorityQueue.last().first;
761     if (!lowPriorityQueue.isEmpty())
762         return lowPriorityQueue.last().first;
763     return QHttpNetworkRequest();
764 }
765 
766 // this is called from _q_startNextRequest and when a request has been sent down a socket from the channel
767 void QHttpNetworkConnectionPrivate::fillPipeline(QAbstractSocket *socket)
768 {
769     // return fast if there is nothing to pipeline
770     if (highPriorityQueue.isEmpty() && lowPriorityQueue.isEmpty())
771         return;
772 
773     int i = indexOf(socket);
774 
775     // return fast if there was no reply right now processed
776     if (channels[i].reply == nullptr)
777         return;
778 
779     if (! (defaultPipelineLength - channels[i].alreadyPipelinedRequests.length() >= defaultRePipelineLength)) {
780         return;
781     }
782 
783     if (channels[i].pipeliningSupported != QHttpNetworkConnectionChannel::PipeliningProbablySupported)
784         return;
785 
786     // the current request that is in must already support pipelining
787     if (!channels[i].request.isPipeliningAllowed())
788         return;
789 
790     // the current request must be a idempotent (right now we only check GET)
791     if (channels[i].request.operation() != QHttpNetworkRequest::Get)
792         return;
793 
794     // check if socket is connected
795     if (socket->state() != QAbstractSocket::ConnectedState)
796         return;
797 
798     // check for resendCurrent
799     if (channels[i].resendCurrent)
800         return;
801 
802     // we do not like authentication stuff
803     // ### make sure to be OK with this in later releases
804     if (!channels[i].authenticator.isNull()
805         && (!channels[i].authenticator.user().isEmpty()
806             || !channels[i].authenticator.password().isEmpty()))
807         return;
808     if (!channels[i].proxyAuthenticator.isNull()
809         && (!channels[i].proxyAuthenticator.user().isEmpty()
810             || !channels[i].proxyAuthenticator.password().isEmpty()))
811         return;
812 
813     // must be in ReadingState or WaitingState
814     if (! (channels[i].state == QHttpNetworkConnectionChannel::WaitingState
815            || channels[i].state == QHttpNetworkConnectionChannel::ReadingState))
816         return;
817 
818     int lengthBefore;
819     while (!highPriorityQueue.isEmpty()) {
820         lengthBefore = channels[i].alreadyPipelinedRequests.length();
821         fillPipeline(highPriorityQueue, channels[i]);
822 
823         if (channels[i].alreadyPipelinedRequests.length() >= defaultPipelineLength) {
824             channels[i].pipelineFlush();
825             return;
826         }
827 
828         if (lengthBefore == channels[i].alreadyPipelinedRequests.length())
829             break; // did not process anything, now do the low prio queue
830     }
831 
832     while (!lowPriorityQueue.isEmpty()) {
833         lengthBefore = channels[i].alreadyPipelinedRequests.length();
834         fillPipeline(lowPriorityQueue, channels[i]);
835 
836         if (channels[i].alreadyPipelinedRequests.length() >= defaultPipelineLength) {
837             channels[i].pipelineFlush();
838             return;
839         }
840 
841         if (lengthBefore == channels[i].alreadyPipelinedRequests.length())
842             break; // did not process anything
843     }
844 
845 
846     channels[i].pipelineFlush();
847 }
848 
849 // returns true when the processing of a queue has been done
850 bool QHttpNetworkConnectionPrivate::fillPipeline(QList<HttpMessagePair> &queue, QHttpNetworkConnectionChannel &channel)
851 {
852     if (queue.isEmpty())
853         return true;
854 
855     for (int i = queue.count() - 1; i >= 0; --i) {
856         HttpMessagePair messagePair = queue.at(i);
857         const QHttpNetworkRequest &request = messagePair.first;
858 
859         // we currently do not support pipelining if HTTP authentication is used
860         if (!request.url().userInfo().isEmpty())
861             continue;
862 
863         // take only GET requests
864         if (request.operation() != QHttpNetworkRequest::Get)
865             continue;
866 
867         if (!request.isPipeliningAllowed())
868             continue;
869 
870         // remove it from the queue
871         queue.takeAt(i);
872         // we modify the queue we iterate over here, but since we return from the function
873         // afterwards this is fine.
874 
875         // actually send it
876         if (!messagePair.second->d_func()->requestIsPrepared)
877             prepareRequest(messagePair);
878         channel.pipelineInto(messagePair);
879 
880         // return false because we processed something and need to process again
881         return false;
882     }
883 
884     // return true, the queue has been processed and not changed
885     return true;
886 }
887 
888 
889 QString QHttpNetworkConnectionPrivate::errorDetail(QNetworkReply::NetworkError errorCode, QAbstractSocket *socket, const QString &extraDetail)
890 {
891     QString errorString;
892     switch (errorCode) {
893     case QNetworkReply::HostNotFoundError:
894         if (socket)
895             errorString = QCoreApplication::translate("QHttp", "Host %1 not found").arg(socket->peerName());
896         else
897             errorString = QCoreApplication::translate("QHttp", "Host %1 not found").arg(hostName);
898         break;
899     case QNetworkReply::ConnectionRefusedError:
900         errorString = QCoreApplication::translate("QHttp", "Connection refused");
901         break;
902     case QNetworkReply::RemoteHostClosedError:
903         errorString = QCoreApplication::translate("QHttp", "Connection closed");
904         break;
905     case QNetworkReply::TimeoutError:
906         errorString = QCoreApplication::translate("QAbstractSocket", "Socket operation timed out");
907         break;
908     case QNetworkReply::ProxyAuthenticationRequiredError:
909         errorString = QCoreApplication::translate("QHttp", "Proxy requires authentication");
910         break;
911     case QNetworkReply::AuthenticationRequiredError:
912         errorString = QCoreApplication::translate("QHttp", "Host requires authentication");
913         break;
914     case QNetworkReply::ProtocolFailure:
915         errorString = QCoreApplication::translate("QHttp", "Data corrupted");
916         break;
917     case QNetworkReply::ProtocolUnknownError:
918         errorString = QCoreApplication::translate("QHttp", "Unknown protocol specified");
919         break;
920     case QNetworkReply::SslHandshakeFailedError:
921         errorString = QCoreApplication::translate("QHttp", "SSL handshake failed");
922         break;
923     case QNetworkReply::TooManyRedirectsError:
924         errorString = QCoreApplication::translate("QHttp", "Too many redirects");
925         break;
926     case QNetworkReply::InsecureRedirectError:
927         errorString = QCoreApplication::translate("QHttp", "Insecure redirect");
928         break;
929     default:
930         // all other errors are treated as QNetworkReply::UnknownNetworkError
931         errorString = extraDetail;
932         break;
933     }
934     return errorString;
935 }
936 
937 // this is called from the destructor of QHttpNetworkReply. It is called when
938 // the reply was finished correctly or when it was aborted.
939 void QHttpNetworkConnectionPrivate::removeReply(QHttpNetworkReply *reply)
940 {
941     Q_Q(QHttpNetworkConnection);
942 
943     // check if the reply is currently being processed or it is pipelined in
944     for (int i = 0; i < activeChannelCount; ++i) {
945         // is the reply associated the currently processing of this channel?
946         if (channels[i].reply == reply) {
947             channels[i].reply = nullptr;
948             if (channels[i].protocolHandler)
949                 channels[i].protocolHandler->setReply(nullptr);
950             channels[i].request = QHttpNetworkRequest();
951             channels[i].resendCurrent = false;
952 
953             if (!reply->isFinished() && !channels[i].alreadyPipelinedRequests.isEmpty()) {
954                 // the reply had to be prematurely removed, e.g. it was not finished
955                 // therefore we have to requeue the already pipelined requests.
956                 channels[i].requeueCurrentlyPipelinedRequests();
957             }
958 
959             // if HTTP mandates we should close
960             // or the reply is not finished yet, e.g. it was aborted
961             // we have to close that connection
962             if (reply->d_func()->isConnectionCloseEnabled() || !reply->isFinished()) {
963                 if (reply->isAborted()) {
964                     channels[i].abort();
965                 } else {
966                     channels[i].close();
967                 }
968             }
969 
970             QMetaObject::invokeMethod(q, "_q_startNextRequest", Qt::QueuedConnection);
971             return;
972         }
973 
974         // is the reply inside the pipeline of this channel already?
975         for (int j = 0; j < channels[i].alreadyPipelinedRequests.length(); j++) {
976             if (channels[i].alreadyPipelinedRequests.at(j).second == reply) {
977                // Remove that HttpMessagePair
978                channels[i].alreadyPipelinedRequests.removeAt(j);
979 
980                channels[i].requeueCurrentlyPipelinedRequests();
981 
982                // Since some requests had already been pipelined, but we removed
983                // one and re-queued the others
984                // we must force a connection close after the request that is
985                // currently in processing has been finished.
986                if (channels[i].reply)
987                    channels[i].reply->d_func()->forceConnectionCloseEnabled = true;
988 
989                QMetaObject::invokeMethod(q, "_q_startNextRequest", Qt::QueuedConnection);
990                return;
991             }
992         }
993 #ifndef QT_NO_SSL
994         // is the reply inside the SPDY pipeline of this channel already?
995         QMultiMap<int, HttpMessagePair>::iterator it = channels[i].spdyRequestsToSend.begin();
996         QMultiMap<int, HttpMessagePair>::iterator end = channels[i].spdyRequestsToSend.end();
997         for (; it != end; ++it) {
998             if (it.value().second == reply) {
999                 channels[i].spdyRequestsToSend.remove(it.key());
1000 
1001                 QMetaObject::invokeMethod(q, "_q_startNextRequest", Qt::QueuedConnection);
1002                 return;
1003             }
1004         }
1005 #endif
1006     }
1007     // remove from the high priority queue
1008     if (!highPriorityQueue.isEmpty()) {
1009         for (int j = highPriorityQueue.count() - 1; j >= 0; --j) {
1010             HttpMessagePair messagePair = highPriorityQueue.at(j);
1011             if (messagePair.second == reply) {
1012                 highPriorityQueue.removeAt(j);
1013                 QMetaObject::invokeMethod(q, "_q_startNextRequest", Qt::QueuedConnection);
1014                 return;
1015             }
1016         }
1017     }
1018     // remove from the low priority queue
1019     if (!lowPriorityQueue.isEmpty()) {
1020         for (int j = lowPriorityQueue.count() - 1; j >= 0; --j) {
1021             HttpMessagePair messagePair = lowPriorityQueue.at(j);
1022             if (messagePair.second == reply) {
1023                 lowPriorityQueue.removeAt(j);
1024                 QMetaObject::invokeMethod(q, "_q_startNextRequest", Qt::QueuedConnection);
1025                 return;
1026             }
1027         }
1028     }
1029 }
1030 
1031 
1032 
1033 // This function must be called from the event loop. The only
1034 // exception is documented in QHttpNetworkConnectionPrivate::queueRequest
1035 // although it is called _q_startNextRequest, it will actually start multiple requests when possible
1036 void QHttpNetworkConnectionPrivate::_q_startNextRequest()
1037 {
1038     // If there is no network layer state decided we should not start any new requests.
1039     if (networkLayerState == Unknown || networkLayerState == HostLookupPending || networkLayerState == IPv4or6)
1040         return;
1041 
1042     // If the QHttpNetworkConnection is currently paused then bail out immediately
1043     if (state == PausedState)
1044         return;
1045 
1046     //resend the necessary ones.
1047     for (int i = 0; i < activeChannelCount; ++i) {
1048         if (channels[i].resendCurrent && (channels[i].state != QHttpNetworkConnectionChannel::ClosingState)) {
1049             channels[i].resendCurrent = false;
1050 
1051             // if this is not possible, error will be emitted and connection terminated
1052             if (!channels[i].resetUploadData())
1053                 continue;
1054             channels[i].sendRequest();
1055         }
1056     }
1057 
1058     // dequeue new ones
1059 
1060     switch (connectionType) {
1061     case QHttpNetworkConnection::ConnectionTypeHTTP: {
1062         // return fast if there is nothing to do
1063         if (highPriorityQueue.isEmpty() && lowPriorityQueue.isEmpty())
1064             return;
1065 
1066         // try to get a free AND connected socket
1067         for (int i = 0; i < activeChannelCount; ++i) {
1068             if (channels[i].socket) {
1069                 if (!channels[i].reply && !channels[i].isSocketBusy() && channels[i].socket->state() == QAbstractSocket::ConnectedState) {
1070                     if (dequeueRequest(channels[i].socket))
1071                         channels[i].sendRequest();
1072                 }
1073             }
1074         }
1075         break;
1076     }
1077     case QHttpNetworkConnection::ConnectionTypeHTTP2Direct:
1078     case QHttpNetworkConnection::ConnectionTypeHTTP2:
1079     case QHttpNetworkConnection::ConnectionTypeSPDY: {
1080         if (channels[0].spdyRequestsToSend.isEmpty() && !channels[0].reply
1081             && highPriorityQueue.isEmpty() && lowPriorityQueue.isEmpty()) {
1082             return;
1083         }
1084 
1085         if (networkLayerState == IPv4)
1086             channels[0].networkLayerPreference = QAbstractSocket::IPv4Protocol;
1087         else if (networkLayerState == IPv6)
1088             channels[0].networkLayerPreference = QAbstractSocket::IPv6Protocol;
1089         channels[0].ensureConnection();
1090         if (channels[0].socket && channels[0].socket->state() == QAbstractSocket::ConnectedState
1091                 && !channels[0].pendingEncrypt && channels[0].spdyRequestsToSend.size())
1092             channels[0].sendRequest();
1093         break;
1094     }
1095     }
1096 
1097     // try to push more into all sockets
1098     // ### FIXME we should move this to the beginning of the function
1099     // as soon as QtWebkit is properly using the pipelining
1100     // (e.g. not for XMLHttpRequest or the first page load)
1101     // ### FIXME we should also divide the requests more even
1102     // on the connected sockets
1103     //tryToFillPipeline(socket);
1104     // return fast if there is nothing to pipeline
1105     if (highPriorityQueue.isEmpty() && lowPriorityQueue.isEmpty())
1106         return;
1107     for (int i = 0; i < activeChannelCount; i++)
1108         if (channels[i].socket && channels[i].socket->state() == QAbstractSocket::ConnectedState)
1109             fillPipeline(channels[i].socket);
1110 
1111     // If there is not already any connected channels we need to connect a new one.
1112     // We do not pair the channel with the request until we know if it is
1113     // connected or not. This is to reuse connected channels before we connect new once.
1114     int queuedRequests = highPriorityQueue.count() + lowPriorityQueue.count();
1115 
1116     // in case we have in-flight preconnect requests and normal requests,
1117     // we only need one socket for each (preconnect, normal request) pair
1118     int neededOpenChannels = queuedRequests;
1119     if (preConnectRequests > 0) {
1120         int normalRequests = queuedRequests - preConnectRequests;
1121         neededOpenChannels = qMax(normalRequests, preConnectRequests);
1122     }
1123 
1124     if (neededOpenChannels <= 0)
1125         return;
1126 
1127     QQueue<int> channelsToConnect;
1128 
1129     // use previously used channels first
1130     for (int i = 0; i < activeChannelCount && neededOpenChannels > 0; ++i) {
1131         if (!channels[i].socket)
1132             continue;
1133 
1134         if ((channels[i].socket->state() == QAbstractSocket::ConnectingState)
1135             || (channels[i].socket->state() == QAbstractSocket::HostLookupState)
1136             || channels[i].pendingEncrypt) { // pendingEncrypt == "EncryptingState"
1137             neededOpenChannels--;
1138             continue;
1139         }
1140 
1141         if (!channels[i].reply && !channels[i].isSocketBusy()
1142             && (channels[i].socket->state() == QAbstractSocket::UnconnectedState)) {
1143             channelsToConnect.enqueue(i);
1144             neededOpenChannels--;
1145         }
1146     }
1147 
1148     // use other channels
1149     for (int i = 0; i < activeChannelCount && neededOpenChannels > 0; ++i) {
1150         if (channels[i].socket)
1151             continue;
1152 
1153         channelsToConnect.enqueue(i);
1154         neededOpenChannels--;
1155     }
1156 
1157     while (!channelsToConnect.isEmpty()) {
1158         const int channel = channelsToConnect.dequeue();
1159 
1160         if (networkLayerState == IPv4)
1161             channels[channel].networkLayerPreference = QAbstractSocket::IPv4Protocol;
1162         else if (networkLayerState == IPv6)
1163             channels[channel].networkLayerPreference = QAbstractSocket::IPv6Protocol;
1164 
1165         channels[channel].ensureConnection();
1166     }
1167 }
1168 
1169 
1170 void QHttpNetworkConnectionPrivate::readMoreLater(QHttpNetworkReply *reply)
1171 {
1172     for (int i = 0 ; i < activeChannelCount; ++i) {
1173         if (channels[i].reply ==  reply) {
1174             // emulate a readyRead() from the socket
1175             QMetaObject::invokeMethod(&channels[i], "_q_readyRead", Qt::QueuedConnection);
1176             return;
1177         }
1178     }
1179 }
1180 
1181 
1182 
1183 // The first time we start the connection is used we do not know if we
1184 // should use IPv4 or IPv6. So we start a hostlookup to figure this out.
1185 // Later when we do the connection the socket will not need to do another
1186 // lookup as then the hostinfo will already be in the cache.
1187 void QHttpNetworkConnectionPrivate::startHostInfoLookup()
1188 {
1189     networkLayerState = HostLookupPending;
1190 
1191     // check if we already now can decide if this is IPv4 or IPv6
1192     QString lookupHost = hostName;
1193 #ifndef QT_NO_NETWORKPROXY
1194     if (networkProxy.capabilities() & QNetworkProxy::HostNameLookupCapability) {
1195         lookupHost = networkProxy.hostName();
1196     } else if (channels[0].proxy.capabilities() & QNetworkProxy::HostNameLookupCapability) {
1197         lookupHost = channels[0].proxy.hostName();
1198     }
1199 #endif
1200     QHostAddress temp;
1201     if (temp.setAddress(lookupHost)) {
1202         const QAbstractSocket::NetworkLayerProtocol protocol = temp.protocol();
1203         if (protocol == QAbstractSocket::IPv4Protocol) {
1204             networkLayerState = QHttpNetworkConnectionPrivate::IPv4;
1205             QMetaObject::invokeMethod(this->q_func(), "_q_startNextRequest", Qt::QueuedConnection);
1206             return;
1207         } else if (protocol == QAbstractSocket::IPv6Protocol) {
1208             networkLayerState = QHttpNetworkConnectionPrivate::IPv6;
1209             QMetaObject::invokeMethod(this->q_func(), "_q_startNextRequest", Qt::QueuedConnection);
1210             return;
1211         }
1212     } else {
1213         int hostLookupId;
1214         bool immediateResultValid = false;
1215         QHostInfo hostInfo = qt_qhostinfo_lookup(lookupHost,
1216                                                  this->q_func(),
1217                                                  SLOT(_q_hostLookupFinished(QHostInfo)),
1218                                                  &immediateResultValid,
1219                                                  &hostLookupId);
1220         if (immediateResultValid) {
1221             _q_hostLookupFinished(hostInfo);
1222         }
1223     }
1224 }
1225 
1226 
1227 void QHttpNetworkConnectionPrivate::_q_hostLookupFinished(const QHostInfo &info)
1228 {
1229     bool bIpv4 = false;
1230     bool bIpv6 = false;
1231     bool foundAddress = false;
1232     if (networkLayerState == IPv4 || networkLayerState == IPv6 || networkLayerState == IPv4or6)
1233         return;
1234 
1235     const auto addresses = info.addresses();
1236     for (const QHostAddress &address : addresses) {
1237         const QAbstractSocket::NetworkLayerProtocol protocol = address.protocol();
1238         if (protocol == QAbstractSocket::IPv4Protocol) {
1239             if (!foundAddress) {
1240                 foundAddress = true;
1241                 delayIpv4 = false;
1242             }
1243             bIpv4 = true;
1244         } else if (protocol == QAbstractSocket::IPv6Protocol) {
1245             if (!foundAddress) {
1246                 foundAddress = true;
1247                 delayIpv4 = true;
1248             }
1249             bIpv6 = true;
1250         }
1251     }
1252 
1253     if (bIpv4 && bIpv6)
1254         startNetworkLayerStateLookup();
1255     else if (bIpv4) {
1256         networkLayerState = QHttpNetworkConnectionPrivate::IPv4;
1257         QMetaObject::invokeMethod(this->q_func(), "_q_startNextRequest", Qt::QueuedConnection);
1258     } else if (bIpv6) {
1259         networkLayerState = QHttpNetworkConnectionPrivate::IPv6;
1260         QMetaObject::invokeMethod(this->q_func(), "_q_startNextRequest", Qt::QueuedConnection);
1261     } else {
1262         if (dequeueRequest(channels[0].socket)) {
1263             emitReplyError(channels[0].socket, channels[0].reply, QNetworkReply::HostNotFoundError);
1264             networkLayerState = QHttpNetworkConnectionPrivate::Unknown;
1265         } else if (connectionType == QHttpNetworkConnection::ConnectionTypeSPDY
1266                    || connectionType == QHttpNetworkConnection::ConnectionTypeHTTP2
1267                    || connectionType == QHttpNetworkConnection::ConnectionTypeHTTP2Direct) {
1268             for (const HttpMessagePair &spdyPair : qAsConst(channels[0].spdyRequestsToSend)) {
1269                 // emit error for all replies
1270                 QHttpNetworkReply *currentReply = spdyPair.second;
1271                 Q_ASSERT(currentReply);
1272                 emitReplyError(channels[0].socket, currentReply, QNetworkReply::HostNotFoundError);
1273             }
1274         } else {
1275             // Should not happen: we start a host lookup before sending a request,
1276             // so it's natural to have requests either in SPDY/HTTP/2 queue,
1277             // or in low/high priority queues.
1278             qWarning("QHttpNetworkConnectionPrivate::_q_hostLookupFinished"
1279                      " could not de-queue request, failed to report HostNotFoundError");
1280             networkLayerState = QHttpNetworkConnectionPrivate::Unknown;
1281         }
1282     }
1283 }
1284 
1285 
1286 // This will be used if the host lookup found both and Ipv4 and
1287 // Ipv6 address. Then we will start up two connections and pick
1288 // the network layer of the one that finish first. The second
1289 // connection will then be disconnected.
1290 void QHttpNetworkConnectionPrivate::startNetworkLayerStateLookup()
1291 {
1292     if (activeChannelCount > 1) {
1293         // At this time all channels should be unconnected.
1294         Q_ASSERT(!channels[0].isSocketBusy());
1295         Q_ASSERT(!channels[1].isSocketBusy());
1296 
1297         networkLayerState = IPv4or6;
1298 
1299         channels[0].networkLayerPreference = QAbstractSocket::IPv4Protocol;
1300         channels[1].networkLayerPreference = QAbstractSocket::IPv6Protocol;
1301 
1302         int timeout = 300;
1303 #ifndef QT_NO_BEARERMANAGEMENT // ### Qt6: Remove section
1304         if (networkSession) {
1305             const QNetworkConfiguration::BearerType bearerType = networkSession->configuration().bearerType();
1306             if (bearerType == QNetworkConfiguration::Bearer2G)
1307                 timeout = 800;
1308             else if (bearerType == QNetworkConfiguration::BearerCDMA2000)
1309                 timeout = 500;
1310             else if (bearerType == QNetworkConfiguration::BearerWCDMA)
1311                 timeout = 500;
1312             else if (bearerType == QNetworkConfiguration::BearerHSPA)
1313                 timeout = 400;
1314         }
1315 #endif
1316         delayedConnectionTimer.start(timeout);
1317         if (delayIpv4)
1318             channels[1].ensureConnection();
1319         else
1320             channels[0].ensureConnection();
1321     } else {
1322         networkLayerState = IPv4or6;
1323         channels[0].networkLayerPreference = QAbstractSocket::AnyIPProtocol;
1324         channels[0].ensureConnection();
1325     }
1326 }
1327 
1328 void QHttpNetworkConnectionPrivate::networkLayerDetected(QAbstractSocket::NetworkLayerProtocol protocol)
1329 {
1330     for (int i = 0 ; i < activeChannelCount; ++i) {
1331         if ((channels[i].networkLayerPreference != protocol) && (channels[i].state == QHttpNetworkConnectionChannel::ConnectingState)) {
1332             channels[i].close();
1333         }
1334     }
1335 }
1336 
1337 void QHttpNetworkConnectionPrivate::_q_connectDelayedChannel()
1338 {
1339     if (delayIpv4)
1340         channels[0].ensureConnection();
1341     else
1342         channels[1].ensureConnection();
1343 }
1344 
1345 #ifndef QT_NO_BEARERMANAGEMENT // ### Qt6: Remove section
1346 QHttpNetworkConnection::QHttpNetworkConnection(const QString &hostName, quint16 port, bool encrypt,
1347                                                QHttpNetworkConnection::ConnectionType connectionType,
1348                                                QObject *parent, QSharedPointer<QNetworkSession> networkSession)
1349     : QObject(*(new QHttpNetworkConnectionPrivate(hostName, port, encrypt, connectionType)), parent)
1350 {
1351     Q_D(QHttpNetworkConnection);
1352     d->networkSession = std::move(networkSession);
1353     d->init();
1354     if (QNetworkStatusMonitor::isEnabled()) {
1355         connect(&d->connectionMonitor, &QNetworkConnectionMonitor::reachabilityChanged,
1356                 this, &QHttpNetworkConnection::onlineStateChanged, Qt::QueuedConnection);
1357     }
1358 }
1359 
1360 QHttpNetworkConnection::QHttpNetworkConnection(quint16 connectionCount, const QString &hostName,
1361                                                quint16 port, bool encrypt, QObject *parent,
1362                                                QSharedPointer<QNetworkSession> networkSession,
1363                                                QHttpNetworkConnection::ConnectionType connectionType)
1364      : QObject(*(new QHttpNetworkConnectionPrivate(connectionCount, hostName, port, encrypt,
1365                                                    connectionType)), parent)
1366 {
1367     Q_D(QHttpNetworkConnection);
1368     d->networkSession = std::move(networkSession);
1369     d->init();
1370     if (QNetworkStatusMonitor::isEnabled()) {
1371         connect(&d->connectionMonitor, &QNetworkConnectionMonitor::reachabilityChanged,
1372                 this, &QHttpNetworkConnection::onlineStateChanged, Qt::QueuedConnection);
1373     }
1374 }
1375 #else
1376 QHttpNetworkConnection::QHttpNetworkConnection(const QString &hostName, quint16 port, bool encrypt,
1377                                                QHttpNetworkConnection::ConnectionType connectionType, QObject *parent)
1378     : QObject(*(new QHttpNetworkConnectionPrivate(hostName, port, encrypt , connectionType)), parent)
1379 {
1380     Q_D(QHttpNetworkConnection);
1381     d->init();
1382     if (QNetworkStatusMonitor::isEnabled()) {
1383         connect(&d->connectionMonitor, &QNetworkConnectionMonitor::reachabilityChanged,
1384                 this, &QHttpNetworkConnection::onlineStateChanged, Qt::QueuedConnection);
1385     }
1386 }
1387 
1388 QHttpNetworkConnection::QHttpNetworkConnection(quint16 connectionCount, const QString &hostName,
1389                                                quint16 port, bool encrypt, QObject *parent,
1390                                                QHttpNetworkConnection::ConnectionType connectionType)
1391      : QObject(*(new QHttpNetworkConnectionPrivate(connectionCount, hostName, port, encrypt,
1392                                                    connectionType)), parent)
1393 {
1394     Q_D(QHttpNetworkConnection);
1395     d->init();
1396     if (QNetworkStatusMonitor::isEnabled()) {
1397         connect(&d->connectionMonitor, &QNetworkConnectionMonitor::reachabilityChanged,
1398                 this, &QHttpNetworkConnection::onlineStateChanged, Qt::QueuedConnection);
1399     }
1400 }
1401 #endif // QT_NO_BEARERMANAGEMENT
1402 
1403 QHttpNetworkConnection::~QHttpNetworkConnection()
1404 {
1405 }
1406 
1407 QString QHttpNetworkConnection::hostName() const
1408 {
1409     Q_D(const QHttpNetworkConnection);
1410     return d->hostName;
1411 }
1412 
1413 quint16 QHttpNetworkConnection::port() const
1414 {
1415     Q_D(const QHttpNetworkConnection);
1416     return d->port;
1417 }
1418 
1419 QHttpNetworkReply* QHttpNetworkConnection::sendRequest(const QHttpNetworkRequest &request)
1420 {
1421     Q_D(QHttpNetworkConnection);
1422     return d->queueRequest(request);
1423 }
1424 
1425 void QHttpNetworkConnection::fillHttp2Queue()
1426 {
1427     Q_D(QHttpNetworkConnection);
1428     d->fillHttp2Queue();
1429 }
1430 
1431 bool QHttpNetworkConnection::isSsl() const
1432 {
1433     Q_D(const QHttpNetworkConnection);
1434     return d->encrypt;
1435 }
1436 
1437 QHttpNetworkConnectionChannel *QHttpNetworkConnection::channels() const
1438 {
1439     return d_func()->channels;
1440 }
1441 
1442 #ifndef QT_NO_NETWORKPROXY
1443 void QHttpNetworkConnection::setCacheProxy(const QNetworkProxy &networkProxy)
1444 {
1445     Q_D(QHttpNetworkConnection);
1446     d->networkProxy = networkProxy;
1447     // update the authenticator
1448     if (!d->networkProxy.user().isEmpty()) {
1449         for (int i = 0; i < d->activeChannelCount; ++i) {
1450             d->channels[i].proxyAuthenticator.setUser(d->networkProxy.user());
1451             d->channels[i].proxyAuthenticator.setPassword(d->networkProxy.password());
1452         }
1453     }
1454 }
1455 
1456 QNetworkProxy QHttpNetworkConnection::cacheProxy() const
1457 {
1458     Q_D(const QHttpNetworkConnection);
1459     return d->networkProxy;
1460 }
1461 
1462 void QHttpNetworkConnection::setTransparentProxy(const QNetworkProxy &networkProxy)
1463 {
1464     Q_D(QHttpNetworkConnection);
1465     for (int i = 0; i < d->activeChannelCount; ++i)
1466         d->channels[i].setProxy(networkProxy);
1467 }
1468 
1469 QNetworkProxy QHttpNetworkConnection::transparentProxy() const
1470 {
1471     Q_D(const QHttpNetworkConnection);
1472     return d->channels[0].proxy;
1473 }
1474 #endif
1475 
1476 QHttpNetworkConnection::ConnectionType QHttpNetworkConnection::connectionType()
1477 {
1478     Q_D(QHttpNetworkConnection);
1479     return d->connectionType;
1480 }
1481 
1482 void QHttpNetworkConnection::setConnectionType(ConnectionType type)
1483 {
1484     Q_D(QHttpNetworkConnection);
1485     d->connectionType = type;
1486 }
1487 
1488 QHttp2Configuration QHttpNetworkConnection::http2Parameters() const
1489 {
1490     Q_D(const QHttpNetworkConnection);
1491     return d->http2Parameters;
1492 }
1493 
1494 void QHttpNetworkConnection::setHttp2Parameters(const QHttp2Configuration &params)
1495 {
1496     Q_D(QHttpNetworkConnection);
1497     d->http2Parameters = params;
1498 }
1499 
1500 // SSL support below
1501 #ifndef QT_NO_SSL
1502 void QHttpNetworkConnection::setSslConfiguration(const QSslConfiguration &config)
1503 {
1504     Q_D(QHttpNetworkConnection);
1505     if (!d->encrypt)
1506         return;
1507 
1508     // set the config on all channels
1509     for (int i = 0; i < d->activeChannelCount; ++i)
1510         d->channels[i].setSslConfiguration(config);
1511 }
1512 
1513 QSharedPointer<QSslContext> QHttpNetworkConnection::sslContext()
1514 {
1515     Q_D(QHttpNetworkConnection);
1516     return d->sslContext;
1517 }
1518 
1519 void QHttpNetworkConnection::setSslContext(QSharedPointer<QSslContext> context)
1520 {
1521     Q_D(QHttpNetworkConnection);
1522     d->sslContext = std::move(context);
1523 }
1524 
1525 void QHttpNetworkConnection::ignoreSslErrors(int channel)
1526 {
1527     Q_D(QHttpNetworkConnection);
1528     if (!d->encrypt)
1529         return;
1530 
1531     if (channel == -1) { // ignore for all channels
1532         // We need to ignore for all channels, even the ones that are not in use just in case they
1533         // will be in the future.
1534         for (int i = 0; i < d->channelCount; ++i) {
1535             d->channels[i].ignoreSslErrors();
1536         }
1537 
1538     } else {
1539         d->channels[channel].ignoreSslErrors();
1540     }
1541 }
1542 
1543 void QHttpNetworkConnection::ignoreSslErrors(const QList<QSslError> &errors, int channel)
1544 {
1545     Q_D(QHttpNetworkConnection);
1546     if (!d->encrypt)
1547         return;
1548 
1549     if (channel == -1) { // ignore for all channels
1550         // We need to ignore for all channels, even the ones that are not in use just in case they
1551         // will be in the future.
1552         for (int i = 0; i < d->channelCount; ++i) {
1553             d->channels[i].ignoreSslErrors(errors);
1554         }
1555 
1556     } else {
1557         d->channels[channel].ignoreSslErrors(errors);
1558     }
1559 }
1560 
1561 #endif //QT_NO_SSL
1562 
1563 void QHttpNetworkConnection::preConnectFinished()
1564 {
1565     d_func()->preConnectRequests--;
1566 }
1567 
1568 QString QHttpNetworkConnection::peerVerifyName() const
1569 {
1570     Q_D(const QHttpNetworkConnection);
1571     return d->peerVerifyName;
1572 }
1573 
1574 void QHttpNetworkConnection::setPeerVerifyName(const QString &peerName)
1575 {
1576     Q_D(QHttpNetworkConnection);
1577     d->peerVerifyName = peerName;
1578 }
1579 
1580 void QHttpNetworkConnection::onlineStateChanged(bool isOnline)
1581 {
1582     Q_D(QHttpNetworkConnection);
1583 
1584     if (isOnline) {
1585         // If we did not have any 'isOffline' previously - well, good
1586         // to know, we are 'online' apparently.
1587         return;
1588     }
1589 
1590     for (int i = 0; i < d->activeChannelCount; i++) {
1591         auto &channel = d->channels[i];
1592         channel.emitFinishedWithError(QNetworkReply::TemporaryNetworkFailureError, "Temporary network failure.");
1593         channel.close();
1594     }
1595 
1596     // We don't care, this connection is broken from our POV.
1597     d->connectionMonitor.stopMonitoring();
1598 }
1599 
1600 #ifndef QT_NO_NETWORKPROXY
1601 // only called from QHttpNetworkConnectionChannel::_q_proxyAuthenticationRequired, not
1602 // from QHttpNetworkConnectionChannel::handleAuthenticationChallenge
1603 // e.g. it is for SOCKS proxies which require authentication.
1604 void QHttpNetworkConnectionPrivate::emitProxyAuthenticationRequired(const QHttpNetworkConnectionChannel *chan, const QNetworkProxy &proxy, QAuthenticator* auth)
1605 {
1606     // Also pause the connection because socket notifiers may fire while an user
1607     // dialog is displaying
1608     pauseConnection();
1609     QHttpNetworkReply *reply;
1610     if (connectionType == QHttpNetworkConnection::ConnectionTypeHTTP2
1611         || connectionType == QHttpNetworkConnection::ConnectionTypeHTTP2Direct
1612 #if QT_CONFIG(ssl)
1613         || connectionType == QHttpNetworkConnection::ConnectionTypeSPDY
1614 #endif
1615         ) {
1616 
1617         // we choose the reply to emit the proxyAuth signal from somewhat arbitrarily,
1618         // but that does not matter because the signal will ultimately be emitted
1619         // by the QNetworkAccessManager.
1620         Q_ASSERT(chan->spdyRequestsToSend.count() > 0);
1621         reply = chan->spdyRequestsToSend.cbegin().value().second;
1622     } else { // HTTP
1623         reply = chan->reply;
1624     }
1625 
1626     Q_ASSERT(reply);
1627     emit reply->proxyAuthenticationRequired(proxy, auth);
1628     resumeConnection();
1629     int i = indexOf(chan->socket);
1630     copyCredentials(i, auth, true);
1631 }
1632 #endif
1633 
1634 
1635 QT_END_NAMESPACE
1636 
1637 #include "moc_qhttpnetworkconnection_p.cpp"
1638