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