Retire SPDY protocol implementation (Qt6)

As it was superseded by HTTP/2. Bye, Speedy. Since it's Qt 6,
we also fix the attribute's enumerator to fit our coding
convention with HTTP2AllowedAttribute becoming Http2AllowedAttribute,
and the same for HTTP2WasUsedAttribute.

tst_qnetworkreply in 'benchmark' directory of qtbase/tests
was updated - we have the logic they tested in preConnectEncrypted
in tst_http2 now.

Manual qnetworkreply test was updated (instead of SPDY in NPN failure
we can use H2, the second test was deleted - again, auto-tested in
tst_http2).

Change-Id: I559c140c333ddf72664911c6e275b1d0d2b980a9
Task-number: QTBUG-78255
Reviewed-by: Mårten Nordheim <marten.nordheim@qt.io>
bb10
Timur Pocheptsov 2019-09-10 09:04:17 +02:00
parent 3bf3964b37
commit 13e0a36626
27 changed files with 96 additions and 2702 deletions

View File

@ -114,11 +114,4 @@ qtConfig(http) {
access/qhttpthreaddelegate_p.h \
access/qnetworkreplyhttpimpl_p.h \
access/qhttp2configuration.h
qtConfig(ssl) {
SOURCES += \
access/qspdyprotocolhandler.cpp
HEADERS += \
access/qspdyprotocolhandler_p.h
}
}

View File

@ -332,13 +332,13 @@ bool QHttp2ProtocolHandler::sendRequest()
// so we cannot create new streams.
m_channel->emitFinishedWithError(QNetworkReply::ProtocolUnknownError,
"GOAWAY received, cannot start a request");
m_channel->spdyRequestsToSend.clear();
m_channel->h2RequestsToSend.clear();
return false;
}
// Process 'fake' (created by QNetworkAccessManager::connectToHostEncrypted())
// requests first:
auto &requests = m_channel->spdyRequestsToSend;
auto &requests = m_channel->h2RequestsToSend;
for (auto it = requests.begin(), endIt = requests.end(); it != endIt;) {
const auto &pair = *it;
const QString scheme(pair.first.url().scheme());
@ -862,7 +862,7 @@ void QHttp2ProtocolHandler::handleGOAWAY()
m_channel->emitFinishedWithError(QNetworkReply::ProtocolUnknownError,
"GOAWAY received, cannot start a request");
// Also, prevent further calls to sendRequest:
m_channel->spdyRequestsToSend.clear();
m_channel->h2RequestsToSend.clear();
QNetworkReply::NetworkError error = QNetworkReply::NoError;
QString message;
@ -1281,7 +1281,7 @@ quint32 QHttp2ProtocolHandler::createNewStream(const HttpMessagePair &message, b
const auto replyPrivate = reply->d_func();
replyPrivate->connection = m_connection;
replyPrivate->connectionChannel = m_channel;
reply->setSpdyWasUsed(true);
reply->setHttp2WasUsed(true);
streamIDs.insert(reply, newStreamID);
connect(reply, SIGNAL(destroyed(QObject*)),
this, SLOT(_q_replyDestroyed(QObject*)));
@ -1390,7 +1390,7 @@ void QHttp2ProtocolHandler::deleteActiveStream(quint32 streamID)
}
removeFromSuspended(streamID);
if (m_channel->spdyRequestsToSend.size())
if (m_channel->h2RequestsToSend.size())
QMetaObject::invokeMethod(this, "sendRequest", Qt::QueuedConnection);
}
@ -1509,7 +1509,7 @@ void QHttp2ProtocolHandler::initReplyFromPushPromise(const HttpMessagePair &mess
Q_ASSERT(promisedData.contains(cacheKey));
auto promise = promisedData.take(cacheKey);
Q_ASSERT(message.second);
message.second->setSpdyWasUsed(true);
message.second->setHttp2WasUsed(true);
qCDebug(QT_HTTP2) << "found cached/promised response on stream" << promise.reservedID;

View File

@ -82,9 +82,6 @@ QHttpNetworkConnectionPrivate::QHttpNetworkConnectionPrivate(const QString &host
hostName(hostName), port(port), encrypt(encrypt), delayIpv4(true)
, activeChannelCount(type == QHttpNetworkConnection::ConnectionTypeHTTP2
|| type == QHttpNetworkConnection::ConnectionTypeHTTP2Direct
#ifndef QT_NO_SSL
|| type == QHttpNetworkConnection::ConnectionTypeSPDY
#endif
? 1 : defaultHttpChannelCount)
, channelCount(defaultHttpChannelCount)
#ifndef QT_NO_NETWORKPROXY
@ -93,9 +90,9 @@ QHttpNetworkConnectionPrivate::QHttpNetworkConnectionPrivate(const QString &host
, preConnectRequests(0)
, connectionType(type)
{
// We allocate all 6 channels even if it's SPDY or HTTP/2 enabled
// connection: in case the protocol negotiation via NPN/ALPN fails,
// we will have normally working HTTP/1.1.
// We allocate all 6 channels even if it's HTTP/2 enabled connection:
// in case the protocol negotiation via NPN/ALPN fails, we will have
// normally working HTTP/1.1.
Q_ASSERT(channelCount >= activeChannelCount);
channels = new QHttpNetworkConnectionChannel[channelCount];
}
@ -641,10 +638,10 @@ QHttpNetworkReply* QHttpNetworkConnectionPrivate::queueRequest(const QHttpNetwor
break;
}
}
else { // SPDY, HTTP/2 ('h2' mode)
else { // HTTP/2 ('h2' mode)
if (!pair.second->d_func()->requestIsPrepared)
prepareRequest(pair);
channels[0].spdyRequestsToSend.insert(request.priority(), pair);
channels[0].h2RequestsToSend.insert(request.priority(), pair);
}
#ifndef Q_OS_WINRT
@ -680,7 +677,7 @@ void QHttpNetworkConnectionPrivate::fillHttp2Queue()
for (auto &pair : highPriorityQueue) {
if (!pair.second->d_func()->requestIsPrepared)
prepareRequest(pair);
channels[0].spdyRequestsToSend.insert(QHttpNetworkRequest::HighPriority, pair);
channels[0].h2RequestsToSend.insert(QHttpNetworkRequest::HighPriority, pair);
}
highPriorityQueue.clear();
@ -688,7 +685,7 @@ void QHttpNetworkConnectionPrivate::fillHttp2Queue()
for (auto &pair : lowPriorityQueue) {
if (!pair.second->d_func()->requestIsPrepared)
prepareRequest(pair);
channels[0].spdyRequestsToSend.insert(pair.first.priority(), pair);
channels[0].h2RequestsToSend.insert(pair.first.priority(), pair);
}
lowPriorityQueue.clear();
@ -984,12 +981,12 @@ void QHttpNetworkConnectionPrivate::removeReply(QHttpNetworkReply *reply)
}
}
#ifndef QT_NO_SSL
// is the reply inside the SPDY pipeline of this channel already?
QMultiMap<int, HttpMessagePair>::iterator it = channels[i].spdyRequestsToSend.begin();
QMultiMap<int, HttpMessagePair>::iterator end = channels[i].spdyRequestsToSend.end();
// is the reply inside the H2 pipeline of this channel already?
QMultiMap<int, HttpMessagePair>::iterator it = channels[i].h2RequestsToSend.begin();
QMultiMap<int, HttpMessagePair>::iterator end = channels[i].h2RequestsToSend.end();
for (; it != end; ++it) {
if (it.value().second == reply) {
channels[i].spdyRequestsToSend.remove(it.key());
channels[i].h2RequestsToSend.remove(it.key());
QMetaObject::invokeMethod(q, "_q_startNextRequest", Qt::QueuedConnection);
return;
@ -1068,9 +1065,8 @@ void QHttpNetworkConnectionPrivate::_q_startNextRequest()
break;
}
case QHttpNetworkConnection::ConnectionTypeHTTP2Direct:
case QHttpNetworkConnection::ConnectionTypeHTTP2:
case QHttpNetworkConnection::ConnectionTypeSPDY: {
if (channels[0].spdyRequestsToSend.isEmpty() && channels[0].switchedToHttp2)
case QHttpNetworkConnection::ConnectionTypeHTTP2: {
if (channels[0].h2RequestsToSend.isEmpty() && channels[0].switchedToHttp2)
return;
if (networkLayerState == IPv4)
@ -1079,7 +1075,7 @@ void QHttpNetworkConnectionPrivate::_q_startNextRequest()
channels[0].networkLayerPreference = QAbstractSocket::IPv6Protocol;
channels[0].ensureConnection();
if (channels[0].socket && channels[0].socket->state() == QAbstractSocket::ConnectedState
&& !channels[0].pendingEncrypt && channels[0].spdyRequestsToSend.size())
&& !channels[0].pendingEncrypt && channels[0].h2RequestsToSend.size())
channels[0].sendRequest();
break;
}
@ -1234,19 +1230,18 @@ void QHttpNetworkConnectionPrivate::_q_hostLookupFinished(const QHostInfo &info)
if (dequeueRequest(channels[0].socket)) {
emitReplyError(channels[0].socket, channels[0].reply, QNetworkReply::HostNotFoundError);
networkLayerState = QHttpNetworkConnectionPrivate::Unknown;
} else if (connectionType == QHttpNetworkConnection::ConnectionTypeSPDY
|| connectionType == QHttpNetworkConnection::ConnectionTypeHTTP2
} else if (connectionType == QHttpNetworkConnection::ConnectionTypeHTTP2
|| connectionType == QHttpNetworkConnection::ConnectionTypeHTTP2Direct) {
for (const HttpMessagePair &spdyPair : qAsConst(channels[0].spdyRequestsToSend)) {
for (const HttpMessagePair &h2Pair : qAsConst(channels[0].h2RequestsToSend)) {
// emit error for all replies
QHttpNetworkReply *currentReply = spdyPair.second;
QHttpNetworkReply *currentReply = h2Pair.second;
Q_ASSERT(currentReply);
emitReplyError(channels[0].socket, currentReply, QNetworkReply::HostNotFoundError);
}
} else {
// Should not happen: we start a host lookup before sending a request,
// so it's natural to have requests either in SPDY/HTTP/2 queue,
// or in low/high priority queues.
// so it's natural to have requests either in HTTP/2 queue, or in low/high
// priority queues.
qWarning("QHttpNetworkConnectionPrivate::_q_hostLookupFinished"
" could not de-queue request, failed to report HostNotFoundError");
networkLayerState = QHttpNetworkConnectionPrivate::Unknown;
@ -1576,17 +1571,12 @@ void QHttpNetworkConnectionPrivate::emitProxyAuthenticationRequired(const QHttpN
pauseConnection();
QHttpNetworkReply *reply;
if (connectionType == QHttpNetworkConnection::ConnectionTypeHTTP2
|| connectionType == QHttpNetworkConnection::ConnectionTypeHTTP2Direct
#if QT_CONFIG(ssl)
|| connectionType == QHttpNetworkConnection::ConnectionTypeSPDY
#endif
) {
|| connectionType == QHttpNetworkConnection::ConnectionTypeHTTP2Direct) {
// we choose the reply to emit the proxyAuth signal from somewhat arbitrarily,
// but that does not matter because the signal will ultimately be emitted
// by the QNetworkAccessManager.
Q_ASSERT(chan->spdyRequestsToSend.count() > 0);
reply = chan->spdyRequestsToSend.cbegin().value().second;
Q_ASSERT(chan->h2RequestsToSend.count() > 0);
reply = chan->h2RequestsToSend.cbegin().value().second;
} else { // HTTP
reply = chan->reply;
}

View File

@ -96,7 +96,6 @@ public:
enum ConnectionType {
ConnectionTypeHTTP,
ConnectionTypeSPDY,
ConnectionTypeHTTP2,
ConnectionTypeHTTP2Direct
};
@ -172,7 +171,6 @@ private:
friend class QHttpNetworkConnectionChannel;
friend class QHttp2ProtocolHandler;
friend class QHttpProtocolHandler;
friend class QSpdyProtocolHandler;
Q_PRIVATE_SLOT(d_func(), void _q_startNextRequest())
Q_PRIVATE_SLOT(d_func(), void _q_hostLookupFinished(QHostInfo))

View File

@ -48,7 +48,6 @@
#include <private/qhttp2protocolhandler_p.h>
#include <private/qhttpprotocolhandler_p.h>
#include <private/qspdyprotocolhandler_p.h>
#include <private/http2protocol_p.h>
#ifndef QT_NO_SSL
@ -931,7 +930,7 @@ void QHttpNetworkConnectionChannel::_q_connected()
} else if (connection->connectionType() == QHttpNetworkConnection::ConnectionTypeHTTP2Direct) {
state = QHttpNetworkConnectionChannel::IdleState;
protocolHandler.reset(new QHttp2ProtocolHandler(this));
if (spdyRequestsToSend.count() > 0) {
if (h2RequestsToSend.count() > 0) {
// In case our peer has sent us its settings (window size, max concurrent streams etc.)
// let's give _q_receiveReply a chance to read them first ('invokeMethod', QueuedConnection).
QMetaObject::invokeMethod(connection, "_q_startNextRequest", Qt::QueuedConnection);
@ -1108,15 +1107,11 @@ void QHttpNetworkConnectionChannel::_q_error(QAbstractSocket::SocketError socket
|| !connection->d_func()->lowPriorityQueue.isEmpty());
if (connection->connectionType() == QHttpNetworkConnection::ConnectionTypeHTTP2
|| connection->connectionType() == QHttpNetworkConnection::ConnectionTypeHTTP2Direct
#ifndef QT_NO_SSL
|| connection->connectionType() == QHttpNetworkConnection::ConnectionTypeSPDY
#endif
) {
QList<HttpMessagePair> spdyPairs = spdyRequestsToSend.values();
for (int a = 0; a < spdyPairs.count(); ++a) {
|| connection->connectionType() == QHttpNetworkConnection::ConnectionTypeHTTP2Direct) {
QList<HttpMessagePair> h2Pairs = h2RequestsToSend.values();
for (int a = 0; a < h2Pairs.count(); ++a) {
// emit error for all replies
QHttpNetworkReply *currentReply = spdyPairs.at(a).second;
QHttpNetworkReply *currentReply = h2Pairs.at(a).second;
Q_ASSERT(currentReply);
emit currentReply->finishedWithError(errorCode, errorString);
}
@ -1143,12 +1138,8 @@ void QHttpNetworkConnectionChannel::_q_error(QAbstractSocket::SocketError socket
void QHttpNetworkConnectionChannel::_q_proxyAuthenticationRequired(const QNetworkProxy &proxy, QAuthenticator* auth)
{
if (connection->connectionType() == QHttpNetworkConnection::ConnectionTypeHTTP2
|| connection->connectionType() == QHttpNetworkConnection::ConnectionTypeHTTP2Direct
#ifndef QT_NO_SSL
|| connection->connectionType() == QHttpNetworkConnection::ConnectionTypeSPDY
#endif
) {
if (spdyRequestsToSend.count() > 0)
|| connection->connectionType() == QHttpNetworkConnection::ConnectionTypeHTTP2Direct) {
if (h2RequestsToSend.count() > 0)
connection->d_func()->emitProxyAuthenticationRequired(this, proxy, auth);
} else { // HTTP
// Need to dequeue the request before we can emit the error.
@ -1171,9 +1162,9 @@ void QHttpNetworkConnectionChannel::emitFinishedWithError(QNetworkReply::Network
{
if (reply)
emit reply->finishedWithError(error, QHttpNetworkConnectionChannel::tr(message));
QList<HttpMessagePair> spdyPairs = spdyRequestsToSend.values();
for (int a = 0; a < spdyPairs.count(); ++a) {
QHttpNetworkReply *currentReply = spdyPairs.at(a).second;
QList<HttpMessagePair> h2Pairs = h2RequestsToSend.values();
for (int a = 0; a < h2Pairs.count(); ++a) {
QHttpNetworkReply *currentReply = h2Pairs.at(a).second;
Q_ASSERT(currentReply);
emit currentReply->finishedWithError(error, QHttpNetworkConnectionChannel::tr(message));
}
@ -1195,12 +1186,6 @@ void QHttpNetworkConnectionChannel::_q_encrypted()
QByteArray nextProtocol = sslSocket->sslConfiguration().nextNegotiatedProtocol();
if (nextProtocol == QSslConfiguration::NextProtocolHttp1_1) {
// fall through to create a QHttpProtocolHandler
} else if (nextProtocol == QSslConfiguration::NextProtocolSpdy3_0) {
protocolHandler.reset(new QSpdyProtocolHandler(this));
connection->setConnectionType(QHttpNetworkConnection::ConnectionTypeSPDY);
// no need to re-queue requests, if SPDY was enabled on the request it
// has gone to the SPDY queue already
break;
} else if (nextProtocol == QSslConfiguration::ALPNProtocolHTTP2) {
switchedToHttp2 = true;
protocolHandler.reset(new QHttp2ProtocolHandler(this));
@ -1229,8 +1214,6 @@ void QHttpNetworkConnectionChannel::_q_encrypted()
// it again on other channels that our connection can create/open.
if (connection->connectionType() == QHttpNetworkConnection::ConnectionTypeHTTP2)
protocols.removeAll(QSslConfiguration::ALPNProtocolHTTP2);
else if (connection->connectionType() == QHttpNetworkConnection::ConnectionTypeSPDY)
protocols.removeAll(QSslConfiguration::NextProtocolSpdy3_0);
if (nProtocols > protocols.size()) {
sslConfiguration->setAllowedNextProtocols(protocols);
@ -1240,13 +1223,13 @@ void QHttpNetworkConnectionChannel::_q_encrypted()
}
connection->setConnectionType(QHttpNetworkConnection::ConnectionTypeHTTP);
// We use only one channel for SPDY or HTTP/2, but normally six for
// We use only one channel for HTTP/2, but normally six for
// HTTP/1.1 - let's restore this number to the reserved number of
// channels:
if (connection->d_func()->activeChannelCount < connection->d_func()->channelCount) {
connection->d_func()->activeChannelCount = connection->d_func()->channelCount;
// re-queue requests from SPDY queue to HTTP queue, if any
requeueSpdyRequests();
// re-queue requests from HTTP/2 queue to HTTP queue, if any
requeueHttp2Requests();
}
break;
}
@ -1266,11 +1249,9 @@ void QHttpNetworkConnectionChannel::_q_encrypted()
state = QHttpNetworkConnectionChannel::IdleState;
pendingEncrypt = false;
if (connection->connectionType() == QHttpNetworkConnection::ConnectionTypeSPDY ||
connection->connectionType() == QHttpNetworkConnection::ConnectionTypeHTTP2 ||
if (connection->connectionType() == QHttpNetworkConnection::ConnectionTypeHTTP2 ||
connection->connectionType() == QHttpNetworkConnection::ConnectionTypeHTTP2Direct) {
// we call setSpdyWasUsed(true) on the replies in the SPDY handler when the request is sent
if (spdyRequestsToSend.count() > 0) {
if (h2RequestsToSend.count() > 0) {
// In case our peer has sent us its settings (window size, max concurrent streams etc.)
// let's give _q_receiveReply a chance to read them first ('invokeMethod', QueuedConnection).
QMetaObject::invokeMethod(connection, "_q_startNextRequest", Qt::QueuedConnection);
@ -1279,7 +1260,7 @@ void QHttpNetworkConnectionChannel::_q_encrypted()
if (!reply)
connection->d_func()->dequeueRequest(socket);
if (reply) {
reply->setSpdyWasUsed(false);
reply->setHttp2WasUsed(false);
Q_ASSERT(reply->d_func()->connectionChannel == this);
emit reply->encrypted();
}
@ -1288,13 +1269,12 @@ void QHttpNetworkConnectionChannel::_q_encrypted()
}
}
void QHttpNetworkConnectionChannel::requeueSpdyRequests()
void QHttpNetworkConnectionChannel::requeueHttp2Requests()
{
QList<HttpMessagePair> spdyPairs = spdyRequestsToSend.values();
for (int a = 0; a < spdyPairs.count(); ++a) {
connection->d_func()->requeueRequest(spdyPairs.at(a));
}
spdyRequestsToSend.clear();
QList<HttpMessagePair> h2Pairs = h2RequestsToSend.values();
for (int a = 0; a < h2Pairs.count(); ++a)
connection->d_func()->requeueRequest(h2Pairs.at(a));
h2RequestsToSend.clear();
}
void QHttpNetworkConnectionChannel::_q_sslErrors(const QList<QSslError> &errors)
@ -1312,11 +1292,11 @@ void QHttpNetworkConnectionChannel::_q_sslErrors(const QList<QSslError> &errors)
emit reply->sslErrors(errors);
}
#ifndef QT_NO_SSL
else { // SPDY
QList<HttpMessagePair> spdyPairs = spdyRequestsToSend.values();
for (int a = 0; a < spdyPairs.count(); ++a) {
else { // HTTP/2
QList<HttpMessagePair> h2Pairs = h2RequestsToSend.values();
for (int a = 0; a < h2Pairs.count(); ++a) {
// emit SSL errors for all replies
QHttpNetworkReply *currentReply = spdyPairs.at(a).second;
QHttpNetworkReply *currentReply = h2Pairs.at(a).second;
Q_ASSERT(currentReply);
emit currentReply->sslErrors(errors);
}
@ -1336,10 +1316,10 @@ void QHttpNetworkConnectionChannel::_q_preSharedKeyAuthenticationRequired(QSslPr
if (reply)
emit reply->preSharedKeyAuthenticationRequired(authenticator);
} else {
QList<HttpMessagePair> spdyPairs = spdyRequestsToSend.values();
for (int a = 0; a < spdyPairs.count(); ++a) {
QList<HttpMessagePair> h2Pairs = h2RequestsToSend.values();
for (int a = 0; a < h2Pairs.count(); ++a) {
// emit SSL errors for all replies
QHttpNetworkReply *currentReply = spdyPairs.at(a).second;
QHttpNetworkReply *currentReply = h2Pairs.at(a).second;
Q_ASSERT(currentReply);
emit currentReply->preSharedKeyAuthenticationRequired(authenticator);
}

View File

@ -123,10 +123,7 @@ public:
bool authenticationCredentialsSent;
bool proxyCredentialsSent;
QScopedPointer<QAbstractProtocolHandler> protocolHandler;
// SPDY or HTTP/2 requests; SPDY is TLS-only, but
// HTTP/2 can be cleartext also, that's why it's
// outside of QT_NO_SSL section. Sorted by priority:
QMultiMap<int, HttpMessagePair> spdyRequestsToSend;
QMultiMap<int, HttpMessagePair> h2RequestsToSend;
bool switchedToHttp2 = false;
#ifndef QT_NO_SSL
bool ignoreAllSslErrors;
@ -135,7 +132,7 @@ public:
void ignoreSslErrors();
void ignoreSslErrors(const QList<QSslError> &errors);
void setSslConfiguration(const QSslConfiguration &config);
void requeueSpdyRequests(); // when we wanted SPDY but got HTTP
void requeueHttp2Requests(); // when we wanted HTTP/2 but got HTTP/1.1
#endif
// to emit the signal for all in-flight replies:
void emitFinishedWithError(QNetworkReply::NetworkError error, const char *message);

View File

@ -287,14 +287,14 @@ bool QHttpNetworkReply::isPipeliningUsed() const
return d_func()->pipeliningUsed;
}
bool QHttpNetworkReply::isSpdyUsed() const
bool QHttpNetworkReply::isHttp2Used() const
{
return d_func()->spdyUsed;
return d_func()->h2Used;
}
void QHttpNetworkReply::setSpdyWasUsed(bool spdy)
void QHttpNetworkReply::setHttp2WasUsed(bool h2)
{
d_func()->spdyUsed = spdy;
d_func()->h2Used = h2;
}
qint64 QHttpNetworkReply::removedContentLength() const
@ -324,15 +324,11 @@ QHttpNetworkReplyPrivate::QHttpNetworkReplyPrivate(const QUrl &newUrl)
forceConnectionCloseEnabled(false),
lastChunkRead(false),
currentChunkSize(0), currentChunkRead(0), readBufferMaxSize(0),
windowSizeDownload(65536), // 64K initial window size according to SPDY standard
windowSizeUpload(65536), // 64K initial window size according to SPDY standard
currentlyReceivedDataInWindow(0),
currentlyUploadedDataInWindow(0),
totallyUploadedData(0),
removedContentLength(-1),
connection(0),
autoDecompress(false), responseData(), requestIsPrepared(false)
,pipeliningUsed(false), spdyUsed(false), downstreamLimited(false)
,pipeliningUsed(false), h2Used(false), downstreamLimited(false)
,userProvidedDownloadBuffer(0)
#ifndef QT_NO_COMPRESS
,inflateStrm(0)

View File

@ -137,8 +137,8 @@ public:
bool isFinished() const;
bool isPipeliningUsed() const;
bool isSpdyUsed() const;
void setSpdyWasUsed(bool spdy);
bool isHttp2Used() const;
void setHttp2WasUsed(bool h2Used);
qint64 removedContentLength() const;
bool isRedirecting() const;
@ -251,11 +251,7 @@ public:
qint64 currentChunkSize;
qint64 currentChunkRead;
qint64 readBufferMaxSize;
qint32 windowSizeDownload; // only for SPDY
qint32 windowSizeUpload; // only for SPDY
qint32 currentlyReceivedDataInWindow; // only for SPDY
qint32 currentlyUploadedDataInWindow; // only for SPDY
qint64 totallyUploadedData; // only for SPDY
qint64 totallyUploadedData; // HTTP/2
qint64 removedContentLength;
QPointer<QHttpNetworkConnection> connection;
QPointer<QHttpNetworkConnectionChannel> connectionChannel;
@ -267,7 +263,7 @@ public:
bool requestIsPrepared;
bool pipeliningUsed;
bool spdyUsed;
bool h2Used;
bool downstreamLimited;
char* userProvidedDownloadBuffer;

View File

@ -45,7 +45,7 @@ QT_BEGIN_NAMESPACE
QHttpNetworkRequestPrivate::QHttpNetworkRequestPrivate(QHttpNetworkRequest::Operation op,
QHttpNetworkRequest::Priority pri, const QUrl &newUrl)
: QHttpNetworkHeaderPrivate(newUrl), operation(op), priority(pri), uploadByteDevice(0),
autoDecompress(false), pipeliningAllowed(false), spdyAllowed(false), http2Allowed(false),
autoDecompress(false), pipeliningAllowed(false), http2Allowed(false),
http2Direct(false), withCredentials(true), preConnect(false), redirectCount(0),
redirectPolicy(QNetworkRequest::ManualRedirectPolicy)
{
@ -59,7 +59,6 @@ QHttpNetworkRequestPrivate::QHttpNetworkRequestPrivate(const QHttpNetworkRequest
uploadByteDevice(other.uploadByteDevice),
autoDecompress(other.autoDecompress),
pipeliningAllowed(other.pipeliningAllowed),
spdyAllowed(other.spdyAllowed),
http2Allowed(other.http2Allowed),
http2Direct(other.http2Direct),
withCredentials(other.withCredentials),
@ -83,7 +82,6 @@ bool QHttpNetworkRequestPrivate::operator==(const QHttpNetworkRequestPrivate &ot
&& (uploadByteDevice == other.uploadByteDevice)
&& (autoDecompress == other.autoDecompress)
&& (pipeliningAllowed == other.pipeliningAllowed)
&& (spdyAllowed == other.spdyAllowed)
&& (http2Allowed == other.http2Allowed)
&& (http2Direct == other.http2Direct)
// we do not clear the customVerb in setOperation
@ -339,16 +337,6 @@ void QHttpNetworkRequest::setPipeliningAllowed(bool b)
d->pipeliningAllowed = b;
}
bool QHttpNetworkRequest::isSPDYAllowed() const
{
return d->spdyAllowed;
}
void QHttpNetworkRequest::setSPDYAllowed(bool b)
{
d->spdyAllowed = b;
}
bool QHttpNetworkRequest::isHTTP2Allowed() const
{
return d->http2Allowed;

View File

@ -116,9 +116,6 @@ public:
bool isPipeliningAllowed() const;
void setPipeliningAllowed(bool b);
bool isSPDYAllowed() const;
void setSPDYAllowed(bool b);
bool isHTTP2Allowed() const;
void setHTTP2Allowed(bool b);
@ -176,7 +173,6 @@ public:
mutable QNonContiguousByteDevice* uploadByteDevice;
bool autoDecompress;
bool pipeliningAllowed;
bool spdyAllowed;
bool http2Allowed;
bool http2Direct;
bool withCredentials;

View File

@ -236,7 +236,7 @@ QHttpThreadDelegate::QHttpThreadDelegate(QObject *parent) :
, synchronous(false)
, incomingStatusCode(0)
, isPipeliningUsed(false)
, isSpdyUsed(false)
, isHttp2Used(false)
, incomingContentLength(-1)
, removedContentLength(-1)
, incomingErrorCode(QNetworkReply::NoError)
@ -320,17 +320,6 @@ void QHttpThreadDelegate::startRequest()
}
}
#ifndef QT_NO_SSL
if (!isH2 && httpRequest.isSPDYAllowed() && ssl) {
connectionType = QHttpNetworkConnection::ConnectionTypeSPDY;
urlCopy.setScheme(QStringLiteral("spdy")); // to differentiate SPDY requests from HTTPS requests
QList<QByteArray> nextProtocols;
nextProtocols << QSslConfiguration::NextProtocolSpdy3_0
<< QSslConfiguration::NextProtocolHttp1_1;
incomingSslConfiguration->setAllowedNextProtocols(nextProtocols);
}
#endif // QT_NO_SSL
#ifndef QT_NO_NETWORKPROXY
if (transparentProxy.type() != QNetworkProxy::NoProxy)
cacheKey = makeCacheKey(urlCopy, &transparentProxy, httpRequest.peerVerifyName());
@ -652,7 +641,7 @@ void QHttpThreadDelegate::headerChangedSlot()
isPipeliningUsed = httpReply->isPipeliningUsed();
incomingContentLength = httpReply->contentLength();
removedContentLength = httpReply->removedContentLength();
isSpdyUsed = httpReply->isSpdyUsed();
isHttp2Used = httpReply->isHttp2Used();
emit downloadMetaData(incomingHeaders,
incomingStatusCode,
@ -661,7 +650,7 @@ void QHttpThreadDelegate::headerChangedSlot()
downloadBuffer,
incomingContentLength,
removedContentLength,
isSpdyUsed);
isHttp2Used);
}
void QHttpThreadDelegate::synchronousHeaderChangedSlot()
@ -677,7 +666,7 @@ void QHttpThreadDelegate::synchronousHeaderChangedSlot()
incomingStatusCode = httpReply->statusCode();
incomingReasonPhrase = httpReply->reasonPhrase();
isPipeliningUsed = httpReply->isPipeliningUsed();
isSpdyUsed = httpReply->isSpdyUsed();
isHttp2Used = httpReply->isHttp2Used();
incomingContentLength = httpReply->contentLength();
}

View File

@ -112,7 +112,7 @@ public:
int incomingStatusCode;
QString incomingReasonPhrase;
bool isPipeliningUsed;
bool isSpdyUsed;
bool isHttp2Used;
qint64 incomingContentLength;
qint64 removedContentLength;
QNetworkReply::NetworkError incomingErrorCode;

View File

@ -1237,12 +1237,10 @@ void QNetworkAccessManager::connectToHostEncrypted(const QString &hostName, quin
if (sslConfiguration != QSslConfiguration::defaultConfiguration())
request.setSslConfiguration(sslConfiguration);
// There is no way to enable SPDY/HTTP2 via a request, so we need to check
// the ssl configuration whether SPDY/HTTP2 is allowed here.
// There is no way to enable HTTP2 via a request, so we need to check
// the ssl configuration whether HTTP2 is allowed here.
if (sslConfiguration.allowedNextProtocols().contains(QSslConfiguration::ALPNProtocolHTTP2))
request.setAttribute(QNetworkRequest::HTTP2AllowedAttribute, true);
else if (sslConfiguration.allowedNextProtocols().contains(QSslConfiguration::NextProtocolSpdy3_0))
request.setAttribute(QNetworkRequest::SpdyAllowedAttribute, true);
request.setAttribute(QNetworkRequest::Http2AllowedAttribute, true);
request.setPeerVerifyName(peerName);
get(request);

View File

@ -774,10 +774,7 @@ void QNetworkReplyHttpImplPrivate::postRequest(const QNetworkRequest &newHttpReq
if (newHttpRequest.attribute(QNetworkRequest::HttpPipeliningAllowedAttribute).toBool())
httpRequest.setPipeliningAllowed(true);
if (request.attribute(QNetworkRequest::SpdyAllowedAttribute).toBool())
httpRequest.setSPDYAllowed(true);
if (request.attribute(QNetworkRequest::HTTP2AllowedAttribute).toBool())
if (request.attribute(QNetworkRequest::Http2AllowedAttribute).toBool())
httpRequest.setHTTP2Allowed(true);
if (request.attribute(QNetworkRequest::Http2DirectAttribute).toBool()) {
@ -968,7 +965,7 @@ void QNetworkReplyHttpImplPrivate::postRequest(const QNetworkRequest &newHttpReq
QSharedPointer<char>(),
delegate->incomingContentLength,
delegate->removedContentLength,
delegate->isSpdyUsed);
delegate->isHttp2Used);
replyDownloadData(delegate->synchronousDownloadData);
httpError(delegate->incomingErrorCode, delegate->incomingErrorDetail);
} else {
@ -980,7 +977,7 @@ void QNetworkReplyHttpImplPrivate::postRequest(const QNetworkRequest &newHttpReq
QSharedPointer<char>(),
delegate->incomingContentLength,
delegate->removedContentLength,
delegate->isSpdyUsed);
delegate->isHttp2Used);
replyDownloadData(delegate->synchronousDownloadData);
}
@ -1254,7 +1251,7 @@ void QNetworkReplyHttpImplPrivate::replyDownloadMetaData(const QList<QPair<QByte
QSharedPointer<char> db,
qint64 contentLength,
qint64 removedContentLength,
bool spdyWasUsed)
bool h2Used)
{
Q_Q(QNetworkReplyHttpImpl);
Q_UNUSED(contentLength);
@ -1280,16 +1277,7 @@ void QNetworkReplyHttpImplPrivate::replyDownloadMetaData(const QList<QPair<QByte
}
q->setAttribute(QNetworkRequest::HttpPipeliningWasUsedAttribute, pu);
const QVariant http2Allowed = request.attribute(QNetworkRequest::HTTP2AllowedAttribute);
const QVariant http2Direct = request.attribute(QNetworkRequest::Http2DirectAttribute);
if ((http2Allowed.isValid() && http2Allowed.toBool())
|| (http2Direct.isValid() && http2Direct.toBool())) {
q->setAttribute(QNetworkRequest::HTTP2WasUsedAttribute, spdyWasUsed);
q->setAttribute(QNetworkRequest::SpdyWasUsedAttribute, false);
} else {
q->setAttribute(QNetworkRequest::SpdyWasUsedAttribute, spdyWasUsed);
q->setAttribute(QNetworkRequest::HTTP2WasUsedAttribute, false);
}
q->setAttribute(QNetworkRequest::Http2WasUsedAttribute, h2Used);
// reconstruct the HTTP header
QList<QPair<QByteArray, QByteArray> > headerMap = hm;

View File

@ -272,18 +272,6 @@ QT_BEGIN_NAMESPACE
The QNetworkSession ConnectInBackground property will be set according to
this attribute.
\value SpdyAllowedAttribute
Requests only, type: QMetaType::Bool (default: false)
Indicates whether the QNetworkAccessManager code is
allowed to use SPDY with this request. This applies only
to SSL requests, and depends on the server supporting SPDY.
Obsolete, use Http2 instead of Spdy.
\value SpdyWasUsedAttribute
Replies only, type: QMetaType::Bool
Indicates whether SPDY was used for receiving
this reply. Obsolete, use Http2 instead of Spdy.
\value Http2AllowedAttribute
Requests only, type: QMetaType::Bool (default: false)
Indicates whether the QNetworkAccessManager code is
@ -295,12 +283,6 @@ QT_BEGIN_NAMESPACE
Indicates whether HTTP/2 was used for receiving this reply.
(This value was introduced in 5.9.)
\value HTTP2AllowedAttribute
Obsolete alias for Http2AllowedAttribute.
\value HTTP2WasUsedAttribute
Obsolete alias for Http2WasUsedAttribute.
\value EmitAllUploadProgressSignalsAttribute
Requests only, type: QMetaType::Bool (default: false)
Indicates whether all upload signals should be emitted.

View File

@ -89,18 +89,10 @@ public:
DownloadBufferAttribute, // internal
SynchronousRequestAttribute, // internal
BackgroundRequestAttribute,
#if QT_DEPRECATED_SINCE(5, 15)
SpdyAllowedAttribute,
SpdyWasUsedAttribute,
#endif // QT_DEPRECATED_SINCE(5, 15)
EmitAllUploadProgressSignalsAttribute = BackgroundRequestAttribute + 3,
FollowRedirectsAttribute,
Http2AllowedAttribute,
Http2WasUsedAttribute,
#if QT_DEPRECATED_SINCE(5, 15)
HTTP2AllowedAttribute Q_DECL_ENUMERATOR_DEPRECATED_X("Use Http2AllowedAttribute") = Http2AllowedAttribute,
HTTP2WasUsedAttribute Q_DECL_ENUMERATOR_DEPRECATED_X("Use Http2WasUsedAttribute"),
#endif // QT_DEPRECATED_SINCE(5, 15)
OriginalContentLengthAttribute,
RedirectPolicyAttribute,
Http2DirectAttribute,

File diff suppressed because it is too large Load Diff

View File

@ -1,232 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2014 BlackBerry Limited. All rights reserved.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtNetwork module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QSPDYPROTOCOLHANDLER_H
#define QSPDYPROTOCOLHANDLER_H
//
// W A R N I N G
// -------------
//
// This file is not part of the Qt API. It exists for the convenience
// of the Network Access API. This header file may change from
// version to version without notice, or even be removed.
//
// We mean it.
//
#include <QtNetwork/private/qtnetworkglobal_p.h>
#include <private/qabstractprotocolhandler_p.h>
#include <QtNetwork/qnetworkreply.h>
#include <private/qbytedata_p.h>
#include <zlib.h>
QT_REQUIRE_CONFIG(http);
#if !defined(QT_NO_SSL)
QT_BEGIN_NAMESPACE
class QHttpNetworkRequest;
#ifndef HttpMessagePair
typedef QPair<QHttpNetworkRequest, QHttpNetworkReply*> HttpMessagePair;
#endif
class QSpdyProtocolHandler : public QObject, public QAbstractProtocolHandler {
Q_OBJECT
public:
QSpdyProtocolHandler(QHttpNetworkConnectionChannel *channel);
~QSpdyProtocolHandler();
enum DataFrameFlag {
DataFrame_FLAG_FIN = 0x01,
DataFrame_FLAG_COMPRESS = 0x02
};
Q_DECLARE_FLAGS(DataFrameFlags, DataFrameFlag)
enum ControlFrameFlag {
ControlFrame_FLAG_FIN = 0x01,
ControlFrame_FLAG_UNIDIRECTIONAL = 0x02
};
Q_DECLARE_FLAGS(ControlFrameFlags, ControlFrameFlag)
enum SETTINGS_Flag {
FLAG_SETTINGS_CLEAR_SETTINGS = 0x01
};
Q_DECLARE_FLAGS(SETTINGS_Flags, SETTINGS_Flag)
enum SETTINGS_ID_Flag {
FLAG_SETTINGS_PERSIST_VALUE = 0x01,
FLAG_SETTINGS_PERSISTED = 0x02
};
Q_DECLARE_FLAGS(SETTINGS_ID_Flags, SETTINGS_ID_Flag)
virtual void _q_receiveReply() override;
virtual void _q_readyRead() override;
virtual bool sendRequest() override;
private slots:
void _q_uploadDataReadyRead();
void _q_replyDestroyed(QObject*);
void _q_uploadDataDestroyed(QObject *);
private:
enum FrameType {
FrameType_SYN_STREAM = 1,
FrameType_SYN_REPLY = 2,
FrameType_RST_STREAM = 3,
FrameType_SETTINGS = 4,
FrameType_PING = 6,
FrameType_GOAWAY = 7,
FrameType_HEADERS = 8,
FrameType_WINDOW_UPDATE = 9,
FrameType_CREDENTIAL // has a special type
};
enum StatusCode {
StatusCode_PROTOCOL_ERROR = 1,
StatusCode_INVALID_STREAM = 2,
StatusCode_REFUSED_STREAM = 3,
StatusCode_UNSUPPORTED_VERSION = 4,
StatusCode_CANCEL = 5,
StatusCode_INTERNAL_ERROR = 6,
StatusCode_FLOW_CONTROL_ERROR = 7,
StatusCode_STREAM_IN_USE = 8,
StatusCode_STREAM_ALREADY_CLOSED = 9,
StatusCode_INVALID_CREDENTIALS = 10,
StatusCode_FRAME_TOO_LARGE = 11
};
enum SETTINGS_ID {
SETTINGS_UPLOAD_BANDWIDTH = 1,
SETTINGS_DOWNLOAD_BANDWIDTH = 2,
SETTINGS_ROUND_TRIP_TIME = 3,
SETTINGS_MAX_CONCURRENT_STREAMS = 4,
SETTINGS_CURRENT_CWND = 5,
SETTINGS_DOWNLOAD_RETRANS_RATE = 6,
SETTINGS_INITIAL_WINDOW_SIZE = 7,
SETTINGS_CLIENT_CERTIFICATE_VECTOR_SIZE = 8
};
enum GOAWAY_STATUS {
GOAWAY_OK = 0,
GOAWAY_PROTOCOL_ERROR = 1,
GOAWAY_INTERNAL_ERROR = 11
};
enum RST_STREAM_STATUS_CODE {
RST_STREAM_PROTOCOL_ERROR = 1,
RST_STREAM_INVALID_STREAM = 2,
RST_STREAM_REFUSED_STREAM = 3,
RST_STREAM_UNSUPPORTED_VERSION = 4,
RST_STREAM_CANCEL = 5,
RST_STREAM_INTERNAL_ERROR = 6,
RST_STREAM_FLOW_CONTROL_ERROR = 7,
RST_STREAM_STREAM_IN_USE = 8,
RST_STREAM_STREAM_ALREADY_CLOSED = 9,
RST_STREAM_INVALID_CREDENTIALS = 10,
RST_STREAM_FRAME_TOO_LARGE = 11
};
quint64 bytesAvailable() const;
bool readNextChunk(qint64 length, char *sink);
void sendControlFrame(FrameType type, ControlFrameFlags flags, const char *data, quint32 length);
void sendSYN_STREAM(const HttpMessagePair &pair, qint32 streamID,
qint32 associatedToStreamID);
void sendRST_STREAM(qint32 streamID, RST_STREAM_STATUS_CODE statusCode);
void sendPING(quint32 pingID);
bool uploadData(qint32 streamID);
Q_INVOKABLE void sendWINDOW_UPDATE(qint32 streamID, quint32 deltaWindowSize);
qint64 sendDataFrame(qint32 streamID, DataFrameFlags flags, quint32 length,
const char *data);
QByteArray composeHeader(const QHttpNetworkRequest &request);
bool uncompressHeader(const QByteArray &input, QByteArray *output);
void handleControlFrame(const QByteArray &frameHeaders);
void handleDataFrame(const QByteArray &frameHeaders);
void handleSYN_STREAM(char, quint32, const QByteArray &frameData);
void handleSYN_REPLY(char flags, quint32, const QByteArray &frameData);
void handleRST_STREAM(char flags, quint32 length, const QByteArray &frameData);
void handleSETTINGS(char flags, quint32 length, const QByteArray &frameData);
void handlePING(char, quint32 length, const QByteArray &frameData);
void handleGOAWAY(char flags, quint32, const QByteArray &frameData);
void handleHEADERS(char flags, quint32, const QByteArray &frameData);
void handleWINDOW_UPDATE(char, quint32, const QByteArray &frameData);
qint32 generateNextStreamID();
void parseHttpHeaders(char flags, const QByteArray &frameData);
void replyFinished(QHttpNetworkReply *httpReply, qint32 streamID);
void replyFinishedWithError(QHttpNetworkReply *httpReply, qint32 streamID,
QNetworkReply::NetworkError errorCode, const char *errorMessage);
qint32 m_nextStreamID;
QHash<quint32, HttpMessagePair> m_inFlightStreams;
qint32 m_maxConcurrentStreams;
quint32 m_initialWindowSize;
QByteDataBuffer m_spdyBuffer;
bool m_waitingForCompleteStream;
z_stream m_deflateStream;
z_stream m_inflateStream;
QHash<QObject *, qint32> m_streamIDs;
};
Q_DECLARE_OPERATORS_FOR_FLAGS(QSpdyProtocolHandler::DataFrameFlags)
Q_DECLARE_OPERATORS_FOR_FLAGS(QSpdyProtocolHandler::ControlFrameFlags)
Q_DECLARE_OPERATORS_FOR_FLAGS(QSpdyProtocolHandler::SETTINGS_Flags)
Q_DECLARE_OPERATORS_FOR_FLAGS(QSpdyProtocolHandler::SETTINGS_ID_Flags)
QT_END_NAMESPACE
#endif // !defined(QT_NO_SSL)
#endif // QSPDYPROTOCOLHANDLER_H

View File

@ -54,7 +54,6 @@ const QSsl::SslOptions QSslConfigurationPrivate::defaultSslOptions = QSsl::SslOp
|QSsl::SslOptionDisableSessionPersistence;
const char QSslConfiguration::ALPNProtocolHTTP2[] = "h2";
const char QSslConfiguration::NextProtocolSpdy3_0[] = "spdy/3";
const char QSslConfiguration::NextProtocolHttp1_1[] = "http/1.1";
/*!
@ -133,12 +132,6 @@ const char QSslConfiguration::NextProtocolHttp1_1[] = "http/1.1";
server could not agree on a common next application protocol.
*/
/*!
\variable QSslConfiguration::NextProtocolSpdy3_0
\brief The value used for negotiating SPDY 3.0 during the Next
Protocol Negotiation.
*/
/*!
\variable QSslConfiguration::NextProtocolHttp1_1
\brief The value used for negotiating HTTP 1.1 during the Next
@ -967,7 +960,7 @@ QByteArray QSslConfiguration::nextNegotiatedProtocol() const
Whether or not the negotiation succeeded can be queried through
nextProtocolNegotiationStatus().
\sa nextNegotiatedProtocol(), nextProtocolNegotiationStatus(), allowedNextProtocols(), QSslConfiguration::NextProtocolSpdy3_0, QSslConfiguration::NextProtocolHttp1_1
\sa nextNegotiatedProtocol(), nextProtocolNegotiationStatus(), allowedNextProtocols(), QSslConfiguration::NextProtocolHttp1_1
*/
#if QT_VERSION >= QT_VERSION_CHECK(6,0,0)
void QSslConfiguration::setAllowedNextProtocols(const QList<QByteArray> &protocols)
@ -985,7 +978,7 @@ void QSslConfiguration::setAllowedNextProtocols(QList<QByteArray> protocols)
server through the Next Protocol Negotiation (NPN) or Application-Layer
Protocol Negotiation (ALPN) TLS extension, as set by setAllowedNextProtocols().
\sa nextNegotiatedProtocol(), nextProtocolNegotiationStatus(), setAllowedNextProtocols(), QSslConfiguration::NextProtocolSpdy3_0, QSslConfiguration::NextProtocolHttp1_1
\sa nextNegotiatedProtocol(), nextProtocolNegotiationStatus(), setAllowedNextProtocols(), QSslConfiguration::NextProtocolHttp1_1
*/
QList<QByteArray> QSslConfiguration::allowedNextProtocols() const
{

View File

@ -188,7 +188,6 @@ public:
NextProtocolNegotiationStatus nextProtocolNegotiationStatus() const;
static const char ALPNProtocolHTTP2[];
static const char NextProtocolSpdy3_0[];
static const char NextProtocolHttp1_1[];
private:

View File

@ -7,7 +7,6 @@ SUBDIRS=\
qnetworkrequest \
qhttpnetworkconnection \
qnetworkreply \
spdy \
qnetworkcachemetadata \
qftp \
qhttpnetworkreply \

View File

@ -219,12 +219,12 @@ void tst_Http2::singleRequest_data()
// 'Clear text' that should always work, either via the protocol upgrade
// or as direct.
QTest::addRow("h2c-upgrade") << QNetworkRequest::HTTP2AllowedAttribute << H2Type::h2c;
QTest::addRow("h2c-upgrade") << QNetworkRequest::Http2AllowedAttribute << H2Type::h2c;
QTest::addRow("h2c-direct") << QNetworkRequest::Http2DirectAttribute << H2Type::h2cDirect;
if (!clearTextHTTP2) {
// Qt with TLS where TLS-backend supports ALPN.
QTest::addRow("h2-ALPN") << QNetworkRequest::HTTP2AllowedAttribute << H2Type::h2Alpn;
QTest::addRow("h2-ALPN") << QNetworkRequest::Http2AllowedAttribute << H2Type::h2Alpn;
}
#if QT_CONFIG(ssl)
@ -429,7 +429,7 @@ void tst_Http2::pushPromise()
url.setPath("/index.html");
QNetworkRequest request(url);
request.setAttribute(QNetworkRequest::HTTP2AllowedAttribute, QVariant(true));
request.setAttribute(QNetworkRequest::Http2AllowedAttribute, QVariant(true));
request.setHttp2Configuration(params);
auto reply = manager->get(request);
@ -455,7 +455,7 @@ void tst_Http2::pushPromise()
url.setPath("/script.js");
QNetworkRequest promisedRequest(url);
promisedRequest.setAttribute(QNetworkRequest::HTTP2AllowedAttribute, QVariant(true));
promisedRequest.setAttribute(QNetworkRequest::Http2AllowedAttribute, QVariant(true));
reply = manager->get(promisedRequest);
connect(reply, &QNetworkReply::finished, this, &tst_Http2::replyFinished);
reply->ignoreSslErrors();
@ -509,7 +509,7 @@ void tst_Http2::goaway()
for (int i = 0; i < nRequests; ++i) {
url.setPath(QString("/%1").arg(i));
QNetworkRequest request(url);
request.setAttribute(QNetworkRequest::HTTP2AllowedAttribute, QVariant(true));
request.setAttribute(QNetworkRequest::Http2AllowedAttribute, QVariant(true));
replies[i] = manager->get(request);
QCOMPARE(replies[i]->error(), QNetworkReply::NoError);
void (QNetworkReply::*errorSignal)(QNetworkReply::NetworkError) =
@ -582,7 +582,7 @@ void tst_Http2::connectToHost_data()
#if QT_CONFIG(ssl)
QTest::addRow("encrypted-h2-direct") << QNetworkRequest::Http2DirectAttribute << H2Type::h2Direct;
if (!clearTextHTTP2)
QTest::addRow("encrypted-h2-ALPN") << QNetworkRequest::HTTP2AllowedAttribute << H2Type::h2Alpn;
QTest::addRow("encrypted-h2-ALPN") << QNetworkRequest::Http2AllowedAttribute << H2Type::h2Alpn;
#endif // QT_CONFIG(ssl)
// This works for all configurations, tests 'preconnect-http' scheme:
// h2 with protocol upgrade is not working for now (the logic is a bit
@ -725,7 +725,7 @@ void tst_Http2::maxFrameSize()
#endif // QT_CONFIG(securetransport)
auto connectionType = H2Type::h2Alpn;
auto attribute = QNetworkRequest::HTTP2AllowedAttribute;
auto attribute = QNetworkRequest::Http2AllowedAttribute;
if (clearTextHTTP2) {
connectionType = H2Type::h2Direct;
attribute = QNetworkRequest::Http2DirectAttribute;
@ -825,7 +825,7 @@ void tst_Http2::sendRequest(int streamNumber,
url.setPath(QString("/stream%1.html").arg(streamNumber));
QNetworkRequest request(url);
request.setAttribute(QNetworkRequest::HTTP2AllowedAttribute, QVariant(true));
request.setAttribute(QNetworkRequest::Http2AllowedAttribute, QVariant(true));
request.setAttribute(QNetworkRequest::FollowRedirectsAttribute, QVariant(true));
request.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("text/plain"));
request.setPriority(priority);
@ -932,20 +932,13 @@ void tst_Http2::replyFinished()
QCOMPARE(reply->error(), QNetworkReply::NoError);
const QVariant http2Used(reply->attribute(QNetworkRequest::HTTP2WasUsedAttribute));
const QVariant http2Used(reply->attribute(QNetworkRequest::Http2WasUsedAttribute));
if (!http2Used.isValid() || !http2Used.toBool())
stopEventLoop();
QVERIFY(http2Used.isValid());
QVERIFY(http2Used.toBool());
const QVariant spdyUsed(reply->attribute(QNetworkRequest::SpdyWasUsedAttribute));
if (!spdyUsed.isValid() || spdyUsed.toBool())
stopEventLoop();
QVERIFY(spdyUsed.isValid());
QVERIFY(!spdyUsed.toBool());
const QVariant code(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute));
if (!code.isValid() || !code.canConvert<int>() || code.value<int>() != 200)
stopEventLoop();

View File

@ -1,7 +0,0 @@
[download]
opensuse-leap
[upload]
opensuse-leap
ubuntu-18.04
b2qt

View File

@ -1,7 +0,0 @@
CONFIG += testcase
TARGET = tst_spdy
SOURCES += tst_spdy.cpp
QT = core core-private network network-private testlib
win32:CONFIG += insignificant_test # QTBUG-47128

View File

@ -1,693 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2014 BlackBerry Limited. All rights reserved.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the test suite of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:GPL-EXCEPT$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include <QtTest/QtTest>
#include <QtNetwork/QNetworkAccessManager>
#include <QtNetwork/QNetworkReply>
#include <QtNetwork/QHttpPart>
#include <QtNetwork/QHttpMultiPart>
#include <QtNetwork/QNetworkProxy>
#include <QtNetwork/QAuthenticator>
#if defined(QT_BUILD_INTERNAL) && !defined(QT_NO_OPENSSL)
#include <QtNetwork/private/qsslsocket_openssl_p.h>
#endif // QT_BUILD_INTERNAL && !QT_NO_OPENSSL
#include "../../../network-settings.h"
Q_DECLARE_METATYPE(QAuthenticator*)
class tst_Spdy: public QObject
{
Q_OBJECT
public:
tst_Spdy();
~tst_Spdy();
private Q_SLOTS:
void initTestCase();
void settingsAndNegotiation_data();
void settingsAndNegotiation();
#ifndef QT_NO_NETWORKPROXY
void download_data();
void download();
#endif // !QT_NO_NETWORKPROXY
void headerFields();
#ifndef QT_NO_NETWORKPROXY
void upload_data();
void upload();
void errors_data();
void errors();
#endif // !QT_NO_NETWORKPROXY
void multipleRequests_data();
void multipleRequests();
private:
QNetworkAccessManager m_manager;
int m_multipleRequestsCount;
int m_multipleRepliesFinishedCount;
const QString m_rfc3252FilePath;
protected Q_SLOTS:
void proxyAuthenticationRequired(const QNetworkProxy &, QAuthenticator *authenticator);
void multipleRequestsFinishedSlot();
};
tst_Spdy::tst_Spdy()
: m_rfc3252FilePath(QFINDTESTDATA("../qnetworkreply/rfc3252.txt"))
{
#if defined(QT_BUILD_INTERNAL) && !defined(QT_NO_SSL) && OPENSSL_VERSION_NUMBER >= 0x1000100fL && !defined(OPENSSL_NO_TLSEXT) && !defined(OPENSSL_NO_NEXTPROTONEG)
qRegisterMetaType<QNetworkReply *>(); // for QSignalSpy
qRegisterMetaType<QAuthenticator *>();
connect(&m_manager, SIGNAL(proxyAuthenticationRequired(const QNetworkProxy &, QAuthenticator *)),
this, SLOT(proxyAuthenticationRequired(const QNetworkProxy &, QAuthenticator *)));
#else
QSKIP("Qt built withouth OpenSSL, or the OpenSSL version is too old");
#endif // defined(QT_BUILD_INTERNAL) && !defined(QT_NO_SSL) ...
}
tst_Spdy::~tst_Spdy()
{
}
void tst_Spdy::initTestCase()
{
QVERIFY(!m_rfc3252FilePath.isEmpty());
QVERIFY(QtNetworkSettings::verifyTestNetworkSettings());
}
void tst_Spdy::settingsAndNegotiation_data()
{
QTest::addColumn<QUrl>("url");
QTest::addColumn<bool>("setAttribute");
QTest::addColumn<bool>("enabled");
QTest::addColumn<QByteArray>("expectedProtocol");
QTest::addColumn<QByteArray>("expectedContent");
QTest::newRow("default-settings") << QUrl("https://" + QtNetworkSettings::serverName()
+ "/qtest/cgi-bin/echo.cgi?1")
<< false << false << QByteArray()
<< QByteArray("1");
QTest::newRow("http-url") << QUrl("http://" + QtNetworkSettings::serverName()
+ "/qtest/cgi-bin/echo.cgi?1")
<< true << true << QByteArray()
<< QByteArray("1");
QTest::newRow("spdy-disabled") << QUrl("https://" + QtNetworkSettings::serverName()
+ "/qtest/cgi-bin/echo.cgi?1")
<< true << false << QByteArray()
<< QByteArray("1");
#ifndef QT_NO_OPENSSL
QTest::newRow("spdy-enabled") << QUrl("https://" + QtNetworkSettings::serverName()
+ "/qtest/cgi-bin/echo.cgi?1")
<< true << true << QByteArray(QSslConfiguration::NextProtocolSpdy3_0)
<< QByteArray("1");
#endif // QT_NO_OPENSSL
}
void tst_Spdy::settingsAndNegotiation()
{
QFETCH(QUrl, url);
QFETCH(bool, setAttribute);
QFETCH(bool, enabled);
QNetworkRequest request(url);
if (setAttribute) {
request.setAttribute(QNetworkRequest::SpdyAllowedAttribute, QVariant(enabled));
}
QNetworkReply *reply = m_manager.get(request);
reply->ignoreSslErrors();
QSignalSpy metaDataChangedSpy(reply, SIGNAL(metaDataChanged()));
QSignalSpy readyReadSpy(reply, SIGNAL(readyRead()));
QSignalSpy finishedSpy(reply, SIGNAL(finished()));
QObject::connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
QSignalSpy finishedManagerSpy(&m_manager, SIGNAL(finished(QNetworkReply*)));
QTestEventLoop::instance().enterLoop(15);
QVERIFY(!QTestEventLoop::instance().timeout());
QFETCH(QByteArray, expectedProtocol);
#ifndef QT_NO_OPENSSL
bool expectedSpdyUsed = (expectedProtocol == QSslConfiguration::NextProtocolSpdy3_0);
QCOMPARE(reply->attribute(QNetworkRequest::SpdyWasUsedAttribute).toBool(), expectedSpdyUsed);
#endif // QT_NO_OPENSSL
QCOMPARE(metaDataChangedSpy.count(), 1);
QCOMPARE(finishedSpy.count(), 1);
int statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
QCOMPARE(statusCode, 200);
QByteArray content = reply->readAll();
QFETCH(QByteArray, expectedContent);
QCOMPARE(expectedContent, content);
#ifndef QT_NO_OPENSSL
QSslConfiguration::NextProtocolNegotiationStatus expectedStatus =
(expectedProtocol.isEmpty())
? QSslConfiguration::NextProtocolNegotiationNone
: QSslConfiguration::NextProtocolNegotiationNegotiated;
QCOMPARE(reply->sslConfiguration().nextProtocolNegotiationStatus(),
expectedStatus);
QCOMPARE(reply->sslConfiguration().nextNegotiatedProtocol(), expectedProtocol);
#endif // QT_NO_OPENSSL
}
void tst_Spdy::proxyAuthenticationRequired(const QNetworkProxy &/*proxy*/,
QAuthenticator *authenticator)
{
authenticator->setUser("qsockstest");
authenticator->setPassword("password");
}
#ifndef QT_NO_NETWORKPROXY
void tst_Spdy::download_data()
{
QTest::addColumn<QUrl>("url");
QTest::addColumn<QString>("fileName");
QTest::addColumn<QNetworkProxy>("proxy");
QTest::newRow("mediumfile") << QUrl("https://" + QtNetworkSettings::serverName()
+ "/qtest/rfc3252.txt")
<< m_rfc3252FilePath
<< QNetworkProxy();
QHostInfo hostInfo = QHostInfo::fromName(QtNetworkSettings::serverName());
QString proxyserver = hostInfo.addresses().first().toString();
QTest::newRow("mediumfile-http-proxy") << QUrl("https://" + QtNetworkSettings::serverName()
+ "/qtest/rfc3252.txt")
<< m_rfc3252FilePath
<< QNetworkProxy(QNetworkProxy::HttpProxy, proxyserver, 3128);
QTest::newRow("mediumfile-http-proxy-auth") << QUrl("https://" + QtNetworkSettings::serverName()
+ "/qtest/rfc3252.txt")
<< m_rfc3252FilePath
<< QNetworkProxy(QNetworkProxy::HttpProxy,
proxyserver, 3129);
QTest::newRow("mediumfile-socks-proxy") << QUrl("https://" + QtNetworkSettings::serverName()
+ "/qtest/rfc3252.txt")
<< m_rfc3252FilePath
<< QNetworkProxy(QNetworkProxy::Socks5Proxy, proxyserver, 1080);
QTest::newRow("mediumfile-socks-proxy-auth") << QUrl("https://" + QtNetworkSettings::serverName()
+ "/qtest/rfc3252.txt")
<< m_rfc3252FilePath
<< QNetworkProxy(QNetworkProxy::Socks5Proxy,
proxyserver, 1081);
QTest::newRow("bigfile") << QUrl("https://" + QtNetworkSettings::serverName()
+ "/qtest/bigfile")
<< QFINDTESTDATA("../qnetworkreply/bigfile")
<< QNetworkProxy();
}
void tst_Spdy::download()
{
QFETCH(QUrl, url);
QFETCH(QString, fileName);
QFETCH(QNetworkProxy, proxy);
QNetworkRequest request(url);
request.setAttribute(QNetworkRequest::SpdyAllowedAttribute, true);
if (proxy.type() != QNetworkProxy::DefaultProxy) {
m_manager.setProxy(proxy);
}
QNetworkReply *reply = m_manager.get(request);
reply->ignoreSslErrors();
QSignalSpy metaDataChangedSpy(reply, SIGNAL(metaDataChanged()));
QSignalSpy downloadProgressSpy(reply, SIGNAL(downloadProgress(qint64, qint64)));
QSignalSpy readyReadSpy(reply, SIGNAL(readyRead()));
QSignalSpy finishedSpy(reply, SIGNAL(finished()));
QObject::connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
QSignalSpy finishedManagerSpy(&m_manager, SIGNAL(finished(QNetworkReply*)));
QSignalSpy proxyAuthRequiredSpy(&m_manager, SIGNAL(
proxyAuthenticationRequired(const QNetworkProxy &,
QAuthenticator *)));
QTestEventLoop::instance().enterLoop(15);
QVERIFY(!QTestEventLoop::instance().timeout());
QCOMPARE(finishedManagerSpy.count(), 1);
QCOMPARE(metaDataChangedSpy.count(), 1);
QCOMPARE(finishedSpy.count(), 1);
QVERIFY(downloadProgressSpy.count() > 0);
QVERIFY(readyReadSpy.count() > 0);
QVERIFY(proxyAuthRequiredSpy.count() <= 1);
QCOMPARE(reply->error(), QNetworkReply::NoError);
QCOMPARE(reply->attribute(QNetworkRequest::SpdyWasUsedAttribute).toBool(), true);
QCOMPARE(reply->attribute(QNetworkRequest::ConnectionEncryptedAttribute).toBool(), true);
QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
QFile file(fileName);
QVERIFY(file.open(QIODevice::ReadOnly));
qint64 contentLength = reply->header(QNetworkRequest::ContentLengthHeader).toLongLong();
qint64 expectedContentLength = file.bytesAvailable();
QCOMPARE(contentLength, expectedContentLength);
QByteArray expectedContent = file.readAll();
QByteArray content = reply->readAll();
QCOMPARE(content, expectedContent);
reply->deleteLater();
m_manager.setProxy(QNetworkProxy()); // reset
}
#endif // !QT_NO_NETWORKPROXY
void tst_Spdy::headerFields()
{
QUrl url(QUrl("https://" + QtNetworkSettings::serverName()));
QNetworkRequest request(url);
request.setAttribute(QNetworkRequest::SpdyAllowedAttribute, true);
QNetworkReply *reply = m_manager.get(request);
reply->ignoreSslErrors();
QObject::connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
QTestEventLoop::instance().enterLoop(15);
QVERIFY(!QTestEventLoop::instance().timeout());
QCOMPARE(reply->rawHeader("Content-Type"), QByteArray("text/html"));
QVERIFY(reply->rawHeader("Content-Length").toInt() > 0);
QVERIFY(reply->rawHeader("server").contains("Apache"));
QCOMPARE(reply->header(QNetworkRequest::ContentTypeHeader).toByteArray(), QByteArray("text/html"));
QVERIFY(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong() > 0);
QVERIFY(reply->header(QNetworkRequest::LastModifiedHeader).toDateTime().isValid());
QVERIFY(reply->header(QNetworkRequest::ServerHeader).toByteArray().contains("Apache"));
}
static inline QByteArray md5sum(const QByteArray &data)
{
return QCryptographicHash::hash(data, QCryptographicHash::Md5).toHex().append('\n');
}
#ifndef QT_NO_NETWORKPROXY
void tst_Spdy::upload_data()
{
QTest::addColumn<QUrl>("url");
QTest::addColumn<QByteArray>("data");
QTest::addColumn<QByteArray>("uploadMethod");
QTest::addColumn<QObject *>("uploadObject");
QTest::addColumn<QByteArray>("md5sum");
QTest::addColumn<QNetworkProxy>("proxy");
// 1. test uploading of byte arrays
QUrl md5Url("https://" + QtNetworkSettings::serverName() + "/qtest/cgi-bin/md5sum.cgi");
QByteArray data;
data = "";
QObject *dummyObject = 0;
QTest::newRow("empty") << md5Url << data << QByteArray("POST") << dummyObject
<< md5sum(data) << QNetworkProxy();
data = "This is a normal message.";
QTest::newRow("generic") << md5Url << data << QByteArray("POST") << dummyObject
<< md5sum(data) << QNetworkProxy();
data = "This is a message to show that Qt rocks!\r\n\n";
QTest::newRow("small") << md5Url << data << QByteArray("POST") << dummyObject
<< md5sum(data) << QNetworkProxy();
data = QByteArray("abcd\0\1\2\abcd",12);
QTest::newRow("with-nul") << md5Url << data << QByteArray("POST") << dummyObject
<< md5sum(data) << QNetworkProxy();
data = QByteArray(4097, '\4');
QTest::newRow("4k+1") << md5Url << data << QByteArray("POST") << dummyObject
<< md5sum(data)<< QNetworkProxy();
QHostInfo hostInfo = QHostInfo::fromName(QtNetworkSettings::serverName());
QString proxyserver = hostInfo.addresses().first().toString();
QTest::newRow("4k+1-with-http-proxy") << md5Url << data << QByteArray("POST") << dummyObject
<< md5sum(data)
<< QNetworkProxy(QNetworkProxy::HttpProxy, proxyserver, 3128);
QTest::newRow("4k+1-with-http-proxy-auth") << md5Url << data << QByteArray("POST") << dummyObject
<< md5sum(data)
<< QNetworkProxy(QNetworkProxy::HttpProxy,
proxyserver, 3129);
QTest::newRow("4k+1-with-socks-proxy") << md5Url << data << QByteArray("POST") << dummyObject
<< md5sum(data)
<< QNetworkProxy(QNetworkProxy::Socks5Proxy, proxyserver, 1080);
QTest::newRow("4k+1-with-socks-proxy-auth") << md5Url << data << QByteArray("POST") << dummyObject
<< md5sum(data)
<< QNetworkProxy(QNetworkProxy::Socks5Proxy,
proxyserver, 1081);
data = QByteArray(128*1024+1, '\177');
QTest::newRow("128k+1") << md5Url << data << QByteArray("POST") << dummyObject
<< md5sum(data) << QNetworkProxy();
data = QByteArray(128*1024+1, '\177');
QTest::newRow("128k+1-put") << md5Url << data << QByteArray("PUT") << dummyObject
<< md5sum(data) << QNetworkProxy();
data = QByteArray(2*1024*1024+1, '\177');
QTest::newRow("2MB+1") << md5Url << data << QByteArray("POST") << dummyObject
<< md5sum(data) << QNetworkProxy();
// 2. test uploading of files
QFile *file = new QFile(m_rfc3252FilePath);
file->open(QIODevice::ReadOnly);
QTest::newRow("file-26K") << md5Url << QByteArray() << QByteArray("POST")
<< static_cast<QObject *>(file)
<< QByteArray("b3e32ac459b99d3f59318f3ac31e4bee\n") << QNetworkProxy();
QFile *file2 = new QFile(QFINDTESTDATA("../qnetworkreply/image1.jpg"));
file2->open(QIODevice::ReadOnly);
QTest::newRow("file-1MB") << md5Url << QByteArray() << QByteArray("POST")
<< static_cast<QObject *>(file2)
<< QByteArray("87ef3bb319b004ba9e5e9c9fa713776e\n") << QNetworkProxy();
// 3. test uploading of multipart
QUrl multiPartUrl("https://" + QtNetworkSettings::serverName() + "/qtest/cgi-bin/multipart.cgi");
QHttpPart imagePart31;
imagePart31.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("image/jpeg"));
imagePart31.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"testImage1\""));
imagePart31.setRawHeader("Content-Location", "http://my.test.location.tld");
imagePart31.setRawHeader("Content-ID", "my@id.tld");
QFile *file31 = new QFile(QFINDTESTDATA("../qnetworkreply/image1.jpg"));
file31->open(QIODevice::ReadOnly);
imagePart31.setBodyDevice(file31);
QHttpMultiPart *imageMultiPart3 = new QHttpMultiPart(QHttpMultiPart::FormDataType);
imageMultiPart3->append(imagePart31);
file31->setParent(imageMultiPart3);
QHttpPart imagePart32;
imagePart32.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("image/jpeg"));
imagePart32.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"testImage2\""));
QFile *file32 = new QFile(QFINDTESTDATA("../qnetworkreply/image2.jpg"));
file32->open(QIODevice::ReadOnly);
imagePart32.setBodyDevice(file31); // check that resetting works
imagePart32.setBodyDevice(file32);
imageMultiPart3->append(imagePart32);
file32->setParent(imageMultiPart3);
QHttpPart imagePart33;
imagePart33.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("image/jpeg"));
imagePart33.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"testImage3\""));
QFile *file33 = new QFile(QFINDTESTDATA("../qnetworkreply/image3.jpg"));
file33->open(QIODevice::ReadOnly);
imagePart33.setBodyDevice(file33);
imageMultiPart3->append(imagePart33);
file33->setParent(imageMultiPart3);
QByteArray expectedData = "content type: multipart/form-data; boundary=\""
+ imageMultiPart3->boundary();
expectedData.append("\"\nkey: testImage1, value: 87ef3bb319b004ba9e5e9c9fa713776e\n"
"key: testImage2, value: 483761b893f7fb1bd2414344cd1f3dfb\n"
"key: testImage3, value: ab0eb6fd4fcf8b4436254870b4513033\n");
QTest::newRow("multipart-3images") << multiPartUrl << QByteArray() << QByteArray("POST")
<< static_cast<QObject *>(imageMultiPart3) << expectedData
<< QNetworkProxy();
}
void tst_Spdy::upload()
{
QFETCH(QUrl, url);
QNetworkRequest request(url);
request.setAttribute(QNetworkRequest::SpdyAllowedAttribute, true);
QFETCH(QByteArray, data);
QFETCH(QByteArray, uploadMethod);
QFETCH(QObject *, uploadObject);
QFETCH(QNetworkProxy, proxy);
if (proxy.type() != QNetworkProxy::DefaultProxy) {
m_manager.setProxy(proxy);
}
QNetworkReply *reply;
QHttpMultiPart *multiPart = 0;
if (uploadObject) {
// upload via device
if (QIODevice *device = qobject_cast<QIODevice *>(uploadObject)) {
reply = m_manager.post(request, device);
} else if ((multiPart = qobject_cast<QHttpMultiPart *>(uploadObject))) {
reply = m_manager.post(request, multiPart);
} else {
QFAIL("got unknown upload device");
}
} else {
// upload via byte array
if (uploadMethod == "PUT") {
reply = m_manager.put(request, data);
} else {
reply = m_manager.post(request, data);
}
}
reply->ignoreSslErrors();
QSignalSpy metaDataChangedSpy(reply, SIGNAL(metaDataChanged()));
QSignalSpy uploadProgressSpy(reply, SIGNAL(uploadProgress(qint64, qint64)));
QSignalSpy readyReadSpy(reply, SIGNAL(readyRead()));
QSignalSpy finishedSpy(reply, SIGNAL(finished()));
QObject::connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
QSignalSpy finishedManagerSpy(&m_manager, SIGNAL(finished(QNetworkReply*)));
QTestEventLoop::instance().enterLoop(20);
QVERIFY(!QTestEventLoop::instance().timeout());
QCOMPARE(finishedManagerSpy.count(), 1);
QCOMPARE(metaDataChangedSpy.count(), 1);
QCOMPARE(finishedSpy.count(), 1);
QVERIFY(uploadProgressSpy.count() > 0);
QVERIFY(readyReadSpy.count() > 0);
QCOMPARE(reply->error(), QNetworkReply::NoError);
QCOMPARE(reply->attribute(QNetworkRequest::SpdyWasUsedAttribute).toBool(), true);
QCOMPARE(reply->attribute(QNetworkRequest::ConnectionEncryptedAttribute).toBool(), true);
QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
qint64 contentLength = reply->header(QNetworkRequest::ContentLengthHeader).toLongLong();
if (!multiPart) // script to test multiparts does not return a content length
QCOMPARE(contentLength, 33); // 33 bytes for md5 sums (including new line)
QFETCH(QByteArray, md5sum);
QByteArray content = reply->readAll();
QCOMPARE(content, md5sum);
reply->deleteLater();
if (uploadObject)
uploadObject->deleteLater();
m_manager.setProxy(QNetworkProxy()); // reset
}
void tst_Spdy::errors_data()
{
QTest::addColumn<QUrl>("url");
QTest::addColumn<QNetworkProxy>("proxy");
QTest::addColumn<bool>("ignoreSslErrors");
QTest::addColumn<int>("expectedReplyError");
QTest::newRow("http-404") << QUrl("https://" + QtNetworkSettings::serverName() + "/non-existent-url")
<< QNetworkProxy() << true << int(QNetworkReply::ContentNotFoundError);
QTest::newRow("ssl-errors") << QUrl("https://" + QtNetworkSettings::serverName())
<< QNetworkProxy() << false << int(QNetworkReply::SslHandshakeFailedError);
QTest::newRow("host-not-found") << QUrl("https://this-host-does-not.exist")
<< QNetworkProxy()
<< true << int(QNetworkReply::HostNotFoundError);
QTest::newRow("proxy-not-found") << QUrl("https://" + QtNetworkSettings::serverName())
<< QNetworkProxy(QNetworkProxy::HttpProxy,
"https://this-host-does-not.exist", 3128)
<< true << int(QNetworkReply::HostNotFoundError);
QHostInfo hostInfo = QHostInfo::fromName(QtNetworkSettings::serverName());
QString proxyserver = hostInfo.addresses().first().toString();
QTest::newRow("proxy-unavailable") << QUrl("https://" + QtNetworkSettings::serverName())
<< QNetworkProxy(QNetworkProxy::HttpProxy, proxyserver, 10)
<< true << int(QNetworkReply::UnknownNetworkError);
QTest::newRow("no-proxy-credentials") << QUrl("https://" + QtNetworkSettings::serverName())
<< QNetworkProxy(QNetworkProxy::HttpProxy, proxyserver, 3129)
<< true << int(QNetworkReply::ProxyAuthenticationRequiredError);
}
void tst_Spdy::errors()
{
QFETCH(QUrl, url);
QFETCH(QNetworkProxy, proxy);
QFETCH(bool, ignoreSslErrors);
QFETCH(int, expectedReplyError);
QNetworkRequest request(url);
request.setAttribute(QNetworkRequest::SpdyAllowedAttribute, true);
disconnect(&m_manager, SIGNAL(proxyAuthenticationRequired(const QNetworkProxy &, QAuthenticator *)),
0, 0);
if (proxy.type() != QNetworkProxy::DefaultProxy) {
m_manager.setProxy(proxy);
}
QNetworkReply *reply = m_manager.get(request);
if (ignoreSslErrors)
reply->ignoreSslErrors();
QSignalSpy finishedSpy(reply, SIGNAL(finished()));
QSignalSpy errorSpy(reply, SIGNAL(error(QNetworkReply::NetworkError)));
QObject::connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
QTestEventLoop::instance().enterLoop(15);
QVERIFY(!QTestEventLoop::instance().timeout());
QCOMPARE(finishedSpy.count(), 1);
QCOMPARE(errorSpy.count(), 1);
QCOMPARE(reply->error(), static_cast<QNetworkReply::NetworkError>(expectedReplyError));
m_manager.setProxy(QNetworkProxy()); // reset
m_manager.clearAccessCache(); // e.g. to get an SSL error we need a new connection
connect(&m_manager, SIGNAL(proxyAuthenticationRequired(const QNetworkProxy &, QAuthenticator *)),
this, SLOT(proxyAuthenticationRequired(const QNetworkProxy &, QAuthenticator *)),
Qt::UniqueConnection); // reset
}
#endif // !QT_NO_NETWORKPROXY
void tst_Spdy::multipleRequests_data()
{
QTest::addColumn<QList<QUrl> >("urls");
QString baseUrl = "https://" + QtNetworkSettings::serverName() + "/qtest/cgi-bin/echo.cgi?";
QList<QUrl> urls;
for (int a = 1; a <= 50; ++a)
urls.append(QUrl(baseUrl + QLatin1String(QByteArray::number(a))));
QTest::newRow("one-request") << urls.mid(0, 1);
QTest::newRow("two-requests") << urls.mid(0, 2);
QTest::newRow("ten-requests") << urls.mid(0, 10);
QTest::newRow("twenty-requests") << urls.mid(0, 20);
QTest::newRow("fifty-requests") << urls;
}
void tst_Spdy::multipleRequestsFinishedSlot()
{
m_multipleRepliesFinishedCount++;
if (m_multipleRepliesFinishedCount == m_multipleRequestsCount)
QTestEventLoop::instance().exitLoop();
}
void tst_Spdy::multipleRequests()
{
QFETCH(QList<QUrl>, urls);
m_multipleRequestsCount = urls.count();
m_multipleRepliesFinishedCount = 0;
QList<QNetworkReply *> replies;
QList<QSignalSpy *> metaDataChangedSpies;
QList<QSignalSpy *> readyReadSpies;
QList<QSignalSpy *> finishedSpies;
foreach (const QUrl &url, urls) {
QNetworkRequest request(url);
request.setAttribute(QNetworkRequest::SpdyAllowedAttribute, true);
QNetworkReply *reply = m_manager.get(request);
replies.append(reply);
reply->ignoreSslErrors();
QObject::connect(reply, SIGNAL(finished()), this, SLOT(multipleRequestsFinishedSlot()));
QSignalSpy *metaDataChangedSpy = new QSignalSpy(reply, SIGNAL(metaDataChanged()));
metaDataChangedSpies << metaDataChangedSpy;
QSignalSpy *readyReadSpy = new QSignalSpy(reply, SIGNAL(readyRead()));
readyReadSpies << readyReadSpy;
QSignalSpy *finishedSpy = new QSignalSpy(reply, SIGNAL(finished()));
finishedSpies << finishedSpy;
}
QSignalSpy finishedManagerSpy(&m_manager, SIGNAL(finished(QNetworkReply*)));
QTestEventLoop::instance().enterLoop(15);
QVERIFY(!QTestEventLoop::instance().timeout());
QCOMPARE(finishedManagerSpy.count(), m_multipleRequestsCount);
for (int a = 0; a < replies.count(); ++a) {
#ifndef QT_NO_OPENSSL
QCOMPARE(replies.at(a)->sslConfiguration().nextProtocolNegotiationStatus(),
QSslConfiguration::NextProtocolNegotiationNegotiated);
QCOMPARE(replies.at(a)->sslConfiguration().nextNegotiatedProtocol(),
QByteArray(QSslConfiguration::NextProtocolSpdy3_0));
#endif // QT_NO_OPENSSL
QCOMPARE(replies.at(a)->error(), QNetworkReply::NoError);
QCOMPARE(replies.at(a)->attribute(QNetworkRequest::SpdyWasUsedAttribute).toBool(), true);
QCOMPARE(replies.at(a)->attribute(QNetworkRequest::ConnectionEncryptedAttribute).toBool(), true);
QCOMPARE(replies.at(a)->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
// using the echo script, a request to "echo.cgi?1" will return a body of "1"
QByteArray expectedContent = replies.at(a)->url().query().toUtf8();
QByteArray content = replies.at(a)->readAll();
QCOMPARE(expectedContent, content);
QCOMPARE(metaDataChangedSpies.at(a)->count(), 1);
metaDataChangedSpies.at(a)->deleteLater();
QCOMPARE(finishedSpies.at(a)->count(), 1);
finishedSpies.at(a)->deleteLater();
QVERIFY(readyReadSpies.at(a)->count() > 0);
readyReadSpies.at(a)->deleteLater();
replies.at(a)->deleteLater();
}
}
QTEST_MAIN(tst_Spdy)
#include "tst_spdy.moc"

View File

@ -544,15 +544,10 @@ void tst_qnetworkreply::echoPerformance()
void tst_qnetworkreply::preConnectEncrypted()
{
QFETCH(int, sleepTime);
QFETCH(QSslConfiguration, sslConfiguration);
bool spdyEnabled = !sslConfiguration.isNull();
QString hostName = QLatin1String("www.google.com");
QNetworkAccessManager manager;
QNetworkRequest request(QUrl("https://" + hostName));
if (spdyEnabled)
request.setAttribute(QNetworkRequest::SpdyAllowedAttribute, true);
// make sure we have a full request including
// DNS lookup, TCP and SSL handshakes
@ -578,12 +573,7 @@ void tst_qnetworkreply::preConnectEncrypted()
manager.clearAccessCache();
// now try to make the connection beforehand
if (spdyEnabled) {
request.setAttribute(QNetworkRequest::SpdyAllowedAttribute, true);
manager.connectToHostEncrypted(hostName, 443, sslConfiguration);
} else {
manager.connectToHostEncrypted(hostName);
}
manager.connectToHostEncrypted(hostName);
QTestEventLoop::instance().enterLoopMSecs(sleepTime);
// now make another request and hopefully use the existing connection
@ -591,8 +581,6 @@ void tst_qnetworkreply::preConnectEncrypted()
QNetworkReply *preConnectReply = normalResult.first;
QVERIFY(!QTestEventLoop::instance().timeout());
QVERIFY(preConnectReply->error() == QNetworkReply::NoError);
bool spdyWasUsed = preConnectReply->attribute(QNetworkRequest::SpdyWasUsedAttribute).toBool();
QCOMPARE(spdyEnabled, spdyWasUsed);
qint64 preConnectElapsed = preConnectResult.second;
qDebug() << request.url().toString() << "full request:" << normalElapsed
<< "ms, pre-connect request:" << preConnectElapsed << "ms, difference:"
@ -605,27 +593,11 @@ void tst_qnetworkreply::preConnectEncrypted_data()
{
#ifndef QT_NO_OPENSSL
QTest::addColumn<int>("sleepTime");
QTest::addColumn<QSslConfiguration>("sslConfiguration");
// start a new normal request after preconnecting is done
QTest::newRow("HTTPS-2secs") << 2000 << QSslConfiguration();
QTest::newRow("HTTPS-2secs") << 2000;
// start a new normal request while preconnecting is in-flight
QTest::newRow("HTTPS-100ms") << 100 << QSslConfiguration();
QSslConfiguration spdySslConf = QSslConfiguration::defaultConfiguration();
QList<QByteArray> nextProtocols = QList<QByteArray>()
<< QSslConfiguration::NextProtocolSpdy3_0
<< QSslConfiguration::NextProtocolHttp1_1;
spdySslConf.setAllowedNextProtocols(nextProtocols);
#if defined(QT_BUILD_INTERNAL) && !defined(QT_NO_SSL) && OPENSSL_VERSION_NUMBER >= 0x1000100fL && !defined(OPENSSL_NO_TLSEXT) && !defined(OPENSSL_NO_NEXTPROTONEG)
// start a new SPDY request while preconnecting is done
QTest::newRow("SPDY-2secs") << 2000 << spdySslConf;
// start a new SPDY request while preconnecting is in-flight
QTest::newRow("SPDY-100ms") << 100 << spdySslConf;
#endif // defined (QT_BUILD_INTERNAL) && !defined(QT_NO_SSL) ...
QTest::newRow("HTTPS-100ms") << 100;
#endif // QT_NO_OPENSSL
}

View File

@ -58,9 +58,6 @@ private slots:
void setSslConfiguration_data();
void setSslConfiguration();
void uploadToFacebook();
void spdy_data();
void spdy();
void spdyMultipleRequestsPerHost();
void proxyAuthentication_data();
void proxyAuthentication();
void authentication();
@ -290,126 +287,6 @@ void tst_qnetworkreply::uploadToFacebook()
}
}
void tst_qnetworkreply::spdy_data()
{
QTest::addColumn<QString>("host");
QTest::addColumn<bool>("setAttribute");
QTest::addColumn<bool>("enabled");
QTest::addColumn<QByteArray>("expectedProtocol");
QList<QString> hosts = QList<QString>()
<< QStringLiteral("www.google.com") // sends SPDY and 30x redirect
<< QStringLiteral("www.google.de") // sends SPDY and 200 OK
<< QStringLiteral("mail.google.com") // sends SPDY and 200 OK
<< QStringLiteral("www.youtube.com") // sends SPDY and 200 OK
<< QStringLiteral("www.dropbox.com") // no SPDY, but NPN which selects HTTP
<< QStringLiteral("www.facebook.com") // sends SPDY and 200 OK
<< QStringLiteral("graph.facebook.com") // sends SPDY and 200 OK
<< QStringLiteral("www.twitter.com") // sends SPDY and 30x redirect
<< QStringLiteral("twitter.com") // sends SPDY and 200 OK
<< QStringLiteral("api.twitter.com"); // sends SPDY and 200 OK
foreach (const QString &host, hosts) {
QByteArray tag = host.toLocal8Bit();
tag.append("-not-used");
QTest::newRow(tag)
<< QStringLiteral("https://") + host
<< false
<< false
<< QByteArray();
tag = host.toLocal8Bit();
tag.append("-disabled");
QTest::newRow(tag)
<< QStringLiteral("https://") + host
<< true
<< false
<< QByteArray();
if (host != QStringLiteral("api.twitter.com")) { // they don't offer an API over HTTP
tag = host.toLocal8Bit();
tag.append("-no-https-url");
QTest::newRow(tag)
<< QStringLiteral("http://") + host
<< true
<< true
<< QByteArray();
}
#ifndef QT_NO_OPENSSL
tag = host.toLocal8Bit();
tag.append("-enabled");
QTest::newRow(tag)
<< QStringLiteral("https://") + host
<< true
<< true
<< (host == QStringLiteral("www.dropbox.com")
? QByteArray(QSslConfiguration::NextProtocolHttp1_1)
: QByteArray(QSslConfiguration::NextProtocolSpdy3_0));
#endif // QT_NO_OPENSSL
}
}
void tst_qnetworkreply::spdy()
{
#if defined(QT_BUILD_INTERNAL) && !defined(QT_NO_SSL) && OPENSSL_VERSION_NUMBER >= 0x1000100fL && !defined(OPENSSL_NO_TLSEXT) && !defined(OPENSSL_NO_NEXTPROTONEG)
m_manager.clearAccessCache();
QFETCH(QString, host);
QUrl url(host);
QNetworkRequest request(url);
QFETCH(bool, setAttribute);
QFETCH(bool, enabled);
if (setAttribute) {
request.setAttribute(QNetworkRequest::SpdyAllowedAttribute, QVariant(enabled));
}
QNetworkReply *reply = m_manager.get(request);
QObject::connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
QSignalSpy metaDataChangedSpy(reply, SIGNAL(metaDataChanged()));
QSignalSpy readyReadSpy(reply, SIGNAL(readyRead()));
QSignalSpy finishedSpy(reply, SIGNAL(finished()));
QSignalSpy finishedManagerSpy(&m_manager, SIGNAL(finished(QNetworkReply*)));
QTestEventLoop::instance().enterLoop(15);
QVERIFY(!QTestEventLoop::instance().timeout());
QFETCH(QByteArray, expectedProtocol);
bool expectedSpdyUsed = (expectedProtocol == QSslConfiguration::NextProtocolSpdy3_0);
QCOMPARE(reply->attribute(QNetworkRequest::SpdyWasUsedAttribute).toBool(), expectedSpdyUsed);
QCOMPARE(metaDataChangedSpy.count(), 1);
QCOMPARE(finishedSpy.count(), 1);
QCOMPARE(finishedManagerSpy.count(), 1);
QUrl redirectUrl = reply->header(QNetworkRequest::LocationHeader).toUrl();
QByteArray content = reply->readAll();
int statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
QVERIFY(statusCode >= 200 && statusCode < 500);
if (statusCode == 200 || statusCode >= 400) {
QVERIFY(readyReadSpy.count() > 0);
QVERIFY(!content.isEmpty());
} else if (statusCode >= 300 && statusCode < 400) {
QVERIFY(!redirectUrl.isEmpty());
}
QSslConfiguration::NextProtocolNegotiationStatus expectedStatus =
expectedProtocol.isNull() ? QSslConfiguration::NextProtocolNegotiationNone
: QSslConfiguration::NextProtocolNegotiationNegotiated;
QCOMPARE(reply->sslConfiguration().nextProtocolNegotiationStatus(),
expectedStatus);
QCOMPARE(reply->sslConfiguration().nextNegotiatedProtocol(), expectedProtocol);
#else
QSKIP("Qt built withouth OpenSSL, or the OpenSSL version is too old");
#endif // defined(QT_BUILD_INTERNAL) && !defined(QT_NO_SSL) ...
}
void tst_qnetworkreply::spdyReplyFinished()
{
static int finishedCount = 0;
@ -419,85 +296,6 @@ void tst_qnetworkreply::spdyReplyFinished()
QTestEventLoop::instance().exitLoop();
}
void tst_qnetworkreply::spdyMultipleRequestsPerHost()
{
#if defined(QT_BUILD_INTERNAL) && !defined(QT_NO_SSL) && OPENSSL_VERSION_NUMBER >= 0x1000100fL && !defined(OPENSSL_NO_TLSEXT) && !defined(OPENSSL_NO_NEXTPROTONEG)
QList<QNetworkRequest> requests;
requests
<< QNetworkRequest(QUrl("https://www.facebook.com"))
<< QNetworkRequest(QUrl("https://www.facebook.com/images/fb_icon_325x325.png"))
<< QNetworkRequest(QUrl("https://www.google.de"))
<< QNetworkRequest(QUrl("https://www.google.de/preferences?hl=de"))
<< QNetworkRequest(QUrl("https://www.google.de/intl/de/policies/?fg=1"))
<< QNetworkRequest(QUrl("https://www.google.de/intl/de/about.html?fg=1"))
<< QNetworkRequest(QUrl("https://www.google.de/services/?fg=1"))
<< QNetworkRequest(QUrl("https://www.google.de/intl/de/ads/?fg=1"))
<< QNetworkRequest(QUrl("https://i1.ytimg.com/li/tnHdj3df7iM/default.jpg"))
<< QNetworkRequest(QUrl("https://i1.ytimg.com/li/7Dr1BKwqctY/default.jpg"))
<< QNetworkRequest(QUrl("https://i1.ytimg.com/li/hfZhJdhTqX8/default.jpg"))
<< QNetworkRequest(QUrl("https://i1.ytimg.com/vi/14Nprh8163I/hqdefault.jpg"))
;
QList<QNetworkReply *> replies;
QList<QSignalSpy *> metaDataChangedSpies;
QList<QSignalSpy *> readyReadSpies;
QList<QSignalSpy *> finishedSpies;
QSignalSpy finishedManagerSpy(&m_manager, SIGNAL(finished(QNetworkReply*)));
foreach (QNetworkRequest request, requests) {
request.setAttribute(QNetworkRequest::SpdyAllowedAttribute, true);
QNetworkReply *reply = m_manager.get(request);
QObject::connect(reply, SIGNAL(finished()), this, SLOT(spdyReplyFinished()));
replies << reply;
QSignalSpy *metaDataChangedSpy = new QSignalSpy(reply, SIGNAL(metaDataChanged()));
metaDataChangedSpies << metaDataChangedSpy;
QSignalSpy *readyReadSpy = new QSignalSpy(reply, SIGNAL(readyRead()));
readyReadSpies << readyReadSpy;
QSignalSpy *finishedSpy = new QSignalSpy(reply, SIGNAL(finished()));
finishedSpies << finishedSpy;
}
QCOMPARE(requests.count(), replies.count());
QTestEventLoop::instance().enterLoop(15);
QVERIFY(!QTestEventLoop::instance().timeout());
QCOMPARE(finishedManagerSpy.count(), requests.count());
for (int a = 0; a < replies.count(); ++a) {
QCOMPARE(replies.at(a)->sslConfiguration().nextProtocolNegotiationStatus(),
QSslConfiguration::NextProtocolNegotiationNegotiated);
QCOMPARE(replies.at(a)->sslConfiguration().nextNegotiatedProtocol(),
QByteArray(QSslConfiguration::NextProtocolSpdy3_0));
QCOMPARE(replies.at(a)->error(), QNetworkReply::NoError);
QCOMPARE(replies.at(a)->attribute(QNetworkRequest::SpdyWasUsedAttribute).toBool(), true);
QCOMPARE(replies.at(a)->attribute(QNetworkRequest::ConnectionEncryptedAttribute).toBool(), true);
QCOMPARE(replies.at(a)->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
QByteArray content = replies.at(a)->readAll();
QVERIFY(content.count() > 0);
QCOMPARE(metaDataChangedSpies.at(a)->count(), 1);
metaDataChangedSpies.at(a)->deleteLater();
QCOMPARE(finishedSpies.at(a)->count(), 1);
finishedSpies.at(a)->deleteLater();
QVERIFY(readyReadSpies.at(a)->count() > 0);
readyReadSpies.at(a)->deleteLater();
replies.at(a)->deleteLater();
}
#else
QSKIP("Qt built withouth OpenSSL, or the OpenSSL version is too old");
#endif // defined(QT_BUILD_INTERNAL) && !defined(QT_NO_SSL) ...
}
void tst_qnetworkreply::proxyAuthentication_data()
{
QTest::addColumn<QUrl>("url");
@ -586,7 +384,7 @@ void tst_qnetworkreply::npnWithEmptyList() // QTBUG-40714
QUrl url(QStringLiteral("https://www.ossifrage.net/"));
QNetworkRequest request(url);
request.setAttribute(QNetworkRequest::SpdyAllowedAttribute, QVariant(true));
request.setAttribute(QNetworkRequest::Http2AllowedAttribute, QVariant(true));
QNetworkReply *reply = m_manager.get(request);
QObject::connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));