Qt 6.x
The Qt SDK
Loading...
Searching...
No Matches
http2protocol.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "http2protocol_p.h"
5#include "http2frames_p.h"
6
7#include "private/qhttpnetworkrequest_p.h"
8#include "private/qhttpnetworkreply_p.h"
9
11
12#include <QtCore/qbytearray.h>
13#include <QtCore/qstring.h>
14
16
17using namespace Qt::StringLiterals;
18
20
21Q_LOGGING_CATEGORY(QT_HTTP2, "qt.network.http2")
22
23namespace Http2
24{
25
26// 3.5 HTTP/2 Connection Preface:
27// "That is, the connection preface starts with the string
28// PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n)."
30 {0x50, 0x52, 0x49, 0x20, 0x2a, 0x20,
31 0x48, 0x54, 0x54, 0x50, 0x2f, 0x32,
32 0x2e, 0x30, 0x0d, 0x0a, 0x0d, 0x0a,
33 0x53, 0x4d, 0x0d, 0x0a, 0x0d, 0x0a};
34
36{
37 // 6.5 SETTINGS
38 FrameWriter builder(FrameType::SETTINGS, FrameFlag::EMPTY, connectionStreamID);
39 // Server push:
40 builder.append(Settings::ENABLE_PUSH_ID);
41 builder.append(int(config.serverPushEnabled()));
42
43 // Stream receive window size (if it's a default value, don't include):
44 if (config.streamReceiveWindowSize() != defaultSessionWindowSize) {
45 builder.append(Settings::INITIAL_WINDOW_SIZE_ID);
46 builder.append(config.streamReceiveWindowSize());
47 }
48
49 if (config.maxFrameSize() != minPayloadLimit) {
50 builder.append(Settings::MAX_FRAME_SIZE_ID);
51 builder.append(config.maxFrameSize());
52 }
53 // TODO: In future, if the need is proven, we can
54 // also send decoding table size and header list size.
55 // For now, defaults suffice.
56 return builder.outboundFrame();
57}
58
60{
61 // SETTINGS frame's payload consists of pairs:
62 // 2-byte-identifier | 4-byte-value == multiple of 6.
63 Q_ASSERT(frame.payloadSize() && !(frame.payloadSize() % 6));
64 const char *src = reinterpret_cast<const char *>(frame.dataBegin());
65 const QByteArray wrapper(QByteArray::fromRawData(src, int(frame.dataSize())));
66 // 3.2.1
67 // The content of the HTTP2-Settings header field is the payload
68 // of a SETTINGS frame (Section 6.5), encoded as a base64url string
69 // (that is, the URL- and filename-safe Base64 encoding described in
70 // Section 5 of [RFC4648], with any trailing '=' characters omitted).
72}
73
75{
77 // RFC 2616, 14.10
78 // RFC 7540, 3.2
79 QByteArray value(request->headerField("Connection"));
80 // We _append_ 'Upgrade':
81 if (value.size())
82 value += ", ";
83
84 value += "Upgrade, HTTP2-Settings";
85 request->setHeaderField("Connection", value);
86 // This we just (re)write.
87 request->setHeaderField("Upgrade", "h2c");
88
90 // This we just (re)write.
91 request->setHeaderField("HTTP2-Settings", settingsFrameToBase64(frame));
92}
93
96{
97 if (errorCode > quint32(HTTP_1_1_REQUIRED)) {
99 errorMessage = "RST_STREAM with unknown error code (%1)"_L1;
100 errorMessage = errorMessage.arg(errorCode);
101 return;
102 }
103
104 const Http2Error http2Error = Http2Error(errorCode);
105
106 switch (http2Error) {
107 case HTTP2_NO_ERROR:
110 break;
111 case PROTOCOL_ERROR:
113 errorMessage = "HTTP/2 protocol error"_L1;
114 break;
115 case INTERNAL_ERROR:
117 errorMessage = "Internal server error"_L1;
118 break;
121 errorMessage = "Flow control error"_L1;
122 break;
123 case SETTINGS_TIMEOUT:
125 errorMessage = "SETTINGS ACK timeout error"_L1;
126 break;
127 case STREAM_CLOSED:
129 errorMessage = "Server received frame(s) on a half-closed stream"_L1;
130 break;
131 case FRAME_SIZE_ERROR:
133 errorMessage = "Server received a frame with an invalid size"_L1;
134 break;
135 case REFUSE_STREAM:
137 errorMessage = "Server refused a stream"_L1;
138 break;
139 case CANCEL:
141 errorMessage = "Stream is no longer needed"_L1;
142 break;
145 errorMessage = "Server is unable to maintain the "
146 "header compression context for the connection"_L1;
147 break;
148 case CONNECT_ERROR:
149 // TODO: in Qt6 we'll have to add more error codes in QNetworkReply.
151 errorMessage = "The connection established in response "
152 "to a CONNECT request was reset or abnormally closed"_L1;
153 break;
156 errorMessage = "Server dislikes our behavior, excessive load detected."_L1;
157 break;
160 errorMessage = "The underlying transport has properties "
161 "that do not meet minimum security "
162 "requirements"_L1;
163 break;
166 errorMessage = "Server requires that HTTP/1.1 "
167 "be used instead of HTTP/2."_L1;
168 }
169}
170
172{
175 qt_error(errorCode, error, message);
176 return message;
177}
178
180{
183 qt_error(errorCode, error, message);
184 return error;
185}
186
188{
189 if (reply.statusCode() == 101) {
190 // Do some minimal checks here - we expect 'Upgrade: h2c' to be found.
191 const auto &header = reply.header();
192 for (const QPair<QByteArray, QByteArray> &field : header) {
193 if (field.first.compare("upgrade", Qt::CaseInsensitive) == 0 &&
194 field.second.compare("h2c", Qt::CaseInsensitive) == 0)
195 return true;
196 }
197 }
198
199 return false;
200}
201
202} // namespace Http2
203
void append(ValueType val)
Frame & outboundFrame()
\inmodule QtCore
Definition qbytearray.h:57
@ Base64UrlEncoding
Definition qbytearray.h:74
@ OmitTrailingEquals
Definition qbytearray.h:77
static QByteArray fromRawData(const char *data, qsizetype size)
Constructs a QByteArray that uses the first size bytes of the data array.
Definition qbytearray.h:394
The QHttp2Configuration class controls HTTP/2 parameters and settings.
QVariant header(QNetworkRequest::KnownHeaders header) const
Returns the value of the known header header, if that header was sent by the remote server.
NetworkError
Indicates all possible error conditions found during the processing of the request.
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:127
void clear()
Clears the contents of the string and makes it null.
Definition qstring.h:1107
QString arg(qlonglong a, int fieldwidth=0, int base=10, QChar fillChar=u' ') const
Definition qstring.cpp:8606
Frame configurationToSettingsFrame(const QHttp2Configuration &config)
const char Http2clientPreface[clientPrefaceLength]
bool is_protocol_upgraded(const QHttpNetworkReply &reply)
void appendProtocolUpgradeHeaders(const QHttp2Configuration &config, QHttpNetworkRequest *request)
@ defaultSessionWindowSize
@ connectionStreamID
@ clientPrefaceLength
@ minPayloadLimit
QByteArray settingsFrameToBase64(const Frame &frame)
@ COMPRESSION_ERROR
@ INADEQUATE_SECURITY
@ ENHANCE_YOUR_CALM
@ FLOW_CONTROL_ERROR
@ HTTP_1_1_REQUIRED
void qt_error(quint32 errorCode, QNetworkReply::NetworkError &error, QString &errorMessage)
Combined button and popup list for selecting options.
@ CaseInsensitive
std::pair< T1, T2 > QPair
DBusConnection const char DBusError * error
static QString header(const QString &name)
EGLConfig config
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
Q_DECL_COLD_FUNCTION Q_CORE_EXPORT QString qt_error_string(int errorCode=-1)
#define Q_LOGGING_CATEGORY(name,...)
#define QT_IMPL_METATYPE_EXTERN_TAGGED(TYPE, TAG)
Definition qmetatype.h:1363
GLenum src
GLuint GLsizei const GLchar * message
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
unsigned int quint32
Definition qtypes.h:45
static QString errorMessage(QUrlPrivate::ErrorCode errorCode, const QString &errorSource, qsizetype errorPosition)
Definition qurl.cpp:3503
QFrame frame
[0]
QNetworkRequest request(url)
QNetworkReply * reply
void wrapper()