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