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