]> granicus.if.org Git - libevent/commitdiff
make sure that the rpc callback receives an unmarshaled payload;
authorNiels Provos <provos@gmail.com>
Fri, 17 Nov 2006 06:06:17 +0000 (06:06 +0000)
committerNiels Provos <provos@gmail.com>
Fri, 17 Nov 2006 06:06:17 +0000 (06:06 +0000)
make sure that the rpc reply contains a good rpc structure, too.

svn:r258

event_tagging.c
evrpc.c
evrpc.h
http.c
test/regress_http.c
test/regress_rpc.c

index b60d722eff99aa7cdedb96f2df301b85ff564762..ac4e347500f1ffc4caad8c5bbcadc31bc7a02615 100644 (file)
 
 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__);
 }
diff --git a/evrpc.c b/evrpc.c
index 4e9ba87d36373152c04d8a308fff9ca7278b71b7..74d6601add43eaa46d232151909cc4a7c10d9d29 100644 (file)
--- a/evrpc.c
+++ b/evrpc.c
 #include "log.h"
 
 struct evrpc_base *
-evrpc_init(struct evhttphttp_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*);
 
@@ -105,6 +114,8 @@ evrpc_register_rpc(struct evrpc_base *base, struct evrpc *rpc,
            constructed_uri,
            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;
        }
diff --git a/evrpc.h b/evrpc.h
index c46dcba94f0904325fed4789415e98d9867a9ec1..18db7f1be614fd45617ddcba08857c239dab378c 100644 (file)
--- a/evrpc.h
+++ b/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; \
diff --git a/http.c b/http.c
index 4dfcd3fba421297559bf3f08b8169b74f2fd6683..a7a1bdb10c69917cde42181262b06f74f46bf4b8 100644 (file)
--- a/http.c
+++ b/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");
 
index b04a3639367ea2581bb767f6796c87e8926c1230..395e0ab926294fed81719d715a1028776a0fb2e5 100644 (file)
@@ -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();
 }
index 09a59606723cbfaf26b40dd69022f52c3870c4b8..59113bf509ea88521e1469e24a48a082373c0afc 100644 (file)
 #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_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();
 }