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