libmicrohttpd2

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

stream_funcs.c (37744B)


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