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