stream_funcs.c (37744B)
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) 2022-2024 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/stream_funcs.c 41 * @brief The definition of the stream internal functions 42 * @author Karlson2k (Evgeny Grin) 43 */ 44 45 #include "mhd_sys_options.h" 46 47 #include "stream_funcs.h" 48 49 #include "mhd_assert.h" 50 #include "mhd_unreachable.h" 51 52 #ifdef mhd_DEBUG_CONN_ADD_CLOSE 53 # include <stdio.h> 54 #endif /* mhd_DEBUG_CONN_ADD_CLOSE */ 55 #include <string.h> 56 #include "extr_events_funcs.h" 57 #ifdef MHD_SUPPORT_EPOLL 58 # include <sys/epoll.h> 59 #endif 60 #include "sys_malloc.h" 61 62 #include "mhd_daemon.h" 63 #include "mhd_connection.h" 64 #include "mhd_response.h" 65 #include "mempool_funcs.h" 66 #include "mhd_str.h" 67 #include "mhd_str_macros.h" 68 69 #include "mhd_sockets_funcs.h" 70 71 #include "request_get_value.h" 72 #include "response_destroy.h" 73 #include "mhd_mono_clock.h" 74 #include "daemon_logger.h" 75 #include "daemon_funcs.h" 76 #include "conn_timeout.h" 77 #include "conn_mark_ready.h" 78 #include "stream_process_reply.h" 79 #include "extr_events_funcs.h" 80 81 #ifdef MHD_SUPPORT_HTTPS 82 # include "mhd_tls_funcs.h" 83 #endif 84 85 #include "mhd_public_api.h" 86 87 88 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ void * 89 mhd_stream_alloc_memory (struct MHD_Connection *restrict c, 90 size_t size) 91 { 92 struct mhd_MemoryPool *const restrict pool = c->pool; /* a short alias */ 93 size_t need_to_be_freed = 0; /**< The required amount of additional free memory */ 94 void *res; 95 96 res = mhd_pool_try_alloc (pool, 97 size, 98 &need_to_be_freed); 99 if (NULL != res) 100 return res; 101 102 if (mhd_pool_is_resizable_inplace (pool, 103 c->write_buffer, 104 c->write_buffer_size)) 105 { 106 if (c->write_buffer_size - c->write_buffer_append_offset >= 107 need_to_be_freed) 108 { 109 char *buf; 110 const size_t new_buf_size = c->write_buffer_size - need_to_be_freed; 111 buf = (char *) mhd_pool_reallocate (pool, 112 c->write_buffer, 113 c->write_buffer_size, 114 new_buf_size); 115 mhd_assert (c->write_buffer == buf); 116 mhd_assert (c->write_buffer_append_offset <= new_buf_size); 117 mhd_assert (c->write_buffer_send_offset <= new_buf_size); 118 c->write_buffer_size = new_buf_size; 119 c->write_buffer = buf; 120 } 121 else 122 return NULL; 123 } 124 else if (mhd_pool_is_resizable_inplace (pool, 125 c->read_buffer, 126 c->read_buffer_size)) 127 { 128 if (c->read_buffer_size - c->read_buffer_offset >= need_to_be_freed) 129 { 130 char *buf; 131 const size_t new_buf_size = c->read_buffer_size - need_to_be_freed; 132 buf = (char *) mhd_pool_reallocate (pool, 133 c->read_buffer, 134 c->read_buffer_size, 135 new_buf_size); 136 mhd_assert (c->read_buffer == buf); 137 mhd_assert (c->read_buffer_offset <= new_buf_size); 138 c->read_buffer_size = new_buf_size; 139 c->read_buffer = buf; 140 } 141 else 142 return NULL; 143 } 144 else 145 return NULL; 146 res = mhd_pool_allocate (pool, size, true); 147 mhd_assert (NULL != res); /* It has been checked that pool has enough space */ 148 return res; 149 } 150 151 152 /** 153 * Shrink stream read buffer to the zero size of free space in the buffer 154 * @param c the connection whose read buffer is being manipulated 155 */ 156 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ void 157 mhd_stream_shrink_read_buffer (struct MHD_Connection *restrict c) 158 { 159 void *new_buf; 160 161 if ((NULL == c->read_buffer) || (0 == c->read_buffer_size)) 162 { 163 mhd_assert (0 == c->read_buffer_size); 164 mhd_assert (0 == c->read_buffer_offset); 165 return; 166 } 167 168 mhd_assert (c->read_buffer_offset <= c->read_buffer_size); 169 if (0 == c->read_buffer_offset) 170 { 171 mhd_pool_deallocate (c->pool, c->read_buffer, c->read_buffer_size); 172 c->read_buffer = NULL; 173 c->read_buffer_size = 0; 174 } 175 else 176 { 177 mhd_assert (mhd_pool_is_resizable_inplace (c->pool, c->read_buffer, \ 178 c->read_buffer_size)); 179 new_buf = mhd_pool_reallocate (c->pool, c->read_buffer, c->read_buffer_size, 180 c->read_buffer_offset); 181 mhd_assert (c->read_buffer == new_buf); 182 c->read_buffer = (char *) new_buf; 183 c->read_buffer_size = c->read_buffer_offset; 184 } 185 } 186 187 188 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ size_t 189 mhd_stream_maximize_write_buffer (struct MHD_Connection *restrict c) 190 { 191 struct mhd_MemoryPool *const restrict pool = c->pool; 192 void *new_buf; 193 size_t new_size; 194 size_t free_size; 195 196 mhd_assert ((NULL != c->write_buffer) || (0 == c->write_buffer_size)); 197 mhd_assert (c->write_buffer_append_offset >= c->write_buffer_send_offset); 198 mhd_assert (c->write_buffer_size >= c->write_buffer_append_offset); 199 200 free_size = mhd_pool_get_free (pool); 201 if (0 != free_size) 202 { 203 new_size = c->write_buffer_size + free_size; 204 /* This function must not move the buffer position. 205 * mhd_pool_reallocate () may return the new position only if buffer was 206 * allocated 'from_end' or is not the last allocation, 207 * which should not happen. */ 208 mhd_assert ((NULL == c->write_buffer) || \ 209 mhd_pool_is_resizable_inplace (pool, c->write_buffer, \ 210 c->write_buffer_size)); 211 new_buf = mhd_pool_reallocate (pool, 212 c->write_buffer, 213 c->write_buffer_size, 214 new_size); 215 mhd_assert ((c->write_buffer == new_buf) || (NULL == c->write_buffer)); 216 c->write_buffer = (char *) new_buf; 217 c->write_buffer_size = new_size; 218 if (c->write_buffer_send_offset == c->write_buffer_append_offset) 219 { 220 /* All data have been sent, reset offsets to zero. */ 221 c->write_buffer_send_offset = 0; 222 c->write_buffer_append_offset = 0; 223 } 224 } 225 226 return c->write_buffer_size - c->write_buffer_append_offset; 227 } 228 229 230 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ void 231 mhd_stream_release_write_buffer (struct MHD_Connection *restrict c) 232 { 233 struct mhd_MemoryPool *const restrict pool = c->pool; 234 235 mhd_assert ((NULL != c->write_buffer) || (0 == c->write_buffer_size)); 236 mhd_assert (c->write_buffer_append_offset == c->write_buffer_send_offset); 237 mhd_assert (c->write_buffer_size >= c->write_buffer_append_offset); 238 239 mhd_pool_deallocate (pool, c->write_buffer, c->write_buffer_size); 240 c->write_buffer_send_offset = 0; 241 c->write_buffer_append_offset = 0; 242 c->write_buffer_size = 0; 243 c->write_buffer = NULL; 244 245 } 246 247 248 #ifndef MHD_MAX_REASONABLE_HEADERS_SIZE_ 249 /** 250 * A reasonable headers size (excluding request line) that should be sufficient 251 * for most requests. 252 * If incoming data buffer free space is not enough to process the complete 253 * header (the request line and all headers) and the headers size is larger than 254 * this size then the status code 431 "Request Header Fields Too Large" is 255 * returned to the client. 256 * The larger headers are processed by MHD if enough space is available. 257 */ 258 # define MHD_MAX_REASONABLE_HEADERS_SIZE_ (6 * 1024) 259 #endif /* ! MHD_MAX_REASONABLE_HEADERS_SIZE_ */ 260 261 #ifndef MHD_MAX_REASONABLE_REQ_TARGET_SIZE_ 262 /** 263 * A reasonable request target (the request URI) size that should be sufficient 264 * for most requests. 265 * If incoming data buffer free space is not enough to process the complete 266 * header (the request line and all headers) and the request target size is 267 * larger than this size then the status code 414 "URI Too Long" is 268 * returned to the client. 269 * The larger request targets are processed by MHD if enough space is available. 270 * The value chosen according to RFC 9112 Section 3, paragraph 5 271 */ 272 # define MHD_MAX_REASONABLE_REQ_TARGET_SIZE_ 8000 273 #endif /* ! MHD_MAX_REASONABLE_REQ_TARGET_SIZE_ */ 274 275 #ifndef MHD_MIN_REASONABLE_HEADERS_SIZE_ 276 /** 277 * A reasonable headers size (excluding request line) that should be sufficient 278 * for basic simple requests. 279 * When no space left in the receiving buffer try to avoid replying with 280 * the status code 431 "Request Header Fields Too Large" if headers size 281 * is smaller then this value. 282 */ 283 # define MHD_MIN_REASONABLE_HEADERS_SIZE_ 26 284 #endif /* ! MHD_MIN_REASONABLE_HEADERS_SIZE_ */ 285 286 #ifndef MHD_MIN_REASONABLE_REQ_TARGET_SIZE_ 287 /** 288 * A reasonable request target (the request URI) size that should be sufficient 289 * for basic simple requests. 290 * When no space left in the receiving buffer try to avoid replying with 291 * the status code 414 "URI Too Long" if the request target size is smaller then 292 * this value. 293 */ 294 # define MHD_MIN_REASONABLE_REQ_TARGET_SIZE_ 40 295 #endif /* ! MHD_MIN_REASONABLE_REQ_TARGET_SIZE_ */ 296 297 #ifndef MHD_MIN_REASONABLE_REQ_METHOD_SIZE_ 298 /** 299 * A reasonable request method string size that should be sufficient 300 * for basic simple requests. 301 * When no space left in the receiving buffer try to avoid replying with 302 * the status code 501 "Not Implemented" if the request method size is 303 * smaller then this value. 304 */ 305 # define MHD_MIN_REASONABLE_REQ_METHOD_SIZE_ 16 306 #endif /* ! MHD_MIN_REASONABLE_REQ_METHOD_SIZE_ */ 307 308 #ifndef MHD_MIN_REASONABLE_REQ_CHUNK_LINE_LENGTH_ 309 /** 310 * A reasonable minimal chunk line length. 311 * When no space left in the receiving buffer reply with 413 "Content Too Large" 312 * if the chunk line length is larger than this value. 313 */ 314 # define MHD_MIN_REASONABLE_REQ_CHUNK_LINE_LENGTH_ 4 315 #endif /* ! MHD_MIN_REASONABLE_REQ_CHUNK_LINE_LENGTH_ */ 316 317 318 MHD_INTERNAL 319 MHD_FN_PAR_NONNULL_ (1) MHD_FN_PAR_IN_SIZE_ (4,3) unsigned int 320 mhd_stream_get_no_space_err_status_code (struct MHD_Connection *restrict c, 321 enum MHD_ProcRecvDataStage stage, 322 size_t add_element_size, 323 const char *restrict add_element) 324 { 325 size_t method_size; 326 size_t uri_size; 327 size_t opt_headers_size; 328 size_t host_field_line_size; 329 330 mhd_assert ((0 == add_element_size) || (NULL != add_element)); 331 332 c->rq.too_large = true; 333 334 if (mhd_HTTP_STAGE_REQ_LINE_RECEIVED < c->stage) 335 { 336 if (mhd_HTTP_STAGE_HEADERS_RECEIVED > c->stage) 337 { 338 mhd_assert (NULL != c->rq.field_lines.start); 339 opt_headers_size = 340 (size_t) ((c->read_buffer + c->read_buffer_offset) 341 - c->rq.field_lines.start); 342 } 343 else 344 opt_headers_size = c->rq.field_lines.size; 345 } 346 else 347 opt_headers_size = 0u; 348 349 /* The read buffer is fully used by the request line, the field lines 350 (headers) and internal information. 351 The return status code works as a suggestion for the client to reduce 352 one of the request elements. */ 353 354 if ((MHD_PROC_RECV_BODY_CHUNKED == stage) && 355 (MHD_MIN_REASONABLE_REQ_CHUNK_LINE_LENGTH_ < add_element_size)) 356 { 357 /* Request could be re-tried easily with smaller chunk sizes */ 358 return MHD_HTTP_STATUS_CONTENT_TOO_LARGE; 359 } 360 361 host_field_line_size = 0; 362 /* The "Host:" field line is mandatory. 363 The total size of the field lines (headers) cannot be smaller than 364 the size of the "Host:" field line. */ 365 if ((MHD_PROC_RECV_HEADERS == stage) 366 && (0 != add_element_size)) 367 { 368 static const size_t header_host_key_len = 369 mhd_SSTR_LEN (MHD_HTTP_HEADER_HOST); 370 const bool is_host_header = 371 (header_host_key_len + 1 <= add_element_size) 372 && ( (0 == add_element[header_host_key_len]) 373 || (':' == add_element[header_host_key_len]) ) 374 && mhd_str_equal_caseless_bin_n (MHD_HTTP_HEADER_HOST, 375 add_element, 376 header_host_key_len); 377 if (is_host_header) 378 { 379 const bool is_parsed = ! ( 380 (mhd_HTTP_STAGE_HEADERS_RECEIVED > c->stage) && 381 (add_element_size == c->read_buffer_offset) && 382 (c->read_buffer == add_element) ); 383 size_t actual_element_size; 384 385 mhd_assert (! is_parsed || (0 == add_element[header_host_key_len])); 386 /* The actual size should be larger due to CRLF or LF chars, 387 however the exact termination sequence is not known here and 388 as perfect precision is not required, to simplify the code 389 assume the minimal length. */ 390 if (is_parsed) 391 actual_element_size = add_element_size + 1; /* "1" for LF */ 392 else 393 actual_element_size = add_element_size; 394 395 host_field_line_size = actual_element_size; 396 mhd_assert (opt_headers_size >= actual_element_size); 397 opt_headers_size -= actual_element_size; 398 } 399 } 400 if (0 == host_field_line_size) 401 { 402 static const size_t host_field_name_len = 403 mhd_SSTR_LEN (MHD_HTTP_HEADER_HOST); 404 struct MHD_StringNullable host_value; 405 406 if (mhd_request_get_value_n (&(c->rq), 407 MHD_VK_HEADER, 408 host_field_name_len, 409 MHD_HTTP_HEADER_HOST, 410 &host_value)) 411 { 412 /* Calculate the minimal size of the field line: no space between 413 colon and the field value, line terminated by LR */ 414 host_field_line_size = 415 host_field_name_len + host_value.len + 2; /* "2" for ':' and LF */ 416 417 /* The "Host:" field could be added by application */ 418 if (opt_headers_size >= host_field_line_size) 419 { 420 opt_headers_size -= host_field_line_size; 421 /* Take into account typical space after colon and CR at the end of the line */ 422 if (opt_headers_size >= 2) 423 opt_headers_size -= 2; 424 } 425 else 426 host_field_line_size = 0; /* No "Host:" field line set by the client */ 427 } 428 } 429 430 uri_size = c->rq.req_target_len; 431 if (mhd_HTTP_METHOD_OTHER != c->rq.http_mthd) 432 method_size = 0; /* Do not recommend shorter request method */ 433 else 434 { 435 mhd_assert (NULL != c->rq.method.cstr); 436 method_size = c->rq.method.len; 437 mhd_assert (method_size == strlen (c->rq.method.cstr)); 438 } 439 440 if ((size_t) MHD_MAX_REASONABLE_HEADERS_SIZE_ < opt_headers_size) 441 { 442 /* Typically the easiest way to reduce request header size is 443 a removal of some optional headers. */ 444 if (opt_headers_size > (uri_size / 8)) 445 { 446 if ((opt_headers_size / 2) > method_size) 447 return MHD_HTTP_STATUS_REQUEST_HEADER_FIELDS_TOO_LARGE; 448 else 449 return MHD_HTTP_STATUS_NOT_IMPLEMENTED; /* The length of the HTTP request method is unreasonably large */ 450 } 451 else 452 { /* Request target is MUCH larger than headers */ 453 if ((uri_size / 16) > method_size) 454 return MHD_HTTP_STATUS_URI_TOO_LONG; 455 else 456 return MHD_HTTP_STATUS_NOT_IMPLEMENTED; /* The length of the HTTP request method is unreasonably large */ 457 } 458 } 459 if ((size_t) MHD_MAX_REASONABLE_REQ_TARGET_SIZE_ < uri_size) 460 { 461 /* If request target size if larger than maximum reasonable size 462 recommend client to reduce the request target size (length). */ 463 if ((uri_size / 16) > method_size) 464 return MHD_HTTP_STATUS_URI_TOO_LONG; /* Request target is MUCH larger than headers */ 465 else 466 return MHD_HTTP_STATUS_NOT_IMPLEMENTED; /* The length of the HTTP request method is unreasonably large */ 467 } 468 469 /* The read buffer is too small to handle reasonably large requests */ 470 471 if ((size_t) MHD_MIN_REASONABLE_HEADERS_SIZE_ < opt_headers_size) 472 { 473 /* Recommend application to retry with minimal headers */ 474 if ((opt_headers_size * 4) > uri_size) 475 { 476 if (opt_headers_size > method_size) 477 return MHD_HTTP_STATUS_REQUEST_HEADER_FIELDS_TOO_LARGE; 478 else 479 return MHD_HTTP_STATUS_NOT_IMPLEMENTED; /* The length of the HTTP request method is unreasonably large */ 480 } 481 else 482 { /* Request target is significantly larger than headers */ 483 if (uri_size > method_size * 4) 484 return MHD_HTTP_STATUS_URI_TOO_LONG; 485 else 486 return MHD_HTTP_STATUS_NOT_IMPLEMENTED; /* The length of the HTTP request method is unreasonably large */ 487 } 488 } 489 if ((size_t) MHD_MIN_REASONABLE_REQ_TARGET_SIZE_ < uri_size) 490 { 491 /* Recommend application to retry with a shorter request target */ 492 if (uri_size > method_size * 4) 493 return MHD_HTTP_STATUS_URI_TOO_LONG; 494 else 495 return MHD_HTTP_STATUS_NOT_IMPLEMENTED; /* The length of the HTTP request method is unreasonably large */ 496 } 497 498 if ((size_t) MHD_MIN_REASONABLE_REQ_METHOD_SIZE_ < method_size) 499 { 500 /* The request target (URI) and headers are (reasonably) very small. 501 Some non-standard long request method is used. */ 502 /* The last resort response as it means "the method is not supported 503 by the server for any URI". */ 504 return MHD_HTTP_STATUS_NOT_IMPLEMENTED; 505 } 506 507 /* The almost impossible situation: all elements are small, but cannot 508 fit the buffer. The application set the buffer size to 509 critically low value? */ 510 511 if ((1 < opt_headers_size) || (1 < uri_size)) 512 { 513 if (opt_headers_size >= uri_size) 514 return MHD_HTTP_STATUS_REQUEST_HEADER_FIELDS_TOO_LARGE; 515 else 516 return MHD_HTTP_STATUS_URI_TOO_LONG; 517 } 518 519 /* Nothing to reduce in the request. 520 Reply with some status. */ 521 if (0 != host_field_line_size) 522 return MHD_HTTP_STATUS_REQUEST_HEADER_FIELDS_TOO_LARGE; 523 524 return MHD_HTTP_STATUS_URI_TOO_LONG; 525 } 526 527 528 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ void 529 mhd_stream_switch_from_recv_to_send (struct MHD_Connection *c) 530 { 531 /* Read buffer is not needed for this request, shrink it.*/ 532 mhd_stream_shrink_read_buffer (c); 533 } 534 535 536 /** 537 * Finish request serving. 538 * The stream will be re-used or closed. 539 * 540 * @param c the connection to use. 541 */ 542 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ void 543 mhd_stream_finish_req_serving (struct MHD_Connection *restrict c, 544 bool reuse) 545 { 546 struct MHD_Daemon *const restrict d = c->daemon; 547 548 if (! reuse) 549 { 550 mhd_assert (! c->stop_with_error || (NULL == c->rp.response) || \ 551 (c->rp.response->cfg.int_err_resp)); 552 553 /* Next function will notify client and set connection 554 * state to "PRE-CLOSING" */ 555 /* Later response and memory pool will be destroyed */ 556 mhd_conn_start_closing (c, 557 c->stop_with_error ? 558 mhd_CONN_CLOSE_ERR_REPLY_SENT : 559 mhd_CONN_CLOSE_HTTP_COMPLETED, 560 NULL); 561 } 562 else 563 { 564 /* Reset connection to process the next request */ 565 size_t new_read_buf_size; 566 mhd_assert (! c->stop_with_error); 567 mhd_assert (! c->discard_request); 568 mhd_assert (NULL == c->rq.cntn.lbuf.data); 569 570 #if 0 // TODO: notification callback 571 if ( (NULL != d->notify_completed) && 572 (c->rq.app_aware) ) 573 d->notify_completed (d->notify_completed_cls, 574 c, 575 &c->rq.app_context, 576 MHD_REQUEST_ENDED_COMPLETED_OK); 577 c->rq.app_aware = false; 578 #endif 579 580 mhd_stream_call_dcc_cleanup_if_needed (c); 581 if (NULL != c->rp.resp_iov.iov) 582 { 583 free (c->rp.resp_iov.iov); 584 c->rp.resp_iov.iov = NULL; 585 } 586 587 if (NULL != c->rp.response) 588 mhd_response_dec_use_count (c->rp.response); 589 c->rp.response = NULL; 590 591 c->conn_reuse = mhd_CONN_KEEPALIVE_POSSIBLE; 592 c->stage = mhd_HTTP_STAGE_INIT; 593 c->event_loop_info = MHD_EVENT_LOOP_INFO_RECV; /* Dummy state, real state set later */ 594 595 // TODO: move request reset to special function 596 memset (&c->rq, 0, sizeof(c->rq)); 597 598 // TODO: move reply reset to special function 599 /* iov (if any) will be deallocated by mhd_pool_reset */ 600 memset (&c->rp, 0, sizeof(c->rp)); 601 602 #ifndef HAVE_NULL_PTR_ALL_ZEROS 603 // TODO: move request reset to special function 604 mhd_DLINKEDL_INIT_LIST (&(c->rq), fields); 605 #ifdef MHD_SUPPORT_POST_PARSER 606 mhd_DLINKEDL_INIT_LIST (&(c->rq), post_fields); 607 #endif /* MHD_SUPPORT_POST_PARSER */ 608 c->rq.version = NULL; 609 c->rq.url = NULL; 610 c->rq.field_lines.start = NULL; 611 c->rq.app_context = NULL; 612 c->rq.hdrs.rq_line.rq_tgt = NULL; 613 c->rq.hdrs.rq_line.rq_tgt_qmark = NULL; 614 615 // TODO: move reply reset to special function 616 c->rp.app_act_ctx.connection = NULL; 617 c->rp.response = NULL; 618 c->rp.resp_iov.iov = NULL; 619 #endif /* ! HAVE_NULL_PTR_ALL_ZEROS */ 620 621 c->write_buffer = NULL; 622 c->write_buffer_size = 0; 623 c->write_buffer_send_offset = 0; 624 c->write_buffer_append_offset = 0; 625 c->continue_message_write_offset = 0; 626 627 /* Reset the read buffer to the starting size, 628 preserving the bytes we have already read. */ 629 new_read_buf_size = d->conns.cfg.mem_pool_size / 2; 630 if (c->read_buffer_offset > new_read_buf_size) 631 new_read_buf_size = c->read_buffer_offset; 632 633 c->read_buffer 634 = (char *) mhd_pool_reset (c->pool, 635 c->read_buffer, 636 c->read_buffer_offset, 637 new_read_buf_size); 638 c->read_buffer_size = new_read_buf_size; 639 } 640 c->rq.app_context = NULL; 641 } 642 643 644 /* return 'true' is lingering needed, 'false' is lingering is not needed */ 645 static MHD_FN_PAR_NONNULL_ALL_ bool 646 conn_start_socket_closing (struct MHD_Connection *restrict c, 647 bool close_hard) 648 { 649 bool need_lingering; 650 /* Make changes on the socket early to let the kernel and the remote 651 * to process the changes in parallel. */ 652 if (close_hard) 653 { 654 /* Use abortive closing, send RST to remote to indicate a problem */ 655 (void) mhd_socket_set_hard_close (c->sk.fd); 656 c->stage = mhd_HTTP_STAGE_PRE_CLOSING; 657 c->event_loop_info = MHD_EVENT_LOOP_INFO_CLEANUP; 658 659 return false; 660 } 661 662 mhd_assert (c->sk.state.rmt_shut_wr || \ 663 ! mhd_SOCKET_ERR_IS_HARD (c->sk.state.discnt_err)); 664 665 need_lingering = ! c->sk.state.rmt_shut_wr; 666 if (need_lingering) 667 { 668 #ifdef MHD_SUPPORT_HTTPS 669 if (mhd_C_HAS_TLS (c)) 670 { 671 if ((0 != (((unsigned int) c->sk.ready) 672 & mhd_SOCKET_NET_STATE_SEND_READY)) 673 || c->sk.props.is_nonblck) 674 need_lingering = 675 (mhd_TLS_PROCED_FAILED != mhd_tls_conn_shutdown (c->tls)); 676 } 677 else 678 #endif /* MHD_SUPPORT_HTTPS */ 679 if (1) 680 { 681 need_lingering = mhd_socket_shut_wr (c->sk.fd); 682 if (need_lingering) 683 need_lingering = (! c->sk.state.rmt_shut_wr); /* Skip as already closed */ 684 } 685 } 686 687 return need_lingering; 688 } 689 690 691 #ifdef MHD_SUPPORT_HTTP2 692 693 static MHD_FN_PAR_NONNULL_ALL_ void 694 conn_h2_start_closing (struct MHD_Connection *restrict c, 695 bool close_hard) 696 { 697 mhd_assert (mhd_C_IS_HTTP2 (c)); 698 mhd_assert (c->h2.dbg.h2_deinited); 699 mhd_assert (! c->rq.app_aware); 700 701 conn_start_socket_closing (c, 702 close_hard); 703 704 mhd_conn_deinit_activity_timeout (c); 705 706 #ifndef NDEBUG 707 c->dbg.closing_started = true; 708 #endif 709 } 710 711 712 #endif /* MHD_SUPPORT_HTTP2 */ 713 714 715 MHD_INTERNAL 716 MHD_FN_PAR_NONNULL_ (1) MHD_FN_PAR_CSTR_ (3) void 717 mhd_conn_start_closing (struct MHD_Connection *restrict c, 718 enum mhd_ConnCloseReason reason, 719 const char *log_msg) 720 { 721 bool close_hard; 722 enum MHD_RequestEndedCode end_code; 723 enum MHD_StatusCode sc; 724 bool reply_sending_aborted; 725 726 #ifdef mhd_DEBUG_CONN_ADD_CLOSE 727 fprintf (stderr, 728 "&&& mhd_conn_start_closing([FD: %2llu], %u, %s%s%s)...\n", 729 (unsigned long long) c->sk.fd, 730 (unsigned int) reason, 731 log_msg ? "\"" : "", 732 log_msg ? log_msg : "[NULL]", 733 log_msg ? "\"" : ""); 734 #endif /* mhd_DEBUG_CONN_ADD_CLOSE */ 735 736 #ifdef MHD_SUPPORT_HTTP2 737 if (mhd_C_IS_HTTP2 (c)) 738 { 739 mhd_assert ((mhd_CONN_CLOSE_TIMEDOUT == reason) || 740 (mhd_CONN_CLOSE_DAEMON_SHUTDOWN == reason) || 741 (mhd_CONN_CLOSE_H2_CLOSE_SOFT == reason) || 742 (mhd_CONN_CLOSE_H2_CLOSE_HARD == reason)); 743 mhd_assert (NULL == log_msg); 744 conn_h2_start_closing (c, 745 reason != mhd_CONN_CLOSE_H2_CLOSE_SOFT); 746 return; 747 } 748 #endif /* MHD_SUPPORT_HTTP2 */ 749 750 reply_sending_aborted = 751 ((mhd_HTTP_STAGE_HEADERS_SENDING <= c->stage) 752 && (mhd_HTTP_STAGE_FULL_REPLY_SENT > c->stage)); 753 sc = MHD_SC_INTERNAL_ERROR; 754 switch (reason) 755 { 756 case mhd_CONN_CLOSE_CLIENT_HTTP_ERR_ABORT_CONN: 757 close_hard = true; 758 end_code = MHD_REQUEST_ENDED_HTTP_PROTOCOL_ERROR; 759 sc = MHD_SC_REQ_MALFORMED; 760 mhd_assert (! reply_sending_aborted); 761 break; 762 case mhd_CONN_CLOSE_NO_POOL_MEM_FOR_REQUEST: 763 close_hard = true; 764 end_code = MHD_REQUEST_ENDED_NO_RESOURCES; 765 mhd_assert (! reply_sending_aborted); 766 break; 767 case mhd_CONN_CLOSE_CLIENT_SHUTDOWN_EARLY: 768 close_hard = true; 769 end_code = MHD_REQUEST_ENDED_CLIENT_ABORT; 770 sc = MHD_SC_CLIENT_SHUTDOWN_EARLY; 771 mhd_assert (! reply_sending_aborted); 772 break; 773 case mhd_CONN_CLOSE_H2_PREFACE_MISSING: 774 close_hard = true; 775 end_code = MHD_REQUEST_ENDED_HTTP_PROTOCOL_ERROR; 776 sc = MHD_SC_ALPN_H2_NO_PREFACE; 777 break; 778 case mhd_CONN_CLOSE_NO_POOL_MEM_FOR_REPLY: 779 close_hard = true; 780 end_code = (! c->stop_with_error || c->rq.too_large) ? 781 MHD_REQUEST_ENDED_NO_RESOURCES : 782 MHD_REQUEST_ENDED_HTTP_PROTOCOL_ERROR; 783 sc = MHD_SC_REPLY_POOL_ALLOCATION_FAILURE; 784 if (reply_sending_aborted && (NULL == log_msg)) 785 log_msg = mhd_MSG4LOG ("Response aborted due to insufficient memory " \ 786 "in the connection pool"); 787 break; 788 case mhd_CONN_CLOSE_NO_MEM_FOR_ERR_RESPONSE: 789 close_hard = true; 790 end_code = c->rq.too_large ? 791 MHD_REQUEST_ENDED_NO_RESOURCES : 792 MHD_REQUEST_ENDED_HTTP_PROTOCOL_ERROR; 793 sc = MHD_SC_ERR_RESPONSE_ALLOCATION_FAILURE; 794 break; 795 case mhd_CONN_CLOSE_APP_ERROR: 796 close_hard = true; 797 end_code = MHD_REQUEST_ENDED_BY_APP_ERROR; 798 sc = MHD_SC_APPLICATION_DATA_GENERATION_FAILURE_CLOSED; 799 if (reply_sending_aborted && (NULL == log_msg)) 800 log_msg = mhd_MSG4LOG ("Response aborted due to application reply " \ 801 "generation failure"); 802 break; 803 case mhd_CONN_CLOSE_APP_ABORTED: 804 close_hard = true; 805 end_code = MHD_REQUEST_ENDED_BY_APP_ABORT; 806 sc = MHD_SC_APPLICATION_CALLBACK_ABORT_ACTION; 807 if (reply_sending_aborted && (NULL == log_msg)) 808 log_msg = mhd_MSG4LOG ("Application aborted reply sending"); 809 break; 810 case mhd_CONN_CLOSE_FILE_OFFSET_TOO_LARGE: 811 close_hard = true; 812 end_code = MHD_REQUEST_ENDED_FILE_ERROR; 813 sc = MHD_SC_REPLY_FILE_OFFSET_TOO_LARGE; 814 if (reply_sending_aborted && (NULL == log_msg)) 815 log_msg = mhd_MSG4LOG ("Response aborted because OS failed " \ 816 "to read too large response file"); 817 break; 818 case mhd_CONN_CLOSE_FILE_READ_ERROR: 819 close_hard = true; 820 end_code = MHD_REQUEST_ENDED_FILE_ERROR; 821 sc = MHD_SC_REPLY_FILE_READ_ERROR; 822 if (reply_sending_aborted && (NULL == log_msg)) 823 log_msg = mhd_MSG4LOG ("Response aborted because OS failed " \ 824 "to read response file"); 825 break; 826 case mhd_CONN_CLOSE_FILE_TOO_SHORT: 827 close_hard = true; 828 end_code = MHD_REQUEST_ENDED_BY_APP_ERROR; 829 sc = MHD_SC_REPLY_FILE_TOO_SHORT; 830 if (reply_sending_aborted && (NULL == log_msg)) 831 log_msg = mhd_MSG4LOG ("Response aborted because response file is " 832 "shorter that expected"); 833 break; 834 #ifdef MHD_SUPPORT_AUTH_DIGEST 835 case mhd_CONN_CLOSE_NONCE_ERROR: 836 close_hard = true; 837 end_code = MHD_REQUEST_ENDED_NONCE_ERROR; 838 sc = MHD_SC_REPLY_NONCE_ERROR; 839 mhd_assert (! reply_sending_aborted); 840 break; 841 #endif /* MHD_SUPPORT_AUTH_DIGEST */ 842 843 case mhd_CONN_CLOSE_INT_ERROR: 844 close_hard = true; 845 end_code = MHD_REQUEST_ENDED_NO_RESOURCES; 846 if (reply_sending_aborted && (NULL == log_msg)) 847 log_msg = mhd_MSG4LOG ("Response aborted due to MHD internal error"); 848 break; 849 case mhd_CONN_CLOSE_EXTR_EVENT_REG_FAILED: 850 close_hard = true; 851 end_code = MHD_REQUEST_ENDED_BY_EXT_EVENT_ERROR; 852 sc = MHD_SC_EXTR_EVENT_REG_FAILED; 853 if (reply_sending_aborted && (NULL == log_msg)) 854 log_msg = mhd_MSG4LOG ("Response aborted due to external event " \ 855 "registration failure"); 856 break; 857 case mhd_CONN_CLOSE_NO_SYS_RESOURCES: 858 close_hard = true; 859 end_code = MHD_REQUEST_ENDED_NO_RESOURCES; 860 sc = MHD_SC_NO_SYS_RESOURCES; 861 if (reply_sending_aborted && (NULL == log_msg)) 862 log_msg = mhd_MSG4LOG ("Response aborted due to lack of " \ 863 "system resources"); 864 break; 865 case mhd_CONN_CLOSE_SOCKET_ERR: 866 close_hard = true; 867 switch (c->sk.state.discnt_err) 868 { 869 case mhd_SOCKET_ERR_NOMEM: 870 end_code = MHD_REQUEST_ENDED_NO_RESOURCES; 871 sc = MHD_SC_NO_SYS_RESOURCES; 872 if (reply_sending_aborted && (NULL == log_msg)) 873 log_msg = mhd_MSG4LOG ("Response aborted because system closed " \ 874 "socket due to lack of system resources"); 875 break; 876 case mhd_SOCKET_ERR_REMT_DISCONN: 877 close_hard = false; 878 end_code = (mhd_HTTP_STAGE_INIT == c->stage) ? 879 MHD_REQUEST_ENDED_COMPLETED_OK /* Not used */ 880 : MHD_REQUEST_ENDED_CLIENT_ABORT; 881 if (reply_sending_aborted) 882 { 883 sc = MHD_SC_CLIENT_CLOSED_CONN_EARLY; 884 if (NULL == log_msg) 885 log_msg = mhd_MSG4LOG ("Response aborted because remote client " \ 886 "closed connection early"); 887 } 888 break; 889 case mhd_SOCKET_ERR_CONNRESET: 890 end_code = MHD_REQUEST_ENDED_CLIENT_ABORT; 891 sc = MHD_SC_CONNECTION_RESET; 892 if (reply_sending_aborted && (NULL == log_msg)) 893 log_msg = mhd_MSG4LOG ("Response aborted due to aborted connection"); 894 break; 895 case mhd_SOCKET_ERR_CONN_BROKEN: 896 case mhd_SOCKET_ERR_NOTCONN: 897 case mhd_SOCKET_ERR_TLS: 898 case mhd_SOCKET_ERR_PIPE: 899 case mhd_SOCKET_ERR_NOT_CHECKED: 900 case mhd_SOCKET_ERR_BADF: 901 case mhd_SOCKET_ERR_INVAL: 902 case mhd_SOCKET_ERR_OPNOTSUPP: 903 case mhd_SOCKET_ERR_NOTSOCK: 904 case mhd_SOCKET_ERR_OTHER: 905 case mhd_SOCKET_ERR_INTERNAL: 906 case mhd_SOCKET_ERR_NO_ERROR: 907 end_code = MHD_REQUEST_ENDED_CONNECTION_ERROR; 908 sc = MHD_SC_CONNECTION_BROKEN; 909 if (reply_sending_aborted && (NULL == log_msg)) 910 log_msg = mhd_MSG4LOG ("Response aborted due to broken connection"); 911 break; 912 case mhd_SOCKET_ERR_AGAIN: 913 case mhd_SOCKET_ERR_INTR: 914 default: 915 mhd_UNREACHABLE (); 916 break; 917 } 918 break; 919 case mhd_CONN_CLOSE_DAEMON_SHUTDOWN: 920 close_hard = true; 921 end_code = MHD_REQUEST_ENDED_DAEMON_SHUTDOWN; 922 break; 923 924 case mhd_CONN_CLOSE_TIMEDOUT: 925 if (mhd_HTTP_STAGE_INIT == c->stage) 926 { 927 close_hard = false; 928 end_code = MHD_REQUEST_ENDED_COMPLETED_OK; /* Not used */ 929 break; 930 } 931 close_hard = true; 932 end_code = MHD_REQUEST_ENDED_TIMEOUT_REACHED; 933 sc = MHD_SC_CONNECTION_TIMEOUT; 934 if (reply_sending_aborted && (NULL == log_msg)) 935 log_msg = mhd_MSG4LOG ("Response aborted due to sending timeout"); 936 break; 937 938 case mhd_CONN_CLOSE_ERR_REPLY_SENT: 939 close_hard = false; 940 end_code = c->rq.too_large ? 941 MHD_REQUEST_ENDED_NO_RESOURCES : 942 MHD_REQUEST_ENDED_HTTP_PROTOCOL_ERROR; 943 break; 944 #ifdef MHD_SUPPORT_UPGRADE 945 case mhd_CONN_CLOSE_UPGRADE: 946 close_hard = false; 947 end_code = MHD_REQUEST_ENDED_COMPLETED_OK_UPGRADE; 948 break; 949 #endif /* MHD_SUPPORT_UPGRADE */ 950 case mhd_CONN_CLOSE_HTTP_COMPLETED: 951 close_hard = false; 952 end_code = MHD_REQUEST_ENDED_COMPLETED_OK; 953 break; 954 955 #ifdef MHD_SUPPORT_HTTP2 956 case mhd_CONN_CLOSE_H2_CLOSE_SOFT: 957 case mhd_CONN_CLOSE_H2_CLOSE_HARD: 958 #endif /* MHD_SUPPORT_HTTP2 */ 959 default: 960 mhd_assert (0 && "Unreachable code"); 961 mhd_UNREACHABLE (); 962 end_code = MHD_REQUEST_ENDED_COMPLETED_OK; 963 close_hard = false; 964 break; 965 } 966 967 mhd_assert ((NULL == log_msg) || (MHD_SC_INTERNAL_ERROR != sc)); 968 969 #ifdef MHD_SUPPORT_UPGRADE 970 if (mhd_CONN_CLOSE_UPGRADE == reason) 971 { 972 mhd_assert (mhd_HTTP_STAGE_UPGRADING == c->stage); 973 c->event_loop_info = MHD_EVENT_LOOP_INFO_UPGRADED; 974 } 975 else 976 #endif /* MHD_SUPPORT_UPGRADE */ 977 if (1) 978 { 979 if (conn_start_socket_closing (c, 980 close_hard)) 981 { 982 (void) 0; // TODO: start local lingering phase 983 c->stage = mhd_HTTP_STAGE_PRE_CLOSING; // TODO: start local lingering phase 984 c->event_loop_info = MHD_EVENT_LOOP_INFO_CLEANUP; // TODO: start local lingering phase 985 } 986 else 987 { /* No need / not possible to linger */ 988 c->stage = mhd_HTTP_STAGE_PRE_CLOSING; 989 c->event_loop_info = MHD_EVENT_LOOP_INFO_CLEANUP; 990 } 991 } 992 993 #ifdef MHD_SUPPORT_LOG_FUNCTIONALITY 994 if (NULL != log_msg) 995 { 996 mhd_LOG_MSG (c->daemon, sc, log_msg); 997 } 998 #else /* ! MHD_SUPPORT_LOG_FUNCTIONALITY */ 999 (void) log_msg; /* Mute compiler warning */ 1000 (void) sc; /* Mute compiler warning */ 1001 #endif /* ! MHD_SUPPORT_LOG_FUNCTIONALITY */ 1002 1003 #if 0 // TODO: notification callback 1004 mhd_assert ((mhd_HTTP_STAGE_INIT != c->stage) || (! c->rq.app_aware)); 1005 if ( (NULL != d->notify_completed) && 1006 (c->rq.app_aware) ) 1007 d->notify_completed (d->notify_completed_cls, 1008 c, 1009 &c->rq.app_context, 1010 MHD_REQUEST_ENDED_COMPLETED_OK); 1011 #else 1012 (void) end_code; 1013 #endif 1014 c->rq.app_aware = false; 1015 1016 if (! c->suspended) 1017 { 1018 mhd_assert (! c->resuming); 1019 mhd_conn_deinit_activity_timeout (c); 1020 } 1021 1022 #ifndef NDEBUG 1023 c->dbg.closing_started = true; 1024 #endif 1025 } 1026 1027 1028 MHD_INTERNAL 1029 MHD_FN_PAR_NONNULL_ (1) void 1030 mhd_conn_pre_clean_part1 (struct MHD_Connection *restrict c) 1031 { 1032 // TODO: support suspended connections 1033 mhd_conn_mark_unready (c, c->daemon); 1034 1035 mhd_stream_call_dcc_cleanup_if_needed (c); 1036 if (NULL != c->rq.cntn.lbuf.data) 1037 mhd_daemon_free_lbuf (c->daemon, &(c->rq.cntn.lbuf)); 1038 1039 if (mhd_WM_INT_HAS_EXT_EVENTS (c->daemon->wmode_int)) 1040 { 1041 struct MHD_Daemon *const d = c->daemon; 1042 if (NULL != c->extr_event.app_cntx) 1043 { 1044 c->extr_event.app_cntx = 1045 mhd_daemon_extr_event_reg (d, 1046 c->sk.fd, 1047 MHD_FD_STATE_NONE, 1048 c->extr_event.app_cntx, 1049 (struct MHD_EventUpdateContext *) c); 1050 if (NULL != c->extr_event.app_cntx) 1051 mhd_log_extr_event_dereg_failed (d); 1052 } 1053 } 1054 #ifdef MHD_SUPPORT_EPOLL 1055 else if (mhd_POLL_TYPE_EPOLL == c->daemon->events.poll_type) 1056 { 1057 struct epoll_event event; 1058 1059 event.events = 0; 1060 event.data.ptr = NULL; 1061 if (0 != epoll_ctl (c->daemon->events.data.epoll.e_fd, 1062 EPOLL_CTL_DEL, 1063 c->sk.fd, 1064 &event)) 1065 { 1066 mhd_LOG_MSG (c->daemon, MHD_SC_EPOLL_CTL_REMOVE_FAILED, 1067 "Failed to remove connection socket from epoll."); 1068 } 1069 } 1070 #endif /* MHD_SUPPORT_EPOLL */ 1071 } 1072 1073 1074 MHD_INTERNAL 1075 MHD_FN_PAR_NONNULL_ (1) void 1076 mhd_conn_pre_clean (struct MHD_Connection *restrict c) 1077 { 1078 #ifdef mhd_DEBUG_CONN_ADD_CLOSE 1079 fprintf (stderr, 1080 "&&& Closing connection, FD: %2llu\n", 1081 (unsigned long long) c->sk.fd); 1082 #endif /* mhd_DEBUG_CONN_ADD_CLOSE */ 1083 1084 mhd_assert (c->dbg.closing_started); 1085 mhd_assert (! c->dbg.pre_cleaned); 1086 1087 #ifdef MHD_SUPPORT_UPGRADE 1088 if (NULL == c->upgr.c) 1089 #endif 1090 mhd_conn_pre_clean_part1 (c); 1091 1092 if (NULL != c->rp.resp_iov.iov) 1093 { 1094 free (c->rp.resp_iov.iov); 1095 c->rp.resp_iov.iov = NULL; 1096 } 1097 if (NULL != c->rp.response) 1098 mhd_response_dec_use_count (c->rp.response); 1099 c->rp.response = NULL; 1100 1101 mhd_assert (NULL != c->pool); 1102 c->read_buffer_offset = 0; 1103 c->read_buffer_size = 0; 1104 c->read_buffer = NULL; 1105 c->write_buffer_send_offset = 0; 1106 c->write_buffer_append_offset = 0; 1107 c->write_buffer_size = 0; 1108 c->write_buffer = NULL; 1109 // TODO: call in the thread where it was allocated for thread-per-connection 1110 mhd_pool_destroy (c->pool); 1111 c->pool = NULL; 1112 1113 c->stage = mhd_HTTP_STAGE_CLOSED; 1114 #ifndef NDEBUG 1115 c->dbg.pre_cleaned = true; 1116 #endif 1117 }