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