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