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