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