2 * Copyright (c) 2003-2007 Niels Provos <provos@citi.umich.edu>
3 * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. The name of the author may not be used to endorse or promote products
14 * derived from this software without specific prior written permission.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 #include "util-internal.h"
35 #include "event2/event-config.h"
37 #include <sys/types.h>
39 #ifdef EVENT__HAVE_SYS_TIME_H
42 #include <sys/queue.h>
44 #include <sys/socket.h>
55 #include "event2/dns.h"
57 #include "event2/event.h"
58 #include "event2/http.h"
59 #include "event2/buffer.h"
60 #include "event2/bufferevent.h"
61 #include "event2/util.h"
62 #include "log-internal.h"
63 #include "http-internal.h"
65 #include "regress_testutils.h"
67 static struct evhttp *http;
68 /* set if a test needs to call loopexit on a base */
69 static struct event_base *exit_base;
71 static char const BASIC_REQUEST_BODY[] = "This is funny";
73 #define IMPL_HTTP_REQUEST_ERROR_CB(name, expecting_error) \
75 http_request_error_cb_with_##name##_(enum evhttp_request_error error, \
78 if (error != expecting_error) { \
79 fprintf(stderr, "FAILED\n"); \
84 IMPL_HTTP_REQUEST_ERROR_CB(cancel, EVREQ_HTTP_REQUEST_CANCEL)
86 static void http_basic_cb(struct evhttp_request *req, void *arg);
87 static void http_chunked_cb(struct evhttp_request *req, void *arg);
88 static void http_post_cb(struct evhttp_request *req, void *arg);
89 static void http_put_cb(struct evhttp_request *req, void *arg);
90 static void http_delete_cb(struct evhttp_request *req, void *arg);
91 static void http_delay_cb(struct evhttp_request *req, void *arg);
92 static void http_large_delay_cb(struct evhttp_request *req, void *arg);
93 static void http_badreq_cb(struct evhttp_request *req, void *arg);
94 static void http_dispatcher_cb(struct evhttp_request *req, void *arg);
95 static void http_on_complete_cb(struct evhttp_request *req, void *arg);
98 http_bind(struct evhttp *myhttp, ev_uint16_t *pport, int ipv6)
101 struct evhttp_bound_socket *sock;
104 sock = evhttp_bind_socket_with_handle(myhttp, "::1", *pport);
106 sock = evhttp_bind_socket_with_handle(myhttp, "127.0.0.1", *pport);
112 event_errx(1, "Could not start web server");
115 port = regress_get_socket_port(evhttp_bound_socket_get_fd(sock));
118 *pport = (ev_uint16_t) port;
123 static struct evhttp *
124 http_setup(ev_uint16_t *pport, struct event_base *base, int ipv6)
126 struct evhttp *myhttp;
128 /* Try a few different ports */
129 myhttp = evhttp_new(base);
131 if (http_bind(myhttp, pport, ipv6) < 0)
134 /* Register a callback for certain types of requests */
135 evhttp_set_cb(myhttp, "/test", http_basic_cb, base);
136 evhttp_set_cb(myhttp, "/chunked", http_chunked_cb, base);
137 evhttp_set_cb(myhttp, "/streamed", http_chunked_cb, base);
138 evhttp_set_cb(myhttp, "/postit", http_post_cb, base);
139 evhttp_set_cb(myhttp, "/putit", http_put_cb, base);
140 evhttp_set_cb(myhttp, "/deleteit", http_delete_cb, base);
141 evhttp_set_cb(myhttp, "/delay", http_delay_cb, base);
142 evhttp_set_cb(myhttp, "/largedelay", http_large_delay_cb, base);
143 evhttp_set_cb(myhttp, "/badrequest", http_badreq_cb, base);
144 evhttp_set_cb(myhttp, "/oncomplete", http_on_complete_cb, base);
145 evhttp_set_cb(myhttp, "/", http_dispatcher_cb, base);
150 #define NI_MAXSERV 1024
153 static evutil_socket_t
154 http_connect(const char *address, u_short port)
156 /* Stupid code for connecting */
157 struct evutil_addrinfo ai, *aitop;
158 char strport[NI_MAXSERV];
164 memset(&ai, 0, sizeof(ai));
165 ai.ai_family = AF_INET;
166 ai.ai_socktype = SOCK_STREAM;
167 evutil_snprintf(strport, sizeof(strport), "%d", port);
168 if (evutil_getaddrinfo(address, strport, &ai, &aitop) != 0) {
169 event_warn("getaddrinfo");
173 slen = aitop->ai_addrlen;
175 fd = socket(AF_INET, SOCK_STREAM, 0);
177 event_err(1, "socket failed");
179 evutil_make_socket_nonblocking(fd);
180 if (connect(fd, sa, slen) == -1) {
182 int tmp_err = WSAGetLastError();
183 if (tmp_err != WSAEINPROGRESS && tmp_err != WSAEINVAL &&
184 tmp_err != WSAEWOULDBLOCK)
185 event_err(1, "connect failed");
187 if (errno != EINPROGRESS)
188 event_err(1, "connect failed");
192 evutil_freeaddrinfo(aitop);
197 /* Helper: do a strcmp on the contents of buf and the string s. */
199 evbuffer_datacmp(struct evbuffer *buf, const char *s)
201 size_t b_sz = evbuffer_get_length(buf);
202 size_t s_sz = strlen(s);
209 d = evbuffer_pullup(buf, s_sz);
210 if ((r = memcmp(d, s, s_sz)))
219 /* Helper: Return true iff buf contains s */
221 evbuffer_contains(struct evbuffer *buf, const char *s)
223 struct evbuffer_ptr ptr;
224 ptr = evbuffer_search(buf, s, strlen(s), NULL);
225 return ptr.pos != -1;
229 http_readcb(struct bufferevent *bev, void *arg)
231 const char *what = BASIC_REQUEST_BODY;
232 struct event_base *my_base = arg;
234 if (evbuffer_contains(bufferevent_get_input(bev), what)) {
235 struct evhttp_request *req = evhttp_request_new(NULL, NULL);
236 enum message_read_status done;
238 /* req->kind = EVHTTP_RESPONSE; */
239 done = evhttp_parse_firstline_(req, bufferevent_get_input(bev));
240 if (done != ALL_DATA_READ)
243 done = evhttp_parse_headers_(req, bufferevent_get_input(bev));
244 if (done != ALL_DATA_READ)
248 evhttp_find_header(evhttp_request_get_input_headers(req),
249 "Content-Type") != NULL)
253 evhttp_request_free(req);
254 bufferevent_disable(bev, EV_READ);
256 event_base_loopexit(exit_base, NULL);
258 event_base_loopexit(my_base, NULL);
260 fprintf(stderr, "No way to exit loop!\n");
267 http_writecb(struct bufferevent *bev, void *arg)
269 if (evbuffer_get_length(bufferevent_get_output(bev)) == 0) {
270 /* enable reading of the reply */
271 bufferevent_enable(bev, EV_READ);
277 http_errorcb(struct bufferevent *bev, short what, void *arg)
280 event_base_loopexit(arg, NULL);
283 static int found_multi = 0;
284 static int found_multi2 = 0;
287 http_basic_cb(struct evhttp_request *req, void *arg)
289 struct evbuffer *evb = evbuffer_new();
290 struct evhttp_connection *evcon;
291 int empty = evhttp_find_header(evhttp_request_get_input_headers(req), "Empty") != NULL;
292 event_debug(("%s: called\n", __func__));
293 evbuffer_add_printf(evb, BASIC_REQUEST_BODY);
295 evcon = evhttp_request_get_connection(req);
296 tt_assert(evhttp_connection_get_server(evcon) == http);
298 /* For multi-line headers test */
301 evhttp_find_header(evhttp_request_get_input_headers(req),"X-Multi");
303 found_multi = !strcmp(multi,"aaaaaaaa a END");
304 if (strcmp("END", multi + strlen(multi) - 3) == 0)
306 if (evhttp_find_header(evhttp_request_get_input_headers(req), "X-Last"))
312 evhttp_find_header(evhttp_request_get_input_headers(req),"X-Multi-Extra-WS");
314 found_multi2 = !strcmp(multi2,"libevent 2.1");
319 /* injecting a bad content-length */
320 if (evhttp_find_header(evhttp_request_get_input_headers(req), "X-Negative"))
321 evhttp_add_header(evhttp_request_get_output_headers(req),
322 "Content-Length", "-100");
324 /* allow sending of an empty reply */
325 evhttp_send_reply(req, HTTP_OK, "Everything is fine",
326 !empty ? evb : NULL);
332 static char const* const CHUNKS[] = {
334 "but not hilarious.",
338 struct chunk_req_state {
339 struct event_base *base;
340 struct evhttp_request *req;
345 http_chunked_trickle_cb(evutil_socket_t fd, short events, void *arg)
347 struct evbuffer *evb = evbuffer_new();
348 struct chunk_req_state *state = arg;
349 struct timeval when = { 0, 0 };
351 evbuffer_add_printf(evb, "%s", CHUNKS[state->i]);
352 evhttp_send_reply_chunk(state->req, evb);
355 if (++state->i < (int) (sizeof(CHUNKS)/sizeof(CHUNKS[0]))) {
356 event_base_once(state->base, -1, EV_TIMEOUT,
357 http_chunked_trickle_cb, state, &when);
359 evhttp_send_reply_end(state->req);
365 http_chunked_cb(struct evhttp_request *req, void *arg)
367 struct timeval when = { 0, 0 };
368 struct chunk_req_state *state = malloc(sizeof(struct chunk_req_state));
369 event_debug(("%s: called\n", __func__));
371 fprintf(stderr, "Unable to allocate memory in http_chunked_cb()\n");
375 memset(state, 0, sizeof(struct chunk_req_state));
379 if (strcmp(evhttp_request_get_uri(req), "/streamed") == 0) {
380 evhttp_add_header(evhttp_request_get_output_headers(req), "Content-Length", "39");
383 /* generate a chunked/streamed reply */
384 evhttp_send_reply_start(req, HTTP_OK, "Everything is fine");
386 /* but trickle it across several iterations to ensure we're not
387 * assuming it comes all at once */
388 event_base_once(arg, -1, EV_TIMEOUT, http_chunked_trickle_cb, state, &when);
392 http_complete_write(evutil_socket_t fd, short what, void *arg)
394 struct bufferevent *bev = arg;
395 const char *http_request = "host\r\n"
396 "Connection: close\r\n"
398 bufferevent_write(bev, http_request, strlen(http_request));
402 http_basic_test(void *arg)
404 struct basic_test_data *data = arg;
406 struct bufferevent *bev = NULL;
408 const char *http_request;
409 ev_uint16_t port = 0, port2 = 0;
413 http = http_setup(&port, data->base, 0);
415 /* bind to a second socket */
416 if (http_bind(http, &port2, 0) == -1) {
417 fprintf(stdout, "FAILED (bind)\n");
421 fd = http_connect("127.0.0.1", port);
423 /* Stupid thing to send a request */
424 bev = bufferevent_socket_new(data->base, fd, 0);
425 bufferevent_setcb(bev, http_readcb, http_writecb,
426 http_errorcb, data->base);
428 /* first half of the http request */
430 "GET /test HTTP/1.1\r\n"
433 bufferevent_write(bev, http_request, strlen(http_request));
434 evutil_timerclear(&tv);
436 event_base_once(data->base,
437 -1, EV_TIMEOUT, http_complete_write, bev, &tv);
439 event_base_dispatch(data->base);
441 tt_assert(test_ok == 3);
443 /* connect to the second port */
444 bufferevent_free(bev);
445 evutil_closesocket(fd);
447 fd = http_connect("127.0.0.1", port2);
449 /* Stupid thing to send a request */
450 bev = bufferevent_socket_new(data->base, fd, 0);
451 bufferevent_setcb(bev, http_readcb, http_writecb,
452 http_errorcb, data->base);
455 "GET /test HTTP/1.1\r\n"
457 "Connection: close\r\n"
460 bufferevent_write(bev, http_request, strlen(http_request));
462 event_base_dispatch(data->base);
464 tt_assert(test_ok == 5);
466 /* Connect to the second port again. This time, send an absolute uri. */
467 bufferevent_free(bev);
468 evutil_closesocket(fd);
470 fd = http_connect("127.0.0.1", port2);
472 /* Stupid thing to send a request */
473 bev = bufferevent_socket_new(data->base, fd, 0);
474 bufferevent_setcb(bev, http_readcb, http_writecb,
475 http_errorcb, data->base);
478 "GET http://somehost.net/test HTTP/1.1\r\n"
480 "Connection: close\r\n"
483 bufferevent_write(bev, http_request, strlen(http_request));
485 event_base_dispatch(data->base);
487 tt_assert(test_ok == 7);
492 bufferevent_free(bev);
497 http_delay_reply(evutil_socket_t fd, short what, void *arg)
499 struct evhttp_request *req = arg;
501 evhttp_send_reply(req, HTTP_OK, "Everything is fine", NULL);
507 http_delay_cb(struct evhttp_request *req, void *arg)
510 evutil_timerclear(&tv);
512 tv.tv_usec = 200 * 1000;
514 event_base_once(arg, -1, EV_TIMEOUT, http_delay_reply, req, &tv);
518 http_badreq_cb(struct evhttp_request *req, void *arg)
520 struct evbuffer *buf = evbuffer_new();
522 evhttp_add_header(evhttp_request_get_output_headers(req), "Content-Type", "text/xml; charset=UTF-8");
523 evbuffer_add_printf(buf, "Hello, %s!", "127.0.0.1");
525 evhttp_send_reply(req, HTTP_OK, "OK", buf);
530 http_badreq_errorcb(struct bufferevent *bev, short what, void *arg)
532 event_debug(("%s: called (what=%04x, arg=%p)", __func__, what, arg));
538 #define SHUT_WR SD_SEND
545 http_badreq_readcb(struct bufferevent *bev, void *arg)
547 const char *what = "Hello, 127.0.0.1";
548 const char *bad_request = "400 Bad Request";
550 if (evbuffer_contains(bufferevent_get_input(bev), bad_request)) {
551 TT_FAIL(("%s:bad request detected", __func__));
552 bufferevent_disable(bev, EV_READ);
553 event_base_loopexit(arg, NULL);
557 if (evbuffer_contains(bufferevent_get_input(bev), what)) {
558 struct evhttp_request *req = evhttp_request_new(NULL, NULL);
559 enum message_read_status done;
561 /* req->kind = EVHTTP_RESPONSE; */
562 done = evhttp_parse_firstline_(req, bufferevent_get_input(bev));
563 if (done != ALL_DATA_READ)
566 done = evhttp_parse_headers_(req, bufferevent_get_input(bev));
567 if (done != ALL_DATA_READ)
571 evhttp_find_header(evhttp_request_get_input_headers(req),
572 "Content-Type") != NULL)
576 evhttp_request_free(req);
577 evbuffer_drain(bufferevent_get_input(bev), evbuffer_get_length(bufferevent_get_input(bev)));
580 shutdown(bufferevent_getfd(bev), SHUT_WR);
584 http_badreq_successcb(evutil_socket_t fd, short what, void *arg)
586 event_debug(("%s: called (what=%04x, arg=%p)", __func__, what, arg));
587 event_base_loopexit(exit_base, NULL);
591 http_bad_request_test(void *arg)
593 struct basic_test_data *data = arg;
595 struct bufferevent *bev = NULL;
596 evutil_socket_t fd = -1;
597 const char *http_request;
598 ev_uint16_t port=0, port2=0;
601 exit_base = data->base;
603 http = http_setup(&port, data->base, 0);
605 /* bind to a second socket */
606 if (http_bind(http, &port2, 0) == -1)
607 TT_DIE(("Bind socket failed"));
609 /* NULL request test */
610 fd = http_connect("127.0.0.1", port);
611 tt_int_op(fd, >=, 0);
613 /* Stupid thing to send a request */
614 bev = bufferevent_socket_new(data->base, fd, 0);
615 bufferevent_setcb(bev, http_badreq_readcb, http_writecb,
616 http_badreq_errorcb, data->base);
617 bufferevent_enable(bev, EV_READ);
619 /* real NULL request */
622 bufferevent_write(bev, http_request, strlen(http_request));
624 shutdown(fd, SHUT_WR);
627 event_base_once(data->base, -1, EV_TIMEOUT, http_badreq_successcb, bev, &tv);
629 event_base_dispatch(data->base);
631 bufferevent_free(bev);
632 evutil_closesocket(fd);
635 fprintf(stdout, "FAILED\n");
639 /* Second answer (BAD REQUEST) on connection close */
641 /* connect to the second port */
642 fd = http_connect("127.0.0.1", port2);
644 /* Stupid thing to send a request */
645 bev = bufferevent_socket_new(data->base, fd, 0);
646 bufferevent_setcb(bev, http_badreq_readcb, http_writecb,
647 http_badreq_errorcb, data->base);
648 bufferevent_enable(bev, EV_READ);
650 /* first half of the http request */
652 "GET /badrequest HTTP/1.0\r\n" \
653 "Connection: Keep-Alive\r\n" \
656 bufferevent_write(bev, http_request, strlen(http_request));
660 event_base_once(data->base, -1, EV_TIMEOUT, http_badreq_successcb, bev, &tv);
662 event_base_dispatch(data->base);
664 tt_int_op(test_ok, ==, 2);
669 bufferevent_free(bev);
671 evutil_closesocket(fd);
674 static struct evhttp_connection *delayed_client;
677 http_large_delay_cb(struct evhttp_request *req, void *arg)
680 evutil_timerclear(&tv);
683 event_base_once(arg, -1, EV_TIMEOUT, http_delay_reply, req, &tv);
684 evhttp_connection_fail_(delayed_client, EVREQ_HTTP_EOF);
688 * HTTP DELETE test, just piggyback on the basic test
692 http_delete_cb(struct evhttp_request *req, void *arg)
694 struct evbuffer *evb = evbuffer_new();
695 int empty = evhttp_find_header(evhttp_request_get_input_headers(req), "Empty") != NULL;
697 /* Expecting a DELETE request */
698 if (evhttp_request_get_command(req) != EVHTTP_REQ_DELETE) {
699 fprintf(stdout, "FAILED (delete type)\n");
703 event_debug(("%s: called\n", __func__));
704 evbuffer_add_printf(evb, BASIC_REQUEST_BODY);
706 /* allow sending of an empty reply */
707 evhttp_send_reply(req, HTTP_OK, "Everything is fine",
708 !empty ? evb : NULL);
714 http_delete_test(void *arg)
716 struct basic_test_data *data = arg;
717 struct bufferevent *bev;
718 evutil_socket_t fd = -1;
719 const char *http_request;
720 ev_uint16_t port = 0;
724 http = http_setup(&port, data->base, 0);
727 fd = http_connect("127.0.0.1", port);
728 tt_int_op(fd, >=, 0);
730 /* Stupid thing to send a request */
731 bev = bufferevent_socket_new(data->base, fd, 0);
732 bufferevent_setcb(bev, http_readcb, http_writecb,
733 http_errorcb, data->base);
736 "DELETE /deleteit HTTP/1.1\r\n"
738 "Connection: close\r\n"
741 bufferevent_write(bev, http_request, strlen(http_request));
743 event_base_dispatch(data->base);
745 bufferevent_free(bev);
746 evutil_closesocket(fd);
751 tt_int_op(test_ok, ==, 2);
754 evutil_closesocket(fd);
758 http_sent_cb(struct evhttp_request *req, void *arg)
760 ev_uintptr_t val = (ev_uintptr_t)arg;
763 if (val != 0xDEADBEEF) {
764 fprintf(stdout, "FAILED on_complete_cb argument\n");
768 b = evhttp_request_get_output_buffer(req);
769 if (evbuffer_get_length(b) != 0) {
770 fprintf(stdout, "FAILED on_complete_cb output buffer not written\n");
774 event_debug(("%s: called\n", __func__));
780 http_on_complete_cb(struct evhttp_request *req, void *arg)
782 struct evbuffer *evb = evbuffer_new();
784 evhttp_request_set_on_complete_cb(req, http_sent_cb, (void *)0xDEADBEEF);
786 event_debug(("%s: called\n", __func__));
787 evbuffer_add_printf(evb, BASIC_REQUEST_BODY);
789 /* allow sending of an empty reply */
790 evhttp_send_reply(req, HTTP_OK, "Everything is fine", evb);
798 http_on_complete_test(void *arg)
800 struct basic_test_data *data = arg;
801 struct bufferevent *bev;
802 evutil_socket_t fd = -1;
803 const char *http_request;
804 ev_uint16_t port = 0;
808 http = http_setup(&port, data->base, 0);
810 fd = http_connect("127.0.0.1", port);
811 tt_int_op(fd, >=, 0);
813 /* Stupid thing to send a request */
814 bev = bufferevent_socket_new(data->base, fd, 0);
815 bufferevent_setcb(bev, http_readcb, http_writecb,
816 http_errorcb, data->base);
819 "GET /oncomplete HTTP/1.1\r\n"
821 "Connection: close\r\n"
824 bufferevent_write(bev, http_request, strlen(http_request));
826 event_base_dispatch(data->base);
828 bufferevent_free(bev);
832 tt_int_op(test_ok, ==, 4);
835 evutil_closesocket(fd);
839 http_allowed_methods_eventcb(struct bufferevent *bev, short what, void *arg)
842 if ((what & (BEV_EVENT_ERROR|BEV_EVENT_EOF))) {
845 n = evbuffer_remove(bufferevent_get_input(bev), buf,
851 *output = strdup(buf);
853 event_base_loopexit(exit_base, NULL);
858 http_allowed_methods_test(void *arg)
860 struct basic_test_data *data = arg;
861 struct bufferevent *bev1, *bev2, *bev3;
862 evutil_socket_t fd1=-1, fd2=-1, fd3=-1;
863 const char *http_request;
864 char *result1=NULL, *result2=NULL, *result3=NULL;
865 ev_uint16_t port = 0;
867 exit_base = data->base;
870 http = http_setup(&port, data->base, 0);
872 fd1 = http_connect("127.0.0.1", port);
873 tt_int_op(fd1, >=, 0);
875 /* GET is out; PATCH is in. */
876 evhttp_set_allowed_methods(http, EVHTTP_REQ_PATCH);
878 /* Stupid thing to send a request */
879 bev1 = bufferevent_socket_new(data->base, fd1, 0);
880 bufferevent_enable(bev1, EV_READ|EV_WRITE);
881 bufferevent_setcb(bev1, NULL, NULL,
882 http_allowed_methods_eventcb, &result1);
885 "GET /index.html HTTP/1.1\r\n"
887 "Connection: close\r\n"
890 bufferevent_write(bev1, http_request, strlen(http_request));
892 event_base_dispatch(data->base);
894 fd2 = http_connect("127.0.0.1", port);
895 tt_int_op(fd2, >=, 0);
897 bev2 = bufferevent_socket_new(data->base, fd2, 0);
898 bufferevent_enable(bev2, EV_READ|EV_WRITE);
899 bufferevent_setcb(bev2, NULL, NULL,
900 http_allowed_methods_eventcb, &result2);
903 "PATCH /test HTTP/1.1\r\n"
905 "Connection: close\r\n"
908 bufferevent_write(bev2, http_request, strlen(http_request));
910 event_base_dispatch(data->base);
912 fd3 = http_connect("127.0.0.1", port);
913 tt_int_op(fd3, >=, 0);
915 bev3 = bufferevent_socket_new(data->base, fd3, 0);
916 bufferevent_enable(bev3, EV_READ|EV_WRITE);
917 bufferevent_setcb(bev3, NULL, NULL,
918 http_allowed_methods_eventcb, &result3);
921 "FLOOP /test HTTP/1.1\r\n"
923 "Connection: close\r\n"
926 bufferevent_write(bev3, http_request, strlen(http_request));
928 event_base_dispatch(data->base);
930 bufferevent_free(bev1);
931 bufferevent_free(bev2);
932 bufferevent_free(bev3);
936 /* Method known but disallowed */
938 tt_assert(!strncmp(result1, "HTTP/1.1 501 ", strlen("HTTP/1.1 501 ")));
940 /* Method known and allowed */
942 tt_assert(!strncmp(result2, "HTTP/1.1 200 ", strlen("HTTP/1.1 200 ")));
946 tt_assert(!strncmp(result3, "HTTP/1.1 501 ", strlen("HTTP/1.1 501 ")));
956 evutil_closesocket(fd1);
958 evutil_closesocket(fd2);
960 evutil_closesocket(fd3);
963 static void http_request_done(struct evhttp_request *, void *);
964 static void http_request_empty_done(struct evhttp_request *, void *);
967 http_connection_test_(struct basic_test_data *data, int persistent,
968 const char *address, struct evdns_base *dnsbase, int ipv6, int family)
970 ev_uint16_t port = 0;
971 struct evhttp_connection *evcon = NULL;
972 struct evhttp_request *req = NULL;
976 http = http_setup(&port, data->base, ipv6);
982 evcon = evhttp_connection_base_new(data->base, dnsbase, address, port);
984 evhttp_connection_set_family(evcon, family);
986 tt_assert(evhttp_connection_get_base(evcon) == data->base);
988 exit_base = data->base;
990 tt_assert(evhttp_connection_get_server(evcon) == NULL);
993 * At this point, we want to schedule a request to the HTTP
994 * server using our make request method.
996 req = evhttp_request_new(http_request_done, (void*) BASIC_REQUEST_BODY);
998 /* Add the information that we care about */
999 evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
1001 /* We give ownership of the request to the connection */
1002 if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test") == -1) {
1003 fprintf(stdout, "FAILED\n");
1007 event_base_dispatch(data->base);
1011 /* try to make another request over the same connection */
1014 req = evhttp_request_new(http_request_done, (void*) BASIC_REQUEST_BODY);
1016 /* Add the information that we care about */
1017 evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
1020 * if our connections are not supposed to be persistent; request
1021 * a close from the server.
1024 evhttp_add_header(evhttp_request_get_output_headers(req), "Connection", "close");
1026 /* We give ownership of the request to the connection */
1027 if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test") == -1) {
1028 tt_abort_msg("couldn't make request");
1031 event_base_dispatch(data->base);
1033 /* make another request: request empty reply */
1036 req = evhttp_request_new(http_request_empty_done, data->base);
1038 /* Add the information that we care about */
1039 evhttp_add_header(evhttp_request_get_output_headers(req), "Empty", "itis");
1041 /* We give ownership of the request to the connection */
1042 if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test") == -1) {
1043 tt_abort_msg("Couldn't make request");
1046 event_base_dispatch(data->base);
1050 evhttp_connection_free(evcon);
1056 http_connection_test(void *arg)
1058 http_connection_test_(arg, 0, "127.0.0.1", NULL, 0, AF_UNSPEC);
1061 http_persist_connection_test(void *arg)
1063 http_connection_test_(arg, 1, "127.0.0.1", NULL, 0, AF_UNSPEC);
1066 static struct regress_dns_server_table search_table[] = {
1067 { "localhost", "A", "127.0.0.1", 0 },
1068 { NULL, NULL, NULL, 0 }
1072 http_connection_async_test(void *arg)
1074 struct basic_test_data *data = arg;
1075 ev_uint16_t port = 0;
1076 struct evhttp_connection *evcon = NULL;
1077 struct evhttp_request *req = NULL;
1078 struct evdns_base *dns_base = NULL;
1079 ev_uint16_t portnum = 0;
1082 exit_base = data->base;
1083 tt_assert(regress_dnsserver(data->base, &portnum, search_table));
1085 dns_base = evdns_base_new(data->base, 0/* init name servers */);
1086 tt_assert(dns_base);
1088 /* Add ourself as the only nameserver, and make sure we really are
1089 * the only nameserver. */
1090 evutil_snprintf(address, sizeof(address), "127.0.0.1:%d", portnum);
1091 evdns_base_nameserver_ip_add(dns_base, address);
1095 http = http_setup(&port, data->base, 0);
1097 evcon = evhttp_connection_base_new(data->base, dns_base, "127.0.0.1", port);
1101 * At this point, we want to schedule a request to the HTTP
1102 * server using our make request method.
1105 req = evhttp_request_new(http_request_done, (void*) BASIC_REQUEST_BODY);
1107 /* Add the information that we care about */
1108 evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
1110 /* We give ownership of the request to the connection */
1111 if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test") == -1) {
1112 fprintf(stdout, "FAILED\n");
1116 event_base_dispatch(data->base);
1120 /* try to make another request over the same connection */
1123 req = evhttp_request_new(http_request_done, (void*) BASIC_REQUEST_BODY);
1125 /* Add the information that we care about */
1126 evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
1129 * if our connections are not supposed to be persistent; request
1130 * a close from the server.
1132 evhttp_add_header(evhttp_request_get_output_headers(req), "Connection", "close");
1134 /* We give ownership of the request to the connection */
1135 if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test") == -1) {
1136 tt_abort_msg("couldn't make request");
1139 event_base_dispatch(data->base);
1141 /* make another request: request empty reply */
1144 req = evhttp_request_new(http_request_empty_done, data->base);
1146 /* Add the information that we care about */
1147 evhttp_add_header(evhttp_request_get_output_headers(req), "Empty", "itis");
1149 /* We give ownership of the request to the connection */
1150 if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test") == -1) {
1151 tt_abort_msg("Couldn't make request");
1154 event_base_dispatch(data->base);
1158 evhttp_connection_free(evcon);
1162 evdns_base_free(dns_base, 0);
1163 regress_clean_dnsserver();
1167 http_autofree_connection_test(void *arg)
1169 struct basic_test_data *data = arg;
1170 ev_uint16_t port = 0;
1171 struct evhttp_connection *evcon = NULL;
1172 struct evhttp_request *req[2] = { NULL };
1175 http = http_setup(&port, data->base, 0);
1177 evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port);
1181 * At this point, we want to schedule two request to the HTTP
1182 * server using our make request method.
1184 req[0] = evhttp_request_new(http_request_empty_done, data->base);
1185 req[1] = evhttp_request_new(http_request_empty_done, data->base);
1187 /* Add the information that we care about */
1188 evhttp_add_header(evhttp_request_get_output_headers(req[0]), "Host", "somehost");
1189 evhttp_add_header(evhttp_request_get_output_headers(req[0]), "Connection", "close");
1190 evhttp_add_header(evhttp_request_get_output_headers(req[0]), "Empty", "itis");
1191 evhttp_add_header(evhttp_request_get_output_headers(req[1]), "Host", "somehost");
1192 evhttp_add_header(evhttp_request_get_output_headers(req[1]), "Connection", "close");
1193 evhttp_add_header(evhttp_request_get_output_headers(req[1]), "Empty", "itis");
1195 /* We give ownership of the request to the connection */
1196 if (evhttp_make_request(evcon, req[0], EVHTTP_REQ_GET, "/test") == -1) {
1197 tt_abort_msg("couldn't make request");
1199 if (evhttp_make_request(evcon, req[1], EVHTTP_REQ_GET, "/test") == -1) {
1200 tt_abort_msg("couldn't make request");
1204 * Tell libevent to free the connection when the request completes
1205 * We then set the evcon pointer to NULL since we don't want to free it
1206 * when this function ends.
1208 evhttp_connection_free_on_completion(evcon);
1211 event_base_dispatch(data->base);
1213 /* at this point, the http server should have no connection */
1214 tt_assert(TAILQ_FIRST(&http->connections) == NULL);
1218 evhttp_connection_free(evcon);
1224 http_request_never_call(struct evhttp_request *req, void *arg)
1226 fprintf(stdout, "FAILED\n");
1231 http_do_cancel(evutil_socket_t fd, short what, void *arg)
1233 struct evhttp_request *req = arg;
1235 struct event_base *base;
1236 evutil_timerclear(&tv);
1238 tv.tv_usec = 500 * 1000;
1240 base = evhttp_connection_get_base(evhttp_request_get_connection(req));
1241 evhttp_cancel_request(req);
1243 event_base_loopexit(base, &tv);
1249 http_cancel_test(void *arg)
1251 struct basic_test_data *data = arg;
1252 ev_uint16_t port = 0;
1253 struct evhttp_connection *evcon = NULL;
1254 struct evhttp_request *req = NULL;
1257 exit_base = data->base;
1261 http = http_setup(&port, data->base, 0);
1263 evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port);
1267 * At this point, we want to schedule a request to the HTTP
1268 * server using our make request method.
1271 req = evhttp_request_new(http_request_never_call, NULL);
1272 evhttp_request_set_error_cb(req, http_request_error_cb_with_cancel_);
1274 /* Add the information that we care about */
1275 evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
1277 /* We give ownership of the request to the connection */
1278 tt_int_op(evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/delay"),
1281 evutil_timerclear(&tv);
1283 tv.tv_usec = 100 * 1000;
1285 event_base_once(data->base, -1, EV_TIMEOUT, http_do_cancel, req, &tv);
1287 event_base_dispatch(data->base);
1289 tt_int_op(test_ok, ==, 3);
1291 /* try to make another request over the same connection */
1294 req = evhttp_request_new(http_request_done, (void*) BASIC_REQUEST_BODY);
1296 /* Add the information that we care about */
1297 evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
1299 /* We give ownership of the request to the connection */
1300 tt_int_op(evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test"),
1303 event_base_dispatch(data->base);
1305 /* make another request: request empty reply */
1308 req = evhttp_request_new(http_request_empty_done, data->base);
1310 /* Add the information that we care about */
1311 evhttp_add_header(evhttp_request_get_output_headers(req), "Empty", "itis");
1313 /* We give ownership of the request to the connection */
1314 tt_int_op(evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test"),
1317 event_base_dispatch(data->base);
1321 evhttp_connection_free(evcon);
1327 http_request_done(struct evhttp_request *req, void *arg)
1329 const char *what = arg;
1331 if (evhttp_request_get_response_code(req) != HTTP_OK) {
1332 fprintf(stderr, "FAILED\n");
1336 if (evhttp_find_header(evhttp_request_get_input_headers(req), "Content-Type") == NULL) {
1337 fprintf(stderr, "FAILED\n");
1341 if (evbuffer_get_length(evhttp_request_get_input_buffer(req)) != strlen(what)) {
1342 fprintf(stderr, "FAILED\n");
1346 if (evbuffer_datacmp(evhttp_request_get_input_buffer(req), what) != 0) {
1347 fprintf(stderr, "FAILED\n");
1352 EVUTIL_ASSERT(exit_base);
1353 event_base_loopexit(exit_base, NULL);
1357 http_request_expect_error(struct evhttp_request *req, void *arg)
1359 if (evhttp_request_get_response_code(req) == HTTP_OK) {
1360 fprintf(stderr, "FAILED\n");
1366 event_base_loopexit(arg, NULL);
1369 /* test virtual hosts */
1371 http_virtual_host_test(void *arg)
1373 struct basic_test_data *data = arg;
1374 ev_uint16_t port = 0;
1375 struct evhttp_connection *evcon = NULL;
1376 struct evhttp_request *req = NULL;
1377 struct evhttp *second = NULL, *third = NULL;
1379 struct bufferevent *bev;
1380 const char *http_request;
1382 exit_base = data->base;
1384 http = http_setup(&port, data->base, 0);
1387 second = evhttp_new(NULL);
1388 evhttp_set_cb(second, "/funnybunny", http_basic_cb, NULL);
1389 third = evhttp_new(NULL);
1390 evhttp_set_cb(third, "/blackcoffee", http_basic_cb, NULL);
1392 if (evhttp_add_virtual_host(http, "foo.com", second) == -1) {
1393 tt_abort_msg("Couldn't add vhost");
1396 if (evhttp_add_virtual_host(http, "bar.*.foo.com", third) == -1) {
1397 tt_abort_msg("Couldn't add wildcarded vhost");
1400 /* add some aliases to the vhosts */
1401 tt_assert(evhttp_add_server_alias(second, "manolito.info") == 0);
1402 tt_assert(evhttp_add_server_alias(third, "bonkers.org") == 0);
1404 evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port);
1407 /* make a request with a different host and expect an error */
1408 req = evhttp_request_new(http_request_expect_error, data->base);
1410 /* Add the information that we care about */
1411 evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
1413 /* We give ownership of the request to the connection */
1414 if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET,
1415 "/funnybunny") == -1) {
1416 tt_abort_msg("Couldn't make request");
1419 event_base_dispatch(data->base);
1421 tt_assert(test_ok == 1);
1425 /* make a request with the right host and expect a response */
1426 req = evhttp_request_new(http_request_done, (void*) BASIC_REQUEST_BODY);
1428 /* Add the information that we care about */
1429 evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "foo.com");
1431 /* We give ownership of the request to the connection */
1432 if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET,
1433 "/funnybunny") == -1) {
1434 fprintf(stdout, "FAILED\n");
1438 event_base_dispatch(data->base);
1440 tt_assert(test_ok == 1);
1444 /* make a request with the right host and expect a response */
1445 req = evhttp_request_new(http_request_done, (void*) BASIC_REQUEST_BODY);
1447 /* Add the information that we care about */
1448 evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "bar.magic.foo.com");
1450 /* We give ownership of the request to the connection */
1451 if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET,
1452 "/blackcoffee") == -1) {
1453 tt_abort_msg("Couldn't make request");
1456 event_base_dispatch(data->base);
1458 tt_assert(test_ok == 1)
1462 /* make a request with the right host and expect a response */
1463 req = evhttp_request_new(http_request_done, (void*) BASIC_REQUEST_BODY);
1465 /* Add the information that we care about */
1466 evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "manolito.info");
1468 /* We give ownership of the request to the connection */
1469 if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET,
1470 "/funnybunny") == -1) {
1471 tt_abort_msg("Couldn't make request");
1474 event_base_dispatch(data->base);
1476 tt_assert(test_ok == 1)
1480 /* make a request with the right host and expect a response */
1481 req = evhttp_request_new(http_request_done, (void*) BASIC_REQUEST_BODY);
1483 /* Add the Host header. This time with the optional port. */
1484 evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "bonkers.org:8000");
1486 /* We give ownership of the request to the connection */
1487 if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET,
1488 "/blackcoffee") == -1) {
1489 tt_abort_msg("Couldn't make request");
1492 event_base_dispatch(data->base);
1494 tt_assert(test_ok == 1)
1498 /* Now make a raw request with an absolute URI. */
1499 fd = http_connect("127.0.0.1", port);
1501 /* Stupid thing to send a request */
1502 bev = bufferevent_socket_new(data->base, fd, 0);
1503 bufferevent_setcb(bev, http_readcb, http_writecb,
1504 http_errorcb, NULL);
1506 /* The host in the URI should override the Host: header */
1508 "GET http://manolito.info/funnybunny HTTP/1.1\r\n"
1509 "Host: somehost\r\n"
1510 "Connection: close\r\n"
1513 bufferevent_write(bev, http_request, strlen(http_request));
1515 event_base_dispatch(data->base);
1517 tt_int_op(test_ok, ==, 2);
1519 bufferevent_free(bev);
1520 evutil_closesocket(fd);
1524 evhttp_connection_free(evcon);
1530 /* test date header and content length */
1533 http_request_empty_done(struct evhttp_request *req, void *arg)
1535 if (evhttp_request_get_response_code(req) != HTTP_OK) {
1536 fprintf(stderr, "FAILED\n");
1540 if (evhttp_find_header(evhttp_request_get_input_headers(req), "Date") == NULL) {
1541 fprintf(stderr, "FAILED\n");
1546 if (evhttp_find_header(evhttp_request_get_input_headers(req), "Content-Length") == NULL) {
1547 fprintf(stderr, "FAILED\n");
1551 if (strcmp(evhttp_find_header(evhttp_request_get_input_headers(req), "Content-Length"),
1553 fprintf(stderr, "FAILED\n");
1557 if (evbuffer_get_length(evhttp_request_get_input_buffer(req)) != 0) {
1558 fprintf(stderr, "FAILED\n");
1564 event_base_loopexit(arg, NULL);
1568 * HTTP DISPATCHER test
1572 http_dispatcher_cb(struct evhttp_request *req, void *arg)
1575 struct evbuffer *evb = evbuffer_new();
1576 event_debug(("%s: called\n", __func__));
1577 evbuffer_add_printf(evb, "DISPATCHER_TEST");
1579 evhttp_send_reply(req, HTTP_OK, "Everything is fine", evb);
1585 http_dispatcher_test_done(struct evhttp_request *req, void *arg)
1587 struct event_base *base = arg;
1588 const char *what = "DISPATCHER_TEST";
1590 if (evhttp_request_get_response_code(req) != HTTP_OK) {
1591 fprintf(stderr, "FAILED\n");
1595 if (evhttp_find_header(evhttp_request_get_input_headers(req), "Content-Type") == NULL) {
1596 fprintf(stderr, "FAILED (content type)\n");
1600 if (evbuffer_get_length(evhttp_request_get_input_buffer(req)) != strlen(what)) {
1601 fprintf(stderr, "FAILED (length %lu vs %lu)\n",
1602 (unsigned long)evbuffer_get_length(evhttp_request_get_input_buffer(req)), (unsigned long)strlen(what));
1606 if (evbuffer_datacmp(evhttp_request_get_input_buffer(req), what) != 0) {
1607 fprintf(stderr, "FAILED (data)\n");
1612 event_base_loopexit(base, NULL);
1616 http_dispatcher_test(void *arg)
1618 struct basic_test_data *data = arg;
1619 ev_uint16_t port = 0;
1620 struct evhttp_connection *evcon = NULL;
1621 struct evhttp_request *req = NULL;
1625 http = http_setup(&port, data->base, 0);
1627 evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port);
1630 /* also bind to local host */
1631 evhttp_connection_set_local_address(evcon, "127.0.0.1");
1634 * At this point, we want to schedule an HTTP GET request
1635 * server using our make request method.
1638 req = evhttp_request_new(http_dispatcher_test_done, data->base);
1641 /* Add the information that we care about */
1642 evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
1644 if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/?arg=val") == -1) {
1645 tt_abort_msg("Couldn't make request");
1648 event_base_dispatch(data->base);
1652 evhttp_connection_free(evcon);
1661 void http_postrequest_done(struct evhttp_request *, void *);
1663 #define POST_DATA "Okay. Not really printf"
1666 http_post_test(void *arg)
1668 struct basic_test_data *data = arg;
1669 ev_uint16_t port = 0;
1670 struct evhttp_connection *evcon = NULL;
1671 struct evhttp_request *req = NULL;
1675 http = http_setup(&port, data->base, 0);
1677 evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port);
1681 * At this point, we want to schedule an HTTP POST request
1682 * server using our make request method.
1685 req = evhttp_request_new(http_postrequest_done, data->base);
1688 /* Add the information that we care about */
1689 evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
1690 evbuffer_add_printf(evhttp_request_get_output_buffer(req), POST_DATA);
1692 if (evhttp_make_request(evcon, req, EVHTTP_REQ_POST, "/postit") == -1) {
1693 tt_abort_msg("Couldn't make request");
1696 event_base_dispatch(data->base);
1698 tt_int_op(test_ok, ==, 1);
1702 req = evhttp_request_new(http_postrequest_done, data->base);
1705 /* Now try with 100-continue. */
1707 /* Add the information that we care about */
1708 evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
1709 evhttp_add_header(evhttp_request_get_output_headers(req), "Expect", "100-continue");
1710 evbuffer_add_printf(evhttp_request_get_output_buffer(req), POST_DATA);
1712 if (evhttp_make_request(evcon, req, EVHTTP_REQ_POST, "/postit") == -1) {
1713 tt_abort_msg("Couldn't make request");
1716 event_base_dispatch(data->base);
1718 tt_int_op(test_ok, ==, 1);
1720 evhttp_connection_free(evcon);
1728 http_post_cb(struct evhttp_request *req, void *arg)
1730 struct evbuffer *evb;
1731 event_debug(("%s: called\n", __func__));
1733 /* Yes, we are expecting a post request */
1734 if (evhttp_request_get_command(req) != EVHTTP_REQ_POST) {
1735 fprintf(stdout, "FAILED (post type)\n");
1739 if (evbuffer_get_length(evhttp_request_get_input_buffer(req)) != strlen(POST_DATA)) {
1740 fprintf(stdout, "FAILED (length: %lu vs %lu)\n",
1741 (unsigned long) evbuffer_get_length(evhttp_request_get_input_buffer(req)), (unsigned long) strlen(POST_DATA));
1745 if (evbuffer_datacmp(evhttp_request_get_input_buffer(req), POST_DATA) != 0) {
1746 fprintf(stdout, "FAILED (data)\n");
1747 fprintf(stdout, "Got :%s\n", evbuffer_pullup(evhttp_request_get_input_buffer(req),-1));
1748 fprintf(stdout, "Want:%s\n", POST_DATA);
1752 evb = evbuffer_new();
1753 evbuffer_add_printf(evb, BASIC_REQUEST_BODY);
1755 evhttp_send_reply(req, HTTP_OK, "Everything is fine", evb);
1761 http_postrequest_done(struct evhttp_request *req, void *arg)
1763 const char *what = BASIC_REQUEST_BODY;
1764 struct event_base *base = arg;
1767 fprintf(stderr, "FAILED (timeout)\n");
1771 if (evhttp_request_get_response_code(req) != HTTP_OK) {
1773 fprintf(stderr, "FAILED (response code)\n");
1777 if (evhttp_find_header(evhttp_request_get_input_headers(req), "Content-Type") == NULL) {
1778 fprintf(stderr, "FAILED (content type)\n");
1782 if (evbuffer_get_length(evhttp_request_get_input_buffer(req)) != strlen(what)) {
1783 fprintf(stderr, "FAILED (length %lu vs %lu)\n",
1784 (unsigned long)evbuffer_get_length(evhttp_request_get_input_buffer(req)), (unsigned long)strlen(what));
1788 if (evbuffer_datacmp(evhttp_request_get_input_buffer(req), what) != 0) {
1789 fprintf(stderr, "FAILED (data)\n");
1794 event_base_loopexit(base, NULL);
1798 * HTTP PUT test, basically just like POST, but ...
1801 void http_putrequest_done(struct evhttp_request *, void *);
1803 #define PUT_DATA "Hi, I'm some PUT data"
1806 http_put_test(void *arg)
1808 struct basic_test_data *data = arg;
1809 ev_uint16_t port = 0;
1810 struct evhttp_connection *evcon = NULL;
1811 struct evhttp_request *req = NULL;
1815 http = http_setup(&port, data->base, 0);
1817 evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port);
1821 * Schedule the HTTP PUT request
1824 req = evhttp_request_new(http_putrequest_done, data->base);
1827 /* Add the information that we care about */
1828 evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "someotherhost");
1829 evbuffer_add_printf(evhttp_request_get_output_buffer(req), PUT_DATA);
1831 if (evhttp_make_request(evcon, req, EVHTTP_REQ_PUT, "/putit") == -1) {
1832 tt_abort_msg("Couldn't make request");
1835 event_base_dispatch(data->base);
1837 evhttp_connection_free(evcon);
1840 tt_int_op(test_ok, ==, 1);
1846 http_put_cb(struct evhttp_request *req, void *arg)
1848 struct evbuffer *evb;
1849 event_debug(("%s: called\n", __func__));
1851 /* Expecting a PUT request */
1852 if (evhttp_request_get_command(req) != EVHTTP_REQ_PUT) {
1853 fprintf(stdout, "FAILED (put type)\n");
1857 if (evbuffer_get_length(evhttp_request_get_input_buffer(req)) != strlen(PUT_DATA)) {
1858 fprintf(stdout, "FAILED (length: %lu vs %lu)\n",
1859 (unsigned long)evbuffer_get_length(evhttp_request_get_input_buffer(req)), (unsigned long)strlen(PUT_DATA));
1863 if (evbuffer_datacmp(evhttp_request_get_input_buffer(req), PUT_DATA) != 0) {
1864 fprintf(stdout, "FAILED (data)\n");
1865 fprintf(stdout, "Got :%s\n", evbuffer_pullup(evhttp_request_get_input_buffer(req),-1));
1866 fprintf(stdout, "Want:%s\n", PUT_DATA);
1870 evb = evbuffer_new();
1871 evbuffer_add_printf(evb, "That ain't funny");
1873 evhttp_send_reply(req, HTTP_OK, "Everything is great", evb);
1879 http_putrequest_done(struct evhttp_request *req, void *arg)
1881 struct event_base *base = arg;
1882 const char *what = "That ain't funny";
1885 fprintf(stderr, "FAILED (timeout)\n");
1889 if (evhttp_request_get_response_code(req) != HTTP_OK) {
1891 fprintf(stderr, "FAILED (response code)\n");
1895 if (evhttp_find_header(evhttp_request_get_input_headers(req), "Content-Type") == NULL) {
1896 fprintf(stderr, "FAILED (content type)\n");
1900 if (evbuffer_get_length(evhttp_request_get_input_buffer(req)) != strlen(what)) {
1901 fprintf(stderr, "FAILED (length %lu vs %lu)\n",
1902 (unsigned long)evbuffer_get_length(evhttp_request_get_input_buffer(req)), (unsigned long)strlen(what));
1907 if (evbuffer_datacmp(evhttp_request_get_input_buffer(req), what) != 0) {
1908 fprintf(stderr, "FAILED (data)\n");
1913 event_base_loopexit(base, NULL);
1917 http_failure_readcb(struct bufferevent *bev, void *arg)
1919 const char *what = "400 Bad Request";
1920 if (evbuffer_contains(bufferevent_get_input(bev), what)) {
1922 bufferevent_disable(bev, EV_READ);
1923 event_base_loopexit(arg, NULL);
1928 * Testing that the HTTP server can deal with a malformed request.
1931 http_failure_test(void *arg)
1933 struct basic_test_data *data = arg;
1934 struct bufferevent *bev;
1935 evutil_socket_t fd = -1;
1936 const char *http_request;
1937 ev_uint16_t port = 0;
1941 http = http_setup(&port, data->base, 0);
1943 fd = http_connect("127.0.0.1", port);
1944 tt_int_op(fd, >=, 0);
1946 /* Stupid thing to send a request */
1947 bev = bufferevent_socket_new(data->base, fd, 0);
1948 bufferevent_setcb(bev, http_failure_readcb, http_writecb,
1949 http_errorcb, data->base);
1951 http_request = "illegal request\r\n";
1953 bufferevent_write(bev, http_request, strlen(http_request));
1955 event_base_dispatch(data->base);
1957 bufferevent_free(bev);
1961 tt_int_op(test_ok, ==, 2);
1964 evutil_closesocket(fd);
1968 close_detect_done(struct evhttp_request *req, void *arg)
1972 tt_assert(evhttp_request_get_response_code(req) == HTTP_OK);
1977 evutil_timerclear(&tv);
1978 tv.tv_usec = 150000;
1979 event_base_loopexit(arg, &tv);
1983 close_detect_launch(evutil_socket_t fd, short what, void *arg)
1985 struct evhttp_connection *evcon = arg;
1986 struct event_base *base = evhttp_connection_get_base(evcon);
1987 struct evhttp_request *req;
1989 req = evhttp_request_new(close_detect_done, base);
1991 /* Add the information that we care about */
1992 evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
1994 /* We give ownership of the request to the connection */
1995 if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test") == -1) {
1996 tt_fail_msg("Couldn't make request");
2001 close_detect_cb(struct evhttp_request *req, void *arg)
2003 struct evhttp_connection *evcon = arg;
2004 struct event_base *base = evhttp_connection_get_base(evcon);
2007 if (req != NULL && evhttp_request_get_response_code(req) != HTTP_OK) {
2008 tt_abort_msg("Failed");
2011 evutil_timerclear(&tv);
2012 tv.tv_sec = 0; /* longer than the http time out */
2013 tv.tv_usec = 600000; /* longer than the http time out */
2015 /* launch a new request on the persistent connection in .3 seconds */
2016 event_base_once(base, -1, EV_TIMEOUT, close_detect_launch, evcon, &tv);
2023 http_close_detection_(struct basic_test_data *data, int with_delay)
2025 ev_uint16_t port = 0;
2026 struct evhttp_connection *evcon = NULL;
2027 struct evhttp_request *req = NULL;
2028 const struct timeval sec_tenth = { 0, 100000 };
2031 http = http_setup(&port, data->base, 0);
2033 /* .1 second timeout */
2034 evhttp_set_timeout_tv(http, &sec_tenth);
2036 evcon = evhttp_connection_base_new(data->base, NULL,
2039 evhttp_connection_set_timeout_tv(evcon, &sec_tenth);
2043 delayed_client = evcon;
2046 * At this point, we want to schedule a request to the HTTP
2047 * server using our make request method.
2050 req = evhttp_request_new(close_detect_cb, evcon);
2052 /* Add the information that we care about */
2053 evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
2055 /* We give ownership of the request to the connection */
2056 if (evhttp_make_request(evcon,
2057 req, EVHTTP_REQ_GET, with_delay ? "/largedelay" : "/test") == -1) {
2058 tt_abort_msg("couldn't make request");
2061 event_base_dispatch(data->base);
2063 /* at this point, the http server should have no connection */
2064 tt_assert(TAILQ_FIRST(&http->connections) == NULL);
2068 evhttp_connection_free(evcon);
2073 http_close_detection_test(void *arg)
2075 http_close_detection_(arg, 0);
2078 http_close_detection_delay_test(void *arg)
2080 http_close_detection_(arg, 1);
2084 http_highport_test(void *arg)
2086 struct basic_test_data *data = arg;
2088 struct evhttp *myhttp = NULL;
2090 /* Try a few different ports */
2091 for (i = 0; i < 50; ++i) {
2092 myhttp = evhttp_new(data->base);
2093 if (evhttp_bind_socket(myhttp, "127.0.0.1", 65535 - i) == 0) {
2095 evhttp_free(myhttp);
2098 evhttp_free(myhttp);
2101 tt_fail_msg("Couldn't get a high port");
2105 http_bad_header_test(void *ptr)
2107 struct evkeyvalq headers;
2109 TAILQ_INIT(&headers);
2111 tt_want(evhttp_add_header(&headers, "One", "Two") == 0);
2112 tt_want(evhttp_add_header(&headers, "One", "Two\r\n Three") == 0);
2113 tt_want(evhttp_add_header(&headers, "One\r", "Two") == -1);
2114 tt_want(evhttp_add_header(&headers, "One\n", "Two") == -1);
2115 tt_want(evhttp_add_header(&headers, "One", "Two\r") == -1);
2116 tt_want(evhttp_add_header(&headers, "One", "Two\n") == -1);
2118 evhttp_clear_headers(&headers);
2121 static int validate_header(
2122 const struct evkeyvalq* headers,
2123 const char *key, const char *value)
2125 const char *real_val = evhttp_find_header(headers, key);
2126 tt_assert(real_val != NULL);
2127 tt_want(strcmp(real_val, value) == 0);
2133 http_parse_query_test(void *ptr)
2135 struct evkeyvalq headers;
2138 TAILQ_INIT(&headers);
2140 r = evhttp_parse_query("http://www.test.com/?q=test", &headers);
2141 tt_want(validate_header(&headers, "q", "test") == 0);
2142 tt_int_op(r, ==, 0);
2143 evhttp_clear_headers(&headers);
2145 r = evhttp_parse_query("http://www.test.com/?q=test&foo=bar", &headers);
2146 tt_want(validate_header(&headers, "q", "test") == 0);
2147 tt_want(validate_header(&headers, "foo", "bar") == 0);
2148 tt_int_op(r, ==, 0);
2149 evhttp_clear_headers(&headers);
2151 r = evhttp_parse_query("http://www.test.com/?q=test+foo", &headers);
2152 tt_want(validate_header(&headers, "q", "test foo") == 0);
2153 tt_int_op(r, ==, 0);
2154 evhttp_clear_headers(&headers);
2156 r = evhttp_parse_query("http://www.test.com/?q=test%0Afoo", &headers);
2157 tt_want(validate_header(&headers, "q", "test\nfoo") == 0);
2158 tt_int_op(r, ==, 0);
2159 evhttp_clear_headers(&headers);
2161 r = evhttp_parse_query("http://www.test.com/?q=test%0Dfoo", &headers);
2162 tt_want(validate_header(&headers, "q", "test\rfoo") == 0);
2163 tt_int_op(r, ==, 0);
2164 evhttp_clear_headers(&headers);
2166 r = evhttp_parse_query("http://www.test.com/?q=test&&q2", &headers);
2167 tt_int_op(r, ==, -1);
2168 evhttp_clear_headers(&headers);
2170 r = evhttp_parse_query("http://www.test.com/?q=test+this", &headers);
2171 tt_want(validate_header(&headers, "q", "test this") == 0);
2172 tt_int_op(r, ==, 0);
2173 evhttp_clear_headers(&headers);
2175 r = evhttp_parse_query("http://www.test.com/?q=test&q2=foo", &headers);
2176 tt_int_op(r, ==, 0);
2177 tt_want(validate_header(&headers, "q", "test") == 0);
2178 tt_want(validate_header(&headers, "q2", "foo") == 0);
2179 evhttp_clear_headers(&headers);
2181 r = evhttp_parse_query("http://www.test.com/?q&q2=foo", &headers);
2182 tt_int_op(r, ==, -1);
2183 evhttp_clear_headers(&headers);
2185 r = evhttp_parse_query("http://www.test.com/?q=foo&q2", &headers);
2186 tt_int_op(r, ==, -1);
2187 evhttp_clear_headers(&headers);
2189 r = evhttp_parse_query("http://www.test.com/?q=foo&q2&q3=x", &headers);
2190 tt_int_op(r, ==, -1);
2191 evhttp_clear_headers(&headers);
2193 r = evhttp_parse_query("http://www.test.com/?q=&q2=&q3=", &headers);
2194 tt_int_op(r, ==, 0);
2195 tt_want(validate_header(&headers, "q", "") == 0);
2196 tt_want(validate_header(&headers, "q2", "") == 0);
2197 tt_want(validate_header(&headers, "q3", "") == 0);
2198 evhttp_clear_headers(&headers);
2201 evhttp_clear_headers(&headers);
2205 http_parse_uri_test(void *ptr)
2207 const int nonconform = (ptr != NULL);
2208 const unsigned parse_flags =
2209 nonconform ? EVHTTP_URI_NONCONFORMANT : 0;
2210 struct evhttp_uri *uri = NULL;
2212 #define URI_PARSE(uri) \
2213 evhttp_uri_parse_with_flags((uri), parse_flags)
2215 #define TT_URI(want) do { \
2216 char *ret = evhttp_uri_join(uri, url_tmp, sizeof(url_tmp)); \
2217 tt_want(ret != NULL); \
2218 tt_want(ret == url_tmp); \
2219 if (strcmp(ret,want) != 0) \
2220 TT_FAIL(("\"%s\" != \"%s\"",ret,want)); \
2223 tt_want(evhttp_uri_join(NULL, 0, 0) == NULL);
2224 tt_want(evhttp_uri_join(NULL, url_tmp, 0) == NULL);
2225 tt_want(evhttp_uri_join(NULL, url_tmp, sizeof(url_tmp)) == NULL);
2227 /* bad URIs: parsing */
2228 #define BAD(s) do { \
2229 if (URI_PARSE(s) != NULL) \
2230 TT_FAIL(("Expected error parsing \"%s\"",s)); \
2232 /* Nonconformant URIs we can parse: parsing */
2233 #define NCF(s) do { \
2234 uri = URI_PARSE(s); \
2235 if (uri != NULL && !nonconform) { \
2236 TT_FAIL(("Expected error parsing \"%s\"",s)); \
2237 } else if (uri == NULL && nonconform) { \
2238 TT_FAIL(("Couldn't parse nonconformant URI \"%s\"", \
2242 tt_want(evhttp_uri_join(uri, url_tmp, \
2243 sizeof(url_tmp))); \
2244 evhttp_uri_free(uri); \
2248 NCF("http://www.test.com/ why hello");
2249 NCF("http://www.test.com/why-hello\x01");
2250 NCF("http://www.test.com/why-hello?\x01");
2251 NCF("http://www.test.com/why-hello#\x01");
2252 BAD("http://www.\x01.test.com/why-hello");
2253 BAD("http://www.%7test.com/why-hello");
2254 NCF("http://www.test.com/why-hell%7o");
2255 BAD("h%3ttp://www.test.com/why-hello");
2256 NCF("http://www.test.com/why-hello%7");
2257 NCF("http://www.test.com/why-hell%7o");
2258 NCF("http://www.test.com/foo?ba%r");
2259 NCF("http://www.test.com/foo#ba%r");
2261 BAD("http://www.test.com:999x/");
2262 BAD("http://www.test.com:x/");
2263 BAD("http://[hello-there]/");
2264 BAD("http://[::1]]/");
2265 BAD("http://[::1/");
2266 BAD("http://[foob/");
2268 BAD("http://[ffff:ffff:ffff:ffff:Ffff:ffff:ffff:"
2269 "ffff:ffff:ffff:ffff:ffff:ffff:ffff]/");
2270 BAD("http://[vX.foo]/");
2271 BAD("http://[vX.foo]/");
2272 BAD("http://[v.foo]/");
2273 BAD("http://[v5.fo%o]/");
2274 BAD("http://[v5X]/");
2275 BAD("http://[v5]/");
2277 BAD("http://f\x01red@www.example.com/");
2278 BAD("http://f%0red@www.example.com/");
2279 BAD("http://www.example.com:9999999999999999999999999999999999999/");
2280 BAD("http://www.example.com:hihi/");
2281 BAD("://www.example.com/");
2283 /* bad URIs: joining */
2284 uri = evhttp_uri_new();
2285 tt_want(0==evhttp_uri_set_host(uri, "www.example.com"));
2286 tt_want(evhttp_uri_join(uri, url_tmp, sizeof(url_tmp)) != NULL);
2287 /* not enough space: */
2288 tt_want(evhttp_uri_join(uri, url_tmp, 3) == NULL);
2289 /* host is set, but path doesn't start with "/": */
2290 tt_want(0==evhttp_uri_set_path(uri, "hi_mom"));
2291 tt_want(evhttp_uri_join(uri, url_tmp, sizeof(url_tmp)) == NULL);
2292 tt_want(evhttp_uri_join(uri, NULL, sizeof(url_tmp))==NULL);
2293 tt_want(evhttp_uri_join(uri, url_tmp, 0)==NULL);
2294 evhttp_uri_free(uri);
2295 uri = URI_PARSE("mailto:foo@bar");
2296 tt_want(uri != NULL);
2297 tt_want(evhttp_uri_get_host(uri) == NULL);
2298 tt_want(evhttp_uri_get_userinfo(uri) == NULL);
2299 tt_want(evhttp_uri_get_port(uri) == -1);
2300 tt_want(!strcmp(evhttp_uri_get_scheme(uri), "mailto"));
2301 tt_want(!strcmp(evhttp_uri_get_path(uri), "foo@bar"));
2302 tt_want(evhttp_uri_get_query(uri) == NULL);
2303 tt_want(evhttp_uri_get_fragment(uri) == NULL);
2304 TT_URI("mailto:foo@bar");
2305 evhttp_uri_free(uri);
2307 uri = evhttp_uri_new();
2308 /* Bad URI usage: setting invalid values */
2309 tt_want(-1 == evhttp_uri_set_scheme(uri,""));
2310 tt_want(-1 == evhttp_uri_set_scheme(uri,"33"));
2311 tt_want(-1 == evhttp_uri_set_scheme(uri,"hi!"));
2312 tt_want(-1 == evhttp_uri_set_userinfo(uri,"hello@"));
2313 tt_want(-1 == evhttp_uri_set_host(uri,"[1.2.3.4]"));
2314 tt_want(-1 == evhttp_uri_set_host(uri,"["));
2315 tt_want(-1 == evhttp_uri_set_host(uri,"www.[foo].com"));
2316 tt_want(-1 == evhttp_uri_set_port(uri,-3));
2317 tt_want(-1 == evhttp_uri_set_path(uri,"hello?world"));
2318 tt_want(-1 == evhttp_uri_set_query(uri,"hello#world"));
2319 tt_want(-1 == evhttp_uri_set_fragment(uri,"hello#world"));
2320 /* Valid URI usage: setting valid values */
2321 tt_want(0 == evhttp_uri_set_scheme(uri,"http"));
2322 tt_want(0 == evhttp_uri_set_scheme(uri,NULL));
2323 tt_want(0 == evhttp_uri_set_userinfo(uri,"username:pass"));
2324 tt_want(0 == evhttp_uri_set_userinfo(uri,NULL));
2325 tt_want(0 == evhttp_uri_set_host(uri,"www.example.com"));
2326 tt_want(0 == evhttp_uri_set_host(uri,"1.2.3.4"));
2327 tt_want(0 == evhttp_uri_set_host(uri,"[1:2:3:4::]"));
2328 tt_want(0 == evhttp_uri_set_host(uri,"[v7.wobblewobble]"));
2329 tt_want(0 == evhttp_uri_set_host(uri,NULL));
2330 tt_want(0 == evhttp_uri_set_host(uri,""));
2331 tt_want(0 == evhttp_uri_set_port(uri, -1));
2332 tt_want(0 == evhttp_uri_set_port(uri, 80));
2333 tt_want(0 == evhttp_uri_set_port(uri, 65535));
2334 tt_want(0 == evhttp_uri_set_path(uri, ""));
2335 tt_want(0 == evhttp_uri_set_path(uri, "/documents/public/index.html"));
2336 tt_want(0 == evhttp_uri_set_path(uri, NULL));
2337 tt_want(0 == evhttp_uri_set_query(uri, "key=val&key2=val2"));
2338 tt_want(0 == evhttp_uri_set_query(uri, "keyvalblarg"));
2339 tt_want(0 == evhttp_uri_set_query(uri, ""));
2340 tt_want(0 == evhttp_uri_set_query(uri, NULL));
2341 tt_want(0 == evhttp_uri_set_fragment(uri, ""));
2342 tt_want(0 == evhttp_uri_set_fragment(uri, "here?i?am"));
2343 tt_want(0 == evhttp_uri_set_fragment(uri, NULL));
2344 evhttp_uri_free(uri);
2347 uri = URI_PARSE("http://www.test.com/?q=t%33est");
2348 tt_want(strcmp(evhttp_uri_get_scheme(uri), "http") == 0);
2349 tt_want(strcmp(evhttp_uri_get_host(uri), "www.test.com") == 0);
2350 tt_want(strcmp(evhttp_uri_get_path(uri), "/") == 0);
2351 tt_want(strcmp(evhttp_uri_get_query(uri), "q=t%33est") == 0);
2352 tt_want(evhttp_uri_get_userinfo(uri) == NULL);
2353 tt_want(evhttp_uri_get_port(uri) == -1);
2354 tt_want(evhttp_uri_get_fragment(uri) == NULL);
2355 TT_URI("http://www.test.com/?q=t%33est");
2356 evhttp_uri_free(uri);
2358 uri = URI_PARSE("http://%77ww.test.com");
2359 tt_want(strcmp(evhttp_uri_get_scheme(uri), "http") == 0);
2360 tt_want(strcmp(evhttp_uri_get_host(uri), "%77ww.test.com") == 0);
2361 tt_want(strcmp(evhttp_uri_get_path(uri), "") == 0);
2362 tt_want(evhttp_uri_get_query(uri) == NULL);
2363 tt_want(evhttp_uri_get_userinfo(uri) == NULL);
2364 tt_want(evhttp_uri_get_port(uri) == -1);
2365 tt_want(evhttp_uri_get_fragment(uri) == NULL);
2366 TT_URI("http://%77ww.test.com");
2367 evhttp_uri_free(uri);
2369 uri = URI_PARSE("http://www.test.com?q=test");
2370 tt_want(strcmp(evhttp_uri_get_scheme(uri), "http") == 0);
2371 tt_want(strcmp(evhttp_uri_get_host(uri), "www.test.com") == 0);
2372 tt_want(strcmp(evhttp_uri_get_path(uri), "") == 0);
2373 tt_want(strcmp(evhttp_uri_get_query(uri), "q=test") == 0);
2374 tt_want(evhttp_uri_get_userinfo(uri) == NULL);
2375 tt_want(evhttp_uri_get_port(uri) == -1);
2376 tt_want(evhttp_uri_get_fragment(uri) == NULL);
2377 TT_URI("http://www.test.com?q=test");
2378 evhttp_uri_free(uri);
2380 uri = URI_PARSE("http://www.test.com#fragment");
2381 tt_want(strcmp(evhttp_uri_get_scheme(uri), "http") == 0);
2382 tt_want(strcmp(evhttp_uri_get_host(uri), "www.test.com") == 0);
2383 tt_want(strcmp(evhttp_uri_get_path(uri), "") == 0);
2384 tt_want(evhttp_uri_get_query(uri) == NULL);
2385 tt_want(evhttp_uri_get_userinfo(uri) == NULL);
2386 tt_want(evhttp_uri_get_port(uri) == -1);
2387 tt_want_str_op(evhttp_uri_get_fragment(uri), ==, "fragment");
2388 TT_URI("http://www.test.com#fragment");
2389 evhttp_uri_free(uri);
2391 uri = URI_PARSE("http://8000/");
2392 tt_want(strcmp(evhttp_uri_get_scheme(uri), "http") == 0);
2393 tt_want(strcmp(evhttp_uri_get_host(uri), "8000") == 0);
2394 tt_want(strcmp(evhttp_uri_get_path(uri), "/") == 0);
2395 tt_want(evhttp_uri_get_query(uri) == NULL);
2396 tt_want(evhttp_uri_get_userinfo(uri) == NULL);
2397 tt_want(evhttp_uri_get_port(uri) == -1);
2398 tt_want(evhttp_uri_get_fragment(uri) == NULL);
2399 TT_URI("http://8000/");
2400 evhttp_uri_free(uri);
2402 uri = URI_PARSE("http://:8000/");
2403 tt_want(strcmp(evhttp_uri_get_scheme(uri), "http") == 0);
2404 tt_want(strcmp(evhttp_uri_get_host(uri), "") == 0);
2405 tt_want(strcmp(evhttp_uri_get_path(uri), "/") == 0);
2406 tt_want(evhttp_uri_get_query(uri) == NULL);
2407 tt_want(evhttp_uri_get_userinfo(uri) == NULL);
2408 tt_want(evhttp_uri_get_port(uri) == 8000);
2409 tt_want(evhttp_uri_get_fragment(uri) == NULL);
2410 TT_URI("http://:8000/");
2411 evhttp_uri_free(uri);
2413 uri = URI_PARSE("http://www.test.com:/"); /* empty port */
2414 tt_want(strcmp(evhttp_uri_get_scheme(uri), "http") == 0);
2415 tt_want(strcmp(evhttp_uri_get_host(uri), "www.test.com") == 0);
2416 tt_want_str_op(evhttp_uri_get_path(uri), ==, "/");
2417 tt_want(evhttp_uri_get_query(uri) == NULL);
2418 tt_want(evhttp_uri_get_userinfo(uri) == NULL);
2419 tt_want(evhttp_uri_get_port(uri) == -1);
2420 tt_want(evhttp_uri_get_fragment(uri) == NULL);
2421 TT_URI("http://www.test.com/");
2422 evhttp_uri_free(uri);
2424 uri = URI_PARSE("http://www.test.com:"); /* empty port 2 */
2425 tt_want(strcmp(evhttp_uri_get_scheme(uri), "http") == 0);
2426 tt_want(strcmp(evhttp_uri_get_host(uri), "www.test.com") == 0);
2427 tt_want(strcmp(evhttp_uri_get_path(uri), "") == 0);
2428 tt_want(evhttp_uri_get_query(uri) == NULL);
2429 tt_want(evhttp_uri_get_userinfo(uri) == NULL);
2430 tt_want(evhttp_uri_get_port(uri) == -1);
2431 tt_want(evhttp_uri_get_fragment(uri) == NULL);
2432 TT_URI("http://www.test.com");
2433 evhttp_uri_free(uri);
2435 uri = URI_PARSE("ftp://www.test.com/?q=test");
2436 tt_want(strcmp(evhttp_uri_get_scheme(uri), "ftp") == 0);
2437 tt_want(strcmp(evhttp_uri_get_host(uri), "www.test.com") == 0);
2438 tt_want(strcmp(evhttp_uri_get_path(uri), "/") == 0);
2439 tt_want(strcmp(evhttp_uri_get_query(uri), "q=test") == 0);
2440 tt_want(evhttp_uri_get_userinfo(uri) == NULL);
2441 tt_want(evhttp_uri_get_port(uri) == -1);
2442 tt_want(evhttp_uri_get_fragment(uri) == NULL);
2443 TT_URI("ftp://www.test.com/?q=test");
2444 evhttp_uri_free(uri);
2446 uri = URI_PARSE("ftp://[::1]:999/?q=test");
2447 tt_want(strcmp(evhttp_uri_get_scheme(uri), "ftp") == 0);
2448 tt_want(strcmp(evhttp_uri_get_host(uri), "[::1]") == 0);
2449 tt_want(strcmp(evhttp_uri_get_path(uri), "/") == 0);
2450 tt_want(strcmp(evhttp_uri_get_query(uri), "q=test") == 0);
2451 tt_want(evhttp_uri_get_userinfo(uri) == NULL);
2452 tt_want(evhttp_uri_get_port(uri) == 999);
2453 tt_want(evhttp_uri_get_fragment(uri) == NULL);
2454 TT_URI("ftp://[::1]:999/?q=test");
2455 evhttp_uri_free(uri);
2457 uri = URI_PARSE("ftp://[ff00::127.0.0.1]/?q=test");
2458 tt_want(strcmp(evhttp_uri_get_scheme(uri), "ftp") == 0);
2459 tt_want(strcmp(evhttp_uri_get_host(uri), "[ff00::127.0.0.1]") == 0);
2460 tt_want(strcmp(evhttp_uri_get_path(uri), "/") == 0);
2461 tt_want(strcmp(evhttp_uri_get_query(uri), "q=test") == 0);
2462 tt_want(evhttp_uri_get_userinfo(uri) == NULL);
2463 tt_want(evhttp_uri_get_port(uri) == -1);
2464 tt_want(evhttp_uri_get_fragment(uri) == NULL);
2465 TT_URI("ftp://[ff00::127.0.0.1]/?q=test");
2466 evhttp_uri_free(uri);
2468 uri = URI_PARSE("ftp://[v99.not_(any:time)_soon]/?q=test");
2469 tt_want(strcmp(evhttp_uri_get_scheme(uri), "ftp") == 0);
2470 tt_want(strcmp(evhttp_uri_get_host(uri), "[v99.not_(any:time)_soon]") == 0);
2471 tt_want(strcmp(evhttp_uri_get_path(uri), "/") == 0);
2472 tt_want(strcmp(evhttp_uri_get_query(uri), "q=test") == 0);
2473 tt_want(evhttp_uri_get_userinfo(uri) == NULL);
2474 tt_want(evhttp_uri_get_port(uri) == -1);
2475 tt_want(evhttp_uri_get_fragment(uri) == NULL);
2476 TT_URI("ftp://[v99.not_(any:time)_soon]/?q=test");
2477 evhttp_uri_free(uri);
2479 uri = URI_PARSE("scheme://user:pass@foo.com:42/?q=test&s=some+thing#fragment");
2480 tt_want(strcmp(evhttp_uri_get_scheme(uri), "scheme") == 0);
2481 tt_want(strcmp(evhttp_uri_get_userinfo(uri), "user:pass") == 0);
2482 tt_want(strcmp(evhttp_uri_get_host(uri), "foo.com") == 0);
2483 tt_want(evhttp_uri_get_port(uri) == 42);
2484 tt_want(strcmp(evhttp_uri_get_path(uri), "/") == 0);
2485 tt_want(strcmp(evhttp_uri_get_query(uri), "q=test&s=some+thing") == 0);
2486 tt_want(strcmp(evhttp_uri_get_fragment(uri), "fragment") == 0);
2487 TT_URI("scheme://user:pass@foo.com:42/?q=test&s=some+thing#fragment");
2488 evhttp_uri_free(uri);
2490 uri = URI_PARSE("scheme://user@foo.com/#fragment");
2491 tt_want(strcmp(evhttp_uri_get_scheme(uri), "scheme") == 0);
2492 tt_want(strcmp(evhttp_uri_get_userinfo(uri), "user") == 0);
2493 tt_want(strcmp(evhttp_uri_get_host(uri), "foo.com") == 0);
2494 tt_want(evhttp_uri_get_port(uri) == -1);
2495 tt_want(strcmp(evhttp_uri_get_path(uri), "/") == 0);
2496 tt_want(evhttp_uri_get_query(uri) == NULL);
2497 tt_want(strcmp(evhttp_uri_get_fragment(uri), "fragment") == 0);
2498 TT_URI("scheme://user@foo.com/#fragment");
2499 evhttp_uri_free(uri);
2501 uri = URI_PARSE("scheme://%75ser@foo.com/#frag@ment");
2502 tt_want(strcmp(evhttp_uri_get_scheme(uri), "scheme") == 0);
2503 tt_want(strcmp(evhttp_uri_get_userinfo(uri), "%75ser") == 0);
2504 tt_want(strcmp(evhttp_uri_get_host(uri), "foo.com") == 0);
2505 tt_want(evhttp_uri_get_port(uri) == -1);
2506 tt_want(strcmp(evhttp_uri_get_path(uri), "/") == 0);
2507 tt_want(evhttp_uri_get_query(uri) == NULL);
2508 tt_want(strcmp(evhttp_uri_get_fragment(uri), "frag@ment") == 0);
2509 TT_URI("scheme://%75ser@foo.com/#frag@ment");
2510 evhttp_uri_free(uri);
2512 uri = URI_PARSE("file:///some/path/to/the/file");
2513 tt_want(strcmp(evhttp_uri_get_scheme(uri), "file") == 0);
2514 tt_want(evhttp_uri_get_userinfo(uri) == NULL);
2515 tt_want(strcmp(evhttp_uri_get_host(uri), "") == 0);
2516 tt_want(evhttp_uri_get_port(uri) == -1);
2517 tt_want(strcmp(evhttp_uri_get_path(uri), "/some/path/to/the/file") == 0);
2518 tt_want(evhttp_uri_get_query(uri) == NULL);
2519 tt_want(evhttp_uri_get_fragment(uri) == NULL);
2520 TT_URI("file:///some/path/to/the/file");
2521 evhttp_uri_free(uri);
2523 uri = URI_PARSE("///some/path/to/the-file");
2524 tt_want(uri != NULL);
2525 tt_want(evhttp_uri_get_scheme(uri) == NULL);
2526 tt_want(evhttp_uri_get_userinfo(uri) == NULL);
2527 tt_want(strcmp(evhttp_uri_get_host(uri), "") == 0);
2528 tt_want(evhttp_uri_get_port(uri) == -1);
2529 tt_want(strcmp(evhttp_uri_get_path(uri), "/some/path/to/the-file") == 0);
2530 tt_want(evhttp_uri_get_query(uri) == NULL);
2531 tt_want(evhttp_uri_get_fragment(uri) == NULL);
2532 TT_URI("///some/path/to/the-file");
2533 evhttp_uri_free(uri);
2535 uri = URI_PARSE("/s:ome/path/to/the-file?q=99#fred");
2536 tt_want(uri != NULL);
2537 tt_want(evhttp_uri_get_scheme(uri) == NULL);
2538 tt_want(evhttp_uri_get_userinfo(uri) == NULL);
2539 tt_want(evhttp_uri_get_host(uri) == NULL);
2540 tt_want(evhttp_uri_get_port(uri) == -1);
2541 tt_want(strcmp(evhttp_uri_get_path(uri), "/s:ome/path/to/the-file") == 0);
2542 tt_want(strcmp(evhttp_uri_get_query(uri), "q=99") == 0);
2543 tt_want(strcmp(evhttp_uri_get_fragment(uri), "fred") == 0);
2544 TT_URI("/s:ome/path/to/the-file?q=99#fred");
2545 evhttp_uri_free(uri);
2547 uri = URI_PARSE("relative/path/with/co:lon");
2548 tt_want(uri != NULL);
2549 tt_want(evhttp_uri_get_scheme(uri) == NULL);
2550 tt_want(evhttp_uri_get_userinfo(uri) == NULL);
2551 tt_want(evhttp_uri_get_host(uri) == NULL);
2552 tt_want(evhttp_uri_get_port(uri) == -1);
2553 tt_want(strcmp(evhttp_uri_get_path(uri), "relative/path/with/co:lon") == 0);
2554 tt_want(evhttp_uri_get_query(uri) == NULL);
2555 tt_want(evhttp_uri_get_fragment(uri) == NULL);
2556 TT_URI("relative/path/with/co:lon");
2557 evhttp_uri_free(uri);
2559 uri = URI_PARSE("bob?q=99&q2=q?33#fr?ed");
2560 tt_want(uri != NULL);
2561 tt_want(evhttp_uri_get_scheme(uri) == NULL);
2562 tt_want(evhttp_uri_get_userinfo(uri) == NULL);
2563 tt_want(evhttp_uri_get_host(uri) == NULL);
2564 tt_want(evhttp_uri_get_port(uri) == -1);
2565 tt_want(strcmp(evhttp_uri_get_path(uri), "bob") == 0);
2566 tt_want(strcmp(evhttp_uri_get_query(uri), "q=99&q2=q?33") == 0);
2567 tt_want(strcmp(evhttp_uri_get_fragment(uri), "fr?ed") == 0);
2568 TT_URI("bob?q=99&q2=q?33#fr?ed");
2569 evhttp_uri_free(uri);
2571 uri = URI_PARSE("#fr?ed");
2572 tt_want(uri != NULL);
2573 tt_want(evhttp_uri_get_scheme(uri) == NULL);
2574 tt_want(evhttp_uri_get_userinfo(uri) == NULL);
2575 tt_want(evhttp_uri_get_host(uri) == NULL);
2576 tt_want(evhttp_uri_get_port(uri) == -1);
2577 tt_want(strcmp(evhttp_uri_get_path(uri), "") == 0);
2578 tt_want(evhttp_uri_get_query(uri) == NULL);
2579 tt_want(strcmp(evhttp_uri_get_fragment(uri), "fr?ed") == 0);
2581 evhttp_uri_free(uri);
2588 http_uriencode_test(void *ptr)
2590 char *s=NULL, *s2=NULL;
2594 #define ENC(from,want,plus) do { \
2595 s = evhttp_uriencode((from), -1, (plus)); \
2597 tt_str_op(s,==,(want)); \
2599 s2 = evhttp_uridecode((s), (plus), &sz); \
2601 tt_str_op(s2,==,(from)); \
2602 tt_int_op(sz,==,strlen(from)); \
2608 #define DEC(from,want,dp) do { \
2609 s = evhttp_uridecode((from),(dp),&sz); \
2611 tt_str_op(s,==,(want)); \
2612 tt_int_op(sz,==,strlen(want)); \
2617 #define OLD_DEC(from,want) do { \
2618 s = evhttp_decode_uri((from)); \
2620 tt_str_op(s,==,(want)); \
2626 ENC("Hello", "Hello",0);
2630 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ123456789-.~_",
2631 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ123456789-.~_",0);
2634 ENC("\xff\xf0\xe0", "%FF%F0%E0",0);
2635 ENC("\x01\x19", "%01%19",1);
2636 ENC("http://www.ietf.org/rfc/rfc3986.txt",
2637 "http%3A%2F%2Fwww.ietf.org%2Frfc%2Frfc3986.txt",1);
2639 ENC("1+2=3", "1%2B2%3D3",1);
2640 ENC("1+2=3", "1%2B2%3D3",0);
2642 /* Now try encoding with internal NULs. */
2643 s = evhttp_uriencode("hello\0world", 11, 0);
2645 tt_str_op(s,==,"hello%00world");
2649 /* Now try decoding just part of string. */
2650 s = malloc(6 + 1 /* NUL byte */);
2651 bytes_decoded = evhttp_decode_uri_internal("hello%20%20", 6, s, 0);
2653 tt_int_op(bytes_decoded,==,6);
2654 tt_str_op(s,==,"hello%");
2658 /* Now try out some decoding cases that we don't generate with
2659 * encode_uri: Make sure that malformed stuff doesn't crash... */
2660 DEC("%%xhello th+ere \xff",
2661 "%%xhello th+ere \xff", 0);
2662 /* Make sure plus decoding works */
2663 DEC("plus+should%20work+", "plus should work ",1);
2664 /* Try some lowercase hex */
2665 DEC("%f0%a0%b0", "\xf0\xa0\xb0",1);
2667 /* Try an internal NUL. */
2669 s = evhttp_uridecode("%00%00x%00%00", 1, &sz);
2671 tt_assert(!memcmp(s, "\0\0x\0\0", 5));
2675 /* Try with size == NULL */
2677 s = evhttp_uridecode("%00%00x%00%00", 1, NULL);
2678 tt_assert(!memcmp(s, "\0\0x\0\0", 5));
2682 /* Test out the crazy old behavior of the deprecated
2683 * evhttp_decode_uri */
2684 OLD_DEC("http://example.com/normal+path/?key=val+with+spaces",
2685 "http://example.com/normal+path/?key=val with spaces");
2698 http_base_test(void *ptr)
2700 struct event_base *base = NULL;
2701 struct bufferevent *bev;
2703 const char *http_request;
2704 ev_uint16_t port = 0;
2707 base = event_base_new();
2709 http = http_setup(&port, base, 0);
2711 fd = http_connect("127.0.0.1", port);
2712 tt_int_op(fd, >=, 0);
2714 /* Stupid thing to send a request */
2715 bev = bufferevent_socket_new(base, fd, 0);
2716 bufferevent_setcb(bev, http_readcb, http_writecb,
2717 http_errorcb, base);
2718 bufferevent_base_set(base, bev);
2721 "GET /test HTTP/1.1\r\n"
2722 "Host: somehost\r\n"
2723 "Connection: close\r\n"
2726 bufferevent_write(bev, http_request, strlen(http_request));
2728 event_base_dispatch(base);
2730 bufferevent_free(bev);
2731 evutil_closesocket(fd);
2735 tt_int_op(test_ok, ==, 2);
2739 event_base_free(base);
2743 * the server is just going to close the connection if it times out during
2744 * reading the headers.
2748 http_incomplete_readcb(struct bufferevent *bev, void *arg)
2751 event_base_loopexit(exit_base,NULL);
2755 http_incomplete_errorcb(struct bufferevent *bev, short what, void *arg)
2757 if (what == (BEV_EVENT_READING|BEV_EVENT_EOF))
2761 event_base_loopexit(exit_base,NULL);
2765 http_incomplete_writecb(struct bufferevent *bev, void *arg)
2768 evutil_socket_t fd = *(evutil_socket_t *)arg;
2769 /* terminate the write side to simulate EOF */
2770 shutdown(fd, SHUT_WR);
2772 if (evbuffer_get_length(bufferevent_get_output(bev)) == 0) {
2773 /* enable reading of the reply */
2774 bufferevent_enable(bev, EV_READ);
2780 http_incomplete_test_(struct basic_test_data *data, int use_timeout)
2782 struct bufferevent *bev;
2784 const char *http_request;
2785 ev_uint16_t port = 0;
2786 struct timeval tv_start, tv_end;
2788 exit_base = data->base;
2792 http = http_setup(&port, data->base, 0);
2793 evhttp_set_timeout(http, 1);
2795 fd = http_connect("127.0.0.1", port);
2796 tt_int_op(fd, >=, 0);
2798 /* Stupid thing to send a request */
2799 bev = bufferevent_socket_new(data->base, fd, 0);
2800 bufferevent_setcb(bev,
2801 http_incomplete_readcb, http_incomplete_writecb,
2802 http_incomplete_errorcb, use_timeout ? NULL : &fd);
2805 "GET /test HTTP/1.1\r\n"
2806 "Host: somehost\r\n";
2808 bufferevent_write(bev, http_request, strlen(http_request));
2810 evutil_gettimeofday(&tv_start, NULL);
2812 event_base_dispatch(data->base);
2814 evutil_gettimeofday(&tv_end, NULL);
2815 evutil_timersub(&tv_end, &tv_start, &tv_end);
2817 bufferevent_free(bev);
2819 evutil_closesocket(fd);
2825 if (use_timeout && tv_end.tv_sec >= 3) {
2826 tt_abort_msg("time");
2827 } else if (!use_timeout && tv_end.tv_sec >= 1) {
2828 /* we should be done immediately */
2829 tt_abort_msg("time");
2832 tt_int_op(test_ok, ==, 2);
2835 evutil_closesocket(fd);
2838 http_incomplete_test(void *arg)
2840 http_incomplete_test_(arg, 0);
2843 http_incomplete_timeout_test(void *arg)
2845 http_incomplete_test_(arg, 1);
2849 * the server is going to reply with chunked data.
2853 http_chunked_readcb(struct bufferevent *bev, void *arg)
2859 http_chunked_errorcb(struct bufferevent *bev, short what, void *arg)
2861 struct evhttp_request *req = NULL;
2868 if ((what & BEV_EVENT_EOF) != 0) {
2870 enum message_read_status done;
2871 req = evhttp_request_new(NULL, NULL);
2873 /* req->kind = EVHTTP_RESPONSE; */
2874 done = evhttp_parse_firstline_(req, bufferevent_get_input(bev));
2875 if (done != ALL_DATA_READ)
2878 done = evhttp_parse_headers_(req, bufferevent_get_input(bev));
2879 if (done != ALL_DATA_READ)
2882 header = evhttp_find_header(evhttp_request_get_input_headers(req), "Transfer-Encoding");
2883 if (header == NULL || strcmp(header, "chunked"))
2886 header = evhttp_find_header(evhttp_request_get_input_headers(req), "Connection");
2887 if (header == NULL || strcmp(header, "close"))
2890 header = evbuffer_readln(bufferevent_get_input(bev), NULL, EVBUFFER_EOL_CRLF);
2894 if (strcmp(header, "d")) {
2895 free((void*)header);
2898 free((void*)header);
2900 if (strncmp((char *)evbuffer_pullup(bufferevent_get_input(bev), 13),
2901 "This is funny", 13))
2904 evbuffer_drain(bufferevent_get_input(bev), 13 + 2);
2906 header = evbuffer_readln(bufferevent_get_input(bev), NULL, EVBUFFER_EOL_CRLF);
2910 if (strcmp(header, "12"))
2912 free((char *)header);
2914 if (strncmp((char *)evbuffer_pullup(bufferevent_get_input(bev), 18),
2915 "but not hilarious.", 18))
2918 evbuffer_drain(bufferevent_get_input(bev), 18 + 2);
2920 header = evbuffer_readln(bufferevent_get_input(bev), NULL, EVBUFFER_EOL_CRLF);
2924 if (strcmp(header, "8")) {
2925 free((void*)header);
2928 free((char *)header);
2930 if (strncmp((char *)evbuffer_pullup(bufferevent_get_input(bev), 8),
2934 evbuffer_drain(bufferevent_get_input(bev), 8 + 2);
2936 header = evbuffer_readln(bufferevent_get_input(bev), NULL, EVBUFFER_EOL_CRLF);
2940 if (strcmp(header, "0")) {
2941 free((void*)header);
2944 free((void *)header);
2951 evhttp_request_free(req);
2953 event_base_loopexit(arg, NULL);
2957 http_chunked_writecb(struct bufferevent *bev, void *arg)
2959 if (evbuffer_get_length(bufferevent_get_output(bev)) == 0) {
2960 /* enable reading of the reply */
2961 bufferevent_enable(bev, EV_READ);
2967 http_chunked_request_done(struct evhttp_request *req, void *arg)
2969 if (evhttp_request_get_response_code(req) != HTTP_OK) {
2970 fprintf(stderr, "FAILED\n");
2974 if (evhttp_find_header(evhttp_request_get_input_headers(req),
2975 "Transfer-Encoding") == NULL) {
2976 fprintf(stderr, "FAILED\n");
2980 if (evbuffer_get_length(evhttp_request_get_input_buffer(req)) != 13 + 18 + 8) {
2981 fprintf(stderr, "FAILED\n");
2985 if (strncmp((char *)evbuffer_pullup(evhttp_request_get_input_buffer(req), 13 + 18 + 8),
2986 "This is funnybut not hilarious.bwv 1052",
2988 fprintf(stderr, "FAILED\n");
2993 event_base_loopexit(arg, NULL);
2997 http_chunk_out_test(void *arg)
2999 struct basic_test_data *data = arg;
3000 struct bufferevent *bev;
3002 const char *http_request;
3003 ev_uint16_t port = 0;
3004 struct timeval tv_start, tv_end;
3005 struct evhttp_connection *evcon = NULL;
3006 struct evhttp_request *req = NULL;
3009 exit_base = data->base;
3012 http = http_setup(&port, data->base, 0);
3014 fd = http_connect("127.0.0.1", port);
3016 /* Stupid thing to send a request */
3017 bev = bufferevent_socket_new(data->base, fd, 0);
3018 bufferevent_setcb(bev,
3019 http_chunked_readcb, http_chunked_writecb,
3020 http_chunked_errorcb, data->base);
3023 "GET /chunked HTTP/1.1\r\n"
3024 "Host: somehost\r\n"
3025 "Connection: close\r\n"
3028 bufferevent_write(bev, http_request, strlen(http_request));
3030 evutil_gettimeofday(&tv_start, NULL);
3032 event_base_dispatch(data->base);
3034 bufferevent_free(bev);
3036 evutil_gettimeofday(&tv_end, NULL);
3037 evutil_timersub(&tv_end, &tv_start, &tv_end);
3039 tt_int_op(tv_end.tv_sec, <, 1);
3041 tt_int_op(test_ok, ==, 2);
3043 /* now try again with the regular connection object */
3044 evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port);
3047 /* make two requests to check the keepalive behavior */
3048 for (i = 0; i < 2; i++) {
3050 req = evhttp_request_new(http_chunked_request_done,data->base);
3052 /* Add the information that we care about */
3053 evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
3055 /* We give ownership of the request to the connection */
3056 if (evhttp_make_request(evcon, req,
3057 EVHTTP_REQ_GET, "/chunked") == -1) {
3058 tt_abort_msg("Couldn't make request");
3061 event_base_dispatch(data->base);
3063 tt_assert(test_ok == 1);
3068 evhttp_connection_free(evcon);
3074 http_stream_out_test(void *arg)
3076 struct basic_test_data *data = arg;
3077 ev_uint16_t port = 0;
3078 struct evhttp_connection *evcon = NULL;
3079 struct evhttp_request *req = NULL;
3082 exit_base = data->base;
3084 http = http_setup(&port, data->base, 0);
3086 evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port);
3090 * At this point, we want to schedule a request to the HTTP
3091 * server using our make request method.
3094 req = evhttp_request_new(http_request_done,
3095 (void *)"This is funnybut not hilarious.bwv 1052");
3097 /* Add the information that we care about */
3098 evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
3100 /* We give ownership of the request to the connection */
3101 if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/streamed")
3103 tt_abort_msg("Couldn't make request");
3106 event_base_dispatch(data->base);
3110 evhttp_connection_free(evcon);
3116 http_stream_in_chunk(struct evhttp_request *req, void *arg)
3118 struct evbuffer *reply = arg;
3120 if (evhttp_request_get_response_code(req) != HTTP_OK) {
3121 fprintf(stderr, "FAILED\n");
3125 evbuffer_add_buffer(reply, evhttp_request_get_input_buffer(req));
3129 http_stream_in_done(struct evhttp_request *req, void *arg)
3131 if (evbuffer_get_length(evhttp_request_get_input_buffer(req)) != 0) {
3132 fprintf(stderr, "FAILED\n");
3136 event_base_loopexit(exit_base, NULL);
3140 * Makes a request and reads the response in chunks.
3143 http_stream_in_test_(struct basic_test_data *data, char const *url,
3144 size_t expected_len, char const *expected)
3146 struct evhttp_connection *evcon;
3147 struct evbuffer *reply = evbuffer_new();
3148 struct evhttp_request *req = NULL;
3149 ev_uint16_t port = 0;
3151 exit_base = data->base;
3152 http = http_setup(&port, data->base, 0);
3154 evcon = evhttp_connection_base_new(data->base, NULL,"127.0.0.1", port);
3157 req = evhttp_request_new(http_stream_in_done, reply);
3158 evhttp_request_set_chunked_cb(req, http_stream_in_chunk);
3160 /* We give ownership of the request to the connection */
3161 if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, url) == -1) {
3162 tt_abort_msg("Couldn't make request");
3165 event_base_dispatch(data->base);
3167 if (evbuffer_get_length(reply) != expected_len) {
3168 TT_DIE(("reply length %lu; expected %lu; FAILED (%s)\n",
3169 (unsigned long)evbuffer_get_length(reply),
3170 (unsigned long)expected_len,
3171 (char*)evbuffer_pullup(reply, -1)));
3174 if (memcmp(evbuffer_pullup(reply, -1), expected, expected_len) != 0) {
3175 tt_abort_msg("Memory mismatch");
3181 evbuffer_free(reply);
3183 evhttp_connection_free(evcon);
3189 http_stream_in_test(void *arg)
3191 http_stream_in_test_(arg, "/chunked", 13 + 18 + 8,
3192 "This is funnybut not hilarious.bwv 1052");
3194 http_stream_in_test_(arg, "/test", strlen(BASIC_REQUEST_BODY),
3195 BASIC_REQUEST_BODY);
3199 http_stream_in_cancel_chunk(struct evhttp_request *req, void *arg)
3201 tt_int_op(evhttp_request_get_response_code(req), ==, HTTP_OK);
3204 evhttp_cancel_request(req);
3205 event_base_loopexit(arg, NULL);
3209 http_stream_in_cancel_done(struct evhttp_request *req, void *arg)
3211 /* should never be called */
3212 tt_fail_msg("In cancel done");
3216 http_stream_in_cancel_test(void *arg)
3218 struct basic_test_data *data = arg;
3219 struct evhttp_connection *evcon;
3220 struct evhttp_request *req = NULL;
3221 ev_uint16_t port = 0;
3223 http = http_setup(&port, data->base, 0);
3225 evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port);
3228 req = evhttp_request_new(http_stream_in_cancel_done, data->base);
3229 evhttp_request_set_chunked_cb(req, http_stream_in_cancel_chunk);
3231 /* We give ownership of the request to the connection */
3232 if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/chunked") == -1) {
3233 tt_abort_msg("Couldn't make request");
3236 event_base_dispatch(data->base);
3240 evhttp_connection_free(evcon);
3246 http_connection_fail_done(struct evhttp_request *req, void *arg)
3248 struct evhttp_connection *evcon = arg;
3249 struct event_base *base = evhttp_connection_get_base(evcon);
3251 /* An ENETUNREACH error results in an unrecoverable
3252 * evhttp_connection error (see evhttp_connection_fail_()). The
3253 * connection will be reset, and the user will be notified with a NULL
3257 evhttp_connection_free(evcon);
3262 event_base_loopexit(base, NULL);
3265 /* Test unrecoverable evhttp_connection errors by generating an ENETUNREACH
3266 * error on connection. */
3268 http_connection_fail_test(void *arg)
3270 struct basic_test_data *data = arg;
3271 ev_uint16_t port = 0;
3272 struct evhttp_connection *evcon = NULL;
3273 struct evhttp_request *req = NULL;
3275 exit_base = data->base;
3278 /* auto detect a port */
3279 http = http_setup(&port, data->base, 0);
3283 /* Pick an unroutable address. This administratively scoped multicast
3284 * address should do when working with TCP. */
3285 evcon = evhttp_connection_base_new(data->base, NULL, "239.10.20.30", 80);
3289 * At this point, we want to schedule an HTTP GET request
3290 * server using our make request method.
3293 req = evhttp_request_new(http_connection_fail_done, evcon);
3296 if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/") == -1) {
3297 tt_abort_msg("Couldn't make request");
3300 event_base_dispatch(data->base);
3302 tt_int_op(test_ok, ==, 1);
3309 http_connection_retry_done(struct evhttp_request *req, void *arg)
3312 tt_int_op(evhttp_request_get_response_code(req), !=, HTTP_OK);
3313 if (evhttp_find_header(evhttp_request_get_input_headers(req), "Content-Type") != NULL) {
3314 tt_abort_msg("(content type)\n");
3317 tt_uint_op(evbuffer_get_length(evhttp_request_get_input_buffer(req)), ==, 0);
3321 event_base_loopexit(arg,NULL);
3324 static struct event_base *http_make_web_server_base=NULL;
3326 http_make_web_server(evutil_socket_t fd, short what, void *arg)
3328 ev_uint16_t port = *(ev_uint16_t*)arg;
3329 http = http_setup(&port, http_make_web_server_base, 0);
3333 http_connection_retry_test(void *arg)
3335 struct basic_test_data *data = arg;
3336 ev_uint16_t port = 0;
3337 struct evhttp_connection *evcon = NULL;
3338 struct evhttp_request *req = NULL;
3339 struct timeval tv, tv_start, tv_end;
3341 exit_base = data->base;
3344 /* auto detect a port */
3345 http = http_setup(&port, data->base, 0);
3349 evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port);
3352 evhttp_connection_set_timeout(evcon, 1);
3353 /* also bind to local host */
3354 evhttp_connection_set_local_address(evcon, "127.0.0.1");
3357 * At this point, we want to schedule an HTTP GET request
3358 * server using our make request method.
3361 req = evhttp_request_new(http_connection_retry_done, data->base);
3364 /* Add the information that we care about */
3365 evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
3367 if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET,
3368 "/?arg=val") == -1) {
3369 tt_abort_msg("Couldn't make request");
3372 evutil_gettimeofday(&tv_start, NULL);
3373 event_base_dispatch(data->base);
3374 evutil_gettimeofday(&tv_end, NULL);
3375 evutil_timersub(&tv_end, &tv_start, &tv_end);
3376 tt_int_op(tv_end.tv_sec, <, 1);
3378 tt_int_op(test_ok, ==, 1);
3381 * now test the same but with retries
3386 const struct timeval tv_timeout = { 0, 500000 };
3387 const struct timeval tv_retry = { 0, 500000 };
3388 evhttp_connection_set_timeout_tv(evcon, &tv_timeout);
3389 evhttp_connection_set_initial_retry_tv(evcon, &tv_retry);
3391 evhttp_connection_set_retries(evcon, 1);
3393 req = evhttp_request_new(http_connection_retry_done, data->base);
3396 /* Add the information that we care about */
3397 evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
3399 if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET,
3400 "/?arg=val") == -1) {
3401 tt_abort_msg("Couldn't make request");
3404 evutil_gettimeofday(&tv_start, NULL);
3405 event_base_dispatch(data->base);
3406 evutil_gettimeofday(&tv_end, NULL);
3408 /* fails fast, .5 sec to wait to retry, fails fast again. */
3409 test_timeval_diff_leq(&tv_start, &tv_end, 500, 200);
3411 tt_assert(test_ok == 1);
3414 * now test the same but with retries and give it a web server
3419 evhttp_connection_set_timeout(evcon, 1);
3420 evhttp_connection_set_retries(evcon, 3);
3422 req = evhttp_request_new(http_dispatcher_test_done, data->base);
3425 /* Add the information that we care about */
3426 evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
3428 if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET,
3429 "/?arg=val") == -1) {
3430 tt_abort_msg("Couldn't make request");
3433 /* start up a web server .2 seconds after the connection tried
3436 evutil_timerclear(&tv);
3437 tv.tv_usec = 200000;
3438 http_make_web_server_base = data->base;
3439 event_base_once(data->base, -1, EV_TIMEOUT, http_make_web_server, &port, &tv);
3441 evutil_gettimeofday(&tv_start, NULL);
3442 event_base_dispatch(data->base);
3443 evutil_gettimeofday(&tv_end, NULL);
3444 /* We'll wait twice as long as we did last time. */
3445 test_timeval_diff_leq(&tv_start, &tv_end, 1000, 400);
3447 tt_int_op(test_ok, ==, 1);
3451 evhttp_connection_free(evcon);
3457 http_primitives(void *ptr)
3459 char *escaped = NULL;
3460 struct evhttp *http = NULL;
3462 escaped = evhttp_htmlescape("<script>");
3464 tt_str_op(escaped, ==, "<script>");
3467 escaped = evhttp_htmlescape("\"\'&");
3469 tt_str_op(escaped, ==, ""'&");
3471 http = evhttp_new(NULL);
3473 tt_int_op(evhttp_set_cb(http, "/test", http_basic_cb, NULL), ==, 0);
3474 tt_int_op(evhttp_set_cb(http, "/test", http_basic_cb, NULL), ==, -1);
3475 tt_int_op(evhttp_del_cb(http, "/test"), ==, 0);
3476 tt_int_op(evhttp_del_cb(http, "/test"), ==, -1);
3477 tt_int_op(evhttp_set_cb(http, "/test", http_basic_cb, NULL), ==, 0);
3487 http_multi_line_header_test(void *arg)
3489 struct basic_test_data *data = arg;
3490 struct bufferevent *bev= NULL;
3491 evutil_socket_t fd = -1;
3492 const char *http_start_request;
3493 ev_uint16_t port = 0;
3497 http = http_setup(&port, data->base, 0);
3499 tt_ptr_op(http, !=, NULL);
3501 fd = http_connect("127.0.0.1", port);
3503 tt_int_op(fd, !=, -1);
3505 /* Stupid thing to send a request */
3506 bev = bufferevent_socket_new(data->base, fd, 0);
3507 tt_ptr_op(bev, !=, NULL);
3508 bufferevent_setcb(bev, http_readcb, http_writecb,
3509 http_errorcb, data->base);
3511 http_start_request =
3512 "GET /test HTTP/1.1\r\n"
3513 "Host: somehost\r\n"
3514 "Connection: close\r\n"
3515 "X-Multi-Extra-WS: libevent \r\n"
3517 "X-Multi: aaaaaaaa\r\n"
3523 bufferevent_write(bev, http_start_request, strlen(http_start_request));
3524 found_multi = found_multi2 = 0;
3526 event_base_dispatch(data->base);
3528 tt_int_op(found_multi, ==, 1);
3529 tt_int_op(found_multi2, ==, 1);
3530 tt_int_op(test_ok, ==, 4);
3533 bufferevent_free(bev);
3535 evutil_closesocket(fd);
3541 http_request_bad(struct evhttp_request *req, void *arg)
3544 fprintf(stderr, "FAILED\n");
3549 event_base_loopexit(arg, NULL);
3553 http_negative_content_length_test(void *arg)
3555 struct basic_test_data *data = arg;
3556 ev_uint16_t port = 0;
3557 struct evhttp_connection *evcon = NULL;
3558 struct evhttp_request *req = NULL;
3562 http = http_setup(&port, data->base, 0);
3564 evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port);
3568 * At this point, we want to schedule a request to the HTTP
3569 * server using our make request method.
3572 req = evhttp_request_new(http_request_bad, data->base);
3574 /* Cause the response to have a negative content-length */
3575 evhttp_add_header(evhttp_request_get_output_headers(req), "X-Negative", "makeitso");
3577 /* We give ownership of the request to the connection */
3578 if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test") == -1) {
3579 tt_abort_msg("Couldn't make request");
3582 event_base_dispatch(data->base);
3586 evhttp_connection_free(evcon);
3593 http_data_length_constraints_test_done(struct evhttp_request *req, void *arg)
3596 tt_int_op(evhttp_request_get_response_code(req), ==, HTTP_BADREQUEST);
3598 event_base_loopexit(arg, NULL);
3602 http_large_entity_test_done(struct evhttp_request *req, void *arg)
3605 tt_int_op(evhttp_request_get_response_code(req), ==, HTTP_ENTITYTOOLARGE);
3607 event_base_loopexit(arg, NULL);
3611 http_data_length_constraints_test(void *arg)
3613 struct basic_test_data *data = arg;
3614 ev_uint16_t port = 0;
3615 struct evhttp_connection *evcon = NULL;
3616 struct evhttp_request *req = NULL;
3617 char long_str[8192];
3621 http = http_setup(&port, data->base, 0);
3623 evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port);
3626 /* also bind to local host */
3627 evhttp_connection_set_local_address(evcon, "127.0.0.1");
3630 * At this point, we want to schedule an HTTP GET request
3631 * server using our make request method.
3634 req = evhttp_request_new(http_data_length_constraints_test_done, data->base);
3637 memset(long_str, 'a', 8192);
3638 long_str[8191] = '\0';
3639 /* Add the information that we care about */
3640 evhttp_set_max_headers_size(http, 8191);
3641 evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
3642 evhttp_add_header(evhttp_request_get_output_headers(req), "Longheader", long_str);
3644 if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/?arg=val") == -1) {
3645 tt_abort_msg("Couldn't make request");
3647 event_base_dispatch(data->base);
3649 req = evhttp_request_new(http_data_length_constraints_test_done, data->base);
3651 evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
3653 /* GET /?arg=verylongvalue HTTP/1.1 */
3654 if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, long_str) == -1) {
3655 tt_abort_msg("Couldn't make request");
3657 event_base_dispatch(data->base);
3659 evhttp_set_max_body_size(http, 8190);
3660 req = evhttp_request_new(http_data_length_constraints_test_done, data->base);
3661 evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
3662 evbuffer_add_printf(evhttp_request_get_output_buffer(req), "%s", long_str);
3663 if (evhttp_make_request(evcon, req, EVHTTP_REQ_POST, "/") == -1) {
3664 tt_abort_msg("Couldn't make request");
3666 event_base_dispatch(data->base);
3668 req = evhttp_request_new(http_large_entity_test_done, data->base);
3669 evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
3670 evhttp_add_header(evhttp_request_get_output_headers(req), "Expect", "100-continue");
3671 evbuffer_add_printf(evhttp_request_get_output_buffer(req), "%s", long_str);
3672 if (evhttp_make_request(evcon, req, EVHTTP_REQ_POST, "/") == -1) {
3673 tt_abort_msg("Couldn't make request");
3675 event_base_dispatch(data->base);
3680 evhttp_connection_free(evcon);
3686 * Testing client reset of server chunked connections
3689 struct terminate_state {
3690 struct event_base *base;
3691 struct evhttp_request *req;
3692 struct bufferevent *bev;
3698 terminate_chunked_trickle_cb(evutil_socket_t fd, short events, void *arg)
3700 struct terminate_state *state = arg;
3701 struct evbuffer *evb;
3704 if (evhttp_request_get_connection(state->req) == NULL) {
3706 evhttp_request_free(state->req);
3707 event_base_loopexit(state->base,NULL);
3711 evb = evbuffer_new();
3712 evbuffer_add_printf(evb, "%p", evb);
3713 evhttp_send_reply_chunk(state->req, evb);
3718 EVUTIL_ASSERT(state);
3719 EVUTIL_ASSERT(state->base);
3720 event_base_once(state->base, -1, EV_TIMEOUT, terminate_chunked_trickle_cb, arg, &tv);
3724 terminate_chunked_close_cb(struct evhttp_connection *evcon, void *arg)
3726 struct terminate_state *state = arg;
3727 state->gotclosecb = 1;
3731 terminate_chunked_cb(struct evhttp_request *req, void *arg)
3733 struct terminate_state *state = arg;
3736 /* we want to know if this connection closes on us */
3737 evhttp_connection_set_closecb(
3738 evhttp_request_get_connection(req),
3739 terminate_chunked_close_cb, arg);
3743 evhttp_send_reply_start(req, HTTP_OK, "OK");
3747 event_base_once(state->base, -1, EV_TIMEOUT, terminate_chunked_trickle_cb, arg, &tv);
3751 terminate_chunked_client(evutil_socket_t fd, short event, void *arg)
3753 struct terminate_state *state = arg;
3754 bufferevent_free(state->bev);
3755 evutil_closesocket(state->fd);
3759 terminate_readcb(struct bufferevent *bev, void *arg)
3761 /* just drop the data */
3762 evbuffer_drain(bufferevent_get_input(bev), -1);
3767 http_terminate_chunked_test(void *arg)
3769 struct basic_test_data *data = arg;
3770 struct bufferevent *bev = NULL;
3772 const char *http_request;
3773 ev_uint16_t port = 0;
3774 evutil_socket_t fd = -1;
3775 struct terminate_state terminate_state;
3779 http = http_setup(&port, data->base, 0);
3780 evhttp_del_cb(http, "/test");
3781 tt_assert(evhttp_set_cb(http, "/test",
3782 terminate_chunked_cb, &terminate_state) == 0);
3784 fd = http_connect("127.0.0.1", port);
3786 /* Stupid thing to send a request */
3787 bev = bufferevent_socket_new(data->base, fd, 0);
3788 bufferevent_setcb(bev, terminate_readcb, http_writecb,
3789 http_errorcb, data->base);
3791 memset(&terminate_state, 0, sizeof(terminate_state));
3792 terminate_state.base = data->base;
3793 terminate_state.fd = fd;
3794 terminate_state.bev = bev;
3795 terminate_state.gotclosecb = 0;
3797 /* first half of the http request */
3799 "GET /test HTTP/1.1\r\n"
3800 "Host: some\r\n\r\n";
3802 bufferevent_write(bev, http_request, strlen(http_request));
3803 evutil_timerclear(&tv);
3805 event_base_once(data->base, -1, EV_TIMEOUT, terminate_chunked_client, &terminate_state,
3808 event_base_dispatch(data->base);
3810 if (terminate_state.gotclosecb == 0)
3815 evutil_closesocket(fd);
3820 static struct regress_dns_server_table ipv6_search_table[] = {
3821 { "localhost", "AAAA", "::1", 0 },
3822 { NULL, NULL, NULL, 0 }
3826 http_ipv6_for_domain_test_impl(void *arg, int family)
3828 struct basic_test_data *data = arg;
3829 struct evdns_base *dns_base = NULL;
3830 ev_uint16_t portnum = 0;
3833 tt_assert(regress_dnsserver(data->base, &portnum, ipv6_search_table));
3835 dns_base = evdns_base_new(data->base, 0/* init name servers */);
3836 tt_assert(dns_base);
3838 /* Add ourself as the only nameserver, and make sure we really are
3839 * the only nameserver. */
3840 evutil_snprintf(address, sizeof(address), "127.0.0.1:%d", portnum);
3841 evdns_base_nameserver_ip_add(dns_base, address);
3843 http_connection_test_(arg, 0 /* not persistent */, "localhost", dns_base,
3844 1 /* ipv6 */, family);
3848 evdns_base_free(dns_base, 0);
3849 regress_clean_dnsserver();
3852 http_ipv6_for_domain_test(void *arg)
3854 http_ipv6_for_domain_test_impl(arg, AF_UNSPEC);
3858 http_request_get_addr_on_close(struct evhttp_connection *evcon, void *arg)
3860 const struct sockaddr *storage;
3862 char local[] = "127.0.0.1:";
3867 storage = evhttp_connection_get_addr(evcon);
3870 evutil_format_sockaddr_port_((struct sockaddr *)storage, addrbuf, sizeof(addrbuf));
3871 tt_assert(!strncmp(addrbuf, local, sizeof(local) - 1));
3881 http_get_addr_test(void *arg)
3883 struct basic_test_data *data = arg;
3884 ev_uint16_t port = 0;
3885 struct evhttp_connection *evcon = NULL;
3886 struct evhttp_request *req = NULL;
3889 exit_base = data->base;
3891 http = http_setup(&port, data->base, 0);
3893 evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port);
3895 evhttp_connection_set_closecb(evcon, http_request_get_addr_on_close, arg);
3898 * At this point, we want to schedule a request to the HTTP
3899 * server using our make request method.
3902 req = evhttp_request_new(http_request_done, (void *)BASIC_REQUEST_BODY);
3904 /* We give ownership of the request to the connection */
3905 if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test") == -1) {
3906 tt_abort_msg("Couldn't make request");
3909 event_base_dispatch(data->base);
3911 http_request_get_addr_on_close(evcon, NULL);
3915 evhttp_connection_free(evcon);
3921 http_set_family_test(void *arg)
3923 http_connection_test_(arg, 0, "127.0.0.1", NULL, 0, AF_UNSPEC);
3926 http_set_family_ipv4_test(void *arg)
3928 http_connection_test_(arg, 0, "127.0.0.1", NULL, 0, AF_INET);
3931 http_set_family_ipv6_test(void *arg)
3933 http_ipv6_for_domain_test_impl(arg, AF_INET6);
3936 #define HTTP_LEGACY(name) \
3937 { #name, run_legacy_test_fn, TT_ISOLATED|TT_LEGACY, &legacy_setup, \
3938 http_##name##_test }
3940 #define HTTP(name) \
3941 { #name, http_##name##_test, TT_ISOLATED, &basic_setup, NULL }
3943 struct testcase_t http_testcases[] = {
3944 { "primitives", http_primitives, 0, NULL, NULL },
3945 { "base", http_base_test, TT_FORK, NULL, NULL },
3946 { "bad_headers", http_bad_header_test, 0, NULL, NULL },
3947 { "parse_query", http_parse_query_test, 0, NULL, NULL },
3948 { "parse_uri", http_parse_uri_test, 0, NULL, NULL },
3949 { "parse_uri_nc", http_parse_uri_test, 0, &basic_setup, (void*)"nc" },
3950 { "uriencode", http_uriencode_test, 0, NULL, NULL },
3957 HTTP(allowed_methods),
3960 HTTP(persist_connection),
3961 HTTP(autofree_connection),
3962 HTTP(connection_async),
3963 HTTP(close_detection),
3964 HTTP(close_detection_delay),
3967 HTTP(incomplete_timeout),
3968 HTTP(terminate_chunked),
3973 HTTP(multi_line_header),
3974 HTTP(negative_content_length),
3979 HTTP(stream_in_cancel),
3981 HTTP(connection_fail),
3982 { "connection_retry", http_connection_retry_test, TT_ISOLATED|TT_OFF_BY_DEFAULT, &basic_setup, NULL },
3984 HTTP(data_length_constraints),
3986 HTTP(ipv6_for_domain),
3990 HTTP(set_family_ipv4),
3991 HTTP(set_family_ipv6),