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