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