kore

Kore is a web application platform for writing scalable, concurrent web based processes in C or Python.
Commits | Files | Refs | README | LICENSE | git clone https://git.kore.io/kore.git

http.c (59993B)



      1 /*
      2  * Copyright (c) 2013-2022 Joris Vink <joris@coders.se>
      3  *
      4  * Permission to use, copy, modify, and distribute this software for any
      5  * purpose with or without fee is hereby granted, provided that the above
      6  * copyright notice and this permission notice appear in all copies.
      7  *
      8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
      9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
     10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
     11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
     13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
     14  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     15  */
     16 
     17 #include <sys/param.h>
     18 #include <sys/types.h>
     19 
     20 #include <sys/socket.h>
     21 #include <netinet/in.h>
     22 
     23 #include <ctype.h>
     24 #include <fcntl.h>
     25 #include <inttypes.h>
     26 #include <float.h>
     27 #include <time.h>
     28 #include <stdio.h>
     29 
     30 #include "kore.h"
     31 #include "http.h"
     32 
     33 #if defined(KORE_USE_PYTHON)
     34 #include "python_api.h"
     35 #endif
     36 
     37 #if defined(KORE_USE_PGSQL)
     38 #include "pgsql.h"
     39 #endif
     40 
     41 #if defined(KORE_USE_TASKS)
     42 #include "tasks.h"
     43 #endif
     44 
     45 #if defined(KORE_USE_CURL)
     46 #include "curl.h"
     47 #endif
     48 
     49 static struct {
     50 	const char	*ext;
     51 	const char	*type;
     52 } builtin_media[] = {
     53 	{ "gif",	"image/gif" },
     54 	{ "png",	"image/png" },
     55 	{ "jpeg",	"image/jpeg" },
     56 	{ "jpg",	"image/jpeg" },
     57 	{ "zip",	"application/zip" },
     58 	{ "pdf",	"application/pdf" },
     59 	{ "json",	"application/json" },
     60 	{ "js",		"application/javascript" },
     61 	{ "htm",	"text/html" },
     62 	{ "txt",	"text/plain" },
     63 	{ "css",	"text/css" },
     64 	{ "html",	"text/html" },
     65 	{ NULL,		NULL },
     66 };
     67 
     68 #define HTTP_MAP_LIMIT		127
     69 
     70 /*
     71  * token      = 1*<any CHAR except CTLs or separators>
     72  * separators = "(" | ")" | "<" | ">" | "@"
     73  *            | "," | ";" | ":" | "\" | <">
     74  *            | "/" | "[" | "]" | "?" | "="
     75  *            | "{" | "}" | SP | HT
     76  */
     77 static const char http_token[] = {
     78 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     79 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     80 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     81 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     82 	0x00, '!' , 0x00, '#' , '$' , '%' , '&' , '\'',
     83 	0x00, 0x00, '*' , '+' , 0x00, '-' , '.' , 0x00,
     84 	'0' , '1' , '2' , '3' , '4' , '5' , '6' , '7' ,
     85 	'8' , '9' , 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     86 	0x00, 'A' , 'B' , 'C' , 'D' , 'E' , 'F' , 'G' ,
     87 	'H' , 'I' , 'J' , 'K' , 'L' , 'M' , 'N' , 'O' ,
     88 	'P' , 'Q' , 'R' , 'S' , 'T' , 'U' , 'V' , 'W' ,
     89 	'X' , 'Y' , 'Z' , 0x00, 0x00, 0x00, '^' , '_' ,
     90 	'`' , 'a' , 'b' , 'c' , 'd' , 'e' , 'f' , 'g' ,
     91 	'h' , 'i' , 'j' , 'k' , 'l' , 'm' , 'n' , 'o' ,
     92 	'p' , 'q' , 'r' , 's' , 't' , 'u' , 'v' , 'w' ,
     93 	'x' , 'y' , 'z' , 0x00, '|' , 0x00, '~' , 0x00
     94 };
     95 
     96 /*
     97  * field-content  = <the OCTETs making up the field-value
     98  *                   and consisting of either *TEXT or combinations
     99  *                   of token, separators, and quoted-string>
    100  */
    101 static const char http_field_content[] = {
    102 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    103 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    104 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    105 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    106 	' ' , '!' , '"' , '#' , '$' , '%' , '&' , '\'',
    107 	'(' , ')' , '*' , '+' , ',' , '-' , '.' , '/' ,
    108 	'0' , '1' , '2' , '3' , '4' , '5' , '6' , '7' ,
    109 	'8' , '9' , ':' , ';' , '<' , '=' , '>' , '?' ,
    110 	'@' , 'A' , 'B' , 'C' , 'D' , 'E' , 'F' , 'G' ,
    111 	'H' , 'I' , 'J' , 'K' , 'L' , 'M' , 'N' , 'O' ,
    112 	'P' , 'Q' , 'R' , 'S' , 'T' , 'U' , 'V' , 'W' ,
    113 	'X' , 'Y' , 'Z' , '[' , '\\', ']' , '^' , '_' ,
    114 	'`' , 'a' , 'b' , 'c' , 'd' , 'e' , 'f' , 'g' ,
    115 	'h' , 'i' , 'j' , 'k' , 'l' , 'm' , 'n' , 'o' ,
    116 	'p' , 'q' , 'r' , 's' , 't' , 'u' , 'v' , 'w' ,
    117 	'x' , 'y' , 'z' , '{' , '|' , '}' , '~' , 0x00
    118 };
    119 
    120 /*
    121  * Fixed "pretty" HTTP error HTML page.
    122  */
    123 static const char *pretty_error_fmt =
    124 	"<html>\n<head>\n\t<title>%d %s</title>"
    125 	"</head>\n<body>\n\t"
    126 	"<h1>%d %s</h1>\n"
    127 	"</body>\n</html>\n";
    128 
    129 static int	http_body_recv(struct netbuf *);
    130 static int	http_release_buffer(struct netbuf *);
    131 static void	http_error_response(struct connection *, int);
    132 static int	http_data_convert(void *, void **, void *, int);
    133 static void	http_write_response_cookie(struct http_cookie *);
    134 static int	http_body_update(struct http_request *, const void *, size_t);
    135 static void	http_argument_add(struct http_request *, char *, char *,
    136 		    int, int);
    137 static int	http_check_redirect(struct http_request *,
    138 		    struct kore_domain *);
    139 static void	http_response_normal(struct http_request *,
    140 		    struct connection *, int, const void *, size_t);
    141 static void	multipart_add_field(struct http_request *, struct kore_buf *,
    142 		    char *, const char *, const int);
    143 static void	multipart_file_add(struct http_request *, struct kore_buf *,
    144 		    const char *, const char *, const char *, const int);
    145 static int	multipart_find_data(struct kore_buf *, struct kore_buf *,
    146 		    size_t *, struct http_request *, const void *, size_t);
    147 static int	multipart_parse_headers(struct http_request *,
    148 		    struct kore_buf *, struct kore_buf *,
    149 		    const char *, const int);
    150 
    151 static struct http_request	*http_request_new(struct connection *,
    152 				    const char *, const char *, char *,
    153 				    const char *);
    154 
    155 static struct kore_buf			*header_buf;
    156 static struct kore_buf			*ckhdr_buf;
    157 static char				http_version[64];
    158 static u_int16_t			http_version_len;
    159 static TAILQ_HEAD(, http_request)	http_requests;
    160 static TAILQ_HEAD(, http_request)	http_requests_sleeping;
    161 static LIST_HEAD(, http_media_type)	http_media_types;
    162 static struct kore_pool			http_request_pool;
    163 static struct kore_pool			http_cookie_pool;
    164 static struct kore_pool			http_body_path;
    165 static struct kore_pool			http_rlq_pool;
    166 
    167 struct kore_pool			http_header_pool;
    168 
    169 int		http_pretty_error = 0;
    170 u_int32_t	http_request_count = 0;
    171 u_int32_t	http_request_ms = HTTP_REQUEST_MS;
    172 u_int16_t	http_body_timeout = HTTP_BODY_TIMEOUT;
    173 u_int32_t	http_request_limit = HTTP_REQUEST_LIMIT;
    174 u_int64_t	http_hsts_enable = HTTP_HSTS_ENABLE;
    175 u_int16_t	http_header_max = HTTP_HEADER_MAX_LEN;
    176 u_int16_t	http_keepalive_time = HTTP_KEEPALIVE_TIME;
    177 u_int16_t	http_header_timeout = HTTP_HEADER_TIMEOUT;
    178 
    179 size_t		http_body_max = HTTP_BODY_MAX_LEN;
    180 char		*http_body_disk_path = HTTP_BODY_DISK_PATH;
    181 u_int64_t	http_body_disk_offload = HTTP_BODY_DISK_OFFLOAD;
    182 
    183 void
    184 http_parent_init(void)
    185 {
    186 	LIST_INIT(&http_media_types);
    187 }
    188 
    189 void
    190 http_init(void)
    191 {
    192 	int		prealloc, l, i;
    193 
    194 	TAILQ_INIT(&http_requests);
    195 	TAILQ_INIT(&http_requests_sleeping);
    196 
    197 	header_buf = kore_buf_alloc(HTTP_HEADER_BUFSIZE);
    198 	ckhdr_buf = kore_buf_alloc(HTTP_COOKIE_BUFSIZE);
    199 
    200 	if (!http_version_len) {
    201 		l = snprintf(http_version, sizeof(http_version),
    202 		    "server: kore (%s)\r\n", kore_version);
    203 		if (l == -1 || (size_t)l >= sizeof(http_version))
    204 			fatal("http_init(): http_version buffer too small");
    205 
    206 		http_version_len = l;
    207 	}
    208 
    209 	prealloc = MIN((worker_max_connections / 10), 1000);
    210 	kore_pool_init(&http_request_pool, "http_request_pool",
    211 	    sizeof(struct http_request), http_request_limit);
    212 	kore_pool_init(&http_header_pool, "http_header_pool",
    213 	    sizeof(struct http_header), prealloc * HTTP_REQ_HEADER_MAX);
    214 	kore_pool_init(&http_cookie_pool, "http_cookie_pool",
    215 		sizeof(struct http_cookie), prealloc * HTTP_MAX_COOKIES);
    216 	kore_pool_init(&http_rlq_pool, "http_rlq_pool",
    217 		sizeof(struct http_runlock_queue), http_request_limit);
    218 
    219 	kore_pool_init(&http_body_path,
    220 	    "http_body_path", HTTP_BODY_PATH_MAX, prealloc);
    221 
    222 	for (i = 0; builtin_media[i].ext != NULL; i++) {
    223 		if (!http_media_register(builtin_media[i].ext,
    224 		    builtin_media[i].type)) {
    225 			fatal("duplicate media type for %s",
    226 			    builtin_media[i].ext);
    227 		}
    228 	}
    229 }
    230 
    231 void
    232 http_cleanup(void)
    233 {
    234 	if (header_buf != NULL) {
    235 		kore_buf_free(header_buf);
    236 		header_buf = NULL;
    237 	}
    238 
    239 	if (ckhdr_buf != NULL) {
    240 		kore_buf_free(ckhdr_buf);
    241 		ckhdr_buf = NULL;
    242 	}
    243 
    244 	kore_pool_cleanup(&http_request_pool);
    245 	kore_pool_cleanup(&http_header_pool);
    246 	kore_pool_cleanup(&http_body_path);
    247 }
    248 
    249 void
    250 http_server_version(const char *version)
    251 {
    252 	int		l;
    253 
    254 	l = snprintf(http_version, sizeof(http_version),
    255 	    "server: %s\r\n", version);
    256 	if (l == -1 || (size_t)l >= sizeof(http_version))
    257 		fatal("http_server_version(): http_version buffer too small");
    258 
    259 	http_version_len = l;
    260 }
    261 
    262 int
    263 http_check_timeout(struct connection *c, u_int64_t now)
    264 {
    265 	u_int64_t	d;
    266 
    267 	if (c->http_timeout == 0)
    268 		return (KORE_RESULT_OK);
    269 
    270 	if (now > c->http_start)
    271 		d = now - c->http_start;
    272 	else
    273 		d = 0;
    274 
    275 	if (d >= c->http_timeout) {
    276 		http_error_response(c, HTTP_STATUS_REQUEST_TIMEOUT);
    277 		kore_connection_disconnect(c);
    278 		return (KORE_RESULT_ERROR);
    279 	}
    280 
    281 	return (KORE_RESULT_OK);
    282 }
    283 
    284 void
    285 http_request_sleep(struct http_request *req)
    286 {
    287 	if (!(req->flags & HTTP_REQUEST_SLEEPING)) {
    288 		req->flags |= HTTP_REQUEST_SLEEPING;
    289 		TAILQ_REMOVE(&http_requests, req, list);
    290 		TAILQ_INSERT_TAIL(&http_requests_sleeping, req, list);
    291 	}
    292 }
    293 
    294 void
    295 http_request_wakeup(struct http_request *req)
    296 {
    297 	if (req->flags & HTTP_REQUEST_SLEEPING) {
    298 		req->flags &= ~HTTP_REQUEST_SLEEPING;
    299 		TAILQ_REMOVE(&http_requests_sleeping, req, list);
    300 		TAILQ_INSERT_TAIL(&http_requests, req, list);
    301 	}
    302 }
    303 
    304 void
    305 http_process(void)
    306 {
    307 	u_int64_t			total;
    308 	struct http_request		*req, *next;
    309 
    310 	total = 0;
    311 
    312 	for (req = TAILQ_FIRST(&http_requests); req != NULL; req = next) {
    313 		if (total >= http_request_ms)
    314 			break;
    315 
    316 		next = TAILQ_NEXT(req, list);
    317 		if (req->flags & HTTP_REQUEST_DELETE) {
    318 			http_request_free(req);
    319 			continue;
    320 		}
    321 
    322 		/* Sleeping requests should be in http_requests_sleeping. */
    323 		if (req->flags & HTTP_REQUEST_SLEEPING)
    324 			fatal("http_process: sleeping request on list");
    325 
    326 		if (!(req->flags & HTTP_REQUEST_COMPLETE))
    327 			continue;
    328 
    329 		http_process_request(req);
    330 		total += req->ms;
    331 
    332 		if (req->flags & HTTP_REQUEST_DELETE)
    333 			http_request_free(req);
    334 	}
    335 }
    336 
    337 void
    338 http_process_request(struct http_request *req)
    339 {
    340 	int		r;
    341 
    342 	if (req->flags & HTTP_REQUEST_DELETE || req->rt == NULL)
    343 		return;
    344 
    345 	req->start = kore_time_ms();
    346 	if (req->rt->auth != NULL && !(req->flags & HTTP_REQUEST_AUTHED))
    347 		r = kore_auth_run(req, req->rt->auth);
    348 	else
    349 		r = KORE_RESULT_OK;
    350 
    351 	switch (r) {
    352 	case KORE_RESULT_OK:
    353 		r = kore_runtime_http_request(req->rt->rcall, req);
    354 		break;
    355 	case KORE_RESULT_RETRY:
    356 		break;
    357 	case KORE_RESULT_ERROR:
    358 		/*
    359 		 * Set r to KORE_RESULT_OK so we can properly
    360 		 * flush the result from kore_auth_run().
    361 		 */
    362 		r = KORE_RESULT_OK;
    363 		break;
    364 	default:
    365 		fatal("kore_auth() returned unknown %d", r);
    366 	}
    367 	req->end = kore_time_ms();
    368 	req->ms = req->end - req->start;
    369 	req->total += req->ms;
    370 
    371 	switch (r) {
    372 	case KORE_RESULT_OK:
    373 		r = net_send_flush(req->owner);
    374 		if (r == KORE_RESULT_ERROR)
    375 			kore_connection_disconnect(req->owner);
    376 		break;
    377 	case KORE_RESULT_ERROR:
    378 		kore_connection_disconnect(req->owner);
    379 		break;
    380 	case KORE_RESULT_RETRY:
    381 		return;
    382 	default:
    383 		fatal("A page handler returned an unknown result: %d", r);
    384 	}
    385 
    386 	if (req->rt->dom->accesslog)
    387 		kore_accesslog(req);
    388 
    389 	req->flags |= HTTP_REQUEST_DELETE;
    390 }
    391 
    392 void
    393 http_response_header(struct http_request *req,
    394     const char *header, const char *value)
    395 {
    396 	struct http_header	*hdr;
    397 
    398 	hdr = NULL;
    399 
    400 	TAILQ_FOREACH(hdr, &req->resp_headers, list) {
    401 		if (!strcasecmp(hdr->header, header)) {
    402 			TAILQ_REMOVE(&req->resp_headers, hdr, list);
    403 			kore_free(hdr->header);
    404 			kore_free(hdr->value);
    405 			break;
    406 		}
    407 	}
    408 
    409 	if (hdr == NULL)
    410 		hdr = kore_pool_get(&http_header_pool);
    411 
    412 	hdr->header = kore_strdup(header);
    413 	hdr->value = kore_strdup(value);
    414 
    415 	TAILQ_INSERT_TAIL(&(req->resp_headers), hdr, list);
    416 }
    417 
    418 void
    419 http_request_free(struct http_request *req)
    420 {
    421 #if defined(KORE_USE_TASKS)
    422 	struct kore_task	*t, *nt;
    423 	int			pending_tasks;
    424 #endif
    425 #if defined(KORE_USE_PGSQL)
    426 	struct kore_pgsql	*pgsql;
    427 #endif
    428 #if defined(KORE_USE_CURL)
    429 	struct kore_curl	*client;
    430 #endif
    431 	struct http_file	*f, *fnext;
    432 	struct http_arg		*q, *qnext;
    433 	struct http_header	*hdr, *next;
    434 	struct http_cookie	*ck, *cknext;
    435 
    436 	if (req->rt != NULL && req->rt->on_free != NULL)
    437 		kore_runtime_http_request_free(req->rt->on_free, req);
    438 
    439 	if (req->runlock != NULL) {
    440 		LIST_REMOVE(req->runlock, list);
    441 		req->runlock = NULL;
    442 	}
    443 
    444 #if defined(KORE_USE_TASKS)
    445 	pending_tasks = 0;
    446 	for (t = LIST_FIRST(&(req->tasks)); t != NULL; t = nt) {
    447 		nt = LIST_NEXT(t, rlist);
    448 		if (!kore_task_finished(t)) {
    449 			pending_tasks++;
    450 		} else {
    451 			kore_task_destroy(t);
    452 		}
    453 	}
    454 
    455 	if (pending_tasks)
    456 		return;
    457 #endif
    458 
    459 #if defined(KORE_USE_PYTHON)
    460 	if (req->py_coro != NULL) {
    461 		kore_python_coro_delete(req->py_coro);
    462 		req->py_coro = NULL;
    463 	}
    464 	if (req->py_validator != NULL) {
    465 		kore_python_coro_delete(req->py_validator);
    466 		req->py_validator = NULL;
    467 	}
    468 	Py_XDECREF(req->py_req);
    469 #endif
    470 #if defined(KORE_USE_PGSQL)
    471 	while (!LIST_EMPTY(&(req->pgsqls))) {
    472 		pgsql = LIST_FIRST(&(req->pgsqls));
    473 		kore_pgsql_cleanup(pgsql);
    474 	}
    475 #endif
    476 #if defined(KORE_USE_CURL)
    477 	while (!LIST_EMPTY(&req->chandles)) {
    478 		client = LIST_FIRST(&req->chandles);
    479 		kore_curl_cleanup(client);
    480 	}
    481 #endif
    482 	kore_free(req->headers);
    483 
    484 	req->host = NULL;
    485 	req->path = NULL;
    486 	req->headers = NULL;
    487 
    488 	TAILQ_REMOVE(&http_requests, req, list);
    489 	if (req->owner != NULL)
    490 		TAILQ_REMOVE(&(req->owner->http_requests), req, olist);
    491 
    492 	for (hdr = TAILQ_FIRST(&(req->resp_headers)); hdr != NULL; hdr = next) {
    493 		next = TAILQ_NEXT(hdr, list);
    494 		TAILQ_REMOVE(&(req->resp_headers), hdr, list);
    495 		kore_free(hdr->header);
    496 		kore_free(hdr->value);
    497 		kore_pool_put(&http_header_pool, hdr);
    498 	}
    499 
    500 	for (hdr = TAILQ_FIRST(&(req->req_headers)); hdr != NULL; hdr = next) {
    501 		next = TAILQ_NEXT(hdr, list);
    502 		TAILQ_REMOVE(&(req->req_headers), hdr, list);
    503 		kore_pool_put(&http_header_pool, hdr);
    504 	}
    505 
    506 	for (ck = TAILQ_FIRST(&(req->resp_cookies)); ck != NULL; ck = cknext) {
    507 		cknext = TAILQ_NEXT(ck, list);
    508 		TAILQ_REMOVE(&(req->resp_cookies), ck, list);
    509 		kore_free(ck->name);
    510 		kore_free(ck->value);
    511 		kore_free(ck->path);
    512 		kore_free(ck->domain);
    513 		kore_pool_put(&http_cookie_pool, ck);
    514 	}
    515 
    516 	for (ck = TAILQ_FIRST(&(req->req_cookies)); ck != NULL; ck = cknext) {
    517 		cknext = TAILQ_NEXT(ck, list);
    518 		TAILQ_REMOVE(&(req->req_cookies), ck, list);
    519 		kore_free(ck->name);
    520 		kore_free(ck->value);
    521 		kore_pool_put(&http_cookie_pool, ck);
    522 	}
    523 
    524 	for (q = TAILQ_FIRST(&(req->arguments)); q != NULL; q = qnext) {
    525 		qnext = TAILQ_NEXT(q, list);
    526 		TAILQ_REMOVE(&(req->arguments), q, list);
    527 		kore_free(q->name);
    528 		kore_free(q->s_value);
    529 		kore_free(q);
    530 	}
    531 
    532 	for (f = TAILQ_FIRST(&(req->files)); f != NULL; f = fnext) {
    533 		fnext = TAILQ_NEXT(f, list);
    534 		TAILQ_REMOVE(&(req->files), f, list);
    535 		kore_free(f->filename);
    536 		kore_free(f->name);
    537 		kore_free(f);
    538 	}
    539 
    540 	if (req->http_body != NULL)
    541 		kore_buf_free(req->http_body);
    542 
    543 	if (req->http_body_fd != -1)
    544 		(void)close(req->http_body_fd);
    545 
    546 	if (req->http_body_path != NULL) {
    547 		if (unlink(req->http_body_path) == -1 && errno != ENOENT) {
    548 			kore_log(LOG_NOTICE, "failed to unlink %s: %s",
    549 			    req->http_body_path, errno_s);
    550 		}
    551 		kore_pool_put(&http_body_path, req->http_body_path);
    552 	}
    553 
    554 	if (req->hdlr_extra != NULL &&
    555 	    !(req->flags & HTTP_REQUEST_RETAIN_EXTRA))
    556 		kore_free(req->hdlr_extra);
    557 
    558 	kore_pool_put(&http_request_pool, req);
    559 	http_request_count--;
    560 }
    561 
    562 void
    563 http_serveable(struct http_request *req, const void *data, size_t len,
    564     const char *etag, const char *type)
    565 {
    566 	const char		*match;
    567 
    568 	if (req->method != HTTP_METHOD_GET) {
    569 		http_response_header(req, "allow", "get");
    570 		http_response(req, HTTP_STATUS_BAD_REQUEST, NULL, 0);
    571 		return;
    572 	}
    573 
    574 	if (http_request_header(req, "if-none-match", &match)) {
    575 		if (!strcmp(match, etag)) {
    576 			http_response(req, HTTP_STATUS_NOT_MODIFIED, NULL, 0);
    577 			return;
    578 		}
    579 	}
    580 
    581 	http_response_header(req, "etag", etag);
    582 	http_response_header(req, "content-type", type);
    583 	http_response(req, HTTP_STATUS_OK, data, len);
    584 }
    585 
    586 void
    587 http_response(struct http_request *req, int code, const void *d, size_t l)
    588 {
    589 	if (req->owner == NULL)
    590 		return;
    591 
    592 	req->status = code;
    593 
    594 	switch (req->owner->proto) {
    595 	case CONN_PROTO_HTTP:
    596 	case CONN_PROTO_WEBSOCKET:
    597 		http_response_normal(req, req->owner, code, d, l);
    598 		break;
    599 	default:
    600 		fatal("%s: bad proto %d", __func__, req->owner->proto);
    601 		/* NOTREACHED. */
    602 	}
    603 }
    604 
    605 void
    606 http_response_close(struct http_request *req, int code, const void *d, size_t l)
    607 {
    608 	if (req->owner == NULL)
    609 		return;
    610 
    611 	req->status = code;
    612 	req->owner->flags |= CONN_CLOSE_EMPTY;
    613 
    614 	switch (req->owner->proto) {
    615 	case CONN_PROTO_HTTP:
    616 	case CONN_PROTO_WEBSOCKET:
    617 		http_response_normal(req, req->owner, code, d, l);
    618 		break;
    619 	default:
    620 		fatal("%s: bad proto %d", __func__, req->owner->proto);
    621 		/* NOTREACHED. */
    622 	}
    623 }
    624 
    625 void
    626 http_response_json(struct http_request *req, int status,
    627     struct kore_json_item *json)
    628 {
    629 	struct kore_buf		*buf;
    630 
    631 	if (req->owner == NULL)
    632 		return;
    633 
    634 	buf = kore_buf_alloc(1024);
    635 	kore_json_item_tobuf(json, buf);
    636 	kore_json_item_free(json);
    637 
    638 	req->status = status;
    639 	http_response_header(req, "content-type", "application/json");
    640 
    641 	switch (req->owner->proto) {
    642 	case CONN_PROTO_HTTP:
    643 		http_response_stream(req, status, buf->data, buf->offset,
    644 		    http_release_buffer, buf);
    645 		break;
    646 	default:
    647 		fatal("%s: bad proto %d", __func__, req->owner->proto);
    648 		/* NOTREACHED. */
    649 	}
    650 }
    651 
    652 void
    653 http_response_stream(struct http_request *req, int status, void *base,
    654     size_t len, int (*cb)(struct netbuf *), void *arg)
    655 {
    656 	struct netbuf		*nb;
    657 
    658 	if (req->owner == NULL)
    659 		return;
    660 
    661 	req->status = status;
    662 
    663 	switch (req->owner->proto) {
    664 	case CONN_PROTO_HTTP:
    665 		http_response_normal(req, req->owner, status, NULL, len);
    666 		break;
    667 	default:
    668 		fatal("%s: bad proto %d", __func__, req->owner->proto);
    669 		/* NOTREACHED. */
    670 	}
    671 
    672 	net_send_stream(req->owner, base, len, cb, &nb);
    673 	nb->extra = arg;
    674 
    675 	if (req->method == HTTP_METHOD_HEAD) {
    676 		nb->s_off = nb->b_len;
    677 		net_remove_netbuf(req->owner, nb);
    678 	}
    679 }
    680 
    681 void
    682 http_response_fileref(struct http_request *req, int status,
    683     struct kore_fileref *ref)
    684 {
    685 	struct tm		*tm;
    686 	time_t			mtime;
    687 	char			tbuf[128];
    688 	const char		*media_type, *modified;
    689 
    690 	if (req->owner == NULL)
    691 		return;
    692 
    693 	media_type = http_media_type(ref->path);
    694 	if (media_type != NULL)
    695 		http_response_header(req, "content-type", media_type);
    696 
    697 	if (http_request_header(req, "if-modified-since", &modified)) {
    698 		mtime = kore_date_to_time(modified);
    699 		if (mtime == ref->mtime_sec) {
    700 			kore_fileref_release(ref);
    701 			http_response(req, HTTP_STATUS_NOT_MODIFIED, NULL, 0);
    702 			return;
    703 		}
    704 	}
    705 
    706 	if ((tm = gmtime(&ref->mtime_sec)) != NULL) {
    707 		if (strftime(tbuf, sizeof(tbuf),
    708 		    "%a, %d %b %Y %H:%M:%S GMT", tm) > 0) {
    709 			http_response_header(req, "last-modified", tbuf);
    710 		}
    711 	}
    712 
    713 	req->status = status;
    714 	switch (req->owner->proto) {
    715 	case CONN_PROTO_HTTP:
    716 		http_response_normal(req, req->owner, status, NULL, ref->size);
    717 		break;
    718 	default:
    719 		fatal("http_response_fd() bad proto %d", req->owner->proto);
    720 		/* NOTREACHED. */
    721 	}
    722 
    723 	if (req->method != HTTP_METHOD_HEAD)
    724 		net_send_fileref(req->owner, ref);
    725 	else
    726 		kore_fileref_release(ref);
    727 }
    728 
    729 int
    730 http_request_header(struct http_request *req, const char *header,
    731     const char **out)
    732 {
    733 	struct http_header	*hdr;
    734 
    735 	TAILQ_FOREACH(hdr, &(req->req_headers), list) {
    736 		if (!strcasecmp(hdr->header, header)) {
    737 			*out = hdr->value;
    738 			return (KORE_RESULT_OK);
    739 		}
    740 	}
    741 
    742 	if (!strcasecmp(header, "host")) {
    743 		*out = req->host;
    744 		return (KORE_RESULT_OK);
    745 	}
    746 
    747 	return (KORE_RESULT_ERROR);
    748 }
    749 
    750 int
    751 http_request_header_get(struct http_request *req, const char *header,
    752     void **out, void *nout, int type)
    753 {
    754 	struct http_header	*hdr;
    755 
    756 	if (type == HTTP_ARG_TYPE_STRING)
    757 		fatal("%s: cannot be called with type string", __func__);
    758 
    759 	TAILQ_FOREACH(hdr, &req->req_headers, list) {
    760 		if (strcasecmp(hdr->header, header))
    761 			continue;
    762 
    763 		if (http_data_convert(hdr->value, out, nout, type))
    764 			return (KORE_RESULT_OK);
    765 
    766 		return (KORE_RESULT_ERROR);
    767 	}
    768 
    769 	return (KORE_RESULT_ERROR);
    770 }
    771 
    772 int
    773 http_request_cookie(struct http_request *req, const char *cookie, char **out)
    774 {
    775 	struct http_cookie	*ck;
    776 
    777 	TAILQ_FOREACH(ck, &(req->req_cookies), list) {
    778 		if (!strcasecmp(ck->name, cookie)) {
    779 			*out = ck->value;
    780 			return (KORE_RESULT_OK);
    781 		}
    782 	}
    783 
    784 	return (KORE_RESULT_ERROR);
    785 }
    786 
    787 int
    788 http_header_recv(struct netbuf *nb)
    789 {
    790 	struct connection	*c;
    791 	size_t			len;
    792 	struct http_header	*hdr;
    793 	struct http_request	*req;
    794 	u_int8_t		*end_headers;
    795 	int			h, i, v, skip, l;
    796 	char			*headers[HTTP_REQ_HEADER_MAX];
    797 	char			*value, *host, *request[4], *hbuf;
    798 
    799 	c = nb->owner;
    800 
    801 	if (nb->s_off < 4)
    802 		return (KORE_RESULT_OK);
    803 
    804 	if (!isalpha(nb->buf[0])) {
    805 		http_error_response(c, HTTP_STATUS_BAD_REQUEST);
    806 		return (KORE_RESULT_ERROR);
    807 	}
    808 
    809 	skip = 4;
    810 	end_headers = kore_mem_find(nb->buf, nb->s_off, "\r\n\r\n", 4);
    811 	if (end_headers == NULL) {
    812 		end_headers = kore_mem_find(nb->buf, nb->s_off, "\n\n", 2);
    813 		if (end_headers == NULL) {
    814 			if (nb->s_off == http_header_max) {
    815 				http_error_response(c,
    816 				    HTTP_STATUS_REQUEST_ENTITY_TOO_LARGE);
    817 				return (KORE_RESULT_ERROR);
    818 			}
    819 			return (KORE_RESULT_OK);
    820 		}
    821 		skip = 2;
    822 	}
    823 
    824 	*end_headers = '\0';
    825 	end_headers += skip;
    826 	len = end_headers - nb->buf;
    827 	hbuf = (char *)nb->buf;
    828 
    829 	h = kore_split_string(hbuf, "\r\n", headers, HTTP_REQ_HEADER_MAX);
    830 	if (h < 2) {
    831 		http_error_response(c, HTTP_STATUS_BAD_REQUEST);
    832 		return (KORE_RESULT_OK);
    833 	}
    834 
    835 	v = kore_split_string(headers[0], " ", request, 4);
    836 	if (v != 3) {
    837 		http_error_response(c, HTTP_STATUS_BAD_REQUEST);
    838 		return (KORE_RESULT_OK);
    839 	}
    840 
    841 	skip = 0;
    842 	host = NULL;
    843 	for (i = 0; i < h; i++) {
    844 		if (strncasecmp(headers[i], "host", 4))
    845 			continue;
    846 
    847 		if ((host = http_validate_header(headers[i])) == NULL) {
    848 			http_error_response(c, HTTP_STATUS_BAD_REQUEST);
    849 			return (KORE_RESULT_OK);
    850 		}
    851 
    852 		if (*host == '\0') {
    853 			http_error_response(c, HTTP_STATUS_BAD_REQUEST);
    854 			return (KORE_RESULT_OK);
    855 		}
    856 
    857 		skip = i;
    858 		break;
    859 	}
    860 
    861 	if (host == NULL) {
    862 		http_error_response(c, HTTP_STATUS_BAD_REQUEST);
    863 		return (KORE_RESULT_OK);
    864 	}
    865 
    866 	req = http_request_new(c, host, request[0], request[1], request[2]);
    867 	if (req == NULL)
    868 		return (KORE_RESULT_OK);
    869 
    870 	/* take full ownership of the buffer. */
    871 	req->headers = nb->buf;
    872 	nb->buf = NULL;
    873 	nb->m_len = 0;
    874 
    875 	for (i = 1; i < h; i++) {
    876 		if (i == skip)
    877 			continue;
    878 
    879 		if ((value = http_validate_header(headers[i])) == NULL) {
    880 			req->flags |= HTTP_REQUEST_DELETE;
    881 			http_error_response(c, HTTP_STATUS_BAD_REQUEST);
    882 			return (KORE_RESULT_OK);
    883 		}
    884 
    885 		if (*value == '\0') {
    886 			req->flags |= HTTP_REQUEST_DELETE;
    887 			http_error_response(c, HTTP_STATUS_BAD_REQUEST);
    888 			return (KORE_RESULT_OK);
    889 		}
    890 
    891 		hdr = kore_pool_get(&http_header_pool);
    892 		hdr->header = headers[i];
    893 		hdr->value = value;
    894 		TAILQ_INSERT_TAIL(&(req->req_headers), hdr, list);
    895 
    896 		if (req->agent == NULL &&
    897 		    !strcasecmp(hdr->header, "user-agent"))
    898 			req->agent = hdr->value;
    899 
    900 		if (req->referer == NULL &&
    901 		    !strcasecmp(hdr->header, "referer"))
    902 			req->referer = hdr->value;
    903 	}
    904 
    905 	if (req->flags & HTTP_REQUEST_EXPECT_BODY) {
    906 		if (http_body_max == 0) {
    907 			req->flags |= HTTP_REQUEST_DELETE;
    908 			http_error_response(req->owner,
    909 			    HTTP_STATUS_METHOD_NOT_ALLOWED);
    910 			return (KORE_RESULT_OK);
    911 		}
    912 
    913 		if (!http_request_header_uint64(req, "content-length",
    914 		    &req->content_length)) {
    915 			if (req->method == HTTP_METHOD_DELETE) {
    916 				req->flags |= HTTP_REQUEST_COMPLETE;
    917 				return (KORE_RESULT_OK);
    918 			}
    919 
    920 			req->flags |= HTTP_REQUEST_DELETE;
    921 			http_error_response(req->owner,
    922 			    HTTP_STATUS_LENGTH_REQUIRED);
    923 			return (KORE_RESULT_OK);
    924 		}
    925 
    926 		if (req->content_length == 0) {
    927 			c->http_timeout = 0;
    928 			req->flags |= HTTP_REQUEST_COMPLETE;
    929 			req->flags &= ~HTTP_REQUEST_EXPECT_BODY;
    930 			return (KORE_RESULT_OK);
    931 		}
    932 
    933 		if (((nb->s_off - len) > req->content_length) ||
    934 		    (req->content_length > http_body_max)) {
    935 			req->flags |= HTTP_REQUEST_DELETE;
    936 			http_error_response(req->owner,
    937 			    HTTP_STATUS_REQUEST_ENTITY_TOO_LARGE);
    938 			return (KORE_RESULT_OK);
    939 		}
    940 
    941 		req->http_body_length = req->content_length;
    942 
    943 		if (req->rt->on_body_chunk == NULL &&
    944 		    http_body_disk_offload > 0 &&
    945 		    req->content_length > http_body_disk_offload) {
    946 			req->http_body_path = kore_pool_get(&http_body_path);
    947 			l = snprintf(req->http_body_path, HTTP_BODY_PATH_MAX,
    948 			    "%s/http_body.XXXXXX", http_body_disk_path);
    949 			if (l == -1 || (size_t)l >= HTTP_BODY_PATH_MAX) {
    950 				req->flags |= HTTP_REQUEST_DELETE;
    951 				http_error_response(req->owner,
    952 				    HTTP_STATUS_INTERNAL_ERROR);
    953 				return (KORE_RESULT_ERROR);
    954 			}
    955 
    956 			req->http_body = NULL;
    957 			req->http_body_fd = mkstemp(req->http_body_path);
    958 			if (req->http_body_fd == -1) {
    959 				req->flags |= HTTP_REQUEST_DELETE;
    960 				http_error_response(req->owner,
    961 				    HTTP_STATUS_INTERNAL_ERROR);
    962 				return (KORE_RESULT_OK);
    963 			}
    964 		} else if (req->rt->on_body_chunk == NULL) {
    965 			req->http_body_fd = -1;
    966 			req->http_body = kore_buf_alloc(req->content_length);
    967 		}
    968 
    969 		SHA256Init(&req->hashctx);
    970 		c->http_timeout = http_body_timeout * 1000;
    971 
    972 		if (!http_body_update(req, end_headers, nb->s_off - len)) {
    973 			req->flags |= HTTP_REQUEST_DELETE;
    974 			http_error_response(req->owner,
    975 			    HTTP_STATUS_INTERNAL_ERROR);
    976 			return (KORE_RESULT_OK);
    977 		}
    978 	} else {
    979 		c->http_timeout = 0;
    980 	}
    981 
    982 	if (req->rt->on_headers != NULL) {
    983 		if (!kore_runtime_http_request(req->rt->on_headers, req)) {
    984 			req->flags |= HTTP_REQUEST_DELETE;
    985 			return (KORE_RESULT_OK);
    986 		}
    987 	}
    988 
    989 	return (KORE_RESULT_OK);
    990 }
    991 
    992 int
    993 http_argument_get(struct http_request *req, const char *name,
    994     void **out, void *nout, int type)
    995 {
    996 	struct http_arg		*q;
    997 
    998 	TAILQ_FOREACH(q, &(req->arguments), list) {
    999 		if (strcmp(q->name, name))
   1000 			continue;
   1001 
   1002 		if (http_data_convert(q->s_value, out, nout, type))
   1003 			return (KORE_RESULT_OK);
   1004 
   1005 		break;
   1006 	}
   1007 
   1008 	return (KORE_RESULT_ERROR);
   1009 }
   1010 
   1011 int
   1012 http_argument_urldecode(char *arg, int url)
   1013 {
   1014 	u_int8_t	v;
   1015 	int		err;
   1016 	size_t		len;
   1017 	char		*p, *in, h[5];
   1018 
   1019 	p = arg;
   1020 	in = arg;
   1021 	len = strlen(arg);
   1022 
   1023 	while (*p != '\0' && p < (arg + len)) {
   1024 		if (*p == '+')
   1025 			*p = ' ';
   1026 		if (*p != '%') {
   1027 			*in++ = *p++;
   1028 			continue;
   1029 		}
   1030 
   1031 		if ((p + 2) >= (arg + len))
   1032 			return (KORE_RESULT_ERROR);
   1033 
   1034 		if (!isxdigit((unsigned char)*(p + 1)) ||
   1035 		    !isxdigit((unsigned char)*(p + 2))) {
   1036 			*in++ = *p++;
   1037 			continue;
   1038 		}
   1039 
   1040 		h[0] = '0';
   1041 		h[1] = 'x';
   1042 		h[2] = *(p + 1);
   1043 		h[3] = *(p + 2);
   1044 		h[4] = '\0';
   1045 
   1046 		v = kore_strtonum(h, 16, 0x0, 0xff, &err);
   1047 		if (err != KORE_RESULT_OK)
   1048 			return (err);
   1049 
   1050 		if (url) {
   1051 			if (v <= 0x1f || v == 0x7f)
   1052 				return (KORE_RESULT_ERROR);
   1053 		} else {
   1054 			if ((v <= 0x1f || v == 0x7f) &&
   1055 			    (v != '\n' && v != '\r' && v != '\t'))
   1056 				return (KORE_RESULT_ERROR);
   1057 		}
   1058 
   1059 		*in++ = (char)v;
   1060 		p += 3;
   1061 	}
   1062 
   1063 	*in = '\0';
   1064 	return (KORE_RESULT_OK);
   1065 }
   1066 
   1067 struct http_file *
   1068 http_file_lookup(struct http_request *req, const char *name)
   1069 {
   1070 	struct http_file	*f;
   1071 
   1072 	TAILQ_FOREACH(f, &(req->files), list) {
   1073 		if (!strcmp(f->name, name))
   1074 			return (f);
   1075 	}
   1076 
   1077 	return (NULL);
   1078 }
   1079 
   1080 ssize_t
   1081 http_file_read(struct http_file *file, void *buf, size_t len)
   1082 {
   1083 	ssize_t		ret;
   1084 	size_t		toread, off;
   1085 
   1086 	if (file->length < file->offset)
   1087 		return (-1);
   1088 	if ((file->offset + len) < file->offset)
   1089 		return (-1);
   1090 	if ((file->position + file->offset) < file->position)
   1091 		return (-1);
   1092 
   1093 	off = file->position + file->offset;
   1094 	toread = MIN(len, (file->length - file->offset));
   1095 	if (toread == 0)
   1096 		return (0);
   1097 
   1098 	if (file->req->http_body_fd != -1) {
   1099 		if (lseek(file->req->http_body_fd, off, SEEK_SET) == -1) {
   1100 			kore_log(LOG_ERR, "http_file_read: lseek(%s): %s",
   1101 			    file->req->http_body_path, errno_s);
   1102 			return (-1);
   1103 		}
   1104 
   1105 		for (;;) {
   1106 			ret = read(file->req->http_body_fd, buf, toread);
   1107 			if (ret == -1) {
   1108 				if (errno == EINTR)
   1109 					continue;
   1110 				kore_log(LOG_ERR, "failed to read %s: %s",
   1111 				    file->req->http_body_path, errno_s);
   1112 				return (-1);
   1113 			}
   1114 			if (ret == 0)
   1115 				return (0);
   1116 			break;
   1117 		}
   1118 	} else if (file->req->http_body != NULL) {
   1119 		if (off > file->req->http_body->length)
   1120 			return (0);
   1121 		memcpy(buf, file->req->http_body->data + off, toread);
   1122 		ret = toread;
   1123 	} else {
   1124 		kore_log(LOG_ERR, "http_file_read: called without body");
   1125 		return (-1);
   1126 	}
   1127 
   1128 	file->offset += (size_t)ret;
   1129 	return (ret);
   1130 }
   1131 
   1132 void
   1133 http_file_rewind(struct http_file *file)
   1134 {
   1135 	file->offset = 0;
   1136 }
   1137 
   1138 void
   1139 http_response_cookie(struct http_request *req, const char *name,
   1140     const char *val, const char *path, time_t expires, u_int32_t maxage,
   1141     struct http_cookie **out)
   1142 {
   1143 	char			*p;
   1144 	struct http_cookie	*ck;
   1145 
   1146 	if (name == NULL || val == NULL)
   1147 		fatal("http_response_cookie: invalid parameters");
   1148 
   1149 	ck = kore_pool_get(&http_cookie_pool);
   1150 
   1151 	ck->maxage = maxage;
   1152 	ck->expires = expires;
   1153 	ck->name = kore_strdup(name);
   1154 	ck->value = kore_strdup(val);
   1155 	ck->domain = kore_strdup(req->host);
   1156 	ck->flags = HTTP_COOKIE_HTTPONLY | HTTP_COOKIE_SECURE;
   1157 
   1158 	if ((p = strrchr(ck->domain, ':')) != NULL)
   1159 		*p = '\0';
   1160 
   1161 	if (path != NULL)
   1162 		ck->path = kore_strdup(path);
   1163 	else
   1164 		ck->path = NULL;
   1165 
   1166 	TAILQ_INSERT_TAIL(&(req->resp_cookies), ck, list);
   1167 
   1168 	if (out != NULL)
   1169 		*out = ck;
   1170 }
   1171 
   1172 void
   1173 http_populate_cookies(struct http_request *req)
   1174 {
   1175 	struct http_cookie	*ck;
   1176 	const char		*hdr;
   1177 	int			 i, v, n;
   1178 	char			*c, *header, *pair[3];
   1179 	char			*cookies[HTTP_MAX_COOKIES];
   1180 
   1181 	if (!http_request_header(req, "cookie", &hdr))
   1182 		return;
   1183 
   1184 	header = kore_strdup(hdr);
   1185 	v = kore_split_string(header, ";", cookies, HTTP_MAX_COOKIES);
   1186 	for (i = 0; i < v; i++) {
   1187 		for (c = cookies[i]; isspace(*(unsigned char *)c); c++)
   1188 			;
   1189 
   1190 		n = kore_split_string(c, "=", pair, 3);
   1191 		if (n != 2)
   1192 			continue;
   1193 
   1194 		ck = kore_pool_get(&http_cookie_pool);
   1195 		ck->name = kore_strdup(pair[0]);
   1196 		ck->value = kore_strdup(pair[1]);
   1197 		TAILQ_INSERT_TAIL(&(req->req_cookies), ck, list);
   1198 	}
   1199 
   1200 	kore_free(header);
   1201 }
   1202 
   1203 void
   1204 http_populate_post(struct http_request *req)
   1205 {
   1206 	ssize_t			ret;
   1207 	int			i, v;
   1208 	struct kore_buf		*body;
   1209 	char			data[BUFSIZ];
   1210 	char			*args[HTTP_MAX_QUERY_ARGS], *val[3], *string;
   1211 
   1212 	if (req->method != HTTP_METHOD_POST)
   1213 		return;
   1214 
   1215 	if (req->http_body != NULL) {
   1216 		body = NULL;
   1217 		req->http_body->offset = req->content_length;
   1218 		string = kore_buf_stringify(req->http_body, NULL);
   1219 		req->http_body_length = 0;
   1220 		req->http_body_offset = 0;
   1221 	} else {
   1222 		body = kore_buf_alloc(128);
   1223 		for (;;) {
   1224 			ret = http_body_read(req, data, sizeof(data));
   1225 			if (ret == -1)
   1226 				goto out;
   1227 			if (ret == 0)
   1228 				break;
   1229 			kore_buf_append(body, data, ret);
   1230 		}
   1231 		string = kore_buf_stringify(body, NULL);
   1232 	}
   1233 
   1234 	v = kore_split_string(string, "&", args, HTTP_MAX_QUERY_ARGS);
   1235 	for (i = 0; i < v; i++) {
   1236 		kore_split_string(args[i], "=", val, 3);
   1237 		if (val[0] != NULL && val[1] != NULL)
   1238 			http_argument_add(req, val[0], val[1], 0, 1);
   1239 	}
   1240 
   1241 out:
   1242 	if (body != NULL)
   1243 		kore_buf_free(body);
   1244 }
   1245 
   1246 void
   1247 http_populate_qs(struct http_request *req)
   1248 {
   1249 	int		i, v;
   1250 	char		*query, *args[HTTP_MAX_QUERY_ARGS], *val[3];
   1251 
   1252 	if (req->query_string == NULL)
   1253 		return;
   1254 
   1255 	query = kore_strdup(req->query_string);
   1256 	v = kore_split_string(query, "&", args, HTTP_MAX_QUERY_ARGS);
   1257 	for (i = 0; i < v; i++) {
   1258 		kore_split_string(args[i], "=", val, 3);
   1259 		if (val[0] != NULL && val[1] != NULL)
   1260 			http_argument_add(req, val[0], val[1], 1, 1);
   1261 	}
   1262 
   1263 	kore_free(query);
   1264 }
   1265 
   1266 void
   1267 http_populate_multipart_form(struct http_request *req)
   1268 {
   1269 	const char		*hdr;
   1270 	int			h, blen;
   1271 	struct kore_buf		in, out;
   1272 	char			*type, *val, *args[3];
   1273 	char			boundary[HTTP_BOUNDARY_MAX];
   1274 
   1275 	if (req->method != HTTP_METHOD_POST)
   1276 		return;
   1277 
   1278 	if (!http_request_header(req, "content-type", &hdr))
   1279 		return;
   1280 
   1281 	kore_buf_init(&in, 128);
   1282 	kore_buf_init(&out, 128);
   1283 
   1284 	type = kore_strdup(hdr);
   1285 	h = kore_split_string(type, ";", args, 3);
   1286 	if (h != 2)
   1287 		goto cleanup;
   1288 
   1289 	if (strcasecmp(args[0], "multipart/form-data"))
   1290 		goto cleanup;
   1291 
   1292 	if ((val = strchr(args[1], '=')) == NULL)
   1293 		goto cleanup;
   1294 
   1295 	val++;
   1296 	blen = snprintf(boundary, sizeof(boundary), "--%s", val);
   1297 	if (blen == -1 || (size_t)blen >= sizeof(boundary))
   1298 		goto cleanup;
   1299 
   1300 	if (!multipart_find_data(&in, NULL, NULL, req, boundary, blen))
   1301 		goto cleanup;
   1302 
   1303 	for (;;) {
   1304 		if (!multipart_find_data(&in, NULL, NULL, req, "\r\n", 2))
   1305 			break;
   1306 		if (in.offset < 4 && req->http_body_length == 0)
   1307 			break;
   1308 		if (!multipart_find_data(&in, &out, NULL, req, "\r\n\r\n", 4))
   1309 			break;
   1310 		if (!multipart_parse_headers(req, &in, &out, boundary, blen))
   1311 			break;
   1312 
   1313 		kore_buf_reset(&out);
   1314 	}
   1315 
   1316 cleanup:
   1317 	kore_free(type);
   1318 	kore_buf_cleanup(&in);
   1319 	kore_buf_cleanup(&out);
   1320 }
   1321 
   1322 int
   1323 http_body_rewind(struct http_request *req)
   1324 {
   1325 	if (req->http_body_fd != -1) {
   1326 		if (lseek(req->http_body_fd, 0, SEEK_SET) == -1) {
   1327 			kore_log(LOG_ERR, "lseek(%s) failed: %s",
   1328 			    req->http_body_path, errno_s);
   1329 			return (KORE_RESULT_ERROR);
   1330 		}
   1331 	} else if (req->http_body != NULL) {
   1332 		kore_buf_reset(req->http_body);
   1333 	}
   1334 
   1335 	req->http_body_offset = 0;
   1336 	req->http_body_length = req->content_length;
   1337 
   1338 	return (KORE_RESULT_OK);
   1339 }
   1340 
   1341 int
   1342 http_body_digest(struct http_request *req, char *out, size_t len)
   1343 {
   1344 	size_t		idx;
   1345 	int		slen;
   1346 
   1347 	if (len != HTTP_BODY_DIGEST_STRLEN) {
   1348 		fatal("http_body_digest: bad len:%zu wanted:%u",
   1349 		    len, HTTP_BODY_DIGEST_STRLEN);
   1350 	}
   1351 
   1352 	if (!(req->flags & HTTP_REQUEST_COMPLETE))
   1353 		return (KORE_RESULT_ERROR);
   1354 
   1355 	for (idx = 0; idx < sizeof(req->http_body_digest); idx++) {
   1356 		slen = snprintf(out + (idx * 2), len - (idx * 2), "%02x",
   1357 		    req->http_body_digest[idx]);
   1358 		if (slen == -1 || (size_t)slen >= len)
   1359 			fatal("failed to create hex string");
   1360 	}
   1361 
   1362 	return (KORE_RESULT_OK);
   1363 }
   1364 
   1365 ssize_t
   1366 http_body_read(struct http_request *req, void *out, size_t len)
   1367 {
   1368 	ssize_t		ret;
   1369 	size_t		toread;
   1370 
   1371 	toread = MIN(req->http_body_length, len);
   1372 	if (toread == 0)
   1373 		return (0);
   1374 
   1375 	if (req->http_body_fd != -1) {
   1376 		for (;;) {
   1377 			ret = read(req->http_body_fd, out, toread);
   1378 			if (ret == -1) {
   1379 				if (errno == EINTR)
   1380 					continue;
   1381 				kore_log(LOG_ERR, "failed to read %s: %s",
   1382 				    req->http_body_path, errno_s);
   1383 				return (-1);
   1384 			}
   1385 			if (ret == 0)
   1386 				return (0);
   1387 			break;
   1388 		}
   1389 	} else if (req->http_body != NULL) {
   1390 		memcpy(out,
   1391 		    (req->http_body->data + req->http_body->offset), toread);
   1392 		req->http_body->offset += toread;
   1393 		ret = toread;
   1394 	} else {
   1395 		kore_log(LOG_ERR, "http_body_read: called without body");
   1396 		return (-1);
   1397 	}
   1398 
   1399 	req->http_body_length -= (size_t)ret;
   1400 	req->http_body_offset += (size_t)ret;
   1401 
   1402 	return (ret);
   1403 }
   1404 
   1405 int
   1406 http_state_run(struct http_state *states, u_int8_t elm,
   1407     struct http_request *req)
   1408 {
   1409 	int		r, done;
   1410 
   1411 	done = 0;
   1412 
   1413 	while (!done) {
   1414 		if (req->fsm_state >= elm) {
   1415 			fatal("http_state_run: fsm_state > elm (%d/%d)",
   1416 			    req->fsm_state, elm);
   1417 		}
   1418 
   1419 		r = states[req->fsm_state].cb(req);
   1420 		switch (r) {
   1421 		case HTTP_STATE_ERROR:
   1422 			return (KORE_RESULT_OK);
   1423 		case HTTP_STATE_RETRY:
   1424 			return (KORE_RESULT_RETRY);
   1425 		case HTTP_STATE_CONTINUE:
   1426 			break;
   1427 		case HTTP_STATE_COMPLETE:
   1428 			done = 1;
   1429 			break;
   1430 		default:
   1431 			fatal("http_state_run: unknown return value %d", r);
   1432 		}
   1433 	}
   1434 
   1435 	req->fsm_state = 0;
   1436 
   1437 	return (KORE_RESULT_OK);
   1438 }
   1439 
   1440 int
   1441 http_state_exists(struct http_request *req)
   1442 {
   1443 	return (req->hdlr_extra != NULL);
   1444 }
   1445 
   1446 void *
   1447 http_state_create(struct http_request *req, size_t len)
   1448 {
   1449 	if (req->hdlr_extra != NULL)
   1450 		fatal("http_state_create: state already exists");
   1451 
   1452 	req->state_len = len;
   1453 	req->hdlr_extra = kore_calloc(1, len);
   1454 
   1455 	return (req->hdlr_extra);
   1456 }
   1457 
   1458 void *
   1459 http_state_get(struct http_request *req)
   1460 {
   1461 	return (req->hdlr_extra);
   1462 }
   1463 
   1464 void
   1465 http_state_cleanup(struct http_request *req)
   1466 {
   1467 	kore_free(req->hdlr_extra);
   1468 	req->hdlr_extra = NULL;
   1469 }
   1470 
   1471 void
   1472 http_start_recv(struct connection *c)
   1473 {
   1474 	c->http_start = kore_time_ms();
   1475 	c->http_timeout = http_header_timeout * 1000;
   1476 	net_recv_reset(c, http_header_max, http_header_recv);
   1477 }
   1478 
   1479 void
   1480 http_runlock_init(struct http_runlock *lock)
   1481 {
   1482 	lock->owner = NULL;
   1483 	LIST_INIT(&lock->queue);
   1484 }
   1485 
   1486 int
   1487 http_runlock_acquire(struct http_runlock *lock, struct http_request *req)
   1488 {
   1489 	if (lock->owner != NULL) {
   1490 		if (req->runlock != NULL)
   1491 			fatal("%s: request already waiting on lock", __func__);
   1492 
   1493 		req->runlock = kore_pool_get(&http_rlq_pool);
   1494 		req->runlock->req = req;
   1495 		LIST_INSERT_HEAD(&lock->queue, req->runlock, list);
   1496 
   1497 		http_request_sleep(req);
   1498 		return (KORE_RESULT_ERROR);
   1499 	}
   1500 
   1501 	lock->owner = req;
   1502 
   1503 	return (KORE_RESULT_OK);
   1504 }
   1505 
   1506 void
   1507 http_runlock_release(struct http_runlock *lock, struct http_request *req)
   1508 {
   1509 	struct http_runlock_queue	*next;
   1510 	struct http_request		*nextreq;
   1511 
   1512 	if (lock->owner != req)
   1513 		fatal("%s: calling request != owner of runlock", __func__);
   1514 
   1515 	lock->owner = NULL;
   1516 
   1517 	if ((next = LIST_FIRST(&lock->queue)) != NULL) {
   1518 		LIST_REMOVE(next, list);
   1519 
   1520 		nextreq = next->req;
   1521 		nextreq->runlock = NULL;
   1522 
   1523 		http_request_wakeup(nextreq);
   1524 		kore_pool_put(&http_rlq_pool, next);
   1525 	}
   1526 }
   1527 
   1528 int
   1529 http_redirect_add(struct kore_domain *dom, const char *path, int status,
   1530     const char *target)
   1531 {
   1532 	struct http_redirect	*rdr;
   1533 
   1534 	rdr = kore_calloc(1, sizeof(*rdr));
   1535 
   1536 	if (regcomp(&(rdr->rctx), path, REG_EXTENDED)) {
   1537 		kore_free(rdr);
   1538 		return (KORE_RESULT_ERROR);
   1539 	}
   1540 
   1541 	rdr->status = status;
   1542 
   1543 	if (target != NULL)
   1544 		rdr->target = kore_strdup(target);
   1545 	else
   1546 		rdr->target = NULL;
   1547 
   1548 	TAILQ_INSERT_TAIL(&dom->redirects, rdr, list);
   1549 
   1550 	return (KORE_RESULT_OK);
   1551 }
   1552 
   1553 const char *
   1554 http_status_text(int status)
   1555 {
   1556 	const char	*r;
   1557 
   1558 	switch (status) {
   1559 	case HTTP_STATUS_CONTINUE:
   1560 		r = "Continue";
   1561 		break;
   1562 	case HTTP_STATUS_SWITCHING_PROTOCOLS:
   1563 		r = "Switching Protocols";
   1564 		break;
   1565 	case HTTP_STATUS_OK:
   1566 		r = "OK";
   1567 		break;
   1568 	case HTTP_STATUS_CREATED:
   1569 		r = "Created";
   1570 		break;
   1571 	case HTTP_STATUS_ACCEPTED:
   1572 		r = "Accepted";
   1573 		break;
   1574 	case HTTP_STATUS_NON_AUTHORITATIVE:
   1575 		r = "Non-Authoritative Information";
   1576 		break;
   1577 	case HTTP_STATUS_NO_CONTENT:
   1578 		r = "No Content";
   1579 		break;
   1580 	case HTTP_STATUS_RESET_CONTENT:
   1581 		r = "Reset Content";
   1582 		break;
   1583 	case HTTP_STATUS_PARTIAL_CONTENT:
   1584 		r = "Partial Content";
   1585 		break;
   1586 	case HTTP_STATUS_MULTIPLE_CHOICES:
   1587 		r = "Multiple Choices";
   1588 		break;
   1589 	case HTTP_STATUS_MOVED_PERMANENTLY:
   1590 		r = "Moved Permanently";
   1591 		break;
   1592 	case HTTP_STATUS_FOUND:
   1593 		r = "Found";
   1594 		break;
   1595 	case HTTP_STATUS_SEE_OTHER:
   1596 		r = "See Other";
   1597 		break;
   1598 	case HTTP_STATUS_NOT_MODIFIED:
   1599 		r = "Not Modified";
   1600 		break;
   1601 	case HTTP_STATUS_USE_PROXY:
   1602 		r = "Use Proxy";
   1603 		break;
   1604 	case HTTP_STATUS_TEMPORARY_REDIRECT:
   1605 		r = "Temporary Redirect";
   1606 		break;
   1607 	case HTTP_STATUS_BAD_REQUEST:
   1608 		r = "Bad Request";
   1609 		break;
   1610 	case HTTP_STATUS_UNAUTHORIZED:
   1611 		r = "Unauthorized";
   1612 		break;
   1613 	case HTTP_STATUS_PAYMENT_REQUIRED:
   1614 		r = "Payment Required";
   1615 		break;
   1616 	case HTTP_STATUS_FORBIDDEN:
   1617 		r = "Forbidden";
   1618 		break;
   1619 	case HTTP_STATUS_NOT_FOUND:
   1620 		r = "Not Found";
   1621 		break;
   1622 	case HTTP_STATUS_METHOD_NOT_ALLOWED:
   1623 		r = "Method Not Allowed";
   1624 		break;
   1625 	case HTTP_STATUS_NOT_ACCEPTABLE:
   1626 		r = "Not Acceptable";
   1627 		break;
   1628 	case HTTP_STATUS_PROXY_AUTH_REQUIRED:
   1629 		r = "Proxy Authentication Required";
   1630 		break;
   1631 	case HTTP_STATUS_REQUEST_TIMEOUT:
   1632 		r = "Request Time-out";
   1633 		break;
   1634 	case HTTP_STATUS_CONFLICT:
   1635 		r = "Conflict";
   1636 		break;
   1637 	case HTTP_STATUS_GONE:
   1638 		r = "Gone";
   1639 		break;
   1640 	case HTTP_STATUS_LENGTH_REQUIRED:
   1641 		r = "Length Required";
   1642 		break;
   1643 	case HTTP_STATUS_PRECONDITION_FAILED:
   1644 		r = "Precondition Failed";
   1645 		break;
   1646 	case HTTP_STATUS_REQUEST_ENTITY_TOO_LARGE:
   1647 		r = "Request Entity Too Large";
   1648 		break;
   1649 	case HTTP_STATUS_REQUEST_URI_TOO_LARGE:
   1650 		r = "Request-URI Too Large";
   1651 		break;
   1652 	case HTTP_STATUS_UNSUPPORTED_MEDIA_TYPE:
   1653 		r = "Unsupported Media Type";
   1654 		break;
   1655 	case HTTP_STATUS_REQUEST_RANGE_INVALID:
   1656 		r = "Requested range not satisfiable";
   1657 		break;
   1658 	case HTTP_STATUS_EXPECTATION_FAILED:
   1659 		r = "Expectation Failed";
   1660 		break;
   1661 	case HTTP_STATUS_MISDIRECTED_REQUEST:
   1662 		r = "Misdirected Request";
   1663 		break;
   1664 	case HTTP_STATUS_INTERNAL_ERROR:
   1665 		r = "Internal Server Error";
   1666 		break;
   1667 	case HTTP_STATUS_NOT_IMPLEMENTED:
   1668 		r = "Not Implemented";
   1669 		break;
   1670 	case HTTP_STATUS_BAD_GATEWAY:
   1671 		r = "Bad Gateway";
   1672 		break;
   1673 	case HTTP_STATUS_SERVICE_UNAVAILABLE:
   1674 		r = "Service Unavailable";
   1675 		break;
   1676 	case HTTP_STATUS_GATEWAY_TIMEOUT:
   1677 		r = "Gateway Time-out";
   1678 		break;
   1679 	case HTTP_STATUS_BAD_VERSION:
   1680 		r = "HTTP Version not supported";
   1681 		break;
   1682 	default:
   1683 		r = "";
   1684 		break;
   1685 	}
   1686 
   1687 	return (r);
   1688 }
   1689 
   1690 const char *
   1691 http_method_text(int method)
   1692 {
   1693 	char		*r;
   1694 
   1695 	switch(method) {
   1696 	case HTTP_METHOD_GET:
   1697 		r = "GET";
   1698 		break;
   1699 	case HTTP_METHOD_POST:
   1700 		r = "POST";
   1701 		break;
   1702 	case HTTP_METHOD_PUT:
   1703 		r = "PUT";
   1704 		break;
   1705 	case HTTP_METHOD_DELETE:
   1706 		r = "DELETE";
   1707 		break;
   1708 	case HTTP_METHOD_HEAD:
   1709 		r = "HEAD";
   1710 		break;
   1711 	case HTTP_METHOD_OPTIONS:
   1712 		r = "OPTIONS";
   1713 		break;
   1714 	case HTTP_METHOD_PATCH:
   1715 		r = "PATCH";
   1716 		break;
   1717 	default:
   1718 		r = "";
   1719 		break;
   1720 	}
   1721 
   1722 	return (r);
   1723 }
   1724 
   1725 int
   1726 http_method_value(const char *method)
   1727 {
   1728 	if (!strcasecmp(method, "GET"))
   1729 		return (HTTP_METHOD_GET);
   1730 
   1731 	if (!strcasecmp(method, "POST"))
   1732 		return (HTTP_METHOD_POST);
   1733 
   1734 	if (!strcasecmp(method, "PUT"))
   1735 		return (HTTP_METHOD_PUT);
   1736 
   1737 	if (!strcasecmp(method, "DELETE"))
   1738 		return (HTTP_METHOD_DELETE);
   1739 
   1740 	if (!strcasecmp(method, "HEAD"))
   1741 		return (HTTP_METHOD_HEAD);
   1742 
   1743 	if (!strcasecmp(method, "OPTIONS"))
   1744 		return (HTTP_METHOD_OPTIONS);
   1745 
   1746 	if (!strcasecmp(method, "PATCH"))
   1747 		return (HTTP_METHOD_PATCH);
   1748 
   1749 	return (0);
   1750 }
   1751 
   1752 int
   1753 http_media_register(const char *ext, const char *type)
   1754 {
   1755 	struct http_media_type	*media;
   1756 
   1757 	LIST_FOREACH(media, &http_media_types, list) {
   1758 		if (!strcasecmp(media->ext, ext))
   1759 			return (KORE_RESULT_ERROR);
   1760 	}
   1761 
   1762 	media = kore_calloc(1, sizeof(*media));
   1763 	media->ext = kore_strdup(ext);
   1764 	media->type = kore_strdup(type);
   1765 
   1766 	LIST_INSERT_HEAD(&http_media_types, media, list);
   1767 
   1768 	return (KORE_RESULT_OK);
   1769 }
   1770 
   1771 const char *
   1772 http_media_type(const char *path)
   1773 {
   1774 	const char		*p;
   1775 	struct http_media_type	*media;
   1776 
   1777 	if ((p = strrchr(path, '.')) == NULL)
   1778 		return (NULL);
   1779 
   1780 	p++;
   1781 	if (*p == '\0')
   1782 		return (NULL);
   1783 
   1784 	LIST_FOREACH(media, &http_media_types, list) {
   1785 		if (!strcasecmp(media->ext, p))
   1786 			return (media->type);
   1787 	}
   1788 
   1789 	return (NULL);
   1790 }
   1791 
   1792 char *
   1793 http_validate_header(char *header)
   1794 {
   1795 	u_int8_t	idx;
   1796 	char		*p, *value;
   1797 
   1798 	for (p = header; *p != '\0'; p++) {
   1799 		idx = *p;
   1800 		if (idx > HTTP_MAP_LIMIT)
   1801 			return (NULL);
   1802 
   1803 		if (*p == ':') {
   1804 			*(p)++ = '\0';
   1805 			break;
   1806 		}
   1807 
   1808 		if (*p >= 'A' && *p <= 'Z')
   1809 			*p += 32;
   1810 
   1811 		if (http_token[idx] == 0x00)
   1812 			return (NULL);
   1813 	}
   1814 
   1815 	while (isspace(*(unsigned char *)p))
   1816 		p++;
   1817 
   1818 	if (*p == '\0')
   1819 		return (NULL);
   1820 
   1821 	value = p;
   1822 	while (*p != '\0') {
   1823 		idx = *p;
   1824 		if (idx > HTTP_MAP_LIMIT)
   1825 			return (NULL);
   1826 		if (http_field_content[idx] == 0x00)
   1827 			return (NULL);
   1828 		p++;
   1829 	}
   1830 
   1831 	return (value);
   1832 }
   1833 
   1834 static int
   1835 http_release_buffer(struct netbuf *nb)
   1836 {
   1837 	kore_buf_free(nb->extra);
   1838 
   1839 	return (KORE_RESULT_OK);
   1840 }
   1841 
   1842 static int
   1843 http_check_redirect(struct http_request *req, struct kore_domain *dom)
   1844 {
   1845 	int			idx;
   1846 	struct http_redirect	*rdr;
   1847 	const char		*uri;
   1848 	char			key[4];
   1849 	struct kore_buf		location;
   1850 
   1851 	TAILQ_FOREACH(rdr, &dom->redirects, list) {
   1852 		if (!regexec(&(rdr->rctx), req->path,
   1853 		    HTTP_CAPTURE_GROUPS, req->cgroups, 0))
   1854 			break;
   1855 	}
   1856 
   1857 	if (rdr == NULL)
   1858 		return (KORE_RESULT_ERROR);
   1859 
   1860 	uri = NULL;
   1861 	kore_buf_init(&location, 128);
   1862 
   1863 	if (rdr->target) {
   1864 		kore_buf_appendf(&location, "%s", rdr->target);
   1865 
   1866 		if (req->query_string != NULL) {
   1867 			kore_buf_replace_string(&location, "$qs",
   1868 			    req->query_string, strlen(req->query_string));
   1869 		}
   1870 
   1871 		/* Starts at 1 to skip the full path. */
   1872 		for (idx = 1; idx < HTTP_CAPTURE_GROUPS - 1; idx++) {
   1873 			if (req->cgroups[idx].rm_so == -1 ||
   1874 			    req->cgroups[idx].rm_eo == -1)
   1875 				break;
   1876 
   1877 			(void)snprintf(key, sizeof(key), "$%d", idx);
   1878 
   1879 			kore_buf_replace_string(&location, key,
   1880 			    req->path + req->cgroups[idx].rm_so,
   1881 			    req->cgroups[idx].rm_eo - req->cgroups[idx].rm_so);
   1882 		}
   1883 
   1884 		uri = kore_buf_stringify(&location, NULL);
   1885 	}
   1886 
   1887 	if (uri)
   1888 		http_response_header(req, "location", uri);
   1889 
   1890 	http_response(req, rdr->status, NULL, 0);
   1891 	kore_buf_cleanup(&location);
   1892 
   1893 	if (dom->accesslog)
   1894 		kore_accesslog(req);
   1895 
   1896 	return (KORE_RESULT_OK);
   1897 }
   1898 
   1899 static struct http_request *
   1900 http_request_new(struct connection *c, const char *host,
   1901     const char *method, char *path, const char *version)
   1902 {
   1903 	struct kore_domain		*dom;
   1904 	struct http_request		*req;
   1905 	size_t				qsoff;
   1906 	char				*p, *hp;
   1907 	int				m, flags, exists;
   1908 
   1909 	if (http_request_count >= http_request_limit) {
   1910 		http_error_response(c, HTTP_STATUS_SERVICE_UNAVAILABLE);
   1911 		return (NULL);
   1912 	}
   1913 
   1914 	if (strlen(host) >= KORE_DOMAINNAME_LEN - 1) {
   1915 		http_error_response(c, HTTP_STATUS_BAD_REQUEST);
   1916 		return (NULL);
   1917 	}
   1918 
   1919 	if (strlen(path) >= HTTP_URI_LEN - 1) {
   1920 		http_error_response(c, HTTP_STATUS_REQUEST_URI_TOO_LARGE);
   1921 		return (NULL);
   1922 	}
   1923 
   1924 	if (strcasecmp(version, "http/1.1")) {
   1925 		if (strcasecmp(version, "http/1.0")) {
   1926 			http_error_response(c, HTTP_STATUS_BAD_VERSION);
   1927 			return (NULL);
   1928 		}
   1929 
   1930 		flags = HTTP_VERSION_1_0;
   1931 	} else {
   1932 		flags = HTTP_VERSION_1_1;
   1933 	}
   1934 
   1935 	if ((p = strchr(path, '?')) != NULL) {
   1936 		qsoff = p - path;
   1937 	} else {
   1938 		qsoff = 0;
   1939 	}
   1940 
   1941 	hp = NULL;
   1942 
   1943 	switch (c->family) {
   1944 	case AF_INET6:
   1945 		if (*host == '[') {
   1946 			if ((hp = strrchr(host, ']')) == NULL) {
   1947 				http_error_response(c, HTTP_STATUS_BAD_REQUEST);
   1948 				return (NULL);
   1949 			}
   1950 			hp++;
   1951 			if (*hp == ':')
   1952 				*hp = '\0';
   1953 			else
   1954 				hp = NULL;
   1955 		}
   1956 		break;
   1957 	default:
   1958 		if ((hp = strrchr(host, ':')) != NULL)
   1959 			*hp = '\0';
   1960 		break;
   1961 	}
   1962 
   1963 	if (c->owner->server->tls && c->tls_sni != NULL) {
   1964 		if (strcasecmp(c->tls_sni, host)) {
   1965 			http_error_response(c, HTTP_STATUS_MISDIRECTED_REQUEST);
   1966 			return (NULL);
   1967 		}
   1968 	}
   1969 
   1970 	if ((dom = kore_domain_lookup(c->owner->server, host)) == NULL) {
   1971 		http_error_response(c, HTTP_STATUS_NOT_FOUND);
   1972 		return (NULL);
   1973 	}
   1974 
   1975 	if (dom->cafile != NULL && c->tls_cert == NULL) {
   1976 		http_error_response(c, HTTP_STATUS_FORBIDDEN);
   1977 		return (NULL);
   1978 	}
   1979 
   1980 	if (hp != NULL)
   1981 		*hp = ':';
   1982 
   1983 	if (!strcasecmp(method, "get")) {
   1984 		m = HTTP_METHOD_GET;
   1985 		flags |= HTTP_REQUEST_COMPLETE;
   1986 	} else if (!strcasecmp(method, "delete")) {
   1987 		m = HTTP_METHOD_DELETE;
   1988 		flags |= HTTP_REQUEST_EXPECT_BODY;
   1989 	} else if (!strcasecmp(method, "post")) {
   1990 		m = HTTP_METHOD_POST;
   1991 		flags |= HTTP_REQUEST_EXPECT_BODY;
   1992 	} else if (!strcasecmp(method, "put")) {
   1993 		m = HTTP_METHOD_PUT;
   1994 		flags |= HTTP_REQUEST_EXPECT_BODY;
   1995 	} else if (!strcasecmp(method, "head")) {
   1996 		m = HTTP_METHOD_HEAD;
   1997 		flags |= HTTP_REQUEST_COMPLETE;
   1998 	} else if (!strcasecmp(method, "options")) {
   1999 		m = HTTP_METHOD_OPTIONS;
   2000 		flags |= HTTP_REQUEST_COMPLETE;
   2001 	} else if (!strcasecmp(method, "patch")) {
   2002 		m = HTTP_METHOD_PATCH;
   2003 		flags |= HTTP_REQUEST_EXPECT_BODY;
   2004 	} else {
   2005 		http_error_response(c, HTTP_STATUS_BAD_REQUEST);
   2006 		return (NULL);
   2007 	}
   2008 
   2009 	if (flags & HTTP_VERSION_1_0) {
   2010 		if (m != HTTP_METHOD_GET && m != HTTP_METHOD_POST &&
   2011 		    m != HTTP_METHOD_HEAD) {
   2012 			http_error_response(c, HTTP_STATUS_METHOD_NOT_ALLOWED);
   2013 			return (NULL);
   2014 		}
   2015 	}
   2016 
   2017 	req = kore_pool_get(&http_request_pool);
   2018 
   2019 	req->end = 0;
   2020 	req->total = 0;
   2021 	req->start = 0;
   2022 	req->owner = c;
   2023 	req->status = 0;
   2024 	req->method = m;
   2025 	req->agent = NULL;
   2026 	req->referer = NULL;
   2027 	req->runlock = NULL;
   2028 	req->flags = flags;
   2029 	req->fsm_state = 0;
   2030 	req->http_body = NULL;
   2031 	req->http_body_fd = -1;
   2032 	req->hdlr_extra = NULL;
   2033 	req->content_length = 0;
   2034 	req->query_string = NULL;
   2035 	req->http_body_length = 0;
   2036 	req->http_body_offset = 0;
   2037 	req->http_body_path = NULL;
   2038 
   2039 	req->host = host;
   2040 	req->path = path;
   2041 
   2042 #if defined(KORE_USE_PYTHON)
   2043 	req->py_req = NULL;
   2044 	req->py_coro = NULL;
   2045 	req->py_rqnext = NULL;
   2046 	req->py_validator = NULL;
   2047 #endif
   2048 
   2049 	if (qsoff > 0) {
   2050 		req->query_string = path + qsoff;
   2051 		*(req->query_string)++ = '\0';
   2052 	} else {
   2053 		req->query_string = NULL;
   2054 	}
   2055 
   2056 	/* Checked further down below if we need to 404. */
   2057 	exists = kore_route_lookup(req, dom, m, &req->rt);
   2058 
   2059 	TAILQ_INIT(&(req->resp_headers));
   2060 	TAILQ_INIT(&(req->req_headers));
   2061 	TAILQ_INIT(&(req->resp_cookies));
   2062 	TAILQ_INIT(&(req->req_cookies));
   2063 	TAILQ_INIT(&(req->arguments));
   2064 	TAILQ_INIT(&(req->files));
   2065 
   2066 #if defined(KORE_USE_TASKS)
   2067 	LIST_INIT(&(req->tasks));
   2068 #endif
   2069 
   2070 #if defined(KORE_USE_PGSQL)
   2071 	LIST_INIT(&(req->pgsqls));
   2072 #endif
   2073 
   2074 	http_request_count++;
   2075 	TAILQ_INSERT_HEAD(&http_requests, req, list);
   2076 	TAILQ_INSERT_TAIL(&(c->http_requests), req, olist);
   2077 
   2078 	if (http_check_redirect(req, dom)) {
   2079 		http_request_free(req);
   2080 		return (NULL);
   2081 	}
   2082 
   2083 	if (exists == 0) {
   2084 		http_request_free(req);
   2085 		http_error_response(c, HTTP_STATUS_NOT_FOUND);
   2086 		return (NULL);
   2087 	}
   2088 
   2089 	if (req->rt == NULL) {
   2090 		http_request_free(req);
   2091 		http_error_response(c, HTTP_STATUS_METHOD_NOT_ALLOWED);
   2092 		return (NULL);
   2093 	}
   2094 
   2095 	return (req);
   2096 }
   2097 
   2098 static int
   2099 multipart_find_data(struct kore_buf *in, struct kore_buf *out,
   2100     size_t *olen, struct http_request *req, const void *needle, size_t len)
   2101 {
   2102 	ssize_t			ret;
   2103 	size_t			left;
   2104 	u_int8_t		*p, first, data[4096];
   2105 
   2106 	if (olen != NULL)
   2107 		*olen = 0;
   2108 
   2109 	first = *(const u_int8_t *)needle;
   2110 	for (;;) {
   2111 		if (in->offset < len) {
   2112 			ret = http_body_read(req, data, sizeof(data));
   2113 			if (ret == -1)
   2114 				return (KORE_RESULT_ERROR);
   2115 			if (ret == 0)
   2116 				return (KORE_RESULT_ERROR);
   2117 
   2118 			kore_buf_append(in, data, ret);
   2119 			continue;
   2120 		}
   2121 
   2122 		p = kore_mem_find(in->data, in->offset, &first, 1);
   2123 		if (p == NULL) {
   2124 			if (out != NULL)
   2125 				kore_buf_append(out, in->data, in->offset);
   2126 			if (olen != NULL)
   2127 				*olen += in->offset;
   2128 			kore_buf_reset(in);
   2129 			continue;
   2130 		}
   2131 
   2132 		left = in->offset - (p - in->data);
   2133 		if (left < len) {
   2134 			if (out != NULL)
   2135 				kore_buf_append(out, in->data, (p - in->data));
   2136 			if (olen != NULL)
   2137 				*olen += (p - in->data);
   2138 			memmove(in->data, p, left);
   2139 			in->offset = left;
   2140 			continue;
   2141 		}
   2142 
   2143 		if (!memcmp(p, needle, len)) {
   2144 			if (out != NULL)
   2145 				kore_buf_append(out, in->data, p - in->data);
   2146 			if (olen != NULL)
   2147 				*olen += (p - in->data);
   2148 
   2149 			in->offset = left - len;
   2150 			if (in->offset > 0)
   2151 				memmove(in->data, p + len, in->offset);
   2152 			return (KORE_RESULT_OK);
   2153 		}
   2154 
   2155 		if (out != NULL)
   2156 			kore_buf_append(out, in->data, (p - in->data) + 1);
   2157 		if (olen != NULL)
   2158 			*olen += (p - in->data) + 1;
   2159 
   2160 		in->offset = left - 1;
   2161 		if (in->offset > 0)
   2162 			memmove(in->data, p + 1, in->offset);
   2163 	}
   2164 
   2165 	return (KORE_RESULT_ERROR);
   2166 }
   2167 
   2168 static int
   2169 multipart_parse_headers(struct http_request *req, struct kore_buf *in,
   2170     struct kore_buf *hbuf, const char *boundary, const int blen)
   2171 {
   2172 	int		h, c, i;
   2173 	char		*headers[5], *args[5], *opt[5];
   2174 	char		*d, *val, *name, *fname, *string;
   2175 
   2176 	string = kore_buf_stringify(hbuf, NULL);
   2177 	h = kore_split_string(string, "\r\n", headers, 5);
   2178 	for (i = 0; i < h; i++) {
   2179 		c = kore_split_string(headers[i], ":", args, 5);
   2180 		if (c != 2)
   2181 			continue;
   2182 
   2183 		/* Ignore other headers for now. */
   2184 		if (strcasecmp(args[0], "content-disposition"))
   2185 			continue;
   2186 
   2187 		for (d = args[1]; isspace(*(unsigned char *)d); d++)
   2188 			;
   2189 
   2190 		c = kore_split_string(d, ";", opt, 5);
   2191 		if (c < 2)
   2192 			continue;
   2193 
   2194 		if (strcasecmp(opt[0], "form-data"))
   2195 			continue;
   2196 
   2197 		if ((val = strchr(opt[1], '=')) == NULL)
   2198 			continue;
   2199 		if (strlen(val) < 3)
   2200 			continue;
   2201 
   2202 		val++;
   2203 		kore_strip_chars(val, '"', &name);
   2204 
   2205 		if (opt[2] == NULL) {
   2206 			multipart_add_field(req, in, name, boundary, blen);
   2207 			kore_free(name);
   2208 			continue;
   2209 		}
   2210 
   2211 		for (d = opt[2]; isspace(*(unsigned char *)d); d++)
   2212 			;
   2213 
   2214 		if (!strncasecmp(d, "filename=", 9)) {
   2215 			if ((val = strchr(d, '=')) == NULL) {
   2216 				kore_free(name);
   2217 				continue;
   2218 			}
   2219 
   2220 			val++;
   2221 			kore_strip_chars(val, '"', &fname);
   2222 			if (strlen(fname) > 0) {
   2223 				multipart_file_add(req,
   2224 				    in, name, fname, boundary, blen);
   2225 			}
   2226 			kore_free(fname);
   2227 		}
   2228 
   2229 		kore_free(name);
   2230 	}
   2231 
   2232 	return (KORE_RESULT_OK);
   2233 }
   2234 
   2235 static void
   2236 multipart_add_field(struct http_request *req, struct kore_buf *in,
   2237     char *name, const char *boundary, const int blen)
   2238 {
   2239 	struct kore_buf		*data;
   2240 	char			*string;
   2241 
   2242 	data = kore_buf_alloc(128);
   2243 
   2244 	if (!multipart_find_data(in, data, NULL, req, boundary, blen)) {
   2245 		kore_buf_free(data);
   2246 		return;
   2247 	}
   2248 
   2249 	if (data->offset < 3) {
   2250 		kore_buf_free(data);
   2251 		return;
   2252 	}
   2253 
   2254 	data->offset -= 2;
   2255 	string = kore_buf_stringify(data, NULL);
   2256 	http_argument_add(req, name, string, 0, 0);
   2257 	kore_buf_free(data);
   2258 }
   2259 
   2260 static void
   2261 multipart_file_add(struct http_request *req, struct kore_buf *in,
   2262     const char *name, const char *fname, const char *boundary, const int blen)
   2263 {
   2264 	struct http_file	*f;
   2265 	size_t			position, len;
   2266 
   2267 	position = req->http_body_offset - in->offset;
   2268 	if (!multipart_find_data(in, NULL, &len, req, boundary, blen))
   2269 		return;
   2270 
   2271 	if (len < 3)
   2272 		return;
   2273 	len -= 2;
   2274 
   2275 	f = kore_malloc(sizeof(struct http_file));
   2276 	f->req = req;
   2277 	f->offset = 0;
   2278 	f->length = len;
   2279 	f->position = position;
   2280 	f->name = kore_strdup(name);
   2281 	f->filename = kore_strdup(fname);
   2282 
   2283 	TAILQ_INSERT_TAIL(&(req->files), f, list);
   2284 }
   2285 
   2286 static void
   2287 http_argument_add(struct http_request *req, char *name, char *value, int qs,
   2288     int decode)
   2289 {
   2290 	struct http_arg			*q;
   2291 	struct kore_route_params	*p;
   2292 
   2293 	if (decode) {
   2294 		if (!http_argument_urldecode(name, qs))
   2295 			return;
   2296 	}
   2297 
   2298 	TAILQ_FOREACH(p, &req->rt->params, list) {
   2299 		if (qs == 1 && !(p->flags & KORE_PARAMS_QUERY_STRING))
   2300 			continue;
   2301 		if (qs == 0 && (p->flags & KORE_PARAMS_QUERY_STRING))
   2302 			continue;
   2303 
   2304 		if (p->method != req->method)
   2305 			continue;
   2306 
   2307 		if (strcmp(p->name, name))
   2308 			continue;
   2309 
   2310 		if (decode) {
   2311 			if (!http_argument_urldecode(value, qs))
   2312 				return;
   2313 		}
   2314 
   2315 		if (!kore_validator_check(req, p->validator, value))
   2316 			break;
   2317 
   2318 		q = kore_malloc(sizeof(struct http_arg));
   2319 		q->name = kore_strdup(name);
   2320 		q->s_value = kore_strdup(value);
   2321 		TAILQ_INSERT_TAIL(&(req->arguments), q, list);
   2322 		break;
   2323 	}
   2324 }
   2325 
   2326 static int
   2327 http_body_recv(struct netbuf *nb)
   2328 {
   2329 	struct http_request	*req = (struct http_request *)nb->extra;
   2330 
   2331 	return (http_body_update(req, nb->buf, nb->s_off));
   2332 }
   2333 
   2334 static int
   2335 http_body_update(struct http_request *req, const void *data, size_t len)
   2336 {
   2337 	ssize_t			ret;
   2338 	u_int64_t		bytes_left;
   2339 
   2340 	SHA256Update(&req->hashctx, data, len);
   2341 
   2342 	if (req->rt->on_body_chunk != NULL) {
   2343 		if (kore_runtime_http_body_chunk(req->rt->on_body_chunk,
   2344 		    req, data, len) != KORE_RESULT_OK) {
   2345 			req->flags |= HTTP_REQUEST_DELETE;
   2346 			http_error_response(req->owner,
   2347 			    HTTP_STATUS_INTERNAL_ERROR);
   2348 			return (KORE_RESULT_ERROR);
   2349 		}
   2350 	} else if (req->http_body_fd != -1) {
   2351 		ret = write(req->http_body_fd, data, len);
   2352 		if (ret == -1 || (size_t)ret != len) {
   2353 			req->flags |= HTTP_REQUEST_DELETE;
   2354 			http_error_response(req->owner,
   2355 			    HTTP_STATUS_INTERNAL_ERROR);
   2356 			return (KORE_RESULT_ERROR);
   2357 		}
   2358 	} else if (req->http_body != NULL) {
   2359 		kore_buf_append(req->http_body, data, len);
   2360 	} else {
   2361 		req->flags |= HTTP_REQUEST_DELETE;
   2362 		http_error_response(req->owner,
   2363 		    HTTP_STATUS_INTERNAL_ERROR);
   2364 		return (KORE_RESULT_ERROR);
   2365 	}
   2366 
   2367 	req->content_length -= len;
   2368 
   2369 	if (req->content_length == 0) {
   2370 		req->owner->http_timeout = 0;
   2371 		req->owner->rnb->extra = NULL;
   2372 		http_request_wakeup(req);
   2373 		req->flags |= HTTP_REQUEST_COMPLETE;
   2374 		req->flags &= ~HTTP_REQUEST_EXPECT_BODY;
   2375 		req->content_length = req->http_body_length;
   2376 		if (!http_body_rewind(req)) {
   2377 			req->flags |= HTTP_REQUEST_DELETE;
   2378 			http_error_response(req->owner,
   2379 			    HTTP_STATUS_INTERNAL_ERROR);
   2380 			return (KORE_RESULT_ERROR);
   2381 		}
   2382 		SHA256Final(req->http_body_digest, &req->hashctx);
   2383 	} else {
   2384 		bytes_left = req->content_length;
   2385 		net_recv_reset(req->owner,
   2386 		    MIN(bytes_left, NETBUF_SEND_PAYLOAD_MAX),
   2387 		    http_body_recv);
   2388 		req->owner->rnb->extra = req;
   2389 	}
   2390 
   2391 	return (KORE_RESULT_OK);
   2392 }
   2393 
   2394 static void
   2395 http_error_response(struct connection *c, int status)
   2396 {
   2397 	c->flags |= CONN_CLOSE_EMPTY;
   2398 
   2399 	switch (c->proto) {
   2400 	case CONN_PROTO_HTTP:
   2401 		http_response_normal(NULL, c, status, NULL, 0);
   2402 		break;
   2403 	default:
   2404 		fatal("http_error_response() bad proto %d", c->proto);
   2405 		/* NOTREACHED. */
   2406 	}
   2407 
   2408 	if (!net_send_flush(c))
   2409 		kore_connection_disconnect(c);
   2410 }
   2411 
   2412 static void
   2413 http_response_normal(struct http_request *req, struct connection *c,
   2414     int status, const void *d, size_t len)
   2415 {
   2416 	struct kore_buf		buf;
   2417 	struct http_cookie	*ck;
   2418 	struct http_header	*hdr;
   2419 	char			version;
   2420 	const char		*conn, *text;
   2421 	int			connection_close, send_body;
   2422 
   2423 	send_body = 1;
   2424 	text = http_status_text(status);
   2425 
   2426 	kore_buf_reset(header_buf);
   2427 
   2428 	if (req != NULL) {
   2429 		if (req->flags & HTTP_VERSION_1_0)
   2430 			version = '0';
   2431 		else
   2432 			version = '1';
   2433 	} else {
   2434 		version = '1';
   2435 	}
   2436 
   2437 	kore_buf_appendf(header_buf, "HTTP/1.%c %d %s\r\n",
   2438 	    version, status, text);
   2439 
   2440 	if (status == 100) {
   2441 		kore_buf_append(header_buf, "\r\n", 2);
   2442 		net_send_queue(c, header_buf->data, header_buf->offset);
   2443 		return;
   2444 	}
   2445 
   2446 	kore_buf_append(header_buf, http_version, http_version_len);
   2447 
   2448 	if ((c->flags & CONN_CLOSE_EMPTY) ||
   2449 	    (req != NULL && (req->flags & HTTP_VERSION_1_0))) {
   2450 		connection_close = 1;
   2451 	} else {
   2452 		connection_close = 0;
   2453 	}
   2454 
   2455 	if (connection_close == 0 && req != NULL) {
   2456 		if (http_request_header(req, "connection", &conn)) {
   2457 			if ((*conn == 'c' || *conn == 'C') &&
   2458 			    !strcasecmp(conn, "close")) {
   2459 				connection_close = 1;
   2460 			}
   2461 		}
   2462 	}
   2463 
   2464 	kore_buf_init(&buf, 1024);
   2465 
   2466 	/* Note that req CAN be NULL. */
   2467 	if (req == NULL || req->owner->proto != CONN_PROTO_WEBSOCKET) {
   2468 		if (http_keepalive_time && connection_close == 0) {
   2469 			kore_buf_appendf(header_buf,
   2470 			    "connection: keep-alive\r\n");
   2471 			kore_buf_appendf(header_buf,
   2472 			    "keep-alive: timeout=%d\r\n", http_keepalive_time);
   2473 		} else {
   2474 			c->flags |= CONN_CLOSE_EMPTY;
   2475 			kore_buf_appendf(header_buf, "connection: close\r\n");
   2476 		}
   2477 	}
   2478 
   2479 	if (c->tls && http_hsts_enable) {
   2480 		kore_buf_appendf(header_buf, "strict-transport-security: ");
   2481 		kore_buf_appendf(header_buf,
   2482 		    "max-age=%" PRIu64 "; includeSubDomains\r\n",
   2483 		    http_hsts_enable);
   2484 	}
   2485 
   2486 	if (http_pretty_error && d == NULL && status >= 400) {
   2487 		kore_buf_appendf(&buf, pretty_error_fmt,
   2488 		    status, text, status, text);
   2489 
   2490 		d = buf.data;
   2491 		len = buf.offset;
   2492 	}
   2493 
   2494 	if (req != NULL) {
   2495 		TAILQ_FOREACH(ck, &(req->resp_cookies), list)
   2496 			http_write_response_cookie(ck);
   2497 
   2498 		TAILQ_FOREACH(hdr, &(req->resp_headers), list) {
   2499 			kore_buf_appendf(header_buf, "%s: %s\r\n",
   2500 			    hdr->header, hdr->value);
   2501 		}
   2502 
   2503 		TAILQ_FOREACH(hdr, &(req->rt->dom->headers), list) {
   2504 			kore_buf_appendf(header_buf, "%s: %s\r\n",
   2505 			    hdr->header, hdr->value);
   2506 		}
   2507 
   2508 		if (status != 204 && status >= 200 &&
   2509 		    !(req->flags & HTTP_REQUEST_NO_CONTENT_LENGTH)) {
   2510 			kore_buf_appendf(header_buf,
   2511 			    "content-length: %zu\r\n", len);
   2512 		}
   2513 	} else {
   2514 		if (status != 204 && status >= 200) {
   2515 			kore_buf_appendf(header_buf,
   2516 			    "content-length: %zu\r\n", len);
   2517 		}
   2518 	}
   2519 
   2520 	kore_buf_append(header_buf, "\r\n", 2);
   2521 	net_send_queue(c, header_buf->data, header_buf->offset);
   2522 
   2523 	if (req != NULL && req->method == HTTP_METHOD_HEAD)
   2524 		send_body = 0;
   2525 
   2526 	if (d != NULL && send_body)
   2527 		net_send_queue(c, d, len);
   2528 
   2529 	if (!(c->flags & CONN_CLOSE_EMPTY) && !(c->flags & CONN_IS_BUSY))
   2530 		http_start_recv(c);
   2531 
   2532 	if (req != NULL)
   2533 		req->content_length = len;
   2534 
   2535 	kore_buf_cleanup(&buf);
   2536 }
   2537 
   2538 static void
   2539 http_write_response_cookie(struct http_cookie *ck)
   2540 {
   2541 	struct tm		tm;
   2542 	char			expires[HTTP_DATE_MAXSIZE];
   2543 
   2544 	kore_buf_reset(ckhdr_buf);
   2545 	kore_buf_appendf(ckhdr_buf, "%s=%s", ck->name, ck->value);
   2546 
   2547 	if (ck->path != NULL)
   2548 		kore_buf_appendf(ckhdr_buf, "; Path=%s", ck->path);
   2549 	if (ck->domain != NULL)
   2550 		kore_buf_appendf(ckhdr_buf, "; Domain=%s", ck->domain);
   2551 
   2552 	if (ck->expires > 0) {
   2553 		if (gmtime_r(&ck->expires, &tm) == NULL) {
   2554 			kore_log(LOG_ERR, "gmtime_r(): %s", errno_s);
   2555 			return;
   2556 		}
   2557 
   2558 		if (strftime(expires, sizeof(expires),
   2559 		    "%a, %d %b %y %H:%M:%S GMT", &tm) == 0) {
   2560 			kore_log(LOG_ERR, "strftime(): %s", errno_s);
   2561 			return;
   2562 		}
   2563 
   2564 		kore_buf_appendf(ckhdr_buf, "; Expires=%s", expires);
   2565 	}
   2566 
   2567 	if (ck->maxage > 0)
   2568 		kore_buf_appendf(ckhdr_buf, "; Max-Age=%u", ck->maxage);
   2569 
   2570 	if (ck->flags & HTTP_COOKIE_HTTPONLY)
   2571 		kore_buf_appendf(ckhdr_buf, "; HttpOnly");
   2572 	if (ck->flags & HTTP_COOKIE_SECURE)
   2573 		kore_buf_appendf(ckhdr_buf, "; Secure");
   2574 
   2575 	kore_buf_appendf(header_buf, "set-cookie: %s\r\n",
   2576 	    kore_buf_stringify(ckhdr_buf, NULL));
   2577 }
   2578 
   2579 static int
   2580 http_data_convert(void *data, void **out, void *nout, int type)
   2581 {
   2582 	switch (type) {
   2583 	case HTTP_ARG_TYPE_RAW:
   2584 	case HTTP_ARG_TYPE_STRING:
   2585 		*out = data;
   2586 		return (KORE_RESULT_OK);
   2587 	case HTTP_ARG_TYPE_BYTE:
   2588 		COPY_ARG_TYPE(*(u_int8_t *)data, u_int8_t);
   2589 		return (KORE_RESULT_OK);
   2590 	case HTTP_ARG_TYPE_INT16:
   2591 		COPY_AS_INTTYPE(SHRT_MIN, SHRT_MAX, int16_t);
   2592 		return (KORE_RESULT_OK);
   2593 	case HTTP_ARG_TYPE_UINT16:
   2594 		COPY_AS_INTTYPE(0, USHRT_MAX, u_int16_t);
   2595 		return (KORE_RESULT_OK);
   2596 	case HTTP_ARG_TYPE_INT32:
   2597 		COPY_AS_INTTYPE(INT_MIN, INT_MAX, int32_t);
   2598 		return (KORE_RESULT_OK);
   2599 	case HTTP_ARG_TYPE_UINT32:
   2600 		COPY_AS_INTTYPE(0, UINT_MAX, u_int32_t);
   2601 		return (KORE_RESULT_OK);
   2602 	case HTTP_ARG_TYPE_INT64:
   2603 		COPY_AS_INTTYPE_64(int64_t, 1);
   2604 		return (KORE_RESULT_OK);
   2605 	case HTTP_ARG_TYPE_UINT64:
   2606 		COPY_AS_INTTYPE_64(u_int64_t, 0);
   2607 		return (KORE_RESULT_OK);
   2608 	case HTTP_ARG_TYPE_FLOAT:
   2609 		COPY_ARG_DOUBLE(-FLT_MAX, FLT_MAX, float);
   2610 		return (KORE_RESULT_OK);
   2611 	case HTTP_ARG_TYPE_DOUBLE:
   2612 		COPY_ARG_DOUBLE(-DBL_MAX, DBL_MAX, double);
   2613 		return (KORE_RESULT_OK);
   2614 	default:
   2615 		break;
   2616 	}
   2617 
   2618 	return (KORE_RESULT_ERROR);
   2619 }