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