summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLeon M. George <leon@georgemail.eu>2022-08-01 10:16:18 +0200
committerAzat Khuzhin <azat@libevent.org>2022-08-13 20:12:18 +0200
commit1bdc91350ee30d3aa51fe809fd719c2c3183b445 (patch)
tree7f0c51badd9293c101f206a874e1f437815011dc
parenta4cdc3c5e864c3ee4b836c78f92e07229be39c0f (diff)
downloadlibevent-1bdc91350ee30d3aa51fe809fd719c2c3183b445.tar.gz
http: allow setting bevcb per socket
Co-authored-by: Azat Khuzhin <azat@libevent.org> v2: remove handling of HTTP_BIND_IPV6
-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
4 files changed, 134 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