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 memset(state, 0, sizeof(struct chunk_req_state));
375 if (strcmp(evhttp_request_get_uri(req), "/streamed") == 0) {
376 evhttp_add_header(evhttp_request_get_output_headers(req), "Content-Length", "39");
379 /* generate a chunked/streamed reply */
380 evhttp_send_reply_start(req, HTTP_OK, "Everything is fine");
382 /* but trickle it across several iterations to ensure we're not
383 * assuming it comes all at once */
384 event_base_once(arg, -1, EV_TIMEOUT, http_chunked_trickle_cb, state, &when);
388 http_complete_write(evutil_socket_t fd, short what, void *arg)
390 struct bufferevent *bev = arg;
391 const char *http_request = "host\r\n"
392 "Connection: close\r\n"
394 bufferevent_write(bev, http_request, strlen(http_request));
398 http_basic_test(void *arg)
400 struct basic_test_data *data = arg;
402 struct bufferevent *bev = NULL;
404 const char *http_request;
405 ev_uint16_t port = 0, port2 = 0;
409 http = http_setup(&port, data->base, 0);
411 /* bind to a second socket */
412 if (http_bind(http, &port2, 0) == -1) {
413 fprintf(stdout, "FAILED (bind)\n");
417 fd = http_connect("127.0.0.1", port);
419 /* Stupid thing to send a request */
420 bev = bufferevent_socket_new(data->base, fd, 0);
421 bufferevent_setcb(bev, http_readcb, http_writecb,
422 http_errorcb, data->base);
424 /* first half of the http request */
426 "GET /test HTTP/1.1\r\n"
429 bufferevent_write(bev, http_request, strlen(http_request));
430 evutil_timerclear(&tv);
432 event_base_once(data->base,
433 -1, EV_TIMEOUT, http_complete_write, bev, &tv);
435 event_base_dispatch(data->base);
437 tt_assert(test_ok == 3);
439 /* connect to the second port */
440 bufferevent_free(bev);
441 evutil_closesocket(fd);
443 fd = http_connect("127.0.0.1", port2);
445 /* Stupid thing to send a request */
446 bev = bufferevent_socket_new(data->base, fd, 0);
447 bufferevent_setcb(bev, http_readcb, http_writecb,
448 http_errorcb, data->base);
451 "GET /test HTTP/1.1\r\n"
453 "Connection: close\r\n"
456 bufferevent_write(bev, http_request, strlen(http_request));
458 event_base_dispatch(data->base);
460 tt_assert(test_ok == 5);
462 /* Connect to the second port again. This time, send an absolute uri. */
463 bufferevent_free(bev);
464 evutil_closesocket(fd);
466 fd = http_connect("127.0.0.1", port2);
468 /* Stupid thing to send a request */
469 bev = bufferevent_socket_new(data->base, fd, 0);
470 bufferevent_setcb(bev, http_readcb, http_writecb,
471 http_errorcb, data->base);
474 "GET http://somehost.net/test HTTP/1.1\r\n"
476 "Connection: close\r\n"
479 bufferevent_write(bev, http_request, strlen(http_request));
481 event_base_dispatch(data->base);
483 tt_assert(test_ok == 7);
488 bufferevent_free(bev);
493 http_delay_reply(evutil_socket_t fd, short what, void *arg)
495 struct evhttp_request *req = arg;
497 evhttp_send_reply(req, HTTP_OK, "Everything is fine", NULL);
503 http_delay_cb(struct evhttp_request *req, void *arg)
506 evutil_timerclear(&tv);
508 tv.tv_usec = 200 * 1000;
510 event_base_once(arg, -1, EV_TIMEOUT, http_delay_reply, req, &tv);
514 http_badreq_cb(struct evhttp_request *req, void *arg)
516 struct evbuffer *buf = evbuffer_new();
518 evhttp_add_header(evhttp_request_get_output_headers(req), "Content-Type", "text/xml; charset=UTF-8");
519 evbuffer_add_printf(buf, "Hello, %s!", "127.0.0.1");
521 evhttp_send_reply(req, HTTP_OK, "OK", buf);
526 http_badreq_errorcb(struct bufferevent *bev, short what, void *arg)
528 event_debug(("%s: called (what=%04x, arg=%p)", __func__, what, arg));
534 #define SHUT_WR SD_SEND
541 http_badreq_readcb(struct bufferevent *bev, void *arg)
543 const char *what = "Hello, 127.0.0.1";
544 const char *bad_request = "400 Bad Request";
546 if (evbuffer_contains(bufferevent_get_input(bev), bad_request)) {
547 TT_FAIL(("%s:bad request detected", __func__));
548 bufferevent_disable(bev, EV_READ);
549 event_base_loopexit(arg, NULL);
553 if (evbuffer_contains(bufferevent_get_input(bev), what)) {
554 struct evhttp_request *req = evhttp_request_new(NULL, NULL);
555 enum message_read_status done;
557 /* req->kind = EVHTTP_RESPONSE; */
558 done = evhttp_parse_firstline_(req, bufferevent_get_input(bev));
559 if (done != ALL_DATA_READ)
562 done = evhttp_parse_headers_(req, bufferevent_get_input(bev));
563 if (done != ALL_DATA_READ)
567 evhttp_find_header(evhttp_request_get_input_headers(req),
568 "Content-Type") != NULL)
572 evhttp_request_free(req);
573 evbuffer_drain(bufferevent_get_input(bev), evbuffer_get_length(bufferevent_get_input(bev)));
576 shutdown(bufferevent_getfd(bev), SHUT_WR);
580 http_badreq_successcb(evutil_socket_t fd, short what, void *arg)
582 event_debug(("%s: called (what=%04x, arg=%p)", __func__, what, arg));
583 event_base_loopexit(exit_base, NULL);
587 http_bad_request_test(void *arg)
589 struct basic_test_data *data = arg;
591 struct bufferevent *bev = NULL;
592 evutil_socket_t fd = -1;
593 const char *http_request;
594 ev_uint16_t port=0, port2=0;
597 exit_base = data->base;
599 http = http_setup(&port, data->base, 0);
601 /* bind to a second socket */
602 if (http_bind(http, &port2, 0) == -1)
603 TT_DIE(("Bind socket failed"));
605 /* NULL request test */
606 fd = http_connect("127.0.0.1", port);
607 tt_int_op(fd, >=, 0);
609 /* Stupid thing to send a request */
610 bev = bufferevent_socket_new(data->base, fd, 0);
611 bufferevent_setcb(bev, http_badreq_readcb, http_writecb,
612 http_badreq_errorcb, data->base);
613 bufferevent_enable(bev, EV_READ);
615 /* real NULL request */
618 bufferevent_write(bev, http_request, strlen(http_request));
620 shutdown(fd, SHUT_WR);
623 event_base_once(data->base, -1, EV_TIMEOUT, http_badreq_successcb, bev, &tv);
625 event_base_dispatch(data->base);
627 bufferevent_free(bev);
628 evutil_closesocket(fd);
631 fprintf(stdout, "FAILED\n");
635 /* Second answer (BAD REQUEST) on connection close */
637 /* connect to the second port */
638 fd = http_connect("127.0.0.1", port2);
640 /* Stupid thing to send a request */
641 bev = bufferevent_socket_new(data->base, fd, 0);
642 bufferevent_setcb(bev, http_badreq_readcb, http_writecb,
643 http_badreq_errorcb, data->base);
644 bufferevent_enable(bev, EV_READ);
646 /* first half of the http request */
648 "GET /badrequest HTTP/1.0\r\n" \
649 "Connection: Keep-Alive\r\n" \
652 bufferevent_write(bev, http_request, strlen(http_request));
656 event_base_once(data->base, -1, EV_TIMEOUT, http_badreq_successcb, bev, &tv);
658 event_base_dispatch(data->base);
660 tt_int_op(test_ok, ==, 2);
665 bufferevent_free(bev);
667 evutil_closesocket(fd);
670 static struct evhttp_connection *delayed_client;
673 http_large_delay_cb(struct evhttp_request *req, void *arg)
676 evutil_timerclear(&tv);
679 event_base_once(arg, -1, EV_TIMEOUT, http_delay_reply, req, &tv);
680 evhttp_connection_fail_(delayed_client, EVREQ_HTTP_EOF);
684 * HTTP DELETE test, just piggyback on the basic test
688 http_delete_cb(struct evhttp_request *req, void *arg)
690 struct evbuffer *evb = evbuffer_new();
691 int empty = evhttp_find_header(evhttp_request_get_input_headers(req), "Empty") != NULL;
693 /* Expecting a DELETE request */
694 if (evhttp_request_get_command(req) != EVHTTP_REQ_DELETE) {
695 fprintf(stdout, "FAILED (delete type)\n");
699 event_debug(("%s: called\n", __func__));
700 evbuffer_add_printf(evb, BASIC_REQUEST_BODY);
702 /* allow sending of an empty reply */
703 evhttp_send_reply(req, HTTP_OK, "Everything is fine",
704 !empty ? evb : NULL);
710 http_delete_test(void *arg)
712 struct basic_test_data *data = arg;
713 struct bufferevent *bev;
714 evutil_socket_t fd = -1;
715 const char *http_request;
716 ev_uint16_t port = 0;
720 http = http_setup(&port, data->base, 0);
723 fd = http_connect("127.0.0.1", port);
724 tt_int_op(fd, >=, 0);
726 /* Stupid thing to send a request */
727 bev = bufferevent_socket_new(data->base, fd, 0);
728 bufferevent_setcb(bev, http_readcb, http_writecb,
729 http_errorcb, data->base);
732 "DELETE /deleteit HTTP/1.1\r\n"
734 "Connection: close\r\n"
737 bufferevent_write(bev, http_request, strlen(http_request));
739 event_base_dispatch(data->base);
741 bufferevent_free(bev);
742 evutil_closesocket(fd);
747 tt_int_op(test_ok, ==, 2);
750 evutil_closesocket(fd);
754 http_sent_cb(struct evhttp_request *req, void *arg)
756 ev_uintptr_t val = (ev_uintptr_t)arg;
759 if (val != 0xDEADBEEF) {
760 fprintf(stdout, "FAILED on_complete_cb argument\n");
764 b = evhttp_request_get_output_buffer(req);
765 if (evbuffer_get_length(b) != 0) {
766 fprintf(stdout, "FAILED on_complete_cb output buffer not written\n");
770 event_debug(("%s: called\n", __func__));
776 http_on_complete_cb(struct evhttp_request *req, void *arg)
778 struct evbuffer *evb = evbuffer_new();
780 evhttp_request_set_on_complete_cb(req, http_sent_cb, (void *)0xDEADBEEF);
782 event_debug(("%s: called\n", __func__));
783 evbuffer_add_printf(evb, BASIC_REQUEST_BODY);
785 /* allow sending of an empty reply */
786 evhttp_send_reply(req, HTTP_OK, "Everything is fine", evb);
794 http_on_complete_test(void *arg)
796 struct basic_test_data *data = arg;
797 struct bufferevent *bev;
798 evutil_socket_t fd = -1;
799 const char *http_request;
800 ev_uint16_t port = 0;
804 http = http_setup(&port, data->base, 0);
806 fd = http_connect("127.0.0.1", port);
807 tt_int_op(fd, >=, 0);
809 /* Stupid thing to send a request */
810 bev = bufferevent_socket_new(data->base, fd, 0);
811 bufferevent_setcb(bev, http_readcb, http_writecb,
812 http_errorcb, data->base);
815 "GET /oncomplete HTTP/1.1\r\n"
817 "Connection: close\r\n"
820 bufferevent_write(bev, http_request, strlen(http_request));
822 event_base_dispatch(data->base);
824 bufferevent_free(bev);
828 tt_int_op(test_ok, ==, 4);
831 evutil_closesocket(fd);
835 http_allowed_methods_eventcb(struct bufferevent *bev, short what, void *arg)
838 if ((what & (BEV_EVENT_ERROR|BEV_EVENT_EOF))) {
841 n = evbuffer_remove(bufferevent_get_input(bev), buf,
847 *output = strdup(buf);
849 event_base_loopexit(exit_base, NULL);
854 http_allowed_methods_test(void *arg)
856 struct basic_test_data *data = arg;
857 struct bufferevent *bev1, *bev2, *bev3;
858 evutil_socket_t fd1=-1, fd2=-1, fd3=-1;
859 const char *http_request;
860 char *result1=NULL, *result2=NULL, *result3=NULL;
861 ev_uint16_t port = 0;
863 exit_base = data->base;
866 http = http_setup(&port, data->base, 0);
868 fd1 = http_connect("127.0.0.1", port);
869 tt_int_op(fd1, >=, 0);
871 /* GET is out; PATCH is in. */
872 evhttp_set_allowed_methods(http, EVHTTP_REQ_PATCH);
874 /* Stupid thing to send a request */
875 bev1 = bufferevent_socket_new(data->base, fd1, 0);
876 bufferevent_enable(bev1, EV_READ|EV_WRITE);
877 bufferevent_setcb(bev1, NULL, NULL,
878 http_allowed_methods_eventcb, &result1);
881 "GET /index.html HTTP/1.1\r\n"
883 "Connection: close\r\n"
886 bufferevent_write(bev1, http_request, strlen(http_request));
888 event_base_dispatch(data->base);
890 fd2 = http_connect("127.0.0.1", port);
891 tt_int_op(fd2, >=, 0);
893 bev2 = bufferevent_socket_new(data->base, fd2, 0);
894 bufferevent_enable(bev2, EV_READ|EV_WRITE);
895 bufferevent_setcb(bev2, NULL, NULL,
896 http_allowed_methods_eventcb, &result2);
899 "PATCH /test HTTP/1.1\r\n"
901 "Connection: close\r\n"
904 bufferevent_write(bev2, http_request, strlen(http_request));
906 event_base_dispatch(data->base);
908 fd3 = http_connect("127.0.0.1", port);
909 tt_int_op(fd3, >=, 0);
911 bev3 = bufferevent_socket_new(data->base, fd3, 0);
912 bufferevent_enable(bev3, EV_READ|EV_WRITE);
913 bufferevent_setcb(bev3, NULL, NULL,
914 http_allowed_methods_eventcb, &result3);
917 "FLOOP /test HTTP/1.1\r\n"
919 "Connection: close\r\n"
922 bufferevent_write(bev3, http_request, strlen(http_request));
924 event_base_dispatch(data->base);
926 bufferevent_free(bev1);
927 bufferevent_free(bev2);
928 bufferevent_free(bev3);
932 /* Method known but disallowed */
934 tt_assert(!strncmp(result1, "HTTP/1.1 501 ", strlen("HTTP/1.1 501 ")));
936 /* Method known and allowed */
938 tt_assert(!strncmp(result2, "HTTP/1.1 200 ", strlen("HTTP/1.1 200 ")));
942 tt_assert(!strncmp(result3, "HTTP/1.1 501 ", strlen("HTTP/1.1 501 ")));
952 evutil_closesocket(fd1);
954 evutil_closesocket(fd2);
956 evutil_closesocket(fd3);
959 static void http_request_done(struct evhttp_request *, void *);
960 static void http_request_empty_done(struct evhttp_request *, void *);
963 http_connection_test_(struct basic_test_data *data, int persistent,
964 const char *address, struct evdns_base *dnsbase, int ipv6, int family)
966 ev_uint16_t port = 0;
967 struct evhttp_connection *evcon = NULL;
968 struct evhttp_request *req = NULL;
972 http = http_setup(&port, data->base, ipv6);
978 evcon = evhttp_connection_base_new(data->base, dnsbase, address, port);
980 evhttp_connection_set_family(evcon, family);
982 tt_assert(evhttp_connection_get_base(evcon) == data->base);
984 exit_base = data->base;
986 tt_assert(evhttp_connection_get_server(evcon) == NULL);
989 * At this point, we want to schedule a request to the HTTP
990 * server using our make request method.
992 req = evhttp_request_new(http_request_done, (void*) BASIC_REQUEST_BODY);
994 /* Add the information that we care about */
995 evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
997 /* We give ownership of the request to the connection */
998 if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test") == -1) {
999 fprintf(stdout, "FAILED\n");
1003 event_base_dispatch(data->base);
1007 /* try to make another request over the same connection */
1010 req = evhttp_request_new(http_request_done, (void*) BASIC_REQUEST_BODY);
1012 /* Add the information that we care about */
1013 evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
1016 * if our connections are not supposed to be persistent; request
1017 * a close from the server.
1020 evhttp_add_header(evhttp_request_get_output_headers(req), "Connection", "close");
1022 /* We give ownership of the request to the connection */
1023 if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test") == -1) {
1024 tt_abort_msg("couldn't make request");
1027 event_base_dispatch(data->base);
1029 /* make another request: request empty reply */
1032 req = evhttp_request_new(http_request_empty_done, data->base);
1034 /* Add the information that we care about */
1035 evhttp_add_header(evhttp_request_get_output_headers(req), "Empty", "itis");
1037 /* We give ownership of the request to the connection */
1038 if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test") == -1) {
1039 tt_abort_msg("Couldn't make request");
1042 event_base_dispatch(data->base);
1046 evhttp_connection_free(evcon);
1052 http_connection_test(void *arg)
1054 http_connection_test_(arg, 0, "127.0.0.1", NULL, 0, AF_UNSPEC);
1057 http_persist_connection_test(void *arg)
1059 http_connection_test_(arg, 1, "127.0.0.1", NULL, 0, AF_UNSPEC);
1062 static struct regress_dns_server_table search_table[] = {
1063 { "localhost", "A", "127.0.0.1", 0 },
1064 { NULL, NULL, NULL, 0 }
1068 http_connection_async_test(void *arg)
1070 struct basic_test_data *data = arg;
1071 ev_uint16_t port = 0;
1072 struct evhttp_connection *evcon = NULL;
1073 struct evhttp_request *req = NULL;
1074 struct evdns_base *dns_base = NULL;
1075 ev_uint16_t portnum = 0;
1078 exit_base = data->base;
1079 tt_assert(regress_dnsserver(data->base, &portnum, search_table));
1081 dns_base = evdns_base_new(data->base, 0/* init name servers */);
1082 tt_assert(dns_base);
1084 /* Add ourself as the only nameserver, and make sure we really are
1085 * the only nameserver. */
1086 evutil_snprintf(address, sizeof(address), "127.0.0.1:%d", portnum);
1087 evdns_base_nameserver_ip_add(dns_base, address);
1091 http = http_setup(&port, data->base, 0);
1093 evcon = evhttp_connection_base_new(data->base, dns_base, "127.0.0.1", port);
1097 * At this point, we want to schedule a request to the HTTP
1098 * server using our make request method.
1101 req = evhttp_request_new(http_request_done, (void*) BASIC_REQUEST_BODY);
1103 /* Add the information that we care about */
1104 evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
1106 /* We give ownership of the request to the connection */
1107 if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test") == -1) {
1108 fprintf(stdout, "FAILED\n");
1112 event_base_dispatch(data->base);
1116 /* try to make another request over the same connection */
1119 req = evhttp_request_new(http_request_done, (void*) BASIC_REQUEST_BODY);
1121 /* Add the information that we care about */
1122 evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
1125 * if our connections are not supposed to be persistent; request
1126 * a close from the server.
1128 evhttp_add_header(evhttp_request_get_output_headers(req), "Connection", "close");
1130 /* We give ownership of the request to the connection */
1131 if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test") == -1) {
1132 tt_abort_msg("couldn't make request");
1135 event_base_dispatch(data->base);
1137 /* make another request: request empty reply */
1140 req = evhttp_request_new(http_request_empty_done, data->base);
1142 /* Add the information that we care about */
1143 evhttp_add_header(evhttp_request_get_output_headers(req), "Empty", "itis");
1145 /* We give ownership of the request to the connection */
1146 if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test") == -1) {
1147 tt_abort_msg("Couldn't make request");
1150 event_base_dispatch(data->base);
1154 evhttp_connection_free(evcon);
1158 evdns_base_free(dns_base, 0);
1159 regress_clean_dnsserver();
1163 http_autofree_connection_test(void *arg)
1165 struct basic_test_data *data = arg;
1166 ev_uint16_t port = 0;
1167 struct evhttp_connection *evcon = NULL;
1168 struct evhttp_request *req[2] = { NULL };
1171 http = http_setup(&port, data->base, 0);
1173 evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port);
1177 * At this point, we want to schedule two request to the HTTP
1178 * server using our make request method.
1180 req[0] = evhttp_request_new(http_request_empty_done, data->base);
1181 req[1] = evhttp_request_new(http_request_empty_done, data->base);
1183 /* Add the information that we care about */
1184 evhttp_add_header(evhttp_request_get_output_headers(req[0]), "Host", "somehost");
1185 evhttp_add_header(evhttp_request_get_output_headers(req[0]), "Connection", "close");
1186 evhttp_add_header(evhttp_request_get_output_headers(req[0]), "Empty", "itis");
1187 evhttp_add_header(evhttp_request_get_output_headers(req[1]), "Host", "somehost");
1188 evhttp_add_header(evhttp_request_get_output_headers(req[1]), "Connection", "close");
1189 evhttp_add_header(evhttp_request_get_output_headers(req[1]), "Empty", "itis");
1191 /* We give ownership of the request to the connection */
1192 if (evhttp_make_request(evcon, req[0], EVHTTP_REQ_GET, "/test") == -1) {
1193 tt_abort_msg("couldn't make request");
1195 if (evhttp_make_request(evcon, req[1], EVHTTP_REQ_GET, "/test") == -1) {
1196 tt_abort_msg("couldn't make request");
1200 * Tell libevent to free the connection when the request completes
1201 * We then set the evcon pointer to NULL since we don't want to free it
1202 * when this function ends.
1204 evhttp_connection_free_on_completion(evcon);
1207 event_base_dispatch(data->base);
1209 /* at this point, the http server should have no connection */
1210 tt_assert(TAILQ_FIRST(&http->connections) == NULL);
1214 evhttp_connection_free(evcon);
1220 http_request_never_call(struct evhttp_request *req, void *arg)
1222 fprintf(stdout, "FAILED\n");
1227 http_do_cancel(evutil_socket_t fd, short what, void *arg)
1229 struct evhttp_request *req = arg;
1231 struct event_base *base;
1232 evutil_timerclear(&tv);
1234 tv.tv_usec = 500 * 1000;
1236 base = evhttp_connection_get_base(evhttp_request_get_connection(req));
1237 evhttp_cancel_request(req);
1239 event_base_loopexit(base, &tv);
1245 http_cancel_test(void *arg)
1247 struct basic_test_data *data = arg;
1248 ev_uint16_t port = 0;
1249 struct evhttp_connection *evcon = NULL;
1250 struct evhttp_request *req = NULL;
1253 exit_base = data->base;
1257 http = http_setup(&port, data->base, 0);
1259 evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port);
1263 * At this point, we want to schedule a request to the HTTP
1264 * server using our make request method.
1267 req = evhttp_request_new(http_request_never_call, NULL);
1268 evhttp_request_set_error_cb(req, http_request_error_cb_with_cancel_);
1270 /* Add the information that we care about */
1271 evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
1273 /* We give ownership of the request to the connection */
1274 tt_int_op(evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/delay"),
1277 evutil_timerclear(&tv);
1279 tv.tv_usec = 100 * 1000;
1281 event_base_once(data->base, -1, EV_TIMEOUT, http_do_cancel, req, &tv);
1283 event_base_dispatch(data->base);
1285 tt_int_op(test_ok, ==, 3);
1287 /* try to make another request over the same connection */
1290 req = evhttp_request_new(http_request_done, (void*) BASIC_REQUEST_BODY);
1292 /* Add the information that we care about */
1293 evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
1295 /* We give ownership of the request to the connection */
1296 tt_int_op(evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test"),
1299 event_base_dispatch(data->base);
1301 /* make another request: request empty reply */
1304 req = evhttp_request_new(http_request_empty_done, data->base);
1306 /* Add the information that we care about */
1307 evhttp_add_header(evhttp_request_get_output_headers(req), "Empty", "itis");
1309 /* We give ownership of the request to the connection */
1310 tt_int_op(evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test"),
1313 event_base_dispatch(data->base);
1317 evhttp_connection_free(evcon);
1323 http_request_done(struct evhttp_request *req, void *arg)
1325 const char *what = arg;
1327 if (evhttp_request_get_response_code(req) != HTTP_OK) {
1328 fprintf(stderr, "FAILED\n");
1332 if (evhttp_find_header(evhttp_request_get_input_headers(req), "Content-Type") == NULL) {
1333 fprintf(stderr, "FAILED\n");
1337 if (evbuffer_get_length(evhttp_request_get_input_buffer(req)) != strlen(what)) {
1338 fprintf(stderr, "FAILED\n");
1342 if (evbuffer_datacmp(evhttp_request_get_input_buffer(req), what) != 0) {
1343 fprintf(stderr, "FAILED\n");
1348 EVUTIL_ASSERT(exit_base);
1349 event_base_loopexit(exit_base, NULL);
1353 http_request_expect_error(struct evhttp_request *req, void *arg)
1355 if (evhttp_request_get_response_code(req) == HTTP_OK) {
1356 fprintf(stderr, "FAILED\n");
1362 event_base_loopexit(arg, NULL);
1365 /* test virtual hosts */
1367 http_virtual_host_test(void *arg)
1369 struct basic_test_data *data = arg;
1370 ev_uint16_t port = 0;
1371 struct evhttp_connection *evcon = NULL;
1372 struct evhttp_request *req = NULL;
1373 struct evhttp *second = NULL, *third = NULL;
1375 struct bufferevent *bev;
1376 const char *http_request;
1378 exit_base = data->base;
1380 http = http_setup(&port, data->base, 0);
1383 second = evhttp_new(NULL);
1384 evhttp_set_cb(second, "/funnybunny", http_basic_cb, NULL);
1385 third = evhttp_new(NULL);
1386 evhttp_set_cb(third, "/blackcoffee", http_basic_cb, NULL);
1388 if (evhttp_add_virtual_host(http, "foo.com", second) == -1) {
1389 tt_abort_msg("Couldn't add vhost");
1392 if (evhttp_add_virtual_host(http, "bar.*.foo.com", third) == -1) {
1393 tt_abort_msg("Couldn't add wildcarded vhost");
1396 /* add some aliases to the vhosts */
1397 tt_assert(evhttp_add_server_alias(second, "manolito.info") == 0);
1398 tt_assert(evhttp_add_server_alias(third, "bonkers.org") == 0);
1400 evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port);
1403 /* make a request with a different host and expect an error */
1404 req = evhttp_request_new(http_request_expect_error, data->base);
1406 /* Add the information that we care about */
1407 evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
1409 /* We give ownership of the request to the connection */
1410 if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET,
1411 "/funnybunny") == -1) {
1412 tt_abort_msg("Couldn't make request");
1415 event_base_dispatch(data->base);
1417 tt_assert(test_ok == 1);
1421 /* make a request with the right host and expect a response */
1422 req = evhttp_request_new(http_request_done, (void*) BASIC_REQUEST_BODY);
1424 /* Add the information that we care about */
1425 evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "foo.com");
1427 /* We give ownership of the request to the connection */
1428 if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET,
1429 "/funnybunny") == -1) {
1430 fprintf(stdout, "FAILED\n");
1434 event_base_dispatch(data->base);
1436 tt_assert(test_ok == 1);
1440 /* make a request with the right host and expect a response */
1441 req = evhttp_request_new(http_request_done, (void*) BASIC_REQUEST_BODY);
1443 /* Add the information that we care about */
1444 evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "bar.magic.foo.com");
1446 /* We give ownership of the request to the connection */
1447 if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET,
1448 "/blackcoffee") == -1) {
1449 tt_abort_msg("Couldn't make request");
1452 event_base_dispatch(data->base);
1454 tt_assert(test_ok == 1)
1458 /* make a request with the right host and expect a response */
1459 req = evhttp_request_new(http_request_done, (void*) BASIC_REQUEST_BODY);
1461 /* Add the information that we care about */
1462 evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "manolito.info");
1464 /* We give ownership of the request to the connection */
1465 if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET,
1466 "/funnybunny") == -1) {
1467 tt_abort_msg("Couldn't make request");
1470 event_base_dispatch(data->base);
1472 tt_assert(test_ok == 1)
1476 /* make a request with the right host and expect a response */
1477 req = evhttp_request_new(http_request_done, (void*) BASIC_REQUEST_BODY);
1479 /* Add the Host header. This time with the optional port. */
1480 evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "bonkers.org:8000");
1482 /* We give ownership of the request to the connection */
1483 if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET,
1484 "/blackcoffee") == -1) {
1485 tt_abort_msg("Couldn't make request");
1488 event_base_dispatch(data->base);
1490 tt_assert(test_ok == 1)
1494 /* Now make a raw request with an absolute URI. */
1495 fd = http_connect("127.0.0.1", port);
1497 /* Stupid thing to send a request */
1498 bev = bufferevent_socket_new(data->base, fd, 0);
1499 bufferevent_setcb(bev, http_readcb, http_writecb,
1500 http_errorcb, NULL);
1502 /* The host in the URI should override the Host: header */
1504 "GET http://manolito.info/funnybunny HTTP/1.1\r\n"
1505 "Host: somehost\r\n"
1506 "Connection: close\r\n"
1509 bufferevent_write(bev, http_request, strlen(http_request));
1511 event_base_dispatch(data->base);
1513 tt_int_op(test_ok, ==, 2);
1515 bufferevent_free(bev);
1516 evutil_closesocket(fd);
1520 evhttp_connection_free(evcon);
1526 /* test date header and content length */
1529 http_request_empty_done(struct evhttp_request *req, void *arg)
1531 if (evhttp_request_get_response_code(req) != HTTP_OK) {
1532 fprintf(stderr, "FAILED\n");
1536 if (evhttp_find_header(evhttp_request_get_input_headers(req), "Date") == NULL) {
1537 fprintf(stderr, "FAILED\n");
1542 if (evhttp_find_header(evhttp_request_get_input_headers(req), "Content-Length") == NULL) {
1543 fprintf(stderr, "FAILED\n");
1547 if (strcmp(evhttp_find_header(evhttp_request_get_input_headers(req), "Content-Length"),
1549 fprintf(stderr, "FAILED\n");
1553 if (evbuffer_get_length(evhttp_request_get_input_buffer(req)) != 0) {
1554 fprintf(stderr, "FAILED\n");
1560 event_base_loopexit(arg, NULL);
1564 * HTTP DISPATCHER test
1568 http_dispatcher_cb(struct evhttp_request *req, void *arg)
1571 struct evbuffer *evb = evbuffer_new();
1572 event_debug(("%s: called\n", __func__));
1573 evbuffer_add_printf(evb, "DISPATCHER_TEST");
1575 evhttp_send_reply(req, HTTP_OK, "Everything is fine", evb);
1581 http_dispatcher_test_done(struct evhttp_request *req, void *arg)
1583 struct event_base *base = arg;
1584 const char *what = "DISPATCHER_TEST";
1586 if (evhttp_request_get_response_code(req) != HTTP_OK) {
1587 fprintf(stderr, "FAILED\n");
1591 if (evhttp_find_header(evhttp_request_get_input_headers(req), "Content-Type") == NULL) {
1592 fprintf(stderr, "FAILED (content type)\n");
1596 if (evbuffer_get_length(evhttp_request_get_input_buffer(req)) != strlen(what)) {
1597 fprintf(stderr, "FAILED (length %lu vs %lu)\n",
1598 (unsigned long)evbuffer_get_length(evhttp_request_get_input_buffer(req)), (unsigned long)strlen(what));
1602 if (evbuffer_datacmp(evhttp_request_get_input_buffer(req), what) != 0) {
1603 fprintf(stderr, "FAILED (data)\n");
1608 event_base_loopexit(base, NULL);
1612 http_dispatcher_test(void *arg)
1614 struct basic_test_data *data = arg;
1615 ev_uint16_t port = 0;
1616 struct evhttp_connection *evcon = NULL;
1617 struct evhttp_request *req = NULL;
1621 http = http_setup(&port, data->base, 0);
1623 evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port);
1626 /* also bind to local host */
1627 evhttp_connection_set_local_address(evcon, "127.0.0.1");
1630 * At this point, we want to schedule an HTTP GET request
1631 * server using our make request method.
1634 req = evhttp_request_new(http_dispatcher_test_done, data->base);
1637 /* Add the information that we care about */
1638 evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
1640 if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/?arg=val") == -1) {
1641 tt_abort_msg("Couldn't make request");
1644 event_base_dispatch(data->base);
1648 evhttp_connection_free(evcon);
1657 void http_postrequest_done(struct evhttp_request *, void *);
1659 #define POST_DATA "Okay. Not really printf"
1662 http_post_test(void *arg)
1664 struct basic_test_data *data = arg;
1665 ev_uint16_t port = 0;
1666 struct evhttp_connection *evcon = NULL;
1667 struct evhttp_request *req = NULL;
1671 http = http_setup(&port, data->base, 0);
1673 evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port);
1677 * At this point, we want to schedule an HTTP POST request
1678 * server using our make request method.
1681 req = evhttp_request_new(http_postrequest_done, data->base);
1684 /* Add the information that we care about */
1685 evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
1686 evbuffer_add_printf(evhttp_request_get_output_buffer(req), POST_DATA);
1688 if (evhttp_make_request(evcon, req, EVHTTP_REQ_POST, "/postit") == -1) {
1689 tt_abort_msg("Couldn't make request");
1692 event_base_dispatch(data->base);
1694 tt_int_op(test_ok, ==, 1);
1698 req = evhttp_request_new(http_postrequest_done, data->base);
1701 /* Now try with 100-continue. */
1703 /* Add the information that we care about */
1704 evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
1705 evhttp_add_header(evhttp_request_get_output_headers(req), "Expect", "100-continue");
1706 evbuffer_add_printf(evhttp_request_get_output_buffer(req), POST_DATA);
1708 if (evhttp_make_request(evcon, req, EVHTTP_REQ_POST, "/postit") == -1) {
1709 tt_abort_msg("Couldn't make request");
1712 event_base_dispatch(data->base);
1714 tt_int_op(test_ok, ==, 1);
1716 evhttp_connection_free(evcon);
1724 http_post_cb(struct evhttp_request *req, void *arg)
1726 struct evbuffer *evb;
1727 event_debug(("%s: called\n", __func__));
1729 /* Yes, we are expecting a post request */
1730 if (evhttp_request_get_command(req) != EVHTTP_REQ_POST) {
1731 fprintf(stdout, "FAILED (post type)\n");
1735 if (evbuffer_get_length(evhttp_request_get_input_buffer(req)) != strlen(POST_DATA)) {
1736 fprintf(stdout, "FAILED (length: %lu vs %lu)\n",
1737 (unsigned long) evbuffer_get_length(evhttp_request_get_input_buffer(req)), (unsigned long) strlen(POST_DATA));
1741 if (evbuffer_datacmp(evhttp_request_get_input_buffer(req), POST_DATA) != 0) {
1742 fprintf(stdout, "FAILED (data)\n");
1743 fprintf(stdout, "Got :%s\n", evbuffer_pullup(evhttp_request_get_input_buffer(req),-1));
1744 fprintf(stdout, "Want:%s\n", POST_DATA);
1748 evb = evbuffer_new();
1749 evbuffer_add_printf(evb, BASIC_REQUEST_BODY);
1751 evhttp_send_reply(req, HTTP_OK, "Everything is fine", evb);
1757 http_postrequest_done(struct evhttp_request *req, void *arg)
1759 const char *what = BASIC_REQUEST_BODY;
1760 struct event_base *base = arg;
1763 fprintf(stderr, "FAILED (timeout)\n");
1767 if (evhttp_request_get_response_code(req) != HTTP_OK) {
1769 fprintf(stderr, "FAILED (response code)\n");
1773 if (evhttp_find_header(evhttp_request_get_input_headers(req), "Content-Type") == NULL) {
1774 fprintf(stderr, "FAILED (content type)\n");
1778 if (evbuffer_get_length(evhttp_request_get_input_buffer(req)) != strlen(what)) {
1779 fprintf(stderr, "FAILED (length %lu vs %lu)\n",
1780 (unsigned long)evbuffer_get_length(evhttp_request_get_input_buffer(req)), (unsigned long)strlen(what));
1784 if (evbuffer_datacmp(evhttp_request_get_input_buffer(req), what) != 0) {
1785 fprintf(stderr, "FAILED (data)\n");
1790 event_base_loopexit(base, NULL);
1794 * HTTP PUT test, basically just like POST, but ...
1797 void http_putrequest_done(struct evhttp_request *, void *);
1799 #define PUT_DATA "Hi, I'm some PUT data"
1802 http_put_test(void *arg)
1804 struct basic_test_data *data = arg;
1805 ev_uint16_t port = 0;
1806 struct evhttp_connection *evcon = NULL;
1807 struct evhttp_request *req = NULL;
1811 http = http_setup(&port, data->base, 0);
1813 evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port);
1817 * Schedule the HTTP PUT request
1820 req = evhttp_request_new(http_putrequest_done, data->base);
1823 /* Add the information that we care about */
1824 evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "someotherhost");
1825 evbuffer_add_printf(evhttp_request_get_output_buffer(req), PUT_DATA);
1827 if (evhttp_make_request(evcon, req, EVHTTP_REQ_PUT, "/putit") == -1) {
1828 tt_abort_msg("Couldn't make request");
1831 event_base_dispatch(data->base);
1833 evhttp_connection_free(evcon);
1836 tt_int_op(test_ok, ==, 1);
1842 http_put_cb(struct evhttp_request *req, void *arg)
1844 struct evbuffer *evb;
1845 event_debug(("%s: called\n", __func__));
1847 /* Expecting a PUT request */
1848 if (evhttp_request_get_command(req) != EVHTTP_REQ_PUT) {
1849 fprintf(stdout, "FAILED (put type)\n");
1853 if (evbuffer_get_length(evhttp_request_get_input_buffer(req)) != strlen(PUT_DATA)) {
1854 fprintf(stdout, "FAILED (length: %lu vs %lu)\n",
1855 (unsigned long)evbuffer_get_length(evhttp_request_get_input_buffer(req)), (unsigned long)strlen(PUT_DATA));
1859 if (evbuffer_datacmp(evhttp_request_get_input_buffer(req), PUT_DATA) != 0) {
1860 fprintf(stdout, "FAILED (data)\n");
1861 fprintf(stdout, "Got :%s\n", evbuffer_pullup(evhttp_request_get_input_buffer(req),-1));
1862 fprintf(stdout, "Want:%s\n", PUT_DATA);
1866 evb = evbuffer_new();
1867 evbuffer_add_printf(evb, "That ain't funny");
1869 evhttp_send_reply(req, HTTP_OK, "Everything is great", evb);
1875 http_putrequest_done(struct evhttp_request *req, void *arg)
1877 struct event_base *base = arg;
1878 const char *what = "That ain't funny";
1881 fprintf(stderr, "FAILED (timeout)\n");
1885 if (evhttp_request_get_response_code(req) != HTTP_OK) {
1887 fprintf(stderr, "FAILED (response code)\n");
1891 if (evhttp_find_header(evhttp_request_get_input_headers(req), "Content-Type") == NULL) {
1892 fprintf(stderr, "FAILED (content type)\n");
1896 if (evbuffer_get_length(evhttp_request_get_input_buffer(req)) != strlen(what)) {
1897 fprintf(stderr, "FAILED (length %lu vs %lu)\n",
1898 (unsigned long)evbuffer_get_length(evhttp_request_get_input_buffer(req)), (unsigned long)strlen(what));
1903 if (evbuffer_datacmp(evhttp_request_get_input_buffer(req), what) != 0) {
1904 fprintf(stderr, "FAILED (data)\n");
1909 event_base_loopexit(base, NULL);
1913 http_failure_readcb(struct bufferevent *bev, void *arg)
1915 const char *what = "400 Bad Request";
1916 if (evbuffer_contains(bufferevent_get_input(bev), what)) {
1918 bufferevent_disable(bev, EV_READ);
1919 event_base_loopexit(arg, NULL);
1924 * Testing that the HTTP server can deal with a malformed request.
1927 http_failure_test(void *arg)
1929 struct basic_test_data *data = arg;
1930 struct bufferevent *bev;
1931 evutil_socket_t fd = -1;
1932 const char *http_request;
1933 ev_uint16_t port = 0;
1937 http = http_setup(&port, data->base, 0);
1939 fd = http_connect("127.0.0.1", port);
1940 tt_int_op(fd, >=, 0);
1942 /* Stupid thing to send a request */
1943 bev = bufferevent_socket_new(data->base, fd, 0);
1944 bufferevent_setcb(bev, http_failure_readcb, http_writecb,
1945 http_errorcb, data->base);
1947 http_request = "illegal request\r\n";
1949 bufferevent_write(bev, http_request, strlen(http_request));
1951 event_base_dispatch(data->base);
1953 bufferevent_free(bev);
1957 tt_int_op(test_ok, ==, 2);
1960 evutil_closesocket(fd);
1964 close_detect_done(struct evhttp_request *req, void *arg)
1968 tt_assert(evhttp_request_get_response_code(req) == HTTP_OK);
1973 evutil_timerclear(&tv);
1974 tv.tv_usec = 150000;
1975 event_base_loopexit(arg, &tv);
1979 close_detect_launch(evutil_socket_t fd, short what, void *arg)
1981 struct evhttp_connection *evcon = arg;
1982 struct event_base *base = evhttp_connection_get_base(evcon);
1983 struct evhttp_request *req;
1985 req = evhttp_request_new(close_detect_done, base);
1987 /* Add the information that we care about */
1988 evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
1990 /* We give ownership of the request to the connection */
1991 if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test") == -1) {
1992 tt_fail_msg("Couldn't make request");
1997 close_detect_cb(struct evhttp_request *req, void *arg)
1999 struct evhttp_connection *evcon = arg;
2000 struct event_base *base = evhttp_connection_get_base(evcon);
2003 if (req != NULL && evhttp_request_get_response_code(req) != HTTP_OK) {
2004 tt_abort_msg("Failed");
2007 evutil_timerclear(&tv);
2008 tv.tv_sec = 0; /* longer than the http time out */
2009 tv.tv_usec = 600000; /* longer than the http time out */
2011 /* launch a new request on the persistent connection in .3 seconds */
2012 event_base_once(base, -1, EV_TIMEOUT, close_detect_launch, evcon, &tv);
2019 http_close_detection_(struct basic_test_data *data, int with_delay)
2021 ev_uint16_t port = 0;
2022 struct evhttp_connection *evcon = NULL;
2023 struct evhttp_request *req = NULL;
2024 const struct timeval sec_tenth = { 0, 100000 };
2027 http = http_setup(&port, data->base, 0);
2029 /* .1 second timeout */
2030 evhttp_set_timeout_tv(http, &sec_tenth);
2032 evcon = evhttp_connection_base_new(data->base, NULL,
2035 evhttp_connection_set_timeout_tv(evcon, &sec_tenth);
2039 delayed_client = evcon;
2042 * At this point, we want to schedule a request to the HTTP
2043 * server using our make request method.
2046 req = evhttp_request_new(close_detect_cb, evcon);
2048 /* Add the information that we care about */
2049 evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
2051 /* We give ownership of the request to the connection */
2052 if (evhttp_make_request(evcon,
2053 req, EVHTTP_REQ_GET, with_delay ? "/largedelay" : "/test") == -1) {
2054 tt_abort_msg("couldn't make request");
2057 event_base_dispatch(data->base);
2059 /* at this point, the http server should have no connection */
2060 tt_assert(TAILQ_FIRST(&http->connections) == NULL);
2064 evhttp_connection_free(evcon);
2069 http_close_detection_test(void *arg)
2071 http_close_detection_(arg, 0);
2074 http_close_detection_delay_test(void *arg)
2076 http_close_detection_(arg, 1);
2080 http_highport_test(void *arg)
2082 struct basic_test_data *data = arg;
2084 struct evhttp *myhttp = NULL;
2086 /* Try a few different ports */
2087 for (i = 0; i < 50; ++i) {
2088 myhttp = evhttp_new(data->base);
2089 if (evhttp_bind_socket(myhttp, "127.0.0.1", 65535 - i) == 0) {
2091 evhttp_free(myhttp);
2094 evhttp_free(myhttp);
2097 tt_fail_msg("Couldn't get a high port");
2101 http_bad_header_test(void *ptr)
2103 struct evkeyvalq headers;
2105 TAILQ_INIT(&headers);
2107 tt_want(evhttp_add_header(&headers, "One", "Two") == 0);
2108 tt_want(evhttp_add_header(&headers, "One", "Two\r\n Three") == 0);
2109 tt_want(evhttp_add_header(&headers, "One\r", "Two") == -1);
2110 tt_want(evhttp_add_header(&headers, "One\n", "Two") == -1);
2111 tt_want(evhttp_add_header(&headers, "One", "Two\r") == -1);
2112 tt_want(evhttp_add_header(&headers, "One", "Two\n") == -1);
2114 evhttp_clear_headers(&headers);
2117 static int validate_header(
2118 const struct evkeyvalq* headers,
2119 const char *key, const char *value)
2121 const char *real_val = evhttp_find_header(headers, key);
2122 tt_assert(real_val != NULL);
2123 tt_want(strcmp(real_val, value) == 0);
2129 http_parse_query_test(void *ptr)
2131 struct evkeyvalq headers;
2134 TAILQ_INIT(&headers);
2136 r = evhttp_parse_query("http://www.test.com/?q=test", &headers);
2137 tt_want(validate_header(&headers, "q", "test") == 0);
2138 tt_int_op(r, ==, 0);
2139 evhttp_clear_headers(&headers);
2141 r = evhttp_parse_query("http://www.test.com/?q=test&foo=bar", &headers);
2142 tt_want(validate_header(&headers, "q", "test") == 0);
2143 tt_want(validate_header(&headers, "foo", "bar") == 0);
2144 tt_int_op(r, ==, 0);
2145 evhttp_clear_headers(&headers);
2147 r = evhttp_parse_query("http://www.test.com/?q=test+foo", &headers);
2148 tt_want(validate_header(&headers, "q", "test foo") == 0);
2149 tt_int_op(r, ==, 0);
2150 evhttp_clear_headers(&headers);
2152 r = evhttp_parse_query("http://www.test.com/?q=test%0Afoo", &headers);
2153 tt_want(validate_header(&headers, "q", "test\nfoo") == 0);
2154 tt_int_op(r, ==, 0);
2155 evhttp_clear_headers(&headers);
2157 r = evhttp_parse_query("http://www.test.com/?q=test%0Dfoo", &headers);
2158 tt_want(validate_header(&headers, "q", "test\rfoo") == 0);
2159 tt_int_op(r, ==, 0);
2160 evhttp_clear_headers(&headers);
2162 r = evhttp_parse_query("http://www.test.com/?q=test&&q2", &headers);
2163 tt_int_op(r, ==, -1);
2164 evhttp_clear_headers(&headers);
2166 r = evhttp_parse_query("http://www.test.com/?q=test+this", &headers);
2167 tt_want(validate_header(&headers, "q", "test this") == 0);
2168 tt_int_op(r, ==, 0);
2169 evhttp_clear_headers(&headers);
2171 r = evhttp_parse_query("http://www.test.com/?q=test&q2=foo", &headers);
2172 tt_int_op(r, ==, 0);
2173 tt_want(validate_header(&headers, "q", "test") == 0);
2174 tt_want(validate_header(&headers, "q2", "foo") == 0);
2175 evhttp_clear_headers(&headers);
2177 r = evhttp_parse_query("http://www.test.com/?q&q2=foo", &headers);
2178 tt_int_op(r, ==, -1);
2179 evhttp_clear_headers(&headers);
2181 r = evhttp_parse_query("http://www.test.com/?q=foo&q2", &headers);
2182 tt_int_op(r, ==, -1);
2183 evhttp_clear_headers(&headers);
2185 r = evhttp_parse_query("http://www.test.com/?q=foo&q2&q3=x", &headers);
2186 tt_int_op(r, ==, -1);
2187 evhttp_clear_headers(&headers);
2189 r = evhttp_parse_query("http://www.test.com/?q=&q2=&q3=", &headers);
2190 tt_int_op(r, ==, 0);
2191 tt_want(validate_header(&headers, "q", "") == 0);
2192 tt_want(validate_header(&headers, "q2", "") == 0);
2193 tt_want(validate_header(&headers, "q3", "") == 0);
2194 evhttp_clear_headers(&headers);
2197 evhttp_clear_headers(&headers);
2201 http_parse_uri_test(void *ptr)
2203 const int nonconform = (ptr != NULL);
2204 const unsigned parse_flags =
2205 nonconform ? EVHTTP_URI_NONCONFORMANT : 0;
2206 struct evhttp_uri *uri = NULL;
2208 #define URI_PARSE(uri) \
2209 evhttp_uri_parse_with_flags((uri), parse_flags)
2211 #define TT_URI(want) do { \
2212 char *ret = evhttp_uri_join(uri, url_tmp, sizeof(url_tmp)); \
2213 tt_want(ret != NULL); \
2214 tt_want(ret == url_tmp); \
2215 if (strcmp(ret,want) != 0) \
2216 TT_FAIL(("\"%s\" != \"%s\"",ret,want)); \
2219 tt_want(evhttp_uri_join(NULL, 0, 0) == NULL);
2220 tt_want(evhttp_uri_join(NULL, url_tmp, 0) == NULL);
2221 tt_want(evhttp_uri_join(NULL, url_tmp, sizeof(url_tmp)) == NULL);
2223 /* bad URIs: parsing */
2224 #define BAD(s) do { \
2225 if (URI_PARSE(s) != NULL) \
2226 TT_FAIL(("Expected error parsing \"%s\"",s)); \
2228 /* Nonconformant URIs we can parse: parsing */
2229 #define NCF(s) do { \
2230 uri = URI_PARSE(s); \
2231 if (uri != NULL && !nonconform) { \
2232 TT_FAIL(("Expected error parsing \"%s\"",s)); \
2233 } else if (uri == NULL && nonconform) { \
2234 TT_FAIL(("Couldn't parse nonconformant URI \"%s\"", \
2238 tt_want(evhttp_uri_join(uri, url_tmp, \
2239 sizeof(url_tmp))); \
2240 evhttp_uri_free(uri); \
2244 NCF("http://www.test.com/ why hello");
2245 NCF("http://www.test.com/why-hello\x01");
2246 NCF("http://www.test.com/why-hello?\x01");
2247 NCF("http://www.test.com/why-hello#\x01");
2248 BAD("http://www.\x01.test.com/why-hello");
2249 BAD("http://www.%7test.com/why-hello");
2250 NCF("http://www.test.com/why-hell%7o");
2251 BAD("h%3ttp://www.test.com/why-hello");
2252 NCF("http://www.test.com/why-hello%7");
2253 NCF("http://www.test.com/why-hell%7o");
2254 NCF("http://www.test.com/foo?ba%r");
2255 NCF("http://www.test.com/foo#ba%r");
2257 BAD("http://www.test.com:999x/");
2258 BAD("http://www.test.com:x/");
2259 BAD("http://[hello-there]/");
2260 BAD("http://[::1]]/");
2261 BAD("http://[::1/");
2262 BAD("http://[foob/");
2264 BAD("http://[ffff:ffff:ffff:ffff:Ffff:ffff:ffff:"
2265 "ffff:ffff:ffff:ffff:ffff:ffff:ffff]/");
2266 BAD("http://[vX.foo]/");
2267 BAD("http://[vX.foo]/");
2268 BAD("http://[v.foo]/");
2269 BAD("http://[v5.fo%o]/");
2270 BAD("http://[v5X]/");
2271 BAD("http://[v5]/");
2273 BAD("http://f\x01red@www.example.com/");
2274 BAD("http://f%0red@www.example.com/");
2275 BAD("http://www.example.com:9999999999999999999999999999999999999/");
2276 BAD("http://www.example.com:hihi/");
2277 BAD("://www.example.com/");
2279 /* bad URIs: joining */
2280 uri = evhttp_uri_new();
2281 tt_want(0==evhttp_uri_set_host(uri, "www.example.com"));
2282 tt_want(evhttp_uri_join(uri, url_tmp, sizeof(url_tmp)) != NULL);
2283 /* not enough space: */
2284 tt_want(evhttp_uri_join(uri, url_tmp, 3) == NULL);
2285 /* host is set, but path doesn't start with "/": */
2286 tt_want(0==evhttp_uri_set_path(uri, "hi_mom"));
2287 tt_want(evhttp_uri_join(uri, url_tmp, sizeof(url_tmp)) == NULL);
2288 tt_want(evhttp_uri_join(uri, NULL, sizeof(url_tmp))==NULL);
2289 tt_want(evhttp_uri_join(uri, url_tmp, 0)==NULL);
2290 evhttp_uri_free(uri);
2291 uri = URI_PARSE("mailto:foo@bar");
2292 tt_want(uri != NULL);
2293 tt_want(evhttp_uri_get_host(uri) == NULL);
2294 tt_want(evhttp_uri_get_userinfo(uri) == NULL);
2295 tt_want(evhttp_uri_get_port(uri) == -1);
2296 tt_want(!strcmp(evhttp_uri_get_scheme(uri), "mailto"));
2297 tt_want(!strcmp(evhttp_uri_get_path(uri), "foo@bar"));
2298 tt_want(evhttp_uri_get_query(uri) == NULL);
2299 tt_want(evhttp_uri_get_fragment(uri) == NULL);
2300 TT_URI("mailto:foo@bar");
2301 evhttp_uri_free(uri);
2303 uri = evhttp_uri_new();
2304 /* Bad URI usage: setting invalid values */
2305 tt_want(-1 == evhttp_uri_set_scheme(uri,""));
2306 tt_want(-1 == evhttp_uri_set_scheme(uri,"33"));
2307 tt_want(-1 == evhttp_uri_set_scheme(uri,"hi!"));
2308 tt_want(-1 == evhttp_uri_set_userinfo(uri,"hello@"));
2309 tt_want(-1 == evhttp_uri_set_host(uri,"[1.2.3.4]"));
2310 tt_want(-1 == evhttp_uri_set_host(uri,"["));
2311 tt_want(-1 == evhttp_uri_set_host(uri,"www.[foo].com"));
2312 tt_want(-1 == evhttp_uri_set_port(uri,-3));
2313 tt_want(-1 == evhttp_uri_set_path(uri,"hello?world"));
2314 tt_want(-1 == evhttp_uri_set_query(uri,"hello#world"));
2315 tt_want(-1 == evhttp_uri_set_fragment(uri,"hello#world"));
2316 /* Valid URI usage: setting valid values */
2317 tt_want(0 == evhttp_uri_set_scheme(uri,"http"));
2318 tt_want(0 == evhttp_uri_set_scheme(uri,NULL));
2319 tt_want(0 == evhttp_uri_set_userinfo(uri,"username:pass"));
2320 tt_want(0 == evhttp_uri_set_userinfo(uri,NULL));
2321 tt_want(0 == evhttp_uri_set_host(uri,"www.example.com"));
2322 tt_want(0 == evhttp_uri_set_host(uri,"1.2.3.4"));
2323 tt_want(0 == evhttp_uri_set_host(uri,"[1:2:3:4::]"));
2324 tt_want(0 == evhttp_uri_set_host(uri,"[v7.wobblewobble]"));
2325 tt_want(0 == evhttp_uri_set_host(uri,NULL));
2326 tt_want(0 == evhttp_uri_set_host(uri,""));
2327 tt_want(0 == evhttp_uri_set_port(uri, -1));
2328 tt_want(0 == evhttp_uri_set_port(uri, 80));
2329 tt_want(0 == evhttp_uri_set_port(uri, 65535));
2330 tt_want(0 == evhttp_uri_set_path(uri, ""));
2331 tt_want(0 == evhttp_uri_set_path(uri, "/documents/public/index.html"));
2332 tt_want(0 == evhttp_uri_set_path(uri, NULL));
2333 tt_want(0 == evhttp_uri_set_query(uri, "key=val&key2=val2"));
2334 tt_want(0 == evhttp_uri_set_query(uri, "keyvalblarg"));
2335 tt_want(0 == evhttp_uri_set_query(uri, ""));
2336 tt_want(0 == evhttp_uri_set_query(uri, NULL));
2337 tt_want(0 == evhttp_uri_set_fragment(uri, ""));
2338 tt_want(0 == evhttp_uri_set_fragment(uri, "here?i?am"));
2339 tt_want(0 == evhttp_uri_set_fragment(uri, NULL));
2340 evhttp_uri_free(uri);
2343 uri = URI_PARSE("http://www.test.com/?q=t%33est");
2344 tt_want(strcmp(evhttp_uri_get_scheme(uri), "http") == 0);
2345 tt_want(strcmp(evhttp_uri_get_host(uri), "www.test.com") == 0);
2346 tt_want(strcmp(evhttp_uri_get_path(uri), "/") == 0);
2347 tt_want(strcmp(evhttp_uri_get_query(uri), "q=t%33est") == 0);
2348 tt_want(evhttp_uri_get_userinfo(uri) == NULL);
2349 tt_want(evhttp_uri_get_port(uri) == -1);
2350 tt_want(evhttp_uri_get_fragment(uri) == NULL);
2351 TT_URI("http://www.test.com/?q=t%33est");
2352 evhttp_uri_free(uri);
2354 uri = URI_PARSE("http://%77ww.test.com");
2355 tt_want(strcmp(evhttp_uri_get_scheme(uri), "http") == 0);
2356 tt_want(strcmp(evhttp_uri_get_host(uri), "%77ww.test.com") == 0);
2357 tt_want(strcmp(evhttp_uri_get_path(uri), "") == 0);
2358 tt_want(evhttp_uri_get_query(uri) == NULL);
2359 tt_want(evhttp_uri_get_userinfo(uri) == NULL);
2360 tt_want(evhttp_uri_get_port(uri) == -1);
2361 tt_want(evhttp_uri_get_fragment(uri) == NULL);
2362 TT_URI("http://%77ww.test.com");
2363 evhttp_uri_free(uri);
2365 uri = URI_PARSE("http://www.test.com?q=test");
2366 tt_want(strcmp(evhttp_uri_get_scheme(uri), "http") == 0);
2367 tt_want(strcmp(evhttp_uri_get_host(uri), "www.test.com") == 0);
2368 tt_want(strcmp(evhttp_uri_get_path(uri), "") == 0);
2369 tt_want(strcmp(evhttp_uri_get_query(uri), "q=test") == 0);
2370 tt_want(evhttp_uri_get_userinfo(uri) == NULL);
2371 tt_want(evhttp_uri_get_port(uri) == -1);
2372 tt_want(evhttp_uri_get_fragment(uri) == NULL);
2373 TT_URI("http://www.test.com?q=test");
2374 evhttp_uri_free(uri);
2376 uri = URI_PARSE("http://www.test.com#fragment");
2377 tt_want(strcmp(evhttp_uri_get_scheme(uri), "http") == 0);
2378 tt_want(strcmp(evhttp_uri_get_host(uri), "www.test.com") == 0);
2379 tt_want(strcmp(evhttp_uri_get_path(uri), "") == 0);
2380 tt_want(evhttp_uri_get_query(uri) == NULL);
2381 tt_want(evhttp_uri_get_userinfo(uri) == NULL);
2382 tt_want(evhttp_uri_get_port(uri) == -1);
2383 tt_want_str_op(evhttp_uri_get_fragment(uri), ==, "fragment");
2384 TT_URI("http://www.test.com#fragment");
2385 evhttp_uri_free(uri);
2387 uri = URI_PARSE("http://8000/");
2388 tt_want(strcmp(evhttp_uri_get_scheme(uri), "http") == 0);
2389 tt_want(strcmp(evhttp_uri_get_host(uri), "8000") == 0);
2390 tt_want(strcmp(evhttp_uri_get_path(uri), "/") == 0);
2391 tt_want(evhttp_uri_get_query(uri) == NULL);
2392 tt_want(evhttp_uri_get_userinfo(uri) == NULL);
2393 tt_want(evhttp_uri_get_port(uri) == -1);
2394 tt_want(evhttp_uri_get_fragment(uri) == NULL);
2395 TT_URI("http://8000/");
2396 evhttp_uri_free(uri);
2398 uri = URI_PARSE("http://:8000/");
2399 tt_want(strcmp(evhttp_uri_get_scheme(uri), "http") == 0);
2400 tt_want(strcmp(evhttp_uri_get_host(uri), "") == 0);
2401 tt_want(strcmp(evhttp_uri_get_path(uri), "/") == 0);
2402 tt_want(evhttp_uri_get_query(uri) == NULL);
2403 tt_want(evhttp_uri_get_userinfo(uri) == NULL);
2404 tt_want(evhttp_uri_get_port(uri) == 8000);
2405 tt_want(evhttp_uri_get_fragment(uri) == NULL);
2406 TT_URI("http://:8000/");
2407 evhttp_uri_free(uri);
2409 uri = URI_PARSE("http://www.test.com:/"); /* empty port */
2410 tt_want(strcmp(evhttp_uri_get_scheme(uri), "http") == 0);
2411 tt_want(strcmp(evhttp_uri_get_host(uri), "www.test.com") == 0);
2412 tt_want_str_op(evhttp_uri_get_path(uri), ==, "/");
2413 tt_want(evhttp_uri_get_query(uri) == NULL);
2414 tt_want(evhttp_uri_get_userinfo(uri) == NULL);
2415 tt_want(evhttp_uri_get_port(uri) == -1);
2416 tt_want(evhttp_uri_get_fragment(uri) == NULL);
2417 TT_URI("http://www.test.com/");
2418 evhttp_uri_free(uri);
2420 uri = URI_PARSE("http://www.test.com:"); /* empty port 2 */
2421 tt_want(strcmp(evhttp_uri_get_scheme(uri), "http") == 0);
2422 tt_want(strcmp(evhttp_uri_get_host(uri), "www.test.com") == 0);
2423 tt_want(strcmp(evhttp_uri_get_path(uri), "") == 0);
2424 tt_want(evhttp_uri_get_query(uri) == NULL);
2425 tt_want(evhttp_uri_get_userinfo(uri) == NULL);
2426 tt_want(evhttp_uri_get_port(uri) == -1);
2427 tt_want(evhttp_uri_get_fragment(uri) == NULL);
2428 TT_URI("http://www.test.com");
2429 evhttp_uri_free(uri);
2431 uri = URI_PARSE("ftp://www.test.com/?q=test");
2432 tt_want(strcmp(evhttp_uri_get_scheme(uri), "ftp") == 0);
2433 tt_want(strcmp(evhttp_uri_get_host(uri), "www.test.com") == 0);
2434 tt_want(strcmp(evhttp_uri_get_path(uri), "/") == 0);
2435 tt_want(strcmp(evhttp_uri_get_query(uri), "q=test") == 0);
2436 tt_want(evhttp_uri_get_userinfo(uri) == NULL);
2437 tt_want(evhttp_uri_get_port(uri) == -1);
2438 tt_want(evhttp_uri_get_fragment(uri) == NULL);
2439 TT_URI("ftp://www.test.com/?q=test");
2440 evhttp_uri_free(uri);
2442 uri = URI_PARSE("ftp://[::1]:999/?q=test");
2443 tt_want(strcmp(evhttp_uri_get_scheme(uri), "ftp") == 0);
2444 tt_want(strcmp(evhttp_uri_get_host(uri), "[::1]") == 0);
2445 tt_want(strcmp(evhttp_uri_get_path(uri), "/") == 0);
2446 tt_want(strcmp(evhttp_uri_get_query(uri), "q=test") == 0);
2447 tt_want(evhttp_uri_get_userinfo(uri) == NULL);
2448 tt_want(evhttp_uri_get_port(uri) == 999);
2449 tt_want(evhttp_uri_get_fragment(uri) == NULL);
2450 TT_URI("ftp://[::1]:999/?q=test");
2451 evhttp_uri_free(uri);
2453 uri = URI_PARSE("ftp://[ff00::127.0.0.1]/?q=test");
2454 tt_want(strcmp(evhttp_uri_get_scheme(uri), "ftp") == 0);
2455 tt_want(strcmp(evhttp_uri_get_host(uri), "[ff00::127.0.0.1]") == 0);
2456 tt_want(strcmp(evhttp_uri_get_path(uri), "/") == 0);
2457 tt_want(strcmp(evhttp_uri_get_query(uri), "q=test") == 0);
2458 tt_want(evhttp_uri_get_userinfo(uri) == NULL);
2459 tt_want(evhttp_uri_get_port(uri) == -1);
2460 tt_want(evhttp_uri_get_fragment(uri) == NULL);
2461 TT_URI("ftp://[ff00::127.0.0.1]/?q=test");
2462 evhttp_uri_free(uri);
2464 uri = URI_PARSE("ftp://[v99.not_(any:time)_soon]/?q=test");
2465 tt_want(strcmp(evhttp_uri_get_scheme(uri), "ftp") == 0);
2466 tt_want(strcmp(evhttp_uri_get_host(uri), "[v99.not_(any:time)_soon]") == 0);
2467 tt_want(strcmp(evhttp_uri_get_path(uri), "/") == 0);
2468 tt_want(strcmp(evhttp_uri_get_query(uri), "q=test") == 0);
2469 tt_want(evhttp_uri_get_userinfo(uri) == NULL);
2470 tt_want(evhttp_uri_get_port(uri) == -1);
2471 tt_want(evhttp_uri_get_fragment(uri) == NULL);
2472 TT_URI("ftp://[v99.not_(any:time)_soon]/?q=test");
2473 evhttp_uri_free(uri);
2475 uri = URI_PARSE("scheme://user:pass@foo.com:42/?q=test&s=some+thing#fragment");
2476 tt_want(strcmp(evhttp_uri_get_scheme(uri), "scheme") == 0);
2477 tt_want(strcmp(evhttp_uri_get_userinfo(uri), "user:pass") == 0);
2478 tt_want(strcmp(evhttp_uri_get_host(uri), "foo.com") == 0);
2479 tt_want(evhttp_uri_get_port(uri) == 42);
2480 tt_want(strcmp(evhttp_uri_get_path(uri), "/") == 0);
2481 tt_want(strcmp(evhttp_uri_get_query(uri), "q=test&s=some+thing") == 0);
2482 tt_want(strcmp(evhttp_uri_get_fragment(uri), "fragment") == 0);
2483 TT_URI("scheme://user:pass@foo.com:42/?q=test&s=some+thing#fragment");
2484 evhttp_uri_free(uri);
2486 uri = URI_PARSE("scheme://user@foo.com/#fragment");
2487 tt_want(strcmp(evhttp_uri_get_scheme(uri), "scheme") == 0);
2488 tt_want(strcmp(evhttp_uri_get_userinfo(uri), "user") == 0);
2489 tt_want(strcmp(evhttp_uri_get_host(uri), "foo.com") == 0);
2490 tt_want(evhttp_uri_get_port(uri) == -1);
2491 tt_want(strcmp(evhttp_uri_get_path(uri), "/") == 0);
2492 tt_want(evhttp_uri_get_query(uri) == NULL);
2493 tt_want(strcmp(evhttp_uri_get_fragment(uri), "fragment") == 0);
2494 TT_URI("scheme://user@foo.com/#fragment");
2495 evhttp_uri_free(uri);
2497 uri = URI_PARSE("scheme://%75ser@foo.com/#frag@ment");
2498 tt_want(strcmp(evhttp_uri_get_scheme(uri), "scheme") == 0);
2499 tt_want(strcmp(evhttp_uri_get_userinfo(uri), "%75ser") == 0);
2500 tt_want(strcmp(evhttp_uri_get_host(uri), "foo.com") == 0);
2501 tt_want(evhttp_uri_get_port(uri) == -1);
2502 tt_want(strcmp(evhttp_uri_get_path(uri), "/") == 0);
2503 tt_want(evhttp_uri_get_query(uri) == NULL);
2504 tt_want(strcmp(evhttp_uri_get_fragment(uri), "frag@ment") == 0);
2505 TT_URI("scheme://%75ser@foo.com/#frag@ment");
2506 evhttp_uri_free(uri);
2508 uri = URI_PARSE("file:///some/path/to/the/file");
2509 tt_want(strcmp(evhttp_uri_get_scheme(uri), "file") == 0);
2510 tt_want(evhttp_uri_get_userinfo(uri) == NULL);
2511 tt_want(strcmp(evhttp_uri_get_host(uri), "") == 0);
2512 tt_want(evhttp_uri_get_port(uri) == -1);
2513 tt_want(strcmp(evhttp_uri_get_path(uri), "/some/path/to/the/file") == 0);
2514 tt_want(evhttp_uri_get_query(uri) == NULL);
2515 tt_want(evhttp_uri_get_fragment(uri) == NULL);
2516 TT_URI("file:///some/path/to/the/file");
2517 evhttp_uri_free(uri);
2519 uri = URI_PARSE("///some/path/to/the-file");
2520 tt_want(uri != NULL);
2521 tt_want(evhttp_uri_get_scheme(uri) == NULL);
2522 tt_want(evhttp_uri_get_userinfo(uri) == NULL);
2523 tt_want(strcmp(evhttp_uri_get_host(uri), "") == 0);
2524 tt_want(evhttp_uri_get_port(uri) == -1);
2525 tt_want(strcmp(evhttp_uri_get_path(uri), "/some/path/to/the-file") == 0);
2526 tt_want(evhttp_uri_get_query(uri) == NULL);
2527 tt_want(evhttp_uri_get_fragment(uri) == NULL);
2528 TT_URI("///some/path/to/the-file");
2529 evhttp_uri_free(uri);
2531 uri = URI_PARSE("/s:ome/path/to/the-file?q=99#fred");
2532 tt_want(uri != NULL);
2533 tt_want(evhttp_uri_get_scheme(uri) == NULL);
2534 tt_want(evhttp_uri_get_userinfo(uri) == NULL);
2535 tt_want(evhttp_uri_get_host(uri) == NULL);
2536 tt_want(evhttp_uri_get_port(uri) == -1);
2537 tt_want(strcmp(evhttp_uri_get_path(uri), "/s:ome/path/to/the-file") == 0);
2538 tt_want(strcmp(evhttp_uri_get_query(uri), "q=99") == 0);
2539 tt_want(strcmp(evhttp_uri_get_fragment(uri), "fred") == 0);
2540 TT_URI("/s:ome/path/to/the-file?q=99#fred");
2541 evhttp_uri_free(uri);
2543 uri = URI_PARSE("relative/path/with/co:lon");
2544 tt_want(uri != NULL);
2545 tt_want(evhttp_uri_get_scheme(uri) == NULL);
2546 tt_want(evhttp_uri_get_userinfo(uri) == NULL);
2547 tt_want(evhttp_uri_get_host(uri) == NULL);
2548 tt_want(evhttp_uri_get_port(uri) == -1);
2549 tt_want(strcmp(evhttp_uri_get_path(uri), "relative/path/with/co:lon") == 0);
2550 tt_want(evhttp_uri_get_query(uri) == NULL);
2551 tt_want(evhttp_uri_get_fragment(uri) == NULL);
2552 TT_URI("relative/path/with/co:lon");
2553 evhttp_uri_free(uri);
2555 uri = URI_PARSE("bob?q=99&q2=q?33#fr?ed");
2556 tt_want(uri != NULL);
2557 tt_want(evhttp_uri_get_scheme(uri) == NULL);
2558 tt_want(evhttp_uri_get_userinfo(uri) == NULL);
2559 tt_want(evhttp_uri_get_host(uri) == NULL);
2560 tt_want(evhttp_uri_get_port(uri) == -1);
2561 tt_want(strcmp(evhttp_uri_get_path(uri), "bob") == 0);
2562 tt_want(strcmp(evhttp_uri_get_query(uri), "q=99&q2=q?33") == 0);
2563 tt_want(strcmp(evhttp_uri_get_fragment(uri), "fr?ed") == 0);
2564 TT_URI("bob?q=99&q2=q?33#fr?ed");
2565 evhttp_uri_free(uri);
2567 uri = URI_PARSE("#fr?ed");
2568 tt_want(uri != NULL);
2569 tt_want(evhttp_uri_get_scheme(uri) == NULL);
2570 tt_want(evhttp_uri_get_userinfo(uri) == NULL);
2571 tt_want(evhttp_uri_get_host(uri) == NULL);
2572 tt_want(evhttp_uri_get_port(uri) == -1);
2573 tt_want(strcmp(evhttp_uri_get_path(uri), "") == 0);
2574 tt_want(evhttp_uri_get_query(uri) == NULL);
2575 tt_want(strcmp(evhttp_uri_get_fragment(uri), "fr?ed") == 0);
2577 evhttp_uri_free(uri);
2584 http_uriencode_test(void *ptr)
2586 char *s=NULL, *s2=NULL;
2590 #define ENC(from,want,plus) do { \
2591 s = evhttp_uriencode((from), -1, (plus)); \
2593 tt_str_op(s,==,(want)); \
2595 s2 = evhttp_uridecode((s), (plus), &sz); \
2597 tt_str_op(s2,==,(from)); \
2598 tt_int_op(sz,==,strlen(from)); \
2604 #define DEC(from,want,dp) do { \
2605 s = evhttp_uridecode((from),(dp),&sz); \
2607 tt_str_op(s,==,(want)); \
2608 tt_int_op(sz,==,strlen(want)); \
2613 #define OLD_DEC(from,want) do { \
2614 s = evhttp_decode_uri((from)); \
2616 tt_str_op(s,==,(want)); \
2622 ENC("Hello", "Hello",0);
2626 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ123456789-.~_",
2627 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ123456789-.~_",0);
2630 ENC("\xff\xf0\xe0", "%FF%F0%E0",0);
2631 ENC("\x01\x19", "%01%19",1);
2632 ENC("http://www.ietf.org/rfc/rfc3986.txt",
2633 "http%3A%2F%2Fwww.ietf.org%2Frfc%2Frfc3986.txt",1);
2635 ENC("1+2=3", "1%2B2%3D3",1);
2636 ENC("1+2=3", "1%2B2%3D3",0);
2638 /* Now try encoding with internal NULs. */
2639 s = evhttp_uriencode("hello\0world", 11, 0);
2641 tt_str_op(s,==,"hello%00world");
2645 /* Now try decoding just part of string. */
2646 s = malloc(6 + 1 /* NUL byte */);
2647 bytes_decoded = evhttp_decode_uri_internal("hello%20%20", 6, s, 0);
2649 tt_int_op(bytes_decoded,==,6);
2650 tt_str_op(s,==,"hello%");
2654 /* Now try out some decoding cases that we don't generate with
2655 * encode_uri: Make sure that malformed stuff doesn't crash... */
2656 DEC("%%xhello th+ere \xff",
2657 "%%xhello th+ere \xff", 0);
2658 /* Make sure plus decoding works */
2659 DEC("plus+should%20work+", "plus should work ",1);
2660 /* Try some lowercase hex */
2661 DEC("%f0%a0%b0", "\xf0\xa0\xb0",1);
2663 /* Try an internal NUL. */
2665 s = evhttp_uridecode("%00%00x%00%00", 1, &sz);
2667 tt_assert(!memcmp(s, "\0\0x\0\0", 5));
2671 /* Try with size == NULL */
2673 s = evhttp_uridecode("%00%00x%00%00", 1, NULL);
2674 tt_assert(!memcmp(s, "\0\0x\0\0", 5));
2678 /* Test out the crazy old behavior of the deprecated
2679 * evhttp_decode_uri */
2680 OLD_DEC("http://example.com/normal+path/?key=val+with+spaces",
2681 "http://example.com/normal+path/?key=val with spaces");
2694 http_base_test(void *ptr)
2696 struct event_base *base = NULL;
2697 struct bufferevent *bev;
2699 const char *http_request;
2700 ev_uint16_t port = 0;
2703 base = event_base_new();
2705 http = http_setup(&port, base, 0);
2707 fd = http_connect("127.0.0.1", port);
2708 tt_int_op(fd, >=, 0);
2710 /* Stupid thing to send a request */
2711 bev = bufferevent_socket_new(base, fd, 0);
2712 bufferevent_setcb(bev, http_readcb, http_writecb,
2713 http_errorcb, base);
2714 bufferevent_base_set(base, bev);
2717 "GET /test HTTP/1.1\r\n"
2718 "Host: somehost\r\n"
2719 "Connection: close\r\n"
2722 bufferevent_write(bev, http_request, strlen(http_request));
2724 event_base_dispatch(base);
2726 bufferevent_free(bev);
2727 evutil_closesocket(fd);
2731 tt_int_op(test_ok, ==, 2);
2735 event_base_free(base);
2739 * the server is just going to close the connection if it times out during
2740 * reading the headers.
2744 http_incomplete_readcb(struct bufferevent *bev, void *arg)
2747 event_base_loopexit(exit_base,NULL);
2751 http_incomplete_errorcb(struct bufferevent *bev, short what, void *arg)
2753 if (what == (BEV_EVENT_READING|BEV_EVENT_EOF))
2757 event_base_loopexit(exit_base,NULL);
2761 http_incomplete_writecb(struct bufferevent *bev, void *arg)
2764 evutil_socket_t fd = *(evutil_socket_t *)arg;
2765 /* terminate the write side to simulate EOF */
2766 shutdown(fd, SHUT_WR);
2768 if (evbuffer_get_length(bufferevent_get_output(bev)) == 0) {
2769 /* enable reading of the reply */
2770 bufferevent_enable(bev, EV_READ);
2776 http_incomplete_test_(struct basic_test_data *data, int use_timeout)
2778 struct bufferevent *bev;
2780 const char *http_request;
2781 ev_uint16_t port = 0;
2782 struct timeval tv_start, tv_end;
2784 exit_base = data->base;
2788 http = http_setup(&port, data->base, 0);
2789 evhttp_set_timeout(http, 1);
2791 fd = http_connect("127.0.0.1", port);
2792 tt_int_op(fd, >=, 0);
2794 /* Stupid thing to send a request */
2795 bev = bufferevent_socket_new(data->base, fd, 0);
2796 bufferevent_setcb(bev,
2797 http_incomplete_readcb, http_incomplete_writecb,
2798 http_incomplete_errorcb, use_timeout ? NULL : &fd);
2801 "GET /test HTTP/1.1\r\n"
2802 "Host: somehost\r\n";
2804 bufferevent_write(bev, http_request, strlen(http_request));
2806 evutil_gettimeofday(&tv_start, NULL);
2808 event_base_dispatch(data->base);
2810 evutil_gettimeofday(&tv_end, NULL);
2811 evutil_timersub(&tv_end, &tv_start, &tv_end);
2813 bufferevent_free(bev);
2815 evutil_closesocket(fd);
2821 if (use_timeout && tv_end.tv_sec >= 3) {
2822 tt_abort_msg("time");
2823 } else if (!use_timeout && tv_end.tv_sec >= 1) {
2824 /* we should be done immediately */
2825 tt_abort_msg("time");
2828 tt_int_op(test_ok, ==, 2);
2831 evutil_closesocket(fd);
2834 http_incomplete_test(void *arg)
2836 http_incomplete_test_(arg, 0);
2839 http_incomplete_timeout_test(void *arg)
2841 http_incomplete_test_(arg, 1);
2845 * the server is going to reply with chunked data.
2849 http_chunked_readcb(struct bufferevent *bev, void *arg)
2855 http_chunked_errorcb(struct bufferevent *bev, short what, void *arg)
2857 struct evhttp_request *req = NULL;
2864 if ((what & BEV_EVENT_EOF) != 0) {
2866 enum message_read_status done;
2867 req = evhttp_request_new(NULL, NULL);
2869 /* req->kind = EVHTTP_RESPONSE; */
2870 done = evhttp_parse_firstline_(req, bufferevent_get_input(bev));
2871 if (done != ALL_DATA_READ)
2874 done = evhttp_parse_headers_(req, bufferevent_get_input(bev));
2875 if (done != ALL_DATA_READ)
2878 header = evhttp_find_header(evhttp_request_get_input_headers(req), "Transfer-Encoding");
2879 if (header == NULL || strcmp(header, "chunked"))
2882 header = evhttp_find_header(evhttp_request_get_input_headers(req), "Connection");
2883 if (header == NULL || strcmp(header, "close"))
2886 header = evbuffer_readln(bufferevent_get_input(bev), NULL, EVBUFFER_EOL_CRLF);
2890 if (strcmp(header, "d")) {
2891 free((void*)header);
2894 free((void*)header);
2896 if (strncmp((char *)evbuffer_pullup(bufferevent_get_input(bev), 13),
2897 "This is funny", 13))
2900 evbuffer_drain(bufferevent_get_input(bev), 13 + 2);
2902 header = evbuffer_readln(bufferevent_get_input(bev), NULL, EVBUFFER_EOL_CRLF);
2906 if (strcmp(header, "12"))
2908 free((char *)header);
2910 if (strncmp((char *)evbuffer_pullup(bufferevent_get_input(bev), 18),
2911 "but not hilarious.", 18))
2914 evbuffer_drain(bufferevent_get_input(bev), 18 + 2);
2916 header = evbuffer_readln(bufferevent_get_input(bev), NULL, EVBUFFER_EOL_CRLF);
2920 if (strcmp(header, "8")) {
2921 free((void*)header);
2924 free((char *)header);
2926 if (strncmp((char *)evbuffer_pullup(bufferevent_get_input(bev), 8),
2930 evbuffer_drain(bufferevent_get_input(bev), 8 + 2);
2932 header = evbuffer_readln(bufferevent_get_input(bev), NULL, EVBUFFER_EOL_CRLF);
2936 if (strcmp(header, "0")) {
2937 free((void*)header);
2940 free((void *)header);
2947 evhttp_request_free(req);
2949 event_base_loopexit(arg, NULL);
2953 http_chunked_writecb(struct bufferevent *bev, void *arg)
2955 if (evbuffer_get_length(bufferevent_get_output(bev)) == 0) {
2956 /* enable reading of the reply */
2957 bufferevent_enable(bev, EV_READ);
2963 http_chunked_request_done(struct evhttp_request *req, void *arg)
2965 if (evhttp_request_get_response_code(req) != HTTP_OK) {
2966 fprintf(stderr, "FAILED\n");
2970 if (evhttp_find_header(evhttp_request_get_input_headers(req),
2971 "Transfer-Encoding") == NULL) {
2972 fprintf(stderr, "FAILED\n");
2976 if (evbuffer_get_length(evhttp_request_get_input_buffer(req)) != 13 + 18 + 8) {
2977 fprintf(stderr, "FAILED\n");
2981 if (strncmp((char *)evbuffer_pullup(evhttp_request_get_input_buffer(req), 13 + 18 + 8),
2982 "This is funnybut not hilarious.bwv 1052",
2984 fprintf(stderr, "FAILED\n");
2989 event_base_loopexit(arg, NULL);
2993 http_chunk_out_test(void *arg)
2995 struct basic_test_data *data = arg;
2996 struct bufferevent *bev;
2998 const char *http_request;
2999 ev_uint16_t port = 0;
3000 struct timeval tv_start, tv_end;
3001 struct evhttp_connection *evcon = NULL;
3002 struct evhttp_request *req = NULL;
3005 exit_base = data->base;
3008 http = http_setup(&port, data->base, 0);
3010 fd = http_connect("127.0.0.1", port);
3012 /* Stupid thing to send a request */
3013 bev = bufferevent_socket_new(data->base, fd, 0);
3014 bufferevent_setcb(bev,
3015 http_chunked_readcb, http_chunked_writecb,
3016 http_chunked_errorcb, data->base);
3019 "GET /chunked HTTP/1.1\r\n"
3020 "Host: somehost\r\n"
3021 "Connection: close\r\n"
3024 bufferevent_write(bev, http_request, strlen(http_request));
3026 evutil_gettimeofday(&tv_start, NULL);
3028 event_base_dispatch(data->base);
3030 bufferevent_free(bev);
3032 evutil_gettimeofday(&tv_end, NULL);
3033 evutil_timersub(&tv_end, &tv_start, &tv_end);
3035 tt_int_op(tv_end.tv_sec, <, 1);
3037 tt_int_op(test_ok, ==, 2);
3039 /* now try again with the regular connection object */
3040 evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port);
3043 /* make two requests to check the keepalive behavior */
3044 for (i = 0; i < 2; i++) {
3046 req = evhttp_request_new(http_chunked_request_done,data->base);
3048 /* Add the information that we care about */
3049 evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
3051 /* We give ownership of the request to the connection */
3052 if (evhttp_make_request(evcon, req,
3053 EVHTTP_REQ_GET, "/chunked") == -1) {
3054 tt_abort_msg("Couldn't make request");
3057 event_base_dispatch(data->base);
3059 tt_assert(test_ok == 1);
3064 evhttp_connection_free(evcon);
3070 http_stream_out_test(void *arg)
3072 struct basic_test_data *data = arg;
3073 ev_uint16_t port = 0;
3074 struct evhttp_connection *evcon = NULL;
3075 struct evhttp_request *req = NULL;
3078 exit_base = data->base;
3080 http = http_setup(&port, data->base, 0);
3082 evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port);
3086 * At this point, we want to schedule a request to the HTTP
3087 * server using our make request method.
3090 req = evhttp_request_new(http_request_done,
3091 (void *)"This is funnybut not hilarious.bwv 1052");
3093 /* Add the information that we care about */
3094 evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
3096 /* We give ownership of the request to the connection */
3097 if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/streamed")
3099 tt_abort_msg("Couldn't make request");
3102 event_base_dispatch(data->base);
3106 evhttp_connection_free(evcon);
3112 http_stream_in_chunk(struct evhttp_request *req, void *arg)
3114 struct evbuffer *reply = arg;
3116 if (evhttp_request_get_response_code(req) != HTTP_OK) {
3117 fprintf(stderr, "FAILED\n");
3121 evbuffer_add_buffer(reply, evhttp_request_get_input_buffer(req));
3125 http_stream_in_done(struct evhttp_request *req, void *arg)
3127 if (evbuffer_get_length(evhttp_request_get_input_buffer(req)) != 0) {
3128 fprintf(stderr, "FAILED\n");
3132 event_base_loopexit(exit_base, NULL);
3136 * Makes a request and reads the response in chunks.
3139 http_stream_in_test_(struct basic_test_data *data, char const *url,
3140 size_t expected_len, char const *expected)
3142 struct evhttp_connection *evcon;
3143 struct evbuffer *reply = evbuffer_new();
3144 struct evhttp_request *req = NULL;
3145 ev_uint16_t port = 0;
3147 exit_base = data->base;
3148 http = http_setup(&port, data->base, 0);
3150 evcon = evhttp_connection_base_new(data->base, NULL,"127.0.0.1", port);
3153 req = evhttp_request_new(http_stream_in_done, reply);
3154 evhttp_request_set_chunked_cb(req, http_stream_in_chunk);
3156 /* We give ownership of the request to the connection */
3157 if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, url) == -1) {
3158 tt_abort_msg("Couldn't make request");
3161 event_base_dispatch(data->base);
3163 if (evbuffer_get_length(reply) != expected_len) {
3164 TT_DIE(("reply length %lu; expected %lu; FAILED (%s)\n",
3165 (unsigned long)evbuffer_get_length(reply),
3166 (unsigned long)expected_len,
3167 (char*)evbuffer_pullup(reply, -1)));
3170 if (memcmp(evbuffer_pullup(reply, -1), expected, expected_len) != 0) {
3171 tt_abort_msg("Memory mismatch");
3177 evbuffer_free(reply);
3179 evhttp_connection_free(evcon);
3185 http_stream_in_test(void *arg)
3187 http_stream_in_test_(arg, "/chunked", 13 + 18 + 8,
3188 "This is funnybut not hilarious.bwv 1052");
3190 http_stream_in_test_(arg, "/test", strlen(BASIC_REQUEST_BODY),
3191 BASIC_REQUEST_BODY);
3195 http_stream_in_cancel_chunk(struct evhttp_request *req, void *arg)
3197 tt_int_op(evhttp_request_get_response_code(req), ==, HTTP_OK);
3200 evhttp_cancel_request(req);
3201 event_base_loopexit(arg, NULL);
3205 http_stream_in_cancel_done(struct evhttp_request *req, void *arg)
3207 /* should never be called */
3208 tt_fail_msg("In cancel done");
3212 http_stream_in_cancel_test(void *arg)
3214 struct basic_test_data *data = arg;
3215 struct evhttp_connection *evcon;
3216 struct evhttp_request *req = NULL;
3217 ev_uint16_t port = 0;
3219 http = http_setup(&port, data->base, 0);
3221 evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port);
3224 req = evhttp_request_new(http_stream_in_cancel_done, data->base);
3225 evhttp_request_set_chunked_cb(req, http_stream_in_cancel_chunk);
3227 /* We give ownership of the request to the connection */
3228 if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/chunked") == -1) {
3229 tt_abort_msg("Couldn't make request");
3232 event_base_dispatch(data->base);
3236 evhttp_connection_free(evcon);
3242 http_connection_fail_done(struct evhttp_request *req, void *arg)
3244 struct evhttp_connection *evcon = arg;
3245 struct event_base *base = evhttp_connection_get_base(evcon);
3247 /* An ENETUNREACH error results in an unrecoverable
3248 * evhttp_connection error (see evhttp_connection_fail_()). The
3249 * connection will be reset, and the user will be notified with a NULL
3253 evhttp_connection_free(evcon);
3258 event_base_loopexit(base, NULL);
3261 /* Test unrecoverable evhttp_connection errors by generating an ENETUNREACH
3262 * error on connection. */
3264 http_connection_fail_test(void *arg)
3266 struct basic_test_data *data = arg;
3267 ev_uint16_t port = 0;
3268 struct evhttp_connection *evcon = NULL;
3269 struct evhttp_request *req = NULL;
3271 exit_base = data->base;
3274 /* auto detect a port */
3275 http = http_setup(&port, data->base, 0);
3279 /* Pick an unroutable address. This administratively scoped multicast
3280 * address should do when working with TCP. */
3281 evcon = evhttp_connection_base_new(data->base, NULL, "239.10.20.30", 80);
3285 * At this point, we want to schedule an HTTP GET request
3286 * server using our make request method.
3289 req = evhttp_request_new(http_connection_fail_done, evcon);
3292 if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/") == -1) {
3293 tt_abort_msg("Couldn't make request");
3296 event_base_dispatch(data->base);
3298 tt_int_op(test_ok, ==, 1);
3305 http_connection_retry_done(struct evhttp_request *req, void *arg)
3308 tt_int_op(evhttp_request_get_response_code(req), !=, HTTP_OK);
3309 if (evhttp_find_header(evhttp_request_get_input_headers(req), "Content-Type") != NULL) {
3310 tt_abort_msg("(content type)\n");
3313 tt_uint_op(evbuffer_get_length(evhttp_request_get_input_buffer(req)), ==, 0);
3317 event_base_loopexit(arg,NULL);
3320 static struct event_base *http_make_web_server_base=NULL;
3322 http_make_web_server(evutil_socket_t fd, short what, void *arg)
3324 ev_uint16_t port = *(ev_uint16_t*)arg;
3325 http = http_setup(&port, http_make_web_server_base, 0);
3329 http_connection_retry_test(void *arg)
3331 struct basic_test_data *data = arg;
3332 ev_uint16_t port = 0;
3333 struct evhttp_connection *evcon = NULL;
3334 struct evhttp_request *req = NULL;
3335 struct timeval tv, tv_start, tv_end;
3337 exit_base = data->base;
3340 /* auto detect a port */
3341 http = http_setup(&port, data->base, 0);
3345 evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port);
3348 evhttp_connection_set_timeout(evcon, 1);
3349 /* also bind to local host */
3350 evhttp_connection_set_local_address(evcon, "127.0.0.1");
3353 * At this point, we want to schedule an HTTP GET request
3354 * server using our make request method.
3357 req = evhttp_request_new(http_connection_retry_done, data->base);
3360 /* Add the information that we care about */
3361 evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
3363 if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET,
3364 "/?arg=val") == -1) {
3365 tt_abort_msg("Couldn't make request");
3368 evutil_gettimeofday(&tv_start, NULL);
3369 event_base_dispatch(data->base);
3370 evutil_gettimeofday(&tv_end, NULL);
3371 evutil_timersub(&tv_end, &tv_start, &tv_end);
3372 tt_int_op(tv_end.tv_sec, <, 1);
3374 tt_int_op(test_ok, ==, 1);
3377 * now test the same but with retries
3382 const struct timeval tv_timeout = { 0, 500000 };
3383 const struct timeval tv_retry = { 0, 500000 };
3384 evhttp_connection_set_timeout_tv(evcon, &tv_timeout);
3385 evhttp_connection_set_initial_retry_tv(evcon, &tv_retry);
3387 evhttp_connection_set_retries(evcon, 1);
3389 req = evhttp_request_new(http_connection_retry_done, data->base);
3392 /* Add the information that we care about */
3393 evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
3395 if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET,
3396 "/?arg=val") == -1) {
3397 tt_abort_msg("Couldn't make request");
3400 evutil_gettimeofday(&tv_start, NULL);
3401 event_base_dispatch(data->base);
3402 evutil_gettimeofday(&tv_end, NULL);
3404 /* fails fast, .5 sec to wait to retry, fails fast again. */
3405 test_timeval_diff_leq(&tv_start, &tv_end, 500, 200);
3407 tt_assert(test_ok == 1);
3410 * now test the same but with retries and give it a web server
3415 evhttp_connection_set_timeout(evcon, 1);
3416 evhttp_connection_set_retries(evcon, 3);
3418 req = evhttp_request_new(http_dispatcher_test_done, data->base);
3421 /* Add the information that we care about */
3422 evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
3424 if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET,
3425 "/?arg=val") == -1) {
3426 tt_abort_msg("Couldn't make request");
3429 /* start up a web server .2 seconds after the connection tried
3432 evutil_timerclear(&tv);
3433 tv.tv_usec = 200000;
3434 http_make_web_server_base = data->base;
3435 event_base_once(data->base, -1, EV_TIMEOUT, http_make_web_server, &port, &tv);
3437 evutil_gettimeofday(&tv_start, NULL);
3438 event_base_dispatch(data->base);
3439 evutil_gettimeofday(&tv_end, NULL);
3440 /* We'll wait twice as long as we did last time. */
3441 test_timeval_diff_leq(&tv_start, &tv_end, 1000, 400);
3443 tt_int_op(test_ok, ==, 1);
3447 evhttp_connection_free(evcon);
3453 http_primitives(void *ptr)
3455 char *escaped = NULL;
3456 struct evhttp *http = NULL;
3458 escaped = evhttp_htmlescape("<script>");
3460 tt_str_op(escaped, ==, "<script>");
3463 escaped = evhttp_htmlescape("\"\'&");
3465 tt_str_op(escaped, ==, ""'&");
3467 http = evhttp_new(NULL);
3469 tt_int_op(evhttp_set_cb(http, "/test", http_basic_cb, NULL), ==, 0);
3470 tt_int_op(evhttp_set_cb(http, "/test", http_basic_cb, NULL), ==, -1);
3471 tt_int_op(evhttp_del_cb(http, "/test"), ==, 0);
3472 tt_int_op(evhttp_del_cb(http, "/test"), ==, -1);
3473 tt_int_op(evhttp_set_cb(http, "/test", http_basic_cb, NULL), ==, 0);
3483 http_multi_line_header_test(void *arg)
3485 struct basic_test_data *data = arg;
3486 struct bufferevent *bev= NULL;
3487 evutil_socket_t fd = -1;
3488 const char *http_start_request;
3489 ev_uint16_t port = 0;
3493 http = http_setup(&port, data->base, 0);
3495 tt_ptr_op(http, !=, NULL);
3497 fd = http_connect("127.0.0.1", port);
3499 tt_int_op(fd, !=, -1);
3501 /* Stupid thing to send a request */
3502 bev = bufferevent_socket_new(data->base, fd, 0);
3503 tt_ptr_op(bev, !=, NULL);
3504 bufferevent_setcb(bev, http_readcb, http_writecb,
3505 http_errorcb, data->base);
3507 http_start_request =
3508 "GET /test HTTP/1.1\r\n"
3509 "Host: somehost\r\n"
3510 "Connection: close\r\n"
3511 "X-Multi-Extra-WS: libevent \r\n"
3513 "X-Multi: aaaaaaaa\r\n"
3519 bufferevent_write(bev, http_start_request, strlen(http_start_request));
3520 found_multi = found_multi2 = 0;
3522 event_base_dispatch(data->base);
3524 tt_int_op(found_multi, ==, 1);
3525 tt_int_op(found_multi2, ==, 1);
3526 tt_int_op(test_ok, ==, 4);
3529 bufferevent_free(bev);
3531 evutil_closesocket(fd);
3537 http_request_bad(struct evhttp_request *req, void *arg)
3540 fprintf(stderr, "FAILED\n");
3545 event_base_loopexit(arg, NULL);
3549 http_negative_content_length_test(void *arg)
3551 struct basic_test_data *data = arg;
3552 ev_uint16_t port = 0;
3553 struct evhttp_connection *evcon = NULL;
3554 struct evhttp_request *req = NULL;
3558 http = http_setup(&port, data->base, 0);
3560 evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port);
3564 * At this point, we want to schedule a request to the HTTP
3565 * server using our make request method.
3568 req = evhttp_request_new(http_request_bad, data->base);
3570 /* Cause the response to have a negative content-length */
3571 evhttp_add_header(evhttp_request_get_output_headers(req), "X-Negative", "makeitso");
3573 /* We give ownership of the request to the connection */
3574 if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test") == -1) {
3575 tt_abort_msg("Couldn't make request");
3578 event_base_dispatch(data->base);
3582 evhttp_connection_free(evcon);
3589 http_data_length_constraints_test_done(struct evhttp_request *req, void *arg)
3592 tt_int_op(evhttp_request_get_response_code(req), ==, HTTP_BADREQUEST);
3594 event_base_loopexit(arg, NULL);
3598 http_large_entity_test_done(struct evhttp_request *req, void *arg)
3601 tt_int_op(evhttp_request_get_response_code(req), ==, HTTP_ENTITYTOOLARGE);
3603 event_base_loopexit(arg, NULL);
3607 http_data_length_constraints_test(void *arg)
3609 struct basic_test_data *data = arg;
3610 ev_uint16_t port = 0;
3611 struct evhttp_connection *evcon = NULL;
3612 struct evhttp_request *req = NULL;
3613 char long_str[8192];
3617 http = http_setup(&port, data->base, 0);
3619 evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port);
3622 /* also bind to local host */
3623 evhttp_connection_set_local_address(evcon, "127.0.0.1");
3626 * At this point, we want to schedule an HTTP GET request
3627 * server using our make request method.
3630 req = evhttp_request_new(http_data_length_constraints_test_done, data->base);
3633 memset(long_str, 'a', 8192);
3634 long_str[8191] = '\0';
3635 /* Add the information that we care about */
3636 evhttp_set_max_headers_size(http, 8191);
3637 evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
3638 evhttp_add_header(evhttp_request_get_output_headers(req), "Longheader", long_str);
3640 if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/?arg=val") == -1) {
3641 tt_abort_msg("Couldn't make request");
3643 event_base_dispatch(data->base);
3645 req = evhttp_request_new(http_data_length_constraints_test_done, data->base);
3647 evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
3649 /* GET /?arg=verylongvalue HTTP/1.1 */
3650 if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, long_str) == -1) {
3651 tt_abort_msg("Couldn't make request");
3653 event_base_dispatch(data->base);
3655 evhttp_set_max_body_size(http, 8190);
3656 req = evhttp_request_new(http_data_length_constraints_test_done, data->base);
3657 evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
3658 evbuffer_add_printf(evhttp_request_get_output_buffer(req), "%s", long_str);
3659 if (evhttp_make_request(evcon, req, EVHTTP_REQ_POST, "/") == -1) {
3660 tt_abort_msg("Couldn't make request");
3662 event_base_dispatch(data->base);
3664 req = evhttp_request_new(http_large_entity_test_done, data->base);
3665 evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
3666 evhttp_add_header(evhttp_request_get_output_headers(req), "Expect", "100-continue");
3667 evbuffer_add_printf(evhttp_request_get_output_buffer(req), "%s", long_str);
3668 if (evhttp_make_request(evcon, req, EVHTTP_REQ_POST, "/") == -1) {
3669 tt_abort_msg("Couldn't make request");
3671 event_base_dispatch(data->base);
3676 evhttp_connection_free(evcon);
3682 * Testing client reset of server chunked connections
3685 struct terminate_state {
3686 struct event_base *base;
3687 struct evhttp_request *req;
3688 struct bufferevent *bev;
3694 terminate_chunked_trickle_cb(evutil_socket_t fd, short events, void *arg)
3696 struct terminate_state *state = arg;
3697 struct evbuffer *evb;
3700 if (evhttp_request_get_connection(state->req) == NULL) {
3702 evhttp_request_free(state->req);
3703 event_base_loopexit(state->base,NULL);
3707 evb = evbuffer_new();
3708 evbuffer_add_printf(evb, "%p", evb);
3709 evhttp_send_reply_chunk(state->req, evb);
3714 EVUTIL_ASSERT(state);
3715 EVUTIL_ASSERT(state->base);
3716 event_base_once(state->base, -1, EV_TIMEOUT, terminate_chunked_trickle_cb, arg, &tv);
3720 terminate_chunked_close_cb(struct evhttp_connection *evcon, void *arg)
3722 struct terminate_state *state = arg;
3723 state->gotclosecb = 1;
3727 terminate_chunked_cb(struct evhttp_request *req, void *arg)
3729 struct terminate_state *state = arg;
3732 /* we want to know if this connection closes on us */
3733 evhttp_connection_set_closecb(
3734 evhttp_request_get_connection(req),
3735 terminate_chunked_close_cb, arg);
3739 evhttp_send_reply_start(req, HTTP_OK, "OK");
3743 event_base_once(state->base, -1, EV_TIMEOUT, terminate_chunked_trickle_cb, arg, &tv);
3747 terminate_chunked_client(evutil_socket_t fd, short event, void *arg)
3749 struct terminate_state *state = arg;
3750 bufferevent_free(state->bev);
3751 evutil_closesocket(state->fd);
3755 terminate_readcb(struct bufferevent *bev, void *arg)
3757 /* just drop the data */
3758 evbuffer_drain(bufferevent_get_input(bev), -1);
3763 http_terminate_chunked_test(void *arg)
3765 struct basic_test_data *data = arg;
3766 struct bufferevent *bev = NULL;
3768 const char *http_request;
3769 ev_uint16_t port = 0;
3770 evutil_socket_t fd = -1;
3771 struct terminate_state terminate_state;
3775 http = http_setup(&port, data->base, 0);
3776 evhttp_del_cb(http, "/test");
3777 tt_assert(evhttp_set_cb(http, "/test",
3778 terminate_chunked_cb, &terminate_state) == 0);
3780 fd = http_connect("127.0.0.1", port);
3782 /* Stupid thing to send a request */
3783 bev = bufferevent_socket_new(data->base, fd, 0);
3784 bufferevent_setcb(bev, terminate_readcb, http_writecb,
3785 http_errorcb, data->base);
3787 memset(&terminate_state, 0, sizeof(terminate_state));
3788 terminate_state.base = data->base;
3789 terminate_state.fd = fd;
3790 terminate_state.bev = bev;
3791 terminate_state.gotclosecb = 0;
3793 /* first half of the http request */
3795 "GET /test HTTP/1.1\r\n"
3796 "Host: some\r\n\r\n";
3798 bufferevent_write(bev, http_request, strlen(http_request));
3799 evutil_timerclear(&tv);
3801 event_base_once(data->base, -1, EV_TIMEOUT, terminate_chunked_client, &terminate_state,
3804 event_base_dispatch(data->base);
3806 if (terminate_state.gotclosecb == 0)
3811 evutil_closesocket(fd);
3816 static struct regress_dns_server_table ipv6_search_table[] = {
3817 { "localhost", "AAAA", "::1", 0 },
3818 { NULL, NULL, NULL, 0 }
3822 http_ipv6_for_domain_test_impl(void *arg, int family)
3824 struct basic_test_data *data = arg;
3825 struct evdns_base *dns_base = NULL;
3826 ev_uint16_t portnum = 0;
3829 tt_assert(regress_dnsserver(data->base, &portnum, ipv6_search_table));
3831 dns_base = evdns_base_new(data->base, 0/* init name servers */);
3832 tt_assert(dns_base);
3834 /* Add ourself as the only nameserver, and make sure we really are
3835 * the only nameserver. */
3836 evutil_snprintf(address, sizeof(address), "127.0.0.1:%d", portnum);
3837 evdns_base_nameserver_ip_add(dns_base, address);
3839 http_connection_test_(arg, 0 /* not persistent */, "localhost", dns_base,
3840 1 /* ipv6 */, family);
3844 evdns_base_free(dns_base, 0);
3845 regress_clean_dnsserver();
3848 http_ipv6_for_domain_test(void *arg)
3850 http_ipv6_for_domain_test_impl(arg, AF_UNSPEC);
3854 http_request_get_addr_on_close(struct evhttp_connection *evcon, void *arg)
3856 const struct sockaddr *storage;
3858 char local[] = "127.0.0.1:";
3863 storage = evhttp_connection_get_addr(evcon);
3866 evutil_format_sockaddr_port_((struct sockaddr *)storage, addrbuf, sizeof(addrbuf));
3867 tt_assert(!strncmp(addrbuf, local, sizeof(local) - 1));
3877 http_get_addr_test(void *arg)
3879 struct basic_test_data *data = arg;
3880 ev_uint16_t port = 0;
3881 struct evhttp_connection *evcon = NULL;
3882 struct evhttp_request *req = NULL;
3885 exit_base = data->base;
3887 http = http_setup(&port, data->base, 0);
3889 evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port);
3891 evhttp_connection_set_closecb(evcon, http_request_get_addr_on_close, arg);
3894 * At this point, we want to schedule a request to the HTTP
3895 * server using our make request method.
3898 req = evhttp_request_new(http_request_done, (void *)BASIC_REQUEST_BODY);
3900 /* We give ownership of the request to the connection */
3901 if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test") == -1) {
3902 tt_abort_msg("Couldn't make request");
3905 event_base_dispatch(data->base);
3907 http_request_get_addr_on_close(evcon, NULL);
3911 evhttp_connection_free(evcon);
3917 http_set_family_test(void *arg)
3919 http_connection_test_(arg, 0, "127.0.0.1", NULL, 0, AF_UNSPEC);
3922 http_set_family_ipv4_test(void *arg)
3924 http_connection_test_(arg, 0, "127.0.0.1", NULL, 0, AF_INET);
3927 http_set_family_ipv6_test(void *arg)
3929 http_ipv6_for_domain_test_impl(arg, AF_INET6);
3932 #define HTTP_LEGACY(name) \
3933 { #name, run_legacy_test_fn, TT_ISOLATED|TT_LEGACY, &legacy_setup, \
3934 http_##name##_test }
3936 #define HTTP(name) \
3937 { #name, http_##name##_test, TT_ISOLATED, &basic_setup, NULL }
3939 struct testcase_t http_testcases[] = {
3940 { "primitives", http_primitives, 0, NULL, NULL },
3941 { "base", http_base_test, TT_FORK, NULL, NULL },
3942 { "bad_headers", http_bad_header_test, 0, NULL, NULL },
3943 { "parse_query", http_parse_query_test, 0, NULL, NULL },
3944 { "parse_uri", http_parse_uri_test, 0, NULL, NULL },
3945 { "parse_uri_nc", http_parse_uri_test, 0, &basic_setup, (void*)"nc" },
3946 { "uriencode", http_uriencode_test, 0, NULL, NULL },
3953 HTTP(allowed_methods),
3956 HTTP(persist_connection),
3957 HTTP(autofree_connection),
3958 HTTP(connection_async),
3959 HTTP(close_detection),
3960 HTTP(close_detection_delay),
3963 HTTP(incomplete_timeout),
3964 HTTP(terminate_chunked),
3969 HTTP(multi_line_header),
3970 HTTP(negative_content_length),
3975 HTTP(stream_in_cancel),
3977 HTTP(connection_fail),
3978 { "connection_retry", http_connection_retry_test, TT_ISOLATED|TT_OFF_BY_DEFAULT, &basic_setup, NULL },
3980 HTTP(data_length_constraints),
3982 HTTP(ipv6_for_domain),
3986 HTTP(set_family_ipv4),
3987 HTTP(set_family_ipv6),