Home | History | Annotate | Line # | Download | only in netmgr
      1 /*	$NetBSD: http.c,v 1.8 2026/05/20 16:53:47 christos Exp $	*/
      2 
      3 /*
      4  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
      5  *
      6  * SPDX-License-Identifier: MPL-2.0
      7  *
      8  * This Source Code Form is subject to the terms of the Mozilla Public
      9  * License, v. 2.0. If a copy of the MPL was not distributed with this
     10  * file, you can obtain one at https://mozilla.org/MPL/2.0/.
     11  *
     12  * See the COPYRIGHT file distributed with this work for additional
     13  * information regarding copyright ownership.
     14  */
     15 
     16 #include <ctype.h>
     17 #include <inttypes.h>
     18 #include <limits.h>
     19 #include <nghttp2/nghttp2.h>
     20 #include <signal.h>
     21 #include <string.h>
     22 
     23 #include <isc/async.h>
     24 #include <isc/base64.h>
     25 #include <isc/log.h>
     26 #include <isc/netmgr.h>
     27 #include <isc/sockaddr.h>
     28 #include <isc/tls.h>
     29 #include <isc/url.h>
     30 #include <isc/util.h>
     31 
     32 #include "netmgr-int.h"
     33 
     34 #define AUTHEXTRA 7
     35 
     36 #define MAX_DNS_MESSAGE_SIZE (UINT16_MAX)
     37 
     38 #define DNS_MEDIA_TYPE "application/dns-message"
     39 
     40 /*
     41  * See https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control
     42  * for additional details. Basically it means "avoid caching by any
     43  * means."
     44  */
     45 #define DEFAULT_CACHE_CONTROL "no-cache, no-store, must-revalidate"
     46 
     47 /*
     48  * If server during request processing surpasses any of the limits
     49  * below, it will just reset the stream without returning any error
     50  * codes in a response.  Ideally, these parameters should be
     51  * configurable both globally and per every HTTP endpoint description
     52  * in the configuration file, but for now it should be enough.
     53  */
     54 
     55 /*
     56  * 128K should be enough to encode 64K of data into base64url inside GET
     57  * request and have extra space for other headers
     58  */
     59 #define MAX_ALLOWED_DATA_IN_HEADERS (MAX_DNS_MESSAGE_SIZE * 2)
     60 
     61 #define MAX_ALLOWED_DATA_IN_POST \
     62 	(MAX_DNS_MESSAGE_SIZE + MAX_DNS_MESSAGE_SIZE / 2)
     63 
     64 #define HEADER_MATCH(header, name, namelen)   \
     65 	(((namelen) == sizeof(header) - 1) && \
     66 	 (strncasecmp((header), (const char *)(name), (namelen)) == 0))
     67 
     68 #define MIN_SUCCESSFUL_HTTP_STATUS (200)
     69 #define MAX_SUCCESSFUL_HTTP_STATUS (299)
     70 
     71 /* This definition sets the upper limit of pending write buffer to an
     72  * adequate enough value. That is done mostly to fight a limitation
     73  * for a max TLS record size in flamethrower (2K).  In a perfect world
     74  * this constant should not be required, if we ever move closer to
     75  * that state, the constant, and corresponding code, should be
     76  * removed. For now the limit seems adequate enough to fight
     77  * "tinygrams" problem. */
     78 #define FLUSH_HTTP_WRITE_BUFFER_AFTER (1536)
     79 
     80 /* This switch is here mostly to test the code interoperability with
     81  * buggy implementations */
     82 #define ENABLE_HTTP_WRITE_BUFFERING 1
     83 
     84 #define SUCCESSFUL_HTTP_STATUS(code)             \
     85 	((code) >= MIN_SUCCESSFUL_HTTP_STATUS && \
     86 	 (code) <= MAX_SUCCESSFUL_HTTP_STATUS)
     87 
     88 #define INITIAL_DNS_MESSAGE_BUFFER_SIZE (512)
     89 
     90 /*
     91  * The value should be small enough to not allow a server to open too
     92  * many streams at once. It should not be too small either because
     93  * the incoming data will be split into too many chunks with each of
     94  * them processed asynchronously.
     95  */
     96 #define INCOMING_DATA_CHUNK_SIZE (256)
     97 
     98 /*
     99  * Often processing a chunk does not change the number of streams. In
    100  * that case we can process more than once, but we still should have a
    101  * hard limit on that.
    102  */
    103 #define INCOMING_DATA_MAX_CHUNKS_AT_ONCE (4)
    104 
    105 /*
    106  * These constants define the grace period to help detect flooding clients.
    107  *
    108  * The first one defines how much data can be processed before opening
    109  * a first stream and received at least some useful (=DNS) data.
    110  *
    111  * The second one defines how much data from a client we read before
    112  * trying to drop a clients who sends not enough useful data.
    113  *
    114  * The third constant defines how many streams we agree to process
    115  * before checking if there was at least one DNS request received.
    116  */
    117 #define INCOMING_DATA_INITIAL_STREAM_SIZE (1536)
    118 #define INCOMING_DATA_GRACE_SIZE	  (MAX_ALLOWED_DATA_IN_HEADERS)
    119 #define MAX_STREAMS_BEFORE_FIRST_REQUEST  (50)
    120 
    121 typedef struct isc_nm_http_response_status {
    122 	size_t code;
    123 	size_t content_length;
    124 	bool content_type_valid;
    125 } isc_nm_http_response_status_t;
    126 
    127 typedef struct http_cstream {
    128 	isc_nm_recv_cb_t read_cb;
    129 	void *read_cbarg;
    130 	isc_nm_cb_t connect_cb;
    131 	void *connect_cbarg;
    132 
    133 	bool sending;
    134 	bool reading;
    135 
    136 	char *uri;
    137 	isc_url_parser_t up;
    138 
    139 	char *authority;
    140 	size_t authoritylen;
    141 	char *path;
    142 
    143 	isc_buffer_t *rbuf;
    144 
    145 	size_t pathlen;
    146 	int32_t stream_id;
    147 
    148 	bool post; /* POST or GET */
    149 	isc_buffer_t *postdata;
    150 	char *GET_path;
    151 	size_t GET_path_len;
    152 
    153 	isc_nm_http_response_status_t response_status;
    154 	isc_nmsocket_t *httpsock;
    155 	LINK(struct http_cstream) link;
    156 } http_cstream_t;
    157 
    158 #define HTTP2_SESSION_MAGIC    ISC_MAGIC('H', '2', 'S', 'S')
    159 #define VALID_HTTP2_SESSION(t) ISC_MAGIC_VALID(t, HTTP2_SESSION_MAGIC)
    160 
    161 typedef ISC_LIST(isc__nm_uvreq_t) isc__nm_http_pending_callbacks_t;
    162 
    163 struct isc_nm_http_session {
    164 	unsigned int magic;
    165 	isc_refcount_t references;
    166 	isc_mem_t *mctx;
    167 
    168 	size_t sending;
    169 	bool reading;
    170 	bool closed;
    171 	bool closing;
    172 
    173 	nghttp2_session *ngsession;
    174 	bool client;
    175 
    176 	ISC_LIST(http_cstream_t) cstreams;
    177 	ISC_LIST(isc_nmsocket_h2_t) sstreams;
    178 	size_t nsstreams;
    179 	uint64_t total_opened_sstreams;
    180 
    181 	isc_nmhandle_t *handle;
    182 	isc_nmhandle_t *client_httphandle;
    183 	isc_nmsocket_t *serversocket;
    184 
    185 	isc_buffer_t *buf;
    186 
    187 	isc_tlsctx_t *tlsctx;
    188 	uint32_t max_concurrent_streams;
    189 
    190 	isc__nm_http_pending_callbacks_t pending_write_callbacks;
    191 	isc_buffer_t *pending_write_data;
    192 
    193 	size_t data_in_flight;
    194 
    195 	bool async_queued;
    196 
    197 	/*
    198 	 * The statistical values below are for usage on server-side
    199 	 * only. They are meant to detect clients that are taking too many
    200 	 * resources from the server.
    201 	 */
    202 	uint64_t received;  /* How many requests have been received. */
    203 	uint64_t submitted; /* How many responses were submitted to send */
    204 	uint64_t processed; /* How many responses were processed. */
    205 
    206 	uint64_t processed_incoming_data;
    207 	uint64_t processed_useful_data; /* DNS data */
    208 };
    209 
    210 typedef enum isc_http_error_responses {
    211 	ISC_HTTP_ERROR_SUCCESS,		       /* 200 */
    212 	ISC_HTTP_ERROR_NOT_FOUND,	       /* 404 */
    213 	ISC_HTTP_ERROR_PAYLOAD_TOO_LARGE,      /* 413 */
    214 	ISC_HTTP_ERROR_URI_TOO_LONG,	       /* 414 */
    215 	ISC_HTTP_ERROR_UNSUPPORTED_MEDIA_TYPE, /* 415 */
    216 	ISC_HTTP_ERROR_BAD_REQUEST,	       /* 400 */
    217 	ISC_HTTP_ERROR_NOT_IMPLEMENTED,	       /* 501 */
    218 	ISC_HTTP_ERROR_GENERIC,		       /* 500 Internal Server Error */
    219 	ISC_HTTP_ERROR_MAX
    220 } isc_http_error_responses_t;
    221 
    222 typedef struct isc_http_send_req {
    223 	isc_nm_http_session_t *session;
    224 	isc_nmhandle_t *transphandle;
    225 	isc_nmhandle_t *httphandle;
    226 	isc_nm_cb_t cb;
    227 	void *cbarg;
    228 	isc_buffer_t *pending_write_data;
    229 	isc__nm_http_pending_callbacks_t pending_write_callbacks;
    230 	uint64_t submitted;
    231 } isc_http_send_req_t;
    232 
    233 #define HTTP_ENDPOINTS_MAGIC	ISC_MAGIC('H', 'T', 'E', 'P')
    234 #define VALID_HTTP_ENDPOINTS(t) ISC_MAGIC_VALID(t, HTTP_ENDPOINTS_MAGIC)
    235 
    236 #define HTTP_HANDLER_MAGIC    ISC_MAGIC('H', 'T', 'H', 'L')
    237 #define VALID_HTTP_HANDLER(t) ISC_MAGIC_VALID(t, HTTP_HANDLER_MAGIC)
    238 
    239 static void
    240 http_send_outgoing(isc_nm_http_session_t *session, isc_nmhandle_t *httphandle,
    241 		   isc_nm_cb_t cb, void *cbarg);
    242 
    243 static void
    244 http_log_flooding_peer(isc_nm_http_session_t *session);
    245 
    246 static bool
    247 http_is_flooding_peer(isc_nm_http_session_t *session);
    248 
    249 static ssize_t
    250 http_process_input_data(isc_nm_http_session_t *session,
    251 			isc_buffer_t *input_data);
    252 
    253 static inline bool
    254 http_too_many_active_streams(isc_nm_http_session_t *session);
    255 
    256 static void
    257 http_do_bio(isc_nm_http_session_t *session, isc_nmhandle_t *send_httphandle,
    258 	    isc_nm_cb_t send_cb, void *send_cbarg);
    259 
    260 static void
    261 http_do_bio_async(isc_nm_http_session_t *session);
    262 
    263 static void
    264 failed_httpstream_read_cb(isc_nmsocket_t *sock, isc_result_t result,
    265 			  isc_nm_http_session_t *session);
    266 
    267 static void
    268 client_call_failed_read_cb(isc_result_t result, isc_nm_http_session_t *session);
    269 
    270 static void
    271 server_call_failed_read_cb(isc_result_t result, isc_nm_http_session_t *session);
    272 
    273 static void
    274 failed_read_cb(isc_result_t result, isc_nm_http_session_t *session);
    275 
    276 static isc_result_t
    277 server_send_error_response(const isc_http_error_responses_t error,
    278 			   nghttp2_session *ngsession, isc_nmsocket_t *socket);
    279 
    280 static isc_result_t
    281 client_send(isc_nmhandle_t *handle, const isc_region_t *region);
    282 
    283 static void
    284 finish_http_session(isc_nm_http_session_t *session);
    285 
    286 static void
    287 http_transpost_tcp_nodelay(isc_nmhandle_t *transphandle);
    288 
    289 static void
    290 call_pending_callbacks(isc__nm_http_pending_callbacks_t pending_callbacks,
    291 		       isc_result_t result);
    292 
    293 static void
    294 server_call_cb(isc_nmsocket_t *socket, const isc_result_t result,
    295 	       isc_region_t *data);
    296 
    297 static isc_nm_httphandler_t *
    298 http_endpoints_find(const char *request_path,
    299 		    const isc_nm_http_endpoints_t *restrict eps);
    300 
    301 static void
    302 http_init_listener_endpoints(isc_nmsocket_t *listener,
    303 			     isc_nm_http_endpoints_t *epset);
    304 
    305 static void
    306 http_cleanup_listener_endpoints(isc_nmsocket_t *listener);
    307 
    308 static isc_nm_http_endpoints_t *
    309 http_get_listener_endpoints(isc_nmsocket_t *listener, const int tid);
    310 
    311 static void
    312 http_initsocket(isc_nmsocket_t *sock);
    313 
    314 static bool
    315 http_session_active(isc_nm_http_session_t *session) {
    316 	REQUIRE(VALID_HTTP2_SESSION(session));
    317 	return !session->closed && !session->closing;
    318 }
    319 
    320 static void *
    321 http_malloc(size_t sz, isc_mem_t *mctx) {
    322 	return isc_mem_allocate(mctx, sz);
    323 }
    324 
    325 static void *
    326 http_calloc(size_t n, size_t sz, isc_mem_t *mctx) {
    327 	return isc_mem_callocate(mctx, n, sz);
    328 }
    329 
    330 static void *
    331 http_realloc(void *p, size_t newsz, isc_mem_t *mctx) {
    332 	return isc_mem_reallocate(mctx, p, newsz);
    333 }
    334 
    335 static void
    336 http_free(void *p, isc_mem_t *mctx) {
    337 	if (p == NULL) { /* as standard free() behaves */
    338 		return;
    339 	}
    340 	isc_mem_free(mctx, p);
    341 }
    342 
    343 static void
    344 init_nghttp2_mem(isc_mem_t *mctx, nghttp2_mem *mem) {
    345 	*mem = (nghttp2_mem){ .malloc = (nghttp2_malloc)http_malloc,
    346 			      .calloc = (nghttp2_calloc)http_calloc,
    347 			      .realloc = (nghttp2_realloc)http_realloc,
    348 			      .free = (nghttp2_free)http_free,
    349 			      .mem_user_data = mctx };
    350 }
    351 
    352 static void
    353 new_session(isc_mem_t *mctx, isc_tlsctx_t *tctx,
    354 	    isc_nm_http_session_t **sessionp) {
    355 	isc_nm_http_session_t *session = NULL;
    356 
    357 	REQUIRE(sessionp != NULL && *sessionp == NULL);
    358 	REQUIRE(mctx != NULL);
    359 
    360 	session = isc_mem_get(mctx, sizeof(isc_nm_http_session_t));
    361 	*session = (isc_nm_http_session_t){ .magic = HTTP2_SESSION_MAGIC,
    362 					    .tlsctx = tctx };
    363 	isc_refcount_init(&session->references, 1);
    364 	isc_mem_attach(mctx, &session->mctx);
    365 	ISC_LIST_INIT(session->cstreams);
    366 	ISC_LIST_INIT(session->sstreams);
    367 	ISC_LIST_INIT(session->pending_write_callbacks);
    368 
    369 	*sessionp = session;
    370 }
    371 
    372 void
    373 isc__nm_httpsession_attach(isc_nm_http_session_t *source,
    374 			   isc_nm_http_session_t **targetp) {
    375 	REQUIRE(VALID_HTTP2_SESSION(source));
    376 	REQUIRE(targetp != NULL && *targetp == NULL);
    377 
    378 	isc_refcount_increment(&source->references);
    379 
    380 	*targetp = source;
    381 }
    382 
    383 void
    384 isc__nm_httpsession_detach(isc_nm_http_session_t **sessionp) {
    385 	isc_nm_http_session_t *session = NULL;
    386 
    387 	REQUIRE(sessionp != NULL);
    388 
    389 	session = *sessionp;
    390 	*sessionp = NULL;
    391 
    392 	REQUIRE(VALID_HTTP2_SESSION(session));
    393 
    394 	if (isc_refcount_decrement(&session->references) > 1) {
    395 		return;
    396 	}
    397 
    398 	finish_http_session(session);
    399 
    400 	INSIST(ISC_LIST_EMPTY(session->sstreams));
    401 	INSIST(ISC_LIST_EMPTY(session->cstreams));
    402 
    403 	if (session->ngsession != NULL) {
    404 		nghttp2_session_del(session->ngsession);
    405 		session->ngsession = NULL;
    406 	}
    407 
    408 	if (session->buf != NULL) {
    409 		isc_buffer_free(&session->buf);
    410 	}
    411 
    412 	/* We need an acquire memory barrier here */
    413 	(void)isc_refcount_current(&session->references);
    414 
    415 	session->magic = 0;
    416 	isc_mem_putanddetach(&session->mctx, session,
    417 			     sizeof(isc_nm_http_session_t));
    418 }
    419 
    420 isc_nmhandle_t *
    421 isc__nm_httpsession_handle(isc_nm_http_session_t *session) {
    422 	REQUIRE(VALID_HTTP2_SESSION(session));
    423 
    424 	return session->handle;
    425 }
    426 
    427 static http_cstream_t *
    428 find_http_cstream(int32_t stream_id, isc_nm_http_session_t *session) {
    429 	http_cstream_t *cstream = NULL;
    430 	REQUIRE(VALID_HTTP2_SESSION(session));
    431 
    432 	if (ISC_LIST_EMPTY(session->cstreams)) {
    433 		return NULL;
    434 	}
    435 
    436 	for (cstream = ISC_LIST_HEAD(session->cstreams); cstream != NULL;
    437 	     cstream = ISC_LIST_NEXT(cstream, link))
    438 	{
    439 		if (cstream->stream_id == stream_id) {
    440 			break;
    441 		}
    442 	}
    443 
    444 	/* LRU-like behaviour */
    445 	if (cstream && ISC_LIST_HEAD(session->cstreams) != cstream) {
    446 		ISC_LIST_UNLINK(session->cstreams, cstream, link);
    447 		ISC_LIST_PREPEND(session->cstreams, cstream, link);
    448 	}
    449 
    450 	return cstream;
    451 }
    452 
    453 static isc_result_t
    454 new_http_cstream(isc_nmsocket_t *sock, http_cstream_t **streamp) {
    455 	isc_mem_t *mctx = sock->worker->mctx;
    456 	const char *uri = NULL;
    457 	bool post;
    458 	http_cstream_t *stream = NULL;
    459 	isc_result_t result;
    460 
    461 	uri = sock->h2->session->handle->sock->h2->connect.uri;
    462 	post = sock->h2->session->handle->sock->h2->connect.post;
    463 
    464 	stream = isc_mem_get(mctx, sizeof(http_cstream_t));
    465 	*stream = (http_cstream_t){ .stream_id = -1,
    466 				    .post = post,
    467 				    .uri = isc_mem_strdup(mctx, uri) };
    468 	ISC_LINK_INIT(stream, link);
    469 
    470 	result = isc_url_parse(stream->uri, strlen(stream->uri), 0,
    471 			       &stream->up);
    472 	if (result != ISC_R_SUCCESS) {
    473 		isc_mem_free(mctx, stream->uri);
    474 		isc_mem_put(mctx, stream, sizeof(http_cstream_t));
    475 		return result;
    476 	}
    477 
    478 	isc__nmsocket_attach(sock, &stream->httpsock);
    479 	stream->authoritylen = stream->up.field_data[ISC_UF_HOST].len;
    480 	stream->authority = isc_mem_get(mctx, stream->authoritylen + AUTHEXTRA);
    481 	memmove(stream->authority, &uri[stream->up.field_data[ISC_UF_HOST].off],
    482 		stream->up.field_data[ISC_UF_HOST].len);
    483 
    484 	if (stream->up.field_set & (1 << ISC_UF_PORT)) {
    485 		stream->authoritylen += (size_t)snprintf(
    486 			stream->authority +
    487 				stream->up.field_data[ISC_UF_HOST].len,
    488 			AUTHEXTRA, ":%u", stream->up.port);
    489 	}
    490 
    491 	/* If we don't have path in URI, we use "/" as path. */
    492 	stream->pathlen = 1;
    493 	if (stream->up.field_set & (1 << ISC_UF_PATH)) {
    494 		stream->pathlen = stream->up.field_data[ISC_UF_PATH].len;
    495 	}
    496 	if (stream->up.field_set & (1 << ISC_UF_QUERY)) {
    497 		/* +1 for '?' character */
    498 		stream->pathlen +=
    499 			(size_t)(stream->up.field_data[ISC_UF_QUERY].len + 1);
    500 	}
    501 
    502 	stream->path = isc_mem_get(mctx, stream->pathlen);
    503 	if (stream->up.field_set & (1 << ISC_UF_PATH)) {
    504 		memmove(stream->path,
    505 			&uri[stream->up.field_data[ISC_UF_PATH].off],
    506 			stream->up.field_data[ISC_UF_PATH].len);
    507 	} else {
    508 		stream->path[0] = '/';
    509 	}
    510 
    511 	if (stream->up.field_set & (1 << ISC_UF_QUERY)) {
    512 		stream->path[stream->pathlen -
    513 			     stream->up.field_data[ISC_UF_QUERY].len - 1] = '?';
    514 		memmove(stream->path + stream->pathlen -
    515 				stream->up.field_data[ISC_UF_QUERY].len,
    516 			&uri[stream->up.field_data[ISC_UF_QUERY].off],
    517 			stream->up.field_data[ISC_UF_QUERY].len);
    518 	}
    519 
    520 	isc_buffer_allocate(mctx, &stream->rbuf,
    521 			    INITIAL_DNS_MESSAGE_BUFFER_SIZE);
    522 
    523 	ISC_LIST_PREPEND(sock->h2->session->cstreams, stream, link);
    524 	*streamp = stream;
    525 
    526 	return ISC_R_SUCCESS;
    527 }
    528 
    529 static void
    530 put_http_cstream(isc_mem_t *mctx, http_cstream_t *stream) {
    531 	isc_mem_put(mctx, stream->path, stream->pathlen);
    532 	isc_mem_put(mctx, stream->authority,
    533 		    stream->up.field_data[ISC_UF_HOST].len + AUTHEXTRA);
    534 	isc_mem_free(mctx, stream->uri);
    535 	if (stream->GET_path != NULL) {
    536 		isc_mem_free(mctx, stream->GET_path);
    537 		stream->GET_path = NULL;
    538 		stream->GET_path_len = 0;
    539 	}
    540 
    541 	if (stream->postdata != NULL) {
    542 		INSIST(stream->post);
    543 		isc_buffer_free(&stream->postdata);
    544 	}
    545 
    546 	if (stream == stream->httpsock->h2->connect.cstream) {
    547 		stream->httpsock->h2->connect.cstream = NULL;
    548 	}
    549 	if (ISC_LINK_LINKED(stream, link)) {
    550 		ISC_LIST_UNLINK(stream->httpsock->h2->session->cstreams, stream,
    551 				link);
    552 	}
    553 	isc__nmsocket_detach(&stream->httpsock);
    554 
    555 	isc_buffer_free(&stream->rbuf);
    556 	isc_mem_put(mctx, stream, sizeof(http_cstream_t));
    557 }
    558 
    559 static void
    560 finish_http_session(isc_nm_http_session_t *session) {
    561 	if (session->closed) {
    562 		return;
    563 	}
    564 
    565 	if (session->handle != NULL) {
    566 		if (!session->closed) {
    567 			session->closed = true;
    568 			session->reading = false;
    569 			isc_nm_read_stop(session->handle);
    570 			isc__nmsocket_timer_stop(session->handle->sock);
    571 			isc_nmhandle_close(session->handle);
    572 		}
    573 
    574 		/*
    575 		 * Free any unprocessed incoming data in order to not process
    576 		 * it during indirect calls to http_do_bio() that might happen
    577 		 * when calling the failed callbacks.
    578 		 */
    579 		if (session->buf != NULL) {
    580 			isc_buffer_free(&session->buf);
    581 		}
    582 
    583 		if (session->client) {
    584 			client_call_failed_read_cb(ISC_R_UNEXPECTED, session);
    585 		} else {
    586 			server_call_failed_read_cb(ISC_R_UNEXPECTED, session);
    587 		}
    588 
    589 		call_pending_callbacks(session->pending_write_callbacks,
    590 				       ISC_R_UNEXPECTED);
    591 		ISC_LIST_INIT(session->pending_write_callbacks);
    592 
    593 		if (session->pending_write_data != NULL) {
    594 			isc_buffer_free(&session->pending_write_data);
    595 		}
    596 
    597 		isc_nmhandle_detach(&session->handle);
    598 	}
    599 
    600 	if (session->client_httphandle != NULL) {
    601 		isc_nmhandle_detach(&session->client_httphandle);
    602 	}
    603 
    604 	INSIST(ISC_LIST_EMPTY(session->cstreams));
    605 
    606 	/* detach from server socket */
    607 	if (session->serversocket != NULL) {
    608 		isc__nmsocket_detach(&session->serversocket);
    609 	}
    610 	session->closed = true;
    611 }
    612 
    613 static int
    614 on_client_data_chunk_recv_callback(int32_t stream_id, const uint8_t *data,
    615 				   size_t len, isc_nm_http_session_t *session) {
    616 	http_cstream_t *cstream = find_http_cstream(stream_id, session);
    617 
    618 	if (cstream != NULL) {
    619 		size_t new_rbufsize = len;
    620 		INSIST(cstream->rbuf != NULL);
    621 		new_rbufsize += isc_buffer_usedlength(cstream->rbuf);
    622 		if (new_rbufsize <= MAX_DNS_MESSAGE_SIZE &&
    623 		    new_rbufsize <= cstream->response_status.content_length)
    624 		{
    625 			isc_buffer_putmem(cstream->rbuf, data, len);
    626 		} else {
    627 			return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
    628 		}
    629 	} else {
    630 		return NGHTTP2_ERR_CALLBACK_FAILURE;
    631 	}
    632 
    633 	return 0;
    634 }
    635 
    636 static int
    637 on_server_data_chunk_recv_callback(int32_t stream_id, const uint8_t *data,
    638 				   size_t len, isc_nm_http_session_t *session) {
    639 	isc_nmsocket_h2_t *h2 = ISC_LIST_HEAD(session->sstreams);
    640 	isc_mem_t *mctx = h2->psock->worker->mctx;
    641 
    642 	while (h2 != NULL) {
    643 		if (stream_id == h2->stream_id) {
    644 			if (isc_buffer_base(&h2->rbuf) == NULL) {
    645 				isc_buffer_init(
    646 					&h2->rbuf,
    647 					isc_mem_allocate(mctx,
    648 							 h2->content_length),
    649 					h2->content_length);
    650 			}
    651 			size_t new_bufsize = isc_buffer_usedlength(&h2->rbuf) +
    652 					     len;
    653 			if (new_bufsize <= h2->content_length) {
    654 				session->processed_useful_data += len;
    655 				isc_buffer_putmem(&h2->rbuf, data, len);
    656 				break;
    657 			}
    658 
    659 			return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
    660 		}
    661 		h2 = ISC_LIST_NEXT(h2, link);
    662 	}
    663 	if (h2 == NULL) {
    664 		return NGHTTP2_ERR_CALLBACK_FAILURE;
    665 	}
    666 
    667 	return 0;
    668 }
    669 
    670 static int
    671 on_data_chunk_recv_callback(nghttp2_session *ngsession, uint8_t flags,
    672 			    int32_t stream_id, const uint8_t *data, size_t len,
    673 			    void *user_data) {
    674 	isc_nm_http_session_t *session = (isc_nm_http_session_t *)user_data;
    675 	int rv;
    676 
    677 	UNUSED(ngsession);
    678 	UNUSED(flags);
    679 
    680 	if (session->client) {
    681 		rv = on_client_data_chunk_recv_callback(stream_id, data, len,
    682 							session);
    683 	} else {
    684 		rv = on_server_data_chunk_recv_callback(stream_id, data, len,
    685 							session);
    686 	}
    687 
    688 	return rv;
    689 }
    690 
    691 static void
    692 call_unlink_cstream_readcb(http_cstream_t *cstream,
    693 			   isc_nm_http_session_t *session,
    694 			   isc_result_t result) {
    695 	isc_region_t read_data;
    696 	REQUIRE(VALID_HTTP2_SESSION(session));
    697 	REQUIRE(cstream != NULL);
    698 	ISC_LIST_UNLINK(session->cstreams, cstream, link);
    699 	INSIST(VALID_NMHANDLE(session->client_httphandle));
    700 	isc_buffer_usedregion(cstream->rbuf, &read_data);
    701 	cstream->read_cb(session->client_httphandle, result, &read_data,
    702 			 cstream->read_cbarg);
    703 	if (result == ISC_R_SUCCESS) {
    704 		isc__nmsocket_timer_restart(session->handle->sock);
    705 	}
    706 	put_http_cstream(session->mctx, cstream);
    707 }
    708 
    709 static int
    710 on_client_stream_close_callback(int32_t stream_id,
    711 				isc_nm_http_session_t *session) {
    712 	http_cstream_t *cstream = find_http_cstream(stream_id, session);
    713 
    714 	if (cstream != NULL) {
    715 		isc_result_t result =
    716 			SUCCESSFUL_HTTP_STATUS(cstream->response_status.code)
    717 				? ISC_R_SUCCESS
    718 				: ISC_R_FAILURE;
    719 		call_unlink_cstream_readcb(cstream, session, result);
    720 		if (ISC_LIST_EMPTY(session->cstreams)) {
    721 			int rv = 0;
    722 			rv = nghttp2_session_terminate_session(
    723 				session->ngsession, NGHTTP2_NO_ERROR);
    724 			if (rv != 0) {
    725 				return rv;
    726 			}
    727 			/* Mark the session as closing one to finish it on a
    728 			 * subsequent call to http_do_bio() */
    729 			session->closing = true;
    730 		}
    731 	} else {
    732 		return NGHTTP2_ERR_CALLBACK_FAILURE;
    733 	}
    734 
    735 	return 0;
    736 }
    737 
    738 static int
    739 on_server_stream_close_callback(int32_t stream_id,
    740 				isc_nm_http_session_t *session) {
    741 	isc_nmsocket_t *sock = nghttp2_session_get_stream_user_data(
    742 		session->ngsession, stream_id);
    743 	int rv = 0;
    744 
    745 	ISC_LIST_UNLINK(session->sstreams, sock->h2, link);
    746 	session->nsstreams--;
    747 	if (sock->h2->request_received) {
    748 		session->submitted++;
    749 	}
    750 
    751 	/*
    752 	 * By making a call to isc__nmsocket_prep_destroy(), we ensure that
    753 	 * the socket gets marked as inactive, allowing the HTTP/2 data
    754 	 * associated with it to be properly disposed of eventually.
    755 	 *
    756 	 * An HTTP/2 stream socket will normally be marked as inactive in
    757 	 * the normal course of operation. However, when browsers terminate
    758 	 * HTTP/2 streams prematurely (e.g. by sending RST_STREAM),
    759 	 * corresponding sockets can remain marked as active, retaining
    760 	 * references to the HTTP/2 data (most notably the session objects),
    761 	 * preventing them from being correctly freed and leading to BIND
    762 	 * hanging on shutdown.  Calling isc__nmsocket_prep_destroy()
    763 	 * ensures that this will not happen.
    764 	 */
    765 	isc__nmsocket_prep_destroy(sock);
    766 	isc__nmsocket_detach(&sock);
    767 	return rv;
    768 }
    769 
    770 static int
    771 on_stream_close_callback(nghttp2_session *ngsession, int32_t stream_id,
    772 			 uint32_t error_code, void *user_data) {
    773 	isc_nm_http_session_t *session = (isc_nm_http_session_t *)user_data;
    774 	int rv = 0;
    775 
    776 	REQUIRE(VALID_HTTP2_SESSION(session));
    777 	REQUIRE(session->ngsession == ngsession);
    778 
    779 	UNUSED(error_code);
    780 
    781 	if (session->client) {
    782 		rv = on_client_stream_close_callback(stream_id, session);
    783 	} else {
    784 		rv = on_server_stream_close_callback(stream_id, session);
    785 	}
    786 
    787 	return rv;
    788 }
    789 
    790 static bool
    791 client_handle_status_header(http_cstream_t *cstream, const uint8_t *value,
    792 			    const size_t valuelen) {
    793 	char tmp[32] = { 0 };
    794 	const size_t tmplen = sizeof(tmp) - 1;
    795 
    796 	strncpy(tmp, (const char *)value, ISC_MIN(tmplen, valuelen));
    797 	cstream->response_status.code = strtoul(tmp, NULL, 10);
    798 
    799 	if (SUCCESSFUL_HTTP_STATUS(cstream->response_status.code)) {
    800 		return true;
    801 	}
    802 
    803 	return false;
    804 }
    805 
    806 static bool
    807 client_handle_content_length_header(http_cstream_t *cstream,
    808 				    const uint8_t *value,
    809 				    const size_t valuelen) {
    810 	char tmp[32] = { 0 };
    811 	const size_t tmplen = sizeof(tmp) - 1;
    812 
    813 	strncpy(tmp, (const char *)value, ISC_MIN(tmplen, valuelen));
    814 	cstream->response_status.content_length = strtoul(tmp, NULL, 10);
    815 
    816 	if (cstream->response_status.content_length == 0 ||
    817 	    cstream->response_status.content_length > MAX_DNS_MESSAGE_SIZE)
    818 	{
    819 		return false;
    820 	}
    821 
    822 	return true;
    823 }
    824 
    825 static bool
    826 client_handle_content_type_header(http_cstream_t *cstream, const uint8_t *value,
    827 				  const size_t valuelen) {
    828 	const char type_dns_message[] = DNS_MEDIA_TYPE;
    829 	const size_t len = sizeof(type_dns_message) - 1;
    830 
    831 	UNUSED(valuelen);
    832 
    833 	if (strncasecmp((const char *)value, type_dns_message, len) == 0) {
    834 		cstream->response_status.content_type_valid = true;
    835 		return true;
    836 	}
    837 
    838 	return false;
    839 }
    840 
    841 static int
    842 client_on_header_callback(nghttp2_session *ngsession,
    843 			  const nghttp2_frame *frame, const uint8_t *name,
    844 			  size_t namelen, const uint8_t *value, size_t valuelen,
    845 			  uint8_t flags, void *user_data) {
    846 	isc_nm_http_session_t *session = (isc_nm_http_session_t *)user_data;
    847 	http_cstream_t *cstream = NULL;
    848 	const char status[] = ":status";
    849 	const char content_length[] = "Content-Length";
    850 	const char content_type[] = "Content-Type";
    851 	bool header_ok = true;
    852 
    853 	REQUIRE(VALID_HTTP2_SESSION(session));
    854 	REQUIRE(session->client);
    855 
    856 	UNUSED(flags);
    857 	UNUSED(ngsession);
    858 
    859 	cstream = find_http_cstream(frame->hd.stream_id, session);
    860 	if (cstream == NULL) {
    861 		/*
    862 		 * This could happen in two cases:
    863 		 * - the server sent us bad data, or
    864 		 * - we closed the session prematurely before receiving all
    865 		 *   responses (i.e., because of a belated or partial response).
    866 		 */
    867 		return NGHTTP2_ERR_CALLBACK_FAILURE;
    868 	}
    869 
    870 	INSIST(!ISC_LIST_EMPTY(session->cstreams));
    871 
    872 	switch (frame->hd.type) {
    873 	case NGHTTP2_HEADERS:
    874 		if (frame->headers.cat != NGHTTP2_HCAT_RESPONSE) {
    875 			break;
    876 		}
    877 
    878 		if (HEADER_MATCH(status, name, namelen)) {
    879 			header_ok = client_handle_status_header(cstream, value,
    880 								valuelen);
    881 		} else if (HEADER_MATCH(content_length, name, namelen)) {
    882 			header_ok = client_handle_content_length_header(
    883 				cstream, value, valuelen);
    884 		} else if (HEADER_MATCH(content_type, name, namelen)) {
    885 			header_ok = client_handle_content_type_header(
    886 				cstream, value, valuelen);
    887 		}
    888 		break;
    889 	}
    890 
    891 	if (!header_ok) {
    892 		return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
    893 	}
    894 
    895 	return 0;
    896 }
    897 
    898 static void
    899 initialize_nghttp2_client_session(isc_nm_http_session_t *session) {
    900 	nghttp2_session_callbacks *callbacks = NULL;
    901 	nghttp2_option *option = NULL;
    902 	nghttp2_mem mem;
    903 
    904 	init_nghttp2_mem(session->mctx, &mem);
    905 	RUNTIME_CHECK(nghttp2_session_callbacks_new(&callbacks) == 0);
    906 	RUNTIME_CHECK(nghttp2_option_new(&option) == 0);
    907 
    908 #if NGHTTP2_VERSION_NUM >= (0x010c00)
    909 	nghttp2_option_set_max_send_header_block_length(
    910 		option, MAX_ALLOWED_DATA_IN_HEADERS);
    911 #endif
    912 
    913 	nghttp2_session_callbacks_set_on_data_chunk_recv_callback(
    914 		callbacks, on_data_chunk_recv_callback);
    915 
    916 	nghttp2_session_callbacks_set_on_stream_close_callback(
    917 		callbacks, on_stream_close_callback);
    918 
    919 	nghttp2_session_callbacks_set_on_header_callback(
    920 		callbacks, client_on_header_callback);
    921 
    922 	RUNTIME_CHECK(nghttp2_session_client_new3(&session->ngsession,
    923 						  callbacks, session, option,
    924 						  &mem) == 0);
    925 
    926 	nghttp2_option_del(option);
    927 	nghttp2_session_callbacks_del(callbacks);
    928 }
    929 
    930 static bool
    931 send_client_connection_header(isc_nm_http_session_t *session) {
    932 	nghttp2_settings_entry iv[] = { { NGHTTP2_SETTINGS_ENABLE_PUSH, 0 } };
    933 	int rv;
    934 
    935 	rv = nghttp2_submit_settings(session->ngsession, NGHTTP2_FLAG_NONE, iv,
    936 				     sizeof(iv) / sizeof(iv[0]));
    937 	if (rv != 0) {
    938 		return false;
    939 	}
    940 
    941 	return true;
    942 }
    943 
    944 #define MAKE_NV(NAME, VALUE, VALUELEN)                                 \
    945 	{ (uint8_t *)(uintptr_t)(NAME), (uint8_t *)(uintptr_t)(VALUE), \
    946 	  sizeof(NAME) - 1, VALUELEN, NGHTTP2_NV_FLAG_NONE }
    947 
    948 #define MAKE_NV2(NAME, VALUE)                                          \
    949 	{ (uint8_t *)(uintptr_t)(NAME), (uint8_t *)(uintptr_t)(VALUE), \
    950 	  sizeof(NAME) - 1, sizeof(VALUE) - 1, NGHTTP2_NV_FLAG_NONE }
    951 
    952 static ssize_t
    953 client_read_callback(nghttp2_session *ngsession, int32_t stream_id,
    954 		     uint8_t *buf, size_t length, uint32_t *data_flags,
    955 		     nghttp2_data_source *source, void *user_data) {
    956 	isc_nm_http_session_t *session = (isc_nm_http_session_t *)user_data;
    957 	http_cstream_t *cstream = NULL;
    958 
    959 	REQUIRE(session->client);
    960 	REQUIRE(!ISC_LIST_EMPTY(session->cstreams));
    961 
    962 	UNUSED(ngsession);
    963 	UNUSED(source);
    964 
    965 	cstream = find_http_cstream(stream_id, session);
    966 	if (!cstream || cstream->stream_id != stream_id) {
    967 		/* We haven't found the stream, so we are not reading */
    968 		return NGHTTP2_ERR_CALLBACK_FAILURE;
    969 	}
    970 
    971 	if (cstream->post) {
    972 		size_t len = isc_buffer_remaininglength(cstream->postdata);
    973 
    974 		if (len > length) {
    975 			len = length;
    976 		}
    977 
    978 		if (len > 0) {
    979 			memmove(buf, isc_buffer_current(cstream->postdata),
    980 				len);
    981 			isc_buffer_forward(cstream->postdata, len);
    982 		}
    983 
    984 		if (isc_buffer_remaininglength(cstream->postdata) == 0) {
    985 			*data_flags |= NGHTTP2_DATA_FLAG_EOF;
    986 		}
    987 
    988 		return len;
    989 	} else {
    990 		*data_flags |= NGHTTP2_DATA_FLAG_EOF;
    991 		return 0;
    992 	}
    993 
    994 	return 0;
    995 }
    996 
    997 /*
    998  * Send HTTP request to the remote peer.
    999  */
   1000 static isc_result_t
   1001 client_submit_request(isc_nm_http_session_t *session, http_cstream_t *stream) {
   1002 	int32_t stream_id;
   1003 	char *uri = stream->uri;
   1004 	isc_url_parser_t *up = &stream->up;
   1005 	nghttp2_data_provider dp;
   1006 
   1007 	if (stream->post) {
   1008 		char p[64];
   1009 		snprintf(p, sizeof(p), "%u",
   1010 			 isc_buffer_usedlength(stream->postdata));
   1011 		nghttp2_nv hdrs[] = {
   1012 			MAKE_NV2(":method", "POST"),
   1013 			MAKE_NV(":scheme",
   1014 				&uri[up->field_data[ISC_UF_SCHEMA].off],
   1015 				up->field_data[ISC_UF_SCHEMA].len),
   1016 			MAKE_NV(":authority", stream->authority,
   1017 				stream->authoritylen),
   1018 			MAKE_NV(":path", stream->path, stream->pathlen),
   1019 			MAKE_NV2("content-type", DNS_MEDIA_TYPE),
   1020 			MAKE_NV2("accept", DNS_MEDIA_TYPE),
   1021 			MAKE_NV("content-length", p, strlen(p)),
   1022 			MAKE_NV2("cache-control", DEFAULT_CACHE_CONTROL)
   1023 		};
   1024 
   1025 		dp = (nghttp2_data_provider){ .read_callback =
   1026 						      client_read_callback };
   1027 		stream_id = nghttp2_submit_request(
   1028 			session->ngsession, NULL, hdrs,
   1029 			sizeof(hdrs) / sizeof(hdrs[0]), &dp, stream);
   1030 	} else {
   1031 		INSIST(stream->GET_path != NULL);
   1032 		INSIST(stream->GET_path_len != 0);
   1033 		nghttp2_nv hdrs[] = {
   1034 			MAKE_NV2(":method", "GET"),
   1035 			MAKE_NV(":scheme",
   1036 				&uri[up->field_data[ISC_UF_SCHEMA].off],
   1037 				up->field_data[ISC_UF_SCHEMA].len),
   1038 			MAKE_NV(":authority", stream->authority,
   1039 				stream->authoritylen),
   1040 			MAKE_NV(":path", stream->GET_path,
   1041 				stream->GET_path_len),
   1042 			MAKE_NV2("accept", DNS_MEDIA_TYPE),
   1043 			MAKE_NV2("cache-control", DEFAULT_CACHE_CONTROL)
   1044 		};
   1045 
   1046 		dp = (nghttp2_data_provider){ .read_callback =
   1047 						      client_read_callback };
   1048 		stream_id = nghttp2_submit_request(
   1049 			session->ngsession, NULL, hdrs,
   1050 			sizeof(hdrs) / sizeof(hdrs[0]), &dp, stream);
   1051 	}
   1052 	if (stream_id < 0) {
   1053 		return ISC_R_FAILURE;
   1054 	}
   1055 
   1056 	stream->stream_id = stream_id;
   1057 
   1058 	return ISC_R_SUCCESS;
   1059 }
   1060 
   1061 static inline size_t
   1062 http_in_flight_data_size(isc_nm_http_session_t *session) {
   1063 	size_t in_flight = 0;
   1064 
   1065 	if (session->pending_write_data != NULL) {
   1066 		in_flight += isc_buffer_usedlength(session->pending_write_data);
   1067 	}
   1068 
   1069 	in_flight += session->data_in_flight;
   1070 
   1071 	return in_flight;
   1072 }
   1073 
   1074 static ssize_t
   1075 http_process_input_data(isc_nm_http_session_t *session,
   1076 			isc_buffer_t *input_data) {
   1077 	ssize_t readlen = 0;
   1078 	ssize_t processed = 0;
   1079 	isc_region_t chunk = { 0 };
   1080 	size_t before, after;
   1081 	size_t i;
   1082 
   1083 	REQUIRE(VALID_HTTP2_SESSION(session));
   1084 	REQUIRE(input_data != NULL);
   1085 
   1086 	if (!http_session_active(session)) {
   1087 		return 0;
   1088 	}
   1089 
   1090 	/*
   1091 	 * For clients that initiate request themselves just process
   1092 	 * everything.
   1093 	 */
   1094 	if (session->client) {
   1095 		isc_buffer_remainingregion(input_data, &chunk);
   1096 		if (chunk.length == 0) {
   1097 			return 0;
   1098 		}
   1099 
   1100 		readlen = nghttp2_session_mem_recv(session->ngsession,
   1101 						   chunk.base, chunk.length);
   1102 
   1103 		if (readlen >= 0) {
   1104 			isc_buffer_forward(input_data, readlen);
   1105 			session->processed_incoming_data += readlen;
   1106 		}
   1107 
   1108 		return readlen;
   1109 	}
   1110 
   1111 	/*
   1112 	 * If no streams are created during processing, we might process
   1113 	 * more than one chunk at a time. Still we should not overdo that
   1114 	 * to avoid processing too much data at once as such behaviour is
   1115 	 * known for trashing the memory allocator at times.
   1116 	 */
   1117 	for (before = after = session->nsstreams, i = 0;
   1118 	     after <= before && i < INCOMING_DATA_MAX_CHUNKS_AT_ONCE;
   1119 	     after = session->nsstreams, i++)
   1120 	{
   1121 		const uint64_t active_streams =
   1122 			(session->received - session->processed);
   1123 
   1124 		/*
   1125 		 * If there is too much outgoing data in flight - let's not
   1126 		 * process any incoming data, as it could lead to piling up
   1127 		 * too much send data in send buffers. With many clients
   1128 		 * connected it can lead to excessive memory consumption on
   1129 		 * the server instance.
   1130 		 */
   1131 		const size_t in_flight = http_in_flight_data_size(session);
   1132 		if (in_flight >= ISC_NETMGR_TCP_SENDBUF_SIZE) {
   1133 			break;
   1134 		}
   1135 
   1136 		/*
   1137 		 * If we have reached the maximum number of streams used, we
   1138 		 * might stop processing for now, as nghttp2 will happily
   1139 		 * consume as much data as possible.
   1140 		 */
   1141 		if (session->nsstreams >= session->max_concurrent_streams &&
   1142 		    active_streams > 0)
   1143 		{
   1144 			break;
   1145 		}
   1146 
   1147 		if (http_too_many_active_streams(session)) {
   1148 			break;
   1149 		}
   1150 
   1151 		isc_buffer_remainingregion(input_data, &chunk);
   1152 		if (chunk.length == 0) {
   1153 			break;
   1154 		}
   1155 
   1156 		chunk.length = ISC_MIN(chunk.length, INCOMING_DATA_CHUNK_SIZE);
   1157 
   1158 		readlen = nghttp2_session_mem_recv(session->ngsession,
   1159 						   chunk.base, chunk.length);
   1160 
   1161 		if (readlen >= 0) {
   1162 			isc_buffer_forward(input_data, readlen);
   1163 			session->processed_incoming_data += readlen;
   1164 			processed += readlen;
   1165 		} else {
   1166 			isc_buffer_clear(input_data);
   1167 			return readlen;
   1168 		}
   1169 	}
   1170 
   1171 	return processed;
   1172 }
   1173 
   1174 static void
   1175 http_log_flooding_peer(isc_nm_http_session_t *session) {
   1176 	const int log_level = ISC_LOG_DEBUG(1);
   1177 	if (session->handle != NULL && isc_log_wouldlog(isc_lctx, log_level)) {
   1178 		char client_sabuf[ISC_SOCKADDR_FORMATSIZE];
   1179 		char local_sabuf[ISC_SOCKADDR_FORMATSIZE];
   1180 
   1181 		isc_sockaddr_format(&session->handle->sock->peer, client_sabuf,
   1182 				    sizeof(client_sabuf));
   1183 		isc_sockaddr_format(&session->handle->sock->iface, local_sabuf,
   1184 				    sizeof(local_sabuf));
   1185 		isc__nmsocket_log(session->handle->sock, log_level,
   1186 				  "Dropping a flooding HTTP/2 peer "
   1187 				  "%s (on %s) - processed: %" PRIu64
   1188 				  " bytes, of them useful: %" PRIu64 "",
   1189 				  client_sabuf, local_sabuf,
   1190 				  session->processed_incoming_data,
   1191 				  session->processed_useful_data);
   1192 	}
   1193 }
   1194 
   1195 static bool
   1196 http_is_flooding_peer(isc_nm_http_session_t *session) {
   1197 	if (session->client) {
   1198 		return false;
   1199 	}
   1200 
   1201 	/*
   1202 	 * A flooding client can try to open a lot of streams before
   1203 	 * submitting a request. Let's drop such clients.
   1204 	 */
   1205 	if (session->received == 0 &&
   1206 	    session->total_opened_sstreams > MAX_STREAMS_BEFORE_FIRST_REQUEST)
   1207 	{
   1208 		return true;
   1209 	}
   1210 
   1211 	/*
   1212 	 * We have processed enough data to open at least one stream and
   1213 	 * get some useful data.
   1214 	 */
   1215 	if (session->processed_incoming_data >
   1216 		    INCOMING_DATA_INITIAL_STREAM_SIZE &&
   1217 	    (session->total_opened_sstreams == 0 ||
   1218 	     session->processed_useful_data == 0))
   1219 	{
   1220 		return true;
   1221 	}
   1222 
   1223 	if (session->processed_incoming_data < INCOMING_DATA_GRACE_SIZE) {
   1224 		return false;
   1225 	}
   1226 
   1227 	/*
   1228 	 * The overhead of DoH per DNS message can be minimum 160-180
   1229 	 * bytes. We should allow more for extra information that can be
   1230 	 * included in headers, so let's use 256 bytes. Minimum DNS
   1231 	 * message size is 12 bytes. So, (256+12)/12=22. Even that can be
   1232 	 * too restricting for some edge cases, but should be good enough
   1233 	 * for any practical purposes. Not to mention that HTTP/2 may
   1234 	 * include legitimate data that is completely useless for DNS
   1235 	 * purposes...
   1236 	 *
   1237 	 * Anyway, at that point we should have processed enough requests
   1238 	 * for such clients (if any).
   1239 	 */
   1240 	if (session->processed_useful_data == 0 ||
   1241 	    (session->processed_incoming_data /
   1242 	     session->processed_useful_data) > 22)
   1243 	{
   1244 		return true;
   1245 	}
   1246 
   1247 	return false;
   1248 }
   1249 
   1250 /*
   1251  * Read callback from TLS socket.
   1252  */
   1253 static void
   1254 http_readcb(isc_nmhandle_t *handle ISC_ATTR_UNUSED, isc_result_t result,
   1255 	    isc_region_t *region, void *data) {
   1256 	isc_nm_http_session_t *session = (isc_nm_http_session_t *)data;
   1257 	isc_nm_http_session_t *tmpsess = NULL;
   1258 	ssize_t readlen;
   1259 	isc_buffer_t input;
   1260 
   1261 	REQUIRE(VALID_HTTP2_SESSION(session));
   1262 
   1263 	/*
   1264 	 * Let's ensure that HTTP/2 session and its associated data will
   1265 	 * not go "out of scope" too early.
   1266 	 */
   1267 	isc__nm_httpsession_attach(session, &tmpsess);
   1268 
   1269 	if (result != ISC_R_SUCCESS) {
   1270 		if (result != ISC_R_TIMEDOUT) {
   1271 			session->reading = false;
   1272 		}
   1273 		failed_read_cb(result, session);
   1274 		goto done;
   1275 	}
   1276 
   1277 	isc_buffer_init(&input, region->base, region->length);
   1278 	isc_buffer_add(&input, region->length);
   1279 
   1280 	readlen = http_process_input_data(session, &input);
   1281 	if (readlen < 0) {
   1282 		failed_read_cb(ISC_R_UNEXPECTED, session);
   1283 		goto done;
   1284 	} else if (http_is_flooding_peer(session)) {
   1285 		http_log_flooding_peer(session);
   1286 		failed_read_cb(ISC_R_RANGE, session);
   1287 		goto done;
   1288 	}
   1289 
   1290 	if ((size_t)readlen < region->length) {
   1291 		size_t unread_size = region->length - readlen;
   1292 		if (session->buf == NULL) {
   1293 			isc_buffer_allocate(session->mctx, &session->buf,
   1294 					    unread_size);
   1295 		}
   1296 		isc_buffer_putmem(session->buf, region->base + readlen,
   1297 				  unread_size);
   1298 		if (session->handle != NULL) {
   1299 			INSIST(VALID_NMHANDLE(session->handle));
   1300 			isc_nm_read_stop(session->handle);
   1301 		}
   1302 		http_do_bio_async(session);
   1303 	} else {
   1304 		/* We might have something to receive or send, do IO */
   1305 		http_do_bio(session, NULL, NULL, NULL);
   1306 	}
   1307 
   1308 done:
   1309 	isc__nm_httpsession_detach(&tmpsess);
   1310 }
   1311 
   1312 static void
   1313 call_pending_callbacks(isc__nm_http_pending_callbacks_t pending_callbacks,
   1314 		       isc_result_t result) {
   1315 	isc__nm_uvreq_t *cbreq = ISC_LIST_HEAD(pending_callbacks);
   1316 	while (cbreq != NULL) {
   1317 		isc__nm_uvreq_t *next = ISC_LIST_NEXT(cbreq, link);
   1318 		ISC_LIST_UNLINK(pending_callbacks, cbreq, link);
   1319 		isc__nm_sendcb(cbreq->handle->sock, cbreq, result, true);
   1320 		cbreq = next;
   1321 	}
   1322 }
   1323 
   1324 static void
   1325 http_writecb(isc_nmhandle_t *handle, isc_result_t result, void *arg) {
   1326 	isc_http_send_req_t *req = (isc_http_send_req_t *)arg;
   1327 	isc_nm_http_session_t *session = req->session;
   1328 	isc_nmhandle_t *transphandle = req->transphandle;
   1329 
   1330 	REQUIRE(VALID_HTTP2_SESSION(session));
   1331 	REQUIRE(VALID_NMHANDLE(handle));
   1332 
   1333 	if (http_session_active(session)) {
   1334 		INSIST(session->handle == handle);
   1335 	}
   1336 
   1337 	call_pending_callbacks(req->pending_write_callbacks, result);
   1338 
   1339 	if (req->cb != NULL) {
   1340 		req->cb(req->httphandle, result, req->cbarg);
   1341 		isc_nmhandle_detach(&req->httphandle);
   1342 	}
   1343 
   1344 	session->data_in_flight -=
   1345 		isc_buffer_usedlength(req->pending_write_data);
   1346 	isc_buffer_free(&req->pending_write_data);
   1347 	session->processed += req->submitted;
   1348 	isc_mem_put(session->mctx, req, sizeof(*req));
   1349 
   1350 	session->sending--;
   1351 
   1352 	if (result == ISC_R_SUCCESS) {
   1353 		http_do_bio(session, NULL, NULL, NULL);
   1354 	} else {
   1355 		finish_http_session(session);
   1356 	}
   1357 	isc_nmhandle_detach(&transphandle);
   1358 
   1359 	isc__nm_httpsession_detach(&session);
   1360 }
   1361 
   1362 static void
   1363 move_pending_send_callbacks(isc_nm_http_session_t *session,
   1364 			    isc_http_send_req_t *send) {
   1365 	STATIC_ASSERT(
   1366 		sizeof(session->pending_write_callbacks) ==
   1367 			sizeof(send->pending_write_callbacks),
   1368 		"size of pending writes requests callbacks lists differs");
   1369 	memmove(&send->pending_write_callbacks,
   1370 		&session->pending_write_callbacks,
   1371 		sizeof(session->pending_write_callbacks));
   1372 	ISC_LIST_INIT(session->pending_write_callbacks);
   1373 }
   1374 
   1375 static inline void
   1376 http_append_pending_send_request(isc_nm_http_session_t *session,
   1377 				 isc_nmhandle_t *httphandle, isc_nm_cb_t cb,
   1378 				 void *cbarg) {
   1379 	REQUIRE(VALID_HTTP2_SESSION(session));
   1380 	REQUIRE(VALID_NMHANDLE(httphandle));
   1381 	REQUIRE(cb != NULL);
   1382 
   1383 	isc__nm_uvreq_t *newcb = isc__nm_uvreq_get(httphandle->sock);
   1384 
   1385 	newcb->cb.send = cb;
   1386 	newcb->cbarg = cbarg;
   1387 	isc_nmhandle_attach(httphandle, &newcb->handle);
   1388 	ISC_LIST_APPEND(session->pending_write_callbacks, newcb, link);
   1389 }
   1390 
   1391 static void
   1392 http_send_outgoing(isc_nm_http_session_t *session, isc_nmhandle_t *httphandle,
   1393 		   isc_nm_cb_t cb, void *cbarg) {
   1394 	isc_http_send_req_t *send = NULL;
   1395 	size_t total = 0;
   1396 	isc_region_t send_data = { 0 };
   1397 	isc_nmhandle_t *transphandle = NULL;
   1398 #ifdef ENABLE_HTTP_WRITE_BUFFERING
   1399 	size_t max_total_write_size = 0;
   1400 #endif /* ENABLE_HTTP_WRITE_BUFFERING */
   1401 
   1402 	if (!http_session_active(session)) {
   1403 		if (cb != NULL) {
   1404 			isc__nm_uvreq_t *req =
   1405 				isc__nm_uvreq_get(httphandle->sock);
   1406 
   1407 			req->cb.send = cb;
   1408 			req->cbarg = cbarg;
   1409 			isc_nmhandle_attach(httphandle, &req->handle);
   1410 			isc__nm_sendcb(httphandle->sock, req, ISC_R_CANCELED,
   1411 				       true);
   1412 		}
   1413 		return;
   1414 	} else if (!nghttp2_session_want_write(session->ngsession) &&
   1415 		   session->pending_write_data == NULL)
   1416 	{
   1417 		if (cb != NULL) {
   1418 			http_append_pending_send_request(session, httphandle,
   1419 							 cb, cbarg);
   1420 		}
   1421 		return;
   1422 	}
   1423 
   1424 	/*
   1425 	 * We need to attach to the session->handle earlier because as an
   1426 	 * indirect result of the nghttp2_session_mem_send() the session
   1427 	 * might get closed and the handle detached. However, there is
   1428 	 * still some outgoing data to handle and we need to call it
   1429 	 * anyway if only to get the write callback passed here to get
   1430 	 * called properly.
   1431 	 */
   1432 	isc_nmhandle_attach(session->handle, &transphandle);
   1433 
   1434 	while (nghttp2_session_want_write(session->ngsession)) {
   1435 		const uint8_t *data = NULL;
   1436 		const size_t pending =
   1437 			nghttp2_session_mem_send(session->ngsession, &data);
   1438 		const size_t new_total = total + pending;
   1439 
   1440 		/*
   1441 		 * Sometimes nghttp2_session_mem_send() does not return any
   1442 		 * data to send even though nghttp2_session_want_write()
   1443 		 * returns success.
   1444 		 */
   1445 		if (pending == 0 || data == NULL) {
   1446 			break;
   1447 		}
   1448 
   1449 		/* reallocate buffer if required */
   1450 		if (session->pending_write_data == NULL) {
   1451 			isc_buffer_allocate(session->mctx,
   1452 					    &session->pending_write_data,
   1453 					    INITIAL_DNS_MESSAGE_BUFFER_SIZE);
   1454 		}
   1455 		isc_buffer_putmem(session->pending_write_data, data, pending);
   1456 		total = new_total;
   1457 	}
   1458 
   1459 #ifdef ENABLE_HTTP_WRITE_BUFFERING
   1460 	if (session->pending_write_data != NULL) {
   1461 		max_total_write_size =
   1462 			isc_buffer_usedlength(session->pending_write_data);
   1463 	}
   1464 
   1465 	/*
   1466 	 * Here we are trying to flush the pending writes buffer earlier
   1467 	 * to avoid hitting unnecessary limitations on a TLS record size
   1468 	 * within some tools (e.g. flamethrower).
   1469 	 */
   1470 	if (cb != NULL) {
   1471 		/*
   1472 		 * Case 0: The callback is specified, that means that a DNS
   1473 		 * message is ready. Let's flush the the buffer.
   1474 		 */
   1475 		total = max_total_write_size;
   1476 	} else if (max_total_write_size >= FLUSH_HTTP_WRITE_BUFFER_AFTER) {
   1477 		/*
   1478 		 * Case 1: We have equal or more than
   1479 		 * FLUSH_HTTP_WRITE_BUFFER_AFTER bytes to send. Let's flush it.
   1480 		 */
   1481 		total = max_total_write_size;
   1482 	} else if (session->sending > 0 && total > 0) {
   1483 		/*
   1484 		 * Case 2: There is one or more write requests in flight and
   1485 		 * we have some new data form nghttp2 to send.
   1486 		 * Then let's return from the function: as soon as the
   1487 		 * "in-flight" write callback get's called or we have reached
   1488 		 * FLUSH_HTTP_WRITE_BUFFER_AFTER bytes in the write buffer, we
   1489 		 * will flush the buffer. */
   1490 		INSIST(cb == NULL);
   1491 		goto nothing_to_send;
   1492 	} else if (session->sending == 0 && total == 0 &&
   1493 		   session->pending_write_data != NULL)
   1494 	{
   1495 		/*
   1496 		 * Case 3: There is no write in flight and we haven't got
   1497 		 * anything new from nghttp2, but there is some data pending
   1498 		 * in the write buffer. Let's flush the buffer.
   1499 		 */
   1500 		isc_region_t region = { 0 };
   1501 		total = isc_buffer_usedlength(session->pending_write_data);
   1502 		INSIST(total > 0);
   1503 		isc_buffer_usedregion(session->pending_write_data, &region);
   1504 		INSIST(total == region.length);
   1505 	} else {
   1506 		/*
   1507 		 * The other cases are uninteresting, fall-through ones.
   1508 		 * In the following cases (4-6) we will just bail out:
   1509 		 *
   1510 		 * Case 4: There is nothing new to send, nor anything in the
   1511 		 * write buffer.
   1512 		 * Case 5: There is nothing new to send and there are write
   1513 		 * request(s) in flight.
   1514 		 * Case 6: There is nothing new to send nor are there any
   1515 		 * write requests in flight.
   1516 		 *
   1517 		 * Case 7: There is some new data to send and there are no
   1518 		 * write requests in flight: Let's send the data.
   1519 		 */
   1520 		INSIST((total == 0 && session->pending_write_data == NULL) ||
   1521 		       (total == 0 && session->sending > 0) ||
   1522 		       (total == 0 && session->sending == 0) ||
   1523 		       (total > 0 && session->sending == 0));
   1524 	}
   1525 #endif /* ENABLE_HTTP_WRITE_BUFFERING */
   1526 
   1527 	if (total == 0) {
   1528 		/* No data returned */
   1529 		if (cb != NULL) {
   1530 			http_append_pending_send_request(session, httphandle,
   1531 							 cb, cbarg);
   1532 		}
   1533 		goto nothing_to_send;
   1534 	}
   1535 
   1536 	/*
   1537 	 * If we have reached this point it means that we need to send some
   1538 	 * data and flush the outgoing buffer. The code below does that.
   1539 	 */
   1540 	send = isc_mem_get(session->mctx, sizeof(*send));
   1541 
   1542 	*send = (isc_http_send_req_t){ .pending_write_data =
   1543 					       session->pending_write_data,
   1544 				       .cb = cb,
   1545 				       .cbarg = cbarg,
   1546 				       .submitted = session->submitted };
   1547 	session->submitted = 0;
   1548 	session->pending_write_data = NULL;
   1549 	move_pending_send_callbacks(session, send);
   1550 
   1551 	send->transphandle = transphandle;
   1552 	isc__nm_httpsession_attach(session, &send->session);
   1553 
   1554 	if (cb != NULL) {
   1555 		INSIST(VALID_NMHANDLE(httphandle));
   1556 		isc_nmhandle_attach(httphandle, &send->httphandle);
   1557 	}
   1558 
   1559 	session->sending++;
   1560 	isc_buffer_usedregion(send->pending_write_data, &send_data);
   1561 	session->data_in_flight += send_data.length;
   1562 	isc_nm_send(transphandle, &send_data, http_writecb, send);
   1563 	return;
   1564 
   1565 nothing_to_send:
   1566 	isc_nmhandle_detach(&transphandle);
   1567 }
   1568 
   1569 static inline bool
   1570 http_too_many_active_streams(isc_nm_http_session_t *session) {
   1571 	const uint64_t active_streams = session->received - session->processed;
   1572 	/*
   1573 	 * The motivation behind capping the maximum active streams number
   1574 	 * to a third of maximum streams is to allow the value to scale
   1575 	 * with the max number of streams.
   1576 	 *
   1577 	 * We do not want to have too many active streams at once as every
   1578 	 * stream is processed as a separate virtual connection by the
   1579 	 * higher level code. If a client sends a bulk of requests without
   1580 	 * waiting for the previous ones to complete we might want to
   1581 	 * throttle it as it might be not a friend knocking at the
   1582 	 * door. We already have some job to do for it.
   1583 	 */
   1584 	const uint64_t max_active_streams =
   1585 		ISC_MAX(ISC_NETMGR_MAX_STREAM_CLIENTS_PER_CONN,
   1586 			(session->max_concurrent_streams * 6) / 10); /* 60% */
   1587 
   1588 	if (session->client) {
   1589 		return false;
   1590 	}
   1591 
   1592 	/*
   1593 	 * Do not process incoming data if there are too many active DNS
   1594 	 * clients (streams) per connection.
   1595 	 */
   1596 	if (active_streams >= max_active_streams) {
   1597 		return true;
   1598 	}
   1599 
   1600 	return false;
   1601 }
   1602 
   1603 static void
   1604 http_do_bio(isc_nm_http_session_t *session, isc_nmhandle_t *send_httphandle,
   1605 	    isc_nm_cb_t send_cb, void *send_cbarg) {
   1606 	isc__nm_uvreq_t *req = NULL;
   1607 	size_t remaining = 0;
   1608 	REQUIRE(VALID_HTTP2_SESSION(session));
   1609 
   1610 	if (session->closed) {
   1611 		goto cancel;
   1612 	} else if (session->closing) {
   1613 		/*
   1614 		 * There might be leftover callbacks waiting to be received
   1615 		 */
   1616 		if (session->sending == 0) {
   1617 			finish_http_session(session);
   1618 		}
   1619 		goto cancel;
   1620 	} else if (nghttp2_session_want_read(session->ngsession) == 0 &&
   1621 		   nghttp2_session_want_write(session->ngsession) == 0 &&
   1622 		   session->pending_write_data == NULL)
   1623 	{
   1624 		session->closing = true;
   1625 		if (session->handle != NULL) {
   1626 			isc_nm_read_stop(session->handle);
   1627 		}
   1628 		if (session->sending == 0) {
   1629 			finish_http_session(session);
   1630 		}
   1631 		goto cancel;
   1632 	}
   1633 
   1634 	else if (session->buf != NULL)
   1635 	{
   1636 		remaining = isc_buffer_remaininglength(session->buf);
   1637 	}
   1638 
   1639 	if (nghttp2_session_want_read(session->ngsession) != 0) {
   1640 		if (!session->reading) {
   1641 			/* We have not yet started reading from this handle */
   1642 			isc__nmsocket_timer_start(session->handle->sock);
   1643 			isc_nm_read(session->handle, http_readcb, session);
   1644 			session->reading = true;
   1645 		} else if (session->buf != NULL && remaining > 0) {
   1646 			/* Leftover data in the buffer, use it */
   1647 			size_t remaining_after = 0;
   1648 			ssize_t readlen = 0;
   1649 			isc_nm_http_session_t *tmpsess = NULL;
   1650 
   1651 			/*
   1652 			 * Let's ensure that HTTP/2 session and its associated
   1653 			 * data will not go "out of scope" too early.
   1654 			 */
   1655 			isc__nm_httpsession_attach(session, &tmpsess);
   1656 
   1657 			readlen = http_process_input_data(session,
   1658 							  session->buf);
   1659 
   1660 			remaining_after =
   1661 				isc_buffer_remaininglength(session->buf);
   1662 
   1663 			if (readlen < 0) {
   1664 				failed_read_cb(ISC_R_UNEXPECTED, session);
   1665 			} else if (http_is_flooding_peer(session)) {
   1666 				http_log_flooding_peer(session);
   1667 				failed_read_cb(ISC_R_RANGE, session);
   1668 			} else if ((size_t)readlen == remaining) {
   1669 				isc_buffer_clear(session->buf);
   1670 				isc_buffer_compact(session->buf);
   1671 				http_do_bio(session, send_httphandle, send_cb,
   1672 					    send_cbarg);
   1673 				isc__nm_httpsession_detach(&tmpsess);
   1674 				return;
   1675 			} else if (remaining_after > 0 &&
   1676 				   remaining_after < remaining)
   1677 			{
   1678 				/*
   1679 				 * We have processed a part of the data, now
   1680 				 * let's delay processing of whatever is left
   1681 				 * here. We want it to be an async operation so
   1682 				 * that we will:
   1683 				 *
   1684 				 * a) let other things run;
   1685 				 * b) have finer grained control over how much
   1686 				 * data is processed at once, because nghttp2
   1687 				 * would happily consume as much data we pass to
   1688 				 * it and that could overwhelm the server.
   1689 				 */
   1690 				http_do_bio_async(session);
   1691 			}
   1692 			isc__nm_httpsession_detach(&tmpsess);
   1693 		} else if (session->handle != NULL) {
   1694 			INSIST(VALID_NMHANDLE(session->handle));
   1695 			/*
   1696 			 * Resume reading, it's idempotent, wait for more
   1697 			 */
   1698 			isc__nmsocket_timer_start(session->handle->sock);
   1699 			isc_nm_read(session->handle, http_readcb, session);
   1700 		}
   1701 	} else if (session->handle != NULL) {
   1702 		INSIST(VALID_NMHANDLE(session->handle));
   1703 		/* We don't want more data, stop reading for now */
   1704 		isc_nm_read_stop(session->handle);
   1705 	}
   1706 
   1707 	/* we might have some data to send after processing */
   1708 	http_send_outgoing(session, send_httphandle, send_cb, send_cbarg);
   1709 
   1710 	return;
   1711 cancel:
   1712 	if (send_cb == NULL) {
   1713 		return;
   1714 	}
   1715 	req = isc__nm_uvreq_get(send_httphandle->sock);
   1716 
   1717 	req->cb.send = send_cb;
   1718 	req->cbarg = send_cbarg;
   1719 	isc_nmhandle_attach(send_httphandle, &req->handle);
   1720 	isc__nm_sendcb(send_httphandle->sock, req, ISC_R_CANCELED, true);
   1721 }
   1722 
   1723 static void
   1724 http_do_bio_async_cb(void *arg) {
   1725 	isc_nm_http_session_t *session = arg;
   1726 
   1727 	REQUIRE(VALID_HTTP2_SESSION(session));
   1728 
   1729 	session->async_queued = false;
   1730 
   1731 	if (session->handle != NULL &&
   1732 	    !isc__nmsocket_closing(session->handle->sock))
   1733 	{
   1734 		http_do_bio(session, NULL, NULL, NULL);
   1735 	}
   1736 
   1737 	isc__nm_httpsession_detach(&session);
   1738 }
   1739 
   1740 static void
   1741 http_do_bio_async(isc_nm_http_session_t *session) {
   1742 	isc_nm_http_session_t *tmpsess = NULL;
   1743 
   1744 	REQUIRE(VALID_HTTP2_SESSION(session));
   1745 
   1746 	if (session->handle == NULL ||
   1747 	    isc__nmsocket_closing(session->handle->sock) ||
   1748 	    session->async_queued)
   1749 	{
   1750 		return;
   1751 	}
   1752 	session->async_queued = true;
   1753 	isc__nm_httpsession_attach(session, &tmpsess);
   1754 	isc_async_run(session->handle->sock->worker->loop, http_do_bio_async_cb,
   1755 		      tmpsess);
   1756 }
   1757 
   1758 static isc_result_t
   1759 get_http_cstream(isc_nmsocket_t *sock, http_cstream_t **streamp) {
   1760 	http_cstream_t *cstream = sock->h2->connect.cstream;
   1761 	isc_result_t result;
   1762 
   1763 	REQUIRE(streamp != NULL && *streamp == NULL);
   1764 
   1765 	sock->h2->connect.cstream = NULL;
   1766 
   1767 	if (cstream == NULL) {
   1768 		result = new_http_cstream(sock, &cstream);
   1769 		if (result != ISC_R_SUCCESS) {
   1770 			INSIST(cstream == NULL);
   1771 			return result;
   1772 		}
   1773 	}
   1774 
   1775 	*streamp = cstream;
   1776 	return ISC_R_SUCCESS;
   1777 }
   1778 
   1779 static void
   1780 http_call_connect_cb(isc_nmsocket_t *sock, isc_nm_http_session_t *session,
   1781 		     isc_result_t result) {
   1782 	isc_nmhandle_t *httphandle = isc__nmhandle_get(sock, &sock->peer,
   1783 						       &sock->iface);
   1784 	void *cbarg;
   1785 	isc_nm_cb_t connect_cb;
   1786 
   1787 	REQUIRE(sock->connect_cb != NULL);
   1788 
   1789 	cbarg = sock->connect_cbarg;
   1790 	connect_cb = sock->connect_cb;
   1791 	isc__nmsocket_clearcb(sock);
   1792 	if (result == ISC_R_SUCCESS) {
   1793 		if (session != NULL) {
   1794 			session->client_httphandle = httphandle;
   1795 		}
   1796 		connect_cb(httphandle, result, cbarg);
   1797 	} else {
   1798 		connect_cb(httphandle, result, cbarg);
   1799 		isc_nmhandle_detach(&httphandle);
   1800 	}
   1801 }
   1802 
   1803 static void
   1804 transport_connect_cb(isc_nmhandle_t *handle, isc_result_t result, void *cbarg) {
   1805 	isc_nmsocket_t *http_sock = (isc_nmsocket_t *)cbarg;
   1806 	isc_nmsocket_t *transp_sock = NULL;
   1807 	isc_nm_http_session_t *session = NULL;
   1808 	http_cstream_t *cstream = NULL;
   1809 	isc_mem_t *mctx = NULL;
   1810 
   1811 	REQUIRE(VALID_NMSOCK(http_sock));
   1812 	REQUIRE(VALID_NMHANDLE(handle));
   1813 
   1814 	transp_sock = handle->sock;
   1815 
   1816 	REQUIRE(VALID_NMSOCK(transp_sock));
   1817 
   1818 	mctx = transp_sock->worker->mctx;
   1819 
   1820 	INSIST(http_sock->h2->connect.uri != NULL);
   1821 
   1822 	http_sock->h2->connect.tls_peer_verify_string =
   1823 		isc_nm_verify_tls_peer_result_string(handle);
   1824 	if (result != ISC_R_SUCCESS) {
   1825 		goto error;
   1826 	}
   1827 
   1828 	http_initsocket(transp_sock);
   1829 	new_session(mctx, http_sock->h2->connect.tlsctx, &session);
   1830 	session->client = true;
   1831 	transp_sock->h2->session = session;
   1832 	http_sock->h2->connect.tlsctx = NULL;
   1833 	/* otherwise we will get some garbage output in DIG */
   1834 	http_sock->iface = isc_nmhandle_localaddr(handle);
   1835 	http_sock->peer = isc_nmhandle_peeraddr(handle);
   1836 
   1837 	transp_sock->h2->connect.post = http_sock->h2->connect.post;
   1838 	transp_sock->h2->connect.uri = http_sock->h2->connect.uri;
   1839 	http_sock->h2->connect.uri = NULL;
   1840 	isc__nm_httpsession_attach(session, &http_sock->h2->session);
   1841 
   1842 	if (session->tlsctx != NULL) {
   1843 		const unsigned char *alpn = NULL;
   1844 		unsigned int alpnlen = 0;
   1845 
   1846 		INSIST(transp_sock->type == isc_nm_tlssocket ||
   1847 		       transp_sock->type == isc_nm_proxystreamsocket);
   1848 
   1849 		isc__nmhandle_get_selected_alpn(handle, &alpn, &alpnlen);
   1850 		if (alpn == NULL || alpnlen != NGHTTP2_PROTO_VERSION_ID_LEN ||
   1851 		    memcmp(NGHTTP2_PROTO_VERSION_ID, alpn,
   1852 			   NGHTTP2_PROTO_VERSION_ID_LEN) != 0)
   1853 		{
   1854 			/*
   1855 			 * HTTP/2 negotiation error.
   1856 			 * Any sensible DoH client
   1857 			 * will fail if HTTP/2 cannot
   1858 			 * be negotiated via ALPN.
   1859 			 */
   1860 			result = ISC_R_HTTP2ALPNERROR;
   1861 			goto error;
   1862 		}
   1863 	}
   1864 
   1865 	isc_nmhandle_attach(handle, &session->handle);
   1866 
   1867 	initialize_nghttp2_client_session(session);
   1868 	if (!send_client_connection_header(session)) {
   1869 		goto error;
   1870 	}
   1871 
   1872 	result = get_http_cstream(http_sock, &cstream);
   1873 	http_sock->h2->connect.cstream = cstream;
   1874 	if (result != ISC_R_SUCCESS) {
   1875 		goto error;
   1876 	}
   1877 
   1878 	http_transpost_tcp_nodelay(handle);
   1879 	isc__nmhandle_set_manual_timer(session->handle, true);
   1880 
   1881 	http_call_connect_cb(http_sock, session, result);
   1882 
   1883 	http_do_bio(session, NULL, NULL, NULL);
   1884 	isc__nmsocket_detach(&http_sock);
   1885 	return;
   1886 
   1887 error:
   1888 	http_call_connect_cb(http_sock, session, result);
   1889 
   1890 	if (http_sock->h2->connect.uri != NULL) {
   1891 		isc_mem_free(http_sock->worker->mctx,
   1892 			     http_sock->h2->connect.uri);
   1893 	}
   1894 
   1895 	isc__nmsocket_prep_destroy(http_sock);
   1896 	isc__nmsocket_detach(&http_sock);
   1897 }
   1898 
   1899 void
   1900 isc_nm_httpconnect(isc_nm_t *mgr, isc_sockaddr_t *local, isc_sockaddr_t *peer,
   1901 		   const char *uri, bool post, isc_nm_cb_t cb, void *cbarg,
   1902 		   isc_tlsctx_t *tlsctx, const char *sni_hostname,
   1903 		   isc_tlsctx_client_session_cache_t *client_sess_cache,
   1904 		   unsigned int timeout, isc_nm_proxy_type_t proxy_type,
   1905 		   isc_nm_proxyheader_info_t *proxy_info) {
   1906 	isc_sockaddr_t local_interface;
   1907 	isc_nmsocket_t *sock = NULL;
   1908 	isc__networker_t *worker = NULL;
   1909 
   1910 	REQUIRE(VALID_NM(mgr));
   1911 	REQUIRE(cb != NULL);
   1912 	REQUIRE(peer != NULL);
   1913 	REQUIRE(uri != NULL);
   1914 	REQUIRE(*uri != '\0');
   1915 
   1916 	worker = &mgr->workers[isc_tid()];
   1917 
   1918 	if (isc__nm_closing(worker)) {
   1919 		cb(NULL, ISC_R_SHUTTINGDOWN, cbarg);
   1920 		return;
   1921 	}
   1922 
   1923 	if (local == NULL) {
   1924 		isc_sockaddr_anyofpf(&local_interface, peer->type.sa.sa_family);
   1925 		local = &local_interface;
   1926 	}
   1927 
   1928 	sock = isc_mempool_get(worker->nmsocket_pool);
   1929 	isc__nmsocket_init(sock, worker, isc_nm_httpsocket, local, NULL);
   1930 	http_initsocket(sock);
   1931 
   1932 	sock->connect_timeout = timeout;
   1933 	sock->connect_cb = cb;
   1934 	sock->connect_cbarg = cbarg;
   1935 	sock->client = true;
   1936 
   1937 	if (isc__nm_closing(worker)) {
   1938 		isc__nm_uvreq_t *req = isc__nm_uvreq_get(sock);
   1939 
   1940 		req->cb.connect = cb;
   1941 		req->cbarg = cbarg;
   1942 		req->peer = *peer;
   1943 		req->local = *local;
   1944 		req->handle = isc__nmhandle_get(sock, &req->peer, &sock->iface);
   1945 
   1946 		isc__nmsocket_clearcb(sock);
   1947 		isc__nm_connectcb(sock, req, ISC_R_SHUTTINGDOWN, true);
   1948 		isc__nmsocket_prep_destroy(sock);
   1949 		isc__nmsocket_detach(&sock);
   1950 		return;
   1951 	}
   1952 
   1953 	*sock->h2 = (isc_nmsocket_h2_t){ .connect.uri = isc_mem_strdup(
   1954 						 sock->worker->mctx, uri),
   1955 					 .connect.post = post,
   1956 					 .connect.tlsctx = tlsctx };
   1957 	ISC_LINK_INIT(sock->h2, link);
   1958 
   1959 	/*
   1960 	 * We need to prevent the interface object data from going out of
   1961 	 * scope too early.
   1962 	 */
   1963 	if (local == &local_interface) {
   1964 		sock->h2->connect.local_interface = local_interface;
   1965 		sock->iface = sock->h2->connect.local_interface;
   1966 	}
   1967 
   1968 	switch (proxy_type) {
   1969 	case ISC_NM_PROXY_NONE:
   1970 		if (tlsctx != NULL) {
   1971 			isc_nm_tlsconnect(mgr, local, peer,
   1972 					  transport_connect_cb, sock, tlsctx,
   1973 					  sni_hostname, client_sess_cache,
   1974 					  timeout, false, NULL);
   1975 		} else {
   1976 			isc_nm_tcpconnect(mgr, local, peer,
   1977 					  transport_connect_cb, sock, timeout);
   1978 		}
   1979 		break;
   1980 	case ISC_NM_PROXY_PLAIN:
   1981 		if (tlsctx != NULL) {
   1982 			isc_nm_tlsconnect(mgr, local, peer,
   1983 					  transport_connect_cb, sock, tlsctx,
   1984 					  sni_hostname, client_sess_cache,
   1985 					  timeout, true, proxy_info);
   1986 		} else {
   1987 			isc_nm_proxystreamconnect(
   1988 				mgr, local, peer, transport_connect_cb, sock,
   1989 				timeout, NULL, NULL, NULL, proxy_info);
   1990 		}
   1991 		break;
   1992 	case ISC_NM_PROXY_ENCRYPTED:
   1993 		INSIST(tlsctx != NULL);
   1994 		isc_nm_proxystreamconnect(
   1995 			mgr, local, peer, transport_connect_cb, sock, timeout,
   1996 			tlsctx, sni_hostname, client_sess_cache, proxy_info);
   1997 		break;
   1998 	default:
   1999 		UNREACHABLE();
   2000 	}
   2001 }
   2002 
   2003 static isc_result_t
   2004 client_send(isc_nmhandle_t *handle, const isc_region_t *region) {
   2005 	isc_result_t result = ISC_R_SUCCESS;
   2006 	isc_nmsocket_t *sock = handle->sock;
   2007 	isc_mem_t *mctx = sock->worker->mctx;
   2008 	isc_nm_http_session_t *session = sock->h2->session;
   2009 	http_cstream_t *cstream = sock->h2->connect.cstream;
   2010 
   2011 	REQUIRE(VALID_HTTP2_SESSION(handle->sock->h2->session));
   2012 	REQUIRE(session->client);
   2013 	REQUIRE(region != NULL);
   2014 	REQUIRE(region->base != NULL);
   2015 	REQUIRE(region->length <= MAX_DNS_MESSAGE_SIZE);
   2016 
   2017 	if (session->closed) {
   2018 		return ISC_R_CANCELED;
   2019 	}
   2020 
   2021 	INSIST(cstream != NULL);
   2022 
   2023 	if (cstream->post) {
   2024 		/* POST */
   2025 		isc_buffer_allocate(mctx, &cstream->postdata, region->length);
   2026 		isc_buffer_putmem(cstream->postdata, region->base,
   2027 				  region->length);
   2028 	} else {
   2029 		/* GET */
   2030 		size_t path_size = 0;
   2031 		char *base64url_data = NULL;
   2032 		size_t base64url_data_len = 0;
   2033 		isc_buffer_t *buf = NULL;
   2034 		isc_region_t data = *region;
   2035 		isc_region_t base64_region;
   2036 		size_t base64_len = ((4 * data.length / 3) + 3) & ~3;
   2037 
   2038 		isc_buffer_allocate(mctx, &buf, base64_len);
   2039 
   2040 		result = isc_base64_totext(&data, -1, "", buf);
   2041 		if (result != ISC_R_SUCCESS) {
   2042 			isc_buffer_free(&buf);
   2043 			goto error;
   2044 		}
   2045 
   2046 		isc_buffer_usedregion(buf, &base64_region);
   2047 		INSIST(base64_region.length == base64_len);
   2048 
   2049 		base64url_data = isc__nm_base64_to_base64url(
   2050 			mctx, (const char *)base64_region.base,
   2051 			base64_region.length, &base64url_data_len);
   2052 		isc_buffer_free(&buf);
   2053 		if (base64url_data == NULL) {
   2054 			goto error;
   2055 		}
   2056 
   2057 		/* len("?dns=") + len(path) + len(base64url) + len("\0") */
   2058 		path_size = cstream->pathlen + base64url_data_len + 5 + 1;
   2059 		cstream->GET_path = isc_mem_allocate(mctx, path_size);
   2060 		cstream->GET_path_len = (size_t)snprintf(
   2061 			cstream->GET_path, path_size, "%.*s?dns=%s",
   2062 			(int)cstream->pathlen, cstream->path, base64url_data);
   2063 
   2064 		INSIST(cstream->GET_path_len == (path_size - 1));
   2065 		isc_mem_free(mctx, base64url_data);
   2066 	}
   2067 
   2068 	cstream->sending = true;
   2069 
   2070 	sock->h2->connect.cstream = NULL;
   2071 	result = client_submit_request(session, cstream);
   2072 	if (result != ISC_R_SUCCESS) {
   2073 		put_http_cstream(session->mctx, cstream);
   2074 		goto error;
   2075 	}
   2076 
   2077 error:
   2078 	return result;
   2079 }
   2080 
   2081 isc_result_t
   2082 isc__nm_http_request(isc_nmhandle_t *handle, isc_region_t *region,
   2083 		     isc_nm_recv_cb_t cb, void *cbarg) {
   2084 	isc_result_t result = ISC_R_SUCCESS;
   2085 	isc_nmsocket_t *sock = NULL;
   2086 	http_cstream_t *cstream = NULL;
   2087 
   2088 	REQUIRE(VALID_NMHANDLE(handle));
   2089 	REQUIRE(VALID_NMSOCK(handle->sock));
   2090 	REQUIRE(handle->sock->tid == isc_tid());
   2091 	REQUIRE(handle->sock->client);
   2092 
   2093 	REQUIRE(cb != NULL);
   2094 
   2095 	sock = handle->sock;
   2096 
   2097 	isc__nm_http_read(handle, cb, cbarg);
   2098 	if (!http_session_active(handle->sock->h2->session)) {
   2099 		/* the callback was called by isc__nm_http_read() */
   2100 		return ISC_R_CANCELED;
   2101 	}
   2102 	result = client_send(handle, region);
   2103 	if (result != ISC_R_SUCCESS) {
   2104 		goto error;
   2105 	}
   2106 
   2107 	return ISC_R_SUCCESS;
   2108 
   2109 error:
   2110 	cstream = sock->h2->connect.cstream;
   2111 	if (cstream->read_cb != NULL) {
   2112 		cstream->read_cb(handle, result, NULL, cstream->read_cbarg);
   2113 	}
   2114 	return result;
   2115 }
   2116 
   2117 static int
   2118 server_on_begin_headers_callback(nghttp2_session *ngsession,
   2119 				 const nghttp2_frame *frame, void *user_data) {
   2120 	isc_nm_http_session_t *session = (isc_nm_http_session_t *)user_data;
   2121 	isc_nmsocket_t *socket = NULL;
   2122 	isc__networker_t *worker = NULL;
   2123 	isc_sockaddr_t local;
   2124 
   2125 	if (frame->hd.type != NGHTTP2_HEADERS ||
   2126 	    frame->headers.cat != NGHTTP2_HCAT_REQUEST)
   2127 	{
   2128 		return 0;
   2129 	} else if (frame->hd.length > MAX_ALLOWED_DATA_IN_HEADERS) {
   2130 		return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
   2131 	}
   2132 
   2133 	if (session->nsstreams >= session->max_concurrent_streams) {
   2134 		return NGHTTP2_ERR_CALLBACK_FAILURE;
   2135 	}
   2136 
   2137 	INSIST(session->handle->sock->tid == isc_tid());
   2138 
   2139 	worker = session->handle->sock->worker;
   2140 	socket = isc_mempool_get(worker->nmsocket_pool);
   2141 	local = isc_nmhandle_localaddr(session->handle);
   2142 	isc__nmsocket_init(socket, worker, isc_nm_httpsocket, &local, NULL);
   2143 	http_initsocket(socket);
   2144 	socket->peer = isc_nmhandle_peeraddr(session->handle);
   2145 	*socket->h2 = (isc_nmsocket_h2_t){
   2146 		.psock = socket,
   2147 		.stream_id = frame->hd.stream_id,
   2148 		.headers_error_code = ISC_HTTP_ERROR_SUCCESS,
   2149 		.request_type = ISC_HTTP_REQ_UNSUPPORTED,
   2150 		.request_scheme = ISC_HTTP_SCHEME_UNSUPPORTED,
   2151 		.link = ISC_LINK_INITIALIZER,
   2152 	};
   2153 	isc_buffer_initnull(&socket->h2->rbuf);
   2154 	isc_buffer_initnull(&socket->h2->wbuf);
   2155 	isc_nm_http_endpoints_attach(
   2156 		http_get_listener_endpoints(session->serversocket, socket->tid),
   2157 		&socket->h2->peer_endpoints);
   2158 	session->nsstreams++;
   2159 	isc__nm_httpsession_attach(session, &socket->h2->session);
   2160 	ISC_LIST_APPEND(session->sstreams, socket->h2, link);
   2161 	session->total_opened_sstreams++;
   2162 
   2163 	nghttp2_session_set_stream_user_data(ngsession, frame->hd.stream_id,
   2164 					     socket);
   2165 	return 0;
   2166 }
   2167 
   2168 static isc_http_error_responses_t
   2169 server_handle_path_header(isc_nmsocket_t *socket, const uint8_t *value,
   2170 			  const size_t valuelen) {
   2171 	isc_nm_httphandler_t *handler = NULL;
   2172 	const uint8_t *qstr = NULL;
   2173 	size_t vlen = valuelen;
   2174 
   2175 	qstr = memchr(value, '?', valuelen);
   2176 	if (qstr != NULL) {
   2177 		vlen = qstr - value;
   2178 	}
   2179 
   2180 	if (socket->h2->request_path != NULL) {
   2181 		isc_mem_free(socket->worker->mctx, socket->h2->request_path);
   2182 	}
   2183 	socket->h2->request_path = isc_mem_strndup(
   2184 		socket->worker->mctx, (const char *)value, vlen + 1);
   2185 
   2186 	if (!isc_nm_http_path_isvalid(socket->h2->request_path)) {
   2187 		isc_mem_free(socket->worker->mctx, socket->h2->request_path);
   2188 		socket->h2->request_path = NULL;
   2189 		return ISC_HTTP_ERROR_BAD_REQUEST;
   2190 	}
   2191 
   2192 	handler = http_endpoints_find(socket->h2->request_path,
   2193 				      socket->h2->peer_endpoints);
   2194 	if (handler != NULL) {
   2195 		socket->h2->cb = handler->cb;
   2196 		socket->h2->cbarg = handler->cbarg;
   2197 	} else {
   2198 		isc_mem_free(socket->worker->mctx, socket->h2->request_path);
   2199 		socket->h2->request_path = NULL;
   2200 		return ISC_HTTP_ERROR_NOT_FOUND;
   2201 	}
   2202 
   2203 	if (qstr != NULL) {
   2204 		const char *dns_value = NULL;
   2205 		size_t dns_value_len = 0;
   2206 
   2207 		if (isc__nm_parse_httpquery((const char *)qstr, &dns_value,
   2208 					    &dns_value_len))
   2209 		{
   2210 			const size_t decoded_size = dns_value_len / 4 * 3;
   2211 			if (decoded_size <= MAX_DNS_MESSAGE_SIZE) {
   2212 				if (socket->h2->query_data != NULL) {
   2213 					isc_mem_free(socket->worker->mctx,
   2214 						     socket->h2->query_data);
   2215 				}
   2216 				socket->h2->query_data =
   2217 					isc__nm_base64url_to_base64(
   2218 						socket->worker->mctx, dns_value,
   2219 						dns_value_len,
   2220 						&socket->h2->query_data_len);
   2221 				socket->h2->session->processed_useful_data +=
   2222 					dns_value_len;
   2223 			} else {
   2224 				socket->h2->query_too_large = true;
   2225 				return ISC_HTTP_ERROR_PAYLOAD_TOO_LARGE;
   2226 			}
   2227 		} else {
   2228 			return ISC_HTTP_ERROR_BAD_REQUEST;
   2229 		}
   2230 	}
   2231 	return ISC_HTTP_ERROR_SUCCESS;
   2232 }
   2233 
   2234 static isc_http_error_responses_t
   2235 server_handle_method_header(isc_nmsocket_t *socket, const uint8_t *value,
   2236 			    const size_t valuelen) {
   2237 	const char get[] = "GET";
   2238 	const char post[] = "POST";
   2239 
   2240 	if (HEADER_MATCH(get, value, valuelen)) {
   2241 		socket->h2->request_type = ISC_HTTP_REQ_GET;
   2242 	} else if (HEADER_MATCH(post, value, valuelen)) {
   2243 		socket->h2->request_type = ISC_HTTP_REQ_POST;
   2244 	} else {
   2245 		return ISC_HTTP_ERROR_NOT_IMPLEMENTED;
   2246 	}
   2247 	return ISC_HTTP_ERROR_SUCCESS;
   2248 }
   2249 
   2250 static isc_http_error_responses_t
   2251 server_handle_scheme_header(isc_nmsocket_t *socket, const uint8_t *value,
   2252 			    const size_t valuelen) {
   2253 	const char http[] = "http";
   2254 	const char http_secure[] = "https";
   2255 
   2256 	if (HEADER_MATCH(http_secure, value, valuelen)) {
   2257 		socket->h2->request_scheme = ISC_HTTP_SCHEME_HTTP_SECURE;
   2258 	} else if (HEADER_MATCH(http, value, valuelen)) {
   2259 		socket->h2->request_scheme = ISC_HTTP_SCHEME_HTTP;
   2260 	} else {
   2261 		return ISC_HTTP_ERROR_BAD_REQUEST;
   2262 	}
   2263 	return ISC_HTTP_ERROR_SUCCESS;
   2264 }
   2265 
   2266 static isc_http_error_responses_t
   2267 server_handle_content_length_header(isc_nmsocket_t *socket,
   2268 				    const uint8_t *value,
   2269 				    const size_t valuelen) {
   2270 	char tmp[32] = { 0 };
   2271 	const size_t tmplen = sizeof(tmp) - 1;
   2272 
   2273 	strncpy(tmp, (const char *)value,
   2274 		valuelen > tmplen ? tmplen : valuelen);
   2275 	socket->h2->content_length = strtoul(tmp, NULL, 10);
   2276 	if (socket->h2->content_length > MAX_DNS_MESSAGE_SIZE) {
   2277 		return ISC_HTTP_ERROR_PAYLOAD_TOO_LARGE;
   2278 	} else if (socket->h2->content_length == 0) {
   2279 		return ISC_HTTP_ERROR_BAD_REQUEST;
   2280 	}
   2281 	return ISC_HTTP_ERROR_SUCCESS;
   2282 }
   2283 
   2284 static isc_http_error_responses_t
   2285 server_handle_content_type_header(isc_nmsocket_t *socket, const uint8_t *value,
   2286 				  const size_t valuelen) {
   2287 	const char type_dns_message[] = DNS_MEDIA_TYPE;
   2288 	isc_http_error_responses_t resp = ISC_HTTP_ERROR_SUCCESS;
   2289 
   2290 	UNUSED(socket);
   2291 
   2292 	if (!HEADER_MATCH(type_dns_message, value, valuelen)) {
   2293 		resp = ISC_HTTP_ERROR_UNSUPPORTED_MEDIA_TYPE;
   2294 	}
   2295 	return resp;
   2296 }
   2297 
   2298 static isc_http_error_responses_t
   2299 server_handle_header(isc_nmsocket_t *socket, const uint8_t *name,
   2300 		     size_t namelen, const uint8_t *value,
   2301 		     const size_t valuelen) {
   2302 	isc_http_error_responses_t code = ISC_HTTP_ERROR_SUCCESS;
   2303 	bool was_error;
   2304 	const char path[] = ":path";
   2305 	const char method[] = ":method";
   2306 	const char scheme[] = ":scheme";
   2307 	const char content_length[] = "Content-Length";
   2308 	const char content_type[] = "Content-Type";
   2309 
   2310 	was_error = socket->h2->headers_error_code != ISC_HTTP_ERROR_SUCCESS;
   2311 	/*
   2312 	 * process Content-Length even when there was an error,
   2313 	 * to drop the connection earlier if required.
   2314 	 */
   2315 	if (HEADER_MATCH(content_length, name, namelen)) {
   2316 		code = server_handle_content_length_header(socket, value,
   2317 							   valuelen);
   2318 	} else if (!was_error && HEADER_MATCH(path, name, namelen)) {
   2319 		code = server_handle_path_header(socket, value, valuelen);
   2320 	} else if (!was_error && HEADER_MATCH(method, name, namelen)) {
   2321 		code = server_handle_method_header(socket, value, valuelen);
   2322 	} else if (!was_error && HEADER_MATCH(scheme, name, namelen)) {
   2323 		code = server_handle_scheme_header(socket, value, valuelen);
   2324 	} else if (!was_error && HEADER_MATCH(content_type, name, namelen)) {
   2325 		code = server_handle_content_type_header(socket, value,
   2326 							 valuelen);
   2327 	}
   2328 
   2329 	return code;
   2330 }
   2331 
   2332 static int
   2333 server_on_header_callback(nghttp2_session *session, const nghttp2_frame *frame,
   2334 			  const uint8_t *name, size_t namelen,
   2335 			  const uint8_t *value, size_t valuelen, uint8_t flags,
   2336 			  void *user_data) {
   2337 	isc_nmsocket_t *socket = NULL;
   2338 	isc_http_error_responses_t code = ISC_HTTP_ERROR_SUCCESS;
   2339 
   2340 	UNUSED(flags);
   2341 	UNUSED(user_data);
   2342 
   2343 	socket = nghttp2_session_get_stream_user_data(session,
   2344 						      frame->hd.stream_id);
   2345 	if (socket == NULL) {
   2346 		return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
   2347 	}
   2348 
   2349 	socket->h2->headers_data_processed += (namelen + valuelen);
   2350 
   2351 	switch (frame->hd.type) {
   2352 	case NGHTTP2_HEADERS:
   2353 		if (frame->headers.cat != NGHTTP2_HCAT_REQUEST) {
   2354 			break;
   2355 		}
   2356 		code = server_handle_header(socket, name, namelen, value,
   2357 					    valuelen);
   2358 		break;
   2359 	}
   2360 
   2361 	INSIST(socket != NULL);
   2362 
   2363 	if (socket->h2->headers_data_processed > MAX_ALLOWED_DATA_IN_HEADERS) {
   2364 		return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
   2365 	} else if (socket->h2->content_length > MAX_ALLOWED_DATA_IN_POST) {
   2366 		return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
   2367 	}
   2368 
   2369 	if (code == ISC_HTTP_ERROR_SUCCESS) {
   2370 		return 0;
   2371 	} else {
   2372 		socket->h2->headers_error_code = code;
   2373 	}
   2374 
   2375 	return 0;
   2376 }
   2377 
   2378 static ssize_t
   2379 server_read_callback(nghttp2_session *ngsession, int32_t stream_id,
   2380 		     uint8_t *buf, size_t length, uint32_t *data_flags,
   2381 		     nghttp2_data_source *source, void *user_data) {
   2382 	isc_nm_http_session_t *session = (isc_nm_http_session_t *)user_data;
   2383 	isc_nmsocket_t *socket = (isc_nmsocket_t *)source->ptr;
   2384 	size_t buflen;
   2385 
   2386 	REQUIRE(socket->h2->stream_id == stream_id);
   2387 
   2388 	UNUSED(ngsession);
   2389 	UNUSED(session);
   2390 
   2391 	buflen = isc_buffer_remaininglength(&socket->h2->wbuf);
   2392 	if (buflen > length) {
   2393 		buflen = length;
   2394 	}
   2395 
   2396 	if (buflen > 0) {
   2397 		(void)memmove(buf, isc_buffer_current(&socket->h2->wbuf),
   2398 			      buflen);
   2399 		isc_buffer_forward(&socket->h2->wbuf, buflen);
   2400 	}
   2401 
   2402 	if (isc_buffer_remaininglength(&socket->h2->wbuf) == 0) {
   2403 		*data_flags |= NGHTTP2_DATA_FLAG_EOF;
   2404 	}
   2405 
   2406 	return buflen;
   2407 }
   2408 
   2409 static isc_result_t
   2410 server_send_response(nghttp2_session *ngsession, int32_t stream_id,
   2411 		     const nghttp2_nv *nva, size_t nvlen,
   2412 		     isc_nmsocket_t *socket) {
   2413 	nghttp2_data_provider data_prd;
   2414 	int rv;
   2415 
   2416 	if (socket->h2->response_submitted) {
   2417 		/* NGHTTP2 will gladly accept new response (write request)
   2418 		 * from us even though we cannot send more than one over the
   2419 		 * same HTTP/2 stream. Thus, we need to handle this case
   2420 		 * manually. We will return failure code so that it will be
   2421 		 * passed to the write callback. */
   2422 		return ISC_R_FAILURE;
   2423 	}
   2424 
   2425 	data_prd.source.ptr = socket;
   2426 	data_prd.read_callback = server_read_callback;
   2427 
   2428 	rv = nghttp2_submit_response(ngsession, stream_id, nva, nvlen,
   2429 				     &data_prd);
   2430 	if (rv != 0) {
   2431 		return ISC_R_FAILURE;
   2432 	}
   2433 
   2434 	socket->h2->response_submitted = true;
   2435 	return ISC_R_SUCCESS;
   2436 }
   2437 
   2438 #define MAKE_ERROR_REPLY(tag, code, desc) \
   2439 	{ tag, MAKE_NV2(":status", #code), desc }
   2440 
   2441 /*
   2442  * Here we use roughly the same error codes that Unbound uses.
   2443  * (https://blog.nlnetlabs.nl/dns-over-https-in-unbound/)
   2444  */
   2445 
   2446 static struct http_error_responses {
   2447 	const isc_http_error_responses_t type;
   2448 	const nghttp2_nv header;
   2449 	const char *desc;
   2450 } error_responses[] = {
   2451 	MAKE_ERROR_REPLY(ISC_HTTP_ERROR_BAD_REQUEST, 400, "Bad Request"),
   2452 	MAKE_ERROR_REPLY(ISC_HTTP_ERROR_NOT_FOUND, 404, "Not Found"),
   2453 	MAKE_ERROR_REPLY(ISC_HTTP_ERROR_PAYLOAD_TOO_LARGE, 413,
   2454 			 "Payload Too Large"),
   2455 	MAKE_ERROR_REPLY(ISC_HTTP_ERROR_URI_TOO_LONG, 414, "URI Too Long"),
   2456 	MAKE_ERROR_REPLY(ISC_HTTP_ERROR_UNSUPPORTED_MEDIA_TYPE, 415,
   2457 			 "Unsupported Media Type"),
   2458 	MAKE_ERROR_REPLY(ISC_HTTP_ERROR_GENERIC, 500, "Internal Server Error"),
   2459 	MAKE_ERROR_REPLY(ISC_HTTP_ERROR_NOT_IMPLEMENTED, 501, "Not Implemented")
   2460 };
   2461 
   2462 static void
   2463 log_server_error_response(const isc_nmsocket_t *socket,
   2464 			  const struct http_error_responses *response) {
   2465 	const int log_level = ISC_LOG_DEBUG(1);
   2466 	char client_sabuf[ISC_SOCKADDR_FORMATSIZE];
   2467 	char local_sabuf[ISC_SOCKADDR_FORMATSIZE];
   2468 
   2469 	if (!isc_log_wouldlog(isc_lctx, log_level)) {
   2470 		return;
   2471 	}
   2472 
   2473 	isc_sockaddr_format(&socket->peer, client_sabuf, sizeof(client_sabuf));
   2474 	isc_sockaddr_format(&socket->iface, local_sabuf, sizeof(local_sabuf));
   2475 	isc__nmsocket_log(socket, log_level,
   2476 			  "HTTP/2 request from %s (on %s) failed: %s %s",
   2477 			  client_sabuf, local_sabuf, response->header.value,
   2478 			  response->desc);
   2479 }
   2480 
   2481 static isc_result_t
   2482 server_send_error_response(const isc_http_error_responses_t error,
   2483 			   nghttp2_session *ngsession, isc_nmsocket_t *socket) {
   2484 	void *base;
   2485 
   2486 	REQUIRE(error != ISC_HTTP_ERROR_SUCCESS);
   2487 
   2488 	base = isc_buffer_base(&socket->h2->rbuf);
   2489 	if (base != NULL) {
   2490 		isc_mem_free(socket->h2->session->mctx, base);
   2491 		isc_buffer_initnull(&socket->h2->rbuf);
   2492 	}
   2493 
   2494 	/* We do not want the error response to be cached anywhere. */
   2495 	socket->h2->min_ttl = 0;
   2496 
   2497 	for (size_t i = 0;
   2498 	     i < sizeof(error_responses) / sizeof(error_responses[0]); i++)
   2499 	{
   2500 		if (error_responses[i].type == error) {
   2501 			log_server_error_response(socket, &error_responses[i]);
   2502 			return server_send_response(
   2503 				ngsession, socket->h2->stream_id,
   2504 				&error_responses[i].header, 1, socket);
   2505 		}
   2506 	}
   2507 
   2508 	return server_send_error_response(ISC_HTTP_ERROR_GENERIC, ngsession,
   2509 					  socket);
   2510 }
   2511 
   2512 static void
   2513 server_call_cb(isc_nmsocket_t *socket, const isc_result_t result,
   2514 	       isc_region_t *data) {
   2515 	isc_nmhandle_t *handle = NULL;
   2516 
   2517 	REQUIRE(VALID_NMSOCK(socket));
   2518 
   2519 	/*
   2520 	 * In some cases the callback could not have been set (e.g. when
   2521 	 * the stream was closed prematurely (before processing its HTTP
   2522 	 * path).
   2523 	 */
   2524 	if (socket->h2->cb == NULL) {
   2525 		return;
   2526 	}
   2527 
   2528 	handle = isc__nmhandle_get(socket, NULL, NULL);
   2529 	if (result != ISC_R_SUCCESS) {
   2530 		data = NULL;
   2531 	} else if (socket->h2->session->handle != NULL) {
   2532 		isc__nmsocket_timer_restart(socket->h2->session->handle->sock);
   2533 	}
   2534 	if (result == ISC_R_SUCCESS) {
   2535 		socket->h2->request_received = true;
   2536 		socket->h2->session->received++;
   2537 	}
   2538 	socket->h2->cb(handle, result, data, socket->h2->cbarg);
   2539 	isc_nmhandle_detach(&handle);
   2540 }
   2541 
   2542 void
   2543 isc__nm_http_bad_request(isc_nmhandle_t *handle) {
   2544 	isc_nmsocket_t *sock = NULL;
   2545 
   2546 	REQUIRE(VALID_NMHANDLE(handle));
   2547 	REQUIRE(VALID_NMSOCK(handle->sock));
   2548 	sock = handle->sock;
   2549 	REQUIRE(sock->type == isc_nm_httpsocket);
   2550 	REQUIRE(!sock->client);
   2551 	REQUIRE(VALID_HTTP2_SESSION(sock->h2->session));
   2552 
   2553 	if (sock->h2->response_submitted ||
   2554 	    !http_session_active(sock->h2->session))
   2555 	{
   2556 		return;
   2557 	}
   2558 
   2559 	(void)server_send_error_response(ISC_HTTP_ERROR_BAD_REQUEST,
   2560 					 sock->h2->session->ngsession, sock);
   2561 }
   2562 
   2563 static int
   2564 server_on_request_recv(nghttp2_session *ngsession, isc_nmsocket_t *socket) {
   2565 	isc_result_t result;
   2566 	isc_http_error_responses_t code = ISC_HTTP_ERROR_SUCCESS;
   2567 	isc_region_t data;
   2568 	uint8_t tmp_buf[MAX_DNS_MESSAGE_SIZE];
   2569 
   2570 	code = socket->h2->headers_error_code;
   2571 	if (code != ISC_HTTP_ERROR_SUCCESS) {
   2572 		goto error;
   2573 	}
   2574 
   2575 	if (socket->h2->request_path == NULL || socket->h2->cb == NULL) {
   2576 		code = ISC_HTTP_ERROR_NOT_FOUND;
   2577 	} else if (socket->h2->request_type == ISC_HTTP_REQ_POST &&
   2578 		   socket->h2->content_length == 0)
   2579 	{
   2580 		code = ISC_HTTP_ERROR_BAD_REQUEST;
   2581 	} else if (socket->h2->request_type == ISC_HTTP_REQ_POST &&
   2582 		   isc_buffer_usedlength(&socket->h2->rbuf) >
   2583 			   socket->h2->content_length)
   2584 	{
   2585 		code = ISC_HTTP_ERROR_PAYLOAD_TOO_LARGE;
   2586 	} else if (socket->h2->request_type == ISC_HTTP_REQ_POST &&
   2587 		   isc_buffer_usedlength(&socket->h2->rbuf) !=
   2588 			   socket->h2->content_length)
   2589 	{
   2590 		code = ISC_HTTP_ERROR_BAD_REQUEST;
   2591 	} else if (socket->h2->request_type == ISC_HTTP_REQ_POST &&
   2592 		   socket->h2->query_data != NULL)
   2593 	{
   2594 		/* The spec does not mention which value the query string for
   2595 		 * POST should have. For GET we use its value to decode a DNS
   2596 		 * message from it, for POST the message is transferred in the
   2597 		 * body of the request. Taking it into account, it is much safer
   2598 		 * to treat POST
   2599 		 * requests with query strings as malformed ones. */
   2600 		code = ISC_HTTP_ERROR_BAD_REQUEST;
   2601 	} else if (socket->h2->request_type == ISC_HTTP_REQ_GET &&
   2602 		   socket->h2->content_length > 0)
   2603 	{
   2604 		code = ISC_HTTP_ERROR_BAD_REQUEST;
   2605 	} else if (socket->h2->request_type == ISC_HTTP_REQ_GET &&
   2606 		   socket->h2->query_data == NULL)
   2607 	{
   2608 		/* A GET request without any query data - there is nothing to
   2609 		 * decode. */
   2610 		INSIST(socket->h2->query_data_len == 0);
   2611 		code = ISC_HTTP_ERROR_BAD_REQUEST;
   2612 	}
   2613 
   2614 	if (code != ISC_HTTP_ERROR_SUCCESS) {
   2615 		goto error;
   2616 	}
   2617 
   2618 	if (socket->h2->request_type == ISC_HTTP_REQ_GET) {
   2619 		isc_buffer_t decoded_buf;
   2620 		isc_buffer_init(&decoded_buf, tmp_buf, sizeof(tmp_buf));
   2621 		if (isc_base64_decodestring(socket->h2->query_data,
   2622 					    &decoded_buf) != ISC_R_SUCCESS)
   2623 		{
   2624 			code = ISC_HTTP_ERROR_BAD_REQUEST;
   2625 			goto error;
   2626 		}
   2627 		isc_buffer_usedregion(&decoded_buf, &data);
   2628 	} else if (socket->h2->request_type == ISC_HTTP_REQ_POST) {
   2629 		INSIST(socket->h2->content_length > 0);
   2630 		isc_buffer_usedregion(&socket->h2->rbuf, &data);
   2631 	} else {
   2632 		UNREACHABLE();
   2633 	}
   2634 
   2635 	server_call_cb(socket, ISC_R_SUCCESS, &data);
   2636 
   2637 	return 0;
   2638 
   2639 error:
   2640 	result = server_send_error_response(code, ngsession, socket);
   2641 	if (result != ISC_R_SUCCESS) {
   2642 		return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
   2643 	}
   2644 	return 0;
   2645 }
   2646 
   2647 static void
   2648 http_send_cb(void *arg);
   2649 
   2650 void
   2651 isc__nm_http_send(isc_nmhandle_t *handle, const isc_region_t *region,
   2652 		  isc_nm_cb_t cb, void *cbarg) {
   2653 	isc_nmsocket_t *sock = NULL;
   2654 	isc__nm_uvreq_t *uvreq = NULL;
   2655 
   2656 	REQUIRE(VALID_NMHANDLE(handle));
   2657 
   2658 	sock = handle->sock;
   2659 
   2660 	REQUIRE(VALID_NMSOCK(sock));
   2661 	REQUIRE(sock->tid == isc_tid());
   2662 
   2663 	uvreq = isc__nm_uvreq_get(sock);
   2664 	isc_nmhandle_attach(handle, &uvreq->handle);
   2665 	uvreq->cb.send = cb;
   2666 	uvreq->cbarg = cbarg;
   2667 
   2668 	uvreq->uvbuf.base = (char *)region->base;
   2669 	uvreq->uvbuf.len = region->length;
   2670 
   2671 	isc_job_run(sock->worker->loop, &uvreq->job, http_send_cb, uvreq);
   2672 }
   2673 
   2674 static void
   2675 failed_send_cb(isc_nmsocket_t *sock, isc__nm_uvreq_t *req,
   2676 	       isc_result_t eresult) {
   2677 	REQUIRE(VALID_NMSOCK(sock));
   2678 	REQUIRE(VALID_UVREQ(req));
   2679 
   2680 	if (req->cb.send != NULL) {
   2681 		isc__nm_sendcb(sock, req, eresult, true);
   2682 	} else {
   2683 		isc__nm_uvreq_put(&req);
   2684 	}
   2685 }
   2686 
   2687 static void
   2688 client_httpsend(isc_nmhandle_t *handle, isc_nmsocket_t *sock,
   2689 		isc__nm_uvreq_t *req) {
   2690 	isc_result_t result = ISC_R_SUCCESS;
   2691 	isc_nm_cb_t cb = req->cb.send;
   2692 	void *cbarg = req->cbarg;
   2693 
   2694 	result = client_send(
   2695 		handle,
   2696 		&(isc_region_t){ (uint8_t *)req->uvbuf.base, req->uvbuf.len });
   2697 	if (result != ISC_R_SUCCESS) {
   2698 		failed_send_cb(sock, req, result);
   2699 		return;
   2700 	}
   2701 
   2702 	http_do_bio(sock->h2->session, handle, cb, cbarg);
   2703 	isc__nm_uvreq_put(&req);
   2704 }
   2705 
   2706 static void
   2707 server_httpsend(isc_nmhandle_t *handle, isc_nmsocket_t *sock,
   2708 		isc__nm_uvreq_t *req) {
   2709 	size_t content_len_buf_len, cache_control_buf_len;
   2710 	isc_result_t result = ISC_R_SUCCESS;
   2711 	isc_nm_cb_t cb = req->cb.send;
   2712 	void *cbarg = req->cbarg;
   2713 	if (isc__nmsocket_closing(sock) ||
   2714 	    !http_session_active(handle->httpsession))
   2715 	{
   2716 		failed_send_cb(sock, req, ISC_R_CANCELED);
   2717 		return;
   2718 	}
   2719 
   2720 	INSIST(handle->sock->tid == isc_tid());
   2721 	INSIST(VALID_NMHANDLE(handle->httpsession->handle));
   2722 	INSIST(VALID_NMSOCK(handle->httpsession->handle->sock));
   2723 
   2724 	isc_buffer_init(&sock->h2->wbuf, req->uvbuf.base, req->uvbuf.len);
   2725 	isc_buffer_add(&sock->h2->wbuf, req->uvbuf.len);
   2726 
   2727 	content_len_buf_len = snprintf(sock->h2->clenbuf,
   2728 				       sizeof(sock->h2->clenbuf), "%lu",
   2729 				       (unsigned long)req->uvbuf.len);
   2730 	if (sock->h2->min_ttl == 0) {
   2731 		cache_control_buf_len =
   2732 			snprintf(sock->h2->cache_control_buf,
   2733 				 sizeof(sock->h2->cache_control_buf), "%s",
   2734 				 DEFAULT_CACHE_CONTROL);
   2735 	} else {
   2736 		cache_control_buf_len =
   2737 			snprintf(sock->h2->cache_control_buf,
   2738 				 sizeof(sock->h2->cache_control_buf),
   2739 				 "max-age=%" PRIu32, sock->h2->min_ttl);
   2740 	}
   2741 	const nghttp2_nv hdrs[] = { MAKE_NV2(":status", "200"),
   2742 				    MAKE_NV2("Content-Type", DNS_MEDIA_TYPE),
   2743 				    MAKE_NV("Content-Length", sock->h2->clenbuf,
   2744 					    content_len_buf_len),
   2745 				    MAKE_NV("Cache-Control",
   2746 					    sock->h2->cache_control_buf,
   2747 					    cache_control_buf_len) };
   2748 
   2749 	result = server_send_response(handle->httpsession->ngsession,
   2750 				      sock->h2->stream_id, hdrs,
   2751 				      sizeof(hdrs) / sizeof(nghttp2_nv), sock);
   2752 
   2753 	if (result == ISC_R_SUCCESS) {
   2754 		http_do_bio(handle->httpsession, handle, cb, cbarg);
   2755 	} else {
   2756 		cb(handle, result, cbarg);
   2757 	}
   2758 
   2759 	isc_buffer_initnull(&sock->h2->wbuf);
   2760 	isc__nm_uvreq_put(&req);
   2761 }
   2762 
   2763 static void
   2764 http_send_cb(void *arg) {
   2765 	isc__nm_uvreq_t *req = arg;
   2766 
   2767 	REQUIRE(VALID_UVREQ(req));
   2768 
   2769 	isc_nmsocket_t *sock = req->sock;
   2770 
   2771 	REQUIRE(VALID_NMSOCK(sock));
   2772 	REQUIRE(VALID_HTTP2_SESSION(sock->h2->session));
   2773 
   2774 	isc_nmhandle_t *handle = req->handle;
   2775 
   2776 	REQUIRE(VALID_NMHANDLE(handle));
   2777 
   2778 	isc_nm_http_session_t *session = sock->h2->session;
   2779 	if (session != NULL && session->client) {
   2780 		client_httpsend(handle, sock, req);
   2781 	} else {
   2782 		server_httpsend(handle, sock, req);
   2783 	}
   2784 }
   2785 
   2786 void
   2787 isc__nm_http_read(isc_nmhandle_t *handle, isc_nm_recv_cb_t cb, void *cbarg) {
   2788 	isc_result_t result;
   2789 	http_cstream_t *cstream = NULL;
   2790 	isc_nm_http_session_t *session = NULL;
   2791 
   2792 	REQUIRE(VALID_NMHANDLE(handle));
   2793 
   2794 	session = handle->sock->h2->session;
   2795 	if (!http_session_active(session)) {
   2796 		cb(handle, ISC_R_CANCELED, NULL, cbarg);
   2797 		return;
   2798 	}
   2799 
   2800 	result = get_http_cstream(handle->sock, &cstream);
   2801 	if (result != ISC_R_SUCCESS) {
   2802 		return;
   2803 	}
   2804 
   2805 	handle->sock->h2->connect.cstream = cstream;
   2806 	cstream->read_cb = cb;
   2807 	cstream->read_cbarg = cbarg;
   2808 	cstream->reading = true;
   2809 
   2810 	if (cstream->sending) {
   2811 		result = client_submit_request(session, cstream);
   2812 		if (result != ISC_R_SUCCESS) {
   2813 			put_http_cstream(session->mctx, cstream);
   2814 			return;
   2815 		}
   2816 
   2817 		http_do_bio(session, NULL, NULL, NULL);
   2818 	}
   2819 }
   2820 
   2821 static int
   2822 server_on_frame_recv_callback(nghttp2_session *ngsession,
   2823 			      const nghttp2_frame *frame, void *user_data) {
   2824 	isc_nmsocket_t *socket = NULL;
   2825 
   2826 	UNUSED(user_data);
   2827 
   2828 	switch (frame->hd.type) {
   2829 	case NGHTTP2_DATA:
   2830 	case NGHTTP2_HEADERS:
   2831 		/* Check that the client request has finished */
   2832 		if (frame->hd.flags & NGHTTP2_FLAG_END_STREAM) {
   2833 			socket = nghttp2_session_get_stream_user_data(
   2834 				ngsession, frame->hd.stream_id);
   2835 
   2836 			/*
   2837 			 * For DATA and HEADERS frame,
   2838 			 * this callback may be called
   2839 			 * after
   2840 			 * on_stream_close_callback.
   2841 			 * Check that the stream is
   2842 			 * still alive.
   2843 			 */
   2844 			if (socket == NULL) {
   2845 				return 0;
   2846 			}
   2847 
   2848 			return server_on_request_recv(ngsession, socket);
   2849 		}
   2850 		break;
   2851 	default:
   2852 		break;
   2853 	}
   2854 	return 0;
   2855 }
   2856 
   2857 static void
   2858 initialize_nghttp2_server_session(isc_nm_http_session_t *session) {
   2859 	nghttp2_session_callbacks *callbacks = NULL;
   2860 	nghttp2_mem mem;
   2861 
   2862 	init_nghttp2_mem(session->mctx, &mem);
   2863 
   2864 	RUNTIME_CHECK(nghttp2_session_callbacks_new(&callbacks) == 0);
   2865 
   2866 	nghttp2_session_callbacks_set_on_data_chunk_recv_callback(
   2867 		callbacks, on_data_chunk_recv_callback);
   2868 
   2869 	nghttp2_session_callbacks_set_on_stream_close_callback(
   2870 		callbacks, on_stream_close_callback);
   2871 
   2872 	nghttp2_session_callbacks_set_on_header_callback(
   2873 		callbacks, server_on_header_callback);
   2874 
   2875 	nghttp2_session_callbacks_set_on_begin_headers_callback(
   2876 		callbacks, server_on_begin_headers_callback);
   2877 
   2878 	nghttp2_session_callbacks_set_on_frame_recv_callback(
   2879 		callbacks, server_on_frame_recv_callback);
   2880 
   2881 	RUNTIME_CHECK(nghttp2_session_server_new3(&session->ngsession,
   2882 						  callbacks, session, NULL,
   2883 						  &mem) == 0);
   2884 
   2885 	nghttp2_session_callbacks_del(callbacks);
   2886 }
   2887 
   2888 static int
   2889 server_send_connection_header(isc_nm_http_session_t *session) {
   2890 	nghttp2_settings_entry iv[1] = {
   2891 		{ NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS,
   2892 		  session->max_concurrent_streams }
   2893 	};
   2894 	int rv;
   2895 
   2896 	rv = nghttp2_submit_settings(session->ngsession, NGHTTP2_FLAG_NONE, iv,
   2897 				     1);
   2898 	if (rv != 0) {
   2899 		return -1;
   2900 	}
   2901 	return 0;
   2902 }
   2903 
   2904 /*
   2905  * It is advisable to disable Nagle's algorithm for HTTP/2
   2906  * connections because multiple HTTP/2 streams could be multiplexed
   2907  * over one transport connection. Thus, delays when delivering small
   2908  * packets could bring down performance for the whole session.
   2909  * HTTP/2 is meant to be used this way.
   2910  */
   2911 static void
   2912 http_transpost_tcp_nodelay(isc_nmhandle_t *transphandle) {
   2913 	(void)isc_nmhandle_set_tcp_nodelay(transphandle, true);
   2914 }
   2915 
   2916 static isc_result_t
   2917 httplisten_acceptcb(isc_nmhandle_t *handle, isc_result_t result, void *cbarg) {
   2918 	isc_nmsocket_t *httpserver = (isc_nmsocket_t *)cbarg;
   2919 	isc_nm_http_session_t *session = NULL;
   2920 
   2921 	REQUIRE(VALID_NMHANDLE(handle));
   2922 	REQUIRE(VALID_NMSOCK(handle->sock));
   2923 
   2924 	if (isc__nm_closing(handle->sock->worker)) {
   2925 		return ISC_R_SHUTTINGDOWN;
   2926 	} else if (result != ISC_R_SUCCESS) {
   2927 		return result;
   2928 	}
   2929 
   2930 	REQUIRE(VALID_NMSOCK(httpserver));
   2931 	REQUIRE(httpserver->type == isc_nm_httplistener);
   2932 
   2933 	http_initsocket(handle->sock);
   2934 
   2935 	http_transpost_tcp_nodelay(handle);
   2936 
   2937 	new_session(handle->sock->worker->mctx, NULL, &session);
   2938 	session->max_concurrent_streams =
   2939 		atomic_load_relaxed(&httpserver->h2->max_concurrent_streams);
   2940 	initialize_nghttp2_server_session(session);
   2941 	handle->sock->h2->session = session;
   2942 
   2943 	isc_nmhandle_attach(handle, &session->handle);
   2944 	isc__nmsocket_attach(httpserver, &session->serversocket);
   2945 	server_send_connection_header(session);
   2946 
   2947 	isc__nmhandle_set_manual_timer(session->handle, true);
   2948 
   2949 	/* TODO H2 */
   2950 	http_do_bio(session, NULL, NULL, NULL);
   2951 	return ISC_R_SUCCESS;
   2952 }
   2953 
   2954 isc_result_t
   2955 isc_nm_listenhttp(isc_nm_t *mgr, uint32_t workers, isc_sockaddr_t *iface,
   2956 		  int backlog, isc_quota_t *quota, isc_tlsctx_t *ctx,
   2957 		  isc_nm_http_endpoints_t *eps, uint32_t max_concurrent_streams,
   2958 		  isc_nm_proxy_type_t proxy_type, isc_nmsocket_t **sockp) {
   2959 	isc_nmsocket_t *sock = NULL;
   2960 	isc_result_t result = ISC_R_FAILURE;
   2961 	isc__networker_t *worker = NULL;
   2962 
   2963 	REQUIRE(VALID_NM(mgr));
   2964 	REQUIRE(!ISC_LIST_EMPTY(eps->handlers));
   2965 	REQUIRE(atomic_load(&eps->in_use) == false);
   2966 	REQUIRE(isc_tid() == 0);
   2967 
   2968 	worker = &mgr->workers[isc_tid()];
   2969 	sock = isc_mempool_get(worker->nmsocket_pool);
   2970 	isc__nmsocket_init(sock, worker, isc_nm_httplistener, iface, NULL);
   2971 	http_initsocket(sock);
   2972 	atomic_init(&sock->h2->max_concurrent_streams,
   2973 		    NGHTTP2_INITIAL_MAX_CONCURRENT_STREAMS);
   2974 
   2975 	isc_nmsocket_set_max_streams(sock, max_concurrent_streams);
   2976 
   2977 	atomic_store(&eps->in_use, true);
   2978 	http_init_listener_endpoints(sock, eps);
   2979 
   2980 	switch (proxy_type) {
   2981 	case ISC_NM_PROXY_NONE:
   2982 		if (ctx != NULL) {
   2983 			result = isc_nm_listentls(
   2984 				mgr, workers, iface, httplisten_acceptcb, sock,
   2985 				backlog, quota, ctx, false, &sock->outer);
   2986 		} else {
   2987 			result = isc_nm_listentcp(mgr, workers, iface,
   2988 						  httplisten_acceptcb, sock,
   2989 						  backlog, quota, &sock->outer);
   2990 		}
   2991 		break;
   2992 	case ISC_NM_PROXY_PLAIN:
   2993 		if (ctx != NULL) {
   2994 			result = isc_nm_listentls(
   2995 				mgr, workers, iface, httplisten_acceptcb, sock,
   2996 				backlog, quota, ctx, true, &sock->outer);
   2997 		} else {
   2998 			result = isc_nm_listenproxystream(
   2999 				mgr, workers, iface, httplisten_acceptcb, sock,
   3000 				backlog, quota, NULL, &sock->outer);
   3001 		}
   3002 		break;
   3003 	case ISC_NM_PROXY_ENCRYPTED:
   3004 		INSIST(ctx != NULL);
   3005 		result = isc_nm_listenproxystream(
   3006 			mgr, workers, iface, httplisten_acceptcb, sock, backlog,
   3007 			quota, ctx, &sock->outer);
   3008 		break;
   3009 	default:
   3010 		UNREACHABLE();
   3011 	}
   3012 
   3013 	if (result != ISC_R_SUCCESS) {
   3014 		sock->closed = true;
   3015 		isc__nmsocket_detach(&sock);
   3016 		return result;
   3017 	}
   3018 
   3019 	sock->nchildren = sock->outer->nchildren;
   3020 	sock->fd = (uv_os_sock_t)-1;
   3021 
   3022 	*sockp = sock;
   3023 	return ISC_R_SUCCESS;
   3024 }
   3025 
   3026 isc_nm_http_endpoints_t *
   3027 isc_nm_http_endpoints_new(isc_mem_t *mctx) {
   3028 	isc_nm_http_endpoints_t *restrict eps;
   3029 	REQUIRE(mctx != NULL);
   3030 
   3031 	eps = isc_mem_get(mctx, sizeof(*eps));
   3032 	*eps = (isc_nm_http_endpoints_t){ .mctx = NULL };
   3033 
   3034 	isc_mem_attach(mctx, &eps->mctx);
   3035 	ISC_LIST_INIT(eps->handlers);
   3036 	isc_refcount_init(&eps->references, 1);
   3037 	atomic_init(&eps->in_use, false);
   3038 	eps->magic = HTTP_ENDPOINTS_MAGIC;
   3039 
   3040 	return eps;
   3041 }
   3042 
   3043 void
   3044 isc_nm_http_endpoints_detach(isc_nm_http_endpoints_t **restrict epsp) {
   3045 	isc_nm_http_endpoints_t *restrict eps;
   3046 	isc_mem_t *mctx;
   3047 	isc_nm_httphandler_t *handler = NULL;
   3048 
   3049 	REQUIRE(epsp != NULL);
   3050 	eps = *epsp;
   3051 	REQUIRE(VALID_HTTP_ENDPOINTS(eps));
   3052 
   3053 	if (isc_refcount_decrement(&eps->references) > 1) {
   3054 		*epsp = NULL;
   3055 		return;
   3056 	}
   3057 
   3058 	mctx = eps->mctx;
   3059 
   3060 	/* Delete all handlers */
   3061 	handler = ISC_LIST_HEAD(eps->handlers);
   3062 	while (handler != NULL) {
   3063 		isc_nm_httphandler_t *next = NULL;
   3064 
   3065 		next = ISC_LIST_NEXT(handler, link);
   3066 		ISC_LIST_DEQUEUE(eps->handlers, handler, link);
   3067 		isc_mem_free(mctx, handler->path);
   3068 		handler->magic = 0;
   3069 		isc_mem_put(mctx, handler, sizeof(*handler));
   3070 		handler = next;
   3071 	}
   3072 
   3073 	eps->magic = 0;
   3074 
   3075 	isc_mem_putanddetach(&mctx, eps, sizeof(*eps));
   3076 	*epsp = NULL;
   3077 }
   3078 
   3079 void
   3080 isc_nm_http_endpoints_attach(isc_nm_http_endpoints_t *source,
   3081 			     isc_nm_http_endpoints_t **targetp) {
   3082 	REQUIRE(VALID_HTTP_ENDPOINTS(source));
   3083 	REQUIRE(targetp != NULL && *targetp == NULL);
   3084 
   3085 	isc_refcount_increment(&source->references);
   3086 
   3087 	*targetp = source;
   3088 }
   3089 
   3090 static isc_nm_httphandler_t *
   3091 http_endpoints_find(const char *request_path,
   3092 		    const isc_nm_http_endpoints_t *restrict eps) {
   3093 	isc_nm_httphandler_t *handler = NULL;
   3094 
   3095 	REQUIRE(VALID_HTTP_ENDPOINTS(eps));
   3096 
   3097 	if (request_path == NULL || *request_path == '\0') {
   3098 		return NULL;
   3099 	}
   3100 
   3101 	for (handler = ISC_LIST_HEAD(eps->handlers); handler != NULL;
   3102 	     handler = ISC_LIST_NEXT(handler, link))
   3103 	{
   3104 		if (!strcmp(request_path, handler->path)) {
   3105 			INSIST(VALID_HTTP_HANDLER(handler));
   3106 			INSIST(handler->cb != NULL);
   3107 			break;
   3108 		}
   3109 	}
   3110 
   3111 	return handler;
   3112 }
   3113 
   3114 isc_result_t
   3115 isc_nm_http_endpoints_add(isc_nm_http_endpoints_t *restrict eps,
   3116 			  const char *uri, const isc_nm_recv_cb_t cb,
   3117 			  void *cbarg) {
   3118 	isc_mem_t *mctx;
   3119 	isc_nm_httphandler_t *restrict handler = NULL;
   3120 
   3121 	REQUIRE(VALID_HTTP_ENDPOINTS(eps));
   3122 	REQUIRE(isc_nm_http_path_isvalid(uri));
   3123 	REQUIRE(cb != NULL);
   3124 	REQUIRE(atomic_load(&eps->in_use) == false);
   3125 
   3126 	mctx = eps->mctx;
   3127 
   3128 	if (http_endpoints_find(uri, eps) == NULL) {
   3129 		handler = isc_mem_get(mctx, sizeof(*handler));
   3130 		*handler = (isc_nm_httphandler_t){
   3131 			.cb = cb,
   3132 			.cbarg = cbarg,
   3133 			.path = isc_mem_strdup(mctx, uri),
   3134 			.link = ISC_LINK_INITIALIZER,
   3135 			.magic = HTTP_HANDLER_MAGIC
   3136 		};
   3137 
   3138 		ISC_LIST_APPEND(eps->handlers, handler, link);
   3139 	}
   3140 
   3141 	return ISC_R_SUCCESS;
   3142 }
   3143 
   3144 void
   3145 isc__nm_http_stoplistening(isc_nmsocket_t *sock) {
   3146 	REQUIRE(VALID_NMSOCK(sock));
   3147 	REQUIRE(sock->type == isc_nm_httplistener);
   3148 	REQUIRE(isc_tid() == sock->tid);
   3149 
   3150 	isc__nmsocket_stop(sock);
   3151 }
   3152 
   3153 static void
   3154 http_close_direct(isc_nmsocket_t *sock) {
   3155 	isc_nm_http_session_t *session = NULL;
   3156 
   3157 	REQUIRE(VALID_NMSOCK(sock));
   3158 
   3159 	sock->closed = true;
   3160 	sock->active = false;
   3161 	session = sock->h2->session;
   3162 
   3163 	if (session != NULL && session->sending == 0 && !session->reading) {
   3164 		/*
   3165 		 * The socket is going to be closed too early without been
   3166 		 * used even once (might happen in a case of low level
   3167 		 * error).
   3168 		 */
   3169 		finish_http_session(session);
   3170 	} else if (session != NULL && session->handle) {
   3171 		http_do_bio(session, NULL, NULL, NULL);
   3172 	}
   3173 }
   3174 
   3175 static void
   3176 http_close_cb(void *arg) {
   3177 	isc_nmsocket_t *sock = arg;
   3178 	REQUIRE(VALID_NMSOCK(sock));
   3179 
   3180 	http_close_direct(sock);
   3181 	isc__nmsocket_detach(&sock);
   3182 }
   3183 
   3184 void
   3185 isc__nm_http_close(isc_nmsocket_t *sock) {
   3186 	bool destroy = false;
   3187 	REQUIRE(VALID_NMSOCK(sock));
   3188 	REQUIRE(sock->type == isc_nm_httpsocket);
   3189 	REQUIRE(!isc__nmsocket_active(sock));
   3190 	REQUIRE(!sock->closing);
   3191 
   3192 	sock->closing = true;
   3193 
   3194 	if (sock->h2->session != NULL && sock->h2->session->closed &&
   3195 	    sock->tid == isc_tid())
   3196 	{
   3197 		isc__nm_httpsession_detach(&sock->h2->session);
   3198 		destroy = true;
   3199 	} else if (sock->h2->session == NULL && sock->tid == isc_tid()) {
   3200 		destroy = true;
   3201 	}
   3202 
   3203 	if (destroy) {
   3204 		http_close_direct(sock);
   3205 		isc__nmsocket_prep_destroy(sock);
   3206 		return;
   3207 	}
   3208 
   3209 	isc__nmsocket_attach(sock, &(isc_nmsocket_t *){ NULL });
   3210 	isc_async_run(sock->worker->loop, http_close_cb, sock);
   3211 }
   3212 
   3213 static void
   3214 failed_httpstream_read_cb(isc_nmsocket_t *sock, isc_result_t result,
   3215 			  isc_nm_http_session_t *session) {
   3216 	isc_region_t data;
   3217 	REQUIRE(VALID_NMSOCK(sock));
   3218 	INSIST(sock->type == isc_nm_httpsocket);
   3219 
   3220 	if (sock->h2->request_path == NULL) {
   3221 		return;
   3222 	}
   3223 
   3224 	(void)nghttp2_submit_rst_stream(
   3225 		session->ngsession, NGHTTP2_FLAG_END_STREAM,
   3226 		sock->h2->stream_id, NGHTTP2_REFUSED_STREAM);
   3227 	isc_buffer_usedregion(&sock->h2->rbuf, &data);
   3228 	server_call_cb(sock, result, &data);
   3229 }
   3230 
   3231 static void
   3232 client_call_failed_read_cb(isc_result_t result,
   3233 			   isc_nm_http_session_t *session) {
   3234 	http_cstream_t *cstream = NULL;
   3235 
   3236 	REQUIRE(VALID_HTTP2_SESSION(session));
   3237 	REQUIRE(result != ISC_R_SUCCESS);
   3238 
   3239 	cstream = ISC_LIST_HEAD(session->cstreams);
   3240 	while (cstream != NULL) {
   3241 		http_cstream_t *next = ISC_LIST_NEXT(cstream, link);
   3242 
   3243 		/*
   3244 		 * read_cb could be NULL if cstream was allocated and added
   3245 		 * to the tracking list, but was not properly initialized due
   3246 		 * to a low-level error. It is safe to get rid of the object
   3247 		 * in such a case.
   3248 		 */
   3249 		if (cstream->read_cb != NULL) {
   3250 			isc_region_t read_data;
   3251 			isc_buffer_usedregion(cstream->rbuf, &read_data);
   3252 			cstream->read_cb(session->client_httphandle, result,
   3253 					 &read_data, cstream->read_cbarg);
   3254 		}
   3255 
   3256 		if (result != ISC_R_TIMEDOUT || cstream->read_cb == NULL ||
   3257 		    !(session->handle != NULL &&
   3258 		      isc__nmsocket_timer_running(session->handle->sock)))
   3259 		{
   3260 			ISC_LIST_DEQUEUE(session->cstreams, cstream, link);
   3261 			put_http_cstream(session->mctx, cstream);
   3262 		}
   3263 
   3264 		cstream = next;
   3265 	}
   3266 }
   3267 
   3268 static void
   3269 server_call_failed_read_cb(isc_result_t result,
   3270 			   isc_nm_http_session_t *session) {
   3271 	isc_nmsocket_h2_t *h2data = NULL; /* stream socket */
   3272 
   3273 	REQUIRE(VALID_HTTP2_SESSION(session));
   3274 	REQUIRE(result != ISC_R_SUCCESS);
   3275 
   3276 	for (h2data = ISC_LIST_HEAD(session->sstreams); h2data != NULL;
   3277 	     h2data = ISC_LIST_NEXT(h2data, link))
   3278 	{
   3279 		failed_httpstream_read_cb(h2data->psock, result, session);
   3280 	}
   3281 
   3282 	h2data = ISC_LIST_HEAD(session->sstreams);
   3283 	while (h2data != NULL) {
   3284 		isc_nmsocket_h2_t *next = ISC_LIST_NEXT(h2data, link);
   3285 		ISC_LIST_DEQUEUE(session->sstreams, h2data, link);
   3286 		/* Cleanup socket in place */
   3287 		h2data->psock->active = false;
   3288 		h2data->psock->closed = true;
   3289 		isc__nmsocket_detach(&h2data->psock);
   3290 
   3291 		h2data = next;
   3292 	}
   3293 }
   3294 
   3295 static void
   3296 failed_read_cb(isc_result_t result, isc_nm_http_session_t *session) {
   3297 	if (session->client) {
   3298 		client_call_failed_read_cb(result, session);
   3299 		/*
   3300 		 * If result was ISC_R_TIMEDOUT and the timer was reset,
   3301 		 * then we still have active streams and should not close
   3302 		 * the session.
   3303 		 */
   3304 		if (ISC_LIST_EMPTY(session->cstreams)) {
   3305 			finish_http_session(session);
   3306 		}
   3307 	} else {
   3308 		server_call_failed_read_cb(result, session);
   3309 		/*
   3310 		 * All streams are now destroyed; close the session.
   3311 		 */
   3312 		finish_http_session(session);
   3313 	}
   3314 }
   3315 
   3316 void
   3317 isc__nm_http_set_maxage(isc_nmhandle_t *handle, const uint32_t ttl) {
   3318 	isc_nm_http_session_t *session;
   3319 	isc_nmsocket_t *sock;
   3320 
   3321 	REQUIRE(VALID_NMHANDLE(handle));
   3322 	REQUIRE(VALID_NMSOCK(handle->sock));
   3323 
   3324 	sock = handle->sock;
   3325 	session = sock->h2->session;
   3326 
   3327 	INSIST(VALID_HTTP2_SESSION(session));
   3328 	INSIST(!session->client);
   3329 
   3330 	sock->h2->min_ttl = ttl;
   3331 }
   3332 
   3333 bool
   3334 isc__nm_http_has_encryption(const isc_nmhandle_t *handle) {
   3335 	isc_nm_http_session_t *session;
   3336 	isc_nmsocket_t *sock;
   3337 
   3338 	REQUIRE(VALID_NMHANDLE(handle));
   3339 	REQUIRE(VALID_NMSOCK(handle->sock));
   3340 
   3341 	sock = handle->sock;
   3342 	session = sock->h2->session;
   3343 
   3344 	INSIST(VALID_HTTP2_SESSION(session));
   3345 
   3346 	if (session->handle == NULL) {
   3347 		return false;
   3348 	}
   3349 
   3350 	return isc_nm_has_encryption(session->handle);
   3351 }
   3352 
   3353 const char *
   3354 isc__nm_http_verify_tls_peer_result_string(const isc_nmhandle_t *handle) {
   3355 	isc_nmsocket_t *sock = NULL;
   3356 	isc_nm_http_session_t *session;
   3357 
   3358 	REQUIRE(VALID_NMHANDLE(handle));
   3359 	REQUIRE(VALID_NMSOCK(handle->sock));
   3360 	REQUIRE(handle->sock->type == isc_nm_httpsocket);
   3361 
   3362 	sock = handle->sock;
   3363 	session = sock->h2->session;
   3364 
   3365 	/*
   3366 	 * In the case of a low-level error the session->handle is not
   3367 	 * attached nor session object is created.
   3368 	 */
   3369 	if (session == NULL && sock->h2->connect.tls_peer_verify_string != NULL)
   3370 	{
   3371 		return sock->h2->connect.tls_peer_verify_string;
   3372 	}
   3373 
   3374 	if (session == NULL) {
   3375 		return NULL;
   3376 	}
   3377 
   3378 	INSIST(VALID_HTTP2_SESSION(session));
   3379 
   3380 	if (session->handle == NULL) {
   3381 		return NULL;
   3382 	}
   3383 
   3384 	return isc_nm_verify_tls_peer_result_string(session->handle);
   3385 }
   3386 
   3387 void
   3388 isc__nm_http_set_tlsctx(isc_nmsocket_t *listener, isc_tlsctx_t *tlsctx) {
   3389 	REQUIRE(VALID_NMSOCK(listener));
   3390 	REQUIRE(listener->type == isc_nm_httplistener);
   3391 
   3392 	isc_nmsocket_set_tlsctx(listener->outer, tlsctx);
   3393 }
   3394 
   3395 void
   3396 isc__nm_http_set_max_streams(isc_nmsocket_t *listener,
   3397 			     const uint32_t max_concurrent_streams) {
   3398 	uint32_t max_streams = NGHTTP2_INITIAL_MAX_CONCURRENT_STREAMS;
   3399 
   3400 	REQUIRE(VALID_NMSOCK(listener));
   3401 	REQUIRE(listener->type == isc_nm_httplistener);
   3402 
   3403 	if (max_concurrent_streams > 0 &&
   3404 	    max_concurrent_streams < NGHTTP2_INITIAL_MAX_CONCURRENT_STREAMS)
   3405 	{
   3406 		max_streams = max_concurrent_streams;
   3407 	}
   3408 
   3409 	atomic_store_relaxed(&listener->h2->max_concurrent_streams,
   3410 			     max_streams);
   3411 }
   3412 
   3413 typedef struct http_endpoints_data {
   3414 	isc_nmsocket_t *listener;
   3415 	isc_nm_http_endpoints_t *endpoints;
   3416 } http_endpoints_data_t;
   3417 
   3418 static void
   3419 http_set_endpoints_cb(void *arg) {
   3420 	http_endpoints_data_t *data = arg;
   3421 	const int tid = isc_tid();
   3422 	isc_nmsocket_t *listener = data->listener;
   3423 	isc_nm_http_endpoints_t *endpoints = data->endpoints;
   3424 	isc__networker_t *worker = &listener->worker->netmgr->workers[tid];
   3425 
   3426 	isc_mem_put(worker->loop->mctx, data, sizeof(*data));
   3427 
   3428 	isc_nm_http_endpoints_detach(&listener->h2->listener_endpoints[tid]);
   3429 	isc_nm_http_endpoints_attach(endpoints,
   3430 				     &listener->h2->listener_endpoints[tid]);
   3431 
   3432 	isc_nm_http_endpoints_detach(&endpoints);
   3433 	isc__nmsocket_detach(&listener);
   3434 }
   3435 
   3436 void
   3437 isc_nm_http_set_endpoints(isc_nmsocket_t *listener,
   3438 			  isc_nm_http_endpoints_t *eps) {
   3439 	isc_loopmgr_t *loopmgr = NULL;
   3440 
   3441 	REQUIRE(VALID_NMSOCK(listener));
   3442 	REQUIRE(listener->type == isc_nm_httplistener);
   3443 	REQUIRE(VALID_HTTP_ENDPOINTS(eps));
   3444 
   3445 	loopmgr = listener->worker->netmgr->loopmgr;
   3446 
   3447 	atomic_store(&eps->in_use, true);
   3448 
   3449 	for (size_t i = 0; i < isc_loopmgr_nloops(loopmgr); i++) {
   3450 		isc__networker_t *worker =
   3451 			&listener->worker->netmgr->workers[i];
   3452 		http_endpoints_data_t *data = isc_mem_cget(worker->loop->mctx,
   3453 							   1, sizeof(*data));
   3454 
   3455 		isc__nmsocket_attach(listener, &data->listener);
   3456 		isc_nm_http_endpoints_attach(eps, &data->endpoints);
   3457 
   3458 		isc_async_run(worker->loop, http_set_endpoints_cb, data);
   3459 	}
   3460 }
   3461 
   3462 static void
   3463 http_init_listener_endpoints(isc_nmsocket_t *listener,
   3464 			     isc_nm_http_endpoints_t *epset) {
   3465 	size_t nworkers;
   3466 	isc_loopmgr_t *loopmgr = NULL;
   3467 
   3468 	REQUIRE(VALID_NMSOCK(listener));
   3469 	REQUIRE(listener->worker != NULL && VALID_NM(listener->worker->netmgr));
   3470 	REQUIRE(VALID_HTTP_ENDPOINTS(epset));
   3471 
   3472 	loopmgr = listener->worker->netmgr->loopmgr;
   3473 	nworkers = (size_t)isc_loopmgr_nloops(loopmgr);
   3474 	INSIST(nworkers > 0);
   3475 
   3476 	listener->h2->listener_endpoints =
   3477 		isc_mem_cget(listener->worker->mctx, nworkers,
   3478 			     sizeof(isc_nm_http_endpoints_t *));
   3479 	listener->h2->n_listener_endpoints = nworkers;
   3480 	for (size_t i = 0; i < nworkers; i++) {
   3481 		listener->h2->listener_endpoints[i] = NULL;
   3482 		isc_nm_http_endpoints_attach(
   3483 			epset, &listener->h2->listener_endpoints[i]);
   3484 	}
   3485 }
   3486 
   3487 static void
   3488 http_cleanup_listener_endpoints(isc_nmsocket_t *listener) {
   3489 	REQUIRE(listener->worker != NULL && VALID_NM(listener->worker->netmgr));
   3490 
   3491 	if (listener->h2->listener_endpoints == NULL) {
   3492 		return;
   3493 	}
   3494 
   3495 	for (size_t i = 0; i < listener->h2->n_listener_endpoints; i++) {
   3496 		isc_nm_http_endpoints_detach(
   3497 			&listener->h2->listener_endpoints[i]);
   3498 	}
   3499 	isc_mem_cput(listener->worker->mctx, listener->h2->listener_endpoints,
   3500 		     listener->h2->n_listener_endpoints,
   3501 		     sizeof(isc_nm_http_endpoints_t *));
   3502 	listener->h2->n_listener_endpoints = 0;
   3503 }
   3504 
   3505 static isc_nm_http_endpoints_t *
   3506 http_get_listener_endpoints(isc_nmsocket_t *listener, const int tid) {
   3507 	isc_nm_http_endpoints_t *eps;
   3508 	REQUIRE(VALID_NMSOCK(listener));
   3509 	REQUIRE(tid >= 0);
   3510 	REQUIRE((size_t)tid < listener->h2->n_listener_endpoints);
   3511 
   3512 	eps = listener->h2->listener_endpoints[tid];
   3513 	INSIST(eps != NULL);
   3514 	return eps;
   3515 }
   3516 
   3517 static const bool base64url_validation_table[256] = {
   3518 	false, false, false, false, false, false, false, false, false, false,
   3519 	false, false, false, false, false, false, false, false, false, false,
   3520 	false, false, false, false, false, false, false, false, false, false,
   3521 	false, false, false, false, false, false, false, false, false, false,
   3522 	false, false, false, false, false, true,  false, false, true,  true,
   3523 	true,  true,  true,  true,  true,  true,  true,	 true,	false, false,
   3524 	false, false, false, false, false, true,  true,	 true,	true,  true,
   3525 	true,  true,  true,  true,  true,  true,  true,	 true,	true,  true,
   3526 	true,  true,  true,  true,  true,  true,  true,	 true,	true,  true,
   3527 	true,  false, false, false, false, true,  false, true,	true,  true,
   3528 	true,  true,  true,  true,  true,  true,  true,	 true,	true,  true,
   3529 	true,  true,  true,  true,  true,  true,  true,	 true,	true,  true,
   3530 	true,  true,  true,  false, false, false, false, false, false, false,
   3531 	false, false, false, false, false, false, false, false, false, false,
   3532 	false, false, false, false, false, false, false, false, false, false,
   3533 	false, false, false, false, false, false, false, false, false, false,
   3534 	false, false, false, false, false, false, false, false, false, false,
   3535 	false, false, false, false, false, false, false, false, false, false,
   3536 	false, false, false, false, false, false, false, false, false, false,
   3537 	false, false, false, false, false, false, false, false, false, false,
   3538 	false, false, false, false, false, false, false, false, false, false,
   3539 	false, false, false, false, false, false, false, false, false, false,
   3540 	false, false, false, false, false, false, false, false, false, false,
   3541 	false, false, false, false, false, false, false, false, false, false,
   3542 	false, false, false, false, false, false, false, false, false, false,
   3543 	false, false, false, false, false, false
   3544 };
   3545 
   3546 char *
   3547 isc__nm_base64url_to_base64(isc_mem_t *mem, const char *base64url,
   3548 			    const size_t base64url_len, size_t *res_len) {
   3549 	char *res = NULL;
   3550 	size_t i, k, len;
   3551 
   3552 	if (mem == NULL || base64url == NULL || base64url_len == 0) {
   3553 		return NULL;
   3554 	}
   3555 
   3556 	len = base64url_len % 4 ? base64url_len + (4 - base64url_len % 4)
   3557 				: base64url_len;
   3558 	res = isc_mem_allocate(mem, len + 1); /* '\0' */
   3559 
   3560 	for (i = 0; i < base64url_len; i++) {
   3561 		switch (base64url[i]) {
   3562 		case '-':
   3563 			res[i] = '+';
   3564 			break;
   3565 		case '_':
   3566 			res[i] = '/';
   3567 			break;
   3568 		default:
   3569 			if (base64url_validation_table[(size_t)base64url[i]]) {
   3570 				res[i] = base64url[i];
   3571 			} else {
   3572 				isc_mem_free(mem, res);
   3573 				return NULL;
   3574 			}
   3575 			break;
   3576 		}
   3577 	}
   3578 
   3579 	if (base64url_len % 4 != 0) {
   3580 		for (k = 0; k < (4 - base64url_len % 4); k++, i++) {
   3581 			res[i] = '=';
   3582 		}
   3583 	}
   3584 
   3585 	INSIST(i == len);
   3586 
   3587 	SET_IF_NOT_NULL(res_len, len);
   3588 
   3589 	res[len] = '\0';
   3590 
   3591 	return res;
   3592 }
   3593 
   3594 char *
   3595 isc__nm_base64_to_base64url(isc_mem_t *mem, const char *base64,
   3596 			    const size_t base64_len, size_t *res_len) {
   3597 	char *res = NULL;
   3598 	size_t i;
   3599 
   3600 	if (mem == NULL || base64 == NULL || base64_len == 0) {
   3601 		return NULL;
   3602 	}
   3603 
   3604 	res = isc_mem_allocate(mem, base64_len + 1); /* '\0' */
   3605 
   3606 	for (i = 0; i < base64_len; i++) {
   3607 		switch (base64[i]) {
   3608 		case '+':
   3609 			res[i] = '-';
   3610 			break;
   3611 		case '/':
   3612 			res[i] = '_';
   3613 			break;
   3614 		case '=':
   3615 			goto end;
   3616 			break;
   3617 		default:
   3618 			/*
   3619 			 * All other characters from
   3620 			 * the alphabet are the same
   3621 			 * for both base64 and
   3622 			 * base64url, so we can reuse
   3623 			 * the validation table for
   3624 			 * the rest of the characters.
   3625 			 */
   3626 			if (base64[i] != '-' && base64[i] != '_' &&
   3627 			    base64url_validation_table[(size_t)base64[i]])
   3628 			{
   3629 				res[i] = base64[i];
   3630 			} else {
   3631 				isc_mem_free(mem, res);
   3632 				return NULL;
   3633 			}
   3634 			break;
   3635 		}
   3636 	}
   3637 end:
   3638 	SET_IF_NOT_NULL(res_len, i);
   3639 
   3640 	res[i] = '\0';
   3641 
   3642 	return res;
   3643 }
   3644 
   3645 static void
   3646 http_initsocket(isc_nmsocket_t *sock) {
   3647 	REQUIRE(sock != NULL);
   3648 
   3649 	sock->h2 = isc_mem_get(sock->worker->mctx, sizeof(*sock->h2));
   3650 	*sock->h2 = (isc_nmsocket_h2_t){
   3651 		.request_type = ISC_HTTP_REQ_UNSUPPORTED,
   3652 		.request_scheme = ISC_HTTP_SCHEME_UNSUPPORTED,
   3653 	};
   3654 }
   3655 
   3656 void
   3657 isc__nm_http_cleanup_data(isc_nmsocket_t *sock) {
   3658 	switch (sock->type) {
   3659 	case isc_nm_httplistener:
   3660 	case isc_nm_httpsocket:
   3661 		if (sock->type == isc_nm_httplistener &&
   3662 		    sock->h2->listener_endpoints != NULL)
   3663 		{
   3664 			/* Delete all handlers */
   3665 			http_cleanup_listener_endpoints(sock);
   3666 		}
   3667 
   3668 		if (sock->type == isc_nm_httpsocket &&
   3669 		    sock->h2->peer_endpoints != NULL)
   3670 		{
   3671 			isc_nm_http_endpoints_detach(&sock->h2->peer_endpoints);
   3672 		}
   3673 
   3674 		if (sock->h2->request_path != NULL) {
   3675 			isc_mem_free(sock->worker->mctx,
   3676 				     sock->h2->request_path);
   3677 			sock->h2->request_path = NULL;
   3678 		}
   3679 
   3680 		if (sock->h2->query_data != NULL) {
   3681 			isc_mem_free(sock->worker->mctx, sock->h2->query_data);
   3682 			sock->h2->query_data = NULL;
   3683 		}
   3684 
   3685 		INSIST(sock->h2->connect.cstream == NULL);
   3686 
   3687 		if (isc_buffer_base(&sock->h2->rbuf) != NULL) {
   3688 			void *base = isc_buffer_base(&sock->h2->rbuf);
   3689 			isc_mem_free(sock->worker->mctx, base);
   3690 			isc_buffer_initnull(&sock->h2->rbuf);
   3691 		}
   3692 		FALLTHROUGH;
   3693 	case isc_nm_proxystreamlistener:
   3694 	case isc_nm_proxystreamsocket:
   3695 	case isc_nm_tcpsocket:
   3696 	case isc_nm_tlssocket:
   3697 		if (sock->h2 != NULL) {
   3698 			if (sock->h2->session != NULL) {
   3699 				if (sock->h2->connect.uri != NULL) {
   3700 					isc_mem_free(sock->worker->mctx,
   3701 						     sock->h2->connect.uri);
   3702 					sock->h2->connect.uri = NULL;
   3703 				}
   3704 				isc__nm_httpsession_detach(&sock->h2->session);
   3705 			}
   3706 
   3707 			isc_mem_put(sock->worker->mctx, sock->h2,
   3708 				    sizeof(*sock->h2));
   3709 		};
   3710 		break;
   3711 	default:
   3712 		break;
   3713 	}
   3714 }
   3715 
   3716 void
   3717 isc__nm_http_cleartimeout(isc_nmhandle_t *handle) {
   3718 	isc_nmsocket_t *sock = NULL;
   3719 
   3720 	REQUIRE(VALID_NMHANDLE(handle));
   3721 	REQUIRE(VALID_NMSOCK(handle->sock));
   3722 	REQUIRE(handle->sock->type == isc_nm_httpsocket);
   3723 
   3724 	sock = handle->sock;
   3725 	if (sock->h2->session != NULL && sock->h2->session->handle != NULL) {
   3726 		INSIST(VALID_HTTP2_SESSION(sock->h2->session));
   3727 		INSIST(VALID_NMHANDLE(sock->h2->session->handle));
   3728 		isc_nmhandle_cleartimeout(sock->h2->session->handle);
   3729 	}
   3730 }
   3731 
   3732 void
   3733 isc__nm_http_settimeout(isc_nmhandle_t *handle, uint32_t timeout) {
   3734 	isc_nmsocket_t *sock = NULL;
   3735 
   3736 	REQUIRE(VALID_NMHANDLE(handle));
   3737 	REQUIRE(VALID_NMSOCK(handle->sock));
   3738 	REQUIRE(handle->sock->type == isc_nm_httpsocket);
   3739 
   3740 	sock = handle->sock;
   3741 	if (sock->h2->session != NULL && sock->h2->session->handle != NULL) {
   3742 		INSIST(VALID_HTTP2_SESSION(sock->h2->session));
   3743 		INSIST(VALID_NMHANDLE(sock->h2->session->handle));
   3744 		isc_nmhandle_settimeout(sock->h2->session->handle, timeout);
   3745 	}
   3746 }
   3747 
   3748 void
   3749 isc__nmhandle_http_keepalive(isc_nmhandle_t *handle, bool value) {
   3750 	isc_nmsocket_t *sock = NULL;
   3751 
   3752 	REQUIRE(VALID_NMHANDLE(handle));
   3753 	REQUIRE(VALID_NMSOCK(handle->sock));
   3754 	REQUIRE(handle->sock->type == isc_nm_httpsocket);
   3755 
   3756 	sock = handle->sock;
   3757 	if (sock->h2->session != NULL && sock->h2->session->handle) {
   3758 		INSIST(VALID_HTTP2_SESSION(sock->h2->session));
   3759 		INSIST(VALID_NMHANDLE(sock->h2->session->handle));
   3760 
   3761 		isc_nmhandle_keepalive(sock->h2->session->handle, value);
   3762 	}
   3763 }
   3764 
   3765 void
   3766 isc_nm_http_makeuri(const bool https, const isc_sockaddr_t *sa,
   3767 		    const char *hostname, const uint16_t http_port,
   3768 		    const char *abs_path, char *outbuf,
   3769 		    const size_t outbuf_len) {
   3770 	char saddr[INET6_ADDRSTRLEN] = { 0 };
   3771 	int family;
   3772 	bool ipv6_addr = false;
   3773 	struct sockaddr_in6 sa6;
   3774 	uint16_t host_port = http_port;
   3775 	const char *host = NULL;
   3776 
   3777 	REQUIRE(outbuf != NULL);
   3778 	REQUIRE(outbuf_len != 0);
   3779 	REQUIRE(isc_nm_http_path_isvalid(abs_path));
   3780 
   3781 	/* If hostname is specified, use that. */
   3782 	if (hostname != NULL && hostname[0] != '\0') {
   3783 		/*
   3784 		 * The host name could be an IPv6 address. If so,
   3785 		 * wrap it between [ and ].
   3786 		 */
   3787 		if (inet_pton(AF_INET6, hostname, &sa6) == 1 &&
   3788 		    hostname[0] != '[')
   3789 		{
   3790 			ipv6_addr = true;
   3791 		}
   3792 		host = hostname;
   3793 	} else {
   3794 		/*
   3795 		 * A hostname was not specified; build one from
   3796 		 * the given IP address.
   3797 		 */
   3798 		INSIST(sa != NULL);
   3799 		family = ((const struct sockaddr *)&sa->type.sa)->sa_family;
   3800 		host_port = ntohs(family == AF_INET ? sa->type.sin.sin_port
   3801 						    : sa->type.sin6.sin6_port);
   3802 		ipv6_addr = family == AF_INET6;
   3803 		(void)inet_ntop(
   3804 			family,
   3805 			family == AF_INET
   3806 				? (const struct sockaddr *)&sa->type.sin.sin_addr
   3807 				: (const struct sockaddr *)&sa->type.sin6
   3808 					  .sin6_addr,
   3809 			saddr, sizeof(saddr));
   3810 		host = saddr;
   3811 	}
   3812 
   3813 	/*
   3814 	 * If the port number was not specified, the default
   3815 	 * depends on whether we're using encryption or not.
   3816 	 */
   3817 	if (host_port == 0) {
   3818 		host_port = https ? 443 : 80;
   3819 	}
   3820 
   3821 	(void)snprintf(outbuf, outbuf_len, "%s://%s%s%s:%u%s",
   3822 		       https ? "https" : "http", ipv6_addr ? "[" : "", host,
   3823 		       ipv6_addr ? "]" : "", host_port, abs_path);
   3824 }
   3825 
   3826 /*
   3827  * DoH GET Query String Scanner-less Recursive Descent Parser/Verifier
   3828  *
   3829  * It is based on the following grammar (using WSN/EBNF):
   3830  *
   3831  * S                = query-string.
   3832  * query-string     = ['?'] { key-value-pair } EOF.
   3833  * key-value-pair   = key '=' value [ '&' ].
   3834  * key              = ('_' | alpha) { '_' | alnum}.
   3835  * value            = value-char {value-char}.
   3836  * value-char       = unreserved-char | percent-charcode.
   3837  * unreserved-char  = alnum |'_' | '.' | '-' | '~'. (* RFC3986, Section 2.3 *)
   3838  * percent-charcode = '%' hexdigit hexdigit.
   3839  * ...
   3840  *
   3841  * Should be good enough.
   3842  */
   3843 typedef struct isc_httpparser_state {
   3844 	const char *str;
   3845 
   3846 	const char *last_key;
   3847 	size_t last_key_len;
   3848 
   3849 	const char *last_value;
   3850 	size_t last_value_len;
   3851 
   3852 	bool query_found;
   3853 	const char *query;
   3854 	size_t query_len;
   3855 } isc_httpparser_state_t;
   3856 
   3857 #define MATCH(ch)      (st->str[0] == (ch))
   3858 #define MATCH_ALPHA()  isalpha((unsigned char)(st->str[0]))
   3859 #define MATCH_DIGIT()  isdigit((unsigned char)(st->str[0]))
   3860 #define MATCH_ALNUM()  isalnum((unsigned char)(st->str[0]))
   3861 #define MATCH_XDIGIT() isxdigit((unsigned char)(st->str[0]))
   3862 #define ADVANCE()      st->str++
   3863 #define GETP()	       (st->str)
   3864 
   3865 static bool
   3866 rule_query_string(isc_httpparser_state_t *st);
   3867 
   3868 bool
   3869 isc__nm_parse_httpquery(const char *query_string, const char **start,
   3870 			size_t *len) {
   3871 	isc_httpparser_state_t state;
   3872 
   3873 	REQUIRE(start != NULL);
   3874 	REQUIRE(len != NULL);
   3875 
   3876 	if (query_string == NULL || query_string[0] == '\0') {
   3877 		return false;
   3878 	}
   3879 
   3880 	state = (isc_httpparser_state_t){ .str = query_string };
   3881 	if (!rule_query_string(&state)) {
   3882 		return false;
   3883 	}
   3884 
   3885 	if (!state.query_found) {
   3886 		return false;
   3887 	}
   3888 
   3889 	*start = state.query;
   3890 	*len = state.query_len;
   3891 
   3892 	return true;
   3893 }
   3894 
   3895 static bool
   3896 rule_key_value_pair(isc_httpparser_state_t *st);
   3897 
   3898 static bool
   3899 rule_key(isc_httpparser_state_t *st);
   3900 
   3901 static bool
   3902 rule_value(isc_httpparser_state_t *st);
   3903 
   3904 static bool
   3905 rule_value_char(isc_httpparser_state_t *st);
   3906 
   3907 static bool
   3908 rule_percent_charcode(isc_httpparser_state_t *st);
   3909 
   3910 static bool
   3911 rule_unreserved_char(isc_httpparser_state_t *st);
   3912 
   3913 static bool
   3914 rule_query_string(isc_httpparser_state_t *st) {
   3915 	if (MATCH('?')) {
   3916 		ADVANCE();
   3917 	}
   3918 
   3919 	while (rule_key_value_pair(st)) {
   3920 		/* skip */;
   3921 	}
   3922 
   3923 	if (!MATCH('\0')) {
   3924 		return false;
   3925 	}
   3926 
   3927 	ADVANCE();
   3928 	return true;
   3929 }
   3930 
   3931 static bool
   3932 rule_key_value_pair(isc_httpparser_state_t *st) {
   3933 	if (!rule_key(st)) {
   3934 		return false;
   3935 	}
   3936 
   3937 	if (MATCH('=')) {
   3938 		ADVANCE();
   3939 	} else {
   3940 		return false;
   3941 	}
   3942 
   3943 	if (rule_value(st)) {
   3944 		const char dns[] = "dns";
   3945 		if (st->last_key_len == sizeof(dns) - 1 &&
   3946 		    memcmp(st->last_key, dns, sizeof(dns) - 1) == 0)
   3947 		{
   3948 			st->query_found = true;
   3949 			st->query = st->last_value;
   3950 			st->query_len = st->last_value_len;
   3951 		}
   3952 	} else {
   3953 		return false;
   3954 	}
   3955 
   3956 	if (MATCH('&')) {
   3957 		ADVANCE();
   3958 	}
   3959 
   3960 	return true;
   3961 }
   3962 
   3963 static bool
   3964 rule_key(isc_httpparser_state_t *st) {
   3965 	if (MATCH('_') || MATCH_ALPHA()) {
   3966 		st->last_key = GETP();
   3967 		ADVANCE();
   3968 	} else {
   3969 		return false;
   3970 	}
   3971 
   3972 	while (MATCH('_') || MATCH_ALNUM()) {
   3973 		ADVANCE();
   3974 	}
   3975 
   3976 	st->last_key_len = GETP() - st->last_key;
   3977 	return true;
   3978 }
   3979 
   3980 static bool
   3981 rule_value(isc_httpparser_state_t *st) {
   3982 	const char *s = GETP();
   3983 	if (!rule_value_char(st)) {
   3984 		return false;
   3985 	}
   3986 
   3987 	st->last_value = s;
   3988 	while (rule_value_char(st)) {
   3989 		/* skip */;
   3990 	}
   3991 	st->last_value_len = GETP() - st->last_value;
   3992 	return true;
   3993 }
   3994 
   3995 static bool
   3996 rule_value_char(isc_httpparser_state_t *st) {
   3997 	if (rule_unreserved_char(st)) {
   3998 		return true;
   3999 	}
   4000 
   4001 	return rule_percent_charcode(st);
   4002 }
   4003 
   4004 static bool
   4005 rule_unreserved_char(isc_httpparser_state_t *st) {
   4006 	if (MATCH_ALNUM() || MATCH('_') || MATCH('.') || MATCH('-') ||
   4007 	    MATCH('~'))
   4008 	{
   4009 		ADVANCE();
   4010 		return true;
   4011 	}
   4012 	return false;
   4013 }
   4014 
   4015 static bool
   4016 rule_percent_charcode(isc_httpparser_state_t *st) {
   4017 	if (MATCH('%')) {
   4018 		ADVANCE();
   4019 	} else {
   4020 		return false;
   4021 	}
   4022 
   4023 	if (!MATCH_XDIGIT()) {
   4024 		return false;
   4025 	}
   4026 	ADVANCE();
   4027 
   4028 	if (!MATCH_XDIGIT()) {
   4029 		return false;
   4030 	}
   4031 	ADVANCE();
   4032 
   4033 	return true;
   4034 }
   4035 
   4036 /*
   4037  * DoH URL Location Verifier. Based on the following grammar (EBNF/WSN
   4038  * notation):
   4039  *
   4040  * S             = path_absolute.
   4041  * path_absolute = '/' [ segments ] '\0'.
   4042  * segments      = segment_nz { slash_segment }.
   4043  * slash_segment = '/' segment.
   4044  * segment       = { pchar }.
   4045  * segment_nz    = pchar { pchar }.
   4046  * pchar         = unreserved | pct_encoded | sub_delims | ':' | '@'.
   4047  * unreserved    = ALPHA | DIGIT | '-' | '.' | '_' | '~'.
   4048  * pct_encoded   = '%' XDIGIT XDIGIT.
   4049  * sub_delims    = '!' | '$' | '&' | '\'' | '(' | ')' | '*' | '+' |
   4050  *                 ',' | ';' | '='.
   4051  *
   4052  * The grammar is extracted from RFC 3986. It is slightly modified to
   4053  * aid in parser creation, but the end result is the same
   4054  * (path_absolute is defined slightly differently - split into
   4055  * multiple productions).
   4056  *
   4057  * https://datatracker.ietf.org/doc/html/rfc3986#appendix-A
   4058  */
   4059 
   4060 typedef struct isc_http_location_parser_state {
   4061 	const char *str;
   4062 } isc_http_location_parser_state_t;
   4063 
   4064 static bool
   4065 rule_loc_path_absolute(isc_http_location_parser_state_t *);
   4066 
   4067 static bool
   4068 rule_loc_segments(isc_http_location_parser_state_t *);
   4069 
   4070 static bool
   4071 rule_loc_slash_segment(isc_http_location_parser_state_t *);
   4072 
   4073 static bool
   4074 rule_loc_segment(isc_http_location_parser_state_t *);
   4075 
   4076 static bool
   4077 rule_loc_segment_nz(isc_http_location_parser_state_t *);
   4078 
   4079 static bool
   4080 rule_loc_pchar(isc_http_location_parser_state_t *);
   4081 
   4082 static bool
   4083 rule_loc_unreserved(isc_http_location_parser_state_t *);
   4084 
   4085 static bool
   4086 rule_loc_pct_encoded(isc_http_location_parser_state_t *);
   4087 
   4088 static bool
   4089 rule_loc_sub_delims(isc_http_location_parser_state_t *);
   4090 
   4091 static bool
   4092 rule_loc_path_absolute(isc_http_location_parser_state_t *st) {
   4093 	if (MATCH('/')) {
   4094 		ADVANCE();
   4095 	} else {
   4096 		return false;
   4097 	}
   4098 
   4099 	(void)rule_loc_segments(st);
   4100 
   4101 	if (MATCH('\0')) {
   4102 		ADVANCE();
   4103 	} else {
   4104 		return false;
   4105 	}
   4106 
   4107 	return true;
   4108 }
   4109 
   4110 static bool
   4111 rule_loc_segments(isc_http_location_parser_state_t *st) {
   4112 	if (!rule_loc_segment_nz(st)) {
   4113 		return false;
   4114 	}
   4115 
   4116 	while (rule_loc_slash_segment(st)) {
   4117 		/* zero or more */;
   4118 	}
   4119 
   4120 	return true;
   4121 }
   4122 
   4123 static bool
   4124 rule_loc_slash_segment(isc_http_location_parser_state_t *st) {
   4125 	if (MATCH('/')) {
   4126 		ADVANCE();
   4127 	} else {
   4128 		return false;
   4129 	}
   4130 
   4131 	return rule_loc_segment(st);
   4132 }
   4133 
   4134 static bool
   4135 rule_loc_segment(isc_http_location_parser_state_t *st) {
   4136 	while (rule_loc_pchar(st)) {
   4137 		/* zero or more */;
   4138 	}
   4139 
   4140 	return true;
   4141 }
   4142 
   4143 static bool
   4144 rule_loc_segment_nz(isc_http_location_parser_state_t *st) {
   4145 	if (!rule_loc_pchar(st)) {
   4146 		return false;
   4147 	}
   4148 
   4149 	while (rule_loc_pchar(st)) {
   4150 		/* zero or more */;
   4151 	}
   4152 
   4153 	return true;
   4154 }
   4155 
   4156 static bool
   4157 rule_loc_pchar(isc_http_location_parser_state_t *st) {
   4158 	if (rule_loc_unreserved(st)) {
   4159 		return true;
   4160 	} else if (rule_loc_pct_encoded(st)) {
   4161 		return true;
   4162 	} else if (rule_loc_sub_delims(st)) {
   4163 		return true;
   4164 	} else if (MATCH(':') || MATCH('@')) {
   4165 		ADVANCE();
   4166 		return true;
   4167 	}
   4168 
   4169 	return false;
   4170 }
   4171 
   4172 static bool
   4173 rule_loc_unreserved(isc_http_location_parser_state_t *st) {
   4174 	if (MATCH_ALPHA() | MATCH_DIGIT() | MATCH('-') | MATCH('.') |
   4175 	    MATCH('_') | MATCH('~'))
   4176 	{
   4177 		ADVANCE();
   4178 		return true;
   4179 	}
   4180 	return false;
   4181 }
   4182 
   4183 static bool
   4184 rule_loc_pct_encoded(isc_http_location_parser_state_t *st) {
   4185 	if (!MATCH('%')) {
   4186 		return false;
   4187 	}
   4188 	ADVANCE();
   4189 
   4190 	if (!MATCH_XDIGIT()) {
   4191 		return false;
   4192 	}
   4193 	ADVANCE();
   4194 
   4195 	if (!MATCH_XDIGIT()) {
   4196 		return false;
   4197 	}
   4198 	ADVANCE();
   4199 
   4200 	return true;
   4201 }
   4202 
   4203 static bool
   4204 rule_loc_sub_delims(isc_http_location_parser_state_t *st) {
   4205 	if (MATCH('!') | MATCH('$') | MATCH('&') | MATCH('\'') | MATCH('(') |
   4206 	    MATCH(')') | MATCH('*') | MATCH('+') | MATCH(',') | MATCH(';') |
   4207 	    MATCH('='))
   4208 	{
   4209 		ADVANCE();
   4210 		return true;
   4211 	}
   4212 
   4213 	return false;
   4214 }
   4215 
   4216 bool
   4217 isc_nm_http_path_isvalid(const char *path) {
   4218 	isc_http_location_parser_state_t state = { 0 };
   4219 
   4220 	REQUIRE(path != NULL);
   4221 
   4222 	state.str = path;
   4223 
   4224 	return rule_loc_path_absolute(&state);
   4225 }
   4226