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