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