Revert "Implement protocol upgrade for HTTP/2 enabled requests"
This reverts commit 12d71f4ea2
.
This change is breaking a build + incomplete as my test revealed.
Will have to re-try later.
Change-Id: I7ea089093a832aa5822caaaac56e62f5fda4df17
Reviewed-by: Liang Qi <liang.qi@qt.io>
This commit is contained in:
parent
4a40c717f3
commit
2d1f137173
@ -37,12 +37,9 @@
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include <QtCore/qbytearray.h>
|
||||
#include <QtCore/qstring.h>
|
||||
|
||||
#include "private/qhttpnetworkrequest_p.h"
|
||||
#include "http2protocol_p.h"
|
||||
#include "http2frames_p.h"
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
@ -60,37 +57,6 @@ const char Http2clientPreface[clientPrefaceLength] =
|
||||
0x2e, 0x30, 0x0d, 0x0a, 0x0d, 0x0a,
|
||||
0x53, 0x4d, 0x0d, 0x0a, 0x0d, 0x0a};
|
||||
|
||||
QByteArray qt_default_SETTINGS_to_Base64()
|
||||
{
|
||||
FrameWriter frame(qt_default_SETTINGS_frame());
|
||||
// SETTINGS frame's payload consists of pairs:
|
||||
// 2-byte-identifier | 4-byte-value - multiple of 6.
|
||||
// Also it's allowed to be empty.
|
||||
Q_ASSERT(!(frame.payloadSize() % 6));
|
||||
const char *src = reinterpret_cast<const char *>(&frame.rawFrameBuffer()[frameHeaderSize]);
|
||||
const QByteArray wrapper(QByteArray::fromRawData(src, int(frame.payloadSize())));
|
||||
// 3.2.1
|
||||
// The content of the HTTP2-Settings header field is the payload
|
||||
// of a SETTINGS frame (Section 6.5), encoded as a base64url string
|
||||
// (that is, the URL- and filename-safe Base64 encoding described in
|
||||
// Section 5 of [RFC4648], with any trailing '=' characters omitted).
|
||||
return wrapper.toBase64(QByteArray::Base64UrlEncoding | QByteArray::OmitTrailingEquals);
|
||||
}
|
||||
|
||||
void qt_add_ProtocolUpgradeRequest(QHttpNetworkRequest &request)
|
||||
{
|
||||
// RFC 2616, 14.10
|
||||
QByteArray value(request.headerField("Connection"));
|
||||
if (value.size())
|
||||
value += ", ";
|
||||
|
||||
value += "Upgrade, HTTP2-Settings";
|
||||
request.setHeaderField("Connection", value);
|
||||
// This we just (re)write.
|
||||
request.setHeaderField("Upgrade", "h2c");
|
||||
// This we just (re)write.
|
||||
request.setHeaderField("HTTP2-Settings", qt_default_SETTINGS_to_Base64());
|
||||
}
|
||||
|
||||
void qt_error(quint32 errorCode, QNetworkReply::NetworkError &error,
|
||||
QString &errorMessage)
|
||||
@ -185,19 +151,6 @@ QNetworkReply::NetworkError qt_error(quint32 errorCode)
|
||||
return error;
|
||||
}
|
||||
|
||||
FrameWriter qt_default_SETTINGS_frame()
|
||||
{
|
||||
// 6.5 SETTINGS
|
||||
FrameWriter frame(FrameType::SETTINGS, FrameFlag::EMPTY, connectionStreamID);
|
||||
// MAX frame size (16 kb), disable PUSH
|
||||
frame.append(Settings::MAX_FRAME_SIZE_ID);
|
||||
frame.append(quint32(maxFrameSize));
|
||||
frame.append(Settings::ENABLE_PUSH_ID);
|
||||
frame.append(quint32(0));
|
||||
|
||||
return frame;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
@ -59,8 +59,6 @@
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
class QHttpNetworkRequest;
|
||||
class QByteArray;
|
||||
class QString;
|
||||
|
||||
namespace Http2
|
||||
@ -130,7 +128,6 @@ enum Http2PredefinedParameters
|
||||
};
|
||||
|
||||
extern const Q_AUTOTEST_EXPORT char Http2clientPreface[clientPrefaceLength];
|
||||
void qt_add_ProtocolUpgradeRequest(QHttpNetworkRequest &request);
|
||||
|
||||
enum class FrameStatus
|
||||
{
|
||||
@ -169,8 +166,6 @@ void qt_error(quint32 errorCode, QNetworkReply::NetworkError &error, QString &er
|
||||
QString qt_error_string(quint32 errorCode);
|
||||
QNetworkReply::NetworkError qt_error(quint32 errorCode);
|
||||
|
||||
class FrameWriter qt_default_SETTINGS_frame();
|
||||
|
||||
}
|
||||
|
||||
Q_DECLARE_LOGGING_CATEGORY(QT_HTTP2)
|
||||
|
@ -40,7 +40,7 @@
|
||||
#include "qhttpnetworkconnection_p.h"
|
||||
#include "qhttp2protocolhandler_p.h"
|
||||
|
||||
#if !defined(QT_NO_HTTP)
|
||||
#if !defined(QT_NO_HTTP) && !defined(QT_NO_SSL)
|
||||
|
||||
#include "http2/bitstreams_p.h"
|
||||
|
||||
@ -54,7 +54,6 @@
|
||||
#include <QtCore/qurl.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
@ -134,28 +133,6 @@ QHttp2ProtocolHandler::QHttp2ProtocolHandler(QHttpNetworkConnectionChannel *chan
|
||||
continuedFrames.reserve(20);
|
||||
}
|
||||
|
||||
QHttp2ProtocolHandler::QHttp2ProtocolHandler(QHttpNetworkConnectionChannel *channel,
|
||||
const HttpMessagePair &message)
|
||||
: QAbstractProtocolHandler(channel),
|
||||
prefaceSent(false),
|
||||
waitingForSettingsACK(false),
|
||||
decoder(HPack::FieldLookupTable::DefaultSize),
|
||||
encoder(HPack::FieldLookupTable::DefaultSize, true)
|
||||
{
|
||||
// That's a protocol upgrade scenario - 3.2.
|
||||
//
|
||||
// We still have to send settings and the preface
|
||||
// (though SETTINGS was a part of the first HTTP/1.1
|
||||
// request "HTTP2-Settings" field).
|
||||
//
|
||||
// We pass 'false' for upload data, this was done by HTTP/1.1 protocol
|
||||
// handler for us while sending the first request.
|
||||
const quint32 initialStreamID = createNewStream(message, false);
|
||||
Q_ASSERT(initialStreamID == 1);
|
||||
Stream &stream = activeStreams[initialStreamID];
|
||||
stream.state = Stream::halfClosedLocal;
|
||||
}
|
||||
|
||||
void QHttp2ProtocolHandler::_q_uploadDataReadyRead()
|
||||
{
|
||||
auto data = qobject_cast<QNonContiguousByteDevice *>(sender());
|
||||
@ -270,7 +247,7 @@ bool QHttp2ProtocolHandler::sendRequest()
|
||||
auto it = requests.begin();
|
||||
m_channel->state = QHttpNetworkConnectionChannel::WritingState;
|
||||
for (quint32 i = 0; i < streamsToUse; ++i) {
|
||||
const qint32 newStreamID = createNewStream(*it, true /* upload data */);
|
||||
const qint32 newStreamID = createNewStream(*it);
|
||||
if (!newStreamID) {
|
||||
// TODO: actually we have to open a new connection.
|
||||
qCCritical(QT_HTTP2, "sendRequest: out of stream IDs");
|
||||
@ -301,6 +278,7 @@ bool QHttp2ProtocolHandler::sendRequest()
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool QHttp2ProtocolHandler::sendClientPreface()
|
||||
{
|
||||
// 3.5 HTTP/2 Connection Preface
|
||||
@ -315,8 +293,12 @@ bool QHttp2ProtocolHandler::sendClientPreface()
|
||||
return false;
|
||||
|
||||
// 6.5 SETTINGS
|
||||
outboundFrame = Http2::qt_default_SETTINGS_frame();
|
||||
Q_ASSERT(outboundFrame.payloadSize());
|
||||
outboundFrame.start(FrameType::SETTINGS, FrameFlag::EMPTY, Http2::connectionStreamID);
|
||||
// MAX frame size (16 kb), disable PUSH
|
||||
outboundFrame.append(Settings::MAX_FRAME_SIZE_ID);
|
||||
outboundFrame.append(quint32(Http2::maxFrameSize));
|
||||
outboundFrame.append(Settings::ENABLE_PUSH_ID);
|
||||
outboundFrame.append(quint32(0));
|
||||
|
||||
if (!outboundFrame.write(*m_socket))
|
||||
return false;
|
||||
@ -1040,8 +1022,7 @@ void QHttp2ProtocolHandler::finishStreamWithError(Stream &stream, QNetworkReply:
|
||||
emit httpReply->finishedWithError(error, message);
|
||||
}
|
||||
|
||||
quint32 QHttp2ProtocolHandler::createNewStream(const HttpMessagePair &message,
|
||||
bool uploadData)
|
||||
quint32 QHttp2ProtocolHandler::createNewStream(const HttpMessagePair &message)
|
||||
{
|
||||
const qint32 newStreamID = allocateStreamID();
|
||||
if (!newStreamID)
|
||||
@ -1062,12 +1043,10 @@ quint32 QHttp2ProtocolHandler::createNewStream(const HttpMessagePair &message,
|
||||
streamInitialSendWindowSize,
|
||||
streamInitialRecvWindowSize);
|
||||
|
||||
if (uploadData) {
|
||||
if (auto src = newStream.data()) {
|
||||
connect(src, SIGNAL(readyRead()), this,
|
||||
SLOT(_q_uploadDataReadyRead()), Qt::QueuedConnection);
|
||||
src->setProperty("HTTP2StreamID", newStreamID);
|
||||
}
|
||||
if (auto src = newStream.data()) {
|
||||
connect(src, SIGNAL(readyRead()), this,
|
||||
SLOT(_q_uploadDataReadyRead()), Qt::QueuedConnection);
|
||||
src->setProperty("HTTP2StreamID", newStreamID);
|
||||
}
|
||||
|
||||
activeStreams.insert(newStreamID, newStream);
|
||||
@ -1235,4 +1214,4 @@ void QHttp2ProtocolHandler::closeSession()
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#endif // !defined(QT_NO_HTTP)
|
||||
#endif // !defined(QT_NO_HTTP) && !defined(QT_NO_SSL)
|
||||
|
@ -55,7 +55,7 @@
|
||||
#include <private/qabstractprotocolhandler_p.h>
|
||||
#include <private/qhttpnetworkrequest_p.h>
|
||||
|
||||
#if !defined(QT_NO_HTTP)
|
||||
#if !defined(QT_NO_HTTP) && !defined(QT_NO_SSL)
|
||||
|
||||
#include "http2/http2protocol_p.h"
|
||||
#include "http2/http2streams_p.h"
|
||||
@ -81,15 +81,7 @@ class QHttp2ProtocolHandler : public QObject, public QAbstractProtocolHandler
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
// "TLS + ALPN/NPN" case:
|
||||
QHttp2ProtocolHandler(QHttpNetworkConnectionChannel *channel);
|
||||
// HTTP2 without TLS - the first request was sent as an HTTP/1.1 request
|
||||
// with Upgrade:h2c header. That serves as an implicit HTTP/2 request
|
||||
// on a stream with ID 1 (it will be created in this ctor in a
|
||||
// 'half-closed-local' state); reply, if server supports HTTP/2,
|
||||
// will be HTTP/2 frame(s):
|
||||
QHttp2ProtocolHandler(QHttpNetworkConnectionChannel *channel,
|
||||
const HttpMessagePair &message);
|
||||
|
||||
QHttp2ProtocolHandler(const QHttp2ProtocolHandler &rhs) = delete;
|
||||
QHttp2ProtocolHandler(QHttp2ProtocolHandler &&rhs) = delete;
|
||||
@ -141,7 +133,7 @@ private:
|
||||
const QString &message);
|
||||
|
||||
// Stream's lifecycle management:
|
||||
quint32 createNewStream(const HttpMessagePair &message, bool uploadData);
|
||||
quint32 createNewStream(const HttpMessagePair &message);
|
||||
void addToSuspended(Stream &stream);
|
||||
void markAsReset(quint32 streamID);
|
||||
quint32 popStreamToResume();
|
||||
@ -210,6 +202,6 @@ private:
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#endif // !defined(QT_NO_HTTP)
|
||||
#endif // !defined(QT_NO_HTTP) && !defined(QT_NO_SSL)
|
||||
|
||||
#endif
|
||||
|
@ -50,7 +50,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
|
||||
# include <private/qsslsocket_p.h>
|
||||
@ -181,9 +180,6 @@ void QHttpNetworkConnectionChannel::init()
|
||||
sslSocket->setSslConfiguration(sslConfiguration);
|
||||
} else {
|
||||
#endif // QT_NO_SSL
|
||||
// Even if connection->connectionType is ConnectionTypeHTTP2,
|
||||
// we first start as HTTP/1.1, asking for a protocol upgrade
|
||||
// in the first response.
|
||||
protocolHandler.reset(new QHttpProtocolHandler(this));
|
||||
#ifndef QT_NO_SSL
|
||||
}
|
||||
@ -839,16 +835,6 @@ void QHttpNetworkConnectionChannel::_q_connected()
|
||||
#endif
|
||||
} else {
|
||||
state = QHttpNetworkConnectionChannel::IdleState;
|
||||
if (connection->connectionType() == QHttpNetworkConnection::ConnectionTypeHTTP2) {
|
||||
Q_ASSERT(spdyRequestsToSend.size());
|
||||
auto it = spdyRequestsToSend.begin();
|
||||
// Let's inject some magic fields, requesting a protocol upgrade:
|
||||
Http2::qt_add_ProtocolUpgradeRequest(it->first);
|
||||
connection->d_func()->requeueRequest(*it);
|
||||
// Remove it, we never send it again as HTTP/2.
|
||||
spdyRequestsToSend.erase(it);
|
||||
}
|
||||
|
||||
if (!reply)
|
||||
connection->d_func()->dequeueRequest(socket);
|
||||
if (reply)
|
||||
@ -986,12 +972,9 @@ void QHttpNetworkConnectionChannel::_q_error(QAbstractSocket::SocketError socket
|
||||
}
|
||||
} while (!connection->d_func()->highPriorityQueue.isEmpty()
|
||||
|| !connection->d_func()->lowPriorityQueue.isEmpty());
|
||||
|
||||
if (connection->connectionType() == QHttpNetworkConnection::ConnectionTypeHTTP2
|
||||
#ifndef QT_NO_SSL
|
||||
|| connection->connectionType() == QHttpNetworkConnection::ConnectionTypeSPDY
|
||||
#endif
|
||||
) {
|
||||
if (connection->connectionType() == QHttpNetworkConnection::ConnectionTypeSPDY ||
|
||||
connection->connectionType() == QHttpNetworkConnection::ConnectionTypeHTTP2) {
|
||||
QList<HttpMessagePair> spdyPairs = spdyRequestsToSend.values();
|
||||
for (int a = 0; a < spdyPairs.count(); ++a) {
|
||||
// emit error for all replies
|
||||
@ -1000,6 +983,7 @@ void QHttpNetworkConnectionChannel::_q_error(QAbstractSocket::SocketError socket
|
||||
emit currentReply->finishedWithError(errorCode, errorString);
|
||||
}
|
||||
}
|
||||
#endif // QT_NO_SSL
|
||||
|
||||
// send the next request
|
||||
QMetaObject::invokeMethod(that, "_q_startNextRequest", Qt::QueuedConnection);
|
||||
@ -1018,31 +1002,23 @@ void QHttpNetworkConnectionChannel::_q_error(QAbstractSocket::SocketError socket
|
||||
}
|
||||
}
|
||||
|
||||
void QHttpNetworkConnectionChannel::_q_protocolSwitch()
|
||||
{
|
||||
Q_ASSERT(connection->connectionType() == QHttpNetworkConnection::ConnectionTypeHTTP2);
|
||||
Q_ASSERT(reply);
|
||||
Q_ASSERT(reply->statusCode() == 101);
|
||||
protocolHandler.reset(new QHttp2ProtocolHandler(this, HttpMessagePair(request, reply)));
|
||||
protocolHandler->_q_receiveReply();
|
||||
}
|
||||
|
||||
#ifndef QT_NO_NETWORKPROXY
|
||||
void QHttpNetworkConnectionChannel::_q_proxyAuthenticationRequired(const QNetworkProxy &proxy, QAuthenticator* auth)
|
||||
{
|
||||
if (connection->connectionType() == QHttpNetworkConnection::ConnectionTypeHTTP2
|
||||
#ifndef QT_NO_SSL
|
||||
|| connection->connectionType() == QHttpNetworkConnection::ConnectionTypeSPDY
|
||||
#endif
|
||||
) {
|
||||
if (connection->connectionType() == QHttpNetworkConnection::ConnectionTypeSPDY ||
|
||||
connection->connectionType() == QHttpNetworkConnection::ConnectionTypeHTTP2) {
|
||||
connection->d_func()->emitProxyAuthenticationRequired(this, proxy, auth);
|
||||
} else { // HTTP
|
||||
#endif // QT_NO_SSL
|
||||
// Need to dequeue the request before we can emit the error.
|
||||
if (!reply)
|
||||
connection->d_func()->dequeueRequest(socket);
|
||||
if (reply)
|
||||
connection->d_func()->emitProxyAuthenticationRequired(this, proxy, auth);
|
||||
#ifndef QT_NO_SSL
|
||||
}
|
||||
#endif // QT_NO_SSL
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -121,14 +121,11 @@ 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;
|
||||
#ifndef QT_NO_SSL
|
||||
bool ignoreAllSslErrors;
|
||||
QList<QSslError> ignoreSslErrorsList;
|
||||
QSslConfiguration sslConfiguration;
|
||||
QMultiMap<int, HttpMessagePair> spdyRequestsToSend; // sorted by priority
|
||||
void ignoreSslErrors();
|
||||
void ignoreSslErrors(const QList<QSslError> &errors);
|
||||
void setSslConfiguration(const QSslConfiguration &config);
|
||||
@ -195,7 +192,6 @@ public:
|
||||
void _q_disconnected(); // disconnected from host
|
||||
void _q_connected(); // start sending request
|
||||
void _q_error(QAbstractSocket::SocketError); // error from socket
|
||||
void _q_protocolSwitch(); // HTTP/2 was negotiated to replace HTTP/1.1
|
||||
#ifndef QT_NO_NETWORKPROXY
|
||||
void _q_proxyAuthenticationRequired(const QNetworkProxy &proxy, QAuthenticator *auth); // from transparent proxy
|
||||
#endif
|
||||
|
@ -129,15 +129,6 @@ void QHttpProtocolHandler::_q_receiveReply()
|
||||
} else {
|
||||
replyPrivate->autoDecompress = false;
|
||||
}
|
||||
if (m_connection->connectionType() == QHttpNetworkConnection::ConnectionTypeHTTP2) {
|
||||
if (replyPrivate->statusCode == 101) {
|
||||
QMetaObject::invokeMethod(m_channel, "_q_protocolSwitch", Qt::QueuedConnection);
|
||||
return;
|
||||
}
|
||||
|
||||
// HTTP/2 is not supported? TODO - but can it be something else?
|
||||
m_channel->requeueSpdyRequests();
|
||||
}
|
||||
if (replyPrivate->statusCode == 100) {
|
||||
replyPrivate->clearHttpLayerInformation();
|
||||
replyPrivate->state = QHttpNetworkReplyPrivate::ReadingStatusState;
|
||||
|
@ -286,12 +286,9 @@ void QHttpThreadDelegate::startRequest()
|
||||
|
||||
QHttpNetworkConnection::ConnectionType connectionType
|
||||
= QHttpNetworkConnection::ConnectionTypeHTTP;
|
||||
|
||||
if (httpRequest.isHTTP2Allowed())
|
||||
connectionType = QHttpNetworkConnection::ConnectionTypeHTTP2;
|
||||
|
||||
#ifndef QT_NO_SSL
|
||||
if (httpRequest.isHTTP2Allowed() && ssl) {
|
||||
connectionType = QHttpNetworkConnection::ConnectionTypeHTTP2;
|
||||
QList<QByteArray> protocols;
|
||||
protocols << QSslConfiguration::ALPNProtocolHTTP2
|
||||
<< QSslConfiguration::NextProtocolHttp1_1;
|
||||
|
Loading…
Reference in New Issue
Block a user