summaryrefslogtreecommitdiffstats
path: root/src/network
diff options
context:
space:
mode:
Diffstat (limited to 'src/network')
-rw-r--r--src/network/access/qhttp2protocolhandler.cpp101
-rw-r--r--src/network/access/qhttpnetworkconnection.cpp4
-rw-r--r--src/network/access/qhttpnetworkconnectionchannel.cpp20
-rw-r--r--src/network/access/qhttpnetworkrequest.cpp4
-rw-r--r--src/network/access/qhttpnetworkrequest_p.h1
-rw-r--r--src/network/access/qnetworkdiskcache.cpp13
-rw-r--r--src/network/access/qspdyprotocolhandler.cpp3
-rw-r--r--src/network/socket/qlocalsocket.h5
-rw-r--r--src/network/ssl/qsslcertificate_openssl.cpp4
-rw-r--r--src/network/ssl/qsslsocket_openssl_symbols_p.h10
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)