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