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