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