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
This commit is contained in:
Niels Provos 2006-12-09 02:58:12 +00:00
parent 852d05a3c0
commit de7db33a61
3 changed files with 80 additions and 2 deletions

View File

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

View 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 {

66
http.c
View File

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