1#include "request.h" 2#include "keyvalue.h" 3#include "log.h" 4 5#include <sys/stat.h> 6 7#include <limits.h> 8#include <stdlib.h> 9#include <string.h> 10#include <stdio.h> 11#include <ctype.h> 12 13static int request_check_hostname(server *srv, connection *con, buffer *host) { 14 enum { DOMAINLABEL, TOPLABEL } stage = TOPLABEL; 15 size_t i; 16 int label_len = 0; 17 size_t host_len; 18 char *colon; 19 int is_ip = -1; /* -1 don't know yet, 0 no, 1 yes */ 20 int level = 0; 21 22 UNUSED(srv); 23 UNUSED(con); 24 25 /* 26 * hostport = host [ ":" port ] 27 * host = hostname | IPv4address | IPv6address 28 * hostname = *( domainlabel "." ) toplabel [ "." ] 29 * domainlabel = alphanum | alphanum *( alphanum | "-" ) alphanum 30 * toplabel = alpha | alpha *( alphanum | "-" ) alphanum 31 * IPv4address = 1*digit "." 1*digit "." 1*digit "." 1*digit 32 * IPv6address = "[" ... "]" 33 * port = *digit 34 */ 35 36 /* no Host: */ 37 if (buffer_is_empty(host)) return 0; 38 39 host_len = buffer_string_length(host); 40 41 /* IPv6 adress */ 42 if (host->ptr[0] == '[') { 43 char *c = host->ptr + 1; 44 int colon_cnt = 0; 45 46 /* check the address inside [...] */ 47 for (; *c && *c != ']'; c++) { 48 if (*c == ':') { 49 if (++colon_cnt > 7) { 50 return -1; 51 } 52 } else if (!light_isxdigit(*c) && '.' != *c) { 53 return -1; 54 } 55 } 56 57 /* missing ] */ 58 if (!*c) { 59 return -1; 60 } 61 62 /* check port */ 63 if (*(c+1) == ':') { 64 for (c += 2; *c; c++) { 65 if (!light_isdigit(*c)) { 66 return -1; 67 } 68 } 69 } 70 else if ('\0' != *(c+1)) { 71 /* only a port is allowed to follow [...] */ 72 return -1; 73 } 74 return 0; 75 } 76 77 if (NULL != (colon = memchr(host->ptr, ':', host_len))) { 78 char *c = colon + 1; 79 80 /* check portnumber */ 81 for (; *c; c++) { 82 if (!light_isdigit(*c)) return -1; 83 } 84 85 /* remove the port from the host-len */ 86 host_len = colon - host->ptr; 87 } 88 89 /* Host is empty */ 90 if (host_len == 0) return -1; 91 92 /* if the hostname ends in a "." strip it */ 93 if (host->ptr[host_len-1] == '.') { 94 /* shift port info one left */ 95 if (NULL != colon) memmove(colon-1, colon, buffer_string_length(host) - host_len); 96 buffer_string_set_length(host, buffer_string_length(host) - 1); 97 host_len -= 1; 98 } 99 100 if (host_len == 0) return -1; 101 102 /* scan from the right and skip the \0 */ 103 for (i = host_len; i-- > 0; ) { 104 const char c = host->ptr[i]; 105 106 switch (stage) { 107 case TOPLABEL: 108 if (c == '.') { 109 /* only switch stage, if this is not the last character */ 110 if (i != host_len - 1) { 111 if (label_len == 0) { 112 return -1; 113 } 114 115 /* check the first character at right of the dot */ 116 if (is_ip == 0) { 117 if (!light_isalnum(host->ptr[i+1])) { 118 return -1; 119 } 120 } else if (!light_isdigit(host->ptr[i+1])) { 121 is_ip = 0; 122 } else if ('-' == host->ptr[i+1]) { 123 return -1; 124 } else { 125 /* just digits */ 126 is_ip = 1; 127 } 128 129 stage = DOMAINLABEL; 130 131 label_len = 0; 132 level++; 133 } else if (i == 0) { 134 /* just a dot and nothing else is evil */ 135 return -1; 136 } 137 } else if (i == 0) { 138 /* the first character of the hostname */ 139 if (!light_isalnum(c)) { 140 return -1; 141 } 142 label_len++; 143 } else { 144 if (c != '-' && !light_isalnum(c)) { 145 return -1; 146 } 147 if (is_ip == -1) { 148 if (!light_isdigit(c)) is_ip = 0; 149 } 150 label_len++; 151 } 152 153 break; 154 case DOMAINLABEL: 155 if (is_ip == 1) { 156 if (c == '.') { 157 if (label_len == 0) { 158 return -1; 159 } 160 161 label_len = 0; 162 level++; 163 } else if (!light_isdigit(c)) { 164 return -1; 165 } else { 166 label_len++; 167 } 168 } else { 169 if (c == '.') { 170 if (label_len == 0) { 171 return -1; 172 } 173 174 /* c is either - or alphanum here */ 175 if ('-' == host->ptr[i+1]) { 176 return -1; 177 } 178 179 label_len = 0; 180 level++; 181 } else if (i == 0) { 182 if (!light_isalnum(c)) { 183 return -1; 184 } 185 label_len++; 186 } else { 187 if (c != '-' && !light_isalnum(c)) { 188 return -1; 189 } 190 label_len++; 191 } 192 } 193 194 break; 195 } 196 } 197 198 /* a IP has to consist of 4 parts */ 199 if (is_ip == 1 && level != 3) { 200 return -1; 201 } 202 203 if (label_len == 0) { 204 return -1; 205 } 206 207 return 0; 208} 209 210#if 0 211#define DUMP_HEADER 212#endif 213 214static int http_request_split_value(array *vals, buffer *b) { 215 size_t i, len; 216 int state = 0; 217 218 const char *current; 219 const char *token_start = NULL, *token_end = NULL; 220 /* 221 * parse 222 * 223 * val1, val2, val3, val4 224 * 225 * into a array (more or less a explode() incl. striping of whitespaces 226 */ 227 228 if (buffer_string_is_empty(b)) return 0; 229 230 current = b->ptr; 231 len = buffer_string_length(b); 232 for (i = 0; i <= len; ++i, ++current) { 233 data_string *ds; 234 235 switch (state) { 236 case 0: /* find start of a token */ 237 switch (*current) { 238 case ' ': 239 case '\t': /* skip white space */ 240 case ',': /* skip empty token */ 241 break; 242 case '\0': /* end of string */ 243 return 0; 244 default: 245 /* found real data, switch to state 1 to find the end of the token */ 246 token_start = token_end = current; 247 state = 1; 248 break; 249 } 250 break; 251 case 1: /* find end of token and last non white space character */ 252 switch (*current) { 253 case ' ': 254 case '\t': 255 /* space - don't update token_end */ 256 break; 257 case ',': 258 case '\0': /* end of string also marks the end of a token */ 259 if (NULL == (ds = (data_string *)array_get_unused_element(vals, TYPE_STRING))) { 260 ds = data_string_init(); 261 } 262 263 buffer_copy_string_len(ds->value, token_start, token_end-token_start+1); 264 array_insert_unique(vals, (data_unset *)ds); 265 266 state = 0; 267 break; 268 default: 269 /* no white space, update token_end to include current character */ 270 token_end = current; 271 break; 272 } 273 break; 274 } 275 } 276 277 return 0; 278} 279 280static int request_uri_is_valid_char(unsigned char c) { 281 if (c <= 32) return 0; 282 if (c == 127) return 0; 283 if (c == 255) return 0; 284 285 return 1; 286} 287 288int http_request_parse(server *srv, connection *con) { 289 char *uri = NULL, *proto = NULL, *method = NULL, con_length_set; 290 int is_key = 1, key_len = 0, is_ws_after_key = 0, in_folding; 291 char *value = NULL, *key = NULL; 292 char *reqline_host = NULL; 293 int reqline_hostlen = 0; 294 295 enum { HTTP_CONNECTION_UNSET, HTTP_CONNECTION_KEEPALIVE, HTTP_CONNECTION_CLOSE } keep_alive_set = HTTP_CONNECTION_UNSET; 296 297 int line = 0; 298 299 int request_line_stage = 0; 300 size_t i, first, ilen; 301 302 int done = 0; 303 304 /* 305 * Request: "^(GET|POST|HEAD) ([^ ]+(\\?[^ ]+|)) (HTTP/1\\.[01])$" 306 * Option : "^([-a-zA-Z]+): (.+)$" 307 * End : "^$" 308 */ 309 310 if (con->conf.log_request_header) { 311 log_error_write(srv, __FILE__, __LINE__, "sdsdSb", 312 "fd:", con->fd, 313 "request-len:", buffer_string_length(con->request.request), 314 "\n", con->request.request); 315 } 316 317 if (con->request_count > 1 && 318 con->request.request->ptr[0] == '\r' && 319 con->request.request->ptr[1] == '\n') { 320 /* we are in keep-alive and might get \r\n after a previous POST request.*/ 321 322 buffer_copy_string_len(con->parse_request, con->request.request->ptr + 2, buffer_string_length(con->request.request) - 2); 323 } else { 324 /* fill the local request buffer */ 325 buffer_copy_buffer(con->parse_request, con->request.request); 326 } 327 328 keep_alive_set = 0; 329 con_length_set = 0; 330 331 /* parse the first line of the request 332 * 333 * should be: 334 * 335 * <method> <uri> <protocol>\r\n 336 * */ 337 ilen = buffer_string_length(con->parse_request); 338 for (i = 0, first = 0; i < ilen && line == 0; i++) { 339 switch(con->parse_request->ptr[i]) { 340 case '\r': 341 if (con->parse_request->ptr[i+1] == '\n') { 342 http_method_t r; 343 char *nuri = NULL; 344 size_t j, jlen; 345 346 /* \r\n -> \0\0 */ 347 con->parse_request->ptr[i] = '\0'; 348 con->parse_request->ptr[i+1] = '\0'; 349 350 buffer_copy_string_len(con->request.request_line, con->parse_request->ptr, i); 351 352 if (request_line_stage != 2) { 353 con->http_status = 400; 354 con->response.keep_alive = 0; 355 con->keep_alive = 0; 356 357 if (srv->srvconf.log_request_header_on_error) { 358 log_error_write(srv, __FILE__, __LINE__, "s", "incomplete request line -> 400"); 359 log_error_write(srv, __FILE__, __LINE__, "Sb", 360 "request-header:\n", 361 con->request.request); 362 } 363 return 0; 364 } 365 366 proto = con->parse_request->ptr + first; 367 368 *(uri - 1) = '\0'; 369 *(proto - 1) = '\0'; 370 371 /* we got the first one :) */ 372 if (HTTP_METHOD_UNSET == (r = get_http_method_key(method))) { 373 con->http_status = 501; 374 con->response.keep_alive = 0; 375 con->keep_alive = 0; 376 377 if (srv->srvconf.log_request_header_on_error) { 378 log_error_write(srv, __FILE__, __LINE__, "s", "unknown http-method -> 501"); 379 log_error_write(srv, __FILE__, __LINE__, "Sb", 380 "request-header:\n", 381 con->request.request); 382 } 383 384 return 0; 385 } 386 387 con->request.http_method = r; 388 389 /* 390 * RFC2616 says: 391 * 392 * HTTP-Version = "HTTP" "/" 1*DIGIT "." 1*DIGIT 393 * 394 * */ 395 if (0 == strncmp(proto, "HTTP/", sizeof("HTTP/") - 1)) { 396 char * major = proto + sizeof("HTTP/") - 1; 397 char * minor = strchr(major, '.'); 398 char *err = NULL; 399 int major_num = 0, minor_num = 0; 400 401 int invalid_version = 0; 402 403 if (NULL == minor || /* no dot */ 404 minor == major || /* no major */ 405 *(minor + 1) == '\0' /* no minor */) { 406 invalid_version = 1; 407 } else { 408 *minor = '\0'; 409 major_num = strtol(major, &err, 10); 410 411 if (*err != '\0') invalid_version = 1; 412 413 *minor++ = '.'; 414 minor_num = strtol(minor, &err, 10); 415 416 if (*err != '\0') invalid_version = 1; 417 } 418 419 if (invalid_version) { 420 con->http_status = 400; 421 con->keep_alive = 0; 422 423 if (srv->srvconf.log_request_header_on_error) { 424 log_error_write(srv, __FILE__, __LINE__, "s", "unknown protocol -> 400"); 425 log_error_write(srv, __FILE__, __LINE__, "Sb", 426 "request-header:\n", 427 con->request.request); 428 } 429 return 0; 430 } 431 432 if (major_num == 1 && minor_num == 1) { 433 con->request.http_version = con->conf.allow_http11 ? HTTP_VERSION_1_1 : HTTP_VERSION_1_0; 434 } else if (major_num == 1 && minor_num == 0) { 435 con->request.http_version = HTTP_VERSION_1_0; 436 } else { 437 con->http_status = 505; 438 439 if (srv->srvconf.log_request_header_on_error) { 440 log_error_write(srv, __FILE__, __LINE__, "s", "unknown HTTP version -> 505"); 441 log_error_write(srv, __FILE__, __LINE__, "Sb", 442 "request-header:\n", 443 con->request.request); 444 } 445 return 0; 446 } 447 } else { 448 con->http_status = 400; 449 con->keep_alive = 0; 450 451 if (srv->srvconf.log_request_header_on_error) { 452 log_error_write(srv, __FILE__, __LINE__, "s", "unknown protocol -> 400"); 453 log_error_write(srv, __FILE__, __LINE__, "Sb", 454 "request-header:\n", 455 con->request.request); 456 } 457 return 0; 458 } 459 460 if (0 == strncmp(uri, "http://", 7) && 461 NULL != (nuri = strchr(uri + 7, '/'))) { 462 reqline_host = uri + 7; 463 reqline_hostlen = nuri - reqline_host; 464 465 buffer_copy_string_len(con->request.uri, nuri, proto - nuri - 1); 466 } else if (0 == strncmp(uri, "https://", 8) && 467 NULL != (nuri = strchr(uri + 8, '/'))) { 468 reqline_host = uri + 8; 469 reqline_hostlen = nuri - reqline_host; 470 471 buffer_copy_string_len(con->request.uri, nuri, proto - nuri - 1); 472 } else { 473 /* everything looks good so far */ 474 buffer_copy_string_len(con->request.uri, uri, proto - uri - 1); 475 } 476 477 /* check uri for invalid characters */ 478 jlen = buffer_string_length(con->request.uri); 479 for (j = 0; j < jlen; j++) { 480 if (!request_uri_is_valid_char(con->request.uri->ptr[j])) { 481 unsigned char buf[2]; 482 con->http_status = 400; 483 con->keep_alive = 0; 484 485 if (srv->srvconf.log_request_header_on_error) { 486 buf[0] = con->request.uri->ptr[j]; 487 buf[1] = '\0'; 488 489 if (con->request.uri->ptr[j] > 32 && 490 con->request.uri->ptr[j] != 127) { 491 /* the character is printable -> print it */ 492 log_error_write(srv, __FILE__, __LINE__, "ss", 493 "invalid character in URI -> 400", 494 buf); 495 } else { 496 /* a control-character, print ascii-code */ 497 log_error_write(srv, __FILE__, __LINE__, "sd", 498 "invalid character in URI -> 400", 499 con->request.uri->ptr[j]); 500 } 501 502 log_error_write(srv, __FILE__, __LINE__, "Sb", 503 "request-header:\n", 504 con->request.request); 505 } 506 507 return 0; 508 } 509 } 510 511 buffer_copy_buffer(con->request.orig_uri, con->request.uri); 512 513 con->http_status = 0; 514 515 i++; 516 line++; 517 first = i+1; 518 } 519 break; 520 case ' ': 521 switch(request_line_stage) { 522 case 0: 523 /* GET|POST|... */ 524 method = con->parse_request->ptr + first; 525 first = i + 1; 526 break; 527 case 1: 528 /* /foobar/... */ 529 uri = con->parse_request->ptr + first; 530 first = i + 1; 531 break; 532 default: 533 /* ERROR, one space to much */ 534 con->http_status = 400; 535 con->response.keep_alive = 0; 536 con->keep_alive = 0; 537 538 if (srv->srvconf.log_request_header_on_error) { 539 log_error_write(srv, __FILE__, __LINE__, "s", "overlong request line -> 400"); 540 log_error_write(srv, __FILE__, __LINE__, "Sb", 541 "request-header:\n", 542 con->request.request); 543 } 544 return 0; 545 } 546 547 request_line_stage++; 548 break; 549 } 550 } 551 552 in_folding = 0; 553 554 if (buffer_string_is_empty(con->request.uri)) { 555 con->http_status = 400; 556 con->response.keep_alive = 0; 557 con->keep_alive = 0; 558 559 if (srv->srvconf.log_request_header_on_error) { 560 log_error_write(srv, __FILE__, __LINE__, "s", "no uri specified -> 400"); 561 log_error_write(srv, __FILE__, __LINE__, "Sb", 562 "request-header:\n", 563 con->request.request); 564 } 565 return 0; 566 } 567 568 if (reqline_host) { 569 /* Insert as host header */ 570 data_string *ds; 571 572 if (NULL == (ds = (data_string *)array_get_unused_element(con->request.headers, TYPE_STRING))) { 573 ds = data_string_init(); 574 } 575 576 buffer_copy_string_len(ds->key, CONST_STR_LEN("Host")); 577 buffer_copy_string_len(ds->value, reqline_host, reqline_hostlen); 578 array_insert_unique(con->request.headers, (data_unset *)ds); 579 con->request.http_host = ds->value; 580 } 581 582 for (; i <= ilen && !done; i++) { 583 char *cur = con->parse_request->ptr + i; 584 585 if (is_key) { 586 size_t j; 587 int got_colon = 0; 588 589 /** 590 * 1*<any CHAR except CTLs or separators> 591 * CTLs == 0-31 + 127, CHAR = 7-bit ascii (0..127) 592 * 593 */ 594 switch(*cur) { 595 case ':': 596 is_key = 0; 597 598 value = cur + 1; 599 600 if (is_ws_after_key == 0) { 601 key_len = i - first; 602 } 603 is_ws_after_key = 0; 604 605 break; 606 case '(': 607 case ')': 608 case '<': 609 case '>': 610 case '@': 611 case ',': 612 case ';': 613 case '\\': 614 case '\"': 615 case '/': 616 case '[': 617 case ']': 618 case '?': 619 case '=': 620 case '{': 621 case '}': 622 con->http_status = 400; 623 con->keep_alive = 0; 624 con->response.keep_alive = 0; 625 626 if (srv->srvconf.log_request_header_on_error) { 627 log_error_write(srv, __FILE__, __LINE__, "sbsds", 628 "invalid character in key", con->request.request, cur, *cur, "-> 400"); 629 630 log_error_write(srv, __FILE__, __LINE__, "Sb", 631 "request-header:\n", 632 con->request.request); 633 } 634 return 0; 635 case ' ': 636 case '\t': 637 if (i == first) { 638 is_key = 0; 639 in_folding = 1; 640 value = cur; 641 642 break; 643 } 644 645 646 key_len = i - first; 647 648 /* skip every thing up to the : */ 649 for (j = 1; !got_colon; j++) { 650 switch(con->parse_request->ptr[j + i]) { 651 case ' ': 652 case '\t': 653 /* skip WS */ 654 continue; 655 case ':': 656 /* ok, done; handle the colon the usual way */ 657 658 i += j - 1; 659 got_colon = 1; 660 is_ws_after_key = 1; /* we already know the key length */ 661 662 break; 663 default: 664 /* error */ 665 666 if (srv->srvconf.log_request_header_on_error) { 667 log_error_write(srv, __FILE__, __LINE__, "s", "WS character in key -> 400"); 668 log_error_write(srv, __FILE__, __LINE__, "Sb", 669 "request-header:\n", 670 con->request.request); 671 } 672 673 con->http_status = 400; 674 con->response.keep_alive = 0; 675 con->keep_alive = 0; 676 677 return 0; 678 } 679 } 680 681 break; 682 case '\r': 683 if (con->parse_request->ptr[i+1] == '\n' && i == first) { 684 /* End of Header */ 685 con->parse_request->ptr[i] = '\0'; 686 con->parse_request->ptr[i+1] = '\0'; 687 688 i++; 689 690 done = 1; 691 } else { 692 if (srv->srvconf.log_request_header_on_error) { 693 log_error_write(srv, __FILE__, __LINE__, "s", "CR without LF -> 400"); 694 log_error_write(srv, __FILE__, __LINE__, "Sb", 695 "request-header:\n", 696 con->request.request); 697 } 698 699 con->http_status = 400; 700 con->keep_alive = 0; 701 con->response.keep_alive = 0; 702 return 0; 703 } 704 break; 705 default: 706 if (*cur < 32 || ((unsigned char)*cur) >= 127) { 707 con->http_status = 400; 708 con->keep_alive = 0; 709 con->response.keep_alive = 0; 710 711 if (srv->srvconf.log_request_header_on_error) { 712 log_error_write(srv, __FILE__, __LINE__, "sbsds", 713 "invalid character in key", con->request.request, cur, *cur, "-> 400"); 714 715 log_error_write(srv, __FILE__, __LINE__, "Sb", 716 "request-header:\n", 717 con->request.request); 718 } 719 720 return 0; 721 } 722 /* ok */ 723 break; 724 } 725 } else { 726 switch(*cur) { 727 case '\r': 728 if (con->parse_request->ptr[i+1] == '\n') { 729 data_string *ds = NULL; 730 731 /* End of Headerline */ 732 con->parse_request->ptr[i] = '\0'; 733 con->parse_request->ptr[i+1] = '\0'; 734 735 if (in_folding) { 736 buffer *key_b; 737 /** 738 * we use a evil hack to handle the line-folding 739 * 740 * As array_insert_unique() deletes 'ds' in the case of a duplicate 741 * ds points somewhere and we get a evil crash. As a solution we keep the old 742 * "key" and get the current value from the hash and append us 743 * 744 * */ 745 746 if (!key || !key_len) { 747 /* 400 */ 748 749 if (srv->srvconf.log_request_header_on_error) { 750 log_error_write(srv, __FILE__, __LINE__, "s", "WS at the start of first line -> 400"); 751 752 log_error_write(srv, __FILE__, __LINE__, "Sb", 753 "request-header:\n", 754 con->request.request); 755 } 756 757 758 con->http_status = 400; 759 con->keep_alive = 0; 760 con->response.keep_alive = 0; 761 return 0; 762 } 763 764 key_b = buffer_init(); 765 buffer_copy_string_len(key_b, key, key_len); 766 767 if (NULL != (ds = (data_string *)array_get_element(con->request.headers, key_b->ptr))) { 768 buffer_append_string(ds->value, value); 769 } 770 771 buffer_free(key_b); 772 } else { 773 int s_len; 774 key = con->parse_request->ptr + first; 775 776 s_len = cur - value; 777 778 /* strip trailing white-spaces */ 779 for (; s_len > 0 && 780 (value[s_len - 1] == ' ' || 781 value[s_len - 1] == '\t'); s_len--); 782 783 value[s_len] = '\0'; 784 785 if (s_len > 0) { 786 int cmp = 0; 787 if (NULL == (ds = (data_string *)array_get_unused_element(con->request.headers, TYPE_STRING))) { 788 ds = data_string_init(); 789 } 790 buffer_copy_string_len(ds->key, key, key_len); 791 buffer_copy_string_len(ds->value, value, s_len); 792 793 /* retreive values 794 * 795 * 796 * the list of options is sorted to simplify the search 797 */ 798 799 if (0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("Connection")))) { 800 array *vals; 801 size_t vi; 802 803 /* split on , */ 804 805 vals = srv->split_vals; 806 807 array_reset(vals); 808 809 http_request_split_value(vals, ds->value); 810 811 for (vi = 0; vi < vals->used; vi++) { 812 data_string *dsv = (data_string *)vals->data[vi]; 813 814 if (0 == buffer_caseless_compare(CONST_BUF_LEN(dsv->value), CONST_STR_LEN("keep-alive"))) { 815 keep_alive_set = HTTP_CONNECTION_KEEPALIVE; 816 817 break; 818 } else if (0 == buffer_caseless_compare(CONST_BUF_LEN(dsv->value), CONST_STR_LEN("close"))) { 819 keep_alive_set = HTTP_CONNECTION_CLOSE; 820 821 break; 822 } 823 } 824 825 } else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("Content-Length")))) { 826 char *err; 827 unsigned long int r; 828 size_t j, jlen; 829 830 if (con_length_set) { 831 con->http_status = 400; 832 con->keep_alive = 0; 833 834 if (srv->srvconf.log_request_header_on_error) { 835 log_error_write(srv, __FILE__, __LINE__, "s", 836 "duplicate Content-Length-header -> 400"); 837 log_error_write(srv, __FILE__, __LINE__, "Sb", 838 "request-header:\n", 839 con->request.request); 840 } 841 array_insert_unique(con->request.headers, (data_unset *)ds); 842 return 0; 843 } 844 845 jlen = buffer_string_length(ds->value); 846 for (j = 0; j < jlen; j++) { 847 char c = ds->value->ptr[j]; 848 if (!isdigit((unsigned char)c)) { 849 log_error_write(srv, __FILE__, __LINE__, "sbs", 850 "content-length broken:", ds->value, "-> 400"); 851 852 con->http_status = 400; 853 con->keep_alive = 0; 854 855 array_insert_unique(con->request.headers, (data_unset *)ds); 856 return 0; 857 } 858 } 859 860 r = strtoul(ds->value->ptr, &err, 10); 861 862 if (*err == '\0') { 863 con_length_set = 1; 864 con->request.content_length = r; 865 } else { 866 log_error_write(srv, __FILE__, __LINE__, "sbs", 867 "content-length broken:", ds->value, "-> 400"); 868 869 con->http_status = 400; 870 con->keep_alive = 0; 871 872 array_insert_unique(con->request.headers, (data_unset *)ds); 873 return 0; 874 } 875 } else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("Content-Type")))) { 876 /* if dup, only the first one will survive */ 877 if (!con->request.http_content_type) { 878 con->request.http_content_type = ds->value->ptr; 879 } else { 880 con->http_status = 400; 881 con->keep_alive = 0; 882 883 if (srv->srvconf.log_request_header_on_error) { 884 log_error_write(srv, __FILE__, __LINE__, "s", 885 "duplicate Content-Type-header -> 400"); 886 log_error_write(srv, __FILE__, __LINE__, "Sb", 887 "request-header:\n", 888 con->request.request); 889 } 890 array_insert_unique(con->request.headers, (data_unset *)ds); 891 return 0; 892 } 893 } else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("Expect")))) { 894 /* HTTP 2616 8.2.3 895 * Expect: 100-continue 896 * 897 * -> (10.1.1) 100 (read content, process request, send final status-code) 898 * -> (10.4.18) 417 (close) 899 * 900 * (not handled at all yet, we always send 417 here) 901 * 902 * What has to be added ? 903 * 1. handling of chunked request body 904 * 2. out-of-order sending from the HTTP/1.1 100 Continue 905 * header 906 * 907 */ 908 909 if (srv->srvconf.reject_expect_100_with_417 && 0 == buffer_caseless_compare(CONST_BUF_LEN(ds->value), CONST_STR_LEN("100-continue"))) { 910 con->http_status = 417; 911 con->keep_alive = 0; 912 array_insert_unique(con->request.headers, (data_unset *)ds); 913 return 0; 914 } 915 } else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("Host")))) { 916 if (reqline_host) { 917 /* ignore all host: headers as we got the host in the request line */ 918 ds->free((data_unset*) ds); 919 ds = NULL; 920 } else if (!con->request.http_host) { 921 con->request.http_host = ds->value; 922 } else { 923 con->http_status = 400; 924 con->keep_alive = 0; 925 926 if (srv->srvconf.log_request_header_on_error) { 927 log_error_write(srv, __FILE__, __LINE__, "s", 928 "duplicate Host-header -> 400"); 929 log_error_write(srv, __FILE__, __LINE__, "Sb", 930 "request-header:\n", 931 con->request.request); 932 } 933 array_insert_unique(con->request.headers, (data_unset *)ds); 934 return 0; 935 } 936 } else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("If-Modified-Since")))) { 937 /* Proxies sometimes send dup headers 938 * if they are the same we ignore the second 939 * if not, we raise an error */ 940 if (!con->request.http_if_modified_since) { 941 con->request.http_if_modified_since = ds->value->ptr; 942 } else if (0 == strcasecmp(con->request.http_if_modified_since, 943 ds->value->ptr)) { 944 /* ignore it if they are the same */ 945 946 ds->free((data_unset *)ds); 947 ds = NULL; 948 } else { 949 con->http_status = 400; 950 con->keep_alive = 0; 951 952 if (srv->srvconf.log_request_header_on_error) { 953 log_error_write(srv, __FILE__, __LINE__, "s", 954 "duplicate If-Modified-Since header -> 400"); 955 log_error_write(srv, __FILE__, __LINE__, "Sb", 956 "request-header:\n", 957 con->request.request); 958 } 959 array_insert_unique(con->request.headers, (data_unset *)ds); 960 return 0; 961 } 962 } else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("If-None-Match")))) { 963 /* if dup, only the first one will survive */ 964 if (!con->request.http_if_none_match) { 965 con->request.http_if_none_match = ds->value->ptr; 966 } else { 967 ds->free((data_unset*) ds); 968 ds = NULL; 969 } 970 } else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("Range")))) { 971 if (!con->request.http_range) { 972 /* bytes=.*-.* */ 973 974 if (0 == strncasecmp(ds->value->ptr, "bytes=", 6) && 975 NULL != strchr(ds->value->ptr+6, '-')) { 976 977 /* if dup, only the first one will survive */ 978 con->request.http_range = ds->value->ptr + 6; 979 } 980 } else { 981 con->http_status = 400; 982 con->keep_alive = 0; 983 984 if (srv->srvconf.log_request_header_on_error) { 985 log_error_write(srv, __FILE__, __LINE__, "s", 986 "duplicate Range-header -> 400"); 987 log_error_write(srv, __FILE__, __LINE__, "Sb", 988 "request-header:\n", 989 con->request.request); 990 } 991 array_insert_unique(con->request.headers, (data_unset *)ds); 992 return 0; 993 } 994 } 995 996 if (ds) array_insert_unique(con->request.headers, (data_unset *)ds); 997 } else { 998 /* empty header-fields are not allowed by HTTP-RFC, we just ignore them */ 999 } 1000 } 1001 1002 i++; 1003 first = i+1; 1004 is_key = 1; 1005 value = NULL; 1006#if 0 1007 /** 1008 * for Bug 1230 keep the key_len a live 1009 */ 1010 key_len = 0; 1011#endif 1012 in_folding = 0; 1013 } else { 1014 if (srv->srvconf.log_request_header_on_error) { 1015 log_error_write(srv, __FILE__, __LINE__, "sbs", 1016 "CR without LF", con->request.request, "-> 400"); 1017 } 1018 1019 con->http_status = 400; 1020 con->keep_alive = 0; 1021 con->response.keep_alive = 0; 1022 return 0; 1023 } 1024 break; 1025 case ' ': 1026 case '\t': 1027 /* strip leading WS */ 1028 if (value == cur) value = cur+1; 1029 /* fallthrough */ 1030 default: 1031 if (*cur >= 0 && *cur < 32 && *cur != '\t') { 1032 if (srv->srvconf.log_request_header_on_error) { 1033 log_error_write(srv, __FILE__, __LINE__, "sds", 1034 "invalid char in header", (int)*cur, "-> 400"); 1035 } 1036 1037 con->http_status = 400; 1038 con->keep_alive = 0; 1039 1040 return 0; 1041 } 1042 break; 1043 } 1044 } 1045 } 1046 1047 con->header_len = i; 1048 1049 /* do some post-processing */ 1050 1051 if (con->request.http_version == HTTP_VERSION_1_1) { 1052 if (keep_alive_set != HTTP_CONNECTION_CLOSE) { 1053 /* no Connection-Header sent */ 1054 1055 /* HTTP/1.1 -> keep-alive default TRUE */ 1056 con->keep_alive = 1; 1057 } else { 1058 con->keep_alive = 0; 1059 } 1060 1061 /* RFC 2616, 14.23 */ 1062 if (con->request.http_host == NULL || 1063 buffer_string_is_empty(con->request.http_host)) { 1064 con->http_status = 400; 1065 con->response.keep_alive = 0; 1066 con->keep_alive = 0; 1067 1068 if (srv->srvconf.log_request_header_on_error) { 1069 log_error_write(srv, __FILE__, __LINE__, "s", "HTTP/1.1 but Host missing -> 400"); 1070 log_error_write(srv, __FILE__, __LINE__, "Sb", 1071 "request-header:\n", 1072 con->request.request); 1073 } 1074 return 0; 1075 } 1076 } else { 1077 if (keep_alive_set == HTTP_CONNECTION_KEEPALIVE) { 1078 /* no Connection-Header sent */ 1079 1080 /* HTTP/1.0 -> keep-alive default FALSE */ 1081 con->keep_alive = 1; 1082 } else { 1083 con->keep_alive = 0; 1084 } 1085 } 1086 1087 /* check hostname field if it is set */ 1088 if (NULL != con->request.http_host && 1089 0 != request_check_hostname(srv, con, con->request.http_host)) { 1090 1091 if (srv->srvconf.log_request_header_on_error) { 1092 log_error_write(srv, __FILE__, __LINE__, "s", 1093 "Invalid Hostname -> 400"); 1094 log_error_write(srv, __FILE__, __LINE__, "Sb", 1095 "request-header:\n", 1096 con->request.request); 1097 } 1098 1099 con->http_status = 400; 1100 con->response.keep_alive = 0; 1101 con->keep_alive = 0; 1102 1103 return 0; 1104 } 1105 1106 switch(con->request.http_method) { 1107 case HTTP_METHOD_GET: 1108 case HTTP_METHOD_HEAD: 1109 /* content-length is forbidden for those */ 1110 if (con_length_set && con->request.content_length != 0) { 1111 /* content-length is missing */ 1112 log_error_write(srv, __FILE__, __LINE__, "s", 1113 "GET/HEAD with content-length -> 400"); 1114 1115 con->keep_alive = 0; 1116 con->http_status = 400; 1117 return 0; 1118 } 1119 break; 1120 case HTTP_METHOD_POST: 1121 /* content-length is required for them */ 1122 if (!con_length_set) { 1123 /* content-length is missing */ 1124 log_error_write(srv, __FILE__, __LINE__, "s", 1125 "POST-request, but content-length missing -> 411"); 1126 1127 con->keep_alive = 0; 1128 con->http_status = 411; 1129 return 0; 1130 1131 } 1132 break; 1133 default: 1134 /* the may have a content-length */ 1135 break; 1136 } 1137 1138 1139 /* check if we have read post data */ 1140 if (con_length_set) { 1141 /* don't handle more the SSIZE_MAX bytes in content-length */ 1142 if (con->request.content_length > SSIZE_MAX) { 1143 con->http_status = 413; 1144 con->keep_alive = 0; 1145 1146 log_error_write(srv, __FILE__, __LINE__, "sos", 1147 "request-size too long:", (off_t) con->request.content_length, "-> 413"); 1148 return 0; 1149 } 1150 1151 /* divide by 1024 as srvconf.max_request_size is in kBytes */ 1152 if (srv->srvconf.max_request_size != 0 && 1153 (con->request.content_length >> 10) > srv->srvconf.max_request_size) { 1154 /* the request body itself is larger then 1155 * our our max_request_size 1156 */ 1157 1158 con->http_status = 413; 1159 con->keep_alive = 0; 1160 1161 log_error_write(srv, __FILE__, __LINE__, "sos", 1162 "request-size too long:", (off_t) con->request.content_length, "-> 413"); 1163 return 0; 1164 } 1165 1166 1167 /* we have content */ 1168 if (con->request.content_length != 0) { 1169 return 1; 1170 } 1171 } 1172 1173 return 0; 1174} 1175 1176int http_request_header_finished(server *srv, connection *con) { 1177 UNUSED(srv); 1178 1179 if (buffer_string_length(con->request.request) < 4) return 0; 1180 1181 if (0 == memcmp(con->request.request->ptr + buffer_string_length(con->request.request) - 4, CONST_STR_LEN("\r\n\r\n"))) return 1; 1182 if (NULL != strstr(con->request.request->ptr, "\r\n\r\n")) return 1; 1183 1184 return 0; 1185} 1186