libmicrohttpd

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

connection.c (289003B)


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