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