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