Skip to content

Commit

Permalink
http: allow setting bevcb per socket
Browse files Browse the repository at this point in the history
Co-authored-by: Azat Khuzhin <[email protected]>
v2: remove handling of HTTP_BIND_IPV6
  • Loading branch information
yogo1212 and azat committed Aug 13, 2022
1 parent a4cdc3c commit 1bdc913
Show file tree
Hide file tree
Showing 4 changed files with 134 additions and 10 deletions.
4 changes: 4 additions & 0 deletions http-internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
};

Expand Down
37 changes: 27 additions & 10 deletions http.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 *);
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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;
}

Expand All @@ -3911,6 +3919,14 @@ evhttp_bound_socket_get_listener(struct evhttp_bound_socket *bound)
return bound->listener;
}

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)
{
Expand Down Expand Up @@ -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) {
Expand All @@ -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);
}

Expand All @@ -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(
Expand Down Expand Up @@ -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));
Expand Down
10 changes: 10 additions & 0 deletions include/event2/http.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
93 changes: 93 additions & 0 deletions test/regress_http.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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[] = {
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand Down

0 comments on commit 1bdc913

Please sign in to comment.