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