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