xref: /netbsd-src/external/mpl/bind/dist/tests/isc/doh_test.c (revision 0a3071956a3a9fdebdbf7f338cf2d439b45fc728)
1 /*	$NetBSD: doh_test.c,v 1.2 2024/02/21 22:52:50 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 <inttypes.h>
17 #include <sched.h> /* IWYU pragma: keep */
18 #include <setjmp.h>
19 #include <stdarg.h>
20 #include <stdbool.h>
21 #include <stddef.h>
22 #include <stdlib.h>
23 #include <time.h>
24 #include <unistd.h>
25 #include <uv.h>
26 
27 /*
28  * As a workaround, include an OpenSSL header file before including cmocka.h,
29  * because OpenSSL 3.1.0 uses __attribute__(malloc), conflicting with a
30  * redefined malloc in cmocka.h.
31  */
32 #include <openssl/err.h>
33 
34 #define UNIT_TESTING
35 #include <cmocka.h>
36 
37 #include <isc/atomic.h>
38 #include <isc/buffer.h>
39 #include <isc/condition.h>
40 #include <isc/mutex.h>
41 #include <isc/netmgr.h>
42 #include <isc/nonce.h>
43 #include <isc/os.h>
44 #include <isc/print.h>
45 #include <isc/refcount.h>
46 #include <isc/sockaddr.h>
47 #include <isc/thread.h>
48 
49 #include "uv_wrap.h"
50 #define KEEP_BEFORE
51 
52 #include "netmgr/http.c"
53 #include "netmgr/netmgr-int.h"
54 #include "netmgr/uv-compat.c"
55 #include "netmgr/uv-compat.h"
56 #include "netmgr_p.h"
57 
58 #include <tests/isc.h>
59 
60 #define MAX_NM 2
61 
62 static isc_sockaddr_t tcp_listen_addr;
63 
64 static uint64_t send_magic = 0;
65 static uint64_t stop_magic = 0;
66 
67 static uv_buf_t send_msg = { .base = (char *)&send_magic,
68 			     .len = sizeof(send_magic) };
69 
70 static atomic_int_fast64_t active_cconnects = 0;
71 static atomic_int_fast64_t nsends = 0;
72 static atomic_int_fast64_t ssends = 0;
73 static atomic_int_fast64_t sreads = 0;
74 static atomic_int_fast64_t csends = 0;
75 static atomic_int_fast64_t creads = 0;
76 static atomic_int_fast64_t ctimeouts = 0;
77 static atomic_int_fast64_t total_sends = 0;
78 
79 static atomic_bool was_error = false;
80 
81 static bool reuse_supported = true;
82 static bool noanswer = false;
83 
84 static atomic_bool POST = true;
85 
86 static atomic_bool slowdown = false;
87 
88 static atomic_bool use_TLS = false;
89 static isc_tlsctx_t *server_tlsctx = NULL;
90 static isc_tlsctx_t *client_tlsctx = NULL;
91 static isc_tlsctx_client_session_cache_t *client_sess_cache = NULL;
92 
93 static isc_quota_t listener_quota;
94 static atomic_bool check_listener_quota = false;
95 
96 static isc_nm_http_endpoints_t *endpoints = NULL;
97 
98 static bool skip_long_tests = false;
99 
100 /* Timeout for soft-timeout tests (0.05 seconds) */
101 #define T_SOFT 50
102 
103 #define NSENDS	100
104 #define NWRITES 10
105 
106 #define CHECK_RANGE_FULL(v)                                    \
107 	{                                                      \
108 		int __v = atomic_load(&v);                     \
109 		assert_true(__v >= atomic_load(&total_sends)); \
110 	}
111 
112 #define CHECK_RANGE_HALF(v)                                        \
113 	{                                                          \
114 		int __v = atomic_load(&v);                         \
115 		assert_true(__v >= atomic_load(&total_sends) / 2); \
116 	}
117 
118 /* Enable this to print values while running tests */
119 #undef PRINT_DEBUG
120 #ifdef PRINT_DEBUG
121 #define X(v) fprintf(stderr, #v " = %" PRIu64 "\n", atomic_load(&v))
122 #else
123 #define X(v)
124 #endif
125 
126 #define SKIP_IN_CI             \
127 	if (skip_long_tests) { \
128 		skip();        \
129 		return;        \
130 	}
131 
132 typedef struct csdata {
133 	isc_nm_recv_cb_t reply_cb;
134 	void *cb_arg;
135 	isc_region_t region;
136 } csdata_t;
137 
138 static void
139 connect_send_cb(isc_nmhandle_t *handle, isc_result_t result, void *arg) {
140 	csdata_t data;
141 
142 	(void)atomic_fetch_sub(&active_cconnects, 1);
143 	memmove(&data, arg, sizeof(data));
144 	isc_mem_put(handle->sock->mgr->mctx, arg, sizeof(data));
145 	if (result != ISC_R_SUCCESS) {
146 		goto error;
147 	}
148 
149 	REQUIRE(VALID_NMHANDLE(handle));
150 
151 	result = isc__nm_http_request(handle, &data.region, data.reply_cb,
152 				      data.cb_arg);
153 	if (result != ISC_R_SUCCESS) {
154 		goto error;
155 	}
156 
157 	isc_mem_put(handle->sock->mgr->mctx, data.region.base,
158 		    data.region.length);
159 	return;
160 error:
161 	data.reply_cb(handle, result, NULL, data.cb_arg);
162 	isc_mem_put(handle->sock->mgr->mctx, data.region.base,
163 		    data.region.length);
164 	if (result == ISC_R_TOOMANYOPENFILES) {
165 		atomic_store(&slowdown, true);
166 	} else {
167 		atomic_store(&was_error, true);
168 	}
169 }
170 
171 static void
172 connect_send_request(isc_nm_t *mgr, const char *uri, bool post,
173 		     isc_region_t *region, isc_nm_recv_cb_t cb, void *cbarg,
174 		     bool tls, unsigned int timeout) {
175 	isc_region_t copy;
176 	csdata_t *data = NULL;
177 	isc_tlsctx_t *ctx = NULL;
178 
179 	copy = (isc_region_t){ .base = isc_mem_get(mgr->mctx, region->length),
180 			       .length = region->length };
181 	memmove(copy.base, region->base, region->length);
182 	data = isc_mem_get(mgr->mctx, sizeof(*data));
183 	*data = (csdata_t){ .reply_cb = cb, .cb_arg = cbarg, .region = copy };
184 	if (tls) {
185 		ctx = client_tlsctx;
186 	}
187 
188 	isc_nm_httpconnect(mgr, NULL, &tcp_listen_addr, uri, post,
189 			   connect_send_cb, data, ctx, client_sess_cache,
190 			   timeout, 0);
191 }
192 
193 static int
194 setup_ephemeral_port(isc_sockaddr_t *addr, sa_family_t family) {
195 	isc_result_t result;
196 	socklen_t addrlen = sizeof(*addr);
197 	int fd;
198 	int r;
199 
200 	isc_sockaddr_fromin6(addr, &in6addr_loopback, 0);
201 
202 	fd = socket(AF_INET6, family, 0);
203 	if (fd < 0) {
204 		perror("setup_ephemeral_port: socket()");
205 		return (-1);
206 	}
207 
208 	r = bind(fd, (const struct sockaddr *)&addr->type.sa,
209 		 sizeof(addr->type.sin6));
210 	if (r != 0) {
211 		perror("setup_ephemeral_port: bind()");
212 		isc__nm_closesocket(fd);
213 		return (r);
214 	}
215 
216 	r = getsockname(fd, (struct sockaddr *)&addr->type.sa, &addrlen);
217 	if (r != 0) {
218 		perror("setup_ephemeral_port: getsockname()");
219 		isc__nm_closesocket(fd);
220 		return (r);
221 	}
222 
223 	result = isc__nm_socket_reuse(fd);
224 	if (result != ISC_R_SUCCESS && result != ISC_R_NOTIMPLEMENTED) {
225 		fprintf(stderr,
226 			"setup_ephemeral_port: isc__nm_socket_reuse(): %s",
227 			isc_result_totext(result));
228 		close(fd);
229 		return (-1);
230 	}
231 
232 	result = isc__nm_socket_reuse_lb(fd);
233 	if (result != ISC_R_SUCCESS && result != ISC_R_NOTIMPLEMENTED) {
234 		fprintf(stderr,
235 			"setup_ephemeral_port: isc__nm_socket_reuse_lb(): %s",
236 			isc_result_totext(result));
237 		close(fd);
238 		return (-1);
239 	}
240 	if (result == ISC_R_NOTIMPLEMENTED) {
241 		reuse_supported = false;
242 	}
243 
244 #if IPV6_RECVERR
245 #define setsockopt_on(socket, level, name) \
246 	setsockopt(socket, level, name, &(int){ 1 }, sizeof(int))
247 
248 	r = setsockopt_on(fd, IPPROTO_IPV6, IPV6_RECVERR);
249 	if (r != 0) {
250 		perror("setup_ephemeral_port");
251 		close(fd);
252 		return (r);
253 	}
254 #endif
255 
256 	return (fd);
257 }
258 
259 /* Generic */
260 
261 static void
262 noop_read_cb(isc_nmhandle_t *handle, isc_result_t result, isc_region_t *region,
263 	     void *cbarg) {
264 	UNUSED(handle);
265 	UNUSED(result);
266 	UNUSED(region);
267 	UNUSED(cbarg);
268 }
269 
270 thread_local uint8_t tcp_buffer_storage[4096];
271 thread_local size_t tcp_buffer_length = 0;
272 
273 static int
274 setup_test(void **state) {
275 	char *env_workers = getenv("ISC_TASK_WORKERS");
276 	size_t nworkers;
277 	uv_os_sock_t tcp_listen_sock = -1;
278 	isc_nm_t **nm = NULL;
279 
280 	tcp_listen_addr = (isc_sockaddr_t){ .length = 0 };
281 	tcp_listen_sock = setup_ephemeral_port(&tcp_listen_addr, SOCK_STREAM);
282 	if (tcp_listen_sock < 0) {
283 		return (-1);
284 	}
285 	close(tcp_listen_sock);
286 	tcp_listen_sock = -1;
287 
288 	if (env_workers != NULL) {
289 		workers = atoi(env_workers);
290 	} else {
291 		workers = isc_os_ncpus();
292 	}
293 	INSIST(workers > 0);
294 	nworkers = ISC_MAX(ISC_MIN(workers, 32), 1);
295 
296 	if (!reuse_supported || getenv("CI") != NULL) {
297 		skip_long_tests = true;
298 	}
299 
300 	atomic_store(&total_sends, NSENDS * NWRITES);
301 	atomic_store(&nsends, atomic_load(&total_sends));
302 
303 	atomic_store(&csends, 0);
304 	atomic_store(&creads, 0);
305 	atomic_store(&sreads, 0);
306 	atomic_store(&ssends, 0);
307 	atomic_store(&ctimeouts, 0);
308 	atomic_store(&active_cconnects, 0);
309 
310 	atomic_store(&was_error, false);
311 
312 	atomic_store(&POST, false);
313 	atomic_store(&use_TLS, false);
314 
315 	noanswer = false;
316 
317 	isc_nonce_buf(&send_magic, sizeof(send_magic));
318 	isc_nonce_buf(&stop_magic, sizeof(stop_magic));
319 	if (send_magic == stop_magic) {
320 		return (-1);
321 	}
322 
323 	nm = isc_mem_get(mctx, MAX_NM * sizeof(nm[0]));
324 	for (size_t i = 0; i < MAX_NM; i++) {
325 		isc__netmgr_create(mctx, nworkers, &nm[i]);
326 		assert_non_null(nm[i]);
327 	}
328 
329 	server_tlsctx = NULL;
330 	isc_tlsctx_createserver(NULL, NULL, &server_tlsctx);
331 	isc_tlsctx_enable_http2server_alpn(server_tlsctx);
332 	client_tlsctx = NULL;
333 	isc_tlsctx_createclient(&client_tlsctx);
334 	isc_tlsctx_enable_http2client_alpn(client_tlsctx);
335 	isc_tlsctx_client_session_cache_create(
336 		mctx, client_tlsctx,
337 		ISC_TLSCTX_CLIENT_SESSION_CACHE_DEFAULT_SIZE,
338 		&client_sess_cache);
339 
340 	isc_quota_init(&listener_quota, 0);
341 	atomic_store(&check_listener_quota, false);
342 
343 	INSIST(endpoints == NULL);
344 	endpoints = isc_nm_http_endpoints_new(mctx);
345 
346 	*state = nm;
347 
348 	return (0);
349 }
350 
351 static int
352 teardown_test(void **state) {
353 	isc_nm_t **nm = (isc_nm_t **)*state;
354 
355 	for (size_t i = 0; i < MAX_NM; i++) {
356 		isc__netmgr_destroy(&nm[i]);
357 		assert_null(nm[i]);
358 	}
359 	isc_mem_put(mctx, nm, MAX_NM * sizeof(nm[0]));
360 
361 	if (server_tlsctx != NULL) {
362 		isc_tlsctx_free(&server_tlsctx);
363 	}
364 	if (client_tlsctx != NULL) {
365 		isc_tlsctx_free(&client_tlsctx);
366 	}
367 
368 	isc_tlsctx_client_session_cache_detach(&client_sess_cache);
369 
370 	isc_quota_destroy(&listener_quota);
371 
372 	isc_nm_http_endpoints_detach(&endpoints);
373 
374 	return (0);
375 }
376 
377 thread_local size_t nwrites = NWRITES;
378 
379 static void
380 sockaddr_to_url(isc_sockaddr_t *sa, const bool https, char *outbuf,
381 		size_t outbuf_len, const char *append) {
382 	isc_nm_http_makeuri(https, sa, NULL, 0, append, outbuf, outbuf_len);
383 }
384 
385 static isc_quota_t *
386 init_listener_quota(size_t nthreads) {
387 	isc_quota_t *quotap = NULL;
388 	if (atomic_load(&check_listener_quota)) {
389 		unsigned max_quota = ISC_MAX(nthreads / 2, 1);
390 		isc_quota_max(&listener_quota, max_quota);
391 		quotap = &listener_quota;
392 	}
393 	return (quotap);
394 }
395 
396 static void
397 doh_receive_reply_cb(isc_nmhandle_t *handle, isc_result_t eresult,
398 		     isc_region_t *region, void *cbarg) {
399 	assert_non_null(handle);
400 	UNUSED(cbarg);
401 	UNUSED(region);
402 
403 	if (eresult == ISC_R_SUCCESS) {
404 		(void)atomic_fetch_sub(&nsends, 1);
405 		atomic_fetch_add(&csends, 1);
406 		atomic_fetch_add(&creads, 1);
407 	} else {
408 		/* We failed to connect; try again */
409 		atomic_store(&was_error, true);
410 	}
411 }
412 
413 static void
414 doh_reply_sent_cb(isc_nmhandle_t *handle, isc_result_t eresult, void *cbarg) {
415 	UNUSED(eresult);
416 	UNUSED(cbarg);
417 
418 	assert_non_null(handle);
419 
420 	if (eresult == ISC_R_SUCCESS) {
421 		atomic_fetch_add(&ssends, 1);
422 	}
423 }
424 
425 static void
426 doh_receive_request_cb(isc_nmhandle_t *handle, isc_result_t eresult,
427 		       isc_region_t *region, void *cbarg) {
428 	uint64_t magic = 0;
429 
430 	UNUSED(cbarg);
431 	assert_non_null(handle);
432 
433 	if (eresult != ISC_R_SUCCESS) {
434 		atomic_store(&was_error, true);
435 		return;
436 	}
437 
438 	atomic_fetch_add(&sreads, 1);
439 
440 	memmove(tcp_buffer_storage + tcp_buffer_length, region->base,
441 		region->length);
442 	tcp_buffer_length += region->length;
443 
444 	while (tcp_buffer_length >= sizeof(magic)) {
445 		magic = *(uint64_t *)tcp_buffer_storage;
446 		assert_true(magic == stop_magic || magic == send_magic);
447 
448 		tcp_buffer_length -= sizeof(magic);
449 		memmove(tcp_buffer_storage, tcp_buffer_storage + sizeof(magic),
450 			tcp_buffer_length);
451 
452 		if (magic == send_magic) {
453 			if (!noanswer) {
454 				isc_nm_send(handle, region, doh_reply_sent_cb,
455 					    NULL);
456 			}
457 			return;
458 		} else if (magic == stop_magic) {
459 			/*
460 			 * We are done, so we don't send anything back.
461 			 * There should be no more packets in the buffer.
462 			 */
463 			assert_int_equal(tcp_buffer_length, 0);
464 		}
465 	}
466 }
467 
468 ISC_RUN_TEST_IMPL(mock_doh_uv_tcp_bind) {
469 	isc_nm_t **nm = (isc_nm_t **)*state;
470 	isc_nm_t *listen_nm = nm[0];
471 	isc_result_t result = ISC_R_SUCCESS;
472 	isc_nmsocket_t *listen_sock = NULL;
473 
474 	WILL_RETURN(uv_tcp_bind, UV_EADDRINUSE);
475 
476 	result = isc_nm_http_endpoints_add(endpoints, ISC_NM_HTTP_DEFAULT_PATH,
477 					   noop_read_cb, NULL, 0);
478 	assert_int_equal(result, ISC_R_SUCCESS);
479 	result = isc_nm_listenhttp(listen_nm, &tcp_listen_addr, 0, NULL, NULL,
480 				   endpoints, 0, &listen_sock);
481 	assert_int_not_equal(result, ISC_R_SUCCESS);
482 	assert_null(listen_sock);
483 
484 	RESET_RETURN;
485 }
486 
487 static void
488 doh_noop(void **state) {
489 	isc_nm_t **nm = (isc_nm_t **)*state;
490 	isc_nm_t *listen_nm = nm[0];
491 	isc_nm_t *connect_nm = nm[1];
492 	isc_result_t result = ISC_R_SUCCESS;
493 	isc_nmsocket_t *listen_sock = NULL;
494 	char req_url[256];
495 
496 	result = isc_nm_http_endpoints_add(endpoints, ISC_NM_HTTP_DEFAULT_PATH,
497 					   noop_read_cb, NULL, 0);
498 	assert_int_equal(result, ISC_R_SUCCESS);
499 
500 	result = isc_nm_listenhttp(listen_nm, &tcp_listen_addr, 0, NULL, NULL,
501 				   endpoints, 0, &listen_sock);
502 	assert_int_equal(result, ISC_R_SUCCESS);
503 
504 	isc_nm_stoplistening(listen_sock);
505 	isc_nmsocket_close(&listen_sock);
506 	assert_null(listen_sock);
507 
508 	sockaddr_to_url(&tcp_listen_addr, false, req_url, sizeof(req_url),
509 			ISC_NM_HTTP_DEFAULT_PATH);
510 	connect_send_request(connect_nm, req_url, atomic_load(&POST),
511 			     &(isc_region_t){ .base = (uint8_t *)send_msg.base,
512 					      .length = send_msg.len },
513 			     noop_read_cb, NULL, atomic_load(&use_TLS), 30000);
514 
515 	isc__netmgr_shutdown(connect_nm);
516 
517 	assert_int_equal(0, atomic_load(&csends));
518 	assert_int_equal(0, atomic_load(&creads));
519 	assert_int_equal(0, atomic_load(&sreads));
520 	assert_int_equal(0, atomic_load(&ssends));
521 }
522 
523 ISC_RUN_TEST_IMPL(doh_noop_POST) {
524 	atomic_store(&POST, true);
525 	doh_noop(state);
526 }
527 
528 ISC_RUN_TEST_IMPL(doh_noop_GET) {
529 	atomic_store(&POST, false);
530 	doh_noop(state);
531 }
532 
533 static void
534 doh_noresponse(void **state) {
535 	isc_nm_t **nm = (isc_nm_t **)*state;
536 	isc_nm_t *listen_nm = nm[0];
537 	isc_nm_t *connect_nm = nm[1];
538 	isc_result_t result = ISC_R_SUCCESS;
539 	isc_nmsocket_t *listen_sock = NULL;
540 	char req_url[256];
541 
542 	result = isc_nm_http_endpoints_add(endpoints, ISC_NM_HTTP_DEFAULT_PATH,
543 					   noop_read_cb, NULL, 0);
544 	assert_int_equal(result, ISC_R_SUCCESS);
545 
546 	result = isc_nm_listenhttp(listen_nm, &tcp_listen_addr, 0, NULL, NULL,
547 				   endpoints, 0, &listen_sock);
548 	assert_int_equal(result, ISC_R_SUCCESS);
549 
550 	sockaddr_to_url(&tcp_listen_addr, false, req_url, sizeof(req_url),
551 			ISC_NM_HTTP_DEFAULT_PATH);
552 	connect_send_request(connect_nm, req_url, atomic_load(&POST),
553 			     &(isc_region_t){ .base = (uint8_t *)send_msg.base,
554 					      .length = send_msg.len },
555 			     noop_read_cb, NULL, atomic_load(&use_TLS), 30000);
556 
557 	isc_nm_stoplistening(listen_sock);
558 	isc_nmsocket_close(&listen_sock);
559 	assert_null(listen_sock);
560 	isc__netmgr_shutdown(connect_nm);
561 }
562 
563 ISC_RUN_TEST_IMPL(doh_noresponse_POST) {
564 	atomic_store(&POST, true);
565 	doh_noresponse(state);
566 }
567 
568 ISC_RUN_TEST_IMPL(doh_noresponse_GET) {
569 	atomic_store(&POST, false);
570 	doh_noresponse(state);
571 }
572 
573 static void
574 timeout_query_sent_cb(isc_nmhandle_t *handle, isc_result_t eresult,
575 		      void *cbarg) {
576 	UNUSED(eresult);
577 	UNUSED(cbarg);
578 
579 	assert_non_null(handle);
580 
581 	if (eresult == ISC_R_SUCCESS) {
582 		atomic_fetch_add(&csends, 1);
583 	}
584 
585 	isc_nmhandle_detach(&handle);
586 }
587 
588 static void
589 timeout_retry_cb(isc_nmhandle_t *handle, isc_result_t eresult,
590 		 isc_region_t *region, void *arg) {
591 	UNUSED(region);
592 	UNUSED(arg);
593 
594 	assert_non_null(handle);
595 
596 	atomic_fetch_add(&ctimeouts, 1);
597 
598 	if (eresult == ISC_R_TIMEDOUT && atomic_load(&ctimeouts) < 5) {
599 		isc_nmhandle_settimeout(handle, T_SOFT);
600 		return;
601 	}
602 
603 	isc_nmhandle_detach(&handle);
604 }
605 
606 static void
607 timeout_request_cb(isc_nmhandle_t *handle, isc_result_t result, void *arg) {
608 	isc_nmhandle_t *sendhandle = NULL;
609 	isc_nmhandle_t *readhandle = NULL;
610 
611 	REQUIRE(VALID_NMHANDLE(handle));
612 
613 	if (result != ISC_R_SUCCESS) {
614 		goto error;
615 	}
616 
617 	isc_nmhandle_attach(handle, &sendhandle);
618 	isc_nm_send(handle,
619 		    &(isc_region_t){ .base = (uint8_t *)send_msg.base,
620 				     .length = send_msg.len },
621 		    timeout_query_sent_cb, arg);
622 
623 	isc_nmhandle_attach(handle, &readhandle);
624 	isc_nm_read(handle, timeout_retry_cb, NULL);
625 	return;
626 
627 error:
628 	atomic_store(&was_error, true);
629 }
630 
631 static void
632 doh_timeout_recovery(void **state) {
633 	isc_nm_t **nm = (isc_nm_t **)*state;
634 	isc_nm_t *listen_nm = nm[0];
635 	isc_nm_t *connect_nm = nm[1];
636 	isc_result_t result = ISC_R_SUCCESS;
637 	isc_nmsocket_t *listen_sock = NULL;
638 	isc_tlsctx_t *ctx = atomic_load(&use_TLS) ? server_tlsctx : NULL;
639 	char req_url[256];
640 
641 	result = isc_nm_http_endpoints_add(endpoints, ISC_NM_HTTP_DEFAULT_PATH,
642 					   doh_receive_request_cb, NULL, 0);
643 	assert_int_equal(result, ISC_R_SUCCESS);
644 
645 	result = isc_nm_listenhttp(listen_nm, &tcp_listen_addr, 0, NULL, NULL,
646 				   endpoints, 0, &listen_sock);
647 	assert_int_equal(result, ISC_R_SUCCESS);
648 
649 	/*
650 	 * Accept connections but don't send responses, forcing client
651 	 * reads to time out.
652 	 */
653 	noanswer = true;
654 
655 	/*
656 	 * Shorten all the TCP client timeouts to 0.05 seconds.
657 	 * timeout_retry_cb() will give up after five timeouts.
658 	 */
659 	isc_nm_settimeouts(connect_nm, T_SOFT, T_SOFT, T_SOFT, T_SOFT);
660 	sockaddr_to_url(&tcp_listen_addr, false, req_url, sizeof(req_url),
661 			ISC_NM_HTTP_DEFAULT_PATH);
662 	isc_nm_httpconnect(connect_nm, NULL, &tcp_listen_addr, req_url,
663 			   atomic_load(&POST), timeout_request_cb, NULL, ctx,
664 			   client_sess_cache, T_SOFT, 0);
665 
666 	/*
667 	 * Sleep until sends reaches 5.
668 	 */
669 	for (size_t i = 0; i < 1000; i++) {
670 		if (atomic_load(&ctimeouts) == 5) {
671 			break;
672 		}
673 		isc_test_nap(1);
674 	}
675 	assert_true(atomic_load(&ctimeouts) == 5);
676 
677 	isc_nm_stoplistening(listen_sock);
678 	isc_nmsocket_close(&listen_sock);
679 	assert_null(listen_sock);
680 	isc__netmgr_shutdown(connect_nm);
681 }
682 
683 ISC_RUN_TEST_IMPL(doh_timeout_recovery_POST) {
684 	SKIP_IN_CI;
685 
686 	atomic_store(&POST, true);
687 	doh_timeout_recovery(state);
688 }
689 
690 ISC_RUN_TEST_IMPL(doh_timeout_recovery_GET) {
691 	SKIP_IN_CI;
692 
693 	atomic_store(&POST, false);
694 	doh_timeout_recovery(state);
695 }
696 
697 static void
698 doh_receive_send_reply_cb(isc_nmhandle_t *handle, isc_result_t eresult,
699 			  isc_region_t *region, void *cbarg) {
700 	UNUSED(region);
701 
702 	if (eresult != ISC_R_SUCCESS) {
703 		atomic_store(&was_error, true);
704 		return;
705 	}
706 
707 	assert_non_null(handle);
708 
709 	int_fast64_t sends = atomic_fetch_sub(&nsends, 1);
710 	atomic_fetch_add(&csends, 1);
711 	atomic_fetch_add(&creads, 1);
712 	if (sends > 0 && cbarg == NULL) {
713 		size_t i;
714 		for (i = 0; i < NWRITES / 2; i++) {
715 			eresult = isc__nm_http_request(
716 				handle,
717 				&(isc_region_t){
718 					.base = (uint8_t *)send_msg.base,
719 					.length = send_msg.len },
720 				doh_receive_send_reply_cb, (void *)1);
721 			if (eresult == ISC_R_CANCELED) {
722 				break;
723 			}
724 			assert_true(eresult == ISC_R_SUCCESS);
725 		}
726 	}
727 }
728 
729 static isc_threadresult_t
730 doh_connect_thread(isc_threadarg_t arg) {
731 	isc_nm_t *connect_nm = (isc_nm_t *)arg;
732 	char req_url[256];
733 	int64_t sends = atomic_load(&nsends);
734 
735 	sockaddr_to_url(&tcp_listen_addr, atomic_load(&use_TLS), req_url,
736 			sizeof(req_url), ISC_NM_HTTP_DEFAULT_PATH);
737 
738 	while (sends > 0) {
739 		/*
740 		 * We need to back off and slow down if we start getting
741 		 * errors, to prevent a thundering herd problem.
742 		 */
743 		int_fast64_t active = atomic_fetch_add(&active_cconnects, 1);
744 		if (atomic_load(&slowdown) || active > workers) {
745 			isc_test_nap(active - workers);
746 			atomic_store(&slowdown, false);
747 		}
748 		connect_send_request(
749 			connect_nm, req_url, atomic_load(&POST),
750 			&(isc_region_t){ .base = (uint8_t *)send_msg.base,
751 					 .length = send_msg.len },
752 			doh_receive_send_reply_cb, NULL, atomic_load(&use_TLS),
753 			30000);
754 		sends = atomic_load(&nsends);
755 	}
756 
757 	return ((isc_threadresult_t)0);
758 }
759 
760 static void
761 doh_recv_one(void **state) {
762 	isc_nm_t **nm = (isc_nm_t **)*state;
763 	isc_nm_t *listen_nm = nm[0];
764 	isc_nm_t *connect_nm = nm[1];
765 	isc_result_t result = ISC_R_SUCCESS;
766 	isc_nmsocket_t *listen_sock = NULL;
767 	char req_url[256];
768 	isc_quota_t *quotap = init_listener_quota(workers);
769 
770 	atomic_store(&total_sends, 1);
771 
772 	atomic_store(&nsends, atomic_load(&total_sends));
773 
774 	result = isc_nm_http_endpoints_add(endpoints, ISC_NM_HTTP_DEFAULT_PATH,
775 					   doh_receive_request_cb, NULL, 0);
776 	assert_int_equal(result, ISC_R_SUCCESS);
777 
778 	result = isc_nm_listenhttp(listen_nm, &tcp_listen_addr, 0, quotap,
779 				   atomic_load(&use_TLS) ? server_tlsctx : NULL,
780 				   endpoints, 0, &listen_sock);
781 	assert_int_equal(result, ISC_R_SUCCESS);
782 
783 	sockaddr_to_url(&tcp_listen_addr, atomic_load(&use_TLS), req_url,
784 			sizeof(req_url), ISC_NM_HTTP_DEFAULT_PATH);
785 	connect_send_request(connect_nm, req_url, atomic_load(&POST),
786 			     &(isc_region_t){ .base = (uint8_t *)send_msg.base,
787 					      .length = send_msg.len },
788 			     doh_receive_reply_cb, NULL, atomic_load(&use_TLS),
789 			     30000);
790 
791 	while (atomic_load(&nsends) > 0) {
792 		if (atomic_load(&was_error)) {
793 			break;
794 		}
795 		isc_thread_yield();
796 	}
797 
798 	while (atomic_load(&ssends) != 1 || atomic_load(&sreads) != 1 ||
799 	       atomic_load(&csends) != 1)
800 	{
801 		if (atomic_load(&was_error)) {
802 			break;
803 		}
804 		isc_thread_yield();
805 	}
806 
807 	isc_nm_stoplistening(listen_sock);
808 	isc_nmsocket_close(&listen_sock);
809 	assert_null(listen_sock);
810 	isc__netmgr_shutdown(connect_nm);
811 
812 	X(total_sends);
813 	X(csends);
814 	X(creads);
815 	X(sreads);
816 	X(ssends);
817 
818 	assert_int_equal(atomic_load(&csends), 1);
819 	assert_int_equal(atomic_load(&creads), 1);
820 	assert_int_equal(atomic_load(&sreads), 1);
821 	assert_int_equal(atomic_load(&ssends), 1);
822 }
823 
824 ISC_RUN_TEST_IMPL(doh_recv_one_POST) {
825 	SKIP_IN_CI;
826 
827 	atomic_store(&POST, true);
828 	doh_recv_one(state);
829 }
830 
831 ISC_RUN_TEST_IMPL(doh_recv_one_GET) {
832 	SKIP_IN_CI;
833 
834 	atomic_store(&POST, false);
835 	doh_recv_one(state);
836 }
837 
838 ISC_RUN_TEST_IMPL(doh_recv_one_POST_TLS) {
839 	SKIP_IN_CI;
840 
841 	atomic_store(&use_TLS, true);
842 	atomic_store(&POST, true);
843 	doh_recv_one(state);
844 }
845 
846 ISC_RUN_TEST_IMPL(doh_recv_one_GET_TLS) {
847 	SKIP_IN_CI;
848 
849 	atomic_store(&use_TLS, true);
850 	atomic_store(&POST, false);
851 	doh_recv_one(state);
852 }
853 
854 ISC_RUN_TEST_IMPL(doh_recv_one_POST_quota) {
855 	SKIP_IN_CI;
856 
857 	atomic_store(&POST, true);
858 	atomic_store(&check_listener_quota, true);
859 	doh_recv_one(state);
860 }
861 
862 ISC_RUN_TEST_IMPL(doh_recv_one_GET_quota) {
863 	SKIP_IN_CI;
864 
865 	atomic_store(&POST, false);
866 	atomic_store(&check_listener_quota, true);
867 	doh_recv_one(state);
868 }
869 
870 ISC_RUN_TEST_IMPL(doh_recv_one_POST_TLS_quota) {
871 	SKIP_IN_CI;
872 
873 	atomic_store(&use_TLS, true);
874 	atomic_store(&POST, true);
875 	atomic_store(&check_listener_quota, true);
876 	doh_recv_one(state);
877 }
878 
879 ISC_RUN_TEST_IMPL(doh_recv_one_GET_TLS_quota) {
880 	SKIP_IN_CI;
881 
882 	atomic_store(&use_TLS, true);
883 	atomic_store(&POST, false);
884 	atomic_store(&check_listener_quota, true);
885 	doh_recv_one(state);
886 }
887 
888 static void
889 doh_connect_send_two_requests_cb(isc_nmhandle_t *handle, isc_result_t result,
890 				 void *arg) {
891 	REQUIRE(VALID_NMHANDLE(handle));
892 	if (result != ISC_R_SUCCESS) {
893 		goto error;
894 	}
895 
896 	result = isc__nm_http_request(
897 		handle,
898 		&(isc_region_t){ .base = (uint8_t *)send_msg.base,
899 				 .length = send_msg.len },
900 		doh_receive_reply_cb, arg);
901 	if (result != ISC_R_SUCCESS) {
902 		goto error;
903 	}
904 
905 	result = isc__nm_http_request(
906 		handle,
907 		&(isc_region_t){ .base = (uint8_t *)send_msg.base,
908 				 .length = send_msg.len },
909 		doh_receive_reply_cb, arg);
910 	if (result != ISC_R_SUCCESS) {
911 		goto error;
912 	}
913 	return;
914 error:
915 	atomic_store(&was_error, true);
916 }
917 
918 static void
919 doh_recv_two(void **state) {
920 	isc_nm_t **nm = (isc_nm_t **)*state;
921 	isc_nm_t *listen_nm = nm[0];
922 	isc_nm_t *connect_nm = nm[1];
923 	isc_result_t result = ISC_R_SUCCESS;
924 	isc_nmsocket_t *listen_sock = NULL;
925 	char req_url[256];
926 	isc_tlsctx_t *ctx = NULL;
927 	isc_quota_t *quotap = init_listener_quota(workers);
928 
929 	atomic_store(&total_sends, 2);
930 
931 	atomic_store(&nsends, atomic_load(&total_sends));
932 
933 	result = isc_nm_http_endpoints_add(endpoints, ISC_NM_HTTP_DEFAULT_PATH,
934 					   doh_receive_request_cb, NULL, 0);
935 	assert_int_equal(result, ISC_R_SUCCESS);
936 
937 	result = isc_nm_listenhttp(listen_nm, &tcp_listen_addr, 0, quotap,
938 				   atomic_load(&use_TLS) ? server_tlsctx : NULL,
939 				   endpoints, 0, &listen_sock);
940 	assert_int_equal(result, ISC_R_SUCCESS);
941 
942 	sockaddr_to_url(&tcp_listen_addr, atomic_load(&use_TLS), req_url,
943 			sizeof(req_url), ISC_NM_HTTP_DEFAULT_PATH);
944 
945 	if (atomic_load(&use_TLS)) {
946 		ctx = client_tlsctx;
947 	}
948 
949 	isc_nm_httpconnect(connect_nm, NULL, &tcp_listen_addr, req_url,
950 			   atomic_load(&POST), doh_connect_send_two_requests_cb,
951 			   NULL, ctx, client_sess_cache, 5000, 0);
952 
953 	while (atomic_load(&nsends) > 0) {
954 		if (atomic_load(&was_error)) {
955 			break;
956 		}
957 		isc_thread_yield();
958 	}
959 
960 	while (atomic_load(&ssends) != 2 || atomic_load(&sreads) != 2 ||
961 	       atomic_load(&csends) != 2)
962 	{
963 		if (atomic_load(&was_error)) {
964 			break;
965 		}
966 		isc_thread_yield();
967 	}
968 
969 	isc_nm_stoplistening(listen_sock);
970 	isc_nmsocket_close(&listen_sock);
971 	assert_null(listen_sock);
972 	isc__netmgr_shutdown(connect_nm);
973 
974 	X(total_sends);
975 	X(csends);
976 	X(creads);
977 	X(sreads);
978 	X(ssends);
979 
980 	assert_int_equal(atomic_load(&csends), 2);
981 	assert_int_equal(atomic_load(&creads), 2);
982 	assert_int_equal(atomic_load(&sreads), 2);
983 	assert_int_equal(atomic_load(&ssends), 2);
984 }
985 
986 ISC_RUN_TEST_IMPL(doh_recv_two_POST) {
987 	SKIP_IN_CI;
988 
989 	atomic_store(&POST, true);
990 	doh_recv_two(state);
991 }
992 
993 ISC_RUN_TEST_IMPL(doh_recv_two_GET) {
994 	SKIP_IN_CI;
995 
996 	atomic_store(&POST, false);
997 	doh_recv_two(state);
998 }
999 
1000 ISC_RUN_TEST_IMPL(doh_recv_two_POST_TLS) {
1001 	SKIP_IN_CI;
1002 
1003 	atomic_store(&use_TLS, true);
1004 	atomic_store(&POST, true);
1005 	doh_recv_two(state);
1006 }
1007 
1008 ISC_RUN_TEST_IMPL(doh_recv_two_GET_TLS) {
1009 	SKIP_IN_CI;
1010 
1011 	atomic_store(&use_TLS, true);
1012 	atomic_store(&POST, false);
1013 	doh_recv_two(state);
1014 }
1015 
1016 ISC_RUN_TEST_IMPL(doh_recv_two_POST_quota) {
1017 	SKIP_IN_CI;
1018 
1019 	atomic_store(&POST, true);
1020 	atomic_store(&check_listener_quota, true);
1021 	doh_recv_two(state);
1022 }
1023 
1024 ISC_RUN_TEST_IMPL(doh_recv_two_GET_quota) {
1025 	SKIP_IN_CI;
1026 
1027 	atomic_store(&POST, false);
1028 	atomic_store(&check_listener_quota, true);
1029 	doh_recv_two(state);
1030 }
1031 
1032 ISC_RUN_TEST_IMPL(doh_recv_two_POST_TLS_quota) {
1033 	SKIP_IN_CI;
1034 
1035 	atomic_store(&use_TLS, true);
1036 	atomic_store(&POST, true);
1037 	atomic_store(&check_listener_quota, true);
1038 	doh_recv_two(state);
1039 }
1040 
1041 ISC_RUN_TEST_IMPL(doh_recv_two_GET_TLS_quota) {
1042 	SKIP_IN_CI;
1043 
1044 	atomic_store(&use_TLS, true);
1045 	atomic_store(&POST, false);
1046 	atomic_store(&check_listener_quota, true);
1047 	doh_recv_two(state);
1048 }
1049 
1050 static void
1051 doh_recv_send(void **state) {
1052 	isc_nm_t **nm = (isc_nm_t **)*state;
1053 	isc_nm_t *listen_nm = nm[0];
1054 	isc_nm_t *connect_nm = nm[1];
1055 	isc_result_t result = ISC_R_SUCCESS;
1056 	isc_nmsocket_t *listen_sock = NULL;
1057 	size_t nthreads = ISC_MAX(ISC_MIN(workers, 32), 1);
1058 	isc_thread_t threads[32] = { 0 };
1059 	isc_quota_t *quotap = init_listener_quota(workers);
1060 
1061 	result = isc_nm_http_endpoints_add(endpoints, ISC_NM_HTTP_DEFAULT_PATH,
1062 					   doh_receive_request_cb, NULL, 0);
1063 	assert_int_equal(result, ISC_R_SUCCESS);
1064 
1065 	result = isc_nm_listenhttp(listen_nm, &tcp_listen_addr, 0, quotap,
1066 				   atomic_load(&use_TLS) ? server_tlsctx : NULL,
1067 				   endpoints, 0, &listen_sock);
1068 	assert_int_equal(result, ISC_R_SUCCESS);
1069 
1070 	for (size_t i = 0; i < nthreads; i++) {
1071 		isc_thread_create(doh_connect_thread, connect_nm, &threads[i]);
1072 	}
1073 
1074 	/* wait for the all responses from the server */
1075 	while (atomic_load(&ssends) < atomic_load(&total_sends)) {
1076 		if (atomic_load(&was_error)) {
1077 			break;
1078 		}
1079 		isc_test_nap(1);
1080 	}
1081 
1082 	for (size_t i = 0; i < nthreads; i++) {
1083 		isc_thread_join(threads[i], NULL);
1084 	}
1085 
1086 	isc__netmgr_shutdown(connect_nm);
1087 	isc_nm_stoplistening(listen_sock);
1088 	isc_nmsocket_close(&listen_sock);
1089 	assert_null(listen_sock);
1090 
1091 	X(total_sends);
1092 	X(csends);
1093 	X(creads);
1094 	X(sreads);
1095 	X(ssends);
1096 
1097 	CHECK_RANGE_FULL(csends);
1098 	CHECK_RANGE_FULL(creads);
1099 	CHECK_RANGE_FULL(sreads);
1100 	CHECK_RANGE_FULL(ssends);
1101 }
1102 
1103 ISC_RUN_TEST_IMPL(doh_recv_send_POST) {
1104 	SKIP_IN_CI;
1105 
1106 	atomic_store(&POST, true);
1107 	doh_recv_send(state);
1108 }
1109 
1110 ISC_RUN_TEST_IMPL(doh_recv_send_GET) {
1111 	SKIP_IN_CI;
1112 
1113 	atomic_store(&POST, false);
1114 	doh_recv_send(state);
1115 }
1116 
1117 ISC_RUN_TEST_IMPL(doh_recv_send_POST_TLS) {
1118 	SKIP_IN_CI;
1119 
1120 	atomic_store(&POST, true);
1121 	atomic_store(&use_TLS, true);
1122 	doh_recv_send(state);
1123 }
1124 
1125 ISC_RUN_TEST_IMPL(doh_recv_send_GET_TLS) {
1126 	SKIP_IN_CI;
1127 
1128 	atomic_store(&POST, false);
1129 	atomic_store(&use_TLS, true);
1130 	doh_recv_send(state);
1131 }
1132 
1133 ISC_RUN_TEST_IMPL(doh_recv_send_POST_quota) {
1134 	SKIP_IN_CI;
1135 
1136 	atomic_store(&POST, true);
1137 	atomic_store(&check_listener_quota, true);
1138 	doh_recv_send(state);
1139 }
1140 
1141 ISC_RUN_TEST_IMPL(doh_recv_send_GET_quota) {
1142 	SKIP_IN_CI;
1143 
1144 	atomic_store(&POST, false);
1145 	atomic_store(&check_listener_quota, true);
1146 	doh_recv_send(state);
1147 }
1148 
1149 ISC_RUN_TEST_IMPL(doh_recv_send_POST_TLS_quota) {
1150 	SKIP_IN_CI;
1151 
1152 	atomic_store(&POST, true);
1153 	atomic_store(&use_TLS, true);
1154 	atomic_store(&check_listener_quota, true);
1155 	doh_recv_send(state);
1156 }
1157 
1158 ISC_RUN_TEST_IMPL(doh_recv_send_GET_TLS_quota) {
1159 	SKIP_IN_CI;
1160 
1161 	atomic_store(&POST, false);
1162 	atomic_store(&use_TLS, true);
1163 	atomic_store(&check_listener_quota, true);
1164 	doh_recv_send(state);
1165 }
1166 
1167 static void
1168 doh_recv_half_send(void **state) {
1169 	isc_nm_t **nm = (isc_nm_t **)*state;
1170 	isc_nm_t *listen_nm = nm[0];
1171 	isc_nm_t *connect_nm = nm[1];
1172 	isc_result_t result = ISC_R_SUCCESS;
1173 	isc_nmsocket_t *listen_sock = NULL;
1174 	size_t nthreads = ISC_MAX(ISC_MIN(workers, 32), 1);
1175 	isc_thread_t threads[32] = { 0 };
1176 	isc_quota_t *quotap = init_listener_quota(workers);
1177 
1178 	atomic_store(&total_sends, atomic_load(&total_sends) / 2);
1179 
1180 	atomic_store(&nsends, atomic_load(&total_sends));
1181 
1182 	result = isc_nm_http_endpoints_add(endpoints, ISC_NM_HTTP_DEFAULT_PATH,
1183 					   doh_receive_request_cb, NULL, 0);
1184 	assert_int_equal(result, ISC_R_SUCCESS);
1185 
1186 	result = isc_nm_listenhttp(listen_nm, &tcp_listen_addr, 0, quotap,
1187 				   atomic_load(&use_TLS) ? server_tlsctx : NULL,
1188 				   endpoints, 0, &listen_sock);
1189 	assert_int_equal(result, ISC_R_SUCCESS);
1190 
1191 	for (size_t i = 0; i < nthreads; i++) {
1192 		isc_thread_create(doh_connect_thread, connect_nm, &threads[i]);
1193 	}
1194 
1195 	while (atomic_load(&nsends) > 0) {
1196 		isc_thread_yield();
1197 	}
1198 
1199 	isc__netmgr_shutdown(connect_nm);
1200 
1201 	for (size_t i = 0; i < nthreads; i++) {
1202 		isc_thread_join(threads[i], NULL);
1203 	}
1204 
1205 	isc_nm_stoplistening(listen_sock);
1206 	isc_nmsocket_close(&listen_sock);
1207 	assert_null(listen_sock);
1208 
1209 	X(total_sends);
1210 	X(csends);
1211 	X(creads);
1212 	X(sreads);
1213 	X(ssends);
1214 
1215 	CHECK_RANGE_HALF(csends);
1216 	CHECK_RANGE_HALF(creads);
1217 	CHECK_RANGE_HALF(sreads);
1218 	CHECK_RANGE_HALF(ssends);
1219 }
1220 
1221 ISC_RUN_TEST_IMPL(doh_recv_half_send_POST) {
1222 	SKIP_IN_CI;
1223 
1224 	atomic_store(&POST, true);
1225 	doh_recv_half_send(state);
1226 }
1227 
1228 ISC_RUN_TEST_IMPL(doh_recv_half_send_GET) {
1229 	SKIP_IN_CI;
1230 
1231 	atomic_store(&POST, false);
1232 	doh_recv_half_send(state);
1233 }
1234 
1235 ISC_RUN_TEST_IMPL(doh_recv_half_send_POST_TLS) {
1236 	SKIP_IN_CI;
1237 
1238 	atomic_store(&use_TLS, true);
1239 	atomic_store(&POST, true);
1240 	doh_recv_half_send(state);
1241 }
1242 
1243 ISC_RUN_TEST_IMPL(doh_recv_half_send_GET_TLS) {
1244 	SKIP_IN_CI;
1245 
1246 	atomic_store(&use_TLS, true);
1247 	atomic_store(&POST, false);
1248 	doh_recv_half_send(state);
1249 }
1250 
1251 ISC_RUN_TEST_IMPL(doh_recv_half_send_POST_quota) {
1252 	SKIP_IN_CI;
1253 
1254 	atomic_store(&POST, true);
1255 	atomic_store(&check_listener_quota, true);
1256 	doh_recv_half_send(state);
1257 }
1258 
1259 ISC_RUN_TEST_IMPL(doh_recv_half_send_GET_quota) {
1260 	SKIP_IN_CI;
1261 
1262 	atomic_store(&POST, false);
1263 	atomic_store(&check_listener_quota, true);
1264 	doh_recv_half_send(state);
1265 }
1266 
1267 ISC_RUN_TEST_IMPL(doh_recv_half_send_POST_TLS_quota) {
1268 	SKIP_IN_CI;
1269 
1270 	atomic_store(&use_TLS, true);
1271 	atomic_store(&POST, true);
1272 	atomic_store(&check_listener_quota, true);
1273 	doh_recv_half_send(state);
1274 }
1275 
1276 ISC_RUN_TEST_IMPL(doh_recv_half_send_GET_TLS_quota) {
1277 	SKIP_IN_CI;
1278 
1279 	atomic_store(&use_TLS, true);
1280 	atomic_store(&POST, false);
1281 	atomic_store(&check_listener_quota, true);
1282 	doh_recv_half_send(state);
1283 }
1284 
1285 static void
1286 doh_half_recv_send(void **state) {
1287 	isc_nm_t **nm = (isc_nm_t **)*state;
1288 	isc_nm_t *listen_nm = nm[0];
1289 	isc_nm_t *connect_nm = nm[1];
1290 	isc_result_t result = ISC_R_SUCCESS;
1291 	isc_nmsocket_t *listen_sock = NULL;
1292 	size_t nthreads = ISC_MAX(ISC_MIN(workers, 32), 1);
1293 	isc_thread_t threads[32] = { 0 };
1294 	isc_quota_t *quotap = init_listener_quota(workers);
1295 
1296 	atomic_store(&total_sends, atomic_load(&total_sends) / 2);
1297 
1298 	atomic_store(&nsends, atomic_load(&total_sends));
1299 
1300 	result = isc_nm_http_endpoints_add(endpoints, ISC_NM_HTTP_DEFAULT_PATH,
1301 					   doh_receive_request_cb, NULL, 0);
1302 	assert_int_equal(result, ISC_R_SUCCESS);
1303 
1304 	result = isc_nm_listenhttp(listen_nm, &tcp_listen_addr, 0, quotap,
1305 				   atomic_load(&use_TLS) ? server_tlsctx : NULL,
1306 				   endpoints, 0, &listen_sock);
1307 	assert_int_equal(result, ISC_R_SUCCESS);
1308 
1309 	for (size_t i = 0; i < nthreads; i++) {
1310 		isc_thread_create(doh_connect_thread, connect_nm, &threads[i]);
1311 	}
1312 
1313 	while (atomic_load(&nsends) > 0) {
1314 		isc_thread_yield();
1315 	}
1316 
1317 	isc_nm_stoplistening(listen_sock);
1318 	isc_nmsocket_close(&listen_sock);
1319 	assert_null(listen_sock);
1320 
1321 	for (size_t i = 0; i < nthreads; i++) {
1322 		isc_thread_join(threads[i], NULL);
1323 	}
1324 
1325 	isc__netmgr_shutdown(connect_nm);
1326 
1327 	X(total_sends);
1328 	X(csends);
1329 	X(creads);
1330 	X(sreads);
1331 	X(ssends);
1332 
1333 	CHECK_RANGE_HALF(csends);
1334 	CHECK_RANGE_HALF(creads);
1335 	CHECK_RANGE_HALF(sreads);
1336 	CHECK_RANGE_HALF(ssends);
1337 }
1338 
1339 ISC_RUN_TEST_IMPL(doh_half_recv_send_POST) {
1340 	SKIP_IN_CI;
1341 
1342 	atomic_store(&POST, true);
1343 	doh_half_recv_send(state);
1344 }
1345 
1346 ISC_RUN_TEST_IMPL(doh_half_recv_send_GET) {
1347 	SKIP_IN_CI;
1348 
1349 	atomic_store(&POST, false);
1350 	doh_half_recv_send(state);
1351 }
1352 
1353 ISC_RUN_TEST_IMPL(doh_half_recv_send_POST_TLS) {
1354 	SKIP_IN_CI;
1355 
1356 	atomic_store(&use_TLS, true);
1357 	atomic_store(&POST, true);
1358 	doh_half_recv_send(state);
1359 }
1360 
1361 ISC_RUN_TEST_IMPL(doh_half_recv_send_GET_TLS) {
1362 	SKIP_IN_CI;
1363 
1364 	atomic_store(&use_TLS, true);
1365 	atomic_store(&POST, false);
1366 	doh_half_recv_send(state);
1367 }
1368 
1369 ISC_RUN_TEST_IMPL(doh_half_recv_send_POST_quota) {
1370 	SKIP_IN_CI;
1371 
1372 	atomic_store(&POST, true);
1373 	atomic_store(&check_listener_quota, true);
1374 	doh_half_recv_send(state);
1375 }
1376 
1377 ISC_RUN_TEST_IMPL(doh_half_recv_send_GET_quota) {
1378 	SKIP_IN_CI;
1379 
1380 	atomic_store(&POST, false);
1381 	atomic_store(&check_listener_quota, true);
1382 	doh_half_recv_send(state);
1383 }
1384 
1385 ISC_RUN_TEST_IMPL(doh_half_recv_send_POST_TLS_quota) {
1386 	SKIP_IN_CI;
1387 
1388 	atomic_store(&use_TLS, true);
1389 	atomic_store(&POST, true);
1390 	atomic_store(&check_listener_quota, true);
1391 	doh_half_recv_send(state);
1392 }
1393 
1394 ISC_RUN_TEST_IMPL(doh_half_recv_send_GET_TLS_quota) {
1395 	SKIP_IN_CI;
1396 
1397 	atomic_store(&use_TLS, true);
1398 	atomic_store(&POST, false);
1399 	atomic_store(&check_listener_quota, true);
1400 	doh_half_recv_send(state);
1401 }
1402 
1403 static void
1404 doh_half_recv_half_send(void **state) {
1405 	isc_nm_t **nm = (isc_nm_t **)*state;
1406 	isc_nm_t *listen_nm = nm[0];
1407 	isc_nm_t *connect_nm = nm[1];
1408 	isc_result_t result = ISC_R_SUCCESS;
1409 	isc_nmsocket_t *listen_sock = NULL;
1410 	size_t nthreads = ISC_MAX(ISC_MIN(workers, 32), 1);
1411 	isc_thread_t threads[32] = { 0 };
1412 	isc_quota_t *quotap = init_listener_quota(workers);
1413 
1414 	atomic_store(&total_sends, atomic_load(&total_sends) / 2);
1415 
1416 	atomic_store(&nsends, atomic_load(&total_sends));
1417 
1418 	result = isc_nm_http_endpoints_add(endpoints, ISC_NM_HTTP_DEFAULT_PATH,
1419 					   doh_receive_request_cb, NULL, 0);
1420 	assert_int_equal(result, ISC_R_SUCCESS);
1421 
1422 	result = isc_nm_listenhttp(listen_nm, &tcp_listen_addr, 0, quotap,
1423 				   atomic_load(&use_TLS) ? server_tlsctx : NULL,
1424 				   endpoints, 0, &listen_sock);
1425 	assert_int_equal(result, ISC_R_SUCCESS);
1426 
1427 	for (size_t i = 0; i < nthreads; i++) {
1428 		isc_thread_create(doh_connect_thread, connect_nm, &threads[i]);
1429 	}
1430 
1431 	while (atomic_load(&nsends) > 0) {
1432 		isc_thread_yield();
1433 	}
1434 
1435 	isc__netmgr_shutdown(connect_nm);
1436 	isc_nm_stoplistening(listen_sock);
1437 	isc_nmsocket_close(&listen_sock);
1438 	assert_null(listen_sock);
1439 
1440 	for (size_t i = 0; i < nthreads; i++) {
1441 		isc_thread_join(threads[i], NULL);
1442 	}
1443 
1444 	X(total_sends);
1445 	X(csends);
1446 	X(creads);
1447 	X(sreads);
1448 	X(ssends);
1449 
1450 	CHECK_RANGE_HALF(csends);
1451 	CHECK_RANGE_HALF(creads);
1452 	CHECK_RANGE_HALF(sreads);
1453 	CHECK_RANGE_HALF(ssends);
1454 }
1455 
1456 ISC_RUN_TEST_IMPL(doh_half_recv_half_send_POST) {
1457 	SKIP_IN_CI;
1458 
1459 	atomic_store(&POST, true);
1460 	doh_half_recv_half_send(state);
1461 }
1462 
1463 ISC_RUN_TEST_IMPL(doh_half_recv_half_send_GET) {
1464 	SKIP_IN_CI;
1465 
1466 	atomic_store(&POST, false);
1467 	doh_half_recv_half_send(state);
1468 }
1469 
1470 ISC_RUN_TEST_IMPL(doh_half_recv_half_send_POST_TLS) {
1471 	SKIP_IN_CI;
1472 
1473 	atomic_store(&use_TLS, true);
1474 	atomic_store(&POST, true);
1475 	doh_half_recv_half_send(state);
1476 }
1477 
1478 ISC_RUN_TEST_IMPL(doh_half_recv_half_send_GET_TLS) {
1479 	SKIP_IN_CI;
1480 
1481 	atomic_store(&use_TLS, true);
1482 	atomic_store(&POST, false);
1483 	doh_half_recv_half_send(state);
1484 }
1485 
1486 ISC_RUN_TEST_IMPL(doh_half_recv_half_send_POST_quota) {
1487 	SKIP_IN_CI;
1488 
1489 	atomic_store(&POST, true);
1490 	atomic_store(&check_listener_quota, true);
1491 	doh_half_recv_half_send(state);
1492 }
1493 
1494 ISC_RUN_TEST_IMPL(doh_half_recv_half_send_GET_quota) {
1495 	SKIP_IN_CI;
1496 
1497 	atomic_store(&POST, false);
1498 	atomic_store(&check_listener_quota, true);
1499 	doh_half_recv_half_send(state);
1500 }
1501 
1502 ISC_RUN_TEST_IMPL(doh_half_recv_half_send_POST_TLS_quota) {
1503 	SKIP_IN_CI;
1504 
1505 	atomic_store(&use_TLS, true);
1506 	atomic_store(&POST, true);
1507 	atomic_store(&check_listener_quota, true);
1508 	doh_half_recv_half_send(state);
1509 }
1510 
1511 ISC_RUN_TEST_IMPL(doh_half_recv_half_send_GET_TLS_quota) {
1512 	SKIP_IN_CI;
1513 
1514 	atomic_store(&use_TLS, true);
1515 	atomic_store(&POST, false);
1516 	atomic_store(&check_listener_quota, true);
1517 	doh_half_recv_half_send(state);
1518 }
1519 
1520 /* See: GL #2858, !5319 */
1521 ISC_RUN_TEST_IMPL(doh_bad_connect_uri) {
1522 	isc_nm_t **nm = (isc_nm_t **)*state;
1523 	isc_nm_t *listen_nm = nm[0];
1524 	isc_nm_t *connect_nm = nm[1];
1525 	isc_result_t result = ISC_R_SUCCESS;
1526 	isc_nmsocket_t *listen_sock = NULL;
1527 	char req_url[256];
1528 	isc_quota_t *quotap = init_listener_quota(workers);
1529 
1530 	atomic_store(&total_sends, 1);
1531 
1532 	atomic_store(&nsends, atomic_load(&total_sends));
1533 
1534 	result = isc_nm_http_endpoints_add(endpoints, ISC_NM_HTTP_DEFAULT_PATH,
1535 					   doh_receive_request_cb, NULL, 0);
1536 	assert_int_equal(result, ISC_R_SUCCESS);
1537 
1538 	result = isc_nm_listenhttp(listen_nm, &tcp_listen_addr, 0, quotap,
1539 				   server_tlsctx, endpoints, 0, &listen_sock);
1540 	assert_int_equal(result, ISC_R_SUCCESS);
1541 
1542 	/*
1543 	 * "https://::1:XXXX/dns-query" is a bad URI, it should be
1544 	 * "https://[::1]:XXXX/dns-query"
1545 	 */
1546 	(void)snprintf(req_url, sizeof(req_url), "https://::1:%u/%s",
1547 		       isc_sockaddr_getport(&tcp_listen_addr),
1548 		       ISC_NM_HTTP_DEFAULT_PATH);
1549 	connect_send_request(connect_nm, req_url, atomic_load(&POST),
1550 			     &(isc_region_t){ .base = (uint8_t *)send_msg.base,
1551 					      .length = send_msg.len },
1552 			     doh_receive_reply_cb, NULL, true, 30000);
1553 
1554 	while (atomic_load(&nsends) > 0) {
1555 		if (atomic_load(&was_error)) {
1556 			break;
1557 		}
1558 		isc_thread_yield();
1559 	}
1560 
1561 	isc_nm_stoplistening(listen_sock);
1562 	isc_nmsocket_close(&listen_sock);
1563 	assert_null(listen_sock);
1564 	isc__netmgr_shutdown(connect_nm);
1565 
1566 	X(total_sends);
1567 	X(csends);
1568 	X(creads);
1569 	X(sreads);
1570 	X(ssends);
1571 
1572 	/* As we used an ill-formed URI, there ought to be an error. */
1573 	assert_true(atomic_load(&was_error));
1574 	assert_int_equal(atomic_load(&csends), 0);
1575 	assert_int_equal(atomic_load(&creads), 0);
1576 	assert_int_equal(atomic_load(&sreads), 0);
1577 	assert_int_equal(atomic_load(&ssends), 0);
1578 }
1579 
1580 ISC_RUN_TEST_IMPL(doh_parse_GET_query_string) {
1581 	UNUSED(state);
1582 	/* valid */
1583 	{
1584 		bool ret;
1585 		const char *queryp = NULL;
1586 		size_t len = 0;
1587 		char str[] =
1588 			"dns=AAABAAABAAAAAAAAAWE-"
1589 			"NjJjaGFyYWN0ZXJsYWJlbC1tYWtlcy1iYXNlNjR1cmwtZGlzdGluY3"
1590 			"QtZnJvbS1zdGFuZGFyZC1iYXNlNjQHZXhhbXBsZQNjb20AAAEAAQ";
1591 
1592 		ret = isc__nm_parse_httpquery(str, &queryp, &len);
1593 		assert_true(ret);
1594 		assert_non_null(queryp);
1595 		assert_true(len > 0);
1596 		assert_true(len == strlen(str) - 4);
1597 		assert_true(memcmp(queryp, str + 4, len) == 0);
1598 	}
1599 	/* valid */
1600 	{
1601 		bool ret;
1602 		const char *queryp = NULL;
1603 		size_t len = 0;
1604 		char str[] =
1605 			"?dns=AAABAAABAAAAAAAAAWE-"
1606 			"NjJjaGFyYWN0ZXJsYWJlbC1tYWtlcy1iYXNlNjR1cmwtZGlzdGluY3"
1607 			"QtZnJvbS1zdGFuZGFyZC1iYXNlNjQHZXhhbXBsZQNjb20AAAEAAQ&";
1608 
1609 		ret = isc__nm_parse_httpquery(str, &queryp, &len);
1610 		assert_true(ret);
1611 		assert_non_null(queryp);
1612 		assert_true(len > 0);
1613 		assert_true(len == strlen(str) - 6);
1614 		assert_true(memcmp(queryp, str + 5, len) == 0);
1615 	}
1616 	/* valid */
1617 	{
1618 		bool ret;
1619 		const char *queryp = NULL;
1620 		size_t len = 0;
1621 		char str[] = "?dns=123&dns=567";
1622 
1623 		ret = isc__nm_parse_httpquery(str, &queryp, &len);
1624 		assert_true(ret);
1625 		assert_non_null(queryp);
1626 		assert_true(len > 0);
1627 		assert_true(len == 3);
1628 		assert_true(memcmp(queryp, "567", 3) == 0);
1629 	}
1630 	/* valid */
1631 	{
1632 		bool ret;
1633 		const char *queryp = NULL;
1634 		size_t len = 0;
1635 		char str[] = "?name1=123&dns=567&name2=123&";
1636 
1637 		ret = isc__nm_parse_httpquery(str, &queryp, &len);
1638 		assert_true(ret);
1639 		assert_non_null(queryp);
1640 		assert_true(len > 0);
1641 		assert_true(len == 3);
1642 		assert_true(memcmp(queryp, "567", 3) == 0);
1643 	}
1644 	/* complex, but still valid */
1645 	{
1646 		bool ret;
1647 		const char *queryp = NULL;
1648 		size_t len = 0;
1649 		char str[] =
1650 			"?title=%D0%92%D1%96%D0%B4%D1%81%D0%BE%D1%82%D0%BA%D0%"
1651 			"BE%D0%B2%D0%B5_%D0%BA%D0%BE%D0%B4%D1%83%D0%B2%D0%B0%"
1652 			"D0%BD%D0%BD%D1%8F&dns=123&veaction=edit&section=0";
1653 
1654 		ret = isc__nm_parse_httpquery(str, &queryp, &len);
1655 		assert_true(ret);
1656 		assert_non_null(queryp);
1657 		assert_true(len > 0);
1658 		assert_true(len == 3);
1659 		assert_true(memcmp(queryp, "123", 3) == 0);
1660 	}
1661 	/* invalid */
1662 	{
1663 		bool ret;
1664 		const char *queryp = NULL;
1665 		size_t len = 0;
1666 		char str[] =
1667 			"?title=%D0%92%D1%96%D0%B4%D1%81%D0%BE%D1%82%D0%BA%D0%"
1668 			"BE%D0%B2%D0%B5_%D0%BA%D0%BE%D0%B4%D1%83%D0%B2%D0%B0%"
1669 			"D0%BD%D0%BD%D1%8F&veaction=edit&section=0";
1670 
1671 		ret = isc__nm_parse_httpquery(str, &queryp, &len);
1672 		assert_false(ret);
1673 		assert_null(queryp);
1674 		assert_true(len == 0);
1675 	}
1676 	/* invalid */
1677 	{
1678 		bool ret;
1679 		const char *queryp = NULL;
1680 		size_t len = 0;
1681 		char str[] = "";
1682 
1683 		ret = isc__nm_parse_httpquery(str, &queryp, &len);
1684 		assert_false(ret);
1685 		assert_null(queryp);
1686 		assert_true(len == 0);
1687 	}
1688 	/* invalid */
1689 	{
1690 		bool ret;
1691 		const char *queryp = NULL;
1692 		size_t len = 0;
1693 		char str[] = "?&";
1694 
1695 		ret = isc__nm_parse_httpquery(str, &queryp, &len);
1696 		assert_false(ret);
1697 		assert_null(queryp);
1698 		assert_true(len == 0);
1699 	}
1700 	/* invalid */
1701 	{
1702 		bool ret;
1703 		const char *queryp = NULL;
1704 		size_t len = 0;
1705 		char str[] = "?dns&";
1706 
1707 		ret = isc__nm_parse_httpquery(str, &queryp, &len);
1708 		assert_false(ret);
1709 		assert_null(queryp);
1710 		assert_true(len == 0);
1711 	}
1712 	/* invalid */
1713 	{
1714 		bool ret;
1715 		const char *queryp = NULL;
1716 		size_t len = 0;
1717 		char str[] = "?dns=&";
1718 
1719 		ret = isc__nm_parse_httpquery(str, &queryp, &len);
1720 		assert_false(ret);
1721 		assert_null(queryp);
1722 		assert_true(len == 0);
1723 	}
1724 	/* invalid */
1725 	{
1726 		bool ret;
1727 		const char *queryp = NULL;
1728 		size_t len = 0;
1729 		char str[] = "?dns=123&&";
1730 
1731 		ret = isc__nm_parse_httpquery(str, &queryp, &len);
1732 		assert_false(ret);
1733 		assert_null(queryp);
1734 		assert_true(len == 0);
1735 	}
1736 	/* valid */
1737 	{
1738 		bool ret;
1739 		const char *queryp = NULL;
1740 		size_t len = 0;
1741 		char str[] = "?dns=123%12&";
1742 
1743 		ret = isc__nm_parse_httpquery(str, &queryp, &len);
1744 		assert_true(ret);
1745 		assert_non_null(queryp);
1746 		assert_true(len > 0);
1747 		assert_true(len == 6);
1748 		assert_true(memcmp(queryp, "123%12", 6) == 0);
1749 	}
1750 	/* invalid */
1751 	{
1752 		bool ret;
1753 		const char *queryp = NULL;
1754 		size_t len = 0;
1755 		char str[] = "?dns=123%ZZ&";
1756 
1757 		ret = isc__nm_parse_httpquery(str, &queryp, &len);
1758 		assert_false(ret);
1759 		assert_null(queryp);
1760 		assert_true(len == 0);
1761 	}
1762 	/* invalid */
1763 	{
1764 		bool ret;
1765 		const char *queryp = NULL;
1766 		size_t len = 0;
1767 		char str[] = "?dns=123%%&";
1768 
1769 		ret = isc__nm_parse_httpquery(str, &queryp, &len);
1770 		assert_false(ret);
1771 		assert_null(queryp);
1772 		assert_true(len == 0);
1773 	}
1774 	/* invalid */
1775 	{
1776 		bool ret;
1777 		const char *queryp = NULL;
1778 		size_t len = 0;
1779 		char str[] = "?dns=123%AZ&";
1780 
1781 		ret = isc__nm_parse_httpquery(str, &queryp, &len);
1782 		assert_false(ret);
1783 		assert_null(queryp);
1784 		assert_true(len == 0);
1785 	}
1786 	/* valid */
1787 	{
1788 		bool ret;
1789 		const char *queryp = NULL;
1790 		size_t len = 0;
1791 		char str[] = "?dns=123%0AZ&";
1792 
1793 		ret = isc__nm_parse_httpquery(str, &queryp, &len);
1794 		assert_true(ret);
1795 		assert_non_null(queryp);
1796 		assert_true(len > 0);
1797 		assert_true(len == 7);
1798 		assert_true(memcmp(queryp, "123%0AZ", 7) == 0);
1799 	}
1800 }
1801 
1802 ISC_RUN_TEST_IMPL(doh_base64url_to_base64) {
1803 	UNUSED(state);
1804 	char *res;
1805 	size_t res_len = 0;
1806 	/* valid */
1807 	{
1808 		char test[] = "YW55IGNhcm5hbCBwbGVhc3VyZS4";
1809 		char res_test[] = "YW55IGNhcm5hbCBwbGVhc3VyZS4=";
1810 
1811 		res = isc__nm_base64url_to_base64(mctx, test, strlen(test),
1812 						  &res_len);
1813 		assert_non_null(res);
1814 		assert_true(res_len == strlen(res_test));
1815 		assert_true(strcmp(res, res_test) == 0);
1816 		isc_mem_free(mctx, res);
1817 	}
1818 	/* valid */
1819 	{
1820 		char test[] = "YW55IGNhcm5hbCBwbGVhcw";
1821 		char res_test[] = "YW55IGNhcm5hbCBwbGVhcw==";
1822 
1823 		res = isc__nm_base64url_to_base64(mctx, test, strlen(test),
1824 						  &res_len);
1825 		assert_non_null(res);
1826 		assert_true(res_len == strlen(res_test));
1827 		assert_true(strcmp(res, res_test) == 0);
1828 		isc_mem_free(mctx, res);
1829 	}
1830 	/* valid */
1831 	{
1832 		char test[] = "YW55IGNhcm5hbCBwbGVhc3Vy";
1833 		char res_test[] = "YW55IGNhcm5hbCBwbGVhc3Vy";
1834 
1835 		res = isc__nm_base64url_to_base64(mctx, test, strlen(test),
1836 						  &res_len);
1837 		assert_non_null(res);
1838 		assert_true(res_len == strlen(res_test));
1839 		assert_true(strcmp(res, res_test) == 0);
1840 		isc_mem_free(mctx, res);
1841 	}
1842 	/* valid */
1843 	{
1844 		char test[] = "YW55IGNhcm5hbCBwbGVhc3U";
1845 		char res_test[] = "YW55IGNhcm5hbCBwbGVhc3U=";
1846 
1847 		res = isc__nm_base64url_to_base64(mctx, test, strlen(test),
1848 						  &res_len);
1849 		assert_non_null(res);
1850 		assert_true(res_len == strlen(res_test));
1851 		assert_true(strcmp(res, res_test) == 0);
1852 		isc_mem_free(mctx, res);
1853 	}
1854 	/* valid */
1855 	{
1856 		char test[] = "YW55IGNhcm5hbCBwbGVhcw";
1857 		char res_test[] = "YW55IGNhcm5hbCBwbGVhcw==";
1858 
1859 		res = isc__nm_base64url_to_base64(mctx, test, strlen(test),
1860 						  &res_len);
1861 		assert_non_null(res);
1862 		assert_true(res_len == strlen(res_test));
1863 		assert_true(strcmp(res, res_test) == 0);
1864 		isc_mem_free(mctx, res);
1865 	}
1866 	/* valid */
1867 	{
1868 		char test[] = "PDw_Pz8-Pg";
1869 		char res_test[] = "PDw/Pz8+Pg==";
1870 
1871 		res = isc__nm_base64url_to_base64(mctx, test, strlen(test),
1872 						  &res_len);
1873 		assert_non_null(res);
1874 		assert_true(res_len == strlen(res_test));
1875 		assert_true(strcmp(res, res_test) == 0);
1876 		isc_mem_free(mctx, res);
1877 	}
1878 	/* valid */
1879 	{
1880 		char test[] = "PDw_Pz8-Pg";
1881 		char res_test[] = "PDw/Pz8+Pg==";
1882 
1883 		res = isc__nm_base64url_to_base64(mctx, test, strlen(test),
1884 						  NULL);
1885 		assert_non_null(res);
1886 		assert_true(strcmp(res, res_test) == 0);
1887 		isc_mem_free(mctx, res);
1888 	}
1889 	/* invalid */
1890 	{
1891 		char test[] = "YW55IGNhcm5hbCBwbGVhcw";
1892 		res_len = 0;
1893 
1894 		res = isc__nm_base64url_to_base64(mctx, test, 0, &res_len);
1895 		assert_null(res);
1896 		assert_true(res_len == 0);
1897 	}
1898 	/* invalid */
1899 	{
1900 		char test[] = "";
1901 		res_len = 0;
1902 
1903 		res = isc__nm_base64url_to_base64(mctx, test, strlen(test),
1904 						  &res_len);
1905 		assert_null(res);
1906 		assert_true(res_len == 0);
1907 	}
1908 	/* invalid */
1909 	{
1910 		char test[] = "PDw_Pz8-Pg==";
1911 		res_len = 0;
1912 
1913 		res = isc__nm_base64url_to_base64(mctx, test, strlen(test),
1914 						  &res_len);
1915 		assert_null(res);
1916 		assert_true(res_len == 0);
1917 	}
1918 	/* invalid */
1919 	{
1920 		char test[] = "PDw_Pz8-Pg%3D%3D"; /* percent encoded "==" at the
1921 						     end */
1922 		res_len = 0;
1923 
1924 		res = isc__nm_base64url_to_base64(mctx, test, strlen(test),
1925 						  &res_len);
1926 		assert_null(res);
1927 		assert_true(res_len == 0);
1928 	}
1929 	/* invalid */
1930 	{
1931 		res_len = 0;
1932 
1933 		res = isc__nm_base64url_to_base64(mctx, NULL, 31231, &res_len);
1934 		assert_null(res);
1935 		assert_true(res_len == 0);
1936 	}
1937 }
1938 
1939 ISC_RUN_TEST_IMPL(doh_base64_to_base64url) {
1940 	char *res;
1941 	size_t res_len = 0;
1942 	UNUSED(state);
1943 	/* valid */
1944 	{
1945 		char res_test[] = "YW55IGNhcm5hbCBwbGVhc3VyZS4";
1946 		char test[] = "YW55IGNhcm5hbCBwbGVhc3VyZS4=";
1947 
1948 		res = isc__nm_base64_to_base64url(mctx, test, strlen(test),
1949 						  &res_len);
1950 		assert_non_null(res);
1951 		assert_true(res_len == strlen(res_test));
1952 		assert_true(strcmp(res, res_test) == 0);
1953 		isc_mem_free(mctx, res);
1954 	}
1955 	/* valid */
1956 	{
1957 		char res_test[] = "YW55IGNhcm5hbCBwbGVhcw";
1958 		char test[] = "YW55IGNhcm5hbCBwbGVhcw==";
1959 
1960 		res = isc__nm_base64_to_base64url(mctx, test, strlen(test),
1961 						  &res_len);
1962 		assert_non_null(res);
1963 		assert_true(res_len == strlen(res_test));
1964 		assert_true(strcmp(res, res_test) == 0);
1965 		isc_mem_free(mctx, res);
1966 	}
1967 	/* valid */
1968 	{
1969 		char res_test[] = "YW55IGNhcm5hbCBwbGVhc3Vy";
1970 		char test[] = "YW55IGNhcm5hbCBwbGVhc3Vy";
1971 
1972 		res = isc__nm_base64_to_base64url(mctx, test, strlen(test),
1973 						  &res_len);
1974 		assert_non_null(res);
1975 		assert_true(res_len == strlen(res_test));
1976 		assert_true(strcmp(res, res_test) == 0);
1977 		isc_mem_free(mctx, res);
1978 	}
1979 	/* valid */
1980 	{
1981 		char res_test[] = "YW55IGNhcm5hbCBwbGVhc3U";
1982 		char test[] = "YW55IGNhcm5hbCBwbGVhc3U=";
1983 
1984 		res = isc__nm_base64_to_base64url(mctx, test, strlen(test),
1985 						  &res_len);
1986 		assert_non_null(res);
1987 		assert_true(res_len == strlen(res_test));
1988 		assert_true(strcmp(res, res_test) == 0);
1989 		isc_mem_free(mctx, res);
1990 	}
1991 	/* valid */
1992 	{
1993 		char res_test[] = "YW55IGNhcm5hbCBwbGVhcw";
1994 		char test[] = "YW55IGNhcm5hbCBwbGVhcw==";
1995 
1996 		res = isc__nm_base64_to_base64url(mctx, test, strlen(test),
1997 						  &res_len);
1998 		assert_non_null(res);
1999 		assert_true(res_len == strlen(res_test));
2000 		assert_true(strcmp(res, res_test) == 0);
2001 		isc_mem_free(mctx, res);
2002 	}
2003 	/* valid */
2004 	{
2005 		char res_test[] = "PDw_Pz8-Pg";
2006 		char test[] = "PDw/Pz8+Pg==";
2007 
2008 		res = isc__nm_base64_to_base64url(mctx, test, strlen(test),
2009 						  &res_len);
2010 		assert_non_null(res);
2011 		assert_true(res_len == strlen(res_test));
2012 		assert_true(strcmp(res, res_test) == 0);
2013 		isc_mem_free(mctx, res);
2014 	}
2015 	/* valid */
2016 	{
2017 		char res_test[] = "PDw_Pz8-Pg";
2018 		char test[] = "PDw/Pz8+Pg==";
2019 
2020 		res = isc__nm_base64_to_base64url(mctx, test, strlen(test),
2021 						  NULL);
2022 		assert_non_null(res);
2023 		assert_true(strcmp(res, res_test) == 0);
2024 		isc_mem_free(mctx, res);
2025 	}
2026 	/* invalid */
2027 	{
2028 		char test[] = "YW55IGNhcm5hbCBwbGVhcw";
2029 		res_len = 0;
2030 
2031 		res = isc__nm_base64_to_base64url(mctx, test, 0, &res_len);
2032 		assert_null(res);
2033 		assert_true(res_len == 0);
2034 	}
2035 	/* invalid */
2036 	{
2037 		char test[] = "";
2038 		res_len = 0;
2039 
2040 		res = isc__nm_base64_to_base64url(mctx, test, strlen(test),
2041 						  &res_len);
2042 		assert_null(res);
2043 		assert_true(res_len == 0);
2044 	}
2045 	/* invalid */
2046 	{
2047 		char test[] = "PDw_Pz8-Pg==";
2048 		res_len = 0;
2049 
2050 		res = isc__nm_base64_to_base64url(mctx, test, strlen(test),
2051 						  &res_len);
2052 		assert_null(res);
2053 		assert_true(res_len == 0);
2054 	}
2055 	/* invalid */
2056 	{
2057 		char test[] = "PDw_Pz8-Pg%3D%3D"; /* percent encoded "==" at the
2058 						     end */
2059 		res_len = 0;
2060 
2061 		res = isc__nm_base64_to_base64url(mctx, test, strlen(test),
2062 						  &res_len);
2063 		assert_null(res);
2064 		assert_true(res_len == 0);
2065 	}
2066 	/* invalid */
2067 	{
2068 		res_len = 0;
2069 
2070 		res = isc__nm_base64_to_base64url(mctx, NULL, 31231, &res_len);
2071 		assert_null(res);
2072 		assert_true(res_len == 0);
2073 	}
2074 }
2075 
2076 ISC_RUN_TEST_IMPL(doh_path_validation) {
2077 	UNUSED(state);
2078 
2079 	assert_true(isc_nm_http_path_isvalid("/"));
2080 	assert_true(isc_nm_http_path_isvalid(ISC_NM_HTTP_DEFAULT_PATH));
2081 	assert_false(isc_nm_http_path_isvalid("laaaa"));
2082 	assert_false(isc_nm_http_path_isvalid(""));
2083 	assert_false(isc_nm_http_path_isvalid("//"));
2084 	assert_true(isc_nm_http_path_isvalid("/lala///"));
2085 	assert_true(isc_nm_http_path_isvalid("/lalaaaaaa"));
2086 	assert_true(isc_nm_http_path_isvalid("/lalaaa/la/la/la"));
2087 	assert_true(isc_nm_http_path_isvalid("/la/a"));
2088 	assert_true(isc_nm_http_path_isvalid("/la+la"));
2089 	assert_true(isc_nm_http_path_isvalid("/la&la/la*la/l-a_/la!/la\'"));
2090 	assert_true(isc_nm_http_path_isvalid("/la/(la)/la"));
2091 	assert_true(isc_nm_http_path_isvalid("/la,la,la"));
2092 	assert_true(isc_nm_http_path_isvalid("/la-'la'-la"));
2093 	assert_true(isc_nm_http_path_isvalid("/la:la=la"));
2094 	assert_true(isc_nm_http_path_isvalid("/l@l@l@"));
2095 	assert_false(isc_nm_http_path_isvalid("/#lala"));
2096 	assert_true(isc_nm_http_path_isvalid("/lala;la"));
2097 	assert_false(
2098 		isc_nm_http_path_isvalid("la&la/laalaala*lala/l-al_a/lal!/"));
2099 	assert_true(isc_nm_http_path_isvalid("/Lal/lAla.jpg"));
2100 
2101 	/* had to replace ? with ! because it does not verify a query string */
2102 	assert_true(isc_nm_http_path_isvalid("/watch!v=oavMtUWDBTM"));
2103 	assert_false(isc_nm_http_path_isvalid("/watch?v=dQw4w9WgXcQ"));
2104 	assert_true(isc_nm_http_path_isvalid("/datatracker.ietf.org/doc/html/"
2105 					     "rfc2616"));
2106 	assert_true(isc_nm_http_path_isvalid("/doc/html/rfc8484"));
2107 	assert_true(isc_nm_http_path_isvalid("/123"));
2108 }
2109 
2110 ISC_RUN_TEST_IMPL(doh_connect_makeuri) {
2111 	struct in_addr localhostv4 = { .s_addr = ntohl(INADDR_LOOPBACK) };
2112 	isc_sockaddr_t sa;
2113 	char uri[256];
2114 	UNUSED(state);
2115 
2116 	/* Firstly, test URI generation using isc_sockaddr_t */
2117 	isc_sockaddr_fromin(&sa, &localhostv4, 0);
2118 	uri[0] = '\0';
2119 	isc_nm_http_makeuri(true, &sa, NULL, 0, ISC_NM_HTTP_DEFAULT_PATH, uri,
2120 			    sizeof(uri));
2121 	assert_true(strcmp("https://127.0.0.1:443/dns-query", uri) == 0);
2122 
2123 	uri[0] = '\0';
2124 	isc_nm_http_makeuri(false, &sa, NULL, 0, ISC_NM_HTTP_DEFAULT_PATH, uri,
2125 			    sizeof(uri));
2126 	assert_true(strcmp("http://127.0.0.1:80/dns-query", uri) == 0);
2127 
2128 	/*
2129 	 * The port value should be ignored, because we can get one from
2130 	 * the isc_sockaddr_t object.
2131 	 */
2132 	uri[0] = '\0';
2133 	isc_nm_http_makeuri(true, &sa, NULL, 44343, ISC_NM_HTTP_DEFAULT_PATH,
2134 			    uri, sizeof(uri));
2135 	assert_true(strcmp("https://127.0.0.1:443/dns-query", uri) == 0);
2136 
2137 	uri[0] = '\0';
2138 	isc_nm_http_makeuri(false, &sa, NULL, 8080, ISC_NM_HTTP_DEFAULT_PATH,
2139 			    uri, sizeof(uri));
2140 	assert_true(strcmp("http://127.0.0.1:80/dns-query", uri) == 0);
2141 
2142 	/* IPv6 */
2143 	isc_sockaddr_fromin6(&sa, &in6addr_loopback, 0);
2144 	uri[0] = '\0';
2145 	isc_nm_http_makeuri(true, &sa, NULL, 0, ISC_NM_HTTP_DEFAULT_PATH, uri,
2146 			    sizeof(uri));
2147 	assert_true(strcmp("https://[::1]:443/dns-query", uri) == 0);
2148 
2149 	uri[0] = '\0';
2150 	isc_nm_http_makeuri(false, &sa, NULL, 0, ISC_NM_HTTP_DEFAULT_PATH, uri,
2151 			    sizeof(uri));
2152 	assert_true(strcmp("http://[::1]:80/dns-query", uri) == 0);
2153 
2154 	/*
2155 	 * The port value should be ignored, because we can get one from
2156 	 * the isc_sockaddr_t object.
2157 	 */
2158 	uri[0] = '\0';
2159 	isc_nm_http_makeuri(true, &sa, NULL, 44343, ISC_NM_HTTP_DEFAULT_PATH,
2160 			    uri, sizeof(uri));
2161 	assert_true(strcmp("https://[::1]:443/dns-query", uri) == 0);
2162 
2163 	uri[0] = '\0';
2164 	isc_nm_http_makeuri(false, &sa, NULL, 8080, ISC_NM_HTTP_DEFAULT_PATH,
2165 			    uri, sizeof(uri));
2166 	assert_true(strcmp("http://[::1]:80/dns-query", uri) == 0);
2167 
2168 	/* Try to set the port numbers. */
2169 	isc_sockaddr_setport(&sa, 44343);
2170 	uri[0] = '\0';
2171 	isc_nm_http_makeuri(true, &sa, NULL, 0, ISC_NM_HTTP_DEFAULT_PATH, uri,
2172 			    sizeof(uri));
2173 	assert_true(strcmp("https://[::1]:44343/dns-query", uri) == 0);
2174 
2175 	isc_sockaddr_setport(&sa, 8080);
2176 	uri[0] = '\0';
2177 	isc_nm_http_makeuri(false, &sa, NULL, 0, ISC_NM_HTTP_DEFAULT_PATH, uri,
2178 			    sizeof(uri));
2179 	assert_true(strcmp("http://[::1]:8080/dns-query", uri) == 0);
2180 
2181 	/*
2182 	 * Try to make a URI using a hostname and a port number. The
2183 	 * isc_sockaddr_t object will be ignored.
2184 	 */
2185 	isc_sockaddr_any(&sa);
2186 	uri[0] = '\0';
2187 	isc_nm_http_makeuri(true, &sa, "example.com", 0,
2188 			    ISC_NM_HTTP_DEFAULT_PATH, uri, sizeof(uri));
2189 	assert_true(strcmp("https://example.com:443/dns-query", uri) == 0);
2190 
2191 	uri[0] = '\0';
2192 	isc_nm_http_makeuri(false, &sa, "example.com", 0,
2193 			    ISC_NM_HTTP_DEFAULT_PATH, uri, sizeof(uri));
2194 	assert_true(strcmp("http://example.com:80/dns-query", uri) == 0);
2195 
2196 	/* Try to set the port numbers. */
2197 	isc_sockaddr_setport(&sa, 443);
2198 	uri[0] = '\0';
2199 	isc_nm_http_makeuri(true, &sa, "example.com", 44343,
2200 			    ISC_NM_HTTP_DEFAULT_PATH, uri, sizeof(uri));
2201 	assert_true(strcmp("https://example.com:44343/dns-query", uri) == 0);
2202 
2203 	isc_sockaddr_setport(&sa, 80);
2204 	uri[0] = '\0';
2205 	isc_nm_http_makeuri(false, &sa, "example.com", 8080,
2206 			    ISC_NM_HTTP_DEFAULT_PATH, uri, sizeof(uri));
2207 	assert_true(strcmp("http://example.com:8080/dns-query", uri) == 0);
2208 
2209 	/* IPv4 as the hostname - nothing fancy here */
2210 	uri[0] = '\0';
2211 	isc_nm_http_makeuri(false, NULL, "127.0.0.1", 8080,
2212 			    ISC_NM_HTTP_DEFAULT_PATH, uri, sizeof(uri));
2213 	assert_true(strcmp("http://127.0.0.1:8080/dns-query", uri) == 0);
2214 
2215 	uri[0] = '\0';
2216 	isc_nm_http_makeuri(true, NULL, "127.0.0.1", 44343,
2217 			    ISC_NM_HTTP_DEFAULT_PATH, uri, sizeof(uri));
2218 	assert_true(strcmp("https://127.0.0.1:44343/dns-query", uri) == 0);
2219 
2220 	/*
2221 	 * A peculiar edge case: IPv6 given as the hostname (notice
2222 	 * the brackets)
2223 	 */
2224 	uri[0] = '\0';
2225 	isc_nm_http_makeuri(false, NULL, "::1", 8080, ISC_NM_HTTP_DEFAULT_PATH,
2226 			    uri, sizeof(uri));
2227 	assert_true(strcmp("http://[::1]:8080/dns-query", uri) == 0);
2228 
2229 	uri[0] = '\0';
2230 	isc_nm_http_makeuri(true, NULL, "[::1]", 44343,
2231 			    ISC_NM_HTTP_DEFAULT_PATH, uri, sizeof(uri));
2232 	assert_true(strcmp("https://[::1]:44343/dns-query", uri) == 0);
2233 }
2234 
2235 ISC_TEST_LIST_START
2236 ISC_TEST_ENTRY_CUSTOM(mock_doh_uv_tcp_bind, setup_test, teardown_test)
2237 ISC_TEST_ENTRY(doh_parse_GET_query_string)
2238 ISC_TEST_ENTRY(doh_base64url_to_base64)
2239 ISC_TEST_ENTRY(doh_base64_to_base64url)
2240 ISC_TEST_ENTRY(doh_path_validation)
2241 ISC_TEST_ENTRY(doh_connect_makeuri)
2242 ISC_TEST_ENTRY_CUSTOM(doh_noop_POST, setup_test, teardown_test)
2243 ISC_TEST_ENTRY_CUSTOM(doh_noop_GET, setup_test, teardown_test)
2244 ISC_TEST_ENTRY_CUSTOM(doh_noresponse_POST, setup_test, teardown_test)
2245 ISC_TEST_ENTRY_CUSTOM(doh_noresponse_GET, setup_test, teardown_test)
2246 ISC_TEST_ENTRY_CUSTOM(doh_timeout_recovery_POST, setup_test, teardown_test)
2247 ISC_TEST_ENTRY_CUSTOM(doh_timeout_recovery_GET, setup_test, teardown_test)
2248 ISC_TEST_ENTRY_CUSTOM(doh_recv_one_POST, setup_test, teardown_test)
2249 ISC_TEST_ENTRY_CUSTOM(doh_recv_one_GET, setup_test, teardown_test)
2250 ISC_TEST_ENTRY_CUSTOM(doh_recv_one_POST_TLS, setup_test, teardown_test)
2251 ISC_TEST_ENTRY_CUSTOM(doh_recv_one_GET_TLS, setup_test, teardown_test)
2252 ISC_TEST_ENTRY_CUSTOM(doh_recv_one_POST_quota, setup_test, teardown_test)
2253 ISC_TEST_ENTRY_CUSTOM(doh_recv_one_GET_quota, setup_test, teardown_test)
2254 ISC_TEST_ENTRY_CUSTOM(doh_recv_one_POST_TLS_quota, setup_test, teardown_test)
2255 ISC_TEST_ENTRY_CUSTOM(doh_recv_one_GET_TLS_quota, setup_test, teardown_test)
2256 ISC_TEST_ENTRY_CUSTOM(doh_recv_two_POST, setup_test, teardown_test)
2257 ISC_TEST_ENTRY_CUSTOM(doh_recv_two_GET, setup_test, teardown_test)
2258 ISC_TEST_ENTRY_CUSTOM(doh_recv_two_POST_TLS, setup_test, teardown_test)
2259 ISC_TEST_ENTRY_CUSTOM(doh_recv_two_GET_TLS, setup_test, teardown_test)
2260 ISC_TEST_ENTRY_CUSTOM(doh_recv_two_POST_quota, setup_test, teardown_test)
2261 ISC_TEST_ENTRY_CUSTOM(doh_recv_two_GET_quota, setup_test, teardown_test)
2262 ISC_TEST_ENTRY_CUSTOM(doh_recv_two_POST_TLS_quota, setup_test, teardown_test)
2263 ISC_TEST_ENTRY_CUSTOM(doh_recv_two_GET_TLS_quota, setup_test, teardown_test)
2264 ISC_TEST_ENTRY_CUSTOM(doh_recv_send_GET, setup_test, teardown_test)
2265 ISC_TEST_ENTRY_CUSTOM(doh_recv_send_POST, setup_test, teardown_test)
2266 ISC_TEST_ENTRY_CUSTOM(doh_recv_send_GET_TLS, setup_test, teardown_test)
2267 ISC_TEST_ENTRY_CUSTOM(doh_recv_send_POST_TLS, setup_test, teardown_test)
2268 ISC_TEST_ENTRY_CUSTOM(doh_recv_send_GET_quota, setup_test, teardown_test)
2269 ISC_TEST_ENTRY_CUSTOM(doh_recv_send_POST_quota, setup_test, teardown_test)
2270 ISC_TEST_ENTRY_CUSTOM(doh_recv_send_GET_TLS_quota, setup_test, teardown_test)
2271 ISC_TEST_ENTRY_CUSTOM(doh_recv_send_POST_TLS_quota, setup_test, teardown_test)
2272 ISC_TEST_ENTRY_CUSTOM(doh_recv_half_send_GET, setup_test, teardown_test)
2273 ISC_TEST_ENTRY_CUSTOM(doh_recv_half_send_POST, setup_test, teardown_test)
2274 ISC_TEST_ENTRY_CUSTOM(doh_recv_half_send_GET_TLS, setup_test, teardown_test)
2275 ISC_TEST_ENTRY_CUSTOM(doh_recv_half_send_POST_TLS, setup_test, teardown_test)
2276 ISC_TEST_ENTRY_CUSTOM(doh_recv_half_send_GET_quota, setup_test, teardown_test)
2277 ISC_TEST_ENTRY_CUSTOM(doh_recv_half_send_POST_quota, setup_test, teardown_test)
2278 ISC_TEST_ENTRY_CUSTOM(doh_recv_half_send_GET_TLS_quota, setup_test,
2279 		      teardown_test)
2280 ISC_TEST_ENTRY_CUSTOM(doh_recv_half_send_POST_TLS_quota, setup_test,
2281 		      teardown_test)
2282 ISC_TEST_ENTRY_CUSTOM(doh_half_recv_send_GET, setup_test, teardown_test)
2283 ISC_TEST_ENTRY_CUSTOM(doh_half_recv_send_POST, setup_test, teardown_test)
2284 ISC_TEST_ENTRY_CUSTOM(doh_half_recv_send_GET_TLS, setup_test, teardown_test)
2285 ISC_TEST_ENTRY_CUSTOM(doh_half_recv_send_POST_TLS, setup_test, teardown_test)
2286 ISC_TEST_ENTRY_CUSTOM(doh_half_recv_send_GET_quota, setup_test, teardown_test)
2287 ISC_TEST_ENTRY_CUSTOM(doh_half_recv_send_POST_quota, setup_test, teardown_test)
2288 ISC_TEST_ENTRY_CUSTOM(doh_half_recv_send_GET_TLS_quota, setup_test,
2289 		      teardown_test)
2290 ISC_TEST_ENTRY_CUSTOM(doh_half_recv_send_POST_TLS_quota, setup_test,
2291 		      teardown_test)
2292 ISC_TEST_ENTRY_CUSTOM(doh_half_recv_half_send_GET, setup_test, teardown_test)
2293 ISC_TEST_ENTRY_CUSTOM(doh_half_recv_half_send_POST, setup_test, teardown_test)
2294 ISC_TEST_ENTRY_CUSTOM(doh_half_recv_half_send_GET_TLS, setup_test,
2295 		      teardown_test)
2296 ISC_TEST_ENTRY_CUSTOM(doh_half_recv_half_send_POST_TLS, setup_test,
2297 		      teardown_test)
2298 ISC_TEST_ENTRY_CUSTOM(doh_half_recv_half_send_GET_quota, setup_test,
2299 		      teardown_test)
2300 ISC_TEST_ENTRY_CUSTOM(doh_half_recv_half_send_POST_quota, setup_test,
2301 		      teardown_test)
2302 ISC_TEST_ENTRY_CUSTOM(doh_half_recv_half_send_GET_TLS_quota, setup_test,
2303 		      teardown_test)
2304 ISC_TEST_ENTRY_CUSTOM(doh_half_recv_half_send_POST_TLS_quota, setup_test,
2305 		      teardown_test)
2306 ISC_TEST_ENTRY_CUSTOM(doh_bad_connect_uri, setup_test, teardown_test)
2307 ISC_TEST_LIST_END
2308 
2309 ISC_TEST_MAIN
2310