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