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