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