xref: /freebsd/contrib/ntp/sntp/libevent/test/regress_http.c (revision a466cc55373fc3cf86837f09da729535b57e69a1)
12b15cb3dSCy Schubert /*
22b15cb3dSCy Schubert  * Copyright (c) 2003-2007 Niels Provos <provos@citi.umich.edu>
32b15cb3dSCy Schubert  * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson
42b15cb3dSCy Schubert  *
52b15cb3dSCy Schubert  * Redistribution and use in source and binary forms, with or without
62b15cb3dSCy Schubert  * modification, are permitted provided that the following conditions
72b15cb3dSCy Schubert  * are met:
82b15cb3dSCy Schubert  * 1. Redistributions of source code must retain the above copyright
92b15cb3dSCy Schubert  *    notice, this list of conditions and the following disclaimer.
102b15cb3dSCy Schubert  * 2. Redistributions in binary form must reproduce the above copyright
112b15cb3dSCy Schubert  *    notice, this list of conditions and the following disclaimer in the
122b15cb3dSCy Schubert  *    documentation and/or other materials provided with the distribution.
132b15cb3dSCy Schubert  * 3. The name of the author may not be used to endorse or promote products
142b15cb3dSCy Schubert  *    derived from this software without specific prior written permission.
152b15cb3dSCy Schubert  *
162b15cb3dSCy Schubert  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
172b15cb3dSCy Schubert  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
182b15cb3dSCy Schubert  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
192b15cb3dSCy Schubert  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
202b15cb3dSCy Schubert  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
212b15cb3dSCy Schubert  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
222b15cb3dSCy Schubert  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
232b15cb3dSCy Schubert  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
242b15cb3dSCy Schubert  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
252b15cb3dSCy Schubert  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
262b15cb3dSCy Schubert  */
272b15cb3dSCy Schubert #include "util-internal.h"
282b15cb3dSCy Schubert 
292b15cb3dSCy Schubert #ifdef _WIN32
302b15cb3dSCy Schubert #include <winsock2.h>
312b15cb3dSCy Schubert #include <ws2tcpip.h>
322b15cb3dSCy Schubert #include <windows.h>
332b15cb3dSCy Schubert #endif
342b15cb3dSCy Schubert 
352b15cb3dSCy Schubert #include "event2/event-config.h"
362b15cb3dSCy Schubert 
372b15cb3dSCy Schubert #include <sys/types.h>
382b15cb3dSCy Schubert #include <sys/stat.h>
392b15cb3dSCy Schubert #ifdef EVENT__HAVE_SYS_TIME_H
402b15cb3dSCy Schubert #include <sys/time.h>
412b15cb3dSCy Schubert #endif
422b15cb3dSCy Schubert #include <sys/queue.h>
432b15cb3dSCy Schubert #ifndef _WIN32
442b15cb3dSCy Schubert #include <sys/socket.h>
452b15cb3dSCy Schubert #include <signal.h>
462b15cb3dSCy Schubert #include <unistd.h>
472b15cb3dSCy Schubert #include <netdb.h>
482b15cb3dSCy Schubert #endif
492b15cb3dSCy Schubert #include <fcntl.h>
502b15cb3dSCy Schubert #include <stdlib.h>
512b15cb3dSCy Schubert #include <stdio.h>
522b15cb3dSCy Schubert #include <string.h>
532b15cb3dSCy Schubert #include <errno.h>
542b15cb3dSCy Schubert 
552b15cb3dSCy Schubert #include "event2/dns.h"
562b15cb3dSCy Schubert 
572b15cb3dSCy Schubert #include "event2/event.h"
582b15cb3dSCy Schubert #include "event2/http.h"
592b15cb3dSCy Schubert #include "event2/buffer.h"
602b15cb3dSCy Schubert #include "event2/bufferevent.h"
61*a466cc55SCy Schubert #include "event2/bufferevent_ssl.h"
622b15cb3dSCy Schubert #include "event2/util.h"
63*a466cc55SCy Schubert #include "event2/listener.h"
642b15cb3dSCy Schubert #include "log-internal.h"
652b15cb3dSCy Schubert #include "http-internal.h"
662b15cb3dSCy Schubert #include "regress.h"
672b15cb3dSCy Schubert #include "regress_testutils.h"
682b15cb3dSCy Schubert 
69*a466cc55SCy Schubert #define ARRAY_SIZE(x) (sizeof(x)/sizeof((x)[0]))
70*a466cc55SCy Schubert 
712b15cb3dSCy Schubert /* set if a test needs to call loopexit on a base */
722b15cb3dSCy Schubert static struct event_base *exit_base;
732b15cb3dSCy Schubert 
742b15cb3dSCy Schubert static char const BASIC_REQUEST_BODY[] = "This is funny";
752b15cb3dSCy Schubert 
762b15cb3dSCy Schubert static void http_basic_cb(struct evhttp_request *req, void *arg);
77*a466cc55SCy Schubert static void http_timeout_cb(struct evhttp_request *req, void *arg);
78*a466cc55SCy Schubert static void http_large_cb(struct evhttp_request *req, void *arg);
792b15cb3dSCy Schubert static void http_chunked_cb(struct evhttp_request *req, void *arg);
802b15cb3dSCy Schubert static void http_post_cb(struct evhttp_request *req, void *arg);
812b15cb3dSCy Schubert static void http_put_cb(struct evhttp_request *req, void *arg);
822b15cb3dSCy Schubert static void http_delete_cb(struct evhttp_request *req, void *arg);
832b15cb3dSCy Schubert static void http_delay_cb(struct evhttp_request *req, void *arg);
842b15cb3dSCy Schubert static void http_large_delay_cb(struct evhttp_request *req, void *arg);
852b15cb3dSCy Schubert static void http_badreq_cb(struct evhttp_request *req, void *arg);
862b15cb3dSCy Schubert static void http_dispatcher_cb(struct evhttp_request *req, void *arg);
872b15cb3dSCy Schubert static void http_on_complete_cb(struct evhttp_request *req, void *arg);
882b15cb3dSCy Schubert 
89*a466cc55SCy Schubert #define HTTP_BIND_IPV6 1
90*a466cc55SCy Schubert #define HTTP_BIND_SSL 2
91*a466cc55SCy Schubert #define HTTP_SSL_FILTER 4
922b15cb3dSCy Schubert static int
http_bind(struct evhttp * myhttp,ev_uint16_t * pport,int mask)93*a466cc55SCy Schubert http_bind(struct evhttp *myhttp, ev_uint16_t *pport, int mask)
942b15cb3dSCy Schubert {
952b15cb3dSCy Schubert 	int port;
962b15cb3dSCy Schubert 	struct evhttp_bound_socket *sock;
97*a466cc55SCy Schubert 	int ipv6 = mask & HTTP_BIND_IPV6;
982b15cb3dSCy Schubert 
992b15cb3dSCy Schubert 	if (ipv6)
1002b15cb3dSCy Schubert 		sock = evhttp_bind_socket_with_handle(myhttp, "::1", *pport);
1012b15cb3dSCy Schubert 	else
1022b15cb3dSCy Schubert 		sock = evhttp_bind_socket_with_handle(myhttp, "127.0.0.1", *pport);
1032b15cb3dSCy Schubert 
104a25439b6SCy Schubert 	if (sock == NULL) {
105a25439b6SCy Schubert 		if (ipv6)
106a25439b6SCy Schubert 			return -1;
107a25439b6SCy Schubert 		else
1082b15cb3dSCy Schubert 			event_errx(1, "Could not start web server");
109a25439b6SCy Schubert 	}
1102b15cb3dSCy Schubert 
1112b15cb3dSCy Schubert 	port = regress_get_socket_port(evhttp_bound_socket_get_fd(sock));
1122b15cb3dSCy Schubert 	if (port < 0)
1132b15cb3dSCy Schubert 		return -1;
1142b15cb3dSCy Schubert 	*pport = (ev_uint16_t) port;
1152b15cb3dSCy Schubert 
1162b15cb3dSCy Schubert 	return 0;
1172b15cb3dSCy Schubert }
1182b15cb3dSCy Schubert 
119*a466cc55SCy Schubert #ifdef EVENT__HAVE_OPENSSL
120*a466cc55SCy Schubert static struct bufferevent *
https_bev(struct event_base * base,void * arg)121*a466cc55SCy Schubert https_bev(struct event_base *base, void *arg)
122*a466cc55SCy Schubert {
123*a466cc55SCy Schubert 	SSL *ssl = SSL_new(get_ssl_ctx());
124*a466cc55SCy Schubert 
125*a466cc55SCy Schubert 	SSL_use_certificate(ssl, ssl_getcert(ssl_getkey()));
126*a466cc55SCy Schubert 	SSL_use_PrivateKey(ssl, ssl_getkey());
127*a466cc55SCy Schubert 
128*a466cc55SCy Schubert 	return bufferevent_openssl_socket_new(
129*a466cc55SCy Schubert 		base, -1, ssl, BUFFEREVENT_SSL_ACCEPTING,
130*a466cc55SCy Schubert 		BEV_OPT_CLOSE_ON_FREE);
131*a466cc55SCy Schubert }
132*a466cc55SCy Schubert #endif
1332b15cb3dSCy Schubert static struct evhttp *
http_setup_gencb(ev_uint16_t * pport,struct event_base * base,int mask,void (* cb)(struct evhttp_request *,void *),void * cbarg)134*a466cc55SCy Schubert http_setup_gencb(ev_uint16_t *pport, struct event_base *base, int mask,
135*a466cc55SCy Schubert 	void (*cb)(struct evhttp_request *, void *), void *cbarg)
1362b15cb3dSCy Schubert {
1372b15cb3dSCy Schubert 	struct evhttp *myhttp;
1382b15cb3dSCy Schubert 
1392b15cb3dSCy Schubert 	/* Try a few different ports */
1402b15cb3dSCy Schubert 	myhttp = evhttp_new(base);
1412b15cb3dSCy Schubert 
142*a466cc55SCy Schubert 	if (http_bind(myhttp, pport, mask) < 0)
1432b15cb3dSCy Schubert 		return NULL;
144*a466cc55SCy Schubert #ifdef EVENT__HAVE_OPENSSL
145*a466cc55SCy Schubert 	if (mask & HTTP_BIND_SSL) {
146*a466cc55SCy Schubert 		init_ssl();
147*a466cc55SCy Schubert 		evhttp_set_bevcb(myhttp, https_bev, NULL);
148*a466cc55SCy Schubert 	}
149*a466cc55SCy Schubert #endif
150*a466cc55SCy Schubert 
151*a466cc55SCy Schubert 	evhttp_set_gencb(myhttp, cb, cbarg);
1522b15cb3dSCy Schubert 
1532b15cb3dSCy Schubert 	/* Register a callback for certain types of requests */
154*a466cc55SCy Schubert 	evhttp_set_cb(myhttp, "/test", http_basic_cb, myhttp);
155*a466cc55SCy Schubert 	evhttp_set_cb(myhttp, "/test nonconformant", http_basic_cb, myhttp);
156*a466cc55SCy Schubert 	evhttp_set_cb(myhttp, "/timeout", http_timeout_cb, myhttp);
157*a466cc55SCy Schubert 	evhttp_set_cb(myhttp, "/large", http_large_cb, base);
1582b15cb3dSCy Schubert 	evhttp_set_cb(myhttp, "/chunked", http_chunked_cb, base);
1592b15cb3dSCy Schubert 	evhttp_set_cb(myhttp, "/streamed", http_chunked_cb, base);
1602b15cb3dSCy Schubert 	evhttp_set_cb(myhttp, "/postit", http_post_cb, base);
1612b15cb3dSCy Schubert 	evhttp_set_cb(myhttp, "/putit", http_put_cb, base);
1622b15cb3dSCy Schubert 	evhttp_set_cb(myhttp, "/deleteit", http_delete_cb, base);
1632b15cb3dSCy Schubert 	evhttp_set_cb(myhttp, "/delay", http_delay_cb, base);
1642b15cb3dSCy Schubert 	evhttp_set_cb(myhttp, "/largedelay", http_large_delay_cb, base);
1652b15cb3dSCy Schubert 	evhttp_set_cb(myhttp, "/badrequest", http_badreq_cb, base);
1662b15cb3dSCy Schubert 	evhttp_set_cb(myhttp, "/oncomplete", http_on_complete_cb, base);
1672b15cb3dSCy Schubert 	evhttp_set_cb(myhttp, "/", http_dispatcher_cb, base);
1682b15cb3dSCy Schubert 	return (myhttp);
1692b15cb3dSCy Schubert }
170*a466cc55SCy Schubert static struct evhttp *
http_setup(ev_uint16_t * pport,struct event_base * base,int mask)171*a466cc55SCy Schubert http_setup(ev_uint16_t *pport, struct event_base *base, int mask)
172*a466cc55SCy Schubert { return http_setup_gencb(pport, base, mask, NULL, NULL); }
1732b15cb3dSCy Schubert 
1742b15cb3dSCy Schubert #ifndef NI_MAXSERV
1752b15cb3dSCy Schubert #define NI_MAXSERV 1024
1762b15cb3dSCy Schubert #endif
1772b15cb3dSCy Schubert 
1782b15cb3dSCy Schubert static evutil_socket_t
http_connect(const char * address,ev_uint16_t port)179*a466cc55SCy Schubert http_connect(const char *address, ev_uint16_t port)
1802b15cb3dSCy Schubert {
1812b15cb3dSCy Schubert 	/* Stupid code for connecting */
1822b15cb3dSCy Schubert 	struct evutil_addrinfo ai, *aitop;
1832b15cb3dSCy Schubert 	char strport[NI_MAXSERV];
1842b15cb3dSCy Schubert 
1852b15cb3dSCy Schubert 	struct sockaddr *sa;
186*a466cc55SCy Schubert 	size_t slen;
1872b15cb3dSCy Schubert 	evutil_socket_t fd;
1882b15cb3dSCy Schubert 
1892b15cb3dSCy Schubert 	memset(&ai, 0, sizeof(ai));
1902b15cb3dSCy Schubert 	ai.ai_family = AF_INET;
1912b15cb3dSCy Schubert 	ai.ai_socktype = SOCK_STREAM;
1922b15cb3dSCy Schubert 	evutil_snprintf(strport, sizeof(strport), "%d", port);
1932b15cb3dSCy Schubert 	if (evutil_getaddrinfo(address, strport, &ai, &aitop) != 0) {
1942b15cb3dSCy Schubert 		event_warn("getaddrinfo");
1952b15cb3dSCy Schubert 		return (-1);
1962b15cb3dSCy Schubert 	}
1972b15cb3dSCy Schubert 	sa = aitop->ai_addr;
1982b15cb3dSCy Schubert 	slen = aitop->ai_addrlen;
1992b15cb3dSCy Schubert 
2002b15cb3dSCy Schubert 	fd = socket(AF_INET, SOCK_STREAM, 0);
2012b15cb3dSCy Schubert 	if (fd == -1)
2022b15cb3dSCy Schubert 		event_err(1, "socket failed");
2032b15cb3dSCy Schubert 
2042b15cb3dSCy Schubert 	evutil_make_socket_nonblocking(fd);
2052b15cb3dSCy Schubert 	if (connect(fd, sa, slen) == -1) {
2062b15cb3dSCy Schubert #ifdef _WIN32
2072b15cb3dSCy Schubert 		int tmp_err = WSAGetLastError();
2082b15cb3dSCy Schubert 		if (tmp_err != WSAEINPROGRESS && tmp_err != WSAEINVAL &&
2092b15cb3dSCy Schubert 		    tmp_err != WSAEWOULDBLOCK)
2102b15cb3dSCy Schubert 			event_err(1, "connect failed");
2112b15cb3dSCy Schubert #else
2122b15cb3dSCy Schubert 		if (errno != EINPROGRESS)
2132b15cb3dSCy Schubert 			event_err(1, "connect failed");
2142b15cb3dSCy Schubert #endif
2152b15cb3dSCy Schubert 	}
2162b15cb3dSCy Schubert 
2172b15cb3dSCy Schubert 	evutil_freeaddrinfo(aitop);
2182b15cb3dSCy Schubert 
2192b15cb3dSCy Schubert 	return (fd);
2202b15cb3dSCy Schubert }
2212b15cb3dSCy Schubert 
2222b15cb3dSCy Schubert /* Helper: do a strcmp on the contents of buf and the string s. */
2232b15cb3dSCy Schubert static int
evbuffer_datacmp(struct evbuffer * buf,const char * s)2242b15cb3dSCy Schubert evbuffer_datacmp(struct evbuffer *buf, const char *s)
2252b15cb3dSCy Schubert {
2262b15cb3dSCy Schubert 	size_t b_sz = evbuffer_get_length(buf);
2272b15cb3dSCy Schubert 	size_t s_sz = strlen(s);
2282b15cb3dSCy Schubert 	unsigned char *d;
2292b15cb3dSCy Schubert 	int r;
2302b15cb3dSCy Schubert 
2312b15cb3dSCy Schubert 	if (b_sz < s_sz)
2322b15cb3dSCy Schubert 		return -1;
2332b15cb3dSCy Schubert 
2342b15cb3dSCy Schubert 	d = evbuffer_pullup(buf, s_sz);
235*a466cc55SCy Schubert 	if (!d)
236*a466cc55SCy Schubert 		d = (unsigned char *)"";
2372b15cb3dSCy Schubert 	if ((r = memcmp(d, s, s_sz)))
2382b15cb3dSCy Schubert 		return r;
2392b15cb3dSCy Schubert 
2402b15cb3dSCy Schubert 	if (b_sz > s_sz)
2412b15cb3dSCy Schubert 		return 1;
2422b15cb3dSCy Schubert 	else
2432b15cb3dSCy Schubert 		return 0;
2442b15cb3dSCy Schubert }
2452b15cb3dSCy Schubert 
2462b15cb3dSCy Schubert /* Helper: Return true iff buf contains s */
2472b15cb3dSCy Schubert static int
evbuffer_contains(struct evbuffer * buf,const char * s)2482b15cb3dSCy Schubert evbuffer_contains(struct evbuffer *buf, const char *s)
2492b15cb3dSCy Schubert {
2502b15cb3dSCy Schubert 	struct evbuffer_ptr ptr;
2512b15cb3dSCy Schubert 	ptr = evbuffer_search(buf, s, strlen(s), NULL);
2522b15cb3dSCy Schubert 	return ptr.pos != -1;
2532b15cb3dSCy Schubert }
2542b15cb3dSCy Schubert 
2552b15cb3dSCy Schubert static void
http_readcb(struct bufferevent * bev,void * arg)2562b15cb3dSCy Schubert http_readcb(struct bufferevent *bev, void *arg)
2572b15cb3dSCy Schubert {
2582b15cb3dSCy Schubert 	const char *what = BASIC_REQUEST_BODY;
2592b15cb3dSCy Schubert 	struct event_base *my_base = arg;
2602b15cb3dSCy Schubert 
2612b15cb3dSCy Schubert 	if (evbuffer_contains(bufferevent_get_input(bev), what)) {
2622b15cb3dSCy Schubert 		struct evhttp_request *req = evhttp_request_new(NULL, NULL);
2632b15cb3dSCy Schubert 		enum message_read_status done;
2642b15cb3dSCy Schubert 
2652b15cb3dSCy Schubert 		/* req->kind = EVHTTP_RESPONSE; */
2662b15cb3dSCy Schubert 		done = evhttp_parse_firstline_(req, bufferevent_get_input(bev));
2672b15cb3dSCy Schubert 		if (done != ALL_DATA_READ)
2682b15cb3dSCy Schubert 			goto out;
2692b15cb3dSCy Schubert 
2702b15cb3dSCy Schubert 		done = evhttp_parse_headers_(req, bufferevent_get_input(bev));
2712b15cb3dSCy Schubert 		if (done != ALL_DATA_READ)
2722b15cb3dSCy Schubert 			goto out;
2732b15cb3dSCy Schubert 
2742b15cb3dSCy Schubert 		if (done == 1 &&
2752b15cb3dSCy Schubert 		    evhttp_find_header(evhttp_request_get_input_headers(req),
2762b15cb3dSCy Schubert 			"Content-Type") != NULL)
2772b15cb3dSCy Schubert 			test_ok++;
2782b15cb3dSCy Schubert 
2792b15cb3dSCy Schubert 	 out:
2802b15cb3dSCy Schubert 		evhttp_request_free(req);
2812b15cb3dSCy Schubert 		bufferevent_disable(bev, EV_READ);
2822b15cb3dSCy Schubert 		if (exit_base)
2832b15cb3dSCy Schubert 			event_base_loopexit(exit_base, NULL);
2842b15cb3dSCy Schubert 		else if (my_base)
2852b15cb3dSCy Schubert 			event_base_loopexit(my_base, NULL);
2862b15cb3dSCy Schubert 		else {
2872b15cb3dSCy Schubert 			fprintf(stderr, "No way to exit loop!\n");
2882b15cb3dSCy Schubert 			exit(1);
2892b15cb3dSCy Schubert 		}
2902b15cb3dSCy Schubert 	}
2912b15cb3dSCy Schubert }
2922b15cb3dSCy Schubert 
2932b15cb3dSCy Schubert static void
http_writecb(struct bufferevent * bev,void * arg)2942b15cb3dSCy Schubert http_writecb(struct bufferevent *bev, void *arg)
2952b15cb3dSCy Schubert {
2962b15cb3dSCy Schubert 	if (evbuffer_get_length(bufferevent_get_output(bev)) == 0) {
2972b15cb3dSCy Schubert 		/* enable reading of the reply */
2982b15cb3dSCy Schubert 		bufferevent_enable(bev, EV_READ);
2992b15cb3dSCy Schubert 		test_ok++;
3002b15cb3dSCy Schubert 	}
3012b15cb3dSCy Schubert }
3022b15cb3dSCy Schubert 
3032b15cb3dSCy Schubert static void
http_errorcb(struct bufferevent * bev,short what,void * arg)3042b15cb3dSCy Schubert http_errorcb(struct bufferevent *bev, short what, void *arg)
3052b15cb3dSCy Schubert {
306*a466cc55SCy Schubert 	/** For ssl */
307*a466cc55SCy Schubert 	if (what & BEV_EVENT_CONNECTED)
308*a466cc55SCy Schubert 		return;
3092b15cb3dSCy Schubert 	test_ok = -2;
3102b15cb3dSCy Schubert 	event_base_loopexit(arg, NULL);
3112b15cb3dSCy Schubert }
3122b15cb3dSCy Schubert 
3132b15cb3dSCy Schubert static int found_multi = 0;
3142b15cb3dSCy Schubert static int found_multi2 = 0;
3152b15cb3dSCy Schubert 
3162b15cb3dSCy Schubert static void
http_basic_cb(struct evhttp_request * req,void * arg)3172b15cb3dSCy Schubert http_basic_cb(struct evhttp_request *req, void *arg)
3182b15cb3dSCy Schubert {
3192b15cb3dSCy Schubert 	struct evbuffer *evb = evbuffer_new();
3202b15cb3dSCy Schubert 	struct evhttp_connection *evcon;
3212b15cb3dSCy Schubert 	int empty = evhttp_find_header(evhttp_request_get_input_headers(req), "Empty") != NULL;
322*a466cc55SCy Schubert 
323*a466cc55SCy Schubert 	TT_BLATHER(("%s: called\n", __func__));
3242b15cb3dSCy Schubert 	evbuffer_add_printf(evb, BASIC_REQUEST_BODY);
3252b15cb3dSCy Schubert 
3262b15cb3dSCy Schubert 	evcon = evhttp_request_get_connection(req);
327*a466cc55SCy Schubert 	tt_assert(evhttp_connection_get_server(evcon) == arg);
328*a466cc55SCy Schubert 
329*a466cc55SCy Schubert 	{
330*a466cc55SCy Schubert 		const struct sockaddr *sa;
331*a466cc55SCy Schubert 		char addrbuf[128];
332*a466cc55SCy Schubert 
333*a466cc55SCy Schubert 		sa = evhttp_connection_get_addr(evcon);
334*a466cc55SCy Schubert 		tt_assert(sa);
335*a466cc55SCy Schubert 
336*a466cc55SCy Schubert 		if (sa->sa_family == AF_INET) {
337*a466cc55SCy Schubert 			evutil_format_sockaddr_port_((struct sockaddr *)sa, addrbuf, sizeof(addrbuf));
338*a466cc55SCy Schubert 			tt_assert(!strncmp(addrbuf, "127.0.0.1:", strlen("127.0.0.1:")));
339*a466cc55SCy Schubert 		} else if (sa->sa_family == AF_INET6) {
340*a466cc55SCy Schubert 			evutil_format_sockaddr_port_((struct sockaddr *)sa, addrbuf, sizeof(addrbuf));
341*a466cc55SCy Schubert 			tt_assert(!strncmp(addrbuf, "[::1]:", strlen("[::1]:")));
342*a466cc55SCy Schubert 		} else {
343*a466cc55SCy Schubert 			tt_fail_msg("Unsupported family");
344*a466cc55SCy Schubert 		}
345*a466cc55SCy Schubert 	}
3462b15cb3dSCy Schubert 
3472b15cb3dSCy Schubert 	/* For multi-line headers test */
3482b15cb3dSCy Schubert 	{
3492b15cb3dSCy Schubert 		const char *multi =
3502b15cb3dSCy Schubert 		    evhttp_find_header(evhttp_request_get_input_headers(req),"X-Multi");
3512b15cb3dSCy Schubert 		if (multi) {
3522b15cb3dSCy Schubert 			found_multi = !strcmp(multi,"aaaaaaaa a END");
3532b15cb3dSCy Schubert 			if (strcmp("END", multi + strlen(multi) - 3) == 0)
3542b15cb3dSCy Schubert 				test_ok++;
3552b15cb3dSCy Schubert 			if (evhttp_find_header(evhttp_request_get_input_headers(req), "X-Last"))
3562b15cb3dSCy Schubert 				test_ok++;
3572b15cb3dSCy Schubert 		}
3582b15cb3dSCy Schubert 	}
3592b15cb3dSCy Schubert 	{
3602b15cb3dSCy Schubert 		const char *multi2 =
3612b15cb3dSCy Schubert 		    evhttp_find_header(evhttp_request_get_input_headers(req),"X-Multi-Extra-WS");
3622b15cb3dSCy Schubert 		if (multi2) {
3632b15cb3dSCy Schubert 			found_multi2 = !strcmp(multi2,"libevent 2.1");
3642b15cb3dSCy Schubert 		}
3652b15cb3dSCy Schubert 	}
3662b15cb3dSCy Schubert 
3672b15cb3dSCy Schubert 
3682b15cb3dSCy Schubert 	/* injecting a bad content-length */
3692b15cb3dSCy Schubert 	if (evhttp_find_header(evhttp_request_get_input_headers(req), "X-Negative"))
3702b15cb3dSCy Schubert 		evhttp_add_header(evhttp_request_get_output_headers(req),
3712b15cb3dSCy Schubert 		    "Content-Length", "-100");
3722b15cb3dSCy Schubert 
3732b15cb3dSCy Schubert 	/* allow sending of an empty reply */
3742b15cb3dSCy Schubert 	evhttp_send_reply(req, HTTP_OK, "Everything is fine",
3752b15cb3dSCy Schubert 	    !empty ? evb : NULL);
3762b15cb3dSCy Schubert 
3772b15cb3dSCy Schubert end:
3782b15cb3dSCy Schubert 	evbuffer_free(evb);
3792b15cb3dSCy Schubert }
3802b15cb3dSCy Schubert 
http_timeout_reply_cb(evutil_socket_t fd,short events,void * arg)381*a466cc55SCy Schubert static void http_timeout_reply_cb(evutil_socket_t fd, short events, void *arg)
382*a466cc55SCy Schubert {
383*a466cc55SCy Schubert 	struct evhttp_request *req = arg;
384*a466cc55SCy Schubert 	evhttp_send_reply(req, HTTP_OK, "Everything is fine", NULL);
385*a466cc55SCy Schubert 	test_ok++;
386*a466cc55SCy Schubert }
387*a466cc55SCy Schubert static void
http_timeout_cb(struct evhttp_request * req,void * arg)388*a466cc55SCy Schubert http_timeout_cb(struct evhttp_request *req, void *arg)
389*a466cc55SCy Schubert {
390*a466cc55SCy Schubert 	struct timeval when = { 0, 100 };
391*a466cc55SCy Schubert 	event_base_once(exit_base, -1, EV_TIMEOUT,
392*a466cc55SCy Schubert 	    http_timeout_reply_cb, req, &when);
393*a466cc55SCy Schubert }
394*a466cc55SCy Schubert 
395*a466cc55SCy Schubert static void
http_large_cb(struct evhttp_request * req,void * arg)396*a466cc55SCy Schubert http_large_cb(struct evhttp_request *req, void *arg)
397*a466cc55SCy Schubert {
398*a466cc55SCy Schubert 	struct evbuffer *evb = evbuffer_new();
399*a466cc55SCy Schubert 	int i;
400*a466cc55SCy Schubert 
401*a466cc55SCy Schubert 	for (i = 0; i < 1<<20; ++i) {
402*a466cc55SCy Schubert 		evbuffer_add_printf(evb, BASIC_REQUEST_BODY);
403*a466cc55SCy Schubert 	}
404*a466cc55SCy Schubert 	evhttp_send_reply(req, HTTP_OK, "Everything is fine", evb);
405*a466cc55SCy Schubert 	evbuffer_free(evb);
406*a466cc55SCy Schubert }
407*a466cc55SCy Schubert 
4082b15cb3dSCy Schubert static char const* const CHUNKS[] = {
4092b15cb3dSCy Schubert 	"This is funny",
4102b15cb3dSCy Schubert 	"but not hilarious.",
4112b15cb3dSCy Schubert 	"bwv 1052"
4122b15cb3dSCy Schubert };
4132b15cb3dSCy Schubert 
4142b15cb3dSCy Schubert struct chunk_req_state {
4152b15cb3dSCy Schubert 	struct event_base *base;
4162b15cb3dSCy Schubert 	struct evhttp_request *req;
4172b15cb3dSCy Schubert 	int i;
4182b15cb3dSCy Schubert };
4192b15cb3dSCy Schubert 
4202b15cb3dSCy Schubert static void
http_chunked_trickle_cb(evutil_socket_t fd,short events,void * arg)4212b15cb3dSCy Schubert http_chunked_trickle_cb(evutil_socket_t fd, short events, void *arg)
4222b15cb3dSCy Schubert {
4232b15cb3dSCy Schubert 	struct evbuffer *evb = evbuffer_new();
4242b15cb3dSCy Schubert 	struct chunk_req_state *state = arg;
4252b15cb3dSCy Schubert 	struct timeval when = { 0, 0 };
4262b15cb3dSCy Schubert 
4272b15cb3dSCy Schubert 	evbuffer_add_printf(evb, "%s", CHUNKS[state->i]);
4282b15cb3dSCy Schubert 	evhttp_send_reply_chunk(state->req, evb);
4292b15cb3dSCy Schubert 	evbuffer_free(evb);
4302b15cb3dSCy Schubert 
4312b15cb3dSCy Schubert 	if (++state->i < (int) (sizeof(CHUNKS)/sizeof(CHUNKS[0]))) {
4322b15cb3dSCy Schubert 		event_base_once(state->base, -1, EV_TIMEOUT,
4332b15cb3dSCy Schubert 		    http_chunked_trickle_cb, state, &when);
4342b15cb3dSCy Schubert 	} else {
4352b15cb3dSCy Schubert 		evhttp_send_reply_end(state->req);
4362b15cb3dSCy Schubert 		free(state);
4372b15cb3dSCy Schubert 	}
4382b15cb3dSCy Schubert }
4392b15cb3dSCy Schubert 
4402b15cb3dSCy Schubert static void
http_chunked_cb(struct evhttp_request * req,void * arg)4412b15cb3dSCy Schubert http_chunked_cb(struct evhttp_request *req, void *arg)
4422b15cb3dSCy Schubert {
4432b15cb3dSCy Schubert 	struct timeval when = { 0, 0 };
4442b15cb3dSCy Schubert 	struct chunk_req_state *state = malloc(sizeof(struct chunk_req_state));
445*a466cc55SCy Schubert 	TT_BLATHER(("%s: called\n", __func__));
4462b15cb3dSCy Schubert 
4472b15cb3dSCy Schubert 	memset(state, 0, sizeof(struct chunk_req_state));
4482b15cb3dSCy Schubert 	state->req = req;
4492b15cb3dSCy Schubert 	state->base = arg;
4502b15cb3dSCy Schubert 
4512b15cb3dSCy Schubert 	if (strcmp(evhttp_request_get_uri(req), "/streamed") == 0) {
4522b15cb3dSCy Schubert 		evhttp_add_header(evhttp_request_get_output_headers(req), "Content-Length", "39");
4532b15cb3dSCy Schubert 	}
4542b15cb3dSCy Schubert 
4552b15cb3dSCy Schubert 	/* generate a chunked/streamed reply */
4562b15cb3dSCy Schubert 	evhttp_send_reply_start(req, HTTP_OK, "Everything is fine");
4572b15cb3dSCy Schubert 
4582b15cb3dSCy Schubert 	/* but trickle it across several iterations to ensure we're not
4592b15cb3dSCy Schubert 	 * assuming it comes all at once */
4602b15cb3dSCy Schubert 	event_base_once(arg, -1, EV_TIMEOUT, http_chunked_trickle_cb, state, &when);
4612b15cb3dSCy Schubert }
4622b15cb3dSCy Schubert 
463*a466cc55SCy Schubert static struct bufferevent *
create_bev(struct event_base * base,evutil_socket_t fd,int ssl_mask,int flags_)464*a466cc55SCy Schubert create_bev(struct event_base *base, evutil_socket_t fd, int ssl_mask, int flags_)
4652b15cb3dSCy Schubert {
466*a466cc55SCy Schubert 	int flags = BEV_OPT_DEFER_CALLBACKS | flags_;
467*a466cc55SCy Schubert 	struct bufferevent *bev = NULL;
468*a466cc55SCy Schubert 
469*a466cc55SCy Schubert 	if (!ssl_mask) {
470*a466cc55SCy Schubert 		bev = bufferevent_socket_new(base, fd, flags);
471*a466cc55SCy Schubert 	} else {
472*a466cc55SCy Schubert #ifdef EVENT__HAVE_OPENSSL
473*a466cc55SCy Schubert 		SSL *ssl = SSL_new(get_ssl_ctx());
474*a466cc55SCy Schubert 		if (ssl_mask & HTTP_SSL_FILTER) {
475*a466cc55SCy Schubert 			struct bufferevent *underlying =
476*a466cc55SCy Schubert 				bufferevent_socket_new(base, fd, flags);
477*a466cc55SCy Schubert 			bev = bufferevent_openssl_filter_new(
478*a466cc55SCy Schubert 				base, underlying, ssl, BUFFEREVENT_SSL_CONNECTING, flags);
479*a466cc55SCy Schubert 		} else {
480*a466cc55SCy Schubert 			bev = bufferevent_openssl_socket_new(
481*a466cc55SCy Schubert 				base, fd, ssl, BUFFEREVENT_SSL_CONNECTING, flags);
482*a466cc55SCy Schubert 		}
483*a466cc55SCy Schubert 		bufferevent_openssl_set_allow_dirty_shutdown(bev, 1);
484*a466cc55SCy Schubert #endif
485*a466cc55SCy Schubert 	}
486*a466cc55SCy Schubert 
487*a466cc55SCy Schubert 	return bev;
488*a466cc55SCy Schubert }
489*a466cc55SCy Schubert 
490*a466cc55SCy Schubert static void
http_half_writecb(struct bufferevent * bev,void * arg)491*a466cc55SCy Schubert http_half_writecb(struct bufferevent *bev, void *arg)
492*a466cc55SCy Schubert {
493*a466cc55SCy Schubert 	if (evbuffer_get_length(bufferevent_get_output(bev)) == 0) {
494*a466cc55SCy Schubert 		if (!test_ok) {
495*a466cc55SCy Schubert 			const char http_request[] = "host\r\n"
4962b15cb3dSCy Schubert 				"Connection: close\r\n"
4972b15cb3dSCy Schubert 				"\r\n";
4982b15cb3dSCy Schubert 			bufferevent_write(bev, http_request, strlen(http_request));
4992b15cb3dSCy Schubert 		}
500*a466cc55SCy Schubert 		/* enable reading of the reply */
501*a466cc55SCy Schubert 		bufferevent_enable(bev, EV_READ);
502*a466cc55SCy Schubert 		test_ok++;
503*a466cc55SCy Schubert 	}
504*a466cc55SCy Schubert }
5052b15cb3dSCy Schubert 
5062b15cb3dSCy Schubert static void
http_basic_test_impl(void * arg,int ssl,const char * request_line)507*a466cc55SCy Schubert http_basic_test_impl(void *arg, int ssl, const char *request_line)
5082b15cb3dSCy Schubert {
5092b15cb3dSCy Schubert 	struct basic_test_data *data = arg;
510a25439b6SCy Schubert 	struct bufferevent *bev = NULL;
5112b15cb3dSCy Schubert 	evutil_socket_t fd;
5122b15cb3dSCy Schubert 	const char *http_request;
5132b15cb3dSCy Schubert 	ev_uint16_t port = 0, port2 = 0;
514*a466cc55SCy Schubert 	int server_flags = ssl ? HTTP_BIND_SSL : 0;
515*a466cc55SCy Schubert 	struct evhttp *http = http_setup(&port, data->base, server_flags);
516*a466cc55SCy Schubert 	struct evbuffer *out;
5172b15cb3dSCy Schubert 
518*a466cc55SCy Schubert 	exit_base = data->base;
5192b15cb3dSCy Schubert 
5202b15cb3dSCy Schubert 	/* bind to a second socket */
521*a466cc55SCy Schubert 	if (http_bind(http, &port2, server_flags) == -1) {
5222b15cb3dSCy Schubert 		fprintf(stdout, "FAILED (bind)\n");
5232b15cb3dSCy Schubert 		exit(1);
5242b15cb3dSCy Schubert 	}
5252b15cb3dSCy Schubert 
5262b15cb3dSCy Schubert 	fd = http_connect("127.0.0.1", port);
5272b15cb3dSCy Schubert 
5282b15cb3dSCy Schubert 	/* Stupid thing to send a request */
529*a466cc55SCy Schubert 	bev = create_bev(data->base, fd, ssl, BEV_OPT_CLOSE_ON_FREE);
530*a466cc55SCy Schubert 	bufferevent_setcb(bev, http_readcb, http_half_writecb,
5312b15cb3dSCy Schubert 	    http_errorcb, data->base);
532*a466cc55SCy Schubert 	out = bufferevent_get_output(bev);
5332b15cb3dSCy Schubert 
5342b15cb3dSCy Schubert 	/* first half of the http request */
535*a466cc55SCy Schubert 	evbuffer_add_printf(out,
536*a466cc55SCy Schubert 	    "%s\r\n"
537*a466cc55SCy Schubert 	    "Host: some", request_line);
5382b15cb3dSCy Schubert 
539*a466cc55SCy Schubert 	test_ok = 0;
5402b15cb3dSCy Schubert 	event_base_dispatch(data->base);
541*a466cc55SCy Schubert 	tt_int_op(test_ok, ==, 3);
5422b15cb3dSCy Schubert 
5432b15cb3dSCy Schubert 	/* connect to the second port */
5442b15cb3dSCy Schubert 	bufferevent_free(bev);
5452b15cb3dSCy Schubert 
5462b15cb3dSCy Schubert 	fd = http_connect("127.0.0.1", port2);
5472b15cb3dSCy Schubert 
5482b15cb3dSCy Schubert 	/* Stupid thing to send a request */
549*a466cc55SCy Schubert 	bev = create_bev(data->base, fd, ssl, BEV_OPT_CLOSE_ON_FREE);
5502b15cb3dSCy Schubert 	bufferevent_setcb(bev, http_readcb, http_writecb,
5512b15cb3dSCy Schubert 	    http_errorcb, data->base);
552*a466cc55SCy Schubert 	out = bufferevent_get_output(bev);
5532b15cb3dSCy Schubert 
554*a466cc55SCy Schubert 	evbuffer_add_printf(out,
555*a466cc55SCy Schubert 	    "%s\r\n"
5562b15cb3dSCy Schubert 	    "Host: somehost\r\n"
5572b15cb3dSCy Schubert 	    "Connection: close\r\n"
558*a466cc55SCy Schubert 	    "\r\n", request_line);
5592b15cb3dSCy Schubert 
560*a466cc55SCy Schubert 	test_ok = 0;
5612b15cb3dSCy Schubert 	event_base_dispatch(data->base);
562*a466cc55SCy Schubert 	tt_int_op(test_ok, ==, 2);
5632b15cb3dSCy Schubert 
5642b15cb3dSCy Schubert 	/* Connect to the second port again. This time, send an absolute uri. */
5652b15cb3dSCy Schubert 	bufferevent_free(bev);
5662b15cb3dSCy Schubert 
5672b15cb3dSCy Schubert 	fd = http_connect("127.0.0.1", port2);
5682b15cb3dSCy Schubert 
5692b15cb3dSCy Schubert 	/* Stupid thing to send a request */
570*a466cc55SCy Schubert 	bev = create_bev(data->base, fd, ssl, BEV_OPT_CLOSE_ON_FREE);
5712b15cb3dSCy Schubert 	bufferevent_setcb(bev, http_readcb, http_writecb,
5722b15cb3dSCy Schubert 	    http_errorcb, data->base);
5732b15cb3dSCy Schubert 
5742b15cb3dSCy Schubert 	http_request =
5752b15cb3dSCy Schubert 	    "GET http://somehost.net/test HTTP/1.1\r\n"
5762b15cb3dSCy Schubert 	    "Host: somehost\r\n"
5772b15cb3dSCy Schubert 	    "Connection: close\r\n"
5782b15cb3dSCy Schubert 	    "\r\n";
5792b15cb3dSCy Schubert 
5802b15cb3dSCy Schubert 	bufferevent_write(bev, http_request, strlen(http_request));
5812b15cb3dSCy Schubert 
582*a466cc55SCy Schubert 	test_ok = 0;
5832b15cb3dSCy Schubert 	event_base_dispatch(data->base);
584*a466cc55SCy Schubert 	tt_int_op(test_ok, ==, 2);
5852b15cb3dSCy Schubert 
5862b15cb3dSCy Schubert 	evhttp_free(http);
5872b15cb3dSCy Schubert end:
588a25439b6SCy Schubert 	if (bev)
589a25439b6SCy Schubert 		bufferevent_free(bev);
5902b15cb3dSCy Schubert }
http_basic_test(void * arg)591*a466cc55SCy Schubert static void http_basic_test(void *arg)\
592*a466cc55SCy Schubert { http_basic_test_impl(arg, 0, "GET /test HTTP/1.1"); }
http_basic_trailing_space_test(void * arg)593*a466cc55SCy Schubert static void http_basic_trailing_space_test(void *arg)
594*a466cc55SCy Schubert { http_basic_test_impl(arg, 0, "GET /test HTTP/1.1 "); }
5952b15cb3dSCy Schubert 
5962b15cb3dSCy Schubert 
5972b15cb3dSCy Schubert static void
http_delay_reply(evutil_socket_t fd,short what,void * arg)5982b15cb3dSCy Schubert http_delay_reply(evutil_socket_t fd, short what, void *arg)
5992b15cb3dSCy Schubert {
6002b15cb3dSCy Schubert 	struct evhttp_request *req = arg;
6012b15cb3dSCy Schubert 
6022b15cb3dSCy Schubert 	evhttp_send_reply(req, HTTP_OK, "Everything is fine", NULL);
6032b15cb3dSCy Schubert 
6042b15cb3dSCy Schubert 	++test_ok;
6052b15cb3dSCy Schubert }
6062b15cb3dSCy Schubert 
6072b15cb3dSCy Schubert static void
http_delay_cb(struct evhttp_request * req,void * arg)6082b15cb3dSCy Schubert http_delay_cb(struct evhttp_request *req, void *arg)
6092b15cb3dSCy Schubert {
6102b15cb3dSCy Schubert 	struct timeval tv;
6112b15cb3dSCy Schubert 	evutil_timerclear(&tv);
6122b15cb3dSCy Schubert 	tv.tv_sec = 0;
6132b15cb3dSCy Schubert 	tv.tv_usec = 200 * 1000;
6142b15cb3dSCy Schubert 
6152b15cb3dSCy Schubert 	event_base_once(arg, -1, EV_TIMEOUT, http_delay_reply, req, &tv);
6162b15cb3dSCy Schubert }
6172b15cb3dSCy Schubert 
6182b15cb3dSCy Schubert static void
http_badreq_cb(struct evhttp_request * req,void * arg)6192b15cb3dSCy Schubert http_badreq_cb(struct evhttp_request *req, void *arg)
6202b15cb3dSCy Schubert {
6212b15cb3dSCy Schubert 	struct evbuffer *buf = evbuffer_new();
6222b15cb3dSCy Schubert 
6232b15cb3dSCy Schubert 	evhttp_add_header(evhttp_request_get_output_headers(req), "Content-Type", "text/xml; charset=UTF-8");
6242b15cb3dSCy Schubert 	evbuffer_add_printf(buf, "Hello, %s!", "127.0.0.1");
6252b15cb3dSCy Schubert 
6262b15cb3dSCy Schubert 	evhttp_send_reply(req, HTTP_OK, "OK", buf);
6272b15cb3dSCy Schubert 	evbuffer_free(buf);
6282b15cb3dSCy Schubert }
6292b15cb3dSCy Schubert 
6302b15cb3dSCy Schubert static void
http_badreq_errorcb(struct bufferevent * bev,short what,void * arg)6312b15cb3dSCy Schubert http_badreq_errorcb(struct bufferevent *bev, short what, void *arg)
6322b15cb3dSCy Schubert {
633*a466cc55SCy Schubert 	TT_BLATHER(("%s: called (what=%04x, arg=%p)", __func__, what, arg));
6342b15cb3dSCy Schubert 	/* ignore */
6352b15cb3dSCy Schubert }
6362b15cb3dSCy Schubert 
6372b15cb3dSCy Schubert static void
http_badreq_readcb(struct bufferevent * bev,void * arg)6382b15cb3dSCy Schubert http_badreq_readcb(struct bufferevent *bev, void *arg)
6392b15cb3dSCy Schubert {
6402b15cb3dSCy Schubert 	const char *what = "Hello, 127.0.0.1";
6412b15cb3dSCy Schubert 	const char *bad_request = "400 Bad Request";
6422b15cb3dSCy Schubert 
6432b15cb3dSCy Schubert 	if (evbuffer_contains(bufferevent_get_input(bev), bad_request)) {
6442b15cb3dSCy Schubert 		TT_FAIL(("%s:bad request detected", __func__));
6452b15cb3dSCy Schubert 		bufferevent_disable(bev, EV_READ);
6462b15cb3dSCy Schubert 		event_base_loopexit(arg, NULL);
6472b15cb3dSCy Schubert 		return;
6482b15cb3dSCy Schubert 	}
6492b15cb3dSCy Schubert 
6502b15cb3dSCy Schubert 	if (evbuffer_contains(bufferevent_get_input(bev), what)) {
6512b15cb3dSCy Schubert 		struct evhttp_request *req = evhttp_request_new(NULL, NULL);
6522b15cb3dSCy Schubert 		enum message_read_status done;
6532b15cb3dSCy Schubert 
6542b15cb3dSCy Schubert 		/* req->kind = EVHTTP_RESPONSE; */
6552b15cb3dSCy Schubert 		done = evhttp_parse_firstline_(req, bufferevent_get_input(bev));
6562b15cb3dSCy Schubert 		if (done != ALL_DATA_READ)
6572b15cb3dSCy Schubert 			goto out;
6582b15cb3dSCy Schubert 
6592b15cb3dSCy Schubert 		done = evhttp_parse_headers_(req, bufferevent_get_input(bev));
6602b15cb3dSCy Schubert 		if (done != ALL_DATA_READ)
6612b15cb3dSCy Schubert 			goto out;
6622b15cb3dSCy Schubert 
6632b15cb3dSCy Schubert 		if (done == 1 &&
6642b15cb3dSCy Schubert 		    evhttp_find_header(evhttp_request_get_input_headers(req),
6652b15cb3dSCy Schubert 			"Content-Type") != NULL)
6662b15cb3dSCy Schubert 			test_ok++;
6672b15cb3dSCy Schubert 
6682b15cb3dSCy Schubert 	out:
6692b15cb3dSCy Schubert 		evhttp_request_free(req);
6702b15cb3dSCy Schubert 		evbuffer_drain(bufferevent_get_input(bev), evbuffer_get_length(bufferevent_get_input(bev)));
6712b15cb3dSCy Schubert 	}
6722b15cb3dSCy Schubert 
673*a466cc55SCy Schubert 	shutdown(bufferevent_getfd(bev), EVUTIL_SHUT_WR);
6742b15cb3dSCy Schubert }
6752b15cb3dSCy Schubert 
6762b15cb3dSCy Schubert static void
http_badreq_successcb(evutil_socket_t fd,short what,void * arg)6772b15cb3dSCy Schubert http_badreq_successcb(evutil_socket_t fd, short what, void *arg)
6782b15cb3dSCy Schubert {
679*a466cc55SCy Schubert 	TT_BLATHER(("%s: called (what=%04x, arg=%p)", __func__, what, arg));
6802b15cb3dSCy Schubert 	event_base_loopexit(exit_base, NULL);
6812b15cb3dSCy Schubert }
6822b15cb3dSCy Schubert 
6832b15cb3dSCy Schubert static void
http_bad_request_test(void * arg)6842b15cb3dSCy Schubert http_bad_request_test(void *arg)
6852b15cb3dSCy Schubert {
6862b15cb3dSCy Schubert 	struct basic_test_data *data = arg;
6872b15cb3dSCy Schubert 	struct timeval tv;
6882b15cb3dSCy Schubert 	struct bufferevent *bev = NULL;
689*a466cc55SCy Schubert 	evutil_socket_t fd = EVUTIL_INVALID_SOCKET;
6902b15cb3dSCy Schubert 	const char *http_request;
6912b15cb3dSCy Schubert 	ev_uint16_t port=0, port2=0;
692*a466cc55SCy Schubert 	struct evhttp *http = http_setup(&port, data->base, 0);
6932b15cb3dSCy Schubert 
6942b15cb3dSCy Schubert 	test_ok = 0;
6952b15cb3dSCy Schubert 	exit_base = data->base;
6962b15cb3dSCy Schubert 
6972b15cb3dSCy Schubert 	/* bind to a second socket */
6982b15cb3dSCy Schubert 	if (http_bind(http, &port2, 0) == -1)
6992b15cb3dSCy Schubert 		TT_DIE(("Bind socket failed"));
7002b15cb3dSCy Schubert 
7012b15cb3dSCy Schubert 	/* NULL request test */
7022b15cb3dSCy Schubert 	fd = http_connect("127.0.0.1", port);
703*a466cc55SCy Schubert 	tt_assert(fd != EVUTIL_INVALID_SOCKET);
7042b15cb3dSCy Schubert 
7052b15cb3dSCy Schubert 	/* Stupid thing to send a request */
7062b15cb3dSCy Schubert 	bev = bufferevent_socket_new(data->base, fd, 0);
7072b15cb3dSCy Schubert 	bufferevent_setcb(bev, http_badreq_readcb, http_writecb,
7082b15cb3dSCy Schubert 	    http_badreq_errorcb, data->base);
7092b15cb3dSCy Schubert 	bufferevent_enable(bev, EV_READ);
7102b15cb3dSCy Schubert 
7112b15cb3dSCy Schubert 	/* real NULL request */
7122b15cb3dSCy Schubert 	http_request = "";
7132b15cb3dSCy Schubert 
7142b15cb3dSCy Schubert 	bufferevent_write(bev, http_request, strlen(http_request));
7152b15cb3dSCy Schubert 
716*a466cc55SCy Schubert 	shutdown(fd, EVUTIL_SHUT_WR);
7172b15cb3dSCy Schubert 	timerclear(&tv);
7182b15cb3dSCy Schubert 	tv.tv_usec = 10000;
7192b15cb3dSCy Schubert 	event_base_once(data->base, -1, EV_TIMEOUT, http_badreq_successcb, bev, &tv);
7202b15cb3dSCy Schubert 
7212b15cb3dSCy Schubert 	event_base_dispatch(data->base);
7222b15cb3dSCy Schubert 
7232b15cb3dSCy Schubert 	bufferevent_free(bev);
7242b15cb3dSCy Schubert 	evutil_closesocket(fd);
7252b15cb3dSCy Schubert 
7262b15cb3dSCy Schubert 	if (test_ok != 0) {
7272b15cb3dSCy Schubert 		fprintf(stdout, "FAILED\n");
7282b15cb3dSCy Schubert 		exit(1);
7292b15cb3dSCy Schubert 	}
7302b15cb3dSCy Schubert 
7312b15cb3dSCy Schubert 	/* Second answer (BAD REQUEST) on connection close */
7322b15cb3dSCy Schubert 
7332b15cb3dSCy Schubert 	/* connect to the second port */
7342b15cb3dSCy Schubert 	fd = http_connect("127.0.0.1", port2);
735*a466cc55SCy Schubert 	tt_assert(fd != EVUTIL_INVALID_SOCKET);
7362b15cb3dSCy Schubert 
7372b15cb3dSCy Schubert 	/* Stupid thing to send a request */
7382b15cb3dSCy Schubert 	bev = bufferevent_socket_new(data->base, fd, 0);
7392b15cb3dSCy Schubert 	bufferevent_setcb(bev, http_badreq_readcb, http_writecb,
7402b15cb3dSCy Schubert 	    http_badreq_errorcb, data->base);
7412b15cb3dSCy Schubert 	bufferevent_enable(bev, EV_READ);
7422b15cb3dSCy Schubert 
7432b15cb3dSCy Schubert 	/* first half of the http request */
7442b15cb3dSCy Schubert 	http_request =
7452b15cb3dSCy Schubert 		"GET /badrequest HTTP/1.0\r\n"	\
7462b15cb3dSCy Schubert 		"Connection: Keep-Alive\r\n"	\
7472b15cb3dSCy Schubert 		"\r\n";
7482b15cb3dSCy Schubert 
7492b15cb3dSCy Schubert 	bufferevent_write(bev, http_request, strlen(http_request));
7502b15cb3dSCy Schubert 
7512b15cb3dSCy Schubert 	timerclear(&tv);
7522b15cb3dSCy Schubert 	tv.tv_usec = 10000;
7532b15cb3dSCy Schubert 	event_base_once(data->base, -1, EV_TIMEOUT, http_badreq_successcb, bev, &tv);
7542b15cb3dSCy Schubert 
7552b15cb3dSCy Schubert 	event_base_dispatch(data->base);
7562b15cb3dSCy Schubert 
7572b15cb3dSCy Schubert 	tt_int_op(test_ok, ==, 2);
7582b15cb3dSCy Schubert 
7592b15cb3dSCy Schubert end:
7602b15cb3dSCy Schubert 	evhttp_free(http);
7612b15cb3dSCy Schubert 	if (bev)
7622b15cb3dSCy Schubert 		bufferevent_free(bev);
7632b15cb3dSCy Schubert 	if (fd >= 0)
7642b15cb3dSCy Schubert 		evutil_closesocket(fd);
7652b15cb3dSCy Schubert }
7662b15cb3dSCy Schubert 
7672b15cb3dSCy Schubert static struct evhttp_connection *delayed_client;
7682b15cb3dSCy Schubert 
7692b15cb3dSCy Schubert static void
http_large_delay_cb(struct evhttp_request * req,void * arg)7702b15cb3dSCy Schubert http_large_delay_cb(struct evhttp_request *req, void *arg)
7712b15cb3dSCy Schubert {
7722b15cb3dSCy Schubert 	struct timeval tv;
7732b15cb3dSCy Schubert 	evutil_timerclear(&tv);
7742b15cb3dSCy Schubert 	tv.tv_usec = 500000;
7752b15cb3dSCy Schubert 
7762b15cb3dSCy Schubert 	event_base_once(arg, -1, EV_TIMEOUT, http_delay_reply, req, &tv);
7772b15cb3dSCy Schubert 	evhttp_connection_fail_(delayed_client, EVREQ_HTTP_EOF);
7782b15cb3dSCy Schubert }
7792b15cb3dSCy Schubert 
7802b15cb3dSCy Schubert /*
7812b15cb3dSCy Schubert  * HTTP DELETE test,  just piggyback on the basic test
7822b15cb3dSCy Schubert  */
7832b15cb3dSCy Schubert 
7842b15cb3dSCy Schubert static void
http_delete_cb(struct evhttp_request * req,void * arg)7852b15cb3dSCy Schubert http_delete_cb(struct evhttp_request *req, void *arg)
7862b15cb3dSCy Schubert {
7872b15cb3dSCy Schubert 	struct evbuffer *evb = evbuffer_new();
7882b15cb3dSCy Schubert 	int empty = evhttp_find_header(evhttp_request_get_input_headers(req), "Empty") != NULL;
7892b15cb3dSCy Schubert 
7902b15cb3dSCy Schubert 	/* Expecting a DELETE request */
7912b15cb3dSCy Schubert 	if (evhttp_request_get_command(req) != EVHTTP_REQ_DELETE) {
7922b15cb3dSCy Schubert 		fprintf(stdout, "FAILED (delete type)\n");
7932b15cb3dSCy Schubert 		exit(1);
7942b15cb3dSCy Schubert 	}
7952b15cb3dSCy Schubert 
796*a466cc55SCy Schubert 	TT_BLATHER(("%s: called\n", __func__));
7972b15cb3dSCy Schubert 	evbuffer_add_printf(evb, BASIC_REQUEST_BODY);
7982b15cb3dSCy Schubert 
7992b15cb3dSCy Schubert 	/* allow sending of an empty reply */
8002b15cb3dSCy Schubert 	evhttp_send_reply(req, HTTP_OK, "Everything is fine",
8012b15cb3dSCy Schubert 	    !empty ? evb : NULL);
8022b15cb3dSCy Schubert 
8032b15cb3dSCy Schubert 	evbuffer_free(evb);
8042b15cb3dSCy Schubert }
8052b15cb3dSCy Schubert 
8062b15cb3dSCy Schubert static void
http_delete_test(void * arg)8072b15cb3dSCy Schubert http_delete_test(void *arg)
8082b15cb3dSCy Schubert {
8092b15cb3dSCy Schubert 	struct basic_test_data *data = arg;
8102b15cb3dSCy Schubert 	struct bufferevent *bev;
811*a466cc55SCy Schubert 	evutil_socket_t fd = EVUTIL_INVALID_SOCKET;
8122b15cb3dSCy Schubert 	const char *http_request;
8132b15cb3dSCy Schubert 	ev_uint16_t port = 0;
814*a466cc55SCy Schubert 	struct evhttp *http = http_setup(&port, data->base, 0);
8152b15cb3dSCy Schubert 
816*a466cc55SCy Schubert 	exit_base = data->base;
8172b15cb3dSCy Schubert 	test_ok = 0;
8182b15cb3dSCy Schubert 
819a25439b6SCy Schubert 	tt_assert(http);
8202b15cb3dSCy Schubert 	fd = http_connect("127.0.0.1", port);
821*a466cc55SCy Schubert 	tt_assert(fd != EVUTIL_INVALID_SOCKET);
8222b15cb3dSCy Schubert 
8232b15cb3dSCy Schubert 	/* Stupid thing to send a request */
8242b15cb3dSCy Schubert 	bev = bufferevent_socket_new(data->base, fd, 0);
8252b15cb3dSCy Schubert 	bufferevent_setcb(bev, http_readcb, http_writecb,
8262b15cb3dSCy Schubert 	    http_errorcb, data->base);
8272b15cb3dSCy Schubert 
8282b15cb3dSCy Schubert 	http_request =
8292b15cb3dSCy Schubert 	    "DELETE /deleteit HTTP/1.1\r\n"
8302b15cb3dSCy Schubert 	    "Host: somehost\r\n"
8312b15cb3dSCy Schubert 	    "Connection: close\r\n"
8322b15cb3dSCy Schubert 	    "\r\n";
8332b15cb3dSCy Schubert 
8342b15cb3dSCy Schubert 	bufferevent_write(bev, http_request, strlen(http_request));
8352b15cb3dSCy Schubert 
8362b15cb3dSCy Schubert 	event_base_dispatch(data->base);
8372b15cb3dSCy Schubert 
8382b15cb3dSCy Schubert 	bufferevent_free(bev);
8392b15cb3dSCy Schubert 	evutil_closesocket(fd);
840*a466cc55SCy Schubert 	fd = EVUTIL_INVALID_SOCKET;
8412b15cb3dSCy Schubert 
8422b15cb3dSCy Schubert 	evhttp_free(http);
8432b15cb3dSCy Schubert 
8442b15cb3dSCy Schubert 	tt_int_op(test_ok, ==, 2);
8452b15cb3dSCy Schubert  end:
8462b15cb3dSCy Schubert 	if (fd >= 0)
8472b15cb3dSCy Schubert 		evutil_closesocket(fd);
8482b15cb3dSCy Schubert }
8492b15cb3dSCy Schubert 
8502b15cb3dSCy Schubert static void
http_sent_cb(struct evhttp_request * req,void * arg)8512b15cb3dSCy Schubert http_sent_cb(struct evhttp_request *req, void *arg)
8522b15cb3dSCy Schubert {
8532b15cb3dSCy Schubert 	ev_uintptr_t val = (ev_uintptr_t)arg;
8542b15cb3dSCy Schubert 	struct evbuffer *b;
8552b15cb3dSCy Schubert 
8562b15cb3dSCy Schubert 	if (val != 0xDEADBEEF) {
8572b15cb3dSCy Schubert 		fprintf(stdout, "FAILED on_complete_cb argument\n");
8582b15cb3dSCy Schubert 		exit(1);
8592b15cb3dSCy Schubert 	}
8602b15cb3dSCy Schubert 
8612b15cb3dSCy Schubert 	b = evhttp_request_get_output_buffer(req);
8622b15cb3dSCy Schubert 	if (evbuffer_get_length(b) != 0) {
8632b15cb3dSCy Schubert 		fprintf(stdout, "FAILED on_complete_cb output buffer not written\n");
8642b15cb3dSCy Schubert 		exit(1);
8652b15cb3dSCy Schubert 	}
8662b15cb3dSCy Schubert 
867*a466cc55SCy Schubert 	TT_BLATHER(("%s: called\n", __func__));
8682b15cb3dSCy Schubert 
8692b15cb3dSCy Schubert 	++test_ok;
8702b15cb3dSCy Schubert }
8712b15cb3dSCy Schubert 
8722b15cb3dSCy Schubert static void
http_on_complete_cb(struct evhttp_request * req,void * arg)8732b15cb3dSCy Schubert http_on_complete_cb(struct evhttp_request *req, void *arg)
8742b15cb3dSCy Schubert {
8752b15cb3dSCy Schubert 	struct evbuffer *evb = evbuffer_new();
8762b15cb3dSCy Schubert 
8772b15cb3dSCy Schubert 	evhttp_request_set_on_complete_cb(req, http_sent_cb, (void *)0xDEADBEEF);
8782b15cb3dSCy Schubert 
879*a466cc55SCy Schubert 	TT_BLATHER(("%s: called\n", __func__));
8802b15cb3dSCy Schubert 	evbuffer_add_printf(evb, BASIC_REQUEST_BODY);
8812b15cb3dSCy Schubert 
8822b15cb3dSCy Schubert 	/* allow sending of an empty reply */
8832b15cb3dSCy Schubert 	evhttp_send_reply(req, HTTP_OK, "Everything is fine", evb);
8842b15cb3dSCy Schubert 
8852b15cb3dSCy Schubert 	evbuffer_free(evb);
8862b15cb3dSCy Schubert 
8872b15cb3dSCy Schubert 	++test_ok;
8882b15cb3dSCy Schubert }
8892b15cb3dSCy Schubert 
8902b15cb3dSCy Schubert static void
http_on_complete_test(void * arg)8912b15cb3dSCy Schubert http_on_complete_test(void *arg)
8922b15cb3dSCy Schubert {
8932b15cb3dSCy Schubert 	struct basic_test_data *data = arg;
8942b15cb3dSCy Schubert 	struct bufferevent *bev;
895*a466cc55SCy Schubert 	evutil_socket_t fd = EVUTIL_INVALID_SOCKET;
8962b15cb3dSCy Schubert 	const char *http_request;
8972b15cb3dSCy Schubert 	ev_uint16_t port = 0;
898*a466cc55SCy Schubert 	struct evhttp *http = http_setup(&port, data->base, 0);
8992b15cb3dSCy Schubert 
900*a466cc55SCy Schubert 	exit_base = data->base;
9012b15cb3dSCy Schubert 	test_ok = 0;
9022b15cb3dSCy Schubert 
9032b15cb3dSCy Schubert 	fd = http_connect("127.0.0.1", port);
904*a466cc55SCy Schubert 	tt_assert(fd != EVUTIL_INVALID_SOCKET);
9052b15cb3dSCy Schubert 
9062b15cb3dSCy Schubert 	/* Stupid thing to send a request */
9072b15cb3dSCy Schubert 	bev = bufferevent_socket_new(data->base, fd, 0);
9082b15cb3dSCy Schubert 	bufferevent_setcb(bev, http_readcb, http_writecb,
9092b15cb3dSCy Schubert 	    http_errorcb, data->base);
9102b15cb3dSCy Schubert 
9112b15cb3dSCy Schubert 	http_request =
9122b15cb3dSCy Schubert 	    "GET /oncomplete HTTP/1.1\r\n"
9132b15cb3dSCy Schubert 	    "Host: somehost\r\n"
9142b15cb3dSCy Schubert 	    "Connection: close\r\n"
9152b15cb3dSCy Schubert 	    "\r\n";
9162b15cb3dSCy Schubert 
9172b15cb3dSCy Schubert 	bufferevent_write(bev, http_request, strlen(http_request));
9182b15cb3dSCy Schubert 
9192b15cb3dSCy Schubert 	event_base_dispatch(data->base);
9202b15cb3dSCy Schubert 
9212b15cb3dSCy Schubert 	bufferevent_free(bev);
9222b15cb3dSCy Schubert 
9232b15cb3dSCy Schubert 	evhttp_free(http);
9242b15cb3dSCy Schubert 
9252b15cb3dSCy Schubert 	tt_int_op(test_ok, ==, 4);
9262b15cb3dSCy Schubert  end:
9272b15cb3dSCy Schubert 	if (fd >= 0)
9282b15cb3dSCy Schubert 		evutil_closesocket(fd);
9292b15cb3dSCy Schubert }
9302b15cb3dSCy Schubert 
9312b15cb3dSCy Schubert static void
http_allowed_methods_eventcb(struct bufferevent * bev,short what,void * arg)9322b15cb3dSCy Schubert http_allowed_methods_eventcb(struct bufferevent *bev, short what, void *arg)
9332b15cb3dSCy Schubert {
9342b15cb3dSCy Schubert 	char **output = arg;
9352b15cb3dSCy Schubert 	if ((what & (BEV_EVENT_ERROR|BEV_EVENT_EOF))) {
9362b15cb3dSCy Schubert 		char buf[4096];
9372b15cb3dSCy Schubert 		int n;
9382b15cb3dSCy Schubert 		n = evbuffer_remove(bufferevent_get_input(bev), buf,
9392b15cb3dSCy Schubert 		    sizeof(buf)-1);
9402b15cb3dSCy Schubert 		if (n >= 0) {
9412b15cb3dSCy Schubert 			buf[n]='\0';
9422b15cb3dSCy Schubert 			if (*output)
9432b15cb3dSCy Schubert 				free(*output);
9442b15cb3dSCy Schubert 			*output = strdup(buf);
9452b15cb3dSCy Schubert 		}
9462b15cb3dSCy Schubert 		event_base_loopexit(exit_base, NULL);
9472b15cb3dSCy Schubert 	}
9482b15cb3dSCy Schubert }
9492b15cb3dSCy Schubert 
9502b15cb3dSCy Schubert static void
http_allowed_methods_test(void * arg)9512b15cb3dSCy Schubert http_allowed_methods_test(void *arg)
9522b15cb3dSCy Schubert {
9532b15cb3dSCy Schubert 	struct basic_test_data *data = arg;
9542b15cb3dSCy Schubert 	struct bufferevent *bev1, *bev2, *bev3;
9552b15cb3dSCy Schubert 	evutil_socket_t fd1=-1, fd2=-1, fd3=-1;
9562b15cb3dSCy Schubert 	const char *http_request;
9572b15cb3dSCy Schubert 	char *result1=NULL, *result2=NULL, *result3=NULL;
9582b15cb3dSCy Schubert 	ev_uint16_t port = 0;
959*a466cc55SCy Schubert 	struct evhttp *http = http_setup(&port, data->base, 0);
9602b15cb3dSCy Schubert 
9612b15cb3dSCy Schubert 	exit_base = data->base;
9622b15cb3dSCy Schubert 	test_ok = 0;
9632b15cb3dSCy Schubert 
9642b15cb3dSCy Schubert 	fd1 = http_connect("127.0.0.1", port);
965*a466cc55SCy Schubert 	tt_assert(fd1 != EVUTIL_INVALID_SOCKET);
9662b15cb3dSCy Schubert 
9672b15cb3dSCy Schubert 	/* GET is out; PATCH is in. */
9682b15cb3dSCy Schubert 	evhttp_set_allowed_methods(http, EVHTTP_REQ_PATCH);
9692b15cb3dSCy Schubert 
9702b15cb3dSCy Schubert 	/* Stupid thing to send a request */
9712b15cb3dSCy Schubert 	bev1 = bufferevent_socket_new(data->base, fd1, 0);
9722b15cb3dSCy Schubert 	bufferevent_enable(bev1, EV_READ|EV_WRITE);
9732b15cb3dSCy Schubert 	bufferevent_setcb(bev1, NULL, NULL,
9742b15cb3dSCy Schubert 	    http_allowed_methods_eventcb, &result1);
9752b15cb3dSCy Schubert 
9762b15cb3dSCy Schubert 	http_request =
9772b15cb3dSCy Schubert 	    "GET /index.html HTTP/1.1\r\n"
9782b15cb3dSCy Schubert 	    "Host: somehost\r\n"
9792b15cb3dSCy Schubert 	    "Connection: close\r\n"
9802b15cb3dSCy Schubert 	    "\r\n";
9812b15cb3dSCy Schubert 
9822b15cb3dSCy Schubert 	bufferevent_write(bev1, http_request, strlen(http_request));
9832b15cb3dSCy Schubert 
9842b15cb3dSCy Schubert 	event_base_dispatch(data->base);
9852b15cb3dSCy Schubert 
9862b15cb3dSCy Schubert 	fd2 = http_connect("127.0.0.1", port);
987*a466cc55SCy Schubert 	tt_assert(fd2 != EVUTIL_INVALID_SOCKET);
9882b15cb3dSCy Schubert 
9892b15cb3dSCy Schubert 	bev2 = bufferevent_socket_new(data->base, fd2, 0);
9902b15cb3dSCy Schubert 	bufferevent_enable(bev2, EV_READ|EV_WRITE);
9912b15cb3dSCy Schubert 	bufferevent_setcb(bev2, NULL, NULL,
9922b15cb3dSCy Schubert 	    http_allowed_methods_eventcb, &result2);
9932b15cb3dSCy Schubert 
9942b15cb3dSCy Schubert 	http_request =
9952b15cb3dSCy Schubert 	    "PATCH /test HTTP/1.1\r\n"
9962b15cb3dSCy Schubert 	    "Host: somehost\r\n"
9972b15cb3dSCy Schubert 	    "Connection: close\r\n"
9982b15cb3dSCy Schubert 	    "\r\n";
9992b15cb3dSCy Schubert 
10002b15cb3dSCy Schubert 	bufferevent_write(bev2, http_request, strlen(http_request));
10012b15cb3dSCy Schubert 
10022b15cb3dSCy Schubert 	event_base_dispatch(data->base);
10032b15cb3dSCy Schubert 
10042b15cb3dSCy Schubert 	fd3 = http_connect("127.0.0.1", port);
1005*a466cc55SCy Schubert 	tt_assert(fd3 != EVUTIL_INVALID_SOCKET);
10062b15cb3dSCy Schubert 
10072b15cb3dSCy Schubert 	bev3 = bufferevent_socket_new(data->base, fd3, 0);
10082b15cb3dSCy Schubert 	bufferevent_enable(bev3, EV_READ|EV_WRITE);
10092b15cb3dSCy Schubert 	bufferevent_setcb(bev3, NULL, NULL,
10102b15cb3dSCy Schubert 	    http_allowed_methods_eventcb, &result3);
10112b15cb3dSCy Schubert 
10122b15cb3dSCy Schubert 	http_request =
10132b15cb3dSCy Schubert 	    "FLOOP /test HTTP/1.1\r\n"
10142b15cb3dSCy Schubert 	    "Host: somehost\r\n"
10152b15cb3dSCy Schubert 	    "Connection: close\r\n"
10162b15cb3dSCy Schubert 	    "\r\n";
10172b15cb3dSCy Schubert 
10182b15cb3dSCy Schubert 	bufferevent_write(bev3, http_request, strlen(http_request));
10192b15cb3dSCy Schubert 
10202b15cb3dSCy Schubert 	event_base_dispatch(data->base);
10212b15cb3dSCy Schubert 
10222b15cb3dSCy Schubert 	bufferevent_free(bev1);
10232b15cb3dSCy Schubert 	bufferevent_free(bev2);
10242b15cb3dSCy Schubert 	bufferevent_free(bev3);
10252b15cb3dSCy Schubert 
10262b15cb3dSCy Schubert 	evhttp_free(http);
10272b15cb3dSCy Schubert 
10282b15cb3dSCy Schubert 	/* Method known but disallowed */
10292b15cb3dSCy Schubert 	tt_assert(result1);
10302b15cb3dSCy Schubert 	tt_assert(!strncmp(result1, "HTTP/1.1 501 ", strlen("HTTP/1.1 501 ")));
10312b15cb3dSCy Schubert 
10322b15cb3dSCy Schubert 	/* Method known and allowed */
10332b15cb3dSCy Schubert 	tt_assert(result2);
10342b15cb3dSCy Schubert 	tt_assert(!strncmp(result2, "HTTP/1.1 200 ", strlen("HTTP/1.1 200 ")));
10352b15cb3dSCy Schubert 
10362b15cb3dSCy Schubert 	/* Method unknown */
10372b15cb3dSCy Schubert 	tt_assert(result3);
10382b15cb3dSCy Schubert 	tt_assert(!strncmp(result3, "HTTP/1.1 501 ", strlen("HTTP/1.1 501 ")));
10392b15cb3dSCy Schubert 
10402b15cb3dSCy Schubert  end:
10412b15cb3dSCy Schubert 	if (result1)
10422b15cb3dSCy Schubert 		free(result1);
10432b15cb3dSCy Schubert 	if (result2)
10442b15cb3dSCy Schubert 		free(result2);
10452b15cb3dSCy Schubert 	if (result3)
10462b15cb3dSCy Schubert 		free(result3);
10472b15cb3dSCy Schubert 	if (fd1 >= 0)
10482b15cb3dSCy Schubert 		evutil_closesocket(fd1);
10492b15cb3dSCy Schubert 	if (fd2 >= 0)
10502b15cb3dSCy Schubert 		evutil_closesocket(fd2);
10512b15cb3dSCy Schubert 	if (fd3 >= 0)
10522b15cb3dSCy Schubert 		evutil_closesocket(fd3);
10532b15cb3dSCy Schubert }
10542b15cb3dSCy Schubert 
1055*a466cc55SCy Schubert static void http_request_no_action_done(struct evhttp_request *, void *);
10562b15cb3dSCy Schubert static void http_request_done(struct evhttp_request *, void *);
10572b15cb3dSCy Schubert static void http_request_empty_done(struct evhttp_request *, void *);
10582b15cb3dSCy Schubert 
10592b15cb3dSCy Schubert static void
http_connection_test_(struct basic_test_data * data,int persistent,const char * address,struct evdns_base * dnsbase,int ipv6,int family,int ssl)1060a25439b6SCy Schubert http_connection_test_(struct basic_test_data *data, int persistent,
1061*a466cc55SCy Schubert 	const char *address, struct evdns_base *dnsbase, int ipv6, int family,
1062*a466cc55SCy Schubert 	int ssl)
10632b15cb3dSCy Schubert {
10642b15cb3dSCy Schubert 	ev_uint16_t port = 0;
10652b15cb3dSCy Schubert 	struct evhttp_connection *evcon = NULL;
10662b15cb3dSCy Schubert 	struct evhttp_request *req = NULL;
1067*a466cc55SCy Schubert 	struct evhttp *http;
1068*a466cc55SCy Schubert 
1069*a466cc55SCy Schubert 	int mask = 0;
1070*a466cc55SCy Schubert 	if (ipv6)
1071*a466cc55SCy Schubert 		mask |= HTTP_BIND_IPV6;
1072*a466cc55SCy Schubert 	if (ssl)
1073*a466cc55SCy Schubert 		mask |= HTTP_BIND_SSL;
1074*a466cc55SCy Schubert 
1075*a466cc55SCy Schubert 	http = http_setup(&port, data->base, mask);
10762b15cb3dSCy Schubert 
10772b15cb3dSCy Schubert 	test_ok = 0;
1078a25439b6SCy Schubert 	if (!http && ipv6) {
1079a25439b6SCy Schubert 		tt_skip();
1080a25439b6SCy Schubert 	}
1081a25439b6SCy Schubert 	tt_assert(http);
10822b15cb3dSCy Schubert 
1083*a466cc55SCy Schubert 	if (ssl) {
1084*a466cc55SCy Schubert #ifdef EVENT__HAVE_OPENSSL
1085*a466cc55SCy Schubert 		SSL *ssl = SSL_new(get_ssl_ctx());
1086*a466cc55SCy Schubert 		struct bufferevent *bev = bufferevent_openssl_socket_new(
1087*a466cc55SCy Schubert 			data->base, -1, ssl,
1088*a466cc55SCy Schubert 			BUFFEREVENT_SSL_CONNECTING, BEV_OPT_DEFER_CALLBACKS);
1089*a466cc55SCy Schubert 		bufferevent_openssl_set_allow_dirty_shutdown(bev, 1);
1090*a466cc55SCy Schubert 
1091*a466cc55SCy Schubert 		evcon = evhttp_connection_base_bufferevent_new(data->base, dnsbase, bev, address, port);
1092*a466cc55SCy Schubert #else
1093*a466cc55SCy Schubert 		tt_skip();
1094*a466cc55SCy Schubert #endif
1095*a466cc55SCy Schubert 	} else {
10962b15cb3dSCy Schubert 		evcon = evhttp_connection_base_new(data->base, dnsbase, address, port);
1097*a466cc55SCy Schubert 	}
10982b15cb3dSCy Schubert 	tt_assert(evcon);
1099a25439b6SCy Schubert 	evhttp_connection_set_family(evcon, family);
11002b15cb3dSCy Schubert 
11012b15cb3dSCy Schubert 	tt_assert(evhttp_connection_get_base(evcon) == data->base);
11022b15cb3dSCy Schubert 
11032b15cb3dSCy Schubert 	exit_base = data->base;
11042b15cb3dSCy Schubert 
11052b15cb3dSCy Schubert 	tt_assert(evhttp_connection_get_server(evcon) == NULL);
11062b15cb3dSCy Schubert 
11072b15cb3dSCy Schubert 	/*
11082b15cb3dSCy Schubert 	 * At this point, we want to schedule a request to the HTTP
11092b15cb3dSCy Schubert 	 * server using our make request method.
11102b15cb3dSCy Schubert 	 */
11112b15cb3dSCy Schubert 	req = evhttp_request_new(http_request_done, (void*) BASIC_REQUEST_BODY);
11122b15cb3dSCy Schubert 
11132b15cb3dSCy Schubert 	/* Add the information that we care about */
11142b15cb3dSCy Schubert 	evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
11152b15cb3dSCy Schubert 
11162b15cb3dSCy Schubert 	/* We give ownership of the request to the connection */
11172b15cb3dSCy Schubert 	if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test") == -1) {
11182b15cb3dSCy Schubert 		fprintf(stdout, "FAILED\n");
11192b15cb3dSCy Schubert 		exit(1);
11202b15cb3dSCy Schubert 	}
11212b15cb3dSCy Schubert 
11222b15cb3dSCy Schubert 	event_base_dispatch(data->base);
11232b15cb3dSCy Schubert 
11242b15cb3dSCy Schubert 	tt_assert(test_ok);
11252b15cb3dSCy Schubert 
11262b15cb3dSCy Schubert 	/* try to make another request over the same connection */
11272b15cb3dSCy Schubert 	test_ok = 0;
11282b15cb3dSCy Schubert 
11292b15cb3dSCy Schubert 	req = evhttp_request_new(http_request_done, (void*) BASIC_REQUEST_BODY);
11302b15cb3dSCy Schubert 
11312b15cb3dSCy Schubert 	/* Add the information that we care about */
11322b15cb3dSCy Schubert 	evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
11332b15cb3dSCy Schubert 
11342b15cb3dSCy Schubert 	/*
11352b15cb3dSCy Schubert 	 * if our connections are not supposed to be persistent; request
11362b15cb3dSCy Schubert 	 * a close from the server.
11372b15cb3dSCy Schubert 	 */
11382b15cb3dSCy Schubert 	if (!persistent)
11392b15cb3dSCy Schubert 		evhttp_add_header(evhttp_request_get_output_headers(req), "Connection", "close");
11402b15cb3dSCy Schubert 
11412b15cb3dSCy Schubert 	/* We give ownership of the request to the connection */
11422b15cb3dSCy Schubert 	if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test") == -1) {
11432b15cb3dSCy Schubert 		tt_abort_msg("couldn't make request");
11442b15cb3dSCy Schubert 	}
11452b15cb3dSCy Schubert 
11462b15cb3dSCy Schubert 	event_base_dispatch(data->base);
11472b15cb3dSCy Schubert 
11482b15cb3dSCy Schubert 	/* make another request: request empty reply */
11492b15cb3dSCy Schubert 	test_ok = 0;
11502b15cb3dSCy Schubert 
11512b15cb3dSCy Schubert 	req = evhttp_request_new(http_request_empty_done, data->base);
11522b15cb3dSCy Schubert 
11532b15cb3dSCy Schubert 	/* Add the information that we care about */
11542b15cb3dSCy Schubert 	evhttp_add_header(evhttp_request_get_output_headers(req), "Empty", "itis");
11552b15cb3dSCy Schubert 
11562b15cb3dSCy Schubert 	/* We give ownership of the request to the connection */
11572b15cb3dSCy Schubert 	if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test") == -1) {
11582b15cb3dSCy Schubert 		tt_abort_msg("Couldn't make request");
11592b15cb3dSCy Schubert 	}
11602b15cb3dSCy Schubert 
11612b15cb3dSCy Schubert 	event_base_dispatch(data->base);
11622b15cb3dSCy Schubert 
11632b15cb3dSCy Schubert  end:
11642b15cb3dSCy Schubert 	if (evcon)
11652b15cb3dSCy Schubert 		evhttp_connection_free(evcon);
11662b15cb3dSCy Schubert 	if (http)
11672b15cb3dSCy Schubert 		evhttp_free(http);
11682b15cb3dSCy Schubert }
11692b15cb3dSCy Schubert 
11702b15cb3dSCy Schubert static void
http_connection_test(void * arg)11712b15cb3dSCy Schubert http_connection_test(void *arg)
11722b15cb3dSCy Schubert {
1173*a466cc55SCy Schubert 	http_connection_test_(arg, 0, "127.0.0.1", NULL, 0, AF_UNSPEC, 0);
11742b15cb3dSCy Schubert }
11752b15cb3dSCy Schubert static void
http_persist_connection_test(void * arg)11762b15cb3dSCy Schubert http_persist_connection_test(void *arg)
11772b15cb3dSCy Schubert {
1178*a466cc55SCy Schubert 	http_connection_test_(arg, 1, "127.0.0.1", NULL, 0, AF_UNSPEC, 0);
11792b15cb3dSCy Schubert }
11802b15cb3dSCy Schubert 
11812b15cb3dSCy Schubert static struct regress_dns_server_table search_table[] = {
1182*a466cc55SCy Schubert 	{ "localhost", "A", "127.0.0.1", 0, 0 },
1183*a466cc55SCy Schubert 	{ NULL, NULL, NULL, 0, 0 }
11842b15cb3dSCy Schubert };
11852b15cb3dSCy Schubert 
11862b15cb3dSCy Schubert static void
http_connection_async_test(void * arg)11872b15cb3dSCy Schubert http_connection_async_test(void *arg)
11882b15cb3dSCy Schubert {
11892b15cb3dSCy Schubert 	struct basic_test_data *data = arg;
11902b15cb3dSCy Schubert 	ev_uint16_t port = 0;
11912b15cb3dSCy Schubert 	struct evhttp_connection *evcon = NULL;
11922b15cb3dSCy Schubert 	struct evhttp_request *req = NULL;
11932b15cb3dSCy Schubert 	struct evdns_base *dns_base = NULL;
11942b15cb3dSCy Schubert 	ev_uint16_t portnum = 0;
11952b15cb3dSCy Schubert 	char address[64];
1196*a466cc55SCy Schubert 	struct evhttp *http = http_setup(&port, data->base, 0);
11972b15cb3dSCy Schubert 
11982b15cb3dSCy Schubert 	exit_base = data->base;
11992b15cb3dSCy Schubert 	tt_assert(regress_dnsserver(data->base, &portnum, search_table));
12002b15cb3dSCy Schubert 
12012b15cb3dSCy Schubert 	dns_base = evdns_base_new(data->base, 0/* init name servers */);
12022b15cb3dSCy Schubert 	tt_assert(dns_base);
12032b15cb3dSCy Schubert 
12042b15cb3dSCy Schubert 	/* Add ourself as the only nameserver, and make sure we really are
12052b15cb3dSCy Schubert 	 * the only nameserver. */
12062b15cb3dSCy Schubert 	evutil_snprintf(address, sizeof(address), "127.0.0.1:%d", portnum);
12072b15cb3dSCy Schubert 	evdns_base_nameserver_ip_add(dns_base, address);
12082b15cb3dSCy Schubert 
12092b15cb3dSCy Schubert 	test_ok = 0;
12102b15cb3dSCy Schubert 
12112b15cb3dSCy Schubert 	evcon = evhttp_connection_base_new(data->base, dns_base, "127.0.0.1", port);
12122b15cb3dSCy Schubert 	tt_assert(evcon);
12132b15cb3dSCy Schubert 
12142b15cb3dSCy Schubert 	/*
12152b15cb3dSCy Schubert 	 * At this point, we want to schedule a request to the HTTP
12162b15cb3dSCy Schubert 	 * server using our make request method.
12172b15cb3dSCy Schubert 	 */
12182b15cb3dSCy Schubert 
12192b15cb3dSCy Schubert 	req = evhttp_request_new(http_request_done, (void*) BASIC_REQUEST_BODY);
12202b15cb3dSCy Schubert 
12212b15cb3dSCy Schubert 	/* Add the information that we care about */
12222b15cb3dSCy Schubert 	evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
12232b15cb3dSCy Schubert 
12242b15cb3dSCy Schubert 	/* We give ownership of the request to the connection */
12252b15cb3dSCy Schubert 	if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test") == -1) {
12262b15cb3dSCy Schubert 		fprintf(stdout, "FAILED\n");
12272b15cb3dSCy Schubert 		exit(1);
12282b15cb3dSCy Schubert 	}
12292b15cb3dSCy Schubert 
12302b15cb3dSCy Schubert 	event_base_dispatch(data->base);
12312b15cb3dSCy Schubert 
12322b15cb3dSCy Schubert 	tt_assert(test_ok);
12332b15cb3dSCy Schubert 
12342b15cb3dSCy Schubert 	/* try to make another request over the same connection */
12352b15cb3dSCy Schubert 	test_ok = 0;
12362b15cb3dSCy Schubert 
12372b15cb3dSCy Schubert 	req = evhttp_request_new(http_request_done, (void*) BASIC_REQUEST_BODY);
12382b15cb3dSCy Schubert 
12392b15cb3dSCy Schubert 	/* Add the information that we care about */
12402b15cb3dSCy Schubert 	evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
12412b15cb3dSCy Schubert 
12422b15cb3dSCy Schubert 	/*
12432b15cb3dSCy Schubert 	 * if our connections are not supposed to be persistent; request
12442b15cb3dSCy Schubert 	 * a close from the server.
12452b15cb3dSCy Schubert 	 */
12462b15cb3dSCy Schubert 	evhttp_add_header(evhttp_request_get_output_headers(req), "Connection", "close");
12472b15cb3dSCy Schubert 
12482b15cb3dSCy Schubert 	/* We give ownership of the request to the connection */
12492b15cb3dSCy Schubert 	if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test") == -1) {
12502b15cb3dSCy Schubert 		tt_abort_msg("couldn't make request");
12512b15cb3dSCy Schubert 	}
12522b15cb3dSCy Schubert 
12532b15cb3dSCy Schubert 	event_base_dispatch(data->base);
12542b15cb3dSCy Schubert 
12552b15cb3dSCy Schubert 	/* make another request: request empty reply */
12562b15cb3dSCy Schubert 	test_ok = 0;
12572b15cb3dSCy Schubert 
12582b15cb3dSCy Schubert 	req = evhttp_request_new(http_request_empty_done, data->base);
12592b15cb3dSCy Schubert 
12602b15cb3dSCy Schubert 	/* Add the information that we care about */
12612b15cb3dSCy Schubert 	evhttp_add_header(evhttp_request_get_output_headers(req), "Empty", "itis");
12622b15cb3dSCy Schubert 
12632b15cb3dSCy Schubert 	/* We give ownership of the request to the connection */
12642b15cb3dSCy Schubert 	if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test") == -1) {
12652b15cb3dSCy Schubert 		tt_abort_msg("Couldn't make request");
12662b15cb3dSCy Schubert 	}
12672b15cb3dSCy Schubert 
12682b15cb3dSCy Schubert 	event_base_dispatch(data->base);
12692b15cb3dSCy Schubert 
12702b15cb3dSCy Schubert  end:
12712b15cb3dSCy Schubert 	if (evcon)
12722b15cb3dSCy Schubert 		evhttp_connection_free(evcon);
12732b15cb3dSCy Schubert 	if (http)
12742b15cb3dSCy Schubert 		evhttp_free(http);
12752b15cb3dSCy Schubert 	if (dns_base)
12762b15cb3dSCy Schubert 		evdns_base_free(dns_base, 0);
12772b15cb3dSCy Schubert 	regress_clean_dnsserver();
12782b15cb3dSCy Schubert }
12792b15cb3dSCy Schubert 
12802b15cb3dSCy Schubert static void
http_autofree_connection_test(void * arg)1281a25439b6SCy Schubert http_autofree_connection_test(void *arg)
1282a25439b6SCy Schubert {
1283a25439b6SCy Schubert 	struct basic_test_data *data = arg;
1284a25439b6SCy Schubert 	ev_uint16_t port = 0;
1285a25439b6SCy Schubert 	struct evhttp_connection *evcon = NULL;
1286a25439b6SCy Schubert 	struct evhttp_request *req[2] = { NULL };
1287*a466cc55SCy Schubert 	struct evhttp *http = http_setup(&port, data->base, 0);
1288*a466cc55SCy Schubert 	size_t i;
1289a25439b6SCy Schubert 
1290a25439b6SCy Schubert 	test_ok = 0;
1291a25439b6SCy Schubert 
1292a25439b6SCy Schubert 	evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port);
1293a25439b6SCy Schubert 	tt_assert(evcon);
1294a25439b6SCy Schubert 
1295a25439b6SCy Schubert 	/*
1296a25439b6SCy Schubert 	 * At this point, we want to schedule two request to the HTTP
1297a25439b6SCy Schubert 	 * server using our make request method.
1298a25439b6SCy Schubert 	 */
1299a25439b6SCy Schubert 	req[0] = evhttp_request_new(http_request_empty_done, data->base);
1300a25439b6SCy Schubert 	req[1] = evhttp_request_new(http_request_empty_done, data->base);
1301a25439b6SCy Schubert 
1302a25439b6SCy Schubert 	/* Add the information that we care about */
1303*a466cc55SCy Schubert 	for (i = 0; i < ARRAY_SIZE(req); ++i) {
1304*a466cc55SCy Schubert 		evhttp_add_header(evhttp_request_get_output_headers(req[i]), "Host", "somehost");
1305*a466cc55SCy Schubert 		evhttp_add_header(evhttp_request_get_output_headers(req[i]), "Connection", "close");
1306*a466cc55SCy Schubert 		evhttp_add_header(evhttp_request_get_output_headers(req[i]), "Empty", "itis");
1307a25439b6SCy Schubert 
1308*a466cc55SCy Schubert 		if (evhttp_make_request(evcon, req[i], EVHTTP_REQ_GET, "/test") == -1) {
1309a25439b6SCy Schubert 			tt_abort_msg("couldn't make request");
1310a25439b6SCy Schubert 		}
1311a25439b6SCy Schubert 	}
1312a25439b6SCy Schubert 
1313a25439b6SCy Schubert 	/*
1314a25439b6SCy Schubert 	 * Tell libevent to free the connection when the request completes
1315a25439b6SCy Schubert 	 *	We then set the evcon pointer to NULL since we don't want to free it
1316a25439b6SCy Schubert 	 *	when this function ends.
1317a25439b6SCy Schubert 	 */
1318a25439b6SCy Schubert 	evhttp_connection_free_on_completion(evcon);
1319a25439b6SCy Schubert 	evcon = NULL;
1320a25439b6SCy Schubert 
1321*a466cc55SCy Schubert 	for (i = 0; i < ARRAY_SIZE(req); ++i)
1322a25439b6SCy Schubert 		event_base_dispatch(data->base);
1323a25439b6SCy Schubert 
1324a25439b6SCy Schubert 	/* at this point, the http server should have no connection */
1325a25439b6SCy Schubert 	tt_assert(TAILQ_FIRST(&http->connections) == NULL);
1326a25439b6SCy Schubert 
1327a25439b6SCy Schubert  end:
1328a25439b6SCy Schubert 	if (evcon)
1329a25439b6SCy Schubert 		evhttp_connection_free(evcon);
1330a25439b6SCy Schubert 	if (http)
1331a25439b6SCy Schubert 		evhttp_free(http);
1332a25439b6SCy Schubert }
1333a25439b6SCy Schubert 
1334a25439b6SCy Schubert static void
http_request_never_call(struct evhttp_request * req,void * arg)13352b15cb3dSCy Schubert http_request_never_call(struct evhttp_request *req, void *arg)
13362b15cb3dSCy Schubert {
13372b15cb3dSCy Schubert 	fprintf(stdout, "FAILED\n");
13382b15cb3dSCy Schubert 	exit(1);
13392b15cb3dSCy Schubert }
1340*a466cc55SCy Schubert static void
http_failed_request_done(struct evhttp_request * req,void * arg)1341*a466cc55SCy Schubert http_failed_request_done(struct evhttp_request *req, void *arg)
1342*a466cc55SCy Schubert {
1343*a466cc55SCy Schubert 	tt_assert(!req);
1344*a466cc55SCy Schubert end:
1345*a466cc55SCy Schubert 	event_base_loopexit(arg, NULL);
1346*a466cc55SCy Schubert }
1347*a466cc55SCy Schubert #ifndef _WIN32
1348*a466cc55SCy Schubert static void
http_timed_out_request_done(struct evhttp_request * req,void * arg)1349*a466cc55SCy Schubert http_timed_out_request_done(struct evhttp_request *req, void *arg)
1350*a466cc55SCy Schubert {
1351*a466cc55SCy Schubert 	tt_assert(req);
1352*a466cc55SCy Schubert 	tt_int_op(evhttp_request_get_response_code(req), !=, HTTP_OK);
1353*a466cc55SCy Schubert end:
1354*a466cc55SCy Schubert 	event_base_loopexit(arg, NULL);
1355*a466cc55SCy Schubert }
1356*a466cc55SCy Schubert #endif
13572b15cb3dSCy Schubert 
13582b15cb3dSCy Schubert static void
http_request_error_cb_with_cancel(enum evhttp_request_error error,void * arg)1359*a466cc55SCy Schubert http_request_error_cb_with_cancel(enum evhttp_request_error error, void *arg)
1360*a466cc55SCy Schubert {
1361*a466cc55SCy Schubert 	if (error != EVREQ_HTTP_REQUEST_CANCEL) {
1362*a466cc55SCy Schubert 		fprintf(stderr, "FAILED\n");
1363*a466cc55SCy Schubert 		exit(1);
1364*a466cc55SCy Schubert 	}
1365*a466cc55SCy Schubert 	test_ok = 1;
1366*a466cc55SCy Schubert 
1367*a466cc55SCy Schubert 	{
1368*a466cc55SCy Schubert 		struct timeval tv;
1369*a466cc55SCy Schubert 		evutil_timerclear(&tv);
1370*a466cc55SCy Schubert 		tv.tv_sec = 0;
1371*a466cc55SCy Schubert 		tv.tv_usec = 500 * 1000;
1372*a466cc55SCy Schubert 		event_base_loopexit(exit_base, &tv);
1373*a466cc55SCy Schubert 	}
1374*a466cc55SCy Schubert }
1375*a466cc55SCy Schubert static void
http_do_cancel(evutil_socket_t fd,short what,void * arg)13762b15cb3dSCy Schubert http_do_cancel(evutil_socket_t fd, short what, void *arg)
13772b15cb3dSCy Schubert {
13782b15cb3dSCy Schubert 	struct evhttp_request *req = arg;
13792b15cb3dSCy Schubert 	evhttp_cancel_request(req);
13802b15cb3dSCy Schubert 	++test_ok;
13812b15cb3dSCy Schubert }
1382*a466cc55SCy Schubert static void
http_no_write(struct evbuffer * buffer,const struct evbuffer_cb_info * info,void * arg)1383*a466cc55SCy Schubert http_no_write(struct evbuffer *buffer, const struct evbuffer_cb_info *info, void *arg)
1384*a466cc55SCy Schubert {
1385*a466cc55SCy Schubert 	fprintf(stdout, "FAILED\n");
1386*a466cc55SCy Schubert 	exit(1);
1387*a466cc55SCy Schubert }
1388*a466cc55SCy Schubert static void
http_free_evcons(struct evhttp_connection ** evcons)1389*a466cc55SCy Schubert http_free_evcons(struct evhttp_connection **evcons)
1390*a466cc55SCy Schubert {
1391*a466cc55SCy Schubert 	struct evhttp_connection *evcon, **orig = evcons;
13922b15cb3dSCy Schubert 
1393*a466cc55SCy Schubert 	if (!evcons)
1394*a466cc55SCy Schubert 		return;
1395*a466cc55SCy Schubert 
1396*a466cc55SCy Schubert 	while ((evcon = *evcons++)) {
1397*a466cc55SCy Schubert 		evhttp_connection_free(evcon);
1398*a466cc55SCy Schubert 	}
1399*a466cc55SCy Schubert 	free(orig);
1400*a466cc55SCy Schubert }
1401*a466cc55SCy Schubert /** fill the backlog to force server drop packages for timeouts */
1402*a466cc55SCy Schubert static struct evhttp_connection **
http_fill_backlog(struct event_base * base,int port)1403*a466cc55SCy Schubert http_fill_backlog(struct event_base *base, int port)
1404*a466cc55SCy Schubert {
1405*a466cc55SCy Schubert #define BACKLOG_SIZE 256
1406*a466cc55SCy Schubert 		struct evhttp_connection **evcon = malloc(sizeof(*evcon) * (BACKLOG_SIZE + 1));
1407*a466cc55SCy Schubert 		int i;
1408*a466cc55SCy Schubert 
1409*a466cc55SCy Schubert 		for (i = 0; i < BACKLOG_SIZE; ++i) {
1410*a466cc55SCy Schubert 			struct evhttp_request *req;
1411*a466cc55SCy Schubert 
1412*a466cc55SCy Schubert 			evcon[i] = evhttp_connection_base_new(base, NULL, "127.0.0.1", port);
1413*a466cc55SCy Schubert 			tt_assert(evcon[i]);
1414*a466cc55SCy Schubert 			evhttp_connection_set_timeout(evcon[i], 5);
1415*a466cc55SCy Schubert 
1416*a466cc55SCy Schubert 			req = evhttp_request_new(http_request_never_call, NULL);
1417*a466cc55SCy Schubert 			tt_assert(req);
1418*a466cc55SCy Schubert 			tt_int_op(evhttp_make_request(evcon[i], req, EVHTTP_REQ_GET, "/delay"), !=, -1);
1419*a466cc55SCy Schubert 		}
1420*a466cc55SCy Schubert 		evcon[i] = NULL;
1421*a466cc55SCy Schubert 
1422*a466cc55SCy Schubert 		return evcon;
1423*a466cc55SCy Schubert  end:
1424*a466cc55SCy Schubert 		fprintf(stderr, "Couldn't fill the backlog");
1425*a466cc55SCy Schubert 		return NULL;
1426*a466cc55SCy Schubert }
1427*a466cc55SCy Schubert 
1428*a466cc55SCy Schubert enum http_cancel_test_type {
1429*a466cc55SCy Schubert 	BASIC = 1,
1430*a466cc55SCy Schubert 	BY_HOST = 2,
1431*a466cc55SCy Schubert 	NO_NS = 4,
1432*a466cc55SCy Schubert 	INACTIVE_SERVER = 8,
1433*a466cc55SCy Schubert 	SERVER_TIMEOUT = 16,
1434*a466cc55SCy Schubert 	NS_TIMEOUT = 32,
1435*a466cc55SCy Schubert };
1436*a466cc55SCy Schubert static struct evhttp_request *
http_cancel_test_bad_request_new(enum http_cancel_test_type type,struct event_base * base)1437*a466cc55SCy Schubert http_cancel_test_bad_request_new(enum http_cancel_test_type type,
1438*a466cc55SCy Schubert 	struct event_base *base)
1439*a466cc55SCy Schubert {
1440*a466cc55SCy Schubert #ifndef _WIN32
1441*a466cc55SCy Schubert 	if (!(type & NO_NS) && (type & SERVER_TIMEOUT))
1442*a466cc55SCy Schubert 		return evhttp_request_new(http_timed_out_request_done, base);
1443*a466cc55SCy Schubert 	else
1444*a466cc55SCy Schubert #endif
1445*a466cc55SCy Schubert 	if ((type & INACTIVE_SERVER) || (type & NO_NS))
1446*a466cc55SCy Schubert 		return evhttp_request_new(http_failed_request_done, base);
1447*a466cc55SCy Schubert 	else
1448*a466cc55SCy Schubert 		return NULL;
1449*a466cc55SCy Schubert }
14502b15cb3dSCy Schubert static void
http_cancel_test(void * arg)14512b15cb3dSCy Schubert http_cancel_test(void *arg)
14522b15cb3dSCy Schubert {
14532b15cb3dSCy Schubert 	struct basic_test_data *data = arg;
14542b15cb3dSCy Schubert 	ev_uint16_t port = 0;
14552b15cb3dSCy Schubert 	struct evhttp_connection *evcon = NULL;
14562b15cb3dSCy Schubert 	struct evhttp_request *req = NULL;
1457*a466cc55SCy Schubert 	struct bufferevent *bufev = NULL;
14582b15cb3dSCy Schubert 	struct timeval tv;
1459*a466cc55SCy Schubert 	struct evdns_base *dns_base = NULL;
1460*a466cc55SCy Schubert 	ev_uint16_t portnum = 0;
1461*a466cc55SCy Schubert 	char address[64];
1462*a466cc55SCy Schubert 	struct evhttp *inactive_http = NULL;
1463*a466cc55SCy Schubert 	struct event_base *inactive_base = NULL;
1464*a466cc55SCy Schubert 	struct evhttp_connection **evcons = NULL;
1465*a466cc55SCy Schubert 	struct event_base *base_to_fill = data->base;
1466*a466cc55SCy Schubert 
1467*a466cc55SCy Schubert 	enum http_cancel_test_type type =
1468*a466cc55SCy Schubert 		(enum http_cancel_test_type)data->setup_data;
1469*a466cc55SCy Schubert 	struct evhttp *http = http_setup(&port, data->base, 0);
1470*a466cc55SCy Schubert 
1471*a466cc55SCy Schubert 	if (type & BY_HOST) {
1472*a466cc55SCy Schubert 		const char *timeout = (type & NS_TIMEOUT) ? "6" : "3";
1473*a466cc55SCy Schubert 
1474*a466cc55SCy Schubert 		tt_assert(regress_dnsserver(data->base, &portnum, search_table));
1475*a466cc55SCy Schubert 
1476*a466cc55SCy Schubert 		dns_base = evdns_base_new(data->base, 0/* init name servers */);
1477*a466cc55SCy Schubert 		tt_assert(dns_base);
1478*a466cc55SCy Schubert 
1479*a466cc55SCy Schubert 		/** XXX: Hack the port to make timeout after resolving */
1480*a466cc55SCy Schubert 		if (type & NO_NS)
1481*a466cc55SCy Schubert 			++portnum;
1482*a466cc55SCy Schubert 
1483*a466cc55SCy Schubert 		evutil_snprintf(address, sizeof(address), "127.0.0.1:%d", portnum);
1484*a466cc55SCy Schubert 		evdns_base_nameserver_ip_add(dns_base, address);
1485*a466cc55SCy Schubert 
1486*a466cc55SCy Schubert 		evdns_base_set_option(dns_base, "timeout:", timeout);
1487*a466cc55SCy Schubert 		evdns_base_set_option(dns_base, "initial-probe-timeout:", timeout);
1488*a466cc55SCy Schubert 		evdns_base_set_option(dns_base, "attempts:", "1");
1489*a466cc55SCy Schubert 	}
14902b15cb3dSCy Schubert 
14912b15cb3dSCy Schubert 	exit_base = data->base;
14922b15cb3dSCy Schubert 
14932b15cb3dSCy Schubert 	test_ok = 0;
14942b15cb3dSCy Schubert 
1495*a466cc55SCy Schubert 	if (type & INACTIVE_SERVER) {
1496*a466cc55SCy Schubert 		port = 0;
1497*a466cc55SCy Schubert 		inactive_base = event_base_new();
1498*a466cc55SCy Schubert 		inactive_http = http_setup(&port, inactive_base, 0);
14992b15cb3dSCy Schubert 
1500*a466cc55SCy Schubert 		base_to_fill = inactive_base;
1501*a466cc55SCy Schubert 	}
1502*a466cc55SCy Schubert 
1503*a466cc55SCy Schubert 	if (type & SERVER_TIMEOUT)
1504*a466cc55SCy Schubert 		evcons = http_fill_backlog(base_to_fill, port);
1505*a466cc55SCy Schubert 
1506*a466cc55SCy Schubert 	evcon = evhttp_connection_base_new(
1507*a466cc55SCy Schubert 		data->base, dns_base,
1508*a466cc55SCy Schubert 		type & BY_HOST ? "localhost" : "127.0.0.1",
1509*a466cc55SCy Schubert 		port);
1510*a466cc55SCy Schubert 	if (type & INACTIVE_SERVER)
1511*a466cc55SCy Schubert 		evhttp_connection_set_timeout(evcon, 5);
15122b15cb3dSCy Schubert 	tt_assert(evcon);
15132b15cb3dSCy Schubert 
1514*a466cc55SCy Schubert 	bufev = evhttp_connection_get_bufferevent(evcon);
1515*a466cc55SCy Schubert 	/* Guarantee that we stack in connect() not after waiting EV_READ after
1516*a466cc55SCy Schubert 	 * write() */
1517*a466cc55SCy Schubert 	if (type & SERVER_TIMEOUT)
1518*a466cc55SCy Schubert 		evbuffer_add_cb(bufferevent_get_output(bufev), http_no_write, NULL);
1519*a466cc55SCy Schubert 
15202b15cb3dSCy Schubert 	/*
15212b15cb3dSCy Schubert 	 * At this point, we want to schedule a request to the HTTP
15222b15cb3dSCy Schubert 	 * server using our make request method.
15232b15cb3dSCy Schubert 	 */
15242b15cb3dSCy Schubert 
15252b15cb3dSCy Schubert 	req = evhttp_request_new(http_request_never_call, NULL);
1526*a466cc55SCy Schubert 	evhttp_request_set_error_cb(req, http_request_error_cb_with_cancel);
15272b15cb3dSCy Schubert 
15282b15cb3dSCy Schubert 	/* Add the information that we care about */
15292b15cb3dSCy Schubert 	evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
15302b15cb3dSCy Schubert 
15312b15cb3dSCy Schubert 	/* We give ownership of the request to the connection */
15322b15cb3dSCy Schubert 	tt_int_op(evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/delay"),
15332b15cb3dSCy Schubert 		  !=, -1);
15342b15cb3dSCy Schubert 
15352b15cb3dSCy Schubert 	evutil_timerclear(&tv);
15362b15cb3dSCy Schubert 	tv.tv_sec = 0;
15372b15cb3dSCy Schubert 	tv.tv_usec = 100 * 1000;
15382b15cb3dSCy Schubert 
15392b15cb3dSCy Schubert 	event_base_once(data->base, -1, EV_TIMEOUT, http_do_cancel, req, &tv);
15402b15cb3dSCy Schubert 
15412b15cb3dSCy Schubert 	event_base_dispatch(data->base);
15422b15cb3dSCy Schubert 
1543*a466cc55SCy Schubert 	if (type & NO_NS || type & INACTIVE_SERVER)
1544*a466cc55SCy Schubert 		tt_int_op(test_ok, ==, 2); /** no servers responses */
1545*a466cc55SCy Schubert 	else
15462b15cb3dSCy Schubert 		tt_int_op(test_ok, ==, 3);
15472b15cb3dSCy Schubert 
15482b15cb3dSCy Schubert 	/* try to make another request over the same connection */
15492b15cb3dSCy Schubert 	test_ok = 0;
15502b15cb3dSCy Schubert 
1551*a466cc55SCy Schubert 	http_free_evcons(evcons);
1552*a466cc55SCy Schubert 	if (type & SERVER_TIMEOUT)
1553*a466cc55SCy Schubert 		evcons = http_fill_backlog(base_to_fill, port);
1554*a466cc55SCy Schubert 
1555*a466cc55SCy Schubert 	req = http_cancel_test_bad_request_new(type, data->base);
1556*a466cc55SCy Schubert 	if (!req)
15572b15cb3dSCy Schubert 		req = evhttp_request_new(http_request_done, (void*) BASIC_REQUEST_BODY);
15582b15cb3dSCy Schubert 
15592b15cb3dSCy Schubert 	/* Add the information that we care about */
15602b15cb3dSCy Schubert 	evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
15612b15cb3dSCy Schubert 
15622b15cb3dSCy Schubert 	/* We give ownership of the request to the connection */
15632b15cb3dSCy Schubert 	tt_int_op(evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test"),
15642b15cb3dSCy Schubert 		  !=, -1);
15652b15cb3dSCy Schubert 
15662b15cb3dSCy Schubert 	event_base_dispatch(data->base);
15672b15cb3dSCy Schubert 
15682b15cb3dSCy Schubert 	/* make another request: request empty reply */
15692b15cb3dSCy Schubert 	test_ok = 0;
15702b15cb3dSCy Schubert 
1571*a466cc55SCy Schubert 	http_free_evcons(evcons);
1572*a466cc55SCy Schubert 	if (type & SERVER_TIMEOUT)
1573*a466cc55SCy Schubert 		evcons = http_fill_backlog(base_to_fill, port);
1574*a466cc55SCy Schubert 
1575*a466cc55SCy Schubert 	req = http_cancel_test_bad_request_new(type, data->base);
1576*a466cc55SCy Schubert 	if (!req)
15772b15cb3dSCy Schubert 		req = evhttp_request_new(http_request_empty_done, data->base);
15782b15cb3dSCy Schubert 
15792b15cb3dSCy Schubert 	/* Add the information that we care about */
15802b15cb3dSCy Schubert 	evhttp_add_header(evhttp_request_get_output_headers(req), "Empty", "itis");
15812b15cb3dSCy Schubert 
15822b15cb3dSCy Schubert 	/* We give ownership of the request to the connection */
15832b15cb3dSCy Schubert 	tt_int_op(evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test"),
15842b15cb3dSCy Schubert 		  !=, -1);
15852b15cb3dSCy Schubert 
15862b15cb3dSCy Schubert 	event_base_dispatch(data->base);
15872b15cb3dSCy Schubert 
15882b15cb3dSCy Schubert  end:
1589*a466cc55SCy Schubert 	http_free_evcons(evcons);
1590*a466cc55SCy Schubert 	if (bufev)
1591*a466cc55SCy Schubert 		evbuffer_remove_cb(bufferevent_get_output(bufev), http_no_write, NULL);
15922b15cb3dSCy Schubert 	if (evcon)
15932b15cb3dSCy Schubert 		evhttp_connection_free(evcon);
15942b15cb3dSCy Schubert 	if (http)
15952b15cb3dSCy Schubert 		evhttp_free(http);
1596*a466cc55SCy Schubert 	if (dns_base)
1597*a466cc55SCy Schubert 		evdns_base_free(dns_base, 0);
1598*a466cc55SCy Schubert 	regress_clean_dnsserver();
1599*a466cc55SCy Schubert 	if (inactive_http)
1600*a466cc55SCy Schubert 		evhttp_free(inactive_http);
1601*a466cc55SCy Schubert 	if (inactive_base)
1602*a466cc55SCy Schubert 		event_base_free(inactive_base);
1603*a466cc55SCy Schubert }
1604*a466cc55SCy Schubert 
1605*a466cc55SCy Schubert static void
http_request_no_action_done(struct evhttp_request * req,void * arg)1606*a466cc55SCy Schubert http_request_no_action_done(struct evhttp_request *req, void *arg)
1607*a466cc55SCy Schubert {
1608*a466cc55SCy Schubert 	EVUTIL_ASSERT(exit_base);
1609*a466cc55SCy Schubert 	event_base_loopexit(exit_base, NULL);
16102b15cb3dSCy Schubert }
16112b15cb3dSCy Schubert 
16122b15cb3dSCy Schubert static void
http_request_done(struct evhttp_request * req,void * arg)16132b15cb3dSCy Schubert http_request_done(struct evhttp_request *req, void *arg)
16142b15cb3dSCy Schubert {
16152b15cb3dSCy Schubert 	const char *what = arg;
16162b15cb3dSCy Schubert 
1617*a466cc55SCy Schubert 	if (!req) {
1618*a466cc55SCy Schubert 		fprintf(stderr, "FAILED\n");
1619*a466cc55SCy Schubert 		exit(1);
1620*a466cc55SCy Schubert 	}
1621*a466cc55SCy Schubert 
16222b15cb3dSCy Schubert 	if (evhttp_request_get_response_code(req) != HTTP_OK) {
16232b15cb3dSCy Schubert 		fprintf(stderr, "FAILED\n");
16242b15cb3dSCy Schubert 		exit(1);
16252b15cb3dSCy Schubert 	}
16262b15cb3dSCy Schubert 
16272b15cb3dSCy Schubert 	if (evhttp_find_header(evhttp_request_get_input_headers(req), "Content-Type") == NULL) {
16282b15cb3dSCy Schubert 		fprintf(stderr, "FAILED\n");
16292b15cb3dSCy Schubert 		exit(1);
16302b15cb3dSCy Schubert 	}
16312b15cb3dSCy Schubert 
16322b15cb3dSCy Schubert 	if (evbuffer_get_length(evhttp_request_get_input_buffer(req)) != strlen(what)) {
16332b15cb3dSCy Schubert 		fprintf(stderr, "FAILED\n");
16342b15cb3dSCy Schubert 		exit(1);
16352b15cb3dSCy Schubert 	}
16362b15cb3dSCy Schubert 
16372b15cb3dSCy Schubert 	if (evbuffer_datacmp(evhttp_request_get_input_buffer(req), what) != 0) {
16382b15cb3dSCy Schubert 		fprintf(stderr, "FAILED\n");
16392b15cb3dSCy Schubert 		exit(1);
16402b15cb3dSCy Schubert 	}
16412b15cb3dSCy Schubert 
16422b15cb3dSCy Schubert 	test_ok = 1;
16432b15cb3dSCy Schubert 	EVUTIL_ASSERT(exit_base);
16442b15cb3dSCy Schubert 	event_base_loopexit(exit_base, NULL);
16452b15cb3dSCy Schubert }
16462b15cb3dSCy Schubert 
16472b15cb3dSCy Schubert static void
http_request_expect_error(struct evhttp_request * req,void * arg)16482b15cb3dSCy Schubert http_request_expect_error(struct evhttp_request *req, void *arg)
16492b15cb3dSCy Schubert {
16502b15cb3dSCy Schubert 	if (evhttp_request_get_response_code(req) == HTTP_OK) {
16512b15cb3dSCy Schubert 		fprintf(stderr, "FAILED\n");
16522b15cb3dSCy Schubert 		exit(1);
16532b15cb3dSCy Schubert 	}
16542b15cb3dSCy Schubert 
16552b15cb3dSCy Schubert 	test_ok = 1;
16562b15cb3dSCy Schubert 	EVUTIL_ASSERT(arg);
16572b15cb3dSCy Schubert 	event_base_loopexit(arg, NULL);
16582b15cb3dSCy Schubert }
16592b15cb3dSCy Schubert 
16602b15cb3dSCy Schubert /* test virtual hosts */
16612b15cb3dSCy Schubert static void
http_virtual_host_test(void * arg)16622b15cb3dSCy Schubert http_virtual_host_test(void *arg)
16632b15cb3dSCy Schubert {
16642b15cb3dSCy Schubert 	struct basic_test_data *data = arg;
16652b15cb3dSCy Schubert 	ev_uint16_t port = 0;
16662b15cb3dSCy Schubert 	struct evhttp_connection *evcon = NULL;
16672b15cb3dSCy Schubert 	struct evhttp_request *req = NULL;
16682b15cb3dSCy Schubert 	struct evhttp *second = NULL, *third = NULL;
16692b15cb3dSCy Schubert 	evutil_socket_t fd;
16702b15cb3dSCy Schubert 	struct bufferevent *bev;
16712b15cb3dSCy Schubert 	const char *http_request;
1672*a466cc55SCy Schubert 	struct evhttp *http = http_setup(&port, data->base, 0);
16732b15cb3dSCy Schubert 
16742b15cb3dSCy Schubert 	exit_base = data->base;
16752b15cb3dSCy Schubert 
16762b15cb3dSCy Schubert 	/* virtual host */
16772b15cb3dSCy Schubert 	second = evhttp_new(NULL);
1678*a466cc55SCy Schubert 	evhttp_set_cb(second, "/funnybunny", http_basic_cb, http);
16792b15cb3dSCy Schubert 	third = evhttp_new(NULL);
1680*a466cc55SCy Schubert 	evhttp_set_cb(third, "/blackcoffee", http_basic_cb, http);
16812b15cb3dSCy Schubert 
16822b15cb3dSCy Schubert 	if (evhttp_add_virtual_host(http, "foo.com", second) == -1) {
16832b15cb3dSCy Schubert 		tt_abort_msg("Couldn't add vhost");
16842b15cb3dSCy Schubert 	}
16852b15cb3dSCy Schubert 
16862b15cb3dSCy Schubert 	if (evhttp_add_virtual_host(http, "bar.*.foo.com", third) == -1) {
16872b15cb3dSCy Schubert 		tt_abort_msg("Couldn't add wildcarded vhost");
16882b15cb3dSCy Schubert 	}
16892b15cb3dSCy Schubert 
16902b15cb3dSCy Schubert 	/* add some aliases to the vhosts */
16912b15cb3dSCy Schubert 	tt_assert(evhttp_add_server_alias(second, "manolito.info") == 0);
16922b15cb3dSCy Schubert 	tt_assert(evhttp_add_server_alias(third, "bonkers.org") == 0);
16932b15cb3dSCy Schubert 
16942b15cb3dSCy Schubert 	evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port);
16952b15cb3dSCy Schubert 	tt_assert(evcon);
16962b15cb3dSCy Schubert 
16972b15cb3dSCy Schubert 	/* make a request with a different host and expect an error */
16982b15cb3dSCy Schubert 	req = evhttp_request_new(http_request_expect_error, data->base);
16992b15cb3dSCy Schubert 
17002b15cb3dSCy Schubert 	/* Add the information that we care about */
17012b15cb3dSCy Schubert 	evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
17022b15cb3dSCy Schubert 
17032b15cb3dSCy Schubert 	/* We give ownership of the request to the connection */
17042b15cb3dSCy Schubert 	if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET,
17052b15cb3dSCy Schubert 		"/funnybunny") == -1) {
17062b15cb3dSCy Schubert 		tt_abort_msg("Couldn't make request");
17072b15cb3dSCy Schubert 	}
17082b15cb3dSCy Schubert 
17092b15cb3dSCy Schubert 	event_base_dispatch(data->base);
17102b15cb3dSCy Schubert 
17112b15cb3dSCy Schubert 	tt_assert(test_ok == 1);
17122b15cb3dSCy Schubert 
17132b15cb3dSCy Schubert 	test_ok = 0;
17142b15cb3dSCy Schubert 
17152b15cb3dSCy Schubert 	/* make a request with the right host and expect a response */
17162b15cb3dSCy Schubert 	req = evhttp_request_new(http_request_done, (void*) BASIC_REQUEST_BODY);
17172b15cb3dSCy Schubert 
17182b15cb3dSCy Schubert 	/* Add the information that we care about */
17192b15cb3dSCy Schubert 	evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "foo.com");
17202b15cb3dSCy Schubert 
17212b15cb3dSCy Schubert 	/* We give ownership of the request to the connection */
17222b15cb3dSCy Schubert 	if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET,
17232b15cb3dSCy Schubert 		"/funnybunny") == -1) {
17242b15cb3dSCy Schubert 		fprintf(stdout, "FAILED\n");
17252b15cb3dSCy Schubert 		exit(1);
17262b15cb3dSCy Schubert 	}
17272b15cb3dSCy Schubert 
17282b15cb3dSCy Schubert 	event_base_dispatch(data->base);
17292b15cb3dSCy Schubert 
17302b15cb3dSCy Schubert 	tt_assert(test_ok == 1);
17312b15cb3dSCy Schubert 
17322b15cb3dSCy Schubert 	test_ok = 0;
17332b15cb3dSCy Schubert 
17342b15cb3dSCy Schubert 	/* make a request with the right host and expect a response */
17352b15cb3dSCy Schubert 	req = evhttp_request_new(http_request_done, (void*) BASIC_REQUEST_BODY);
17362b15cb3dSCy Schubert 
17372b15cb3dSCy Schubert 	/* Add the information that we care about */
17382b15cb3dSCy Schubert 	evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "bar.magic.foo.com");
17392b15cb3dSCy Schubert 
17402b15cb3dSCy Schubert 	/* We give ownership of the request to the connection */
17412b15cb3dSCy Schubert 	if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET,
17422b15cb3dSCy Schubert 		"/blackcoffee") == -1) {
17432b15cb3dSCy Schubert 		tt_abort_msg("Couldn't make request");
17442b15cb3dSCy Schubert 	}
17452b15cb3dSCy Schubert 
17462b15cb3dSCy Schubert 	event_base_dispatch(data->base);
17472b15cb3dSCy Schubert 
17482b15cb3dSCy Schubert 	tt_assert(test_ok == 1)
17492b15cb3dSCy Schubert 
17502b15cb3dSCy Schubert 	test_ok = 0;
17512b15cb3dSCy Schubert 
17522b15cb3dSCy Schubert 	/* make a request with the right host and expect a response */
17532b15cb3dSCy Schubert 	req = evhttp_request_new(http_request_done, (void*) BASIC_REQUEST_BODY);
17542b15cb3dSCy Schubert 
17552b15cb3dSCy Schubert 	/* Add the information that we care about */
17562b15cb3dSCy Schubert 	evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "manolito.info");
17572b15cb3dSCy Schubert 
17582b15cb3dSCy Schubert 	/* We give ownership of the request to the connection */
17592b15cb3dSCy Schubert 	if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET,
17602b15cb3dSCy Schubert 		"/funnybunny") == -1) {
17612b15cb3dSCy Schubert 		tt_abort_msg("Couldn't make request");
17622b15cb3dSCy Schubert 	}
17632b15cb3dSCy Schubert 
17642b15cb3dSCy Schubert 	event_base_dispatch(data->base);
17652b15cb3dSCy Schubert 
17662b15cb3dSCy Schubert 	tt_assert(test_ok == 1)
17672b15cb3dSCy Schubert 
17682b15cb3dSCy Schubert 	test_ok = 0;
17692b15cb3dSCy Schubert 
17702b15cb3dSCy Schubert 	/* make a request with the right host and expect a response */
17712b15cb3dSCy Schubert 	req = evhttp_request_new(http_request_done, (void*) BASIC_REQUEST_BODY);
17722b15cb3dSCy Schubert 
17732b15cb3dSCy Schubert 	/* Add the Host header. This time with the optional port. */
17742b15cb3dSCy Schubert 	evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "bonkers.org:8000");
17752b15cb3dSCy Schubert 
17762b15cb3dSCy Schubert 	/* We give ownership of the request to the connection */
17772b15cb3dSCy Schubert 	if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET,
17782b15cb3dSCy Schubert 		"/blackcoffee") == -1) {
17792b15cb3dSCy Schubert 		tt_abort_msg("Couldn't make request");
17802b15cb3dSCy Schubert 	}
17812b15cb3dSCy Schubert 
17822b15cb3dSCy Schubert 	event_base_dispatch(data->base);
17832b15cb3dSCy Schubert 
17842b15cb3dSCy Schubert 	tt_assert(test_ok == 1)
17852b15cb3dSCy Schubert 
17862b15cb3dSCy Schubert 	test_ok = 0;
17872b15cb3dSCy Schubert 
17882b15cb3dSCy Schubert 	/* Now make a raw request with an absolute URI. */
17892b15cb3dSCy Schubert 	fd = http_connect("127.0.0.1", port);
1790*a466cc55SCy Schubert 	tt_assert(fd != EVUTIL_INVALID_SOCKET);
17912b15cb3dSCy Schubert 
17922b15cb3dSCy Schubert 	/* Stupid thing to send a request */
17932b15cb3dSCy Schubert 	bev = bufferevent_socket_new(data->base, fd, 0);
17942b15cb3dSCy Schubert 	bufferevent_setcb(bev, http_readcb, http_writecb,
17952b15cb3dSCy Schubert 	    http_errorcb, NULL);
17962b15cb3dSCy Schubert 
17972b15cb3dSCy Schubert 	/* The host in the URI should override the Host: header */
17982b15cb3dSCy Schubert 	http_request =
17992b15cb3dSCy Schubert 	    "GET http://manolito.info/funnybunny HTTP/1.1\r\n"
18002b15cb3dSCy Schubert 	    "Host: somehost\r\n"
18012b15cb3dSCy Schubert 	    "Connection: close\r\n"
18022b15cb3dSCy Schubert 	    "\r\n";
18032b15cb3dSCy Schubert 
18042b15cb3dSCy Schubert 	bufferevent_write(bev, http_request, strlen(http_request));
18052b15cb3dSCy Schubert 
18062b15cb3dSCy Schubert 	event_base_dispatch(data->base);
18072b15cb3dSCy Schubert 
18082b15cb3dSCy Schubert 	tt_int_op(test_ok, ==, 2);
18092b15cb3dSCy Schubert 
18102b15cb3dSCy Schubert 	bufferevent_free(bev);
18112b15cb3dSCy Schubert 	evutil_closesocket(fd);
18122b15cb3dSCy Schubert 
18132b15cb3dSCy Schubert  end:
18142b15cb3dSCy Schubert 	if (evcon)
18152b15cb3dSCy Schubert 		evhttp_connection_free(evcon);
18162b15cb3dSCy Schubert 	if (http)
18172b15cb3dSCy Schubert 		evhttp_free(http);
18182b15cb3dSCy Schubert }
18192b15cb3dSCy Schubert 
18202b15cb3dSCy Schubert 
18212b15cb3dSCy Schubert /* test date header and content length */
18222b15cb3dSCy Schubert 
18232b15cb3dSCy Schubert static void
http_request_empty_done(struct evhttp_request * req,void * arg)18242b15cb3dSCy Schubert http_request_empty_done(struct evhttp_request *req, void *arg)
18252b15cb3dSCy Schubert {
1826*a466cc55SCy Schubert 	if (!req) {
1827*a466cc55SCy Schubert 		fprintf(stderr, "FAILED\n");
1828*a466cc55SCy Schubert 		exit(1);
1829*a466cc55SCy Schubert 	}
1830*a466cc55SCy Schubert 
18312b15cb3dSCy Schubert 	if (evhttp_request_get_response_code(req) != HTTP_OK) {
18322b15cb3dSCy Schubert 		fprintf(stderr, "FAILED\n");
18332b15cb3dSCy Schubert 		exit(1);
18342b15cb3dSCy Schubert 	}
18352b15cb3dSCy Schubert 
18362b15cb3dSCy Schubert 	if (evhttp_find_header(evhttp_request_get_input_headers(req), "Date") == NULL) {
18372b15cb3dSCy Schubert 		fprintf(stderr, "FAILED\n");
18382b15cb3dSCy Schubert 		exit(1);
18392b15cb3dSCy Schubert 	}
18402b15cb3dSCy Schubert 
18412b15cb3dSCy Schubert 
18422b15cb3dSCy Schubert 	if (evhttp_find_header(evhttp_request_get_input_headers(req), "Content-Length") == NULL) {
18432b15cb3dSCy Schubert 		fprintf(stderr, "FAILED\n");
18442b15cb3dSCy Schubert 		exit(1);
18452b15cb3dSCy Schubert 	}
18462b15cb3dSCy Schubert 
18472b15cb3dSCy Schubert 	if (strcmp(evhttp_find_header(evhttp_request_get_input_headers(req), "Content-Length"),
18482b15cb3dSCy Schubert 		"0")) {
18492b15cb3dSCy Schubert 		fprintf(stderr, "FAILED\n");
18502b15cb3dSCy Schubert 		exit(1);
18512b15cb3dSCy Schubert 	}
18522b15cb3dSCy Schubert 
18532b15cb3dSCy Schubert 	if (evbuffer_get_length(evhttp_request_get_input_buffer(req)) != 0) {
18542b15cb3dSCy Schubert 		fprintf(stderr, "FAILED\n");
18552b15cb3dSCy Schubert 		exit(1);
18562b15cb3dSCy Schubert 	}
18572b15cb3dSCy Schubert 
18582b15cb3dSCy Schubert 	test_ok = 1;
18592b15cb3dSCy Schubert 	EVUTIL_ASSERT(arg);
18602b15cb3dSCy Schubert 	event_base_loopexit(arg, NULL);
18612b15cb3dSCy Schubert }
18622b15cb3dSCy Schubert 
18632b15cb3dSCy Schubert /*
18642b15cb3dSCy Schubert  * HTTP DISPATCHER test
18652b15cb3dSCy Schubert  */
18662b15cb3dSCy Schubert 
18672b15cb3dSCy Schubert void
http_dispatcher_cb(struct evhttp_request * req,void * arg)18682b15cb3dSCy Schubert http_dispatcher_cb(struct evhttp_request *req, void *arg)
18692b15cb3dSCy Schubert {
18702b15cb3dSCy Schubert 
18712b15cb3dSCy Schubert 	struct evbuffer *evb = evbuffer_new();
1872*a466cc55SCy Schubert 	TT_BLATHER(("%s: called\n", __func__));
18732b15cb3dSCy Schubert 	evbuffer_add_printf(evb, "DISPATCHER_TEST");
18742b15cb3dSCy Schubert 
18752b15cb3dSCy Schubert 	evhttp_send_reply(req, HTTP_OK, "Everything is fine", evb);
18762b15cb3dSCy Schubert 
18772b15cb3dSCy Schubert 	evbuffer_free(evb);
18782b15cb3dSCy Schubert }
18792b15cb3dSCy Schubert 
18802b15cb3dSCy Schubert static void
http_dispatcher_test_done(struct evhttp_request * req,void * arg)18812b15cb3dSCy Schubert http_dispatcher_test_done(struct evhttp_request *req, void *arg)
18822b15cb3dSCy Schubert {
18832b15cb3dSCy Schubert 	struct event_base *base = arg;
18842b15cb3dSCy Schubert 	const char *what = "DISPATCHER_TEST";
18852b15cb3dSCy Schubert 
1886*a466cc55SCy Schubert 	if (!req) {
1887*a466cc55SCy Schubert 		fprintf(stderr, "FAILED\n");
1888*a466cc55SCy Schubert 		exit(1);
1889*a466cc55SCy Schubert 	}
1890*a466cc55SCy Schubert 
18912b15cb3dSCy Schubert 	if (evhttp_request_get_response_code(req) != HTTP_OK) {
18922b15cb3dSCy Schubert 		fprintf(stderr, "FAILED\n");
18932b15cb3dSCy Schubert 		exit(1);
18942b15cb3dSCy Schubert 	}
18952b15cb3dSCy Schubert 
18962b15cb3dSCy Schubert 	if (evhttp_find_header(evhttp_request_get_input_headers(req), "Content-Type") == NULL) {
18972b15cb3dSCy Schubert 		fprintf(stderr, "FAILED (content type)\n");
18982b15cb3dSCy Schubert 		exit(1);
18992b15cb3dSCy Schubert 	}
19002b15cb3dSCy Schubert 
19012b15cb3dSCy Schubert 	if (evbuffer_get_length(evhttp_request_get_input_buffer(req)) != strlen(what)) {
19022b15cb3dSCy Schubert 		fprintf(stderr, "FAILED (length %lu vs %lu)\n",
19032b15cb3dSCy Schubert 		    (unsigned long)evbuffer_get_length(evhttp_request_get_input_buffer(req)), (unsigned long)strlen(what));
19042b15cb3dSCy Schubert 		exit(1);
19052b15cb3dSCy Schubert 	}
19062b15cb3dSCy Schubert 
19072b15cb3dSCy Schubert 	if (evbuffer_datacmp(evhttp_request_get_input_buffer(req), what) != 0) {
19082b15cb3dSCy Schubert 		fprintf(stderr, "FAILED (data)\n");
19092b15cb3dSCy Schubert 		exit(1);
19102b15cb3dSCy Schubert 	}
19112b15cb3dSCy Schubert 
19122b15cb3dSCy Schubert 	test_ok = 1;
19132b15cb3dSCy Schubert 	event_base_loopexit(base, NULL);
19142b15cb3dSCy Schubert }
19152b15cb3dSCy Schubert 
19162b15cb3dSCy Schubert static void
http_dispatcher_test(void * arg)19172b15cb3dSCy Schubert http_dispatcher_test(void *arg)
19182b15cb3dSCy Schubert {
19192b15cb3dSCy Schubert 	struct basic_test_data *data = arg;
19202b15cb3dSCy Schubert 	ev_uint16_t port = 0;
19212b15cb3dSCy Schubert 	struct evhttp_connection *evcon = NULL;
19222b15cb3dSCy Schubert 	struct evhttp_request *req = NULL;
1923*a466cc55SCy Schubert 	struct evhttp *http = http_setup(&port, data->base, 0);
19242b15cb3dSCy Schubert 
19252b15cb3dSCy Schubert 	test_ok = 0;
19262b15cb3dSCy Schubert 
19272b15cb3dSCy Schubert 	evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port);
19282b15cb3dSCy Schubert 	tt_assert(evcon);
19292b15cb3dSCy Schubert 
19302b15cb3dSCy Schubert 	/* also bind to local host */
19312b15cb3dSCy Schubert 	evhttp_connection_set_local_address(evcon, "127.0.0.1");
19322b15cb3dSCy Schubert 
19332b15cb3dSCy Schubert 	/*
19342b15cb3dSCy Schubert 	 * At this point, we want to schedule an HTTP GET request
19352b15cb3dSCy Schubert 	 * server using our make request method.
19362b15cb3dSCy Schubert 	 */
19372b15cb3dSCy Schubert 
19382b15cb3dSCy Schubert 	req = evhttp_request_new(http_dispatcher_test_done, data->base);
19392b15cb3dSCy Schubert 	tt_assert(req);
19402b15cb3dSCy Schubert 
19412b15cb3dSCy Schubert 	/* Add the information that we care about */
19422b15cb3dSCy Schubert 	evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
19432b15cb3dSCy Schubert 
19442b15cb3dSCy Schubert 	if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/?arg=val") == -1) {
19452b15cb3dSCy Schubert 		tt_abort_msg("Couldn't make request");
19462b15cb3dSCy Schubert 	}
19472b15cb3dSCy Schubert 
19482b15cb3dSCy Schubert 	event_base_dispatch(data->base);
19492b15cb3dSCy Schubert 
19502b15cb3dSCy Schubert  end:
19512b15cb3dSCy Schubert 	if (evcon)
19522b15cb3dSCy Schubert 		evhttp_connection_free(evcon);
19532b15cb3dSCy Schubert 	if (http)
19542b15cb3dSCy Schubert 		evhttp_free(http);
19552b15cb3dSCy Schubert }
19562b15cb3dSCy Schubert 
19572b15cb3dSCy Schubert /*
19582b15cb3dSCy Schubert  * HTTP POST test.
19592b15cb3dSCy Schubert  */
19602b15cb3dSCy Schubert 
19612b15cb3dSCy Schubert void http_postrequest_done(struct evhttp_request *, void *);
19622b15cb3dSCy Schubert 
19632b15cb3dSCy Schubert #define POST_DATA "Okay.  Not really printf"
19642b15cb3dSCy Schubert 
19652b15cb3dSCy Schubert static void
http_post_test(void * arg)19662b15cb3dSCy Schubert http_post_test(void *arg)
19672b15cb3dSCy Schubert {
19682b15cb3dSCy Schubert 	struct basic_test_data *data = arg;
19692b15cb3dSCy Schubert 	ev_uint16_t port = 0;
19702b15cb3dSCy Schubert 	struct evhttp_connection *evcon = NULL;
19712b15cb3dSCy Schubert 	struct evhttp_request *req = NULL;
1972*a466cc55SCy Schubert 	struct evhttp *http = http_setup(&port, data->base, 0);
19732b15cb3dSCy Schubert 
19742b15cb3dSCy Schubert 	test_ok = 0;
19752b15cb3dSCy Schubert 
19762b15cb3dSCy Schubert 	evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port);
19772b15cb3dSCy Schubert 	tt_assert(evcon);
19782b15cb3dSCy Schubert 
19792b15cb3dSCy Schubert 	/*
19802b15cb3dSCy Schubert 	 * At this point, we want to schedule an HTTP POST request
19812b15cb3dSCy Schubert 	 * server using our make request method.
19822b15cb3dSCy Schubert 	 */
19832b15cb3dSCy Schubert 
19842b15cb3dSCy Schubert 	req = evhttp_request_new(http_postrequest_done, data->base);
19852b15cb3dSCy Schubert 	tt_assert(req);
19862b15cb3dSCy Schubert 
19872b15cb3dSCy Schubert 	/* Add the information that we care about */
19882b15cb3dSCy Schubert 	evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
19892b15cb3dSCy Schubert 	evbuffer_add_printf(evhttp_request_get_output_buffer(req), POST_DATA);
19902b15cb3dSCy Schubert 
19912b15cb3dSCy Schubert 	if (evhttp_make_request(evcon, req, EVHTTP_REQ_POST, "/postit") == -1) {
19922b15cb3dSCy Schubert 		tt_abort_msg("Couldn't make request");
19932b15cb3dSCy Schubert 	}
19942b15cb3dSCy Schubert 
19952b15cb3dSCy Schubert 	event_base_dispatch(data->base);
19962b15cb3dSCy Schubert 
19972b15cb3dSCy Schubert 	tt_int_op(test_ok, ==, 1);
19982b15cb3dSCy Schubert 
19992b15cb3dSCy Schubert 	test_ok = 0;
20002b15cb3dSCy Schubert 
20012b15cb3dSCy Schubert 	req = evhttp_request_new(http_postrequest_done, data->base);
20022b15cb3dSCy Schubert 	tt_assert(req);
20032b15cb3dSCy Schubert 
20042b15cb3dSCy Schubert 	/* Now try with 100-continue. */
20052b15cb3dSCy Schubert 
20062b15cb3dSCy Schubert 	/* Add the information that we care about */
20072b15cb3dSCy Schubert 	evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
20082b15cb3dSCy Schubert 	evhttp_add_header(evhttp_request_get_output_headers(req), "Expect", "100-continue");
20092b15cb3dSCy Schubert 	evbuffer_add_printf(evhttp_request_get_output_buffer(req), POST_DATA);
20102b15cb3dSCy Schubert 
20112b15cb3dSCy Schubert 	if (evhttp_make_request(evcon, req, EVHTTP_REQ_POST, "/postit") == -1) {
20122b15cb3dSCy Schubert 		tt_abort_msg("Couldn't make request");
20132b15cb3dSCy Schubert 	}
20142b15cb3dSCy Schubert 
20152b15cb3dSCy Schubert 	event_base_dispatch(data->base);
20162b15cb3dSCy Schubert 
20172b15cb3dSCy Schubert 	tt_int_op(test_ok, ==, 1);
20182b15cb3dSCy Schubert 
20192b15cb3dSCy Schubert 	evhttp_connection_free(evcon);
20202b15cb3dSCy Schubert 	evhttp_free(http);
20212b15cb3dSCy Schubert 
20222b15cb3dSCy Schubert  end:
20232b15cb3dSCy Schubert 	;
20242b15cb3dSCy Schubert }
20252b15cb3dSCy Schubert 
20262b15cb3dSCy Schubert void
http_post_cb(struct evhttp_request * req,void * arg)20272b15cb3dSCy Schubert http_post_cb(struct evhttp_request *req, void *arg)
20282b15cb3dSCy Schubert {
20292b15cb3dSCy Schubert 	struct evbuffer *evb;
2030*a466cc55SCy Schubert 	TT_BLATHER(("%s: called\n", __func__));
20312b15cb3dSCy Schubert 
20322b15cb3dSCy Schubert 	/* Yes, we are expecting a post request */
20332b15cb3dSCy Schubert 	if (evhttp_request_get_command(req) != EVHTTP_REQ_POST) {
20342b15cb3dSCy Schubert 		fprintf(stdout, "FAILED (post type)\n");
20352b15cb3dSCy Schubert 		exit(1);
20362b15cb3dSCy Schubert 	}
20372b15cb3dSCy Schubert 
20382b15cb3dSCy Schubert 	if (evbuffer_get_length(evhttp_request_get_input_buffer(req)) != strlen(POST_DATA)) {
20392b15cb3dSCy Schubert 		fprintf(stdout, "FAILED (length: %lu vs %lu)\n",
20402b15cb3dSCy Schubert 		    (unsigned long) evbuffer_get_length(evhttp_request_get_input_buffer(req)), (unsigned long) strlen(POST_DATA));
20412b15cb3dSCy Schubert 		exit(1);
20422b15cb3dSCy Schubert 	}
20432b15cb3dSCy Schubert 
20442b15cb3dSCy Schubert 	if (evbuffer_datacmp(evhttp_request_get_input_buffer(req), POST_DATA) != 0) {
20452b15cb3dSCy Schubert 		fprintf(stdout, "FAILED (data)\n");
20462b15cb3dSCy Schubert 		fprintf(stdout, "Got :%s\n", evbuffer_pullup(evhttp_request_get_input_buffer(req),-1));
20472b15cb3dSCy Schubert 		fprintf(stdout, "Want:%s\n", POST_DATA);
20482b15cb3dSCy Schubert 		exit(1);
20492b15cb3dSCy Schubert 	}
20502b15cb3dSCy Schubert 
20512b15cb3dSCy Schubert 	evb = evbuffer_new();
20522b15cb3dSCy Schubert 	evbuffer_add_printf(evb, BASIC_REQUEST_BODY);
20532b15cb3dSCy Schubert 
20542b15cb3dSCy Schubert 	evhttp_send_reply(req, HTTP_OK, "Everything is fine", evb);
20552b15cb3dSCy Schubert 
20562b15cb3dSCy Schubert 	evbuffer_free(evb);
20572b15cb3dSCy Schubert }
20582b15cb3dSCy Schubert 
20592b15cb3dSCy Schubert void
http_postrequest_done(struct evhttp_request * req,void * arg)20602b15cb3dSCy Schubert http_postrequest_done(struct evhttp_request *req, void *arg)
20612b15cb3dSCy Schubert {
20622b15cb3dSCy Schubert 	const char *what = BASIC_REQUEST_BODY;
20632b15cb3dSCy Schubert 	struct event_base *base = arg;
20642b15cb3dSCy Schubert 
20652b15cb3dSCy Schubert 	if (req == NULL) {
20662b15cb3dSCy Schubert 		fprintf(stderr, "FAILED (timeout)\n");
20672b15cb3dSCy Schubert 		exit(1);
20682b15cb3dSCy Schubert 	}
20692b15cb3dSCy Schubert 
20702b15cb3dSCy Schubert 	if (evhttp_request_get_response_code(req) != HTTP_OK) {
20712b15cb3dSCy Schubert 
20722b15cb3dSCy Schubert 		fprintf(stderr, "FAILED (response code)\n");
20732b15cb3dSCy Schubert 		exit(1);
20742b15cb3dSCy Schubert 	}
20752b15cb3dSCy Schubert 
20762b15cb3dSCy Schubert 	if (evhttp_find_header(evhttp_request_get_input_headers(req), "Content-Type") == NULL) {
20772b15cb3dSCy Schubert 		fprintf(stderr, "FAILED (content type)\n");
20782b15cb3dSCy Schubert 		exit(1);
20792b15cb3dSCy Schubert 	}
20802b15cb3dSCy Schubert 
20812b15cb3dSCy Schubert 	if (evbuffer_get_length(evhttp_request_get_input_buffer(req)) != strlen(what)) {
20822b15cb3dSCy Schubert 		fprintf(stderr, "FAILED (length %lu vs %lu)\n",
20832b15cb3dSCy Schubert 		    (unsigned long)evbuffer_get_length(evhttp_request_get_input_buffer(req)), (unsigned long)strlen(what));
20842b15cb3dSCy Schubert 		exit(1);
20852b15cb3dSCy Schubert 	}
20862b15cb3dSCy Schubert 
20872b15cb3dSCy Schubert 	if (evbuffer_datacmp(evhttp_request_get_input_buffer(req), what) != 0) {
20882b15cb3dSCy Schubert 		fprintf(stderr, "FAILED (data)\n");
20892b15cb3dSCy Schubert 		exit(1);
20902b15cb3dSCy Schubert 	}
20912b15cb3dSCy Schubert 
20922b15cb3dSCy Schubert 	test_ok = 1;
20932b15cb3dSCy Schubert 	event_base_loopexit(base, NULL);
20942b15cb3dSCy Schubert }
20952b15cb3dSCy Schubert 
20962b15cb3dSCy Schubert /*
20972b15cb3dSCy Schubert  * HTTP PUT test, basically just like POST, but ...
20982b15cb3dSCy Schubert  */
20992b15cb3dSCy Schubert 
21002b15cb3dSCy Schubert void http_putrequest_done(struct evhttp_request *, void *);
21012b15cb3dSCy Schubert 
21022b15cb3dSCy Schubert #define PUT_DATA "Hi, I'm some PUT data"
21032b15cb3dSCy Schubert 
21042b15cb3dSCy Schubert static void
http_put_test(void * arg)21052b15cb3dSCy Schubert http_put_test(void *arg)
21062b15cb3dSCy Schubert {
21072b15cb3dSCy Schubert 	struct basic_test_data *data = arg;
21082b15cb3dSCy Schubert 	ev_uint16_t port = 0;
21092b15cb3dSCy Schubert 	struct evhttp_connection *evcon = NULL;
21102b15cb3dSCy Schubert 	struct evhttp_request *req = NULL;
2111*a466cc55SCy Schubert 	struct evhttp *http = http_setup(&port, data->base, 0);
21122b15cb3dSCy Schubert 
21132b15cb3dSCy Schubert 	test_ok = 0;
21142b15cb3dSCy Schubert 
21152b15cb3dSCy Schubert 	evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port);
21162b15cb3dSCy Schubert 	tt_assert(evcon);
21172b15cb3dSCy Schubert 
21182b15cb3dSCy Schubert 	/*
21192b15cb3dSCy Schubert 	 * Schedule the HTTP PUT request
21202b15cb3dSCy Schubert 	 */
21212b15cb3dSCy Schubert 
21222b15cb3dSCy Schubert 	req = evhttp_request_new(http_putrequest_done, data->base);
21232b15cb3dSCy Schubert 	tt_assert(req);
21242b15cb3dSCy Schubert 
21252b15cb3dSCy Schubert 	/* Add the information that we care about */
21262b15cb3dSCy Schubert 	evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "someotherhost");
21272b15cb3dSCy Schubert 	evbuffer_add_printf(evhttp_request_get_output_buffer(req), PUT_DATA);
21282b15cb3dSCy Schubert 
21292b15cb3dSCy Schubert 	if (evhttp_make_request(evcon, req, EVHTTP_REQ_PUT, "/putit") == -1) {
21302b15cb3dSCy Schubert 		tt_abort_msg("Couldn't make request");
21312b15cb3dSCy Schubert 	}
21322b15cb3dSCy Schubert 
21332b15cb3dSCy Schubert 	event_base_dispatch(data->base);
21342b15cb3dSCy Schubert 
21352b15cb3dSCy Schubert 	evhttp_connection_free(evcon);
21362b15cb3dSCy Schubert 	evhttp_free(http);
21372b15cb3dSCy Schubert 
21382b15cb3dSCy Schubert 	tt_int_op(test_ok, ==, 1);
21392b15cb3dSCy Schubert  end:
21402b15cb3dSCy Schubert 	;
21412b15cb3dSCy Schubert }
21422b15cb3dSCy Schubert 
21432b15cb3dSCy Schubert void
http_put_cb(struct evhttp_request * req,void * arg)21442b15cb3dSCy Schubert http_put_cb(struct evhttp_request *req, void *arg)
21452b15cb3dSCy Schubert {
21462b15cb3dSCy Schubert 	struct evbuffer *evb;
2147*a466cc55SCy Schubert 	TT_BLATHER(("%s: called\n", __func__));
21482b15cb3dSCy Schubert 
21492b15cb3dSCy Schubert 	/* Expecting a PUT request */
21502b15cb3dSCy Schubert 	if (evhttp_request_get_command(req) != EVHTTP_REQ_PUT) {
21512b15cb3dSCy Schubert 		fprintf(stdout, "FAILED (put type)\n");
21522b15cb3dSCy Schubert 		exit(1);
21532b15cb3dSCy Schubert 	}
21542b15cb3dSCy Schubert 
21552b15cb3dSCy Schubert 	if (evbuffer_get_length(evhttp_request_get_input_buffer(req)) != strlen(PUT_DATA)) {
21562b15cb3dSCy Schubert 		fprintf(stdout, "FAILED (length: %lu vs %lu)\n",
21572b15cb3dSCy Schubert 		    (unsigned long)evbuffer_get_length(evhttp_request_get_input_buffer(req)), (unsigned long)strlen(PUT_DATA));
21582b15cb3dSCy Schubert 		exit(1);
21592b15cb3dSCy Schubert 	}
21602b15cb3dSCy Schubert 
21612b15cb3dSCy Schubert 	if (evbuffer_datacmp(evhttp_request_get_input_buffer(req), PUT_DATA) != 0) {
21622b15cb3dSCy Schubert 		fprintf(stdout, "FAILED (data)\n");
21632b15cb3dSCy Schubert 		fprintf(stdout, "Got :%s\n", evbuffer_pullup(evhttp_request_get_input_buffer(req),-1));
21642b15cb3dSCy Schubert 		fprintf(stdout, "Want:%s\n", PUT_DATA);
21652b15cb3dSCy Schubert 		exit(1);
21662b15cb3dSCy Schubert 	}
21672b15cb3dSCy Schubert 
21682b15cb3dSCy Schubert 	evb = evbuffer_new();
21692b15cb3dSCy Schubert 	evbuffer_add_printf(evb, "That ain't funny");
21702b15cb3dSCy Schubert 
21712b15cb3dSCy Schubert 	evhttp_send_reply(req, HTTP_OK, "Everything is great", evb);
21722b15cb3dSCy Schubert 
21732b15cb3dSCy Schubert 	evbuffer_free(evb);
21742b15cb3dSCy Schubert }
21752b15cb3dSCy Schubert 
21762b15cb3dSCy Schubert void
http_putrequest_done(struct evhttp_request * req,void * arg)21772b15cb3dSCy Schubert http_putrequest_done(struct evhttp_request *req, void *arg)
21782b15cb3dSCy Schubert {
21792b15cb3dSCy Schubert 	struct event_base *base = arg;
21802b15cb3dSCy Schubert 	const char *what = "That ain't funny";
21812b15cb3dSCy Schubert 
21822b15cb3dSCy Schubert 	if (req == NULL) {
21832b15cb3dSCy Schubert 		fprintf(stderr, "FAILED (timeout)\n");
21842b15cb3dSCy Schubert 		exit(1);
21852b15cb3dSCy Schubert 	}
21862b15cb3dSCy Schubert 
21872b15cb3dSCy Schubert 	if (evhttp_request_get_response_code(req) != HTTP_OK) {
21882b15cb3dSCy Schubert 
21892b15cb3dSCy Schubert 		fprintf(stderr, "FAILED (response code)\n");
21902b15cb3dSCy Schubert 		exit(1);
21912b15cb3dSCy Schubert 	}
21922b15cb3dSCy Schubert 
21932b15cb3dSCy Schubert 	if (evhttp_find_header(evhttp_request_get_input_headers(req), "Content-Type") == NULL) {
21942b15cb3dSCy Schubert 		fprintf(stderr, "FAILED (content type)\n");
21952b15cb3dSCy Schubert 		exit(1);
21962b15cb3dSCy Schubert 	}
21972b15cb3dSCy Schubert 
21982b15cb3dSCy Schubert 	if (evbuffer_get_length(evhttp_request_get_input_buffer(req)) != strlen(what)) {
21992b15cb3dSCy Schubert 		fprintf(stderr, "FAILED (length %lu vs %lu)\n",
22002b15cb3dSCy Schubert 		    (unsigned long)evbuffer_get_length(evhttp_request_get_input_buffer(req)), (unsigned long)strlen(what));
22012b15cb3dSCy Schubert 		exit(1);
22022b15cb3dSCy Schubert 	}
22032b15cb3dSCy Schubert 
22042b15cb3dSCy Schubert 
22052b15cb3dSCy Schubert 	if (evbuffer_datacmp(evhttp_request_get_input_buffer(req), what) != 0) {
22062b15cb3dSCy Schubert 		fprintf(stderr, "FAILED (data)\n");
22072b15cb3dSCy Schubert 		exit(1);
22082b15cb3dSCy Schubert 	}
22092b15cb3dSCy Schubert 
22102b15cb3dSCy Schubert 	test_ok = 1;
22112b15cb3dSCy Schubert 	event_base_loopexit(base, NULL);
22122b15cb3dSCy Schubert }
22132b15cb3dSCy Schubert 
22142b15cb3dSCy Schubert static void
http_failure_readcb(struct bufferevent * bev,void * arg)22152b15cb3dSCy Schubert http_failure_readcb(struct bufferevent *bev, void *arg)
22162b15cb3dSCy Schubert {
22172b15cb3dSCy Schubert 	const char *what = "400 Bad Request";
22182b15cb3dSCy Schubert 	if (evbuffer_contains(bufferevent_get_input(bev), what)) {
22192b15cb3dSCy Schubert 		test_ok = 2;
22202b15cb3dSCy Schubert 		bufferevent_disable(bev, EV_READ);
22212b15cb3dSCy Schubert 		event_base_loopexit(arg, NULL);
22222b15cb3dSCy Schubert 	}
22232b15cb3dSCy Schubert }
22242b15cb3dSCy Schubert 
22252b15cb3dSCy Schubert /*
22262b15cb3dSCy Schubert  * Testing that the HTTP server can deal with a malformed request.
22272b15cb3dSCy Schubert  */
22282b15cb3dSCy Schubert static void
http_failure_test(void * arg)22292b15cb3dSCy Schubert http_failure_test(void *arg)
22302b15cb3dSCy Schubert {
22312b15cb3dSCy Schubert 	struct basic_test_data *data = arg;
22322b15cb3dSCy Schubert 	struct bufferevent *bev;
2233*a466cc55SCy Schubert 	evutil_socket_t fd = EVUTIL_INVALID_SOCKET;
22342b15cb3dSCy Schubert 	const char *http_request;
22352b15cb3dSCy Schubert 	ev_uint16_t port = 0;
2236*a466cc55SCy Schubert 	struct evhttp *http = http_setup(&port, data->base, 0);
22372b15cb3dSCy Schubert 
22382b15cb3dSCy Schubert 	test_ok = 0;
22392b15cb3dSCy Schubert 
22402b15cb3dSCy Schubert 	fd = http_connect("127.0.0.1", port);
2241*a466cc55SCy Schubert 	tt_assert(fd != EVUTIL_INVALID_SOCKET);
22422b15cb3dSCy Schubert 
22432b15cb3dSCy Schubert 	/* Stupid thing to send a request */
22442b15cb3dSCy Schubert 	bev = bufferevent_socket_new(data->base, fd, 0);
22452b15cb3dSCy Schubert 	bufferevent_setcb(bev, http_failure_readcb, http_writecb,
22462b15cb3dSCy Schubert 	    http_errorcb, data->base);
22472b15cb3dSCy Schubert 
22482b15cb3dSCy Schubert 	http_request = "illegal request\r\n";
22492b15cb3dSCy Schubert 
22502b15cb3dSCy Schubert 	bufferevent_write(bev, http_request, strlen(http_request));
22512b15cb3dSCy Schubert 
22522b15cb3dSCy Schubert 	event_base_dispatch(data->base);
22532b15cb3dSCy Schubert 
22542b15cb3dSCy Schubert 	bufferevent_free(bev);
22552b15cb3dSCy Schubert 
22562b15cb3dSCy Schubert 	evhttp_free(http);
22572b15cb3dSCy Schubert 
22582b15cb3dSCy Schubert 	tt_int_op(test_ok, ==, 2);
22592b15cb3dSCy Schubert  end:
22602b15cb3dSCy Schubert 	if (fd >= 0)
22612b15cb3dSCy Schubert 		evutil_closesocket(fd);
22622b15cb3dSCy Schubert }
22632b15cb3dSCy Schubert 
22642b15cb3dSCy Schubert static void
close_detect_done(struct evhttp_request * req,void * arg)22652b15cb3dSCy Schubert close_detect_done(struct evhttp_request *req, void *arg)
22662b15cb3dSCy Schubert {
22672b15cb3dSCy Schubert 	struct timeval tv;
22682b15cb3dSCy Schubert 	tt_assert(req);
22692b15cb3dSCy Schubert 	tt_assert(evhttp_request_get_response_code(req) == HTTP_OK);
22702b15cb3dSCy Schubert 
22712b15cb3dSCy Schubert 	test_ok = 1;
22722b15cb3dSCy Schubert 
22732b15cb3dSCy Schubert  end:
22742b15cb3dSCy Schubert 	evutil_timerclear(&tv);
22752b15cb3dSCy Schubert 	tv.tv_usec = 150000;
22762b15cb3dSCy Schubert 	event_base_loopexit(arg, &tv);
22772b15cb3dSCy Schubert }
22782b15cb3dSCy Schubert 
22792b15cb3dSCy Schubert static void
close_detect_launch(evutil_socket_t fd,short what,void * arg)22802b15cb3dSCy Schubert close_detect_launch(evutil_socket_t fd, short what, void *arg)
22812b15cb3dSCy Schubert {
22822b15cb3dSCy Schubert 	struct evhttp_connection *evcon = arg;
22832b15cb3dSCy Schubert 	struct event_base *base = evhttp_connection_get_base(evcon);
22842b15cb3dSCy Schubert 	struct evhttp_request *req;
22852b15cb3dSCy Schubert 
22862b15cb3dSCy Schubert 	req = evhttp_request_new(close_detect_done, base);
22872b15cb3dSCy Schubert 
22882b15cb3dSCy Schubert 	/* Add the information that we care about */
22892b15cb3dSCy Schubert 	evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
22902b15cb3dSCy Schubert 
22912b15cb3dSCy Schubert 	/* We give ownership of the request to the connection */
22922b15cb3dSCy Schubert 	if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test") == -1) {
22932b15cb3dSCy Schubert 		tt_fail_msg("Couldn't make request");
22942b15cb3dSCy Schubert 	}
22952b15cb3dSCy Schubert }
22962b15cb3dSCy Schubert 
22972b15cb3dSCy Schubert static void
close_detect_cb(struct evhttp_request * req,void * arg)22982b15cb3dSCy Schubert close_detect_cb(struct evhttp_request *req, void *arg)
22992b15cb3dSCy Schubert {
23002b15cb3dSCy Schubert 	struct evhttp_connection *evcon = arg;
23012b15cb3dSCy Schubert 	struct event_base *base = evhttp_connection_get_base(evcon);
23022b15cb3dSCy Schubert 	struct timeval tv;
23032b15cb3dSCy Schubert 
23042b15cb3dSCy Schubert 	if (req != NULL && evhttp_request_get_response_code(req) != HTTP_OK) {
23052b15cb3dSCy Schubert 		tt_abort_msg("Failed");
23062b15cb3dSCy Schubert 	}
23072b15cb3dSCy Schubert 
23082b15cb3dSCy Schubert 	evutil_timerclear(&tv);
23092b15cb3dSCy Schubert 	tv.tv_sec = 0;   /* longer than the http time out */
23102b15cb3dSCy Schubert 	tv.tv_usec = 600000;   /* longer than the http time out */
23112b15cb3dSCy Schubert 
23122b15cb3dSCy Schubert 	/* launch a new request on the persistent connection in .3 seconds */
23132b15cb3dSCy Schubert 	event_base_once(base, -1, EV_TIMEOUT, close_detect_launch, evcon, &tv);
23142b15cb3dSCy Schubert  end:
23152b15cb3dSCy Schubert 	;
23162b15cb3dSCy Schubert }
23172b15cb3dSCy Schubert 
23182b15cb3dSCy Schubert 
23192b15cb3dSCy Schubert static void
http_close_detection_(struct basic_test_data * data,int with_delay)23202b15cb3dSCy Schubert http_close_detection_(struct basic_test_data *data, int with_delay)
23212b15cb3dSCy Schubert {
23222b15cb3dSCy Schubert 	ev_uint16_t port = 0;
23232b15cb3dSCy Schubert 	struct evhttp_connection *evcon = NULL;
23242b15cb3dSCy Schubert 	struct evhttp_request *req = NULL;
23252b15cb3dSCy Schubert 	const struct timeval sec_tenth = { 0, 100000 };
2326*a466cc55SCy Schubert 	struct evhttp *http = http_setup(&port, data->base, 0);
23272b15cb3dSCy Schubert 
23282b15cb3dSCy Schubert 	test_ok = 0;
23292b15cb3dSCy Schubert 
23302b15cb3dSCy Schubert 	/* .1 second timeout */
23312b15cb3dSCy Schubert 	evhttp_set_timeout_tv(http, &sec_tenth);
23322b15cb3dSCy Schubert 
23332b15cb3dSCy Schubert 	evcon = evhttp_connection_base_new(data->base, NULL,
23342b15cb3dSCy Schubert 	    "127.0.0.1", port);
23352b15cb3dSCy Schubert 	tt_assert(evcon);
23362b15cb3dSCy Schubert 	evhttp_connection_set_timeout_tv(evcon, &sec_tenth);
23372b15cb3dSCy Schubert 
23382b15cb3dSCy Schubert 
23392b15cb3dSCy Schubert 	tt_assert(evcon);
23402b15cb3dSCy Schubert 	delayed_client = evcon;
23412b15cb3dSCy Schubert 
23422b15cb3dSCy Schubert 	/*
23432b15cb3dSCy Schubert 	 * At this point, we want to schedule a request to the HTTP
23442b15cb3dSCy Schubert 	 * server using our make request method.
23452b15cb3dSCy Schubert 	 */
23462b15cb3dSCy Schubert 
23472b15cb3dSCy Schubert 	req = evhttp_request_new(close_detect_cb, evcon);
23482b15cb3dSCy Schubert 
23492b15cb3dSCy Schubert 	/* Add the information that we care about */
23502b15cb3dSCy Schubert 	evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
23512b15cb3dSCy Schubert 
23522b15cb3dSCy Schubert 	/* We give ownership of the request to the connection */
23532b15cb3dSCy Schubert 	if (evhttp_make_request(evcon,
23542b15cb3dSCy Schubert 	    req, EVHTTP_REQ_GET, with_delay ? "/largedelay" : "/test") == -1) {
23552b15cb3dSCy Schubert 		tt_abort_msg("couldn't make request");
23562b15cb3dSCy Schubert 	}
23572b15cb3dSCy Schubert 
23582b15cb3dSCy Schubert 	event_base_dispatch(data->base);
23592b15cb3dSCy Schubert 
23602b15cb3dSCy Schubert 	/* at this point, the http server should have no connection */
23612b15cb3dSCy Schubert 	tt_assert(TAILQ_FIRST(&http->connections) == NULL);
23622b15cb3dSCy Schubert 
23632b15cb3dSCy Schubert  end:
23642b15cb3dSCy Schubert 	if (evcon)
23652b15cb3dSCy Schubert 		evhttp_connection_free(evcon);
23662b15cb3dSCy Schubert 	if (http)
23672b15cb3dSCy Schubert 		evhttp_free(http);
23682b15cb3dSCy Schubert }
23692b15cb3dSCy Schubert static void
http_close_detection_test(void * arg)23702b15cb3dSCy Schubert http_close_detection_test(void *arg)
23712b15cb3dSCy Schubert {
23722b15cb3dSCy Schubert 	http_close_detection_(arg, 0);
23732b15cb3dSCy Schubert }
23742b15cb3dSCy Schubert static void
http_close_detection_delay_test(void * arg)23752b15cb3dSCy Schubert http_close_detection_delay_test(void *arg)
23762b15cb3dSCy Schubert {
23772b15cb3dSCy Schubert 	http_close_detection_(arg, 1);
23782b15cb3dSCy Schubert }
23792b15cb3dSCy Schubert 
23802b15cb3dSCy Schubert static void
http_highport_test(void * arg)23812b15cb3dSCy Schubert http_highport_test(void *arg)
23822b15cb3dSCy Schubert {
23832b15cb3dSCy Schubert 	struct basic_test_data *data = arg;
23842b15cb3dSCy Schubert 	int i = -1;
23852b15cb3dSCy Schubert 	struct evhttp *myhttp = NULL;
23862b15cb3dSCy Schubert 
23872b15cb3dSCy Schubert 	/* Try a few different ports */
23882b15cb3dSCy Schubert 	for (i = 0; i < 50; ++i) {
23892b15cb3dSCy Schubert 		myhttp = evhttp_new(data->base);
23902b15cb3dSCy Schubert 		if (evhttp_bind_socket(myhttp, "127.0.0.1", 65535 - i) == 0) {
23912b15cb3dSCy Schubert 			test_ok = 1;
23922b15cb3dSCy Schubert 			evhttp_free(myhttp);
23932b15cb3dSCy Schubert 			return;
23942b15cb3dSCy Schubert 		}
23952b15cb3dSCy Schubert 		evhttp_free(myhttp);
23962b15cb3dSCy Schubert 	}
23972b15cb3dSCy Schubert 
23982b15cb3dSCy Schubert 	tt_fail_msg("Couldn't get a high port");
23992b15cb3dSCy Schubert }
24002b15cb3dSCy Schubert 
24012b15cb3dSCy Schubert static void
http_bad_header_test(void * ptr)24022b15cb3dSCy Schubert http_bad_header_test(void *ptr)
24032b15cb3dSCy Schubert {
24042b15cb3dSCy Schubert 	struct evkeyvalq headers;
24052b15cb3dSCy Schubert 
24062b15cb3dSCy Schubert 	TAILQ_INIT(&headers);
24072b15cb3dSCy Schubert 
24082b15cb3dSCy Schubert 	tt_want(evhttp_add_header(&headers, "One", "Two") == 0);
24092b15cb3dSCy Schubert 	tt_want(evhttp_add_header(&headers, "One", "Two\r\n Three") == 0);
24102b15cb3dSCy Schubert 	tt_want(evhttp_add_header(&headers, "One\r", "Two") == -1);
24112b15cb3dSCy Schubert 	tt_want(evhttp_add_header(&headers, "One\n", "Two") == -1);
24122b15cb3dSCy Schubert 	tt_want(evhttp_add_header(&headers, "One", "Two\r") == -1);
24132b15cb3dSCy Schubert 	tt_want(evhttp_add_header(&headers, "One", "Two\n") == -1);
24142b15cb3dSCy Schubert 
24152b15cb3dSCy Schubert 	evhttp_clear_headers(&headers);
24162b15cb3dSCy Schubert }
24172b15cb3dSCy Schubert 
validate_header(const struct evkeyvalq * headers,const char * key,const char * value)24182b15cb3dSCy Schubert static int validate_header(
24192b15cb3dSCy Schubert 	const struct evkeyvalq* headers,
24202b15cb3dSCy Schubert 	const char *key, const char *value)
24212b15cb3dSCy Schubert {
24222b15cb3dSCy Schubert 	const char *real_val = evhttp_find_header(headers, key);
24232b15cb3dSCy Schubert 	tt_assert(real_val != NULL);
24242b15cb3dSCy Schubert 	tt_want(strcmp(real_val, value) == 0);
24252b15cb3dSCy Schubert end:
24262b15cb3dSCy Schubert 	return (0);
24272b15cb3dSCy Schubert }
24282b15cb3dSCy Schubert 
24292b15cb3dSCy Schubert static void
http_parse_query_test(void * ptr)24302b15cb3dSCy Schubert http_parse_query_test(void *ptr)
24312b15cb3dSCy Schubert {
24322b15cb3dSCy Schubert 	struct evkeyvalq headers;
24332b15cb3dSCy Schubert 	int r;
24342b15cb3dSCy Schubert 
24352b15cb3dSCy Schubert 	TAILQ_INIT(&headers);
24362b15cb3dSCy Schubert 
24372b15cb3dSCy Schubert 	r = evhttp_parse_query("http://www.test.com/?q=test", &headers);
24382b15cb3dSCy Schubert 	tt_want(validate_header(&headers, "q", "test") == 0);
24392b15cb3dSCy Schubert 	tt_int_op(r, ==, 0);
24402b15cb3dSCy Schubert 	evhttp_clear_headers(&headers);
24412b15cb3dSCy Schubert 
24422b15cb3dSCy Schubert 	r = evhttp_parse_query("http://www.test.com/?q=test&foo=bar", &headers);
24432b15cb3dSCy Schubert 	tt_want(validate_header(&headers, "q", "test") == 0);
24442b15cb3dSCy Schubert 	tt_want(validate_header(&headers, "foo", "bar") == 0);
24452b15cb3dSCy Schubert 	tt_int_op(r, ==, 0);
24462b15cb3dSCy Schubert 	evhttp_clear_headers(&headers);
24472b15cb3dSCy Schubert 
24482b15cb3dSCy Schubert 	r = evhttp_parse_query("http://www.test.com/?q=test+foo", &headers);
24492b15cb3dSCy Schubert 	tt_want(validate_header(&headers, "q", "test foo") == 0);
24502b15cb3dSCy Schubert 	tt_int_op(r, ==, 0);
24512b15cb3dSCy Schubert 	evhttp_clear_headers(&headers);
24522b15cb3dSCy Schubert 
24532b15cb3dSCy Schubert 	r = evhttp_parse_query("http://www.test.com/?q=test%0Afoo", &headers);
24542b15cb3dSCy Schubert 	tt_want(validate_header(&headers, "q", "test\nfoo") == 0);
24552b15cb3dSCy Schubert 	tt_int_op(r, ==, 0);
24562b15cb3dSCy Schubert 	evhttp_clear_headers(&headers);
24572b15cb3dSCy Schubert 
24582b15cb3dSCy Schubert 	r = evhttp_parse_query("http://www.test.com/?q=test%0Dfoo", &headers);
24592b15cb3dSCy Schubert 	tt_want(validate_header(&headers, "q", "test\rfoo") == 0);
24602b15cb3dSCy Schubert 	tt_int_op(r, ==, 0);
24612b15cb3dSCy Schubert 	evhttp_clear_headers(&headers);
24622b15cb3dSCy Schubert 
24632b15cb3dSCy Schubert 	r = evhttp_parse_query("http://www.test.com/?q=test&&q2", &headers);
24642b15cb3dSCy Schubert 	tt_int_op(r, ==, -1);
24652b15cb3dSCy Schubert 	evhttp_clear_headers(&headers);
24662b15cb3dSCy Schubert 
24672b15cb3dSCy Schubert 	r = evhttp_parse_query("http://www.test.com/?q=test+this", &headers);
24682b15cb3dSCy Schubert 	tt_want(validate_header(&headers, "q", "test this") == 0);
24692b15cb3dSCy Schubert 	tt_int_op(r, ==, 0);
24702b15cb3dSCy Schubert 	evhttp_clear_headers(&headers);
24712b15cb3dSCy Schubert 
24722b15cb3dSCy Schubert 	r = evhttp_parse_query("http://www.test.com/?q=test&q2=foo", &headers);
24732b15cb3dSCy Schubert 	tt_int_op(r, ==, 0);
24742b15cb3dSCy Schubert 	tt_want(validate_header(&headers, "q", "test") == 0);
24752b15cb3dSCy Schubert 	tt_want(validate_header(&headers, "q2", "foo") == 0);
24762b15cb3dSCy Schubert 	evhttp_clear_headers(&headers);
24772b15cb3dSCy Schubert 
24782b15cb3dSCy Schubert 	r = evhttp_parse_query("http://www.test.com/?q&q2=foo", &headers);
24792b15cb3dSCy Schubert 	tt_int_op(r, ==, -1);
24802b15cb3dSCy Schubert 	evhttp_clear_headers(&headers);
24812b15cb3dSCy Schubert 
24822b15cb3dSCy Schubert 	r = evhttp_parse_query("http://www.test.com/?q=foo&q2", &headers);
24832b15cb3dSCy Schubert 	tt_int_op(r, ==, -1);
24842b15cb3dSCy Schubert 	evhttp_clear_headers(&headers);
24852b15cb3dSCy Schubert 
24862b15cb3dSCy Schubert 	r = evhttp_parse_query("http://www.test.com/?q=foo&q2&q3=x", &headers);
24872b15cb3dSCy Schubert 	tt_int_op(r, ==, -1);
24882b15cb3dSCy Schubert 	evhttp_clear_headers(&headers);
24892b15cb3dSCy Schubert 
24902b15cb3dSCy Schubert 	r = evhttp_parse_query("http://www.test.com/?q=&q2=&q3=", &headers);
24912b15cb3dSCy Schubert 	tt_int_op(r, ==, 0);
24922b15cb3dSCy Schubert 	tt_want(validate_header(&headers, "q", "") == 0);
24932b15cb3dSCy Schubert 	tt_want(validate_header(&headers, "q2", "") == 0);
24942b15cb3dSCy Schubert 	tt_want(validate_header(&headers, "q3", "") == 0);
24952b15cb3dSCy Schubert 	evhttp_clear_headers(&headers);
24962b15cb3dSCy Schubert 
24972b15cb3dSCy Schubert end:
24982b15cb3dSCy Schubert 	evhttp_clear_headers(&headers);
24992b15cb3dSCy Schubert }
2500*a466cc55SCy Schubert static void
http_parse_query_str_test(void * ptr)2501*a466cc55SCy Schubert http_parse_query_str_test(void *ptr)
2502*a466cc55SCy Schubert {
2503*a466cc55SCy Schubert 	struct evkeyvalq headers;
2504*a466cc55SCy Schubert 	int r;
2505*a466cc55SCy Schubert 
2506*a466cc55SCy Schubert 	TAILQ_INIT(&headers);
2507*a466cc55SCy Schubert 
2508*a466cc55SCy Schubert 	r = evhttp_parse_query_str("http://www.test.com/?q=test", &headers);
2509*a466cc55SCy Schubert 	tt_assert(evhttp_find_header(&headers, "q") == NULL);
2510*a466cc55SCy Schubert 	tt_int_op(r, ==, 0);
2511*a466cc55SCy Schubert 	evhttp_clear_headers(&headers);
2512*a466cc55SCy Schubert 
2513*a466cc55SCy Schubert 	r = evhttp_parse_query_str("q=test", &headers);
2514*a466cc55SCy Schubert 	tt_want(validate_header(&headers, "q", "test") == 0);
2515*a466cc55SCy Schubert 	tt_int_op(r, ==, 0);
2516*a466cc55SCy Schubert 	evhttp_clear_headers(&headers);
2517*a466cc55SCy Schubert 
2518*a466cc55SCy Schubert end:
2519*a466cc55SCy Schubert 	evhttp_clear_headers(&headers);
2520*a466cc55SCy Schubert }
25212b15cb3dSCy Schubert 
25222b15cb3dSCy Schubert static void
http_parse_uri_test(void * ptr)25232b15cb3dSCy Schubert http_parse_uri_test(void *ptr)
25242b15cb3dSCy Schubert {
25252b15cb3dSCy Schubert 	const int nonconform = (ptr != NULL);
25262b15cb3dSCy Schubert 	const unsigned parse_flags =
25272b15cb3dSCy Schubert 	    nonconform ? EVHTTP_URI_NONCONFORMANT : 0;
25282b15cb3dSCy Schubert 	struct evhttp_uri *uri = NULL;
25292b15cb3dSCy Schubert 	char url_tmp[4096];
25302b15cb3dSCy Schubert #define URI_PARSE(uri) \
25312b15cb3dSCy Schubert 	evhttp_uri_parse_with_flags((uri), parse_flags)
25322b15cb3dSCy Schubert 
25332b15cb3dSCy Schubert #define TT_URI(want) do { 						\
25342b15cb3dSCy Schubert 	char *ret = evhttp_uri_join(uri, url_tmp, sizeof(url_tmp));	\
25352b15cb3dSCy Schubert 	tt_want(ret != NULL);						\
25362b15cb3dSCy Schubert 	tt_want(ret == url_tmp);					\
25372b15cb3dSCy Schubert 	if (strcmp(ret,want) != 0)					\
25382b15cb3dSCy Schubert 		TT_FAIL(("\"%s\" != \"%s\"",ret,want));			\
25392b15cb3dSCy Schubert 	} while(0)
25402b15cb3dSCy Schubert 
25412b15cb3dSCy Schubert 	tt_want(evhttp_uri_join(NULL, 0, 0) == NULL);
25422b15cb3dSCy Schubert 	tt_want(evhttp_uri_join(NULL, url_tmp, 0) == NULL);
25432b15cb3dSCy Schubert 	tt_want(evhttp_uri_join(NULL, url_tmp, sizeof(url_tmp)) == NULL);
25442b15cb3dSCy Schubert 
25452b15cb3dSCy Schubert 	/* bad URIs: parsing */
25462b15cb3dSCy Schubert #define BAD(s) do {							\
25472b15cb3dSCy Schubert 		if (URI_PARSE(s) != NULL)				\
25482b15cb3dSCy Schubert 			TT_FAIL(("Expected error parsing \"%s\"",s));	\
25492b15cb3dSCy Schubert 	} while(0)
25502b15cb3dSCy Schubert 	/* Nonconformant URIs we can parse: parsing */
25512b15cb3dSCy Schubert #define NCF(s) do {							\
25522b15cb3dSCy Schubert 		uri = URI_PARSE(s);					\
25532b15cb3dSCy Schubert 		if (uri != NULL && !nonconform) {			\
25542b15cb3dSCy Schubert 			TT_FAIL(("Expected error parsing \"%s\"",s));	\
25552b15cb3dSCy Schubert 		} else if (uri == NULL && nonconform) {			\
25562b15cb3dSCy Schubert 			TT_FAIL(("Couldn't parse nonconformant URI \"%s\"", \
25572b15cb3dSCy Schubert 				s));					\
25582b15cb3dSCy Schubert 		}							\
25592b15cb3dSCy Schubert 		if (uri) {						\
25602b15cb3dSCy Schubert 			tt_want(evhttp_uri_join(uri, url_tmp,		\
25612b15cb3dSCy Schubert 				sizeof(url_tmp)));			\
25622b15cb3dSCy Schubert 			evhttp_uri_free(uri);				\
25632b15cb3dSCy Schubert 		}							\
25642b15cb3dSCy Schubert 	} while(0)
25652b15cb3dSCy Schubert 
25662b15cb3dSCy Schubert 	NCF("http://www.test.com/ why hello");
25672b15cb3dSCy Schubert 	NCF("http://www.test.com/why-hello\x01");
25682b15cb3dSCy Schubert 	NCF("http://www.test.com/why-hello?\x01");
25692b15cb3dSCy Schubert 	NCF("http://www.test.com/why-hello#\x01");
25702b15cb3dSCy Schubert 	BAD("http://www.\x01.test.com/why-hello");
25712b15cb3dSCy Schubert 	BAD("http://www.%7test.com/why-hello");
25722b15cb3dSCy Schubert 	NCF("http://www.test.com/why-hell%7o");
25732b15cb3dSCy Schubert 	BAD("h%3ttp://www.test.com/why-hello");
25742b15cb3dSCy Schubert 	NCF("http://www.test.com/why-hello%7");
25752b15cb3dSCy Schubert 	NCF("http://www.test.com/why-hell%7o");
25762b15cb3dSCy Schubert 	NCF("http://www.test.com/foo?ba%r");
25772b15cb3dSCy Schubert 	NCF("http://www.test.com/foo#ba%r");
25782b15cb3dSCy Schubert 	BAD("99:99/foo");
25792b15cb3dSCy Schubert 	BAD("http://www.test.com:999x/");
25802b15cb3dSCy Schubert 	BAD("http://www.test.com:x/");
25812b15cb3dSCy Schubert 	BAD("http://[hello-there]/");
25822b15cb3dSCy Schubert 	BAD("http://[::1]]/");
25832b15cb3dSCy Schubert 	BAD("http://[::1/");
25842b15cb3dSCy Schubert 	BAD("http://[foob/");
25852b15cb3dSCy Schubert 	BAD("http://[/");
25862b15cb3dSCy Schubert 	BAD("http://[ffff:ffff:ffff:ffff:Ffff:ffff:ffff:"
25872b15cb3dSCy Schubert 	            "ffff:ffff:ffff:ffff:ffff:ffff:ffff]/");
25882b15cb3dSCy Schubert 	BAD("http://[vX.foo]/");
25892b15cb3dSCy Schubert 	BAD("http://[vX.foo]/");
25902b15cb3dSCy Schubert 	BAD("http://[v.foo]/");
25912b15cb3dSCy Schubert 	BAD("http://[v5.fo%o]/");
25922b15cb3dSCy Schubert 	BAD("http://[v5X]/");
25932b15cb3dSCy Schubert 	BAD("http://[v5]/");
25942b15cb3dSCy Schubert 	BAD("http://[]/");
25952b15cb3dSCy Schubert 	BAD("http://f\x01red@www.example.com/");
25962b15cb3dSCy Schubert 	BAD("http://f%0red@www.example.com/");
25972b15cb3dSCy Schubert 	BAD("http://www.example.com:9999999999999999999999999999999999999/");
25982b15cb3dSCy Schubert 	BAD("http://www.example.com:hihi/");
25992b15cb3dSCy Schubert 	BAD("://www.example.com/");
26002b15cb3dSCy Schubert 
26012b15cb3dSCy Schubert 	/* bad URIs: joining */
26022b15cb3dSCy Schubert 	uri = evhttp_uri_new();
26032b15cb3dSCy Schubert 	tt_want(0==evhttp_uri_set_host(uri, "www.example.com"));
26042b15cb3dSCy Schubert 	tt_want(evhttp_uri_join(uri, url_tmp, sizeof(url_tmp)) != NULL);
26052b15cb3dSCy Schubert 	/* not enough space: */
26062b15cb3dSCy Schubert 	tt_want(evhttp_uri_join(uri, url_tmp, 3) == NULL);
26072b15cb3dSCy Schubert 	/* host is set, but path doesn't start with "/": */
26082b15cb3dSCy Schubert 	tt_want(0==evhttp_uri_set_path(uri, "hi_mom"));
26092b15cb3dSCy Schubert 	tt_want(evhttp_uri_join(uri, url_tmp, sizeof(url_tmp)) == NULL);
26102b15cb3dSCy Schubert 	tt_want(evhttp_uri_join(uri, NULL, sizeof(url_tmp))==NULL);
26112b15cb3dSCy Schubert 	tt_want(evhttp_uri_join(uri, url_tmp, 0)==NULL);
26122b15cb3dSCy Schubert 	evhttp_uri_free(uri);
26132b15cb3dSCy Schubert 	uri = URI_PARSE("mailto:foo@bar");
26142b15cb3dSCy Schubert 	tt_want(uri != NULL);
26152b15cb3dSCy Schubert 	tt_want(evhttp_uri_get_host(uri) == NULL);
26162b15cb3dSCy Schubert 	tt_want(evhttp_uri_get_userinfo(uri) == NULL);
26172b15cb3dSCy Schubert 	tt_want(evhttp_uri_get_port(uri) == -1);
26182b15cb3dSCy Schubert 	tt_want(!strcmp(evhttp_uri_get_scheme(uri), "mailto"));
26192b15cb3dSCy Schubert 	tt_want(!strcmp(evhttp_uri_get_path(uri), "foo@bar"));
26202b15cb3dSCy Schubert 	tt_want(evhttp_uri_get_query(uri) == NULL);
26212b15cb3dSCy Schubert 	tt_want(evhttp_uri_get_fragment(uri) == NULL);
26222b15cb3dSCy Schubert 	TT_URI("mailto:foo@bar");
26232b15cb3dSCy Schubert 	evhttp_uri_free(uri);
26242b15cb3dSCy Schubert 
26252b15cb3dSCy Schubert 	uri = evhttp_uri_new();
26262b15cb3dSCy Schubert 	/* Bad URI usage: setting invalid values */
26272b15cb3dSCy Schubert 	tt_want(-1 == evhttp_uri_set_scheme(uri,""));
26282b15cb3dSCy Schubert 	tt_want(-1 == evhttp_uri_set_scheme(uri,"33"));
26292b15cb3dSCy Schubert 	tt_want(-1 == evhttp_uri_set_scheme(uri,"hi!"));
26302b15cb3dSCy Schubert 	tt_want(-1 == evhttp_uri_set_userinfo(uri,"hello@"));
26312b15cb3dSCy Schubert 	tt_want(-1 == evhttp_uri_set_host(uri,"[1.2.3.4]"));
26322b15cb3dSCy Schubert 	tt_want(-1 == evhttp_uri_set_host(uri,"["));
26332b15cb3dSCy Schubert 	tt_want(-1 == evhttp_uri_set_host(uri,"www.[foo].com"));
26342b15cb3dSCy Schubert 	tt_want(-1 == evhttp_uri_set_port(uri,-3));
26352b15cb3dSCy Schubert 	tt_want(-1 == evhttp_uri_set_path(uri,"hello?world"));
26362b15cb3dSCy Schubert 	tt_want(-1 == evhttp_uri_set_query(uri,"hello#world"));
26372b15cb3dSCy Schubert 	tt_want(-1 == evhttp_uri_set_fragment(uri,"hello#world"));
26382b15cb3dSCy Schubert 	/* Valid URI usage: setting valid values */
26392b15cb3dSCy Schubert 	tt_want(0 == evhttp_uri_set_scheme(uri,"http"));
26402b15cb3dSCy Schubert 	tt_want(0 == evhttp_uri_set_scheme(uri,NULL));
26412b15cb3dSCy Schubert 	tt_want(0 == evhttp_uri_set_userinfo(uri,"username:pass"));
26422b15cb3dSCy Schubert 	tt_want(0 == evhttp_uri_set_userinfo(uri,NULL));
26432b15cb3dSCy Schubert 	tt_want(0 == evhttp_uri_set_host(uri,"www.example.com"));
26442b15cb3dSCy Schubert 	tt_want(0 == evhttp_uri_set_host(uri,"1.2.3.4"));
26452b15cb3dSCy Schubert 	tt_want(0 == evhttp_uri_set_host(uri,"[1:2:3:4::]"));
26462b15cb3dSCy Schubert 	tt_want(0 == evhttp_uri_set_host(uri,"[v7.wobblewobble]"));
26472b15cb3dSCy Schubert 	tt_want(0 == evhttp_uri_set_host(uri,NULL));
26482b15cb3dSCy Schubert 	tt_want(0 == evhttp_uri_set_host(uri,""));
26492b15cb3dSCy Schubert 	tt_want(0 == evhttp_uri_set_port(uri, -1));
26502b15cb3dSCy Schubert 	tt_want(0 == evhttp_uri_set_port(uri, 80));
26512b15cb3dSCy Schubert 	tt_want(0 == evhttp_uri_set_port(uri, 65535));
26522b15cb3dSCy Schubert 	tt_want(0 == evhttp_uri_set_path(uri, ""));
26532b15cb3dSCy Schubert 	tt_want(0 == evhttp_uri_set_path(uri, "/documents/public/index.html"));
26542b15cb3dSCy Schubert 	tt_want(0 == evhttp_uri_set_path(uri, NULL));
26552b15cb3dSCy Schubert 	tt_want(0 == evhttp_uri_set_query(uri, "key=val&key2=val2"));
26562b15cb3dSCy Schubert 	tt_want(0 == evhttp_uri_set_query(uri, "keyvalblarg"));
26572b15cb3dSCy Schubert 	tt_want(0 == evhttp_uri_set_query(uri, ""));
26582b15cb3dSCy Schubert 	tt_want(0 == evhttp_uri_set_query(uri, NULL));
26592b15cb3dSCy Schubert 	tt_want(0 == evhttp_uri_set_fragment(uri, ""));
26602b15cb3dSCy Schubert 	tt_want(0 == evhttp_uri_set_fragment(uri, "here?i?am"));
26612b15cb3dSCy Schubert 	tt_want(0 == evhttp_uri_set_fragment(uri, NULL));
26622b15cb3dSCy Schubert 	evhttp_uri_free(uri);
26632b15cb3dSCy Schubert 
26642b15cb3dSCy Schubert 	/* Valid parsing */
26652b15cb3dSCy Schubert 	uri = URI_PARSE("http://www.test.com/?q=t%33est");
26662b15cb3dSCy Schubert 	tt_want(strcmp(evhttp_uri_get_scheme(uri), "http") == 0);
26672b15cb3dSCy Schubert 	tt_want(strcmp(evhttp_uri_get_host(uri), "www.test.com") == 0);
26682b15cb3dSCy Schubert 	tt_want(strcmp(evhttp_uri_get_path(uri), "/") == 0);
26692b15cb3dSCy Schubert 	tt_want(strcmp(evhttp_uri_get_query(uri), "q=t%33est") == 0);
26702b15cb3dSCy Schubert 	tt_want(evhttp_uri_get_userinfo(uri) == NULL);
26712b15cb3dSCy Schubert 	tt_want(evhttp_uri_get_port(uri) == -1);
26722b15cb3dSCy Schubert 	tt_want(evhttp_uri_get_fragment(uri) == NULL);
26732b15cb3dSCy Schubert 	TT_URI("http://www.test.com/?q=t%33est");
26742b15cb3dSCy Schubert 	evhttp_uri_free(uri);
26752b15cb3dSCy Schubert 
26762b15cb3dSCy Schubert 	uri = URI_PARSE("http://%77ww.test.com");
26772b15cb3dSCy Schubert 	tt_want(strcmp(evhttp_uri_get_scheme(uri), "http") == 0);
26782b15cb3dSCy Schubert 	tt_want(strcmp(evhttp_uri_get_host(uri), "%77ww.test.com") == 0);
26792b15cb3dSCy Schubert 	tt_want(strcmp(evhttp_uri_get_path(uri), "") == 0);
26802b15cb3dSCy Schubert 	tt_want(evhttp_uri_get_query(uri) == NULL);
26812b15cb3dSCy Schubert 	tt_want(evhttp_uri_get_userinfo(uri) == NULL);
26822b15cb3dSCy Schubert 	tt_want(evhttp_uri_get_port(uri) == -1);
26832b15cb3dSCy Schubert 	tt_want(evhttp_uri_get_fragment(uri) == NULL);
26842b15cb3dSCy Schubert 	TT_URI("http://%77ww.test.com");
26852b15cb3dSCy Schubert 	evhttp_uri_free(uri);
26862b15cb3dSCy Schubert 
26872b15cb3dSCy Schubert 	uri = URI_PARSE("http://www.test.com?q=test");
26882b15cb3dSCy Schubert 	tt_want(strcmp(evhttp_uri_get_scheme(uri), "http") == 0);
26892b15cb3dSCy Schubert 	tt_want(strcmp(evhttp_uri_get_host(uri), "www.test.com") == 0);
26902b15cb3dSCy Schubert 	tt_want(strcmp(evhttp_uri_get_path(uri), "") == 0);
26912b15cb3dSCy Schubert 	tt_want(strcmp(evhttp_uri_get_query(uri), "q=test") == 0);
26922b15cb3dSCy Schubert 	tt_want(evhttp_uri_get_userinfo(uri) == NULL);
26932b15cb3dSCy Schubert 	tt_want(evhttp_uri_get_port(uri) == -1);
26942b15cb3dSCy Schubert 	tt_want(evhttp_uri_get_fragment(uri) == NULL);
26952b15cb3dSCy Schubert 	TT_URI("http://www.test.com?q=test");
26962b15cb3dSCy Schubert 	evhttp_uri_free(uri);
26972b15cb3dSCy Schubert 
26982b15cb3dSCy Schubert 	uri = URI_PARSE("http://www.test.com#fragment");
26992b15cb3dSCy Schubert 	tt_want(strcmp(evhttp_uri_get_scheme(uri), "http") == 0);
27002b15cb3dSCy Schubert 	tt_want(strcmp(evhttp_uri_get_host(uri), "www.test.com") == 0);
27012b15cb3dSCy Schubert 	tt_want(strcmp(evhttp_uri_get_path(uri), "") == 0);
27022b15cb3dSCy Schubert 	tt_want(evhttp_uri_get_query(uri) == NULL);
27032b15cb3dSCy Schubert 	tt_want(evhttp_uri_get_userinfo(uri) == NULL);
27042b15cb3dSCy Schubert 	tt_want(evhttp_uri_get_port(uri) == -1);
27052b15cb3dSCy Schubert 	tt_want_str_op(evhttp_uri_get_fragment(uri), ==, "fragment");
27062b15cb3dSCy Schubert 	TT_URI("http://www.test.com#fragment");
27072b15cb3dSCy Schubert 	evhttp_uri_free(uri);
27082b15cb3dSCy Schubert 
27092b15cb3dSCy Schubert 	uri = URI_PARSE("http://8000/");
27102b15cb3dSCy Schubert 	tt_want(strcmp(evhttp_uri_get_scheme(uri), "http") == 0);
27112b15cb3dSCy Schubert 	tt_want(strcmp(evhttp_uri_get_host(uri), "8000") == 0);
27122b15cb3dSCy Schubert 	tt_want(strcmp(evhttp_uri_get_path(uri), "/") == 0);
27132b15cb3dSCy Schubert 	tt_want(evhttp_uri_get_query(uri) == NULL);
27142b15cb3dSCy Schubert 	tt_want(evhttp_uri_get_userinfo(uri) == NULL);
27152b15cb3dSCy Schubert 	tt_want(evhttp_uri_get_port(uri) == -1);
27162b15cb3dSCy Schubert 	tt_want(evhttp_uri_get_fragment(uri) == NULL);
27172b15cb3dSCy Schubert 	TT_URI("http://8000/");
27182b15cb3dSCy Schubert 	evhttp_uri_free(uri);
27192b15cb3dSCy Schubert 
27202b15cb3dSCy Schubert 	uri = URI_PARSE("http://:8000/");
27212b15cb3dSCy Schubert 	tt_want(strcmp(evhttp_uri_get_scheme(uri), "http") == 0);
27222b15cb3dSCy Schubert 	tt_want(strcmp(evhttp_uri_get_host(uri), "") == 0);
27232b15cb3dSCy Schubert 	tt_want(strcmp(evhttp_uri_get_path(uri), "/") == 0);
27242b15cb3dSCy Schubert 	tt_want(evhttp_uri_get_query(uri) == NULL);
27252b15cb3dSCy Schubert 	tt_want(evhttp_uri_get_userinfo(uri) == NULL);
27262b15cb3dSCy Schubert 	tt_want(evhttp_uri_get_port(uri) == 8000);
27272b15cb3dSCy Schubert 	tt_want(evhttp_uri_get_fragment(uri) == NULL);
27282b15cb3dSCy Schubert 	TT_URI("http://:8000/");
27292b15cb3dSCy Schubert 	evhttp_uri_free(uri);
27302b15cb3dSCy Schubert 
27312b15cb3dSCy Schubert 	uri = URI_PARSE("http://www.test.com:/"); /* empty port */
27322b15cb3dSCy Schubert 	tt_want(strcmp(evhttp_uri_get_scheme(uri), "http") == 0);
27332b15cb3dSCy Schubert 	tt_want(strcmp(evhttp_uri_get_host(uri), "www.test.com") == 0);
27342b15cb3dSCy Schubert 	tt_want_str_op(evhttp_uri_get_path(uri), ==, "/");
27352b15cb3dSCy Schubert 	tt_want(evhttp_uri_get_query(uri) == NULL);
27362b15cb3dSCy Schubert 	tt_want(evhttp_uri_get_userinfo(uri) == NULL);
27372b15cb3dSCy Schubert 	tt_want(evhttp_uri_get_port(uri) == -1);
27382b15cb3dSCy Schubert 	tt_want(evhttp_uri_get_fragment(uri) == NULL);
27392b15cb3dSCy Schubert 	TT_URI("http://www.test.com/");
27402b15cb3dSCy Schubert 	evhttp_uri_free(uri);
27412b15cb3dSCy Schubert 
27422b15cb3dSCy Schubert 	uri = URI_PARSE("http://www.test.com:"); /* empty port 2 */
27432b15cb3dSCy Schubert 	tt_want(strcmp(evhttp_uri_get_scheme(uri), "http") == 0);
27442b15cb3dSCy Schubert 	tt_want(strcmp(evhttp_uri_get_host(uri), "www.test.com") == 0);
27452b15cb3dSCy Schubert 	tt_want(strcmp(evhttp_uri_get_path(uri), "") == 0);
27462b15cb3dSCy Schubert 	tt_want(evhttp_uri_get_query(uri) == NULL);
27472b15cb3dSCy Schubert 	tt_want(evhttp_uri_get_userinfo(uri) == NULL);
27482b15cb3dSCy Schubert 	tt_want(evhttp_uri_get_port(uri) == -1);
27492b15cb3dSCy Schubert 	tt_want(evhttp_uri_get_fragment(uri) == NULL);
27502b15cb3dSCy Schubert 	TT_URI("http://www.test.com");
27512b15cb3dSCy Schubert 	evhttp_uri_free(uri);
27522b15cb3dSCy Schubert 
27532b15cb3dSCy Schubert 	uri = URI_PARSE("ftp://www.test.com/?q=test");
27542b15cb3dSCy Schubert 	tt_want(strcmp(evhttp_uri_get_scheme(uri), "ftp") == 0);
27552b15cb3dSCy Schubert 	tt_want(strcmp(evhttp_uri_get_host(uri), "www.test.com") == 0);
27562b15cb3dSCy Schubert 	tt_want(strcmp(evhttp_uri_get_path(uri), "/") == 0);
27572b15cb3dSCy Schubert 	tt_want(strcmp(evhttp_uri_get_query(uri), "q=test") == 0);
27582b15cb3dSCy Schubert 	tt_want(evhttp_uri_get_userinfo(uri) == NULL);
27592b15cb3dSCy Schubert 	tt_want(evhttp_uri_get_port(uri) == -1);
27602b15cb3dSCy Schubert 	tt_want(evhttp_uri_get_fragment(uri) == NULL);
27612b15cb3dSCy Schubert 	TT_URI("ftp://www.test.com/?q=test");
27622b15cb3dSCy Schubert 	evhttp_uri_free(uri);
27632b15cb3dSCy Schubert 
27642b15cb3dSCy Schubert 	uri = URI_PARSE("ftp://[::1]:999/?q=test");
27652b15cb3dSCy Schubert 	tt_want(strcmp(evhttp_uri_get_scheme(uri), "ftp") == 0);
27662b15cb3dSCy Schubert 	tt_want(strcmp(evhttp_uri_get_host(uri), "[::1]") == 0);
27672b15cb3dSCy Schubert 	tt_want(strcmp(evhttp_uri_get_path(uri), "/") == 0);
27682b15cb3dSCy Schubert 	tt_want(strcmp(evhttp_uri_get_query(uri), "q=test") == 0);
27692b15cb3dSCy Schubert 	tt_want(evhttp_uri_get_userinfo(uri) == NULL);
27702b15cb3dSCy Schubert 	tt_want(evhttp_uri_get_port(uri) == 999);
27712b15cb3dSCy Schubert 	tt_want(evhttp_uri_get_fragment(uri) == NULL);
27722b15cb3dSCy Schubert 	TT_URI("ftp://[::1]:999/?q=test");
27732b15cb3dSCy Schubert 	evhttp_uri_free(uri);
27742b15cb3dSCy Schubert 
27752b15cb3dSCy Schubert 	uri = URI_PARSE("ftp://[ff00::127.0.0.1]/?q=test");
27762b15cb3dSCy Schubert 	tt_want(strcmp(evhttp_uri_get_scheme(uri), "ftp") == 0);
27772b15cb3dSCy Schubert 	tt_want(strcmp(evhttp_uri_get_host(uri), "[ff00::127.0.0.1]") == 0);
27782b15cb3dSCy Schubert 	tt_want(strcmp(evhttp_uri_get_path(uri), "/") == 0);
27792b15cb3dSCy Schubert 	tt_want(strcmp(evhttp_uri_get_query(uri), "q=test") == 0);
27802b15cb3dSCy Schubert 	tt_want(evhttp_uri_get_userinfo(uri) == NULL);
27812b15cb3dSCy Schubert 	tt_want(evhttp_uri_get_port(uri) == -1);
27822b15cb3dSCy Schubert 	tt_want(evhttp_uri_get_fragment(uri) == NULL);
27832b15cb3dSCy Schubert 	TT_URI("ftp://[ff00::127.0.0.1]/?q=test");
27842b15cb3dSCy Schubert 	evhttp_uri_free(uri);
27852b15cb3dSCy Schubert 
27862b15cb3dSCy Schubert 	uri = URI_PARSE("ftp://[v99.not_(any:time)_soon]/?q=test");
27872b15cb3dSCy Schubert 	tt_want(strcmp(evhttp_uri_get_scheme(uri), "ftp") == 0);
27882b15cb3dSCy Schubert 	tt_want(strcmp(evhttp_uri_get_host(uri), "[v99.not_(any:time)_soon]") == 0);
27892b15cb3dSCy Schubert 	tt_want(strcmp(evhttp_uri_get_path(uri), "/") == 0);
27902b15cb3dSCy Schubert 	tt_want(strcmp(evhttp_uri_get_query(uri), "q=test") == 0);
27912b15cb3dSCy Schubert 	tt_want(evhttp_uri_get_userinfo(uri) == NULL);
27922b15cb3dSCy Schubert 	tt_want(evhttp_uri_get_port(uri) == -1);
27932b15cb3dSCy Schubert 	tt_want(evhttp_uri_get_fragment(uri) == NULL);
27942b15cb3dSCy Schubert 	TT_URI("ftp://[v99.not_(any:time)_soon]/?q=test");
27952b15cb3dSCy Schubert 	evhttp_uri_free(uri);
27962b15cb3dSCy Schubert 
27972b15cb3dSCy Schubert 	uri = URI_PARSE("scheme://user:pass@foo.com:42/?q=test&s=some+thing#fragment");
27982b15cb3dSCy Schubert 	tt_want(strcmp(evhttp_uri_get_scheme(uri), "scheme") == 0);
27992b15cb3dSCy Schubert 	tt_want(strcmp(evhttp_uri_get_userinfo(uri), "user:pass") == 0);
28002b15cb3dSCy Schubert 	tt_want(strcmp(evhttp_uri_get_host(uri), "foo.com") == 0);
28012b15cb3dSCy Schubert 	tt_want(evhttp_uri_get_port(uri) == 42);
28022b15cb3dSCy Schubert 	tt_want(strcmp(evhttp_uri_get_path(uri), "/") == 0);
28032b15cb3dSCy Schubert 	tt_want(strcmp(evhttp_uri_get_query(uri), "q=test&s=some+thing") == 0);
28042b15cb3dSCy Schubert 	tt_want(strcmp(evhttp_uri_get_fragment(uri), "fragment") == 0);
28052b15cb3dSCy Schubert 	TT_URI("scheme://user:pass@foo.com:42/?q=test&s=some+thing#fragment");
28062b15cb3dSCy Schubert 	evhttp_uri_free(uri);
28072b15cb3dSCy Schubert 
28082b15cb3dSCy Schubert 	uri = URI_PARSE("scheme://user@foo.com/#fragment");
28092b15cb3dSCy Schubert 	tt_want(strcmp(evhttp_uri_get_scheme(uri), "scheme") == 0);
28102b15cb3dSCy Schubert 	tt_want(strcmp(evhttp_uri_get_userinfo(uri), "user") == 0);
28112b15cb3dSCy Schubert 	tt_want(strcmp(evhttp_uri_get_host(uri), "foo.com") == 0);
28122b15cb3dSCy Schubert 	tt_want(evhttp_uri_get_port(uri) == -1);
28132b15cb3dSCy Schubert 	tt_want(strcmp(evhttp_uri_get_path(uri), "/") == 0);
28142b15cb3dSCy Schubert 	tt_want(evhttp_uri_get_query(uri) == NULL);
28152b15cb3dSCy Schubert 	tt_want(strcmp(evhttp_uri_get_fragment(uri), "fragment") == 0);
28162b15cb3dSCy Schubert 	TT_URI("scheme://user@foo.com/#fragment");
28172b15cb3dSCy Schubert 	evhttp_uri_free(uri);
28182b15cb3dSCy Schubert 
28192b15cb3dSCy Schubert 	uri = URI_PARSE("scheme://%75ser@foo.com/#frag@ment");
28202b15cb3dSCy Schubert 	tt_want(strcmp(evhttp_uri_get_scheme(uri), "scheme") == 0);
28212b15cb3dSCy Schubert 	tt_want(strcmp(evhttp_uri_get_userinfo(uri), "%75ser") == 0);
28222b15cb3dSCy Schubert 	tt_want(strcmp(evhttp_uri_get_host(uri), "foo.com") == 0);
28232b15cb3dSCy Schubert 	tt_want(evhttp_uri_get_port(uri) == -1);
28242b15cb3dSCy Schubert 	tt_want(strcmp(evhttp_uri_get_path(uri), "/") == 0);
28252b15cb3dSCy Schubert 	tt_want(evhttp_uri_get_query(uri) == NULL);
28262b15cb3dSCy Schubert 	tt_want(strcmp(evhttp_uri_get_fragment(uri), "frag@ment") == 0);
28272b15cb3dSCy Schubert 	TT_URI("scheme://%75ser@foo.com/#frag@ment");
28282b15cb3dSCy Schubert 	evhttp_uri_free(uri);
28292b15cb3dSCy Schubert 
28302b15cb3dSCy Schubert 	uri = URI_PARSE("file:///some/path/to/the/file");
28312b15cb3dSCy Schubert 	tt_want(strcmp(evhttp_uri_get_scheme(uri), "file") == 0);
28322b15cb3dSCy Schubert 	tt_want(evhttp_uri_get_userinfo(uri) == NULL);
28332b15cb3dSCy Schubert 	tt_want(strcmp(evhttp_uri_get_host(uri), "") == 0);
28342b15cb3dSCy Schubert 	tt_want(evhttp_uri_get_port(uri) == -1);
28352b15cb3dSCy Schubert 	tt_want(strcmp(evhttp_uri_get_path(uri), "/some/path/to/the/file") == 0);
28362b15cb3dSCy Schubert 	tt_want(evhttp_uri_get_query(uri) == NULL);
28372b15cb3dSCy Schubert 	tt_want(evhttp_uri_get_fragment(uri) == NULL);
28382b15cb3dSCy Schubert 	TT_URI("file:///some/path/to/the/file");
28392b15cb3dSCy Schubert 	evhttp_uri_free(uri);
28402b15cb3dSCy Schubert 
28412b15cb3dSCy Schubert 	uri = URI_PARSE("///some/path/to/the-file");
28422b15cb3dSCy Schubert 	tt_want(uri != NULL);
28432b15cb3dSCy Schubert 	tt_want(evhttp_uri_get_scheme(uri) == NULL);
28442b15cb3dSCy Schubert 	tt_want(evhttp_uri_get_userinfo(uri) == NULL);
28452b15cb3dSCy Schubert 	tt_want(strcmp(evhttp_uri_get_host(uri), "") == 0);
28462b15cb3dSCy Schubert 	tt_want(evhttp_uri_get_port(uri) == -1);
28472b15cb3dSCy Schubert 	tt_want(strcmp(evhttp_uri_get_path(uri), "/some/path/to/the-file") == 0);
28482b15cb3dSCy Schubert 	tt_want(evhttp_uri_get_query(uri) == NULL);
28492b15cb3dSCy Schubert 	tt_want(evhttp_uri_get_fragment(uri) == NULL);
28502b15cb3dSCy Schubert 	TT_URI("///some/path/to/the-file");
28512b15cb3dSCy Schubert 	evhttp_uri_free(uri);
28522b15cb3dSCy Schubert 
28532b15cb3dSCy Schubert 	uri = URI_PARSE("/s:ome/path/to/the-file?q=99#fred");
28542b15cb3dSCy Schubert 	tt_want(uri != NULL);
28552b15cb3dSCy Schubert 	tt_want(evhttp_uri_get_scheme(uri) == NULL);
28562b15cb3dSCy Schubert 	tt_want(evhttp_uri_get_userinfo(uri) == NULL);
28572b15cb3dSCy Schubert 	tt_want(evhttp_uri_get_host(uri) == NULL);
28582b15cb3dSCy Schubert 	tt_want(evhttp_uri_get_port(uri) == -1);
28592b15cb3dSCy Schubert 	tt_want(strcmp(evhttp_uri_get_path(uri), "/s:ome/path/to/the-file") == 0);
28602b15cb3dSCy Schubert 	tt_want(strcmp(evhttp_uri_get_query(uri), "q=99") == 0);
28612b15cb3dSCy Schubert 	tt_want(strcmp(evhttp_uri_get_fragment(uri), "fred") == 0);
28622b15cb3dSCy Schubert 	TT_URI("/s:ome/path/to/the-file?q=99#fred");
28632b15cb3dSCy Schubert 	evhttp_uri_free(uri);
28642b15cb3dSCy Schubert 
28652b15cb3dSCy Schubert 	uri = URI_PARSE("relative/path/with/co:lon");
28662b15cb3dSCy Schubert 	tt_want(uri != NULL);
28672b15cb3dSCy Schubert 	tt_want(evhttp_uri_get_scheme(uri) == NULL);
28682b15cb3dSCy Schubert 	tt_want(evhttp_uri_get_userinfo(uri) == NULL);
28692b15cb3dSCy Schubert 	tt_want(evhttp_uri_get_host(uri) == NULL);
28702b15cb3dSCy Schubert 	tt_want(evhttp_uri_get_port(uri) == -1);
28712b15cb3dSCy Schubert 	tt_want(strcmp(evhttp_uri_get_path(uri), "relative/path/with/co:lon") == 0);
28722b15cb3dSCy Schubert 	tt_want(evhttp_uri_get_query(uri) == NULL);
28732b15cb3dSCy Schubert 	tt_want(evhttp_uri_get_fragment(uri) == NULL);
28742b15cb3dSCy Schubert 	TT_URI("relative/path/with/co:lon");
28752b15cb3dSCy Schubert 	evhttp_uri_free(uri);
28762b15cb3dSCy Schubert 
28772b15cb3dSCy Schubert 	uri = URI_PARSE("bob?q=99&q2=q?33#fr?ed");
28782b15cb3dSCy Schubert 	tt_want(uri != NULL);
28792b15cb3dSCy Schubert 	tt_want(evhttp_uri_get_scheme(uri) == NULL);
28802b15cb3dSCy Schubert 	tt_want(evhttp_uri_get_userinfo(uri) == NULL);
28812b15cb3dSCy Schubert 	tt_want(evhttp_uri_get_host(uri) == NULL);
28822b15cb3dSCy Schubert 	tt_want(evhttp_uri_get_port(uri) == -1);
28832b15cb3dSCy Schubert 	tt_want(strcmp(evhttp_uri_get_path(uri), "bob") == 0);
28842b15cb3dSCy Schubert 	tt_want(strcmp(evhttp_uri_get_query(uri), "q=99&q2=q?33") == 0);
28852b15cb3dSCy Schubert 	tt_want(strcmp(evhttp_uri_get_fragment(uri), "fr?ed") == 0);
28862b15cb3dSCy Schubert 	TT_URI("bob?q=99&q2=q?33#fr?ed");
28872b15cb3dSCy Schubert 	evhttp_uri_free(uri);
28882b15cb3dSCy Schubert 
28892b15cb3dSCy Schubert 	uri = URI_PARSE("#fr?ed");
28902b15cb3dSCy Schubert 	tt_want(uri != NULL);
28912b15cb3dSCy Schubert 	tt_want(evhttp_uri_get_scheme(uri) == NULL);
28922b15cb3dSCy Schubert 	tt_want(evhttp_uri_get_userinfo(uri) == NULL);
28932b15cb3dSCy Schubert 	tt_want(evhttp_uri_get_host(uri) == NULL);
28942b15cb3dSCy Schubert 	tt_want(evhttp_uri_get_port(uri) == -1);
28952b15cb3dSCy Schubert 	tt_want(strcmp(evhttp_uri_get_path(uri), "") == 0);
28962b15cb3dSCy Schubert 	tt_want(evhttp_uri_get_query(uri) == NULL);
28972b15cb3dSCy Schubert 	tt_want(strcmp(evhttp_uri_get_fragment(uri), "fr?ed") == 0);
28982b15cb3dSCy Schubert 	TT_URI("#fr?ed");
28992b15cb3dSCy Schubert 	evhttp_uri_free(uri);
29002b15cb3dSCy Schubert #undef URI_PARSE
29012b15cb3dSCy Schubert #undef TT_URI
29022b15cb3dSCy Schubert #undef BAD
29032b15cb3dSCy Schubert }
29042b15cb3dSCy Schubert 
29052b15cb3dSCy Schubert static void
http_uriencode_test(void * ptr)29062b15cb3dSCy Schubert http_uriencode_test(void *ptr)
29072b15cb3dSCy Schubert {
29082b15cb3dSCy Schubert 	char *s=NULL, *s2=NULL;
29092b15cb3dSCy Schubert 	size_t sz;
29102b15cb3dSCy Schubert 	int bytes_decoded;
29112b15cb3dSCy Schubert 
29122b15cb3dSCy Schubert #define ENC(from,want,plus) do {				\
29132b15cb3dSCy Schubert 		s = evhttp_uriencode((from), -1, (plus));	\
29142b15cb3dSCy Schubert 		tt_assert(s);					\
29152b15cb3dSCy Schubert 		tt_str_op(s,==,(want));				\
29162b15cb3dSCy Schubert 		sz = -1;					\
29172b15cb3dSCy Schubert 		s2 = evhttp_uridecode((s), (plus), &sz);	\
29182b15cb3dSCy Schubert 		tt_assert(s2);					\
29192b15cb3dSCy Schubert 		tt_str_op(s2,==,(from));			\
29202b15cb3dSCy Schubert 		tt_int_op(sz,==,strlen(from));			\
29212b15cb3dSCy Schubert 		free(s);					\
29222b15cb3dSCy Schubert 		free(s2);					\
29232b15cb3dSCy Schubert 		s = s2 = NULL;					\
29242b15cb3dSCy Schubert 	} while (0)
29252b15cb3dSCy Schubert 
29262b15cb3dSCy Schubert #define DEC(from,want,dp) do {					\
29272b15cb3dSCy Schubert 		s = evhttp_uridecode((from),(dp),&sz);		\
29282b15cb3dSCy Schubert 		tt_assert(s);					\
29292b15cb3dSCy Schubert 		tt_str_op(s,==,(want));				\
29302b15cb3dSCy Schubert 		tt_int_op(sz,==,strlen(want));			\
29312b15cb3dSCy Schubert 		free(s);					\
29322b15cb3dSCy Schubert 		s = NULL;					\
29332b15cb3dSCy Schubert 	} while (0)
29342b15cb3dSCy Schubert 
29352b15cb3dSCy Schubert #define OLD_DEC(from,want)  do {				\
29362b15cb3dSCy Schubert 		s = evhttp_decode_uri((from));			\
29372b15cb3dSCy Schubert 		tt_assert(s);					\
29382b15cb3dSCy Schubert 		tt_str_op(s,==,(want));				\
29392b15cb3dSCy Schubert 		free(s);					\
29402b15cb3dSCy Schubert 		s = NULL;					\
29412b15cb3dSCy Schubert 	} while (0)
29422b15cb3dSCy Schubert 
29432b15cb3dSCy Schubert 
29442b15cb3dSCy Schubert       	ENC("Hello", "Hello",0);
29452b15cb3dSCy Schubert 	ENC("99", "99",0);
29462b15cb3dSCy Schubert 	ENC("", "",0);
29472b15cb3dSCy Schubert 	ENC(
29482b15cb3dSCy Schubert 	 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ123456789-.~_",
29492b15cb3dSCy Schubert 	 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ123456789-.~_",0);
29502b15cb3dSCy Schubert 	ENC(" ", "%20",0);
29512b15cb3dSCy Schubert 	ENC(" ", "+",1);
29522b15cb3dSCy Schubert 	ENC("\xff\xf0\xe0", "%FF%F0%E0",0);
29532b15cb3dSCy Schubert 	ENC("\x01\x19", "%01%19",1);
29542b15cb3dSCy Schubert 	ENC("http://www.ietf.org/rfc/rfc3986.txt",
29552b15cb3dSCy Schubert 	    "http%3A%2F%2Fwww.ietf.org%2Frfc%2Frfc3986.txt",1);
29562b15cb3dSCy Schubert 
29572b15cb3dSCy Schubert 	ENC("1+2=3", "1%2B2%3D3",1);
29582b15cb3dSCy Schubert 	ENC("1+2=3", "1%2B2%3D3",0);
29592b15cb3dSCy Schubert 
29602b15cb3dSCy Schubert 	/* Now try encoding with internal NULs. */
29612b15cb3dSCy Schubert 	s = evhttp_uriencode("hello\0world", 11, 0);
29622b15cb3dSCy Schubert 	tt_assert(s);
29632b15cb3dSCy Schubert 	tt_str_op(s,==,"hello%00world");
29642b15cb3dSCy Schubert 	free(s);
29652b15cb3dSCy Schubert 	s = NULL;
29662b15cb3dSCy Schubert 
29672b15cb3dSCy Schubert 	/* Now try decoding just part of string. */
29682b15cb3dSCy Schubert 	s = malloc(6 + 1 /* NUL byte */);
29692b15cb3dSCy Schubert 	bytes_decoded = evhttp_decode_uri_internal("hello%20%20", 6, s, 0);
29702b15cb3dSCy Schubert 	tt_assert(s);
29712b15cb3dSCy Schubert 	tt_int_op(bytes_decoded,==,6);
29722b15cb3dSCy Schubert 	tt_str_op(s,==,"hello%");
29732b15cb3dSCy Schubert 	free(s);
29742b15cb3dSCy Schubert 	s = NULL;
29752b15cb3dSCy Schubert 
29762b15cb3dSCy Schubert 	/* Now try out some decoding cases that we don't generate with
29772b15cb3dSCy Schubert 	 * encode_uri: Make sure that malformed stuff doesn't crash... */
29782b15cb3dSCy Schubert 	DEC("%%xhello th+ere \xff",
29792b15cb3dSCy Schubert 	    "%%xhello th+ere \xff", 0);
29802b15cb3dSCy Schubert 	/* Make sure plus decoding works */
29812b15cb3dSCy Schubert 	DEC("plus+should%20work+", "plus should work ",1);
29822b15cb3dSCy Schubert 	/* Try some lowercase hex */
29832b15cb3dSCy Schubert 	DEC("%f0%a0%b0", "\xf0\xa0\xb0",1);
29842b15cb3dSCy Schubert 
29852b15cb3dSCy Schubert 	/* Try an internal NUL. */
29862b15cb3dSCy Schubert 	sz = 0;
29872b15cb3dSCy Schubert 	s = evhttp_uridecode("%00%00x%00%00", 1, &sz);
29882b15cb3dSCy Schubert 	tt_int_op(sz,==,5);
29892b15cb3dSCy Schubert 	tt_assert(!memcmp(s, "\0\0x\0\0", 5));
29902b15cb3dSCy Schubert 	free(s);
29912b15cb3dSCy Schubert 	s = NULL;
29922b15cb3dSCy Schubert 
29932b15cb3dSCy Schubert 	/* Try with size == NULL */
29942b15cb3dSCy Schubert 	sz = 0;
29952b15cb3dSCy Schubert 	s = evhttp_uridecode("%00%00x%00%00", 1, NULL);
29962b15cb3dSCy Schubert 	tt_assert(!memcmp(s, "\0\0x\0\0", 5));
29972b15cb3dSCy Schubert 	free(s);
29982b15cb3dSCy Schubert 	s = NULL;
29992b15cb3dSCy Schubert 
30002b15cb3dSCy Schubert 	/* Test out the crazy old behavior of the deprecated
30012b15cb3dSCy Schubert 	 * evhttp_decode_uri */
30022b15cb3dSCy Schubert 	OLD_DEC("http://example.com/normal+path/?key=val+with+spaces",
30032b15cb3dSCy Schubert 	        "http://example.com/normal+path/?key=val with spaces");
30042b15cb3dSCy Schubert 
30052b15cb3dSCy Schubert end:
30062b15cb3dSCy Schubert 	if (s)
30072b15cb3dSCy Schubert 		free(s);
30082b15cb3dSCy Schubert 	if (s2)
30092b15cb3dSCy Schubert 		free(s2);
30102b15cb3dSCy Schubert #undef ENC
30112b15cb3dSCy Schubert #undef DEC
30122b15cb3dSCy Schubert #undef OLD_DEC
30132b15cb3dSCy Schubert }
30142b15cb3dSCy Schubert 
30152b15cb3dSCy Schubert static void
http_base_test(void * ptr)30162b15cb3dSCy Schubert http_base_test(void *ptr)
30172b15cb3dSCy Schubert {
30182b15cb3dSCy Schubert 	struct event_base *base = NULL;
30192b15cb3dSCy Schubert 	struct bufferevent *bev;
30202b15cb3dSCy Schubert 	evutil_socket_t fd;
30212b15cb3dSCy Schubert 	const char *http_request;
30222b15cb3dSCy Schubert 	ev_uint16_t port = 0;
3023*a466cc55SCy Schubert 	struct evhttp *http;
30242b15cb3dSCy Schubert 
30252b15cb3dSCy Schubert 	test_ok = 0;
30262b15cb3dSCy Schubert 	base = event_base_new();
30272b15cb3dSCy Schubert 	tt_assert(base);
30282b15cb3dSCy Schubert 	http = http_setup(&port, base, 0);
30292b15cb3dSCy Schubert 
30302b15cb3dSCy Schubert 	fd = http_connect("127.0.0.1", port);
3031*a466cc55SCy Schubert 	tt_assert(fd != EVUTIL_INVALID_SOCKET);
30322b15cb3dSCy Schubert 
30332b15cb3dSCy Schubert 	/* Stupid thing to send a request */
30342b15cb3dSCy Schubert 	bev = bufferevent_socket_new(base, fd, 0);
30352b15cb3dSCy Schubert 	bufferevent_setcb(bev, http_readcb, http_writecb,
30362b15cb3dSCy Schubert 	    http_errorcb, base);
30372b15cb3dSCy Schubert 	bufferevent_base_set(base, bev);
30382b15cb3dSCy Schubert 
30392b15cb3dSCy Schubert 	http_request =
30402b15cb3dSCy Schubert 	    "GET /test HTTP/1.1\r\n"
30412b15cb3dSCy Schubert 	    "Host: somehost\r\n"
30422b15cb3dSCy Schubert 	    "Connection: close\r\n"
30432b15cb3dSCy Schubert 	    "\r\n";
30442b15cb3dSCy Schubert 
30452b15cb3dSCy Schubert 	bufferevent_write(bev, http_request, strlen(http_request));
30462b15cb3dSCy Schubert 
30472b15cb3dSCy Schubert 	event_base_dispatch(base);
30482b15cb3dSCy Schubert 
30492b15cb3dSCy Schubert 	bufferevent_free(bev);
30502b15cb3dSCy Schubert 	evutil_closesocket(fd);
30512b15cb3dSCy Schubert 
30522b15cb3dSCy Schubert 	evhttp_free(http);
30532b15cb3dSCy Schubert 
30542b15cb3dSCy Schubert 	tt_int_op(test_ok, ==, 2);
30552b15cb3dSCy Schubert 
30562b15cb3dSCy Schubert end:
30572b15cb3dSCy Schubert 	if (base)
30582b15cb3dSCy Schubert 		event_base_free(base);
30592b15cb3dSCy Schubert }
30602b15cb3dSCy Schubert 
30612b15cb3dSCy Schubert /*
30622b15cb3dSCy Schubert  * the server is just going to close the connection if it times out during
30632b15cb3dSCy Schubert  * reading the headers.
30642b15cb3dSCy Schubert  */
30652b15cb3dSCy Schubert 
30662b15cb3dSCy Schubert static void
http_incomplete_readcb(struct bufferevent * bev,void * arg)30672b15cb3dSCy Schubert http_incomplete_readcb(struct bufferevent *bev, void *arg)
30682b15cb3dSCy Schubert {
30692b15cb3dSCy Schubert 	test_ok = -1;
30702b15cb3dSCy Schubert 	event_base_loopexit(exit_base,NULL);
30712b15cb3dSCy Schubert }
30722b15cb3dSCy Schubert 
30732b15cb3dSCy Schubert static void
http_incomplete_errorcb(struct bufferevent * bev,short what,void * arg)30742b15cb3dSCy Schubert http_incomplete_errorcb(struct bufferevent *bev, short what, void *arg)
30752b15cb3dSCy Schubert {
3076*a466cc55SCy Schubert 	/** For ssl */
3077*a466cc55SCy Schubert 	if (what & BEV_EVENT_CONNECTED)
3078*a466cc55SCy Schubert 		return;
3079*a466cc55SCy Schubert 
30802b15cb3dSCy Schubert 	if (what == (BEV_EVENT_READING|BEV_EVENT_EOF))
30812b15cb3dSCy Schubert 		test_ok++;
30822b15cb3dSCy Schubert 	else
30832b15cb3dSCy Schubert 		test_ok = -2;
30842b15cb3dSCy Schubert 	event_base_loopexit(exit_base,NULL);
30852b15cb3dSCy Schubert }
30862b15cb3dSCy Schubert 
30872b15cb3dSCy Schubert static void
http_incomplete_writecb(struct bufferevent * bev,void * arg)30882b15cb3dSCy Schubert http_incomplete_writecb(struct bufferevent *bev, void *arg)
30892b15cb3dSCy Schubert {
30902b15cb3dSCy Schubert 	if (arg != NULL) {
30912b15cb3dSCy Schubert 		evutil_socket_t fd = *(evutil_socket_t *)arg;
30922b15cb3dSCy Schubert 		/* terminate the write side to simulate EOF */
3093*a466cc55SCy Schubert 		shutdown(fd, EVUTIL_SHUT_WR);
30942b15cb3dSCy Schubert 	}
30952b15cb3dSCy Schubert 	if (evbuffer_get_length(bufferevent_get_output(bev)) == 0) {
30962b15cb3dSCy Schubert 		/* enable reading of the reply */
30972b15cb3dSCy Schubert 		bufferevent_enable(bev, EV_READ);
30982b15cb3dSCy Schubert 		test_ok++;
30992b15cb3dSCy Schubert 	}
31002b15cb3dSCy Schubert }
31012b15cb3dSCy Schubert 
31022b15cb3dSCy Schubert static void
http_incomplete_test_(struct basic_test_data * data,int use_timeout,int ssl)3103*a466cc55SCy Schubert http_incomplete_test_(struct basic_test_data *data, int use_timeout, int ssl)
31042b15cb3dSCy Schubert {
31052b15cb3dSCy Schubert 	struct bufferevent *bev;
31062b15cb3dSCy Schubert 	evutil_socket_t fd;
31072b15cb3dSCy Schubert 	const char *http_request;
31082b15cb3dSCy Schubert 	ev_uint16_t port = 0;
31092b15cb3dSCy Schubert 	struct timeval tv_start, tv_end;
3110*a466cc55SCy Schubert 	struct evhttp *http = http_setup(&port, data->base, ssl ? HTTP_BIND_SSL : 0);
31112b15cb3dSCy Schubert 
31122b15cb3dSCy Schubert 	exit_base = data->base;
31132b15cb3dSCy Schubert 	test_ok = 0;
31142b15cb3dSCy Schubert 
31152b15cb3dSCy Schubert 	evhttp_set_timeout(http, 1);
31162b15cb3dSCy Schubert 
31172b15cb3dSCy Schubert 	fd = http_connect("127.0.0.1", port);
3118*a466cc55SCy Schubert 	tt_assert(fd != EVUTIL_INVALID_SOCKET);
31192b15cb3dSCy Schubert 
31202b15cb3dSCy Schubert 	/* Stupid thing to send a request */
3121*a466cc55SCy Schubert 	bev = create_bev(data->base, fd, ssl, 0);
31222b15cb3dSCy Schubert 	bufferevent_setcb(bev,
31232b15cb3dSCy Schubert 	    http_incomplete_readcb, http_incomplete_writecb,
31242b15cb3dSCy Schubert 	    http_incomplete_errorcb, use_timeout ? NULL : &fd);
31252b15cb3dSCy Schubert 
31262b15cb3dSCy Schubert 	http_request =
31272b15cb3dSCy Schubert 	    "GET /test HTTP/1.1\r\n"
31282b15cb3dSCy Schubert 	    "Host: somehost\r\n";
31292b15cb3dSCy Schubert 
31302b15cb3dSCy Schubert 	bufferevent_write(bev, http_request, strlen(http_request));
31312b15cb3dSCy Schubert 
31322b15cb3dSCy Schubert 	evutil_gettimeofday(&tv_start, NULL);
31332b15cb3dSCy Schubert 
31342b15cb3dSCy Schubert 	event_base_dispatch(data->base);
31352b15cb3dSCy Schubert 
31362b15cb3dSCy Schubert 	evutil_gettimeofday(&tv_end, NULL);
31372b15cb3dSCy Schubert 	evutil_timersub(&tv_end, &tv_start, &tv_end);
31382b15cb3dSCy Schubert 
31392b15cb3dSCy Schubert 	bufferevent_free(bev);
31402b15cb3dSCy Schubert 	if (use_timeout) {
31412b15cb3dSCy Schubert 		evutil_closesocket(fd);
3142*a466cc55SCy Schubert 		fd = EVUTIL_INVALID_SOCKET;
31432b15cb3dSCy Schubert 	}
31442b15cb3dSCy Schubert 
31452b15cb3dSCy Schubert 	evhttp_free(http);
31462b15cb3dSCy Schubert 
31472b15cb3dSCy Schubert 	if (use_timeout && tv_end.tv_sec >= 3) {
31482b15cb3dSCy Schubert 		tt_abort_msg("time");
31492b15cb3dSCy Schubert 	} else if (!use_timeout && tv_end.tv_sec >= 1) {
31502b15cb3dSCy Schubert 		/* we should be done immediately */
31512b15cb3dSCy Schubert 		tt_abort_msg("time");
31522b15cb3dSCy Schubert 	}
31532b15cb3dSCy Schubert 
31542b15cb3dSCy Schubert 	tt_int_op(test_ok, ==, 2);
31552b15cb3dSCy Schubert  end:
31562b15cb3dSCy Schubert 	if (fd >= 0)
31572b15cb3dSCy Schubert 		evutil_closesocket(fd);
31582b15cb3dSCy Schubert }
http_incomplete_test(void * arg)3159*a466cc55SCy Schubert static void http_incomplete_test(void *arg)
3160*a466cc55SCy Schubert { http_incomplete_test_(arg, 0, 0); }
http_incomplete_timeout_test(void * arg)3161*a466cc55SCy Schubert static void http_incomplete_timeout_test(void *arg)
3162*a466cc55SCy Schubert { http_incomplete_test_(arg, 1, 0); }
3163*a466cc55SCy Schubert 
31642b15cb3dSCy Schubert 
31652b15cb3dSCy Schubert /*
31662b15cb3dSCy Schubert  * the server is going to reply with chunked data.
31672b15cb3dSCy Schubert  */
31682b15cb3dSCy Schubert 
31692b15cb3dSCy Schubert static void
http_chunked_readcb(struct bufferevent * bev,void * arg)31702b15cb3dSCy Schubert http_chunked_readcb(struct bufferevent *bev, void *arg)
31712b15cb3dSCy Schubert {
31722b15cb3dSCy Schubert 	/* nothing here */
31732b15cb3dSCy Schubert }
31742b15cb3dSCy Schubert 
31752b15cb3dSCy Schubert static void
http_chunked_errorcb(struct bufferevent * bev,short what,void * arg)31762b15cb3dSCy Schubert http_chunked_errorcb(struct bufferevent *bev, short what, void *arg)
31772b15cb3dSCy Schubert {
31782b15cb3dSCy Schubert 	struct evhttp_request *req = NULL;
31792b15cb3dSCy Schubert 
3180*a466cc55SCy Schubert 	/** SSL */
3181*a466cc55SCy Schubert 	if (what & BEV_EVENT_CONNECTED)
3182*a466cc55SCy Schubert 		return;
3183*a466cc55SCy Schubert 
31842b15cb3dSCy Schubert 	if (!test_ok)
31852b15cb3dSCy Schubert 		goto out;
31862b15cb3dSCy Schubert 
31872b15cb3dSCy Schubert 	test_ok = -1;
31882b15cb3dSCy Schubert 
31892b15cb3dSCy Schubert 	if ((what & BEV_EVENT_EOF) != 0) {
31902b15cb3dSCy Schubert 		const char *header;
31912b15cb3dSCy Schubert 		enum message_read_status done;
31922b15cb3dSCy Schubert 		req = evhttp_request_new(NULL, NULL);
31932b15cb3dSCy Schubert 
31942b15cb3dSCy Schubert 		/* req->kind = EVHTTP_RESPONSE; */
31952b15cb3dSCy Schubert 		done = evhttp_parse_firstline_(req, bufferevent_get_input(bev));
31962b15cb3dSCy Schubert 		if (done != ALL_DATA_READ)
31972b15cb3dSCy Schubert 			goto out;
31982b15cb3dSCy Schubert 
31992b15cb3dSCy Schubert 		done = evhttp_parse_headers_(req, bufferevent_get_input(bev));
32002b15cb3dSCy Schubert 		if (done != ALL_DATA_READ)
32012b15cb3dSCy Schubert 			goto out;
32022b15cb3dSCy Schubert 
32032b15cb3dSCy Schubert 		header = evhttp_find_header(evhttp_request_get_input_headers(req), "Transfer-Encoding");
32042b15cb3dSCy Schubert 		if (header == NULL || strcmp(header, "chunked"))
32052b15cb3dSCy Schubert 			goto out;
32062b15cb3dSCy Schubert 
32072b15cb3dSCy Schubert 		header = evhttp_find_header(evhttp_request_get_input_headers(req), "Connection");
32082b15cb3dSCy Schubert 		if (header == NULL || strcmp(header, "close"))
32092b15cb3dSCy Schubert 			goto out;
32102b15cb3dSCy Schubert 
32112b15cb3dSCy Schubert 		header = evbuffer_readln(bufferevent_get_input(bev), NULL, EVBUFFER_EOL_CRLF);
32122b15cb3dSCy Schubert 		if (header == NULL)
32132b15cb3dSCy Schubert 			goto out;
32142b15cb3dSCy Schubert 		/* 13 chars */
32152b15cb3dSCy Schubert 		if (strcmp(header, "d")) {
32162b15cb3dSCy Schubert 			free((void*)header);
32172b15cb3dSCy Schubert 			goto out;
32182b15cb3dSCy Schubert 		}
32192b15cb3dSCy Schubert 		free((void*)header);
32202b15cb3dSCy Schubert 
32212b15cb3dSCy Schubert 		if (strncmp((char *)evbuffer_pullup(bufferevent_get_input(bev), 13),
32222b15cb3dSCy Schubert 			"This is funny", 13))
32232b15cb3dSCy Schubert 			goto out;
32242b15cb3dSCy Schubert 
32252b15cb3dSCy Schubert 		evbuffer_drain(bufferevent_get_input(bev), 13 + 2);
32262b15cb3dSCy Schubert 
32272b15cb3dSCy Schubert 		header = evbuffer_readln(bufferevent_get_input(bev), NULL, EVBUFFER_EOL_CRLF);
32282b15cb3dSCy Schubert 		if (header == NULL)
32292b15cb3dSCy Schubert 			goto out;
32302b15cb3dSCy Schubert 		/* 18 chars */
32312b15cb3dSCy Schubert 		if (strcmp(header, "12"))
32322b15cb3dSCy Schubert 			goto out;
32332b15cb3dSCy Schubert 		free((char *)header);
32342b15cb3dSCy Schubert 
32352b15cb3dSCy Schubert 		if (strncmp((char *)evbuffer_pullup(bufferevent_get_input(bev), 18),
32362b15cb3dSCy Schubert 			"but not hilarious.", 18))
32372b15cb3dSCy Schubert 			goto out;
32382b15cb3dSCy Schubert 
32392b15cb3dSCy Schubert 		evbuffer_drain(bufferevent_get_input(bev), 18 + 2);
32402b15cb3dSCy Schubert 
32412b15cb3dSCy Schubert 		header = evbuffer_readln(bufferevent_get_input(bev), NULL, EVBUFFER_EOL_CRLF);
32422b15cb3dSCy Schubert 		if (header == NULL)
32432b15cb3dSCy Schubert 			goto out;
32442b15cb3dSCy Schubert 		/* 8 chars */
32452b15cb3dSCy Schubert 		if (strcmp(header, "8")) {
32462b15cb3dSCy Schubert 			free((void*)header);
32472b15cb3dSCy Schubert 			goto out;
32482b15cb3dSCy Schubert 		}
32492b15cb3dSCy Schubert 		free((char *)header);
32502b15cb3dSCy Schubert 
32512b15cb3dSCy Schubert 		if (strncmp((char *)evbuffer_pullup(bufferevent_get_input(bev), 8),
32522b15cb3dSCy Schubert 			"bwv 1052.", 8))
32532b15cb3dSCy Schubert 			goto out;
32542b15cb3dSCy Schubert 
32552b15cb3dSCy Schubert 		evbuffer_drain(bufferevent_get_input(bev), 8 + 2);
32562b15cb3dSCy Schubert 
32572b15cb3dSCy Schubert 		header = evbuffer_readln(bufferevent_get_input(bev), NULL, EVBUFFER_EOL_CRLF);
32582b15cb3dSCy Schubert 		if (header == NULL)
32592b15cb3dSCy Schubert 			goto out;
32602b15cb3dSCy Schubert 		/* 0 chars */
32612b15cb3dSCy Schubert 		if (strcmp(header, "0")) {
32622b15cb3dSCy Schubert 			free((void*)header);
32632b15cb3dSCy Schubert 			goto out;
32642b15cb3dSCy Schubert 		}
32652b15cb3dSCy Schubert 		free((void *)header);
32662b15cb3dSCy Schubert 
32672b15cb3dSCy Schubert 		test_ok = 2;
32682b15cb3dSCy Schubert 	}
32692b15cb3dSCy Schubert 
32702b15cb3dSCy Schubert out:
32712b15cb3dSCy Schubert 	if (req)
32722b15cb3dSCy Schubert 		evhttp_request_free(req);
32732b15cb3dSCy Schubert 
32742b15cb3dSCy Schubert 	event_base_loopexit(arg, NULL);
32752b15cb3dSCy Schubert }
32762b15cb3dSCy Schubert 
32772b15cb3dSCy Schubert static void
http_chunked_writecb(struct bufferevent * bev,void * arg)32782b15cb3dSCy Schubert http_chunked_writecb(struct bufferevent *bev, void *arg)
32792b15cb3dSCy Schubert {
32802b15cb3dSCy Schubert 	if (evbuffer_get_length(bufferevent_get_output(bev)) == 0) {
32812b15cb3dSCy Schubert 		/* enable reading of the reply */
32822b15cb3dSCy Schubert 		bufferevent_enable(bev, EV_READ);
32832b15cb3dSCy Schubert 		test_ok++;
32842b15cb3dSCy Schubert 	}
32852b15cb3dSCy Schubert }
32862b15cb3dSCy Schubert 
32872b15cb3dSCy Schubert static void
http_chunked_request_done(struct evhttp_request * req,void * arg)32882b15cb3dSCy Schubert http_chunked_request_done(struct evhttp_request *req, void *arg)
32892b15cb3dSCy Schubert {
32902b15cb3dSCy Schubert 	if (evhttp_request_get_response_code(req) != HTTP_OK) {
32912b15cb3dSCy Schubert 		fprintf(stderr, "FAILED\n");
32922b15cb3dSCy Schubert 		exit(1);
32932b15cb3dSCy Schubert 	}
32942b15cb3dSCy Schubert 
32952b15cb3dSCy Schubert 	if (evhttp_find_header(evhttp_request_get_input_headers(req),
32962b15cb3dSCy Schubert 		"Transfer-Encoding") == NULL) {
32972b15cb3dSCy Schubert 		fprintf(stderr, "FAILED\n");
32982b15cb3dSCy Schubert 		exit(1);
32992b15cb3dSCy Schubert 	}
33002b15cb3dSCy Schubert 
33012b15cb3dSCy Schubert 	if (evbuffer_get_length(evhttp_request_get_input_buffer(req)) != 13 + 18 + 8) {
33022b15cb3dSCy Schubert 		fprintf(stderr, "FAILED\n");
33032b15cb3dSCy Schubert 		exit(1);
33042b15cb3dSCy Schubert 	}
33052b15cb3dSCy Schubert 
33062b15cb3dSCy Schubert 	if (strncmp((char *)evbuffer_pullup(evhttp_request_get_input_buffer(req), 13 + 18 + 8),
33072b15cb3dSCy Schubert 		"This is funnybut not hilarious.bwv 1052",
33082b15cb3dSCy Schubert 		13 + 18 + 8)) {
33092b15cb3dSCy Schubert 		fprintf(stderr, "FAILED\n");
33102b15cb3dSCy Schubert 		exit(1);
33112b15cb3dSCy Schubert 	}
33122b15cb3dSCy Schubert 
33132b15cb3dSCy Schubert 	test_ok = 1;
33142b15cb3dSCy Schubert 	event_base_loopexit(arg, NULL);
33152b15cb3dSCy Schubert }
33162b15cb3dSCy Schubert 
33172b15cb3dSCy Schubert static void
http_chunk_out_test_impl(void * arg,int ssl)3318*a466cc55SCy Schubert http_chunk_out_test_impl(void *arg, int ssl)
33192b15cb3dSCy Schubert {
33202b15cb3dSCy Schubert 	struct basic_test_data *data = arg;
3321*a466cc55SCy Schubert 	struct bufferevent *bev = NULL;
33222b15cb3dSCy Schubert 	evutil_socket_t fd;
33232b15cb3dSCy Schubert 	const char *http_request;
33242b15cb3dSCy Schubert 	ev_uint16_t port = 0;
33252b15cb3dSCy Schubert 	struct timeval tv_start, tv_end;
33262b15cb3dSCy Schubert 	struct evhttp_connection *evcon = NULL;
33272b15cb3dSCy Schubert 	struct evhttp_request *req = NULL;
33282b15cb3dSCy Schubert 	int i;
3329*a466cc55SCy Schubert 	struct evhttp *http = http_setup(&port, data->base, ssl ? HTTP_BIND_SSL : 0);
33302b15cb3dSCy Schubert 
33312b15cb3dSCy Schubert 	exit_base = data->base;
33322b15cb3dSCy Schubert 	test_ok = 0;
33332b15cb3dSCy Schubert 
33342b15cb3dSCy Schubert 	fd = http_connect("127.0.0.1", port);
3335*a466cc55SCy Schubert 	tt_assert(fd != EVUTIL_INVALID_SOCKET);
33362b15cb3dSCy Schubert 
33372b15cb3dSCy Schubert 	/* Stupid thing to send a request */
3338*a466cc55SCy Schubert 	bev = create_bev(data->base, fd, ssl, BEV_OPT_CLOSE_ON_FREE);
33392b15cb3dSCy Schubert 	bufferevent_setcb(bev,
33402b15cb3dSCy Schubert 	    http_chunked_readcb, http_chunked_writecb,
33412b15cb3dSCy Schubert 	    http_chunked_errorcb, data->base);
33422b15cb3dSCy Schubert 
33432b15cb3dSCy Schubert 	http_request =
33442b15cb3dSCy Schubert 	    "GET /chunked HTTP/1.1\r\n"
33452b15cb3dSCy Schubert 	    "Host: somehost\r\n"
33462b15cb3dSCy Schubert 	    "Connection: close\r\n"
33472b15cb3dSCy Schubert 	    "\r\n";
33482b15cb3dSCy Schubert 
33492b15cb3dSCy Schubert 	bufferevent_write(bev, http_request, strlen(http_request));
33502b15cb3dSCy Schubert 
33512b15cb3dSCy Schubert 	evutil_gettimeofday(&tv_start, NULL);
33522b15cb3dSCy Schubert 
33532b15cb3dSCy Schubert 	event_base_dispatch(data->base);
33542b15cb3dSCy Schubert 
33552b15cb3dSCy Schubert 	bufferevent_free(bev);
3356*a466cc55SCy Schubert 	bev = NULL;
33572b15cb3dSCy Schubert 
33582b15cb3dSCy Schubert 	evutil_gettimeofday(&tv_end, NULL);
33592b15cb3dSCy Schubert 	evutil_timersub(&tv_end, &tv_start, &tv_end);
33602b15cb3dSCy Schubert 
33612b15cb3dSCy Schubert 	tt_int_op(tv_end.tv_sec, <, 1);
33622b15cb3dSCy Schubert 
33632b15cb3dSCy Schubert 	tt_int_op(test_ok, ==, 2);
33642b15cb3dSCy Schubert 
33652b15cb3dSCy Schubert 	/* now try again with the regular connection object */
3366*a466cc55SCy Schubert 	bev = create_bev(data->base, -1, ssl, BEV_OPT_CLOSE_ON_FREE);
3367*a466cc55SCy Schubert 	evcon = evhttp_connection_base_bufferevent_new(
3368*a466cc55SCy Schubert 		data->base, NULL, bev, "127.0.0.1", port);
33692b15cb3dSCy Schubert 	tt_assert(evcon);
33702b15cb3dSCy Schubert 
33712b15cb3dSCy Schubert 	/* make two requests to check the keepalive behavior */
33722b15cb3dSCy Schubert 	for (i = 0; i < 2; i++) {
33732b15cb3dSCy Schubert 		test_ok = 0;
33742b15cb3dSCy Schubert 		req = evhttp_request_new(http_chunked_request_done, data->base);
33752b15cb3dSCy Schubert 
33762b15cb3dSCy Schubert 		/* Add the information that we care about */
33772b15cb3dSCy Schubert 		evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
33782b15cb3dSCy Schubert 
33792b15cb3dSCy Schubert 		/* We give ownership of the request to the connection */
3380*a466cc55SCy Schubert 		if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/chunked") == -1) {
33812b15cb3dSCy Schubert 			tt_abort_msg("Couldn't make request");
33822b15cb3dSCy Schubert 		}
33832b15cb3dSCy Schubert 
33842b15cb3dSCy Schubert 		event_base_dispatch(data->base);
33852b15cb3dSCy Schubert 
33862b15cb3dSCy Schubert 		tt_assert(test_ok == 1);
33872b15cb3dSCy Schubert 	}
33882b15cb3dSCy Schubert 
33892b15cb3dSCy Schubert  end:
33902b15cb3dSCy Schubert 	if (evcon)
33912b15cb3dSCy Schubert 		evhttp_connection_free(evcon);
33922b15cb3dSCy Schubert 	if (http)
33932b15cb3dSCy Schubert 		evhttp_free(http);
33942b15cb3dSCy Schubert }
http_chunk_out_test(void * arg)3395*a466cc55SCy Schubert static void http_chunk_out_test(void *arg)
3396*a466cc55SCy Schubert { http_chunk_out_test_impl(arg, 0); }
33972b15cb3dSCy Schubert 
33982b15cb3dSCy Schubert static void
http_stream_out_test_impl(void * arg,int ssl)3399*a466cc55SCy Schubert http_stream_out_test_impl(void *arg, int ssl)
34002b15cb3dSCy Schubert {
34012b15cb3dSCy Schubert 	struct basic_test_data *data = arg;
34022b15cb3dSCy Schubert 	ev_uint16_t port = 0;
34032b15cb3dSCy Schubert 	struct evhttp_connection *evcon = NULL;
34042b15cb3dSCy Schubert 	struct evhttp_request *req = NULL;
3405*a466cc55SCy Schubert 	struct bufferevent *bev;
3406*a466cc55SCy Schubert 	struct evhttp *http = http_setup(&port, data->base, ssl ? HTTP_BIND_SSL : 0);
34072b15cb3dSCy Schubert 
34082b15cb3dSCy Schubert 	test_ok = 0;
34092b15cb3dSCy Schubert 	exit_base = data->base;
34102b15cb3dSCy Schubert 
3411*a466cc55SCy Schubert 	bev = create_bev(data->base, -1, ssl, 0);
3412*a466cc55SCy Schubert 	evcon = evhttp_connection_base_bufferevent_new(
3413*a466cc55SCy Schubert 		data->base, NULL, bev, "127.0.0.1", port);
34142b15cb3dSCy Schubert 	tt_assert(evcon);
34152b15cb3dSCy Schubert 
34162b15cb3dSCy Schubert 	/*
34172b15cb3dSCy Schubert 	 * At this point, we want to schedule a request to the HTTP
34182b15cb3dSCy Schubert 	 * server using our make request method.
34192b15cb3dSCy Schubert 	 */
34202b15cb3dSCy Schubert 
34212b15cb3dSCy Schubert 	req = evhttp_request_new(http_request_done,
34222b15cb3dSCy Schubert 	    (void *)"This is funnybut not hilarious.bwv 1052");
34232b15cb3dSCy Schubert 
34242b15cb3dSCy Schubert 	/* Add the information that we care about */
34252b15cb3dSCy Schubert 	evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
34262b15cb3dSCy Schubert 
34272b15cb3dSCy Schubert 	/* We give ownership of the request to the connection */
34282b15cb3dSCy Schubert 	if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/streamed")
34292b15cb3dSCy Schubert 	    == -1) {
34302b15cb3dSCy Schubert 		tt_abort_msg("Couldn't make request");
34312b15cb3dSCy Schubert 	}
34322b15cb3dSCy Schubert 
34332b15cb3dSCy Schubert 	event_base_dispatch(data->base);
34342b15cb3dSCy Schubert 
34352b15cb3dSCy Schubert  end:
34362b15cb3dSCy Schubert 	if (evcon)
34372b15cb3dSCy Schubert 		evhttp_connection_free(evcon);
34382b15cb3dSCy Schubert 	if (http)
34392b15cb3dSCy Schubert 		evhttp_free(http);
34402b15cb3dSCy Schubert }
http_stream_out_test(void * arg)3441*a466cc55SCy Schubert static void http_stream_out_test(void *arg)
3442*a466cc55SCy Schubert { http_stream_out_test_impl(arg, 0); }
34432b15cb3dSCy Schubert 
34442b15cb3dSCy Schubert static void
http_stream_in_chunk(struct evhttp_request * req,void * arg)34452b15cb3dSCy Schubert http_stream_in_chunk(struct evhttp_request *req, void *arg)
34462b15cb3dSCy Schubert {
34472b15cb3dSCy Schubert 	struct evbuffer *reply = arg;
34482b15cb3dSCy Schubert 
34492b15cb3dSCy Schubert 	if (evhttp_request_get_response_code(req) != HTTP_OK) {
34502b15cb3dSCy Schubert 		fprintf(stderr, "FAILED\n");
34512b15cb3dSCy Schubert 		exit(1);
34522b15cb3dSCy Schubert 	}
34532b15cb3dSCy Schubert 
34542b15cb3dSCy Schubert 	evbuffer_add_buffer(reply, evhttp_request_get_input_buffer(req));
34552b15cb3dSCy Schubert }
34562b15cb3dSCy Schubert 
34572b15cb3dSCy Schubert static void
http_stream_in_done(struct evhttp_request * req,void * arg)34582b15cb3dSCy Schubert http_stream_in_done(struct evhttp_request *req, void *arg)
34592b15cb3dSCy Schubert {
34602b15cb3dSCy Schubert 	if (evbuffer_get_length(evhttp_request_get_input_buffer(req)) != 0) {
34612b15cb3dSCy Schubert 		fprintf(stderr, "FAILED\n");
34622b15cb3dSCy Schubert 		exit(1);
34632b15cb3dSCy Schubert 	}
34642b15cb3dSCy Schubert 
34652b15cb3dSCy Schubert 	event_base_loopexit(exit_base, NULL);
34662b15cb3dSCy Schubert }
34672b15cb3dSCy Schubert 
34682b15cb3dSCy Schubert /**
34692b15cb3dSCy Schubert  * Makes a request and reads the response in chunks.
34702b15cb3dSCy Schubert  */
34712b15cb3dSCy Schubert static void
http_stream_in_test_(struct basic_test_data * data,char const * url,size_t expected_len,char const * expected)34722b15cb3dSCy Schubert http_stream_in_test_(struct basic_test_data *data, char const *url,
34732b15cb3dSCy Schubert     size_t expected_len, char const *expected)
34742b15cb3dSCy Schubert {
34752b15cb3dSCy Schubert 	struct evhttp_connection *evcon;
34762b15cb3dSCy Schubert 	struct evbuffer *reply = evbuffer_new();
34772b15cb3dSCy Schubert 	struct evhttp_request *req = NULL;
34782b15cb3dSCy Schubert 	ev_uint16_t port = 0;
3479*a466cc55SCy Schubert 	struct evhttp *http = http_setup(&port, data->base, 0);
34802b15cb3dSCy Schubert 
34812b15cb3dSCy Schubert 	exit_base = data->base;
34822b15cb3dSCy Schubert 
34832b15cb3dSCy Schubert 	evcon = evhttp_connection_base_new(data->base, NULL,"127.0.0.1", port);
34842b15cb3dSCy Schubert 	tt_assert(evcon);
34852b15cb3dSCy Schubert 
34862b15cb3dSCy Schubert 	req = evhttp_request_new(http_stream_in_done, reply);
34872b15cb3dSCy Schubert 	evhttp_request_set_chunked_cb(req, http_stream_in_chunk);
34882b15cb3dSCy Schubert 
34892b15cb3dSCy Schubert 	/* We give ownership of the request to the connection */
34902b15cb3dSCy Schubert 	if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, url) == -1) {
34912b15cb3dSCy Schubert 		tt_abort_msg("Couldn't make request");
34922b15cb3dSCy Schubert 	}
34932b15cb3dSCy Schubert 
34942b15cb3dSCy Schubert 	event_base_dispatch(data->base);
34952b15cb3dSCy Schubert 
34962b15cb3dSCy Schubert 	if (evbuffer_get_length(reply) != expected_len) {
34972b15cb3dSCy Schubert 		TT_DIE(("reply length %lu; expected %lu; FAILED (%s)\n",
34982b15cb3dSCy Schubert 				(unsigned long)evbuffer_get_length(reply),
34992b15cb3dSCy Schubert 				(unsigned long)expected_len,
35002b15cb3dSCy Schubert 				(char*)evbuffer_pullup(reply, -1)));
35012b15cb3dSCy Schubert 	}
35022b15cb3dSCy Schubert 
35032b15cb3dSCy Schubert 	if (memcmp(evbuffer_pullup(reply, -1), expected, expected_len) != 0) {
35042b15cb3dSCy Schubert 		tt_abort_msg("Memory mismatch");
35052b15cb3dSCy Schubert 	}
35062b15cb3dSCy Schubert 
35072b15cb3dSCy Schubert 	test_ok = 1;
35082b15cb3dSCy Schubert  end:
35092b15cb3dSCy Schubert 	if (reply)
35102b15cb3dSCy Schubert 		evbuffer_free(reply);
35112b15cb3dSCy Schubert 	if (evcon)
35122b15cb3dSCy Schubert 		evhttp_connection_free(evcon);
35132b15cb3dSCy Schubert 	if (http)
35142b15cb3dSCy Schubert 		evhttp_free(http);
35152b15cb3dSCy Schubert }
35162b15cb3dSCy Schubert 
35172b15cb3dSCy Schubert static void
http_stream_in_test(void * arg)35182b15cb3dSCy Schubert http_stream_in_test(void *arg)
35192b15cb3dSCy Schubert {
35202b15cb3dSCy Schubert 	http_stream_in_test_(arg, "/chunked", 13 + 18 + 8,
35212b15cb3dSCy Schubert 	    "This is funnybut not hilarious.bwv 1052");
35222b15cb3dSCy Schubert 
35232b15cb3dSCy Schubert 	http_stream_in_test_(arg, "/test", strlen(BASIC_REQUEST_BODY),
35242b15cb3dSCy Schubert 	    BASIC_REQUEST_BODY);
35252b15cb3dSCy Schubert }
35262b15cb3dSCy Schubert 
35272b15cb3dSCy Schubert static void
http_stream_in_cancel_chunk(struct evhttp_request * req,void * arg)35282b15cb3dSCy Schubert http_stream_in_cancel_chunk(struct evhttp_request *req, void *arg)
35292b15cb3dSCy Schubert {
35302b15cb3dSCy Schubert 	tt_int_op(evhttp_request_get_response_code(req), ==, HTTP_OK);
35312b15cb3dSCy Schubert 
35322b15cb3dSCy Schubert  end:
35332b15cb3dSCy Schubert 	evhttp_cancel_request(req);
35342b15cb3dSCy Schubert 	event_base_loopexit(arg, NULL);
35352b15cb3dSCy Schubert }
35362b15cb3dSCy Schubert 
35372b15cb3dSCy Schubert static void
http_stream_in_cancel_done(struct evhttp_request * req,void * arg)35382b15cb3dSCy Schubert http_stream_in_cancel_done(struct evhttp_request *req, void *arg)
35392b15cb3dSCy Schubert {
35402b15cb3dSCy Schubert 	/* should never be called */
35412b15cb3dSCy Schubert 	tt_fail_msg("In cancel done");
35422b15cb3dSCy Schubert }
35432b15cb3dSCy Schubert 
35442b15cb3dSCy Schubert static void
http_stream_in_cancel_test(void * arg)35452b15cb3dSCy Schubert http_stream_in_cancel_test(void *arg)
35462b15cb3dSCy Schubert {
35472b15cb3dSCy Schubert 	struct basic_test_data *data = arg;
35482b15cb3dSCy Schubert 	struct evhttp_connection *evcon;
35492b15cb3dSCy Schubert 	struct evhttp_request *req = NULL;
35502b15cb3dSCy Schubert 	ev_uint16_t port = 0;
3551*a466cc55SCy Schubert 	struct evhttp *http = http_setup(&port, data->base, 0);
35522b15cb3dSCy Schubert 
35532b15cb3dSCy Schubert 	evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port);
35542b15cb3dSCy Schubert 	tt_assert(evcon);
35552b15cb3dSCy Schubert 
35562b15cb3dSCy Schubert 	req = evhttp_request_new(http_stream_in_cancel_done, data->base);
35572b15cb3dSCy Schubert 	evhttp_request_set_chunked_cb(req, http_stream_in_cancel_chunk);
35582b15cb3dSCy Schubert 
35592b15cb3dSCy Schubert 	/* We give ownership of the request to the connection */
35602b15cb3dSCy Schubert 	if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/chunked") == -1) {
35612b15cb3dSCy Schubert 		tt_abort_msg("Couldn't make request");
35622b15cb3dSCy Schubert 	}
35632b15cb3dSCy Schubert 
35642b15cb3dSCy Schubert 	event_base_dispatch(data->base);
35652b15cb3dSCy Schubert 
35662b15cb3dSCy Schubert 	test_ok = 1;
35672b15cb3dSCy Schubert  end:
35682b15cb3dSCy Schubert 	evhttp_connection_free(evcon);
35692b15cb3dSCy Schubert 	evhttp_free(http);
35702b15cb3dSCy Schubert 
35712b15cb3dSCy Schubert }
35722b15cb3dSCy Schubert 
35732b15cb3dSCy Schubert static void
http_connection_fail_done(struct evhttp_request * req,void * arg)35742b15cb3dSCy Schubert http_connection_fail_done(struct evhttp_request *req, void *arg)
35752b15cb3dSCy Schubert {
35762b15cb3dSCy Schubert 	struct evhttp_connection *evcon = arg;
35772b15cb3dSCy Schubert 	struct event_base *base = evhttp_connection_get_base(evcon);
35782b15cb3dSCy Schubert 
35792b15cb3dSCy Schubert 	/* An ENETUNREACH error results in an unrecoverable
35802b15cb3dSCy Schubert 	 * evhttp_connection error (see evhttp_connection_fail_()).  The
35812b15cb3dSCy Schubert 	 * connection will be reset, and the user will be notified with a NULL
35822b15cb3dSCy Schubert 	 * req parameter. */
35832b15cb3dSCy Schubert 	tt_assert(!req);
35842b15cb3dSCy Schubert 
35852b15cb3dSCy Schubert 	evhttp_connection_free(evcon);
35862b15cb3dSCy Schubert 
35872b15cb3dSCy Schubert 	test_ok = 1;
35882b15cb3dSCy Schubert 
35892b15cb3dSCy Schubert  end:
35902b15cb3dSCy Schubert 	event_base_loopexit(base, NULL);
35912b15cb3dSCy Schubert }
35922b15cb3dSCy Schubert 
35932b15cb3dSCy Schubert /* Test unrecoverable evhttp_connection errors by generating an ENETUNREACH
35942b15cb3dSCy Schubert  * error on connection. */
35952b15cb3dSCy Schubert static void
http_connection_fail_test_impl(void * arg,int ssl)3596*a466cc55SCy Schubert http_connection_fail_test_impl(void *arg, int ssl)
35972b15cb3dSCy Schubert {
35982b15cb3dSCy Schubert 	struct basic_test_data *data = arg;
35992b15cb3dSCy Schubert 	ev_uint16_t port = 0;
36002b15cb3dSCy Schubert 	struct evhttp_connection *evcon = NULL;
36012b15cb3dSCy Schubert 	struct evhttp_request *req = NULL;
3602*a466cc55SCy Schubert 	struct bufferevent *bev;
3603*a466cc55SCy Schubert 	struct evhttp *http = http_setup(&port, data->base, ssl ? HTTP_BIND_SSL : 0);
36042b15cb3dSCy Schubert 
36052b15cb3dSCy Schubert 	exit_base = data->base;
36062b15cb3dSCy Schubert 	test_ok = 0;
36072b15cb3dSCy Schubert 
36082b15cb3dSCy Schubert 	/* auto detect a port */
36092b15cb3dSCy Schubert 	evhttp_free(http);
36102b15cb3dSCy Schubert 
3611*a466cc55SCy Schubert 	bev = create_bev(data->base, -1, ssl, 0);
36122b15cb3dSCy Schubert 	/* Pick an unroutable address. This administratively scoped multicast
36132b15cb3dSCy Schubert 	 * address should do when working with TCP. */
3614*a466cc55SCy Schubert 	evcon = evhttp_connection_base_bufferevent_new(
3615*a466cc55SCy Schubert 		data->base, NULL, bev, "239.10.20.30", 80);
36162b15cb3dSCy Schubert 	tt_assert(evcon);
36172b15cb3dSCy Schubert 
36182b15cb3dSCy Schubert 	/*
36192b15cb3dSCy Schubert 	 * At this point, we want to schedule an HTTP GET request
36202b15cb3dSCy Schubert 	 * server using our make request method.
36212b15cb3dSCy Schubert 	 */
36222b15cb3dSCy Schubert 
36232b15cb3dSCy Schubert 	req = evhttp_request_new(http_connection_fail_done, evcon);
36242b15cb3dSCy Schubert 	tt_assert(req);
36252b15cb3dSCy Schubert 
36262b15cb3dSCy Schubert 	if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/") == -1) {
36272b15cb3dSCy Schubert 		tt_abort_msg("Couldn't make request");
36282b15cb3dSCy Schubert 	}
36292b15cb3dSCy Schubert 
36302b15cb3dSCy Schubert 	event_base_dispatch(data->base);
36312b15cb3dSCy Schubert 
36322b15cb3dSCy Schubert 	tt_int_op(test_ok, ==, 1);
36332b15cb3dSCy Schubert 
36342b15cb3dSCy Schubert  end:
36352b15cb3dSCy Schubert 	;
36362b15cb3dSCy Schubert }
http_connection_fail_test(void * arg)3637*a466cc55SCy Schubert static void http_connection_fail_test(void *arg)
3638*a466cc55SCy Schubert { http_connection_fail_test_impl(arg, 0); }
36392b15cb3dSCy Schubert 
36402b15cb3dSCy Schubert static void
http_connection_retry_done(struct evhttp_request * req,void * arg)36412b15cb3dSCy Schubert http_connection_retry_done(struct evhttp_request *req, void *arg)
36422b15cb3dSCy Schubert {
36432b15cb3dSCy Schubert 	tt_assert(req);
36442b15cb3dSCy Schubert 	tt_int_op(evhttp_request_get_response_code(req), !=, HTTP_OK);
36452b15cb3dSCy Schubert 	if (evhttp_find_header(evhttp_request_get_input_headers(req), "Content-Type") != NULL) {
36462b15cb3dSCy Schubert 		tt_abort_msg("(content type)\n");
36472b15cb3dSCy Schubert 	}
36482b15cb3dSCy Schubert 
36492b15cb3dSCy Schubert 	tt_uint_op(evbuffer_get_length(evhttp_request_get_input_buffer(req)), ==, 0);
36502b15cb3dSCy Schubert 
36512b15cb3dSCy Schubert 	test_ok = 1;
36522b15cb3dSCy Schubert  end:
36532b15cb3dSCy Schubert 	event_base_loopexit(arg,NULL);
36542b15cb3dSCy Schubert }
36552b15cb3dSCy Schubert 
3656*a466cc55SCy Schubert struct http_server
3657*a466cc55SCy Schubert {
3658*a466cc55SCy Schubert 	ev_uint16_t port;
3659*a466cc55SCy Schubert 	int ssl;
3660*a466cc55SCy Schubert 	struct evhttp *http;
3661*a466cc55SCy Schubert };
36622b15cb3dSCy Schubert static struct event_base *http_make_web_server_base=NULL;
36632b15cb3dSCy Schubert static void
http_make_web_server(evutil_socket_t fd,short what,void * arg)36642b15cb3dSCy Schubert http_make_web_server(evutil_socket_t fd, short what, void *arg)
36652b15cb3dSCy Schubert {
3666*a466cc55SCy Schubert 	struct http_server *hs = (struct http_server *)arg;
3667*a466cc55SCy Schubert 	hs->http = http_setup(&hs->port, http_make_web_server_base, hs->ssl ? HTTP_BIND_SSL : 0);
36682b15cb3dSCy Schubert }
36692b15cb3dSCy Schubert 
36702b15cb3dSCy Schubert static void
http_simple_test_impl(void * arg,int ssl,int dirty,const char * uri)3671*a466cc55SCy Schubert http_simple_test_impl(void *arg, int ssl, int dirty, const char *uri)
36722b15cb3dSCy Schubert {
36732b15cb3dSCy Schubert 	struct basic_test_data *data = arg;
3674*a466cc55SCy Schubert 	struct evhttp_connection *evcon = NULL;
3675*a466cc55SCy Schubert 	struct evhttp_request *req = NULL;
3676*a466cc55SCy Schubert 	struct bufferevent *bev;
3677*a466cc55SCy Schubert 	struct http_server hs = { 0, ssl, NULL, };
3678*a466cc55SCy Schubert 	struct evhttp *http = http_setup(&hs.port, data->base, ssl ? HTTP_BIND_SSL : 0);
3679*a466cc55SCy Schubert 
3680*a466cc55SCy Schubert 	exit_base = data->base;
3681*a466cc55SCy Schubert 	test_ok = 0;
3682*a466cc55SCy Schubert 
3683*a466cc55SCy Schubert 	bev = create_bev(data->base, -1, ssl, 0);
3684*a466cc55SCy Schubert #ifdef EVENT__HAVE_OPENSSL
3685*a466cc55SCy Schubert 	bufferevent_openssl_set_allow_dirty_shutdown(bev, dirty);
3686*a466cc55SCy Schubert #endif
3687*a466cc55SCy Schubert 
3688*a466cc55SCy Schubert 	evcon = evhttp_connection_base_bufferevent_new(
3689*a466cc55SCy Schubert 		data->base, NULL, bev, "127.0.0.1", hs.port);
3690*a466cc55SCy Schubert 	tt_assert(evcon);
3691*a466cc55SCy Schubert 	evhttp_connection_set_local_address(evcon, "127.0.0.1");
3692*a466cc55SCy Schubert 
3693*a466cc55SCy Schubert 	req = evhttp_request_new(http_request_done, (void*) BASIC_REQUEST_BODY);
3694*a466cc55SCy Schubert 	tt_assert(req);
3695*a466cc55SCy Schubert 
3696*a466cc55SCy Schubert 	if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, uri) == -1)
3697*a466cc55SCy Schubert 		tt_abort_msg("Couldn't make request");
3698*a466cc55SCy Schubert 
3699*a466cc55SCy Schubert 	event_base_dispatch(data->base);
3700*a466cc55SCy Schubert 	tt_int_op(test_ok, ==, 1);
3701*a466cc55SCy Schubert 
3702*a466cc55SCy Schubert  end:
3703*a466cc55SCy Schubert 	if (evcon)
3704*a466cc55SCy Schubert 		evhttp_connection_free(evcon);
3705*a466cc55SCy Schubert 	if (http)
3706*a466cc55SCy Schubert 		evhttp_free(http);
3707*a466cc55SCy Schubert }
http_simple_test(void * arg)3708*a466cc55SCy Schubert static void http_simple_test(void *arg)
3709*a466cc55SCy Schubert { http_simple_test_impl(arg, 0, 0, "/test"); }
http_simple_nonconformant_test(void * arg)3710*a466cc55SCy Schubert static void http_simple_nonconformant_test(void *arg)
3711*a466cc55SCy Schubert { http_simple_test_impl(arg, 0, 0, "/test nonconformant"); }
3712*a466cc55SCy Schubert 
3713*a466cc55SCy Schubert static void
http_connection_retry_test_basic(void * arg,const char * addr,struct evdns_base * dns_base,int ssl)3714*a466cc55SCy Schubert http_connection_retry_test_basic(void *arg, const char *addr, struct evdns_base *dns_base, int ssl)
3715*a466cc55SCy Schubert {
3716*a466cc55SCy Schubert 	struct basic_test_data *data = arg;
37172b15cb3dSCy Schubert 	struct evhttp_connection *evcon = NULL;
37182b15cb3dSCy Schubert 	struct evhttp_request *req = NULL;
37192b15cb3dSCy Schubert 	struct timeval tv, tv_start, tv_end;
3720*a466cc55SCy Schubert 	struct bufferevent *bev;
3721*a466cc55SCy Schubert 	struct http_server hs = { 0, ssl, NULL, };
3722*a466cc55SCy Schubert 	struct evhttp *http = http_setup(&hs.port, data->base, ssl ? HTTP_BIND_SSL : 0);
37232b15cb3dSCy Schubert 
37242b15cb3dSCy Schubert 	exit_base = data->base;
37252b15cb3dSCy Schubert 	test_ok = 0;
37262b15cb3dSCy Schubert 
37272b15cb3dSCy Schubert 	/* auto detect a port */
37282b15cb3dSCy Schubert 	evhttp_free(http);
37292b15cb3dSCy Schubert 
3730*a466cc55SCy Schubert 	bev = create_bev(data->base, -1, ssl, 0);
3731*a466cc55SCy Schubert 	evcon = evhttp_connection_base_bufferevent_new(data->base, dns_base, bev, addr, hs.port);
37322b15cb3dSCy Schubert 	tt_assert(evcon);
3733*a466cc55SCy Schubert 	if (dns_base)
3734*a466cc55SCy Schubert 		tt_assert(!evhttp_connection_set_flags(evcon, EVHTTP_CON_REUSE_CONNECTED_ADDR));
37352b15cb3dSCy Schubert 
37362b15cb3dSCy Schubert 	evhttp_connection_set_timeout(evcon, 1);
37372b15cb3dSCy Schubert 	/* also bind to local host */
37382b15cb3dSCy Schubert 	evhttp_connection_set_local_address(evcon, "127.0.0.1");
37392b15cb3dSCy Schubert 
37402b15cb3dSCy Schubert 	/*
37412b15cb3dSCy Schubert 	 * At this point, we want to schedule an HTTP GET request
37422b15cb3dSCy Schubert 	 * server using our make request method.
37432b15cb3dSCy Schubert 	 */
37442b15cb3dSCy Schubert 
37452b15cb3dSCy Schubert 	req = evhttp_request_new(http_connection_retry_done, data->base);
37462b15cb3dSCy Schubert 	tt_assert(req);
37472b15cb3dSCy Schubert 
37482b15cb3dSCy Schubert 	/* Add the information that we care about */
37492b15cb3dSCy Schubert 	evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
37502b15cb3dSCy Schubert 
37512b15cb3dSCy Schubert 	if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET,
37522b15cb3dSCy Schubert 		"/?arg=val") == -1) {
37532b15cb3dSCy Schubert 		tt_abort_msg("Couldn't make request");
37542b15cb3dSCy Schubert 	}
37552b15cb3dSCy Schubert 
37562b15cb3dSCy Schubert 	evutil_gettimeofday(&tv_start, NULL);
37572b15cb3dSCy Schubert 	event_base_dispatch(data->base);
37582b15cb3dSCy Schubert 	evutil_gettimeofday(&tv_end, NULL);
37592b15cb3dSCy Schubert 	evutil_timersub(&tv_end, &tv_start, &tv_end);
37602b15cb3dSCy Schubert 	tt_int_op(tv_end.tv_sec, <, 1);
37612b15cb3dSCy Schubert 
37622b15cb3dSCy Schubert 	tt_int_op(test_ok, ==, 1);
37632b15cb3dSCy Schubert 
37642b15cb3dSCy Schubert 	/*
37652b15cb3dSCy Schubert 	 * now test the same but with retries
37662b15cb3dSCy Schubert 	 */
37672b15cb3dSCy Schubert 	test_ok = 0;
3768*a466cc55SCy Schubert 	/** Shutdown dns server, to test conn_address reusing */
3769*a466cc55SCy Schubert 	if (dns_base)
3770*a466cc55SCy Schubert 		regress_clean_dnsserver();
37712b15cb3dSCy Schubert 
37722b15cb3dSCy Schubert 	{
37732b15cb3dSCy Schubert 		const struct timeval tv_timeout = { 0, 500000 };
37742b15cb3dSCy Schubert 		const struct timeval tv_retry = { 0, 500000 };
37752b15cb3dSCy Schubert 		evhttp_connection_set_timeout_tv(evcon, &tv_timeout);
37762b15cb3dSCy Schubert 		evhttp_connection_set_initial_retry_tv(evcon, &tv_retry);
37772b15cb3dSCy Schubert 	}
37782b15cb3dSCy Schubert 	evhttp_connection_set_retries(evcon, 1);
37792b15cb3dSCy Schubert 
37802b15cb3dSCy Schubert 	req = evhttp_request_new(http_connection_retry_done, data->base);
37812b15cb3dSCy Schubert 	tt_assert(req);
37822b15cb3dSCy Schubert 
37832b15cb3dSCy Schubert 	/* Add the information that we care about */
37842b15cb3dSCy Schubert 	evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
37852b15cb3dSCy Schubert 
37862b15cb3dSCy Schubert 	if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET,
37872b15cb3dSCy Schubert 		"/?arg=val") == -1) {
37882b15cb3dSCy Schubert 		tt_abort_msg("Couldn't make request");
37892b15cb3dSCy Schubert 	}
37902b15cb3dSCy Schubert 
37912b15cb3dSCy Schubert 	evutil_gettimeofday(&tv_start, NULL);
37922b15cb3dSCy Schubert 	event_base_dispatch(data->base);
37932b15cb3dSCy Schubert 	evutil_gettimeofday(&tv_end, NULL);
37942b15cb3dSCy Schubert 
37952b15cb3dSCy Schubert 	/* fails fast, .5 sec to wait to retry, fails fast again. */
37962b15cb3dSCy Schubert 	test_timeval_diff_leq(&tv_start, &tv_end, 500, 200);
37972b15cb3dSCy Schubert 
37982b15cb3dSCy Schubert 	tt_assert(test_ok == 1);
37992b15cb3dSCy Schubert 
38002b15cb3dSCy Schubert 	/*
38012b15cb3dSCy Schubert 	 * now test the same but with retries and give it a web server
38022b15cb3dSCy Schubert 	 * at the end
38032b15cb3dSCy Schubert 	 */
38042b15cb3dSCy Schubert 	test_ok = 0;
38052b15cb3dSCy Schubert 
38062b15cb3dSCy Schubert 	evhttp_connection_set_timeout(evcon, 1);
38072b15cb3dSCy Schubert 	evhttp_connection_set_retries(evcon, 3);
38082b15cb3dSCy Schubert 
38092b15cb3dSCy Schubert 	req = evhttp_request_new(http_dispatcher_test_done, data->base);
38102b15cb3dSCy Schubert 	tt_assert(req);
38112b15cb3dSCy Schubert 
38122b15cb3dSCy Schubert 	/* Add the information that we care about */
38132b15cb3dSCy Schubert 	evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
38142b15cb3dSCy Schubert 
38152b15cb3dSCy Schubert 	if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET,
38162b15cb3dSCy Schubert 		"/?arg=val") == -1) {
38172b15cb3dSCy Schubert 		tt_abort_msg("Couldn't make request");
38182b15cb3dSCy Schubert 	}
38192b15cb3dSCy Schubert 
38202b15cb3dSCy Schubert 	/* start up a web server .2 seconds after the connection tried
38212b15cb3dSCy Schubert 	 * to send a request
38222b15cb3dSCy Schubert 	 */
38232b15cb3dSCy Schubert 	evutil_timerclear(&tv);
38242b15cb3dSCy Schubert 	tv.tv_usec = 200000;
38252b15cb3dSCy Schubert 	http_make_web_server_base = data->base;
3826*a466cc55SCy Schubert 	event_base_once(data->base, -1, EV_TIMEOUT, http_make_web_server, &hs, &tv);
38272b15cb3dSCy Schubert 
38282b15cb3dSCy Schubert 	evutil_gettimeofday(&tv_start, NULL);
38292b15cb3dSCy Schubert 	event_base_dispatch(data->base);
38302b15cb3dSCy Schubert 	evutil_gettimeofday(&tv_end, NULL);
38312b15cb3dSCy Schubert 	/* We'll wait twice as long as we did last time. */
38322b15cb3dSCy Schubert 	test_timeval_diff_leq(&tv_start, &tv_end, 1000, 400);
38332b15cb3dSCy Schubert 
38342b15cb3dSCy Schubert 	tt_int_op(test_ok, ==, 1);
38352b15cb3dSCy Schubert 
38362b15cb3dSCy Schubert  end:
38372b15cb3dSCy Schubert 	if (evcon)
38382b15cb3dSCy Schubert 		evhttp_connection_free(evcon);
38392b15cb3dSCy Schubert 	if (http)
3840*a466cc55SCy Schubert 		evhttp_free(hs.http);
38412b15cb3dSCy Schubert }
38422b15cb3dSCy Schubert 
38432b15cb3dSCy Schubert static void
http_connection_retry_conn_address_test_impl(void * arg,int ssl)3844*a466cc55SCy Schubert http_connection_retry_conn_address_test_impl(void *arg, int ssl)
3845*a466cc55SCy Schubert {
3846*a466cc55SCy Schubert 	struct basic_test_data *data = arg;
3847*a466cc55SCy Schubert 	ev_uint16_t portnum = 0;
3848*a466cc55SCy Schubert 	struct evdns_base *dns_base = NULL;
3849*a466cc55SCy Schubert 	char address[64];
3850*a466cc55SCy Schubert 
3851*a466cc55SCy Schubert 	tt_assert(regress_dnsserver(data->base, &portnum, search_table));
3852*a466cc55SCy Schubert 	dns_base = evdns_base_new(data->base, 0/* init name servers */);
3853*a466cc55SCy Schubert 	tt_assert(dns_base);
3854*a466cc55SCy Schubert 
3855*a466cc55SCy Schubert 	/* Add ourself as the only nameserver, and make sure we really are
3856*a466cc55SCy Schubert 	 * the only nameserver. */
3857*a466cc55SCy Schubert 	evutil_snprintf(address, sizeof(address), "127.0.0.1:%d", portnum);
3858*a466cc55SCy Schubert 	evdns_base_nameserver_ip_add(dns_base, address);
3859*a466cc55SCy Schubert 
3860*a466cc55SCy Schubert 	http_connection_retry_test_basic(arg, "localhost", dns_base, ssl);
3861*a466cc55SCy Schubert 
3862*a466cc55SCy Schubert  end:
3863*a466cc55SCy Schubert 	if (dns_base)
3864*a466cc55SCy Schubert 		evdns_base_free(dns_base, 0);
3865*a466cc55SCy Schubert 	/** dnsserver will be cleaned in http_connection_retry_test_basic() */
3866*a466cc55SCy Schubert }
http_connection_retry_conn_address_test(void * arg)3867*a466cc55SCy Schubert static void http_connection_retry_conn_address_test(void *arg)
3868*a466cc55SCy Schubert { http_connection_retry_conn_address_test_impl(arg, 0); }
3869*a466cc55SCy Schubert 
3870*a466cc55SCy Schubert static void
http_connection_retry_test_impl(void * arg,int ssl)3871*a466cc55SCy Schubert http_connection_retry_test_impl(void *arg, int ssl)
3872*a466cc55SCy Schubert {
3873*a466cc55SCy Schubert 	http_connection_retry_test_basic(arg, "127.0.0.1", NULL, ssl);
3874*a466cc55SCy Schubert }
3875*a466cc55SCy Schubert static void
http_connection_retry_test(void * arg)3876*a466cc55SCy Schubert http_connection_retry_test(void *arg)
3877*a466cc55SCy Schubert { http_connection_retry_test_impl(arg, 0); }
3878*a466cc55SCy Schubert 
3879*a466cc55SCy Schubert static void
http_primitives(void * ptr)38802b15cb3dSCy Schubert http_primitives(void *ptr)
38812b15cb3dSCy Schubert {
38822b15cb3dSCy Schubert 	char *escaped = NULL;
38832b15cb3dSCy Schubert 	struct evhttp *http = NULL;
38842b15cb3dSCy Schubert 
38852b15cb3dSCy Schubert 	escaped = evhttp_htmlescape("<script>");
38862b15cb3dSCy Schubert 	tt_assert(escaped);
38872b15cb3dSCy Schubert 	tt_str_op(escaped, ==, "&lt;script&gt;");
38882b15cb3dSCy Schubert 	free(escaped);
38892b15cb3dSCy Schubert 
38902b15cb3dSCy Schubert 	escaped = evhttp_htmlescape("\"\'&");
38912b15cb3dSCy Schubert 	tt_assert(escaped);
38922b15cb3dSCy Schubert 	tt_str_op(escaped, ==, "&quot;&#039;&amp;");
38932b15cb3dSCy Schubert 
38942b15cb3dSCy Schubert 	http = evhttp_new(NULL);
38952b15cb3dSCy Schubert 	tt_assert(http);
3896*a466cc55SCy Schubert 	tt_int_op(evhttp_set_cb(http, "/test", http_basic_cb, http), ==, 0);
3897*a466cc55SCy Schubert 	tt_int_op(evhttp_set_cb(http, "/test", http_basic_cb, http), ==, -1);
38982b15cb3dSCy Schubert 	tt_int_op(evhttp_del_cb(http, "/test"), ==, 0);
38992b15cb3dSCy Schubert 	tt_int_op(evhttp_del_cb(http, "/test"), ==, -1);
3900*a466cc55SCy Schubert 	tt_int_op(evhttp_set_cb(http, "/test", http_basic_cb, http), ==, 0);
39012b15cb3dSCy Schubert 
39022b15cb3dSCy Schubert  end:
39032b15cb3dSCy Schubert 	if (escaped)
39042b15cb3dSCy Schubert 		free(escaped);
39052b15cb3dSCy Schubert 	if (http)
39062b15cb3dSCy Schubert 		evhttp_free(http);
39072b15cb3dSCy Schubert }
39082b15cb3dSCy Schubert 
39092b15cb3dSCy Schubert static void
http_multi_line_header_test(void * arg)39102b15cb3dSCy Schubert http_multi_line_header_test(void *arg)
39112b15cb3dSCy Schubert {
39122b15cb3dSCy Schubert 	struct basic_test_data *data = arg;
39132b15cb3dSCy Schubert 	struct bufferevent *bev= NULL;
3914*a466cc55SCy Schubert 	evutil_socket_t fd = EVUTIL_INVALID_SOCKET;
39152b15cb3dSCy Schubert 	const char *http_start_request;
39162b15cb3dSCy Schubert 	ev_uint16_t port = 0;
3917*a466cc55SCy Schubert 	struct evhttp *http = http_setup(&port, data->base, 0);
39182b15cb3dSCy Schubert 
3919*a466cc55SCy Schubert 	exit_base = data->base;
39202b15cb3dSCy Schubert 	test_ok = 0;
39212b15cb3dSCy Schubert 
39222b15cb3dSCy Schubert 	tt_ptr_op(http, !=, NULL);
39232b15cb3dSCy Schubert 
39242b15cb3dSCy Schubert 	fd = http_connect("127.0.0.1", port);
3925*a466cc55SCy Schubert 	tt_assert(fd != EVUTIL_INVALID_SOCKET);
39262b15cb3dSCy Schubert 
39272b15cb3dSCy Schubert 	/* Stupid thing to send a request */
39282b15cb3dSCy Schubert 	bev = bufferevent_socket_new(data->base, fd, 0);
39292b15cb3dSCy Schubert 	tt_ptr_op(bev, !=, NULL);
39302b15cb3dSCy Schubert 	bufferevent_setcb(bev, http_readcb, http_writecb,
39312b15cb3dSCy Schubert 	    http_errorcb, data->base);
39322b15cb3dSCy Schubert 
39332b15cb3dSCy Schubert 	http_start_request =
39342b15cb3dSCy Schubert 	    "GET /test HTTP/1.1\r\n"
39352b15cb3dSCy Schubert 	    "Host: somehost\r\n"
39362b15cb3dSCy Schubert 	    "Connection: close\r\n"
39372b15cb3dSCy Schubert 	    "X-Multi-Extra-WS:  libevent  \r\n"
39382b15cb3dSCy Schubert 	    "\t\t\t2.1 \r\n"
39392b15cb3dSCy Schubert 	    "X-Multi:  aaaaaaaa\r\n"
39402b15cb3dSCy Schubert 	    " a\r\n"
39412b15cb3dSCy Schubert 	    "\tEND\r\n"
39422b15cb3dSCy Schubert 	    "X-Last: last\r\n"
39432b15cb3dSCy Schubert 	    "\r\n";
39442b15cb3dSCy Schubert 
39452b15cb3dSCy Schubert 	bufferevent_write(bev, http_start_request, strlen(http_start_request));
39462b15cb3dSCy Schubert 	found_multi = found_multi2 = 0;
39472b15cb3dSCy Schubert 
39482b15cb3dSCy Schubert 	event_base_dispatch(data->base);
39492b15cb3dSCy Schubert 
39502b15cb3dSCy Schubert 	tt_int_op(found_multi, ==, 1);
39512b15cb3dSCy Schubert 	tt_int_op(found_multi2, ==, 1);
39522b15cb3dSCy Schubert 	tt_int_op(test_ok, ==, 4);
39532b15cb3dSCy Schubert  end:
39542b15cb3dSCy Schubert 	if (bev)
39552b15cb3dSCy Schubert 		bufferevent_free(bev);
39562b15cb3dSCy Schubert 	if (fd >= 0)
39572b15cb3dSCy Schubert 		evutil_closesocket(fd);
39582b15cb3dSCy Schubert 	if (http)
39592b15cb3dSCy Schubert 		evhttp_free(http);
39602b15cb3dSCy Schubert }
39612b15cb3dSCy Schubert 
39622b15cb3dSCy Schubert static void
http_request_bad(struct evhttp_request * req,void * arg)39632b15cb3dSCy Schubert http_request_bad(struct evhttp_request *req, void *arg)
39642b15cb3dSCy Schubert {
39652b15cb3dSCy Schubert 	if (req != NULL) {
39662b15cb3dSCy Schubert 		fprintf(stderr, "FAILED\n");
39672b15cb3dSCy Schubert 		exit(1);
39682b15cb3dSCy Schubert 	}
39692b15cb3dSCy Schubert 
39702b15cb3dSCy Schubert 	test_ok = 1;
39712b15cb3dSCy Schubert 	event_base_loopexit(arg, NULL);
39722b15cb3dSCy Schubert }
39732b15cb3dSCy Schubert 
39742b15cb3dSCy Schubert static void
http_negative_content_length_test(void * arg)39752b15cb3dSCy Schubert http_negative_content_length_test(void *arg)
39762b15cb3dSCy Schubert {
39772b15cb3dSCy Schubert 	struct basic_test_data *data = arg;
39782b15cb3dSCy Schubert 	ev_uint16_t port = 0;
39792b15cb3dSCy Schubert 	struct evhttp_connection *evcon = NULL;
39802b15cb3dSCy Schubert 	struct evhttp_request *req = NULL;
3981*a466cc55SCy Schubert 	struct evhttp *http = http_setup(&port, data->base, 0);
39822b15cb3dSCy Schubert 
39832b15cb3dSCy Schubert 	test_ok = 0;
39842b15cb3dSCy Schubert 
39852b15cb3dSCy Schubert 	evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port);
39862b15cb3dSCy Schubert 	tt_assert(evcon);
39872b15cb3dSCy Schubert 
39882b15cb3dSCy Schubert 	/*
39892b15cb3dSCy Schubert 	 * At this point, we want to schedule a request to the HTTP
39902b15cb3dSCy Schubert 	 * server using our make request method.
39912b15cb3dSCy Schubert 	 */
39922b15cb3dSCy Schubert 
39932b15cb3dSCy Schubert 	req = evhttp_request_new(http_request_bad, data->base);
39942b15cb3dSCy Schubert 
39952b15cb3dSCy Schubert 	/* Cause the response to have a negative content-length */
39962b15cb3dSCy Schubert 	evhttp_add_header(evhttp_request_get_output_headers(req), "X-Negative", "makeitso");
39972b15cb3dSCy Schubert 
39982b15cb3dSCy Schubert 	/* We give ownership of the request to the connection */
39992b15cb3dSCy Schubert 	if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test") == -1) {
40002b15cb3dSCy Schubert 		tt_abort_msg("Couldn't make request");
40012b15cb3dSCy Schubert 	}
40022b15cb3dSCy Schubert 
40032b15cb3dSCy Schubert 	event_base_dispatch(data->base);
40042b15cb3dSCy Schubert 
40052b15cb3dSCy Schubert  end:
40062b15cb3dSCy Schubert 	if (evcon)
40072b15cb3dSCy Schubert 		evhttp_connection_free(evcon);
40082b15cb3dSCy Schubert 	if (http)
40092b15cb3dSCy Schubert 		evhttp_free(http);
40102b15cb3dSCy Schubert }
40112b15cb3dSCy Schubert 
40122b15cb3dSCy Schubert 
40132b15cb3dSCy Schubert static void
http_data_length_constraints_test_done(struct evhttp_request * req,void * arg)40142b15cb3dSCy Schubert http_data_length_constraints_test_done(struct evhttp_request *req, void *arg)
40152b15cb3dSCy Schubert {
40162b15cb3dSCy Schubert 	tt_assert(req);
40172b15cb3dSCy Schubert 	tt_int_op(evhttp_request_get_response_code(req), ==, HTTP_BADREQUEST);
40182b15cb3dSCy Schubert end:
40192b15cb3dSCy Schubert 	event_base_loopexit(arg, NULL);
40202b15cb3dSCy Schubert }
40212b15cb3dSCy Schubert static void
http_large_entity_test_done(struct evhttp_request * req,void * arg)40222b15cb3dSCy Schubert http_large_entity_test_done(struct evhttp_request *req, void *arg)
40232b15cb3dSCy Schubert {
40242b15cb3dSCy Schubert 	tt_assert(req);
40252b15cb3dSCy Schubert 	tt_int_op(evhttp_request_get_response_code(req), ==, HTTP_ENTITYTOOLARGE);
40262b15cb3dSCy Schubert end:
40272b15cb3dSCy Schubert 	event_base_loopexit(arg, NULL);
40282b15cb3dSCy Schubert }
4029*a466cc55SCy Schubert static void
http_expectation_failed_done(struct evhttp_request * req,void * arg)4030*a466cc55SCy Schubert http_expectation_failed_done(struct evhttp_request *req, void *arg)
4031*a466cc55SCy Schubert {
4032*a466cc55SCy Schubert 	tt_assert(req);
4033*a466cc55SCy Schubert 	tt_int_op(evhttp_request_get_response_code(req), ==, HTTP_EXPECTATIONFAILED);
4034*a466cc55SCy Schubert end:
4035*a466cc55SCy Schubert 	event_base_loopexit(arg, NULL);
4036*a466cc55SCy Schubert }
40372b15cb3dSCy Schubert 
40382b15cb3dSCy Schubert static void
http_data_length_constraints_test_impl(void * arg,int read_on_write_error)4039*a466cc55SCy Schubert http_data_length_constraints_test_impl(void *arg, int read_on_write_error)
40402b15cb3dSCy Schubert {
40412b15cb3dSCy Schubert 	struct basic_test_data *data = arg;
40422b15cb3dSCy Schubert 	ev_uint16_t port = 0;
40432b15cb3dSCy Schubert 	struct evhttp_connection *evcon = NULL;
40442b15cb3dSCy Schubert 	struct evhttp_request *req = NULL;
4045*a466cc55SCy Schubert 	char *long_str = NULL;
4046*a466cc55SCy Schubert 	const size_t continue_size = 1<<20;
4047*a466cc55SCy Schubert 	const size_t size = (1<<20) * 3;
4048*a466cc55SCy Schubert 	void (*cb)(struct evhttp_request *, void *);
4049*a466cc55SCy Schubert 	struct evhttp *http = http_setup(&port, data->base, 0);
40502b15cb3dSCy Schubert 
40512b15cb3dSCy Schubert 	test_ok = 0;
4052*a466cc55SCy Schubert 	cb = http_failed_request_done;
4053*a466cc55SCy Schubert 	if (read_on_write_error)
4054*a466cc55SCy Schubert 		cb = http_data_length_constraints_test_done;
40552b15cb3dSCy Schubert 
4056*a466cc55SCy Schubert 	tt_assert(continue_size < size);
40572b15cb3dSCy Schubert 
4058*a466cc55SCy Schubert 	long_str = malloc(size);
4059*a466cc55SCy Schubert 	memset(long_str, 'a', size);
4060*a466cc55SCy Schubert 	long_str[size - 1] = '\0';
4061*a466cc55SCy Schubert 
4062*a466cc55SCy Schubert 	TT_BLATHER(("Creating connection to :%i", port));
40632b15cb3dSCy Schubert 	evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port);
40642b15cb3dSCy Schubert 	tt_assert(evcon);
40652b15cb3dSCy Schubert 
4066*a466cc55SCy Schubert 	if (read_on_write_error)
4067*a466cc55SCy Schubert 		tt_assert(!evhttp_connection_set_flags(evcon, EVHTTP_CON_READ_ON_WRITE_ERROR));
4068*a466cc55SCy Schubert 
40692b15cb3dSCy Schubert 	evhttp_connection_set_local_address(evcon, "127.0.0.1");
40702b15cb3dSCy Schubert 
4071*a466cc55SCy Schubert 	evhttp_set_max_headers_size(http, size - 1);
4072*a466cc55SCy Schubert 	TT_BLATHER(("Set max header size %zu", size - 1));
40732b15cb3dSCy Schubert 
40742b15cb3dSCy Schubert 	req = evhttp_request_new(http_data_length_constraints_test_done, data->base);
40752b15cb3dSCy Schubert 	tt_assert(req);
40762b15cb3dSCy Schubert 	evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
40772b15cb3dSCy Schubert 	evhttp_add_header(evhttp_request_get_output_headers(req), "Longheader", long_str);
4078*a466cc55SCy Schubert 	TT_BLATHER(("GET /?arg=val"));
40792b15cb3dSCy Schubert 	if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/?arg=val") == -1) {
40802b15cb3dSCy Schubert 		tt_abort_msg("Couldn't make request");
40812b15cb3dSCy Schubert 	}
40822b15cb3dSCy Schubert 	event_base_dispatch(data->base);
40832b15cb3dSCy Schubert 
40842b15cb3dSCy Schubert 	req = evhttp_request_new(http_data_length_constraints_test_done, data->base);
40852b15cb3dSCy Schubert 	tt_assert(req);
40862b15cb3dSCy Schubert 	evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
40872b15cb3dSCy Schubert 	/* GET /?arg=verylongvalue HTTP/1.1 */
4088*a466cc55SCy Schubert 	TT_BLATHER(("GET %s", long_str));
40892b15cb3dSCy Schubert 	if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, long_str) == -1) {
40902b15cb3dSCy Schubert 		tt_abort_msg("Couldn't make request");
40912b15cb3dSCy Schubert 	}
40922b15cb3dSCy Schubert 	event_base_dispatch(data->base);
40932b15cb3dSCy Schubert 
4094*a466cc55SCy Schubert 	evhttp_set_max_body_size(http, size - 2);
4095*a466cc55SCy Schubert 	TT_BLATHER(("Set body header size %zu", size - 2));
4096*a466cc55SCy Schubert 
4097*a466cc55SCy Schubert 	if (read_on_write_error)
4098*a466cc55SCy Schubert 		cb = http_large_entity_test_done;
4099*a466cc55SCy Schubert 	req = evhttp_request_new(cb, data->base);
41002b15cb3dSCy Schubert 	evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
41012b15cb3dSCy Schubert 	evbuffer_add_printf(evhttp_request_get_output_buffer(req), "%s", long_str);
4102*a466cc55SCy Schubert 	TT_BLATHER(("POST /"));
41032b15cb3dSCy Schubert 	if (evhttp_make_request(evcon, req, EVHTTP_REQ_POST, "/") == -1) {
41042b15cb3dSCy Schubert 		tt_abort_msg("Couldn't make request");
41052b15cb3dSCy Schubert 	}
41062b15cb3dSCy Schubert 	event_base_dispatch(data->base);
41072b15cb3dSCy Schubert 
41082b15cb3dSCy Schubert 	req = evhttp_request_new(http_large_entity_test_done, data->base);
41092b15cb3dSCy Schubert 	evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
41102b15cb3dSCy Schubert 	evhttp_add_header(evhttp_request_get_output_headers(req), "Expect", "100-continue");
41112b15cb3dSCy Schubert 	evbuffer_add_printf(evhttp_request_get_output_buffer(req), "%s", long_str);
4112*a466cc55SCy Schubert 	TT_BLATHER(("POST / (Expect: 100-continue, http_large_entity_test_done)"));
4113*a466cc55SCy Schubert 	if (evhttp_make_request(evcon, req, EVHTTP_REQ_POST, "/") == -1) {
4114*a466cc55SCy Schubert 		tt_abort_msg("Couldn't make request");
4115*a466cc55SCy Schubert 	}
4116*a466cc55SCy Schubert 	event_base_dispatch(data->base);
4117*a466cc55SCy Schubert 
4118*a466cc55SCy Schubert 	long_str[continue_size] = '\0';
4119*a466cc55SCy Schubert 
4120*a466cc55SCy Schubert 	req = evhttp_request_new(http_dispatcher_test_done, data->base);
4121*a466cc55SCy Schubert 	evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
4122*a466cc55SCy Schubert 	evhttp_add_header(evhttp_request_get_output_headers(req), "Expect", "100-continue");
4123*a466cc55SCy Schubert 	evbuffer_add_printf(evhttp_request_get_output_buffer(req), "%s", long_str);
4124*a466cc55SCy Schubert 	TT_BLATHER(("POST / (Expect: 100-continue, http_dispatcher_test_done)"));
4125*a466cc55SCy Schubert 	if (evhttp_make_request(evcon, req, EVHTTP_REQ_POST, "/") == -1) {
4126*a466cc55SCy Schubert 		tt_abort_msg("Couldn't make request");
4127*a466cc55SCy Schubert 	}
4128*a466cc55SCy Schubert 	event_base_dispatch(data->base);
4129*a466cc55SCy Schubert 
4130*a466cc55SCy Schubert 	if (read_on_write_error)
4131*a466cc55SCy Schubert 		cb = http_expectation_failed_done;
4132*a466cc55SCy Schubert 	req = evhttp_request_new(cb, data->base);
4133*a466cc55SCy Schubert 	evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
4134*a466cc55SCy Schubert 	evhttp_add_header(evhttp_request_get_output_headers(req), "Expect", "101-continue");
4135*a466cc55SCy Schubert 	evbuffer_add_printf(evhttp_request_get_output_buffer(req), "%s", long_str);
4136*a466cc55SCy Schubert 	TT_BLATHER(("POST / (Expect: 101-continue)"));
4137*a466cc55SCy Schubert 	if (evhttp_make_request(evcon, req, EVHTTP_REQ_POST, "/") == -1) {
4138*a466cc55SCy Schubert 		tt_abort_msg("Couldn't make request");
4139*a466cc55SCy Schubert 	}
4140*a466cc55SCy Schubert 	event_base_dispatch(data->base);
4141*a466cc55SCy Schubert 
4142*a466cc55SCy Schubert 	test_ok = 1;
4143*a466cc55SCy Schubert  end:
4144*a466cc55SCy Schubert 	if (evcon)
4145*a466cc55SCy Schubert 		evhttp_connection_free(evcon);
4146*a466cc55SCy Schubert 	if (http)
4147*a466cc55SCy Schubert 		evhttp_free(http);
4148*a466cc55SCy Schubert 	if (long_str)
4149*a466cc55SCy Schubert 		free(long_str);
4150*a466cc55SCy Schubert }
http_data_length_constraints_test(void * arg)4151*a466cc55SCy Schubert static void http_data_length_constraints_test(void *arg)
4152*a466cc55SCy Schubert { http_data_length_constraints_test_impl(arg, 0); }
http_read_on_write_error_test(void * arg)4153*a466cc55SCy Schubert static void http_read_on_write_error_test(void *arg)
4154*a466cc55SCy Schubert { http_data_length_constraints_test_impl(arg, 1); }
4155*a466cc55SCy Schubert 
4156*a466cc55SCy Schubert static void
http_lingering_close_test_impl(void * arg,int lingering)4157*a466cc55SCy Schubert http_lingering_close_test_impl(void *arg, int lingering)
4158*a466cc55SCy Schubert {
4159*a466cc55SCy Schubert 	struct basic_test_data *data = arg;
4160*a466cc55SCy Schubert 	ev_uint16_t port = 0;
4161*a466cc55SCy Schubert 	struct evhttp_connection *evcon = NULL;
4162*a466cc55SCy Schubert 	struct evhttp_request *req = NULL;
4163*a466cc55SCy Schubert 	char *long_str = NULL;
4164*a466cc55SCy Schubert 	size_t size = (1<<20) * 3;
4165*a466cc55SCy Schubert 	void (*cb)(struct evhttp_request *, void *);
4166*a466cc55SCy Schubert 	struct evhttp *http = http_setup(&port, data->base, 0);
4167*a466cc55SCy Schubert 
4168*a466cc55SCy Schubert 	test_ok = 0;
4169*a466cc55SCy Schubert 
4170*a466cc55SCy Schubert 	if (lingering)
4171*a466cc55SCy Schubert 		tt_assert(!evhttp_set_flags(http, EVHTTP_SERVER_LINGERING_CLOSE));
4172*a466cc55SCy Schubert 	evhttp_set_max_body_size(http, size / 2);
4173*a466cc55SCy Schubert 
4174*a466cc55SCy Schubert 	evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port);
4175*a466cc55SCy Schubert 	tt_assert(evcon);
4176*a466cc55SCy Schubert 	evhttp_connection_set_local_address(evcon, "127.0.0.1");
4177*a466cc55SCy Schubert 
4178*a466cc55SCy Schubert 	/*
4179*a466cc55SCy Schubert 	 * At this point, we want to schedule an HTTP GET request
4180*a466cc55SCy Schubert 	 * server using our make request method.
4181*a466cc55SCy Schubert 	 */
4182*a466cc55SCy Schubert 
4183*a466cc55SCy Schubert 	long_str = malloc(size);
4184*a466cc55SCy Schubert 	memset(long_str, 'a', size);
4185*a466cc55SCy Schubert 	long_str[size - 1] = '\0';
4186*a466cc55SCy Schubert 
4187*a466cc55SCy Schubert 	if (lingering)
4188*a466cc55SCy Schubert 		cb = http_large_entity_test_done;
4189*a466cc55SCy Schubert 	else
4190*a466cc55SCy Schubert 		cb = http_failed_request_done;
4191*a466cc55SCy Schubert 	req = evhttp_request_new(cb, data->base);
4192*a466cc55SCy Schubert 	tt_assert(req);
4193*a466cc55SCy Schubert 	evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
4194*a466cc55SCy Schubert 	evbuffer_add_printf(evhttp_request_get_output_buffer(req), "%s", long_str);
41952b15cb3dSCy Schubert 	if (evhttp_make_request(evcon, req, EVHTTP_REQ_POST, "/") == -1) {
41962b15cb3dSCy Schubert 		tt_abort_msg("Couldn't make request");
41972b15cb3dSCy Schubert 	}
41982b15cb3dSCy Schubert 	event_base_dispatch(data->base);
41992b15cb3dSCy Schubert 
42002b15cb3dSCy Schubert 	test_ok = 1;
42012b15cb3dSCy Schubert  end:
42022b15cb3dSCy Schubert 	if (evcon)
42032b15cb3dSCy Schubert 		evhttp_connection_free(evcon);
42042b15cb3dSCy Schubert 	if (http)
42052b15cb3dSCy Schubert 		evhttp_free(http);
4206*a466cc55SCy Schubert 	if (long_str)
4207*a466cc55SCy Schubert 		free(long_str);
42082b15cb3dSCy Schubert }
http_non_lingering_close_test(void * arg)4209*a466cc55SCy Schubert static void http_non_lingering_close_test(void *arg)
4210*a466cc55SCy Schubert { http_lingering_close_test_impl(arg, 0); }
http_lingering_close_test(void * arg)4211*a466cc55SCy Schubert static void http_lingering_close_test(void *arg)
4212*a466cc55SCy Schubert { http_lingering_close_test_impl(arg, 1); }
42132b15cb3dSCy Schubert 
42142b15cb3dSCy Schubert /*
42152b15cb3dSCy Schubert  * Testing client reset of server chunked connections
42162b15cb3dSCy Schubert  */
42172b15cb3dSCy Schubert 
42182b15cb3dSCy Schubert struct terminate_state {
42192b15cb3dSCy Schubert 	struct event_base *base;
42202b15cb3dSCy Schubert 	struct evhttp_request *req;
42212b15cb3dSCy Schubert 	struct bufferevent *bev;
42222b15cb3dSCy Schubert 	evutil_socket_t fd;
42232b15cb3dSCy Schubert 	int gotclosecb: 1;
4224*a466cc55SCy Schubert 	int oneshot: 1;
42252b15cb3dSCy Schubert };
42262b15cb3dSCy Schubert 
42272b15cb3dSCy Schubert static void
terminate_chunked_trickle_cb(evutil_socket_t fd,short events,void * arg)42282b15cb3dSCy Schubert terminate_chunked_trickle_cb(evutil_socket_t fd, short events, void *arg)
42292b15cb3dSCy Schubert {
42302b15cb3dSCy Schubert 	struct terminate_state *state = arg;
42312b15cb3dSCy Schubert 	struct evbuffer *evb;
4232*a466cc55SCy Schubert 
4233*a466cc55SCy Schubert 	if (!state->req) {
4234*a466cc55SCy Schubert 		return;
4235*a466cc55SCy Schubert 	}
42362b15cb3dSCy Schubert 
42372b15cb3dSCy Schubert 	if (evhttp_request_get_connection(state->req) == NULL) {
42382b15cb3dSCy Schubert 		test_ok = 1;
42392b15cb3dSCy Schubert 		evhttp_request_free(state->req);
42402b15cb3dSCy Schubert 		event_base_loopexit(state->base,NULL);
42412b15cb3dSCy Schubert 		return;
42422b15cb3dSCy Schubert 	}
42432b15cb3dSCy Schubert 
42442b15cb3dSCy Schubert 	evb = evbuffer_new();
42452b15cb3dSCy Schubert 	evbuffer_add_printf(evb, "%p", evb);
42462b15cb3dSCy Schubert 	evhttp_send_reply_chunk(state->req, evb);
42472b15cb3dSCy Schubert 	evbuffer_free(evb);
42482b15cb3dSCy Schubert 
4249*a466cc55SCy Schubert 	if (!state->oneshot) {
4250*a466cc55SCy Schubert 		struct timeval tv;
42512b15cb3dSCy Schubert 		tv.tv_sec = 0;
42522b15cb3dSCy Schubert 		tv.tv_usec = 3000;
42532b15cb3dSCy Schubert 		EVUTIL_ASSERT(state);
42542b15cb3dSCy Schubert 		EVUTIL_ASSERT(state->base);
42552b15cb3dSCy Schubert 		event_base_once(state->base, -1, EV_TIMEOUT, terminate_chunked_trickle_cb, arg, &tv);
42562b15cb3dSCy Schubert 	}
4257*a466cc55SCy Schubert }
42582b15cb3dSCy Schubert 
42592b15cb3dSCy Schubert static void
terminate_chunked_close_cb(struct evhttp_connection * evcon,void * arg)42602b15cb3dSCy Schubert terminate_chunked_close_cb(struct evhttp_connection *evcon, void *arg)
42612b15cb3dSCy Schubert {
42622b15cb3dSCy Schubert 	struct terminate_state *state = arg;
42632b15cb3dSCy Schubert 	state->gotclosecb = 1;
4264*a466cc55SCy Schubert 
4265*a466cc55SCy Schubert 	/** TODO: though we can do this unconditionally */
4266*a466cc55SCy Schubert 	if (state->oneshot) {
4267*a466cc55SCy Schubert 		evhttp_request_free(state->req);
4268*a466cc55SCy Schubert 		state->req = NULL;
4269*a466cc55SCy Schubert 		event_base_loopexit(state->base,NULL);
4270*a466cc55SCy Schubert 	}
42712b15cb3dSCy Schubert }
42722b15cb3dSCy Schubert 
42732b15cb3dSCy Schubert static void
terminate_chunked_cb(struct evhttp_request * req,void * arg)42742b15cb3dSCy Schubert terminate_chunked_cb(struct evhttp_request *req, void *arg)
42752b15cb3dSCy Schubert {
42762b15cb3dSCy Schubert 	struct terminate_state *state = arg;
42772b15cb3dSCy Schubert 	struct timeval tv;
42782b15cb3dSCy Schubert 
42792b15cb3dSCy Schubert 	/* we want to know if this connection closes on us */
42802b15cb3dSCy Schubert 	evhttp_connection_set_closecb(
42812b15cb3dSCy Schubert 		evhttp_request_get_connection(req),
42822b15cb3dSCy Schubert 		terminate_chunked_close_cb, arg);
42832b15cb3dSCy Schubert 
42842b15cb3dSCy Schubert 	state->req = req;
42852b15cb3dSCy Schubert 
42862b15cb3dSCy Schubert 	evhttp_send_reply_start(req, HTTP_OK, "OK");
42872b15cb3dSCy Schubert 
42882b15cb3dSCy Schubert 	tv.tv_sec = 0;
42892b15cb3dSCy Schubert 	tv.tv_usec = 3000;
42902b15cb3dSCy Schubert 	event_base_once(state->base, -1, EV_TIMEOUT, terminate_chunked_trickle_cb, arg, &tv);
42912b15cb3dSCy Schubert }
42922b15cb3dSCy Schubert 
42932b15cb3dSCy Schubert static void
terminate_chunked_client(evutil_socket_t fd,short event,void * arg)42942b15cb3dSCy Schubert terminate_chunked_client(evutil_socket_t fd, short event, void *arg)
42952b15cb3dSCy Schubert {
42962b15cb3dSCy Schubert 	struct terminate_state *state = arg;
42972b15cb3dSCy Schubert 	bufferevent_free(state->bev);
42982b15cb3dSCy Schubert 	evutil_closesocket(state->fd);
42992b15cb3dSCy Schubert }
43002b15cb3dSCy Schubert 
43012b15cb3dSCy Schubert static void
terminate_readcb(struct bufferevent * bev,void * arg)43022b15cb3dSCy Schubert terminate_readcb(struct bufferevent *bev, void *arg)
43032b15cb3dSCy Schubert {
43042b15cb3dSCy Schubert 	/* just drop the data */
43052b15cb3dSCy Schubert 	evbuffer_drain(bufferevent_get_input(bev), -1);
43062b15cb3dSCy Schubert }
43072b15cb3dSCy Schubert 
43082b15cb3dSCy Schubert 
43092b15cb3dSCy Schubert static void
http_terminate_chunked_test_impl(void * arg,int oneshot)4310*a466cc55SCy Schubert http_terminate_chunked_test_impl(void *arg, int oneshot)
43112b15cb3dSCy Schubert {
43122b15cb3dSCy Schubert 	struct basic_test_data *data = arg;
43132b15cb3dSCy Schubert 	struct bufferevent *bev = NULL;
43142b15cb3dSCy Schubert 	struct timeval tv;
43152b15cb3dSCy Schubert 	const char *http_request;
43162b15cb3dSCy Schubert 	ev_uint16_t port = 0;
4317*a466cc55SCy Schubert 	evutil_socket_t fd = EVUTIL_INVALID_SOCKET;
43182b15cb3dSCy Schubert 	struct terminate_state terminate_state;
4319*a466cc55SCy Schubert 	struct evhttp *http = http_setup(&port, data->base, 0);
43202b15cb3dSCy Schubert 
43212b15cb3dSCy Schubert 	test_ok = 0;
43222b15cb3dSCy Schubert 
43232b15cb3dSCy Schubert 	evhttp_del_cb(http, "/test");
43242b15cb3dSCy Schubert 	tt_assert(evhttp_set_cb(http, "/test",
43252b15cb3dSCy Schubert 		terminate_chunked_cb, &terminate_state) == 0);
43262b15cb3dSCy Schubert 
43272b15cb3dSCy Schubert 	fd = http_connect("127.0.0.1", port);
4328*a466cc55SCy Schubert 	tt_assert(fd != EVUTIL_INVALID_SOCKET);
43292b15cb3dSCy Schubert 
43302b15cb3dSCy Schubert 	/* Stupid thing to send a request */
43312b15cb3dSCy Schubert 	bev = bufferevent_socket_new(data->base, fd, 0);
43322b15cb3dSCy Schubert 	bufferevent_setcb(bev, terminate_readcb, http_writecb,
43332b15cb3dSCy Schubert 	    http_errorcb, data->base);
43342b15cb3dSCy Schubert 
43352b15cb3dSCy Schubert 	memset(&terminate_state, 0, sizeof(terminate_state));
43362b15cb3dSCy Schubert 	terminate_state.base = data->base;
43372b15cb3dSCy Schubert 	terminate_state.fd = fd;
43382b15cb3dSCy Schubert 	terminate_state.bev = bev;
43392b15cb3dSCy Schubert 	terminate_state.gotclosecb = 0;
4340*a466cc55SCy Schubert 	terminate_state.oneshot = oneshot;
43412b15cb3dSCy Schubert 
43422b15cb3dSCy Schubert 	/* first half of the http request */
43432b15cb3dSCy Schubert 	http_request =
43442b15cb3dSCy Schubert 	    "GET /test HTTP/1.1\r\n"
43452b15cb3dSCy Schubert 	    "Host: some\r\n\r\n";
43462b15cb3dSCy Schubert 
43472b15cb3dSCy Schubert 	bufferevent_write(bev, http_request, strlen(http_request));
43482b15cb3dSCy Schubert 	evutil_timerclear(&tv);
43492b15cb3dSCy Schubert 	tv.tv_usec = 10000;
43502b15cb3dSCy Schubert 	event_base_once(data->base, -1, EV_TIMEOUT, terminate_chunked_client, &terminate_state,
43512b15cb3dSCy Schubert 	    &tv);
43522b15cb3dSCy Schubert 
43532b15cb3dSCy Schubert 	event_base_dispatch(data->base);
43542b15cb3dSCy Schubert 
43552b15cb3dSCy Schubert 	if (terminate_state.gotclosecb == 0)
43562b15cb3dSCy Schubert 		test_ok = 0;
43572b15cb3dSCy Schubert 
43582b15cb3dSCy Schubert  end:
43592b15cb3dSCy Schubert 	if (fd >= 0)
43602b15cb3dSCy Schubert 		evutil_closesocket(fd);
43612b15cb3dSCy Schubert 	if (http)
43622b15cb3dSCy Schubert 		evhttp_free(http);
43632b15cb3dSCy Schubert }
4364*a466cc55SCy Schubert static void
http_terminate_chunked_test(void * arg)4365*a466cc55SCy Schubert http_terminate_chunked_test(void *arg)
4366*a466cc55SCy Schubert {
4367*a466cc55SCy Schubert 	http_terminate_chunked_test_impl(arg, 0);
4368*a466cc55SCy Schubert }
4369*a466cc55SCy Schubert static void
http_terminate_chunked_oneshot_test(void * arg)4370*a466cc55SCy Schubert http_terminate_chunked_oneshot_test(void *arg)
4371*a466cc55SCy Schubert {
4372*a466cc55SCy Schubert 	http_terminate_chunked_test_impl(arg, 1);
4373*a466cc55SCy Schubert }
43742b15cb3dSCy Schubert 
43752b15cb3dSCy Schubert static struct regress_dns_server_table ipv6_search_table[] = {
4376*a466cc55SCy Schubert 	{ "localhost", "AAAA", "::1", 0, 0 },
4377*a466cc55SCy Schubert 	{ NULL, NULL, NULL, 0, 0 }
43782b15cb3dSCy Schubert };
43792b15cb3dSCy Schubert 
43802b15cb3dSCy Schubert static void
http_ipv6_for_domain_test_impl(void * arg,int family)4381a25439b6SCy Schubert http_ipv6_for_domain_test_impl(void *arg, int family)
43822b15cb3dSCy Schubert {
43832b15cb3dSCy Schubert 	struct basic_test_data *data = arg;
43842b15cb3dSCy Schubert 	struct evdns_base *dns_base = NULL;
43852b15cb3dSCy Schubert 	ev_uint16_t portnum = 0;
43862b15cb3dSCy Schubert 	char address[64];
43872b15cb3dSCy Schubert 
43882b15cb3dSCy Schubert 	tt_assert(regress_dnsserver(data->base, &portnum, ipv6_search_table));
43892b15cb3dSCy Schubert 
43902b15cb3dSCy Schubert 	dns_base = evdns_base_new(data->base, 0/* init name servers */);
43912b15cb3dSCy Schubert 	tt_assert(dns_base);
43922b15cb3dSCy Schubert 
43932b15cb3dSCy Schubert 	/* Add ourself as the only nameserver, and make sure we really are
43942b15cb3dSCy Schubert 	 * the only nameserver. */
43952b15cb3dSCy Schubert 	evutil_snprintf(address, sizeof(address), "127.0.0.1:%d", portnum);
43962b15cb3dSCy Schubert 	evdns_base_nameserver_ip_add(dns_base, address);
43972b15cb3dSCy Schubert 
4398a25439b6SCy Schubert 	http_connection_test_(arg, 0 /* not persistent */, "localhost", dns_base,
4399*a466cc55SCy Schubert 		1 /* ipv6 */, family, 0);
44002b15cb3dSCy Schubert 
44012b15cb3dSCy Schubert  end:
44022b15cb3dSCy Schubert 	if (dns_base)
44032b15cb3dSCy Schubert 		evdns_base_free(dns_base, 0);
44042b15cb3dSCy Schubert 	regress_clean_dnsserver();
44052b15cb3dSCy Schubert }
4406a25439b6SCy Schubert static void
http_ipv6_for_domain_test(void * arg)4407a25439b6SCy Schubert http_ipv6_for_domain_test(void *arg)
4408a25439b6SCy Schubert {
4409a25439b6SCy Schubert 	http_ipv6_for_domain_test_impl(arg, AF_UNSPEC);
4410a25439b6SCy Schubert }
44112b15cb3dSCy Schubert 
44122b15cb3dSCy Schubert static void
http_request_get_addr_on_close(struct evhttp_connection * evcon,void * arg)44132b15cb3dSCy Schubert http_request_get_addr_on_close(struct evhttp_connection *evcon, void *arg)
44142b15cb3dSCy Schubert {
44152b15cb3dSCy Schubert 	const struct sockaddr *storage;
44162b15cb3dSCy Schubert 	char addrbuf[128];
44172b15cb3dSCy Schubert 	char local[] = "127.0.0.1:";
44182b15cb3dSCy Schubert 
44192b15cb3dSCy Schubert 	test_ok = 0;
44202b15cb3dSCy Schubert 	tt_assert(evcon);
44212b15cb3dSCy Schubert 
44222b15cb3dSCy Schubert 	storage = evhttp_connection_get_addr(evcon);
44232b15cb3dSCy Schubert 	tt_assert(storage);
44242b15cb3dSCy Schubert 
44252b15cb3dSCy Schubert 	evutil_format_sockaddr_port_((struct sockaddr *)storage, addrbuf, sizeof(addrbuf));
44262b15cb3dSCy Schubert 	tt_assert(!strncmp(addrbuf, local, sizeof(local) - 1));
44272b15cb3dSCy Schubert 
44282b15cb3dSCy Schubert 	test_ok = 1;
44292b15cb3dSCy Schubert 	return;
44302b15cb3dSCy Schubert 
44312b15cb3dSCy Schubert end:
44322b15cb3dSCy Schubert 	test_ok = 0;
44332b15cb3dSCy Schubert }
44342b15cb3dSCy Schubert 
44352b15cb3dSCy Schubert static void
http_get_addr_test(void * arg)44362b15cb3dSCy Schubert http_get_addr_test(void *arg)
44372b15cb3dSCy Schubert {
44382b15cb3dSCy Schubert 	struct basic_test_data *data = arg;
44392b15cb3dSCy Schubert 	ev_uint16_t port = 0;
44402b15cb3dSCy Schubert 	struct evhttp_connection *evcon = NULL;
44412b15cb3dSCy Schubert 	struct evhttp_request *req = NULL;
4442*a466cc55SCy Schubert 	struct evhttp *http = http_setup(&port, data->base, 0);
44432b15cb3dSCy Schubert 
44442b15cb3dSCy Schubert 	test_ok = 0;
44452b15cb3dSCy Schubert 	exit_base = data->base;
44462b15cb3dSCy Schubert 
44472b15cb3dSCy Schubert 	evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port);
44482b15cb3dSCy Schubert 	tt_assert(evcon);
44492b15cb3dSCy Schubert 	evhttp_connection_set_closecb(evcon, http_request_get_addr_on_close, arg);
44502b15cb3dSCy Schubert 
44512b15cb3dSCy Schubert 	/*
44522b15cb3dSCy Schubert 	 * At this point, we want to schedule a request to the HTTP
44532b15cb3dSCy Schubert 	 * server using our make request method.
44542b15cb3dSCy Schubert 	 */
44552b15cb3dSCy Schubert 
44562b15cb3dSCy Schubert 	req = evhttp_request_new(http_request_done, (void *)BASIC_REQUEST_BODY);
44572b15cb3dSCy Schubert 
44582b15cb3dSCy Schubert 	/* We give ownership of the request to the connection */
44592b15cb3dSCy Schubert 	if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test") == -1) {
44602b15cb3dSCy Schubert 		tt_abort_msg("Couldn't make request");
44612b15cb3dSCy Schubert 	}
44622b15cb3dSCy Schubert 
44632b15cb3dSCy Schubert 	event_base_dispatch(data->base);
44642b15cb3dSCy Schubert 
44652b15cb3dSCy Schubert 	http_request_get_addr_on_close(evcon, NULL);
44662b15cb3dSCy Schubert 
44672b15cb3dSCy Schubert  end:
44682b15cb3dSCy Schubert 	if (evcon)
44692b15cb3dSCy Schubert 		evhttp_connection_free(evcon);
44702b15cb3dSCy Schubert 	if (http)
44712b15cb3dSCy Schubert 		evhttp_free(http);
44722b15cb3dSCy Schubert }
44732b15cb3dSCy Schubert 
4474a25439b6SCy Schubert static void
http_set_family_test(void * arg)4475a25439b6SCy Schubert http_set_family_test(void *arg)
4476a25439b6SCy Schubert {
4477*a466cc55SCy Schubert 	http_connection_test_(arg, 0, "127.0.0.1", NULL, 0, AF_UNSPEC, 0);
4478a25439b6SCy Schubert }
4479a25439b6SCy Schubert static void
http_set_family_ipv4_test(void * arg)4480a25439b6SCy Schubert http_set_family_ipv4_test(void *arg)
4481a25439b6SCy Schubert {
4482*a466cc55SCy Schubert 	http_connection_test_(arg, 0, "127.0.0.1", NULL, 0, AF_INET, 0);
4483a25439b6SCy Schubert }
4484a25439b6SCy Schubert static void
http_set_family_ipv6_test(void * arg)4485a25439b6SCy Schubert http_set_family_ipv6_test(void *arg)
4486a25439b6SCy Schubert {
4487a25439b6SCy Schubert 	http_ipv6_for_domain_test_impl(arg, AF_INET6);
4488a25439b6SCy Schubert }
4489a25439b6SCy Schubert 
4490*a466cc55SCy Schubert static void
http_write_during_read(evutil_socket_t fd,short what,void * arg)4491*a466cc55SCy Schubert http_write_during_read(evutil_socket_t fd, short what, void *arg)
4492*a466cc55SCy Schubert {
4493*a466cc55SCy Schubert 	struct bufferevent *bev = arg;
4494*a466cc55SCy Schubert 	struct timeval tv;
4495*a466cc55SCy Schubert 
4496*a466cc55SCy Schubert 	bufferevent_write(bev, "foobar", strlen("foobar"));
4497*a466cc55SCy Schubert 
4498*a466cc55SCy Schubert 	evutil_timerclear(&tv);
4499*a466cc55SCy Schubert 	tv.tv_sec = 1;
4500*a466cc55SCy Schubert 	event_base_loopexit(exit_base, &tv);
4501*a466cc55SCy Schubert }
4502*a466cc55SCy Schubert static void
http_write_during_read_test_impl(void * arg,int ssl)4503*a466cc55SCy Schubert http_write_during_read_test_impl(void *arg, int ssl)
4504*a466cc55SCy Schubert {
4505*a466cc55SCy Schubert 	struct basic_test_data *data = arg;
4506*a466cc55SCy Schubert 	ev_uint16_t port = 0;
4507*a466cc55SCy Schubert 	struct bufferevent *bev = NULL;
4508*a466cc55SCy Schubert 	struct timeval tv;
4509*a466cc55SCy Schubert 	evutil_socket_t fd;
4510*a466cc55SCy Schubert 	const char *http_request;
4511*a466cc55SCy Schubert 	struct evhttp *http = http_setup(&port, data->base, ssl ? HTTP_BIND_SSL : 0);
4512*a466cc55SCy Schubert 
4513*a466cc55SCy Schubert 	test_ok = 0;
4514*a466cc55SCy Schubert 	exit_base = data->base;
4515*a466cc55SCy Schubert 
4516*a466cc55SCy Schubert 	fd = http_connect("127.0.0.1", port);
4517*a466cc55SCy Schubert 	tt_assert(fd != EVUTIL_INVALID_SOCKET);
4518*a466cc55SCy Schubert 	bev = create_bev(data->base, fd, 0, 0);
4519*a466cc55SCy Schubert 	bufferevent_setcb(bev, NULL, NULL, NULL, data->base);
4520*a466cc55SCy Schubert 	bufferevent_disable(bev, EV_READ);
4521*a466cc55SCy Schubert 
4522*a466cc55SCy Schubert 	http_request =
4523*a466cc55SCy Schubert 	    "GET /large HTTP/1.1\r\n"
4524*a466cc55SCy Schubert 	    "Host: somehost\r\n"
4525*a466cc55SCy Schubert 	    "\r\n";
4526*a466cc55SCy Schubert 
4527*a466cc55SCy Schubert 	bufferevent_write(bev, http_request, strlen(http_request));
4528*a466cc55SCy Schubert 	evutil_timerclear(&tv);
4529*a466cc55SCy Schubert 	tv.tv_usec = 10000;
4530*a466cc55SCy Schubert 	event_base_once(data->base, -1, EV_TIMEOUT, http_write_during_read, bev, &tv);
4531*a466cc55SCy Schubert 
4532*a466cc55SCy Schubert 	event_base_dispatch(data->base);
4533*a466cc55SCy Schubert 
4534*a466cc55SCy Schubert end:
4535*a466cc55SCy Schubert 	if (bev)
4536*a466cc55SCy Schubert 		bufferevent_free(bev);
4537*a466cc55SCy Schubert 	if (http)
4538*a466cc55SCy Schubert 		evhttp_free(http);
4539*a466cc55SCy Schubert }
http_write_during_read_test(void * arg)4540*a466cc55SCy Schubert static void http_write_during_read_test(void *arg)
4541*a466cc55SCy Schubert { http_write_during_read_test_impl(arg, 0); }
4542*a466cc55SCy Schubert 
4543*a466cc55SCy Schubert static void
http_request_own_test(void * arg)4544*a466cc55SCy Schubert http_request_own_test(void *arg)
4545*a466cc55SCy Schubert {
4546*a466cc55SCy Schubert 	struct basic_test_data *data = arg;
4547*a466cc55SCy Schubert 	ev_uint16_t port = 0;
4548*a466cc55SCy Schubert 	struct evhttp_connection *evcon = NULL;
4549*a466cc55SCy Schubert 	struct evhttp_request *req = NULL;
4550*a466cc55SCy Schubert 	struct evhttp *http = http_setup(&port, data->base, 0);
4551*a466cc55SCy Schubert 
4552*a466cc55SCy Schubert 	test_ok = 0;
4553*a466cc55SCy Schubert 	exit_base = data->base;
4554*a466cc55SCy Schubert 
4555*a466cc55SCy Schubert 	evhttp_free(http);
4556*a466cc55SCy Schubert 
4557*a466cc55SCy Schubert 	evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port);
4558*a466cc55SCy Schubert 	tt_assert(evcon);
4559*a466cc55SCy Schubert 
4560*a466cc55SCy Schubert 	req = evhttp_request_new(http_request_no_action_done, NULL);
4561*a466cc55SCy Schubert 
4562*a466cc55SCy Schubert 	if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test") == -1) {
4563*a466cc55SCy Schubert 		tt_abort_msg("Couldn't make request");
4564*a466cc55SCy Schubert 	}
4565*a466cc55SCy Schubert 	evhttp_request_own(req);
4566*a466cc55SCy Schubert 
4567*a466cc55SCy Schubert 	event_base_dispatch(data->base);
4568*a466cc55SCy Schubert 
4569*a466cc55SCy Schubert  end:
4570*a466cc55SCy Schubert 	if (evcon)
4571*a466cc55SCy Schubert 		evhttp_connection_free(evcon);
4572*a466cc55SCy Schubert 	if (req)
4573*a466cc55SCy Schubert 		evhttp_request_free(req);
4574*a466cc55SCy Schubert 
4575*a466cc55SCy Schubert 	test_ok = 1;
4576*a466cc55SCy Schubert }
4577*a466cc55SCy Schubert 
http_run_bev_request(struct event_base * base,int port,const char * fmt,...)4578*a466cc55SCy Schubert static void http_run_bev_request(struct event_base *base, int port,
4579*a466cc55SCy Schubert 	const char *fmt, ...)
4580*a466cc55SCy Schubert {
4581*a466cc55SCy Schubert 	struct bufferevent *bev = NULL;
4582*a466cc55SCy Schubert 	va_list ap;
4583*a466cc55SCy Schubert 	evutil_socket_t fd;
4584*a466cc55SCy Schubert 	struct evbuffer *out;
4585*a466cc55SCy Schubert 
4586*a466cc55SCy Schubert 	fd = http_connect("127.0.0.1", port);
4587*a466cc55SCy Schubert 	tt_assert(fd != EVUTIL_INVALID_SOCKET);
4588*a466cc55SCy Schubert 
4589*a466cc55SCy Schubert 	/* Stupid thing to send a request */
4590*a466cc55SCy Schubert 	bev = create_bev(base, fd, 0, 0);
4591*a466cc55SCy Schubert 	bufferevent_setcb(bev, http_readcb, http_writecb,
4592*a466cc55SCy Schubert 	    http_errorcb, base);
4593*a466cc55SCy Schubert 	out = bufferevent_get_output(bev);
4594*a466cc55SCy Schubert 
4595*a466cc55SCy Schubert 	va_start(ap, fmt);
4596*a466cc55SCy Schubert 	evbuffer_add_vprintf(out, fmt, ap);
4597*a466cc55SCy Schubert 	va_end(ap);
4598*a466cc55SCy Schubert 
4599*a466cc55SCy Schubert 	event_base_dispatch(base);
4600*a466cc55SCy Schubert 
4601*a466cc55SCy Schubert end:
4602*a466cc55SCy Schubert 	if (bev)
4603*a466cc55SCy Schubert 		bufferevent_free(bev);
4604*a466cc55SCy Schubert }
4605*a466cc55SCy Schubert static void
http_request_extra_body_test(void * arg)4606*a466cc55SCy Schubert http_request_extra_body_test(void *arg)
4607*a466cc55SCy Schubert {
4608*a466cc55SCy Schubert 	struct basic_test_data *data = arg;
4609*a466cc55SCy Schubert 	struct bufferevent *bev = NULL;
4610*a466cc55SCy Schubert 	ev_uint16_t port = 0;
4611*a466cc55SCy Schubert 	int i;
4612*a466cc55SCy Schubert 	struct evhttp *http =
4613*a466cc55SCy Schubert 		http_setup_gencb(&port, data->base, 0, http_timeout_cb, NULL);
4614*a466cc55SCy Schubert 	struct evbuffer *body = NULL;
4615*a466cc55SCy Schubert 
4616*a466cc55SCy Schubert 	exit_base = data->base;
4617*a466cc55SCy Schubert 	test_ok = 0;
4618*a466cc55SCy Schubert 
4619*a466cc55SCy Schubert 	body = evbuffer_new();
4620*a466cc55SCy Schubert 	for (i = 0; i < 10000; ++i)
4621*a466cc55SCy Schubert 		evbuffer_add_printf(body, "this is the body that HEAD should not have");
4622*a466cc55SCy Schubert 
4623*a466cc55SCy Schubert 	http_run_bev_request(data->base, port,
4624*a466cc55SCy Schubert 		"HEAD /timeout HTTP/1.1\r\n"
4625*a466cc55SCy Schubert 		"Host: somehost\r\n"
4626*a466cc55SCy Schubert 		"Connection: close\r\n"
4627*a466cc55SCy Schubert 		"Content-Length: %i\r\n"
4628*a466cc55SCy Schubert 		"\r\n%s",
4629*a466cc55SCy Schubert 		(int)evbuffer_get_length(body),
4630*a466cc55SCy Schubert 		evbuffer_pullup(body, -1)
4631*a466cc55SCy Schubert 	);
4632*a466cc55SCy Schubert 	tt_assert(test_ok == -2);
4633*a466cc55SCy Schubert 
4634*a466cc55SCy Schubert 	http_run_bev_request(data->base, port,
4635*a466cc55SCy Schubert 		"HEAD /__gencb__ HTTP/1.1\r\n"
4636*a466cc55SCy Schubert 		"Host: somehost\r\n"
4637*a466cc55SCy Schubert 		"Connection: close\r\n"
4638*a466cc55SCy Schubert 		"Content-Length: %i\r\n"
4639*a466cc55SCy Schubert 		"\r\n%s",
4640*a466cc55SCy Schubert 		(int)evbuffer_get_length(body),
4641*a466cc55SCy Schubert 		evbuffer_pullup(body, -1)
4642*a466cc55SCy Schubert 	);
4643*a466cc55SCy Schubert 	tt_assert(test_ok == -2);
4644*a466cc55SCy Schubert 
4645*a466cc55SCy Schubert  end:
4646*a466cc55SCy Schubert 	evhttp_free(http);
4647*a466cc55SCy Schubert 	if (bev)
4648*a466cc55SCy Schubert 		bufferevent_free(bev);
4649*a466cc55SCy Schubert 	if (body)
4650*a466cc55SCy Schubert 		evbuffer_free(body);
4651*a466cc55SCy Schubert }
4652*a466cc55SCy Schubert 
46532b15cb3dSCy Schubert #define HTTP_LEGACY(name)						\
46542b15cb3dSCy Schubert 	{ #name, run_legacy_test_fn, TT_ISOLATED|TT_LEGACY, &legacy_setup, \
46552b15cb3dSCy Schubert 		    http_##name##_test }
46562b15cb3dSCy Schubert 
4657*a466cc55SCy Schubert #define HTTP_CAST_ARG(a) ((void *)(a))
4658*a466cc55SCy Schubert #define HTTP_OFF_N(title, name, arg) \
4659*a466cc55SCy Schubert 	{ #title, http_##name##_test, TT_ISOLATED|TT_OFF_BY_DEFAULT, &basic_setup, HTTP_CAST_ARG(arg) }
4660*a466cc55SCy Schubert #define HTTP_RET_N(title, name, test_opts, arg) \
4661*a466cc55SCy Schubert 	{ #title, http_##name##_test, TT_ISOLATED|TT_RETRIABLE|test_opts, &basic_setup, HTTP_CAST_ARG(arg) }
4662*a466cc55SCy Schubert #define HTTP_N(title, name, test_opts, arg) \
4663*a466cc55SCy Schubert 	{ #title, http_##name##_test, TT_ISOLATED|test_opts, &basic_setup, HTTP_CAST_ARG(arg) }
4664*a466cc55SCy Schubert #define HTTP(name) HTTP_N(name, name, 0, NULL)
4665*a466cc55SCy Schubert #define HTTPS(name) \
4666*a466cc55SCy Schubert 	{ "https_" #name, https_##name##_test, TT_ISOLATED, &basic_setup, NULL }
4667*a466cc55SCy Schubert 
4668*a466cc55SCy Schubert #ifdef EVENT__HAVE_OPENSSL
https_basic_test(void * arg)4669*a466cc55SCy Schubert static void https_basic_test(void *arg)
4670*a466cc55SCy Schubert { http_basic_test_impl(arg, 1, "GET /test HTTP/1.1"); }
https_filter_basic_test(void * arg)4671*a466cc55SCy Schubert static void https_filter_basic_test(void *arg)
4672*a466cc55SCy Schubert { http_basic_test_impl(arg, 1 | HTTP_SSL_FILTER, "GET /test HTTP/1.1"); }
https_incomplete_test(void * arg)4673*a466cc55SCy Schubert static void https_incomplete_test(void *arg)
4674*a466cc55SCy Schubert { http_incomplete_test_(arg, 0, 1); }
https_incomplete_timeout_test(void * arg)4675*a466cc55SCy Schubert static void https_incomplete_timeout_test(void *arg)
4676*a466cc55SCy Schubert { http_incomplete_test_(arg, 1, 1); }
https_simple_test(void * arg)4677*a466cc55SCy Schubert static void https_simple_test(void *arg)
4678*a466cc55SCy Schubert { http_simple_test_impl(arg, 1, 0, "/test"); }
https_simple_dirty_test(void * arg)4679*a466cc55SCy Schubert static void https_simple_dirty_test(void *arg)
4680*a466cc55SCy Schubert { http_simple_test_impl(arg, 1, 1, "/test"); }
https_connection_retry_conn_address_test(void * arg)4681*a466cc55SCy Schubert static void https_connection_retry_conn_address_test(void *arg)
4682*a466cc55SCy Schubert { http_connection_retry_conn_address_test_impl(arg, 1); }
https_connection_retry_test(void * arg)4683*a466cc55SCy Schubert static void https_connection_retry_test(void *arg)
4684*a466cc55SCy Schubert { http_connection_retry_test_impl(arg, 1); }
https_chunk_out_test(void * arg)4685*a466cc55SCy Schubert static void https_chunk_out_test(void *arg)
4686*a466cc55SCy Schubert { http_chunk_out_test_impl(arg, 1); }
https_filter_chunk_out_test(void * arg)4687*a466cc55SCy Schubert static void https_filter_chunk_out_test(void *arg)
4688*a466cc55SCy Schubert { http_chunk_out_test_impl(arg, 1 | HTTP_SSL_FILTER); }
https_stream_out_test(void * arg)4689*a466cc55SCy Schubert static void https_stream_out_test(void *arg)
4690*a466cc55SCy Schubert { http_stream_out_test_impl(arg, 1); }
https_connection_fail_test(void * arg)4691*a466cc55SCy Schubert static void https_connection_fail_test(void *arg)
4692*a466cc55SCy Schubert { http_connection_fail_test_impl(arg, 1); }
https_write_during_read_test(void * arg)4693*a466cc55SCy Schubert static void https_write_during_read_test(void *arg)
4694*a466cc55SCy Schubert { http_write_during_read_test_impl(arg, 1); }
https_connection_test(void * arg)4695*a466cc55SCy Schubert static void https_connection_test(void *arg)
4696*a466cc55SCy Schubert { http_connection_test_(arg, 0, "127.0.0.1", NULL, 0, AF_UNSPEC, 1); }
https_persist_connection_test(void * arg)4697*a466cc55SCy Schubert static void https_persist_connection_test(void *arg)
4698*a466cc55SCy Schubert { http_connection_test_(arg, 1, "127.0.0.1", NULL, 0, AF_UNSPEC, 1); }
4699*a466cc55SCy Schubert #endif
47002b15cb3dSCy Schubert 
47012b15cb3dSCy Schubert struct testcase_t http_testcases[] = {
47022b15cb3dSCy Schubert 	{ "primitives", http_primitives, 0, NULL, NULL },
47032b15cb3dSCy Schubert 	{ "base", http_base_test, TT_FORK, NULL, NULL },
47042b15cb3dSCy Schubert 	{ "bad_headers", http_bad_header_test, 0, NULL, NULL },
47052b15cb3dSCy Schubert 	{ "parse_query", http_parse_query_test, 0, NULL, NULL },
4706*a466cc55SCy Schubert 	{ "parse_query_str", http_parse_query_str_test, 0, NULL, NULL },
47072b15cb3dSCy Schubert 	{ "parse_uri", http_parse_uri_test, 0, NULL, NULL },
47082b15cb3dSCy Schubert 	{ "parse_uri_nc", http_parse_uri_test, 0, &basic_setup, (void*)"nc" },
47092b15cb3dSCy Schubert 	{ "uriencode", http_uriencode_test, 0, NULL, NULL },
47102b15cb3dSCy Schubert 	HTTP(basic),
4711*a466cc55SCy Schubert 	HTTP(basic_trailing_space),
4712*a466cc55SCy Schubert 	HTTP(simple),
4713*a466cc55SCy Schubert 	HTTP(simple_nonconformant),
4714*a466cc55SCy Schubert 
4715*a466cc55SCy Schubert 	HTTP_N(cancel, cancel, 0, BASIC),
4716*a466cc55SCy Schubert 	HTTP_RET_N(cancel_by_host, cancel, 0, BY_HOST),
4717*a466cc55SCy Schubert 	HTTP_RET_N(cancel_by_host_inactive_server, cancel, TT_NO_LOGS, BY_HOST | INACTIVE_SERVER),
4718*a466cc55SCy Schubert 	HTTP_RET_N(cancel_by_host_no_ns, cancel, TT_NO_LOGS, BY_HOST | NO_NS),
4719*a466cc55SCy Schubert 	HTTP_N(cancel_inactive_server, cancel, 0, INACTIVE_SERVER),
4720*a466cc55SCy Schubert 	HTTP_N(cancel_by_host_no_ns_inactive_server, cancel, TT_NO_LOGS, BY_HOST | NO_NS | INACTIVE_SERVER),
4721*a466cc55SCy Schubert 	HTTP_OFF_N(cancel_by_host_server_timeout, cancel, BY_HOST | INACTIVE_SERVER | SERVER_TIMEOUT),
4722*a466cc55SCy Schubert 	HTTP_OFF_N(cancel_server_timeout, cancel, INACTIVE_SERVER | SERVER_TIMEOUT),
4723*a466cc55SCy Schubert 	HTTP_OFF_N(cancel_by_host_no_ns_server_timeout, cancel, BY_HOST | NO_NS | INACTIVE_SERVER | SERVER_TIMEOUT),
4724*a466cc55SCy Schubert 	HTTP_OFF_N(cancel_by_host_ns_timeout_server_timeout, cancel, BY_HOST | NO_NS | NS_TIMEOUT | INACTIVE_SERVER | SERVER_TIMEOUT),
4725*a466cc55SCy Schubert 	HTTP_RET_N(cancel_by_host_ns_timeout, cancel, TT_NO_LOGS, BY_HOST | NO_NS | NS_TIMEOUT),
4726*a466cc55SCy Schubert 	HTTP_RET_N(cancel_by_host_ns_timeout_inactive_server, cancel, TT_NO_LOGS, BY_HOST | NO_NS | NS_TIMEOUT | INACTIVE_SERVER),
4727*a466cc55SCy Schubert 
47282b15cb3dSCy Schubert 	HTTP(virtual_host),
47292b15cb3dSCy Schubert 	HTTP(post),
47302b15cb3dSCy Schubert 	HTTP(put),
47312b15cb3dSCy Schubert 	HTTP(delete),
47322b15cb3dSCy Schubert 	HTTP(allowed_methods),
47332b15cb3dSCy Schubert 	HTTP(failure),
47342b15cb3dSCy Schubert 	HTTP(connection),
47352b15cb3dSCy Schubert 	HTTP(persist_connection),
4736a25439b6SCy Schubert 	HTTP(autofree_connection),
47372b15cb3dSCy Schubert 	HTTP(connection_async),
47382b15cb3dSCy Schubert 	HTTP(close_detection),
47392b15cb3dSCy Schubert 	HTTP(close_detection_delay),
47402b15cb3dSCy Schubert 	HTTP(bad_request),
47412b15cb3dSCy Schubert 	HTTP(incomplete),
47422b15cb3dSCy Schubert 	HTTP(incomplete_timeout),
47432b15cb3dSCy Schubert 	HTTP(terminate_chunked),
4744*a466cc55SCy Schubert 	HTTP(terminate_chunked_oneshot),
47452b15cb3dSCy Schubert 	HTTP(on_complete),
47462b15cb3dSCy Schubert 
47472b15cb3dSCy Schubert 	HTTP(highport),
47482b15cb3dSCy Schubert 	HTTP(dispatcher),
47492b15cb3dSCy Schubert 	HTTP(multi_line_header),
47502b15cb3dSCy Schubert 	HTTP(negative_content_length),
47512b15cb3dSCy Schubert 	HTTP(chunk_out),
47522b15cb3dSCy Schubert 	HTTP(stream_out),
47532b15cb3dSCy Schubert 
47542b15cb3dSCy Schubert 	HTTP(stream_in),
47552b15cb3dSCy Schubert 	HTTP(stream_in_cancel),
47562b15cb3dSCy Schubert 
47572b15cb3dSCy Schubert 	HTTP(connection_fail),
47582b15cb3dSCy Schubert 	{ "connection_retry", http_connection_retry_test, TT_ISOLATED|TT_OFF_BY_DEFAULT, &basic_setup, NULL },
4759*a466cc55SCy Schubert 	{ "connection_retry_conn_address", http_connection_retry_conn_address_test,
4760*a466cc55SCy Schubert 	  TT_ISOLATED|TT_OFF_BY_DEFAULT, &basic_setup, NULL },
47612b15cb3dSCy Schubert 
47622b15cb3dSCy Schubert 	HTTP(data_length_constraints),
4763*a466cc55SCy Schubert 	HTTP(read_on_write_error),
4764*a466cc55SCy Schubert 	HTTP(non_lingering_close),
4765*a466cc55SCy Schubert 	HTTP(lingering_close),
47662b15cb3dSCy Schubert 
47672b15cb3dSCy Schubert 	HTTP(ipv6_for_domain),
47682b15cb3dSCy Schubert 	HTTP(get_addr),
47692b15cb3dSCy Schubert 
4770a25439b6SCy Schubert 	HTTP(set_family),
4771a25439b6SCy Schubert 	HTTP(set_family_ipv4),
4772a25439b6SCy Schubert 	HTTP(set_family_ipv6),
4773a25439b6SCy Schubert 
4774*a466cc55SCy Schubert 	HTTP(write_during_read),
4775*a466cc55SCy Schubert 	HTTP(request_own),
4776*a466cc55SCy Schubert 
4777*a466cc55SCy Schubert 	HTTP(request_extra_body),
4778*a466cc55SCy Schubert 
4779*a466cc55SCy Schubert #ifdef EVENT__HAVE_OPENSSL
4780*a466cc55SCy Schubert 	HTTPS(basic),
4781*a466cc55SCy Schubert 	HTTPS(filter_basic),
4782*a466cc55SCy Schubert 	HTTPS(simple),
4783*a466cc55SCy Schubert 	HTTPS(simple_dirty),
4784*a466cc55SCy Schubert 	HTTPS(incomplete),
4785*a466cc55SCy Schubert 	HTTPS(incomplete_timeout),
4786*a466cc55SCy Schubert 	{ "https_connection_retry", https_connection_retry_test, TT_ISOLATED|TT_OFF_BY_DEFAULT, &basic_setup, NULL },
4787*a466cc55SCy Schubert 	{ "https_connection_retry_conn_address", https_connection_retry_conn_address_test,
4788*a466cc55SCy Schubert 	  TT_ISOLATED|TT_OFF_BY_DEFAULT, &basic_setup, NULL },
4789*a466cc55SCy Schubert 	HTTPS(chunk_out),
4790*a466cc55SCy Schubert 	HTTPS(filter_chunk_out),
4791*a466cc55SCy Schubert 	HTTPS(stream_out),
4792*a466cc55SCy Schubert 	HTTPS(connection_fail),
4793*a466cc55SCy Schubert 	HTTPS(write_during_read),
4794*a466cc55SCy Schubert 	HTTPS(connection),
4795*a466cc55SCy Schubert 	HTTPS(persist_connection),
4796*a466cc55SCy Schubert #endif
4797*a466cc55SCy Schubert 
47982b15cb3dSCy Schubert 	END_OF_TESTCASES
47992b15cb3dSCy Schubert };
48002b15cb3dSCy Schubert 
4801*a466cc55SCy Schubert struct testcase_t http_iocp_testcases[] = {
4802*a466cc55SCy Schubert 	{ "simple", http_simple_test, TT_FORK|TT_NEED_BASE|TT_ENABLE_IOCP, &basic_setup, NULL },
4803*a466cc55SCy Schubert #ifdef EVENT__HAVE_OPENSSL
4804*a466cc55SCy Schubert 	{ "https_simple", https_simple_test, TT_FORK|TT_NEED_BASE|TT_ENABLE_IOCP, &basic_setup, NULL },
4805*a466cc55SCy Schubert #endif
4806*a466cc55SCy Schubert 	END_OF_TESTCASES
4807*a466cc55SCy Schubert };
4808