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