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