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