]> granicus.if.org Git - libevent/commitdiff
Add unit-test for bad_request bug fixed in 1.4 recently.
authorPavel Plesov <mclap@users.sourceforge.net>
Tue, 12 Jan 2010 00:04:11 +0000 (19:04 -0500)
committerNick Mathewson <nickm@torproject.org>
Tue, 12 Jan 2010 00:04:11 +0000 (19:04 -0500)
This is a partial forward-port from 4fd2dd9d83a000b6.  There's no need
to forward-port the bugfix, since the test passes with http.c as-is.
I believe we fixed this while we were porting evhttp to bufferevent.
--nickm

test/regress_http.c

index c91fbb4675153c833cb297830f6b1d71cd11b5ac..c13edee8f8616bf5347ed8e83d9221e5693498a3 100644 (file)
@@ -70,8 +70,8 @@ static void http_put_cb(struct evhttp_request *req, void *arg);
 static void http_delete_cb(struct evhttp_request *req, void *arg);
 static void http_delay_cb(struct evhttp_request *req, void *arg);
 static void http_large_delay_cb(struct evhttp_request *req, void *arg);
+static void http_badreq_cb(struct evhttp_request *req, void *arg);
 static void http_dispatcher_cb(struct evhttp_request *req, void *arg);
-
 static struct evhttp *
 http_setup(short *pport, struct event_base *base)
 {
@@ -100,6 +100,7 @@ http_setup(short *pport, struct event_base *base)
        evhttp_set_cb(myhttp, "/deleteit", http_delete_cb, NULL);
        evhttp_set_cb(myhttp, "/delay", http_delay_cb, NULL);
        evhttp_set_cb(myhttp, "/largedelay", http_large_delay_cb, NULL);
+       evhttp_set_cb(myhttp, "/badrequest", http_badreq_cb, NULL);
        evhttp_set_cb(myhttp, "/", http_dispatcher_cb, NULL);
 
        *pport = port;
@@ -409,6 +410,151 @@ http_delay_cb(struct evhttp_request *req, void *arg)
        event_once(-1, EV_TIMEOUT, http_delay_reply, req, &tv);
 }
 
+static void
+http_badreq_cb(struct evhttp_request *req, void *arg)
+{
+       struct evbuffer *buf = evbuffer_new();
+
+       evhttp_add_header(req->output_headers, "Content-Type", "text/xml; charset=UTF-8");
+       evbuffer_add_printf(buf, "Hello, %s!", "127.0.0.1");
+
+       evhttp_send_reply(req, HTTP_OK, "OK", buf);
+       evbuffer_free(buf);
+}
+
+static void
+http_badreq_errorcb(struct bufferevent *bev, short what, void *arg)
+{
+       event_debug(("%s: called (what=%04x, arg=%p)", __func__, what, arg));
+       /* ignore */
+}
+
+static void
+http_badreq_readcb(struct bufferevent *bev, void *arg)
+{
+       const char *what = "Hello, 127.0.0.1";
+       const char *bad_request = "400 Bad Request";
+
+       event_debug(("%s: %s\n", __func__, EVBUFFER_DATA(bev->input)));
+
+       if (evbuffer_find(bev->input,
+               (const unsigned char *) bad_request,
+               strlen(bad_request)) != NULL) {
+               TT_FAIL(("%s: bad request detected", __func__));
+               bufferevent_disable(bev, EV_READ);
+               event_loopexit(NULL);
+               return;
+       }
+
+       if (evbuffer_find(bev->input,
+               (const unsigned char*) what, strlen(what)) != NULL) {
+               struct evhttp_request *req = evhttp_request_new(NULL, NULL);
+               enum message_read_status done;
+
+               req->kind = EVHTTP_RESPONSE;
+               done = evhttp_parse_firstline(req, bev->input);
+               if (done != ALL_DATA_READ)
+                       goto out;
+
+               done = evhttp_parse_headers(req, bev->input);
+               if (done != ALL_DATA_READ)
+                       goto out;
+
+               if (done == 1 &&
+                   evhttp_find_header(req->input_headers,
+                       "Content-Type") != NULL)
+                       test_ok++;
+
+       out:
+               evhttp_request_free(req);
+               evbuffer_drain(bev->input, EVBUFFER_LENGTH(bev->input));
+       }
+
+       shutdown(bev->ev_read.ev_fd, SHUT_WR);
+}
+
+static void
+http_badreq_successcb(int fd, short what, void *arg)
+{
+       event_debug(("%s: called (what=%04x, arg=%p)", __func__, what, arg));
+       event_loopexit(NULL);
+}
+
+static void
+http_bad_request_test(void)
+{
+       struct timeval tv;
+       struct bufferevent *bev;
+       int fd;
+       const char *http_request;
+       short port = -1;
+
+       test_ok = 0;
+
+       /* fprintf(stdout, "Testing \"Bad Request\" on connection close: "); */
+
+       http = http_setup(&port, NULL);
+
+       /* bind to a second socket */
+       if (evhttp_bind_socket(http, "127.0.0.1", port + 1) == -1)
+               TT_DIE(("Bind socket failed"));
+
+       /* NULL request test */
+       fd = http_connect("127.0.0.1", port);
+
+       /* Stupid thing to send a request */
+       bev = bufferevent_new(fd, http_badreq_readcb, http_writecb,
+           http_badreq_errorcb, NULL);
+       bufferevent_enable(bev, EV_READ);
+
+       /* real NULL request */
+       http_request = "";
+
+       shutdown(fd, SHUT_WR);
+       timerclear(&tv);
+       tv.tv_usec = 10000;
+       event_once(-1, EV_TIMEOUT, http_badreq_successcb, bev, &tv);
+
+       event_dispatch();
+
+       bufferevent_free(bev);
+       EVUTIL_CLOSESOCKET(fd);
+
+       if (test_ok != 0) {
+               fprintf(stdout, "FAILED\n");
+               exit(1);
+       }
+
+       /* Second answer (BAD REQUEST) on connection close */
+
+       /* connect to the second port */
+       fd = http_connect("127.0.0.1", port + 1);
+
+       /* Stupid thing to send a request */
+       bev = bufferevent_new(fd, http_badreq_readcb, http_writecb,
+           http_badreq_errorcb, NULL);
+       bufferevent_enable(bev, EV_READ);
+
+       /* first half of the http request */
+       http_request =
+               "GET /badrequest HTTP/1.0\r\n"  \
+               "Connection: Keep-Alive\r\n"    \
+               "\r\n";
+
+       bufferevent_write(bev, http_request, strlen(http_request));
+
+       timerclear(&tv);
+       tv.tv_usec = 10000;
+       event_once(-1, EV_TIMEOUT, http_badreq_successcb, bev, &tv);
+
+       event_dispatch();
+
+       tt_int_op(test_ok, ==, 2);
+
+end:
+       evhttp_free(http);
+}
+
 static struct evhttp_connection *delayed_client;
 
 static void
@@ -2282,6 +2428,7 @@ struct testcase_t http_testcases[] = {
        HTTP_LEGACY(persist_connection),
        HTTP_LEGACY(close_detection),
        HTTP_LEGACY(close_detection_delay),
+       HTTP_LEGACY(bad_request),
        HTTP_LEGACY(incomplete),
        HTTP_LEGACY(incomplete_timeout),