1 /** @file
2 
3   Http2ClientSession.
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 "Http2ClientSession.h"
25 #include "HttpDebugNames.h"
26 #include "tscore/ink_base64.h"
27 
28 #define REMEMBER(e, r)                          \
29   {                                             \
30     this->remember(MakeSourceLocation(), e, r); \
31   }
32 
33 #define STATE_ENTER(state_name, event)                                                       \
34   do {                                                                                       \
35     REMEMBER(event, this->recursion)                                                         \
36     SsnDebug(this, "http2_cs", "[%" PRId64 "] [%s, %s]", this->connection_id(), #state_name, \
37              HttpDebugNames::get_event_name(event));                                         \
38   } while (0)
39 
40 #define Http2SsnDebug(fmt, ...) SsnDebug(this, "http2_cs", "[%" PRId64 "] " fmt, this->connection_id(), ##__VA_ARGS__)
41 
42 #define HTTP2_SET_SESSION_HANDLER(handler) \
43   do {                                     \
44     REMEMBER(NO_EVENT, this->recursion);   \
45     this->session_handler = (handler);     \
46   } while (0)
47 
48 ClassAllocator<Http2ClientSession, true> http2ClientSessionAllocator("http2ClientSessionAllocator");
49 
50 // memcpy the requested bytes from the IOBufferReader, returning how many were
51 // actually copied.
52 static inline unsigned
copy_from_buffer_reader(void * dst,IOBufferReader * reader,unsigned nbytes)53 copy_from_buffer_reader(void *dst, IOBufferReader *reader, unsigned nbytes)
54 {
55   char *end;
56 
57   end = reader->memcpy(dst, nbytes, 0 /* offset */);
58   return end - static_cast<char *>(dst);
59 }
60 
61 static int
send_connection_event(Continuation * cont,int event,void * edata)62 send_connection_event(Continuation *cont, int event, void *edata)
63 {
64   SCOPED_MUTEX_LOCK(lock, cont->mutex, this_ethread());
65   return cont->handleEvent(event, edata);
66 }
67 
Http2ClientSession()68 Http2ClientSession::Http2ClientSession() : super() {}
69 
70 void
destroy()71 Http2ClientSession::destroy()
72 {
73   if (!in_destroy) {
74     in_destroy = true;
75     REMEMBER(NO_EVENT, this->recursion)
76     Http2SsnDebug("session destroy");
77     // Let everyone know we are going down
78     do_api_callout(TS_HTTP_SSN_CLOSE_HOOK);
79   }
80 }
81 
82 void
free()83 Http2ClientSession::free()
84 {
85   if (_vc) {
86     _vc->do_io_close();
87     _vc = nullptr;
88   }
89 
90   // Make sure the we are at the bottom of the stack
91   if (connection_state.is_recursing() || this->recursion != 0) {
92     // Note that we are ready to be cleaned up
93     // One of the event handlers will catch it
94     kill_me = true;
95     return;
96   }
97 
98   REMEMBER(NO_EVENT, this->recursion)
99   Http2SsnDebug("session free");
100 
101   if (this->_reenable_event) {
102     this->_reenable_event->cancel();
103     this->_reenable_event = nullptr;
104   }
105 
106   // Don't free active ProxySession
107   ink_release_assert(is_active() == false);
108 
109   this->_milestones.mark(Http2SsnMilestone::CLOSE);
110   ink_hrtime total_time = this->_milestones.elapsed(Http2SsnMilestone::OPEN, Http2SsnMilestone::CLOSE);
111 
112   // Slow Log
113   if (Http2::con_slow_log_threshold != 0 && ink_hrtime_from_msec(Http2::con_slow_log_threshold) < total_time) {
114     Error("[%" PRIu64 "] Slow H2 Connection: open: %" PRIu64 " close: %.3f", this->con_id,
115           ink_hrtime_to_msec(this->_milestones[Http2SsnMilestone::OPEN]),
116           this->_milestones.difference_sec(Http2SsnMilestone::OPEN, Http2SsnMilestone::CLOSE));
117   }
118 
119   HTTP2_DECREMENT_THREAD_DYN_STAT(HTTP2_STAT_CURRENT_CLIENT_SESSION_COUNT, this->mutex->thread_holding);
120 
121   // Update stats on how we died.  May want to eliminate this.  Was useful for
122   // tracking down which cases we were having problems cleaning up.  But for general
123   // use probably not worth the effort
124   if (cause_of_death != Http2SessionCod::NOT_PROVIDED) {
125     switch (cause_of_death) {
126     case Http2SessionCod::HIGH_ERROR_RATE:
127       HTTP2_INCREMENT_THREAD_DYN_STAT(HTTP2_STAT_SESSION_DIE_HIGH_ERROR_RATE, this_ethread());
128       break;
129     case Http2SessionCod::NOT_PROVIDED:
130       // Can't happen but this case is here to not have default case.
131       HTTP2_INCREMENT_THREAD_DYN_STAT(HTTP2_STAT_SESSION_DIE_OTHER, this_ethread());
132       break;
133     }
134   } else {
135     switch (dying_event) {
136     case VC_EVENT_NONE:
137       HTTP2_INCREMENT_THREAD_DYN_STAT(HTTP2_STAT_SESSION_DIE_DEFAULT, this_ethread());
138       break;
139     case VC_EVENT_ACTIVE_TIMEOUT:
140       HTTP2_INCREMENT_THREAD_DYN_STAT(HTTP2_STAT_SESSION_DIE_ACTIVE, this_ethread());
141       break;
142     case VC_EVENT_INACTIVITY_TIMEOUT:
143       HTTP2_INCREMENT_THREAD_DYN_STAT(HTTP2_STAT_SESSION_DIE_INACTIVE, this_ethread());
144       break;
145     case VC_EVENT_ERROR:
146       HTTP2_INCREMENT_THREAD_DYN_STAT(HTTP2_STAT_SESSION_DIE_ERROR, this_ethread());
147       break;
148     case VC_EVENT_EOS:
149       HTTP2_INCREMENT_THREAD_DYN_STAT(HTTP2_STAT_SESSION_DIE_EOS, this_ethread());
150       break;
151     default:
152       HTTP2_INCREMENT_THREAD_DYN_STAT(HTTP2_STAT_SESSION_DIE_OTHER, this_ethread());
153       break;
154     }
155   }
156 
157   ink_release_assert(this->_vc == nullptr);
158 
159   delete _h2_pushed_urls;
160   this->connection_state.destroy();
161 
162   free_MIOBuffer(this->read_buffer);
163   free_MIOBuffer(this->write_buffer);
164   THREAD_FREE(this, http2ClientSessionAllocator, this_ethread());
165 }
166 
167 void
start()168 Http2ClientSession::start()
169 {
170   SCOPED_MUTEX_LOCK(lock, this->mutex, this_ethread());
171 
172   SET_HANDLER(&Http2ClientSession::main_event_handler);
173   HTTP2_SET_SESSION_HANDLER(&Http2ClientSession::state_read_connection_preface);
174 
175   VIO *read_vio = this->do_io_read(this, INT64_MAX, this->read_buffer);
176   write_vio     = this->do_io_write(this, INT64_MAX, this->_write_buffer_reader);
177 
178   this->connection_state.init();
179   send_connection_event(&this->connection_state, HTTP2_SESSION_EVENT_INIT, this);
180 
181   if (this->_read_buffer_reader->is_read_avail_more_than(0)) {
182     this->handleEvent(VC_EVENT_READ_READY, read_vio);
183   }
184 }
185 
186 void
new_connection(NetVConnection * new_vc,MIOBuffer * iobuf,IOBufferReader * reader)187 Http2ClientSession::new_connection(NetVConnection *new_vc, MIOBuffer *iobuf, IOBufferReader *reader)
188 {
189   ink_assert(new_vc->mutex->thread_holding == this_ethread());
190   HTTP2_INCREMENT_THREAD_DYN_STAT(HTTP2_STAT_CURRENT_CLIENT_SESSION_COUNT, new_vc->mutex->thread_holding);
191   HTTP2_INCREMENT_THREAD_DYN_STAT(HTTP2_STAT_TOTAL_CLIENT_CONNECTION_COUNT, new_vc->mutex->thread_holding);
192   this->_milestones.mark(Http2SsnMilestone::OPEN);
193 
194   // Unique client session identifier.
195   this->con_id = ProxySession::next_connection_id();
196   this->_vc    = new_vc;
197   _vc->set_inactivity_timeout(HRTIME_SECONDS(Http2::accept_no_activity_timeout));
198   this->schedule_event = nullptr;
199   this->mutex          = new_vc->mutex;
200   this->in_destroy     = false;
201 
202   this->connection_state.mutex = this->mutex;
203 
204   SSLNetVConnection *ssl_vc = dynamic_cast<SSLNetVConnection *>(new_vc);
205   if (ssl_vc != nullptr) {
206     this->read_from_early_data = ssl_vc->read_from_early_data;
207     Debug("ssl_early_data", "read_from_early_data = %" PRId64, this->read_from_early_data);
208   }
209 
210   Http2SsnDebug("session born, netvc %p", this->_vc);
211 
212   this->_vc->set_tcp_congestion_control(CLIENT_SIDE);
213 
214   this->read_buffer             = iobuf ? iobuf : new_MIOBuffer(HTTP2_HEADER_BUFFER_SIZE_INDEX);
215   this->read_buffer->water_mark = connection_state.server_settings.get(HTTP2_SETTINGS_MAX_FRAME_SIZE);
216   this->_read_buffer_reader     = reader ? reader : this->read_buffer->alloc_reader();
217 
218   // This block size is the buffer size that we pass to SSLWriteBuffer
219   auto buffer_block_size_index = iobuffer_size_to_index(Http2::write_buffer_block_size, MAX_BUFFER_SIZE_INDEX);
220   this->write_buffer           = new_MIOBuffer(buffer_block_size_index);
221   this->_write_buffer_reader   = this->write_buffer->alloc_reader();
222   this->_write_size_threshold  = index_to_buffer_size(buffer_block_size_index) * Http2::write_size_threshold;
223 
224   this->_handle_if_ssl(new_vc);
225 
226   do_api_callout(TS_HTTP_SSN_START_HOOK);
227 }
228 
229 // XXX Currently, we don't have a half-closed state, but we will need to
230 // implement that. After we send a GOAWAY, there
231 // are scenarios where we would like to complete the outstanding streams.
232 
233 void
do_io_close(int alerrno)234 Http2ClientSession::do_io_close(int alerrno)
235 {
236   REMEMBER(NO_EVENT, this->recursion)
237   Http2SsnDebug("session closed");
238 
239   ink_assert(this->mutex->thread_holding == this_ethread());
240   send_connection_event(&this->connection_state, HTTP2_SESSION_EVENT_FINI, this);
241 
242   {
243     SCOPED_MUTEX_LOCK(lock, this->connection_state.mutex, this_ethread());
244     this->connection_state.release_stream();
245   }
246 
247   this->clear_session_active();
248 
249   // Clean up the write VIO in case of inactivity timeout
250   this->do_io_write(this, 0, nullptr);
251 }
252 
253 void
set_half_close_local_flag(bool flag)254 Http2ClientSession::set_half_close_local_flag(bool flag)
255 {
256   if (!half_close_local && flag) {
257     Http2SsnDebug("session half-close local");
258   }
259   half_close_local = flag;
260 }
261 
262 int64_t
xmit(const Http2TxFrame & frame,bool flush)263 Http2ClientSession::xmit(const Http2TxFrame &frame, bool flush)
264 {
265   int64_t len = frame.write_to(this->write_buffer);
266   this->_pending_sending_data_size += len;
267   // Force flush for some cases
268   if (!flush) {
269     // Flush if we already use half of the buffer to avoid adding a new block to the chain.
270     // A frame size can be 16MB at maximum so blocks can be added, but that's fine.
271     if (this->_pending_sending_data_size >= this->_write_size_threshold) {
272       flush = true;
273     }
274   }
275 
276   if (flush) {
277     this->flush();
278   }
279 
280   return len;
281 }
282 
283 void
flush()284 Http2ClientSession::flush()
285 {
286   if (this->_pending_sending_data_size > 0) {
287     this->_pending_sending_data_size = 0;
288     this->_write_buffer_last_flush   = Thread::get_hrtime();
289     write_reenable();
290   }
291 }
292 
293 int
main_event_handler(int event,void * edata)294 Http2ClientSession::main_event_handler(int event, void *edata)
295 {
296   ink_assert(this->mutex->thread_holding == this_ethread());
297   int retval;
298 
299   recursion++;
300 
301   Event *e = static_cast<Event *>(edata);
302   if (e == schedule_event) {
303     schedule_event = nullptr;
304   }
305 
306   switch (event) {
307   case VC_EVENT_READ_COMPLETE:
308   case VC_EVENT_READ_READY: {
309     bool is_zombie = connection_state.get_zombie_event() != nullptr;
310     retval         = (this->*session_handler)(event, edata);
311     if (is_zombie && connection_state.get_zombie_event() != nullptr) {
312       Warning("Processed read event for zombie session %" PRId64, connection_id());
313     }
314     break;
315   }
316 
317   case HTTP2_SESSION_EVENT_REENABLE:
318     // VIO will be reenableed in this handler
319     retval = (this->*session_handler)(VC_EVENT_READ_READY, static_cast<VIO *>(e->cookie));
320     // Clear the event after calling session_handler to not reschedule REENABLE in it
321     this->_reenable_event = nullptr;
322     break;
323 
324   case VC_EVENT_ACTIVE_TIMEOUT:
325   case VC_EVENT_INACTIVITY_TIMEOUT:
326   case VC_EVENT_ERROR:
327   case VC_EVENT_EOS:
328     Http2SsnDebug("Closing event %d", event);
329     this->set_dying_event(event);
330     this->do_io_close();
331     retval = 0;
332     break;
333 
334   case VC_EVENT_WRITE_READY:
335   case VC_EVENT_WRITE_COMPLETE:
336     this->connection_state.restart_streams();
337     if ((Thread::get_hrtime() >= this->_write_buffer_last_flush + HRTIME_MSECONDS(this->_write_time_threshold))) {
338       this->flush();
339     }
340     retval = 0;
341     break;
342 
343   case HTTP2_SESSION_EVENT_XMIT:
344   default:
345     Http2SsnDebug("unexpected event=%d edata=%p", event, edata);
346     ink_release_assert(0);
347     retval = 0;
348     break;
349   }
350 
351   if (!this->is_draining() && this->connection_state.get_shutdown_reason() == Http2ErrorCode::HTTP2_ERROR_MAX) {
352     this->connection_state.set_shutdown_state(HTTP2_SHUTDOWN_NONE);
353   }
354 
355   if (this->connection_state.get_shutdown_state() == HTTP2_SHUTDOWN_NONE) {
356     if (this->is_draining()) { // For a case we already checked Connection header and it didn't exist
357       Http2SsnDebug("Preparing for graceful shutdown because of draining state");
358       this->connection_state.set_shutdown_state(HTTP2_SHUTDOWN_NOT_INITIATED);
359     } else if (this->connection_state.get_stream_error_rate() >
360                Http2::stream_error_rate_threshold) { // For a case many stream errors happened
361       ip_port_text_buffer ipb;
362       const char *client_ip = ats_ip_ntop(get_remote_addr(), ipb, sizeof(ipb));
363       Warning("HTTP/2 session error client_ip=%s session_id=%" PRId64
364               " closing a connection, because its stream error rate (%f) exceeded the threshold (%f)",
365               client_ip, connection_id(), this->connection_state.get_stream_error_rate(), Http2::stream_error_rate_threshold);
366       Http2SsnDebug("Preparing for graceful shutdown because of a high stream error rate");
367       cause_of_death = Http2SessionCod::HIGH_ERROR_RATE;
368       this->connection_state.set_shutdown_state(HTTP2_SHUTDOWN_NOT_INITIATED, Http2ErrorCode::HTTP2_ERROR_ENHANCE_YOUR_CALM);
369     }
370   }
371 
372   if (this->connection_state.get_shutdown_state() == HTTP2_SHUTDOWN_NOT_INITIATED) {
373     send_connection_event(&this->connection_state, HTTP2_SESSION_EVENT_SHUTDOWN_INIT, this);
374   }
375 
376   recursion--;
377   if (!connection_state.is_recursing() && this->recursion == 0 && kill_me) {
378     this->free();
379   }
380   return retval;
381 }
382 
383 int
state_read_connection_preface(int event,void * edata)384 Http2ClientSession::state_read_connection_preface(int event, void *edata)
385 {
386   VIO *vio = static_cast<VIO *>(edata);
387 
388   STATE_ENTER(&Http2ClientSession::state_read_connection_preface, event);
389   ink_assert(event == VC_EVENT_READ_COMPLETE || event == VC_EVENT_READ_READY);
390 
391   if (this->_read_buffer_reader->read_avail() >= static_cast<int64_t>(HTTP2_CONNECTION_PREFACE_LEN)) {
392     char buf[HTTP2_CONNECTION_PREFACE_LEN];
393     unsigned nbytes;
394 
395     nbytes = copy_from_buffer_reader(buf, this->_read_buffer_reader, sizeof(buf));
396     ink_release_assert(nbytes == HTTP2_CONNECTION_PREFACE_LEN);
397 
398     if (memcmp(HTTP2_CONNECTION_PREFACE, buf, nbytes) != 0) {
399       Http2SsnDebug("invalid connection preface");
400       this->do_io_close();
401       return 0;
402     }
403 
404     // Check whether data is read from early data
405     if (this->read_from_early_data > 0) {
406       this->read_from_early_data -= this->read_from_early_data > nbytes ? nbytes : this->read_from_early_data;
407     }
408 
409     Http2SsnDebug("received connection preface");
410     this->_read_buffer_reader->consume(nbytes);
411     HTTP2_SET_SESSION_HANDLER(&Http2ClientSession::state_start_frame_read);
412 
413     _vc->set_inactivity_timeout(HRTIME_SECONDS(Http2::no_activity_timeout_in));
414     _vc->set_active_timeout(HRTIME_SECONDS(Http2::active_timeout_in));
415 
416     // XXX start the write VIO ...
417 
418     // If we have unconsumed data, start tranferring frames now.
419     if (this->_read_buffer_reader->is_read_avail_more_than(0)) {
420       return this->handleEvent(VC_EVENT_READ_READY, vio);
421     }
422   }
423 
424   // XXX We don't have enough data to check the connection preface. We should
425   // reset the accept inactivity
426   // timeout. We should have a maximum timeout to get the session started
427   // though.
428 
429   vio->reenable();
430   return 0;
431 }
432 
433 int
state_start_frame_read(int event,void * edata)434 Http2ClientSession::state_start_frame_read(int event, void *edata)
435 {
436   VIO *vio = static_cast<VIO *>(edata);
437 
438   STATE_ENTER(&Http2ClientSession::state_start_frame_read, event);
439   ink_assert(event == VC_EVENT_READ_COMPLETE || event == VC_EVENT_READ_READY);
440   return state_process_frame_read(event, vio, false);
441 }
442 
443 int
do_start_frame_read(Http2ErrorCode & ret_error)444 Http2ClientSession::do_start_frame_read(Http2ErrorCode &ret_error)
445 {
446   ret_error = Http2ErrorCode::HTTP2_ERROR_NO_ERROR;
447   ink_release_assert(this->_read_buffer_reader->read_avail() >= (int64_t)HTTP2_FRAME_HEADER_LEN);
448 
449   uint8_t buf[HTTP2_FRAME_HEADER_LEN];
450   unsigned nbytes;
451 
452   Http2SsnDebug("receiving frame header");
453   nbytes = copy_from_buffer_reader(buf, this->_read_buffer_reader, sizeof(buf));
454 
455   this->cur_frame_from_early_data = false;
456   if (!http2_parse_frame_header(make_iovec(buf), this->current_hdr)) {
457     Http2SsnDebug("frame header parse failure");
458     this->do_io_close();
459     return -1;
460   }
461 
462   // Check whether data is read from early data
463   if (this->read_from_early_data > 0) {
464     this->read_from_early_data -= this->read_from_early_data > nbytes ? nbytes : this->read_from_early_data;
465     this->cur_frame_from_early_data = true;
466   }
467 
468   Http2SsnDebug("frame header length=%u, type=%u, flags=0x%x, streamid=%u", (unsigned)this->current_hdr.length,
469                 (unsigned)this->current_hdr.type, (unsigned)this->current_hdr.flags, this->current_hdr.streamid);
470 
471   this->_read_buffer_reader->consume(nbytes);
472 
473   if (!http2_frame_header_is_valid(this->current_hdr, this->connection_state.server_settings.get(HTTP2_SETTINGS_MAX_FRAME_SIZE))) {
474     ret_error = Http2ErrorCode::HTTP2_ERROR_PROTOCOL_ERROR;
475     return -1;
476   }
477 
478   // If we know up front that the payload is too long, nuke this connection.
479   if (this->current_hdr.length > this->connection_state.server_settings.get(HTTP2_SETTINGS_MAX_FRAME_SIZE)) {
480     ret_error = Http2ErrorCode::HTTP2_ERROR_FRAME_SIZE_ERROR;
481     return -1;
482   }
483 
484   // CONTINUATIONs MUST follow behind HEADERS which doesn't have END_HEADERS
485   Http2StreamId continued_stream_id = this->connection_state.get_continued_stream_id();
486 
487   if (continued_stream_id != 0 &&
488       (continued_stream_id != this->current_hdr.streamid || this->current_hdr.type != HTTP2_FRAME_TYPE_CONTINUATION)) {
489     ret_error = Http2ErrorCode::HTTP2_ERROR_PROTOCOL_ERROR;
490     return -1;
491   }
492   return 0;
493 }
494 
495 int
state_complete_frame_read(int event,void * edata)496 Http2ClientSession::state_complete_frame_read(int event, void *edata)
497 {
498   VIO *vio = static_cast<VIO *>(edata);
499   STATE_ENTER(&Http2ClientSession::state_complete_frame_read, event);
500   ink_assert(event == VC_EVENT_READ_COMPLETE || event == VC_EVENT_READ_READY);
501   if (this->_read_buffer_reader->read_avail() < this->current_hdr.length) {
502     if (this->_should_do_something_else()) {
503       if (this->_reenable_event == nullptr) {
504         vio->disable();
505         this->_reenable_event = mutex->thread_holding->schedule_in(this, HRTIME_MSECONDS(1), HTTP2_SESSION_EVENT_REENABLE, vio);
506       } else {
507         vio->reenable();
508       }
509     } else {
510       vio->reenable();
511     }
512     return 0;
513   }
514   Http2SsnDebug("completed frame read, %" PRId64 " bytes available", this->_read_buffer_reader->read_avail());
515 
516   return state_process_frame_read(event, vio, true);
517 }
518 
519 int
do_complete_frame_read()520 Http2ClientSession::do_complete_frame_read()
521 {
522   // XXX parse the frame and handle it ...
523   ink_release_assert(this->_read_buffer_reader->read_avail() >= this->current_hdr.length);
524 
525   Http2Frame frame(this->current_hdr, this->_read_buffer_reader, this->cur_frame_from_early_data);
526   send_connection_event(&this->connection_state, HTTP2_SESSION_EVENT_RECV, &frame);
527   // Check whether data is read from early data
528   if (this->read_from_early_data > 0) {
529     this->read_from_early_data -=
530       this->read_from_early_data > this->current_hdr.length ? this->current_hdr.length : this->read_from_early_data;
531   }
532   this->_read_buffer_reader->consume(this->current_hdr.length);
533   ++(this->_n_frame_read);
534 
535   // Set the event handler if there is no more data to process a new frame
536   HTTP2_SET_SESSION_HANDLER(&Http2ClientSession::state_start_frame_read);
537 
538   return 0;
539 }
540 
541 int
state_process_frame_read(int event,VIO * vio,bool inside_frame)542 Http2ClientSession::state_process_frame_read(int event, VIO *vio, bool inside_frame)
543 {
544   if (inside_frame) {
545     do_complete_frame_read();
546   }
547 
548   while (this->_read_buffer_reader->read_avail() >= static_cast<int64_t>(HTTP2_FRAME_HEADER_LEN)) {
549     // Cancel reading if there was an error or connection is closed
550     if (connection_state.tx_error_code.code != static_cast<uint32_t>(Http2ErrorCode::HTTP2_ERROR_NO_ERROR) ||
551         connection_state.is_state_closed()) {
552       Http2SsnDebug("reading a frame has been canceled (%u)", connection_state.tx_error_code.code);
553       break;
554     }
555 
556     Http2ErrorCode err = Http2ErrorCode::HTTP2_ERROR_NO_ERROR;
557     if (this->connection_state.get_stream_error_rate() > std::min(1.0, Http2::stream_error_rate_threshold * 2.0)) {
558       ip_port_text_buffer ipb;
559       const char *client_ip = ats_ip_ntop(get_remote_addr(), ipb, sizeof(ipb));
560       Warning("HTTP/2 session error client_ip=%s session_id=%" PRId64
561               " closing a connection, because its stream error rate (%f) exceeded the threshold (%f)",
562               client_ip, connection_id(), this->connection_state.get_stream_error_rate(), Http2::stream_error_rate_threshold);
563       err = Http2ErrorCode::HTTP2_ERROR_ENHANCE_YOUR_CALM;
564     }
565 
566     // Return if there was an error
567     if (err > Http2ErrorCode::HTTP2_ERROR_NO_ERROR || do_start_frame_read(err) < 0) {
568       // send an error if specified.  Otherwise, just go away
569       if (err > Http2ErrorCode::HTTP2_ERROR_NO_ERROR) {
570         SCOPED_MUTEX_LOCK(lock, this->connection_state.mutex, this_ethread());
571         if (!this->connection_state.is_state_closed()) {
572           this->connection_state.send_goaway_frame(this->connection_state.get_latest_stream_id_in(), err);
573           this->set_half_close_local_flag(true);
574         }
575       }
576       return 0;
577     }
578 
579     // If there is no more data to finish the frame, set up the event handler and reenable
580     if (this->_read_buffer_reader->read_avail() < this->current_hdr.length) {
581       HTTP2_SET_SESSION_HANDLER(&Http2ClientSession::state_complete_frame_read);
582       break;
583     }
584     do_complete_frame_read();
585 
586     if (this->_should_do_something_else()) {
587       if (this->_reenable_event == nullptr) {
588         vio->disable();
589         this->_reenable_event = mutex->thread_holding->schedule_in(this, HRTIME_MSECONDS(1), HTTP2_SESSION_EVENT_REENABLE, vio);
590         return 0;
591       }
592     }
593   }
594 
595   // If the client hasn't shut us down, reenable
596   if (!this->is_client_closed()) {
597     vio->reenable();
598   }
599   return 0;
600 }
601 
602 void
increment_current_active_connections_stat()603 Http2ClientSession::increment_current_active_connections_stat()
604 {
605   HTTP2_INCREMENT_THREAD_DYN_STAT(HTTP2_STAT_CURRENT_ACTIVE_CLIENT_CONNECTION_COUNT, this_ethread());
606 }
607 
608 void
decrement_current_active_connections_stat()609 Http2ClientSession::decrement_current_active_connections_stat()
610 {
611   HTTP2_DECREMENT_THREAD_DYN_STAT(HTTP2_STAT_CURRENT_ACTIVE_CLIENT_CONNECTION_COUNT, this_ethread());
612 }
613 
614 void
remember(const SourceLocation & location,int event,int reentrant)615 Http2ClientSession::remember(const SourceLocation &location, int event, int reentrant)
616 {
617   this->_history.push_back(location, event, reentrant);
618 }
619 
620 bool
_should_do_something_else()621 Http2ClientSession::_should_do_something_else()
622 {
623   // Do something else every 128 incoming frames if connection state isn't closed
624   return (this->_n_frame_read & 0x7F) == 0 && !connection_state.is_state_closed();
625 }
626 
627 sockaddr const *
get_remote_addr() const628 Http2ClientSession::get_remote_addr() const
629 {
630   return _vc ? _vc->get_remote_addr() : &cached_client_addr.sa;
631 }
632 
633 sockaddr const *
get_local_addr()634 Http2ClientSession::get_local_addr()
635 {
636   return _vc ? _vc->get_local_addr() : &cached_local_addr.sa;
637 }
638 
639 int64_t
write_avail()640 Http2ClientSession::write_avail()
641 {
642   return this->write_buffer->write_avail();
643 }
644 
645 void
write_reenable()646 Http2ClientSession::write_reenable()
647 {
648   write_vio->reenable();
649 }
650 
651 int
get_transact_count() const652 Http2ClientSession::get_transact_count() const
653 {
654   return connection_state.get_stream_requests();
655 }
656 
657 void
release(ProxyTransaction * trans)658 Http2ClientSession::release(ProxyTransaction *trans)
659 {
660 }
661 
662 const char *
get_protocol_string() const663 Http2ClientSession::get_protocol_string() const
664 {
665   return "http/2";
666 }
667 
668 int
populate_protocol(std::string_view * result,int size) const669 Http2ClientSession::populate_protocol(std::string_view *result, int size) const
670 {
671   int retval = 0;
672   if (size > retval) {
673     result[retval++] = IP_PROTO_TAG_HTTP_2_0;
674     if (size > retval) {
675       retval += super::populate_protocol(result + retval, size - retval);
676     }
677   }
678   return retval;
679 }
680 
681 const char *
protocol_contains(std::string_view prefix) const682 Http2ClientSession::protocol_contains(std::string_view prefix) const
683 {
684   const char *retval = nullptr;
685 
686   if (prefix.size() <= IP_PROTO_TAG_HTTP_2_0.size() && strncmp(IP_PROTO_TAG_HTTP_2_0.data(), prefix.data(), prefix.size()) == 0) {
687     retval = IP_PROTO_TAG_HTTP_2_0.data();
688   } else {
689     retval = super::protocol_contains(prefix);
690   }
691   return retval;
692 }
693 
694 void
add_url_to_pushed_table(const char * url,int url_len)695 Http2ClientSession::add_url_to_pushed_table(const char *url, int url_len)
696 {
697   // Delay std::unordered_set allocation until when it used
698   if (_h2_pushed_urls == nullptr) {
699     this->_h2_pushed_urls = new std::unordered_set<std::string>();
700     this->_h2_pushed_urls->reserve(Http2::push_diary_size);
701   }
702 
703   if (_h2_pushed_urls->size() < Http2::push_diary_size) {
704     _h2_pushed_urls->emplace(url);
705   }
706 }
707