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#ifndef QHTTP2PROTOCOLHANDLER_P_H
5#define QHTTP2PROTOCOLHANDLER_P_H
6
7//
8// W A R N I N G
9// -------------
10//
11// This file is not part of the Qt API. It exists for the convenience
12// of the Network Access API. This header file may change from
13// version to version without notice, or even be removed.
14//
15// We mean it.
16//
17
18#include <private/qhttpnetworkconnectionchannel_p.h>
19#include <private/qabstractprotocolhandler_p.h>
20#include <private/qhttpnetworkrequest_p.h>
21
22#include <access/qhttp2configuration.h>
23
24#include <private/http2protocol_p.h>
25#include <private/http2streams_p.h>
26#include <private/http2frames_p.h>
27#include <private/hpacktable_p.h>
28#include <private/hpack_p.h>
29
30#include <QtCore/qnamespace.h>
31#include <QtCore/qbytearray.h>
32#include <QtCore/qglobal.h>
33#include <QtCore/qobject.h>
34#include <QtCore/qflags.h>
35#include <QtCore/qhash.h>
36
37#include <vector>
38#include <limits>
39#include <deque>
40#include <set>
41
42QT_REQUIRE_CONFIG(http);
43
44QT_BEGIN_NAMESPACE
45
46class QHttp2ProtocolHandler : public QObject, public QAbstractProtocolHandler
47{
48 Q_OBJECT
49
50public:
51 QHttp2ProtocolHandler(QHttpNetworkConnectionChannel *channel);
52
53 QHttp2ProtocolHandler(const QHttp2ProtocolHandler &rhs) = delete;
54 QHttp2ProtocolHandler(QHttp2ProtocolHandler &&rhs) = delete;
55
56 QHttp2ProtocolHandler &operator = (const QHttp2ProtocolHandler &rhs) = delete;
57 QHttp2ProtocolHandler &operator = (QHttp2ProtocolHandler &&rhs) = delete;
58
59 Q_INVOKABLE void handleConnectionClosure();
60 Q_INVOKABLE void ensureClientPrefaceSent();
61
62private slots:
63 void _q_uploadDataReadyRead();
64 void _q_replyDestroyed(QObject* reply);
65 void _q_uploadDataDestroyed(QObject* uploadData);
66
67private:
68 using Stream = Http2::Stream;
69
70 void _q_readyRead() override;
71 Q_INVOKABLE void _q_receiveReply() override;
72 Q_INVOKABLE bool sendRequest() override;
73
74 bool sendClientPreface();
75 bool sendSETTINGS_ACK();
76 bool sendHEADERS(Stream &stream);
77 bool sendDATA(Stream &stream);
78 Q_INVOKABLE bool sendWINDOW_UPDATE(quint32 streamID, quint32 delta);
79 bool sendRST_STREAM(quint32 streamID, quint32 errorCoder);
80 bool sendGOAWAY(quint32 errorCode);
81
82 void handleDATA();
83 void handleHEADERS();
84 void handlePRIORITY();
85 void handleRST_STREAM();
86 void handleSETTINGS();
87 void handlePUSH_PROMISE();
88 void handlePING();
89 void handleGOAWAY();
90 void handleWINDOW_UPDATE();
91 void handleCONTINUATION();
92
93 void handleContinuedHEADERS();
94
95 bool acceptSetting(Http2::Settings identifier, quint32 newValue);
96
97 void updateStream(Stream &stream, const HPack::HttpHeader &headers,
98 Qt::ConnectionType connectionType = Qt::DirectConnection);
99 void updateStream(Stream &stream, const Http2::Frame &dataFrame,
100 Qt::ConnectionType connectionType = Qt::DirectConnection);
101 void finishStream(Stream &stream, Qt::ConnectionType connectionType = Qt::DirectConnection);
102 // Error code send by a peer (GOAWAY/RST_STREAM):
103 void finishStreamWithError(Stream &stream, quint32 errorCode);
104 // Locally encountered error:
105 void finishStreamWithError(Stream &stream, QNetworkReply::NetworkError error,
106 const QString &message);
107
108 // Stream's lifecycle management:
109 quint32 createNewStream(const HttpMessagePair &message, bool uploadDone = false);
110 void addToSuspended(Stream &stream);
111 void markAsReset(quint32 streamID);
112 quint32 popStreamToResume();
113 void removeFromSuspended(quint32 streamID);
114 void deleteActiveStream(quint32 streamID);
115 bool streamWasReset(quint32 streamID) const;
116
117 bool prefaceSent = false;
118 // In the current implementation we send
119 // SETTINGS only once, immediately after
120 // the client's preface 24-byte message.
121 bool waitingForSettingsACK = false;
122
123 static const quint32 maxAcceptableTableSize = 16 * HPack::FieldLookupTable::DefaultSize;
124 // HTTP/2 4.3: Header compression is stateful. One compression context and
125 // one decompression context are used for the entire connection.
126 HPack::Decoder decoder;
127 HPack::Encoder encoder;
128
129 QHash<QObject *, int> streamIDs;
130 QHash<quint32, Stream> activeStreams;
131 std::deque<quint32> suspendedStreams[3]; // 3 for priorities: High, Normal, Low.
132 static const std::deque<quint32>::size_type maxRecycledStreams;
133 std::deque<quint32> recycledStreams;
134
135 // Peer's max frame size (this min is the default value
136 // we start with, that can be updated by SETTINGS frame):
137 quint32 maxFrameSize = Http2::minPayloadLimit;
138
139 Http2::FrameReader frameReader;
140 Http2::Frame inboundFrame;
141 Http2::FrameWriter frameWriter;
142 // Temporary storage to assemble HEADERS' block
143 // from several CONTINUATION frames ...
144 bool continuationExpected = false;
145 std::vector<Http2::Frame> continuedFrames;
146
147 // Control flow:
148
149 // This is how many concurrent streams our peer allows us, 100 is the
150 // initial value, can be updated by the server's SETTINGS frame(s):
151 quint32 maxConcurrentStreams = Http2::maxConcurrentStreams;
152 // While we allow sending SETTTINGS_MAX_CONCURRENT_STREAMS to limit our peer,
153 // it's just a hint and we do not actually enforce it (and we can continue
154 // sending requests and creating streams while maxConcurrentStreams allows).
155
156 // This is our (client-side) maximum possible receive window size, we set
157 // it in a ctor from QHttp2Configuration, it does not change after that.
158 // The default is 64Kb:
159 qint32 maxSessionReceiveWindowSize = Http2::defaultSessionWindowSize;
160
161 // Our session current receive window size, updated in a ctor from
162 // QHttp2Configuration. Signed integer since it can become negative
163 // (it's still a valid window size).
164 qint32 sessionReceiveWindowSize = Http2::defaultSessionWindowSize;
165 // Our per-stream receive window size, default is 64 Kb, will be updated
166 // from QHttp2Configuration. Again, signed - can become negative.
167 qint32 streamInitialReceiveWindowSize = Http2::defaultSessionWindowSize;
168
169 // These are our peer's receive window sizes, they will be updated by the
170 // peer's SETTINGS and WINDOW_UPDATE frames, defaults presumed to be 64Kb.
171 qint32 sessionSendWindowSize = Http2::defaultSessionWindowSize;
172 qint32 streamInitialSendWindowSize = Http2::defaultSessionWindowSize;
173
174 // Our peer's header size limitations. It's unlimited by default, but can
175 // be changed via peer's SETTINGS frame.
176 quint32 maxHeaderListSize = (std::numeric_limits<quint32>::max)();
177 // While we can send SETTINGS_MAX_HEADER_LIST_SIZE value (our limit on
178 // the headers size), we never enforce it, it's just a hint to our peer.
179
180 Q_INVOKABLE void resumeSuspendedStreams();
181 // Our stream IDs (all odd), the first valid will be 1.
182 quint32 nextID = 1;
183 quint32 allocateStreamID();
184 bool validPeerStreamID() const;
185 bool goingAway = false;
186 bool pushPromiseEnabled = false;
187 quint32 lastPromisedID = Http2::connectionStreamID;
188 QHash<QString, Http2::PushPromise> promisedData;
189 bool tryReserveStream(const Http2::Frame &pushPromiseFrame,
190 const HPack::HttpHeader &requestHeader);
191 void resetPromisedStream(const Http2::Frame &pushPromiseFrame,
192 Http2::Http2Error reason);
193 void initReplyFromPushPromise(const HttpMessagePair &message,
194 const QString &cacheKey);
195 // Errors:
196 void connectionError(Http2::Http2Error errorCode,
197 const char *message);
198 void closeSession();
199};
200
201QT_END_NAMESPACE
202
203#endif
204

source code of qtbase/src/network/access/qhttp2protocolhandler_p.h