libmicrohttpd

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

connection.c (284818B)


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