Changes to update Tomato RAF.
[tomato.git] / release / src / router / dnscrypt / src / libevent / test / regress_http.c
blobaea318f41111451b095657b70880b120fcfad7e6
1 /*
2 * Copyright (c) 2003-2007 Niels Provos <provos@citi.umich.edu>
3 * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson
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.
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.
28 #ifdef WIN32
29 #include <winsock2.h>
30 #include <ws2tcpip.h>
31 #include <windows.h>
32 #endif
34 #include "event2/event-config.h"
36 #include <sys/types.h>
37 #include <sys/stat.h>
38 #ifdef _EVENT_HAVE_SYS_TIME_H
39 #include <sys/time.h>
40 #endif
41 #include <sys/queue.h>
42 #ifndef WIN32
43 #include <sys/socket.h>
44 #include <signal.h>
45 #include <unistd.h>
46 #include <netdb.h>
47 #endif
48 #include <fcntl.h>
49 #include <stdlib.h>
50 #include <stdio.h>
51 #include <string.h>
52 #include <errno.h>
54 #include "event2/dns.h"
56 #include "event2/event.h"
57 #include "event2/http.h"
58 #include "event2/buffer.h"
59 #include "event2/bufferevent.h"
60 #include "event2/util.h"
61 #include "log-internal.h"
62 #include "util-internal.h"
63 #include "http-internal.h"
64 #include "regress.h"
65 #include "regress_testutils.h"
67 static struct evhttp *http;
68 /* set if a test needs to call loopexit on a base */
69 static struct event_base *exit_base;
71 static char const BASIC_REQUEST_BODY[] = "This is funny";
73 static void http_basic_cb(struct evhttp_request *req, void *arg);
74 static void http_chunked_cb(struct evhttp_request *req, void *arg);
75 static void http_post_cb(struct evhttp_request *req, void *arg);
76 static void http_put_cb(struct evhttp_request *req, void *arg);
77 static void http_delete_cb(struct evhttp_request *req, void *arg);
78 static void http_delay_cb(struct evhttp_request *req, void *arg);
79 static void http_large_delay_cb(struct evhttp_request *req, void *arg);
80 static void http_badreq_cb(struct evhttp_request *req, void *arg);
81 static void http_dispatcher_cb(struct evhttp_request *req, void *arg);
82 static int
83 http_bind(struct evhttp *myhttp, ev_uint16_t *pport)
85 int port;
86 struct evhttp_bound_socket *sock;
88 sock = evhttp_bind_socket_with_handle(myhttp, "127.0.0.1", *pport);
89 if (sock == NULL)
90 event_errx(1, "Could not start web server");
92 port = regress_get_socket_port(evhttp_bound_socket_get_fd(sock));
93 if (port < 0)
94 return -1;
95 *pport = (ev_uint16_t) port;
97 return 0;
100 static struct evhttp *
101 http_setup(ev_uint16_t *pport, struct event_base *base)
103 struct evhttp *myhttp;
105 /* Try a few different ports */
106 myhttp = evhttp_new(base);
108 if (http_bind(myhttp, pport) < 0)
109 return NULL;
111 /* Register a callback for certain types of requests */
112 evhttp_set_cb(myhttp, "/test", http_basic_cb, base);
113 evhttp_set_cb(myhttp, "/chunked", http_chunked_cb, base);
114 evhttp_set_cb(myhttp, "/streamed", http_chunked_cb, base);
115 evhttp_set_cb(myhttp, "/postit", http_post_cb, base);
116 evhttp_set_cb(myhttp, "/putit", http_put_cb, base);
117 evhttp_set_cb(myhttp, "/deleteit", http_delete_cb, base);
118 evhttp_set_cb(myhttp, "/delay", http_delay_cb, base);
119 evhttp_set_cb(myhttp, "/largedelay", http_large_delay_cb, base);
120 evhttp_set_cb(myhttp, "/badrequest", http_badreq_cb, base);
121 evhttp_set_cb(myhttp, "/", http_dispatcher_cb, base);
122 return (myhttp);
125 #ifndef NI_MAXSERV
126 #define NI_MAXSERV 1024
127 #endif
129 static evutil_socket_t
130 http_connect(const char *address, u_short port)
132 /* Stupid code for connecting */
133 struct evutil_addrinfo ai, *aitop;
134 char strport[NI_MAXSERV];
136 struct sockaddr *sa;
137 int slen;
138 evutil_socket_t fd;
140 memset(&ai, 0, sizeof(ai));
141 ai.ai_family = AF_INET;
142 ai.ai_socktype = SOCK_STREAM;
143 evutil_snprintf(strport, sizeof(strport), "%d", port);
144 if (evutil_getaddrinfo(address, strport, &ai, &aitop) != 0) {
145 event_warn("getaddrinfo");
146 return (-1);
148 sa = aitop->ai_addr;
149 slen = aitop->ai_addrlen;
151 fd = socket(AF_INET, SOCK_STREAM, 0);
152 if (fd == -1)
153 event_err(1, "socket failed");
155 evutil_make_socket_nonblocking(fd);
156 if (connect(fd, sa, slen) == -1) {
157 #ifdef WIN32
158 int tmp_err = WSAGetLastError();
159 if (tmp_err != WSAEINPROGRESS && tmp_err != WSAEINVAL &&
160 tmp_err != WSAEWOULDBLOCK)
161 event_err(1, "connect failed");
162 #else
163 if (errno != EINPROGRESS)
164 event_err(1, "connect failed");
165 #endif
168 evutil_freeaddrinfo(aitop);
170 return (fd);
173 /* Helper: do a strcmp on the contents of buf and the string s. */
174 static int
175 evbuffer_datacmp(struct evbuffer *buf, const char *s)
177 size_t b_sz = evbuffer_get_length(buf);
178 size_t s_sz = strlen(s);
179 unsigned char *d;
180 int r;
182 if (b_sz < s_sz)
183 return -1;
185 d = evbuffer_pullup(buf, s_sz);
186 if ((r = memcmp(d, s, s_sz)))
187 return r;
189 if (b_sz > s_sz)
190 return 1;
191 else
192 return 0;
195 /* Helper: Return true iff buf contains s */
196 static int
197 evbuffer_contains(struct evbuffer *buf, const char *s)
199 struct evbuffer_ptr ptr;
200 ptr = evbuffer_search(buf, s, strlen(s), NULL);
201 return ptr.pos != -1;
204 static void
205 http_readcb(struct bufferevent *bev, void *arg)
207 const char *what = BASIC_REQUEST_BODY;
208 struct event_base *my_base = arg;
210 if (evbuffer_contains(bufferevent_get_input(bev), what)) {
211 struct evhttp_request *req = evhttp_request_new(NULL, NULL);
212 enum message_read_status done;
214 /* req->kind = EVHTTP_RESPONSE; */
215 done = evhttp_parse_firstline(req, bufferevent_get_input(bev));
216 if (done != ALL_DATA_READ)
217 goto out;
219 done = evhttp_parse_headers(req, bufferevent_get_input(bev));
220 if (done != ALL_DATA_READ)
221 goto out;
223 if (done == 1 &&
224 evhttp_find_header(evhttp_request_get_input_headers(req),
225 "Content-Type") != NULL)
226 test_ok++;
228 out:
229 evhttp_request_free(req);
230 bufferevent_disable(bev, EV_READ);
231 if (exit_base)
232 event_base_loopexit(exit_base, NULL);
233 else if (my_base)
234 event_base_loopexit(my_base, NULL);
235 else {
236 fprintf(stderr, "No way to exit loop!\n");
237 exit(1);
242 static void
243 http_writecb(struct bufferevent *bev, void *arg)
245 if (evbuffer_get_length(bufferevent_get_output(bev)) == 0) {
246 /* enable reading of the reply */
247 bufferevent_enable(bev, EV_READ);
248 test_ok++;
252 static void
253 http_errorcb(struct bufferevent *bev, short what, void *arg)
255 test_ok = -2;
256 event_base_loopexit(arg, NULL);
259 static void
260 http_basic_cb(struct evhttp_request *req, void *arg)
262 struct evbuffer *evb = evbuffer_new();
263 int empty = evhttp_find_header(evhttp_request_get_input_headers(req), "Empty") != NULL;
264 event_debug(("%s: called\n", __func__));
265 evbuffer_add_printf(evb, BASIC_REQUEST_BODY);
267 /* For multi-line headers test */
269 const char *multi =
270 evhttp_find_header(evhttp_request_get_input_headers(req),"X-multi");
271 if (multi) {
272 if (strcmp("END", multi + strlen(multi) - 3) == 0)
273 test_ok++;
274 if (evhttp_find_header(evhttp_request_get_input_headers(req), "X-Last"))
275 test_ok++;
279 /* injecting a bad content-length */
280 if (evhttp_find_header(evhttp_request_get_input_headers(req), "X-Negative"))
281 evhttp_add_header(evhttp_request_get_output_headers(req),
282 "Content-Length", "-100");
284 /* allow sending of an empty reply */
285 evhttp_send_reply(req, HTTP_OK, "Everything is fine",
286 !empty ? evb : NULL);
288 evbuffer_free(evb);
291 static char const* const CHUNKS[] = {
292 "This is funny",
293 "but not hilarious.",
294 "bwv 1052"
297 struct chunk_req_state {
298 struct event_base *base;
299 struct evhttp_request *req;
300 int i;
303 static void
304 http_chunked_trickle_cb(evutil_socket_t fd, short events, void *arg)
306 struct evbuffer *evb = evbuffer_new();
307 struct chunk_req_state *state = arg;
308 struct timeval when = { 0, 0 };
310 evbuffer_add_printf(evb, "%s", CHUNKS[state->i]);
311 evhttp_send_reply_chunk(state->req, evb);
312 evbuffer_free(evb);
314 if (++state->i < (int) (sizeof(CHUNKS)/sizeof(CHUNKS[0]))) {
315 event_base_once(state->base, -1, EV_TIMEOUT,
316 http_chunked_trickle_cb, state, &when);
317 } else {
318 evhttp_send_reply_end(state->req);
319 free(state);
323 static void
324 http_chunked_cb(struct evhttp_request *req, void *arg)
326 struct timeval when = { 0, 0 };
327 struct chunk_req_state *state = malloc(sizeof(struct chunk_req_state));
328 event_debug(("%s: called\n", __func__));
330 memset(state, 0, sizeof(struct chunk_req_state));
331 state->req = req;
332 state->base = arg;
334 if (strcmp(evhttp_request_get_uri(req), "/streamed") == 0) {
335 evhttp_add_header(evhttp_request_get_output_headers(req), "Content-Length", "39");
338 /* generate a chunked/streamed reply */
339 evhttp_send_reply_start(req, HTTP_OK, "Everything is fine");
341 /* but trickle it across several iterations to ensure we're not
342 * assuming it comes all at once */
343 event_base_once(arg, -1, EV_TIMEOUT, http_chunked_trickle_cb, state, &when);
346 static void
347 http_complete_write(evutil_socket_t fd, short what, void *arg)
349 struct bufferevent *bev = arg;
350 const char *http_request = "host\r\n"
351 "Connection: close\r\n"
352 "\r\n";
353 bufferevent_write(bev, http_request, strlen(http_request));
356 static void
357 http_basic_test(void *arg)
359 struct basic_test_data *data = arg;
360 struct timeval tv;
361 struct bufferevent *bev;
362 evutil_socket_t fd;
363 const char *http_request;
364 ev_uint16_t port = 0, port2 = 0;
366 test_ok = 0;
368 http = http_setup(&port, data->base);
370 /* bind to a second socket */
371 if (http_bind(http, &port2) == -1) {
372 fprintf(stdout, "FAILED (bind)\n");
373 exit(1);
376 fd = http_connect("127.0.0.1", port);
378 /* Stupid thing to send a request */
379 bev = bufferevent_socket_new(data->base, fd, 0);
380 bufferevent_setcb(bev, http_readcb, http_writecb,
381 http_errorcb, data->base);
383 /* first half of the http request */
384 http_request =
385 "GET /test HTTP/1.1\r\n"
386 "Host: some";
388 bufferevent_write(bev, http_request, strlen(http_request));
389 evutil_timerclear(&tv);
390 tv.tv_usec = 10000;
391 event_base_once(data->base,
392 -1, EV_TIMEOUT, http_complete_write, bev, &tv);
394 event_base_dispatch(data->base);
396 tt_assert(test_ok == 3);
398 /* connect to the second port */
399 bufferevent_free(bev);
400 evutil_closesocket(fd);
402 fd = http_connect("127.0.0.1", port2);
404 /* Stupid thing to send a request */
405 bev = bufferevent_socket_new(data->base, fd, 0);
406 bufferevent_setcb(bev, http_readcb, http_writecb,
407 http_errorcb, data->base);
409 http_request =
410 "GET /test HTTP/1.1\r\n"
411 "Host: somehost\r\n"
412 "Connection: close\r\n"
413 "\r\n";
415 bufferevent_write(bev, http_request, strlen(http_request));
417 event_base_dispatch(data->base);
419 tt_assert(test_ok == 5);
421 /* Connect to the second port again. This time, send an absolute uri. */
422 bufferevent_free(bev);
423 evutil_closesocket(fd);
425 fd = http_connect("127.0.0.1", port2);
427 /* Stupid thing to send a request */
428 bev = bufferevent_socket_new(data->base, fd, 0);
429 bufferevent_setcb(bev, http_readcb, http_writecb,
430 http_errorcb, data->base);
432 http_request =
433 "GET http://somehost.net/test HTTP/1.1\r\n"
434 "Host: somehost\r\n"
435 "Connection: close\r\n"
436 "\r\n";
438 bufferevent_write(bev, http_request, strlen(http_request));
440 event_base_dispatch(data->base);
442 tt_assert(test_ok == 7);
444 evhttp_free(http);
445 end:
449 static void
450 http_delay_reply(evutil_socket_t fd, short what, void *arg)
452 struct evhttp_request *req = arg;
454 evhttp_send_reply(req, HTTP_OK, "Everything is fine", NULL);
456 ++test_ok;
459 static void
460 http_delay_cb(struct evhttp_request *req, void *arg)
462 struct timeval tv;
463 evutil_timerclear(&tv);
464 tv.tv_sec = 0;
465 tv.tv_usec = 200 * 1000;
467 event_base_once(arg, -1, EV_TIMEOUT, http_delay_reply, req, &tv);
470 static void
471 http_badreq_cb(struct evhttp_request *req, void *arg)
473 struct evbuffer *buf = evbuffer_new();
475 evhttp_add_header(evhttp_request_get_output_headers(req), "Content-Type", "text/xml; charset=UTF-8");
476 evbuffer_add_printf(buf, "Hello, %s!", "127.0.0.1");
478 evhttp_send_reply(req, HTTP_OK, "OK", buf);
479 evbuffer_free(buf);
482 static void
483 http_badreq_errorcb(struct bufferevent *bev, short what, void *arg)
485 event_debug(("%s: called (what=%04x, arg=%p)", __func__, what, arg));
486 /* ignore */
489 #ifndef SHUT_WR
490 #ifdef WIN32
491 #define SHUT_WR SD_SEND
492 #else
493 #define SHUT_WR 1
494 #endif
495 #endif
497 static void
498 http_badreq_readcb(struct bufferevent *bev, void *arg)
500 const char *what = "Hello, 127.0.0.1";
501 const char *bad_request = "400 Bad Request";
503 if (evbuffer_contains(bufferevent_get_input(bev), bad_request)) {
504 TT_FAIL(("%s:bad request detected", __func__));
505 bufferevent_disable(bev, EV_READ);
506 event_base_loopexit(arg, NULL);
507 return;
510 if (evbuffer_contains(bufferevent_get_input(bev), what)) {
511 struct evhttp_request *req = evhttp_request_new(NULL, NULL);
512 enum message_read_status done;
514 /* req->kind = EVHTTP_RESPONSE; */
515 done = evhttp_parse_firstline(req, bufferevent_get_input(bev));
516 if (done != ALL_DATA_READ)
517 goto out;
519 done = evhttp_parse_headers(req, bufferevent_get_input(bev));
520 if (done != ALL_DATA_READ)
521 goto out;
523 if (done == 1 &&
524 evhttp_find_header(evhttp_request_get_input_headers(req),
525 "Content-Type") != NULL)
526 test_ok++;
528 out:
529 evhttp_request_free(req);
530 evbuffer_drain(bufferevent_get_input(bev), evbuffer_get_length(bufferevent_get_input(bev)));
533 shutdown(bufferevent_getfd(bev), SHUT_WR);
536 static void
537 http_badreq_successcb(evutil_socket_t fd, short what, void *arg)
539 event_debug(("%s: called (what=%04x, arg=%p)", __func__, what, arg));
540 event_base_loopexit(exit_base, NULL);
543 static void
544 http_bad_request_test(void *arg)
546 struct basic_test_data *data = arg;
547 struct timeval tv;
548 struct bufferevent *bev = NULL;
549 evutil_socket_t fd;
550 const char *http_request;
551 ev_uint16_t port=0, port2=0;
553 test_ok = 0;
554 exit_base = data->base;
556 http = http_setup(&port, data->base);
558 /* bind to a second socket */
559 if (http_bind(http, &port2) == -1)
560 TT_DIE(("Bind socket failed"));
562 /* NULL request test */
563 fd = http_connect("127.0.0.1", port);
565 /* Stupid thing to send a request */
566 bev = bufferevent_socket_new(data->base, fd, 0);
567 bufferevent_setcb(bev, http_badreq_readcb, http_writecb,
568 http_badreq_errorcb, data->base);
569 bufferevent_enable(bev, EV_READ);
571 /* real NULL request */
572 http_request = "";
574 bufferevent_write(bev, http_request, strlen(http_request));
576 shutdown(fd, SHUT_WR);
577 timerclear(&tv);
578 tv.tv_usec = 10000;
579 event_base_once(data->base, -1, EV_TIMEOUT, http_badreq_successcb, bev, &tv);
581 event_base_dispatch(data->base);
583 bufferevent_free(bev);
584 evutil_closesocket(fd);
586 if (test_ok != 0) {
587 fprintf(stdout, "FAILED\n");
588 exit(1);
591 /* Second answer (BAD REQUEST) on connection close */
593 /* connect to the second port */
594 fd = http_connect("127.0.0.1", port2);
596 /* Stupid thing to send a request */
597 bev = bufferevent_socket_new(data->base, fd, 0);
598 bufferevent_setcb(bev, http_badreq_readcb, http_writecb,
599 http_badreq_errorcb, data->base);
600 bufferevent_enable(bev, EV_READ);
602 /* first half of the http request */
603 http_request =
604 "GET /badrequest HTTP/1.0\r\n" \
605 "Connection: Keep-Alive\r\n" \
606 "\r\n";
608 bufferevent_write(bev, http_request, strlen(http_request));
610 timerclear(&tv);
611 tv.tv_usec = 10000;
612 event_base_once(data->base, -1, EV_TIMEOUT, http_badreq_successcb, bev, &tv);
614 event_base_dispatch(data->base);
616 tt_int_op(test_ok, ==, 2);
618 end:
619 evhttp_free(http);
620 if (bev)
621 bufferevent_free(bev);
624 static struct evhttp_connection *delayed_client;
626 static void
627 http_large_delay_cb(struct evhttp_request *req, void *arg)
629 struct timeval tv;
630 evutil_timerclear(&tv);
631 tv.tv_sec = 3;
633 event_base_once(arg, -1, EV_TIMEOUT, http_delay_reply, req, &tv);
634 evhttp_connection_fail(delayed_client, EVCON_HTTP_EOF);
638 * HTTP DELETE test, just piggyback on the basic test
641 static void
642 http_delete_cb(struct evhttp_request *req, void *arg)
644 struct evbuffer *evb = evbuffer_new();
645 int empty = evhttp_find_header(evhttp_request_get_input_headers(req), "Empty") != NULL;
647 /* Expecting a DELETE request */
648 if (evhttp_request_get_command(req) != EVHTTP_REQ_DELETE) {
649 fprintf(stdout, "FAILED (delete type)\n");
650 exit(1);
653 event_debug(("%s: called\n", __func__));
654 evbuffer_add_printf(evb, BASIC_REQUEST_BODY);
656 /* allow sending of an empty reply */
657 evhttp_send_reply(req, HTTP_OK, "Everything is fine",
658 !empty ? evb : NULL);
660 evbuffer_free(evb);
663 static void
664 http_delete_test(void *arg)
666 struct basic_test_data *data = arg;
667 struct bufferevent *bev;
668 evutil_socket_t fd;
669 const char *http_request;
670 ev_uint16_t port = 0;
672 test_ok = 0;
674 http = http_setup(&port, data->base);
676 fd = http_connect("127.0.0.1", port);
678 /* Stupid thing to send a request */
679 bev = bufferevent_socket_new(data->base, fd, 0);
680 bufferevent_setcb(bev, http_readcb, http_writecb,
681 http_errorcb, data->base);
683 http_request =
684 "DELETE /deleteit HTTP/1.1\r\n"
685 "Host: somehost\r\n"
686 "Connection: close\r\n"
687 "\r\n";
689 bufferevent_write(bev, http_request, strlen(http_request));
691 event_base_dispatch(data->base);
693 bufferevent_free(bev);
694 evutil_closesocket(fd);
696 evhttp_free(http);
698 tt_int_op(test_ok, ==, 2);
699 end:
703 static void
704 http_allowed_methods_eventcb(struct bufferevent *bev, short what, void *arg)
706 char **output = arg;
707 if ((what & (BEV_EVENT_ERROR|BEV_EVENT_EOF))) {
708 char buf[4096];
709 int n;
710 n = evbuffer_remove(bufferevent_get_input(bev), buf,
711 sizeof(buf)-1);
712 if (n >= 0) {
713 buf[n]='\0';
714 if (*output)
715 free(*output);
716 *output = strdup(buf);
718 event_base_loopexit(exit_base, NULL);
722 static void
723 http_allowed_methods_test(void *arg)
725 struct basic_test_data *data = arg;
726 struct bufferevent *bev1, *bev2, *bev3;
727 evutil_socket_t fd1, fd2, fd3;
728 const char *http_request;
729 char *result1=NULL, *result2=NULL, *result3=NULL;
730 ev_uint16_t port = 0;
732 exit_base = data->base;
733 test_ok = 0;
735 http = http_setup(&port, data->base);
737 fd1 = http_connect("127.0.0.1", port);
739 /* GET is out; PATCH is in. */
740 evhttp_set_allowed_methods(http, EVHTTP_REQ_PATCH);
742 /* Stupid thing to send a request */
743 bev1 = bufferevent_socket_new(data->base, fd1, 0);
744 bufferevent_enable(bev1, EV_READ|EV_WRITE);
745 bufferevent_setcb(bev1, NULL, NULL,
746 http_allowed_methods_eventcb, &result1);
748 http_request =
749 "GET /index.html HTTP/1.1\r\n"
750 "Host: somehost\r\n"
751 "Connection: close\r\n"
752 "\r\n";
754 bufferevent_write(bev1, http_request, strlen(http_request));
756 event_base_dispatch(data->base);
758 fd2 = http_connect("127.0.0.1", port);
760 bev2 = bufferevent_socket_new(data->base, fd2, 0);
761 bufferevent_enable(bev2, EV_READ|EV_WRITE);
762 bufferevent_setcb(bev2, NULL, NULL,
763 http_allowed_methods_eventcb, &result2);
765 http_request =
766 "PATCH /test HTTP/1.1\r\n"
767 "Host: somehost\r\n"
768 "Connection: close\r\n"
769 "\r\n";
771 bufferevent_write(bev2, http_request, strlen(http_request));
773 event_base_dispatch(data->base);
775 fd3 = http_connect("127.0.0.1", port);
777 bev3 = bufferevent_socket_new(data->base, fd3, 0);
778 bufferevent_enable(bev3, EV_READ|EV_WRITE);
779 bufferevent_setcb(bev3, NULL, NULL,
780 http_allowed_methods_eventcb, &result3);
782 http_request =
783 "FLOOP /test HTTP/1.1\r\n"
784 "Host: somehost\r\n"
785 "Connection: close\r\n"
786 "\r\n";
788 bufferevent_write(bev3, http_request, strlen(http_request));
790 event_base_dispatch(data->base);
792 bufferevent_free(bev1);
793 bufferevent_free(bev2);
794 bufferevent_free(bev3);
795 evutil_closesocket(fd1);
796 evutil_closesocket(fd2);
797 evutil_closesocket(fd3);
799 evhttp_free(http);
801 /* Method known but disallowed */
802 tt_assert(result1);
803 tt_assert(!strncmp(result1, "HTTP/1.1 501 ", strlen("HTTP/1.1 501 ")));
805 /* Method known and allowed */
806 tt_assert(result2);
807 tt_assert(!strncmp(result2, "HTTP/1.1 200 ", strlen("HTTP/1.1 200 ")));
809 /* Method unknown */
810 tt_assert(result3);
811 tt_assert(!strncmp(result3, "HTTP/1.1 501 ", strlen("HTTP/1.1 501 ")));
813 end:
814 if (result1)
815 free(result1);
816 if (result2)
817 free(result2);
818 if (result3)
819 free(result3);
822 static void http_request_done(struct evhttp_request *, void *);
823 static void http_request_empty_done(struct evhttp_request *, void *);
825 static void
826 _http_connection_test(struct basic_test_data *data, int persistent)
828 ev_uint16_t port = 0;
829 struct evhttp_connection *evcon = NULL;
830 struct evhttp_request *req = NULL;
832 test_ok = 0;
834 http = http_setup(&port, data->base);
836 evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port);
837 tt_assert(evcon);
839 tt_assert(evhttp_connection_get_base(evcon) == data->base);
841 exit_base = data->base;
843 * At this point, we want to schedule a request to the HTTP
844 * server using our make request method.
847 req = evhttp_request_new(http_request_done, (void*) BASIC_REQUEST_BODY);
849 /* Add the information that we care about */
850 evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
852 /* We give ownership of the request to the connection */
853 if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test") == -1) {
854 fprintf(stdout, "FAILED\n");
855 exit(1);
858 event_base_dispatch(data->base);
860 tt_assert(test_ok);
862 /* try to make another request over the same connection */
863 test_ok = 0;
865 req = evhttp_request_new(http_request_done, (void*) BASIC_REQUEST_BODY);
867 /* Add the information that we care about */
868 evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
871 * if our connections are not supposed to be persistent; request
872 * a close from the server.
874 if (!persistent)
875 evhttp_add_header(evhttp_request_get_output_headers(req), "Connection", "close");
877 /* We give ownership of the request to the connection */
878 if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test") == -1) {
879 tt_abort_msg("couldn't make request");
882 event_base_dispatch(data->base);
884 /* make another request: request empty reply */
885 test_ok = 0;
887 req = evhttp_request_new(http_request_empty_done, data->base);
889 /* Add the information that we care about */
890 evhttp_add_header(evhttp_request_get_output_headers(req), "Empty", "itis");
892 /* We give ownership of the request to the connection */
893 if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test") == -1) {
894 tt_abort_msg("Couldn't make request");
895 exit(1);
898 event_base_dispatch(data->base);
900 end:
901 if (evcon)
902 evhttp_connection_free(evcon);
903 if (http)
904 evhttp_free(http);
907 static void
908 http_connection_test(void *arg)
910 _http_connection_test(arg, 0);
912 static void
913 http_persist_connection_test(void *arg)
915 _http_connection_test(arg, 1);
918 static struct regress_dns_server_table search_table[] = {
919 { "localhost", "A", "127.0.0.1", 0 },
920 { NULL, NULL, NULL, 0 }
923 static void
924 http_connection_async_test(void *arg)
926 struct basic_test_data *data = arg;
927 ev_uint16_t port = 0;
928 struct evhttp_connection *evcon = NULL;
929 struct evhttp_request *req = NULL;
930 struct evdns_base *dns_base = NULL;
931 ev_uint16_t portnum = 0;
932 char address[64];
934 exit_base = data->base;
935 tt_assert(regress_dnsserver(data->base, &portnum, search_table));
937 dns_base = evdns_base_new(data->base, 0/* init name servers */);
938 tt_assert(dns_base);
940 /* Add ourself as the only nameserver, and make sure we really are
941 * the only nameserver. */
942 evutil_snprintf(address, sizeof(address), "127.0.0.1:%d", portnum);
943 evdns_base_nameserver_ip_add(dns_base, address);
945 test_ok = 0;
947 http = http_setup(&port, data->base);
949 evcon = evhttp_connection_base_new(data->base, dns_base, "127.0.0.1", port);
950 tt_assert(evcon);
953 * At this point, we want to schedule a request to the HTTP
954 * server using our make request method.
957 req = evhttp_request_new(http_request_done, (void*) BASIC_REQUEST_BODY);
959 /* Add the information that we care about */
960 evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
962 /* We give ownership of the request to the connection */
963 if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test") == -1) {
964 fprintf(stdout, "FAILED\n");
965 exit(1);
968 event_base_dispatch(data->base);
970 tt_assert(test_ok);
972 /* try to make another request over the same connection */
973 test_ok = 0;
975 req = evhttp_request_new(http_request_done, (void*) BASIC_REQUEST_BODY);
977 /* Add the information that we care about */
978 evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
981 * if our connections are not supposed to be persistent; request
982 * a close from the server.
984 evhttp_add_header(evhttp_request_get_output_headers(req), "Connection", "close");
986 /* We give ownership of the request to the connection */
987 if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test") == -1) {
988 tt_abort_msg("couldn't make request");
991 event_base_dispatch(data->base);
993 /* make another request: request empty reply */
994 test_ok = 0;
996 req = evhttp_request_new(http_request_empty_done, data->base);
998 /* Add the information that we care about */
999 evhttp_add_header(evhttp_request_get_output_headers(req), "Empty", "itis");
1001 /* We give ownership of the request to the connection */
1002 if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test") == -1) {
1003 tt_abort_msg("Couldn't make request");
1004 exit(1);
1007 event_base_dispatch(data->base);
1009 end:
1010 if (evcon)
1011 evhttp_connection_free(evcon);
1012 if (http)
1013 evhttp_free(http);
1014 if (dns_base)
1015 evdns_base_free(dns_base, 0);
1016 regress_clean_dnsserver();
1019 static void
1020 http_request_never_call(struct evhttp_request *req, void *arg)
1022 fprintf(stdout, "FAILED\n");
1023 exit(1);
1026 static void
1027 http_do_cancel(evutil_socket_t fd, short what, void *arg)
1029 struct evhttp_request *req = arg;
1030 struct timeval tv;
1031 struct event_base *base;
1032 evutil_timerclear(&tv);
1033 tv.tv_sec = 0;
1034 tv.tv_usec = 500 * 1000;
1036 base = evhttp_connection_get_base(evhttp_request_get_connection(req));
1037 evhttp_cancel_request(req);
1039 event_base_loopexit(base, &tv);
1041 ++test_ok;
1044 static void
1045 http_cancel_test(void *arg)
1047 struct basic_test_data *data = arg;
1048 ev_uint16_t port = 0;
1049 struct evhttp_connection *evcon = NULL;
1050 struct evhttp_request *req = NULL;
1051 struct timeval tv;
1053 exit_base = data->base;
1055 test_ok = 0;
1057 http = http_setup(&port, data->base);
1059 evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port);
1060 tt_assert(evcon);
1063 * At this point, we want to schedule a request to the HTTP
1064 * server using our make request method.
1067 req = evhttp_request_new(http_request_never_call, NULL);
1069 /* Add the information that we care about */
1070 evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
1072 /* We give ownership of the request to the connection */
1073 tt_int_op(evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/delay"),
1074 !=, -1);
1076 evutil_timerclear(&tv);
1077 tv.tv_sec = 0;
1078 tv.tv_usec = 100 * 1000;
1080 event_base_once(data->base, -1, EV_TIMEOUT, http_do_cancel, req, &tv);
1082 event_base_dispatch(data->base);
1084 tt_int_op(test_ok, ==, 2);
1086 /* try to make another request over the same connection */
1087 test_ok = 0;
1089 req = evhttp_request_new(http_request_done, (void*) BASIC_REQUEST_BODY);
1091 /* Add the information that we care about */
1092 evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
1094 /* We give ownership of the request to the connection */
1095 tt_int_op(evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test"),
1096 !=, -1);
1098 event_base_dispatch(data->base);
1100 /* make another request: request empty reply */
1101 test_ok = 0;
1103 req = evhttp_request_new(http_request_empty_done, data->base);
1105 /* Add the information that we care about */
1106 evhttp_add_header(evhttp_request_get_output_headers(req), "Empty", "itis");
1108 /* We give ownership of the request to the connection */
1109 tt_int_op(evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test"),
1110 !=, -1);
1112 event_base_dispatch(data->base);
1114 end:
1115 if (evcon)
1116 evhttp_connection_free(evcon);
1117 if (http)
1118 evhttp_free(http);
1121 static void
1122 http_request_done(struct evhttp_request *req, void *arg)
1124 const char *what = arg;
1126 if (evhttp_request_get_response_code(req) != HTTP_OK) {
1127 fprintf(stderr, "FAILED\n");
1128 exit(1);
1131 if (evhttp_find_header(evhttp_request_get_input_headers(req), "Content-Type") == NULL) {
1132 fprintf(stderr, "FAILED\n");
1133 exit(1);
1136 if (evbuffer_get_length(evhttp_request_get_input_buffer(req)) != strlen(what)) {
1137 fprintf(stderr, "FAILED\n");
1138 exit(1);
1141 if (evbuffer_datacmp(evhttp_request_get_input_buffer(req), what) != 0) {
1142 fprintf(stderr, "FAILED\n");
1143 exit(1);
1146 test_ok = 1;
1147 EVUTIL_ASSERT(exit_base);
1148 event_base_loopexit(exit_base, NULL);
1151 static void
1152 http_request_expect_error(struct evhttp_request *req, void *arg)
1154 if (evhttp_request_get_response_code(req) == HTTP_OK) {
1155 fprintf(stderr, "FAILED\n");
1156 exit(1);
1159 test_ok = 1;
1160 EVUTIL_ASSERT(arg);
1161 event_base_loopexit(arg, NULL);
1164 /* test virtual hosts */
1165 static void
1166 http_virtual_host_test(void *arg)
1168 struct basic_test_data *data = arg;
1169 ev_uint16_t port = 0;
1170 struct evhttp_connection *evcon = NULL;
1171 struct evhttp_request *req = NULL;
1172 struct evhttp *second = NULL, *third = NULL;
1173 evutil_socket_t fd;
1174 struct bufferevent *bev;
1175 const char *http_request;
1177 exit_base = data->base;
1179 http = http_setup(&port, data->base);
1181 /* virtual host */
1182 second = evhttp_new(NULL);
1183 evhttp_set_cb(second, "/funnybunny", http_basic_cb, NULL);
1184 third = evhttp_new(NULL);
1185 evhttp_set_cb(third, "/blackcoffee", http_basic_cb, NULL);
1187 if (evhttp_add_virtual_host(http, "foo.com", second) == -1) {
1188 tt_abort_msg("Couldn't add vhost");
1191 if (evhttp_add_virtual_host(http, "bar.*.foo.com", third) == -1) {
1192 tt_abort_msg("Couldn't add wildcarded vhost");
1195 /* add some aliases to the vhosts */
1196 tt_assert(evhttp_add_server_alias(second, "manolito.info") == 0);
1197 tt_assert(evhttp_add_server_alias(third, "bonkers.org") == 0);
1199 evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port);
1200 tt_assert(evcon);
1202 /* make a request with a different host and expect an error */
1203 req = evhttp_request_new(http_request_expect_error, data->base);
1205 /* Add the information that we care about */
1206 evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
1208 /* We give ownership of the request to the connection */
1209 if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET,
1210 "/funnybunny") == -1) {
1211 tt_abort_msg("Couldn't make request");
1214 event_base_dispatch(data->base);
1216 tt_assert(test_ok == 1);
1218 test_ok = 0;
1220 /* make a request with the right host and expect a response */
1221 req = evhttp_request_new(http_request_done, (void*) BASIC_REQUEST_BODY);
1223 /* Add the information that we care about */
1224 evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "foo.com");
1226 /* We give ownership of the request to the connection */
1227 if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET,
1228 "/funnybunny") == -1) {
1229 fprintf(stdout, "FAILED\n");
1230 exit(1);
1233 event_base_dispatch(data->base);
1235 tt_assert(test_ok == 1);
1237 test_ok = 0;
1239 /* make a request with the right host and expect a response */
1240 req = evhttp_request_new(http_request_done, (void*) BASIC_REQUEST_BODY);
1242 /* Add the information that we care about */
1243 evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "bar.magic.foo.com");
1245 /* We give ownership of the request to the connection */
1246 if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET,
1247 "/blackcoffee") == -1) {
1248 tt_abort_msg("Couldn't make request");
1251 event_base_dispatch(data->base);
1253 tt_assert(test_ok == 1)
1255 test_ok = 0;
1257 /* make a request with the right host and expect a response */
1258 req = evhttp_request_new(http_request_done, (void*) BASIC_REQUEST_BODY);
1260 /* Add the information that we care about */
1261 evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "manolito.info");
1263 /* We give ownership of the request to the connection */
1264 if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET,
1265 "/funnybunny") == -1) {
1266 tt_abort_msg("Couldn't make request");
1269 event_base_dispatch(data->base);
1271 tt_assert(test_ok == 1)
1273 test_ok = 0;
1275 /* make a request with the right host and expect a response */
1276 req = evhttp_request_new(http_request_done, (void*) BASIC_REQUEST_BODY);
1278 /* Add the Host header. This time with the optional port. */
1279 evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "bonkers.org:8000");
1281 /* We give ownership of the request to the connection */
1282 if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET,
1283 "/blackcoffee") == -1) {
1284 tt_abort_msg("Couldn't make request");
1287 event_base_dispatch(data->base);
1289 tt_assert(test_ok == 1)
1291 test_ok = 0;
1293 /* Now make a raw request with an absolute URI. */
1294 fd = http_connect("127.0.0.1", port);
1296 /* Stupid thing to send a request */
1297 bev = bufferevent_socket_new(data->base, fd, 0);
1298 bufferevent_setcb(bev, http_readcb, http_writecb,
1299 http_errorcb, NULL);
1301 /* The host in the URI should override the Host: header */
1302 http_request =
1303 "GET http://manolito.info/funnybunny HTTP/1.1\r\n"
1304 "Host: somehost\r\n"
1305 "Connection: close\r\n"
1306 "\r\n";
1308 bufferevent_write(bev, http_request, strlen(http_request));
1310 event_base_dispatch(data->base);
1312 tt_int_op(test_ok, ==, 2);
1314 bufferevent_free(bev);
1315 evutil_closesocket(fd);
1317 end:
1318 if (evcon)
1319 evhttp_connection_free(evcon);
1320 if (http)
1321 evhttp_free(http);
1325 /* test date header and content length */
1327 static void
1328 http_request_empty_done(struct evhttp_request *req, void *arg)
1330 if (evhttp_request_get_response_code(req) != HTTP_OK) {
1331 fprintf(stderr, "FAILED\n");
1332 exit(1);
1335 if (evhttp_find_header(evhttp_request_get_input_headers(req), "Date") == NULL) {
1336 fprintf(stderr, "FAILED\n");
1337 exit(1);
1341 if (evhttp_find_header(evhttp_request_get_input_headers(req), "Content-Length") == NULL) {
1342 fprintf(stderr, "FAILED\n");
1343 exit(1);
1346 if (strcmp(evhttp_find_header(evhttp_request_get_input_headers(req), "Content-Length"),
1347 "0")) {
1348 fprintf(stderr, "FAILED\n");
1349 exit(1);
1352 if (evbuffer_get_length(evhttp_request_get_input_buffer(req)) != 0) {
1353 fprintf(stderr, "FAILED\n");
1354 exit(1);
1357 test_ok = 1;
1358 EVUTIL_ASSERT(arg);
1359 event_base_loopexit(arg, NULL);
1363 * HTTP DISPATCHER test
1366 void
1367 http_dispatcher_cb(struct evhttp_request *req, void *arg)
1370 struct evbuffer *evb = evbuffer_new();
1371 event_debug(("%s: called\n", __func__));
1372 evbuffer_add_printf(evb, "DISPATCHER_TEST");
1374 evhttp_send_reply(req, HTTP_OK, "Everything is fine", evb);
1376 evbuffer_free(evb);
1379 static void
1380 http_dispatcher_test_done(struct evhttp_request *req, void *arg)
1382 struct event_base *base = arg;
1383 const char *what = "DISPATCHER_TEST";
1385 if (evhttp_request_get_response_code(req) != HTTP_OK) {
1386 fprintf(stderr, "FAILED\n");
1387 exit(1);
1390 if (evhttp_find_header(evhttp_request_get_input_headers(req), "Content-Type") == NULL) {
1391 fprintf(stderr, "FAILED (content type)\n");
1392 exit(1);
1395 if (evbuffer_get_length(evhttp_request_get_input_buffer(req)) != strlen(what)) {
1396 fprintf(stderr, "FAILED (length %lu vs %lu)\n",
1397 (unsigned long)evbuffer_get_length(evhttp_request_get_input_buffer(req)), (unsigned long)strlen(what));
1398 exit(1);
1401 if (evbuffer_datacmp(evhttp_request_get_input_buffer(req), what) != 0) {
1402 fprintf(stderr, "FAILED (data)\n");
1403 exit(1);
1406 test_ok = 1;
1407 event_base_loopexit(base, NULL);
1410 static void
1411 http_dispatcher_test(void *arg)
1413 struct basic_test_data *data = arg;
1414 ev_uint16_t port = 0;
1415 struct evhttp_connection *evcon = NULL;
1416 struct evhttp_request *req = NULL;
1418 test_ok = 0;
1420 http = http_setup(&port, data->base);
1422 evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port);
1423 tt_assert(evcon);
1425 /* also bind to local host */
1426 evhttp_connection_set_local_address(evcon, "127.0.0.1");
1429 * At this point, we want to schedule an HTTP GET request
1430 * server using our make request method.
1433 req = evhttp_request_new(http_dispatcher_test_done, data->base);
1434 tt_assert(req);
1436 /* Add the information that we care about */
1437 evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
1439 if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/?arg=val") == -1) {
1440 tt_abort_msg("Couldn't make request");
1443 event_base_dispatch(data->base);
1445 end:
1446 if (evcon)
1447 evhttp_connection_free(evcon);
1448 if (http)
1449 evhttp_free(http);
1453 * HTTP POST test.
1456 void http_postrequest_done(struct evhttp_request *, void *);
1458 #define POST_DATA "Okay. Not really printf"
1460 static void
1461 http_post_test(void *arg)
1463 struct basic_test_data *data = arg;
1464 ev_uint16_t port = 0;
1465 struct evhttp_connection *evcon = NULL;
1466 struct evhttp_request *req = NULL;
1468 test_ok = 0;
1470 http = http_setup(&port, data->base);
1472 evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port);
1473 tt_assert(evcon);
1476 * At this point, we want to schedule an HTTP POST request
1477 * server using our make request method.
1480 req = evhttp_request_new(http_postrequest_done, data->base);
1481 tt_assert(req);
1483 /* Add the information that we care about */
1484 evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
1485 evbuffer_add_printf(evhttp_request_get_output_buffer(req), POST_DATA);
1487 if (evhttp_make_request(evcon, req, EVHTTP_REQ_POST, "/postit") == -1) {
1488 tt_abort_msg("Couldn't make request");
1491 event_base_dispatch(data->base);
1493 tt_int_op(test_ok, ==, 1);
1495 test_ok = 0;
1497 req = evhttp_request_new(http_postrequest_done, data->base);
1498 tt_assert(req);
1500 /* Now try with 100-continue. */
1502 /* Add the information that we care about */
1503 evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
1504 evhttp_add_header(evhttp_request_get_output_headers(req), "Expect", "100-continue");
1505 evbuffer_add_printf(evhttp_request_get_output_buffer(req), POST_DATA);
1507 if (evhttp_make_request(evcon, req, EVHTTP_REQ_POST, "/postit") == -1) {
1508 tt_abort_msg("Couldn't make request");
1511 event_base_dispatch(data->base);
1513 tt_int_op(test_ok, ==, 1);
1515 evhttp_connection_free(evcon);
1516 evhttp_free(http);
1518 end:
1522 void
1523 http_post_cb(struct evhttp_request *req, void *arg)
1525 struct evbuffer *evb;
1526 event_debug(("%s: called\n", __func__));
1528 /* Yes, we are expecting a post request */
1529 if (evhttp_request_get_command(req) != EVHTTP_REQ_POST) {
1530 fprintf(stdout, "FAILED (post type)\n");
1531 exit(1);
1534 if (evbuffer_get_length(evhttp_request_get_input_buffer(req)) != strlen(POST_DATA)) {
1535 fprintf(stdout, "FAILED (length: %lu vs %lu)\n",
1536 (unsigned long) evbuffer_get_length(evhttp_request_get_input_buffer(req)), (unsigned long) strlen(POST_DATA));
1537 exit(1);
1540 if (evbuffer_datacmp(evhttp_request_get_input_buffer(req), POST_DATA) != 0) {
1541 fprintf(stdout, "FAILED (data)\n");
1542 fprintf(stdout, "Got :%s\n", evbuffer_pullup(evhttp_request_get_input_buffer(req),-1));
1543 fprintf(stdout, "Want:%s\n", POST_DATA);
1544 exit(1);
1547 evb = evbuffer_new();
1548 evbuffer_add_printf(evb, BASIC_REQUEST_BODY);
1550 evhttp_send_reply(req, HTTP_OK, "Everything is fine", evb);
1552 evbuffer_free(evb);
1555 void
1556 http_postrequest_done(struct evhttp_request *req, void *arg)
1558 const char *what = BASIC_REQUEST_BODY;
1559 struct event_base *base = arg;
1561 if (req == NULL) {
1562 fprintf(stderr, "FAILED (timeout)\n");
1563 exit(1);
1566 if (evhttp_request_get_response_code(req) != HTTP_OK) {
1568 fprintf(stderr, "FAILED (response code)\n");
1569 exit(1);
1572 if (evhttp_find_header(evhttp_request_get_input_headers(req), "Content-Type") == NULL) {
1573 fprintf(stderr, "FAILED (content type)\n");
1574 exit(1);
1577 if (evbuffer_get_length(evhttp_request_get_input_buffer(req)) != strlen(what)) {
1578 fprintf(stderr, "FAILED (length %lu vs %lu)\n",
1579 (unsigned long)evbuffer_get_length(evhttp_request_get_input_buffer(req)), (unsigned long)strlen(what));
1580 exit(1);
1583 if (evbuffer_datacmp(evhttp_request_get_input_buffer(req), what) != 0) {
1584 fprintf(stderr, "FAILED (data)\n");
1585 exit(1);
1588 test_ok = 1;
1589 event_base_loopexit(base, NULL);
1593 * HTTP PUT test, basically just like POST, but ...
1596 void http_putrequest_done(struct evhttp_request *, void *);
1598 #define PUT_DATA "Hi, I'm some PUT data"
1600 static void
1601 http_put_test(void *arg)
1603 struct basic_test_data *data = arg;
1604 ev_uint16_t port = 0;
1605 struct evhttp_connection *evcon = NULL;
1606 struct evhttp_request *req = NULL;
1608 test_ok = 0;
1610 http = http_setup(&port, data->base);
1612 evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port);
1613 tt_assert(evcon);
1616 * Schedule the HTTP PUT request
1619 req = evhttp_request_new(http_putrequest_done, data->base);
1620 tt_assert(req);
1622 /* Add the information that we care about */
1623 evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "someotherhost");
1624 evbuffer_add_printf(evhttp_request_get_output_buffer(req), PUT_DATA);
1626 if (evhttp_make_request(evcon, req, EVHTTP_REQ_PUT, "/putit") == -1) {
1627 tt_abort_msg("Couldn't make request");
1630 event_base_dispatch(data->base);
1632 evhttp_connection_free(evcon);
1633 evhttp_free(http);
1635 tt_int_op(test_ok, ==, 1);
1636 end:
1640 void
1641 http_put_cb(struct evhttp_request *req, void *arg)
1643 struct evbuffer *evb;
1644 event_debug(("%s: called\n", __func__));
1646 /* Expecting a PUT request */
1647 if (evhttp_request_get_command(req) != EVHTTP_REQ_PUT) {
1648 fprintf(stdout, "FAILED (put type)\n");
1649 exit(1);
1652 if (evbuffer_get_length(evhttp_request_get_input_buffer(req)) != strlen(PUT_DATA)) {
1653 fprintf(stdout, "FAILED (length: %lu vs %lu)\n",
1654 (unsigned long)evbuffer_get_length(evhttp_request_get_input_buffer(req)), (unsigned long)strlen(PUT_DATA));
1655 exit(1);
1658 if (evbuffer_datacmp(evhttp_request_get_input_buffer(req), PUT_DATA) != 0) {
1659 fprintf(stdout, "FAILED (data)\n");
1660 fprintf(stdout, "Got :%s\n", evbuffer_pullup(evhttp_request_get_input_buffer(req),-1));
1661 fprintf(stdout, "Want:%s\n", PUT_DATA);
1662 exit(1);
1665 evb = evbuffer_new();
1666 evbuffer_add_printf(evb, "That ain't funny");
1668 evhttp_send_reply(req, HTTP_OK, "Everything is great", evb);
1670 evbuffer_free(evb);
1673 void
1674 http_putrequest_done(struct evhttp_request *req, void *arg)
1676 struct event_base *base = arg;
1677 const char *what = "That ain't funny";
1679 if (req == NULL) {
1680 fprintf(stderr, "FAILED (timeout)\n");
1681 exit(1);
1684 if (evhttp_request_get_response_code(req) != HTTP_OK) {
1686 fprintf(stderr, "FAILED (response code)\n");
1687 exit(1);
1690 if (evhttp_find_header(evhttp_request_get_input_headers(req), "Content-Type") == NULL) {
1691 fprintf(stderr, "FAILED (content type)\n");
1692 exit(1);
1695 if (evbuffer_get_length(evhttp_request_get_input_buffer(req)) != strlen(what)) {
1696 fprintf(stderr, "FAILED (length %lu vs %lu)\n",
1697 (unsigned long)evbuffer_get_length(evhttp_request_get_input_buffer(req)), (unsigned long)strlen(what));
1698 exit(1);
1702 if (evbuffer_datacmp(evhttp_request_get_input_buffer(req), what) != 0) {
1703 fprintf(stderr, "FAILED (data)\n");
1704 exit(1);
1707 test_ok = 1;
1708 event_base_loopexit(base, NULL);
1711 static void
1712 http_failure_readcb(struct bufferevent *bev, void *arg)
1714 const char *what = "400 Bad Request";
1715 if (evbuffer_contains(bufferevent_get_input(bev), what)) {
1716 test_ok = 2;
1717 bufferevent_disable(bev, EV_READ);
1718 event_base_loopexit(arg, NULL);
1723 * Testing that the HTTP server can deal with a malformed request.
1725 static void
1726 http_failure_test(void *arg)
1728 struct basic_test_data *data = arg;
1729 struct bufferevent *bev;
1730 evutil_socket_t fd;
1731 const char *http_request;
1732 ev_uint16_t port = 0;
1734 test_ok = 0;
1736 http = http_setup(&port, data->base);
1738 fd = http_connect("127.0.0.1", port);
1740 /* Stupid thing to send a request */
1741 bev = bufferevent_socket_new(data->base, fd, 0);
1742 bufferevent_setcb(bev, http_failure_readcb, http_writecb,
1743 http_errorcb, data->base);
1745 http_request = "illegal request\r\n";
1747 bufferevent_write(bev, http_request, strlen(http_request));
1749 event_base_dispatch(data->base);
1751 bufferevent_free(bev);
1752 evutil_closesocket(fd);
1754 evhttp_free(http);
1756 tt_int_op(test_ok, ==, 2);
1757 end:
1761 static void
1762 close_detect_done(struct evhttp_request *req, void *arg)
1764 struct timeval tv;
1765 tt_assert(req);
1766 tt_assert(evhttp_request_get_response_code(req) == HTTP_OK);
1768 test_ok = 1;
1770 end:
1771 evutil_timerclear(&tv);
1772 tv.tv_sec = 3;
1773 event_base_loopexit(arg, &tv);
1776 static void
1777 close_detect_launch(evutil_socket_t fd, short what, void *arg)
1779 struct evhttp_connection *evcon = arg;
1780 struct event_base *base = evhttp_connection_get_base(evcon);
1781 struct evhttp_request *req;
1783 req = evhttp_request_new(close_detect_done, base);
1785 /* Add the information that we care about */
1786 evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
1788 /* We give ownership of the request to the connection */
1789 if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test") == -1) {
1790 tt_fail_msg("Couldn't make request");
1794 static void
1795 close_detect_cb(struct evhttp_request *req, void *arg)
1797 struct evhttp_connection *evcon = arg;
1798 struct event_base *base = evhttp_connection_get_base(evcon);
1799 struct timeval tv;
1801 if (req != NULL && evhttp_request_get_response_code(req) != HTTP_OK) {
1802 tt_abort_msg("Failed");
1805 evutil_timerclear(&tv);
1806 tv.tv_sec = 3; /* longer than the http time out */
1808 /* launch a new request on the persistent connection in 3 seconds */
1809 event_base_once(base, -1, EV_TIMEOUT, close_detect_launch, evcon, &tv);
1810 end:
1815 static void
1816 _http_close_detection(struct basic_test_data *data, int with_delay)
1818 ev_uint16_t port = 0;
1819 struct evhttp_connection *evcon = NULL;
1820 struct evhttp_request *req = NULL;
1822 test_ok = 0;
1823 http = http_setup(&port, data->base);
1825 /* 2 second timeout */
1826 evhttp_set_timeout(http, 1);
1828 evcon = evhttp_connection_base_new(data->base, NULL,
1829 "127.0.0.1", port);
1830 tt_assert(evcon);
1831 delayed_client = evcon;
1834 * At this point, we want to schedule a request to the HTTP
1835 * server using our make request method.
1838 req = evhttp_request_new(close_detect_cb, evcon);
1840 /* Add the information that we care about */
1841 evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
1843 /* We give ownership of the request to the connection */
1844 if (evhttp_make_request(evcon,
1845 req, EVHTTP_REQ_GET, with_delay ? "/largedelay" : "/test") == -1) {
1846 tt_abort_msg("couldn't make request");
1847 exit(1);
1850 event_base_dispatch(data->base);
1852 /* at this point, the http server should have no connection */
1853 tt_assert(TAILQ_FIRST(&http->connections) == NULL);
1855 end:
1856 if (evcon)
1857 evhttp_connection_free(evcon);
1858 if (http)
1859 evhttp_free(http);
1861 static void
1862 http_close_detection_test(void *arg)
1864 _http_close_detection(arg, 0);
1866 static void
1867 http_close_detection_delay_test(void *arg)
1869 _http_close_detection(arg, 1);
1872 static void
1873 http_highport_test(void *arg)
1875 struct basic_test_data *data = arg;
1876 int i = -1;
1877 struct evhttp *myhttp = NULL;
1879 /* Try a few different ports */
1880 for (i = 0; i < 50; ++i) {
1881 myhttp = evhttp_new(data->base);
1882 if (evhttp_bind_socket(myhttp, "127.0.0.1", 65535 - i) == 0) {
1883 test_ok = 1;
1884 evhttp_free(myhttp);
1885 return;
1887 evhttp_free(myhttp);
1890 tt_fail_msg("Couldn't get a high port");
1893 static void
1894 http_bad_header_test(void *ptr)
1896 struct evkeyvalq headers;
1898 TAILQ_INIT(&headers);
1900 tt_want(evhttp_add_header(&headers, "One", "Two") == 0);
1901 tt_want(evhttp_add_header(&headers, "One", "Two\r\n Three") == 0);
1902 tt_want(evhttp_add_header(&headers, "One\r", "Two") == -1);
1903 tt_want(evhttp_add_header(&headers, "One\n", "Two") == -1);
1904 tt_want(evhttp_add_header(&headers, "One", "Two\r") == -1);
1905 tt_want(evhttp_add_header(&headers, "One", "Two\n") == -1);
1907 evhttp_clear_headers(&headers);
1910 static int validate_header(
1911 const struct evkeyvalq* headers,
1912 const char *key, const char *value)
1914 const char *real_val = evhttp_find_header(headers, key);
1915 tt_assert(real_val != NULL);
1916 tt_want(strcmp(real_val, value) == 0);
1917 end:
1918 return (0);
1921 static void
1922 http_parse_query_test(void *ptr)
1924 struct evkeyvalq headers;
1925 int r;
1927 TAILQ_INIT(&headers);
1929 r = evhttp_parse_query("http://www.test.com/?q=test", &headers);
1930 tt_want(validate_header(&headers, "q", "test") == 0);
1931 tt_int_op(r, ==, 0);
1932 evhttp_clear_headers(&headers);
1934 r = evhttp_parse_query("http://www.test.com/?q=test&foo=bar", &headers);
1935 tt_want(validate_header(&headers, "q", "test") == 0);
1936 tt_want(validate_header(&headers, "foo", "bar") == 0);
1937 tt_int_op(r, ==, 0);
1938 evhttp_clear_headers(&headers);
1940 r = evhttp_parse_query("http://www.test.com/?q=test+foo", &headers);
1941 tt_want(validate_header(&headers, "q", "test foo") == 0);
1942 tt_int_op(r, ==, 0);
1943 evhttp_clear_headers(&headers);
1945 r = evhttp_parse_query("http://www.test.com/?q=test%0Afoo", &headers);
1946 tt_want(validate_header(&headers, "q", "test\nfoo") == 0);
1947 tt_int_op(r, ==, 0);
1948 evhttp_clear_headers(&headers);
1950 r = evhttp_parse_query("http://www.test.com/?q=test%0Dfoo", &headers);
1951 tt_want(validate_header(&headers, "q", "test\rfoo") == 0);
1952 tt_int_op(r, ==, 0);
1953 evhttp_clear_headers(&headers);
1955 r = evhttp_parse_query("http://www.test.com/?q=test&&q2", &headers);
1956 tt_int_op(r, ==, -1);
1957 evhttp_clear_headers(&headers);
1959 r = evhttp_parse_query("http://www.test.com/?q=test+this", &headers);
1960 tt_want(validate_header(&headers, "q", "test this") == 0);
1961 tt_int_op(r, ==, 0);
1962 evhttp_clear_headers(&headers);
1964 r = evhttp_parse_query("http://www.test.com/?q=test&q2=foo", &headers);
1965 tt_int_op(r, ==, 0);
1966 tt_want(validate_header(&headers, "q", "test") == 0);
1967 tt_want(validate_header(&headers, "q2", "foo") == 0);
1968 evhttp_clear_headers(&headers);
1970 r = evhttp_parse_query("http://www.test.com/?q&q2=foo", &headers);
1971 tt_int_op(r, ==, -1);
1972 evhttp_clear_headers(&headers);
1974 r = evhttp_parse_query("http://www.test.com/?q=foo&q2", &headers);
1975 tt_int_op(r, ==, -1);
1976 evhttp_clear_headers(&headers);
1978 r = evhttp_parse_query("http://www.test.com/?q=foo&q2&q3=x", &headers);
1979 tt_int_op(r, ==, -1);
1980 evhttp_clear_headers(&headers);
1982 r = evhttp_parse_query("http://www.test.com/?q=&q2=&q3=", &headers);
1983 tt_int_op(r, ==, 0);
1984 tt_want(validate_header(&headers, "q", "") == 0);
1985 tt_want(validate_header(&headers, "q2", "") == 0);
1986 tt_want(validate_header(&headers, "q3", "") == 0);
1987 evhttp_clear_headers(&headers);
1989 end:
1990 evhttp_clear_headers(&headers);
1993 static void
1994 http_parse_uri_test(void *ptr)
1996 const int nonconform = (ptr != NULL);
1997 const unsigned parse_flags =
1998 nonconform ? EVHTTP_URI_NONCONFORMANT : 0;
1999 struct evhttp_uri *uri = NULL;
2000 char url_tmp[4096];
2001 #define URI_PARSE(uri) \
2002 evhttp_uri_parse_with_flags((uri), parse_flags)
2004 #define TT_URI(want) do { \
2005 char *ret = evhttp_uri_join(uri, url_tmp, sizeof(url_tmp)); \
2006 tt_want(ret != NULL); \
2007 tt_want(ret == url_tmp); \
2008 if (strcmp(ret,want) != 0) \
2009 TT_FAIL(("\"%s\" != \"%s\"",ret,want)); \
2010 } while(0)
2012 tt_want(evhttp_uri_join(NULL, 0, 0) == NULL);
2013 tt_want(evhttp_uri_join(NULL, url_tmp, 0) == NULL);
2014 tt_want(evhttp_uri_join(NULL, url_tmp, sizeof(url_tmp)) == NULL);
2016 /* bad URIs: parsing */
2017 #define BAD(s) do { \
2018 if (URI_PARSE(s) != NULL) \
2019 TT_FAIL(("Expected error parsing \"%s\"",s)); \
2020 } while(0)
2021 /* Nonconformant URIs we can parse: parsing */
2022 #define NCF(s) do { \
2023 uri = URI_PARSE(s); \
2024 if (uri != NULL && !nonconform) { \
2025 TT_FAIL(("Expected error parsing \"%s\"",s)); \
2026 } else if (uri == NULL && nonconform) { \
2027 TT_FAIL(("Couldn't parse nonconformant URI \"%s\"", \
2028 s)); \
2030 if (uri) { \
2031 tt_want(evhttp_uri_join(uri, url_tmp, \
2032 sizeof(url_tmp))); \
2033 evhttp_uri_free(uri); \
2035 } while(0)
2037 NCF("http://www.test.com/ why hello");
2038 NCF("http://www.test.com/why-hello\x01");
2039 NCF("http://www.test.com/why-hello?\x01");
2040 NCF("http://www.test.com/why-hello#\x01");
2041 BAD("http://www.\x01.test.com/why-hello");
2042 BAD("http://www.%7test.com/why-hello");
2043 NCF("http://www.test.com/why-hell%7o");
2044 BAD("h%3ttp://www.test.com/why-hello");
2045 NCF("http://www.test.com/why-hello%7");
2046 NCF("http://www.test.com/why-hell%7o");
2047 NCF("http://www.test.com/foo?ba%r");
2048 NCF("http://www.test.com/foo#ba%r");
2049 BAD("99:99/foo");
2050 BAD("http://www.test.com:999x/");
2051 BAD("http://www.test.com:x/");
2052 BAD("http://[hello-there]/");
2053 BAD("http://[::1]]/");
2054 BAD("http://[::1/");
2055 BAD("http://[foob/");
2056 BAD("http://[/");
2057 BAD("http://[ffff:ffff:ffff:ffff:Ffff:ffff:ffff:"
2058 "ffff:ffff:ffff:ffff:ffff:ffff:ffff]/");
2059 BAD("http://[vX.foo]/");
2060 BAD("http://[vX.foo]/");
2061 BAD("http://[v.foo]/");
2062 BAD("http://[v5.fo%o]/");
2063 BAD("http://[v5X]/");
2064 BAD("http://[v5]/");
2065 BAD("http://[]/");
2066 BAD("http://f\x01red@www.example.com/");
2067 BAD("http://f%0red@www.example.com/");
2068 BAD("http://www.example.com:9999999999999999999999999999999999999/");
2069 BAD("http://www.example.com:hihi/");
2070 BAD("://www.example.com/");
2072 /* bad URIs: joining */
2073 uri = evhttp_uri_new();
2074 tt_want(0==evhttp_uri_set_host(uri, "www.example.com"));
2075 tt_want(evhttp_uri_join(uri, url_tmp, sizeof(url_tmp)) != NULL);
2076 /* not enough space: */
2077 tt_want(evhttp_uri_join(uri, url_tmp, 3) == NULL);
2078 /* host is set, but path doesn't start with "/": */
2079 tt_want(0==evhttp_uri_set_path(uri, "hi_mom"));
2080 tt_want(evhttp_uri_join(uri, url_tmp, sizeof(url_tmp)) == NULL);
2081 tt_want(evhttp_uri_join(uri, NULL, sizeof(url_tmp))==NULL);
2082 tt_want(evhttp_uri_join(uri, url_tmp, 0)==NULL);
2083 evhttp_uri_free(uri);
2084 uri = URI_PARSE("mailto:foo@bar");
2085 tt_want(uri != NULL);
2086 tt_want(evhttp_uri_get_host(uri) == NULL);
2087 tt_want(evhttp_uri_get_userinfo(uri) == NULL);
2088 tt_want(evhttp_uri_get_port(uri) == -1);
2089 tt_want(!strcmp(evhttp_uri_get_scheme(uri), "mailto"));
2090 tt_want(!strcmp(evhttp_uri_get_path(uri), "foo@bar"));
2091 tt_want(evhttp_uri_get_query(uri) == NULL);
2092 tt_want(evhttp_uri_get_fragment(uri) == NULL);
2093 TT_URI("mailto:foo@bar");
2094 evhttp_uri_free(uri);
2096 uri = evhttp_uri_new();
2097 /* Bad URI usage: setting invalid values */
2098 tt_want(-1 == evhttp_uri_set_scheme(uri,""));
2099 tt_want(-1 == evhttp_uri_set_scheme(uri,"33"));
2100 tt_want(-1 == evhttp_uri_set_scheme(uri,"hi!"));
2101 tt_want(-1 == evhttp_uri_set_userinfo(uri,"hello@"));
2102 tt_want(-1 == evhttp_uri_set_host(uri,"[1.2.3.4]"));
2103 tt_want(-1 == evhttp_uri_set_host(uri,"["));
2104 tt_want(-1 == evhttp_uri_set_host(uri,"www.[foo].com"));
2105 tt_want(-1 == evhttp_uri_set_port(uri,-3));
2106 tt_want(-1 == evhttp_uri_set_path(uri,"hello?world"));
2107 tt_want(-1 == evhttp_uri_set_query(uri,"hello#world"));
2108 tt_want(-1 == evhttp_uri_set_fragment(uri,"hello#world"));
2109 /* Valid URI usage: setting valid values */
2110 tt_want(0 == evhttp_uri_set_scheme(uri,"http"));
2111 tt_want(0 == evhttp_uri_set_scheme(uri,NULL));
2112 tt_want(0 == evhttp_uri_set_userinfo(uri,"username:pass"));
2113 tt_want(0 == evhttp_uri_set_userinfo(uri,NULL));
2114 tt_want(0 == evhttp_uri_set_host(uri,"www.example.com"));
2115 tt_want(0 == evhttp_uri_set_host(uri,"1.2.3.4"));
2116 tt_want(0 == evhttp_uri_set_host(uri,"[1:2:3:4::]"));
2117 tt_want(0 == evhttp_uri_set_host(uri,"[v7.wobblewobble]"));
2118 tt_want(0 == evhttp_uri_set_host(uri,NULL));
2119 tt_want(0 == evhttp_uri_set_host(uri,""));
2120 tt_want(0 == evhttp_uri_set_port(uri, -1));
2121 tt_want(0 == evhttp_uri_set_port(uri, 80));
2122 tt_want(0 == evhttp_uri_set_port(uri, 65535));
2123 tt_want(0 == evhttp_uri_set_path(uri, ""));
2124 tt_want(0 == evhttp_uri_set_path(uri, "/documents/public/index.html"));
2125 tt_want(0 == evhttp_uri_set_path(uri, NULL));
2126 tt_want(0 == evhttp_uri_set_query(uri, "key=val&key2=val2"));
2127 tt_want(0 == evhttp_uri_set_query(uri, "keyvalblarg"));
2128 tt_want(0 == evhttp_uri_set_query(uri, ""));
2129 tt_want(0 == evhttp_uri_set_query(uri, NULL));
2130 tt_want(0 == evhttp_uri_set_fragment(uri, ""));
2131 tt_want(0 == evhttp_uri_set_fragment(uri, "here?i?am"));
2132 tt_want(0 == evhttp_uri_set_fragment(uri, NULL));
2133 evhttp_uri_free(uri);
2135 /* Valid parsing */
2136 uri = URI_PARSE("http://www.test.com/?q=t%33est");
2137 tt_want(strcmp(evhttp_uri_get_scheme(uri), "http") == 0);
2138 tt_want(strcmp(evhttp_uri_get_host(uri), "www.test.com") == 0);
2139 tt_want(strcmp(evhttp_uri_get_path(uri), "/") == 0);
2140 tt_want(strcmp(evhttp_uri_get_query(uri), "q=t%33est") == 0);
2141 tt_want(evhttp_uri_get_userinfo(uri) == NULL);
2142 tt_want(evhttp_uri_get_port(uri) == -1);
2143 tt_want(evhttp_uri_get_fragment(uri) == NULL);
2144 TT_URI("http://www.test.com/?q=t%33est");
2145 evhttp_uri_free(uri);
2147 uri = URI_PARSE("http://%77ww.test.com");
2148 tt_want(strcmp(evhttp_uri_get_scheme(uri), "http") == 0);
2149 tt_want(strcmp(evhttp_uri_get_host(uri), "%77ww.test.com") == 0);
2150 tt_want(strcmp(evhttp_uri_get_path(uri), "") == 0);
2151 tt_want(evhttp_uri_get_query(uri) == NULL);
2152 tt_want(evhttp_uri_get_userinfo(uri) == NULL);
2153 tt_want(evhttp_uri_get_port(uri) == -1);
2154 tt_want(evhttp_uri_get_fragment(uri) == NULL);
2155 TT_URI("http://%77ww.test.com");
2156 evhttp_uri_free(uri);
2158 uri = URI_PARSE("http://www.test.com?q=test");
2159 tt_want(strcmp(evhttp_uri_get_scheme(uri), "http") == 0);
2160 tt_want(strcmp(evhttp_uri_get_host(uri), "www.test.com") == 0);
2161 tt_want(strcmp(evhttp_uri_get_path(uri), "") == 0);
2162 tt_want(strcmp(evhttp_uri_get_query(uri), "q=test") == 0);
2163 tt_want(evhttp_uri_get_userinfo(uri) == NULL);
2164 tt_want(evhttp_uri_get_port(uri) == -1);
2165 tt_want(evhttp_uri_get_fragment(uri) == NULL);
2166 TT_URI("http://www.test.com?q=test");
2167 evhttp_uri_free(uri);
2169 uri = URI_PARSE("http://www.test.com#fragment");
2170 tt_want(strcmp(evhttp_uri_get_scheme(uri), "http") == 0);
2171 tt_want(strcmp(evhttp_uri_get_host(uri), "www.test.com") == 0);
2172 tt_want(strcmp(evhttp_uri_get_path(uri), "") == 0);
2173 tt_want(evhttp_uri_get_query(uri) == NULL);
2174 tt_want(evhttp_uri_get_userinfo(uri) == NULL);
2175 tt_want(evhttp_uri_get_port(uri) == -1);
2176 tt_want_str_op(evhttp_uri_get_fragment(uri), ==, "fragment");
2177 TT_URI("http://www.test.com#fragment");
2178 evhttp_uri_free(uri);
2180 uri = URI_PARSE("http://8000/");
2181 tt_want(strcmp(evhttp_uri_get_scheme(uri), "http") == 0);
2182 tt_want(strcmp(evhttp_uri_get_host(uri), "8000") == 0);
2183 tt_want(strcmp(evhttp_uri_get_path(uri), "/") == 0);
2184 tt_want(evhttp_uri_get_query(uri) == NULL);
2185 tt_want(evhttp_uri_get_userinfo(uri) == NULL);
2186 tt_want(evhttp_uri_get_port(uri) == -1);
2187 tt_want(evhttp_uri_get_fragment(uri) == NULL);
2188 TT_URI("http://8000/");
2189 evhttp_uri_free(uri);
2191 uri = URI_PARSE("http://:8000/");
2192 tt_want(strcmp(evhttp_uri_get_scheme(uri), "http") == 0);
2193 tt_want(strcmp(evhttp_uri_get_host(uri), "") == 0);
2194 tt_want(strcmp(evhttp_uri_get_path(uri), "/") == 0);
2195 tt_want(evhttp_uri_get_query(uri) == NULL);
2196 tt_want(evhttp_uri_get_userinfo(uri) == NULL);
2197 tt_want(evhttp_uri_get_port(uri) == 8000);
2198 tt_want(evhttp_uri_get_fragment(uri) == NULL);
2199 TT_URI("http://:8000/");
2200 evhttp_uri_free(uri);
2202 uri = URI_PARSE("http://www.test.com:/"); /* empty port */
2203 tt_want(strcmp(evhttp_uri_get_scheme(uri), "http") == 0);
2204 tt_want(strcmp(evhttp_uri_get_host(uri), "www.test.com") == 0);
2205 tt_want_str_op(evhttp_uri_get_path(uri), ==, "/");
2206 tt_want(evhttp_uri_get_query(uri) == NULL);
2207 tt_want(evhttp_uri_get_userinfo(uri) == NULL);
2208 tt_want(evhttp_uri_get_port(uri) == -1);
2209 tt_want(evhttp_uri_get_fragment(uri) == NULL);
2210 TT_URI("http://www.test.com/");
2211 evhttp_uri_free(uri);
2213 uri = URI_PARSE("http://www.test.com:"); /* empty port 2 */
2214 tt_want(strcmp(evhttp_uri_get_scheme(uri), "http") == 0);
2215 tt_want(strcmp(evhttp_uri_get_host(uri), "www.test.com") == 0);
2216 tt_want(strcmp(evhttp_uri_get_path(uri), "") == 0);
2217 tt_want(evhttp_uri_get_query(uri) == NULL);
2218 tt_want(evhttp_uri_get_userinfo(uri) == NULL);
2219 tt_want(evhttp_uri_get_port(uri) == -1);
2220 tt_want(evhttp_uri_get_fragment(uri) == NULL);
2221 TT_URI("http://www.test.com");
2222 evhttp_uri_free(uri);
2224 uri = URI_PARSE("ftp://www.test.com/?q=test");
2225 tt_want(strcmp(evhttp_uri_get_scheme(uri), "ftp") == 0);
2226 tt_want(strcmp(evhttp_uri_get_host(uri), "www.test.com") == 0);
2227 tt_want(strcmp(evhttp_uri_get_path(uri), "/") == 0);
2228 tt_want(strcmp(evhttp_uri_get_query(uri), "q=test") == 0);
2229 tt_want(evhttp_uri_get_userinfo(uri) == NULL);
2230 tt_want(evhttp_uri_get_port(uri) == -1);
2231 tt_want(evhttp_uri_get_fragment(uri) == NULL);
2232 TT_URI("ftp://www.test.com/?q=test");
2233 evhttp_uri_free(uri);
2235 uri = URI_PARSE("ftp://[::1]:999/?q=test");
2236 tt_want(strcmp(evhttp_uri_get_scheme(uri), "ftp") == 0);
2237 tt_want(strcmp(evhttp_uri_get_host(uri), "[::1]") == 0);
2238 tt_want(strcmp(evhttp_uri_get_path(uri), "/") == 0);
2239 tt_want(strcmp(evhttp_uri_get_query(uri), "q=test") == 0);
2240 tt_want(evhttp_uri_get_userinfo(uri) == NULL);
2241 tt_want(evhttp_uri_get_port(uri) == 999);
2242 tt_want(evhttp_uri_get_fragment(uri) == NULL);
2243 TT_URI("ftp://[::1]:999/?q=test");
2244 evhttp_uri_free(uri);
2246 uri = URI_PARSE("ftp://[ff00::127.0.0.1]/?q=test");
2247 tt_want(strcmp(evhttp_uri_get_scheme(uri), "ftp") == 0);
2248 tt_want(strcmp(evhttp_uri_get_host(uri), "[ff00::127.0.0.1]") == 0);
2249 tt_want(strcmp(evhttp_uri_get_path(uri), "/") == 0);
2250 tt_want(strcmp(evhttp_uri_get_query(uri), "q=test") == 0);
2251 tt_want(evhttp_uri_get_userinfo(uri) == NULL);
2252 tt_want(evhttp_uri_get_port(uri) == -1);
2253 tt_want(evhttp_uri_get_fragment(uri) == NULL);
2254 TT_URI("ftp://[ff00::127.0.0.1]/?q=test");
2255 evhttp_uri_free(uri);
2257 uri = URI_PARSE("ftp://[v99.not_(any:time)_soon]/?q=test");
2258 tt_want(strcmp(evhttp_uri_get_scheme(uri), "ftp") == 0);
2259 tt_want(strcmp(evhttp_uri_get_host(uri), "[v99.not_(any:time)_soon]") == 0);
2260 tt_want(strcmp(evhttp_uri_get_path(uri), "/") == 0);
2261 tt_want(strcmp(evhttp_uri_get_query(uri), "q=test") == 0);
2262 tt_want(evhttp_uri_get_userinfo(uri) == NULL);
2263 tt_want(evhttp_uri_get_port(uri) == -1);
2264 tt_want(evhttp_uri_get_fragment(uri) == NULL);
2265 TT_URI("ftp://[v99.not_(any:time)_soon]/?q=test");
2266 evhttp_uri_free(uri);
2268 uri = URI_PARSE("scheme://user:pass@foo.com:42/?q=test&s=some+thing#fragment");
2269 tt_want(strcmp(evhttp_uri_get_scheme(uri), "scheme") == 0);
2270 tt_want(strcmp(evhttp_uri_get_userinfo(uri), "user:pass") == 0);
2271 tt_want(strcmp(evhttp_uri_get_host(uri), "foo.com") == 0);
2272 tt_want(evhttp_uri_get_port(uri) == 42);
2273 tt_want(strcmp(evhttp_uri_get_path(uri), "/") == 0);
2274 tt_want(strcmp(evhttp_uri_get_query(uri), "q=test&s=some+thing") == 0);
2275 tt_want(strcmp(evhttp_uri_get_fragment(uri), "fragment") == 0);
2276 TT_URI("scheme://user:pass@foo.com:42/?q=test&s=some+thing#fragment");
2277 evhttp_uri_free(uri);
2279 uri = URI_PARSE("scheme://user@foo.com/#fragment");
2280 tt_want(strcmp(evhttp_uri_get_scheme(uri), "scheme") == 0);
2281 tt_want(strcmp(evhttp_uri_get_userinfo(uri), "user") == 0);
2282 tt_want(strcmp(evhttp_uri_get_host(uri), "foo.com") == 0);
2283 tt_want(evhttp_uri_get_port(uri) == -1);
2284 tt_want(strcmp(evhttp_uri_get_path(uri), "/") == 0);
2285 tt_want(evhttp_uri_get_query(uri) == NULL);
2286 tt_want(strcmp(evhttp_uri_get_fragment(uri), "fragment") == 0);
2287 TT_URI("scheme://user@foo.com/#fragment");
2288 evhttp_uri_free(uri);
2290 uri = URI_PARSE("scheme://%75ser@foo.com/#frag@ment");
2291 tt_want(strcmp(evhttp_uri_get_scheme(uri), "scheme") == 0);
2292 tt_want(strcmp(evhttp_uri_get_userinfo(uri), "%75ser") == 0);
2293 tt_want(strcmp(evhttp_uri_get_host(uri), "foo.com") == 0);
2294 tt_want(evhttp_uri_get_port(uri) == -1);
2295 tt_want(strcmp(evhttp_uri_get_path(uri), "/") == 0);
2296 tt_want(evhttp_uri_get_query(uri) == NULL);
2297 tt_want(strcmp(evhttp_uri_get_fragment(uri), "frag@ment") == 0);
2298 TT_URI("scheme://%75ser@foo.com/#frag@ment");
2299 evhttp_uri_free(uri);
2301 uri = URI_PARSE("file:///some/path/to/the/file");
2302 tt_want(strcmp(evhttp_uri_get_scheme(uri), "file") == 0);
2303 tt_want(evhttp_uri_get_userinfo(uri) == NULL);
2304 tt_want(strcmp(evhttp_uri_get_host(uri), "") == 0);
2305 tt_want(evhttp_uri_get_port(uri) == -1);
2306 tt_want(strcmp(evhttp_uri_get_path(uri), "/some/path/to/the/file") == 0);
2307 tt_want(evhttp_uri_get_query(uri) == NULL);
2308 tt_want(evhttp_uri_get_fragment(uri) == NULL);
2309 TT_URI("file:///some/path/to/the/file");
2310 evhttp_uri_free(uri);
2312 uri = URI_PARSE("///some/path/to/the-file");
2313 tt_want(uri != NULL);
2314 tt_want(evhttp_uri_get_scheme(uri) == NULL);
2315 tt_want(evhttp_uri_get_userinfo(uri) == NULL);
2316 tt_want(strcmp(evhttp_uri_get_host(uri), "") == 0);
2317 tt_want(evhttp_uri_get_port(uri) == -1);
2318 tt_want(strcmp(evhttp_uri_get_path(uri), "/some/path/to/the-file") == 0);
2319 tt_want(evhttp_uri_get_query(uri) == NULL);
2320 tt_want(evhttp_uri_get_fragment(uri) == NULL);
2321 TT_URI("///some/path/to/the-file");
2322 evhttp_uri_free(uri);
2324 uri = URI_PARSE("/s:ome/path/to/the-file?q=99#fred");
2325 tt_want(uri != NULL);
2326 tt_want(evhttp_uri_get_scheme(uri) == NULL);
2327 tt_want(evhttp_uri_get_userinfo(uri) == NULL);
2328 tt_want(evhttp_uri_get_host(uri) == NULL);
2329 tt_want(evhttp_uri_get_port(uri) == -1);
2330 tt_want(strcmp(evhttp_uri_get_path(uri), "/s:ome/path/to/the-file") == 0);
2331 tt_want(strcmp(evhttp_uri_get_query(uri), "q=99") == 0);
2332 tt_want(strcmp(evhttp_uri_get_fragment(uri), "fred") == 0);
2333 TT_URI("/s:ome/path/to/the-file?q=99#fred");
2334 evhttp_uri_free(uri);
2336 uri = URI_PARSE("relative/path/with/co:lon");
2337 tt_want(uri != NULL);
2338 tt_want(evhttp_uri_get_scheme(uri) == NULL);
2339 tt_want(evhttp_uri_get_userinfo(uri) == NULL);
2340 tt_want(evhttp_uri_get_host(uri) == NULL);
2341 tt_want(evhttp_uri_get_port(uri) == -1);
2342 tt_want(strcmp(evhttp_uri_get_path(uri), "relative/path/with/co:lon") == 0);
2343 tt_want(evhttp_uri_get_query(uri) == NULL);
2344 tt_want(evhttp_uri_get_fragment(uri) == NULL);
2345 TT_URI("relative/path/with/co:lon");
2346 evhttp_uri_free(uri);
2348 uri = URI_PARSE("bob?q=99&q2=q?33#fr?ed");
2349 tt_want(uri != NULL);
2350 tt_want(evhttp_uri_get_scheme(uri) == NULL);
2351 tt_want(evhttp_uri_get_userinfo(uri) == NULL);
2352 tt_want(evhttp_uri_get_host(uri) == NULL);
2353 tt_want(evhttp_uri_get_port(uri) == -1);
2354 tt_want(strcmp(evhttp_uri_get_path(uri), "bob") == 0);
2355 tt_want(strcmp(evhttp_uri_get_query(uri), "q=99&q2=q?33") == 0);
2356 tt_want(strcmp(evhttp_uri_get_fragment(uri), "fr?ed") == 0);
2357 TT_URI("bob?q=99&q2=q?33#fr?ed");
2358 evhttp_uri_free(uri);
2360 uri = URI_PARSE("#fr?ed");
2361 tt_want(uri != NULL);
2362 tt_want(evhttp_uri_get_scheme(uri) == NULL);
2363 tt_want(evhttp_uri_get_userinfo(uri) == NULL);
2364 tt_want(evhttp_uri_get_host(uri) == NULL);
2365 tt_want(evhttp_uri_get_port(uri) == -1);
2366 tt_want(strcmp(evhttp_uri_get_path(uri), "") == 0);
2367 tt_want(evhttp_uri_get_query(uri) == NULL);
2368 tt_want(strcmp(evhttp_uri_get_fragment(uri), "fr?ed") == 0);
2369 TT_URI("#fr?ed");
2370 evhttp_uri_free(uri);
2371 #undef URI_PARSE
2372 #undef TT_URI
2373 #undef BAD
2376 static void
2377 http_uriencode_test(void *ptr)
2379 char *s=NULL, *s2=NULL;
2380 size_t sz;
2382 #define ENC(from,want,plus) do { \
2383 s = evhttp_uriencode((from), -1, (plus)); \
2384 tt_assert(s); \
2385 tt_str_op(s,==,(want)); \
2386 sz = -1; \
2387 s2 = evhttp_uridecode((s), (plus), &sz); \
2388 tt_assert(s2); \
2389 tt_str_op(s2,==,(from)); \
2390 tt_int_op(sz,==,strlen(from)); \
2391 free(s); \
2392 free(s2); \
2393 s = s2 = NULL; \
2394 } while (0)
2396 #define DEC(from,want,dp) do { \
2397 s = evhttp_uridecode((from),(dp),&sz); \
2398 tt_assert(s); \
2399 tt_str_op(s,==,(want)); \
2400 tt_int_op(sz,==,strlen(want)); \
2401 free(s); \
2402 s = NULL; \
2403 } while (0)
2405 #define OLD_DEC(from,want) do { \
2406 s = evhttp_decode_uri((from)); \
2407 tt_assert(s); \
2408 tt_str_op(s,==,(want)); \
2409 free(s); \
2410 s = NULL; \
2411 } while (0)
2414 ENC("Hello", "Hello",0);
2415 ENC("99", "99",0);
2416 ENC("", "",0);
2417 ENC(
2418 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ123456789-.~_",
2419 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ123456789-.~_",0);
2420 ENC(" ", "%20",0);
2421 ENC(" ", "+",1);
2422 ENC("\xff\xf0\xe0", "%FF%F0%E0",0);
2423 ENC("\x01\x19", "%01%19",1);
2424 ENC("http://www.ietf.org/rfc/rfc3986.txt",
2425 "http%3A%2F%2Fwww.ietf.org%2Frfc%2Frfc3986.txt",1);
2427 ENC("1+2=3", "1%2B2%3D3",1);
2428 ENC("1+2=3", "1%2B2%3D3",0);
2430 /* Now try encoding with internal NULs. */
2431 s = evhttp_uriencode("hello\0world", 11, 0);
2432 tt_assert(s);
2433 tt_str_op(s,==,"hello%00world");
2434 free(s);
2435 s = NULL;
2437 /* Now try out some decoding cases that we don't generate with
2438 * encode_uri: Make sure that malformed stuff doesn't crash... */
2439 DEC("%%xhello th+ere \xff",
2440 "%%xhello th+ere \xff", 0);
2441 /* Make sure plus decoding works */
2442 DEC("plus+should%20work+", "plus should work ",1);
2443 /* Try some lowercase hex */
2444 DEC("%f0%a0%b0", "\xf0\xa0\xb0",1);
2446 /* Try an internal NUL. */
2447 sz = 0;
2448 s = evhttp_uridecode("%00%00x%00%00", 1, &sz);
2449 tt_int_op(sz,==,5);
2450 tt_assert(!memcmp(s, "\0\0x\0\0", 5));
2451 free(s);
2452 s = NULL;
2454 /* Try with size == NULL */
2455 sz = 0;
2456 s = evhttp_uridecode("%00%00x%00%00", 1, NULL);
2457 tt_assert(!memcmp(s, "\0\0x\0\0", 5));
2458 free(s);
2459 s = NULL;
2461 /* Test out the crazy old behavior of the deprecated
2462 * evhttp_decode_uri */
2463 OLD_DEC("http://example.com/normal+path/?key=val+with+spaces",
2464 "http://example.com/normal+path/?key=val with spaces");
2466 end:
2467 if (s)
2468 free(s);
2469 if (s2)
2470 free(s2);
2471 #undef ENC
2472 #undef DEC
2473 #undef OLD_DEC
2476 static void
2477 http_base_test(void *ptr)
2479 struct event_base *base = NULL;
2480 struct bufferevent *bev;
2481 evutil_socket_t fd;
2482 const char *http_request;
2483 ev_uint16_t port = 0;
2485 test_ok = 0;
2486 base = event_base_new();
2487 http = http_setup(&port, base);
2489 fd = http_connect("127.0.0.1", port);
2491 /* Stupid thing to send a request */
2492 bev = bufferevent_socket_new(base, fd, 0);
2493 bufferevent_setcb(bev, http_readcb, http_writecb,
2494 http_errorcb, base);
2495 bufferevent_base_set(base, bev);
2497 http_request =
2498 "GET /test HTTP/1.1\r\n"
2499 "Host: somehost\r\n"
2500 "Connection: close\r\n"
2501 "\r\n";
2503 bufferevent_write(bev, http_request, strlen(http_request));
2505 event_base_dispatch(base);
2507 bufferevent_free(bev);
2508 evutil_closesocket(fd);
2510 evhttp_free(http);
2512 tt_int_op(test_ok, ==, 2);
2514 end:
2515 if (base)
2516 event_base_free(base);
2520 * the server is just going to close the connection if it times out during
2521 * reading the headers.
2524 static void
2525 http_incomplete_readcb(struct bufferevent *bev, void *arg)
2527 test_ok = -1;
2528 event_base_loopexit(exit_base,NULL);
2531 static void
2532 http_incomplete_errorcb(struct bufferevent *bev, short what, void *arg)
2534 if (what == (BEV_EVENT_READING|BEV_EVENT_EOF))
2535 test_ok++;
2536 else
2537 test_ok = -2;
2538 event_base_loopexit(exit_base,NULL);
2541 static void
2542 http_incomplete_writecb(struct bufferevent *bev, void *arg)
2544 if (arg != NULL) {
2545 evutil_socket_t fd = *(evutil_socket_t *)arg;
2546 /* terminate the write side to simulate EOF */
2547 shutdown(fd, SHUT_WR);
2549 if (evbuffer_get_length(bufferevent_get_output(bev)) == 0) {
2550 /* enable reading of the reply */
2551 bufferevent_enable(bev, EV_READ);
2552 test_ok++;
2556 static void
2557 _http_incomplete_test(struct basic_test_data *data, int use_timeout)
2559 struct bufferevent *bev;
2560 evutil_socket_t fd;
2561 const char *http_request;
2562 ev_uint16_t port = 0;
2563 struct timeval tv_start, tv_end;
2565 exit_base = data->base;
2567 test_ok = 0;
2569 http = http_setup(&port, data->base);
2570 evhttp_set_timeout(http, 1);
2572 fd = http_connect("127.0.0.1", port);
2574 /* Stupid thing to send a request */
2575 bev = bufferevent_socket_new(data->base, fd, 0);
2576 bufferevent_setcb(bev,
2577 http_incomplete_readcb, http_incomplete_writecb,
2578 http_incomplete_errorcb, use_timeout ? NULL : &fd);
2580 http_request =
2581 "GET /test HTTP/1.1\r\n"
2582 "Host: somehost\r\n";
2584 bufferevent_write(bev, http_request, strlen(http_request));
2586 evutil_gettimeofday(&tv_start, NULL);
2588 event_base_dispatch(data->base);
2590 evutil_gettimeofday(&tv_end, NULL);
2591 evutil_timersub(&tv_end, &tv_start, &tv_end);
2593 bufferevent_free(bev);
2594 if (use_timeout) {
2595 evutil_closesocket(fd);
2598 evhttp_free(http);
2600 if (use_timeout && tv_end.tv_sec >= 3) {
2601 tt_abort_msg("time");
2602 } else if (!use_timeout && tv_end.tv_sec >= 1) {
2603 /* we should be done immediately */
2604 tt_abort_msg("time");
2607 tt_int_op(test_ok, ==, 2);
2608 end:
2611 static void
2612 http_incomplete_test(void *arg)
2614 _http_incomplete_test(arg, 0);
2616 static void
2617 http_incomplete_timeout_test(void *arg)
2619 _http_incomplete_test(arg, 1);
2623 * the server is going to reply with chunked data.
2626 static void
2627 http_chunked_readcb(struct bufferevent *bev, void *arg)
2629 /* nothing here */
2632 static void
2633 http_chunked_errorcb(struct bufferevent *bev, short what, void *arg)
2635 if (!test_ok)
2636 goto out;
2638 test_ok = -1;
2640 if ((what & BEV_EVENT_EOF) != 0) {
2641 struct evhttp_request *req = evhttp_request_new(NULL, NULL);
2642 const char *header;
2643 enum message_read_status done;
2645 /* req->kind = EVHTTP_RESPONSE; */
2646 done = evhttp_parse_firstline(req, bufferevent_get_input(bev));
2647 if (done != ALL_DATA_READ)
2648 goto out;
2650 done = evhttp_parse_headers(req, bufferevent_get_input(bev));
2651 if (done != ALL_DATA_READ)
2652 goto out;
2654 header = evhttp_find_header(evhttp_request_get_input_headers(req), "Transfer-Encoding");
2655 if (header == NULL || strcmp(header, "chunked"))
2656 goto out;
2658 header = evhttp_find_header(evhttp_request_get_input_headers(req), "Connection");
2659 if (header == NULL || strcmp(header, "close"))
2660 goto out;
2662 header = evbuffer_readln(bufferevent_get_input(bev), NULL, EVBUFFER_EOL_CRLF);
2663 if (header == NULL)
2664 goto out;
2665 /* 13 chars */
2666 if (strcmp(header, "d"))
2667 goto out;
2668 free((char*)header);
2670 if (strncmp((char *)evbuffer_pullup(bufferevent_get_input(bev), 13),
2671 "This is funny", 13))
2672 goto out;
2674 evbuffer_drain(bufferevent_get_input(bev), 13 + 2);
2676 header = evbuffer_readln(bufferevent_get_input(bev), NULL, EVBUFFER_EOL_CRLF);
2677 if (header == NULL)
2678 goto out;
2679 /* 18 chars */
2680 if (strcmp(header, "12"))
2681 goto out;
2682 free((char *)header);
2684 if (strncmp((char *)evbuffer_pullup(bufferevent_get_input(bev), 18),
2685 "but not hilarious.", 18))
2686 goto out;
2688 evbuffer_drain(bufferevent_get_input(bev), 18 + 2);
2690 header = evbuffer_readln(bufferevent_get_input(bev), NULL, EVBUFFER_EOL_CRLF);
2691 if (header == NULL)
2692 goto out;
2693 /* 8 chars */
2694 if (strcmp(header, "8"))
2695 goto out;
2696 free((char *)header);
2698 if (strncmp((char *)evbuffer_pullup(bufferevent_get_input(bev), 8),
2699 "bwv 1052.", 8))
2700 goto out;
2702 evbuffer_drain(bufferevent_get_input(bev), 8 + 2);
2704 header = evbuffer_readln(bufferevent_get_input(bev), NULL, EVBUFFER_EOL_CRLF);
2705 if (header == NULL)
2706 goto out;
2707 /* 0 chars */
2708 if (strcmp(header, "0"))
2709 goto out;
2710 free((char *)header);
2712 test_ok = 2;
2714 evhttp_request_free(req);
2717 out:
2718 event_base_loopexit(arg, NULL);
2721 static void
2722 http_chunked_writecb(struct bufferevent *bev, void *arg)
2724 if (evbuffer_get_length(bufferevent_get_output(bev)) == 0) {
2725 /* enable reading of the reply */
2726 bufferevent_enable(bev, EV_READ);
2727 test_ok++;
2731 static void
2732 http_chunked_request_done(struct evhttp_request *req, void *arg)
2734 if (evhttp_request_get_response_code(req) != HTTP_OK) {
2735 fprintf(stderr, "FAILED\n");
2736 exit(1);
2739 if (evhttp_find_header(evhttp_request_get_input_headers(req),
2740 "Transfer-Encoding") == NULL) {
2741 fprintf(stderr, "FAILED\n");
2742 exit(1);
2745 if (evbuffer_get_length(evhttp_request_get_input_buffer(req)) != 13 + 18 + 8) {
2746 fprintf(stderr, "FAILED\n");
2747 exit(1);
2750 if (strncmp((char *)evbuffer_pullup(evhttp_request_get_input_buffer(req), 13 + 18 + 8),
2751 "This is funnybut not hilarious.bwv 1052",
2752 13 + 18 + 8)) {
2753 fprintf(stderr, "FAILED\n");
2754 exit(1);
2757 test_ok = 1;
2758 event_base_loopexit(arg, NULL);
2761 static void
2762 http_chunk_out_test(void *arg)
2764 struct basic_test_data *data = arg;
2765 struct bufferevent *bev;
2766 evutil_socket_t fd;
2767 const char *http_request;
2768 ev_uint16_t port = 0;
2769 struct timeval tv_start, tv_end;
2770 struct evhttp_connection *evcon = NULL;
2771 struct evhttp_request *req = NULL;
2772 int i;
2774 exit_base = data->base;
2775 test_ok = 0;
2777 http = http_setup(&port, data->base);
2779 fd = http_connect("127.0.0.1", port);
2781 /* Stupid thing to send a request */
2782 bev = bufferevent_socket_new(data->base, fd, 0);
2783 bufferevent_setcb(bev,
2784 http_chunked_readcb, http_chunked_writecb,
2785 http_chunked_errorcb, data->base);
2787 http_request =
2788 "GET /chunked HTTP/1.1\r\n"
2789 "Host: somehost\r\n"
2790 "Connection: close\r\n"
2791 "\r\n";
2793 bufferevent_write(bev, http_request, strlen(http_request));
2795 evutil_gettimeofday(&tv_start, NULL);
2797 event_base_dispatch(data->base);
2799 bufferevent_free(bev);
2801 evutil_gettimeofday(&tv_end, NULL);
2802 evutil_timersub(&tv_end, &tv_start, &tv_end);
2804 tt_int_op(tv_end.tv_sec, <, 1);
2806 tt_int_op(test_ok, ==, 2);
2808 /* now try again with the regular connection object */
2809 evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port);
2810 tt_assert(evcon);
2812 /* make two requests to check the keepalive behavior */
2813 for (i = 0; i < 2; i++) {
2814 test_ok = 0;
2815 req = evhttp_request_new(http_chunked_request_done,data->base);
2817 /* Add the information that we care about */
2818 evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
2820 /* We give ownership of the request to the connection */
2821 if (evhttp_make_request(evcon, req,
2822 EVHTTP_REQ_GET, "/chunked") == -1) {
2823 tt_abort_msg("Couldn't make request");
2826 event_base_dispatch(data->base);
2828 tt_assert(test_ok == 1);
2831 end:
2832 if (evcon)
2833 evhttp_connection_free(evcon);
2834 if (http)
2835 evhttp_free(http);
2838 static void
2839 http_stream_out_test(void *arg)
2841 struct basic_test_data *data = arg;
2842 ev_uint16_t port = 0;
2843 struct evhttp_connection *evcon = NULL;
2844 struct evhttp_request *req = NULL;
2846 test_ok = 0;
2847 exit_base = data->base;
2849 http = http_setup(&port, data->base);
2851 evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port);
2852 tt_assert(evcon);
2855 * At this point, we want to schedule a request to the HTTP
2856 * server using our make request method.
2859 req = evhttp_request_new(http_request_done,
2860 (void *)"This is funnybut not hilarious.bwv 1052");
2862 /* Add the information that we care about */
2863 evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
2865 /* We give ownership of the request to the connection */
2866 if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/streamed")
2867 == -1) {
2868 tt_abort_msg("Couldn't make request");
2871 event_base_dispatch(data->base);
2873 end:
2874 if (evcon)
2875 evhttp_connection_free(evcon);
2876 if (http)
2877 evhttp_free(http);
2880 static void
2881 http_stream_in_chunk(struct evhttp_request *req, void *arg)
2883 struct evbuffer *reply = arg;
2885 if (evhttp_request_get_response_code(req) != HTTP_OK) {
2886 fprintf(stderr, "FAILED\n");
2887 exit(1);
2890 evbuffer_add_buffer(reply, evhttp_request_get_input_buffer(req));
2893 static void
2894 http_stream_in_done(struct evhttp_request *req, void *arg)
2896 if (evbuffer_get_length(evhttp_request_get_input_buffer(req)) != 0) {
2897 fprintf(stderr, "FAILED\n");
2898 exit(1);
2901 event_base_loopexit(exit_base, NULL);
2905 * Makes a request and reads the response in chunks.
2907 static void
2908 _http_stream_in_test(struct basic_test_data *data, char const *url,
2909 size_t expected_len, char const *expected)
2911 struct evhttp_connection *evcon;
2912 struct evbuffer *reply = evbuffer_new();
2913 struct evhttp_request *req = NULL;
2914 ev_uint16_t port = 0;
2916 exit_base = data->base;
2917 http = http_setup(&port, data->base);
2919 evcon = evhttp_connection_base_new(data->base, NULL,"127.0.0.1", port);
2920 tt_assert(evcon);
2922 req = evhttp_request_new(http_stream_in_done, reply);
2923 evhttp_request_set_chunked_cb(req, http_stream_in_chunk);
2925 /* We give ownership of the request to the connection */
2926 if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, url) == -1) {
2927 tt_abort_msg("Couldn't make request");
2930 event_base_dispatch(data->base);
2932 if (evbuffer_get_length(reply) != expected_len) {
2933 TT_DIE(("reply length %lu; expected %lu; FAILED (%s)\n",
2934 (unsigned long)evbuffer_get_length(reply),
2935 (unsigned long)expected_len,
2936 (char*)evbuffer_pullup(reply, -1)));
2939 if (memcmp(evbuffer_pullup(reply, -1), expected, expected_len) != 0) {
2940 tt_abort_msg("Memory mismatch");
2943 test_ok = 1;
2944 end:
2945 if (reply)
2946 evbuffer_free(reply);
2947 if (evcon)
2948 evhttp_connection_free(evcon);
2949 if (http)
2950 evhttp_free(http);
2953 static void
2954 http_stream_in_test(void *arg)
2956 _http_stream_in_test(arg, "/chunked", 13 + 18 + 8,
2957 "This is funnybut not hilarious.bwv 1052");
2959 _http_stream_in_test(arg, "/test", strlen(BASIC_REQUEST_BODY),
2960 BASIC_REQUEST_BODY);
2963 static void
2964 http_stream_in_cancel_chunk(struct evhttp_request *req, void *arg)
2966 tt_int_op(evhttp_request_get_response_code(req), ==, HTTP_OK);
2968 end:
2969 evhttp_cancel_request(req);
2970 event_base_loopexit(arg, NULL);
2973 static void
2974 http_stream_in_cancel_done(struct evhttp_request *req, void *arg)
2976 /* should never be called */
2977 tt_fail_msg("In cancel done");
2980 static void
2981 http_stream_in_cancel_test(void *arg)
2983 struct basic_test_data *data = arg;
2984 struct evhttp_connection *evcon;
2985 struct evhttp_request *req = NULL;
2986 ev_uint16_t port = 0;
2988 http = http_setup(&port, data->base);
2990 evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port);
2991 tt_assert(evcon);
2993 req = evhttp_request_new(http_stream_in_cancel_done, data->base);
2994 evhttp_request_set_chunked_cb(req, http_stream_in_cancel_chunk);
2996 /* We give ownership of the request to the connection */
2997 if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/chunked") == -1) {
2998 tt_abort_msg("Couldn't make request");
3001 event_base_dispatch(data->base);
3003 test_ok = 1;
3004 end:
3005 evhttp_connection_free(evcon);
3006 evhttp_free(http);
3010 static void
3011 http_connection_fail_done(struct evhttp_request *req, void *arg)
3013 /* An ENETUNREACH error results in an unrecoverable
3014 * evhttp_connection error (see evhttp_connection_fail()). The
3015 * connection will be reset, and the user will be notified with a NULL
3016 * req parameter. */
3017 tt_assert(!req);
3019 test_ok = 1;
3021 end:
3022 event_base_loopexit(arg, NULL);
3025 /* Test unrecoverable evhttp_connection errors by generating an ENETUNREACH
3026 * error on connection. */
3027 static void
3028 http_connection_fail_test(void *arg)
3030 struct basic_test_data *data = arg;
3031 ev_uint16_t port = 0;
3032 struct evhttp_connection *evcon = NULL;
3033 struct evhttp_request *req = NULL;
3035 exit_base = data->base;
3036 test_ok = 0;
3038 /* auto detect a port */
3039 http = http_setup(&port, data->base);
3040 evhttp_free(http);
3041 http = NULL;
3043 /* Pick an unroutable address. This administratively scoped multicast
3044 * address should do when working with TCP. */
3045 evcon = evhttp_connection_base_new(data->base, NULL, "239.10.20.30", 80);
3046 tt_assert(evcon);
3049 * At this point, we want to schedule an HTTP GET request
3050 * server using our make request method.
3053 req = evhttp_request_new(http_connection_fail_done, data->base);
3054 tt_assert(req);
3056 if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/") == -1) {
3057 tt_abort_msg("Couldn't make request");
3060 event_base_dispatch(data->base);
3062 tt_int_op(test_ok, ==, 1);
3064 end:
3065 if (evcon)
3066 evhttp_connection_free(evcon);
3069 static void
3070 http_connection_retry_done(struct evhttp_request *req, void *arg)
3072 tt_assert(req);
3073 tt_int_op(evhttp_request_get_response_code(req), !=, HTTP_OK);
3074 if (evhttp_find_header(evhttp_request_get_input_headers(req), "Content-Type") != NULL) {
3075 tt_abort_msg("(content type)\n");
3078 tt_uint_op(evbuffer_get_length(evhttp_request_get_input_buffer(req)), ==, 0);
3080 test_ok = 1;
3081 end:
3082 event_base_loopexit(arg,NULL);
3085 static struct event_base *http_make_web_server_base=NULL;
3086 static void
3087 http_make_web_server(evutil_socket_t fd, short what, void *arg)
3089 ev_uint16_t port = *(ev_uint16_t*)arg;
3090 http = http_setup(&port, http_make_web_server_base);
3093 static void
3094 http_connection_retry_test(void *arg)
3096 struct basic_test_data *data = arg;
3097 ev_uint16_t port = 0;
3098 struct evhttp_connection *evcon = NULL;
3099 struct evhttp_request *req = NULL;
3100 struct timeval tv, tv_start, tv_end;
3102 exit_base = data->base;
3103 test_ok = 0;
3105 /* auto detect a port */
3106 http = http_setup(&port, data->base);
3107 evhttp_free(http);
3108 http = NULL;
3110 evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port);
3111 tt_assert(evcon);
3113 evhttp_connection_set_timeout(evcon, 1);
3114 /* also bind to local host */
3115 evhttp_connection_set_local_address(evcon, "127.0.0.1");
3118 * At this point, we want to schedule an HTTP GET request
3119 * server using our make request method.
3122 req = evhttp_request_new(http_connection_retry_done, data->base);
3123 tt_assert(req);
3125 /* Add the information that we care about */
3126 evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
3128 if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET,
3129 "/?arg=val") == -1) {
3130 tt_abort_msg("Couldn't make request");
3133 evutil_gettimeofday(&tv_start, NULL);
3134 event_base_dispatch(data->base);
3135 evutil_gettimeofday(&tv_end, NULL);
3136 evutil_timersub(&tv_end, &tv_start, &tv_end);
3137 tt_int_op(tv_end.tv_sec, <, 1);
3139 tt_int_op(test_ok, ==, 1);
3142 * now test the same but with retries
3144 test_ok = 0;
3146 evhttp_connection_set_timeout(evcon, 1);
3147 evhttp_connection_set_retries(evcon, 1);
3149 req = evhttp_request_new(http_connection_retry_done, data->base);
3150 tt_assert(req);
3152 /* Add the information that we care about */
3153 evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
3155 if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET,
3156 "/?arg=val") == -1) {
3157 tt_abort_msg("Couldn't make request");
3160 evutil_gettimeofday(&tv_start, NULL);
3161 event_base_dispatch(data->base);
3162 evutil_gettimeofday(&tv_end, NULL);
3163 evutil_timersub(&tv_end, &tv_start, &tv_end);
3164 tt_int_op(tv_end.tv_sec, >, 1);
3165 tt_int_op(tv_end.tv_sec, <, 6);
3167 tt_assert(test_ok == 1);
3170 * now test the same but with retries and give it a web server
3171 * at the end
3173 test_ok = 0;
3175 evhttp_connection_set_timeout(evcon, 1);
3176 evhttp_connection_set_retries(evcon, 3);
3178 req = evhttp_request_new(http_dispatcher_test_done, data->base);
3179 tt_assert(req);
3181 /* Add the information that we care about */
3182 evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
3184 if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET,
3185 "/?arg=val") == -1) {
3186 tt_abort_msg("Couldn't make request");
3189 /* start up a web server one second after the connection tried
3190 * to send a request
3192 evutil_timerclear(&tv);
3193 tv.tv_sec = 1;
3194 http_make_web_server_base = data->base;
3195 event_base_once(data->base, -1, EV_TIMEOUT, http_make_web_server, &port, &tv);
3197 evutil_gettimeofday(&tv_start, NULL);
3198 event_base_dispatch(data->base);
3199 evutil_gettimeofday(&tv_end, NULL);
3201 evutil_timersub(&tv_end, &tv_start, &tv_end);
3203 tt_int_op(tv_end.tv_sec, >, 1);
3204 tt_int_op(tv_end.tv_sec, <, 6);
3206 tt_int_op(test_ok, ==, 1);
3208 end:
3209 if (evcon)
3210 evhttp_connection_free(evcon);
3211 if (http)
3212 evhttp_free(http);
3215 static void
3216 http_primitives(void *ptr)
3218 char *escaped = NULL;
3219 struct evhttp *http;
3221 escaped = evhttp_htmlescape("<script>");
3222 tt_str_op(escaped, ==, "&lt;script&gt;");
3223 free(escaped);
3225 escaped = evhttp_htmlescape("\"\'&");
3226 tt_str_op(escaped, ==, "&quot;&#039;&amp;");
3228 http = evhttp_new(NULL);
3229 tt_int_op(evhttp_set_cb(http, "/test", http_basic_cb, NULL), ==, 0);
3230 tt_int_op(evhttp_set_cb(http, "/test", http_basic_cb, NULL), ==, -1);
3231 tt_int_op(evhttp_del_cb(http, "/test"), ==, 0);
3232 tt_int_op(evhttp_del_cb(http, "/test"), ==, -1);
3233 tt_int_op(evhttp_set_cb(http, "/test", http_basic_cb, NULL), ==, 0);
3234 evhttp_free(http);
3236 end:
3237 if (escaped)
3238 free(escaped);
3241 static void
3242 http_multi_line_header_test(void *arg)
3244 struct basic_test_data *data = arg;
3245 struct bufferevent *bev= NULL;
3246 evutil_socket_t fd = -1;
3247 const char *http_start_request;
3248 ev_uint16_t port = 0;
3250 test_ok = 0;
3252 http = http_setup(&port, data->base);
3254 fd = http_connect("127.0.0.1", port);
3256 /* Stupid thing to send a request */
3257 bev = bufferevent_socket_new(data->base, fd, 0);
3258 bufferevent_setcb(bev, http_readcb, http_writecb,
3259 http_errorcb, data->base);
3261 http_start_request =
3262 "GET /test HTTP/1.1\r\n"
3263 "Host: somehost\r\n"
3264 "Connection: close\r\n"
3265 "X-Multi: aaaaaaaa\r\n"
3266 " a\r\n"
3267 "\tEND\r\n"
3268 "X-Last: last\r\n"
3269 "\r\n";
3271 bufferevent_write(bev, http_start_request, strlen(http_start_request));
3273 event_base_dispatch(data->base);
3275 tt_int_op(test_ok, ==, 4);
3276 end:
3277 if (bev)
3278 bufferevent_free(bev);
3279 if (fd >= 0)
3280 evutil_closesocket(fd);
3281 if (http)
3282 evhttp_free(http);
3285 static void
3286 http_request_bad(struct evhttp_request *req, void *arg)
3288 if (req != NULL) {
3289 fprintf(stderr, "FAILED\n");
3290 exit(1);
3293 test_ok = 1;
3294 event_base_loopexit(arg, NULL);
3297 static void
3298 http_negative_content_length_test(void *arg)
3300 struct basic_test_data *data = arg;
3301 ev_uint16_t port = 0;
3302 struct evhttp_connection *evcon = NULL;
3303 struct evhttp_request *req = NULL;
3305 test_ok = 0;
3307 http = http_setup(&port, data->base);
3309 evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port);
3310 tt_assert(evcon);
3313 * At this point, we want to schedule a request to the HTTP
3314 * server using our make request method.
3317 req = evhttp_request_new(http_request_bad, data->base);
3319 /* Cause the response to have a negative content-length */
3320 evhttp_add_header(evhttp_request_get_output_headers(req), "X-Negative", "makeitso");
3322 /* We give ownership of the request to the connection */
3323 if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test") == -1) {
3324 tt_abort_msg("Couldn't make request");
3327 event_base_dispatch(data->base);
3329 end:
3330 if (evcon)
3331 evhttp_connection_free(evcon);
3332 if (http)
3333 evhttp_free(http);
3337 static void
3338 http_data_length_constraints_test_done(struct evhttp_request *req, void *arg)
3340 tt_assert(req);
3341 tt_int_op(evhttp_request_get_response_code(req), ==, HTTP_BADREQUEST);
3342 end:
3343 event_base_loopexit(arg, NULL);
3346 static void
3347 http_large_entity_test_done(struct evhttp_request *req, void *arg)
3349 tt_assert(req);
3350 tt_int_op(evhttp_request_get_response_code(req), ==, HTTP_ENTITYTOOLARGE);
3351 end:
3352 event_base_loopexit(arg, NULL);
3355 static void
3356 http_data_length_constraints_test(void *arg)
3358 struct basic_test_data *data = arg;
3359 ev_uint16_t port = 0;
3360 struct evhttp_connection *evcon = NULL;
3361 struct evhttp_request *req = NULL;
3362 char long_str[8192];
3364 test_ok = 0;
3366 http = http_setup(&port, data->base);
3368 evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port);
3369 tt_assert(evcon);
3371 /* also bind to local host */
3372 evhttp_connection_set_local_address(evcon, "127.0.0.1");
3375 * At this point, we want to schedule an HTTP GET request
3376 * server using our make request method.
3379 req = evhttp_request_new(http_data_length_constraints_test_done, data->base);
3380 tt_assert(req);
3382 memset(long_str, 'a', 8192);
3383 long_str[8191] = '\0';
3384 /* Add the information that we care about */
3385 evhttp_set_max_headers_size(http, 8191);
3386 evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
3387 evhttp_add_header(evhttp_request_get_output_headers(req), "Longheader", long_str);
3389 if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/?arg=val") == -1) {
3390 tt_abort_msg("Couldn't make request");
3392 event_base_dispatch(data->base);
3394 req = evhttp_request_new(http_data_length_constraints_test_done, data->base);
3395 tt_assert(req);
3396 evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
3398 /* GET /?arg=verylongvalue HTTP/1.1 */
3399 if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, long_str) == -1) {
3400 tt_abort_msg("Couldn't make request");
3402 event_base_dispatch(data->base);
3404 evhttp_set_max_body_size(http, 8190);
3405 req = evhttp_request_new(http_data_length_constraints_test_done, data->base);
3406 evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
3407 evbuffer_add_printf(evhttp_request_get_output_buffer(req), "%s", long_str);
3408 if (evhttp_make_request(evcon, req, EVHTTP_REQ_POST, "/") == -1) {
3409 tt_abort_msg("Couldn't make request");
3411 event_base_dispatch(data->base);
3413 req = evhttp_request_new(http_large_entity_test_done, data->base);
3414 evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
3415 evhttp_add_header(evhttp_request_get_output_headers(req), "Expect", "100-continue");
3416 evbuffer_add_printf(evhttp_request_get_output_buffer(req), "%s", long_str);
3417 if (evhttp_make_request(evcon, req, EVHTTP_REQ_POST, "/") == -1) {
3418 tt_abort_msg("Couldn't make request");
3420 event_base_dispatch(data->base);
3422 test_ok = 1;
3423 end:
3424 if (evcon)
3425 evhttp_connection_free(evcon);
3426 if (http)
3427 evhttp_free(http);
3431 * Testing client reset of server chunked connections
3434 struct terminate_state {
3435 struct event_base *base;
3436 struct evhttp_request *req;
3437 struct bufferevent *bev;
3438 evutil_socket_t fd;
3439 int gotclosecb: 1;
3442 static void
3443 terminate_chunked_trickle_cb(evutil_socket_t fd, short events, void *arg)
3445 struct terminate_state *state = arg;
3446 struct evbuffer *evb;
3447 struct timeval tv;
3449 if (evhttp_request_get_connection(state->req) == NULL) {
3450 test_ok = 1;
3451 evhttp_request_free(state->req);
3452 event_base_loopexit(state->base,NULL);
3453 return;
3456 evb = evbuffer_new();
3457 evbuffer_add_printf(evb, "%p", evb);
3458 evhttp_send_reply_chunk(state->req, evb);
3459 evbuffer_free(evb);
3461 tv.tv_sec = 0;
3462 tv.tv_usec = 3000;
3463 EVUTIL_ASSERT(state);
3464 EVUTIL_ASSERT(state->base);
3465 event_base_once(state->base, -1, EV_TIMEOUT, terminate_chunked_trickle_cb, arg, &tv);
3468 static void
3469 terminate_chunked_close_cb(struct evhttp_connection *evcon, void *arg)
3471 struct terminate_state *state = arg;
3472 state->gotclosecb = 1;
3475 static void
3476 terminate_chunked_cb(struct evhttp_request *req, void *arg)
3478 struct terminate_state *state = arg;
3479 struct timeval tv;
3481 /* we want to know if this connection closes on us */
3482 evhttp_connection_set_closecb(
3483 evhttp_request_get_connection(req),
3484 terminate_chunked_close_cb, arg);
3486 state->req = req;
3488 evhttp_send_reply_start(req, HTTP_OK, "OK");
3490 tv.tv_sec = 0;
3491 tv.tv_usec = 3000;
3492 event_base_once(state->base, -1, EV_TIMEOUT, terminate_chunked_trickle_cb, arg, &tv);
3495 static void
3496 terminate_chunked_client(evutil_socket_t fd, short event, void *arg)
3498 struct terminate_state *state = arg;
3499 bufferevent_free(state->bev);
3500 evutil_closesocket(state->fd);
3503 static void
3504 terminate_readcb(struct bufferevent *bev, void *arg)
3506 /* just drop the data */
3507 evbuffer_drain(bufferevent_get_input(bev), -1);
3511 static void
3512 http_terminate_chunked_test(void *arg)
3514 struct basic_test_data *data = arg;
3515 struct bufferevent *bev = NULL;
3516 struct timeval tv;
3517 const char *http_request;
3518 ev_uint16_t port = 0;
3519 evutil_socket_t fd = -1;
3520 struct terminate_state terminate_state;
3522 test_ok = 0;
3524 http = http_setup(&port, data->base);
3525 evhttp_del_cb(http, "/test");
3526 tt_assert(evhttp_set_cb(http, "/test",
3527 terminate_chunked_cb, &terminate_state) == 0);
3529 fd = http_connect("127.0.0.1", port);
3531 /* Stupid thing to send a request */
3532 bev = bufferevent_socket_new(data->base, fd, 0);
3533 bufferevent_setcb(bev, terminate_readcb, http_writecb,
3534 http_errorcb, data->base);
3536 memset(&terminate_state, 0, sizeof(terminate_state));
3537 terminate_state.base = data->base;
3538 terminate_state.fd = fd;
3539 terminate_state.bev = bev;
3540 terminate_state.gotclosecb = 0;
3542 /* first half of the http request */
3543 http_request =
3544 "GET /test HTTP/1.1\r\n"
3545 "Host: some\r\n\r\n";
3547 bufferevent_write(bev, http_request, strlen(http_request));
3548 evutil_timerclear(&tv);
3549 tv.tv_usec = 10000;
3550 event_base_once(data->base, -1, EV_TIMEOUT, terminate_chunked_client, &terminate_state,
3551 &tv);
3553 event_base_dispatch(data->base);
3555 if (terminate_state.gotclosecb == 0)
3556 test_ok = 0;
3558 end:
3559 if (fd >= 0)
3560 evutil_closesocket(fd);
3561 if (http)
3562 evhttp_free(http);
3565 #define HTTP_LEGACY(name) \
3566 { #name, run_legacy_test_fn, TT_ISOLATED|TT_LEGACY, &legacy_setup, \
3567 http_##name##_test }
3569 #define HTTP(name) \
3570 { #name, http_##name##_test, TT_ISOLATED, &basic_setup, NULL }
3572 struct testcase_t http_testcases[] = {
3573 { "primitives", http_primitives, 0, NULL, NULL },
3574 { "base", http_base_test, TT_FORK, NULL, NULL },
3575 { "bad_headers", http_bad_header_test, 0, NULL, NULL },
3576 { "parse_query", http_parse_query_test, 0, NULL, NULL },
3577 { "parse_uri", http_parse_uri_test, 0, NULL, NULL },
3578 { "parse_uri_nc", http_parse_uri_test, 0, &basic_setup, (void*)"nc" },
3579 { "uriencode", http_uriencode_test, 0, NULL, NULL },
3580 HTTP(basic),
3581 HTTP(cancel),
3582 HTTP(virtual_host),
3583 HTTP(post),
3584 HTTP(put),
3585 HTTP(delete),
3586 HTTP(allowed_methods),
3587 HTTP(failure),
3588 HTTP(connection),
3589 HTTP(persist_connection),
3590 HTTP(connection_async),
3591 HTTP(close_detection),
3592 HTTP(close_detection_delay),
3593 HTTP(bad_request),
3594 HTTP(incomplete),
3595 HTTP(incomplete_timeout),
3596 HTTP(terminate_chunked),
3598 HTTP(highport),
3599 HTTP(dispatcher),
3600 HTTP(multi_line_header),
3601 HTTP(negative_content_length),
3602 HTTP(chunk_out),
3603 HTTP(stream_out),
3605 HTTP(stream_in),
3606 HTTP(stream_in_cancel),
3608 HTTP(connection_fail),
3609 HTTP(connection_retry),
3610 HTTP(data_length_constraints),
3612 END_OF_TESTCASES