h2_comm.c (19386B)
1 /* SPDX-License-Identifier: LGPL-2.1-or-later OR (GPL-2.0-or-later WITH eCos-exception-2.0) */ 2 /* 3 This file is part of GNU libmicrohttpd. 4 Copyright (C) 2025 Evgeny Grin (Karlson2k) 5 6 GNU libmicrohttpd is free software; you can redistribute it and/or 7 modify it under the terms of the GNU Lesser General Public 8 License as published by the Free Software Foundation; either 9 version 2.1 of the License, or (at your option) any later version. 10 11 GNU libmicrohttpd is distributed in the hope that it will be useful, 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 Lesser General Public License for more details. 15 16 Alternatively, you can redistribute GNU libmicrohttpd and/or 17 modify it under the terms of the GNU General Public License as 18 published by the Free Software Foundation; either version 2 of 19 the License, or (at your option) any later version, together 20 with the eCos exception, as follows: 21 22 As a special exception, if other files instantiate templates or 23 use macros or inline functions from this file, or you compile this 24 file and link it with other works to produce a work based on this 25 file, this file does not by itself cause the resulting work to be 26 covered by the GNU General Public License. However the source code 27 for this file must still be made available in accordance with 28 section (3) of the GNU General Public License v2. 29 30 This exception does not invalidate any other reasons why a work 31 based on this file might be covered by the GNU General Public 32 License. 33 34 You should have received copies of the GNU Lesser General Public 35 License and the GNU General Public License along with this library; 36 if not, see <https://www.gnu.org/licenses/>. 37 */ 38 39 /** 40 * @file src/mhd2/h2/h2_comm.c 41 * @brief Implementation of HTTP/2 connection communication functions 42 * @author Karlson2k (Evgeny Grin) 43 */ 44 45 #include "mhd_sys_options.h" 46 47 #include "sys_bool_type.h" 48 #include "sys_base_types.h" 49 50 #include <string.h> 51 52 #include "mhd_unreachable.h" 53 #include "mhd_constexpr.h" 54 #include "mhd_assert.h" 55 56 #include "mhd_connection.h" 57 #include "mhd_daemon.h" 58 59 #include "mempool_funcs.h" 60 61 #ifdef MHD_SUPPORT_HTTPS 62 # include "mhd_tls_funcs.h" 63 #endif 64 65 #include "respond_with_error.h" 66 #include "stream_funcs.h" 67 #include "daemon_logger.h" 68 69 #include "h2_req_items_funcs.h" 70 #include "h2_frame_codec.h" 71 #include "h2_proc_settings.h" 72 #include "h2_proc_conn.h" 73 #include "h2_proc_in.h" 74 #include "h2_conn_streams.h" 75 #include "hpack/mhd_hpack_codec.h" 76 77 #include "h2_comm.h" 78 79 #ifndef HAVE_NULL_PTR_ALL_ZEROS 80 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ void 81 mhd_h2_blank_init (struct MHD_Connection *restrict c) 82 { 83 c->write_buffer = NULL; 84 } 85 86 87 #endif /* HAVE_NULL_PTR_ALL_ZEROS */ 88 89 /** 90 * HTTP/2 connection preface 91 * 92 * Extracted from RFC 9113, Section 3.4 93 */ 94 mhd_constexpr uint8_t mhd_h2_preface[mhd_H2_PREFACE_LEN] = { 95 0x50u, 0x52u, 0x49u, 0x20u, 0x2Au, 0x20u, 0x48u, 0x54u, 0x54u, 0x50u, 96 0x2Fu, 0x32u, 0x2Eu, 0x30u, 0x0Du, 0x0Au, 0x0Du, 0x0Au, 0x53u, 0x4Du, 97 0x0Du, 0x0Au, 0x0Du, 0x0Au 98 }; 99 100 101 /** 102 * Result of HTTP/2 preface check 103 */ 104 enum MHD_FIXED_ENUM_ mhd_H2PrefaceCheckResult 105 { 106 /** 107 * Received data matches HTTP/2 preface 108 */ 109 mhd_H2_PREFACE_CHECK_IS_HTTP2 110 , 111 /** 112 * Received data does not match HTTP/2 preface 113 */ 114 mhd_H2_PREFACE_CHECK_IS_NOT_HTTP2 115 , 116 /** 117 * Not enough data has been received 118 */ 119 mhd_H2_PREFACE_CHECK_NEED_MORE_DATA 120 }; 121 122 /** 123 * Check HTTP/2 connection preface 124 * @param c the connection to process 125 * @return enum mhd_H2PrefaceCheckResult status code 126 */ 127 mhd_static_inline MHD_FN_PAR_NONNULL_ALL_ enum mhd_H2PrefaceCheckResult 128 mhd_h2_check_preface (struct MHD_Connection *restrict c) 129 { 130 bool have_enough_data; 131 132 mhd_assert (mhd_HTTP_LAYER_PREFACE == c->h_layer.state); 133 mhd_assert (NULL != c->read_buffer); 134 mhd_assert (mhd_H2_PREFACE_LEN <= c->read_buffer_size); 135 136 if (0u == c->read_buffer_offset) 137 return mhd_H2_PREFACE_CHECK_NEED_MORE_DATA; 138 139 have_enough_data = (mhd_H2_PREFACE_LEN <= c->read_buffer_offset); 140 141 if (0 != 142 memcmp (mhd_h2_preface, 143 c->read_buffer, 144 have_enough_data ? mhd_H2_PREFACE_LEN : c->read_buffer_offset)) 145 return mhd_H2_PREFACE_CHECK_IS_NOT_HTTP2; 146 147 return (have_enough_data ? 148 mhd_H2_PREFACE_CHECK_IS_HTTP2 : mhd_H2_PREFACE_CHECK_NEED_MORE_DATA); 149 } 150 151 152 #define ERR_RSP_H2_NOT_SUPPORTED \ 153 "<html><head><title>HTTP/2 is not supported</title></head>" \ 154 "<body>HTTP/2 protocol is not supported.</body></html>" 155 156 #define ERR_RSP_H2_WITH_ALPN_HTTP1 \ 157 "<html><head><title>HTTP/2 without matching ALPN</title></head>" \ 158 "<body>ALPN selected HTTP/1.x protocol, HTTP/2 cannot be used " \ 159 "over TLS if ALPN selected another application protocol.</body></html>" 160 161 #define ERR_RSP_H2_WITHOUT_ALPN \ 162 "<html><head><title>HTTP/2 without ALPN on HTTPS</title></head>" \ 163 "<body>HTTP/2 cannot be used over TLS without ALPN.</body></html>" 164 165 /** 166 * Perform switching connection to HTTP/2 mode 167 * @param c the connection to switch 168 * @return 'true' if switched successfully, 169 * 'false' if connection is broken and should be closed 170 */ 171 static MHD_FN_PAR_NONNULL_ALL_ bool 172 h2_switch_to_h2 (struct MHD_Connection *restrict c) 173 { 174 size_t buff_size; 175 mhd_assert (mhd_HTTP_LAYER_PREFACE == c->h_layer.state); 176 mhd_assert (mhd_H2_PREFACE_LEN <= c->read_buffer_offset); 177 mhd_assert (mhd_HTTP_VER_FAM_NOT_SET == c->h_layer.fam); 178 179 mhd_DLINKEDL_INIT_LIST_D (&(c->h2.streams.active)); 180 mhd_DLINKEDL_INIT_LIST_D (&(c->h2.streams.send_q)); 181 c->h2.streams.num_streams = 0u; 182 183 c->h2.state.init.got_setns = false; 184 c->h2.state.init.sent_setns = false; 185 186 c->h2.state.sent_setns_noakc = 0u; 187 188 c->h2.state.send_window = mhd_H2_STNG_DEF_INIT_WIN_SIZE; 189 c->h2.state.recv_window = mhd_H2_STNG_DEF_INIT_WIN_SIZE; 190 191 c->h2.state.top_seen_stream_id = 0u; 192 193 // TODO: make some parameters configurable 194 c->h2.rcv_cfg.stream_init_win_sz = 0x7FFFFFFFu; 195 c->h2.rcv_cfg.conn_full_win_sz = 0x7FFFFFFFu; 196 c->h2.rcv_cfg.max_frame_size = mhd_H2_STNG_DEF_MAX_FRAME_SIZE; 197 c->h2.rcv_cfg.max_header_list = 16u * 1024u; 198 c->h2.rcv_cfg.max_concur_streams = 100u; 199 200 c->h2.peer.stream_init_win_sz = mhd_H2_STNG_DEF_INIT_WIN_SIZE; 201 c->h2.peer.max_frame_size = mhd_H2_STNG_DEF_MAX_FRAME_SIZE; 202 c->h2.peer.max_header_list = (uint_least32_t) (~((uint_least32_t) 0u)); 203 c->h2.peer.max_concur_streams = (uint_least32_t) (~((uint_least32_t) 0u)); 204 205 buff_size = mhd_pool_get_size (c->pool); 206 c->read_buffer = 207 (char *) 208 mhd_pool_reset (c->pool, 209 c->read_buffer, 210 c->read_buffer_offset, 211 buff_size); 212 mhd_assert (NULL != c->read_buffer); 213 c->read_buffer_size = buff_size; 214 c->h2.buff.r_cur_frame = mhd_H2_PREFACE_LEN; 215 216 c->h2.mem.send_pool = 217 mhd_pool_create (c->daemon->conns.cfg.mem_pool_size, 218 c->daemon->conns.cfg.mem_pool_zeroing); 219 if (NULL != c->h2.mem.send_pool) 220 { 221 buff_size = mhd_pool_get_size (c->h2.mem.send_pool); 222 c->write_buffer = 223 (char *) 224 mhd_pool_allocate (c->h2.mem.send_pool, 225 buff_size, 226 false); 227 mhd_assert (NULL != c->write_buffer); 228 c->write_buffer_size = buff_size; 229 c->write_buffer_append_offset = 0u; 230 c->write_buffer_send_offset = 0u; 231 232 if (mhd_hpack_dec_init (&(c->h2.hk_dec))) 233 { 234 if (mhd_hpack_enc_init (&(c->h2.hk_enc))) 235 { 236 // TODO: make the size configurable 237 c->h2.mem.req_ib = mhd_h2_items_block_create (16u * 1024); 238 239 if (NULL != c->h2.mem.req_ib) 240 { 241 c->h_layer.fam = mhd_HTTP_VER_FAM_2; 242 c->h_layer.state = mhd_HTTP_LAYER_CONNECTED; 243 244 return true; /* Success exit point */ 245 } 246 /* Clean-up */ 247 mhd_hpack_enc_deinit (&(c->h2.hk_enc)); 248 } 249 mhd_hpack_dec_deinit (&(c->h2.hk_dec)); 250 } 251 c->write_buffer = NULL; 252 mhd_pool_destroy (c->h2.mem.send_pool); 253 c->h2.mem.send_pool = NULL; 254 mhd_LOG_MSG (c->daemon, MHD_SC_H2_CONN_MEM_ALLOC_FAILURE, \ 255 "Failed to allocate memory for the HTTP/2 " 256 "connection resources."); 257 } 258 else 259 mhd_LOG_MSG (c->daemon, MHD_SC_POOL_MEM_ALLOC_FAILURE, \ 260 "Failed to allocate memory for the HTTP/2 send buffer."); 261 262 mhd_conn_start_closing_no_sys_res (c); 263 c->h_layer.fam = mhd_HTTP_VER_FAM_NOT_SET; 264 c->h_layer.state = mhd_HTTP_LAYER_BROKEN; 265 return false; 266 } 267 268 269 /** 270 * Perform de-initialisation of HTTP/2-specific data and start connection 271 * closing 272 * @param c the connection to de-initialise 273 */ 274 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ void 275 mhd_h2_conn_h2_deinit_start_closing (struct MHD_Connection *restrict c) 276 { 277 mhd_assert (mhd_C_IS_HTTP2 (c)); 278 mhd_assert ((mhd_HTTP_LAYER_CONNECTED == c->h_layer.state) || 279 (mhd_HTTP_LAYER_CLOSING == c->h_layer.state) || 280 (mhd_HTTP_LAYER_BROKEN == c->h_layer.state)); 281 mhd_assert (! c->h2.dbg.h2_deinited); 282 283 mhd_h2_conn_close_streams_all (c); 284 285 mhd_h2_items_block_destroy (c->h2.mem.req_ib); 286 c->h2.mem.req_ib = NULL; 287 mhd_hpack_enc_deinit (&(c->h2.hk_enc)); 288 mhd_hpack_dec_deinit (&(c->h2.hk_dec)); 289 290 mhd_assert (NULL != c->write_buffer); 291 mhd_assert (NULL != c->h2.mem.send_pool); 292 c->write_buffer_send_offset = 0u; 293 c->write_buffer_append_offset = 0u; 294 c->write_buffer_size = 0u; 295 c->write_buffer = NULL; 296 mhd_pool_destroy (c->h2.mem.send_pool); 297 c->h2.mem.send_pool = NULL; 298 299 #ifndef NDEBUG 300 c->h2.dbg.h2_deinited = true; 301 #endif /* ! NDEBUG */ 302 303 if ((mhd_HTTP_LAYER_BROKEN == c->h_layer.state) || 304 (mhd_SOCKET_ERR_NO_ERROR != c->sk.state.discnt_err) || 305 (0 != (c->sk.ready & mhd_SOCKET_NET_STATE_ERROR_READY))) 306 mhd_conn_start_closing_h2_hard (c); 307 else 308 mhd_conn_start_closing_h2_soft (c); 309 310 if (mhd_HTTP_LAYER_CLOSED > c->h_layer.state) 311 c->h_layer.state = mhd_HTTP_LAYER_CLOSED; 312 } 313 314 315 /** 316 * Handle detection of HTTP/2 preface 317 * @param c the connection to process 318 * @return 'true' if connection should be continued to be processed as 319 * HTTP connection (possibly to send already scheduled error 320 * response), 321 * 'false' if connection is broken and should be closed 322 */ 323 static MHD_FN_PAR_NONNULL_ALL_ bool 324 h2_handle_preface_found (struct MHD_Connection *restrict c) 325 { 326 const bool allow_on_alpn_mismatch = 327 (c->daemon->req_cfg.strictness <= MHD_PSL_EXTRA_PERMISSIVE); 328 const bool allow_without_alpn = 329 (c->daemon->req_cfg.strictness <= MHD_PSL_PERMISSIVE); 330 331 mhd_assert (mhd_HTTP_LAYER_PREFACE == c->h_layer.state); 332 mhd_assert (mhd_H2_PREFACE_LEN <= c->read_buffer_offset); 333 334 if (! mhd_D_IS_HTTP2_ENABLED (c->daemon)) 335 { 336 c->h_layer.state = mhd_HTTP_LAYER_CONNECTED; 337 c->h_layer.fam = mhd_HTTP_VER_FAM_NOT_2; 338 mhd_RESPOND_WITH_ERROR_STATIC (c, 339 MHD_HTTP_STATUS_HTTP_VERSION_NOT_SUPPORTED, 340 ERR_RSP_H2_NOT_SUPPORTED); 341 return true; /* Send error response */ 342 } 343 344 #ifdef MHD_SUPPORT_HTTPS 345 if (mhd_C_HAS_TLS (c)) 346 { 347 switch (mhd_tls_conn_get_alpn_prot (c->tls)) 348 { 349 case mhd_TLS_ALPN_PROT_HTTP1_0: 350 case mhd_TLS_ALPN_PROT_HTTP1_1: 351 if (! allow_on_alpn_mismatch) 352 { 353 c->h_layer.state = mhd_HTTP_LAYER_CONNECTED; 354 c->h_layer.fam = mhd_HTTP_VER_FAM_NOT_2; 355 mhd_RESPOND_WITH_ERROR_STATIC (c, 356 MHD_HTTP_STATUS_BAD_REQUEST, 357 ERR_RSP_H2_WITH_ALPN_HTTP1); 358 return true; /* Send error response */ 359 } 360 break; 361 case mhd_TLS_ALPN_PROT_HTTP2: 362 break; 363 case mhd_TLS_ALPN_PROT_NOT_SELECTED: 364 case mhd_TLS_ALPN_PROT_ERROR: 365 if (! allow_without_alpn) 366 { 367 c->h_layer.state = mhd_HTTP_LAYER_CONNECTED; 368 c->h_layer.fam = mhd_HTTP_VER_FAM_NOT_2; 369 mhd_RESPOND_WITH_ERROR_STATIC (c, 370 MHD_HTTP_STATUS_BAD_REQUEST, 371 ERR_RSP_H2_WITHOUT_ALPN); 372 return true; /* Send error response */ 373 } 374 break; 375 default: 376 mhd_UNREACHABLE (); 377 return false; 378 } 379 } 380 #endif /* MHD_SUPPORT_HTTPS */ 381 return h2_switch_to_h2 (c); 382 } 383 384 385 #define ERR_RSP_H2_REQUIRED \ 386 "<html><head><title>HTTP/2 is required</title></head>" \ 387 "<body>HTTP/2 protocol is required</body></html>" 388 389 #define ERR_RSP_NOT_H2_WITH_ALPN_H2 \ 390 "<html><head><title>ALPN selected HTTP/2</title></head>" \ 391 "<body>ALPN selected HTTP/2 protocol, " \ 392 "only HTTP/2 communication could be used.</body></html>" 393 394 /** 395 * Handle absence of HTTP/2 preface 396 * @param c the connection to process 397 * @return 'true' if connection should be continued to be processed as 398 * HTTP connection (possibly to send already scheduled error 399 * response), 400 * 'false' if connection is broken and should be closed 401 */ 402 static MHD_FN_PAR_NONNULL_ALL_ bool 403 h2_handle_preface_not_found (struct MHD_Connection *restrict c) 404 { 405 const bool allow_on_alpn_mismatch = 406 (c->daemon->req_cfg.strictness <= MHD_PSL_EXTRA_PERMISSIVE); 407 408 mhd_assert (mhd_HTTP_LAYER_PREFACE == c->h_layer.state); 409 mhd_assert (mhd_H2_PREFACE_LEN <= c->read_buffer_offset); 410 411 #ifdef MHD_SUPPORT_HTTPS 412 if (mhd_C_HAS_TLS (c)) 413 { 414 switch (mhd_tls_conn_get_alpn_prot (c->tls)) 415 { 416 case mhd_TLS_ALPN_PROT_HTTP1_0: 417 case mhd_TLS_ALPN_PROT_HTTP1_1: 418 case mhd_TLS_ALPN_PROT_NOT_SELECTED: 419 case mhd_TLS_ALPN_PROT_ERROR: 420 break; 421 case mhd_TLS_ALPN_PROT_HTTP2: 422 if (! allow_on_alpn_mismatch) 423 { 424 c->h_layer.state = mhd_HTTP_LAYER_BROKEN; 425 c->h_layer.fam = mhd_HTTP_VER_FAM_INVALID; 426 mhd_conn_start_closing (c, 427 mhd_CONN_CLOSE_H2_PREFACE_MISSING, 428 mhd_MSG4LOG ("No valid HTTP/2 preface on " \ 429 "TLS connection with 'h2' " 430 "selected by ALPN")); 431 return false; 432 } 433 break; 434 default: 435 mhd_UNREACHABLE (); 436 c->h_layer.state = mhd_HTTP_LAYER_BROKEN; 437 c->h_layer.fam = mhd_HTTP_VER_FAM_INVALID; 438 return false; 439 break; 440 } 441 } 442 #endif /* MHD_SUPPORT_HTTPS */ 443 444 if (! mhd_D_IS_HTTP1_ENABLED (c->daemon)) 445 { 446 c->h_layer.state = mhd_HTTP_LAYER_CONNECTED; 447 c->h_layer.fam = mhd_HTTP_VER_FAM_NOT_2; 448 mhd_RESPOND_WITH_ERROR_STATIC (c, 449 MHD_HTTP_STATUS_HTTP_VERSION_NOT_SUPPORTED, 450 ERR_RSP_H2_REQUIRED); 451 return true; /* Send error response */ 452 } 453 454 c->h_layer.state = mhd_HTTP_LAYER_CONNECTED; 455 c->h_layer.fam = mhd_HTTP_VER_FAM_NOT_2; 456 /* The data in the receive buffer will be re-interpreted as HTTP/1.x request */ 457 return true; 458 } 459 460 461 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ MHD_INTERNAL enum mhd_CommLayerState 462 mhd_h2_process_preface (struct MHD_Connection *restrict c) 463 { 464 mhd_assert (mhd_HTTP_LAYER_PREFACE == c->h_layer.state); 465 466 switch (mhd_h2_check_preface (c)) 467 { 468 case mhd_H2_PREFACE_CHECK_IS_HTTP2: 469 return 470 h2_handle_preface_found (c) ? mhd_COMM_LAYER_OK : mhd_COMM_LAYER_BROKEN; 471 case mhd_H2_PREFACE_CHECK_IS_NOT_HTTP2: 472 return 473 h2_handle_preface_not_found (c) ? 474 mhd_COMM_LAYER_OK : mhd_COMM_LAYER_BROKEN; 475 case mhd_H2_PREFACE_CHECK_NEED_MORE_DATA: 476 return mhd_COMM_LAYER_PROCESSING; 477 default: 478 break; 479 } 480 mhd_UNREACHABLE (); 481 return mhd_COMM_LAYER_BROKEN; 482 } 483 484 485 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ void 486 mhd_h2_conn_state_update (struct MHD_Connection *restrict c) 487 { 488 unsigned int new_state; 489 490 mhd_assert (mhd_C_IS_HTTP2 (c)); 491 492 mhd_assert (0u == (c->event_loop_info & MHD_EVENT_LOOP_INFO_CLEANUP)); 493 #ifdef MHD_SUPPORT_UPGRADE 494 mhd_assert (0u == (c->event_loop_info & MHD_EVENT_LOOP_INFO_UPGRADED)); 495 #endif /* MHD_SUPPORT_UPGRADE */ 496 497 new_state = 0u; 498 499 if (c->read_buffer_offset < c->read_buffer_size) 500 new_state |= (unsigned int) MHD_EVENT_LOOP_INFO_RECV; 501 502 if (c->write_buffer_send_offset < c->write_buffer_append_offset) 503 new_state |= (unsigned int) MHD_EVENT_LOOP_INFO_SEND; 504 505 c->event_loop_info = (enum MHD_ConnectionEventLoopInfo) new_state; 506 } 507 508 509 static MHD_FN_PAR_NONNULL_ALL_ void 510 h2_conn_manage_buff_out (struct MHD_Connection *restrict c) 511 { 512 mhd_assert (c->write_buffer_send_offset <= c->write_buffer_append_offset); 513 if (c->write_buffer_send_offset == c->write_buffer_append_offset) 514 { 515 c->write_buffer_send_offset = 0u; 516 c->write_buffer_append_offset = 0u; 517 } 518 else if ((0u != c->write_buffer_append_offset) && 519 (c->write_buffer_send_offset > c->write_buffer_size / 128)) 520 { 521 const size_t left_unsent = 522 c->write_buffer_append_offset - c->write_buffer_send_offset; 523 memmove (c->write_buffer, 524 c->write_buffer + c->write_buffer_send_offset, 525 left_unsent); 526 c->write_buffer_send_offset = 0u; 527 c->write_buffer_append_offset = left_unsent; 528 } 529 } 530 531 532 static MHD_FN_PAR_NONNULL_ALL_ void 533 h2_conn_process_data_inner (struct MHD_Connection *restrict c) 534 { 535 /* Check whether first SETTINGS frame was send (queued). 536 It is a part of connection initialisation. */ 537 if (! c->h2.state.init.sent_setns) 538 { 539 if (! mhd_h2_q_settings_first_fr (c)) 540 return; 541 } 542 /* Check whether first peer SETTINGS frame was received. 543 It is a part of connection initialisation. */ 544 if (! c->h2.state.init.got_setns) 545 { 546 if (! mhd_h2_conn_process_first_fr (c)) 547 return; /* HTTP/2 cannot be processed */ 548 } 549 550 h2_conn_manage_buff_out (c); 551 552 /* Process incoming data. 553 When incoming frames are processed, short control frames (such as 554 PING ACK, SETTINGS ACK, RST_STREAM) could be added to the sending buffer. 555 If connection is broken or output buffer has no space to add required 556 frame, this connection processing is stopped here until the output buffer 557 got more space. */ 558 if (! mhd_h2_conn_process_in_data (c)) 559 return; 560 561 /* Close broken streams, update receive windows. 562 Short control frames, like WINDOW_UPDATE, RST_STREAM could be added to the 563 sending buffer. 564 If connection is broken or output buffer has no space to add required 565 frame, this connection processing is stopped here until the output buffer 566 got more space. */ 567 if (! mhd_h2_conn_process_changes (c)) 568 return; 569 570 /* Finally send the replies (if output buffer still have any space). */ 571 mhd_h2_conn_process_streams_sending_queue (c); 572 573 return; 574 } 575 576 577 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ bool 578 mhd_h2_conn_process_data (struct MHD_Connection *restrict c) 579 { 580 mhd_assert (mhd_C_IS_HTTP2 (c)); 581 582 mhd_assert (mhd_HTTP_LAYER_CONNECTED <= c->h_layer.state); 583 mhd_assert (mhd_HTTP_LAYER_CLOSING >= c->h_layer.state); 584 585 if (mhd_HTTP_LAYER_CLOSING == c->h_layer.state) 586 { 587 if ((c->write_buffer_append_offset == c->write_buffer_send_offset) 588 || (mhd_SOCKET_ERR_NO_ERROR != c->sk.state.discnt_err)) 589 { 590 mhd_h2_conn_h2_deinit_start_closing (c); 591 return false; 592 } 593 return true; 594 } 595 596 h2_conn_process_data_inner (c); 597 598 mhd_assert (mhd_HTTP_LAYER_CLOSED != c->h_layer.state); 599 if ((mhd_SOCKET_ERR_NO_ERROR != c->sk.state.discnt_err) || 600 (mhd_HTTP_LAYER_CLOSING == c->h_layer.state)) 601 { 602 mhd_h2_conn_h2_deinit_start_closing (c); 603 return false; 604 } 605 606 return true; 607 }