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