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