]> granicus.if.org Git - libevent/commitdiff
low-level interfaces for streaming; from dug song
authorNiels Provos <provos@gmail.com>
Sat, 9 Dec 2006 02:58:12 +0000 (02:58 +0000)
committerNiels Provos <provos@gmail.com>
Sat, 9 Dec 2006 02:58:12 +0000 (02:58 +0000)
i applied some bug fixes and slight re-arranged the logic
on when to call the close notification callback;
i also don't like the streaming interface; i'd rather
see it do the chunked response formatting explicitly.

svn:r298

evhttp.h
http-internal.h
http.c

index 6fa3e9760a796a5a0bb03573f2b431ea119f7896..7b6e75019a097ce57938de7066e37f72ad7290cf 100644 (file)
--- a/evhttp.h
+++ b/evhttp.h
@@ -87,6 +87,11 @@ void evhttp_send_error(struct evhttp_request *, int, const char *);
 void evhttp_send_reply(struct evhttp_request *, int, const char *,
     struct evbuffer *);
 
+/* Low-level response interface, for streaming/chunked replies */
+void evhttp_send_reply_start(struct evhttp_request *, int, const char *);
+void evhttp_send_reply_data(struct evhttp_request *, struct evbuffer *);
+void evhttp_send_reply_done(struct evhttp_request *);
+       
 /* Interfaces for making requests */
 enum evhttp_cmd_type { EVHTTP_REQ_GET, EVHTTP_REQ_POST, EVHTTP_REQ_HEAD };
 
@@ -164,6 +169,14 @@ void evhttp_connection_set_timeout(struct evhttp_connection *evcon,
 void evhttp_connection_set_retries(struct evhttp_connection *evcon,
     int retry_max);
 
+/* Set a callback for connection close. */
+void evhttp_connection_set_closecb(struct evhttp_connection *evcon,
+    void (*)(struct evhttp_connection *, void *), void *);
+
+/* Get the remote address and port associated with this connection. */
+void evhttp_connection_get_peer(struct evhttp_connection *evcon,
+    char **address, u_short *port);
+
 /* The connection gets ownership of the request */
 int evhttp_make_request(struct evhttp_connection *evcon,
     struct evhttp_request *req,
index 69fc39ae3212b1fb7090cebbdc039504362b3345..66ba64fae4f96ad10df66ba04c0268ef5cb2a74c 100644 (file)
@@ -65,6 +65,9 @@ struct evhttp_connection {
        
        void (*cb)(struct evhttp_connection *, void *);
        void *cb_arg;
+       
+       void (*closecb)(struct evhttp_connection *, void *);
+       void *closecb_arg;
 };
 
 struct evhttp_cb {
diff --git a/http.c b/http.c
index 123b1c21c8e9cd7b34d8cd853602e24184f8e8b8..2b4d43072b4a4d236f24ed9172cb3bea3005a4e2 100644 (file)
--- a/http.c
+++ b/http.c
@@ -523,7 +523,8 @@ evhttp_write(int fd, short what, void *arg)
        }
 
        /* Activate our call back */
-       (*evcon->cb)(evcon, evcon->cb_arg);
+       if (evcon->cb != NULL)
+               (*evcon->cb)(evcon, evcon->cb_arg);
 }
 
 void
@@ -640,6 +641,12 @@ evhttp_connection_free(struct evhttp_connection *evcon)
 {
        struct evhttp_request *req;
 
+       /* notify interested parties that this connection is going down */
+       if (evcon->fd != -1) {
+               if (evcon->closecb != NULL)
+                       (*evcon->closecb)(evcon, evcon->closecb_arg);
+       }
+
        /* remove all requests that might be queued on this connection */
        while ((req = TAILQ_FIRST(&evcon->requests)) != NULL) {
                TAILQ_REMOVE(&evcon->requests, req, next);
@@ -698,6 +705,10 @@ evhttp_connection_reset(struct evhttp_connection *evcon)
                event_del(&evcon->ev);
 
        if (evcon->fd != -1) {
+               /* inform interested parties about connection close */
+               if (evcon->closecb != NULL)
+                       (*evcon->closecb)(evcon, evcon->closecb_arg);
+
                close(evcon->fd);
                evcon->fd = -1;
        }
@@ -717,7 +728,6 @@ evhttp_detect_close_cb(int fd, short what, void *arg)
 static void
 evhttp_connection_start_detectclose(struct evhttp_connection *evcon)
 {
-       assert((evcon->flags & EVHTTP_REQ_OWN_CONNECTION) == 0);
        evcon->flags |= EVHTTP_CON_CLOSEDETECT;
        
        event_del(&evcon->ev);
@@ -1248,6 +1258,27 @@ evhttp_connection_set_retries(struct evhttp_connection *evcon,
        evcon->retry_max = retry_max;
 }
 
+void
+evhttp_connection_set_closecb(struct evhttp_connection *evcon,
+    void (*cb)(struct evhttp_connection *, void *), void *cbarg)
+{
+       evcon->closecb = cb;
+       evcon->closecb_arg = cbarg;
+       /* 
+        * xxx: we cannot just call evhttp_connection_start_detectclose here
+        * that's valid only for client initiated connections that currently
+        * do not process any requests.
+        */
+}
+
+void
+evhttp_connection_get_peer(struct evhttp_connection *evcon,
+    char **address, u_short *port)
+{
+       *address = evcon->address;
+       *port = evcon->port;
+}
+
 int
 evhttp_connection_connect(struct evhttp_connection *evcon)
 {
@@ -1417,6 +1448,37 @@ evhttp_send_reply(struct evhttp_request *req, int code, const char *reason,
        evhttp_send(req, databuf);
 }
 
+void
+evhttp_send_reply_start(struct evhttp_request *req, int code,
+    const char *reason)
+{
+       evhttp_response_code(req, code, reason);
+       evhttp_make_header(req->evcon, req);
+       evhttp_write_buffer(req->evcon, NULL, NULL);
+}
+
+void
+evhttp_send_reply_data(struct evhttp_request *req, struct evbuffer *databuf)
+{
+       evbuffer_add_buffer(req->evcon->output_buffer, databuf);
+       evhttp_write_buffer(req->evcon, NULL, NULL);
+}
+
+void
+evhttp_send_reply_done(struct evhttp_request *req)
+{
+       struct evhttp_connection *evcon = req->evcon;
+
+       if (!event_pending(&evcon->ev, EV_WRITE|EV_TIMEOUT, NULL)) {
+               /* let the connection know that we are done with the request */
+               evhttp_send_done(evcon, NULL);
+       } else {
+               /* make the callback execute after all data has been written */
+               evcon->cb = evhttp_send_done;
+               evcon->cb_arg = NULL;
+       }
+}
+
 void
 evhttp_response_code(struct evhttp_request *req, int code, const char *reason)
 {