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