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 #pragma once 25 26 #include <atomic> 27 28 #include "NetTimeout.h" 29 30 #include "HTTP2.h" 31 #include "HPACK.h" 32 #include "Http2Stream.h" 33 #include "Http2DependencyTree.h" 34 #include "Http2FrequencyCounter.h" 35 36 class Http2ClientSession; 37 38 enum class Http2SendDataFrameResult { 39 NO_ERROR = 0, 40 NO_WINDOW, 41 NO_PAYLOAD, 42 NOT_WRITE_AVAIL, 43 ERROR, 44 DONE, 45 }; 46 47 enum Http2ShutdownState { HTTP2_SHUTDOWN_NONE, HTTP2_SHUTDOWN_NOT_INITIATED, HTTP2_SHUTDOWN_INITIATED, HTTP2_SHUTDOWN_IN_PROGRESS }; 48 49 class Http2ConnectionSettings 50 { 51 public: Http2ConnectionSettings()52 Http2ConnectionSettings() 53 { 54 // 6.5.2. Defined SETTINGS Parameters. These should generally not be 55 // modified, 56 // only if the protocol changes should these change. 57 settings[indexof(HTTP2_SETTINGS_ENABLE_PUSH)] = HTTP2_ENABLE_PUSH; 58 settings[indexof(HTTP2_SETTINGS_MAX_CONCURRENT_STREAMS)] = HTTP2_MAX_CONCURRENT_STREAMS; 59 settings[indexof(HTTP2_SETTINGS_INITIAL_WINDOW_SIZE)] = HTTP2_INITIAL_WINDOW_SIZE; 60 settings[indexof(HTTP2_SETTINGS_MAX_FRAME_SIZE)] = HTTP2_MAX_FRAME_SIZE; 61 settings[indexof(HTTP2_SETTINGS_HEADER_TABLE_SIZE)] = HTTP2_HEADER_TABLE_SIZE; 62 settings[indexof(HTTP2_SETTINGS_MAX_HEADER_LIST_SIZE)] = HTTP2_MAX_HEADER_LIST_SIZE; 63 } 64 65 void settings_from_configs()66 settings_from_configs() 67 { 68 settings[indexof(HTTP2_SETTINGS_MAX_CONCURRENT_STREAMS)] = Http2::max_concurrent_streams_in; 69 settings[indexof(HTTP2_SETTINGS_INITIAL_WINDOW_SIZE)] = Http2::initial_window_size; 70 settings[indexof(HTTP2_SETTINGS_MAX_FRAME_SIZE)] = Http2::max_frame_size; 71 settings[indexof(HTTP2_SETTINGS_HEADER_TABLE_SIZE)] = Http2::header_table_size; 72 settings[indexof(HTTP2_SETTINGS_MAX_HEADER_LIST_SIZE)] = Http2::max_header_list_size; 73 } 74 75 unsigned get(Http2SettingsIdentifier id)76 get(Http2SettingsIdentifier id) const 77 { 78 if (0 < id && id < HTTP2_SETTINGS_MAX) { 79 return this->settings[indexof(id)]; 80 } else { 81 ink_assert(!"Bad Settings Identifier"); 82 } 83 84 return 0; 85 } 86 87 unsigned set(Http2SettingsIdentifier id,unsigned value)88 set(Http2SettingsIdentifier id, unsigned value) 89 { 90 if (0 < id && id < HTTP2_SETTINGS_MAX) { 91 return this->settings[indexof(id)] = value; 92 } else { 93 // Do nothing - 6.5.2 Unsupported parameters MUST be ignored 94 } 95 96 return 0; 97 } 98 99 private: 100 // Settings ID is 1-based, so convert it to a 0-based index. 101 static unsigned indexof(Http2SettingsIdentifier id)102 indexof(Http2SettingsIdentifier id) 103 { 104 ink_assert(0 < id && id < HTTP2_SETTINGS_MAX); 105 106 return id - 1; 107 } 108 109 unsigned settings[HTTP2_SETTINGS_MAX - 1]; 110 }; 111 112 // Http2ConnectionState 113 // 114 // Capture the semantics of a HTTP/2 connection. The client session captures the 115 // frame layer, and the 116 // connection state captures the connection-wide state. 117 118 class Http2ConnectionState : public Continuation 119 { 120 public: Http2ConnectionState()121 Http2ConnectionState() : stream_list() { SET_HANDLER(&Http2ConnectionState::main_event_handler); } 122 123 ProxyError rx_error_code; 124 ProxyError tx_error_code; 125 Http2ClientSession *ua_session = nullptr; 126 HpackHandle *local_hpack_handle = nullptr; 127 HpackHandle *remote_hpack_handle = nullptr; 128 DependencyTree *dependency_tree = nullptr; 129 ActivityCop<Http2Stream> _cop; 130 131 // Settings. 132 Http2ConnectionSettings server_settings; 133 Http2ConnectionSettings client_settings; 134 135 void init()136 init() 137 { 138 this->_server_rwnd = Http2::initial_window_size; 139 140 local_hpack_handle = new HpackHandle(HTTP2_HEADER_TABLE_SIZE); 141 remote_hpack_handle = new HpackHandle(HTTP2_HEADER_TABLE_SIZE); 142 if (Http2::stream_priority_enabled) { 143 dependency_tree = new DependencyTree(Http2::max_concurrent_streams_in); 144 } 145 146 _cop = ActivityCop<Http2Stream>(this->mutex, &stream_list, 1); 147 _cop.start(); 148 } 149 150 void destroy()151 destroy() 152 { 153 if (in_destroy) { 154 schedule_zombie_event(); 155 return; 156 } 157 in_destroy = true; 158 159 _cop.stop(); 160 161 if (shutdown_cont_event) { 162 shutdown_cont_event->cancel(); 163 shutdown_cont_event = nullptr; 164 } 165 cleanup_streams(); 166 167 delete local_hpack_handle; 168 local_hpack_handle = nullptr; 169 delete remote_hpack_handle; 170 remote_hpack_handle = nullptr; 171 delete dependency_tree; 172 dependency_tree = nullptr; 173 this->ua_session = nullptr; 174 175 if (fini_event) { 176 fini_event->cancel(); 177 } 178 if (zombie_event) { 179 zombie_event->cancel(); 180 } 181 // release the mutex after the events are cancelled and sessions are destroyed. 182 mutex = nullptr; // magic happens - assigning to nullptr frees the ProxyMutex 183 } 184 185 // Event handlers 186 int main_event_handler(int, void *); 187 int state_closed(int, void *); 188 189 // Stream control interfaces 190 Http2Stream *create_stream(Http2StreamId new_id, Http2Error &error); 191 Http2Stream *find_stream(Http2StreamId id) const; 192 void restart_streams(); 193 bool delete_stream(Http2Stream *stream); 194 void release_stream(); 195 void cleanup_streams(); 196 void restart_receiving(Http2Stream *stream); 197 void update_initial_rwnd(Http2WindowSize new_size); 198 199 Http2StreamId get_latest_stream_id_in()200 get_latest_stream_id_in() const 201 { 202 return latest_streamid_in; 203 } 204 205 Http2StreamId get_latest_stream_id_out()206 get_latest_stream_id_out() const 207 { 208 return latest_streamid_out; 209 } 210 211 int get_stream_requests()212 get_stream_requests() const 213 { 214 return stream_requests; 215 } 216 217 void increment_stream_requests()218 increment_stream_requests() 219 { 220 stream_requests++; 221 } 222 223 // Continuated header decoding 224 Http2StreamId get_continued_stream_id()225 get_continued_stream_id() const 226 { 227 return continued_stream_id; 228 } 229 void set_continued_stream_id(Http2StreamId stream_id)230 set_continued_stream_id(Http2StreamId stream_id) 231 { 232 continued_stream_id = stream_id; 233 } 234 void clear_continued_stream_id()235 clear_continued_stream_id() 236 { 237 continued_stream_id = 0; 238 } 239 240 uint32_t get_client_stream_count()241 get_client_stream_count() const 242 { 243 return client_streams_in_count; 244 } 245 246 void decrement_stream_count()247 decrement_stream_count() 248 { 249 --total_client_streams_count; 250 } 251 252 double get_stream_error_rate()253 get_stream_error_rate() const 254 { 255 int total = get_stream_requests(); 256 257 if (total >= (1 / Http2::stream_error_rate_threshold)) { 258 return (double)stream_error_count / (double)total; 259 } else { 260 return 0; 261 } 262 } 263 264 Http2ErrorCode get_shutdown_reason()265 get_shutdown_reason() const 266 { 267 return shutdown_reason; 268 } 269 270 // HTTP/2 frame sender 271 void schedule_stream(Http2Stream *stream); 272 void send_data_frames_depends_on_priority(); 273 void send_data_frames(Http2Stream *stream); 274 Http2SendDataFrameResult send_a_data_frame(Http2Stream *stream, size_t &payload_length); 275 void send_headers_frame(Http2Stream *stream); 276 bool send_push_promise_frame(Http2Stream *stream, URL &url, const MIMEField *accept_encoding); 277 void send_rst_stream_frame(Http2StreamId id, Http2ErrorCode ec); 278 void send_settings_frame(const Http2ConnectionSettings &new_settings); 279 void send_ping_frame(Http2StreamId id, uint8_t flag, const uint8_t *opaque_data); 280 void send_goaway_frame(Http2StreamId id, Http2ErrorCode ec); 281 void send_window_update_frame(Http2StreamId id, uint32_t size); 282 283 bool is_state_closed()284 is_state_closed() const 285 { 286 return ua_session == nullptr || fini_received; 287 } 288 289 bool is_recursing()290 is_recursing() const 291 { 292 return recursion > 0; 293 } 294 295 bool is_valid_streamid(Http2StreamId id)296 is_valid_streamid(Http2StreamId id) const 297 { 298 if (http2_is_client_streamid(id)) { 299 return id <= get_latest_stream_id_in(); 300 } else { 301 return id <= get_latest_stream_id_out(); 302 } 303 } 304 305 Http2ShutdownState get_shutdown_state()306 get_shutdown_state() const 307 { 308 return shutdown_state; 309 } 310 311 void 312 set_shutdown_state(Http2ShutdownState state, Http2ErrorCode reason = Http2ErrorCode::HTTP2_ERROR_NO_ERROR) 313 { 314 shutdown_state = state; 315 shutdown_reason = reason; 316 } 317 318 // noncopyable 319 Http2ConnectionState(const Http2ConnectionState &) = delete; 320 Http2ConnectionState &operator=(const Http2ConnectionState &) = delete; 321 322 Event * get_zombie_event()323 get_zombie_event() 324 { 325 return zombie_event; 326 } 327 328 void schedule_zombie_event()329 schedule_zombie_event() 330 { 331 if (Http2::zombie_timeout_in) { // If we have zombie debugging enabled 332 if (zombie_event) { 333 zombie_event->cancel(); 334 } 335 zombie_event = this_ethread()->schedule_in(this, HRTIME_SECONDS(Http2::zombie_timeout_in)); 336 } 337 } 338 339 void increment_received_settings_count(uint32_t count); 340 uint32_t get_received_settings_count(); 341 void increment_received_settings_frame_count(); 342 uint32_t get_received_settings_frame_count(); 343 void increment_received_ping_frame_count(); 344 uint32_t get_received_ping_frame_count(); 345 void increment_received_priority_frame_count(); 346 uint32_t get_received_priority_frame_count(); 347 348 ssize_t client_rwnd() const; 349 Http2ErrorCode increment_client_rwnd(size_t amount); 350 Http2ErrorCode decrement_client_rwnd(size_t amount); 351 ssize_t server_rwnd() const; 352 Http2ErrorCode increment_server_rwnd(size_t amount); 353 Http2ErrorCode decrement_server_rwnd(size_t amount); 354 355 private: 356 unsigned _adjust_concurrent_stream(); 357 358 // NOTE: 'stream_list' has only active streams. 359 // If given Stream Identifier is not found in stream_list and it is less 360 // than or equal to latest_streamid_in, the state of Stream 361 // is CLOSED. 362 // If given Stream Identifier is not found in stream_list and it is greater 363 // than latest_streamid_in, the state of Stream is IDLE. 364 Queue<Http2Stream> stream_list; 365 Http2StreamId latest_streamid_in = 0; 366 Http2StreamId latest_streamid_out = 0; 367 std::atomic<int> stream_requests = 0; 368 369 // Counter for current active streams which is started by client 370 std::atomic<uint32_t> client_streams_in_count = 0; 371 372 // Counter for current active streams which is started by server 373 std::atomic<uint32_t> client_streams_out_count = 0; 374 375 // Counter for current active streams and streams in the process of shutting down 376 std::atomic<uint32_t> total_client_streams_count = 0; 377 378 // Counter for stream errors ATS sent 379 uint32_t stream_error_count = 0; 380 381 // Connection level window size 382 ssize_t _client_rwnd = HTTP2_INITIAL_WINDOW_SIZE; 383 ssize_t _server_rwnd = 0; 384 385 std::vector<size_t> _recent_rwnd_increment = {SIZE_MAX, SIZE_MAX, SIZE_MAX, SIZE_MAX, SIZE_MAX}; 386 int _recent_rwnd_increment_index = 0; 387 388 Http2FrequencyCounter _received_settings_counter; 389 Http2FrequencyCounter _received_settings_frame_counter; 390 Http2FrequencyCounter _received_ping_frame_counter; 391 Http2FrequencyCounter _received_priority_frame_counter; 392 393 // NOTE: Id of stream which MUST receive CONTINUATION frame. 394 // - [RFC 7540] 6.2 HEADERS 395 // "A HEADERS frame without the END_HEADERS flag set MUST be followed by a 396 // CONTINUATION frame for the same stream." 397 // - [RFC 7540] 6.10 CONTINUATION 398 // "If the END_HEADERS bit is not set, this frame MUST be followed by 399 // another CONTINUATION frame." 400 Http2StreamId continued_stream_id = 0; 401 bool _scheduled = false; 402 bool fini_received = false; 403 bool in_destroy = false; 404 int recursion = 0; 405 Http2ShutdownState shutdown_state = HTTP2_SHUTDOWN_NONE; 406 Http2ErrorCode shutdown_reason = Http2ErrorCode::HTTP2_ERROR_MAX; 407 Event *shutdown_cont_event = nullptr; 408 Event *fini_event = nullptr; 409 Event *zombie_event = nullptr; 410 }; 411