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