2
0
mirror of https://gitlab.isc.org/isc-projects/bind9 synced 2025-08-31 14:35:26 +00:00

Update the set of HTTP endpoints on reconfiguration

This commit ensures that on reconfiguration the set of HTTP
endpoints (=paths) is being updated within HTTP listeners.
This commit is contained in:
Artem Boldariev
2022-06-22 19:31:18 +03:00
parent e72962d5f1
commit d2e13ddf22
5 changed files with 202 additions and 18 deletions

View File

@@ -638,8 +638,7 @@ isc_nm_http_set_endpoints(isc_nmsocket_t *listener,
* during reconfiguration.
*
* Requires:
* \li 'listener' is a pointer to a valid network manager listener socket
object with TLS support;
* \li 'listener' is a pointer to a valid network manager HTTP listener socket;
* \li 'eps' is a valid pointer to an HTTP endpoints set.
*/

View File

@@ -179,6 +179,9 @@ typedef struct isc_http_send_req {
isc__nm_http_pending_callbacks_t pending_write_callbacks;
} isc_http_send_req_t;
#define HTTP_ENDPOINTS_MAGIC ISC_MAGIC('H', 'T', 'E', 'P')
#define VALID_HTTP_ENDPOINTS(t) ISC_MAGIC_VALID(t, HTTP_ENDPOINTS_MAGIC)
static bool
http_send_outgoing(isc_nm_http_session_t *session, isc_nmhandle_t *httphandle,
isc_nm_cb_t cb, void *cbarg);
@@ -225,6 +228,16 @@ static isc_nm_httphandler_t *
http_endpoints_find(const char *request_path,
const isc_nm_http_endpoints_t *restrict eps);
static void
http_init_listener_endpoints(isc_nmsocket_t *listener,
isc_nm_http_endpoints_t *epset);
static void
http_cleanup_listener_endpoints(isc_nmsocket_t *listener);
static isc_nm_http_endpoints_t *
http_get_listener_endpoints(isc_nmsocket_t *listener, const int tid);
static bool
http_session_active(isc_nm_http_session_t *session) {
REQUIRE(VALID_HTTP2_SESSION(session));
@@ -1655,14 +1668,15 @@ server_on_begin_headers_callback(nghttp2_session *ngsession,
static isc_nm_httphandler_t *
find_server_request_handler(const char *request_path,
const isc_nmsocket_t *serversocket) {
isc_nmsocket_t *serversocket, const int tid) {
isc_nm_httphandler_t *handler = NULL;
REQUIRE(VALID_NMSOCK(serversocket));
if (atomic_load(&serversocket->listening)) {
handler = http_endpoints_find(
request_path, serversocket->h2.listener_endpoints);
request_path,
http_get_listener_endpoints(serversocket, tid));
}
return (handler);
}
@@ -1692,7 +1706,8 @@ server_handle_path_header(isc_nmsocket_t *socket, const uint8_t *value,
}
handler = find_server_request_handler(socket->h2.request_path,
socket->h2.session->serversocket);
socket->h2.session->serversocket,
socket->tid);
if (handler != NULL) {
socket->h2.cb = handler->cb;
socket->h2.cbarg = handler->cbarg;
@@ -2487,7 +2502,7 @@ isc_nm_listenhttp(isc_nm_t *mgr, uint32_t workers, isc_sockaddr_t *iface,
isc_nmsocket_set_max_streams(sock, max_concurrent_streams);
atomic_store(&eps->in_use, true);
isc_nm_http_endpoints_attach(eps, &sock->h2.listener_endpoints);
http_init_listener_endpoints(sock, eps);
if (ctx != NULL) {
result = isc_nm_listentls(mgr, workers, iface,
@@ -2530,6 +2545,7 @@ isc_nm_http_endpoints_new(isc_mem_t *mctx) {
ISC_LIST_INIT(eps->handlers);
isc_refcount_init(&eps->references, 1);
atomic_init(&eps->in_use, false);
eps->magic = HTTP_ENDPOINTS_MAGIC;
return eps;
}
@@ -2543,9 +2559,10 @@ isc_nm_http_endpoints_detach(isc_nm_http_endpoints_t **restrict epsp) {
REQUIRE(epsp != NULL);
eps = *epsp;
REQUIRE(eps != NULL);
REQUIRE(VALID_HTTP_ENDPOINTS(eps));
if (isc_refcount_decrement(&eps->references) > 1) {
*epsp = NULL;
return;
}
@@ -2573,6 +2590,8 @@ isc_nm_http_endpoints_detach(isc_nm_http_endpoints_t **restrict epsp) {
httpcbarg = next;
}
eps->magic = 0;
isc_mem_putanddetach(&mctx, eps, sizeof(*eps));
*epsp = NULL;
}
@@ -2580,6 +2599,7 @@ isc_nm_http_endpoints_detach(isc_nm_http_endpoints_t **restrict epsp) {
void
isc_nm_http_endpoints_attach(isc_nm_http_endpoints_t *source,
isc_nm_http_endpoints_t **targetp) {
REQUIRE(VALID_HTTP_ENDPOINTS(source));
REQUIRE(targetp != NULL && *targetp == NULL);
isc_refcount_increment(&source->references);
@@ -2592,6 +2612,8 @@ http_endpoints_find(const char *request_path,
const isc_nm_http_endpoints_t *restrict eps) {
isc_nm_httphandler_t *handler = NULL;
REQUIRE(VALID_HTTP_ENDPOINTS(eps));
if (request_path == NULL || *request_path == '\0') {
return (NULL);
}
@@ -2637,7 +2659,7 @@ isc_nm_http_endpoints_add(isc_nm_http_endpoints_t *restrict eps,
isc_nm_httpcbarg_t *restrict httpcbarg = NULL;
bool newhandler = false;
REQUIRE(eps != NULL);
REQUIRE(VALID_HTTP_ENDPOINTS(eps));
REQUIRE(isc_nm_http_path_isvalid(uri));
REQUIRE(atomic_load(&eps->in_use) == false);
@@ -2966,6 +2988,90 @@ isc__nm_http_set_max_streams(isc_nmsocket_t *listener,
atomic_store(&listener->h2.max_concurrent_streams, max_streams);
}
void
isc_nm_http_set_endpoints(isc_nmsocket_t *listener,
isc_nm_http_endpoints_t *eps) {
REQUIRE(VALID_NMSOCK(listener));
REQUIRE(listener->type == isc_nm_httplistener);
REQUIRE(VALID_HTTP_ENDPOINTS(eps));
atomic_store(&eps->in_use, true);
for (size_t i = 0; i < isc_nm_getnworkers(listener->mgr); i++) {
isc__netievent__http_eps_t *ievent =
isc__nm_get_netievent_httpendpoints(listener->mgr,
listener, eps);
isc__nm_enqueue_ievent(&listener->mgr->workers[i],
(isc__netievent_t *)ievent);
}
}
void
isc__nm_async_httpendpoints(isc__networker_t *worker, isc__netievent_t *ev0) {
isc__netievent__http_eps_t *ievent = (isc__netievent__http_eps_t *)ev0;
const int tid = isc_nm_tid();
isc_nmsocket_t *listener = ievent->sock;
isc_nm_http_endpoints_t *eps = ievent->endpoints;
UNUSED(worker);
isc_nm_http_endpoints_detach(&listener->h2.listener_endpoints[tid]);
isc_nm_http_endpoints_attach(eps,
&listener->h2.listener_endpoints[tid]);
}
static void
http_init_listener_endpoints(isc_nmsocket_t *listener,
isc_nm_http_endpoints_t *epset) {
size_t nworkers;
REQUIRE(VALID_NMSOCK(listener));
REQUIRE(VALID_NM(listener->mgr));
REQUIRE(VALID_HTTP_ENDPOINTS(epset));
nworkers = (size_t)isc_nm_getnworkers(listener->mgr);
INSIST(nworkers > 0);
listener->h2.listener_endpoints =
isc_mem_get(listener->mgr->mctx,
sizeof(isc_nm_http_endpoints_t *) * nworkers);
listener->h2.n_listener_endpoints = nworkers;
for (size_t i = 0; i < nworkers; i++) {
listener->h2.listener_endpoints[i] = NULL;
isc_nm_http_endpoints_attach(
epset, &listener->h2.listener_endpoints[i]);
}
}
static void
http_cleanup_listener_endpoints(isc_nmsocket_t *listener) {
REQUIRE(VALID_NM(listener->mgr));
if (listener->h2.listener_endpoints == NULL) {
return;
}
for (size_t i = 0; i < listener->h2.n_listener_endpoints; i++) {
isc_nm_http_endpoints_detach(
&listener->h2.listener_endpoints[i]);
}
isc_mem_put(listener->mgr->mctx, listener->h2.listener_endpoints,
sizeof(isc_nm_http_endpoints_t *) *
listener->h2.n_listener_endpoints);
listener->h2.n_listener_endpoints = 0;
}
static isc_nm_http_endpoints_t *
http_get_listener_endpoints(isc_nmsocket_t *listener, const int tid) {
isc_nm_http_endpoints_t *eps;
REQUIRE(VALID_NMSOCK(listener));
REQUIRE(tid >= 0);
REQUIRE((size_t)tid < listener->h2.n_listener_endpoints);
eps = listener->h2.listener_endpoints[tid];
INSIST(eps != NULL);
return (eps);
}
static const bool base64url_validation_table[256] = {
false, false, false, false, false, false, false, false, false, false,
false, false, false, false, false, false, false, false, false, false,
@@ -3119,8 +3225,7 @@ isc__nm_http_cleanup_data(isc_nmsocket_t *sock) {
if (sock->type == isc_nm_httplistener &&
sock->h2.listener_endpoints != NULL) {
/* Delete all handlers */
isc_nm_http_endpoints_detach(
&sock->h2.listener_endpoints);
http_cleanup_listener_endpoints(sock);
}
if (sock->h2.request_path != NULL) {

View File

@@ -313,6 +313,7 @@ typedef enum isc__netievent_type {
netievent_httpclose,
netievent_httpsend,
netievent_httpendpoints,
netievent_shutdown,
netievent_stop,
@@ -695,6 +696,42 @@ typedef struct isc__netievent__tlsctx {
isc__nm_put_netievent(nm, ievent); \
}
#ifdef HAVE_LIBNGHTTP2
typedef struct isc__netievent__http_eps {
NETIEVENT__SOCKET;
isc_nm_http_endpoints_t *endpoints;
} isc__netievent__http_eps_t;
#define NETIEVENT_SOCKET_HTTP_EPS_TYPE(type) \
typedef isc__netievent__http_eps_t isc__netievent_##type##_t;
#define NETIEVENT_SOCKET_HTTP_EPS_DECL(type) \
isc__netievent_##type##_t *isc__nm_get_netievent_##type( \
isc_nm_t *nm, isc_nmsocket_t *sock, \
isc_nm_http_endpoints_t *endpoints); \
void isc__nm_put_netievent_##type(isc_nm_t *nm, \
isc__netievent_##type##_t *ievent);
#define NETIEVENT_SOCKET_HTTP_EPS_DEF(type) \
isc__netievent_##type##_t *isc__nm_get_netievent_##type( \
isc_nm_t *nm, isc_nmsocket_t *sock, \
isc_nm_http_endpoints_t *endpoints) { \
isc__netievent_##type##_t *ievent = \
isc__nm_get_netievent(nm, netievent_##type); \
isc__nmsocket_attach(sock, &ievent->sock); \
isc_nm_http_endpoints_attach(endpoints, &ievent->endpoints); \
\
return (ievent); \
} \
\
void isc__nm_put_netievent_##type(isc_nm_t *nm, \
isc__netievent_##type##_t *ievent) { \
isc_nm_http_endpoints_detach(&ievent->endpoints); \
isc__nmsocket_detach(&ievent->sock); \
isc__nm_put_netievent(nm, ievent); \
}
#endif /* HAVE_LIBNGHTTP2 */
typedef union {
isc__netievent_t ni;
isc__netievent__socket_t nis;
@@ -703,6 +740,9 @@ typedef union {
isc__netievent__socket_quota_t nisq;
isc__netievent_tlsconnect_t nitc;
isc__netievent__tlsctx_t nitls;
#ifdef HAVE_LIBNGHTTP2
isc__netievent__http_eps_t nihttpeps;
#endif /* HAVE_LIBNGHTTP2 */
} isc__netievent_storage_t;
/*
@@ -846,6 +886,7 @@ typedef struct isc_nm_httphandler {
} isc_nm_httphandler_t;
struct isc_nm_http_endpoints {
uint32_t magic;
isc_mem_t *mctx;
ISC_LIST(isc_nm_httphandler_t) handlers;
@@ -891,7 +932,8 @@ typedef struct isc_nmsocket_h2 {
void *cbarg;
LINK(struct isc_nmsocket_h2) link;
isc_nm_http_endpoints_t *listener_endpoints;
isc_nm_http_endpoints_t **listener_endpoints;
size_t n_listener_endpoints;
bool response_submitted;
struct {
@@ -1796,6 +1838,9 @@ isc__nm_async_httpstop(isc__networker_t *worker, isc__netievent_t *ev0);
void
isc__nm_async_httpclose(isc__networker_t *worker, isc__netievent_t *ev0);
void
isc__nm_async_httpendpoints(isc__networker_t *worker, isc__netievent_t *ev0);
bool
isc__nm_parse_httpquery(const char *query_string, const char **start,
size_t *len);
@@ -1971,9 +2016,12 @@ NETIEVENT_SOCKET_HANDLE_TYPE(tlsdnscancel);
NETIEVENT_SOCKET_QUOTA_TYPE(tlsdnsaccept);
NETIEVENT_SOCKET_TYPE(tlsdnscycle);
#ifdef HAVE_LIBNGHTTP2
NETIEVENT_SOCKET_TYPE(httpstop);
NETIEVENT_SOCKET_REQ_TYPE(httpsend);
NETIEVENT_SOCKET_TYPE(httpclose);
NETIEVENT_SOCKET_HTTP_EPS_TYPE(httpendpoints);
#endif /* HAVE_LIBNGHTTP2 */
NETIEVENT_SOCKET_REQ_TYPE(tcpconnect);
NETIEVENT_SOCKET_REQ_TYPE(tcpsend);
@@ -2041,9 +2089,12 @@ NETIEVENT_SOCKET_HANDLE_DECL(tlsdnscancel);
NETIEVENT_SOCKET_QUOTA_DECL(tlsdnsaccept);
NETIEVENT_SOCKET_DECL(tlsdnscycle);
#ifdef HAVE_LIBNGHTTP2
NETIEVENT_SOCKET_DECL(httpstop);
NETIEVENT_SOCKET_REQ_DECL(httpsend);
NETIEVENT_SOCKET_DECL(httpclose);
NETIEVENT_SOCKET_HTTP_EPS_DECL(httpendpoints);
#endif /* HAVE_LIBNGHTTP2 */
NETIEVENT_SOCKET_REQ_DECL(tcpconnect);
NETIEVENT_SOCKET_REQ_DECL(tcpsend);

View File

@@ -921,6 +921,7 @@ process_netievent(isc__networker_t *worker, isc__netievent_t *ievent) {
NETIEVENT_CASE(httpstop);
NETIEVENT_CASE(httpsend);
NETIEVENT_CASE(httpclose);
NETIEVENT_CASE(httpendpoints);
#endif
NETIEVENT_CASE(settlsctx);
@@ -1034,9 +1035,12 @@ NETIEVENT_SOCKET_QUOTA_DEF(tlsdnsaccept);
NETIEVENT_SOCKET_DEF(tlsdnscycle);
NETIEVENT_SOCKET_DEF(tlsdnsshutdown);
#ifdef HAVE_LIBNGHTTP2
NETIEVENT_SOCKET_DEF(httpstop);
NETIEVENT_SOCKET_REQ_DEF(httpsend);
NETIEVENT_SOCKET_DEF(httpclose);
NETIEVENT_SOCKET_HTTP_EPS_DEF(httpendpoints);
#endif /* HAVE_LIBNGHTTP2 */
NETIEVENT_SOCKET_REQ_DEF(tcpconnect);
NETIEVENT_SOCKET_REQ_DEF(tcpsend);

View File

@@ -570,6 +570,24 @@ ns_interface_listentls(ns_interface_t *ifp, isc_tlsctx_t *sslctx) {
return (result);
}
#ifdef HAVE_LIBNGHTTP2
static isc_result_t
load_http_endpoints(isc_nm_http_endpoints_t *epset, ns_interface_t *ifp,
char **eps, size_t neps) {
isc_result_t result = ISC_R_FAILURE;
for (size_t i = 0; i < neps; i++) {
result = isc_nm_http_endpoints_add(epset, eps[i],
ns__client_request, ifp);
if (result != ISC_R_SUCCESS) {
break;
}
}
return (result);
}
#endif /* HAVE_LIBNGHTTP2 */
static isc_result_t
ns_interface_listenhttp(ns_interface_t *ifp, isc_tlsctx_t *sslctx, char **eps,
size_t neps, uint32_t max_clients,
@@ -582,13 +600,7 @@ ns_interface_listenhttp(ns_interface_t *ifp, isc_tlsctx_t *sslctx, char **eps,
epset = isc_nm_http_endpoints_new(ifp->mgr->mctx);
for (size_t i = 0; i < neps; i++) {
result = isc_nm_http_endpoints_add(epset, eps[i],
ns__client_request, ifp);
if (result != ISC_R_SUCCESS) {
break;
}
}
result = load_http_endpoints(epset, ifp, eps, neps);
if (result == ISC_R_SUCCESS) {
quota = isc_mem_get(ifp->mgr->mctx, sizeof(*quota));
@@ -946,7 +958,9 @@ replace_listener_tlsctx(ns_interface_t *ifp, isc_tlsctx_t *newctx) {
#ifdef HAVE_LIBNGHTTP2
static void
update_http_settings(ns_interface_t *ifp, ns_listenelt_t *le) {
isc_result_t result;
isc_nmsocket_t *listener;
isc_nm_http_endpoints_t *epset;
REQUIRE(le->is_http);
@@ -961,6 +975,17 @@ update_http_settings(ns_interface_t *ifp, ns_listenelt_t *le) {
}
isc_nmsocket_set_max_streams(listener, le->max_concurrent_streams);
epset = isc_nm_http_endpoints_new(ifp->mgr->mctx);
result = load_http_endpoints(epset, ifp, le->http_endpoints,
le->http_endpoints_number);
if (result == ISC_R_SUCCESS) {
isc_nm_http_set_endpoints(listener, epset);
}
isc_nm_http_endpoints_detach(&epset);
}
#endif /* HAVE_LIBNGHTTP2 */