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