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