libmicrohttpd

HTTP/1.x server C library (MHD 1.x, stable)
Log | Files | Refs | Submodules | README | LICENSE

connection.c (282426B)


      1 /*
      2      This file is part of libmicrohttpd
      3      Copyright (C) 2007-2020 Daniel Pittman and Christian Grothoff
      4      Copyright (C) 2015-2024 Evgeny Grin (Karlson2k)
      5 
      6      This library 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      This library 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      You should have received a copy of the GNU Lesser General Public
     17      License along with this library; if not, write to the Free Software
     18      Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
     19 
     20 */
     21 /**
     22  * @file connection.c
     23  * @brief  Methods for managing connections
     24  * @author Daniel Pittman
     25  * @author Christian Grothoff
     26  * @author Karlson2k (Evgeny Grin)
     27  */
     28 #include "internal.h"
     29 #include "mhd_limits.h"
     30 #include "connection.h"
     31 #include "memorypool.h"
     32 #include "response.h"
     33 #include "mhd_mono_clock.h"
     34 #include "mhd_str.h"
     35 #if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS)
     36 #include "mhd_locks.h"
     37 #endif
     38 #include "mhd_sockets.h"
     39 #include "mhd_compat.h"
     40 #include "mhd_itc.h"
     41 #ifdef MHD_LINUX_SOLARIS_SENDFILE
     42 #include <sys/sendfile.h>
     43 #endif /* MHD_LINUX_SOLARIS_SENDFILE */
     44 #if defined(HAVE_FREEBSD_SENDFILE) || defined(HAVE_DARWIN_SENDFILE)
     45 #include <sys/types.h>
     46 #include <sys/socket.h>
     47 #include <sys/uio.h>
     48 #endif /* HAVE_FREEBSD_SENDFILE || HAVE_DARWIN_SENDFILE */
     49 #ifdef HTTPS_SUPPORT
     50 #include "connection_https.h"
     51 #endif /* HTTPS_SUPPORT */
     52 #ifdef HAVE_SYS_PARAM_H
     53 /* For FreeBSD version identification */
     54 #include <sys/param.h>
     55 #endif /* HAVE_SYS_PARAM_H */
     56 #include "mhd_send.h"
     57 #include "mhd_assert.h"
     58 
     59 /**
     60  * Get whether bare LF in HTTP header and other protocol elements
     61  * should be treated as the line termination depending on the configured
     62  * strictness level.
     63  * RFC 9112, section 2.2
     64  */
     65 #define MHD_ALLOW_BARE_LF_AS_CRLF_(discp_lvl) (0 >= discp_lvl)
     66 
     67 /**
     68  * The reasonable length of the upload chunk "header" (the size specifier
     69  * with optional chunk extension).
     70  * MHD tries to keep the space in the read buffer large enough to read
     71  * the chunk "header" in one step.
     72  * The real "header" could be much larger, it will be handled correctly
     73  * anyway, however it may require several rounds of buffer grow.
     74  */
     75 #define MHD_CHUNK_HEADER_REASONABLE_LEN 24
     76 
     77 /**
     78  * Message to transmit when http 1.1 request is received
     79  */
     80 #define HTTP_100_CONTINUE "HTTP/1.1 100 Continue\r\n\r\n"
     81 
     82 /**
     83  * Response text used when the request (http header) is too big to
     84  * be processed.
     85  */
     86 #ifdef HAVE_MESSAGES
     87 #define ERR_MSG_REQUEST_TOO_BIG \
     88   "<html>" \
     89   "<head><title>Request too big</title></head>" \
     90   "<body>Request HTTP header is too big for the memory constraints " \
     91   "of this webserver.</body>" \
     92   "</html>"
     93 #else
     94 #define ERR_MSG_REQUEST_TOO_BIG ""
     95 #endif
     96 
     97 /**
     98  * Response text used when the request header is too big to be processed.
     99  */
    100 #ifdef HAVE_MESSAGES
    101 #define ERR_MSG_REQUEST_HEADER_TOO_BIG \
    102   "<html>" \
    103   "<head><title>Request too big</title></head>" \
    104   "<body><p>The total size of the request headers, which includes the " \
    105   "request target and the request field lines, exceeds the memory " \
    106   "constraints of this web server.</p>" \
    107   "<p>The request could be re-tried with shorter field lines, a shorter " \
    108   "request target or a shorter request method token.</p></body>" \
    109   "</html>"
    110 #else
    111 #define ERR_MSG_REQUEST_HEADER_TOO_BIG ""
    112 #endif
    113 
    114 /**
    115  * Response text used when the request cookie header is too big to be processed.
    116  */
    117 #ifdef HAVE_MESSAGES
    118 #define ERR_MSG_REQUEST_HEADER_WITH_COOKIES_TOO_BIG \
    119   "<html>" \
    120   "<head><title>Request too big</title></head>" \
    121   "<body><p>The total size of the request headers, which includes the " \
    122   "request target and the request field lines, exceeds the memory " \
    123   "constraints of this web server.</p> " \
    124   "<p>The request could be re-tried with smaller " \
    125   "<b>&quot;Cookie:&quot;</b> field value, shorter other field lines, " \
    126   "a shorter request target or a shorter request method token.</p></body> " \
    127   "</html>"
    128 #else
    129 #define ERR_MSG_REQUEST_HEADER_WITH_COOKIES_TOO_BIG ""
    130 #endif
    131 
    132 /**
    133  * Response text used when the request chunk size line with chunk extension
    134  * cannot fit the buffer.
    135  */
    136 #ifdef HAVE_MESSAGES
    137 #define ERR_MSG_REQUEST_CHUNK_LINE_EXT_TOO_BIG \
    138   "<html>" \
    139   "<head><title>Request too big</title></head>" \
    140   "<body><p>The total size of the request target, the request field lines " \
    141   "and the chunk size line exceeds the memory constraints of this web " \
    142   "server.</p>" \
    143   "<p>The request could be re-tried without chunk extensions, with a smaller " \
    144   "chunk size, shorter field lines, a shorter request target or a shorter " \
    145   "request method token.</p></body>" \
    146   "</html>"
    147 #else
    148 #define ERR_MSG_REQUEST_CHUNK_LINE_EXT_TOO_BIG ""
    149 #endif
    150 
    151 /**
    152  * Response text used when the request chunk size line without chunk extension
    153  * cannot fit the buffer.
    154  */
    155 #ifdef HAVE_MESSAGES
    156 #define ERR_MSG_REQUEST_CHUNK_LINE_TOO_BIG \
    157   "<html>" \
    158   "<head><title>Request too big</title></head>" \
    159   "<body><p>The total size of the request target, the request field lines " \
    160   "and the chunk size line exceeds the memory constraints of this web " \
    161   "server.</p>" \
    162   "<p>The request could be re-tried with a smaller " \
    163   "chunk size, shorter field lines, a shorter request target or a shorter " \
    164   "request method token.</p></body>" \
    165   "</html>"
    166 #else
    167 #define ERR_MSG_REQUEST_CHUNK_LINE_TOO_BIG ""
    168 #endif
    169 
    170 /**
    171  * Response text used when the request header is too big to be processed.
    172  */
    173 #ifdef HAVE_MESSAGES
    174 #define ERR_MSG_REQUEST_FOOTER_TOO_BIG \
    175   "<html>" \
    176   "<head><title>Request too big</title></head>" \
    177   "<body><p>The total size of the request headers, which includes the " \
    178   "request target, the request field lines and the chunked trailer " \
    179   "section exceeds the memory constraints of this web server.</p>" \
    180   "<p>The request could be re-tried with a shorter chunked trailer " \
    181   "section, shorter field lines, a shorter request target or " \
    182   "a shorter request method token.</p></body>" \
    183   "</html>"
    184 #else
    185 #define ERR_MSG_REQUEST_FOOTER_TOO_BIG ""
    186 #endif
    187 
    188 /**
    189  * Response text used when the request line has more then two whitespaces.
    190  */
    191 #ifdef HAVE_MESSAGES
    192 #define RQ_LINE_TOO_MANY_WSP \
    193   "<html>" \
    194   "<head><title>Request broken</title></head>" \
    195   "<body>The request line has more then two whitespaces.</body>" \
    196   "</html>"
    197 #else
    198 #define RQ_LINE_TOO_MANY_WSP ""
    199 #endif
    200 
    201 /**
    202  * Response text used when the request HTTP header has bare CR character
    203  * without LF character (and CR is not allowed to be treated as whitespace).
    204  */
    205 #ifdef HAVE_MESSAGES
    206 #define BARE_CR_IN_HEADER \
    207   "<html>" \
    208   "<head><title>Request broken</title></head>" \
    209   "<body>Request HTTP header has bare CR character without " \
    210   "following LF character.</body>" \
    211   "</html>"
    212 #else
    213 #define BARE_CR_IN_HEADER ""
    214 #endif
    215 
    216 /**
    217  * Response text used when the request HTTP footer has bare CR character
    218  * without LF character (and CR is not allowed to be treated as whitespace).
    219  */
    220 #ifdef HAVE_MESSAGES
    221 #define BARE_CR_IN_FOOTER \
    222   "<html>" \
    223   "<head><title>Request broken</title></head>" \
    224   "<body>Request HTTP footer has bare CR character without " \
    225   "following LF character.</body>" \
    226   "</html>"
    227 #else
    228 #define BARE_CR_IN_FOOTER ""
    229 #endif
    230 
    231 /**
    232  * Response text used when the request HTTP header has bare LF character
    233  * without CR character.
    234  */
    235 #ifdef HAVE_MESSAGES
    236 #define BARE_LF_IN_HEADER \
    237   "<html>" \
    238   "<head><title>Request broken</title></head>" \
    239   "<body>Request HTTP header has bare LF character without " \
    240   "preceding CR character.</body>" \
    241   "</html>"
    242 #else
    243 #define BARE_LF_IN_HEADER ""
    244 #endif
    245 
    246 /**
    247  * Response text used when the request HTTP footer has bare LF character
    248  * without CR character.
    249  */
    250 #ifdef HAVE_MESSAGES
    251 #define BARE_LF_IN_FOOTER \
    252   "<html>" \
    253   "<head><title>Request broken</title></head>" \
    254   "<body>Request HTTP footer has bare LF character without " \
    255   "preceding CR character.</body>" \
    256   "</html>"
    257 #else
    258 #define BARE_LF_IN_FOOTER ""
    259 #endif
    260 
    261 /**
    262  * Response text used when the request line has invalid characters in URI.
    263  */
    264 #ifdef HAVE_MESSAGES
    265 #define RQ_TARGET_INVALID_CHAR \
    266   "<html>" \
    267   "<head><title>Request broken</title></head>" \
    268   "<body>HTTP request has invalid characters in " \
    269   "the request-target.</body>" \
    270   "</html>"
    271 #else
    272 #define RQ_TARGET_INVALID_CHAR ""
    273 #endif
    274 
    275 /**
    276  * Response text used when line folding is used in request headers.
    277  */
    278 #ifdef HAVE_MESSAGES
    279 #define ERR_RSP_OBS_FOLD \
    280   "<html>" \
    281   "<head><title>Request broken</title></head>" \
    282   "<body>Obsolete line folding is used in HTTP request header.</body>" \
    283   "</html>"
    284 #else
    285 #define ERR_RSP_OBS_FOLD ""
    286 #endif
    287 
    288 /**
    289  * Response text used when line folding is used in request footers.
    290  */
    291 #ifdef HAVE_MESSAGES
    292 #define ERR_RSP_OBS_FOLD_FOOTER \
    293   "<html>" \
    294   "<head><title>Request broken</title></head>" \
    295   "<body>Obsolete line folding is used in HTTP request footer.</body>" \
    296   "</html>"
    297 #else
    298 #define ERR_RSP_OBS_FOLD_FOOTER ""
    299 #endif
    300 
    301 /**
    302  * Response text used when the request has whitespace at the start
    303  * of the first header line.
    304  */
    305 #ifdef HAVE_MESSAGES
    306 #define ERR_RSP_WSP_BEFORE_HEADER \
    307   "<html>" \
    308   "<head><title>Request broken</title></head>" \
    309   "<body>HTTP request has whitespace between the request line and " \
    310   "the first header.</body>" \
    311   "</html>"
    312 #else
    313 #define ERR_RSP_WSP_BEFORE_HEADER ""
    314 #endif
    315 
    316 /**
    317  * Response text used when the request has whitespace at the start
    318  * of the first footer line.
    319  */
    320 #ifdef HAVE_MESSAGES
    321 #define ERR_RSP_WSP_BEFORE_FOOTER \
    322   "<html>" \
    323   "<head><title>Request broken</title></head>" \
    324   "<body>First HTTP footer line has whitespace at the first " \
    325   "position.</body>" \
    326   "</html>"
    327 #else
    328 #define ERR_RSP_WSP_BEFORE_FOOTER ""
    329 #endif
    330 
    331 /**
    332  * Response text used when the whitespace found before colon (inside header
    333  * name or between header name and colon).
    334  */
    335 #ifdef HAVE_MESSAGES
    336 #define ERR_RSP_WSP_IN_HEADER_NAME \
    337   "<html>" \
    338   "<head><title>Request broken</title></head>" \
    339   "<body>HTTP request has whitespace before the first colon " \
    340   "in header line.</body>" \
    341   "</html>"
    342 #else
    343 #define ERR_RSP_WSP_IN_HEADER_NAME ""
    344 #endif
    345 
    346 /**
    347  * Response text used when the whitespace found before colon (inside header
    348  * name or between header name and colon).
    349  */
    350 #ifdef HAVE_MESSAGES
    351 #define ERR_RSP_WSP_IN_FOOTER_NAME \
    352   "<html>" \
    353   "<head><title>Request broken</title></head>" \
    354   "<body>HTTP request has whitespace before the first colon " \
    355   "in footer line.</body>" \
    356   "</html>"
    357 #else
    358 #define ERR_RSP_WSP_IN_FOOTER_NAME ""
    359 #endif
    360 
    361 
    362 /**
    363  * Response text used when the whitespace found before colon (inside header
    364  * name or between header name and colon).
    365  */
    366 #ifdef HAVE_MESSAGES
    367 #define ERR_RSP_INVALID_CHAR_IN_FIELD_NAME \
    368   "<html>" \
    369   "<head><title>Request broken</title></head>" \
    370   "<body>HTTP request has invalid character in field name.</body>" \
    371   "</html>"
    372 #else
    373 #define ERR_RSP_INVALID_CHAR_IN_FIELD_NAME ""
    374 #endif
    375 
    376 /**
    377  * Response text used when request header has invalid character.
    378  */
    379 #ifdef HAVE_MESSAGES
    380 #define ERR_RSP_INVALID_CHR_IN_HEADER \
    381   "<html>" \
    382   "<head><title>Request broken</title></head>" \
    383   "<body>HTTP request has invalid character in header.</body>" \
    384   "</html>"
    385 #else
    386 #define ERR_RSP_INVALID_CHR_IN_HEADER ""
    387 #endif
    388 
    389 /**
    390  * Response text used when request header has invalid character.
    391  */
    392 #ifdef HAVE_MESSAGES
    393 #define ERR_RSP_INVALID_CHR_IN_FOOTER \
    394   "<html>" \
    395   "<head><title>Request broken</title></head>" \
    396   "<body>HTTP request has invalid character in footer.</body>" \
    397   "</html>"
    398 #else
    399 #define ERR_RSP_INVALID_CHR_IN_FOOTER ""
    400 #endif
    401 
    402 /**
    403  * Response text used when request header has no colon character.
    404  */
    405 #ifdef HAVE_MESSAGES
    406 #define ERR_RSP_HEADER_WITHOUT_COLON \
    407   "<html>" \
    408   "<head><title>Request broken</title></head>" \
    409   "<body>HTTP request header line has no colon character.</body>" \
    410   "</html>"
    411 #else
    412 #define ERR_RSP_HEADER_WITHOUT_COLON ""
    413 #endif
    414 
    415 /**
    416  * Response text used when request footer has no colon character.
    417  */
    418 #ifdef HAVE_MESSAGES
    419 #define ERR_RSP_FOOTER_WITHOUT_COLON \
    420   "<html>" \
    421   "<head><title>Request broken</title></head>" \
    422   "<body>HTTP request footer line has no colon character.</body>" \
    423   "</html>"
    424 #else
    425 #define ERR_RSP_FOOTER_WITHOUT_COLON ""
    426 #endif
    427 
    428 /**
    429  * Response text used when request header has zero-length header (filed) name.
    430  */
    431 #ifdef HAVE_MESSAGES
    432 #define ERR_RSP_EMPTY_HEADER_NAME \
    433   "<html>" \
    434   "<head><title>Request broken</title></head>" \
    435   "<body>HTTP request header has empty header name.</body>" \
    436   "</html>"
    437 #else
    438 #define ERR_RSP_EMPTY_HEADER_NAME ""
    439 #endif
    440 
    441 /**
    442  * Response text used when request header has zero-length header (filed) name.
    443  */
    444 #ifdef HAVE_MESSAGES
    445 #define ERR_RSP_EMPTY_FOOTER_NAME \
    446   "<html>" \
    447   "<head><title>Request broken</title></head>" \
    448   "<body>HTTP request footer has empty footer name.</body>" \
    449   "</html>"
    450 #else
    451 #define ERR_RSP_EMPTY_FOOTER_NAME ""
    452 #endif
    453 
    454 /**
    455  * Response text used when the request (http header) does not
    456  * contain a "Host:" header and still claims to be HTTP 1.1.
    457  *
    458  * Intentionally empty here to keep our memory footprint
    459  * minimal.
    460  */
    461 #ifdef HAVE_MESSAGES
    462 #define REQUEST_LACKS_HOST \
    463   "<html>" \
    464   "<head><title>&quot;Host:&quot; header required</title></head>" \
    465   "<body>HTTP/1.1 request without <b>&quot;Host:&quot;</b>.</body>" \
    466   "</html>"
    467 
    468 #else
    469 #define REQUEST_LACKS_HOST ""
    470 #endif
    471 
    472 /**
    473  * Response text used when the request has unsupported "Transfer-Encoding:".
    474  */
    475 #ifdef HAVE_MESSAGES
    476 #define REQUEST_UNSUPPORTED_TR_ENCODING \
    477   "<html>" \
    478   "<head><title>Unsupported Transfer-Encoding</title></head>" \
    479   "<body>The Transfer-Encoding used in request is not supported.</body>" \
    480   "</html>"
    481 #else
    482 #define REQUEST_UNSUPPORTED_TR_ENCODING ""
    483 #endif
    484 
    485 /**
    486  * Response text used when the request has unsupported both headers:
    487  * "Transfer-Encoding:" and "Content-Length:"
    488  */
    489 #ifdef HAVE_MESSAGES
    490 #define REQUEST_LENGTH_WITH_TR_ENCODING \
    491   "<html>" \
    492   "<head><title>Malformed request</title></head>" \
    493   "<body>Wrong combination of the request headers: both Transfer-Encoding " \
    494   "and Content-Length headers are used at the same time.</body>" \
    495   "</html>"
    496 #else
    497 #define REQUEST_LENGTH_WITH_TR_ENCODING ""
    498 #endif
    499 
    500 /**
    501  * Response text used when the request (http header) is
    502  * malformed.
    503  *
    504  * Intentionally empty here to keep our memory footprint
    505  * minimal.
    506  */
    507 #ifdef HAVE_MESSAGES
    508 #define REQUEST_MALFORMED \
    509   "<html><head><title>Request malformed</title></head>" \
    510   "<body>HTTP request is syntactically incorrect.</body></html>"
    511 #else
    512 #define REQUEST_MALFORMED ""
    513 #endif
    514 
    515 /**
    516  * Response text used when the request HTTP chunked encoding is
    517  * malformed.
    518  */
    519 #ifdef HAVE_MESSAGES
    520 #define REQUEST_CHUNKED_MALFORMED \
    521   "<html><head><title>Request malformed</title></head>" \
    522   "<body>HTTP chunked encoding is syntactically incorrect.</body></html>"
    523 #else
    524 #define REQUEST_CHUNKED_MALFORMED ""
    525 #endif
    526 
    527 /**
    528  * Response text used when the request HTTP chunk is too large.
    529  */
    530 #ifdef HAVE_MESSAGES
    531 #define REQUEST_CHUNK_TOO_LARGE \
    532   "<html><head><title>Request content too large</title></head>" \
    533   "<body>The chunk size used in HTTP chunked encoded " \
    534   "request is too large.</body></html>"
    535 #else
    536 #define REQUEST_CHUNK_TOO_LARGE ""
    537 #endif
    538 
    539 /**
    540  * Response text used when the request HTTP content is too large.
    541  */
    542 #ifdef HAVE_MESSAGES
    543 #define REQUEST_CONTENTLENGTH_TOOLARGE \
    544   "<html><head><title>Request content too large</title></head>" \
    545   "<body>HTTP request has too large value for " \
    546   "<b>Content-Length</b> header.</body></html>"
    547 #else
    548 #define REQUEST_CONTENTLENGTH_TOOLARGE ""
    549 #endif
    550 
    551 /**
    552  * Response text used when the request HTTP chunked encoding is
    553  * malformed.
    554  */
    555 #ifdef HAVE_MESSAGES
    556 #define REQUEST_CONTENTLENGTH_MALFORMED \
    557   "<html><head><title>Request malformed</title></head>" \
    558   "<body>HTTP request has wrong value for " \
    559   "<b>Content-Length</b> header.</body></html>"
    560 #else
    561 #define REQUEST_CONTENTLENGTH_MALFORMED ""
    562 #endif
    563 
    564 /**
    565  * Response text used when there is an internal server error.
    566  *
    567  * Intentionally empty here to keep our memory footprint
    568  * minimal.
    569  */
    570 #ifdef HAVE_MESSAGES
    571 #define ERROR_MSG_DATA_NOT_HANDLED_BY_APP \
    572   "<html><head><title>Internal server error</title></head>" \
    573   "<body>Please ask the developer of this Web server to carefully " \
    574   "read the GNU libmicrohttpd documentation about connection " \
    575   "management and blocking.</body></html>"
    576 #else
    577 #define ERROR_MSG_DATA_NOT_HANDLED_BY_APP ""
    578 #endif
    579 
    580 /**
    581  * Response text used when the request HTTP version is too old.
    582  */
    583 #ifdef HAVE_MESSAGES
    584 #define REQ_HTTP_VER_IS_TOO_OLD \
    585   "<html><head><title>Requested HTTP version is not supported</title></head>" \
    586   "<body>Requested HTTP version is too old and not " \
    587   "supported.</body></html>"
    588 #else
    589 #define REQ_HTTP_VER_IS_TOO_OLD ""
    590 #endif
    591 
    592 /**
    593  * Response text used when the request HTTP version is not supported.
    594  */
    595 #ifdef HAVE_MESSAGES
    596 #define REQ_HTTP_VER_IS_NOT_SUPPORTED \
    597   "<html><head><title>Requested HTTP version is not supported</title></head>" \
    598   "<body>Requested HTTP version is not supported.</body></html>"
    599 #else
    600 #define REQ_HTTP_VER_IS_NOT_SUPPORTED ""
    601 #endif
    602 
    603 
    604 /**
    605  * sendfile() chuck size
    606  */
    607 #define MHD_SENFILE_CHUNK_         (0x20000)
    608 
    609 /**
    610  * sendfile() chuck size for thread-per-connection
    611  */
    612 #define MHD_SENFILE_CHUNK_THR_P_C_ (0x200000)
    613 
    614 #ifdef HAVE_MESSAGES
    615 /**
    616  * Return text description for MHD_ERR_*_ codes
    617  * @param mhd_err_code the error code
    618  * @return pointer to static string with error description
    619  */
    620 static const char *
    621 str_conn_error_ (ssize_t mhd_err_code)
    622 {
    623   switch (mhd_err_code)
    624   {
    625   case MHD_ERR_AGAIN_:
    626     return _ ("The operation would block, retry later");
    627   case MHD_ERR_CONNRESET_:
    628     return _ ("The connection was forcibly closed by remote peer");
    629   case MHD_ERR_NOTCONN_:
    630     return _ ("The socket is not connected");
    631   case MHD_ERR_NOMEM_:
    632     return _ ("Not enough system resources to serve the request");
    633   case MHD_ERR_BADF_:
    634     return _ ("Bad FD value");
    635   case MHD_ERR_INVAL_:
    636     return _ ("Argument value is invalid");
    637   case MHD_ERR_OPNOTSUPP_:
    638     return _ ("Argument value is not supported");
    639   case MHD_ERR_PIPE_:
    640     return _ ("The socket is no longer available for sending");
    641   case MHD_ERR_TLS_:
    642     return _ ("TLS encryption or decryption error");
    643   default:
    644     break;   /* Mute compiler warning */
    645   }
    646   if (0 <= mhd_err_code)
    647     return _ ("Not an error code");
    648 
    649   mhd_assert (0); /* Should never be reachable */
    650   return _ ("Wrong error code value");
    651 }
    652 
    653 
    654 #endif /* HAVE_MESSAGES */
    655 
    656 /**
    657  * Allocate memory from connection's memory pool.
    658  * If memory pool doesn't have enough free memory but read or write buffer
    659  * have some unused memory, the size of the buffer will be reduced as needed.
    660  * @param connection the connection to use
    661  * @param size the size of allocated memory area
    662  * @return pointer to allocated memory region in the pool or
    663  *         NULL if no memory is available
    664  */
    665 void *
    666 MHD_connection_alloc_memory_ (struct MHD_Connection *connection,
    667                               size_t size)
    668 {
    669   struct MHD_Connection *const c = connection; /* a short alias */
    670   struct MemoryPool *const pool = c->pool;     /* a short alias */
    671   size_t need_to_be_freed = 0; /**< The required amount of additional free memory */
    672   void *res;
    673 
    674   res = MHD_pool_try_alloc (pool,
    675                             size,
    676                             &need_to_be_freed);
    677   if (NULL != res)
    678     return res;
    679 
    680   if (MHD_pool_is_resizable_inplace (pool,
    681                                      c->write_buffer,
    682                                      c->write_buffer_size))
    683   {
    684     if (c->write_buffer_size - c->write_buffer_append_offset >=
    685         need_to_be_freed)
    686     {
    687       char *buf;
    688       const size_t new_buf_size = c->write_buffer_size - need_to_be_freed;
    689       buf = MHD_pool_reallocate (pool,
    690                                  c->write_buffer,
    691                                  c->write_buffer_size,
    692                                  new_buf_size);
    693       mhd_assert (c->write_buffer == buf);
    694       mhd_assert (c->write_buffer_append_offset <= new_buf_size);
    695       mhd_assert (c->write_buffer_send_offset <= new_buf_size);
    696       c->write_buffer_size = new_buf_size;
    697       c->write_buffer = buf;
    698     }
    699     else
    700       return NULL;
    701   }
    702   else if (MHD_pool_is_resizable_inplace (pool,
    703                                           c->read_buffer,
    704                                           c->read_buffer_size))
    705   {
    706     if (c->read_buffer_size - c->read_buffer_offset >= need_to_be_freed)
    707     {
    708       char *buf;
    709       const size_t new_buf_size = c->read_buffer_size - need_to_be_freed;
    710       buf = MHD_pool_reallocate (pool,
    711                                  c->read_buffer,
    712                                  c->read_buffer_size,
    713                                  new_buf_size);
    714       mhd_assert (c->read_buffer == buf);
    715       mhd_assert (c->read_buffer_offset <= new_buf_size);
    716       c->read_buffer_size = new_buf_size;
    717       c->read_buffer = buf;
    718     }
    719     else
    720       return NULL;
    721   }
    722   else
    723     return NULL;
    724   res = MHD_pool_allocate (pool, size, true);
    725   mhd_assert (NULL != res); /* It has been checked that pool has enough space */
    726   return res;
    727 }
    728 
    729 
    730 /**
    731  * Callback for receiving data from the socket.
    732  *
    733  * @param connection the MHD connection structure
    734  * @param other where to write received data to
    735  * @param i maximum size of other (in bytes)
    736  * @return positive value for number of bytes actually received or
    737  *         negative value for error number MHD_ERR_xxx_
    738  */
    739 static ssize_t
    740 recv_param_adapter (struct MHD_Connection *connection,
    741                     void *other,
    742                     size_t i)
    743 {
    744   ssize_t ret;
    745 
    746   if ( (MHD_INVALID_SOCKET == connection->socket_fd) ||
    747        (MHD_CONNECTION_CLOSED == connection->state) )
    748   {
    749     return MHD_ERR_NOTCONN_;
    750   }
    751   if (i > MHD_SCKT_SEND_MAX_SIZE_)
    752     i = MHD_SCKT_SEND_MAX_SIZE_; /* return value limit */
    753 
    754   ret = MHD_recv_ (connection->socket_fd,
    755                    other,
    756                    i);
    757   if (0 > ret)
    758   {
    759     const int err = MHD_socket_get_error_ ();
    760     if (MHD_SCKT_ERR_IS_EAGAIN_ (err))
    761     {
    762 #ifdef EPOLL_SUPPORT
    763       /* Got EAGAIN --- no longer read-ready */
    764       connection->epoll_state &=
    765         ~((enum MHD_EpollState) MHD_EPOLL_STATE_READ_READY);
    766 #endif /* EPOLL_SUPPORT */
    767       return MHD_ERR_AGAIN_;
    768     }
    769     if (MHD_SCKT_ERR_IS_EINTR_ (err))
    770       return MHD_ERR_AGAIN_;
    771     if (MHD_SCKT_ERR_IS_REMOTE_DISCNN_ (err))
    772       return MHD_ERR_CONNRESET_;
    773     if (MHD_SCKT_ERR_IS_ (err, MHD_SCKT_EOPNOTSUPP_))
    774       return MHD_ERR_OPNOTSUPP_;
    775     if (MHD_SCKT_ERR_IS_ (err, MHD_SCKT_ENOTCONN_))
    776       return MHD_ERR_NOTCONN_;
    777     if (MHD_SCKT_ERR_IS_ (err, MHD_SCKT_EINVAL_))
    778       return MHD_ERR_INVAL_;
    779     if (MHD_SCKT_ERR_IS_LOW_RESOURCES_ (err))
    780       return MHD_ERR_NOMEM_;
    781     if (MHD_SCKT_ERR_IS_ (err, MHD_SCKT_EBADF_))
    782       return MHD_ERR_BADF_;
    783     /* Treat any other error as a hard error. */
    784     return MHD_ERR_NOTCONN_;
    785   }
    786 #ifdef EPOLL_SUPPORT
    787   else if (i > (size_t) ret)
    788     connection->epoll_state &=
    789       ~((enum MHD_EpollState) MHD_EPOLL_STATE_READ_READY);
    790 #endif /* EPOLL_SUPPORT */
    791   return ret;
    792 }
    793 
    794 
    795 /**
    796  * Get all of the headers from the request.
    797  *
    798  * @param connection connection to get values from
    799  * @param kind types of values to iterate over, can be a bitmask
    800  * @param iterator callback to call on each header;
    801  *        maybe NULL (then just count headers)
    802  * @param iterator_cls extra argument to @a iterator
    803  * @return number of entries iterated over
    804  *         -1 if connection is NULL.
    805  * @ingroup request
    806  */
    807 _MHD_EXTERN int
    808 MHD_get_connection_values (struct MHD_Connection *connection,
    809                            enum MHD_ValueKind kind,
    810                            MHD_KeyValueIterator iterator,
    811                            void *iterator_cls)
    812 {
    813   int ret;
    814   struct MHD_HTTP_Req_Header *pos;
    815 
    816   if (NULL == connection)
    817     return -1;
    818   ret = 0;
    819   for (pos = connection->rq.headers_received; NULL != pos; pos = pos->next)
    820     if (0 != (pos->kind & kind))
    821     {
    822       ret++;
    823       if ( (NULL != iterator) &&
    824            (MHD_NO == iterator (iterator_cls,
    825                                 pos->kind,
    826                                 pos->header,
    827                                 pos->value)) )
    828         return ret;
    829     }
    830   return ret;
    831 }
    832 
    833 
    834 /**
    835  * Get all of the headers from the request.
    836  *
    837  * @param connection connection to get values from
    838  * @param kind types of values to iterate over, can be a bitmask
    839  * @param iterator callback to call on each header;
    840  *        maybe NULL (then just count headers)
    841  * @param iterator_cls extra argument to @a iterator
    842  * @return number of entries iterated over,
    843  *         -1 if connection is NULL.
    844  * @ingroup request
    845  */
    846 _MHD_EXTERN int
    847 MHD_get_connection_values_n (struct MHD_Connection *connection,
    848                              enum MHD_ValueKind kind,
    849                              MHD_KeyValueIteratorN iterator,
    850                              void *iterator_cls)
    851 {
    852   int ret;
    853   struct MHD_HTTP_Req_Header *pos;
    854 
    855   if (NULL == connection)
    856     return -1;
    857   ret = 0;
    858 
    859   if (NULL == iterator)
    860     for (pos = connection->rq.headers_received; NULL != pos; pos = pos->next)
    861     {
    862       if (0 != (kind & pos->kind))
    863         ret++;
    864     }
    865   else
    866     for (pos = connection->rq.headers_received; NULL != pos; pos = pos->next)
    867       if (0 != (kind & pos->kind))
    868       {
    869         ret++;
    870         if (MHD_NO == iterator (iterator_cls,
    871                                 pos->kind,
    872                                 pos->header,
    873                                 pos->header_size,
    874                                 pos->value,
    875                                 pos->value_size))
    876           return ret;
    877       }
    878   return ret;
    879 }
    880 
    881 
    882 /**
    883  * This function can be used to add an arbitrary entry to connection.
    884  * Internal version of #MHD_set_connection_value_n() without checking
    885  * of arguments values.
    886  *
    887  * @param connection the connection for which a
    888  *                   value should be set
    889  * @param kind kind of the value
    890  * @param key key for the value, must be zero-terminated
    891  * @param key_size number of bytes in @a key (excluding 0-terminator)
    892  * @param value the value itself, must be zero-terminated
    893  * @param value_size number of bytes in @a value (excluding 0-terminator)
    894  * @return #MHD_NO if the operation could not be
    895  *         performed due to insufficient memory;
    896  *         #MHD_YES on success
    897  * @ingroup request
    898  */
    899 static enum MHD_Result
    900 MHD_set_connection_value_n_nocheck_ (struct MHD_Connection *connection,
    901                                      enum MHD_ValueKind kind,
    902                                      const char *key,
    903                                      size_t key_size,
    904                                      const char *value,
    905                                      size_t value_size)
    906 {
    907   struct MHD_HTTP_Req_Header *pos;
    908 
    909   pos = MHD_connection_alloc_memory_ (connection,
    910                                       sizeof (struct MHD_HTTP_Res_Header));
    911   if (NULL == pos)
    912     return MHD_NO;
    913   pos->header = key;
    914   pos->header_size = key_size;
    915   pos->value = value;
    916   pos->value_size = value_size;
    917   pos->kind = kind;
    918   pos->next = NULL;
    919   /* append 'pos' to the linked list of headers */
    920   if (NULL == connection->rq.headers_received_tail)
    921   {
    922     connection->rq.headers_received = pos;
    923     connection->rq.headers_received_tail = pos;
    924   }
    925   else
    926   {
    927     connection->rq.headers_received_tail->next = pos;
    928     connection->rq.headers_received_tail = pos;
    929   }
    930   return MHD_YES;
    931 }
    932 
    933 
    934 /**
    935  * This function can be used to add an arbitrary entry to connection.
    936  * This function could add entry with binary zero, which is allowed
    937  * for #MHD_GET_ARGUMENT_KIND. For other kind on entries it is
    938  * recommended to use #MHD_set_connection_value.
    939  *
    940  * This function MUST only be called from within the
    941  * #MHD_AccessHandlerCallback (otherwise, access maybe improperly
    942  * synchronized).  Furthermore, the client must guarantee that the key
    943  * and value arguments are 0-terminated strings that are NOT freed
    944  * until the connection is closed.  (The easiest way to do this is by
    945  * passing only arguments to permanently allocated strings.).
    946  *
    947  * @param connection the connection for which a
    948  *  value should be set
    949  * @param kind kind of the value
    950  * @param key key for the value, must be zero-terminated
    951  * @param key_size number of bytes in @a key (excluding 0-terminator)
    952  * @param value the value itself, must be zero-terminated
    953  * @param value_size number of bytes in @a value (excluding 0-terminator)
    954  * @return #MHD_NO if the operation could not be
    955  *         performed due to insufficient memory;
    956  *         #MHD_YES on success
    957  * @ingroup request
    958  */
    959 _MHD_EXTERN enum MHD_Result
    960 MHD_set_connection_value_n (struct MHD_Connection *connection,
    961                             enum MHD_ValueKind kind,
    962                             const char *key,
    963                             size_t key_size,
    964                             const char *value,
    965                             size_t value_size)
    966 {
    967   if ( (MHD_GET_ARGUMENT_KIND != kind) &&
    968        ( ((key ? strlen (key) : 0) != key_size) ||
    969          ((value ? strlen (value) : 0) != value_size) ) )
    970     return MHD_NO; /* binary zero is allowed only in GET arguments */
    971 
    972   return MHD_set_connection_value_n_nocheck_ (connection,
    973                                               kind,
    974                                               key,
    975                                               key_size,
    976                                               value,
    977                                               value_size);
    978 }
    979 
    980 
    981 /**
    982  * This function can be used to add an entry to the HTTP headers of a
    983  * connection (so that the #MHD_get_connection_values function will
    984  * return them -- and the `struct MHD_PostProcessor` will also see
    985  * them).  This maybe required in certain situations (see Mantis
    986  * #1399) where (broken) HTTP implementations fail to supply values
    987  * needed by the post processor (or other parts of the application).
    988  *
    989  * This function MUST only be called from within the
    990  * #MHD_AccessHandlerCallback (otherwise, access maybe improperly
    991  * synchronized).  Furthermore, the client must guarantee that the key
    992  * and value arguments are 0-terminated strings that are NOT freed
    993  * until the connection is closed.  (The easiest way to do this is by
    994  * passing only arguments to permanently allocated strings.).
    995  *
    996  * @param connection the connection for which a
    997  *  value should be set
    998  * @param kind kind of the value
    999  * @param key key for the value
   1000  * @param value the value itself
   1001  * @return #MHD_NO if the operation could not be
   1002  *         performed due to insufficient memory;
   1003  *         #MHD_YES on success
   1004  * @ingroup request
   1005  */
   1006 _MHD_EXTERN enum MHD_Result
   1007 MHD_set_connection_value (struct MHD_Connection *connection,
   1008                           enum MHD_ValueKind kind,
   1009                           const char *key,
   1010                           const char *value)
   1011 {
   1012   return MHD_set_connection_value_n_nocheck_ (connection,
   1013                                               kind,
   1014                                               key,
   1015                                               NULL != key
   1016                                               ? strlen (key)
   1017                                               : 0,
   1018                                               value,
   1019                                               NULL != value
   1020                                               ? strlen (value)
   1021                                               : 0);
   1022 }
   1023 
   1024 
   1025 /**
   1026  * Get a particular header value.  If multiple
   1027  * values match the kind, return any one of them.
   1028  *
   1029  * @param connection connection to get values from
   1030  * @param kind what kind of value are we looking for
   1031  * @param key the header to look for, NULL to lookup 'trailing' value without a key
   1032  * @return NULL if no such item was found
   1033  * @ingroup request
   1034  */
   1035 _MHD_EXTERN const char *
   1036 MHD_lookup_connection_value (struct MHD_Connection *connection,
   1037                              enum MHD_ValueKind kind,
   1038                              const char *key)
   1039 {
   1040   const char *value;
   1041 
   1042   value = NULL;
   1043   (void) MHD_lookup_connection_value_n (connection,
   1044                                         kind,
   1045                                         key,
   1046                                         (NULL == key) ? 0 : strlen (key),
   1047                                         &value,
   1048                                         NULL);
   1049   return value;
   1050 }
   1051 
   1052 
   1053 /**
   1054  * Get a particular header value.  If multiple
   1055  * values match the kind, return any one of them.
   1056  * @note Since MHD_VERSION 0x00096304
   1057  *
   1058  * @param connection connection to get values from
   1059  * @param kind what kind of value are we looking for
   1060  * @param key the header to look for, NULL to lookup 'trailing' value without a key
   1061  * @param key_size the length of @a key in bytes
   1062  * @param[out] value_ptr the pointer to variable, which will be set to found value,
   1063  *                       will not be updated if key not found,
   1064  *                       could be NULL to just check for presence of @a key
   1065  * @param[out] value_size_ptr the pointer variable, which will set to found value,
   1066  *                            will not be updated if key not found,
   1067  *                            could be NULL
   1068  * @return #MHD_YES if key is found,
   1069  *         #MHD_NO otherwise.
   1070  * @ingroup request
   1071  */
   1072 _MHD_EXTERN enum MHD_Result
   1073 MHD_lookup_connection_value_n (struct MHD_Connection *connection,
   1074                                enum MHD_ValueKind kind,
   1075                                const char *key,
   1076                                size_t key_size,
   1077                                const char **value_ptr,
   1078                                size_t *value_size_ptr)
   1079 {
   1080   struct MHD_HTTP_Req_Header *pos;
   1081 
   1082   if (NULL == connection)
   1083     return MHD_NO;
   1084 
   1085   if (NULL == key)
   1086   {
   1087     for (pos = connection->rq.headers_received; NULL != pos; pos = pos->next)
   1088     {
   1089       if ( (0 != (kind & pos->kind)) &&
   1090            (NULL == pos->header) )
   1091         break;
   1092     }
   1093   }
   1094   else
   1095   {
   1096     for (pos = connection->rq.headers_received; NULL != pos; pos = pos->next)
   1097     {
   1098       if ( (0 != (kind & pos->kind)) &&
   1099            (key_size == pos->header_size) &&
   1100            ( (key == pos->header) ||
   1101              (MHD_str_equal_caseless_bin_n_ (key,
   1102                                              pos->header,
   1103                                              key_size) ) ) )
   1104         break;
   1105     }
   1106   }
   1107 
   1108   if (NULL == pos)
   1109     return MHD_NO;
   1110 
   1111   if (NULL != value_ptr)
   1112     *value_ptr = pos->value;
   1113 
   1114   if (NULL != value_size_ptr)
   1115     *value_size_ptr = pos->value_size;
   1116 
   1117   return MHD_YES;
   1118 }
   1119 
   1120 
   1121 /**
   1122  * Check whether request header contains particular token.
   1123  *
   1124  * Token could be surrounded by spaces and tabs and delimited by comma.
   1125  * Case-insensitive match used for header names and tokens.
   1126  * @param connection the connection to get values from
   1127  * @param header     the header name
   1128  * @param header_len the length of header, not including optional
   1129  *                   terminating null-character
   1130  * @param token      the token to find
   1131  * @param token_len  the length of token, not including optional
   1132  *                   terminating null-character.
   1133  * @return true if token is found in specified header,
   1134  *         false otherwise
   1135  */
   1136 static bool
   1137 MHD_lookup_header_token_ci (const struct MHD_Connection *connection,
   1138                             const char *header,
   1139                             size_t header_len,
   1140                             const char *token,
   1141                             size_t token_len)
   1142 {
   1143   struct MHD_HTTP_Req_Header *pos;
   1144 
   1145   if ((NULL == connection) || (NULL == header) || (0 == header[0]) ||
   1146       (NULL == token) || (0 == token[0]))
   1147     return false;
   1148 
   1149   for (pos = connection->rq.headers_received; NULL != pos; pos = pos->next)
   1150   {
   1151     if ((0 != (pos->kind & MHD_HEADER_KIND)) &&
   1152         (header_len == pos->header_size) &&
   1153         ( (header == pos->header) ||
   1154           (MHD_str_equal_caseless_bin_n_ (header,
   1155                                           pos->header,
   1156                                           header_len)) ) &&
   1157         (MHD_str_has_token_caseless_ (pos->value, token, token_len)))
   1158       return true;
   1159   }
   1160   return false;
   1161 }
   1162 
   1163 
   1164 /**
   1165  * Check whether request header contains particular static @a tkn.
   1166  *
   1167  * Token could be surrounded by spaces and tabs and delimited by comma.
   1168  * Case-insensitive match used for header names and tokens.
   1169  * @param c   the connection to get values from
   1170  * @param h   the static string of header name
   1171  * @param tkn the static string of token to find
   1172  * @return true if token is found in specified header,
   1173  *         false otherwise
   1174  */
   1175 #define MHD_lookup_header_s_token_ci(c,h,tkn) \
   1176   MHD_lookup_header_token_ci ((c),(h),MHD_STATICSTR_LEN_ (h), \
   1177                               (tkn),MHD_STATICSTR_LEN_ (tkn))
   1178 
   1179 
   1180 /**
   1181  * Do we (still) need to send a 100 continue
   1182  * message for this connection?
   1183  *
   1184  * @param connection connection to test
   1185  * @return false if we don't need 100 CONTINUE, true if we do
   1186  */
   1187 static bool
   1188 need_100_continue (struct MHD_Connection *connection)
   1189 {
   1190   const char *expect;
   1191 
   1192   if (! MHD_IS_HTTP_VER_1_1_COMPAT (connection->rq.http_ver))
   1193     return false;
   1194 
   1195   if (0 == connection->rq.remaining_upload_size)
   1196     return false;
   1197 
   1198   if (MHD_NO ==
   1199       MHD_lookup_connection_value_n (connection,
   1200                                      MHD_HEADER_KIND,
   1201                                      MHD_HTTP_HEADER_EXPECT,
   1202                                      MHD_STATICSTR_LEN_ ( \
   1203                                        MHD_HTTP_HEADER_EXPECT),
   1204                                      &expect,
   1205                                      NULL))
   1206     return false;
   1207 
   1208   if (MHD_str_equal_caseless_ (expect,
   1209                                "100-continue"))
   1210     return true;
   1211 
   1212   return false;
   1213 }
   1214 
   1215 
   1216 /**
   1217  * Mark connection as "closed".
   1218  * @remark To be called from any thread.
   1219  *
   1220  * @param connection connection to close
   1221  */
   1222 void
   1223 MHD_connection_mark_closed_ (struct MHD_Connection *connection)
   1224 {
   1225   const struct MHD_Daemon *daemon = connection->daemon;
   1226 
   1227   if (0 == (daemon->options & MHD_USE_TURBO))
   1228   {
   1229 #ifdef HTTPS_SUPPORT
   1230     /* For TLS connection use shutdown of TLS layer
   1231      * and do not shutdown TCP socket. This give more
   1232      * chances to send TLS closure data to remote side.
   1233      * Closure of TLS layer will be interpreted by
   1234      * remote side as end of transmission. */
   1235     if (0 != (daemon->options & MHD_USE_TLS))
   1236     {
   1237       if (! MHD_tls_connection_shutdown (connection))
   1238         shutdown (connection->socket_fd,
   1239                   SHUT_WR);
   1240     }
   1241     else   /* Combined with next 'shutdown()'. */
   1242 #endif /* HTTPS_SUPPORT */
   1243     shutdown (connection->socket_fd,
   1244               SHUT_WR);
   1245   }
   1246   connection->state = MHD_CONNECTION_CLOSED;
   1247   connection->event_loop_info = MHD_EVENT_LOOP_INFO_CLEANUP;
   1248 }
   1249 
   1250 
   1251 /**
   1252  * Close the given connection and give the
   1253  * specified termination code to the user.
   1254  * @remark To be called only from thread that
   1255  * process connection's recv(), send() and response.
   1256  *
   1257  * @param connection connection to close
   1258  * @param termination_code termination reason to give
   1259  */
   1260 void
   1261 MHD_connection_close_ (struct MHD_Connection *connection,
   1262                        enum MHD_RequestTerminationCode termination_code)
   1263 {
   1264   struct MHD_Daemon *daemon = connection->daemon;
   1265   struct MHD_Response *resp = connection->rp.response;
   1266 
   1267   mhd_assert (! connection->suspended);
   1268 #ifdef MHD_USE_THREADS
   1269   mhd_assert ( (! MHD_D_IS_USING_THREADS_ (daemon)) || \
   1270                MHD_thread_handle_ID_is_current_thread_ (connection->tid) );
   1271 #endif /* MHD_USE_THREADS */
   1272   if ( (NULL != daemon->notify_completed) &&
   1273        (connection->rq.client_aware) )
   1274     daemon->notify_completed (daemon->notify_completed_cls,
   1275                               connection,
   1276                               &connection->rq.client_context,
   1277                               termination_code);
   1278   connection->rq.client_aware = false;
   1279   if (NULL != resp)
   1280   {
   1281     connection->rp.response = NULL;
   1282     MHD_destroy_response (resp);
   1283   }
   1284   if (NULL != connection->pool)
   1285   {
   1286     MHD_pool_destroy (connection->pool);
   1287     connection->pool = NULL;
   1288   }
   1289 
   1290   MHD_connection_mark_closed_ (connection);
   1291 }
   1292 
   1293 
   1294 #if defined(HTTPS_SUPPORT) && defined(UPGRADE_SUPPORT)
   1295 /**
   1296  * Stop TLS forwarding on upgraded connection and
   1297  * reflect remote disconnect state to socketpair.
   1298  * @remark In thread-per-connection mode this function
   1299  * can be called from any thread, in other modes this
   1300  * function must be called only from thread that process
   1301  * daemon's select()/poll()/etc.
   1302  *
   1303  * @param connection the upgraded connection
   1304  */
   1305 void
   1306 MHD_connection_finish_forward_ (struct MHD_Connection *connection)
   1307 {
   1308   struct MHD_Daemon *daemon = connection->daemon;
   1309   struct MHD_UpgradeResponseHandle *urh = connection->urh;
   1310 
   1311 #ifdef MHD_USE_THREADS
   1312   mhd_assert ( (! MHD_D_IS_USING_THREADS_ (daemon)) || \
   1313                MHD_D_IS_USING_THREAD_PER_CONN_ (daemon) || \
   1314                MHD_thread_handle_ID_is_current_thread_ (daemon->tid) );
   1315 #endif /* MHD_USE_THREADS */
   1316 
   1317   if (0 == (daemon->options & MHD_USE_TLS))
   1318     return; /* Nothing to do with non-TLS connection. */
   1319 
   1320   if (! MHD_D_IS_USING_THREAD_PER_CONN_ (daemon))
   1321     DLL_remove (daemon->urh_head,
   1322                 daemon->urh_tail,
   1323                 urh);
   1324 #ifdef EPOLL_SUPPORT
   1325   if (MHD_D_IS_USING_EPOLL_ (daemon) &&
   1326       (0 != epoll_ctl (daemon->epoll_upgrade_fd,
   1327                        EPOLL_CTL_DEL,
   1328                        connection->socket_fd,
   1329                        NULL)) )
   1330   {
   1331     MHD_PANIC (_ ("Failed to remove FD from epoll set.\n"));
   1332   }
   1333   if (urh->in_eready_list)
   1334   {
   1335     EDLL_remove (daemon->eready_urh_head,
   1336                  daemon->eready_urh_tail,
   1337                  urh);
   1338     urh->in_eready_list = false;
   1339   }
   1340 #endif /* EPOLL_SUPPORT */
   1341   if (MHD_INVALID_SOCKET != urh->mhd.socket)
   1342   {
   1343 #ifdef EPOLL_SUPPORT
   1344     if (MHD_D_IS_USING_EPOLL_ (daemon) &&
   1345         (0 != epoll_ctl (daemon->epoll_upgrade_fd,
   1346                          EPOLL_CTL_DEL,
   1347                          urh->mhd.socket,
   1348                          NULL)) )
   1349     {
   1350       MHD_PANIC (_ ("Failed to remove FD from epoll set.\n"));
   1351     }
   1352 #endif /* EPOLL_SUPPORT */
   1353     /* Reflect remote disconnect to application by breaking
   1354      * socketpair connection. */
   1355     shutdown (urh->mhd.socket, SHUT_RDWR);
   1356   }
   1357   /* Socketpair sockets will remain open as they will be
   1358    * used with MHD_UPGRADE_ACTION_CLOSE. They will be
   1359    * closed by cleanup_upgraded_connection() during
   1360    * connection's final cleanup.
   1361    */
   1362 }
   1363 
   1364 
   1365 #endif /* HTTPS_SUPPORT && UPGRADE_SUPPORT*/
   1366 
   1367 
   1368 /**
   1369  * A serious error occurred, close the
   1370  * connection (and notify the application).
   1371  *
   1372  * @param connection connection to close with error
   1373  * @param emsg error message (can be NULL)
   1374  */
   1375 static void
   1376 connection_close_error (struct MHD_Connection *connection,
   1377                         const char *emsg)
   1378 {
   1379   connection->stop_with_error = true;
   1380   connection->discard_request = true;
   1381 #ifdef HAVE_MESSAGES
   1382   if (NULL != emsg)
   1383     MHD_DLOG (connection->daemon,
   1384               "%s\n",
   1385               emsg);
   1386 #else  /* ! HAVE_MESSAGES */
   1387   (void) emsg; /* Mute compiler warning. */
   1388 #endif /* ! HAVE_MESSAGES */
   1389   MHD_connection_close_ (connection,
   1390                          MHD_REQUEST_TERMINATED_WITH_ERROR);
   1391 }
   1392 
   1393 
   1394 /**
   1395  * Macro to only include error message in call to
   1396  * #connection_close_error() if we have HAVE_MESSAGES.
   1397  */
   1398 #ifdef HAVE_MESSAGES
   1399 #define CONNECTION_CLOSE_ERROR(c, emsg) connection_close_error (c, emsg)
   1400 #else
   1401 #define CONNECTION_CLOSE_ERROR(c, emsg) connection_close_error (c, NULL)
   1402 #endif
   1403 
   1404 
   1405 /**
   1406  * Prepare the response buffer of this connection for
   1407  * sending.  Assumes that the response mutex is
   1408  * already held.  If the transmission is complete,
   1409  * this function may close the socket (and return
   1410  * #MHD_NO).
   1411  *
   1412  * @param connection the connection
   1413  * @return #MHD_NO if readying the response failed (the
   1414  *  lock on the response will have been released already
   1415  *  in this case).
   1416  */
   1417 static enum MHD_Result
   1418 try_ready_normal_body (struct MHD_Connection *connection)
   1419 {
   1420   ssize_t ret;
   1421   struct MHD_Response *response;
   1422 
   1423   response = connection->rp.response;
   1424   mhd_assert (connection->rp.props.send_reply_body);
   1425 
   1426   if ( (0 == response->total_size) ||
   1427                      /* TODO: replace the next check with assert */
   1428        (connection->rp.rsp_write_position == response->total_size) )
   1429     return MHD_YES;  /* 0-byte response is always ready */
   1430   if (NULL != response->data_iov)
   1431   {
   1432     size_t copy_size;
   1433 
   1434     if (NULL != connection->rp.resp_iov.iov)
   1435       return MHD_YES;
   1436     copy_size = response->data_iovcnt * sizeof(MHD_iovec_);
   1437     connection->rp.resp_iov.iov = MHD_connection_alloc_memory_ (connection,
   1438                                                                 copy_size);
   1439     if (NULL == connection->rp.resp_iov.iov)
   1440     {
   1441       MHD_mutex_unlock_chk_ (&response->mutex);
   1442       /* not enough memory */
   1443       CONNECTION_CLOSE_ERROR (connection,
   1444                               _ ("Closing connection (out of memory)."));
   1445       return MHD_NO;
   1446     }
   1447     memcpy (connection->rp.resp_iov.iov,
   1448             response->data_iov,
   1449             copy_size);
   1450     connection->rp.resp_iov.cnt = response->data_iovcnt;
   1451     connection->rp.resp_iov.sent = 0;
   1452     return MHD_YES;
   1453   }
   1454   if (NULL == response->crc)
   1455     return MHD_YES;
   1456   if ( (response->data_start <=
   1457         connection->rp.rsp_write_position) &&
   1458        (response->data_size + response->data_start >
   1459         connection->rp.rsp_write_position) )
   1460     return MHD_YES; /* response already ready */
   1461 #if defined(_MHD_HAVE_SENDFILE)
   1462   if (MHD_resp_sender_sendfile == connection->rp.resp_sender)
   1463   {
   1464     /* will use sendfile, no need to bother response crc */
   1465     return MHD_YES;
   1466   }
   1467 #endif /* _MHD_HAVE_SENDFILE */
   1468 
   1469   ret = response->crc (response->crc_cls,
   1470                        connection->rp.rsp_write_position,
   1471                        (char *) response->data,
   1472                        (size_t) MHD_MIN ((uint64_t) response->data_buffer_size,
   1473                                          response->total_size
   1474                                          - connection->rp.rsp_write_position));
   1475   if (0 > ret)
   1476   {
   1477     /* either error or http 1.0 transfer, close socket! */
   1478     /* TODO: do not update total size, check whether response
   1479      * was really with unknown size */
   1480     response->total_size = connection->rp.rsp_write_position;
   1481 #if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS)
   1482     MHD_mutex_unlock_chk_ (&response->mutex);
   1483 #endif
   1484     if (MHD_CONTENT_READER_END_OF_STREAM == ret)
   1485       MHD_connection_close_ (connection,
   1486                              MHD_REQUEST_TERMINATED_COMPLETED_OK);
   1487     else
   1488       CONNECTION_CLOSE_ERROR (connection,
   1489                               _ ("Closing connection (application reported " \
   1490                                  "error generating data)."));
   1491     return MHD_NO;
   1492   }
   1493   response->data_start = connection->rp.rsp_write_position;
   1494   response->data_size = (size_t) ret;
   1495   if (0 == ret)
   1496   {
   1497     connection->state = MHD_CONNECTION_NORMAL_BODY_UNREADY;
   1498 #if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS)
   1499     MHD_mutex_unlock_chk_ (&response->mutex);
   1500 #endif
   1501     return MHD_NO;
   1502   }
   1503   return MHD_YES;
   1504 }
   1505 
   1506 
   1507 /**
   1508  * Prepare the response buffer of this connection for sending.
   1509  * Assumes that the response mutex is already held.  If the
   1510  * transmission is complete, this function may close the socket (and
   1511  * return #MHD_NO).
   1512  *
   1513  * @param connection the connection
   1514  * @param[out] p_finished the pointer to variable that will be set to "true"
   1515  *                        when application returned indication of the end
   1516  *                        of the stream
   1517  * @return #MHD_NO if readying the response failed
   1518  */
   1519 static enum MHD_Result
   1520 try_ready_chunked_body (struct MHD_Connection *connection,
   1521                         bool *p_finished)
   1522 {
   1523   ssize_t ret;
   1524   struct MHD_Response *response;
   1525   static const size_t max_chunk = 0xFFFFFF;
   1526   char chunk_hdr[6];            /* 6: max strlen of "FFFFFF" */
   1527   /* "FFFFFF" + "\r\n" */
   1528   static const size_t max_chunk_hdr_len = sizeof(chunk_hdr) + 2;
   1529   /* "FFFFFF" + "\r\n" + "\r\n" (chunk termination) */
   1530   static const size_t max_chunk_overhead = sizeof(chunk_hdr) + 2 + 2;
   1531   size_t chunk_hdr_len;
   1532   uint64_t left_to_send;
   1533   size_t size_to_fill;
   1534 
   1535   response = connection->rp.response;
   1536   mhd_assert (NULL != response->crc || NULL != response->data);
   1537 
   1538   mhd_assert (0 == connection->write_buffer_append_offset);
   1539 
   1540   /* The buffer must be reasonably large enough */
   1541   if (128 > connection->write_buffer_size)
   1542   {
   1543     size_t size;
   1544 
   1545     size = connection->write_buffer_size + MHD_pool_get_free (connection->pool);
   1546     if (128 > size)
   1547     {
   1548 #if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS)
   1549       MHD_mutex_unlock_chk_ (&response->mutex);
   1550 #endif
   1551       /* not enough memory */
   1552       CONNECTION_CLOSE_ERROR (connection,
   1553                               _ ("Closing connection (out of memory)."));
   1554       return MHD_NO;
   1555     }
   1556     /* Limit the buffer size to the largest usable size for chunks */
   1557     if ( (max_chunk + max_chunk_overhead) < size)
   1558       size = max_chunk + max_chunk_overhead;
   1559     mhd_assert ((NULL == connection->write_buffer) || \
   1560                 MHD_pool_is_resizable_inplace (connection->pool, \
   1561                                                connection->write_buffer, \
   1562                                                connection->write_buffer_size));
   1563     connection->write_buffer =
   1564       MHD_pool_reallocate (connection->pool,
   1565                            connection->write_buffer,
   1566                            connection->write_buffer_size,
   1567                            size);
   1568     mhd_assert (NULL != connection->write_buffer);
   1569     connection->write_buffer_size = size;
   1570   }
   1571   mhd_assert (max_chunk_overhead < connection->write_buffer_size);
   1572 
   1573   if (MHD_SIZE_UNKNOWN == response->total_size)
   1574     left_to_send = MHD_SIZE_UNKNOWN;
   1575   else
   1576     left_to_send = response->total_size
   1577                    - connection->rp.rsp_write_position;
   1578 
   1579   size_to_fill = connection->write_buffer_size - max_chunk_overhead;
   1580   /* Limit size for the callback to the max usable size */
   1581   if (max_chunk < size_to_fill)
   1582     size_to_fill = max_chunk;
   1583   if (left_to_send < size_to_fill)
   1584     size_to_fill = (size_t) left_to_send;
   1585 
   1586   if (0 == left_to_send)
   1587     /* nothing to send, don't bother calling crc */
   1588     ret = MHD_CONTENT_READER_END_OF_STREAM;
   1589   else if ( (response->data_start <=
   1590              connection->rp.rsp_write_position) &&
   1591             (response->data_start + response->data_size >
   1592              connection->rp.rsp_write_position) )
   1593   {
   1594     /* difference between rsp_write_position and data_start is less
   1595        than data_size which is size_t type, no need to check for overflow */
   1596     const size_t data_write_offset
   1597       = (size_t) (connection->rp.rsp_write_position
   1598                   - response->data_start);
   1599     /* buffer already ready, use what is there for the chunk */
   1600     mhd_assert (SSIZE_MAX >= (response->data_size - data_write_offset));
   1601     mhd_assert (response->data_size >= data_write_offset);
   1602     ret = (ssize_t) (response->data_size - data_write_offset);
   1603     if ( ((size_t) ret) > size_to_fill)
   1604       ret = (ssize_t) size_to_fill;
   1605     memcpy (&connection->write_buffer[max_chunk_hdr_len],
   1606             &response->data[data_write_offset],
   1607             (size_t) ret);
   1608   }
   1609   else
   1610   {
   1611     if (NULL == response->crc)
   1612     { /* There is no way to reach this code */
   1613 #if defined(MHD_USE_THREADS)
   1614       MHD_mutex_unlock_chk_ (&response->mutex);
   1615 #endif
   1616       CONNECTION_CLOSE_ERROR (connection,
   1617                               _ ("No callback for the chunked data."));
   1618       return MHD_NO;
   1619     }
   1620     ret = response->crc (response->crc_cls,
   1621                          connection->rp.rsp_write_position,
   1622                          &connection->write_buffer[max_chunk_hdr_len],
   1623                          size_to_fill);
   1624   }
   1625   if (MHD_CONTENT_READER_END_WITH_ERROR == ret)
   1626   {
   1627     /* error, close socket! */
   1628     /* TODO: remove update of the response size */
   1629     response->total_size = connection->rp.rsp_write_position;
   1630 #if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS)
   1631     MHD_mutex_unlock_chk_ (&response->mutex);
   1632 #endif
   1633     CONNECTION_CLOSE_ERROR (connection,
   1634                             _ ("Closing connection (application error " \
   1635                                "generating response)."));
   1636     return MHD_NO;
   1637   }
   1638   if (MHD_CONTENT_READER_END_OF_STREAM == ret)
   1639   {
   1640     *p_finished = true;
   1641     /* TODO: remove update of the response size */
   1642     response->total_size = connection->rp.rsp_write_position;
   1643     return MHD_YES;
   1644   }
   1645   if (0 == ret)
   1646   {
   1647     connection->state = MHD_CONNECTION_CHUNKED_BODY_UNREADY;
   1648 #if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS)
   1649     MHD_mutex_unlock_chk_ (&response->mutex);
   1650 #endif
   1651     return MHD_NO;
   1652   }
   1653   if (size_to_fill < (size_t) ret)
   1654   {
   1655 #if defined(MHD_USE_THREADS)
   1656     MHD_mutex_unlock_chk_ (&response->mutex);
   1657 #endif
   1658     CONNECTION_CLOSE_ERROR (connection,
   1659                             _ ("Closing connection (application returned " \
   1660                                "more data than requested)."));
   1661     return MHD_NO;
   1662   }
   1663   chunk_hdr_len = MHD_uint32_to_strx ((uint32_t) ret, chunk_hdr,
   1664                                       sizeof(chunk_hdr));
   1665   mhd_assert (chunk_hdr_len != 0);
   1666   mhd_assert (chunk_hdr_len < sizeof(chunk_hdr));
   1667   *p_finished = false;
   1668   connection->write_buffer_send_offset =
   1669     (max_chunk_hdr_len - (chunk_hdr_len + 2));
   1670   memcpy (connection->write_buffer + connection->write_buffer_send_offset,
   1671           chunk_hdr,
   1672           chunk_hdr_len);
   1673   connection->write_buffer[max_chunk_hdr_len - 2] = '\r';
   1674   connection->write_buffer[max_chunk_hdr_len - 1] = '\n';
   1675   connection->write_buffer[max_chunk_hdr_len + (size_t) ret] = '\r';
   1676   connection->write_buffer[max_chunk_hdr_len + (size_t) ret + 1] = '\n';
   1677   connection->rp.rsp_write_position += (size_t) ret;
   1678   connection->write_buffer_append_offset = max_chunk_hdr_len + (size_t) ret + 2;
   1679   return MHD_YES;
   1680 }
   1681 
   1682 
   1683 /**
   1684  * Are we allowed to keep the given connection alive?
   1685  * We can use the TCP stream for a second request if the connection
   1686  * is HTTP 1.1 and the "Connection" header either does not exist or
   1687  * is not set to "close", or if the connection is HTTP 1.0 and the
   1688  * "Connection" header is explicitly set to "keep-alive".
   1689  * If no HTTP version is specified (or if it is not 1.0 or 1.1), we
   1690  * definitively close the connection.  If the "Connection" header is
   1691  * not exactly "close" or "keep-alive", we proceed to use the default
   1692  * for the respective HTTP version.
   1693  * If response has HTTP/1.0 flag or has "Connection: close" header
   1694  * then connection must be closed.
   1695  * If full request has not been read then connection must be closed
   1696  * as well.
   1697  *
   1698  * @param connection the connection to check for keepalive
   1699  * @return MHD_CONN_USE_KEEPALIVE if (based on the request and the response),
   1700  *         a keepalive is legal,
   1701  *         MHD_CONN_MUST_CLOSE if connection must be closed after sending
   1702  *         complete reply,
   1703  *         MHD_CONN_MUST_UPGRADE if connection must be upgraded.
   1704  */
   1705 static enum MHD_ConnKeepAlive
   1706 keepalive_possible (struct MHD_Connection *connection)
   1707 {
   1708   struct MHD_Connection *const c = connection; /**< a short alias */
   1709   struct MHD_Response *const r = c->rp.response;  /**< a short alias */
   1710 
   1711   mhd_assert (NULL != r);
   1712   if (MHD_CONN_MUST_CLOSE == c->keepalive)
   1713     return MHD_CONN_MUST_CLOSE;
   1714 
   1715 #ifdef UPGRADE_SUPPORT
   1716   /* TODO: Move below the next check when MHD stops closing connections
   1717    * when response is queued in first callback */
   1718   if (NULL != r->upgrade_handler)
   1719   {
   1720     /* No "close" token is enforced by 'add_response_header_connection()' */
   1721     mhd_assert (0 == (r->flags_auto & MHD_RAF_HAS_CONNECTION_CLOSE));
   1722     /* Valid HTTP version is enforced by 'MHD_queue_response()' */
   1723     mhd_assert (MHD_IS_HTTP_VER_SUPPORTED (c->rq.http_ver));
   1724     mhd_assert (! c->stop_with_error);
   1725     return MHD_CONN_MUST_UPGRADE;
   1726   }
   1727 #endif /* UPGRADE_SUPPORT */
   1728 
   1729   mhd_assert ( (! c->stop_with_error) || (c->discard_request));
   1730   if ((c->read_closed) || (c->discard_request))
   1731     return MHD_CONN_MUST_CLOSE;
   1732 
   1733   if (0 != (r->flags & MHD_RF_HTTP_1_0_COMPATIBLE_STRICT))
   1734     return MHD_CONN_MUST_CLOSE;
   1735   if (0 != (r->flags_auto & MHD_RAF_HAS_CONNECTION_CLOSE))
   1736     return MHD_CONN_MUST_CLOSE;
   1737 
   1738   if (! MHD_IS_HTTP_VER_SUPPORTED (c->rq.http_ver))
   1739     return MHD_CONN_MUST_CLOSE;
   1740 
   1741   if (MHD_lookup_header_s_token_ci (c,
   1742                                     MHD_HTTP_HEADER_CONNECTION,
   1743                                     "close"))
   1744     return MHD_CONN_MUST_CLOSE;
   1745 
   1746   if ((MHD_HTTP_VER_1_0 == connection->rq.http_ver) ||
   1747       (0 != (connection->rp.response->flags & MHD_RF_HTTP_1_0_SERVER)))
   1748   {
   1749     if (MHD_lookup_header_s_token_ci (connection,
   1750                                       MHD_HTTP_HEADER_CONNECTION,
   1751                                       "Keep-Alive"))
   1752       return MHD_CONN_USE_KEEPALIVE;
   1753 
   1754     return MHD_CONN_MUST_CLOSE;
   1755   }
   1756 
   1757   if (MHD_IS_HTTP_VER_1_1_COMPAT (c->rq.http_ver))
   1758     return MHD_CONN_USE_KEEPALIVE;
   1759 
   1760   return MHD_CONN_MUST_CLOSE;
   1761 }
   1762 
   1763 
   1764 /**
   1765  * Produce time stamp.
   1766  *
   1767  * Result is NOT null-terminated.
   1768  * Result is always 29 bytes long.
   1769  *
   1770  * @param[out] date where to write the time stamp, with
   1771  *             at least 29 bytes available space.
   1772  */
   1773 static bool
   1774 get_date_str (char *date)
   1775 {
   1776   static const char *const days[] = {
   1777     "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
   1778   };
   1779   static const char *const mons[] = {
   1780     "Jan", "Feb", "Mar", "Apr", "May", "Jun",
   1781     "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
   1782   };
   1783   static const size_t buf_len = 29;
   1784   struct tm now;
   1785   time_t t;
   1786   const char *src;
   1787 #if ! defined(HAVE_C11_GMTIME_S) && ! defined(HAVE_W32_GMTIME_S) && \
   1788   ! defined(HAVE_GMTIME_R)
   1789   struct tm *pNow;
   1790 #endif
   1791 
   1792   if ((time_t) -1 == time (&t))
   1793     return false;
   1794 #if defined(HAVE_C11_GMTIME_S)
   1795   if (NULL == gmtime_s (&t,
   1796                         &now))
   1797     return false;
   1798 #elif defined(HAVE_W32_GMTIME_S)
   1799   if (0 != gmtime_s (&now,
   1800                      &t))
   1801     return false;
   1802 #elif defined(HAVE_GMTIME_R)
   1803   if (NULL == gmtime_r (&t,
   1804                         &now))
   1805     return false;
   1806 #else
   1807   pNow = gmtime (&t);
   1808   if (NULL == pNow)
   1809     return false;
   1810   now = *pNow;
   1811 #endif
   1812 
   1813   /* Day of the week */
   1814   src = days[now.tm_wday % 7];
   1815   date[0] = src[0];
   1816   date[1] = src[1];
   1817   date[2] = src[2];
   1818   date[3] = ',';
   1819   date[4] = ' ';
   1820   /* Day of the month */
   1821   if (2 != MHD_uint8_to_str_pad ((uint8_t) now.tm_mday, 2,
   1822                                  date + 5, buf_len - 5))
   1823     return false;
   1824   date[7] = ' ';
   1825   /* Month */
   1826   src = mons[now.tm_mon % 12];
   1827   date[8] = src[0];
   1828   date[9] = src[1];
   1829   date[10] = src[2];
   1830   date[11] = ' ';
   1831   /* Year */
   1832   if (4 != MHD_uint16_to_str ((uint16_t) (1900 + now.tm_year), date + 12,
   1833                               buf_len - 12))
   1834     return false;
   1835   date[16] = ' ';
   1836   /* Time */
   1837   MHD_uint8_to_str_pad ((uint8_t) now.tm_hour, 2, date + 17, buf_len - 17);
   1838   date[19] = ':';
   1839   MHD_uint8_to_str_pad ((uint8_t) now.tm_min, 2, date + 20, buf_len - 20);
   1840   date[22] = ':';
   1841   MHD_uint8_to_str_pad ((uint8_t) now.tm_sec, 2, date + 23, buf_len - 23);
   1842   date[25] = ' ';
   1843   date[26] = 'G';
   1844   date[27] = 'M';
   1845   date[28] = 'T';
   1846 
   1847   return true;
   1848 }
   1849 
   1850 
   1851 /**
   1852  * Produce HTTP DATE header.
   1853  * Result is always 37 bytes long (plus one terminating null).
   1854  *
   1855  * @param[out] header where to write the header, with
   1856  *             at least 38 bytes available space.
   1857  */
   1858 static bool
   1859 get_date_header (char *header)
   1860 {
   1861   if (! get_date_str (header + 6))
   1862   {
   1863     header[0] = 0;
   1864     return false;
   1865   }
   1866   header[0] = 'D';
   1867   header[1] = 'a';
   1868   header[2] = 't';
   1869   header[3] = 'e';
   1870   header[4] = ':';
   1871   header[5] = ' ';
   1872   header[35] = '\r';
   1873   header[36] = '\n';
   1874   header[37] = 0;
   1875   return true;
   1876 }
   1877 
   1878 
   1879 /**
   1880  * Try growing the read buffer.  We initially claim half the available
   1881  * buffer space for the read buffer (the other half being left for
   1882  * management data structures; the write buffer can in the end take
   1883  * virtually everything as the read buffer can be reduced to the
   1884  * minimum necessary at that point.
   1885  *
   1886  * @param connection the connection
   1887  * @param required set to 'true' if grow is required, i.e. connection
   1888  *                 will fail if no additional space is granted
   1889  * @return 'true' on success, 'false' on failure
   1890  */
   1891 static bool
   1892 try_grow_read_buffer (struct MHD_Connection *connection,
   1893                       bool required)
   1894 {
   1895   size_t new_size;
   1896   size_t avail_size;
   1897   const size_t def_grow_size = connection->daemon->pool_increment;
   1898   void *rb;
   1899 
   1900   avail_size = MHD_pool_get_free (connection->pool);
   1901   if (0 == avail_size)
   1902     return false;               /* No more space available */
   1903   if (0 == connection->read_buffer_size)
   1904     new_size = avail_size / 2;  /* Use half of available buffer for reading */
   1905   else
   1906   {
   1907     size_t grow_size;
   1908 
   1909     grow_size = avail_size / 8;
   1910     if (def_grow_size > grow_size)
   1911     {                  /* Shortage of space */
   1912       const size_t left_free =
   1913         connection->read_buffer_size - connection->read_buffer_offset;
   1914       mhd_assert (connection->read_buffer_size >= \
   1915                   connection->read_buffer_offset);
   1916       if ((def_grow_size <= grow_size + left_free)
   1917           && (left_free < def_grow_size))
   1918         grow_size = def_grow_size - left_free;  /* Use precise 'def_grow_size' for new free space */
   1919       else if (! required)
   1920         return false;                           /* Grow is not mandatory, leave some space in pool */
   1921       else
   1922       {
   1923         /* Shortage of space, but grow is mandatory */
   1924         const size_t small_inc =
   1925           ((MHD_BUF_INC_SIZE > def_grow_size) ?
   1926            def_grow_size : MHD_BUF_INC_SIZE) / 8;
   1927         if (small_inc < avail_size)
   1928           grow_size = small_inc;
   1929         else
   1930           grow_size = avail_size;
   1931       }
   1932     }
   1933     new_size = connection->read_buffer_size + grow_size;
   1934   }
   1935   /* Make sure that read buffer will not be moved */
   1936   if ((NULL != connection->read_buffer) &&
   1937       ! MHD_pool_is_resizable_inplace (connection->pool,
   1938                                        connection->read_buffer,
   1939                                        connection->read_buffer_size))
   1940   {
   1941     mhd_assert (0);
   1942     return false;
   1943   }
   1944   /* we can actually grow the buffer, do it! */
   1945   rb = MHD_pool_reallocate (connection->pool,
   1946                             connection->read_buffer,
   1947                             connection->read_buffer_size,
   1948                             new_size);
   1949   if (NULL == rb)
   1950   {
   1951     /* This should NOT be possible: we just computed 'new_size' so that
   1952        it should fit. If it happens, somehow our read buffer is not in
   1953        the right position in the pool, say because someone called
   1954        MHD_pool_allocate() without 'from_end' set to 'true'? Anyway,
   1955        should be investigated! (Ideally provide all data from
   1956        *pool and connection->read_buffer and new_size for debugging). */
   1957     mhd_assert (0);
   1958     return false;
   1959   }
   1960   mhd_assert (connection->read_buffer == rb);
   1961   connection->read_buffer = rb;
   1962   mhd_assert (NULL != connection->read_buffer);
   1963   connection->read_buffer_size = new_size;
   1964   return true;
   1965 }
   1966 
   1967 
   1968 /**
   1969  * Shrink connection read buffer to the zero size of free space in the buffer
   1970  * @param connection the connection whose read buffer is being manipulated
   1971  */
   1972 static void
   1973 connection_shrink_read_buffer (struct MHD_Connection *connection)
   1974 {
   1975   struct MHD_Connection *const c = connection; /**< a short alias */
   1976   void *new_buf;
   1977 
   1978   if ((NULL == c->read_buffer) || (0 == c->read_buffer_size))
   1979   {
   1980     mhd_assert (0 == c->read_buffer_size);
   1981     mhd_assert (0 == c->read_buffer_offset);
   1982     return;
   1983   }
   1984 
   1985   mhd_assert (c->read_buffer_offset <= c->read_buffer_size);
   1986   if (0 == c->read_buffer_offset)
   1987   {
   1988     MHD_pool_deallocate (c->pool, c->read_buffer, c->read_buffer_size);
   1989     c->read_buffer = NULL;
   1990     c->read_buffer_size = 0;
   1991   }
   1992   else
   1993   {
   1994     mhd_assert (MHD_pool_is_resizable_inplace (c->pool, c->read_buffer, \
   1995                                                c->read_buffer_size));
   1996     new_buf = MHD_pool_reallocate (c->pool, c->read_buffer, c->read_buffer_size,
   1997                                    c->read_buffer_offset);
   1998     mhd_assert (c->read_buffer == new_buf);
   1999     c->read_buffer = new_buf;
   2000     c->read_buffer_size = c->read_buffer_offset;
   2001   }
   2002 }
   2003 
   2004 
   2005 /**
   2006  * Allocate the maximum available amount of memory from MemoryPool
   2007  * for write buffer.
   2008  * @param connection the connection whose write buffer is being manipulated
   2009  * @return the size of the free space in the write buffer
   2010  */
   2011 static size_t
   2012 connection_maximize_write_buffer (struct MHD_Connection *connection)
   2013 {
   2014   struct MHD_Connection *const c = connection; /**< a short alias */
   2015   struct MemoryPool *const pool = connection->pool;
   2016   void *new_buf;
   2017   size_t new_size;
   2018   size_t free_size;
   2019 
   2020   mhd_assert ((NULL != c->write_buffer) || (0 == c->write_buffer_size));
   2021   mhd_assert (c->write_buffer_append_offset >= c->write_buffer_send_offset);
   2022   mhd_assert (c->write_buffer_size >= c->write_buffer_append_offset);
   2023 
   2024   free_size = MHD_pool_get_free (pool);
   2025   if (0 != free_size)
   2026   {
   2027     new_size = c->write_buffer_size + free_size;
   2028     /* This function must not move the buffer position.
   2029      * MHD_pool_reallocate () may return the new position only if buffer was
   2030      * allocated 'from_end' or is not the last allocation,
   2031      * which should not happen. */
   2032     mhd_assert ((NULL == c->write_buffer) || \
   2033                 MHD_pool_is_resizable_inplace (pool, c->write_buffer, \
   2034                                                c->write_buffer_size));
   2035     new_buf = MHD_pool_reallocate (pool,
   2036                                    c->write_buffer,
   2037                                    c->write_buffer_size,
   2038                                    new_size);
   2039     mhd_assert ((c->write_buffer == new_buf) || (NULL == c->write_buffer));
   2040     c->write_buffer = new_buf;
   2041     c->write_buffer_size = new_size;
   2042     if (c->write_buffer_send_offset == c->write_buffer_append_offset)
   2043     {
   2044       /* All data have been sent, reset offsets to zero. */
   2045       c->write_buffer_send_offset = 0;
   2046       c->write_buffer_append_offset = 0;
   2047     }
   2048   }
   2049 
   2050   return c->write_buffer_size - c->write_buffer_append_offset;
   2051 }
   2052 
   2053 
   2054 #if 0 /* disable unused function */
   2055 /**
   2056  * Shrink connection write buffer to the size of unsent data.
   2057  *
   2058  * @note: The number of calls of this function should be limited to avoid extra
   2059  * zeroing of the memory.
   2060  * @param connection the connection whose write buffer is being manipulated
   2061  * @param connection the connection to manipulate write buffer
   2062  */
   2063 static void
   2064 connection_shrink_write_buffer (struct MHD_Connection *connection)
   2065 {
   2066   struct MHD_Connection *const c = connection; /**< a short alias */
   2067   struct MemoryPool *const pool = connection->pool;
   2068   void *new_buf;
   2069 
   2070   mhd_assert ((NULL != c->write_buffer) || (0 == c->write_buffer_size));
   2071   mhd_assert (c->write_buffer_append_offset >= c->write_buffer_send_offset);
   2072   mhd_assert (c->write_buffer_size >= c->write_buffer_append_offset);
   2073 
   2074   if ( (NULL == c->write_buffer) || (0 == c->write_buffer_size))
   2075   {
   2076     mhd_assert (0 == c->write_buffer_append_offset);
   2077     mhd_assert (0 == c->write_buffer_send_offset);
   2078     c->write_buffer = NULL;
   2079     return;
   2080   }
   2081   if (c->write_buffer_append_offset == c->write_buffer_size)
   2082     return;
   2083 
   2084   new_buf = MHD_pool_reallocate (pool, c->write_buffer, c->write_buffer_size,
   2085                                  c->write_buffer_append_offset);
   2086   mhd_assert ((c->write_buffer == new_buf) || \
   2087               (0 == c->write_buffer_append_offset));
   2088   c->write_buffer_size = c->write_buffer_append_offset;
   2089   if (0 == c->write_buffer_size)
   2090     c->write_buffer = NULL;
   2091   else
   2092     c->write_buffer = new_buf;
   2093 }
   2094 
   2095 
   2096 #endif /* unused function */
   2097 
   2098 
   2099 /**
   2100  * Switch connection from recv mode to send mode.
   2101  *
   2102  * Current request header or body will not be read anymore,
   2103  * response must be assigned to connection.
   2104  * @param connection the connection to prepare for sending.
   2105  */
   2106 static void
   2107 connection_switch_from_recv_to_send (struct MHD_Connection *connection)
   2108 {
   2109   /* Read buffer is not needed for this request, shrink it.*/
   2110   connection_shrink_read_buffer (connection);
   2111 }
   2112 
   2113 
   2114 /**
   2115  * This enum type describes requirements for reply body and reply bode-specific
   2116  * headers (namely Content-Length, Transfer-Encoding).
   2117  */
   2118 enum replyBodyUse
   2119 {
   2120   /**
   2121    * No reply body allowed.
   2122    * Reply body headers 'Content-Length:' or 'Transfer-Encoding: chunked' are
   2123    * not allowed as well.
   2124    */
   2125   RP_BODY_NONE = 0,
   2126 
   2127   /**
   2128    * Do not send reply body.
   2129    * Reply body headers 'Content-Length:' or 'Transfer-Encoding: chunked' are
   2130    * allowed, but optional.
   2131    */
   2132   RP_BODY_HEADERS_ONLY = 1,
   2133 
   2134   /**
   2135    * Send reply body and
   2136    * reply body headers 'Content-Length:' or 'Transfer-Encoding: chunked'.
   2137    * Reply body headers are required.
   2138    */
   2139   RP_BODY_SEND = 2
   2140 };
   2141 
   2142 
   2143 /**
   2144  * Check whether reply body must be used.
   2145  *
   2146  * If reply body is needed, it could be zero-sized.
   2147  *
   2148  * @param connection the connection to check
   2149  * @param rcode the response code
   2150  * @return enum value indicating whether response body can be used and
   2151  *         whether response body length headers are allowed or required.
   2152  * @sa is_reply_body_header_needed()
   2153  */
   2154 static enum replyBodyUse
   2155 is_reply_body_needed (struct MHD_Connection *connection,
   2156                       unsigned int rcode)
   2157 {
   2158   struct MHD_Connection *const c = connection; /**< a short alias */
   2159 
   2160   mhd_assert (100 <= rcode);
   2161   mhd_assert (999 >= rcode);
   2162 
   2163   if (199 >= rcode)
   2164     return RP_BODY_NONE;
   2165 
   2166   if (MHD_HTTP_NO_CONTENT == rcode)
   2167     return RP_BODY_NONE;
   2168 
   2169 #if 0
   2170   /* This check is not needed as upgrade handler is used only with code 101 */
   2171 #ifdef UPGRADE_SUPPORT
   2172   if (NULL != rp.response->upgrade_handler)
   2173     return RP_BODY_NONE;
   2174 #endif /* UPGRADE_SUPPORT */
   2175 #endif
   2176 
   2177 #if 0
   2178   /* CONNECT is not supported by MHD */
   2179   /* Successful responses for connect requests are filtered by
   2180    * MHD_queue_response() */
   2181   if ( (MHD_HTTP_MTHD_CONNECT == c->rq.http_mthd) &&
   2182        (2 == rcode / 100) )
   2183     return false; /* Actually pass-through CONNECT is not supported by MHD */
   2184 #endif
   2185 
   2186   /* Reply body headers could be used.
   2187    * Check whether reply body itself must be used. */
   2188 
   2189   if (MHD_HTTP_MTHD_HEAD == c->rq.http_mthd)
   2190     return RP_BODY_HEADERS_ONLY;
   2191 
   2192   if (MHD_HTTP_NOT_MODIFIED == rcode)
   2193     return RP_BODY_HEADERS_ONLY;
   2194 
   2195   /* Reply body must be sent. The body may have zero length, but body size
   2196    * must be indicated by headers ('Content-Length:' or
   2197    * 'Transfer-Encoding: chunked'). */
   2198   return RP_BODY_SEND;
   2199 }
   2200 
   2201 
   2202 /**
   2203  * Setup connection reply properties.
   2204  *
   2205  * Reply properties include presence of reply body, transfer-encoding
   2206  * type and other.
   2207  *
   2208  * @param connection to connection to process
   2209  */
   2210 static void
   2211 setup_reply_properties (struct MHD_Connection *connection)
   2212 {
   2213   struct MHD_Connection *const c = connection; /**< a short alias */
   2214   struct MHD_Response *const r = c->rp.response;  /**< a short alias */
   2215   enum replyBodyUse use_rp_body;
   2216   bool use_chunked;
   2217 
   2218   mhd_assert (NULL != r);
   2219 
   2220   /* ** Adjust reply properties ** */
   2221 
   2222   c->keepalive = keepalive_possible (c);
   2223   use_rp_body = is_reply_body_needed (c, c->rp.responseCode);
   2224   c->rp.props.send_reply_body = (use_rp_body > RP_BODY_HEADERS_ONLY);
   2225   c->rp.props.use_reply_body_headers = (use_rp_body >= RP_BODY_HEADERS_ONLY);
   2226 
   2227 #ifdef UPGRADE_SUPPORT
   2228   mhd_assert ( (NULL == r->upgrade_handler) ||
   2229                (RP_BODY_NONE == use_rp_body) );
   2230 #endif /* UPGRADE_SUPPORT */
   2231 
   2232   if (c->rp.props.use_reply_body_headers)
   2233   {
   2234     if ((MHD_SIZE_UNKNOWN == r->total_size) ||
   2235         (0 != (r->flags_auto & MHD_RAF_HAS_TRANS_ENC_CHUNKED)))
   2236     { /* Use chunked reply encoding if possible */
   2237 
   2238       /* Check whether chunked encoding is supported by the client */
   2239       if (! MHD_IS_HTTP_VER_1_1_COMPAT (c->rq.http_ver))
   2240         use_chunked = false;
   2241       /* Check whether chunked encoding is allowed for the reply */
   2242       else if (0 != (r->flags & (MHD_RF_HTTP_1_0_COMPATIBLE_STRICT
   2243                                  | MHD_RF_HTTP_1_0_SERVER)))
   2244         use_chunked = false;
   2245       else
   2246         /* If chunked encoding is supported and allowed, and response size
   2247          * is unknown, use chunked even for non-Keep-Alive connections.
   2248          * See https://datatracker.ietf.org/doc/html/rfc7230#section-3.3.3
   2249          * Also use chunked if it is enforced by application and supported by
   2250          * the client. */
   2251         use_chunked = true;
   2252     }
   2253     else
   2254       use_chunked = false;
   2255 
   2256     if ( (MHD_SIZE_UNKNOWN == r->total_size) &&
   2257          (! use_chunked) )
   2258     {
   2259       /* End of the stream is indicated by closure */
   2260       c->keepalive = MHD_CONN_MUST_CLOSE;
   2261     }
   2262   }
   2263   else
   2264     use_chunked = false; /* chunked encoding cannot be used without body */
   2265 
   2266   c->rp.props.chunked = use_chunked;
   2267 #ifdef _DEBUG
   2268   c->rp.props.set = true;
   2269 #endif /* _DEBUG */
   2270 }
   2271 
   2272 
   2273 /**
   2274  * Check whether queued response is suitable for @a connection.
   2275  * @param connection to connection to check
   2276  */
   2277 static void
   2278 check_connection_reply (struct MHD_Connection *connection)
   2279 {
   2280   struct MHD_Connection *const c = connection; /**< a short alias */
   2281   struct MHD_Response *const r = c->rp.response;  /**< a short alias */
   2282 
   2283   mhd_assert (c->rp.props.set);
   2284 #ifdef HAVE_MESSAGES
   2285   if ( (! c->rp.props.use_reply_body_headers) &&
   2286        (0 != r->total_size) )
   2287   {
   2288     MHD_DLOG (c->daemon,
   2289               _ ("This reply with response code %u cannot use reply body. "
   2290                  "Non-empty response body is ignored and not used.\n"),
   2291               (unsigned) (c->rp.responseCode));
   2292   }
   2293   if ( (! c->rp.props.use_reply_body_headers) &&
   2294        (0 != (r->flags_auto & MHD_RAF_HAS_CONTENT_LENGTH)) )
   2295   {
   2296     MHD_DLOG (c->daemon,
   2297               _ ("This reply with response code %u cannot use reply body. "
   2298                  "Application defined \"Content-Length\" header violates"
   2299                  "HTTP specification.\n"),
   2300               (unsigned) (c->rp.responseCode));
   2301   }
   2302 #else
   2303   (void) c; /* Mute compiler warning */
   2304   (void) r; /* Mute compiler warning */
   2305 #endif
   2306 }
   2307 
   2308 
   2309 /**
   2310  * Append data to the buffer if enough space is available,
   2311  * update position.
   2312  * @param[out] buf the buffer to append data to
   2313  * @param[in,out] ppos the pointer to position in the @a buffer
   2314  * @param buf_size the size of the @a buffer
   2315  * @param append the data to append
   2316  * @param append_size the size of the @a append
   2317  * @return true if data has been added and position has been updated,
   2318  *         false if not enough space is available
   2319  */
   2320 static bool
   2321 buffer_append (char *buf,
   2322                size_t *ppos,
   2323                size_t buf_size,
   2324                const char *append,
   2325                size_t append_size)
   2326 {
   2327   mhd_assert (NULL != buf); /* Mute static analyzer */
   2328   if (buf_size < *ppos + append_size)
   2329     return false;
   2330   memcpy (buf + *ppos, append, append_size);
   2331   *ppos += append_size;
   2332   return true;
   2333 }
   2334 
   2335 
   2336 /**
   2337  * Append static string to the buffer if enough space is available,
   2338  * update position.
   2339  * @param[out] buf the buffer to append data to
   2340  * @param[in,out] ppos the pointer to position in the @a buffer
   2341  * @param buf_size the size of the @a buffer
   2342  * @param str the static string to append
   2343  * @return true if data has been added and position has been updated,
   2344  *         false if not enough space is available
   2345  */
   2346 #define buffer_append_s(buf,ppos,buf_size,str) \
   2347   buffer_append (buf,ppos,buf_size,str, MHD_STATICSTR_LEN_ (str))
   2348 
   2349 
   2350 /**
   2351  * Add user-defined headers from response object to
   2352  * the text buffer.
   2353  *
   2354  * @param buf the buffer to add headers to
   2355  * @param ppos the pointer to the position in the @a buf
   2356  * @param buf_size the size of the @a buf
   2357  * @param response the response
   2358  * @param filter_transf_enc skip "Transfer-Encoding" header if any
   2359  * @param filter_content_len skip "Content-Length" header if any
   2360  * @param add_close add "close" token to the
   2361  *                  "Connection:" header (if any), ignored if no "Connection:"
   2362  *                  header was added by user or if "close" token is already
   2363  *                  present in "Connection:" header
   2364  * @param add_keep_alive add "Keep-Alive" token to the
   2365  *                       "Connection:" header (if any)
   2366  * @return true if succeed,
   2367  *         false if buffer is too small
   2368  */
   2369 static bool
   2370 add_user_headers (char *buf,
   2371                   size_t *ppos,
   2372                   size_t buf_size,
   2373                   struct MHD_Response *response,
   2374                   bool filter_transf_enc,
   2375                   bool filter_content_len,
   2376                   bool add_close,
   2377                   bool add_keep_alive)
   2378 {
   2379   struct MHD_Response *const r = response; /**< a short alias */
   2380   struct MHD_HTTP_Res_Header *hdr; /**< Iterates through User-specified headers */
   2381   size_t el_size; /**< the size of current element to be added to the @a buf */
   2382 
   2383   mhd_assert (! add_close || ! add_keep_alive);
   2384 
   2385   if (0 == (r->flags_auto & MHD_RAF_HAS_TRANS_ENC_CHUNKED))
   2386     filter_transf_enc = false;   /* No such header */
   2387   if (0 == (r->flags_auto & MHD_RAF_HAS_CONTENT_LENGTH))
   2388     filter_content_len = false;  /* No such header */
   2389   if (0 == (r->flags_auto & MHD_RAF_HAS_CONNECTION_HDR))
   2390   {
   2391     add_close = false;          /* No such header */
   2392     add_keep_alive = false;     /* No such header */
   2393   }
   2394   else if (0 != (r->flags_auto & MHD_RAF_HAS_CONNECTION_CLOSE))
   2395     add_close = false;          /* "close" token was already set */
   2396 
   2397   for (hdr = r->first_header; NULL != hdr; hdr = hdr->next)
   2398   {
   2399     size_t initial_pos = *ppos;
   2400     if (MHD_HEADER_KIND != hdr->kind)
   2401       continue;
   2402     if (filter_transf_enc)
   2403     { /* Need to filter-out "Transfer-Encoding" */
   2404       if ((MHD_STATICSTR_LEN_ (MHD_HTTP_HEADER_TRANSFER_ENCODING) ==
   2405            hdr->header_size) &&
   2406           (MHD_str_equal_caseless_bin_n_ (MHD_HTTP_HEADER_TRANSFER_ENCODING,
   2407                                           hdr->header, hdr->header_size)) )
   2408       {
   2409         filter_transf_enc = false; /* There is the only one such header */
   2410         continue; /* Skip "Transfer-Encoding" header */
   2411       }
   2412     }
   2413     if (filter_content_len)
   2414     { /* Need to filter-out "Content-Length" */
   2415       if ((MHD_STATICSTR_LEN_ (MHD_HTTP_HEADER_CONTENT_LENGTH) ==
   2416            hdr->header_size) &&
   2417           (MHD_str_equal_caseless_bin_n_ (MHD_HTTP_HEADER_CONTENT_LENGTH,
   2418                                           hdr->header, hdr->header_size)) )
   2419       {
   2420         /* Reset filter flag if only one header is allowed */
   2421         filter_transf_enc =
   2422           (0 == (r->flags & MHD_RF_INSANITY_HEADER_CONTENT_LENGTH));
   2423         continue; /* Skip "Content-Length" header */
   2424       }
   2425     }
   2426 
   2427     /* Add user header */
   2428     el_size = hdr->header_size + 2 + hdr->value_size + 2;
   2429     if (buf_size < *ppos + el_size)
   2430       return false;
   2431     memcpy (buf + *ppos, hdr->header, hdr->header_size);
   2432     (*ppos) += hdr->header_size;
   2433     buf[(*ppos)++] = ':';
   2434     buf[(*ppos)++] = ' ';
   2435     if (add_close || add_keep_alive)
   2436     {
   2437       /* "Connection:" header must be always the first one */
   2438       mhd_assert (MHD_str_equal_caseless_n_ (hdr->header, \
   2439                                              MHD_HTTP_HEADER_CONNECTION, \
   2440                                              hdr->header_size));
   2441 
   2442       if (add_close)
   2443       {
   2444         el_size += MHD_STATICSTR_LEN_ ("close, ");
   2445         if (buf_size < initial_pos + el_size)
   2446           return false;
   2447         memcpy (buf + *ppos, "close, ",
   2448                 MHD_STATICSTR_LEN_ ("close, "));
   2449         *ppos += MHD_STATICSTR_LEN_ ("close, ");
   2450       }
   2451       else
   2452       {
   2453         el_size += MHD_STATICSTR_LEN_ ("Keep-Alive, ");
   2454         if (buf_size < initial_pos + el_size)
   2455           return false;
   2456         memcpy (buf + *ppos, "Keep-Alive, ",
   2457                 MHD_STATICSTR_LEN_ ("Keep-Alive, "));
   2458         *ppos += MHD_STATICSTR_LEN_ ("Keep-Alive, ");
   2459       }
   2460       add_close = false;
   2461       add_keep_alive = false;
   2462     }
   2463     if (0 != hdr->value_size)
   2464       memcpy (buf + *ppos, hdr->value, hdr->value_size);
   2465     *ppos += hdr->value_size;
   2466     buf[(*ppos)++] = '\r';
   2467     buf[(*ppos)++] = '\n';
   2468     mhd_assert (initial_pos + el_size == (*ppos));
   2469   }
   2470   return true;
   2471 }
   2472 
   2473 
   2474 /**
   2475  * Allocate the connection's write buffer and fill it with all of the
   2476  * headers from the response.
   2477  * Required headers are added here.
   2478  *
   2479  * @param connection the connection
   2480  * @return #MHD_YES on success, #MHD_NO on failure (out of memory)
   2481  */
   2482 static enum MHD_Result
   2483 build_header_response (struct MHD_Connection *connection)
   2484 {
   2485   struct MHD_Connection *const c = connection; /**< a short alias */
   2486   struct MHD_Response *const r = c->rp.response; /**< a short alias */
   2487   char *buf;                                     /**< the output buffer */
   2488   size_t pos;                                    /**< append offset in the @a buf */
   2489   size_t buf_size;                               /**< the size of the @a buf */
   2490   size_t el_size;                                /**< the size of current element to be added to the @a buf */
   2491   unsigned rcode;                                /**< the response code */
   2492   bool use_conn_close;                           /**< Use "Connection: close" header */
   2493   bool use_conn_k_alive;                         /**< Use "Connection: Keep-Alive" header */
   2494 
   2495   mhd_assert (NULL != r);
   2496 
   2497   /* ** Adjust response properties ** */
   2498   setup_reply_properties (c);
   2499 
   2500   mhd_assert (c->rp.props.set);
   2501   mhd_assert ((MHD_CONN_MUST_CLOSE == c->keepalive) || \
   2502               (MHD_CONN_USE_KEEPALIVE == c->keepalive) || \
   2503               (MHD_CONN_MUST_UPGRADE == c->keepalive));
   2504 #ifdef UPGRADE_SUPPORT
   2505   mhd_assert ((NULL == r->upgrade_handler) || \
   2506               (MHD_CONN_MUST_UPGRADE == c->keepalive));
   2507 #else  /* ! UPGRADE_SUPPORT */
   2508   mhd_assert (MHD_CONN_MUST_UPGRADE != c->keepalive);
   2509 #endif /* ! UPGRADE_SUPPORT */
   2510   mhd_assert ((! c->rp.props.chunked) || c->rp.props.use_reply_body_headers);
   2511   mhd_assert ((! c->rp.props.send_reply_body) || \
   2512               c->rp.props.use_reply_body_headers);
   2513 #ifdef UPGRADE_SUPPORT
   2514   mhd_assert (NULL == r->upgrade_handler || \
   2515               ! c->rp.props.use_reply_body_headers);
   2516 #endif /* UPGRADE_SUPPORT */
   2517 
   2518   check_connection_reply (c);
   2519 
   2520   rcode = (unsigned) c->rp.responseCode;
   2521   if (MHD_CONN_MUST_CLOSE == c->keepalive)
   2522   {
   2523     /* The closure of connection must be always indicated by header
   2524      * to avoid hung connections */
   2525     use_conn_close = true;
   2526     use_conn_k_alive = false;
   2527   }
   2528   else if (MHD_CONN_USE_KEEPALIVE == c->keepalive)
   2529   {
   2530     use_conn_close = false;
   2531     /* Add "Connection: keep-alive" if request is HTTP/1.0 or
   2532      * if reply is HTTP/1.0
   2533      * For HTTP/1.1 add header only if explicitly requested by app
   2534      * (by response flag), as "Keep-Alive" is default for HTTP/1.1. */
   2535     if ((0 != (r->flags & MHD_RF_SEND_KEEP_ALIVE_HEADER)) ||
   2536         (MHD_HTTP_VER_1_0 == c->rq.http_ver) ||
   2537         (0 != (r->flags & MHD_RF_HTTP_1_0_SERVER)))
   2538       use_conn_k_alive = true;
   2539     else
   2540       use_conn_k_alive = false;
   2541   }
   2542   else
   2543   {
   2544     use_conn_close = false;
   2545     use_conn_k_alive = false;
   2546   }
   2547 
   2548   /* ** Actually build the response header ** */
   2549 
   2550   /* Get all space available */
   2551   connection_maximize_write_buffer (c);
   2552   buf = c->write_buffer;
   2553   pos = c->write_buffer_append_offset;
   2554   buf_size = c->write_buffer_size;
   2555   if (0 == buf_size)
   2556     return MHD_NO;
   2557   mhd_assert (NULL != buf);
   2558 
   2559   /* * The status line * */
   2560 
   2561   /* The HTTP version */
   2562   if (! c->rp.responseIcy)
   2563   { /* HTTP reply */
   2564     if (0 == (r->flags & MHD_RF_HTTP_1_0_SERVER))
   2565     { /* HTTP/1.1 reply */
   2566       /* Use HTTP/1.1 responses for HTTP/1.0 clients.
   2567        * See https://datatracker.ietf.org/doc/html/rfc7230#section-2.6 */
   2568       if (! buffer_append_s (buf, &pos, buf_size, MHD_HTTP_VERSION_1_1))
   2569         return MHD_NO;
   2570     }
   2571     else
   2572     { /* HTTP/1.0 reply */
   2573       if (! buffer_append_s (buf, &pos, buf_size, MHD_HTTP_VERSION_1_0))
   2574         return MHD_NO;
   2575     }
   2576   }
   2577   else
   2578   { /* ICY reply */
   2579     if (! buffer_append_s (buf, &pos, buf_size, "ICY"))
   2580       return MHD_NO;
   2581   }
   2582 
   2583   /* The response code */
   2584   if (buf_size < pos + 5) /* space + code + space */
   2585     return MHD_NO;
   2586   buf[pos++] = ' ';
   2587   pos += MHD_uint16_to_str ((uint16_t) rcode, buf + pos,
   2588                             buf_size - pos);
   2589   buf[pos++] = ' ';
   2590 
   2591   /* The reason phrase */
   2592   el_size = MHD_get_reason_phrase_len_for (rcode);
   2593   if (0 == el_size)
   2594   {
   2595     if (! buffer_append_s (buf, &pos, buf_size, "Non-Standard Status"))
   2596       return MHD_NO;
   2597   }
   2598   else if (! buffer_append (buf, &pos, buf_size,
   2599                             MHD_get_reason_phrase_for (rcode),
   2600                             el_size))
   2601     return MHD_NO;
   2602 
   2603   /* The linefeed */
   2604   if (buf_size < pos + 2)
   2605     return MHD_NO;
   2606   buf[pos++] = '\r';
   2607   buf[pos++] = '\n';
   2608 
   2609   /* * The headers * */
   2610 
   2611   /* Main automatic headers */
   2612 
   2613   /* The "Date:" header */
   2614   if ( (0 == (r->flags_auto & MHD_RAF_HAS_DATE_HDR)) &&
   2615        (0 == (c->daemon->options & MHD_USE_SUPPRESS_DATE_NO_CLOCK)) )
   2616   {
   2617     /* Additional byte for unused zero-termination */
   2618     if (buf_size < pos + 38)
   2619       return MHD_NO;
   2620     if (get_date_header (buf + pos))
   2621       pos += 37;
   2622   }
   2623   /* The "Connection:" header */
   2624   mhd_assert (! use_conn_close || ! use_conn_k_alive);
   2625   mhd_assert (! use_conn_k_alive || ! use_conn_close);
   2626   if (0 == (r->flags_auto & MHD_RAF_HAS_CONNECTION_HDR))
   2627   {
   2628     if (use_conn_close)
   2629     {
   2630       if (! buffer_append_s (buf, &pos, buf_size,
   2631                              MHD_HTTP_HEADER_CONNECTION ": close\r\n"))
   2632         return MHD_NO;
   2633     }
   2634     else if (use_conn_k_alive)
   2635     {
   2636       if (! buffer_append_s (buf, &pos, buf_size,
   2637                              MHD_HTTP_HEADER_CONNECTION ": Keep-Alive\r\n"))
   2638         return MHD_NO;
   2639     }
   2640   }
   2641 
   2642   /* User-defined headers */
   2643 
   2644   if (! add_user_headers (buf, &pos, buf_size, r,
   2645                           ! c->rp.props.chunked,
   2646                           (! c->rp.props.use_reply_body_headers) &&
   2647                           (0 ==
   2648                            (r->flags & MHD_RF_INSANITY_HEADER_CONTENT_LENGTH)),
   2649                           use_conn_close,
   2650                           use_conn_k_alive))
   2651     return MHD_NO;
   2652 
   2653   /* Other automatic headers */
   2654 
   2655   if ( (c->rp.props.use_reply_body_headers) &&
   2656        (0 == (r->flags & MHD_RF_HEAD_ONLY_RESPONSE)) )
   2657   {
   2658     /* Body-specific headers */
   2659 
   2660     if (c->rp.props.chunked)
   2661     { /* Chunked encoding is used */
   2662       if (0 == (r->flags_auto & MHD_RAF_HAS_TRANS_ENC_CHUNKED))
   2663       { /* No chunked encoding header set by user */
   2664         if (! buffer_append_s (buf, &pos, buf_size,
   2665                                MHD_HTTP_HEADER_TRANSFER_ENCODING ": " \
   2666                                "chunked\r\n"))
   2667           return MHD_NO;
   2668       }
   2669     }
   2670     else /* Chunked encoding is not used */
   2671     {
   2672       if (MHD_SIZE_UNKNOWN != r->total_size)
   2673       { /* The size is known */
   2674         if (0 == (r->flags_auto & MHD_RAF_HAS_CONTENT_LENGTH))
   2675         { /* The response does not have "Content-Length" header */
   2676           if (! buffer_append_s (buf, &pos, buf_size,
   2677                                  MHD_HTTP_HEADER_CONTENT_LENGTH ": "))
   2678             return MHD_NO;
   2679           el_size = MHD_uint64_to_str (r->total_size, buf + pos,
   2680                                        buf_size - pos);
   2681           if (0 == el_size)
   2682             return MHD_NO;
   2683           pos += el_size;
   2684 
   2685           if (buf_size < pos + 2)
   2686             return MHD_NO;
   2687           buf[pos++] = '\r';
   2688           buf[pos++] = '\n';
   2689         }
   2690       }
   2691     }
   2692   }
   2693 
   2694   /* * Header termination * */
   2695   if (buf_size < pos + 2)
   2696     return MHD_NO;
   2697   buf[pos++] = '\r';
   2698   buf[pos++] = '\n';
   2699 
   2700   c->write_buffer_append_offset = pos;
   2701   return MHD_YES;
   2702 }
   2703 
   2704 
   2705 /**
   2706  * Allocate the connection's write buffer (if necessary) and fill it
   2707  * with response footers.
   2708  * Works only for chunked responses as other responses do not need
   2709  * and do not support any kind of footers.
   2710  *
   2711  * @param connection the connection
   2712  * @return #MHD_YES on success, #MHD_NO on failure (out of memory)
   2713  */
   2714 static enum MHD_Result
   2715 build_connection_chunked_response_footer (struct MHD_Connection *connection)
   2716 {
   2717   char *buf;           /**< the buffer to write footers to */
   2718   size_t buf_size;     /**< the size of the @a buf */
   2719   size_t used_size;    /**< the used size of the @a buf */
   2720   struct MHD_Connection *const c = connection; /**< a short alias */
   2721   struct MHD_HTTP_Res_Header *pos;
   2722 
   2723   mhd_assert (connection->rp.props.chunked);
   2724   /* TODO: allow combining of the final footer with the last chunk,
   2725    * modify the next assert. */
   2726   mhd_assert (MHD_CONNECTION_CHUNKED_BODY_SENT == connection->state);
   2727   mhd_assert (NULL != c->rp.response);
   2728 
   2729   buf_size = connection_maximize_write_buffer (c);
   2730   /* '5' is the minimal size of chunked footer ("0\r\n\r\n") */
   2731   if (buf_size < 5)
   2732     return MHD_NO;
   2733   mhd_assert (NULL != c->write_buffer);
   2734   buf = c->write_buffer + c->write_buffer_append_offset;
   2735   mhd_assert (NULL != buf);
   2736   used_size = 0;
   2737   buf[used_size++] = '0';
   2738   buf[used_size++] = '\r';
   2739   buf[used_size++] = '\n';
   2740 
   2741   for (pos = c->rp.response->first_header; NULL != pos; pos = pos->next)
   2742   {
   2743     if (MHD_FOOTER_KIND == pos->kind)
   2744     {
   2745       size_t new_used_size; /* resulting size with this header */
   2746       /* '4' is colon, space, linefeeds */
   2747       new_used_size = used_size + pos->header_size + pos->value_size + 4;
   2748       if (new_used_size > buf_size)
   2749         return MHD_NO;
   2750       memcpy (buf + used_size, pos->header, pos->header_size);
   2751       used_size += pos->header_size;
   2752       buf[used_size++] = ':';
   2753       buf[used_size++] = ' ';
   2754       memcpy (buf + used_size, pos->value, pos->value_size);
   2755       used_size += pos->value_size;
   2756       buf[used_size++] = '\r';
   2757       buf[used_size++] = '\n';
   2758       mhd_assert (used_size == new_used_size);
   2759     }
   2760   }
   2761   if (used_size + 2 > buf_size)
   2762     return MHD_NO;
   2763   buf[used_size++] = '\r';
   2764   buf[used_size++] = '\n';
   2765 
   2766   c->write_buffer_append_offset += used_size;
   2767   mhd_assert (c->write_buffer_append_offset <= c->write_buffer_size);
   2768 
   2769   return MHD_YES;
   2770 }
   2771 
   2772 
   2773 /**
   2774  * We encountered an error processing the request.
   2775  * Handle it properly by stopping to read data
   2776  * and sending the indicated response code and message.
   2777  *
   2778  * @param connection the connection
   2779  * @param status_code the response code to send (400, 413 or 414)
   2780  * @param message the error message to send
   2781  * @param message_len the length of the @a message
   2782  * @param header_name the name of the header, malloc()ed by the caller,
   2783  *                    free() by this function, optional, can be NULL
   2784  * @param header_name_len the length of the @a header_name
   2785  * @param header_value the value of the header, malloc()ed by the caller,
   2786  *                     free() by this function, optional, can be NULL
   2787  * @param header_value_len the length of the @a header_value
   2788  */
   2789 static void
   2790 transmit_error_response_len (struct MHD_Connection *connection,
   2791                              unsigned int status_code,
   2792                              const char *message,
   2793                              size_t message_len,
   2794                              char *header_name,
   2795                              size_t header_name_len,
   2796                              char *header_value,
   2797                              size_t header_value_len)
   2798 {
   2799   struct MHD_Response *response;
   2800   enum MHD_Result iret;
   2801 
   2802   mhd_assert (! connection->stop_with_error); /* Do not send error twice */
   2803   if (connection->stop_with_error)
   2804   { /* Should not happen */
   2805     if (MHD_CONNECTION_CLOSED > connection->state)
   2806       connection->state = MHD_CONNECTION_CLOSED;
   2807     free (header_name);
   2808     free (header_value);
   2809     return;
   2810   }
   2811   connection->stop_with_error = true;
   2812   connection->discard_request = true;
   2813 #ifdef HAVE_MESSAGES
   2814   MHD_DLOG (connection->daemon,
   2815             _ ("Error processing request (HTTP response code is %u ('%s')). " \
   2816                "Closing connection.\n"),
   2817             status_code,
   2818             message);
   2819 #endif
   2820   if (MHD_CONNECTION_START_REPLY < connection->state)
   2821   {
   2822 #ifdef HAVE_MESSAGES
   2823     MHD_DLOG (connection->daemon,
   2824               _ ("Too late to send an error response, " \
   2825                  "response is being sent already.\n"),
   2826               status_code,
   2827               message);
   2828 #endif
   2829     CONNECTION_CLOSE_ERROR (connection,
   2830                             _ ("Too late for error response."));
   2831     free (header_name);
   2832     free (header_value);
   2833     return;
   2834   }
   2835   /* TODO: remove when special error queue function is implemented */
   2836   connection->state = MHD_CONNECTION_FULL_REQ_RECEIVED;
   2837   if (0 != connection->read_buffer_size)
   2838   {
   2839     /* Read buffer is not needed anymore, discard it
   2840      * to free some space for error response. */
   2841     MHD_pool_deallocate (connection->pool,
   2842                          connection->read_buffer,
   2843                          connection->read_buffer_size);
   2844     connection->read_buffer = NULL;
   2845     connection->read_buffer_size = 0;
   2846     connection->read_buffer_offset = 0;
   2847   }
   2848   if (NULL != connection->rp.response)
   2849   {
   2850     MHD_destroy_response (connection->rp.response);
   2851     connection->rp.response = NULL;
   2852   }
   2853   response = MHD_create_response_from_buffer_static (message_len,
   2854                                                      message);
   2855   if (NULL == response)
   2856   {
   2857 #ifdef HAVE_MESSAGES
   2858     MHD_DLOG (connection->daemon,
   2859               _ ("Failed to create error response.\n"),
   2860               status_code,
   2861               message);
   2862 #endif
   2863     /* can't even send a reply, at least close the connection */
   2864     connection->state = MHD_CONNECTION_CLOSED;
   2865     free (header_name);
   2866     free (header_value);
   2867     return;
   2868   }
   2869   mhd_assert ((0 == header_name_len) || (NULL != header_name));
   2870   mhd_assert ((NULL == header_name) || (0 != header_name_len));
   2871   mhd_assert ((0 == header_value_len) || (NULL != header_value));
   2872   mhd_assert ((NULL == header_value) || (0 != header_value_len));
   2873   mhd_assert ((NULL == header_name) || (NULL != header_value));
   2874   mhd_assert ((NULL != header_value) || (NULL == header_name));
   2875   if (NULL != header_name)
   2876   {
   2877     iret = MHD_add_response_entry_no_alloc_ (response,
   2878                                              MHD_HEADER_KIND,
   2879                                              header_name, header_name_len,
   2880                                              header_value, header_value_len);
   2881     if (MHD_NO == iret)
   2882     {
   2883       free (header_name);
   2884       free (header_value);
   2885     }
   2886   }
   2887   else
   2888     iret = MHD_YES;
   2889 
   2890   if (MHD_NO != iret)
   2891   {
   2892     bool before = connection->in_access_handler;
   2893 
   2894     /* Fake the flag for the internal call */
   2895     connection->in_access_handler = true;
   2896     iret = MHD_queue_response (connection,
   2897                                status_code,
   2898                                response);
   2899     connection->in_access_handler = before;
   2900   }
   2901   MHD_destroy_response (response);
   2902   if (MHD_NO == iret)
   2903   {
   2904     /* can't even send a reply, at least close the connection */
   2905     CONNECTION_CLOSE_ERROR (connection,
   2906                             _ ("Closing connection " \
   2907                                "(failed to queue error response)."));
   2908     return;
   2909   }
   2910   mhd_assert (NULL != connection->rp.response);
   2911   /* Do not reuse this connection. */
   2912   connection->keepalive = MHD_CONN_MUST_CLOSE;
   2913   if (MHD_NO == build_header_response (connection))
   2914   {
   2915     /* No memory. Release everything. */
   2916     connection->rq.version = NULL;
   2917     connection->rq.method = NULL;
   2918     connection->rq.url = NULL;
   2919     connection->rq.url_len = 0;
   2920     connection->rq.headers_received = NULL;
   2921     connection->rq.headers_received_tail = NULL;
   2922     connection->write_buffer = NULL;
   2923     connection->write_buffer_size = 0;
   2924     connection->write_buffer_send_offset = 0;
   2925     connection->write_buffer_append_offset = 0;
   2926     connection->read_buffer
   2927       = MHD_pool_reset (connection->pool,
   2928                         NULL,
   2929                         0,
   2930                         0);
   2931     connection->read_buffer_size = 0;
   2932 
   2933     /* Retry with empty buffer */
   2934     if (MHD_NO == build_header_response (connection))
   2935     {
   2936       CONNECTION_CLOSE_ERROR (connection,
   2937                               _ ("Closing connection " \
   2938                                  "(failed to create error response header)."));
   2939       return;
   2940     }
   2941   }
   2942   connection->state = MHD_CONNECTION_HEADERS_SENDING;
   2943 }
   2944 
   2945 
   2946 /**
   2947  * Transmit static string as error response
   2948  */
   2949 #define transmit_error_response_static(c, code, msg) \
   2950   transmit_error_response_len (c, code, \
   2951                                msg, MHD_STATICSTR_LEN_ (msg), \
   2952                                NULL, 0, NULL, 0)
   2953 
   2954 /**
   2955  * Transmit static string as error response and add specified header
   2956  */
   2957 #define transmit_error_response_header(c, code, m, hd_n, hd_n_l, hd_v, hd_v_l) \
   2958   transmit_error_response_len (c, code, \
   2959                                m, MHD_STATICSTR_LEN_ (m), \
   2960                                hd_n, hd_n_l, \
   2961                                hd_v, hd_v_l)
   2962 
   2963 
   2964 /**
   2965  * Check whether the read buffer has any upload body data ready to
   2966  * be processed.
   2967  * Must be called only when connection is in MHD_CONNECTION_BODY_RECEIVING
   2968  * state.
   2969  *
   2970  * @param c the connection to check
   2971  * @return 'true' if upload body data is already in the read buffer,
   2972  *         'false' if no upload data is received and not processed.
   2973  */
   2974 static bool
   2975 has_unprocessed_upload_body_data_in_buffer (struct MHD_Connection *c)
   2976 {
   2977   mhd_assert (MHD_CONNECTION_BODY_RECEIVING == c->state);
   2978   if (! c->rq.have_chunked_upload)
   2979     return 0 != c->read_buffer_offset;
   2980 
   2981   /* Chunked upload */
   2982   mhd_assert (0 != c->rq.remaining_upload_size); /* Must not be possible in MHD_CONNECTION_BODY_RECEIVING state */
   2983   if (c->rq.current_chunk_offset == c->rq.current_chunk_size)
   2984   {
   2985     /* 0 == c->rq.current_chunk_size: Waiting the chunk size (chunk header).
   2986        0 != c->rq.current_chunk_size: Waiting for chunk-closing CRLF. */
   2987     return false;
   2988   }
   2989   return 0 != c->read_buffer_offset; /* Chunk payload data in the read buffer */
   2990 }
   2991 
   2992 
   2993 /**
   2994  * The stage of input data processing.
   2995  * Used for out-of-memory (in the pool) handling.
   2996  */
   2997 enum MHD_ProcRecvDataStage
   2998 {
   2999   MHD_PROC_RECV_INIT,        /**< No data HTTP request data have been processed yet */
   3000   MHD_PROC_RECV_METHOD,      /**< Processing/receiving the request HTTP method */
   3001   MHD_PROC_RECV_URI,         /**< Processing/receiving the request URI */
   3002   MHD_PROC_RECV_HTTPVER,     /**< Processing/receiving the request HTTP version string */
   3003   MHD_PROC_RECV_HEADERS,     /**< Processing/receiving the request HTTP headers */
   3004   MHD_PROC_RECV_COOKIE,      /**< Processing the received request cookie header */
   3005   MHD_PROC_RECV_BODY_NORMAL, /**< Processing/receiving the request non-chunked body */
   3006   MHD_PROC_RECV_BODY_CHUNKED,/**< Processing/receiving the request chunked body */
   3007   MHD_PROC_RECV_FOOTERS      /**< Processing/receiving the request footers */
   3008 };
   3009 
   3010 
   3011 #ifndef MHD_MAX_REASONABLE_HEADERS_SIZE_
   3012 /**
   3013  * A reasonable headers size (excluding request line) that should be sufficient
   3014  * for most requests.
   3015  * If incoming data buffer free space is not enough to process the complete
   3016  * header (the request line and all headers) and the headers size is larger than
   3017  * this size then the status code 431 "Request Header Fields Too Large" is
   3018  * returned to the client.
   3019  * The larger headers are processed by MHD if enough space is available.
   3020  */
   3021 #  define MHD_MAX_REASONABLE_HEADERS_SIZE_ (6 * 1024)
   3022 #endif /* ! MHD_MAX_REASONABLE_HEADERS_SIZE_ */
   3023 
   3024 #ifndef MHD_MAX_REASONABLE_REQ_TARGET_SIZE_
   3025 /**
   3026  * A reasonable request target (the request URI) size that should be sufficient
   3027  * for most requests.
   3028  * If incoming data buffer free space is not enough to process the complete
   3029  * header (the request line and all headers) and the request target size is
   3030  * larger than this size then the status code 414 "URI Too Long" is
   3031  * returned to the client.
   3032  * The larger request targets are processed by MHD if enough space is available.
   3033  * The value chosen according to RFC 9112 Section 3, paragraph 5
   3034  */
   3035 #  define MHD_MAX_REASONABLE_REQ_TARGET_SIZE_ 8000
   3036 #endif /* ! MHD_MAX_REASONABLE_REQ_TARGET_SIZE_ */
   3037 
   3038 #ifndef MHD_MIN_REASONABLE_HEADERS_SIZE_
   3039 /**
   3040  * A reasonable headers size (excluding request line) that should be sufficient
   3041  * for basic simple requests.
   3042  * When no space left in the receiving buffer try to avoid replying with
   3043  * the status code 431 "Request Header Fields Too Large" if headers size
   3044  * is smaller then this value.
   3045  */
   3046 #  define MHD_MIN_REASONABLE_HEADERS_SIZE_ 26
   3047 #endif /* ! MHD_MIN_REASONABLE_HEADERS_SIZE_ */
   3048 
   3049 #ifndef MHD_MIN_REASONABLE_REQ_TARGET_SIZE_
   3050 /**
   3051  * A reasonable request target (the request URI) size that should be sufficient
   3052  * for basic simple requests.
   3053  * When no space left in the receiving buffer try to avoid replying with
   3054  * the status code 414 "URI Too Long" if the request target size is smaller then
   3055  * this value.
   3056  */
   3057 #  define MHD_MIN_REASONABLE_REQ_TARGET_SIZE_ 40
   3058 #endif /* ! MHD_MIN_REASONABLE_REQ_TARGET_SIZE_ */
   3059 
   3060 #ifndef MHD_MIN_REASONABLE_REQ_METHOD_SIZE_
   3061 /**
   3062  * A reasonable request method string size that should be sufficient
   3063  * for basic simple requests.
   3064  * When no space left in the receiving buffer try to avoid replying with
   3065  * the status code 501 "Not Implemented" if the request method size is
   3066  * smaller then this value.
   3067  */
   3068 #  define MHD_MIN_REASONABLE_REQ_METHOD_SIZE_ 16
   3069 #endif /* ! MHD_MIN_REASONABLE_REQ_METHOD_SIZE_ */
   3070 
   3071 #ifndef MHD_MIN_REASONABLE_REQ_CHUNK_LINE_LENGTH_
   3072 /**
   3073  * A reasonable minimal chunk line length.
   3074  * When no space left in the receiving buffer reply with 413 "Content Too Large"
   3075  * if the chunk line length is larger than this value.
   3076  */
   3077 #  define MHD_MIN_REASONABLE_REQ_CHUNK_LINE_LENGTH_ 4
   3078 #endif /* ! MHD_MIN_REASONABLE_REQ_CHUNK_LINE_LENGTH_ */
   3079 
   3080 
   3081 /**
   3082  * Select the HTTP error status code for "out of receive buffer space" error.
   3083  * @param c the connection to process
   3084  * @param stage the current stage of request receiving
   3085  * @param add_element the optional pointer to the element failed to be processed
   3086  *                    or added, the meaning of the element depends on
   3087  *                    the @a stage. Could be not zero-terminated and can
   3088  *                    contain binary zeros. Can be NULL.
   3089  * @param add_element_size the size of the @a add_element
   3090  * @return the HTTP error code to use in the error reply
   3091  */
   3092 static unsigned int
   3093 get_no_space_err_status_code (struct MHD_Connection *c,
   3094                               enum MHD_ProcRecvDataStage stage,
   3095                               const char *add_element,
   3096                               size_t add_element_size)
   3097 {
   3098   size_t method_size;
   3099   size_t uri_size;
   3100   size_t opt_headers_size;
   3101   size_t host_field_line_size;
   3102 
   3103   mhd_assert (MHD_CONNECTION_REQ_LINE_RECEIVED < c->state);
   3104   mhd_assert (MHD_PROC_RECV_HEADERS <= stage);
   3105   mhd_assert ((0 == add_element_size) || (NULL != add_element));
   3106 
   3107   if (MHD_CONNECTION_HEADERS_RECEIVED > c->state)
   3108   {
   3109     mhd_assert (NULL != c->rq.field_lines.start);
   3110     opt_headers_size =
   3111       (size_t) ((c->read_buffer + c->read_buffer_offset)
   3112                 - c->rq.field_lines.start);
   3113   }
   3114   else
   3115     opt_headers_size = c->rq.field_lines.size;
   3116 
   3117   /* The read buffer is fully used by the request line, the field lines
   3118      (headers) and internal information.
   3119      The return status code works as a suggestion for the client to reduce
   3120      one of the request elements. */
   3121 
   3122   if ((MHD_PROC_RECV_BODY_CHUNKED == stage) &&
   3123       (MHD_MIN_REASONABLE_REQ_CHUNK_LINE_LENGTH_ < add_element_size))
   3124   {
   3125     /* Request could be re-tried easily with smaller chunk sizes */
   3126     return MHD_HTTP_CONTENT_TOO_LARGE;
   3127   }
   3128 
   3129   host_field_line_size = 0;
   3130   /* The "Host:" field line is mandatory.
   3131      The total size of the field lines (headers) cannot be smaller than
   3132      the size of the "Host:" field line. */
   3133   if ((MHD_PROC_RECV_HEADERS == stage)
   3134       && (0 != add_element_size))
   3135   {
   3136     static const size_t header_host_key_len =
   3137       MHD_STATICSTR_LEN_ (MHD_HTTP_HEADER_HOST);
   3138     const bool is_host_header =
   3139       (header_host_key_len + 1 <= add_element_size)
   3140       && ( (0 == add_element[header_host_key_len])
   3141            || (':' == add_element[header_host_key_len]) )
   3142       && MHD_str_equal_caseless_bin_n_ (MHD_HTTP_HEADER_HOST,
   3143                                         add_element,
   3144                                         header_host_key_len);
   3145     if (is_host_header)
   3146     {
   3147       const bool is_parsed = ! (
   3148         (MHD_CONNECTION_HEADERS_RECEIVED > c->state) &&
   3149         (add_element_size == c->read_buffer_offset) &&
   3150         (c->read_buffer == add_element) );
   3151       size_t actual_element_size;
   3152 
   3153       mhd_assert (! is_parsed || (0 == add_element[header_host_key_len]));
   3154       /* The actual size should be larger due to CRLF or LF chars,
   3155          however the exact termination sequence is not known here and
   3156          as perfect precision is not required, to simplify the code
   3157          assume the minimal length. */
   3158       if (is_parsed)
   3159         actual_element_size = add_element_size + 1;  /* "1" for LF */
   3160       else
   3161         actual_element_size = add_element_size;
   3162 
   3163       host_field_line_size = actual_element_size;
   3164       mhd_assert (opt_headers_size >= actual_element_size);
   3165       opt_headers_size -= actual_element_size;
   3166     }
   3167   }
   3168   if (0 == host_field_line_size)
   3169   {
   3170     static const size_t host_field_name_len =
   3171       MHD_STATICSTR_LEN_ (MHD_HTTP_HEADER_HOST);
   3172     size_t host_field_name_value_len;
   3173     if (MHD_NO != MHD_lookup_connection_value_n (c,
   3174                                                  MHD_HEADER_KIND,
   3175                                                  MHD_HTTP_HEADER_HOST,
   3176                                                  host_field_name_len,
   3177                                                  NULL,
   3178                                                  &host_field_name_value_len))
   3179     {
   3180       /* Calculate the minimal size of the field line: no space between
   3181          colon and the field value, line terminated by LR */
   3182       host_field_line_size =
   3183         host_field_name_len + host_field_name_value_len + 2; /* "2" for ':' and LF */
   3184 
   3185       /* The "Host:" field could be added by application */
   3186       if (opt_headers_size >= host_field_line_size)
   3187       {
   3188         opt_headers_size -= host_field_line_size;
   3189         /* Take into account typical space after colon and CR at the end of the line */
   3190         if (opt_headers_size >= 2)
   3191           opt_headers_size -= 2;
   3192       }
   3193       else
   3194         host_field_line_size = 0; /* No "Host:" field line set by the client */
   3195     }
   3196   }
   3197 
   3198   uri_size = c->rq.req_target_len;
   3199   if (MHD_HTTP_MTHD_OTHER != c->rq.http_mthd)
   3200     method_size = 0; /* Do not recommend shorter request method */
   3201   else
   3202   {
   3203     mhd_assert (NULL != c->rq.method);
   3204     method_size = strlen (c->rq.method);
   3205   }
   3206 
   3207   if ((size_t) MHD_MAX_REASONABLE_HEADERS_SIZE_ < opt_headers_size)
   3208   {
   3209     /* Typically the easiest way to reduce request header size is
   3210        a removal of some optional headers. */
   3211     if (opt_headers_size > (uri_size / 8))
   3212     {
   3213       if ((opt_headers_size / 2) > method_size)
   3214         return MHD_HTTP_REQUEST_HEADER_FIELDS_TOO_LARGE;
   3215       else
   3216         return MHD_HTTP_NOT_IMPLEMENTED; /* The length of the HTTP request method is unreasonably large */
   3217     }
   3218     else
   3219     { /* Request target is MUCH larger than headers */
   3220       if ((uri_size / 16) > method_size)
   3221         return MHD_HTTP_URI_TOO_LONG;
   3222       else
   3223         return MHD_HTTP_NOT_IMPLEMENTED; /* The length of the HTTP request method is unreasonably large */
   3224     }
   3225   }
   3226   if ((size_t) MHD_MAX_REASONABLE_REQ_TARGET_SIZE_ < uri_size)
   3227   {
   3228     /* If request target size if larger than maximum reasonable size
   3229        recommend client to reduce the request target size (length). */
   3230     if ((uri_size / 16) > method_size)
   3231       return MHD_HTTP_URI_TOO_LONG;     /* Request target is MUCH larger than headers */
   3232     else
   3233       return MHD_HTTP_NOT_IMPLEMENTED;  /* The length of the HTTP request method is unreasonably large */
   3234   }
   3235 
   3236   /* The read buffer is too small to handle reasonably large requests */
   3237 
   3238   if ((size_t) MHD_MIN_REASONABLE_HEADERS_SIZE_ < opt_headers_size)
   3239   {
   3240     /* Recommend application to retry with minimal headers */
   3241     if ((opt_headers_size * 4) > uri_size)
   3242     {
   3243       if (opt_headers_size > method_size)
   3244         return MHD_HTTP_REQUEST_HEADER_FIELDS_TOO_LARGE;
   3245       else
   3246         return MHD_HTTP_NOT_IMPLEMENTED; /* The length of the HTTP request method is unreasonably large */
   3247     }
   3248     else
   3249     { /* Request target is significantly larger than headers */
   3250       if (uri_size > method_size * 4)
   3251         return MHD_HTTP_URI_TOO_LONG;
   3252       else
   3253         return MHD_HTTP_NOT_IMPLEMENTED; /* The length of the HTTP request method is unreasonably large */
   3254     }
   3255   }
   3256   if ((size_t) MHD_MIN_REASONABLE_REQ_TARGET_SIZE_ < uri_size)
   3257   {
   3258     /* Recommend application to retry with a shorter request target */
   3259     if (uri_size > method_size * 4)
   3260       return MHD_HTTP_URI_TOO_LONG;
   3261     else
   3262       return MHD_HTTP_NOT_IMPLEMENTED; /* The length of the HTTP request method is unreasonably large */
   3263   }
   3264 
   3265   if ((size_t) MHD_MIN_REASONABLE_REQ_METHOD_SIZE_ < method_size)
   3266   {
   3267     /* The request target (URI) and headers are (reasonably) very small.
   3268        Some non-standard long request method is used. */
   3269     /* The last resort response as it means "the method is not supported
   3270        by the server for any URI". */
   3271     return MHD_HTTP_NOT_IMPLEMENTED;
   3272   }
   3273 
   3274   /* The almost impossible situation: all elements are small, but cannot
   3275      fit the buffer. The application set the buffer size to
   3276      critically low value? */
   3277 
   3278   if ((1 < opt_headers_size) || (1 < uri_size))
   3279   {
   3280     if (opt_headers_size >= uri_size)
   3281       return MHD_HTTP_REQUEST_HEADER_FIELDS_TOO_LARGE;
   3282     else
   3283       return MHD_HTTP_URI_TOO_LONG;
   3284   }
   3285 
   3286   /* Nothing to reduce in the request.
   3287      Reply with some status. */
   3288   if (0 != host_field_line_size)
   3289     return MHD_HTTP_REQUEST_HEADER_FIELDS_TOO_LARGE;
   3290 
   3291   return MHD_HTTP_URI_TOO_LONG;
   3292 }
   3293 
   3294 
   3295 /**
   3296  * Send error reply when receive buffer space exhausted while receiving or
   3297  * storing the request headers
   3298  * @param c the connection to handle
   3299  * @param add_header the optional pointer to the current header string being
   3300  *                   processed or the header failed to be added.
   3301  *                   Could be not zero-terminated and can contain binary zeros.
   3302  *                   Can be NULL.
   3303  * @param add_header_size the size of the @a add_header
   3304  */
   3305 static void
   3306 handle_req_headers_no_space (struct MHD_Connection *c,
   3307                              const char *add_header,
   3308                              size_t add_header_size)
   3309 {
   3310   unsigned int err_code;
   3311 
   3312   err_code = get_no_space_err_status_code (c,
   3313                                            MHD_PROC_RECV_HEADERS,
   3314                                            add_header,
   3315                                            add_header_size);
   3316   transmit_error_response_static (c,
   3317                                   err_code,
   3318                                   ERR_MSG_REQUEST_HEADER_TOO_BIG);
   3319 }
   3320 
   3321 
   3322 #ifdef COOKIE_SUPPORT
   3323 /**
   3324  * Send error reply when the pool has no space to store 'cookie' header
   3325  * parsing results.
   3326  * @param c the connection to handle
   3327  */
   3328 static void
   3329 handle_req_cookie_no_space (struct MHD_Connection *c)
   3330 {
   3331   unsigned int err_code;
   3332 
   3333   err_code = get_no_space_err_status_code (c,
   3334                                            MHD_PROC_RECV_COOKIE,
   3335                                            NULL,
   3336                                            0);
   3337   transmit_error_response_static (c,
   3338                                   err_code,
   3339                                   ERR_MSG_REQUEST_HEADER_WITH_COOKIES_TOO_BIG);
   3340 }
   3341 
   3342 
   3343 #endif /* COOKIE_SUPPORT */
   3344 
   3345 
   3346 /**
   3347  * Send error reply when receive buffer space exhausted while receiving
   3348  * the chunk size line.
   3349  * @param c the connection to handle
   3350  * @param add_header the optional pointer to the partially received
   3351  *                   the current chunk size line.
   3352  *                   Could be not zero-terminated and can contain binary zeros.
   3353  *                   Can be NULL.
   3354  * @param add_header_size the size of the @a add_header
   3355  */
   3356 static void
   3357 handle_req_chunk_size_line_no_space (struct MHD_Connection *c,
   3358                                      const char *chunk_size_line,
   3359                                      size_t chunk_size_line_size)
   3360 {
   3361   unsigned int err_code;
   3362 
   3363   if (NULL != chunk_size_line)
   3364   {
   3365     const char *semicol;
   3366     /* Check for chunk extension */
   3367     semicol = memchr (chunk_size_line, ';', chunk_size_line_size);
   3368     if (NULL != semicol)
   3369     { /* Chunk extension present. It could be removed without any loss of the
   3370          details of the request. */
   3371       transmit_error_response_static (c,
   3372                                       MHD_HTTP_CONTENT_TOO_LARGE,
   3373                                       ERR_MSG_REQUEST_CHUNK_LINE_EXT_TOO_BIG);
   3374     }
   3375   }
   3376   err_code = get_no_space_err_status_code (c,
   3377                                            MHD_PROC_RECV_BODY_CHUNKED,
   3378                                            chunk_size_line,
   3379                                            chunk_size_line_size);
   3380   transmit_error_response_static (c,
   3381                                   err_code,
   3382                                   ERR_MSG_REQUEST_CHUNK_LINE_TOO_BIG);
   3383 }
   3384 
   3385 
   3386 /**
   3387  * Send error reply when receive buffer space exhausted while receiving or
   3388  * storing the request footers (for chunked requests).
   3389  * @param c the connection to handle
   3390  * @param add_footer the optional pointer to the current footer string being
   3391  *                   processed or the footer failed to be added.
   3392  *                   Could be not zero-terminated and can contain binary zeros.
   3393  *                   Can be NULL.
   3394  * @param add_footer_size the size of the @a add_footer
   3395  */
   3396 static void
   3397 handle_req_footers_no_space (struct MHD_Connection *c,
   3398                              const char *add_footer,
   3399                              size_t add_footer_size)
   3400 {
   3401   (void) add_footer; (void) add_footer_size; /* Unused */
   3402   mhd_assert (c->rq.have_chunked_upload);
   3403 
   3404   /* Footers should be optional */
   3405   transmit_error_response_static (c,
   3406                                   MHD_HTTP_REQUEST_HEADER_FIELDS_TOO_LARGE,
   3407                                   ERR_MSG_REQUEST_FOOTER_TOO_BIG);
   3408 }
   3409 
   3410 
   3411 /**
   3412  * Handle situation with read buffer exhaustion.
   3413  * Must be called when no more space left in the read buffer, no more
   3414  * space left in the memory pool to grow the read buffer, but more data
   3415  * need to be received from the client.
   3416  * Could be called when the result of received data processing cannot be
   3417  * stored in the memory pool (like some header).
   3418  * @param c the connection to process
   3419  * @param stage the receive stage where the exhaustion happens.
   3420  */
   3421 static void
   3422 handle_recv_no_space (struct MHD_Connection *c,
   3423                       enum MHD_ProcRecvDataStage stage)
   3424 {
   3425   mhd_assert (MHD_PROC_RECV_INIT <= stage);
   3426   mhd_assert (MHD_PROC_RECV_FOOTERS >= stage);
   3427   mhd_assert (MHD_CONNECTION_FULL_REQ_RECEIVED > c->state);
   3428   mhd_assert ((MHD_PROC_RECV_INIT != stage) || \
   3429               (MHD_CONNECTION_INIT == c->state));
   3430   mhd_assert ((MHD_PROC_RECV_METHOD != stage) || \
   3431               (MHD_CONNECTION_REQ_LINE_RECEIVING == c->state));
   3432   mhd_assert ((MHD_PROC_RECV_URI != stage) || \
   3433               (MHD_CONNECTION_REQ_LINE_RECEIVING == c->state));
   3434   mhd_assert ((MHD_PROC_RECV_HTTPVER != stage) || \
   3435               (MHD_CONNECTION_REQ_LINE_RECEIVING == c->state));
   3436   mhd_assert ((MHD_PROC_RECV_HEADERS != stage) || \
   3437               (MHD_CONNECTION_REQ_HEADERS_RECEIVING == c->state));
   3438   mhd_assert (MHD_PROC_RECV_COOKIE != stage); /* handle_req_cookie_no_space() must be called directly */
   3439   mhd_assert ((MHD_PROC_RECV_BODY_NORMAL != stage) || \
   3440               (MHD_CONNECTION_BODY_RECEIVING == c->state));
   3441   mhd_assert ((MHD_PROC_RECV_BODY_CHUNKED != stage) || \
   3442               (MHD_CONNECTION_BODY_RECEIVING == c->state));
   3443   mhd_assert ((MHD_PROC_RECV_FOOTERS != stage) || \
   3444               (MHD_CONNECTION_FOOTERS_RECEIVING == c->state));
   3445   mhd_assert ((MHD_PROC_RECV_BODY_NORMAL != stage) || \
   3446               (! c->rq.have_chunked_upload));
   3447   mhd_assert ((MHD_PROC_RECV_BODY_CHUNKED != stage) || \
   3448               (c->rq.have_chunked_upload));
   3449   switch (stage)
   3450   {
   3451   case MHD_PROC_RECV_INIT:
   3452   case MHD_PROC_RECV_METHOD:
   3453     /* Some data has been received, but it is not clear yet whether
   3454      * the received data is an valid HTTP request */
   3455     connection_close_error (c,
   3456                             _ ("No space left in the read buffer when " \
   3457                                "receiving the initial part of " \
   3458                                "the request line."));
   3459     return;
   3460   case MHD_PROC_RECV_URI:
   3461   case MHD_PROC_RECV_HTTPVER:
   3462     /* Some data has been received, but the request line is incomplete */
   3463     mhd_assert (MHD_HTTP_MTHD_NO_METHOD != c->rq.http_mthd);
   3464     mhd_assert (MHD_HTTP_VER_UNKNOWN == c->rq.http_ver);
   3465     /* A quick simple check whether the incomplete line looks
   3466      * like an HTTP request */
   3467     if ((MHD_HTTP_MTHD_GET <= c->rq.http_mthd) &&
   3468         (MHD_HTTP_MTHD_DELETE >= c->rq.http_mthd))
   3469     {
   3470       transmit_error_response_static (c,
   3471                                       MHD_HTTP_URI_TOO_LONG,
   3472                                       ERR_MSG_REQUEST_TOO_BIG);
   3473       return;
   3474     }
   3475     connection_close_error (c,
   3476                             _ ("No space left in the read buffer when " \
   3477                                "receiving the URI in " \
   3478                                "the request line. " \
   3479                                "The request uses non-standard HTTP request " \
   3480                                "method token."));
   3481     return;
   3482   case MHD_PROC_RECV_HEADERS:
   3483     handle_req_headers_no_space (c, c->read_buffer, c->read_buffer_offset);
   3484     return;
   3485   case MHD_PROC_RECV_BODY_NORMAL:
   3486   case MHD_PROC_RECV_BODY_CHUNKED:
   3487     mhd_assert ((MHD_PROC_RECV_BODY_CHUNKED != stage) || \
   3488                 ! c->rq.some_payload_processed);
   3489     if (has_unprocessed_upload_body_data_in_buffer (c))
   3490     {
   3491       /* The connection must not be in MHD_EVENT_LOOP_INFO_READ state
   3492          when external polling is used and some data left unprocessed. */
   3493       mhd_assert (MHD_D_IS_USING_THREADS_ (c->daemon));
   3494       /* failed to grow the read buffer, and the
   3495          client which is supposed to handle the
   3496          received data in a *blocking* fashion
   3497          (in this mode) did not handle the data as
   3498          it was supposed to!
   3499          => we would either have to do busy-waiting
   3500          (on the client, which would likely fail),
   3501          or if we do nothing, we would just timeout
   3502          on the connection (if a timeout is even
   3503          set!).
   3504          Solution: we kill the connection with an error */
   3505       transmit_error_response_static (c,
   3506                                       MHD_HTTP_INTERNAL_SERVER_ERROR,
   3507                                       ERROR_MSG_DATA_NOT_HANDLED_BY_APP);
   3508     }
   3509     else
   3510     {
   3511       if (MHD_PROC_RECV_BODY_NORMAL == stage)
   3512       {
   3513         /* A header probably has been added to a suspended connection and
   3514            it took precisely all the space in the buffer.
   3515            Very low probability. */
   3516         mhd_assert (! c->rq.have_chunked_upload);
   3517         handle_req_headers_no_space (c, NULL, 0);
   3518       }
   3519       else
   3520       {
   3521         mhd_assert (c->rq.have_chunked_upload);
   3522         if (c->rq.current_chunk_offset != c->rq.current_chunk_size)
   3523         { /* Receiving content of the chunk */
   3524           /* A header probably has been added to a suspended connection and
   3525              it took precisely all the space in the buffer.
   3526              Very low probability. */
   3527           handle_req_headers_no_space (c, NULL, 0);
   3528         }
   3529         else
   3530         {
   3531           if (0 != c->rq.current_chunk_size)
   3532           { /* Waiting for chunk-closing CRLF */
   3533             /* Not really possible as some payload should be
   3534                processed and the space used by payload should be available. */
   3535             handle_req_headers_no_space (c, NULL, 0);
   3536           }
   3537           else
   3538           { /* Reading the line with the chunk size */
   3539             handle_req_chunk_size_line_no_space (c,
   3540                                                  c->read_buffer,
   3541                                                  c->read_buffer_offset);
   3542           }
   3543         }
   3544       }
   3545     }
   3546     return;
   3547   case MHD_PROC_RECV_FOOTERS:
   3548     handle_req_footers_no_space (c, c->read_buffer, c->read_buffer_offset);
   3549     return;
   3550   /* The next cases should not be possible */
   3551   case MHD_PROC_RECV_COOKIE:
   3552   default:
   3553     break;
   3554   }
   3555   mhd_assert (0);
   3556 }
   3557 
   3558 
   3559 /**
   3560  * Check whether enough space is available in the read buffer for the next
   3561  * operation.
   3562  * Handles grow of the buffer if required and error conditions (when buffer
   3563  * grow is required but not possible).
   3564  * Must be called only when processing the event loop states and when
   3565  * reading is required for the next phase.
   3566  * @param c the connection to check
   3567  * @return true if connection handled successfully and enough buffer
   3568  *         is available,
   3569  *         false if not enough buffer is available and the loop's states
   3570  *         must be processed again as connection is in the error state.
   3571  */
   3572 static bool
   3573 check_and_grow_read_buffer_space (struct MHD_Connection *c)
   3574 {
   3575   /**
   3576    * The increase of read buffer size is desirable.
   3577    */
   3578   bool rbuff_grow_desired;
   3579   /**
   3580    * The increase of read buffer size is a hard requirement.
   3581    */
   3582   bool rbuff_grow_required;
   3583 
   3584   mhd_assert (0 != (MHD_EVENT_LOOP_INFO_READ & c->event_loop_info));
   3585   mhd_assert (! c->discard_request);
   3586 
   3587   rbuff_grow_required = (c->read_buffer_offset == c->read_buffer_size);
   3588   if (rbuff_grow_required)
   3589     rbuff_grow_desired = true;
   3590   else
   3591   {
   3592     rbuff_grow_desired = (c->read_buffer_offset + c->daemon->pool_increment >
   3593                           c->read_buffer_size);
   3594 
   3595     if ((rbuff_grow_desired) &&
   3596         (MHD_CONNECTION_BODY_RECEIVING == c->state))
   3597     {
   3598       if (! c->rq.have_chunked_upload)
   3599       {
   3600         mhd_assert (MHD_SIZE_UNKNOWN != c->rq.remaining_upload_size);
   3601         /* Do not grow read buffer more than necessary to process the current
   3602            request. */
   3603         rbuff_grow_desired =
   3604           (c->rq.remaining_upload_size > c->read_buffer_size);
   3605       }
   3606       else
   3607       {
   3608         mhd_assert (MHD_SIZE_UNKNOWN == c->rq.remaining_upload_size);
   3609         if (0 == c->rq.current_chunk_size)
   3610           rbuff_grow_desired =  /* Reading value of the next chunk size */
   3611                                (MHD_CHUNK_HEADER_REASONABLE_LEN >
   3612                                 c->read_buffer_size);
   3613         else
   3614         {
   3615           const uint64_t cur_chunk_left =
   3616             c->rq.current_chunk_size - c->rq.current_chunk_offset;
   3617           /* Do not grow read buffer more than necessary to process the current
   3618              chunk with terminating CRLF. */
   3619           mhd_assert (c->rq.current_chunk_offset <= c->rq.current_chunk_size);
   3620           rbuff_grow_desired =
   3621             ((cur_chunk_left + 2) > (uint64_t) (c->read_buffer_size));
   3622         }
   3623       }
   3624     }
   3625   }
   3626 
   3627   if (! rbuff_grow_desired)
   3628     return true; /* No need to increase the buffer */
   3629 
   3630   if (try_grow_read_buffer (c, rbuff_grow_required))
   3631     return true; /* Buffer increase succeed */
   3632 
   3633   if (! rbuff_grow_required)
   3634     return true; /* Can continue without buffer increase */
   3635 
   3636   /* Failed to increase the read buffer size, but need to read the data
   3637      from the network.
   3638      No more space left in the buffer, no more space to increase the buffer. */
   3639 
   3640   /* 'PROCESS_READ' event state flag must be set only if the last application
   3641      callback has processed some data. If any data is processed then some
   3642      space in the read buffer must be available. */
   3643   mhd_assert (0 == (MHD_EVENT_LOOP_INFO_PROCESS & c->event_loop_info));
   3644 
   3645   if ((! MHD_D_IS_USING_THREADS_ (c->daemon))
   3646       && (MHD_CONNECTION_BODY_RECEIVING == c->state)
   3647       && has_unprocessed_upload_body_data_in_buffer (c))
   3648   {
   3649     /* The application is handling processing cycles.
   3650        The data could be processed later. */
   3651     c->event_loop_info = MHD_EVENT_LOOP_INFO_PROCESS;
   3652     return true;
   3653   }
   3654   else
   3655   {
   3656     enum MHD_ProcRecvDataStage stage;
   3657 
   3658     switch (c->state)
   3659     {
   3660     case MHD_CONNECTION_INIT:
   3661       stage = MHD_PROC_RECV_INIT;
   3662       break;
   3663     case MHD_CONNECTION_REQ_LINE_RECEIVING:
   3664       if (MHD_HTTP_MTHD_NO_METHOD == c->rq.http_mthd)
   3665         stage = MHD_PROC_RECV_METHOD;
   3666       else if (0 == c->rq.req_target_len)
   3667         stage = MHD_PROC_RECV_URI;
   3668       else
   3669         stage = MHD_PROC_RECV_HTTPVER;
   3670       break;
   3671     case MHD_CONNECTION_REQ_HEADERS_RECEIVING:
   3672       stage = MHD_PROC_RECV_HEADERS;
   3673       break;
   3674     case MHD_CONNECTION_BODY_RECEIVING:
   3675       stage = c->rq.have_chunked_upload ?
   3676               MHD_PROC_RECV_BODY_CHUNKED : MHD_PROC_RECV_BODY_NORMAL;
   3677       break;
   3678     case MHD_CONNECTION_FOOTERS_RECEIVING:
   3679       stage = MHD_PROC_RECV_FOOTERS;
   3680       break;
   3681     case MHD_CONNECTION_REQ_LINE_RECEIVED:
   3682     case MHD_CONNECTION_HEADERS_RECEIVED:
   3683     case MHD_CONNECTION_HEADERS_PROCESSED:
   3684     case MHD_CONNECTION_CONTINUE_SENDING:
   3685     case MHD_CONNECTION_BODY_RECEIVED:
   3686     case MHD_CONNECTION_FOOTERS_RECEIVED:
   3687     case MHD_CONNECTION_FULL_REQ_RECEIVED:
   3688     case MHD_CONNECTION_START_REPLY:
   3689     case MHD_CONNECTION_HEADERS_SENDING:
   3690     case MHD_CONNECTION_HEADERS_SENT:
   3691     case MHD_CONNECTION_NORMAL_BODY_UNREADY:
   3692     case MHD_CONNECTION_NORMAL_BODY_READY:
   3693     case MHD_CONNECTION_CHUNKED_BODY_UNREADY:
   3694     case MHD_CONNECTION_CHUNKED_BODY_READY:
   3695     case MHD_CONNECTION_CHUNKED_BODY_SENT:
   3696     case MHD_CONNECTION_FOOTERS_SENDING:
   3697     case MHD_CONNECTION_FULL_REPLY_SENT:
   3698     case MHD_CONNECTION_CLOSED:
   3699 #ifdef UPGRADE_SUPPORT
   3700     case MHD_CONNECTION_UPGRADE:
   3701 #endif
   3702     default:
   3703       stage = MHD_PROC_RECV_BODY_NORMAL;
   3704       mhd_assert (0);
   3705     }
   3706 
   3707     handle_recv_no_space (c, stage);
   3708   }
   3709   return false;
   3710 }
   3711 
   3712 
   3713 /**
   3714  * Update the 'event_loop_info' field of this connection based on the state
   3715  * that the connection is now in.  May also close the connection or
   3716  * perform other updates to the connection if needed to prepare for
   3717  * the next round of the event loop.
   3718  *
   3719  * @param connection connection to get poll set for
   3720  */
   3721 static void
   3722 MHD_connection_update_event_loop_info (struct MHD_Connection *connection)
   3723 {
   3724   /* Do not update states of suspended connection */
   3725   if (connection->suspended)
   3726     return; /* States will be updated after resume. */
   3727 #ifdef HTTPS_SUPPORT
   3728   if (MHD_TLS_CONN_NO_TLS != connection->tls_state)
   3729   {   /* HTTPS connection. */
   3730     switch (connection->tls_state)
   3731     {
   3732     case MHD_TLS_CONN_INIT:
   3733       connection->event_loop_info = MHD_EVENT_LOOP_INFO_READ;
   3734       return;
   3735     case MHD_TLS_CONN_HANDSHAKING:
   3736     case MHD_TLS_CONN_WR_CLOSING:
   3737       if (0 == gnutls_record_get_direction (connection->tls_session))
   3738         connection->event_loop_info = MHD_EVENT_LOOP_INFO_READ;
   3739       else
   3740         connection->event_loop_info = MHD_EVENT_LOOP_INFO_WRITE;
   3741       return;
   3742     case MHD_TLS_CONN_CONNECTED:
   3743       break; /* Do normal processing */
   3744     case MHD_TLS_CONN_WR_CLOSED:
   3745     case MHD_TLS_CONN_TLS_FAILED:
   3746       connection->event_loop_info = MHD_EVENT_LOOP_INFO_CLEANUP;
   3747       return;
   3748     case MHD_TLS_CONN_TLS_CLOSING:  /* Not implemented yet */
   3749     case MHD_TLS_CONN_TLS_CLOSED:   /* Not implemented yet */
   3750     case MHD_TLS_CONN_INVALID_STATE:
   3751     case MHD_TLS_CONN_NO_TLS: /* Not possible */
   3752     default:
   3753       MHD_PANIC (_ ("Invalid TLS state value.\n"));
   3754     }
   3755   }
   3756 #endif /* HTTPS_SUPPORT */
   3757   while (1)
   3758   {
   3759 #if DEBUG_STATES
   3760     MHD_DLOG (connection->daemon,
   3761               _ ("In function %s handling connection at state: %s\n"),
   3762               MHD_FUNC_,
   3763               MHD_state_to_string (connection->state));
   3764 #endif
   3765     switch (connection->state)
   3766     {
   3767     case MHD_CONNECTION_INIT:
   3768     case MHD_CONNECTION_REQ_LINE_RECEIVING:
   3769       connection->event_loop_info = MHD_EVENT_LOOP_INFO_READ;
   3770       break;
   3771     case MHD_CONNECTION_REQ_LINE_RECEIVED:
   3772       mhd_assert (0);
   3773       break;
   3774     case MHD_CONNECTION_REQ_HEADERS_RECEIVING:
   3775       connection->event_loop_info = MHD_EVENT_LOOP_INFO_READ;
   3776       break;
   3777     case MHD_CONNECTION_HEADERS_RECEIVED:
   3778     case MHD_CONNECTION_HEADERS_PROCESSED:
   3779       mhd_assert (0);
   3780       break;
   3781     case MHD_CONNECTION_CONTINUE_SENDING:
   3782       connection->event_loop_info = MHD_EVENT_LOOP_INFO_WRITE;
   3783       break;
   3784     case MHD_CONNECTION_BODY_RECEIVING:
   3785       if ((connection->rq.some_payload_processed) &&
   3786           has_unprocessed_upload_body_data_in_buffer (connection))
   3787       {
   3788         /* Some data was processed, the buffer must have some free space */
   3789         mhd_assert (connection->read_buffer_offset < \
   3790                     connection->read_buffer_size);
   3791         if (! connection->rq.have_chunked_upload)
   3792         {
   3793           /* Not a chunked upload. Do not read more than necessary to
   3794              process the current request. */
   3795           if (connection->rq.remaining_upload_size >=
   3796               connection->read_buffer_offset)
   3797             connection->event_loop_info = MHD_EVENT_LOOP_INFO_PROCESS;
   3798           else
   3799             connection->event_loop_info = MHD_EVENT_LOOP_INFO_PROCESS_READ;
   3800         }
   3801         else
   3802         {
   3803           /* Chunked upload. The size of the current request is unknown.
   3804              Continue reading as the space in the read buffer is available. */
   3805           connection->event_loop_info = MHD_EVENT_LOOP_INFO_PROCESS_READ;
   3806         }
   3807       }
   3808       else
   3809         connection->event_loop_info = MHD_EVENT_LOOP_INFO_READ;
   3810       break;
   3811     case MHD_CONNECTION_BODY_RECEIVED:
   3812       mhd_assert (0);
   3813       break;
   3814     case MHD_CONNECTION_FOOTERS_RECEIVING:
   3815       connection->event_loop_info = MHD_EVENT_LOOP_INFO_READ;
   3816       break;
   3817     case MHD_CONNECTION_FOOTERS_RECEIVED:
   3818       mhd_assert (0);
   3819       break;
   3820     case MHD_CONNECTION_FULL_REQ_RECEIVED:
   3821       connection->event_loop_info = MHD_EVENT_LOOP_INFO_PROCESS;
   3822       break;
   3823     case MHD_CONNECTION_START_REPLY:
   3824       mhd_assert (0);
   3825       break;
   3826     case MHD_CONNECTION_HEADERS_SENDING:
   3827       /* headers in buffer, keep writing */
   3828       connection->event_loop_info = MHD_EVENT_LOOP_INFO_WRITE;
   3829       break;
   3830     case MHD_CONNECTION_HEADERS_SENT:
   3831       mhd_assert (0);
   3832       break;
   3833     case MHD_CONNECTION_NORMAL_BODY_UNREADY:
   3834       connection->event_loop_info = MHD_EVENT_LOOP_INFO_PROCESS;
   3835       break;
   3836     case MHD_CONNECTION_NORMAL_BODY_READY:
   3837       connection->event_loop_info = MHD_EVENT_LOOP_INFO_WRITE;
   3838       break;
   3839     case MHD_CONNECTION_CHUNKED_BODY_UNREADY:
   3840       connection->event_loop_info = MHD_EVENT_LOOP_INFO_PROCESS;
   3841       break;
   3842     case MHD_CONNECTION_CHUNKED_BODY_READY:
   3843       connection->event_loop_info = MHD_EVENT_LOOP_INFO_WRITE;
   3844       break;
   3845     case MHD_CONNECTION_CHUNKED_BODY_SENT:
   3846       mhd_assert (0);
   3847       break;
   3848     case MHD_CONNECTION_FOOTERS_SENDING:
   3849       connection->event_loop_info = MHD_EVENT_LOOP_INFO_WRITE;
   3850       break;
   3851     case MHD_CONNECTION_FULL_REPLY_SENT:
   3852       mhd_assert (0);
   3853       break;
   3854     case MHD_CONNECTION_CLOSED:
   3855       connection->event_loop_info = MHD_EVENT_LOOP_INFO_CLEANUP;
   3856       return;           /* do nothing, not even reading */
   3857 #ifdef UPGRADE_SUPPORT
   3858     case MHD_CONNECTION_UPGRADE:
   3859       mhd_assert (0);
   3860       break;
   3861 #endif /* UPGRADE_SUPPORT */
   3862     default:
   3863       mhd_assert (0);
   3864     }
   3865 
   3866     if (0 != (MHD_EVENT_LOOP_INFO_READ & connection->event_loop_info))
   3867     {
   3868       /* Check whether the space is available to receive data */
   3869       if (! check_and_grow_read_buffer_space (connection))
   3870       {
   3871         mhd_assert (connection->discard_request);
   3872         continue;
   3873       }
   3874     }
   3875     break; /* Everything was processed. */
   3876   }
   3877 }
   3878 
   3879 
   3880 /**
   3881  * Add an entry to the HTTP headers of a connection.  If this fails,
   3882  * transmit an error response (request too big).
   3883  *
   3884  * @param cls the context (connection)
   3885  * @param kind kind of the value
   3886  * @param key key for the value
   3887  * @param key_size number of bytes in @a key
   3888  * @param value the value itself
   3889  * @param value_size number of bytes in @a value
   3890  * @return #MHD_NO on failure (out of memory), #MHD_YES for success
   3891  */
   3892 static enum MHD_Result
   3893 connection_add_header (void *cls,
   3894                        const char *key,
   3895                        size_t key_size,
   3896                        const char *value,
   3897                        size_t value_size,
   3898                        enum MHD_ValueKind kind)
   3899 {
   3900   struct MHD_Connection *connection = (struct MHD_Connection *) cls;
   3901   if (MHD_NO ==
   3902       MHD_set_connection_value_n (connection,
   3903                                   kind,
   3904                                   key,
   3905                                   key_size,
   3906                                   value,
   3907                                   value_size))
   3908   {
   3909 #ifdef HAVE_MESSAGES
   3910     MHD_DLOG (connection->daemon,
   3911               _ ("Not enough memory in pool to allocate header record!\n"));
   3912 #endif
   3913     transmit_error_response_static (connection,
   3914                                     MHD_HTTP_REQUEST_HEADER_FIELDS_TOO_LARGE,
   3915                                     ERR_MSG_REQUEST_TOO_BIG);
   3916     return MHD_NO;
   3917   }
   3918   return MHD_YES;
   3919 }
   3920 
   3921 
   3922 #ifdef COOKIE_SUPPORT
   3923 
   3924 /**
   3925  * Cookie parsing result
   3926  */
   3927 enum _MHD_ParseCookie
   3928 {
   3929   MHD_PARSE_COOKIE_OK = MHD_YES,      /**< Success or no cookies in headers */
   3930   MHD_PARSE_COOKIE_OK_LAX = 2,        /**< Cookies parsed, but workarounds used */
   3931   MHD_PARSE_COOKIE_MALFORMED = -1,    /**< Invalid cookie header */
   3932   MHD_PARSE_COOKIE_NO_MEMORY = MHD_NO /**< Not enough memory in the pool */
   3933 };
   3934 
   3935 
   3936 /**
   3937  * Parse the cookies string (see RFC 6265).
   3938  *
   3939  * Try to parse the cookies string even if it is not strictly formed
   3940  * as specified by RFC 6265.
   3941  *
   3942  * @param str the string to parse, without leading whitespaces
   3943  * @param str_len the size of the @a str, not including mandatory
   3944  *                zero-termination
   3945  * @param connection the connection to add parsed cookies
   3946  * @return #MHD_PARSE_COOKIE_OK for success, error code otherwise
   3947  */
   3948 static enum _MHD_ParseCookie
   3949 parse_cookies_string (char *str,
   3950                       const size_t str_len,
   3951                       struct MHD_Connection *connection)
   3952 {
   3953   size_t i;
   3954   bool non_strict;
   3955   /* Skip extra whitespaces and empty cookies */
   3956   const bool allow_wsp_empty = (0 >= connection->daemon->client_discipline);
   3957   /* Allow whitespaces around '=' character */
   3958   const bool wsp_around_eq = (-3 >= connection->daemon->client_discipline);
   3959   /* Allow whitespaces in quoted cookie value */
   3960   const bool wsp_in_quoted = (-2 >= connection->daemon->client_discipline);
   3961   /* Allow tab as space after semicolon between cookies */
   3962   const bool tab_as_sp = (0 >= connection->daemon->client_discipline);
   3963   /* Allow no space after semicolon between cookies */
   3964   const bool allow_no_space = (0 >= connection->daemon->client_discipline);
   3965 
   3966   non_strict = false;
   3967   i = 0;
   3968   while (i < str_len)
   3969   {
   3970     size_t name_start;
   3971     size_t name_len;
   3972     size_t value_start;
   3973     size_t value_len;
   3974     bool val_quoted;
   3975     /* Skip any whitespaces and empty cookies */
   3976     while (' ' == str[i] || '\t' == str[i] || ';' == str[i])
   3977     {
   3978       if (! allow_wsp_empty)
   3979         return MHD_PARSE_COOKIE_MALFORMED;
   3980       non_strict = true;
   3981       i++;
   3982       if (i == str_len)
   3983         return non_strict? MHD_PARSE_COOKIE_OK_LAX : MHD_PARSE_COOKIE_OK;
   3984     }
   3985     /* 'i' must point to the first char of cookie-name */
   3986     name_start = i;
   3987     /* Find the end of the cookie-name */
   3988     do
   3989     {
   3990       const char l = str[i];
   3991       if (('=' == l) || (' ' == l) || ('\t' == l) || ('"' == l) || (',' == l) ||
   3992           (';' == l) || (0 == l))
   3993         break;
   3994     } while (str_len > ++i);
   3995     name_len = i - name_start;
   3996     /* Skip any whitespaces */
   3997     while (str_len > i && (' ' == str[i] || '\t' == str[i]))
   3998     {
   3999       if (! wsp_around_eq)
   4000         return MHD_PARSE_COOKIE_MALFORMED;
   4001       non_strict = true;
   4002       i++;
   4003     }
   4004     if ((str_len == i) || ('=' != str[i]) || (0 == name_len))
   4005       return MHD_PARSE_COOKIE_MALFORMED; /* Incomplete cookie name */
   4006     /* 'i' must point to the '=' char */
   4007     mhd_assert ('=' == str[i]);
   4008     i++;
   4009     /* Skip any whitespaces */
   4010     while (str_len > i && (' ' == str[i] || '\t' == str[i]))
   4011     {
   4012       if (! wsp_around_eq)
   4013         return MHD_PARSE_COOKIE_MALFORMED;
   4014       non_strict = true;
   4015       i++;
   4016     }
   4017     /* 'i' must point to the first char of cookie-value */
   4018     if (str_len == i)
   4019     {
   4020       value_start = 0;
   4021       value_len = 0;
   4022 #ifdef _DEBUG
   4023       val_quoted = false; /* This assignment used in assert */
   4024 #endif
   4025     }
   4026     else
   4027     {
   4028       bool valid_cookie;
   4029       val_quoted = ('"' == str[i]);
   4030       if (val_quoted)
   4031         i++;
   4032       value_start = i;
   4033       /* Find the end of the cookie-value */
   4034       while (str_len > i)
   4035       {
   4036         const char l = str[i];
   4037         if ((';' == l) || ('"' == l) || (',' == l) || (';' == l) ||
   4038             ('\\' == l) || (0 == l))
   4039           break;
   4040         if ((' ' == l) || ('\t' == l))
   4041         {
   4042           if (! val_quoted)
   4043             break;
   4044           if (! wsp_in_quoted)
   4045             return MHD_PARSE_COOKIE_MALFORMED;
   4046           non_strict = true;
   4047         }
   4048         i++;
   4049       }
   4050       value_len = i - value_start;
   4051       if (val_quoted)
   4052       {
   4053         if ((str_len == i) || ('"' != str[i]))
   4054           return MHD_PARSE_COOKIE_MALFORMED; /* Incomplete cookie value, no closing quote */
   4055         i++;
   4056       }
   4057       /* Skip any whitespaces */
   4058       if ((str_len > i) && ((' ' == str[i]) || ('\t' == str[i])))
   4059       {
   4060         do
   4061         {
   4062           i++;
   4063         } while (str_len > i && (' ' == str[i] || '\t' == str[i]));
   4064         /* Whitespace at the end? */
   4065         if (str_len > i)
   4066         {
   4067           if (! allow_wsp_empty)
   4068             return MHD_PARSE_COOKIE_MALFORMED;
   4069           non_strict = true;
   4070         }
   4071       }
   4072       if (str_len == i)
   4073         valid_cookie = true;
   4074       else if (';' == str[i])
   4075         valid_cookie = true;
   4076       else
   4077         valid_cookie = false;
   4078 
   4079       if (! valid_cookie)
   4080         return MHD_PARSE_COOKIE_MALFORMED; /* Garbage at the end of the cookie value */
   4081     }
   4082     mhd_assert (0 != name_len);
   4083     str[name_start + name_len] = 0; /* Zero-terminate the name */
   4084     if (0 != value_len)
   4085     {
   4086       mhd_assert (value_start + value_len <= str_len);
   4087       str[value_start + value_len] = 0; /* Zero-terminate the value */
   4088       if (MHD_NO ==
   4089           MHD_set_connection_value_n_nocheck_ (connection,
   4090                                                MHD_COOKIE_KIND,
   4091                                                str + name_start,
   4092                                                name_len,
   4093                                                str + value_start,
   4094                                                value_len))
   4095         return MHD_PARSE_COOKIE_NO_MEMORY;
   4096     }
   4097     else
   4098     {
   4099       if (MHD_NO ==
   4100           MHD_set_connection_value_n_nocheck_ (connection,
   4101                                                MHD_COOKIE_KIND,
   4102                                                str + name_start,
   4103                                                name_len,
   4104                                                "",
   4105                                                0))
   4106         return MHD_PARSE_COOKIE_NO_MEMORY;
   4107     }
   4108     if (str_len > i)
   4109     {
   4110       mhd_assert (0 == str[i] || ';' == str[i]);
   4111       mhd_assert (! val_quoted || ';' == str[i]);
   4112       mhd_assert (';' != str[i] || val_quoted || non_strict || 0 == value_len);
   4113       i++;
   4114       if (str_len == i)
   4115       { /* No next cookie after semicolon */
   4116         if (! allow_wsp_empty)
   4117           return MHD_PARSE_COOKIE_MALFORMED;
   4118         non_strict = true;
   4119       }
   4120       else if (' ' != str[i])
   4121       {/* No space after semicolon */
   4122         if (('\t' == str[i]) && tab_as_sp)
   4123           i++;
   4124         else if (! allow_no_space)
   4125           return MHD_PARSE_COOKIE_MALFORMED;
   4126         non_strict = true;
   4127       }
   4128       else
   4129       {
   4130         i++;
   4131         if (str_len == i)
   4132         {
   4133           if (! allow_wsp_empty)
   4134             return MHD_PARSE_COOKIE_MALFORMED;
   4135           non_strict = true;
   4136         }
   4137       }
   4138     }
   4139   }
   4140   return non_strict? MHD_PARSE_COOKIE_OK_LAX : MHD_PARSE_COOKIE_OK;
   4141 }
   4142 
   4143 
   4144 /**
   4145  * Parse the cookie header (see RFC 6265).
   4146  *
   4147  * @param connection connection to parse header of
   4148  * @return #MHD_PARSE_COOKIE_OK for success, error code otherwise
   4149  */
   4150 static enum _MHD_ParseCookie
   4151 parse_cookie_header (struct MHD_Connection *connection)
   4152 {
   4153   const char *hdr;
   4154   size_t hdr_len;
   4155   char *cpy;
   4156   size_t i;
   4157   enum _MHD_ParseCookie parse_res;
   4158   struct MHD_HTTP_Req_Header *const saved_tail =
   4159     connection->rq.headers_received_tail;
   4160   const bool allow_partially_correct_cookie =
   4161     (1 >= connection->daemon->client_discipline);
   4162 
   4163   if (MHD_NO ==
   4164       MHD_lookup_connection_value_n (connection,
   4165                                      MHD_HEADER_KIND,
   4166                                      MHD_HTTP_HEADER_COOKIE,
   4167                                      MHD_STATICSTR_LEN_ (
   4168                                        MHD_HTTP_HEADER_COOKIE),
   4169                                      &hdr,
   4170                                      &hdr_len))
   4171     return MHD_PARSE_COOKIE_OK;
   4172   if (0 == hdr_len)
   4173     return MHD_PARSE_COOKIE_OK;
   4174 
   4175   cpy = MHD_connection_alloc_memory_ (connection,
   4176                                       hdr_len + 1);
   4177   if (NULL == cpy)
   4178     parse_res = MHD_PARSE_COOKIE_NO_MEMORY;
   4179   else
   4180   {
   4181     memcpy (cpy,
   4182             hdr,
   4183             hdr_len);
   4184     cpy[hdr_len] = '\0';
   4185 
   4186     i = 0;
   4187     /* Skip all initial whitespaces */
   4188     while (i < hdr_len && (' ' == cpy[i] || '\t' == cpy[i]))
   4189       i++;
   4190 
   4191     parse_res = parse_cookies_string (cpy + i, hdr_len - i, connection);
   4192   }
   4193 
   4194   switch (parse_res)
   4195   {
   4196   case MHD_PARSE_COOKIE_OK:
   4197     break;
   4198   case MHD_PARSE_COOKIE_OK_LAX:
   4199 #ifdef HAVE_MESSAGES
   4200     if (saved_tail != connection->rq.headers_received_tail)
   4201       MHD_DLOG (connection->daemon,
   4202                 _ ("The Cookie header has been parsed, but it is not fully "
   4203                    "compliant with the standard.\n"));
   4204 #endif /* HAVE_MESSAGES */
   4205     break;
   4206   case MHD_PARSE_COOKIE_MALFORMED:
   4207     if (saved_tail != connection->rq.headers_received_tail)
   4208     {
   4209       if (! allow_partially_correct_cookie)
   4210       {
   4211         /* Remove extracted values from partially broken cookie */
   4212         /* Memory remains allocated until the end of the request processing */
   4213         connection->rq.headers_received_tail = saved_tail;
   4214         saved_tail->next = NULL;
   4215 #ifdef HAVE_MESSAGES
   4216         MHD_DLOG (connection->daemon,
   4217                   _ ("The Cookie header has been ignored as it contains "
   4218                      "malformed data.\n"));
   4219 #endif /* HAVE_MESSAGES */
   4220       }
   4221 #ifdef HAVE_MESSAGES
   4222       else
   4223         MHD_DLOG (connection->daemon,
   4224                   _ ("The Cookie header has been only partially parsed as it "
   4225                      "contains malformed data.\n"));
   4226 #endif /* HAVE_MESSAGES */
   4227     }
   4228 #ifdef HAVE_MESSAGES
   4229     else
   4230       MHD_DLOG (connection->daemon,
   4231                 _ ("The Cookie header has malformed data.\n"));
   4232 #endif /* HAVE_MESSAGES */
   4233     break;
   4234   case MHD_PARSE_COOKIE_NO_MEMORY:
   4235 #ifdef HAVE_MESSAGES
   4236     MHD_DLOG (connection->daemon,
   4237               _ ("Not enough memory in the connection pool to "
   4238                  "parse client cookies!\n"));
   4239 #endif /* HAVE_MESSAGES */
   4240     break;
   4241   default:
   4242     mhd_assert (0);
   4243     break;
   4244   }
   4245 #ifndef HAVE_MESSAGES
   4246   (void) saved_tail; /* Mute compiler warning */
   4247 #endif /* ! HAVE_MESSAGES */
   4248 
   4249   return parse_res;
   4250 }
   4251 
   4252 
   4253 #endif /* COOKIE_SUPPORT */
   4254 
   4255 
   4256 /**
   4257  * The valid length of any HTTP version string
   4258  */
   4259 #define HTTP_VER_LEN (MHD_STATICSTR_LEN_ (MHD_HTTP_VERSION_1_1))
   4260 
   4261 /**
   4262  * Detect HTTP version, send error response if version is not supported
   4263  *
   4264  * @param connection the connection
   4265  * @param http_string the pointer to HTTP version string
   4266  * @param len the length of @a http_string in bytes
   4267  * @return true if HTTP version is correct and supported,
   4268  *         false if HTTP version is not correct or unsupported.
   4269  */
   4270 static bool
   4271 parse_http_version (struct MHD_Connection *connection,
   4272                     const char *http_string,
   4273                     size_t len)
   4274 {
   4275   const char *const h = http_string; /**< short alias */
   4276   mhd_assert (NULL != http_string);
   4277 
   4278   /* String must start with 'HTTP/d.d', case-sensetive match.
   4279    * See https://www.rfc-editor.org/rfc/rfc9112#name-http-version */
   4280   if ((HTTP_VER_LEN != len) ||
   4281       ('H' != h[0]) || ('T' != h[1]) || ('T' != h[2]) || ('P' != h[3]) ||
   4282       ('/' != h[4])
   4283       || ('.' != h[6]) ||
   4284       (('0' > h[5]) || ('9' < h[5])) ||
   4285       (('0' > h[7]) || ('9' < h[7])))
   4286   {
   4287     connection->rq.http_ver = MHD_HTTP_VER_INVALID;
   4288     transmit_error_response_static (connection,
   4289                                     MHD_HTTP_BAD_REQUEST,
   4290                                     REQUEST_MALFORMED);
   4291     return false;
   4292   }
   4293   if (1 == h[5] - '0')
   4294   {
   4295     /* HTTP/1.x */
   4296     if (1 == h[7] - '0')
   4297       connection->rq.http_ver = MHD_HTTP_VER_1_1;
   4298     else if (0 == h[7] - '0')
   4299       connection->rq.http_ver = MHD_HTTP_VER_1_0;
   4300     else
   4301       connection->rq.http_ver = MHD_HTTP_VER_1_2__1_9;
   4302 
   4303     return true;
   4304   }
   4305 
   4306   if (0 == h[5] - '0')
   4307   {
   4308     /* Too old major version */
   4309     connection->rq.http_ver = MHD_HTTP_VER_TOO_OLD;
   4310     transmit_error_response_static (connection,
   4311                                     MHD_HTTP_HTTP_VERSION_NOT_SUPPORTED,
   4312                                     REQ_HTTP_VER_IS_TOO_OLD);
   4313     return false;
   4314   }
   4315 
   4316   connection->rq.http_ver = MHD_HTTP_VER_FUTURE;
   4317   transmit_error_response_static (connection,
   4318                                   MHD_HTTP_HTTP_VERSION_NOT_SUPPORTED,
   4319                                   REQ_HTTP_VER_IS_NOT_SUPPORTED);
   4320   return false;
   4321 }
   4322 
   4323 
   4324 /**
   4325  * Detect standard HTTP request method
   4326  *
   4327  * @param connection the connection
   4328  * @param method the pointer to HTTP request method string
   4329  * @param len the length of @a method in bytes
   4330  */
   4331 static void
   4332 parse_http_std_method (struct MHD_Connection *connection,
   4333                        const char *method,
   4334                        size_t len)
   4335 {
   4336   const char *const m = method; /**< short alias */
   4337   mhd_assert (NULL != m);
   4338   mhd_assert (0 != len);
   4339 
   4340   if ((MHD_STATICSTR_LEN_ (MHD_HTTP_METHOD_GET) == len) &&
   4341       (0 == memcmp (m, MHD_HTTP_METHOD_GET, len)))
   4342     connection->rq.http_mthd = MHD_HTTP_MTHD_GET;
   4343   else if ((MHD_STATICSTR_LEN_ (MHD_HTTP_METHOD_HEAD) == len) &&
   4344            (0 == memcmp (m, MHD_HTTP_METHOD_HEAD, len)))
   4345     connection->rq.http_mthd = MHD_HTTP_MTHD_HEAD;
   4346   else if ((MHD_STATICSTR_LEN_ (MHD_HTTP_METHOD_POST) == len) &&
   4347            (0 == memcmp (m, MHD_HTTP_METHOD_POST, len)))
   4348     connection->rq.http_mthd = MHD_HTTP_MTHD_POST;
   4349   else if ((MHD_STATICSTR_LEN_ (MHD_HTTP_METHOD_PUT) == len) &&
   4350            (0 == memcmp (m, MHD_HTTP_METHOD_PUT, len)))
   4351     connection->rq.http_mthd = MHD_HTTP_MTHD_PUT;
   4352   else if ((MHD_STATICSTR_LEN_ (MHD_HTTP_METHOD_DELETE) == len) &&
   4353            (0 == memcmp (m, MHD_HTTP_METHOD_DELETE, len)))
   4354     connection->rq.http_mthd = MHD_HTTP_MTHD_DELETE;
   4355   else if ((MHD_STATICSTR_LEN_ (MHD_HTTP_METHOD_CONNECT) == len) &&
   4356            (0 == memcmp (m, MHD_HTTP_METHOD_CONNECT, len)))
   4357     connection->rq.http_mthd = MHD_HTTP_MTHD_CONNECT;
   4358   else if ((MHD_STATICSTR_LEN_ (MHD_HTTP_METHOD_OPTIONS) == len) &&
   4359            (0 == memcmp (m, MHD_HTTP_METHOD_OPTIONS, len)))
   4360     connection->rq.http_mthd = MHD_HTTP_MTHD_OPTIONS;
   4361   else if ((MHD_STATICSTR_LEN_ (MHD_HTTP_METHOD_TRACE) == len) &&
   4362            (0 == memcmp (m, MHD_HTTP_METHOD_TRACE, len)))
   4363     connection->rq.http_mthd = MHD_HTTP_MTHD_TRACE;
   4364   else
   4365     connection->rq.http_mthd = MHD_HTTP_MTHD_OTHER;
   4366 }
   4367 
   4368 
   4369 /**
   4370  * Call the handler of the application for this
   4371  * connection.  Handles chunking of the upload
   4372  * as well as normal uploads.
   4373  *
   4374  * @param connection connection we're processing
   4375  */
   4376 static void
   4377 call_connection_handler (struct MHD_Connection *connection)
   4378 {
   4379   struct MHD_Daemon *daemon = connection->daemon;
   4380   size_t processed;
   4381 
   4382   if (NULL != connection->rp.response)
   4383     return;                     /* already queued a response */
   4384   processed = 0;
   4385   connection->rq.client_aware = true;
   4386   connection->in_access_handler = true;
   4387   if (MHD_NO ==
   4388       daemon->default_handler (daemon->default_handler_cls,
   4389                                connection,
   4390                                connection->rq.url,
   4391                                connection->rq.method,
   4392                                connection->rq.version,
   4393                                NULL,
   4394                                &processed,
   4395                                &connection->rq.client_context))
   4396   {
   4397     connection->in_access_handler = false;
   4398     /* serious internal error, close connection */
   4399     CONNECTION_CLOSE_ERROR (connection,
   4400                             _ ("Application reported internal error, " \
   4401                                "closing connection."));
   4402     return;
   4403   }
   4404   connection->in_access_handler = false;
   4405 }
   4406 
   4407 
   4408 /**
   4409  * Call the handler of the application for this
   4410  * connection.  Handles chunking of the upload
   4411  * as well as normal uploads.
   4412  *
   4413  * @param connection connection we're processing
   4414  */
   4415 static void
   4416 process_request_body (struct MHD_Connection *connection)
   4417 {
   4418   struct MHD_Daemon *daemon = connection->daemon;
   4419   size_t available;
   4420   bool instant_retry;
   4421   char *buffer_head;
   4422   const int discp_lvl = daemon->client_discipline;
   4423   /* Treat bare LF as the end of the line.
   4424      RFC 9112, section 2.2-3
   4425      Note: MHD never replaces bare LF with space (RFC 9110, section 5.5-5).
   4426      Bare LF is processed as end of the line or rejected as broken request. */
   4427   const bool bare_lf_as_crlf = MHD_ALLOW_BARE_LF_AS_CRLF_ (discp_lvl);
   4428   /* Allow "Bad WhiteSpace" in chunk extension.
   4429      RFC 9112, Section 7.1.1, Paragraph 2 */
   4430   const bool allow_bws = (2 < discp_lvl);
   4431 
   4432   mhd_assert (NULL == connection->rp.response);
   4433 
   4434   buffer_head = connection->read_buffer;
   4435   available = connection->read_buffer_offset;
   4436   do
   4437   {
   4438     size_t to_be_processed;
   4439     size_t left_unprocessed;
   4440     size_t processed_size;
   4441 
   4442     instant_retry = false;
   4443     if (connection->rq.have_chunked_upload)
   4444     {
   4445       mhd_assert (MHD_SIZE_UNKNOWN == connection->rq.remaining_upload_size);
   4446       if ( (connection->rq.current_chunk_offset ==
   4447             connection->rq.current_chunk_size) &&
   4448            (0 != connection->rq.current_chunk_size) )
   4449       {
   4450         size_t i;
   4451         mhd_assert (0 != available);
   4452         /* skip new line at the *end* of a chunk */
   4453         i = 0;
   4454         if ( (2 <= available) &&
   4455              ('\r' == buffer_head[0]) &&
   4456              ('\n' == buffer_head[1]) )
   4457           i += 2;                        /* skip CRLF */
   4458         else if (bare_lf_as_crlf && ('\n' == buffer_head[0]))
   4459           i++;                           /* skip bare LF */
   4460         else if (2 > available)
   4461           break;                         /* need more upload data */
   4462         if (0 == i)
   4463         {
   4464           /* malformed encoding */
   4465           transmit_error_response_static (connection,
   4466                                           MHD_HTTP_BAD_REQUEST,
   4467                                           REQUEST_CHUNKED_MALFORMED);
   4468           return;
   4469         }
   4470         available -= i;
   4471         buffer_head += i;
   4472         connection->rq.current_chunk_offset = 0;
   4473         connection->rq.current_chunk_size = 0;
   4474         if (0 == available)
   4475           break;
   4476       }
   4477       if (0 != connection->rq.current_chunk_size)
   4478       {
   4479         uint64_t cur_chunk_left;
   4480         mhd_assert (connection->rq.current_chunk_offset < \
   4481                     connection->rq.current_chunk_size);
   4482         /* we are in the middle of a chunk, give
   4483            as much as possible to the client (without
   4484            crossing chunk boundaries) */
   4485         cur_chunk_left
   4486           = connection->rq.current_chunk_size
   4487             - connection->rq.current_chunk_offset;
   4488         if (cur_chunk_left > available)
   4489           to_be_processed = available;
   4490         else
   4491         {         /* cur_chunk_left <= (size_t)available */
   4492           to_be_processed = (size_t) cur_chunk_left;
   4493           if (available > to_be_processed)
   4494             instant_retry = true;
   4495         }
   4496       }
   4497       else
   4498       { /* Need the parse the chunk size line */
   4499         /** The number of found digits in the chunk size number */
   4500         size_t num_dig;
   4501         uint64_t chunk_size;
   4502         bool broken;
   4503         bool overflow;
   4504 
   4505         mhd_assert (0 != available);
   4506 
   4507         overflow = false;
   4508         chunk_size = 0; /* Mute possible compiler warning.
   4509                            The real value will be set later. */
   4510 
   4511         num_dig = MHD_strx_to_uint64_n_ (buffer_head,
   4512                                          available,
   4513                                          &chunk_size);
   4514         mhd_assert (num_dig <= available);
   4515         if (num_dig == available)
   4516           continue; /* Need line delimiter */
   4517 
   4518         broken = (0 == num_dig);
   4519         if (broken)
   4520           /* Check whether result is invalid due to uint64_t overflow */
   4521           overflow = ((('0' <= buffer_head[0]) && ('9' >= buffer_head[0])) ||
   4522                       (('A' <= buffer_head[0]) && ('F' >= buffer_head[0])) ||
   4523                       (('a' <= buffer_head[0]) && ('f' >= buffer_head[0])));
   4524         else
   4525         {
   4526           /**
   4527            * The length of the string with the number of the chunk size,
   4528            * including chunk extension
   4529            */
   4530           size_t chunk_size_line_len;
   4531 
   4532           chunk_size_line_len = 0;
   4533           if ((';' == buffer_head[num_dig]) ||
   4534               (allow_bws &&
   4535                ((' ' == buffer_head[num_dig]) ||
   4536                 ('\t' == buffer_head[num_dig]))))
   4537           { /* Chunk extension */
   4538             size_t i;
   4539 
   4540             /* Skip bad whitespaces (if any) */
   4541             for (i = num_dig; i < available; ++i)
   4542             {
   4543               if ((' ' != buffer_head[i]) && ('\t' != buffer_head[i]))
   4544                 break;
   4545             }
   4546             if (i == available)
   4547               break; /* need more data */
   4548             if (';' == buffer_head[i])
   4549             {
   4550               for (++i; i < available; ++i)
   4551               {
   4552                 if ('\n' == buffer_head[i])
   4553                   break;
   4554               }
   4555               if (i == available)
   4556                 break; /* need more data */
   4557               mhd_assert (i > num_dig);
   4558               mhd_assert (1 <= i);
   4559               /* Found LF position */
   4560               if (bare_lf_as_crlf)
   4561                 chunk_size_line_len = i; /* Don't care about CR before LF */
   4562               else if ('\r' == buffer_head[i - 1])
   4563                 chunk_size_line_len = i;
   4564             }
   4565             else
   4566             { /* No ';' after "bad whitespace" */
   4567               mhd_assert (allow_bws);
   4568               mhd_assert (0 == chunk_size_line_len);
   4569             }
   4570           }
   4571           else
   4572           {
   4573             mhd_assert (available >= num_dig);
   4574             if ((2 <= (available - num_dig)) &&
   4575                 ('\r' == buffer_head[num_dig]) &&
   4576                 ('\n' == buffer_head[num_dig + 1]))
   4577               chunk_size_line_len = num_dig + 2;
   4578             else if (bare_lf_as_crlf &&
   4579                      ('\n' == buffer_head[num_dig]))
   4580               chunk_size_line_len = num_dig + 1;
   4581             else if (2 > (available - num_dig))
   4582               break; /* need more data */
   4583           }
   4584 
   4585           if (0 != chunk_size_line_len)
   4586           { /* Valid termination of the chunk size line */
   4587             mhd_assert (chunk_size_line_len <= available);
   4588             /* Start reading payload data of the chunk */
   4589             connection->rq.current_chunk_offset = 0;
   4590             connection->rq.current_chunk_size = chunk_size;
   4591 
   4592             available -= chunk_size_line_len;
   4593             buffer_head += chunk_size_line_len;
   4594 
   4595             if (0 == chunk_size)
   4596             { /* The final (termination) chunk */
   4597               connection->rq.remaining_upload_size = 0;
   4598               break;
   4599             }
   4600             if (available > 0)
   4601               instant_retry = true;
   4602             continue;
   4603           }
   4604           /* Invalid chunk size line */
   4605         }
   4606 
   4607         if (! overflow)
   4608           transmit_error_response_static (connection,
   4609                                           MHD_HTTP_BAD_REQUEST,
   4610                                           REQUEST_CHUNKED_MALFORMED);
   4611         else
   4612           transmit_error_response_static (connection,
   4613                                           MHD_HTTP_CONTENT_TOO_LARGE,
   4614                                           REQUEST_CHUNK_TOO_LARGE);
   4615         return;
   4616       }
   4617     }
   4618     else
   4619     {
   4620       /* no chunked encoding, give all to the client */
   4621       mhd_assert (MHD_SIZE_UNKNOWN != connection->rq.remaining_upload_size);
   4622       mhd_assert (0 != connection->rq.remaining_upload_size);
   4623       if (connection->rq.remaining_upload_size < available)
   4624         to_be_processed = (size_t) connection->rq.remaining_upload_size;
   4625       else
   4626         to_be_processed = available;
   4627     }
   4628     left_unprocessed = to_be_processed;
   4629     connection->rq.client_aware = true;
   4630     connection->in_access_handler = true;
   4631     if (MHD_NO ==
   4632         daemon->default_handler (daemon->default_handler_cls,
   4633                                  connection,
   4634                                  connection->rq.url,
   4635                                  connection->rq.method,
   4636                                  connection->rq.version,
   4637                                  buffer_head,
   4638                                  &left_unprocessed,
   4639                                  &connection->rq.client_context))
   4640     {
   4641       connection->in_access_handler = false;
   4642       /* serious internal error, close connection */
   4643       CONNECTION_CLOSE_ERROR (connection,
   4644                               _ ("Application reported internal error, " \
   4645                                  "closing connection."));
   4646       return;
   4647     }
   4648     connection->in_access_handler = false;
   4649 
   4650     if (left_unprocessed > to_be_processed)
   4651       MHD_PANIC (_ ("libmicrohttpd API violation.\n"));
   4652 
   4653     connection->rq.some_payload_processed =
   4654       (left_unprocessed != to_be_processed);
   4655 
   4656     if (0 != left_unprocessed)
   4657     {
   4658       instant_retry = false; /* client did not process everything */
   4659 #ifdef HAVE_MESSAGES
   4660       if ((! connection->rq.some_payload_processed) &&
   4661           (! connection->suspended))
   4662       {
   4663         /* client did not process any upload data, complain if
   4664            the setup was incorrect, which may prevent us from
   4665            handling the rest of the request */
   4666         if (MHD_D_IS_USING_THREADS_ (daemon))
   4667           MHD_DLOG (daemon,
   4668                     _ ("WARNING: Access Handler Callback has not processed " \
   4669                        "any upload data and connection is not suspended. " \
   4670                        "This may result in hung connection.\n"));
   4671       }
   4672 #endif /* HAVE_MESSAGES */
   4673     }
   4674     processed_size = to_be_processed - left_unprocessed;
   4675     /* dh left "processed" bytes in buffer for next time... */
   4676     buffer_head += processed_size;
   4677     available -= processed_size;
   4678     if (! connection->rq.have_chunked_upload)
   4679     {
   4680       mhd_assert (MHD_SIZE_UNKNOWN != connection->rq.remaining_upload_size);
   4681       connection->rq.remaining_upload_size -= processed_size;
   4682     }
   4683     else
   4684     {
   4685       mhd_assert (MHD_SIZE_UNKNOWN == connection->rq.remaining_upload_size);
   4686       connection->rq.current_chunk_offset += processed_size;
   4687     }
   4688   } while (instant_retry);
   4689   /* TODO: zero out reused memory region */
   4690   if ( (available > 0) &&
   4691        (buffer_head != connection->read_buffer) )
   4692     memmove (connection->read_buffer,
   4693              buffer_head,
   4694              available);
   4695   else
   4696     mhd_assert ((0 == available) || \
   4697                 (connection->read_buffer_offset == available));
   4698   connection->read_buffer_offset = available;
   4699 }
   4700 
   4701 
   4702 /**
   4703  * Check if we are done sending the write-buffer.
   4704  * If so, transition into "next_state".
   4705  *
   4706  * @param connection connection to check write status for
   4707  * @param next_state the next state to transition to
   4708  * @return #MHD_NO if we are not done, #MHD_YES if we are
   4709  */
   4710 static enum MHD_Result
   4711 check_write_done (struct MHD_Connection *connection,
   4712                   enum MHD_CONNECTION_STATE next_state)
   4713 {
   4714   if ( (connection->write_buffer_append_offset !=
   4715         connection->write_buffer_send_offset)
   4716        /* || data_in_tls_buffers == true  */
   4717        )
   4718     return MHD_NO;
   4719   connection->write_buffer_append_offset = 0;
   4720   connection->write_buffer_send_offset = 0;
   4721   connection->state = next_state;
   4722   return MHD_YES;
   4723 }
   4724 
   4725 
   4726 /**
   4727  * Parse the various headers; figure out the size
   4728  * of the upload and make sure the headers follow
   4729  * the protocol.  Advance to the appropriate state.
   4730  *
   4731  * @param connection connection we're processing
   4732  */
   4733 static void
   4734 parse_connection_headers (struct MHD_Connection *connection)
   4735 {
   4736   const char *clen;
   4737   const char *enc;
   4738   size_t val_len;
   4739 
   4740 #ifdef COOKIE_SUPPORT
   4741   if (MHD_PARSE_COOKIE_NO_MEMORY == parse_cookie_header (connection))
   4742   {
   4743     handle_req_cookie_no_space (connection);
   4744     return;
   4745   }
   4746 #endif /* COOKIE_SUPPORT */
   4747   if ( (-3 < connection->daemon->client_discipline) &&
   4748        (MHD_IS_HTTP_VER_1_1_COMPAT (connection->rq.http_ver)) &&
   4749        (MHD_NO ==
   4750         MHD_lookup_connection_value_n (connection,
   4751                                        MHD_HEADER_KIND,
   4752                                        MHD_HTTP_HEADER_HOST,
   4753                                        MHD_STATICSTR_LEN_ (
   4754                                          MHD_HTTP_HEADER_HOST),
   4755                                        NULL,
   4756                                        NULL)) )
   4757   {
   4758 #ifdef HAVE_MESSAGES
   4759     MHD_DLOG (connection->daemon,
   4760               _ ("Received HTTP/1.1 request without `Host' header.\n"));
   4761 #endif
   4762     transmit_error_response_static (connection,
   4763                                     MHD_HTTP_BAD_REQUEST,
   4764                                     REQUEST_LACKS_HOST);
   4765     return;
   4766   }
   4767 
   4768   /* The presence of the request body is indicated by "Content-Length:" or
   4769      "Transfer-Encoding:" request headers.
   4770      Unless one of these two headers is used, the request has no request body.
   4771      See RFC9112, Section 6, paragraph 4. */
   4772   connection->rq.remaining_upload_size = 0;
   4773   if (MHD_NO !=
   4774       MHD_lookup_connection_value_n (connection,
   4775                                      MHD_HEADER_KIND,
   4776                                      MHD_HTTP_HEADER_TRANSFER_ENCODING,
   4777                                      MHD_STATICSTR_LEN_ (
   4778                                        MHD_HTTP_HEADER_TRANSFER_ENCODING),
   4779                                      &enc,
   4780                                      NULL))
   4781   {
   4782     if (! MHD_str_equal_caseless_ (enc,
   4783                                    "chunked"))
   4784     {
   4785       transmit_error_response_static (connection,
   4786                                       MHD_HTTP_BAD_REQUEST,
   4787                                       REQUEST_UNSUPPORTED_TR_ENCODING);
   4788       return;
   4789     }
   4790     else if (MHD_NO !=
   4791              MHD_lookup_connection_value_n (connection,
   4792                                             MHD_HEADER_KIND,
   4793                                             MHD_HTTP_HEADER_CONTENT_LENGTH,
   4794                                             MHD_STATICSTR_LEN_ ( \
   4795                                               MHD_HTTP_HEADER_CONTENT_LENGTH),
   4796                                             NULL,
   4797                                             NULL))
   4798     {
   4799       /* TODO: add individual settings */
   4800       if (1 <= connection->daemon->client_discipline)
   4801       {
   4802         transmit_error_response_static (connection,
   4803                                         MHD_HTTP_BAD_REQUEST,
   4804                                         REQUEST_LENGTH_WITH_TR_ENCODING);
   4805         return;
   4806       }
   4807       else
   4808       {
   4809         /* Must close connection after reply to prevent potential attack */
   4810         connection->keepalive = MHD_CONN_MUST_CLOSE;
   4811 #ifdef HAVE_MESSAGES
   4812         MHD_DLOG (connection->daemon,
   4813                   _ ("The 'Content-Length' request header is ignored "
   4814                      "as chunked Transfer-Encoding is used "
   4815                      "for this request.\n"));
   4816 #endif /* HAVE_MESSAGES */
   4817       }
   4818     }
   4819     connection->rq.have_chunked_upload = true;
   4820     connection->rq.remaining_upload_size = MHD_SIZE_UNKNOWN;
   4821   }
   4822   else if (MHD_NO !=
   4823            MHD_lookup_connection_value_n (connection,
   4824                                           MHD_HEADER_KIND,
   4825                                           MHD_HTTP_HEADER_CONTENT_LENGTH,
   4826                                           MHD_STATICSTR_LEN_ (
   4827                                             MHD_HTTP_HEADER_CONTENT_LENGTH),
   4828                                           &clen,
   4829                                           &val_len))
   4830   {
   4831     size_t num_digits;
   4832 
   4833     num_digits = MHD_str_to_uint64_n_ (clen,
   4834                                        val_len,
   4835                                        &connection->rq.remaining_upload_size);
   4836 
   4837     if (((0 == num_digits) &&
   4838          (0 != val_len) &&
   4839          ('0' <= clen[0]) && ('9' >= clen[0]))
   4840         || (MHD_SIZE_UNKNOWN == connection->rq.remaining_upload_size))
   4841     {
   4842       connection->rq.remaining_upload_size = 0;
   4843 #ifdef HAVE_MESSAGES
   4844       MHD_DLOG (connection->daemon,
   4845                 _ ("Too large value of 'Content-Length' header. " \
   4846                    "Closing connection.\n"));
   4847 #endif
   4848       transmit_error_response_static (connection,
   4849                                       MHD_HTTP_CONTENT_TOO_LARGE,
   4850                                       REQUEST_CONTENTLENGTH_TOOLARGE);
   4851     }
   4852     else if ((val_len != num_digits) ||
   4853              (0 == num_digits))
   4854     {
   4855       connection->rq.remaining_upload_size = 0;
   4856 #ifdef HAVE_MESSAGES
   4857       MHD_DLOG (connection->daemon,
   4858                 _ ("Failed to parse 'Content-Length' header. " \
   4859                    "Closing connection.\n"));
   4860 #endif
   4861       transmit_error_response_static (connection,
   4862                                       MHD_HTTP_BAD_REQUEST,
   4863                                       REQUEST_CONTENTLENGTH_MALFORMED);
   4864     }
   4865   }
   4866 }
   4867 
   4868 
   4869 /**
   4870  * Reset request header processing state.
   4871  *
   4872  * This function resets the processing state before processing the next header
   4873  * (or footer) line.
   4874  * @param c the connection to process
   4875  */
   4876 _MHD_static_inline void
   4877 reset_rq_header_processing_state (struct MHD_Connection *c)
   4878 {
   4879   memset (&c->rq.hdrs.hdr, 0, sizeof(c->rq.hdrs.hdr));
   4880 }
   4881 
   4882 
   4883 /**
   4884  * Switch to request headers (field lines) processing state.
   4885  * @param c the connection to process
   4886  */
   4887 _MHD_static_inline void
   4888 switch_to_rq_headers_processing (struct MHD_Connection *c)
   4889 {
   4890   c->rq.field_lines.start = c->read_buffer;
   4891   memset (&c->rq.hdrs.hdr, 0, sizeof(c->rq.hdrs.hdr));
   4892   c->state = MHD_CONNECTION_REQ_HEADERS_RECEIVING;
   4893 }
   4894 
   4895 
   4896 #ifndef MHD_MAX_EMPTY_LINES_SKIP
   4897 /**
   4898  * The maximum number of ignored empty line before the request line
   4899  * at default "strictness" level.
   4900  */
   4901 #define MHD_MAX_EMPTY_LINES_SKIP 1024
   4902 #endif /* ! MHD_MAX_EMPTY_LINES_SKIP */
   4903 
   4904 /**
   4905  * Find and parse the request line.
   4906  * @param c the connection to process
   4907  * @return true if request line completely processed (or unrecoverable error
   4908  *         found) and state is changed,
   4909  *         false if not enough data yet in the receive buffer
   4910  */
   4911 static bool
   4912 get_request_line_inner (struct MHD_Connection *c)
   4913 {
   4914   size_t p; /**< The current processing position */
   4915   const int discp_lvl = c->daemon->client_discipline;
   4916   /* Allow to skip one or more empty lines before the request line.
   4917      RFC 9112, section 2.2 */
   4918   const bool skip_empty_lines = (1 >= discp_lvl);
   4919   /* Allow to skip more then one empty line before the request line.
   4920      RFC 9112, section 2.2 */
   4921   const bool skip_several_empty_lines = (skip_empty_lines && (0 >= discp_lvl));
   4922   /* Allow to skip number of unlimited empty lines before the request line.
   4923      RFC 9112, section 2.2 */
   4924   const bool skip_unlimited_empty_lines =
   4925     (skip_empty_lines && (-3 >= discp_lvl));
   4926   /* Treat bare LF as the end of the line.
   4927      RFC 9112, section 2.2 */
   4928   const bool bare_lf_as_crlf = MHD_ALLOW_BARE_LF_AS_CRLF_ (discp_lvl);
   4929   /* Treat tab as whitespace delimiter.
   4930      RFC 9112, section 3 */
   4931   const bool tab_as_wsp = (0 >= discp_lvl);
   4932   /* Treat VT (vertical tab) and FF (form feed) as whitespace delimiters.
   4933      RFC 9112, section 3 */
   4934   const bool other_wsp_as_wsp = (-1 >= discp_lvl);
   4935   /* Treat continuous whitespace block as a single space.
   4936      RFC 9112, section 3 */
   4937   const bool wsp_blocks = (-1 >= discp_lvl);
   4938   /* Parse whitespace in URI, special parsing of the request line.
   4939      RFC 9112, section 3.2 */
   4940   const bool wsp_in_uri = (0 >= discp_lvl);
   4941   /* Keep whitespace in URI, give app URI with whitespace instead of
   4942      automatic redirect to fixed URI.
   4943      Violates RFC 9112, section 3.2 */
   4944   const bool wsp_in_uri_keep = (-2 >= discp_lvl);
   4945   /* Keep bare CR character as is.
   4946      Violates RFC 9112, section 2.2 */
   4947   const bool bare_cr_keep = (wsp_in_uri_keep && (-3 >= discp_lvl));
   4948   /* Treat bare CR as space; replace it with space before processing.
   4949      RFC 9112, section 2.2 */
   4950   const bool bare_cr_as_sp = ((! bare_cr_keep) && (-1 >= discp_lvl));
   4951 
   4952   mhd_assert (MHD_CONNECTION_INIT == c->state || \
   4953               MHD_CONNECTION_REQ_LINE_RECEIVING == c->state);
   4954   mhd_assert (NULL == c->rq.method || \
   4955               MHD_CONNECTION_REQ_LINE_RECEIVING == c->state);
   4956   mhd_assert (MHD_HTTP_MTHD_NO_METHOD == c->rq.http_mthd || \
   4957               MHD_CONNECTION_REQ_LINE_RECEIVING == c->state);
   4958   mhd_assert (MHD_HTTP_MTHD_NO_METHOD == c->rq.http_mthd || \
   4959               0 != c->rq.hdrs.rq_line.proc_pos);
   4960 
   4961   if (0 == c->read_buffer_offset)
   4962   {
   4963     mhd_assert (MHD_CONNECTION_INIT == c->state);
   4964     return false; /* No data to process */
   4965   }
   4966   p = c->rq.hdrs.rq_line.proc_pos;
   4967   mhd_assert (p <= c->read_buffer_offset);
   4968 
   4969   /* Skip empty lines, if any (and if allowed) */
   4970   /* See RFC 9112, section 2.2 */
   4971   if ((0 == p)
   4972       && (skip_empty_lines))
   4973   {
   4974     /* Skip empty lines before the request line.
   4975        See RFC 9112, section 2.2 */
   4976     bool is_empty_line;
   4977     mhd_assert (MHD_CONNECTION_INIT == c->state);
   4978     mhd_assert (NULL == c->rq.method);
   4979     mhd_assert (NULL == c->rq.url);
   4980     mhd_assert (0 == c->rq.url_len);
   4981     mhd_assert (NULL == c->rq.hdrs.rq_line.rq_tgt);
   4982     mhd_assert (0 == c->rq.req_target_len);
   4983     mhd_assert (NULL == c->rq.version);
   4984     do
   4985     {
   4986       is_empty_line = false;
   4987       if ('\r' == c->read_buffer[0])
   4988       {
   4989         if (1 == c->read_buffer_offset)
   4990           return false; /* Not enough data yet */
   4991         if ('\n' == c->read_buffer[1])
   4992         {
   4993           is_empty_line = true;
   4994           c->read_buffer += 2;
   4995           c->read_buffer_size -= 2;
   4996           c->read_buffer_offset -= 2;
   4997           c->rq.hdrs.rq_line.skipped_empty_lines++;
   4998         }
   4999       }
   5000       else if (('\n' == c->read_buffer[0]) &&
   5001                (bare_lf_as_crlf))
   5002       {
   5003         is_empty_line = true;
   5004         c->read_buffer += 1;
   5005         c->read_buffer_size -= 1;
   5006         c->read_buffer_offset -= 1;
   5007         c->rq.hdrs.rq_line.skipped_empty_lines++;
   5008       }
   5009       if (is_empty_line)
   5010       {
   5011         if ((! skip_unlimited_empty_lines) &&
   5012             (((unsigned int) ((skip_several_empty_lines) ?
   5013                               MHD_MAX_EMPTY_LINES_SKIP : 1)) <
   5014              c->rq.hdrs.rq_line.skipped_empty_lines))
   5015         {
   5016           connection_close_error (c,
   5017                                   _ ("Too many meaningless extra empty lines " \
   5018                                      "received before the request"));
   5019           return true; /* Process connection closure */
   5020         }
   5021         if (0 == c->read_buffer_offset)
   5022           return false;  /* No more data to process */
   5023       }
   5024     } while (is_empty_line);
   5025   }
   5026   /* All empty lines are skipped */
   5027 
   5028   c->state = MHD_CONNECTION_REQ_LINE_RECEIVING;
   5029   /* Read and parse the request line */
   5030   mhd_assert (1 <= c->read_buffer_offset);
   5031 
   5032   while (p < c->read_buffer_offset)
   5033   {
   5034     const char chr = c->read_buffer[p];
   5035     bool end_of_line;
   5036     /*
   5037        The processing logic is different depending on the configured strictness:
   5038 
   5039        When whitespace BLOCKS are NOT ALLOWED, the end of the whitespace is
   5040        processed BEFORE processing of the current character.
   5041        When whitespace BLOCKS are ALLOWED, the end of the whitespace is
   5042        processed AFTER processing of the current character.
   5043 
   5044        When space char in the URI is ALLOWED, the delimiter between the URI and
   5045        the HTTP version string is processed only at the END of the line.
   5046        When space in the URI is NOT ALLOWED, the delimiter between the URI and
   5047        the HTTP version string is processed as soon as the FIRST whitespace is
   5048        found after URI start.
   5049      */
   5050 
   5051     end_of_line = false;
   5052 
   5053     mhd_assert ((0 == c->rq.hdrs.rq_line.last_ws_end) || \
   5054                 (c->rq.hdrs.rq_line.last_ws_end > \
   5055                  c->rq.hdrs.rq_line.last_ws_start));
   5056     mhd_assert ((0 == c->rq.hdrs.rq_line.last_ws_start) || \
   5057                 (0 != c->rq.hdrs.rq_line.last_ws_end));
   5058 
   5059     /* Check for the end of the line */
   5060     if ('\r' == chr)
   5061     {
   5062       if (p + 1 == c->read_buffer_offset)
   5063       {
   5064         c->rq.hdrs.rq_line.proc_pos = p;
   5065         return false; /* Not enough data yet */
   5066       }
   5067       else if ('\n' == c->read_buffer[p + 1])
   5068         end_of_line = true;
   5069       else
   5070       {
   5071         /* Bare CR alone */
   5072         /* Must be rejected or replaced with space char.
   5073            See RFC 9112, section 2.2 */
   5074         if (bare_cr_as_sp)
   5075         {
   5076           c->read_buffer[p] = ' ';
   5077           c->rq.num_cr_sp_replaced++;
   5078           continue; /* Re-start processing of the current character */
   5079         }
   5080         else if (! bare_cr_keep)
   5081         {
   5082           /* A quick simple check whether this line looks like an HTTP request */
   5083           if ((MHD_HTTP_MTHD_GET <= c->rq.http_mthd) &&
   5084               (MHD_HTTP_MTHD_DELETE >= c->rq.http_mthd))
   5085           {
   5086             transmit_error_response_static (c,
   5087                                             MHD_HTTP_BAD_REQUEST,
   5088                                             BARE_CR_IN_HEADER);
   5089           }
   5090           else
   5091             connection_close_error (c,
   5092                                     _ ("Bare CR characters are not allowed " \
   5093                                        "in the request line.\n"));
   5094           return true; /* Error in the request */
   5095         }
   5096       }
   5097     }
   5098     else if ('\n' == chr)
   5099     {
   5100       /* Bare LF may be recognised as a line delimiter.
   5101          See RFC 9112, section 2.2 */
   5102       if (bare_lf_as_crlf)
   5103         end_of_line = true;
   5104       else
   5105       {
   5106         /* While RFC does not enforce error for bare LF character,
   5107            if this char is not treated as a line delimiter, it should be
   5108            rejected to avoid any security weakness due to request smuggling. */
   5109         /* A quick simple check whether this line looks like an HTTP request */
   5110         if ((MHD_HTTP_MTHD_GET <= c->rq.http_mthd) &&
   5111             (MHD_HTTP_MTHD_DELETE >= c->rq.http_mthd))
   5112         {
   5113           transmit_error_response_static (c,
   5114                                           MHD_HTTP_BAD_REQUEST,
   5115                                           BARE_LF_IN_HEADER);
   5116         }
   5117         else
   5118           connection_close_error (c,
   5119                                   _ ("Bare LF characters are not allowed " \
   5120                                      "in the request line.\n"));
   5121         return true; /* Error in the request */
   5122       }
   5123     }
   5124 
   5125     if (end_of_line)
   5126     {
   5127       /* Handle the end of the request line */
   5128 
   5129       if (NULL != c->rq.method)
   5130       {
   5131         if (wsp_in_uri)
   5132         {
   5133           /* The end of the URI and the start of the HTTP version string
   5134              should be determined now. */
   5135           mhd_assert (NULL == c->rq.version);
   5136           mhd_assert (0 == c->rq.req_target_len);
   5137           if (0 != c->rq.hdrs.rq_line.last_ws_end)
   5138           {
   5139             /* Determine the end and the length of the URI */
   5140             if (NULL != c->rq.hdrs.rq_line.rq_tgt)
   5141             {
   5142               c->read_buffer [c->rq.hdrs.rq_line.last_ws_start] = 0; /* Zero terminate the URI */
   5143               c->rq.req_target_len =
   5144                 c->rq.hdrs.rq_line.last_ws_start
   5145                 - (size_t) (c->rq.hdrs.rq_line.rq_tgt - c->read_buffer);
   5146             }
   5147             else if ((c->rq.hdrs.rq_line.last_ws_start + 1 <
   5148                       c->rq.hdrs.rq_line.last_ws_end) &&
   5149                      (HTTP_VER_LEN == (p - c->rq.hdrs.rq_line.last_ws_end)))
   5150             {
   5151               /* Found only HTTP method and HTTP version and more than one
   5152                  whitespace between them. Assume zero-length URI. */
   5153               mhd_assert (wsp_blocks);
   5154               c->rq.hdrs.rq_line.last_ws_start++;
   5155               c->read_buffer[c->rq.hdrs.rq_line.last_ws_start] = 0; /* Zero terminate the URI */
   5156               c->rq.hdrs.rq_line.rq_tgt =
   5157                 c->read_buffer + c->rq.hdrs.rq_line.last_ws_start;
   5158               c->rq.req_target_len = 0;
   5159               c->rq.hdrs.rq_line.num_ws_in_uri = 0;
   5160               c->rq.hdrs.rq_line.rq_tgt_qmark = NULL;
   5161             }
   5162             /* Determine the start of the HTTP version string */
   5163             if (NULL != c->rq.hdrs.rq_line.rq_tgt)
   5164             {
   5165               c->rq.version = c->read_buffer + c->rq.hdrs.rq_line.last_ws_end;
   5166             }
   5167           }
   5168         }
   5169         else
   5170         {
   5171           /* The end of the URI and the start of the HTTP version string
   5172              should be already known. */
   5173           if ((NULL == c->rq.version)
   5174               && (NULL != c->rq.hdrs.rq_line.rq_tgt)
   5175               && (HTTP_VER_LEN == p - (size_t) (c->rq.hdrs.rq_line.rq_tgt
   5176                                                 - c->read_buffer))
   5177               && (0 != c->read_buffer[(size_t)
   5178                                       (c->rq.hdrs.rq_line.rq_tgt
   5179                                        - c->read_buffer) - 1]))
   5180           {
   5181             /* Found only HTTP method and HTTP version and more than one
   5182                whitespace between them. Assume zero-length URI. */
   5183             size_t uri_pos;
   5184             mhd_assert (wsp_blocks);
   5185             mhd_assert (0 == c->rq.req_target_len);
   5186             uri_pos = (size_t) (c->rq.hdrs.rq_line.rq_tgt - c->read_buffer) - 1;
   5187             mhd_assert (uri_pos < p);
   5188             c->rq.version = c->rq.hdrs.rq_line.rq_tgt;
   5189             c->read_buffer[uri_pos] = 0;  /* Zero terminate the URI */
   5190             c->rq.hdrs.rq_line.rq_tgt = c->read_buffer + uri_pos;
   5191             c->rq.req_target_len = 0;
   5192             c->rq.hdrs.rq_line.num_ws_in_uri = 0;
   5193             c->rq.hdrs.rq_line.rq_tgt_qmark = NULL;
   5194           }
   5195         }
   5196 
   5197         if (NULL != c->rq.version)
   5198         {
   5199           mhd_assert (NULL != c->rq.hdrs.rq_line.rq_tgt);
   5200           if (! parse_http_version (c, c->rq.version,
   5201                                     p
   5202                                     - (size_t) (c->rq.version
   5203                                                 - c->read_buffer)))
   5204           {
   5205             mhd_assert (MHD_CONNECTION_REQ_LINE_RECEIVING < c->state);
   5206             return true; /* Unsupported / broken HTTP version */
   5207           }
   5208           c->read_buffer[p] = 0; /* Zero terminate the HTTP version strings */
   5209           if ('\r' == chr)
   5210           {
   5211             p++; /* Consume CR */
   5212             mhd_assert (p < c->read_buffer_offset); /* The next character has been already checked */
   5213           }
   5214           p++; /* Consume LF */
   5215           c->read_buffer += p;
   5216           c->read_buffer_size -= p;
   5217           c->read_buffer_offset -= p;
   5218           mhd_assert (c->rq.hdrs.rq_line.num_ws_in_uri <= \
   5219                       c->rq.req_target_len);
   5220           mhd_assert ((NULL == c->rq.hdrs.rq_line.rq_tgt_qmark) || \
   5221                       (0 != c->rq.req_target_len));
   5222           mhd_assert ((NULL == c->rq.hdrs.rq_line.rq_tgt_qmark) || \
   5223                       ((size_t) (c->rq.hdrs.rq_line.rq_tgt_qmark \
   5224                                  - c->rq.hdrs.rq_line.rq_tgt) < \
   5225                        c->rq.req_target_len));
   5226           mhd_assert ((NULL == c->rq.hdrs.rq_line.rq_tgt_qmark) || \
   5227                       (c->rq.hdrs.rq_line.rq_tgt_qmark >= \
   5228                        c->rq.hdrs.rq_line.rq_tgt));
   5229           return true; /* The request line is successfully parsed */
   5230         }
   5231       }
   5232       /* Error in the request line */
   5233 
   5234       /* A quick simple check whether this line looks like an HTTP request */
   5235       if ((MHD_HTTP_MTHD_GET <= c->rq.http_mthd) &&
   5236           (MHD_HTTP_MTHD_DELETE >= c->rq.http_mthd))
   5237       {
   5238         transmit_error_response_static (c,
   5239                                         MHD_HTTP_BAD_REQUEST,
   5240                                         REQUEST_MALFORMED);
   5241       }
   5242       else
   5243         connection_close_error (c,
   5244                                 _ ("The request line is malformed.\n"));
   5245 
   5246       return true;
   5247     }
   5248 
   5249     /* Process possible end of the previously found whitespace delimiter */
   5250     if ((! wsp_blocks) &&
   5251         (p == c->rq.hdrs.rq_line.last_ws_end) &&
   5252         (0 != c->rq.hdrs.rq_line.last_ws_end))
   5253     {
   5254       /* Previous character was a whitespace char and whitespace blocks
   5255          are not allowed. */
   5256       /* The current position is the next character after
   5257          a whitespace delimiter */
   5258       if (NULL == c->rq.hdrs.rq_line.rq_tgt)
   5259       {
   5260         /* The current position is the start of the URI */
   5261         mhd_assert (0 == c->rq.req_target_len);
   5262         mhd_assert (NULL == c->rq.version);
   5263         c->rq.hdrs.rq_line.rq_tgt = c->read_buffer + p;
   5264         /* Reset the whitespace marker */
   5265         c->rq.hdrs.rq_line.last_ws_start = 0;
   5266         c->rq.hdrs.rq_line.last_ws_end = 0;
   5267       }
   5268       else
   5269       {
   5270         /* It was a whitespace after the start of the URI */
   5271         if (! wsp_in_uri)
   5272         {
   5273           mhd_assert ((0 != c->rq.req_target_len) || \
   5274                       (c->rq.hdrs.rq_line.rq_tgt + 1 == c->read_buffer + p));
   5275           mhd_assert (NULL == c->rq.version); /* Too many whitespaces? This error is handled at whitespace start */
   5276           c->rq.version = c->read_buffer + p;
   5277           /* Reset the whitespace marker */
   5278           c->rq.hdrs.rq_line.last_ws_start = 0;
   5279           c->rq.hdrs.rq_line.last_ws_end = 0;
   5280         }
   5281       }
   5282     }
   5283 
   5284     /* Process the current character.
   5285        Is it not the end of the line.  */
   5286     if ((' ' == chr)
   5287         || (('\t' == chr) && (tab_as_wsp))
   5288         || ((other_wsp_as_wsp) && ((0xb == chr) || (0xc == chr))))
   5289     {
   5290       /* A whitespace character */
   5291       if ((0 == c->rq.hdrs.rq_line.last_ws_end) ||
   5292           (p != c->rq.hdrs.rq_line.last_ws_end) ||
   5293           (! wsp_blocks))
   5294       {
   5295         /* Found first whitespace char of the new whitespace block */
   5296         if (NULL == c->rq.method)
   5297         {
   5298           /* Found the end of the HTTP method string */
   5299           mhd_assert (0 == c->rq.hdrs.rq_line.last_ws_start);
   5300           mhd_assert (0 == c->rq.hdrs.rq_line.last_ws_end);
   5301           mhd_assert (NULL == c->rq.hdrs.rq_line.rq_tgt);
   5302           mhd_assert (0 == c->rq.req_target_len);
   5303           mhd_assert (NULL == c->rq.version);
   5304           if (0 == p)
   5305           {
   5306             connection_close_error (c,
   5307                                     _ ("The request line starts with "
   5308                                        "a whitespace.\n"));
   5309             return true; /* Error in the request */
   5310           }
   5311           c->read_buffer[p] = 0; /* Zero-terminate the request method string */
   5312           c->rq.method = c->read_buffer;
   5313           parse_http_std_method (c, c->rq.method, p);
   5314         }
   5315         else
   5316         {
   5317           /* A whitespace after the start of the URI */
   5318           if (! wsp_in_uri)
   5319           {
   5320             /* Whitespace in URI is not allowed to be parsed */
   5321             if (NULL == c->rq.version)
   5322             {
   5323               mhd_assert (NULL != c->rq.hdrs.rq_line.rq_tgt);
   5324               /* This is a delimiter between URI and HTTP version string */
   5325               c->read_buffer[p] = 0; /* Zero-terminate request URI string */
   5326               mhd_assert (((size_t) (c->rq.hdrs.rq_line.rq_tgt   \
   5327                                      - c->read_buffer)) <= p);
   5328               c->rq.req_target_len =
   5329                 p - (size_t) (c->rq.hdrs.rq_line.rq_tgt - c->read_buffer);
   5330             }
   5331             else
   5332             {
   5333               /* This is a delimiter AFTER version string */
   5334 
   5335               /* A quick simple check whether this line looks like an HTTP request */
   5336               if ((MHD_HTTP_MTHD_GET <= c->rq.http_mthd) &&
   5337                   (MHD_HTTP_MTHD_DELETE >= c->rq.http_mthd))
   5338               {
   5339                 transmit_error_response_static (c,
   5340                                                 MHD_HTTP_BAD_REQUEST,
   5341                                                 RQ_LINE_TOO_MANY_WSP);
   5342               }
   5343               else
   5344                 connection_close_error (c,
   5345                                         _ ("The request line has more than "
   5346                                            "two whitespaces.\n"));
   5347               return true; /* Error in the request */
   5348             }
   5349           }
   5350           else
   5351           {
   5352             /* Whitespace in URI is allowed to be parsed */
   5353             if (0 != c->rq.hdrs.rq_line.last_ws_end)
   5354             {
   5355               /* The whitespace after the start of the URI has been found already */
   5356               c->rq.hdrs.rq_line.num_ws_in_uri +=
   5357                 c->rq.hdrs.rq_line.last_ws_end
   5358                 - c->rq.hdrs.rq_line.last_ws_start;
   5359             }
   5360           }
   5361         }
   5362         c->rq.hdrs.rq_line.last_ws_start = p;
   5363         c->rq.hdrs.rq_line.last_ws_end = p + 1; /* Will be updated on the next char parsing */
   5364       }
   5365       else
   5366       {
   5367         /* Continuation of the whitespace block */
   5368         mhd_assert (0 != c->rq.hdrs.rq_line.last_ws_end);
   5369         mhd_assert (0 != p);
   5370         c->rq.hdrs.rq_line.last_ws_end = p + 1;
   5371       }
   5372     }
   5373     else
   5374     {
   5375       /* Non-whitespace char, not the end of the line */
   5376       mhd_assert ((0 == c->rq.hdrs.rq_line.last_ws_end) || \
   5377                   (c->rq.hdrs.rq_line.last_ws_end == p) || \
   5378                   wsp_in_uri);
   5379 
   5380       if ((p == c->rq.hdrs.rq_line.last_ws_end) &&
   5381           (0 != c->rq.hdrs.rq_line.last_ws_end) &&
   5382           (wsp_blocks))
   5383       {
   5384         /* The end of the whitespace block */
   5385         if (NULL == c->rq.hdrs.rq_line.rq_tgt)
   5386         {
   5387           /* This is the first character of the URI */
   5388           mhd_assert (0 == c->rq.req_target_len);
   5389           mhd_assert (NULL == c->rq.version);
   5390           c->rq.hdrs.rq_line.rq_tgt = c->read_buffer + p;
   5391           /* Reset the whitespace marker */
   5392           c->rq.hdrs.rq_line.last_ws_start = 0;
   5393           c->rq.hdrs.rq_line.last_ws_end = 0;
   5394         }
   5395         else
   5396         {
   5397           if (! wsp_in_uri)
   5398           {
   5399             /* This is the first character of the HTTP version */
   5400             mhd_assert (NULL != c->rq.hdrs.rq_line.rq_tgt);
   5401             mhd_assert ((0 != c->rq.req_target_len) || \
   5402                         (c->rq.hdrs.rq_line.rq_tgt + 1 == c->read_buffer + p));
   5403             mhd_assert (NULL == c->rq.version); /* Handled at whitespace start */
   5404             c->rq.version = c->read_buffer + p;
   5405             /* Reset the whitespace marker */
   5406             c->rq.hdrs.rq_line.last_ws_start = 0;
   5407             c->rq.hdrs.rq_line.last_ws_end = 0;
   5408           }
   5409         }
   5410       }
   5411 
   5412       /* Handle other special characters */
   5413       if ('?' == chr)
   5414       {
   5415         if ((NULL == c->rq.hdrs.rq_line.rq_tgt_qmark) &&
   5416             (NULL != c->rq.hdrs.rq_line.rq_tgt))
   5417         {
   5418           c->rq.hdrs.rq_line.rq_tgt_qmark = c->read_buffer + p;
   5419         }
   5420       }
   5421       else if ((0xb == chr) || (0xc == chr))
   5422       {
   5423         /* VT or LF characters */
   5424         mhd_assert (! other_wsp_as_wsp);
   5425         if ((NULL != c->rq.hdrs.rq_line.rq_tgt) &&
   5426             (NULL == c->rq.version) &&
   5427             (wsp_in_uri))
   5428         {
   5429           c->rq.hdrs.rq_line.num_ws_in_uri++;
   5430         }
   5431         else
   5432         {
   5433           connection_close_error (c,
   5434                                   _ ("Invalid character is in the "
   5435                                      "request line.\n"));
   5436           return true; /* Error in the request */
   5437         }
   5438       }
   5439       else if (0 == chr)
   5440       {
   5441         /* NUL character */
   5442         connection_close_error (c,
   5443                                 _ ("The NUL character is in the "
   5444                                    "request line.\n"));
   5445         return true; /* Error in the request */
   5446       }
   5447     }
   5448 
   5449     p++;
   5450   }
   5451 
   5452   c->rq.hdrs.rq_line.proc_pos = p;
   5453   return false; /* Not enough data yet */
   5454 }
   5455 
   5456 
   5457 #ifndef MHD_MAX_FIXED_URI_LEN
   5458 /**
   5459  * The maximum size of the fixed URI for automatic redirection
   5460  */
   5461 #define MHD_MAX_FIXED_URI_LEN (64 * 1024)
   5462 #endif /* ! MHD_MAX_FIXED_URI_LEN */
   5463 
   5464 /**
   5465  * Send the automatic redirection to fixed URI when received URI with
   5466  * whitespaces.
   5467  * If URI is too large, close connection with error.
   5468  *
   5469  * @param c the connection to process
   5470  */
   5471 static void
   5472 send_redirect_fixed_rq_target (struct MHD_Connection *c)
   5473 {
   5474   char *b;
   5475   size_t fixed_uri_len;
   5476   size_t i;
   5477   size_t o;
   5478   char *hdr_name;
   5479   size_t hdr_name_len;
   5480 
   5481   mhd_assert (MHD_CONNECTION_REQ_LINE_RECEIVING == c->state);
   5482   mhd_assert (0 != c->rq.hdrs.rq_line.num_ws_in_uri);
   5483   mhd_assert (c->rq.hdrs.rq_line.num_ws_in_uri <= \
   5484               c->rq.req_target_len);
   5485   fixed_uri_len = c->rq.req_target_len
   5486                   + 2 * c->rq.hdrs.rq_line.num_ws_in_uri;
   5487   if ( (fixed_uri_len + 200 > c->daemon->pool_size) ||
   5488        (fixed_uri_len > MHD_MAX_FIXED_URI_LEN) ||
   5489        (NULL == (b = malloc (fixed_uri_len + 1))) )
   5490   {
   5491     connection_close_error (c,
   5492                             _ ("The request has whitespace character is " \
   5493                                "in the URI and the URI is too large to " \
   5494                                "send automatic redirect to fixed URI.\n"));
   5495     return;
   5496   }
   5497   i = 0;
   5498   o = 0;
   5499 
   5500   do
   5501   {
   5502     const char chr = c->rq.hdrs.rq_line.rq_tgt[i++];
   5503 
   5504     mhd_assert ('\r' != chr); /* Replaced during request line parsing */
   5505     mhd_assert ('\n' != chr); /* Rejected during request line parsing */
   5506     mhd_assert (0 != chr); /* Rejected during request line parsing */
   5507     switch (chr)
   5508     {
   5509     case ' ':
   5510       b[o++] = '%';
   5511       b[o++] = '2';
   5512       b[o++] = '0';
   5513       break;
   5514     case '\t':
   5515       b[o++] = '%';
   5516       b[o++] = '0';
   5517       b[o++] = '9';
   5518       break;
   5519     case 0x0B:   /* VT (vertical tab) */
   5520       b[o++] = '%';
   5521       b[o++] = '0';
   5522       b[o++] = 'B';
   5523       break;
   5524     case 0x0C:   /* FF (form feed) */
   5525       b[o++] = '%';
   5526       b[o++] = '0';
   5527       b[o++] = 'C';
   5528       break;
   5529     default:
   5530       b[o++] = chr;
   5531       break;
   5532     }
   5533   } while (i < c->rq.req_target_len);
   5534   mhd_assert (fixed_uri_len == o);
   5535   b[o] = 0; /* Zero-terminate the result */
   5536 
   5537   hdr_name_len = MHD_STATICSTR_LEN_ (MHD_HTTP_HEADER_LOCATION);
   5538   hdr_name = malloc (hdr_name_len + 1);
   5539   if (NULL != hdr_name)
   5540   {
   5541     memcpy (hdr_name,
   5542             MHD_HTTP_HEADER_LOCATION,
   5543             hdr_name_len + 1);
   5544     /* hdr_name and b are free()d within this call */
   5545     transmit_error_response_header (c,
   5546                                     MHD_HTTP_MOVED_PERMANENTLY,
   5547                                     RQ_TARGET_INVALID_CHAR,
   5548                                     hdr_name,
   5549                                     hdr_name_len,
   5550                                     b,
   5551                                     o);
   5552     return;
   5553   }
   5554   free (b);
   5555   connection_close_error (c,
   5556                           _ ("The request has whitespace character is in the " \
   5557                              "URI.\n"));
   5558   return;
   5559 }
   5560 
   5561 
   5562 /**
   5563  * Process request-target string, form URI and URI parameters
   5564  * @param c the connection to process
   5565  * @return true if request-target successfully processed,
   5566  *         false if error encountered
   5567  */
   5568 static bool
   5569 process_request_target (struct MHD_Connection *c)
   5570 {
   5571 #ifdef _DEBUG
   5572   size_t params_len;
   5573 #endif /* _DEBUG */
   5574   mhd_assert (MHD_CONNECTION_REQ_LINE_RECEIVING == c->state);
   5575   mhd_assert (NULL == c->rq.url);
   5576   mhd_assert (0 == c->rq.url_len);
   5577   mhd_assert (NULL != c->rq.hdrs.rq_line.rq_tgt);
   5578   mhd_assert ((NULL == c->rq.hdrs.rq_line.rq_tgt_qmark) || \
   5579               (c->rq.hdrs.rq_line.rq_tgt <= c->rq.hdrs.rq_line.rq_tgt_qmark));
   5580   mhd_assert ((NULL == c->rq.hdrs.rq_line.rq_tgt_qmark) || \
   5581               (c->rq.req_target_len > \
   5582                (size_t) (c->rq.hdrs.rq_line.rq_tgt_qmark \
   5583                          - c->rq.hdrs.rq_line.rq_tgt)));
   5584 
   5585   /* Log callback before the request-target is modified/decoded */
   5586   if (NULL != c->daemon->uri_log_callback)
   5587   {
   5588     c->rq.client_aware = true;
   5589     c->rq.client_context =
   5590       c->daemon->uri_log_callback (c->daemon->uri_log_callback_cls,
   5591                                    c->rq.hdrs.rq_line.rq_tgt,
   5592                                    c);
   5593   }
   5594 
   5595   if (NULL != c->rq.hdrs.rq_line.rq_tgt_qmark)
   5596   {
   5597 #ifdef _DEBUG
   5598     params_len =
   5599       c->rq.req_target_len
   5600       - (size_t) (c->rq.hdrs.rq_line.rq_tgt_qmark - c->rq.hdrs.rq_line.rq_tgt);
   5601 #endif /* _DEBUG */
   5602     c->rq.hdrs.rq_line.rq_tgt_qmark[0] = 0; /* Replace '?' with zero termination */
   5603     if (MHD_NO == MHD_parse_arguments_ (c,
   5604                                         MHD_GET_ARGUMENT_KIND,
   5605                                         c->rq.hdrs.rq_line.rq_tgt_qmark + 1,
   5606                                         &connection_add_header,
   5607                                         c))
   5608     {
   5609       mhd_assert (MHD_CONNECTION_REQ_LINE_RECEIVING != c->state);
   5610       return false;
   5611     }
   5612   }
   5613 #ifdef _DEBUG
   5614   else
   5615     params_len = 0;
   5616 #endif /* _DEBUG */
   5617 
   5618   mhd_assert (strlen (c->rq.hdrs.rq_line.rq_tgt) == \
   5619               c->rq.req_target_len - params_len);
   5620 
   5621   /* Finally unescape URI itself */
   5622   c->rq.url_len =
   5623     c->daemon->unescape_callback (c->daemon->unescape_callback_cls,
   5624                                   c,
   5625                                   c->rq.hdrs.rq_line.rq_tgt);
   5626   c->rq.url = c->rq.hdrs.rq_line.rq_tgt;
   5627 
   5628   return true;
   5629 }
   5630 
   5631 
   5632 /**
   5633  * Find and parse the request line.
   5634  * Advance to the next state when done, handle errors.
   5635  * @param c the connection to process
   5636  * @return true if request line completely processed and state is changed,
   5637  *         false if not enough data yet in the receive buffer
   5638  */
   5639 static bool
   5640 get_request_line (struct MHD_Connection *c)
   5641 {
   5642   const int discp_lvl = c->daemon->client_discipline;
   5643   /* Parse whitespace in URI, special parsing of the request line */
   5644   const bool wsp_in_uri = (0 >= discp_lvl);
   5645   /* Keep whitespace in URI, give app URI with whitespace instead of
   5646      automatic redirect to fixed URI */
   5647   const bool wsp_in_uri_keep = (-2 >= discp_lvl);
   5648 
   5649   if (! get_request_line_inner (c))
   5650   {
   5651     /* End of the request line has not been found yet */
   5652     mhd_assert ((! wsp_in_uri) || NULL == c->rq.version);
   5653     if ((NULL != c->rq.version) &&
   5654         (HTTP_VER_LEN <
   5655          (c->rq.hdrs.rq_line.proc_pos
   5656           - (size_t) (c->rq.version - c->read_buffer))))
   5657     {
   5658       c->rq.http_ver = MHD_HTTP_VER_INVALID;
   5659       transmit_error_response_static (c,
   5660                                       MHD_HTTP_BAD_REQUEST,
   5661                                       REQUEST_MALFORMED);
   5662       return true; /* Error in the request */
   5663     }
   5664     return false;
   5665   }
   5666   if (MHD_CONNECTION_REQ_LINE_RECEIVING < c->state)
   5667     return true; /* Error in the request */
   5668 
   5669   mhd_assert (MHD_CONNECTION_REQ_LINE_RECEIVING == c->state);
   5670   mhd_assert (NULL == c->rq.url);
   5671   mhd_assert (0 == c->rq.url_len);
   5672   mhd_assert (NULL != c->rq.hdrs.rq_line.rq_tgt);
   5673   if (0 != c->rq.hdrs.rq_line.num_ws_in_uri)
   5674   {
   5675     if (! wsp_in_uri)
   5676     {
   5677       transmit_error_response_static (c,
   5678                                       MHD_HTTP_BAD_REQUEST,
   5679                                       RQ_TARGET_INVALID_CHAR);
   5680       return true; /* Error in the request */
   5681     }
   5682     if (! wsp_in_uri_keep)
   5683     {
   5684       send_redirect_fixed_rq_target (c);
   5685       return true; /* Error in the request */
   5686     }
   5687   }
   5688   if (! process_request_target (c))
   5689     return true; /* Error in processing */
   5690 
   5691   c->state = MHD_CONNECTION_REQ_LINE_RECEIVED;
   5692   return true;
   5693 }
   5694 
   5695 
   5696 /**
   5697  * Results of header line reading
   5698  */
   5699 enum MHD_HdrLineReadRes_
   5700 {
   5701   /**
   5702    * Not enough data yet
   5703    */
   5704   MHD_HDR_LINE_READING_NEED_MORE_DATA = 0,
   5705   /**
   5706    * New header line has been read
   5707    */
   5708   MHD_HDR_LINE_READING_GOT_HEADER,
   5709   /**
   5710    * Error in header data, error response has been queued
   5711    */
   5712   MHD_HDR_LINE_READING_DATA_ERROR,
   5713   /**
   5714    * Found the end of the request header (end of field lines)
   5715    */
   5716   MHD_HDR_LINE_READING_GOT_END_OF_HEADER
   5717 } _MHD_FIXED_ENUM;
   5718 
   5719 
   5720 /**
   5721  * Check if a character is legal inside of a field
   5722  * name according to RFC 9110.
   5723  *
   5724  * @param chr character to test
   5725  * @return true if character is allowed
   5726  */
   5727 static bool
   5728 char_legal_in_field_name (char chr)
   5729 {
   5730   switch (chr)
   5731   {
   5732   case '!':
   5733   case '#':
   5734   case '$':
   5735   case '%':
   5736   case '&':
   5737   case '\'':
   5738   case '*':
   5739   case '+':
   5740   case '-':
   5741   case '.':
   5742   case '^':
   5743   case '_':
   5744   case '`':
   5745   case '|':
   5746   case '~':
   5747   case 'a':
   5748   case 'b':
   5749   case 'c':
   5750   case 'd':
   5751   case 'e':
   5752   case 'f':
   5753   case 'g':
   5754   case 'h':
   5755   case 'i':
   5756   case 'j':
   5757   case 'k':
   5758   case 'l':
   5759   case 'm':
   5760   case 'n':
   5761   case 'o':
   5762   case 'p':
   5763   case 'q':
   5764   case 'r':
   5765   case 's':
   5766   case 't':
   5767   case 'u':
   5768   case 'v':
   5769   case 'w':
   5770   case 'x':
   5771   case 'y':
   5772   case 'z':
   5773   case 'A':
   5774   case 'B':
   5775   case 'C':
   5776   case 'D':
   5777   case 'E':
   5778   case 'F':
   5779   case 'G':
   5780   case 'H':
   5781   case 'I':
   5782   case 'J':
   5783   case 'K':
   5784   case 'L':
   5785   case 'M':
   5786   case 'N':
   5787   case 'O':
   5788   case 'P':
   5789   case 'Q':
   5790   case 'R':
   5791   case 'S':
   5792   case 'T':
   5793   case 'U':
   5794   case 'V':
   5795   case 'W':
   5796   case 'X':
   5797   case 'Y':
   5798   case 'Z':
   5799   case '0':
   5800   case '1':
   5801   case '2':
   5802   case '3':
   5803   case '4':
   5804   case '5':
   5805   case '6':
   5806   case '7':
   5807   case '8':
   5808   case '9':
   5809     return true;
   5810   default:
   5811     return false;
   5812   }
   5813 }
   5814 
   5815 
   5816 /**
   5817  * Find the end of the request header line and make basic header parsing.
   5818  * Handle errors and header folding.
   5819  * @param c the connection to process
   5820  * @param process_footers if true then footers are processed,
   5821  *                        if false then headers are processed
   5822  * @param[out] hdr_name the name of the parsed header (field)
   5823  * @param[out] hdr_name the value of the parsed header (field)
   5824  * @return true if request header line completely processed,
   5825  *         false if not enough data yet in the receive buffer
   5826  */
   5827 static enum MHD_HdrLineReadRes_
   5828 get_req_header (struct MHD_Connection *c,
   5829                 bool process_footers,
   5830                 struct _MHD_str_w_len *hdr_name,
   5831                 struct _MHD_str_w_len *hdr_value)
   5832 {
   5833   const int discp_lvl = c->daemon->client_discipline;
   5834   /* Treat bare LF as the end of the line.
   5835      RFC 9112, section 2.2-3
   5836      Note: MHD never replaces bare LF with space (RFC 9110, section 5.5-5).
   5837      Bare LF is processed as end of the line or rejected as broken request. */
   5838   const bool bare_lf_as_crlf = MHD_ALLOW_BARE_LF_AS_CRLF_ (discp_lvl);
   5839   /* Keep bare CR character as is.
   5840      Violates RFC 9112, section 2.2-4 */
   5841   const bool bare_cr_keep = (-3 >= discp_lvl);
   5842   /* Treat bare CR as space; replace it with space before processing.
   5843      RFC 9112, section 2.2-4 */
   5844   const bool bare_cr_as_sp = ((! bare_cr_keep) && (-1 >= discp_lvl));
   5845   /* Treat NUL as space; replace it with space before processing.
   5846      RFC 9110, section 5.5-5 */
   5847   const bool nul_as_sp = (-1 >= discp_lvl);
   5848   /* Allow folded header lines.
   5849      RFC 9112, section 5.2-4 */
   5850   const bool allow_folded = (0 >= discp_lvl);
   5851   /* Do not reject headers with the whitespace at the start of the first line.
   5852      When allowed, the first line with whitespace character at the first
   5853      position is ignored (as well as all possible line foldings of the first
   5854      line).
   5855      RFC 9112, section 2.2-8 */
   5856   const bool allow_wsp_at_start = allow_folded && (-1 >= discp_lvl);
   5857   /* Allow whitespace in header (field) name.
   5858      Violates RFC 9110, section 5.1-2 */
   5859   const bool allow_wsp_in_name = (-2 >= discp_lvl);
   5860   /* Allow zero-length header (field) name.
   5861      Violates RFC 9110, section 5.1-2 */
   5862   const bool allow_empty_name = (-2 >= discp_lvl);
   5863   /* Allow non-tchar characters in header (field) name.
   5864      Violates RFC 9110, section 5.1 */
   5865   const bool allow_extended_charset = (-2 >= discp_lvl);
   5866   /* Allow whitespace before colon.
   5867      Violates RFC 9112, section 5.1-2 */
   5868   const bool allow_wsp_before_colon = (-3 >= discp_lvl);
   5869   /* Do not abort the request when header line has no colon, just skip such
   5870      bad lines.
   5871      RFC 9112, section 5-1 */
   5872   const bool allow_line_without_colon = (-2 >= discp_lvl);
   5873 
   5874   size_t p; /**< The position of the currently processed character */
   5875 
   5876 #if ! defined (HAVE_MESSAGES) && ! defined(_DEBUG)
   5877   (void) process_footers; /* Unused parameter */
   5878 #endif /* !HAVE_MESSAGES && !_DEBUG */
   5879 
   5880   mhd_assert ((process_footers ? MHD_CONNECTION_FOOTERS_RECEIVING : \
   5881                MHD_CONNECTION_REQ_HEADERS_RECEIVING) == \
   5882               c->state);
   5883 
   5884   p = c->rq.hdrs.hdr.proc_pos;
   5885 
   5886   mhd_assert (p <= c->read_buffer_offset);
   5887   while (p < c->read_buffer_offset)
   5888   {
   5889     const char chr = c->read_buffer[p];
   5890     bool end_of_line;
   5891 
   5892     mhd_assert ((0 == c->rq.hdrs.hdr.name_len) || \
   5893                 (c->rq.hdrs.hdr.name_len < p));
   5894     mhd_assert ((0 == c->rq.hdrs.hdr.name_len) || (0 != p));
   5895     mhd_assert ((0 == c->rq.hdrs.hdr.name_len) || \
   5896                 (c->rq.hdrs.hdr.name_end_found));
   5897     mhd_assert ((0 == c->rq.hdrs.hdr.value_start) || \
   5898                 (c->rq.hdrs.hdr.name_len < c->rq.hdrs.hdr.value_start));
   5899     mhd_assert ((0 == c->rq.hdrs.hdr.value_start) || \
   5900                 (0 != c->rq.hdrs.hdr.name_len));
   5901     mhd_assert ((0 == c->rq.hdrs.hdr.ws_start) || \
   5902                 (0 == c->rq.hdrs.hdr.name_len) || \
   5903                 (c->rq.hdrs.hdr.ws_start > c->rq.hdrs.hdr.name_len));
   5904     mhd_assert ((0 == c->rq.hdrs.hdr.ws_start) || \
   5905                 (0 == c->rq.hdrs.hdr.value_start) || \
   5906                 (c->rq.hdrs.hdr.ws_start > c->rq.hdrs.hdr.value_start));
   5907 
   5908     /* Check for the end of the line */
   5909     if ('\r' == chr)
   5910     {
   5911       if (0 != p)
   5912       {
   5913         /* Line is not empty, need to check for possible line folding */
   5914         if (p + 2 >= c->read_buffer_offset)
   5915           break; /* Not enough data yet to check for folded line */
   5916       }
   5917       else
   5918       {
   5919         /* Line is empty, no need to check for possible line folding */
   5920         if (p + 2 > c->read_buffer_offset)
   5921           break; /* Not enough data yet to check for the end of the line */
   5922       }
   5923       if ('\n' == c->read_buffer[p + 1])
   5924         end_of_line = true;
   5925       else
   5926       {
   5927         /* Bare CR alone */
   5928         /* Must be rejected or replaced with space char.
   5929            See RFC 9112, section 2.2-4 */
   5930         if (bare_cr_as_sp)
   5931         {
   5932           c->read_buffer[p] = ' ';
   5933           c->rq.num_cr_sp_replaced++;
   5934           continue; /* Re-start processing of the current character */
   5935         }
   5936         else if (! bare_cr_keep)
   5937         {
   5938           if (! process_footers)
   5939             transmit_error_response_static (c,
   5940                                             MHD_HTTP_BAD_REQUEST,
   5941                                             BARE_CR_IN_HEADER);
   5942           else
   5943             transmit_error_response_static (c,
   5944                                             MHD_HTTP_BAD_REQUEST,
   5945                                             BARE_CR_IN_FOOTER);
   5946           return MHD_HDR_LINE_READING_DATA_ERROR; /* Error in the request */
   5947         }
   5948         end_of_line = false;
   5949       }
   5950     }
   5951     else if ('\n' == chr)
   5952     {
   5953       /* Bare LF may be recognised as a line delimiter.
   5954          See RFC 9112, section 2.2-3 */
   5955       if (bare_lf_as_crlf)
   5956       {
   5957         if (0 != p)
   5958         {
   5959           /* Line is not empty, need to check for possible line folding */
   5960           if (p + 1 >= c->read_buffer_offset)
   5961             break; /* Not enough data yet to check for folded line */
   5962         }
   5963         end_of_line = true;
   5964       }
   5965       else
   5966       {
   5967         if (! process_footers)
   5968           transmit_error_response_static (c,
   5969                                           MHD_HTTP_BAD_REQUEST,
   5970                                           BARE_LF_IN_HEADER);
   5971         else
   5972           transmit_error_response_static (c,
   5973                                           MHD_HTTP_BAD_REQUEST,
   5974                                           BARE_LF_IN_FOOTER);
   5975         return MHD_HDR_LINE_READING_DATA_ERROR; /* Error in the request */
   5976       }
   5977     }
   5978     else
   5979       end_of_line = false;
   5980 
   5981     if (end_of_line)
   5982     {
   5983       /* Handle the end of the line */
   5984       /**
   5985        *  The full length of the line, including CRLF (or bare LF).
   5986        */
   5987       const size_t line_len = p + (('\r' == chr) ? 2 : 1);
   5988       char next_line_char;
   5989       mhd_assert (line_len <= c->read_buffer_offset);
   5990 
   5991       if (0 == p)
   5992       {
   5993         /* Zero-length header line. This is the end of the request header
   5994            section.
   5995            RFC 9112, Section 2.1-1 */
   5996         mhd_assert (! c->rq.hdrs.hdr.starts_with_ws);
   5997         mhd_assert (! c->rq.hdrs.hdr.name_end_found);
   5998         mhd_assert (0 == c->rq.hdrs.hdr.name_len);
   5999         mhd_assert (0 == c->rq.hdrs.hdr.ws_start);
   6000         mhd_assert (0 == c->rq.hdrs.hdr.value_start);
   6001         /* Consume the line with CRLF (or bare LF) */
   6002         c->read_buffer += line_len;
   6003         c->read_buffer_offset -= line_len;
   6004         c->read_buffer_size -= line_len;
   6005         return MHD_HDR_LINE_READING_GOT_END_OF_HEADER;
   6006       }
   6007 
   6008       mhd_assert (line_len < c->read_buffer_offset);
   6009       mhd_assert (0 != line_len);
   6010       mhd_assert ('\n' == c->read_buffer[line_len - 1]);
   6011       next_line_char = c->read_buffer[line_len];
   6012       if ((' ' == next_line_char) ||
   6013           ('\t' == next_line_char))
   6014       {
   6015         /* Folded line */
   6016         if (! allow_folded)
   6017         {
   6018           if (! process_footers)
   6019             transmit_error_response_static (c,
   6020                                             MHD_HTTP_BAD_REQUEST,
   6021                                             ERR_RSP_OBS_FOLD);
   6022           else
   6023             transmit_error_response_static (c,
   6024                                             MHD_HTTP_BAD_REQUEST,
   6025                                             ERR_RSP_OBS_FOLD_FOOTER);
   6026 
   6027           return MHD_HDR_LINE_READING_DATA_ERROR; /* Error in the request */
   6028         }
   6029         /* Replace CRLF (or bare LF) character(s) with space characters.
   6030            See RFC 9112, Section 5.2-4 */
   6031         c->read_buffer[p] = ' ';
   6032         if ('\r' == chr)
   6033           c->read_buffer[p + 1] = ' ';
   6034         continue; /* Re-start processing of the current character */
   6035       }
   6036       else
   6037       {
   6038         /* It is not a folded line, it's the real end of the non-empty line */
   6039         bool skip_line = false;
   6040         mhd_assert (0 != p);
   6041         if (c->rq.hdrs.hdr.starts_with_ws)
   6042         {
   6043           /* This is the first line and it starts with whitespace. This line
   6044              must be discarded completely.
   6045              See RFC 9112, Section 2.2-8 */
   6046           mhd_assert (allow_wsp_at_start);
   6047 #ifdef HAVE_MESSAGES
   6048           MHD_DLOG (c->daemon,
   6049                     _ ("Whitespace-prefixed first header line " \
   6050                        "has been skipped.\n"));
   6051 #endif /* HAVE_MESSAGES */
   6052           skip_line = true;
   6053         }
   6054         else if (! c->rq.hdrs.hdr.name_end_found)
   6055         {
   6056           if (! allow_line_without_colon)
   6057           {
   6058             if (! process_footers)
   6059               transmit_error_response_static (c,
   6060                                               MHD_HTTP_BAD_REQUEST,
   6061                                               ERR_RSP_HEADER_WITHOUT_COLON);
   6062             else
   6063               transmit_error_response_static (c,
   6064                                               MHD_HTTP_BAD_REQUEST,
   6065                                               ERR_RSP_FOOTER_WITHOUT_COLON);
   6066 
   6067             return MHD_HDR_LINE_READING_DATA_ERROR; /* Error in the request */
   6068           }
   6069           /* Skip broken line completely */
   6070           c->rq.skipped_broken_lines++;
   6071           skip_line = true;
   6072         }
   6073         if (skip_line)
   6074         {
   6075           /* Skip the entire line */
   6076           c->read_buffer += line_len;
   6077           c->read_buffer_offset -= line_len;
   6078           c->read_buffer_size -= line_len;
   6079           p = 0;
   6080           /* Reset processing state */
   6081           memset (&c->rq.hdrs.hdr, 0, sizeof(c->rq.hdrs.hdr));
   6082           /* Start processing of the next line */
   6083           continue;
   6084         }
   6085         else
   6086         {
   6087           /* This line should be valid header line */
   6088           size_t value_len;
   6089           mhd_assert ((0 != c->rq.hdrs.hdr.name_len) || allow_empty_name);
   6090 
   6091           hdr_name->str = c->read_buffer + 0; /* The name always starts at the first character */
   6092           hdr_name->len = c->rq.hdrs.hdr.name_len;
   6093           mhd_assert (0 == hdr_name->str[hdr_name->len]);
   6094 
   6095           if (0 == c->rq.hdrs.hdr.value_start)
   6096           {
   6097             c->rq.hdrs.hdr.value_start = p;
   6098             c->read_buffer[p] = 0;
   6099             value_len = 0;
   6100           }
   6101           else if (0 != c->rq.hdrs.hdr.ws_start)
   6102           {
   6103             mhd_assert (p > c->rq.hdrs.hdr.ws_start);
   6104             mhd_assert (c->rq.hdrs.hdr.ws_start > c->rq.hdrs.hdr.value_start);
   6105             c->read_buffer[c->rq.hdrs.hdr.ws_start] = 0;
   6106             value_len = c->rq.hdrs.hdr.ws_start - c->rq.hdrs.hdr.value_start;
   6107           }
   6108           else
   6109           {
   6110             mhd_assert (p > c->rq.hdrs.hdr.ws_start);
   6111             c->read_buffer[p] = 0;
   6112             value_len = p - c->rq.hdrs.hdr.value_start;
   6113           }
   6114           hdr_value->str = c->read_buffer + c->rq.hdrs.hdr.value_start;
   6115           hdr_value->len = value_len;
   6116           mhd_assert (0 == hdr_value->str[hdr_value->len]);
   6117           /* Consume the entire line */
   6118           c->read_buffer += line_len;
   6119           c->read_buffer_offset -= line_len;
   6120           c->read_buffer_size -= line_len;
   6121           return MHD_HDR_LINE_READING_GOT_HEADER;
   6122         }
   6123       }
   6124     }
   6125     else if ((' ' == chr) || ('\t' == chr))
   6126     {
   6127       if (0 == p)
   6128       {
   6129         if (! allow_wsp_at_start)
   6130         {
   6131           if (! process_footers)
   6132             transmit_error_response_static (c,
   6133                                             MHD_HTTP_BAD_REQUEST,
   6134                                             ERR_RSP_WSP_BEFORE_HEADER);
   6135           else
   6136             transmit_error_response_static (c,
   6137                                             MHD_HTTP_BAD_REQUEST,
   6138                                             ERR_RSP_WSP_BEFORE_FOOTER);
   6139           return MHD_HDR_LINE_READING_DATA_ERROR; /* Error in the request */
   6140         }
   6141         c->rq.hdrs.hdr.starts_with_ws = true;
   6142       }
   6143       else if ((! c->rq.hdrs.hdr.name_end_found) &&
   6144                (! c->rq.hdrs.hdr.starts_with_ws))
   6145       {
   6146         /* Whitespace in header name / between header name and colon */
   6147         if (allow_wsp_in_name || allow_wsp_before_colon)
   6148         {
   6149           if (0 == c->rq.hdrs.hdr.ws_start)
   6150             c->rq.hdrs.hdr.ws_start = p;
   6151         }
   6152         else
   6153         {
   6154           if (! process_footers)
   6155             transmit_error_response_static (c,
   6156                                             MHD_HTTP_BAD_REQUEST,
   6157                                             ERR_RSP_WSP_IN_HEADER_NAME);
   6158           else
   6159             transmit_error_response_static (c,
   6160                                             MHD_HTTP_BAD_REQUEST,
   6161                                             ERR_RSP_WSP_IN_FOOTER_NAME);
   6162 
   6163           return MHD_HDR_LINE_READING_DATA_ERROR; /* Error in the request */
   6164         }
   6165       }
   6166       else
   6167       {
   6168         /* Whitespace before/inside/after header (field) value */
   6169         if (0 == c->rq.hdrs.hdr.ws_start)
   6170           c->rq.hdrs.hdr.ws_start = p;
   6171       }
   6172     }
   6173     else if (0 == chr)
   6174     {
   6175       if (! nul_as_sp)
   6176       {
   6177         if (! process_footers)
   6178           transmit_error_response_static (c,
   6179                                           MHD_HTTP_BAD_REQUEST,
   6180                                           ERR_RSP_INVALID_CHR_IN_HEADER);
   6181         else
   6182           transmit_error_response_static (c,
   6183                                           MHD_HTTP_BAD_REQUEST,
   6184                                           ERR_RSP_INVALID_CHR_IN_FOOTER);
   6185 
   6186         return MHD_HDR_LINE_READING_DATA_ERROR; /* Error in the request */
   6187       }
   6188       c->read_buffer[p] = ' ';
   6189       continue; /* Re-start processing of the current character */
   6190     }
   6191     else
   6192     {
   6193       /* Not a whitespace, not the end of the header line */
   6194       mhd_assert ('\r' != chr);
   6195       mhd_assert ('\n' != chr);
   6196       mhd_assert ('\0' != chr);
   6197       if ( (! c->rq.hdrs.hdr.name_end_found) &&
   6198            (! c->rq.hdrs.hdr.starts_with_ws) )
   6199       {
   6200         /* Processing the header (field) name */
   6201         if ( (! allow_extended_charset) &&
   6202              (':' != chr) &&
   6203              (! char_legal_in_field_name (chr)) )
   6204         {
   6205           transmit_error_response_static (c,
   6206                                           MHD_HTTP_BAD_REQUEST,
   6207                                           ERR_RSP_INVALID_CHAR_IN_FIELD_NAME);
   6208           return MHD_HDR_LINE_READING_DATA_ERROR;
   6209         }
   6210 
   6211         if (':' == chr)
   6212         {
   6213           if (0 == c->rq.hdrs.hdr.ws_start)
   6214             c->rq.hdrs.hdr.name_len = p;
   6215           else
   6216           {
   6217             mhd_assert (allow_wsp_in_name || allow_wsp_before_colon);
   6218             if (! allow_wsp_before_colon)
   6219             {
   6220               if (! process_footers)
   6221                 transmit_error_response_static (c,
   6222                                                 MHD_HTTP_BAD_REQUEST,
   6223                                                 ERR_RSP_WSP_IN_HEADER_NAME);
   6224               else
   6225                 transmit_error_response_static (c,
   6226                                                 MHD_HTTP_BAD_REQUEST,
   6227                                                 ERR_RSP_WSP_IN_FOOTER_NAME);
   6228               return MHD_HDR_LINE_READING_DATA_ERROR; /* Error in the request */
   6229             }
   6230             c->rq.hdrs.hdr.name_len = c->rq.hdrs.hdr.ws_start;
   6231 #ifndef MHD_FAVOR_SMALL_CODE
   6232             c->rq.hdrs.hdr.ws_start = 0; /* Not on whitespace anymore */
   6233 #endif /* ! MHD_FAVOR_SMALL_CODE */
   6234           }
   6235           if ((0 == c->rq.hdrs.hdr.name_len) && ! allow_empty_name)
   6236           {
   6237             if (! process_footers)
   6238               transmit_error_response_static (c,
   6239                                               MHD_HTTP_BAD_REQUEST,
   6240                                               ERR_RSP_EMPTY_HEADER_NAME);
   6241             else
   6242               transmit_error_response_static (c,
   6243                                               MHD_HTTP_BAD_REQUEST,
   6244                                               ERR_RSP_EMPTY_FOOTER_NAME);
   6245             return MHD_HDR_LINE_READING_DATA_ERROR; /* Error in the request */
   6246           }
   6247           c->rq.hdrs.hdr.name_end_found = true;
   6248           c->read_buffer[c->rq.hdrs.hdr.name_len] = 0; /* Zero-terminate the name */
   6249         }
   6250         else
   6251         {
   6252           if (0 != c->rq.hdrs.hdr.ws_start)
   6253           {
   6254             /* End of the whitespace in header (field) name */
   6255             mhd_assert (allow_wsp_in_name || allow_wsp_before_colon);
   6256             if (! allow_wsp_in_name)
   6257             {
   6258               if (! process_footers)
   6259                 transmit_error_response_static (c,
   6260                                                 MHD_HTTP_BAD_REQUEST,
   6261                                                 ERR_RSP_WSP_IN_HEADER_NAME);
   6262               else
   6263                 transmit_error_response_static (c,
   6264                                                 MHD_HTTP_BAD_REQUEST,
   6265                                                 ERR_RSP_WSP_IN_FOOTER_NAME);
   6266 
   6267               return MHD_HDR_LINE_READING_DATA_ERROR; /* Error in the request */
   6268             }
   6269 #ifndef MHD_FAVOR_SMALL_CODE
   6270             c->rq.hdrs.hdr.ws_start = 0; /* Not on whitespace anymore */
   6271 #endif /* ! MHD_FAVOR_SMALL_CODE */
   6272           }
   6273         }
   6274       }
   6275       else
   6276       {
   6277         /* Processing the header (field) value */
   6278         if (0 == c->rq.hdrs.hdr.value_start)
   6279           c->rq.hdrs.hdr.value_start = p;
   6280 #ifndef MHD_FAVOR_SMALL_CODE
   6281         c->rq.hdrs.hdr.ws_start = 0; /* Not on whitespace anymore */
   6282 #endif /* ! MHD_FAVOR_SMALL_CODE */
   6283       }
   6284 #ifdef MHD_FAVOR_SMALL_CODE
   6285       c->rq.hdrs.hdr.ws_start = 0; /* Not on whitespace anymore */
   6286 #endif /* MHD_FAVOR_SMALL_CODE */
   6287     }
   6288     p++;
   6289   }
   6290   c->rq.hdrs.hdr.proc_pos = p;
   6291   return MHD_HDR_LINE_READING_NEED_MORE_DATA; /* Not enough data yet */
   6292 }
   6293 
   6294 
   6295 /**
   6296  * Find the end of the request headers and make basic header parsing.
   6297  * Advance to the next state when done, handle errors.
   6298  * @param c the connection to process
   6299  * @param process_footers if true then footers are processed,
   6300  *                        if false then headers are processed
   6301  * @return true if request headers reading finished (either successfully
   6302  *         or with error),
   6303  *         false if not enough data yet in the receive buffer
   6304  */
   6305 static bool
   6306 get_req_headers (struct MHD_Connection *c, bool process_footers)
   6307 {
   6308   do
   6309   {
   6310     struct _MHD_str_w_len hdr_name;
   6311     struct _MHD_str_w_len hdr_value;
   6312     enum MHD_HdrLineReadRes_ res;
   6313 
   6314     mhd_assert ((process_footers ? MHD_CONNECTION_FOOTERS_RECEIVING : \
   6315                  MHD_CONNECTION_REQ_HEADERS_RECEIVING) == \
   6316                 c->state);
   6317 
   6318     #ifdef _DEBUG
   6319     hdr_name.str = NULL;
   6320     hdr_value.str = NULL;
   6321 #endif /* _DEBUG */
   6322     res = get_req_header (c, process_footers, &hdr_name, &hdr_value);
   6323     if (MHD_HDR_LINE_READING_GOT_HEADER == res)
   6324     {
   6325       mhd_assert ((process_footers ? MHD_CONNECTION_FOOTERS_RECEIVING : \
   6326                    MHD_CONNECTION_REQ_HEADERS_RECEIVING) == \
   6327                   c->state);
   6328       mhd_assert (NULL != hdr_name.str);
   6329       mhd_assert (NULL != hdr_value.str);
   6330       /* Values must be zero-terminated and must not have binary zeros */
   6331       mhd_assert (strlen (hdr_name.str) == hdr_name.len);
   6332       mhd_assert (strlen (hdr_value.str) == hdr_value.len);
   6333       /* Values must not have whitespaces at the start or at the end */
   6334       mhd_assert ((hdr_name.len == 0) || (hdr_name.str[0] != ' '));
   6335       mhd_assert ((hdr_name.len == 0) || (hdr_name.str[0] != '\t'));
   6336       mhd_assert ((hdr_name.len == 0) || \
   6337                   (hdr_name.str[hdr_name.len - 1] != ' '));
   6338       mhd_assert ((hdr_name.len == 0) || \
   6339                   (hdr_name.str[hdr_name.len - 1] != '\t'));
   6340       mhd_assert ((hdr_value.len == 0) || (hdr_value.str[0] != ' '));
   6341       mhd_assert ((hdr_value.len == 0) || (hdr_value.str[0] != '\t'));
   6342       mhd_assert ((hdr_value.len == 0) || \
   6343                   (hdr_value.str[hdr_value.len - 1] != ' '));
   6344       mhd_assert ((hdr_value.len == 0) || \
   6345                   (hdr_value.str[hdr_value.len - 1] != '\t'));
   6346 
   6347       if (MHD_NO ==
   6348           MHD_set_connection_value_n_nocheck_ (c,
   6349                                                (! process_footers) ?
   6350                                                MHD_HEADER_KIND :
   6351                                                MHD_FOOTER_KIND,
   6352                                                hdr_name.str, hdr_name.len,
   6353                                                hdr_value.str, hdr_value.len))
   6354       {
   6355         size_t add_element_size;
   6356 
   6357         mhd_assert (hdr_name.str < hdr_value.str);
   6358 
   6359 #ifdef HAVE_MESSAGES
   6360         MHD_DLOG (c->daemon,
   6361                   _ ("Failed to allocate memory in the connection memory " \
   6362                      "pool to store %s.\n"),
   6363                   (! process_footers) ? _ ("header") : _ ("footer"));
   6364 #endif /* HAVE_MESSAGES */
   6365 
   6366         add_element_size = hdr_value.len
   6367                            + (size_t) (hdr_value.str - hdr_name.str);
   6368 
   6369         if (! process_footers)
   6370           handle_req_headers_no_space (c, hdr_name.str, add_element_size);
   6371         else
   6372           handle_req_footers_no_space (c, hdr_name.str, add_element_size);
   6373 
   6374         mhd_assert (MHD_CONNECTION_FULL_REQ_RECEIVED < c->state);
   6375         return true;
   6376       }
   6377       /* Reset processing state */
   6378       reset_rq_header_processing_state (c);
   6379       mhd_assert ((process_footers ? MHD_CONNECTION_FOOTERS_RECEIVING : \
   6380                    MHD_CONNECTION_REQ_HEADERS_RECEIVING) == \
   6381                   c->state);
   6382       /* Read the next header (field) line */
   6383       continue;
   6384     }
   6385     else if (MHD_HDR_LINE_READING_NEED_MORE_DATA == res)
   6386     {
   6387       mhd_assert ((process_footers ? MHD_CONNECTION_FOOTERS_RECEIVING : \
   6388                    MHD_CONNECTION_REQ_HEADERS_RECEIVING) == \
   6389                   c->state);
   6390       return false;
   6391     }
   6392     else if (MHD_HDR_LINE_READING_DATA_ERROR == res)
   6393     {
   6394       mhd_assert ((process_footers ? \
   6395                    MHD_CONNECTION_FOOTERS_RECEIVING : \
   6396                    MHD_CONNECTION_REQ_HEADERS_RECEIVING) < c->state);
   6397       mhd_assert (c->stop_with_error);
   6398       mhd_assert (c->discard_request);
   6399       return true;
   6400     }
   6401     mhd_assert (MHD_HDR_LINE_READING_GOT_END_OF_HEADER == res);
   6402     break;
   6403   } while (1);
   6404 
   6405 #ifdef HAVE_MESSAGES
   6406   if (1 == c->rq.num_cr_sp_replaced)
   6407   {
   6408     MHD_DLOG (c->daemon,
   6409               _ ("One bare CR character has been replaced with space " \
   6410                  "in %s.\n"),
   6411               (! process_footers) ?
   6412               _ ("the request line or in the request headers") :
   6413               _ ("the request footers"));
   6414   }
   6415   else if (0 != c->rq.num_cr_sp_replaced)
   6416   {
   6417     MHD_DLOG (c->daemon,
   6418               _ ("%" PRIu64 " bare CR characters have been replaced with " \
   6419                  "spaces in the request line and/or in the request %s.\n"),
   6420               (uint64_t) c->rq.num_cr_sp_replaced,
   6421               (! process_footers) ? _ ("headers") : _ ("footers"));
   6422   }
   6423   if (1 == c->rq.skipped_broken_lines)
   6424   {
   6425     MHD_DLOG (c->daemon,
   6426               _ ("One %s line without colon has been skipped.\n"),
   6427               (! process_footers) ? _ ("header") : _ ("footer"));
   6428   }
   6429   else if (0 != c->rq.skipped_broken_lines)
   6430   {
   6431     MHD_DLOG (c->daemon,
   6432               _ ("%" PRIu64 " %s lines without colons has been skipped.\n"),
   6433               (uint64_t) c->rq.skipped_broken_lines,
   6434               (! process_footers) ? _ ("header") : _ ("footer"));
   6435   }
   6436 #endif /* HAVE_MESSAGES */
   6437 
   6438   mhd_assert (c->rq.method < c->read_buffer);
   6439   if (! process_footers)
   6440   {
   6441     c->rq.header_size = (size_t) (c->read_buffer - c->rq.method);
   6442     mhd_assert (NULL != c->rq.field_lines.start);
   6443     c->rq.field_lines.size =
   6444       (size_t) ((c->read_buffer - c->rq.field_lines.start) - 1);
   6445     if ('\r' == *(c->read_buffer - 2))
   6446       c->rq.field_lines.size--;
   6447     c->state = MHD_CONNECTION_HEADERS_RECEIVED;
   6448 
   6449     if (MHD_BUF_INC_SIZE > c->read_buffer_size)
   6450     {
   6451       /* Try to re-use some of the last bytes of the request header */
   6452       /* Do this only if space in the read buffer is limited AND
   6453          amount of read ahead data is small. */
   6454       /**
   6455        *  The position of the terminating NUL after the last character of
   6456        *  the last header element.
   6457        */
   6458       const char *last_elmnt_end;
   6459       size_t shift_back_size;
   6460       if (NULL != c->rq.headers_received_tail)
   6461         last_elmnt_end =
   6462           c->rq.headers_received_tail->value
   6463           + c->rq.headers_received_tail->value_size;
   6464       else
   6465         last_elmnt_end = c->rq.version + HTTP_VER_LEN;
   6466       mhd_assert ((last_elmnt_end + 1) < c->read_buffer);
   6467       shift_back_size = (size_t) (c->read_buffer - (last_elmnt_end + 1));
   6468       if (0 != c->read_buffer_offset)
   6469         memmove (c->read_buffer - shift_back_size,
   6470                  c->read_buffer,
   6471                  c->read_buffer_offset);
   6472       c->read_buffer -= shift_back_size;
   6473       c->read_buffer_size += shift_back_size;
   6474     }
   6475   }
   6476   else
   6477     c->state = MHD_CONNECTION_FOOTERS_RECEIVED;
   6478 
   6479   return true;
   6480 }
   6481 
   6482 
   6483 /**
   6484  * Update the 'last_activity' field of the connection to the current time
   6485  * and move the connection to the head of the 'normal_timeout' list if
   6486  * the timeout for the connection uses the default value.
   6487  *
   6488  * @param connection the connection that saw some activity
   6489  */
   6490 void
   6491 MHD_update_last_activity_ (struct MHD_Connection *connection)
   6492 {
   6493   struct MHD_Daemon *daemon = connection->daemon;
   6494 #if defined(MHD_USE_THREADS)
   6495   mhd_assert (NULL == daemon->worker_pool);
   6496 #endif /* MHD_USE_THREADS */
   6497 
   6498   if (0 == connection->connection_timeout_ms)
   6499     return;  /* Skip update of activity for connections
   6500                without timeout timer. */
   6501   if (connection->suspended)
   6502     return;  /* no activity on suspended connections */
   6503 
   6504   connection->last_activity = MHD_monotonic_msec_counter ();
   6505   if (MHD_D_IS_USING_THREAD_PER_CONN_ (daemon))
   6506     return; /* each connection has personal timeout */
   6507 
   6508   if (connection->connection_timeout_ms != daemon->connection_timeout_ms)
   6509     return; /* custom timeout, no need to move it in "normal" DLL */
   6510 #if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS)
   6511   MHD_mutex_lock_chk_ (&daemon->cleanup_connection_mutex);
   6512 #endif
   6513   /* move connection to head of timeout list (by remove + add operation) */
   6514   XDLL_remove (daemon->normal_timeout_head,
   6515                daemon->normal_timeout_tail,
   6516                connection);
   6517   XDLL_insert (daemon->normal_timeout_head,
   6518                daemon->normal_timeout_tail,
   6519                connection);
   6520 #if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS)
   6521   MHD_mutex_unlock_chk_ (&daemon->cleanup_connection_mutex);
   6522 #endif
   6523 }
   6524 
   6525 
   6526 /**
   6527  * This function handles a particular connection when it has been
   6528  * determined that there is data to be read off a socket. All
   6529  * implementations (multithreaded, external polling, internal polling)
   6530  * call this function to handle reads.
   6531  *
   6532  * @param connection connection to handle
   6533  * @param socket_error set to true if socket error was detected
   6534  */
   6535 void
   6536 MHD_connection_handle_read (struct MHD_Connection *connection,
   6537                             bool socket_error)
   6538 {
   6539   ssize_t bytes_read;
   6540 
   6541   if ( (MHD_CONNECTION_CLOSED == connection->state) ||
   6542        (connection->suspended) )
   6543     return;
   6544 #ifdef HTTPS_SUPPORT
   6545   if (MHD_TLS_CONN_NO_TLS != connection->tls_state)
   6546   {   /* HTTPS connection. */
   6547     if (MHD_TLS_CONN_CONNECTED > connection->tls_state)
   6548     {
   6549       if (! MHD_run_tls_handshake_ (connection))
   6550         return;
   6551     }
   6552   }
   6553 #endif /* HTTPS_SUPPORT */
   6554 
   6555   mhd_assert (NULL != connection->read_buffer);
   6556   if (connection->read_buffer_size == connection->read_buffer_offset)
   6557     return; /* No space for receiving data. */
   6558 
   6559   bytes_read = connection->recv_cls (connection,
   6560                                      &connection->read_buffer
   6561                                      [connection->read_buffer_offset],
   6562                                      connection->read_buffer_size
   6563                                      - connection->read_buffer_offset);
   6564   if ((bytes_read < 0) || socket_error)
   6565   {
   6566     if ((MHD_ERR_AGAIN_ == bytes_read) && ! socket_error)
   6567       return;     /* No new data to process. */
   6568     if ((bytes_read > 0) && connection->sk_nonblck)
   6569     { /* Try to detect the socket error */
   6570       int dummy;
   6571       bytes_read = connection->recv_cls (connection, &dummy, sizeof (dummy));
   6572     }
   6573     if (MHD_ERR_CONNRESET_ == bytes_read)
   6574     {
   6575       if ( (MHD_CONNECTION_INIT < connection->state) &&
   6576            (MHD_CONNECTION_FULL_REQ_RECEIVED > connection->state) )
   6577       {
   6578 #ifdef HAVE_MESSAGES
   6579         MHD_DLOG (connection->daemon,
   6580                   _ ("Socket has been disconnected when reading request.\n"));
   6581 #endif
   6582         connection->discard_request = true;
   6583       }
   6584       MHD_connection_close_ (connection,
   6585                              MHD_REQUEST_TERMINATED_READ_ERROR);
   6586       return;
   6587     }
   6588 
   6589 #ifdef HAVE_MESSAGES
   6590     if (MHD_CONNECTION_INIT != connection->state)
   6591       MHD_DLOG (connection->daemon,
   6592                 _ ("Connection socket is closed when reading " \
   6593                    "request due to the error: %s\n"),
   6594                 (bytes_read < 0) ? str_conn_error_ (bytes_read) :
   6595                 "detected connection closure");
   6596 #endif
   6597     CONNECTION_CLOSE_ERROR (connection,
   6598                             NULL);
   6599     return;
   6600   }
   6601 
   6602   if (0 == bytes_read)
   6603   {   /* Remote side closed connection. */
   6604     connection->read_closed = true;
   6605     if ( (MHD_CONNECTION_INIT < connection->state) &&
   6606          (MHD_CONNECTION_FULL_REQ_RECEIVED > connection->state) )
   6607     {
   6608 #ifdef HAVE_MESSAGES
   6609       MHD_DLOG (connection->daemon,
   6610                 _ ("Connection was closed by remote side with incomplete "
   6611                    "request.\n"));
   6612 #endif
   6613       connection->discard_request = true;
   6614       MHD_connection_close_ (connection,
   6615                              MHD_REQUEST_TERMINATED_CLIENT_ABORT);
   6616     }
   6617     else if (MHD_CONNECTION_INIT == connection->state)
   6618       /* This termination code cannot be reported to the application
   6619        * because application has not been informed yet about this request */
   6620       MHD_connection_close_ (connection,
   6621                              MHD_REQUEST_TERMINATED_COMPLETED_OK);
   6622     else
   6623       MHD_connection_close_ (connection,
   6624                              MHD_REQUEST_TERMINATED_WITH_ERROR);
   6625     return;
   6626   }
   6627   connection->read_buffer_offset += (size_t) bytes_read;
   6628   MHD_update_last_activity_ (connection);
   6629 #if DEBUG_STATES
   6630   MHD_DLOG (connection->daemon,
   6631             _ ("In function %s handling connection at state: %s\n"),
   6632             MHD_FUNC_,
   6633             MHD_state_to_string (connection->state));
   6634 #endif
   6635   /* TODO: check whether the next 'switch()' really needed */
   6636   switch (connection->state)
   6637   {
   6638   case MHD_CONNECTION_INIT:
   6639   case MHD_CONNECTION_REQ_LINE_RECEIVING:
   6640   case MHD_CONNECTION_REQ_HEADERS_RECEIVING:
   6641   case MHD_CONNECTION_BODY_RECEIVING:
   6642   case MHD_CONNECTION_FOOTERS_RECEIVING:
   6643   case MHD_CONNECTION_FULL_REQ_RECEIVED:
   6644     /* nothing to do but default action */
   6645     if (connection->read_closed)
   6646     {
   6647       /* TODO: check whether this really needed */
   6648       MHD_connection_close_ (connection,
   6649                              MHD_REQUEST_TERMINATED_READ_ERROR);
   6650     }
   6651     return;
   6652   case MHD_CONNECTION_CLOSED:
   6653     return;
   6654 #ifdef UPGRADE_SUPPORT
   6655   case MHD_CONNECTION_UPGRADE:
   6656     mhd_assert (0);
   6657     return;
   6658 #endif /* UPGRADE_SUPPORT */
   6659   case MHD_CONNECTION_START_REPLY:
   6660     /* shrink read buffer to how much is actually used */
   6661     /* TODO: remove shrink as it handled in special function */
   6662     if ((0 != connection->read_buffer_size) &&
   6663         (connection->read_buffer_size != connection->read_buffer_offset))
   6664     {
   6665       mhd_assert (NULL != connection->read_buffer);
   6666       connection->read_buffer =
   6667         MHD_pool_reallocate (connection->pool,
   6668                              connection->read_buffer,
   6669                              connection->read_buffer_size,
   6670                              connection->read_buffer_offset);
   6671       connection->read_buffer_size = connection->read_buffer_offset;
   6672     }
   6673     break;
   6674   case MHD_CONNECTION_REQ_LINE_RECEIVED:
   6675   case MHD_CONNECTION_HEADERS_RECEIVED:
   6676   case MHD_CONNECTION_HEADERS_PROCESSED:
   6677   case MHD_CONNECTION_BODY_RECEIVED:
   6678   case MHD_CONNECTION_FOOTERS_RECEIVED:
   6679     /* Milestone state, no data should be read */
   6680     mhd_assert (0); /* Should not be possible */
   6681     break;
   6682   case MHD_CONNECTION_CONTINUE_SENDING:
   6683   case MHD_CONNECTION_HEADERS_SENDING:
   6684   case MHD_CONNECTION_HEADERS_SENT:
   6685   case MHD_CONNECTION_NORMAL_BODY_UNREADY:
   6686   case MHD_CONNECTION_NORMAL_BODY_READY:
   6687   case MHD_CONNECTION_CHUNKED_BODY_UNREADY:
   6688   case MHD_CONNECTION_CHUNKED_BODY_READY:
   6689   case MHD_CONNECTION_CHUNKED_BODY_SENT:
   6690   case MHD_CONNECTION_FOOTERS_SENDING:
   6691   case MHD_CONNECTION_FULL_REPLY_SENT:
   6692   default:
   6693     mhd_assert (0); /* Should not be possible */
   6694     break;
   6695   }
   6696   return;
   6697 }
   6698 
   6699 
   6700 /**
   6701  * This function was created to handle writes to sockets when it has
   6702  * been determined that the socket can be written to. All
   6703  * implementations (multithreaded, external select, internal select)
   6704  * call this function
   6705  *
   6706  * @param connection connection to handle
   6707  */
   6708 void
   6709 MHD_connection_handle_write (struct MHD_Connection *connection)
   6710 {
   6711   struct MHD_Response *response;
   6712   ssize_t ret;
   6713   if (connection->suspended)
   6714     return;
   6715 
   6716 #ifdef HTTPS_SUPPORT
   6717   if (MHD_TLS_CONN_NO_TLS != connection->tls_state)
   6718   {   /* HTTPS connection. */
   6719     if (MHD_TLS_CONN_CONNECTED > connection->tls_state)
   6720     {
   6721       if (! MHD_run_tls_handshake_ (connection))
   6722         return;
   6723     }
   6724   }
   6725 #endif /* HTTPS_SUPPORT */
   6726 
   6727 #if DEBUG_STATES
   6728   MHD_DLOG (connection->daemon,
   6729             _ ("In function %s handling connection at state: %s\n"),
   6730             MHD_FUNC_,
   6731             MHD_state_to_string (connection->state));
   6732 #endif
   6733   switch (connection->state)
   6734   {
   6735   case MHD_CONNECTION_INIT:
   6736   case MHD_CONNECTION_REQ_LINE_RECEIVING:
   6737   case MHD_CONNECTION_REQ_LINE_RECEIVED:
   6738   case MHD_CONNECTION_REQ_HEADERS_RECEIVING:
   6739   case MHD_CONNECTION_HEADERS_RECEIVED:
   6740   case MHD_CONNECTION_HEADERS_PROCESSED:
   6741     mhd_assert (0);
   6742     return;
   6743   case MHD_CONNECTION_CONTINUE_SENDING:
   6744     ret = MHD_send_data_ (connection,
   6745                           &HTTP_100_CONTINUE
   6746                           [connection->continue_message_write_offset],
   6747                           MHD_STATICSTR_LEN_ (HTTP_100_CONTINUE)
   6748                           - connection->continue_message_write_offset,
   6749                           true);
   6750     if (ret < 0)
   6751     {
   6752       if (MHD_ERR_AGAIN_ == ret)
   6753         return;
   6754 #ifdef HAVE_MESSAGES
   6755       MHD_DLOG (connection->daemon,
   6756                 _ ("Failed to send data in request for %s.\n"),
   6757                 connection->rq.url);
   6758 #endif
   6759       CONNECTION_CLOSE_ERROR (connection,
   6760                               NULL);
   6761       return;
   6762     }
   6763 #if _MHD_DEBUG_SEND_DATA
   6764     fprintf (stderr,
   6765              _ ("Sent 100 continue response: `%.*s'\n"),
   6766              (int) ret,
   6767              &HTTP_100_CONTINUE[connection->continue_message_write_offset]);
   6768 #endif
   6769     connection->continue_message_write_offset += (size_t) ret;
   6770     MHD_update_last_activity_ (connection);
   6771     return;
   6772   case MHD_CONNECTION_BODY_RECEIVING:
   6773   case MHD_CONNECTION_BODY_RECEIVED:
   6774   case MHD_CONNECTION_FOOTERS_RECEIVING:
   6775   case MHD_CONNECTION_FOOTERS_RECEIVED:
   6776   case MHD_CONNECTION_FULL_REQ_RECEIVED:
   6777     mhd_assert (0);
   6778     return;
   6779   case MHD_CONNECTION_START_REPLY:
   6780     mhd_assert (0);
   6781     return;
   6782   case MHD_CONNECTION_HEADERS_SENDING:
   6783     {
   6784       struct MHD_Response *const resp = connection->rp.response;
   6785       const size_t wb_ready = connection->write_buffer_append_offset
   6786                               - connection->write_buffer_send_offset;
   6787       mhd_assert (connection->write_buffer_append_offset >= \
   6788                   connection->write_buffer_send_offset);
   6789       mhd_assert (NULL != resp);
   6790       mhd_assert ( (0 == resp->data_size) || \
   6791                    (0 == resp->data_start) || \
   6792                    (NULL != resp->crc) );
   6793       mhd_assert ( (0 == connection->rp.rsp_write_position) || \
   6794                    (resp->total_size ==
   6795                     connection->rp.rsp_write_position) );
   6796       mhd_assert ((MHD_CONN_MUST_UPGRADE != connection->keepalive) || \
   6797                   (! connection->rp.props.send_reply_body));
   6798 
   6799       if ( (connection->rp.props.send_reply_body) &&
   6800            (NULL == resp->crc) &&
   6801            (NULL == resp->data_iov) &&
   6802            /* TODO: remove the next check as 'send_reply_body' is used */
   6803            (0 == connection->rp.rsp_write_position) &&
   6804            (! connection->rp.props.chunked) )
   6805       {
   6806         mhd_assert (resp->total_size >= resp->data_size);
   6807         mhd_assert (0 == resp->data_start);
   6808         /* Send response headers alongside the response body, if the body
   6809          * data is available. */
   6810         ret = MHD_send_hdr_and_body_ (connection,
   6811                                       &connection->write_buffer
   6812                                       [connection->write_buffer_send_offset],
   6813                                       wb_ready,
   6814                                       false,
   6815                                       resp->data,
   6816                                       resp->data_size,
   6817                                       (resp->total_size == resp->data_size));
   6818       }
   6819       else
   6820       {
   6821         /* This is response for HEAD request or reply body is not allowed
   6822          * for any other reason or reply body is dynamically generated. */
   6823         /* Do not send the body data even if it's available. */
   6824         ret = MHD_send_hdr_and_body_ (connection,
   6825                                       &connection->write_buffer
   6826                                       [connection->write_buffer_send_offset],
   6827                                       wb_ready,
   6828                                       false,
   6829                                       NULL,
   6830                                       0,
   6831                                       ((0 == resp->total_size) ||
   6832                                        (! connection->rp.props.send_reply_body)
   6833                                       ));
   6834       }
   6835 
   6836       if (ret < 0)
   6837       {
   6838         if (MHD_ERR_AGAIN_ == ret)
   6839           return;
   6840 #ifdef HAVE_MESSAGES
   6841         MHD_DLOG (connection->daemon,
   6842                   _ ("Failed to send the response headers for the " \
   6843                      "request for `%s'. Error: %s\n"),
   6844                   connection->rq.url,
   6845                   str_conn_error_ (ret));
   6846 #endif
   6847         CONNECTION_CLOSE_ERROR (connection,
   6848                                 NULL);
   6849         return;
   6850       }
   6851       /* 'ret' is not negative, it's safe to cast it to 'size_t'. */
   6852       if (((size_t) ret) > wb_ready)
   6853       {
   6854         /* The complete header and some response data have been sent,
   6855          * update both offsets. */
   6856         mhd_assert (0 == connection->rp.rsp_write_position);
   6857         mhd_assert (! connection->rp.props.chunked);
   6858         mhd_assert (connection->rp.props.send_reply_body);
   6859         connection->write_buffer_send_offset += wb_ready;
   6860         connection->rp.rsp_write_position = ((size_t) ret) - wb_ready;
   6861       }
   6862       else
   6863         connection->write_buffer_send_offset += (size_t) ret;
   6864       MHD_update_last_activity_ (connection);
   6865       if (MHD_CONNECTION_HEADERS_SENDING != connection->state)
   6866         return;
   6867       check_write_done (connection,
   6868                         MHD_CONNECTION_HEADERS_SENT);
   6869       return;
   6870     }
   6871   case MHD_CONNECTION_HEADERS_SENT:
   6872     return;
   6873   case MHD_CONNECTION_NORMAL_BODY_READY:
   6874     response = connection->rp.response;
   6875     if (connection->rp.rsp_write_position <
   6876         connection->rp.response->total_size)
   6877     {
   6878       uint64_t data_write_offset;
   6879 
   6880 #if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS)
   6881       if (NULL != response->crc)
   6882         MHD_mutex_lock_chk_ (&response->mutex);
   6883 #endif
   6884       if (MHD_NO == try_ready_normal_body (connection))
   6885       {
   6886         /* mutex was already unlocked by try_ready_normal_body */
   6887         return;
   6888       }
   6889 #if defined(_MHD_HAVE_SENDFILE)
   6890       if (MHD_resp_sender_sendfile == connection->rp.resp_sender)
   6891       {
   6892         mhd_assert (NULL == response->data_iov);
   6893         ret = MHD_send_sendfile_ (connection);
   6894       }
   6895       else /* combined with the next 'if' */
   6896 #endif /* _MHD_HAVE_SENDFILE */
   6897       if (NULL != response->data_iov)
   6898       {
   6899         ret = MHD_send_iovec_ (connection,
   6900                                &connection->rp.resp_iov,
   6901                                true);
   6902       }
   6903       else
   6904       {
   6905         data_write_offset = connection->rp.rsp_write_position
   6906                             - response->data_start;
   6907         if (data_write_offset > (uint64_t) SIZE_MAX)
   6908           MHD_PANIC (_ ("Data offset exceeds limit.\n"));
   6909         ret = MHD_send_data_ (connection,
   6910                               &response->data
   6911                               [(size_t) data_write_offset],
   6912                               response->data_size
   6913                               - (size_t) data_write_offset,
   6914                               true);
   6915 #if _MHD_DEBUG_SEND_DATA
   6916         if (ret > 0)
   6917           fprintf (stderr,
   6918                    _ ("Sent %d-byte DATA response: `%.*s'\n"),
   6919                    (int) ret,
   6920                    (int) ret,
   6921                    &rp.response->data[connection->rp.rsp_write_position
   6922                                       - rp.response->data_start]);
   6923 #endif
   6924       }
   6925 #if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS)
   6926       if (NULL != response->crc)
   6927         MHD_mutex_unlock_chk_ (&response->mutex);
   6928 #endif
   6929       if (ret < 0)
   6930       {
   6931         if (MHD_ERR_AGAIN_ == ret)
   6932           return;
   6933 #ifdef HAVE_MESSAGES
   6934         MHD_DLOG (connection->daemon,
   6935                   _ ("Failed to send the response body for the " \
   6936                      "request for `%s'. Error: %s\n"),
   6937                   connection->rq.url,
   6938                   str_conn_error_ (ret));
   6939 #endif
   6940         CONNECTION_CLOSE_ERROR (connection,
   6941                                 NULL);
   6942         return;
   6943       }
   6944       connection->rp.rsp_write_position += (size_t) ret;
   6945       MHD_update_last_activity_ (connection);
   6946     }
   6947     if (connection->rp.rsp_write_position ==
   6948         connection->rp.response->total_size)
   6949       connection->state = MHD_CONNECTION_FULL_REPLY_SENT;
   6950     return;
   6951   case MHD_CONNECTION_NORMAL_BODY_UNREADY:
   6952     mhd_assert (0);
   6953     return;
   6954   case MHD_CONNECTION_CHUNKED_BODY_READY:
   6955     ret = MHD_send_data_ (connection,
   6956                           &connection->write_buffer
   6957                           [connection->write_buffer_send_offset],
   6958                           connection->write_buffer_append_offset
   6959                           - connection->write_buffer_send_offset,
   6960                           true);
   6961     if (ret < 0)
   6962     {
   6963       if (MHD_ERR_AGAIN_ == ret)
   6964         return;
   6965 #ifdef HAVE_MESSAGES
   6966       MHD_DLOG (connection->daemon,
   6967                 _ ("Failed to send the chunked response body for the " \
   6968                    "request for `%s'. Error: %s\n"),
   6969                 connection->rq.url,
   6970                 str_conn_error_ (ret));
   6971 #endif
   6972       CONNECTION_CLOSE_ERROR (connection,
   6973                               NULL);
   6974       return;
   6975     }
   6976     connection->write_buffer_send_offset += (size_t) ret;
   6977     MHD_update_last_activity_ (connection);
   6978     if (MHD_CONNECTION_CHUNKED_BODY_READY != connection->state)
   6979       return;
   6980     check_write_done (connection,
   6981                       (connection->rp.response->total_size ==
   6982                        connection->rp.rsp_write_position) ?
   6983                       MHD_CONNECTION_CHUNKED_BODY_SENT :
   6984                       MHD_CONNECTION_CHUNKED_BODY_UNREADY);
   6985     return;
   6986   case MHD_CONNECTION_CHUNKED_BODY_UNREADY:
   6987   case MHD_CONNECTION_CHUNKED_BODY_SENT:
   6988     mhd_assert (0);
   6989     return;
   6990   case MHD_CONNECTION_FOOTERS_SENDING:
   6991     ret = MHD_send_data_ (connection,
   6992                           &connection->write_buffer
   6993                           [connection->write_buffer_send_offset],
   6994                           connection->write_buffer_append_offset
   6995                           - connection->write_buffer_send_offset,
   6996                           true);
   6997     if (ret < 0)
   6998     {
   6999       if (MHD_ERR_AGAIN_ == ret)
   7000         return;
   7001 #ifdef HAVE_MESSAGES
   7002       MHD_DLOG (connection->daemon,
   7003                 _ ("Failed to send the footers for the " \
   7004                    "request for `%s'. Error: %s\n"),
   7005                 connection->rq.url,
   7006                 str_conn_error_ (ret));
   7007 #endif
   7008       CONNECTION_CLOSE_ERROR (connection,
   7009                               NULL);
   7010       return;
   7011     }
   7012     connection->write_buffer_send_offset += (size_t) ret;
   7013     MHD_update_last_activity_ (connection);
   7014     if (MHD_CONNECTION_FOOTERS_SENDING != connection->state)
   7015       return;
   7016     check_write_done (connection,
   7017                       MHD_CONNECTION_FULL_REPLY_SENT);
   7018     return;
   7019   case MHD_CONNECTION_FULL_REPLY_SENT:
   7020     mhd_assert (0);
   7021     return;
   7022   case MHD_CONNECTION_CLOSED:
   7023     return;
   7024 #ifdef UPGRADE_SUPPORT
   7025   case MHD_CONNECTION_UPGRADE:
   7026     mhd_assert (0);
   7027     return;
   7028 #endif /* UPGRADE_SUPPORT */
   7029   default:
   7030     mhd_assert (0);
   7031     CONNECTION_CLOSE_ERROR (connection,
   7032                             _ ("Internal error.\n"));
   7033     break;
   7034   }
   7035   return;
   7036 }
   7037 
   7038 
   7039 /**
   7040  * Check whether connection has timed out.
   7041  * @param c the connection to check
   7042  * @return true if connection has timeout and needs to be closed,
   7043  *         false otherwise.
   7044  */
   7045 static bool
   7046 connection_check_timedout (struct MHD_Connection *c)
   7047 {
   7048   const uint64_t timeout = c->connection_timeout_ms;
   7049   uint64_t now;
   7050   uint64_t since_actv;
   7051 
   7052   if (c->suspended)
   7053     return false;
   7054   if (0 == timeout)
   7055     return false;
   7056   now = MHD_monotonic_msec_counter ();
   7057   since_actv = now - c->last_activity;
   7058   /* Keep the next lines in sync with #connection_get_wait() to avoid
   7059    * undesired side-effects like busy-waiting. */
   7060   if (timeout < since_actv)
   7061   {
   7062     if (UINT64_MAX / 2 < since_actv)
   7063     {
   7064       const uint64_t jump_back = c->last_activity - now;
   7065       /* Very unlikely that it is more than quarter-million years pause.
   7066        * More likely that system clock jumps back. */
   7067       if (5000 >= jump_back)
   7068       {
   7069 #ifdef HAVE_MESSAGES
   7070         MHD_DLOG (c->daemon,
   7071                   _ ("Detected system clock %u milliseconds jump back.\n"),
   7072                   (unsigned int) jump_back);
   7073 #endif
   7074         return false;
   7075       }
   7076 #ifdef HAVE_MESSAGES
   7077       MHD_DLOG (c->daemon,
   7078                 _ ("Detected too large system clock %" PRIu64 " milliseconds "
   7079                    "jump back.\n"),
   7080                 jump_back);
   7081 #endif
   7082     }
   7083     return true;
   7084   }
   7085   return false;
   7086 }
   7087 
   7088 
   7089 /**
   7090  * Clean up the state of the given connection and move it into the
   7091  * clean up queue for final disposal.
   7092  * @remark To be called only from thread that process connection's
   7093  * recv(), send() and response.
   7094  *
   7095  * @param connection handle for the connection to clean up
   7096  */
   7097 static void
   7098 cleanup_connection (struct MHD_Connection *connection)
   7099 {
   7100   struct MHD_Daemon *daemon = connection->daemon;
   7101 #ifdef MHD_USE_THREADS
   7102   mhd_assert ( (! MHD_D_IS_USING_THREADS_ (daemon)) || \
   7103                MHD_thread_handle_ID_is_current_thread_ (connection->tid) );
   7104   mhd_assert (NULL == daemon->worker_pool);
   7105 #endif /* MHD_USE_THREADS */
   7106 
   7107   if (connection->in_cleanup)
   7108     return; /* Prevent double cleanup. */
   7109   connection->in_cleanup = true;
   7110   if (NULL != connection->rp.response)
   7111   {
   7112     MHD_destroy_response (connection->rp.response);
   7113     connection->rp.response = NULL;
   7114   }
   7115 #if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS)
   7116   MHD_mutex_lock_chk_ (&daemon->cleanup_connection_mutex);
   7117 #endif
   7118   if (connection->suspended)
   7119   {
   7120     DLL_remove (daemon->suspended_connections_head,
   7121                 daemon->suspended_connections_tail,
   7122                 connection);
   7123     connection->suspended = false;
   7124   }
   7125   else
   7126   {
   7127     if (! MHD_D_IS_USING_THREAD_PER_CONN_ (daemon))
   7128     {
   7129       if (connection->connection_timeout_ms == daemon->connection_timeout_ms)
   7130         XDLL_remove (daemon->normal_timeout_head,
   7131                      daemon->normal_timeout_tail,
   7132                      connection);
   7133       else
   7134         XDLL_remove (daemon->manual_timeout_head,
   7135                      daemon->manual_timeout_tail,
   7136                      connection);
   7137     }
   7138     DLL_remove (daemon->connections_head,
   7139                 daemon->connections_tail,
   7140                 connection);
   7141   }
   7142   DLL_insert (daemon->cleanup_head,
   7143               daemon->cleanup_tail,
   7144               connection);
   7145   connection->resuming = false;
   7146   connection->in_idle = false;
   7147 #if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS)
   7148   MHD_mutex_unlock_chk_ (&daemon->cleanup_connection_mutex);
   7149 #endif
   7150   if (MHD_D_IS_USING_THREAD_PER_CONN_ (daemon))
   7151   {
   7152     /* if we were at the connection limit before and are in
   7153        thread-per-connection mode, signal the main thread
   7154        to resume accepting connections */
   7155     if ( (MHD_ITC_IS_VALID_ (daemon->itc)) &&
   7156          (! MHD_itc_activate_ (daemon->itc, "c")) )
   7157     {
   7158 #ifdef HAVE_MESSAGES
   7159       MHD_DLOG (daemon,
   7160                 _ ("Failed to signal end of connection via inter-thread " \
   7161                    "communication channel.\n"));
   7162 #endif
   7163     }
   7164   }
   7165 }
   7166 
   7167 
   7168 /**
   7169  * Set initial internal states for the connection to start reading and
   7170  * processing incoming data.
   7171  * @param c the connection to process
   7172  */
   7173 void
   7174 MHD_connection_set_initial_state_ (struct MHD_Connection *c)
   7175 {
   7176   size_t read_buf_size;
   7177 
   7178 #ifdef HTTPS_SUPPORT
   7179   mhd_assert ( (0 == (c->daemon->options & MHD_USE_TLS)) || \
   7180                (MHD_TLS_CONN_INIT == c->tls_state) );
   7181   mhd_assert ( (0 != (c->daemon->options & MHD_USE_TLS)) || \
   7182                (MHD_TLS_CONN_NO_TLS == c->tls_state) );
   7183 #endif /* HTTPS_SUPPORT */
   7184   mhd_assert (MHD_CONNECTION_INIT == c->state);
   7185 
   7186   c->keepalive = MHD_CONN_KEEPALIVE_UNKOWN;
   7187   c->event_loop_info = MHD_EVENT_LOOP_INFO_READ;
   7188 
   7189   memset (&c->rq, 0, sizeof(c->rq));
   7190   memset (&c->rp, 0, sizeof(c->rp));
   7191 
   7192   c->write_buffer = NULL;
   7193   c->write_buffer_size = 0;
   7194   c->write_buffer_send_offset = 0;
   7195   c->write_buffer_append_offset = 0;
   7196 
   7197   c->continue_message_write_offset = 0;
   7198 
   7199   c->read_buffer_offset = 0;
   7200   read_buf_size = c->daemon->pool_size / 2;
   7201   c->read_buffer
   7202     = MHD_pool_allocate (c->pool,
   7203                          read_buf_size,
   7204                          false);
   7205   c->read_buffer_size = read_buf_size;
   7206 }
   7207 
   7208 
   7209 /**
   7210  * Reset connection after request-reply cycle.
   7211  * @param connection the connection to process
   7212  * @param reuse the flag to choose whether to close connection or
   7213  *              prepare connection for the next request processing
   7214  */
   7215 static void
   7216 connection_reset (struct MHD_Connection *connection,
   7217                   bool reuse)
   7218 {
   7219   struct MHD_Connection *const c = connection; /**< a short alias */
   7220   struct MHD_Daemon *const d = connection->daemon;
   7221 
   7222   if (! reuse)
   7223   {
   7224     /* Next function will destroy response, notify client,
   7225      * destroy memory pool, and set connection state to "CLOSED" */
   7226     MHD_connection_close_ (c,
   7227                            c->stop_with_error ?
   7228                            MHD_REQUEST_TERMINATED_WITH_ERROR :
   7229                            MHD_REQUEST_TERMINATED_COMPLETED_OK);
   7230     c->read_buffer = NULL;
   7231     c->read_buffer_size = 0;
   7232     c->read_buffer_offset = 0;
   7233     c->write_buffer = NULL;
   7234     c->write_buffer_size = 0;
   7235     c->write_buffer_send_offset = 0;
   7236     c->write_buffer_append_offset = 0;
   7237   }
   7238   else
   7239   {
   7240     /* Reset connection to process the next request */
   7241     size_t new_read_buf_size;
   7242     mhd_assert (! c->stop_with_error);
   7243     mhd_assert (! c->discard_request);
   7244 
   7245     if ( (NULL != d->notify_completed) &&
   7246          (c->rq.client_aware) )
   7247       d->notify_completed (d->notify_completed_cls,
   7248                            c,
   7249                            &c->rq.client_context,
   7250                            MHD_REQUEST_TERMINATED_COMPLETED_OK);
   7251     c->rq.client_aware = false;
   7252 
   7253     if (NULL != c->rp.response)
   7254       MHD_destroy_response (c->rp.response);
   7255     c->rp.response = NULL;
   7256 
   7257     c->keepalive = MHD_CONN_KEEPALIVE_UNKOWN;
   7258     c->state = MHD_CONNECTION_INIT;
   7259     c->event_loop_info =
   7260       (0 == c->read_buffer_offset) ?
   7261       MHD_EVENT_LOOP_INFO_READ : MHD_EVENT_LOOP_INFO_PROCESS;
   7262 
   7263     memset (&c->rq, 0, sizeof(c->rq));
   7264 
   7265     /* iov (if any) will be deallocated by MHD_pool_reset */
   7266     memset (&c->rp, 0, sizeof(c->rp));
   7267 
   7268     c->write_buffer = NULL;
   7269     c->write_buffer_size = 0;
   7270     c->write_buffer_send_offset = 0;
   7271     c->write_buffer_append_offset = 0;
   7272     c->continue_message_write_offset = 0;
   7273 
   7274     /* Reset the read buffer to the starting size,
   7275        preserving the bytes we have already read. */
   7276     new_read_buf_size = c->daemon->pool_size / 2;
   7277     if (c->read_buffer_offset > new_read_buf_size)
   7278       new_read_buf_size = c->read_buffer_offset;
   7279 
   7280     c->read_buffer
   7281       = MHD_pool_reset (c->pool,
   7282                         c->read_buffer,
   7283                         c->read_buffer_offset,
   7284                         new_read_buf_size);
   7285     c->read_buffer_size = new_read_buf_size;
   7286   }
   7287   c->rq.client_context = NULL;
   7288 }
   7289 
   7290 
   7291 /**
   7292  * This function was created to handle per-connection processing that
   7293  * has to happen even if the socket cannot be read or written to.
   7294  * All implementations (multithreaded, external select, internal select)
   7295  * call this function.
   7296  * @remark To be called only from thread that process connection's
   7297  * recv(), send() and response.
   7298  *
   7299  * @param connection connection to handle
   7300  * @return #MHD_YES if we should continue to process the
   7301  *         connection (not dead yet), #MHD_NO if it died
   7302  */
   7303 enum MHD_Result
   7304 MHD_connection_handle_idle (struct MHD_Connection *connection)
   7305 {
   7306   struct MHD_Daemon *daemon = connection->daemon;
   7307   enum MHD_Result ret;
   7308 #ifdef MHD_USE_THREADS
   7309   mhd_assert ( (! MHD_D_IS_USING_THREADS_ (daemon)) || \
   7310                MHD_thread_handle_ID_is_current_thread_ (connection->tid) );
   7311 #endif /* MHD_USE_THREADS */
   7312   /* 'daemon' is not used if epoll is not available and asserts are disabled */
   7313   (void) daemon; /* Mute compiler warning */
   7314 
   7315   connection->in_idle = true;
   7316   while (! connection->suspended)
   7317   {
   7318 #ifdef HTTPS_SUPPORT
   7319     if (MHD_TLS_CONN_NO_TLS != connection->tls_state)
   7320     {     /* HTTPS connection. */
   7321       if ((MHD_TLS_CONN_INIT <= connection->tls_state) &&
   7322           (MHD_TLS_CONN_CONNECTED > connection->tls_state))
   7323         break;
   7324     }
   7325 #endif /* HTTPS_SUPPORT */
   7326 #if DEBUG_STATES
   7327     MHD_DLOG (daemon,
   7328               _ ("In function %s handling connection at state: %s\n"),
   7329               MHD_FUNC_,
   7330               MHD_state_to_string (connection->state));
   7331 #endif
   7332     switch (connection->state)
   7333     {
   7334     case MHD_CONNECTION_INIT:
   7335     case MHD_CONNECTION_REQ_LINE_RECEIVING:
   7336       if (get_request_line (connection))
   7337       {
   7338         mhd_assert (MHD_CONNECTION_REQ_LINE_RECEIVING < connection->state);
   7339         mhd_assert ((MHD_IS_HTTP_VER_SUPPORTED (connection->rq.http_ver)) \
   7340                     || (connection->discard_request));
   7341         continue;
   7342       }
   7343       mhd_assert (MHD_CONNECTION_REQ_LINE_RECEIVING >= connection->state);
   7344       break;
   7345     case MHD_CONNECTION_REQ_LINE_RECEIVED:
   7346       switch_to_rq_headers_processing (connection);
   7347       mhd_assert (MHD_CONNECTION_REQ_LINE_RECEIVED != connection->state);
   7348       continue;
   7349     case MHD_CONNECTION_REQ_HEADERS_RECEIVING:
   7350       if (get_req_headers (connection, false))
   7351       {
   7352         mhd_assert (MHD_CONNECTION_REQ_HEADERS_RECEIVING < connection->state);
   7353         mhd_assert ((MHD_CONNECTION_HEADERS_RECEIVED == connection->state) || \
   7354                     (connection->discard_request));
   7355         continue;
   7356       }
   7357       mhd_assert (MHD_CONNECTION_REQ_HEADERS_RECEIVING == connection->state);
   7358       break;
   7359     case MHD_CONNECTION_HEADERS_RECEIVED:
   7360       parse_connection_headers (connection);
   7361       if (MHD_CONNECTION_HEADERS_RECEIVED != connection->state)
   7362         continue;
   7363       connection->state = MHD_CONNECTION_HEADERS_PROCESSED;
   7364       if (connection->suspended)
   7365         break;
   7366       continue;
   7367     case MHD_CONNECTION_HEADERS_PROCESSED:
   7368       call_connection_handler (connection);     /* first call */
   7369       if (MHD_CONNECTION_HEADERS_PROCESSED != connection->state)
   7370         continue;
   7371       if (connection->suspended)
   7372         continue;
   7373 
   7374       if ( (NULL == connection->rp.response) &&
   7375            (need_100_continue (connection)) &&
   7376            /* If the client is already sending the payload (body)
   7377               there is no need to send "100 Continue" */
   7378            (0 == connection->read_buffer_offset) )
   7379       {
   7380         connection->state = MHD_CONNECTION_CONTINUE_SENDING;
   7381         break;
   7382       }
   7383       if ( (NULL != connection->rp.response) &&
   7384            (0 != connection->rq.remaining_upload_size) )
   7385       {
   7386         /* we refused (no upload allowed!) */
   7387         connection->rq.remaining_upload_size = 0;
   7388         /* force close, in case client still tries to upload... */
   7389         connection->discard_request = true;
   7390       }
   7391       connection->state = (0 == connection->rq.remaining_upload_size)
   7392                           ? MHD_CONNECTION_FULL_REQ_RECEIVED
   7393                           : MHD_CONNECTION_BODY_RECEIVING;
   7394       if (connection->suspended)
   7395         break;
   7396       continue;
   7397     case MHD_CONNECTION_CONTINUE_SENDING:
   7398       if (connection->continue_message_write_offset ==
   7399           MHD_STATICSTR_LEN_ (HTTP_100_CONTINUE))
   7400       {
   7401         connection->state = MHD_CONNECTION_BODY_RECEIVING;
   7402         continue;
   7403       }
   7404       break;
   7405     case MHD_CONNECTION_BODY_RECEIVING:
   7406       mhd_assert (0 != connection->rq.remaining_upload_size);
   7407       mhd_assert (! connection->discard_request);
   7408       mhd_assert (NULL == connection->rp.response);
   7409       if (0 != connection->read_buffer_offset)
   7410       {
   7411         process_request_body (connection);           /* loop call */
   7412         if (MHD_CONNECTION_BODY_RECEIVING != connection->state)
   7413           continue;
   7414       }
   7415       /* Modify here when queueing of the response during data processing
   7416          will be supported */
   7417       mhd_assert (! connection->discard_request);
   7418       mhd_assert (NULL == connection->rp.response);
   7419       if (0 == connection->rq.remaining_upload_size)
   7420       {
   7421         connection->state = MHD_CONNECTION_BODY_RECEIVED;
   7422         continue;
   7423       }
   7424       break;
   7425     case MHD_CONNECTION_BODY_RECEIVED:
   7426       mhd_assert (! connection->discard_request);
   7427       mhd_assert (NULL == connection->rp.response);
   7428       if (0 == connection->rq.remaining_upload_size)
   7429       {
   7430         if (connection->rq.have_chunked_upload)
   7431         {
   7432           /* Reset counter variables reused for footers */
   7433           connection->rq.num_cr_sp_replaced = 0;
   7434           connection->rq.skipped_broken_lines = 0;
   7435           reset_rq_header_processing_state (connection);
   7436           connection->state = MHD_CONNECTION_FOOTERS_RECEIVING;
   7437         }
   7438         else
   7439           connection->state = MHD_CONNECTION_FULL_REQ_RECEIVED;
   7440         continue;
   7441       }
   7442       break;
   7443     case MHD_CONNECTION_FOOTERS_RECEIVING:
   7444       if (get_req_headers (connection, true))
   7445       {
   7446         mhd_assert (MHD_CONNECTION_FOOTERS_RECEIVING < connection->state);
   7447         mhd_assert ((MHD_CONNECTION_FOOTERS_RECEIVED == connection->state) || \
   7448                     (connection->discard_request));
   7449         continue;
   7450       }
   7451       mhd_assert (MHD_CONNECTION_FOOTERS_RECEIVING == connection->state);
   7452       break;
   7453     case MHD_CONNECTION_FOOTERS_RECEIVED:
   7454       /* The header, the body, and the footers of the request has been received,
   7455        * switch to the final processing of the request. */
   7456       connection->state = MHD_CONNECTION_FULL_REQ_RECEIVED;
   7457       continue;
   7458     case MHD_CONNECTION_FULL_REQ_RECEIVED:
   7459       call_connection_handler (connection);     /* "final" call */
   7460       if (connection->state != MHD_CONNECTION_FULL_REQ_RECEIVED)
   7461         continue;
   7462       if (NULL == connection->rp.response)
   7463         break;                  /* try again next time */
   7464       /* Response is ready, start reply */
   7465       connection->state = MHD_CONNECTION_START_REPLY;
   7466       continue;
   7467     case MHD_CONNECTION_START_REPLY:
   7468       mhd_assert (NULL != connection->rp.response);
   7469       connection_switch_from_recv_to_send (connection);
   7470       if (MHD_NO == build_header_response (connection))
   7471       {
   7472         /* oops - close! */
   7473         CONNECTION_CLOSE_ERROR (connection,
   7474                                 _ ("Closing connection (failed to create "
   7475                                    "response header).\n"));
   7476         continue;
   7477       }
   7478       connection->state = MHD_CONNECTION_HEADERS_SENDING;
   7479       break;
   7480 
   7481     case MHD_CONNECTION_HEADERS_SENDING:
   7482       /* no default action */
   7483       break;
   7484     case MHD_CONNECTION_HEADERS_SENT:
   7485 #ifdef UPGRADE_SUPPORT
   7486       if (NULL != connection->rp.response->upgrade_handler)
   7487       {
   7488         connection->state = MHD_CONNECTION_UPGRADE;
   7489         /* This connection is "upgraded".  Pass socket to application. */
   7490         if (MHD_NO ==
   7491             MHD_response_execute_upgrade_ (connection->rp.response,
   7492                                            connection))
   7493         {
   7494           /* upgrade failed, fail hard */
   7495           CONNECTION_CLOSE_ERROR (connection,
   7496                                   NULL);
   7497           continue;
   7498         }
   7499         /* Response is not required anymore for this connection. */
   7500         if (1)
   7501         {
   7502           struct MHD_Response *const resp = connection->rp.response;
   7503 
   7504           connection->rp.response = NULL;
   7505           MHD_destroy_response (resp);
   7506         }
   7507         continue;
   7508       }
   7509 #endif /* UPGRADE_SUPPORT */
   7510 
   7511       if (connection->rp.props.send_reply_body)
   7512       {
   7513         if (connection->rp.props.chunked)
   7514           connection->state = MHD_CONNECTION_CHUNKED_BODY_UNREADY;
   7515         else
   7516           connection->state = MHD_CONNECTION_NORMAL_BODY_UNREADY;
   7517       }
   7518       else
   7519         connection->state = MHD_CONNECTION_FULL_REPLY_SENT;
   7520       continue;
   7521     case MHD_CONNECTION_NORMAL_BODY_READY:
   7522       mhd_assert (connection->rp.props.send_reply_body);
   7523       mhd_assert (! connection->rp.props.chunked);
   7524       /* nothing to do here */
   7525       break;
   7526     case MHD_CONNECTION_NORMAL_BODY_UNREADY:
   7527       mhd_assert (connection->rp.props.send_reply_body);
   7528       mhd_assert (! connection->rp.props.chunked);
   7529 #if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS)
   7530       if (NULL != connection->rp.response->crc)
   7531         MHD_mutex_lock_chk_ (&connection->rp.response->mutex);
   7532 #endif
   7533       if (0 == connection->rp.response->total_size)
   7534       {
   7535 #if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS)
   7536         if (NULL != connection->rp.response->crc)
   7537           MHD_mutex_unlock_chk_ (&connection->rp.response->mutex);
   7538 #endif
   7539         if (connection->rp.props.chunked)
   7540           connection->state = MHD_CONNECTION_CHUNKED_BODY_SENT;
   7541         else
   7542           connection->state = MHD_CONNECTION_FULL_REPLY_SENT;
   7543         continue;
   7544       }
   7545       if (MHD_NO != try_ready_normal_body (connection))
   7546       {
   7547 #if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS)
   7548         if (NULL != connection->rp.response->crc)
   7549           MHD_mutex_unlock_chk_ (&connection->rp.response->mutex);
   7550 #endif
   7551         connection->state = MHD_CONNECTION_NORMAL_BODY_READY;
   7552         /* Buffering for flushable socket was already enabled*/
   7553 
   7554         break;
   7555       }
   7556       /* mutex was already unlocked by "try_ready_normal_body */
   7557       /* not ready, no socket action */
   7558       break;
   7559     case MHD_CONNECTION_CHUNKED_BODY_READY:
   7560       mhd_assert (connection->rp.props.send_reply_body);
   7561       mhd_assert (connection->rp.props.chunked);
   7562       /* nothing to do here */
   7563       break;
   7564     case MHD_CONNECTION_CHUNKED_BODY_UNREADY:
   7565       mhd_assert (connection->rp.props.send_reply_body);
   7566       mhd_assert (connection->rp.props.chunked);
   7567 #if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS)
   7568       if (NULL != connection->rp.response->crc)
   7569         MHD_mutex_lock_chk_ (&connection->rp.response->mutex);
   7570 #endif
   7571       if ( (0 == connection->rp.response->total_size) ||
   7572            (connection->rp.rsp_write_position ==
   7573             connection->rp.response->total_size) )
   7574       {
   7575 #if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS)
   7576         if (NULL != connection->rp.response->crc)
   7577           MHD_mutex_unlock_chk_ (&connection->rp.response->mutex);
   7578 #endif
   7579         connection->state = MHD_CONNECTION_CHUNKED_BODY_SENT;
   7580         continue;
   7581       }
   7582       if (1)
   7583       { /* pseudo-branch for local variables scope */
   7584         bool finished;
   7585         if (MHD_NO != try_ready_chunked_body (connection, &finished))
   7586         {
   7587 #if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS)
   7588           if (NULL != connection->rp.response->crc)
   7589             MHD_mutex_unlock_chk_ (&connection->rp.response->mutex);
   7590 #endif
   7591           connection->state = finished ? MHD_CONNECTION_CHUNKED_BODY_SENT :
   7592                               MHD_CONNECTION_CHUNKED_BODY_READY;
   7593           continue;
   7594         }
   7595         /* mutex was already unlocked by try_ready_chunked_body */
   7596       }
   7597       break;
   7598     case MHD_CONNECTION_CHUNKED_BODY_SENT:
   7599       mhd_assert (connection->rp.props.send_reply_body);
   7600       mhd_assert (connection->rp.props.chunked);
   7601       mhd_assert (connection->write_buffer_send_offset <= \
   7602                   connection->write_buffer_append_offset);
   7603 
   7604       if (MHD_NO == build_connection_chunked_response_footer (connection))
   7605       {
   7606         /* oops - close! */
   7607         CONNECTION_CLOSE_ERROR (connection,
   7608                                 _ ("Closing connection (failed to create " \
   7609                                    "response footer)."));
   7610         continue;
   7611       }
   7612       mhd_assert (connection->write_buffer_send_offset < \
   7613                   connection->write_buffer_append_offset);
   7614       connection->state = MHD_CONNECTION_FOOTERS_SENDING;
   7615       continue;
   7616     case MHD_CONNECTION_FOOTERS_SENDING:
   7617       mhd_assert (connection->rp.props.send_reply_body);
   7618       mhd_assert (connection->rp.props.chunked);
   7619       /* no default action */
   7620       break;
   7621     case MHD_CONNECTION_FULL_REPLY_SENT:
   7622       if (MHD_HTTP_PROCESSING == connection->rp.responseCode)
   7623       {
   7624         /* After this type of response, we allow sending another! */
   7625         connection->state = MHD_CONNECTION_HEADERS_PROCESSED;
   7626         MHD_destroy_response (connection->rp.response);
   7627         connection->rp.response = NULL;
   7628         /* FIXME: maybe partially reset memory pool? */
   7629         continue;
   7630       }
   7631       /* Reset connection after complete reply */
   7632       connection_reset (connection,
   7633                         MHD_CONN_USE_KEEPALIVE == connection->keepalive &&
   7634                         ! connection->read_closed &&
   7635                         ! connection->discard_request);
   7636       continue;
   7637     case MHD_CONNECTION_CLOSED:
   7638       cleanup_connection (connection);
   7639       connection->in_idle = false;
   7640       return MHD_NO;
   7641 #ifdef UPGRADE_SUPPORT
   7642     case MHD_CONNECTION_UPGRADE:
   7643       connection->in_idle = false;
   7644       return MHD_YES;     /* keep open */
   7645 #endif /* UPGRADE_SUPPORT */
   7646     default:
   7647       mhd_assert (0);
   7648       break;
   7649     }
   7650     break;
   7651   }
   7652   if (connection_check_timedout (connection))
   7653   {
   7654     MHD_connection_close_ (connection,
   7655                            MHD_REQUEST_TERMINATED_TIMEOUT_REACHED);
   7656     connection->in_idle = false;
   7657     return MHD_YES;
   7658   }
   7659   MHD_connection_update_event_loop_info (connection);
   7660   ret = MHD_YES;
   7661 #ifdef EPOLL_SUPPORT
   7662   if ( (! connection->suspended) &&
   7663        MHD_D_IS_USING_EPOLL_ (daemon) )
   7664   {
   7665     ret = MHD_connection_epoll_update_ (connection);
   7666   }
   7667 #endif /* EPOLL_SUPPORT */
   7668   connection->in_idle = false;
   7669   return ret;
   7670 }
   7671 
   7672 
   7673 #ifdef EPOLL_SUPPORT
   7674 /**
   7675  * Perform epoll() processing, possibly moving the connection back into
   7676  * the epoll() set if needed.
   7677  *
   7678  * @param connection connection to process
   7679  * @return #MHD_YES if we should continue to process the
   7680  *         connection (not dead yet), #MHD_NO if it died
   7681  */
   7682 enum MHD_Result
   7683 MHD_connection_epoll_update_ (struct MHD_Connection *connection)
   7684 {
   7685   struct MHD_Daemon *const daemon = connection->daemon;
   7686 
   7687   mhd_assert (MHD_D_IS_USING_EPOLL_ (daemon));
   7688 
   7689   if ((0 != (MHD_EVENT_LOOP_INFO_PROCESS & connection->event_loop_info)) &&
   7690       (0 == (connection->epoll_state & MHD_EPOLL_STATE_IN_EREADY_EDLL)))
   7691   {
   7692     /* Make sure that connection waiting for processing will be processed */
   7693     EDLL_insert (daemon->eready_head,
   7694                  daemon->eready_tail,
   7695                  connection);
   7696     connection->epoll_state |= MHD_EPOLL_STATE_IN_EREADY_EDLL;
   7697   }
   7698 
   7699   if ( (0 == (connection->epoll_state & MHD_EPOLL_STATE_IN_EPOLL_SET)) &&
   7700        (0 == (connection->epoll_state & MHD_EPOLL_STATE_SUSPENDED)) &&
   7701        ( ( (MHD_EVENT_LOOP_INFO_WRITE == connection->event_loop_info) &&
   7702            (0 == (connection->epoll_state & MHD_EPOLL_STATE_WRITE_READY))) ||
   7703          ( (0 != (MHD_EVENT_LOOP_INFO_READ & connection->event_loop_info)) &&
   7704            (0 == (connection->epoll_state & MHD_EPOLL_STATE_READ_READY)) ) ) )
   7705   {
   7706     /* add to epoll set */
   7707     struct epoll_event event;
   7708 
   7709     event.events = EPOLLIN | EPOLLOUT | EPOLLPRI | EPOLLET;
   7710     event.data.ptr = connection;
   7711     if (0 != epoll_ctl (daemon->epoll_fd,
   7712                         EPOLL_CTL_ADD,
   7713                         connection->socket_fd,
   7714                         &event))
   7715     {
   7716 #ifdef HAVE_MESSAGES
   7717       if (0 != (daemon->options & MHD_USE_ERROR_LOG))
   7718         MHD_DLOG (daemon,
   7719                   _ ("Call to epoll_ctl failed: %s\n"),
   7720                   MHD_socket_last_strerr_ ());
   7721 #endif
   7722       connection->state = MHD_CONNECTION_CLOSED;
   7723       cleanup_connection (connection);
   7724       return MHD_NO;
   7725     }
   7726     connection->epoll_state |= MHD_EPOLL_STATE_IN_EPOLL_SET;
   7727   }
   7728   return MHD_YES;
   7729 }
   7730 
   7731 
   7732 #endif
   7733 
   7734 
   7735 /**
   7736  * Set callbacks for this connection to those for HTTP.
   7737  *
   7738  * @param connection connection to initialize
   7739  */
   7740 void
   7741 MHD_set_http_callbacks_ (struct MHD_Connection *connection)
   7742 {
   7743   connection->recv_cls = &recv_param_adapter;
   7744 }
   7745 
   7746 
   7747 /**
   7748  * Obtain information about the given connection.
   7749  * The returned pointer is invalidated with the next call of this function or
   7750  * when the connection is closed.
   7751  *
   7752  * @param connection what connection to get information about
   7753  * @param info_type what information is desired?
   7754  * @param ... depends on @a info_type
   7755  * @return NULL if this information is not available
   7756  *         (or if the @a info_type is unknown)
   7757  * @ingroup specialized
   7758  */
   7759 _MHD_EXTERN const union MHD_ConnectionInfo *
   7760 MHD_get_connection_info (struct MHD_Connection *connection,
   7761                          enum MHD_ConnectionInfoType info_type,
   7762                          ...)
   7763 {
   7764   switch (info_type)
   7765   {
   7766 #ifdef HTTPS_SUPPORT
   7767   case MHD_CONNECTION_INFO_CIPHER_ALGO:
   7768     if (NULL == connection->tls_session)
   7769       return NULL;
   7770     if (1)
   7771     { /* Workaround to mute compiler warning */
   7772       gnutls_cipher_algorithm_t res;
   7773       res = gnutls_cipher_get (connection->tls_session);
   7774       connection->connection_info_dummy.cipher_algorithm = (int) res;
   7775     }
   7776     return &connection->connection_info_dummy;
   7777   case MHD_CONNECTION_INFO_PROTOCOL:
   7778     if (NULL == connection->tls_session)
   7779       return NULL;
   7780     if (1)
   7781     { /* Workaround to mute compiler warning */
   7782       gnutls_protocol_t res;
   7783       res = gnutls_protocol_get_version (connection->tls_session);
   7784       connection->connection_info_dummy.protocol = (int) res;
   7785     }
   7786     return &connection->connection_info_dummy;
   7787   case MHD_CONNECTION_INFO_GNUTLS_SESSION:
   7788     if (NULL == connection->tls_session)
   7789       return NULL;
   7790     connection->connection_info_dummy.tls_session = connection->tls_session;
   7791     return &connection->connection_info_dummy;
   7792 #else  /* ! HTTPS_SUPPORT */
   7793   case MHD_CONNECTION_INFO_CIPHER_ALGO:
   7794   case MHD_CONNECTION_INFO_PROTOCOL:
   7795   case MHD_CONNECTION_INFO_GNUTLS_SESSION:
   7796 #endif /* ! HTTPS_SUPPORT */
   7797   case MHD_CONNECTION_INFO_GNUTLS_CLIENT_CERT:
   7798     return NULL; /* Not implemented */
   7799   case MHD_CONNECTION_INFO_CLIENT_ADDRESS:
   7800     if (0 < connection->addr_len)
   7801     {
   7802       mhd_assert (sizeof (connection->addr) == \
   7803                   sizeof (connection->connection_info_dummy.client_addr));
   7804       memcpy (&connection->connection_info_dummy.client_addr,
   7805               &connection->addr,
   7806               sizeof(connection->addr));
   7807       return &connection->connection_info_dummy;
   7808     }
   7809     return NULL;
   7810   case MHD_CONNECTION_INFO_DAEMON:
   7811     connection->connection_info_dummy.daemon =
   7812       MHD_get_master (connection->daemon);
   7813     return &connection->connection_info_dummy;
   7814   case MHD_CONNECTION_INFO_CONNECTION_FD:
   7815     connection->connection_info_dummy.connect_fd = connection->socket_fd;
   7816     return &connection->connection_info_dummy;
   7817   case MHD_CONNECTION_INFO_SOCKET_CONTEXT:
   7818     connection->connection_info_dummy.socket_context =
   7819       connection->socket_context;
   7820     return &connection->connection_info_dummy;
   7821   case MHD_CONNECTION_INFO_CONNECTION_SUSPENDED:
   7822     connection->connection_info_dummy.suspended =
   7823       connection->suspended ? MHD_YES : MHD_NO;
   7824     return &connection->connection_info_dummy;
   7825   case MHD_CONNECTION_INFO_CONNECTION_TIMEOUT:
   7826 #if SIZEOF_UNSIGNED_INT <= (SIZEOF_UINT64_T - 2)
   7827     if (UINT_MAX < connection->connection_timeout_ms / 1000)
   7828       connection->connection_info_dummy.connection_timeout = UINT_MAX;
   7829     else
   7830 #endif /* SIZEOF_UNSIGNED_INT <=(SIZEOF_UINT64_T - 2) */
   7831     connection->connection_info_dummy.connection_timeout =
   7832       (unsigned int) (connection->connection_timeout_ms / 1000);
   7833     return &connection->connection_info_dummy;
   7834   case MHD_CONNECTION_INFO_REQUEST_HEADER_SIZE:
   7835     if ( (MHD_CONNECTION_HEADERS_RECEIVED > connection->state) ||
   7836          (MHD_CONNECTION_CLOSED == connection->state) )
   7837       return NULL;   /* invalid, too early! */
   7838     connection->connection_info_dummy.header_size = connection->rq.header_size;
   7839     return &connection->connection_info_dummy;
   7840   case MHD_CONNECTION_INFO_HTTP_STATUS:
   7841     if (NULL == connection->rp.response)
   7842       return NULL;
   7843     connection->connection_info_dummy.http_status = connection->rp.responseCode;
   7844     return &connection->connection_info_dummy;
   7845   default:
   7846     return NULL;
   7847   }
   7848 }
   7849 
   7850 
   7851 /**
   7852  * Set a custom option for the given connection, overriding defaults.
   7853  *
   7854  * @param connection connection to modify
   7855  * @param option option to set
   7856  * @param ... arguments to the option, depending on the option type
   7857  * @return #MHD_YES on success, #MHD_NO if setting the option failed
   7858  * @ingroup specialized
   7859  */
   7860 _MHD_EXTERN enum MHD_Result
   7861 MHD_set_connection_option (struct MHD_Connection *connection,
   7862                            enum MHD_CONNECTION_OPTION option,
   7863                            ...)
   7864 {
   7865   va_list ap;
   7866   struct MHD_Daemon *daemon;
   7867   unsigned int ui_val;
   7868 
   7869   daemon = connection->daemon;
   7870   switch (option)
   7871   {
   7872   case MHD_CONNECTION_OPTION_TIMEOUT:
   7873     if (0 == connection->connection_timeout_ms)
   7874       connection->last_activity = MHD_monotonic_msec_counter ();
   7875     va_start (ap, option);
   7876     ui_val = va_arg (ap, unsigned int);
   7877     va_end (ap);
   7878 #if (SIZEOF_UINT64_T - 2) <= SIZEOF_UNSIGNED_INT
   7879     if ((UINT64_MAX / 4000 - 1) < ui_val)
   7880     {
   7881 #ifdef HAVE_MESSAGES
   7882       MHD_DLOG (connection->daemon,
   7883                 _ ("The specified connection timeout (%u) is too " \
   7884                    "large. Maximum allowed value (%" PRIu64 ") will be used " \
   7885                    "instead.\n"),
   7886                 ui_val,
   7887                 (UINT64_MAX / 4000 - 1));
   7888 #endif
   7889       ui_val = UINT64_MAX / 4000 - 1;
   7890     }
   7891 #endif /* (SIZEOF_UINT64_T - 2) <= SIZEOF_UNSIGNED_INT */
   7892     if (! MHD_D_IS_USING_THREAD_PER_CONN_ (daemon))
   7893     {
   7894 #if defined(MHD_USE_THREADS)
   7895       MHD_mutex_lock_chk_ (&daemon->cleanup_connection_mutex);
   7896 #endif
   7897       if (! connection->suspended)
   7898       {
   7899         if (connection->connection_timeout_ms == daemon->connection_timeout_ms)
   7900           XDLL_remove (daemon->normal_timeout_head,
   7901                        daemon->normal_timeout_tail,
   7902                        connection);
   7903         else
   7904           XDLL_remove (daemon->manual_timeout_head,
   7905                        daemon->manual_timeout_tail,
   7906                        connection);
   7907         connection->connection_timeout_ms = ((uint64_t) ui_val) * 1000;
   7908         if (connection->connection_timeout_ms == daemon->connection_timeout_ms)
   7909           XDLL_insert (daemon->normal_timeout_head,
   7910                        daemon->normal_timeout_tail,
   7911                        connection);
   7912         else
   7913           XDLL_insert (daemon->manual_timeout_head,
   7914                        daemon->manual_timeout_tail,
   7915                        connection);
   7916       }
   7917 #if defined(MHD_USE_THREADS)
   7918       MHD_mutex_unlock_chk_ (&daemon->cleanup_connection_mutex);
   7919 #endif
   7920     }
   7921     return MHD_YES;
   7922   default:
   7923     return MHD_NO;
   7924   }
   7925 }
   7926 
   7927 
   7928 /**
   7929  * Queue a response to be transmitted to the client (as soon as
   7930  * possible but after #MHD_AccessHandlerCallback returns).
   7931  *
   7932  * For any active connection this function must be called
   7933  * only by #MHD_AccessHandlerCallback callback.
   7934  *
   7935  * For suspended connection this function can be called at any moment (this
   7936  * behaviour is deprecated and will be removed!). Response  will be sent
   7937  * as soon as connection is resumed.
   7938  *
   7939  * For single thread environment, when MHD is used in "external polling" mode
   7940  * (without MHD_USE_SELECT_INTERNALLY) this function can be called any
   7941  * time (this behaviour is deprecated and will be removed!).
   7942  *
   7943  * If HTTP specifications require use no body in reply, like @a status_code with
   7944  * value 1xx, the response body is automatically not sent even if it is present
   7945  * in the response. No "Content-Length" or "Transfer-Encoding" headers are
   7946  * generated and added.
   7947  *
   7948  * When the response is used to respond HEAD request or used with @a status_code
   7949  * #MHD_HTTP_NOT_MODIFIED, then response body is not sent, but "Content-Length"
   7950  * header is added automatically based the size of the body in the response.
   7951  * If body size it set to #MHD_SIZE_UNKNOWN or chunked encoding is enforced
   7952  * then "Transfer-Encoding: chunked" header (for HTTP/1.1 only) is added instead
   7953  * of "Content-Length" header. For example, if response with zero-size body is
   7954  * used for HEAD request, then "Content-Length: 0" is added automatically to
   7955  * reply headers.
   7956  * @sa #MHD_RF_HEAD_ONLY_RESPONSE
   7957  *
   7958  * In situations, where reply body is required, like answer for the GET request
   7959  * with @a status_code #MHD_HTTP_OK, headers "Content-Length" (for known body
   7960  * size) or "Transfer-Encoding: chunked" (for #MHD_SIZE_UNKNOWN with HTTP/1.1)
   7961  * are added automatically.
   7962  * In practice, the same response object can be used to respond to both HEAD and
   7963  * GET requests.
   7964  *
   7965  * @param connection the connection identifying the client
   7966  * @param status_code HTTP status code (i.e. #MHD_HTTP_OK)
   7967  * @param response response to transmit, the NULL is tolerated
   7968  * @return #MHD_NO on error (reply already sent, response is NULL),
   7969  *         #MHD_YES on success or if message has been queued
   7970  * @ingroup response
   7971  * @sa #MHD_AccessHandlerCallback
   7972  */
   7973 _MHD_EXTERN enum MHD_Result
   7974 MHD_queue_response (struct MHD_Connection *connection,
   7975                     unsigned int status_code,
   7976                     struct MHD_Response *response)
   7977 {
   7978   struct MHD_Daemon *daemon;
   7979   bool reply_icy;
   7980 
   7981   if ((NULL == connection) || (NULL == response))
   7982     return MHD_NO;
   7983 
   7984   daemon = connection->daemon;
   7985   if ((! connection->in_access_handler) && (! connection->suspended) &&
   7986       MHD_D_IS_USING_THREADS_ (daemon))
   7987     return MHD_NO;
   7988 
   7989   reply_icy = (0 != (status_code & MHD_ICY_FLAG));
   7990   status_code &= ~MHD_ICY_FLAG;
   7991 
   7992 #if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS)
   7993   if ( (! connection->suspended) &&
   7994        MHD_D_IS_USING_THREADS_ (daemon) &&
   7995        (! MHD_thread_handle_ID_is_current_thread_ (connection->tid)) )
   7996   {
   7997 #ifdef HAVE_MESSAGES
   7998     MHD_DLOG (daemon,
   7999               _ ("Attempted to queue response on wrong thread!\n"));
   8000 #endif
   8001     return MHD_NO;
   8002   }
   8003 #endif
   8004 
   8005   if (NULL != connection->rp.response)
   8006     return MHD_NO; /* The response was already set */
   8007 
   8008   if ( (MHD_CONNECTION_HEADERS_PROCESSED != connection->state) &&
   8009        (MHD_CONNECTION_FULL_REQ_RECEIVED != connection->state) )
   8010     return MHD_NO; /* Wrong connection state */
   8011 
   8012   if (daemon->shutdown)
   8013     return MHD_NO;
   8014 
   8015 #ifdef UPGRADE_SUPPORT
   8016   if (NULL != response->upgrade_handler)
   8017   {
   8018     struct MHD_HTTP_Res_Header *conn_header;
   8019     if (0 == (daemon->options & MHD_ALLOW_UPGRADE))
   8020     {
   8021 #ifdef HAVE_MESSAGES
   8022       MHD_DLOG (daemon,
   8023                 _ ("Attempted 'upgrade' connection on daemon without" \
   8024                    " MHD_ALLOW_UPGRADE option!\n"));
   8025 #endif
   8026       return MHD_NO;
   8027     }
   8028     if (MHD_HTTP_SWITCHING_PROTOCOLS != status_code)
   8029     {
   8030 #ifdef HAVE_MESSAGES
   8031       MHD_DLOG (daemon,
   8032                 _ ("Application used invalid status code for" \
   8033                    " 'upgrade' response!\n"));
   8034 #endif
   8035       return MHD_NO;
   8036     }
   8037     if (0 == (response->flags_auto & MHD_RAF_HAS_CONNECTION_HDR))
   8038     {
   8039 #ifdef HAVE_MESSAGES
   8040       MHD_DLOG (daemon,
   8041                 _ ("Application used invalid response" \
   8042                    " without \"Connection\" header!\n"));
   8043 #endif
   8044       return MHD_NO;
   8045     }
   8046     conn_header = response->first_header;
   8047     mhd_assert (NULL != conn_header);
   8048     mhd_assert (MHD_str_equal_caseless_ (conn_header->header,
   8049                                          MHD_HTTP_HEADER_CONNECTION));
   8050     if (! MHD_str_has_s_token_caseless_ (conn_header->value,
   8051                                          "upgrade"))
   8052     {
   8053 #ifdef HAVE_MESSAGES
   8054       MHD_DLOG (daemon,
   8055                 _ ("Application used invalid response" \
   8056                    " without \"upgrade\" token in" \
   8057                    " \"Connection\" header!\n"));
   8058 #endif
   8059       return MHD_NO;
   8060     }
   8061     if (! MHD_IS_HTTP_VER_1_1_COMPAT (connection->rq.http_ver))
   8062     {
   8063 #ifdef HAVE_MESSAGES
   8064       MHD_DLOG (daemon,
   8065                 _ ("Connection \"Upgrade\" can be used only " \
   8066                    "with HTTP/1.1 connections!\n"));
   8067 #endif
   8068       return MHD_NO;
   8069     }
   8070   }
   8071 #endif /* UPGRADE_SUPPORT */
   8072   if (MHD_HTTP_SWITCHING_PROTOCOLS == status_code)
   8073   {
   8074 #ifdef UPGRADE_SUPPORT
   8075     if (NULL == response->upgrade_handler)
   8076     {
   8077 #ifdef HAVE_MESSAGES
   8078       MHD_DLOG (daemon,
   8079                 _ ("Application used status code 101 \"Switching Protocols\" " \
   8080                    "with non-'upgrade' response!\n"));
   8081 #endif /* HAVE_MESSAGES */
   8082       return MHD_NO;
   8083     }
   8084 #else  /* ! UPGRADE_SUPPORT */
   8085 #ifdef HAVE_MESSAGES
   8086     MHD_DLOG (daemon,
   8087               _ ("Application used status code 101 \"Switching Protocols\", " \
   8088                  "but this MHD was built without \"Upgrade\" support!\n"));
   8089 #endif /* HAVE_MESSAGES */
   8090     return MHD_NO;
   8091 #endif /* ! UPGRADE_SUPPORT */
   8092   }
   8093   if ( (100 > status_code) ||
   8094        (999 < status_code) )
   8095   {
   8096 #ifdef HAVE_MESSAGES
   8097     MHD_DLOG (daemon,
   8098               _ ("Refused wrong status code (%u). " \
   8099                  "HTTP requires three digits status code!\n"),
   8100               status_code);
   8101 #endif
   8102     return MHD_NO;
   8103   }
   8104   if (200 > status_code)
   8105   {
   8106     if (MHD_HTTP_VER_1_0 == connection->rq.http_ver)
   8107     {
   8108 #ifdef HAVE_MESSAGES
   8109       MHD_DLOG (daemon,
   8110                 _ ("Wrong status code (%u) refused. " \
   8111                    "HTTP/1.0 clients do not support 1xx status codes!\n"),
   8112                 (status_code));
   8113 #endif
   8114       return MHD_NO;
   8115     }
   8116     if (0 != (response->flags & (MHD_RF_HTTP_1_0_COMPATIBLE_STRICT
   8117                                  | MHD_RF_HTTP_1_0_SERVER)))
   8118     {
   8119 #ifdef HAVE_MESSAGES
   8120       MHD_DLOG (daemon,
   8121                 _ ("Wrong status code (%u) refused. " \
   8122                    "HTTP/1.0 reply mode does not support 1xx status codes!\n"),
   8123                 (status_code));
   8124 #endif
   8125       return MHD_NO;
   8126     }
   8127   }
   8128   if ( (MHD_HTTP_MTHD_CONNECT == connection->rq.http_mthd) &&
   8129        (2 == status_code / 100) )
   8130   {
   8131 #ifdef HAVE_MESSAGES
   8132     MHD_DLOG (daemon,
   8133               _ ("Successful (%u) response code cannot be used to answer " \
   8134                  "\"CONNECT\" request!\n"),
   8135               (status_code));
   8136 #endif
   8137     return MHD_NO;
   8138   }
   8139 
   8140   if ( (0 != (MHD_RF_HEAD_ONLY_RESPONSE & response->flags)) &&
   8141        (RP_BODY_HEADERS_ONLY < is_reply_body_needed (connection, status_code)) )
   8142   {
   8143 #ifdef HAVE_MESSAGES
   8144     MHD_DLOG (daemon,
   8145               _ ("HEAD-only response cannot be used when the request requires "
   8146                  "reply body to be sent!\n"));
   8147 #endif
   8148     return MHD_NO;
   8149   }
   8150 
   8151 #ifdef HAVE_MESSAGES
   8152   if ( (0 != (MHD_RF_INSANITY_HEADER_CONTENT_LENGTH & response->flags)) &&
   8153        (0 != (MHD_RAF_HAS_CONTENT_LENGTH & response->flags_auto)) )
   8154   {
   8155     MHD_DLOG (daemon,
   8156               _ ("The response has application-defined \"Content-Length\" " \
   8157                  "header. The reply to the request will be not " \
   8158                  "HTTP-compliant and may result in hung connection or " \
   8159                  "other problems!\n"));
   8160   }
   8161 #endif
   8162 
   8163   MHD_increment_response_rc (response);
   8164   connection->rp.response = response;
   8165   connection->rp.responseCode = status_code;
   8166   connection->rp.responseIcy = reply_icy;
   8167 #if defined(_MHD_HAVE_SENDFILE)
   8168   if ( (response->fd == -1) ||
   8169        (response->is_pipe) ||
   8170        (0 != (connection->daemon->options & MHD_USE_TLS))
   8171 #if defined(MHD_SEND_SPIPE_SUPPRESS_NEEDED) && \
   8172        defined(MHD_SEND_SPIPE_SUPPRESS_POSSIBLE)
   8173        || (! daemon->sigpipe_blocked && ! connection->sk_spipe_suppress)
   8174 #endif /* MHD_SEND_SPIPE_SUPPRESS_NEEDED &&
   8175           MHD_SEND_SPIPE_SUPPRESS_POSSIBLE */
   8176        )
   8177     connection->rp.resp_sender = MHD_resp_sender_std;
   8178   else
   8179     connection->rp.resp_sender = MHD_resp_sender_sendfile;
   8180 #endif /* _MHD_HAVE_SENDFILE */
   8181   /* FIXME: if 'is_pipe' is set, TLS is off, and we have *splice*, we could use splice()
   8182      to avoid two user-space copies... */
   8183 
   8184   if ( (MHD_HTTP_MTHD_HEAD == connection->rq.http_mthd) ||
   8185        (MHD_HTTP_OK > status_code) ||
   8186        (MHD_HTTP_NO_CONTENT == status_code) ||
   8187        (MHD_HTTP_NOT_MODIFIED == status_code) )
   8188   {
   8189     /* if this is a "HEAD" request, or a status code for
   8190        which a body is not allowed, pretend that we
   8191        have already sent the full message body. */
   8192     /* TODO: remove the next assignment, use 'rp_props.send_reply_body' in
   8193      * checks */
   8194     connection->rp.rsp_write_position = response->total_size;
   8195   }
   8196   if (MHD_CONNECTION_HEADERS_PROCESSED == connection->state)
   8197   {
   8198     /* response was queued "early", refuse to read body / footers or
   8199        further requests! */
   8200     connection->discard_request = true;
   8201     connection->state = MHD_CONNECTION_START_REPLY;
   8202     connection->rq.remaining_upload_size = 0;
   8203   }
   8204   if (! connection->in_idle)
   8205     (void) MHD_connection_handle_idle (connection);
   8206   MHD_update_last_activity_ (connection);
   8207   return MHD_YES;
   8208 }
   8209 
   8210 
   8211 /* end of connection.c */