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