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