make sure that the rpc reply contains a good rpc structure, too.
svn:r258
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__);
}
#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*);
constructed_uri,
evrpc_request_cb,
rpc);
+
+ free(constructed_uri);
return (0);
}
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 */
if (rpc_state->reply == NULL)
goto error;
- rpc_state->rpc = rpc;
rpc_state->http_req = req;
rpc_state->done = evrpc_request_done;
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);
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;
}
/* 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);
* 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 */
(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; \
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) {
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");
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)
http_basic_test();
http_connection_test();
http_post_test();
+ http_failure_test();
}
#include "evhttp.h"
#include "log.h"
#include "evrpc.h"
+
#include "regress.gen.h"
+extern int test_ok;
+
static struct evhttp *
http_setup(short *pport)
{
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_basic_test(void)
+rpc_setup(struct evhttp **phttp, short *pport, struct evrpc_base **pbase)
{
short port;
struct evhttp *http = NULL;
struct evrpc_base *base = NULL;
- fprintf(stdout, "Testing Basic RPC Support: ");
-
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: ");
+
+ 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_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();
}