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