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
http_response_delay(connection * const con)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
http_response_omit_header(request_st * const r,const data_string * const ds)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
http_response_write_header_partial_1xx(request_st * const r,buffer * const b)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
http_response_write_header(request_st * const r)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
http_response_physical_path_error(request_st * const r,const int code,const char * const msg)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
http_response_physical_path_check(request_st * const r)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__
http_status_set_error_close(request_st * const r,int status)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__
http_response_prepare_options_star(request_st * const r)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__
http_response_prepare_connect(request_st * const r)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
http_response_config(request_st * const r)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
http_response_prepare(request_st * const r)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",
544 BUFFER_INTLEN_PTR(&r->pathinfo));
545 }
546
547 /* call the handlers */
548 rc = plugins_call_handle_subrequest_start(r);
549 if (HANDLER_GO_ON != rc) return rc;
550
551 if (__builtin_expect( (NULL == r->handler_module), 0)) {
552 /* no handler; finish request */
553 if (__builtin_expect( (0 == r->http_status), 0)) {
554 if (r->http_method == HTTP_METHOD_OPTIONS) {
555 http_response_body_clear(r, 0);
556 http_response_prepare_options_star(r); /*(treat like "*")*/
557 }
558 else if (r->http_method == HTTP_METHOD_CONNECT)
559 /* 405 Method Not Allowed */
560 return http_status_set_error_close(r, 405);
561 /*return http_response_prepare_connect(r);*/
562 else if (!http_method_get_head_query_post(r->http_method))
563 r->http_status = 501;
564 else
565 r->http_status = 403;
566 }
567 return HANDLER_FINISHED;
568 }
569
570 return HANDLER_GO_ON;
571 }
572
573
574 __attribute_cold__
575 __attribute_noinline__
http_response_comeback(request_st * const r)576 static handler_t http_response_comeback (request_st * const r)
577 {
578 if (NULL != r->handler_module || !buffer_is_unset(&r->physical.path))
579 return HANDLER_GO_ON;
580
581 request_config_reset(r);
582
583 if (__builtin_expect( (r->http_host != NULL), 1))
584 buffer_copy_string_len_lc(&r->uri.authority, BUF_PTR_LEN(r->http_host));
585 else /*(buffer_blank(&r->uri.authority) w/o code inline)*/
586 buffer_copy_string_len(&r->uri.authority, CONST_STR_LEN(""));
587
588 int status = http_request_parse_target(r, r->con->proto_default_port);
589 if (0 == status) {
590 r->conditional_is_valid = (1 << COMP_SERVER_SOCKET)
591 | (1 << COMP_HTTP_SCHEME)
592 | (1 << COMP_HTTP_HOST)
593 | (1 << COMP_HTTP_REMOTE_IP)
594 | (1 << COMP_HTTP_REQUEST_METHOD)
595 | (1 << COMP_HTTP_URL)
596 | (1 << COMP_HTTP_QUERY_STRING)
597 | (1 << COMP_HTTP_REQUEST_HEADER);
598 return HANDLER_GO_ON;
599 }
600 else {
601 r->conditional_is_valid = (1 << COMP_SERVER_SOCKET)
602 | (1 << COMP_HTTP_REMOTE_IP);
603 config_cond_cache_reset(r);
604 return http_status_set_error_close(r, status);
605 }
606 }
607
608
609 __attribute_cold__
610 static void
http_response_errdoc_init(request_st * const r)611 http_response_errdoc_init (request_st * const r)
612 {
613 /* modules that produce headers required with error response should
614 * typically also produce an error document. Make an exception for
615 * mod_auth WWW-Authenticate response header. */
616 buffer *www_auth = NULL;
617 if (401 == r->http_status) {
618 const buffer * const vb =
619 http_header_response_get(r, HTTP_HEADER_WWW_AUTHENTICATE,
620 CONST_STR_LEN("WWW-Authenticate"));
621 if (NULL != vb) buffer_copy_buffer((www_auth = buffer_init()), vb);
622 }
623
624 buffer_reset(&r->physical.path);
625 r->resp_htags = 0;
626 array_reset_data_strings(&r->resp_headers);
627 http_response_body_clear(r, 0);
628
629 if (NULL != www_auth) {
630 http_header_response_set(r, HTTP_HEADER_WWW_AUTHENTICATE,
631 CONST_STR_LEN("WWW-Authenticate"),
632 BUF_PTR_LEN(www_auth));
633 buffer_free(www_auth);
634 }
635 }
636
637
638 __attribute_cold__
639 static void
http_response_static_errdoc(request_st * const r)640 http_response_static_errdoc (request_st * const r)
641 {
642 if (NULL == r->handler_module
643 ? r->error_handler_saved_status >= 65535
644 : (!r->conf.error_intercept || r->error_handler_saved_status))
645 return;
646
647 http_response_errdoc_init(r);
648 r->resp_body_finished = 1;
649
650 /* try to send static errorfile */
651 if (r->conf.errorfile_prefix) {
652 buffer_copy_buffer(&r->physical.path, r->conf.errorfile_prefix);
653 buffer_append_int(&r->physical.path, r->http_status);
654 buffer_append_string_len(&r->physical.path, CONST_STR_LEN(".html"));
655 stat_cache_entry *sce =
656 stat_cache_get_entry_open(&r->physical.path, r->conf.follow_symlink);
657 if (sce && 0 == http_chunk_append_file_ref(r, sce)) {
658 const buffer *content_type = stat_cache_content_type_get(sce, r);
659 if (content_type)
660 http_header_response_set(r, HTTP_HEADER_CONTENT_TYPE,
661 CONST_STR_LEN("Content-Type"),
662 BUF_PTR_LEN(content_type));
663 return;
664 }
665 buffer_clear(&r->physical.path);
666 }
667
668 /* build default error-page */
669 buffer * const b = chunkqueue_append_buffer_open(&r->write_queue);
670 buffer_copy_string_len(b, CONST_STR_LEN(
671 "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n"
672 "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n"
673 " \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n"
674 "<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n"
675 " <head>\n"
676 " <title>"));
677 http_status_append(b, r->http_status);
678 buffer_append_string_len(b, CONST_STR_LEN(
679 "</title>\n"
680 " </head>\n"
681 " <body>\n"
682 " <h1>"));
683 http_status_append(b, r->http_status);
684 buffer_append_string_len(b, CONST_STR_LEN(
685 "</h1>\n"
686 " </body>\n"
687 "</html>\n"));
688 chunkqueue_append_buffer_commit(&r->write_queue);
689
690 http_header_response_set(r, HTTP_HEADER_CONTENT_TYPE,
691 CONST_STR_LEN("Content-Type"),
692 CONST_STR_LEN("text/html"));
693 }
694
695
696 __attribute_cold__
697 static void
http_response_merge_trailers(request_st * const r)698 http_response_merge_trailers (request_st * const r)
699 {
700 /* attempt to merge trailers into headers; header not yet sent by caller */
701 if (buffer_is_blank(&r->gw_dechunk->b)) return;
702 const int done = r->gw_dechunk->done;
703 if (!done) return; /* XXX: !done; could scan for '\n' and send only those */
704
705 /* do not include trailers if success status (when response was read from
706 * backend) subsequently changed to error status. http_chunk could add the
707 * trailers, but such actions are better on a different code layer than in
708 * http_chunk.c */
709 if (done < 400 && r->http_status >= 400) return;
710
711 /* XXX: trailers passed through; no sanity check currently done
712 * https://tools.ietf.org/html/rfc7230#section-4.1.2
713 *
714 * Not checking for disallowed fields
715 * Not handling (deprecated) line wrapping
716 * Not strictly checking fields
717 */
718 const char *k = strchr(r->gw_dechunk->b.ptr, '\n'); /*(skip final chunk)*/
719 if (NULL == k) return; /*(should not happen)*/
720 ++k;
721 for (const char *v, *e; (e = strchr(k, '\n')); k = e+1) {
722 v = memchr(k, ':', (size_t)(e - k));
723 if (NULL == v || v == k || *k == ' ' || *k == '\t') continue;
724 uint32_t klen = (uint32_t)(v - k);
725 do { ++v; } while (*v == ' ' || *v == '\t');
726 if (*v == '\r' || *v == '\n') continue;
727 enum http_header_e id = http_header_hkey_get(k, klen);
728 http_header_response_insert(r, id, k, klen, v, (size_t)(e - v));
729 }
730 http_header_response_unset(r, HTTP_HEADER_OTHER, CONST_STR_LEN("Trailer"));
731 buffer_clear(&r->gw_dechunk->b);
732 }
733
734
735 __attribute_noinline__
736 static handler_t
http_response_write_prepare(request_st * const r)737 http_response_write_prepare(request_st * const r)
738 {
739 switch (r->http_status) {
740 case 200: /* common case */
741 break;
742 case 204: /* class: header only */
743 case 205:
744 case 304:
745 /* disable chunked encoding again as we have no body */
746 http_response_body_clear(r, 1);
747 /* no Content-Body, no Content-Length */
748 http_header_response_unset(r, HTTP_HEADER_CONTENT_LENGTH,
749 CONST_STR_LEN("Content-Length"));
750 r->resp_body_finished = 1;
751 break;
752 default: /* class: header + body */
753 /* only custom body for 4xx and 5xx */
754 if (r->http_status >= 400 && r->http_status < 600)
755 http_response_static_errdoc(r);
756 break;
757 }
758
759 if (r->gw_dechunk)
760 http_response_merge_trailers(r);
761
762 /* Allow filter plugins to change response headers */
763 switch (plugins_call_handle_response_start(r)) {
764 case HANDLER_GO_ON:
765 case HANDLER_FINISHED:
766 break;
767 default:
768 log_error(r->conf.errh, __FILE__, __LINE__,
769 "response_start plugin failed");
770 return HANDLER_ERROR;
771 }
772
773 if (r->resp_body_finished) {
774 /* check for Range request (current impl requires resp_body_finished) */
775 if (r->conf.range_requests && r->http_status == 200
776 && http_range_rfc7233(r) >= 400)
777 http_response_static_errdoc(r); /* 416 Range Not Satisfiable */
778
779 /* set content-length if length is known and not already set */
780 if (!(r->resp_htags
781 & (light_bshift(HTTP_HEADER_CONTENT_LENGTH)
782 |light_bshift(HTTP_HEADER_TRANSFER_ENCODING)))) {
783 off_t qlen = chunkqueue_length(&r->write_queue);
784 /**
785 * The Content-Length header can only be sent if we have content:
786 * - HEAD does not have a content-body (but can have content-length)
787 * - 1xx, 204 and 304 does not have a content-body
788 * (RFC 2616 Section 4.3)
789 *
790 * Otherwise generate a Content-Length header
791 * (if chunked encoding is not available)
792 *
793 * (should not reach here if 1xx (r->http_status < 200))
794 */
795 if (qlen > 0) {
796 buffer_append_int(
797 http_header_response_set_ptr(r, HTTP_HEADER_CONTENT_LENGTH,
798 CONST_STR_LEN("Content-Length")),
799 qlen);
800 }
801 else if (r->http_method != HTTP_METHOD_HEAD
802 && r->http_status != 204 && r->http_status != 304) {
803 /* Content-Length: 0 is important for Redirects (301, ...) as
804 * there might be content. */
805 http_header_response_set(r, HTTP_HEADER_CONTENT_LENGTH,
806 CONST_STR_LEN("Content-Length"),
807 CONST_STR_LEN("0"));
808 }
809 }
810 }
811 else if (r->http_version == HTTP_VERSION_2) {
812 /* handled by HTTP/2 framing */
813 }
814 else {
815 /**
816 * response is not yet finished, but we have all headers
817 *
818 * keep-alive requires one of:
819 * - Content-Length: ... (HTTP/1.0 and HTTP/1.0)
820 * - Transfer-Encoding: chunked (HTTP/1.1)
821 * - Upgrade: ... (lighttpd then acts as transparent proxy)
822 */
823
824 if (!(r->resp_htags
825 & (light_bshift(HTTP_HEADER_CONTENT_LENGTH)
826 |light_bshift(HTTP_HEADER_TRANSFER_ENCODING)
827 |light_bshift(HTTP_HEADER_UPGRADE)))) {
828 if (r->http_method == HTTP_METHOD_CONNECT && r->http_status == 200){
829 /*(no transfer-encoding if successful CONNECT)*/
830 }
831 else if (r->http_version == HTTP_VERSION_1_1) {
832 off_t qlen = chunkqueue_length(&r->write_queue);
833 r->resp_send_chunked = 1;
834 if (r->resp_decode_chunked) {
835 /*(reconstitute initial partially-decoded chunk)*/
836 off_t gw_chunked = r->gw_dechunk->gw_chunked;
837 if (gw_chunked >= 2)
838 qlen += gw_chunked - 2;
839 else if (1 == gw_chunked)
840 chunkqueue_append_mem(&r->write_queue,
841 CONST_STR_LEN("\r"));
842 else {
843 if (qlen)
844 chunkqueue_append_mem(&r->write_queue,
845 CONST_STR_LEN("\r\n"));
846 const buffer * const hdr = &r->gw_dechunk->b;
847 if (!buffer_is_blank(hdr)) /*(partial chunked header)*/
848 chunkqueue_append_mem(&r->write_queue,
849 BUF_PTR_LEN(hdr));
850 }
851 }
852 else if (qlen) {
853 chunkqueue_append_mem(&r->write_queue,
854 CONST_STR_LEN("\r\n"));
855 }
856 if (qlen) {
857 /* create initial Transfer-Encoding: chunked segment */
858 buffer * const b =
859 chunkqueue_prepend_buffer_open(&r->write_queue);
860 buffer_append_uint_hex(b, (uintmax_t)qlen);
861 buffer_append_string_len(b, CONST_STR_LEN("\r\n"));
862 chunkqueue_prepend_buffer_commit(&r->write_queue);
863 }
864 http_header_response_append(r, HTTP_HEADER_TRANSFER_ENCODING,
865 CONST_STR_LEN("Transfer-Encoding"),
866 CONST_STR_LEN("chunked"));
867 }
868 else { /* if (r->http_version == HTTP_VERSION_1_0) */
869 r->keep_alive = 0;
870 }
871 }
872 }
873
874 if (r->http_method == HTTP_METHOD_HEAD) {
875 /* HEAD request is like a GET, but without the content */
876 http_response_body_clear(r, 1);
877 r->resp_body_finished = 1;
878 }
879
880 return HANDLER_GO_ON;
881 }
882
883
884 __attribute_cold__
885 static int
http_response_call_error_handler(request_st * const r,const buffer * const error_handler)886 http_response_call_error_handler (request_st * const r, const buffer * const error_handler)
887 {
888 /* call error-handler */
889
890 /* set REDIRECT_STATUS to save current HTTP status code
891 * for access by dynamic handlers
892 * https://redmine.lighttpd.net/issues/1828 */
893 buffer_append_int(
894 http_header_env_set_ptr(r, CONST_STR_LEN("REDIRECT_STATUS")),
895 r->http_status);
896
897 if (error_handler == r->conf.error_handler) {
898 plugins_call_handle_request_reset(r);
899
900 if (r->reqbody_length) {
901 if (r->reqbody_length != r->reqbody_queue.bytes_in)
902 r->keep_alive = 0;
903 r->reqbody_length = 0;
904 chunkqueue_reset(&r->reqbody_queue);
905 }
906
907 r->con->is_writable = 1;
908 r->error_handler_saved_status = r->http_status;
909 r->error_handler_saved_method = r->http_method;
910 r->http_method = HTTP_METHOD_GET;
911 }
912 else { /*(preserve behavior for server.error-handler-404)*/
913 /*(negative to flag old behavior)*/
914 r->error_handler_saved_status = -r->http_status;
915 }
916
917 if (r->http_version == HTTP_VERSION_UNSET)
918 r->http_version = HTTP_VERSION_1_0;
919
920 buffer_copy_buffer(&r->target, error_handler);
921 http_response_errdoc_init(r);
922 r->http_status = 0; /*(after http_response_errdoc_init())*/
923 return 1;
924 }
925
926
927 __attribute_cold__
928 __attribute_noinline__
929 static int
http_response_has_error_handler(request_st * const r)930 http_response_has_error_handler (request_st * const r)
931 {
932 if (r->error_handler_saved_status > 0)
933 r->http_method = r->error_handler_saved_method;
934 if (NULL == r->handler_module || r->conf.error_intercept) {
935 if (__builtin_expect( (r->error_handler_saved_status), 0)) {
936 const int subreq_status = r->http_status;
937 if (r->error_handler_saved_status > 0)
938 r->http_status = r->error_handler_saved_status;
939 else if (r->http_status == 404 || r->http_status == 403)
940 /* error-handler-404 is a 404 */
941 r->http_status = -r->error_handler_saved_status;
942 else {
943 /* error-handler-404 is back and has generated content */
944 /* if Status: was set, take it otherwise use 200 */
945 }
946 if (200 <= subreq_status && subreq_status <= 299) {
947 /*(flag value to indicate that error handler succeeded)
948 *(for (NULL == r->handler_module))*/
949 r->error_handler_saved_status = 65535; /* >= 1000 */
950 }
951 }
952 else if (__builtin_expect( (r->http_status >= 400), 0)) {
953 const buffer *error_handler = NULL;
954 if (r->conf.error_handler)
955 error_handler = r->conf.error_handler;
956 else if ((r->http_status == 404 || r->http_status == 403)
957 && r->conf.error_handler_404)
958 error_handler = r->conf.error_handler_404;
959
960 if (error_handler)
961 return http_response_call_error_handler(r, error_handler);
962 }
963 }
964 return 0;
965 }
966
967
968 handler_t
http_response_handler(request_st * const r)969 http_response_handler (request_st * const r)
970 {
971 int rc;
972 do {
973 const plugin *p = r->handler_module;
974 if (NULL != p
975 || ((rc = http_response_prepare(r)) == HANDLER_GO_ON
976 && NULL != (p = r->handler_module)))
977 rc = p->handle_subrequest(r, p->data);
978
979 switch (rc) {
980 case HANDLER_WAIT_FOR_EVENT:
981 if (!r->resp_body_finished
982 && (!r->resp_body_started
983 || 0 == (r->conf.stream_response_body
984 & (FDEVENT_STREAM_RESPONSE
985 |FDEVENT_STREAM_RESPONSE_BUFMIN))))
986 return HANDLER_WAIT_FOR_EVENT; /* come back here */
987 /* response headers received from backend; start response */
988 __attribute_fallthrough__
989 case HANDLER_GO_ON:
990 case HANDLER_FINISHED:
991 if (r->http_status == 0) r->http_status = 200;
992 if ((__builtin_expect( (r->http_status < 400), 1)
993 && __builtin_expect( (0 == r->error_handler_saved_status), 1))
994 || __builtin_expect( (!http_response_has_error_handler(r)), 1))
995 /* we have something to send; go on */
996 /*(CON_STATE_RESPONSE_START; transient state)*/
997 return http_response_write_prepare(r);
998 __attribute_fallthrough__
999 case HANDLER_COMEBACK:
1000 http_response_comeback(r);
1001 rc = HANDLER_COMEBACK;
1002 continue;
1003 /*case HANDLER_ERROR:*/
1004 default:
1005 return HANDLER_ERROR; /* something went wrong */
1006 }
1007 } while (rc == HANDLER_COMEBACK);
1008 #ifndef __COVERITY__
1009 return HANDLER_ERROR; /* should not happen */ /*(not reached)*/
1010 #endif
1011 }
1012