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