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