mirror of
https://github.com/libevent/libevent.git
synced 2025-01-09 00:56:20 +08:00
pausing an rpc via a hook needs to deal with the fact that http callbacks free the request after they return; provide a way for a callback to take ownership of the request structure; the user then needs to explicitly free it.
svn:r620
This commit is contained in:
parent
6d291da240
commit
955c6abf53
@ -31,6 +31,7 @@ Changes in current version:
|
|||||||
o event_rpcgen now allows creating integer arrays
|
o event_rpcgen now allows creating integer arrays
|
||||||
o support string arrays in event_rpcgen
|
o support string arrays in event_rpcgen
|
||||||
o change evrpc hooking to allow pausing of RPCs; this will make it possible for the hook to do some meaning ful work; this is not backwards compatible.
|
o change evrpc hooking to allow pausing of RPCs; this will make it possible for the hook to do some meaning ful work; this is not backwards compatible.
|
||||||
|
o allow an http request callback to take ownership of a request structure
|
||||||
|
|
||||||
Changes in 1.4.0:
|
Changes in 1.4.0:
|
||||||
o allow \r or \n individually to separate HTTP headers instead of the standard "\r\n"; from Charles Kerr.
|
o allow \r or \n individually to separate HTTP headers instead of the standard "\r\n"; from Charles Kerr.
|
||||||
|
11
evhttp.h
11
evhttp.h
@ -182,6 +182,7 @@ struct {
|
|||||||
int flags;
|
int flags;
|
||||||
#define EVHTTP_REQ_OWN_CONNECTION 0x0001
|
#define EVHTTP_REQ_OWN_CONNECTION 0x0001
|
||||||
#define EVHTTP_PROXY_REQUEST 0x0002
|
#define EVHTTP_PROXY_REQUEST 0x0002
|
||||||
|
#define EVHTTP_USER_OWNED 0x0004
|
||||||
|
|
||||||
struct evkeyvalq *input_headers;
|
struct evkeyvalq *input_headers;
|
||||||
struct evkeyvalq *output_headers;
|
struct evkeyvalq *output_headers;
|
||||||
@ -235,6 +236,16 @@ void evhttp_request_set_chunked_cb(struct evhttp_request *,
|
|||||||
/** Frees the request object and removes associated events. */
|
/** Frees the request object and removes associated events. */
|
||||||
void evhttp_request_free(struct evhttp_request *req);
|
void evhttp_request_free(struct evhttp_request *req);
|
||||||
|
|
||||||
|
/** Takes ownership of the request object
|
||||||
|
*
|
||||||
|
* Can be used in a request callback to keep onto the request until
|
||||||
|
* evhttp_request_free() is explicitly called by the user.
|
||||||
|
*/
|
||||||
|
void evhttp_request_own(struct evhttp_request *req);
|
||||||
|
|
||||||
|
/** Returns 1 if the request is owned by the user */
|
||||||
|
int evhttp_request_is_owned(struct evhttp_request *req);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A connection object that can be used to for making HTTP requests. The
|
* A connection object that can be used to for making HTTP requests. The
|
||||||
* connection object tries to establish the connection when it is given an
|
* connection object tries to establish the connection when it is given an
|
||||||
|
23
evrpc.c
23
evrpc.c
@ -175,11 +175,12 @@ evrpc_process_hooks(struct evrpc_hook_list *head, void *ctx,
|
|||||||
{
|
{
|
||||||
struct evrpc_hook *hook;
|
struct evrpc_hook *hook;
|
||||||
TAILQ_FOREACH(hook, head, next) {
|
TAILQ_FOREACH(hook, head, next) {
|
||||||
if (hook->process(ctx, req, evbuf, hook->process_arg) == -1)
|
int res = hook->process(ctx, req, evbuf, hook->process_arg);
|
||||||
return (-1);
|
if (res != EVRPC_CONTINUE)
|
||||||
|
return (res);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (0);
|
return (EVRPC_CONTINUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void evrpc_pool_schedule(struct evrpc_pool *pool);
|
static void evrpc_pool_schedule(struct evrpc_pool *pool);
|
||||||
@ -761,7 +762,6 @@ evrpc_reply_done(struct evhttp_request *req, void *arg)
|
|||||||
/* cancel any timeout we might have scheduled */
|
/* cancel any timeout we might have scheduled */
|
||||||
event_del(&ctx->ev_timeout);
|
event_del(&ctx->ev_timeout);
|
||||||
|
|
||||||
/* if we get paused we also need to know the request */
|
|
||||||
ctx->req = req;
|
ctx->req = req;
|
||||||
|
|
||||||
/* we need to get the reply now */
|
/* we need to get the reply now */
|
||||||
@ -780,12 +780,22 @@ evrpc_reply_done(struct evhttp_request *req, void *arg)
|
|||||||
evrpc_reply_done_closure(ctx, hook_res);
|
evrpc_reply_done_closure(ctx, hook_res);
|
||||||
return;
|
return;
|
||||||
case EVRPC_PAUSE:
|
case EVRPC_PAUSE:
|
||||||
|
/*
|
||||||
|
* if we get paused we also need to know the request.
|
||||||
|
* unfortunately, the underlying layer is going to free it.
|
||||||
|
* we need to request ownership explicitly
|
||||||
|
*/
|
||||||
|
if (req != NULL)
|
||||||
|
evhttp_request_own(req);
|
||||||
|
|
||||||
evrpc_pause_request(pool, ctx, evrpc_reply_done_closure);
|
evrpc_pause_request(pool, ctx, evrpc_reply_done_closure);
|
||||||
return;
|
return;
|
||||||
default:
|
default:
|
||||||
assert(hook_res == EVRPC_TERMINATE ||
|
assert(hook_res == EVRPC_TERMINATE ||
|
||||||
hook_res == EVRPC_CONTINUE || hook_res == EVRPC_PAUSE);
|
hook_res == EVRPC_CONTINUE || hook_res == EVRPC_PAUSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* http request is being freed by underlying layer */
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -820,7 +830,10 @@ evrpc_reply_done_closure(void *arg, enum EVRPC_HOOK_RESULT hook_res)
|
|||||||
|
|
||||||
evrpc_request_wrapper_free(ctx);
|
evrpc_request_wrapper_free(ctx);
|
||||||
|
|
||||||
/* the http layer owns the request structure */
|
/* the http layer owned the orignal request structure, but if we
|
||||||
|
* got paused, we asked for ownership and need to free it here. */
|
||||||
|
if (req != NULL && evhttp_request_is_owned(req))
|
||||||
|
evhttp_request_free(req);
|
||||||
|
|
||||||
/* see if we can schedule another request */
|
/* see if we can schedule another request */
|
||||||
evrpc_pool_schedule(pool);
|
evrpc_pool_schedule(pool);
|
||||||
|
18
http.c
18
http.c
@ -674,8 +674,10 @@ evhttp_connection_done(struct evhttp_connection *evcon)
|
|||||||
/* notify the user of the request */
|
/* notify the user of the request */
|
||||||
(*req->cb)(req, req->cb_arg);
|
(*req->cb)(req, req->cb_arg);
|
||||||
|
|
||||||
/* if this was an outgoing request, we own and it's done. so free it */
|
/* if this was an outgoing request, we own and it's done. so free it.
|
||||||
if (con_outgoing) {
|
* unless the callback specifically requested to own the request.
|
||||||
|
*/
|
||||||
|
if (con_outgoing && ((req->flags & EVHTTP_USER_OWNED) == 0)) {
|
||||||
evhttp_request_free(req);
|
evhttp_request_free(req);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2210,6 +2212,18 @@ evhttp_request_free(struct evhttp_request *req)
|
|||||||
event_free(req);
|
event_free(req);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
evhttp_request_own(struct evhttp_request *req)
|
||||||
|
{
|
||||||
|
req->flags |= EVHTTP_USER_OWNED;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
evhttp_request_is_owned(struct evhttp_request *req)
|
||||||
|
{
|
||||||
|
return (req->flags & EVHTTP_USER_OWNED) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
evhttp_request_set_chunked_cb(struct evhttp_request *req,
|
evhttp_request_set_chunked_cb(struct evhttp_request *req,
|
||||||
void (*cb)(struct evhttp_request *, void *))
|
void (*cb)(struct evhttp_request *, void *))
|
||||||
|
@ -579,10 +579,13 @@ struct _rpc_hook_ctx {
|
|||||||
void *ctx;
|
void *ctx;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static int hook_pause_cb_called;
|
||||||
|
|
||||||
static void
|
static void
|
||||||
rpc_hook_pause_cb(int fd, short what, void *arg)
|
rpc_hook_pause_cb(int fd, short what, void *arg)
|
||||||
{
|
{
|
||||||
struct _rpc_hook_ctx *ctx = arg;
|
struct _rpc_hook_ctx *ctx = arg;
|
||||||
|
++hook_pause_cb_called;
|
||||||
evrpc_resume_request(ctx->vbase, ctx->ctx, EVRPC_CONTINUE);
|
evrpc_resume_request(ctx->vbase, ctx->ctx, EVRPC_CONTINUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -631,31 +634,19 @@ rpc_basic_client_with_pause(void)
|
|||||||
|
|
||||||
kill = kill_new();
|
kill = kill_new();
|
||||||
|
|
||||||
EVRPC_MAKE_REQUEST(Message, pool, msg, kill, GotKillCb, NULL);
|
EVRPC_MAKE_REQUEST(Message, pool, msg, kill, GotKillCb, NULL);
|
||||||
|
|
||||||
test_ok = 0;
|
test_ok = 0;
|
||||||
|
|
||||||
event_dispatch();
|
event_dispatch();
|
||||||
|
|
||||||
if (test_ok != 1) {
|
if (test_ok != 1 || hook_pause_cb_called != 4) {
|
||||||
fprintf(stdout, "FAILED (1)\n");
|
fprintf(stdout, "FAILED\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* we do it twice to make sure that reuse works correctly */
|
|
||||||
kill_clear(kill);
|
|
||||||
|
|
||||||
EVRPC_MAKE_REQUEST(Message, pool, msg, kill, GotKillCb, NULL);
|
|
||||||
|
|
||||||
event_dispatch();
|
|
||||||
|
|
||||||
rpc_teardown(base);
|
rpc_teardown(base);
|
||||||
|
|
||||||
if (test_ok != 2) {
|
|
||||||
fprintf(stdout, "FAILED (2)\n");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
fprintf(stdout, "OK\n");
|
fprintf(stdout, "OK\n");
|
||||||
|
|
||||||
msg_free(msg);
|
msg_free(msg);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user