diff options
author | Liang Qi <liang.qi@qt.io> | 2017-10-17 10:19:31 +0200 |
---|---|---|
committer | Liang Qi <liang.qi@qt.io> | 2017-10-17 10:34:24 +0200 |
commit | d0a0a3c0418a0fdd2ed84b2a5f7e6565537715c6 (patch) | |
tree | d6aeb4d51caf30ccf23eadb806a09295cbf679cd /src/network | |
parent | 9f405f98a4247cd263b9c5d35659a4ba89e282de (diff) | |
parent | ac35f9c44c0fb3b2f40ae5585c497200b2ba743d (diff) |
Merge remote-tracking branch 'origin/5.10' into dev
Conflicts:
examples/network/fortuneclient/client.cpp
examples/network/fortuneserver/server.cpp
src/platformsupport/platformcompositor/qopenglcompositorbackingstore_p.h
src/plugins/platforms/cocoa/qcocoabackingstore.h
src/plugins/platforms/cocoa/qcocoaintegration.h
src/plugins/platforms/cocoa/qcocoascreen.h
src/plugins/platforms/ios/qiosbackingstore.h
src/plugins/sqldrivers/oci/qsql_oci.cpp
src/widgets/kernel/qwidgetwindow.cpp
Change-Id: Ia6dd2c52d4a691b671cf9a2ffca70deccece8f10
Diffstat (limited to 'src/network')
-rw-r--r-- | src/network/access/http2/http2protocol.cpp | 2 | ||||
-rw-r--r-- | src/network/access/http2/http2protocol_p.h | 14 | ||||
-rw-r--r-- | src/network/access/qhttp2protocolhandler.cpp | 52 | ||||
-rw-r--r-- | src/network/access/qhttp2protocolhandler_p.h | 8 | ||||
-rw-r--r-- | src/network/access/qnetworkaccessmanager.cpp | 11 | ||||
-rw-r--r-- | src/network/access/qnetworkdiskcache.cpp | 4 | ||||
-rw-r--r-- | src/network/access/qnetworkreplyhttpimpl.cpp | 8 | ||||
-rw-r--r-- | src/network/kernel/qnetworkinterface.cpp | 25 | ||||
-rw-r--r-- | src/network/socket/qabstractsocket.cpp | 38 | ||||
-rw-r--r-- | src/network/socket/qabstractsocket.h | 1 | ||||
-rw-r--r-- | src/network/socket/qabstractsocket_p.h | 2 |
11 files changed, 90 insertions, 75 deletions
diff --git a/src/network/access/http2/http2protocol.cpp b/src/network/access/http2/http2protocol.cpp index 54811aeab0..bb3d6bf575 100644 --- a/src/network/access/http2/http2protocol.cpp +++ b/src/network/access/http2/http2protocol.cpp @@ -216,6 +216,8 @@ Frame default_SETTINGS_frame() // MAX frame size (16 kb), disable/enable PUSH_PROMISE builder.append(Settings::MAX_FRAME_SIZE_ID); builder.append(quint32(maxFrameSize)); + builder.append(Settings::INITIAL_WINDOW_SIZE_ID); + builder.append(initialStreamReceiveWindowSize); builder.append(Settings::ENABLE_PUSH_ID); builder.append(quint32(is_PUSH_PROMISE_enabled())); diff --git a/src/network/access/http2/http2protocol_p.h b/src/network/access/http2/http2protocol_p.h index b26ff0e9f4..c64e960002 100644 --- a/src/network/access/http2/http2protocol_p.h +++ b/src/network/access/http2/http2protocol_p.h @@ -129,10 +129,20 @@ enum Http2PredefinedParameters maxConcurrentStreams = 100 // HTTP/2, 6.5.2 }; -// It's int, it has internal linkage, it's ok to have it in headers - -// no ODR violation is possible. +// These are ints, const, they have internal linkage, it's ok to have them in +// headers - no ODR violation. const quint32 lastValidStreamID((quint32(1) << 31) - 1); // HTTP/2, 5.1.1 +// The default size of 64K is too small and limiting: if we use it, we end up +// sending WINDOW_UPDATE frames on a stream/session all the time, for each +// 2 DATE frames of size 16K (also default) we'll send a WINDOW_UPDATE frame +// for a given stream and have a download speed order of magnitude lower than +// our own HTTP/1.1 protocol handler. We choose a bigger window size (normally, +// HTTP/2 servers are not afraid to immediately set it to possible max anyway) +// and split this window size between our concurrent streams. +const qint32 initialSessionReceiveWindowSize = defaultSessionWindowSize * 10000; +const qint32 initialStreamReceiveWindowSize = initialSessionReceiveWindowSize / maxConcurrentStreams; + extern const Q_AUTOTEST_EXPORT char Http2clientPreface[clientPrefaceLength]; void prepare_for_protocol_upgrade(QHttpNetworkRequest &request); diff --git a/src/network/access/qhttp2protocolhandler.cpp b/src/network/access/qhttp2protocolhandler.cpp index 5032f6017f..461f2429b3 100644 --- a/src/network/access/qhttp2protocolhandler.cpp +++ b/src/network/access/qhttp2protocolhandler.cpp @@ -161,8 +161,6 @@ bool sum_will_overflow(qint32 windowSize, qint32 delta) using namespace Http2; const std::deque<quint32>::size_type QHttp2ProtocolHandler::maxRecycledStreams = 10000; -const qint32 QHttp2ProtocolHandler::sessionMaxRecvWindowSize; -const qint32 QHttp2ProtocolHandler::streamInitialRecvWindowSize; const quint32 QHttp2ProtocolHandler::maxAcceptableTableSize; QHttp2ProtocolHandler::QHttp2ProtocolHandler(QHttpNetworkConnectionChannel *channel) @@ -374,12 +372,10 @@ bool QHttp2ProtocolHandler::sendClientPreface() if (!frameWriter.write(*m_socket)) return false; - sessionRecvWindowSize = sessionMaxRecvWindowSize; - if (defaultSessionWindowSize < sessionMaxRecvWindowSize) { - const auto delta = sessionMaxRecvWindowSize - defaultSessionWindowSize; - if (!sendWINDOW_UPDATE(connectionStreamID, delta)) - return false; - } + sessionRecvWindowSize = Http2::initialSessionReceiveWindowSize; + const auto delta = Http2::initialSessionReceiveWindowSize - Http2::defaultSessionWindowSize; + if (!sendWINDOW_UPDATE(Http2::connectionStreamID, delta)) + return false; prefaceSent = true; waitingForSettingsACK = true; @@ -549,20 +545,20 @@ void QHttp2ProtocolHandler::handleDATA() if (inboundFrame.flags().testFlag(FrameFlag::END_STREAM)) { finishStream(stream); deleteActiveStream(stream.streamID); - } else if (stream.recvWindow < streamInitialRecvWindowSize / 2) { + } else if (stream.recvWindow < Http2::initialStreamReceiveWindowSize / 2) { QMetaObject::invokeMethod(this, "sendWINDOW_UPDATE", Qt::QueuedConnection, Q_ARG(quint32, stream.streamID), - Q_ARG(quint32, streamInitialRecvWindowSize - stream.recvWindow)); - stream.recvWindow = streamInitialRecvWindowSize; + Q_ARG(quint32, Http2::initialStreamReceiveWindowSize - stream.recvWindow)); + stream.recvWindow = Http2::initialStreamReceiveWindowSize; } } } - if (sessionRecvWindowSize < sessionMaxRecvWindowSize / 2) { + if (sessionRecvWindowSize < Http2::initialSessionReceiveWindowSize / 2) { QMetaObject::invokeMethod(this, "sendWINDOW_UPDATE", Qt::QueuedConnection, Q_ARG(quint32, connectionStreamID), - Q_ARG(quint32, sessionMaxRecvWindowSize - sessionRecvWindowSize)); - sessionRecvWindowSize = sessionMaxRecvWindowSize; + Q_ARG(quint32, Http2::initialSessionReceiveWindowSize - sessionRecvWindowSize)); + sessionRecvWindowSize = Http2::initialSessionReceiveWindowSize; } } @@ -1042,12 +1038,26 @@ void QHttp2ProtocolHandler::updateStream(Stream &stream, const HPack::HttpHeader } const auto httpReplyPrivate = httpReply->d_func(); + + // For HTTP/1 'location' is handled (and redirect URL set) when a protocol + // handler emits channel->allDone(). Http/2 protocol handler never emits + // allDone, since we have many requests multiplexed in one channel at any + // moment and we are probably not done yet. So we extract url and set it + // here, if needed. + int statusCode = 0; + QUrl redirectUrl; + for (const auto &pair : headers) { const auto &name = pair.name; auto value = pair.value; + // TODO: part of this code copies what SPDY protocol handler does when + // processing headers. Binary nature of HTTP/2 and SPDY saves us a lot + // of parsing and related errors/bugs, but it would be nice to have + // more detailed validation of headers. if (name == ":status") { - httpReply->setStatusCode(value.left(3).toInt()); + statusCode = value.left(3).toInt(); + httpReply->setStatusCode(statusCode); httpReplyPrivate->reasonPhrase = QString::fromLatin1(value.mid(4)); } else if (name == ":version") { httpReplyPrivate->majorVersion = value.at(5) - '0'; @@ -1058,6 +1068,8 @@ void QHttp2ProtocolHandler::updateStream(Stream &stream, const HPack::HttpHeader if (ok) httpReply->setContentLength(length); } else { + if (name == "location") + redirectUrl = QUrl::fromEncoded(value); QByteArray binder(", "); if (name == "set-cookie") binder = "\n"; @@ -1065,6 +1077,9 @@ void QHttp2ProtocolHandler::updateStream(Stream &stream, const HPack::HttpHeader } } + if (QHttpNetworkReply::isHttpRedirect(statusCode) && redirectUrl.isValid()) + httpReply->setRedirectUrl(redirectUrl); + if (connectionType == Qt::DirectConnection) emit httpReply->headerChanged(); else @@ -1184,7 +1199,7 @@ quint32 QHttp2ProtocolHandler::createNewStream(const HttpMessagePair &message, b const Stream newStream(message, newStreamID, streamInitialSendWindowSize, - streamInitialRecvWindowSize); + Http2::initialStreamReceiveWindowSize); if (!uploadDone) { if (auto src = newStream.data()) { @@ -1379,7 +1394,8 @@ bool QHttp2ProtocolHandler::tryReserveStream(const Http2::Frame &pushPromiseFram promise.reservedID = reservedID; promise.pushHeader = requestHeader; - activeStreams.insert(reservedID, Stream(urlKey, reservedID, streamInitialRecvWindowSize)); + activeStreams.insert(reservedID, Stream(urlKey, reservedID, + Http2::initialStreamReceiveWindowSize)); return true; } @@ -1413,7 +1429,7 @@ void QHttp2ProtocolHandler::initReplyFromPushPromise(const HttpMessagePair &mess // Let's pretent we're sending a request now: Stream closedStream(message, promise.reservedID, streamInitialSendWindowSize, - streamInitialRecvWindowSize); + Http2::initialStreamReceiveWindowSize); closedStream.state = Stream::halfClosedLocal; activeStreams.insert(promise.reservedID, closedStream); promisedStream = &activeStreams[promise.reservedID]; diff --git a/src/network/access/qhttp2protocolhandler_p.h b/src/network/access/qhttp2protocolhandler_p.h index 82eea21818..b52f8ae10c 100644 --- a/src/network/access/qhttp2protocolhandler_p.h +++ b/src/network/access/qhttp2protocolhandler_p.h @@ -176,13 +176,9 @@ private: quint32 maxConcurrentStreams = Http2::maxConcurrentStreams; // Control flow: - static const qint32 sessionMaxRecvWindowSize = Http2::defaultSessionWindowSize * 10; - // Signed integer, it can become negative (it's still a valid window size): - qint32 sessionRecvWindowSize = sessionMaxRecvWindowSize; - // We do not negotiate this window size - // We have to send WINDOW_UPDATE frames to our peer also. - static const qint32 streamInitialRecvWindowSize = Http2::defaultSessionWindowSize; + // Signed integer, it can become negative (it's still a valid window size): + qint32 sessionRecvWindowSize = Http2::initialSessionReceiveWindowSize; // Updated by SETTINGS and WINDOW_UPDATE. qint32 sessionSendWindowSize = Http2::defaultSessionWindowSize; diff --git a/src/network/access/qnetworkaccessmanager.cpp b/src/network/access/qnetworkaccessmanager.cpp index 8bbef0a0d8..edf9dee78e 100644 --- a/src/network/access/qnetworkaccessmanager.cpp +++ b/src/network/access/qnetworkaccessmanager.cpp @@ -75,6 +75,12 @@ #include <QHostInfo> +#if defined(Q_OS_MACOS) +#include <CoreServices/CoreServices.h> +#include <SystemConfiguration/SystemConfiguration.h> +#include <Security/SecKeychain.h> +#endif + QT_BEGIN_NAMESPACE Q_GLOBAL_STATIC(QNetworkAccessFileBackendFactory, fileBackend) @@ -87,11 +93,6 @@ Q_GLOBAL_STATIC(QNetworkAccessDebugPipeBackendFactory, debugpipeBackend) #endif #if defined(Q_OS_MACX) - -#include <CoreServices/CoreServices.h> -#include <SystemConfiguration/SystemConfiguration.h> -#include <Security/SecKeychain.h> - bool getProxyAuth(const QString& proxyHostname, const QString &scheme, QString& username, QString& password) { OSStatus err; diff --git a/src/network/access/qnetworkdiskcache.cpp b/src/network/access/qnetworkdiskcache.cpp index fca880d9b3..c9d658225e 100644 --- a/src/network/access/qnetworkdiskcache.cpp +++ b/src/network/access/qnetworkdiskcache.cpp @@ -537,7 +537,9 @@ qint64 QNetworkDiskCache::expire() QFileInfo info = it.fileInfo(); QString fileName = info.fileName(); if (fileName.endsWith(CACHE_POSTFIX)) { - cacheItems.insert(info.created(), path); + const QDateTime birthTime = info.fileTime(QFile::FileBirthTime); + cacheItems.insert(birthTime.isValid() ? birthTime + : info.fileTime(QFile::FileMetadataChangeTime), path); totalSize += info.size(); } } diff --git a/src/network/access/qnetworkreplyhttpimpl.cpp b/src/network/access/qnetworkreplyhttpimpl.cpp index 55eb7d4f08..684fee610c 100644 --- a/src/network/access/qnetworkreplyhttpimpl.cpp +++ b/src/network/access/qnetworkreplyhttpimpl.cpp @@ -1175,6 +1175,14 @@ void QNetworkReplyHttpImplPrivate::onRedirected(const QUrl &redirectUrl, int htt redirectRequest = createRedirectRequest(originalRequest, url, maxRedirectsRemaining); operation = getRedirectOperation(operation, httpStatus); + if (const QNetworkCookieJar *const cookieJar = (manager ? manager->cookieJar() : nullptr)) { + auto cookies = cookieJar->cookiesForUrl(url); + if (!cookies.empty()) { + redirectRequest.setHeader(QNetworkRequest::KnownHeaders::CookieHeader, + QVariant::fromValue(cookies)); + } + } + if (httpRequest.redirectPolicy() != QNetworkRequest::UserVerifiedRedirectPolicy) followRedirect(); diff --git a/src/network/kernel/qnetworkinterface.cpp b/src/network/kernel/qnetworkinterface.cpp index 2c28ae9ed9..3857ff87b9 100644 --- a/src/network/kernel/qnetworkinterface.cpp +++ b/src/network/kernel/qnetworkinterface.cpp @@ -355,9 +355,9 @@ void QNetworkAddressEntry::setBroadcast(const QHostAddress &newBroadcast) contain zero or more IP addresses, each of which is optionally associated with a netmask and/or a broadcast address. The list of such trios can be obtained with addressEntries(). Alternatively, - when the netmask or the broadcast addresses aren't necessary, use - the allAddresses() convenience function to obtain just the IP - addresses. + when the netmask or the broadcast addresses or other information aren't + necessary, use the allAddresses() convenience function to obtain just the + IP addresses of the active interfaces. QNetworkInterface also reports the interface's hardware address with hardwareAddress(). @@ -516,9 +516,9 @@ QString QNetworkInterface::hardwareAddress() const Returns the list of IP addresses that this interface possesses along with their associated netmasks and broadcast addresses. - If the netmask or broadcast address information is not necessary, - you can call the allAddresses() function to obtain just the IP - addresses. + If the netmask or broadcast address or other information is not necessary, + you can call the allAddresses() function to obtain just the IP addresses of + the active interfaces. */ QList<QNetworkAddressEntry> QNetworkInterface::addressEntries() const { @@ -624,16 +624,21 @@ QList<QNetworkInterface> QNetworkInterface::allInterfaces() } /*! - This convenience function returns all IP addresses found on the - host machine. It is equivalent to calling addressEntries() on all the - objects returned by allInterfaces() to obtain lists of QHostAddress - objects then calling QHostAddress::ip() on each of these. + This convenience function returns all IP addresses found on the host + machine. It is equivalent to calling addressEntries() on all the objects + returned by allInterfaces() that are in the QNetworkInterface::IsUp state + to obtain lists of QNetworkAddressEntry objects then calling + QNetworkAddressEntry::ip() on each of these. */ QList<QHostAddress> QNetworkInterface::allAddresses() { const QList<QSharedDataPointer<QNetworkInterfacePrivate> > privs = manager()->allInterfaces(); QList<QHostAddress> result; for (const auto &p : privs) { + // skip addresses if the interface isn't up + if ((p->flags & QNetworkInterface::IsUp) == 0) + continue; + for (const QNetworkAddressEntry &entry : qAsConst(p->addressEntries)) result += entry.ip(); } diff --git a/src/network/socket/qabstractsocket.cpp b/src/network/socket/qabstractsocket.cpp index c7b779d5f9..6d47540b75 100644 --- a/src/network/socket/qabstractsocket.cpp +++ b/src/network/socket/qabstractsocket.cpp @@ -565,7 +565,6 @@ QAbstractSocketPrivate::QAbstractSocketPrivate() isBuffered(false), hasPendingData(false), connectTimer(0), - disconnectTimer(0), hostLookupId(-1), socketType(QAbstractSocket::UnknownSocketType), state(QAbstractSocket::UnconnectedState), @@ -604,8 +603,6 @@ void QAbstractSocketPrivate::resetSocketLayer() } if (connectTimer) connectTimer->stop(); - if (disconnectTimer) - disconnectTimer->stop(); } /*! \internal @@ -967,13 +964,17 @@ void QAbstractSocketPrivate::startConnectingByName(const QString &host) emit q->stateChanged(state); if (cachedSocketDescriptor != -1 || initSocketLayer(QAbstractSocket::UnknownNetworkLayerProtocol)) { - if (socketEngine->connectToHostByName(host, port) || - socketEngine->state() == QAbstractSocket::ConnectingState) { - cachedSocketDescriptor = socketEngine->socketDescriptor(); - + // Try to connect to the host. If it succeeds immediately + // (e.g. QSocks5SocketEngine in UDPASSOCIATE mode), emit + // connected() and return. + if (socketEngine->connectToHostByName(host, port)) { + fetchConnectionParameters(); return; } + if (socketEngine->state() == QAbstractSocket::ConnectingState) + return; + // failed to connect setError(socketEngine->error(), socketEngine->errorString()); } @@ -1220,15 +1221,6 @@ void QAbstractSocketPrivate::_q_abortConnectionAttempt() } } -void QAbstractSocketPrivate::_q_forceDisconnect() -{ - Q_Q(QAbstractSocket); - if (socketEngine && socketEngine->isValid() && state == QAbstractSocket::ClosingState) { - socketEngine->close(); - q->disconnectFromHost(); - } -} - /*! \internal Reads data from the socket layer into the read buffer. Returns @@ -2770,20 +2762,6 @@ void QAbstractSocket::disconnectFromHost() // Wait for pending data to be written. if (d->socketEngine && d->socketEngine->isValid() && (!d->allWriteBuffersEmpty() || d->socketEngine->bytesToWrite() > 0)) { - // hack: when we are waiting for the socket engine to write bytes (only - // possible when using Socks5 or HTTP socket engine), then close - // anyway after 2 seconds. This is to prevent a timeout on Mac, where we - // sometimes just did not get the write notifier from the underlying - // CFSocket and no progress was made. - if (d->allWriteBuffersEmpty() && d->socketEngine->bytesToWrite() > 0) { - if (!d->disconnectTimer) { - d->disconnectTimer = new QTimer(this); - connect(d->disconnectTimer, SIGNAL(timeout()), this, - SLOT(_q_forceDisconnect()), Qt::DirectConnection); - } - if (!d->disconnectTimer->isActive()) - d->disconnectTimer->start(2000); - } d->socketEngine->setWriteNotificationEnabled(true); #if defined(QABSTRACTSOCKET_DEBUG) diff --git a/src/network/socket/qabstractsocket.h b/src/network/socket/qabstractsocket.h index 710eac6c3e..ba499ddf7d 100644 --- a/src/network/socket/qabstractsocket.h +++ b/src/network/socket/qabstractsocket.h @@ -231,7 +231,6 @@ private: Q_PRIVATE_SLOT(d_func(), void _q_startConnecting(const QHostInfo &)) Q_PRIVATE_SLOT(d_func(), void _q_abortConnectionAttempt()) Q_PRIVATE_SLOT(d_func(), void _q_testConnection()) - Q_PRIVATE_SLOT(d_func(), void _q_forceDisconnect()) }; diff --git a/src/network/socket/qabstractsocket_p.h b/src/network/socket/qabstractsocket_p.h index 62b7aceae8..3d788319a8 100644 --- a/src/network/socket/qabstractsocket_p.h +++ b/src/network/socket/qabstractsocket_p.h @@ -98,7 +98,6 @@ public: void _q_startConnecting(const QHostInfo &hostInfo); void _q_testConnection(); void _q_abortConnectionAttempt(); - void _q_forceDisconnect(); bool emittedReadyRead; bool emittedBytesWritten; @@ -151,7 +150,6 @@ public: bool hasPendingData; QTimer *connectTimer; - QTimer *disconnectTimer; int hostLookupId; |