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