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