1 /*	$NetBSD: regress_http.c,v 1.4 2015/01/29 07:26:02 spz Exp $	*/
2 /*
3  * Copyright (c) 2003-2007 Niels Provos <provos@citi.umich.edu>
4  * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  * 3. The name of the author may not be used to endorse or promote products
15  *    derived from this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 #ifdef WIN32
30 #include <winsock2.h>
31 #include <ws2tcpip.h>
32 #include <windows.h>
33 #endif
34 
35 #include "event2/event-config.h"
36 #include <sys/cdefs.h>
37 __RCSID("$NetBSD: regress_http.c,v 1.4 2015/01/29 07:26:02 spz Exp $");
38 
39 #include <sys/types.h>
40 #include <sys/stat.h>
41 #ifdef _EVENT_HAVE_SYS_TIME_H
42 #include <sys/time.h>
43 #endif
44 #include <sys/queue.h>
45 #ifndef WIN32
46 #include <sys/socket.h>
47 #include <signal.h>
48 #include <unistd.h>
49 #include <netdb.h>
50 #endif
51 #include <fcntl.h>
52 #include <stdlib.h>
53 #include <stdio.h>
54 #include <string.h>
55 #include <errno.h>
56 
57 #include "event2/dns.h"
58 
59 #include "event2/event.h"
60 #include "event2/http.h"
61 #include "event2/buffer.h"
62 #include "event2/bufferevent.h"
63 #include "event2/util.h"
64 #include "log-internal.h"
65 #include "util-internal.h"
66 #include "http-internal.h"
67 #include "regress.h"
68 #include "regress_testutils.h"
69 
70 static struct evhttp *http;
71 /* set if a test needs to call loopexit on a base */
72 static struct event_base *exit_base;
73 
74 static char const BASIC_REQUEST_BODY[] = "This is funny";
75 static void *basic_request_body = __UNCONST(BASIC_REQUEST_BODY);
76 
77 static void http_basic_cb(struct evhttp_request *req, void *arg);
78 static void http_chunked_cb(struct evhttp_request *req, void *arg);
79 static void http_post_cb(struct evhttp_request *req, void *arg);
80 static void http_put_cb(struct evhttp_request *req, void *arg);
81 static void http_delete_cb(struct evhttp_request *req, void *arg);
82 static void http_delay_cb(struct evhttp_request *req, void *arg);
83 static void http_large_delay_cb(struct evhttp_request *req, void *arg);
84 static void http_badreq_cb(struct evhttp_request *req, void *arg);
85 static void http_dispatcher_cb(struct evhttp_request *req, void *arg);
86 static int
http_bind(struct evhttp * myhttp,ev_uint16_t * pport)87 http_bind(struct evhttp *myhttp, ev_uint16_t *pport)
88 {
89 	int port;
90 	struct evhttp_bound_socket *sock;
91 
92 	sock = evhttp_bind_socket_with_handle(myhttp, "127.0.0.1", *pport);
93 	if (sock == NULL)
94 		event_errx(1, "Could not start web server");
95 
96 	port = regress_get_socket_port(evhttp_bound_socket_get_fd(sock));
97 	if (port < 0)
98 		return -1;
99 	*pport = (ev_uint16_t) port;
100 
101 	return 0;
102 }
103 
104 static struct evhttp *
http_setup(ev_uint16_t * pport,struct event_base * base)105 http_setup(ev_uint16_t *pport, struct event_base *base)
106 {
107 	struct evhttp *myhttp;
108 
109 	/* Try a few different ports */
110 	myhttp = evhttp_new(base);
111 
112 	if (http_bind(myhttp, pport) < 0)
113 		return NULL;
114 
115 	/* Register a callback for certain types of requests */
116 	evhttp_set_cb(myhttp, "/test", http_basic_cb, base);
117 	evhttp_set_cb(myhttp, "/chunked", http_chunked_cb, base);
118 	evhttp_set_cb(myhttp, "/streamed", http_chunked_cb, base);
119 	evhttp_set_cb(myhttp, "/postit", http_post_cb, base);
120 	evhttp_set_cb(myhttp, "/putit", http_put_cb, base);
121 	evhttp_set_cb(myhttp, "/deleteit", http_delete_cb, base);
122 	evhttp_set_cb(myhttp, "/delay", http_delay_cb, base);
123 	evhttp_set_cb(myhttp, "/largedelay", http_large_delay_cb, base);
124 	evhttp_set_cb(myhttp, "/badrequest", http_badreq_cb, base);
125 	evhttp_set_cb(myhttp, "/", http_dispatcher_cb, base);
126 	return (myhttp);
127 }
128 
129 #ifndef NI_MAXSERV
130 #define NI_MAXSERV 1024
131 #endif
132 
133 static evutil_socket_t
http_connect(const char * address,u_short port)134 http_connect(const char *address, u_short port)
135 {
136 	/* Stupid code for connecting */
137 	struct evutil_addrinfo ai, *aitop;
138 	char strport[NI_MAXSERV];
139 
140 	struct sockaddr *sa;
141 	int slen;
142 	evutil_socket_t fd;
143 
144 	memset(&ai, 0, sizeof(ai));
145 	ai.ai_family = AF_INET;
146 	ai.ai_socktype = SOCK_STREAM;
147 	evutil_snprintf(strport, sizeof(strport), "%d", port);
148 	if (evutil_getaddrinfo(address, strport, &ai, &aitop) != 0) {
149 		event_warn("getaddrinfo");
150 		return (-1);
151 	}
152 	sa = aitop->ai_addr;
153 	slen = aitop->ai_addrlen;
154 
155 	fd = socket(AF_INET, SOCK_STREAM, 0);
156 	if (fd == -1)
157 		event_err(1, "socket failed");
158 
159 	evutil_make_socket_nonblocking(fd);
160 	if (connect(fd, sa, slen) == -1) {
161 #ifdef WIN32
162 		int tmp_err = WSAGetLastError();
163 		if (tmp_err != WSAEINPROGRESS && tmp_err != WSAEINVAL &&
164 		    tmp_err != WSAEWOULDBLOCK)
165 			event_err(1, "connect failed");
166 #else
167 		if (errno != EINPROGRESS)
168 			event_err(1, "connect failed");
169 #endif
170 	}
171 
172 	evutil_freeaddrinfo(aitop);
173 
174 	return (fd);
175 }
176 
177 /* Helper: do a strcmp on the contents of buf and the string s. */
178 static int
evbuffer_datacmp(struct evbuffer * buf,const char * s)179 evbuffer_datacmp(struct evbuffer *buf, const char *s)
180 {
181 	size_t b_sz = evbuffer_get_length(buf);
182 	size_t s_sz = strlen(s);
183 	unsigned char *d;
184 	int r;
185 
186 	if (b_sz < s_sz)
187 		return -1;
188 
189 	d = evbuffer_pullup(buf, s_sz);
190 	if ((r = memcmp(d, s, s_sz)))
191 		return r;
192 
193 	if (b_sz > s_sz)
194 		return 1;
195 	else
196 		return 0;
197 }
198 
199 /* Helper: Return true iff buf contains s */
200 static int
evbuffer_contains(struct evbuffer * buf,const char * s)201 evbuffer_contains(struct evbuffer *buf, const char *s)
202 {
203 	struct evbuffer_ptr ptr;
204 	ptr = evbuffer_search(buf, s, strlen(s), NULL);
205 	return ptr.pos != -1;
206 }
207 
208 static void
http_readcb(struct bufferevent * bev,void * arg)209 http_readcb(struct bufferevent *bev, void *arg)
210 {
211 	const char *what = BASIC_REQUEST_BODY;
212 	struct event_base *my_base = arg;
213 
214 	if (evbuffer_contains(bufferevent_get_input(bev), what)) {
215 		struct evhttp_request *req = evhttp_request_new(NULL, NULL);
216 		enum message_read_status done;
217 
218 		/* req->kind = EVHTTP_RESPONSE; */
219 		done = evhttp_parse_firstline(req, bufferevent_get_input(bev));
220 		if (done != ALL_DATA_READ)
221 			goto out;
222 
223 		done = evhttp_parse_headers(req, bufferevent_get_input(bev));
224 		if (done != ALL_DATA_READ)
225 			goto out;
226 
227 		if (done == 1 &&
228 		    evhttp_find_header(evhttp_request_get_input_headers(req),
229 			"Content-Type") != NULL)
230 			test_ok++;
231 
232 	 out:
233 		evhttp_request_free(req);
234 		bufferevent_disable(bev, EV_READ);
235 		if (exit_base)
236 			event_base_loopexit(exit_base, NULL);
237 		else if (my_base)
238 			event_base_loopexit(my_base, NULL);
239 		else {
240 			fprintf(stderr, "No way to exit loop!\n");
241 			exit(1);
242 		}
243 	}
244 }
245 
246 static void
http_writecb(struct bufferevent * bev,void * arg)247 http_writecb(struct bufferevent *bev, void *arg)
248 {
249 	if (evbuffer_get_length(bufferevent_get_output(bev)) == 0) {
250 		/* enable reading of the reply */
251 		bufferevent_enable(bev, EV_READ);
252 		test_ok++;
253 	}
254 }
255 
256 static void
http_errorcb(struct bufferevent * bev,short what,void * arg)257 http_errorcb(struct bufferevent *bev, short what, void *arg)
258 {
259 	test_ok = -2;
260 	event_base_loopexit(arg, NULL);
261 }
262 
263 static void
http_basic_cb(struct evhttp_request * req,void * arg)264 http_basic_cb(struct evhttp_request *req, void *arg)
265 {
266 	struct evbuffer *evb = evbuffer_new();
267 	int empty = evhttp_find_header(evhttp_request_get_input_headers(req), "Empty") != NULL;
268 	event_debug(("%s: called\n", __func__));
269 	evbuffer_add_printf(evb, BASIC_REQUEST_BODY);
270 
271 	/* For multi-line headers test */
272 	{
273 		const char *multi =
274 		    evhttp_find_header(evhttp_request_get_input_headers(req),"X-multi");
275 		if (multi) {
276 			if (strcmp("END", multi + strlen(multi) - 3) == 0)
277 				test_ok++;
278 			if (evhttp_find_header(evhttp_request_get_input_headers(req), "X-Last"))
279 				test_ok++;
280 		}
281 	}
282 
283 	/* injecting a bad content-length */
284 	if (evhttp_find_header(evhttp_request_get_input_headers(req), "X-Negative"))
285 		evhttp_add_header(evhttp_request_get_output_headers(req),
286 		    "Content-Length", "-100");
287 
288 	/* allow sending of an empty reply */
289 	evhttp_send_reply(req, HTTP_OK, "Everything is fine",
290 	    !empty ? evb : NULL);
291 
292 	evbuffer_free(evb);
293 }
294 
295 static char const* const CHUNKS[] = {
296 	"This is funny",
297 	"but not hilarious.",
298 	"bwv 1052"
299 };
300 
301 struct chunk_req_state {
302 	struct event_base *base;
303 	struct evhttp_request *req;
304 	int i;
305 };
306 
307 static void
http_chunked_trickle_cb(evutil_socket_t fd,short events,void * arg)308 http_chunked_trickle_cb(evutil_socket_t fd, short events, void *arg)
309 {
310 	struct evbuffer *evb = evbuffer_new();
311 	struct chunk_req_state *state = arg;
312 	struct timeval when = { 0, 0 };
313 
314 	evbuffer_add_printf(evb, "%s", CHUNKS[state->i]);
315 	evhttp_send_reply_chunk(state->req, evb);
316 	evbuffer_free(evb);
317 
318 	if (++state->i < (int) (sizeof(CHUNKS)/sizeof(CHUNKS[0]))) {
319 		event_base_once(state->base, -1, EV_TIMEOUT,
320 		    http_chunked_trickle_cb, state, &when);
321 	} else {
322 		evhttp_send_reply_end(state->req);
323 		free(state);
324 	}
325 }
326 
327 static void
http_chunked_cb(struct evhttp_request * req,void * arg)328 http_chunked_cb(struct evhttp_request *req, void *arg)
329 {
330 	struct timeval when = { 0, 0 };
331 	struct chunk_req_state *state = malloc(sizeof(struct chunk_req_state));
332 	event_debug(("%s: called\n", __func__));
333 
334 	memset(state, 0, sizeof(struct chunk_req_state));
335 	state->req = req;
336 	state->base = arg;
337 
338 	if (strcmp(evhttp_request_get_uri(req), "/streamed") == 0) {
339 		evhttp_add_header(evhttp_request_get_output_headers(req), "Content-Length", "39");
340 	}
341 
342 	/* generate a chunked/streamed reply */
343 	evhttp_send_reply_start(req, HTTP_OK, "Everything is fine");
344 
345 	/* but trickle it across several iterations to ensure we're not
346 	 * assuming it comes all at once */
347 	event_base_once(arg, -1, EV_TIMEOUT, http_chunked_trickle_cb, state, &when);
348 }
349 
350 static void
http_complete_write(evutil_socket_t fd,short what,void * arg)351 http_complete_write(evutil_socket_t fd, short what, void *arg)
352 {
353 	struct bufferevent *bev = arg;
354 	const char *http_request = "host\r\n"
355 	    "Connection: close\r\n"
356 	    "\r\n";
357 	bufferevent_write(bev, http_request, strlen(http_request));
358 }
359 
360 static void
http_basic_test(void * arg)361 http_basic_test(void *arg)
362 {
363 	struct basic_test_data *data = arg;
364 	struct timeval tv;
365 	struct bufferevent *bev;
366 	evutil_socket_t fd;
367 	const char *http_request;
368 	ev_uint16_t port = 0, port2 = 0;
369 
370 	test_ok = 0;
371 
372 	http = http_setup(&port, data->base);
373 
374 	/* bind to a second socket */
375 	if (http_bind(http, &port2) == -1) {
376 		fprintf(stdout, "FAILED (bind)\n");
377 		exit(1);
378 	}
379 
380 	fd = http_connect("127.0.0.1", port);
381 
382 	/* Stupid thing to send a request */
383 	bev = bufferevent_socket_new(data->base, fd, 0);
384 	bufferevent_setcb(bev, http_readcb, http_writecb,
385 	    http_errorcb, data->base);
386 
387 	/* first half of the http request */
388 	http_request =
389 	    "GET /test HTTP/1.1\r\n"
390 	    "Host: some";
391 
392 	bufferevent_write(bev, http_request, strlen(http_request));
393 	evutil_timerclear(&tv);
394 	tv.tv_usec = 10000;
395 	event_base_once(data->base,
396 	    -1, EV_TIMEOUT, http_complete_write, bev, &tv);
397 
398 	event_base_dispatch(data->base);
399 
400 	tt_assert(test_ok == 3);
401 
402 	/* connect to the second port */
403 	bufferevent_free(bev);
404 	evutil_closesocket(fd);
405 
406 	fd = http_connect("127.0.0.1", port2);
407 
408 	/* Stupid thing to send a request */
409 	bev = bufferevent_socket_new(data->base, fd, 0);
410 	bufferevent_setcb(bev, http_readcb, http_writecb,
411 	    http_errorcb, data->base);
412 
413 	http_request =
414 	    "GET /test HTTP/1.1\r\n"
415 	    "Host: somehost\r\n"
416 	    "Connection: close\r\n"
417 	    "\r\n";
418 
419 	bufferevent_write(bev, http_request, strlen(http_request));
420 
421 	event_base_dispatch(data->base);
422 
423 	tt_assert(test_ok == 5);
424 
425 	/* Connect to the second port again. This time, send an absolute uri. */
426 	bufferevent_free(bev);
427 	evutil_closesocket(fd);
428 
429 	fd = http_connect("127.0.0.1", port2);
430 
431 	/* Stupid thing to send a request */
432 	bev = bufferevent_socket_new(data->base, fd, 0);
433 	bufferevent_setcb(bev, http_readcb, http_writecb,
434 	    http_errorcb, data->base);
435 
436 	http_request =
437 	    "GET http://somehost.net/test HTTP/1.1\r\n"
438 	    "Host: somehost\r\n"
439 	    "Connection: close\r\n"
440 	    "\r\n";
441 
442 	bufferevent_write(bev, http_request, strlen(http_request));
443 
444 	event_base_dispatch(data->base);
445 
446 	tt_assert(test_ok == 7);
447 
448 	evhttp_free(http);
449  end:
450 	;
451 }
452 
453 static void
http_delay_reply(evutil_socket_t fd,short what,void * arg)454 http_delay_reply(evutil_socket_t fd, short what, void *arg)
455 {
456 	struct evhttp_request *req = arg;
457 
458 	evhttp_send_reply(req, HTTP_OK, "Everything is fine", NULL);
459 
460 	++test_ok;
461 }
462 
463 static void
http_delay_cb(struct evhttp_request * req,void * arg)464 http_delay_cb(struct evhttp_request *req, void *arg)
465 {
466 	struct timeval tv;
467 	evutil_timerclear(&tv);
468 	tv.tv_sec = 0;
469 	tv.tv_usec = 200 * 1000;
470 
471 	event_base_once(arg, -1, EV_TIMEOUT, http_delay_reply, req, &tv);
472 }
473 
474 static void
http_badreq_cb(struct evhttp_request * req,void * arg)475 http_badreq_cb(struct evhttp_request *req, void *arg)
476 {
477 	struct evbuffer *buf = evbuffer_new();
478 
479 	evhttp_add_header(evhttp_request_get_output_headers(req), "Content-Type", "text/xml; charset=UTF-8");
480 	evbuffer_add_printf(buf, "Hello, %s!", "127.0.0.1");
481 
482 	evhttp_send_reply(req, HTTP_OK, "OK", buf);
483 	evbuffer_free(buf);
484 }
485 
486 static void
http_badreq_errorcb(struct bufferevent * bev,short what,void * arg)487 http_badreq_errorcb(struct bufferevent *bev, short what, void *arg)
488 {
489 	event_debug(("%s: called (what=%04x, arg=%p)", __func__, what, arg));
490 	/* ignore */
491 }
492 
493 #ifndef SHUT_WR
494 #ifdef WIN32
495 #define SHUT_WR SD_SEND
496 #else
497 #define SHUT_WR 1
498 #endif
499 #endif
500 
501 static void
http_badreq_readcb(struct bufferevent * bev,void * arg)502 http_badreq_readcb(struct bufferevent *bev, void *arg)
503 {
504 	const char *what = "Hello, 127.0.0.1";
505 	const char *bad_request = "400 Bad Request";
506 
507 	if (evbuffer_contains(bufferevent_get_input(bev), bad_request)) {
508 		TT_FAIL(("%s:bad request detected", __func__));
509 		bufferevent_disable(bev, EV_READ);
510 		event_base_loopexit(arg, NULL);
511 		return;
512 	}
513 
514 	if (evbuffer_contains(bufferevent_get_input(bev), what)) {
515 		struct evhttp_request *req = evhttp_request_new(NULL, NULL);
516 		enum message_read_status done;
517 
518 		/* req->kind = EVHTTP_RESPONSE; */
519 		done = evhttp_parse_firstline(req, bufferevent_get_input(bev));
520 		if (done != ALL_DATA_READ)
521 			goto out;
522 
523 		done = evhttp_parse_headers(req, bufferevent_get_input(bev));
524 		if (done != ALL_DATA_READ)
525 			goto out;
526 
527 		if (done == 1 &&
528 		    evhttp_find_header(evhttp_request_get_input_headers(req),
529 			"Content-Type") != NULL)
530 			test_ok++;
531 
532 	out:
533 		evhttp_request_free(req);
534 		evbuffer_drain(bufferevent_get_input(bev), evbuffer_get_length(bufferevent_get_input(bev)));
535 	}
536 
537 	shutdown(bufferevent_getfd(bev), SHUT_WR);
538 }
539 
540 static void
http_badreq_successcb(evutil_socket_t fd,short what,void * arg)541 http_badreq_successcb(evutil_socket_t fd, short what, void *arg)
542 {
543 	event_debug(("%s: called (what=%04x, arg=%p)", __func__, what, arg));
544 	event_base_loopexit(exit_base, NULL);
545 }
546 
547 static void
http_bad_request_test(void * arg)548 http_bad_request_test(void *arg)
549 {
550 	struct basic_test_data *data = arg;
551 	struct timeval tv;
552 	struct bufferevent *bev = NULL;
553 	evutil_socket_t fd;
554 	const char *http_request;
555 	ev_uint16_t port=0, port2=0;
556 
557 	test_ok = 0;
558 	exit_base = data->base;
559 
560 	http = http_setup(&port, data->base);
561 
562 	/* bind to a second socket */
563 	if (http_bind(http, &port2) == -1)
564 		TT_DIE(("Bind socket failed"));
565 
566 	/* NULL request test */
567 	fd = http_connect("127.0.0.1", port);
568 
569 	/* Stupid thing to send a request */
570 	bev = bufferevent_socket_new(data->base, fd, 0);
571 	bufferevent_setcb(bev, http_badreq_readcb, http_writecb,
572 	    http_badreq_errorcb, data->base);
573 	bufferevent_enable(bev, EV_READ);
574 
575 	/* real NULL request */
576 	http_request = "";
577 
578 	bufferevent_write(bev, http_request, strlen(http_request));
579 
580 	shutdown(fd, SHUT_WR);
581 	timerclear(&tv);
582 	tv.tv_usec = 10000;
583 	event_base_once(data->base, -1, EV_TIMEOUT, http_badreq_successcb, bev, &tv);
584 
585 	event_base_dispatch(data->base);
586 
587 	bufferevent_free(bev);
588 	evutil_closesocket(fd);
589 
590 	if (test_ok != 0) {
591 		fprintf(stdout, "FAILED\n");
592 		exit(1);
593 	}
594 
595 	/* Second answer (BAD REQUEST) on connection close */
596 
597 	/* connect to the second port */
598 	fd = http_connect("127.0.0.1", port2);
599 
600 	/* Stupid thing to send a request */
601 	bev = bufferevent_socket_new(data->base, fd, 0);
602 	bufferevent_setcb(bev, http_badreq_readcb, http_writecb,
603 	    http_badreq_errorcb, data->base);
604 	bufferevent_enable(bev, EV_READ);
605 
606 	/* first half of the http request */
607 	http_request =
608 		"GET /badrequest HTTP/1.0\r\n"	\
609 		"Connection: Keep-Alive\r\n"	\
610 		"\r\n";
611 
612 	bufferevent_write(bev, http_request, strlen(http_request));
613 
614 	timerclear(&tv);
615 	tv.tv_usec = 10000;
616 	event_base_once(data->base, -1, EV_TIMEOUT, http_badreq_successcb, bev, &tv);
617 
618 	event_base_dispatch(data->base);
619 
620 	tt_int_op(test_ok, ==, 2);
621 
622 end:
623 	evhttp_free(http);
624 	if (bev)
625 		bufferevent_free(bev);
626 }
627 
628 static struct evhttp_connection *delayed_client;
629 
630 static void
http_large_delay_cb(struct evhttp_request * req,void * arg)631 http_large_delay_cb(struct evhttp_request *req, void *arg)
632 {
633 	struct timeval tv;
634 	evutil_timerclear(&tv);
635 	tv.tv_sec = 3;
636 
637 	event_base_once(arg, -1, EV_TIMEOUT, http_delay_reply, req, &tv);
638 	evhttp_connection_fail(delayed_client, EVCON_HTTP_EOF);
639 }
640 
641 /*
642  * HTTP DELETE test,  just piggyback on the basic test
643  */
644 
645 static void
http_delete_cb(struct evhttp_request * req,void * arg)646 http_delete_cb(struct evhttp_request *req, void *arg)
647 {
648 	struct evbuffer *evb = evbuffer_new();
649 	int empty = evhttp_find_header(evhttp_request_get_input_headers(req), "Empty") != NULL;
650 
651 	/* Expecting a DELETE request */
652 	if (evhttp_request_get_command(req) != EVHTTP_REQ_DELETE) {
653 		fprintf(stdout, "FAILED (delete type)\n");
654 		exit(1);
655 	}
656 
657 	event_debug(("%s: called\n", __func__));
658 	evbuffer_add_printf(evb, BASIC_REQUEST_BODY);
659 
660 	/* allow sending of an empty reply */
661 	evhttp_send_reply(req, HTTP_OK, "Everything is fine",
662 	    !empty ? evb : NULL);
663 
664 	evbuffer_free(evb);
665 }
666 
667 static void
http_delete_test(void * arg)668 http_delete_test(void *arg)
669 {
670 	struct basic_test_data *data = arg;
671 	struct bufferevent *bev;
672 	evutil_socket_t fd;
673 	const char *http_request;
674 	ev_uint16_t port = 0;
675 
676 	test_ok = 0;
677 
678 	http = http_setup(&port, data->base);
679 
680 	fd = http_connect("127.0.0.1", port);
681 
682 	/* Stupid thing to send a request */
683 	bev = bufferevent_socket_new(data->base, fd, 0);
684 	bufferevent_setcb(bev, http_readcb, http_writecb,
685 	    http_errorcb, data->base);
686 
687 	http_request =
688 	    "DELETE /deleteit HTTP/1.1\r\n"
689 	    "Host: somehost\r\n"
690 	    "Connection: close\r\n"
691 	    "\r\n";
692 
693 	bufferevent_write(bev, http_request, strlen(http_request));
694 
695 	event_base_dispatch(data->base);
696 
697 	bufferevent_free(bev);
698 	evutil_closesocket(fd);
699 
700 	evhttp_free(http);
701 
702 	tt_int_op(test_ok, ==, 2);
703  end:
704 	;
705 }
706 
707 static void
http_allowed_methods_eventcb(struct bufferevent * bev,short what,void * arg)708 http_allowed_methods_eventcb(struct bufferevent *bev, short what, void *arg)
709 {
710 	char **output = arg;
711 	if ((what & (BEV_EVENT_ERROR|BEV_EVENT_EOF))) {
712 		char buf[4096];
713 		int n;
714 		n = evbuffer_remove(bufferevent_get_input(bev), buf,
715 		    sizeof(buf)-1);
716 		if (n >= 0) {
717 			buf[n]='\0';
718 			if (*output)
719 				free(*output);
720 			*output = strdup(buf);
721 		}
722 		event_base_loopexit(exit_base, NULL);
723 	}
724 }
725 
726 static void
http_allowed_methods_test(void * arg)727 http_allowed_methods_test(void *arg)
728 {
729 	struct basic_test_data *data = arg;
730 	struct bufferevent *bev1, *bev2, *bev3;
731 	evutil_socket_t fd1, fd2, fd3;
732 	const char *http_request;
733 	char *result1=NULL, *result2=NULL, *result3=NULL;
734 	ev_uint16_t port = 0;
735 
736 	exit_base = data->base;
737 	test_ok = 0;
738 
739 	http = http_setup(&port, data->base);
740 
741 	fd1 = http_connect("127.0.0.1", port);
742 
743 	/* GET is out; PATCH is in. */
744 	evhttp_set_allowed_methods(http, EVHTTP_REQ_PATCH);
745 
746 	/* Stupid thing to send a request */
747 	bev1 = bufferevent_socket_new(data->base, fd1, 0);
748 	bufferevent_enable(bev1, EV_READ|EV_WRITE);
749 	bufferevent_setcb(bev1, NULL, NULL,
750 	    http_allowed_methods_eventcb, &result1);
751 
752 	http_request =
753 	    "GET /index.html HTTP/1.1\r\n"
754 	    "Host: somehost\r\n"
755 	    "Connection: close\r\n"
756 	    "\r\n";
757 
758 	bufferevent_write(bev1, http_request, strlen(http_request));
759 
760 	event_base_dispatch(data->base);
761 
762 	fd2 = http_connect("127.0.0.1", port);
763 
764 	bev2 = bufferevent_socket_new(data->base, fd2, 0);
765 	bufferevent_enable(bev2, EV_READ|EV_WRITE);
766 	bufferevent_setcb(bev2, NULL, NULL,
767 	    http_allowed_methods_eventcb, &result2);
768 
769 	http_request =
770 	    "PATCH /test HTTP/1.1\r\n"
771 	    "Host: somehost\r\n"
772 	    "Connection: close\r\n"
773 	    "\r\n";
774 
775 	bufferevent_write(bev2, http_request, strlen(http_request));
776 
777 	event_base_dispatch(data->base);
778 
779 	fd3 = http_connect("127.0.0.1", port);
780 
781 	bev3 = bufferevent_socket_new(data->base, fd3, 0);
782 	bufferevent_enable(bev3, EV_READ|EV_WRITE);
783 	bufferevent_setcb(bev3, NULL, NULL,
784 	    http_allowed_methods_eventcb, &result3);
785 
786 	http_request =
787 	    "FLOOP /test HTTP/1.1\r\n"
788 	    "Host: somehost\r\n"
789 	    "Connection: close\r\n"
790 	    "\r\n";
791 
792 	bufferevent_write(bev3, http_request, strlen(http_request));
793 
794 	event_base_dispatch(data->base);
795 
796 	bufferevent_free(bev1);
797 	bufferevent_free(bev2);
798 	bufferevent_free(bev3);
799 	evutil_closesocket(fd1);
800 	evutil_closesocket(fd2);
801 	evutil_closesocket(fd3);
802 
803 	evhttp_free(http);
804 
805 	/* Method known but disallowed */
806 	tt_assert(result1);
807 	tt_assert(!strncmp(result1, "HTTP/1.1 501 ", strlen("HTTP/1.1 501 ")));
808 
809 	/* Method known and allowed */
810 	tt_assert(result2);
811 	tt_assert(!strncmp(result2, "HTTP/1.1 200 ", strlen("HTTP/1.1 200 ")));
812 
813 	/* Method unknown */
814 	tt_assert(result3);
815 	tt_assert(!strncmp(result3, "HTTP/1.1 501 ", strlen("HTTP/1.1 501 ")));
816 
817  end:
818 	if (result1)
819 		free(result1);
820 	if (result2)
821 		free(result2);
822 	if (result3)
823 		free(result3);
824 }
825 
826 static void http_request_done(struct evhttp_request *, void *);
827 static void http_request_empty_done(struct evhttp_request *, void *);
828 
829 static void
_http_connection_test(struct basic_test_data * data,int persistent)830 _http_connection_test(struct basic_test_data *data, int persistent)
831 {
832 	ev_uint16_t port = 0;
833 	struct evhttp_connection *evcon = NULL;
834 	struct evhttp_request *req = NULL;
835 
836 	test_ok = 0;
837 
838 	http = http_setup(&port, data->base);
839 
840 	evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port);
841 	tt_assert(evcon);
842 
843 	tt_assert(evhttp_connection_get_base(evcon) == data->base);
844 
845 	exit_base = data->base;
846 	/*
847 	 * At this point, we want to schedule a request to the HTTP
848 	 * server using our make request method.
849 	 */
850 
851 	req = evhttp_request_new(http_request_done, basic_request_body);
852 
853 	/* Add the information that we care about */
854 	evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
855 
856 	/* We give ownership of the request to the connection */
857 	if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test") == -1) {
858 		fprintf(stdout, "FAILED\n");
859 		exit(1);
860 	}
861 
862 	event_base_dispatch(data->base);
863 
864 	tt_assert(test_ok);
865 
866 	/* try to make another request over the same connection */
867 	test_ok = 0;
868 
869 	req = evhttp_request_new(http_request_done, basic_request_body);
870 
871 	/* Add the information that we care about */
872 	evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
873 
874 	/*
875 	 * if our connections are not supposed to be persistent; request
876 	 * a close from the server.
877 	 */
878 	if (!persistent)
879 		evhttp_add_header(evhttp_request_get_output_headers(req), "Connection", "close");
880 
881 	/* We give ownership of the request to the connection */
882 	if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test") == -1) {
883 		tt_abort_msg("couldn't make request");
884 	}
885 
886 	event_base_dispatch(data->base);
887 
888 	/* make another request: request empty reply */
889 	test_ok = 0;
890 
891 	req = evhttp_request_new(http_request_empty_done, data->base);
892 
893 	/* Add the information that we care about */
894 	evhttp_add_header(evhttp_request_get_output_headers(req), "Empty", "itis");
895 
896 	/* We give ownership of the request to the connection */
897 	if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test") == -1) {
898 		tt_abort_msg("Couldn't make request");
899 	}
900 
901 	event_base_dispatch(data->base);
902 
903  end:
904 	if (evcon)
905 		evhttp_connection_free(evcon);
906 	if (http)
907 		evhttp_free(http);
908 }
909 
910 static void
http_connection_test(void * arg)911 http_connection_test(void *arg)
912 {
913 	_http_connection_test(arg, 0);
914 }
915 static void
http_persist_connection_test(void * arg)916 http_persist_connection_test(void *arg)
917 {
918 	_http_connection_test(arg, 1);
919 }
920 
921 static struct regress_dns_server_table search_table[] = {
922 	{ "localhost", "A", "127.0.0.1", 0 },
923 	{ NULL, NULL, NULL, 0 }
924 };
925 
926 static void
http_connection_async_test(void * arg)927 http_connection_async_test(void *arg)
928 {
929 	struct basic_test_data *data = arg;
930 	ev_uint16_t port = 0;
931 	struct evhttp_connection *evcon = NULL;
932 	struct evhttp_request *req = NULL;
933 	struct evdns_base *dns_base = NULL;
934 	ev_uint16_t portnum = 0;
935 	char address[64];
936 
937 	exit_base = data->base;
938 	tt_assert(regress_dnsserver(data->base, &portnum, search_table));
939 
940 	dns_base = evdns_base_new(data->base, 0/* init name servers */);
941 	tt_assert(dns_base);
942 
943 	/* Add ourself as the only nameserver, and make sure we really are
944 	 * the only nameserver. */
945 	evutil_snprintf(address, sizeof(address), "127.0.0.1:%d", portnum);
946 	evdns_base_nameserver_ip_add(dns_base, address);
947 
948 	test_ok = 0;
949 
950 	http = http_setup(&port, data->base);
951 
952 	evcon = evhttp_connection_base_new(data->base, dns_base, "127.0.0.1", port);
953 	tt_assert(evcon);
954 
955 	/*
956 	 * At this point, we want to schedule a request to the HTTP
957 	 * server using our make request method.
958 	 */
959 
960 	req = evhttp_request_new(http_request_done, basic_request_body);
961 
962 	/* Add the information that we care about */
963 	evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
964 
965 	/* We give ownership of the request to the connection */
966 	if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test") == -1) {
967 		fprintf(stdout, "FAILED\n");
968 		exit(1);
969 	}
970 
971 	event_base_dispatch(data->base);
972 
973 	tt_assert(test_ok);
974 
975 	/* try to make another request over the same connection */
976 	test_ok = 0;
977 
978 	req = evhttp_request_new(http_request_done, basic_request_body);
979 
980 	/* Add the information that we care about */
981 	evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
982 
983 	/*
984 	 * if our connections are not supposed to be persistent; request
985 	 * a close from the server.
986 	 */
987 	evhttp_add_header(evhttp_request_get_output_headers(req), "Connection", "close");
988 
989 	/* We give ownership of the request to the connection */
990 	if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test") == -1) {
991 		tt_abort_msg("couldn't make request");
992 	}
993 
994 	event_base_dispatch(data->base);
995 
996 	/* make another request: request empty reply */
997 	test_ok = 0;
998 
999 	req = evhttp_request_new(http_request_empty_done, data->base);
1000 
1001 	/* Add the information that we care about */
1002 	evhttp_add_header(evhttp_request_get_output_headers(req), "Empty", "itis");
1003 
1004 	/* We give ownership of the request to the connection */
1005 	if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test") == -1) {
1006 		tt_abort_msg("Couldn't make request");
1007 	}
1008 
1009 	event_base_dispatch(data->base);
1010 
1011  end:
1012 	if (evcon)
1013 		evhttp_connection_free(evcon);
1014 	if (http)
1015 		evhttp_free(http);
1016 	if (dns_base)
1017 		evdns_base_free(dns_base, 0);
1018 	regress_clean_dnsserver();
1019 }
1020 
1021 static void
http_request_never_call(struct evhttp_request * req,void * arg)1022 http_request_never_call(struct evhttp_request *req, void *arg)
1023 {
1024 	fprintf(stdout, "FAILED\n");
1025 	exit(1);
1026 }
1027 
1028 static void
http_do_cancel(evutil_socket_t fd,short what,void * arg)1029 http_do_cancel(evutil_socket_t fd, short what, void *arg)
1030 {
1031 	struct evhttp_request *req = arg;
1032 	struct timeval tv;
1033 	struct event_base *base;
1034 	evutil_timerclear(&tv);
1035 	tv.tv_sec = 0;
1036 	tv.tv_usec = 500 * 1000;
1037 
1038 	base = evhttp_connection_get_base(evhttp_request_get_connection(req));
1039 	evhttp_cancel_request(req);
1040 
1041 	event_base_loopexit(base, &tv);
1042 
1043 	++test_ok;
1044 }
1045 
1046 static void
http_cancel_test(void * arg)1047 http_cancel_test(void *arg)
1048 {
1049 	struct basic_test_data *data = arg;
1050 	ev_uint16_t port = 0;
1051 	struct evhttp_connection *evcon = NULL;
1052 	struct evhttp_request *req = NULL;
1053 	struct timeval tv;
1054 
1055 	exit_base = data->base;
1056 
1057 	test_ok = 0;
1058 
1059 	http = http_setup(&port, data->base);
1060 
1061 	evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port);
1062 	tt_assert(evcon);
1063 
1064 	/*
1065 	 * At this point, we want to schedule a request to the HTTP
1066 	 * server using our make request method.
1067 	 */
1068 
1069 	req = evhttp_request_new(http_request_never_call, NULL);
1070 
1071 	/* Add the information that we care about */
1072 	evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
1073 
1074 	/* We give ownership of the request to the connection */
1075 	tt_int_op(evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/delay"),
1076 		  !=, -1);
1077 
1078 	evutil_timerclear(&tv);
1079 	tv.tv_sec = 0;
1080 	tv.tv_usec = 100 * 1000;
1081 
1082 	event_base_once(data->base, -1, EV_TIMEOUT, http_do_cancel, req, &tv);
1083 
1084 	event_base_dispatch(data->base);
1085 
1086 	tt_int_op(test_ok, ==, 2);
1087 
1088 	/* try to make another request over the same connection */
1089 	test_ok = 0;
1090 
1091 	req = evhttp_request_new(http_request_done, basic_request_body);
1092 
1093 	/* Add the information that we care about */
1094 	evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
1095 
1096 	/* We give ownership of the request to the connection */
1097 	tt_int_op(evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test"),
1098 		  !=, -1);
1099 
1100 	event_base_dispatch(data->base);
1101 
1102 	/* make another request: request empty reply */
1103 	test_ok = 0;
1104 
1105 	req = evhttp_request_new(http_request_empty_done, data->base);
1106 
1107 	/* Add the information that we care about */
1108 	evhttp_add_header(evhttp_request_get_output_headers(req), "Empty", "itis");
1109 
1110 	/* We give ownership of the request to the connection */
1111 	tt_int_op(evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test"),
1112 		  !=, -1);
1113 
1114 	event_base_dispatch(data->base);
1115 
1116  end:
1117 	if (evcon)
1118 		evhttp_connection_free(evcon);
1119 	if (http)
1120 		evhttp_free(http);
1121 }
1122 
1123 static void
http_request_done(struct evhttp_request * req,void * arg)1124 http_request_done(struct evhttp_request *req, void *arg)
1125 {
1126 	const char *what = arg;
1127 
1128 	if (evhttp_request_get_response_code(req) != HTTP_OK) {
1129 		fprintf(stderr, "FAILED\n");
1130 		exit(1);
1131 	}
1132 
1133 	if (evhttp_find_header(evhttp_request_get_input_headers(req), "Content-Type") == NULL) {
1134 		fprintf(stderr, "FAILED\n");
1135 		exit(1);
1136 	}
1137 
1138 	if (evbuffer_get_length(evhttp_request_get_input_buffer(req)) != strlen(what)) {
1139 		fprintf(stderr, "FAILED\n");
1140 		exit(1);
1141 	}
1142 
1143 	if (evbuffer_datacmp(evhttp_request_get_input_buffer(req), what) != 0) {
1144 		fprintf(stderr, "FAILED\n");
1145 		exit(1);
1146 	}
1147 
1148 	test_ok = 1;
1149 	EVUTIL_ASSERT(exit_base);
1150 	event_base_loopexit(exit_base, NULL);
1151 }
1152 
1153 static void
http_request_expect_error(struct evhttp_request * req,void * arg)1154 http_request_expect_error(struct evhttp_request *req, void *arg)
1155 {
1156 	if (evhttp_request_get_response_code(req) == HTTP_OK) {
1157 		fprintf(stderr, "FAILED\n");
1158 		exit(1);
1159 	}
1160 
1161 	test_ok = 1;
1162 	EVUTIL_ASSERT(arg);
1163 	event_base_loopexit(arg, NULL);
1164 }
1165 
1166 /* test virtual hosts */
1167 static void
http_virtual_host_test(void * arg)1168 http_virtual_host_test(void *arg)
1169 {
1170 	struct basic_test_data *data = arg;
1171 	ev_uint16_t port = 0;
1172 	struct evhttp_connection *evcon = NULL;
1173 	struct evhttp_request *req = NULL;
1174 	struct evhttp *second = NULL, *third = NULL;
1175 	evutil_socket_t fd;
1176 	struct bufferevent *bev;
1177 	const char *http_request;
1178 
1179 	exit_base = data->base;
1180 
1181 	http = http_setup(&port, data->base);
1182 
1183 	/* virtual host */
1184 	second = evhttp_new(NULL);
1185 	evhttp_set_cb(second, "/funnybunny", http_basic_cb, NULL);
1186 	third = evhttp_new(NULL);
1187 	evhttp_set_cb(third, "/blackcoffee", http_basic_cb, NULL);
1188 
1189 	if (evhttp_add_virtual_host(http, "foo.com", second) == -1) {
1190 		tt_abort_msg("Couldn't add vhost");
1191 	}
1192 
1193 	if (evhttp_add_virtual_host(http, "bar.*.foo.com", third) == -1) {
1194 		tt_abort_msg("Couldn't add wildcarded vhost");
1195 	}
1196 
1197 	/* add some aliases to the vhosts */
1198 	tt_assert(evhttp_add_server_alias(second, "manolito.info") == 0);
1199 	tt_assert(evhttp_add_server_alias(third, "bonkers.org") == 0);
1200 
1201 	evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port);
1202 	tt_assert(evcon);
1203 
1204 	/* make a request with a different host and expect an error */
1205 	req = evhttp_request_new(http_request_expect_error, data->base);
1206 
1207 	/* Add the information that we care about */
1208 	evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
1209 
1210 	/* We give ownership of the request to the connection */
1211 	if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET,
1212 		"/funnybunny") == -1) {
1213 		tt_abort_msg("Couldn't make request");
1214 	}
1215 
1216 	event_base_dispatch(data->base);
1217 
1218 	tt_assert(test_ok == 1);
1219 
1220 	test_ok = 0;
1221 
1222 	/* make a request with the right host and expect a response */
1223 	req = evhttp_request_new(http_request_done, basic_request_body);
1224 
1225 	/* Add the information that we care about */
1226 	evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "foo.com");
1227 
1228 	/* We give ownership of the request to the connection */
1229 	if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET,
1230 		"/funnybunny") == -1) {
1231 		fprintf(stdout, "FAILED\n");
1232 		exit(1);
1233 	}
1234 
1235 	event_base_dispatch(data->base);
1236 
1237 	tt_assert(test_ok == 1);
1238 
1239 	test_ok = 0;
1240 
1241 	/* make a request with the right host and expect a response */
1242 	req = evhttp_request_new(http_request_done, basic_request_body);
1243 
1244 	/* Add the information that we care about */
1245 	evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "bar.magic.foo.com");
1246 
1247 	/* We give ownership of the request to the connection */
1248 	if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET,
1249 		"/blackcoffee") == -1) {
1250 		tt_abort_msg("Couldn't make request");
1251 	}
1252 
1253 	event_base_dispatch(data->base);
1254 
1255 	tt_assert(test_ok == 1)
1256 
1257 	test_ok = 0;
1258 
1259 	/* make a request with the right host and expect a response */
1260 	req = evhttp_request_new(http_request_done, basic_request_body);
1261 
1262 	/* Add the information that we care about */
1263 	evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "manolito.info");
1264 
1265 	/* We give ownership of the request to the connection */
1266 	if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET,
1267 		"/funnybunny") == -1) {
1268 		tt_abort_msg("Couldn't make request");
1269 	}
1270 
1271 	event_base_dispatch(data->base);
1272 
1273 	tt_assert(test_ok == 1)
1274 
1275 	test_ok = 0;
1276 
1277 	/* make a request with the right host and expect a response */
1278 	req = evhttp_request_new(http_request_done, basic_request_body);
1279 
1280 	/* Add the Host header. This time with the optional port. */
1281 	evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "bonkers.org:8000");
1282 
1283 	/* We give ownership of the request to the connection */
1284 	if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET,
1285 		"/blackcoffee") == -1) {
1286 		tt_abort_msg("Couldn't make request");
1287 	}
1288 
1289 	event_base_dispatch(data->base);
1290 
1291 	tt_assert(test_ok == 1)
1292 
1293 	test_ok = 0;
1294 
1295 	/* Now make a raw request with an absolute URI. */
1296 	fd = http_connect("127.0.0.1", port);
1297 
1298 	/* Stupid thing to send a request */
1299 	bev = bufferevent_socket_new(data->base, fd, 0);
1300 	bufferevent_setcb(bev, http_readcb, http_writecb,
1301 	    http_errorcb, NULL);
1302 
1303 	/* The host in the URI should override the Host: header */
1304 	http_request =
1305 	    "GET http://manolito.info/funnybunny HTTP/1.1\r\n"
1306 	    "Host: somehost\r\n"
1307 	    "Connection: close\r\n"
1308 	    "\r\n";
1309 
1310 	bufferevent_write(bev, http_request, strlen(http_request));
1311 
1312 	event_base_dispatch(data->base);
1313 
1314 	tt_int_op(test_ok, ==, 2);
1315 
1316 	bufferevent_free(bev);
1317 	evutil_closesocket(fd);
1318 
1319  end:
1320 	if (evcon)
1321 		evhttp_connection_free(evcon);
1322 	if (http)
1323 		evhttp_free(http);
1324 }
1325 
1326 
1327 /* test date header and content length */
1328 
1329 static void
http_request_empty_done(struct evhttp_request * req,void * arg)1330 http_request_empty_done(struct evhttp_request *req, void *arg)
1331 {
1332 	if (evhttp_request_get_response_code(req) != HTTP_OK) {
1333 		fprintf(stderr, "FAILED\n");
1334 		exit(1);
1335 	}
1336 
1337 	if (evhttp_find_header(evhttp_request_get_input_headers(req), "Date") == NULL) {
1338 		fprintf(stderr, "FAILED\n");
1339 		exit(1);
1340 	}
1341 
1342 
1343 	if (evhttp_find_header(evhttp_request_get_input_headers(req), "Content-Length") == NULL) {
1344 		fprintf(stderr, "FAILED\n");
1345 		exit(1);
1346 	}
1347 
1348 	if (strcmp(evhttp_find_header(evhttp_request_get_input_headers(req), "Content-Length"),
1349 		"0")) {
1350 		fprintf(stderr, "FAILED\n");
1351 		exit(1);
1352 	}
1353 
1354 	if (evbuffer_get_length(evhttp_request_get_input_buffer(req)) != 0) {
1355 		fprintf(stderr, "FAILED\n");
1356 		exit(1);
1357 	}
1358 
1359 	test_ok = 1;
1360 	EVUTIL_ASSERT(arg);
1361 	event_base_loopexit(arg, NULL);
1362 }
1363 
1364 /*
1365  * HTTP DISPATCHER test
1366  */
1367 
1368 void
http_dispatcher_cb(struct evhttp_request * req,void * arg)1369 http_dispatcher_cb(struct evhttp_request *req, void *arg)
1370 {
1371 
1372 	struct evbuffer *evb = evbuffer_new();
1373 	event_debug(("%s: called\n", __func__));
1374 	evbuffer_add_printf(evb, "DISPATCHER_TEST");
1375 
1376 	evhttp_send_reply(req, HTTP_OK, "Everything is fine", evb);
1377 
1378 	evbuffer_free(evb);
1379 }
1380 
1381 static void
http_dispatcher_test_done(struct evhttp_request * req,void * arg)1382 http_dispatcher_test_done(struct evhttp_request *req, void *arg)
1383 {
1384 	struct event_base *base = arg;
1385 	const char *what = "DISPATCHER_TEST";
1386 
1387 	if (evhttp_request_get_response_code(req) != HTTP_OK) {
1388 		fprintf(stderr, "FAILED\n");
1389 		exit(1);
1390 	}
1391 
1392 	if (evhttp_find_header(evhttp_request_get_input_headers(req), "Content-Type") == NULL) {
1393 		fprintf(stderr, "FAILED (content type)\n");
1394 		exit(1);
1395 	}
1396 
1397 	if (evbuffer_get_length(evhttp_request_get_input_buffer(req)) != strlen(what)) {
1398 		fprintf(stderr, "FAILED (length %lu vs %lu)\n",
1399 		    (unsigned long)evbuffer_get_length(evhttp_request_get_input_buffer(req)), (unsigned long)strlen(what));
1400 		exit(1);
1401 	}
1402 
1403 	if (evbuffer_datacmp(evhttp_request_get_input_buffer(req), what) != 0) {
1404 		fprintf(stderr, "FAILED (data)\n");
1405 		exit(1);
1406 	}
1407 
1408 	test_ok = 1;
1409 	event_base_loopexit(base, NULL);
1410 }
1411 
1412 static void
http_dispatcher_test(void * arg)1413 http_dispatcher_test(void *arg)
1414 {
1415 	struct basic_test_data *data = arg;
1416 	ev_uint16_t port = 0;
1417 	struct evhttp_connection *evcon = NULL;
1418 	struct evhttp_request *req = NULL;
1419 
1420 	test_ok = 0;
1421 
1422 	http = http_setup(&port, data->base);
1423 
1424 	evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port);
1425 	tt_assert(evcon);
1426 
1427 	/* also bind to local host */
1428 	evhttp_connection_set_local_address(evcon, "127.0.0.1");
1429 
1430 	/*
1431 	 * At this point, we want to schedule an HTTP GET request
1432 	 * server using our make request method.
1433 	 */
1434 
1435 	req = evhttp_request_new(http_dispatcher_test_done, data->base);
1436 	tt_assert(req);
1437 
1438 	/* Add the information that we care about */
1439 	evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
1440 
1441 	if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/?arg=val") == -1) {
1442 		tt_abort_msg("Couldn't make request");
1443 	}
1444 
1445 	event_base_dispatch(data->base);
1446 
1447  end:
1448 	if (evcon)
1449 		evhttp_connection_free(evcon);
1450 	if (http)
1451 		evhttp_free(http);
1452 }
1453 
1454 /*
1455  * HTTP POST test.
1456  */
1457 
1458 void http_postrequest_done(struct evhttp_request *, void *);
1459 
1460 #define POST_DATA "Okay.  Not really printf"
1461 
1462 static void
http_post_test(void * arg)1463 http_post_test(void *arg)
1464 {
1465 	struct basic_test_data *data = arg;
1466 	ev_uint16_t port = 0;
1467 	struct evhttp_connection *evcon = NULL;
1468 	struct evhttp_request *req = NULL;
1469 
1470 	test_ok = 0;
1471 
1472 	http = http_setup(&port, data->base);
1473 
1474 	evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port);
1475 	tt_assert(evcon);
1476 
1477 	/*
1478 	 * At this point, we want to schedule an HTTP POST request
1479 	 * server using our make request method.
1480 	 */
1481 
1482 	req = evhttp_request_new(http_postrequest_done, data->base);
1483 	tt_assert(req);
1484 
1485 	/* Add the information that we care about */
1486 	evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
1487 	evbuffer_add_printf(evhttp_request_get_output_buffer(req), POST_DATA);
1488 
1489 	if (evhttp_make_request(evcon, req, EVHTTP_REQ_POST, "/postit") == -1) {
1490 		tt_abort_msg("Couldn't make request");
1491 	}
1492 
1493 	event_base_dispatch(data->base);
1494 
1495 	tt_int_op(test_ok, ==, 1);
1496 
1497 	test_ok = 0;
1498 
1499 	req = evhttp_request_new(http_postrequest_done, data->base);
1500 	tt_assert(req);
1501 
1502 	/* Now try with 100-continue. */
1503 
1504 	/* Add the information that we care about */
1505 	evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
1506 	evhttp_add_header(evhttp_request_get_output_headers(req), "Expect", "100-continue");
1507 	evbuffer_add_printf(evhttp_request_get_output_buffer(req), POST_DATA);
1508 
1509 	if (evhttp_make_request(evcon, req, EVHTTP_REQ_POST, "/postit") == -1) {
1510 		tt_abort_msg("Couldn't make request");
1511 	}
1512 
1513 	event_base_dispatch(data->base);
1514 
1515 	tt_int_op(test_ok, ==, 1);
1516 
1517 	evhttp_connection_free(evcon);
1518 	evhttp_free(http);
1519 
1520  end:
1521 	;
1522 }
1523 
1524 void
http_post_cb(struct evhttp_request * req,void * arg)1525 http_post_cb(struct evhttp_request *req, void *arg)
1526 {
1527 	struct evbuffer *evb;
1528 	event_debug(("%s: called\n", __func__));
1529 
1530 	/* Yes, we are expecting a post request */
1531 	if (evhttp_request_get_command(req) != EVHTTP_REQ_POST) {
1532 		fprintf(stdout, "FAILED (post type)\n");
1533 		exit(1);
1534 	}
1535 
1536 	if (evbuffer_get_length(evhttp_request_get_input_buffer(req)) != strlen(POST_DATA)) {
1537 		fprintf(stdout, "FAILED (length: %lu vs %lu)\n",
1538 		    (unsigned long) evbuffer_get_length(evhttp_request_get_input_buffer(req)), (unsigned long) strlen(POST_DATA));
1539 		exit(1);
1540 	}
1541 
1542 	if (evbuffer_datacmp(evhttp_request_get_input_buffer(req), POST_DATA) != 0) {
1543 		fprintf(stdout, "FAILED (data)\n");
1544 		fprintf(stdout, "Got :%s\n", evbuffer_pullup(evhttp_request_get_input_buffer(req),-1));
1545 		fprintf(stdout, "Want:%s\n", POST_DATA);
1546 		exit(1);
1547 	}
1548 
1549 	evb = evbuffer_new();
1550 	evbuffer_add_printf(evb, BASIC_REQUEST_BODY);
1551 
1552 	evhttp_send_reply(req, HTTP_OK, "Everything is fine", evb);
1553 
1554 	evbuffer_free(evb);
1555 }
1556 
1557 void
http_postrequest_done(struct evhttp_request * req,void * arg)1558 http_postrequest_done(struct evhttp_request *req, void *arg)
1559 {
1560 	const char *what = BASIC_REQUEST_BODY;
1561 	struct event_base *base = arg;
1562 
1563 	if (req == NULL) {
1564 		fprintf(stderr, "FAILED (timeout)\n");
1565 		exit(1);
1566 	}
1567 
1568 	if (evhttp_request_get_response_code(req) != HTTP_OK) {
1569 
1570 		fprintf(stderr, "FAILED (response code)\n");
1571 		exit(1);
1572 	}
1573 
1574 	if (evhttp_find_header(evhttp_request_get_input_headers(req), "Content-Type") == NULL) {
1575 		fprintf(stderr, "FAILED (content type)\n");
1576 		exit(1);
1577 	}
1578 
1579 	if (evbuffer_get_length(evhttp_request_get_input_buffer(req)) != strlen(what)) {
1580 		fprintf(stderr, "FAILED (length %lu vs %lu)\n",
1581 		    (unsigned long)evbuffer_get_length(evhttp_request_get_input_buffer(req)), (unsigned long)strlen(what));
1582 		exit(1);
1583 	}
1584 
1585 	if (evbuffer_datacmp(evhttp_request_get_input_buffer(req), what) != 0) {
1586 		fprintf(stderr, "FAILED (data)\n");
1587 		exit(1);
1588 	}
1589 
1590 	test_ok = 1;
1591 	event_base_loopexit(base, NULL);
1592 }
1593 
1594 /*
1595  * HTTP PUT test, basically just like POST, but ...
1596  */
1597 
1598 void http_putrequest_done(struct evhttp_request *, void *);
1599 
1600 #define PUT_DATA "Hi, I'm some PUT data"
1601 
1602 static void
http_put_test(void * arg)1603 http_put_test(void *arg)
1604 {
1605 	struct basic_test_data *data = arg;
1606 	ev_uint16_t port = 0;
1607 	struct evhttp_connection *evcon = NULL;
1608 	struct evhttp_request *req = NULL;
1609 
1610 	test_ok = 0;
1611 
1612 	http = http_setup(&port, data->base);
1613 
1614 	evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port);
1615 	tt_assert(evcon);
1616 
1617 	/*
1618 	 * Schedule the HTTP PUT request
1619 	 */
1620 
1621 	req = evhttp_request_new(http_putrequest_done, data->base);
1622 	tt_assert(req);
1623 
1624 	/* Add the information that we care about */
1625 	evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "someotherhost");
1626 	evbuffer_add_printf(evhttp_request_get_output_buffer(req), PUT_DATA);
1627 
1628 	if (evhttp_make_request(evcon, req, EVHTTP_REQ_PUT, "/putit") == -1) {
1629 		tt_abort_msg("Couldn't make request");
1630 	}
1631 
1632 	event_base_dispatch(data->base);
1633 
1634 	evhttp_connection_free(evcon);
1635 	evhttp_free(http);
1636 
1637 	tt_int_op(test_ok, ==, 1);
1638  end:
1639 	;
1640 }
1641 
1642 void
http_put_cb(struct evhttp_request * req,void * arg)1643 http_put_cb(struct evhttp_request *req, void *arg)
1644 {
1645 	struct evbuffer *evb;
1646 	event_debug(("%s: called\n", __func__));
1647 
1648 	/* Expecting a PUT request */
1649 	if (evhttp_request_get_command(req) != EVHTTP_REQ_PUT) {
1650 		fprintf(stdout, "FAILED (put type)\n");
1651 		exit(1);
1652 	}
1653 
1654 	if (evbuffer_get_length(evhttp_request_get_input_buffer(req)) != strlen(PUT_DATA)) {
1655 		fprintf(stdout, "FAILED (length: %lu vs %lu)\n",
1656 		    (unsigned long)evbuffer_get_length(evhttp_request_get_input_buffer(req)), (unsigned long)strlen(PUT_DATA));
1657 		exit(1);
1658 	}
1659 
1660 	if (evbuffer_datacmp(evhttp_request_get_input_buffer(req), PUT_DATA) != 0) {
1661 		fprintf(stdout, "FAILED (data)\n");
1662 		fprintf(stdout, "Got :%s\n", evbuffer_pullup(evhttp_request_get_input_buffer(req),-1));
1663 		fprintf(stdout, "Want:%s\n", PUT_DATA);
1664 		exit(1);
1665 	}
1666 
1667 	evb = evbuffer_new();
1668 	evbuffer_add_printf(evb, "That ain't funny");
1669 
1670 	evhttp_send_reply(req, HTTP_OK, "Everything is great", evb);
1671 
1672 	evbuffer_free(evb);
1673 }
1674 
1675 void
http_putrequest_done(struct evhttp_request * req,void * arg)1676 http_putrequest_done(struct evhttp_request *req, void *arg)
1677 {
1678 	struct event_base *base = arg;
1679 	const char *what = "That ain't funny";
1680 
1681 	if (req == NULL) {
1682 		fprintf(stderr, "FAILED (timeout)\n");
1683 		exit(1);
1684 	}
1685 
1686 	if (evhttp_request_get_response_code(req) != HTTP_OK) {
1687 
1688 		fprintf(stderr, "FAILED (response code)\n");
1689 		exit(1);
1690 	}
1691 
1692 	if (evhttp_find_header(evhttp_request_get_input_headers(req), "Content-Type") == NULL) {
1693 		fprintf(stderr, "FAILED (content type)\n");
1694 		exit(1);
1695 	}
1696 
1697 	if (evbuffer_get_length(evhttp_request_get_input_buffer(req)) != strlen(what)) {
1698 		fprintf(stderr, "FAILED (length %lu vs %lu)\n",
1699 		    (unsigned long)evbuffer_get_length(evhttp_request_get_input_buffer(req)), (unsigned long)strlen(what));
1700 		exit(1);
1701 	}
1702 
1703 
1704 	if (evbuffer_datacmp(evhttp_request_get_input_buffer(req), what) != 0) {
1705 		fprintf(stderr, "FAILED (data)\n");
1706 		exit(1);
1707 	}
1708 
1709 	test_ok = 1;
1710 	event_base_loopexit(base, NULL);
1711 }
1712 
1713 static void
http_failure_readcb(struct bufferevent * bev,void * arg)1714 http_failure_readcb(struct bufferevent *bev, void *arg)
1715 {
1716 	const char *what = "400 Bad Request";
1717 	if (evbuffer_contains(bufferevent_get_input(bev), what)) {
1718 		test_ok = 2;
1719 		bufferevent_disable(bev, EV_READ);
1720 		event_base_loopexit(arg, NULL);
1721 	}
1722 }
1723 
1724 /*
1725  * Testing that the HTTP server can deal with a malformed request.
1726  */
1727 static void
http_failure_test(void * arg)1728 http_failure_test(void *arg)
1729 {
1730 	struct basic_test_data *data = arg;
1731 	struct bufferevent *bev;
1732 	evutil_socket_t fd;
1733 	const char *http_request;
1734 	ev_uint16_t port = 0;
1735 
1736 	test_ok = 0;
1737 
1738 	http = http_setup(&port, data->base);
1739 
1740 	fd = http_connect("127.0.0.1", port);
1741 
1742 	/* Stupid thing to send a request */
1743 	bev = bufferevent_socket_new(data->base, fd, 0);
1744 	bufferevent_setcb(bev, http_failure_readcb, http_writecb,
1745 	    http_errorcb, data->base);
1746 
1747 	http_request = "illegal request\r\n";
1748 
1749 	bufferevent_write(bev, http_request, strlen(http_request));
1750 
1751 	event_base_dispatch(data->base);
1752 
1753 	bufferevent_free(bev);
1754 	evutil_closesocket(fd);
1755 
1756 	evhttp_free(http);
1757 
1758 	tt_int_op(test_ok, ==, 2);
1759  end:
1760 	;
1761 }
1762 
1763 static void
close_detect_done(struct evhttp_request * req,void * arg)1764 close_detect_done(struct evhttp_request *req, void *arg)
1765 {
1766 	struct timeval tv;
1767 	tt_assert(req);
1768 	tt_assert(evhttp_request_get_response_code(req) == HTTP_OK);
1769 
1770 	test_ok = 1;
1771 
1772  end:
1773 	evutil_timerclear(&tv);
1774 	tv.tv_sec = 3;
1775 	event_base_loopexit(arg, &tv);
1776 }
1777 
1778 static void
close_detect_launch(evutil_socket_t fd,short what,void * arg)1779 close_detect_launch(evutil_socket_t fd, short what, void *arg)
1780 {
1781 	struct evhttp_connection *evcon = arg;
1782 	struct event_base *base = evhttp_connection_get_base(evcon);
1783 	struct evhttp_request *req;
1784 
1785 	req = evhttp_request_new(close_detect_done, base);
1786 
1787 	/* Add the information that we care about */
1788 	evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
1789 
1790 	/* We give ownership of the request to the connection */
1791 	if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test") == -1) {
1792 		tt_fail_msg("Couldn't make request");
1793 	}
1794 }
1795 
1796 static void
close_detect_cb(struct evhttp_request * req,void * arg)1797 close_detect_cb(struct evhttp_request *req, void *arg)
1798 {
1799 	struct evhttp_connection *evcon = arg;
1800 	struct event_base *base = evhttp_connection_get_base(evcon);
1801 	struct timeval tv;
1802 
1803 	if (req != NULL && evhttp_request_get_response_code(req) != HTTP_OK) {
1804 		tt_abort_msg("Failed");
1805 	}
1806 
1807 	evutil_timerclear(&tv);
1808 	tv.tv_sec = 3;   /* longer than the http time out */
1809 
1810 	/* launch a new request on the persistent connection in 3 seconds */
1811 	event_base_once(base, -1, EV_TIMEOUT, close_detect_launch, evcon, &tv);
1812  end:
1813 	;
1814 }
1815 
1816 
1817 static void
_http_close_detection(struct basic_test_data * data,int with_delay)1818 _http_close_detection(struct basic_test_data *data, int with_delay)
1819 {
1820 	ev_uint16_t port = 0;
1821 	struct evhttp_connection *evcon = NULL;
1822 	struct evhttp_request *req = NULL;
1823 
1824 	test_ok = 0;
1825 	http = http_setup(&port, data->base);
1826 
1827 	/* 2 second timeout */
1828 	evhttp_set_timeout(http, 1);
1829 
1830 	evcon = evhttp_connection_base_new(data->base, NULL,
1831 	    "127.0.0.1", port);
1832 	tt_assert(evcon);
1833 	delayed_client = evcon;
1834 
1835 	/*
1836 	 * At this point, we want to schedule a request to the HTTP
1837 	 * server using our make request method.
1838 	 */
1839 
1840 	req = evhttp_request_new(close_detect_cb, evcon);
1841 
1842 	/* Add the information that we care about */
1843 	evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
1844 
1845 	/* We give ownership of the request to the connection */
1846 	if (evhttp_make_request(evcon,
1847 	    req, EVHTTP_REQ_GET, with_delay ? "/largedelay" : "/test") == -1) {
1848 		tt_abort_msg("couldn't make request");
1849 	}
1850 
1851 	event_base_dispatch(data->base);
1852 
1853 	/* at this point, the http server should have no connection */
1854 	tt_assert(TAILQ_FIRST(&http->connections) == NULL);
1855 
1856  end:
1857 	if (evcon)
1858 		evhttp_connection_free(evcon);
1859 	if (http)
1860 		evhttp_free(http);
1861 }
1862 static void
http_close_detection_test(void * arg)1863 http_close_detection_test(void *arg)
1864 {
1865 	_http_close_detection(arg, 0);
1866 }
1867 static void
http_close_detection_delay_test(void * arg)1868 http_close_detection_delay_test(void *arg)
1869 {
1870 	_http_close_detection(arg, 1);
1871 }
1872 
1873 static void
http_highport_test(void * arg)1874 http_highport_test(void *arg)
1875 {
1876 	struct basic_test_data *data = arg;
1877 	int i = -1;
1878 	struct evhttp *myhttp = NULL;
1879 
1880 	/* Try a few different ports */
1881 	for (i = 0; i < 50; ++i) {
1882 		myhttp = evhttp_new(data->base);
1883 		if (evhttp_bind_socket(myhttp, "127.0.0.1", 65535 - i) == 0) {
1884 			test_ok = 1;
1885 			evhttp_free(myhttp);
1886 			return;
1887 		}
1888 		evhttp_free(myhttp);
1889 	}
1890 
1891 	tt_fail_msg("Couldn't get a high port");
1892 }
1893 
1894 static void
http_bad_header_test(void * ptr)1895 http_bad_header_test(void *ptr)
1896 {
1897 	struct evkeyvalq headers;
1898 
1899 	TAILQ_INIT(&headers);
1900 
1901 	tt_want(evhttp_add_header(&headers, "One", "Two") == 0);
1902 	tt_want(evhttp_add_header(&headers, "One", "Two\r\n Three") == 0);
1903 	tt_want(evhttp_add_header(&headers, "One\r", "Two") == -1);
1904 	tt_want(evhttp_add_header(&headers, "One\n", "Two") == -1);
1905 	tt_want(evhttp_add_header(&headers, "One", "Two\r") == -1);
1906 	tt_want(evhttp_add_header(&headers, "One", "Two\n") == -1);
1907 
1908 	evhttp_clear_headers(&headers);
1909 }
1910 
validate_header(const struct evkeyvalq * headers,const char * key,const char * value)1911 static int validate_header(
1912 	const struct evkeyvalq* headers,
1913 	const char *key, const char *value)
1914 {
1915 	const char *real_val = evhttp_find_header(headers, key);
1916 	tt_assert(real_val != NULL);
1917 	tt_want(strcmp(real_val, value) == 0);
1918 end:
1919 	return (0);
1920 }
1921 
1922 static void
http_parse_query_test(void * ptr)1923 http_parse_query_test(void *ptr)
1924 {
1925 	struct evkeyvalq headers;
1926 	int r;
1927 
1928 	TAILQ_INIT(&headers);
1929 
1930 	r = evhttp_parse_query("http://www.test.com/?q=test", &headers);
1931 	tt_want(validate_header(&headers, "q", "test") == 0);
1932 	tt_int_op(r, ==, 0);
1933 	evhttp_clear_headers(&headers);
1934 
1935 	r = evhttp_parse_query("http://www.test.com/?q=test&foo=bar", &headers);
1936 	tt_want(validate_header(&headers, "q", "test") == 0);
1937 	tt_want(validate_header(&headers, "foo", "bar") == 0);
1938 	tt_int_op(r, ==, 0);
1939 	evhttp_clear_headers(&headers);
1940 
1941 	r = evhttp_parse_query("http://www.test.com/?q=test+foo", &headers);
1942 	tt_want(validate_header(&headers, "q", "test foo") == 0);
1943 	tt_int_op(r, ==, 0);
1944 	evhttp_clear_headers(&headers);
1945 
1946 	r = evhttp_parse_query("http://www.test.com/?q=test%0Afoo", &headers);
1947 	tt_want(validate_header(&headers, "q", "test\nfoo") == 0);
1948 	tt_int_op(r, ==, 0);
1949 	evhttp_clear_headers(&headers);
1950 
1951 	r = evhttp_parse_query("http://www.test.com/?q=test%0Dfoo", &headers);
1952 	tt_want(validate_header(&headers, "q", "test\rfoo") == 0);
1953 	tt_int_op(r, ==, 0);
1954 	evhttp_clear_headers(&headers);
1955 
1956 	r = evhttp_parse_query("http://www.test.com/?q=test&&q2", &headers);
1957 	tt_int_op(r, ==, -1);
1958 	evhttp_clear_headers(&headers);
1959 
1960 	r = evhttp_parse_query("http://www.test.com/?q=test+this", &headers);
1961 	tt_want(validate_header(&headers, "q", "test this") == 0);
1962 	tt_int_op(r, ==, 0);
1963 	evhttp_clear_headers(&headers);
1964 
1965 	r = evhttp_parse_query("http://www.test.com/?q=test&q2=foo", &headers);
1966 	tt_int_op(r, ==, 0);
1967 	tt_want(validate_header(&headers, "q", "test") == 0);
1968 	tt_want(validate_header(&headers, "q2", "foo") == 0);
1969 	evhttp_clear_headers(&headers);
1970 
1971 	r = evhttp_parse_query("http://www.test.com/?q&q2=foo", &headers);
1972 	tt_int_op(r, ==, -1);
1973 	evhttp_clear_headers(&headers);
1974 
1975 	r = evhttp_parse_query("http://www.test.com/?q=foo&q2", &headers);
1976 	tt_int_op(r, ==, -1);
1977 	evhttp_clear_headers(&headers);
1978 
1979 	r = evhttp_parse_query("http://www.test.com/?q=foo&q2&q3=x", &headers);
1980 	tt_int_op(r, ==, -1);
1981 	evhttp_clear_headers(&headers);
1982 
1983 	r = evhttp_parse_query("http://www.test.com/?q=&q2=&q3=", &headers);
1984 	tt_int_op(r, ==, 0);
1985 	tt_want(validate_header(&headers, "q", "") == 0);
1986 	tt_want(validate_header(&headers, "q2", "") == 0);
1987 	tt_want(validate_header(&headers, "q3", "") == 0);
1988 	evhttp_clear_headers(&headers);
1989 
1990 end:
1991 	evhttp_clear_headers(&headers);
1992 }
1993 
1994 static void
http_parse_uri_test(void * ptr)1995 http_parse_uri_test(void *ptr)
1996 {
1997 	const int nonconform = (ptr != NULL);
1998 	const unsigned parse_flags =
1999 	    nonconform ? EVHTTP_URI_NONCONFORMANT : 0;
2000 	struct evhttp_uri *uri = NULL;
2001 	char url_tmp[4096];
2002 #define URI_PARSE(uri) \
2003 	evhttp_uri_parse_with_flags((uri), parse_flags)
2004 
2005 #define TT_URI(want) do { 						\
2006 	char *ret = evhttp_uri_join(uri, url_tmp, sizeof(url_tmp));	\
2007 	tt_want(ret != NULL);						\
2008 	tt_want(ret == url_tmp);					\
2009 	if (strcmp(ret,want) != 0)					\
2010 		TT_FAIL(("\"%s\" != \"%s\"",ret,want));			\
2011 	} while(/*CONSTCOND*/0)
2012 
2013 	tt_want(evhttp_uri_join(NULL, 0, 0) == NULL);
2014 	tt_want(evhttp_uri_join(NULL, url_tmp, 0) == NULL);
2015 	tt_want(evhttp_uri_join(NULL, url_tmp, sizeof(url_tmp)) == NULL);
2016 
2017 	/* bad URIs: parsing */
2018 #define BAD(s) do {							\
2019 		if (URI_PARSE(s) != NULL)				\
2020 			TT_FAIL(("Expected error parsing \"%s\"",s));	\
2021 	} while(/*CONSTCOND*/0)
2022 	/* Nonconformant URIs we can parse: parsing */
2023 #define NCF(s) do {							\
2024 		uri = URI_PARSE(s);					\
2025 		if (uri != NULL && !nonconform) {			\
2026 			TT_FAIL(("Expected error parsing \"%s\"",s));	\
2027 		} else if (uri == NULL && nonconform) {			\
2028 			TT_FAIL(("Couldn't parse nonconformant URI \"%s\"", \
2029 				s));					\
2030 		}							\
2031 		if (uri) {						\
2032 			tt_want(evhttp_uri_join(uri, url_tmp,		\
2033 				sizeof(url_tmp)));			\
2034 			evhttp_uri_free(uri);				\
2035 		}							\
2036 	} while(/*CONSTCOND*/0)
2037 
2038 	NCF("http://www.test.com/ why hello");
2039 	NCF("http://www.test.com/why-hello\x01");
2040 	NCF("http://www.test.com/why-hello?\x01");
2041 	NCF("http://www.test.com/why-hello#\x01");
2042 	BAD("http://www.\x01.test.com/why-hello");
2043 	BAD("http://www.%7test.com/why-hello");
2044 	NCF("http://www.test.com/why-hell%7o");
2045 	BAD("h%3ttp://www.test.com/why-hello");
2046 	NCF("http://www.test.com/why-hello%7");
2047 	NCF("http://www.test.com/why-hell%7o");
2048 	NCF("http://www.test.com/foo?ba%r");
2049 	NCF("http://www.test.com/foo#ba%r");
2050 	BAD("99:99/foo");
2051 	BAD("http://www.test.com:999x/");
2052 	BAD("http://www.test.com:x/");
2053 	BAD("http://[hello-there]/");
2054 	BAD("http://[::1]]/");
2055 	BAD("http://[::1/");
2056 	BAD("http://[foob/");
2057 	BAD("http://[/");
2058 	BAD("http://[ffff:ffff:ffff:ffff:Ffff:ffff:ffff:"
2059 	            "ffff:ffff:ffff:ffff:ffff:ffff:ffff]/");
2060 	BAD("http://[vX.foo]/");
2061 	BAD("http://[vX.foo]/");
2062 	BAD("http://[v.foo]/");
2063 	BAD("http://[v5.fo%o]/");
2064 	BAD("http://[v5X]/");
2065 	BAD("http://[v5]/");
2066 	BAD("http://[]/");
2067 	BAD("http://f\x01red@www.example.com/");
2068 	BAD("http://f%0red@www.example.com/");
2069 	BAD("http://www.example.com:9999999999999999999999999999999999999/");
2070 	BAD("http://www.example.com:hihi/");
2071 	BAD("://www.example.com/");
2072 
2073 	/* bad URIs: joining */
2074 	uri = evhttp_uri_new();
2075 	tt_want(0==evhttp_uri_set_host(uri, "www.example.com"));
2076 	tt_want(evhttp_uri_join(uri, url_tmp, sizeof(url_tmp)) != NULL);
2077 	/* not enough space: */
2078 	tt_want(evhttp_uri_join(uri, url_tmp, 3) == NULL);
2079 	/* host is set, but path doesn't start with "/": */
2080 	tt_want(0==evhttp_uri_set_path(uri, "hi_mom"));
2081 	tt_want(evhttp_uri_join(uri, url_tmp, sizeof(url_tmp)) == NULL);
2082 	tt_want(evhttp_uri_join(uri, NULL, sizeof(url_tmp))==NULL);
2083 	tt_want(evhttp_uri_join(uri, url_tmp, 0)==NULL);
2084 	evhttp_uri_free(uri);
2085 	uri = URI_PARSE("mailto:foo@bar");
2086 	tt_want(uri != NULL);
2087 	tt_want(evhttp_uri_get_host(uri) == NULL);
2088 	tt_want(evhttp_uri_get_userinfo(uri) == NULL);
2089 	tt_want(evhttp_uri_get_port(uri) == -1);
2090 	tt_want(!strcmp(evhttp_uri_get_scheme(uri), "mailto"));
2091 	tt_want(!strcmp(evhttp_uri_get_path(uri), "foo@bar"));
2092 	tt_want(evhttp_uri_get_query(uri) == NULL);
2093 	tt_want(evhttp_uri_get_fragment(uri) == NULL);
2094 	TT_URI("mailto:foo@bar");
2095 	evhttp_uri_free(uri);
2096 
2097 	uri = evhttp_uri_new();
2098 	/* Bad URI usage: setting invalid values */
2099 	tt_want(-1 == evhttp_uri_set_scheme(uri,""));
2100 	tt_want(-1 == evhttp_uri_set_scheme(uri,"33"));
2101 	tt_want(-1 == evhttp_uri_set_scheme(uri,"hi!"));
2102 	tt_want(-1 == evhttp_uri_set_userinfo(uri,"hello@"));
2103 	tt_want(-1 == evhttp_uri_set_host(uri,"[1.2.3.4]"));
2104 	tt_want(-1 == evhttp_uri_set_host(uri,"["));
2105 	tt_want(-1 == evhttp_uri_set_host(uri,"www.[foo].com"));
2106 	tt_want(-1 == evhttp_uri_set_port(uri,-3));
2107 	tt_want(-1 == evhttp_uri_set_path(uri,"hello?world"));
2108 	tt_want(-1 == evhttp_uri_set_query(uri,"hello#world"));
2109 	tt_want(-1 == evhttp_uri_set_fragment(uri,"hello#world"));
2110 	/* Valid URI usage: setting valid values */
2111 	tt_want(0 == evhttp_uri_set_scheme(uri,"http"));
2112 	tt_want(0 == evhttp_uri_set_scheme(uri,NULL));
2113 	tt_want(0 == evhttp_uri_set_userinfo(uri,"username:pass"));
2114 	tt_want(0 == evhttp_uri_set_userinfo(uri,NULL));
2115 	tt_want(0 == evhttp_uri_set_host(uri,"www.example.com"));
2116 	tt_want(0 == evhttp_uri_set_host(uri,"1.2.3.4"));
2117 	tt_want(0 == evhttp_uri_set_host(uri,"[1:2:3:4::]"));
2118 	tt_want(0 == evhttp_uri_set_host(uri,"[v7.wobblewobble]"));
2119 	tt_want(0 == evhttp_uri_set_host(uri,NULL));
2120 	tt_want(0 == evhttp_uri_set_host(uri,""));
2121 	tt_want(0 == evhttp_uri_set_port(uri, -1));
2122 	tt_want(0 == evhttp_uri_set_port(uri, 80));
2123 	tt_want(0 == evhttp_uri_set_port(uri, 65535));
2124 	tt_want(0 == evhttp_uri_set_path(uri, ""));
2125 	tt_want(0 == evhttp_uri_set_path(uri, "/documents/public/index.html"));
2126 	tt_want(0 == evhttp_uri_set_path(uri, NULL));
2127 	tt_want(0 == evhttp_uri_set_query(uri, "key=val&key2=val2"));
2128 	tt_want(0 == evhttp_uri_set_query(uri, "keyvalblarg"));
2129 	tt_want(0 == evhttp_uri_set_query(uri, ""));
2130 	tt_want(0 == evhttp_uri_set_query(uri, NULL));
2131 	tt_want(0 == evhttp_uri_set_fragment(uri, ""));
2132 	tt_want(0 == evhttp_uri_set_fragment(uri, "here?i?am"));
2133 	tt_want(0 == evhttp_uri_set_fragment(uri, NULL));
2134 	evhttp_uri_free(uri);
2135 
2136 	/* Valid parsing */
2137 	uri = URI_PARSE("http://www.test.com/?q=t%33est");
2138 	tt_want(strcmp(evhttp_uri_get_scheme(uri), "http") == 0);
2139 	tt_want(strcmp(evhttp_uri_get_host(uri), "www.test.com") == 0);
2140 	tt_want(strcmp(evhttp_uri_get_path(uri), "/") == 0);
2141 	tt_want(strcmp(evhttp_uri_get_query(uri), "q=t%33est") == 0);
2142 	tt_want(evhttp_uri_get_userinfo(uri) == NULL);
2143 	tt_want(evhttp_uri_get_port(uri) == -1);
2144 	tt_want(evhttp_uri_get_fragment(uri) == NULL);
2145 	TT_URI("http://www.test.com/?q=t%33est");
2146 	evhttp_uri_free(uri);
2147 
2148 	uri = URI_PARSE("http://%77ww.test.com");
2149 	tt_want(strcmp(evhttp_uri_get_scheme(uri), "http") == 0);
2150 	tt_want(strcmp(evhttp_uri_get_host(uri), "%77ww.test.com") == 0);
2151 	tt_want(strcmp(evhttp_uri_get_path(uri), "") == 0);
2152 	tt_want(evhttp_uri_get_query(uri) == NULL);
2153 	tt_want(evhttp_uri_get_userinfo(uri) == NULL);
2154 	tt_want(evhttp_uri_get_port(uri) == -1);
2155 	tt_want(evhttp_uri_get_fragment(uri) == NULL);
2156 	TT_URI("http://%77ww.test.com");
2157 	evhttp_uri_free(uri);
2158 
2159 	uri = URI_PARSE("http://www.test.com?q=test");
2160 	tt_want(strcmp(evhttp_uri_get_scheme(uri), "http") == 0);
2161 	tt_want(strcmp(evhttp_uri_get_host(uri), "www.test.com") == 0);
2162 	tt_want(strcmp(evhttp_uri_get_path(uri), "") == 0);
2163 	tt_want(strcmp(evhttp_uri_get_query(uri), "q=test") == 0);
2164 	tt_want(evhttp_uri_get_userinfo(uri) == NULL);
2165 	tt_want(evhttp_uri_get_port(uri) == -1);
2166 	tt_want(evhttp_uri_get_fragment(uri) == NULL);
2167 	TT_URI("http://www.test.com?q=test");
2168 	evhttp_uri_free(uri);
2169 
2170 	uri = URI_PARSE("http://www.test.com#fragment");
2171 	tt_want(strcmp(evhttp_uri_get_scheme(uri), "http") == 0);
2172 	tt_want(strcmp(evhttp_uri_get_host(uri), "www.test.com") == 0);
2173 	tt_want(strcmp(evhttp_uri_get_path(uri), "") == 0);
2174 	tt_want(evhttp_uri_get_query(uri) == NULL);
2175 	tt_want(evhttp_uri_get_userinfo(uri) == NULL);
2176 	tt_want(evhttp_uri_get_port(uri) == -1);
2177 	tt_want_str_op(evhttp_uri_get_fragment(uri), ==, "fragment");
2178 	TT_URI("http://www.test.com#fragment");
2179 	evhttp_uri_free(uri);
2180 
2181 	uri = URI_PARSE("http://8000/");
2182 	tt_want(strcmp(evhttp_uri_get_scheme(uri), "http") == 0);
2183 	tt_want(strcmp(evhttp_uri_get_host(uri), "8000") == 0);
2184 	tt_want(strcmp(evhttp_uri_get_path(uri), "/") == 0);
2185 	tt_want(evhttp_uri_get_query(uri) == NULL);
2186 	tt_want(evhttp_uri_get_userinfo(uri) == NULL);
2187 	tt_want(evhttp_uri_get_port(uri) == -1);
2188 	tt_want(evhttp_uri_get_fragment(uri) == NULL);
2189 	TT_URI("http://8000/");
2190 	evhttp_uri_free(uri);
2191 
2192 	uri = URI_PARSE("http://:8000/");
2193 	tt_want(strcmp(evhttp_uri_get_scheme(uri), "http") == 0);
2194 	tt_want(strcmp(evhttp_uri_get_host(uri), "") == 0);
2195 	tt_want(strcmp(evhttp_uri_get_path(uri), "/") == 0);
2196 	tt_want(evhttp_uri_get_query(uri) == NULL);
2197 	tt_want(evhttp_uri_get_userinfo(uri) == NULL);
2198 	tt_want(evhttp_uri_get_port(uri) == 8000);
2199 	tt_want(evhttp_uri_get_fragment(uri) == NULL);
2200 	TT_URI("http://:8000/");
2201 	evhttp_uri_free(uri);
2202 
2203 	uri = URI_PARSE("http://www.test.com:/"); /* empty port */
2204 	tt_want(strcmp(evhttp_uri_get_scheme(uri), "http") == 0);
2205 	tt_want(strcmp(evhttp_uri_get_host(uri), "www.test.com") == 0);
2206 	tt_want_str_op(evhttp_uri_get_path(uri), ==, "/");
2207 	tt_want(evhttp_uri_get_query(uri) == NULL);
2208 	tt_want(evhttp_uri_get_userinfo(uri) == NULL);
2209 	tt_want(evhttp_uri_get_port(uri) == -1);
2210 	tt_want(evhttp_uri_get_fragment(uri) == NULL);
2211 	TT_URI("http://www.test.com/");
2212 	evhttp_uri_free(uri);
2213 
2214 	uri = URI_PARSE("http://www.test.com:"); /* empty port 2 */
2215 	tt_want(strcmp(evhttp_uri_get_scheme(uri), "http") == 0);
2216 	tt_want(strcmp(evhttp_uri_get_host(uri), "www.test.com") == 0);
2217 	tt_want(strcmp(evhttp_uri_get_path(uri), "") == 0);
2218 	tt_want(evhttp_uri_get_query(uri) == NULL);
2219 	tt_want(evhttp_uri_get_userinfo(uri) == NULL);
2220 	tt_want(evhttp_uri_get_port(uri) == -1);
2221 	tt_want(evhttp_uri_get_fragment(uri) == NULL);
2222 	TT_URI("http://www.test.com");
2223 	evhttp_uri_free(uri);
2224 
2225 	uri = URI_PARSE("ftp://www.test.com/?q=test");
2226 	tt_want(strcmp(evhttp_uri_get_scheme(uri), "ftp") == 0);
2227 	tt_want(strcmp(evhttp_uri_get_host(uri), "www.test.com") == 0);
2228 	tt_want(strcmp(evhttp_uri_get_path(uri), "/") == 0);
2229 	tt_want(strcmp(evhttp_uri_get_query(uri), "q=test") == 0);
2230 	tt_want(evhttp_uri_get_userinfo(uri) == NULL);
2231 	tt_want(evhttp_uri_get_port(uri) == -1);
2232 	tt_want(evhttp_uri_get_fragment(uri) == NULL);
2233 	TT_URI("ftp://www.test.com/?q=test");
2234 	evhttp_uri_free(uri);
2235 
2236 	uri = URI_PARSE("ftp://[::1]:999/?q=test");
2237 	tt_want(strcmp(evhttp_uri_get_scheme(uri), "ftp") == 0);
2238 	tt_want(strcmp(evhttp_uri_get_host(uri), "[::1]") == 0);
2239 	tt_want(strcmp(evhttp_uri_get_path(uri), "/") == 0);
2240 	tt_want(strcmp(evhttp_uri_get_query(uri), "q=test") == 0);
2241 	tt_want(evhttp_uri_get_userinfo(uri) == NULL);
2242 	tt_want(evhttp_uri_get_port(uri) == 999);
2243 	tt_want(evhttp_uri_get_fragment(uri) == NULL);
2244 	TT_URI("ftp://[::1]:999/?q=test");
2245 	evhttp_uri_free(uri);
2246 
2247 	uri = URI_PARSE("ftp://[ff00::127.0.0.1]/?q=test");
2248 	tt_want(strcmp(evhttp_uri_get_scheme(uri), "ftp") == 0);
2249 	tt_want(strcmp(evhttp_uri_get_host(uri), "[ff00::127.0.0.1]") == 0);
2250 	tt_want(strcmp(evhttp_uri_get_path(uri), "/") == 0);
2251 	tt_want(strcmp(evhttp_uri_get_query(uri), "q=test") == 0);
2252 	tt_want(evhttp_uri_get_userinfo(uri) == NULL);
2253 	tt_want(evhttp_uri_get_port(uri) == -1);
2254 	tt_want(evhttp_uri_get_fragment(uri) == NULL);
2255 	TT_URI("ftp://[ff00::127.0.0.1]/?q=test");
2256 	evhttp_uri_free(uri);
2257 
2258 	uri = URI_PARSE("ftp://[v99.not_(any:time)_soon]/?q=test");
2259 	tt_want(strcmp(evhttp_uri_get_scheme(uri), "ftp") == 0);
2260 	tt_want(strcmp(evhttp_uri_get_host(uri), "[v99.not_(any:time)_soon]") == 0);
2261 	tt_want(strcmp(evhttp_uri_get_path(uri), "/") == 0);
2262 	tt_want(strcmp(evhttp_uri_get_query(uri), "q=test") == 0);
2263 	tt_want(evhttp_uri_get_userinfo(uri) == NULL);
2264 	tt_want(evhttp_uri_get_port(uri) == -1);
2265 	tt_want(evhttp_uri_get_fragment(uri) == NULL);
2266 	TT_URI("ftp://[v99.not_(any:time)_soon]/?q=test");
2267 	evhttp_uri_free(uri);
2268 
2269 	uri = URI_PARSE("scheme://user:pass@foo.com:42/?q=test&s=some+thing#fragment");
2270 	tt_want(strcmp(evhttp_uri_get_scheme(uri), "scheme") == 0);
2271 	tt_want(strcmp(evhttp_uri_get_userinfo(uri), "user:pass") == 0);
2272 	tt_want(strcmp(evhttp_uri_get_host(uri), "foo.com") == 0);
2273 	tt_want(evhttp_uri_get_port(uri) == 42);
2274 	tt_want(strcmp(evhttp_uri_get_path(uri), "/") == 0);
2275 	tt_want(strcmp(evhttp_uri_get_query(uri), "q=test&s=some+thing") == 0);
2276 	tt_want(strcmp(evhttp_uri_get_fragment(uri), "fragment") == 0);
2277 	TT_URI("scheme://user:pass@foo.com:42/?q=test&s=some+thing#fragment");
2278 	evhttp_uri_free(uri);
2279 
2280 	uri = URI_PARSE("scheme://user@foo.com/#fragment");
2281 	tt_want(strcmp(evhttp_uri_get_scheme(uri), "scheme") == 0);
2282 	tt_want(strcmp(evhttp_uri_get_userinfo(uri), "user") == 0);
2283 	tt_want(strcmp(evhttp_uri_get_host(uri), "foo.com") == 0);
2284 	tt_want(evhttp_uri_get_port(uri) == -1);
2285 	tt_want(strcmp(evhttp_uri_get_path(uri), "/") == 0);
2286 	tt_want(evhttp_uri_get_query(uri) == NULL);
2287 	tt_want(strcmp(evhttp_uri_get_fragment(uri), "fragment") == 0);
2288 	TT_URI("scheme://user@foo.com/#fragment");
2289 	evhttp_uri_free(uri);
2290 
2291 	uri = URI_PARSE("scheme://%75ser@foo.com/#frag@ment");
2292 	tt_want(strcmp(evhttp_uri_get_scheme(uri), "scheme") == 0);
2293 	tt_want(strcmp(evhttp_uri_get_userinfo(uri), "%75ser") == 0);
2294 	tt_want(strcmp(evhttp_uri_get_host(uri), "foo.com") == 0);
2295 	tt_want(evhttp_uri_get_port(uri) == -1);
2296 	tt_want(strcmp(evhttp_uri_get_path(uri), "/") == 0);
2297 	tt_want(evhttp_uri_get_query(uri) == NULL);
2298 	tt_want(strcmp(evhttp_uri_get_fragment(uri), "frag@ment") == 0);
2299 	TT_URI("scheme://%75ser@foo.com/#frag@ment");
2300 	evhttp_uri_free(uri);
2301 
2302 	uri = URI_PARSE("file:///some/path/to/the/file");
2303 	tt_want(strcmp(evhttp_uri_get_scheme(uri), "file") == 0);
2304 	tt_want(evhttp_uri_get_userinfo(uri) == NULL);
2305 	tt_want(strcmp(evhttp_uri_get_host(uri), "") == 0);
2306 	tt_want(evhttp_uri_get_port(uri) == -1);
2307 	tt_want(strcmp(evhttp_uri_get_path(uri), "/some/path/to/the/file") == 0);
2308 	tt_want(evhttp_uri_get_query(uri) == NULL);
2309 	tt_want(evhttp_uri_get_fragment(uri) == NULL);
2310 	TT_URI("file:///some/path/to/the/file");
2311 	evhttp_uri_free(uri);
2312 
2313 	uri = URI_PARSE("///some/path/to/the-file");
2314 	tt_want(uri != NULL);
2315 	tt_want(evhttp_uri_get_scheme(uri) == NULL);
2316 	tt_want(evhttp_uri_get_userinfo(uri) == NULL);
2317 	tt_want(strcmp(evhttp_uri_get_host(uri), "") == 0);
2318 	tt_want(evhttp_uri_get_port(uri) == -1);
2319 	tt_want(strcmp(evhttp_uri_get_path(uri), "/some/path/to/the-file") == 0);
2320 	tt_want(evhttp_uri_get_query(uri) == NULL);
2321 	tt_want(evhttp_uri_get_fragment(uri) == NULL);
2322 	TT_URI("///some/path/to/the-file");
2323 	evhttp_uri_free(uri);
2324 
2325 	uri = URI_PARSE("/s:ome/path/to/the-file?q=99#fred");
2326 	tt_want(uri != NULL);
2327 	tt_want(evhttp_uri_get_scheme(uri) == NULL);
2328 	tt_want(evhttp_uri_get_userinfo(uri) == NULL);
2329 	tt_want(evhttp_uri_get_host(uri) == NULL);
2330 	tt_want(evhttp_uri_get_port(uri) == -1);
2331 	tt_want(strcmp(evhttp_uri_get_path(uri), "/s:ome/path/to/the-file") == 0);
2332 	tt_want(strcmp(evhttp_uri_get_query(uri), "q=99") == 0);
2333 	tt_want(strcmp(evhttp_uri_get_fragment(uri), "fred") == 0);
2334 	TT_URI("/s:ome/path/to/the-file?q=99#fred");
2335 	evhttp_uri_free(uri);
2336 
2337 	uri = URI_PARSE("relative/path/with/co:lon");
2338 	tt_want(uri != NULL);
2339 	tt_want(evhttp_uri_get_scheme(uri) == NULL);
2340 	tt_want(evhttp_uri_get_userinfo(uri) == NULL);
2341 	tt_want(evhttp_uri_get_host(uri) == NULL);
2342 	tt_want(evhttp_uri_get_port(uri) == -1);
2343 	tt_want(strcmp(evhttp_uri_get_path(uri), "relative/path/with/co:lon") == 0);
2344 	tt_want(evhttp_uri_get_query(uri) == NULL);
2345 	tt_want(evhttp_uri_get_fragment(uri) == NULL);
2346 	TT_URI("relative/path/with/co:lon");
2347 	evhttp_uri_free(uri);
2348 
2349 	uri = URI_PARSE("bob?q=99&q2=q?33#fr?ed");
2350 	tt_want(uri != NULL);
2351 	tt_want(evhttp_uri_get_scheme(uri) == NULL);
2352 	tt_want(evhttp_uri_get_userinfo(uri) == NULL);
2353 	tt_want(evhttp_uri_get_host(uri) == NULL);
2354 	tt_want(evhttp_uri_get_port(uri) == -1);
2355 	tt_want(strcmp(evhttp_uri_get_path(uri), "bob") == 0);
2356 	tt_want(strcmp(evhttp_uri_get_query(uri), "q=99&q2=q?33") == 0);
2357 	tt_want(strcmp(evhttp_uri_get_fragment(uri), "fr?ed") == 0);
2358 	TT_URI("bob?q=99&q2=q?33#fr?ed");
2359 	evhttp_uri_free(uri);
2360 
2361 	uri = URI_PARSE("#fr?ed");
2362 	tt_want(uri != NULL);
2363 	tt_want(evhttp_uri_get_scheme(uri) == NULL);
2364 	tt_want(evhttp_uri_get_userinfo(uri) == NULL);
2365 	tt_want(evhttp_uri_get_host(uri) == NULL);
2366 	tt_want(evhttp_uri_get_port(uri) == -1);
2367 	tt_want(strcmp(evhttp_uri_get_path(uri), "") == 0);
2368 	tt_want(evhttp_uri_get_query(uri) == NULL);
2369 	tt_want(strcmp(evhttp_uri_get_fragment(uri), "fr?ed") == 0);
2370 	TT_URI("#fr?ed");
2371 	evhttp_uri_free(uri);
2372 #undef URI_PARSE
2373 #undef TT_URI
2374 #undef BAD
2375 }
2376 
2377 static void
http_uriencode_test(void * ptr)2378 http_uriencode_test(void *ptr)
2379 {
2380 	char *s=NULL, *s2=NULL;
2381 	size_t sz;
2382 
2383 #define ENC(from,want,plus) do {				\
2384 		s = evhttp_uriencode((from), -1, (plus));	\
2385 		tt_assert(s);					\
2386 		tt_str_op(s,==,(want));				\
2387 		sz = -1;					\
2388 		s2 = evhttp_uridecode((s), (plus), &sz);	\
2389 		tt_assert(s2);					\
2390 		tt_str_op(s2,==,(from));			\
2391 		tt_int_op(sz,==,strlen(from));			\
2392 		free(s);					\
2393 		free(s2);					\
2394 		s = s2 = NULL;					\
2395 	} while (/*CONSTCOND*/0)
2396 
2397 #define DEC(from,want,dp) do {					\
2398 		s = evhttp_uridecode((from),(dp),&sz);		\
2399 		tt_assert(s);					\
2400 		tt_str_op(s,==,(want));				\
2401 		tt_int_op(sz,==,strlen(want));			\
2402 		free(s);					\
2403 		s = NULL;					\
2404 	} while (/*CONSTCOND*/0)
2405 
2406 #define OLD_DEC(from,want)  do {				\
2407 		s = evhttp_decode_uri((from));			\
2408 		tt_assert(s);					\
2409 		tt_str_op(s,==,(want));				\
2410 		free(s);					\
2411 		s = NULL;					\
2412 	} while (/*CONSTCOND*/0)
2413 
2414 
2415       	ENC("Hello", "Hello",0);
2416 	ENC("99", "99",0);
2417 	ENC("", "",0);
2418 	ENC(
2419 	 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ123456789-.~_",
2420 	 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ123456789-.~_",0);
2421 	ENC(" ", "%20",0);
2422 	ENC(" ", "+",1);
2423 	ENC("\xff\xf0\xe0", "%FF%F0%E0",0);
2424 	ENC("\x01\x19", "%01%19",1);
2425 	ENC("http://www.ietf.org/rfc/rfc3986.txt",
2426 	    "http%3A%2F%2Fwww.ietf.org%2Frfc%2Frfc3986.txt",1);
2427 
2428 	ENC("1+2=3", "1%2B2%3D3",1);
2429 	ENC("1+2=3", "1%2B2%3D3",0);
2430 
2431 	/* Now try encoding with internal NULs. */
2432 	s = evhttp_uriencode("hello\0world", 11, 0);
2433 	tt_assert(s);
2434 	tt_str_op(s,==,"hello%00world");
2435 	free(s);
2436 	s = NULL;
2437 
2438 	/* Now try out some decoding cases that we don't generate with
2439 	 * encode_uri: Make sure that malformed stuff doesn't crash... */
2440 	DEC("%%xhello th+ere \xff",
2441 	    "%%xhello th+ere \xff", 0);
2442 	/* Make sure plus decoding works */
2443 	DEC("plus+should%20work+", "plus should work ",1);
2444 	/* Try some lowercase hex */
2445 	DEC("%f0%a0%b0", "\xf0\xa0\xb0",1);
2446 
2447 	/* Try an internal NUL. */
2448 	sz = 0;
2449 	s = evhttp_uridecode("%00%00x%00%00", 1, &sz);
2450 	tt_int_op(sz,==,5);
2451 	tt_assert(!memcmp(s, "\0\0x\0\0", 5));
2452 	free(s);
2453 	s = NULL;
2454 
2455 	/* Try with size == NULL */
2456 	sz = 0;
2457 	s = evhttp_uridecode("%00%00x%00%00", 1, NULL);
2458 	tt_assert(!memcmp(s, "\0\0x\0\0", 5));
2459 	free(s);
2460 	s = NULL;
2461 
2462 	/* Test out the crazy old behavior of the deprecated
2463 	 * evhttp_decode_uri */
2464 	OLD_DEC("http://example.com/normal+path/?key=val+with+spaces",
2465 	        "http://example.com/normal+path/?key=val with spaces");
2466 
2467 end:
2468 	if (s)
2469 		free(s);
2470 	if (s2)
2471 		free(s2);
2472 #undef ENC
2473 #undef DEC
2474 #undef OLD_DEC
2475 }
2476 
2477 static void
http_base_test(void * ptr)2478 http_base_test(void *ptr)
2479 {
2480 	struct event_base *base = NULL;
2481 	struct bufferevent *bev;
2482 	evutil_socket_t fd;
2483 	const char *http_request;
2484 	ev_uint16_t port = 0;
2485 
2486 	test_ok = 0;
2487 	base = event_base_new();
2488 	http = http_setup(&port, base);
2489 
2490 	fd = http_connect("127.0.0.1", port);
2491 
2492 	/* Stupid thing to send a request */
2493 	bev = bufferevent_socket_new(base, fd, 0);
2494 	bufferevent_setcb(bev, http_readcb, http_writecb,
2495 	    http_errorcb, base);
2496 	bufferevent_base_set(base, bev);
2497 
2498 	http_request =
2499 	    "GET /test HTTP/1.1\r\n"
2500 	    "Host: somehost\r\n"
2501 	    "Connection: close\r\n"
2502 	    "\r\n";
2503 
2504 	bufferevent_write(bev, http_request, strlen(http_request));
2505 
2506 	event_base_dispatch(base);
2507 
2508 	bufferevent_free(bev);
2509 	evutil_closesocket(fd);
2510 
2511 	evhttp_free(http);
2512 
2513 	tt_int_op(test_ok, ==, 2);
2514 
2515 end:
2516 	if (base)
2517 		event_base_free(base);
2518 }
2519 
2520 /*
2521  * the server is just going to close the connection if it times out during
2522  * reading the headers.
2523  */
2524 
2525 static void
http_incomplete_readcb(struct bufferevent * bev,void * arg)2526 http_incomplete_readcb(struct bufferevent *bev, void *arg)
2527 {
2528 	test_ok = -1;
2529 	event_base_loopexit(exit_base,NULL);
2530 }
2531 
2532 static void
http_incomplete_errorcb(struct bufferevent * bev,short what,void * arg)2533 http_incomplete_errorcb(struct bufferevent *bev, short what, void *arg)
2534 {
2535 	if (what == (BEV_EVENT_READING|BEV_EVENT_EOF))
2536 		test_ok++;
2537 	else
2538 		test_ok = -2;
2539 	event_base_loopexit(exit_base,NULL);
2540 }
2541 
2542 static void
http_incomplete_writecb(struct bufferevent * bev,void * arg)2543 http_incomplete_writecb(struct bufferevent *bev, void *arg)
2544 {
2545 	if (arg != NULL) {
2546 		evutil_socket_t fd = *(evutil_socket_t *)arg;
2547 		/* terminate the write side to simulate EOF */
2548 		shutdown(fd, SHUT_WR);
2549 	}
2550 	if (evbuffer_get_length(bufferevent_get_output(bev)) == 0) {
2551 		/* enable reading of the reply */
2552 		bufferevent_enable(bev, EV_READ);
2553 		test_ok++;
2554 	}
2555 }
2556 
2557 static void
_http_incomplete_test(struct basic_test_data * data,int use_timeout)2558 _http_incomplete_test(struct basic_test_data *data, int use_timeout)
2559 {
2560 	struct bufferevent *bev;
2561 	evutil_socket_t fd;
2562 	const char *http_request;
2563 	ev_uint16_t port = 0;
2564 	struct timeval tv_start, tv_end;
2565 
2566 	exit_base = data->base;
2567 
2568 	test_ok = 0;
2569 
2570 	http = http_setup(&port, data->base);
2571 	evhttp_set_timeout(http, 1);
2572 
2573 	fd = http_connect("127.0.0.1", port);
2574 
2575 	/* Stupid thing to send a request */
2576 	bev = bufferevent_socket_new(data->base, fd, 0);
2577 	bufferevent_setcb(bev,
2578 	    http_incomplete_readcb, http_incomplete_writecb,
2579 	    http_incomplete_errorcb, use_timeout ? NULL : &fd);
2580 
2581 	http_request =
2582 	    "GET /test HTTP/1.1\r\n"
2583 	    "Host: somehost\r\n";
2584 
2585 	bufferevent_write(bev, http_request, strlen(http_request));
2586 
2587 	evutil_gettimeofday(&tv_start, NULL);
2588 
2589 	event_base_dispatch(data->base);
2590 
2591 	evutil_gettimeofday(&tv_end, NULL);
2592 	evutil_timersub(&tv_end, &tv_start, &tv_end);
2593 
2594 	bufferevent_free(bev);
2595 	if (use_timeout) {
2596 		evutil_closesocket(fd);
2597 	}
2598 
2599 	evhttp_free(http);
2600 
2601 	if (use_timeout && tv_end.tv_sec >= 3) {
2602 		tt_abort_msg("time");
2603 	} else if (!use_timeout && tv_end.tv_sec >= 1) {
2604 		/* we should be done immediately */
2605 		tt_abort_msg("time");
2606 	}
2607 
2608 	tt_int_op(test_ok, ==, 2);
2609  end:
2610 	;
2611 }
2612 static void
http_incomplete_test(void * arg)2613 http_incomplete_test(void *arg)
2614 {
2615 	_http_incomplete_test(arg, 0);
2616 }
2617 static void
http_incomplete_timeout_test(void * arg)2618 http_incomplete_timeout_test(void *arg)
2619 {
2620 	_http_incomplete_test(arg, 1);
2621 }
2622 
2623 /*
2624  * the server is going to reply with chunked data.
2625  */
2626 
2627 static void
http_chunked_readcb(struct bufferevent * bev,void * arg)2628 http_chunked_readcb(struct bufferevent *bev, void *arg)
2629 {
2630 	/* nothing here */
2631 }
2632 
2633 static void
http_chunked_errorcb(struct bufferevent * bev,short what,void * arg)2634 http_chunked_errorcb(struct bufferevent *bev, short what, void *arg)
2635 {
2636 	if (!test_ok)
2637 		goto out;
2638 
2639 	test_ok = -1;
2640 
2641 	if ((what & BEV_EVENT_EOF) != 0) {
2642 		struct evhttp_request *req = evhttp_request_new(NULL, NULL);
2643 		const char *header;
2644 		enum message_read_status done;
2645 
2646 		/* req->kind = EVHTTP_RESPONSE; */
2647 		done = evhttp_parse_firstline(req, bufferevent_get_input(bev));
2648 		if (done != ALL_DATA_READ)
2649 			goto out;
2650 
2651 		done = evhttp_parse_headers(req, bufferevent_get_input(bev));
2652 		if (done != ALL_DATA_READ)
2653 			goto out;
2654 
2655 		header = evhttp_find_header(evhttp_request_get_input_headers(req), "Transfer-Encoding");
2656 		if (header == NULL || strcmp(header, "chunked"))
2657 			goto out;
2658 
2659 		header = evhttp_find_header(evhttp_request_get_input_headers(req), "Connection");
2660 		if (header == NULL || strcmp(header, "close"))
2661 			goto out;
2662 
2663 		header = evbuffer_readln(bufferevent_get_input(bev), NULL, EVBUFFER_EOL_CRLF);
2664 		if (header == NULL)
2665 			goto out;
2666 		/* 13 chars */
2667 		if (strcmp(header, "d")) {
2668 			free(__UNCONST(header));
2669 			goto out;
2670 		}
2671 		free(__UNCONST(header));
2672 
2673 		if (strncmp((char *)evbuffer_pullup(bufferevent_get_input(bev), 13),
2674 			"This is funny", 13))
2675 			goto out;
2676 
2677 		evbuffer_drain(bufferevent_get_input(bev), 13 + 2);
2678 
2679 		header = evbuffer_readln(bufferevent_get_input(bev), NULL, EVBUFFER_EOL_CRLF);
2680 		if (header == NULL)
2681 			goto out;
2682 		/* 18 chars */
2683 		if (strcmp(header, "12"))
2684 			goto out;
2685 		free(__UNCONST(header));
2686 
2687 		if (strncmp((char *)evbuffer_pullup(bufferevent_get_input(bev), 18),
2688 			"but not hilarious.", 18))
2689 			goto out;
2690 
2691 		evbuffer_drain(bufferevent_get_input(bev), 18 + 2);
2692 
2693 		header = evbuffer_readln(bufferevent_get_input(bev), NULL, EVBUFFER_EOL_CRLF);
2694 		if (header == NULL)
2695 			goto out;
2696 		/* 8 chars */
2697 		if (strcmp(header, "8")) {
2698 			free(__UNCONST(header));
2699 			goto out;
2700 		}
2701 		free(__UNCONST(header));
2702 
2703 		if (strncmp((char *)evbuffer_pullup(bufferevent_get_input(bev), 8),
2704 			"bwv 1052.", 8))
2705 			goto out;
2706 
2707 		evbuffer_drain(bufferevent_get_input(bev), 8 + 2);
2708 
2709 		header = evbuffer_readln(bufferevent_get_input(bev), NULL, EVBUFFER_EOL_CRLF);
2710 		if (header == NULL)
2711 			goto out;
2712 		/* 0 chars */
2713 		if (strcmp(header, "0")) {
2714 			free(__UNCONST(header));
2715 			goto out;
2716 		}
2717 		free(__UNCONST(header));
2718 
2719 		test_ok = 2;
2720 
2721 		evhttp_request_free(req);
2722 	}
2723 
2724 out:
2725 	event_base_loopexit(arg, NULL);
2726 }
2727 
2728 static void
http_chunked_writecb(struct bufferevent * bev,void * arg)2729 http_chunked_writecb(struct bufferevent *bev, void *arg)
2730 {
2731 	if (evbuffer_get_length(bufferevent_get_output(bev)) == 0) {
2732 		/* enable reading of the reply */
2733 		bufferevent_enable(bev, EV_READ);
2734 		test_ok++;
2735 	}
2736 }
2737 
2738 static void
http_chunked_request_done(struct evhttp_request * req,void * arg)2739 http_chunked_request_done(struct evhttp_request *req, void *arg)
2740 {
2741 	if (evhttp_request_get_response_code(req) != HTTP_OK) {
2742 		fprintf(stderr, "FAILED\n");
2743 		exit(1);
2744 	}
2745 
2746 	if (evhttp_find_header(evhttp_request_get_input_headers(req),
2747 		"Transfer-Encoding") == NULL) {
2748 		fprintf(stderr, "FAILED\n");
2749 		exit(1);
2750 	}
2751 
2752 	if (evbuffer_get_length(evhttp_request_get_input_buffer(req)) != 13 + 18 + 8) {
2753 		fprintf(stderr, "FAILED\n");
2754 		exit(1);
2755 	}
2756 
2757 	if (strncmp((char *)evbuffer_pullup(evhttp_request_get_input_buffer(req), 13 + 18 + 8),
2758 		"This is funnybut not hilarious.bwv 1052",
2759 		13 + 18 + 8)) {
2760 		fprintf(stderr, "FAILED\n");
2761 		exit(1);
2762 	}
2763 
2764 	test_ok = 1;
2765 	event_base_loopexit(arg, NULL);
2766 }
2767 
2768 static void
http_chunk_out_test(void * arg)2769 http_chunk_out_test(void *arg)
2770 {
2771 	struct basic_test_data *data = arg;
2772 	struct bufferevent *bev;
2773 	evutil_socket_t fd;
2774 	const char *http_request;
2775 	ev_uint16_t port = 0;
2776 	struct timeval tv_start, tv_end;
2777 	struct evhttp_connection *evcon = NULL;
2778 	struct evhttp_request *req = NULL;
2779 	int i;
2780 
2781 	exit_base = data->base;
2782 	test_ok = 0;
2783 
2784 	http = http_setup(&port, data->base);
2785 
2786 	fd = http_connect("127.0.0.1", port);
2787 
2788 	/* Stupid thing to send a request */
2789 	bev = bufferevent_socket_new(data->base, fd, 0);
2790 	bufferevent_setcb(bev,
2791 	    http_chunked_readcb, http_chunked_writecb,
2792 	    http_chunked_errorcb, data->base);
2793 
2794 	http_request =
2795 	    "GET /chunked HTTP/1.1\r\n"
2796 	    "Host: somehost\r\n"
2797 	    "Connection: close\r\n"
2798 	    "\r\n";
2799 
2800 	bufferevent_write(bev, http_request, strlen(http_request));
2801 
2802 	evutil_gettimeofday(&tv_start, NULL);
2803 
2804 	event_base_dispatch(data->base);
2805 
2806 	bufferevent_free(bev);
2807 
2808 	evutil_gettimeofday(&tv_end, NULL);
2809 	evutil_timersub(&tv_end, &tv_start, &tv_end);
2810 
2811 	tt_int_op(tv_end.tv_sec, <, 1);
2812 
2813 	tt_int_op(test_ok, ==, 2);
2814 
2815 	/* now try again with the regular connection object */
2816 	evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port);
2817 	tt_assert(evcon);
2818 
2819 	/* make two requests to check the keepalive behavior */
2820 	for (i = 0; i < 2; i++) {
2821 		test_ok = 0;
2822 		req = evhttp_request_new(http_chunked_request_done,data->base);
2823 
2824 		/* Add the information that we care about */
2825 		evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
2826 
2827 		/* We give ownership of the request to the connection */
2828 		if (evhttp_make_request(evcon, req,
2829 			EVHTTP_REQ_GET, "/chunked") == -1) {
2830 			tt_abort_msg("Couldn't make request");
2831 		}
2832 
2833 		event_base_dispatch(data->base);
2834 
2835 		tt_assert(test_ok == 1);
2836 	}
2837 
2838  end:
2839 	if (evcon)
2840 		evhttp_connection_free(evcon);
2841 	if (http)
2842 		evhttp_free(http);
2843 }
2844 
2845 static void
http_stream_out_test(void * arg)2846 http_stream_out_test(void *arg)
2847 {
2848 	struct basic_test_data *data = arg;
2849 	ev_uint16_t port = 0;
2850 	struct evhttp_connection *evcon = NULL;
2851 	struct evhttp_request *req = NULL;
2852 
2853 	test_ok = 0;
2854 	exit_base = data->base;
2855 
2856 	http = http_setup(&port, data->base);
2857 
2858 	evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port);
2859 	tt_assert(evcon);
2860 
2861 	/*
2862 	 * At this point, we want to schedule a request to the HTTP
2863 	 * server using our make request method.
2864 	 */
2865 
2866 	req = evhttp_request_new(http_request_done,
2867 	    __UNCONST("This is funnybut not hilarious.bwv 1052"));
2868 
2869 	/* Add the information that we care about */
2870 	evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
2871 
2872 	/* We give ownership of the request to the connection */
2873 	if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/streamed")
2874 	    == -1) {
2875 		tt_abort_msg("Couldn't make request");
2876 	}
2877 
2878 	event_base_dispatch(data->base);
2879 
2880  end:
2881 	if (evcon)
2882 		evhttp_connection_free(evcon);
2883 	if (http)
2884 		evhttp_free(http);
2885 }
2886 
2887 static void
http_stream_in_chunk(struct evhttp_request * req,void * arg)2888 http_stream_in_chunk(struct evhttp_request *req, void *arg)
2889 {
2890 	struct evbuffer *reply = arg;
2891 
2892 	if (evhttp_request_get_response_code(req) != HTTP_OK) {
2893 		fprintf(stderr, "FAILED\n");
2894 		exit(1);
2895 	}
2896 
2897 	evbuffer_add_buffer(reply, evhttp_request_get_input_buffer(req));
2898 }
2899 
2900 static void
http_stream_in_done(struct evhttp_request * req,void * arg)2901 http_stream_in_done(struct evhttp_request *req, void *arg)
2902 {
2903 	if (evbuffer_get_length(evhttp_request_get_input_buffer(req)) != 0) {
2904 		fprintf(stderr, "FAILED\n");
2905 		exit(1);
2906 	}
2907 
2908 	event_base_loopexit(exit_base, NULL);
2909 }
2910 
2911 /**
2912  * Makes a request and reads the response in chunks.
2913  */
2914 static void
_http_stream_in_test(struct basic_test_data * data,char const * url,size_t expected_len,char const * expected)2915 _http_stream_in_test(struct basic_test_data *data, char const *url,
2916     size_t expected_len, char const *expected)
2917 {
2918 	struct evhttp_connection *evcon;
2919 	struct evbuffer *reply = evbuffer_new();
2920 	struct evhttp_request *req = NULL;
2921 	ev_uint16_t port = 0;
2922 
2923 	exit_base = data->base;
2924 	http = http_setup(&port, data->base);
2925 
2926 	evcon = evhttp_connection_base_new(data->base, NULL,"127.0.0.1", port);
2927 	tt_assert(evcon);
2928 
2929 	req = evhttp_request_new(http_stream_in_done, reply);
2930 	evhttp_request_set_chunked_cb(req, http_stream_in_chunk);
2931 
2932 	/* We give ownership of the request to the connection */
2933 	if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, url) == -1) {
2934 		tt_abort_msg("Couldn't make request");
2935 	}
2936 
2937 	event_base_dispatch(data->base);
2938 
2939 	if (evbuffer_get_length(reply) != expected_len) {
2940 		TT_DIE(("reply length %lu; expected %lu; FAILED (%s)\n",
2941 				(unsigned long)evbuffer_get_length(reply),
2942 				(unsigned long)expected_len,
2943 				(char*)evbuffer_pullup(reply, -1)));
2944 	}
2945 
2946 	if (memcmp(evbuffer_pullup(reply, -1), expected, expected_len) != 0) {
2947 		tt_abort_msg("Memory mismatch");
2948 	}
2949 
2950 	test_ok = 1;
2951  end:
2952 	if (reply)
2953 		evbuffer_free(reply);
2954 	if (evcon)
2955 		evhttp_connection_free(evcon);
2956 	if (http)
2957 		evhttp_free(http);
2958 }
2959 
2960 static void
http_stream_in_test(void * arg)2961 http_stream_in_test(void *arg)
2962 {
2963 	_http_stream_in_test(arg, "/chunked", 13 + 18 + 8,
2964 	    "This is funnybut not hilarious.bwv 1052");
2965 
2966 	_http_stream_in_test(arg, "/test", strlen(BASIC_REQUEST_BODY),
2967 	    BASIC_REQUEST_BODY);
2968 }
2969 
2970 static void
http_stream_in_cancel_chunk(struct evhttp_request * req,void * arg)2971 http_stream_in_cancel_chunk(struct evhttp_request *req, void *arg)
2972 {
2973 	tt_int_op(evhttp_request_get_response_code(req), ==, HTTP_OK);
2974 
2975  end:
2976 	evhttp_cancel_request(req);
2977 	event_base_loopexit(arg, NULL);
2978 }
2979 
2980 static void
http_stream_in_cancel_done(struct evhttp_request * req,void * arg)2981 http_stream_in_cancel_done(struct evhttp_request *req, void *arg)
2982 {
2983 	/* should never be called */
2984 	tt_fail_msg("In cancel done");
2985 }
2986 
2987 static void
http_stream_in_cancel_test(void * arg)2988 http_stream_in_cancel_test(void *arg)
2989 {
2990 	struct basic_test_data *data = arg;
2991 	struct evhttp_connection *evcon;
2992 	struct evhttp_request *req = NULL;
2993 	ev_uint16_t port = 0;
2994 
2995 	http = http_setup(&port, data->base);
2996 
2997 	evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port);
2998 	tt_assert(evcon);
2999 
3000 	req = evhttp_request_new(http_stream_in_cancel_done, data->base);
3001 	evhttp_request_set_chunked_cb(req, http_stream_in_cancel_chunk);
3002 
3003 	/* We give ownership of the request to the connection */
3004 	if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/chunked") == -1) {
3005 		tt_abort_msg("Couldn't make request");
3006 	}
3007 
3008 	event_base_dispatch(data->base);
3009 
3010 	test_ok = 1;
3011  end:
3012 	evhttp_connection_free(evcon);
3013 	evhttp_free(http);
3014 
3015 }
3016 
3017 static void
http_connection_fail_done(struct evhttp_request * req,void * arg)3018 http_connection_fail_done(struct evhttp_request *req, void *arg)
3019 {
3020        struct evhttp_connection *evcon = arg;
3021        struct event_base *base = evhttp_connection_get_base(evcon);
3022 
3023        /* An ENETUNREACH error results in an unrecoverable
3024         * evhttp_connection error (see evhttp_connection_fail()).  The
3025         * connection will be reset, and the user will be notified with a NULL
3026         * req parameter. */
3027        tt_assert(!req);
3028 
3029        evhttp_connection_free(evcon);
3030 
3031        test_ok = 1;
3032 
3033  end:
3034        event_base_loopexit(base, NULL);
3035 }
3036 
3037 /* Test unrecoverable evhttp_connection errors by generating an ENETUNREACH
3038  * error on connection. */
3039 static void
http_connection_fail_test(void * arg)3040 http_connection_fail_test(void *arg)
3041 {
3042        struct basic_test_data *data = arg;
3043        ev_uint16_t port = 0;
3044        struct evhttp_connection *evcon = NULL;
3045        struct evhttp_request *req = NULL;
3046 
3047        exit_base = data->base;
3048        test_ok = 0;
3049 
3050        /* auto detect a port */
3051        http = http_setup(&port, data->base);
3052        evhttp_free(http);
3053        http = NULL;
3054 
3055        /* Pick an unroutable address.  This administratively scoped multicast
3056 	* address should do when working with TCP. */
3057        evcon = evhttp_connection_base_new(data->base, NULL, "239.10.20.30", 80);
3058        tt_assert(evcon);
3059 
3060        /*
3061         * At this point, we want to schedule an HTTP GET request
3062         * server using our make request method.
3063         */
3064 
3065        req = evhttp_request_new(http_connection_fail_done, evcon);
3066        tt_assert(req);
3067 
3068        if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/") == -1) {
3069                tt_abort_msg("Couldn't make request");
3070        }
3071 
3072        event_base_dispatch(data->base);
3073 
3074        tt_int_op(test_ok, ==, 1);
3075 
3076  end:
3077         ;
3078 }
3079 
3080 static void
http_connection_retry_done(struct evhttp_request * req,void * arg)3081 http_connection_retry_done(struct evhttp_request *req, void *arg)
3082 {
3083 	tt_assert(req);
3084 	tt_int_op(evhttp_request_get_response_code(req), !=, HTTP_OK);
3085 	if (evhttp_find_header(evhttp_request_get_input_headers(req), "Content-Type") != NULL) {
3086 		tt_abort_msg("(content type)\n");
3087 	}
3088 
3089 	tt_uint_op(evbuffer_get_length(evhttp_request_get_input_buffer(req)), ==, 0);
3090 
3091 	test_ok = 1;
3092  end:
3093 	event_base_loopexit(arg,NULL);
3094 }
3095 
3096 static struct event_base *http_make_web_server_base=NULL;
3097 static void
http_make_web_server(evutil_socket_t fd,short what,void * arg)3098 http_make_web_server(evutil_socket_t fd, short what, void *arg)
3099 {
3100 	ev_uint16_t port = *(ev_uint16_t*)arg;
3101 	http = http_setup(&port, http_make_web_server_base);
3102 }
3103 
3104 static void
http_connection_retry_test(void * arg)3105 http_connection_retry_test(void *arg)
3106 {
3107 	struct basic_test_data *data = arg;
3108 	ev_uint16_t port = 0;
3109 	struct evhttp_connection *evcon = NULL;
3110 	struct evhttp_request *req = NULL;
3111 	struct timeval tv, tv_start, tv_end;
3112 
3113 	exit_base = data->base;
3114 	test_ok = 0;
3115 
3116 	/* auto detect a port */
3117 	http = http_setup(&port, data->base);
3118 	evhttp_free(http);
3119 	http = NULL;
3120 
3121 	evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port);
3122 	tt_assert(evcon);
3123 
3124 	evhttp_connection_set_timeout(evcon, 1);
3125 	/* also bind to local host */
3126 	evhttp_connection_set_local_address(evcon, "127.0.0.1");
3127 
3128 	/*
3129 	 * At this point, we want to schedule an HTTP GET request
3130 	 * server using our make request method.
3131 	 */
3132 
3133 	req = evhttp_request_new(http_connection_retry_done, data->base);
3134 	tt_assert(req);
3135 
3136 	/* Add the information that we care about */
3137 	evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
3138 
3139 	if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET,
3140 		"/?arg=val") == -1) {
3141 		tt_abort_msg("Couldn't make request");
3142 	}
3143 
3144 	evutil_gettimeofday(&tv_start, NULL);
3145 	event_base_dispatch(data->base);
3146 	evutil_gettimeofday(&tv_end, NULL);
3147 	evutil_timersub(&tv_end, &tv_start, &tv_end);
3148 	tt_int_op(tv_end.tv_sec, <, 1);
3149 
3150 	tt_int_op(test_ok, ==, 1);
3151 
3152 	/*
3153 	 * now test the same but with retries
3154 	 */
3155 	test_ok = 0;
3156 
3157 	evhttp_connection_set_timeout(evcon, 1);
3158 	evhttp_connection_set_retries(evcon, 1);
3159 
3160 	req = evhttp_request_new(http_connection_retry_done, data->base);
3161 	tt_assert(req);
3162 
3163 	/* Add the information that we care about */
3164 	evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
3165 
3166 	if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET,
3167 		"/?arg=val") == -1) {
3168 		tt_abort_msg("Couldn't make request");
3169 	}
3170 
3171 	evutil_gettimeofday(&tv_start, NULL);
3172 	event_base_dispatch(data->base);
3173 	evutil_gettimeofday(&tv_end, NULL);
3174 	evutil_timersub(&tv_end, &tv_start, &tv_end);
3175 	tt_int_op(tv_end.tv_sec, >, 1);
3176 	tt_int_op(tv_end.tv_sec, <, 6);
3177 
3178 	tt_assert(test_ok == 1);
3179 
3180 	/*
3181 	 * now test the same but with retries and give it a web server
3182 	 * at the end
3183 	 */
3184 	test_ok = 0;
3185 
3186 	evhttp_connection_set_timeout(evcon, 1);
3187 	evhttp_connection_set_retries(evcon, 3);
3188 
3189 	req = evhttp_request_new(http_dispatcher_test_done, data->base);
3190 	tt_assert(req);
3191 
3192 	/* Add the information that we care about */
3193 	evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
3194 
3195 	if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET,
3196 		"/?arg=val") == -1) {
3197 		tt_abort_msg("Couldn't make request");
3198 	}
3199 
3200 	/* start up a web server one second after the connection tried
3201 	 * to send a request
3202 	 */
3203 	evutil_timerclear(&tv);
3204 	tv.tv_sec = 1;
3205 	http_make_web_server_base = data->base;
3206 	event_base_once(data->base, -1, EV_TIMEOUT, http_make_web_server, &port, &tv);
3207 
3208 	evutil_gettimeofday(&tv_start, NULL);
3209 	event_base_dispatch(data->base);
3210 	evutil_gettimeofday(&tv_end, NULL);
3211 
3212 	evutil_timersub(&tv_end, &tv_start, &tv_end);
3213 
3214 	tt_int_op(tv_end.tv_sec, >, 1);
3215 	tt_int_op(tv_end.tv_sec, <, 6);
3216 
3217 	tt_int_op(test_ok, ==, 1);
3218 
3219  end:
3220 	if (evcon)
3221 		evhttp_connection_free(evcon);
3222 	if (http)
3223 		evhttp_free(http);
3224 }
3225 
3226 static void
http_primitives(void * ptr)3227 http_primitives(void *ptr)
3228 {
3229 	char *escaped = NULL;
3230 	struct evhttp *xhttp = NULL;
3231 
3232 	escaped = evhttp_htmlescape("<script>");
3233 	tt_assert(escaped);
3234 	tt_str_op(escaped, ==, "&lt;script&gt;");
3235 	free(escaped);
3236 
3237 	escaped = evhttp_htmlescape("\"\'&");
3238 	tt_assert(escaped);
3239 	tt_str_op(escaped, ==, "&quot;&#039;&amp;");
3240 
3241 	xhttp = evhttp_new(NULL);
3242 	tt_assert(xhttp);
3243 	tt_int_op(evhttp_set_cb(xhttp, "/test", http_basic_cb, NULL), ==, 0);
3244 	tt_int_op(evhttp_set_cb(xhttp, "/test", http_basic_cb, NULL), ==, -1);
3245 	tt_int_op(evhttp_del_cb(xhttp, "/test"), ==, 0);
3246 	tt_int_op(evhttp_del_cb(xhttp, "/test"), ==, -1);
3247 	tt_int_op(evhttp_set_cb(xhttp, "/test", http_basic_cb, NULL), ==, 0);
3248 
3249  end:
3250 	if (escaped)
3251 		free(escaped);
3252 	if (xhttp)
3253 		evhttp_free(xhttp);
3254 }
3255 
3256 static void
http_multi_line_header_test(void * arg)3257 http_multi_line_header_test(void *arg)
3258 {
3259 	struct basic_test_data *data = arg;
3260 	struct bufferevent *bev= NULL;
3261 	evutil_socket_t fd = -1;
3262 	const char *http_start_request;
3263 	ev_uint16_t port = 0;
3264 
3265 	test_ok = 0;
3266 
3267 	http = http_setup(&port, data->base);
3268 
3269 	fd = http_connect("127.0.0.1", port);
3270 
3271 	/* Stupid thing to send a request */
3272 	bev = bufferevent_socket_new(data->base, fd, 0);
3273 	bufferevent_setcb(bev, http_readcb, http_writecb,
3274 	    http_errorcb, data->base);
3275 
3276 	http_start_request =
3277 	    "GET /test HTTP/1.1\r\n"
3278 	    "Host: somehost\r\n"
3279 	    "Connection: close\r\n"
3280 	    "X-Multi:  aaaaaaaa\r\n"
3281 	    " a\r\n"
3282 	    "\tEND\r\n"
3283 	    "X-Last: last\r\n"
3284 	    "\r\n";
3285 
3286 	bufferevent_write(bev, http_start_request, strlen(http_start_request));
3287 
3288 	event_base_dispatch(data->base);
3289 
3290 	tt_int_op(test_ok, ==, 4);
3291  end:
3292 	if (bev)
3293 		bufferevent_free(bev);
3294 	if (fd >= 0)
3295 		evutil_closesocket(fd);
3296 	if (http)
3297 		evhttp_free(http);
3298 }
3299 
3300 static void
http_request_bad(struct evhttp_request * req,void * arg)3301 http_request_bad(struct evhttp_request *req, void *arg)
3302 {
3303 	if (req != NULL) {
3304 		fprintf(stderr, "FAILED\n");
3305 		exit(1);
3306 	}
3307 
3308 	test_ok = 1;
3309 	event_base_loopexit(arg, NULL);
3310 }
3311 
3312 static void
http_negative_content_length_test(void * arg)3313 http_negative_content_length_test(void *arg)
3314 {
3315 	struct basic_test_data *data = arg;
3316 	ev_uint16_t port = 0;
3317 	struct evhttp_connection *evcon = NULL;
3318 	struct evhttp_request *req = NULL;
3319 
3320 	test_ok = 0;
3321 
3322 	http = http_setup(&port, data->base);
3323 
3324 	evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port);
3325 	tt_assert(evcon);
3326 
3327 	/*
3328 	 * At this point, we want to schedule a request to the HTTP
3329 	 * server using our make request method.
3330 	 */
3331 
3332 	req = evhttp_request_new(http_request_bad, data->base);
3333 
3334 	/* Cause the response to have a negative content-length */
3335 	evhttp_add_header(evhttp_request_get_output_headers(req), "X-Negative", "makeitso");
3336 
3337 	/* We give ownership of the request to the connection */
3338 	if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test") == -1) {
3339 		tt_abort_msg("Couldn't make request");
3340 	}
3341 
3342 	event_base_dispatch(data->base);
3343 
3344  end:
3345 	if (evcon)
3346 		evhttp_connection_free(evcon);
3347 	if (http)
3348 		evhttp_free(http);
3349 }
3350 
3351 
3352 static void
http_data_length_constraints_test_done(struct evhttp_request * req,void * arg)3353 http_data_length_constraints_test_done(struct evhttp_request *req, void *arg)
3354 {
3355 	tt_assert(req);
3356 	tt_int_op(evhttp_request_get_response_code(req), ==, HTTP_BADREQUEST);
3357 end:
3358 	event_base_loopexit(arg, NULL);
3359 }
3360 
3361 static void
http_large_entity_test_done(struct evhttp_request * req,void * arg)3362 http_large_entity_test_done(struct evhttp_request *req, void *arg)
3363 {
3364 	tt_assert(req);
3365 	tt_int_op(evhttp_request_get_response_code(req), ==, HTTP_ENTITYTOOLARGE);
3366 end:
3367 	event_base_loopexit(arg, NULL);
3368 }
3369 
3370 static void
http_data_length_constraints_test(void * arg)3371 http_data_length_constraints_test(void *arg)
3372 {
3373 	struct basic_test_data *data = arg;
3374 	ev_uint16_t port = 0;
3375 	struct evhttp_connection *evcon = NULL;
3376 	struct evhttp_request *req = NULL;
3377 	char long_str[8192];
3378 
3379 	test_ok = 0;
3380 
3381 	http = http_setup(&port, data->base);
3382 
3383 	evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port);
3384 	tt_assert(evcon);
3385 
3386 	/* also bind to local host */
3387 	evhttp_connection_set_local_address(evcon, "127.0.0.1");
3388 
3389 	/*
3390 	 * At this point, we want to schedule an HTTP GET request
3391 	 * server using our make request method.
3392 	 */
3393 
3394 	req = evhttp_request_new(http_data_length_constraints_test_done, data->base);
3395 	tt_assert(req);
3396 
3397 	memset(long_str, 'a', 8192);
3398 	long_str[8191] = '\0';
3399 	/* Add the information that we care about */
3400 	evhttp_set_max_headers_size(http, 8191);
3401 	evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
3402 	evhttp_add_header(evhttp_request_get_output_headers(req), "Longheader", long_str);
3403 
3404 	if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/?arg=val") == -1) {
3405 		tt_abort_msg("Couldn't make request");
3406 	}
3407 	event_base_dispatch(data->base);
3408 
3409 	req = evhttp_request_new(http_data_length_constraints_test_done, data->base);
3410 	tt_assert(req);
3411 	evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
3412 
3413 	/* GET /?arg=verylongvalue HTTP/1.1 */
3414 	if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, long_str) == -1) {
3415 		tt_abort_msg("Couldn't make request");
3416 	}
3417 	event_base_dispatch(data->base);
3418 
3419 	evhttp_set_max_body_size(http, 8190);
3420 	req = evhttp_request_new(http_data_length_constraints_test_done, data->base);
3421 	evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
3422 	evbuffer_add_printf(evhttp_request_get_output_buffer(req), "%s", long_str);
3423 	if (evhttp_make_request(evcon, req, EVHTTP_REQ_POST, "/") == -1) {
3424 		tt_abort_msg("Couldn't make request");
3425 	}
3426 	event_base_dispatch(data->base);
3427 
3428 	req = evhttp_request_new(http_large_entity_test_done, data->base);
3429 	evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
3430 	evhttp_add_header(evhttp_request_get_output_headers(req), "Expect", "100-continue");
3431 	evbuffer_add_printf(evhttp_request_get_output_buffer(req), "%s", long_str);
3432 	if (evhttp_make_request(evcon, req, EVHTTP_REQ_POST, "/") == -1) {
3433 		tt_abort_msg("Couldn't make request");
3434 	}
3435 	event_base_dispatch(data->base);
3436 
3437 	test_ok = 1;
3438  end:
3439 	if (evcon)
3440 		evhttp_connection_free(evcon);
3441 	if (http)
3442 		evhttp_free(http);
3443 }
3444 
3445 /*
3446  * Testing client reset of server chunked connections
3447  */
3448 
3449 struct terminate_state {
3450 	struct event_base *base;
3451 	struct evhttp_request *req;
3452 	struct bufferevent *bev;
3453 	evutil_socket_t fd;
3454 	int gotclosecb: 1;
3455 };
3456 
3457 static void
terminate_chunked_trickle_cb(evutil_socket_t fd,short events,void * arg)3458 terminate_chunked_trickle_cb(evutil_socket_t fd, short events, void *arg)
3459 {
3460 	struct terminate_state *state = arg;
3461 	struct evbuffer *evb;
3462 	struct timeval tv;
3463 
3464 	if (evhttp_request_get_connection(state->req) == NULL) {
3465 		test_ok = 1;
3466 		evhttp_request_free(state->req);
3467 		event_base_loopexit(state->base,NULL);
3468 		return;
3469 	}
3470 
3471 	evb = evbuffer_new();
3472 	evbuffer_add_printf(evb, "%p", evb);
3473 	evhttp_send_reply_chunk(state->req, evb);
3474 	evbuffer_free(evb);
3475 
3476 	tv.tv_sec = 0;
3477 	tv.tv_usec = 3000;
3478 	EVUTIL_ASSERT(state);
3479 	EVUTIL_ASSERT(state->base);
3480 	event_base_once(state->base, -1, EV_TIMEOUT, terminate_chunked_trickle_cb, arg, &tv);
3481 }
3482 
3483 static void
terminate_chunked_close_cb(struct evhttp_connection * evcon,void * arg)3484 terminate_chunked_close_cb(struct evhttp_connection *evcon, void *arg)
3485 {
3486 	struct terminate_state *state = arg;
3487 	state->gotclosecb = 1;
3488 }
3489 
3490 static void
terminate_chunked_cb(struct evhttp_request * req,void * arg)3491 terminate_chunked_cb(struct evhttp_request *req, void *arg)
3492 {
3493 	struct terminate_state *state = arg;
3494 	struct timeval tv;
3495 
3496 	/* we want to know if this connection closes on us */
3497 	evhttp_connection_set_closecb(
3498 		evhttp_request_get_connection(req),
3499 		terminate_chunked_close_cb, arg);
3500 
3501 	state->req = req;
3502 
3503 	evhttp_send_reply_start(req, HTTP_OK, "OK");
3504 
3505 	tv.tv_sec = 0;
3506 	tv.tv_usec = 3000;
3507 	event_base_once(state->base, -1, EV_TIMEOUT, terminate_chunked_trickle_cb, arg, &tv);
3508 }
3509 
3510 static void
terminate_chunked_client(evutil_socket_t fd,short event,void * arg)3511 terminate_chunked_client(evutil_socket_t fd, short event, void *arg)
3512 {
3513 	struct terminate_state *state = arg;
3514 	bufferevent_free(state->bev);
3515 	evutil_closesocket(state->fd);
3516 }
3517 
3518 static void
terminate_readcb(struct bufferevent * bev,void * arg)3519 terminate_readcb(struct bufferevent *bev, void *arg)
3520 {
3521 	/* just drop the data */
3522 	evbuffer_drain(bufferevent_get_input(bev), -1);
3523 }
3524 
3525 
3526 static void
http_terminate_chunked_test(void * arg)3527 http_terminate_chunked_test(void *arg)
3528 {
3529 	struct basic_test_data *data = arg;
3530 	struct bufferevent *bev = NULL;
3531 	struct timeval tv;
3532 	const char *http_request;
3533 	ev_uint16_t port = 0;
3534 	evutil_socket_t fd = -1;
3535 	struct terminate_state terminate_state;
3536 
3537 	test_ok = 0;
3538 
3539 	http = http_setup(&port, data->base);
3540 	evhttp_del_cb(http, "/test");
3541 	tt_assert(evhttp_set_cb(http, "/test",
3542 		terminate_chunked_cb, &terminate_state) == 0);
3543 
3544 	fd = http_connect("127.0.0.1", port);
3545 
3546 	/* Stupid thing to send a request */
3547 	bev = bufferevent_socket_new(data->base, fd, 0);
3548 	bufferevent_setcb(bev, terminate_readcb, http_writecb,
3549 	    http_errorcb, data->base);
3550 
3551 	memset(&terminate_state, 0, sizeof(terminate_state));
3552 	terminate_state.base = data->base;
3553 	terminate_state.fd = fd;
3554 	terminate_state.bev = bev;
3555 	terminate_state.gotclosecb = 0;
3556 
3557 	/* first half of the http request */
3558 	http_request =
3559 	    "GET /test HTTP/1.1\r\n"
3560 	    "Host: some\r\n\r\n";
3561 
3562 	bufferevent_write(bev, http_request, strlen(http_request));
3563 	evutil_timerclear(&tv);
3564 	tv.tv_usec = 10000;
3565 	event_base_once(data->base, -1, EV_TIMEOUT, terminate_chunked_client, &terminate_state,
3566 	    &tv);
3567 
3568 	event_base_dispatch(data->base);
3569 
3570 	if (terminate_state.gotclosecb == 0)
3571 		test_ok = 0;
3572 
3573  end:
3574 	if (fd >= 0)
3575 		evutil_closesocket(fd);
3576 	if (http)
3577 		evhttp_free(http);
3578 }
3579 
3580 #define HTTP_LEGACY(name)						\
3581 	{ #name, run_legacy_test_fn, TT_ISOLATED|TT_LEGACY, &legacy_setup, \
3582 		    http_##name##_test }
3583 
3584 #define HTTP(name) \
3585 	{ #name, http_##name##_test, TT_ISOLATED, &basic_setup, NULL }
3586 
3587 struct testcase_t http_testcases[] = {
3588 	{ "primitives", http_primitives, 0, NULL, NULL },
3589 	{ "base", http_base_test, TT_FORK, NULL, NULL },
3590 	{ "bad_headers", http_bad_header_test, 0, NULL, NULL },
3591 	{ "parse_query", http_parse_query_test, 0, NULL, NULL },
3592 	{ "parse_uri", http_parse_uri_test, 0, NULL, NULL },
3593 	{ "parse_uri_nc", http_parse_uri_test, 0, &basic_setup, __UNCONST("nc") },
3594 	{ "uriencode", http_uriencode_test, 0, NULL, NULL },
3595 	HTTP(basic),
3596 	HTTP(cancel),
3597 	HTTP(virtual_host),
3598 	HTTP(post),
3599 	HTTP(put),
3600 	HTTP(delete),
3601 	HTTP(allowed_methods),
3602 	HTTP(failure),
3603 	HTTP(connection),
3604 	HTTP(persist_connection),
3605 	HTTP(connection_async),
3606 	HTTP(close_detection),
3607 	HTTP(close_detection_delay),
3608 	HTTP(bad_request),
3609 	HTTP(incomplete),
3610 	HTTP(incomplete_timeout),
3611 	HTTP(terminate_chunked),
3612 
3613 	HTTP(highport),
3614 	HTTP(dispatcher),
3615 	HTTP(multi_line_header),
3616 	HTTP(negative_content_length),
3617 	HTTP(chunk_out),
3618 	HTTP(stream_out),
3619 
3620 	HTTP(stream_in),
3621 	HTTP(stream_in_cancel),
3622 
3623 	HTTP(connection_fail),
3624 	HTTP(connection_retry),
3625 	HTTP(data_length_constraints),
3626 
3627 	END_OF_TESTCASES
3628 };
3629 
3630