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

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 /*
     2  * Copyright (c) 2003-2007 Niels Provos <provos@citi.umich.edu>
     3  * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson
     4  *
     5  * Redistribution and use in source and binary forms, with or without
     6  * modification, are permitted provided that the following conditions
     7  * are met:
     8  * 1. Redistributions of source code must retain the above copyright
     9  *    notice, this list of conditions and the following disclaimer.
    10  * 2. Redistributions in binary form must reproduce the above copyright
    11  *    notice, this list of conditions and the following disclaimer in the
    12  *    documentation and/or other materials provided with the distribution.
    13  * 3. The name of the author may not be used to endorse or promote products
    14  *    derived from this software without specific prior written permission.
    15  *
    16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
    17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
    18  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
    19  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
    20  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
    21  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
    22  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
    23  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
    25  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    26  */
    28 #ifdef WIN32
    29 #include <winsock2.h>
    30 #include <ws2tcpip.h>
    31 #include <windows.h>
    32 #endif
    34 #include "event2/event-config.h"
    36 #include <sys/types.h>
    37 #include <sys/stat.h>
    38 #ifdef _EVENT_HAVE_SYS_TIME_H
    39 #include <sys/time.h>
    40 #endif
    41 #include <sys/queue.h>
    42 #ifndef WIN32
    43 #include <sys/socket.h>
    44 #include <signal.h>
    45 #include <unistd.h>
    46 #include <netdb.h>
    47 #endif
    48 #include <fcntl.h>
    49 #include <stdlib.h>
    50 #include <stdio.h>
    51 #include <string.h>
    52 #include <errno.h>
    54 #include "event2/dns.h"
    56 #include "event2/event.h"
    57 #include "event2/http.h"
    58 #include "event2/buffer.h"
    59 #include "event2/bufferevent.h"
    60 #include "event2/util.h"
    61 #include "log-internal.h"
    62 #include "util-internal.h"
    63 #include "http-internal.h"
    64 #include "regress.h"
    65 #include "regress_testutils.h"
    67 static struct evhttp *http;
    68 /* set if a test needs to call loopexit on a base */
    69 static struct event_base *exit_base;
    71 static char const BASIC_REQUEST_BODY[] = "This is funny";
    73 static void http_basic_cb(struct evhttp_request *req, void *arg);
    74 static void http_chunked_cb(struct evhttp_request *req, void *arg);
    75 static void http_post_cb(struct evhttp_request *req, void *arg);
    76 static void http_put_cb(struct evhttp_request *req, void *arg);
    77 static void http_delete_cb(struct evhttp_request *req, void *arg);
    78 static void http_delay_cb(struct evhttp_request *req, void *arg);
    79 static void http_large_delay_cb(struct evhttp_request *req, void *arg);
    80 static void http_badreq_cb(struct evhttp_request *req, void *arg);
    81 static void http_dispatcher_cb(struct evhttp_request *req, void *arg);
    82 static int
    83 http_bind(struct evhttp *myhttp, ev_uint16_t *pport)
    84 {
    85 	int port;
    86 	struct evhttp_bound_socket *sock;
    88 	sock = evhttp_bind_socket_with_handle(myhttp, "127.0.0.1", *pport);
    89 	if (sock == NULL)
    90 		event_errx(1, "Could not start web server");
    92 	port = regress_get_socket_port(evhttp_bound_socket_get_fd(sock));
    93 	if (port < 0)
    94 		return -1;
    95 	*pport = (ev_uint16_t) port;
    97 	return 0;
    98 }
   100 static struct evhttp *
   101 http_setup(ev_uint16_t *pport, struct event_base *base)
   102 {
   103 	struct evhttp *myhttp;
   105 	/* Try a few different ports */
   106 	myhttp = evhttp_new(base);
   108 	if (http_bind(myhttp, pport) < 0)
   109 		return NULL;
   111 	/* Register a callback for certain types of requests */
   112 	evhttp_set_cb(myhttp, "/test", http_basic_cb, base);
   113 	evhttp_set_cb(myhttp, "/chunked", http_chunked_cb, base);
   114 	evhttp_set_cb(myhttp, "/streamed", http_chunked_cb, base);
   115 	evhttp_set_cb(myhttp, "/postit", http_post_cb, base);
   116 	evhttp_set_cb(myhttp, "/putit", http_put_cb, base);
   117 	evhttp_set_cb(myhttp, "/deleteit", http_delete_cb, base);
   118 	evhttp_set_cb(myhttp, "/delay", http_delay_cb, base);
   119 	evhttp_set_cb(myhttp, "/largedelay", http_large_delay_cb, base);
   120 	evhttp_set_cb(myhttp, "/badrequest", http_badreq_cb, base);
   121 	evhttp_set_cb(myhttp, "/", http_dispatcher_cb, base);
   122 	return (myhttp);
   123 }
   125 #ifndef NI_MAXSERV
   126 #define NI_MAXSERV 1024
   127 #endif
   129 static evutil_socket_t
   130 http_connect(const char *address, u_short port)
   131 {
   132 	/* Stupid code for connecting */
   133 	struct evutil_addrinfo ai, *aitop;
   134 	char strport[NI_MAXSERV];
   136 	struct sockaddr *sa;
   137 	int slen;
   138 	evutil_socket_t fd;
   140 	memset(&ai, 0, sizeof(ai));
   141 	ai.ai_family = AF_INET;
   142 	ai.ai_socktype = SOCK_STREAM;
   143 	evutil_snprintf(strport, sizeof(strport), "%d", port);
   144 	if (evutil_getaddrinfo(address, strport, &ai, &aitop) != 0) {
   145 		event_warn("getaddrinfo");
   146 		return (-1);
   147 	}
   148 	sa = aitop->ai_addr;
   149 	slen = aitop->ai_addrlen;
   151 	fd = socket(AF_INET, SOCK_STREAM, 0);
   152 	if (fd == -1)
   153 		event_err(1, "socket failed");
   155 	evutil_make_socket_nonblocking(fd);
   156 	if (connect(fd, sa, slen) == -1) {
   157 #ifdef WIN32
   158 		int tmp_err = WSAGetLastError();
   159 		if (tmp_err != WSAEINPROGRESS && tmp_err != WSAEINVAL &&
   160 		    tmp_err != WSAEWOULDBLOCK)
   161 			event_err(1, "connect failed");
   162 #else
   163 		if (errno != EINPROGRESS)
   164 			event_err(1, "connect failed");
   165 #endif
   166 	}
   168 	evutil_freeaddrinfo(aitop);
   170 	return (fd);
   171 }
   173 /* Helper: do a strcmp on the contents of buf and the string s. */
   174 static int
   175 evbuffer_datacmp(struct evbuffer *buf, const char *s)
   176 {
   177 	size_t b_sz = evbuffer_get_length(buf);
   178 	size_t s_sz = strlen(s);
   179 	unsigned char *d;
   180 	int r;
   182 	if (b_sz < s_sz)
   183 		return -1;
   185 	d = evbuffer_pullup(buf, s_sz);
   186 	if ((r = memcmp(d, s, s_sz)))
   187 		return r;
   189 	if (b_sz > s_sz)
   190 		return 1;
   191 	else
   192 		return 0;
   193 }
   195 /* Helper: Return true iff buf contains s */
   196 static int
   197 evbuffer_contains(struct evbuffer *buf, const char *s)
   198 {
   199 	struct evbuffer_ptr ptr;
   200 	ptr = evbuffer_search(buf, s, strlen(s), NULL);
   201 	return ptr.pos != -1;
   202 }
   204 static void
   205 http_readcb(struct bufferevent *bev, void *arg)
   206 {
   207 	const char *what = BASIC_REQUEST_BODY;
   208 	struct event_base *my_base = arg;
   210 	if (evbuffer_contains(bufferevent_get_input(bev), what)) {
   211 		struct evhttp_request *req = evhttp_request_new(NULL, NULL);
   212 		enum message_read_status done;
   214 		/* req->kind = EVHTTP_RESPONSE; */
   215 		done = evhttp_parse_firstline(req, bufferevent_get_input(bev));
   216 		if (done != ALL_DATA_READ)
   217 			goto out;
   219 		done = evhttp_parse_headers(req, bufferevent_get_input(bev));
   220 		if (done != ALL_DATA_READ)
   221 			goto out;
   223 		if (done == 1 &&
   224 		    evhttp_find_header(evhttp_request_get_input_headers(req),
   225 			"Content-Type") != NULL)
   226 			test_ok++;
   228 	 out:
   229 		evhttp_request_free(req);
   230 		bufferevent_disable(bev, EV_READ);
   231 		if (exit_base)
   232 			event_base_loopexit(exit_base, NULL);
   233 		else if (my_base)
   234 			event_base_loopexit(my_base, NULL);
   235 		else {
   236 			fprintf(stderr, "No way to exit loop!\n");
   237 			exit(1);
   238 		}
   239 	}
   240 }
   242 static void
   243 http_writecb(struct bufferevent *bev, void *arg)
   244 {
   245 	if (evbuffer_get_length(bufferevent_get_output(bev)) == 0) {
   246 		/* enable reading of the reply */
   247 		bufferevent_enable(bev, EV_READ);
   248 		test_ok++;
   249 	}
   250 }
   252 static void
   253 http_errorcb(struct bufferevent *bev, short what, void *arg)
   254 {
   255 	test_ok = -2;
   256 	event_base_loopexit(arg, NULL);
   257 }
   259 static void
   260 http_basic_cb(struct evhttp_request *req, void *arg)
   261 {
   262 	struct evbuffer *evb = evbuffer_new();
   263 	int empty = evhttp_find_header(evhttp_request_get_input_headers(req), "Empty") != NULL;
   264 	event_debug(("%s: called\n", __func__));
   265 	evbuffer_add_printf(evb, BASIC_REQUEST_BODY);
   267 	/* For multi-line headers test */
   268 	{
   269 		const char *multi =
   270 		    evhttp_find_header(evhttp_request_get_input_headers(req),"X-multi");
   271 		if (multi) {
   272 			if (strcmp("END", multi + strlen(multi) - 3) == 0)
   273 				test_ok++;
   274 			if (evhttp_find_header(evhttp_request_get_input_headers(req), "X-Last"))
   275 				test_ok++;
   276 		}
   277 	}
   279 	/* injecting a bad content-length */
   280 	if (evhttp_find_header(evhttp_request_get_input_headers(req), "X-Negative"))
   281 		evhttp_add_header(evhttp_request_get_output_headers(req),
   282 		    "Content-Length", "-100");
   284 	/* allow sending of an empty reply */
   285 	evhttp_send_reply(req, HTTP_OK, "Everything is fine",
   286 	    !empty ? evb : NULL);
   288 	evbuffer_free(evb);
   289 }
   291 static char const* const CHUNKS[] = {
   292 	"This is funny",
   293 	"but not hilarious.",
   294 	"bwv 1052"
   295 };
   297 struct chunk_req_state {
   298 	struct event_base *base;
   299 	struct evhttp_request *req;
   300 	int i;
   301 };
   303 static void
   304 http_chunked_trickle_cb(evutil_socket_t fd, short events, void *arg)
   305 {
   306 	struct evbuffer *evb = evbuffer_new();
   307 	struct chunk_req_state *state = arg;
   308 	struct timeval when = { 0, 0 };
   310 	evbuffer_add_printf(evb, "%s", CHUNKS[state->i]);
   311 	evhttp_send_reply_chunk(state->req, evb);
   312 	evbuffer_free(evb);
   314 	if (++state->i < (int) (sizeof(CHUNKS)/sizeof(CHUNKS[0]))) {
   315 		event_base_once(state->base, -1, EV_TIMEOUT,
   316 		    http_chunked_trickle_cb, state, &when);
   317 	} else {
   318 		evhttp_send_reply_end(state->req);
   319 		free(state);
   320 	}
   321 }
   323 static void
   324 http_chunked_cb(struct evhttp_request *req, void *arg)
   325 {
   326 	struct timeval when = { 0, 0 };
   327 	struct chunk_req_state *state = malloc(sizeof(struct chunk_req_state));
   328 	event_debug(("%s: called\n", __func__));
   330 	memset(state, 0, sizeof(struct chunk_req_state));
   331 	state->req = req;
   332 	state->base = arg;
   334 	if (strcmp(evhttp_request_get_uri(req), "/streamed") == 0) {
   335 		evhttp_add_header(evhttp_request_get_output_headers(req), "Content-Length", "39");
   336 	}
   338 	/* generate a chunked/streamed reply */
   339 	evhttp_send_reply_start(req, HTTP_OK, "Everything is fine");
   341 	/* but trickle it across several iterations to ensure we're not
   342 	 * assuming it comes all at once */
   343 	event_base_once(arg, -1, EV_TIMEOUT, http_chunked_trickle_cb, state, &when);
   344 }
   346 static void
   347 http_complete_write(evutil_socket_t fd, short what, void *arg)
   348 {
   349 	struct bufferevent *bev = arg;
   350 	const char *http_request = "host\r\n"
   351 	    "Connection: close\r\n"
   352 	    "\r\n";
   353 	bufferevent_write(bev, http_request, strlen(http_request));
   354 }
   356 static void
   357 http_basic_test(void *arg)
   358 {
   359 	struct basic_test_data *data = arg;
   360 	struct timeval tv;
   361 	struct bufferevent *bev;
   362 	evutil_socket_t fd;
   363 	const char *http_request;
   364 	ev_uint16_t port = 0, port2 = 0;
   366 	test_ok = 0;
   368 	http = http_setup(&port, data->base);
   370 	/* bind to a second socket */
   371 	if (http_bind(http, &port2) == -1) {
   372 		fprintf(stdout, "FAILED (bind)\n");
   373 		exit(1);
   374 	}
   376 	fd = http_connect("127.0.0.1", port);
   378 	/* Stupid thing to send a request */
   379 	bev = bufferevent_socket_new(data->base, fd, 0);
   380 	bufferevent_setcb(bev, http_readcb, http_writecb,
   381 	    http_errorcb, data->base);
   383 	/* first half of the http request */
   384 	http_request =
   385 	    "GET /test HTTP/1.1\r\n"
   386 	    "Host: some";
   388 	bufferevent_write(bev, http_request, strlen(http_request));
   389 	evutil_timerclear(&tv);
   390 	tv.tv_usec = 10000;
   391 	event_base_once(data->base,
   392 	    -1, EV_TIMEOUT, http_complete_write, bev, &tv);
   394 	event_base_dispatch(data->base);
   396 	tt_assert(test_ok == 3);
   398 	/* connect to the second port */
   399 	bufferevent_free(bev);
   400 	evutil_closesocket(fd);
   402 	fd = http_connect("127.0.0.1", port2);
   404 	/* Stupid thing to send a request */
   405 	bev = bufferevent_socket_new(data->base, fd, 0);
   406 	bufferevent_setcb(bev, http_readcb, http_writecb,
   407 	    http_errorcb, data->base);
   409 	http_request =
   410 	    "GET /test HTTP/1.1\r\n"
   411 	    "Host: somehost\r\n"
   412 	    "Connection: close\r\n"
   413 	    "\r\n";
   415 	bufferevent_write(bev, http_request, strlen(http_request));
   417 	event_base_dispatch(data->base);
   419 	tt_assert(test_ok == 5);
   421 	/* Connect to the second port again. This time, send an absolute uri. */
   422 	bufferevent_free(bev);
   423 	evutil_closesocket(fd);
   425 	fd = http_connect("127.0.0.1", port2);
   427 	/* Stupid thing to send a request */
   428 	bev = bufferevent_socket_new(data->base, fd, 0);
   429 	bufferevent_setcb(bev, http_readcb, http_writecb,
   430 	    http_errorcb, data->base);
   432 	http_request =
   433 	    "GET http://somehost.net/test HTTP/1.1\r\n"
   434 	    "Host: somehost\r\n"
   435 	    "Connection: close\r\n"
   436 	    "\r\n";
   438 	bufferevent_write(bev, http_request, strlen(http_request));
   440 	event_base_dispatch(data->base);
   442 	tt_assert(test_ok == 7);
   444 	evhttp_free(http);
   445  end:
   446 	;
   447 }
   449 static void
   450 http_delay_reply(evutil_socket_t fd, short what, void *arg)
   451 {
   452 	struct evhttp_request *req = arg;
   454 	evhttp_send_reply(req, HTTP_OK, "Everything is fine", NULL);
   456 	++test_ok;
   457 }
   459 static void
   460 http_delay_cb(struct evhttp_request *req, void *arg)
   461 {
   462 	struct timeval tv;
   463 	evutil_timerclear(&tv);
   464 	tv.tv_sec = 0;
   465 	tv.tv_usec = 200 * 1000;
   467 	event_base_once(arg, -1, EV_TIMEOUT, http_delay_reply, req, &tv);
   468 }
   470 static void
   471 http_badreq_cb(struct evhttp_request *req, void *arg)
   472 {
   473 	struct evbuffer *buf = evbuffer_new();
   475 	evhttp_add_header(evhttp_request_get_output_headers(req), "Content-Type", "text/xml; charset=UTF-8");
   476 	evbuffer_add_printf(buf, "Hello, %s!", "127.0.0.1");
   478 	evhttp_send_reply(req, HTTP_OK, "OK", buf);
   479 	evbuffer_free(buf);
   480 }
   482 static void
   483 http_badreq_errorcb(struct bufferevent *bev, short what, void *arg)
   484 {
   485 	event_debug(("%s: called (what=%04x, arg=%p)", __func__, what, arg));
   486 	/* ignore */
   487 }
   489 #ifndef SHUT_WR
   490 #ifdef WIN32
   491 #define SHUT_WR SD_SEND
   492 #else
   493 #define SHUT_WR 1
   494 #endif
   495 #endif
   497 static void
   498 http_badreq_readcb(struct bufferevent *bev, void *arg)
   499 {
   500 	const char *what = "Hello, 127.0.0.1";
   501 	const char *bad_request = "400 Bad Request";
   503 	if (evbuffer_contains(bufferevent_get_input(bev), bad_request)) {
   504 		TT_FAIL(("%s:bad request detected", __func__));
   505 		bufferevent_disable(bev, EV_READ);
   506 		event_base_loopexit(arg, NULL);
   507 		return;
   508 	}
   510 	if (evbuffer_contains(bufferevent_get_input(bev), what)) {
   511 		struct evhttp_request *req = evhttp_request_new(NULL, NULL);
   512 		enum message_read_status done;
   514 		/* req->kind = EVHTTP_RESPONSE; */
   515 		done = evhttp_parse_firstline(req, bufferevent_get_input(bev));
   516 		if (done != ALL_DATA_READ)
   517 			goto out;
   519 		done = evhttp_parse_headers(req, bufferevent_get_input(bev));
   520 		if (done != ALL_DATA_READ)
   521 			goto out;
   523 		if (done == 1 &&
   524 		    evhttp_find_header(evhttp_request_get_input_headers(req),
   525 			"Content-Type") != NULL)
   526 			test_ok++;
   528 	out:
   529 		evhttp_request_free(req);
   530 		evbuffer_drain(bufferevent_get_input(bev), evbuffer_get_length(bufferevent_get_input(bev)));
   531 	}
   533 	shutdown(bufferevent_getfd(bev), SHUT_WR);
   534 }
   536 static void
   537 http_badreq_successcb(evutil_socket_t fd, short what, void *arg)
   538 {
   539 	event_debug(("%s: called (what=%04x, arg=%p)", __func__, what, arg));
   540 	event_base_loopexit(exit_base, NULL);
   541 }
   543 static void
   544 http_bad_request_test(void *arg)
   545 {
   546 	struct basic_test_data *data = arg;
   547 	struct timeval tv;
   548 	struct bufferevent *bev = NULL;
   549 	evutil_socket_t fd;
   550 	const char *http_request;
   551 	ev_uint16_t port=0, port2=0;
   553 	test_ok = 0;
   554 	exit_base = data->base;
   556 	http = http_setup(&port, data->base);
   558 	/* bind to a second socket */
   559 	if (http_bind(http, &port2) == -1)
   560 		TT_DIE(("Bind socket failed"));
   562 	/* NULL request test */
   563 	fd = http_connect("127.0.0.1", port);
   565 	/* Stupid thing to send a request */
   566 	bev = bufferevent_socket_new(data->base, fd, 0);
   567 	bufferevent_setcb(bev, http_badreq_readcb, http_writecb,
   568 	    http_badreq_errorcb, data->base);
   569 	bufferevent_enable(bev, EV_READ);
   571 	/* real NULL request */
   572 	http_request = "";
   574 	bufferevent_write(bev, http_request, strlen(http_request));
   576 	shutdown(fd, SHUT_WR);
   577 	timerclear(&tv);
   578 	tv.tv_usec = 10000;
   579 	event_base_once(data->base, -1, EV_TIMEOUT, http_badreq_successcb, bev, &tv);
   581 	event_base_dispatch(data->base);
   583 	bufferevent_free(bev);
   584 	evutil_closesocket(fd);
   586 	if (test_ok != 0) {
   587 		fprintf(stdout, "FAILED\n");
   588 		exit(1);
   589 	}
   591 	/* Second answer (BAD REQUEST) on connection close */
   593 	/* connect to the second port */
   594 	fd = http_connect("127.0.0.1", port2);
   596 	/* Stupid thing to send a request */
   597 	bev = bufferevent_socket_new(data->base, fd, 0);
   598 	bufferevent_setcb(bev, http_badreq_readcb, http_writecb,
   599 	    http_badreq_errorcb, data->base);
   600 	bufferevent_enable(bev, EV_READ);
   602 	/* first half of the http request */
   603 	http_request =
   604 		"GET /badrequest HTTP/1.0\r\n"	\
   605 		"Connection: Keep-Alive\r\n"	\
   606 		"\r\n";
   608 	bufferevent_write(bev, http_request, strlen(http_request));
   610 	timerclear(&tv);
   611 	tv.tv_usec = 10000;
   612 	event_base_once(data->base, -1, EV_TIMEOUT, http_badreq_successcb, bev, &tv);
   614 	event_base_dispatch(data->base);
   616 	tt_int_op(test_ok, ==, 2);
   618 end:
   619 	evhttp_free(http);
   620 	if (bev)
   621 		bufferevent_free(bev);
   622 }
   624 static struct evhttp_connection *delayed_client;
   626 static void
   627 http_large_delay_cb(struct evhttp_request *req, void *arg)
   628 {
   629 	struct timeval tv;
   630 	evutil_timerclear(&tv);
   631 	tv.tv_sec = 3;
   633 	event_base_once(arg, -1, EV_TIMEOUT, http_delay_reply, req, &tv);
   634 	evhttp_connection_fail(delayed_client, EVCON_HTTP_EOF);
   635 }
   637 /*
   638  * HTTP DELETE test,  just piggyback on the basic test
   639  */
   641 static void
   642 http_delete_cb(struct evhttp_request *req, void *arg)
   643 {
   644 	struct evbuffer *evb = evbuffer_new();
   645 	int empty = evhttp_find_header(evhttp_request_get_input_headers(req), "Empty") != NULL;
   647 	/* Expecting a DELETE request */
   648 	if (evhttp_request_get_command(req) != EVHTTP_REQ_DELETE) {
   649 		fprintf(stdout, "FAILED (delete type)\n");
   650 		exit(1);
   651 	}
   653 	event_debug(("%s: called\n", __func__));
   654 	evbuffer_add_printf(evb, BASIC_REQUEST_BODY);
   656 	/* allow sending of an empty reply */
   657 	evhttp_send_reply(req, HTTP_OK, "Everything is fine",
   658 	    !empty ? evb : NULL);
   660 	evbuffer_free(evb);
   661 }
   663 static void
   664 http_delete_test(void *arg)
   665 {
   666 	struct basic_test_data *data = arg;
   667 	struct bufferevent *bev;
   668 	evutil_socket_t fd;
   669 	const char *http_request;
   670 	ev_uint16_t port = 0;
   672 	test_ok = 0;
   674 	http = http_setup(&port, data->base);
   676 	fd = http_connect("127.0.0.1", port);
   678 	/* Stupid thing to send a request */
   679 	bev = bufferevent_socket_new(data->base, fd, 0);
   680 	bufferevent_setcb(bev, http_readcb, http_writecb,
   681 	    http_errorcb, data->base);
   683 	http_request =
   684 	    "DELETE /deleteit HTTP/1.1\r\n"
   685 	    "Host: somehost\r\n"
   686 	    "Connection: close\r\n"
   687 	    "\r\n";
   689 	bufferevent_write(bev, http_request, strlen(http_request));
   691 	event_base_dispatch(data->base);
   693 	bufferevent_free(bev);
   694 	evutil_closesocket(fd);
   696 	evhttp_free(http);
   698 	tt_int_op(test_ok, ==, 2);
   699  end:
   700 	;
   701 }
   703 static void
   704 http_allowed_methods_eventcb(struct bufferevent *bev, short what, void *arg)
   705 {
   706 	char **output = arg;
   707 	if ((what & (BEV_EVENT_ERROR|BEV_EVENT_EOF))) {
   708 		char buf[4096];
   709 		int n;
   710 		n = evbuffer_remove(bufferevent_get_input(bev), buf,
   711 		    sizeof(buf)-1);
   712 		if (n >= 0) {
   713 			buf[n]='\0';
   714 			if (*output)
   715 				free(*output);
   716 			*output = strdup(buf);
   717 		}
   718 		event_base_loopexit(exit_base, NULL);
   719 	}
   720 }
   722 static void
   723 http_allowed_methods_test(void *arg)
   724 {
   725 	struct basic_test_data *data = arg;
   726 	struct bufferevent *bev1, *bev2, *bev3;
   727 	evutil_socket_t fd1, fd2, fd3;
   728 	const char *http_request;
   729 	char *result1=NULL, *result2=NULL, *result3=NULL;
   730 	ev_uint16_t port = 0;
   732 	exit_base = data->base;
   733 	test_ok = 0;
   735 	http = http_setup(&port, data->base);
   737 	fd1 = http_connect("127.0.0.1", port);
   739 	/* GET is out; PATCH is in. */
   740 	evhttp_set_allowed_methods(http, EVHTTP_REQ_PATCH);
   742 	/* Stupid thing to send a request */
   743 	bev1 = bufferevent_socket_new(data->base, fd1, 0);
   744 	bufferevent_enable(bev1, EV_READ|EV_WRITE);
   745 	bufferevent_setcb(bev1, NULL, NULL,
   746 	    http_allowed_methods_eventcb, &result1);
   748 	http_request =
   749 	    "GET /index.html HTTP/1.1\r\n"
   750 	    "Host: somehost\r\n"
   751 	    "Connection: close\r\n"
   752 	    "\r\n";
   754 	bufferevent_write(bev1, http_request, strlen(http_request));
   756 	event_base_dispatch(data->base);
   758 	fd2 = http_connect("127.0.0.1", port);
   760 	bev2 = bufferevent_socket_new(data->base, fd2, 0);
   761 	bufferevent_enable(bev2, EV_READ|EV_WRITE);
   762 	bufferevent_setcb(bev2, NULL, NULL,
   763 	    http_allowed_methods_eventcb, &result2);
   765 	http_request =
   766 	    "PATCH /test HTTP/1.1\r\n"
   767 	    "Host: somehost\r\n"
   768 	    "Connection: close\r\n"
   769 	    "\r\n";
   771 	bufferevent_write(bev2, http_request, strlen(http_request));
   773 	event_base_dispatch(data->base);
   775 	fd3 = http_connect("127.0.0.1", port);
   777 	bev3 = bufferevent_socket_new(data->base, fd3, 0);
   778 	bufferevent_enable(bev3, EV_READ|EV_WRITE);
   779 	bufferevent_setcb(bev3, NULL, NULL,
   780 	    http_allowed_methods_eventcb, &result3);
   782 	http_request =
   783 	    "FLOOP /test HTTP/1.1\r\n"
   784 	    "Host: somehost\r\n"
   785 	    "Connection: close\r\n"
   786 	    "\r\n";
   788 	bufferevent_write(bev3, http_request, strlen(http_request));
   790 	event_base_dispatch(data->base);
   792 	bufferevent_free(bev1);
   793 	bufferevent_free(bev2);
   794 	bufferevent_free(bev3);
   795 	evutil_closesocket(fd1);
   796 	evutil_closesocket(fd2);
   797 	evutil_closesocket(fd3);
   799 	evhttp_free(http);
   801 	/* Method known but disallowed */
   802 	tt_assert(result1);
   803 	tt_assert(!strncmp(result1, "HTTP/1.1 501 ", strlen("HTTP/1.1 501 ")));
   805 	/* Method known and allowed */
   806 	tt_assert(result2);
   807 	tt_assert(!strncmp(result2, "HTTP/1.1 200 ", strlen("HTTP/1.1 200 ")));
   809 	/* Method unknown */
   810 	tt_assert(result3);
   811 	tt_assert(!strncmp(result3, "HTTP/1.1 501 ", strlen("HTTP/1.1 501 ")));
   813  end:
   814 	if (result1)
   815 		free(result1);
   816 	if (result2)
   817 		free(result2);
   818 	if (result3)
   819 		free(result3);
   820 }
   822 static void http_request_done(struct evhttp_request *, void *);
   823 static void http_request_empty_done(struct evhttp_request *, void *);
   825 static void
   826 _http_connection_test(struct basic_test_data *data, int persistent)
   827 {
   828 	ev_uint16_t port = 0;
   829 	struct evhttp_connection *evcon = NULL;
   830 	struct evhttp_request *req = NULL;
   832 	test_ok = 0;
   834 	http = http_setup(&port, data->base);
   836 	evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port);
   837 	tt_assert(evcon);
   839 	tt_assert(evhttp_connection_get_base(evcon) == data->base);
   841 	exit_base = data->base;
   842 	/*
   843 	 * At this point, we want to schedule a request to the HTTP
   844 	 * server using our make request method.
   845 	 */
   847 	req = evhttp_request_new(http_request_done, (void*) BASIC_REQUEST_BODY);
   849 	/* Add the information that we care about */
   850 	evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
   852 	/* We give ownership of the request to the connection */
   853 	if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test") == -1) {
   854 		fprintf(stdout, "FAILED\n");
   855 		exit(1);
   856 	}
   858 	event_base_dispatch(data->base);
   860 	tt_assert(test_ok);
   862 	/* try to make another request over the same connection */
   863 	test_ok = 0;
   865 	req = evhttp_request_new(http_request_done, (void*) BASIC_REQUEST_BODY);
   867 	/* Add the information that we care about */
   868 	evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
   870 	/*
   871 	 * if our connections are not supposed to be persistent; request
   872 	 * a close from the server.
   873 	 */
   874 	if (!persistent)
   875 		evhttp_add_header(evhttp_request_get_output_headers(req), "Connection", "close");
   877 	/* We give ownership of the request to the connection */
   878 	if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test") == -1) {
   879 		tt_abort_msg("couldn't make request");
   880 	}
   882 	event_base_dispatch(data->base);
   884 	/* make another request: request empty reply */
   885 	test_ok = 0;
   887 	req = evhttp_request_new(http_request_empty_done, data->base);
   889 	/* Add the information that we care about */
   890 	evhttp_add_header(evhttp_request_get_output_headers(req), "Empty", "itis");
   892 	/* We give ownership of the request to the connection */
   893 	if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test") == -1) {
   894 		tt_abort_msg("Couldn't make request");
   895 	}
   897 	event_base_dispatch(data->base);
   899  end:
   900 	if (evcon)
   901 		evhttp_connection_free(evcon);
   902 	if (http)
   903 		evhttp_free(http);
   904 }
   906 static void
   907 http_connection_test(void *arg)
   908 {
   909 	_http_connection_test(arg, 0);
   910 }
   911 static void
   912 http_persist_connection_test(void *arg)
   913 {
   914 	_http_connection_test(arg, 1);
   915 }
   917 static struct regress_dns_server_table search_table[] = {
   918 	{ "localhost", "A", "127.0.0.1", 0 },
   919 	{ NULL, NULL, NULL, 0 }
   920 };
   922 static void
   923 http_connection_async_test(void *arg)
   924 {
   925 	struct basic_test_data *data = arg;
   926 	ev_uint16_t port = 0;
   927 	struct evhttp_connection *evcon = NULL;
   928 	struct evhttp_request *req = NULL;
   929 	struct evdns_base *dns_base = NULL;
   930 	ev_uint16_t portnum = 0;
   931 	char address[64];
   933 	exit_base = data->base;
   934 	tt_assert(regress_dnsserver(data->base, &portnum, search_table));
   936 	dns_base = evdns_base_new(data->base, 0/* init name servers */);
   937 	tt_assert(dns_base);
   939 	/* Add ourself as the only nameserver, and make sure we really are
   940 	 * the only nameserver. */
   941 	evutil_snprintf(address, sizeof(address), "127.0.0.1:%d", portnum);
   942 	evdns_base_nameserver_ip_add(dns_base, address);
   944 	test_ok = 0;
   946 	http = http_setup(&port, data->base);
   948 	evcon = evhttp_connection_base_new(data->base, dns_base, "127.0.0.1", port);
   949 	tt_assert(evcon);
   951 	/*
   952 	 * At this point, we want to schedule a request to the HTTP
   953 	 * server using our make request method.
   954 	 */
   956 	req = evhttp_request_new(http_request_done, (void*) BASIC_REQUEST_BODY);
   958 	/* Add the information that we care about */
   959 	evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
   961 	/* We give ownership of the request to the connection */
   962 	if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test") == -1) {
   963 		fprintf(stdout, "FAILED\n");
   964 		exit(1);
   965 	}
   967 	event_base_dispatch(data->base);
   969 	tt_assert(test_ok);
   971 	/* try to make another request over the same connection */
   972 	test_ok = 0;
   974 	req = evhttp_request_new(http_request_done, (void*) BASIC_REQUEST_BODY);
   976 	/* Add the information that we care about */
   977 	evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
   979 	/*
   980 	 * if our connections are not supposed to be persistent; request
   981 	 * a close from the server.
   982 	 */
   983 	evhttp_add_header(evhttp_request_get_output_headers(req), "Connection", "close");
   985 	/* We give ownership of the request to the connection */
   986 	if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test") == -1) {
   987 		tt_abort_msg("couldn't make request");
   988 	}
   990 	event_base_dispatch(data->base);
   992 	/* make another request: request empty reply */
   993 	test_ok = 0;
   995 	req = evhttp_request_new(http_request_empty_done, data->base);
   997 	/* Add the information that we care about */
   998 	evhttp_add_header(evhttp_request_get_output_headers(req), "Empty", "itis");
  1000 	/* We give ownership of the request to the connection */
  1001 	if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test") == -1) {
  1002 		tt_abort_msg("Couldn't make request");
  1005 	event_base_dispatch(data->base);
  1007  end:
  1008 	if (evcon)
  1009 		evhttp_connection_free(evcon);
  1010 	if (http)
  1011 		evhttp_free(http);
  1012 	if (dns_base)
  1013 		evdns_base_free(dns_base, 0);
  1014 	regress_clean_dnsserver();
  1017 static void
  1018 http_request_never_call(struct evhttp_request *req, void *arg)
  1020 	fprintf(stdout, "FAILED\n");
  1021 	exit(1);
  1024 static void
  1025 http_do_cancel(evutil_socket_t fd, short what, void *arg)
  1027 	struct evhttp_request *req = arg;
  1028 	struct timeval tv;
  1029 	struct event_base *base;
  1030 	evutil_timerclear(&tv);
  1031 	tv.tv_sec = 0;
  1032 	tv.tv_usec = 500 * 1000;
  1034 	base = evhttp_connection_get_base(evhttp_request_get_connection(req));
  1035 	evhttp_cancel_request(req);
  1037 	event_base_loopexit(base, &tv);
  1039 	++test_ok;
  1042 static void
  1043 http_cancel_test(void *arg)
  1045 	struct basic_test_data *data = arg;
  1046 	ev_uint16_t port = 0;
  1047 	struct evhttp_connection *evcon = NULL;
  1048 	struct evhttp_request *req = NULL;
  1049 	struct timeval tv;
  1051 	exit_base = data->base;
  1053 	test_ok = 0;
  1055 	http = http_setup(&port, data->base);
  1057 	evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port);
  1058 	tt_assert(evcon);
  1060 	/*
  1061 	 * At this point, we want to schedule a request to the HTTP
  1062 	 * server using our make request method.
  1063 	 */
  1065 	req = evhttp_request_new(http_request_never_call, NULL);
  1067 	/* Add the information that we care about */
  1068 	evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
  1070 	/* We give ownership of the request to the connection */
  1071 	tt_int_op(evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/delay"),
  1072 		  !=, -1);
  1074 	evutil_timerclear(&tv);
  1075 	tv.tv_sec = 0;
  1076 	tv.tv_usec = 100 * 1000;
  1078 	event_base_once(data->base, -1, EV_TIMEOUT, http_do_cancel, req, &tv);
  1080 	event_base_dispatch(data->base);
  1082 	tt_int_op(test_ok, ==, 2);
  1084 	/* try to make another request over the same connection */
  1085 	test_ok = 0;
  1087 	req = evhttp_request_new(http_request_done, (void*) BASIC_REQUEST_BODY);
  1089 	/* Add the information that we care about */
  1090 	evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
  1092 	/* We give ownership of the request to the connection */
  1093 	tt_int_op(evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test"),
  1094 		  !=, -1);
  1096 	event_base_dispatch(data->base);
  1098 	/* make another request: request empty reply */
  1099 	test_ok = 0;
  1101 	req = evhttp_request_new(http_request_empty_done, data->base);
  1103 	/* Add the information that we care about */
  1104 	evhttp_add_header(evhttp_request_get_output_headers(req), "Empty", "itis");
  1106 	/* We give ownership of the request to the connection */
  1107 	tt_int_op(evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test"),
  1108 		  !=, -1);
  1110 	event_base_dispatch(data->base);
  1112  end:
  1113 	if (evcon)
  1114 		evhttp_connection_free(evcon);
  1115 	if (http)
  1116 		evhttp_free(http);
  1119 static void
  1120 http_request_done(struct evhttp_request *req, void *arg)
  1122 	const char *what = arg;
  1124 	if (evhttp_request_get_response_code(req) != HTTP_OK) {
  1125 		fprintf(stderr, "FAILED\n");
  1126 		exit(1);
  1129 	if (evhttp_find_header(evhttp_request_get_input_headers(req), "Content-Type") == NULL) {
  1130 		fprintf(stderr, "FAILED\n");
  1131 		exit(1);
  1134 	if (evbuffer_get_length(evhttp_request_get_input_buffer(req)) != strlen(what)) {
  1135 		fprintf(stderr, "FAILED\n");
  1136 		exit(1);
  1139 	if (evbuffer_datacmp(evhttp_request_get_input_buffer(req), what) != 0) {
  1140 		fprintf(stderr, "FAILED\n");
  1141 		exit(1);
  1144 	test_ok = 1;
  1145 	EVUTIL_ASSERT(exit_base);
  1146 	event_base_loopexit(exit_base, NULL);
  1149 static void
  1150 http_request_expect_error(struct evhttp_request *req, void *arg)
  1152 	if (evhttp_request_get_response_code(req) == HTTP_OK) {
  1153 		fprintf(stderr, "FAILED\n");
  1154 		exit(1);
  1157 	test_ok = 1;
  1158 	EVUTIL_ASSERT(arg);
  1159 	event_base_loopexit(arg, NULL);
  1162 /* test virtual hosts */
  1163 static void
  1164 http_virtual_host_test(void *arg)
  1166 	struct basic_test_data *data = arg;
  1167 	ev_uint16_t port = 0;
  1168 	struct evhttp_connection *evcon = NULL;
  1169 	struct evhttp_request *req = NULL;
  1170 	struct evhttp *second = NULL, *third = NULL;
  1171 	evutil_socket_t fd;
  1172 	struct bufferevent *bev;
  1173 	const char *http_request;
  1175 	exit_base = data->base;
  1177 	http = http_setup(&port, data->base);
  1179 	/* virtual host */
  1180 	second = evhttp_new(NULL);
  1181 	evhttp_set_cb(second, "/funnybunny", http_basic_cb, NULL);
  1182 	third = evhttp_new(NULL);
  1183 	evhttp_set_cb(third, "/blackcoffee", http_basic_cb, NULL);
  1185 	if (evhttp_add_virtual_host(http, "foo.com", second) == -1) {
  1186 		tt_abort_msg("Couldn't add vhost");
  1189 	if (evhttp_add_virtual_host(http, "bar.*.foo.com", third) == -1) {
  1190 		tt_abort_msg("Couldn't add wildcarded vhost");
  1193 	/* add some aliases to the vhosts */
  1194 	tt_assert(evhttp_add_server_alias(second, "manolito.info") == 0);
  1195 	tt_assert(evhttp_add_server_alias(third, "bonkers.org") == 0);
  1197 	evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port);
  1198 	tt_assert(evcon);
  1200 	/* make a request with a different host and expect an error */
  1201 	req = evhttp_request_new(http_request_expect_error, data->base);
  1203 	/* Add the information that we care about */
  1204 	evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
  1206 	/* We give ownership of the request to the connection */
  1207 	if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET,
  1208 		"/funnybunny") == -1) {
  1209 		tt_abort_msg("Couldn't make request");
  1212 	event_base_dispatch(data->base);
  1214 	tt_assert(test_ok == 1);
  1216 	test_ok = 0;
  1218 	/* make a request with the right host and expect a response */
  1219 	req = evhttp_request_new(http_request_done, (void*) BASIC_REQUEST_BODY);
  1221 	/* Add the information that we care about */
  1222 	evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "foo.com");
  1224 	/* We give ownership of the request to the connection */
  1225 	if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET,
  1226 		"/funnybunny") == -1) {
  1227 		fprintf(stdout, "FAILED\n");
  1228 		exit(1);
  1231 	event_base_dispatch(data->base);
  1233 	tt_assert(test_ok == 1);
  1235 	test_ok = 0;
  1237 	/* make a request with the right host and expect a response */
  1238 	req = evhttp_request_new(http_request_done, (void*) BASIC_REQUEST_BODY);
  1240 	/* Add the information that we care about */
  1241 	evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "bar.magic.foo.com");
  1243 	/* We give ownership of the request to the connection */
  1244 	if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET,
  1245 		"/blackcoffee") == -1) {
  1246 		tt_abort_msg("Couldn't make request");
  1249 	event_base_dispatch(data->base);
  1251 	tt_assert(test_ok == 1)
  1253 	test_ok = 0;
  1255 	/* make a request with the right host and expect a response */
  1256 	req = evhttp_request_new(http_request_done, (void*) BASIC_REQUEST_BODY);
  1258 	/* Add the information that we care about */
  1259 	evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "manolito.info");
  1261 	/* We give ownership of the request to the connection */
  1262 	if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET,
  1263 		"/funnybunny") == -1) {
  1264 		tt_abort_msg("Couldn't make request");
  1267 	event_base_dispatch(data->base);
  1269 	tt_assert(test_ok == 1)
  1271 	test_ok = 0;
  1273 	/* make a request with the right host and expect a response */
  1274 	req = evhttp_request_new(http_request_done, (void*) BASIC_REQUEST_BODY);
  1276 	/* Add the Host header. This time with the optional port. */
  1277 	evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "bonkers.org:8000");
  1279 	/* We give ownership of the request to the connection */
  1280 	if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET,
  1281 		"/blackcoffee") == -1) {
  1282 		tt_abort_msg("Couldn't make request");
  1285 	event_base_dispatch(data->base);
  1287 	tt_assert(test_ok == 1)
  1289 	test_ok = 0;
  1291 	/* Now make a raw request with an absolute URI. */
  1292 	fd = http_connect("127.0.0.1", port);
  1294 	/* Stupid thing to send a request */
  1295 	bev = bufferevent_socket_new(data->base, fd, 0);
  1296 	bufferevent_setcb(bev, http_readcb, http_writecb,
  1297 	    http_errorcb, NULL);
  1299 	/* The host in the URI should override the Host: header */
  1300 	http_request =
  1301 	    "GET http://manolito.info/funnybunny HTTP/1.1\r\n"
  1302 	    "Host: somehost\r\n"
  1303 	    "Connection: close\r\n"
  1304 	    "\r\n";
  1306 	bufferevent_write(bev, http_request, strlen(http_request));
  1308 	event_base_dispatch(data->base);
  1310 	tt_int_op(test_ok, ==, 2);
  1312 	bufferevent_free(bev);
  1313 	evutil_closesocket(fd);
  1315  end:
  1316 	if (evcon)
  1317 		evhttp_connection_free(evcon);
  1318 	if (http)
  1319 		evhttp_free(http);
  1323 /* test date header and content length */
  1325 static void
  1326 http_request_empty_done(struct evhttp_request *req, void *arg)
  1328 	if (evhttp_request_get_response_code(req) != HTTP_OK) {
  1329 		fprintf(stderr, "FAILED\n");
  1330 		exit(1);
  1333 	if (evhttp_find_header(evhttp_request_get_input_headers(req), "Date") == NULL) {
  1334 		fprintf(stderr, "FAILED\n");
  1335 		exit(1);
  1339 	if (evhttp_find_header(evhttp_request_get_input_headers(req), "Content-Length") == NULL) {
  1340 		fprintf(stderr, "FAILED\n");
  1341 		exit(1);
  1344 	if (strcmp(evhttp_find_header(evhttp_request_get_input_headers(req), "Content-Length"),
  1345 		"0")) {
  1346 		fprintf(stderr, "FAILED\n");
  1347 		exit(1);
  1350 	if (evbuffer_get_length(evhttp_request_get_input_buffer(req)) != 0) {
  1351 		fprintf(stderr, "FAILED\n");
  1352 		exit(1);
  1355 	test_ok = 1;
  1356 	EVUTIL_ASSERT(arg);
  1357 	event_base_loopexit(arg, NULL);
  1360 /*
  1361  * HTTP DISPATCHER test
  1362  */
  1364 void
  1365 http_dispatcher_cb(struct evhttp_request *req, void *arg)
  1368 	struct evbuffer *evb = evbuffer_new();
  1369 	event_debug(("%s: called\n", __func__));
  1370 	evbuffer_add_printf(evb, "DISPATCHER_TEST");
  1372 	evhttp_send_reply(req, HTTP_OK, "Everything is fine", evb);
  1374 	evbuffer_free(evb);
  1377 static void
  1378 http_dispatcher_test_done(struct evhttp_request *req, void *arg)
  1380 	struct event_base *base = arg;
  1381 	const char *what = "DISPATCHER_TEST";
  1383 	if (evhttp_request_get_response_code(req) != HTTP_OK) {
  1384 		fprintf(stderr, "FAILED\n");
  1385 		exit(1);
  1388 	if (evhttp_find_header(evhttp_request_get_input_headers(req), "Content-Type") == NULL) {
  1389 		fprintf(stderr, "FAILED (content type)\n");
  1390 		exit(1);
  1393 	if (evbuffer_get_length(evhttp_request_get_input_buffer(req)) != strlen(what)) {
  1394 		fprintf(stderr, "FAILED (length %lu vs %lu)\n",
  1395 		    (unsigned long)evbuffer_get_length(evhttp_request_get_input_buffer(req)), (unsigned long)strlen(what));
  1396 		exit(1);
  1399 	if (evbuffer_datacmp(evhttp_request_get_input_buffer(req), what) != 0) {
  1400 		fprintf(stderr, "FAILED (data)\n");
  1401 		exit(1);
  1404 	test_ok = 1;
  1405 	event_base_loopexit(base, NULL);
  1408 static void
  1409 http_dispatcher_test(void *arg)
  1411 	struct basic_test_data *data = arg;
  1412 	ev_uint16_t port = 0;
  1413 	struct evhttp_connection *evcon = NULL;
  1414 	struct evhttp_request *req = NULL;
  1416 	test_ok = 0;
  1418 	http = http_setup(&port, data->base);
  1420 	evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port);
  1421 	tt_assert(evcon);
  1423 	/* also bind to local host */
  1424 	evhttp_connection_set_local_address(evcon, "127.0.0.1");
  1426 	/*
  1427 	 * At this point, we want to schedule an HTTP GET request
  1428 	 * server using our make request method.
  1429 	 */
  1431 	req = evhttp_request_new(http_dispatcher_test_done, data->base);
  1432 	tt_assert(req);
  1434 	/* Add the information that we care about */
  1435 	evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
  1437 	if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/?arg=val") == -1) {
  1438 		tt_abort_msg("Couldn't make request");
  1441 	event_base_dispatch(data->base);
  1443  end:
  1444 	if (evcon)
  1445 		evhttp_connection_free(evcon);
  1446 	if (http)
  1447 		evhttp_free(http);
  1450 /*
  1451  * HTTP POST test.
  1452  */
  1454 void http_postrequest_done(struct evhttp_request *, void *);
  1456 #define POST_DATA "Okay.  Not really printf"
  1458 static void
  1459 http_post_test(void *arg)
  1461 	struct basic_test_data *data = arg;
  1462 	ev_uint16_t port = 0;
  1463 	struct evhttp_connection *evcon = NULL;
  1464 	struct evhttp_request *req = NULL;
  1466 	test_ok = 0;
  1468 	http = http_setup(&port, data->base);
  1470 	evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port);
  1471 	tt_assert(evcon);
  1473 	/*
  1474 	 * At this point, we want to schedule an HTTP POST request
  1475 	 * server using our make request method.
  1476 	 */
  1478 	req = evhttp_request_new(http_postrequest_done, data->base);
  1479 	tt_assert(req);
  1481 	/* Add the information that we care about */
  1482 	evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
  1483 	evbuffer_add_printf(evhttp_request_get_output_buffer(req), POST_DATA);
  1485 	if (evhttp_make_request(evcon, req, EVHTTP_REQ_POST, "/postit") == -1) {
  1486 		tt_abort_msg("Couldn't make request");
  1489 	event_base_dispatch(data->base);
  1491 	tt_int_op(test_ok, ==, 1);
  1493 	test_ok = 0;
  1495 	req = evhttp_request_new(http_postrequest_done, data->base);
  1496 	tt_assert(req);
  1498 	/* Now try with 100-continue. */
  1500 	/* Add the information that we care about */
  1501 	evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
  1502 	evhttp_add_header(evhttp_request_get_output_headers(req), "Expect", "100-continue");
  1503 	evbuffer_add_printf(evhttp_request_get_output_buffer(req), POST_DATA);
  1505 	if (evhttp_make_request(evcon, req, EVHTTP_REQ_POST, "/postit") == -1) {
  1506 		tt_abort_msg("Couldn't make request");
  1509 	event_base_dispatch(data->base);
  1511 	tt_int_op(test_ok, ==, 1);
  1513 	evhttp_connection_free(evcon);
  1514 	evhttp_free(http);
  1516  end:
  1520 void
  1521 http_post_cb(struct evhttp_request *req, void *arg)
  1523 	struct evbuffer *evb;
  1524 	event_debug(("%s: called\n", __func__));
  1526 	/* Yes, we are expecting a post request */
  1527 	if (evhttp_request_get_command(req) != EVHTTP_REQ_POST) {
  1528 		fprintf(stdout, "FAILED (post type)\n");
  1529 		exit(1);
  1532 	if (evbuffer_get_length(evhttp_request_get_input_buffer(req)) != strlen(POST_DATA)) {
  1533 		fprintf(stdout, "FAILED (length: %lu vs %lu)\n",
  1534 		    (unsigned long) evbuffer_get_length(evhttp_request_get_input_buffer(req)), (unsigned long) strlen(POST_DATA));
  1535 		exit(1);
  1538 	if (evbuffer_datacmp(evhttp_request_get_input_buffer(req), POST_DATA) != 0) {
  1539 		fprintf(stdout, "FAILED (data)\n");
  1540 		fprintf(stdout, "Got :%s\n", evbuffer_pullup(evhttp_request_get_input_buffer(req),-1));
  1541 		fprintf(stdout, "Want:%s\n", POST_DATA);
  1542 		exit(1);
  1545 	evb = evbuffer_new();
  1546 	evbuffer_add_printf(evb, BASIC_REQUEST_BODY);
  1548 	evhttp_send_reply(req, HTTP_OK, "Everything is fine", evb);
  1550 	evbuffer_free(evb);
  1553 void
  1554 http_postrequest_done(struct evhttp_request *req, void *arg)
  1556 	const char *what = BASIC_REQUEST_BODY;
  1557 	struct event_base *base = arg;
  1559 	if (req == NULL) {
  1560 		fprintf(stderr, "FAILED (timeout)\n");
  1561 		exit(1);
  1564 	if (evhttp_request_get_response_code(req) != HTTP_OK) {
  1566 		fprintf(stderr, "FAILED (response code)\n");
  1567 		exit(1);
  1570 	if (evhttp_find_header(evhttp_request_get_input_headers(req), "Content-Type") == NULL) {
  1571 		fprintf(stderr, "FAILED (content type)\n");
  1572 		exit(1);
  1575 	if (evbuffer_get_length(evhttp_request_get_input_buffer(req)) != strlen(what)) {
  1576 		fprintf(stderr, "FAILED (length %lu vs %lu)\n",
  1577 		    (unsigned long)evbuffer_get_length(evhttp_request_get_input_buffer(req)), (unsigned long)strlen(what));
  1578 		exit(1);
  1581 	if (evbuffer_datacmp(evhttp_request_get_input_buffer(req), what) != 0) {
  1582 		fprintf(stderr, "FAILED (data)\n");
  1583 		exit(1);
  1586 	test_ok = 1;
  1587 	event_base_loopexit(base, NULL);
  1590 /*
  1591  * HTTP PUT test, basically just like POST, but ...
  1592  */
  1594 void http_putrequest_done(struct evhttp_request *, void *);
  1596 #define PUT_DATA "Hi, I'm some PUT data"
  1598 static void
  1599 http_put_test(void *arg)
  1601 	struct basic_test_data *data = arg;
  1602 	ev_uint16_t port = 0;
  1603 	struct evhttp_connection *evcon = NULL;
  1604 	struct evhttp_request *req = NULL;
  1606 	test_ok = 0;
  1608 	http = http_setup(&port, data->base);
  1610 	evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port);
  1611 	tt_assert(evcon);
  1613 	/*
  1614 	 * Schedule the HTTP PUT request
  1615 	 */
  1617 	req = evhttp_request_new(http_putrequest_done, data->base);
  1618 	tt_assert(req);
  1620 	/* Add the information that we care about */
  1621 	evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "someotherhost");
  1622 	evbuffer_add_printf(evhttp_request_get_output_buffer(req), PUT_DATA);
  1624 	if (evhttp_make_request(evcon, req, EVHTTP_REQ_PUT, "/putit") == -1) {
  1625 		tt_abort_msg("Couldn't make request");
  1628 	event_base_dispatch(data->base);
  1630 	evhttp_connection_free(evcon);
  1631 	evhttp_free(http);
  1633 	tt_int_op(test_ok, ==, 1);
  1634  end:
  1638 void
  1639 http_put_cb(struct evhttp_request *req, void *arg)
  1641 	struct evbuffer *evb;
  1642 	event_debug(("%s: called\n", __func__));
  1644 	/* Expecting a PUT request */
  1645 	if (evhttp_request_get_command(req) != EVHTTP_REQ_PUT) {
  1646 		fprintf(stdout, "FAILED (put type)\n");
  1647 		exit(1);
  1650 	if (evbuffer_get_length(evhttp_request_get_input_buffer(req)) != strlen(PUT_DATA)) {
  1651 		fprintf(stdout, "FAILED (length: %lu vs %lu)\n",
  1652 		    (unsigned long)evbuffer_get_length(evhttp_request_get_input_buffer(req)), (unsigned long)strlen(PUT_DATA));
  1653 		exit(1);
  1656 	if (evbuffer_datacmp(evhttp_request_get_input_buffer(req), PUT_DATA) != 0) {
  1657 		fprintf(stdout, "FAILED (data)\n");
  1658 		fprintf(stdout, "Got :%s\n", evbuffer_pullup(evhttp_request_get_input_buffer(req),-1));
  1659 		fprintf(stdout, "Want:%s\n", PUT_DATA);
  1660 		exit(1);
  1663 	evb = evbuffer_new();
  1664 	evbuffer_add_printf(evb, "That ain't funny");
  1666 	evhttp_send_reply(req, HTTP_OK, "Everything is great", evb);
  1668 	evbuffer_free(evb);
  1671 void
  1672 http_putrequest_done(struct evhttp_request *req, void *arg)
  1674 	struct event_base *base = arg;
  1675 	const char *what = "That ain't funny";
  1677 	if (req == NULL) {
  1678 		fprintf(stderr, "FAILED (timeout)\n");
  1679 		exit(1);
  1682 	if (evhttp_request_get_response_code(req) != HTTP_OK) {
  1684 		fprintf(stderr, "FAILED (response code)\n");
  1685 		exit(1);
  1688 	if (evhttp_find_header(evhttp_request_get_input_headers(req), "Content-Type") == NULL) {
  1689 		fprintf(stderr, "FAILED (content type)\n");
  1690 		exit(1);
  1693 	if (evbuffer_get_length(evhttp_request_get_input_buffer(req)) != strlen(what)) {
  1694 		fprintf(stderr, "FAILED (length %lu vs %lu)\n",
  1695 		    (unsigned long)evbuffer_get_length(evhttp_request_get_input_buffer(req)), (unsigned long)strlen(what));
  1696 		exit(1);
  1700 	if (evbuffer_datacmp(evhttp_request_get_input_buffer(req), what) != 0) {
  1701 		fprintf(stderr, "FAILED (data)\n");
  1702 		exit(1);
  1705 	test_ok = 1;
  1706 	event_base_loopexit(base, NULL);
  1709 static void
  1710 http_failure_readcb(struct bufferevent *bev, void *arg)
  1712 	const char *what = "400 Bad Request";
  1713 	if (evbuffer_contains(bufferevent_get_input(bev), what)) {
  1714 		test_ok = 2;
  1715 		bufferevent_disable(bev, EV_READ);
  1716 		event_base_loopexit(arg, NULL);
  1720 /*
  1721  * Testing that the HTTP server can deal with a malformed request.
  1722  */
  1723 static void
  1724 http_failure_test(void *arg)
  1726 	struct basic_test_data *data = arg;
  1727 	struct bufferevent *bev;
  1728 	evutil_socket_t fd;
  1729 	const char *http_request;
  1730 	ev_uint16_t port = 0;
  1732 	test_ok = 0;
  1734 	http = http_setup(&port, data->base);
  1736 	fd = http_connect("127.0.0.1", port);
  1738 	/* Stupid thing to send a request */
  1739 	bev = bufferevent_socket_new(data->base, fd, 0);
  1740 	bufferevent_setcb(bev, http_failure_readcb, http_writecb,
  1741 	    http_errorcb, data->base);
  1743 	http_request = "illegal request\r\n";
  1745 	bufferevent_write(bev, http_request, strlen(http_request));
  1747 	event_base_dispatch(data->base);
  1749 	bufferevent_free(bev);
  1750 	evutil_closesocket(fd);
  1752 	evhttp_free(http);
  1754 	tt_int_op(test_ok, ==, 2);
  1755  end:
  1759 static void
  1760 close_detect_done(struct evhttp_request *req, void *arg)
  1762 	struct timeval tv;
  1763 	tt_assert(req);
  1764 	tt_assert(evhttp_request_get_response_code(req) == HTTP_OK);
  1766 	test_ok = 1;
  1768  end:
  1769 	evutil_timerclear(&tv);
  1770 	tv.tv_sec = 3;
  1771 	event_base_loopexit(arg, &tv);
  1774 static void
  1775 close_detect_launch(evutil_socket_t fd, short what, void *arg)
  1777 	struct evhttp_connection *evcon = arg;
  1778 	struct event_base *base = evhttp_connection_get_base(evcon);
  1779 	struct evhttp_request *req;
  1781 	req = evhttp_request_new(close_detect_done, base);
  1783 	/* Add the information that we care about */
  1784 	evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
  1786 	/* We give ownership of the request to the connection */
  1787 	if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test") == -1) {
  1788 		tt_fail_msg("Couldn't make request");
  1792 static void
  1793 close_detect_cb(struct evhttp_request *req, void *arg)
  1795 	struct evhttp_connection *evcon = arg;
  1796 	struct event_base *base = evhttp_connection_get_base(evcon);
  1797 	struct timeval tv;
  1799 	if (req != NULL && evhttp_request_get_response_code(req) != HTTP_OK) {
  1800 		tt_abort_msg("Failed");
  1803 	evutil_timerclear(&tv);
  1804 	tv.tv_sec = 3;   /* longer than the http time out */
  1806 	/* launch a new request on the persistent connection in 3 seconds */
  1807 	event_base_once(base, -1, EV_TIMEOUT, close_detect_launch, evcon, &tv);
  1808  end:
  1813 static void
  1814 _http_close_detection(struct basic_test_data *data, int with_delay)
  1816 	ev_uint16_t port = 0;
  1817 	struct evhttp_connection *evcon = NULL;
  1818 	struct evhttp_request *req = NULL;
  1820 	test_ok = 0;
  1821 	http = http_setup(&port, data->base);
  1823 	/* 2 second timeout */
  1824 	evhttp_set_timeout(http, 1);
  1826 	evcon = evhttp_connection_base_new(data->base, NULL,
  1827 	    "127.0.0.1", port);
  1828 	tt_assert(evcon);
  1829 	delayed_client = evcon;
  1831 	/*
  1832 	 * At this point, we want to schedule a request to the HTTP
  1833 	 * server using our make request method.
  1834 	 */
  1836 	req = evhttp_request_new(close_detect_cb, evcon);
  1838 	/* Add the information that we care about */
  1839 	evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
  1841 	/* We give ownership of the request to the connection */
  1842 	if (evhttp_make_request(evcon,
  1843 	    req, EVHTTP_REQ_GET, with_delay ? "/largedelay" : "/test") == -1) {
  1844 		tt_abort_msg("couldn't make request");
  1847 	event_base_dispatch(data->base);
  1849 	/* at this point, the http server should have no connection */
  1850 	tt_assert(TAILQ_FIRST(&http->connections) == NULL);
  1852  end:
  1853 	if (evcon)
  1854 		evhttp_connection_free(evcon);
  1855 	if (http)
  1856 		evhttp_free(http);
  1858 static void
  1859 http_close_detection_test(void *arg)
  1861 	_http_close_detection(arg, 0);
  1863 static void
  1864 http_close_detection_delay_test(void *arg)
  1866 	_http_close_detection(arg, 1);
  1869 static void
  1870 http_highport_test(void *arg)
  1872 	struct basic_test_data *data = arg;
  1873 	int i = -1;
  1874 	struct evhttp *myhttp = NULL;
  1876 	/* Try a few different ports */
  1877 	for (i = 0; i < 50; ++i) {
  1878 		myhttp = evhttp_new(data->base);
  1879 		if (evhttp_bind_socket(myhttp, "127.0.0.1", 65535 - i) == 0) {
  1880 			test_ok = 1;
  1881 			evhttp_free(myhttp);
  1882 			return;
  1884 		evhttp_free(myhttp);
  1887 	tt_fail_msg("Couldn't get a high port");
  1890 static void
  1891 http_bad_header_test(void *ptr)
  1893 	struct evkeyvalq headers;
  1895 	TAILQ_INIT(&headers);
  1897 	tt_want(evhttp_add_header(&headers, "One", "Two") == 0);
  1898 	tt_want(evhttp_add_header(&headers, "One", "Two\r\n Three") == 0);
  1899 	tt_want(evhttp_add_header(&headers, "One\r", "Two") == -1);
  1900 	tt_want(evhttp_add_header(&headers, "One\n", "Two") == -1);
  1901 	tt_want(evhttp_add_header(&headers, "One", "Two\r") == -1);
  1902 	tt_want(evhttp_add_header(&headers, "One", "Two\n") == -1);
  1904 	evhttp_clear_headers(&headers);
  1907 static int validate_header(
  1908 	const struct evkeyvalq* headers,
  1909 	const char *key, const char *value)
  1911 	const char *real_val = evhttp_find_header(headers, key);
  1912 	tt_assert(real_val != NULL);
  1913 	tt_want(strcmp(real_val, value) == 0);
  1914 end:
  1915 	return (0);
  1918 static void
  1919 http_parse_query_test(void *ptr)
  1921 	struct evkeyvalq headers;
  1922 	int r;
  1924 	TAILQ_INIT(&headers);
  1926 	r = evhttp_parse_query("http://www.test.com/?q=test", &headers);
  1927 	tt_want(validate_header(&headers, "q", "test") == 0);
  1928 	tt_int_op(r, ==, 0);
  1929 	evhttp_clear_headers(&headers);
  1931 	r = evhttp_parse_query("http://www.test.com/?q=test&foo=bar", &headers);
  1932 	tt_want(validate_header(&headers, "q", "test") == 0);
  1933 	tt_want(validate_header(&headers, "foo", "bar") == 0);
  1934 	tt_int_op(r, ==, 0);
  1935 	evhttp_clear_headers(&headers);
  1937 	r = evhttp_parse_query("http://www.test.com/?q=test+foo", &headers);
  1938 	tt_want(validate_header(&headers, "q", "test foo") == 0);
  1939 	tt_int_op(r, ==, 0);
  1940 	evhttp_clear_headers(&headers);
  1942 	r = evhttp_parse_query("http://www.test.com/?q=test%0Afoo", &headers);
  1943 	tt_want(validate_header(&headers, "q", "test\nfoo") == 0);
  1944 	tt_int_op(r, ==, 0);
  1945 	evhttp_clear_headers(&headers);
  1947 	r = evhttp_parse_query("http://www.test.com/?q=test%0Dfoo", &headers);
  1948 	tt_want(validate_header(&headers, "q", "test\rfoo") == 0);
  1949 	tt_int_op(r, ==, 0);
  1950 	evhttp_clear_headers(&headers);
  1952 	r = evhttp_parse_query("http://www.test.com/?q=test&&q2", &headers);
  1953 	tt_int_op(r, ==, -1);
  1954 	evhttp_clear_headers(&headers);
  1956 	r = evhttp_parse_query("http://www.test.com/?q=test+this", &headers);
  1957 	tt_want(validate_header(&headers, "q", "test this") == 0);
  1958 	tt_int_op(r, ==, 0);
  1959 	evhttp_clear_headers(&headers);
  1961 	r = evhttp_parse_query("http://www.test.com/?q=test&q2=foo", &headers);
  1962 	tt_int_op(r, ==, 0);
  1963 	tt_want(validate_header(&headers, "q", "test") == 0);
  1964 	tt_want(validate_header(&headers, "q2", "foo") == 0);
  1965 	evhttp_clear_headers(&headers);
  1967 	r = evhttp_parse_query("http://www.test.com/?q&q2=foo", &headers);
  1968 	tt_int_op(r, ==, -1);
  1969 	evhttp_clear_headers(&headers);
  1971 	r = evhttp_parse_query("http://www.test.com/?q=foo&q2", &headers);
  1972 	tt_int_op(r, ==, -1);
  1973 	evhttp_clear_headers(&headers);
  1975 	r = evhttp_parse_query("http://www.test.com/?q=foo&q2&q3=x", &headers);
  1976 	tt_int_op(r, ==, -1);
  1977 	evhttp_clear_headers(&headers);
  1979 	r = evhttp_parse_query("http://www.test.com/?q=&q2=&q3=", &headers);
  1980 	tt_int_op(r, ==, 0);
  1981 	tt_want(validate_header(&headers, "q", "") == 0);
  1982 	tt_want(validate_header(&headers, "q2", "") == 0);
  1983 	tt_want(validate_header(&headers, "q3", "") == 0);
  1984 	evhttp_clear_headers(&headers);
  1986 end:
  1987 	evhttp_clear_headers(&headers);
  1990 static void
  1991 http_parse_uri_test(void *ptr)
  1993 	const int nonconform = (ptr != NULL);
  1994 	const unsigned parse_flags =
  1995 	    nonconform ? EVHTTP_URI_NONCONFORMANT : 0;
  1996 	struct evhttp_uri *uri = NULL;
  1997 	char url_tmp[4096];
  1998 #define URI_PARSE(uri) \
  1999 	evhttp_uri_parse_with_flags((uri), parse_flags)
  2001 #define TT_URI(want) do { 						\
  2002 	char *ret = evhttp_uri_join(uri, url_tmp, sizeof(url_tmp));	\
  2003 	tt_want(ret != NULL);						\
  2004 	tt_want(ret == url_tmp);					\
  2005 	if (strcmp(ret,want) != 0)					\
  2006 		TT_FAIL(("\"%s\" != \"%s\"",ret,want));			\
  2007 	} while(0)
  2009 	tt_want(evhttp_uri_join(NULL, 0, 0) == NULL);
  2010 	tt_want(evhttp_uri_join(NULL, url_tmp, 0) == NULL);
  2011 	tt_want(evhttp_uri_join(NULL, url_tmp, sizeof(url_tmp)) == NULL);
  2013 	/* bad URIs: parsing */
  2014 #define BAD(s) do {							\
  2015 		if (URI_PARSE(s) != NULL)				\
  2016 			TT_FAIL(("Expected error parsing \"%s\"",s));	\
  2017 	} while(0)
  2018 	/* Nonconformant URIs we can parse: parsing */
  2019 #define NCF(s) do {							\
  2020 		uri = URI_PARSE(s);					\
  2021 		if (uri != NULL && !nonconform) {			\
  2022 			TT_FAIL(("Expected error parsing \"%s\"",s));	\
  2023 		} else if (uri == NULL && nonconform) {			\
  2024 			TT_FAIL(("Couldn't parse nonconformant URI \"%s\"", \
  2025 				s));					\
  2026 		}							\
  2027 		if (uri) {						\
  2028 			tt_want(evhttp_uri_join(uri, url_tmp,		\
  2029 				sizeof(url_tmp)));			\
  2030 			evhttp_uri_free(uri);				\
  2031 		}							\
  2032 	} while(0)
  2034 	NCF("http://www.test.com/ why hello");
  2035 	NCF("http://www.test.com/why-hello\x01");
  2036 	NCF("http://www.test.com/why-hello?\x01");
  2037 	NCF("http://www.test.com/why-hello#\x01");
  2038 	BAD("http://www.\x01.test.com/why-hello");
  2039 	BAD("http://www.%7test.com/why-hello");
  2040 	NCF("http://www.test.com/why-hell%7o");
  2041 	BAD("h%3ttp://www.test.com/why-hello");
  2042 	NCF("http://www.test.com/why-hello%7");
  2043 	NCF("http://www.test.com/why-hell%7o");
  2044 	NCF("http://www.test.com/foo?ba%r");
  2045 	NCF("http://www.test.com/foo#ba%r");
  2046 	BAD("99:99/foo");
  2047 	BAD("http://www.test.com:999x/");
  2048 	BAD("http://www.test.com:x/");
  2049 	BAD("http://[hello-there]/");
  2050 	BAD("http://[::1]]/");
  2051 	BAD("http://[::1/");
  2052 	BAD("http://[foob/");
  2053 	BAD("http://[/");
  2054 	BAD("http://[ffff:ffff:ffff:ffff:Ffff:ffff:ffff:"
  2055 	            "ffff:ffff:ffff:ffff:ffff:ffff:ffff]/");
  2056 	BAD("http://[vX.foo]/");
  2057 	BAD("http://[vX.foo]/");
  2058 	BAD("http://[v.foo]/");
  2059 	BAD("http://[v5.fo%o]/");
  2060 	BAD("http://[v5X]/");
  2061 	BAD("http://[v5]/");
  2062 	BAD("http://[]/");
  2063 	BAD("http://f\x01red@www.example.com/");
  2064 	BAD("http://f%0red@www.example.com/");
  2065 	BAD("http://www.example.com:9999999999999999999999999999999999999/");
  2066 	BAD("http://www.example.com:hihi/");
  2067 	BAD("://www.example.com/");
  2069 	/* bad URIs: joining */
  2070 	uri = evhttp_uri_new();
  2071 	tt_want(0==evhttp_uri_set_host(uri, "www.example.com"));
  2072 	tt_want(evhttp_uri_join(uri, url_tmp, sizeof(url_tmp)) != NULL);
  2073 	/* not enough space: */
  2074 	tt_want(evhttp_uri_join(uri, url_tmp, 3) == NULL);
  2075 	/* host is set, but path doesn't start with "/": */
  2076 	tt_want(0==evhttp_uri_set_path(uri, "hi_mom"));
  2077 	tt_want(evhttp_uri_join(uri, url_tmp, sizeof(url_tmp)) == NULL);
  2078 	tt_want(evhttp_uri_join(uri, NULL, sizeof(url_tmp))==NULL);
  2079 	tt_want(evhttp_uri_join(uri, url_tmp, 0)==NULL);
  2080 	evhttp_uri_free(uri);
  2081 	uri = URI_PARSE("mailto:foo@bar");
  2082 	tt_want(uri != NULL);
  2083 	tt_want(evhttp_uri_get_host(uri) == NULL);
  2084 	tt_want(evhttp_uri_get_userinfo(uri) == NULL);
  2085 	tt_want(evhttp_uri_get_port(uri) == -1);
  2086 	tt_want(!strcmp(evhttp_uri_get_scheme(uri), "mailto"));
  2087 	tt_want(!strcmp(evhttp_uri_get_path(uri), "foo@bar"));
  2088 	tt_want(evhttp_uri_get_query(uri) == NULL);
  2089 	tt_want(evhttp_uri_get_fragment(uri) == NULL);
  2090 	TT_URI("mailto:foo@bar");
  2091 	evhttp_uri_free(uri);
  2093 	uri = evhttp_uri_new();
  2094 	/* Bad URI usage: setting invalid values */
  2095 	tt_want(-1 == evhttp_uri_set_scheme(uri,""));
  2096 	tt_want(-1 == evhttp_uri_set_scheme(uri,"33"));
  2097 	tt_want(-1 == evhttp_uri_set_scheme(uri,"hi!"));
  2098 	tt_want(-1 == evhttp_uri_set_userinfo(uri,"hello@"));
  2099 	tt_want(-1 == evhttp_uri_set_host(uri,"[1.2.3.4]"));
  2100 	tt_want(-1 == evhttp_uri_set_host(uri,"["));
  2101 	tt_want(-1 == evhttp_uri_set_host(uri,"www.[foo].com"));
  2102 	tt_want(-1 == evhttp_uri_set_port(uri,-3));
  2103 	tt_want(-1 == evhttp_uri_set_path(uri,"hello?world"));
  2104 	tt_want(-1 == evhttp_uri_set_query(uri,"hello#world"));
  2105 	tt_want(-1 == evhttp_uri_set_fragment(uri,"hello#world"));
  2106 	/* Valid URI usage: setting valid values */
  2107 	tt_want(0 == evhttp_uri_set_scheme(uri,"http"));
  2108 	tt_want(0 == evhttp_uri_set_scheme(uri,NULL));
  2109 	tt_want(0 == evhttp_uri_set_userinfo(uri,"username:pass"));
  2110 	tt_want(0 == evhttp_uri_set_userinfo(uri,NULL));
  2111 	tt_want(0 == evhttp_uri_set_host(uri,"www.example.com"));
  2112 	tt_want(0 == evhttp_uri_set_host(uri,"1.2.3.4"));
  2113 	tt_want(0 == evhttp_uri_set_host(uri,"[1:2:3:4::]"));
  2114 	tt_want(0 == evhttp_uri_set_host(uri,"[v7.wobblewobble]"));
  2115 	tt_want(0 == evhttp_uri_set_host(uri,NULL));
  2116 	tt_want(0 == evhttp_uri_set_host(uri,""));
  2117 	tt_want(0 == evhttp_uri_set_port(uri, -1));
  2118 	tt_want(0 == evhttp_uri_set_port(uri, 80));
  2119 	tt_want(0 == evhttp_uri_set_port(uri, 65535));
  2120 	tt_want(0 == evhttp_uri_set_path(uri, ""));
  2121 	tt_want(0 == evhttp_uri_set_path(uri, "/documents/public/index.html"));
  2122 	tt_want(0 == evhttp_uri_set_path(uri, NULL));
  2123 	tt_want(0 == evhttp_uri_set_query(uri, "key=val&key2=val2"));
  2124 	tt_want(0 == evhttp_uri_set_query(uri, "keyvalblarg"));
  2125 	tt_want(0 == evhttp_uri_set_query(uri, ""));
  2126 	tt_want(0 == evhttp_uri_set_query(uri, NULL));
  2127 	tt_want(0 == evhttp_uri_set_fragment(uri, ""));
  2128 	tt_want(0 == evhttp_uri_set_fragment(uri, "here?i?am"));
  2129 	tt_want(0 == evhttp_uri_set_fragment(uri, NULL));
  2130 	evhttp_uri_free(uri);
  2132 	/* Valid parsing */
  2133 	uri = URI_PARSE("http://www.test.com/?q=t%33est");
  2134 	tt_want(strcmp(evhttp_uri_get_scheme(uri), "http") == 0);
  2135 	tt_want(strcmp(evhttp_uri_get_host(uri), "www.test.com") == 0);
  2136 	tt_want(strcmp(evhttp_uri_get_path(uri), "/") == 0);
  2137 	tt_want(strcmp(evhttp_uri_get_query(uri), "q=t%33est") == 0);
  2138 	tt_want(evhttp_uri_get_userinfo(uri) == NULL);
  2139 	tt_want(evhttp_uri_get_port(uri) == -1);
  2140 	tt_want(evhttp_uri_get_fragment(uri) == NULL);
  2141 	TT_URI("http://www.test.com/?q=t%33est");
  2142 	evhttp_uri_free(uri);
  2144 	uri = URI_PARSE("http://%77ww.test.com");
  2145 	tt_want(strcmp(evhttp_uri_get_scheme(uri), "http") == 0);
  2146 	tt_want(strcmp(evhttp_uri_get_host(uri), "%77ww.test.com") == 0);
  2147 	tt_want(strcmp(evhttp_uri_get_path(uri), "") == 0);
  2148 	tt_want(evhttp_uri_get_query(uri) == NULL);
  2149 	tt_want(evhttp_uri_get_userinfo(uri) == NULL);
  2150 	tt_want(evhttp_uri_get_port(uri) == -1);
  2151 	tt_want(evhttp_uri_get_fragment(uri) == NULL);
  2152 	TT_URI("http://%77ww.test.com");
  2153 	evhttp_uri_free(uri);
  2155 	uri = URI_PARSE("http://www.test.com?q=test");
  2156 	tt_want(strcmp(evhttp_uri_get_scheme(uri), "http") == 0);
  2157 	tt_want(strcmp(evhttp_uri_get_host(uri), "www.test.com") == 0);
  2158 	tt_want(strcmp(evhttp_uri_get_path(uri), "") == 0);
  2159 	tt_want(strcmp(evhttp_uri_get_query(uri), "q=test") == 0);
  2160 	tt_want(evhttp_uri_get_userinfo(uri) == NULL);
  2161 	tt_want(evhttp_uri_get_port(uri) == -1);
  2162 	tt_want(evhttp_uri_get_fragment(uri) == NULL);
  2163 	TT_URI("http://www.test.com?q=test");
  2164 	evhttp_uri_free(uri);
  2166 	uri = URI_PARSE("http://www.test.com#fragment");
  2167 	tt_want(strcmp(evhttp_uri_get_scheme(uri), "http") == 0);
  2168 	tt_want(strcmp(evhttp_uri_get_host(uri), "www.test.com") == 0);
  2169 	tt_want(strcmp(evhttp_uri_get_path(uri), "") == 0);
  2170 	tt_want(evhttp_uri_get_query(uri) == NULL);
  2171 	tt_want(evhttp_uri_get_userinfo(uri) == NULL);
  2172 	tt_want(evhttp_uri_get_port(uri) == -1);
  2173 	tt_want_str_op(evhttp_uri_get_fragment(uri), ==, "fragment");
  2174 	TT_URI("http://www.test.com#fragment");
  2175 	evhttp_uri_free(uri);
  2177 	uri = URI_PARSE("http://8000/");
  2178 	tt_want(strcmp(evhttp_uri_get_scheme(uri), "http") == 0);
  2179 	tt_want(strcmp(evhttp_uri_get_host(uri), "8000") == 0);
  2180 	tt_want(strcmp(evhttp_uri_get_path(uri), "/") == 0);
  2181 	tt_want(evhttp_uri_get_query(uri) == NULL);
  2182 	tt_want(evhttp_uri_get_userinfo(uri) == NULL);
  2183 	tt_want(evhttp_uri_get_port(uri) == -1);
  2184 	tt_want(evhttp_uri_get_fragment(uri) == NULL);
  2185 	TT_URI("http://8000/");
  2186 	evhttp_uri_free(uri);
  2188 	uri = URI_PARSE("http://:8000/");
  2189 	tt_want(strcmp(evhttp_uri_get_scheme(uri), "http") == 0);
  2190 	tt_want(strcmp(evhttp_uri_get_host(uri), "") == 0);
  2191 	tt_want(strcmp(evhttp_uri_get_path(uri), "/") == 0);
  2192 	tt_want(evhttp_uri_get_query(uri) == NULL);
  2193 	tt_want(evhttp_uri_get_userinfo(uri) == NULL);
  2194 	tt_want(evhttp_uri_get_port(uri) == 8000);
  2195 	tt_want(evhttp_uri_get_fragment(uri) == NULL);
  2196 	TT_URI("http://:8000/");
  2197 	evhttp_uri_free(uri);
  2199 	uri = URI_PARSE("http://www.test.com:/"); /* empty port */
  2200 	tt_want(strcmp(evhttp_uri_get_scheme(uri), "http") == 0);
  2201 	tt_want(strcmp(evhttp_uri_get_host(uri), "www.test.com") == 0);
  2202 	tt_want_str_op(evhttp_uri_get_path(uri), ==, "/");
  2203 	tt_want(evhttp_uri_get_query(uri) == NULL);
  2204 	tt_want(evhttp_uri_get_userinfo(uri) == NULL);
  2205 	tt_want(evhttp_uri_get_port(uri) == -1);
  2206 	tt_want(evhttp_uri_get_fragment(uri) == NULL);
  2207 	TT_URI("http://www.test.com/");
  2208 	evhttp_uri_free(uri);
  2210 	uri = URI_PARSE("http://www.test.com:"); /* empty port 2 */
  2211 	tt_want(strcmp(evhttp_uri_get_scheme(uri), "http") == 0);
  2212 	tt_want(strcmp(evhttp_uri_get_host(uri), "www.test.com") == 0);
  2213 	tt_want(strcmp(evhttp_uri_get_path(uri), "") == 0);
  2214 	tt_want(evhttp_uri_get_query(uri) == NULL);
  2215 	tt_want(evhttp_uri_get_userinfo(uri) == NULL);
  2216 	tt_want(evhttp_uri_get_port(uri) == -1);
  2217 	tt_want(evhttp_uri_get_fragment(uri) == NULL);
  2218 	TT_URI("http://www.test.com");
  2219 	evhttp_uri_free(uri);
  2221 	uri = URI_PARSE("ftp://www.test.com/?q=test");
  2222 	tt_want(strcmp(evhttp_uri_get_scheme(uri), "ftp") == 0);
  2223 	tt_want(strcmp(evhttp_uri_get_host(uri), "www.test.com") == 0);
  2224 	tt_want(strcmp(evhttp_uri_get_path(uri), "/") == 0);
  2225 	tt_want(strcmp(evhttp_uri_get_query(uri), "q=test") == 0);
  2226 	tt_want(evhttp_uri_get_userinfo(uri) == NULL);
  2227 	tt_want(evhttp_uri_get_port(uri) == -1);
  2228 	tt_want(evhttp_uri_get_fragment(uri) == NULL);
  2229 	TT_URI("ftp://www.test.com/?q=test");
  2230 	evhttp_uri_free(uri);
  2232 	uri = URI_PARSE("ftp://[::1]:999/?q=test");
  2233 	tt_want(strcmp(evhttp_uri_get_scheme(uri), "ftp") == 0);
  2234 	tt_want(strcmp(evhttp_uri_get_host(uri), "[::1]") == 0);
  2235 	tt_want(strcmp(evhttp_uri_get_path(uri), "/") == 0);
  2236 	tt_want(strcmp(evhttp_uri_get_query(uri), "q=test") == 0);
  2237 	tt_want(evhttp_uri_get_userinfo(uri) == NULL);
  2238 	tt_want(evhttp_uri_get_port(uri) == 999);
  2239 	tt_want(evhttp_uri_get_fragment(uri) == NULL);
  2240 	TT_URI("ftp://[::1]:999/?q=test");
  2241 	evhttp_uri_free(uri);
  2243 	uri = URI_PARSE("ftp://[ff00::127.0.0.1]/?q=test");
  2244 	tt_want(strcmp(evhttp_uri_get_scheme(uri), "ftp") == 0);
  2245 	tt_want(strcmp(evhttp_uri_get_host(uri), "[ff00::127.0.0.1]") == 0);
  2246 	tt_want(strcmp(evhttp_uri_get_path(uri), "/") == 0);
  2247 	tt_want(strcmp(evhttp_uri_get_query(uri), "q=test") == 0);
  2248 	tt_want(evhttp_uri_get_userinfo(uri) == NULL);
  2249 	tt_want(evhttp_uri_get_port(uri) == -1);
  2250 	tt_want(evhttp_uri_get_fragment(uri) == NULL);
  2251 	TT_URI("ftp://[ff00::127.0.0.1]/?q=test");
  2252 	evhttp_uri_free(uri);
  2254 	uri = URI_PARSE("ftp://[v99.not_(any:time)_soon]/?q=test");
  2255 	tt_want(strcmp(evhttp_uri_get_scheme(uri), "ftp") == 0);
  2256 	tt_want(strcmp(evhttp_uri_get_host(uri), "[v99.not_(any:time)_soon]") == 0);
  2257 	tt_want(strcmp(evhttp_uri_get_path(uri), "/") == 0);
  2258 	tt_want(strcmp(evhttp_uri_get_query(uri), "q=test") == 0);
  2259 	tt_want(evhttp_uri_get_userinfo(uri) == NULL);
  2260 	tt_want(evhttp_uri_get_port(uri) == -1);
  2261 	tt_want(evhttp_uri_get_fragment(uri) == NULL);
  2262 	TT_URI("ftp://[v99.not_(any:time)_soon]/?q=test");
  2263 	evhttp_uri_free(uri);
  2265 	uri = URI_PARSE("scheme://user:pass@foo.com:42/?q=test&s=some+thing#fragment");
  2266 	tt_want(strcmp(evhttp_uri_get_scheme(uri), "scheme") == 0);
  2267 	tt_want(strcmp(evhttp_uri_get_userinfo(uri), "user:pass") == 0);
  2268 	tt_want(strcmp(evhttp_uri_get_host(uri), "foo.com") == 0);
  2269 	tt_want(evhttp_uri_get_port(uri) == 42);
  2270 	tt_want(strcmp(evhttp_uri_get_path(uri), "/") == 0);
  2271 	tt_want(strcmp(evhttp_uri_get_query(uri), "q=test&s=some+thing") == 0);
  2272 	tt_want(strcmp(evhttp_uri_get_fragment(uri), "fragment") == 0);
  2273 	TT_URI("scheme://user:pass@foo.com:42/?q=test&s=some+thing#fragment");
  2274 	evhttp_uri_free(uri);
  2276 	uri = URI_PARSE("scheme://user@foo.com/#fragment");
  2277 	tt_want(strcmp(evhttp_uri_get_scheme(uri), "scheme") == 0);
  2278 	tt_want(strcmp(evhttp_uri_get_userinfo(uri), "user") == 0);
  2279 	tt_want(strcmp(evhttp_uri_get_host(uri), "foo.com") == 0);
  2280 	tt_want(evhttp_uri_get_port(uri) == -1);
  2281 	tt_want(strcmp(evhttp_uri_get_path(uri), "/") == 0);
  2282 	tt_want(evhttp_uri_get_query(uri) == NULL);
  2283 	tt_want(strcmp(evhttp_uri_get_fragment(uri), "fragment") == 0);
  2284 	TT_URI("scheme://user@foo.com/#fragment");
  2285 	evhttp_uri_free(uri);
  2287 	uri = URI_PARSE("scheme://%75ser@foo.com/#frag@ment");
  2288 	tt_want(strcmp(evhttp_uri_get_scheme(uri), "scheme") == 0);
  2289 	tt_want(strcmp(evhttp_uri_get_userinfo(uri), "%75ser") == 0);
  2290 	tt_want(strcmp(evhttp_uri_get_host(uri), "foo.com") == 0);
  2291 	tt_want(evhttp_uri_get_port(uri) == -1);
  2292 	tt_want(strcmp(evhttp_uri_get_path(uri), "/") == 0);
  2293 	tt_want(evhttp_uri_get_query(uri) == NULL);
  2294 	tt_want(strcmp(evhttp_uri_get_fragment(uri), "frag@ment") == 0);
  2295 	TT_URI("scheme://%75ser@foo.com/#frag@ment");
  2296 	evhttp_uri_free(uri);
  2298 	uri = URI_PARSE("file:///some/path/to/the/file");
  2299 	tt_want(strcmp(evhttp_uri_get_scheme(uri), "file") == 0);
  2300 	tt_want(evhttp_uri_get_userinfo(uri) == NULL);
  2301 	tt_want(strcmp(evhttp_uri_get_host(uri), "") == 0);
  2302 	tt_want(evhttp_uri_get_port(uri) == -1);
  2303 	tt_want(strcmp(evhttp_uri_get_path(uri), "/some/path/to/the/file") == 0);
  2304 	tt_want(evhttp_uri_get_query(uri) == NULL);
  2305 	tt_want(evhttp_uri_get_fragment(uri) == NULL);
  2306 	TT_URI("file:///some/path/to/the/file");
  2307 	evhttp_uri_free(uri);
  2309 	uri = URI_PARSE("///some/path/to/the-file");
  2310 	tt_want(uri != NULL);
  2311 	tt_want(evhttp_uri_get_scheme(uri) == NULL);
  2312 	tt_want(evhttp_uri_get_userinfo(uri) == NULL);
  2313 	tt_want(strcmp(evhttp_uri_get_host(uri), "") == 0);
  2314 	tt_want(evhttp_uri_get_port(uri) == -1);
  2315 	tt_want(strcmp(evhttp_uri_get_path(uri), "/some/path/to/the-file") == 0);
  2316 	tt_want(evhttp_uri_get_query(uri) == NULL);
  2317 	tt_want(evhttp_uri_get_fragment(uri) == NULL);
  2318 	TT_URI("///some/path/to/the-file");
  2319 	evhttp_uri_free(uri);
  2321 	uri = URI_PARSE("/s:ome/path/to/the-file?q=99#fred");
  2322 	tt_want(uri != NULL);
  2323 	tt_want(evhttp_uri_get_scheme(uri) == NULL);
  2324 	tt_want(evhttp_uri_get_userinfo(uri) == NULL);
  2325 	tt_want(evhttp_uri_get_host(uri) == NULL);
  2326 	tt_want(evhttp_uri_get_port(uri) == -1);
  2327 	tt_want(strcmp(evhttp_uri_get_path(uri), "/s:ome/path/to/the-file") == 0);
  2328 	tt_want(strcmp(evhttp_uri_get_query(uri), "q=99") == 0);
  2329 	tt_want(strcmp(evhttp_uri_get_fragment(uri), "fred") == 0);
  2330 	TT_URI("/s:ome/path/to/the-file?q=99#fred");
  2331 	evhttp_uri_free(uri);
  2333 	uri = URI_PARSE("relative/path/with/co:lon");
  2334 	tt_want(uri != NULL);
  2335 	tt_want(evhttp_uri_get_scheme(uri) == NULL);
  2336 	tt_want(evhttp_uri_get_userinfo(uri) == NULL);
  2337 	tt_want(evhttp_uri_get_host(uri) == NULL);
  2338 	tt_want(evhttp_uri_get_port(uri) == -1);
  2339 	tt_want(strcmp(evhttp_uri_get_path(uri), "relative/path/with/co:lon") == 0);
  2340 	tt_want(evhttp_uri_get_query(uri) == NULL);
  2341 	tt_want(evhttp_uri_get_fragment(uri) == NULL);
  2342 	TT_URI("relative/path/with/co:lon");
  2343 	evhttp_uri_free(uri);
  2345 	uri = URI_PARSE("bob?q=99&q2=q?33#fr?ed");
  2346 	tt_want(uri != NULL);
  2347 	tt_want(evhttp_uri_get_scheme(uri) == NULL);
  2348 	tt_want(evhttp_uri_get_userinfo(uri) == NULL);
  2349 	tt_want(evhttp_uri_get_host(uri) == NULL);
  2350 	tt_want(evhttp_uri_get_port(uri) == -1);
  2351 	tt_want(strcmp(evhttp_uri_get_path(uri), "bob") == 0);
  2352 	tt_want(strcmp(evhttp_uri_get_query(uri), "q=99&q2=q?33") == 0);
  2353 	tt_want(strcmp(evhttp_uri_get_fragment(uri), "fr?ed") == 0);
  2354 	TT_URI("bob?q=99&q2=q?33#fr?ed");
  2355 	evhttp_uri_free(uri);
  2357 	uri = URI_PARSE("#fr?ed");
  2358 	tt_want(uri != NULL);
  2359 	tt_want(evhttp_uri_get_scheme(uri) == NULL);
  2360 	tt_want(evhttp_uri_get_userinfo(uri) == NULL);
  2361 	tt_want(evhttp_uri_get_host(uri) == NULL);
  2362 	tt_want(evhttp_uri_get_port(uri) == -1);
  2363 	tt_want(strcmp(evhttp_uri_get_path(uri), "") == 0);
  2364 	tt_want(evhttp_uri_get_query(uri) == NULL);
  2365 	tt_want(strcmp(evhttp_uri_get_fragment(uri), "fr?ed") == 0);
  2366 	TT_URI("#fr?ed");
  2367 	evhttp_uri_free(uri);
  2368 #undef URI_PARSE
  2369 #undef TT_URI
  2370 #undef BAD
  2373 static void
  2374 http_uriencode_test(void *ptr)
  2376 	char *s=NULL, *s2=NULL;
  2377 	size_t sz;
  2379 #define ENC(from,want,plus) do {				\
  2380 		s = evhttp_uriencode((from), -1, (plus));	\
  2381 		tt_assert(s);					\
  2382 		tt_str_op(s,==,(want));				\
  2383 		sz = -1;					\
  2384 		s2 = evhttp_uridecode((s), (plus), &sz);	\
  2385 		tt_assert(s2);					\
  2386 		tt_str_op(s2,==,(from));			\
  2387 		tt_int_op(sz,==,strlen(from));			\
  2388 		free(s);					\
  2389 		free(s2);					\
  2390 		s = s2 = NULL;					\
  2391 	} while (0)
  2393 #define DEC(from,want,dp) do {					\
  2394 		s = evhttp_uridecode((from),(dp),&sz);		\
  2395 		tt_assert(s);					\
  2396 		tt_str_op(s,==,(want));				\
  2397 		tt_int_op(sz,==,strlen(want));			\
  2398 		free(s);					\
  2399 		s = NULL;					\
  2400 	} while (0)
  2402 #define OLD_DEC(from,want)  do {				\
  2403 		s = evhttp_decode_uri((from));			\
  2404 		tt_assert(s);					\
  2405 		tt_str_op(s,==,(want));				\
  2406 		free(s);					\
  2407 		s = NULL;					\
  2408 	} while (0)
  2411       	ENC("Hello", "Hello",0);
  2412 	ENC("99", "99",0);
  2413 	ENC("", "",0);
  2414 	ENC(
  2415 	 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ123456789-.~_",
  2416 	 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ123456789-.~_",0);
  2417 	ENC(" ", "%20",0);
  2418 	ENC(" ", "+",1);
  2419 	ENC("\xff\xf0\xe0", "%FF%F0%E0",0);
  2420 	ENC("\x01\x19", "%01%19",1);
  2421 	ENC("http://www.ietf.org/rfc/rfc3986.txt",
  2422 	    "http%3A%2F%2Fwww.ietf.org%2Frfc%2Frfc3986.txt",1);
  2424 	ENC("1+2=3", "1%2B2%3D3",1);
  2425 	ENC("1+2=3", "1%2B2%3D3",0);
  2427 	/* Now try encoding with internal NULs. */
  2428 	s = evhttp_uriencode("hello\0world", 11, 0);
  2429 	tt_assert(s);
  2430 	tt_str_op(s,==,"hello%00world");
  2431 	free(s);
  2432 	s = NULL;
  2434 	/* Now try out some decoding cases that we don't generate with
  2435 	 * encode_uri: Make sure that malformed stuff doesn't crash... */
  2436 	DEC("%%xhello th+ere \xff",
  2437 	    "%%xhello th+ere \xff", 0);
  2438 	/* Make sure plus decoding works */
  2439 	DEC("plus+should%20work+", "plus should work ",1);
  2440 	/* Try some lowercase hex */
  2441 	DEC("%f0%a0%b0", "\xf0\xa0\xb0",1);
  2443 	/* Try an internal NUL. */
  2444 	sz = 0;
  2445 	s = evhttp_uridecode("%00%00x%00%00", 1, &sz);
  2446 	tt_int_op(sz,==,5);
  2447 	tt_assert(!memcmp(s, "\0\0x\0\0", 5));
  2448 	free(s);
  2449 	s = NULL;
  2451 	/* Try with size == NULL */
  2452 	sz = 0;
  2453 	s = evhttp_uridecode("%00%00x%00%00", 1, NULL);
  2454 	tt_assert(!memcmp(s, "\0\0x\0\0", 5));
  2455 	free(s);
  2456 	s = NULL;
  2458 	/* Test out the crazy old behavior of the deprecated
  2459 	 * evhttp_decode_uri */
  2460 	OLD_DEC("http://example.com/normal+path/?key=val+with+spaces",
  2461 	        "http://example.com/normal+path/?key=val with spaces");
  2463 end:
  2464 	if (s)
  2465 		free(s);
  2466 	if (s2)
  2467 		free(s2);
  2468 #undef ENC
  2469 #undef DEC
  2470 #undef OLD_DEC
  2473 static void
  2474 http_base_test(void *ptr)
  2476 	struct event_base *base = NULL;
  2477 	struct bufferevent *bev;
  2478 	evutil_socket_t fd;
  2479 	const char *http_request;
  2480 	ev_uint16_t port = 0;
  2482 	test_ok = 0;
  2483 	base = event_base_new();
  2484 	http = http_setup(&port, base);
  2486 	fd = http_connect("127.0.0.1", port);
  2488 	/* Stupid thing to send a request */
  2489 	bev = bufferevent_socket_new(base, fd, 0);
  2490 	bufferevent_setcb(bev, http_readcb, http_writecb,
  2491 	    http_errorcb, base);
  2492 	bufferevent_base_set(base, bev);
  2494 	http_request =
  2495 	    "GET /test HTTP/1.1\r\n"
  2496 	    "Host: somehost\r\n"
  2497 	    "Connection: close\r\n"
  2498 	    "\r\n";
  2500 	bufferevent_write(bev, http_request, strlen(http_request));
  2502 	event_base_dispatch(base);
  2504 	bufferevent_free(bev);
  2505 	evutil_closesocket(fd);
  2507 	evhttp_free(http);
  2509 	tt_int_op(test_ok, ==, 2);
  2511 end:
  2512 	if (base)
  2513 		event_base_free(base);
  2516 /*
  2517  * the server is just going to close the connection if it times out during
  2518  * reading the headers.
  2519  */
  2521 static void
  2522 http_incomplete_readcb(struct bufferevent *bev, void *arg)
  2524 	test_ok = -1;
  2525 	event_base_loopexit(exit_base,NULL);
  2528 static void
  2529 http_incomplete_errorcb(struct bufferevent *bev, short what, void *arg)
  2531 	if (what == (BEV_EVENT_READING|BEV_EVENT_EOF))
  2532 		test_ok++;
  2533 	else
  2534 		test_ok = -2;
  2535 	event_base_loopexit(exit_base,NULL);
  2538 static void
  2539 http_incomplete_writecb(struct bufferevent *bev, void *arg)
  2541 	if (arg != NULL) {
  2542 		evutil_socket_t fd = *(evutil_socket_t *)arg;
  2543 		/* terminate the write side to simulate EOF */
  2544 		shutdown(fd, SHUT_WR);
  2546 	if (evbuffer_get_length(bufferevent_get_output(bev)) == 0) {
  2547 		/* enable reading of the reply */
  2548 		bufferevent_enable(bev, EV_READ);
  2549 		test_ok++;
  2553 static void
  2554 _http_incomplete_test(struct basic_test_data *data, int use_timeout)
  2556 	struct bufferevent *bev;
  2557 	evutil_socket_t fd;
  2558 	const char *http_request;
  2559 	ev_uint16_t port = 0;
  2560 	struct timeval tv_start, tv_end;
  2562 	exit_base = data->base;
  2564 	test_ok = 0;
  2566 	http = http_setup(&port, data->base);
  2567 	evhttp_set_timeout(http, 1);
  2569 	fd = http_connect("127.0.0.1", port);
  2571 	/* Stupid thing to send a request */
  2572 	bev = bufferevent_socket_new(data->base, fd, 0);
  2573 	bufferevent_setcb(bev,
  2574 	    http_incomplete_readcb, http_incomplete_writecb,
  2575 	    http_incomplete_errorcb, use_timeout ? NULL : &fd);
  2577 	http_request =
  2578 	    "GET /test HTTP/1.1\r\n"
  2579 	    "Host: somehost\r\n";
  2581 	bufferevent_write(bev, http_request, strlen(http_request));
  2583 	evutil_gettimeofday(&tv_start, NULL);
  2585 	event_base_dispatch(data->base);
  2587 	evutil_gettimeofday(&tv_end, NULL);
  2588 	evutil_timersub(&tv_end, &tv_start, &tv_end);
  2590 	bufferevent_free(bev);
  2591 	if (use_timeout) {
  2592 		evutil_closesocket(fd);
  2595 	evhttp_free(http);
  2597 	if (use_timeout && tv_end.tv_sec >= 3) {
  2598 		tt_abort_msg("time");
  2599 	} else if (!use_timeout && tv_end.tv_sec >= 1) {
  2600 		/* we should be done immediately */
  2601 		tt_abort_msg("time");
  2604 	tt_int_op(test_ok, ==, 2);
  2605  end:
  2608 static void
  2609 http_incomplete_test(void *arg)
  2611 	_http_incomplete_test(arg, 0);
  2613 static void
  2614 http_incomplete_timeout_test(void *arg)
  2616 	_http_incomplete_test(arg, 1);
  2619 /*
  2620  * the server is going to reply with chunked data.
  2621  */
  2623 static void
  2624 http_chunked_readcb(struct bufferevent *bev, void *arg)
  2626 	/* nothing here */
  2629 static void
  2630 http_chunked_errorcb(struct bufferevent *bev, short what, void *arg)
  2632 	if (!test_ok)
  2633 		goto out;
  2635 	test_ok = -1;
  2637 	if ((what & BEV_EVENT_EOF) != 0) {
  2638 		struct evhttp_request *req = evhttp_request_new(NULL, NULL);
  2639 		const char *header;
  2640 		enum message_read_status done;
  2642 		/* req->kind = EVHTTP_RESPONSE; */
  2643 		done = evhttp_parse_firstline(req, bufferevent_get_input(bev));
  2644 		if (done != ALL_DATA_READ)
  2645 			goto out;
  2647 		done = evhttp_parse_headers(req, bufferevent_get_input(bev));
  2648 		if (done != ALL_DATA_READ)
  2649 			goto out;
  2651 		header = evhttp_find_header(evhttp_request_get_input_headers(req), "Transfer-Encoding");
  2652 		if (header == NULL || strcmp(header, "chunked"))
  2653 			goto out;
  2655 		header = evhttp_find_header(evhttp_request_get_input_headers(req), "Connection");
  2656 		if (header == NULL || strcmp(header, "close"))
  2657 			goto out;
  2659 		header = evbuffer_readln(bufferevent_get_input(bev), NULL, EVBUFFER_EOL_CRLF);
  2660 		if (header == NULL)
  2661 			goto out;
  2662 		/* 13 chars */
  2663 		if (strcmp(header, "d")) {
  2664 			free((void*)header);
  2665 			goto out;
  2667 		free((void*)header);
  2669 		if (strncmp((char *)evbuffer_pullup(bufferevent_get_input(bev), 13),
  2670 			"This is funny", 13))
  2671 			goto out;
  2673 		evbuffer_drain(bufferevent_get_input(bev), 13 + 2);
  2675 		header = evbuffer_readln(bufferevent_get_input(bev), NULL, EVBUFFER_EOL_CRLF);
  2676 		if (header == NULL)
  2677 			goto out;
  2678 		/* 18 chars */
  2679 		if (strcmp(header, "12"))
  2680 			goto out;
  2681 		free((char *)header);
  2683 		if (strncmp((char *)evbuffer_pullup(bufferevent_get_input(bev), 18),
  2684 			"but not hilarious.", 18))
  2685 			goto out;
  2687 		evbuffer_drain(bufferevent_get_input(bev), 18 + 2);
  2689 		header = evbuffer_readln(bufferevent_get_input(bev), NULL, EVBUFFER_EOL_CRLF);
  2690 		if (header == NULL)
  2691 			goto out;
  2692 		/* 8 chars */
  2693 		if (strcmp(header, "8")) {
  2694 			free((void*)header);
  2695 			goto out;
  2697 		free((char *)header);
  2699 		if (strncmp((char *)evbuffer_pullup(bufferevent_get_input(bev), 8),
  2700 			"bwv 1052.", 8))
  2701 			goto out;
  2703 		evbuffer_drain(bufferevent_get_input(bev), 8 + 2);
  2705 		header = evbuffer_readln(bufferevent_get_input(bev), NULL, EVBUFFER_EOL_CRLF);
  2706 		if (header == NULL)
  2707 			goto out;
  2708 		/* 0 chars */
  2709 		if (strcmp(header, "0")) {
  2710 			free((void*)header);
  2711 			goto out;
  2713 		free((void *)header);
  2715 		test_ok = 2;
  2717 		evhttp_request_free(req);
  2720 out:
  2721 	event_base_loopexit(arg, NULL);
  2724 static void
  2725 http_chunked_writecb(struct bufferevent *bev, void *arg)
  2727 	if (evbuffer_get_length(bufferevent_get_output(bev)) == 0) {
  2728 		/* enable reading of the reply */
  2729 		bufferevent_enable(bev, EV_READ);
  2730 		test_ok++;
  2734 static void
  2735 http_chunked_request_done(struct evhttp_request *req, void *arg)
  2737 	if (evhttp_request_get_response_code(req) != HTTP_OK) {
  2738 		fprintf(stderr, "FAILED\n");
  2739 		exit(1);
  2742 	if (evhttp_find_header(evhttp_request_get_input_headers(req),
  2743 		"Transfer-Encoding") == NULL) {
  2744 		fprintf(stderr, "FAILED\n");
  2745 		exit(1);
  2748 	if (evbuffer_get_length(evhttp_request_get_input_buffer(req)) != 13 + 18 + 8) {
  2749 		fprintf(stderr, "FAILED\n");
  2750 		exit(1);
  2753 	if (strncmp((char *)evbuffer_pullup(evhttp_request_get_input_buffer(req), 13 + 18 + 8),
  2754 		"This is funnybut not hilarious.bwv 1052",
  2755 		13 + 18 + 8)) {
  2756 		fprintf(stderr, "FAILED\n");
  2757 		exit(1);
  2760 	test_ok = 1;
  2761 	event_base_loopexit(arg, NULL);
  2764 static void
  2765 http_chunk_out_test(void *arg)
  2767 	struct basic_test_data *data = arg;
  2768 	struct bufferevent *bev;
  2769 	evutil_socket_t fd;
  2770 	const char *http_request;
  2771 	ev_uint16_t port = 0;
  2772 	struct timeval tv_start, tv_end;
  2773 	struct evhttp_connection *evcon = NULL;
  2774 	struct evhttp_request *req = NULL;
  2775 	int i;
  2777 	exit_base = data->base;
  2778 	test_ok = 0;
  2780 	http = http_setup(&port, data->base);
  2782 	fd = http_connect("127.0.0.1", port);
  2784 	/* Stupid thing to send a request */
  2785 	bev = bufferevent_socket_new(data->base, fd, 0);
  2786 	bufferevent_setcb(bev,
  2787 	    http_chunked_readcb, http_chunked_writecb,
  2788 	    http_chunked_errorcb, data->base);
  2790 	http_request =
  2791 	    "GET /chunked HTTP/1.1\r\n"
  2792 	    "Host: somehost\r\n"
  2793 	    "Connection: close\r\n"
  2794 	    "\r\n";
  2796 	bufferevent_write(bev, http_request, strlen(http_request));
  2798 	evutil_gettimeofday(&tv_start, NULL);
  2800 	event_base_dispatch(data->base);
  2802 	bufferevent_free(bev);
  2804 	evutil_gettimeofday(&tv_end, NULL);
  2805 	evutil_timersub(&tv_end, &tv_start, &tv_end);
  2807 	tt_int_op(tv_end.tv_sec, <, 1);
  2809 	tt_int_op(test_ok, ==, 2);
  2811 	/* now try again with the regular connection object */
  2812 	evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port);
  2813 	tt_assert(evcon);
  2815 	/* make two requests to check the keepalive behavior */
  2816 	for (i = 0; i < 2; i++) {
  2817 		test_ok = 0;
  2818 		req = evhttp_request_new(http_chunked_request_done,data->base);
  2820 		/* Add the information that we care about */
  2821 		evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
  2823 		/* We give ownership of the request to the connection */
  2824 		if (evhttp_make_request(evcon, req,
  2825 			EVHTTP_REQ_GET, "/chunked") == -1) {
  2826 			tt_abort_msg("Couldn't make request");
  2829 		event_base_dispatch(data->base);
  2831 		tt_assert(test_ok == 1);
  2834  end:
  2835 	if (evcon)
  2836 		evhttp_connection_free(evcon);
  2837 	if (http)
  2838 		evhttp_free(http);
  2841 static void
  2842 http_stream_out_test(void *arg)
  2844 	struct basic_test_data *data = arg;
  2845 	ev_uint16_t port = 0;
  2846 	struct evhttp_connection *evcon = NULL;
  2847 	struct evhttp_request *req = NULL;
  2849 	test_ok = 0;
  2850 	exit_base = data->base;
  2852 	http = http_setup(&port, data->base);
  2854 	evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port);
  2855 	tt_assert(evcon);
  2857 	/*
  2858 	 * At this point, we want to schedule a request to the HTTP
  2859 	 * server using our make request method.
  2860 	 */
  2862 	req = evhttp_request_new(http_request_done,
  2863 	    (void *)"This is funnybut not hilarious.bwv 1052");
  2865 	/* Add the information that we care about */
  2866 	evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
  2868 	/* We give ownership of the request to the connection */
  2869 	if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/streamed")
  2870 	    == -1) {
  2871 		tt_abort_msg("Couldn't make request");
  2874 	event_base_dispatch(data->base);
  2876  end:
  2877 	if (evcon)
  2878 		evhttp_connection_free(evcon);
  2879 	if (http)
  2880 		evhttp_free(http);
  2883 static void
  2884 http_stream_in_chunk(struct evhttp_request *req, void *arg)
  2886 	struct evbuffer *reply = arg;
  2888 	if (evhttp_request_get_response_code(req) != HTTP_OK) {
  2889 		fprintf(stderr, "FAILED\n");
  2890 		exit(1);
  2893 	evbuffer_add_buffer(reply, evhttp_request_get_input_buffer(req));
  2896 static void
  2897 http_stream_in_done(struct evhttp_request *req, void *arg)
  2899 	if (evbuffer_get_length(evhttp_request_get_input_buffer(req)) != 0) {
  2900 		fprintf(stderr, "FAILED\n");
  2901 		exit(1);
  2904 	event_base_loopexit(exit_base, NULL);
  2907 /**
  2908  * Makes a request and reads the response in chunks.
  2909  */
  2910 static void
  2911 _http_stream_in_test(struct basic_test_data *data, char const *url,
  2912     size_t expected_len, char const *expected)
  2914 	struct evhttp_connection *evcon;
  2915 	struct evbuffer *reply = evbuffer_new();
  2916 	struct evhttp_request *req = NULL;
  2917 	ev_uint16_t port = 0;
  2919 	exit_base = data->base;
  2920 	http = http_setup(&port, data->base);
  2922 	evcon = evhttp_connection_base_new(data->base, NULL,"127.0.0.1", port);
  2923 	tt_assert(evcon);
  2925 	req = evhttp_request_new(http_stream_in_done, reply);
  2926 	evhttp_request_set_chunked_cb(req, http_stream_in_chunk);
  2928 	/* We give ownership of the request to the connection */
  2929 	if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, url) == -1) {
  2930 		tt_abort_msg("Couldn't make request");
  2933 	event_base_dispatch(data->base);
  2935 	if (evbuffer_get_length(reply) != expected_len) {
  2936 		TT_DIE(("reply length %lu; expected %lu; FAILED (%s)\n",
  2937 				(unsigned long)evbuffer_get_length(reply),
  2938 				(unsigned long)expected_len,
  2939 				(char*)evbuffer_pullup(reply, -1)));
  2942 	if (memcmp(evbuffer_pullup(reply, -1), expected, expected_len) != 0) {
  2943 		tt_abort_msg("Memory mismatch");
  2946 	test_ok = 1;
  2947  end:
  2948 	if (reply)
  2949 		evbuffer_free(reply);
  2950 	if (evcon)
  2951 		evhttp_connection_free(evcon);
  2952 	if (http)
  2953 		evhttp_free(http);
  2956 static void
  2957 http_stream_in_test(void *arg)
  2959 	_http_stream_in_test(arg, "/chunked", 13 + 18 + 8,
  2960 	    "This is funnybut not hilarious.bwv 1052");
  2962 	_http_stream_in_test(arg, "/test", strlen(BASIC_REQUEST_BODY),
  2963 	    BASIC_REQUEST_BODY);
  2966 static void
  2967 http_stream_in_cancel_chunk(struct evhttp_request *req, void *arg)
  2969 	tt_int_op(evhttp_request_get_response_code(req), ==, HTTP_OK);
  2971  end:
  2972 	evhttp_cancel_request(req);
  2973 	event_base_loopexit(arg, NULL);
  2976 static void
  2977 http_stream_in_cancel_done(struct evhttp_request *req, void *arg)
  2979 	/* should never be called */
  2980 	tt_fail_msg("In cancel done");
  2983 static void
  2984 http_stream_in_cancel_test(void *arg)
  2986 	struct basic_test_data *data = arg;
  2987 	struct evhttp_connection *evcon;
  2988 	struct evhttp_request *req = NULL;
  2989 	ev_uint16_t port = 0;
  2991 	http = http_setup(&port, data->base);
  2993 	evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port);
  2994 	tt_assert(evcon);
  2996 	req = evhttp_request_new(http_stream_in_cancel_done, data->base);
  2997 	evhttp_request_set_chunked_cb(req, http_stream_in_cancel_chunk);
  2999 	/* We give ownership of the request to the connection */
  3000 	if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/chunked") == -1) {
  3001 		tt_abort_msg("Couldn't make request");
  3004 	event_base_dispatch(data->base);
  3006 	test_ok = 1;
  3007  end:
  3008 	evhttp_connection_free(evcon);
  3009 	evhttp_free(http);
  3013 static void
  3014 http_connection_fail_done(struct evhttp_request *req, void *arg)
  3016        /* An ENETUNREACH error results in an unrecoverable
  3017         * evhttp_connection error (see evhttp_connection_fail()).  The
  3018         * connection will be reset, and the user will be notified with a NULL
  3019         * req parameter. */
  3020        tt_assert(!req);
  3022        test_ok = 1;
  3024  end:
  3025        event_base_loopexit(arg, NULL);
  3028 /* Test unrecoverable evhttp_connection errors by generating an ENETUNREACH
  3029  * error on connection. */
  3030 static void
  3031 http_connection_fail_test(void *arg)
  3033        struct basic_test_data *data = arg;
  3034        ev_uint16_t port = 0;
  3035        struct evhttp_connection *evcon = NULL;
  3036        struct evhttp_request *req = NULL;
  3038        exit_base = data->base;
  3039        test_ok = 0;
  3041        /* auto detect a port */
  3042        http = http_setup(&port, data->base);
  3043        evhttp_free(http);
  3044        http = NULL;
  3046        /* Pick an unroutable address.  This administratively scoped multicast
  3047 	* address should do when working with TCP. */
  3048        evcon = evhttp_connection_base_new(data->base, NULL, "239.10.20.30", 80);
  3049        tt_assert(evcon);
  3051        /*
  3052         * At this point, we want to schedule an HTTP GET request
  3053         * server using our make request method.
  3054         */
  3056        req = evhttp_request_new(http_connection_fail_done, data->base);
  3057        tt_assert(req);
  3059        if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/") == -1) {
  3060                tt_abort_msg("Couldn't make request");
  3063        event_base_dispatch(data->base);
  3065        tt_int_op(test_ok, ==, 1);
  3067  end:
  3068        if (evcon)
  3069                evhttp_connection_free(evcon);
  3072 static void
  3073 http_connection_retry_done(struct evhttp_request *req, void *arg)
  3075 	tt_assert(req);
  3076 	tt_int_op(evhttp_request_get_response_code(req), !=, HTTP_OK);
  3077 	if (evhttp_find_header(evhttp_request_get_input_headers(req), "Content-Type") != NULL) {
  3078 		tt_abort_msg("(content type)\n");
  3081 	tt_uint_op(evbuffer_get_length(evhttp_request_get_input_buffer(req)), ==, 0);
  3083 	test_ok = 1;
  3084  end:
  3085 	event_base_loopexit(arg,NULL);
  3088 static struct event_base *http_make_web_server_base=NULL;
  3089 static void
  3090 http_make_web_server(evutil_socket_t fd, short what, void *arg)
  3092 	ev_uint16_t port = *(ev_uint16_t*)arg;
  3093 	http = http_setup(&port, http_make_web_server_base);
  3096 static void
  3097 http_connection_retry_test(void *arg)
  3099 	struct basic_test_data *data = arg;
  3100 	ev_uint16_t port = 0;
  3101 	struct evhttp_connection *evcon = NULL;
  3102 	struct evhttp_request *req = NULL;
  3103 	struct timeval tv, tv_start, tv_end;
  3105 	exit_base = data->base;
  3106 	test_ok = 0;
  3108 	/* auto detect a port */
  3109 	http = http_setup(&port, data->base);
  3110 	evhttp_free(http);
  3111 	http = NULL;
  3113 	evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port);
  3114 	tt_assert(evcon);
  3116 	evhttp_connection_set_timeout(evcon, 1);
  3117 	/* also bind to local host */
  3118 	evhttp_connection_set_local_address(evcon, "127.0.0.1");
  3120 	/*
  3121 	 * At this point, we want to schedule an HTTP GET request
  3122 	 * server using our make request method.
  3123 	 */
  3125 	req = evhttp_request_new(http_connection_retry_done, data->base);
  3126 	tt_assert(req);
  3128 	/* Add the information that we care about */
  3129 	evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
  3131 	if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET,
  3132 		"/?arg=val") == -1) {
  3133 		tt_abort_msg("Couldn't make request");
  3136 	evutil_gettimeofday(&tv_start, NULL);
  3137 	event_base_dispatch(data->base);
  3138 	evutil_gettimeofday(&tv_end, NULL);
  3139 	evutil_timersub(&tv_end, &tv_start, &tv_end);
  3140 	tt_int_op(tv_end.tv_sec, <, 1);
  3142 	tt_int_op(test_ok, ==, 1);
  3144 	/*
  3145 	 * now test the same but with retries
  3146 	 */
  3147 	test_ok = 0;
  3149 	evhttp_connection_set_timeout(evcon, 1);
  3150 	evhttp_connection_set_retries(evcon, 1);
  3152 	req = evhttp_request_new(http_connection_retry_done, data->base);
  3153 	tt_assert(req);
  3155 	/* Add the information that we care about */
  3156 	evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
  3158 	if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET,
  3159 		"/?arg=val") == -1) {
  3160 		tt_abort_msg("Couldn't make request");
  3163 	evutil_gettimeofday(&tv_start, NULL);
  3164 	event_base_dispatch(data->base);
  3165 	evutil_gettimeofday(&tv_end, NULL);
  3166 	evutil_timersub(&tv_end, &tv_start, &tv_end);
  3167 	tt_int_op(tv_end.tv_sec, >, 1);
  3168 	tt_int_op(tv_end.tv_sec, <, 6);
  3170 	tt_assert(test_ok == 1);
  3172 	/*
  3173 	 * now test the same but with retries and give it a web server
  3174 	 * at the end
  3175 	 */
  3176 	test_ok = 0;
  3178 	evhttp_connection_set_timeout(evcon, 1);
  3179 	evhttp_connection_set_retries(evcon, 3);
  3181 	req = evhttp_request_new(http_dispatcher_test_done, data->base);
  3182 	tt_assert(req);
  3184 	/* Add the information that we care about */
  3185 	evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
  3187 	if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET,
  3188 		"/?arg=val") == -1) {
  3189 		tt_abort_msg("Couldn't make request");
  3192 	/* start up a web server one second after the connection tried
  3193 	 * to send a request
  3194 	 */
  3195 	evutil_timerclear(&tv);
  3196 	tv.tv_sec = 1;
  3197 	http_make_web_server_base = data->base;
  3198 	event_base_once(data->base, -1, EV_TIMEOUT, http_make_web_server, &port, &tv);
  3200 	evutil_gettimeofday(&tv_start, NULL);
  3201 	event_base_dispatch(data->base);
  3202 	evutil_gettimeofday(&tv_end, NULL);
  3204 	evutil_timersub(&tv_end, &tv_start, &tv_end);
  3206 	tt_int_op(tv_end.tv_sec, >, 1);
  3207 	tt_int_op(tv_end.tv_sec, <, 6);
  3209 	tt_int_op(test_ok, ==, 1);
  3211  end:
  3212 	if (evcon)
  3213 		evhttp_connection_free(evcon);
  3214 	if (http)
  3215 		evhttp_free(http);
  3218 static void
  3219 http_primitives(void *ptr)
  3221 	char *escaped = NULL;
  3222 	struct evhttp *http = NULL;
  3224 	escaped = evhttp_htmlescape("<script>");
  3225 	tt_assert(escaped);
  3226 	tt_str_op(escaped, ==, "&lt;script&gt;");
  3227 	free(escaped);
  3229 	escaped = evhttp_htmlescape("\"\'&");
  3230 	tt_assert(escaped);
  3231 	tt_str_op(escaped, ==, "&quot;&#039;&amp;");
  3233 	http = evhttp_new(NULL);
  3234 	tt_assert(http);
  3235 	tt_int_op(evhttp_set_cb(http, "/test", http_basic_cb, NULL), ==, 0);
  3236 	tt_int_op(evhttp_set_cb(http, "/test", http_basic_cb, NULL), ==, -1);
  3237 	tt_int_op(evhttp_del_cb(http, "/test"), ==, 0);
  3238 	tt_int_op(evhttp_del_cb(http, "/test"), ==, -1);
  3239 	tt_int_op(evhttp_set_cb(http, "/test", http_basic_cb, NULL), ==, 0);
  3241  end:
  3242 	if (escaped)
  3243 		free(escaped);
  3244 	if (http)
  3245 		evhttp_free(http);
  3248 static void
  3249 http_multi_line_header_test(void *arg)
  3251 	struct basic_test_data *data = arg;
  3252 	struct bufferevent *bev= NULL;
  3253 	evutil_socket_t fd = -1;
  3254 	const char *http_start_request;
  3255 	ev_uint16_t port = 0;
  3257 	test_ok = 0;
  3259 	http = http_setup(&port, data->base);
  3261 	fd = http_connect("127.0.0.1", port);
  3263 	/* Stupid thing to send a request */
  3264 	bev = bufferevent_socket_new(data->base, fd, 0);
  3265 	bufferevent_setcb(bev, http_readcb, http_writecb,
  3266 	    http_errorcb, data->base);
  3268 	http_start_request =
  3269 	    "GET /test HTTP/1.1\r\n"
  3270 	    "Host: somehost\r\n"
  3271 	    "Connection: close\r\n"
  3272 	    "X-Multi:  aaaaaaaa\r\n"
  3273 	    " a\r\n"
  3274 	    "\tEND\r\n"
  3275 	    "X-Last: last\r\n"
  3276 	    "\r\n";
  3278 	bufferevent_write(bev, http_start_request, strlen(http_start_request));
  3280 	event_base_dispatch(data->base);
  3282 	tt_int_op(test_ok, ==, 4);
  3283  end:
  3284 	if (bev)
  3285 		bufferevent_free(bev);
  3286 	if (fd >= 0)
  3287 		evutil_closesocket(fd);
  3288 	if (http)
  3289 		evhttp_free(http);
  3292 static void
  3293 http_request_bad(struct evhttp_request *req, void *arg)
  3295 	if (req != NULL) {
  3296 		fprintf(stderr, "FAILED\n");
  3297 		exit(1);
  3300 	test_ok = 1;
  3301 	event_base_loopexit(arg, NULL);
  3304 static void
  3305 http_negative_content_length_test(void *arg)
  3307 	struct basic_test_data *data = arg;
  3308 	ev_uint16_t port = 0;
  3309 	struct evhttp_connection *evcon = NULL;
  3310 	struct evhttp_request *req = NULL;
  3312 	test_ok = 0;
  3314 	http = http_setup(&port, data->base);
  3316 	evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port);
  3317 	tt_assert(evcon);
  3319 	/*
  3320 	 * At this point, we want to schedule a request to the HTTP
  3321 	 * server using our make request method.
  3322 	 */
  3324 	req = evhttp_request_new(http_request_bad, data->base);
  3326 	/* Cause the response to have a negative content-length */
  3327 	evhttp_add_header(evhttp_request_get_output_headers(req), "X-Negative", "makeitso");
  3329 	/* We give ownership of the request to the connection */
  3330 	if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test") == -1) {
  3331 		tt_abort_msg("Couldn't make request");
  3334 	event_base_dispatch(data->base);
  3336  end:
  3337 	if (evcon)
  3338 		evhttp_connection_free(evcon);
  3339 	if (http)
  3340 		evhttp_free(http);
  3344 static void
  3345 http_data_length_constraints_test_done(struct evhttp_request *req, void *arg)
  3347 	tt_assert(req);
  3348 	tt_int_op(evhttp_request_get_response_code(req), ==, HTTP_BADREQUEST);
  3349 end:
  3350 	event_base_loopexit(arg, NULL);
  3353 static void
  3354 http_large_entity_test_done(struct evhttp_request *req, void *arg)
  3356 	tt_assert(req);
  3357 	tt_int_op(evhttp_request_get_response_code(req), ==, HTTP_ENTITYTOOLARGE);
  3358 end:
  3359 	event_base_loopexit(arg, NULL);
  3362 static void
  3363 http_data_length_constraints_test(void *arg)
  3365 	struct basic_test_data *data = arg;
  3366 	ev_uint16_t port = 0;
  3367 	struct evhttp_connection *evcon = NULL;
  3368 	struct evhttp_request *req = NULL;
  3369 	char long_str[8192];
  3371 	test_ok = 0;
  3373 	http = http_setup(&port, data->base);
  3375 	evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port);
  3376 	tt_assert(evcon);
  3378 	/* also bind to local host */
  3379 	evhttp_connection_set_local_address(evcon, "127.0.0.1");
  3381 	/*
  3382 	 * At this point, we want to schedule an HTTP GET request
  3383 	 * server using our make request method.
  3384 	 */
  3386 	req = evhttp_request_new(http_data_length_constraints_test_done, data->base);
  3387 	tt_assert(req);
  3389 	memset(long_str, 'a', 8192);
  3390 	long_str[8191] = '\0';
  3391 	/* Add the information that we care about */
  3392 	evhttp_set_max_headers_size(http, 8191);
  3393 	evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
  3394 	evhttp_add_header(evhttp_request_get_output_headers(req), "Longheader", long_str);
  3396 	if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/?arg=val") == -1) {
  3397 		tt_abort_msg("Couldn't make request");
  3399 	event_base_dispatch(data->base);
  3401 	req = evhttp_request_new(http_data_length_constraints_test_done, data->base);
  3402 	tt_assert(req);
  3403 	evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
  3405 	/* GET /?arg=verylongvalue HTTP/1.1 */
  3406 	if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, long_str) == -1) {
  3407 		tt_abort_msg("Couldn't make request");
  3409 	event_base_dispatch(data->base);
  3411 	evhttp_set_max_body_size(http, 8190);
  3412 	req = evhttp_request_new(http_data_length_constraints_test_done, data->base);
  3413 	evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
  3414 	evbuffer_add_printf(evhttp_request_get_output_buffer(req), "%s", long_str);
  3415 	if (evhttp_make_request(evcon, req, EVHTTP_REQ_POST, "/") == -1) {
  3416 		tt_abort_msg("Couldn't make request");
  3418 	event_base_dispatch(data->base);
  3420 	req = evhttp_request_new(http_large_entity_test_done, data->base);
  3421 	evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
  3422 	evhttp_add_header(evhttp_request_get_output_headers(req), "Expect", "100-continue");
  3423 	evbuffer_add_printf(evhttp_request_get_output_buffer(req), "%s", long_str);
  3424 	if (evhttp_make_request(evcon, req, EVHTTP_REQ_POST, "/") == -1) {
  3425 		tt_abort_msg("Couldn't make request");
  3427 	event_base_dispatch(data->base);
  3429 	test_ok = 1;
  3430  end:
  3431 	if (evcon)
  3432 		evhttp_connection_free(evcon);
  3433 	if (http)
  3434 		evhttp_free(http);
  3437 /*
  3438  * Testing client reset of server chunked connections
  3439  */
  3441 struct terminate_state {
  3442 	struct event_base *base;
  3443 	struct evhttp_request *req;
  3444 	struct bufferevent *bev;
  3445 	evutil_socket_t fd;
  3446 	int gotclosecb: 1;
  3447 };
  3449 static void
  3450 terminate_chunked_trickle_cb(evutil_socket_t fd, short events, void *arg)
  3452 	struct terminate_state *state = arg;
  3453 	struct evbuffer *evb;
  3454 	struct timeval tv;
  3456 	if (evhttp_request_get_connection(state->req) == NULL) {
  3457 		test_ok = 1;
  3458 		evhttp_request_free(state->req);
  3459 		event_base_loopexit(state->base,NULL);
  3460 		return;
  3463 	evb = evbuffer_new();
  3464 	evbuffer_add_printf(evb, "%p", evb);
  3465 	evhttp_send_reply_chunk(state->req, evb);
  3466 	evbuffer_free(evb);
  3468 	tv.tv_sec = 0;
  3469 	tv.tv_usec = 3000;
  3470 	EVUTIL_ASSERT(state);
  3471 	EVUTIL_ASSERT(state->base);
  3472 	event_base_once(state->base, -1, EV_TIMEOUT, terminate_chunked_trickle_cb, arg, &tv);
  3475 static void
  3476 terminate_chunked_close_cb(struct evhttp_connection *evcon, void *arg)
  3478 	struct terminate_state *state = arg;
  3479 	state->gotclosecb = 1;
  3482 static void
  3483 terminate_chunked_cb(struct evhttp_request *req, void *arg)
  3485 	struct terminate_state *state = arg;
  3486 	struct timeval tv;
  3488 	/* we want to know if this connection closes on us */
  3489 	evhttp_connection_set_closecb(
  3490 		evhttp_request_get_connection(req),
  3491 		terminate_chunked_close_cb, arg);
  3493 	state->req = req;
  3495 	evhttp_send_reply_start(req, HTTP_OK, "OK");
  3497 	tv.tv_sec = 0;
  3498 	tv.tv_usec = 3000;
  3499 	event_base_once(state->base, -1, EV_TIMEOUT, terminate_chunked_trickle_cb, arg, &tv);
  3502 static void
  3503 terminate_chunked_client(evutil_socket_t fd, short event, void *arg)
  3505 	struct terminate_state *state = arg;
  3506 	bufferevent_free(state->bev);
  3507 	evutil_closesocket(state->fd);
  3510 static void
  3511 terminate_readcb(struct bufferevent *bev, void *arg)
  3513 	/* just drop the data */
  3514 	evbuffer_drain(bufferevent_get_input(bev), -1);
  3518 static void
  3519 http_terminate_chunked_test(void *arg)
  3521 	struct basic_test_data *data = arg;
  3522 	struct bufferevent *bev = NULL;
  3523 	struct timeval tv;
  3524 	const char *http_request;
  3525 	ev_uint16_t port = 0;
  3526 	evutil_socket_t fd = -1;
  3527 	struct terminate_state terminate_state;
  3529 	test_ok = 0;
  3531 	http = http_setup(&port, data->base);
  3532 	evhttp_del_cb(http, "/test");
  3533 	tt_assert(evhttp_set_cb(http, "/test",
  3534 		terminate_chunked_cb, &terminate_state) == 0);
  3536 	fd = http_connect("127.0.0.1", port);
  3538 	/* Stupid thing to send a request */
  3539 	bev = bufferevent_socket_new(data->base, fd, 0);
  3540 	bufferevent_setcb(bev, terminate_readcb, http_writecb,
  3541 	    http_errorcb, data->base);
  3543 	memset(&terminate_state, 0, sizeof(terminate_state));
  3544 	terminate_state.base = data->base;
  3545 	terminate_state.fd = fd;
  3546 	terminate_state.bev = bev;
  3547 	terminate_state.gotclosecb = 0;
  3549 	/* first half of the http request */
  3550 	http_request =
  3551 	    "GET /test HTTP/1.1\r\n"
  3552 	    "Host: some\r\n\r\n";
  3554 	bufferevent_write(bev, http_request, strlen(http_request));
  3555 	evutil_timerclear(&tv);
  3556 	tv.tv_usec = 10000;
  3557 	event_base_once(data->base, -1, EV_TIMEOUT, terminate_chunked_client, &terminate_state,
  3558 	    &tv);
  3560 	event_base_dispatch(data->base);
  3562 	if (terminate_state.gotclosecb == 0)
  3563 		test_ok = 0;
  3565  end:
  3566 	if (fd >= 0)
  3567 		evutil_closesocket(fd);
  3568 	if (http)
  3569 		evhttp_free(http);
  3572 #define HTTP_LEGACY(name)						\
  3573 	{ #name, run_legacy_test_fn, TT_ISOLATED|TT_LEGACY, &legacy_setup, \
  3574 		    http_##name##_test }
  3576 #define HTTP(name) \
  3577 	{ #name, http_##name##_test, TT_ISOLATED, &basic_setup, NULL }
  3579 struct testcase_t http_testcases[] = {
  3580 	{ "primitives", http_primitives, 0, NULL, NULL },
  3581 	{ "base", http_base_test, TT_FORK, NULL, NULL },
  3582 	{ "bad_headers", http_bad_header_test, 0, NULL, NULL },
  3583 	{ "parse_query", http_parse_query_test, 0, NULL, NULL },
  3584 	{ "parse_uri", http_parse_uri_test, 0, NULL, NULL },
  3585 	{ "parse_uri_nc", http_parse_uri_test, 0, &basic_setup, (void*)"nc" },
  3586 	{ "uriencode", http_uriencode_test, 0, NULL, NULL },
  3587 	HTTP(basic),
  3588 	HTTP(cancel),
  3589 	HTTP(virtual_host),
  3590 	HTTP(post),
  3591 	HTTP(put),
  3592 	HTTP(delete),
  3593 	HTTP(allowed_methods),
  3594 	HTTP(failure),
  3595 	HTTP(connection),
  3596 	HTTP(persist_connection),
  3597 	HTTP(connection_async),
  3598 	HTTP(close_detection),
  3599 	HTTP(close_detection_delay),
  3600 	HTTP(bad_request),
  3601 	HTTP(incomplete),
  3602 	HTTP(incomplete_timeout),
  3603 	HTTP(terminate_chunked),
  3605 	HTTP(highport),
  3606 	HTTP(dispatcher),
  3607 	HTTP(multi_line_header),
  3608 	HTTP(negative_content_length),
  3609 	HTTP(chunk_out),
  3610 	HTTP(stream_out),
  3612 	HTTP(stream_in),
  3613 	HTTP(stream_in_cancel),
  3615 	HTTP(connection_fail),
  3616 	HTTP(connection_retry),
  3617 	HTTP(data_length_constraints),
  3619 	END_OF_TESTCASES
  3620 };

mercurial