libmicrohttpd

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

connection.c (289537B)


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