From b083ca0551ec8ca63245e2e78dfefd11072443fc Mon Sep 17 00:00:00 2001 From: Andrew Sweeney Date: Sun, 5 Jan 2014 20:35:46 -0500 Subject: [PATCH] Provide on request complete callback facility This patch provides the ability to receive a callback on the completion of a request. The callback takes place immediately before the request's resources are released. --- http.c | 12 ++++++ include/event2/http.h | 10 +++++ include/event2/http_struct.h | 7 ++++ test/regress_http.c | 77 ++++++++++++++++++++++++++++++++++++ 4 files changed, 106 insertions(+) diff --git a/http.c b/http.c index 826deffe..b0d659b5 100644 --- a/http.c +++ b/http.c @@ -2552,6 +2552,10 @@ evhttp_send_done(struct evhttp_connection *evcon, void *arg) struct evhttp_request *req = TAILQ_FIRST(&evcon->requests); TAILQ_REMOVE(&evcon->requests, req, next); + if (req->on_complete_cb != NULL) { + req->on_complete_cb(req, req->on_complete_cb_arg); + } + need_close = (REQ_VERSION_BEFORE(req, 1, 1) && !evhttp_is_connection_keepalive(req->input_headers))|| @@ -3840,6 +3844,14 @@ evhttp_request_set_error_cb(struct evhttp_request *req, req->error_cb = cb; } +void +evhttp_request_set_on_complete_cb(struct evhttp_request *req, + void (*cb)(struct evhttp_request *, void *), void *arg) +{ + req->on_complete_cb = cb; + req->on_complete_cb_arg = arg; +} + /* * Allows for inspection of the request URI */ diff --git a/include/event2/http.h b/include/event2/http.h index 068120c7..ff19b449 100644 --- a/include/event2/http.h +++ b/include/event2/http.h @@ -554,6 +554,16 @@ enum evhttp_request_error { void evhttp_request_set_error_cb(struct evhttp_request *, void (*)(enum evhttp_request_error, void *)); +/** + * Set a on request complete callback. + * + * Receive a callback on request completion. This callback is triggered once + * the request is complete and all resources associated with the request will + * be released. + */ +void evhttp_request_set_on_complete_cb(struct evhttp_request *, + void (*)(struct evhttp_request *, void *), void *); + /** Frees the request object and removes associated events. */ void evhttp_request_free(struct evhttp_request *req); diff --git a/include/event2/http_struct.h b/include/event2/http_struct.h index 4ca196ee..4bf5b1ff 100644 --- a/include/event2/http_struct.h +++ b/include/event2/http_struct.h @@ -135,6 +135,13 @@ struct { * @see evhttp_request_set_error_cb() */ void (*error_cb)(enum evhttp_request_error, void *); + + /* + * Send complete callback - called when the request is actually + * sent and completed. + */ + void (*on_complete_cb)(struct evhttp_request *, void *); + void *on_complete_cb_arg; }; #ifdef __cplusplus diff --git a/test/regress_http.c b/test/regress_http.c index faebabc4..f8e14635 100644 --- a/test/regress_http.c +++ b/test/regress_http.c @@ -92,6 +92,7 @@ static void http_delay_cb(struct evhttp_request *req, void *arg); static void http_large_delay_cb(struct evhttp_request *req, void *arg); static void http_badreq_cb(struct evhttp_request *req, void *arg); static void http_dispatcher_cb(struct evhttp_request *req, void *arg); +static void http_on_complete_cb(struct evhttp_request *req, void *arg); static int http_bind(struct evhttp *myhttp, ev_uint16_t *pport, int ipv6) @@ -136,6 +137,7 @@ http_setup(ev_uint16_t *pport, struct event_base *base, int ipv6) evhttp_set_cb(myhttp, "/delay", http_delay_cb, base); evhttp_set_cb(myhttp, "/largedelay", http_large_delay_cb, base); evhttp_set_cb(myhttp, "/badrequest", http_badreq_cb, base); + evhttp_set_cb(myhttp, "/oncomplete", http_on_complete_cb, base); evhttp_set_cb(myhttp, "/", http_dispatcher_cb, base); return (myhttp); } @@ -481,6 +483,7 @@ http_basic_test(void *arg) ; } + static void http_delay_reply(evutil_socket_t fd, short what, void *arg) { @@ -735,6 +738,79 @@ http_delete_test(void *arg) ; } +static void +http_sent_cb(struct evhttp_request *req, void *arg) +{ + unsigned int val = (unsigned int)arg; + + if (val != 0xDEADBEEF) { + fprintf(stdout, "FAILED on_complete_cb argument\n"); + exit(1); + } + + event_debug(("%s: called\n", __func__)); + + ++test_ok; +} + +static void +http_on_complete_cb(struct evhttp_request *req, void *arg) +{ + struct evbuffer *evb = evbuffer_new(); + + evhttp_request_set_on_complete_cb(req, http_sent_cb, (void *)0xDEADBEEF); + + event_debug(("%s: called\n", __func__)); + evbuffer_add_printf(evb, BASIC_REQUEST_BODY); + + /* allow sending of an empty reply */ + evhttp_send_reply(req, HTTP_OK, "Everything is fine", evb); + + evbuffer_free(evb); + + ++test_ok; +} + +static void +http_on_complete_test(void *arg) +{ + struct basic_test_data *data = arg; + struct bufferevent *bev; + evutil_socket_t fd; + const char *http_request; + ev_uint16_t port = 0; + + test_ok = 0; + + http = http_setup(&port, data->base, 0); + + fd = http_connect("127.0.0.1", port); + + /* Stupid thing to send a request */ + bev = bufferevent_socket_new(data->base, fd, 0); + bufferevent_setcb(bev, http_readcb, http_writecb, + http_errorcb, data->base); + + http_request = + "DELETE /oncomplete HTTP/1.1\r\n" + "Host: somehost\r\n" + "Connection: close\r\n" + "\r\n"; + + bufferevent_write(bev, http_request, strlen(http_request)); + + event_base_dispatch(data->base); + + bufferevent_free(bev); + evutil_closesocket(fd); + + evhttp_free(http); + + tt_int_op(test_ok, ==, 4); + end: + ; +} + static void http_allowed_methods_eventcb(struct bufferevent *bev, short what, void *arg) { @@ -3759,6 +3835,7 @@ struct testcase_t http_testcases[] = { HTTP(incomplete), HTTP(incomplete_timeout), HTTP(terminate_chunked), + HTTP(on_complete), HTTP(highport), HTTP(dispatcher), -- 2.40.0