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