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