| Index: third_party/libevent/test/regress_http.c
|
| diff --git a/third_party/libevent/test/regress_http.c b/third_party/libevent/test/regress_http.c
|
| index 7dc763cf8fe2c2b7d9dd7b395a8c7a11628c98d6..1e2a1eb062a3cdbc674a3aad45b50e2b418beb71 100644
|
| --- a/third_party/libevent/test/regress_http.c
|
| +++ b/third_party/libevent/test/regress_http.c
|
| @@ -42,7 +42,7 @@
|
| #include <sys/queue.h>
|
| #ifndef WIN32
|
| #include <sys/socket.h>
|
| -#include <sys/signal.h>
|
| +#include <signal.h>
|
| #include <unistd.h>
|
| #include <netdb.h>
|
| #endif
|
| @@ -70,6 +70,7 @@ void http_basic_cb(struct evhttp_request *req, void *arg);
|
| static void http_chunked_cb(struct evhttp_request *req, void *arg);
|
| void http_post_cb(struct evhttp_request *req, void *arg);
|
| void http_dispatcher_cb(struct evhttp_request *req, void *arg);
|
| +static void http_large_delay_cb(struct evhttp_request *req, void *arg);
|
|
|
| static struct evhttp *
|
| http_setup(short *pport, struct event_base *base)
|
| @@ -94,6 +95,7 @@ http_setup(short *pport, struct event_base *base)
|
| evhttp_set_cb(myhttp, "/test", http_basic_cb, NULL);
|
| evhttp_set_cb(myhttp, "/chunked", http_chunked_cb, NULL);
|
| evhttp_set_cb(myhttp, "/postit", http_post_cb, NULL);
|
| + evhttp_set_cb(myhttp, "/largedelay", http_large_delay_cb, NULL);
|
| evhttp_set_cb(myhttp, "/", http_dispatcher_cb, NULL);
|
|
|
| *pport = port;
|
| @@ -375,6 +377,31 @@ http_basic_test(void)
|
| fprintf(stdout, "OK\n");
|
| }
|
|
|
| +static struct evhttp_connection *delayed_client;
|
| +
|
| +static void
|
| +http_delay_reply(int fd, short what, void *arg)
|
| +{
|
| + struct evhttp_request *req = arg;
|
| +
|
| + evhttp_send_reply(req, HTTP_OK, "Everything is fine", NULL);
|
| +
|
| + ++test_ok;
|
| +}
|
| +
|
| +static void
|
| +http_large_delay_cb(struct evhttp_request *req, void *arg)
|
| +{
|
| + struct timeval tv;
|
| + timerclear(&tv);
|
| + tv.tv_sec = 3;
|
| +
|
| + event_once(-1, EV_TIMEOUT, http_delay_reply, req, &tv);
|
| +
|
| + /* here we close the client connection which will cause an EOF */
|
| + evhttp_connection_fail(delayed_client, EVCON_HTTP_EOF);
|
| +}
|
| +
|
| void http_request_done(struct evhttp_request *, void *);
|
| void http_request_empty_done(struct evhttp_request *, void *);
|
|
|
| @@ -819,6 +846,7 @@ http_failure_test(void)
|
| static void
|
| close_detect_done(struct evhttp_request *req, void *arg)
|
| {
|
| + struct timeval tv;
|
| if (req == NULL || req->response_code != HTTP_OK) {
|
|
|
| fprintf(stderr, "FAILED\n");
|
| @@ -826,7 +854,11 @@ close_detect_done(struct evhttp_request *req, void *arg)
|
| }
|
|
|
| test_ok = 1;
|
| - event_loopexit(NULL);
|
| +
|
| + timerclear(&tv);
|
| + tv.tv_sec = 3; /* longer than the http time out */
|
| +
|
| + event_loopexit(&tv);
|
| }
|
|
|
| static void
|
| @@ -853,7 +885,7 @@ close_detect_cb(struct evhttp_request *req, void *arg)
|
| struct evhttp_connection *evcon = arg;
|
| struct timeval tv;
|
|
|
| - if (req->response_code != HTTP_OK) {
|
| + if (req != NULL && req->response_code != HTTP_OK) {
|
|
|
| fprintf(stderr, "FAILED\n");
|
| exit(1);
|
| @@ -868,14 +900,15 @@ close_detect_cb(struct evhttp_request *req, void *arg)
|
|
|
|
|
| static void
|
| -http_close_detection(void)
|
| +http_close_detection(int with_delay)
|
| {
|
| short port = -1;
|
| struct evhttp_connection *evcon = NULL;
|
| struct evhttp_request *req = NULL;
|
|
|
| test_ok = 0;
|
| - fprintf(stdout, "Testing Connection Close Detection: ");
|
| + fprintf(stdout, "Testing Connection Close Detection%s: ",
|
| + with_delay ? " (with delay)" : "");
|
|
|
| http = http_setup(&port, NULL);
|
|
|
| @@ -888,6 +921,8 @@ http_close_detection(void)
|
| exit(1);
|
| }
|
|
|
| + delayed_client = evcon;
|
| +
|
| /*
|
| * At this point, we want to schedule a request to the HTTP
|
| * server using our make request method.
|
| @@ -899,7 +934,8 @@ http_close_detection(void)
|
| evhttp_add_header(req->output_headers, "Host", "somehost");
|
|
|
| /* We give ownership of the request to the connection */
|
| - if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test") == -1) {
|
| + if (evhttp_make_request(evcon,
|
| + req, EVHTTP_REQ_GET, with_delay ? "/largedelay" : "/test") == -1) {
|
| fprintf(stdout, "FAILED\n");
|
| exit(1);
|
| }
|
| @@ -911,6 +947,12 @@ http_close_detection(void)
|
| exit(1);
|
| }
|
|
|
| + /* at this point, the http server should have no connection */
|
| + if (TAILQ_FIRST(&http->connections) != NULL) {
|
| + fprintf(stdout, "FAILED (left connections)\n");
|
| + exit(1);
|
| + }
|
| +
|
| evhttp_connection_free(evcon);
|
| evhttp_free(http);
|
|
|
| @@ -953,13 +995,16 @@ http_bad_header_test(void)
|
|
|
| if (evhttp_add_header(&headers, "One\r", "Two") != -1)
|
| goto fail;
|
| -
|
| + if (evhttp_add_header(&headers, "One", "Two") != 0)
|
| + goto fail;
|
| + if (evhttp_add_header(&headers, "One", "Two\r\n Three") != 0)
|
| + goto fail;
|
| + if (evhttp_add_header(&headers, "One\r", "Two") != -1)
|
| + goto fail;
|
| if (evhttp_add_header(&headers, "One\n", "Two") != -1)
|
| goto fail;
|
| -
|
| if (evhttp_add_header(&headers, "One", "Two\r") != -1)
|
| goto fail;
|
| -
|
| if (evhttp_add_header(&headers, "One", "Two\n") != -1)
|
| goto fail;
|
|
|
| @@ -972,6 +1017,61 @@ fail:
|
| exit(1);
|
| }
|
|
|
| +static int validate_header(
|
| + const struct evkeyvalq* headers,
|
| + const char *key, const char *value)
|
| +{
|
| + const char *real_val = evhttp_find_header(headers, key);
|
| + if (real_val == NULL)
|
| + return (-1);
|
| + if (strcmp(real_val, value) != 0)
|
| + return (-1);
|
| + return (0);
|
| +}
|
| +
|
| +static void
|
| +http_parse_query_test(void)
|
| +{
|
| + struct evkeyvalq headers;
|
| +
|
| + fprintf(stdout, "Testing HTTP query parsing: ");
|
| +
|
| + TAILQ_INIT(&headers);
|
| +
|
| + evhttp_parse_query("http://www.test.com/?q=test", &headers);
|
| + if (validate_header(&headers, "q", "test") != 0)
|
| + goto fail;
|
| + evhttp_clear_headers(&headers);
|
| +
|
| + evhttp_parse_query("http://www.test.com/?q=test&foo=bar", &headers);
|
| + if (validate_header(&headers, "q", "test") != 0)
|
| + goto fail;
|
| + if (validate_header(&headers, "foo", "bar") != 0)
|
| + goto fail;
|
| + evhttp_clear_headers(&headers);
|
| +
|
| + evhttp_parse_query("http://www.test.com/?q=test+foo", &headers);
|
| + if (validate_header(&headers, "q", "test foo") != 0)
|
| + goto fail;
|
| + evhttp_clear_headers(&headers);
|
| +
|
| + evhttp_parse_query("http://www.test.com/?q=test%0Afoo", &headers);
|
| + if (validate_header(&headers, "q", "test\nfoo") != 0)
|
| + goto fail;
|
| + evhttp_clear_headers(&headers);
|
| +
|
| + evhttp_parse_query("http://www.test.com/?q=test%0Dfoo", &headers);
|
| + if (validate_header(&headers, "q", "test\rfoo") != 0)
|
| + goto fail;
|
| + evhttp_clear_headers(&headers);
|
| +
|
| + fprintf(stdout, "OK\n");
|
| + return;
|
| +fail:
|
| + fprintf(stdout, "FAILED\n");
|
| + exit(1);
|
| +}
|
| +
|
| static void
|
| http_base_test(void)
|
| {
|
| @@ -1358,10 +1458,12 @@ http_suite(void)
|
| {
|
| http_base_test();
|
| http_bad_header_test();
|
| + http_parse_query_test();
|
| http_basic_test();
|
| http_connection_test(0 /* not-persistent */);
|
| http_connection_test(1 /* persistent */);
|
| - http_close_detection();
|
| + http_close_detection(0 /* with delay */);
|
| + http_close_detection(1 /* with delay */);
|
| http_post_test();
|
| http_failure_test();
|
| http_highport_test();
|
|
|