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