summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAzat Khuzhin <azat@libevent.org>2022-08-14 00:46:48 +0200
committerGitHub <noreply@github.com>2022-08-14 00:46:48 +0200
commit77a9b60e479fd09ce9cece0ebec1863ba3e69273 (patch)
treed986c0ddd9723b91951ae3ba838e49b64f7351de
parentc198b0ceb349d8b1154d4b2f7b2ee373d6fd21c4 (diff)
parent1bdc91350ee30d3aa51fe809fd719c2c3183b445 (diff)
downloadlibevent-77a9b60e479fd09ce9cece0ebec1863ba3e69273.tar.gz
Merge pull request #1315 from yogo1212/http_per_socket_bebcb
In it's current form, libevent requires multiple struct evhttp objects to be created in order to enable listening on sockets with more than one type of encryption. This change allows specifying per-socket how the associated bufferevents should be created. Thus, it becomes possible to have multiple listening sockets with different encryption parameters using only one evttp.
-rw-r--r--http-internal.h4
-rw-r--r--http.c37
-rw-r--r--include/event2/http.h10
-rw-r--r--test/regress_http.c93
-rw-r--r--test/regress_openssl.c5
5 files changed, 139 insertions, 10 deletions
diff --git a/http-internal.h b/http-internal.h
index a5844e1d..705daba2 100644
--- a/http-internal.h
+++ b/http-internal.h
@@ -128,6 +128,10 @@ TAILQ_HEAD(evconq, evhttp_connection);
struct evhttp_bound_socket {
TAILQ_ENTRY(evhttp_bound_socket) next;
+ struct evhttp *http;
+ struct bufferevent* (*bevcb)(struct event_base *, void *);
+ void *bevcbarg;
+
struct evconnlistener *listener;
};
diff --git a/http.c b/http.c
index d578735d..9072fcec 100644
--- a/http.c
+++ b/http.c
@@ -197,7 +197,7 @@ static void evhttp_read_header(struct evhttp_connection *evcon,
static int evhttp_add_header_internal(struct evkeyvalq *headers,
const char *key, const char *value);
static const char *evhttp_response_phrase_internal(int code);
-static void evhttp_get_request(struct evhttp *, evutil_socket_t, struct sockaddr *, ev_socklen_t);
+static void evhttp_get_request(struct evhttp *, evutil_socket_t, struct sockaddr *, ev_socklen_t, struct bufferevent *bev);
static void evhttp_write_buffer(struct evhttp_connection *,
void (*)(struct evhttp_connection *, void *), void *);
static void evhttp_make_header(struct evhttp_connection *, struct evhttp_request *);
@@ -3795,9 +3795,15 @@ evhttp_handle_request(struct evhttp_request *req, void *arg)
static void
accept_socket_cb(struct evconnlistener *listener, evutil_socket_t nfd, struct sockaddr *peer_sa, int peer_socklen, void *arg)
{
- struct evhttp *http = arg;
+ struct evhttp_bound_socket *bound = arg;
+
+ struct evhttp *http = bound->http;
- evhttp_get_request(http, nfd, peer_sa, peer_socklen);
+ struct bufferevent *bev = NULL;
+ if (bound->bevcb)
+ bev = bound->bevcb(http->base, bound->bevcbarg);
+
+ evhttp_get_request(http, nfd, peer_sa, peer_socklen, bev);
}
int
@@ -3893,9 +3899,11 @@ evhttp_bind_listener(struct evhttp *http, struct evconnlistener *listener)
return (NULL);
bound->listener = listener;
+ bound->bevcb = NULL;
+ bound->http = http;
TAILQ_INSERT_TAIL(&http->sockets, bound, next);
- evconnlistener_set_cb(listener, accept_socket_cb, http);
+ evconnlistener_set_cb(listener, accept_socket_cb, bound);
return bound;
}
@@ -3912,6 +3920,14 @@ evhttp_bound_socket_get_listener(struct evhttp_bound_socket *bound)
}
void
+evhttp_bound_set_bevcb(struct evhttp_bound_socket *bound,
+ struct bufferevent* (*cb)(struct event_base *, void *), void *cbarg)
+{
+ bound->bevcb = cb;
+ bound->bevcbarg = cbarg;
+}
+
+void
evhttp_del_accept_socket(struct evhttp *http, struct evhttp_bound_socket *bound)
{
TAILQ_REMOVE(&http->sockets, bound, next);
@@ -4517,10 +4533,10 @@ struct evbuffer *evhttp_request_get_output_buffer(struct evhttp_request *req)
static struct evhttp_connection*
evhttp_get_request_connection(
struct evhttp* http,
- evutil_socket_t fd, struct sockaddr *sa, ev_socklen_t salen)
+ evutil_socket_t fd, struct sockaddr *sa, ev_socklen_t salen,
+ struct bufferevent* bev)
{
struct evhttp_connection *evcon;
- struct bufferevent* bev = NULL;
#ifdef EVENT__HAVE_STRUCT_SOCKADDR_UN
if (sa->sa_family == AF_UNIX) {
@@ -4537,7 +4553,7 @@ evhttp_get_request_connection(
EV_SOCK_FMT"\n", __func__, EV_SOCK_ARG(fd)));
/* we need a connection object to put the http request on */
- if (http->bevcb != NULL) {
+ if (!bev && http->bevcb != NULL) {
bev = (*http->bevcb)(http->base, http->bevcbarg);
}
@@ -4560,7 +4576,7 @@ evhttp_get_request_connection(
__func__, hostname, portname, EV_SOCK_ARG(fd)));
/* we need a connection object to put the http request on */
- if (http->bevcb != NULL) {
+ if (!bev && http->bevcb != NULL) {
bev = (*http->bevcb)(http->base, http->bevcbarg);
}
evcon = evhttp_connection_base_bufferevent_new(
@@ -4636,11 +4652,12 @@ evhttp_associate_new_request_with_connection(struct evhttp_connection *evcon)
static void
evhttp_get_request(struct evhttp *http, evutil_socket_t fd,
- struct sockaddr *sa, ev_socklen_t salen)
+ struct sockaddr *sa, ev_socklen_t salen,
+ struct bufferevent *bev)
{
struct evhttp_connection *evcon;
- evcon = evhttp_get_request_connection(http, fd, sa, salen);
+ evcon = evhttp_get_request_connection(http, fd, sa, salen, bev);
if (evcon == NULL) {
event_sock_warn(fd, "%s: cannot get connection on "EV_SOCK_FMT,
__func__, EV_SOCK_ARG(fd));
diff --git a/include/event2/http.h b/include/event2/http.h
index 27cbd35e..50c0a27b 100644
--- a/include/event2/http.h
+++ b/include/event2/http.h
@@ -172,6 +172,14 @@ struct evhttp_bound_socket *evhttp_bind_listener(struct evhttp *http, struct evc
EVENT2_EXPORT_SYMBOL
struct evconnlistener *evhttp_bound_socket_get_listener(struct evhttp_bound_socket *bound);
+/*
+ * Like evhttp_set_bevcb.
+ * If cb returns a non-NULL bufferevent, * the callback supplied through
+ * evhttp_set_bevcb isn't used.
+ */
+EVENT2_EXPORT_SYMBOL
+void evhttp_bound_set_bevcb(struct evhttp_bound_socket *bound, struct bufferevent* (*cb)(struct event_base *, void *), void *cbarg);
+
typedef void evhttp_bound_socket_foreach_fn(struct evhttp_bound_socket *, void *);
/**
* Applies the function specified in the first argument to all
@@ -333,6 +341,8 @@ void evhttp_set_gencb(struct evhttp *http,
/**
Set a callback used to create new bufferevents for connections
to a given evhttp object.
+ cb is not called if a non-NULL bufferevent was supplied by
+ evhttp_bound_set_bevcb.
You can use this to override the default bufferevent type -- for example,
to make this evhttp object use SSL bufferevents rather than unencrypted
diff --git a/test/regress_http.c b/test/regress_http.c
index d950e644..3f6b71b1 100644
--- a/test/regress_http.c
+++ b/test/regress_http.c
@@ -4309,6 +4309,93 @@ static void http_simple_test(void *arg)
static void http_simple_nonconformant_test(void *arg)
{ http_simple_test_impl(arg, 0, 0, "/test nonconformant"); }
+static int
+https_bind_ssl_bevcb(struct evhttp *http, ev_uint16_t port, ev_uint16_t *pport, int mask)
+{
+ int _port;
+ struct evhttp_bound_socket *sock = NULL;
+ sock = evhttp_bind_socket_with_handle(http, "127.0.0.1", port);
+
+#ifdef EVENT__HAVE_OPENSSL
+ if (mask & HTTP_OPENSSL) {
+ init_ssl();
+ evhttp_bound_set_bevcb(sock, https_bev, NULL);
+ }
+#endif
+#ifdef EVENT__HAVE_MBEDTLS
+ if (mask & HTTP_MBEDTLS) {
+ evhttp_bound_set_bevcb(sock, https_mbedtls_bev, NULL);
+ }
+#endif
+
+ _port = regress_get_socket_port(evhttp_bound_socket_get_fd(sock));
+ if (_port < 0)
+ return -1;
+
+ if (pport)
+ *pport = (ev_uint16_t)_port;
+
+ return 0;
+}
+static void
+https_per_socket_bevcb_impl(void *arg, ev_uint16_t http_port, ev_uint16_t https_port, int mask)
+{
+ struct bufferevent *bev;
+ struct basic_test_data *data = arg;
+ struct evhttp_connection *evcon = NULL;
+ struct evhttp *http = NULL;
+ ev_uint16_t new_https_port = 0;
+ struct evhttp_request *req = NULL;
+
+ http = evhttp_new(data->base);
+ tt_assert(http);
+
+ evhttp_bind_socket_with_handle(http, "127.0.0.1", http_port);
+
+ tt_assert(https_bind_ssl_bevcb(http, https_port, &new_https_port, mask) == 0);
+
+ evhttp_set_gencb(http, http_basic_cb, http);
+
+ bev = create_bev(data->base, -1, mask, 0);
+
+#ifdef EVENT__HAVE_OPENSSL
+ bufferevent_openssl_set_allow_dirty_shutdown(bev, 1);
+#endif
+#ifdef EVENT__HAVE_MBEDTLS
+ bufferevent_mbedtls_set_allow_dirty_shutdown(bev, 1);
+#endif
+
+ evcon = evhttp_connection_base_bufferevent_new(data->base, NULL, bev, "127.0.0.1", new_https_port);
+ tt_assert(evcon);
+
+ evhttp_connection_set_timeout(evcon, 1);
+ /* make sure to use the same address that is used by http */
+ evhttp_connection_set_local_address(evcon, "127.0.0.1");
+
+ req = evhttp_request_new(http_request_done, (void *) BASIC_REQUEST_BODY);
+ tt_assert(req);
+
+ evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
+
+ if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test") == -1) {
+ evhttp_request_free(req);
+ TT_GRIPE(("make_request_failed"));
+ goto end;
+ }
+
+ exit_base = data->base;
+ event_base_dispatch(data->base);
+
+end:
+ if (evcon)
+ evhttp_connection_free(evcon);
+
+ if (http)
+ evhttp_free(http);
+}
+static void https_per_socket_bevcb(void *arg, int ssl)
+{ https_per_socket_bevcb_impl(arg, 0, 0, ssl); }
+
static void
http_connection_retry_test_basic(void *arg, const char *addr, struct evdns_base *dns_base, int ssl)
{
@@ -5758,6 +5845,8 @@ static void https_connection_test(void *arg)
{ http_connection_test_(arg, 0, "127.0.0.1", NULL, 0, AF_UNSPEC, HTTP_OPENSSL); }
static void https_persist_connection_test(void *arg)
{ http_connection_test_(arg, 1, "127.0.0.1", NULL, 0, AF_UNSPEC, HTTP_OPENSSL); }
+static void https_per_socket_bevcb_test(void *arg)
+{ https_per_socket_bevcb_impl(arg, 0, 0, HTTP_OPENSSL); }
#endif
#ifdef EVENT__HAVE_MBEDTLS
@@ -5791,6 +5880,8 @@ static void https_mbedtls_connection_test(void *arg)
{ http_connection_test_(arg, 0, "127.0.0.1", NULL, 0, AF_UNSPEC, HTTP_MBEDTLS); }
static void https_mbedtls_persist_connection_test(void *arg)
{ http_connection_test_(arg, 1, "127.0.0.1", NULL, 0, AF_UNSPEC, HTTP_MBEDTLS); }
+static void https_mbedtls_per_socket_bevcb_test(void *arg)
+{ https_per_socket_bevcb_impl(arg, 0, 0, HTTP_MBEDTLS); }
#endif
struct testcase_t http_testcases[] = {
@@ -5910,6 +6001,7 @@ struct testcase_t http_testcases[] = {
HTTPS(write_during_read),
HTTPS(connection),
HTTPS(persist_connection),
+ HTTPS(per_socket_bevcb),
#endif
#ifdef EVENT__HAVE_MBEDTLS
@@ -5929,6 +6021,7 @@ struct testcase_t http_testcases[] = {
HTTPS_MBEDTLS(write_during_read),
HTTPS_MBEDTLS(connection),
HTTPS_MBEDTLS(persist_connection),
+ HTTPS_MBEDTLS(per_socket_bevcb),
#endif
END_OF_TESTCASES
diff --git a/test/regress_openssl.c b/test/regress_openssl.c
index 3ea767c6..89cc0140 100644
--- a/test/regress_openssl.c
+++ b/test/regress_openssl.c
@@ -150,6 +150,11 @@ get_ssl_ctx(void)
void
init_ssl(void)
{
+ static int initialized;
+ if (initialized)
+ return;
+ initialized = 1;
+
#if (OPENSSL_VERSION_NUMBER < 0x10100000L) || \
(defined(LIBRESSL_VERSION_NUMBER) && \
LIBRESSL_VERSION_NUMBER < 0x20700000L)