root/opal/mca/event/libevent2022/libevent/test/regress_http.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. http_bind
  2. http_setup
  3. http_connect
  4. evbuffer_datacmp
  5. evbuffer_contains
  6. http_readcb
  7. http_writecb
  8. http_errorcb
  9. http_basic_cb
  10. http_chunked_trickle_cb
  11. http_chunked_cb
  12. http_complete_write
  13. http_basic_test
  14. http_delay_reply
  15. http_delay_cb
  16. http_badreq_cb
  17. http_badreq_errorcb
  18. http_badreq_readcb
  19. http_badreq_successcb
  20. http_bad_request_test
  21. http_large_delay_cb
  22. http_delete_cb
  23. http_delete_test
  24. http_allowed_methods_eventcb
  25. http_allowed_methods_test
  26. _http_connection_test
  27. http_connection_test
  28. http_persist_connection_test
  29. http_connection_async_test
  30. http_request_never_call
  31. http_do_cancel
  32. http_cancel_test
  33. http_request_done
  34. http_request_expect_error
  35. http_virtual_host_test
  36. http_request_empty_done
  37. http_dispatcher_cb
  38. http_dispatcher_test_done
  39. http_dispatcher_test
  40. http_post_test
  41. http_post_cb
  42. http_postrequest_done
  43. http_put_test
  44. http_put_cb
  45. http_putrequest_done
  46. http_failure_readcb
  47. http_failure_test
  48. close_detect_done
  49. close_detect_launch
  50. close_detect_cb
  51. _http_close_detection
  52. http_close_detection_test
  53. http_close_detection_delay_test
  54. http_highport_test
  55. http_bad_header_test
  56. validate_header
  57. http_parse_query_test
  58. http_parse_uri_test
  59. http_uriencode_test
  60. http_base_test
  61. http_incomplete_readcb
  62. http_incomplete_errorcb
  63. http_incomplete_writecb
  64. _http_incomplete_test
  65. http_incomplete_test
  66. http_incomplete_timeout_test
  67. http_chunked_readcb
  68. http_chunked_errorcb
  69. http_chunked_writecb
  70. http_chunked_request_done
  71. http_chunk_out_test
  72. http_stream_out_test
  73. http_stream_in_chunk
  74. http_stream_in_done
  75. _http_stream_in_test
  76. http_stream_in_test
  77. http_stream_in_cancel_chunk
  78. http_stream_in_cancel_done
  79. http_stream_in_cancel_test
  80. http_connection_fail_done
  81. http_connection_fail_test
  82. http_connection_retry_done
  83. http_make_web_server
  84. http_connection_retry_test
  85. http_primitives
  86. http_multi_line_header_test
  87. http_request_bad
  88. http_negative_content_length_test
  89. http_data_length_constraints_test_done
  90. http_large_entity_test_done
  91. http_data_length_constraints_test
  92. terminate_chunked_trickle_cb
  93. terminate_chunked_close_cb
  94. terminate_chunked_cb
  95. terminate_chunked_client
  96. terminate_readcb
  97. http_terminate_chunked_test

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

/* [<][>][^][v][top][bottom][index][help] */