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.
This commit is contained in:
Andrew Sweeney 2014-01-05 20:35:46 -05:00
parent 4c8ebcd359
commit b083ca0551
4 changed files with 106 additions and 0 deletions

12
http.c
View File

@ -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
*/

View File

@ -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);

View File

@ -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

View File

@ -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),