1 #include "first.h" 2 3 #include "base.h" 4 #include "array.h" 5 #include "buffer.h" 6 #include "chunk.h" 7 #include "fdevent.h" 8 #include "log.h" 9 #include "etag.h" 10 #include "http_chunk.h" 11 #include "http_header.h" 12 #include "response.h" 13 #include "sock_addr.h" 14 #include "stat_cache.h" 15 16 #include <stdlib.h> 17 #include <string.h> 18 #include <errno.h> 19 #include <fcntl.h> 20 21 #include <time.h> 22 23 #include "sys-socket.h" 24 #include <unistd.h> 25 26 /** 27 * max size of the HTTP response header from backends 28 * (differs from server.max-request-field-size for max request field size) 29 */ 30 #define MAX_HTTP_RESPONSE_FIELD_SIZE 65535 31 32 33 __attribute_cold__ 34 static int http_response_buffer_append_authority(request_st * const r, buffer * const o) { 35 if (!buffer_string_is_empty(&r->uri.authority)) { 36 buffer_append_string_buffer(o, &r->uri.authority); 37 } else { 38 /* get the name of the currently connected socket */ 39 sock_addr our_addr; 40 socklen_t our_addr_len; 41 42 our_addr.plain.sa_family = 0; 43 our_addr_len = sizeof(our_addr); 44 45 if (-1 == getsockname(r->con->fd, (struct sockaddr *)&our_addr, &our_addr_len) 46 || our_addr_len > (socklen_t)sizeof(our_addr)) { 47 r->http_status = 500; 48 log_perror(r->conf.errh, __FILE__, __LINE__, "can't get sockname"); 49 return -1; 50 } 51 52 if (our_addr.plain.sa_family == AF_INET 53 && our_addr.ipv4.sin_addr.s_addr == htonl(INADDR_LOOPBACK)) { 54 static char lhost[32]; 55 static size_t lhost_len = 0; 56 if (0 != lhost_len) { 57 buffer_append_string_len(o, lhost, lhost_len); 58 } 59 else { 60 size_t olen = buffer_string_length(o); 61 if (0 == sock_addr_nameinfo_append_buffer(o, &our_addr, r->conf.errh)) { 62 lhost_len = buffer_string_length(o) - olen; 63 if (lhost_len < sizeof(lhost)) { 64 memcpy(lhost, o->ptr+olen, lhost_len+1); /*(+1 for '\0')*/ 65 } 66 else { 67 lhost_len = 0; 68 } 69 } 70 else { 71 lhost_len = sizeof("localhost")-1; 72 memcpy(lhost, "localhost", lhost_len+1); /*(+1 for '\0')*/ 73 buffer_append_string_len(o, lhost, lhost_len); 74 } 75 } 76 } else if (!buffer_string_is_empty(r->server_name)) { 77 buffer_append_string_buffer(o, r->server_name); 78 } else 79 /* Lookup name: secondly try to get hostname for bind address */ 80 if (0 != sock_addr_nameinfo_append_buffer(o, &our_addr, r->conf.errh)) { 81 r->http_status = 500; 82 return -1; 83 } 84 85 { 86 unsigned short listen_port = sock_addr_get_port(&our_addr); 87 unsigned short default_port = 80; 88 if (buffer_is_equal_string(&r->uri.scheme, CONST_STR_LEN("https"))) { 89 default_port = 443; 90 } 91 if (0 == listen_port) listen_port = r->con->srv->srvconf.port; 92 if (default_port != listen_port) { 93 buffer_append_string_len(o, CONST_STR_LEN(":")); 94 buffer_append_int(o, listen_port); 95 } 96 } 97 } 98 return 0; 99 } 100 101 int http_response_redirect_to_directory(request_st * const r, int status) { 102 buffer *o = r->tmp_buf; 103 buffer_clear(o); 104 /* XXX: store flag in global at startup? */ 105 if (r->con->srv->srvconf.absolute_dir_redirect) { 106 buffer_copy_buffer(o, &r->uri.scheme); 107 buffer_append_string_len(o, CONST_STR_LEN("://")); 108 if (0 != http_response_buffer_append_authority(r, o)) { 109 return -1; 110 } 111 } 112 buffer_append_string_encoded(o, CONST_BUF_LEN(&r->uri.path), ENCODING_REL_URI); 113 buffer_append_string_len(o, CONST_STR_LEN("/")); 114 if (!buffer_string_is_empty(&r->uri.query)) { 115 buffer_append_string_len(o, CONST_STR_LEN("?")); 116 buffer_append_string_buffer(o, &r->uri.query); 117 } 118 119 if (status >= 300) { 120 http_header_response_set(r, HTTP_HEADER_LOCATION, 121 CONST_STR_LEN("Location"), 122 CONST_BUF_LEN(o)); 123 r->http_status = status; 124 r->resp_body_finished = 1; 125 } 126 else { 127 http_header_response_set(r, HTTP_HEADER_CONTENT_LOCATION, 128 CONST_STR_LEN("Content-Location"), 129 CONST_BUF_LEN(o)); 130 } 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][30]; 142 /* 30-chars for "%a, %d %b %Y %H:%M:%S 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 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 mtime_cache[i].mtime = last_mod; 165 strftime(mtime_cache[i].str.ptr, sizeof(mtime_cache_str[0]), 166 "%a, %d %b %Y %H:%M:%S GMT", gmtime(&mtime_cache[i].mtime)); 167 168 return &mtime_cache[i].str; 169 } 170 171 172 int http_response_handle_cachable(request_st * const r, const buffer * const mtime) { 173 const buffer *vb; 174 175 /* 176 * 14.26 If-None-Match 177 * [...] 178 * If none of the entity tags match, then the server MAY perform the 179 * requested method as if the If-None-Match header field did not exist, 180 * but MUST also ignore any If-Modified-Since header field(s) in the 181 * request. That is, if no entity tags match, then the server MUST NOT 182 * return a 304 (Not Modified) response. 183 */ 184 185 if ((vb = http_header_request_get(r, HTTP_HEADER_IF_NONE_MATCH, 186 CONST_STR_LEN("If-None-Match")))) { 187 /*(weak etag comparison must not be used for ranged requests)*/ 188 int range_request = 189 (r->conf.range_requests 190 && (200 == r->http_status || 0 == r->http_status) 191 && NULL != http_header_request_get(r, HTTP_HEADER_RANGE, 192 CONST_STR_LEN("Range"))); 193 if (etag_is_equal(&r->physical.etag, vb->ptr, !range_request)) { 194 if (http_method_get_or_head(r->http_method)) { 195 r->http_status = 304; 196 return HANDLER_FINISHED; 197 } else { 198 r->http_status = 412; 199 r->handler_module = NULL; 200 return HANDLER_FINISHED; 201 } 202 } 203 } else if (http_method_get_or_head(r->http_method) 204 && (vb = http_header_request_get(r, HTTP_HEADER_IF_MODIFIED_SINCE, 205 CONST_STR_LEN("If-Modified-Since")))) { 206 /* last-modified handling */ 207 size_t used_len; 208 char *semicolon; 209 210 if (NULL == (semicolon = strchr(vb->ptr, ';'))) { 211 used_len = buffer_string_length(vb); 212 } else { 213 used_len = semicolon - vb->ptr; 214 } 215 216 if (buffer_is_equal_string(mtime, vb->ptr, used_len)) { 217 if ('\0' == mtime->ptr[used_len]) r->http_status = 304; 218 return HANDLER_FINISHED; 219 } else { 220 char buf[sizeof("Sat, 23 Jul 2005 21:20:01 GMT")]; 221 time_t t_header, t_file; 222 struct tm tm; 223 224 /* convert to timestamp */ 225 if (used_len >= sizeof(buf)) return HANDLER_GO_ON; 226 227 memcpy(buf, vb->ptr, used_len); 228 buf[used_len] = '\0'; 229 230 if (NULL == strptime(buf, "%a, %d %b %Y %H:%M:%S GMT", &tm)) { 231 /** 232 * parsing failed, let's get out of here 233 */ 234 return HANDLER_GO_ON; 235 } 236 tm.tm_isdst = 0; 237 t_header = mktime(&tm); 238 239 strptime(mtime->ptr, "%a, %d %b %Y %H:%M:%S GMT", &tm); 240 tm.tm_isdst = 0; 241 t_file = mktime(&tm); 242 243 if (t_file > t_header) return HANDLER_GO_ON; 244 245 r->http_status = 304; 246 return HANDLER_FINISHED; 247 } 248 } 249 250 return HANDLER_GO_ON; 251 } 252 253 254 void http_response_body_clear (request_st * const r, int preserve_length) { 255 r->resp_send_chunked = 0; 256 if (light_btst(r->resp_htags, HTTP_HEADER_TRANSFER_ENCODING)) { 257 http_header_response_unset(r, HTTP_HEADER_TRANSFER_ENCODING, 258 CONST_STR_LEN("Transfer-Encoding")); 259 } 260 if (!preserve_length) { /* preserve for HEAD responses and no-content responses (204, 205, 304) */ 261 r->content_length = -1; 262 if (light_btst(r->resp_htags, HTTP_HEADER_CONTENT_LENGTH)) { 263 http_header_response_unset(r, HTTP_HEADER_CONTENT_LENGTH, 264 CONST_STR_LEN("Content-Length")); 265 } 266 /*(if not preserving Content-Length, do not preserve trailers, if any)*/ 267 r->resp_decode_chunked = 0; 268 if (r->gw_dechunk) { 269 free(r->gw_dechunk->b.ptr); 270 free(r->gw_dechunk); 271 r->gw_dechunk = NULL; 272 } 273 } 274 chunkqueue_reset(r->write_queue); 275 } 276 277 278 void http_response_reset (request_st * const r) { 279 r->http_status = 0; 280 r->con->is_writable = 1; 281 r->resp_body_finished = 0; 282 r->resp_body_started = 0; 283 r->handler_module = NULL; 284 if (r->physical.path.ptr) { /*(skip for mod_fastcgi authorizer)*/ 285 buffer_clear(&r->physical.doc_root); 286 buffer_clear(&r->physical.basedir); 287 buffer_clear(&r->physical.etag); 288 buffer_reset(&r->physical.path); 289 buffer_reset(&r->physical.rel_path); 290 } 291 r->resp_htags = 0; 292 r->resp_header_len = 0; 293 r->resp_header_repeated = 0; 294 array_reset_data_strings(&r->resp_headers); 295 http_response_body_clear(r, 0); 296 } 297 298 299 handler_t http_response_reqbody_read_error (request_st * const r, int http_status) { 300 r->keep_alive = 0; 301 302 /*(do not change status if response headers already set and possibly sent)*/ 303 if (0 != r->resp_header_len) return HANDLER_ERROR; 304 305 http_response_body_clear(r, 0); 306 r->http_status = http_status; 307 r->handler_module = NULL; 308 return HANDLER_FINISHED; 309 } 310 311 312 static int http_response_parse_range(request_st * const r, buffer * const path, stat_cache_entry * const sce, const char * const range) { 313 int multipart = 0; 314 int error; 315 off_t start, end; 316 const char *s, *minus; 317 static const char boundary[] = "fkj49sn38dcn3"; 318 const buffer *content_type = 319 http_header_response_get(r, HTTP_HEADER_CONTENT_TYPE, 320 CONST_STR_LEN("Content-Type")); 321 322 start = 0; 323 end = sce->st.st_size - 1; 324 325 r->content_length = 0; 326 327 for (s = range, error = 0; 328 !error && *s && NULL != (minus = strchr(s, '-')); ) { 329 char *err; 330 off_t la = 0, le; 331 *((const char **)&err) = s; /*(quiet clang --analyze)*/ 332 333 if (s != minus) { 334 la = strtoll(s, &err, 10); 335 if (err != minus) { 336 /* should not have multiple range-unit in Range, but 337 * handle just in case multiple Range headers merged */ 338 while (*s == ' ' || *s == '\t') ++s; 339 if (0 != strncmp(s, "bytes=", 6)) return -1; 340 s += 6; 341 if (s != minus) { 342 la = strtoll(s, &err, 10); 343 if (err != minus) return -1; 344 } 345 } 346 } 347 348 if (s == minus) { 349 /* -<stop> */ 350 351 le = strtoll(s, &err, 10); 352 353 if (le == 0) { 354 /* RFC 2616 - 14.35.1 */ 355 356 r->http_status = 416; 357 error = 1; 358 } else if (*err == '\0') { 359 /* end */ 360 s = err; 361 362 end = sce->st.st_size - 1; 363 start = sce->st.st_size + le; 364 } else if (*err == ',') { 365 multipart = 1; 366 s = err + 1; 367 368 end = sce->st.st_size - 1; 369 start = sce->st.st_size + le; 370 } else { 371 error = 1; 372 } 373 374 } else if (*(minus+1) == '\0' || *(minus+1) == ',') { 375 /* <start>- */ 376 377 /* ok */ 378 379 if (*(err + 1) == '\0') { 380 s = err + 1; 381 382 end = sce->st.st_size - 1; 383 start = la; 384 385 } else if (*(err + 1) == ',') { 386 multipart = 1; 387 s = err + 2; 388 389 end = sce->st.st_size - 1; 390 start = la; 391 } else { 392 error = 1; 393 } 394 } else { 395 /* <start>-<stop> */ 396 397 le = strtoll(minus+1, &err, 10); 398 399 /* RFC 2616 - 14.35.1 */ 400 if (la > le) { 401 error = 1; 402 } 403 404 if (*err == '\0') { 405 /* ok, end*/ 406 s = err; 407 408 end = le; 409 start = la; 410 } else if (*err == ',') { 411 multipart = 1; 412 s = err + 1; 413 414 end = le; 415 start = la; 416 } else { 417 /* error */ 418 419 error = 1; 420 } 421 } 422 423 if (!error) { 424 if (start < 0) start = 0; 425 426 /* RFC 2616 - 14.35.1 */ 427 if (end > sce->st.st_size - 1) end = sce->st.st_size - 1; 428 429 if (start > sce->st.st_size - 1) { 430 error = 1; 431 432 r->http_status = 416; 433 } 434 } 435 436 if (!error) { 437 if (multipart) { 438 /* write boundary-header */ 439 buffer *b = r->tmp_buf; 440 buffer_copy_string_len(b, CONST_STR_LEN("\r\n--")); 441 buffer_append_string_len(b, boundary, sizeof(boundary)-1); 442 443 /* write Content-Range */ 444 buffer_append_string_len(b, CONST_STR_LEN("\r\nContent-Range: bytes ")); 445 buffer_append_int(b, start); 446 buffer_append_string_len(b, CONST_STR_LEN("-")); 447 buffer_append_int(b, end); 448 buffer_append_string_len(b, CONST_STR_LEN("/")); 449 buffer_append_int(b, sce->st.st_size); 450 451 if (content_type) { 452 buffer_append_string_len(b, CONST_STR_LEN("\r\nContent-Type: ")); 453 buffer_append_string_buffer(b, content_type); 454 } 455 456 /* write END-OF-HEADER */ 457 buffer_append_string_len(b, CONST_STR_LEN("\r\n\r\n")); 458 459 r->content_length += buffer_string_length(b); 460 chunkqueue_append_mem(r->write_queue, CONST_BUF_LEN(b)); 461 } 462 463 chunkqueue_append_file(r->write_queue, path, start, end - start + 1); 464 r->content_length += end - start + 1; 465 } 466 } 467 468 /* something went wrong */ 469 if (error) return -1; 470 471 buffer * const tb = r->tmp_buf; 472 473 if (multipart) { 474 /* add boundary end */ 475 buffer_copy_string_len(tb, "\r\n--", 4); 476 buffer_append_string_len(tb, boundary, sizeof(boundary)-1); 477 buffer_append_string_len(tb, "--\r\n", 4); 478 479 r->content_length += buffer_string_length(tb); 480 chunkqueue_append_mem(r->write_queue, CONST_BUF_LEN(tb)); 481 482 /* set header-fields */ 483 484 buffer_copy_string_len(tb, CONST_STR_LEN("multipart/byteranges; boundary=")); 485 buffer_append_string_len(tb, boundary, sizeof(boundary)-1); 486 487 /* overwrite content-type */ 488 http_header_response_set(r, HTTP_HEADER_CONTENT_TYPE, 489 CONST_STR_LEN("Content-Type"), 490 CONST_BUF_LEN(tb)); 491 } else { 492 /* add Content-Range-header */ 493 494 buffer_copy_string_len(tb, CONST_STR_LEN("bytes ")); 495 buffer_append_int(tb, start); 496 buffer_append_string_len(tb, CONST_STR_LEN("-")); 497 buffer_append_int(tb, end); 498 buffer_append_string_len(tb, CONST_STR_LEN("/")); 499 buffer_append_int(tb, sce->st.st_size); 500 501 http_header_response_set(r, HTTP_HEADER_CONTENT_RANGE, 502 CONST_STR_LEN("Content-Range"), 503 CONST_BUF_LEN(tb)); 504 } 505 506 /* ok, the file is set-up */ 507 return 0; 508 } 509 510 511 void http_response_send_file (request_st * const r, buffer * const path) { 512 stat_cache_entry * const sce = stat_cache_get_entry(path); 513 const buffer *mtime = NULL; 514 const buffer *vb; 515 int allow_caching = (0 == r->http_status || 200 == r->http_status); 516 517 if (NULL == sce) { 518 r->http_status = (errno == ENOENT) ? 404 : 403; 519 log_error(r->conf.errh, __FILE__, __LINE__, 520 "not a regular file: %s -> %s", r->uri.path.ptr, path->ptr); 521 return; 522 } 523 524 if (!r->conf.follow_symlink 525 && 0 != stat_cache_path_contains_symlink(path, r->conf.errh)) { 526 r->http_status = 403; 527 if (r->conf.log_request_handling) { 528 log_error(r->conf.errh, __FILE__, __LINE__, 529 "-- access denied due symlink restriction"); 530 log_error(r->conf.errh, __FILE__, __LINE__, 531 "Path : %s", path->ptr); 532 } 533 return; 534 } 535 536 /* we only handle regular files */ 537 if (!S_ISREG(sce->st.st_mode)) { 538 r->http_status = 403; 539 if (r->conf.log_file_not_found) { 540 log_error(r->conf.errh, __FILE__, __LINE__, 541 "not a regular file: %s -> %s", 542 r->uri.path.ptr, path->ptr); 543 } 544 return; 545 } 546 547 /*(Note: O_NOFOLLOW affects only the final path segment, 548 * the target file, not any intermediate symlinks along path)*/ 549 const int fd = (0 != sce->st.st_size) 550 ? fdevent_open_cloexec(path->ptr, r->conf.follow_symlink, O_RDONLY, 0) 551 : -1; 552 if (fd < 0 && 0 != sce->st.st_size) { 553 r->http_status = (errno == ENOENT) ? 404 : 403; 554 if (r->conf.log_request_handling) { 555 log_perror(r->conf.errh, __FILE__, __LINE__, 556 "file open failed: %s", path->ptr); 557 } 558 return; 559 } 560 561 /* set response content-type, if not set already */ 562 563 if (NULL == http_header_response_get(r, HTTP_HEADER_CONTENT_TYPE, 564 CONST_STR_LEN("Content-Type"))) { 565 const buffer *content_type = stat_cache_content_type_get(sce, r); 566 if (buffer_string_is_empty(content_type)) { 567 /* we are setting application/octet-stream, but also announce that 568 * this header field might change in the seconds few requests 569 * 570 * This should fix the aggressive caching of FF and the script download 571 * seen by the first installations 572 */ 573 http_header_response_set(r, HTTP_HEADER_CONTENT_TYPE, 574 CONST_STR_LEN("Content-Type"), 575 CONST_STR_LEN("application/octet-stream")); 576 577 allow_caching = 0; 578 } else { 579 http_header_response_set(r, HTTP_HEADER_CONTENT_TYPE, 580 CONST_STR_LEN("Content-Type"), 581 CONST_BUF_LEN(content_type)); 582 } 583 } 584 585 if (r->conf.range_requests) { 586 http_header_response_append(r, HTTP_HEADER_ACCEPT_RANGES, 587 CONST_STR_LEN("Accept-Ranges"), 588 CONST_STR_LEN("bytes")); 589 } 590 591 if (allow_caching) { 592 const buffer *etag = (0 != r->conf.etag_flags) 593 ? stat_cache_etag_get(sce, r->conf.etag_flags) 594 : NULL; 595 if (!buffer_string_is_empty(etag)) { 596 if (NULL == http_header_response_get(r, HTTP_HEADER_ETAG, 597 CONST_STR_LEN("ETag"))) { 598 /* generate e-tag */ 599 etag_mutate(&r->physical.etag, etag); 600 601 http_header_response_set(r, HTTP_HEADER_ETAG, 602 CONST_STR_LEN("ETag"), 603 CONST_BUF_LEN(&r->physical.etag)); 604 } 605 } 606 607 /* prepare header */ 608 mtime = http_header_response_get(r, HTTP_HEADER_LAST_MODIFIED, 609 CONST_STR_LEN("Last-Modified")); 610 if (NULL == mtime) { 611 mtime = strftime_cache_get(sce->st.st_mtime); 612 http_header_response_set(r, HTTP_HEADER_LAST_MODIFIED, 613 CONST_STR_LEN("Last-Modified"), 614 CONST_BUF_LEN(mtime)); 615 } 616 617 if (HANDLER_FINISHED == http_response_handle_cachable(r, mtime)) { 618 if (fd >= 0) close(fd); 619 return; 620 } 621 } 622 623 if (fd < 0) { /* 0-length file */ 624 r->http_status = 200; 625 r->resp_body_finished = 1; 626 /*(Transfer-Encoding should not have been set at this point)*/ 627 http_header_response_set(r, HTTP_HEADER_CONTENT_LENGTH, 628 CONST_STR_LEN("Content-Length"), 629 CONST_STR_LEN("0")); 630 return; 631 } 632 633 if (r->conf.range_requests 634 && (200 == r->http_status || 0 == r->http_status) 635 && NULL != (vb = http_header_request_get(r, HTTP_HEADER_RANGE, 636 CONST_STR_LEN("Range"))) 637 && NULL == http_header_response_get(r, HTTP_HEADER_CONTENT_ENCODING, 638 CONST_STR_LEN("Content-Encoding"))) { 639 const buffer *range = vb; 640 int do_range_request = 1; 641 /* check if we have a conditional GET */ 642 643 if (NULL != (vb = http_header_request_get(r, HTTP_HEADER_IF_RANGE, 644 CONST_STR_LEN("If-Range")))) { 645 /* if the value is the same as our ETag, we do a Range-request, 646 * otherwise a full 200 */ 647 648 if (vb->ptr[0] == '"') { 649 /** 650 * client wants a ETag 651 */ 652 if (!buffer_is_equal(vb, &r->physical.etag)) { 653 do_range_request = 0; 654 } 655 } else if (!mtime) { 656 /** 657 * we don't have a Last-Modified and can match the If-Range: 658 * 659 * sending all 660 */ 661 do_range_request = 0; 662 } else if (!buffer_is_equal(vb, mtime)) { 663 do_range_request = 0; 664 } 665 } 666 667 if (do_range_request 668 && !buffer_string_is_empty(range) 669 && 0 == strncmp(range->ptr, "bytes=", 6)) { 670 /* support only "bytes" byte-unit */ 671 /* content prepared, I'm done */ 672 r->resp_body_finished = 1; 673 674 if (0 == http_response_parse_range(r, path, sce, range->ptr+6)) { 675 r->http_status = 206; 676 } 677 close(fd); 678 return; 679 } 680 } 681 682 /* if we are still here, prepare body */ 683 684 /* we add it here for all requests 685 * the HEAD request will drop it afterwards again 686 */ 687 688 if (0 == http_chunk_append_file_fd(r, path, fd, sce->st.st_size)) { 689 r->http_status = 200; 690 r->resp_body_finished = 1; 691 /*(Transfer-Encoding should not have been set at this point)*/ 692 buffer * const tb = r->tmp_buf; 693 buffer_clear(tb); 694 buffer_append_int(tb, sce->st.st_size); 695 http_header_response_set(r, HTTP_HEADER_CONTENT_LENGTH, 696 CONST_STR_LEN("Content-Length"), 697 CONST_BUF_LEN(tb)); 698 } 699 else { 700 r->http_status = 500; 701 } 702 } 703 704 705 static void http_response_xsendfile (request_st * const r, buffer * const path, const array * const xdocroot) { 706 const int status = r->http_status; 707 int valid = 1; 708 709 /* reset Content-Length, if set by backend 710 * Content-Length might later be set to size of X-Sendfile static file, 711 * determined by open(), fstat() to reduces race conditions if the file 712 * is modified between stat() (stat_cache_get_entry()) and open(). */ 713 if (light_btst(r->resp_htags, HTTP_HEADER_CONTENT_LENGTH)) { 714 http_header_response_unset(r, HTTP_HEADER_CONTENT_LENGTH, 715 CONST_STR_LEN("Content-Length")); 716 r->content_length = -1; 717 } 718 719 buffer_urldecode_path(path); 720 if (!buffer_is_valid_UTF8(path)) { 721 log_error(r->conf.errh, __FILE__, __LINE__, 722 "X-Sendfile invalid UTF-8 after url-decode: %s", path->ptr); 723 if (r->http_status < 400) { 724 r->http_status = 502; 725 r->handler_module = NULL; 726 } 727 return; 728 } 729 buffer_path_simplify(path, path); 730 if (r->conf.force_lowercase_filenames) { 731 buffer_to_lower(path); 732 } 733 734 /* check that path is under xdocroot(s) 735 * - xdocroot should have trailing slash appended at config time 736 * - r->conf.force_lowercase_filenames is not a server-wide setting, 737 * and so can not be definitively applied to xdocroot at config time*/ 738 if (xdocroot) { 739 size_t i, xlen = buffer_string_length(path); 740 for (i = 0; i < xdocroot->used; ++i) { 741 data_string *ds = (data_string *)xdocroot->data[i]; 742 size_t dlen = buffer_string_length(&ds->value); 743 if (dlen <= xlen 744 && (!r->conf.force_lowercase_filenames 745 ? 0 == memcmp(path->ptr, ds->value.ptr, dlen) 746 : buffer_eq_icase_ssn(path->ptr, ds->value.ptr, dlen))) { 747 break; 748 } 749 } 750 if (i == xdocroot->used && 0 != i) { 751 log_error(r->conf.errh, __FILE__, __LINE__, 752 "X-Sendfile (%s) not under configured x-sendfile-docroot(s)", path->ptr); 753 r->http_status = 403; 754 valid = 0; 755 } 756 } 757 758 if (valid) http_response_send_file(r, path); 759 760 if (r->http_status >= 400 && status < 300) { 761 r->handler_module = NULL; 762 } else if (0 != status && 200 != status) { 763 r->http_status = status; 764 } 765 } 766 767 768 static void http_response_xsendfile2(request_st * const r, const buffer * const value, const array * const xdocroot) { 769 const char *pos = value->ptr; 770 buffer * const b = r->tmp_buf; 771 const int status = r->http_status; 772 773 /* reset Content-Length, if set by backend */ 774 if (light_btst(r->resp_htags, HTTP_HEADER_CONTENT_LENGTH)) { 775 http_header_response_unset(r, HTTP_HEADER_CONTENT_LENGTH, 776 CONST_STR_LEN("Content-Length")); 777 r->content_length = -1; 778 } 779 780 while (*pos) { 781 const char *filename, *range; 782 stat_cache_entry *sce; 783 off_t begin_range, end_range, range_len; 784 785 while (' ' == *pos) pos++; 786 if (!*pos) break; 787 788 filename = pos; 789 if (NULL == (range = strchr(pos, ' '))) { 790 /* missing range */ 791 log_error(r->conf.errh, __FILE__, __LINE__, 792 "Couldn't find range after filename: %s", filename); 793 r->http_status = 502; 794 break; 795 } 796 buffer_copy_string_len(b, filename, range - filename); 797 798 /* find end of range */ 799 for (pos = ++range; *pos && *pos != ' ' && *pos != ','; pos++) ; 800 801 buffer_urldecode_path(b); 802 if (!buffer_is_valid_UTF8(b)) { 803 log_error(r->conf.errh, __FILE__, __LINE__, 804 "X-Sendfile2 invalid UTF-8 after url-decode: %s", b->ptr); 805 r->http_status = 502; 806 break; 807 } 808 buffer_path_simplify(b, b); 809 if (r->conf.force_lowercase_filenames) { 810 buffer_to_lower(b); 811 } 812 if (xdocroot) { 813 size_t i, xlen = buffer_string_length(b); 814 for (i = 0; i < xdocroot->used; ++i) { 815 data_string *ds = (data_string *)xdocroot->data[i]; 816 size_t dlen = buffer_string_length(&ds->value); 817 if (dlen <= xlen 818 && (!r->conf.force_lowercase_filenames 819 ? 0 == memcmp(b->ptr, ds->value.ptr, dlen) 820 : buffer_eq_icase_ssn(b->ptr, ds->value.ptr, dlen))) { 821 break; 822 } 823 } 824 if (i == xdocroot->used && 0 != i) { 825 log_error(r->conf.errh, __FILE__, __LINE__, 826 "X-Sendfile2 (%s) not under configured x-sendfile-docroot(s)", 827 b->ptr); 828 r->http_status = 403; 829 break; 830 } 831 } 832 833 sce = stat_cache_get_entry(b); 834 if (NULL == sce) { 835 log_error(r->conf.errh, __FILE__, __LINE__, 836 "send-file error: couldn't get stat_cache entry for " 837 "X-Sendfile2: %s", b->ptr); 838 r->http_status = 404; 839 break; 840 } else if (!S_ISREG(sce->st.st_mode)) { 841 log_error(r->conf.errh, __FILE__, __LINE__, 842 "send-file error: wrong filetype for X-Sendfile2: %s", b->ptr); 843 r->http_status = 502; 844 break; 845 } 846 /* found the file */ 847 848 /* parse range */ 849 end_range = sce->st.st_size - 1; 850 { 851 char *rpos = NULL; 852 errno = 0; 853 begin_range = strtoll(range, &rpos, 10); 854 if (errno != 0 || begin_range < 0 || rpos == range) 855 goto range_failed; 856 if ('-' != *rpos++) goto range_failed; 857 if (rpos != pos) { 858 range = rpos; 859 end_range = strtoll(range, &rpos, 10); 860 if (errno != 0 || end_range < 0 || rpos == range) 861 goto range_failed; 862 } 863 if (rpos != pos) goto range_failed; 864 865 goto range_success; 866 867 range_failed: 868 log_error(r->conf.errh, __FILE__, __LINE__, 869 "Couldn't decode range after filename: %s", filename); 870 r->http_status = 502; 871 break; 872 873 range_success: ; 874 } 875 876 /* no parameters accepted */ 877 878 while (*pos == ' ') pos++; 879 if (*pos != '\0' && *pos != ',') { 880 r->http_status = 502; 881 break; 882 } 883 884 range_len = end_range - begin_range + 1; 885 if (range_len < 0) { 886 r->http_status = 502; 887 break; 888 } 889 if (range_len != 0) { 890 if (0 != 891 http_chunk_append_file_range(r, b, begin_range, range_len)) { 892 r->http_status = 502; 893 break; 894 } 895 } 896 897 if (*pos == ',') pos++; 898 } 899 900 if (r->http_status >= 400 && status < 300) { 901 r->handler_module = NULL; 902 } else if (0 != status && 200 != status) { 903 r->http_status = status; 904 } 905 } 906 907 908 void http_response_backend_error (request_st * const r) { 909 if (r->resp_body_started) { 910 /*(response might have been already started, kill the connection)*/ 911 /*(mode == DIRECT to avoid later call to http_response_backend_done())*/ 912 r->handler_module = NULL; /*(avoid sending final chunked block)*/ 913 r->keep_alive = 0; 914 r->resp_body_finished = 1; 915 } /*(else error status set later by http_response_backend_done())*/ 916 } 917 918 void http_response_backend_done (request_st * const r) { 919 /* (not CON_STATE_ERROR and not CON_STATE_RESPONSE_END, 920 * i.e. not called from handle_connection_close or handle_request_reset 921 * hooks, except maybe from errdoc handler, which later resets state)*/ 922 switch (r->state) { 923 case CON_STATE_HANDLE_REQUEST: 924 case CON_STATE_READ_POST: 925 if (!r->resp_body_started) { 926 /* Send an error if we haven't sent any data yet */ 927 r->http_status = 500; 928 r->handler_module = NULL; 929 break; 930 } /* else fall through */ 931 case CON_STATE_WRITE: 932 if (!r->resp_body_finished) { 933 if (r->http_version == HTTP_VERSION_1_1) 934 http_chunk_close(r); 935 r->resp_body_finished = 1; 936 } 937 default: 938 break; 939 } 940 } 941 942 943 void http_response_upgrade_read_body_unknown(request_st * const r) { 944 /* act as transparent proxy */ 945 if (!(r->conf.stream_request_body & FDEVENT_STREAM_REQUEST)) 946 r->conf.stream_request_body |= 947 (FDEVENT_STREAM_REQUEST_BUFMIN | FDEVENT_STREAM_REQUEST); 948 if (!(r->conf.stream_response_body & FDEVENT_STREAM_RESPONSE)) 949 r->conf.stream_response_body |= 950 (FDEVENT_STREAM_RESPONSE_BUFMIN | FDEVENT_STREAM_RESPONSE); 951 r->conf.stream_request_body |= FDEVENT_STREAM_REQUEST_POLLIN; 952 r->reqbody_length = -2; 953 r->keep_alive = 0; 954 } 955 956 957 static handler_t http_response_process_local_redir(request_st * const r, size_t blen) { 958 /* [RFC3875] The Common Gateway Interface (CGI) Version 1.1 959 * [RFC3875] 6.2.2 Local Redirect Response 960 * 961 * The CGI script can return a URI path and query-string 962 * ('local-pathquery') for a local resource in a Location header field. 963 * This indicates to the server that it should reprocess the request 964 * using the path specified. 965 * 966 * local-redir-response = local-Location NL 967 * 968 * The script MUST NOT return any other header fields or a message-body, 969 * and the server MUST generate the response that it would have produced 970 * in response to a request containing the URL 971 * 972 * scheme "://" server-name ":" server-port local-pathquery 973 * 974 * (Might not have begun to receive body yet, but do skip local-redir 975 * if we already have started receiving a response body (blen > 0)) 976 * (Also, while not required by the RFC, do not send local-redir back 977 * to same URL, since CGI should have handled it internally if it 978 * really wanted to do that internally) 979 */ 980 981 /* r->http_status >= 300 && r->http_status < 400) */ 982 size_t ulen = buffer_string_length(&r->uri.path); 983 const buffer *vb = http_header_response_get(r, HTTP_HEADER_LOCATION, 984 CONST_STR_LEN("Location")); 985 if (NULL != vb 986 && vb->ptr[0] == '/' 987 && (0 != strncmp(vb->ptr, r->uri.path.ptr, ulen) 988 || ( vb->ptr[ulen] != '\0' 989 && vb->ptr[ulen] != '/' 990 && vb->ptr[ulen] != '?')) 991 && 0 == blen /*no "Status" or NPH response*/ 992 && !light_btst(r->resp_htags, HTTP_HEADER_STATUS) 993 && 1 == r->resp_headers.used) { 994 if (++r->loops_per_request > 5) { 995 log_error(r->conf.errh, __FILE__, __LINE__, 996 "too many internal loops while processing request: %s", 997 r->target_orig.ptr); 998 r->http_status = 500; /* Internal Server Error */ 999 r->handler_module = NULL; 1000 return HANDLER_FINISHED; 1001 } 1002 1003 buffer_copy_buffer(&r->target, vb); 1004 1005 if (r->reqbody_length) { 1006 if (r->reqbody_length 1007 != r->reqbody_queue->bytes_in) { 1008 r->keep_alive = 0; 1009 } 1010 r->reqbody_length = 0; 1011 chunkqueue_reset(r->reqbody_queue); 1012 } 1013 1014 if (r->http_status != 307 && r->http_status != 308) { 1015 /* Note: request body (if any) sent to initial dynamic handler 1016 * and is not available to the internal redirect */ 1017 r->http_method = HTTP_METHOD_GET; 1018 } 1019 1020 /*(caller must reset request as follows)*/ 1021 /*http_response_reset(r);*/ /*(sets r->http_status = 0)*/ 1022 /*plugins_call_handle_request_reset(r);*/ 1023 1024 return HANDLER_COMEBACK; 1025 } 1026 1027 return HANDLER_GO_ON; 1028 } 1029 1030 1031 static int http_response_process_headers(request_st * const r, http_response_opts * const opts, buffer * const hdrs) { 1032 char *ns; 1033 const char *s; 1034 int line = 0; 1035 int status_is_set = 0; 1036 1037 for (s = hdrs->ptr; NULL != (ns = strchr(s, '\n')); s = ns + 1, ++line) { 1038 const char *key, *value; 1039 int key_len; 1040 enum http_header_e id; 1041 1042 /* strip the \n */ 1043 ns[0] = '\0'; 1044 if (ns > s && ns[-1] == '\r') ns[-1] = '\0'; 1045 1046 if (0 == line && 0 == strncmp(s, "HTTP/1.", 7)) { 1047 /* non-parsed headers ... we parse them anyway */ 1048 if ((s[7] == '1' || s[7] == '0') && s[8] == ' ') { 1049 /* after the space should be a status code for us */ 1050 int status = http_header_str_to_code(s+9); 1051 if (status >= 100 && status < 1000) { 1052 status_is_set = 1; 1053 light_bset(r->resp_htags, HTTP_HEADER_STATUS); 1054 r->http_status = status; 1055 } /* else we expected 3 digits and didn't get them */ 1056 } 1057 1058 if (0 == r->http_status) { 1059 log_error(r->conf.errh, __FILE__, __LINE__, 1060 "invalid HTTP status line: %s", s); 1061 r->http_status = 502; /* Bad Gateway */ 1062 r->handler_module = NULL; 1063 return -1; 1064 } 1065 1066 continue; 1067 } 1068 1069 /* parse the headers */ 1070 key = s; 1071 if (NULL == (value = strchr(s, ':'))) { 1072 /* we expect: "<key>: <value>\r\n" */ 1073 continue; 1074 } 1075 1076 key_len = value - key; 1077 if (0 == key_len) continue; /*(already ignored when writing response)*/ 1078 do { ++value; } while (*value == ' ' || *value == '\t'); /* skip LWS */ 1079 id = http_header_hkey_get(key, key_len); 1080 1081 if (opts->authorizer) { 1082 if (0 == r->http_status || 200 == r->http_status) { 1083 if (id == HTTP_HEADER_STATUS) { 1084 int status = http_header_str_to_code(value); 1085 if (status >= 100 && status < 1000) { 1086 r->http_status = status; 1087 } else { 1088 r->http_status = 502; /* Bad Gateway */ 1089 break; 1090 } 1091 } 1092 else if (id == HTTP_HEADER_OTHER && key_len > 9 1093 && (key[0] & 0xdf) == 'V' 1094 && buffer_eq_icase_ssn(key, 1095 CONST_STR_LEN("Variable-"))) { 1096 http_header_env_append(r, key + 9, key_len - 9, value, strlen(value)); 1097 } 1098 continue; 1099 } 1100 } 1101 1102 switch (id) { 1103 case HTTP_HEADER_STATUS: 1104 { 1105 if (opts->backend == BACKEND_PROXY) break; /*(pass w/o parse)*/ 1106 int status = http_header_str_to_code(value); 1107 if (status >= 100 && status < 1000) { 1108 r->http_status = status; 1109 status_is_set = 1; 1110 } else { 1111 r->http_status = 502; 1112 r->handler_module = NULL; 1113 } 1114 continue; /* do not send Status to client */ 1115 } 1116 break; 1117 case HTTP_HEADER_UPGRADE: 1118 /*(technically, should also verify Connection: upgrade)*/ 1119 /*(flag only for mod_proxy and mod_cgi (for now))*/ 1120 if (opts->backend != BACKEND_PROXY && opts->backend != BACKEND_CGI) 1121 continue; 1122 if (r->http_version >= HTTP_VERSION_2) continue; 1123 break; 1124 case HTTP_HEADER_CONNECTION: 1125 if (opts->backend == BACKEND_PROXY) continue; 1126 /*(should parse for tokens and do case-insensitive match for "close" 1127 * but this is an imperfect though simplistic attempt to honor 1128 * backend request to close)*/ 1129 if (NULL != strstr(value, "lose")) r->keep_alive = 0; 1130 if (r->http_version >= HTTP_VERSION_2) continue; 1131 break; 1132 case HTTP_HEADER_CONTENT_LENGTH: 1133 r->content_length = strtoul(value, NULL, 10); 1134 if (*value == '+') ++value; 1135 break; 1136 case HTTP_HEADER_TRANSFER_ENCODING: 1137 /*(assumes "Transfer-Encoding: chunked"; does not verify)*/ 1138 r->resp_decode_chunked = 1; 1139 r->gw_dechunk = calloc(1, sizeof(response_dechunk)); 1140 /* XXX: future: might consider using chunk_buffer_acquire() 1141 * and chunk_buffer_release() for r->gw_dechunk->b */ 1142 force_assert(r->gw_dechunk); 1143 continue; 1144 case HTTP_HEADER_HTTP2_SETTINGS: 1145 /* RFC7540 3.2.1 1146 * A server MUST NOT send this header field. */ 1147 /* (not bothering to remove HTTP2-Settings from Connection) */ 1148 continue; 1149 default: 1150 break; 1151 } 1152 1153 http_header_response_insert(r, id, key, key_len, value, strlen(value)); 1154 } 1155 1156 /* CGI/1.1 rev 03 - 7.2.1.2 */ 1157 /* (proxy requires Status-Line, so never true for proxy)*/ 1158 if (!status_is_set && light_btst(r->resp_htags, HTTP_HEADER_LOCATION)) { 1159 r->http_status = 302; 1160 } 1161 1162 return 0; 1163 } 1164 1165 1166 __attribute_hot__ 1167 __attribute_pure__ 1168 static const char * 1169 http_response_end_of_header (const char * const restrict ptr) 1170 { 1171 /* find \n(\r)?\n sequence */ 1172 for (const char *n=ptr-1, *nn=NULL; NULL != (n = strchr(n+1, '\n')); nn=n) { 1173 if (n - nn == 2 ? n[-1] == '\r' : n - nn == 1) return n+1; 1174 } 1175 return NULL; 1176 } 1177 1178 1179 __attribute_cold__ 1180 static uint32_t 1181 http_response_discard_1xx (buffer * const restrict b, uint32_t len) 1182 { 1183 char * const ptr = b->ptr; 1184 const char * const n = http_response_end_of_header(ptr+12); 1185 if (NULL == n) return 0; /* * unfinished headers */ 1186 1187 /* discard 100 Continue headers */ 1188 len -= (uint32_t)(n - ptr); 1189 memmove(ptr, n, len); 1190 buffer_string_set_length(b, len); 1191 return len; 1192 } 1193 1194 1195 __attribute_cold__ 1196 __attribute_noinline__ 1197 static uint32_t 1198 http_response_check_1xx (buffer * const restrict b, uint32_t len) 1199 { 1200 const char * const s = b->ptr; 1201 while (len > 7 && 0 == memcmp(s, "HTTP/1.", 7)) { 1202 /* discard HTTP/1.1 1xx responses other than 101 Switching Protocols */ 1203 if (len > 12 1204 && s[8] == ' ' && s[9] == '1' && s[10] == '0' && s[11] != '1') { 1205 len = http_response_discard_1xx(b, len); 1206 continue; 1207 } 1208 break; 1209 } 1210 return len; 1211 } 1212 1213 1214 handler_t http_response_parse_headers(request_st * const r, http_response_opts * const opts, buffer * const b) { 1215 /** 1216 * possible formats of response headers: 1217 * 1218 * proxy or NPH (non-parsed headers): 1219 * 1220 * HTTP/1.0 200 Ok\n 1221 * Header: Value\n 1222 * \n 1223 * 1224 * CGI: 1225 * 1226 * Header: Value\n 1227 * Status: 200\n 1228 * \n 1229 * 1230 * and different mixes of \n and \r\n combinations 1231 * 1232 * Some users also forget about CGI and just send a response 1233 * and hope we handle it. No headers, no header-content separator 1234 */ 1235 1236 uint32_t header_len = buffer_string_length(b); 1237 if (header_len > 12 && b->ptr[9] == '1') { 1238 header_len = http_response_check_1xx(b, header_len); 1239 if (0 == header_len) 1240 return HANDLER_GO_ON; /* unfinished header */ 1241 } 1242 /*("HTTP/1.1 200 " is at least 13 chars + \r\n)*/ 1243 const int is_nph = (header_len > 12 && 0 == memcmp(b->ptr, "HTTP/1.", 7)); 1244 1245 int is_header_end = 0; 1246 uint32_t i = 0, blen; 1247 const char *bstart; 1248 1249 if (b->ptr[0] == '\n' || (b->ptr[0] == '\r' && b->ptr[1] == '\n')) { 1250 /* no HTTP headers */ 1251 i = (b->ptr[0] == '\n') ? 0 : 1; 1252 is_header_end = 1; 1253 } else if (is_nph || b->ptr[(i = strcspn(b->ptr, ":\n"))] == ':') { 1254 /* HTTP headers */ 1255 const char *n = http_response_end_of_header(b->ptr+i+1); 1256 if (n) { 1257 i = (uint32_t)(n - b->ptr - 1); 1258 is_header_end = 1; 1259 } 1260 } else if (i == header_len) { /* (no newline yet; partial header line?) */ 1261 } else if (opts->backend == BACKEND_CGI) { 1262 /* no HTTP headers, but a body (special-case for CGI compat) */ 1263 /* no colon found; does not appear to be HTTP headers */ 1264 if (0 != http_chunk_append_buffer(r, b)) { 1265 return HANDLER_ERROR; 1266 } 1267 r->http_status = 200; /* OK */ 1268 r->resp_body_started = 1; 1269 return HANDLER_GO_ON; 1270 } else { 1271 /* invalid response headers */ 1272 r->http_status = 502; /* Bad Gateway */ 1273 r->handler_module = NULL; 1274 return HANDLER_FINISHED; 1275 } 1276 1277 if (!is_header_end) { 1278 if (header_len > MAX_HTTP_RESPONSE_FIELD_SIZE) { 1279 log_error(r->conf.errh, __FILE__, __LINE__, 1280 "response headers too large for %s", r->uri.path.ptr); 1281 r->http_status = 502; /* Bad Gateway */ 1282 r->handler_module = NULL; 1283 return HANDLER_FINISHED; 1284 } 1285 return HANDLER_GO_ON; 1286 } 1287 1288 /* the body starts after the EOL */ 1289 bstart = b->ptr + (i + 1); 1290 blen = header_len - (i + 1); 1291 1292 /* strip the last \r?\n */ 1293 if (i > 0 && (b->ptr[i - 1] == '\r')) { 1294 i--; 1295 } 1296 1297 buffer_string_set_length(b, i); 1298 1299 if (opts->backend == BACKEND_PROXY && !is_nph) { 1300 /* invalid response Status-Line from HTTP proxy */ 1301 r->http_status = 502; /* Bad Gateway */ 1302 r->handler_module = NULL; 1303 return HANDLER_FINISHED; 1304 } 1305 1306 if (0 != http_response_process_headers(r, opts, b)) { 1307 return HANDLER_ERROR; 1308 } 1309 1310 r->resp_body_started = 1; 1311 1312 if (opts->authorizer 1313 && (r->http_status == 0 || r->http_status == 200)) { 1314 return HANDLER_GO_ON; 1315 } 1316 1317 if (NULL == r->handler_module) { 1318 return HANDLER_FINISHED; 1319 } 1320 1321 if (opts->local_redir && r->http_status >= 300 && r->http_status < 400){ 1322 /*(light_btst(r->resp_htags, HTTP_HEADER_LOCATION))*/ 1323 handler_t rc = http_response_process_local_redir(r, blen); 1324 if (NULL == r->handler_module) 1325 r->resp_body_started = 0; 1326 if (rc != HANDLER_GO_ON) return rc; 1327 } 1328 1329 if (opts->xsendfile_allow) { 1330 buffer *vb; 1331 /* X-Sendfile2 is deprecated; historical for fastcgi */ 1332 if (opts->backend == BACKEND_FASTCGI 1333 && NULL != (vb = http_header_response_get(r, HTTP_HEADER_OTHER, 1334 CONST_STR_LEN("X-Sendfile2")))) { 1335 http_response_xsendfile2(r, vb, opts->xsendfile_docroot); 1336 /* http_header_response_unset() shortcut for HTTP_HEADER_OTHER */ 1337 buffer_clear(vb); /*(do not send to client)*/ 1338 if (NULL == r->handler_module) 1339 r->resp_body_started = 0; 1340 return HANDLER_FINISHED; 1341 } else if (NULL != (vb = http_header_response_get(r, HTTP_HEADER_OTHER, 1342 CONST_STR_LEN("X-Sendfile"))) 1343 || (opts->backend == BACKEND_FASTCGI /* X-LIGHTTPD-send-file is deprecated; historical for fastcgi */ 1344 && NULL != (vb = http_header_response_get(r, HTTP_HEADER_OTHER, 1345 CONST_STR_LEN("X-LIGHTTPD-send-file"))))) { 1346 http_response_xsendfile(r, vb, opts->xsendfile_docroot); 1347 /* http_header_response_unset() shortcut for HTTP_HEADER_OTHER */ 1348 buffer_clear(vb); /*(do not send to client)*/ 1349 if (NULL == r->handler_module) 1350 r->resp_body_started = 0; 1351 return HANDLER_FINISHED; 1352 } 1353 } 1354 1355 if (blen > 0) { 1356 if (0 != http_chunk_decode_append_mem(r, bstart, blen)) 1357 return HANDLER_ERROR; 1358 } 1359 1360 /* (callback for response headers complete) */ 1361 return (opts->headers) ? opts->headers(r, opts) : HANDLER_GO_ON; 1362 } 1363 1364 1365 handler_t http_response_read(request_st * const r, http_response_opts * const opts, buffer * const b, fdnode * const fdn) { 1366 const int fd = fdn->fd; 1367 while (1) { 1368 ssize_t n; 1369 size_t avail = buffer_string_space(b); 1370 unsigned int toread = 0; 1371 1372 if (0 == fdevent_ioctl_fionread(fd, opts->fdfmt, (int *)&toread)) { 1373 if (avail < toread) { 1374 size_t blen = buffer_string_length(b); 1375 if (toread + blen < 4096) 1376 toread = 4095 - blen; 1377 else if (toread > MAX_READ_LIMIT) 1378 toread = MAX_READ_LIMIT; 1379 } 1380 else if (0 == toread) { 1381 #if 0 1382 return (fdevent_fdnode_interest(fdn) & FDEVENT_IN) 1383 ? HANDLER_FINISHED /* read finished */ 1384 : HANDLER_GO_ON; /* optimistic read; data not ready */ 1385 #else 1386 if (!(fdevent_fdnode_interest(fdn) & FDEVENT_IN)) { 1387 if (!(r->conf.stream_response_body 1388 & FDEVENT_STREAM_RESPONSE_POLLRDHUP)) 1389 return HANDLER_GO_ON;/*optimistic read; data not ready*/ 1390 } 1391 if (0 == avail) /* let read() below indicate if EOF or EAGAIN */ 1392 toread = 1024; 1393 #endif 1394 } 1395 } 1396 else if (avail < 1024) { 1397 toread = 4095 - avail; 1398 } 1399 1400 if (r->conf.stream_response_body & FDEVENT_STREAM_RESPONSE_BUFMIN) { 1401 off_t cqlen = chunkqueue_length(r->write_queue); 1402 if (cqlen + (off_t)toread > 65536 - 4096) { 1403 if (!r->con->is_writable) { 1404 /*(defer removal of FDEVENT_IN interest since 1405 * connection_state_machine() might be able to send data 1406 * immediately, unless !con->is_writable, where 1407 * connection_state_machine() might not loop back to call 1408 * mod_proxy_handle_subrequest())*/ 1409 fdevent_fdnode_event_clr(r->con->srv->ev, fdn, FDEVENT_IN); 1410 } 1411 if (cqlen >= 65536-1) return HANDLER_GO_ON; 1412 toread = 65536 - 1 - (unsigned int)cqlen; 1413 /* Note: heuristic is fuzzy in that it limits how much to read 1414 * from backend based on how much is pending to write to client. 1415 * Modules where data from backend is framed (e.g. FastCGI) may 1416 * want to limit how much is buffered from backend while waiting 1417 * for a complete data frame or data packet from backend. */ 1418 } 1419 } 1420 1421 if (avail < toread) { 1422 /*(add avail+toread to reduce allocations when ioctl EOPNOTSUPP)*/ 1423 avail = avail ? avail - 1 + toread : toread; 1424 buffer_string_prepare_append(b, avail); 1425 } 1426 1427 n = read(fd, b->ptr+buffer_string_length(b), avail); 1428 1429 if (n < 0) { 1430 switch (errno) { 1431 case EAGAIN: 1432 #ifdef EWOULDBLOCK 1433 #if EWOULDBLOCK != EAGAIN 1434 case EWOULDBLOCK: 1435 #endif 1436 #endif 1437 case EINTR: 1438 return HANDLER_GO_ON; 1439 default: 1440 log_perror(r->conf.errh, __FILE__, __LINE__, 1441 "read() %d %d", r->con->fd, fd); 1442 return HANDLER_ERROR; 1443 } 1444 } 1445 1446 buffer_commit(b, (size_t)n); 1447 #ifdef __COVERITY__ 1448 /* Coverity Scan overlooks the effect of buffer_commit() */ 1449 b->ptr[buffer_string_length(b)+n] = '\0'; 1450 #endif 1451 1452 if (NULL != opts->parse) { 1453 handler_t rc = opts->parse(r, opts, b, (size_t)n); 1454 if (rc != HANDLER_GO_ON) return rc; 1455 } else if (0 == n) { 1456 /* note: no further data is sent to backend after read EOF on socket 1457 * (not checking for half-closed TCP socket) 1458 * (backend should read all data desired prior to closing socket, 1459 * though might send app-level close data frame, if applicable) */ 1460 return HANDLER_FINISHED; /* read finished */ 1461 } else if (0 == r->resp_body_started) { 1462 /* split header from body */ 1463 handler_t rc = http_response_parse_headers(r, opts, b); 1464 if (rc != HANDLER_GO_ON) return rc; 1465 /* accumulate response in b until headers completed (or error) */ 1466 if (r->resp_body_started) buffer_clear(b); 1467 } else { 1468 if (0 != http_chunk_decode_append_buffer(r, b)) { 1469 /* error writing to tempfile; 1470 * truncate response or send 500 if nothing sent yet */ 1471 return HANDLER_ERROR; 1472 } 1473 buffer_clear(b); 1474 } 1475 1476 if (r->conf.stream_response_body & FDEVENT_STREAM_RESPONSE_BUFMIN) { 1477 if (chunkqueue_length(r->write_queue) > 65536 - 4096) { 1478 /*(defer removal of FDEVENT_IN interest since 1479 * connection_state_machine() might be able to send 1480 * data immediately, unless !con->is_writable, where 1481 * connection_state_machine() might not loop back to 1482 * call the subrequest handler)*/ 1483 if (!r->con->is_writable) 1484 fdevent_fdnode_event_clr(r->con->srv->ev, fdn, FDEVENT_IN); 1485 break; 1486 } 1487 } 1488 1489 if ((size_t)n < avail) 1490 break; /* emptied kernel read buffer or partial read */ 1491 } 1492 1493 return HANDLER_GO_ON; 1494 } 1495 1496 1497 int http_cgi_headers (request_st * const r, http_cgi_opts * const opts, http_cgi_header_append_cb cb, void *vdata) { 1498 1499 /* CGI-SPEC 6.1.2, FastCGI spec 6.3 and SCGI spec */ 1500 1501 int rc = 0; 1502 const connection * const con = r->con; 1503 server_socket * const srv_sock = con->srv_socket; 1504 buffer * const tb = r->tmp_buf; 1505 const char *s; 1506 size_t n; 1507 char buf[LI_ITOSTRING_LENGTH]; 1508 sock_addr *addr; 1509 sock_addr addrbuf; 1510 char b2[INET6_ADDRSTRLEN + 1]; 1511 1512 /* (CONTENT_LENGTH must be first for SCGI) */ 1513 if (!opts->authorizer) { 1514 rc |= cb(vdata, CONST_STR_LEN("CONTENT_LENGTH"), 1515 buf, li_itostrn(buf,sizeof(buf),r->reqbody_length)); 1516 } 1517 1518 if (!buffer_string_is_empty(&r->uri.query)) { 1519 rc |= cb(vdata, CONST_STR_LEN("QUERY_STRING"), 1520 CONST_BUF_LEN(&r->uri.query)); 1521 } else { 1522 rc |= cb(vdata, CONST_STR_LEN("QUERY_STRING"), 1523 CONST_STR_LEN("")); 1524 } 1525 if (!buffer_string_is_empty(opts->strip_request_uri)) { 1526 /** 1527 * /app1/index/list 1528 * 1529 * stripping /app1 or /app1/ should lead to 1530 * 1531 * /index/list 1532 * 1533 */ 1534 size_t len = buffer_string_length(opts->strip_request_uri); 1535 if ('/' == opts->strip_request_uri->ptr[len-1]) { 1536 --len; 1537 } 1538 1539 if (buffer_string_length(&r->target_orig) >= len 1540 && 0 == memcmp(r->target_orig.ptr, 1541 opts->strip_request_uri->ptr, len) 1542 && r->target_orig.ptr[len] == '/') { 1543 rc |= cb(vdata, CONST_STR_LEN("REQUEST_URI"), 1544 r->target_orig.ptr+len, 1545 buffer_string_length(&r->target_orig)-len); 1546 } else { 1547 rc |= cb(vdata, CONST_STR_LEN("REQUEST_URI"), 1548 CONST_BUF_LEN(&r->target_orig)); 1549 } 1550 } else { 1551 rc |= cb(vdata, CONST_STR_LEN("REQUEST_URI"), 1552 CONST_BUF_LEN(&r->target_orig)); 1553 } 1554 if (!buffer_is_equal(&r->target, &r->target_orig)) { 1555 rc |= cb(vdata, CONST_STR_LEN("REDIRECT_URI"), 1556 CONST_BUF_LEN(&r->target)); 1557 } 1558 /* set REDIRECT_STATUS for php compiled with --force-redirect 1559 * (if REDIRECT_STATUS has not already been set by error handler) */ 1560 if (0 == r->error_handler_saved_status) { 1561 rc |= cb(vdata, CONST_STR_LEN("REDIRECT_STATUS"), 1562 CONST_STR_LEN("200")); 1563 } 1564 1565 /* 1566 * SCRIPT_NAME, PATH_INFO and PATH_TRANSLATED according to 1567 * http://cgi-spec.golux.com/draft-coar-cgi-v11-03-clean.html 1568 * (6.1.14, 6.1.6, 6.1.7) 1569 */ 1570 if (!opts->authorizer) { 1571 rc |= cb(vdata, CONST_STR_LEN("SCRIPT_NAME"), 1572 CONST_BUF_LEN(&r->uri.path)); 1573 if (!buffer_string_is_empty(&r->pathinfo)) { 1574 rc |= cb(vdata, CONST_STR_LEN("PATH_INFO"), 1575 CONST_BUF_LEN(&r->pathinfo)); 1576 /* PATH_TRANSLATED is only defined if PATH_INFO is set */ 1577 if (!buffer_string_is_empty(opts->docroot)) { 1578 buffer_copy_buffer(tb, opts->docroot); 1579 } else { 1580 buffer_copy_buffer(tb, &r->physical.basedir); 1581 } 1582 buffer_append_string_buffer(tb, &r->pathinfo); 1583 rc |= cb(vdata, CONST_STR_LEN("PATH_TRANSLATED"), 1584 CONST_BUF_LEN(tb)); 1585 } 1586 } 1587 1588 /* 1589 * SCRIPT_FILENAME and DOCUMENT_ROOT for php 1590 * The PHP manual http://www.php.net/manual/en/reserved.variables.php 1591 * treatment of PATH_TRANSLATED is different from the one of CGI specs. 1592 * (see php.ini cgi.fix_pathinfo = 1 config parameter) 1593 */ 1594 1595 if (!buffer_string_is_empty(opts->docroot)) { 1596 /* alternate docroot, e.g. for remote FastCGI or SCGI server */ 1597 buffer_copy_buffer(tb, opts->docroot); 1598 buffer_append_string_buffer(tb, &r->uri.path); 1599 rc |= cb(vdata, CONST_STR_LEN("SCRIPT_FILENAME"), 1600 CONST_BUF_LEN(tb)); 1601 rc |= cb(vdata, CONST_STR_LEN("DOCUMENT_ROOT"), 1602 CONST_BUF_LEN(opts->docroot)); 1603 } else { 1604 if (opts->break_scriptfilename_for_php) { 1605 /* php.ini config cgi.fix_pathinfo = 1 need a broken SCRIPT_FILENAME 1606 * to find out what PATH_INFO is itself 1607 * 1608 * see src/sapi/cgi_main.c, init_request_info() 1609 */ 1610 buffer_copy_buffer(tb, &r->physical.path); 1611 buffer_append_string_buffer(tb, &r->pathinfo); 1612 rc |= cb(vdata, CONST_STR_LEN("SCRIPT_FILENAME"), 1613 CONST_BUF_LEN(tb)); 1614 } else { 1615 rc |= cb(vdata, CONST_STR_LEN("SCRIPT_FILENAME"), 1616 CONST_BUF_LEN(&r->physical.path)); 1617 } 1618 rc |= cb(vdata, CONST_STR_LEN("DOCUMENT_ROOT"), 1619 CONST_BUF_LEN(&r->physical.basedir)); 1620 } 1621 1622 s = get_http_method_name(r->http_method); 1623 force_assert(s); 1624 rc |= cb(vdata, CONST_STR_LEN("REQUEST_METHOD"), s, strlen(s)); 1625 1626 s = get_http_version_name(r->http_version); 1627 force_assert(s); 1628 rc |= cb(vdata, CONST_STR_LEN("SERVER_PROTOCOL"), s, strlen(s)); 1629 1630 rc |= cb(vdata, CONST_STR_LEN("SERVER_SOFTWARE"), 1631 CONST_BUF_LEN(r->conf.server_tag)); 1632 1633 rc |= cb(vdata, CONST_STR_LEN("GATEWAY_INTERFACE"), 1634 CONST_STR_LEN("CGI/1.1")); 1635 1636 rc |= cb(vdata, CONST_STR_LEN("REQUEST_SCHEME"), 1637 CONST_BUF_LEN(&r->uri.scheme)); 1638 1639 if (buffer_is_equal_string(&r->uri.scheme, CONST_STR_LEN("https"))) { 1640 rc |= cb(vdata, CONST_STR_LEN("HTTPS"), CONST_STR_LEN("on")); 1641 } 1642 1643 addr = &srv_sock->addr; 1644 rc |= cb(vdata, CONST_STR_LEN("SERVER_PORT"), 1645 buf, li_utostrn(buf,sizeof(buf),sock_addr_get_port(addr))); 1646 1647 switch (addr->plain.sa_family) { 1648 case AF_INET: 1649 case AF_INET6: 1650 if (sock_addr_is_addr_wildcard(addr)) { 1651 socklen_t addrlen = sizeof(addrbuf); 1652 if (0 == getsockname(con->fd,(struct sockaddr *)&addrbuf,&addrlen)){ 1653 addr = &addrbuf; 1654 } else { 1655 s = ""; 1656 break; 1657 } 1658 } 1659 s = sock_addr_inet_ntop(addr, b2, sizeof(b2)-1); 1660 if (NULL == s) s = ""; 1661 break; 1662 default: 1663 s = ""; 1664 break; 1665 } 1666 force_assert(s); 1667 rc |= cb(vdata, CONST_STR_LEN("SERVER_ADDR"), s, strlen(s)); 1668 1669 if (!buffer_string_is_empty(r->server_name)) { 1670 size_t len = buffer_string_length(r->server_name); 1671 1672 if (r->server_name->ptr[0] == '[') { 1673 const char *colon = strstr(r->server_name->ptr, "]:"); 1674 if (colon) len = (colon + 1) - r->server_name->ptr; 1675 } else { 1676 const char *colon = strchr(r->server_name->ptr, ':'); 1677 if (colon) len = colon - r->server_name->ptr; 1678 } 1679 1680 rc |= cb(vdata, CONST_STR_LEN("SERVER_NAME"), 1681 r->server_name->ptr, len); 1682 } else { 1683 /* set to be same as SERVER_ADDR (above) */ 1684 rc |= cb(vdata, CONST_STR_LEN("SERVER_NAME"), s, strlen(s)); 1685 } 1686 1687 rc |= cb(vdata, CONST_STR_LEN("REMOTE_ADDR"), 1688 CONST_BUF_LEN(con->dst_addr_buf)); 1689 1690 rc |= cb(vdata, CONST_STR_LEN("REMOTE_PORT"), buf, 1691 li_utostrn(buf,sizeof(buf),sock_addr_get_port(&con->dst_addr))); 1692 1693 for (n = 0; n < r->rqst_headers.used; n++) { 1694 data_string *ds = (data_string *)r->rqst_headers.data[n]; 1695 if (!buffer_string_is_empty(&ds->value) && !buffer_is_empty(&ds->key)) { 1696 /* Security: Do not emit HTTP_PROXY in environment. 1697 * Some executables use HTTP_PROXY to configure 1698 * outgoing proxy. See also https://httpoxy.org/ */ 1699 if (buffer_is_equal_caseless_string(&ds->key, 1700 CONST_STR_LEN("Proxy"))) { 1701 continue; 1702 } 1703 buffer_copy_string_encoded_cgi_varnames(tb, 1704 CONST_BUF_LEN(&ds->key), 1); 1705 rc |= cb(vdata, CONST_BUF_LEN(tb), 1706 CONST_BUF_LEN(&ds->value)); 1707 } 1708 } 1709 1710 con->srv->request_env(r); 1711 1712 for (n = 0; n < r->env.used; n++) { 1713 data_string *ds = (data_string *)r->env.data[n]; 1714 if (!buffer_is_empty(&ds->value) && !buffer_is_empty(&ds->key)) { 1715 buffer_copy_string_encoded_cgi_varnames(tb, 1716 CONST_BUF_LEN(&ds->key), 0); 1717 rc |= cb(vdata, CONST_BUF_LEN(tb), 1718 CONST_BUF_LEN(&ds->value)); 1719 } 1720 } 1721 1722 return rc; 1723 } 1724