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