Home | History | Annotate | Line # | Download | only in test
regress_http.c revision 1.1.1.2
      1 /*	$NetBSD: regress_http.c,v 1.1.1.2 2013/04/11 16:43:33 christos Exp $	*/
      2 /*
      3  * Copyright (c) 2003-2007 Niels Provos <provos (at) citi.umich.edu>
      4  * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson
      5  *
      6  * Redistribution and use in source and binary forms, with or without
      7  * modification, are permitted provided that the following conditions
      8  * are met:
      9  * 1. Redistributions of source code must retain the above copyright
     10  *    notice, this list of conditions and the following disclaimer.
     11  * 2. Redistributions in binary form must reproduce the above copyright
     12  *    notice, this list of conditions and the following disclaimer in the
     13  *    documentation and/or other materials provided with the distribution.
     14  * 3. The name of the author may not be used to endorse or promote products
     15  *    derived from this software without specific prior written permission.
     16  *
     17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     19  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     20  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     22  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     27  */
     28 
     29 #ifdef WIN32
     30 #include <winsock2.h>
     31 #include <ws2tcpip.h>
     32 #include <windows.h>
     33 #endif
     34 
     35 #include "event2/event-config.h"
     36 #include <sys/cdefs.h>
     37 __RCSID("$NetBSD: regress_http.c,v 1.1.1.2 2013/04/11 16:43:33 christos Exp $");
     38 
     39 #include <sys/types.h>
     40 #include <sys/stat.h>
     41 #ifdef _EVENT_HAVE_SYS_TIME_H
     42 #include <sys/time.h>
     43 #endif
     44 #include <sys/queue.h>
     45 #ifndef WIN32
     46 #include <sys/socket.h>
     47 #include <signal.h>
     48 #include <unistd.h>
     49 #include <netdb.h>
     50 #endif
     51 #include <fcntl.h>
     52 #include <stdlib.h>
     53 #include <stdio.h>
     54 #include <string.h>
     55 #include <errno.h>
     56 
     57 #include "event2/dns.h"
     58 
     59 #include "event2/event.h"
     60 #include "event2/http.h"
     61 #include "event2/buffer.h"
     62 #include "event2/bufferevent.h"
     63 #include "event2/util.h"
     64 #include "log-internal.h"
     65 #include "util-internal.h"
     66 #include "http-internal.h"
     67 #include "regress.h"
     68 #include "regress_testutils.h"
     69 
     70 static struct evhttp *http;
     71 /* set if a test needs to call loopexit on a base */
     72 static struct event_base *exit_base;
     73 
     74 static char const BASIC_REQUEST_BODY[] = "This is funny";
     75 
     76 static void http_basic_cb(struct evhttp_request *req, void *arg);
     77 static void http_chunked_cb(struct evhttp_request *req, void *arg);
     78 static void http_post_cb(struct evhttp_request *req, void *arg);
     79 static void http_put_cb(struct evhttp_request *req, void *arg);
     80 static void http_delete_cb(struct evhttp_request *req, void *arg);
     81 static void http_delay_cb(struct evhttp_request *req, void *arg);
     82 static void http_large_delay_cb(struct evhttp_request *req, void *arg);
     83 static void http_badreq_cb(struct evhttp_request *req, void *arg);
     84 static void http_dispatcher_cb(struct evhttp_request *req, void *arg);
     85 static int
     86 http_bind(struct evhttp *myhttp, ev_uint16_t *pport)
     87 {
     88 	int port;
     89 	struct evhttp_bound_socket *sock;
     90 
     91 	sock = evhttp_bind_socket_with_handle(myhttp, "127.0.0.1", *pport);
     92 	if (sock == NULL)
     93 		event_errx(1, "Could not start web server");
     94 
     95 	port = regress_get_socket_port(evhttp_bound_socket_get_fd(sock));
     96 	if (port < 0)
     97 		return -1;
     98 	*pport = (ev_uint16_t) port;
     99 
    100 	return 0;
    101 }
    102 
    103 static struct evhttp *
    104 http_setup(ev_uint16_t *pport, struct event_base *base)
    105 {
    106 	struct evhttp *myhttp;
    107 
    108 	/* Try a few different ports */
    109 	myhttp = evhttp_new(base);
    110 
    111 	if (http_bind(myhttp, pport) < 0)
    112 		return NULL;
    113 
    114 	/* Register a callback for certain types of requests */
    115 	evhttp_set_cb(myhttp, "/test", http_basic_cb, base);
    116 	evhttp_set_cb(myhttp, "/chunked", http_chunked_cb, base);
    117 	evhttp_set_cb(myhttp, "/streamed", http_chunked_cb, base);
    118 	evhttp_set_cb(myhttp, "/postit", http_post_cb, base);
    119 	evhttp_set_cb(myhttp, "/putit", http_put_cb, base);
    120 	evhttp_set_cb(myhttp, "/deleteit", http_delete_cb, base);
    121 	evhttp_set_cb(myhttp, "/delay", http_delay_cb, base);
    122 	evhttp_set_cb(myhttp, "/largedelay", http_large_delay_cb, base);
    123 	evhttp_set_cb(myhttp, "/badrequest", http_badreq_cb, base);
    124 	evhttp_set_cb(myhttp, "/", http_dispatcher_cb, base);
    125 	return (myhttp);
    126 }
    127 
    128 #ifndef NI_MAXSERV
    129 #define NI_MAXSERV 1024
    130 #endif
    131 
    132 static evutil_socket_t
    133 http_connect(const char *address, u_short port)
    134 {
    135 	/* Stupid code for connecting */
    136 	struct evutil_addrinfo ai, *aitop;
    137 	char strport[NI_MAXSERV];
    138 
    139 	struct sockaddr *sa;
    140 	int slen;
    141 	evutil_socket_t fd;
    142 
    143 	memset(&ai, 0, sizeof(ai));
    144 	ai.ai_family = AF_INET;
    145 	ai.ai_socktype = SOCK_STREAM;
    146 	evutil_snprintf(strport, sizeof(strport), "%d", port);
    147 	if (evutil_getaddrinfo(address, strport, &ai, &aitop) != 0) {
    148 		event_warn("getaddrinfo");
    149 		return (-1);
    150 	}
    151 	sa = aitop->ai_addr;
    152 	slen = aitop->ai_addrlen;
    153 
    154 	fd = socket(AF_INET, SOCK_STREAM, 0);
    155 	if (fd == -1)
    156 		event_err(1, "socket failed");
    157 
    158 	evutil_make_socket_nonblocking(fd);
    159 	if (connect(fd, sa, slen) == -1) {
    160 #ifdef WIN32
    161 		int tmp_err = WSAGetLastError();
    162 		if (tmp_err != WSAEINPROGRESS && tmp_err != WSAEINVAL &&
    163 		    tmp_err != WSAEWOULDBLOCK)
    164 			event_err(1, "connect failed");
    165 #else
    166 		if (errno != EINPROGRESS)
    167 			event_err(1, "connect failed");
    168 #endif
    169 	}
    170 
    171 	evutil_freeaddrinfo(aitop);
    172 
    173 	return (fd);
    174 }
    175 
    176 /* Helper: do a strcmp on the contents of buf and the string s. */
    177 static int
    178 evbuffer_datacmp(struct evbuffer *buf, const char *s)
    179 {
    180 	size_t b_sz = evbuffer_get_length(buf);
    181 	size_t s_sz = strlen(s);
    182 	unsigned char *d;
    183 	int r;
    184 
    185 	if (b_sz < s_sz)
    186 		return -1;
    187 
    188 	d = evbuffer_pullup(buf, s_sz);
    189 	if ((r = memcmp(d, s, s_sz)))
    190 		return r;
    191 
    192 	if (b_sz > s_sz)
    193 		return 1;
    194 	else
    195 		return 0;
    196 }
    197 
    198 /* Helper: Return true iff buf contains s */
    199 static int
    200 evbuffer_contains(struct evbuffer *buf, const char *s)
    201 {
    202 	struct evbuffer_ptr ptr;
    203 	ptr = evbuffer_search(buf, s, strlen(s), NULL);
    204 	return ptr.pos != -1;
    205 }
    206 
    207 static void
    208 http_readcb(struct bufferevent *bev, void *arg)
    209 {
    210 	const char *what = BASIC_REQUEST_BODY;
    211 	struct event_base *my_base = arg;
    212 
    213 	if (evbuffer_contains(bufferevent_get_input(bev), what)) {
    214 		struct evhttp_request *req = evhttp_request_new(NULL, NULL);
    215 		enum message_read_status done;
    216 
    217 		/* req->kind = EVHTTP_RESPONSE; */
    218 		done = evhttp_parse_firstline(req, bufferevent_get_input(bev));
    219 		if (done != ALL_DATA_READ)
    220 			goto out;
    221 
    222 		done = evhttp_parse_headers(req, bufferevent_get_input(bev));
    223 		if (done != ALL_DATA_READ)
    224 			goto out;
    225 
    226 		if (done == 1 &&
    227 		    evhttp_find_header(evhttp_request_get_input_headers(req),
    228 			"Content-Type") != NULL)
    229 			test_ok++;
    230 
    231 	 out:
    232 		evhttp_request_free(req);
    233 		bufferevent_disable(bev, EV_READ);
    234 		if (exit_base)
    235 			event_base_loopexit(exit_base, NULL);
    236 		else if (my_base)
    237 			event_base_loopexit(my_base, NULL);
    238 		else {
    239 			fprintf(stderr, "No way to exit loop!\n");
    240 			exit(1);
    241 		}
    242 	}
    243 }
    244 
    245 static void
    246 http_writecb(struct bufferevent *bev, void *arg)
    247 {
    248 	if (evbuffer_get_length(bufferevent_get_output(bev)) == 0) {
    249 		/* enable reading of the reply */
    250 		bufferevent_enable(bev, EV_READ);
    251 		test_ok++;
    252 	}
    253 }
    254 
    255 static void
    256 http_errorcb(struct bufferevent *bev, short what, void *arg)
    257 {
    258 	test_ok = -2;
    259 	event_base_loopexit(arg, NULL);
    260 }
    261 
    262 static void
    263 http_basic_cb(struct evhttp_request *req, void *arg)
    264 {
    265 	struct evbuffer *evb = evbuffer_new();
    266 	int empty = evhttp_find_header(evhttp_request_get_input_headers(req), "Empty") != NULL;
    267 	event_debug(("%s: called\n", __func__));
    268 	evbuffer_add_printf(evb, BASIC_REQUEST_BODY);
    269 
    270 	/* For multi-line headers test */
    271 	{
    272 		const char *multi =
    273 		    evhttp_find_header(evhttp_request_get_input_headers(req),"X-multi");
    274 		if (multi) {
    275 			if (strcmp("END", multi + strlen(multi) - 3) == 0)
    276 				test_ok++;
    277 			if (evhttp_find_header(evhttp_request_get_input_headers(req), "X-Last"))
    278 				test_ok++;
    279 		}
    280 	}
    281 
    282 	/* injecting a bad content-length */
    283 	if (evhttp_find_header(evhttp_request_get_input_headers(req), "X-Negative"))
    284 		evhttp_add_header(evhttp_request_get_output_headers(req),
    285 		    "Content-Length", "-100");
    286 
    287 	/* allow sending of an empty reply */
    288 	evhttp_send_reply(req, HTTP_OK, "Everything is fine",
    289 	    !empty ? evb : NULL);
    290 
    291 	evbuffer_free(evb);
    292 }
    293 
    294 static char const* const CHUNKS[] = {
    295 	"This is funny",
    296 	"but not hilarious.",
    297 	"bwv 1052"
    298 };
    299 
    300 struct chunk_req_state {
    301 	struct event_base *base;
    302 	struct evhttp_request *req;
    303 	int i;
    304 };
    305 
    306 static void
    307 http_chunked_trickle_cb(evutil_socket_t fd, short events, void *arg)
    308 {
    309 	struct evbuffer *evb = evbuffer_new();
    310 	struct chunk_req_state *state = arg;
    311 	struct timeval when = { 0, 0 };
    312 
    313 	evbuffer_add_printf(evb, "%s", CHUNKS[state->i]);
    314 	evhttp_send_reply_chunk(state->req, evb);
    315 	evbuffer_free(evb);
    316 
    317 	if (++state->i < (int) (sizeof(CHUNKS)/sizeof(CHUNKS[0]))) {
    318 		event_base_once(state->base, -1, EV_TIMEOUT,
    319 		    http_chunked_trickle_cb, state, &when);
    320 	} else {
    321 		evhttp_send_reply_end(state->req);
    322 		free(state);
    323 	}
    324 }
    325 
    326 static void
    327 http_chunked_cb(struct evhttp_request *req, void *arg)
    328 {
    329 	struct timeval when = { 0, 0 };
    330 	struct chunk_req_state *state = malloc(sizeof(struct chunk_req_state));
    331 	event_debug(("%s: called\n", __func__));
    332 
    333 	memset(state, 0, sizeof(struct chunk_req_state));
    334 	state->req = req;
    335 	state->base = arg;
    336 
    337 	if (strcmp(evhttp_request_get_uri(req), "/streamed") == 0) {
    338 		evhttp_add_header(evhttp_request_get_output_headers(req), "Content-Length", "39");
    339 	}
    340 
    341 	/* generate a chunked/streamed reply */
    342 	evhttp_send_reply_start(req, HTTP_OK, "Everything is fine");
    343 
    344 	/* but trickle it across several iterations to ensure we're not
    345 	 * assuming it comes all at once */
    346 	event_base_once(arg, -1, EV_TIMEOUT, http_chunked_trickle_cb, state, &when);
    347 }
    348 
    349 static void
    350 http_complete_write(evutil_socket_t fd, short what, void *arg)
    351 {
    352 	struct bufferevent *bev = arg;
    353 	const char *http_request = "host\r\n"
    354 	    "Connection: close\r\n"
    355 	    "\r\n";
    356 	bufferevent_write(bev, http_request, strlen(http_request));
    357 }
    358 
    359 static void
    360 http_basic_test(void *arg)
    361 {
    362 	struct basic_test_data *data = arg;
    363 	struct timeval tv;
    364 	struct bufferevent *bev;
    365 	evutil_socket_t fd;
    366 	const char *http_request;
    367 	ev_uint16_t port = 0, port2 = 0;
    368 
    369 	test_ok = 0;
    370 
    371 	http = http_setup(&port, data->base);
    372 
    373 	/* bind to a second socket */
    374 	if (http_bind(http, &port2) == -1) {
    375 		fprintf(stdout, "FAILED (bind)\n");
    376 		exit(1);
    377 	}
    378 
    379 	fd = http_connect("127.0.0.1", port);
    380 
    381 	/* Stupid thing to send a request */
    382 	bev = bufferevent_socket_new(data->base, fd, 0);
    383 	bufferevent_setcb(bev, http_readcb, http_writecb,
    384 	    http_errorcb, data->base);
    385 
    386 	/* first half of the http request */
    387 	http_request =
    388 	    "GET /test HTTP/1.1\r\n"
    389 	    "Host: some";
    390 
    391 	bufferevent_write(bev, http_request, strlen(http_request));
    392 	evutil_timerclear(&tv);
    393 	tv.tv_usec = 10000;
    394 	event_base_once(data->base,
    395 	    -1, EV_TIMEOUT, http_complete_write, bev, &tv);
    396 
    397 	event_base_dispatch(data->base);
    398 
    399 	tt_assert(test_ok == 3);
    400 
    401 	/* connect to the second port */
    402 	bufferevent_free(bev);
    403 	evutil_closesocket(fd);
    404 
    405 	fd = http_connect("127.0.0.1", port2);
    406 
    407 	/* Stupid thing to send a request */
    408 	bev = bufferevent_socket_new(data->base, fd, 0);
    409 	bufferevent_setcb(bev, http_readcb, http_writecb,
    410 	    http_errorcb, data->base);
    411 
    412 	http_request =
    413 	    "GET /test HTTP/1.1\r\n"
    414 	    "Host: somehost\r\n"
    415 	    "Connection: close\r\n"
    416 	    "\r\n";
    417 
    418 	bufferevent_write(bev, http_request, strlen(http_request));
    419 
    420 	event_base_dispatch(data->base);
    421 
    422 	tt_assert(test_ok == 5);
    423 
    424 	/* Connect to the second port again. This time, send an absolute uri. */
    425 	bufferevent_free(bev);
    426 	evutil_closesocket(fd);
    427 
    428 	fd = http_connect("127.0.0.1", port2);
    429 
    430 	/* Stupid thing to send a request */
    431 	bev = bufferevent_socket_new(data->base, fd, 0);
    432 	bufferevent_setcb(bev, http_readcb, http_writecb,
    433 	    http_errorcb, data->base);
    434 
    435 	http_request =
    436 	    "GET http://somehost.net/test HTTP/1.1\r\n"
    437 	    "Host: somehost\r\n"
    438 	    "Connection: close\r\n"
    439 	    "\r\n";
    440 
    441 	bufferevent_write(bev, http_request, strlen(http_request));
    442 
    443 	event_base_dispatch(data->base);
    444 
    445 	tt_assert(test_ok == 7);
    446 
    447 	evhttp_free(http);
    448  end:
    449 	;
    450 }
    451 
    452 static void
    453 http_delay_reply(evutil_socket_t fd, short what, void *arg)
    454 {
    455 	struct evhttp_request *req = arg;
    456 
    457 	evhttp_send_reply(req, HTTP_OK, "Everything is fine", NULL);
    458 
    459 	++test_ok;
    460 }
    461 
    462 static void
    463 http_delay_cb(struct evhttp_request *req, void *arg)
    464 {
    465 	struct timeval tv;
    466 	evutil_timerclear(&tv);
    467 	tv.tv_sec = 0;
    468 	tv.tv_usec = 200 * 1000;
    469 
    470 	event_base_once(arg, -1, EV_TIMEOUT, http_delay_reply, req, &tv);
    471 }
    472 
    473 static void
    474 http_badreq_cb(struct evhttp_request *req, void *arg)
    475 {
    476 	struct evbuffer *buf = evbuffer_new();
    477 
    478 	evhttp_add_header(evhttp_request_get_output_headers(req), "Content-Type", "text/xml; charset=UTF-8");
    479 	evbuffer_add_printf(buf, "Hello, %s!", "127.0.0.1");
    480 
    481 	evhttp_send_reply(req, HTTP_OK, "OK", buf);
    482 	evbuffer_free(buf);
    483 }
    484 
    485 static void
    486 http_badreq_errorcb(struct bufferevent *bev, short what, void *arg)
    487 {
    488 	event_debug(("%s: called (what=%04x, arg=%p)", __func__, what, arg));
    489 	/* ignore */
    490 }
    491 
    492 #ifndef SHUT_WR
    493 #ifdef WIN32
    494 #define SHUT_WR SD_SEND
    495 #else
    496 #define SHUT_WR 1
    497 #endif
    498 #endif
    499 
    500 static void
    501 http_badreq_readcb(struct bufferevent *bev, void *arg)
    502 {
    503 	const char *what = "Hello, 127.0.0.1";
    504 	const char *bad_request = "400 Bad Request";
    505 
    506 	if (evbuffer_contains(bufferevent_get_input(bev), bad_request)) {
    507 		TT_FAIL(("%s:bad request detected", __func__));
    508 		bufferevent_disable(bev, EV_READ);
    509 		event_base_loopexit(arg, NULL);
    510 		return;
    511 	}
    512 
    513 	if (evbuffer_contains(bufferevent_get_input(bev), what)) {
    514 		struct evhttp_request *req = evhttp_request_new(NULL, NULL);
    515 		enum message_read_status done;
    516 
    517 		/* req->kind = EVHTTP_RESPONSE; */
    518 		done = evhttp_parse_firstline(req, bufferevent_get_input(bev));
    519 		if (done != ALL_DATA_READ)
    520 			goto out;
    521 
    522 		done = evhttp_parse_headers(req, bufferevent_get_input(bev));
    523 		if (done != ALL_DATA_READ)
    524 			goto out;
    525 
    526 		if (done == 1 &&
    527 		    evhttp_find_header(evhttp_request_get_input_headers(req),
    528 			"Content-Type") != NULL)
    529 			test_ok++;
    530 
    531 	out:
    532 		evhttp_request_free(req);
    533 		evbuffer_drain(bufferevent_get_input(bev), evbuffer_get_length(bufferevent_get_input(bev)));
    534 	}
    535 
    536 	shutdown(bufferevent_getfd(bev), SHUT_WR);
    537 }
    538 
    539 static void
    540 http_badreq_successcb(evutil_socket_t fd, short what, void *arg)
    541 {
    542 	event_debug(("%s: called (what=%04x, arg=%p)", __func__, what, arg));
    543 	event_base_loopexit(exit_base, NULL);
    544 }
    545 
    546 static void
    547 http_bad_request_test(void *arg)
    548 {
    549 	struct basic_test_data *data = arg;
    550 	struct timeval tv;
    551 	struct bufferevent *bev = NULL;
    552 	evutil_socket_t fd;
    553 	const char *http_request;
    554 	ev_uint16_t port=0, port2=0;
    555 
    556 	test_ok = 0;
    557 	exit_base = data->base;
    558 
    559 	http = http_setup(&port, data->base);
    560 
    561 	/* bind to a second socket */
    562 	if (http_bind(http, &port2) == -1)
    563 		TT_DIE(("Bind socket failed"));
    564 
    565 	/* NULL request test */
    566 	fd = http_connect("127.0.0.1", port);
    567 
    568 	/* Stupid thing to send a request */
    569 	bev = bufferevent_socket_new(data->base, fd, 0);
    570 	bufferevent_setcb(bev, http_badreq_readcb, http_writecb,
    571 	    http_badreq_errorcb, data->base);
    572 	bufferevent_enable(bev, EV_READ);
    573 
    574 	/* real NULL request */
    575 	http_request = "";
    576 
    577 	bufferevent_write(bev, http_request, strlen(http_request));
    578 
    579 	shutdown(fd, SHUT_WR);
    580 	timerclear(&tv);
    581 	tv.tv_usec = 10000;
    582 	event_base_once(data->base, -1, EV_TIMEOUT, http_badreq_successcb, bev, &tv);
    583 
    584 	event_base_dispatch(data->base);
    585 
    586 	bufferevent_free(bev);
    587 	evutil_closesocket(fd);
    588 
    589 	if (test_ok != 0) {
    590 		fprintf(stdout, "FAILED\n");
    591 		exit(1);
    592 	}
    593 
    594 	/* Second answer (BAD REQUEST) on connection close */
    595 
    596 	/* connect to the second port */
    597 	fd = http_connect("127.0.0.1", port2);
    598 
    599 	/* Stupid thing to send a request */
    600 	bev = bufferevent_socket_new(data->base, fd, 0);
    601 	bufferevent_setcb(bev, http_badreq_readcb, http_writecb,
    602 	    http_badreq_errorcb, data->base);
    603 	bufferevent_enable(bev, EV_READ);
    604 
    605 	/* first half of the http request */
    606 	http_request =
    607 		"GET /badrequest HTTP/1.0\r\n"	\
    608 		"Connection: Keep-Alive\r\n"	\
    609 		"\r\n";
    610 
    611 	bufferevent_write(bev, http_request, strlen(http_request));
    612 
    613 	timerclear(&tv);
    614 	tv.tv_usec = 10000;
    615 	event_base_once(data->base, -1, EV_TIMEOUT, http_badreq_successcb, bev, &tv);
    616 
    617 	event_base_dispatch(data->base);
    618 
    619 	tt_int_op(test_ok, ==, 2);
    620 
    621 end:
    622 	evhttp_free(http);
    623 	if (bev)
    624 		bufferevent_free(bev);
    625 }
    626 
    627 static struct evhttp_connection *delayed_client;
    628 
    629 static void
    630 http_large_delay_cb(struct evhttp_request *req, void *arg)
    631 {
    632 	struct timeval tv;
    633 	evutil_timerclear(&tv);
    634 	tv.tv_sec = 3;
    635 
    636 	event_base_once(arg, -1, EV_TIMEOUT, http_delay_reply, req, &tv);
    637 	evhttp_connection_fail(delayed_client, EVCON_HTTP_EOF);
    638 }
    639 
    640 /*
    641  * HTTP DELETE test,  just piggyback on the basic test
    642  */
    643 
    644 static void
    645 http_delete_cb(struct evhttp_request *req, void *arg)
    646 {
    647 	struct evbuffer *evb = evbuffer_new();
    648 	int empty = evhttp_find_header(evhttp_request_get_input_headers(req), "Empty") != NULL;
    649 
    650 	/* Expecting a DELETE request */
    651 	if (evhttp_request_get_command(req) != EVHTTP_REQ_DELETE) {
    652 		fprintf(stdout, "FAILED (delete type)\n");
    653 		exit(1);
    654 	}
    655 
    656 	event_debug(("%s: called\n", __func__));
    657 	evbuffer_add_printf(evb, BASIC_REQUEST_BODY);
    658 
    659 	/* allow sending of an empty reply */
    660 	evhttp_send_reply(req, HTTP_OK, "Everything is fine",
    661 	    !empty ? evb : NULL);
    662 
    663 	evbuffer_free(evb);
    664 }
    665 
    666 static void
    667 http_delete_test(void *arg)
    668 {
    669 	struct basic_test_data *data = arg;
    670 	struct bufferevent *bev;
    671 	evutil_socket_t fd;
    672 	const char *http_request;
    673 	ev_uint16_t port = 0;
    674 
    675 	test_ok = 0;
    676 
    677 	http = http_setup(&port, data->base);
    678 
    679 	fd = http_connect("127.0.0.1", port);
    680 
    681 	/* Stupid thing to send a request */
    682 	bev = bufferevent_socket_new(data->base, fd, 0);
    683 	bufferevent_setcb(bev, http_readcb, http_writecb,
    684 	    http_errorcb, data->base);
    685 
    686 	http_request =
    687 	    "DELETE /deleteit HTTP/1.1\r\n"
    688 	    "Host: somehost\r\n"
    689 	    "Connection: close\r\n"
    690 	    "\r\n";
    691 
    692 	bufferevent_write(bev, http_request, strlen(http_request));
    693 
    694 	event_base_dispatch(data->base);
    695 
    696 	bufferevent_free(bev);
    697 	evutil_closesocket(fd);
    698 
    699 	evhttp_free(http);
    700 
    701 	tt_int_op(test_ok, ==, 2);
    702  end:
    703 	;
    704 }
    705 
    706 static void
    707 http_allowed_methods_eventcb(struct bufferevent *bev, short what, void *arg)
    708 {
    709 	char **output = arg;
    710 	if ((what & (BEV_EVENT_ERROR|BEV_EVENT_EOF))) {
    711 		char buf[4096];
    712 		int n;
    713 		n = evbuffer_remove(bufferevent_get_input(bev), buf,
    714 		    sizeof(buf)-1);
    715 		if (n >= 0) {
    716 			buf[n]='\0';
    717 			if (*output)
    718 				free(*output);
    719 			*output = strdup(buf);
    720 		}
    721 		event_base_loopexit(exit_base, NULL);
    722 	}
    723 }
    724 
    725 static void
    726 http_allowed_methods_test(void *arg)
    727 {
    728 	struct basic_test_data *data = arg;
    729 	struct bufferevent *bev1, *bev2, *bev3;
    730 	evutil_socket_t fd1, fd2, fd3;
    731 	const char *http_request;
    732 	char *result1=NULL, *result2=NULL, *result3=NULL;
    733 	ev_uint16_t port = 0;
    734 
    735 	exit_base = data->base;
    736 	test_ok = 0;
    737 
    738 	http = http_setup(&port, data->base);
    739 
    740 	fd1 = http_connect("127.0.0.1", port);
    741 
    742 	/* GET is out; PATCH is in. */
    743 	evhttp_set_allowed_methods(http, EVHTTP_REQ_PATCH);
    744 
    745 	/* Stupid thing to send a request */
    746 	bev1 = bufferevent_socket_new(data->base, fd1, 0);
    747 	bufferevent_enable(bev1, EV_READ|EV_WRITE);
    748 	bufferevent_setcb(bev1, NULL, NULL,
    749 	    http_allowed_methods_eventcb, &result1);
    750 
    751 	http_request =
    752 	    "GET /index.html HTTP/1.1\r\n"
    753 	    "Host: somehost\r\n"
    754 	    "Connection: close\r\n"
    755 	    "\r\n";
    756 
    757 	bufferevent_write(bev1, http_request, strlen(http_request));
    758 
    759 	event_base_dispatch(data->base);
    760 
    761 	fd2 = http_connect("127.0.0.1", port);
    762 
    763 	bev2 = bufferevent_socket_new(data->base, fd2, 0);
    764 	bufferevent_enable(bev2, EV_READ|EV_WRITE);
    765 	bufferevent_setcb(bev2, NULL, NULL,
    766 	    http_allowed_methods_eventcb, &result2);
    767 
    768 	http_request =
    769 	    "PATCH /test HTTP/1.1\r\n"
    770 	    "Host: somehost\r\n"
    771 	    "Connection: close\r\n"
    772 	    "\r\n";
    773 
    774 	bufferevent_write(bev2, http_request, strlen(http_request));
    775 
    776 	event_base_dispatch(data->base);
    777 
    778 	fd3 = http_connect("127.0.0.1", port);
    779 
    780 	bev3 = bufferevent_socket_new(data->base, fd3, 0);
    781 	bufferevent_enable(bev3, EV_READ|EV_WRITE);
    782 	bufferevent_setcb(bev3, NULL, NULL,
    783 	    http_allowed_methods_eventcb, &result3);
    784 
    785 	http_request =
    786 	    "FLOOP /test HTTP/1.1\r\n"
    787 	    "Host: somehost\r\n"
    788 	    "Connection: close\r\n"
    789 	    "\r\n";
    790 
    791 	bufferevent_write(bev3, http_request, strlen(http_request));
    792 
    793 	event_base_dispatch(data->base);
    794 
    795 	bufferevent_free(bev1);
    796 	bufferevent_free(bev2);
    797 	bufferevent_free(bev3);
    798 	evutil_closesocket(fd1);
    799 	evutil_closesocket(fd2);
    800 	evutil_closesocket(fd3);
    801 
    802 	evhttp_free(http);
    803 
    804 	/* Method known but disallowed */
    805 	tt_assert(result1);
    806 	tt_assert(!strncmp(result1, "HTTP/1.1 501 ", strlen("HTTP/1.1 501 ")));
    807 
    808 	/* Method known and allowed */
    809 	tt_assert(result2);
    810 	tt_assert(!strncmp(result2, "HTTP/1.1 200 ", strlen("HTTP/1.1 200 ")));
    811 
    812 	/* Method unknown */
    813 	tt_assert(result3);
    814 	tt_assert(!strncmp(result3, "HTTP/1.1 501 ", strlen("HTTP/1.1 501 ")));
    815 
    816  end:
    817 	if (result1)
    818 		free(result1);
    819 	if (result2)
    820 		free(result2);
    821 	if (result3)
    822 		free(result3);
    823 }
    824 
    825 static void http_request_done(struct evhttp_request *, void *);
    826 static void http_request_empty_done(struct evhttp_request *, void *);
    827 
    828 static void
    829 _http_connection_test(struct basic_test_data *data, int persistent)
    830 {
    831 	ev_uint16_t port = 0;
    832 	struct evhttp_connection *evcon = NULL;
    833 	struct evhttp_request *req = NULL;
    834 
    835 	test_ok = 0;
    836 
    837 	http = http_setup(&port, data->base);
    838 
    839 	evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port);
    840 	tt_assert(evcon);
    841 
    842 	tt_assert(evhttp_connection_get_base(evcon) == data->base);
    843 
    844 	exit_base = data->base;
    845 	/*
    846 	 * At this point, we want to schedule a request to the HTTP
    847 	 * server using our make request method.
    848 	 */
    849 
    850 	req = evhttp_request_new(http_request_done, (void*) BASIC_REQUEST_BODY);
    851 
    852 	/* Add the information that we care about */
    853 	evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
    854 
    855 	/* We give ownership of the request to the connection */
    856 	if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test") == -1) {
    857 		fprintf(stdout, "FAILED\n");
    858 		exit(1);
    859 	}
    860 
    861 	event_base_dispatch(data->base);
    862 
    863 	tt_assert(test_ok);
    864 
    865 	/* try to make another request over the same connection */
    866 	test_ok = 0;
    867 
    868 	req = evhttp_request_new(http_request_done, (void*) BASIC_REQUEST_BODY);
    869 
    870 	/* Add the information that we care about */
    871 	evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
    872 
    873 	/*
    874 	 * if our connections are not supposed to be persistent; request
    875 	 * a close from the server.
    876 	 */
    877 	if (!persistent)
    878 		evhttp_add_header(evhttp_request_get_output_headers(req), "Connection", "close");
    879 
    880 	/* We give ownership of the request to the connection */
    881 	if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test") == -1) {
    882 		tt_abort_msg("couldn't make request");
    883 	}
    884 
    885 	event_base_dispatch(data->base);
    886 
    887 	/* make another request: request empty reply */
    888 	test_ok = 0;
    889 
    890 	req = evhttp_request_new(http_request_empty_done, data->base);
    891 
    892 	/* Add the information that we care about */
    893 	evhttp_add_header(evhttp_request_get_output_headers(req), "Empty", "itis");
    894 
    895 	/* We give ownership of the request to the connection */
    896 	if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test") == -1) {
    897 		tt_abort_msg("Couldn't make request");
    898 	}
    899 
    900 	event_base_dispatch(data->base);
    901 
    902  end:
    903 	if (evcon)
    904 		evhttp_connection_free(evcon);
    905 	if (http)
    906 		evhttp_free(http);
    907 }
    908 
    909 static void
    910 http_connection_test(void *arg)
    911 {
    912 	_http_connection_test(arg, 0);
    913 }
    914 static void
    915 http_persist_connection_test(void *arg)
    916 {
    917 	_http_connection_test(arg, 1);
    918 }
    919 
    920 static struct regress_dns_server_table search_table[] = {
    921 	{ "localhost", "A", "127.0.0.1", 0 },
    922 	{ NULL, NULL, NULL, 0 }
    923 };
    924 
    925 static void
    926 http_connection_async_test(void *arg)
    927 {
    928 	struct basic_test_data *data = arg;
    929 	ev_uint16_t port = 0;
    930 	struct evhttp_connection *evcon = NULL;
    931 	struct evhttp_request *req = NULL;
    932 	struct evdns_base *dns_base = NULL;
    933 	ev_uint16_t portnum = 0;
    934 	char address[64];
    935 
    936 	exit_base = data->base;
    937 	tt_assert(regress_dnsserver(data->base, &portnum, search_table));
    938 
    939 	dns_base = evdns_base_new(data->base, 0/* init name servers */);
    940 	tt_assert(dns_base);
    941 
    942 	/* Add ourself as the only nameserver, and make sure we really are
    943 	 * the only nameserver. */
    944 	evutil_snprintf(address, sizeof(address), "127.0.0.1:%d", portnum);
    945 	evdns_base_nameserver_ip_add(dns_base, address);
    946 
    947 	test_ok = 0;
    948 
    949 	http = http_setup(&port, data->base);
    950 
    951 	evcon = evhttp_connection_base_new(data->base, dns_base, "127.0.0.1", port);
    952 	tt_assert(evcon);
    953 
    954 	/*
    955 	 * At this point, we want to schedule a request to the HTTP
    956 	 * server using our make request method.
    957 	 */
    958 
    959 	req = evhttp_request_new(http_request_done, (void*) BASIC_REQUEST_BODY);
    960 
    961 	/* Add the information that we care about */
    962 	evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
    963 
    964 	/* We give ownership of the request to the connection */
    965 	if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test") == -1) {
    966 		fprintf(stdout, "FAILED\n");
    967 		exit(1);
    968 	}
    969 
    970 	event_base_dispatch(data->base);
    971 
    972 	tt_assert(test_ok);
    973 
    974 	/* try to make another request over the same connection */
    975 	test_ok = 0;
    976 
    977 	req = evhttp_request_new(http_request_done, (void*) BASIC_REQUEST_BODY);
    978 
    979 	/* Add the information that we care about */
    980 	evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
    981 
    982 	/*
    983 	 * if our connections are not supposed to be persistent; request
    984 	 * a close from the server.
    985 	 */
    986 	evhttp_add_header(evhttp_request_get_output_headers(req), "Connection", "close");
    987 
    988 	/* We give ownership of the request to the connection */
    989 	if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test") == -1) {
    990 		tt_abort_msg("couldn't make request");
    991 	}
    992 
    993 	event_base_dispatch(data->base);
    994 
    995 	/* make another request: request empty reply */
    996 	test_ok = 0;
    997 
    998 	req = evhttp_request_new(http_request_empty_done, data->base);
    999 
   1000 	/* Add the information that we care about */
   1001 	evhttp_add_header(evhttp_request_get_output_headers(req), "Empty", "itis");
   1002 
   1003 	/* We give ownership of the request to the connection */
   1004 	if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test") == -1) {
   1005 		tt_abort_msg("Couldn't make request");
   1006 	}
   1007 
   1008 	event_base_dispatch(data->base);
   1009 
   1010  end:
   1011 	if (evcon)
   1012 		evhttp_connection_free(evcon);
   1013 	if (http)
   1014 		evhttp_free(http);
   1015 	if (dns_base)
   1016 		evdns_base_free(dns_base, 0);
   1017 	regress_clean_dnsserver();
   1018 }
   1019 
   1020 static void
   1021 http_request_never_call(struct evhttp_request *req, void *arg)
   1022 {
   1023 	fprintf(stdout, "FAILED\n");
   1024 	exit(1);
   1025 }
   1026 
   1027 static void
   1028 http_do_cancel(evutil_socket_t fd, short what, void *arg)
   1029 {
   1030 	struct evhttp_request *req = arg;
   1031 	struct timeval tv;
   1032 	struct event_base *base;
   1033 	evutil_timerclear(&tv);
   1034 	tv.tv_sec = 0;
   1035 	tv.tv_usec = 500 * 1000;
   1036 
   1037 	base = evhttp_connection_get_base(evhttp_request_get_connection(req));
   1038 	evhttp_cancel_request(req);
   1039 
   1040 	event_base_loopexit(base, &tv);
   1041 
   1042 	++test_ok;
   1043 }
   1044 
   1045 static void
   1046 http_cancel_test(void *arg)
   1047 {
   1048 	struct basic_test_data *data = arg;
   1049 	ev_uint16_t port = 0;
   1050 	struct evhttp_connection *evcon = NULL;
   1051 	struct evhttp_request *req = NULL;
   1052 	struct timeval tv;
   1053 
   1054 	exit_base = data->base;
   1055 
   1056 	test_ok = 0;
   1057 
   1058 	http = http_setup(&port, data->base);
   1059 
   1060 	evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port);
   1061 	tt_assert(evcon);
   1062 
   1063 	/*
   1064 	 * At this point, we want to schedule a request to the HTTP
   1065 	 * server using our make request method.
   1066 	 */
   1067 
   1068 	req = evhttp_request_new(http_request_never_call, NULL);
   1069 
   1070 	/* Add the information that we care about */
   1071 	evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
   1072 
   1073 	/* We give ownership of the request to the connection */
   1074 	tt_int_op(evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/delay"),
   1075 		  !=, -1);
   1076 
   1077 	evutil_timerclear(&tv);
   1078 	tv.tv_sec = 0;
   1079 	tv.tv_usec = 100 * 1000;
   1080 
   1081 	event_base_once(data->base, -1, EV_TIMEOUT, http_do_cancel, req, &tv);
   1082 
   1083 	event_base_dispatch(data->base);
   1084 
   1085 	tt_int_op(test_ok, ==, 2);
   1086 
   1087 	/* try to make another request over the same connection */
   1088 	test_ok = 0;
   1089 
   1090 	req = evhttp_request_new(http_request_done, (void*) BASIC_REQUEST_BODY);
   1091 
   1092 	/* Add the information that we care about */
   1093 	evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
   1094 
   1095 	/* We give ownership of the request to the connection */
   1096 	tt_int_op(evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test"),
   1097 		  !=, -1);
   1098 
   1099 	event_base_dispatch(data->base);
   1100 
   1101 	/* make another request: request empty reply */
   1102 	test_ok = 0;
   1103 
   1104 	req = evhttp_request_new(http_request_empty_done, data->base);
   1105 
   1106 	/* Add the information that we care about */
   1107 	evhttp_add_header(evhttp_request_get_output_headers(req), "Empty", "itis");
   1108 
   1109 	/* We give ownership of the request to the connection */
   1110 	tt_int_op(evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test"),
   1111 		  !=, -1);
   1112 
   1113 	event_base_dispatch(data->base);
   1114 
   1115  end:
   1116 	if (evcon)
   1117 		evhttp_connection_free(evcon);
   1118 	if (http)
   1119 		evhttp_free(http);
   1120 }
   1121 
   1122 static void
   1123 http_request_done(struct evhttp_request *req, void *arg)
   1124 {
   1125 	const char *what = arg;
   1126 
   1127 	if (evhttp_request_get_response_code(req) != HTTP_OK) {
   1128 		fprintf(stderr, "FAILED\n");
   1129 		exit(1);
   1130 	}
   1131 
   1132 	if (evhttp_find_header(evhttp_request_get_input_headers(req), "Content-Type") == NULL) {
   1133 		fprintf(stderr, "FAILED\n");
   1134 		exit(1);
   1135 	}
   1136 
   1137 	if (evbuffer_get_length(evhttp_request_get_input_buffer(req)) != strlen(what)) {
   1138 		fprintf(stderr, "FAILED\n");
   1139 		exit(1);
   1140 	}
   1141 
   1142 	if (evbuffer_datacmp(evhttp_request_get_input_buffer(req), what) != 0) {
   1143 		fprintf(stderr, "FAILED\n");
   1144 		exit(1);
   1145 	}
   1146 
   1147 	test_ok = 1;
   1148 	EVUTIL_ASSERT(exit_base);
   1149 	event_base_loopexit(exit_base, NULL);
   1150 }
   1151 
   1152 static void
   1153 http_request_expect_error(struct evhttp_request *req, void *arg)
   1154 {
   1155 	if (evhttp_request_get_response_code(req) == HTTP_OK) {
   1156 		fprintf(stderr, "FAILED\n");
   1157 		exit(1);
   1158 	}
   1159 
   1160 	test_ok = 1;
   1161 	EVUTIL_ASSERT(arg);
   1162 	event_base_loopexit(arg, NULL);
   1163 }
   1164 
   1165 /* test virtual hosts */
   1166 static void
   1167 http_virtual_host_test(void *arg)
   1168 {
   1169 	struct basic_test_data *data = arg;
   1170 	ev_uint16_t port = 0;
   1171 	struct evhttp_connection *evcon = NULL;
   1172 	struct evhttp_request *req = NULL;
   1173 	struct evhttp *second = NULL, *third = NULL;
   1174 	evutil_socket_t fd;
   1175 	struct bufferevent *bev;
   1176 	const char *http_request;
   1177 
   1178 	exit_base = data->base;
   1179 
   1180 	http = http_setup(&port, data->base);
   1181 
   1182 	/* virtual host */
   1183 	second = evhttp_new(NULL);
   1184 	evhttp_set_cb(second, "/funnybunny", http_basic_cb, NULL);
   1185 	third = evhttp_new(NULL);
   1186 	evhttp_set_cb(third, "/blackcoffee", http_basic_cb, NULL);
   1187 
   1188 	if (evhttp_add_virtual_host(http, "foo.com", second) == -1) {
   1189 		tt_abort_msg("Couldn't add vhost");
   1190 	}
   1191 
   1192 	if (evhttp_add_virtual_host(http, "bar.*.foo.com", third) == -1) {
   1193 		tt_abort_msg("Couldn't add wildcarded vhost");
   1194 	}
   1195 
   1196 	/* add some aliases to the vhosts */
   1197 	tt_assert(evhttp_add_server_alias(second, "manolito.info") == 0);
   1198 	tt_assert(evhttp_add_server_alias(third, "bonkers.org") == 0);
   1199 
   1200 	evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port);
   1201 	tt_assert(evcon);
   1202 
   1203 	/* make a request with a different host and expect an error */
   1204 	req = evhttp_request_new(http_request_expect_error, data->base);
   1205 
   1206 	/* Add the information that we care about */
   1207 	evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
   1208 
   1209 	/* We give ownership of the request to the connection */
   1210 	if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET,
   1211 		"/funnybunny") == -1) {
   1212 		tt_abort_msg("Couldn't make request");
   1213 	}
   1214 
   1215 	event_base_dispatch(data->base);
   1216 
   1217 	tt_assert(test_ok == 1);
   1218 
   1219 	test_ok = 0;
   1220 
   1221 	/* make a request with the right host and expect a response */
   1222 	req = evhttp_request_new(http_request_done, (void*) BASIC_REQUEST_BODY);
   1223 
   1224 	/* Add the information that we care about */
   1225 	evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "foo.com");
   1226 
   1227 	/* We give ownership of the request to the connection */
   1228 	if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET,
   1229 		"/funnybunny") == -1) {
   1230 		fprintf(stdout, "FAILED\n");
   1231 		exit(1);
   1232 	}
   1233 
   1234 	event_base_dispatch(data->base);
   1235 
   1236 	tt_assert(test_ok == 1);
   1237 
   1238 	test_ok = 0;
   1239 
   1240 	/* make a request with the right host and expect a response */
   1241 	req = evhttp_request_new(http_request_done, (void*) BASIC_REQUEST_BODY);
   1242 
   1243 	/* Add the information that we care about */
   1244 	evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "bar.magic.foo.com");
   1245 
   1246 	/* We give ownership of the request to the connection */
   1247 	if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET,
   1248 		"/blackcoffee") == -1) {
   1249 		tt_abort_msg("Couldn't make request");
   1250 	}
   1251 
   1252 	event_base_dispatch(data->base);
   1253 
   1254 	tt_assert(test_ok == 1)
   1255 
   1256 	test_ok = 0;
   1257 
   1258 	/* make a request with the right host and expect a response */
   1259 	req = evhttp_request_new(http_request_done, (void*) BASIC_REQUEST_BODY);
   1260 
   1261 	/* Add the information that we care about */
   1262 	evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "manolito.info");
   1263 
   1264 	/* We give ownership of the request to the connection */
   1265 	if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET,
   1266 		"/funnybunny") == -1) {
   1267 		tt_abort_msg("Couldn't make request");
   1268 	}
   1269 
   1270 	event_base_dispatch(data->base);
   1271 
   1272 	tt_assert(test_ok == 1)
   1273 
   1274 	test_ok = 0;
   1275 
   1276 	/* make a request with the right host and expect a response */
   1277 	req = evhttp_request_new(http_request_done, (void*) BASIC_REQUEST_BODY);
   1278 
   1279 	/* Add the Host header. This time with the optional port. */
   1280 	evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "bonkers.org:8000");
   1281 
   1282 	/* We give ownership of the request to the connection */
   1283 	if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET,
   1284 		"/blackcoffee") == -1) {
   1285 		tt_abort_msg("Couldn't make request");
   1286 	}
   1287 
   1288 	event_base_dispatch(data->base);
   1289 
   1290 	tt_assert(test_ok == 1)
   1291 
   1292 	test_ok = 0;
   1293 
   1294 	/* Now make a raw request with an absolute URI. */
   1295 	fd = http_connect("127.0.0.1", port);
   1296 
   1297 	/* Stupid thing to send a request */
   1298 	bev = bufferevent_socket_new(data->base, fd, 0);
   1299 	bufferevent_setcb(bev, http_readcb, http_writecb,
   1300 	    http_errorcb, NULL);
   1301 
   1302 	/* The host in the URI should override the Host: header */
   1303 	http_request =
   1304 	    "GET http://manolito.info/funnybunny HTTP/1.1\r\n"
   1305 	    "Host: somehost\r\n"
   1306 	    "Connection: close\r\n"
   1307 	    "\r\n";
   1308 
   1309 	bufferevent_write(bev, http_request, strlen(http_request));
   1310 
   1311 	event_base_dispatch(data->base);
   1312 
   1313 	tt_int_op(test_ok, ==, 2);
   1314 
   1315 	bufferevent_free(bev);
   1316 	evutil_closesocket(fd);
   1317 
   1318  end:
   1319 	if (evcon)
   1320 		evhttp_connection_free(evcon);
   1321 	if (http)
   1322 		evhttp_free(http);
   1323 }
   1324 
   1325 
   1326 /* test date header and content length */
   1327 
   1328 static void
   1329 http_request_empty_done(struct evhttp_request *req, void *arg)
   1330 {
   1331 	if (evhttp_request_get_response_code(req) != HTTP_OK) {
   1332 		fprintf(stderr, "FAILED\n");
   1333 		exit(1);
   1334 	}
   1335 
   1336 	if (evhttp_find_header(evhttp_request_get_input_headers(req), "Date") == NULL) {
   1337 		fprintf(stderr, "FAILED\n");
   1338 		exit(1);
   1339 	}
   1340 
   1341 
   1342 	if (evhttp_find_header(evhttp_request_get_input_headers(req), "Content-Length") == NULL) {
   1343 		fprintf(stderr, "FAILED\n");
   1344 		exit(1);
   1345 	}
   1346 
   1347 	if (strcmp(evhttp_find_header(evhttp_request_get_input_headers(req), "Content-Length"),
   1348 		"0")) {
   1349 		fprintf(stderr, "FAILED\n");
   1350 		exit(1);
   1351 	}
   1352 
   1353 	if (evbuffer_get_length(evhttp_request_get_input_buffer(req)) != 0) {
   1354 		fprintf(stderr, "FAILED\n");
   1355 		exit(1);
   1356 	}
   1357 
   1358 	test_ok = 1;
   1359 	EVUTIL_ASSERT(arg);
   1360 	event_base_loopexit(arg, NULL);
   1361 }
   1362 
   1363 /*
   1364  * HTTP DISPATCHER test
   1365  */
   1366 
   1367 void
   1368 http_dispatcher_cb(struct evhttp_request *req, void *arg)
   1369 {
   1370 
   1371 	struct evbuffer *evb = evbuffer_new();
   1372 	event_debug(("%s: called\n", __func__));
   1373 	evbuffer_add_printf(evb, "DISPATCHER_TEST");
   1374 
   1375 	evhttp_send_reply(req, HTTP_OK, "Everything is fine", evb);
   1376 
   1377 	evbuffer_free(evb);
   1378 }
   1379 
   1380 static void
   1381 http_dispatcher_test_done(struct evhttp_request *req, void *arg)
   1382 {
   1383 	struct event_base *base = arg;
   1384 	const char *what = "DISPATCHER_TEST";
   1385 
   1386 	if (evhttp_request_get_response_code(req) != HTTP_OK) {
   1387 		fprintf(stderr, "FAILED\n");
   1388 		exit(1);
   1389 	}
   1390 
   1391 	if (evhttp_find_header(evhttp_request_get_input_headers(req), "Content-Type") == NULL) {
   1392 		fprintf(stderr, "FAILED (content type)\n");
   1393 		exit(1);
   1394 	}
   1395 
   1396 	if (evbuffer_get_length(evhttp_request_get_input_buffer(req)) != strlen(what)) {
   1397 		fprintf(stderr, "FAILED (length %lu vs %lu)\n",
   1398 		    (unsigned long)evbuffer_get_length(evhttp_request_get_input_buffer(req)), (unsigned long)strlen(what));
   1399 		exit(1);
   1400 	}
   1401 
   1402 	if (evbuffer_datacmp(evhttp_request_get_input_buffer(req), what) != 0) {
   1403 		fprintf(stderr, "FAILED (data)\n");
   1404 		exit(1);
   1405 	}
   1406 
   1407 	test_ok = 1;
   1408 	event_base_loopexit(base, NULL);
   1409 }
   1410 
   1411 static void
   1412 http_dispatcher_test(void *arg)
   1413 {
   1414 	struct basic_test_data *data = arg;
   1415 	ev_uint16_t port = 0;
   1416 	struct evhttp_connection *evcon = NULL;
   1417 	struct evhttp_request *req = NULL;
   1418 
   1419 	test_ok = 0;
   1420 
   1421 	http = http_setup(&port, data->base);
   1422 
   1423 	evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port);
   1424 	tt_assert(evcon);
   1425 
   1426 	/* also bind to local host */
   1427 	evhttp_connection_set_local_address(evcon, "127.0.0.1");
   1428 
   1429 	/*
   1430 	 * At this point, we want to schedule an HTTP GET request
   1431 	 * server using our make request method.
   1432 	 */
   1433 
   1434 	req = evhttp_request_new(http_dispatcher_test_done, data->base);
   1435 	tt_assert(req);
   1436 
   1437 	/* Add the information that we care about */
   1438 	evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
   1439 
   1440 	if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/?arg=val") == -1) {
   1441 		tt_abort_msg("Couldn't make request");
   1442 	}
   1443 
   1444 	event_base_dispatch(data->base);
   1445 
   1446  end:
   1447 	if (evcon)
   1448 		evhttp_connection_free(evcon);
   1449 	if (http)
   1450 		evhttp_free(http);
   1451 }
   1452 
   1453 /*
   1454  * HTTP POST test.
   1455  */
   1456 
   1457 void http_postrequest_done(struct evhttp_request *, void *);
   1458 
   1459 #define POST_DATA "Okay.  Not really printf"
   1460 
   1461 static void
   1462 http_post_test(void *arg)
   1463 {
   1464 	struct basic_test_data *data = arg;
   1465 	ev_uint16_t port = 0;
   1466 	struct evhttp_connection *evcon = NULL;
   1467 	struct evhttp_request *req = NULL;
   1468 
   1469 	test_ok = 0;
   1470 
   1471 	http = http_setup(&port, data->base);
   1472 
   1473 	evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port);
   1474 	tt_assert(evcon);
   1475 
   1476 	/*
   1477 	 * At this point, we want to schedule an HTTP POST request
   1478 	 * server using our make request method.
   1479 	 */
   1480 
   1481 	req = evhttp_request_new(http_postrequest_done, data->base);
   1482 	tt_assert(req);
   1483 
   1484 	/* Add the information that we care about */
   1485 	evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
   1486 	evbuffer_add_printf(evhttp_request_get_output_buffer(req), POST_DATA);
   1487 
   1488 	if (evhttp_make_request(evcon, req, EVHTTP_REQ_POST, "/postit") == -1) {
   1489 		tt_abort_msg("Couldn't make request");
   1490 	}
   1491 
   1492 	event_base_dispatch(data->base);
   1493 
   1494 	tt_int_op(test_ok, ==, 1);
   1495 
   1496 	test_ok = 0;
   1497 
   1498 	req = evhttp_request_new(http_postrequest_done, data->base);
   1499 	tt_assert(req);
   1500 
   1501 	/* Now try with 100-continue. */
   1502 
   1503 	/* Add the information that we care about */
   1504 	evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
   1505 	evhttp_add_header(evhttp_request_get_output_headers(req), "Expect", "100-continue");
   1506 	evbuffer_add_printf(evhttp_request_get_output_buffer(req), POST_DATA);
   1507 
   1508 	if (evhttp_make_request(evcon, req, EVHTTP_REQ_POST, "/postit") == -1) {
   1509 		tt_abort_msg("Couldn't make request");
   1510 	}
   1511 
   1512 	event_base_dispatch(data->base);
   1513 
   1514 	tt_int_op(test_ok, ==, 1);
   1515 
   1516 	evhttp_connection_free(evcon);
   1517 	evhttp_free(http);
   1518 
   1519  end:
   1520 	;
   1521 }
   1522 
   1523 void
   1524 http_post_cb(struct evhttp_request *req, void *arg)
   1525 {
   1526 	struct evbuffer *evb;
   1527 	event_debug(("%s: called\n", __func__));
   1528 
   1529 	/* Yes, we are expecting a post request */
   1530 	if (evhttp_request_get_command(req) != EVHTTP_REQ_POST) {
   1531 		fprintf(stdout, "FAILED (post type)\n");
   1532 		exit(1);
   1533 	}
   1534 
   1535 	if (evbuffer_get_length(evhttp_request_get_input_buffer(req)) != strlen(POST_DATA)) {
   1536 		fprintf(stdout, "FAILED (length: %lu vs %lu)\n",
   1537 		    (unsigned long) evbuffer_get_length(evhttp_request_get_input_buffer(req)), (unsigned long) strlen(POST_DATA));
   1538 		exit(1);
   1539 	}
   1540 
   1541 	if (evbuffer_datacmp(evhttp_request_get_input_buffer(req), POST_DATA) != 0) {
   1542 		fprintf(stdout, "FAILED (data)\n");
   1543 		fprintf(stdout, "Got :%s\n", evbuffer_pullup(evhttp_request_get_input_buffer(req),-1));
   1544 		fprintf(stdout, "Want:%s\n", POST_DATA);
   1545 		exit(1);
   1546 	}
   1547 
   1548 	evb = evbuffer_new();
   1549 	evbuffer_add_printf(evb, BASIC_REQUEST_BODY);
   1550 
   1551 	evhttp_send_reply(req, HTTP_OK, "Everything is fine", evb);
   1552 
   1553 	evbuffer_free(evb);
   1554 }
   1555 
   1556 void
   1557 http_postrequest_done(struct evhttp_request *req, void *arg)
   1558 {
   1559 	const char *what = BASIC_REQUEST_BODY;
   1560 	struct event_base *base = arg;
   1561 
   1562 	if (req == NULL) {
   1563 		fprintf(stderr, "FAILED (timeout)\n");
   1564 		exit(1);
   1565 	}
   1566 
   1567 	if (evhttp_request_get_response_code(req) != HTTP_OK) {
   1568 
   1569 		fprintf(stderr, "FAILED (response code)\n");
   1570 		exit(1);
   1571 	}
   1572 
   1573 	if (evhttp_find_header(evhttp_request_get_input_headers(req), "Content-Type") == NULL) {
   1574 		fprintf(stderr, "FAILED (content type)\n");
   1575 		exit(1);
   1576 	}
   1577 
   1578 	if (evbuffer_get_length(evhttp_request_get_input_buffer(req)) != strlen(what)) {
   1579 		fprintf(stderr, "FAILED (length %lu vs %lu)\n",
   1580 		    (unsigned long)evbuffer_get_length(evhttp_request_get_input_buffer(req)), (unsigned long)strlen(what));
   1581 		exit(1);
   1582 	}
   1583 
   1584 	if (evbuffer_datacmp(evhttp_request_get_input_buffer(req), what) != 0) {
   1585 		fprintf(stderr, "FAILED (data)\n");
   1586 		exit(1);
   1587 	}
   1588 
   1589 	test_ok = 1;
   1590 	event_base_loopexit(base, NULL);
   1591 }
   1592 
   1593 /*
   1594  * HTTP PUT test, basically just like POST, but ...
   1595  */
   1596 
   1597 void http_putrequest_done(struct evhttp_request *, void *);
   1598 
   1599 #define PUT_DATA "Hi, I'm some PUT data"
   1600 
   1601 static void
   1602 http_put_test(void *arg)
   1603 {
   1604 	struct basic_test_data *data = arg;
   1605 	ev_uint16_t port = 0;
   1606 	struct evhttp_connection *evcon = NULL;
   1607 	struct evhttp_request *req = NULL;
   1608 
   1609 	test_ok = 0;
   1610 
   1611 	http = http_setup(&port, data->base);
   1612 
   1613 	evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port);
   1614 	tt_assert(evcon);
   1615 
   1616 	/*
   1617 	 * Schedule the HTTP PUT request
   1618 	 */
   1619 
   1620 	req = evhttp_request_new(http_putrequest_done, data->base);
   1621 	tt_assert(req);
   1622 
   1623 	/* Add the information that we care about */
   1624 	evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "someotherhost");
   1625 	evbuffer_add_printf(evhttp_request_get_output_buffer(req), PUT_DATA);
   1626 
   1627 	if (evhttp_make_request(evcon, req, EVHTTP_REQ_PUT, "/putit") == -1) {
   1628 		tt_abort_msg("Couldn't make request");
   1629 	}
   1630 
   1631 	event_base_dispatch(data->base);
   1632 
   1633 	evhttp_connection_free(evcon);
   1634 	evhttp_free(http);
   1635 
   1636 	tt_int_op(test_ok, ==, 1);
   1637  end:
   1638 	;
   1639 }
   1640 
   1641 void
   1642 http_put_cb(struct evhttp_request *req, void *arg)
   1643 {
   1644 	struct evbuffer *evb;
   1645 	event_debug(("%s: called\n", __func__));
   1646 
   1647 	/* Expecting a PUT request */
   1648 	if (evhttp_request_get_command(req) != EVHTTP_REQ_PUT) {
   1649 		fprintf(stdout, "FAILED (put type)\n");
   1650 		exit(1);
   1651 	}
   1652 
   1653 	if (evbuffer_get_length(evhttp_request_get_input_buffer(req)) != strlen(PUT_DATA)) {
   1654 		fprintf(stdout, "FAILED (length: %lu vs %lu)\n",
   1655 		    (unsigned long)evbuffer_get_length(evhttp_request_get_input_buffer(req)), (unsigned long)strlen(PUT_DATA));
   1656 		exit(1);
   1657 	}
   1658 
   1659 	if (evbuffer_datacmp(evhttp_request_get_input_buffer(req), PUT_DATA) != 0) {
   1660 		fprintf(stdout, "FAILED (data)\n");
   1661 		fprintf(stdout, "Got :%s\n", evbuffer_pullup(evhttp_request_get_input_buffer(req),-1));
   1662 		fprintf(stdout, "Want:%s\n", PUT_DATA);
   1663 		exit(1);
   1664 	}
   1665 
   1666 	evb = evbuffer_new();
   1667 	evbuffer_add_printf(evb, "That ain't funny");
   1668 
   1669 	evhttp_send_reply(req, HTTP_OK, "Everything is great", evb);
   1670 
   1671 	evbuffer_free(evb);
   1672 }
   1673 
   1674 void
   1675 http_putrequest_done(struct evhttp_request *req, void *arg)
   1676 {
   1677 	struct event_base *base = arg;
   1678 	const char *what = "That ain't funny";
   1679 
   1680 	if (req == NULL) {
   1681 		fprintf(stderr, "FAILED (timeout)\n");
   1682 		exit(1);
   1683 	}
   1684 
   1685 	if (evhttp_request_get_response_code(req) != HTTP_OK) {
   1686 
   1687 		fprintf(stderr, "FAILED (response code)\n");
   1688 		exit(1);
   1689 	}
   1690 
   1691 	if (evhttp_find_header(evhttp_request_get_input_headers(req), "Content-Type") == NULL) {
   1692 		fprintf(stderr, "FAILED (content type)\n");
   1693 		exit(1);
   1694 	}
   1695 
   1696 	if (evbuffer_get_length(evhttp_request_get_input_buffer(req)) != strlen(what)) {
   1697 		fprintf(stderr, "FAILED (length %lu vs %lu)\n",
   1698 		    (unsigned long)evbuffer_get_length(evhttp_request_get_input_buffer(req)), (unsigned long)strlen(what));
   1699 		exit(1);
   1700 	}
   1701 
   1702 
   1703 	if (evbuffer_datacmp(evhttp_request_get_input_buffer(req), what) != 0) {
   1704 		fprintf(stderr, "FAILED (data)\n");
   1705 		exit(1);
   1706 	}
   1707 
   1708 	test_ok = 1;
   1709 	event_base_loopexit(base, NULL);
   1710 }
   1711 
   1712 static void
   1713 http_failure_readcb(struct bufferevent *bev, void *arg)
   1714 {
   1715 	const char *what = "400 Bad Request";
   1716 	if (evbuffer_contains(bufferevent_get_input(bev), what)) {
   1717 		test_ok = 2;
   1718 		bufferevent_disable(bev, EV_READ);
   1719 		event_base_loopexit(arg, NULL);
   1720 	}
   1721 }
   1722 
   1723 /*
   1724  * Testing that the HTTP server can deal with a malformed request.
   1725  */
   1726 static void
   1727 http_failure_test(void *arg)
   1728 {
   1729 	struct basic_test_data *data = arg;
   1730 	struct bufferevent *bev;
   1731 	evutil_socket_t fd;
   1732 	const char *http_request;
   1733 	ev_uint16_t port = 0;
   1734 
   1735 	test_ok = 0;
   1736 
   1737 	http = http_setup(&port, data->base);
   1738 
   1739 	fd = http_connect("127.0.0.1", port);
   1740 
   1741 	/* Stupid thing to send a request */
   1742 	bev = bufferevent_socket_new(data->base, fd, 0);
   1743 	bufferevent_setcb(bev, http_failure_readcb, http_writecb,
   1744 	    http_errorcb, data->base);
   1745 
   1746 	http_request = "illegal request\r\n";
   1747 
   1748 	bufferevent_write(bev, http_request, strlen(http_request));
   1749 
   1750 	event_base_dispatch(data->base);
   1751 
   1752 	bufferevent_free(bev);
   1753 	evutil_closesocket(fd);
   1754 
   1755 	evhttp_free(http);
   1756 
   1757 	tt_int_op(test_ok, ==, 2);
   1758  end:
   1759 	;
   1760 }
   1761 
   1762 static void
   1763 close_detect_done(struct evhttp_request *req, void *arg)
   1764 {
   1765 	struct timeval tv;
   1766 	tt_assert(req);
   1767 	tt_assert(evhttp_request_get_response_code(req) == HTTP_OK);
   1768 
   1769 	test_ok = 1;
   1770 
   1771  end:
   1772 	evutil_timerclear(&tv);
   1773 	tv.tv_sec = 3;
   1774 	event_base_loopexit(arg, &tv);
   1775 }
   1776 
   1777 static void
   1778 close_detect_launch(evutil_socket_t fd, short what, void *arg)
   1779 {
   1780 	struct evhttp_connection *evcon = arg;
   1781 	struct event_base *base = evhttp_connection_get_base(evcon);
   1782 	struct evhttp_request *req;
   1783 
   1784 	req = evhttp_request_new(close_detect_done, base);
   1785 
   1786 	/* Add the information that we care about */
   1787 	evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
   1788 
   1789 	/* We give ownership of the request to the connection */
   1790 	if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test") == -1) {
   1791 		tt_fail_msg("Couldn't make request");
   1792 	}
   1793 }
   1794 
   1795 static void
   1796 close_detect_cb(struct evhttp_request *req, void *arg)
   1797 {
   1798 	struct evhttp_connection *evcon = arg;
   1799 	struct event_base *base = evhttp_connection_get_base(evcon);
   1800 	struct timeval tv;
   1801 
   1802 	if (req != NULL && evhttp_request_get_response_code(req) != HTTP_OK) {
   1803 		tt_abort_msg("Failed");
   1804 	}
   1805 
   1806 	evutil_timerclear(&tv);
   1807 	tv.tv_sec = 3;   /* longer than the http time out */
   1808 
   1809 	/* launch a new request on the persistent connection in 3 seconds */
   1810 	event_base_once(base, -1, EV_TIMEOUT, close_detect_launch, evcon, &tv);
   1811  end:
   1812 	;
   1813 }
   1814 
   1815 
   1816 static void
   1817 _http_close_detection(struct basic_test_data *data, int with_delay)
   1818 {
   1819 	ev_uint16_t port = 0;
   1820 	struct evhttp_connection *evcon = NULL;
   1821 	struct evhttp_request *req = NULL;
   1822 
   1823 	test_ok = 0;
   1824 	http = http_setup(&port, data->base);
   1825 
   1826 	/* 2 second timeout */
   1827 	evhttp_set_timeout(http, 1);
   1828 
   1829 	evcon = evhttp_connection_base_new(data->base, NULL,
   1830 	    "127.0.0.1", port);
   1831 	tt_assert(evcon);
   1832 	delayed_client = evcon;
   1833 
   1834 	/*
   1835 	 * At this point, we want to schedule a request to the HTTP
   1836 	 * server using our make request method.
   1837 	 */
   1838 
   1839 	req = evhttp_request_new(close_detect_cb, evcon);
   1840 
   1841 	/* Add the information that we care about */
   1842 	evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
   1843 
   1844 	/* We give ownership of the request to the connection */
   1845 	if (evhttp_make_request(evcon,
   1846 	    req, EVHTTP_REQ_GET, with_delay ? "/largedelay" : "/test") == -1) {
   1847 		tt_abort_msg("couldn't make request");
   1848 	}
   1849 
   1850 	event_base_dispatch(data->base);
   1851 
   1852 	/* at this point, the http server should have no connection */
   1853 	tt_assert(TAILQ_FIRST(&http->connections) == NULL);
   1854 
   1855  end:
   1856 	if (evcon)
   1857 		evhttp_connection_free(evcon);
   1858 	if (http)
   1859 		evhttp_free(http);
   1860 }
   1861 static void
   1862 http_close_detection_test(void *arg)
   1863 {
   1864 	_http_close_detection(arg, 0);
   1865 }
   1866 static void
   1867 http_close_detection_delay_test(void *arg)
   1868 {
   1869 	_http_close_detection(arg, 1);
   1870 }
   1871 
   1872 static void
   1873 http_highport_test(void *arg)
   1874 {
   1875 	struct basic_test_data *data = arg;
   1876 	int i = -1;
   1877 	struct evhttp *myhttp = NULL;
   1878 
   1879 	/* Try a few different ports */
   1880 	for (i = 0; i < 50; ++i) {
   1881 		myhttp = evhttp_new(data->base);
   1882 		if (evhttp_bind_socket(myhttp, "127.0.0.1", 65535 - i) == 0) {
   1883 			test_ok = 1;
   1884 			evhttp_free(myhttp);
   1885 			return;
   1886 		}
   1887 		evhttp_free(myhttp);
   1888 	}
   1889 
   1890 	tt_fail_msg("Couldn't get a high port");
   1891 }
   1892 
   1893 static void
   1894 http_bad_header_test(void *ptr)
   1895 {
   1896 	struct evkeyvalq headers;
   1897 
   1898 	TAILQ_INIT(&headers);
   1899 
   1900 	tt_want(evhttp_add_header(&headers, "One", "Two") == 0);
   1901 	tt_want(evhttp_add_header(&headers, "One", "Two\r\n Three") == 0);
   1902 	tt_want(evhttp_add_header(&headers, "One\r", "Two") == -1);
   1903 	tt_want(evhttp_add_header(&headers, "One\n", "Two") == -1);
   1904 	tt_want(evhttp_add_header(&headers, "One", "Two\r") == -1);
   1905 	tt_want(evhttp_add_header(&headers, "One", "Two\n") == -1);
   1906 
   1907 	evhttp_clear_headers(&headers);
   1908 }
   1909 
   1910 static int validate_header(
   1911 	const struct evkeyvalq* headers,
   1912 	const char *key, const char *value)
   1913 {
   1914 	const char *real_val = evhttp_find_header(headers, key);
   1915 	tt_assert(real_val != NULL);
   1916 	tt_want(strcmp(real_val, value) == 0);
   1917 end:
   1918 	return (0);
   1919 }
   1920 
   1921 static void
   1922 http_parse_query_test(void *ptr)
   1923 {
   1924 	struct evkeyvalq headers;
   1925 	int r;
   1926 
   1927 	TAILQ_INIT(&headers);
   1928 
   1929 	r = evhttp_parse_query("http://www.test.com/?q=test", &headers);
   1930 	tt_want(validate_header(&headers, "q", "test") == 0);
   1931 	tt_int_op(r, ==, 0);
   1932 	evhttp_clear_headers(&headers);
   1933 
   1934 	r = evhttp_parse_query("http://www.test.com/?q=test&foo=bar", &headers);
   1935 	tt_want(validate_header(&headers, "q", "test") == 0);
   1936 	tt_want(validate_header(&headers, "foo", "bar") == 0);
   1937 	tt_int_op(r, ==, 0);
   1938 	evhttp_clear_headers(&headers);
   1939 
   1940 	r = evhttp_parse_query("http://www.test.com/?q=test+foo", &headers);
   1941 	tt_want(validate_header(&headers, "q", "test foo") == 0);
   1942 	tt_int_op(r, ==, 0);
   1943 	evhttp_clear_headers(&headers);
   1944 
   1945 	r = evhttp_parse_query("http://www.test.com/?q=test%0Afoo", &headers);
   1946 	tt_want(validate_header(&headers, "q", "test\nfoo") == 0);
   1947 	tt_int_op(r, ==, 0);
   1948 	evhttp_clear_headers(&headers);
   1949 
   1950 	r = evhttp_parse_query("http://www.test.com/?q=test%0Dfoo", &headers);
   1951 	tt_want(validate_header(&headers, "q", "test\rfoo") == 0);
   1952 	tt_int_op(r, ==, 0);
   1953 	evhttp_clear_headers(&headers);
   1954 
   1955 	r = evhttp_parse_query("http://www.test.com/?q=test&&q2", &headers);
   1956 	tt_int_op(r, ==, -1);
   1957 	evhttp_clear_headers(&headers);
   1958 
   1959 	r = evhttp_parse_query("http://www.test.com/?q=test+this", &headers);
   1960 	tt_want(validate_header(&headers, "q", "test this") == 0);
   1961 	tt_int_op(r, ==, 0);
   1962 	evhttp_clear_headers(&headers);
   1963 
   1964 	r = evhttp_parse_query("http://www.test.com/?q=test&q2=foo", &headers);
   1965 	tt_int_op(r, ==, 0);
   1966 	tt_want(validate_header(&headers, "q", "test") == 0);
   1967 	tt_want(validate_header(&headers, "q2", "foo") == 0);
   1968 	evhttp_clear_headers(&headers);
   1969 
   1970 	r = evhttp_parse_query("http://www.test.com/?q&q2=foo", &headers);
   1971 	tt_int_op(r, ==, -1);
   1972 	evhttp_clear_headers(&headers);
   1973 
   1974 	r = evhttp_parse_query("http://www.test.com/?q=foo&q2", &headers);
   1975 	tt_int_op(r, ==, -1);
   1976 	evhttp_clear_headers(&headers);
   1977 
   1978 	r = evhttp_parse_query("http://www.test.com/?q=foo&q2&q3=x", &headers);
   1979 	tt_int_op(r, ==, -1);
   1980 	evhttp_clear_headers(&headers);
   1981 
   1982 	r = evhttp_parse_query("http://www.test.com/?q=&q2=&q3=", &headers);
   1983 	tt_int_op(r, ==, 0);
   1984 	tt_want(validate_header(&headers, "q", "") == 0);
   1985 	tt_want(validate_header(&headers, "q2", "") == 0);
   1986 	tt_want(validate_header(&headers, "q3", "") == 0);
   1987 	evhttp_clear_headers(&headers);
   1988 
   1989 end:
   1990 	evhttp_clear_headers(&headers);
   1991 }
   1992 
   1993 static void
   1994 http_parse_uri_test(void *ptr)
   1995 {
   1996 	const int nonconform = (ptr != NULL);
   1997 	const unsigned parse_flags =
   1998 	    nonconform ? EVHTTP_URI_NONCONFORMANT : 0;
   1999 	struct evhttp_uri *uri = NULL;
   2000 	char url_tmp[4096];
   2001 #define URI_PARSE(uri) \
   2002 	evhttp_uri_parse_with_flags((uri), parse_flags)
   2003 
   2004 #define TT_URI(want) do { 						\
   2005 	char *ret = evhttp_uri_join(uri, url_tmp, sizeof(url_tmp));	\
   2006 	tt_want(ret != NULL);						\
   2007 	tt_want(ret == url_tmp);					\
   2008 	if (strcmp(ret,want) != 0)					\
   2009 		TT_FAIL(("\"%s\" != \"%s\"",ret,want));			\
   2010 	} while(0)
   2011 
   2012 	tt_want(evhttp_uri_join(NULL, 0, 0) == NULL);
   2013 	tt_want(evhttp_uri_join(NULL, url_tmp, 0) == NULL);
   2014 	tt_want(evhttp_uri_join(NULL, url_tmp, sizeof(url_tmp)) == NULL);
   2015 
   2016 	/* bad URIs: parsing */
   2017 #define BAD(s) do {							\
   2018 		if (URI_PARSE(s) != NULL)				\
   2019 			TT_FAIL(("Expected error parsing \"%s\"",s));	\
   2020 	} while(0)
   2021 	/* Nonconformant URIs we can parse: parsing */
   2022 #define NCF(s) do {							\
   2023 		uri = URI_PARSE(s);					\
   2024 		if (uri != NULL && !nonconform) {			\
   2025 			TT_FAIL(("Expected error parsing \"%s\"",s));	\
   2026 		} else if (uri == NULL && nonconform) {			\
   2027 			TT_FAIL(("Couldn't parse nonconformant URI \"%s\"", \
   2028 				s));					\
   2029 		}							\
   2030 		if (uri) {						\
   2031 			tt_want(evhttp_uri_join(uri, url_tmp,		\
   2032 				sizeof(url_tmp)));			\
   2033 			evhttp_uri_free(uri);				\
   2034 		}							\
   2035 	} while(0)
   2036 
   2037 	NCF("http://www.test.com/ why hello");
   2038 	NCF("http://www.test.com/why-hello\x01");
   2039 	NCF("http://www.test.com/why-hello?\x01");
   2040 	NCF("http://www.test.com/why-hello#\x01");
   2041 	BAD("http://www.\x01.test.com/why-hello");
   2042 	BAD("http://www.%7test.com/why-hello");
   2043 	NCF("http://www.test.com/why-hell%7o");
   2044 	BAD("h%3ttp://www.test.com/why-hello");
   2045 	NCF("http://www.test.com/why-hello%7");
   2046 	NCF("http://www.test.com/why-hell%7o");
   2047 	NCF("http://www.test.com/foo?ba%r");
   2048 	NCF("http://www.test.com/foo#ba%r");
   2049 	BAD("99:99/foo");
   2050 	BAD("http://www.test.com:999x/");
   2051 	BAD("http://www.test.com:x/");
   2052 	BAD("http://[hello-there]/");
   2053 	BAD("http://[::1]]/");
   2054 	BAD("http://[::1/");
   2055 	BAD("http://[foob/");
   2056 	BAD("http://[/");
   2057 	BAD("http://[ffff:ffff:ffff:ffff:Ffff:ffff:ffff:"
   2058 	            "ffff:ffff:ffff:ffff:ffff:ffff:ffff]/");
   2059 	BAD("http://[vX.foo]/");
   2060 	BAD("http://[vX.foo]/");
   2061 	BAD("http://[v.foo]/");
   2062 	BAD("http://[v5.fo%o]/");
   2063 	BAD("http://[v5X]/");
   2064 	BAD("http://[v5]/");
   2065 	BAD("http://[]/");
   2066 	BAD("http://f\x01red@www.example.com/");
   2067 	BAD("http://f%0red@www.example.com/");
   2068 	BAD("http://www.example.com:9999999999999999999999999999999999999/");
   2069 	BAD("http://www.example.com:hihi/");
   2070 	BAD("://www.example.com/");
   2071 
   2072 	/* bad URIs: joining */
   2073 	uri = evhttp_uri_new();
   2074 	tt_want(0==evhttp_uri_set_host(uri, "www.example.com"));
   2075 	tt_want(evhttp_uri_join(uri, url_tmp, sizeof(url_tmp)) != NULL);
   2076 	/* not enough space: */
   2077 	tt_want(evhttp_uri_join(uri, url_tmp, 3) == NULL);
   2078 	/* host is set, but path doesn't start with "/": */
   2079 	tt_want(0==evhttp_uri_set_path(uri, "hi_mom"));
   2080 	tt_want(evhttp_uri_join(uri, url_tmp, sizeof(url_tmp)) == NULL);
   2081 	tt_want(evhttp_uri_join(uri, NULL, sizeof(url_tmp))==NULL);
   2082 	tt_want(evhttp_uri_join(uri, url_tmp, 0)==NULL);
   2083 	evhttp_uri_free(uri);
   2084 	uri = URI_PARSE("mailto:foo@bar");
   2085 	tt_want(uri != NULL);
   2086 	tt_want(evhttp_uri_get_host(uri) == NULL);
   2087 	tt_want(evhttp_uri_get_userinfo(uri) == NULL);
   2088 	tt_want(evhttp_uri_get_port(uri) == -1);
   2089 	tt_want(!strcmp(evhttp_uri_get_scheme(uri), "mailto"));
   2090 	tt_want(!strcmp(evhttp_uri_get_path(uri), "foo@bar"));
   2091 	tt_want(evhttp_uri_get_query(uri) == NULL);
   2092 	tt_want(evhttp_uri_get_fragment(uri) == NULL);
   2093 	TT_URI("mailto:foo@bar");
   2094 	evhttp_uri_free(uri);
   2095 
   2096 	uri = evhttp_uri_new();
   2097 	/* Bad URI usage: setting invalid values */
   2098 	tt_want(-1 == evhttp_uri_set_scheme(uri,""));
   2099 	tt_want(-1 == evhttp_uri_set_scheme(uri,"33"));
   2100 	tt_want(-1 == evhttp_uri_set_scheme(uri,"hi!"));
   2101 	tt_want(-1 == evhttp_uri_set_userinfo(uri,"hello@"));
   2102 	tt_want(-1 == evhttp_uri_set_host(uri,"[1.2.3.4]"));
   2103 	tt_want(-1 == evhttp_uri_set_host(uri,"["));
   2104 	tt_want(-1 == evhttp_uri_set_host(uri,"www.[foo].com"));
   2105 	tt_want(-1 == evhttp_uri_set_port(uri,-3));
   2106 	tt_want(-1 == evhttp_uri_set_path(uri,"hello?world"));
   2107 	tt_want(-1 == evhttp_uri_set_query(uri,"hello#world"));
   2108 	tt_want(-1 == evhttp_uri_set_fragment(uri,"hello#world"));
   2109 	/* Valid URI usage: setting valid values */
   2110 	tt_want(0 == evhttp_uri_set_scheme(uri,"http"));
   2111 	tt_want(0 == evhttp_uri_set_scheme(uri,NULL));
   2112 	tt_want(0 == evhttp_uri_set_userinfo(uri,"username:pass"));
   2113 	tt_want(0 == evhttp_uri_set_userinfo(uri,NULL));
   2114 	tt_want(0 == evhttp_uri_set_host(uri,"www.example.com"));
   2115 	tt_want(0 == evhttp_uri_set_host(uri,"1.2.3.4"));
   2116 	tt_want(0 == evhttp_uri_set_host(uri,"[1:2:3:4::]"));
   2117 	tt_want(0 == evhttp_uri_set_host(uri,"[v7.wobblewobble]"));
   2118 	tt_want(0 == evhttp_uri_set_host(uri,NULL));
   2119 	tt_want(0 == evhttp_uri_set_host(uri,""));
   2120 	tt_want(0 == evhttp_uri_set_port(uri, -1));
   2121 	tt_want(0 == evhttp_uri_set_port(uri, 80));
   2122 	tt_want(0 == evhttp_uri_set_port(uri, 65535));
   2123 	tt_want(0 == evhttp_uri_set_path(uri, ""));
   2124 	tt_want(0 == evhttp_uri_set_path(uri, "/documents/public/index.html"));
   2125 	tt_want(0 == evhttp_uri_set_path(uri, NULL));
   2126 	tt_want(0 == evhttp_uri_set_query(uri, "key=val&key2=val2"));
   2127 	tt_want(0 == evhttp_uri_set_query(uri, "keyvalblarg"));
   2128 	tt_want(0 == evhttp_uri_set_query(uri, ""));
   2129 	tt_want(0 == evhttp_uri_set_query(uri, NULL));
   2130 	tt_want(0 == evhttp_uri_set_fragment(uri, ""));
   2131 	tt_want(0 == evhttp_uri_set_fragment(uri, "here?i?am"));
   2132 	tt_want(0 == evhttp_uri_set_fragment(uri, NULL));
   2133 	evhttp_uri_free(uri);
   2134 
   2135 	/* Valid parsing */
   2136 	uri = URI_PARSE("http://www.test.com/?q=t%33est");
   2137 	tt_want(strcmp(evhttp_uri_get_scheme(uri), "http") == 0);
   2138 	tt_want(strcmp(evhttp_uri_get_host(uri), "www.test.com") == 0);
   2139 	tt_want(strcmp(evhttp_uri_get_path(uri), "/") == 0);
   2140 	tt_want(strcmp(evhttp_uri_get_query(uri), "q=t%33est") == 0);
   2141 	tt_want(evhttp_uri_get_userinfo(uri) == NULL);
   2142 	tt_want(evhttp_uri_get_port(uri) == -1);
   2143 	tt_want(evhttp_uri_get_fragment(uri) == NULL);
   2144 	TT_URI("http://www.test.com/?q=t%33est");
   2145 	evhttp_uri_free(uri);
   2146 
   2147 	uri = URI_PARSE("http://%77ww.test.com");
   2148 	tt_want(strcmp(evhttp_uri_get_scheme(uri), "http") == 0);
   2149 	tt_want(strcmp(evhttp_uri_get_host(uri), "%77ww.test.com") == 0);
   2150 	tt_want(strcmp(evhttp_uri_get_path(uri), "") == 0);
   2151 	tt_want(evhttp_uri_get_query(uri) == NULL);
   2152 	tt_want(evhttp_uri_get_userinfo(uri) == NULL);
   2153 	tt_want(evhttp_uri_get_port(uri) == -1);
   2154 	tt_want(evhttp_uri_get_fragment(uri) == NULL);
   2155 	TT_URI("http://%77ww.test.com");
   2156 	evhttp_uri_free(uri);
   2157 
   2158 	uri = URI_PARSE("http://www.test.com?q=test");
   2159 	tt_want(strcmp(evhttp_uri_get_scheme(uri), "http") == 0);
   2160 	tt_want(strcmp(evhttp_uri_get_host(uri), "www.test.com") == 0);
   2161 	tt_want(strcmp(evhttp_uri_get_path(uri), "") == 0);
   2162 	tt_want(strcmp(evhttp_uri_get_query(uri), "q=test") == 0);
   2163 	tt_want(evhttp_uri_get_userinfo(uri) == NULL);
   2164 	tt_want(evhttp_uri_get_port(uri) == -1);
   2165 	tt_want(evhttp_uri_get_fragment(uri) == NULL);
   2166 	TT_URI("http://www.test.com?q=test");
   2167 	evhttp_uri_free(uri);
   2168 
   2169 	uri = URI_PARSE("http://www.test.com#fragment");
   2170 	tt_want(strcmp(evhttp_uri_get_scheme(uri), "http") == 0);
   2171 	tt_want(strcmp(evhttp_uri_get_host(uri), "www.test.com") == 0);
   2172 	tt_want(strcmp(evhttp_uri_get_path(uri), "") == 0);
   2173 	tt_want(evhttp_uri_get_query(uri) == NULL);
   2174 	tt_want(evhttp_uri_get_userinfo(uri) == NULL);
   2175 	tt_want(evhttp_uri_get_port(uri) == -1);
   2176 	tt_want_str_op(evhttp_uri_get_fragment(uri), ==, "fragment");
   2177 	TT_URI("http://www.test.com#fragment");
   2178 	evhttp_uri_free(uri);
   2179 
   2180 	uri = URI_PARSE("http://8000/");
   2181 	tt_want(strcmp(evhttp_uri_get_scheme(uri), "http") == 0);
   2182 	tt_want(strcmp(evhttp_uri_get_host(uri), "8000") == 0);
   2183 	tt_want(strcmp(evhttp_uri_get_path(uri), "/") == 0);
   2184 	tt_want(evhttp_uri_get_query(uri) == NULL);
   2185 	tt_want(evhttp_uri_get_userinfo(uri) == NULL);
   2186 	tt_want(evhttp_uri_get_port(uri) == -1);
   2187 	tt_want(evhttp_uri_get_fragment(uri) == NULL);
   2188 	TT_URI("http://8000/");
   2189 	evhttp_uri_free(uri);
   2190 
   2191 	uri = URI_PARSE("http://:8000/");
   2192 	tt_want(strcmp(evhttp_uri_get_scheme(uri), "http") == 0);
   2193 	tt_want(strcmp(evhttp_uri_get_host(uri), "") == 0);
   2194 	tt_want(strcmp(evhttp_uri_get_path(uri), "/") == 0);
   2195 	tt_want(evhttp_uri_get_query(uri) == NULL);
   2196 	tt_want(evhttp_uri_get_userinfo(uri) == NULL);
   2197 	tt_want(evhttp_uri_get_port(uri) == 8000);
   2198 	tt_want(evhttp_uri_get_fragment(uri) == NULL);
   2199 	TT_URI("http://:8000/");
   2200 	evhttp_uri_free(uri);
   2201 
   2202 	uri = URI_PARSE("http://www.test.com:/"); /* empty port */
   2203 	tt_want(strcmp(evhttp_uri_get_scheme(uri), "http") == 0);
   2204 	tt_want(strcmp(evhttp_uri_get_host(uri), "www.test.com") == 0);
   2205 	tt_want_str_op(evhttp_uri_get_path(uri), ==, "/");
   2206 	tt_want(evhttp_uri_get_query(uri) == NULL);
   2207 	tt_want(evhttp_uri_get_userinfo(uri) == NULL);
   2208 	tt_want(evhttp_uri_get_port(uri) == -1);
   2209 	tt_want(evhttp_uri_get_fragment(uri) == NULL);
   2210 	TT_URI("http://www.test.com/");
   2211 	evhttp_uri_free(uri);
   2212 
   2213 	uri = URI_PARSE("http://www.test.com:"); /* empty port 2 */
   2214 	tt_want(strcmp(evhttp_uri_get_scheme(uri), "http") == 0);
   2215 	tt_want(strcmp(evhttp_uri_get_host(uri), "www.test.com") == 0);
   2216 	tt_want(strcmp(evhttp_uri_get_path(uri), "") == 0);
   2217 	tt_want(evhttp_uri_get_query(uri) == NULL);
   2218 	tt_want(evhttp_uri_get_userinfo(uri) == NULL);
   2219 	tt_want(evhttp_uri_get_port(uri) == -1);
   2220 	tt_want(evhttp_uri_get_fragment(uri) == NULL);
   2221 	TT_URI("http://www.test.com");
   2222 	evhttp_uri_free(uri);
   2223 
   2224 	uri = URI_PARSE("ftp://www.test.com/?q=test");
   2225 	tt_want(strcmp(evhttp_uri_get_scheme(uri), "ftp") == 0);
   2226 	tt_want(strcmp(evhttp_uri_get_host(uri), "www.test.com") == 0);
   2227 	tt_want(strcmp(evhttp_uri_get_path(uri), "/") == 0);
   2228 	tt_want(strcmp(evhttp_uri_get_query(uri), "q=test") == 0);
   2229 	tt_want(evhttp_uri_get_userinfo(uri) == NULL);
   2230 	tt_want(evhttp_uri_get_port(uri) == -1);
   2231 	tt_want(evhttp_uri_get_fragment(uri) == NULL);
   2232 	TT_URI("ftp://www.test.com/?q=test");
   2233 	evhttp_uri_free(uri);
   2234 
   2235 	uri = URI_PARSE("ftp://[::1]:999/?q=test");
   2236 	tt_want(strcmp(evhttp_uri_get_scheme(uri), "ftp") == 0);
   2237 	tt_want(strcmp(evhttp_uri_get_host(uri), "[::1]") == 0);
   2238 	tt_want(strcmp(evhttp_uri_get_path(uri), "/") == 0);
   2239 	tt_want(strcmp(evhttp_uri_get_query(uri), "q=test") == 0);
   2240 	tt_want(evhttp_uri_get_userinfo(uri) == NULL);
   2241 	tt_want(evhttp_uri_get_port(uri) == 999);
   2242 	tt_want(evhttp_uri_get_fragment(uri) == NULL);
   2243 	TT_URI("ftp://[::1]:999/?q=test");
   2244 	evhttp_uri_free(uri);
   2245 
   2246 	uri = URI_PARSE("ftp://[ff00::127.0.0.1]/?q=test");
   2247 	tt_want(strcmp(evhttp_uri_get_scheme(uri), "ftp") == 0);
   2248 	tt_want(strcmp(evhttp_uri_get_host(uri), "[ff00::127.0.0.1]") == 0);
   2249 	tt_want(strcmp(evhttp_uri_get_path(uri), "/") == 0);
   2250 	tt_want(strcmp(evhttp_uri_get_query(uri), "q=test") == 0);
   2251 	tt_want(evhttp_uri_get_userinfo(uri) == NULL);
   2252 	tt_want(evhttp_uri_get_port(uri) == -1);
   2253 	tt_want(evhttp_uri_get_fragment(uri) == NULL);
   2254 	TT_URI("ftp://[ff00::127.0.0.1]/?q=test");
   2255 	evhttp_uri_free(uri);
   2256 
   2257 	uri = URI_PARSE("ftp://[v99.not_(any:time)_soon]/?q=test");
   2258 	tt_want(strcmp(evhttp_uri_get_scheme(uri), "ftp") == 0);
   2259 	tt_want(strcmp(evhttp_uri_get_host(uri), "[v99.not_(any:time)_soon]") == 0);
   2260 	tt_want(strcmp(evhttp_uri_get_path(uri), "/") == 0);
   2261 	tt_want(strcmp(evhttp_uri_get_query(uri), "q=test") == 0);
   2262 	tt_want(evhttp_uri_get_userinfo(uri) == NULL);
   2263 	tt_want(evhttp_uri_get_port(uri) == -1);
   2264 	tt_want(evhttp_uri_get_fragment(uri) == NULL);
   2265 	TT_URI("ftp://[v99.not_(any:time)_soon]/?q=test");
   2266 	evhttp_uri_free(uri);
   2267 
   2268 	uri = URI_PARSE("scheme://user:pass (at) foo.com:42/?q=test&s=some+thing#fragment");
   2269 	tt_want(strcmp(evhttp_uri_get_scheme(uri), "scheme") == 0);
   2270 	tt_want(strcmp(evhttp_uri_get_userinfo(uri), "user:pass") == 0);
   2271 	tt_want(strcmp(evhttp_uri_get_host(uri), "foo.com") == 0);
   2272 	tt_want(evhttp_uri_get_port(uri) == 42);
   2273 	tt_want(strcmp(evhttp_uri_get_path(uri), "/") == 0);
   2274 	tt_want(strcmp(evhttp_uri_get_query(uri), "q=test&s=some+thing") == 0);
   2275 	tt_want(strcmp(evhttp_uri_get_fragment(uri), "fragment") == 0);
   2276 	TT_URI("scheme://user:pass (at) foo.com:42/?q=test&s=some+thing#fragment");
   2277 	evhttp_uri_free(uri);
   2278 
   2279 	uri = URI_PARSE("scheme://user (at) foo.com/#fragment");
   2280 	tt_want(strcmp(evhttp_uri_get_scheme(uri), "scheme") == 0);
   2281 	tt_want(strcmp(evhttp_uri_get_userinfo(uri), "user") == 0);
   2282 	tt_want(strcmp(evhttp_uri_get_host(uri), "foo.com") == 0);
   2283 	tt_want(evhttp_uri_get_port(uri) == -1);
   2284 	tt_want(strcmp(evhttp_uri_get_path(uri), "/") == 0);
   2285 	tt_want(evhttp_uri_get_query(uri) == NULL);
   2286 	tt_want(strcmp(evhttp_uri_get_fragment(uri), "fragment") == 0);
   2287 	TT_URI("scheme://user (at) foo.com/#fragment");
   2288 	evhttp_uri_free(uri);
   2289 
   2290 	uri = URI_PARSE("scheme://%75ser (at) foo.com/#frag@ment");
   2291 	tt_want(strcmp(evhttp_uri_get_scheme(uri), "scheme") == 0);
   2292 	tt_want(strcmp(evhttp_uri_get_userinfo(uri), "%75ser") == 0);
   2293 	tt_want(strcmp(evhttp_uri_get_host(uri), "foo.com") == 0);
   2294 	tt_want(evhttp_uri_get_port(uri) == -1);
   2295 	tt_want(strcmp(evhttp_uri_get_path(uri), "/") == 0);
   2296 	tt_want(evhttp_uri_get_query(uri) == NULL);
   2297 	tt_want(strcmp(evhttp_uri_get_fragment(uri), "frag@ment") == 0);
   2298 	TT_URI("scheme://%75ser (at) foo.com/#frag@ment");
   2299 	evhttp_uri_free(uri);
   2300 
   2301 	uri = URI_PARSE("file:///some/path/to/the/file");
   2302 	tt_want(strcmp(evhttp_uri_get_scheme(uri), "file") == 0);
   2303 	tt_want(evhttp_uri_get_userinfo(uri) == NULL);
   2304 	tt_want(strcmp(evhttp_uri_get_host(uri), "") == 0);
   2305 	tt_want(evhttp_uri_get_port(uri) == -1);
   2306 	tt_want(strcmp(evhttp_uri_get_path(uri), "/some/path/to/the/file") == 0);
   2307 	tt_want(evhttp_uri_get_query(uri) == NULL);
   2308 	tt_want(evhttp_uri_get_fragment(uri) == NULL);
   2309 	TT_URI("file:///some/path/to/the/file");
   2310 	evhttp_uri_free(uri);
   2311 
   2312 	uri = URI_PARSE("///some/path/to/the-file");
   2313 	tt_want(uri != NULL);
   2314 	tt_want(evhttp_uri_get_scheme(uri) == NULL);
   2315 	tt_want(evhttp_uri_get_userinfo(uri) == NULL);
   2316 	tt_want(strcmp(evhttp_uri_get_host(uri), "") == 0);
   2317 	tt_want(evhttp_uri_get_port(uri) == -1);
   2318 	tt_want(strcmp(evhttp_uri_get_path(uri), "/some/path/to/the-file") == 0);
   2319 	tt_want(evhttp_uri_get_query(uri) == NULL);
   2320 	tt_want(evhttp_uri_get_fragment(uri) == NULL);
   2321 	TT_URI("///some/path/to/the-file");
   2322 	evhttp_uri_free(uri);
   2323 
   2324 	uri = URI_PARSE("/s:ome/path/to/the-file?q=99#fred");
   2325 	tt_want(uri != NULL);
   2326 	tt_want(evhttp_uri_get_scheme(uri) == NULL);
   2327 	tt_want(evhttp_uri_get_userinfo(uri) == NULL);
   2328 	tt_want(evhttp_uri_get_host(uri) == NULL);
   2329 	tt_want(evhttp_uri_get_port(uri) == -1);
   2330 	tt_want(strcmp(evhttp_uri_get_path(uri), "/s:ome/path/to/the-file") == 0);
   2331 	tt_want(strcmp(evhttp_uri_get_query(uri), "q=99") == 0);
   2332 	tt_want(strcmp(evhttp_uri_get_fragment(uri), "fred") == 0);
   2333 	TT_URI("/s:ome/path/to/the-file?q=99#fred");
   2334 	evhttp_uri_free(uri);
   2335 
   2336 	uri = URI_PARSE("relative/path/with/co:lon");
   2337 	tt_want(uri != NULL);
   2338 	tt_want(evhttp_uri_get_scheme(uri) == NULL);
   2339 	tt_want(evhttp_uri_get_userinfo(uri) == NULL);
   2340 	tt_want(evhttp_uri_get_host(uri) == NULL);
   2341 	tt_want(evhttp_uri_get_port(uri) == -1);
   2342 	tt_want(strcmp(evhttp_uri_get_path(uri), "relative/path/with/co:lon") == 0);
   2343 	tt_want(evhttp_uri_get_query(uri) == NULL);
   2344 	tt_want(evhttp_uri_get_fragment(uri) == NULL);
   2345 	TT_URI("relative/path/with/co:lon");
   2346 	evhttp_uri_free(uri);
   2347 
   2348 	uri = URI_PARSE("bob?q=99&q2=q?33#fr?ed");
   2349 	tt_want(uri != NULL);
   2350 	tt_want(evhttp_uri_get_scheme(uri) == NULL);
   2351 	tt_want(evhttp_uri_get_userinfo(uri) == NULL);
   2352 	tt_want(evhttp_uri_get_host(uri) == NULL);
   2353 	tt_want(evhttp_uri_get_port(uri) == -1);
   2354 	tt_want(strcmp(evhttp_uri_get_path(uri), "bob") == 0);
   2355 	tt_want(strcmp(evhttp_uri_get_query(uri), "q=99&q2=q?33") == 0);
   2356 	tt_want(strcmp(evhttp_uri_get_fragment(uri), "fr?ed") == 0);
   2357 	TT_URI("bob?q=99&q2=q?33#fr?ed");
   2358 	evhttp_uri_free(uri);
   2359 
   2360 	uri = URI_PARSE("#fr?ed");
   2361 	tt_want(uri != NULL);
   2362 	tt_want(evhttp_uri_get_scheme(uri) == NULL);
   2363 	tt_want(evhttp_uri_get_userinfo(uri) == NULL);
   2364 	tt_want(evhttp_uri_get_host(uri) == NULL);
   2365 	tt_want(evhttp_uri_get_port(uri) == -1);
   2366 	tt_want(strcmp(evhttp_uri_get_path(uri), "") == 0);
   2367 	tt_want(evhttp_uri_get_query(uri) == NULL);
   2368 	tt_want(strcmp(evhttp_uri_get_fragment(uri), "fr?ed") == 0);
   2369 	TT_URI("#fr?ed");
   2370 	evhttp_uri_free(uri);
   2371 #undef URI_PARSE
   2372 #undef TT_URI
   2373 #undef BAD
   2374 }
   2375 
   2376 static void
   2377 http_uriencode_test(void *ptr)
   2378 {
   2379 	char *s=NULL, *s2=NULL;
   2380 	size_t sz;
   2381 
   2382 #define ENC(from,want,plus) do {				\
   2383 		s = evhttp_uriencode((from), -1, (plus));	\
   2384 		tt_assert(s);					\
   2385 		tt_str_op(s,==,(want));				\
   2386 		sz = -1;					\
   2387 		s2 = evhttp_uridecode((s), (plus), &sz);	\
   2388 		tt_assert(s2);					\
   2389 		tt_str_op(s2,==,(from));			\
   2390 		tt_int_op(sz,==,strlen(from));			\
   2391 		free(s);					\
   2392 		free(s2);					\
   2393 		s = s2 = NULL;					\
   2394 	} while (0)
   2395 
   2396 #define DEC(from,want,dp) do {					\
   2397 		s = evhttp_uridecode((from),(dp),&sz);		\
   2398 		tt_assert(s);					\
   2399 		tt_str_op(s,==,(want));				\
   2400 		tt_int_op(sz,==,strlen(want));			\
   2401 		free(s);					\
   2402 		s = NULL;					\
   2403 	} while (0)
   2404 
   2405 #define OLD_DEC(from,want)  do {				\
   2406 		s = evhttp_decode_uri((from));			\
   2407 		tt_assert(s);					\
   2408 		tt_str_op(s,==,(want));				\
   2409 		free(s);					\
   2410 		s = NULL;					\
   2411 	} while (0)
   2412 
   2413 
   2414       	ENC("Hello", "Hello",0);
   2415 	ENC("99", "99",0);
   2416 	ENC("", "",0);
   2417 	ENC(
   2418 	 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ123456789-.~_",
   2419 	 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ123456789-.~_",0);
   2420 	ENC(" ", "%20",0);
   2421 	ENC(" ", "+",1);
   2422 	ENC("\xff\xf0\xe0", "%FF%F0%E0",0);
   2423 	ENC("\x01\x19", "%01%19",1);
   2424 	ENC("http://www.ietf.org/rfc/rfc3986.txt",
   2425 	    "http%3A%2F%2Fwww.ietf.org%2Frfc%2Frfc3986.txt",1);
   2426 
   2427 	ENC("1+2=3", "1%2B2%3D3",1);
   2428 	ENC("1+2=3", "1%2B2%3D3",0);
   2429 
   2430 	/* Now try encoding with internal NULs. */
   2431 	s = evhttp_uriencode("hello\0world", 11, 0);
   2432 	tt_assert(s);
   2433 	tt_str_op(s,==,"hello%00world");
   2434 	free(s);
   2435 	s = NULL;
   2436 
   2437 	/* Now try out some decoding cases that we don't generate with
   2438 	 * encode_uri: Make sure that malformed stuff doesn't crash... */
   2439 	DEC("%%xhello th+ere \xff",
   2440 	    "%%xhello th+ere \xff", 0);
   2441 	/* Make sure plus decoding works */
   2442 	DEC("plus+should%20work+", "plus should work ",1);
   2443 	/* Try some lowercase hex */
   2444 	DEC("%f0%a0%b0", "\xf0\xa0\xb0",1);
   2445 
   2446 	/* Try an internal NUL. */
   2447 	sz = 0;
   2448 	s = evhttp_uridecode("%00%00x%00%00", 1, &sz);
   2449 	tt_int_op(sz,==,5);
   2450 	tt_assert(!memcmp(s, "\0\0x\0\0", 5));
   2451 	free(s);
   2452 	s = NULL;
   2453 
   2454 	/* Try with size == NULL */
   2455 	sz = 0;
   2456 	s = evhttp_uridecode("%00%00x%00%00", 1, NULL);
   2457 	tt_assert(!memcmp(s, "\0\0x\0\0", 5));
   2458 	free(s);
   2459 	s = NULL;
   2460 
   2461 	/* Test out the crazy old behavior of the deprecated
   2462 	 * evhttp_decode_uri */
   2463 	OLD_DEC("http://example.com/normal+path/?key=val+with+spaces",
   2464 	        "http://example.com/normal+path/?key=val with spaces");
   2465 
   2466 end:
   2467 	if (s)
   2468 		free(s);
   2469 	if (s2)
   2470 		free(s2);
   2471 #undef ENC
   2472 #undef DEC
   2473 #undef OLD_DEC
   2474 }
   2475 
   2476 static void
   2477 http_base_test(void *ptr)
   2478 {
   2479 	struct event_base *base = NULL;
   2480 	struct bufferevent *bev;
   2481 	evutil_socket_t fd;
   2482 	const char *http_request;
   2483 	ev_uint16_t port = 0;
   2484 
   2485 	test_ok = 0;
   2486 	base = event_base_new();
   2487 	http = http_setup(&port, base);
   2488 
   2489 	fd = http_connect("127.0.0.1", port);
   2490 
   2491 	/* Stupid thing to send a request */
   2492 	bev = bufferevent_socket_new(base, fd, 0);
   2493 	bufferevent_setcb(bev, http_readcb, http_writecb,
   2494 	    http_errorcb, base);
   2495 	bufferevent_base_set(base, bev);
   2496 
   2497 	http_request =
   2498 	    "GET /test HTTP/1.1\r\n"
   2499 	    "Host: somehost\r\n"
   2500 	    "Connection: close\r\n"
   2501 	    "\r\n";
   2502 
   2503 	bufferevent_write(bev, http_request, strlen(http_request));
   2504 
   2505 	event_base_dispatch(base);
   2506 
   2507 	bufferevent_free(bev);
   2508 	evutil_closesocket(fd);
   2509 
   2510 	evhttp_free(http);
   2511 
   2512 	tt_int_op(test_ok, ==, 2);
   2513 
   2514 end:
   2515 	if (base)
   2516 		event_base_free(base);
   2517 }
   2518 
   2519 /*
   2520  * the server is just going to close the connection if it times out during
   2521  * reading the headers.
   2522  */
   2523 
   2524 static void
   2525 http_incomplete_readcb(struct bufferevent *bev, void *arg)
   2526 {
   2527 	test_ok = -1;
   2528 	event_base_loopexit(exit_base,NULL);
   2529 }
   2530 
   2531 static void
   2532 http_incomplete_errorcb(struct bufferevent *bev, short what, void *arg)
   2533 {
   2534 	if (what == (BEV_EVENT_READING|BEV_EVENT_EOF))
   2535 		test_ok++;
   2536 	else
   2537 		test_ok = -2;
   2538 	event_base_loopexit(exit_base,NULL);
   2539 }
   2540 
   2541 static void
   2542 http_incomplete_writecb(struct bufferevent *bev, void *arg)
   2543 {
   2544 	if (arg != NULL) {
   2545 		evutil_socket_t fd = *(evutil_socket_t *)arg;
   2546 		/* terminate the write side to simulate EOF */
   2547 		shutdown(fd, SHUT_WR);
   2548 	}
   2549 	if (evbuffer_get_length(bufferevent_get_output(bev)) == 0) {
   2550 		/* enable reading of the reply */
   2551 		bufferevent_enable(bev, EV_READ);
   2552 		test_ok++;
   2553 	}
   2554 }
   2555 
   2556 static void
   2557 _http_incomplete_test(struct basic_test_data *data, int use_timeout)
   2558 {
   2559 	struct bufferevent *bev;
   2560 	evutil_socket_t fd;
   2561 	const char *http_request;
   2562 	ev_uint16_t port = 0;
   2563 	struct timeval tv_start, tv_end;
   2564 
   2565 	exit_base = data->base;
   2566 
   2567 	test_ok = 0;
   2568 
   2569 	http = http_setup(&port, data->base);
   2570 	evhttp_set_timeout(http, 1);
   2571 
   2572 	fd = http_connect("127.0.0.1", port);
   2573 
   2574 	/* Stupid thing to send a request */
   2575 	bev = bufferevent_socket_new(data->base, fd, 0);
   2576 	bufferevent_setcb(bev,
   2577 	    http_incomplete_readcb, http_incomplete_writecb,
   2578 	    http_incomplete_errorcb, use_timeout ? NULL : &fd);
   2579 
   2580 	http_request =
   2581 	    "GET /test HTTP/1.1\r\n"
   2582 	    "Host: somehost\r\n";
   2583 
   2584 	bufferevent_write(bev, http_request, strlen(http_request));
   2585 
   2586 	evutil_gettimeofday(&tv_start, NULL);
   2587 
   2588 	event_base_dispatch(data->base);
   2589 
   2590 	evutil_gettimeofday(&tv_end, NULL);
   2591 	evutil_timersub(&tv_end, &tv_start, &tv_end);
   2592 
   2593 	bufferevent_free(bev);
   2594 	if (use_timeout) {
   2595 		evutil_closesocket(fd);
   2596 	}
   2597 
   2598 	evhttp_free(http);
   2599 
   2600 	if (use_timeout && tv_end.tv_sec >= 3) {
   2601 		tt_abort_msg("time");
   2602 	} else if (!use_timeout && tv_end.tv_sec >= 1) {
   2603 		/* we should be done immediately */
   2604 		tt_abort_msg("time");
   2605 	}
   2606 
   2607 	tt_int_op(test_ok, ==, 2);
   2608  end:
   2609 	;
   2610 }
   2611 static void
   2612 http_incomplete_test(void *arg)
   2613 {
   2614 	_http_incomplete_test(arg, 0);
   2615 }
   2616 static void
   2617 http_incomplete_timeout_test(void *arg)
   2618 {
   2619 	_http_incomplete_test(arg, 1);
   2620 }
   2621 
   2622 /*
   2623  * the server is going to reply with chunked data.
   2624  */
   2625 
   2626 static void
   2627 http_chunked_readcb(struct bufferevent *bev, void *arg)
   2628 {
   2629 	/* nothing here */
   2630 }
   2631 
   2632 static void
   2633 http_chunked_errorcb(struct bufferevent *bev, short what, void *arg)
   2634 {
   2635 	if (!test_ok)
   2636 		goto out;
   2637 
   2638 	test_ok = -1;
   2639 
   2640 	if ((what & BEV_EVENT_EOF) != 0) {
   2641 		struct evhttp_request *req = evhttp_request_new(NULL, NULL);
   2642 		const char *header;
   2643 		enum message_read_status done;
   2644 
   2645 		/* req->kind = EVHTTP_RESPONSE; */
   2646 		done = evhttp_parse_firstline(req, bufferevent_get_input(bev));
   2647 		if (done != ALL_DATA_READ)
   2648 			goto out;
   2649 
   2650 		done = evhttp_parse_headers(req, bufferevent_get_input(bev));
   2651 		if (done != ALL_DATA_READ)
   2652 			goto out;
   2653 
   2654 		header = evhttp_find_header(evhttp_request_get_input_headers(req), "Transfer-Encoding");
   2655 		if (header == NULL || strcmp(header, "chunked"))
   2656 			goto out;
   2657 
   2658 		header = evhttp_find_header(evhttp_request_get_input_headers(req), "Connection");
   2659 		if (header == NULL || strcmp(header, "close"))
   2660 			goto out;
   2661 
   2662 		header = evbuffer_readln(bufferevent_get_input(bev), NULL, EVBUFFER_EOL_CRLF);
   2663 		if (header == NULL)
   2664 			goto out;
   2665 		/* 13 chars */
   2666 		if (strcmp(header, "d")) {
   2667 			free((void*)header);
   2668 			goto out;
   2669 		}
   2670 		free((void*)header);
   2671 
   2672 		if (strncmp((char *)evbuffer_pullup(bufferevent_get_input(bev), 13),
   2673 			"This is funny", 13))
   2674 			goto out;
   2675 
   2676 		evbuffer_drain(bufferevent_get_input(bev), 13 + 2);
   2677 
   2678 		header = evbuffer_readln(bufferevent_get_input(bev), NULL, EVBUFFER_EOL_CRLF);
   2679 		if (header == NULL)
   2680 			goto out;
   2681 		/* 18 chars */
   2682 		if (strcmp(header, "12"))
   2683 			goto out;
   2684 		free((char *)header);
   2685 
   2686 		if (strncmp((char *)evbuffer_pullup(bufferevent_get_input(bev), 18),
   2687 			"but not hilarious.", 18))
   2688 			goto out;
   2689 
   2690 		evbuffer_drain(bufferevent_get_input(bev), 18 + 2);
   2691 
   2692 		header = evbuffer_readln(bufferevent_get_input(bev), NULL, EVBUFFER_EOL_CRLF);
   2693 		if (header == NULL)
   2694 			goto out;
   2695 		/* 8 chars */
   2696 		if (strcmp(header, "8")) {
   2697 			free((void*)header);
   2698 			goto out;
   2699 		}
   2700 		free((char *)header);
   2701 
   2702 		if (strncmp((char *)evbuffer_pullup(bufferevent_get_input(bev), 8),
   2703 			"bwv 1052.", 8))
   2704 			goto out;
   2705 
   2706 		evbuffer_drain(bufferevent_get_input(bev), 8 + 2);
   2707 
   2708 		header = evbuffer_readln(bufferevent_get_input(bev), NULL, EVBUFFER_EOL_CRLF);
   2709 		if (header == NULL)
   2710 			goto out;
   2711 		/* 0 chars */
   2712 		if (strcmp(header, "0")) {
   2713 			free((void*)header);
   2714 			goto out;
   2715 		}
   2716 		free((void *)header);
   2717 
   2718 		test_ok = 2;
   2719 
   2720 		evhttp_request_free(req);
   2721 	}
   2722 
   2723 out:
   2724 	event_base_loopexit(arg, NULL);
   2725 }
   2726 
   2727 static void
   2728 http_chunked_writecb(struct bufferevent *bev, void *arg)
   2729 {
   2730 	if (evbuffer_get_length(bufferevent_get_output(bev)) == 0) {
   2731 		/* enable reading of the reply */
   2732 		bufferevent_enable(bev, EV_READ);
   2733 		test_ok++;
   2734 	}
   2735 }
   2736 
   2737 static void
   2738 http_chunked_request_done(struct evhttp_request *req, void *arg)
   2739 {
   2740 	if (evhttp_request_get_response_code(req) != HTTP_OK) {
   2741 		fprintf(stderr, "FAILED\n");
   2742 		exit(1);
   2743 	}
   2744 
   2745 	if (evhttp_find_header(evhttp_request_get_input_headers(req),
   2746 		"Transfer-Encoding") == NULL) {
   2747 		fprintf(stderr, "FAILED\n");
   2748 		exit(1);
   2749 	}
   2750 
   2751 	if (evbuffer_get_length(evhttp_request_get_input_buffer(req)) != 13 + 18 + 8) {
   2752 		fprintf(stderr, "FAILED\n");
   2753 		exit(1);
   2754 	}
   2755 
   2756 	if (strncmp((char *)evbuffer_pullup(evhttp_request_get_input_buffer(req), 13 + 18 + 8),
   2757 		"This is funnybut not hilarious.bwv 1052",
   2758 		13 + 18 + 8)) {
   2759 		fprintf(stderr, "FAILED\n");
   2760 		exit(1);
   2761 	}
   2762 
   2763 	test_ok = 1;
   2764 	event_base_loopexit(arg, NULL);
   2765 }
   2766 
   2767 static void
   2768 http_chunk_out_test(void *arg)
   2769 {
   2770 	struct basic_test_data *data = arg;
   2771 	struct bufferevent *bev;
   2772 	evutil_socket_t fd;
   2773 	const char *http_request;
   2774 	ev_uint16_t port = 0;
   2775 	struct timeval tv_start, tv_end;
   2776 	struct evhttp_connection *evcon = NULL;
   2777 	struct evhttp_request *req = NULL;
   2778 	int i;
   2779 
   2780 	exit_base = data->base;
   2781 	test_ok = 0;
   2782 
   2783 	http = http_setup(&port, data->base);
   2784 
   2785 	fd = http_connect("127.0.0.1", port);
   2786 
   2787 	/* Stupid thing to send a request */
   2788 	bev = bufferevent_socket_new(data->base, fd, 0);
   2789 	bufferevent_setcb(bev,
   2790 	    http_chunked_readcb, http_chunked_writecb,
   2791 	    http_chunked_errorcb, data->base);
   2792 
   2793 	http_request =
   2794 	    "GET /chunked HTTP/1.1\r\n"
   2795 	    "Host: somehost\r\n"
   2796 	    "Connection: close\r\n"
   2797 	    "\r\n";
   2798 
   2799 	bufferevent_write(bev, http_request, strlen(http_request));
   2800 
   2801 	evutil_gettimeofday(&tv_start, NULL);
   2802 
   2803 	event_base_dispatch(data->base);
   2804 
   2805 	bufferevent_free(bev);
   2806 
   2807 	evutil_gettimeofday(&tv_end, NULL);
   2808 	evutil_timersub(&tv_end, &tv_start, &tv_end);
   2809 
   2810 	tt_int_op(tv_end.tv_sec, <, 1);
   2811 
   2812 	tt_int_op(test_ok, ==, 2);
   2813 
   2814 	/* now try again with the regular connection object */
   2815 	evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port);
   2816 	tt_assert(evcon);
   2817 
   2818 	/* make two requests to check the keepalive behavior */
   2819 	for (i = 0; i < 2; i++) {
   2820 		test_ok = 0;
   2821 		req = evhttp_request_new(http_chunked_request_done,data->base);
   2822 
   2823 		/* Add the information that we care about */
   2824 		evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
   2825 
   2826 		/* We give ownership of the request to the connection */
   2827 		if (evhttp_make_request(evcon, req,
   2828 			EVHTTP_REQ_GET, "/chunked") == -1) {
   2829 			tt_abort_msg("Couldn't make request");
   2830 		}
   2831 
   2832 		event_base_dispatch(data->base);
   2833 
   2834 		tt_assert(test_ok == 1);
   2835 	}
   2836 
   2837  end:
   2838 	if (evcon)
   2839 		evhttp_connection_free(evcon);
   2840 	if (http)
   2841 		evhttp_free(http);
   2842 }
   2843 
   2844 static void
   2845 http_stream_out_test(void *arg)
   2846 {
   2847 	struct basic_test_data *data = arg;
   2848 	ev_uint16_t port = 0;
   2849 	struct evhttp_connection *evcon = NULL;
   2850 	struct evhttp_request *req = NULL;
   2851 
   2852 	test_ok = 0;
   2853 	exit_base = data->base;
   2854 
   2855 	http = http_setup(&port, data->base);
   2856 
   2857 	evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port);
   2858 	tt_assert(evcon);
   2859 
   2860 	/*
   2861 	 * At this point, we want to schedule a request to the HTTP
   2862 	 * server using our make request method.
   2863 	 */
   2864 
   2865 	req = evhttp_request_new(http_request_done,
   2866 	    (void *)"This is funnybut not hilarious.bwv 1052");
   2867 
   2868 	/* Add the information that we care about */
   2869 	evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
   2870 
   2871 	/* We give ownership of the request to the connection */
   2872 	if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/streamed")
   2873 	    == -1) {
   2874 		tt_abort_msg("Couldn't make request");
   2875 	}
   2876 
   2877 	event_base_dispatch(data->base);
   2878 
   2879  end:
   2880 	if (evcon)
   2881 		evhttp_connection_free(evcon);
   2882 	if (http)
   2883 		evhttp_free(http);
   2884 }
   2885 
   2886 static void
   2887 http_stream_in_chunk(struct evhttp_request *req, void *arg)
   2888 {
   2889 	struct evbuffer *reply = arg;
   2890 
   2891 	if (evhttp_request_get_response_code(req) != HTTP_OK) {
   2892 		fprintf(stderr, "FAILED\n");
   2893 		exit(1);
   2894 	}
   2895 
   2896 	evbuffer_add_buffer(reply, evhttp_request_get_input_buffer(req));
   2897 }
   2898 
   2899 static void
   2900 http_stream_in_done(struct evhttp_request *req, void *arg)
   2901 {
   2902 	if (evbuffer_get_length(evhttp_request_get_input_buffer(req)) != 0) {
   2903 		fprintf(stderr, "FAILED\n");
   2904 		exit(1);
   2905 	}
   2906 
   2907 	event_base_loopexit(exit_base, NULL);
   2908 }
   2909 
   2910 /**
   2911  * Makes a request and reads the response in chunks.
   2912  */
   2913 static void
   2914 _http_stream_in_test(struct basic_test_data *data, char const *url,
   2915     size_t expected_len, char const *expected)
   2916 {
   2917 	struct evhttp_connection *evcon;
   2918 	struct evbuffer *reply = evbuffer_new();
   2919 	struct evhttp_request *req = NULL;
   2920 	ev_uint16_t port = 0;
   2921 
   2922 	exit_base = data->base;
   2923 	http = http_setup(&port, data->base);
   2924 
   2925 	evcon = evhttp_connection_base_new(data->base, NULL,"127.0.0.1", port);
   2926 	tt_assert(evcon);
   2927 
   2928 	req = evhttp_request_new(http_stream_in_done, reply);
   2929 	evhttp_request_set_chunked_cb(req, http_stream_in_chunk);
   2930 
   2931 	/* We give ownership of the request to the connection */
   2932 	if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, url) == -1) {
   2933 		tt_abort_msg("Couldn't make request");
   2934 	}
   2935 
   2936 	event_base_dispatch(data->base);
   2937 
   2938 	if (evbuffer_get_length(reply) != expected_len) {
   2939 		TT_DIE(("reply length %lu; expected %lu; FAILED (%s)\n",
   2940 				(unsigned long)evbuffer_get_length(reply),
   2941 				(unsigned long)expected_len,
   2942 				(char*)evbuffer_pullup(reply, -1)));
   2943 	}
   2944 
   2945 	if (memcmp(evbuffer_pullup(reply, -1), expected, expected_len) != 0) {
   2946 		tt_abort_msg("Memory mismatch");
   2947 	}
   2948 
   2949 	test_ok = 1;
   2950  end:
   2951 	if (reply)
   2952 		evbuffer_free(reply);
   2953 	if (evcon)
   2954 		evhttp_connection_free(evcon);
   2955 	if (http)
   2956 		evhttp_free(http);
   2957 }
   2958 
   2959 static void
   2960 http_stream_in_test(void *arg)
   2961 {
   2962 	_http_stream_in_test(arg, "/chunked", 13 + 18 + 8,
   2963 	    "This is funnybut not hilarious.bwv 1052");
   2964 
   2965 	_http_stream_in_test(arg, "/test", strlen(BASIC_REQUEST_BODY),
   2966 	    BASIC_REQUEST_BODY);
   2967 }
   2968 
   2969 static void
   2970 http_stream_in_cancel_chunk(struct evhttp_request *req, void *arg)
   2971 {
   2972 	tt_int_op(evhttp_request_get_response_code(req), ==, HTTP_OK);
   2973 
   2974  end:
   2975 	evhttp_cancel_request(req);
   2976 	event_base_loopexit(arg, NULL);
   2977 }
   2978 
   2979 static void
   2980 http_stream_in_cancel_done(struct evhttp_request *req, void *arg)
   2981 {
   2982 	/* should never be called */
   2983 	tt_fail_msg("In cancel done");
   2984 }
   2985 
   2986 static void
   2987 http_stream_in_cancel_test(void *arg)
   2988 {
   2989 	struct basic_test_data *data = arg;
   2990 	struct evhttp_connection *evcon;
   2991 	struct evhttp_request *req = NULL;
   2992 	ev_uint16_t port = 0;
   2993 
   2994 	http = http_setup(&port, data->base);
   2995 
   2996 	evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port);
   2997 	tt_assert(evcon);
   2998 
   2999 	req = evhttp_request_new(http_stream_in_cancel_done, data->base);
   3000 	evhttp_request_set_chunked_cb(req, http_stream_in_cancel_chunk);
   3001 
   3002 	/* We give ownership of the request to the connection */
   3003 	if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/chunked") == -1) {
   3004 		tt_abort_msg("Couldn't make request");
   3005 	}
   3006 
   3007 	event_base_dispatch(data->base);
   3008 
   3009 	test_ok = 1;
   3010  end:
   3011 	evhttp_connection_free(evcon);
   3012 	evhttp_free(http);
   3013 
   3014 }
   3015 
   3016 static void
   3017 http_connection_fail_done(struct evhttp_request *req, void *arg)
   3018 {
   3019        /* An ENETUNREACH error results in an unrecoverable
   3020         * evhttp_connection error (see evhttp_connection_fail()).  The
   3021         * connection will be reset, and the user will be notified with a NULL
   3022         * req parameter. */
   3023        tt_assert(!req);
   3024 
   3025        test_ok = 1;
   3026 
   3027  end:
   3028        event_base_loopexit(arg, NULL);
   3029 }
   3030 
   3031 /* Test unrecoverable evhttp_connection errors by generating an ENETUNREACH
   3032  * error on connection. */
   3033 static void
   3034 http_connection_fail_test(void *arg)
   3035 {
   3036        struct basic_test_data *data = arg;
   3037        ev_uint16_t port = 0;
   3038        struct evhttp_connection *evcon = NULL;
   3039        struct evhttp_request *req = NULL;
   3040 
   3041        exit_base = data->base;
   3042        test_ok = 0;
   3043 
   3044        /* auto detect a port */
   3045        http = http_setup(&port, data->base);
   3046        evhttp_free(http);
   3047        http = NULL;
   3048 
   3049        /* Pick an unroutable address.  This administratively scoped multicast
   3050 	* address should do when working with TCP. */
   3051        evcon = evhttp_connection_base_new(data->base, NULL, "239.10.20.30", 80);
   3052        tt_assert(evcon);
   3053 
   3054        /*
   3055         * At this point, we want to schedule an HTTP GET request
   3056         * server using our make request method.
   3057         */
   3058 
   3059        req = evhttp_request_new(http_connection_fail_done, data->base);
   3060        tt_assert(req);
   3061 
   3062        if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/") == -1) {
   3063                tt_abort_msg("Couldn't make request");
   3064        }
   3065 
   3066        event_base_dispatch(data->base);
   3067 
   3068        tt_int_op(test_ok, ==, 1);
   3069 
   3070  end:
   3071        if (evcon)
   3072                evhttp_connection_free(evcon);
   3073 }
   3074 
   3075 static void
   3076 http_connection_retry_done(struct evhttp_request *req, void *arg)
   3077 {
   3078 	tt_assert(req);
   3079 	tt_int_op(evhttp_request_get_response_code(req), !=, HTTP_OK);
   3080 	if (evhttp_find_header(evhttp_request_get_input_headers(req), "Content-Type") != NULL) {
   3081 		tt_abort_msg("(content type)\n");
   3082 	}
   3083 
   3084 	tt_uint_op(evbuffer_get_length(evhttp_request_get_input_buffer(req)), ==, 0);
   3085 
   3086 	test_ok = 1;
   3087  end:
   3088 	event_base_loopexit(arg,NULL);
   3089 }
   3090 
   3091 static struct event_base *http_make_web_server_base=NULL;
   3092 static void
   3093 http_make_web_server(evutil_socket_t fd, short what, void *arg)
   3094 {
   3095 	ev_uint16_t port = *(ev_uint16_t*)arg;
   3096 	http = http_setup(&port, http_make_web_server_base);
   3097 }
   3098 
   3099 static void
   3100 http_connection_retry_test(void *arg)
   3101 {
   3102 	struct basic_test_data *data = arg;
   3103 	ev_uint16_t port = 0;
   3104 	struct evhttp_connection *evcon = NULL;
   3105 	struct evhttp_request *req = NULL;
   3106 	struct timeval tv, tv_start, tv_end;
   3107 
   3108 	exit_base = data->base;
   3109 	test_ok = 0;
   3110 
   3111 	/* auto detect a port */
   3112 	http = http_setup(&port, data->base);
   3113 	evhttp_free(http);
   3114 	http = NULL;
   3115 
   3116 	evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port);
   3117 	tt_assert(evcon);
   3118 
   3119 	evhttp_connection_set_timeout(evcon, 1);
   3120 	/* also bind to local host */
   3121 	evhttp_connection_set_local_address(evcon, "127.0.0.1");
   3122 
   3123 	/*
   3124 	 * At this point, we want to schedule an HTTP GET request
   3125 	 * server using our make request method.
   3126 	 */
   3127 
   3128 	req = evhttp_request_new(http_connection_retry_done, data->base);
   3129 	tt_assert(req);
   3130 
   3131 	/* Add the information that we care about */
   3132 	evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
   3133 
   3134 	if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET,
   3135 		"/?arg=val") == -1) {
   3136 		tt_abort_msg("Couldn't make request");
   3137 	}
   3138 
   3139 	evutil_gettimeofday(&tv_start, NULL);
   3140 	event_base_dispatch(data->base);
   3141 	evutil_gettimeofday(&tv_end, NULL);
   3142 	evutil_timersub(&tv_end, &tv_start, &tv_end);
   3143 	tt_int_op(tv_end.tv_sec, <, 1);
   3144 
   3145 	tt_int_op(test_ok, ==, 1);
   3146 
   3147 	/*
   3148 	 * now test the same but with retries
   3149 	 */
   3150 	test_ok = 0;
   3151 
   3152 	evhttp_connection_set_timeout(evcon, 1);
   3153 	evhttp_connection_set_retries(evcon, 1);
   3154 
   3155 	req = evhttp_request_new(http_connection_retry_done, data->base);
   3156 	tt_assert(req);
   3157 
   3158 	/* Add the information that we care about */
   3159 	evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
   3160 
   3161 	if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET,
   3162 		"/?arg=val") == -1) {
   3163 		tt_abort_msg("Couldn't make request");
   3164 	}
   3165 
   3166 	evutil_gettimeofday(&tv_start, NULL);
   3167 	event_base_dispatch(data->base);
   3168 	evutil_gettimeofday(&tv_end, NULL);
   3169 	evutil_timersub(&tv_end, &tv_start, &tv_end);
   3170 	tt_int_op(tv_end.tv_sec, >, 1);
   3171 	tt_int_op(tv_end.tv_sec, <, 6);
   3172 
   3173 	tt_assert(test_ok == 1);
   3174 
   3175 	/*
   3176 	 * now test the same but with retries and give it a web server
   3177 	 * at the end
   3178 	 */
   3179 	test_ok = 0;
   3180 
   3181 	evhttp_connection_set_timeout(evcon, 1);
   3182 	evhttp_connection_set_retries(evcon, 3);
   3183 
   3184 	req = evhttp_request_new(http_dispatcher_test_done, data->base);
   3185 	tt_assert(req);
   3186 
   3187 	/* Add the information that we care about */
   3188 	evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
   3189 
   3190 	if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET,
   3191 		"/?arg=val") == -1) {
   3192 		tt_abort_msg("Couldn't make request");
   3193 	}
   3194 
   3195 	/* start up a web server one second after the connection tried
   3196 	 * to send a request
   3197 	 */
   3198 	evutil_timerclear(&tv);
   3199 	tv.tv_sec = 1;
   3200 	http_make_web_server_base = data->base;
   3201 	event_base_once(data->base, -1, EV_TIMEOUT, http_make_web_server, &port, &tv);
   3202 
   3203 	evutil_gettimeofday(&tv_start, NULL);
   3204 	event_base_dispatch(data->base);
   3205 	evutil_gettimeofday(&tv_end, NULL);
   3206 
   3207 	evutil_timersub(&tv_end, &tv_start, &tv_end);
   3208 
   3209 	tt_int_op(tv_end.tv_sec, >, 1);
   3210 	tt_int_op(tv_end.tv_sec, <, 6);
   3211 
   3212 	tt_int_op(test_ok, ==, 1);
   3213 
   3214  end:
   3215 	if (evcon)
   3216 		evhttp_connection_free(evcon);
   3217 	if (http)
   3218 		evhttp_free(http);
   3219 }
   3220 
   3221 static void
   3222 http_primitives(void *ptr)
   3223 {
   3224 	char *escaped = NULL;
   3225 	struct evhttp *http = NULL;
   3226 
   3227 	escaped = evhttp_htmlescape("<script>");
   3228 	tt_assert(escaped);
   3229 	tt_str_op(escaped, ==, "&lt;script&gt;");
   3230 	free(escaped);
   3231 
   3232 	escaped = evhttp_htmlescape("\"\'&");
   3233 	tt_assert(escaped);
   3234 	tt_str_op(escaped, ==, "&quot;&#039;&amp;");
   3235 
   3236 	http = evhttp_new(NULL);
   3237 	tt_assert(http);
   3238 	tt_int_op(evhttp_set_cb(http, "/test", http_basic_cb, NULL), ==, 0);
   3239 	tt_int_op(evhttp_set_cb(http, "/test", http_basic_cb, NULL), ==, -1);
   3240 	tt_int_op(evhttp_del_cb(http, "/test"), ==, 0);
   3241 	tt_int_op(evhttp_del_cb(http, "/test"), ==, -1);
   3242 	tt_int_op(evhttp_set_cb(http, "/test", http_basic_cb, NULL), ==, 0);
   3243 
   3244  end:
   3245 	if (escaped)
   3246 		free(escaped);
   3247 	if (http)
   3248 		evhttp_free(http);
   3249 }
   3250 
   3251 static void
   3252 http_multi_line_header_test(void *arg)
   3253 {
   3254 	struct basic_test_data *data = arg;
   3255 	struct bufferevent *bev= NULL;
   3256 	evutil_socket_t fd = -1;
   3257 	const char *http_start_request;
   3258 	ev_uint16_t port = 0;
   3259 
   3260 	test_ok = 0;
   3261 
   3262 	http = http_setup(&port, data->base);
   3263 
   3264 	fd = http_connect("127.0.0.1", port);
   3265 
   3266 	/* Stupid thing to send a request */
   3267 	bev = bufferevent_socket_new(data->base, fd, 0);
   3268 	bufferevent_setcb(bev, http_readcb, http_writecb,
   3269 	    http_errorcb, data->base);
   3270 
   3271 	http_start_request =
   3272 	    "GET /test HTTP/1.1\r\n"
   3273 	    "Host: somehost\r\n"
   3274 	    "Connection: close\r\n"
   3275 	    "X-Multi:  aaaaaaaa\r\n"
   3276 	    " a\r\n"
   3277 	    "\tEND\r\n"
   3278 	    "X-Last: last\r\n"
   3279 	    "\r\n";
   3280 
   3281 	bufferevent_write(bev, http_start_request, strlen(http_start_request));
   3282 
   3283 	event_base_dispatch(data->base);
   3284 
   3285 	tt_int_op(test_ok, ==, 4);
   3286  end:
   3287 	if (bev)
   3288 		bufferevent_free(bev);
   3289 	if (fd >= 0)
   3290 		evutil_closesocket(fd);
   3291 	if (http)
   3292 		evhttp_free(http);
   3293 }
   3294 
   3295 static void
   3296 http_request_bad(struct evhttp_request *req, void *arg)
   3297 {
   3298 	if (req != NULL) {
   3299 		fprintf(stderr, "FAILED\n");
   3300 		exit(1);
   3301 	}
   3302 
   3303 	test_ok = 1;
   3304 	event_base_loopexit(arg, NULL);
   3305 }
   3306 
   3307 static void
   3308 http_negative_content_length_test(void *arg)
   3309 {
   3310 	struct basic_test_data *data = arg;
   3311 	ev_uint16_t port = 0;
   3312 	struct evhttp_connection *evcon = NULL;
   3313 	struct evhttp_request *req = NULL;
   3314 
   3315 	test_ok = 0;
   3316 
   3317 	http = http_setup(&port, data->base);
   3318 
   3319 	evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port);
   3320 	tt_assert(evcon);
   3321 
   3322 	/*
   3323 	 * At this point, we want to schedule a request to the HTTP
   3324 	 * server using our make request method.
   3325 	 */
   3326 
   3327 	req = evhttp_request_new(http_request_bad, data->base);
   3328 
   3329 	/* Cause the response to have a negative content-length */
   3330 	evhttp_add_header(evhttp_request_get_output_headers(req), "X-Negative", "makeitso");
   3331 
   3332 	/* We give ownership of the request to the connection */
   3333 	if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test") == -1) {
   3334 		tt_abort_msg("Couldn't make request");
   3335 	}
   3336 
   3337 	event_base_dispatch(data->base);
   3338 
   3339  end:
   3340 	if (evcon)
   3341 		evhttp_connection_free(evcon);
   3342 	if (http)
   3343 		evhttp_free(http);
   3344 }
   3345 
   3346 
   3347 static void
   3348 http_data_length_constraints_test_done(struct evhttp_request *req, void *arg)
   3349 {
   3350 	tt_assert(req);
   3351 	tt_int_op(evhttp_request_get_response_code(req), ==, HTTP_BADREQUEST);
   3352 end:
   3353 	event_base_loopexit(arg, NULL);
   3354 }
   3355 
   3356 static void
   3357 http_large_entity_test_done(struct evhttp_request *req, void *arg)
   3358 {
   3359 	tt_assert(req);
   3360 	tt_int_op(evhttp_request_get_response_code(req), ==, HTTP_ENTITYTOOLARGE);
   3361 end:
   3362 	event_base_loopexit(arg, NULL);
   3363 }
   3364 
   3365 static void
   3366 http_data_length_constraints_test(void *arg)
   3367 {
   3368 	struct basic_test_data *data = arg;
   3369 	ev_uint16_t port = 0;
   3370 	struct evhttp_connection *evcon = NULL;
   3371 	struct evhttp_request *req = NULL;
   3372 	char long_str[8192];
   3373 
   3374 	test_ok = 0;
   3375 
   3376 	http = http_setup(&port, data->base);
   3377 
   3378 	evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port);
   3379 	tt_assert(evcon);
   3380 
   3381 	/* also bind to local host */
   3382 	evhttp_connection_set_local_address(evcon, "127.0.0.1");
   3383 
   3384 	/*
   3385 	 * At this point, we want to schedule an HTTP GET request
   3386 	 * server using our make request method.
   3387 	 */
   3388 
   3389 	req = evhttp_request_new(http_data_length_constraints_test_done, data->base);
   3390 	tt_assert(req);
   3391 
   3392 	memset(long_str, 'a', 8192);
   3393 	long_str[8191] = '\0';
   3394 	/* Add the information that we care about */
   3395 	evhttp_set_max_headers_size(http, 8191);
   3396 	evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
   3397 	evhttp_add_header(evhttp_request_get_output_headers(req), "Longheader", long_str);
   3398 
   3399 	if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/?arg=val") == -1) {
   3400 		tt_abort_msg("Couldn't make request");
   3401 	}
   3402 	event_base_dispatch(data->base);
   3403 
   3404 	req = evhttp_request_new(http_data_length_constraints_test_done, data->base);
   3405 	tt_assert(req);
   3406 	evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
   3407 
   3408 	/* GET /?arg=verylongvalue HTTP/1.1 */
   3409 	if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, long_str) == -1) {
   3410 		tt_abort_msg("Couldn't make request");
   3411 	}
   3412 	event_base_dispatch(data->base);
   3413 
   3414 	evhttp_set_max_body_size(http, 8190);
   3415 	req = evhttp_request_new(http_data_length_constraints_test_done, data->base);
   3416 	evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
   3417 	evbuffer_add_printf(evhttp_request_get_output_buffer(req), "%s", long_str);
   3418 	if (evhttp_make_request(evcon, req, EVHTTP_REQ_POST, "/") == -1) {
   3419 		tt_abort_msg("Couldn't make request");
   3420 	}
   3421 	event_base_dispatch(data->base);
   3422 
   3423 	req = evhttp_request_new(http_large_entity_test_done, data->base);
   3424 	evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
   3425 	evhttp_add_header(evhttp_request_get_output_headers(req), "Expect", "100-continue");
   3426 	evbuffer_add_printf(evhttp_request_get_output_buffer(req), "%s", long_str);
   3427 	if (evhttp_make_request(evcon, req, EVHTTP_REQ_POST, "/") == -1) {
   3428 		tt_abort_msg("Couldn't make request");
   3429 	}
   3430 	event_base_dispatch(data->base);
   3431 
   3432 	test_ok = 1;
   3433  end:
   3434 	if (evcon)
   3435 		evhttp_connection_free(evcon);
   3436 	if (http)
   3437 		evhttp_free(http);
   3438 }
   3439 
   3440 /*
   3441  * Testing client reset of server chunked connections
   3442  */
   3443 
   3444 struct terminate_state {
   3445 	struct event_base *base;
   3446 	struct evhttp_request *req;
   3447 	struct bufferevent *bev;
   3448 	evutil_socket_t fd;
   3449 	int gotclosecb: 1;
   3450 };
   3451 
   3452 static void
   3453 terminate_chunked_trickle_cb(evutil_socket_t fd, short events, void *arg)
   3454 {
   3455 	struct terminate_state *state = arg;
   3456 	struct evbuffer *evb;
   3457 	struct timeval tv;
   3458 
   3459 	if (evhttp_request_get_connection(state->req) == NULL) {
   3460 		test_ok = 1;
   3461 		evhttp_request_free(state->req);
   3462 		event_base_loopexit(state->base,NULL);
   3463 		return;
   3464 	}
   3465 
   3466 	evb = evbuffer_new();
   3467 	evbuffer_add_printf(evb, "%p", evb);
   3468 	evhttp_send_reply_chunk(state->req, evb);
   3469 	evbuffer_free(evb);
   3470 
   3471 	tv.tv_sec = 0;
   3472 	tv.tv_usec = 3000;
   3473 	EVUTIL_ASSERT(state);
   3474 	EVUTIL_ASSERT(state->base);
   3475 	event_base_once(state->base, -1, EV_TIMEOUT, terminate_chunked_trickle_cb, arg, &tv);
   3476 }
   3477 
   3478 static void
   3479 terminate_chunked_close_cb(struct evhttp_connection *evcon, void *arg)
   3480 {
   3481 	struct terminate_state *state = arg;
   3482 	state->gotclosecb = 1;
   3483 }
   3484 
   3485 static void
   3486 terminate_chunked_cb(struct evhttp_request *req, void *arg)
   3487 {
   3488 	struct terminate_state *state = arg;
   3489 	struct timeval tv;
   3490 
   3491 	/* we want to know if this connection closes on us */
   3492 	evhttp_connection_set_closecb(
   3493 		evhttp_request_get_connection(req),
   3494 		terminate_chunked_close_cb, arg);
   3495 
   3496 	state->req = req;
   3497 
   3498 	evhttp_send_reply_start(req, HTTP_OK, "OK");
   3499 
   3500 	tv.tv_sec = 0;
   3501 	tv.tv_usec = 3000;
   3502 	event_base_once(state->base, -1, EV_TIMEOUT, terminate_chunked_trickle_cb, arg, &tv);
   3503 }
   3504 
   3505 static void
   3506 terminate_chunked_client(evutil_socket_t fd, short event, void *arg)
   3507 {
   3508 	struct terminate_state *state = arg;
   3509 	bufferevent_free(state->bev);
   3510 	evutil_closesocket(state->fd);
   3511 }
   3512 
   3513 static void
   3514 terminate_readcb(struct bufferevent *bev, void *arg)
   3515 {
   3516 	/* just drop the data */
   3517 	evbuffer_drain(bufferevent_get_input(bev), -1);
   3518 }
   3519 
   3520 
   3521 static void
   3522 http_terminate_chunked_test(void *arg)
   3523 {
   3524 	struct basic_test_data *data = arg;
   3525 	struct bufferevent *bev = NULL;
   3526 	struct timeval tv;
   3527 	const char *http_request;
   3528 	ev_uint16_t port = 0;
   3529 	evutil_socket_t fd = -1;
   3530 	struct terminate_state terminate_state;
   3531 
   3532 	test_ok = 0;
   3533 
   3534 	http = http_setup(&port, data->base);
   3535 	evhttp_del_cb(http, "/test");
   3536 	tt_assert(evhttp_set_cb(http, "/test",
   3537 		terminate_chunked_cb, &terminate_state) == 0);
   3538 
   3539 	fd = http_connect("127.0.0.1", port);
   3540 
   3541 	/* Stupid thing to send a request */
   3542 	bev = bufferevent_socket_new(data->base, fd, 0);
   3543 	bufferevent_setcb(bev, terminate_readcb, http_writecb,
   3544 	    http_errorcb, data->base);
   3545 
   3546 	memset(&terminate_state, 0, sizeof(terminate_state));
   3547 	terminate_state.base = data->base;
   3548 	terminate_state.fd = fd;
   3549 	terminate_state.bev = bev;
   3550 	terminate_state.gotclosecb = 0;
   3551 
   3552 	/* first half of the http request */
   3553 	http_request =
   3554 	    "GET /test HTTP/1.1\r\n"
   3555 	    "Host: some\r\n\r\n";
   3556 
   3557 	bufferevent_write(bev, http_request, strlen(http_request));
   3558 	evutil_timerclear(&tv);
   3559 	tv.tv_usec = 10000;
   3560 	event_base_once(data->base, -1, EV_TIMEOUT, terminate_chunked_client, &terminate_state,
   3561 	    &tv);
   3562 
   3563 	event_base_dispatch(data->base);
   3564 
   3565 	if (terminate_state.gotclosecb == 0)
   3566 		test_ok = 0;
   3567 
   3568  end:
   3569 	if (fd >= 0)
   3570 		evutil_closesocket(fd);
   3571 	if (http)
   3572 		evhttp_free(http);
   3573 }
   3574 
   3575 #define HTTP_LEGACY(name)						\
   3576 	{ #name, run_legacy_test_fn, TT_ISOLATED|TT_LEGACY, &legacy_setup, \
   3577 		    http_##name##_test }
   3578 
   3579 #define HTTP(name) \
   3580 	{ #name, http_##name##_test, TT_ISOLATED, &basic_setup, NULL }
   3581 
   3582 struct testcase_t http_testcases[] = {
   3583 	{ "primitives", http_primitives, 0, NULL, NULL },
   3584 	{ "base", http_base_test, TT_FORK, NULL, NULL },
   3585 	{ "bad_headers", http_bad_header_test, 0, NULL, NULL },
   3586 	{ "parse_query", http_parse_query_test, 0, NULL, NULL },
   3587 	{ "parse_uri", http_parse_uri_test, 0, NULL, NULL },
   3588 	{ "parse_uri_nc", http_parse_uri_test, 0, &basic_setup, (void*)"nc" },
   3589 	{ "uriencode", http_uriencode_test, 0, NULL, NULL },
   3590 	HTTP(basic),
   3591 	HTTP(cancel),
   3592 	HTTP(virtual_host),
   3593 	HTTP(post),
   3594 	HTTP(put),
   3595 	HTTP(delete),
   3596 	HTTP(allowed_methods),
   3597 	HTTP(failure),
   3598 	HTTP(connection),
   3599 	HTTP(persist_connection),
   3600 	HTTP(connection_async),
   3601 	HTTP(close_detection),
   3602 	HTTP(close_detection_delay),
   3603 	HTTP(bad_request),
   3604 	HTTP(incomplete),
   3605 	HTTP(incomplete_timeout),
   3606 	HTTP(terminate_chunked),
   3607 
   3608 	HTTP(highport),
   3609 	HTTP(dispatcher),
   3610 	HTTP(multi_line_header),
   3611 	HTTP(negative_content_length),
   3612 	HTTP(chunk_out),
   3613 	HTTP(stream_out),
   3614 
   3615 	HTTP(stream_in),
   3616 	HTTP(stream_in_cancel),
   3617 
   3618 	HTTP(connection_fail),
   3619 	HTTP(connection_retry),
   3620 	HTTP(data_length_constraints),
   3621 
   3622 	END_OF_TESTCASES
   3623 };
   3624 
   3625