ipc/chromium/src/third_party/libevent/test/regress_http.c

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/ipc/chromium/src/third_party/libevent/test/regress_http.c	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,3621 @@
     1.4 +/*
     1.5 + * Copyright (c) 2003-2007 Niels Provos <provos@citi.umich.edu>
     1.6 + * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson
     1.7 + *
     1.8 + * Redistribution and use in source and binary forms, with or without
     1.9 + * modification, are permitted provided that the following conditions
    1.10 + * are met:
    1.11 + * 1. Redistributions of source code must retain the above copyright
    1.12 + *    notice, this list of conditions and the following disclaimer.
    1.13 + * 2. Redistributions in binary form must reproduce the above copyright
    1.14 + *    notice, this list of conditions and the following disclaimer in the
    1.15 + *    documentation and/or other materials provided with the distribution.
    1.16 + * 3. The name of the author may not be used to endorse or promote products
    1.17 + *    derived from this software without specific prior written permission.
    1.18 + *
    1.19 + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
    1.20 + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
    1.21 + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
    1.22 + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
    1.23 + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
    1.24 + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
    1.25 + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
    1.26 + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    1.27 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
    1.28 + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    1.29 + */
    1.30 +
    1.31 +#ifdef WIN32
    1.32 +#include <winsock2.h>
    1.33 +#include <ws2tcpip.h>
    1.34 +#include <windows.h>
    1.35 +#endif
    1.36 +
    1.37 +#include "event2/event-config.h"
    1.38 +
    1.39 +#include <sys/types.h>
    1.40 +#include <sys/stat.h>
    1.41 +#ifdef _EVENT_HAVE_SYS_TIME_H
    1.42 +#include <sys/time.h>
    1.43 +#endif
    1.44 +#include <sys/queue.h>
    1.45 +#ifndef WIN32
    1.46 +#include <sys/socket.h>
    1.47 +#include <signal.h>
    1.48 +#include <unistd.h>
    1.49 +#include <netdb.h>
    1.50 +#endif
    1.51 +#include <fcntl.h>
    1.52 +#include <stdlib.h>
    1.53 +#include <stdio.h>
    1.54 +#include <string.h>
    1.55 +#include <errno.h>
    1.56 +
    1.57 +#include "event2/dns.h"
    1.58 +
    1.59 +#include "event2/event.h"
    1.60 +#include "event2/http.h"
    1.61 +#include "event2/buffer.h"
    1.62 +#include "event2/bufferevent.h"
    1.63 +#include "event2/util.h"
    1.64 +#include "log-internal.h"
    1.65 +#include "util-internal.h"
    1.66 +#include "http-internal.h"
    1.67 +#include "regress.h"
    1.68 +#include "regress_testutils.h"
    1.69 +
    1.70 +static struct evhttp *http;
    1.71 +/* set if a test needs to call loopexit on a base */
    1.72 +static struct event_base *exit_base;
    1.73 +
    1.74 +static char const BASIC_REQUEST_BODY[] = "This is funny";
    1.75 +
    1.76 +static void http_basic_cb(struct evhttp_request *req, void *arg);
    1.77 +static void http_chunked_cb(struct evhttp_request *req, void *arg);
    1.78 +static void http_post_cb(struct evhttp_request *req, void *arg);
    1.79 +static void http_put_cb(struct evhttp_request *req, void *arg);
    1.80 +static void http_delete_cb(struct evhttp_request *req, void *arg);
    1.81 +static void http_delay_cb(struct evhttp_request *req, void *arg);
    1.82 +static void http_large_delay_cb(struct evhttp_request *req, void *arg);
    1.83 +static void http_badreq_cb(struct evhttp_request *req, void *arg);
    1.84 +static void http_dispatcher_cb(struct evhttp_request *req, void *arg);
    1.85 +static int
    1.86 +http_bind(struct evhttp *myhttp, ev_uint16_t *pport)
    1.87 +{
    1.88 +	int port;
    1.89 +	struct evhttp_bound_socket *sock;
    1.90 +
    1.91 +	sock = evhttp_bind_socket_with_handle(myhttp, "127.0.0.1", *pport);
    1.92 +	if (sock == NULL)
    1.93 +		event_errx(1, "Could not start web server");
    1.94 +
    1.95 +	port = regress_get_socket_port(evhttp_bound_socket_get_fd(sock));
    1.96 +	if (port < 0)
    1.97 +		return -1;
    1.98 +	*pport = (ev_uint16_t) port;
    1.99 +
   1.100 +	return 0;
   1.101 +}
   1.102 +
   1.103 +static struct evhttp *
   1.104 +http_setup(ev_uint16_t *pport, struct event_base *base)
   1.105 +{
   1.106 +	struct evhttp *myhttp;
   1.107 +
   1.108 +	/* Try a few different ports */
   1.109 +	myhttp = evhttp_new(base);
   1.110 +
   1.111 +	if (http_bind(myhttp, pport) < 0)
   1.112 +		return NULL;
   1.113 +
   1.114 +	/* Register a callback for certain types of requests */
   1.115 +	evhttp_set_cb(myhttp, "/test", http_basic_cb, base);
   1.116 +	evhttp_set_cb(myhttp, "/chunked", http_chunked_cb, base);
   1.117 +	evhttp_set_cb(myhttp, "/streamed", http_chunked_cb, base);
   1.118 +	evhttp_set_cb(myhttp, "/postit", http_post_cb, base);
   1.119 +	evhttp_set_cb(myhttp, "/putit", http_put_cb, base);
   1.120 +	evhttp_set_cb(myhttp, "/deleteit", http_delete_cb, base);
   1.121 +	evhttp_set_cb(myhttp, "/delay", http_delay_cb, base);
   1.122 +	evhttp_set_cb(myhttp, "/largedelay", http_large_delay_cb, base);
   1.123 +	evhttp_set_cb(myhttp, "/badrequest", http_badreq_cb, base);
   1.124 +	evhttp_set_cb(myhttp, "/", http_dispatcher_cb, base);
   1.125 +	return (myhttp);
   1.126 +}
   1.127 +
   1.128 +#ifndef NI_MAXSERV
   1.129 +#define NI_MAXSERV 1024
   1.130 +#endif
   1.131 +
   1.132 +static evutil_socket_t
   1.133 +http_connect(const char *address, u_short port)
   1.134 +{
   1.135 +	/* Stupid code for connecting */
   1.136 +	struct evutil_addrinfo ai, *aitop;
   1.137 +	char strport[NI_MAXSERV];
   1.138 +
   1.139 +	struct sockaddr *sa;
   1.140 +	int slen;
   1.141 +	evutil_socket_t fd;
   1.142 +
   1.143 +	memset(&ai, 0, sizeof(ai));
   1.144 +	ai.ai_family = AF_INET;
   1.145 +	ai.ai_socktype = SOCK_STREAM;
   1.146 +	evutil_snprintf(strport, sizeof(strport), "%d", port);
   1.147 +	if (evutil_getaddrinfo(address, strport, &ai, &aitop) != 0) {
   1.148 +		event_warn("getaddrinfo");
   1.149 +		return (-1);
   1.150 +	}
   1.151 +	sa = aitop->ai_addr;
   1.152 +	slen = aitop->ai_addrlen;
   1.153 +
   1.154 +	fd = socket(AF_INET, SOCK_STREAM, 0);
   1.155 +	if (fd == -1)
   1.156 +		event_err(1, "socket failed");
   1.157 +
   1.158 +	evutil_make_socket_nonblocking(fd);
   1.159 +	if (connect(fd, sa, slen) == -1) {
   1.160 +#ifdef WIN32
   1.161 +		int tmp_err = WSAGetLastError();
   1.162 +		if (tmp_err != WSAEINPROGRESS && tmp_err != WSAEINVAL &&
   1.163 +		    tmp_err != WSAEWOULDBLOCK)
   1.164 +			event_err(1, "connect failed");
   1.165 +#else
   1.166 +		if (errno != EINPROGRESS)
   1.167 +			event_err(1, "connect failed");
   1.168 +#endif
   1.169 +	}
   1.170 +
   1.171 +	evutil_freeaddrinfo(aitop);
   1.172 +
   1.173 +	return (fd);
   1.174 +}
   1.175 +
   1.176 +/* Helper: do a strcmp on the contents of buf and the string s. */
   1.177 +static int
   1.178 +evbuffer_datacmp(struct evbuffer *buf, const char *s)
   1.179 +{
   1.180 +	size_t b_sz = evbuffer_get_length(buf);
   1.181 +	size_t s_sz = strlen(s);
   1.182 +	unsigned char *d;
   1.183 +	int r;
   1.184 +
   1.185 +	if (b_sz < s_sz)
   1.186 +		return -1;
   1.187 +
   1.188 +	d = evbuffer_pullup(buf, s_sz);
   1.189 +	if ((r = memcmp(d, s, s_sz)))
   1.190 +		return r;
   1.191 +
   1.192 +	if (b_sz > s_sz)
   1.193 +		return 1;
   1.194 +	else
   1.195 +		return 0;
   1.196 +}
   1.197 +
   1.198 +/* Helper: Return true iff buf contains s */
   1.199 +static int
   1.200 +evbuffer_contains(struct evbuffer *buf, const char *s)
   1.201 +{
   1.202 +	struct evbuffer_ptr ptr;
   1.203 +	ptr = evbuffer_search(buf, s, strlen(s), NULL);
   1.204 +	return ptr.pos != -1;
   1.205 +}
   1.206 +
   1.207 +static void
   1.208 +http_readcb(struct bufferevent *bev, void *arg)
   1.209 +{
   1.210 +	const char *what = BASIC_REQUEST_BODY;
   1.211 +	struct event_base *my_base = arg;
   1.212 +
   1.213 +	if (evbuffer_contains(bufferevent_get_input(bev), what)) {
   1.214 +		struct evhttp_request *req = evhttp_request_new(NULL, NULL);
   1.215 +		enum message_read_status done;
   1.216 +
   1.217 +		/* req->kind = EVHTTP_RESPONSE; */
   1.218 +		done = evhttp_parse_firstline(req, bufferevent_get_input(bev));
   1.219 +		if (done != ALL_DATA_READ)
   1.220 +			goto out;
   1.221 +
   1.222 +		done = evhttp_parse_headers(req, bufferevent_get_input(bev));
   1.223 +		if (done != ALL_DATA_READ)
   1.224 +			goto out;
   1.225 +
   1.226 +		if (done == 1 &&
   1.227 +		    evhttp_find_header(evhttp_request_get_input_headers(req),
   1.228 +			"Content-Type") != NULL)
   1.229 +			test_ok++;
   1.230 +
   1.231 +	 out:
   1.232 +		evhttp_request_free(req);
   1.233 +		bufferevent_disable(bev, EV_READ);
   1.234 +		if (exit_base)
   1.235 +			event_base_loopexit(exit_base, NULL);
   1.236 +		else if (my_base)
   1.237 +			event_base_loopexit(my_base, NULL);
   1.238 +		else {
   1.239 +			fprintf(stderr, "No way to exit loop!\n");
   1.240 +			exit(1);
   1.241 +		}
   1.242 +	}
   1.243 +}
   1.244 +
   1.245 +static void
   1.246 +http_writecb(struct bufferevent *bev, void *arg)
   1.247 +{
   1.248 +	if (evbuffer_get_length(bufferevent_get_output(bev)) == 0) {
   1.249 +		/* enable reading of the reply */
   1.250 +		bufferevent_enable(bev, EV_READ);
   1.251 +		test_ok++;
   1.252 +	}
   1.253 +}
   1.254 +
   1.255 +static void
   1.256 +http_errorcb(struct bufferevent *bev, short what, void *arg)
   1.257 +{
   1.258 +	test_ok = -2;
   1.259 +	event_base_loopexit(arg, NULL);
   1.260 +}
   1.261 +
   1.262 +static void
   1.263 +http_basic_cb(struct evhttp_request *req, void *arg)
   1.264 +{
   1.265 +	struct evbuffer *evb = evbuffer_new();
   1.266 +	int empty = evhttp_find_header(evhttp_request_get_input_headers(req), "Empty") != NULL;
   1.267 +	event_debug(("%s: called\n", __func__));
   1.268 +	evbuffer_add_printf(evb, BASIC_REQUEST_BODY);
   1.269 +
   1.270 +	/* For multi-line headers test */
   1.271 +	{
   1.272 +		const char *multi =
   1.273 +		    evhttp_find_header(evhttp_request_get_input_headers(req),"X-multi");
   1.274 +		if (multi) {
   1.275 +			if (strcmp("END", multi + strlen(multi) - 3) == 0)
   1.276 +				test_ok++;
   1.277 +			if (evhttp_find_header(evhttp_request_get_input_headers(req), "X-Last"))
   1.278 +				test_ok++;
   1.279 +		}
   1.280 +	}
   1.281 +
   1.282 +	/* injecting a bad content-length */
   1.283 +	if (evhttp_find_header(evhttp_request_get_input_headers(req), "X-Negative"))
   1.284 +		evhttp_add_header(evhttp_request_get_output_headers(req),
   1.285 +		    "Content-Length", "-100");
   1.286 +
   1.287 +	/* allow sending of an empty reply */
   1.288 +	evhttp_send_reply(req, HTTP_OK, "Everything is fine",
   1.289 +	    !empty ? evb : NULL);
   1.290 +
   1.291 +	evbuffer_free(evb);
   1.292 +}
   1.293 +
   1.294 +static char const* const CHUNKS[] = {
   1.295 +	"This is funny",
   1.296 +	"but not hilarious.",
   1.297 +	"bwv 1052"
   1.298 +};
   1.299 +
   1.300 +struct chunk_req_state {
   1.301 +	struct event_base *base;
   1.302 +	struct evhttp_request *req;
   1.303 +	int i;
   1.304 +};
   1.305 +
   1.306 +static void
   1.307 +http_chunked_trickle_cb(evutil_socket_t fd, short events, void *arg)
   1.308 +{
   1.309 +	struct evbuffer *evb = evbuffer_new();
   1.310 +	struct chunk_req_state *state = arg;
   1.311 +	struct timeval when = { 0, 0 };
   1.312 +
   1.313 +	evbuffer_add_printf(evb, "%s", CHUNKS[state->i]);
   1.314 +	evhttp_send_reply_chunk(state->req, evb);
   1.315 +	evbuffer_free(evb);
   1.316 +
   1.317 +	if (++state->i < (int) (sizeof(CHUNKS)/sizeof(CHUNKS[0]))) {
   1.318 +		event_base_once(state->base, -1, EV_TIMEOUT,
   1.319 +		    http_chunked_trickle_cb, state, &when);
   1.320 +	} else {
   1.321 +		evhttp_send_reply_end(state->req);
   1.322 +		free(state);
   1.323 +	}
   1.324 +}
   1.325 +
   1.326 +static void
   1.327 +http_chunked_cb(struct evhttp_request *req, void *arg)
   1.328 +{
   1.329 +	struct timeval when = { 0, 0 };
   1.330 +	struct chunk_req_state *state = malloc(sizeof(struct chunk_req_state));
   1.331 +	event_debug(("%s: called\n", __func__));
   1.332 +
   1.333 +	memset(state, 0, sizeof(struct chunk_req_state));
   1.334 +	state->req = req;
   1.335 +	state->base = arg;
   1.336 +
   1.337 +	if (strcmp(evhttp_request_get_uri(req), "/streamed") == 0) {
   1.338 +		evhttp_add_header(evhttp_request_get_output_headers(req), "Content-Length", "39");
   1.339 +	}
   1.340 +
   1.341 +	/* generate a chunked/streamed reply */
   1.342 +	evhttp_send_reply_start(req, HTTP_OK, "Everything is fine");
   1.343 +
   1.344 +	/* but trickle it across several iterations to ensure we're not
   1.345 +	 * assuming it comes all at once */
   1.346 +	event_base_once(arg, -1, EV_TIMEOUT, http_chunked_trickle_cb, state, &when);
   1.347 +}
   1.348 +
   1.349 +static void
   1.350 +http_complete_write(evutil_socket_t fd, short what, void *arg)
   1.351 +{
   1.352 +	struct bufferevent *bev = arg;
   1.353 +	const char *http_request = "host\r\n"
   1.354 +	    "Connection: close\r\n"
   1.355 +	    "\r\n";
   1.356 +	bufferevent_write(bev, http_request, strlen(http_request));
   1.357 +}
   1.358 +
   1.359 +static void
   1.360 +http_basic_test(void *arg)
   1.361 +{
   1.362 +	struct basic_test_data *data = arg;
   1.363 +	struct timeval tv;
   1.364 +	struct bufferevent *bev;
   1.365 +	evutil_socket_t fd;
   1.366 +	const char *http_request;
   1.367 +	ev_uint16_t port = 0, port2 = 0;
   1.368 +
   1.369 +	test_ok = 0;
   1.370 +
   1.371 +	http = http_setup(&port, data->base);
   1.372 +
   1.373 +	/* bind to a second socket */
   1.374 +	if (http_bind(http, &port2) == -1) {
   1.375 +		fprintf(stdout, "FAILED (bind)\n");
   1.376 +		exit(1);
   1.377 +	}
   1.378 +
   1.379 +	fd = http_connect("127.0.0.1", port);
   1.380 +
   1.381 +	/* Stupid thing to send a request */
   1.382 +	bev = bufferevent_socket_new(data->base, fd, 0);
   1.383 +	bufferevent_setcb(bev, http_readcb, http_writecb,
   1.384 +	    http_errorcb, data->base);
   1.385 +
   1.386 +	/* first half of the http request */
   1.387 +	http_request =
   1.388 +	    "GET /test HTTP/1.1\r\n"
   1.389 +	    "Host: some";
   1.390 +
   1.391 +	bufferevent_write(bev, http_request, strlen(http_request));
   1.392 +	evutil_timerclear(&tv);
   1.393 +	tv.tv_usec = 10000;
   1.394 +	event_base_once(data->base,
   1.395 +	    -1, EV_TIMEOUT, http_complete_write, bev, &tv);
   1.396 +
   1.397 +	event_base_dispatch(data->base);
   1.398 +
   1.399 +	tt_assert(test_ok == 3);
   1.400 +
   1.401 +	/* connect to the second port */
   1.402 +	bufferevent_free(bev);
   1.403 +	evutil_closesocket(fd);
   1.404 +
   1.405 +	fd = http_connect("127.0.0.1", port2);
   1.406 +
   1.407 +	/* Stupid thing to send a request */
   1.408 +	bev = bufferevent_socket_new(data->base, fd, 0);
   1.409 +	bufferevent_setcb(bev, http_readcb, http_writecb,
   1.410 +	    http_errorcb, data->base);
   1.411 +
   1.412 +	http_request =
   1.413 +	    "GET /test HTTP/1.1\r\n"
   1.414 +	    "Host: somehost\r\n"
   1.415 +	    "Connection: close\r\n"
   1.416 +	    "\r\n";
   1.417 +
   1.418 +	bufferevent_write(bev, http_request, strlen(http_request));
   1.419 +
   1.420 +	event_base_dispatch(data->base);
   1.421 +
   1.422 +	tt_assert(test_ok == 5);
   1.423 +
   1.424 +	/* Connect to the second port again. This time, send an absolute uri. */
   1.425 +	bufferevent_free(bev);
   1.426 +	evutil_closesocket(fd);
   1.427 +
   1.428 +	fd = http_connect("127.0.0.1", port2);
   1.429 +
   1.430 +	/* Stupid thing to send a request */
   1.431 +	bev = bufferevent_socket_new(data->base, fd, 0);
   1.432 +	bufferevent_setcb(bev, http_readcb, http_writecb,
   1.433 +	    http_errorcb, data->base);
   1.434 +
   1.435 +	http_request =
   1.436 +	    "GET http://somehost.net/test HTTP/1.1\r\n"
   1.437 +	    "Host: somehost\r\n"
   1.438 +	    "Connection: close\r\n"
   1.439 +	    "\r\n";
   1.440 +
   1.441 +	bufferevent_write(bev, http_request, strlen(http_request));
   1.442 +
   1.443 +	event_base_dispatch(data->base);
   1.444 +
   1.445 +	tt_assert(test_ok == 7);
   1.446 +
   1.447 +	evhttp_free(http);
   1.448 + end:
   1.449 +	;
   1.450 +}
   1.451 +
   1.452 +static void
   1.453 +http_delay_reply(evutil_socket_t fd, short what, void *arg)
   1.454 +{
   1.455 +	struct evhttp_request *req = arg;
   1.456 +
   1.457 +	evhttp_send_reply(req, HTTP_OK, "Everything is fine", NULL);
   1.458 +
   1.459 +	++test_ok;
   1.460 +}
   1.461 +
   1.462 +static void
   1.463 +http_delay_cb(struct evhttp_request *req, void *arg)
   1.464 +{
   1.465 +	struct timeval tv;
   1.466 +	evutil_timerclear(&tv);
   1.467 +	tv.tv_sec = 0;
   1.468 +	tv.tv_usec = 200 * 1000;
   1.469 +
   1.470 +	event_base_once(arg, -1, EV_TIMEOUT, http_delay_reply, req, &tv);
   1.471 +}
   1.472 +
   1.473 +static void
   1.474 +http_badreq_cb(struct evhttp_request *req, void *arg)
   1.475 +{
   1.476 +	struct evbuffer *buf = evbuffer_new();
   1.477 +
   1.478 +	evhttp_add_header(evhttp_request_get_output_headers(req), "Content-Type", "text/xml; charset=UTF-8");
   1.479 +	evbuffer_add_printf(buf, "Hello, %s!", "127.0.0.1");
   1.480 +
   1.481 +	evhttp_send_reply(req, HTTP_OK, "OK", buf);
   1.482 +	evbuffer_free(buf);
   1.483 +}
   1.484 +
   1.485 +static void
   1.486 +http_badreq_errorcb(struct bufferevent *bev, short what, void *arg)
   1.487 +{
   1.488 +	event_debug(("%s: called (what=%04x, arg=%p)", __func__, what, arg));
   1.489 +	/* ignore */
   1.490 +}
   1.491 +
   1.492 +#ifndef SHUT_WR
   1.493 +#ifdef WIN32
   1.494 +#define SHUT_WR SD_SEND
   1.495 +#else
   1.496 +#define SHUT_WR 1
   1.497 +#endif
   1.498 +#endif
   1.499 +
   1.500 +static void
   1.501 +http_badreq_readcb(struct bufferevent *bev, void *arg)
   1.502 +{
   1.503 +	const char *what = "Hello, 127.0.0.1";
   1.504 +	const char *bad_request = "400 Bad Request";
   1.505 +
   1.506 +	if (evbuffer_contains(bufferevent_get_input(bev), bad_request)) {
   1.507 +		TT_FAIL(("%s:bad request detected", __func__));
   1.508 +		bufferevent_disable(bev, EV_READ);
   1.509 +		event_base_loopexit(arg, NULL);
   1.510 +		return;
   1.511 +	}
   1.512 +
   1.513 +	if (evbuffer_contains(bufferevent_get_input(bev), what)) {
   1.514 +		struct evhttp_request *req = evhttp_request_new(NULL, NULL);
   1.515 +		enum message_read_status done;
   1.516 +
   1.517 +		/* req->kind = EVHTTP_RESPONSE; */
   1.518 +		done = evhttp_parse_firstline(req, bufferevent_get_input(bev));
   1.519 +		if (done != ALL_DATA_READ)
   1.520 +			goto out;
   1.521 +
   1.522 +		done = evhttp_parse_headers(req, bufferevent_get_input(bev));
   1.523 +		if (done != ALL_DATA_READ)
   1.524 +			goto out;
   1.525 +
   1.526 +		if (done == 1 &&
   1.527 +		    evhttp_find_header(evhttp_request_get_input_headers(req),
   1.528 +			"Content-Type") != NULL)
   1.529 +			test_ok++;
   1.530 +
   1.531 +	out:
   1.532 +		evhttp_request_free(req);
   1.533 +		evbuffer_drain(bufferevent_get_input(bev), evbuffer_get_length(bufferevent_get_input(bev)));
   1.534 +	}
   1.535 +
   1.536 +	shutdown(bufferevent_getfd(bev), SHUT_WR);
   1.537 +}
   1.538 +
   1.539 +static void
   1.540 +http_badreq_successcb(evutil_socket_t fd, short what, void *arg)
   1.541 +{
   1.542 +	event_debug(("%s: called (what=%04x, arg=%p)", __func__, what, arg));
   1.543 +	event_base_loopexit(exit_base, NULL);
   1.544 +}
   1.545 +
   1.546 +static void
   1.547 +http_bad_request_test(void *arg)
   1.548 +{
   1.549 +	struct basic_test_data *data = arg;
   1.550 +	struct timeval tv;
   1.551 +	struct bufferevent *bev = NULL;
   1.552 +	evutil_socket_t fd;
   1.553 +	const char *http_request;
   1.554 +	ev_uint16_t port=0, port2=0;
   1.555 +
   1.556 +	test_ok = 0;
   1.557 +	exit_base = data->base;
   1.558 +
   1.559 +	http = http_setup(&port, data->base);
   1.560 +
   1.561 +	/* bind to a second socket */
   1.562 +	if (http_bind(http, &port2) == -1)
   1.563 +		TT_DIE(("Bind socket failed"));
   1.564 +
   1.565 +	/* NULL request test */
   1.566 +	fd = http_connect("127.0.0.1", port);
   1.567 +
   1.568 +	/* Stupid thing to send a request */
   1.569 +	bev = bufferevent_socket_new(data->base, fd, 0);
   1.570 +	bufferevent_setcb(bev, http_badreq_readcb, http_writecb,
   1.571 +	    http_badreq_errorcb, data->base);
   1.572 +	bufferevent_enable(bev, EV_READ);
   1.573 +
   1.574 +	/* real NULL request */
   1.575 +	http_request = "";
   1.576 +
   1.577 +	bufferevent_write(bev, http_request, strlen(http_request));
   1.578 +
   1.579 +	shutdown(fd, SHUT_WR);
   1.580 +	timerclear(&tv);
   1.581 +	tv.tv_usec = 10000;
   1.582 +	event_base_once(data->base, -1, EV_TIMEOUT, http_badreq_successcb, bev, &tv);
   1.583 +
   1.584 +	event_base_dispatch(data->base);
   1.585 +
   1.586 +	bufferevent_free(bev);
   1.587 +	evutil_closesocket(fd);
   1.588 +
   1.589 +	if (test_ok != 0) {
   1.590 +		fprintf(stdout, "FAILED\n");
   1.591 +		exit(1);
   1.592 +	}
   1.593 +
   1.594 +	/* Second answer (BAD REQUEST) on connection close */
   1.595 +
   1.596 +	/* connect to the second port */
   1.597 +	fd = http_connect("127.0.0.1", port2);
   1.598 +
   1.599 +	/* Stupid thing to send a request */
   1.600 +	bev = bufferevent_socket_new(data->base, fd, 0);
   1.601 +	bufferevent_setcb(bev, http_badreq_readcb, http_writecb,
   1.602 +	    http_badreq_errorcb, data->base);
   1.603 +	bufferevent_enable(bev, EV_READ);
   1.604 +
   1.605 +	/* first half of the http request */
   1.606 +	http_request =
   1.607 +		"GET /badrequest HTTP/1.0\r\n"	\
   1.608 +		"Connection: Keep-Alive\r\n"	\
   1.609 +		"\r\n";
   1.610 +
   1.611 +	bufferevent_write(bev, http_request, strlen(http_request));
   1.612 +
   1.613 +	timerclear(&tv);
   1.614 +	tv.tv_usec = 10000;
   1.615 +	event_base_once(data->base, -1, EV_TIMEOUT, http_badreq_successcb, bev, &tv);
   1.616 +
   1.617 +	event_base_dispatch(data->base);
   1.618 +
   1.619 +	tt_int_op(test_ok, ==, 2);
   1.620 +
   1.621 +end:
   1.622 +	evhttp_free(http);
   1.623 +	if (bev)
   1.624 +		bufferevent_free(bev);
   1.625 +}
   1.626 +
   1.627 +static struct evhttp_connection *delayed_client;
   1.628 +
   1.629 +static void
   1.630 +http_large_delay_cb(struct evhttp_request *req, void *arg)
   1.631 +{
   1.632 +	struct timeval tv;
   1.633 +	evutil_timerclear(&tv);
   1.634 +	tv.tv_sec = 3;
   1.635 +
   1.636 +	event_base_once(arg, -1, EV_TIMEOUT, http_delay_reply, req, &tv);
   1.637 +	evhttp_connection_fail(delayed_client, EVCON_HTTP_EOF);
   1.638 +}
   1.639 +
   1.640 +/*
   1.641 + * HTTP DELETE test,  just piggyback on the basic test
   1.642 + */
   1.643 +
   1.644 +static void
   1.645 +http_delete_cb(struct evhttp_request *req, void *arg)
   1.646 +{
   1.647 +	struct evbuffer *evb = evbuffer_new();
   1.648 +	int empty = evhttp_find_header(evhttp_request_get_input_headers(req), "Empty") != NULL;
   1.649 +
   1.650 +	/* Expecting a DELETE request */
   1.651 +	if (evhttp_request_get_command(req) != EVHTTP_REQ_DELETE) {
   1.652 +		fprintf(stdout, "FAILED (delete type)\n");
   1.653 +		exit(1);
   1.654 +	}
   1.655 +
   1.656 +	event_debug(("%s: called\n", __func__));
   1.657 +	evbuffer_add_printf(evb, BASIC_REQUEST_BODY);
   1.658 +
   1.659 +	/* allow sending of an empty reply */
   1.660 +	evhttp_send_reply(req, HTTP_OK, "Everything is fine",
   1.661 +	    !empty ? evb : NULL);
   1.662 +
   1.663 +	evbuffer_free(evb);
   1.664 +}
   1.665 +
   1.666 +static void
   1.667 +http_delete_test(void *arg)
   1.668 +{
   1.669 +	struct basic_test_data *data = arg;
   1.670 +	struct bufferevent *bev;
   1.671 +	evutil_socket_t fd;
   1.672 +	const char *http_request;
   1.673 +	ev_uint16_t port = 0;
   1.674 +
   1.675 +	test_ok = 0;
   1.676 +
   1.677 +	http = http_setup(&port, data->base);
   1.678 +
   1.679 +	fd = http_connect("127.0.0.1", port);
   1.680 +
   1.681 +	/* Stupid thing to send a request */
   1.682 +	bev = bufferevent_socket_new(data->base, fd, 0);
   1.683 +	bufferevent_setcb(bev, http_readcb, http_writecb,
   1.684 +	    http_errorcb, data->base);
   1.685 +
   1.686 +	http_request =
   1.687 +	    "DELETE /deleteit HTTP/1.1\r\n"
   1.688 +	    "Host: somehost\r\n"
   1.689 +	    "Connection: close\r\n"
   1.690 +	    "\r\n";
   1.691 +
   1.692 +	bufferevent_write(bev, http_request, strlen(http_request));
   1.693 +
   1.694 +	event_base_dispatch(data->base);
   1.695 +
   1.696 +	bufferevent_free(bev);
   1.697 +	evutil_closesocket(fd);
   1.698 +
   1.699 +	evhttp_free(http);
   1.700 +
   1.701 +	tt_int_op(test_ok, ==, 2);
   1.702 + end:
   1.703 +	;
   1.704 +}
   1.705 +
   1.706 +static void
   1.707 +http_allowed_methods_eventcb(struct bufferevent *bev, short what, void *arg)
   1.708 +{
   1.709 +	char **output = arg;
   1.710 +	if ((what & (BEV_EVENT_ERROR|BEV_EVENT_EOF))) {
   1.711 +		char buf[4096];
   1.712 +		int n;
   1.713 +		n = evbuffer_remove(bufferevent_get_input(bev), buf,
   1.714 +		    sizeof(buf)-1);
   1.715 +		if (n >= 0) {
   1.716 +			buf[n]='\0';
   1.717 +			if (*output)
   1.718 +				free(*output);
   1.719 +			*output = strdup(buf);
   1.720 +		}
   1.721 +		event_base_loopexit(exit_base, NULL);
   1.722 +	}
   1.723 +}
   1.724 +
   1.725 +static void
   1.726 +http_allowed_methods_test(void *arg)
   1.727 +{
   1.728 +	struct basic_test_data *data = arg;
   1.729 +	struct bufferevent *bev1, *bev2, *bev3;
   1.730 +	evutil_socket_t fd1, fd2, fd3;
   1.731 +	const char *http_request;
   1.732 +	char *result1=NULL, *result2=NULL, *result3=NULL;
   1.733 +	ev_uint16_t port = 0;
   1.734 +
   1.735 +	exit_base = data->base;
   1.736 +	test_ok = 0;
   1.737 +
   1.738 +	http = http_setup(&port, data->base);
   1.739 +
   1.740 +	fd1 = http_connect("127.0.0.1", port);
   1.741 +
   1.742 +	/* GET is out; PATCH is in. */
   1.743 +	evhttp_set_allowed_methods(http, EVHTTP_REQ_PATCH);
   1.744 +
   1.745 +	/* Stupid thing to send a request */
   1.746 +	bev1 = bufferevent_socket_new(data->base, fd1, 0);
   1.747 +	bufferevent_enable(bev1, EV_READ|EV_WRITE);
   1.748 +	bufferevent_setcb(bev1, NULL, NULL,
   1.749 +	    http_allowed_methods_eventcb, &result1);
   1.750 +
   1.751 +	http_request =
   1.752 +	    "GET /index.html HTTP/1.1\r\n"
   1.753 +	    "Host: somehost\r\n"
   1.754 +	    "Connection: close\r\n"
   1.755 +	    "\r\n";
   1.756 +
   1.757 +	bufferevent_write(bev1, http_request, strlen(http_request));
   1.758 +
   1.759 +	event_base_dispatch(data->base);
   1.760 +
   1.761 +	fd2 = http_connect("127.0.0.1", port);
   1.762 +
   1.763 +	bev2 = bufferevent_socket_new(data->base, fd2, 0);
   1.764 +	bufferevent_enable(bev2, EV_READ|EV_WRITE);
   1.765 +	bufferevent_setcb(bev2, NULL, NULL,
   1.766 +	    http_allowed_methods_eventcb, &result2);
   1.767 +
   1.768 +	http_request =
   1.769 +	    "PATCH /test HTTP/1.1\r\n"
   1.770 +	    "Host: somehost\r\n"
   1.771 +	    "Connection: close\r\n"
   1.772 +	    "\r\n";
   1.773 +
   1.774 +	bufferevent_write(bev2, http_request, strlen(http_request));
   1.775 +
   1.776 +	event_base_dispatch(data->base);
   1.777 +
   1.778 +	fd3 = http_connect("127.0.0.1", port);
   1.779 +
   1.780 +	bev3 = bufferevent_socket_new(data->base, fd3, 0);
   1.781 +	bufferevent_enable(bev3, EV_READ|EV_WRITE);
   1.782 +	bufferevent_setcb(bev3, NULL, NULL,
   1.783 +	    http_allowed_methods_eventcb, &result3);
   1.784 +
   1.785 +	http_request =
   1.786 +	    "FLOOP /test HTTP/1.1\r\n"
   1.787 +	    "Host: somehost\r\n"
   1.788 +	    "Connection: close\r\n"
   1.789 +	    "\r\n";
   1.790 +
   1.791 +	bufferevent_write(bev3, http_request, strlen(http_request));
   1.792 +
   1.793 +	event_base_dispatch(data->base);
   1.794 +
   1.795 +	bufferevent_free(bev1);
   1.796 +	bufferevent_free(bev2);
   1.797 +	bufferevent_free(bev3);
   1.798 +	evutil_closesocket(fd1);
   1.799 +	evutil_closesocket(fd2);
   1.800 +	evutil_closesocket(fd3);
   1.801 +
   1.802 +	evhttp_free(http);
   1.803 +
   1.804 +	/* Method known but disallowed */
   1.805 +	tt_assert(result1);
   1.806 +	tt_assert(!strncmp(result1, "HTTP/1.1 501 ", strlen("HTTP/1.1 501 ")));
   1.807 +
   1.808 +	/* Method known and allowed */
   1.809 +	tt_assert(result2);
   1.810 +	tt_assert(!strncmp(result2, "HTTP/1.1 200 ", strlen("HTTP/1.1 200 ")));
   1.811 +
   1.812 +	/* Method unknown */
   1.813 +	tt_assert(result3);
   1.814 +	tt_assert(!strncmp(result3, "HTTP/1.1 501 ", strlen("HTTP/1.1 501 ")));
   1.815 +
   1.816 + end:
   1.817 +	if (result1)
   1.818 +		free(result1);
   1.819 +	if (result2)
   1.820 +		free(result2);
   1.821 +	if (result3)
   1.822 +		free(result3);
   1.823 +}
   1.824 +
   1.825 +static void http_request_done(struct evhttp_request *, void *);
   1.826 +static void http_request_empty_done(struct evhttp_request *, void *);
   1.827 +
   1.828 +static void
   1.829 +_http_connection_test(struct basic_test_data *data, int persistent)
   1.830 +{
   1.831 +	ev_uint16_t port = 0;
   1.832 +	struct evhttp_connection *evcon = NULL;
   1.833 +	struct evhttp_request *req = NULL;
   1.834 +
   1.835 +	test_ok = 0;
   1.836 +
   1.837 +	http = http_setup(&port, data->base);
   1.838 +
   1.839 +	evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port);
   1.840 +	tt_assert(evcon);
   1.841 +
   1.842 +	tt_assert(evhttp_connection_get_base(evcon) == data->base);
   1.843 +
   1.844 +	exit_base = data->base;
   1.845 +	/*
   1.846 +	 * At this point, we want to schedule a request to the HTTP
   1.847 +	 * server using our make request method.
   1.848 +	 */
   1.849 +
   1.850 +	req = evhttp_request_new(http_request_done, (void*) BASIC_REQUEST_BODY);
   1.851 +
   1.852 +	/* Add the information that we care about */
   1.853 +	evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
   1.854 +
   1.855 +	/* We give ownership of the request to the connection */
   1.856 +	if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test") == -1) {
   1.857 +		fprintf(stdout, "FAILED\n");
   1.858 +		exit(1);
   1.859 +	}
   1.860 +
   1.861 +	event_base_dispatch(data->base);
   1.862 +
   1.863 +	tt_assert(test_ok);
   1.864 +
   1.865 +	/* try to make another request over the same connection */
   1.866 +	test_ok = 0;
   1.867 +
   1.868 +	req = evhttp_request_new(http_request_done, (void*) BASIC_REQUEST_BODY);
   1.869 +
   1.870 +	/* Add the information that we care about */
   1.871 +	evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
   1.872 +
   1.873 +	/*
   1.874 +	 * if our connections are not supposed to be persistent; request
   1.875 +	 * a close from the server.
   1.876 +	 */
   1.877 +	if (!persistent)
   1.878 +		evhttp_add_header(evhttp_request_get_output_headers(req), "Connection", "close");
   1.879 +
   1.880 +	/* We give ownership of the request to the connection */
   1.881 +	if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test") == -1) {
   1.882 +		tt_abort_msg("couldn't make request");
   1.883 +	}
   1.884 +
   1.885 +	event_base_dispatch(data->base);
   1.886 +
   1.887 +	/* make another request: request empty reply */
   1.888 +	test_ok = 0;
   1.889 +
   1.890 +	req = evhttp_request_new(http_request_empty_done, data->base);
   1.891 +
   1.892 +	/* Add the information that we care about */
   1.893 +	evhttp_add_header(evhttp_request_get_output_headers(req), "Empty", "itis");
   1.894 +
   1.895 +	/* We give ownership of the request to the connection */
   1.896 +	if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test") == -1) {
   1.897 +		tt_abort_msg("Couldn't make request");
   1.898 +	}
   1.899 +
   1.900 +	event_base_dispatch(data->base);
   1.901 +
   1.902 + end:
   1.903 +	if (evcon)
   1.904 +		evhttp_connection_free(evcon);
   1.905 +	if (http)
   1.906 +		evhttp_free(http);
   1.907 +}
   1.908 +
   1.909 +static void
   1.910 +http_connection_test(void *arg)
   1.911 +{
   1.912 +	_http_connection_test(arg, 0);
   1.913 +}
   1.914 +static void
   1.915 +http_persist_connection_test(void *arg)
   1.916 +{
   1.917 +	_http_connection_test(arg, 1);
   1.918 +}
   1.919 +
   1.920 +static struct regress_dns_server_table search_table[] = {
   1.921 +	{ "localhost", "A", "127.0.0.1", 0 },
   1.922 +	{ NULL, NULL, NULL, 0 }
   1.923 +};
   1.924 +
   1.925 +static void
   1.926 +http_connection_async_test(void *arg)
   1.927 +{
   1.928 +	struct basic_test_data *data = arg;
   1.929 +	ev_uint16_t port = 0;
   1.930 +	struct evhttp_connection *evcon = NULL;
   1.931 +	struct evhttp_request *req = NULL;
   1.932 +	struct evdns_base *dns_base = NULL;
   1.933 +	ev_uint16_t portnum = 0;
   1.934 +	char address[64];
   1.935 +
   1.936 +	exit_base = data->base;
   1.937 +	tt_assert(regress_dnsserver(data->base, &portnum, search_table));
   1.938 +
   1.939 +	dns_base = evdns_base_new(data->base, 0/* init name servers */);
   1.940 +	tt_assert(dns_base);
   1.941 +
   1.942 +	/* Add ourself as the only nameserver, and make sure we really are
   1.943 +	 * the only nameserver. */
   1.944 +	evutil_snprintf(address, sizeof(address), "127.0.0.1:%d", portnum);
   1.945 +	evdns_base_nameserver_ip_add(dns_base, address);
   1.946 +
   1.947 +	test_ok = 0;
   1.948 +
   1.949 +	http = http_setup(&port, data->base);
   1.950 +
   1.951 +	evcon = evhttp_connection_base_new(data->base, dns_base, "127.0.0.1", port);
   1.952 +	tt_assert(evcon);
   1.953 +
   1.954 +	/*
   1.955 +	 * At this point, we want to schedule a request to the HTTP
   1.956 +	 * server using our make request method.
   1.957 +	 */
   1.958 +
   1.959 +	req = evhttp_request_new(http_request_done, (void*) BASIC_REQUEST_BODY);
   1.960 +
   1.961 +	/* Add the information that we care about */
   1.962 +	evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
   1.963 +
   1.964 +	/* We give ownership of the request to the connection */
   1.965 +	if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test") == -1) {
   1.966 +		fprintf(stdout, "FAILED\n");
   1.967 +		exit(1);
   1.968 +	}
   1.969 +
   1.970 +	event_base_dispatch(data->base);
   1.971 +
   1.972 +	tt_assert(test_ok);
   1.973 +
   1.974 +	/* try to make another request over the same connection */
   1.975 +	test_ok = 0;
   1.976 +
   1.977 +	req = evhttp_request_new(http_request_done, (void*) BASIC_REQUEST_BODY);
   1.978 +
   1.979 +	/* Add the information that we care about */
   1.980 +	evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
   1.981 +
   1.982 +	/*
   1.983 +	 * if our connections are not supposed to be persistent; request
   1.984 +	 * a close from the server.
   1.985 +	 */
   1.986 +	evhttp_add_header(evhttp_request_get_output_headers(req), "Connection", "close");
   1.987 +
   1.988 +	/* We give ownership of the request to the connection */
   1.989 +	if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test") == -1) {
   1.990 +		tt_abort_msg("couldn't make request");
   1.991 +	}
   1.992 +
   1.993 +	event_base_dispatch(data->base);
   1.994 +
   1.995 +	/* make another request: request empty reply */
   1.996 +	test_ok = 0;
   1.997 +
   1.998 +	req = evhttp_request_new(http_request_empty_done, data->base);
   1.999 +
  1.1000 +	/* Add the information that we care about */
  1.1001 +	evhttp_add_header(evhttp_request_get_output_headers(req), "Empty", "itis");
  1.1002 +
  1.1003 +	/* We give ownership of the request to the connection */
  1.1004 +	if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test") == -1) {
  1.1005 +		tt_abort_msg("Couldn't make request");
  1.1006 +	}
  1.1007 +
  1.1008 +	event_base_dispatch(data->base);
  1.1009 +
  1.1010 + end:
  1.1011 +	if (evcon)
  1.1012 +		evhttp_connection_free(evcon);
  1.1013 +	if (http)
  1.1014 +		evhttp_free(http);
  1.1015 +	if (dns_base)
  1.1016 +		evdns_base_free(dns_base, 0);
  1.1017 +	regress_clean_dnsserver();
  1.1018 +}
  1.1019 +
  1.1020 +static void
  1.1021 +http_request_never_call(struct evhttp_request *req, void *arg)
  1.1022 +{
  1.1023 +	fprintf(stdout, "FAILED\n");
  1.1024 +	exit(1);
  1.1025 +}
  1.1026 +
  1.1027 +static void
  1.1028 +http_do_cancel(evutil_socket_t fd, short what, void *arg)
  1.1029 +{
  1.1030 +	struct evhttp_request *req = arg;
  1.1031 +	struct timeval tv;
  1.1032 +	struct event_base *base;
  1.1033 +	evutil_timerclear(&tv);
  1.1034 +	tv.tv_sec = 0;
  1.1035 +	tv.tv_usec = 500 * 1000;
  1.1036 +
  1.1037 +	base = evhttp_connection_get_base(evhttp_request_get_connection(req));
  1.1038 +	evhttp_cancel_request(req);
  1.1039 +
  1.1040 +	event_base_loopexit(base, &tv);
  1.1041 +
  1.1042 +	++test_ok;
  1.1043 +}
  1.1044 +
  1.1045 +static void
  1.1046 +http_cancel_test(void *arg)
  1.1047 +{
  1.1048 +	struct basic_test_data *data = arg;
  1.1049 +	ev_uint16_t port = 0;
  1.1050 +	struct evhttp_connection *evcon = NULL;
  1.1051 +	struct evhttp_request *req = NULL;
  1.1052 +	struct timeval tv;
  1.1053 +
  1.1054 +	exit_base = data->base;
  1.1055 +
  1.1056 +	test_ok = 0;
  1.1057 +
  1.1058 +	http = http_setup(&port, data->base);
  1.1059 +
  1.1060 +	evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port);
  1.1061 +	tt_assert(evcon);
  1.1062 +
  1.1063 +	/*
  1.1064 +	 * At this point, we want to schedule a request to the HTTP
  1.1065 +	 * server using our make request method.
  1.1066 +	 */
  1.1067 +
  1.1068 +	req = evhttp_request_new(http_request_never_call, NULL);
  1.1069 +
  1.1070 +	/* Add the information that we care about */
  1.1071 +	evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
  1.1072 +
  1.1073 +	/* We give ownership of the request to the connection */
  1.1074 +	tt_int_op(evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/delay"),
  1.1075 +		  !=, -1);
  1.1076 +
  1.1077 +	evutil_timerclear(&tv);
  1.1078 +	tv.tv_sec = 0;
  1.1079 +	tv.tv_usec = 100 * 1000;
  1.1080 +
  1.1081 +	event_base_once(data->base, -1, EV_TIMEOUT, http_do_cancel, req, &tv);
  1.1082 +
  1.1083 +	event_base_dispatch(data->base);
  1.1084 +
  1.1085 +	tt_int_op(test_ok, ==, 2);
  1.1086 +
  1.1087 +	/* try to make another request over the same connection */
  1.1088 +	test_ok = 0;
  1.1089 +
  1.1090 +	req = evhttp_request_new(http_request_done, (void*) BASIC_REQUEST_BODY);
  1.1091 +
  1.1092 +	/* Add the information that we care about */
  1.1093 +	evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
  1.1094 +
  1.1095 +	/* We give ownership of the request to the connection */
  1.1096 +	tt_int_op(evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test"),
  1.1097 +		  !=, -1);
  1.1098 +
  1.1099 +	event_base_dispatch(data->base);
  1.1100 +
  1.1101 +	/* make another request: request empty reply */
  1.1102 +	test_ok = 0;
  1.1103 +
  1.1104 +	req = evhttp_request_new(http_request_empty_done, data->base);
  1.1105 +
  1.1106 +	/* Add the information that we care about */
  1.1107 +	evhttp_add_header(evhttp_request_get_output_headers(req), "Empty", "itis");
  1.1108 +
  1.1109 +	/* We give ownership of the request to the connection */
  1.1110 +	tt_int_op(evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test"),
  1.1111 +		  !=, -1);
  1.1112 +
  1.1113 +	event_base_dispatch(data->base);
  1.1114 +
  1.1115 + end:
  1.1116 +	if (evcon)
  1.1117 +		evhttp_connection_free(evcon);
  1.1118 +	if (http)
  1.1119 +		evhttp_free(http);
  1.1120 +}
  1.1121 +
  1.1122 +static void
  1.1123 +http_request_done(struct evhttp_request *req, void *arg)
  1.1124 +{
  1.1125 +	const char *what = arg;
  1.1126 +
  1.1127 +	if (evhttp_request_get_response_code(req) != HTTP_OK) {
  1.1128 +		fprintf(stderr, "FAILED\n");
  1.1129 +		exit(1);
  1.1130 +	}
  1.1131 +
  1.1132 +	if (evhttp_find_header(evhttp_request_get_input_headers(req), "Content-Type") == NULL) {
  1.1133 +		fprintf(stderr, "FAILED\n");
  1.1134 +		exit(1);
  1.1135 +	}
  1.1136 +
  1.1137 +	if (evbuffer_get_length(evhttp_request_get_input_buffer(req)) != strlen(what)) {
  1.1138 +		fprintf(stderr, "FAILED\n");
  1.1139 +		exit(1);
  1.1140 +	}
  1.1141 +
  1.1142 +	if (evbuffer_datacmp(evhttp_request_get_input_buffer(req), what) != 0) {
  1.1143 +		fprintf(stderr, "FAILED\n");
  1.1144 +		exit(1);
  1.1145 +	}
  1.1146 +
  1.1147 +	test_ok = 1;
  1.1148 +	EVUTIL_ASSERT(exit_base);
  1.1149 +	event_base_loopexit(exit_base, NULL);
  1.1150 +}
  1.1151 +
  1.1152 +static void
  1.1153 +http_request_expect_error(struct evhttp_request *req, void *arg)
  1.1154 +{
  1.1155 +	if (evhttp_request_get_response_code(req) == HTTP_OK) {
  1.1156 +		fprintf(stderr, "FAILED\n");
  1.1157 +		exit(1);
  1.1158 +	}
  1.1159 +
  1.1160 +	test_ok = 1;
  1.1161 +	EVUTIL_ASSERT(arg);
  1.1162 +	event_base_loopexit(arg, NULL);
  1.1163 +}
  1.1164 +
  1.1165 +/* test virtual hosts */
  1.1166 +static void
  1.1167 +http_virtual_host_test(void *arg)
  1.1168 +{
  1.1169 +	struct basic_test_data *data = arg;
  1.1170 +	ev_uint16_t port = 0;
  1.1171 +	struct evhttp_connection *evcon = NULL;
  1.1172 +	struct evhttp_request *req = NULL;
  1.1173 +	struct evhttp *second = NULL, *third = NULL;
  1.1174 +	evutil_socket_t fd;
  1.1175 +	struct bufferevent *bev;
  1.1176 +	const char *http_request;
  1.1177 +
  1.1178 +	exit_base = data->base;
  1.1179 +
  1.1180 +	http = http_setup(&port, data->base);
  1.1181 +
  1.1182 +	/* virtual host */
  1.1183 +	second = evhttp_new(NULL);
  1.1184 +	evhttp_set_cb(second, "/funnybunny", http_basic_cb, NULL);
  1.1185 +	third = evhttp_new(NULL);
  1.1186 +	evhttp_set_cb(third, "/blackcoffee", http_basic_cb, NULL);
  1.1187 +
  1.1188 +	if (evhttp_add_virtual_host(http, "foo.com", second) == -1) {
  1.1189 +		tt_abort_msg("Couldn't add vhost");
  1.1190 +	}
  1.1191 +
  1.1192 +	if (evhttp_add_virtual_host(http, "bar.*.foo.com", third) == -1) {
  1.1193 +		tt_abort_msg("Couldn't add wildcarded vhost");
  1.1194 +	}
  1.1195 +
  1.1196 +	/* add some aliases to the vhosts */
  1.1197 +	tt_assert(evhttp_add_server_alias(second, "manolito.info") == 0);
  1.1198 +	tt_assert(evhttp_add_server_alias(third, "bonkers.org") == 0);
  1.1199 +
  1.1200 +	evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port);
  1.1201 +	tt_assert(evcon);
  1.1202 +
  1.1203 +	/* make a request with a different host and expect an error */
  1.1204 +	req = evhttp_request_new(http_request_expect_error, data->base);
  1.1205 +
  1.1206 +	/* Add the information that we care about */
  1.1207 +	evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
  1.1208 +
  1.1209 +	/* We give ownership of the request to the connection */
  1.1210 +	if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET,
  1.1211 +		"/funnybunny") == -1) {
  1.1212 +		tt_abort_msg("Couldn't make request");
  1.1213 +	}
  1.1214 +
  1.1215 +	event_base_dispatch(data->base);
  1.1216 +
  1.1217 +	tt_assert(test_ok == 1);
  1.1218 +
  1.1219 +	test_ok = 0;
  1.1220 +
  1.1221 +	/* make a request with the right host and expect a response */
  1.1222 +	req = evhttp_request_new(http_request_done, (void*) BASIC_REQUEST_BODY);
  1.1223 +
  1.1224 +	/* Add the information that we care about */
  1.1225 +	evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "foo.com");
  1.1226 +
  1.1227 +	/* We give ownership of the request to the connection */
  1.1228 +	if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET,
  1.1229 +		"/funnybunny") == -1) {
  1.1230 +		fprintf(stdout, "FAILED\n");
  1.1231 +		exit(1);
  1.1232 +	}
  1.1233 +
  1.1234 +	event_base_dispatch(data->base);
  1.1235 +
  1.1236 +	tt_assert(test_ok == 1);
  1.1237 +
  1.1238 +	test_ok = 0;
  1.1239 +
  1.1240 +	/* make a request with the right host and expect a response */
  1.1241 +	req = evhttp_request_new(http_request_done, (void*) BASIC_REQUEST_BODY);
  1.1242 +
  1.1243 +	/* Add the information that we care about */
  1.1244 +	evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "bar.magic.foo.com");
  1.1245 +
  1.1246 +	/* We give ownership of the request to the connection */
  1.1247 +	if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET,
  1.1248 +		"/blackcoffee") == -1) {
  1.1249 +		tt_abort_msg("Couldn't make request");
  1.1250 +	}
  1.1251 +
  1.1252 +	event_base_dispatch(data->base);
  1.1253 +
  1.1254 +	tt_assert(test_ok == 1)
  1.1255 +
  1.1256 +	test_ok = 0;
  1.1257 +
  1.1258 +	/* make a request with the right host and expect a response */
  1.1259 +	req = evhttp_request_new(http_request_done, (void*) BASIC_REQUEST_BODY);
  1.1260 +
  1.1261 +	/* Add the information that we care about */
  1.1262 +	evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "manolito.info");
  1.1263 +
  1.1264 +	/* We give ownership of the request to the connection */
  1.1265 +	if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET,
  1.1266 +		"/funnybunny") == -1) {
  1.1267 +		tt_abort_msg("Couldn't make request");
  1.1268 +	}
  1.1269 +
  1.1270 +	event_base_dispatch(data->base);
  1.1271 +
  1.1272 +	tt_assert(test_ok == 1)
  1.1273 +
  1.1274 +	test_ok = 0;
  1.1275 +
  1.1276 +	/* make a request with the right host and expect a response */
  1.1277 +	req = evhttp_request_new(http_request_done, (void*) BASIC_REQUEST_BODY);
  1.1278 +
  1.1279 +	/* Add the Host header. This time with the optional port. */
  1.1280 +	evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "bonkers.org:8000");
  1.1281 +
  1.1282 +	/* We give ownership of the request to the connection */
  1.1283 +	if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET,
  1.1284 +		"/blackcoffee") == -1) {
  1.1285 +		tt_abort_msg("Couldn't make request");
  1.1286 +	}
  1.1287 +
  1.1288 +	event_base_dispatch(data->base);
  1.1289 +
  1.1290 +	tt_assert(test_ok == 1)
  1.1291 +
  1.1292 +	test_ok = 0;
  1.1293 +
  1.1294 +	/* Now make a raw request with an absolute URI. */
  1.1295 +	fd = http_connect("127.0.0.1", port);
  1.1296 +
  1.1297 +	/* Stupid thing to send a request */
  1.1298 +	bev = bufferevent_socket_new(data->base, fd, 0);
  1.1299 +	bufferevent_setcb(bev, http_readcb, http_writecb,
  1.1300 +	    http_errorcb, NULL);
  1.1301 +
  1.1302 +	/* The host in the URI should override the Host: header */
  1.1303 +	http_request =
  1.1304 +	    "GET http://manolito.info/funnybunny HTTP/1.1\r\n"
  1.1305 +	    "Host: somehost\r\n"
  1.1306 +	    "Connection: close\r\n"
  1.1307 +	    "\r\n";
  1.1308 +
  1.1309 +	bufferevent_write(bev, http_request, strlen(http_request));
  1.1310 +
  1.1311 +	event_base_dispatch(data->base);
  1.1312 +
  1.1313 +	tt_int_op(test_ok, ==, 2);
  1.1314 +
  1.1315 +	bufferevent_free(bev);
  1.1316 +	evutil_closesocket(fd);
  1.1317 +
  1.1318 + end:
  1.1319 +	if (evcon)
  1.1320 +		evhttp_connection_free(evcon);
  1.1321 +	if (http)
  1.1322 +		evhttp_free(http);
  1.1323 +}
  1.1324 +
  1.1325 +
  1.1326 +/* test date header and content length */
  1.1327 +
  1.1328 +static void
  1.1329 +http_request_empty_done(struct evhttp_request *req, void *arg)
  1.1330 +{
  1.1331 +	if (evhttp_request_get_response_code(req) != HTTP_OK) {
  1.1332 +		fprintf(stderr, "FAILED\n");
  1.1333 +		exit(1);
  1.1334 +	}
  1.1335 +
  1.1336 +	if (evhttp_find_header(evhttp_request_get_input_headers(req), "Date") == NULL) {
  1.1337 +		fprintf(stderr, "FAILED\n");
  1.1338 +		exit(1);
  1.1339 +	}
  1.1340 +
  1.1341 +
  1.1342 +	if (evhttp_find_header(evhttp_request_get_input_headers(req), "Content-Length") == NULL) {
  1.1343 +		fprintf(stderr, "FAILED\n");
  1.1344 +		exit(1);
  1.1345 +	}
  1.1346 +
  1.1347 +	if (strcmp(evhttp_find_header(evhttp_request_get_input_headers(req), "Content-Length"),
  1.1348 +		"0")) {
  1.1349 +		fprintf(stderr, "FAILED\n");
  1.1350 +		exit(1);
  1.1351 +	}
  1.1352 +
  1.1353 +	if (evbuffer_get_length(evhttp_request_get_input_buffer(req)) != 0) {
  1.1354 +		fprintf(stderr, "FAILED\n");
  1.1355 +		exit(1);
  1.1356 +	}
  1.1357 +
  1.1358 +	test_ok = 1;
  1.1359 +	EVUTIL_ASSERT(arg);
  1.1360 +	event_base_loopexit(arg, NULL);
  1.1361 +}
  1.1362 +
  1.1363 +/*
  1.1364 + * HTTP DISPATCHER test
  1.1365 + */
  1.1366 +
  1.1367 +void
  1.1368 +http_dispatcher_cb(struct evhttp_request *req, void *arg)
  1.1369 +{
  1.1370 +
  1.1371 +	struct evbuffer *evb = evbuffer_new();
  1.1372 +	event_debug(("%s: called\n", __func__));
  1.1373 +	evbuffer_add_printf(evb, "DISPATCHER_TEST");
  1.1374 +
  1.1375 +	evhttp_send_reply(req, HTTP_OK, "Everything is fine", evb);
  1.1376 +
  1.1377 +	evbuffer_free(evb);
  1.1378 +}
  1.1379 +
  1.1380 +static void
  1.1381 +http_dispatcher_test_done(struct evhttp_request *req, void *arg)
  1.1382 +{
  1.1383 +	struct event_base *base = arg;
  1.1384 +	const char *what = "DISPATCHER_TEST";
  1.1385 +
  1.1386 +	if (evhttp_request_get_response_code(req) != HTTP_OK) {
  1.1387 +		fprintf(stderr, "FAILED\n");
  1.1388 +		exit(1);
  1.1389 +	}
  1.1390 +
  1.1391 +	if (evhttp_find_header(evhttp_request_get_input_headers(req), "Content-Type") == NULL) {
  1.1392 +		fprintf(stderr, "FAILED (content type)\n");
  1.1393 +		exit(1);
  1.1394 +	}
  1.1395 +
  1.1396 +	if (evbuffer_get_length(evhttp_request_get_input_buffer(req)) != strlen(what)) {
  1.1397 +		fprintf(stderr, "FAILED (length %lu vs %lu)\n",
  1.1398 +		    (unsigned long)evbuffer_get_length(evhttp_request_get_input_buffer(req)), (unsigned long)strlen(what));
  1.1399 +		exit(1);
  1.1400 +	}
  1.1401 +
  1.1402 +	if (evbuffer_datacmp(evhttp_request_get_input_buffer(req), what) != 0) {
  1.1403 +		fprintf(stderr, "FAILED (data)\n");
  1.1404 +		exit(1);
  1.1405 +	}
  1.1406 +
  1.1407 +	test_ok = 1;
  1.1408 +	event_base_loopexit(base, NULL);
  1.1409 +}
  1.1410 +
  1.1411 +static void
  1.1412 +http_dispatcher_test(void *arg)
  1.1413 +{
  1.1414 +	struct basic_test_data *data = arg;
  1.1415 +	ev_uint16_t port = 0;
  1.1416 +	struct evhttp_connection *evcon = NULL;
  1.1417 +	struct evhttp_request *req = NULL;
  1.1418 +
  1.1419 +	test_ok = 0;
  1.1420 +
  1.1421 +	http = http_setup(&port, data->base);
  1.1422 +
  1.1423 +	evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port);
  1.1424 +	tt_assert(evcon);
  1.1425 +
  1.1426 +	/* also bind to local host */
  1.1427 +	evhttp_connection_set_local_address(evcon, "127.0.0.1");
  1.1428 +
  1.1429 +	/*
  1.1430 +	 * At this point, we want to schedule an HTTP GET request
  1.1431 +	 * server using our make request method.
  1.1432 +	 */
  1.1433 +
  1.1434 +	req = evhttp_request_new(http_dispatcher_test_done, data->base);
  1.1435 +	tt_assert(req);
  1.1436 +
  1.1437 +	/* Add the information that we care about */
  1.1438 +	evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
  1.1439 +
  1.1440 +	if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/?arg=val") == -1) {
  1.1441 +		tt_abort_msg("Couldn't make request");
  1.1442 +	}
  1.1443 +
  1.1444 +	event_base_dispatch(data->base);
  1.1445 +
  1.1446 + end:
  1.1447 +	if (evcon)
  1.1448 +		evhttp_connection_free(evcon);
  1.1449 +	if (http)
  1.1450 +		evhttp_free(http);
  1.1451 +}
  1.1452 +
  1.1453 +/*
  1.1454 + * HTTP POST test.
  1.1455 + */
  1.1456 +
  1.1457 +void http_postrequest_done(struct evhttp_request *, void *);
  1.1458 +
  1.1459 +#define POST_DATA "Okay.  Not really printf"
  1.1460 +
  1.1461 +static void
  1.1462 +http_post_test(void *arg)
  1.1463 +{
  1.1464 +	struct basic_test_data *data = arg;
  1.1465 +	ev_uint16_t port = 0;
  1.1466 +	struct evhttp_connection *evcon = NULL;
  1.1467 +	struct evhttp_request *req = NULL;
  1.1468 +
  1.1469 +	test_ok = 0;
  1.1470 +
  1.1471 +	http = http_setup(&port, data->base);
  1.1472 +
  1.1473 +	evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port);
  1.1474 +	tt_assert(evcon);
  1.1475 +
  1.1476 +	/*
  1.1477 +	 * At this point, we want to schedule an HTTP POST request
  1.1478 +	 * server using our make request method.
  1.1479 +	 */
  1.1480 +
  1.1481 +	req = evhttp_request_new(http_postrequest_done, data->base);
  1.1482 +	tt_assert(req);
  1.1483 +
  1.1484 +	/* Add the information that we care about */
  1.1485 +	evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
  1.1486 +	evbuffer_add_printf(evhttp_request_get_output_buffer(req), POST_DATA);
  1.1487 +
  1.1488 +	if (evhttp_make_request(evcon, req, EVHTTP_REQ_POST, "/postit") == -1) {
  1.1489 +		tt_abort_msg("Couldn't make request");
  1.1490 +	}
  1.1491 +
  1.1492 +	event_base_dispatch(data->base);
  1.1493 +
  1.1494 +	tt_int_op(test_ok, ==, 1);
  1.1495 +
  1.1496 +	test_ok = 0;
  1.1497 +
  1.1498 +	req = evhttp_request_new(http_postrequest_done, data->base);
  1.1499 +	tt_assert(req);
  1.1500 +
  1.1501 +	/* Now try with 100-continue. */
  1.1502 +
  1.1503 +	/* Add the information that we care about */
  1.1504 +	evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
  1.1505 +	evhttp_add_header(evhttp_request_get_output_headers(req), "Expect", "100-continue");
  1.1506 +	evbuffer_add_printf(evhttp_request_get_output_buffer(req), POST_DATA);
  1.1507 +
  1.1508 +	if (evhttp_make_request(evcon, req, EVHTTP_REQ_POST, "/postit") == -1) {
  1.1509 +		tt_abort_msg("Couldn't make request");
  1.1510 +	}
  1.1511 +
  1.1512 +	event_base_dispatch(data->base);
  1.1513 +
  1.1514 +	tt_int_op(test_ok, ==, 1);
  1.1515 +
  1.1516 +	evhttp_connection_free(evcon);
  1.1517 +	evhttp_free(http);
  1.1518 +
  1.1519 + end:
  1.1520 +	;
  1.1521 +}
  1.1522 +
  1.1523 +void
  1.1524 +http_post_cb(struct evhttp_request *req, void *arg)
  1.1525 +{
  1.1526 +	struct evbuffer *evb;
  1.1527 +	event_debug(("%s: called\n", __func__));
  1.1528 +
  1.1529 +	/* Yes, we are expecting a post request */
  1.1530 +	if (evhttp_request_get_command(req) != EVHTTP_REQ_POST) {
  1.1531 +		fprintf(stdout, "FAILED (post type)\n");
  1.1532 +		exit(1);
  1.1533 +	}
  1.1534 +
  1.1535 +	if (evbuffer_get_length(evhttp_request_get_input_buffer(req)) != strlen(POST_DATA)) {
  1.1536 +		fprintf(stdout, "FAILED (length: %lu vs %lu)\n",
  1.1537 +		    (unsigned long) evbuffer_get_length(evhttp_request_get_input_buffer(req)), (unsigned long) strlen(POST_DATA));
  1.1538 +		exit(1);
  1.1539 +	}
  1.1540 +
  1.1541 +	if (evbuffer_datacmp(evhttp_request_get_input_buffer(req), POST_DATA) != 0) {
  1.1542 +		fprintf(stdout, "FAILED (data)\n");
  1.1543 +		fprintf(stdout, "Got :%s\n", evbuffer_pullup(evhttp_request_get_input_buffer(req),-1));
  1.1544 +		fprintf(stdout, "Want:%s\n", POST_DATA);
  1.1545 +		exit(1);
  1.1546 +	}
  1.1547 +
  1.1548 +	evb = evbuffer_new();
  1.1549 +	evbuffer_add_printf(evb, BASIC_REQUEST_BODY);
  1.1550 +
  1.1551 +	evhttp_send_reply(req, HTTP_OK, "Everything is fine", evb);
  1.1552 +
  1.1553 +	evbuffer_free(evb);
  1.1554 +}
  1.1555 +
  1.1556 +void
  1.1557 +http_postrequest_done(struct evhttp_request *req, void *arg)
  1.1558 +{
  1.1559 +	const char *what = BASIC_REQUEST_BODY;
  1.1560 +	struct event_base *base = arg;
  1.1561 +
  1.1562 +	if (req == NULL) {
  1.1563 +		fprintf(stderr, "FAILED (timeout)\n");
  1.1564 +		exit(1);
  1.1565 +	}
  1.1566 +
  1.1567 +	if (evhttp_request_get_response_code(req) != HTTP_OK) {
  1.1568 +
  1.1569 +		fprintf(stderr, "FAILED (response code)\n");
  1.1570 +		exit(1);
  1.1571 +	}
  1.1572 +
  1.1573 +	if (evhttp_find_header(evhttp_request_get_input_headers(req), "Content-Type") == NULL) {
  1.1574 +		fprintf(stderr, "FAILED (content type)\n");
  1.1575 +		exit(1);
  1.1576 +	}
  1.1577 +
  1.1578 +	if (evbuffer_get_length(evhttp_request_get_input_buffer(req)) != strlen(what)) {
  1.1579 +		fprintf(stderr, "FAILED (length %lu vs %lu)\n",
  1.1580 +		    (unsigned long)evbuffer_get_length(evhttp_request_get_input_buffer(req)), (unsigned long)strlen(what));
  1.1581 +		exit(1);
  1.1582 +	}
  1.1583 +
  1.1584 +	if (evbuffer_datacmp(evhttp_request_get_input_buffer(req), what) != 0) {
  1.1585 +		fprintf(stderr, "FAILED (data)\n");
  1.1586 +		exit(1);
  1.1587 +	}
  1.1588 +
  1.1589 +	test_ok = 1;
  1.1590 +	event_base_loopexit(base, NULL);
  1.1591 +}
  1.1592 +
  1.1593 +/*
  1.1594 + * HTTP PUT test, basically just like POST, but ...
  1.1595 + */
  1.1596 +
  1.1597 +void http_putrequest_done(struct evhttp_request *, void *);
  1.1598 +
  1.1599 +#define PUT_DATA "Hi, I'm some PUT data"
  1.1600 +
  1.1601 +static void
  1.1602 +http_put_test(void *arg)
  1.1603 +{
  1.1604 +	struct basic_test_data *data = arg;
  1.1605 +	ev_uint16_t port = 0;
  1.1606 +	struct evhttp_connection *evcon = NULL;
  1.1607 +	struct evhttp_request *req = NULL;
  1.1608 +
  1.1609 +	test_ok = 0;
  1.1610 +
  1.1611 +	http = http_setup(&port, data->base);
  1.1612 +
  1.1613 +	evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port);
  1.1614 +	tt_assert(evcon);
  1.1615 +
  1.1616 +	/*
  1.1617 +	 * Schedule the HTTP PUT request
  1.1618 +	 */
  1.1619 +
  1.1620 +	req = evhttp_request_new(http_putrequest_done, data->base);
  1.1621 +	tt_assert(req);
  1.1622 +
  1.1623 +	/* Add the information that we care about */
  1.1624 +	evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "someotherhost");
  1.1625 +	evbuffer_add_printf(evhttp_request_get_output_buffer(req), PUT_DATA);
  1.1626 +
  1.1627 +	if (evhttp_make_request(evcon, req, EVHTTP_REQ_PUT, "/putit") == -1) {
  1.1628 +		tt_abort_msg("Couldn't make request");
  1.1629 +	}
  1.1630 +
  1.1631 +	event_base_dispatch(data->base);
  1.1632 +
  1.1633 +	evhttp_connection_free(evcon);
  1.1634 +	evhttp_free(http);
  1.1635 +
  1.1636 +	tt_int_op(test_ok, ==, 1);
  1.1637 + end:
  1.1638 +	;
  1.1639 +}
  1.1640 +
  1.1641 +void
  1.1642 +http_put_cb(struct evhttp_request *req, void *arg)
  1.1643 +{
  1.1644 +	struct evbuffer *evb;
  1.1645 +	event_debug(("%s: called\n", __func__));
  1.1646 +
  1.1647 +	/* Expecting a PUT request */
  1.1648 +	if (evhttp_request_get_command(req) != EVHTTP_REQ_PUT) {
  1.1649 +		fprintf(stdout, "FAILED (put type)\n");
  1.1650 +		exit(1);
  1.1651 +	}
  1.1652 +
  1.1653 +	if (evbuffer_get_length(evhttp_request_get_input_buffer(req)) != strlen(PUT_DATA)) {
  1.1654 +		fprintf(stdout, "FAILED (length: %lu vs %lu)\n",
  1.1655 +		    (unsigned long)evbuffer_get_length(evhttp_request_get_input_buffer(req)), (unsigned long)strlen(PUT_DATA));
  1.1656 +		exit(1);
  1.1657 +	}
  1.1658 +
  1.1659 +	if (evbuffer_datacmp(evhttp_request_get_input_buffer(req), PUT_DATA) != 0) {
  1.1660 +		fprintf(stdout, "FAILED (data)\n");
  1.1661 +		fprintf(stdout, "Got :%s\n", evbuffer_pullup(evhttp_request_get_input_buffer(req),-1));
  1.1662 +		fprintf(stdout, "Want:%s\n", PUT_DATA);
  1.1663 +		exit(1);
  1.1664 +	}
  1.1665 +
  1.1666 +	evb = evbuffer_new();
  1.1667 +	evbuffer_add_printf(evb, "That ain't funny");
  1.1668 +
  1.1669 +	evhttp_send_reply(req, HTTP_OK, "Everything is great", evb);
  1.1670 +
  1.1671 +	evbuffer_free(evb);
  1.1672 +}
  1.1673 +
  1.1674 +void
  1.1675 +http_putrequest_done(struct evhttp_request *req, void *arg)
  1.1676 +{
  1.1677 +	struct event_base *base = arg;
  1.1678 +	const char *what = "That ain't funny";
  1.1679 +
  1.1680 +	if (req == NULL) {
  1.1681 +		fprintf(stderr, "FAILED (timeout)\n");
  1.1682 +		exit(1);
  1.1683 +	}
  1.1684 +
  1.1685 +	if (evhttp_request_get_response_code(req) != HTTP_OK) {
  1.1686 +
  1.1687 +		fprintf(stderr, "FAILED (response code)\n");
  1.1688 +		exit(1);
  1.1689 +	}
  1.1690 +
  1.1691 +	if (evhttp_find_header(evhttp_request_get_input_headers(req), "Content-Type") == NULL) {
  1.1692 +		fprintf(stderr, "FAILED (content type)\n");
  1.1693 +		exit(1);
  1.1694 +	}
  1.1695 +
  1.1696 +	if (evbuffer_get_length(evhttp_request_get_input_buffer(req)) != strlen(what)) {
  1.1697 +		fprintf(stderr, "FAILED (length %lu vs %lu)\n",
  1.1698 +		    (unsigned long)evbuffer_get_length(evhttp_request_get_input_buffer(req)), (unsigned long)strlen(what));
  1.1699 +		exit(1);
  1.1700 +	}
  1.1701 +
  1.1702 +
  1.1703 +	if (evbuffer_datacmp(evhttp_request_get_input_buffer(req), what) != 0) {
  1.1704 +		fprintf(stderr, "FAILED (data)\n");
  1.1705 +		exit(1);
  1.1706 +	}
  1.1707 +
  1.1708 +	test_ok = 1;
  1.1709 +	event_base_loopexit(base, NULL);
  1.1710 +}
  1.1711 +
  1.1712 +static void
  1.1713 +http_failure_readcb(struct bufferevent *bev, void *arg)
  1.1714 +{
  1.1715 +	const char *what = "400 Bad Request";
  1.1716 +	if (evbuffer_contains(bufferevent_get_input(bev), what)) {
  1.1717 +		test_ok = 2;
  1.1718 +		bufferevent_disable(bev, EV_READ);
  1.1719 +		event_base_loopexit(arg, NULL);
  1.1720 +	}
  1.1721 +}
  1.1722 +
  1.1723 +/*
  1.1724 + * Testing that the HTTP server can deal with a malformed request.
  1.1725 + */
  1.1726 +static void
  1.1727 +http_failure_test(void *arg)
  1.1728 +{
  1.1729 +	struct basic_test_data *data = arg;
  1.1730 +	struct bufferevent *bev;
  1.1731 +	evutil_socket_t fd;
  1.1732 +	const char *http_request;
  1.1733 +	ev_uint16_t port = 0;
  1.1734 +
  1.1735 +	test_ok = 0;
  1.1736 +
  1.1737 +	http = http_setup(&port, data->base);
  1.1738 +
  1.1739 +	fd = http_connect("127.0.0.1", port);
  1.1740 +
  1.1741 +	/* Stupid thing to send a request */
  1.1742 +	bev = bufferevent_socket_new(data->base, fd, 0);
  1.1743 +	bufferevent_setcb(bev, http_failure_readcb, http_writecb,
  1.1744 +	    http_errorcb, data->base);
  1.1745 +
  1.1746 +	http_request = "illegal request\r\n";
  1.1747 +
  1.1748 +	bufferevent_write(bev, http_request, strlen(http_request));
  1.1749 +
  1.1750 +	event_base_dispatch(data->base);
  1.1751 +
  1.1752 +	bufferevent_free(bev);
  1.1753 +	evutil_closesocket(fd);
  1.1754 +
  1.1755 +	evhttp_free(http);
  1.1756 +
  1.1757 +	tt_int_op(test_ok, ==, 2);
  1.1758 + end:
  1.1759 +	;
  1.1760 +}
  1.1761 +
  1.1762 +static void
  1.1763 +close_detect_done(struct evhttp_request *req, void *arg)
  1.1764 +{
  1.1765 +	struct timeval tv;
  1.1766 +	tt_assert(req);
  1.1767 +	tt_assert(evhttp_request_get_response_code(req) == HTTP_OK);
  1.1768 +
  1.1769 +	test_ok = 1;
  1.1770 +
  1.1771 + end:
  1.1772 +	evutil_timerclear(&tv);
  1.1773 +	tv.tv_sec = 3;
  1.1774 +	event_base_loopexit(arg, &tv);
  1.1775 +}
  1.1776 +
  1.1777 +static void
  1.1778 +close_detect_launch(evutil_socket_t fd, short what, void *arg)
  1.1779 +{
  1.1780 +	struct evhttp_connection *evcon = arg;
  1.1781 +	struct event_base *base = evhttp_connection_get_base(evcon);
  1.1782 +	struct evhttp_request *req;
  1.1783 +
  1.1784 +	req = evhttp_request_new(close_detect_done, base);
  1.1785 +
  1.1786 +	/* Add the information that we care about */
  1.1787 +	evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
  1.1788 +
  1.1789 +	/* We give ownership of the request to the connection */
  1.1790 +	if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test") == -1) {
  1.1791 +		tt_fail_msg("Couldn't make request");
  1.1792 +	}
  1.1793 +}
  1.1794 +
  1.1795 +static void
  1.1796 +close_detect_cb(struct evhttp_request *req, void *arg)
  1.1797 +{
  1.1798 +	struct evhttp_connection *evcon = arg;
  1.1799 +	struct event_base *base = evhttp_connection_get_base(evcon);
  1.1800 +	struct timeval tv;
  1.1801 +
  1.1802 +	if (req != NULL && evhttp_request_get_response_code(req) != HTTP_OK) {
  1.1803 +		tt_abort_msg("Failed");
  1.1804 +	}
  1.1805 +
  1.1806 +	evutil_timerclear(&tv);
  1.1807 +	tv.tv_sec = 3;   /* longer than the http time out */
  1.1808 +
  1.1809 +	/* launch a new request on the persistent connection in 3 seconds */
  1.1810 +	event_base_once(base, -1, EV_TIMEOUT, close_detect_launch, evcon, &tv);
  1.1811 + end:
  1.1812 +	;
  1.1813 +}
  1.1814 +
  1.1815 +
  1.1816 +static void
  1.1817 +_http_close_detection(struct basic_test_data *data, int with_delay)
  1.1818 +{
  1.1819 +	ev_uint16_t port = 0;
  1.1820 +	struct evhttp_connection *evcon = NULL;
  1.1821 +	struct evhttp_request *req = NULL;
  1.1822 +
  1.1823 +	test_ok = 0;
  1.1824 +	http = http_setup(&port, data->base);
  1.1825 +
  1.1826 +	/* 2 second timeout */
  1.1827 +	evhttp_set_timeout(http, 1);
  1.1828 +
  1.1829 +	evcon = evhttp_connection_base_new(data->base, NULL,
  1.1830 +	    "127.0.0.1", port);
  1.1831 +	tt_assert(evcon);
  1.1832 +	delayed_client = evcon;
  1.1833 +
  1.1834 +	/*
  1.1835 +	 * At this point, we want to schedule a request to the HTTP
  1.1836 +	 * server using our make request method.
  1.1837 +	 */
  1.1838 +
  1.1839 +	req = evhttp_request_new(close_detect_cb, evcon);
  1.1840 +
  1.1841 +	/* Add the information that we care about */
  1.1842 +	evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
  1.1843 +
  1.1844 +	/* We give ownership of the request to the connection */
  1.1845 +	if (evhttp_make_request(evcon,
  1.1846 +	    req, EVHTTP_REQ_GET, with_delay ? "/largedelay" : "/test") == -1) {
  1.1847 +		tt_abort_msg("couldn't make request");
  1.1848 +	}
  1.1849 +
  1.1850 +	event_base_dispatch(data->base);
  1.1851 +
  1.1852 +	/* at this point, the http server should have no connection */
  1.1853 +	tt_assert(TAILQ_FIRST(&http->connections) == NULL);
  1.1854 +
  1.1855 + end:
  1.1856 +	if (evcon)
  1.1857 +		evhttp_connection_free(evcon);
  1.1858 +	if (http)
  1.1859 +		evhttp_free(http);
  1.1860 +}
  1.1861 +static void
  1.1862 +http_close_detection_test(void *arg)
  1.1863 +{
  1.1864 +	_http_close_detection(arg, 0);
  1.1865 +}
  1.1866 +static void
  1.1867 +http_close_detection_delay_test(void *arg)
  1.1868 +{
  1.1869 +	_http_close_detection(arg, 1);
  1.1870 +}
  1.1871 +
  1.1872 +static void
  1.1873 +http_highport_test(void *arg)
  1.1874 +{
  1.1875 +	struct basic_test_data *data = arg;
  1.1876 +	int i = -1;
  1.1877 +	struct evhttp *myhttp = NULL;
  1.1878 +
  1.1879 +	/* Try a few different ports */
  1.1880 +	for (i = 0; i < 50; ++i) {
  1.1881 +		myhttp = evhttp_new(data->base);
  1.1882 +		if (evhttp_bind_socket(myhttp, "127.0.0.1", 65535 - i) == 0) {
  1.1883 +			test_ok = 1;
  1.1884 +			evhttp_free(myhttp);
  1.1885 +			return;
  1.1886 +		}
  1.1887 +		evhttp_free(myhttp);
  1.1888 +	}
  1.1889 +
  1.1890 +	tt_fail_msg("Couldn't get a high port");
  1.1891 +}
  1.1892 +
  1.1893 +static void
  1.1894 +http_bad_header_test(void *ptr)
  1.1895 +{
  1.1896 +	struct evkeyvalq headers;
  1.1897 +
  1.1898 +	TAILQ_INIT(&headers);
  1.1899 +
  1.1900 +	tt_want(evhttp_add_header(&headers, "One", "Two") == 0);
  1.1901 +	tt_want(evhttp_add_header(&headers, "One", "Two\r\n Three") == 0);
  1.1902 +	tt_want(evhttp_add_header(&headers, "One\r", "Two") == -1);
  1.1903 +	tt_want(evhttp_add_header(&headers, "One\n", "Two") == -1);
  1.1904 +	tt_want(evhttp_add_header(&headers, "One", "Two\r") == -1);
  1.1905 +	tt_want(evhttp_add_header(&headers, "One", "Two\n") == -1);
  1.1906 +
  1.1907 +	evhttp_clear_headers(&headers);
  1.1908 +}
  1.1909 +
  1.1910 +static int validate_header(
  1.1911 +	const struct evkeyvalq* headers,
  1.1912 +	const char *key, const char *value)
  1.1913 +{
  1.1914 +	const char *real_val = evhttp_find_header(headers, key);
  1.1915 +	tt_assert(real_val != NULL);
  1.1916 +	tt_want(strcmp(real_val, value) == 0);
  1.1917 +end:
  1.1918 +	return (0);
  1.1919 +}
  1.1920 +
  1.1921 +static void
  1.1922 +http_parse_query_test(void *ptr)
  1.1923 +{
  1.1924 +	struct evkeyvalq headers;
  1.1925 +	int r;
  1.1926 +
  1.1927 +	TAILQ_INIT(&headers);
  1.1928 +
  1.1929 +	r = evhttp_parse_query("http://www.test.com/?q=test", &headers);
  1.1930 +	tt_want(validate_header(&headers, "q", "test") == 0);
  1.1931 +	tt_int_op(r, ==, 0);
  1.1932 +	evhttp_clear_headers(&headers);
  1.1933 +
  1.1934 +	r = evhttp_parse_query("http://www.test.com/?q=test&foo=bar", &headers);
  1.1935 +	tt_want(validate_header(&headers, "q", "test") == 0);
  1.1936 +	tt_want(validate_header(&headers, "foo", "bar") == 0);
  1.1937 +	tt_int_op(r, ==, 0);
  1.1938 +	evhttp_clear_headers(&headers);
  1.1939 +
  1.1940 +	r = evhttp_parse_query("http://www.test.com/?q=test+foo", &headers);
  1.1941 +	tt_want(validate_header(&headers, "q", "test foo") == 0);
  1.1942 +	tt_int_op(r, ==, 0);
  1.1943 +	evhttp_clear_headers(&headers);
  1.1944 +
  1.1945 +	r = evhttp_parse_query("http://www.test.com/?q=test%0Afoo", &headers);
  1.1946 +	tt_want(validate_header(&headers, "q", "test\nfoo") == 0);
  1.1947 +	tt_int_op(r, ==, 0);
  1.1948 +	evhttp_clear_headers(&headers);
  1.1949 +
  1.1950 +	r = evhttp_parse_query("http://www.test.com/?q=test%0Dfoo", &headers);
  1.1951 +	tt_want(validate_header(&headers, "q", "test\rfoo") == 0);
  1.1952 +	tt_int_op(r, ==, 0);
  1.1953 +	evhttp_clear_headers(&headers);
  1.1954 +
  1.1955 +	r = evhttp_parse_query("http://www.test.com/?q=test&&q2", &headers);
  1.1956 +	tt_int_op(r, ==, -1);
  1.1957 +	evhttp_clear_headers(&headers);
  1.1958 +
  1.1959 +	r = evhttp_parse_query("http://www.test.com/?q=test+this", &headers);
  1.1960 +	tt_want(validate_header(&headers, "q", "test this") == 0);
  1.1961 +	tt_int_op(r, ==, 0);
  1.1962 +	evhttp_clear_headers(&headers);
  1.1963 +
  1.1964 +	r = evhttp_parse_query("http://www.test.com/?q=test&q2=foo", &headers);
  1.1965 +	tt_int_op(r, ==, 0);
  1.1966 +	tt_want(validate_header(&headers, "q", "test") == 0);
  1.1967 +	tt_want(validate_header(&headers, "q2", "foo") == 0);
  1.1968 +	evhttp_clear_headers(&headers);
  1.1969 +
  1.1970 +	r = evhttp_parse_query("http://www.test.com/?q&q2=foo", &headers);
  1.1971 +	tt_int_op(r, ==, -1);
  1.1972 +	evhttp_clear_headers(&headers);
  1.1973 +
  1.1974 +	r = evhttp_parse_query("http://www.test.com/?q=foo&q2", &headers);
  1.1975 +	tt_int_op(r, ==, -1);
  1.1976 +	evhttp_clear_headers(&headers);
  1.1977 +
  1.1978 +	r = evhttp_parse_query("http://www.test.com/?q=foo&q2&q3=x", &headers);
  1.1979 +	tt_int_op(r, ==, -1);
  1.1980 +	evhttp_clear_headers(&headers);
  1.1981 +
  1.1982 +	r = evhttp_parse_query("http://www.test.com/?q=&q2=&q3=", &headers);
  1.1983 +	tt_int_op(r, ==, 0);
  1.1984 +	tt_want(validate_header(&headers, "q", "") == 0);
  1.1985 +	tt_want(validate_header(&headers, "q2", "") == 0);
  1.1986 +	tt_want(validate_header(&headers, "q3", "") == 0);
  1.1987 +	evhttp_clear_headers(&headers);
  1.1988 +
  1.1989 +end:
  1.1990 +	evhttp_clear_headers(&headers);
  1.1991 +}
  1.1992 +
  1.1993 +static void
  1.1994 +http_parse_uri_test(void *ptr)
  1.1995 +{
  1.1996 +	const int nonconform = (ptr != NULL);
  1.1997 +	const unsigned parse_flags =
  1.1998 +	    nonconform ? EVHTTP_URI_NONCONFORMANT : 0;
  1.1999 +	struct evhttp_uri *uri = NULL;
  1.2000 +	char url_tmp[4096];
  1.2001 +#define URI_PARSE(uri) \
  1.2002 +	evhttp_uri_parse_with_flags((uri), parse_flags)
  1.2003 +
  1.2004 +#define TT_URI(want) do { 						\
  1.2005 +	char *ret = evhttp_uri_join(uri, url_tmp, sizeof(url_tmp));	\
  1.2006 +	tt_want(ret != NULL);						\
  1.2007 +	tt_want(ret == url_tmp);					\
  1.2008 +	if (strcmp(ret,want) != 0)					\
  1.2009 +		TT_FAIL(("\"%s\" != \"%s\"",ret,want));			\
  1.2010 +	} while(0)
  1.2011 +
  1.2012 +	tt_want(evhttp_uri_join(NULL, 0, 0) == NULL);
  1.2013 +	tt_want(evhttp_uri_join(NULL, url_tmp, 0) == NULL);
  1.2014 +	tt_want(evhttp_uri_join(NULL, url_tmp, sizeof(url_tmp)) == NULL);
  1.2015 +
  1.2016 +	/* bad URIs: parsing */
  1.2017 +#define BAD(s) do {							\
  1.2018 +		if (URI_PARSE(s) != NULL)				\
  1.2019 +			TT_FAIL(("Expected error parsing \"%s\"",s));	\
  1.2020 +	} while(0)
  1.2021 +	/* Nonconformant URIs we can parse: parsing */
  1.2022 +#define NCF(s) do {							\
  1.2023 +		uri = URI_PARSE(s);					\
  1.2024 +		if (uri != NULL && !nonconform) {			\
  1.2025 +			TT_FAIL(("Expected error parsing \"%s\"",s));	\
  1.2026 +		} else if (uri == NULL && nonconform) {			\
  1.2027 +			TT_FAIL(("Couldn't parse nonconformant URI \"%s\"", \
  1.2028 +				s));					\
  1.2029 +		}							\
  1.2030 +		if (uri) {						\
  1.2031 +			tt_want(evhttp_uri_join(uri, url_tmp,		\
  1.2032 +				sizeof(url_tmp)));			\
  1.2033 +			evhttp_uri_free(uri);				\
  1.2034 +		}							\
  1.2035 +	} while(0)
  1.2036 +
  1.2037 +	NCF("http://www.test.com/ why hello");
  1.2038 +	NCF("http://www.test.com/why-hello\x01");
  1.2039 +	NCF("http://www.test.com/why-hello?\x01");
  1.2040 +	NCF("http://www.test.com/why-hello#\x01");
  1.2041 +	BAD("http://www.\x01.test.com/why-hello");
  1.2042 +	BAD("http://www.%7test.com/why-hello");
  1.2043 +	NCF("http://www.test.com/why-hell%7o");
  1.2044 +	BAD("h%3ttp://www.test.com/why-hello");
  1.2045 +	NCF("http://www.test.com/why-hello%7");
  1.2046 +	NCF("http://www.test.com/why-hell%7o");
  1.2047 +	NCF("http://www.test.com/foo?ba%r");
  1.2048 +	NCF("http://www.test.com/foo#ba%r");
  1.2049 +	BAD("99:99/foo");
  1.2050 +	BAD("http://www.test.com:999x/");
  1.2051 +	BAD("http://www.test.com:x/");
  1.2052 +	BAD("http://[hello-there]/");
  1.2053 +	BAD("http://[::1]]/");
  1.2054 +	BAD("http://[::1/");
  1.2055 +	BAD("http://[foob/");
  1.2056 +	BAD("http://[/");
  1.2057 +	BAD("http://[ffff:ffff:ffff:ffff:Ffff:ffff:ffff:"
  1.2058 +	            "ffff:ffff:ffff:ffff:ffff:ffff:ffff]/");
  1.2059 +	BAD("http://[vX.foo]/");
  1.2060 +	BAD("http://[vX.foo]/");
  1.2061 +	BAD("http://[v.foo]/");
  1.2062 +	BAD("http://[v5.fo%o]/");
  1.2063 +	BAD("http://[v5X]/");
  1.2064 +	BAD("http://[v5]/");
  1.2065 +	BAD("http://[]/");
  1.2066 +	BAD("http://f\x01red@www.example.com/");
  1.2067 +	BAD("http://f%0red@www.example.com/");
  1.2068 +	BAD("http://www.example.com:9999999999999999999999999999999999999/");
  1.2069 +	BAD("http://www.example.com:hihi/");
  1.2070 +	BAD("://www.example.com/");
  1.2071 +
  1.2072 +	/* bad URIs: joining */
  1.2073 +	uri = evhttp_uri_new();
  1.2074 +	tt_want(0==evhttp_uri_set_host(uri, "www.example.com"));
  1.2075 +	tt_want(evhttp_uri_join(uri, url_tmp, sizeof(url_tmp)) != NULL);
  1.2076 +	/* not enough space: */
  1.2077 +	tt_want(evhttp_uri_join(uri, url_tmp, 3) == NULL);
  1.2078 +	/* host is set, but path doesn't start with "/": */
  1.2079 +	tt_want(0==evhttp_uri_set_path(uri, "hi_mom"));
  1.2080 +	tt_want(evhttp_uri_join(uri, url_tmp, sizeof(url_tmp)) == NULL);
  1.2081 +	tt_want(evhttp_uri_join(uri, NULL, sizeof(url_tmp))==NULL);
  1.2082 +	tt_want(evhttp_uri_join(uri, url_tmp, 0)==NULL);
  1.2083 +	evhttp_uri_free(uri);
  1.2084 +	uri = URI_PARSE("mailto:foo@bar");
  1.2085 +	tt_want(uri != NULL);
  1.2086 +	tt_want(evhttp_uri_get_host(uri) == NULL);
  1.2087 +	tt_want(evhttp_uri_get_userinfo(uri) == NULL);
  1.2088 +	tt_want(evhttp_uri_get_port(uri) == -1);
  1.2089 +	tt_want(!strcmp(evhttp_uri_get_scheme(uri), "mailto"));
  1.2090 +	tt_want(!strcmp(evhttp_uri_get_path(uri), "foo@bar"));
  1.2091 +	tt_want(evhttp_uri_get_query(uri) == NULL);
  1.2092 +	tt_want(evhttp_uri_get_fragment(uri) == NULL);
  1.2093 +	TT_URI("mailto:foo@bar");
  1.2094 +	evhttp_uri_free(uri);
  1.2095 +
  1.2096 +	uri = evhttp_uri_new();
  1.2097 +	/* Bad URI usage: setting invalid values */
  1.2098 +	tt_want(-1 == evhttp_uri_set_scheme(uri,""));
  1.2099 +	tt_want(-1 == evhttp_uri_set_scheme(uri,"33"));
  1.2100 +	tt_want(-1 == evhttp_uri_set_scheme(uri,"hi!"));
  1.2101 +	tt_want(-1 == evhttp_uri_set_userinfo(uri,"hello@"));
  1.2102 +	tt_want(-1 == evhttp_uri_set_host(uri,"[1.2.3.4]"));
  1.2103 +	tt_want(-1 == evhttp_uri_set_host(uri,"["));
  1.2104 +	tt_want(-1 == evhttp_uri_set_host(uri,"www.[foo].com"));
  1.2105 +	tt_want(-1 == evhttp_uri_set_port(uri,-3));
  1.2106 +	tt_want(-1 == evhttp_uri_set_path(uri,"hello?world"));
  1.2107 +	tt_want(-1 == evhttp_uri_set_query(uri,"hello#world"));
  1.2108 +	tt_want(-1 == evhttp_uri_set_fragment(uri,"hello#world"));
  1.2109 +	/* Valid URI usage: setting valid values */
  1.2110 +	tt_want(0 == evhttp_uri_set_scheme(uri,"http"));
  1.2111 +	tt_want(0 == evhttp_uri_set_scheme(uri,NULL));
  1.2112 +	tt_want(0 == evhttp_uri_set_userinfo(uri,"username:pass"));
  1.2113 +	tt_want(0 == evhttp_uri_set_userinfo(uri,NULL));
  1.2114 +	tt_want(0 == evhttp_uri_set_host(uri,"www.example.com"));
  1.2115 +	tt_want(0 == evhttp_uri_set_host(uri,"1.2.3.4"));
  1.2116 +	tt_want(0 == evhttp_uri_set_host(uri,"[1:2:3:4::]"));
  1.2117 +	tt_want(0 == evhttp_uri_set_host(uri,"[v7.wobblewobble]"));
  1.2118 +	tt_want(0 == evhttp_uri_set_host(uri,NULL));
  1.2119 +	tt_want(0 == evhttp_uri_set_host(uri,""));
  1.2120 +	tt_want(0 == evhttp_uri_set_port(uri, -1));
  1.2121 +	tt_want(0 == evhttp_uri_set_port(uri, 80));
  1.2122 +	tt_want(0 == evhttp_uri_set_port(uri, 65535));
  1.2123 +	tt_want(0 == evhttp_uri_set_path(uri, ""));
  1.2124 +	tt_want(0 == evhttp_uri_set_path(uri, "/documents/public/index.html"));
  1.2125 +	tt_want(0 == evhttp_uri_set_path(uri, NULL));
  1.2126 +	tt_want(0 == evhttp_uri_set_query(uri, "key=val&key2=val2"));
  1.2127 +	tt_want(0 == evhttp_uri_set_query(uri, "keyvalblarg"));
  1.2128 +	tt_want(0 == evhttp_uri_set_query(uri, ""));
  1.2129 +	tt_want(0 == evhttp_uri_set_query(uri, NULL));
  1.2130 +	tt_want(0 == evhttp_uri_set_fragment(uri, ""));
  1.2131 +	tt_want(0 == evhttp_uri_set_fragment(uri, "here?i?am"));
  1.2132 +	tt_want(0 == evhttp_uri_set_fragment(uri, NULL));
  1.2133 +	evhttp_uri_free(uri);
  1.2134 +
  1.2135 +	/* Valid parsing */
  1.2136 +	uri = URI_PARSE("http://www.test.com/?q=t%33est");
  1.2137 +	tt_want(strcmp(evhttp_uri_get_scheme(uri), "http") == 0);
  1.2138 +	tt_want(strcmp(evhttp_uri_get_host(uri), "www.test.com") == 0);
  1.2139 +	tt_want(strcmp(evhttp_uri_get_path(uri), "/") == 0);
  1.2140 +	tt_want(strcmp(evhttp_uri_get_query(uri), "q=t%33est") == 0);
  1.2141 +	tt_want(evhttp_uri_get_userinfo(uri) == NULL);
  1.2142 +	tt_want(evhttp_uri_get_port(uri) == -1);
  1.2143 +	tt_want(evhttp_uri_get_fragment(uri) == NULL);
  1.2144 +	TT_URI("http://www.test.com/?q=t%33est");
  1.2145 +	evhttp_uri_free(uri);
  1.2146 +
  1.2147 +	uri = URI_PARSE("http://%77ww.test.com");
  1.2148 +	tt_want(strcmp(evhttp_uri_get_scheme(uri), "http") == 0);
  1.2149 +	tt_want(strcmp(evhttp_uri_get_host(uri), "%77ww.test.com") == 0);
  1.2150 +	tt_want(strcmp(evhttp_uri_get_path(uri), "") == 0);
  1.2151 +	tt_want(evhttp_uri_get_query(uri) == NULL);
  1.2152 +	tt_want(evhttp_uri_get_userinfo(uri) == NULL);
  1.2153 +	tt_want(evhttp_uri_get_port(uri) == -1);
  1.2154 +	tt_want(evhttp_uri_get_fragment(uri) == NULL);
  1.2155 +	TT_URI("http://%77ww.test.com");
  1.2156 +	evhttp_uri_free(uri);
  1.2157 +
  1.2158 +	uri = URI_PARSE("http://www.test.com?q=test");
  1.2159 +	tt_want(strcmp(evhttp_uri_get_scheme(uri), "http") == 0);
  1.2160 +	tt_want(strcmp(evhttp_uri_get_host(uri), "www.test.com") == 0);
  1.2161 +	tt_want(strcmp(evhttp_uri_get_path(uri), "") == 0);
  1.2162 +	tt_want(strcmp(evhttp_uri_get_query(uri), "q=test") == 0);
  1.2163 +	tt_want(evhttp_uri_get_userinfo(uri) == NULL);
  1.2164 +	tt_want(evhttp_uri_get_port(uri) == -1);
  1.2165 +	tt_want(evhttp_uri_get_fragment(uri) == NULL);
  1.2166 +	TT_URI("http://www.test.com?q=test");
  1.2167 +	evhttp_uri_free(uri);
  1.2168 +
  1.2169 +	uri = URI_PARSE("http://www.test.com#fragment");
  1.2170 +	tt_want(strcmp(evhttp_uri_get_scheme(uri), "http") == 0);
  1.2171 +	tt_want(strcmp(evhttp_uri_get_host(uri), "www.test.com") == 0);
  1.2172 +	tt_want(strcmp(evhttp_uri_get_path(uri), "") == 0);
  1.2173 +	tt_want(evhttp_uri_get_query(uri) == NULL);
  1.2174 +	tt_want(evhttp_uri_get_userinfo(uri) == NULL);
  1.2175 +	tt_want(evhttp_uri_get_port(uri) == -1);
  1.2176 +	tt_want_str_op(evhttp_uri_get_fragment(uri), ==, "fragment");
  1.2177 +	TT_URI("http://www.test.com#fragment");
  1.2178 +	evhttp_uri_free(uri);
  1.2179 +
  1.2180 +	uri = URI_PARSE("http://8000/");
  1.2181 +	tt_want(strcmp(evhttp_uri_get_scheme(uri), "http") == 0);
  1.2182 +	tt_want(strcmp(evhttp_uri_get_host(uri), "8000") == 0);
  1.2183 +	tt_want(strcmp(evhttp_uri_get_path(uri), "/") == 0);
  1.2184 +	tt_want(evhttp_uri_get_query(uri) == NULL);
  1.2185 +	tt_want(evhttp_uri_get_userinfo(uri) == NULL);
  1.2186 +	tt_want(evhttp_uri_get_port(uri) == -1);
  1.2187 +	tt_want(evhttp_uri_get_fragment(uri) == NULL);
  1.2188 +	TT_URI("http://8000/");
  1.2189 +	evhttp_uri_free(uri);
  1.2190 +
  1.2191 +	uri = URI_PARSE("http://:8000/");
  1.2192 +	tt_want(strcmp(evhttp_uri_get_scheme(uri), "http") == 0);
  1.2193 +	tt_want(strcmp(evhttp_uri_get_host(uri), "") == 0);
  1.2194 +	tt_want(strcmp(evhttp_uri_get_path(uri), "/") == 0);
  1.2195 +	tt_want(evhttp_uri_get_query(uri) == NULL);
  1.2196 +	tt_want(evhttp_uri_get_userinfo(uri) == NULL);
  1.2197 +	tt_want(evhttp_uri_get_port(uri) == 8000);
  1.2198 +	tt_want(evhttp_uri_get_fragment(uri) == NULL);
  1.2199 +	TT_URI("http://:8000/");
  1.2200 +	evhttp_uri_free(uri);
  1.2201 +
  1.2202 +	uri = URI_PARSE("http://www.test.com:/"); /* empty port */
  1.2203 +	tt_want(strcmp(evhttp_uri_get_scheme(uri), "http") == 0);
  1.2204 +	tt_want(strcmp(evhttp_uri_get_host(uri), "www.test.com") == 0);
  1.2205 +	tt_want_str_op(evhttp_uri_get_path(uri), ==, "/");
  1.2206 +	tt_want(evhttp_uri_get_query(uri) == NULL);
  1.2207 +	tt_want(evhttp_uri_get_userinfo(uri) == NULL);
  1.2208 +	tt_want(evhttp_uri_get_port(uri) == -1);
  1.2209 +	tt_want(evhttp_uri_get_fragment(uri) == NULL);
  1.2210 +	TT_URI("http://www.test.com/");
  1.2211 +	evhttp_uri_free(uri);
  1.2212 +
  1.2213 +	uri = URI_PARSE("http://www.test.com:"); /* empty port 2 */
  1.2214 +	tt_want(strcmp(evhttp_uri_get_scheme(uri), "http") == 0);
  1.2215 +	tt_want(strcmp(evhttp_uri_get_host(uri), "www.test.com") == 0);
  1.2216 +	tt_want(strcmp(evhttp_uri_get_path(uri), "") == 0);
  1.2217 +	tt_want(evhttp_uri_get_query(uri) == NULL);
  1.2218 +	tt_want(evhttp_uri_get_userinfo(uri) == NULL);
  1.2219 +	tt_want(evhttp_uri_get_port(uri) == -1);
  1.2220 +	tt_want(evhttp_uri_get_fragment(uri) == NULL);
  1.2221 +	TT_URI("http://www.test.com");
  1.2222 +	evhttp_uri_free(uri);
  1.2223 +
  1.2224 +	uri = URI_PARSE("ftp://www.test.com/?q=test");
  1.2225 +	tt_want(strcmp(evhttp_uri_get_scheme(uri), "ftp") == 0);
  1.2226 +	tt_want(strcmp(evhttp_uri_get_host(uri), "www.test.com") == 0);
  1.2227 +	tt_want(strcmp(evhttp_uri_get_path(uri), "/") == 0);
  1.2228 +	tt_want(strcmp(evhttp_uri_get_query(uri), "q=test") == 0);
  1.2229 +	tt_want(evhttp_uri_get_userinfo(uri) == NULL);
  1.2230 +	tt_want(evhttp_uri_get_port(uri) == -1);
  1.2231 +	tt_want(evhttp_uri_get_fragment(uri) == NULL);
  1.2232 +	TT_URI("ftp://www.test.com/?q=test");
  1.2233 +	evhttp_uri_free(uri);
  1.2234 +
  1.2235 +	uri = URI_PARSE("ftp://[::1]:999/?q=test");
  1.2236 +	tt_want(strcmp(evhttp_uri_get_scheme(uri), "ftp") == 0);
  1.2237 +	tt_want(strcmp(evhttp_uri_get_host(uri), "[::1]") == 0);
  1.2238 +	tt_want(strcmp(evhttp_uri_get_path(uri), "/") == 0);
  1.2239 +	tt_want(strcmp(evhttp_uri_get_query(uri), "q=test") == 0);
  1.2240 +	tt_want(evhttp_uri_get_userinfo(uri) == NULL);
  1.2241 +	tt_want(evhttp_uri_get_port(uri) == 999);
  1.2242 +	tt_want(evhttp_uri_get_fragment(uri) == NULL);
  1.2243 +	TT_URI("ftp://[::1]:999/?q=test");
  1.2244 +	evhttp_uri_free(uri);
  1.2245 +
  1.2246 +	uri = URI_PARSE("ftp://[ff00::127.0.0.1]/?q=test");
  1.2247 +	tt_want(strcmp(evhttp_uri_get_scheme(uri), "ftp") == 0);
  1.2248 +	tt_want(strcmp(evhttp_uri_get_host(uri), "[ff00::127.0.0.1]") == 0);
  1.2249 +	tt_want(strcmp(evhttp_uri_get_path(uri), "/") == 0);
  1.2250 +	tt_want(strcmp(evhttp_uri_get_query(uri), "q=test") == 0);
  1.2251 +	tt_want(evhttp_uri_get_userinfo(uri) == NULL);
  1.2252 +	tt_want(evhttp_uri_get_port(uri) == -1);
  1.2253 +	tt_want(evhttp_uri_get_fragment(uri) == NULL);
  1.2254 +	TT_URI("ftp://[ff00::127.0.0.1]/?q=test");
  1.2255 +	evhttp_uri_free(uri);
  1.2256 +
  1.2257 +	uri = URI_PARSE("ftp://[v99.not_(any:time)_soon]/?q=test");
  1.2258 +	tt_want(strcmp(evhttp_uri_get_scheme(uri), "ftp") == 0);
  1.2259 +	tt_want(strcmp(evhttp_uri_get_host(uri), "[v99.not_(any:time)_soon]") == 0);
  1.2260 +	tt_want(strcmp(evhttp_uri_get_path(uri), "/") == 0);
  1.2261 +	tt_want(strcmp(evhttp_uri_get_query(uri), "q=test") == 0);
  1.2262 +	tt_want(evhttp_uri_get_userinfo(uri) == NULL);
  1.2263 +	tt_want(evhttp_uri_get_port(uri) == -1);
  1.2264 +	tt_want(evhttp_uri_get_fragment(uri) == NULL);
  1.2265 +	TT_URI("ftp://[v99.not_(any:time)_soon]/?q=test");
  1.2266 +	evhttp_uri_free(uri);
  1.2267 +
  1.2268 +	uri = URI_PARSE("scheme://user:pass@foo.com:42/?q=test&s=some+thing#fragment");
  1.2269 +	tt_want(strcmp(evhttp_uri_get_scheme(uri), "scheme") == 0);
  1.2270 +	tt_want(strcmp(evhttp_uri_get_userinfo(uri), "user:pass") == 0);
  1.2271 +	tt_want(strcmp(evhttp_uri_get_host(uri), "foo.com") == 0);
  1.2272 +	tt_want(evhttp_uri_get_port(uri) == 42);
  1.2273 +	tt_want(strcmp(evhttp_uri_get_path(uri), "/") == 0);
  1.2274 +	tt_want(strcmp(evhttp_uri_get_query(uri), "q=test&s=some+thing") == 0);
  1.2275 +	tt_want(strcmp(evhttp_uri_get_fragment(uri), "fragment") == 0);
  1.2276 +	TT_URI("scheme://user:pass@foo.com:42/?q=test&s=some+thing#fragment");
  1.2277 +	evhttp_uri_free(uri);
  1.2278 +
  1.2279 +	uri = URI_PARSE("scheme://user@foo.com/#fragment");
  1.2280 +	tt_want(strcmp(evhttp_uri_get_scheme(uri), "scheme") == 0);
  1.2281 +	tt_want(strcmp(evhttp_uri_get_userinfo(uri), "user") == 0);
  1.2282 +	tt_want(strcmp(evhttp_uri_get_host(uri), "foo.com") == 0);
  1.2283 +	tt_want(evhttp_uri_get_port(uri) == -1);
  1.2284 +	tt_want(strcmp(evhttp_uri_get_path(uri), "/") == 0);
  1.2285 +	tt_want(evhttp_uri_get_query(uri) == NULL);
  1.2286 +	tt_want(strcmp(evhttp_uri_get_fragment(uri), "fragment") == 0);
  1.2287 +	TT_URI("scheme://user@foo.com/#fragment");
  1.2288 +	evhttp_uri_free(uri);
  1.2289 +
  1.2290 +	uri = URI_PARSE("scheme://%75ser@foo.com/#frag@ment");
  1.2291 +	tt_want(strcmp(evhttp_uri_get_scheme(uri), "scheme") == 0);
  1.2292 +	tt_want(strcmp(evhttp_uri_get_userinfo(uri), "%75ser") == 0);
  1.2293 +	tt_want(strcmp(evhttp_uri_get_host(uri), "foo.com") == 0);
  1.2294 +	tt_want(evhttp_uri_get_port(uri) == -1);
  1.2295 +	tt_want(strcmp(evhttp_uri_get_path(uri), "/") == 0);
  1.2296 +	tt_want(evhttp_uri_get_query(uri) == NULL);
  1.2297 +	tt_want(strcmp(evhttp_uri_get_fragment(uri), "frag@ment") == 0);
  1.2298 +	TT_URI("scheme://%75ser@foo.com/#frag@ment");
  1.2299 +	evhttp_uri_free(uri);
  1.2300 +
  1.2301 +	uri = URI_PARSE("file:///some/path/to/the/file");
  1.2302 +	tt_want(strcmp(evhttp_uri_get_scheme(uri), "file") == 0);
  1.2303 +	tt_want(evhttp_uri_get_userinfo(uri) == NULL);
  1.2304 +	tt_want(strcmp(evhttp_uri_get_host(uri), "") == 0);
  1.2305 +	tt_want(evhttp_uri_get_port(uri) == -1);
  1.2306 +	tt_want(strcmp(evhttp_uri_get_path(uri), "/some/path/to/the/file") == 0);
  1.2307 +	tt_want(evhttp_uri_get_query(uri) == NULL);
  1.2308 +	tt_want(evhttp_uri_get_fragment(uri) == NULL);
  1.2309 +	TT_URI("file:///some/path/to/the/file");
  1.2310 +	evhttp_uri_free(uri);
  1.2311 +
  1.2312 +	uri = URI_PARSE("///some/path/to/the-file");
  1.2313 +	tt_want(uri != NULL);
  1.2314 +	tt_want(evhttp_uri_get_scheme(uri) == NULL);
  1.2315 +	tt_want(evhttp_uri_get_userinfo(uri) == NULL);
  1.2316 +	tt_want(strcmp(evhttp_uri_get_host(uri), "") == 0);
  1.2317 +	tt_want(evhttp_uri_get_port(uri) == -1);
  1.2318 +	tt_want(strcmp(evhttp_uri_get_path(uri), "/some/path/to/the-file") == 0);
  1.2319 +	tt_want(evhttp_uri_get_query(uri) == NULL);
  1.2320 +	tt_want(evhttp_uri_get_fragment(uri) == NULL);
  1.2321 +	TT_URI("///some/path/to/the-file");
  1.2322 +	evhttp_uri_free(uri);
  1.2323 +
  1.2324 +	uri = URI_PARSE("/s:ome/path/to/the-file?q=99#fred");
  1.2325 +	tt_want(uri != NULL);
  1.2326 +	tt_want(evhttp_uri_get_scheme(uri) == NULL);
  1.2327 +	tt_want(evhttp_uri_get_userinfo(uri) == NULL);
  1.2328 +	tt_want(evhttp_uri_get_host(uri) == NULL);
  1.2329 +	tt_want(evhttp_uri_get_port(uri) == -1);
  1.2330 +	tt_want(strcmp(evhttp_uri_get_path(uri), "/s:ome/path/to/the-file") == 0);
  1.2331 +	tt_want(strcmp(evhttp_uri_get_query(uri), "q=99") == 0);
  1.2332 +	tt_want(strcmp(evhttp_uri_get_fragment(uri), "fred") == 0);
  1.2333 +	TT_URI("/s:ome/path/to/the-file?q=99#fred");
  1.2334 +	evhttp_uri_free(uri);
  1.2335 +
  1.2336 +	uri = URI_PARSE("relative/path/with/co:lon");
  1.2337 +	tt_want(uri != NULL);
  1.2338 +	tt_want(evhttp_uri_get_scheme(uri) == NULL);
  1.2339 +	tt_want(evhttp_uri_get_userinfo(uri) == NULL);
  1.2340 +	tt_want(evhttp_uri_get_host(uri) == NULL);
  1.2341 +	tt_want(evhttp_uri_get_port(uri) == -1);
  1.2342 +	tt_want(strcmp(evhttp_uri_get_path(uri), "relative/path/with/co:lon") == 0);
  1.2343 +	tt_want(evhttp_uri_get_query(uri) == NULL);
  1.2344 +	tt_want(evhttp_uri_get_fragment(uri) == NULL);
  1.2345 +	TT_URI("relative/path/with/co:lon");
  1.2346 +	evhttp_uri_free(uri);
  1.2347 +
  1.2348 +	uri = URI_PARSE("bob?q=99&q2=q?33#fr?ed");
  1.2349 +	tt_want(uri != NULL);
  1.2350 +	tt_want(evhttp_uri_get_scheme(uri) == NULL);
  1.2351 +	tt_want(evhttp_uri_get_userinfo(uri) == NULL);
  1.2352 +	tt_want(evhttp_uri_get_host(uri) == NULL);
  1.2353 +	tt_want(evhttp_uri_get_port(uri) == -1);
  1.2354 +	tt_want(strcmp(evhttp_uri_get_path(uri), "bob") == 0);
  1.2355 +	tt_want(strcmp(evhttp_uri_get_query(uri), "q=99&q2=q?33") == 0);
  1.2356 +	tt_want(strcmp(evhttp_uri_get_fragment(uri), "fr?ed") == 0);
  1.2357 +	TT_URI("bob?q=99&q2=q?33#fr?ed");
  1.2358 +	evhttp_uri_free(uri);
  1.2359 +
  1.2360 +	uri = URI_PARSE("#fr?ed");
  1.2361 +	tt_want(uri != NULL);
  1.2362 +	tt_want(evhttp_uri_get_scheme(uri) == NULL);
  1.2363 +	tt_want(evhttp_uri_get_userinfo(uri) == NULL);
  1.2364 +	tt_want(evhttp_uri_get_host(uri) == NULL);
  1.2365 +	tt_want(evhttp_uri_get_port(uri) == -1);
  1.2366 +	tt_want(strcmp(evhttp_uri_get_path(uri), "") == 0);
  1.2367 +	tt_want(evhttp_uri_get_query(uri) == NULL);
  1.2368 +	tt_want(strcmp(evhttp_uri_get_fragment(uri), "fr?ed") == 0);
  1.2369 +	TT_URI("#fr?ed");
  1.2370 +	evhttp_uri_free(uri);
  1.2371 +#undef URI_PARSE
  1.2372 +#undef TT_URI
  1.2373 +#undef BAD
  1.2374 +}
  1.2375 +
  1.2376 +static void
  1.2377 +http_uriencode_test(void *ptr)
  1.2378 +{
  1.2379 +	char *s=NULL, *s2=NULL;
  1.2380 +	size_t sz;
  1.2381 +
  1.2382 +#define ENC(from,want,plus) do {				\
  1.2383 +		s = evhttp_uriencode((from), -1, (plus));	\
  1.2384 +		tt_assert(s);					\
  1.2385 +		tt_str_op(s,==,(want));				\
  1.2386 +		sz = -1;					\
  1.2387 +		s2 = evhttp_uridecode((s), (plus), &sz);	\
  1.2388 +		tt_assert(s2);					\
  1.2389 +		tt_str_op(s2,==,(from));			\
  1.2390 +		tt_int_op(sz,==,strlen(from));			\
  1.2391 +		free(s);					\
  1.2392 +		free(s2);					\
  1.2393 +		s = s2 = NULL;					\
  1.2394 +	} while (0)
  1.2395 +
  1.2396 +#define DEC(from,want,dp) do {					\
  1.2397 +		s = evhttp_uridecode((from),(dp),&sz);		\
  1.2398 +		tt_assert(s);					\
  1.2399 +		tt_str_op(s,==,(want));				\
  1.2400 +		tt_int_op(sz,==,strlen(want));			\
  1.2401 +		free(s);					\
  1.2402 +		s = NULL;					\
  1.2403 +	} while (0)
  1.2404 +
  1.2405 +#define OLD_DEC(from,want)  do {				\
  1.2406 +		s = evhttp_decode_uri((from));			\
  1.2407 +		tt_assert(s);					\
  1.2408 +		tt_str_op(s,==,(want));				\
  1.2409 +		free(s);					\
  1.2410 +		s = NULL;					\
  1.2411 +	} while (0)
  1.2412 +
  1.2413 +
  1.2414 +      	ENC("Hello", "Hello",0);
  1.2415 +	ENC("99", "99",0);
  1.2416 +	ENC("", "",0);
  1.2417 +	ENC(
  1.2418 +	 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ123456789-.~_",
  1.2419 +	 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ123456789-.~_",0);
  1.2420 +	ENC(" ", "%20",0);
  1.2421 +	ENC(" ", "+",1);
  1.2422 +	ENC("\xff\xf0\xe0", "%FF%F0%E0",0);
  1.2423 +	ENC("\x01\x19", "%01%19",1);
  1.2424 +	ENC("http://www.ietf.org/rfc/rfc3986.txt",
  1.2425 +	    "http%3A%2F%2Fwww.ietf.org%2Frfc%2Frfc3986.txt",1);
  1.2426 +
  1.2427 +	ENC("1+2=3", "1%2B2%3D3",1);
  1.2428 +	ENC("1+2=3", "1%2B2%3D3",0);
  1.2429 +
  1.2430 +	/* Now try encoding with internal NULs. */
  1.2431 +	s = evhttp_uriencode("hello\0world", 11, 0);
  1.2432 +	tt_assert(s);
  1.2433 +	tt_str_op(s,==,"hello%00world");
  1.2434 +	free(s);
  1.2435 +	s = NULL;
  1.2436 +
  1.2437 +	/* Now try out some decoding cases that we don't generate with
  1.2438 +	 * encode_uri: Make sure that malformed stuff doesn't crash... */
  1.2439 +	DEC("%%xhello th+ere \xff",
  1.2440 +	    "%%xhello th+ere \xff", 0);
  1.2441 +	/* Make sure plus decoding works */
  1.2442 +	DEC("plus+should%20work+", "plus should work ",1);
  1.2443 +	/* Try some lowercase hex */
  1.2444 +	DEC("%f0%a0%b0", "\xf0\xa0\xb0",1);
  1.2445 +
  1.2446 +	/* Try an internal NUL. */
  1.2447 +	sz = 0;
  1.2448 +	s = evhttp_uridecode("%00%00x%00%00", 1, &sz);
  1.2449 +	tt_int_op(sz,==,5);
  1.2450 +	tt_assert(!memcmp(s, "\0\0x\0\0", 5));
  1.2451 +	free(s);
  1.2452 +	s = NULL;
  1.2453 +
  1.2454 +	/* Try with size == NULL */
  1.2455 +	sz = 0;
  1.2456 +	s = evhttp_uridecode("%00%00x%00%00", 1, NULL);
  1.2457 +	tt_assert(!memcmp(s, "\0\0x\0\0", 5));
  1.2458 +	free(s);
  1.2459 +	s = NULL;
  1.2460 +
  1.2461 +	/* Test out the crazy old behavior of the deprecated
  1.2462 +	 * evhttp_decode_uri */
  1.2463 +	OLD_DEC("http://example.com/normal+path/?key=val+with+spaces",
  1.2464 +	        "http://example.com/normal+path/?key=val with spaces");
  1.2465 +
  1.2466 +end:
  1.2467 +	if (s)
  1.2468 +		free(s);
  1.2469 +	if (s2)
  1.2470 +		free(s2);
  1.2471 +#undef ENC
  1.2472 +#undef DEC
  1.2473 +#undef OLD_DEC
  1.2474 +}
  1.2475 +
  1.2476 +static void
  1.2477 +http_base_test(void *ptr)
  1.2478 +{
  1.2479 +	struct event_base *base = NULL;
  1.2480 +	struct bufferevent *bev;
  1.2481 +	evutil_socket_t fd;
  1.2482 +	const char *http_request;
  1.2483 +	ev_uint16_t port = 0;
  1.2484 +
  1.2485 +	test_ok = 0;
  1.2486 +	base = event_base_new();
  1.2487 +	http = http_setup(&port, base);
  1.2488 +
  1.2489 +	fd = http_connect("127.0.0.1", port);
  1.2490 +
  1.2491 +	/* Stupid thing to send a request */
  1.2492 +	bev = bufferevent_socket_new(base, fd, 0);
  1.2493 +	bufferevent_setcb(bev, http_readcb, http_writecb,
  1.2494 +	    http_errorcb, base);
  1.2495 +	bufferevent_base_set(base, bev);
  1.2496 +
  1.2497 +	http_request =
  1.2498 +	    "GET /test HTTP/1.1\r\n"
  1.2499 +	    "Host: somehost\r\n"
  1.2500 +	    "Connection: close\r\n"
  1.2501 +	    "\r\n";
  1.2502 +
  1.2503 +	bufferevent_write(bev, http_request, strlen(http_request));
  1.2504 +
  1.2505 +	event_base_dispatch(base);
  1.2506 +
  1.2507 +	bufferevent_free(bev);
  1.2508 +	evutil_closesocket(fd);
  1.2509 +
  1.2510 +	evhttp_free(http);
  1.2511 +
  1.2512 +	tt_int_op(test_ok, ==, 2);
  1.2513 +
  1.2514 +end:
  1.2515 +	if (base)
  1.2516 +		event_base_free(base);
  1.2517 +}
  1.2518 +
  1.2519 +/*
  1.2520 + * the server is just going to close the connection if it times out during
  1.2521 + * reading the headers.
  1.2522 + */
  1.2523 +
  1.2524 +static void
  1.2525 +http_incomplete_readcb(struct bufferevent *bev, void *arg)
  1.2526 +{
  1.2527 +	test_ok = -1;
  1.2528 +	event_base_loopexit(exit_base,NULL);
  1.2529 +}
  1.2530 +
  1.2531 +static void
  1.2532 +http_incomplete_errorcb(struct bufferevent *bev, short what, void *arg)
  1.2533 +{
  1.2534 +	if (what == (BEV_EVENT_READING|BEV_EVENT_EOF))
  1.2535 +		test_ok++;
  1.2536 +	else
  1.2537 +		test_ok = -2;
  1.2538 +	event_base_loopexit(exit_base,NULL);
  1.2539 +}
  1.2540 +
  1.2541 +static void
  1.2542 +http_incomplete_writecb(struct bufferevent *bev, void *arg)
  1.2543 +{
  1.2544 +	if (arg != NULL) {
  1.2545 +		evutil_socket_t fd = *(evutil_socket_t *)arg;
  1.2546 +		/* terminate the write side to simulate EOF */
  1.2547 +		shutdown(fd, SHUT_WR);
  1.2548 +	}
  1.2549 +	if (evbuffer_get_length(bufferevent_get_output(bev)) == 0) {
  1.2550 +		/* enable reading of the reply */
  1.2551 +		bufferevent_enable(bev, EV_READ);
  1.2552 +		test_ok++;
  1.2553 +	}
  1.2554 +}
  1.2555 +
  1.2556 +static void
  1.2557 +_http_incomplete_test(struct basic_test_data *data, int use_timeout)
  1.2558 +{
  1.2559 +	struct bufferevent *bev;
  1.2560 +	evutil_socket_t fd;
  1.2561 +	const char *http_request;
  1.2562 +	ev_uint16_t port = 0;
  1.2563 +	struct timeval tv_start, tv_end;
  1.2564 +
  1.2565 +	exit_base = data->base;
  1.2566 +
  1.2567 +	test_ok = 0;
  1.2568 +
  1.2569 +	http = http_setup(&port, data->base);
  1.2570 +	evhttp_set_timeout(http, 1);
  1.2571 +
  1.2572 +	fd = http_connect("127.0.0.1", port);
  1.2573 +
  1.2574 +	/* Stupid thing to send a request */
  1.2575 +	bev = bufferevent_socket_new(data->base, fd, 0);
  1.2576 +	bufferevent_setcb(bev,
  1.2577 +	    http_incomplete_readcb, http_incomplete_writecb,
  1.2578 +	    http_incomplete_errorcb, use_timeout ? NULL : &fd);
  1.2579 +
  1.2580 +	http_request =
  1.2581 +	    "GET /test HTTP/1.1\r\n"
  1.2582 +	    "Host: somehost\r\n";
  1.2583 +
  1.2584 +	bufferevent_write(bev, http_request, strlen(http_request));
  1.2585 +
  1.2586 +	evutil_gettimeofday(&tv_start, NULL);
  1.2587 +
  1.2588 +	event_base_dispatch(data->base);
  1.2589 +
  1.2590 +	evutil_gettimeofday(&tv_end, NULL);
  1.2591 +	evutil_timersub(&tv_end, &tv_start, &tv_end);
  1.2592 +
  1.2593 +	bufferevent_free(bev);
  1.2594 +	if (use_timeout) {
  1.2595 +		evutil_closesocket(fd);
  1.2596 +	}
  1.2597 +
  1.2598 +	evhttp_free(http);
  1.2599 +
  1.2600 +	if (use_timeout && tv_end.tv_sec >= 3) {
  1.2601 +		tt_abort_msg("time");
  1.2602 +	} else if (!use_timeout && tv_end.tv_sec >= 1) {
  1.2603 +		/* we should be done immediately */
  1.2604 +		tt_abort_msg("time");
  1.2605 +	}
  1.2606 +
  1.2607 +	tt_int_op(test_ok, ==, 2);
  1.2608 + end:
  1.2609 +	;
  1.2610 +}
  1.2611 +static void
  1.2612 +http_incomplete_test(void *arg)
  1.2613 +{
  1.2614 +	_http_incomplete_test(arg, 0);
  1.2615 +}
  1.2616 +static void
  1.2617 +http_incomplete_timeout_test(void *arg)
  1.2618 +{
  1.2619 +	_http_incomplete_test(arg, 1);
  1.2620 +}
  1.2621 +
  1.2622 +/*
  1.2623 + * the server is going to reply with chunked data.
  1.2624 + */
  1.2625 +
  1.2626 +static void
  1.2627 +http_chunked_readcb(struct bufferevent *bev, void *arg)
  1.2628 +{
  1.2629 +	/* nothing here */
  1.2630 +}
  1.2631 +
  1.2632 +static void
  1.2633 +http_chunked_errorcb(struct bufferevent *bev, short what, void *arg)
  1.2634 +{
  1.2635 +	if (!test_ok)
  1.2636 +		goto out;
  1.2637 +
  1.2638 +	test_ok = -1;
  1.2639 +
  1.2640 +	if ((what & BEV_EVENT_EOF) != 0) {
  1.2641 +		struct evhttp_request *req = evhttp_request_new(NULL, NULL);
  1.2642 +		const char *header;
  1.2643 +		enum message_read_status done;
  1.2644 +
  1.2645 +		/* req->kind = EVHTTP_RESPONSE; */
  1.2646 +		done = evhttp_parse_firstline(req, bufferevent_get_input(bev));
  1.2647 +		if (done != ALL_DATA_READ)
  1.2648 +			goto out;
  1.2649 +
  1.2650 +		done = evhttp_parse_headers(req, bufferevent_get_input(bev));
  1.2651 +		if (done != ALL_DATA_READ)
  1.2652 +			goto out;
  1.2653 +
  1.2654 +		header = evhttp_find_header(evhttp_request_get_input_headers(req), "Transfer-Encoding");
  1.2655 +		if (header == NULL || strcmp(header, "chunked"))
  1.2656 +			goto out;
  1.2657 +
  1.2658 +		header = evhttp_find_header(evhttp_request_get_input_headers(req), "Connection");
  1.2659 +		if (header == NULL || strcmp(header, "close"))
  1.2660 +			goto out;
  1.2661 +
  1.2662 +		header = evbuffer_readln(bufferevent_get_input(bev), NULL, EVBUFFER_EOL_CRLF);
  1.2663 +		if (header == NULL)
  1.2664 +			goto out;
  1.2665 +		/* 13 chars */
  1.2666 +		if (strcmp(header, "d")) {
  1.2667 +			free((void*)header);
  1.2668 +			goto out;
  1.2669 +		}
  1.2670 +		free((void*)header);
  1.2671 +
  1.2672 +		if (strncmp((char *)evbuffer_pullup(bufferevent_get_input(bev), 13),
  1.2673 +			"This is funny", 13))
  1.2674 +			goto out;
  1.2675 +
  1.2676 +		evbuffer_drain(bufferevent_get_input(bev), 13 + 2);
  1.2677 +
  1.2678 +		header = evbuffer_readln(bufferevent_get_input(bev), NULL, EVBUFFER_EOL_CRLF);
  1.2679 +		if (header == NULL)
  1.2680 +			goto out;
  1.2681 +		/* 18 chars */
  1.2682 +		if (strcmp(header, "12"))
  1.2683 +			goto out;
  1.2684 +		free((char *)header);
  1.2685 +
  1.2686 +		if (strncmp((char *)evbuffer_pullup(bufferevent_get_input(bev), 18),
  1.2687 +			"but not hilarious.", 18))
  1.2688 +			goto out;
  1.2689 +
  1.2690 +		evbuffer_drain(bufferevent_get_input(bev), 18 + 2);
  1.2691 +
  1.2692 +		header = evbuffer_readln(bufferevent_get_input(bev), NULL, EVBUFFER_EOL_CRLF);
  1.2693 +		if (header == NULL)
  1.2694 +			goto out;
  1.2695 +		/* 8 chars */
  1.2696 +		if (strcmp(header, "8")) {
  1.2697 +			free((void*)header);
  1.2698 +			goto out;
  1.2699 +		}
  1.2700 +		free((char *)header);
  1.2701 +
  1.2702 +		if (strncmp((char *)evbuffer_pullup(bufferevent_get_input(bev), 8),
  1.2703 +			"bwv 1052.", 8))
  1.2704 +			goto out;
  1.2705 +
  1.2706 +		evbuffer_drain(bufferevent_get_input(bev), 8 + 2);
  1.2707 +
  1.2708 +		header = evbuffer_readln(bufferevent_get_input(bev), NULL, EVBUFFER_EOL_CRLF);
  1.2709 +		if (header == NULL)
  1.2710 +			goto out;
  1.2711 +		/* 0 chars */
  1.2712 +		if (strcmp(header, "0")) {
  1.2713 +			free((void*)header);
  1.2714 +			goto out;
  1.2715 +		}
  1.2716 +		free((void *)header);
  1.2717 +
  1.2718 +		test_ok = 2;
  1.2719 +
  1.2720 +		evhttp_request_free(req);
  1.2721 +	}
  1.2722 +
  1.2723 +out:
  1.2724 +	event_base_loopexit(arg, NULL);
  1.2725 +}
  1.2726 +
  1.2727 +static void
  1.2728 +http_chunked_writecb(struct bufferevent *bev, void *arg)
  1.2729 +{
  1.2730 +	if (evbuffer_get_length(bufferevent_get_output(bev)) == 0) {
  1.2731 +		/* enable reading of the reply */
  1.2732 +		bufferevent_enable(bev, EV_READ);
  1.2733 +		test_ok++;
  1.2734 +	}
  1.2735 +}
  1.2736 +
  1.2737 +static void
  1.2738 +http_chunked_request_done(struct evhttp_request *req, void *arg)
  1.2739 +{
  1.2740 +	if (evhttp_request_get_response_code(req) != HTTP_OK) {
  1.2741 +		fprintf(stderr, "FAILED\n");
  1.2742 +		exit(1);
  1.2743 +	}
  1.2744 +
  1.2745 +	if (evhttp_find_header(evhttp_request_get_input_headers(req),
  1.2746 +		"Transfer-Encoding") == NULL) {
  1.2747 +		fprintf(stderr, "FAILED\n");
  1.2748 +		exit(1);
  1.2749 +	}
  1.2750 +
  1.2751 +	if (evbuffer_get_length(evhttp_request_get_input_buffer(req)) != 13 + 18 + 8) {
  1.2752 +		fprintf(stderr, "FAILED\n");
  1.2753 +		exit(1);
  1.2754 +	}
  1.2755 +
  1.2756 +	if (strncmp((char *)evbuffer_pullup(evhttp_request_get_input_buffer(req), 13 + 18 + 8),
  1.2757 +		"This is funnybut not hilarious.bwv 1052",
  1.2758 +		13 + 18 + 8)) {
  1.2759 +		fprintf(stderr, "FAILED\n");
  1.2760 +		exit(1);
  1.2761 +	}
  1.2762 +
  1.2763 +	test_ok = 1;
  1.2764 +	event_base_loopexit(arg, NULL);
  1.2765 +}
  1.2766 +
  1.2767 +static void
  1.2768 +http_chunk_out_test(void *arg)
  1.2769 +{
  1.2770 +	struct basic_test_data *data = arg;
  1.2771 +	struct bufferevent *bev;
  1.2772 +	evutil_socket_t fd;
  1.2773 +	const char *http_request;
  1.2774 +	ev_uint16_t port = 0;
  1.2775 +	struct timeval tv_start, tv_end;
  1.2776 +	struct evhttp_connection *evcon = NULL;
  1.2777 +	struct evhttp_request *req = NULL;
  1.2778 +	int i;
  1.2779 +
  1.2780 +	exit_base = data->base;
  1.2781 +	test_ok = 0;
  1.2782 +
  1.2783 +	http = http_setup(&port, data->base);
  1.2784 +
  1.2785 +	fd = http_connect("127.0.0.1", port);
  1.2786 +
  1.2787 +	/* Stupid thing to send a request */
  1.2788 +	bev = bufferevent_socket_new(data->base, fd, 0);
  1.2789 +	bufferevent_setcb(bev,
  1.2790 +	    http_chunked_readcb, http_chunked_writecb,
  1.2791 +	    http_chunked_errorcb, data->base);
  1.2792 +
  1.2793 +	http_request =
  1.2794 +	    "GET /chunked HTTP/1.1\r\n"
  1.2795 +	    "Host: somehost\r\n"
  1.2796 +	    "Connection: close\r\n"
  1.2797 +	    "\r\n";
  1.2798 +
  1.2799 +	bufferevent_write(bev, http_request, strlen(http_request));
  1.2800 +
  1.2801 +	evutil_gettimeofday(&tv_start, NULL);
  1.2802 +
  1.2803 +	event_base_dispatch(data->base);
  1.2804 +
  1.2805 +	bufferevent_free(bev);
  1.2806 +
  1.2807 +	evutil_gettimeofday(&tv_end, NULL);
  1.2808 +	evutil_timersub(&tv_end, &tv_start, &tv_end);
  1.2809 +
  1.2810 +	tt_int_op(tv_end.tv_sec, <, 1);
  1.2811 +
  1.2812 +	tt_int_op(test_ok, ==, 2);
  1.2813 +
  1.2814 +	/* now try again with the regular connection object */
  1.2815 +	evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port);
  1.2816 +	tt_assert(evcon);
  1.2817 +
  1.2818 +	/* make two requests to check the keepalive behavior */
  1.2819 +	for (i = 0; i < 2; i++) {
  1.2820 +		test_ok = 0;
  1.2821 +		req = evhttp_request_new(http_chunked_request_done,data->base);
  1.2822 +
  1.2823 +		/* Add the information that we care about */
  1.2824 +		evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
  1.2825 +
  1.2826 +		/* We give ownership of the request to the connection */
  1.2827 +		if (evhttp_make_request(evcon, req,
  1.2828 +			EVHTTP_REQ_GET, "/chunked") == -1) {
  1.2829 +			tt_abort_msg("Couldn't make request");
  1.2830 +		}
  1.2831 +
  1.2832 +		event_base_dispatch(data->base);
  1.2833 +
  1.2834 +		tt_assert(test_ok == 1);
  1.2835 +	}
  1.2836 +
  1.2837 + end:
  1.2838 +	if (evcon)
  1.2839 +		evhttp_connection_free(evcon);
  1.2840 +	if (http)
  1.2841 +		evhttp_free(http);
  1.2842 +}
  1.2843 +
  1.2844 +static void
  1.2845 +http_stream_out_test(void *arg)
  1.2846 +{
  1.2847 +	struct basic_test_data *data = arg;
  1.2848 +	ev_uint16_t port = 0;
  1.2849 +	struct evhttp_connection *evcon = NULL;
  1.2850 +	struct evhttp_request *req = NULL;
  1.2851 +
  1.2852 +	test_ok = 0;
  1.2853 +	exit_base = data->base;
  1.2854 +
  1.2855 +	http = http_setup(&port, data->base);
  1.2856 +
  1.2857 +	evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port);
  1.2858 +	tt_assert(evcon);
  1.2859 +
  1.2860 +	/*
  1.2861 +	 * At this point, we want to schedule a request to the HTTP
  1.2862 +	 * server using our make request method.
  1.2863 +	 */
  1.2864 +
  1.2865 +	req = evhttp_request_new(http_request_done,
  1.2866 +	    (void *)"This is funnybut not hilarious.bwv 1052");
  1.2867 +
  1.2868 +	/* Add the information that we care about */
  1.2869 +	evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
  1.2870 +
  1.2871 +	/* We give ownership of the request to the connection */
  1.2872 +	if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/streamed")
  1.2873 +	    == -1) {
  1.2874 +		tt_abort_msg("Couldn't make request");
  1.2875 +	}
  1.2876 +
  1.2877 +	event_base_dispatch(data->base);
  1.2878 +
  1.2879 + end:
  1.2880 +	if (evcon)
  1.2881 +		evhttp_connection_free(evcon);
  1.2882 +	if (http)
  1.2883 +		evhttp_free(http);
  1.2884 +}
  1.2885 +
  1.2886 +static void
  1.2887 +http_stream_in_chunk(struct evhttp_request *req, void *arg)
  1.2888 +{
  1.2889 +	struct evbuffer *reply = arg;
  1.2890 +
  1.2891 +	if (evhttp_request_get_response_code(req) != HTTP_OK) {
  1.2892 +		fprintf(stderr, "FAILED\n");
  1.2893 +		exit(1);
  1.2894 +	}
  1.2895 +
  1.2896 +	evbuffer_add_buffer(reply, evhttp_request_get_input_buffer(req));
  1.2897 +}
  1.2898 +
  1.2899 +static void
  1.2900 +http_stream_in_done(struct evhttp_request *req, void *arg)
  1.2901 +{
  1.2902 +	if (evbuffer_get_length(evhttp_request_get_input_buffer(req)) != 0) {
  1.2903 +		fprintf(stderr, "FAILED\n");
  1.2904 +		exit(1);
  1.2905 +	}
  1.2906 +
  1.2907 +	event_base_loopexit(exit_base, NULL);
  1.2908 +}
  1.2909 +
  1.2910 +/**
  1.2911 + * Makes a request and reads the response in chunks.
  1.2912 + */
  1.2913 +static void
  1.2914 +_http_stream_in_test(struct basic_test_data *data, char const *url,
  1.2915 +    size_t expected_len, char const *expected)
  1.2916 +{
  1.2917 +	struct evhttp_connection *evcon;
  1.2918 +	struct evbuffer *reply = evbuffer_new();
  1.2919 +	struct evhttp_request *req = NULL;
  1.2920 +	ev_uint16_t port = 0;
  1.2921 +
  1.2922 +	exit_base = data->base;
  1.2923 +	http = http_setup(&port, data->base);
  1.2924 +
  1.2925 +	evcon = evhttp_connection_base_new(data->base, NULL,"127.0.0.1", port);
  1.2926 +	tt_assert(evcon);
  1.2927 +
  1.2928 +	req = evhttp_request_new(http_stream_in_done, reply);
  1.2929 +	evhttp_request_set_chunked_cb(req, http_stream_in_chunk);
  1.2930 +
  1.2931 +	/* We give ownership of the request to the connection */
  1.2932 +	if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, url) == -1) {
  1.2933 +		tt_abort_msg("Couldn't make request");
  1.2934 +	}
  1.2935 +
  1.2936 +	event_base_dispatch(data->base);
  1.2937 +
  1.2938 +	if (evbuffer_get_length(reply) != expected_len) {
  1.2939 +		TT_DIE(("reply length %lu; expected %lu; FAILED (%s)\n",
  1.2940 +				(unsigned long)evbuffer_get_length(reply),
  1.2941 +				(unsigned long)expected_len,
  1.2942 +				(char*)evbuffer_pullup(reply, -1)));
  1.2943 +	}
  1.2944 +
  1.2945 +	if (memcmp(evbuffer_pullup(reply, -1), expected, expected_len) != 0) {
  1.2946 +		tt_abort_msg("Memory mismatch");
  1.2947 +	}
  1.2948 +
  1.2949 +	test_ok = 1;
  1.2950 + end:
  1.2951 +	if (reply)
  1.2952 +		evbuffer_free(reply);
  1.2953 +	if (evcon)
  1.2954 +		evhttp_connection_free(evcon);
  1.2955 +	if (http)
  1.2956 +		evhttp_free(http);
  1.2957 +}
  1.2958 +
  1.2959 +static void
  1.2960 +http_stream_in_test(void *arg)
  1.2961 +{
  1.2962 +	_http_stream_in_test(arg, "/chunked", 13 + 18 + 8,
  1.2963 +	    "This is funnybut not hilarious.bwv 1052");
  1.2964 +
  1.2965 +	_http_stream_in_test(arg, "/test", strlen(BASIC_REQUEST_BODY),
  1.2966 +	    BASIC_REQUEST_BODY);
  1.2967 +}
  1.2968 +
  1.2969 +static void
  1.2970 +http_stream_in_cancel_chunk(struct evhttp_request *req, void *arg)
  1.2971 +{
  1.2972 +	tt_int_op(evhttp_request_get_response_code(req), ==, HTTP_OK);
  1.2973 +
  1.2974 + end:
  1.2975 +	evhttp_cancel_request(req);
  1.2976 +	event_base_loopexit(arg, NULL);
  1.2977 +}
  1.2978 +
  1.2979 +static void
  1.2980 +http_stream_in_cancel_done(struct evhttp_request *req, void *arg)
  1.2981 +{
  1.2982 +	/* should never be called */
  1.2983 +	tt_fail_msg("In cancel done");
  1.2984 +}
  1.2985 +
  1.2986 +static void
  1.2987 +http_stream_in_cancel_test(void *arg)
  1.2988 +{
  1.2989 +	struct basic_test_data *data = arg;
  1.2990 +	struct evhttp_connection *evcon;
  1.2991 +	struct evhttp_request *req = NULL;
  1.2992 +	ev_uint16_t port = 0;
  1.2993 +
  1.2994 +	http = http_setup(&port, data->base);
  1.2995 +
  1.2996 +	evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port);
  1.2997 +	tt_assert(evcon);
  1.2998 +
  1.2999 +	req = evhttp_request_new(http_stream_in_cancel_done, data->base);
  1.3000 +	evhttp_request_set_chunked_cb(req, http_stream_in_cancel_chunk);
  1.3001 +
  1.3002 +	/* We give ownership of the request to the connection */
  1.3003 +	if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/chunked") == -1) {
  1.3004 +		tt_abort_msg("Couldn't make request");
  1.3005 +	}
  1.3006 +
  1.3007 +	event_base_dispatch(data->base);
  1.3008 +
  1.3009 +	test_ok = 1;
  1.3010 + end:
  1.3011 +	evhttp_connection_free(evcon);
  1.3012 +	evhttp_free(http);
  1.3013 +
  1.3014 +}
  1.3015 +
  1.3016 +static void
  1.3017 +http_connection_fail_done(struct evhttp_request *req, void *arg)
  1.3018 +{
  1.3019 +       /* An ENETUNREACH error results in an unrecoverable
  1.3020 +        * evhttp_connection error (see evhttp_connection_fail()).  The
  1.3021 +        * connection will be reset, and the user will be notified with a NULL
  1.3022 +        * req parameter. */
  1.3023 +       tt_assert(!req);
  1.3024 +
  1.3025 +       test_ok = 1;
  1.3026 +
  1.3027 + end:
  1.3028 +       event_base_loopexit(arg, NULL);
  1.3029 +}
  1.3030 +
  1.3031 +/* Test unrecoverable evhttp_connection errors by generating an ENETUNREACH
  1.3032 + * error on connection. */
  1.3033 +static void
  1.3034 +http_connection_fail_test(void *arg)
  1.3035 +{
  1.3036 +       struct basic_test_data *data = arg;
  1.3037 +       ev_uint16_t port = 0;
  1.3038 +       struct evhttp_connection *evcon = NULL;
  1.3039 +       struct evhttp_request *req = NULL;
  1.3040 +
  1.3041 +       exit_base = data->base;
  1.3042 +       test_ok = 0;
  1.3043 +
  1.3044 +       /* auto detect a port */
  1.3045 +       http = http_setup(&port, data->base);
  1.3046 +       evhttp_free(http);
  1.3047 +       http = NULL;
  1.3048 +
  1.3049 +       /* Pick an unroutable address.  This administratively scoped multicast
  1.3050 +	* address should do when working with TCP. */
  1.3051 +       evcon = evhttp_connection_base_new(data->base, NULL, "239.10.20.30", 80);
  1.3052 +       tt_assert(evcon);
  1.3053 +
  1.3054 +       /*
  1.3055 +        * At this point, we want to schedule an HTTP GET request
  1.3056 +        * server using our make request method.
  1.3057 +        */
  1.3058 +
  1.3059 +       req = evhttp_request_new(http_connection_fail_done, data->base);
  1.3060 +       tt_assert(req);
  1.3061 +
  1.3062 +       if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/") == -1) {
  1.3063 +               tt_abort_msg("Couldn't make request");
  1.3064 +       }
  1.3065 +
  1.3066 +       event_base_dispatch(data->base);
  1.3067 +
  1.3068 +       tt_int_op(test_ok, ==, 1);
  1.3069 +
  1.3070 + end:
  1.3071 +       if (evcon)
  1.3072 +               evhttp_connection_free(evcon);
  1.3073 +}
  1.3074 +
  1.3075 +static void
  1.3076 +http_connection_retry_done(struct evhttp_request *req, void *arg)
  1.3077 +{
  1.3078 +	tt_assert(req);
  1.3079 +	tt_int_op(evhttp_request_get_response_code(req), !=, HTTP_OK);
  1.3080 +	if (evhttp_find_header(evhttp_request_get_input_headers(req), "Content-Type") != NULL) {
  1.3081 +		tt_abort_msg("(content type)\n");
  1.3082 +	}
  1.3083 +
  1.3084 +	tt_uint_op(evbuffer_get_length(evhttp_request_get_input_buffer(req)), ==, 0);
  1.3085 +
  1.3086 +	test_ok = 1;
  1.3087 + end:
  1.3088 +	event_base_loopexit(arg,NULL);
  1.3089 +}
  1.3090 +
  1.3091 +static struct event_base *http_make_web_server_base=NULL;
  1.3092 +static void
  1.3093 +http_make_web_server(evutil_socket_t fd, short what, void *arg)
  1.3094 +{
  1.3095 +	ev_uint16_t port = *(ev_uint16_t*)arg;
  1.3096 +	http = http_setup(&port, http_make_web_server_base);
  1.3097 +}
  1.3098 +
  1.3099 +static void
  1.3100 +http_connection_retry_test(void *arg)
  1.3101 +{
  1.3102 +	struct basic_test_data *data = arg;
  1.3103 +	ev_uint16_t port = 0;
  1.3104 +	struct evhttp_connection *evcon = NULL;
  1.3105 +	struct evhttp_request *req = NULL;
  1.3106 +	struct timeval tv, tv_start, tv_end;
  1.3107 +
  1.3108 +	exit_base = data->base;
  1.3109 +	test_ok = 0;
  1.3110 +
  1.3111 +	/* auto detect a port */
  1.3112 +	http = http_setup(&port, data->base);
  1.3113 +	evhttp_free(http);
  1.3114 +	http = NULL;
  1.3115 +
  1.3116 +	evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port);
  1.3117 +	tt_assert(evcon);
  1.3118 +
  1.3119 +	evhttp_connection_set_timeout(evcon, 1);
  1.3120 +	/* also bind to local host */
  1.3121 +	evhttp_connection_set_local_address(evcon, "127.0.0.1");
  1.3122 +
  1.3123 +	/*
  1.3124 +	 * At this point, we want to schedule an HTTP GET request
  1.3125 +	 * server using our make request method.
  1.3126 +	 */
  1.3127 +
  1.3128 +	req = evhttp_request_new(http_connection_retry_done, data->base);
  1.3129 +	tt_assert(req);
  1.3130 +
  1.3131 +	/* Add the information that we care about */
  1.3132 +	evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
  1.3133 +
  1.3134 +	if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET,
  1.3135 +		"/?arg=val") == -1) {
  1.3136 +		tt_abort_msg("Couldn't make request");
  1.3137 +	}
  1.3138 +
  1.3139 +	evutil_gettimeofday(&tv_start, NULL);
  1.3140 +	event_base_dispatch(data->base);
  1.3141 +	evutil_gettimeofday(&tv_end, NULL);
  1.3142 +	evutil_timersub(&tv_end, &tv_start, &tv_end);
  1.3143 +	tt_int_op(tv_end.tv_sec, <, 1);
  1.3144 +
  1.3145 +	tt_int_op(test_ok, ==, 1);
  1.3146 +
  1.3147 +	/*
  1.3148 +	 * now test the same but with retries
  1.3149 +	 */
  1.3150 +	test_ok = 0;
  1.3151 +
  1.3152 +	evhttp_connection_set_timeout(evcon, 1);
  1.3153 +	evhttp_connection_set_retries(evcon, 1);
  1.3154 +
  1.3155 +	req = evhttp_request_new(http_connection_retry_done, data->base);
  1.3156 +	tt_assert(req);
  1.3157 +
  1.3158 +	/* Add the information that we care about */
  1.3159 +	evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
  1.3160 +
  1.3161 +	if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET,
  1.3162 +		"/?arg=val") == -1) {
  1.3163 +		tt_abort_msg("Couldn't make request");
  1.3164 +	}
  1.3165 +
  1.3166 +	evutil_gettimeofday(&tv_start, NULL);
  1.3167 +	event_base_dispatch(data->base);
  1.3168 +	evutil_gettimeofday(&tv_end, NULL);
  1.3169 +	evutil_timersub(&tv_end, &tv_start, &tv_end);
  1.3170 +	tt_int_op(tv_end.tv_sec, >, 1);
  1.3171 +	tt_int_op(tv_end.tv_sec, <, 6);
  1.3172 +
  1.3173 +	tt_assert(test_ok == 1);
  1.3174 +
  1.3175 +	/*
  1.3176 +	 * now test the same but with retries and give it a web server
  1.3177 +	 * at the end
  1.3178 +	 */
  1.3179 +	test_ok = 0;
  1.3180 +
  1.3181 +	evhttp_connection_set_timeout(evcon, 1);
  1.3182 +	evhttp_connection_set_retries(evcon, 3);
  1.3183 +
  1.3184 +	req = evhttp_request_new(http_dispatcher_test_done, data->base);
  1.3185 +	tt_assert(req);
  1.3186 +
  1.3187 +	/* Add the information that we care about */
  1.3188 +	evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
  1.3189 +
  1.3190 +	if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET,
  1.3191 +		"/?arg=val") == -1) {
  1.3192 +		tt_abort_msg("Couldn't make request");
  1.3193 +	}
  1.3194 +
  1.3195 +	/* start up a web server one second after the connection tried
  1.3196 +	 * to send a request
  1.3197 +	 */
  1.3198 +	evutil_timerclear(&tv);
  1.3199 +	tv.tv_sec = 1;
  1.3200 +	http_make_web_server_base = data->base;
  1.3201 +	event_base_once(data->base, -1, EV_TIMEOUT, http_make_web_server, &port, &tv);
  1.3202 +
  1.3203 +	evutil_gettimeofday(&tv_start, NULL);
  1.3204 +	event_base_dispatch(data->base);
  1.3205 +	evutil_gettimeofday(&tv_end, NULL);
  1.3206 +
  1.3207 +	evutil_timersub(&tv_end, &tv_start, &tv_end);
  1.3208 +
  1.3209 +	tt_int_op(tv_end.tv_sec, >, 1);
  1.3210 +	tt_int_op(tv_end.tv_sec, <, 6);
  1.3211 +
  1.3212 +	tt_int_op(test_ok, ==, 1);
  1.3213 +
  1.3214 + end:
  1.3215 +	if (evcon)
  1.3216 +		evhttp_connection_free(evcon);
  1.3217 +	if (http)
  1.3218 +		evhttp_free(http);
  1.3219 +}
  1.3220 +
  1.3221 +static void
  1.3222 +http_primitives(void *ptr)
  1.3223 +{
  1.3224 +	char *escaped = NULL;
  1.3225 +	struct evhttp *http = NULL;
  1.3226 +
  1.3227 +	escaped = evhttp_htmlescape("<script>");
  1.3228 +	tt_assert(escaped);
  1.3229 +	tt_str_op(escaped, ==, "&lt;script&gt;");
  1.3230 +	free(escaped);
  1.3231 +
  1.3232 +	escaped = evhttp_htmlescape("\"\'&");
  1.3233 +	tt_assert(escaped);
  1.3234 +	tt_str_op(escaped, ==, "&quot;&#039;&amp;");
  1.3235 +
  1.3236 +	http = evhttp_new(NULL);
  1.3237 +	tt_assert(http);
  1.3238 +	tt_int_op(evhttp_set_cb(http, "/test", http_basic_cb, NULL), ==, 0);
  1.3239 +	tt_int_op(evhttp_set_cb(http, "/test", http_basic_cb, NULL), ==, -1);
  1.3240 +	tt_int_op(evhttp_del_cb(http, "/test"), ==, 0);
  1.3241 +	tt_int_op(evhttp_del_cb(http, "/test"), ==, -1);
  1.3242 +	tt_int_op(evhttp_set_cb(http, "/test", http_basic_cb, NULL), ==, 0);
  1.3243 +
  1.3244 + end:
  1.3245 +	if (escaped)
  1.3246 +		free(escaped);
  1.3247 +	if (http)
  1.3248 +		evhttp_free(http);
  1.3249 +}
  1.3250 +
  1.3251 +static void
  1.3252 +http_multi_line_header_test(void *arg)
  1.3253 +{
  1.3254 +	struct basic_test_data *data = arg;
  1.3255 +	struct bufferevent *bev= NULL;
  1.3256 +	evutil_socket_t fd = -1;
  1.3257 +	const char *http_start_request;
  1.3258 +	ev_uint16_t port = 0;
  1.3259 +
  1.3260 +	test_ok = 0;
  1.3261 +
  1.3262 +	http = http_setup(&port, data->base);
  1.3263 +
  1.3264 +	fd = http_connect("127.0.0.1", port);
  1.3265 +
  1.3266 +	/* Stupid thing to send a request */
  1.3267 +	bev = bufferevent_socket_new(data->base, fd, 0);
  1.3268 +	bufferevent_setcb(bev, http_readcb, http_writecb,
  1.3269 +	    http_errorcb, data->base);
  1.3270 +
  1.3271 +	http_start_request =
  1.3272 +	    "GET /test HTTP/1.1\r\n"
  1.3273 +	    "Host: somehost\r\n"
  1.3274 +	    "Connection: close\r\n"
  1.3275 +	    "X-Multi:  aaaaaaaa\r\n"
  1.3276 +	    " a\r\n"
  1.3277 +	    "\tEND\r\n"
  1.3278 +	    "X-Last: last\r\n"
  1.3279 +	    "\r\n";
  1.3280 +
  1.3281 +	bufferevent_write(bev, http_start_request, strlen(http_start_request));
  1.3282 +
  1.3283 +	event_base_dispatch(data->base);
  1.3284 +
  1.3285 +	tt_int_op(test_ok, ==, 4);
  1.3286 + end:
  1.3287 +	if (bev)
  1.3288 +		bufferevent_free(bev);
  1.3289 +	if (fd >= 0)
  1.3290 +		evutil_closesocket(fd);
  1.3291 +	if (http)
  1.3292 +		evhttp_free(http);
  1.3293 +}
  1.3294 +
  1.3295 +static void
  1.3296 +http_request_bad(struct evhttp_request *req, void *arg)
  1.3297 +{
  1.3298 +	if (req != NULL) {
  1.3299 +		fprintf(stderr, "FAILED\n");
  1.3300 +		exit(1);
  1.3301 +	}
  1.3302 +
  1.3303 +	test_ok = 1;
  1.3304 +	event_base_loopexit(arg, NULL);
  1.3305 +}
  1.3306 +
  1.3307 +static void
  1.3308 +http_negative_content_length_test(void *arg)
  1.3309 +{
  1.3310 +	struct basic_test_data *data = arg;
  1.3311 +	ev_uint16_t port = 0;
  1.3312 +	struct evhttp_connection *evcon = NULL;
  1.3313 +	struct evhttp_request *req = NULL;
  1.3314 +
  1.3315 +	test_ok = 0;
  1.3316 +
  1.3317 +	http = http_setup(&port, data->base);
  1.3318 +
  1.3319 +	evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port);
  1.3320 +	tt_assert(evcon);
  1.3321 +
  1.3322 +	/*
  1.3323 +	 * At this point, we want to schedule a request to the HTTP
  1.3324 +	 * server using our make request method.
  1.3325 +	 */
  1.3326 +
  1.3327 +	req = evhttp_request_new(http_request_bad, data->base);
  1.3328 +
  1.3329 +	/* Cause the response to have a negative content-length */
  1.3330 +	evhttp_add_header(evhttp_request_get_output_headers(req), "X-Negative", "makeitso");
  1.3331 +
  1.3332 +	/* We give ownership of the request to the connection */
  1.3333 +	if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test") == -1) {
  1.3334 +		tt_abort_msg("Couldn't make request");
  1.3335 +	}
  1.3336 +
  1.3337 +	event_base_dispatch(data->base);
  1.3338 +
  1.3339 + end:
  1.3340 +	if (evcon)
  1.3341 +		evhttp_connection_free(evcon);
  1.3342 +	if (http)
  1.3343 +		evhttp_free(http);
  1.3344 +}
  1.3345 +
  1.3346 +
  1.3347 +static void
  1.3348 +http_data_length_constraints_test_done(struct evhttp_request *req, void *arg)
  1.3349 +{
  1.3350 +	tt_assert(req);
  1.3351 +	tt_int_op(evhttp_request_get_response_code(req), ==, HTTP_BADREQUEST);
  1.3352 +end:
  1.3353 +	event_base_loopexit(arg, NULL);
  1.3354 +}
  1.3355 +
  1.3356 +static void
  1.3357 +http_large_entity_test_done(struct evhttp_request *req, void *arg)
  1.3358 +{
  1.3359 +	tt_assert(req);
  1.3360 +	tt_int_op(evhttp_request_get_response_code(req), ==, HTTP_ENTITYTOOLARGE);
  1.3361 +end:
  1.3362 +	event_base_loopexit(arg, NULL);
  1.3363 +}
  1.3364 +
  1.3365 +static void
  1.3366 +http_data_length_constraints_test(void *arg)
  1.3367 +{
  1.3368 +	struct basic_test_data *data = arg;
  1.3369 +	ev_uint16_t port = 0;
  1.3370 +	struct evhttp_connection *evcon = NULL;
  1.3371 +	struct evhttp_request *req = NULL;
  1.3372 +	char long_str[8192];
  1.3373 +
  1.3374 +	test_ok = 0;
  1.3375 +
  1.3376 +	http = http_setup(&port, data->base);
  1.3377 +
  1.3378 +	evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port);
  1.3379 +	tt_assert(evcon);
  1.3380 +
  1.3381 +	/* also bind to local host */
  1.3382 +	evhttp_connection_set_local_address(evcon, "127.0.0.1");
  1.3383 +
  1.3384 +	/*
  1.3385 +	 * At this point, we want to schedule an HTTP GET request
  1.3386 +	 * server using our make request method.
  1.3387 +	 */
  1.3388 +
  1.3389 +	req = evhttp_request_new(http_data_length_constraints_test_done, data->base);
  1.3390 +	tt_assert(req);
  1.3391 +
  1.3392 +	memset(long_str, 'a', 8192);
  1.3393 +	long_str[8191] = '\0';
  1.3394 +	/* Add the information that we care about */
  1.3395 +	evhttp_set_max_headers_size(http, 8191);
  1.3396 +	evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
  1.3397 +	evhttp_add_header(evhttp_request_get_output_headers(req), "Longheader", long_str);
  1.3398 +
  1.3399 +	if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/?arg=val") == -1) {
  1.3400 +		tt_abort_msg("Couldn't make request");
  1.3401 +	}
  1.3402 +	event_base_dispatch(data->base);
  1.3403 +
  1.3404 +	req = evhttp_request_new(http_data_length_constraints_test_done, data->base);
  1.3405 +	tt_assert(req);
  1.3406 +	evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
  1.3407 +
  1.3408 +	/* GET /?arg=verylongvalue HTTP/1.1 */
  1.3409 +	if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, long_str) == -1) {
  1.3410 +		tt_abort_msg("Couldn't make request");
  1.3411 +	}
  1.3412 +	event_base_dispatch(data->base);
  1.3413 +
  1.3414 +	evhttp_set_max_body_size(http, 8190);
  1.3415 +	req = evhttp_request_new(http_data_length_constraints_test_done, data->base);
  1.3416 +	evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
  1.3417 +	evbuffer_add_printf(evhttp_request_get_output_buffer(req), "%s", long_str);
  1.3418 +	if (evhttp_make_request(evcon, req, EVHTTP_REQ_POST, "/") == -1) {
  1.3419 +		tt_abort_msg("Couldn't make request");
  1.3420 +	}
  1.3421 +	event_base_dispatch(data->base);
  1.3422 +
  1.3423 +	req = evhttp_request_new(http_large_entity_test_done, data->base);
  1.3424 +	evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
  1.3425 +	evhttp_add_header(evhttp_request_get_output_headers(req), "Expect", "100-continue");
  1.3426 +	evbuffer_add_printf(evhttp_request_get_output_buffer(req), "%s", long_str);
  1.3427 +	if (evhttp_make_request(evcon, req, EVHTTP_REQ_POST, "/") == -1) {
  1.3428 +		tt_abort_msg("Couldn't make request");
  1.3429 +	}
  1.3430 +	event_base_dispatch(data->base);
  1.3431 +
  1.3432 +	test_ok = 1;
  1.3433 + end:
  1.3434 +	if (evcon)
  1.3435 +		evhttp_connection_free(evcon);
  1.3436 +	if (http)
  1.3437 +		evhttp_free(http);
  1.3438 +}
  1.3439 +
  1.3440 +/*
  1.3441 + * Testing client reset of server chunked connections
  1.3442 + */
  1.3443 +
  1.3444 +struct terminate_state {
  1.3445 +	struct event_base *base;
  1.3446 +	struct evhttp_request *req;
  1.3447 +	struct bufferevent *bev;
  1.3448 +	evutil_socket_t fd;
  1.3449 +	int gotclosecb: 1;
  1.3450 +};
  1.3451 +
  1.3452 +static void
  1.3453 +terminate_chunked_trickle_cb(evutil_socket_t fd, short events, void *arg)
  1.3454 +{
  1.3455 +	struct terminate_state *state = arg;
  1.3456 +	struct evbuffer *evb;
  1.3457 +	struct timeval tv;
  1.3458 +
  1.3459 +	if (evhttp_request_get_connection(state->req) == NULL) {
  1.3460 +		test_ok = 1;
  1.3461 +		evhttp_request_free(state->req);
  1.3462 +		event_base_loopexit(state->base,NULL);
  1.3463 +		return;
  1.3464 +	}
  1.3465 +
  1.3466 +	evb = evbuffer_new();
  1.3467 +	evbuffer_add_printf(evb, "%p", evb);
  1.3468 +	evhttp_send_reply_chunk(state->req, evb);
  1.3469 +	evbuffer_free(evb);
  1.3470 +
  1.3471 +	tv.tv_sec = 0;
  1.3472 +	tv.tv_usec = 3000;
  1.3473 +	EVUTIL_ASSERT(state);
  1.3474 +	EVUTIL_ASSERT(state->base);
  1.3475 +	event_base_once(state->base, -1, EV_TIMEOUT, terminate_chunked_trickle_cb, arg, &tv);
  1.3476 +}
  1.3477 +
  1.3478 +static void
  1.3479 +terminate_chunked_close_cb(struct evhttp_connection *evcon, void *arg)
  1.3480 +{
  1.3481 +	struct terminate_state *state = arg;
  1.3482 +	state->gotclosecb = 1;
  1.3483 +}
  1.3484 +
  1.3485 +static void
  1.3486 +terminate_chunked_cb(struct evhttp_request *req, void *arg)
  1.3487 +{
  1.3488 +	struct terminate_state *state = arg;
  1.3489 +	struct timeval tv;
  1.3490 +
  1.3491 +	/* we want to know if this connection closes on us */
  1.3492 +	evhttp_connection_set_closecb(
  1.3493 +		evhttp_request_get_connection(req),
  1.3494 +		terminate_chunked_close_cb, arg);
  1.3495 +
  1.3496 +	state->req = req;
  1.3497 +
  1.3498 +	evhttp_send_reply_start(req, HTTP_OK, "OK");
  1.3499 +
  1.3500 +	tv.tv_sec = 0;
  1.3501 +	tv.tv_usec = 3000;
  1.3502 +	event_base_once(state->base, -1, EV_TIMEOUT, terminate_chunked_trickle_cb, arg, &tv);
  1.3503 +}
  1.3504 +
  1.3505 +static void
  1.3506 +terminate_chunked_client(evutil_socket_t fd, short event, void *arg)
  1.3507 +{
  1.3508 +	struct terminate_state *state = arg;
  1.3509 +	bufferevent_free(state->bev);
  1.3510 +	evutil_closesocket(state->fd);
  1.3511 +}
  1.3512 +
  1.3513 +static void
  1.3514 +terminate_readcb(struct bufferevent *bev, void *arg)
  1.3515 +{
  1.3516 +	/* just drop the data */
  1.3517 +	evbuffer_drain(bufferevent_get_input(bev), -1);
  1.3518 +}
  1.3519 +
  1.3520 +
  1.3521 +static void
  1.3522 +http_terminate_chunked_test(void *arg)
  1.3523 +{
  1.3524 +	struct basic_test_data *data = arg;
  1.3525 +	struct bufferevent *bev = NULL;
  1.3526 +	struct timeval tv;
  1.3527 +	const char *http_request;
  1.3528 +	ev_uint16_t port = 0;
  1.3529 +	evutil_socket_t fd = -1;
  1.3530 +	struct terminate_state terminate_state;
  1.3531 +
  1.3532 +	test_ok = 0;
  1.3533 +
  1.3534 +	http = http_setup(&port, data->base);
  1.3535 +	evhttp_del_cb(http, "/test");
  1.3536 +	tt_assert(evhttp_set_cb(http, "/test",
  1.3537 +		terminate_chunked_cb, &terminate_state) == 0);
  1.3538 +
  1.3539 +	fd = http_connect("127.0.0.1", port);
  1.3540 +
  1.3541 +	/* Stupid thing to send a request */
  1.3542 +	bev = bufferevent_socket_new(data->base, fd, 0);
  1.3543 +	bufferevent_setcb(bev, terminate_readcb, http_writecb,
  1.3544 +	    http_errorcb, data->base);
  1.3545 +
  1.3546 +	memset(&terminate_state, 0, sizeof(terminate_state));
  1.3547 +	terminate_state.base = data->base;
  1.3548 +	terminate_state.fd = fd;
  1.3549 +	terminate_state.bev = bev;
  1.3550 +	terminate_state.gotclosecb = 0;
  1.3551 +
  1.3552 +	/* first half of the http request */
  1.3553 +	http_request =
  1.3554 +	    "GET /test HTTP/1.1\r\n"
  1.3555 +	    "Host: some\r\n\r\n";
  1.3556 +
  1.3557 +	bufferevent_write(bev, http_request, strlen(http_request));
  1.3558 +	evutil_timerclear(&tv);
  1.3559 +	tv.tv_usec = 10000;
  1.3560 +	event_base_once(data->base, -1, EV_TIMEOUT, terminate_chunked_client, &terminate_state,
  1.3561 +	    &tv);
  1.3562 +
  1.3563 +	event_base_dispatch(data->base);
  1.3564 +
  1.3565 +	if (terminate_state.gotclosecb == 0)
  1.3566 +		test_ok = 0;
  1.3567 +
  1.3568 + end:
  1.3569 +	if (fd >= 0)
  1.3570 +		evutil_closesocket(fd);
  1.3571 +	if (http)
  1.3572 +		evhttp_free(http);
  1.3573 +}
  1.3574 +
  1.3575 +#define HTTP_LEGACY(name)						\
  1.3576 +	{ #name, run_legacy_test_fn, TT_ISOLATED|TT_LEGACY, &legacy_setup, \
  1.3577 +		    http_##name##_test }
  1.3578 +
  1.3579 +#define HTTP(name) \
  1.3580 +	{ #name, http_##name##_test, TT_ISOLATED, &basic_setup, NULL }
  1.3581 +
  1.3582 +struct testcase_t http_testcases[] = {
  1.3583 +	{ "primitives", http_primitives, 0, NULL, NULL },
  1.3584 +	{ "base", http_base_test, TT_FORK, NULL, NULL },
  1.3585 +	{ "bad_headers", http_bad_header_test, 0, NULL, NULL },
  1.3586 +	{ "parse_query", http_parse_query_test, 0, NULL, NULL },
  1.3587 +	{ "parse_uri", http_parse_uri_test, 0, NULL, NULL },
  1.3588 +	{ "parse_uri_nc", http_parse_uri_test, 0, &basic_setup, (void*)"nc" },
  1.3589 +	{ "uriencode", http_uriencode_test, 0, NULL, NULL },
  1.3590 +	HTTP(basic),
  1.3591 +	HTTP(cancel),
  1.3592 +	HTTP(virtual_host),
  1.3593 +	HTTP(post),
  1.3594 +	HTTP(put),
  1.3595 +	HTTP(delete),
  1.3596 +	HTTP(allowed_methods),
  1.3597 +	HTTP(failure),
  1.3598 +	HTTP(connection),
  1.3599 +	HTTP(persist_connection),
  1.3600 +	HTTP(connection_async),
  1.3601 +	HTTP(close_detection),
  1.3602 +	HTTP(close_detection_delay),
  1.3603 +	HTTP(bad_request),
  1.3604 +	HTTP(incomplete),
  1.3605 +	HTTP(incomplete_timeout),
  1.3606 +	HTTP(terminate_chunked),
  1.3607 +
  1.3608 +	HTTP(highport),
  1.3609 +	HTTP(dispatcher),
  1.3610 +	HTTP(multi_line_header),
  1.3611 +	HTTP(negative_content_length),
  1.3612 +	HTTP(chunk_out),
  1.3613 +	HTTP(stream_out),
  1.3614 +
  1.3615 +	HTTP(stream_in),
  1.3616 +	HTTP(stream_in_cancel),
  1.3617 +
  1.3618 +	HTTP(connection_fail),
  1.3619 +	HTTP(connection_retry),
  1.3620 +	HTTP(data_length_constraints),
  1.3621 +
  1.3622 +	END_OF_TESTCASES
  1.3623 +};
  1.3624 +

mercurial