libmicrohttpd

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

connection.c (293671B)


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