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