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