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