Home | History | Annotate | Line # | Download | only in test
regress_http.c revision 1.1
      1  1.1  plunky /*	$NetBSD: regress_http.c,v 1.1 2009/11/02 10:01:04 plunky Exp $	*/
      2  1.1  plunky /*
      3  1.1  plunky  * Copyright (c) 2003-2006 Niels Provos <provos (at) citi.umich.edu>
      4  1.1  plunky  * All rights reserved.
      5  1.1  plunky  *
      6  1.1  plunky  * Redistribution and use in source and binary forms, with or without
      7  1.1  plunky  * modification, are permitted provided that the following conditions
      8  1.1  plunky  * are met:
      9  1.1  plunky  * 1. Redistributions of source code must retain the above copyright
     10  1.1  plunky  *    notice, this list of conditions and the following disclaimer.
     11  1.1  plunky  * 2. Redistributions in binary form must reproduce the above copyright
     12  1.1  plunky  *    notice, this list of conditions and the following disclaimer in the
     13  1.1  plunky  *    documentation and/or other materials provided with the distribution.
     14  1.1  plunky  * 3. The name of the author may not be used to endorse or promote products
     15  1.1  plunky  *    derived from this software without specific prior written permission.
     16  1.1  plunky  *
     17  1.1  plunky  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     18  1.1  plunky  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     19  1.1  plunky  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     20  1.1  plunky  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     21  1.1  plunky  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     22  1.1  plunky  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     23  1.1  plunky  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     24  1.1  plunky  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     25  1.1  plunky  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     26  1.1  plunky  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     27  1.1  plunky  */
     28  1.1  plunky 
     29  1.1  plunky #ifdef WIN32
     30  1.1  plunky #include <winsock2.h>
     31  1.1  plunky #include <windows.h>
     32  1.1  plunky #endif
     33  1.1  plunky 
     34  1.1  plunky #ifdef HAVE_CONFIG_H
     35  1.1  plunky #include "config.h"
     36  1.1  plunky #endif
     37  1.1  plunky 
     38  1.1  plunky #include <sys/types.h>
     39  1.1  plunky #include <sys/stat.h>
     40  1.1  plunky #ifdef HAVE_SYS_TIME_H
     41  1.1  plunky #include <sys/time.h>
     42  1.1  plunky #endif
     43  1.1  plunky #include <sys/queue.h>
     44  1.1  plunky #ifndef WIN32
     45  1.1  plunky #include <sys/socket.h>
     46  1.1  plunky #include <signal.h>
     47  1.1  plunky #include <unistd.h>
     48  1.1  plunky #include <netdb.h>
     49  1.1  plunky #endif
     50  1.1  plunky #include <fcntl.h>
     51  1.1  plunky #include <stdlib.h>
     52  1.1  plunky #include <stdio.h>
     53  1.1  plunky #include <string.h>
     54  1.1  plunky #include <errno.h>
     55  1.1  plunky 
     56  1.1  plunky #include "event.h"
     57  1.1  plunky #include "evhttp.h"
     58  1.1  plunky #include "log.h"
     59  1.1  plunky #include "http-internal.h"
     60  1.1  plunky 
     61  1.1  plunky extern int pair[];
     62  1.1  plunky extern int test_ok;
     63  1.1  plunky 
     64  1.1  plunky static struct evhttp *http;
     65  1.1  plunky /* set if a test needs to call loopexit on a base */
     66  1.1  plunky static struct event_base *base;
     67  1.1  plunky 
     68  1.1  plunky void http_suite(void);
     69  1.1  plunky 
     70  1.1  plunky void http_basic_cb(struct evhttp_request *req, void *arg);
     71  1.1  plunky static void http_chunked_cb(struct evhttp_request *req, void *arg);
     72  1.1  plunky void http_post_cb(struct evhttp_request *req, void *arg);
     73  1.1  plunky void http_dispatcher_cb(struct evhttp_request *req, void *arg);
     74  1.1  plunky static void http_large_delay_cb(struct evhttp_request *req, void *arg);
     75  1.1  plunky 
     76  1.1  plunky static struct evhttp *
     77  1.1  plunky http_setup(short *pport, struct event_base *base)
     78  1.1  plunky {
     79  1.1  plunky 	int i;
     80  1.1  plunky 	struct evhttp *myhttp;
     81  1.1  plunky 	short port = -1;
     82  1.1  plunky 
     83  1.1  plunky 	/* Try a few different ports */
     84  1.1  plunky 	myhttp = evhttp_new(base);
     85  1.1  plunky 	for (i = 0; i < 50; ++i) {
     86  1.1  plunky 		if (evhttp_bind_socket(myhttp, "127.0.0.1", 8080 + i) != -1) {
     87  1.1  plunky 			port = 8080 + i;
     88  1.1  plunky 			break;
     89  1.1  plunky 		}
     90  1.1  plunky 	}
     91  1.1  plunky 
     92  1.1  plunky 	if (port == -1)
     93  1.1  plunky 		event_errx(1, "Could not start web server");
     94  1.1  plunky 
     95  1.1  plunky 	/* Register a callback for certain types of requests */
     96  1.1  plunky 	evhttp_set_cb(myhttp, "/test", http_basic_cb, NULL);
     97  1.1  plunky 	evhttp_set_cb(myhttp, "/chunked", http_chunked_cb, NULL);
     98  1.1  plunky 	evhttp_set_cb(myhttp, "/postit", http_post_cb, NULL);
     99  1.1  plunky 	evhttp_set_cb(myhttp, "/largedelay", http_large_delay_cb, NULL);
    100  1.1  plunky 	evhttp_set_cb(myhttp, "/", http_dispatcher_cb, NULL);
    101  1.1  plunky 
    102  1.1  plunky 	*pport = port;
    103  1.1  plunky 	return (myhttp);
    104  1.1  plunky }
    105  1.1  plunky 
    106  1.1  plunky #ifndef NI_MAXSERV
    107  1.1  plunky #define NI_MAXSERV 1024
    108  1.1  plunky #endif
    109  1.1  plunky 
    110  1.1  plunky static int
    111  1.1  plunky http_connect(const char *address, u_short port)
    112  1.1  plunky {
    113  1.1  plunky 	/* Stupid code for connecting */
    114  1.1  plunky #ifdef WIN32
    115  1.1  plunky 	struct hostent *he;
    116  1.1  plunky 	struct sockaddr_in sin;
    117  1.1  plunky #else
    118  1.1  plunky 	struct addrinfo ai, *aitop;
    119  1.1  plunky 	char strport[NI_MAXSERV];
    120  1.1  plunky #endif
    121  1.1  plunky 	struct sockaddr *sa;
    122  1.1  plunky 	int slen;
    123  1.1  plunky 	int fd;
    124  1.1  plunky 
    125  1.1  plunky #ifdef WIN32
    126  1.1  plunky 	if (!(he = gethostbyname(address))) {
    127  1.1  plunky 		event_warn("gethostbyname");
    128  1.1  plunky 	}
    129  1.1  plunky 	memcpy(&sin.sin_addr, he->h_addr_list[0], he->h_length);
    130  1.1  plunky 	sin.sin_family = AF_INET;
    131  1.1  plunky 	sin.sin_port = htons(port);
    132  1.1  plunky 	slen = sizeof(struct sockaddr_in);
    133  1.1  plunky 	sa = (struct sockaddr*)&sin;
    134  1.1  plunky #else
    135  1.1  plunky 	memset(&ai, 0, sizeof (ai));
    136  1.1  plunky 	ai.ai_family = AF_INET;
    137  1.1  plunky 	ai.ai_socktype = SOCK_STREAM;
    138  1.1  plunky 	snprintf(strport, sizeof (strport), "%d", port);
    139  1.1  plunky 	if (getaddrinfo(address, strport, &ai, &aitop) != 0) {
    140  1.1  plunky 		event_warn("getaddrinfo");
    141  1.1  plunky 		return (-1);
    142  1.1  plunky 	}
    143  1.1  plunky 	sa = aitop->ai_addr;
    144  1.1  plunky 	slen = aitop->ai_addrlen;
    145  1.1  plunky #endif
    146  1.1  plunky 
    147  1.1  plunky 	fd = socket(AF_INET, SOCK_STREAM, 0);
    148  1.1  plunky 	if (fd == -1)
    149  1.1  plunky 		event_err(1, "socket failed");
    150  1.1  plunky 
    151  1.1  plunky 	if (connect(fd, sa, slen) == -1)
    152  1.1  plunky 		event_err(1, "connect failed");
    153  1.1  plunky 
    154  1.1  plunky #ifndef WIN32
    155  1.1  plunky 	freeaddrinfo(aitop);
    156  1.1  plunky #endif
    157  1.1  plunky 
    158  1.1  plunky 	return (fd);
    159  1.1  plunky }
    160  1.1  plunky 
    161  1.1  plunky static void
    162  1.1  plunky http_readcb(struct bufferevent *bev, void *arg)
    163  1.1  plunky {
    164  1.1  plunky 	const char *what = "This is funny";
    165  1.1  plunky 
    166  1.1  plunky  	event_debug(("%s: %s\n", __func__, EVBUFFER_DATA(bev->input)));
    167  1.1  plunky 
    168  1.1  plunky 	if (evbuffer_find(bev->input,
    169  1.1  plunky 		(const unsigned char*) what, strlen(what)) != NULL) {
    170  1.1  plunky 		struct evhttp_request *req = evhttp_request_new(NULL, NULL);
    171  1.1  plunky 		enum message_read_status done;
    172  1.1  plunky 
    173  1.1  plunky 		req->kind = EVHTTP_RESPONSE;
    174  1.1  plunky 		done = evhttp_parse_firstline(req, bev->input);
    175  1.1  plunky 		if (done != ALL_DATA_READ)
    176  1.1  plunky 			goto out;
    177  1.1  plunky 
    178  1.1  plunky 		done = evhttp_parse_headers(req, bev->input);
    179  1.1  plunky 		if (done != ALL_DATA_READ)
    180  1.1  plunky 			goto out;
    181  1.1  plunky 
    182  1.1  plunky 		if (done == 1 &&
    183  1.1  plunky 		    evhttp_find_header(req->input_headers,
    184  1.1  plunky 			"Content-Type") != NULL)
    185  1.1  plunky 			test_ok++;
    186  1.1  plunky 
    187  1.1  plunky 	out:
    188  1.1  plunky 		evhttp_request_free(req);
    189  1.1  plunky 		bufferevent_disable(bev, EV_READ);
    190  1.1  plunky 		if (base)
    191  1.1  plunky 			event_base_loopexit(base, NULL);
    192  1.1  plunky 		else
    193  1.1  plunky 			event_loopexit(NULL);
    194  1.1  plunky 	}
    195  1.1  plunky }
    196  1.1  plunky 
    197  1.1  plunky static void
    198  1.1  plunky http_writecb(struct bufferevent *bev, void *arg)
    199  1.1  plunky {
    200  1.1  plunky 	if (EVBUFFER_LENGTH(bev->output) == 0) {
    201  1.1  plunky 		/* enable reading of the reply */
    202  1.1  plunky 		bufferevent_enable(bev, EV_READ);
    203  1.1  plunky 		test_ok++;
    204  1.1  plunky 	}
    205  1.1  plunky }
    206  1.1  plunky 
    207  1.1  plunky static void
    208  1.1  plunky http_errorcb(struct bufferevent *bev, short what, void *arg)
    209  1.1  plunky {
    210  1.1  plunky 	test_ok = -2;
    211  1.1  plunky 	event_loopexit(NULL);
    212  1.1  plunky }
    213  1.1  plunky 
    214  1.1  plunky void
    215  1.1  plunky http_basic_cb(struct evhttp_request *req, void *arg)
    216  1.1  plunky {
    217  1.1  plunky 	struct evbuffer *evb = evbuffer_new();
    218  1.1  plunky 	int empty = evhttp_find_header(req->input_headers, "Empty") != NULL;
    219  1.1  plunky 	event_debug(("%s: called\n", __func__));
    220  1.1  plunky 	evbuffer_add_printf(evb, "This is funny");
    221  1.1  plunky 
    222  1.1  plunky 	/* For multi-line headers test */
    223  1.1  plunky 	{
    224  1.1  plunky 		const char *multi =
    225  1.1  plunky 		    evhttp_find_header(req->input_headers,"X-multi");
    226  1.1  plunky 		if (multi) {
    227  1.1  plunky 			if (strcmp("END", multi + strlen(multi) - 3) == 0)
    228  1.1  plunky 				test_ok++;
    229  1.1  plunky 			if (evhttp_find_header(req->input_headers, "X-Last"))
    230  1.1  plunky 				test_ok++;
    231  1.1  plunky 		}
    232  1.1  plunky 	}
    233  1.1  plunky 
    234  1.1  plunky 	/* injecting a bad content-length */
    235  1.1  plunky 	if (evhttp_find_header(req->input_headers, "X-Negative"))
    236  1.1  plunky 		evhttp_add_header(req->output_headers,
    237  1.1  plunky 		    "Content-Length", "-100");
    238  1.1  plunky 
    239  1.1  plunky 	/* allow sending of an empty reply */
    240  1.1  plunky 	evhttp_send_reply(req, HTTP_OK, "Everything is fine",
    241  1.1  plunky 	    !empty ? evb : NULL);
    242  1.1  plunky 
    243  1.1  plunky 	evbuffer_free(evb);
    244  1.1  plunky }
    245  1.1  plunky 
    246  1.1  plunky static char const* const CHUNKS[] = {
    247  1.1  plunky 	"This is funny",
    248  1.1  plunky 	"but not hilarious.",
    249  1.1  plunky 	"bwv 1052"
    250  1.1  plunky };
    251  1.1  plunky 
    252  1.1  plunky struct chunk_req_state {
    253  1.1  plunky 	struct evhttp_request *req;
    254  1.1  plunky 	int i;
    255  1.1  plunky };
    256  1.1  plunky 
    257  1.1  plunky static void
    258  1.1  plunky http_chunked_trickle_cb(int fd, short events, void *arg)
    259  1.1  plunky {
    260  1.1  plunky 	struct evbuffer *evb = evbuffer_new();
    261  1.1  plunky 	struct chunk_req_state *state = arg;
    262  1.1  plunky 	struct timeval when = { 0, 0 };
    263  1.1  plunky 
    264  1.1  plunky 	evbuffer_add_printf(evb, "%s", CHUNKS[state->i]);
    265  1.1  plunky 	evhttp_send_reply_chunk(state->req, evb);
    266  1.1  plunky 	evbuffer_free(evb);
    267  1.1  plunky 
    268  1.1  plunky 	if (++state->i < sizeof(CHUNKS)/sizeof(CHUNKS[0])) {
    269  1.1  plunky 		event_once(-1, EV_TIMEOUT,
    270  1.1  plunky 		    http_chunked_trickle_cb, state, &when);
    271  1.1  plunky 	} else {
    272  1.1  plunky 		evhttp_send_reply_end(state->req);
    273  1.1  plunky 		free(state);
    274  1.1  plunky 	}
    275  1.1  plunky }
    276  1.1  plunky 
    277  1.1  plunky static void
    278  1.1  plunky http_chunked_cb(struct evhttp_request *req, void *arg)
    279  1.1  plunky {
    280  1.1  plunky 	struct timeval when = { 0, 0 };
    281  1.1  plunky 	struct chunk_req_state *state = malloc(sizeof(struct chunk_req_state));
    282  1.1  plunky 	event_debug(("%s: called\n", __func__));
    283  1.1  plunky 
    284  1.1  plunky 	memset(state, 0, sizeof(struct chunk_req_state));
    285  1.1  plunky 	state->req = req;
    286  1.1  plunky 
    287  1.1  plunky 	/* generate a chunked reply */
    288  1.1  plunky 	evhttp_send_reply_start(req, HTTP_OK, "Everything is fine");
    289  1.1  plunky 
    290  1.1  plunky 	/* but trickle it across several iterations to ensure we're not
    291  1.1  plunky 	 * assuming it comes all at once */
    292  1.1  plunky 	event_once(-1, EV_TIMEOUT, http_chunked_trickle_cb, state, &when);
    293  1.1  plunky }
    294  1.1  plunky 
    295  1.1  plunky static void
    296  1.1  plunky http_complete_write(int fd, short what, void *arg)
    297  1.1  plunky {
    298  1.1  plunky 	struct bufferevent *bev = arg;
    299  1.1  plunky 	const char *http_request = "host\r\n"
    300  1.1  plunky 	    "Connection: close\r\n"
    301  1.1  plunky 	    "\r\n";
    302  1.1  plunky 	bufferevent_write(bev, http_request, strlen(http_request));
    303  1.1  plunky }
    304  1.1  plunky 
    305  1.1  plunky static void
    306  1.1  plunky http_basic_test(void)
    307  1.1  plunky {
    308  1.1  plunky 	struct timeval tv;
    309  1.1  plunky 	struct bufferevent *bev;
    310  1.1  plunky 	int fd;
    311  1.1  plunky 	const char *http_request;
    312  1.1  plunky 	short port = -1;
    313  1.1  plunky 
    314  1.1  plunky 	test_ok = 0;
    315  1.1  plunky 	fprintf(stdout, "Testing Basic HTTP Server: ");
    316  1.1  plunky 
    317  1.1  plunky 	http = http_setup(&port, NULL);
    318  1.1  plunky 
    319  1.1  plunky 	/* bind to a second socket */
    320  1.1  plunky 	if (evhttp_bind_socket(http, "127.0.0.1", port + 1) == -1) {
    321  1.1  plunky 		fprintf(stdout, "FAILED (bind)\n");
    322  1.1  plunky 		exit(1);
    323  1.1  plunky 	}
    324  1.1  plunky 
    325  1.1  plunky 	fd = http_connect("127.0.0.1", port);
    326  1.1  plunky 
    327  1.1  plunky 	/* Stupid thing to send a request */
    328  1.1  plunky 	bev = bufferevent_new(fd, http_readcb, http_writecb,
    329  1.1  plunky 	    http_errorcb, NULL);
    330  1.1  plunky 
    331  1.1  plunky 	/* first half of the http request */
    332  1.1  plunky 	http_request =
    333  1.1  plunky 	    "GET /test HTTP/1.1\r\n"
    334  1.1  plunky 	    "Host: some";
    335  1.1  plunky 
    336  1.1  plunky 	bufferevent_write(bev, http_request, strlen(http_request));
    337  1.1  plunky 	timerclear(&tv);
    338  1.1  plunky 	tv.tv_usec = 10000;
    339  1.1  plunky 	event_once(-1, EV_TIMEOUT, http_complete_write, bev, &tv);
    340  1.1  plunky 
    341  1.1  plunky 	event_dispatch();
    342  1.1  plunky 
    343  1.1  plunky 	if (test_ok != 3) {
    344  1.1  plunky 		fprintf(stdout, "FAILED\n");
    345  1.1  plunky 		exit(1);
    346  1.1  plunky 	}
    347  1.1  plunky 
    348  1.1  plunky 	/* connect to the second port */
    349  1.1  plunky 	bufferevent_free(bev);
    350  1.1  plunky 	EVUTIL_CLOSESOCKET(fd);
    351  1.1  plunky 
    352  1.1  plunky 	fd = http_connect("127.0.0.1", port + 1);
    353  1.1  plunky 
    354  1.1  plunky 	/* Stupid thing to send a request */
    355  1.1  plunky 	bev = bufferevent_new(fd, http_readcb, http_writecb,
    356  1.1  plunky 	    http_errorcb, NULL);
    357  1.1  plunky 
    358  1.1  plunky 	http_request =
    359  1.1  plunky 	    "GET /test HTTP/1.1\r\n"
    360  1.1  plunky 	    "Host: somehost\r\n"
    361  1.1  plunky 	    "Connection: close\r\n"
    362  1.1  plunky 	    "\r\n";
    363  1.1  plunky 
    364  1.1  plunky 	bufferevent_write(bev, http_request, strlen(http_request));
    365  1.1  plunky 
    366  1.1  plunky 	event_dispatch();
    367  1.1  plunky 
    368  1.1  plunky 	bufferevent_free(bev);
    369  1.1  plunky 	EVUTIL_CLOSESOCKET(fd);
    370  1.1  plunky 
    371  1.1  plunky 	evhttp_free(http);
    372  1.1  plunky 
    373  1.1  plunky 	if (test_ok != 5) {
    374  1.1  plunky 		fprintf(stdout, "FAILED\n");
    375  1.1  plunky 		exit(1);
    376  1.1  plunky 	}
    377  1.1  plunky 
    378  1.1  plunky 	fprintf(stdout, "OK\n");
    379  1.1  plunky }
    380  1.1  plunky 
    381  1.1  plunky static struct evhttp_connection *delayed_client;
    382  1.1  plunky 
    383  1.1  plunky static void
    384  1.1  plunky http_delay_reply(int fd, short what, void *arg)
    385  1.1  plunky {
    386  1.1  plunky 	struct evhttp_request *req = arg;
    387  1.1  plunky 
    388  1.1  plunky 	evhttp_send_reply(req, HTTP_OK, "Everything is fine", NULL);
    389  1.1  plunky 
    390  1.1  plunky 	++test_ok;
    391  1.1  plunky }
    392  1.1  plunky 
    393  1.1  plunky static void
    394  1.1  plunky http_large_delay_cb(struct evhttp_request *req, void *arg)
    395  1.1  plunky {
    396  1.1  plunky 	struct timeval tv;
    397  1.1  plunky 	timerclear(&tv);
    398  1.1  plunky 	tv.tv_sec = 3;
    399  1.1  plunky 
    400  1.1  plunky 	event_once(-1, EV_TIMEOUT, http_delay_reply, req, &tv);
    401  1.1  plunky 
    402  1.1  plunky 	/* here we close the client connection which will cause an EOF */
    403  1.1  plunky 	evhttp_connection_fail(delayed_client, EVCON_HTTP_EOF);
    404  1.1  plunky }
    405  1.1  plunky 
    406  1.1  plunky void http_request_done(struct evhttp_request *, void *);
    407  1.1  plunky void http_request_empty_done(struct evhttp_request *, void *);
    408  1.1  plunky 
    409  1.1  plunky static void
    410  1.1  plunky http_connection_test(int persistent)
    411  1.1  plunky {
    412  1.1  plunky 	short port = -1;
    413  1.1  plunky 	struct evhttp_connection *evcon = NULL;
    414  1.1  plunky 	struct evhttp_request *req = NULL;
    415  1.1  plunky 
    416  1.1  plunky 	test_ok = 0;
    417  1.1  plunky 	fprintf(stdout, "Testing Request Connection Pipeline %s: ",
    418  1.1  plunky 	    persistent ? "(persistent)" : "");
    419  1.1  plunky 
    420  1.1  plunky 	http = http_setup(&port, NULL);
    421  1.1  plunky 
    422  1.1  plunky 	evcon = evhttp_connection_new("127.0.0.1", port);
    423  1.1  plunky 	if (evcon == NULL) {
    424  1.1  plunky 		fprintf(stdout, "FAILED\n");
    425  1.1  plunky 		exit(1);
    426  1.1  plunky 	}
    427  1.1  plunky 
    428  1.1  plunky 	/*
    429  1.1  plunky 	 * At this point, we want to schedule a request to the HTTP
    430  1.1  plunky 	 * server using our make request method.
    431  1.1  plunky 	 */
    432  1.1  plunky 
    433  1.1  plunky 	req = evhttp_request_new(http_request_done, NULL);
    434  1.1  plunky 
    435  1.1  plunky 	/* Add the information that we care about */
    436  1.1  plunky 	evhttp_add_header(req->output_headers, "Host", "somehost");
    437  1.1  plunky 
    438  1.1  plunky 	/* We give ownership of the request to the connection */
    439  1.1  plunky 	if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test") == -1) {
    440  1.1  plunky 		fprintf(stdout, "FAILED\n");
    441  1.1  plunky 		exit(1);
    442  1.1  plunky 	}
    443  1.1  plunky 
    444  1.1  plunky 	event_dispatch();
    445  1.1  plunky 
    446  1.1  plunky 	if (test_ok != 1) {
    447  1.1  plunky 		fprintf(stdout, "FAILED\n");
    448  1.1  plunky 		exit(1);
    449  1.1  plunky 	}
    450  1.1  plunky 
    451  1.1  plunky 	/* try to make another request over the same connection */
    452  1.1  plunky 	test_ok = 0;
    453  1.1  plunky 
    454  1.1  plunky 	req = evhttp_request_new(http_request_done, NULL);
    455  1.1  plunky 
    456  1.1  plunky 	/* Add the information that we care about */
    457  1.1  plunky 	evhttp_add_header(req->output_headers, "Host", "somehost");
    458  1.1  plunky 
    459  1.1  plunky 	/*
    460  1.1  plunky 	 * if our connections are not supposed to be persistent; request
    461  1.1  plunky 	 * a close from the server.
    462  1.1  plunky 	 */
    463  1.1  plunky 	if (!persistent)
    464  1.1  plunky 		evhttp_add_header(req->output_headers, "Connection", "close");
    465  1.1  plunky 
    466  1.1  plunky 	/* We give ownership of the request to the connection */
    467  1.1  plunky 	if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test") == -1) {
    468  1.1  plunky 		fprintf(stdout, "FAILED\n");
    469  1.1  plunky 		exit(1);
    470  1.1  plunky 	}
    471  1.1  plunky 
    472  1.1  plunky 	event_dispatch();
    473  1.1  plunky 
    474  1.1  plunky 	/* make another request: request empty reply */
    475  1.1  plunky 	test_ok = 0;
    476  1.1  plunky 
    477  1.1  plunky 	req = evhttp_request_new(http_request_empty_done, NULL);
    478  1.1  plunky 
    479  1.1  plunky 	/* Add the information that we care about */
    480  1.1  plunky 	evhttp_add_header(req->output_headers, "Empty", "itis");
    481  1.1  plunky 
    482  1.1  plunky 	/* We give ownership of the request to the connection */
    483  1.1  plunky 	if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test") == -1) {
    484  1.1  plunky 		fprintf(stdout, "FAILED\n");
    485  1.1  plunky 		exit(1);
    486  1.1  plunky 	}
    487  1.1  plunky 
    488  1.1  plunky 	event_dispatch();
    489  1.1  plunky 
    490  1.1  plunky 	if (test_ok != 1) {
    491  1.1  plunky 		fprintf(stdout, "FAILED\n");
    492  1.1  plunky 		exit(1);
    493  1.1  plunky 	}
    494  1.1  plunky 
    495  1.1  plunky 	evhttp_connection_free(evcon);
    496  1.1  plunky 	evhttp_free(http);
    497  1.1  plunky 
    498  1.1  plunky 	fprintf(stdout, "OK\n");
    499  1.1  plunky }
    500  1.1  plunky 
    501  1.1  plunky void
    502  1.1  plunky http_request_done(struct evhttp_request *req, void *arg)
    503  1.1  plunky {
    504  1.1  plunky 	const char *what = "This is funny";
    505  1.1  plunky 
    506  1.1  plunky 	if (req->response_code != HTTP_OK) {
    507  1.1  plunky 		fprintf(stderr, "FAILED\n");
    508  1.1  plunky 		exit(1);
    509  1.1  plunky 	}
    510  1.1  plunky 
    511  1.1  plunky 	if (evhttp_find_header(req->input_headers, "Content-Type") == NULL) {
    512  1.1  plunky 		fprintf(stderr, "FAILED\n");
    513  1.1  plunky 		exit(1);
    514  1.1  plunky 	}
    515  1.1  plunky 
    516  1.1  plunky 	if (EVBUFFER_LENGTH(req->input_buffer) != strlen(what)) {
    517  1.1  plunky 		fprintf(stderr, "FAILED\n");
    518  1.1  plunky 		exit(1);
    519  1.1  plunky 	}
    520  1.1  plunky 
    521  1.1  plunky 	if (memcmp(EVBUFFER_DATA(req->input_buffer), what, strlen(what)) != 0) {
    522  1.1  plunky 		fprintf(stderr, "FAILED\n");
    523  1.1  plunky 		exit(1);
    524  1.1  plunky 	}
    525  1.1  plunky 
    526  1.1  plunky 	test_ok = 1;
    527  1.1  plunky 	event_loopexit(NULL);
    528  1.1  plunky }
    529  1.1  plunky 
    530  1.1  plunky /* test date header and content length */
    531  1.1  plunky 
    532  1.1  plunky void
    533  1.1  plunky http_request_empty_done(struct evhttp_request *req, void *arg)
    534  1.1  plunky {
    535  1.1  plunky 	if (req->response_code != HTTP_OK) {
    536  1.1  plunky 		fprintf(stderr, "FAILED\n");
    537  1.1  plunky 		exit(1);
    538  1.1  plunky 	}
    539  1.1  plunky 
    540  1.1  plunky 	if (evhttp_find_header(req->input_headers, "Date") == NULL) {
    541  1.1  plunky 		fprintf(stderr, "FAILED\n");
    542  1.1  plunky 		exit(1);
    543  1.1  plunky 	}
    544  1.1  plunky 
    545  1.1  plunky 
    546  1.1  plunky 	if (evhttp_find_header(req->input_headers, "Content-Length") == NULL) {
    547  1.1  plunky 		fprintf(stderr, "FAILED\n");
    548  1.1  plunky 		exit(1);
    549  1.1  plunky 	}
    550  1.1  plunky 
    551  1.1  plunky 	if (strcmp(evhttp_find_header(req->input_headers, "Content-Length"),
    552  1.1  plunky 		"0")) {
    553  1.1  plunky 		fprintf(stderr, "FAILED\n");
    554  1.1  plunky 		exit(1);
    555  1.1  plunky 	}
    556  1.1  plunky 
    557  1.1  plunky 	if (EVBUFFER_LENGTH(req->input_buffer) != 0) {
    558  1.1  plunky 		fprintf(stderr, "FAILED\n");
    559  1.1  plunky 		exit(1);
    560  1.1  plunky 	}
    561  1.1  plunky 
    562  1.1  plunky 	test_ok = 1;
    563  1.1  plunky 	event_loopexit(NULL);
    564  1.1  plunky }
    565  1.1  plunky 
    566  1.1  plunky /*
    567  1.1  plunky  * HTTP DISPATCHER test
    568  1.1  plunky  */
    569  1.1  plunky 
    570  1.1  plunky void
    571  1.1  plunky http_dispatcher_cb(struct evhttp_request *req, void *arg)
    572  1.1  plunky {
    573  1.1  plunky 
    574  1.1  plunky 	struct evbuffer *evb = evbuffer_new();
    575  1.1  plunky 	event_debug(("%s: called\n", __func__));
    576  1.1  plunky 	evbuffer_add_printf(evb, "DISPATCHER_TEST");
    577  1.1  plunky 
    578  1.1  plunky 	evhttp_send_reply(req, HTTP_OK, "Everything is fine", evb);
    579  1.1  plunky 
    580  1.1  plunky 	evbuffer_free(evb);
    581  1.1  plunky }
    582  1.1  plunky 
    583  1.1  plunky static void
    584  1.1  plunky http_dispatcher_test_done(struct evhttp_request *req, void *arg)
    585  1.1  plunky {
    586  1.1  plunky 	const char *what = "DISPATCHER_TEST";
    587  1.1  plunky 
    588  1.1  plunky 	if (req->response_code != HTTP_OK) {
    589  1.1  plunky 		fprintf(stderr, "FAILED\n");
    590  1.1  plunky 		exit(1);
    591  1.1  plunky 	}
    592  1.1  plunky 
    593  1.1  plunky 	if (evhttp_find_header(req->input_headers, "Content-Type") == NULL) {
    594  1.1  plunky 		fprintf(stderr, "FAILED (content type)\n");
    595  1.1  plunky 		exit(1);
    596  1.1  plunky 	}
    597  1.1  plunky 
    598  1.1  plunky 	if (EVBUFFER_LENGTH(req->input_buffer) != strlen(what)) {
    599  1.1  plunky 		fprintf(stderr, "FAILED (length %zu vs %zu)\n",
    600  1.1  plunky 		    EVBUFFER_LENGTH(req->input_buffer), strlen(what));
    601  1.1  plunky 		exit(1);
    602  1.1  plunky 	}
    603  1.1  plunky 
    604  1.1  plunky 	if (memcmp(EVBUFFER_DATA(req->input_buffer), what, strlen(what)) != 0) {
    605  1.1  plunky 		fprintf(stderr, "FAILED (data)\n");
    606  1.1  plunky 		exit(1);
    607  1.1  plunky 	}
    608  1.1  plunky 
    609  1.1  plunky 	test_ok = 1;
    610  1.1  plunky 	event_loopexit(NULL);
    611  1.1  plunky }
    612  1.1  plunky 
    613  1.1  plunky static void
    614  1.1  plunky http_dispatcher_test(void)
    615  1.1  plunky {
    616  1.1  plunky 	short port = -1;
    617  1.1  plunky 	struct evhttp_connection *evcon = NULL;
    618  1.1  plunky 	struct evhttp_request *req = NULL;
    619  1.1  plunky 
    620  1.1  plunky 	test_ok = 0;
    621  1.1  plunky 	fprintf(stdout, "Testing HTTP Dispatcher: ");
    622  1.1  plunky 
    623  1.1  plunky 	http = http_setup(&port, NULL);
    624  1.1  plunky 
    625  1.1  plunky 	evcon = evhttp_connection_new("127.0.0.1", port);
    626  1.1  plunky 	if (evcon == NULL) {
    627  1.1  plunky 		fprintf(stdout, "FAILED\n");
    628  1.1  plunky 		exit(1);
    629  1.1  plunky 	}
    630  1.1  plunky 
    631  1.1  plunky 	/* also bind to local host */
    632  1.1  plunky 	evhttp_connection_set_local_address(evcon, "127.0.0.1");
    633  1.1  plunky 
    634  1.1  plunky 	/*
    635  1.1  plunky 	 * At this point, we want to schedule an HTTP GET request
    636  1.1  plunky 	 * server using our make request method.
    637  1.1  plunky 	 */
    638  1.1  plunky 
    639  1.1  plunky 	req = evhttp_request_new(http_dispatcher_test_done, NULL);
    640  1.1  plunky 	if (req == NULL) {
    641  1.1  plunky 		fprintf(stdout, "FAILED\n");
    642  1.1  plunky 		exit(1);
    643  1.1  plunky 	}
    644  1.1  plunky 
    645  1.1  plunky 	/* Add the information that we care about */
    646  1.1  plunky 	evhttp_add_header(req->output_headers, "Host", "somehost");
    647  1.1  plunky 
    648  1.1  plunky 	if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/?arg=val") == -1) {
    649  1.1  plunky 		fprintf(stdout, "FAILED\n");
    650  1.1  plunky 		exit(1);
    651  1.1  plunky 	}
    652  1.1  plunky 
    653  1.1  plunky 	event_dispatch();
    654  1.1  plunky 
    655  1.1  plunky 	evhttp_connection_free(evcon);
    656  1.1  plunky 	evhttp_free(http);
    657  1.1  plunky 
    658  1.1  plunky 	if (test_ok != 1) {
    659  1.1  plunky 		fprintf(stdout, "FAILED: %d\n", test_ok);
    660  1.1  plunky 		exit(1);
    661  1.1  plunky 	}
    662  1.1  plunky 
    663  1.1  plunky 	fprintf(stdout, "OK\n");
    664  1.1  plunky }
    665  1.1  plunky 
    666  1.1  plunky /*
    667  1.1  plunky  * HTTP POST test.
    668  1.1  plunky  */
    669  1.1  plunky 
    670  1.1  plunky void http_postrequest_done(struct evhttp_request *, void *);
    671  1.1  plunky 
    672  1.1  plunky #define POST_DATA "Okay.  Not really printf"
    673  1.1  plunky 
    674  1.1  plunky static void
    675  1.1  plunky http_post_test(void)
    676  1.1  plunky {
    677  1.1  plunky 	short port = -1;
    678  1.1  plunky 	struct evhttp_connection *evcon = NULL;
    679  1.1  plunky 	struct evhttp_request *req = NULL;
    680  1.1  plunky 
    681  1.1  plunky 	test_ok = 0;
    682  1.1  plunky 	fprintf(stdout, "Testing HTTP POST Request: ");
    683  1.1  plunky 
    684  1.1  plunky 	http = http_setup(&port, NULL);
    685  1.1  plunky 
    686  1.1  plunky 	evcon = evhttp_connection_new("127.0.0.1", port);
    687  1.1  plunky 	if (evcon == NULL) {
    688  1.1  plunky 		fprintf(stdout, "FAILED\n");
    689  1.1  plunky 		exit(1);
    690  1.1  plunky 	}
    691  1.1  plunky 
    692  1.1  plunky 	/*
    693  1.1  plunky 	 * At this point, we want to schedule an HTTP POST request
    694  1.1  plunky 	 * server using our make request method.
    695  1.1  plunky 	 */
    696  1.1  plunky 
    697  1.1  plunky 	req = evhttp_request_new(http_postrequest_done, NULL);
    698  1.1  plunky 	if (req == NULL) {
    699  1.1  plunky 		fprintf(stdout, "FAILED\n");
    700  1.1  plunky 		exit(1);
    701  1.1  plunky 	}
    702  1.1  plunky 
    703  1.1  plunky 	/* Add the information that we care about */
    704  1.1  plunky 	evhttp_add_header(req->output_headers, "Host", "somehost");
    705  1.1  plunky 	evbuffer_add_printf(req->output_buffer, POST_DATA);
    706  1.1  plunky 
    707  1.1  plunky 	if (evhttp_make_request(evcon, req, EVHTTP_REQ_POST, "/postit") == -1) {
    708  1.1  plunky 		fprintf(stdout, "FAILED\n");
    709  1.1  plunky 		exit(1);
    710  1.1  plunky 	}
    711  1.1  plunky 
    712  1.1  plunky 	event_dispatch();
    713  1.1  plunky 
    714  1.1  plunky 	evhttp_connection_free(evcon);
    715  1.1  plunky 	evhttp_free(http);
    716  1.1  plunky 
    717  1.1  plunky 	if (test_ok != 1) {
    718  1.1  plunky 		fprintf(stdout, "FAILED: %d\n", test_ok);
    719  1.1  plunky 		exit(1);
    720  1.1  plunky 	}
    721  1.1  plunky 
    722  1.1  plunky 	fprintf(stdout, "OK\n");
    723  1.1  plunky }
    724  1.1  plunky 
    725  1.1  plunky void
    726  1.1  plunky http_post_cb(struct evhttp_request *req, void *arg)
    727  1.1  plunky {
    728  1.1  plunky 	struct evbuffer *evb;
    729  1.1  plunky 	event_debug(("%s: called\n", __func__));
    730  1.1  plunky 
    731  1.1  plunky 	/* Yes, we are expecting a post request */
    732  1.1  plunky 	if (req->type != EVHTTP_REQ_POST) {
    733  1.1  plunky 		fprintf(stdout, "FAILED (post type)\n");
    734  1.1  plunky 		exit(1);
    735  1.1  plunky 	}
    736  1.1  plunky 
    737  1.1  plunky 	if (EVBUFFER_LENGTH(req->input_buffer) != strlen(POST_DATA)) {
    738  1.1  plunky 		fprintf(stdout, "FAILED (length: %zu vs %zu)\n",
    739  1.1  plunky 		    EVBUFFER_LENGTH(req->input_buffer), strlen(POST_DATA));
    740  1.1  plunky 		exit(1);
    741  1.1  plunky 	}
    742  1.1  plunky 
    743  1.1  plunky 	if (memcmp(EVBUFFER_DATA(req->input_buffer), POST_DATA,
    744  1.1  plunky 		strlen(POST_DATA))) {
    745  1.1  plunky 		fprintf(stdout, "FAILED (data)\n");
    746  1.1  plunky 		fprintf(stdout, "Got :%s\n", EVBUFFER_DATA(req->input_buffer));
    747  1.1  plunky 		fprintf(stdout, "Want:%s\n", POST_DATA);
    748  1.1  plunky 		exit(1);
    749  1.1  plunky 	}
    750  1.1  plunky 
    751  1.1  plunky 	evb = evbuffer_new();
    752  1.1  plunky 	evbuffer_add_printf(evb, "This is funny");
    753  1.1  plunky 
    754  1.1  plunky 	evhttp_send_reply(req, HTTP_OK, "Everything is fine", evb);
    755  1.1  plunky 
    756  1.1  plunky 	evbuffer_free(evb);
    757  1.1  plunky }
    758  1.1  plunky 
    759  1.1  plunky void
    760  1.1  plunky http_postrequest_done(struct evhttp_request *req, void *arg)
    761  1.1  plunky {
    762  1.1  plunky 	const char *what = "This is funny";
    763  1.1  plunky 
    764  1.1  plunky 	if (req == NULL) {
    765  1.1  plunky 		fprintf(stderr, "FAILED (timeout)\n");
    766  1.1  plunky 		exit(1);
    767  1.1  plunky 	}
    768  1.1  plunky 
    769  1.1  plunky 	if (req->response_code != HTTP_OK) {
    770  1.1  plunky 
    771  1.1  plunky 		fprintf(stderr, "FAILED (response code)\n");
    772  1.1  plunky 		exit(1);
    773  1.1  plunky 	}
    774  1.1  plunky 
    775  1.1  plunky 	if (evhttp_find_header(req->input_headers, "Content-Type") == NULL) {
    776  1.1  plunky 		fprintf(stderr, "FAILED (content type)\n");
    777  1.1  plunky 		exit(1);
    778  1.1  plunky 	}
    779  1.1  plunky 
    780  1.1  plunky 	if (EVBUFFER_LENGTH(req->input_buffer) != strlen(what)) {
    781  1.1  plunky 		fprintf(stderr, "FAILED (length %zu vs %zu)\n",
    782  1.1  plunky 		    EVBUFFER_LENGTH(req->input_buffer), strlen(what));
    783  1.1  plunky 		exit(1);
    784  1.1  plunky 	}
    785  1.1  plunky 
    786  1.1  plunky 	if (memcmp(EVBUFFER_DATA(req->input_buffer), what, strlen(what)) != 0) {
    787  1.1  plunky 		fprintf(stderr, "FAILED (data)\n");
    788  1.1  plunky 		exit(1);
    789  1.1  plunky 	}
    790  1.1  plunky 
    791  1.1  plunky 	test_ok = 1;
    792  1.1  plunky 	event_loopexit(NULL);
    793  1.1  plunky }
    794  1.1  plunky 
    795  1.1  plunky static void
    796  1.1  plunky http_failure_readcb(struct bufferevent *bev, void *arg)
    797  1.1  plunky {
    798  1.1  plunky 	const char *what = "400 Bad Request";
    799  1.1  plunky 	if (evbuffer_find(bev->input, (const unsigned char*) what, strlen(what)) != NULL) {
    800  1.1  plunky 		test_ok = 2;
    801  1.1  plunky 		bufferevent_disable(bev, EV_READ);
    802  1.1  plunky 		event_loopexit(NULL);
    803  1.1  plunky 	}
    804  1.1  plunky }
    805  1.1  plunky 
    806  1.1  plunky /*
    807  1.1  plunky  * Testing that the HTTP server can deal with a malformed request.
    808  1.1  plunky  */
    809  1.1  plunky static void
    810  1.1  plunky http_failure_test(void)
    811  1.1  plunky {
    812  1.1  plunky 	struct bufferevent *bev;
    813  1.1  plunky 	int fd;
    814  1.1  plunky 	const char *http_request;
    815  1.1  plunky 	short port = -1;
    816  1.1  plunky 
    817  1.1  plunky 	test_ok = 0;
    818  1.1  plunky 	fprintf(stdout, "Testing Bad HTTP Request: ");
    819  1.1  plunky 
    820  1.1  plunky 	http = http_setup(&port, NULL);
    821  1.1  plunky 
    822  1.1  plunky 	fd = http_connect("127.0.0.1", port);
    823  1.1  plunky 
    824  1.1  plunky 	/* Stupid thing to send a request */
    825  1.1  plunky 	bev = bufferevent_new(fd, http_failure_readcb, http_writecb,
    826  1.1  plunky 	    http_errorcb, NULL);
    827  1.1  plunky 
    828  1.1  plunky 	http_request = "illegal request\r\n";
    829  1.1  plunky 
    830  1.1  plunky 	bufferevent_write(bev, http_request, strlen(http_request));
    831  1.1  plunky 
    832  1.1  plunky 	event_dispatch();
    833  1.1  plunky 
    834  1.1  plunky 	bufferevent_free(bev);
    835  1.1  plunky 	EVUTIL_CLOSESOCKET(fd);
    836  1.1  plunky 
    837  1.1  plunky 	evhttp_free(http);
    838  1.1  plunky 
    839  1.1  plunky 	if (test_ok != 2) {
    840  1.1  plunky 		fprintf(stdout, "FAILED\n");
    841  1.1  plunky 		exit(1);
    842  1.1  plunky 	}
    843  1.1  plunky 
    844  1.1  plunky 	fprintf(stdout, "OK\n");
    845  1.1  plunky }
    846  1.1  plunky 
    847  1.1  plunky static void
    848  1.1  plunky close_detect_done(struct evhttp_request *req, void *arg)
    849  1.1  plunky {
    850  1.1  plunky 	struct timeval tv;
    851  1.1  plunky 	if (req == NULL || req->response_code != HTTP_OK) {
    852  1.1  plunky 
    853  1.1  plunky 		fprintf(stderr, "FAILED\n");
    854  1.1  plunky 		exit(1);
    855  1.1  plunky 	}
    856  1.1  plunky 
    857  1.1  plunky 	test_ok = 1;
    858  1.1  plunky 
    859  1.1  plunky 	timerclear(&tv);
    860  1.1  plunky 	tv.tv_sec = 3;   /* longer than the http time out */
    861  1.1  plunky 
    862  1.1  plunky 	event_loopexit(&tv);
    863  1.1  plunky }
    864  1.1  plunky 
    865  1.1  plunky static void
    866  1.1  plunky close_detect_launch(int fd, short what, void *arg)
    867  1.1  plunky {
    868  1.1  plunky 	struct evhttp_connection *evcon = arg;
    869  1.1  plunky 	struct evhttp_request *req;
    870  1.1  plunky 
    871  1.1  plunky 	req = evhttp_request_new(close_detect_done, NULL);
    872  1.1  plunky 
    873  1.1  plunky 	/* Add the information that we care about */
    874  1.1  plunky 	evhttp_add_header(req->output_headers, "Host", "somehost");
    875  1.1  plunky 
    876  1.1  plunky 	/* We give ownership of the request to the connection */
    877  1.1  plunky 	if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test") == -1) {
    878  1.1  plunky 		fprintf(stdout, "FAILED\n");
    879  1.1  plunky 		exit(1);
    880  1.1  plunky 	}
    881  1.1  plunky }
    882  1.1  plunky 
    883  1.1  plunky static void
    884  1.1  plunky close_detect_cb(struct evhttp_request *req, void *arg)
    885  1.1  plunky {
    886  1.1  plunky 	struct evhttp_connection *evcon = arg;
    887  1.1  plunky 	struct timeval tv;
    888  1.1  plunky 
    889  1.1  plunky 	if (req != NULL && req->response_code != HTTP_OK) {
    890  1.1  plunky 
    891  1.1  plunky 		fprintf(stderr, "FAILED\n");
    892  1.1  plunky 		exit(1);
    893  1.1  plunky 	}
    894  1.1  plunky 
    895  1.1  plunky 	timerclear(&tv);
    896  1.1  plunky 	tv.tv_sec = 3;   /* longer than the http time out */
    897  1.1  plunky 
    898  1.1  plunky 	/* launch a new request on the persistent connection in 6 seconds */
    899  1.1  plunky 	event_once(-1, EV_TIMEOUT, close_detect_launch, evcon, &tv);
    900  1.1  plunky }
    901  1.1  plunky 
    902  1.1  plunky 
    903  1.1  plunky static void
    904  1.1  plunky http_close_detection(int with_delay)
    905  1.1  plunky {
    906  1.1  plunky 	short port = -1;
    907  1.1  plunky 	struct evhttp_connection *evcon = NULL;
    908  1.1  plunky 	struct evhttp_request *req = NULL;
    909  1.1  plunky 
    910  1.1  plunky 	test_ok = 0;
    911  1.1  plunky 	fprintf(stdout, "Testing Connection Close Detection%s: ",
    912  1.1  plunky 		with_delay ? " (with delay)" : "");
    913  1.1  plunky 
    914  1.1  plunky 	http = http_setup(&port, NULL);
    915  1.1  plunky 
    916  1.1  plunky 	/* 2 second timeout */
    917  1.1  plunky 	evhttp_set_timeout(http, 2);
    918  1.1  plunky 
    919  1.1  plunky 	evcon = evhttp_connection_new("127.0.0.1", port);
    920  1.1  plunky 	if (evcon == NULL) {
    921  1.1  plunky 		fprintf(stdout, "FAILED\n");
    922  1.1  plunky 		exit(1);
    923  1.1  plunky 	}
    924  1.1  plunky 
    925  1.1  plunky 	delayed_client = evcon;
    926  1.1  plunky 
    927  1.1  plunky 	/*
    928  1.1  plunky 	 * At this point, we want to schedule a request to the HTTP
    929  1.1  plunky 	 * server using our make request method.
    930  1.1  plunky 	 */
    931  1.1  plunky 
    932  1.1  plunky 	req = evhttp_request_new(close_detect_cb, evcon);
    933  1.1  plunky 
    934  1.1  plunky 	/* Add the information that we care about */
    935  1.1  plunky 	evhttp_add_header(req->output_headers, "Host", "somehost");
    936  1.1  plunky 
    937  1.1  plunky 	/* We give ownership of the request to the connection */
    938  1.1  plunky 	if (evhttp_make_request(evcon,
    939  1.1  plunky 	    req, EVHTTP_REQ_GET, with_delay ? "/largedelay" : "/test") == -1) {
    940  1.1  plunky 		fprintf(stdout, "FAILED\n");
    941  1.1  plunky 		exit(1);
    942  1.1  plunky 	}
    943  1.1  plunky 
    944  1.1  plunky 	event_dispatch();
    945  1.1  plunky 
    946  1.1  plunky 	if (test_ok != 1) {
    947  1.1  plunky 		fprintf(stdout, "FAILED\n");
    948  1.1  plunky 		exit(1);
    949  1.1  plunky 	}
    950  1.1  plunky 
    951  1.1  plunky 	/* at this point, the http server should have no connection */
    952  1.1  plunky 	if (TAILQ_FIRST(&http->connections) != NULL) {
    953  1.1  plunky 		fprintf(stdout, "FAILED (left connections)\n");
    954  1.1  plunky 		exit(1);
    955  1.1  plunky 	}
    956  1.1  plunky 
    957  1.1  plunky 	evhttp_connection_free(evcon);
    958  1.1  plunky 	evhttp_free(http);
    959  1.1  plunky 
    960  1.1  plunky 	fprintf(stdout, "OK\n");
    961  1.1  plunky }
    962  1.1  plunky 
    963  1.1  plunky static void
    964  1.1  plunky http_highport_test(void)
    965  1.1  plunky {
    966  1.1  plunky 	int i = -1;
    967  1.1  plunky 	struct evhttp *myhttp = NULL;
    968  1.1  plunky 
    969  1.1  plunky 	fprintf(stdout, "Testing HTTP Server with high port: ");
    970  1.1  plunky 
    971  1.1  plunky 	/* Try a few different ports */
    972  1.1  plunky 	for (i = 0; i < 50; ++i) {
    973  1.1  plunky 		myhttp = evhttp_start("127.0.0.1", 65535 - i);
    974  1.1  plunky 		if (myhttp != NULL) {
    975  1.1  plunky 			fprintf(stdout, "OK\n");
    976  1.1  plunky 			evhttp_free(myhttp);
    977  1.1  plunky 			return;
    978  1.1  plunky 		}
    979  1.1  plunky 	}
    980  1.1  plunky 
    981  1.1  plunky 	fprintf(stdout, "FAILED\n");
    982  1.1  plunky 	exit(1);
    983  1.1  plunky }
    984  1.1  plunky 
    985  1.1  plunky static void
    986  1.1  plunky http_bad_header_test(void)
    987  1.1  plunky {
    988  1.1  plunky 	struct evkeyvalq headers;
    989  1.1  plunky 
    990  1.1  plunky 	fprintf(stdout, "Testing HTTP Header filtering: ");
    991  1.1  plunky 
    992  1.1  plunky 	TAILQ_INIT(&headers);
    993  1.1  plunky 
    994  1.1  plunky 	if (evhttp_add_header(&headers, "One", "Two") != 0)
    995  1.1  plunky 		goto fail;
    996  1.1  plunky 
    997  1.1  plunky 	if (evhttp_add_header(&headers, "One\r", "Two") != -1)
    998  1.1  plunky 		goto fail;
    999  1.1  plunky 	if (evhttp_add_header(&headers, "One", "Two") != 0)
   1000  1.1  plunky 		goto fail;
   1001  1.1  plunky 	if (evhttp_add_header(&headers, "One", "Two\r\n Three") != 0)
   1002  1.1  plunky 		goto fail;
   1003  1.1  plunky 	if (evhttp_add_header(&headers, "One\r", "Two") != -1)
   1004  1.1  plunky 		goto fail;
   1005  1.1  plunky 	if (evhttp_add_header(&headers, "One\n", "Two") != -1)
   1006  1.1  plunky 		goto fail;
   1007  1.1  plunky 	if (evhttp_add_header(&headers, "One", "Two\r") != -1)
   1008  1.1  plunky 		goto fail;
   1009  1.1  plunky 	if (evhttp_add_header(&headers, "One", "Two\n") != -1)
   1010  1.1  plunky 		goto fail;
   1011  1.1  plunky 
   1012  1.1  plunky 	evhttp_clear_headers(&headers);
   1013  1.1  plunky 
   1014  1.1  plunky 	fprintf(stdout, "OK\n");
   1015  1.1  plunky 	return;
   1016  1.1  plunky fail:
   1017  1.1  plunky 	fprintf(stdout, "FAILED\n");
   1018  1.1  plunky 	exit(1);
   1019  1.1  plunky }
   1020  1.1  plunky 
   1021  1.1  plunky static int validate_header(
   1022  1.1  plunky 	const struct evkeyvalq* headers,
   1023  1.1  plunky 	const char *key, const char *value)
   1024  1.1  plunky {
   1025  1.1  plunky 	const char *real_val = evhttp_find_header(headers, key);
   1026  1.1  plunky 	if (real_val == NULL)
   1027  1.1  plunky 		return (-1);
   1028  1.1  plunky 	if (strcmp(real_val, value) != 0)
   1029  1.1  plunky 		return (-1);
   1030  1.1  plunky 	return (0);
   1031  1.1  plunky }
   1032  1.1  plunky 
   1033  1.1  plunky static void
   1034  1.1  plunky http_parse_query_test(void)
   1035  1.1  plunky {
   1036  1.1  plunky 	struct evkeyvalq headers;
   1037  1.1  plunky 
   1038  1.1  plunky 	fprintf(stdout, "Testing HTTP query parsing: ");
   1039  1.1  plunky 
   1040  1.1  plunky 	TAILQ_INIT(&headers);
   1041  1.1  plunky 
   1042  1.1  plunky 	evhttp_parse_query("http://www.test.com/?q=test", &headers);
   1043  1.1  plunky 	if (validate_header(&headers, "q", "test") != 0)
   1044  1.1  plunky 		goto fail;
   1045  1.1  plunky 	evhttp_clear_headers(&headers);
   1046  1.1  plunky 
   1047  1.1  plunky 	evhttp_parse_query("http://www.test.com/?q=test&foo=bar", &headers);
   1048  1.1  plunky 	if (validate_header(&headers, "q", "test") != 0)
   1049  1.1  plunky 		goto fail;
   1050  1.1  plunky 	if (validate_header(&headers, "foo", "bar") != 0)
   1051  1.1  plunky 		goto fail;
   1052  1.1  plunky 	evhttp_clear_headers(&headers);
   1053  1.1  plunky 
   1054  1.1  plunky 	evhttp_parse_query("http://www.test.com/?q=test+foo", &headers);
   1055  1.1  plunky 	if (validate_header(&headers, "q", "test foo") != 0)
   1056  1.1  plunky 		goto fail;
   1057  1.1  plunky 	evhttp_clear_headers(&headers);
   1058  1.1  plunky 
   1059  1.1  plunky 	evhttp_parse_query("http://www.test.com/?q=test%0Afoo", &headers);
   1060  1.1  plunky 	if (validate_header(&headers, "q", "test\nfoo") != 0)
   1061  1.1  plunky 		goto fail;
   1062  1.1  plunky 	evhttp_clear_headers(&headers);
   1063  1.1  plunky 
   1064  1.1  plunky 	evhttp_parse_query("http://www.test.com/?q=test%0Dfoo", &headers);
   1065  1.1  plunky 	if (validate_header(&headers, "q", "test\rfoo") != 0)
   1066  1.1  plunky 		goto fail;
   1067  1.1  plunky 	evhttp_clear_headers(&headers);
   1068  1.1  plunky 
   1069  1.1  plunky 	fprintf(stdout, "OK\n");
   1070  1.1  plunky 	return;
   1071  1.1  plunky fail:
   1072  1.1  plunky 	fprintf(stdout, "FAILED\n");
   1073  1.1  plunky 	exit(1);
   1074  1.1  plunky }
   1075  1.1  plunky 
   1076  1.1  plunky static void
   1077  1.1  plunky http_base_test(void)
   1078  1.1  plunky {
   1079  1.1  plunky 	struct bufferevent *bev;
   1080  1.1  plunky 	int fd;
   1081  1.1  plunky 	const char *http_request;
   1082  1.1  plunky 	short port = -1;
   1083  1.1  plunky 
   1084  1.1  plunky 	test_ok = 0;
   1085  1.1  plunky 	fprintf(stdout, "Testing HTTP Server Event Base: ");
   1086  1.1  plunky 
   1087  1.1  plunky 	base = event_init();
   1088  1.1  plunky 
   1089  1.1  plunky 	/*
   1090  1.1  plunky 	 * create another bogus base - which is being used by all subsequen
   1091  1.1  plunky 	 * tests - yuck!
   1092  1.1  plunky 	 */
   1093  1.1  plunky 	event_init();
   1094  1.1  plunky 
   1095  1.1  plunky 	http = http_setup(&port, base);
   1096  1.1  plunky 
   1097  1.1  plunky 	fd = http_connect("127.0.0.1", port);
   1098  1.1  plunky 
   1099  1.1  plunky 	/* Stupid thing to send a request */
   1100  1.1  plunky 	bev = bufferevent_new(fd, http_readcb, http_writecb,
   1101  1.1  plunky 	    http_errorcb, NULL);
   1102  1.1  plunky 	bufferevent_base_set(base, bev);
   1103  1.1  plunky 
   1104  1.1  plunky 	http_request =
   1105  1.1  plunky 	    "GET /test HTTP/1.1\r\n"
   1106  1.1  plunky 	    "Host: somehost\r\n"
   1107  1.1  plunky 	    "Connection: close\r\n"
   1108  1.1  plunky 	    "\r\n";
   1109  1.1  plunky 
   1110  1.1  plunky 	bufferevent_write(bev, http_request, strlen(http_request));
   1111  1.1  plunky 
   1112  1.1  plunky 	event_base_dispatch(base);
   1113  1.1  plunky 
   1114  1.1  plunky 	bufferevent_free(bev);
   1115  1.1  plunky 	EVUTIL_CLOSESOCKET(fd);
   1116  1.1  plunky 
   1117  1.1  plunky 	evhttp_free(http);
   1118  1.1  plunky 
   1119  1.1  plunky 	event_base_free(base);
   1120  1.1  plunky 	base = NULL;
   1121  1.1  plunky 
   1122  1.1  plunky 	if (test_ok != 2) {
   1123  1.1  plunky 		fprintf(stdout, "FAILED\n");
   1124  1.1  plunky 		exit(1);
   1125  1.1  plunky 	}
   1126  1.1  plunky 
   1127  1.1  plunky 	fprintf(stdout, "OK\n");
   1128  1.1  plunky }
   1129  1.1  plunky 
   1130  1.1  plunky /*
   1131  1.1  plunky  * the server is going to reply with chunked data.
   1132  1.1  plunky  */
   1133  1.1  plunky 
   1134  1.1  plunky static void
   1135  1.1  plunky http_chunked_readcb(struct bufferevent *bev, void *arg)
   1136  1.1  plunky {
   1137  1.1  plunky 	/* nothing here */
   1138  1.1  plunky }
   1139  1.1  plunky 
   1140  1.1  plunky static void
   1141  1.1  plunky http_chunked_errorcb(struct bufferevent *bev, short what, void *arg)
   1142  1.1  plunky {
   1143  1.1  plunky 	if (!test_ok)
   1144  1.1  plunky 		goto out;
   1145  1.1  plunky 
   1146  1.1  plunky 	test_ok = -1;
   1147  1.1  plunky 
   1148  1.1  plunky 	if ((what & EVBUFFER_EOF) != 0) {
   1149  1.1  plunky 		struct evhttp_request *req = evhttp_request_new(NULL, NULL);
   1150  1.1  plunky 		const char *header;
   1151  1.1  plunky 		enum message_read_status done;
   1152  1.1  plunky 
   1153  1.1  plunky 		req->kind = EVHTTP_RESPONSE;
   1154  1.1  plunky 		done = evhttp_parse_firstline(req, EVBUFFER_INPUT(bev));
   1155  1.1  plunky 		if (done != ALL_DATA_READ)
   1156  1.1  plunky 			goto out;
   1157  1.1  plunky 
   1158  1.1  plunky 		done = evhttp_parse_headers(req, EVBUFFER_INPUT(bev));
   1159  1.1  plunky 		if (done != ALL_DATA_READ)
   1160  1.1  plunky 			goto out;
   1161  1.1  plunky 
   1162  1.1  plunky 		header = evhttp_find_header(req->input_headers, "Transfer-Encoding");
   1163  1.1  plunky 		if (header == NULL || strcmp(header, "chunked"))
   1164  1.1  plunky 			goto out;
   1165  1.1  plunky 
   1166  1.1  plunky 		header = evhttp_find_header(req->input_headers, "Connection");
   1167  1.1  plunky 		if (header == NULL || strcmp(header, "close"))
   1168  1.1  plunky 			goto out;
   1169  1.1  plunky 
   1170  1.1  plunky 		header = evbuffer_readline(EVBUFFER_INPUT(bev));
   1171  1.1  plunky 		if (header == NULL)
   1172  1.1  plunky 			goto out;
   1173  1.1  plunky 		/* 13 chars */
   1174  1.1  plunky 		if (strcmp(header, "d"))
   1175  1.1  plunky 			goto out;
   1176  1.1  plunky 		free((char*)header);
   1177  1.1  plunky 
   1178  1.1  plunky 		if (strncmp((char *)EVBUFFER_DATA(EVBUFFER_INPUT(bev)),
   1179  1.1  plunky 			"This is funny", 13))
   1180  1.1  plunky 			goto out;
   1181  1.1  plunky 
   1182  1.1  plunky 		evbuffer_drain(EVBUFFER_INPUT(bev), 13 + 2);
   1183  1.1  plunky 
   1184  1.1  plunky 		header = evbuffer_readline(EVBUFFER_INPUT(bev));
   1185  1.1  plunky 		if (header == NULL)
   1186  1.1  plunky 			goto out;
   1187  1.1  plunky 		/* 18 chars */
   1188  1.1  plunky 		if (strcmp(header, "12"))
   1189  1.1  plunky 			goto out;
   1190  1.1  plunky 		free((char *)header);
   1191  1.1  plunky 
   1192  1.1  plunky 		if (strncmp((char *)EVBUFFER_DATA(EVBUFFER_INPUT(bev)),
   1193  1.1  plunky 			"but not hilarious.", 18))
   1194  1.1  plunky 			goto out;
   1195  1.1  plunky 
   1196  1.1  plunky 		evbuffer_drain(EVBUFFER_INPUT(bev), 18 + 2);
   1197  1.1  plunky 
   1198  1.1  plunky 		header = evbuffer_readline(EVBUFFER_INPUT(bev));
   1199  1.1  plunky 		if (header == NULL)
   1200  1.1  plunky 			goto out;
   1201  1.1  plunky 		/* 8 chars */
   1202  1.1  plunky 		if (strcmp(header, "8"))
   1203  1.1  plunky 			goto out;
   1204  1.1  plunky 		free((char *)header);
   1205  1.1  plunky 
   1206  1.1  plunky 		if (strncmp((char *)EVBUFFER_DATA(EVBUFFER_INPUT(bev)),
   1207  1.1  plunky 			"bwv 1052.", 8))
   1208  1.1  plunky 			goto out;
   1209  1.1  plunky 
   1210  1.1  plunky 		evbuffer_drain(EVBUFFER_INPUT(bev), 8 + 2);
   1211  1.1  plunky 
   1212  1.1  plunky 		header = evbuffer_readline(EVBUFFER_INPUT(bev));
   1213  1.1  plunky 		if (header == NULL)
   1214  1.1  plunky 			goto out;
   1215  1.1  plunky 		/* 0 chars */
   1216  1.1  plunky 		if (strcmp(header, "0"))
   1217  1.1  plunky 			goto out;
   1218  1.1  plunky 		free((char *)header);
   1219  1.1  plunky 
   1220  1.1  plunky 		test_ok = 2;
   1221  1.1  plunky 	}
   1222  1.1  plunky 
   1223  1.1  plunky out:
   1224  1.1  plunky 	event_loopexit(NULL);
   1225  1.1  plunky }
   1226  1.1  plunky 
   1227  1.1  plunky static void
   1228  1.1  plunky http_chunked_writecb(struct bufferevent *bev, void *arg)
   1229  1.1  plunky {
   1230  1.1  plunky 	if (EVBUFFER_LENGTH(EVBUFFER_OUTPUT(bev)) == 0) {
   1231  1.1  plunky 		/* enable reading of the reply */
   1232  1.1  plunky 		bufferevent_enable(bev, EV_READ);
   1233  1.1  plunky 		test_ok++;
   1234  1.1  plunky 	}
   1235  1.1  plunky }
   1236  1.1  plunky 
   1237  1.1  plunky static void
   1238  1.1  plunky http_chunked_request_done(struct evhttp_request *req, void *arg)
   1239  1.1  plunky {
   1240  1.1  plunky 	if (req->response_code != HTTP_OK) {
   1241  1.1  plunky 		fprintf(stderr, "FAILED\n");
   1242  1.1  plunky 		exit(1);
   1243  1.1  plunky 	}
   1244  1.1  plunky 
   1245  1.1  plunky 	if (evhttp_find_header(req->input_headers,
   1246  1.1  plunky 		"Transfer-Encoding") == NULL) {
   1247  1.1  plunky 		fprintf(stderr, "FAILED\n");
   1248  1.1  plunky 		exit(1);
   1249  1.1  plunky 	}
   1250  1.1  plunky 
   1251  1.1  plunky 	if (EVBUFFER_LENGTH(req->input_buffer) != 13 + 18 + 8) {
   1252  1.1  plunky 		fprintf(stderr, "FAILED\n");
   1253  1.1  plunky 		exit(1);
   1254  1.1  plunky 	}
   1255  1.1  plunky 
   1256  1.1  plunky 	if (strncmp((char *)EVBUFFER_DATA(req->input_buffer),
   1257  1.1  plunky 		"This is funnybut not hilarious.bwv 1052",
   1258  1.1  plunky 		13 + 18 + 8)) {
   1259  1.1  plunky 		fprintf(stderr, "FAILED\n");
   1260  1.1  plunky 		exit(1);
   1261  1.1  plunky 	}
   1262  1.1  plunky 
   1263  1.1  plunky 	test_ok = 1;
   1264  1.1  plunky 	event_loopexit(NULL);
   1265  1.1  plunky }
   1266  1.1  plunky 
   1267  1.1  plunky static void
   1268  1.1  plunky http_chunked_test(void)
   1269  1.1  plunky {
   1270  1.1  plunky 	struct bufferevent *bev;
   1271  1.1  plunky 	int fd;
   1272  1.1  plunky 	const char *http_request;
   1273  1.1  plunky 	short port = -1;
   1274  1.1  plunky 	struct timeval tv_start, tv_end;
   1275  1.1  plunky 	struct evhttp_connection *evcon = NULL;
   1276  1.1  plunky 	struct evhttp_request *req = NULL;
   1277  1.1  plunky 	int i;
   1278  1.1  plunky 
   1279  1.1  plunky 	test_ok = 0;
   1280  1.1  plunky 	fprintf(stdout, "Testing Chunked HTTP Reply: ");
   1281  1.1  plunky 
   1282  1.1  plunky 	http = http_setup(&port, NULL);
   1283  1.1  plunky 
   1284  1.1  plunky 	fd = http_connect("127.0.0.1", port);
   1285  1.1  plunky 
   1286  1.1  plunky 	/* Stupid thing to send a request */
   1287  1.1  plunky 	bev = bufferevent_new(fd,
   1288  1.1  plunky 	    http_chunked_readcb, http_chunked_writecb,
   1289  1.1  plunky 	    http_chunked_errorcb, NULL);
   1290  1.1  plunky 
   1291  1.1  plunky 	http_request =
   1292  1.1  plunky 	    "GET /chunked HTTP/1.1\r\n"
   1293  1.1  plunky 	    "Host: somehost\r\n"
   1294  1.1  plunky 	    "Connection: close\r\n"
   1295  1.1  plunky 	    "\r\n";
   1296  1.1  plunky 
   1297  1.1  plunky 	bufferevent_write(bev, http_request, strlen(http_request));
   1298  1.1  plunky 
   1299  1.1  plunky 	evutil_gettimeofday(&tv_start, NULL);
   1300  1.1  plunky 
   1301  1.1  plunky 	event_dispatch();
   1302  1.1  plunky 
   1303  1.1  plunky 	evutil_gettimeofday(&tv_end, NULL);
   1304  1.1  plunky 	evutil_timersub(&tv_end, &tv_start, &tv_end);
   1305  1.1  plunky 
   1306  1.1  plunky 	if (tv_end.tv_sec >= 1) {
   1307  1.1  plunky 		fprintf(stdout, "FAILED (time)\n");
   1308  1.1  plunky 		exit (1);
   1309  1.1  plunky 	}
   1310  1.1  plunky 
   1311  1.1  plunky 
   1312  1.1  plunky 	if (test_ok != 2) {
   1313  1.1  plunky 		fprintf(stdout, "FAILED\n");
   1314  1.1  plunky 		exit(1);
   1315  1.1  plunky 	}
   1316  1.1  plunky 
   1317  1.1  plunky 	/* now try again with the regular connection object */
   1318  1.1  plunky 	evcon = evhttp_connection_new("127.0.0.1", port);
   1319  1.1  plunky 	if (evcon == NULL) {
   1320  1.1  plunky 		fprintf(stdout, "FAILED\n");
   1321  1.1  plunky 		exit(1);
   1322  1.1  plunky 	}
   1323  1.1  plunky 
   1324  1.1  plunky 	/* make two requests to check the keepalive behavior */
   1325  1.1  plunky 	for (i = 0; i < 2; i++) {
   1326  1.1  plunky 		test_ok = 0;
   1327  1.1  plunky 		req = evhttp_request_new(http_chunked_request_done, NULL);
   1328  1.1  plunky 
   1329  1.1  plunky 		/* Add the information that we care about */
   1330  1.1  plunky 		evhttp_add_header(req->output_headers, "Host", "somehost");
   1331  1.1  plunky 
   1332  1.1  plunky 		/* We give ownership of the request to the connection */
   1333  1.1  plunky 		if (evhttp_make_request(evcon, req,
   1334  1.1  plunky 			EVHTTP_REQ_GET, "/chunked") == -1) {
   1335  1.1  plunky 			fprintf(stdout, "FAILED\n");
   1336  1.1  plunky 			exit(1);
   1337  1.1  plunky 		}
   1338  1.1  plunky 
   1339  1.1  plunky 		event_dispatch();
   1340  1.1  plunky 
   1341  1.1  plunky 		if (test_ok != 1) {
   1342  1.1  plunky 			fprintf(stdout, "FAILED\n");
   1343  1.1  plunky 			exit(1);
   1344  1.1  plunky 		}
   1345  1.1  plunky 	}
   1346  1.1  plunky 
   1347  1.1  plunky 	evhttp_connection_free(evcon);
   1348  1.1  plunky 	evhttp_free(http);
   1349  1.1  plunky 
   1350  1.1  plunky 	fprintf(stdout, "OK\n");
   1351  1.1  plunky }
   1352  1.1  plunky 
   1353  1.1  plunky static void
   1354  1.1  plunky http_multi_line_header_test(void)
   1355  1.1  plunky {
   1356  1.1  plunky 	struct bufferevent *bev;
   1357  1.1  plunky 	int fd;
   1358  1.1  plunky 	const char *http_start_request;
   1359  1.1  plunky 	short port = -1;
   1360  1.1  plunky 
   1361  1.1  plunky 	test_ok = 0;
   1362  1.1  plunky 	fprintf(stdout, "Testing HTTP Server with multi line: ");
   1363  1.1  plunky 
   1364  1.1  plunky 	http = http_setup(&port, NULL);
   1365  1.1  plunky 
   1366  1.1  plunky 	fd = http_connect("127.0.0.1", port);
   1367  1.1  plunky 
   1368  1.1  plunky 	/* Stupid thing to send a request */
   1369  1.1  plunky 	bev = bufferevent_new(fd, http_readcb, http_writecb,
   1370  1.1  plunky 	    http_errorcb, NULL);
   1371  1.1  plunky 
   1372  1.1  plunky 	http_start_request =
   1373  1.1  plunky 	    "GET /test HTTP/1.1\r\n"
   1374  1.1  plunky 	    "Host: somehost\r\n"
   1375  1.1  plunky 	    "Connection: close\r\n"
   1376  1.1  plunky 	    "X-Multi:  aaaaaaaa\r\n"
   1377  1.1  plunky 	    " a\r\n"
   1378  1.1  plunky 	    "\tEND\r\n"
   1379  1.1  plunky 	    "X-Last: last\r\n"
   1380  1.1  plunky 	    "\r\n";
   1381  1.1  plunky 
   1382  1.1  plunky 	bufferevent_write(bev, http_start_request, strlen(http_start_request));
   1383  1.1  plunky 
   1384  1.1  plunky 	event_dispatch();
   1385  1.1  plunky 
   1386  1.1  plunky 	bufferevent_free(bev);
   1387  1.1  plunky 	EVUTIL_CLOSESOCKET(fd);
   1388  1.1  plunky 
   1389  1.1  plunky 	evhttp_free(http);
   1390  1.1  plunky 
   1391  1.1  plunky 	if (test_ok != 4) {
   1392  1.1  plunky 		fprintf(stdout, "FAILED\n");
   1393  1.1  plunky 		exit(1);
   1394  1.1  plunky 	}
   1395  1.1  plunky 
   1396  1.1  plunky 	fprintf(stdout, "OK\n");
   1397  1.1  plunky }
   1398  1.1  plunky 
   1399  1.1  plunky static void
   1400  1.1  plunky http_request_bad(struct evhttp_request *req, void *arg)
   1401  1.1  plunky {
   1402  1.1  plunky 	if (req != NULL) {
   1403  1.1  plunky 		fprintf(stderr, "FAILED\n");
   1404  1.1  plunky 		exit(1);
   1405  1.1  plunky 	}
   1406  1.1  plunky 
   1407  1.1  plunky 	test_ok = 1;
   1408  1.1  plunky 	event_loopexit(NULL);
   1409  1.1  plunky }
   1410  1.1  plunky 
   1411  1.1  plunky static void
   1412  1.1  plunky http_negative_content_length_test(void)
   1413  1.1  plunky {
   1414  1.1  plunky 	short port = -1;
   1415  1.1  plunky 	struct evhttp_connection *evcon = NULL;
   1416  1.1  plunky 	struct evhttp_request *req = NULL;
   1417  1.1  plunky 
   1418  1.1  plunky 	test_ok = 0;
   1419  1.1  plunky 	fprintf(stdout, "Testing HTTP Negative Content Length: ");
   1420  1.1  plunky 
   1421  1.1  plunky 	http = http_setup(&port, NULL);
   1422  1.1  plunky 
   1423  1.1  plunky 	evcon = evhttp_connection_new("127.0.0.1", port);
   1424  1.1  plunky 	if (evcon == NULL) {
   1425  1.1  plunky 		fprintf(stdout, "FAILED\n");
   1426  1.1  plunky 		exit(1);
   1427  1.1  plunky 	}
   1428  1.1  plunky 
   1429  1.1  plunky 	/*
   1430  1.1  plunky 	 * At this point, we want to schedule a request to the HTTP
   1431  1.1  plunky 	 * server using our make request method.
   1432  1.1  plunky 	 */
   1433  1.1  plunky 
   1434  1.1  plunky 	req = evhttp_request_new(http_request_bad, NULL);
   1435  1.1  plunky 
   1436  1.1  plunky 	/* Cause the response to have a negative content-length */
   1437  1.1  plunky 	evhttp_add_header(req->output_headers, "X-Negative", "makeitso");
   1438  1.1  plunky 
   1439  1.1  plunky 	/* We give ownership of the request to the connection */
   1440  1.1  plunky 	if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test") == -1) {
   1441  1.1  plunky 		fprintf(stdout, "FAILED\n");
   1442  1.1  plunky 		exit(1);
   1443  1.1  plunky 	}
   1444  1.1  plunky 
   1445  1.1  plunky 	event_dispatch();
   1446  1.1  plunky 
   1447  1.1  plunky 	evhttp_free(http);
   1448  1.1  plunky 
   1449  1.1  plunky 	if (test_ok != 1) {
   1450  1.1  plunky 		fprintf(stdout, "FAILED\n");
   1451  1.1  plunky 		exit(1);
   1452  1.1  plunky 	}
   1453  1.1  plunky 
   1454  1.1  plunky 	fprintf(stdout, "OK\n");
   1455  1.1  plunky }
   1456  1.1  plunky 
   1457  1.1  plunky void
   1458  1.1  plunky http_suite(void)
   1459  1.1  plunky {
   1460  1.1  plunky 	http_base_test();
   1461  1.1  plunky 	http_bad_header_test();
   1462  1.1  plunky 	http_parse_query_test();
   1463  1.1  plunky 	http_basic_test();
   1464  1.1  plunky 	http_connection_test(0 /* not-persistent */);
   1465  1.1  plunky 	http_connection_test(1 /* persistent */);
   1466  1.1  plunky 	http_close_detection(0 /* with delay */);
   1467  1.1  plunky 	http_close_detection(1 /* with delay */);
   1468  1.1  plunky 	http_post_test();
   1469  1.1  plunky 	http_failure_test();
   1470  1.1  plunky 	http_highport_test();
   1471  1.1  plunky 	http_dispatcher_test();
   1472  1.1  plunky 
   1473  1.1  plunky 	http_multi_line_header_test();
   1474  1.1  plunky 	http_negative_content_length_test();
   1475  1.1  plunky 
   1476  1.1  plunky 	http_chunked_test();
   1477  1.1  plunky }
   1478