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