diff options
Diffstat (limited to 'src/network')
-rw-r--r-- | src/network/access/qhttp2protocolhandler.cpp | 101 | ||||
-rw-r--r-- | src/network/access/qhttpnetworkconnection.cpp | 4 | ||||
-rw-r--r-- | src/network/access/qhttpnetworkconnectionchannel.cpp | 20 | ||||
-rw-r--r-- | src/network/access/qhttpnetworkrequest.cpp | 4 | ||||
-rw-r--r-- | src/network/access/qhttpnetworkrequest_p.h | 1 | ||||
-rw-r--r-- | src/network/access/qnetworkdiskcache.cpp | 13 | ||||
-rw-r--r-- | src/network/access/qspdyprotocolhandler.cpp | 3 | ||||
-rw-r--r-- | src/network/socket/qlocalsocket.h | 5 | ||||
-rw-r--r-- | src/network/ssl/qsslcertificate_openssl.cpp | 4 | ||||
-rw-r--r-- | src/network/ssl/qsslsocket_openssl_symbols_p.h | 10 |
10 files changed, 115 insertions, 50 deletions
diff --git a/src/network/access/qhttp2protocolhandler.cpp b/src/network/access/qhttp2protocolhandler.cpp index 91c41d8240..f513139304 100644 --- a/src/network/access/qhttp2protocolhandler.cpp +++ b/src/network/access/qhttp2protocolhandler.cpp @@ -495,6 +495,10 @@ bool QHttp2ProtocolHandler::sendHEADERS(Stream &stream) #ifndef QT_NO_NETWORKPROXY useProxy = m_connection->d_func()->networkProxy.type() != QNetworkProxy::NoProxy; #endif + if (stream.request().withCredentials()) { + m_connection->d_func()->createAuthorization(m_socket, stream.request()); + stream.request().d->needResendWithCredentials = false; + } const auto headers = build_headers(stream.request(), maxHeaderListSize, useProxy); if (!headers.size()) // nothing fits into maxHeaderListSize return false; @@ -520,7 +524,7 @@ bool QHttp2ProtocolHandler::sendDATA(Stream &stream) Q_ASSERT(replyPrivate); auto slot = std::min<qint32>(sessionSendWindowSize, stream.sendWindow); - while (!stream.data()->atEnd() && slot) { + while (replyPrivate->totallyUploadedData < request.contentLength() && slot) { qint64 chunkSize = 0; const uchar *src = reinterpret_cast<const uchar *>(stream.data()->readPointer(slot, chunkSize)); @@ -1019,8 +1023,10 @@ void QHttp2ProtocolHandler::handleContinuedHEADERS() if (activeStreams.contains(streamID)) { Stream &stream = activeStreams[streamID]; updateStream(stream, decoder.decodedHeader()); - // No DATA frames. - if (continuedFrames[0].flags() & FrameFlag::END_STREAM) { + // Needs to resend the request; we should finish and delete the current stream + const bool needResend = stream.request().d->needResendWithCredentials; + // No DATA frames. Or needs to resend. + if (continuedFrames[0].flags() & FrameFlag::END_STREAM || needResend) { finishStream(stream); deleteActiveStream(stream.streamID); } @@ -1088,7 +1094,7 @@ bool QHttp2ProtocolHandler::acceptSetting(Http2::Settings identifier, quint32 ne if (identifier == Settings::MAX_FRAME_SIZE_ID) { if (newValue < Http2::minPayloadLimit || newValue > Http2::maxPayloadSize) { - connectionError(PROTOCOL_ERROR, "SETTGINGS max frame size is out of range"); + connectionError(PROTOCOL_ERROR, "SETTINGS max frame size is out of range"); return false; } maxFrameSize = newValue; @@ -1108,7 +1114,7 @@ void QHttp2ProtocolHandler::updateStream(Stream &stream, const HPack::HttpHeader Qt::ConnectionType connectionType) { const auto httpReply = stream.reply(); - const auto &httpRequest = stream.request(); + auto &httpRequest = stream.request(); Q_ASSERT(httpReply || stream.state == Stream::remoteReserved); if (!httpReply) { @@ -1146,6 +1152,7 @@ void QHttp2ProtocolHandler::updateStream(Stream &stream, const HPack::HttpHeader if (name == ":status") { statusCode = value.left(3).toInt(); httpReply->setStatusCode(statusCode); + m_channel->lastStatus = statusCode; // Mostly useless for http/2, needed for auth httpReplyPrivate->reasonPhrase = QString::fromLatin1(value.mid(4)); } else if (name == ":version") { httpReplyPrivate->majorVersion = value.at(5) - '0'; @@ -1165,21 +1172,79 @@ void QHttp2ProtocolHandler::updateStream(Stream &stream, const HPack::HttpHeader } } + const auto handleAuth = [&, this](const QByteArray &authField, bool isProxy) -> bool { + Q_ASSERT(httpReply); + const auto auth = authField.trimmed(); + if (auth.startsWith("Negotiate") || auth.startsWith("NTLM")) { + // @todo: We're supposed to fall back to http/1.1: + // https://docs.microsoft.com/en-us/iis/get-started/whats-new-in-iis-10/http2-on-iis#when-is-http2-not-supported + // "Windows authentication (NTLM/Kerberos/Negotiate) is not supported with HTTP/2. + // In this case IIS will fall back to HTTP/1.1." + // Though it might be OK to ignore this. The server shouldn't let us connect with + // HTTP/2 if it doesn't support us using it. + } else if (!auth.isEmpty()) { + // Somewhat mimics parts of QHttpNetworkConnectionChannel::handleStatus + bool resend = false; + const bool authenticateHandled = m_connection->d_func()->handleAuthenticateChallenge( + m_socket, httpReply, isProxy, resend); + if (authenticateHandled && resend) { + httpReply->d_func()->eraseData(); + // Add the request back in queue, we'll retry later now that + // we've gotten some username/password set on it: + httpRequest.d->needResendWithCredentials = true; + m_channel->spdyRequestsToSend.insert(httpRequest.priority(), stream.httpPair); + httpReply->d_func()->clearHeaders(); + // If we have data we were uploading we need to reset it: + if (stream.data()) { + stream.data()->reset(); + httpReplyPrivate->totallyUploadedData = 0; + } + return true; + } // else: Authentication failed or was cancelled + } + return false; + }; + + if (httpReply) { + // See Note further down. These statuses would in HTTP/1.1 be handled + // by QHttpNetworkConnectionChannel::handleStatus. But because h2 has + // multiple streams/requests in a single channel this structure does not + // map properly to that function. + if (httpReply->statusCode() == 401) { + const auto wwwAuth = httpReply->headerField("www-authenticate"); + if (handleAuth(wwwAuth, false)) { + sendRST_STREAM(stream.streamID, CANCEL); + markAsReset(stream.streamID); + // The stream is finalized and deleted after returning + return; + } // else: errors handled later + } else if (httpReply->statusCode() == 407) { + const auto proxyAuth = httpReply->headerField("proxy-authenticate"); + if (handleAuth(proxyAuth, true)) { + sendRST_STREAM(stream.streamID, CANCEL); + markAsReset(stream.streamID); + // The stream is finalized and deleted after returning + return; + } // else: errors handled later + } + } + if (QHttpNetworkReply::isHttpRedirect(statusCode) && redirectUrl.isValid()) httpReply->setRedirectUrl(redirectUrl); if (httpReplyPrivate->isCompressed() && httpRequest.d->autoDecompress) httpReplyPrivate->removeAutoDecompressHeader(); - if (QHttpNetworkReply::isHttpRedirect(statusCode) - || statusCode == 401 || statusCode == 407) { - // These are the status codes that can trigger uploadByteDevice->reset() - // in QHttpNetworkConnectionChannel::handleStatus. Alas, we have no - // single request/reply, we multiplex several requests and thus we never - // simply call 'handleStatus'. If we have byte-device - we try to reset - // it here, we don't (and can't) handle any error during reset operation. - if (stream.data()) + if (QHttpNetworkReply::isHttpRedirect(statusCode)) { + // Note: This status code can trigger uploadByteDevice->reset() in + // QHttpNetworkConnectionChannel::handleStatus. Alas, we have no single + // request/reply, we multiplex several requests and thus we never simply + // call 'handleStatus'. If we have a byte-device - we try to reset it + // here, we don't (and can't) handle any error during reset operation. + if (stream.data()) { stream.data()->reset(); + httpReplyPrivate->totallyUploadedData = 0; + } } if (connectionType == Qt::DirectConnection) @@ -1248,10 +1313,12 @@ void QHttp2ProtocolHandler::finishStream(Stream &stream, Qt::ConnectionType conn if (stream.data()) stream.data()->disconnect(this); - if (connectionType == Qt::DirectConnection) - emit httpReply->finished(); - else - QMetaObject::invokeMethod(httpReply, "finished", connectionType); + if (!stream.request().d->needResendWithCredentials) { + if (connectionType == Qt::DirectConnection) + emit httpReply->finished(); + else + QMetaObject::invokeMethod(httpReply, "finished", connectionType); + } } qCDebug(QT_HTTP2) << "stream" << stream.streamID << "closed"; diff --git a/src/network/access/qhttpnetworkconnection.cpp b/src/network/access/qhttpnetworkconnection.cpp index 9745f3b322..b093eec161 100644 --- a/src/network/access/qhttpnetworkconnection.cpp +++ b/src/network/access/qhttpnetworkconnection.cpp @@ -510,8 +510,8 @@ bool QHttpNetworkConnectionPrivate::handleAuthenticateChallenge(QAbstractSocket channels[i].authenticator = QAuthenticator(); // authentication is cancelled, send the current contents to the user. - emit channels[i].reply->headerChanged(); - emit channels[i].reply->readyRead(); + emit reply->headerChanged(); + emit reply->readyRead(); QNetworkReply::NetworkError errorCode = isProxy ? QNetworkReply::ProxyAuthenticationRequiredError diff --git a/src/network/access/qhttpnetworkconnectionchannel.cpp b/src/network/access/qhttpnetworkconnectionchannel.cpp index f1db274402..4e1aa541a8 100644 --- a/src/network/access/qhttpnetworkconnectionchannel.cpp +++ b/src/network/access/qhttpnetworkconnectionchannel.cpp @@ -697,17 +697,19 @@ bool QHttpNetworkConnectionChannel::resetUploadData() //this happens if server closes connection while QHttpNetworkConnectionPrivate::_q_startNextRequest is pending return false; } - QNonContiguousByteDevice* uploadByteDevice = request.uploadByteDevice(); - if (!uploadByteDevice) - return true; - - if (uploadByteDevice->reset()) { + if (connection->connectionType() == QHttpNetworkConnection::ConnectionTypeHTTP2Direct + || switchedToHttp2) { + // The else branch doesn't make any sense for HTTP/2, since 1 channel is multiplexed into + // many streams. And having one stream fail to reset upload data should not completely close + // the channel. Handled in the http2 protocol handler. + } else if (QNonContiguousByteDevice *uploadByteDevice = request.uploadByteDevice()) { + if (!uploadByteDevice->reset()) { + connection->d_func()->emitReplyError(socket, reply, QNetworkReply::ContentReSendError); + return false; + } written = 0; - return true; - } else { - connection->d_func()->emitReplyError(socket, reply, QNetworkReply::ContentReSendError); - return false; } + return true; } #ifndef QT_NO_NETWORKPROXY diff --git a/src/network/access/qhttpnetworkrequest.cpp b/src/network/access/qhttpnetworkrequest.cpp index 0ae2498bed..a4e4c673a6 100644 --- a/src/network/access/qhttpnetworkrequest.cpp +++ b/src/network/access/qhttpnetworkrequest.cpp @@ -65,6 +65,7 @@ QHttpNetworkRequestPrivate::QHttpNetworkRequestPrivate(const QHttpNetworkRequest withCredentials(other.withCredentials), ssl(other.ssl), preConnect(other.preConnect), + needResendWithCredentials(other.needResendWithCredentials), redirectCount(other.redirectCount), redirectPolicy(other.redirectPolicy), peerVerifyName(other.peerVerifyName) @@ -92,7 +93,8 @@ bool QHttpNetworkRequestPrivate::operator==(const QHttpNetworkRequestPrivate &ot && (ssl == other.ssl) && (preConnect == other.preConnect) && (redirectPolicy == other.redirectPolicy) - && (peerVerifyName == other.peerVerifyName); + && (peerVerifyName == other.peerVerifyName) + && (needResendWithCredentials == other.needResendWithCredentials); } QByteArray QHttpNetworkRequest::methodName() const diff --git a/src/network/access/qhttpnetworkrequest_p.h b/src/network/access/qhttpnetworkrequest_p.h index 038cb97b31..e23d874f19 100644 --- a/src/network/access/qhttpnetworkrequest_p.h +++ b/src/network/access/qhttpnetworkrequest_p.h @@ -183,6 +183,7 @@ public: bool withCredentials; bool ssl; bool preConnect; + bool needResendWithCredentials = false; int redirectCount; QNetworkRequest::RedirectPolicy redirectPolicy; QString peerVerifyName; diff --git a/src/network/access/qnetworkdiskcache.cpp b/src/network/access/qnetworkdiskcache.cpp index b30d1c9664..0fda4d8296 100644 --- a/src/network/access/qnetworkdiskcache.cpp +++ b/src/network/access/qnetworkdiskcache.cpp @@ -417,18 +417,7 @@ QIODevice *QNetworkDiskCache::data(const QUrl &url) buffer->setData(d->lastItem.data.data()); } else { buffer.reset(new QBuffer); - // ### verify that QFile uses the fd size and not the file name - qint64 size = file->size() - file->pos(); - const uchar *p = nullptr; -#if !defined(Q_OS_INTEGRITY) - p = file->map(file->pos(), size); -#endif - if (p) { - buffer->setData((const char *)p, size); - file.take()->setParent(buffer.data()); - } else { - buffer->setData(file->readAll()); - } + buffer->setData(file->readAll()); } } buffer->open(QBuffer::ReadOnly); diff --git a/src/network/access/qspdyprotocolhandler.cpp b/src/network/access/qspdyprotocolhandler.cpp index eef8df288d..c327494e5c 100644 --- a/src/network/access/qspdyprotocolhandler.cpp +++ b/src/network/access/qspdyprotocolhandler.cpp @@ -762,7 +762,8 @@ bool QSpdyProtocolHandler::uploadData(qint32 streamID) void QSpdyProtocolHandler::_q_uploadDataReadyRead() { QNonContiguousByteDevice *device = qobject_cast<QNonContiguousByteDevice *>(sender()); - Q_ASSERT(device); + if (!device) + return; qint32 streamID = m_streamIDs.value(device); Q_ASSERT(streamID > 0); uploadData(streamID); diff --git a/src/network/socket/qlocalsocket.h b/src/network/socket/qlocalsocket.h index 200d59a309..4034329d64 100644 --- a/src/network/socket/qlocalsocket.h +++ b/src/network/socket/qlocalsocket.h @@ -44,6 +44,10 @@ #include <QtCore/qiodevice.h> #include <QtNetwork/qabstractsocket.h> +#ifndef QT_NO_DEBUG_STREAM +#include <QtCore/qdebug.h> +#endif + QT_REQUIRE_CONFIG(localserver); QT_BEGIN_NAMESPACE @@ -146,7 +150,6 @@ private: }; #ifndef QT_NO_DEBUG_STREAM -#include <QtCore/qdebug.h> Q_NETWORK_EXPORT QDebug operator<<(QDebug, QLocalSocket::LocalSocketError); Q_NETWORK_EXPORT QDebug operator<<(QDebug, QLocalSocket::LocalSocketState); #endif diff --git a/src/network/ssl/qsslcertificate_openssl.cpp b/src/network/ssl/qsslcertificate_openssl.cpp index 5022b899aa..3b8f6732bf 100644 --- a/src/network/ssl/qsslcertificate_openssl.cpp +++ b/src/network/ssl/qsslcertificate_openssl.cpp @@ -356,7 +356,7 @@ static QVariant x509UnknownExtensionToValue(X509_EXTENSION *ext) QVariantList list; bool isMap = false; - for (int j = 0; j < q_SKM_sk_num(CONF_VALUE, val); j++) { + for (int j = 0; j < q_SKM_sk_num(val); j++) { CONF_VALUE *nval = q_SKM_sk_value(CONF_VALUE, val, j); if (nval->name && nval->value) { isMap = true; @@ -428,7 +428,7 @@ static QVariant x509ExtensionToValue(X509_EXTENSION *ext) return QVariant(); QVariantMap result; - for (int i=0; i < q_SKM_sk_num(ACCESS_DESCRIPTION, info); i++) { + for (int i=0; i < q_SKM_sk_num(info); i++) { ACCESS_DESCRIPTION *ad = q_SKM_sk_value(ACCESS_DESCRIPTION, info, i); GENERAL_NAME *name = ad->location; diff --git a/src/network/ssl/qsslsocket_openssl_symbols_p.h b/src/network/ssl/qsslsocket_openssl_symbols_p.h index c46afcf53e..20ce245fe7 100644 --- a/src/network/ssl/qsslsocket_openssl_symbols_p.h +++ b/src/network/ssl/qsslsocket_openssl_symbols_p.h @@ -269,8 +269,8 @@ int q_DH_bits(DH *dh); # define q_SSL_load_error_strings() q_OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS \ | OPENSSL_INIT_LOAD_CRYPTO_STRINGS, NULL) -#define q_SKM_sk_num(type, st) ((int (*)(const STACK_OF(type) *))q_OPENSSL_sk_num)(st) -#define q_SKM_sk_value(type, st,i) ((type * (*)(const STACK_OF(type) *, int))q_OPENSSL_sk_value)(st, i) +#define q_SKM_sk_num(st) q_OPENSSL_sk_num((OPENSSL_STACK *)st) +#define q_SKM_sk_value(type, st,i) (type *)q_OPENSSL_sk_value((OPENSSL_STACK *)st, i) #define q_OPENSSL_add_all_algorithms_conf() q_OPENSSL_init_crypto(OPENSSL_INIT_ADD_ALL_CIPHERS \ | OPENSSL_INIT_ADD_ALL_DIGESTS \ @@ -611,14 +611,14 @@ void q_PKCS12_free(PKCS12 *pkcs12); #define q_BIO_get_mem_data(b, pp) (int)q_BIO_ctrl(b,BIO_CTRL_INFO,0,(char *)pp) #define q_BIO_pending(b) (int)q_BIO_ctrl(b,BIO_CTRL_PENDING,0,NULL) #define q_SSL_CTX_set_mode(ctx,op) q_SSL_CTX_ctrl((ctx),SSL_CTRL_MODE,(op),NULL) -#define q_sk_GENERAL_NAME_num(st) q_SKM_sk_num(GENERAL_NAME, (st)) +#define q_sk_GENERAL_NAME_num(st) q_SKM_sk_num((st)) #define q_sk_GENERAL_NAME_value(st, i) q_SKM_sk_value(GENERAL_NAME, (st), (i)) void q_GENERAL_NAME_free(GENERAL_NAME *a); -#define q_sk_X509_num(st) q_SKM_sk_num(X509, (st)) +#define q_sk_X509_num(st) q_SKM_sk_num((st)) #define q_sk_X509_value(st, i) q_SKM_sk_value(X509, (st), (i)) -#define q_sk_SSL_CIPHER_num(st) q_SKM_sk_num(SSL_CIPHER, (st)) +#define q_sk_SSL_CIPHER_num(st) q_SKM_sk_num((st)) #define q_sk_SSL_CIPHER_value(st, i) q_SKM_sk_value(SSL_CIPHER, (st), (i)) #define q_SSL_CTX_add_extra_chain_cert(ctx,x509) \ q_SSL_CTX_ctrl(ctx,SSL_CTRL_EXTRA_CHAIN_CERT,0,(char *)x509) |