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