libmicrohttpd2

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

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 }