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