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