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, &current_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