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