xref: /openbsd-src/usr.sbin/httpd/server_http.c (revision 4e1ee0786f11cc571bd0be17d38e46f635c719fc)
1 /*	$OpenBSD: server_http.c,v 1.145 2021/10/22 08:51:50 benno Exp $	*/
2 
3 /*
4  * Copyright (c) 2020 Matthias Pressfreund <mpfr@fn.de>
5  * Copyright (c) 2006 - 2018 Reyk Floeter <reyk@openbsd.org>
6  *
7  * Permission to use, copy, modify, and distribute this software for any
8  * purpose with or without fee is hereby granted, provided that the above
9  * copyright notice and this permission notice appear in all copies.
10  *
11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 #include <sys/types.h>
21 #include <sys/queue.h>
22 #include <sys/socket.h>
23 #include <sys/tree.h>
24 #include <sys/stat.h>
25 
26 #include <netinet/in.h>
27 #include <arpa/inet.h>
28 
29 #include <errno.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <unistd.h>
33 #include <limits.h>
34 #include <fnmatch.h>
35 #include <stdio.h>
36 #include <time.h>
37 #include <resolv.h>
38 #include <event.h>
39 #include <ctype.h>
40 #include <vis.h>
41 #include <fcntl.h>
42 
43 #include "httpd.h"
44 #include "http.h"
45 #include "patterns.h"
46 
47 static int	 server_httpmethod_cmp(const void *, const void *);
48 static int	 server_httperror_cmp(const void *, const void *);
49 void		 server_httpdesc_free(struct http_descriptor *);
50 int		 server_http_authenticate(struct server_config *,
51 		    struct client *);
52 char		*server_expand_http(struct client *, const char *,
53 		    char *, size_t);
54 int		 http_version_num(char *);
55 
56 static struct http_method	 http_methods[] = HTTP_METHODS;
57 static struct http_error	 http_errors[] = HTTP_ERRORS;
58 
59 void
60 server_http(void)
61 {
62 	DPRINTF("%s: sorting lookup tables, pid %d", __func__, getpid());
63 
64 	/* Sort the HTTP lookup arrays */
65 	qsort(http_methods, sizeof(http_methods) /
66 	    sizeof(http_methods[0]) - 1,
67 	    sizeof(http_methods[0]), server_httpmethod_cmp);
68 	qsort(http_errors, sizeof(http_errors) /
69 	    sizeof(http_errors[0]) - 1,
70 	    sizeof(http_errors[0]), server_httperror_cmp);
71 }
72 
73 void
74 server_http_init(struct server *srv)
75 {
76 	/* nothing */
77 }
78 
79 int
80 server_httpdesc_init(struct client *clt)
81 {
82 	struct http_descriptor	*desc;
83 
84 	if ((desc = calloc(1, sizeof(*desc))) == NULL)
85 		return (-1);
86 	RB_INIT(&desc->http_headers);
87 	clt->clt_descreq = desc;
88 
89 	if ((desc = calloc(1, sizeof(*desc))) == NULL) {
90 		/* req will be cleaned up later */
91 		return (-1);
92 	}
93 	RB_INIT(&desc->http_headers);
94 	clt->clt_descresp = desc;
95 
96 	return (0);
97 }
98 
99 void
100 server_httpdesc_free(struct http_descriptor *desc)
101 {
102 	if (desc == NULL)
103 		return;
104 
105 	free(desc->http_path);
106 	desc->http_path = NULL;
107 	free(desc->http_path_orig);
108 	desc->http_path_orig = NULL;
109 	free(desc->http_path_alias);
110 	desc->http_path_alias = NULL;
111 	free(desc->http_query);
112 	desc->http_query = NULL;
113 	free(desc->http_query_alias);
114 	desc->http_query_alias = NULL;
115 	free(desc->http_version);
116 	desc->http_version = NULL;
117 	free(desc->http_host);
118 	desc->http_host = NULL;
119 
120 	kv_purge(&desc->http_headers);
121 	desc->http_lastheader = NULL;
122 	desc->http_method = 0;
123 	desc->http_chunked = 0;
124 }
125 
126 int
127 server_http_authenticate(struct server_config *srv_conf, struct client *clt)
128 {
129 	char			 decoded[1024];
130 	FILE			*fp = NULL;
131 	struct http_descriptor	*desc = clt->clt_descreq;
132 	const struct auth	*auth = srv_conf->auth;
133 	struct kv		*ba, key;
134 	size_t			 linesize = 0;
135 	ssize_t			 linelen;
136 	int			 ret = -1;
137 	char			*line = NULL, *user = NULL, *pass = NULL;
138 	char			*clt_user = NULL, *clt_pass = NULL;
139 
140 	memset(decoded, 0, sizeof(decoded));
141 	key.kv_key = "Authorization";
142 
143 	if ((ba = kv_find(&desc->http_headers, &key)) == NULL ||
144 	    ba->kv_value == NULL)
145 		goto done;
146 
147 	if (strncmp(ba->kv_value, "Basic ", strlen("Basic ")) != 0)
148 		goto done;
149 
150 	if (b64_pton(strchr(ba->kv_value, ' ') + 1, (uint8_t *)decoded,
151 	    sizeof(decoded)) <= 0)
152 		goto done;
153 
154 	if ((clt_pass = strchr(decoded, ':')) == NULL)
155 		goto done;
156 
157 	clt_user = decoded;
158 	*clt_pass++ = '\0';
159 	if ((clt->clt_remote_user = strdup(clt_user)) == NULL)
160 		goto done;
161 
162 	if ((fp = fopen(auth->auth_htpasswd, "r")) == NULL)
163 		goto done;
164 
165 	while ((linelen = getline(&line, &linesize, fp)) != -1) {
166 		if (line[linelen - 1] == '\n')
167 			line[linelen - 1] = '\0';
168 		user = line;
169 		pass = strchr(line, ':');
170 
171 		if (pass == NULL) {
172 			explicit_bzero(line, linelen);
173 			continue;
174 		}
175 
176 		*pass++ = '\0';
177 
178 		if (strcmp(clt_user, user) != 0) {
179 			explicit_bzero(line, linelen);
180 			continue;
181 		}
182 
183 		if (crypt_checkpass(clt_pass, pass) == 0) {
184 			explicit_bzero(line, linelen);
185 			ret = 0;
186 			break;
187 		}
188 	}
189 done:
190 	free(line);
191 	if (fp != NULL)
192 		fclose(fp);
193 
194 	if (ba != NULL && ba->kv_value != NULL) {
195 		explicit_bzero(ba->kv_value, strlen(ba->kv_value));
196 		explicit_bzero(decoded, sizeof(decoded));
197 	}
198 
199 	return (ret);
200 }
201 
202 int
203 http_version_num(char *version)
204 {
205 	if (strcmp(version, "HTTP/0.9") == 0)
206 		return (9);
207 	if (strcmp(version, "HTTP/1.0") == 0)
208 		return (10);
209 	/* any other version 1.x gets downgraded to 1.1 */
210 	if (strncmp(version, "HTTP/1", 6) == 0)
211 		return (11);
212 
213 	return (0);
214 }
215 
216 void
217 server_read_http(struct bufferevent *bev, void *arg)
218 {
219 	struct client		*clt = arg;
220 	struct http_descriptor	*desc = clt->clt_descreq;
221 	struct evbuffer		*src = EVBUFFER_INPUT(bev);
222 	char			*line = NULL, *key, *value;
223 	const char		*errstr;
224 	char			*http_version;
225 	size_t			 size, linelen;
226 	int			 version;
227 	struct kv		*hdr = NULL;
228 
229 	getmonotime(&clt->clt_tv_last);
230 
231 	size = EVBUFFER_LENGTH(src);
232 	DPRINTF("%s: session %d: size %lu, to read %lld",
233 	    __func__, clt->clt_id, size, clt->clt_toread);
234 	if (!size) {
235 		clt->clt_toread = TOREAD_HTTP_HEADER;
236 		goto done;
237 	}
238 
239 	while (!clt->clt_headersdone) {
240 		if (!clt->clt_line) {
241 			/* Peek into the buffer to see if it looks like HTTP */
242 			key = EVBUFFER_DATA(src);
243 			if (!isalpha((unsigned char)*key)) {
244 				server_abort_http(clt, 400,
245 				    "invalid request line");
246 				goto abort;
247 			}
248 		}
249 
250 		if ((line = evbuffer_readln(src,
251 		    &linelen, EVBUFFER_EOL_CRLF_STRICT)) == NULL) {
252 			/* No newline found after too many bytes */
253 			if (size > SERVER_MAXHEADERLENGTH) {
254 				server_abort_http(clt, 413,
255 				    "request line too long");
256 				goto abort;
257 			}
258 			break;
259 		}
260 
261 		/*
262 		 * An empty line indicates the end of the request.
263 		 * libevent already stripped the \r\n for us.
264 		 */
265 		if (!linelen) {
266 			clt->clt_headersdone = 1;
267 			free(line);
268 			break;
269 		}
270 		key = line;
271 
272 		/* Limit the total header length minus \r\n */
273 		clt->clt_headerlen += linelen;
274 		if (clt->clt_headerlen > SERVER_MAXHEADERLENGTH) {
275 			server_abort_http(clt, 413, "request too large");
276 			goto abort;
277 		}
278 
279 		/*
280 		 * The first line is the GET/POST/PUT/... request,
281 		 * subsequent lines are HTTP headers.
282 		 */
283 		if (++clt->clt_line == 1)
284 			value = strchr(key, ' ');
285 		else if (*key == ' ' || *key == '\t')
286 			/* Multiline headers wrap with a space or tab */
287 			value = NULL;
288 		else {
289 			/* Not a multiline header, should have a : */
290 			value = strchr(key, ':');
291 			if (value == NULL) {
292 				server_abort_http(clt, 400, "malformed");
293 				goto abort;
294 			}
295 		}
296 		if (value == NULL) {
297 			if (clt->clt_line == 1) {
298 				server_abort_http(clt, 400, "malformed");
299 				goto abort;
300 			}
301 
302 			/* Append line to the last header, if present */
303 			if (kv_extend(&desc->http_headers,
304 			    desc->http_lastheader, line) == NULL)
305 				goto fail;
306 
307 			free(line);
308 			continue;
309 		}
310 		if (*value == ':') {
311 			*value++ = '\0';
312 			value += strspn(value, " \t\r\n");
313 		} else {
314 			*value++ = '\0';
315 		}
316 
317 		DPRINTF("%s: session %d: header '%s: %s'", __func__,
318 		    clt->clt_id, key, value);
319 
320 		/*
321 		 * Identify and handle specific HTTP request methods
322 		 */
323 		if (clt->clt_line == 1) {
324 			if ((desc->http_method = server_httpmethod_byname(key))
325 			    == HTTP_METHOD_NONE) {
326 				server_abort_http(clt, 400, "malformed");
327 				goto abort;
328 			}
329 
330 			/*
331 			 * Decode request path and query
332 			 */
333 			desc->http_path = strdup(value);
334 			if (desc->http_path == NULL)
335 				goto fail;
336 
337 			http_version = strchr(desc->http_path, ' ');
338 			if (http_version == NULL) {
339 				server_abort_http(clt, 400, "malformed");
340 				goto abort;
341 			}
342 
343 			*http_version++ = '\0';
344 			desc->http_query = strchr(desc->http_path, '?');
345 			if (desc->http_query != NULL)
346 				*desc->http_query++ = '\0';
347 
348 			/*
349 			 * We have to allocate the strings because they could
350 			 * be changed independently by the filters later.
351 			 * Allow HTTP version 0.9 to 1.1.
352 			 * Downgrade http version > 1.1 <= 1.9 to version 1.1.
353 			 * Return HTTP Version Not Supported for anything else.
354 			 */
355 
356 			version = http_version_num(http_version);
357 
358 			if (version == 0) {
359 				server_abort_http(clt, 505, "bad http version");
360 				goto abort;
361 			} else if (version == 11) {
362 				if ((desc->http_version =
363 				    strdup("HTTP/1.1")) == NULL)
364 					goto fail;
365 			} else {
366 				if ((desc->http_version =
367 				    strdup(http_version)) == NULL)
368 					goto fail;
369 			}
370 
371 			if (desc->http_query != NULL &&
372 			    (desc->http_query =
373 			    strdup(desc->http_query)) == NULL)
374 				goto fail;
375 
376 		} else if (desc->http_method != HTTP_METHOD_NONE &&
377 		    strcasecmp("Content-Length", key) == 0) {
378 			if (desc->http_method == HTTP_METHOD_TRACE ||
379 			    desc->http_method == HTTP_METHOD_CONNECT) {
380 				/*
381 				 * These method should not have a body
382 				 * and thus no Content-Length header.
383 				 */
384 				server_abort_http(clt, 400, "malformed");
385 				goto abort;
386 			}
387 
388 			/*
389 			 * Need to read data from the client after the
390 			 * HTTP header.
391 			 * XXX What about non-standard clients not using
392 			 * the carriage return? And some browsers seem to
393 			 * include the line length in the content-length.
394 			 */
395 			clt->clt_toread = strtonum(value, 0, LLONG_MAX,
396 			    &errstr);
397 			if (errstr) {
398 				server_abort_http(clt, 500, errstr);
399 				goto abort;
400 			}
401 		}
402 
403 		if (strcasecmp("Transfer-Encoding", key) == 0 &&
404 		    strcasecmp("chunked", value) == 0)
405 			desc->http_chunked = 1;
406 
407 		if (clt->clt_line != 1) {
408 			if ((hdr = kv_add(&desc->http_headers, key,
409 			    value)) == NULL)
410 				goto fail;
411 
412 			desc->http_lastheader = hdr;
413 		}
414 
415 		free(line);
416 	}
417 	if (clt->clt_headersdone) {
418 		if (desc->http_method == HTTP_METHOD_NONE) {
419 			server_abort_http(clt, 406, "no method");
420 			return;
421 		}
422 
423 		switch (desc->http_method) {
424 		case HTTP_METHOD_CONNECT:
425 			/* Data stream */
426 			clt->clt_toread = TOREAD_UNLIMITED;
427 			bev->readcb = server_read;
428 			break;
429 		case HTTP_METHOD_GET:
430 		case HTTP_METHOD_HEAD:
431 		/* WebDAV methods */
432 		case HTTP_METHOD_COPY:
433 		case HTTP_METHOD_MOVE:
434 			clt->clt_toread = 0;
435 			break;
436 		case HTTP_METHOD_DELETE:
437 		case HTTP_METHOD_OPTIONS:
438 		case HTTP_METHOD_POST:
439 		case HTTP_METHOD_PUT:
440 		case HTTP_METHOD_RESPONSE:
441 		/* WebDAV methods */
442 		case HTTP_METHOD_PROPFIND:
443 		case HTTP_METHOD_PROPPATCH:
444 		case HTTP_METHOD_MKCOL:
445 		case HTTP_METHOD_LOCK:
446 		case HTTP_METHOD_UNLOCK:
447 		case HTTP_METHOD_VERSION_CONTROL:
448 		case HTTP_METHOD_REPORT:
449 		case HTTP_METHOD_CHECKOUT:
450 		case HTTP_METHOD_CHECKIN:
451 		case HTTP_METHOD_UNCHECKOUT:
452 		case HTTP_METHOD_MKWORKSPACE:
453 		case HTTP_METHOD_UPDATE:
454 		case HTTP_METHOD_LABEL:
455 		case HTTP_METHOD_MERGE:
456 		case HTTP_METHOD_BASELINE_CONTROL:
457 		case HTTP_METHOD_MKACTIVITY:
458 		case HTTP_METHOD_ORDERPATCH:
459 		case HTTP_METHOD_ACL:
460 		case HTTP_METHOD_MKREDIRECTREF:
461 		case HTTP_METHOD_UPDATEREDIRECTREF:
462 		case HTTP_METHOD_SEARCH:
463 		case HTTP_METHOD_PATCH:
464 			/* HTTP request payload */
465 			if (clt->clt_toread > 0)
466 				bev->readcb = server_read_httpcontent;
467 
468 			/* Single-pass HTTP body */
469 			if (clt->clt_toread < 0) {
470 				clt->clt_toread = TOREAD_UNLIMITED;
471 				bev->readcb = server_read;
472 			}
473 			break;
474 		default:
475 			server_abort_http(clt, 405, "method not allowed");
476 			return;
477 		}
478 		if (desc->http_chunked) {
479 			/* Chunked transfer encoding */
480 			clt->clt_toread = TOREAD_HTTP_CHUNK_LENGTH;
481 			bev->readcb = server_read_httpchunks;
482 		}
483 
484  done:
485 		if (clt->clt_toread != 0)
486 			bufferevent_disable(bev, EV_READ);
487 		server_response(httpd_env, clt);
488 		return;
489 	}
490 	if (clt->clt_done) {
491 		server_close(clt, "done");
492 		return;
493 	}
494 	if (EVBUFFER_LENGTH(src) && bev->readcb != server_read_http)
495 		bev->readcb(bev, arg);
496 	bufferevent_enable(bev, EV_READ);
497 	return;
498  fail:
499 	server_abort_http(clt, 500, strerror(errno));
500  abort:
501 	free(line);
502 }
503 
504 void
505 server_read_httpcontent(struct bufferevent *bev, void *arg)
506 {
507 	struct client		*clt = arg;
508 	struct evbuffer		*src = EVBUFFER_INPUT(bev);
509 	size_t			 size;
510 
511 	getmonotime(&clt->clt_tv_last);
512 
513 	size = EVBUFFER_LENGTH(src);
514 	DPRINTF("%s: session %d: size %lu, to read %lld", __func__,
515 	    clt->clt_id, size, clt->clt_toread);
516 	if (!size)
517 		return;
518 
519 	if (clt->clt_toread > 0) {
520 		/* Read content data */
521 		if ((off_t)size > clt->clt_toread) {
522 			size = clt->clt_toread;
523 			if (fcgi_add_stdin(clt, src) == -1)
524 				goto fail;
525 			clt->clt_toread = 0;
526 		} else {
527 			if (fcgi_add_stdin(clt, src) == -1)
528 				goto fail;
529 			clt->clt_toread -= size;
530 		}
531 		DPRINTF("%s: done, size %lu, to read %lld", __func__,
532 		    size, clt->clt_toread);
533 	}
534 	if (clt->clt_toread == 0) {
535 		fcgi_add_stdin(clt, NULL);
536 		clt->clt_toread = TOREAD_HTTP_HEADER;
537 		bufferevent_disable(bev, EV_READ);
538 		bev->readcb = server_read_http;
539 		return;
540 	}
541 	if (clt->clt_done)
542 		goto done;
543 	if (bev->readcb != server_read_httpcontent)
544 		bev->readcb(bev, arg);
545 
546 	return;
547  done:
548 	return;
549  fail:
550 	server_close(clt, strerror(errno));
551 }
552 
553 void
554 server_read_httpchunks(struct bufferevent *bev, void *arg)
555 {
556 	struct client		*clt = arg;
557 	struct evbuffer		*src = EVBUFFER_INPUT(bev);
558 	char			*line;
559 	long long		 llval;
560 	size_t			 size;
561 
562 	getmonotime(&clt->clt_tv_last);
563 
564 	size = EVBUFFER_LENGTH(src);
565 	DPRINTF("%s: session %d: size %lu, to read %lld", __func__,
566 	    clt->clt_id, size, clt->clt_toread);
567 	if (!size)
568 		return;
569 
570 	if (clt->clt_toread > 0) {
571 		/* Read chunk data */
572 		if ((off_t)size > clt->clt_toread) {
573 			size = clt->clt_toread;
574 			if (server_bufferevent_write_chunk(clt, src, size)
575 			    == -1)
576 				goto fail;
577 			clt->clt_toread = 0;
578 		} else {
579 			if (server_bufferevent_write_buffer(clt, src) == -1)
580 				goto fail;
581 			clt->clt_toread -= size;
582 		}
583 		DPRINTF("%s: done, size %lu, to read %lld", __func__,
584 		    size, clt->clt_toread);
585 	}
586 	switch (clt->clt_toread) {
587 	case TOREAD_HTTP_CHUNK_LENGTH:
588 		line = evbuffer_readln(src, NULL, EVBUFFER_EOL_CRLF_STRICT);
589 		if (line == NULL) {
590 			/* Ignore empty line, continue */
591 			bufferevent_enable(bev, EV_READ);
592 			return;
593 		}
594 		if (strlen(line) == 0) {
595 			free(line);
596 			goto next;
597 		}
598 
599 		/*
600 		 * Read prepended chunk size in hex, ignore the trailer.
601 		 * The returned signed value must not be negative.
602 		 */
603 		if (sscanf(line, "%llx", &llval) != 1 || llval < 0) {
604 			free(line);
605 			server_close(clt, "invalid chunk size");
606 			return;
607 		}
608 
609 		if (server_bufferevent_print(clt, line) == -1 ||
610 		    server_bufferevent_print(clt, "\r\n") == -1) {
611 			free(line);
612 			goto fail;
613 		}
614 		free(line);
615 
616 		if ((clt->clt_toread = llval) == 0) {
617 			DPRINTF("%s: last chunk", __func__);
618 			clt->clt_toread = TOREAD_HTTP_CHUNK_TRAILER;
619 		}
620 		break;
621 	case TOREAD_HTTP_CHUNK_TRAILER:
622 		/* Last chunk is 0 bytes followed by trailer and empty line */
623 		line = evbuffer_readln(src, NULL, EVBUFFER_EOL_CRLF_STRICT);
624 		if (line == NULL) {
625 			/* Ignore empty line, continue */
626 			bufferevent_enable(bev, EV_READ);
627 			return;
628 		}
629 		if (server_bufferevent_print(clt, line) == -1 ||
630 		    server_bufferevent_print(clt, "\r\n") == -1) {
631 			free(line);
632 			goto fail;
633 		}
634 		if (strlen(line) == 0) {
635 			/* Switch to HTTP header mode */
636 			clt->clt_toread = TOREAD_HTTP_HEADER;
637 			bev->readcb = server_read_http;
638 		}
639 		free(line);
640 		break;
641 	case 0:
642 		/* Chunk is terminated by an empty newline */
643 		line = evbuffer_readln(src, NULL, EVBUFFER_EOL_CRLF_STRICT);
644 		free(line);
645 		if (server_bufferevent_print(clt, "\r\n") == -1)
646 			goto fail;
647 		clt->clt_toread = TOREAD_HTTP_CHUNK_LENGTH;
648 		break;
649 	}
650 
651  next:
652 	if (clt->clt_done)
653 		goto done;
654 	if (EVBUFFER_LENGTH(src))
655 		bev->readcb(bev, arg);
656 	bufferevent_enable(bev, EV_READ);
657 	return;
658 
659  done:
660 	server_close(clt, "last http chunk read (done)");
661 	return;
662  fail:
663 	server_close(clt, strerror(errno));
664 }
665 
666 void
667 server_read_httprange(struct bufferevent *bev, void *arg)
668 {
669 	struct client		*clt = arg;
670 	struct evbuffer		*src = EVBUFFER_INPUT(bev);
671 	size_t			 size;
672 	struct media_type	*media;
673 	struct range_data	*r = &clt->clt_ranges;
674 	struct range		*range;
675 
676 	getmonotime(&clt->clt_tv_last);
677 
678 	if (r->range_toread > 0) {
679 		size = EVBUFFER_LENGTH(src);
680 		if (!size)
681 			return;
682 
683 		/* Read chunk data */
684 		if ((off_t)size > r->range_toread) {
685 			size = r->range_toread;
686 			if (server_bufferevent_write_chunk(clt, src, size)
687 			    == -1)
688 				goto fail;
689 			r->range_toread = 0;
690 		} else {
691 			if (server_bufferevent_write_buffer(clt, src) == -1)
692 				goto fail;
693 			r->range_toread -= size;
694 		}
695 		if (r->range_toread < 1)
696 			r->range_toread = TOREAD_HTTP_RANGE;
697 		DPRINTF("%s: done, size %lu, to read %lld", __func__,
698 		    size, r->range_toread);
699 	}
700 
701 	switch (r->range_toread) {
702 	case TOREAD_HTTP_RANGE:
703 		if (r->range_index >= r->range_count) {
704 			if (r->range_count > 1) {
705 				/* Add end marker */
706 				if (server_bufferevent_printf(clt,
707 				    "\r\n--%llu--\r\n",
708 				    clt->clt_boundary) == -1)
709 					goto fail;
710 			}
711 			r->range_toread = TOREAD_HTTP_NONE;
712 			break;
713 		}
714 
715 		range = &r->range[r->range_index];
716 
717 		if (r->range_count > 1) {
718 			media = r->range_media;
719 			if (server_bufferevent_printf(clt,
720 			    "\r\n--%llu\r\n"
721 			    "Content-Type: %s/%s\r\n"
722 			    "Content-Range: bytes %lld-%lld/%zu\r\n\r\n",
723 			    clt->clt_boundary,
724 			    media->media_type, media->media_subtype,
725 			    range->start, range->end, r->range_total) == -1)
726 				goto fail;
727 		}
728 		r->range_toread = range->end - range->start + 1;
729 
730 		if (lseek(clt->clt_fd, range->start, SEEK_SET) == -1)
731 			goto fail;
732 
733 		/* Throw away bytes that are already in the input buffer */
734 		evbuffer_drain(src, EVBUFFER_LENGTH(src));
735 
736 		/* Increment for the next part */
737 		r->range_index++;
738 		break;
739 	case TOREAD_HTTP_NONE:
740 		goto done;
741 	case 0:
742 		break;
743 	}
744 
745 	if (clt->clt_done)
746 		goto done;
747 
748 	if (EVBUFFER_LENGTH(EVBUFFER_OUTPUT(clt->clt_bev)) > (size_t)
749 	    SERVER_MAX_PREFETCH * clt->clt_sndbufsiz) {
750 		bufferevent_disable(clt->clt_srvbev, EV_READ);
751 		clt->clt_srvbev_throttled = 1;
752 	}
753 
754 	return;
755  done:
756 	(*bev->errorcb)(bev, EVBUFFER_READ, bev->cbarg);
757 	return;
758  fail:
759 	server_close(clt, strerror(errno));
760 }
761 
762 void
763 server_reset_http(struct client *clt)
764 {
765 	struct server		*srv = clt->clt_srv;
766 
767 	server_log(clt, NULL);
768 
769 	server_httpdesc_free(clt->clt_descreq);
770 	server_httpdesc_free(clt->clt_descresp);
771 	clt->clt_headerlen = 0;
772 	clt->clt_headersdone = 0;
773 	clt->clt_done = 0;
774 	clt->clt_line = 0;
775 	clt->clt_chunk = 0;
776 	free(clt->clt_remote_user);
777 	clt->clt_remote_user = NULL;
778 	clt->clt_bev->readcb = server_read_http;
779 	clt->clt_srv_conf = &srv->srv_conf;
780 	str_match_free(&clt->clt_srv_match);
781 }
782 
783 ssize_t
784 server_http_time(time_t t, char *tmbuf, size_t len)
785 {
786 	struct tm		 tm;
787 
788 	/* New HTTP/1.1 RFC 7231 prefers IMF-fixdate from RFC 5322 */
789 	if (t == -1 || gmtime_r(&t, &tm) == NULL)
790 		return (-1);
791 	else
792 		return (strftime(tmbuf, len, "%a, %d %h %Y %T %Z", &tm));
793 }
794 
795 const char *
796 server_http_host(struct sockaddr_storage *ss, char *buf, size_t len)
797 {
798 	char		hbuf[HOST_NAME_MAX+1];
799 	in_port_t	port;
800 
801 	if (print_host(ss, buf, len) == NULL)
802 		return (NULL);
803 
804 	port = ntohs(server_socket_getport(ss));
805 	if (port == HTTP_PORT)
806 		return (buf);
807 
808 	switch (ss->ss_family) {
809 	case AF_INET:
810 		if ((size_t)snprintf(hbuf, sizeof(hbuf),
811 		    "%s:%u", buf, port) >= sizeof(hbuf))
812 			return (NULL);
813 		break;
814 	case AF_INET6:
815 		if ((size_t)snprintf(hbuf, sizeof(hbuf),
816 		    "[%s]:%u", buf, port) >= sizeof(hbuf))
817 			return (NULL);
818 		break;
819 	}
820 
821 	if (strlcpy(buf, hbuf, len) >= len)
822 		return (NULL);
823 
824 	return (buf);
825 }
826 
827 char *
828 server_http_parsehost(char *host, char *buf, size_t len, int *portval)
829 {
830 	char		*start, *end, *port;
831 	const char	*errstr = NULL;
832 
833 	if (strlcpy(buf, host, len) >= len) {
834 		log_debug("%s: host name too long", __func__);
835 		return (NULL);
836 	}
837 
838 	start = buf;
839 	end = port = NULL;
840 
841 	if (*start == '[' && (end = strchr(start, ']')) != NULL) {
842 		/* Address enclosed in [] with port, eg. [2001:db8::1]:80 */
843 		start++;
844 		*end++ = '\0';
845 		if ((port = strchr(end, ':')) == NULL || *port == '\0')
846 			port = NULL;
847 		else
848 			port++;
849 		memmove(buf, start, strlen(start) + 1);
850 	} else if ((end = strchr(start, ':')) != NULL) {
851 		/* Name or address with port, eg. www.example.com:80 */
852 		*end++ = '\0';
853 		port = end;
854 	} else {
855 		/* Name or address with default port, eg. www.example.com */
856 		port = NULL;
857 	}
858 
859 	if (port != NULL) {
860 		/* Save the requested port */
861 		*portval = strtonum(port, 0, 0xffff, &errstr);
862 		if (errstr != NULL) {
863 			log_debug("%s: invalid port: %s", __func__,
864 			    strerror(errno));
865 			return (NULL);
866 		}
867 		*portval = htons(*portval);
868 	} else {
869 		/* Port not given, indicate the default port */
870 		*portval = -1;
871 	}
872 
873 	return (start);
874 }
875 
876 void
877 server_abort_http(struct client *clt, unsigned int code, const char *msg)
878 {
879 	struct server_config	*srv_conf = clt->clt_srv_conf;
880 	struct bufferevent	*bev = clt->clt_bev;
881 	struct http_descriptor	*desc = clt->clt_descreq;
882 	const char		*httperr = NULL, *style;
883 	char			*httpmsg, *body = NULL, *extraheader = NULL;
884 	char			 tmbuf[32], hbuf[128], *hstsheader = NULL;
885 	char			*clenheader = NULL;
886 	char			 buf[IBUF_READ_SIZE];
887 	char			*escapedmsg = NULL;
888 	int			 bodylen;
889 
890 	if (code == 0) {
891 		server_close(clt, "dropped");
892 		return;
893 	}
894 
895 	if ((httperr = server_httperror_byid(code)) == NULL)
896 		httperr = "Unknown Error";
897 
898 	if (bev == NULL)
899 		goto done;
900 
901 	if (server_log_http(clt, code, 0) == -1)
902 		goto done;
903 
904 	/* Some system information */
905 	if (print_host(&srv_conf->ss, hbuf, sizeof(hbuf)) == NULL)
906 		goto done;
907 
908 	if (server_http_time(time(NULL), tmbuf, sizeof(tmbuf)) <= 0)
909 		goto done;
910 
911 	/* Do not send details of the Internal Server Error */
912 	switch (code) {
913 	case 301:
914 	case 302:
915 	case 303:
916 	case 307:
917 	case 308:
918 		if (msg == NULL)
919 			break;
920 		memset(buf, 0, sizeof(buf));
921 		if (server_expand_http(clt, msg, buf, sizeof(buf)) == NULL)
922 			goto done;
923 		if (asprintf(&extraheader, "Location: %s\r\n", buf) == -1) {
924 			code = 500;
925 			extraheader = NULL;
926 		}
927 		msg = buf;
928 		break;
929 	case 401:
930 		if (msg == NULL)
931 			break;
932 		if (stravis(&escapedmsg, msg, VIS_DQ) == -1) {
933 			code = 500;
934 			extraheader = NULL;
935 		} else if (asprintf(&extraheader,
936 		    "WWW-Authenticate: Basic realm=\"%s\"\r\n", escapedmsg)
937 		    == -1) {
938 			code = 500;
939 			extraheader = NULL;
940 		}
941 		break;
942 	case 416:
943 		if (msg == NULL)
944 			break;
945 		if (asprintf(&extraheader,
946 		    "Content-Range: %s\r\n", msg) == -1) {
947 			code = 500;
948 			extraheader = NULL;
949 		}
950 		break;
951 	default:
952 		/*
953 		 * Do not send details of the error.  Traditionally,
954 		 * web servers responsed with the request path on 40x
955 		 * errors which could be abused to inject JavaScript etc.
956 		 * Instead of sanitizing the path here, we just don't
957 		 * reprint it.
958 		 */
959 		break;
960 	}
961 
962 	free(escapedmsg);
963 
964 	/* A CSS stylesheet allows minimal customization by the user */
965 	style = "body { background-color: white; color: black; font-family: "
966 	    "'Comic Sans MS', 'Chalkboard SE', 'Comic Neue', sans-serif; }\n"
967 	    "hr { border: 0; border-bottom: 1px dashed; }\n"
968 	    "@media (prefers-color-scheme: dark) {\n"
969 	    "body { background-color: #1E1F21; color: #EEEFF1; }\n"
970 	    "a { color: #BAD7FF; }\n}";
971 
972 	/* Generate simple HTML error document */
973 	if ((bodylen = asprintf(&body,
974 	    "<!DOCTYPE html>\n"
975 	    "<html>\n"
976 	    "<head>\n"
977 	    "<meta charset=\"utf-8\">\n"
978 	    "<title>%03d %s</title>\n"
979 	    "<style type=\"text/css\"><!--\n%s\n--></style>\n"
980 	    "</head>\n"
981 	    "<body>\n"
982 	    "<h1>%03d %s</h1>\n"
983 	    "<hr>\n<address>%s</address>\n"
984 	    "</body>\n"
985 	    "</html>\n",
986 	    code, httperr, style, code, httperr, HTTPD_SERVERNAME)) == -1) {
987 		body = NULL;
988 		goto done;
989 	}
990 
991 	if (srv_conf->flags & SRVFLAG_SERVER_HSTS &&
992 	    srv_conf->flags & SRVFLAG_TLS) {
993 		if (asprintf(&hstsheader, "Strict-Transport-Security: "
994 		    "max-age=%d%s%s\r\n", srv_conf->hsts_max_age,
995 		    srv_conf->hsts_flags & HSTSFLAG_SUBDOMAINS ?
996 		    "; includeSubDomains" : "",
997 		    srv_conf->hsts_flags & HSTSFLAG_PRELOAD ?
998 		    "; preload" : "") == -1) {
999 			hstsheader = NULL;
1000 			goto done;
1001 		}
1002 	}
1003 
1004 	if ((code >= 100 && code < 200) || code == 204)
1005 		clenheader = NULL;
1006 	else {
1007 		if (asprintf(&clenheader,
1008 		    "Content-Length: %d\r\n", bodylen) == -1) {
1009 			clenheader = NULL;
1010 			goto done;
1011 		}
1012 	}
1013 
1014 	/* Add basic HTTP headers */
1015 	if (asprintf(&httpmsg,
1016 	    "HTTP/1.0 %03d %s\r\n"
1017 	    "Date: %s\r\n"
1018 	    "Server: %s\r\n"
1019 	    "Connection: close\r\n"
1020 	    "Content-Type: text/html\r\n"
1021 	    "%s"
1022 	    "%s"
1023 	    "%s"
1024 	    "\r\n"
1025 	    "%s",
1026 	    code, httperr, tmbuf, HTTPD_SERVERNAME,
1027 	    clenheader == NULL ? "" : clenheader,
1028 	    extraheader == NULL ? "" : extraheader,
1029 	    hstsheader == NULL ? "" : hstsheader,
1030 	    desc->http_method == HTTP_METHOD_HEAD || clenheader == NULL ?
1031 	    "" : body) == -1)
1032 		goto done;
1033 
1034 	/* Dump the message without checking for success */
1035 	server_dump(clt, httpmsg, strlen(httpmsg));
1036 	free(httpmsg);
1037 
1038  done:
1039 	free(body);
1040 	free(extraheader);
1041 	free(hstsheader);
1042 	free(clenheader);
1043 	if (msg == NULL)
1044 		msg = "\"\"";
1045 	if (asprintf(&httpmsg, "%s (%03d %s)", msg, code, httperr) == -1) {
1046 		server_close(clt, msg);
1047 	} else {
1048 		server_close(clt, httpmsg);
1049 		free(httpmsg);
1050 	}
1051 }
1052 
1053 void
1054 server_close_http(struct client *clt)
1055 {
1056 	struct http_descriptor *desc;
1057 
1058 	desc = clt->clt_descreq;
1059 	server_httpdesc_free(desc);
1060 	free(desc);
1061 	clt->clt_descreq = NULL;
1062 
1063 	desc = clt->clt_descresp;
1064 	server_httpdesc_free(desc);
1065 	free(desc);
1066 	clt->clt_descresp = NULL;
1067 	free(clt->clt_remote_user);
1068 	clt->clt_remote_user = NULL;
1069 
1070 	str_match_free(&clt->clt_srv_match);
1071 }
1072 
1073 char *
1074 server_expand_http(struct client *clt, const char *val, char *buf,
1075     size_t len)
1076 {
1077 	struct http_descriptor	*desc = clt->clt_descreq;
1078 	struct server_config	*srv_conf = clt->clt_srv_conf;
1079 	char			 ibuf[128], *str, *path, *query;
1080 	const char		*errstr = NULL, *p;
1081 	size_t			 size;
1082 	int			 n, ret;
1083 
1084 	if (strlcpy(buf, val, len) >= len)
1085 		return (NULL);
1086 
1087 	/* Find previously matched substrings by index */
1088 	for (p = val; clt->clt_srv_match.sm_nmatch &&
1089 	    (p = strstr(p, "%")) != NULL; p++) {
1090 		if (!isdigit((unsigned char)*(p + 1)))
1091 			continue;
1092 
1093 		/* Copy number, leading '%' char and add trailing \0 */
1094 		size = strspn(p + 1, "0123456789") + 2;
1095 		if (size  >= sizeof(ibuf))
1096 			return (NULL);
1097 		(void)strlcpy(ibuf, p, size);
1098 		n = strtonum(ibuf + 1, 0,
1099 		    clt->clt_srv_match.sm_nmatch - 1, &errstr);
1100 		if (errstr != NULL)
1101 			return (NULL);
1102 
1103 		/* Expand variable with matched value */
1104 		if ((str = url_encode(clt->clt_srv_match.sm_match[n])) == NULL)
1105 			return (NULL);
1106 		ret = expand_string(buf, len, ibuf, str);
1107 		free(str);
1108 		if (ret != 0)
1109 			return (NULL);
1110 	}
1111 	if (strstr(val, "$DOCUMENT_URI") != NULL) {
1112 		if ((path = url_encode(desc->http_path)) == NULL)
1113 			return (NULL);
1114 		ret = expand_string(buf, len, "$DOCUMENT_URI", path);
1115 		free(path);
1116 		if (ret != 0)
1117 			return (NULL);
1118 	}
1119 	if (strstr(val, "$QUERY_STRING_ENC") != NULL) {
1120 		if (desc->http_query == NULL) {
1121 			ret = expand_string(buf, len, "$QUERY_STRING_ENC", "");
1122 		} else {
1123 			if ((query = url_encode(desc->http_query)) == NULL)
1124 				return (NULL);
1125 			ret = expand_string(buf, len, "$QUERY_STRING_ENC", query);
1126 			free(query);
1127 		}
1128 		if (ret != 0)
1129 			return (NULL);
1130 	}
1131 	if (strstr(val, "$QUERY_STRING") != NULL) {
1132 		if (desc->http_query == NULL) {
1133 			ret = expand_string(buf, len, "$QUERY_STRING", "");
1134 		} else {
1135 			ret = expand_string(buf, len, "$QUERY_STRING",
1136 			    desc->http_query);
1137 		}
1138 		if (ret != 0)
1139 			return (NULL);
1140 	}
1141 	if (strstr(val, "$HTTP_HOST") != NULL) {
1142 		if (desc->http_host == NULL)
1143 			return (NULL);
1144 		if ((str = url_encode(desc->http_host)) == NULL)
1145 			return (NULL);
1146 		expand_string(buf, len, "$HTTP_HOST", str);
1147 		free(str);
1148 	}
1149 	if (strstr(val, "$REMOTE_") != NULL) {
1150 		if (strstr(val, "$REMOTE_ADDR") != NULL) {
1151 			if (print_host(&clt->clt_ss,
1152 			    ibuf, sizeof(ibuf)) == NULL)
1153 				return (NULL);
1154 			if (expand_string(buf, len,
1155 			    "$REMOTE_ADDR", ibuf) != 0)
1156 				return (NULL);
1157 		}
1158 		if (strstr(val, "$REMOTE_PORT") != NULL) {
1159 			snprintf(ibuf, sizeof(ibuf),
1160 			    "%u", ntohs(clt->clt_port));
1161 			if (expand_string(buf, len,
1162 			    "$REMOTE_PORT", ibuf) != 0)
1163 				return (NULL);
1164 		}
1165 		if (strstr(val, "$REMOTE_USER") != NULL) {
1166 			if ((srv_conf->flags & SRVFLAG_AUTH) &&
1167 			    clt->clt_remote_user != NULL) {
1168 				if ((str = url_encode(clt->clt_remote_user))
1169 				    == NULL)
1170 					return (NULL);
1171 			} else
1172 				str = strdup("");
1173 			ret = expand_string(buf, len, "$REMOTE_USER", str);
1174 			free(str);
1175 			if (ret != 0)
1176 				return (NULL);
1177 		}
1178 	}
1179 	if (strstr(val, "$REQUEST_URI") != NULL) {
1180 		if ((path = url_encode(desc->http_path)) == NULL)
1181 			return (NULL);
1182 		if (desc->http_query == NULL) {
1183 			str = path;
1184 		} else {
1185 			ret = asprintf(&str, "%s?%s", path, desc->http_query);
1186 			free(path);
1187 			if (ret == -1)
1188 				return (NULL);
1189 		}
1190 
1191 		ret = expand_string(buf, len, "$REQUEST_URI", str);
1192 		free(str);
1193 		if (ret != 0)
1194 			return (NULL);
1195 	}
1196 	if (strstr(val, "$REQUEST_SCHEME") != NULL) {
1197 		if (srv_conf->flags & SRVFLAG_TLS) {
1198 			ret = expand_string(buf, len, "$REQUEST_SCHEME", "https");
1199 		} else {
1200 			ret = expand_string(buf, len, "$REQUEST_SCHEME", "http");
1201 		}
1202 		if (ret != 0)
1203 			return (NULL);
1204 	}
1205 	if (strstr(val, "$SERVER_") != NULL) {
1206 		if (strstr(val, "$SERVER_ADDR") != NULL) {
1207 			if (print_host(&srv_conf->ss,
1208 			    ibuf, sizeof(ibuf)) == NULL)
1209 				return (NULL);
1210 			if (expand_string(buf, len,
1211 			    "$SERVER_ADDR", ibuf) != 0)
1212 				return (NULL);
1213 		}
1214 		if (strstr(val, "$SERVER_PORT") != NULL) {
1215 			snprintf(ibuf, sizeof(ibuf), "%u",
1216 			    ntohs(srv_conf->port));
1217 			if (expand_string(buf, len,
1218 			    "$SERVER_PORT", ibuf) != 0)
1219 				return (NULL);
1220 		}
1221 		if (strstr(val, "$SERVER_NAME") != NULL) {
1222 			if ((str = url_encode(srv_conf->name))
1223 			     == NULL)
1224 				return (NULL);
1225 			ret = expand_string(buf, len, "$SERVER_NAME", str);
1226 			free(str);
1227 			if (ret != 0)
1228 				return (NULL);
1229 		}
1230 	}
1231 
1232 	return (buf);
1233 }
1234 
1235 int
1236 server_response(struct httpd *httpd, struct client *clt)
1237 {
1238 	char			 path[PATH_MAX];
1239 	char			 hostname[HOST_NAME_MAX+1];
1240 	struct http_descriptor	*desc = clt->clt_descreq;
1241 	struct http_descriptor	*resp = clt->clt_descresp;
1242 	struct server		*srv = clt->clt_srv;
1243 	struct server_config	*srv_conf = &srv->srv_conf;
1244 	struct kv		*kv, key, *host;
1245 	struct str_find		 sm;
1246 	int			 portval = -1, ret;
1247 	char			*hostval, *query;
1248 	const char		*errstr = NULL;
1249 
1250 	/* Preserve original path */
1251 	if (desc->http_path == NULL ||
1252 	    (desc->http_path_orig = strdup(desc->http_path)) == NULL)
1253 		goto fail;
1254 
1255 	/* Decode the URL */
1256 	if (url_decode(desc->http_path) == NULL)
1257 		goto fail;
1258 
1259 	/* Canonicalize the request path */
1260 	if (canonicalize_path(desc->http_path, path, sizeof(path)) == NULL)
1261 		goto fail;
1262 	free(desc->http_path);
1263 	if ((desc->http_path = strdup(path)) == NULL)
1264 		goto fail;
1265 
1266 	key.kv_key = "Host";
1267 	if ((host = kv_find(&desc->http_headers, &key)) != NULL &&
1268 	    host->kv_value == NULL)
1269 		host = NULL;
1270 
1271 	if (strcmp(desc->http_version, "HTTP/1.1") == 0) {
1272 		/* Host header is mandatory */
1273 		if (host == NULL)
1274 			goto fail;
1275 
1276 		/* Is the connection persistent? */
1277 		key.kv_key = "Connection";
1278 		if ((kv = kv_find(&desc->http_headers, &key)) != NULL &&
1279 		    strcasecmp("close", kv->kv_value) == 0)
1280 			clt->clt_persist = 0;
1281 		else
1282 			clt->clt_persist++;
1283 	} else {
1284 		/* Is the connection persistent? */
1285 		key.kv_key = "Connection";
1286 		if ((kv = kv_find(&desc->http_headers, &key)) != NULL &&
1287 		    strcasecmp("keep-alive", kv->kv_value) == 0)
1288 			clt->clt_persist++;
1289 		else
1290 			clt->clt_persist = 0;
1291 	}
1292 
1293 	/*
1294 	 * Do we have a Host header and matching configuration?
1295 	 * XXX the Host can also appear in the URL path.
1296 	 */
1297 	if (host != NULL) {
1298 		if ((hostval = server_http_parsehost(host->kv_value,
1299 		    hostname, sizeof(hostname), &portval)) == NULL)
1300 			goto fail;
1301 
1302 		TAILQ_FOREACH(srv_conf, &srv->srv_hosts, entry) {
1303 #ifdef DEBUG
1304 			if ((srv_conf->flags & SRVFLAG_LOCATION) == 0) {
1305 				DPRINTF("%s: virtual host \"%s:%u\""
1306 				    " host \"%s\" (\"%s\")",
1307 				    __func__, srv_conf->name,
1308 				    ntohs(srv_conf->port), host->kv_value,
1309 				    hostname);
1310 			}
1311 #endif
1312 			if (srv_conf->flags & SRVFLAG_LOCATION)
1313 				continue;
1314 			else if (srv_conf->flags & SRVFLAG_SERVER_MATCH) {
1315 				str_find(hostname, srv_conf->name,
1316 				    &sm, 1, &errstr);
1317 				ret = errstr == NULL ? 0 : -1;
1318 			} else {
1319 				ret = fnmatch(srv_conf->name,
1320 				    hostname, FNM_CASEFOLD);
1321 			}
1322 			if (ret == 0 &&
1323 			    (portval == -1 || portval == srv_conf->port)) {
1324 				/* Replace host configuration */
1325 				clt->clt_srv_conf = srv_conf;
1326 				srv_conf = NULL;
1327 				break;
1328 			}
1329 		}
1330 	}
1331 
1332 	if (srv_conf != NULL) {
1333 		/* Use the actual server IP address */
1334 		if (server_http_host(&clt->clt_srv_ss, hostname,
1335 		    sizeof(hostname)) == NULL)
1336 			goto fail;
1337 	} else {
1338 		/* Host header was valid and found */
1339 		if (strlcpy(hostname, host->kv_value, sizeof(hostname)) >=
1340 		    sizeof(hostname))
1341 			goto fail;
1342 		srv_conf = clt->clt_srv_conf;
1343 	}
1344 
1345 	if (clt->clt_persist >= srv_conf->maxrequests)
1346 		clt->clt_persist = 0;
1347 
1348 	/* pipelining should end after the first "idempotent" method */
1349 	if (clt->clt_pipelining && clt->clt_toread > 0)
1350 		clt->clt_persist = 0;
1351 
1352 	if ((desc->http_host = strdup(hostname)) == NULL)
1353 		goto fail;
1354 
1355 	/* Now fill in the mandatory parts of the response descriptor */
1356 	resp->http_method = desc->http_method;
1357 	if ((resp->http_version = strdup(desc->http_version)) == NULL)
1358 		goto fail;
1359 
1360 	/* Now search for the location */
1361 	if ((srv_conf = server_getlocation(clt, desc->http_path)) == NULL) {
1362 		server_abort_http(clt, 500, desc->http_path);
1363 		return (-1);
1364 	}
1365 
1366 	/* Optional rewrite */
1367 	if (srv_conf->flags & SRVFLAG_PATH_REWRITE) {
1368 		/* Expand macros */
1369 		if (server_expand_http(clt, srv_conf->path,
1370 		    path, sizeof(path)) == NULL)
1371 			goto fail;
1372 
1373 		/*
1374 		 * Reset and update the query.  The updated query must already
1375 		 * be URL encoded - either specified by the user or by using the
1376 		 * original $QUERY_STRING.
1377 		 */
1378 		free(desc->http_query_alias);
1379 		desc->http_query_alias = NULL;
1380 		if ((query = strchr(path, '?')) != NULL) {
1381 			*query++ = '\0';
1382 			if ((desc->http_query_alias = strdup(query)) == NULL)
1383 				goto fail;
1384 		}
1385 
1386 		/* Canonicalize the updated request path */
1387 		if (canonicalize_path(path,
1388 		    path, sizeof(path)) == NULL)
1389 			goto fail;
1390 
1391 		log_debug("%s: rewrote %s?%s -> %s?%s", __func__,
1392 		    desc->http_path, desc->http_query ? desc->http_query : "",
1393 		    path, query ? query : "");
1394 
1395 		free(desc->http_path_alias);
1396 		if ((desc->http_path_alias = strdup(path)) == NULL)
1397 			goto fail;
1398 
1399 		/* Now search for the updated location */
1400 		if ((srv_conf = server_getlocation(clt,
1401 		    desc->http_path_alias)) == NULL) {
1402 			server_abort_http(clt, 500, desc->http_path_alias);
1403 			return (-1);
1404 		}
1405 	}
1406 
1407 	if (clt->clt_toread > 0 && (size_t)clt->clt_toread >
1408 	    srv_conf->maxrequestbody) {
1409 		server_abort_http(clt, 413, NULL);
1410 		return (-1);
1411 	}
1412 
1413 	if (srv_conf->flags & SRVFLAG_BLOCK) {
1414 		server_abort_http(clt, srv_conf->return_code,
1415 		    srv_conf->return_uri);
1416 		return (-1);
1417 	} else if (srv_conf->flags & SRVFLAG_AUTH &&
1418 	    server_http_authenticate(srv_conf, clt) == -1) {
1419 		server_abort_http(clt, 401, srv_conf->auth_realm);
1420 		return (-1);
1421 	} else
1422 		return (server_file(httpd, clt));
1423  fail:
1424 	server_abort_http(clt, 400, "bad request");
1425 	return (-1);
1426 }
1427 
1428 const char *
1429 server_root_strip(const char *path, int n)
1430 {
1431 	const char *p;
1432 
1433 	/* Strip strip leading directories. Leading '/' is ignored. */
1434 	for (; n > 0 && *path != '\0'; n--)
1435 		if ((p = strchr(++path, '/')) == NULL)
1436 			path = strchr(path, '\0');
1437 		else
1438 			path = p;
1439 
1440 	return (path);
1441 }
1442 
1443 struct server_config *
1444 server_getlocation(struct client *clt, const char *path)
1445 {
1446 	struct server		*srv = clt->clt_srv;
1447 	struct server_config	*srv_conf = clt->clt_srv_conf, *location;
1448 	const char		*errstr = NULL;
1449 	int			 ret;
1450 
1451 	/* Now search for the location */
1452 	TAILQ_FOREACH(location, &srv->srv_hosts, entry) {
1453 #ifdef DEBUG
1454 		if (location->flags & SRVFLAG_LOCATION) {
1455 			DPRINTF("%s: location \"%s\" path \"%s\"",
1456 			    __func__, location->location, path);
1457 		}
1458 #endif
1459 		if ((location->flags & SRVFLAG_LOCATION) &&
1460 		    location->parent_id == srv_conf->parent_id) {
1461 			errstr = NULL;
1462 			if (location->flags & SRVFLAG_LOCATION_MATCH) {
1463 				ret = str_match(path, location->location,
1464 				    &clt->clt_srv_match, &errstr);
1465 			} else {
1466 				ret = fnmatch(location->location,
1467 				    path, FNM_CASEFOLD);
1468 			}
1469 			if (ret == 0 && errstr == NULL) {
1470 				if ((ret = server_locationaccesstest(location,
1471 				    path)) == -1)
1472 					return (NULL);
1473 
1474 				if (ret)
1475 					continue;
1476 				/* Replace host configuration */
1477 				clt->clt_srv_conf = srv_conf = location;
1478 				break;
1479 			}
1480 		}
1481 	}
1482 
1483 	return (srv_conf);
1484 }
1485 
1486 int
1487 server_locationaccesstest(struct server_config *srv_conf, const char *path)
1488 {
1489 	int		 rootfd, ret;
1490 	struct stat	 sb;
1491 
1492 	if (((SRVFLAG_LOCATION_FOUND | SRVFLAG_LOCATION_NOT_FOUND) &
1493 	    srv_conf->flags) == 0)
1494 		return (0);
1495 
1496 	if ((rootfd = open(srv_conf->root, O_RDONLY)) == -1)
1497 		return (-1);
1498 
1499 	path = server_root_strip(path, srv_conf->strip) + 1;
1500 	if ((ret = faccessat(rootfd, path, R_OK, 0)) != -1)
1501 		ret = fstatat(rootfd, path, &sb, 0);
1502 	close(rootfd);
1503 	return ((ret == -1 && SRVFLAG_LOCATION_FOUND & srv_conf->flags) ||
1504 	    (ret == 0 && SRVFLAG_LOCATION_NOT_FOUND & srv_conf->flags));
1505 }
1506 
1507 int
1508 server_response_http(struct client *clt, unsigned int code,
1509     struct media_type *media, off_t size, time_t mtime)
1510 {
1511 	struct server_config	*srv_conf = clt->clt_srv_conf;
1512 	struct http_descriptor	*desc = clt->clt_descreq;
1513 	struct http_descriptor	*resp = clt->clt_descresp;
1514 	const char		*error;
1515 	struct kv		*ct, *cl;
1516 	char			 tmbuf[32];
1517 
1518 	if (desc == NULL || media == NULL ||
1519 	    (error = server_httperror_byid(code)) == NULL)
1520 		return (-1);
1521 
1522 	if (server_log_http(clt, code, size >= 0 ? size : 0) == -1)
1523 		return (-1);
1524 
1525 	/* Add error codes */
1526 	if (kv_setkey(&resp->http_pathquery, "%u", code) == -1 ||
1527 	    kv_set(&resp->http_pathquery, "%s", error) == -1)
1528 		return (-1);
1529 
1530 	/* Add headers */
1531 	if (kv_add(&resp->http_headers, "Server", HTTPD_SERVERNAME) == NULL)
1532 		return (-1);
1533 
1534 	/* Is it a persistent connection? */
1535 	if (clt->clt_persist) {
1536 		if (kv_add(&resp->http_headers,
1537 		    "Connection", "keep-alive") == NULL)
1538 			return (-1);
1539 	} else if (kv_add(&resp->http_headers, "Connection", "close") == NULL)
1540 		return (-1);
1541 
1542 	/* Set media type */
1543 	if ((ct = kv_add(&resp->http_headers, "Content-Type", NULL)) == NULL ||
1544 	    kv_set(ct, "%s/%s", media->media_type, media->media_subtype) == -1)
1545 		return (-1);
1546 
1547 	/* Set content length, if specified */
1548 	if (size >= 0 && ((cl =
1549 	    kv_add(&resp->http_headers, "Content-Length", NULL)) == NULL ||
1550 	    kv_set(cl, "%lld", (long long)size) == -1))
1551 		return (-1);
1552 
1553 	/* Set last modification time */
1554 	if (server_http_time(mtime, tmbuf, sizeof(tmbuf)) <= 0 ||
1555 	    kv_add(&resp->http_headers, "Last-Modified", tmbuf) == NULL)
1556 		return (-1);
1557 
1558 	/* HSTS header */
1559 	if (srv_conf->flags & SRVFLAG_SERVER_HSTS &&
1560 	    srv_conf->flags & SRVFLAG_TLS) {
1561 		if ((cl =
1562 		    kv_add(&resp->http_headers, "Strict-Transport-Security",
1563 		    NULL)) == NULL ||
1564 		    kv_set(cl, "max-age=%d%s%s", srv_conf->hsts_max_age,
1565 		    srv_conf->hsts_flags & HSTSFLAG_SUBDOMAINS ?
1566 		    "; includeSubDomains" : "",
1567 		    srv_conf->hsts_flags & HSTSFLAG_PRELOAD ?
1568 		    "; preload" : "") == -1)
1569 			return (-1);
1570 	}
1571 
1572 	/* Date header is mandatory and should be added as late as possible */
1573 	if (server_http_time(time(NULL), tmbuf, sizeof(tmbuf)) <= 0 ||
1574 	    kv_add(&resp->http_headers, "Date", tmbuf) == NULL)
1575 		return (-1);
1576 
1577 	/* Write completed header */
1578 	if (server_writeresponse_http(clt) == -1 ||
1579 	    server_bufferevent_print(clt, "\r\n") == -1 ||
1580 	    server_headers(clt, resp, server_writeheader_http, NULL) == -1 ||
1581 	    server_bufferevent_print(clt, "\r\n") == -1)
1582 		return (-1);
1583 
1584 	if (size <= 0 || resp->http_method == HTTP_METHOD_HEAD) {
1585 		bufferevent_enable(clt->clt_bev, EV_READ|EV_WRITE);
1586 		if (clt->clt_persist)
1587 			clt->clt_toread = TOREAD_HTTP_HEADER;
1588 		else
1589 			clt->clt_toread = TOREAD_HTTP_NONE;
1590 		clt->clt_done = 0;
1591 		return (0);
1592 	}
1593 
1594 	return (1);
1595 }
1596 
1597 int
1598 server_writeresponse_http(struct client *clt)
1599 {
1600 	struct http_descriptor	*desc = clt->clt_descresp;
1601 
1602 	DPRINTF("version: %s rescode: %s resmsg: %s", desc->http_version,
1603 	    desc->http_rescode, desc->http_resmesg);
1604 
1605 	if (server_bufferevent_print(clt, desc->http_version) == -1 ||
1606 	    server_bufferevent_print(clt, " ") == -1 ||
1607 	    server_bufferevent_print(clt, desc->http_rescode) == -1 ||
1608 	    server_bufferevent_print(clt, " ") == -1 ||
1609 	    server_bufferevent_print(clt, desc->http_resmesg) == -1)
1610 		return (-1);
1611 
1612 	return (0);
1613 }
1614 
1615 int
1616 server_writeheader_http(struct client *clt, struct kv *hdr, void *arg)
1617 {
1618 	char			*ptr;
1619 	const char		*key;
1620 
1621 	if (hdr->kv_flags & KV_FLAG_INVALID)
1622 		return (0);
1623 
1624 	/* The key might have been updated in the parent */
1625 	if (hdr->kv_parent != NULL && hdr->kv_parent->kv_key != NULL)
1626 		key = hdr->kv_parent->kv_key;
1627 	else
1628 		key = hdr->kv_key;
1629 
1630 	ptr = hdr->kv_value;
1631 	if (server_bufferevent_print(clt, key) == -1 ||
1632 	    (ptr != NULL &&
1633 	    (server_bufferevent_print(clt, ": ") == -1 ||
1634 	    server_bufferevent_print(clt, ptr) == -1 ||
1635 	    server_bufferevent_print(clt, "\r\n") == -1)))
1636 		return (-1);
1637 	DPRINTF("%s: %s: %s", __func__, key,
1638 	    hdr->kv_value == NULL ? "" : hdr->kv_value);
1639 
1640 	return (0);
1641 }
1642 
1643 int
1644 server_headers(struct client *clt, void *descp,
1645     int (*hdr_cb)(struct client *, struct kv *, void *), void *arg)
1646 {
1647 	struct kv		*hdr, *kv;
1648 	struct http_descriptor	*desc = descp;
1649 
1650 	RB_FOREACH(hdr, kvtree, &desc->http_headers) {
1651 		if ((hdr_cb)(clt, hdr, arg) == -1)
1652 			return (-1);
1653 		TAILQ_FOREACH(kv, &hdr->kv_children, kv_entry) {
1654 			if ((hdr_cb)(clt, kv, arg) == -1)
1655 				return (-1);
1656 		}
1657 	}
1658 
1659 	return (0);
1660 }
1661 
1662 enum httpmethod
1663 server_httpmethod_byname(const char *name)
1664 {
1665 	enum httpmethod		 id = HTTP_METHOD_NONE;
1666 	struct http_method	 method, *res = NULL;
1667 
1668 	/* Set up key */
1669 	method.method_name = name;
1670 
1671 	if ((res = bsearch(&method, http_methods,
1672 	    sizeof(http_methods) / sizeof(http_methods[0]) - 1,
1673 	    sizeof(http_methods[0]), server_httpmethod_cmp)) != NULL)
1674 		id = res->method_id;
1675 
1676 	return (id);
1677 }
1678 
1679 const char *
1680 server_httpmethod_byid(unsigned int id)
1681 {
1682 	const char	*name = "<UNKNOWN>";
1683 	int		 i;
1684 
1685 	for (i = 0; http_methods[i].method_name != NULL; i++) {
1686 		if (http_methods[i].method_id == id) {
1687 			name = http_methods[i].method_name;
1688 			break;
1689 		}
1690 	}
1691 
1692 	return (name);
1693 }
1694 
1695 static int
1696 server_httpmethod_cmp(const void *a, const void *b)
1697 {
1698 	const struct http_method *ma = a;
1699 	const struct http_method *mb = b;
1700 
1701 	/*
1702 	 * RFC 2616 section 5.1.1 says that the method is case
1703 	 * sensitive so we don't do a strcasecmp here.
1704 	 */
1705 	return (strcmp(ma->method_name, mb->method_name));
1706 }
1707 
1708 const char *
1709 server_httperror_byid(unsigned int id)
1710 {
1711 	struct http_error	 error, *res;
1712 
1713 	/* Set up key */
1714 	error.error_code = (int)id;
1715 
1716 	if ((res = bsearch(&error, http_errors,
1717 	    sizeof(http_errors) / sizeof(http_errors[0]) - 1,
1718 	    sizeof(http_errors[0]), server_httperror_cmp)) != NULL)
1719 		return (res->error_name);
1720 
1721 	return (NULL);
1722 }
1723 
1724 static int
1725 server_httperror_cmp(const void *a, const void *b)
1726 {
1727 	const struct http_error *ea = a;
1728 	const struct http_error *eb = b;
1729 	return (ea->error_code - eb->error_code);
1730 }
1731 
1732 int
1733 server_log_http(struct client *clt, unsigned int code, size_t len)
1734 {
1735 	static char		 tstamp[64];
1736 	static char		 ip[INET6_ADDRSTRLEN];
1737 	time_t			 t;
1738 	struct kv		 key, *agent, *referrer, *xff, *xfp;
1739 	struct tm		*tm;
1740 	struct server_config	*srv_conf;
1741 	struct http_descriptor	*desc;
1742 	int			 ret = -1;
1743 	char			*user = NULL;
1744 	char			*path = NULL;
1745 	char			*version = NULL;
1746 	char			*referrer_v = NULL;
1747 	char			*agent_v = NULL;
1748 	char			*xff_v = NULL;
1749 	char			*xfp_v = NULL;
1750 
1751 	if ((srv_conf = clt->clt_srv_conf) == NULL)
1752 		return (-1);
1753 	if ((srv_conf->flags & SRVFLAG_LOG) == 0)
1754 		return (0);
1755 	if ((desc = clt->clt_descreq) == NULL)
1756 		return (-1);
1757 
1758 	if ((t = time(NULL)) == -1)
1759 		return (-1);
1760 	if ((tm = localtime(&t)) == NULL)
1761 		return (-1);
1762 	if (strftime(tstamp, sizeof(tstamp), "%d/%b/%Y:%H:%M:%S %z", tm) == 0)
1763 		return (-1);
1764 
1765 	if (print_host(&clt->clt_ss, ip, sizeof(ip)) == NULL)
1766 		return (-1);
1767 
1768 	/*
1769 	 * For details on common log format, see:
1770 	 * https://httpd.apache.org/docs/current/mod/mod_log_config.html
1771 	 *
1772 	 * httpd's format is similar to these Apache LogFormats:
1773 	 * "%v %h %l %u %t \"%r\" %>s %B"
1774 	 * "%v %h %l %u %t \"%r\" %>s %B \"%{Referer}i\" \"%{User-agent}i\""
1775 	 */
1776 	switch (srv_conf->logformat) {
1777 	case LOG_FORMAT_COMMON:
1778 		/* Use vis to encode input values from the header */
1779 		if (clt->clt_remote_user &&
1780 		    stravis(&user, clt->clt_remote_user, HTTPD_LOGVIS) == -1)
1781 			goto done;
1782 		if (desc->http_version &&
1783 		    stravis(&version, desc->http_version, HTTPD_LOGVIS) == -1)
1784 			goto done;
1785 
1786 		/* The following should be URL-encoded */
1787 		if (desc->http_path &&
1788 		    (path = url_encode(desc->http_path)) == NULL)
1789 			goto done;
1790 
1791 		ret = evbuffer_add_printf(clt->clt_log,
1792 		    "%s %s - %s [%s] \"%s %s%s%s%s%s\" %03d %zu\n",
1793 		    srv_conf->name, ip, clt->clt_remote_user == NULL ? "-" :
1794 		    user, tstamp,
1795 		    server_httpmethod_byid(desc->http_method),
1796 		    desc->http_path == NULL ? "" : path,
1797 		    desc->http_query == NULL ? "" : "?",
1798 		    desc->http_query == NULL ? "" : desc->http_query,
1799 		    desc->http_version == NULL ? "" : " ",
1800 		    desc->http_version == NULL ? "" : version,
1801 		    code, len);
1802 
1803 		break;
1804 
1805 	case LOG_FORMAT_COMBINED:
1806 	case LOG_FORMAT_FORWARDED:
1807 		key.kv_key = "Referer"; /* sic */
1808 		if ((referrer = kv_find(&desc->http_headers, &key)) != NULL &&
1809 		    referrer->kv_value == NULL)
1810 			referrer = NULL;
1811 
1812 		key.kv_key = "User-Agent";
1813 		if ((agent = kv_find(&desc->http_headers, &key)) != NULL &&
1814 		    agent->kv_value == NULL)
1815 			agent = NULL;
1816 
1817 		/* Use vis to encode input values from the header */
1818 		if (clt->clt_remote_user &&
1819 		    stravis(&user, clt->clt_remote_user, HTTPD_LOGVIS) == -1)
1820 			goto done;
1821 		if (clt->clt_remote_user == NULL &&
1822 		    clt->clt_tls_ctx != NULL &&
1823 		    (srv_conf->tls_flags & TLSFLAG_CA) &&
1824 		    tls_peer_cert_subject(clt->clt_tls_ctx) != NULL &&
1825 		    stravis(&user, tls_peer_cert_subject(clt->clt_tls_ctx),
1826 		    HTTPD_LOGVIS) == -1)
1827 			goto done;
1828 		if (desc->http_version &&
1829 		    stravis(&version, desc->http_version, HTTPD_LOGVIS) == -1)
1830 			goto done;
1831 		if (agent &&
1832 		    stravis(&agent_v, agent->kv_value, HTTPD_LOGVIS) == -1)
1833 			goto done;
1834 
1835 		/* The following should be URL-encoded */
1836 		if (desc->http_path &&
1837 		    (path = url_encode(desc->http_path)) == NULL)
1838 			goto done;
1839 		if (referrer &&
1840 		    (referrer_v = url_encode(referrer->kv_value)) == NULL)
1841 			goto done;
1842 
1843 		if ((ret = evbuffer_add_printf(clt->clt_log,
1844 		    "%s %s - %s [%s] \"%s %s%s%s%s%s\""
1845 		    " %03d %zu \"%s\" \"%s\"",
1846 		    srv_conf->name, ip, user == NULL ? "-" :
1847 		    user, tstamp,
1848 		    server_httpmethod_byid(desc->http_method),
1849 		    desc->http_path == NULL ? "" : path,
1850 		    desc->http_query == NULL ? "" : "?",
1851 		    desc->http_query == NULL ? "" : desc->http_query,
1852 		    desc->http_version == NULL ? "" : " ",
1853 		    desc->http_version == NULL ? "" : version,
1854 		    code, len,
1855 		    referrer == NULL ? "" : referrer_v,
1856 		    agent == NULL ? "" : agent_v)) == -1)
1857 			break;
1858 
1859 		if (srv_conf->logformat == LOG_FORMAT_COMBINED)
1860 			goto finish;
1861 
1862 		xff = xfp = NULL;
1863 
1864 		key.kv_key = "X-Forwarded-For";
1865 		if ((xff = kv_find(&desc->http_headers, &key)) != NULL
1866 		    && xff->kv_value == NULL)
1867 			xff = NULL;
1868 
1869 		if (xff &&
1870 		    stravis(&xff_v, xff->kv_value, HTTPD_LOGVIS) == -1)
1871 			goto finish;
1872 
1873 		key.kv_key = "X-Forwarded-Port";
1874 		if ((xfp = kv_find(&desc->http_headers, &key)) != NULL &&
1875 		    (xfp->kv_value == NULL))
1876 			xfp = NULL;
1877 
1878 		if (xfp &&
1879 		    stravis(&xfp_v, xfp->kv_value, HTTPD_LOGVIS) == -1)
1880 			goto finish;
1881 
1882 		if ((ret = evbuffer_add_printf(clt->clt_log, " %s %s",
1883 		    xff == NULL ? "-" : xff_v,
1884 		    xfp == NULL ? "-" : xfp_v)) == -1)
1885 			break;
1886 finish:
1887 		ret = evbuffer_add_printf(clt->clt_log, "\n");
1888 
1889 		break;
1890 
1891 	case LOG_FORMAT_CONNECTION:
1892 		/* URL-encode the path */
1893 		if (desc->http_path &&
1894 		    (path = url_encode(desc->http_path)) == NULL)
1895 			goto done;
1896 
1897 		ret = evbuffer_add_printf(clt->clt_log, " [%s]",
1898 		    desc->http_path == NULL ? "" : path);
1899 
1900 		break;
1901 	}
1902 
1903 done:
1904 	free(user);
1905 	free(path);
1906 	free(version);
1907 	free(referrer_v);
1908 	free(agent_v);
1909 	free(xff_v);
1910 	free(xfp_v);
1911 
1912 	return (ret);
1913 }
1914