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