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