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