mirror of
https://github.com/cuberite/libevent.git
synced 2025-09-14 06:49:35 -04:00
make sure that the rpc callback receives an unmarshaled payload;
make sure that the rpc reply contains a good rpc structure, too. svn:r258
This commit is contained in:
parent
1caff9bcc8
commit
c4836d1053
@ -51,11 +51,14 @@
|
||||
|
||||
int decode_int(u_int32_t *pnumber, struct evbuffer *evbuf);
|
||||
|
||||
static struct evbuffer *_buf;
|
||||
static struct evbuffer *_buf; /* not thread safe */
|
||||
|
||||
void
|
||||
evtag_init()
|
||||
{
|
||||
if (_buf != NULL)
|
||||
return;
|
||||
|
||||
if ((_buf = evbuffer_new()) == NULL)
|
||||
event_err(1, "%s: malloc", __func__);
|
||||
}
|
||||
|
28
evrpc.c
28
evrpc.c
@ -59,18 +59,27 @@
|
||||
#include "log.h"
|
||||
|
||||
struct evrpc_base *
|
||||
evrpc_init(struct evhttp* http_server)
|
||||
evrpc_init(struct evhttp *http_server)
|
||||
{
|
||||
struct evrpc_base* base = calloc(1, sizeof(struct evrpc_base));
|
||||
if (base == NULL)
|
||||
return (NULL);
|
||||
|
||||
/* we rely on the tagging sub system */
|
||||
evtag_init();
|
||||
|
||||
TAILQ_INIT(&base->registered_rpcs);
|
||||
base->http_server = http_server;
|
||||
|
||||
return (base);
|
||||
}
|
||||
|
||||
void
|
||||
evrpc_free(struct evrpc_base *base)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void evrpc_request_cb(struct evhttp_request *, void *);
|
||||
void evrpc_request_done(struct evrpc_req_generic*);
|
||||
|
||||
@ -106,6 +115,8 @@ evrpc_register_rpc(struct evrpc_base *base, struct evrpc *rpc,
|
||||
evrpc_request_cb,
|
||||
rpc);
|
||||
|
||||
free(constructed_uri);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
@ -128,18 +139,14 @@ evrpc_request_cb(struct evhttp_request *req, void *arg)
|
||||
rpc_state->request = rpc->request_new();
|
||||
if (rpc_state->request == NULL)
|
||||
goto error;
|
||||
|
||||
rpc_state->rpc = rpc;
|
||||
|
||||
if (rpc->request_unmarshal(
|
||||
rpc_state->request, req->input_buffer) == -1) {
|
||||
/* we failed to parse the request; that's a bummer */
|
||||
goto error;
|
||||
}
|
||||
if (!rpc->request_complete(rpc_state->request)) {
|
||||
/*
|
||||
* we were able to parse the structure but not all required
|
||||
* fields had been filled in.
|
||||
*/
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* at this point, we have a well formed request, prepare the reply */
|
||||
|
||||
@ -147,7 +154,6 @@ evrpc_request_cb(struct evhttp_request *req, void *arg)
|
||||
if (rpc_state->reply == NULL)
|
||||
goto error;
|
||||
|
||||
rpc_state->rpc = rpc;
|
||||
rpc_state->http_req = req;
|
||||
rpc_state->done = evrpc_request_done;
|
||||
|
||||
@ -170,7 +176,7 @@ evrpc_reqstate_free(struct evrpc_req_generic* rpc_state)
|
||||
struct evrpc *rpc = rpc_state->rpc;
|
||||
|
||||
if (rpc_state->request != NULL)
|
||||
rpc->request_free(rpc_state);
|
||||
rpc->request_free(rpc_state->request);
|
||||
if (rpc_state->reply != NULL)
|
||||
rpc->reply_free(rpc_state->reply);
|
||||
free(rpc_state);
|
||||
@ -184,7 +190,7 @@ evrpc_request_done(struct evrpc_req_generic* rpc_state)
|
||||
struct evrpc *rpc = rpc_state->rpc;
|
||||
struct evbuffer* data;
|
||||
|
||||
if (!rpc->reply_complete(rpc_state->reply)) {
|
||||
if (rpc->reply_complete(rpc_state->reply) == -1) {
|
||||
/* the reply was not completely filled in. error out */
|
||||
goto error;
|
||||
}
|
||||
|
10
evrpc.h
10
evrpc.h
@ -46,9 +46,6 @@ struct evrpc {
|
||||
/* unmarshals the buffer into the proper request structure */
|
||||
int (*request_unmarshal)(void *, struct evbuffer *);
|
||||
|
||||
/* verifies that the unmarshaled buffer is complete */
|
||||
int (*request_complete)(void *);
|
||||
|
||||
/* creates a new reply structure */
|
||||
void *(*reply_new)(void);
|
||||
|
||||
@ -109,9 +106,9 @@ EVRPC_STRUCT(rpcname) { \
|
||||
* after this call has finished.
|
||||
*/
|
||||
#define EVRPC_REQUEST_DONE(rpc_req) do { \
|
||||
struct evrpc_req_generic *req = (struct evrpc_req_generic)(rpc_req); \
|
||||
req->done(req); \
|
||||
}
|
||||
struct evrpc_req_generic *_req = (struct evrpc_req_generic *)(rpc_req); \
|
||||
_req->done(_req); \
|
||||
} while (0)
|
||||
|
||||
|
||||
/* Takes a request object and fills it in with the right magic */
|
||||
@ -123,7 +120,6 @@ EVRPC_STRUCT(rpcname) { \
|
||||
(rpc)->request_new = (void *(*)(void))request##_new; \
|
||||
(rpc)->request_free = (void (*)(void *))request##_free; \
|
||||
(rpc)->request_unmarshal = (int (*)(void *, struct evbuffer *))request##_unmarshal; \
|
||||
(rpc)->request_complete = (int (*)(void *))request##_complete; \
|
||||
(rpc)->reply_new = (void *(*)(void))reply##_new; \
|
||||
(rpc)->reply_free = (void (*)(void *))reply##_free; \
|
||||
(rpc)->reply_complete = (int (*)(void *))reply##_complete; \
|
||||
|
7
http.c
7
http.c
@ -932,7 +932,7 @@ evhttp_read_header(int fd, short what, void *arg)
|
||||
res = evhttp_parse_lines(req, evcon->input_buffer);
|
||||
if (res == -1) {
|
||||
/* Error while reading, terminate */
|
||||
event_warnx("%s: bad header lines on %d\n", __func__, fd);
|
||||
event_debug(("%s: bad header lines on %d\n", __func__, fd));
|
||||
evhttp_connection_fail(evcon);
|
||||
return;
|
||||
} else if (res == 0) {
|
||||
@ -1190,6 +1190,11 @@ evhttp_response_code(struct evhttp_request *req, int code, const char *reason)
|
||||
void
|
||||
evhttp_send_page(struct evhttp_request *req, struct evbuffer *databuf)
|
||||
{
|
||||
if (!req->major || !req->minor) {
|
||||
req->major = 1;
|
||||
req->minor = 1;
|
||||
}
|
||||
|
||||
if (req->kind != EVHTTP_RESPONSE)
|
||||
evhttp_response_code(req, 200, "OK");
|
||||
|
||||
|
@ -416,6 +416,57 @@ http_postrequest_done(struct evhttp_request *req, void *arg)
|
||||
event_loopexit(NULL);
|
||||
}
|
||||
|
||||
void
|
||||
http_failure_readcb(struct bufferevent *bev, void *arg)
|
||||
{
|
||||
const char *what = "400 Bad Request";
|
||||
if (evbuffer_find(bev->input, what, strlen(what)) != NULL) {
|
||||
test_ok = 2;
|
||||
event_loopexit(NULL);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Testing that the HTTP server can deal with a malformed request.
|
||||
*/
|
||||
void
|
||||
http_failure_test(void)
|
||||
{
|
||||
struct bufferevent *bev;
|
||||
int fd;
|
||||
char *http_request;
|
||||
short port = -1;
|
||||
|
||||
test_ok = 0;
|
||||
fprintf(stdout, "Testing Bad HTTP Request: ");
|
||||
|
||||
http = http_setup(&port);
|
||||
|
||||
fd = http_connect("127.0.0.1", port);
|
||||
|
||||
/* Stupid thing to send a request */
|
||||
bev = bufferevent_new(fd, http_failure_readcb, http_writecb,
|
||||
http_errorcb, NULL);
|
||||
|
||||
http_request = "illegal request\r\n";
|
||||
|
||||
bufferevent_write(bev, http_request, strlen(http_request));
|
||||
|
||||
event_dispatch();
|
||||
|
||||
bufferevent_free(bev);
|
||||
close(fd);
|
||||
|
||||
evhttp_free(http);
|
||||
|
||||
if (test_ok != 2) {
|
||||
fprintf(stdout, "FAILED\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
fprintf(stdout, "OK\n");
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
http_suite(void)
|
||||
@ -423,4 +474,5 @@ http_suite(void)
|
||||
http_basic_test();
|
||||
http_connection_test();
|
||||
http_post_test();
|
||||
http_failure_test();
|
||||
}
|
||||
|
@ -56,8 +56,11 @@
|
||||
#include "evhttp.h"
|
||||
#include "log.h"
|
||||
#include "evrpc.h"
|
||||
|
||||
#include "regress.gen.h"
|
||||
|
||||
extern int test_ok;
|
||||
|
||||
static struct evhttp *
|
||||
http_setup(short *pport)
|
||||
{
|
||||
@ -86,29 +89,194 @@ EVRPC_DEFINE(Message, msg, kill);
|
||||
void
|
||||
MessageCB(EVRPC_STRUCT(Message)* rpc, void *arg)
|
||||
{
|
||||
struct kill* kill_reply = rpc->reply;
|
||||
|
||||
/* we just want to fill in some non-sense */
|
||||
EVTAG_ASSIGN(kill_reply, weapon, "dagger");
|
||||
EVTAG_ASSIGN(kill_reply, action, "wave around like an idiot");
|
||||
|
||||
/* no reply to the RPC */
|
||||
EVRPC_REQUEST_DONE(rpc);
|
||||
}
|
||||
|
||||
static void
|
||||
rpc_setup(struct evhttp **phttp, short *pport, struct evrpc_base **pbase)
|
||||
{
|
||||
short port;
|
||||
struct evhttp *http = NULL;
|
||||
struct evrpc_base *base = NULL;
|
||||
|
||||
http = http_setup(&port);
|
||||
base = evrpc_init(http);
|
||||
|
||||
EVRPC_REGISTER(base, "Message", msg, kill, MessageCB, NULL);
|
||||
|
||||
*phttp = http;
|
||||
*pport = port;
|
||||
*pbase = base;
|
||||
}
|
||||
|
||||
static void
|
||||
rpc_postrequest_failure(struct evhttp_request *req, void *arg)
|
||||
{
|
||||
if (req->response_code != HTTP_SERVUNAVAIL) {
|
||||
|
||||
fprintf(stderr, "FAILED (response code)\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
test_ok = 1;
|
||||
event_loopexit(NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Test a malformed payload submitted as an RPC
|
||||
*/
|
||||
|
||||
static void
|
||||
rpc_basic_test(void)
|
||||
{
|
||||
short port;
|
||||
struct evhttp *http = NULL;
|
||||
struct evrpc_base *base = NULL;
|
||||
struct evhttp_connection *evcon = NULL;
|
||||
struct evhttp_request *req = NULL;
|
||||
|
||||
fprintf(stdout, "Testing Basic RPC Support: ");
|
||||
|
||||
http = http_setup(&port);
|
||||
base = evrpc_init(http);
|
||||
rpc_setup(&http, &port, &base);
|
||||
|
||||
EVRPC_REGISTER(base, "Message", msg, kill, MessageCB, NULL);
|
||||
evcon = evhttp_connection_new("127.0.0.1", port);
|
||||
if (evcon == NULL) {
|
||||
fprintf(stdout, "FAILED\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/*
|
||||
* At this point, we want to schedule an HTTP POST request
|
||||
* server using our make request method.
|
||||
*/
|
||||
|
||||
req = evhttp_request_new(rpc_postrequest_failure, NULL);
|
||||
if (req == NULL) {
|
||||
fprintf(stdout, "FAILED\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Add the information that we care about */
|
||||
evhttp_add_header(req->output_headers, "Host", "somehost");
|
||||
evbuffer_add_printf(req->output_buffer, "Some Nonsense");
|
||||
|
||||
if (evhttp_make_request(evcon, req,
|
||||
EVHTTP_REQ_POST,
|
||||
"/.rpc.Message") == -1) {
|
||||
fprintf(stdout, "FAILED\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
test_ok = 0;
|
||||
|
||||
event_dispatch();
|
||||
|
||||
if (test_ok != 1) {
|
||||
fprintf(stdout, "FAILED\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
fprintf(stdout, "OK\n");
|
||||
|
||||
evhttp_free(http);
|
||||
}
|
||||
|
||||
static void
|
||||
rpc_postrequest_done(struct evhttp_request *req, void *arg)
|
||||
{
|
||||
struct kill* kill_reply = NULL;
|
||||
|
||||
if (req->response_code != HTTP_OK) {
|
||||
|
||||
fprintf(stderr, "FAILED (response code)\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
kill_reply = kill_new();
|
||||
|
||||
if ((kill_unmarshal(kill_reply, req->input_buffer)) == -1) {
|
||||
fprintf(stderr, "FAILED (unmarshal)\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
kill_free(kill_reply);
|
||||
|
||||
test_ok = 1;
|
||||
event_loopexit(NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
rpc_basic_message(void)
|
||||
{
|
||||
short port;
|
||||
struct evhttp *http = NULL;
|
||||
struct evrpc_base *base = NULL;
|
||||
struct evhttp_connection *evcon = NULL;
|
||||
struct evhttp_request *req = NULL;
|
||||
struct msg *msg;
|
||||
|
||||
fprintf(stdout, "Testing Good RPC Post: ");
|
||||
|
||||
rpc_setup(&http, &port, &base);
|
||||
|
||||
evcon = evhttp_connection_new("127.0.0.1", port);
|
||||
if (evcon == NULL) {
|
||||
fprintf(stdout, "FAILED\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/*
|
||||
* At this point, we want to schedule an HTTP POST request
|
||||
* server using our make request method.
|
||||
*/
|
||||
|
||||
req = evhttp_request_new(rpc_postrequest_done, NULL);
|
||||
if (req == NULL) {
|
||||
fprintf(stdout, "FAILED\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Add the information that we care about */
|
||||
evhttp_add_header(req->output_headers, "Host", "somehost");
|
||||
|
||||
/* set up the basic message */
|
||||
msg = msg_new();
|
||||
EVTAG_ASSIGN(msg, from_name, "niels");
|
||||
EVTAG_ASSIGN(msg, to_name, "tester");
|
||||
msg_marshal(req->output_buffer, msg);
|
||||
msg_free(msg);
|
||||
|
||||
if (evhttp_make_request(evcon, req,
|
||||
EVHTTP_REQ_POST,
|
||||
"/.rpc.Message") == -1) {
|
||||
fprintf(stdout, "FAILED\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
test_ok = 0;
|
||||
|
||||
event_dispatch();
|
||||
|
||||
if (test_ok != 1) {
|
||||
fprintf(stdout, "FAILED\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
fprintf(stdout, "OK\n");
|
||||
|
||||
evhttp_free(http);
|
||||
}
|
||||
|
||||
void
|
||||
rpc_suite(void)
|
||||
{
|
||||
rpc_basic_test();
|
||||
rpc_basic_message();
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user