kore

An easy to use, scalable and secure web application framework for writing web APIs in C.
Commits | Files | Refs | README | LICENSE | git clone https://git.kore.io/kore.git

http.c (60150B)



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