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