1 #include "first.h" 2 3 #include "sys-time.h" 4 5 #include "base.h" 6 #include "array.h" 7 #include "buffer.h" 8 #include "chunk.h" 9 #include "fdevent.h" 10 #include "log.h" 11 #include "http_chunk.h" 12 #include "http_cgi.h" 13 #include "http_date.h" 14 #include "http_etag.h" 15 #include "http_header.h" 16 #include "response.h" 17 #include "sock_addr.h" 18 #include "stat_cache.h" 19 20 #include <stdlib.h> 21 #include <string.h> 22 #include <errno.h> 23 24 #include "sys-socket.h" 25 #include <unistd.h> 26 27 /** 28 * max size of the HTTP response header from backends 29 * (differs from server.max-request-field-size for max request field size) 30 */ 31 #define MAX_HTTP_RESPONSE_FIELD_SIZE 65535 32 33 34 __attribute_cold__ 35 int http_response_buffer_append_authority(request_st * const r, buffer * const o) { 36 if (!buffer_string_is_empty(&r->uri.authority)) { 37 buffer_append_string_buffer(o, &r->uri.authority); 38 } else { 39 /* get the name of the currently connected socket */ 40 sock_addr our_addr; 41 socklen_t our_addr_len; 42 43 our_addr.plain.sa_family = 0; 44 our_addr_len = sizeof(our_addr); 45 46 if (-1 == getsockname(r->con->fd, (struct sockaddr *)&our_addr, &our_addr_len) 47 || our_addr_len > (socklen_t)sizeof(our_addr)) { 48 r->http_status = 500; 49 log_perror(r->conf.errh, __FILE__, __LINE__, "can't get sockname"); 50 return -1; 51 } 52 53 if (our_addr.plain.sa_family == AF_INET 54 && our_addr.ipv4.sin_addr.s_addr == htonl(INADDR_LOOPBACK)) { 55 static char lhost[32]; 56 static size_t lhost_len = 0; 57 if (0 != lhost_len) { 58 buffer_append_string_len(o, lhost, lhost_len); 59 } 60 else { 61 size_t olen = buffer_string_length(o); 62 if (0 == sock_addr_nameinfo_append_buffer(o, &our_addr, r->conf.errh)) { 63 lhost_len = buffer_string_length(o) - olen; 64 if (lhost_len < sizeof(lhost)) { 65 memcpy(lhost, o->ptr+olen, lhost_len+1); /*(+1 for '\0')*/ 66 } 67 else { 68 lhost_len = 0; 69 } 70 } 71 else { 72 lhost_len = sizeof("localhost")-1; 73 memcpy(lhost, "localhost", lhost_len+1); /*(+1 for '\0')*/ 74 buffer_append_string_len(o, lhost, lhost_len); 75 } 76 } 77 } else if (!buffer_string_is_empty(r->server_name)) { 78 buffer_append_string_buffer(o, r->server_name); 79 } else 80 /* Lookup name: secondly try to get hostname for bind address */ 81 if (0 != sock_addr_nameinfo_append_buffer(o, &our_addr, r->conf.errh)) { 82 r->http_status = 500; 83 return -1; 84 } 85 86 { 87 unsigned short listen_port = sock_addr_get_port(&our_addr); 88 unsigned short default_port = 80; 89 if (buffer_is_equal_string(&r->uri.scheme, CONST_STR_LEN("https"))) { 90 default_port = 443; 91 } 92 if (0 == listen_port) listen_port = r->con->srv->srvconf.port; 93 if (default_port != listen_port) { 94 buffer_append_string_len(o, CONST_STR_LEN(":")); 95 buffer_append_int(o, listen_port); 96 } 97 } 98 } 99 return 0; 100 } 101 102 int http_response_redirect_to_directory(request_st * const r, int status) { 103 buffer *o = r->tmp_buf; 104 buffer_clear(o); 105 /* XXX: store flag in global at startup? */ 106 if (r->con->srv->srvconf.absolute_dir_redirect) { 107 buffer_append_str2(o, CONST_BUF_LEN(&r->uri.scheme), 108 CONST_STR_LEN("://")); 109 if (0 != http_response_buffer_append_authority(r, o)) { 110 return -1; 111 } 112 } 113 buffer *vb; 114 if (status >= 300) { 115 r->http_status = status; 116 r->resp_body_finished = 1; 117 vb = http_header_response_set_ptr(r, HTTP_HEADER_LOCATION, 118 CONST_STR_LEN("Location")); 119 } 120 else { 121 vb = http_header_response_set_ptr(r, HTTP_HEADER_CONTENT_LOCATION, 122 CONST_STR_LEN("Content-Location")); 123 } 124 buffer_copy_buffer(vb, o); 125 buffer_append_string_encoded(vb, CONST_BUF_LEN(&r->uri.path), 126 ENCODING_REL_URI); 127 buffer_append_string_len(vb, CONST_STR_LEN("/")); 128 if (!buffer_string_is_empty(&r->uri.query)) 129 buffer_append_str2(vb, CONST_STR_LEN("?"), 130 CONST_BUF_LEN(&r->uri.query)); 131 132 return 0; 133 } 134 135 #define MTIME_CACHE_MAX 16 136 struct mtime_cache_type { 137 time_t mtime; /* key */ 138 buffer str; /* buffer for string representation */ 139 }; 140 static struct mtime_cache_type mtime_cache[MTIME_CACHE_MAX]; 141 static char mtime_cache_str[MTIME_CACHE_MAX][HTTP_DATE_SZ]; 142 /* 30-chars for "%a, %d %b %Y %T GMT" */ 143 144 void strftime_cache_reset(void) { 145 for (int i = 0; i < MTIME_CACHE_MAX; ++i) { 146 mtime_cache[i].mtime = (time_t)-1; 147 mtime_cache[i].str.ptr = mtime_cache_str[i]; 148 mtime_cache[i].str.used = sizeof(mtime_cache_str[0]); 149 mtime_cache[i].str.size = sizeof(mtime_cache_str[0]); 150 } 151 } 152 153 static const buffer * strftime_cache_get(const time_t last_mod) { 154 static int mtime_cache_idx; 155 156 for (int j = 0; j < MTIME_CACHE_MAX; ++j) { 157 if (mtime_cache[j].mtime == last_mod) 158 return &mtime_cache[j].str; /* found cache-entry */ 159 } 160 161 if (++mtime_cache_idx == MTIME_CACHE_MAX) mtime_cache_idx = 0; 162 163 const int i = mtime_cache_idx; 164 http_date_time_to_str(mtime_cache[i].str.ptr, sizeof(mtime_cache_str[0]), 165 (mtime_cache[i].mtime = last_mod)); 166 167 return &mtime_cache[i].str; 168 } 169 170 171 const buffer * http_response_set_last_modified(request_st * const r, const time_t lmtime) { 172 buffer * const vb = 173 http_header_response_set_ptr(r, HTTP_HEADER_LAST_MODIFIED, 174 CONST_STR_LEN("Last-Modified")); 175 buffer_copy_buffer(vb, strftime_cache_get(lmtime)); 176 return vb; 177 } 178 179 180 int http_response_handle_cachable(request_st * const r, const buffer * const lmod, const time_t lmtime) { 181 if (!(r->rqst_htags 182 & (light_bshift(HTTP_HEADER_IF_NONE_MATCH) 183 |light_bshift(HTTP_HEADER_IF_MODIFIED_SINCE)))) { 184 return HANDLER_GO_ON; 185 } 186 187 const buffer *vb; 188 189 /* 190 * 14.26 If-None-Match 191 * [...] 192 * If none of the entity tags match, then the server MAY perform the 193 * requested method as if the If-None-Match header field did not exist, 194 * but MUST also ignore any If-Modified-Since header field(s) in the 195 * request. That is, if no entity tags match, then the server MUST NOT 196 * return a 304 (Not Modified) response. 197 */ 198 199 if ((vb = http_header_request_get(r, HTTP_HEADER_IF_NONE_MATCH, 200 CONST_STR_LEN("If-None-Match")))) { 201 /*(weak etag comparison must not be used for ranged requests)*/ 202 int range_request = (0 != light_btst(r->rqst_htags, HTTP_HEADER_RANGE)); 203 if (http_etag_matches(&r->physical.etag, vb->ptr, !range_request)) { 204 if (http_method_get_or_head(r->http_method)) { 205 r->http_status = 304; 206 return HANDLER_FINISHED; 207 } else { 208 r->http_status = 412; 209 r->handler_module = NULL; 210 return HANDLER_FINISHED; 211 } 212 } 213 } else if (http_method_get_or_head(r->http_method) 214 && (vb = http_header_request_get(r, HTTP_HEADER_IF_MODIFIED_SINCE, 215 CONST_STR_LEN("If-Modified-Since")))) { 216 /* last-modified handling */ 217 if (buffer_is_equal(lmod, vb) 218 || !http_date_if_modified_since(CONST_BUF_LEN(vb), lmtime)) { 219 r->http_status = 304; 220 return HANDLER_FINISHED; 221 } 222 } 223 224 return HANDLER_GO_ON; 225 } 226 227 228 void http_response_body_clear (request_st * const r, int preserve_length) { 229 r->resp_send_chunked = 0; 230 r->resp_body_scratchpad = -1; 231 if (light_btst(r->resp_htags, HTTP_HEADER_TRANSFER_ENCODING)) { 232 http_header_response_unset(r, HTTP_HEADER_TRANSFER_ENCODING, 233 CONST_STR_LEN("Transfer-Encoding")); 234 } 235 if (!preserve_length) { /* preserve for HEAD responses and no-content responses (204, 205, 304) */ 236 if (light_btst(r->resp_htags, HTTP_HEADER_CONTENT_LENGTH)) { 237 http_header_response_unset(r, HTTP_HEADER_CONTENT_LENGTH, 238 CONST_STR_LEN("Content-Length")); 239 } 240 /*(if not preserving Content-Length, do not preserve trailers, if any)*/ 241 r->resp_decode_chunked = 0; 242 if (r->gw_dechunk) { 243 free(r->gw_dechunk->b.ptr); 244 free(r->gw_dechunk); 245 r->gw_dechunk = NULL; 246 } 247 } 248 chunkqueue_reset(&r->write_queue); 249 } 250 251 252 static void http_response_header_clear (request_st * const r) { 253 r->http_status = 0; 254 r->resp_htags = 0; 255 r->resp_header_len = 0; 256 r->resp_header_repeated = 0; 257 array_reset_data_strings(&r->resp_headers); 258 259 /* Note: http_response_body_clear(r, 0) is not called here 260 * r->write_queue should be preserved for additional data after 1xx response 261 * However, if http_response_process_headers() was called and response had 262 * Transfer-Encoding: chunked set, then other items need to be reset */ 263 r->resp_send_chunked = 0; 264 r->resp_decode_chunked = 0; 265 r->resp_body_scratchpad = -1; 266 if (r->gw_dechunk) { 267 free(r->gw_dechunk->b.ptr); 268 free(r->gw_dechunk); 269 r->gw_dechunk = NULL; 270 } 271 } 272 273 274 void http_response_reset (request_st * const r) { 275 r->http_status = 0; 276 r->con->is_writable = 1; 277 r->resp_body_finished = 0; 278 r->resp_body_started = 0; 279 r->handler_module = NULL; 280 if (r->physical.path.ptr) { /*(skip for mod_fastcgi authorizer)*/ 281 buffer_clear(&r->physical.doc_root); 282 buffer_clear(&r->physical.basedir); 283 buffer_clear(&r->physical.etag); 284 buffer_reset(&r->physical.path); 285 buffer_reset(&r->physical.rel_path); 286 } 287 r->resp_htags = 0; 288 r->resp_header_len = 0; 289 r->resp_header_repeated = 0; 290 array_reset_data_strings(&r->resp_headers); 291 http_response_body_clear(r, 0); 292 } 293 294 295 handler_t http_response_reqbody_read_error (request_st * const r, int http_status) { 296 r->keep_alive = 0; 297 298 /*(do not change status if response headers already set and possibly sent)*/ 299 if (0 != r->resp_header_len) return HANDLER_ERROR; 300 301 http_response_body_clear(r, 0); 302 r->http_status = http_status; 303 r->handler_module = NULL; 304 return HANDLER_FINISHED; 305 } 306 307 308 void http_response_send_file (request_st * const r, buffer * const path) { 309 stat_cache_entry * const sce = stat_cache_get_entry_open(path, r->conf.follow_symlink); 310 const buffer *mtime = NULL; 311 int allow_caching = (0 == r->http_status || 200 == r->http_status); 312 313 if (NULL == sce) { 314 r->http_status = (errno == ENOENT) ? 404 : 403; 315 log_error(r->conf.errh, __FILE__, __LINE__, 316 "not a regular file: %s -> %s", r->uri.path.ptr, path->ptr); 317 return; 318 } 319 320 if (!r->conf.follow_symlink 321 && 0 != stat_cache_path_contains_symlink(path, r->conf.errh)) { 322 r->http_status = 403; 323 if (r->conf.log_request_handling) { 324 log_error(r->conf.errh, __FILE__, __LINE__, 325 "-- access denied due symlink restriction"); 326 log_error(r->conf.errh, __FILE__, __LINE__, 327 "Path : %s", path->ptr); 328 } 329 return; 330 } 331 332 /* we only handle regular files */ 333 if (!S_ISREG(sce->st.st_mode)) { 334 r->http_status = 403; 335 if (r->conf.log_file_not_found) { 336 log_error(r->conf.errh, __FILE__, __LINE__, 337 "not a regular file: %s -> %s", 338 r->uri.path.ptr, path->ptr); 339 } 340 return; 341 } 342 343 if (sce->fd < 0 && 0 != sce->st.st_size) { 344 r->http_status = (errno == ENOENT) ? 404 : 403; 345 if (r->conf.log_request_handling) { 346 log_perror(r->conf.errh, __FILE__, __LINE__, 347 "file open failed: %s", path->ptr); 348 } 349 return; 350 } 351 352 /* set response content-type, if not set already */ 353 354 if (!light_btst(r->resp_htags, HTTP_HEADER_CONTENT_TYPE)) { 355 const buffer *content_type = stat_cache_content_type_get(sce, r); 356 if (buffer_string_is_empty(content_type)) { 357 /* we are setting application/octet-stream, but also announce that 358 * this header field might change in the seconds few requests 359 * 360 * This should fix the aggressive caching of FF and the script download 361 * seen by the first installations 362 */ 363 http_header_response_set(r, HTTP_HEADER_CONTENT_TYPE, 364 CONST_STR_LEN("Content-Type"), 365 CONST_STR_LEN("application/octet-stream")); 366 367 allow_caching = 0; 368 } else { 369 http_header_response_set(r, HTTP_HEADER_CONTENT_TYPE, 370 CONST_STR_LEN("Content-Type"), 371 CONST_BUF_LEN(content_type)); 372 } 373 } 374 375 if (allow_caching) { 376 if (!light_btst(r->resp_htags, HTTP_HEADER_ETAG) 377 && 0 != r->conf.etag_flags) { 378 const buffer *etag = 379 stat_cache_etag_get(sce, r->conf.etag_flags); 380 if (!buffer_string_is_empty(etag)) { 381 buffer_copy_buffer(&r->physical.etag, etag); 382 http_header_response_set(r, HTTP_HEADER_ETAG, 383 CONST_STR_LEN("ETag"), 384 CONST_BUF_LEN(&r->physical.etag)); 385 } 386 } 387 388 /* prepare header */ 389 mtime = http_header_response_get(r, HTTP_HEADER_LAST_MODIFIED, 390 CONST_STR_LEN("Last-Modified")); 391 if (NULL == mtime) { 392 mtime = http_response_set_last_modified(r, sce->st.st_mtime); 393 } 394 395 if (HANDLER_FINISHED == http_response_handle_cachable(r, mtime, sce->st.st_mtime)) { 396 return; 397 } 398 } 399 400 if (0 == sce->st.st_size) { 401 r->http_status = 200; 402 r->resp_body_finished = 1; 403 /*(Transfer-Encoding should not have been set at this point)*/ 404 http_header_response_set(r, HTTP_HEADER_CONTENT_LENGTH, 405 CONST_STR_LEN("Content-Length"), 406 CONST_STR_LEN("0")); 407 return; 408 } 409 410 /* if we are still here, prepare body */ 411 412 /* we add it here for all requests 413 * the HEAD request will drop it afterwards again 414 */ 415 416 if (0 == http_chunk_append_file_ref(r, sce)) { 417 r->http_status = 200; 418 r->resp_body_finished = 1; 419 /*(Transfer-Encoding should not have been set at this point)*/ 420 buffer_append_int( 421 http_header_response_set_ptr(r, HTTP_HEADER_CONTENT_LENGTH, 422 CONST_STR_LEN("Content-Length")), 423 sce->st.st_size); 424 } 425 else { 426 r->http_status = 500; 427 } 428 } 429 430 431 static void http_response_xsendfile (request_st * const r, buffer * const path, const array * const xdocroot) { 432 const int status = r->http_status; 433 int valid = 1; 434 435 /* reset Content-Length, if set by backend 436 * Content-Length might later be set to size of X-Sendfile static file, 437 * determined by open(), fstat() to reduces race conditions if the file 438 * is modified between stat() (stat_cache_get_entry()) and open(). */ 439 if (light_btst(r->resp_htags, HTTP_HEADER_CONTENT_LENGTH)) { 440 http_header_response_unset(r, HTTP_HEADER_CONTENT_LENGTH, 441 CONST_STR_LEN("Content-Length")); 442 } 443 444 buffer_urldecode_path(path); 445 if (!buffer_is_valid_UTF8(path)) { 446 log_error(r->conf.errh, __FILE__, __LINE__, 447 "X-Sendfile invalid UTF-8 after url-decode: %s", path->ptr); 448 if (r->http_status < 400) { 449 r->http_status = 502; 450 r->handler_module = NULL; 451 } 452 return; 453 } 454 buffer_path_simplify(path, path); 455 if (r->conf.force_lowercase_filenames) { 456 buffer_to_lower(path); 457 } 458 if (buffer_string_is_empty(path)) { 459 r->http_status = 502; 460 valid = 0; 461 } 462 463 /* check that path is under xdocroot(s) 464 * - xdocroot should have trailing slash appended at config time 465 * - r->conf.force_lowercase_filenames is not a server-wide setting, 466 * and so can not be definitively applied to xdocroot at config time*/ 467 if (xdocroot) { 468 size_t i, xlen = buffer_string_length(path); 469 for (i = 0; i < xdocroot->used; ++i) { 470 data_string *ds = (data_string *)xdocroot->data[i]; 471 size_t dlen = buffer_string_length(&ds->value); 472 if (dlen <= xlen 473 && (!r->conf.force_lowercase_filenames 474 ? 0 == memcmp(path->ptr, ds->value.ptr, dlen) 475 : buffer_eq_icase_ssn(path->ptr, ds->value.ptr, dlen))) { 476 break; 477 } 478 } 479 if (i == xdocroot->used && 0 != i) { 480 log_error(r->conf.errh, __FILE__, __LINE__, 481 "X-Sendfile (%s) not under configured x-sendfile-docroot(s)", path->ptr); 482 r->http_status = 403; 483 valid = 0; 484 } 485 } 486 487 if (valid) http_response_send_file(r, path); 488 489 if (r->http_status >= 400 && status < 300) { 490 r->handler_module = NULL; 491 } else if (0 != status && 200 != status) { 492 r->http_status = status; 493 } 494 } 495 496 497 static void http_response_xsendfile2(request_st * const r, const buffer * const value, const array * const xdocroot) { 498 const char *pos = value->ptr; 499 buffer * const b = r->tmp_buf; 500 const int status = r->http_status; 501 502 /* reset Content-Length, if set by backend */ 503 if (light_btst(r->resp_htags, HTTP_HEADER_CONTENT_LENGTH)) { 504 http_header_response_unset(r, HTTP_HEADER_CONTENT_LENGTH, 505 CONST_STR_LEN("Content-Length")); 506 } 507 508 while (*pos) { 509 const char *filename, *range; 510 stat_cache_entry *sce; 511 off_t begin_range, end_range, range_len; 512 513 while (' ' == *pos) pos++; 514 if (!*pos) break; 515 516 filename = pos; 517 if (NULL == (range = strchr(pos, ' '))) { 518 /* missing range */ 519 log_error(r->conf.errh, __FILE__, __LINE__, 520 "Couldn't find range after filename: %s", filename); 521 r->http_status = 502; 522 break; 523 } 524 buffer_copy_string_len(b, filename, range - filename); 525 526 /* find end of range */ 527 for (pos = ++range; *pos && *pos != ' ' && *pos != ','; pos++) ; 528 529 buffer_urldecode_path(b); 530 if (!buffer_is_valid_UTF8(b)) { 531 log_error(r->conf.errh, __FILE__, __LINE__, 532 "X-Sendfile2 invalid UTF-8 after url-decode: %s", b->ptr); 533 r->http_status = 502; 534 break; 535 } 536 buffer_path_simplify(b, b); 537 if (r->conf.force_lowercase_filenames) { 538 buffer_to_lower(b); 539 } 540 if (buffer_string_is_empty(b)) { 541 r->http_status = 502; 542 break; 543 } 544 if (xdocroot) { 545 size_t i, xlen = buffer_string_length(b); 546 for (i = 0; i < xdocroot->used; ++i) { 547 data_string *ds = (data_string *)xdocroot->data[i]; 548 size_t dlen = buffer_string_length(&ds->value); 549 if (dlen <= xlen 550 && (!r->conf.force_lowercase_filenames 551 ? 0 == memcmp(b->ptr, ds->value.ptr, dlen) 552 : buffer_eq_icase_ssn(b->ptr, ds->value.ptr, dlen))) { 553 break; 554 } 555 } 556 if (i == xdocroot->used && 0 != i) { 557 log_error(r->conf.errh, __FILE__, __LINE__, 558 "X-Sendfile2 (%s) not under configured x-sendfile-docroot(s)", 559 b->ptr); 560 r->http_status = 403; 561 break; 562 } 563 } 564 565 sce = stat_cache_get_entry_open(b, r->conf.follow_symlink); 566 if (NULL == sce) { 567 log_error(r->conf.errh, __FILE__, __LINE__, 568 "send-file error: couldn't get stat_cache entry for " 569 "X-Sendfile2: %s", b->ptr); 570 r->http_status = 404; 571 break; 572 } else if (!S_ISREG(sce->st.st_mode)) { 573 log_error(r->conf.errh, __FILE__, __LINE__, 574 "send-file error: wrong filetype for X-Sendfile2: %s", b->ptr); 575 r->http_status = 502; 576 break; 577 } 578 /* found the file */ 579 580 /* parse range */ 581 end_range = sce->st.st_size - 1; 582 { 583 char *rpos = NULL; 584 errno = 0; 585 begin_range = strtoll(range, &rpos, 10); 586 if (errno != 0 || begin_range < 0 || rpos == range) 587 goto range_failed; 588 if ('-' != *rpos++) goto range_failed; 589 if (rpos != pos) { 590 range = rpos; 591 end_range = strtoll(range, &rpos, 10); 592 if (errno != 0 || end_range < 0 || rpos == range) 593 goto range_failed; 594 } 595 if (rpos != pos) goto range_failed; 596 597 goto range_success; 598 599 range_failed: 600 log_error(r->conf.errh, __FILE__, __LINE__, 601 "Couldn't decode range after filename: %s", filename); 602 r->http_status = 502; 603 break; 604 605 range_success: ; 606 } 607 608 /* no parameters accepted */ 609 610 while (*pos == ' ') pos++; 611 if (*pos != '\0' && *pos != ',') { 612 r->http_status = 502; 613 break; 614 } 615 616 range_len = end_range - begin_range + 1; 617 if (range_len < 0) { 618 r->http_status = 502; 619 break; 620 } 621 if (range_len != 0) { 622 http_chunk_append_file_ref_range(r, sce, begin_range, range_len); 623 } 624 625 if (*pos == ',') pos++; 626 } 627 628 if (r->http_status >= 400 && status < 300) { 629 r->handler_module = NULL; 630 } else if (0 != status && 200 != status) { 631 r->http_status = status; 632 } 633 } 634 635 636 void http_response_backend_error (request_st * const r) { 637 if (r->resp_body_started) { 638 /*(response might have been already started, kill the connection)*/ 639 /*(mode == DIRECT to avoid later call to http_response_backend_done())*/ 640 r->handler_module = NULL; /*(avoid sending final chunked block)*/ 641 r->keep_alive = 0; 642 r->resp_body_finished = 1; 643 } /*(else error status set later by http_response_backend_done())*/ 644 } 645 646 void http_response_backend_done (request_st * const r) { 647 /* (not CON_STATE_ERROR and not CON_STATE_RESPONSE_END, 648 * i.e. not called from handle_connection_close or handle_request_reset 649 * hooks, except maybe from errdoc handler, which later resets state)*/ 650 switch (r->state) { 651 case CON_STATE_HANDLE_REQUEST: 652 case CON_STATE_READ_POST: 653 if (!r->resp_body_started) { 654 /* Send an error if we haven't sent any data yet */ 655 r->http_status = 500; 656 r->handler_module = NULL; 657 break; 658 } 659 __attribute_fallthrough__ 660 case CON_STATE_WRITE: 661 if (!r->resp_body_finished) { 662 if (r->http_version == HTTP_VERSION_1_1) 663 http_chunk_close(r); 664 r->resp_body_finished = 1; 665 } 666 default: 667 break; 668 } 669 } 670 671 672 void http_response_upgrade_read_body_unknown(request_st * const r) { 673 /* act as transparent proxy */ 674 if (!(r->conf.stream_request_body & FDEVENT_STREAM_REQUEST)) 675 r->conf.stream_request_body |= 676 (FDEVENT_STREAM_REQUEST_BUFMIN | FDEVENT_STREAM_REQUEST); 677 if (!(r->conf.stream_response_body & FDEVENT_STREAM_RESPONSE)) 678 r->conf.stream_response_body |= 679 (FDEVENT_STREAM_RESPONSE_BUFMIN | FDEVENT_STREAM_RESPONSE); 680 r->conf.stream_request_body |= FDEVENT_STREAM_REQUEST_POLLIN; 681 r->reqbody_length = -2; 682 r->resp_body_scratchpad = -1; 683 r->keep_alive = 0; 684 } 685 686 687 static int http_response_process_headers(request_st * const r, http_response_opts * const opts, buffer * const hdrs) { 688 char *ns; 689 const char *s; 690 int line = 0; 691 int status_is_set = 0; 692 693 for (s = hdrs->ptr; NULL != (ns = strchr(s, '\n')); s = ns + 1, ++line) { 694 const char *key, *value; 695 int key_len; 696 enum http_header_e id; 697 698 /* strip the \n */ 699 ns[0] = '\0'; 700 if (ns > s && ns[-1] == '\r') ns[-1] = '\0'; 701 702 if (0 == line && (ns - s) >= 12 && 0 == memcmp(s, "HTTP/", 5)) { 703 /* non-parsed headers ... we parse them anyway */ 704 /* (accept HTTP/2.0 and HTTP/3.0 from naive non-proxy backends) */ 705 if ((s[5] == '1' || opts->backend != BACKEND_PROXY) && s[6] == '.' 706 && (s[7] == '1' || s[7] == '0') && s[8] == ' ') { 707 /* after the space should be a status code for us */ 708 int status = http_header_str_to_code(s+9); 709 if (status >= 100 && status < 1000) { 710 status_is_set = 1; 711 light_bset(r->resp_htags, HTTP_HEADER_STATUS); 712 r->http_status = status; 713 } /* else we expected 3 digits and didn't get them */ 714 } 715 716 if (0 == r->http_status) { 717 log_error(r->conf.errh, __FILE__, __LINE__, 718 "invalid HTTP status line: %s", s); 719 r->http_status = 502; /* Bad Gateway */ 720 r->handler_module = NULL; 721 return -1; 722 } 723 724 continue; 725 } 726 727 /* parse the headers */ 728 key = s; 729 if (NULL == (value = strchr(s, ':'))) { 730 /* we expect: "<key>: <value>\r\n" */ 731 continue; 732 } 733 734 key_len = value - key; 735 if (0 == key_len) continue; /*(already ignored when writing response)*/ 736 do { ++value; } while (*value == ' ' || *value == '\t'); /* skip LWS */ 737 id = http_header_hkey_get(key, key_len); 738 739 if (opts->authorizer) { 740 if (0 == r->http_status || 200 == r->http_status) { 741 if (id == HTTP_HEADER_STATUS) { 742 int status = http_header_str_to_code(value); 743 if (status >= 100 && status < 1000) { 744 r->http_status = status; 745 } else { 746 r->http_status = 502; /* Bad Gateway */ 747 break; 748 } 749 } 750 else if (id == HTTP_HEADER_OTHER && key_len > 9 751 && (key[0] & 0xdf) == 'V' 752 && buffer_eq_icase_ssn(key, 753 CONST_STR_LEN("Variable-"))) { 754 http_header_env_append(r, key + 9, key_len - 9, value, strlen(value)); 755 } 756 continue; 757 } 758 } 759 760 switch (id) { 761 case HTTP_HEADER_STATUS: 762 { 763 if (opts->backend == BACKEND_PROXY) break; /*(pass w/o parse)*/ 764 int status = http_header_str_to_code(value); 765 if (status >= 100 && status < 1000) { 766 r->http_status = status; 767 status_is_set = 1; 768 } else { 769 r->http_status = 502; 770 r->handler_module = NULL; 771 } 772 continue; /* do not send Status to client */ 773 } 774 break; 775 case HTTP_HEADER_UPGRADE: 776 /*(technically, should also verify Connection: upgrade)*/ 777 /*(flag only for mod_proxy and mod_cgi (for now))*/ 778 if (opts->backend != BACKEND_PROXY && opts->backend != BACKEND_CGI) 779 continue; 780 if (r->http_version >= HTTP_VERSION_2) continue; 781 break; 782 case HTTP_HEADER_CONNECTION: 783 if (opts->backend == BACKEND_PROXY) continue; 784 /*(should parse for tokens and do case-insensitive match for "close" 785 * but this is an imperfect though simplistic attempt to honor 786 * backend request to close)*/ 787 if (NULL != strstr(value, "lose")) r->keep_alive = 0; 788 if (r->http_version >= HTTP_VERSION_2) continue; 789 break; 790 case HTTP_HEADER_CONTENT_LENGTH: 791 if (*value == '+') ++value; 792 if (!r->resp_decode_chunked 793 && !light_btst(r->resp_htags, HTTP_HEADER_CONTENT_LENGTH)) { 794 const char *err = ns; 795 if (err[-1] == '\0') --err; /*(skip one '\0', trailing whitespace)*/ 796 while (err > value && (err[-1] == ' ' || err[-1] == '\t')) --err; 797 if (err <= value) continue; /*(might error 502 Bad Gateway)*/ 798 uint32_t vlen = (uint32_t)(err - value); 799 r->resp_body_scratchpad = 800 (off_t)li_restricted_strtoint64(value, vlen, &err); 801 if (err != value + vlen) { 802 /*(invalid Content-Length value from backend; 803 * read from backend until backend close, hope for the best) 804 *(might choose to treat this as 502 Bad Gateway) */ 805 r->resp_body_scratchpad = -1; 806 } 807 } 808 else { 809 /* ignore Content-Length if Transfer-Encoding: chunked 810 * ignore subsequent (multiple) Content-Length 811 * (might choose to treat this as 502 Bad Gateway) */ 812 continue; 813 } 814 break; 815 case HTTP_HEADER_TRANSFER_ENCODING: 816 if (light_btst(r->resp_htags, HTTP_HEADER_CONTENT_LENGTH)) { 817 /* ignore Content-Length if Transfer-Encoding: chunked 818 * (might choose to treat this as 502 Bad Gateway) */ 819 r->resp_body_scratchpad = -1; 820 http_header_response_unset(r, HTTP_HEADER_CONTENT_LENGTH, 821 CONST_STR_LEN("Content-Length")); 822 } 823 /*(assumes "Transfer-Encoding: chunked"; does not verify)*/ 824 r->resp_decode_chunked = 1; 825 r->gw_dechunk = calloc(1, sizeof(response_dechunk)); 826 /* XXX: future: might consider using chunk_buffer_acquire() 827 * and chunk_buffer_release() for r->gw_dechunk->b */ 828 force_assert(r->gw_dechunk); 829 continue; 830 case HTTP_HEADER_HTTP2_SETTINGS: 831 /* RFC7540 3.2.1 832 * A server MUST NOT send this header field. */ 833 /* (not bothering to remove HTTP2-Settings from Connection) */ 834 continue; 835 default: 836 break; 837 } 838 839 http_header_response_insert(r, id, key, key_len, value, strlen(value)); 840 } 841 842 /* CGI/1.1 rev 03 - 7.2.1.2 */ 843 /* (proxy requires Status-Line, so never true for proxy)*/ 844 if (!status_is_set && light_btst(r->resp_htags, HTTP_HEADER_LOCATION)) { 845 r->http_status = 302; 846 } 847 848 return 0; 849 } 850 851 852 static http_response_send_1xx_cb http_response_send_1xx_h1; 853 static http_response_send_1xx_cb http_response_send_1xx_h2; 854 855 void 856 http_response_send_1xx_cb_set (http_response_send_1xx_cb fn, int vers) 857 { 858 if (vers >= HTTP_VERSION_2) 859 http_response_send_1xx_h2 = fn; 860 else if (vers == HTTP_VERSION_1_1) 861 http_response_send_1xx_h1 = fn; 862 } 863 864 865 int 866 http_response_send_1xx (request_st * const r) 867 { 868 http_response_send_1xx_cb http_response_send_1xx_fn = NULL; 869 if (r->http_version >= HTTP_VERSION_2) 870 http_response_send_1xx_fn = http_response_send_1xx_h2; 871 else if (r->http_version == HTTP_VERSION_1_1) 872 http_response_send_1xx_fn = http_response_send_1xx_h1; 873 874 if (http_response_send_1xx_fn && !http_response_send_1xx_fn(r, r->con)) 875 return 0; /* error occurred */ 876 877 http_response_header_clear(r); 878 return 1; /* 1xx response handled */ 879 } 880 881 882 __attribute_cold__ 883 __attribute_noinline__ 884 static int 885 http_response_check_1xx (request_st * const r, buffer * const restrict b, uint32_t hlen, uint32_t dlen) 886 { 887 /* pass through unset r->http_status (not 1xx) or 101 Switching Protocols */ 888 if (0 == r->http_status || 101 == r->http_status) 889 return 0; /* pass through as-is; do not loop for addtl response hdrs */ 890 891 /* discard 1xx response from b; already processed 892 * (but further response might follow in b, so preserve addtl data) */ 893 if (dlen) 894 memmove(b->ptr, b->ptr+hlen, dlen); 895 buffer_string_set_length(b, dlen); 896 897 /* Note: while GW_AUTHORIZER mode is not expected to return 1xx, as a 898 * feature, 1xx responses from authorizer are passed back to client */ 899 900 return http_response_send_1xx(r); 901 /* 0: error, 1: 1xx response handled; loop for next response headers */ 902 } 903 904 905 __attribute_hot__ 906 __attribute_pure__ 907 static const char * 908 http_response_end_of_header (const char * const restrict ptr) 909 { 910 /* find \n(\r)?\n sequence */ 911 for (const char *n=ptr-1, *nn=NULL; NULL != (n = strchr(n+1, '\n')); nn=n) { 912 if (n - nn == 2 ? n[-1] == '\r' : n - nn == 1) return n+1; 913 } 914 return NULL; 915 } 916 917 918 handler_t http_response_parse_headers(request_st * const r, http_response_opts * const opts, buffer * const b) { 919 /** 920 * possible formats of response headers: 921 * 922 * proxy or NPH (non-parsed headers): 923 * 924 * HTTP/1.0 200 Ok\n 925 * Header: Value\n 926 * \n 927 * 928 * CGI: 929 * 930 * Header: Value\n 931 * Status: 200\n 932 * \n 933 * 934 * and different mixes of \n and \r\n combinations 935 * 936 * Some users also forget about CGI and just send a response 937 * and hope we handle it. No headers, no header-content separator 938 */ 939 const char *bstart; 940 uint32_t blen; 941 942 do { 943 944 blen = buffer_string_length(b); 945 /*("HTTP/1.1 200 " is at least 13 chars + \r\n, but accept w/o final ' ')*/ 946 const int is_nph = (blen >= 12 && 0 == memcmp(b->ptr, "HTTP/", 5)); 947 948 int is_header_end = 0; 949 uint32_t i = 0; 950 951 if (b->ptr[0] == '\n' || (b->ptr[0] == '\r' && b->ptr[1] == '\n')) { 952 /* no HTTP headers */ 953 i = (b->ptr[0] == '\n') ? 0 : 1; 954 is_header_end = 1; 955 } else if (is_nph || b->ptr[(i = strcspn(b->ptr, ":\n"))] == ':') { 956 /* HTTP headers */ 957 const char *n = http_response_end_of_header(b->ptr+i+1); 958 if (n) { 959 i = (uint32_t)(n - b->ptr - 1); 960 is_header_end = 1; 961 } 962 } else if (i == blen) { /* (no newline yet; partial header line?) */ 963 } else if (opts->backend == BACKEND_CGI) { 964 /* no HTTP headers, but a body (special-case for CGI compat) */ 965 /* no colon found; does not appear to be HTTP headers */ 966 if (0 != http_chunk_append_buffer(r, b)) { 967 return HANDLER_ERROR; 968 } 969 r->http_status = 200; /* OK */ 970 r->resp_body_started = 1; 971 return HANDLER_GO_ON; 972 } else { 973 /* invalid response headers */ 974 r->http_status = 502; /* Bad Gateway */ 975 r->handler_module = NULL; 976 return HANDLER_FINISHED; 977 } 978 979 if (!is_header_end) { 980 if (blen > MAX_HTTP_RESPONSE_FIELD_SIZE) { 981 log_error(r->conf.errh, __FILE__, __LINE__, 982 "response headers too large for %s", r->uri.path.ptr); 983 r->http_status = 502; /* Bad Gateway */ 984 r->handler_module = NULL; 985 return HANDLER_FINISHED; 986 } 987 return HANDLER_GO_ON; 988 } 989 990 /* the body starts after the EOL */ 991 bstart = b->ptr + (i + 1); 992 blen -= (i + 1); 993 994 /* strip the last \r?\n */ 995 if (i > 0 && (b->ptr[i - 1] == '\r')) { 996 i--; 997 } 998 999 buffer_string_set_length(b, i); 1000 1001 if (opts->backend == BACKEND_PROXY && !is_nph) { 1002 /* invalid response Status-Line from HTTP proxy */ 1003 r->http_status = 502; /* Bad Gateway */ 1004 r->handler_module = NULL; 1005 return HANDLER_FINISHED; 1006 } 1007 1008 if (0 != http_response_process_headers(r, opts, b)) { 1009 return HANDLER_ERROR; 1010 } 1011 1012 } while (r->http_status < 200 1013 && http_response_check_1xx(r, b, bstart - b->ptr, blen)); 1014 1015 r->resp_body_started = 1; 1016 1017 if (opts->authorizer 1018 && (r->http_status == 0 || r->http_status == 200)) { 1019 return HANDLER_GO_ON; 1020 } 1021 1022 if (NULL == r->handler_module) { 1023 return HANDLER_FINISHED; 1024 } 1025 1026 if (opts->local_redir && r->http_status >= 300 && r->http_status < 400 1027 && 0 == blen) { 1028 /* (Might not have begun to receive body yet, but do skip local-redir 1029 * if we already have started receiving a response body (blen > 0)) */ 1030 /*(light_btst(r->resp_htags, HTTP_HEADER_LOCATION))*/ 1031 handler_t rc = http_cgi_local_redir(r); 1032 if (rc != HANDLER_GO_ON) return rc; 1033 } 1034 1035 if (opts->xsendfile_allow) { 1036 buffer *vb; 1037 /* X-Sendfile2 is deprecated; historical for fastcgi */ 1038 if (opts->backend == BACKEND_FASTCGI 1039 && NULL != (vb = http_header_response_get(r, HTTP_HEADER_OTHER, 1040 CONST_STR_LEN("X-Sendfile2")))) { 1041 http_response_xsendfile2(r, vb, opts->xsendfile_docroot); 1042 /* http_header_response_unset() shortcut for HTTP_HEADER_OTHER */ 1043 buffer_clear(vb); /*(do not send to client)*/ 1044 if (NULL == r->handler_module) 1045 r->resp_body_started = 0; 1046 return HANDLER_FINISHED; 1047 } else if (NULL != (vb = http_header_response_get(r, HTTP_HEADER_OTHER, 1048 CONST_STR_LEN("X-Sendfile"))) 1049 || (opts->backend == BACKEND_FASTCGI /* X-LIGHTTPD-send-file is deprecated; historical for fastcgi */ 1050 && NULL != (vb = http_header_response_get(r, HTTP_HEADER_OTHER, 1051 CONST_STR_LEN("X-LIGHTTPD-send-file"))))) { 1052 http_response_xsendfile(r, vb, opts->xsendfile_docroot); 1053 /* http_header_response_unset() shortcut for HTTP_HEADER_OTHER */ 1054 buffer_clear(vb); /*(do not send to client)*/ 1055 if (NULL == r->handler_module) 1056 r->resp_body_started = 0; 1057 return HANDLER_FINISHED; 1058 } 1059 } 1060 1061 if (blen > 0) { 1062 if (0 != http_chunk_decode_append_mem(r, bstart, blen)) 1063 return HANDLER_ERROR; 1064 } 1065 1066 /* (callback for response headers complete) */ 1067 return (opts->headers) ? opts->headers(r, opts) : HANDLER_GO_ON; 1068 } 1069 1070 1071 handler_t http_response_read(request_st * const r, http_response_opts * const opts, buffer * const b, fdnode * const fdn) { 1072 const int fd = fdn->fd; 1073 while (1) { 1074 ssize_t n; 1075 size_t avail = buffer_string_space(b); 1076 unsigned int toread = 0; 1077 1078 if (0 == fdevent_ioctl_fionread(fd, opts->fdfmt, (int *)&toread)) { 1079 if (avail < toread) { 1080 size_t blen = buffer_string_length(b); 1081 if (toread + blen < 4096) 1082 toread = 4095 - blen; 1083 else if (toread > MAX_READ_LIMIT) 1084 toread = MAX_READ_LIMIT; 1085 } 1086 else if (0 == toread) { 1087 #if 0 1088 return (fdevent_fdnode_interest(fdn) & FDEVENT_IN) 1089 ? HANDLER_FINISHED /* read finished */ 1090 : HANDLER_GO_ON; /* optimistic read; data not ready */ 1091 #else 1092 if (!(fdevent_fdnode_interest(fdn) & FDEVENT_IN)) { 1093 if (!(r->conf.stream_response_body 1094 & FDEVENT_STREAM_RESPONSE_POLLRDHUP)) 1095 return HANDLER_GO_ON;/*optimistic read; data not ready*/ 1096 } 1097 if (0 == avail) /* let read() below indicate if EOF or EAGAIN */ 1098 toread = 1024; 1099 #endif 1100 } 1101 } 1102 else if (avail < 1024) { 1103 toread = 4095 - avail; 1104 } 1105 1106 if (r->conf.stream_response_body & FDEVENT_STREAM_RESPONSE_BUFMIN) { 1107 off_t cqlen = chunkqueue_length(&r->write_queue); 1108 if (cqlen + (off_t)toread > 65536 - 4096) { 1109 if (!r->con->is_writable) { 1110 /*(defer removal of FDEVENT_IN interest since 1111 * connection_state_machine() might be able to send data 1112 * immediately, unless !con->is_writable, where 1113 * connection_state_machine() might not loop back to call 1114 * mod_proxy_handle_subrequest())*/ 1115 fdevent_fdnode_event_clr(r->con->srv->ev, fdn, FDEVENT_IN); 1116 } 1117 if (cqlen >= 65536-1) return HANDLER_GO_ON; 1118 toread = 65536 - 1 - (unsigned int)cqlen; 1119 /* Note: heuristic is fuzzy in that it limits how much to read 1120 * from backend based on how much is pending to write to client. 1121 * Modules where data from backend is framed (e.g. FastCGI) may 1122 * want to limit how much is buffered from backend while waiting 1123 * for a complete data frame or data packet from backend. */ 1124 } 1125 } 1126 1127 if (avail < toread) { 1128 /*(add avail+toread to reduce allocations when ioctl EOPNOTSUPP)*/ 1129 avail = avail ? avail - 1 + toread : toread; 1130 avail = chunk_buffer_prepare_append(b, avail); 1131 } 1132 1133 n = read(fd, b->ptr+buffer_string_length(b), avail); 1134 1135 if (n < 0) { 1136 switch (errno) { 1137 case EAGAIN: 1138 #ifdef EWOULDBLOCK 1139 #if EWOULDBLOCK != EAGAIN 1140 case EWOULDBLOCK: 1141 #endif 1142 #endif 1143 case EINTR: 1144 return HANDLER_GO_ON; 1145 default: 1146 log_perror(r->conf.errh, __FILE__, __LINE__, 1147 "read() %d %d", r->con->fd, fd); 1148 return HANDLER_ERROR; 1149 } 1150 } 1151 1152 buffer_commit(b, (size_t)n); 1153 #ifdef __COVERITY__ 1154 /* Coverity Scan overlooks the effect of buffer_commit() */ 1155 b->ptr[buffer_string_length(b)+n] = '\0'; 1156 #endif 1157 1158 if (NULL != opts->parse) { 1159 handler_t rc = opts->parse(r, opts, b, (size_t)n); 1160 if (rc != HANDLER_GO_ON) return rc; 1161 } else if (0 == n) { 1162 /* note: no further data is sent to backend after read EOF on socket 1163 * (not checking for half-closed TCP socket) 1164 * (backend should read all data desired prior to closing socket, 1165 * though might send app-level close data frame, if applicable) */ 1166 return HANDLER_FINISHED; /* read finished */ 1167 } else if (0 == r->resp_body_started) { 1168 /* split header from body */ 1169 handler_t rc = http_response_parse_headers(r, opts, b); 1170 if (rc != HANDLER_GO_ON) return rc; 1171 /* accumulate response in b until headers completed (or error) */ 1172 if (r->resp_body_started) buffer_clear(b); 1173 } else { 1174 if (0 != http_chunk_decode_append_buffer(r, b)) { 1175 /* error writing to tempfile; 1176 * truncate response or send 500 if nothing sent yet */ 1177 return HANDLER_ERROR; 1178 } 1179 buffer_clear(b); 1180 } 1181 1182 if (r->conf.stream_response_body & FDEVENT_STREAM_RESPONSE_BUFMIN) { 1183 if (chunkqueue_length(&r->write_queue) > 65536 - 4096) { 1184 /*(defer removal of FDEVENT_IN interest since 1185 * connection_state_machine() might be able to send 1186 * data immediately, unless !con->is_writable, where 1187 * connection_state_machine() might not loop back to 1188 * call the subrequest handler)*/ 1189 if (!r->con->is_writable) 1190 fdevent_fdnode_event_clr(r->con->srv->ev, fdn, FDEVENT_IN); 1191 break; 1192 } 1193 } 1194 1195 if ((size_t)n < avail) 1196 break; /* emptied kernel read buffer or partial read */ 1197 } 1198 1199 return HANDLER_GO_ON; 1200 } 1201