From de7db33a61f13f94fe3b60a084d20735b06bd72f Mon Sep 17 00:00:00 2001 From: Niels Provos Date: Sat, 9 Dec 2006 02:58:12 +0000 Subject: [PATCH] low-level interfaces for streaming; from dug song 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 | 13 ++++++++++ http-internal.h | 3 +++ http.c | 66 +++++++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 80 insertions(+), 2 deletions(-) diff --git a/evhttp.h b/evhttp.h index 6fa3e976..7b6e7501 100644 --- 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, diff --git a/http-internal.h b/http-internal.h index 69fc39ae..66ba64fa 100644 --- a/http-internal.h +++ b/http-internal.h @@ -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 123b1c21..2b4d4307 100644 --- 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) { -- 2.40.0