]> granicus.if.org Git - libevent/commitdiff
Provide on request complete callback facility
authorAndrew Sweeney <asweeney86@gmail.com>
Mon, 6 Jan 2014 01:35:46 +0000 (20:35 -0500)
committerAndrew Sweeney <asweeney86@gmail.com>
Mon, 6 Jan 2014 01:35:46 +0000 (20:35 -0500)
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
include/event2/http.h
include/event2/http_struct.h
test/regress_http.c

diff --git a/http.c b/http.c
index 826deffe2d9a374a712c3456dc913ec886ccd341..b0d659b58a474595dfbdb0e0b609c1958d07b5c0 100644 (file)
--- 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
  */
index 068120c76444c542dbc46a4e4d989b0d18a792e2..ff19b4493495d437b4b93e7bb0565a3e8a985b2f 100644 (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);
 
index 4ca196ee8bfdfa3bf53827f3bbb29cc0cad41cab..4bf5b1ff60f52b6b3d8e1483baf442cc82885cdd 100644 (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
index faebabc459c40f49c456b7d5e4ed91c36593d086..f8e146359269cc32401cbd56f914174d5d4ebeec 100644 (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),