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