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