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