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 ¶ms)
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