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
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.
27 #include "util-internal.h"
35 #include "event2/event-config.h"
37 #include <sys/types.h>
39 #ifdef EVENT__HAVE_SYS_TIME_H
42 #include <sys/queue.h>
44 #include <sys/socket.h>
55 #include "event2/dns.h"
57 #include "event2/event.h"
58 #include "event2/http.h"
59 #include "event2/buffer.h"
60 #include "event2/bufferevent.h"
61 #include "event2/bufferevent_ssl.h"
62 #include "event2/util.h"
63 #include "event2/listener.h"
64 #include "log-internal.h"
65 #include "http-internal.h"
67 #include "regress_testutils.h"
69 /* set if a test needs to call loopexit on a base */
70 static struct event_base *exit_base;
72 static char const BASIC_REQUEST_BODY[] = "This is funny";
74 static void http_basic_cb(struct evhttp_request *req, void *arg);
75 static void http_timeout_cb(struct evhttp_request *req, void *arg);
76 static void http_large_cb(struct evhttp_request *req, void *arg);
77 static void http_chunked_cb(struct evhttp_request *req, void *arg);
78 static void http_post_cb(struct evhttp_request *req, void *arg);
79 static void http_put_cb(struct evhttp_request *req, void *arg);
80 static void http_delete_cb(struct evhttp_request *req, void *arg);
81 static void http_delay_cb(struct evhttp_request *req, void *arg);
82 static void http_large_delay_cb(struct evhttp_request *req, void *arg);
83 static void http_badreq_cb(struct evhttp_request *req, void *arg);
84 static void http_dispatcher_cb(struct evhttp_request *req, void *arg);
85 static void http_on_complete_cb(struct evhttp_request *req, void *arg);
87 #define HTTP_BIND_IPV6 1
88 #define HTTP_BIND_SSL 2
89 #define HTTP_SSL_FILTER 4
91 http_bind(struct evhttp *myhttp, ev_uint16_t *pport, int mask)
94 struct evhttp_bound_socket *sock;
95 int ipv6 = mask & HTTP_BIND_IPV6;
98 sock = evhttp_bind_socket_with_handle(myhttp, "::1", *pport);
100 sock = evhttp_bind_socket_with_handle(myhttp, "127.0.0.1", *pport);
106 event_errx(1, "Could not start web server");
109 port = regress_get_socket_port(evhttp_bound_socket_get_fd(sock));
112 *pport = (ev_uint16_t) port;
117 #ifdef EVENT__HAVE_OPENSSL
118 static struct bufferevent *
119 https_bev(struct event_base *base, void *arg)
121 SSL *ssl = SSL_new(get_ssl_ctx());
123 SSL_use_certificate(ssl, ssl_getcert(ssl_getkey()));
124 SSL_use_PrivateKey(ssl, ssl_getkey());
126 return bufferevent_openssl_socket_new(
127 base, -1, ssl, BUFFEREVENT_SSL_ACCEPTING,
128 BEV_OPT_CLOSE_ON_FREE);
131 static struct evhttp *
132 http_setup_gencb(ev_uint16_t *pport, struct event_base *base, int mask,
133 void (*cb)(struct evhttp_request *, void *), void *cbarg)
135 struct evhttp *myhttp;
137 /* Try a few different ports */
138 myhttp = evhttp_new(base);
140 if (http_bind(myhttp, pport, mask) < 0)
142 #ifdef EVENT__HAVE_OPENSSL
143 if (mask & HTTP_BIND_SSL) {
145 evhttp_set_bevcb(myhttp, https_bev, NULL);
149 evhttp_set_gencb(myhttp, cb, cbarg);
151 /* Register a callback for certain types of requests */
152 evhttp_set_cb(myhttp, "/test", http_basic_cb, myhttp);
153 evhttp_set_cb(myhttp, "/test nonconformant", http_basic_cb, myhttp);
154 evhttp_set_cb(myhttp, "/timeout", http_timeout_cb, myhttp);
155 evhttp_set_cb(myhttp, "/large", http_large_cb, base);
156 evhttp_set_cb(myhttp, "/chunked", http_chunked_cb, base);
157 evhttp_set_cb(myhttp, "/streamed", http_chunked_cb, base);
158 evhttp_set_cb(myhttp, "/postit", http_post_cb, base);
159 evhttp_set_cb(myhttp, "/putit", http_put_cb, base);
160 evhttp_set_cb(myhttp, "/deleteit", http_delete_cb, base);
161 evhttp_set_cb(myhttp, "/delay", http_delay_cb, base);
162 evhttp_set_cb(myhttp, "/largedelay", http_large_delay_cb, base);
163 evhttp_set_cb(myhttp, "/badrequest", http_badreq_cb, base);
164 evhttp_set_cb(myhttp, "/oncomplete", http_on_complete_cb, base);
165 evhttp_set_cb(myhttp, "/", http_dispatcher_cb, base);
168 static struct evhttp *
169 http_setup(ev_uint16_t *pport, struct event_base *base, int mask)
170 { return http_setup_gencb(pport, base, mask, NULL, NULL); }
173 #define NI_MAXSERV 1024
176 static evutil_socket_t
177 http_connect(const char *address, ev_uint16_t port)
179 /* Stupid code for connecting */
180 struct evutil_addrinfo ai, *aitop;
181 char strport[NI_MAXSERV];
187 memset(&ai, 0, sizeof(ai));
188 ai.ai_family = AF_INET;
189 ai.ai_socktype = SOCK_STREAM;
190 evutil_snprintf(strport, sizeof(strport), "%d", port);
191 if (evutil_getaddrinfo(address, strport, &ai, &aitop) != 0) {
192 event_warn("getaddrinfo");
196 slen = aitop->ai_addrlen;
198 fd = socket(AF_INET, SOCK_STREAM, 0);
200 event_err(1, "socket failed");
202 evutil_make_socket_nonblocking(fd);
203 if (connect(fd, sa, slen) == -1) {
205 int tmp_err = WSAGetLastError();
206 if (tmp_err != WSAEINPROGRESS && tmp_err != WSAEINVAL &&
207 tmp_err != WSAEWOULDBLOCK)
208 event_err(1, "connect failed");
210 if (errno != EINPROGRESS)
211 event_err(1, "connect failed");
215 evutil_freeaddrinfo(aitop);
220 /* Helper: do a strcmp on the contents of buf and the string s. */
222 evbuffer_datacmp(struct evbuffer *buf, const char *s)
224 size_t b_sz = evbuffer_get_length(buf);
225 size_t s_sz = strlen(s);
232 d = evbuffer_pullup(buf, s_sz);
233 if ((r = memcmp(d, s, s_sz)))
242 /* Helper: Return true iff buf contains s */
244 evbuffer_contains(struct evbuffer *buf, const char *s)
246 struct evbuffer_ptr ptr;
247 ptr = evbuffer_search(buf, s, strlen(s), NULL);
248 return ptr.pos != -1;
252 http_readcb(struct bufferevent *bev, void *arg)
254 const char *what = BASIC_REQUEST_BODY;
255 struct event_base *my_base = arg;
257 if (evbuffer_contains(bufferevent_get_input(bev), what)) {
258 struct evhttp_request *req = evhttp_request_new(NULL, NULL);
259 enum message_read_status done;
261 /* req->kind = EVHTTP_RESPONSE; */
262 done = evhttp_parse_firstline_(req, bufferevent_get_input(bev));
263 if (done != ALL_DATA_READ)
266 done = evhttp_parse_headers_(req, bufferevent_get_input(bev));
267 if (done != ALL_DATA_READ)
271 evhttp_find_header(evhttp_request_get_input_headers(req),
272 "Content-Type") != NULL)
276 evhttp_request_free(req);
277 bufferevent_disable(bev, EV_READ);
279 event_base_loopexit(exit_base, NULL);
281 event_base_loopexit(my_base, NULL);
283 fprintf(stderr, "No way to exit loop!\n");
290 http_writecb(struct bufferevent *bev, void *arg)
292 if (evbuffer_get_length(bufferevent_get_output(bev)) == 0) {
293 /* enable reading of the reply */
294 bufferevent_enable(bev, EV_READ);
300 http_errorcb(struct bufferevent *bev, short what, void *arg)
303 if (what & BEV_EVENT_CONNECTED)
306 event_base_loopexit(arg, NULL);
309 static int found_multi = 0;
310 static int found_multi2 = 0;
313 http_basic_cb(struct evhttp_request *req, void *arg)
315 struct evbuffer *evb = evbuffer_new();
316 struct evhttp_connection *evcon;
317 int empty = evhttp_find_header(evhttp_request_get_input_headers(req), "Empty") != NULL;
319 TT_BLATHER(("%s: called\n", __func__));
320 evbuffer_add_printf(evb, BASIC_REQUEST_BODY);
322 evcon = evhttp_request_get_connection(req);
323 tt_assert(evhttp_connection_get_server(evcon) == arg);
326 const struct sockaddr *sa;
329 sa = evhttp_connection_get_addr(evcon);
332 if (sa->sa_family == AF_INET) {
333 evutil_format_sockaddr_port_((struct sockaddr *)sa, addrbuf, sizeof(addrbuf));
334 tt_assert(!strncmp(addrbuf, "127.0.0.1:", strlen("127.0.0.1:")));
335 } else if (sa->sa_family == AF_INET6) {
336 evutil_format_sockaddr_port_((struct sockaddr *)sa, addrbuf, sizeof(addrbuf));
337 tt_assert(!strncmp(addrbuf, "[::1]:", strlen("[::1]:")));
339 tt_fail_msg("Unsupported family");
343 /* For multi-line headers test */
346 evhttp_find_header(evhttp_request_get_input_headers(req),"X-Multi");
348 found_multi = !strcmp(multi,"aaaaaaaa a END");
349 if (strcmp("END", multi + strlen(multi) - 3) == 0)
351 if (evhttp_find_header(evhttp_request_get_input_headers(req), "X-Last"))
357 evhttp_find_header(evhttp_request_get_input_headers(req),"X-Multi-Extra-WS");
359 found_multi2 = !strcmp(multi2,"libevent 2.1");
364 /* injecting a bad content-length */
365 if (evhttp_find_header(evhttp_request_get_input_headers(req), "X-Negative"))
366 evhttp_add_header(evhttp_request_get_output_headers(req),
367 "Content-Length", "-100");
369 /* allow sending of an empty reply */
370 evhttp_send_reply(req, HTTP_OK, "Everything is fine",
371 !empty ? evb : NULL);
377 static void http_timeout_reply_cb(evutil_socket_t fd, short events, void *arg)
379 struct evhttp_request *req = arg;
380 evhttp_send_reply(req, HTTP_OK, "Everything is fine", NULL);
384 http_timeout_cb(struct evhttp_request *req, void *arg)
386 struct timeval when = { 0, 100 };
387 event_base_once(exit_base, -1, EV_TIMEOUT,
388 http_timeout_reply_cb, req, &when);
392 http_large_cb(struct evhttp_request *req, void *arg)
394 struct evbuffer *evb = evbuffer_new();
397 for (i = 0; i < 1<<20; ++i) {
398 evbuffer_add_printf(evb, BASIC_REQUEST_BODY);
400 evhttp_send_reply(req, HTTP_OK, "Everything is fine", evb);
404 static char const* const CHUNKS[] = {
406 "but not hilarious.",
410 struct chunk_req_state {
411 struct event_base *base;
412 struct evhttp_request *req;
417 http_chunked_trickle_cb(evutil_socket_t fd, short events, void *arg)
419 struct evbuffer *evb = evbuffer_new();
420 struct chunk_req_state *state = arg;
421 struct timeval when = { 0, 0 };
423 evbuffer_add_printf(evb, "%s", CHUNKS[state->i]);
424 evhttp_send_reply_chunk(state->req, evb);
427 if (++state->i < (int) (sizeof(CHUNKS)/sizeof(CHUNKS[0]))) {
428 event_base_once(state->base, -1, EV_TIMEOUT,
429 http_chunked_trickle_cb, state, &when);
431 evhttp_send_reply_end(state->req);
437 http_chunked_cb(struct evhttp_request *req, void *arg)
439 struct timeval when = { 0, 0 };
440 struct chunk_req_state *state = malloc(sizeof(struct chunk_req_state));
441 TT_BLATHER(("%s: called\n", __func__));
443 memset(state, 0, sizeof(struct chunk_req_state));
447 if (strcmp(evhttp_request_get_uri(req), "/streamed") == 0) {
448 evhttp_add_header(evhttp_request_get_output_headers(req), "Content-Length", "39");
451 /* generate a chunked/streamed reply */
452 evhttp_send_reply_start(req, HTTP_OK, "Everything is fine");
454 /* but trickle it across several iterations to ensure we're not
455 * assuming it comes all at once */
456 event_base_once(arg, -1, EV_TIMEOUT, http_chunked_trickle_cb, state, &when);
459 static struct bufferevent *
460 create_bev(struct event_base *base, evutil_socket_t fd, int ssl_mask)
462 int flags = BEV_OPT_DEFER_CALLBACKS;
463 struct bufferevent *bev = NULL;
466 bev = bufferevent_socket_new(base, fd, flags);
468 #ifdef EVENT__HAVE_OPENSSL
469 SSL *ssl = SSL_new(get_ssl_ctx());
470 if (ssl_mask & HTTP_SSL_FILTER) {
471 struct bufferevent *underlying =
472 bufferevent_socket_new(base, fd, flags);
473 bev = bufferevent_openssl_filter_new(
474 base, underlying, ssl, BUFFEREVENT_SSL_CONNECTING, flags);
476 bev = bufferevent_openssl_socket_new(
477 base, fd, ssl, BUFFEREVENT_SSL_CONNECTING, flags);
479 bufferevent_openssl_set_allow_dirty_shutdown(bev, 1);
487 http_half_writecb(struct bufferevent *bev, void *arg)
489 if (evbuffer_get_length(bufferevent_get_output(bev)) == 0) {
491 const char http_request[] = "host\r\n"
492 "Connection: close\r\n"
494 bufferevent_write(bev, http_request, strlen(http_request));
496 /* enable reading of the reply */
497 bufferevent_enable(bev, EV_READ);
503 http_basic_test_impl(void *arg, int ssl, const char *request_line)
505 struct basic_test_data *data = arg;
506 struct bufferevent *bev = NULL;
508 const char *http_request;
509 ev_uint16_t port = 0, port2 = 0;
510 int server_flags = ssl ? HTTP_BIND_SSL : 0;
511 struct evhttp *http = http_setup(&port, data->base, server_flags);
512 struct evbuffer *out;
514 exit_base = data->base;
516 /* bind to a second socket */
517 if (http_bind(http, &port2, server_flags) == -1) {
518 fprintf(stdout, "FAILED (bind)\n");
522 fd = http_connect("127.0.0.1", port);
524 /* Stupid thing to send a request */
525 bev = create_bev(data->base, fd, ssl);
526 bufferevent_setcb(bev, http_readcb, http_half_writecb,
527 http_errorcb, data->base);
528 out = bufferevent_get_output(bev);
530 /* first half of the http request */
531 evbuffer_add_printf(out,
533 "Host: some", request_line);
536 event_base_dispatch(data->base);
537 tt_int_op(test_ok, ==, 3);
539 /* connect to the second port */
540 bufferevent_free(bev);
541 evutil_closesocket(fd);
543 fd = http_connect("127.0.0.1", port2);
545 /* Stupid thing to send a request */
546 bev = create_bev(data->base, fd, ssl);
547 bufferevent_setcb(bev, http_readcb, http_writecb,
548 http_errorcb, data->base);
549 out = bufferevent_get_output(bev);
551 evbuffer_add_printf(out,
554 "Connection: close\r\n"
555 "\r\n", request_line);
558 event_base_dispatch(data->base);
559 tt_int_op(test_ok, ==, 2);
561 /* Connect to the second port again. This time, send an absolute uri. */
562 bufferevent_free(bev);
563 evutil_closesocket(fd);
565 fd = http_connect("127.0.0.1", port2);
567 /* Stupid thing to send a request */
568 bev = create_bev(data->base, fd, ssl);
569 bufferevent_setcb(bev, http_readcb, http_writecb,
570 http_errorcb, data->base);
573 "GET http://somehost.net/test HTTP/1.1\r\n"
575 "Connection: close\r\n"
578 bufferevent_write(bev, http_request, strlen(http_request));
581 event_base_dispatch(data->base);
582 tt_int_op(test_ok, ==, 2);
587 bufferevent_free(bev);
589 static void http_basic_test(void *arg)\
590 { http_basic_test_impl(arg, 0, "GET /test HTTP/1.1"); }
591 static void http_basic_trailing_space_test(void *arg)
592 { http_basic_test_impl(arg, 0, "GET /test HTTP/1.1 "); }
596 http_delay_reply(evutil_socket_t fd, short what, void *arg)
598 struct evhttp_request *req = arg;
600 evhttp_send_reply(req, HTTP_OK, "Everything is fine", NULL);
606 http_delay_cb(struct evhttp_request *req, void *arg)
609 evutil_timerclear(&tv);
611 tv.tv_usec = 200 * 1000;
613 event_base_once(arg, -1, EV_TIMEOUT, http_delay_reply, req, &tv);
617 http_badreq_cb(struct evhttp_request *req, void *arg)
619 struct evbuffer *buf = evbuffer_new();
621 evhttp_add_header(evhttp_request_get_output_headers(req), "Content-Type", "text/xml; charset=UTF-8");
622 evbuffer_add_printf(buf, "Hello, %s!", "127.0.0.1");
624 evhttp_send_reply(req, HTTP_OK, "OK", buf);
629 http_badreq_errorcb(struct bufferevent *bev, short what, void *arg)
631 TT_BLATHER(("%s: called (what=%04x, arg=%p)", __func__, what, arg));
636 http_badreq_readcb(struct bufferevent *bev, void *arg)
638 const char *what = "Hello, 127.0.0.1";
639 const char *bad_request = "400 Bad Request";
641 if (evbuffer_contains(bufferevent_get_input(bev), bad_request)) {
642 TT_FAIL(("%s:bad request detected", __func__));
643 bufferevent_disable(bev, EV_READ);
644 event_base_loopexit(arg, NULL);
648 if (evbuffer_contains(bufferevent_get_input(bev), what)) {
649 struct evhttp_request *req = evhttp_request_new(NULL, NULL);
650 enum message_read_status done;
652 /* req->kind = EVHTTP_RESPONSE; */
653 done = evhttp_parse_firstline_(req, bufferevent_get_input(bev));
654 if (done != ALL_DATA_READ)
657 done = evhttp_parse_headers_(req, bufferevent_get_input(bev));
658 if (done != ALL_DATA_READ)
662 evhttp_find_header(evhttp_request_get_input_headers(req),
663 "Content-Type") != NULL)
667 evhttp_request_free(req);
668 evbuffer_drain(bufferevent_get_input(bev), evbuffer_get_length(bufferevent_get_input(bev)));
671 shutdown(bufferevent_getfd(bev), EVUTIL_SHUT_WR);
675 http_badreq_successcb(evutil_socket_t fd, short what, void *arg)
677 TT_BLATHER(("%s: called (what=%04x, arg=%p)", __func__, what, arg));
678 event_base_loopexit(exit_base, NULL);
682 http_bad_request_test(void *arg)
684 struct basic_test_data *data = arg;
686 struct bufferevent *bev = NULL;
687 evutil_socket_t fd = EVUTIL_INVALID_SOCKET;
688 const char *http_request;
689 ev_uint16_t port=0, port2=0;
690 struct evhttp *http = http_setup(&port, data->base, 0);
693 exit_base = data->base;
695 /* bind to a second socket */
696 if (http_bind(http, &port2, 0) == -1)
697 TT_DIE(("Bind socket failed"));
699 /* NULL request test */
700 fd = http_connect("127.0.0.1", port);
701 tt_assert(fd != EVUTIL_INVALID_SOCKET);
703 /* Stupid thing to send a request */
704 bev = bufferevent_socket_new(data->base, fd, 0);
705 bufferevent_setcb(bev, http_badreq_readcb, http_writecb,
706 http_badreq_errorcb, data->base);
707 bufferevent_enable(bev, EV_READ);
709 /* real NULL request */
712 bufferevent_write(bev, http_request, strlen(http_request));
714 shutdown(fd, EVUTIL_SHUT_WR);
717 event_base_once(data->base, -1, EV_TIMEOUT, http_badreq_successcb, bev, &tv);
719 event_base_dispatch(data->base);
721 bufferevent_free(bev);
722 evutil_closesocket(fd);
725 fprintf(stdout, "FAILED\n");
729 /* Second answer (BAD REQUEST) on connection close */
731 /* connect to the second port */
732 fd = http_connect("127.0.0.1", port2);
733 tt_assert(fd != EVUTIL_INVALID_SOCKET);
735 /* Stupid thing to send a request */
736 bev = bufferevent_socket_new(data->base, fd, 0);
737 bufferevent_setcb(bev, http_badreq_readcb, http_writecb,
738 http_badreq_errorcb, data->base);
739 bufferevent_enable(bev, EV_READ);
741 /* first half of the http request */
743 "GET /badrequest HTTP/1.0\r\n" \
744 "Connection: Keep-Alive\r\n" \
747 bufferevent_write(bev, http_request, strlen(http_request));
751 event_base_once(data->base, -1, EV_TIMEOUT, http_badreq_successcb, bev, &tv);
753 event_base_dispatch(data->base);
755 tt_int_op(test_ok, ==, 2);
760 bufferevent_free(bev);
762 evutil_closesocket(fd);
765 static struct evhttp_connection *delayed_client;
768 http_large_delay_cb(struct evhttp_request *req, void *arg)
771 evutil_timerclear(&tv);
774 event_base_once(arg, -1, EV_TIMEOUT, http_delay_reply, req, &tv);
775 evhttp_connection_fail_(delayed_client, EVREQ_HTTP_EOF);
779 * HTTP DELETE test, just piggyback on the basic test
783 http_delete_cb(struct evhttp_request *req, void *arg)
785 struct evbuffer *evb = evbuffer_new();
786 int empty = evhttp_find_header(evhttp_request_get_input_headers(req), "Empty") != NULL;
788 /* Expecting a DELETE request */
789 if (evhttp_request_get_command(req) != EVHTTP_REQ_DELETE) {
790 fprintf(stdout, "FAILED (delete type)\n");
794 TT_BLATHER(("%s: called\n", __func__));
795 evbuffer_add_printf(evb, BASIC_REQUEST_BODY);
797 /* allow sending of an empty reply */
798 evhttp_send_reply(req, HTTP_OK, "Everything is fine",
799 !empty ? evb : NULL);
805 http_delete_test(void *arg)
807 struct basic_test_data *data = arg;
808 struct bufferevent *bev;
809 evutil_socket_t fd = EVUTIL_INVALID_SOCKET;
810 const char *http_request;
811 ev_uint16_t port = 0;
812 struct evhttp *http = http_setup(&port, data->base, 0);
814 exit_base = data->base;
818 fd = http_connect("127.0.0.1", port);
819 tt_assert(fd != EVUTIL_INVALID_SOCKET);
821 /* Stupid thing to send a request */
822 bev = bufferevent_socket_new(data->base, fd, 0);
823 bufferevent_setcb(bev, http_readcb, http_writecb,
824 http_errorcb, data->base);
827 "DELETE /deleteit HTTP/1.1\r\n"
829 "Connection: close\r\n"
832 bufferevent_write(bev, http_request, strlen(http_request));
834 event_base_dispatch(data->base);
836 bufferevent_free(bev);
837 evutil_closesocket(fd);
838 fd = EVUTIL_INVALID_SOCKET;
842 tt_int_op(test_ok, ==, 2);
845 evutil_closesocket(fd);
849 http_sent_cb(struct evhttp_request *req, void *arg)
851 ev_uintptr_t val = (ev_uintptr_t)arg;
854 if (val != 0xDEADBEEF) {
855 fprintf(stdout, "FAILED on_complete_cb argument\n");
859 b = evhttp_request_get_output_buffer(req);
860 if (evbuffer_get_length(b) != 0) {
861 fprintf(stdout, "FAILED on_complete_cb output buffer not written\n");
865 TT_BLATHER(("%s: called\n", __func__));
871 http_on_complete_cb(struct evhttp_request *req, void *arg)
873 struct evbuffer *evb = evbuffer_new();
875 evhttp_request_set_on_complete_cb(req, http_sent_cb, (void *)0xDEADBEEF);
877 TT_BLATHER(("%s: called\n", __func__));
878 evbuffer_add_printf(evb, BASIC_REQUEST_BODY);
880 /* allow sending of an empty reply */
881 evhttp_send_reply(req, HTTP_OK, "Everything is fine", evb);
889 http_on_complete_test(void *arg)
891 struct basic_test_data *data = arg;
892 struct bufferevent *bev;
893 evutil_socket_t fd = EVUTIL_INVALID_SOCKET;
894 const char *http_request;
895 ev_uint16_t port = 0;
896 struct evhttp *http = http_setup(&port, data->base, 0);
898 exit_base = data->base;
901 fd = http_connect("127.0.0.1", port);
902 tt_assert(fd != EVUTIL_INVALID_SOCKET);
904 /* Stupid thing to send a request */
905 bev = bufferevent_socket_new(data->base, fd, 0);
906 bufferevent_setcb(bev, http_readcb, http_writecb,
907 http_errorcb, data->base);
910 "GET /oncomplete HTTP/1.1\r\n"
912 "Connection: close\r\n"
915 bufferevent_write(bev, http_request, strlen(http_request));
917 event_base_dispatch(data->base);
919 bufferevent_free(bev);
923 tt_int_op(test_ok, ==, 4);
926 evutil_closesocket(fd);
930 http_allowed_methods_eventcb(struct bufferevent *bev, short what, void *arg)
933 if ((what & (BEV_EVENT_ERROR|BEV_EVENT_EOF))) {
936 n = evbuffer_remove(bufferevent_get_input(bev), buf,
942 *output = strdup(buf);
944 event_base_loopexit(exit_base, NULL);
949 http_allowed_methods_test(void *arg)
951 struct basic_test_data *data = arg;
952 struct bufferevent *bev1, *bev2, *bev3;
953 evutil_socket_t fd1=-1, fd2=-1, fd3=-1;
954 const char *http_request;
955 char *result1=NULL, *result2=NULL, *result3=NULL;
956 ev_uint16_t port = 0;
957 struct evhttp *http = http_setup(&port, data->base, 0);
959 exit_base = data->base;
962 fd1 = http_connect("127.0.0.1", port);
963 tt_assert(fd1 != EVUTIL_INVALID_SOCKET);
965 /* GET is out; PATCH is in. */
966 evhttp_set_allowed_methods(http, EVHTTP_REQ_PATCH);
968 /* Stupid thing to send a request */
969 bev1 = bufferevent_socket_new(data->base, fd1, 0);
970 bufferevent_enable(bev1, EV_READ|EV_WRITE);
971 bufferevent_setcb(bev1, NULL, NULL,
972 http_allowed_methods_eventcb, &result1);
975 "GET /index.html HTTP/1.1\r\n"
977 "Connection: close\r\n"
980 bufferevent_write(bev1, http_request, strlen(http_request));
982 event_base_dispatch(data->base);
984 fd2 = http_connect("127.0.0.1", port);
985 tt_assert(fd2 != EVUTIL_INVALID_SOCKET);
987 bev2 = bufferevent_socket_new(data->base, fd2, 0);
988 bufferevent_enable(bev2, EV_READ|EV_WRITE);
989 bufferevent_setcb(bev2, NULL, NULL,
990 http_allowed_methods_eventcb, &result2);
993 "PATCH /test HTTP/1.1\r\n"
995 "Connection: close\r\n"
998 bufferevent_write(bev2, http_request, strlen(http_request));
1000 event_base_dispatch(data->base);
1002 fd3 = http_connect("127.0.0.1", port);
1003 tt_assert(fd3 != EVUTIL_INVALID_SOCKET);
1005 bev3 = bufferevent_socket_new(data->base, fd3, 0);
1006 bufferevent_enable(bev3, EV_READ|EV_WRITE);
1007 bufferevent_setcb(bev3, NULL, NULL,
1008 http_allowed_methods_eventcb, &result3);
1011 "FLOOP /test HTTP/1.1\r\n"
1012 "Host: somehost\r\n"
1013 "Connection: close\r\n"
1016 bufferevent_write(bev3, http_request, strlen(http_request));
1018 event_base_dispatch(data->base);
1020 bufferevent_free(bev1);
1021 bufferevent_free(bev2);
1022 bufferevent_free(bev3);
1026 /* Method known but disallowed */
1028 tt_assert(!strncmp(result1, "HTTP/1.1 501 ", strlen("HTTP/1.1 501 ")));
1030 /* Method known and allowed */
1032 tt_assert(!strncmp(result2, "HTTP/1.1 200 ", strlen("HTTP/1.1 200 ")));
1034 /* Method unknown */
1036 tt_assert(!strncmp(result3, "HTTP/1.1 501 ", strlen("HTTP/1.1 501 ")));
1046 evutil_closesocket(fd1);
1048 evutil_closesocket(fd2);
1050 evutil_closesocket(fd3);
1053 static void http_request_no_action_done(struct evhttp_request *, void *);
1054 static void http_request_done(struct evhttp_request *, void *);
1055 static void http_request_empty_done(struct evhttp_request *, void *);
1058 http_connection_test_(struct basic_test_data *data, int persistent,
1059 const char *address, struct evdns_base *dnsbase, int ipv6, int family,
1062 ev_uint16_t port = 0;
1063 struct evhttp_connection *evcon = NULL;
1064 struct evhttp_request *req = NULL;
1065 struct evhttp *http;
1069 mask |= HTTP_BIND_IPV6;
1071 mask |= HTTP_BIND_SSL;
1073 http = http_setup(&port, data->base, mask);
1076 if (!http && ipv6) {
1082 #ifdef EVENT__HAVE_OPENSSL
1083 SSL *ssl = SSL_new(get_ssl_ctx());
1084 struct bufferevent *bev = bufferevent_openssl_socket_new(
1085 data->base, -1, ssl,
1086 BUFFEREVENT_SSL_CONNECTING, BEV_OPT_DEFER_CALLBACKS);
1087 bufferevent_openssl_set_allow_dirty_shutdown(bev, 1);
1089 evcon = evhttp_connection_base_bufferevent_new(data->base, dnsbase, bev, address, port);
1094 evcon = evhttp_connection_base_new(data->base, dnsbase, address, port);
1097 evhttp_connection_set_family(evcon, family);
1099 tt_assert(evhttp_connection_get_base(evcon) == data->base);
1101 exit_base = data->base;
1103 tt_assert(evhttp_connection_get_server(evcon) == NULL);
1106 * At this point, we want to schedule a request to the HTTP
1107 * server using our make request method.
1109 req = evhttp_request_new(http_request_done, (void*) BASIC_REQUEST_BODY);
1111 /* Add the information that we care about */
1112 evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
1114 /* We give ownership of the request to the connection */
1115 if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test") == -1) {
1116 fprintf(stdout, "FAILED\n");
1120 event_base_dispatch(data->base);
1124 /* try to make another request over the same connection */
1127 req = evhttp_request_new(http_request_done, (void*) BASIC_REQUEST_BODY);
1129 /* Add the information that we care about */
1130 evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
1133 * if our connections are not supposed to be persistent; request
1134 * a close from the server.
1137 evhttp_add_header(evhttp_request_get_output_headers(req), "Connection", "close");
1139 /* We give ownership of the request to the connection */
1140 if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test") == -1) {
1141 tt_abort_msg("couldn't make request");
1144 event_base_dispatch(data->base);
1146 /* make another request: request empty reply */
1149 req = evhttp_request_new(http_request_empty_done, data->base);
1151 /* Add the information that we care about */
1152 evhttp_add_header(evhttp_request_get_output_headers(req), "Empty", "itis");
1154 /* We give ownership of the request to the connection */
1155 if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test") == -1) {
1156 tt_abort_msg("Couldn't make request");
1159 event_base_dispatch(data->base);
1163 evhttp_connection_free(evcon);
1169 http_connection_test(void *arg)
1171 http_connection_test_(arg, 0, "127.0.0.1", NULL, 0, AF_UNSPEC, 0);
1174 http_persist_connection_test(void *arg)
1176 http_connection_test_(arg, 1, "127.0.0.1", NULL, 0, AF_UNSPEC, 0);
1179 static struct regress_dns_server_table search_table[] = {
1180 { "localhost", "A", "127.0.0.1", 0, 0 },
1181 { NULL, NULL, NULL, 0, 0 }
1185 http_connection_async_test(void *arg)
1187 struct basic_test_data *data = arg;
1188 ev_uint16_t port = 0;
1189 struct evhttp_connection *evcon = NULL;
1190 struct evhttp_request *req = NULL;
1191 struct evdns_base *dns_base = NULL;
1192 ev_uint16_t portnum = 0;
1194 struct evhttp *http = http_setup(&port, data->base, 0);
1196 exit_base = data->base;
1197 tt_assert(regress_dnsserver(data->base, &portnum, search_table));
1199 dns_base = evdns_base_new(data->base, 0/* init name servers */);
1200 tt_assert(dns_base);
1202 /* Add ourself as the only nameserver, and make sure we really are
1203 * the only nameserver. */
1204 evutil_snprintf(address, sizeof(address), "127.0.0.1:%d", portnum);
1205 evdns_base_nameserver_ip_add(dns_base, address);
1209 evcon = evhttp_connection_base_new(data->base, dns_base, "127.0.0.1", port);
1213 * At this point, we want to schedule a request to the HTTP
1214 * server using our make request method.
1217 req = evhttp_request_new(http_request_done, (void*) BASIC_REQUEST_BODY);
1219 /* Add the information that we care about */
1220 evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
1222 /* We give ownership of the request to the connection */
1223 if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test") == -1) {
1224 fprintf(stdout, "FAILED\n");
1228 event_base_dispatch(data->base);
1232 /* try to make another request over the same connection */
1235 req = evhttp_request_new(http_request_done, (void*) BASIC_REQUEST_BODY);
1237 /* Add the information that we care about */
1238 evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
1241 * if our connections are not supposed to be persistent; request
1242 * a close from the server.
1244 evhttp_add_header(evhttp_request_get_output_headers(req), "Connection", "close");
1246 /* We give ownership of the request to the connection */
1247 if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test") == -1) {
1248 tt_abort_msg("couldn't make request");
1251 event_base_dispatch(data->base);
1253 /* make another request: request empty reply */
1256 req = evhttp_request_new(http_request_empty_done, data->base);
1258 /* Add the information that we care about */
1259 evhttp_add_header(evhttp_request_get_output_headers(req), "Empty", "itis");
1261 /* We give ownership of the request to the connection */
1262 if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test") == -1) {
1263 tt_abort_msg("Couldn't make request");
1266 event_base_dispatch(data->base);
1270 evhttp_connection_free(evcon);
1274 evdns_base_free(dns_base, 0);
1275 regress_clean_dnsserver();
1279 http_autofree_connection_test(void *arg)
1281 struct basic_test_data *data = arg;
1282 ev_uint16_t port = 0;
1283 struct evhttp_connection *evcon = NULL;
1284 struct evhttp_request *req[2] = { NULL };
1285 struct evhttp *http = http_setup(&port, data->base, 0);
1289 evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port);
1293 * At this point, we want to schedule two request to the HTTP
1294 * server using our make request method.
1296 req[0] = evhttp_request_new(http_request_empty_done, data->base);
1297 req[1] = evhttp_request_new(http_request_empty_done, data->base);
1299 /* Add the information that we care about */
1300 evhttp_add_header(evhttp_request_get_output_headers(req[0]), "Host", "somehost");
1301 evhttp_add_header(evhttp_request_get_output_headers(req[0]), "Connection", "close");
1302 evhttp_add_header(evhttp_request_get_output_headers(req[0]), "Empty", "itis");
1303 evhttp_add_header(evhttp_request_get_output_headers(req[1]), "Host", "somehost");
1304 evhttp_add_header(evhttp_request_get_output_headers(req[1]), "Connection", "close");
1305 evhttp_add_header(evhttp_request_get_output_headers(req[1]), "Empty", "itis");
1307 /* We give ownership of the request to the connection */
1308 if (evhttp_make_request(evcon, req[0], EVHTTP_REQ_GET, "/test") == -1) {
1309 tt_abort_msg("couldn't make request");
1311 if (evhttp_make_request(evcon, req[1], EVHTTP_REQ_GET, "/test") == -1) {
1312 tt_abort_msg("couldn't make request");
1316 * Tell libevent to free the connection when the request completes
1317 * We then set the evcon pointer to NULL since we don't want to free it
1318 * when this function ends.
1320 evhttp_connection_free_on_completion(evcon);
1323 event_base_dispatch(data->base);
1325 /* at this point, the http server should have no connection */
1326 tt_assert(TAILQ_FIRST(&http->connections) == NULL);
1330 evhttp_connection_free(evcon);
1336 http_request_never_call(struct evhttp_request *req, void *arg)
1338 fprintf(stdout, "FAILED\n");
1342 http_failed_request_done(struct evhttp_request *req, void *arg)
1346 event_base_loopexit(arg, NULL);
1350 http_timed_out_request_done(struct evhttp_request *req, void *arg)
1353 tt_int_op(evhttp_request_get_response_code(req), !=, HTTP_OK);
1355 event_base_loopexit(arg, NULL);
1360 http_request_error_cb_with_cancel(enum evhttp_request_error error, void *arg)
1362 if (error != EVREQ_HTTP_REQUEST_CANCEL) {
1363 fprintf(stderr, "FAILED\n");
1370 evutil_timerclear(&tv);
1372 tv.tv_usec = 500 * 1000;
1373 event_base_loopexit(exit_base, &tv);
1377 http_do_cancel(evutil_socket_t fd, short what, void *arg)
1379 struct evhttp_request *req = arg;
1380 evhttp_cancel_request(req);
1384 http_no_write(struct evbuffer *buffer, const struct evbuffer_cb_info *info, void *arg)
1386 fprintf(stdout, "FAILED\n");
1390 http_free_evcons(struct evhttp_connection **evcons)
1392 struct evhttp_connection *evcon, **orig = evcons;
1397 while ((evcon = *evcons++)) {
1398 evhttp_connection_free(evcon);
1402 /** fill the backlog to force server drop packages for timeouts */
1403 static struct evhttp_connection **
1404 http_fill_backlog(struct event_base *base, int port)
1406 #define BACKLOG_SIZE 256
1407 struct evhttp_connection **evcon = malloc(sizeof(*evcon) * (BACKLOG_SIZE + 1));
1410 for (i = 0; i < BACKLOG_SIZE; ++i) {
1411 struct evhttp_request *req;
1413 evcon[i] = evhttp_connection_base_new(base, NULL, "127.0.0.1", port);
1414 tt_assert(evcon[i]);
1415 evhttp_connection_set_timeout(evcon[i], 5);
1417 req = evhttp_request_new(http_request_never_call, NULL);
1419 tt_int_op(evhttp_make_request(evcon[i], req, EVHTTP_REQ_GET, "/delay"), !=, -1);
1425 fprintf(stderr, "Couldn't fill the backlog");
1429 enum http_cancel_test_type {
1433 INACTIVE_SERVER = 8,
1434 SERVER_TIMEOUT = 16,
1437 static struct evhttp_request *
1438 http_cancel_test_bad_request_new(enum http_cancel_test_type type,
1439 struct event_base *base)
1442 if (!(type & NO_NS) && (type & SERVER_TIMEOUT))
1443 return evhttp_request_new(http_timed_out_request_done, base);
1446 if ((type & INACTIVE_SERVER) || (type & NO_NS))
1447 return evhttp_request_new(http_failed_request_done, base);
1452 http_cancel_test(void *arg)
1454 struct basic_test_data *data = arg;
1455 ev_uint16_t port = 0;
1456 struct evhttp_connection *evcon = NULL;
1457 struct evhttp_request *req = NULL;
1458 struct bufferevent *bufev = NULL;
1460 struct evdns_base *dns_base = NULL;
1461 ev_uint16_t portnum = 0;
1463 struct evhttp *inactive_http = NULL;
1464 struct event_base *inactive_base = NULL;
1465 struct evhttp_connection **evcons = NULL;
1466 struct event_base *base_to_fill = data->base;
1468 enum http_cancel_test_type type =
1469 (enum http_cancel_test_type)data->setup_data;
1470 struct evhttp *http = http_setup(&port, data->base, 0);
1472 if (type & BY_HOST) {
1473 const char *timeout = (type & NS_TIMEOUT) ? "6" : "3";
1475 tt_assert(regress_dnsserver(data->base, &portnum, search_table));
1477 dns_base = evdns_base_new(data->base, 0/* init name servers */);
1478 tt_assert(dns_base);
1480 /** XXX: Hack the port to make timeout after resolving */
1484 evutil_snprintf(address, sizeof(address), "127.0.0.1:%d", portnum);
1485 evdns_base_nameserver_ip_add(dns_base, address);
1487 evdns_base_set_option(dns_base, "timeout:", timeout);
1488 evdns_base_set_option(dns_base, "initial-probe-timeout:", timeout);
1489 evdns_base_set_option(dns_base, "attempts:", "1");
1492 exit_base = data->base;
1496 if (type & INACTIVE_SERVER) {
1498 inactive_base = event_base_new();
1499 inactive_http = http_setup(&port, inactive_base, 0);
1501 base_to_fill = inactive_base;
1504 if (type & SERVER_TIMEOUT)
1505 evcons = http_fill_backlog(base_to_fill, port);
1507 evcon = evhttp_connection_base_new(
1508 data->base, dns_base,
1509 type & BY_HOST ? "localhost" : "127.0.0.1",
1511 if (type & INACTIVE_SERVER)
1512 evhttp_connection_set_timeout(evcon, 5);
1515 bufev = evhttp_connection_get_bufferevent(evcon);
1516 /* Guarantee that we stack in connect() not after waiting EV_READ after
1518 if (type & SERVER_TIMEOUT)
1519 evbuffer_add_cb(bufferevent_get_output(bufev), http_no_write, NULL);
1522 * At this point, we want to schedule a request to the HTTP
1523 * server using our make request method.
1526 req = evhttp_request_new(http_request_never_call, NULL);
1527 evhttp_request_set_error_cb(req, http_request_error_cb_with_cancel);
1529 /* Add the information that we care about */
1530 evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
1532 /* We give ownership of the request to the connection */
1533 tt_int_op(evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/delay"),
1536 evutil_timerclear(&tv);
1538 tv.tv_usec = 100 * 1000;
1540 event_base_once(data->base, -1, EV_TIMEOUT, http_do_cancel, req, &tv);
1542 event_base_dispatch(data->base);
1544 if (type & NO_NS || type & INACTIVE_SERVER)
1545 tt_int_op(test_ok, ==, 2); /** no servers responses */
1547 tt_int_op(test_ok, ==, 3);
1549 /* try to make another request over the same connection */
1552 http_free_evcons(evcons);
1553 if (type & SERVER_TIMEOUT)
1554 evcons = http_fill_backlog(base_to_fill, port);
1556 req = http_cancel_test_bad_request_new(type, data->base);
1558 req = evhttp_request_new(http_request_done, (void*) BASIC_REQUEST_BODY);
1560 /* Add the information that we care about */
1561 evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
1563 /* We give ownership of the request to the connection */
1564 tt_int_op(evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test"),
1567 event_base_dispatch(data->base);
1569 /* make another request: request empty reply */
1572 http_free_evcons(evcons);
1573 if (type & SERVER_TIMEOUT)
1574 evcons = http_fill_backlog(base_to_fill, port);
1576 req = http_cancel_test_bad_request_new(type, data->base);
1578 req = evhttp_request_new(http_request_empty_done, data->base);
1580 /* Add the information that we care about */
1581 evhttp_add_header(evhttp_request_get_output_headers(req), "Empty", "itis");
1583 /* We give ownership of the request to the connection */
1584 tt_int_op(evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test"),
1587 event_base_dispatch(data->base);
1590 http_free_evcons(evcons);
1592 evbuffer_remove_cb(bufferevent_get_output(bufev), http_no_write, NULL);
1594 evhttp_connection_free(evcon);
1598 evdns_base_free(dns_base, 0);
1599 regress_clean_dnsserver();
1601 evhttp_free(inactive_http);
1603 event_base_free(inactive_base);
1607 http_request_no_action_done(struct evhttp_request *req, void *arg)
1609 EVUTIL_ASSERT(exit_base);
1610 event_base_loopexit(exit_base, NULL);
1614 http_request_done(struct evhttp_request *req, void *arg)
1616 const char *what = arg;
1619 fprintf(stderr, "FAILED\n");
1623 if (evhttp_request_get_response_code(req) != HTTP_OK) {
1624 fprintf(stderr, "FAILED\n");
1628 if (evhttp_find_header(evhttp_request_get_input_headers(req), "Content-Type") == NULL) {
1629 fprintf(stderr, "FAILED\n");
1633 if (evbuffer_get_length(evhttp_request_get_input_buffer(req)) != strlen(what)) {
1634 fprintf(stderr, "FAILED\n");
1638 if (evbuffer_datacmp(evhttp_request_get_input_buffer(req), what) != 0) {
1639 fprintf(stderr, "FAILED\n");
1644 EVUTIL_ASSERT(exit_base);
1645 event_base_loopexit(exit_base, NULL);
1649 http_request_expect_error(struct evhttp_request *req, void *arg)
1651 if (evhttp_request_get_response_code(req) == HTTP_OK) {
1652 fprintf(stderr, "FAILED\n");
1658 event_base_loopexit(arg, NULL);
1661 /* test virtual hosts */
1663 http_virtual_host_test(void *arg)
1665 struct basic_test_data *data = arg;
1666 ev_uint16_t port = 0;
1667 struct evhttp_connection *evcon = NULL;
1668 struct evhttp_request *req = NULL;
1669 struct evhttp *second = NULL, *third = NULL;
1671 struct bufferevent *bev;
1672 const char *http_request;
1673 struct evhttp *http = http_setup(&port, data->base, 0);
1675 exit_base = data->base;
1678 second = evhttp_new(NULL);
1679 evhttp_set_cb(second, "/funnybunny", http_basic_cb, http);
1680 third = evhttp_new(NULL);
1681 evhttp_set_cb(third, "/blackcoffee", http_basic_cb, http);
1683 if (evhttp_add_virtual_host(http, "foo.com", second) == -1) {
1684 tt_abort_msg("Couldn't add vhost");
1687 if (evhttp_add_virtual_host(http, "bar.*.foo.com", third) == -1) {
1688 tt_abort_msg("Couldn't add wildcarded vhost");
1691 /* add some aliases to the vhosts */
1692 tt_assert(evhttp_add_server_alias(second, "manolito.info") == 0);
1693 tt_assert(evhttp_add_server_alias(third, "bonkers.org") == 0);
1695 evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port);
1698 /* make a request with a different host and expect an error */
1699 req = evhttp_request_new(http_request_expect_error, data->base);
1701 /* Add the information that we care about */
1702 evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
1704 /* We give ownership of the request to the connection */
1705 if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET,
1706 "/funnybunny") == -1) {
1707 tt_abort_msg("Couldn't make request");
1710 event_base_dispatch(data->base);
1712 tt_assert(test_ok == 1);
1716 /* make a request with the right host and expect a response */
1717 req = evhttp_request_new(http_request_done, (void*) BASIC_REQUEST_BODY);
1719 /* Add the information that we care about */
1720 evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "foo.com");
1722 /* We give ownership of the request to the connection */
1723 if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET,
1724 "/funnybunny") == -1) {
1725 fprintf(stdout, "FAILED\n");
1729 event_base_dispatch(data->base);
1731 tt_assert(test_ok == 1);
1735 /* make a request with the right host and expect a response */
1736 req = evhttp_request_new(http_request_done, (void*) BASIC_REQUEST_BODY);
1738 /* Add the information that we care about */
1739 evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "bar.magic.foo.com");
1741 /* We give ownership of the request to the connection */
1742 if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET,
1743 "/blackcoffee") == -1) {
1744 tt_abort_msg("Couldn't make request");
1747 event_base_dispatch(data->base);
1749 tt_assert(test_ok == 1)
1753 /* make a request with the right host and expect a response */
1754 req = evhttp_request_new(http_request_done, (void*) BASIC_REQUEST_BODY);
1756 /* Add the information that we care about */
1757 evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "manolito.info");
1759 /* We give ownership of the request to the connection */
1760 if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET,
1761 "/funnybunny") == -1) {
1762 tt_abort_msg("Couldn't make request");
1765 event_base_dispatch(data->base);
1767 tt_assert(test_ok == 1)
1771 /* make a request with the right host and expect a response */
1772 req = evhttp_request_new(http_request_done, (void*) BASIC_REQUEST_BODY);
1774 /* Add the Host header. This time with the optional port. */
1775 evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "bonkers.org:8000");
1777 /* We give ownership of the request to the connection */
1778 if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET,
1779 "/blackcoffee") == -1) {
1780 tt_abort_msg("Couldn't make request");
1783 event_base_dispatch(data->base);
1785 tt_assert(test_ok == 1)
1789 /* Now make a raw request with an absolute URI. */
1790 fd = http_connect("127.0.0.1", port);
1791 tt_assert(fd != EVUTIL_INVALID_SOCKET);
1793 /* Stupid thing to send a request */
1794 bev = bufferevent_socket_new(data->base, fd, 0);
1795 bufferevent_setcb(bev, http_readcb, http_writecb,
1796 http_errorcb, NULL);
1798 /* The host in the URI should override the Host: header */
1800 "GET http://manolito.info/funnybunny HTTP/1.1\r\n"
1801 "Host: somehost\r\n"
1802 "Connection: close\r\n"
1805 bufferevent_write(bev, http_request, strlen(http_request));
1807 event_base_dispatch(data->base);
1809 tt_int_op(test_ok, ==, 2);
1811 bufferevent_free(bev);
1812 evutil_closesocket(fd);
1816 evhttp_connection_free(evcon);
1822 /* test date header and content length */
1825 http_request_empty_done(struct evhttp_request *req, void *arg)
1828 fprintf(stderr, "FAILED\n");
1832 if (evhttp_request_get_response_code(req) != HTTP_OK) {
1833 fprintf(stderr, "FAILED\n");
1837 if (evhttp_find_header(evhttp_request_get_input_headers(req), "Date") == NULL) {
1838 fprintf(stderr, "FAILED\n");
1843 if (evhttp_find_header(evhttp_request_get_input_headers(req), "Content-Length") == NULL) {
1844 fprintf(stderr, "FAILED\n");
1848 if (strcmp(evhttp_find_header(evhttp_request_get_input_headers(req), "Content-Length"),
1850 fprintf(stderr, "FAILED\n");
1854 if (evbuffer_get_length(evhttp_request_get_input_buffer(req)) != 0) {
1855 fprintf(stderr, "FAILED\n");
1861 event_base_loopexit(arg, NULL);
1865 * HTTP DISPATCHER test
1869 http_dispatcher_cb(struct evhttp_request *req, void *arg)
1872 struct evbuffer *evb = evbuffer_new();
1873 TT_BLATHER(("%s: called\n", __func__));
1874 evbuffer_add_printf(evb, "DISPATCHER_TEST");
1876 evhttp_send_reply(req, HTTP_OK, "Everything is fine", evb);
1882 http_dispatcher_test_done(struct evhttp_request *req, void *arg)
1884 struct event_base *base = arg;
1885 const char *what = "DISPATCHER_TEST";
1888 fprintf(stderr, "FAILED\n");
1892 if (evhttp_request_get_response_code(req) != HTTP_OK) {
1893 fprintf(stderr, "FAILED\n");
1897 if (evhttp_find_header(evhttp_request_get_input_headers(req), "Content-Type") == NULL) {
1898 fprintf(stderr, "FAILED (content type)\n");
1902 if (evbuffer_get_length(evhttp_request_get_input_buffer(req)) != strlen(what)) {
1903 fprintf(stderr, "FAILED (length %lu vs %lu)\n",
1904 (unsigned long)evbuffer_get_length(evhttp_request_get_input_buffer(req)), (unsigned long)strlen(what));
1908 if (evbuffer_datacmp(evhttp_request_get_input_buffer(req), what) != 0) {
1909 fprintf(stderr, "FAILED (data)\n");
1914 event_base_loopexit(base, NULL);
1918 http_dispatcher_test(void *arg)
1920 struct basic_test_data *data = arg;
1921 ev_uint16_t port = 0;
1922 struct evhttp_connection *evcon = NULL;
1923 struct evhttp_request *req = NULL;
1924 struct evhttp *http = http_setup(&port, data->base, 0);
1928 evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port);
1931 /* also bind to local host */
1932 evhttp_connection_set_local_address(evcon, "127.0.0.1");
1935 * At this point, we want to schedule an HTTP GET request
1936 * server using our make request method.
1939 req = evhttp_request_new(http_dispatcher_test_done, data->base);
1942 /* Add the information that we care about */
1943 evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
1945 if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/?arg=val") == -1) {
1946 tt_abort_msg("Couldn't make request");
1949 event_base_dispatch(data->base);
1953 evhttp_connection_free(evcon);
1962 void http_postrequest_done(struct evhttp_request *, void *);
1964 #define POST_DATA "Okay. Not really printf"
1967 http_post_test(void *arg)
1969 struct basic_test_data *data = arg;
1970 ev_uint16_t port = 0;
1971 struct evhttp_connection *evcon = NULL;
1972 struct evhttp_request *req = NULL;
1973 struct evhttp *http = http_setup(&port, data->base, 0);
1977 evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port);
1981 * At this point, we want to schedule an HTTP POST request
1982 * server using our make request method.
1985 req = evhttp_request_new(http_postrequest_done, data->base);
1988 /* Add the information that we care about */
1989 evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
1990 evbuffer_add_printf(evhttp_request_get_output_buffer(req), POST_DATA);
1992 if (evhttp_make_request(evcon, req, EVHTTP_REQ_POST, "/postit") == -1) {
1993 tt_abort_msg("Couldn't make request");
1996 event_base_dispatch(data->base);
1998 tt_int_op(test_ok, ==, 1);
2002 req = evhttp_request_new(http_postrequest_done, data->base);
2005 /* Now try with 100-continue. */
2007 /* Add the information that we care about */
2008 evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
2009 evhttp_add_header(evhttp_request_get_output_headers(req), "Expect", "100-continue");
2010 evbuffer_add_printf(evhttp_request_get_output_buffer(req), POST_DATA);
2012 if (evhttp_make_request(evcon, req, EVHTTP_REQ_POST, "/postit") == -1) {
2013 tt_abort_msg("Couldn't make request");
2016 event_base_dispatch(data->base);
2018 tt_int_op(test_ok, ==, 1);
2020 evhttp_connection_free(evcon);
2028 http_post_cb(struct evhttp_request *req, void *arg)
2030 struct evbuffer *evb;
2031 TT_BLATHER(("%s: called\n", __func__));
2033 /* Yes, we are expecting a post request */
2034 if (evhttp_request_get_command(req) != EVHTTP_REQ_POST) {
2035 fprintf(stdout, "FAILED (post type)\n");
2039 if (evbuffer_get_length(evhttp_request_get_input_buffer(req)) != strlen(POST_DATA)) {
2040 fprintf(stdout, "FAILED (length: %lu vs %lu)\n",
2041 (unsigned long) evbuffer_get_length(evhttp_request_get_input_buffer(req)), (unsigned long) strlen(POST_DATA));
2045 if (evbuffer_datacmp(evhttp_request_get_input_buffer(req), POST_DATA) != 0) {
2046 fprintf(stdout, "FAILED (data)\n");
2047 fprintf(stdout, "Got :%s\n", evbuffer_pullup(evhttp_request_get_input_buffer(req),-1));
2048 fprintf(stdout, "Want:%s\n", POST_DATA);
2052 evb = evbuffer_new();
2053 evbuffer_add_printf(evb, BASIC_REQUEST_BODY);
2055 evhttp_send_reply(req, HTTP_OK, "Everything is fine", evb);
2061 http_postrequest_done(struct evhttp_request *req, void *arg)
2063 const char *what = BASIC_REQUEST_BODY;
2064 struct event_base *base = arg;
2067 fprintf(stderr, "FAILED (timeout)\n");
2071 if (evhttp_request_get_response_code(req) != HTTP_OK) {
2073 fprintf(stderr, "FAILED (response code)\n");
2077 if (evhttp_find_header(evhttp_request_get_input_headers(req), "Content-Type") == NULL) {
2078 fprintf(stderr, "FAILED (content type)\n");
2082 if (evbuffer_get_length(evhttp_request_get_input_buffer(req)) != strlen(what)) {
2083 fprintf(stderr, "FAILED (length %lu vs %lu)\n",
2084 (unsigned long)evbuffer_get_length(evhttp_request_get_input_buffer(req)), (unsigned long)strlen(what));
2088 if (evbuffer_datacmp(evhttp_request_get_input_buffer(req), what) != 0) {
2089 fprintf(stderr, "FAILED (data)\n");
2094 event_base_loopexit(base, NULL);
2098 * HTTP PUT test, basically just like POST, but ...
2101 void http_putrequest_done(struct evhttp_request *, void *);
2103 #define PUT_DATA "Hi, I'm some PUT data"
2106 http_put_test(void *arg)
2108 struct basic_test_data *data = arg;
2109 ev_uint16_t port = 0;
2110 struct evhttp_connection *evcon = NULL;
2111 struct evhttp_request *req = NULL;
2112 struct evhttp *http = http_setup(&port, data->base, 0);
2116 evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port);
2120 * Schedule the HTTP PUT request
2123 req = evhttp_request_new(http_putrequest_done, data->base);
2126 /* Add the information that we care about */
2127 evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "someotherhost");
2128 evbuffer_add_printf(evhttp_request_get_output_buffer(req), PUT_DATA);
2130 if (evhttp_make_request(evcon, req, EVHTTP_REQ_PUT, "/putit") == -1) {
2131 tt_abort_msg("Couldn't make request");
2134 event_base_dispatch(data->base);
2136 evhttp_connection_free(evcon);
2139 tt_int_op(test_ok, ==, 1);
2145 http_put_cb(struct evhttp_request *req, void *arg)
2147 struct evbuffer *evb;
2148 TT_BLATHER(("%s: called\n", __func__));
2150 /* Expecting a PUT request */
2151 if (evhttp_request_get_command(req) != EVHTTP_REQ_PUT) {
2152 fprintf(stdout, "FAILED (put type)\n");
2156 if (evbuffer_get_length(evhttp_request_get_input_buffer(req)) != strlen(PUT_DATA)) {
2157 fprintf(stdout, "FAILED (length: %lu vs %lu)\n",
2158 (unsigned long)evbuffer_get_length(evhttp_request_get_input_buffer(req)), (unsigned long)strlen(PUT_DATA));
2162 if (evbuffer_datacmp(evhttp_request_get_input_buffer(req), PUT_DATA) != 0) {
2163 fprintf(stdout, "FAILED (data)\n");
2164 fprintf(stdout, "Got :%s\n", evbuffer_pullup(evhttp_request_get_input_buffer(req),-1));
2165 fprintf(stdout, "Want:%s\n", PUT_DATA);
2169 evb = evbuffer_new();
2170 evbuffer_add_printf(evb, "That ain't funny");
2172 evhttp_send_reply(req, HTTP_OK, "Everything is great", evb);
2178 http_putrequest_done(struct evhttp_request *req, void *arg)
2180 struct event_base *base = arg;
2181 const char *what = "That ain't funny";
2184 fprintf(stderr, "FAILED (timeout)\n");
2188 if (evhttp_request_get_response_code(req) != HTTP_OK) {
2190 fprintf(stderr, "FAILED (response code)\n");
2194 if (evhttp_find_header(evhttp_request_get_input_headers(req), "Content-Type") == NULL) {
2195 fprintf(stderr, "FAILED (content type)\n");
2199 if (evbuffer_get_length(evhttp_request_get_input_buffer(req)) != strlen(what)) {
2200 fprintf(stderr, "FAILED (length %lu vs %lu)\n",
2201 (unsigned long)evbuffer_get_length(evhttp_request_get_input_buffer(req)), (unsigned long)strlen(what));
2206 if (evbuffer_datacmp(evhttp_request_get_input_buffer(req), what) != 0) {
2207 fprintf(stderr, "FAILED (data)\n");
2212 event_base_loopexit(base, NULL);
2216 http_failure_readcb(struct bufferevent *bev, void *arg)
2218 const char *what = "400 Bad Request";
2219 if (evbuffer_contains(bufferevent_get_input(bev), what)) {
2221 bufferevent_disable(bev, EV_READ);
2222 event_base_loopexit(arg, NULL);
2227 * Testing that the HTTP server can deal with a malformed request.
2230 http_failure_test(void *arg)
2232 struct basic_test_data *data = arg;
2233 struct bufferevent *bev;
2234 evutil_socket_t fd = EVUTIL_INVALID_SOCKET;
2235 const char *http_request;
2236 ev_uint16_t port = 0;
2237 struct evhttp *http = http_setup(&port, data->base, 0);
2241 fd = http_connect("127.0.0.1", port);
2242 tt_assert(fd != EVUTIL_INVALID_SOCKET);
2244 /* Stupid thing to send a request */
2245 bev = bufferevent_socket_new(data->base, fd, 0);
2246 bufferevent_setcb(bev, http_failure_readcb, http_writecb,
2247 http_errorcb, data->base);
2249 http_request = "illegal request\r\n";
2251 bufferevent_write(bev, http_request, strlen(http_request));
2253 event_base_dispatch(data->base);
2255 bufferevent_free(bev);
2259 tt_int_op(test_ok, ==, 2);
2262 evutil_closesocket(fd);
2266 close_detect_done(struct evhttp_request *req, void *arg)
2270 tt_assert(evhttp_request_get_response_code(req) == HTTP_OK);
2275 evutil_timerclear(&tv);
2276 tv.tv_usec = 150000;
2277 event_base_loopexit(arg, &tv);
2281 close_detect_launch(evutil_socket_t fd, short what, void *arg)
2283 struct evhttp_connection *evcon = arg;
2284 struct event_base *base = evhttp_connection_get_base(evcon);
2285 struct evhttp_request *req;
2287 req = evhttp_request_new(close_detect_done, base);
2289 /* Add the information that we care about */
2290 evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
2292 /* We give ownership of the request to the connection */
2293 if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test") == -1) {
2294 tt_fail_msg("Couldn't make request");
2299 close_detect_cb(struct evhttp_request *req, void *arg)
2301 struct evhttp_connection *evcon = arg;
2302 struct event_base *base = evhttp_connection_get_base(evcon);
2305 if (req != NULL && evhttp_request_get_response_code(req) != HTTP_OK) {
2306 tt_abort_msg("Failed");
2309 evutil_timerclear(&tv);
2310 tv.tv_sec = 0; /* longer than the http time out */
2311 tv.tv_usec = 600000; /* longer than the http time out */
2313 /* launch a new request on the persistent connection in .3 seconds */
2314 event_base_once(base, -1, EV_TIMEOUT, close_detect_launch, evcon, &tv);
2321 http_close_detection_(struct basic_test_data *data, int with_delay)
2323 ev_uint16_t port = 0;
2324 struct evhttp_connection *evcon = NULL;
2325 struct evhttp_request *req = NULL;
2326 const struct timeval sec_tenth = { 0, 100000 };
2327 struct evhttp *http = http_setup(&port, data->base, 0);
2331 /* .1 second timeout */
2332 evhttp_set_timeout_tv(http, &sec_tenth);
2334 evcon = evhttp_connection_base_new(data->base, NULL,
2337 evhttp_connection_set_timeout_tv(evcon, &sec_tenth);
2341 delayed_client = evcon;
2344 * At this point, we want to schedule a request to the HTTP
2345 * server using our make request method.
2348 req = evhttp_request_new(close_detect_cb, evcon);
2350 /* Add the information that we care about */
2351 evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
2353 /* We give ownership of the request to the connection */
2354 if (evhttp_make_request(evcon,
2355 req, EVHTTP_REQ_GET, with_delay ? "/largedelay" : "/test") == -1) {
2356 tt_abort_msg("couldn't make request");
2359 event_base_dispatch(data->base);
2361 /* at this point, the http server should have no connection */
2362 tt_assert(TAILQ_FIRST(&http->connections) == NULL);
2366 evhttp_connection_free(evcon);
2371 http_close_detection_test(void *arg)
2373 http_close_detection_(arg, 0);
2376 http_close_detection_delay_test(void *arg)
2378 http_close_detection_(arg, 1);
2382 http_highport_test(void *arg)
2384 struct basic_test_data *data = arg;
2386 struct evhttp *myhttp = NULL;
2388 /* Try a few different ports */
2389 for (i = 0; i < 50; ++i) {
2390 myhttp = evhttp_new(data->base);
2391 if (evhttp_bind_socket(myhttp, "127.0.0.1", 65535 - i) == 0) {
2393 evhttp_free(myhttp);
2396 evhttp_free(myhttp);
2399 tt_fail_msg("Couldn't get a high port");
2403 http_bad_header_test(void *ptr)
2405 struct evkeyvalq headers;
2407 TAILQ_INIT(&headers);
2409 tt_want(evhttp_add_header(&headers, "One", "Two") == 0);
2410 tt_want(evhttp_add_header(&headers, "One", "Two\r\n Three") == 0);
2411 tt_want(evhttp_add_header(&headers, "One\r", "Two") == -1);
2412 tt_want(evhttp_add_header(&headers, "One\n", "Two") == -1);
2413 tt_want(evhttp_add_header(&headers, "One", "Two\r") == -1);
2414 tt_want(evhttp_add_header(&headers, "One", "Two\n") == -1);
2416 evhttp_clear_headers(&headers);
2419 static int validate_header(
2420 const struct evkeyvalq* headers,
2421 const char *key, const char *value)
2423 const char *real_val = evhttp_find_header(headers, key);
2424 tt_assert(real_val != NULL);
2425 tt_want(strcmp(real_val, value) == 0);
2431 http_parse_query_test(void *ptr)
2433 struct evkeyvalq headers;
2436 TAILQ_INIT(&headers);
2438 r = evhttp_parse_query("http://www.test.com/?q=test", &headers);
2439 tt_want(validate_header(&headers, "q", "test") == 0);
2440 tt_int_op(r, ==, 0);
2441 evhttp_clear_headers(&headers);
2443 r = evhttp_parse_query("http://www.test.com/?q=test&foo=bar", &headers);
2444 tt_want(validate_header(&headers, "q", "test") == 0);
2445 tt_want(validate_header(&headers, "foo", "bar") == 0);
2446 tt_int_op(r, ==, 0);
2447 evhttp_clear_headers(&headers);
2449 r = evhttp_parse_query("http://www.test.com/?q=test+foo", &headers);
2450 tt_want(validate_header(&headers, "q", "test foo") == 0);
2451 tt_int_op(r, ==, 0);
2452 evhttp_clear_headers(&headers);
2454 r = evhttp_parse_query("http://www.test.com/?q=test%0Afoo", &headers);
2455 tt_want(validate_header(&headers, "q", "test\nfoo") == 0);
2456 tt_int_op(r, ==, 0);
2457 evhttp_clear_headers(&headers);
2459 r = evhttp_parse_query("http://www.test.com/?q=test%0Dfoo", &headers);
2460 tt_want(validate_header(&headers, "q", "test\rfoo") == 0);
2461 tt_int_op(r, ==, 0);
2462 evhttp_clear_headers(&headers);
2464 r = evhttp_parse_query("http://www.test.com/?q=test&&q2", &headers);
2465 tt_int_op(r, ==, -1);
2466 evhttp_clear_headers(&headers);
2468 r = evhttp_parse_query("http://www.test.com/?q=test+this", &headers);
2469 tt_want(validate_header(&headers, "q", "test this") == 0);
2470 tt_int_op(r, ==, 0);
2471 evhttp_clear_headers(&headers);
2473 r = evhttp_parse_query("http://www.test.com/?q=test&q2=foo", &headers);
2474 tt_int_op(r, ==, 0);
2475 tt_want(validate_header(&headers, "q", "test") == 0);
2476 tt_want(validate_header(&headers, "q2", "foo") == 0);
2477 evhttp_clear_headers(&headers);
2479 r = evhttp_parse_query("http://www.test.com/?q&q2=foo", &headers);
2480 tt_int_op(r, ==, -1);
2481 evhttp_clear_headers(&headers);
2483 r = evhttp_parse_query("http://www.test.com/?q=foo&q2", &headers);
2484 tt_int_op(r, ==, -1);
2485 evhttp_clear_headers(&headers);
2487 r = evhttp_parse_query("http://www.test.com/?q=foo&q2&q3=x", &headers);
2488 tt_int_op(r, ==, -1);
2489 evhttp_clear_headers(&headers);
2491 r = evhttp_parse_query("http://www.test.com/?q=&q2=&q3=", &headers);
2492 tt_int_op(r, ==, 0);
2493 tt_want(validate_header(&headers, "q", "") == 0);
2494 tt_want(validate_header(&headers, "q2", "") == 0);
2495 tt_want(validate_header(&headers, "q3", "") == 0);
2496 evhttp_clear_headers(&headers);
2499 evhttp_clear_headers(&headers);
2502 http_parse_query_str_test(void *ptr)
2504 struct evkeyvalq headers;
2507 TAILQ_INIT(&headers);
2509 r = evhttp_parse_query_str("http://www.test.com/?q=test", &headers);
2510 tt_assert(evhttp_find_header(&headers, "q") == NULL);
2511 tt_int_op(r, ==, 0);
2512 evhttp_clear_headers(&headers);
2514 r = evhttp_parse_query_str("q=test", &headers);
2515 tt_want(validate_header(&headers, "q", "test") == 0);
2516 tt_int_op(r, ==, 0);
2517 evhttp_clear_headers(&headers);
2520 evhttp_clear_headers(&headers);
2524 http_parse_uri_test(void *ptr)
2526 const int nonconform = (ptr != NULL);
2527 const unsigned parse_flags =
2528 nonconform ? EVHTTP_URI_NONCONFORMANT : 0;
2529 struct evhttp_uri *uri = NULL;
2531 #define URI_PARSE(uri) \
2532 evhttp_uri_parse_with_flags((uri), parse_flags)
2534 #define TT_URI(want) do { \
2535 char *ret = evhttp_uri_join(uri, url_tmp, sizeof(url_tmp)); \
2536 tt_want(ret != NULL); \
2537 tt_want(ret == url_tmp); \
2538 if (strcmp(ret,want) != 0) \
2539 TT_FAIL(("\"%s\" != \"%s\"",ret,want)); \
2542 tt_want(evhttp_uri_join(NULL, 0, 0) == NULL);
2543 tt_want(evhttp_uri_join(NULL, url_tmp, 0) == NULL);
2544 tt_want(evhttp_uri_join(NULL, url_tmp, sizeof(url_tmp)) == NULL);
2546 /* bad URIs: parsing */
2547 #define BAD(s) do { \
2548 if (URI_PARSE(s) != NULL) \
2549 TT_FAIL(("Expected error parsing \"%s\"",s)); \
2551 /* Nonconformant URIs we can parse: parsing */
2552 #define NCF(s) do { \
2553 uri = URI_PARSE(s); \
2554 if (uri != NULL && !nonconform) { \
2555 TT_FAIL(("Expected error parsing \"%s\"",s)); \
2556 } else if (uri == NULL && nonconform) { \
2557 TT_FAIL(("Couldn't parse nonconformant URI \"%s\"", \
2561 tt_want(evhttp_uri_join(uri, url_tmp, \
2562 sizeof(url_tmp))); \
2563 evhttp_uri_free(uri); \
2567 NCF("http://www.test.com/ why hello");
2568 NCF("http://www.test.com/why-hello\x01");
2569 NCF("http://www.test.com/why-hello?\x01");
2570 NCF("http://www.test.com/why-hello#\x01");
2571 BAD("http://www.\x01.test.com/why-hello");
2572 BAD("http://www.%7test.com/why-hello");
2573 NCF("http://www.test.com/why-hell%7o");
2574 BAD("h%3ttp://www.test.com/why-hello");
2575 NCF("http://www.test.com/why-hello%7");
2576 NCF("http://www.test.com/why-hell%7o");
2577 NCF("http://www.test.com/foo?ba%r");
2578 NCF("http://www.test.com/foo#ba%r");
2580 BAD("http://www.test.com:999x/");
2581 BAD("http://www.test.com:x/");
2582 BAD("http://[hello-there]/");
2583 BAD("http://[::1]]/");
2584 BAD("http://[::1/");
2585 BAD("http://[foob/");
2587 BAD("http://[ffff:ffff:ffff:ffff:Ffff:ffff:ffff:"
2588 "ffff:ffff:ffff:ffff:ffff:ffff:ffff]/");
2589 BAD("http://[vX.foo]/");
2590 BAD("http://[vX.foo]/");
2591 BAD("http://[v.foo]/");
2592 BAD("http://[v5.fo%o]/");
2593 BAD("http://[v5X]/");
2594 BAD("http://[v5]/");
2596 BAD("http://f\x01red@www.example.com/");
2597 BAD("http://f%0red@www.example.com/");
2598 BAD("http://www.example.com:9999999999999999999999999999999999999/");
2599 BAD("http://www.example.com:hihi/");
2600 BAD("://www.example.com/");
2602 /* bad URIs: joining */
2603 uri = evhttp_uri_new();
2604 tt_want(0==evhttp_uri_set_host(uri, "www.example.com"));
2605 tt_want(evhttp_uri_join(uri, url_tmp, sizeof(url_tmp)) != NULL);
2606 /* not enough space: */
2607 tt_want(evhttp_uri_join(uri, url_tmp, 3) == NULL);
2608 /* host is set, but path doesn't start with "/": */
2609 tt_want(0==evhttp_uri_set_path(uri, "hi_mom"));
2610 tt_want(evhttp_uri_join(uri, url_tmp, sizeof(url_tmp)) == NULL);
2611 tt_want(evhttp_uri_join(uri, NULL, sizeof(url_tmp))==NULL);
2612 tt_want(evhttp_uri_join(uri, url_tmp, 0)==NULL);
2613 evhttp_uri_free(uri);
2614 uri = URI_PARSE("mailto:foo@bar");
2615 tt_want(uri != NULL);
2616 tt_want(evhttp_uri_get_host(uri) == NULL);
2617 tt_want(evhttp_uri_get_userinfo(uri) == NULL);
2618 tt_want(evhttp_uri_get_port(uri) == -1);
2619 tt_want(!strcmp(evhttp_uri_get_scheme(uri), "mailto"));
2620 tt_want(!strcmp(evhttp_uri_get_path(uri), "foo@bar"));
2621 tt_want(evhttp_uri_get_query(uri) == NULL);
2622 tt_want(evhttp_uri_get_fragment(uri) == NULL);
2623 TT_URI("mailto:foo@bar");
2624 evhttp_uri_free(uri);
2626 uri = evhttp_uri_new();
2627 /* Bad URI usage: setting invalid values */
2628 tt_want(-1 == evhttp_uri_set_scheme(uri,""));
2629 tt_want(-1 == evhttp_uri_set_scheme(uri,"33"));
2630 tt_want(-1 == evhttp_uri_set_scheme(uri,"hi!"));
2631 tt_want(-1 == evhttp_uri_set_userinfo(uri,"hello@"));
2632 tt_want(-1 == evhttp_uri_set_host(uri,"[1.2.3.4]"));
2633 tt_want(-1 == evhttp_uri_set_host(uri,"["));
2634 tt_want(-1 == evhttp_uri_set_host(uri,"www.[foo].com"));
2635 tt_want(-1 == evhttp_uri_set_port(uri,-3));
2636 tt_want(-1 == evhttp_uri_set_path(uri,"hello?world"));
2637 tt_want(-1 == evhttp_uri_set_query(uri,"hello#world"));
2638 tt_want(-1 == evhttp_uri_set_fragment(uri,"hello#world"));
2639 /* Valid URI usage: setting valid values */
2640 tt_want(0 == evhttp_uri_set_scheme(uri,"http"));
2641 tt_want(0 == evhttp_uri_set_scheme(uri,NULL));
2642 tt_want(0 == evhttp_uri_set_userinfo(uri,"username:pass"));
2643 tt_want(0 == evhttp_uri_set_userinfo(uri,NULL));
2644 tt_want(0 == evhttp_uri_set_host(uri,"www.example.com"));
2645 tt_want(0 == evhttp_uri_set_host(uri,"1.2.3.4"));
2646 tt_want(0 == evhttp_uri_set_host(uri,"[1:2:3:4::]"));
2647 tt_want(0 == evhttp_uri_set_host(uri,"[v7.wobblewobble]"));
2648 tt_want(0 == evhttp_uri_set_host(uri,NULL));
2649 tt_want(0 == evhttp_uri_set_host(uri,""));
2650 tt_want(0 == evhttp_uri_set_port(uri, -1));
2651 tt_want(0 == evhttp_uri_set_port(uri, 80));
2652 tt_want(0 == evhttp_uri_set_port(uri, 65535));
2653 tt_want(0 == evhttp_uri_set_path(uri, ""));
2654 tt_want(0 == evhttp_uri_set_path(uri, "/documents/public/index.html"));
2655 tt_want(0 == evhttp_uri_set_path(uri, NULL));
2656 tt_want(0 == evhttp_uri_set_query(uri, "key=val&key2=val2"));
2657 tt_want(0 == evhttp_uri_set_query(uri, "keyvalblarg"));
2658 tt_want(0 == evhttp_uri_set_query(uri, ""));
2659 tt_want(0 == evhttp_uri_set_query(uri, NULL));
2660 tt_want(0 == evhttp_uri_set_fragment(uri, ""));
2661 tt_want(0 == evhttp_uri_set_fragment(uri, "here?i?am"));
2662 tt_want(0 == evhttp_uri_set_fragment(uri, NULL));
2663 evhttp_uri_free(uri);
2666 uri = URI_PARSE("http://www.test.com/?q=t%33est");
2667 tt_want(strcmp(evhttp_uri_get_scheme(uri), "http") == 0);
2668 tt_want(strcmp(evhttp_uri_get_host(uri), "www.test.com") == 0);
2669 tt_want(strcmp(evhttp_uri_get_path(uri), "/") == 0);
2670 tt_want(strcmp(evhttp_uri_get_query(uri), "q=t%33est") == 0);
2671 tt_want(evhttp_uri_get_userinfo(uri) == NULL);
2672 tt_want(evhttp_uri_get_port(uri) == -1);
2673 tt_want(evhttp_uri_get_fragment(uri) == NULL);
2674 TT_URI("http://www.test.com/?q=t%33est");
2675 evhttp_uri_free(uri);
2677 uri = URI_PARSE("http://%77ww.test.com");
2678 tt_want(strcmp(evhttp_uri_get_scheme(uri), "http") == 0);
2679 tt_want(strcmp(evhttp_uri_get_host(uri), "%77ww.test.com") == 0);
2680 tt_want(strcmp(evhttp_uri_get_path(uri), "") == 0);
2681 tt_want(evhttp_uri_get_query(uri) == NULL);
2682 tt_want(evhttp_uri_get_userinfo(uri) == NULL);
2683 tt_want(evhttp_uri_get_port(uri) == -1);
2684 tt_want(evhttp_uri_get_fragment(uri) == NULL);
2685 TT_URI("http://%77ww.test.com");
2686 evhttp_uri_free(uri);
2688 uri = URI_PARSE("http://www.test.com?q=test");
2689 tt_want(strcmp(evhttp_uri_get_scheme(uri), "http") == 0);
2690 tt_want(strcmp(evhttp_uri_get_host(uri), "www.test.com") == 0);
2691 tt_want(strcmp(evhttp_uri_get_path(uri), "") == 0);
2692 tt_want(strcmp(evhttp_uri_get_query(uri), "q=test") == 0);
2693 tt_want(evhttp_uri_get_userinfo(uri) == NULL);
2694 tt_want(evhttp_uri_get_port(uri) == -1);
2695 tt_want(evhttp_uri_get_fragment(uri) == NULL);
2696 TT_URI("http://www.test.com?q=test");
2697 evhttp_uri_free(uri);
2699 uri = URI_PARSE("http://www.test.com#fragment");
2700 tt_want(strcmp(evhttp_uri_get_scheme(uri), "http") == 0);
2701 tt_want(strcmp(evhttp_uri_get_host(uri), "www.test.com") == 0);
2702 tt_want(strcmp(evhttp_uri_get_path(uri), "") == 0);
2703 tt_want(evhttp_uri_get_query(uri) == NULL);
2704 tt_want(evhttp_uri_get_userinfo(uri) == NULL);
2705 tt_want(evhttp_uri_get_port(uri) == -1);
2706 tt_want_str_op(evhttp_uri_get_fragment(uri), ==, "fragment");
2707 TT_URI("http://www.test.com#fragment");
2708 evhttp_uri_free(uri);
2710 uri = URI_PARSE("http://8000/");
2711 tt_want(strcmp(evhttp_uri_get_scheme(uri), "http") == 0);
2712 tt_want(strcmp(evhttp_uri_get_host(uri), "8000") == 0);
2713 tt_want(strcmp(evhttp_uri_get_path(uri), "/") == 0);
2714 tt_want(evhttp_uri_get_query(uri) == NULL);
2715 tt_want(evhttp_uri_get_userinfo(uri) == NULL);
2716 tt_want(evhttp_uri_get_port(uri) == -1);
2717 tt_want(evhttp_uri_get_fragment(uri) == NULL);
2718 TT_URI("http://8000/");
2719 evhttp_uri_free(uri);
2721 uri = URI_PARSE("http://:8000/");
2722 tt_want(strcmp(evhttp_uri_get_scheme(uri), "http") == 0);
2723 tt_want(strcmp(evhttp_uri_get_host(uri), "") == 0);
2724 tt_want(strcmp(evhttp_uri_get_path(uri), "/") == 0);
2725 tt_want(evhttp_uri_get_query(uri) == NULL);
2726 tt_want(evhttp_uri_get_userinfo(uri) == NULL);
2727 tt_want(evhttp_uri_get_port(uri) == 8000);
2728 tt_want(evhttp_uri_get_fragment(uri) == NULL);
2729 TT_URI("http://:8000/");
2730 evhttp_uri_free(uri);
2732 uri = URI_PARSE("http://www.test.com:/"); /* empty port */
2733 tt_want(strcmp(evhttp_uri_get_scheme(uri), "http") == 0);
2734 tt_want(strcmp(evhttp_uri_get_host(uri), "www.test.com") == 0);
2735 tt_want_str_op(evhttp_uri_get_path(uri), ==, "/");
2736 tt_want(evhttp_uri_get_query(uri) == NULL);
2737 tt_want(evhttp_uri_get_userinfo(uri) == NULL);
2738 tt_want(evhttp_uri_get_port(uri) == -1);
2739 tt_want(evhttp_uri_get_fragment(uri) == NULL);
2740 TT_URI("http://www.test.com/");
2741 evhttp_uri_free(uri);
2743 uri = URI_PARSE("http://www.test.com:"); /* empty port 2 */
2744 tt_want(strcmp(evhttp_uri_get_scheme(uri), "http") == 0);
2745 tt_want(strcmp(evhttp_uri_get_host(uri), "www.test.com") == 0);
2746 tt_want(strcmp(evhttp_uri_get_path(uri), "") == 0);
2747 tt_want(evhttp_uri_get_query(uri) == NULL);
2748 tt_want(evhttp_uri_get_userinfo(uri) == NULL);
2749 tt_want(evhttp_uri_get_port(uri) == -1);
2750 tt_want(evhttp_uri_get_fragment(uri) == NULL);
2751 TT_URI("http://www.test.com");
2752 evhttp_uri_free(uri);
2754 uri = URI_PARSE("ftp://www.test.com/?q=test");
2755 tt_want(strcmp(evhttp_uri_get_scheme(uri), "ftp") == 0);
2756 tt_want(strcmp(evhttp_uri_get_host(uri), "www.test.com") == 0);
2757 tt_want(strcmp(evhttp_uri_get_path(uri), "/") == 0);
2758 tt_want(strcmp(evhttp_uri_get_query(uri), "q=test") == 0);
2759 tt_want(evhttp_uri_get_userinfo(uri) == NULL);
2760 tt_want(evhttp_uri_get_port(uri) == -1);
2761 tt_want(evhttp_uri_get_fragment(uri) == NULL);
2762 TT_URI("ftp://www.test.com/?q=test");
2763 evhttp_uri_free(uri);
2765 uri = URI_PARSE("ftp://[::1]:999/?q=test");
2766 tt_want(strcmp(evhttp_uri_get_scheme(uri), "ftp") == 0);
2767 tt_want(strcmp(evhttp_uri_get_host(uri), "[::1]") == 0);
2768 tt_want(strcmp(evhttp_uri_get_path(uri), "/") == 0);
2769 tt_want(strcmp(evhttp_uri_get_query(uri), "q=test") == 0);
2770 tt_want(evhttp_uri_get_userinfo(uri) == NULL);
2771 tt_want(evhttp_uri_get_port(uri) == 999);
2772 tt_want(evhttp_uri_get_fragment(uri) == NULL);
2773 TT_URI("ftp://[::1]:999/?q=test");
2774 evhttp_uri_free(uri);
2776 uri = URI_PARSE("ftp://[ff00::127.0.0.1]/?q=test");
2777 tt_want(strcmp(evhttp_uri_get_scheme(uri), "ftp") == 0);
2778 tt_want(strcmp(evhttp_uri_get_host(uri), "[ff00::127.0.0.1]") == 0);
2779 tt_want(strcmp(evhttp_uri_get_path(uri), "/") == 0);
2780 tt_want(strcmp(evhttp_uri_get_query(uri), "q=test") == 0);
2781 tt_want(evhttp_uri_get_userinfo(uri) == NULL);
2782 tt_want(evhttp_uri_get_port(uri) == -1);
2783 tt_want(evhttp_uri_get_fragment(uri) == NULL);
2784 TT_URI("ftp://[ff00::127.0.0.1]/?q=test");
2785 evhttp_uri_free(uri);
2787 uri = URI_PARSE("ftp://[v99.not_(any:time)_soon]/?q=test");
2788 tt_want(strcmp(evhttp_uri_get_scheme(uri), "ftp") == 0);
2789 tt_want(strcmp(evhttp_uri_get_host(uri), "[v99.not_(any:time)_soon]") == 0);
2790 tt_want(strcmp(evhttp_uri_get_path(uri), "/") == 0);
2791 tt_want(strcmp(evhttp_uri_get_query(uri), "q=test") == 0);
2792 tt_want(evhttp_uri_get_userinfo(uri) == NULL);
2793 tt_want(evhttp_uri_get_port(uri) == -1);
2794 tt_want(evhttp_uri_get_fragment(uri) == NULL);
2795 TT_URI("ftp://[v99.not_(any:time)_soon]/?q=test");
2796 evhttp_uri_free(uri);
2798 uri = URI_PARSE("scheme://user:pass@foo.com:42/?q=test&s=some+thing#fragment");
2799 tt_want(strcmp(evhttp_uri_get_scheme(uri), "scheme") == 0);
2800 tt_want(strcmp(evhttp_uri_get_userinfo(uri), "user:pass") == 0);
2801 tt_want(strcmp(evhttp_uri_get_host(uri), "foo.com") == 0);
2802 tt_want(evhttp_uri_get_port(uri) == 42);
2803 tt_want(strcmp(evhttp_uri_get_path(uri), "/") == 0);
2804 tt_want(strcmp(evhttp_uri_get_query(uri), "q=test&s=some+thing") == 0);
2805 tt_want(strcmp(evhttp_uri_get_fragment(uri), "fragment") == 0);
2806 TT_URI("scheme://user:pass@foo.com:42/?q=test&s=some+thing#fragment");
2807 evhttp_uri_free(uri);
2809 uri = URI_PARSE("scheme://user@foo.com/#fragment");
2810 tt_want(strcmp(evhttp_uri_get_scheme(uri), "scheme") == 0);
2811 tt_want(strcmp(evhttp_uri_get_userinfo(uri), "user") == 0);
2812 tt_want(strcmp(evhttp_uri_get_host(uri), "foo.com") == 0);
2813 tt_want(evhttp_uri_get_port(uri) == -1);
2814 tt_want(strcmp(evhttp_uri_get_path(uri), "/") == 0);
2815 tt_want(evhttp_uri_get_query(uri) == NULL);
2816 tt_want(strcmp(evhttp_uri_get_fragment(uri), "fragment") == 0);
2817 TT_URI("scheme://user@foo.com/#fragment");
2818 evhttp_uri_free(uri);
2820 uri = URI_PARSE("scheme://%75ser@foo.com/#frag@ment");
2821 tt_want(strcmp(evhttp_uri_get_scheme(uri), "scheme") == 0);
2822 tt_want(strcmp(evhttp_uri_get_userinfo(uri), "%75ser") == 0);
2823 tt_want(strcmp(evhttp_uri_get_host(uri), "foo.com") == 0);
2824 tt_want(evhttp_uri_get_port(uri) == -1);
2825 tt_want(strcmp(evhttp_uri_get_path(uri), "/") == 0);
2826 tt_want(evhttp_uri_get_query(uri) == NULL);
2827 tt_want(strcmp(evhttp_uri_get_fragment(uri), "frag@ment") == 0);
2828 TT_URI("scheme://%75ser@foo.com/#frag@ment");
2829 evhttp_uri_free(uri);
2831 uri = URI_PARSE("file:///some/path/to/the/file");
2832 tt_want(strcmp(evhttp_uri_get_scheme(uri), "file") == 0);
2833 tt_want(evhttp_uri_get_userinfo(uri) == NULL);
2834 tt_want(strcmp(evhttp_uri_get_host(uri), "") == 0);
2835 tt_want(evhttp_uri_get_port(uri) == -1);
2836 tt_want(strcmp(evhttp_uri_get_path(uri), "/some/path/to/the/file") == 0);
2837 tt_want(evhttp_uri_get_query(uri) == NULL);
2838 tt_want(evhttp_uri_get_fragment(uri) == NULL);
2839 TT_URI("file:///some/path/to/the/file");
2840 evhttp_uri_free(uri);
2842 uri = URI_PARSE("///some/path/to/the-file");
2843 tt_want(uri != NULL);
2844 tt_want(evhttp_uri_get_scheme(uri) == NULL);
2845 tt_want(evhttp_uri_get_userinfo(uri) == NULL);
2846 tt_want(strcmp(evhttp_uri_get_host(uri), "") == 0);
2847 tt_want(evhttp_uri_get_port(uri) == -1);
2848 tt_want(strcmp(evhttp_uri_get_path(uri), "/some/path/to/the-file") == 0);
2849 tt_want(evhttp_uri_get_query(uri) == NULL);
2850 tt_want(evhttp_uri_get_fragment(uri) == NULL);
2851 TT_URI("///some/path/to/the-file");
2852 evhttp_uri_free(uri);
2854 uri = URI_PARSE("/s:ome/path/to/the-file?q=99#fred");
2855 tt_want(uri != NULL);
2856 tt_want(evhttp_uri_get_scheme(uri) == NULL);
2857 tt_want(evhttp_uri_get_userinfo(uri) == NULL);
2858 tt_want(evhttp_uri_get_host(uri) == NULL);
2859 tt_want(evhttp_uri_get_port(uri) == -1);
2860 tt_want(strcmp(evhttp_uri_get_path(uri), "/s:ome/path/to/the-file") == 0);
2861 tt_want(strcmp(evhttp_uri_get_query(uri), "q=99") == 0);
2862 tt_want(strcmp(evhttp_uri_get_fragment(uri), "fred") == 0);
2863 TT_URI("/s:ome/path/to/the-file?q=99#fred");
2864 evhttp_uri_free(uri);
2866 uri = URI_PARSE("relative/path/with/co:lon");
2867 tt_want(uri != NULL);
2868 tt_want(evhttp_uri_get_scheme(uri) == NULL);
2869 tt_want(evhttp_uri_get_userinfo(uri) == NULL);
2870 tt_want(evhttp_uri_get_host(uri) == NULL);
2871 tt_want(evhttp_uri_get_port(uri) == -1);
2872 tt_want(strcmp(evhttp_uri_get_path(uri), "relative/path/with/co:lon") == 0);
2873 tt_want(evhttp_uri_get_query(uri) == NULL);
2874 tt_want(evhttp_uri_get_fragment(uri) == NULL);
2875 TT_URI("relative/path/with/co:lon");
2876 evhttp_uri_free(uri);
2878 uri = URI_PARSE("bob?q=99&q2=q?33#fr?ed");
2879 tt_want(uri != NULL);
2880 tt_want(evhttp_uri_get_scheme(uri) == NULL);
2881 tt_want(evhttp_uri_get_userinfo(uri) == NULL);
2882 tt_want(evhttp_uri_get_host(uri) == NULL);
2883 tt_want(evhttp_uri_get_port(uri) == -1);
2884 tt_want(strcmp(evhttp_uri_get_path(uri), "bob") == 0);
2885 tt_want(strcmp(evhttp_uri_get_query(uri), "q=99&q2=q?33") == 0);
2886 tt_want(strcmp(evhttp_uri_get_fragment(uri), "fr?ed") == 0);
2887 TT_URI("bob?q=99&q2=q?33#fr?ed");
2888 evhttp_uri_free(uri);
2890 uri = URI_PARSE("#fr?ed");
2891 tt_want(uri != NULL);
2892 tt_want(evhttp_uri_get_scheme(uri) == NULL);
2893 tt_want(evhttp_uri_get_userinfo(uri) == NULL);
2894 tt_want(evhttp_uri_get_host(uri) == NULL);
2895 tt_want(evhttp_uri_get_port(uri) == -1);
2896 tt_want(strcmp(evhttp_uri_get_path(uri), "") == 0);
2897 tt_want(evhttp_uri_get_query(uri) == NULL);
2898 tt_want(strcmp(evhttp_uri_get_fragment(uri), "fr?ed") == 0);
2900 evhttp_uri_free(uri);
2907 http_uriencode_test(void *ptr)
2909 char *s=NULL, *s2=NULL;
2913 #define ENC(from,want,plus) do { \
2914 s = evhttp_uriencode((from), -1, (plus)); \
2916 tt_str_op(s,==,(want)); \
2918 s2 = evhttp_uridecode((s), (plus), &sz); \
2920 tt_str_op(s2,==,(from)); \
2921 tt_int_op(sz,==,strlen(from)); \
2927 #define DEC(from,want,dp) do { \
2928 s = evhttp_uridecode((from),(dp),&sz); \
2930 tt_str_op(s,==,(want)); \
2931 tt_int_op(sz,==,strlen(want)); \
2936 #define OLD_DEC(from,want) do { \
2937 s = evhttp_decode_uri((from)); \
2939 tt_str_op(s,==,(want)); \
2945 ENC("Hello", "Hello",0);
2949 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ123456789-.~_",
2950 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ123456789-.~_",0);
2953 ENC("\xff\xf0\xe0", "%FF%F0%E0",0);
2954 ENC("\x01\x19", "%01%19",1);
2955 ENC("http://www.ietf.org/rfc/rfc3986.txt",
2956 "http%3A%2F%2Fwww.ietf.org%2Frfc%2Frfc3986.txt",1);
2958 ENC("1+2=3", "1%2B2%3D3",1);
2959 ENC("1+2=3", "1%2B2%3D3",0);
2961 /* Now try encoding with internal NULs. */
2962 s = evhttp_uriencode("hello\0world", 11, 0);
2964 tt_str_op(s,==,"hello%00world");
2968 /* Now try decoding just part of string. */
2969 s = malloc(6 + 1 /* NUL byte */);
2970 bytes_decoded = evhttp_decode_uri_internal("hello%20%20", 6, s, 0);
2972 tt_int_op(bytes_decoded,==,6);
2973 tt_str_op(s,==,"hello%");
2977 /* Now try out some decoding cases that we don't generate with
2978 * encode_uri: Make sure that malformed stuff doesn't crash... */
2979 DEC("%%xhello th+ere \xff",
2980 "%%xhello th+ere \xff", 0);
2981 /* Make sure plus decoding works */
2982 DEC("plus+should%20work+", "plus should work ",1);
2983 /* Try some lowercase hex */
2984 DEC("%f0%a0%b0", "\xf0\xa0\xb0",1);
2986 /* Try an internal NUL. */
2988 s = evhttp_uridecode("%00%00x%00%00", 1, &sz);
2990 tt_assert(!memcmp(s, "\0\0x\0\0", 5));
2994 /* Try with size == NULL */
2996 s = evhttp_uridecode("%00%00x%00%00", 1, NULL);
2997 tt_assert(!memcmp(s, "\0\0x\0\0", 5));
3001 /* Test out the crazy old behavior of the deprecated
3002 * evhttp_decode_uri */
3003 OLD_DEC("http://example.com/normal+path/?key=val+with+spaces",
3004 "http://example.com/normal+path/?key=val with spaces");
3017 http_base_test(void *ptr)
3019 struct event_base *base = NULL;
3020 struct bufferevent *bev;
3022 const char *http_request;
3023 ev_uint16_t port = 0;
3024 struct evhttp *http;
3027 base = event_base_new();
3029 http = http_setup(&port, base, 0);
3031 fd = http_connect("127.0.0.1", port);
3032 tt_assert(fd != EVUTIL_INVALID_SOCKET);
3034 /* Stupid thing to send a request */
3035 bev = bufferevent_socket_new(base, fd, 0);
3036 bufferevent_setcb(bev, http_readcb, http_writecb,
3037 http_errorcb, base);
3038 bufferevent_base_set(base, bev);
3041 "GET /test HTTP/1.1\r\n"
3042 "Host: somehost\r\n"
3043 "Connection: close\r\n"
3046 bufferevent_write(bev, http_request, strlen(http_request));
3048 event_base_dispatch(base);
3050 bufferevent_free(bev);
3051 evutil_closesocket(fd);
3055 tt_int_op(test_ok, ==, 2);
3059 event_base_free(base);
3063 * the server is just going to close the connection if it times out during
3064 * reading the headers.
3068 http_incomplete_readcb(struct bufferevent *bev, void *arg)
3071 event_base_loopexit(exit_base,NULL);
3075 http_incomplete_errorcb(struct bufferevent *bev, short what, void *arg)
3078 if (what & BEV_EVENT_CONNECTED)
3081 if (what == (BEV_EVENT_READING|BEV_EVENT_EOF))
3085 event_base_loopexit(exit_base,NULL);
3089 http_incomplete_writecb(struct bufferevent *bev, void *arg)
3092 evutil_socket_t fd = *(evutil_socket_t *)arg;
3093 /* terminate the write side to simulate EOF */
3094 shutdown(fd, EVUTIL_SHUT_WR);
3096 if (evbuffer_get_length(bufferevent_get_output(bev)) == 0) {
3097 /* enable reading of the reply */
3098 bufferevent_enable(bev, EV_READ);
3104 http_incomplete_test_(struct basic_test_data *data, int use_timeout, int ssl)
3106 struct bufferevent *bev;
3108 const char *http_request;
3109 ev_uint16_t port = 0;
3110 struct timeval tv_start, tv_end;
3111 struct evhttp *http = http_setup(&port, data->base, ssl ? HTTP_BIND_SSL : 0);
3113 exit_base = data->base;
3116 evhttp_set_timeout(http, 1);
3118 fd = http_connect("127.0.0.1", port);
3119 tt_assert(fd != EVUTIL_INVALID_SOCKET);
3121 /* Stupid thing to send a request */
3122 bev = create_bev(data->base, fd, ssl);
3123 bufferevent_setcb(bev,
3124 http_incomplete_readcb, http_incomplete_writecb,
3125 http_incomplete_errorcb, use_timeout ? NULL : &fd);
3128 "GET /test HTTP/1.1\r\n"
3129 "Host: somehost\r\n";
3131 bufferevent_write(bev, http_request, strlen(http_request));
3133 evutil_gettimeofday(&tv_start, NULL);
3135 event_base_dispatch(data->base);
3137 evutil_gettimeofday(&tv_end, NULL);
3138 evutil_timersub(&tv_end, &tv_start, &tv_end);
3140 bufferevent_free(bev);
3142 evutil_closesocket(fd);
3143 fd = EVUTIL_INVALID_SOCKET;
3148 if (use_timeout && tv_end.tv_sec >= 3) {
3149 tt_abort_msg("time");
3150 } else if (!use_timeout && tv_end.tv_sec >= 1) {
3151 /* we should be done immediately */
3152 tt_abort_msg("time");
3155 tt_int_op(test_ok, ==, 2);
3158 evutil_closesocket(fd);
3160 static void http_incomplete_test(void *arg)
3161 { http_incomplete_test_(arg, 0, 0); }
3162 static void http_incomplete_timeout_test(void *arg)
3163 { http_incomplete_test_(arg, 1, 0); }
3167 * the server is going to reply with chunked data.
3171 http_chunked_readcb(struct bufferevent *bev, void *arg)
3177 http_chunked_errorcb(struct bufferevent *bev, short what, void *arg)
3179 struct evhttp_request *req = NULL;
3182 if (what & BEV_EVENT_CONNECTED)
3190 if ((what & BEV_EVENT_EOF) != 0) {
3192 enum message_read_status done;
3193 req = evhttp_request_new(NULL, NULL);
3195 /* req->kind = EVHTTP_RESPONSE; */
3196 done = evhttp_parse_firstline_(req, bufferevent_get_input(bev));
3197 if (done != ALL_DATA_READ)
3200 done = evhttp_parse_headers_(req, bufferevent_get_input(bev));
3201 if (done != ALL_DATA_READ)
3204 header = evhttp_find_header(evhttp_request_get_input_headers(req), "Transfer-Encoding");
3205 if (header == NULL || strcmp(header, "chunked"))
3208 header = evhttp_find_header(evhttp_request_get_input_headers(req), "Connection");
3209 if (header == NULL || strcmp(header, "close"))
3212 header = evbuffer_readln(bufferevent_get_input(bev), NULL, EVBUFFER_EOL_CRLF);
3216 if (strcmp(header, "d")) {
3217 free((void*)header);
3220 free((void*)header);
3222 if (strncmp((char *)evbuffer_pullup(bufferevent_get_input(bev), 13),
3223 "This is funny", 13))
3226 evbuffer_drain(bufferevent_get_input(bev), 13 + 2);
3228 header = evbuffer_readln(bufferevent_get_input(bev), NULL, EVBUFFER_EOL_CRLF);
3232 if (strcmp(header, "12"))
3234 free((char *)header);
3236 if (strncmp((char *)evbuffer_pullup(bufferevent_get_input(bev), 18),
3237 "but not hilarious.", 18))
3240 evbuffer_drain(bufferevent_get_input(bev), 18 + 2);
3242 header = evbuffer_readln(bufferevent_get_input(bev), NULL, EVBUFFER_EOL_CRLF);
3246 if (strcmp(header, "8")) {
3247 free((void*)header);
3250 free((char *)header);
3252 if (strncmp((char *)evbuffer_pullup(bufferevent_get_input(bev), 8),
3256 evbuffer_drain(bufferevent_get_input(bev), 8 + 2);
3258 header = evbuffer_readln(bufferevent_get_input(bev), NULL, EVBUFFER_EOL_CRLF);
3262 if (strcmp(header, "0")) {
3263 free((void*)header);
3266 free((void *)header);
3273 evhttp_request_free(req);
3275 event_base_loopexit(arg, NULL);
3279 http_chunked_writecb(struct bufferevent *bev, void *arg)
3281 if (evbuffer_get_length(bufferevent_get_output(bev)) == 0) {
3282 /* enable reading of the reply */
3283 bufferevent_enable(bev, EV_READ);
3289 http_chunked_request_done(struct evhttp_request *req, void *arg)
3291 if (evhttp_request_get_response_code(req) != HTTP_OK) {
3292 fprintf(stderr, "FAILED\n");
3296 if (evhttp_find_header(evhttp_request_get_input_headers(req),
3297 "Transfer-Encoding") == NULL) {
3298 fprintf(stderr, "FAILED\n");
3302 if (evbuffer_get_length(evhttp_request_get_input_buffer(req)) != 13 + 18 + 8) {
3303 fprintf(stderr, "FAILED\n");
3307 if (strncmp((char *)evbuffer_pullup(evhttp_request_get_input_buffer(req), 13 + 18 + 8),
3308 "This is funnybut not hilarious.bwv 1052",
3310 fprintf(stderr, "FAILED\n");
3315 event_base_loopexit(arg, NULL);
3319 http_chunk_out_test_impl(void *arg, int ssl)
3321 struct basic_test_data *data = arg;
3322 struct bufferevent *bev;
3324 const char *http_request;
3325 ev_uint16_t port = 0;
3326 struct timeval tv_start, tv_end;
3327 struct evhttp_connection *evcon = NULL;
3328 struct evhttp_request *req = NULL;
3330 struct evhttp *http = http_setup(&port, data->base, ssl ? HTTP_BIND_SSL : 0);
3332 exit_base = data->base;
3335 fd = http_connect("127.0.0.1", port);
3336 tt_assert(fd != EVUTIL_INVALID_SOCKET);
3338 /* Stupid thing to send a request */
3339 bev = create_bev(data->base, fd, ssl);
3340 bufferevent_setcb(bev,
3341 http_chunked_readcb, http_chunked_writecb,
3342 http_chunked_errorcb, data->base);
3345 "GET /chunked HTTP/1.1\r\n"
3346 "Host: somehost\r\n"
3347 "Connection: close\r\n"
3350 bufferevent_write(bev, http_request, strlen(http_request));
3352 evutil_gettimeofday(&tv_start, NULL);
3354 event_base_dispatch(data->base);
3356 bufferevent_free(bev);
3358 evutil_gettimeofday(&tv_end, NULL);
3359 evutil_timersub(&tv_end, &tv_start, &tv_end);
3361 tt_int_op(tv_end.tv_sec, <, 1);
3363 tt_int_op(test_ok, ==, 2);
3365 /* now try again with the regular connection object */
3366 bev = create_bev(data->base, -1, ssl);
3367 evcon = evhttp_connection_base_bufferevent_new(
3368 data->base, NULL, bev, "127.0.0.1", port);
3371 /* make two requests to check the keepalive behavior */
3372 for (i = 0; i < 2; i++) {
3374 req = evhttp_request_new(http_chunked_request_done,data->base);
3376 /* Add the information that we care about */
3377 evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
3379 /* We give ownership of the request to the connection */
3380 if (evhttp_make_request(evcon, req,
3381 EVHTTP_REQ_GET, "/chunked") == -1) {
3382 tt_abort_msg("Couldn't make request");
3385 event_base_dispatch(data->base);
3387 tt_assert(test_ok == 1);
3392 evhttp_connection_free(evcon);
3396 static void http_chunk_out_test(void *arg)
3397 { http_chunk_out_test_impl(arg, 0); }
3400 http_stream_out_test_impl(void *arg, int ssl)
3402 struct basic_test_data *data = arg;
3403 ev_uint16_t port = 0;
3404 struct evhttp_connection *evcon = NULL;
3405 struct evhttp_request *req = NULL;
3406 struct bufferevent *bev;
3407 struct evhttp *http = http_setup(&port, data->base, ssl ? HTTP_BIND_SSL : 0);
3410 exit_base = data->base;
3412 bev = create_bev(data->base, -1, ssl);
3413 evcon = evhttp_connection_base_bufferevent_new(
3414 data->base, NULL, bev, "127.0.0.1", port);
3418 * At this point, we want to schedule a request to the HTTP
3419 * server using our make request method.
3422 req = evhttp_request_new(http_request_done,
3423 (void *)"This is funnybut not hilarious.bwv 1052");
3425 /* Add the information that we care about */
3426 evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
3428 /* We give ownership of the request to the connection */
3429 if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/streamed")
3431 tt_abort_msg("Couldn't make request");
3434 event_base_dispatch(data->base);
3438 evhttp_connection_free(evcon);
3442 static void http_stream_out_test(void *arg)
3443 { http_stream_out_test_impl(arg, 0); }
3446 http_stream_in_chunk(struct evhttp_request *req, void *arg)
3448 struct evbuffer *reply = arg;
3450 if (evhttp_request_get_response_code(req) != HTTP_OK) {
3451 fprintf(stderr, "FAILED\n");
3455 evbuffer_add_buffer(reply, evhttp_request_get_input_buffer(req));
3459 http_stream_in_done(struct evhttp_request *req, void *arg)
3461 if (evbuffer_get_length(evhttp_request_get_input_buffer(req)) != 0) {
3462 fprintf(stderr, "FAILED\n");
3466 event_base_loopexit(exit_base, NULL);
3470 * Makes a request and reads the response in chunks.
3473 http_stream_in_test_(struct basic_test_data *data, char const *url,
3474 size_t expected_len, char const *expected)
3476 struct evhttp_connection *evcon;
3477 struct evbuffer *reply = evbuffer_new();
3478 struct evhttp_request *req = NULL;
3479 ev_uint16_t port = 0;
3480 struct evhttp *http = http_setup(&port, data->base, 0);
3482 exit_base = data->base;
3484 evcon = evhttp_connection_base_new(data->base, NULL,"127.0.0.1", port);
3487 req = evhttp_request_new(http_stream_in_done, reply);
3488 evhttp_request_set_chunked_cb(req, http_stream_in_chunk);
3490 /* We give ownership of the request to the connection */
3491 if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, url) == -1) {
3492 tt_abort_msg("Couldn't make request");
3495 event_base_dispatch(data->base);
3497 if (evbuffer_get_length(reply) != expected_len) {
3498 TT_DIE(("reply length %lu; expected %lu; FAILED (%s)\n",
3499 (unsigned long)evbuffer_get_length(reply),
3500 (unsigned long)expected_len,
3501 (char*)evbuffer_pullup(reply, -1)));
3504 if (memcmp(evbuffer_pullup(reply, -1), expected, expected_len) != 0) {
3505 tt_abort_msg("Memory mismatch");
3511 evbuffer_free(reply);
3513 evhttp_connection_free(evcon);
3519 http_stream_in_test(void *arg)
3521 http_stream_in_test_(arg, "/chunked", 13 + 18 + 8,
3522 "This is funnybut not hilarious.bwv 1052");
3524 http_stream_in_test_(arg, "/test", strlen(BASIC_REQUEST_BODY),
3525 BASIC_REQUEST_BODY);
3529 http_stream_in_cancel_chunk(struct evhttp_request *req, void *arg)
3531 tt_int_op(evhttp_request_get_response_code(req), ==, HTTP_OK);
3534 evhttp_cancel_request(req);
3535 event_base_loopexit(arg, NULL);
3539 http_stream_in_cancel_done(struct evhttp_request *req, void *arg)
3541 /* should never be called */
3542 tt_fail_msg("In cancel done");
3546 http_stream_in_cancel_test(void *arg)
3548 struct basic_test_data *data = arg;
3549 struct evhttp_connection *evcon;
3550 struct evhttp_request *req = NULL;
3551 ev_uint16_t port = 0;
3552 struct evhttp *http = http_setup(&port, data->base, 0);
3554 evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port);
3557 req = evhttp_request_new(http_stream_in_cancel_done, data->base);
3558 evhttp_request_set_chunked_cb(req, http_stream_in_cancel_chunk);
3560 /* We give ownership of the request to the connection */
3561 if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/chunked") == -1) {
3562 tt_abort_msg("Couldn't make request");
3565 event_base_dispatch(data->base);
3569 evhttp_connection_free(evcon);
3575 http_connection_fail_done(struct evhttp_request *req, void *arg)
3577 struct evhttp_connection *evcon = arg;
3578 struct event_base *base = evhttp_connection_get_base(evcon);
3580 /* An ENETUNREACH error results in an unrecoverable
3581 * evhttp_connection error (see evhttp_connection_fail_()). The
3582 * connection will be reset, and the user will be notified with a NULL
3586 evhttp_connection_free(evcon);
3591 event_base_loopexit(base, NULL);
3594 /* Test unrecoverable evhttp_connection errors by generating an ENETUNREACH
3595 * error on connection. */
3597 http_connection_fail_test_impl(void *arg, int ssl)
3599 struct basic_test_data *data = arg;
3600 ev_uint16_t port = 0;
3601 struct evhttp_connection *evcon = NULL;
3602 struct evhttp_request *req = NULL;
3603 struct bufferevent *bev;
3604 struct evhttp *http = http_setup(&port, data->base, ssl ? HTTP_BIND_SSL : 0);
3606 exit_base = data->base;
3609 /* auto detect a port */
3612 bev = create_bev(data->base, -1, ssl);
3613 /* Pick an unroutable address. This administratively scoped multicast
3614 * address should do when working with TCP. */
3615 evcon = evhttp_connection_base_bufferevent_new(
3616 data->base, NULL, bev, "239.10.20.30", 80);
3620 * At this point, we want to schedule an HTTP GET request
3621 * server using our make request method.
3624 req = evhttp_request_new(http_connection_fail_done, evcon);
3627 if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/") == -1) {
3628 tt_abort_msg("Couldn't make request");
3631 event_base_dispatch(data->base);
3633 tt_int_op(test_ok, ==, 1);
3638 static void http_connection_fail_test(void *arg)
3639 { http_connection_fail_test_impl(arg, 0); }
3642 http_connection_retry_done(struct evhttp_request *req, void *arg)
3645 tt_int_op(evhttp_request_get_response_code(req), !=, HTTP_OK);
3646 if (evhttp_find_header(evhttp_request_get_input_headers(req), "Content-Type") != NULL) {
3647 tt_abort_msg("(content type)\n");
3650 tt_uint_op(evbuffer_get_length(evhttp_request_get_input_buffer(req)), ==, 0);
3654 event_base_loopexit(arg,NULL);
3661 struct evhttp *http;
3663 static struct event_base *http_make_web_server_base=NULL;
3665 http_make_web_server(evutil_socket_t fd, short what, void *arg)
3667 struct http_server *hs = (struct http_server *)arg;
3668 hs->http = http_setup(&hs->port, http_make_web_server_base, hs->ssl ? HTTP_BIND_SSL : 0);
3672 http_simple_test_impl(void *arg, int ssl, int dirty, const char *uri)
3674 struct basic_test_data *data = arg;
3675 struct evhttp_connection *evcon = NULL;
3676 struct evhttp_request *req = NULL;
3677 struct bufferevent *bev;
3678 struct http_server hs = { 0, ssl, NULL, };
3679 struct evhttp *http = http_setup(&hs.port, data->base, ssl ? HTTP_BIND_SSL : 0);
3681 exit_base = data->base;
3684 bev = create_bev(data->base, -1, ssl);
3685 #ifdef EVENT__HAVE_OPENSSL
3686 bufferevent_openssl_set_allow_dirty_shutdown(bev, dirty);
3689 evcon = evhttp_connection_base_bufferevent_new(
3690 data->base, NULL, bev, "127.0.0.1", hs.port);
3692 evhttp_connection_set_local_address(evcon, "127.0.0.1");
3694 req = evhttp_request_new(http_request_done, (void*) BASIC_REQUEST_BODY);
3697 if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, uri) == -1)
3698 tt_abort_msg("Couldn't make request");
3700 event_base_dispatch(data->base);
3701 tt_int_op(test_ok, ==, 1);
3705 evhttp_connection_free(evcon);
3709 static void http_simple_test(void *arg)
3710 { http_simple_test_impl(arg, 0, 0, "/test"); }
3711 static void http_simple_nonconformant_test(void *arg)
3712 { http_simple_test_impl(arg, 0, 0, "/test nonconformant"); }
3715 http_connection_retry_test_basic(void *arg, const char *addr, struct evdns_base *dns_base, int ssl)
3717 struct basic_test_data *data = arg;
3718 struct evhttp_connection *evcon = NULL;
3719 struct evhttp_request *req = NULL;
3720 struct timeval tv, tv_start, tv_end;
3721 struct bufferevent *bev;
3722 struct http_server hs = { 0, ssl, NULL, };
3723 struct evhttp *http = http_setup(&hs.port, data->base, ssl ? HTTP_BIND_SSL : 0);
3725 exit_base = data->base;
3728 /* auto detect a port */
3731 bev = create_bev(data->base, -1, ssl);
3732 evcon = evhttp_connection_base_bufferevent_new(data->base, dns_base, bev, addr, hs.port);
3735 tt_assert(!evhttp_connection_set_flags(evcon, EVHTTP_CON_REUSE_CONNECTED_ADDR));
3737 evhttp_connection_set_timeout(evcon, 1);
3738 /* also bind to local host */
3739 evhttp_connection_set_local_address(evcon, "127.0.0.1");
3742 * At this point, we want to schedule an HTTP GET request
3743 * server using our make request method.
3746 req = evhttp_request_new(http_connection_retry_done, data->base);
3749 /* Add the information that we care about */
3750 evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
3752 if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET,
3753 "/?arg=val") == -1) {
3754 tt_abort_msg("Couldn't make request");
3757 evutil_gettimeofday(&tv_start, NULL);
3758 event_base_dispatch(data->base);
3759 evutil_gettimeofday(&tv_end, NULL);
3760 evutil_timersub(&tv_end, &tv_start, &tv_end);
3761 tt_int_op(tv_end.tv_sec, <, 1);
3763 tt_int_op(test_ok, ==, 1);
3766 * now test the same but with retries
3769 /** Shutdown dns server, to test conn_address reusing */
3771 regress_clean_dnsserver();
3774 const struct timeval tv_timeout = { 0, 500000 };
3775 const struct timeval tv_retry = { 0, 500000 };
3776 evhttp_connection_set_timeout_tv(evcon, &tv_timeout);
3777 evhttp_connection_set_initial_retry_tv(evcon, &tv_retry);
3779 evhttp_connection_set_retries(evcon, 1);
3781 req = evhttp_request_new(http_connection_retry_done, data->base);
3784 /* Add the information that we care about */
3785 evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
3787 if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET,
3788 "/?arg=val") == -1) {
3789 tt_abort_msg("Couldn't make request");
3792 evutil_gettimeofday(&tv_start, NULL);
3793 event_base_dispatch(data->base);
3794 evutil_gettimeofday(&tv_end, NULL);
3796 /* fails fast, .5 sec to wait to retry, fails fast again. */
3797 test_timeval_diff_leq(&tv_start, &tv_end, 500, 200);
3799 tt_assert(test_ok == 1);
3802 * now test the same but with retries and give it a web server
3807 evhttp_connection_set_timeout(evcon, 1);
3808 evhttp_connection_set_retries(evcon, 3);
3810 req = evhttp_request_new(http_dispatcher_test_done, data->base);
3813 /* Add the information that we care about */
3814 evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
3816 if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET,
3817 "/?arg=val") == -1) {
3818 tt_abort_msg("Couldn't make request");
3821 /* start up a web server .2 seconds after the connection tried
3824 evutil_timerclear(&tv);
3825 tv.tv_usec = 200000;
3826 http_make_web_server_base = data->base;
3827 event_base_once(data->base, -1, EV_TIMEOUT, http_make_web_server, &hs, &tv);
3829 evutil_gettimeofday(&tv_start, NULL);
3830 event_base_dispatch(data->base);
3831 evutil_gettimeofday(&tv_end, NULL);
3832 /* We'll wait twice as long as we did last time. */
3833 test_timeval_diff_leq(&tv_start, &tv_end, 1000, 400);
3835 tt_int_op(test_ok, ==, 1);
3839 evhttp_connection_free(evcon);
3841 evhttp_free(hs.http);
3845 http_connection_retry_conn_address_test_impl(void *arg, int ssl)
3847 struct basic_test_data *data = arg;
3848 ev_uint16_t portnum = 0;
3849 struct evdns_base *dns_base = NULL;
3852 tt_assert(regress_dnsserver(data->base, &portnum, search_table));
3853 dns_base = evdns_base_new(data->base, 0/* init name servers */);
3854 tt_assert(dns_base);
3856 /* Add ourself as the only nameserver, and make sure we really are
3857 * the only nameserver. */
3858 evutil_snprintf(address, sizeof(address), "127.0.0.1:%d", portnum);
3859 evdns_base_nameserver_ip_add(dns_base, address);
3861 http_connection_retry_test_basic(arg, "localhost", dns_base, ssl);
3865 evdns_base_free(dns_base, 0);
3866 /** dnsserver will be cleaned in http_connection_retry_test_basic() */
3868 static void http_connection_retry_conn_address_test(void *arg)
3869 { http_connection_retry_conn_address_test_impl(arg, 0); }
3872 http_connection_retry_test_impl(void *arg, int ssl)
3874 http_connection_retry_test_basic(arg, "127.0.0.1", NULL, ssl);
3877 http_connection_retry_test(void *arg)
3878 { http_connection_retry_test_impl(arg, 0); }
3881 http_primitives(void *ptr)
3883 char *escaped = NULL;
3884 struct evhttp *http = NULL;
3886 escaped = evhttp_htmlescape("<script>");
3888 tt_str_op(escaped, ==, "<script>");
3891 escaped = evhttp_htmlescape("\"\'&");
3893 tt_str_op(escaped, ==, ""'&");
3895 http = evhttp_new(NULL);
3897 tt_int_op(evhttp_set_cb(http, "/test", http_basic_cb, http), ==, 0);
3898 tt_int_op(evhttp_set_cb(http, "/test", http_basic_cb, http), ==, -1);
3899 tt_int_op(evhttp_del_cb(http, "/test"), ==, 0);
3900 tt_int_op(evhttp_del_cb(http, "/test"), ==, -1);
3901 tt_int_op(evhttp_set_cb(http, "/test", http_basic_cb, http), ==, 0);
3911 http_multi_line_header_test(void *arg)
3913 struct basic_test_data *data = arg;
3914 struct bufferevent *bev= NULL;
3915 evutil_socket_t fd = EVUTIL_INVALID_SOCKET;
3916 const char *http_start_request;
3917 ev_uint16_t port = 0;
3918 struct evhttp *http = http_setup(&port, data->base, 0);
3920 exit_base = data->base;
3923 tt_ptr_op(http, !=, NULL);
3925 fd = http_connect("127.0.0.1", port);
3926 tt_assert(fd != EVUTIL_INVALID_SOCKET);
3928 /* Stupid thing to send a request */
3929 bev = bufferevent_socket_new(data->base, fd, 0);
3930 tt_ptr_op(bev, !=, NULL);
3931 bufferevent_setcb(bev, http_readcb, http_writecb,
3932 http_errorcb, data->base);
3934 http_start_request =
3935 "GET /test HTTP/1.1\r\n"
3936 "Host: somehost\r\n"
3937 "Connection: close\r\n"
3938 "X-Multi-Extra-WS: libevent \r\n"
3940 "X-Multi: aaaaaaaa\r\n"
3946 bufferevent_write(bev, http_start_request, strlen(http_start_request));
3947 found_multi = found_multi2 = 0;
3949 event_base_dispatch(data->base);
3951 tt_int_op(found_multi, ==, 1);
3952 tt_int_op(found_multi2, ==, 1);
3953 tt_int_op(test_ok, ==, 4);
3956 bufferevent_free(bev);
3958 evutil_closesocket(fd);
3964 http_request_bad(struct evhttp_request *req, void *arg)
3967 fprintf(stderr, "FAILED\n");
3972 event_base_loopexit(arg, NULL);
3976 http_negative_content_length_test(void *arg)
3978 struct basic_test_data *data = arg;
3979 ev_uint16_t port = 0;
3980 struct evhttp_connection *evcon = NULL;
3981 struct evhttp_request *req = NULL;
3982 struct evhttp *http = http_setup(&port, data->base, 0);
3986 evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port);
3990 * At this point, we want to schedule a request to the HTTP
3991 * server using our make request method.
3994 req = evhttp_request_new(http_request_bad, data->base);
3996 /* Cause the response to have a negative content-length */
3997 evhttp_add_header(evhttp_request_get_output_headers(req), "X-Negative", "makeitso");
3999 /* We give ownership of the request to the connection */
4000 if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test") == -1) {
4001 tt_abort_msg("Couldn't make request");
4004 event_base_dispatch(data->base);
4008 evhttp_connection_free(evcon);
4015 http_data_length_constraints_test_done(struct evhttp_request *req, void *arg)
4018 tt_int_op(evhttp_request_get_response_code(req), ==, HTTP_BADREQUEST);
4020 event_base_loopexit(arg, NULL);
4023 http_large_entity_test_done(struct evhttp_request *req, void *arg)
4026 tt_int_op(evhttp_request_get_response_code(req), ==, HTTP_ENTITYTOOLARGE);
4028 event_base_loopexit(arg, NULL);
4031 http_expectation_failed_done(struct evhttp_request *req, void *arg)
4034 tt_int_op(evhttp_request_get_response_code(req), ==, HTTP_EXPECTATIONFAILED);
4036 event_base_loopexit(arg, NULL);
4040 http_data_length_constraints_test_impl(void *arg, int read_on_write_error)
4042 struct basic_test_data *data = arg;
4043 ev_uint16_t port = 0;
4044 struct evhttp_connection *evcon = NULL;
4045 struct evhttp_request *req = NULL;
4046 char *long_str = NULL;
4047 const size_t continue_size = 1<<20;
4048 const size_t size = (1<<20) * 3;
4049 void (*cb)(struct evhttp_request *, void *);
4050 struct evhttp *http = http_setup(&port, data->base, 0);
4053 cb = http_failed_request_done;
4054 if (read_on_write_error)
4055 cb = http_data_length_constraints_test_done;
4057 tt_assert(continue_size < size);
4059 long_str = malloc(size);
4060 memset(long_str, 'a', size);
4061 long_str[size - 1] = '\0';
4063 TT_BLATHER(("Creating connection to :%i", port));
4064 evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port);
4067 if (read_on_write_error)
4068 tt_assert(!evhttp_connection_set_flags(evcon, EVHTTP_CON_READ_ON_WRITE_ERROR));
4070 evhttp_connection_set_local_address(evcon, "127.0.0.1");
4072 evhttp_set_max_headers_size(http, size - 1);
4073 TT_BLATHER(("Set max header size %zu", size - 1));
4075 req = evhttp_request_new(http_data_length_constraints_test_done, data->base);
4077 evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
4078 evhttp_add_header(evhttp_request_get_output_headers(req), "Longheader", long_str);
4079 TT_BLATHER(("GET /?arg=val"));
4080 if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/?arg=val") == -1) {
4081 tt_abort_msg("Couldn't make request");
4083 event_base_dispatch(data->base);
4085 req = evhttp_request_new(http_data_length_constraints_test_done, data->base);
4087 evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
4088 /* GET /?arg=verylongvalue HTTP/1.1 */
4089 TT_BLATHER(("GET %s", long_str));
4090 if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, long_str) == -1) {
4091 tt_abort_msg("Couldn't make request");
4093 event_base_dispatch(data->base);
4095 evhttp_set_max_body_size(http, size - 2);
4096 TT_BLATHER(("Set body header size %zu", size - 2));
4098 if (read_on_write_error)
4099 cb = http_large_entity_test_done;
4100 req = evhttp_request_new(cb, data->base);
4101 evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
4102 evbuffer_add_printf(evhttp_request_get_output_buffer(req), "%s", long_str);
4103 TT_BLATHER(("POST /"));
4104 if (evhttp_make_request(evcon, req, EVHTTP_REQ_POST, "/") == -1) {
4105 tt_abort_msg("Couldn't make request");
4107 event_base_dispatch(data->base);
4109 req = evhttp_request_new(http_large_entity_test_done, data->base);
4110 evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
4111 evhttp_add_header(evhttp_request_get_output_headers(req), "Expect", "100-continue");
4112 evbuffer_add_printf(evhttp_request_get_output_buffer(req), "%s", long_str);
4113 TT_BLATHER(("POST / (Expect: 100-continue, http_large_entity_test_done)"));
4114 if (evhttp_make_request(evcon, req, EVHTTP_REQ_POST, "/") == -1) {
4115 tt_abort_msg("Couldn't make request");
4117 event_base_dispatch(data->base);
4119 long_str[continue_size] = '\0';
4121 req = evhttp_request_new(http_dispatcher_test_done, data->base);
4122 evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
4123 evhttp_add_header(evhttp_request_get_output_headers(req), "Expect", "100-continue");
4124 evbuffer_add_printf(evhttp_request_get_output_buffer(req), "%s", long_str);
4125 TT_BLATHER(("POST / (Expect: 100-continue, http_dispatcher_test_done)"));
4126 if (evhttp_make_request(evcon, req, EVHTTP_REQ_POST, "/") == -1) {
4127 tt_abort_msg("Couldn't make request");
4129 event_base_dispatch(data->base);
4131 if (read_on_write_error)
4132 cb = http_expectation_failed_done;
4133 req = evhttp_request_new(cb, data->base);
4134 evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
4135 evhttp_add_header(evhttp_request_get_output_headers(req), "Expect", "101-continue");
4136 evbuffer_add_printf(evhttp_request_get_output_buffer(req), "%s", long_str);
4137 TT_BLATHER(("POST / (Expect: 101-continue)"));
4138 if (evhttp_make_request(evcon, req, EVHTTP_REQ_POST, "/") == -1) {
4139 tt_abort_msg("Couldn't make request");
4141 event_base_dispatch(data->base);
4146 evhttp_connection_free(evcon);
4152 static void http_data_length_constraints_test(void *arg)
4153 { http_data_length_constraints_test_impl(arg, 0); }
4154 static void http_read_on_write_error_test(void *arg)
4155 { http_data_length_constraints_test_impl(arg, 1); }
4158 http_lingering_close_test_impl(void *arg, int lingering)
4160 struct basic_test_data *data = arg;
4161 ev_uint16_t port = 0;
4162 struct evhttp_connection *evcon = NULL;
4163 struct evhttp_request *req = NULL;
4164 char *long_str = NULL;
4165 size_t size = (1<<20) * 3;
4166 void (*cb)(struct evhttp_request *, void *);
4167 struct evhttp *http = http_setup(&port, data->base, 0);
4172 tt_assert(!evhttp_set_flags(http, EVHTTP_SERVER_LINGERING_CLOSE));
4173 evhttp_set_max_body_size(http, size / 2);
4175 evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port);
4177 evhttp_connection_set_local_address(evcon, "127.0.0.1");
4180 * At this point, we want to schedule an HTTP GET request
4181 * server using our make request method.
4184 long_str = malloc(size);
4185 memset(long_str, 'a', size);
4186 long_str[size - 1] = '\0';
4189 cb = http_large_entity_test_done;
4191 cb = http_failed_request_done;
4192 req = evhttp_request_new(cb, data->base);
4194 evhttp_add_header(evhttp_request_get_output_headers(req), "Host", "somehost");
4195 evbuffer_add_printf(evhttp_request_get_output_buffer(req), "%s", long_str);
4196 if (evhttp_make_request(evcon, req, EVHTTP_REQ_POST, "/") == -1) {
4197 tt_abort_msg("Couldn't make request");
4199 event_base_dispatch(data->base);
4204 evhttp_connection_free(evcon);
4210 static void http_non_lingering_close_test(void *arg)
4211 { http_lingering_close_test_impl(arg, 0); }
4212 static void http_lingering_close_test(void *arg)
4213 { http_lingering_close_test_impl(arg, 1); }
4216 * Testing client reset of server chunked connections
4219 struct terminate_state {
4220 struct event_base *base;
4221 struct evhttp_request *req;
4222 struct bufferevent *bev;
4229 terminate_chunked_trickle_cb(evutil_socket_t fd, short events, void *arg)
4231 struct terminate_state *state = arg;
4232 struct evbuffer *evb;
4238 if (evhttp_request_get_connection(state->req) == NULL) {
4240 evhttp_request_free(state->req);
4241 event_base_loopexit(state->base,NULL);
4245 evb = evbuffer_new();
4246 evbuffer_add_printf(evb, "%p", evb);
4247 evhttp_send_reply_chunk(state->req, evb);
4250 if (!state->oneshot) {
4254 EVUTIL_ASSERT(state);
4255 EVUTIL_ASSERT(state->base);
4256 event_base_once(state->base, -1, EV_TIMEOUT, terminate_chunked_trickle_cb, arg, &tv);
4261 terminate_chunked_close_cb(struct evhttp_connection *evcon, void *arg)
4263 struct terminate_state *state = arg;
4264 state->gotclosecb = 1;
4266 /** TODO: though we can do this unconditionally */
4267 if (state->oneshot) {
4268 evhttp_request_free(state->req);
4270 event_base_loopexit(state->base,NULL);
4275 terminate_chunked_cb(struct evhttp_request *req, void *arg)
4277 struct terminate_state *state = arg;
4280 /* we want to know if this connection closes on us */
4281 evhttp_connection_set_closecb(
4282 evhttp_request_get_connection(req),
4283 terminate_chunked_close_cb, arg);
4287 evhttp_send_reply_start(req, HTTP_OK, "OK");
4291 event_base_once(state->base, -1, EV_TIMEOUT, terminate_chunked_trickle_cb, arg, &tv);
4295 terminate_chunked_client(evutil_socket_t fd, short event, void *arg)
4297 struct terminate_state *state = arg;
4298 bufferevent_free(state->bev);
4299 evutil_closesocket(state->fd);
4303 terminate_readcb(struct bufferevent *bev, void *arg)
4305 /* just drop the data */
4306 evbuffer_drain(bufferevent_get_input(bev), -1);
4311 http_terminate_chunked_test_impl(void *arg, int oneshot)
4313 struct basic_test_data *data = arg;
4314 struct bufferevent *bev = NULL;
4316 const char *http_request;
4317 ev_uint16_t port = 0;
4318 evutil_socket_t fd = EVUTIL_INVALID_SOCKET;
4319 struct terminate_state terminate_state;
4320 struct evhttp *http = http_setup(&port, data->base, 0);
4324 evhttp_del_cb(http, "/test");
4325 tt_assert(evhttp_set_cb(http, "/test",
4326 terminate_chunked_cb, &terminate_state) == 0);
4328 fd = http_connect("127.0.0.1", port);
4329 tt_assert(fd != EVUTIL_INVALID_SOCKET);
4331 /* Stupid thing to send a request */
4332 bev = bufferevent_socket_new(data->base, fd, 0);
4333 bufferevent_setcb(bev, terminate_readcb, http_writecb,
4334 http_errorcb, data->base);
4336 memset(&terminate_state, 0, sizeof(terminate_state));
4337 terminate_state.base = data->base;
4338 terminate_state.fd = fd;
4339 terminate_state.bev = bev;
4340 terminate_state.gotclosecb = 0;
4341 terminate_state.oneshot = oneshot;
4343 /* first half of the http request */
4345 "GET /test HTTP/1.1\r\n"
4346 "Host: some\r\n\r\n";
4348 bufferevent_write(bev, http_request, strlen(http_request));
4349 evutil_timerclear(&tv);
4351 event_base_once(data->base, -1, EV_TIMEOUT, terminate_chunked_client, &terminate_state,
4354 event_base_dispatch(data->base);
4356 if (terminate_state.gotclosecb == 0)
4361 evutil_closesocket(fd);
4366 http_terminate_chunked_test(void *arg)
4368 http_terminate_chunked_test_impl(arg, 0);
4371 http_terminate_chunked_oneshot_test(void *arg)
4373 http_terminate_chunked_test_impl(arg, 1);
4376 static struct regress_dns_server_table ipv6_search_table[] = {
4377 { "localhost", "AAAA", "::1", 0, 0 },
4378 { NULL, NULL, NULL, 0, 0 }
4382 http_ipv6_for_domain_test_impl(void *arg, int family)
4384 struct basic_test_data *data = arg;
4385 struct evdns_base *dns_base = NULL;
4386 ev_uint16_t portnum = 0;
4389 tt_assert(regress_dnsserver(data->base, &portnum, ipv6_search_table));
4391 dns_base = evdns_base_new(data->base, 0/* init name servers */);
4392 tt_assert(dns_base);
4394 /* Add ourself as the only nameserver, and make sure we really are
4395 * the only nameserver. */
4396 evutil_snprintf(address, sizeof(address), "127.0.0.1:%d", portnum);
4397 evdns_base_nameserver_ip_add(dns_base, address);
4399 http_connection_test_(arg, 0 /* not persistent */, "localhost", dns_base,
4400 1 /* ipv6 */, family, 0);
4404 evdns_base_free(dns_base, 0);
4405 regress_clean_dnsserver();
4408 http_ipv6_for_domain_test(void *arg)
4410 http_ipv6_for_domain_test_impl(arg, AF_UNSPEC);
4414 http_request_get_addr_on_close(struct evhttp_connection *evcon, void *arg)
4416 const struct sockaddr *storage;
4418 char local[] = "127.0.0.1:";
4423 storage = evhttp_connection_get_addr(evcon);
4426 evutil_format_sockaddr_port_((struct sockaddr *)storage, addrbuf, sizeof(addrbuf));
4427 tt_assert(!strncmp(addrbuf, local, sizeof(local) - 1));
4437 http_get_addr_test(void *arg)
4439 struct basic_test_data *data = arg;
4440 ev_uint16_t port = 0;
4441 struct evhttp_connection *evcon = NULL;
4442 struct evhttp_request *req = NULL;
4443 struct evhttp *http = http_setup(&port, data->base, 0);
4446 exit_base = data->base;
4448 evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port);
4450 evhttp_connection_set_closecb(evcon, http_request_get_addr_on_close, arg);
4453 * At this point, we want to schedule a request to the HTTP
4454 * server using our make request method.
4457 req = evhttp_request_new(http_request_done, (void *)BASIC_REQUEST_BODY);
4459 /* We give ownership of the request to the connection */
4460 if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test") == -1) {
4461 tt_abort_msg("Couldn't make request");
4464 event_base_dispatch(data->base);
4466 http_request_get_addr_on_close(evcon, NULL);
4470 evhttp_connection_free(evcon);
4476 http_set_family_test(void *arg)
4478 http_connection_test_(arg, 0, "127.0.0.1", NULL, 0, AF_UNSPEC, 0);
4481 http_set_family_ipv4_test(void *arg)
4483 http_connection_test_(arg, 0, "127.0.0.1", NULL, 0, AF_INET, 0);
4486 http_set_family_ipv6_test(void *arg)
4488 http_ipv6_for_domain_test_impl(arg, AF_INET6);
4492 http_write_during_read(evutil_socket_t fd, short what, void *arg)
4494 struct bufferevent *bev = arg;
4497 bufferevent_write(bev, "foobar", strlen("foobar"));
4499 evutil_timerclear(&tv);
4501 event_base_loopexit(exit_base, &tv);
4504 http_write_during_read_test_impl(void *arg, int ssl)
4506 struct basic_test_data *data = arg;
4507 ev_uint16_t port = 0;
4508 struct bufferevent *bev = NULL;
4511 const char *http_request;
4512 struct evhttp *http = http_setup(&port, data->base, ssl ? HTTP_BIND_SSL : 0);
4515 exit_base = data->base;
4517 fd = http_connect("127.0.0.1", port);
4518 tt_assert(fd != EVUTIL_INVALID_SOCKET);
4519 bev = create_bev(data->base, fd, 0);
4520 bufferevent_setcb(bev, NULL, NULL, NULL, data->base);
4521 bufferevent_disable(bev, EV_READ);
4524 "GET /large HTTP/1.1\r\n"
4525 "Host: somehost\r\n"
4528 bufferevent_write(bev, http_request, strlen(http_request));
4529 evutil_timerclear(&tv);
4531 event_base_once(data->base, -1, EV_TIMEOUT, http_write_during_read, bev, &tv);
4533 event_base_dispatch(data->base);
4537 bufferevent_free(bev);
4541 static void http_write_during_read_test(void *arg)
4542 { http_write_during_read_test_impl(arg, 0); }
4545 http_request_own_test(void *arg)
4547 struct basic_test_data *data = arg;
4548 ev_uint16_t port = 0;
4549 struct evhttp_connection *evcon = NULL;
4550 struct evhttp_request *req = NULL;
4551 struct evhttp *http = http_setup(&port, data->base, 0);
4554 exit_base = data->base;
4558 evcon = evhttp_connection_base_new(data->base, NULL, "127.0.0.1", port);
4561 req = evhttp_request_new(http_request_no_action_done, NULL);
4563 if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test") == -1) {
4564 tt_abort_msg("Couldn't make request");
4566 evhttp_request_own(req);
4568 event_base_dispatch(data->base);
4572 evhttp_connection_free(evcon);
4574 evhttp_request_free(req);
4579 static void http_run_bev_request(struct event_base *base, int port,
4580 const char *fmt, ...)
4582 struct bufferevent *bev = NULL;
4585 struct evbuffer *out;
4587 fd = http_connect("127.0.0.1", port);
4588 tt_assert(fd != EVUTIL_INVALID_SOCKET);
4590 /* Stupid thing to send a request */
4591 bev = create_bev(base, fd, 0);
4592 bufferevent_setcb(bev, http_readcb, http_writecb,
4593 http_errorcb, base);
4594 out = bufferevent_get_output(bev);
4597 evbuffer_add_vprintf(out, fmt, ap);
4600 event_base_dispatch(base);
4604 bufferevent_free(bev);
4607 http_request_extra_body_test(void *arg)
4609 struct basic_test_data *data = arg;
4610 struct bufferevent *bev = NULL;
4611 ev_uint16_t port = 0;
4613 struct evhttp *http =
4614 http_setup_gencb(&port, data->base, 0, http_timeout_cb, NULL);
4615 struct evbuffer *body = NULL;
4617 exit_base = data->base;
4620 body = evbuffer_new();
4621 for (i = 0; i < 10000; ++i)
4622 evbuffer_add_printf(body, "this is the body that HEAD should not have");
4624 http_run_bev_request(data->base, port,
4625 "HEAD /timeout HTTP/1.1\r\n"
4626 "Host: somehost\r\n"
4627 "Connection: close\r\n"
4628 "Content-Length: %i\r\n"
4630 (int)evbuffer_get_length(body),
4631 evbuffer_pullup(body, -1)
4633 tt_assert(test_ok == -2);
4635 http_run_bev_request(data->base, port,
4636 "HEAD /__gencb__ HTTP/1.1\r\n"
4637 "Host: somehost\r\n"
4638 "Connection: close\r\n"
4639 "Content-Length: %i\r\n"
4641 (int)evbuffer_get_length(body),
4642 evbuffer_pullup(body, -1)
4644 tt_assert(test_ok == -2);
4649 bufferevent_free(bev);
4651 evbuffer_free(body);
4654 #define HTTP_LEGACY(name) \
4655 { #name, run_legacy_test_fn, TT_ISOLATED|TT_LEGACY, &legacy_setup, \
4656 http_##name##_test }
4658 #define HTTP_CAST_ARG(a) ((void *)(a))
4659 #define HTTP_OFF_N(title, name, arg) \
4660 { #title, http_##name##_test, TT_ISOLATED|TT_OFF_BY_DEFAULT, &basic_setup, HTTP_CAST_ARG(arg) }
4661 #define HTTP_RET_N(title, name, test_opts, arg) \
4662 { #title, http_##name##_test, TT_ISOLATED|TT_RETRIABLE|test_opts, &basic_setup, HTTP_CAST_ARG(arg) }
4663 #define HTTP_N(title, name, test_opts, arg) \
4664 { #title, http_##name##_test, TT_ISOLATED|test_opts, &basic_setup, HTTP_CAST_ARG(arg) }
4665 #define HTTP(name) HTTP_N(name, name, 0, NULL)
4666 #define HTTPS(name) \
4667 { "https_" #name, https_##name##_test, TT_ISOLATED, &basic_setup, NULL }
4669 #ifdef EVENT__HAVE_OPENSSL
4670 static void https_basic_test(void *arg)
4671 { http_basic_test_impl(arg, 1, "GET /test HTTP/1.1"); }
4672 static void https_filter_basic_test(void *arg)
4673 { http_basic_test_impl(arg, 1 | HTTP_SSL_FILTER, "GET /test HTTP/1.1"); }
4674 static void https_incomplete_test(void *arg)
4675 { http_incomplete_test_(arg, 0, 1); }
4676 static void https_incomplete_timeout_test(void *arg)
4677 { http_incomplete_test_(arg, 1, 1); }
4678 static void https_simple_test(void *arg)
4679 { http_simple_test_impl(arg, 1, 0, "/test"); }
4680 static void https_simple_dirty_test(void *arg)
4681 { http_simple_test_impl(arg, 1, 1, "/test"); }
4682 static void https_connection_retry_conn_address_test(void *arg)
4683 { http_connection_retry_conn_address_test_impl(arg, 1); }
4684 static void https_connection_retry_test(void *arg)
4685 { http_connection_retry_test_impl(arg, 1); }
4686 static void https_chunk_out_test(void *arg)
4687 { http_chunk_out_test_impl(arg, 1); }
4688 static void https_filter_chunk_out_test(void *arg)
4689 { http_chunk_out_test_impl(arg, 1 | HTTP_SSL_FILTER); }
4690 static void https_stream_out_test(void *arg)
4691 { http_stream_out_test_impl(arg, 1); }
4692 static void https_connection_fail_test(void *arg)
4693 { http_connection_fail_test_impl(arg, 1); }
4694 static void https_write_during_read_test(void *arg)
4695 { http_write_during_read_test_impl(arg, 1); }
4696 static void https_connection_test(void *arg)
4697 { http_connection_test_(arg, 0, "127.0.0.1", NULL, 0, AF_UNSPEC, 1); }
4698 static void https_persist_connection_test(void *arg)
4699 { http_connection_test_(arg, 1, "127.0.0.1", NULL, 0, AF_UNSPEC, 1); }
4702 struct testcase_t http_testcases[] = {
4703 { "primitives", http_primitives, 0, NULL, NULL },
4704 { "base", http_base_test, TT_FORK, NULL, NULL },
4705 { "bad_headers", http_bad_header_test, 0, NULL, NULL },
4706 { "parse_query", http_parse_query_test, 0, NULL, NULL },
4707 { "parse_query_str", http_parse_query_str_test, 0, NULL, NULL },
4708 { "parse_uri", http_parse_uri_test, 0, NULL, NULL },
4709 { "parse_uri_nc", http_parse_uri_test, 0, &basic_setup, (void*)"nc" },
4710 { "uriencode", http_uriencode_test, 0, NULL, NULL },
4712 HTTP(basic_trailing_space),
4714 HTTP(simple_nonconformant),
4716 HTTP_N(cancel, cancel, 0, BASIC),
4717 HTTP_RET_N(cancel_by_host, cancel, 0, BY_HOST),
4718 HTTP_RET_N(cancel_by_host_inactive_server, cancel, TT_NO_LOGS, BY_HOST | INACTIVE_SERVER),
4719 HTTP_RET_N(cancel_by_host_no_ns, cancel, TT_NO_LOGS, BY_HOST | NO_NS),
4720 HTTP_N(cancel_inactive_server, cancel, 0, INACTIVE_SERVER),
4721 HTTP_N(cancel_by_host_no_ns_inactive_server, cancel, TT_NO_LOGS, BY_HOST | NO_NS | INACTIVE_SERVER),
4722 HTTP_OFF_N(cancel_by_host_server_timeout, cancel, BY_HOST | INACTIVE_SERVER | SERVER_TIMEOUT),
4723 HTTP_OFF_N(cancel_server_timeout, cancel, INACTIVE_SERVER | SERVER_TIMEOUT),
4724 HTTP_OFF_N(cancel_by_host_no_ns_server_timeout, cancel, BY_HOST | NO_NS | INACTIVE_SERVER | SERVER_TIMEOUT),
4725 HTTP_OFF_N(cancel_by_host_ns_timeout_server_timeout, cancel, BY_HOST | NO_NS | NS_TIMEOUT | INACTIVE_SERVER | SERVER_TIMEOUT),
4726 HTTP_RET_N(cancel_by_host_ns_timeout, cancel, TT_NO_LOGS, BY_HOST | NO_NS | NS_TIMEOUT),
4727 HTTP_RET_N(cancel_by_host_ns_timeout_inactive_server, cancel, TT_NO_LOGS, BY_HOST | NO_NS | NS_TIMEOUT | INACTIVE_SERVER),
4733 HTTP(allowed_methods),
4736 HTTP(persist_connection),
4737 HTTP(autofree_connection),
4738 HTTP(connection_async),
4739 HTTP(close_detection),
4740 HTTP(close_detection_delay),
4743 HTTP(incomplete_timeout),
4744 HTTP(terminate_chunked),
4745 HTTP(terminate_chunked_oneshot),
4750 HTTP(multi_line_header),
4751 HTTP(negative_content_length),
4756 HTTP(stream_in_cancel),
4758 HTTP(connection_fail),
4759 { "connection_retry", http_connection_retry_test, TT_ISOLATED|TT_OFF_BY_DEFAULT, &basic_setup, NULL },
4760 { "connection_retry_conn_address", http_connection_retry_conn_address_test,
4761 TT_ISOLATED|TT_OFF_BY_DEFAULT, &basic_setup, NULL },
4763 HTTP(data_length_constraints),
4764 HTTP(read_on_write_error),
4765 HTTP(non_lingering_close),
4766 HTTP(lingering_close),
4768 HTTP(ipv6_for_domain),
4772 HTTP(set_family_ipv4),
4773 HTTP(set_family_ipv6),
4775 HTTP(write_during_read),
4778 HTTP(request_extra_body),
4780 #ifdef EVENT__HAVE_OPENSSL
4782 HTTPS(filter_basic),
4784 HTTPS(simple_dirty),
4786 HTTPS(incomplete_timeout),
4787 { "https_connection_retry", https_connection_retry_test, TT_ISOLATED|TT_OFF_BY_DEFAULT, &basic_setup, NULL },
4788 { "https_connection_retry_conn_address", https_connection_retry_conn_address_test,
4789 TT_ISOLATED|TT_OFF_BY_DEFAULT, &basic_setup, NULL },
4791 HTTPS(filter_chunk_out),
4793 HTTPS(connection_fail),
4794 HTTPS(write_during_read),
4796 HTTPS(persist_connection),
4802 struct testcase_t http_iocp_testcases[] = {
4803 { "simple", http_simple_test, TT_FORK|TT_NEED_BASE|TT_ENABLE_IOCP, &basic_setup, NULL },
4804 #ifdef EVENT__HAVE_OPENSSL
4805 { "https_simple", https_simple_test, TT_FORK|TT_NEED_BASE|TT_ENABLE_IOCP, &basic_setup, NULL },