1 /** @file
2
3 Http2ConnectionState.
4
5 @section license License
6
7 Licensed to the Apache Software Foundation (ASF) under one
8 or more contributor license agreements. See the NOTICE file
9 distributed with this work for additional information
10 regarding copyright ownership. The ASF licenses this file
11 to you under the Apache License, Version 2.0 (the
12 "License"); you may not use this file except in compliance
13 with the License. You may obtain a copy of the License at
14
15 http://www.apache.org/licenses/LICENSE-2.0
16
17 Unless required by applicable law or agreed to in writing, software
18 distributed under the License is distributed on an "AS IS" BASIS,
19 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20 See the License for the specific language governing permissions and
21 limitations under the License.
22 */
23
24 #include "P_Net.h"
25 #include "Http2ConnectionState.h"
26 #include "Http2ClientSession.h"
27 #include "Http2Stream.h"
28 #include "Http2Frame.h"
29 #include "Http2DebugNames.h"
30 #include "HttpDebugNames.h"
31
32 #include "tscpp/util/PostScript.h"
33 #include "tscpp/util/LocalBuffer.h"
34
35 #include <sstream>
36 #include <numeric>
37
38 #define REMEMBER(e, r) \
39 { \
40 if (this->ua_session) { \
41 this->ua_session->remember(MakeSourceLocation(), e, r); \
42 } \
43 }
44
45 #define Http2ConDebug(ua_session, fmt, ...) \
46 SsnDebug(ua_session, "http2_con", "[%" PRId64 "] " fmt, ua_session->connection_id(), ##__VA_ARGS__);
47
48 #define Http2StreamDebug(ua_session, stream_id, fmt, ...) \
49 SsnDebug(ua_session, "http2_con", "[%" PRId64 "] [%u] " fmt, ua_session->connection_id(), stream_id, ##__VA_ARGS__);
50
51 using http2_frame_dispatch = Http2Error (*)(Http2ConnectionState &, const Http2Frame &);
52
53 static const int buffer_size_index[HTTP2_FRAME_TYPE_MAX] = {
54 BUFFER_SIZE_INDEX_16K, // HTTP2_FRAME_TYPE_DATA
55 BUFFER_SIZE_INDEX_16K, // HTTP2_FRAME_TYPE_HEADERS
56 -1, // HTTP2_FRAME_TYPE_PRIORITY
57 -1, // HTTP2_FRAME_TYPE_RST_STREAM
58 -1, // HTTP2_FRAME_TYPE_SETTINGS
59 BUFFER_SIZE_INDEX_16K, // HTTP2_FRAME_TYPE_PUSH_PROMISE
60 -1, // HTTP2_FRAME_TYPE_PING
61 -1, // HTTP2_FRAME_TYPE_GOAWAY
62 -1, // HTTP2_FRAME_TYPE_WINDOW_UPDATE
63 BUFFER_SIZE_INDEX_16K, // HTTP2_FRAME_TYPE_CONTINUATION
64 };
65
66 inline static unsigned
read_rcv_buffer(char * buf,size_t bufsize,unsigned & nbytes,const Http2Frame & frame)67 read_rcv_buffer(char *buf, size_t bufsize, unsigned &nbytes, const Http2Frame &frame)
68 {
69 char *end;
70
71 if (frame.header().length - nbytes > bufsize) {
72 end = frame.reader()->memcpy(buf, bufsize, nbytes);
73 } else {
74 end = frame.reader()->memcpy(buf, frame.header().length - nbytes, nbytes);
75 }
76 nbytes += end - buf;
77
78 return end - buf;
79 }
80
81 static Http2Error
rcv_data_frame(Http2ConnectionState & cstate,const Http2Frame & frame)82 rcv_data_frame(Http2ConnectionState &cstate, const Http2Frame &frame)
83 {
84 unsigned nbytes = 0;
85 Http2StreamId id = frame.header().streamid;
86 uint8_t pad_length = 0;
87 const uint32_t payload_length = frame.header().length;
88
89 Http2StreamDebug(cstate.ua_session, id, "Received DATA frame");
90
91 if (cstate.get_zombie_event()) {
92 Warning("Data frame for zombied session %" PRId64, cstate.ua_session->connection_id());
93 }
94
95 // If a DATA frame is received whose stream identifier field is 0x0, the
96 // recipient MUST
97 // respond with a connection error of type PROTOCOL_ERROR.
98 if (!http2_is_client_streamid(id)) {
99 return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_CONNECTION, Http2ErrorCode::HTTP2_ERROR_PROTOCOL_ERROR,
100 "recv data bad frame client id");
101 }
102
103 Http2Stream *stream = cstate.find_stream(id);
104 if (stream == nullptr) {
105 if (cstate.is_valid_streamid(id)) {
106 // This error occurs fairly often, and is probably innocuous (SM initiates the shutdown)
107 return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_STREAM, Http2ErrorCode::HTTP2_ERROR_STREAM_CLOSED, nullptr);
108 } else {
109 return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_CONNECTION, Http2ErrorCode::HTTP2_ERROR_PROTOCOL_ERROR,
110 "recv data stream freed with invalid id");
111 }
112 }
113
114 // If a DATA frame is received whose stream is not in "open" or "half closed
115 // (local)" state,
116 // the recipient MUST respond with a stream error of type STREAM_CLOSED.
117 if (stream->get_state() != Http2StreamState::HTTP2_STREAM_STATE_OPEN &&
118 stream->get_state() != Http2StreamState::HTTP2_STREAM_STATE_HALF_CLOSED_LOCAL) {
119 return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_STREAM, Http2ErrorCode::HTTP2_ERROR_STREAM_CLOSED,
120 "recv data stream closed");
121 }
122
123 if (frame.header().flags & HTTP2_FLAGS_DATA_PADDED) {
124 frame.reader()->memcpy(&pad_length, HTTP2_DATA_PADLEN_LEN, nbytes);
125 nbytes += HTTP2_DATA_PADLEN_LEN;
126 if (pad_length > payload_length) {
127 // If the length of the padding is the length of the
128 // frame payload or greater, the recipient MUST treat this as a
129 // connection error of type PROTOCOL_ERROR.
130 return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_CONNECTION, Http2ErrorCode::HTTP2_ERROR_PROTOCOL_ERROR,
131 "recv data pad > payload");
132 }
133 }
134
135 stream->increment_data_length(payload_length - pad_length - nbytes);
136 if (frame.header().flags & HTTP2_FLAGS_DATA_END_STREAM) {
137 stream->recv_end_stream = true;
138 if (!stream->change_state(frame.header().type, frame.header().flags)) {
139 cstate.send_rst_stream_frame(id, Http2ErrorCode::HTTP2_ERROR_STREAM_CLOSED);
140 return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_NONE);
141 }
142 if (!stream->payload_length_is_valid()) {
143 return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_CONNECTION, Http2ErrorCode::HTTP2_ERROR_PROTOCOL_ERROR,
144 "recv data bad payload length");
145 }
146
147 // Pure END_STREAM
148 if (payload_length == 0) {
149 stream->signal_read_event(VC_EVENT_READ_COMPLETE);
150 return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_NONE);
151 }
152 } else {
153 // If payload length is 0 without END_STREAM flag, do nothing
154 if (payload_length == 0) {
155 return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_NONE);
156 }
157 }
158
159 // Check whether Window Size is acceptable
160 if (cstate.server_rwnd() < payload_length) {
161 return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_CONNECTION, Http2ErrorCode::HTTP2_ERROR_FLOW_CONTROL_ERROR,
162 "recv data cstate.server_rwnd < payload_length");
163 }
164 if (stream->server_rwnd() < payload_length) {
165 return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_STREAM, Http2ErrorCode::HTTP2_ERROR_FLOW_CONTROL_ERROR,
166 "recv data stream->server_rwnd < payload_length");
167 }
168
169 // Update Window size
170 cstate.decrement_server_rwnd(payload_length);
171 stream->decrement_server_rwnd(payload_length);
172
173 if (is_debug_tag_set("http2_con")) {
174 uint32_t rwnd = cstate.server_settings.get(HTTP2_SETTINGS_INITIAL_WINDOW_SIZE);
175 Http2StreamDebug(cstate.ua_session, id, "Received DATA frame: rwnd con=%zd/%" PRId32 " stream=%zd/%" PRId32,
176 cstate.server_rwnd(), rwnd, stream->server_rwnd(), rwnd);
177 }
178
179 const uint32_t unpadded_length = payload_length - pad_length;
180 MIOBuffer *writer = stream->read_vio_writer();
181 if (writer == nullptr) {
182 return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_STREAM, Http2ErrorCode::HTTP2_ERROR_INTERNAL_ERROR);
183 }
184
185 // If we call write() multiple times, we must keep the same reader, so we can
186 // update its offset via consume. Otherwise, we will read the same data on the
187 // second time through
188 IOBufferReader *myreader = frame.reader()->clone();
189 // Skip pad length field
190 if (frame.header().flags & HTTP2_FLAGS_DATA_PADDED) {
191 myreader->consume(HTTP2_DATA_PADLEN_LEN);
192 }
193
194 if (nbytes < unpadded_length) {
195 size_t read_len = BUFFER_SIZE_FOR_INDEX(buffer_size_index[HTTP2_FRAME_TYPE_DATA]);
196 if (nbytes + read_len > unpadded_length) {
197 read_len -= nbytes + read_len - unpadded_length;
198 }
199 unsigned int num_written = writer->write(myreader, read_len);
200 if (num_written != read_len) {
201 myreader->writer()->dealloc_reader(myreader);
202 return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_STREAM, Http2ErrorCode::HTTP2_ERROR_INTERNAL_ERROR);
203 }
204 myreader->consume(num_written);
205 }
206 myreader->writer()->dealloc_reader(myreader);
207
208 if (frame.header().flags & HTTP2_FLAGS_DATA_END_STREAM) {
209 // TODO: set total written size to read_vio.nbytes
210 stream->signal_read_event(VC_EVENT_READ_COMPLETE);
211 } else {
212 stream->signal_read_event(VC_EVENT_READ_READY);
213 }
214
215 return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_NONE);
216 }
217
218 /*
219 * [RFC 7540] 6.2 HEADERS Frame
220 *
221 * NOTE: HEADERS Frame and CONTINUATION Frame
222 * 1. A HEADERS frame with the END_STREAM flag set can be followed by
223 * CONTINUATION frames on the same stream.
224 * 2. A HEADERS frame without the END_HEADERS flag set MUST be followed by a
225 * CONTINUATION frame
226 */
227 static Http2Error
rcv_headers_frame(Http2ConnectionState & cstate,const Http2Frame & frame)228 rcv_headers_frame(Http2ConnectionState &cstate, const Http2Frame &frame)
229 {
230 const Http2StreamId stream_id = frame.header().streamid;
231 const uint32_t payload_length = frame.header().length;
232
233 Http2StreamDebug(cstate.ua_session, stream_id, "Received HEADERS frame");
234
235 if (!http2_is_client_streamid(stream_id)) {
236 return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_CONNECTION, Http2ErrorCode::HTTP2_ERROR_PROTOCOL_ERROR,
237 "recv headers bad client id");
238 }
239
240 Http2Stream *stream = nullptr;
241 bool new_stream = false;
242
243 if (cstate.is_valid_streamid(stream_id)) {
244 stream = cstate.find_stream(stream_id);
245 if (stream == nullptr) {
246 return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_CONNECTION, Http2ErrorCode::HTTP2_ERROR_STREAM_CLOSED,
247 "recv headers cannot find existing stream_id");
248 } else if (stream->get_state() == Http2StreamState::HTTP2_STREAM_STATE_CLOSED) {
249 return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_CONNECTION, Http2ErrorCode::HTTP2_ERROR_STREAM_CLOSED,
250 "recv_header to closed stream");
251 } else if (!stream->has_trailing_header()) {
252 return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_CONNECTION, Http2ErrorCode::HTTP2_ERROR_PROTOCOL_ERROR,
253 "stream not expecting trailer header");
254 }
255 } else {
256 // Create new stream
257 Http2Error error(Http2ErrorClass::HTTP2_ERROR_CLASS_NONE);
258 stream = cstate.create_stream(stream_id, error);
259 new_stream = true;
260 if (!stream) {
261 return error;
262 }
263 }
264
265 // Ignoring HEADERS frame on a closed stream. The HdrHeap has gone away and it will core.
266 if (stream->get_state() == Http2StreamState::HTTP2_STREAM_STATE_CLOSED) {
267 return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_NONE);
268 }
269
270 Http2HeadersParameter params;
271 uint32_t header_block_fragment_offset = 0;
272 uint32_t header_block_fragment_length = payload_length;
273
274 if (frame.header().flags & HTTP2_FLAGS_HEADERS_END_STREAM) {
275 stream->recv_end_stream = true;
276 }
277
278 // NOTE: Strip padding if exists
279 if (frame.header().flags & HTTP2_FLAGS_HEADERS_PADDED) {
280 uint8_t buf[HTTP2_HEADERS_PADLEN_LEN] = {0};
281 frame.reader()->memcpy(buf, HTTP2_HEADERS_PADLEN_LEN);
282
283 if (!http2_parse_headers_parameter(make_iovec(buf, HTTP2_HEADERS_PADLEN_LEN), params)) {
284 return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_CONNECTION, Http2ErrorCode::HTTP2_ERROR_PROTOCOL_ERROR,
285 "recv headers failed to parse");
286 }
287
288 // Payload length can't be smaller than the pad length
289 if ((params.pad_length + HTTP2_HEADERS_PADLEN_LEN) > header_block_fragment_length) {
290 return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_CONNECTION, Http2ErrorCode::HTTP2_ERROR_PROTOCOL_ERROR,
291 "recv headers pad > payload length");
292 }
293
294 header_block_fragment_offset += HTTP2_HEADERS_PADLEN_LEN;
295 header_block_fragment_length -= (HTTP2_HEADERS_PADLEN_LEN + params.pad_length);
296 }
297
298 // NOTE: Parse priority parameters if exists
299 if (frame.header().flags & HTTP2_FLAGS_HEADERS_PRIORITY) {
300 uint8_t buf[HTTP2_PRIORITY_LEN] = {0};
301
302 frame.reader()->memcpy(buf, HTTP2_PRIORITY_LEN, header_block_fragment_offset);
303 if (!http2_parse_priority_parameter(make_iovec(buf, HTTP2_PRIORITY_LEN), params.priority)) {
304 return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_CONNECTION, Http2ErrorCode::HTTP2_ERROR_PROTOCOL_ERROR,
305 "recv headers priority parameters failed parse");
306 }
307 // Protocol error if the stream depends on itself
308 if (stream_id == params.priority.stream_dependency) {
309 return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_STREAM, Http2ErrorCode::HTTP2_ERROR_PROTOCOL_ERROR,
310 "recv headers self dependency");
311 }
312
313 // Payload length can't be smaller than the priority length
314 if (HTTP2_PRIORITY_LEN > header_block_fragment_length) {
315 return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_CONNECTION, Http2ErrorCode::HTTP2_ERROR_PROTOCOL_ERROR,
316 "recv priority length > payload length");
317 }
318
319 header_block_fragment_offset += HTTP2_PRIORITY_LEN;
320 header_block_fragment_length -= HTTP2_PRIORITY_LEN;
321 }
322
323 if (new_stream && Http2::stream_priority_enabled) {
324 Http2DependencyTree::Node *node = cstate.dependency_tree->find(stream_id);
325 if (node != nullptr) {
326 stream->priority_node = node;
327 node->t = stream;
328 } else {
329 Http2StreamDebug(cstate.ua_session, stream_id, "HEADER PRIORITY - dep: %d, weight: %d, excl: %d, tree size: %d",
330 params.priority.stream_dependency, params.priority.weight, params.priority.exclusive_flag,
331 cstate.dependency_tree->size());
332
333 stream->priority_node = cstate.dependency_tree->add(params.priority.stream_dependency, stream_id, params.priority.weight,
334 params.priority.exclusive_flag, stream);
335 }
336 }
337
338 stream->header_blocks_length = header_block_fragment_length;
339
340 // ATS advertises SETTINGS_MAX_HEADER_LIST_SIZE as a limit of total header blocks length. (Details in [RFC 7560] 10.5.1.)
341 // Make it double to relax the limit in cases of 1) HPACK is used naively, or 2) Huffman Encoding generates large header blocks.
342 // The total "decoded" header length is strictly checked by hpack_decode_header_block().
343 if (stream->header_blocks_length > std::max(Http2::max_header_list_size, Http2::max_header_list_size * 2)) {
344 return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_CONNECTION, Http2ErrorCode::HTTP2_ERROR_ENHANCE_YOUR_CALM,
345 "header blocks too large");
346 }
347
348 stream->header_blocks = static_cast<uint8_t *>(ats_malloc(header_block_fragment_length));
349 frame.reader()->memcpy(stream->header_blocks, header_block_fragment_length, header_block_fragment_offset);
350
351 if (frame.header().flags & HTTP2_FLAGS_HEADERS_END_HEADERS) {
352 // NOTE: If there are END_HEADERS flag, decode stored Header Blocks.
353 if (!stream->change_state(HTTP2_FRAME_TYPE_HEADERS, frame.header().flags) && stream->has_trailing_header() == false) {
354 return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_CONNECTION, Http2ErrorCode::HTTP2_ERROR_PROTOCOL_ERROR,
355 "recv headers end headers and not trailing header");
356 }
357
358 bool empty_request = false;
359 if (stream->has_trailing_header()) {
360 if (!(frame.header().flags & HTTP2_FLAGS_HEADERS_END_STREAM)) {
361 return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_STREAM, Http2ErrorCode::HTTP2_ERROR_PROTOCOL_ERROR,
362 "recv headers tailing header without endstream");
363 }
364 // If the flag has already been set before decoding header blocks, this is the trailing header.
365 // Set a flag to avoid initializing fetcher for now.
366 // Decoding header blocks is still needed to maintain a HPACK dynamic table.
367 // TODO: TS-3812
368 empty_request = true;
369 }
370
371 stream->mark_milestone(Http2StreamMilestone::START_DECODE_HEADERS);
372 Http2ErrorCode result =
373 stream->decode_header_blocks(*cstate.local_hpack_handle, cstate.server_settings.get(HTTP2_SETTINGS_HEADER_TABLE_SIZE));
374
375 if (result != Http2ErrorCode::HTTP2_ERROR_NO_ERROR) {
376 if (result == Http2ErrorCode::HTTP2_ERROR_COMPRESSION_ERROR) {
377 return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_CONNECTION, Http2ErrorCode::HTTP2_ERROR_COMPRESSION_ERROR,
378 "recv headers compression error");
379 } else if (result == Http2ErrorCode::HTTP2_ERROR_ENHANCE_YOUR_CALM) {
380 return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_CONNECTION, Http2ErrorCode::HTTP2_ERROR_ENHANCE_YOUR_CALM,
381 "recv headers enhance your calm");
382 } else {
383 return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_STREAM, Http2ErrorCode::HTTP2_ERROR_PROTOCOL_ERROR,
384 "recv headers malformed request");
385 }
386 }
387
388 // Set up the State Machine
389 if (!empty_request) {
390 SCOPED_MUTEX_LOCK(stream_lock, stream->mutex, this_ethread());
391 stream->mark_milestone(Http2StreamMilestone::START_TXN);
392 stream->new_transaction(frame.is_from_early_data());
393 // Send request header to SM
394 stream->send_request(cstate);
395 } else {
396 // Signal VC_EVENT_READ_COMPLETE because received trailing header fields with END_STREAM flag
397 stream->signal_read_event(VC_EVENT_READ_COMPLETE);
398 }
399 } else {
400 // NOTE: Expect CONTINUATION Frame. Do NOT change state of stream or decode
401 // Header Blocks.
402 Http2StreamDebug(cstate.ua_session, stream_id, "No END_HEADERS flag, expecting CONTINUATION frame");
403 cstate.set_continued_stream_id(stream_id);
404 }
405
406 return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_NONE);
407 }
408
409 /*
410 * [RFC 7540] 6.3 PRIORITY
411 *
412 */
413 static Http2Error
rcv_priority_frame(Http2ConnectionState & cstate,const Http2Frame & frame)414 rcv_priority_frame(Http2ConnectionState &cstate, const Http2Frame &frame)
415 {
416 const Http2StreamId stream_id = frame.header().streamid;
417 const uint32_t payload_length = frame.header().length;
418
419 Http2StreamDebug(cstate.ua_session, stream_id, "Received PRIORITY frame");
420
421 if (cstate.get_zombie_event()) {
422 Warning("Priority frame for zombied session %" PRId64, cstate.ua_session->connection_id());
423 }
424
425 // If a PRIORITY frame is received with a stream identifier of 0x0, the
426 // recipient MUST respond with a connection error of type PROTOCOL_ERROR.
427 if (stream_id == 0) {
428 return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_CONNECTION, Http2ErrorCode::HTTP2_ERROR_PROTOCOL_ERROR,
429 "priority 0 stream_id");
430 }
431
432 // A PRIORITY frame with a length other than 5 octets MUST be treated as
433 // a stream error (Section 5.4.2) of type FRAME_SIZE_ERROR.
434 if (payload_length != HTTP2_PRIORITY_LEN) {
435 return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_STREAM, Http2ErrorCode::HTTP2_ERROR_FRAME_SIZE_ERROR,
436 "priority bad length");
437 }
438
439 uint8_t buf[HTTP2_PRIORITY_LEN] = {0};
440 frame.reader()->memcpy(buf, HTTP2_PRIORITY_LEN, 0);
441
442 Http2Priority priority;
443 if (!http2_parse_priority_parameter(make_iovec(buf, HTTP2_PRIORITY_LEN), priority)) {
444 return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_CONNECTION, Http2ErrorCode::HTTP2_ERROR_PROTOCOL_ERROR,
445 "priority parse error");
446 }
447
448 // A stream cannot depend on itself. An endpoint MUST treat this as a stream error of type PROTOCOL_ERROR.
449 if (stream_id == priority.stream_dependency) {
450 return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_STREAM, Http2ErrorCode::HTTP2_ERROR_PROTOCOL_ERROR,
451 "PRIORITY frame depends on itself");
452 }
453
454 if (!Http2::stream_priority_enabled) {
455 return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_NONE);
456 }
457
458 // Update PRIORITY frame count per minute
459 cstate.increment_received_priority_frame_count();
460 // Close this connection if its priority frame count received exceeds a limit
461 if (Http2::max_priority_frames_per_minute != 0 &&
462 cstate.get_received_priority_frame_count() > Http2::max_priority_frames_per_minute) {
463 HTTP2_INCREMENT_THREAD_DYN_STAT(HTTP2_STAT_MAX_PRIORITY_FRAMES_PER_MINUTE_EXCEEDED, this_ethread());
464 Http2StreamDebug(cstate.ua_session, stream_id,
465 "Observed too frequent priority changes: %u priority changes within a last minute",
466 cstate.get_received_priority_frame_count());
467 return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_CONNECTION, Http2ErrorCode::HTTP2_ERROR_ENHANCE_YOUR_CALM,
468 "recv priority too frequent priority changes");
469 }
470
471 Http2StreamDebug(cstate.ua_session, stream_id, "PRIORITY - dep: %d, weight: %d, excl: %d, tree size: %d",
472 priority.stream_dependency, priority.weight, priority.exclusive_flag, cstate.dependency_tree->size());
473
474 Http2DependencyTree::Node *node = cstate.dependency_tree->find(stream_id);
475
476 if (node != nullptr) {
477 // [RFC 7540] 5.3.3 Reprioritization
478 Http2StreamDebug(cstate.ua_session, stream_id, "Reprioritize");
479 cstate.dependency_tree->reprioritize(node, priority.stream_dependency, priority.exclusive_flag);
480 if (is_debug_tag_set("http2_priority")) {
481 std::stringstream output;
482 cstate.dependency_tree->dump_tree(output);
483 Debug("http2_priority", "[%" PRId64 "] reprioritize %s", cstate.ua_session->connection_id(), output.str().c_str());
484 }
485 } else {
486 // PRIORITY frame is received before HEADERS frame.
487
488 // Restrict number of inactive node in dependency tree smaller than max_concurrent_streams.
489 // Current number of inactive node is size of tree minus active node count.
490 if (Http2::max_concurrent_streams_in > cstate.dependency_tree->size() - cstate.get_client_stream_count() + 1) {
491 cstate.dependency_tree->add(priority.stream_dependency, stream_id, priority.weight, priority.exclusive_flag, nullptr);
492 }
493 }
494
495 return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_NONE);
496 }
497
498 static Http2Error
rcv_rst_stream_frame(Http2ConnectionState & cstate,const Http2Frame & frame)499 rcv_rst_stream_frame(Http2ConnectionState &cstate, const Http2Frame &frame)
500 {
501 Http2RstStream rst_stream;
502 char buf[HTTP2_RST_STREAM_LEN];
503 char *end;
504 const Http2StreamId stream_id = frame.header().streamid;
505
506 Http2StreamDebug(cstate.ua_session, frame.header().streamid, "Received RST_STREAM frame");
507
508 // RST_STREAM frames MUST be associated with a stream. If a RST_STREAM
509 // frame is received with a stream identifier of 0x0, the recipient MUST
510 // treat this as a connection error (Section 5.4.1) of type
511 // PROTOCOL_ERROR.
512 if (stream_id == 0) {
513 return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_CONNECTION, Http2ErrorCode::HTTP2_ERROR_PROTOCOL_ERROR,
514 "reset access stream with invalid id");
515 }
516
517 Http2Stream *stream = cstate.find_stream(stream_id);
518 if (stream == nullptr) {
519 if (cstate.is_valid_streamid(stream_id)) {
520 return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_NONE);
521 } else {
522 return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_CONNECTION, Http2ErrorCode::HTTP2_ERROR_PROTOCOL_ERROR,
523 "reset frame bad id stream not found");
524 }
525 }
526
527 // A RST_STREAM frame with a length other than 4 octets MUST be treated
528 // as a connection error (Section 5.4.1) of type FRAME_SIZE_ERROR.
529 if (frame.header().length != HTTP2_RST_STREAM_LEN) {
530 return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_CONNECTION, Http2ErrorCode::HTTP2_ERROR_FRAME_SIZE_ERROR,
531 "reset frame wrong length");
532 }
533
534 if (stream == nullptr || !stream->change_state(frame.header().type, frame.header().flags)) {
535 // If a RST_STREAM frame identifying an idle stream is received, the
536 // recipient MUST treat this as a connection error of type PROTOCOL_ERROR.
537 return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_CONNECTION, Http2ErrorCode::HTTP2_ERROR_PROTOCOL_ERROR,
538 "reset missing stream or bad stream state");
539 }
540
541 end = frame.reader()->memcpy(buf, sizeof(buf), 0);
542
543 if (!http2_parse_rst_stream(make_iovec(buf, end - buf), rst_stream)) {
544 return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_CONNECTION, Http2ErrorCode::HTTP2_ERROR_PROTOCOL_ERROR,
545 "reset failed to parse");
546 }
547
548 if (stream != nullptr) {
549 Http2StreamDebug(cstate.ua_session, stream_id, "RST_STREAM: Error Code: %u", rst_stream.error_code);
550
551 stream->set_rx_error_code({ProxyErrorClass::TXN, static_cast<uint32_t>(rst_stream.error_code)});
552 stream->initiating_close();
553 }
554
555 return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_NONE);
556 }
557
558 static Http2Error
rcv_settings_frame(Http2ConnectionState & cstate,const Http2Frame & frame)559 rcv_settings_frame(Http2ConnectionState &cstate, const Http2Frame &frame)
560 {
561 Http2SettingsParameter param;
562 char buf[HTTP2_SETTINGS_PARAMETER_LEN];
563 unsigned nbytes = 0;
564 const Http2StreamId stream_id = frame.header().streamid;
565
566 Http2StreamDebug(cstate.ua_session, stream_id, "Received SETTINGS frame");
567
568 if (cstate.get_zombie_event()) {
569 Warning("Setting frame for zombied session %" PRId64, cstate.ua_session->connection_id());
570 }
571
572 // Update SETTIGNS frame count per minute
573 cstate.increment_received_settings_frame_count();
574 // Close this connection if its SETTINGS frame count exceeds a limit
575 if (cstate.get_received_settings_frame_count() > Http2::max_settings_frames_per_minute) {
576 HTTP2_INCREMENT_THREAD_DYN_STAT(HTTP2_STAT_MAX_SETTINGS_FRAMES_PER_MINUTE_EXCEEDED, this_ethread());
577 Http2StreamDebug(cstate.ua_session, stream_id, "Observed too frequent SETTINGS frames: %u frames within a last minute",
578 cstate.get_received_settings_frame_count());
579 return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_CONNECTION, Http2ErrorCode::HTTP2_ERROR_ENHANCE_YOUR_CALM,
580 "recv settings too frequent SETTINGS frames");
581 }
582
583 // [RFC 7540] 6.5. The stream identifier for a SETTINGS frame MUST be zero.
584 // If an endpoint receives a SETTINGS frame whose stream identifier field is
585 // anything other than 0x0, the endpoint MUST respond with a connection
586 // error (Section 5.4.1) of type PROTOCOL_ERROR.
587 if (stream_id != 0) {
588 return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_CONNECTION, Http2ErrorCode::HTTP2_ERROR_PROTOCOL_ERROR,
589 "recv settings stream not 0");
590 }
591
592 // [RFC 7540] 6.5. Receipt of a SETTINGS frame with the ACK flag set and a
593 // length field value other than 0 MUST be treated as a connection
594 // error of type FRAME_SIZE_ERROR.
595 if (frame.header().flags & HTTP2_FLAGS_SETTINGS_ACK) {
596 if (frame.header().length == 0) {
597 return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_NONE);
598 } else {
599 return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_CONNECTION, Http2ErrorCode::HTTP2_ERROR_FRAME_SIZE_ERROR,
600 "recv settings ACK header length not 0");
601 }
602 }
603
604 // A SETTINGS frame with a length other than a multiple of 6 octets MUST
605 // be treated as a connection error (Section 5.4.1) of type
606 // FRAME_SIZE_ERROR.
607 if (frame.header().length % 6 != 0) {
608 return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_CONNECTION, Http2ErrorCode::HTTP2_ERROR_FRAME_SIZE_ERROR,
609 "recv settings header wrong length");
610 }
611
612 uint32_t n_settings = 0;
613 while (nbytes < frame.header().length) {
614 if (n_settings >= Http2::max_settings_per_frame) {
615 HTTP2_INCREMENT_THREAD_DYN_STAT(HTTP2_STAT_MAX_SETTINGS_PER_FRAME_EXCEEDED, this_ethread());
616 Http2StreamDebug(cstate.ua_session, stream_id, "Observed too many settings in a frame");
617 return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_CONNECTION, Http2ErrorCode::HTTP2_ERROR_ENHANCE_YOUR_CALM,
618 "recv settings too many settings in a frame");
619 }
620
621 unsigned read_bytes = read_rcv_buffer(buf, sizeof(buf), nbytes, frame);
622
623 if (!http2_parse_settings_parameter(make_iovec(buf, read_bytes), param)) {
624 return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_CONNECTION, Http2ErrorCode::HTTP2_ERROR_PROTOCOL_ERROR,
625 "recv settings parse failed");
626 }
627
628 if (!http2_settings_parameter_is_valid(param)) {
629 if (param.id == HTTP2_SETTINGS_INITIAL_WINDOW_SIZE) {
630 return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_CONNECTION, Http2ErrorCode::HTTP2_ERROR_FLOW_CONTROL_ERROR,
631 "recv settings bad initial window size");
632 } else {
633 return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_CONNECTION, Http2ErrorCode::HTTP2_ERROR_PROTOCOL_ERROR,
634 "recv settings bad param");
635 }
636 }
637
638 Http2StreamDebug(cstate.ua_session, stream_id, " %s : %u", Http2DebugNames::get_settings_param_name(param.id), param.value);
639
640 // [RFC 7540] 6.9.2. When the value of SETTINGS_INITIAL_WINDOW_SIZE
641 // changes, a receiver MUST adjust the size of all stream flow control
642 // windows that it maintains by the difference between the new value and
643 // the old value.
644 if (param.id == HTTP2_SETTINGS_INITIAL_WINDOW_SIZE) {
645 cstate.update_initial_rwnd(param.value);
646 }
647
648 cstate.client_settings.set(static_cast<Http2SettingsIdentifier>(param.id), param.value);
649 ++n_settings;
650 }
651
652 // Update settings count per minute
653 cstate.increment_received_settings_count(n_settings);
654 // Close this connection if its settings count received exceeds a limit
655 if (cstate.get_received_settings_count() > Http2::max_settings_per_minute) {
656 HTTP2_INCREMENT_THREAD_DYN_STAT(HTTP2_STAT_MAX_SETTINGS_PER_MINUTE_EXCEEDED, this_ethread());
657 Http2StreamDebug(cstate.ua_session, stream_id, "Observed too frequent setting changes: %u settings within a last minute",
658 cstate.get_received_settings_count());
659 return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_CONNECTION, Http2ErrorCode::HTTP2_ERROR_ENHANCE_YOUR_CALM,
660 "recv settings too frequent setting changes");
661 }
662
663 // [RFC 7540] 6.5. Once all values have been applied, the recipient MUST
664 // immediately emit a SETTINGS frame with the ACK flag set.
665 Http2SettingsFrame ack_frame(0, HTTP2_FLAGS_SETTINGS_ACK);
666 cstate.ua_session->xmit(ack_frame);
667
668 return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_NONE);
669 }
670
671 static Http2Error
rcv_push_promise_frame(Http2ConnectionState & cstate,const Http2Frame & frame)672 rcv_push_promise_frame(Http2ConnectionState &cstate, const Http2Frame &frame)
673 {
674 Http2StreamDebug(cstate.ua_session, frame.header().streamid, "Received PUSH_PROMISE frame");
675
676 // [RFC 7540] 8.2. A client cannot push. Thus, servers MUST treat the receipt of a
677 // PUSH_PROMISE frame as a connection error of type PROTOCOL_ERROR.
678 return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_CONNECTION, Http2ErrorCode::HTTP2_ERROR_PROTOCOL_ERROR,
679 "promise not allowed");
680 }
681
682 static Http2Error
rcv_ping_frame(Http2ConnectionState & cstate,const Http2Frame & frame)683 rcv_ping_frame(Http2ConnectionState &cstate, const Http2Frame &frame)
684 {
685 uint8_t opaque_data[HTTP2_PING_LEN];
686 const Http2StreamId stream_id = frame.header().streamid;
687
688 Http2StreamDebug(cstate.ua_session, stream_id, "Received PING frame");
689
690 cstate.schedule_zombie_event();
691
692 // If a PING frame is received with a stream identifier field value other
693 // than 0x0, the recipient MUST respond with a connection error of type
694 // PROTOCOL_ERROR.
695 if (stream_id != 0x0) {
696 return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_CONNECTION, Http2ErrorCode::HTTP2_ERROR_PROTOCOL_ERROR, "ping id not 0");
697 }
698
699 // Receipt of a PING frame with a length field value other than 8 MUST
700 // be treated as a connection error (Section 5.4.1) of type FRAME_SIZE_ERROR.
701 if (frame.header().length != HTTP2_PING_LEN) {
702 return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_CONNECTION, Http2ErrorCode::HTTP2_ERROR_FRAME_SIZE_ERROR,
703 "ping bad length");
704 }
705
706 // Update PING frame count per minute
707 cstate.increment_received_ping_frame_count();
708 // Close this connection if its ping count received exceeds a limit
709 if (cstate.get_received_ping_frame_count() > Http2::max_ping_frames_per_minute) {
710 HTTP2_INCREMENT_THREAD_DYN_STAT(HTTP2_STAT_MAX_PING_FRAMES_PER_MINUTE_EXCEEDED, this_ethread());
711 Http2StreamDebug(cstate.ua_session, stream_id, "Observed too frequent PING frames: %u PING frames within a last minute",
712 cstate.get_received_ping_frame_count());
713 return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_CONNECTION, Http2ErrorCode::HTTP2_ERROR_ENHANCE_YOUR_CALM,
714 "recv ping too frequent PING frame");
715 }
716
717 // An endpoint MUST NOT respond to PING frames containing this flag.
718 if (frame.header().flags & HTTP2_FLAGS_PING_ACK) {
719 return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_NONE);
720 }
721
722 frame.reader()->memcpy(opaque_data, HTTP2_PING_LEN, 0);
723
724 // ACK (0x1): An endpoint MUST set this flag in PING responses.
725 cstate.send_ping_frame(stream_id, HTTP2_FLAGS_PING_ACK, opaque_data);
726
727 return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_NONE);
728 }
729
730 static Http2Error
rcv_goaway_frame(Http2ConnectionState & cstate,const Http2Frame & frame)731 rcv_goaway_frame(Http2ConnectionState &cstate, const Http2Frame &frame)
732 {
733 Http2Goaway goaway;
734 char buf[HTTP2_GOAWAY_LEN];
735 unsigned nbytes = 0;
736 const Http2StreamId stream_id = frame.header().streamid;
737
738 Http2StreamDebug(cstate.ua_session, stream_id, "Received GOAWAY frame");
739
740 // An endpoint MUST treat a GOAWAY frame with a stream identifier other
741 // than 0x0 as a connection error of type PROTOCOL_ERROR.
742 if (stream_id != 0x0) {
743 return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_CONNECTION, Http2ErrorCode::HTTP2_ERROR_PROTOCOL_ERROR,
744 "goaway id non-zero");
745 }
746
747 while (nbytes < frame.header().length) {
748 unsigned read_bytes = read_rcv_buffer(buf, sizeof(buf), nbytes, frame);
749
750 if (!http2_parse_goaway(make_iovec(buf, read_bytes), goaway)) {
751 return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_CONNECTION, Http2ErrorCode::HTTP2_ERROR_PROTOCOL_ERROR,
752 "goaway failed parse");
753 }
754 }
755
756 Http2StreamDebug(cstate.ua_session, stream_id, "GOAWAY: last stream id=%d, error code=%d", goaway.last_streamid,
757 static_cast<int>(goaway.error_code));
758
759 cstate.rx_error_code = {ProxyErrorClass::SSN, static_cast<uint32_t>(goaway.error_code)};
760 cstate.handleEvent(HTTP2_SESSION_EVENT_FINI, nullptr);
761
762 return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_NONE);
763 }
764
765 static Http2Error
rcv_window_update_frame(Http2ConnectionState & cstate,const Http2Frame & frame)766 rcv_window_update_frame(Http2ConnectionState &cstate, const Http2Frame &frame)
767 {
768 char buf[HTTP2_WINDOW_UPDATE_LEN];
769 uint32_t size;
770 const Http2StreamId stream_id = frame.header().streamid;
771
772 // A WINDOW_UPDATE frame with a length other than 4 octets MUST be
773 // treated as a connection error of type FRAME_SIZE_ERROR.
774 if (frame.header().length != HTTP2_WINDOW_UPDATE_LEN) {
775 Http2StreamDebug(cstate.ua_session, stream_id, "Received WINDOW_UPDATE frame - length incorrect");
776 return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_CONNECTION, Http2ErrorCode::HTTP2_ERROR_FRAME_SIZE_ERROR,
777 "window update bad length");
778 }
779
780 frame.reader()->memcpy(buf, sizeof(buf), 0);
781 http2_parse_window_update(make_iovec(buf, sizeof(buf)), size);
782
783 // A receiver MUST treat the receipt of a WINDOW_UPDATE frame with a flow
784 // control window increment of 0 as a connection error of type PROTOCOL_ERROR;
785 if (size == 0) {
786 if (stream_id == 0) {
787 return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_CONNECTION, Http2ErrorCode::HTTP2_ERROR_PROTOCOL_ERROR,
788 "window update length=0 and id=0");
789 } else {
790 return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_STREAM, Http2ErrorCode::HTTP2_ERROR_PROTOCOL_ERROR,
791 "window update length=0");
792 }
793 }
794
795 if (stream_id == 0) {
796 // Connection level window update
797 Http2StreamDebug(cstate.ua_session, stream_id, "Received WINDOW_UPDATE frame - updated to: %zd delta: %u",
798 (cstate.client_rwnd() + size), size);
799
800 // A sender MUST NOT allow a flow-control window to exceed 2^31-1
801 // octets. If a sender receives a WINDOW_UPDATE that causes a flow-
802 // control window to exceed this maximum, it MUST terminate either the
803 // stream or the connection, as appropriate. For streams, the sender
804 // sends a RST_STREAM with an error code of FLOW_CONTROL_ERROR; for the
805 // connection, a GOAWAY frame with an error code of FLOW_CONTROL_ERROR
806 // is sent.
807 if (size > HTTP2_MAX_WINDOW_SIZE - cstate.client_rwnd()) {
808 return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_CONNECTION, Http2ErrorCode::HTTP2_ERROR_FLOW_CONTROL_ERROR,
809 "window update too big");
810 }
811
812 auto error = cstate.increment_client_rwnd(size);
813 if (error != Http2ErrorCode::HTTP2_ERROR_NO_ERROR) {
814 return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_CONNECTION, error);
815 }
816
817 cstate.restart_streams();
818 } else {
819 // Stream level window update
820 Http2Stream *stream = cstate.find_stream(stream_id);
821
822 if (stream == nullptr) {
823 if (cstate.is_valid_streamid(stream_id)) {
824 return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_NONE);
825 } else {
826 return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_CONNECTION, Http2ErrorCode::HTTP2_ERROR_PROTOCOL_ERROR,
827 "window update stream invalid id");
828 }
829 }
830
831 Http2StreamDebug(cstate.ua_session, stream_id, "Received WINDOW_UPDATE frame - updated to: %zd delta: %u",
832 (stream->client_rwnd() + size), size);
833
834 // A sender MUST NOT allow a flow-control window to exceed 2^31-1
835 // octets. If a sender receives a WINDOW_UPDATE that causes a flow-
836 // control window to exceed this maximum, it MUST terminate either the
837 // stream or the connection, as appropriate. For streams, the sender
838 // sends a RST_STREAM with an error code of FLOW_CONTROL_ERROR; for the
839 // connection, a GOAWAY frame with an error code of FLOW_CONTROL_ERROR
840 // is sent.
841 if (size > HTTP2_MAX_WINDOW_SIZE - stream->client_rwnd()) {
842 return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_STREAM, Http2ErrorCode::HTTP2_ERROR_FLOW_CONTROL_ERROR,
843 "window update too big 2");
844 }
845
846 auto error = stream->increment_client_rwnd(size);
847 if (error != Http2ErrorCode::HTTP2_ERROR_NO_ERROR) {
848 return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_STREAM, error);
849 }
850
851 ssize_t wnd = std::min(cstate.client_rwnd(), stream->client_rwnd());
852 if (!stream->is_closed() && stream->get_state() == Http2StreamState::HTTP2_STREAM_STATE_HALF_CLOSED_REMOTE && wnd > 0) {
853 SCOPED_MUTEX_LOCK(lock, stream->mutex, this_ethread());
854 stream->restart_sending();
855 }
856 }
857
858 return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_NONE);
859 }
860
861 /*
862 * [RFC 7540] 6.10 CONTINUATION
863 *
864 * NOTE: Logically, the CONTINUATION frames are part of the HEADERS frame. ([RFC
865 *7540] 6.2 HEADERS)
866 *
867 */
868 static Http2Error
rcv_continuation_frame(Http2ConnectionState & cstate,const Http2Frame & frame)869 rcv_continuation_frame(Http2ConnectionState &cstate, const Http2Frame &frame)
870 {
871 const Http2StreamId stream_id = frame.header().streamid;
872 const uint32_t payload_length = frame.header().length;
873
874 Http2StreamDebug(cstate.ua_session, stream_id, "Received CONTINUATION frame");
875
876 if (!http2_is_client_streamid(stream_id)) {
877 return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_CONNECTION, Http2ErrorCode::HTTP2_ERROR_PROTOCOL_ERROR,
878 "continuation bad client id");
879 }
880
881 // Find opened stream
882 // CONTINUATION frames MUST be associated with a stream. If a
883 // CONTINUATION frame is received whose stream identifier field is 0x0,
884 // the recipient MUST respond with a connection error ([RFC 7540] Section
885 // 5.4.1) of type PROTOCOL_ERROR.
886 Http2Stream *stream = cstate.find_stream(stream_id);
887 if (stream == nullptr) {
888 if (cstate.is_valid_streamid(stream_id)) {
889 return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_CONNECTION, Http2ErrorCode::HTTP2_ERROR_STREAM_CLOSED,
890 "continuation stream freed with valid id");
891 } else {
892 return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_CONNECTION, Http2ErrorCode::HTTP2_ERROR_PROTOCOL_ERROR,
893 "continuation stream freed with invalid id");
894 }
895 } else {
896 switch (stream->get_state()) {
897 case Http2StreamState::HTTP2_STREAM_STATE_HALF_CLOSED_REMOTE:
898 return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_CONNECTION, Http2ErrorCode::HTTP2_ERROR_STREAM_CLOSED,
899 "continuation half close remote");
900 case Http2StreamState::HTTP2_STREAM_STATE_IDLE:
901 break;
902 default:
903 return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_CONNECTION, Http2ErrorCode::HTTP2_ERROR_PROTOCOL_ERROR,
904 "continuation bad state");
905 }
906 }
907
908 uint32_t header_blocks_offset = stream->header_blocks_length;
909 stream->header_blocks_length += payload_length;
910
911 // ATS advertises SETTINGS_MAX_HEADER_LIST_SIZE as a limit of total header blocks length. (Details in [RFC 7560] 10.5.1.)
912 // Make it double to relax the limit in cases of 1) HPACK is used naively, or 2) Huffman Encoding generates large header blocks.
913 // The total "decoded" header length is strictly checked by hpack_decode_header_block().
914 if (stream->header_blocks_length > std::max(Http2::max_header_list_size, Http2::max_header_list_size * 2)) {
915 return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_CONNECTION, Http2ErrorCode::HTTP2_ERROR_ENHANCE_YOUR_CALM,
916 "header blocks too large");
917 }
918
919 stream->header_blocks = static_cast<uint8_t *>(ats_realloc(stream->header_blocks, stream->header_blocks_length));
920 frame.reader()->memcpy(stream->header_blocks + header_blocks_offset, payload_length);
921
922 if (frame.header().flags & HTTP2_FLAGS_HEADERS_END_HEADERS) {
923 // NOTE: If there are END_HEADERS flag, decode stored Header Blocks.
924 cstate.clear_continued_stream_id();
925
926 if (!stream->change_state(HTTP2_FRAME_TYPE_CONTINUATION, frame.header().flags)) {
927 return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_CONNECTION, Http2ErrorCode::HTTP2_ERROR_PROTOCOL_ERROR,
928 "continuation no state change");
929 }
930
931 Http2ErrorCode result =
932 stream->decode_header_blocks(*cstate.local_hpack_handle, cstate.server_settings.get(HTTP2_SETTINGS_HEADER_TABLE_SIZE));
933
934 if (result != Http2ErrorCode::HTTP2_ERROR_NO_ERROR) {
935 if (result == Http2ErrorCode::HTTP2_ERROR_COMPRESSION_ERROR) {
936 return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_CONNECTION, Http2ErrorCode::HTTP2_ERROR_COMPRESSION_ERROR,
937 "continuation compression error");
938 } else if (result == Http2ErrorCode::HTTP2_ERROR_ENHANCE_YOUR_CALM) {
939 return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_CONNECTION, Http2ErrorCode::HTTP2_ERROR_ENHANCE_YOUR_CALM,
940 "continuation enhance your calm");
941 } else {
942 return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_CONNECTION, Http2ErrorCode::HTTP2_ERROR_PROTOCOL_ERROR,
943 "continuation malformed request");
944 }
945 }
946
947 // Set up the State Machine
948 SCOPED_MUTEX_LOCK(stream_lock, stream->mutex, this_ethread());
949 stream->mark_milestone(Http2StreamMilestone::START_TXN);
950 // This should be fine, need to verify whether we need to replace this with the
951 // "from_early_data" flag from the associated HEADERS frame.
952 stream->new_transaction(frame.is_from_early_data());
953 // Send request header to SM
954 stream->send_request(cstate);
955 } else {
956 // NOTE: Expect another CONTINUATION Frame. Do nothing.
957 Http2StreamDebug(cstate.ua_session, stream_id, "No END_HEADERS flag, expecting CONTINUATION frame");
958 }
959
960 return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_NONE);
961 }
962
963 static const http2_frame_dispatch frame_handlers[HTTP2_FRAME_TYPE_MAX] = {
964 rcv_data_frame, // HTTP2_FRAME_TYPE_DATA
965 rcv_headers_frame, // HTTP2_FRAME_TYPE_HEADERS
966 rcv_priority_frame, // HTTP2_FRAME_TYPE_PRIORITY
967 rcv_rst_stream_frame, // HTTP2_FRAME_TYPE_RST_STREAM
968 rcv_settings_frame, // HTTP2_FRAME_TYPE_SETTINGS
969 rcv_push_promise_frame, // HTTP2_FRAME_TYPE_PUSH_PROMISE
970 rcv_ping_frame, // HTTP2_FRAME_TYPE_PING
971 rcv_goaway_frame, // HTTP2_FRAME_TYPE_GOAWAY
972 rcv_window_update_frame, // HTTP2_FRAME_TYPE_WINDOW_UPDATE
973 rcv_continuation_frame, // HTTP2_FRAME_TYPE_CONTINUATION
974 };
975
976 int
main_event_handler(int event,void * edata)977 Http2ConnectionState::main_event_handler(int event, void *edata)
978 {
979 if (edata == zombie_event) {
980 // zombie session is still around. Assert
981 ink_release_assert(zombie_event == nullptr);
982 } else if (edata == fini_event) {
983 fini_event = nullptr;
984 }
985 ++recursion;
986 switch (event) {
987 // Initialize HTTP/2 Connection
988 case HTTP2_SESSION_EVENT_INIT: {
989 ink_assert(this->ua_session == nullptr);
990 this->ua_session = static_cast<Http2ClientSession *>(edata);
991 REMEMBER(event, this->recursion);
992
993 // [RFC 7540] 3.5. HTTP/2 Connection Preface. Upon establishment of a TCP connection and
994 // determination that HTTP/2 will be used by both peers, each endpoint MUST
995 // send a connection preface as a final confirmation ... The server
996 // connection
997 // preface consists of a potentially empty SETTINGS frame.
998
999 // Load the server settings from the records.config / RecordsConfig.cc
1000 // settings.
1001 Http2ConnectionSettings configured_settings;
1002 configured_settings.settings_from_configs();
1003 configured_settings.set(HTTP2_SETTINGS_MAX_CONCURRENT_STREAMS, _adjust_concurrent_stream());
1004
1005 send_settings_frame(configured_settings);
1006
1007 if (server_settings.get(HTTP2_SETTINGS_INITIAL_WINDOW_SIZE) > HTTP2_INITIAL_WINDOW_SIZE) {
1008 send_window_update_frame(0, server_settings.get(HTTP2_SETTINGS_INITIAL_WINDOW_SIZE) - HTTP2_INITIAL_WINDOW_SIZE);
1009 }
1010
1011 break;
1012 }
1013
1014 // Finalize HTTP/2 Connection
1015 case HTTP2_SESSION_EVENT_FINI: {
1016 SCOPED_MUTEX_LOCK(lock, this->mutex, this_ethread());
1017 REMEMBER(event, this->recursion);
1018
1019 ink_assert(this->fini_received == false);
1020 this->fini_received = true;
1021 cleanup_streams();
1022 release_stream();
1023 SET_HANDLER(&Http2ConnectionState::state_closed);
1024 } break;
1025
1026 case HTTP2_SESSION_EVENT_XMIT: {
1027 REMEMBER(event, this->recursion);
1028 SCOPED_MUTEX_LOCK(lock, this->mutex, this_ethread());
1029 send_data_frames_depends_on_priority();
1030 _scheduled = false;
1031 } break;
1032
1033 // Parse received HTTP/2 frames
1034 case HTTP2_SESSION_EVENT_RECV: {
1035 REMEMBER(event, this->recursion);
1036 const Http2Frame *frame = static_cast<Http2Frame *>(edata);
1037 const Http2StreamId stream_id = frame->header().streamid;
1038 Http2Error error;
1039
1040 // [RFC 7540] 5.5. Extending HTTP/2
1041 // Implementations MUST discard frames that have unknown or unsupported types.
1042 if (frame->header().type >= HTTP2_FRAME_TYPE_MAX) {
1043 Http2StreamDebug(ua_session, stream_id, "Discard a frame which has unknown type, type=%x", frame->header().type);
1044 break;
1045 }
1046
1047 // We need to be careful here, certain frame types are not safe over 0-rtt, tentative for now.
1048 // DATA: NO
1049 // HEADERS: YES (safe http methods only, can only be checked after parsing the payload).
1050 // PRIORITY: YES
1051 // RST_STREAM: NO
1052 // SETTINGS: YES
1053 // PUSH_PROMISE: NO
1054 // PING: YES
1055 // GOAWAY: NO
1056 // WINDOW_UPDATE: YES
1057 // CONTINUATION: YES (safe http methods only, same as HEADERS frame).
1058 if (frame->is_from_early_data() &&
1059 (frame->header().type == HTTP2_FRAME_TYPE_DATA || frame->header().type == HTTP2_FRAME_TYPE_RST_STREAM ||
1060 frame->header().type == HTTP2_FRAME_TYPE_PUSH_PROMISE || frame->header().type == HTTP2_FRAME_TYPE_GOAWAY)) {
1061 Http2StreamDebug(ua_session, stream_id, "Discard a frame which is received from early data and has type=%x",
1062 frame->header().type);
1063 break;
1064 }
1065
1066 if (frame_handlers[frame->header().type]) {
1067 error = frame_handlers[frame->header().type](*this, *frame);
1068 } else {
1069 error = Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_CONNECTION, Http2ErrorCode::HTTP2_ERROR_INTERNAL_ERROR, "no handler");
1070 }
1071
1072 if (error.cls != Http2ErrorClass::HTTP2_ERROR_CLASS_NONE) {
1073 ip_port_text_buffer ipb;
1074 const char *client_ip = ats_ip_ntop(ua_session->get_remote_addr(), ipb, sizeof(ipb));
1075 if (error.cls == Http2ErrorClass::HTTP2_ERROR_CLASS_CONNECTION) {
1076 if (error.msg) {
1077 Error("HTTP/2 connection error code=0x%02x client_ip=%s session_id=%" PRId64 " stream_id=%u %s",
1078 static_cast<int>(error.code), client_ip, ua_session->connection_id(), stream_id, error.msg);
1079 }
1080 this->send_goaway_frame(this->latest_streamid_in, error.code);
1081 this->ua_session->set_half_close_local_flag(true);
1082 if (fini_event == nullptr) {
1083 fini_event = this_ethread()->schedule_imm_local((Continuation *)this, HTTP2_SESSION_EVENT_FINI);
1084 }
1085
1086 // The streams will be cleaned up by the HTTP2_SESSION_EVENT_FINI event
1087 // The Http2ClientSession will shutdown because connection_state.is_state_closed() will be true
1088 } else if (error.cls == Http2ErrorClass::HTTP2_ERROR_CLASS_STREAM) {
1089 if (error.msg) {
1090 Error("HTTP/2 stream error code=0x%02x client_ip=%s session_id=%" PRId64 " stream_id=%u %s", static_cast<int>(error.code),
1091 client_ip, ua_session->connection_id(), stream_id, error.msg);
1092 }
1093 this->send_rst_stream_frame(stream_id, error.code);
1094 }
1095 }
1096
1097 } break;
1098
1099 // Initiate a graceful shutdown
1100 case HTTP2_SESSION_EVENT_SHUTDOWN_INIT: {
1101 REMEMBER(event, this->recursion);
1102 ink_assert(shutdown_state == HTTP2_SHUTDOWN_NOT_INITIATED);
1103 shutdown_state = HTTP2_SHUTDOWN_INITIATED;
1104 // [RFC 7540] 6.8. GOAWAY
1105 // A server that is attempting to gracefully shut down a
1106 // connection SHOULD send an initial GOAWAY frame with the last stream
1107 // identifier set to 2^31-1 and a NO_ERROR code.
1108 send_goaway_frame(INT32_MAX, Http2ErrorCode::HTTP2_ERROR_NO_ERROR);
1109 // After allowing time for any in-flight stream creation (at least one round-trip time),
1110 shutdown_cont_event = this_ethread()->schedule_in((Continuation *)this, HRTIME_SECONDS(2), HTTP2_SESSION_EVENT_SHUTDOWN_CONT);
1111 } break;
1112
1113 // Continue a graceful shutdown
1114 case HTTP2_SESSION_EVENT_SHUTDOWN_CONT: {
1115 REMEMBER(event, this->recursion);
1116 ink_assert(shutdown_state == HTTP2_SHUTDOWN_INITIATED);
1117 shutdown_cont_event = nullptr;
1118 shutdown_state = HTTP2_SHUTDOWN_IN_PROGRESS;
1119 // [RFC 7540] 6.8. GOAWAY
1120 // ..., the server can send another GOAWAY frame with an updated last stream identifier
1121 if (shutdown_reason == Http2ErrorCode::HTTP2_ERROR_MAX) {
1122 shutdown_reason = Http2ErrorCode::HTTP2_ERROR_NO_ERROR;
1123 }
1124 send_goaway_frame(latest_streamid_in, shutdown_reason);
1125 // Stop creating new streams
1126 SCOPED_MUTEX_LOCK(lock, this->ua_session->mutex, this_ethread());
1127 this->ua_session->set_half_close_local_flag(true);
1128 } break;
1129
1130 default:
1131 Http2ConDebug(ua_session, "unexpected event=%d edata=%p", event, edata);
1132 ink_release_assert(0);
1133 break;
1134 }
1135
1136 --recursion;
1137 if (recursion == 0 && ua_session && !ua_session->is_recursing()) {
1138 if (this->ua_session->ready_to_free()) {
1139 MUTEX_TRY_LOCK(lock, this->ua_session->mutex, this_ethread());
1140 if (lock.is_locked()) {
1141 this->ua_session->free();
1142 // After the free, the Http2ConnectionState object is also freed.
1143 // The Http2ConnectionState object is allocated within the Http2ClientSession object
1144 }
1145 }
1146 }
1147
1148 return 0;
1149 }
1150
1151 int
state_closed(int event,void * edata)1152 Http2ConnectionState::state_closed(int event, void *edata)
1153 {
1154 REMEMBER(event, this->recursion);
1155
1156 if (edata == zombie_event) {
1157 // Zombie session is still around. Assert!
1158 ink_release_assert(zombie_event == nullptr);
1159 } else if (edata == fini_event) {
1160 fini_event = nullptr;
1161 } else if (edata == shutdown_cont_event) {
1162 shutdown_cont_event = nullptr;
1163 }
1164 return 0;
1165 }
1166
1167 Http2Stream *
create_stream(Http2StreamId new_id,Http2Error & error)1168 Http2ConnectionState::create_stream(Http2StreamId new_id, Http2Error &error)
1169 {
1170 // first check if we've hit the active connection limit
1171 if (!ua_session->get_netvc()->add_to_active_queue()) {
1172 error = Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_CONNECTION, Http2ErrorCode::HTTP2_ERROR_NO_ERROR,
1173 "refused to create new stream, maxed out active connections");
1174 return nullptr;
1175 }
1176
1177 // In half_close state, TS doesn't create new stream. Because GOAWAY frame is sent to client
1178 if (ua_session->get_half_close_local_flag()) {
1179 error = Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_STREAM, Http2ErrorCode::HTTP2_ERROR_REFUSED_STREAM,
1180 "refused to create new stream, because ua_session is in half_close state");
1181 return nullptr;
1182 }
1183
1184 bool client_streamid = http2_is_client_streamid(new_id);
1185
1186 // 5.1.1 The identifier of a newly established stream MUST be numerically
1187 // greater than all streams that the initiating endpoint has opened or
1188 // reserved. This governs streams that are opened using a HEADERS frame
1189 // and streams that are reserved using PUSH_PROMISE. An endpoint that
1190 // receives an unexpected stream identifier MUST respond with a
1191 // connection error (Section 5.4.1) of type PROTOCOL_ERROR.
1192 if (client_streamid) {
1193 if (new_id <= latest_streamid_in) {
1194 error = Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_CONNECTION, Http2ErrorCode::HTTP2_ERROR_PROTOCOL_ERROR,
1195 "recv headers new client id less than latest stream id");
1196 return nullptr;
1197 }
1198 } else {
1199 if (new_id <= latest_streamid_out) {
1200 error = Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_CONNECTION, Http2ErrorCode::HTTP2_ERROR_PROTOCOL_ERROR,
1201 "recv headers new server id less than latest stream id");
1202 return nullptr;
1203 }
1204 }
1205
1206 // Endpoints MUST NOT exceed the limit set by their peer. An endpoint
1207 // that receives a HEADERS frame that causes their advertised concurrent
1208 // stream limit to be exceeded MUST treat this as a stream error.
1209 if (client_streamid) {
1210 if (client_streams_in_count >= server_settings.get(HTTP2_SETTINGS_MAX_CONCURRENT_STREAMS)) {
1211 error = Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_STREAM, Http2ErrorCode::HTTP2_ERROR_REFUSED_STREAM,
1212 "recv headers creating inbound stream beyond max_concurrent limit");
1213 return nullptr;
1214 }
1215 } else {
1216 if (client_streams_out_count >= client_settings.get(HTTP2_SETTINGS_MAX_CONCURRENT_STREAMS)) {
1217 error = Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_STREAM, Http2ErrorCode::HTTP2_ERROR_REFUSED_STREAM,
1218 "recv headers creating outbound stream beyond max_concurrent limit");
1219 return nullptr;
1220 }
1221 }
1222
1223 Http2Stream *new_stream = THREAD_ALLOC_INIT(http2StreamAllocator, this_ethread(), ua_session, new_id,
1224 client_settings.get(HTTP2_SETTINGS_INITIAL_WINDOW_SIZE));
1225
1226 ink_assert(nullptr != new_stream);
1227 ink_assert(!stream_list.in(new_stream));
1228
1229 stream_list.enqueue(new_stream);
1230 if (client_streamid) {
1231 latest_streamid_in = new_id;
1232 ink_assert(client_streams_in_count < UINT32_MAX);
1233 ++client_streams_in_count;
1234 } else {
1235 latest_streamid_out = new_id;
1236 ink_assert(client_streams_out_count < UINT32_MAX);
1237 ++client_streams_out_count;
1238 }
1239 ++total_client_streams_count;
1240
1241 if (zombie_event != nullptr) {
1242 zombie_event->cancel();
1243 zombie_event = nullptr;
1244 }
1245
1246 new_stream->mutex = new_ProxyMutex();
1247 new_stream->is_first_transaction_flag = get_stream_requests() == 0;
1248 increment_stream_requests();
1249
1250 return new_stream;
1251 }
1252
1253 Http2Stream *
find_stream(Http2StreamId id) const1254 Http2ConnectionState::find_stream(Http2StreamId id) const
1255 {
1256 for (Http2Stream *s = stream_list.head; s; s = static_cast<Http2Stream *>(s->link.next)) {
1257 if (s->get_id() == id) {
1258 return s;
1259 }
1260 ink_assert(s != s->link.next);
1261 }
1262 return nullptr;
1263 }
1264
1265 void
restart_streams()1266 Http2ConnectionState::restart_streams()
1267 {
1268 Http2Stream *s = stream_list.head;
1269 if (s) {
1270 Http2Stream *end = s;
1271
1272 // This is a static variable, so it is shared in Http2ConnectionState instances and will get incremented in subsequent calls.
1273 // It doesn't need to be initialized with rand() nor time(), and doesn't need to be accessed with a lock, because it doesn't
1274 // need that randomness and accuracy.
1275 static uint16_t starting_point = 0;
1276
1277 // Change the start point randomly
1278 for (int i = starting_point % total_client_streams_count; i >= 0; --i) {
1279 end = static_cast<Http2Stream *>(end->link.next ? end->link.next : stream_list.head);
1280 }
1281 s = static_cast<Http2Stream *>(end->link.next ? end->link.next : stream_list.head);
1282
1283 // Call send_response_body() for each streams
1284 while (s != end) {
1285 Http2Stream *next = static_cast<Http2Stream *>(s->link.next ? s->link.next : stream_list.head);
1286 if (!s->is_closed() && s->get_state() == Http2StreamState::HTTP2_STREAM_STATE_HALF_CLOSED_REMOTE &&
1287 std::min(this->client_rwnd(), s->client_rwnd()) > 0) {
1288 SCOPED_MUTEX_LOCK(lock, s->mutex, this_ethread());
1289 s->restart_sending();
1290 }
1291 ink_assert(s != next);
1292 s = next;
1293 }
1294 if (!s->is_closed() && s->get_state() == Http2StreamState::HTTP2_STREAM_STATE_HALF_CLOSED_REMOTE &&
1295 std::min(this->client_rwnd(), s->client_rwnd()) > 0) {
1296 SCOPED_MUTEX_LOCK(lock, s->mutex, this_ethread());
1297 s->restart_sending();
1298 }
1299
1300 ++starting_point;
1301 }
1302 }
1303
1304 void
restart_receiving(Http2Stream * stream)1305 Http2ConnectionState::restart_receiving(Http2Stream *stream)
1306 {
1307 uint32_t initial_rwnd = this->server_settings.get(HTTP2_SETTINGS_INITIAL_WINDOW_SIZE);
1308 uint32_t min_rwnd = std::min(initial_rwnd, this->server_settings.get(HTTP2_SETTINGS_MAX_FRAME_SIZE));
1309
1310 // Connection level WINDOW UPDATE
1311 if (this->server_rwnd() < min_rwnd) {
1312 Http2WindowSize diff_size = initial_rwnd - this->server_rwnd();
1313 this->increment_server_rwnd(diff_size);
1314 this->send_window_update_frame(0, diff_size);
1315 }
1316
1317 // Stream level WINDOW UPDATE
1318 if (stream == nullptr || stream->server_rwnd() >= min_rwnd) {
1319 return;
1320 }
1321
1322 // If read_vio is buffering data, do not fully update window
1323 int64_t data_size = stream->read_vio_read_avail();
1324 if (data_size >= initial_rwnd) {
1325 return;
1326 }
1327
1328 Http2WindowSize diff_size = initial_rwnd - std::max(static_cast<int64_t>(stream->server_rwnd()), data_size);
1329 stream->increment_server_rwnd(diff_size);
1330 this->send_window_update_frame(stream->get_id(), diff_size);
1331 }
1332
1333 void
cleanup_streams()1334 Http2ConnectionState::cleanup_streams()
1335 {
1336 Http2Stream *s = stream_list.head;
1337 while (s) {
1338 Http2Stream *next = static_cast<Http2Stream *>(s->link.next);
1339 if (this->rx_error_code.cls != ProxyErrorClass::NONE) {
1340 s->set_rx_error_code(this->rx_error_code);
1341 }
1342 if (this->tx_error_code.cls != ProxyErrorClass::NONE) {
1343 s->set_tx_error_code(this->tx_error_code);
1344 }
1345 s->initiating_close();
1346 ink_assert(s != next);
1347 s = next;
1348 }
1349
1350 if (!is_state_closed()) {
1351 SCOPED_MUTEX_LOCK(lock, this->ua_session->mutex, this_ethread());
1352
1353 UnixNetVConnection *vc = static_cast<UnixNetVConnection *>(ua_session->get_netvc());
1354 if (vc && vc->active_timeout_in == 0) {
1355 vc->add_to_keep_alive_queue();
1356 }
1357 }
1358 }
1359
1360 bool
delete_stream(Http2Stream * stream)1361 Http2ConnectionState::delete_stream(Http2Stream *stream)
1362 {
1363 ink_assert(nullptr != stream);
1364 SCOPED_MUTEX_LOCK(lock, this->mutex, this_ethread());
1365
1366 // If stream has already been removed from the list, just go on
1367 if (!stream_list.in(stream)) {
1368 return false;
1369 }
1370
1371 Http2StreamDebug(ua_session, stream->get_id(), "Delete stream");
1372 REMEMBER(NO_EVENT, this->recursion);
1373
1374 if (Http2::stream_priority_enabled) {
1375 Http2DependencyTree::Node *node = stream->priority_node;
1376 if (node != nullptr) {
1377 if (node->active) {
1378 dependency_tree->deactivate(node, 0);
1379 }
1380 if (is_debug_tag_set("http2_priority")) {
1381 std::stringstream output;
1382 dependency_tree->dump_tree(output);
1383 Debug("http2_priority", "[%" PRId64 "] %s", ua_session->connection_id(), output.str().c_str());
1384 }
1385 dependency_tree->remove(node);
1386 // ink_release_assert(dependency_tree->find(stream->get_id()) == nullptr);
1387 }
1388 stream->priority_node = nullptr;
1389 }
1390
1391 if (stream->get_state() != Http2StreamState::HTTP2_STREAM_STATE_CLOSED) {
1392 send_rst_stream_frame(stream->get_id(), Http2ErrorCode::HTTP2_ERROR_NO_ERROR);
1393 }
1394
1395 stream_list.remove(stream);
1396 if (http2_is_client_streamid(stream->get_id())) {
1397 ink_assert(client_streams_in_count > 0);
1398 --client_streams_in_count;
1399 } else {
1400 ink_assert(client_streams_out_count > 0);
1401 --client_streams_out_count;
1402 }
1403 // total_client_streams_count will be decremented in release_stream(), because it's a counter include streams in the process of
1404 // shutting down.
1405
1406 stream->initiating_close();
1407
1408 return true;
1409 }
1410
1411 void
release_stream()1412 Http2ConnectionState::release_stream()
1413 {
1414 REMEMBER(NO_EVENT, this->recursion)
1415
1416 SCOPED_MUTEX_LOCK(lock, this->mutex, this_ethread());
1417 if (this->ua_session) {
1418 ink_assert(this->mutex == ua_session->mutex);
1419
1420 if (total_client_streams_count == 0) {
1421 if (fini_received) {
1422 ua_session->clear_session_active();
1423
1424 // We were shutting down, go ahead and terminate the session
1425 // this is a member of Http2ConnectionState and will be freed
1426 // when ua_session is destroyed
1427 ua_session->destroy();
1428
1429 // Can't do this because we just destroyed right here ^,
1430 // or we can use a local variable to do it.
1431 // ua_session = nullptr;
1432 } else if (ua_session->is_active()) {
1433 // If the number of clients is 0, HTTP2_SESSION_EVENT_FINI is not received or sent, and ua_session is active,
1434 // then mark the connection as inactive
1435 ua_session->clear_session_active();
1436 UnixNetVConnection *vc = static_cast<UnixNetVConnection *>(ua_session->get_netvc());
1437 if (vc && vc->active_timeout_in == 0) {
1438 // With heavy traffic, ua_session could be destroyed. Do not touch ua_session after this.
1439 vc->add_to_keep_alive_queue();
1440 }
1441 } else {
1442 schedule_zombie_event();
1443 }
1444 } else if (fini_received) {
1445 schedule_zombie_event();
1446 }
1447 }
1448 }
1449
1450 void
update_initial_rwnd(Http2WindowSize new_size)1451 Http2ConnectionState::update_initial_rwnd(Http2WindowSize new_size)
1452 {
1453 // Update stream level window sizes
1454 for (Http2Stream *s = stream_list.head; s; s = static_cast<Http2Stream *>(s->link.next)) {
1455 SCOPED_MUTEX_LOCK(lock, s->mutex, this_ethread());
1456 s->update_initial_rwnd(new_size - (client_settings.get(HTTP2_SETTINGS_INITIAL_WINDOW_SIZE) - s->client_rwnd()));
1457 }
1458 }
1459
1460 void
schedule_stream(Http2Stream * stream)1461 Http2ConnectionState::schedule_stream(Http2Stream *stream)
1462 {
1463 Http2StreamDebug(ua_session, stream->get_id(), "Scheduled");
1464
1465 Http2DependencyTree::Node *node = stream->priority_node;
1466 ink_release_assert(node != nullptr);
1467
1468 SCOPED_MUTEX_LOCK(lock, this->mutex, this_ethread());
1469 dependency_tree->activate(node);
1470
1471 if (!_scheduled) {
1472 _scheduled = true;
1473
1474 SET_HANDLER(&Http2ConnectionState::main_event_handler);
1475 this_ethread()->schedule_imm_local((Continuation *)this, HTTP2_SESSION_EVENT_XMIT);
1476 }
1477 }
1478
1479 void
send_data_frames_depends_on_priority()1480 Http2ConnectionState::send_data_frames_depends_on_priority()
1481 {
1482 Http2DependencyTree::Node *node = dependency_tree->top();
1483
1484 // No node to send or no connection level window left
1485 if (node == nullptr || _client_rwnd <= 0) {
1486 return;
1487 }
1488
1489 Http2Stream *stream = static_cast<Http2Stream *>(node->t);
1490 ink_release_assert(stream != nullptr);
1491 Http2StreamDebug(ua_session, stream->get_id(), "top node, point=%d", node->point);
1492
1493 size_t len = 0;
1494 Http2SendDataFrameResult result = send_a_data_frame(stream, len);
1495
1496 switch (result) {
1497 case Http2SendDataFrameResult::NO_ERROR: {
1498 // No response body to send
1499 if (len == 0 && !stream->is_write_vio_done()) {
1500 dependency_tree->deactivate(node, len);
1501 } else {
1502 dependency_tree->update(node, len);
1503
1504 SCOPED_MUTEX_LOCK(stream_lock, stream->mutex, this_ethread());
1505 stream->signal_write_event(true);
1506 }
1507 break;
1508 }
1509 case Http2SendDataFrameResult::DONE: {
1510 dependency_tree->deactivate(node, len);
1511 stream->initiating_close();
1512 break;
1513 }
1514 default:
1515 // When no stream level window left, deactivate node once and wait window_update frame
1516 dependency_tree->deactivate(node, len);
1517 break;
1518 }
1519
1520 this_ethread()->schedule_imm_local((Continuation *)this, HTTP2_SESSION_EVENT_XMIT);
1521 return;
1522 }
1523
1524 Http2SendDataFrameResult
send_a_data_frame(Http2Stream * stream,size_t & payload_length)1525 Http2ConnectionState::send_a_data_frame(Http2Stream *stream, size_t &payload_length)
1526 {
1527 const ssize_t window_size = std::min(this->client_rwnd(), stream->client_rwnd());
1528 const size_t buf_len = BUFFER_SIZE_FOR_INDEX(buffer_size_index[HTTP2_FRAME_TYPE_DATA]);
1529 const size_t write_available_size = std::min(buf_len, static_cast<size_t>(window_size));
1530 payload_length = 0;
1531
1532 uint8_t flags = 0x00;
1533 IOBufferReader *resp_reader = stream->response_get_data_reader();
1534
1535 SCOPED_MUTEX_LOCK(stream_lock, stream->mutex, this_ethread());
1536
1537 if (!resp_reader) {
1538 Http2StreamDebug(this->ua_session, stream->get_id(), "couldn't get data reader");
1539 return Http2SendDataFrameResult::ERROR;
1540 }
1541
1542 if (this->ua_session->write_avail() == 0) {
1543 Http2StreamDebug(this->ua_session, stream->get_id(), "Not write avail");
1544 this->ua_session->flush();
1545 return Http2SendDataFrameResult::NOT_WRITE_AVAIL;
1546 }
1547
1548 // Select appropriate payload length
1549 if (resp_reader->is_read_avail_more_than(0)) {
1550 // We only need to check for window size when there is a payload
1551 if (window_size <= 0) {
1552 Http2StreamDebug(this->ua_session, stream->get_id(), "No window");
1553 this->ua_session->flush();
1554 return Http2SendDataFrameResult::NO_WINDOW;
1555 }
1556
1557 if (resp_reader->is_read_avail_more_than(write_available_size)) {
1558 payload_length = write_available_size;
1559 } else {
1560 payload_length = resp_reader->read_avail();
1561 }
1562 } else {
1563 payload_length = 0;
1564 }
1565
1566 // Are we at the end?
1567 // If we return here, we never send the END_STREAM in the case of a early terminating OS.
1568 // OK if there is no body yet. Otherwise continue on to send a DATA frame and delete the stream
1569 if (!stream->is_write_vio_done() && payload_length == 0) {
1570 Http2StreamDebug(this->ua_session, stream->get_id(), "No payload");
1571 this->ua_session->flush();
1572 return Http2SendDataFrameResult::NO_PAYLOAD;
1573 }
1574
1575 if (stream->is_write_vio_done() && !resp_reader->is_read_avail_more_than(0)) {
1576 flags |= HTTP2_FLAGS_DATA_END_STREAM;
1577 }
1578
1579 // Update window size
1580 this->decrement_client_rwnd(payload_length);
1581 stream->decrement_client_rwnd(payload_length);
1582
1583 // Create frame
1584 Http2StreamDebug(ua_session, stream->get_id(), "Send a DATA frame - client window con: %5zd stream: %5zd payload: %5zd",
1585 _client_rwnd, stream->client_rwnd(), payload_length);
1586
1587 Http2DataFrame data(stream->get_id(), flags, resp_reader, payload_length);
1588 this->ua_session->xmit(data, flags & HTTP2_FLAGS_DATA_END_STREAM);
1589
1590 stream->update_sent_count(payload_length);
1591
1592 if (flags & HTTP2_FLAGS_DATA_END_STREAM) {
1593 Http2StreamDebug(ua_session, stream->get_id(), "END_STREAM");
1594 stream->send_end_stream = true;
1595 // Setting to the same state shouldn't be erroneous
1596 stream->change_state(HTTP2_FRAME_TYPE_DATA, flags);
1597
1598 return Http2SendDataFrameResult::DONE;
1599 }
1600
1601 return Http2SendDataFrameResult::NO_ERROR;
1602 }
1603
1604 void
send_data_frames(Http2Stream * stream)1605 Http2ConnectionState::send_data_frames(Http2Stream *stream)
1606 {
1607 // To follow RFC 7540 must not send more frames other than priority on
1608 // a closed stream. So we return without sending
1609 if (stream->get_state() == Http2StreamState::HTTP2_STREAM_STATE_HALF_CLOSED_LOCAL ||
1610 stream->get_state() == Http2StreamState::HTTP2_STREAM_STATE_CLOSED) {
1611 Http2StreamDebug(this->ua_session, stream->get_id(), "Shutdown half closed local stream");
1612 stream->initiating_close();
1613 return;
1614 }
1615
1616 size_t len = 0;
1617 Http2SendDataFrameResult result = Http2SendDataFrameResult::NO_ERROR;
1618 while (result == Http2SendDataFrameResult::NO_ERROR) {
1619 result = send_a_data_frame(stream, len);
1620
1621 if (result == Http2SendDataFrameResult::DONE) {
1622 // Delete a stream immediately
1623 // TODO its should not be deleted for a several time to handling
1624 // RST_STREAM and WINDOW_UPDATE.
1625 // See 'closed' state written at [RFC 7540] 5.1.
1626 Http2StreamDebug(this->ua_session, stream->get_id(), "Shutdown stream");
1627 stream->initiating_close();
1628 }
1629 }
1630
1631 return;
1632 }
1633
1634 void
send_headers_frame(Http2Stream * stream)1635 Http2ConnectionState::send_headers_frame(Http2Stream *stream)
1636 {
1637 uint32_t header_blocks_size = 0;
1638 int payload_length = 0;
1639 uint8_t flags = 0x00;
1640
1641 Http2StreamDebug(ua_session, stream->get_id(), "Send HEADERS frame");
1642
1643 HTTPHdr *resp_hdr = &stream->response_header;
1644 http2_convert_header_from_1_1_to_2(resp_hdr);
1645
1646 uint32_t buf_len = resp_hdr->length_get() * 2; // Make it double just in case
1647 ts::LocalBuffer local_buffer(buf_len);
1648 uint8_t *buf = local_buffer.data();
1649
1650 stream->mark_milestone(Http2StreamMilestone::START_ENCODE_HEADERS);
1651 Http2ErrorCode result = http2_encode_header_blocks(resp_hdr, buf, buf_len, &header_blocks_size, *(this->remote_hpack_handle),
1652 client_settings.get(HTTP2_SETTINGS_HEADER_TABLE_SIZE));
1653 if (result != Http2ErrorCode::HTTP2_ERROR_NO_ERROR) {
1654 return;
1655 }
1656
1657 // Send a HEADERS frame
1658 if (header_blocks_size <= static_cast<uint32_t>(BUFFER_SIZE_FOR_INDEX(buffer_size_index[HTTP2_FRAME_TYPE_HEADERS]))) {
1659 payload_length = header_blocks_size;
1660 flags |= HTTP2_FLAGS_HEADERS_END_HEADERS;
1661 if ((resp_hdr->presence(MIME_PRESENCE_CONTENT_LENGTH) && resp_hdr->get_content_length() == 0) ||
1662 (!resp_hdr->expect_final_response() && stream->is_write_vio_done())) {
1663 Http2StreamDebug(ua_session, stream->get_id(), "END_STREAM");
1664 flags |= HTTP2_FLAGS_HEADERS_END_STREAM;
1665 stream->send_end_stream = true;
1666 }
1667 stream->mark_milestone(Http2StreamMilestone::START_TX_HEADERS_FRAMES);
1668 } else {
1669 payload_length = BUFFER_SIZE_FOR_INDEX(buffer_size_index[HTTP2_FRAME_TYPE_HEADERS]);
1670 }
1671
1672 // Change stream state
1673 if (!stream->change_state(HTTP2_FRAME_TYPE_HEADERS, flags)) {
1674 this->send_goaway_frame(this->latest_streamid_in, Http2ErrorCode::HTTP2_ERROR_PROTOCOL_ERROR);
1675 this->ua_session->set_half_close_local_flag(true);
1676 if (fini_event == nullptr) {
1677 fini_event = this_ethread()->schedule_imm_local((Continuation *)this, HTTP2_SESSION_EVENT_FINI);
1678 }
1679
1680 return;
1681 }
1682
1683 Http2HeadersFrame headers(stream->get_id(), flags, buf, payload_length);
1684 this->ua_session->xmit(headers);
1685 uint64_t sent = payload_length;
1686
1687 // Send CONTINUATION frames
1688 flags = 0;
1689 while (sent < header_blocks_size) {
1690 Http2StreamDebug(ua_session, stream->get_id(), "Send CONTINUATION frame");
1691 payload_length = std::min(static_cast<uint32_t>(BUFFER_SIZE_FOR_INDEX(buffer_size_index[HTTP2_FRAME_TYPE_CONTINUATION])),
1692 static_cast<uint32_t>(header_blocks_size - sent));
1693 if (sent + payload_length == header_blocks_size) {
1694 flags |= HTTP2_FLAGS_CONTINUATION_END_HEADERS;
1695 }
1696 stream->change_state(HTTP2_FRAME_TYPE_CONTINUATION, flags);
1697
1698 Http2ContinuationFrame continuation_frame(stream->get_id(), flags, buf + sent, payload_length);
1699 this->ua_session->xmit(continuation_frame);
1700 sent += payload_length;
1701 }
1702 }
1703
1704 bool
send_push_promise_frame(Http2Stream * stream,URL & url,const MIMEField * accept_encoding)1705 Http2ConnectionState::send_push_promise_frame(Http2Stream *stream, URL &url, const MIMEField *accept_encoding)
1706 {
1707 uint32_t header_blocks_size = 0;
1708 int payload_length = 0;
1709 uint8_t flags = 0x00;
1710
1711 if (client_settings.get(HTTP2_SETTINGS_ENABLE_PUSH) == 0) {
1712 return false;
1713 }
1714
1715 Http2StreamDebug(ua_session, stream->get_id(), "Send PUSH_PROMISE frame");
1716
1717 HTTPHdr hdr;
1718 ts::PostScript hdr_defer([&]() -> void { hdr.destroy(); });
1719 hdr.create(HTTP_TYPE_REQUEST);
1720 http2_init_pseudo_headers(hdr);
1721 hdr.url_set(&url);
1722 hdr.method_set(HTTP_METHOD_GET, HTTP_LEN_GET);
1723
1724 if (accept_encoding != nullptr) {
1725 int name_len;
1726 const char *name = accept_encoding->name_get(&name_len);
1727 MIMEField *f = hdr.field_create(name, name_len);
1728
1729 int value_len;
1730 const char *value = accept_encoding->value_get(&value_len);
1731 f->value_set(hdr.m_heap, hdr.m_mime, value, value_len);
1732
1733 hdr.field_attach(f);
1734 }
1735
1736 http2_convert_header_from_1_1_to_2(&hdr);
1737
1738 uint32_t buf_len = hdr.length_get() * 2; // Make it double just in case
1739 ts::LocalBuffer local_buffer(buf_len);
1740 uint8_t *buf = local_buffer.data();
1741
1742 Http2ErrorCode result = http2_encode_header_blocks(&hdr, buf, buf_len, &header_blocks_size, *(this->remote_hpack_handle),
1743 client_settings.get(HTTP2_SETTINGS_HEADER_TABLE_SIZE));
1744 if (result != Http2ErrorCode::HTTP2_ERROR_NO_ERROR) {
1745 return false;
1746 }
1747
1748 // Send a PUSH_PROMISE frame
1749 Http2PushPromise push_promise;
1750 if (header_blocks_size <=
1751 BUFFER_SIZE_FOR_INDEX(buffer_size_index[HTTP2_FRAME_TYPE_PUSH_PROMISE]) - sizeof(push_promise.promised_streamid)) {
1752 payload_length = header_blocks_size;
1753 flags |= HTTP2_FLAGS_PUSH_PROMISE_END_HEADERS;
1754 } else {
1755 payload_length =
1756 BUFFER_SIZE_FOR_INDEX(buffer_size_index[HTTP2_FRAME_TYPE_PUSH_PROMISE]) - sizeof(push_promise.promised_streamid);
1757 }
1758
1759 Http2StreamId id = this->get_latest_stream_id_out() + 2;
1760 push_promise.promised_streamid = id;
1761
1762 Http2PushPromiseFrame push_promise_frame(stream->get_id(), flags, push_promise, buf, payload_length);
1763 this->ua_session->xmit(push_promise_frame);
1764 uint64_t sent = payload_length;
1765
1766 // Send CONTINUATION frames
1767 flags = 0;
1768 while (sent < header_blocks_size) {
1769 Http2StreamDebug(ua_session, stream->get_id(), "Send CONTINUATION frame");
1770 payload_length = std::min(static_cast<uint32_t>(BUFFER_SIZE_FOR_INDEX(buffer_size_index[HTTP2_FRAME_TYPE_CONTINUATION])),
1771 static_cast<uint32_t>(header_blocks_size - sent));
1772 if (sent + payload_length == header_blocks_size) {
1773 flags |= HTTP2_FLAGS_CONTINUATION_END_HEADERS;
1774 }
1775
1776 Http2ContinuationFrame continuation(stream->get_id(), flags, buf + sent, payload_length);
1777 this->ua_session->xmit(continuation);
1778 sent += payload_length;
1779 }
1780
1781 Http2Error error(Http2ErrorClass::HTTP2_ERROR_CLASS_NONE);
1782 stream = this->create_stream(id, error);
1783 if (!stream) {
1784 return false;
1785 }
1786
1787 SCOPED_MUTEX_LOCK(stream_lock, stream->mutex, this_ethread());
1788 if (Http2::stream_priority_enabled) {
1789 Http2DependencyTree::Node *node = this->dependency_tree->find(id);
1790 if (node != nullptr) {
1791 stream->priority_node = node;
1792 } else {
1793 Http2StreamDebug(this->ua_session, id, "PRIORITY - dep: %d, weight: %d, excl: %d, tree size: %d",
1794 HTTP2_PRIORITY_DEFAULT_STREAM_DEPENDENCY, HTTP2_PRIORITY_DEFAULT_WEIGHT, false,
1795 this->dependency_tree->size());
1796
1797 stream->priority_node =
1798 this->dependency_tree->add(HTTP2_PRIORITY_DEFAULT_STREAM_DEPENDENCY, id, HTTP2_PRIORITY_DEFAULT_WEIGHT, false, stream);
1799 }
1800 }
1801 stream->change_state(HTTP2_FRAME_TYPE_PUSH_PROMISE, HTTP2_FLAGS_PUSH_PROMISE_END_HEADERS);
1802 stream->set_request_headers(hdr);
1803 stream->new_transaction();
1804 stream->recv_end_stream = true; // No more data with the request
1805 stream->send_request(*this);
1806
1807 return true;
1808 }
1809
1810 void
send_rst_stream_frame(Http2StreamId id,Http2ErrorCode ec)1811 Http2ConnectionState::send_rst_stream_frame(Http2StreamId id, Http2ErrorCode ec)
1812 {
1813 Http2StreamDebug(ua_session, id, "Send RST_STREAM frame");
1814
1815 if (ec != Http2ErrorCode::HTTP2_ERROR_NO_ERROR) {
1816 HTTP2_INCREMENT_THREAD_DYN_STAT(HTTP2_STAT_STREAM_ERRORS_COUNT, this_ethread());
1817 ++stream_error_count;
1818 }
1819
1820 // change state to closed
1821 Http2Stream *stream = find_stream(id);
1822 if (stream != nullptr) {
1823 stream->set_tx_error_code({ProxyErrorClass::TXN, static_cast<uint32_t>(ec)});
1824 if (!stream->change_state(HTTP2_FRAME_TYPE_RST_STREAM, 0)) {
1825 this->send_goaway_frame(this->latest_streamid_in, Http2ErrorCode::HTTP2_ERROR_PROTOCOL_ERROR);
1826 this->ua_session->set_half_close_local_flag(true);
1827 if (fini_event == nullptr) {
1828 fini_event = this_ethread()->schedule_imm_local((Continuation *)this, HTTP2_SESSION_EVENT_FINI);
1829 }
1830
1831 return;
1832 }
1833 }
1834
1835 Http2RstStreamFrame rst_stream(id, static_cast<uint32_t>(ec));
1836 this->ua_session->xmit(rst_stream);
1837 }
1838
1839 void
send_settings_frame(const Http2ConnectionSettings & new_settings)1840 Http2ConnectionState::send_settings_frame(const Http2ConnectionSettings &new_settings)
1841 {
1842 const Http2StreamId stream_id = 0;
1843
1844 Http2StreamDebug(ua_session, stream_id, "Send SETTINGS frame");
1845
1846 Http2SettingsParameter params[HTTP2_SETTINGS_MAX];
1847 size_t params_size = 0;
1848
1849 for (int i = HTTP2_SETTINGS_HEADER_TABLE_SIZE; i < HTTP2_SETTINGS_MAX; ++i) {
1850 Http2SettingsIdentifier id = static_cast<Http2SettingsIdentifier>(i);
1851 unsigned settings_value = new_settings.get(id);
1852
1853 // Send only difference
1854 if (settings_value != server_settings.get(id)) {
1855 Http2StreamDebug(ua_session, stream_id, " %s : %u", Http2DebugNames::get_settings_param_name(id), settings_value);
1856
1857 params[params_size++] = {static_cast<uint16_t>(id), settings_value};
1858
1859 // Update current settings
1860 server_settings.set(id, new_settings.get(id));
1861 }
1862 }
1863
1864 Http2SettingsFrame settings(stream_id, HTTP2_FRAME_NO_FLAG, params, params_size);
1865 this->ua_session->xmit(settings);
1866 }
1867
1868 void
send_ping_frame(Http2StreamId id,uint8_t flag,const uint8_t * opaque_data)1869 Http2ConnectionState::send_ping_frame(Http2StreamId id, uint8_t flag, const uint8_t *opaque_data)
1870 {
1871 Http2StreamDebug(ua_session, id, "Send PING frame");
1872
1873 Http2PingFrame ping(id, flag, opaque_data);
1874 this->ua_session->xmit(ping);
1875 }
1876
1877 // As for graceful shutdown, TS should process outstanding stream as long as possible.
1878 // As for signal connection error, TS should close connection immediately.
1879 void
send_goaway_frame(Http2StreamId id,Http2ErrorCode ec)1880 Http2ConnectionState::send_goaway_frame(Http2StreamId id, Http2ErrorCode ec)
1881 {
1882 ink_assert(this->ua_session != nullptr);
1883
1884 Http2ConDebug(ua_session, "Send GOAWAY frame, last_stream_id: %d", id);
1885
1886 if (ec != Http2ErrorCode::HTTP2_ERROR_NO_ERROR) {
1887 HTTP2_INCREMENT_THREAD_DYN_STAT(HTTP2_STAT_CONNECTION_ERRORS_COUNT, this_ethread());
1888 }
1889
1890 this->tx_error_code = {ProxyErrorClass::SSN, static_cast<uint32_t>(ec)};
1891
1892 Http2Goaway goaway;
1893 goaway.last_streamid = id;
1894 goaway.error_code = ec;
1895
1896 Http2GoawayFrame frame(goaway);
1897 this->ua_session->xmit(frame);
1898 }
1899
1900 void
send_window_update_frame(Http2StreamId id,uint32_t size)1901 Http2ConnectionState::send_window_update_frame(Http2StreamId id, uint32_t size)
1902 {
1903 Http2StreamDebug(ua_session, id, "Send WINDOW_UPDATE frame: size=%" PRIu32, size);
1904
1905 // Create WINDOW_UPDATE frame
1906 Http2WindowUpdateFrame window_update(id, size);
1907 this->ua_session->xmit(window_update);
1908 }
1909
1910 void
increment_received_settings_count(uint32_t count)1911 Http2ConnectionState::increment_received_settings_count(uint32_t count)
1912 {
1913 this->_received_settings_counter.increment(count);
1914 }
1915
1916 uint32_t
get_received_settings_count()1917 Http2ConnectionState::get_received_settings_count()
1918 {
1919 return this->_received_settings_counter.get_count();
1920 }
1921
1922 void
increment_received_settings_frame_count()1923 Http2ConnectionState::increment_received_settings_frame_count()
1924 {
1925 this->_received_settings_frame_counter.increment();
1926 }
1927
1928 uint32_t
get_received_settings_frame_count()1929 Http2ConnectionState::get_received_settings_frame_count()
1930 {
1931 return this->_received_settings_frame_counter.get_count();
1932 }
1933
1934 void
increment_received_ping_frame_count()1935 Http2ConnectionState::increment_received_ping_frame_count()
1936 {
1937 this->_received_ping_frame_counter.increment();
1938 }
1939
1940 uint32_t
get_received_ping_frame_count()1941 Http2ConnectionState::get_received_ping_frame_count()
1942 {
1943 return this->_received_ping_frame_counter.get_count();
1944 }
1945
1946 void
increment_received_priority_frame_count()1947 Http2ConnectionState::increment_received_priority_frame_count()
1948 {
1949 this->_received_priority_frame_counter.increment();
1950 }
1951
1952 uint32_t
get_received_priority_frame_count()1953 Http2ConnectionState::get_received_priority_frame_count()
1954 {
1955 return this->_received_priority_frame_counter.get_count();
1956 }
1957
1958 // Return min_concurrent_streams_in when current client streams number is larger than max_active_streams_in.
1959 // Main purpose of this is preventing DDoS Attacks.
1960 unsigned
_adjust_concurrent_stream()1961 Http2ConnectionState::_adjust_concurrent_stream()
1962 {
1963 if (Http2::max_active_streams_in == 0) {
1964 // Throttling down is disabled.
1965 return Http2::max_concurrent_streams_in;
1966 }
1967
1968 int64_t current_client_streams = 0;
1969 RecGetRawStatSum(http2_rsb, HTTP2_STAT_CURRENT_CLIENT_STREAM_COUNT, ¤t_client_streams);
1970
1971 Http2ConDebug(ua_session, "current client streams: %" PRId64, current_client_streams);
1972
1973 if (current_client_streams >= Http2::max_active_streams_in) {
1974 if (!Http2::throttling) {
1975 Warning("too many streams: %" PRId64 ", reduce SETTINGS_MAX_CONCURRENT_STREAMS to %d", current_client_streams,
1976 Http2::min_concurrent_streams_in);
1977 Http2::throttling = true;
1978 }
1979
1980 return Http2::min_concurrent_streams_in;
1981 } else {
1982 if (Http2::throttling) {
1983 Note("revert SETTINGS_MAX_CONCURRENT_STREAMS to %d", Http2::max_concurrent_streams_in);
1984 Http2::throttling = false;
1985 }
1986 }
1987
1988 return Http2::max_concurrent_streams_in;
1989 }
1990
1991 ssize_t
client_rwnd() const1992 Http2ConnectionState::client_rwnd() const
1993 {
1994 return this->_client_rwnd;
1995 }
1996
1997 Http2ErrorCode
increment_client_rwnd(size_t amount)1998 Http2ConnectionState::increment_client_rwnd(size_t amount)
1999 {
2000 this->_client_rwnd += amount;
2001
2002 this->_recent_rwnd_increment[this->_recent_rwnd_increment_index] = amount;
2003 ++this->_recent_rwnd_increment_index;
2004 this->_recent_rwnd_increment_index %= this->_recent_rwnd_increment.size();
2005 double sum = std::accumulate(this->_recent_rwnd_increment.begin(), this->_recent_rwnd_increment.end(), 0.0);
2006 double avg = sum / this->_recent_rwnd_increment.size();
2007 if (avg < Http2::min_avg_window_update) {
2008 HTTP2_INCREMENT_THREAD_DYN_STAT(HTTP2_STAT_INSUFFICIENT_AVG_WINDOW_UPDATE, this_ethread());
2009 return Http2ErrorCode::HTTP2_ERROR_ENHANCE_YOUR_CALM;
2010 }
2011 return Http2ErrorCode::HTTP2_ERROR_NO_ERROR;
2012 }
2013
2014 Http2ErrorCode
decrement_client_rwnd(size_t amount)2015 Http2ConnectionState::decrement_client_rwnd(size_t amount)
2016 {
2017 this->_client_rwnd -= amount;
2018 return Http2ErrorCode::HTTP2_ERROR_NO_ERROR;
2019 }
2020
2021 ssize_t
server_rwnd() const2022 Http2ConnectionState::server_rwnd() const
2023 {
2024 return this->_server_rwnd;
2025 }
2026
2027 Http2ErrorCode
increment_server_rwnd(size_t amount)2028 Http2ConnectionState::increment_server_rwnd(size_t amount)
2029 {
2030 this->_server_rwnd += amount;
2031 return Http2ErrorCode::HTTP2_ERROR_NO_ERROR;
2032 }
2033
2034 Http2ErrorCode
decrement_server_rwnd(size_t amount)2035 Http2ConnectionState::decrement_server_rwnd(size_t amount)
2036 {
2037 this->_server_rwnd -= amount;
2038 return Http2ErrorCode::HTTP2_ERROR_NO_ERROR;
2039 }
2040