libmicrohttpd2

HTTP server C library (MHD 2.x, alpha)
Log | Files | Refs | README | LICENSE

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 }