1 #include "first.h" 2 3 #include "response.h" 4 #include "request.h" 5 #include "base.h" 6 #include "fdevent.h" 7 #include "http_header.h" 8 #include "http_kv.h" 9 #include "log.h" 10 #include "stat_cache.h" 11 #include "chunk.h" 12 #include "http_chunk.h" 13 14 #include "plugin.h" 15 16 #include <sys/types.h> 17 #include <sys/stat.h> 18 19 #include <limits.h> 20 #include <errno.h> 21 #include <stdlib.h> 22 #include <string.h> 23 #include <time.h> 24 25 26 int 27 http_response_omit_header (request_st * const r, const data_string * const ds) 28 { 29 const size_t klen = buffer_string_length(&ds->key); 30 if (klen == sizeof("X-Sendfile")-1 31 && buffer_eq_icase_ssn(ds->key.ptr, CONST_STR_LEN("X-Sendfile"))) 32 return 1; 33 if (klen >= sizeof("X-LIGHTTPD-")-1 34 && buffer_eq_icase_ssn(ds->key.ptr, CONST_STR_LEN("X-LIGHTTPD-"))) { 35 if (klen == sizeof("X-LIGHTTPD-KBytes-per-second")-1 36 && buffer_eq_icase_ssn(ds->key.ptr+sizeof("X-LIGHTTPD-")-1, 37 CONST_STR_LEN("KBytes-per-second"))) { 38 /* "X-LIGHTTPD-KBytes-per-second" */ 39 off_t limit = strtol(ds->value.ptr, NULL, 10) << 10; /*(*=1024)*/ 40 if (limit > 0 41 && (limit < r->conf.bytes_per_second 42 || 0 == r->conf.bytes_per_second)) { 43 r->conf.bytes_per_second = limit; 44 } 45 } 46 return 1; 47 } 48 return 0; 49 } 50 51 52 void 53 http_response_write_header (request_st * const r) 54 { 55 chunkqueue * const cq = r->write_queue; 56 buffer * const b = chunkqueue_prepend_buffer_open(cq); 57 58 const char * const httpv = (r->http_version == HTTP_VERSION_1_1) ? "HTTP/1.1 " : "HTTP/1.0 "; 59 buffer_copy_string_len(b, httpv, sizeof("HTTP/1.1 ")-1); 60 http_status_append(b, r->http_status); 61 62 /* disable keep-alive if requested */ 63 64 if (r->con->request_count > r->conf.max_keep_alive_requests || 0 == r->conf.max_keep_alive_idle) { 65 r->keep_alive = 0; 66 } else if (0 != r->reqbody_length 67 && r->reqbody_length != r->reqbody_queue->bytes_in 68 && (NULL == r->handler_module 69 || 0 == (r->conf.stream_request_body 70 & (FDEVENT_STREAM_REQUEST 71 | FDEVENT_STREAM_REQUEST_BUFMIN)))) { 72 r->keep_alive = 0; 73 } else { 74 r->con->keep_alive_idle = r->conf.max_keep_alive_idle; 75 } 76 77 if ((r->resp_htags & HTTP_HEADER_UPGRADE) && r->http_version == HTTP_VERSION_1_1) { 78 http_header_response_set(r, HTTP_HEADER_CONNECTION, CONST_STR_LEN("Connection"), CONST_STR_LEN("upgrade")); 79 } else if (0 == r->keep_alive) { 80 http_header_response_set(r, HTTP_HEADER_CONNECTION, CONST_STR_LEN("Connection"), CONST_STR_LEN("close")); 81 } else if (r->http_version == HTTP_VERSION_1_0) {/*(&& r->keep_alive != 0)*/ 82 http_header_response_set(r, HTTP_HEADER_CONNECTION, CONST_STR_LEN("Connection"), CONST_STR_LEN("keep-alive")); 83 } 84 85 if (304 == r->http_status && (r->resp_htags & HTTP_HEADER_CONTENT_ENCODING)) { 86 http_header_response_unset(r, HTTP_HEADER_CONTENT_ENCODING, CONST_STR_LEN("Content-Encoding")); 87 } 88 89 /* add all headers */ 90 for (size_t i = 0; i < r->resp_headers.used; ++i) { 91 const data_string * const ds = (data_string *)r->resp_headers.data[i]; 92 93 if (buffer_string_is_empty(&ds->value)) continue; 94 if (buffer_string_is_empty(&ds->key)) continue; 95 if ((ds->key.ptr[0] & 0xdf) == 'X' && http_response_omit_header(r, ds)) 96 continue; 97 98 buffer_append_string_len(b, CONST_STR_LEN("\r\n")); 99 buffer_append_string_buffer(b, &ds->key); 100 buffer_append_string_len(b, CONST_STR_LEN(": ")); 101 buffer_append_string_buffer(b, &ds->value); 102 } 103 104 if (!(r->resp_htags & HTTP_HEADER_DATE)) { 105 static time_t tlast; 106 static char tstr[32]; /* 30-chars for "%a, %d %b %Y %H:%M:%S GMT" */ 107 static size_t tlen; 108 109 /* cache the generated timestamp */ 110 const time_t cur_ts = log_epoch_secs; 111 if (tlast != cur_ts) { 112 tlast = cur_ts; 113 tlen = strftime(tstr, sizeof(tstr), 114 "%a, %d %b %Y %H:%M:%S GMT", gmtime(&tlast)); 115 } 116 117 /* HTTP/1.1 and later requires a Date: header */ 118 buffer_append_string_len(b, CONST_STR_LEN("\r\nDate: ")); 119 buffer_append_string_len(b, tstr, tlen); 120 } 121 122 if (!(r->resp_htags & HTTP_HEADER_SERVER)) { 123 if (!buffer_string_is_empty(r->conf.server_tag)) { 124 buffer_append_string_len(b, CONST_STR_LEN("\r\nServer: ")); 125 buffer_append_string_len(b, CONST_BUF_LEN(r->conf.server_tag)); 126 } 127 } 128 129 buffer_append_string_len(b, CONST_STR_LEN("\r\n\r\n")); 130 131 r->resp_header_len = buffer_string_length(b); 132 133 if (r->conf.log_response_header) { 134 log_error(r->conf.errh,__FILE__,__LINE__,"Response-Header:\n%s",b->ptr); 135 } 136 137 chunkqueue_prepend_buffer_commit(cq); 138 139 /*(optimization to use fewer syscalls to send a small response)*/ 140 off_t cqlen; 141 if (r->resp_body_finished && (r->resp_htags & HTTP_HEADER_CONTENT_LENGTH) 142 && (cqlen = chunkqueue_length(cq) - r->resp_header_len) > 0 143 && cqlen <= 32768) 144 chunkqueue_small_resp_optim(cq); 145 } 146 147 148 static handler_t http_response_physical_path_check(request_st * const r) { 149 stat_cache_entry *sce = stat_cache_get_entry(&r->physical.path); 150 151 if (sce) { 152 /* file exists */ 153 } else { 154 char *pathinfo = NULL; 155 switch (errno) { 156 case EACCES: 157 r->http_status = 403; 158 159 if (r->conf.log_request_handling) { 160 log_error(r->conf.errh, __FILE__, __LINE__, 161 "-- access denied"); 162 log_error(r->conf.errh, __FILE__, __LINE__, 163 "Path : %s", r->physical.path.ptr); 164 } 165 166 buffer_reset(&r->physical.path); 167 return HANDLER_FINISHED; 168 case ENAMETOOLONG: 169 /* file name to be read was too long. return 404 */ 170 case ENOENT: 171 if (r->http_method == HTTP_METHOD_OPTIONS 172 && NULL != http_header_response_get(r, HTTP_HEADER_OTHER, CONST_STR_LEN("Allow"))) { 173 r->http_status = 200; 174 return HANDLER_FINISHED; 175 } 176 177 r->http_status = 404; 178 179 if (r->conf.log_request_handling) { 180 log_error(r->conf.errh, __FILE__, __LINE__, 181 "-- file not found"); 182 log_error(r->conf.errh, __FILE__, __LINE__, 183 "Path : %s", r->physical.path.ptr); 184 } 185 186 buffer_reset(&r->physical.path); 187 return HANDLER_FINISHED; 188 case ENOTDIR: 189 /* PATH_INFO ! :) */ 190 break; 191 default: 192 /* we have no idea what happened. let's tell the user so. */ 193 log_error(r->conf.errh, __FILE__, __LINE__, 194 "file not found ... or so: %s -> %s", 195 r->uri.path.ptr, r->physical.path.ptr); 196 197 r->http_status = 500; 198 buffer_reset(&r->physical.path); 199 200 return HANDLER_FINISHED; 201 } 202 203 /* not found, perhaps PATHINFO */ 204 205 { 206 /*(might check at startup that s->document_root does not end in '/')*/ 207 size_t len = buffer_string_length(&r->physical.basedir); 208 if (len > 0 && '/' == r->physical.basedir.ptr[len-1]) --len; 209 pathinfo = r->physical.path.ptr + len; 210 if ('/' != *pathinfo) { 211 pathinfo = NULL; 212 } 213 else if (pathinfo == r->physical.path.ptr) { /*(basedir is "/")*/ 214 pathinfo = strchr(pathinfo+1, '/'); 215 } 216 } 217 218 buffer * const tb = r->tmp_buf; 219 for (char *pprev = pathinfo; pathinfo; pprev = pathinfo, pathinfo = strchr(pathinfo+1, '/')) { 220 buffer_copy_string_len(tb, r->physical.path.ptr, pathinfo - r->physical.path.ptr); 221 stat_cache_entry *nsce = stat_cache_get_entry(tb); 222 if (NULL == nsce) { 223 pathinfo = pathinfo != pprev ? pprev : NULL; 224 break; 225 } 226 sce = nsce; 227 if (!S_ISDIR(sce->st.st_mode)) break; 228 } 229 230 if (NULL == pathinfo || !S_ISREG(sce->st.st_mode)) { 231 /* no it really doesn't exists */ 232 r->http_status = 404; 233 234 if (r->conf.log_file_not_found) { 235 log_error(r->conf.errh, __FILE__, __LINE__, 236 "file not found: %s -> %s", 237 r->uri.path.ptr, r->physical.path.ptr); 238 } 239 240 buffer_reset(&r->physical.path); 241 242 return HANDLER_FINISHED; 243 } 244 245 /* we have a PATHINFO */ 246 if (pathinfo) { 247 size_t len = strlen(pathinfo), reqlen; 248 if (r->conf.force_lowercase_filenames 249 && len <= (reqlen = buffer_string_length(&r->target)) 250 && buffer_eq_icase_ssn(r->target.ptr + reqlen - len, pathinfo, len)) { 251 /* attempt to preserve case-insensitive PATH_INFO 252 * (works in common case where mod_alias, mod_magnet, and other modules 253 * have not modified the PATH_INFO portion of request URI, or did so 254 * with exactly the PATH_INFO desired) */ 255 buffer_copy_string_len(&r->pathinfo, r->target.ptr + reqlen - len, len); 256 } else { 257 buffer_copy_string_len(&r->pathinfo, pathinfo, len); 258 } 259 260 /* 261 * shorten uri.path 262 */ 263 264 buffer_string_set_length(&r->uri.path, buffer_string_length(&r->uri.path) - len); 265 buffer_string_set_length(&r->physical.path, (size_t)(pathinfo - r->physical.path.ptr)); 266 } 267 } 268 269 if (!r->conf.follow_symlink 270 && 0 != stat_cache_path_contains_symlink(&r->physical.path, r->conf.errh)) { 271 r->http_status = 403; 272 273 if (r->conf.log_request_handling) { 274 log_error(r->conf.errh, __FILE__, __LINE__, 275 "-- access denied due symlink restriction"); 276 log_error(r->conf.errh, __FILE__, __LINE__, 277 "Path : %s", r->physical.path.ptr); 278 } 279 280 buffer_reset(&r->physical.path); 281 return HANDLER_FINISHED; 282 } 283 284 if (S_ISDIR(sce->st.st_mode)) { 285 if (r->uri.path.ptr[buffer_string_length(&r->uri.path) - 1] != '/') { 286 /* redirect to .../ */ 287 288 http_response_redirect_to_directory(r, 301); 289 290 return HANDLER_FINISHED; 291 } 292 } else if (!S_ISREG(sce->st.st_mode)) { 293 /* any special handling of non-reg files ?*/ 294 } 295 296 return HANDLER_GO_ON; 297 } 298 299 __attribute_cold__ 300 __attribute_noinline__ 301 static handler_t http_status_set_error_close (request_st * const r, int status) { 302 r->keep_alive = 0; 303 r->resp_body_finished = 1; 304 r->handler_module = NULL; 305 r->http_status = status; 306 return HANDLER_FINISHED; 307 } 308 309 static handler_t http_response_config (request_st * const r) { 310 if (r->conf.log_condition_handling) 311 log_error(r->conf.errh, __FILE__, __LINE__, "run condition"); 312 313 config_cond_cache_reset(r); 314 config_patch_config(r); 315 316 /* do we have to downgrade from 1.1 to 1.0 ? (ignore for HTTP/2) */ 317 if (!r->conf.allow_http11 && r->http_version == HTTP_VERSION_1_1) 318 r->http_version = HTTP_VERSION_1_0; 319 320 /* r->conf.max_request_size is in kBytes */ 321 if (0 != r->conf.max_request_size && 322 (off_t)r->reqbody_length > ((off_t)r->conf.max_request_size << 10)) { 323 log_error(r->conf.errh, __FILE__, __LINE__, 324 "request-size too long: %lld -> 413", (long long) r->reqbody_length); 325 return /* 413 Payload Too Large */ 326 http_status_set_error_close(r, 413); 327 } 328 329 return HANDLER_GO_ON; 330 } 331 332 333 __attribute_cold__ 334 static handler_t http_response_comeback (request_st * const r); 335 336 337 static handler_t 338 http_response_prepare (request_st * const r) 339 { 340 handler_t rc; 341 342 do { 343 344 /* looks like someone has already made a decision */ 345 if (r->http_status != 0 && r->http_status != 200) { 346 if (0 == r->resp_body_finished) 347 http_response_body_clear(r, 0); 348 return HANDLER_FINISHED; 349 } 350 351 /* no decision yet, build conf->filename */ 352 if (buffer_is_empty(&r->physical.path)) { 353 354 if (!r->async_callback) { 355 rc = http_response_config(r); 356 if (HANDLER_GO_ON != rc) continue; 357 } 358 r->async_callback = 0; /* reset */ 359 360 /* we only come here when we have the parse the full request again 361 * 362 * a HANDLER_COMEBACK from mod_rewrite and mod_fastcgi might be a 363 * problem here as mod_setenv might get called multiple times 364 * 365 * fastcgi-auth might lead to a COMEBACK too 366 * fastcgi again dead server too 367 */ 368 369 if (r->conf.log_request_handling) { 370 log_error(r->conf.errh, __FILE__, __LINE__, 371 "-- parsed Request-URI"); 372 log_error(r->conf.errh, __FILE__, __LINE__, 373 "Request-URI : %s", r->target.ptr); 374 log_error(r->conf.errh, __FILE__, __LINE__, 375 "URI-scheme : %s", r->uri.scheme.ptr); 376 log_error(r->conf.errh, __FILE__, __LINE__, 377 "URI-authority : %s", r->uri.authority.ptr); 378 log_error(r->conf.errh, __FILE__, __LINE__, 379 "URI-path (clean): %s", r->uri.path.ptr); 380 log_error(r->conf.errh, __FILE__, __LINE__, 381 "URI-query : %.*s", 382 BUFFER_INTLEN_PTR(&r->uri.query)); 383 } 384 385 386 /** 387 * 388 * call plugins 389 * 390 * - based on the raw URL 391 * 392 */ 393 394 rc = plugins_call_handle_uri_raw(r); 395 if (HANDLER_GO_ON != rc) continue; 396 397 /** 398 * 399 * call plugins 400 * 401 * - based on the clean URL 402 * 403 */ 404 405 rc = plugins_call_handle_uri_clean(r); 406 if (HANDLER_GO_ON != rc) continue; 407 408 if (r->http_method == HTTP_METHOD_OPTIONS && 409 r->uri.path.ptr[0] == '*' && r->uri.path.ptr[1] == '\0') { 410 /* option requests are handled directly without checking of the path */ 411 412 http_header_response_append(r, HTTP_HEADER_OTHER, CONST_STR_LEN("Allow"), CONST_STR_LEN("OPTIONS, GET, HEAD, POST")); 413 414 r->http_status = 200; 415 r->resp_body_finished = 1; 416 417 return HANDLER_FINISHED; 418 } 419 420 if (r->http_method == HTTP_METHOD_CONNECT && NULL == r->handler_module) { 421 return /* 405 Method Not Allowed */ 422 http_status_set_error_close(r, 405); 423 } 424 425 /*** 426 * 427 * border 428 * 429 * logical filename (URI) becomes a physical filename here 430 * 431 * 432 * 433 */ 434 435 436 437 438 /* 1. stat() 439 * ... ISREG() -> ok, go on 440 * ... ISDIR() -> index-file -> redirect 441 * 442 * 2. pathinfo() 443 * ... ISREG() 444 * 445 * 3. -> 404 446 * 447 */ 448 449 /* 450 * SEARCH DOCUMENT ROOT 451 */ 452 453 /* set a default */ 454 455 buffer_copy_buffer(&r->physical.doc_root, r->conf.document_root); 456 buffer_copy_buffer(&r->physical.rel_path, &r->uri.path); 457 458 #if defined(__WIN32) || defined(__CYGWIN__) 459 /* strip dots from the end and spaces 460 * 461 * windows/dos handle those filenames as the same file 462 * 463 * foo == foo. == foo..... == "foo... " == "foo.. ./" 464 * 465 * This will affect in some cases PATHINFO 466 * 467 * on native windows we could prepend the filename with \\?\ to circumvent 468 * this behaviour. I have no idea how to push this through cygwin 469 * 470 * */ 471 472 if (!buffer_string_is_empty(&r->physical.rel_path)) { 473 buffer *b = &r->physical.rel_path; 474 size_t len = buffer_string_length(b); 475 476 /* strip trailing " /" or "./" once */ 477 if (len > 1 && 478 b->ptr[len - 1] == '/' && 479 (b->ptr[len - 2] == ' ' || b->ptr[len - 2] == '.')) { 480 len -= 2; 481 } 482 /* strip all trailing " " and "." */ 483 while (len > 0 && ( ' ' == b->ptr[len-1] || '.' == b->ptr[len-1] ) ) --len; 484 buffer_string_set_length(b, len); 485 } 486 #endif 487 488 if (r->conf.log_request_handling) { 489 log_error(r->conf.errh, __FILE__, __LINE__, 490 "-- before doc_root"); 491 log_error(r->conf.errh, __FILE__, __LINE__, 492 "Doc-Root : %s", r->physical.doc_root.ptr); 493 log_error(r->conf.errh, __FILE__, __LINE__, 494 "Rel-Path : %s", r->physical.rel_path.ptr); 495 log_error(r->conf.errh, __FILE__, __LINE__, 496 "Path : %s", r->physical.path.ptr); 497 } 498 /* the docroot plugin should set the doc_root and might also set the physical.path 499 * for us (all vhost-plugins are supposed to set the doc_root) 500 * */ 501 rc = plugins_call_handle_docroot(r); 502 if (HANDLER_GO_ON != rc) continue; 503 504 /* MacOS X and Windows can't distinguish between upper and lower-case 505 * 506 * convert to lower-case 507 */ 508 if (r->conf.force_lowercase_filenames) { 509 buffer_to_lower(&r->physical.rel_path); 510 } 511 512 /* the docroot plugins might set the servername, if they don't we take http-host */ 513 if (buffer_string_is_empty(r->server_name)) { 514 r->server_name = &r->uri.authority; 515 } 516 517 /** 518 * create physical filename 519 * -> physical.path = docroot + rel_path 520 * 521 */ 522 523 buffer_copy_buffer(&r->physical.basedir, &r->physical.doc_root); 524 buffer_copy_buffer(&r->physical.path, &r->physical.doc_root); 525 buffer_append_path_len(&r->physical.path, CONST_BUF_LEN(&r->physical.rel_path)); 526 527 if (r->conf.log_request_handling) { 528 log_error(r->conf.errh, __FILE__, __LINE__, 529 "-- after doc_root"); 530 log_error(r->conf.errh, __FILE__, __LINE__, 531 "Doc-Root : %s", r->physical.doc_root.ptr); 532 log_error(r->conf.errh, __FILE__, __LINE__, 533 "Rel-Path : %s", r->physical.rel_path.ptr); 534 log_error(r->conf.errh, __FILE__, __LINE__, 535 "Path : %s", r->physical.path.ptr); 536 } 537 538 if (r->http_method == HTTP_METHOD_CONNECT) { 539 /* do not permit CONNECT requests to hit filesystem hooks 540 * since the CONNECT URI bypassed path normalization */ 541 /* (This check is located here so that r->physical.path 542 * is filled in above to avoid repeating work next time 543 * http_response_prepare() is called while processing request) */ 544 } else { 545 rc = plugins_call_handle_physical(r); 546 if (HANDLER_GO_ON != rc) continue; 547 548 if (r->conf.log_request_handling) { 549 log_error(r->conf.errh, __FILE__, __LINE__, 550 "-- logical -> physical"); 551 log_error(r->conf.errh, __FILE__, __LINE__, 552 "Doc-Root : %s", r->physical.doc_root.ptr); 553 log_error(r->conf.errh, __FILE__, __LINE__, 554 "Basedir : %s", r->physical.basedir.ptr); 555 log_error(r->conf.errh, __FILE__, __LINE__, 556 "Rel-Path : %s", r->physical.rel_path.ptr); 557 log_error(r->conf.errh, __FILE__, __LINE__, 558 "Path : %s", r->physical.path.ptr); 559 } 560 } 561 } 562 563 if (NULL != r->handler_module) return HANDLER_GO_ON; 564 565 /* 566 * No module grabbed the request yet (like mod_access) 567 * 568 * Go on and check of the file exists at all 569 */ 570 571 if (r->conf.log_request_handling) { 572 log_error(r->conf.errh, __FILE__, __LINE__, 573 "-- handling physical path"); 574 log_error(r->conf.errh, __FILE__, __LINE__, 575 "Path : %s", r->physical.path.ptr); 576 } 577 578 rc = http_response_physical_path_check(r); 579 if (HANDLER_GO_ON != rc) continue; 580 581 if (r->conf.log_request_handling) { 582 log_error(r->conf.errh, __FILE__, __LINE__, 583 "-- handling subrequest"); 584 log_error(r->conf.errh, __FILE__, __LINE__, 585 "Path : %s", r->physical.path.ptr); 586 log_error(r->conf.errh, __FILE__, __LINE__, 587 "URI : %s", r->uri.path.ptr); 588 log_error(r->conf.errh, __FILE__, __LINE__, 589 "Pathinfo : %s", r->pathinfo.ptr); 590 } 591 592 /* call the handlers */ 593 rc = plugins_call_handle_subrequest_start(r); 594 if (HANDLER_GO_ON != rc) { 595 if (r->conf.log_request_handling) { 596 log_error(r->conf.errh, __FILE__, __LINE__, 597 "-- subrequest finished"); 598 } 599 continue; 600 } 601 602 /* if we are still here, no one wanted the file, status 403 is ok I think */ 603 if (NULL == r->handler_module && 0 == r->http_status) { 604 r->http_status = (r->http_method != HTTP_METHOD_OPTIONS) ? 403 : 200; 605 return HANDLER_FINISHED; 606 } 607 608 return HANDLER_GO_ON; 609 610 } while (HANDLER_COMEBACK == rc 611 && HANDLER_GO_ON ==(rc = http_response_comeback(r))); 612 613 return rc; 614 } 615 616 617 __attribute_cold__ 618 static handler_t http_response_comeback (request_st * const r) 619 { 620 if (NULL != r->handler_module || !buffer_is_empty(&r->physical.path)) 621 return HANDLER_GO_ON; 622 623 config_reset_config(r); 624 625 buffer_copy_buffer(&r->uri.authority,r->http_host);/*copy even if NULL*/ 626 buffer_to_lower(&r->uri.authority); 627 628 int status = http_request_parse_target(r, r->con->proto_default_port); 629 if (0 == status) { 630 r->conditional_is_valid = (1 << COMP_SERVER_SOCKET) 631 | (1 << COMP_HTTP_SCHEME) 632 | (1 << COMP_HTTP_HOST) 633 | (1 << COMP_HTTP_REMOTE_IP) 634 | (1 << COMP_HTTP_REQUEST_METHOD) 635 | (1 << COMP_HTTP_URL) 636 | (1 << COMP_HTTP_QUERY_STRING) 637 | (1 << COMP_HTTP_REQUEST_HEADER); 638 return HANDLER_GO_ON; 639 } 640 else { 641 r->conditional_is_valid = (1 << COMP_SERVER_SOCKET) 642 | (1 << COMP_HTTP_REMOTE_IP); 643 config_cond_cache_reset(r); 644 return http_status_set_error_close(r, status); 645 } 646 } 647 648 649 __attribute_cold__ 650 static void 651 http_response_errdoc_init (request_st * const r) 652 { 653 /* modules that produce headers required with error response should 654 * typically also produce an error document. Make an exception for 655 * mod_auth WWW-Authenticate response header. */ 656 buffer *www_auth = NULL; 657 if (401 == r->http_status) { 658 const buffer * const vb = 659 http_header_response_get(r, HTTP_HEADER_OTHER, 660 CONST_STR_LEN("WWW-Authenticate")); 661 if (NULL != vb) www_auth = buffer_init_buffer(vb); 662 } 663 664 buffer_reset(&r->physical.path); 665 r->resp_htags = 0; 666 array_reset_data_strings(&r->resp_headers); 667 http_response_body_clear(r, 0); 668 669 if (NULL != www_auth) { 670 http_header_response_set(r, HTTP_HEADER_OTHER, 671 CONST_STR_LEN("WWW-Authenticate"), 672 CONST_BUF_LEN(www_auth)); 673 buffer_free(www_auth); 674 } 675 } 676 677 678 __attribute_cold__ 679 static void 680 http_response_static_errdoc (request_st * const r) 681 { 682 if (NULL == r->handler_module 683 ? r->error_handler_saved_status >= 65535 684 : (!r->conf.error_intercept || r->error_handler_saved_status)) 685 return; 686 687 http_response_errdoc_init(r); 688 r->resp_body_finished = 1; 689 690 /* try to send static errorfile */ 691 if (!buffer_string_is_empty(r->conf.errorfile_prefix)) { 692 buffer_copy_buffer(&r->physical.path, r->conf.errorfile_prefix); 693 buffer_append_int(&r->physical.path, r->http_status); 694 buffer_append_string_len(&r->physical.path, CONST_STR_LEN(".html")); 695 if (0 == http_chunk_append_file(r, &r->physical.path)) { 696 stat_cache_entry *sce = stat_cache_get_entry(&r->physical.path); 697 const buffer *content_type = (NULL != sce) 698 ? stat_cache_content_type_get(sce, r) 699 : NULL; 700 if (content_type) 701 http_header_response_set(r, HTTP_HEADER_CONTENT_TYPE, 702 CONST_STR_LEN("Content-Type"), 703 CONST_BUF_LEN(content_type)); 704 return; 705 } 706 } 707 708 /* build default error-page */ 709 buffer_reset(&r->physical.path); 710 buffer * const b = r->tmp_buf; 711 buffer_copy_string_len(b, CONST_STR_LEN( 712 "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n" 713 "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n" 714 " \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n" 715 "<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n" 716 " <head>\n" 717 " <title>")); 718 http_status_append(b, r->http_status); 719 buffer_append_string_len(b, CONST_STR_LEN( 720 "</title>\n" 721 " </head>\n" 722 " <body>\n" 723 " <h1>")); 724 http_status_append(b, r->http_status); 725 buffer_append_string_len(b, CONST_STR_LEN( 726 "</h1>\n" 727 " </body>\n" 728 "</html>\n")); 729 (void)http_chunk_append_mem(r, CONST_BUF_LEN(b)); 730 731 http_header_response_set(r, HTTP_HEADER_CONTENT_TYPE, 732 CONST_STR_LEN("Content-Type"), 733 CONST_STR_LEN("text/html")); 734 } 735 736 737 __attribute_cold__ 738 static void 739 http_response_merge_trailers (request_st * const r) 740 { 741 /* attempt to merge trailers into headers; header not yet sent by caller */ 742 if (buffer_string_is_empty(&r->gw_dechunk->b)) return; 743 const int done = r->gw_dechunk->done; 744 if (!done) return; /* XXX: !done; could scan for '\n' and send only those */ 745 746 /* do not include trailers if success status (when response was read from 747 * backend) subsequently changed to error status. http_chunk could add the 748 * trailers, but such actions are better on a different code layer than in 749 * http_chunk.c */ 750 if (done < 400 && r->http_status >= 400) return; 751 752 /* XXX: trailers passed through; no sanity check currently done 753 * https://tools.ietf.org/html/rfc7230#section-4.1.2 754 * 755 * Not checking for disallowed fields 756 * Not handling (deprecated) line wrapping 757 * Not strictly checking fields 758 */ 759 const char *k = strchr(r->gw_dechunk->b.ptr, '\n'); /*(skip final chunk)*/ 760 if (NULL == k) return; /*(should not happen)*/ 761 ++k; 762 for (const char *v, *e; (e = strchr(k, '\n')); k = e+1) { 763 v = memchr(k, ':', (size_t)(e - k)); 764 if (NULL == v || v == k || *k == ' ' || *k == '\t') continue; 765 uint32_t klen = (uint32_t)(v - k); 766 do { ++v; } while (*v == ' ' || *v == '\t'); 767 if (*v == '\r' || *v == '\n') continue; 768 enum http_header_e id = http_header_hkey_get(k, klen); 769 http_header_response_insert(r, id, k, klen, v, (size_t)(e - v)); 770 } 771 http_header_response_unset(r, HTTP_HEADER_OTHER, CONST_STR_LEN("Trailer")); 772 buffer_clear(&r->gw_dechunk->b); 773 } 774 775 776 static handler_t 777 http_response_write_prepare(request_st * const r) 778 { 779 if (NULL == r->handler_module) { 780 /* static files */ 781 switch(r->http_method) { 782 case HTTP_METHOD_GET: 783 case HTTP_METHOD_POST: 784 case HTTP_METHOD_HEAD: 785 break; 786 case HTTP_METHOD_OPTIONS: 787 if ((!r->http_status || r->http_status == 200) 788 && !buffer_string_is_empty(&r->uri.path) 789 && r->uri.path.ptr[0] != '*') { 790 http_response_body_clear(r, 0); 791 http_header_response_append(r, HTTP_HEADER_OTHER, 792 CONST_STR_LEN("Allow"), 793 CONST_STR_LEN("OPTIONS, GET, HEAD, POST")); 794 r->http_status = 200; 795 r->resp_body_finished = 1; 796 } 797 break; 798 default: 799 if (r->http_status == 0) 800 r->http_status = 501; 801 break; 802 } 803 } 804 805 if (r->http_status == 0) 806 r->http_status = 403; 807 808 switch (r->http_status) { 809 case 204: /* class: header only */ 810 case 205: 811 case 304: 812 /* disable chunked encoding again as we have no body */ 813 http_response_body_clear(r, 1); 814 r->resp_body_finished = 1; 815 break; 816 default: /* class: header + body */ 817 /* only custom body for 4xx and 5xx */ 818 if (r->http_status >= 400 && r->http_status < 600) 819 http_response_static_errdoc(r); 820 break; 821 } 822 823 if (r->gw_dechunk) 824 http_response_merge_trailers(r); 825 826 /* Allow filter plugins to change response headers */ 827 switch (plugins_call_handle_response_start(r)) { 828 case HANDLER_GO_ON: 829 case HANDLER_FINISHED: 830 break; 831 default: 832 log_error(r->conf.errh, __FILE__, __LINE__, 833 "response_start plugin failed"); 834 return HANDLER_ERROR; 835 } 836 837 if (r->resp_body_finished) { 838 /* set content-length if length is known and not already set */ 839 if (!(r->resp_htags 840 & (HTTP_HEADER_CONTENT_LENGTH | HTTP_HEADER_TRANSFER_ENCODING))) { 841 off_t qlen = chunkqueue_length(r->write_queue); 842 843 /** 844 * The Content-Length header can only be sent if we have content: 845 * - HEAD does not have a content-body (but can have content-length) 846 * - 1xx, 204 and 304 does not have a content-body 847 * (RFC 2616 Section 4.3) 848 * 849 * Otherwise generate a Content-Length header 850 * (if chunked encoding is not available) 851 */ 852 if ( r->http_status < 200 853 || r->http_status == 204 854 || r->http_status == 304) { 855 /* no Content-Body, no Content-Length */ 856 http_header_response_unset(r, HTTP_HEADER_CONTENT_LENGTH, 857 CONST_STR_LEN("Content-Length")); 858 } 859 else if (qlen > 0) { 860 buffer * const tb = r->tmp_buf; 861 buffer_clear(tb); 862 buffer_append_int(tb, qlen); 863 http_header_response_set(r, HTTP_HEADER_CONTENT_LENGTH, 864 CONST_STR_LEN("Content-Length"), 865 CONST_BUF_LEN(tb)); 866 } 867 else if (r->http_method != HTTP_METHOD_HEAD) { 868 /* Content-Length: 0 is important for Redirects (301, ...) as 869 * there might be content. */ 870 http_header_response_set(r, HTTP_HEADER_CONTENT_LENGTH, 871 CONST_STR_LEN("Content-Length"), 872 CONST_STR_LEN("0")); 873 } 874 } 875 } 876 else if (r->http_version == HTTP_VERSION_2) { 877 /* handled by HTTP/2 framing */ 878 } 879 else { 880 /** 881 * response is not yet finished, but we have all headers 882 * 883 * keep-alive requires one of: 884 * - Content-Length: ... (HTTP/1.0 and HTTP/1.0) 885 * - Transfer-Encoding: chunked (HTTP/1.1) 886 * - Upgrade: ... (lighttpd then acts as transparent proxy) 887 */ 888 889 if (!(r->resp_htags 890 & (HTTP_HEADER_CONTENT_LENGTH 891 |HTTP_HEADER_TRANSFER_ENCODING 892 |HTTP_HEADER_UPGRADE))) { 893 if (r->http_method == HTTP_METHOD_CONNECT && r->http_status == 200){ 894 /*(no transfer-encoding if successful CONNECT)*/ 895 } 896 else if (r->http_version == HTTP_VERSION_1_1) { 897 off_t qlen = chunkqueue_length(r->write_queue); 898 r->resp_send_chunked = 1; 899 if (qlen) { 900 /* create initial Transfer-Encoding: chunked segment */ 901 buffer * const b = 902 chunkqueue_prepend_buffer_open(r->write_queue); 903 buffer_append_uint_hex(b, (uintmax_t)qlen); 904 buffer_append_string_len(b, CONST_STR_LEN("\r\n")); 905 chunkqueue_prepend_buffer_commit(r->write_queue); 906 chunkqueue_append_mem(r->write_queue,CONST_STR_LEN("\r\n")); 907 } 908 http_header_response_append(r, HTTP_HEADER_TRANSFER_ENCODING, 909 CONST_STR_LEN("Transfer-Encoding"), 910 CONST_STR_LEN("chunked")); 911 } 912 else { /* if (r->http_version == HTTP_VERSION_1_0) */ 913 r->keep_alive = 0; 914 } 915 } 916 } 917 918 if (r->http_method == HTTP_METHOD_HEAD) { 919 /* HEAD request is like a GET, but without the content */ 920 http_response_body_clear(r, 1); 921 r->resp_body_finished = 1; 922 } 923 924 return HANDLER_GO_ON; 925 } 926 927 928 __attribute_cold__ 929 static handler_t 930 http_response_call_error_handler (request_st * const r, const buffer * const error_handler) 931 { 932 /* call error-handler */ 933 934 /* set REDIRECT_STATUS to save current HTTP status code 935 * for access by dynamic handlers 936 * https://redmine.lighttpd.net/issues/1828 */ 937 buffer * const tb = r->tmp_buf; 938 buffer_clear(tb); 939 buffer_append_int(tb, r->http_status); 940 http_header_env_set(r, CONST_STR_LEN("REDIRECT_STATUS"), CONST_BUF_LEN(tb)); 941 942 if (error_handler == r->conf.error_handler) { 943 plugins_call_handle_request_reset(r); 944 945 if (r->reqbody_length) { 946 if (r->reqbody_length != r->reqbody_queue->bytes_in) 947 r->keep_alive = 0; 948 r->reqbody_length = 0; 949 chunkqueue_reset(r->reqbody_queue); 950 } 951 952 r->con->is_writable = 1; 953 r->resp_body_finished = 0; 954 r->resp_body_started = 0; 955 956 r->error_handler_saved_status = r->http_status; 957 r->error_handler_saved_method = r->http_method; 958 959 r->http_method = HTTP_METHOD_GET; 960 } 961 else { /*(preserve behavior for server.error-handler-404)*/ 962 /*(negative to flag old behavior)*/ 963 r->error_handler_saved_status = -r->http_status; 964 } 965 966 if (r->http_version == HTTP_VERSION_UNSET) 967 r->http_version = HTTP_VERSION_1_0; 968 969 buffer_copy_buffer(&r->target, error_handler); 970 http_response_errdoc_init(r); 971 r->http_status = 0; /*(after http_response_errdoc_init())*/ 972 http_response_comeback(r); 973 return HANDLER_COMEBACK; 974 } 975 976 977 handler_t 978 http_response_handler (request_st * const r) 979 { 980 const plugin *p = r->handler_module; 981 int rc; 982 if (NULL != p 983 || ((rc = http_response_prepare(r)) == HANDLER_GO_ON 984 && NULL != (p = r->handler_module))) 985 rc = p->handle_subrequest(r, p->data); 986 987 switch (rc) { 988 case HANDLER_WAIT_FOR_EVENT: 989 if (!r->resp_body_finished 990 && (!r->resp_body_started || 0 == r->conf.stream_response_body)) 991 return HANDLER_WAIT_FOR_EVENT; /* come back here */ 992 /* response headers received from backend; start response */ 993 __attribute_fallthrough__ 994 case HANDLER_GO_ON: 995 case HANDLER_FINISHED: /*(HANDLER_FINISHED if request not handled)*/ 996 if (r->http_status == 0) r->http_status = 200; 997 if (r->error_handler_saved_status > 0) 998 r->http_method = r->error_handler_saved_method; 999 if (NULL == r->handler_module || r->conf.error_intercept) { 1000 if (r->error_handler_saved_status) { 1001 const int subreq_status = r->http_status; 1002 if (r->error_handler_saved_status > 0) 1003 r->http_status = r->error_handler_saved_status; 1004 else if (r->http_status == 404 || r->http_status == 403) 1005 /* error-handler-404 is a 404 */ 1006 r->http_status = -r->error_handler_saved_status; 1007 else { 1008 /* error-handler-404 is back and has generated content */ 1009 /* if Status: was set, take it otherwise use 200 */ 1010 } 1011 if (200 <= subreq_status && subreq_status <= 299) { 1012 /*(flag value to indicate that error handler succeeded) 1013 *(for (NULL == r->handler_module))*/ 1014 r->error_handler_saved_status = 65535; /* >= 1000 */ 1015 } 1016 } 1017 else if (r->http_status >= 400) { 1018 const buffer *error_handler = NULL; 1019 if (!buffer_string_is_empty(r->conf.error_handler)) 1020 error_handler = r->conf.error_handler; 1021 else if ((r->http_status == 404 || r->http_status == 403) 1022 && !buffer_string_is_empty(r->conf.error_handler_404)) 1023 error_handler = r->conf.error_handler_404; 1024 1025 if (error_handler) 1026 return http_response_call_error_handler(r, error_handler); 1027 } 1028 } 1029 1030 /* we have something to send; go on */ 1031 /*(CON_STATE_RESPONSE_START; transient state)*/ 1032 return http_response_write_prepare(r); 1033 case HANDLER_WAIT_FOR_FD: 1034 return HANDLER_WAIT_FOR_FD; 1035 case HANDLER_COMEBACK: 1036 http_response_comeback(r); 1037 return HANDLER_COMEBACK; 1038 /*case HANDLER_ERROR:*/ 1039 default: 1040 return HANDLER_ERROR; /* something went wrong */ 1041 } 1042 } 1043