stream_funcs.c (40197B)
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_NONNULL_IF_NONZERO_ (4, 3) 357 MHD_FN_PAR_IN_SIZE_ (4, 3) unsigned int 358 mhd_stream_get_no_space_err_status_code (struct MHD_Connection *restrict c, 359 enum MHD_ProcRecvDataStage stage, 360 size_t add_element_size, 361 const char *restrict add_element) 362 { 363 size_t method_size; 364 size_t uri_size; 365 size_t opt_headers_size; 366 size_t host_field_line_size; 367 368 mhd_assert ((0 == add_element_size) || (NULL != add_element)); 369 370 c->rq.too_large = true; 371 372 if (mhd_HTTP_STAGE_REQ_LINE_RECEIVED < c->stage) 373 { 374 if (mhd_HTTP_STAGE_HEADERS_RECEIVED > c->stage) 375 { 376 mhd_assert (NULL != c->rq.field_lines.start); 377 opt_headers_size = 378 (size_t)((c->read_buffer + c->read_buffer_offset) 379 - c->rq.field_lines.start); 380 } 381 else 382 opt_headers_size = c->rq.field_lines.size; 383 } 384 else 385 opt_headers_size = 0u; 386 387 /* The read buffer is fully used by the request line, the field lines 388 (headers) and internal information. 389 The return status code works as a suggestion for the client to reduce 390 one of the request elements. */ 391 392 if ((MHD_PROC_RECV_BODY_CHUNKED == stage) 393 && (MHD_MIN_REASONABLE_REQ_CHUNK_LINE_LENGTH_ < add_element_size)) 394 { 395 /* Request could be re-tried easily with smaller chunk sizes */ 396 return MHD_HTTP_STATUS_CONTENT_TOO_LARGE; 397 } 398 399 host_field_line_size = 0; 400 /* The "Host:" field line is mandatory. 401 The total size of the field lines (headers) cannot be smaller than 402 the size of the "Host:" field line. */ 403 if ((MHD_PROC_RECV_HEADERS == stage) 404 && (0 != add_element_size)) 405 { 406 static const size_t header_host_key_len = 407 mhd_SSTR_LEN (MHD_HTTP_HEADER_HOST); 408 const bool is_host_header = 409 (header_host_key_len + 1 <= add_element_size) 410 && ((0 == add_element[header_host_key_len]) 411 || (':' == add_element[header_host_key_len])) 412 && mhd_str_equal_caseless_bin_n (MHD_HTTP_HEADER_HOST, 413 add_element, 414 header_host_key_len); 415 if (is_host_header) 416 { 417 const bool is_parsed = !( 418 (mhd_HTTP_STAGE_HEADERS_RECEIVED > c->stage) 419 && (add_element_size == c->read_buffer_offset) 420 && (c->read_buffer == add_element)); 421 size_t actual_element_size; 422 423 mhd_assert (!is_parsed || (0 == add_element[header_host_key_len])); 424 /* The actual size should be larger due to CRLF or LF chars, 425 however the exact termination sequence is not known here and 426 as perfect precision is not required, to simplify the code 427 assume the minimal length. */ 428 if (is_parsed) 429 actual_element_size = add_element_size + 1; /* "1" for LF */ 430 else 431 actual_element_size = add_element_size; 432 433 host_field_line_size = actual_element_size; 434 mhd_assert (opt_headers_size >= actual_element_size); 435 opt_headers_size -= actual_element_size; 436 } 437 } 438 if (0 == host_field_line_size) 439 { 440 static const size_t host_field_name_len = 441 mhd_SSTR_LEN (MHD_HTTP_HEADER_HOST); 442 struct MHD_StringNullable host_value; 443 444 if (mhd_request_get_value_n (&(c->rq), 445 MHD_VK_HEADER, 446 host_field_name_len, 447 MHD_HTTP_HEADER_HOST, 448 &host_value)) 449 { 450 /* Calculate the minimal size of the field line: no space between 451 colon and the field value, line terminated by LR */ 452 host_field_line_size = 453 host_field_name_len + host_value.len + 2; /* "2" for ':' and LF */ 454 455 /* The "Host:" field could be added by application */ 456 if (opt_headers_size >= host_field_line_size) 457 { 458 opt_headers_size -= host_field_line_size; 459 /* Take into account typical space after colon and CR at the end of the line */ 460 if (opt_headers_size >= 2) 461 opt_headers_size -= 2; 462 } 463 else 464 host_field_line_size = 0; /* No "Host:" field line set by the client */ 465 } 466 } 467 468 uri_size = c->rq.req_target_len; 469 if (mhd_HTTP_METHOD_OTHER != c->rq.http_mthd) 470 method_size = 0; /* Do not recommend shorter request method */ 471 else 472 { 473 mhd_assert (NULL != c->rq.method.cstr); 474 method_size = c->rq.method.len; 475 mhd_assert (method_size == strlen (c->rq.method.cstr)); 476 } 477 478 if ((size_t)MHD_MAX_REASONABLE_HEADERS_SIZE_ < opt_headers_size) 479 { 480 /* Typically the easiest way to reduce request header size is 481 a removal of some optional headers. */ 482 if (opt_headers_size > (uri_size / 8)) 483 { 484 if ((opt_headers_size / 2) > method_size) 485 return MHD_HTTP_STATUS_REQUEST_HEADER_FIELDS_TOO_LARGE; 486 else 487 return MHD_HTTP_STATUS_NOT_IMPLEMENTED; /* The length of the HTTP request method is unreasonably large */ 488 } 489 else 490 { /* Request target is MUCH larger than headers */ 491 if ((uri_size / 16) > method_size) 492 return MHD_HTTP_STATUS_URI_TOO_LONG; 493 else 494 return MHD_HTTP_STATUS_NOT_IMPLEMENTED; /* The length of the HTTP request method is unreasonably large */ 495 } 496 } 497 if ((size_t)MHD_MAX_REASONABLE_REQ_TARGET_SIZE_ < uri_size) 498 { 499 /* If request target size if larger than maximum reasonable size 500 recommend client to reduce the request target size (length). */ 501 if ((uri_size / 16) > method_size) 502 return MHD_HTTP_STATUS_URI_TOO_LONG; /* Request target is MUCH larger than headers */ 503 else 504 return MHD_HTTP_STATUS_NOT_IMPLEMENTED; /* The length of the HTTP request method is unreasonably large */ 505 } 506 507 /* The read buffer is too small to handle reasonably large requests */ 508 509 if ((size_t)MHD_MIN_REASONABLE_HEADERS_SIZE_ < opt_headers_size) 510 { 511 /* Recommend application to retry with minimal headers */ 512 if ((opt_headers_size * 4) > uri_size) 513 { 514 if (opt_headers_size > method_size) 515 return MHD_HTTP_STATUS_REQUEST_HEADER_FIELDS_TOO_LARGE; 516 else 517 return MHD_HTTP_STATUS_NOT_IMPLEMENTED; /* The length of the HTTP request method is unreasonably large */ 518 } 519 else 520 { /* Request target is significantly larger than headers */ 521 if (uri_size > method_size * 4) 522 return MHD_HTTP_STATUS_URI_TOO_LONG; 523 else 524 return MHD_HTTP_STATUS_NOT_IMPLEMENTED; /* The length of the HTTP request method is unreasonably large */ 525 } 526 } 527 if ((size_t)MHD_MIN_REASONABLE_REQ_TARGET_SIZE_ < uri_size) 528 { 529 /* Recommend application to retry with a shorter request target */ 530 if (uri_size > method_size * 4) 531 return MHD_HTTP_STATUS_URI_TOO_LONG; 532 else 533 return MHD_HTTP_STATUS_NOT_IMPLEMENTED; /* The length of the HTTP request method is unreasonably large */ 534 } 535 536 if ((size_t)MHD_MIN_REASONABLE_REQ_METHOD_SIZE_ < method_size) 537 { 538 /* The request target (URI) and headers are (reasonably) very small. 539 Some non-standard long request method is used. */ 540 /* The last resort response as it means "the method is not supported 541 by the server for any URI". */ 542 return MHD_HTTP_STATUS_NOT_IMPLEMENTED; 543 } 544 545 /* The almost impossible situation: all elements are small, but cannot 546 fit the buffer. The application set the buffer size to 547 critically low value? */ 548 549 if ((1 < opt_headers_size) || (1 < uri_size)) 550 { 551 if (opt_headers_size >= uri_size) 552 return MHD_HTTP_STATUS_REQUEST_HEADER_FIELDS_TOO_LARGE; 553 else 554 return MHD_HTTP_STATUS_URI_TOO_LONG; 555 } 556 557 /* Nothing to reduce in the request. 558 Reply with some status. */ 559 if (0 != host_field_line_size) 560 return MHD_HTTP_STATUS_REQUEST_HEADER_FIELDS_TOO_LARGE; 561 562 return MHD_HTTP_STATUS_URI_TOO_LONG; 563 } 564 565 566 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ void 567 mhd_stream_switch_from_recv_to_send (struct MHD_Connection *c) 568 { 569 /* Read buffer is not needed for this request, shrink it.*/ 570 mhd_stream_shrink_read_buffer (c); 571 } 572 573 574 /** 575 * Finish request serving. 576 * The stream will be re-used or closed. 577 * 578 * @param c the connection to use. 579 */ 580 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ void 581 mhd_stream_finish_req_serving (struct MHD_Connection *restrict c, 582 bool reuse) 583 { 584 struct MHD_Daemon *const restrict d = c->daemon; 585 586 if (!reuse) 587 { 588 mhd_assert (!c->stop_with_error || (NULL == c->rp.response) \ 589 || (c->rp.response->cfg.int_err_resp)); 590 591 /* Next function will notify client and set connection 592 * state to "PRE-CLOSING" */ 593 /* Later response and memory pool will be destroyed */ 594 mhd_conn_start_closing (c, 595 c->stop_with_error ? 596 mhd_CONN_CLOSE_ERR_REPLY_SENT : 597 mhd_CONN_CLOSE_HTTP_COMPLETED, 598 NULL); 599 } 600 else 601 { 602 /* Reset connection to process the next request */ 603 size_t new_read_buf_size; 604 mhd_assert (!c->stop_with_error); 605 mhd_assert (!c->discard_request); 606 mhd_assert (NULL == c->rq.cntn.lbuf.data); 607 608 #if 0 // TODO: notification callback 609 if ((NULL != d->notify_completed) 610 && (c->rq.app_aware)) 611 d->notify_completed (d->notify_completed_cls, 612 c, 613 &c->rq.app_context, 614 MHD_REQUEST_ENDED_COMPLETED_OK); 615 c->rq.app_aware = false; 616 #endif 617 618 mhd_stream_call_dcc_cleanup_if_needed (c); 619 if (NULL != c->rp.resp_iov.iov) 620 { 621 free (c->rp.resp_iov.iov); 622 c->rp.resp_iov.iov = NULL; 623 } 624 625 if (NULL != c->rp.response) 626 mhd_response_dec_use_count (c->rp.response); 627 c->rp.response = NULL; 628 629 c->conn_reuse = mhd_CONN_KEEPALIVE_POSSIBLE; 630 c->stage = mhd_HTTP_STAGE_INIT; 631 c->event_loop_info = MHD_EVENT_LOOP_INFO_RECV; /* Dummy state, real state set later */ 632 633 /* iov (if any) will be deallocated by mhd_pool_reset */ 634 mhd_stream_init_req_reply (c); 635 636 c->write_buffer = NULL; 637 c->write_buffer_size = 0; 638 c->write_buffer_send_offset = 0; 639 c->write_buffer_append_offset = 0; 640 c->continue_message_write_offset = 0; 641 642 /* Reset the read buffer to the starting size, 643 preserving the bytes we have already read. */ 644 new_read_buf_size = d->conns.cfg.mem_pool_size / 2; 645 if (c->read_buffer_offset > new_read_buf_size) 646 new_read_buf_size = c->read_buffer_offset; 647 648 c->read_buffer 649 = (char *)mhd_pool_reset (c->pool, 650 c->read_buffer, 651 c->read_buffer_offset, 652 new_read_buf_size); 653 c->read_buffer_size = new_read_buf_size; 654 } 655 c->rq.app_context = NULL; 656 } 657 658 659 /* return 'true' is lingering needed, 'false' is lingering is not needed */ 660 static MHD_FN_PAR_NONNULL_ALL_ bool 661 conn_start_socket_closing (struct MHD_Connection *restrict c, 662 bool close_hard) 663 { 664 bool need_lingering; 665 /* Make changes on the socket early to let the kernel and the remote 666 * to process the changes in parallel. */ 667 if (close_hard) 668 { 669 /* Use abortive closing, send RST to remote to indicate a problem */ 670 (void)mhd_socket_set_hard_close (c->sk.fd); 671 c->stage = mhd_HTTP_STAGE_PRE_CLOSING; 672 c->event_loop_info = MHD_EVENT_LOOP_INFO_CLEANUP; 673 674 return false; 675 } 676 677 mhd_assert (c->sk.state.rmt_shut_wr \ 678 || !mhd_SOCKET_ERR_IS_HARD (c->sk.state.discnt_err)); 679 680 need_lingering = !c->sk.state.rmt_shut_wr; 681 if (need_lingering) 682 { 683 #ifdef MHD_SUPPORT_HTTPS 684 if (mhd_C_HAS_TLS (c)) 685 { 686 if ((0 != (((unsigned int)c->sk.ready) 687 & mhd_SOCKET_NET_STATE_SEND_READY)) 688 || c->sk.props.is_nonblck) 689 need_lingering = 690 (mhd_TLS_PROCED_FAILED != mhd_tls_conn_shutdown (c->tls)); 691 } 692 else 693 #endif /* MHD_SUPPORT_HTTPS */ 694 if (1) 695 { 696 need_lingering = mhd_socket_shut_wr (c->sk.fd); 697 if (need_lingering) 698 need_lingering = (!c->sk.state.rmt_shut_wr); /* Skip as already closed */ 699 } 700 } 701 702 return need_lingering; 703 } 704 705 706 #ifdef MHD_SUPPORT_HTTP2 707 708 static MHD_FN_PAR_NONNULL_ALL_ void 709 conn_h2_start_closing (struct MHD_Connection *restrict c, 710 bool close_hard) 711 { 712 mhd_assert (mhd_C_IS_HTTP2 (c)); 713 mhd_assert (c->h2.dbg.h2_deinited); 714 mhd_assert (!c->rq.app_aware); 715 716 conn_start_socket_closing (c, 717 close_hard); 718 719 mhd_conn_deinit_activity_timeout (c); 720 721 # ifndef NDEBUG 722 c->dbg.closing_started = true; 723 # endif 724 } 725 726 727 #endif /* MHD_SUPPORT_HTTP2 */ 728 729 730 MHD_INTERNAL 731 MHD_FN_PAR_NONNULL_ (1) MHD_FN_PAR_CSTR_ (3) void 732 mhd_conn_start_closing (struct MHD_Connection *restrict c, 733 enum mhd_ConnCloseReason reason, 734 const char *log_msg) 735 { 736 bool close_hard; 737 enum MHD_RequestEndedCode end_code; 738 enum MHD_StatusCode sc; 739 bool reply_sending_aborted; 740 741 #ifdef MHD_USE_TRACE_CONN_ADD_CLOSE 742 fprintf (stderr, 743 "&&& mhd_conn_start_closing([FD: %2llu], %u, %s%s%s)...\n", 744 (unsigned long long)c->sk.fd, 745 (unsigned int)reason, 746 log_msg ? "\"" : "", 747 log_msg ? log_msg : "[NULL]", 748 log_msg ? "\"" : ""); 749 #endif /* MHD_USE_TRACE_CONN_ADD_CLOSE */ 750 751 #ifdef MHD_SUPPORT_HTTP2 752 if (mhd_C_IS_HTTP2 (c)) 753 { 754 mhd_assert ((mhd_CONN_CLOSE_TIMEDOUT == reason) 755 || (mhd_CONN_CLOSE_DAEMON_SHUTDOWN == reason) 756 || (mhd_CONN_CLOSE_H2_CLOSE_SOFT == reason) 757 || (mhd_CONN_CLOSE_H2_CLOSE_HARD == reason)); 758 mhd_assert (NULL == log_msg); 759 conn_h2_start_closing (c, 760 reason != mhd_CONN_CLOSE_H2_CLOSE_SOFT); 761 return; 762 } 763 #endif /* MHD_SUPPORT_HTTP2 */ 764 765 reply_sending_aborted = 766 ((mhd_HTTP_STAGE_HEADERS_SENDING <= c->stage) 767 && (mhd_HTTP_STAGE_FULL_REPLY_SENT > c->stage)); 768 sc = MHD_SC_INTERNAL_ERROR; 769 switch (reason) 770 { 771 case mhd_CONN_CLOSE_CLIENT_HTTP_ERR_ABORT_CONN: 772 close_hard = true; 773 end_code = MHD_REQUEST_ENDED_HTTP_PROTOCOL_ERROR; 774 sc = MHD_SC_REQ_MALFORMED; 775 mhd_assert (!reply_sending_aborted); 776 break; 777 case mhd_CONN_CLOSE_NO_POOL_MEM_FOR_REQUEST: 778 close_hard = true; 779 end_code = MHD_REQUEST_ENDED_NO_RESOURCES; 780 mhd_assert (!reply_sending_aborted); 781 break; 782 case mhd_CONN_CLOSE_CLIENT_SHUTDOWN_EARLY: 783 close_hard = true; 784 end_code = MHD_REQUEST_ENDED_CLIENT_ABORT; 785 sc = MHD_SC_CLIENT_SHUTDOWN_EARLY; 786 mhd_assert (!reply_sending_aborted); 787 break; 788 case mhd_CONN_CLOSE_H2_PREFACE_MISSING: 789 close_hard = true; 790 end_code = MHD_REQUEST_ENDED_HTTP_PROTOCOL_ERROR; 791 sc = MHD_SC_ALPN_H2_NO_PREFACE; 792 break; 793 case mhd_CONN_CLOSE_NO_POOL_MEM_FOR_REPLY: 794 close_hard = true; 795 end_code = (!c->stop_with_error || c->rq.too_large) ? 796 MHD_REQUEST_ENDED_NO_RESOURCES : 797 MHD_REQUEST_ENDED_HTTP_PROTOCOL_ERROR; 798 sc = MHD_SC_REPLY_POOL_ALLOCATION_FAILURE; 799 if (reply_sending_aborted && (NULL == log_msg)) 800 log_msg = mhd_MSG4LOG ("Response aborted due to insufficient memory " \ 801 "in the connection pool"); 802 break; 803 case mhd_CONN_CLOSE_NO_MEM_FOR_ERR_RESPONSE: 804 close_hard = true; 805 end_code = c->rq.too_large ? 806 MHD_REQUEST_ENDED_NO_RESOURCES : 807 MHD_REQUEST_ENDED_HTTP_PROTOCOL_ERROR; 808 sc = MHD_SC_REPLY_ALLOCATION_FAILED; 809 break; 810 case mhd_CONN_CLOSE_APP_ERROR: 811 close_hard = true; 812 end_code = MHD_REQUEST_ENDED_BY_APP_ERROR; 813 sc = MHD_SC_APPLICATION_DATA_GENERATION_FAILURE_CLOSED; 814 if (reply_sending_aborted && (NULL == log_msg)) 815 log_msg = mhd_MSG4LOG ("Response aborted due to application reply " \ 816 "generation failure"); 817 break; 818 case mhd_CONN_CLOSE_APP_ABORTED: 819 close_hard = true; 820 end_code = MHD_REQUEST_ENDED_BY_APP_ABORT; 821 sc = MHD_SC_APPLICATION_CALLBACK_ABORT_ACTION; 822 if (reply_sending_aborted && (NULL == log_msg)) 823 log_msg = mhd_MSG4LOG ("Application aborted reply sending"); 824 break; 825 case mhd_CONN_CLOSE_FILE_OFFSET_TOO_LARGE: 826 close_hard = true; 827 end_code = MHD_REQUEST_ENDED_FILE_ERROR; 828 sc = MHD_SC_REPLY_FILE_OFFSET_TOO_LARGE; 829 if (reply_sending_aborted && (NULL == log_msg)) 830 log_msg = mhd_MSG4LOG ("Response aborted because OS failed " \ 831 "to read too large response file"); 832 break; 833 case mhd_CONN_CLOSE_FILE_READ_ERROR: 834 close_hard = true; 835 end_code = MHD_REQUEST_ENDED_FILE_ERROR; 836 sc = MHD_SC_REPLY_FILE_READ_ERROR; 837 if (reply_sending_aborted && (NULL == log_msg)) 838 log_msg = mhd_MSG4LOG ("Response aborted because OS failed " \ 839 "to read response file"); 840 break; 841 case mhd_CONN_CLOSE_FILE_TOO_SHORT: 842 close_hard = true; 843 end_code = MHD_REQUEST_ENDED_BY_APP_ERROR; 844 sc = MHD_SC_REPLY_FILE_TOO_SHORT; 845 if (reply_sending_aborted && (NULL == log_msg)) 846 log_msg = mhd_MSG4LOG ("Response aborted because response file is " 847 "shorter that expected"); 848 break; 849 #ifdef MHD_SUPPORT_AUTH_DIGEST 850 case mhd_CONN_CLOSE_NONCE_ERROR: 851 close_hard = true; 852 end_code = MHD_REQUEST_ENDED_NONCE_ERROR; 853 sc = MHD_SC_REPLY_NONCE_ERROR; 854 mhd_assert (!reply_sending_aborted); 855 break; 856 #endif /* MHD_SUPPORT_AUTH_DIGEST */ 857 858 case mhd_CONN_CLOSE_INT_ERROR: 859 close_hard = true; 860 end_code = MHD_REQUEST_ENDED_NO_RESOURCES; 861 if (reply_sending_aborted && (NULL == log_msg)) 862 log_msg = mhd_MSG4LOG ("Response aborted due to MHD internal error"); 863 break; 864 case mhd_CONN_CLOSE_EXTR_EVENT_REG_FAILED: 865 close_hard = true; 866 end_code = MHD_REQUEST_ENDED_BY_EXT_EVENT_ERROR; 867 sc = MHD_SC_EXTR_EVENT_REG_FAILED; 868 if (reply_sending_aborted && (NULL == log_msg)) 869 log_msg = mhd_MSG4LOG ("Response aborted due to external event " \ 870 "registration failure"); 871 break; 872 case mhd_CONN_CLOSE_NO_SYS_RESOURCES: 873 close_hard = true; 874 end_code = MHD_REQUEST_ENDED_NO_RESOURCES; 875 sc = MHD_SC_NO_SYS_RESOURCES; 876 if (reply_sending_aborted && (NULL == log_msg)) 877 log_msg = mhd_MSG4LOG ("Response aborted due to lack of " \ 878 "system resources"); 879 break; 880 case mhd_CONN_CLOSE_SOCKET_ERR: 881 close_hard = true; 882 switch (c->sk.state.discnt_err) 883 { 884 case mhd_SOCKET_ERR_NOMEM: 885 end_code = MHD_REQUEST_ENDED_NO_RESOURCES; 886 sc = MHD_SC_NO_SYS_RESOURCES; 887 if (reply_sending_aborted && (NULL == log_msg)) 888 log_msg = mhd_MSG4LOG ("Response aborted because system closed " \ 889 "socket due to lack of system resources"); 890 break; 891 case mhd_SOCKET_ERR_REMT_DISCONN: 892 close_hard = false; 893 end_code = (mhd_HTTP_STAGE_INIT == c->stage) ? 894 MHD_REQUEST_ENDED_COMPLETED_OK /* Not used */ 895 : MHD_REQUEST_ENDED_CLIENT_ABORT; 896 if (reply_sending_aborted) 897 { 898 sc = MHD_SC_CLIENT_CLOSED_CONN_EARLY; 899 if (NULL == log_msg) 900 log_msg = mhd_MSG4LOG ("Response aborted because remote client " \ 901 "closed connection early"); 902 } 903 break; 904 case mhd_SOCKET_ERR_CONNRESET: 905 end_code = MHD_REQUEST_ENDED_CLIENT_ABORT; 906 sc = MHD_SC_CONNECTION_RESET; 907 if (reply_sending_aborted && (NULL == log_msg)) 908 log_msg = mhd_MSG4LOG ("Response aborted due to aborted connection"); 909 break; 910 case mhd_SOCKET_ERR_CONN_BROKEN: 911 case mhd_SOCKET_ERR_NOTCONN: 912 #ifdef MHD_SUPPORT_HTTPS 913 case mhd_SOCKET_ERR_TLS: 914 #endif /* MHD_SUPPORT_HTTPS */ 915 case mhd_SOCKET_ERR_PIPE: 916 case mhd_SOCKET_ERR_NOT_CHECKED: 917 case mhd_SOCKET_ERR_BADF: 918 case mhd_SOCKET_ERR_INVAL: 919 case mhd_SOCKET_ERR_OPNOTSUPP: 920 case mhd_SOCKET_ERR_NOTSOCK: 921 case mhd_SOCKET_ERR_OTHER: 922 case mhd_SOCKET_ERR_INTERNAL: 923 case mhd_SOCKET_ERR_NO_ERROR: 924 end_code = MHD_REQUEST_ENDED_CONNECTION_ERROR; 925 sc = MHD_SC_CONNECTION_BROKEN; 926 if (reply_sending_aborted && (NULL == log_msg)) 927 log_msg = mhd_MSG4LOG ("Response aborted due to broken connection"); 928 break; 929 case mhd_SOCKET_ERR_AGAIN: 930 case mhd_SOCKET_ERR_INTR: 931 default: 932 mhd_UNREACHABLE (); 933 break; 934 } 935 break; 936 case mhd_CONN_CLOSE_DAEMON_SHUTDOWN: 937 close_hard = true; 938 end_code = MHD_REQUEST_ENDED_DAEMON_SHUTDOWN; 939 break; 940 941 case mhd_CONN_CLOSE_TIMEDOUT: 942 if (mhd_HTTP_STAGE_INIT == c->stage) 943 { 944 close_hard = false; 945 end_code = MHD_REQUEST_ENDED_COMPLETED_OK; /* Not used */ 946 break; 947 } 948 close_hard = true; 949 end_code = MHD_REQUEST_ENDED_TIMEOUT_REACHED; 950 sc = MHD_SC_CONNECTION_TIMEOUT; 951 if (reply_sending_aborted && (NULL == log_msg)) 952 log_msg = mhd_MSG4LOG ("Response aborted due to sending timeout"); 953 break; 954 955 case mhd_CONN_CLOSE_ERR_REPLY_SENT: 956 close_hard = false; 957 end_code = c->rq.too_large ? 958 MHD_REQUEST_ENDED_NO_RESOURCES : 959 MHD_REQUEST_ENDED_HTTP_PROTOCOL_ERROR; 960 break; 961 #ifdef MHD_SUPPORT_UPGRADE 962 case mhd_CONN_CLOSE_UPGRADE: 963 close_hard = false; 964 end_code = MHD_REQUEST_ENDED_COMPLETED_OK_UPGRADE; 965 break; 966 #endif /* MHD_SUPPORT_UPGRADE */ 967 case mhd_CONN_CLOSE_HTTP_COMPLETED: 968 close_hard = false; 969 end_code = MHD_REQUEST_ENDED_COMPLETED_OK; 970 break; 971 #ifdef mhd_HAVE_TLS_ACME 972 case mhd_CONN_CLOSE_ACME_ALPN_CHALLENGE_COMPLETED: 973 close_hard = false; 974 end_code = MHD_REQUEST_ENDED_COMPLETED_OK; 975 break; 976 #endif /* mhd_HAVE_TLS_ACME */ 977 978 979 #ifdef MHD_SUPPORT_HTTP2 980 case mhd_CONN_CLOSE_H2_CLOSE_SOFT: 981 case mhd_CONN_CLOSE_H2_CLOSE_HARD: 982 #endif /* MHD_SUPPORT_HTTP2 */ 983 default: 984 mhd_assert (0 && "Unreachable code"); 985 mhd_UNREACHABLE (); 986 end_code = MHD_REQUEST_ENDED_COMPLETED_OK; 987 close_hard = false; 988 break; 989 } 990 991 mhd_assert ((NULL == log_msg) || (MHD_SC_INTERNAL_ERROR != sc)); 992 993 #ifdef MHD_SUPPORT_UPGRADE 994 if (mhd_CONN_CLOSE_UPGRADE == reason) 995 { 996 mhd_assert (mhd_HTTP_STAGE_UPGRADING == c->stage); 997 c->event_loop_info = MHD_EVENT_LOOP_INFO_UPGRADED; 998 } 999 else 1000 #endif /* MHD_SUPPORT_UPGRADE */ 1001 if (1) 1002 { 1003 if (conn_start_socket_closing (c, 1004 close_hard)) 1005 { 1006 (void)0; // TODO: start local lingering phase 1007 c->stage = mhd_HTTP_STAGE_PRE_CLOSING; // TODO: start local lingering phase 1008 c->event_loop_info = MHD_EVENT_LOOP_INFO_CLEANUP; // TODO: start local lingering phase 1009 } 1010 else 1011 { /* No need / not possible to linger */ 1012 c->stage = mhd_HTTP_STAGE_PRE_CLOSING; 1013 c->event_loop_info = MHD_EVENT_LOOP_INFO_CLEANUP; 1014 } 1015 } 1016 1017 #ifdef MHD_SUPPORT_LOG_FUNCTIONALITY 1018 if (NULL != log_msg) 1019 { 1020 mhd_LOG_MSG (c->daemon, sc, log_msg); 1021 } 1022 #else /* ! MHD_SUPPORT_LOG_FUNCTIONALITY */ 1023 (void)log_msg; /* Mute compiler warning */ 1024 (void)sc; /* Mute compiler warning */ 1025 #endif /* ! MHD_SUPPORT_LOG_FUNCTIONALITY */ 1026 1027 #if 0 // TODO: notification callback 1028 mhd_assert ((mhd_HTTP_STAGE_INIT != c->stage) || (!c->rq.app_aware)); 1029 if ((NULL != d->notify_completed) 1030 && (c->rq.app_aware)) 1031 d->notify_completed (d->notify_completed_cls, 1032 c, 1033 &c->rq.app_context, 1034 MHD_REQUEST_ENDED_COMPLETED_OK); 1035 #else 1036 (void)end_code; 1037 #endif 1038 c->rq.app_aware = false; 1039 1040 if (!c->suspended) 1041 { 1042 mhd_assert (!c->resuming); 1043 mhd_conn_deinit_activity_timeout (c); 1044 } 1045 1046 #ifndef NDEBUG 1047 c->dbg.closing_started = true; 1048 #endif 1049 } 1050 1051 1052 MHD_INTERNAL 1053 MHD_FN_PAR_NONNULL_ (1) void 1054 mhd_conn_pre_clean_part1 (struct MHD_Connection *restrict c) 1055 { 1056 // TODO: support suspended connections 1057 mhd_conn_mark_unready (c, c->daemon); 1058 1059 mhd_stream_call_dcc_cleanup_if_needed (c); 1060 if (NULL != c->rq.cntn.lbuf.data) 1061 mhd_daemon_free_lbuf (c->daemon, &(c->rq.cntn.lbuf)); 1062 1063 if (mhd_WM_INT_HAS_EXT_EVENTS (c->daemon->wmode_int)) 1064 { 1065 struct MHD_Daemon *const d = c->daemon; 1066 if (NULL != c->events.extrn.app_cntx) 1067 { 1068 c->events.extrn.app_cntx = 1069 mhd_daemon_extr_event_reg (d, 1070 c->sk.fd, 1071 MHD_FD_STATE_NONE, 1072 c->events.extrn.app_cntx, 1073 (struct MHD_EventUpdateContext *)c); 1074 if (NULL != c->events.extrn.app_cntx) 1075 mhd_log_extr_event_dereg_failed (d); 1076 } 1077 } 1078 #ifdef MHD_SUPPORT_EPOLL 1079 else if (mhd_POLL_TYPE_EPOLL == c->daemon->events.poll_type) 1080 { 1081 struct epoll_event event; 1082 1083 event.events = 0; 1084 event.data.ptr = NULL; 1085 if (0 != epoll_ctl (c->daemon->events.data.epoll.e_fd, 1086 EPOLL_CTL_DEL, 1087 c->sk.fd, 1088 &event)) 1089 { 1090 mhd_LOG_MSG (c->daemon, MHD_SC_EVENTS_CONN_REMOVE_FAILED, 1091 "Failed to remove connection socket from epoll."); 1092 } 1093 } 1094 #endif /* MHD_SUPPORT_EPOLL */ 1095 #ifdef MHD_SUPPORT_KQUEUE 1096 else if (mhd_D_IS_USING_KQUEUE (c->daemon)) 1097 { 1098 # ifdef MHD_SUPPORT_UPGRADE 1099 /* Remove socket from kqueue monitoring only if upgrading. 1100 If connection is being closed, the socket is removed automatically 1101 when the socket is closed. */ 1102 if (mhd_HTTP_STAGE_UPGRADING == c->stage) 1103 { 1104 static const struct timespec zero_timeout = {0, 0}; 1105 struct kevent events[2]; 1106 int res; 1107 1108 mhd_KE_SET (events + 0u, 1109 c->sk.fd, 1110 EVFILT_WRITE, 1111 EV_DELETE, 1112 c); 1113 mhd_KE_SET (events + 1u, 1114 c->sk.fd, 1115 EVFILT_READ, 1116 EV_DELETE, 1117 c); 1118 1119 # ifdef MHD_USE_TRACE_POLLING_FDS 1120 fprintf (stderr, 1121 "### (Starting) kevent(%d, changes, 2, [NULL], " 1122 "0, [0, 0])...\n", 1123 c->daemon->events.data.kq.kq_fd); 1124 # endif /* MHD_USE_TRACE_POLLING_FDS */ 1125 res = mhd_kevent (c->daemon->events.data.kq.kq_fd, 1126 events, 1127 2, 1128 NULL, 1129 0, 1130 &zero_timeout); 1131 # ifdef MHD_USE_TRACE_POLLING_FDS 1132 fprintf (stderr, 1133 "### (Finished) kevent(%d, changes, 2, [NULL], " 1134 "0, [0, 0]) -> %d\n", 1135 c->daemon->events.data.kq.kq_fd, 1136 res); 1137 # endif /* MHD_USE_TRACE_POLLING_FDS */ 1138 if (0 > res) 1139 { 1140 mhd_LOG_MSG (c->daemon, MHD_SC_EVENTS_CONN_REMOVE_FAILED, 1141 "Failed to remove upgraded connection socket " 1142 "from kqueue monitoring."); 1143 /* Continue with monitored socket which may wake-up 1144 daemon's monitoring */ 1145 } 1146 } 1147 # endif /* MHD_SUPPORT_UPGRADE */ 1148 (void)0; 1149 } 1150 #endif /* MHD_SUPPORT_KQUEUE */ 1151 } 1152 1153 1154 MHD_INTERNAL 1155 MHD_FN_PAR_NONNULL_ (1) void 1156 mhd_conn_pre_clean (struct MHD_Connection *restrict c) 1157 { 1158 #ifdef MHD_USE_TRACE_CONN_ADD_CLOSE 1159 fprintf (stderr, 1160 "&&& Closing connection, FD: %2llu\n", 1161 (unsigned long long)c->sk.fd); 1162 #endif /* MHD_USE_TRACE_CONN_ADD_CLOSE */ 1163 1164 mhd_assert (c->dbg.closing_started); 1165 mhd_assert (!c->dbg.pre_cleaned); 1166 1167 #ifdef MHD_SUPPORT_UPGRADE 1168 if (NULL == c->upgr.c) 1169 #endif 1170 mhd_conn_pre_clean_part1 (c); 1171 1172 if (NULL != c->rp.resp_iov.iov) 1173 { 1174 free (c->rp.resp_iov.iov); 1175 c->rp.resp_iov.iov = NULL; 1176 } 1177 if (NULL != c->rp.response) 1178 mhd_response_dec_use_count (c->rp.response); 1179 c->rp.response = NULL; 1180 1181 mhd_assert (NULL != c->pool); 1182 c->read_buffer_offset = 0; 1183 c->read_buffer_size = 0; 1184 c->read_buffer = NULL; 1185 c->write_buffer_send_offset = 0; 1186 c->write_buffer_append_offset = 0; 1187 c->write_buffer_size = 0; 1188 c->write_buffer = NULL; 1189 // TODO: call in the thread where it was allocated for thread-per-connection 1190 mhd_pool_destroy (c->pool); 1191 c->pool = NULL; 1192 1193 c->stage = mhd_HTTP_STAGE_CLOSED; 1194 #ifndef NDEBUG 1195 c->dbg.pre_cleaned = true; 1196 #endif 1197 }