1 1.5 christos /* $NetBSD: http.c,v 1.5 2021/04/07 03:36:48 christos Exp $ */ 2 1.5 christos 3 1.1 plunky /* 4 1.2 christos * Copyright (c) 2002-2007 Niels Provos <provos (at) citi.umich.edu> 5 1.2 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.1 plunky 30 1.2 christos #include "event2/event-config.h" 31 1.2 christos #include <sys/cdefs.h> 32 1.5 christos __RCSID("$NetBSD: http.c,v 1.5 2021/04/07 03:36:48 christos Exp $"); 33 1.4 christos #include "evconfig-private.h" 34 1.1 plunky 35 1.4 christos #ifdef EVENT__HAVE_SYS_PARAM_H 36 1.1 plunky #include <sys/param.h> 37 1.1 plunky #endif 38 1.4 christos #ifdef EVENT__HAVE_SYS_TYPES_H 39 1.1 plunky #include <sys/types.h> 40 1.1 plunky #endif 41 1.1 plunky 42 1.4 christos #ifdef HAVE_SYS_IOCCOM_H 43 1.4 christos #include <sys/ioccom.h> 44 1.4 christos #endif 45 1.4 christos #ifdef EVENT__HAVE_SYS_RESOURCE_H 46 1.4 christos #include <sys/resource.h> 47 1.4 christos #endif 48 1.4 christos #ifdef EVENT__HAVE_SYS_TIME_H 49 1.1 plunky #include <sys/time.h> 50 1.1 plunky #endif 51 1.4 christos #ifdef EVENT__HAVE_SYS_WAIT_H 52 1.4 christos #include <sys/wait.h> 53 1.1 plunky #endif 54 1.1 plunky 55 1.4 christos #ifndef _WIN32 56 1.1 plunky #include <sys/socket.h> 57 1.1 plunky #include <sys/stat.h> 58 1.5 christos #else /* _WIN32 */ 59 1.2 christos #include <winsock2.h> 60 1.2 christos #include <ws2tcpip.h> 61 1.5 christos #endif /* _WIN32 */ 62 1.5 christos 63 1.5 christos #ifdef EVENT__HAVE_SYS_UN_H 64 1.5 christos #include <sys/un.h> 65 1.5 christos #endif 66 1.5 christos #ifdef EVENT__HAVE_AFUNIX_H 67 1.5 christos #include <afunix.h> 68 1.1 plunky #endif 69 1.1 plunky 70 1.1 plunky #include <sys/queue.h> 71 1.1 plunky 72 1.4 christos #ifdef EVENT__HAVE_NETINET_IN_H 73 1.1 plunky #include <netinet/in.h> 74 1.2 christos #endif 75 1.4 christos #ifdef EVENT__HAVE_ARPA_INET_H 76 1.2 christos #include <arpa/inet.h> 77 1.2 christos #endif 78 1.4 christos #ifdef EVENT__HAVE_NETDB_H 79 1.1 plunky #include <netdb.h> 80 1.1 plunky #endif 81 1.1 plunky 82 1.4 christos #ifdef _WIN32 83 1.1 plunky #include <winsock2.h> 84 1.1 plunky #endif 85 1.1 plunky 86 1.1 plunky #include <errno.h> 87 1.1 plunky #include <stdio.h> 88 1.1 plunky #include <stdlib.h> 89 1.1 plunky #include <string.h> 90 1.4 christos #ifndef _WIN32 91 1.1 plunky #include <syslog.h> 92 1.5 christos #endif /* !_WIN32 */ 93 1.1 plunky #include <signal.h> 94 1.4 christos #ifdef EVENT__HAVE_UNISTD_H 95 1.1 plunky #include <unistd.h> 96 1.1 plunky #endif 97 1.4 christos #ifdef EVENT__HAVE_FCNTL_H 98 1.1 plunky #include <fcntl.h> 99 1.1 plunky #endif 100 1.1 plunky 101 1.1 plunky #undef timeout_pending 102 1.1 plunky #undef timeout_initialized 103 1.1 plunky 104 1.1 plunky #include "strlcpy-internal.h" 105 1.2 christos #include "event2/http.h" 106 1.2 christos #include "event2/event.h" 107 1.2 christos #include "event2/buffer.h" 108 1.2 christos #include "event2/bufferevent.h" 109 1.2 christos #include "event2/http_struct.h" 110 1.2 christos #include "event2/http_compat.h" 111 1.2 christos #include "event2/util.h" 112 1.2 christos #include "event2/listener.h" 113 1.2 christos #include "log-internal.h" 114 1.2 christos #include "util-internal.h" 115 1.1 plunky #include "http-internal.h" 116 1.2 christos #include "mm-internal.h" 117 1.2 christos #include "bufferevent-internal.h" 118 1.1 plunky 119 1.4 christos #ifndef EVENT__HAVE_GETNAMEINFO 120 1.1 plunky #define NI_MAXSERV 32 121 1.1 plunky #define NI_MAXHOST 1025 122 1.1 plunky 123 1.2 christos #ifndef NI_NUMERICHOST 124 1.1 plunky #define NI_NUMERICHOST 1 125 1.2 christos #endif 126 1.2 christos 127 1.2 christos #ifndef NI_NUMERICSERV 128 1.1 plunky #define NI_NUMERICSERV 2 129 1.2 christos #endif 130 1.1 plunky 131 1.1 plunky static int 132 1.2 christos fake_getnameinfo(const struct sockaddr *sa, size_t salen, char *host, 133 1.1 plunky size_t hostlen, char *serv, size_t servlen, int flags) 134 1.1 plunky { 135 1.2 christos struct sockaddr_in *sin = (struct sockaddr_in *)sa; 136 1.1 plunky 137 1.2 christos if (serv != NULL) { 138 1.2 christos char tmpserv[16]; 139 1.2 christos evutil_snprintf(tmpserv, sizeof(tmpserv), 140 1.2 christos "%d", ntohs(sin->sin_port)); 141 1.2 christos if (strlcpy(serv, tmpserv, servlen) >= servlen) 142 1.1 plunky return (-1); 143 1.1 plunky } 144 1.2 christos 145 1.2 christos if (host != NULL) { 146 1.2 christos if (flags & NI_NUMERICHOST) { 147 1.2 christos if (strlcpy(host, inet_ntoa(sin->sin_addr), 148 1.2 christos hostlen) >= hostlen) 149 1.2 christos return (-1); 150 1.2 christos else 151 1.2 christos return (0); 152 1.2 christos } else { 153 1.2 christos struct hostent *hp; 154 1.2 christos hp = gethostbyaddr((char *)&sin->sin_addr, 155 1.2 christos sizeof(struct in_addr), AF_INET); 156 1.2 christos if (hp == NULL) 157 1.2 christos return (-2); 158 1.2 christos 159 1.2 christos if (strlcpy(host, hp->h_name, hostlen) >= hostlen) 160 1.2 christos return (-1); 161 1.2 christos else 162 1.2 christos return (0); 163 1.2 christos } 164 1.1 plunky } 165 1.1 plunky return (0); 166 1.1 plunky } 167 1.2 christos 168 1.1 plunky #endif 169 1.1 plunky 170 1.2 christos #define REQ_VERSION_BEFORE(req, major_v, minor_v) \ 171 1.2 christos ((req)->major < (major_v) || \ 172 1.2 christos ((req)->major == (major_v) && (req)->minor < (minor_v))) 173 1.2 christos 174 1.2 christos #define REQ_VERSION_ATLEAST(req, major_v, minor_v) \ 175 1.2 christos ((req)->major > (major_v) || \ 176 1.2 christos ((req)->major == (major_v) && (req)->minor >= (minor_v))) 177 1.2 christos 178 1.1 plunky #ifndef MIN 179 1.1 plunky #define MIN(a,b) (((a)<(b))?(a):(b)) 180 1.1 plunky #endif 181 1.1 plunky 182 1.1 plunky extern int debug; 183 1.1 plunky 184 1.5 christos static evutil_socket_t create_bind_socket_nonblock(struct evutil_addrinfo *, int reuse); 185 1.2 christos static evutil_socket_t bind_socket(const char *, ev_uint16_t, int reuse); 186 1.2 christos static void name_from_addr(struct sockaddr *, ev_socklen_t, char **, char **); 187 1.5 christos static struct evhttp_uri *evhttp_uri_parse_authority(char *source_uri); 188 1.1 plunky static int evhttp_associate_new_request_with_connection( 189 1.1 plunky struct evhttp_connection *evcon); 190 1.1 plunky static void evhttp_connection_start_detectclose( 191 1.1 plunky struct evhttp_connection *evcon); 192 1.1 plunky static void evhttp_connection_stop_detectclose( 193 1.1 plunky struct evhttp_connection *evcon); 194 1.1 plunky static void evhttp_request_dispatch(struct evhttp_connection* evcon); 195 1.1 plunky static void evhttp_read_firstline(struct evhttp_connection *evcon, 196 1.1 plunky struct evhttp_request *req); 197 1.1 plunky static void evhttp_read_header(struct evhttp_connection *evcon, 198 1.1 plunky struct evhttp_request *req); 199 1.1 plunky static int evhttp_add_header_internal(struct evkeyvalq *headers, 200 1.1 plunky const char *key, const char *value); 201 1.2 christos static const char *evhttp_response_phrase_internal(int code); 202 1.2 christos static void evhttp_get_request(struct evhttp *, evutil_socket_t, struct sockaddr *, ev_socklen_t); 203 1.2 christos static void evhttp_write_buffer(struct evhttp_connection *, 204 1.2 christos void (*)(struct evhttp_connection *, void *), void *); 205 1.2 christos static void evhttp_make_header(struct evhttp_connection *, struct evhttp_request *); 206 1.2 christos 207 1.2 christos /* callbacks for bufferevent */ 208 1.2 christos static void evhttp_read_cb(struct bufferevent *, void *); 209 1.2 christos static void evhttp_write_cb(struct bufferevent *, void *); 210 1.2 christos static void evhttp_error_cb(struct bufferevent *bufev, short what, void *arg); 211 1.2 christos static int evhttp_find_vhost(struct evhttp *http, struct evhttp **outhttp, 212 1.2 christos const char *hostname); 213 1.1 plunky 214 1.4 christos #ifndef EVENT__HAVE_STRSEP 215 1.1 plunky /* strsep replacement for platforms that lack it. Only works if 216 1.1 plunky * del is one character long. */ 217 1.1 plunky static char * 218 1.1 plunky strsep(char **s, const char *del) 219 1.1 plunky { 220 1.1 plunky char *d, *tok; 221 1.2 christos EVUTIL_ASSERT(strlen(del) == 1); 222 1.1 plunky if (!s || !*s) 223 1.1 plunky return NULL; 224 1.1 plunky tok = *s; 225 1.1 plunky d = strstr(tok, del); 226 1.1 plunky if (d) { 227 1.1 plunky *d = '\0'; 228 1.1 plunky *s = d + 1; 229 1.1 plunky } else 230 1.1 plunky *s = NULL; 231 1.1 plunky return tok; 232 1.1 plunky } 233 1.1 plunky #endif 234 1.1 plunky 235 1.2 christos static size_t 236 1.2 christos html_replace(const char ch, const char **escaped) 237 1.1 plunky { 238 1.1 plunky switch (ch) { 239 1.1 plunky case '<': 240 1.2 christos *escaped = "<"; 241 1.2 christos return 4; 242 1.1 plunky case '>': 243 1.2 christos *escaped = ">"; 244 1.2 christos return 4; 245 1.1 plunky case '"': 246 1.2 christos *escaped = """; 247 1.2 christos return 6; 248 1.1 plunky case '\'': 249 1.2 christos *escaped = "'"; 250 1.2 christos return 6; 251 1.1 plunky case '&': 252 1.2 christos *escaped = "&"; 253 1.2 christos return 5; 254 1.1 plunky default: 255 1.1 plunky break; 256 1.1 plunky } 257 1.1 plunky 258 1.2 christos return 1; 259 1.1 plunky } 260 1.1 plunky 261 1.1 plunky /* 262 1.1 plunky * Replaces <, >, ", ' and & with <, >, ", 263 1.1 plunky * ' and & correspondingly. 264 1.1 plunky * 265 1.1 plunky * The returned string needs to be freed by the caller. 266 1.1 plunky */ 267 1.1 plunky 268 1.1 plunky char * 269 1.1 plunky evhttp_htmlescape(const char *html) 270 1.1 plunky { 271 1.2 christos size_t i; 272 1.2 christos size_t new_size = 0, old_size = 0; 273 1.1 plunky char *escaped_html, *p; 274 1.2 christos 275 1.2 christos if (html == NULL) 276 1.2 christos return (NULL); 277 1.2 christos 278 1.2 christos old_size = strlen(html); 279 1.2 christos for (i = 0; i < old_size; ++i) { 280 1.2 christos const char *replaced = NULL; 281 1.2 christos const size_t replace_size = html_replace(html[i], &replaced); 282 1.2 christos if (replace_size > EV_SIZE_MAX - new_size) { 283 1.2 christos event_warn("%s: html_replace overflow", __func__); 284 1.2 christos return (NULL); 285 1.2 christos } 286 1.2 christos new_size += replace_size; 287 1.2 christos } 288 1.2 christos 289 1.2 christos if (new_size == EV_SIZE_MAX) 290 1.2 christos return (NULL); 291 1.2 christos p = escaped_html = mm_malloc(new_size + 1); 292 1.2 christos if (escaped_html == NULL) { 293 1.2 christos event_warn("%s: malloc(%lu)", __func__, 294 1.2 christos (unsigned long)(new_size + 1)); 295 1.2 christos return (NULL); 296 1.2 christos } 297 1.1 plunky for (i = 0; i < old_size; ++i) { 298 1.2 christos const char *replaced = &html[i]; 299 1.2 christos const size_t len = html_replace(html[i], &replaced); 300 1.2 christos memcpy(p, replaced, len); 301 1.2 christos p += len; 302 1.1 plunky } 303 1.1 plunky 304 1.1 plunky *p = '\0'; 305 1.1 plunky 306 1.1 plunky return (escaped_html); 307 1.1 plunky } 308 1.1 plunky 309 1.2 christos /** Given an evhttp_cmd_type, returns a constant string containing the 310 1.2 christos * equivalent HTTP command, or NULL if the evhttp_command_type is 311 1.2 christos * unrecognized. */ 312 1.1 plunky static const char * 313 1.1 plunky evhttp_method(enum evhttp_cmd_type type) 314 1.1 plunky { 315 1.1 plunky const char *method; 316 1.1 plunky 317 1.1 plunky switch (type) { 318 1.1 plunky case EVHTTP_REQ_GET: 319 1.1 plunky method = "GET"; 320 1.1 plunky break; 321 1.1 plunky case EVHTTP_REQ_POST: 322 1.1 plunky method = "POST"; 323 1.1 plunky break; 324 1.1 plunky case EVHTTP_REQ_HEAD: 325 1.1 plunky method = "HEAD"; 326 1.1 plunky break; 327 1.2 christos case EVHTTP_REQ_PUT: 328 1.2 christos method = "PUT"; 329 1.2 christos break; 330 1.2 christos case EVHTTP_REQ_DELETE: 331 1.2 christos method = "DELETE"; 332 1.2 christos break; 333 1.2 christos case EVHTTP_REQ_OPTIONS: 334 1.2 christos method = "OPTIONS"; 335 1.2 christos break; 336 1.2 christos case EVHTTP_REQ_TRACE: 337 1.2 christos method = "TRACE"; 338 1.2 christos break; 339 1.2 christos case EVHTTP_REQ_CONNECT: 340 1.2 christos method = "CONNECT"; 341 1.2 christos break; 342 1.2 christos case EVHTTP_REQ_PATCH: 343 1.2 christos method = "PATCH"; 344 1.2 christos break; 345 1.1 plunky default: 346 1.1 plunky method = NULL; 347 1.1 plunky break; 348 1.1 plunky } 349 1.1 plunky 350 1.1 plunky return (method); 351 1.1 plunky } 352 1.1 plunky 353 1.2 christos /** 354 1.2 christos * Determines if a response should have a body. 355 1.2 christos * Follows the rules in RFC 2616 section 4.3. 356 1.2 christos * @return 1 if the response MUST have a body; 0 if the response MUST NOT have 357 1.2 christos * a body. 358 1.2 christos */ 359 1.2 christos static int 360 1.2 christos evhttp_response_needs_body(struct evhttp_request *req) 361 1.2 christos { 362 1.2 christos return (req->response_code != HTTP_NOCONTENT && 363 1.2 christos req->response_code != HTTP_NOTMODIFIED && 364 1.2 christos (req->response_code < 100 || req->response_code >= 200) && 365 1.5 christos req->type != EVHTTP_REQ_CONNECT && 366 1.2 christos req->type != EVHTTP_REQ_HEAD); 367 1.2 christos } 368 1.2 christos 369 1.2 christos /** Helper: called after we've added some data to an evcon's bufferevent's 370 1.2 christos * output buffer. Sets the evconn's writing-is-done callback, and puts 371 1.2 christos * the bufferevent into writing mode. 372 1.2 christos */ 373 1.2 christos static void 374 1.1 plunky evhttp_write_buffer(struct evhttp_connection *evcon, 375 1.1 plunky void (*cb)(struct evhttp_connection *, void *), void *arg) 376 1.1 plunky { 377 1.1 plunky event_debug(("%s: preparing to write buffer\n", __func__)); 378 1.1 plunky 379 1.1 plunky /* Set call back */ 380 1.1 plunky evcon->cb = cb; 381 1.1 plunky evcon->cb_arg = arg; 382 1.1 plunky 383 1.2 christos /* Disable the read callback: we don't actually care about data; 384 1.5 christos * we only care about close detection. (We don't disable reading -- 385 1.5 christos * EV_READ, since we *do* want to learn about any close events.) */ 386 1.2 christos bufferevent_setcb(evcon->bufev, 387 1.2 christos NULL, /*read*/ 388 1.2 christos evhttp_write_cb, 389 1.2 christos evhttp_error_cb, 390 1.2 christos evcon); 391 1.3 spz 392 1.5 christos bufferevent_enable(evcon->bufev, EV_READ|EV_WRITE); 393 1.2 christos } 394 1.2 christos 395 1.2 christos static void 396 1.2 christos evhttp_send_continue_done(struct evhttp_connection *evcon, void *arg) 397 1.2 christos { 398 1.2 christos bufferevent_disable(evcon->bufev, EV_WRITE); 399 1.2 christos } 400 1.2 christos 401 1.2 christos static void 402 1.2 christos evhttp_send_continue(struct evhttp_connection *evcon, 403 1.2 christos struct evhttp_request *req) 404 1.2 christos { 405 1.2 christos bufferevent_enable(evcon->bufev, EV_WRITE); 406 1.2 christos evbuffer_add_printf(bufferevent_get_output(evcon->bufev), 407 1.2 christos "HTTP/%d.%d 100 Continue\r\n\r\n", 408 1.2 christos req->major, req->minor); 409 1.2 christos evcon->cb = evhttp_send_continue_done; 410 1.2 christos evcon->cb_arg = NULL; 411 1.2 christos bufferevent_setcb(evcon->bufev, 412 1.2 christos evhttp_read_cb, 413 1.2 christos evhttp_write_cb, 414 1.2 christos evhttp_error_cb, 415 1.2 christos evcon); 416 1.1 plunky } 417 1.1 plunky 418 1.2 christos /** Helper: returns true iff evconn is in any connected state. */ 419 1.1 plunky static int 420 1.1 plunky evhttp_connected(struct evhttp_connection *evcon) 421 1.1 plunky { 422 1.1 plunky switch (evcon->state) { 423 1.1 plunky case EVCON_DISCONNECTED: 424 1.1 plunky case EVCON_CONNECTING: 425 1.1 plunky return (0); 426 1.1 plunky case EVCON_IDLE: 427 1.1 plunky case EVCON_READING_FIRSTLINE: 428 1.1 plunky case EVCON_READING_HEADERS: 429 1.1 plunky case EVCON_READING_BODY: 430 1.1 plunky case EVCON_READING_TRAILER: 431 1.1 plunky case EVCON_WRITING: 432 1.1 plunky default: 433 1.1 plunky return (1); 434 1.1 plunky } 435 1.1 plunky } 436 1.1 plunky 437 1.2 christos /* Create the headers needed for an outgoing HTTP request, adds them to 438 1.2 christos * the request's header list, and writes the request line to the 439 1.2 christos * connection's output buffer. 440 1.1 plunky */ 441 1.1 plunky static void 442 1.1 plunky evhttp_make_header_request(struct evhttp_connection *evcon, 443 1.1 plunky struct evhttp_request *req) 444 1.1 plunky { 445 1.1 plunky const char *method; 446 1.2 christos 447 1.1 plunky evhttp_remove_header(req->output_headers, "Proxy-Connection"); 448 1.1 plunky 449 1.1 plunky /* Generate request line */ 450 1.4 christos if (!(method = evhttp_method(req->type))) { 451 1.4 christos method = "NULL"; 452 1.4 christos } 453 1.4 christos 454 1.2 christos evbuffer_add_printf(bufferevent_get_output(evcon->bufev), 455 1.2 christos "%s %s HTTP/%d.%d\r\n", 456 1.1 plunky method, req->uri, req->major, req->minor); 457 1.1 plunky 458 1.2 christos /* Add the content length on a post or put request if missing */ 459 1.2 christos if ((req->type == EVHTTP_REQ_POST || req->type == EVHTTP_REQ_PUT) && 460 1.1 plunky evhttp_find_header(req->output_headers, "Content-Length") == NULL){ 461 1.2 christos char size[22]; 462 1.2 christos evutil_snprintf(size, sizeof(size), EV_SIZE_FMT, 463 1.2 christos EV_SIZE_ARG(evbuffer_get_length(req->output_buffer))); 464 1.1 plunky evhttp_add_header(req->output_headers, "Content-Length", size); 465 1.1 plunky } 466 1.1 plunky } 467 1.1 plunky 468 1.2 christos /** Return true if the list of headers in 'headers', intepreted with respect 469 1.2 christos * to flags, means that we should send a "connection: close" when the request 470 1.2 christos * is done. */ 471 1.1 plunky static int 472 1.1 plunky evhttp_is_connection_close(int flags, struct evkeyvalq* headers) 473 1.1 plunky { 474 1.1 plunky if (flags & EVHTTP_PROXY_REQUEST) { 475 1.1 plunky /* proxy connection */ 476 1.1 plunky const char *connection = evhttp_find_header(headers, "Proxy-Connection"); 477 1.2 christos return (connection == NULL || evutil_ascii_strcasecmp(connection, "keep-alive") != 0); 478 1.1 plunky } else { 479 1.1 plunky const char *connection = evhttp_find_header(headers, "Connection"); 480 1.2 christos return (connection != NULL && evutil_ascii_strcasecmp(connection, "close") == 0); 481 1.1 plunky } 482 1.1 plunky } 483 1.4 christos static int 484 1.4 christos evhttp_is_request_connection_close(struct evhttp_request *req) 485 1.4 christos { 486 1.5 christos if (req->type == EVHTTP_REQ_CONNECT) 487 1.5 christos return 0; 488 1.5 christos 489 1.4 christos return 490 1.4 christos evhttp_is_connection_close(req->flags, req->input_headers) || 491 1.4 christos evhttp_is_connection_close(req->flags, req->output_headers); 492 1.4 christos } 493 1.1 plunky 494 1.2 christos /* Return true iff 'headers' contains 'Connection: keep-alive' */ 495 1.1 plunky static int 496 1.1 plunky evhttp_is_connection_keepalive(struct evkeyvalq* headers) 497 1.1 plunky { 498 1.1 plunky const char *connection = evhttp_find_header(headers, "Connection"); 499 1.2 christos return (connection != NULL 500 1.2 christos && evutil_ascii_strncasecmp(connection, "keep-alive", 10) == 0); 501 1.1 plunky } 502 1.1 plunky 503 1.2 christos /* Add a correct "Date" header to headers, unless it already has one. */ 504 1.1 plunky static void 505 1.1 plunky evhttp_maybe_add_date_header(struct evkeyvalq *headers) 506 1.1 plunky { 507 1.1 plunky if (evhttp_find_header(headers, "Date") == NULL) { 508 1.1 plunky char date[50]; 509 1.4 christos if (sizeof(date) - evutil_date_rfc1123(date, sizeof(date), NULL) > 0) { 510 1.1 plunky evhttp_add_header(headers, "Date", date); 511 1.1 plunky } 512 1.1 plunky } 513 1.1 plunky } 514 1.1 plunky 515 1.2 christos /* Add a "Content-Length" header with value 'content_length' to headers, 516 1.2 christos * unless it already has a content-length or transfer-encoding header. */ 517 1.1 plunky static void 518 1.1 plunky evhttp_maybe_add_content_length_header(struct evkeyvalq *headers, 519 1.2 christos size_t content_length) 520 1.1 plunky { 521 1.1 plunky if (evhttp_find_header(headers, "Transfer-Encoding") == NULL && 522 1.1 plunky evhttp_find_header(headers, "Content-Length") == NULL) { 523 1.2 christos char len[22]; 524 1.2 christos evutil_snprintf(len, sizeof(len), EV_SIZE_FMT, 525 1.2 christos EV_SIZE_ARG(content_length)); 526 1.1 plunky evhttp_add_header(headers, "Content-Length", len); 527 1.1 plunky } 528 1.1 plunky } 529 1.1 plunky 530 1.1 plunky /* 531 1.2 christos * Create the headers needed for an HTTP reply in req->output_headers, 532 1.2 christos * and write the first HTTP response for req line to evcon. 533 1.1 plunky */ 534 1.1 plunky static void 535 1.1 plunky evhttp_make_header_response(struct evhttp_connection *evcon, 536 1.1 plunky struct evhttp_request *req) 537 1.1 plunky { 538 1.1 plunky int is_keepalive = evhttp_is_connection_keepalive(req->input_headers); 539 1.2 christos evbuffer_add_printf(bufferevent_get_output(evcon->bufev), 540 1.2 christos "HTTP/%d.%d %d %s\r\n", 541 1.1 plunky req->major, req->minor, req->response_code, 542 1.1 plunky req->response_code_line); 543 1.1 plunky 544 1.1 plunky if (req->major == 1) { 545 1.2 christos if (req->minor >= 1) 546 1.1 plunky evhttp_maybe_add_date_header(req->output_headers); 547 1.1 plunky 548 1.1 plunky /* 549 1.1 plunky * if the protocol is 1.0; and the connection was keep-alive 550 1.1 plunky * we need to add a keep-alive header, too. 551 1.1 plunky */ 552 1.1 plunky if (req->minor == 0 && is_keepalive) 553 1.1 plunky evhttp_add_header(req->output_headers, 554 1.1 plunky "Connection", "keep-alive"); 555 1.1 plunky 556 1.2 christos if ((req->minor >= 1 || is_keepalive) && 557 1.2 christos evhttp_response_needs_body(req)) { 558 1.2 christos /* 559 1.1 plunky * we need to add the content length if the 560 1.1 plunky * user did not give it, this is required for 561 1.1 plunky * persistent connections to work. 562 1.1 plunky */ 563 1.1 plunky evhttp_maybe_add_content_length_header( 564 1.1 plunky req->output_headers, 565 1.2 christos evbuffer_get_length(req->output_buffer)); 566 1.1 plunky } 567 1.1 plunky } 568 1.1 plunky 569 1.1 plunky /* Potentially add headers for unidentified content. */ 570 1.2 christos if (evhttp_response_needs_body(req)) { 571 1.1 plunky if (evhttp_find_header(req->output_headers, 572 1.4 christos "Content-Type") == NULL 573 1.4 christos && evcon->http_server->default_content_type) { 574 1.1 plunky evhttp_add_header(req->output_headers, 575 1.4 christos "Content-Type", 576 1.4 christos evcon->http_server->default_content_type); 577 1.1 plunky } 578 1.1 plunky } 579 1.1 plunky 580 1.1 plunky /* if the request asked for a close, we send a close, too */ 581 1.1 plunky if (evhttp_is_connection_close(req->flags, req->input_headers)) { 582 1.1 plunky evhttp_remove_header(req->output_headers, "Connection"); 583 1.1 plunky if (!(req->flags & EVHTTP_PROXY_REQUEST)) 584 1.1 plunky evhttp_add_header(req->output_headers, "Connection", "close"); 585 1.1 plunky evhttp_remove_header(req->output_headers, "Proxy-Connection"); 586 1.1 plunky } 587 1.1 plunky } 588 1.1 plunky 589 1.4 christos enum expect { NO, CONTINUE, OTHER }; 590 1.4 christos static enum expect evhttp_have_expect(struct evhttp_request *req, int input) 591 1.4 christos { 592 1.4 christos const char *expect; 593 1.4 christos struct evkeyvalq *h = input ? req->input_headers : req->output_headers; 594 1.4 christos 595 1.4 christos if (!(req->kind == EVHTTP_REQUEST) || !REQ_VERSION_ATLEAST(req, 1, 1)) 596 1.4 christos return NO; 597 1.4 christos 598 1.4 christos expect = evhttp_find_header(h, "Expect"); 599 1.4 christos if (!expect) 600 1.4 christos return NO; 601 1.4 christos 602 1.4 christos return !evutil_ascii_strcasecmp(expect, "100-continue") ? CONTINUE : OTHER; 603 1.4 christos } 604 1.4 christos 605 1.4 christos 606 1.2 christos /** Generate all headers appropriate for sending the http request in req (or 607 1.2 christos * the response, if we're sending a response), and write them to evcon's 608 1.2 christos * bufferevent. Also writes all data from req->output_buffer */ 609 1.2 christos static void 610 1.1 plunky evhttp_make_header(struct evhttp_connection *evcon, struct evhttp_request *req) 611 1.1 plunky { 612 1.1 plunky struct evkeyval *header; 613 1.2 christos struct evbuffer *output = bufferevent_get_output(evcon->bufev); 614 1.1 plunky 615 1.1 plunky /* 616 1.1 plunky * Depending if this is a HTTP request or response, we might need to 617 1.1 plunky * add some new headers or remove existing headers. 618 1.1 plunky */ 619 1.1 plunky if (req->kind == EVHTTP_REQUEST) { 620 1.1 plunky evhttp_make_header_request(evcon, req); 621 1.1 plunky } else { 622 1.1 plunky evhttp_make_header_response(evcon, req); 623 1.1 plunky } 624 1.1 plunky 625 1.1 plunky TAILQ_FOREACH(header, req->output_headers, next) { 626 1.2 christos evbuffer_add_printf(output, "%s: %s\r\n", 627 1.1 plunky header->key, header->value); 628 1.1 plunky } 629 1.2 christos evbuffer_add(output, "\r\n", 2); 630 1.1 plunky 631 1.4 christos if (evhttp_have_expect(req, 0) != CONTINUE && 632 1.4 christos evbuffer_get_length(req->output_buffer)) { 633 1.1 plunky /* 634 1.1 plunky * For a request, we add the POST data, for a reply, this 635 1.1 plunky * is the regular data. 636 1.1 plunky */ 637 1.2 christos evbuffer_add_buffer(output, req->output_buffer); 638 1.1 plunky } 639 1.1 plunky } 640 1.1 plunky 641 1.2 christos void 642 1.2 christos evhttp_connection_set_max_headers_size(struct evhttp_connection *evcon, 643 1.2 christos ev_ssize_t new_max_headers_size) 644 1.2 christos { 645 1.2 christos if (new_max_headers_size<0) 646 1.2 christos evcon->max_headers_size = EV_SIZE_MAX; 647 1.2 christos else 648 1.2 christos evcon->max_headers_size = new_max_headers_size; 649 1.2 christos } 650 1.2 christos void 651 1.2 christos evhttp_connection_set_max_body_size(struct evhttp_connection* evcon, 652 1.2 christos ev_ssize_t new_max_body_size) 653 1.1 plunky { 654 1.2 christos if (new_max_body_size<0) 655 1.2 christos evcon->max_body_size = EV_UINT64_MAX; 656 1.2 christos else 657 1.2 christos evcon->max_body_size = new_max_body_size; 658 1.1 plunky } 659 1.1 plunky 660 1.1 plunky static int 661 1.1 plunky evhttp_connection_incoming_fail(struct evhttp_request *req, 662 1.4 christos enum evhttp_request_error error) 663 1.1 plunky { 664 1.1 plunky switch (error) { 665 1.4 christos case EVREQ_HTTP_DATA_TOO_LONG: 666 1.4 christos req->response_code = HTTP_ENTITYTOOLARGE; 667 1.4 christos break; 668 1.4 christos default: 669 1.4 christos req->response_code = HTTP_BADREQUEST; 670 1.4 christos } 671 1.4 christos 672 1.4 christos switch (error) { 673 1.4 christos case EVREQ_HTTP_TIMEOUT: 674 1.4 christos case EVREQ_HTTP_EOF: 675 1.2 christos /* 676 1.1 plunky * these are cases in which we probably should just 677 1.1 plunky * close the connection and not send a reply. this 678 1.1 plunky * case may happen when a browser keeps a persistent 679 1.2 christos * connection open and we timeout on the read. when 680 1.2 christos * the request is still being used for sending, we 681 1.2 christos * need to disassociated it from the connection here. 682 1.1 plunky */ 683 1.2 christos if (!req->userdone) { 684 1.2 christos /* remove it so that it will not be freed */ 685 1.2 christos TAILQ_REMOVE(&req->evcon->requests, req, next); 686 1.2 christos /* indicate that this request no longer has a 687 1.2 christos * connection object 688 1.2 christos */ 689 1.2 christos req->evcon = NULL; 690 1.2 christos } 691 1.1 plunky return (-1); 692 1.4 christos case EVREQ_HTTP_INVALID_HEADER: 693 1.4 christos case EVREQ_HTTP_BUFFER_ERROR: 694 1.4 christos case EVREQ_HTTP_REQUEST_CANCEL: 695 1.4 christos case EVREQ_HTTP_DATA_TOO_LONG: 696 1.1 plunky default: /* xxx: probably should just error on default */ 697 1.1 plunky /* the callback looks at the uri to determine errors */ 698 1.1 plunky if (req->uri) { 699 1.2 christos mm_free(req->uri); 700 1.1 plunky req->uri = NULL; 701 1.1 plunky } 702 1.2 christos if (req->uri_elems) { 703 1.2 christos evhttp_uri_free(req->uri_elems); 704 1.2 christos req->uri_elems = NULL; 705 1.2 christos } 706 1.1 plunky 707 1.2 christos /* 708 1.1 plunky * the callback needs to send a reply, once the reply has 709 1.1 plunky * been send, the connection should get freed. 710 1.1 plunky */ 711 1.1 plunky (*req->cb)(req, req->cb_arg); 712 1.1 plunky } 713 1.2 christos 714 1.1 plunky return (0); 715 1.1 plunky } 716 1.1 plunky 717 1.4 christos /* Free connection ownership of which can be acquired by user using 718 1.4 christos * evhttp_request_own(). */ 719 1.4 christos static inline void 720 1.4 christos evhttp_request_free_auto(struct evhttp_request *req) 721 1.4 christos { 722 1.4 christos if (!(req->flags & EVHTTP_USER_OWNED)) 723 1.4 christos evhttp_request_free(req); 724 1.4 christos } 725 1.4 christos 726 1.4 christos static void 727 1.4 christos evhttp_request_free_(struct evhttp_connection *evcon, struct evhttp_request *req) 728 1.4 christos { 729 1.4 christos TAILQ_REMOVE(&evcon->requests, req, next); 730 1.4 christos evhttp_request_free_auto(req); 731 1.4 christos } 732 1.4 christos 733 1.2 christos /* Called when evcon has experienced a (non-recoverable? -NM) error, as 734 1.2 christos * given in error. If it's an outgoing connection, reset the connection, 735 1.2 christos * retry any pending requests, and inform the user. If it's incoming, 736 1.2 christos * delegates to evhttp_connection_incoming_fail(). */ 737 1.1 plunky void 738 1.4 christos evhttp_connection_fail_(struct evhttp_connection *evcon, 739 1.4 christos enum evhttp_request_error error) 740 1.1 plunky { 741 1.4 christos const int errsave = EVUTIL_SOCKET_ERROR(); 742 1.1 plunky struct evhttp_request* req = TAILQ_FIRST(&evcon->requests); 743 1.1 plunky void (*cb)(struct evhttp_request *, void *); 744 1.1 plunky void *cb_arg; 745 1.4 christos void (*error_cb)(enum evhttp_request_error, void *); 746 1.4 christos void *error_cb_arg; 747 1.2 christos EVUTIL_ASSERT(req != NULL); 748 1.2 christos 749 1.2 christos bufferevent_disable(evcon->bufev, EV_READ|EV_WRITE); 750 1.2 christos 751 1.1 plunky if (evcon->flags & EVHTTP_CON_INCOMING) { 752 1.2 christos /* 753 1.1 plunky * for incoming requests, there are two different 754 1.1 plunky * failure cases. it's either a network level error 755 1.1 plunky * or an http layer error. for problems on the network 756 1.1 plunky * layer like timeouts we just drop the connections. 757 1.1 plunky * For HTTP problems, we might have to send back a 758 1.1 plunky * reply before the connection can be freed. 759 1.1 plunky */ 760 1.1 plunky if (evhttp_connection_incoming_fail(req, error) == -1) 761 1.1 plunky evhttp_connection_free(evcon); 762 1.1 plunky return; 763 1.1 plunky } 764 1.1 plunky 765 1.4 christos error_cb = req->error_cb; 766 1.4 christos error_cb_arg = req->cb_arg; 767 1.2 christos /* when the request was canceled, the callback is not executed */ 768 1.4 christos if (error != EVREQ_HTTP_REQUEST_CANCEL) { 769 1.2 christos /* save the callback for later; the cb might free our object */ 770 1.2 christos cb = req->cb; 771 1.2 christos cb_arg = req->cb_arg; 772 1.2 christos } else { 773 1.2 christos cb = NULL; 774 1.2 christos cb_arg = NULL; 775 1.2 christos } 776 1.1 plunky 777 1.2 christos /* do not fail all requests; the next request is going to get 778 1.2 christos * send over a new connection. when a user cancels a request, 779 1.2 christos * all other pending requests should be processed as normal 780 1.2 christos */ 781 1.4 christos evhttp_request_free_(evcon, req); 782 1.1 plunky 783 1.1 plunky /* reset the connection */ 784 1.4 christos evhttp_connection_reset_(evcon); 785 1.2 christos 786 1.1 plunky /* We are trying the next request that was queued on us */ 787 1.1 plunky if (TAILQ_FIRST(&evcon->requests) != NULL) 788 1.4 christos evhttp_connection_connect_(evcon); 789 1.5 christos else 790 1.5 christos if ((evcon->flags & EVHTTP_CON_OUTGOING) && 791 1.5 christos (evcon->flags & EVHTTP_CON_AUTOFREE)) { 792 1.5 christos evhttp_connection_free(evcon); 793 1.5 christos } 794 1.4 christos 795 1.4 christos /* The call to evhttp_connection_reset_ overwrote errno. 796 1.4 christos * Let's restore the original errno, so that the user's 797 1.4 christos * callback can have a better idea of what the error was. 798 1.4 christos */ 799 1.4 christos EVUTIL_SET_SOCKET_ERROR(errsave); 800 1.1 plunky 801 1.1 plunky /* inform the user */ 802 1.4 christos if (error_cb != NULL) 803 1.4 christos error_cb(error, error_cb_arg); 804 1.1 plunky if (cb != NULL) 805 1.1 plunky (*cb)(NULL, cb_arg); 806 1.1 plunky } 807 1.1 plunky 808 1.2 christos /* Bufferevent callback: invoked when any data has been written from an 809 1.2 christos * http connection's bufferevent */ 810 1.2 christos static void 811 1.2 christos evhttp_write_cb(struct bufferevent *bufev, void *arg) 812 1.1 plunky { 813 1.1 plunky struct evhttp_connection *evcon = arg; 814 1.1 plunky 815 1.1 plunky /* Activate our call back */ 816 1.1 plunky if (evcon->cb != NULL) 817 1.1 plunky (*evcon->cb)(evcon, evcon->cb_arg); 818 1.1 plunky } 819 1.1 plunky 820 1.1 plunky /** 821 1.1 plunky * Advance the connection state. 822 1.1 plunky * - If this is an outgoing connection, we've just processed the response; 823 1.1 plunky * idle or close the connection. 824 1.1 plunky * - If this is an incoming connection, we've just processed the request; 825 1.1 plunky * respond. 826 1.1 plunky */ 827 1.1 plunky static void 828 1.1 plunky evhttp_connection_done(struct evhttp_connection *evcon) 829 1.1 plunky { 830 1.1 plunky struct evhttp_request *req = TAILQ_FIRST(&evcon->requests); 831 1.1 plunky int con_outgoing = evcon->flags & EVHTTP_CON_OUTGOING; 832 1.4 christos int free_evcon = 0; 833 1.1 plunky 834 1.1 plunky if (con_outgoing) { 835 1.1 plunky /* idle or close the connection */ 836 1.4 christos int need_close = evhttp_is_request_connection_close(req); 837 1.1 plunky TAILQ_REMOVE(&evcon->requests, req, next); 838 1.1 plunky req->evcon = NULL; 839 1.1 plunky 840 1.1 plunky evcon->state = EVCON_IDLE; 841 1.1 plunky 842 1.1 plunky /* check if we got asked to close the connection */ 843 1.1 plunky if (need_close) 844 1.4 christos evhttp_connection_reset_(evcon); 845 1.1 plunky 846 1.1 plunky if (TAILQ_FIRST(&evcon->requests) != NULL) { 847 1.1 plunky /* 848 1.1 plunky * We have more requests; reset the connection 849 1.1 plunky * and deal with the next request. 850 1.1 plunky */ 851 1.1 plunky if (!evhttp_connected(evcon)) 852 1.4 christos evhttp_connection_connect_(evcon); 853 1.1 plunky else 854 1.1 plunky evhttp_request_dispatch(evcon); 855 1.1 plunky } else if (!need_close) { 856 1.1 plunky /* 857 1.1 plunky * The connection is going to be persistent, but we 858 1.1 plunky * need to detect if the other side closes it. 859 1.1 plunky */ 860 1.1 plunky evhttp_connection_start_detectclose(evcon); 861 1.4 christos } else if ((evcon->flags & EVHTTP_CON_AUTOFREE)) { 862 1.4 christos /* 863 1.4 christos * If we have no more requests that need completion 864 1.4 christos * and we're not waiting for the connection to close 865 1.4 christos */ 866 1.4 christos free_evcon = 1; 867 1.1 plunky } 868 1.1 plunky } else { 869 1.1 plunky /* 870 1.1 plunky * incoming connection - we need to leave the request on the 871 1.1 plunky * connection so that we can reply to it. 872 1.1 plunky */ 873 1.1 plunky evcon->state = EVCON_WRITING; 874 1.1 plunky } 875 1.1 plunky 876 1.1 plunky /* notify the user of the request */ 877 1.1 plunky (*req->cb)(req, req->cb_arg); 878 1.1 plunky 879 1.4 christos /* if this was an outgoing request, we own and it's done. so free it. */ 880 1.4 christos if (con_outgoing) { 881 1.4 christos evhttp_request_free_auto(req); 882 1.4 christos } 883 1.4 christos 884 1.4 christos /* If this was the last request of an outgoing connection and we're 885 1.4 christos * not waiting to receive a connection close event and we want to 886 1.4 christos * automatically free the connection. We check to ensure our request 887 1.4 christos * list is empty one last time just in case our callback added a 888 1.4 christos * new request. 889 1.2 christos */ 890 1.4 christos if (free_evcon && TAILQ_FIRST(&evcon->requests) == NULL) { 891 1.4 christos evhttp_connection_free(evcon); 892 1.1 plunky } 893 1.1 plunky } 894 1.1 plunky 895 1.1 plunky /* 896 1.1 plunky * Handles reading from a chunked request. 897 1.1 plunky * return ALL_DATA_READ: 898 1.1 plunky * all data has been read 899 1.1 plunky * return MORE_DATA_EXPECTED: 900 1.1 plunky * more data is expected 901 1.1 plunky * return DATA_CORRUPTED: 902 1.1 plunky * data is corrupted 903 1.2 christos * return REQUEST_CANCELED: 904 1.1 plunky * request was canceled by the user calling evhttp_cancel_request 905 1.2 christos * return DATA_TOO_LONG: 906 1.2 christos * ran over the maximum limit 907 1.1 plunky */ 908 1.1 plunky 909 1.1 plunky static enum message_read_status 910 1.1 plunky evhttp_handle_chunked_read(struct evhttp_request *req, struct evbuffer *buf) 911 1.1 plunky { 912 1.2 christos if (req == NULL || buf == NULL) { 913 1.2 christos return DATA_CORRUPTED; 914 1.2 christos } 915 1.2 christos 916 1.2 christos while (1) { 917 1.2 christos size_t buflen; 918 1.2 christos 919 1.2 christos if ((buflen = evbuffer_get_length(buf)) == 0) { 920 1.2 christos break; 921 1.2 christos } 922 1.2 christos 923 1.2 christos /* evbuffer_get_length returns size_t, but len variable is ssize_t, 924 1.2 christos * check for overflow conditions */ 925 1.2 christos if (buflen > EV_SSIZE_MAX) { 926 1.2 christos return DATA_CORRUPTED; 927 1.2 christos } 928 1.1 plunky 929 1.1 plunky if (req->ntoread < 0) { 930 1.1 plunky /* Read chunk size */ 931 1.1 plunky ev_int64_t ntoread; 932 1.2 christos char *p = evbuffer_readln(buf, NULL, EVBUFFER_EOL_CRLF); 933 1.1 plunky char *endp; 934 1.1 plunky int error; 935 1.1 plunky if (p == NULL) 936 1.1 plunky break; 937 1.1 plunky /* the last chunk is on a new line? */ 938 1.1 plunky if (strlen(p) == 0) { 939 1.2 christos mm_free(p); 940 1.1 plunky continue; 941 1.1 plunky } 942 1.1 plunky ntoread = evutil_strtoll(p, &endp, 16); 943 1.1 plunky error = (*p == '\0' || 944 1.1 plunky (*endp != '\0' && *endp != ' ') || 945 1.1 plunky ntoread < 0); 946 1.2 christos mm_free(p); 947 1.1 plunky if (error) { 948 1.1 plunky /* could not get chunk size */ 949 1.1 plunky return (DATA_CORRUPTED); 950 1.1 plunky } 951 1.2 christos 952 1.2 christos /* ntoread is signed int64, body_size is unsigned size_t, check for under/overflow conditions */ 953 1.2 christos if ((ev_uint64_t)ntoread > EV_SIZE_MAX - req->body_size) { 954 1.2 christos return DATA_CORRUPTED; 955 1.2 christos } 956 1.2 christos 957 1.2 christos if (req->body_size + (size_t)ntoread > req->evcon->max_body_size) { 958 1.2 christos /* failed body length test */ 959 1.2 christos event_debug(("Request body is too long")); 960 1.2 christos return (DATA_TOO_LONG); 961 1.2 christos } 962 1.2 christos 963 1.2 christos req->body_size += (size_t)ntoread; 964 1.1 plunky req->ntoread = ntoread; 965 1.1 plunky if (req->ntoread == 0) { 966 1.1 plunky /* Last chunk */ 967 1.1 plunky return (ALL_DATA_READ); 968 1.1 plunky } 969 1.1 plunky continue; 970 1.1 plunky } 971 1.1 plunky 972 1.2 christos /* req->ntoread is signed int64, len is ssize_t, based on arch, 973 1.2 christos * ssize_t could only be 32b, check for these conditions */ 974 1.2 christos if (req->ntoread > EV_SSIZE_MAX) { 975 1.2 christos return DATA_CORRUPTED; 976 1.2 christos } 977 1.2 christos 978 1.1 plunky /* don't have enough to complete a chunk; wait for more */ 979 1.2 christos if (req->ntoread > 0 && buflen < (ev_uint64_t)req->ntoread) 980 1.1 plunky return (MORE_DATA_EXPECTED); 981 1.1 plunky 982 1.1 plunky /* Completed chunk */ 983 1.2 christos evbuffer_remove_buffer(buf, req->input_buffer, (size_t)req->ntoread); 984 1.1 plunky req->ntoread = -1; 985 1.1 plunky if (req->chunk_cb != NULL) { 986 1.2 christos req->flags |= EVHTTP_REQ_DEFER_FREE; 987 1.1 plunky (*req->chunk_cb)(req, req->cb_arg); 988 1.1 plunky evbuffer_drain(req->input_buffer, 989 1.2 christos evbuffer_get_length(req->input_buffer)); 990 1.2 christos req->flags &= ~EVHTTP_REQ_DEFER_FREE; 991 1.2 christos if ((req->flags & EVHTTP_REQ_NEEDS_FREE) != 0) { 992 1.2 christos return (REQUEST_CANCELED); 993 1.2 christos } 994 1.1 plunky } 995 1.1 plunky } 996 1.1 plunky 997 1.1 plunky return (MORE_DATA_EXPECTED); 998 1.1 plunky } 999 1.1 plunky 1000 1.1 plunky static void 1001 1.1 plunky evhttp_read_trailer(struct evhttp_connection *evcon, struct evhttp_request *req) 1002 1.1 plunky { 1003 1.2 christos struct evbuffer *buf = bufferevent_get_input(evcon->bufev); 1004 1.1 plunky 1005 1.4 christos switch (evhttp_parse_headers_(req, buf)) { 1006 1.1 plunky case DATA_CORRUPTED: 1007 1.2 christos case DATA_TOO_LONG: 1008 1.4 christos evhttp_connection_fail_(evcon, EVREQ_HTTP_DATA_TOO_LONG); 1009 1.1 plunky break; 1010 1.1 plunky case ALL_DATA_READ: 1011 1.2 christos bufferevent_disable(evcon->bufev, EV_READ); 1012 1.1 plunky evhttp_connection_done(evcon); 1013 1.1 plunky break; 1014 1.1 plunky case MORE_DATA_EXPECTED: 1015 1.2 christos case REQUEST_CANCELED: /* ??? */ 1016 1.1 plunky default: 1017 1.1 plunky break; 1018 1.1 plunky } 1019 1.1 plunky } 1020 1.1 plunky 1021 1.1 plunky static void 1022 1.4 christos evhttp_lingering_close(struct evhttp_connection *evcon, 1023 1.4 christos struct evhttp_request *req) 1024 1.4 christos { 1025 1.4 christos struct evbuffer *buf = bufferevent_get_input(evcon->bufev); 1026 1.4 christos 1027 1.4 christos size_t n = evbuffer_get_length(buf); 1028 1.4 christos if (n > (size_t) req->ntoread) 1029 1.4 christos n = (size_t) req->ntoread; 1030 1.4 christos req->ntoread -= n; 1031 1.4 christos req->body_size += n; 1032 1.4 christos 1033 1.4 christos event_debug(("Request body is too long, left " EV_I64_FMT, 1034 1.4 christos EV_I64_ARG(req->ntoread))); 1035 1.4 christos 1036 1.4 christos evbuffer_drain(buf, n); 1037 1.4 christos if (!req->ntoread) 1038 1.4 christos evhttp_connection_fail_(evcon, EVREQ_HTTP_DATA_TOO_LONG); 1039 1.4 christos } 1040 1.4 christos static void 1041 1.4 christos evhttp_lingering_fail(struct evhttp_connection *evcon, 1042 1.4 christos struct evhttp_request *req) 1043 1.4 christos { 1044 1.4 christos if (evcon->flags & EVHTTP_CON_LINGERING_CLOSE) 1045 1.4 christos evhttp_lingering_close(evcon, req); 1046 1.4 christos else 1047 1.4 christos evhttp_connection_fail_(evcon, EVREQ_HTTP_DATA_TOO_LONG); 1048 1.4 christos } 1049 1.4 christos 1050 1.4 christos static void 1051 1.1 plunky evhttp_read_body(struct evhttp_connection *evcon, struct evhttp_request *req) 1052 1.1 plunky { 1053 1.2 christos struct evbuffer *buf = bufferevent_get_input(evcon->bufev); 1054 1.2 christos 1055 1.1 plunky if (req->chunked) { 1056 1.1 plunky switch (evhttp_handle_chunked_read(req, buf)) { 1057 1.1 plunky case ALL_DATA_READ: 1058 1.1 plunky /* finished last chunk */ 1059 1.1 plunky evcon->state = EVCON_READING_TRAILER; 1060 1.1 plunky evhttp_read_trailer(evcon, req); 1061 1.1 plunky return; 1062 1.1 plunky case DATA_CORRUPTED: 1063 1.4 christos case DATA_TOO_LONG: 1064 1.1 plunky /* corrupted data */ 1065 1.4 christos evhttp_connection_fail_(evcon, 1066 1.4 christos EVREQ_HTTP_DATA_TOO_LONG); 1067 1.1 plunky return; 1068 1.1 plunky case REQUEST_CANCELED: 1069 1.1 plunky /* request canceled */ 1070 1.4 christos evhttp_request_free_auto(req); 1071 1.1 plunky return; 1072 1.1 plunky case MORE_DATA_EXPECTED: 1073 1.1 plunky default: 1074 1.1 plunky break; 1075 1.1 plunky } 1076 1.1 plunky } else if (req->ntoread < 0) { 1077 1.1 plunky /* Read until connection close. */ 1078 1.2 christos if ((size_t)(req->body_size + evbuffer_get_length(buf)) < req->body_size) { 1079 1.4 christos evhttp_connection_fail_(evcon, EVREQ_HTTP_INVALID_HEADER); 1080 1.2 christos return; 1081 1.2 christos } 1082 1.2 christos 1083 1.2 christos req->body_size += evbuffer_get_length(buf); 1084 1.1 plunky evbuffer_add_buffer(req->input_buffer, buf); 1085 1.2 christos } else if (req->chunk_cb != NULL || evbuffer_get_length(buf) >= (size_t)req->ntoread) { 1086 1.2 christos /* XXX: the above get_length comparison has to be fixed for overflow conditions! */ 1087 1.2 christos /* We've postponed moving the data until now, but we're 1088 1.2 christos * about to use it. */ 1089 1.2 christos size_t n = evbuffer_get_length(buf); 1090 1.2 christos 1091 1.2 christos if (n > (size_t) req->ntoread) 1092 1.2 christos n = (size_t) req->ntoread; 1093 1.2 christos req->ntoread -= n; 1094 1.2 christos req->body_size += n; 1095 1.2 christos evbuffer_remove_buffer(buf, req->input_buffer, n); 1096 1.2 christos } 1097 1.2 christos 1098 1.2 christos if (req->body_size > req->evcon->max_body_size || 1099 1.2 christos (!req->chunked && req->ntoread >= 0 && 1100 1.2 christos (size_t)req->ntoread > req->evcon->max_body_size)) { 1101 1.2 christos /* XXX: The above casted comparison must checked for overflow */ 1102 1.2 christos /* failed body length test */ 1103 1.4 christos 1104 1.4 christos evhttp_lingering_fail(evcon, req); 1105 1.2 christos return; 1106 1.2 christos } 1107 1.2 christos 1108 1.2 christos if (evbuffer_get_length(req->input_buffer) > 0 && req->chunk_cb != NULL) { 1109 1.2 christos req->flags |= EVHTTP_REQ_DEFER_FREE; 1110 1.2 christos (*req->chunk_cb)(req, req->cb_arg); 1111 1.2 christos req->flags &= ~EVHTTP_REQ_DEFER_FREE; 1112 1.2 christos evbuffer_drain(req->input_buffer, 1113 1.2 christos evbuffer_get_length(req->input_buffer)); 1114 1.2 christos if ((req->flags & EVHTTP_REQ_NEEDS_FREE) != 0) { 1115 1.4 christos evhttp_request_free_auto(req); 1116 1.2 christos return; 1117 1.2 christos } 1118 1.2 christos } 1119 1.2 christos 1120 1.4 christos if (!req->ntoread) { 1121 1.2 christos bufferevent_disable(evcon->bufev, EV_READ); 1122 1.1 plunky /* Completed content length */ 1123 1.1 plunky evhttp_connection_done(evcon); 1124 1.1 plunky return; 1125 1.1 plunky } 1126 1.1 plunky } 1127 1.1 plunky 1128 1.2 christos #define get_deferred_queue(evcon) \ 1129 1.4 christos ((evcon)->base) 1130 1.2 christos 1131 1.1 plunky /* 1132 1.2 christos * Gets called when more data becomes available 1133 1.1 plunky */ 1134 1.1 plunky 1135 1.2 christos static void 1136 1.2 christos evhttp_read_cb(struct bufferevent *bufev, void *arg) 1137 1.1 plunky { 1138 1.1 plunky struct evhttp_connection *evcon = arg; 1139 1.1 plunky struct evhttp_request *req = TAILQ_FIRST(&evcon->requests); 1140 1.1 plunky 1141 1.2 christos /* Cancel if it's pending. */ 1142 1.4 christos event_deferred_cb_cancel_(get_deferred_queue(evcon), 1143 1.2 christos &evcon->read_more_deferred_cb); 1144 1.1 plunky 1145 1.1 plunky switch (evcon->state) { 1146 1.1 plunky case EVCON_READING_FIRSTLINE: 1147 1.1 plunky evhttp_read_firstline(evcon, req); 1148 1.2 christos /* note the request may have been freed in 1149 1.2 christos * evhttp_read_body */ 1150 1.1 plunky break; 1151 1.1 plunky case EVCON_READING_HEADERS: 1152 1.1 plunky evhttp_read_header(evcon, req); 1153 1.2 christos /* note the request may have been freed in 1154 1.2 christos * evhttp_read_body */ 1155 1.1 plunky break; 1156 1.1 plunky case EVCON_READING_BODY: 1157 1.1 plunky evhttp_read_body(evcon, req); 1158 1.2 christos /* note the request may have been freed in 1159 1.2 christos * evhttp_read_body */ 1160 1.1 plunky break; 1161 1.1 plunky case EVCON_READING_TRAILER: 1162 1.1 plunky evhttp_read_trailer(evcon, req); 1163 1.1 plunky break; 1164 1.2 christos case EVCON_IDLE: 1165 1.2 christos { 1166 1.2 christos #ifdef USE_DEBUG 1167 1.2 christos struct evbuffer *input; 1168 1.2 christos size_t total_len; 1169 1.2 christos 1170 1.2 christos input = bufferevent_get_input(evcon->bufev); 1171 1.2 christos total_len = evbuffer_get_length(input); 1172 1.2 christos event_debug(("%s: read "EV_SIZE_FMT 1173 1.2 christos " bytes in EVCON_IDLE state," 1174 1.2 christos " resetting connection", 1175 1.2 christos __func__, EV_SIZE_ARG(total_len))); 1176 1.2 christos #endif 1177 1.2 christos 1178 1.4 christos evhttp_connection_reset_(evcon); 1179 1.2 christos } 1180 1.2 christos break; 1181 1.1 plunky case EVCON_DISCONNECTED: 1182 1.1 plunky case EVCON_CONNECTING: 1183 1.1 plunky case EVCON_WRITING: 1184 1.1 plunky default: 1185 1.1 plunky event_errx(1, "%s: illegal connection state %d", 1186 1.1 plunky __func__, evcon->state); 1187 1.1 plunky } 1188 1.1 plunky } 1189 1.1 plunky 1190 1.1 plunky static void 1191 1.4 christos evhttp_deferred_read_cb(struct event_callback *cb, void *data) 1192 1.2 christos { 1193 1.2 christos struct evhttp_connection *evcon = data; 1194 1.5 christos struct bufferevent *bev = evcon->bufev; 1195 1.5 christos if (bev->readcb) 1196 1.5 christos (bev->readcb)(evcon->bufev, evcon); 1197 1.2 christos } 1198 1.2 christos 1199 1.2 christos static void 1200 1.1 plunky evhttp_write_connectioncb(struct evhttp_connection *evcon, void *arg) 1201 1.1 plunky { 1202 1.1 plunky /* This is after writing the request to the server */ 1203 1.1 plunky struct evhttp_request *req = TAILQ_FIRST(&evcon->requests); 1204 1.4 christos struct evbuffer *output = bufferevent_get_output(evcon->bufev); 1205 1.2 christos EVUTIL_ASSERT(req != NULL); 1206 1.1 plunky 1207 1.2 christos EVUTIL_ASSERT(evcon->state == EVCON_WRITING); 1208 1.1 plunky 1209 1.4 christos /* We need to wait until we've written all of our output data before we can 1210 1.4 christos * continue */ 1211 1.4 christos if (evbuffer_get_length(output) > 0) 1212 1.4 christos return; 1213 1.4 christos 1214 1.1 plunky /* We are done writing our header and are now expecting the response */ 1215 1.1 plunky req->kind = EVHTTP_RESPONSE; 1216 1.1 plunky 1217 1.4 christos evhttp_start_read_(evcon); 1218 1.1 plunky } 1219 1.1 plunky 1220 1.1 plunky /* 1221 1.1 plunky * Clean up a connection object 1222 1.1 plunky */ 1223 1.1 plunky 1224 1.1 plunky void 1225 1.1 plunky evhttp_connection_free(struct evhttp_connection *evcon) 1226 1.1 plunky { 1227 1.1 plunky struct evhttp_request *req; 1228 1.5 christos int need_close = 0; 1229 1.1 plunky 1230 1.1 plunky /* notify interested parties that this connection is going down */ 1231 1.1 plunky if (evcon->fd != -1) { 1232 1.1 plunky if (evhttp_connected(evcon) && evcon->closecb != NULL) 1233 1.1 plunky (*evcon->closecb)(evcon, evcon->closecb_arg); 1234 1.1 plunky } 1235 1.1 plunky 1236 1.2 christos /* remove all requests that might be queued on this 1237 1.2 christos * connection. for server connections, this should be empty. 1238 1.2 christos * because it gets dequeued either in evhttp_connection_done or 1239 1.4 christos * evhttp_connection_fail_. 1240 1.2 christos */ 1241 1.1 plunky while ((req = TAILQ_FIRST(&evcon->requests)) != NULL) { 1242 1.4 christos evhttp_request_free_(evcon, req); 1243 1.1 plunky } 1244 1.1 plunky 1245 1.1 plunky if (evcon->http_server != NULL) { 1246 1.1 plunky struct evhttp *http = evcon->http_server; 1247 1.1 plunky TAILQ_REMOVE(&http->connections, evcon, next); 1248 1.1 plunky } 1249 1.1 plunky 1250 1.2 christos if (event_initialized(&evcon->retry_ev)) { 1251 1.2 christos event_del(&evcon->retry_ev); 1252 1.2 christos event_debug_unassign(&evcon->retry_ev); 1253 1.2 christos } 1254 1.2 christos 1255 1.4 christos event_deferred_cb_cancel_(get_deferred_queue(evcon), 1256 1.2 christos &evcon->read_more_deferred_cb); 1257 1.2 christos 1258 1.5 christos if (evcon->bufev != NULL) { 1259 1.5 christos need_close = 1260 1.5 christos !(bufferevent_get_options_(evcon->bufev) & BEV_OPT_CLOSE_ON_FREE); 1261 1.5 christos if (evcon->fd == -1) 1262 1.5 christos evcon->fd = bufferevent_getfd(evcon->bufev); 1263 1.5 christos 1264 1.5 christos bufferevent_free(evcon->bufev); 1265 1.5 christos } 1266 1.4 christos 1267 1.2 christos if (evcon->fd != -1) { 1268 1.2 christos shutdown(evcon->fd, EVUTIL_SHUT_WR); 1269 1.5 christos if (need_close) 1270 1.4 christos evutil_closesocket(evcon->fd); 1271 1.2 christos } 1272 1.1 plunky 1273 1.1 plunky if (evcon->bind_address != NULL) 1274 1.2 christos mm_free(evcon->bind_address); 1275 1.1 plunky 1276 1.1 plunky if (evcon->address != NULL) 1277 1.2 christos mm_free(evcon->address); 1278 1.1 plunky 1279 1.2 christos mm_free(evcon); 1280 1.1 plunky } 1281 1.1 plunky 1282 1.1 plunky void 1283 1.4 christos evhttp_connection_free_on_completion(struct evhttp_connection *evcon) { 1284 1.4 christos evcon->flags |= EVHTTP_CON_AUTOFREE; 1285 1.4 christos } 1286 1.4 christos 1287 1.4 christos void 1288 1.1 plunky evhttp_connection_set_local_address(struct evhttp_connection *evcon, 1289 1.1 plunky const char *address) 1290 1.1 plunky { 1291 1.2 christos EVUTIL_ASSERT(evcon->state == EVCON_DISCONNECTED); 1292 1.1 plunky if (evcon->bind_address) 1293 1.2 christos mm_free(evcon->bind_address); 1294 1.2 christos if ((evcon->bind_address = mm_strdup(address)) == NULL) 1295 1.2 christos event_warn("%s: strdup", __func__); 1296 1.1 plunky } 1297 1.1 plunky 1298 1.1 plunky void 1299 1.1 plunky evhttp_connection_set_local_port(struct evhttp_connection *evcon, 1300 1.2 christos ev_uint16_t port) 1301 1.1 plunky { 1302 1.2 christos EVUTIL_ASSERT(evcon->state == EVCON_DISCONNECTED); 1303 1.1 plunky evcon->bind_port = port; 1304 1.1 plunky } 1305 1.1 plunky 1306 1.1 plunky static void 1307 1.1 plunky evhttp_request_dispatch(struct evhttp_connection* evcon) 1308 1.1 plunky { 1309 1.1 plunky struct evhttp_request *req = TAILQ_FIRST(&evcon->requests); 1310 1.2 christos 1311 1.1 plunky /* this should not usually happy but it's possible */ 1312 1.1 plunky if (req == NULL) 1313 1.1 plunky return; 1314 1.1 plunky 1315 1.5 christos EVUTIL_ASSERT(req->kind == EVHTTP_REQUEST); 1316 1.5 christos 1317 1.1 plunky /* delete possible close detection events */ 1318 1.1 plunky evhttp_connection_stop_detectclose(evcon); 1319 1.2 christos 1320 1.1 plunky /* we assume that the connection is connected already */ 1321 1.2 christos EVUTIL_ASSERT(evcon->state == EVCON_IDLE); 1322 1.1 plunky 1323 1.1 plunky evcon->state = EVCON_WRITING; 1324 1.1 plunky 1325 1.1 plunky /* Create the header from the store arguments */ 1326 1.1 plunky evhttp_make_header(evcon, req); 1327 1.1 plunky 1328 1.1 plunky evhttp_write_buffer(evcon, evhttp_write_connectioncb, NULL); 1329 1.1 plunky } 1330 1.1 plunky 1331 1.2 christos /* Reset our connection state: disables reading/writing, closes our fd (if 1332 1.2 christos * any), clears out buffers, and puts us in state DISCONNECTED. */ 1333 1.1 plunky void 1334 1.4 christos evhttp_connection_reset_(struct evhttp_connection *evcon) 1335 1.1 plunky { 1336 1.2 christos struct evbuffer *tmp; 1337 1.4 christos int err; 1338 1.2 christos 1339 1.5 christos bufferevent_setcb(evcon->bufev, NULL, NULL, NULL, NULL); 1340 1.5 christos 1341 1.2 christos /* XXXX This is not actually an optimal fix. Instead we ought to have 1342 1.2 christos an API for "stop connecting", or use bufferevent_setfd to turn off 1343 1.2 christos connecting. But for Libevent 2.0, this seems like a minimal change 1344 1.2 christos least likely to disrupt the rest of the bufferevent and http code. 1345 1.2 christos 1346 1.2 christos Why is this here? If the fd is set in the bufferevent, and the 1347 1.2 christos bufferevent is connecting, then you can't actually stop the 1348 1.2 christos bufferevent from trying to connect with bufferevent_disable(). The 1349 1.2 christos connect will never trigger, since we close the fd, but the timeout 1350 1.4 christos might. That caused an assertion failure in evhttp_connection_fail_. 1351 1.2 christos */ 1352 1.4 christos bufferevent_disable_hard_(evcon->bufev, EV_READ|EV_WRITE); 1353 1.4 christos 1354 1.4 christos if (evcon->fd == -1) 1355 1.4 christos evcon->fd = bufferevent_getfd(evcon->bufev); 1356 1.1 plunky 1357 1.1 plunky if (evcon->fd != -1) { 1358 1.1 plunky /* inform interested parties about connection close */ 1359 1.1 plunky if (evhttp_connected(evcon) && evcon->closecb != NULL) 1360 1.1 plunky (*evcon->closecb)(evcon, evcon->closecb_arg); 1361 1.1 plunky 1362 1.2 christos shutdown(evcon->fd, EVUTIL_SHUT_WR); 1363 1.2 christos evutil_closesocket(evcon->fd); 1364 1.1 plunky evcon->fd = -1; 1365 1.1 plunky } 1366 1.5 christos err = bufferevent_setfd(evcon->bufev, -1); 1367 1.5 christos EVUTIL_ASSERT(!err && "setfd"); 1368 1.1 plunky 1369 1.2 christos /* we need to clean up any buffered data */ 1370 1.2 christos tmp = bufferevent_get_output(evcon->bufev); 1371 1.4 christos err = evbuffer_drain(tmp, -1); 1372 1.4 christos EVUTIL_ASSERT(!err && "drain output"); 1373 1.2 christos tmp = bufferevent_get_input(evcon->bufev); 1374 1.4 christos err = evbuffer_drain(tmp, -1); 1375 1.4 christos EVUTIL_ASSERT(!err && "drain input"); 1376 1.4 christos 1377 1.4 christos evcon->flags &= ~EVHTTP_CON_READING_ERROR; 1378 1.1 plunky 1379 1.2 christos evcon->state = EVCON_DISCONNECTED; 1380 1.1 plunky } 1381 1.1 plunky 1382 1.1 plunky static void 1383 1.1 plunky evhttp_connection_start_detectclose(struct evhttp_connection *evcon) 1384 1.1 plunky { 1385 1.1 plunky evcon->flags |= EVHTTP_CON_CLOSEDETECT; 1386 1.2 christos bufferevent_enable(evcon->bufev, EV_READ); 1387 1.1 plunky } 1388 1.1 plunky 1389 1.1 plunky static void 1390 1.1 plunky evhttp_connection_stop_detectclose(struct evhttp_connection *evcon) 1391 1.1 plunky { 1392 1.1 plunky evcon->flags &= ~EVHTTP_CON_CLOSEDETECT; 1393 1.2 christos bufferevent_disable(evcon->bufev, EV_READ); 1394 1.1 plunky } 1395 1.1 plunky 1396 1.1 plunky static void 1397 1.2 christos evhttp_connection_retry(evutil_socket_t fd, short what, void *arg) 1398 1.1 plunky { 1399 1.1 plunky struct evhttp_connection *evcon = arg; 1400 1.1 plunky 1401 1.1 plunky evcon->state = EVCON_DISCONNECTED; 1402 1.4 christos evhttp_connection_connect_(evcon); 1403 1.1 plunky } 1404 1.1 plunky 1405 1.1 plunky static void 1406 1.2 christos evhttp_connection_cb_cleanup(struct evhttp_connection *evcon) 1407 1.1 plunky { 1408 1.2 christos struct evcon_requestq requests; 1409 1.1 plunky 1410 1.4 christos evhttp_connection_reset_(evcon); 1411 1.1 plunky if (evcon->retry_max < 0 || evcon->retry_cnt < evcon->retry_max) { 1412 1.4 christos struct timeval tv_retry = evcon->initial_retry_timeout; 1413 1.4 christos int i; 1414 1.2 christos evtimer_assign(&evcon->retry_ev, evcon->base, evhttp_connection_retry, evcon); 1415 1.2 christos /* XXXX handle failure from evhttp_add_event */ 1416 1.4 christos for (i=0; i < evcon->retry_cnt; ++i) { 1417 1.4 christos tv_retry.tv_usec *= 2; 1418 1.4 christos if (tv_retry.tv_usec > 1000000) { 1419 1.4 christos tv_retry.tv_usec -= 1000000; 1420 1.4 christos tv_retry.tv_sec += 1; 1421 1.4 christos } 1422 1.4 christos tv_retry.tv_sec *= 2; 1423 1.4 christos if (tv_retry.tv_sec > 3600) { 1424 1.4 christos tv_retry.tv_sec = 3600; 1425 1.4 christos tv_retry.tv_usec = 0; 1426 1.4 christos } 1427 1.4 christos } 1428 1.4 christos event_add(&evcon->retry_ev, &tv_retry); 1429 1.1 plunky evcon->retry_cnt++; 1430 1.1 plunky return; 1431 1.1 plunky } 1432 1.1 plunky 1433 1.2 christos /* 1434 1.2 christos * User callback can do evhttp_make_request() on the same 1435 1.2 christos * evcon so new request will be added to evcon->requests. To 1436 1.2 christos * avoid freeing it prematurely we iterate over the copy of 1437 1.2 christos * the queue. 1438 1.2 christos */ 1439 1.2 christos TAILQ_INIT(&requests); 1440 1.1 plunky while (TAILQ_FIRST(&evcon->requests) != NULL) { 1441 1.1 plunky struct evhttp_request *request = TAILQ_FIRST(&evcon->requests); 1442 1.1 plunky TAILQ_REMOVE(&evcon->requests, request, next); 1443 1.2 christos TAILQ_INSERT_TAIL(&requests, request, next); 1444 1.2 christos } 1445 1.2 christos 1446 1.2 christos /* for now, we just signal all requests by executing their callbacks */ 1447 1.2 christos while (TAILQ_FIRST(&requests) != NULL) { 1448 1.2 christos struct evhttp_request *request = TAILQ_FIRST(&requests); 1449 1.2 christos TAILQ_REMOVE(&requests, request, next); 1450 1.1 plunky request->evcon = NULL; 1451 1.1 plunky 1452 1.1 plunky /* we might want to set an error here */ 1453 1.1 plunky request->cb(request, request->cb_arg); 1454 1.4 christos evhttp_request_free_auto(request); 1455 1.1 plunky } 1456 1.1 plunky } 1457 1.1 plunky 1458 1.2 christos static void 1459 1.4 christos evhttp_connection_read_on_write_error(struct evhttp_connection *evcon, 1460 1.4 christos struct evhttp_request *req) 1461 1.4 christos { 1462 1.4 christos struct evbuffer *buf; 1463 1.4 christos 1464 1.4 christos /** Second time, we can't read anything */ 1465 1.4 christos if (evcon->flags & EVHTTP_CON_READING_ERROR) { 1466 1.4 christos evcon->flags &= ~EVHTTP_CON_READING_ERROR; 1467 1.4 christos evhttp_connection_fail_(evcon, EVREQ_HTTP_EOF); 1468 1.4 christos return; 1469 1.4 christos } 1470 1.4 christos 1471 1.4 christos req->kind = EVHTTP_RESPONSE; 1472 1.4 christos 1473 1.4 christos buf = bufferevent_get_output(evcon->bufev); 1474 1.4 christos evbuffer_unfreeze(buf, 1); 1475 1.4 christos evbuffer_drain(buf, evbuffer_get_length(buf)); 1476 1.4 christos evbuffer_freeze(buf, 1); 1477 1.4 christos 1478 1.4 christos evhttp_start_read_(evcon); 1479 1.4 christos evcon->flags |= EVHTTP_CON_READING_ERROR; 1480 1.4 christos } 1481 1.4 christos 1482 1.4 christos static void 1483 1.2 christos evhttp_error_cb(struct bufferevent *bufev, short what, void *arg) 1484 1.2 christos { 1485 1.2 christos struct evhttp_connection *evcon = arg; 1486 1.2 christos struct evhttp_request *req = TAILQ_FIRST(&evcon->requests); 1487 1.1 plunky 1488 1.4 christos if (evcon->fd == -1) 1489 1.4 christos evcon->fd = bufferevent_getfd(bufev); 1490 1.4 christos 1491 1.2 christos switch (evcon->state) { 1492 1.2 christos case EVCON_CONNECTING: 1493 1.2 christos if (what & BEV_EVENT_TIMEOUT) { 1494 1.2 christos event_debug(("%s: connection timeout for \"%s:%d\" on " 1495 1.2 christos EV_SOCK_FMT, 1496 1.2 christos __func__, evcon->address, evcon->port, 1497 1.2 christos EV_SOCK_ARG(evcon->fd))); 1498 1.2 christos evhttp_connection_cb_cleanup(evcon); 1499 1.2 christos return; 1500 1.2 christos } 1501 1.2 christos break; 1502 1.2 christos 1503 1.2 christos case EVCON_READING_BODY: 1504 1.2 christos if (!req->chunked && req->ntoread < 0 1505 1.2 christos && what == (BEV_EVENT_READING|BEV_EVENT_EOF)) { 1506 1.2 christos /* EOF on read can be benign */ 1507 1.2 christos evhttp_connection_done(evcon); 1508 1.2 christos return; 1509 1.2 christos } 1510 1.2 christos break; 1511 1.2 christos 1512 1.2 christos case EVCON_DISCONNECTED: 1513 1.2 christos case EVCON_IDLE: 1514 1.2 christos case EVCON_READING_FIRSTLINE: 1515 1.2 christos case EVCON_READING_HEADERS: 1516 1.2 christos case EVCON_READING_TRAILER: 1517 1.2 christos case EVCON_WRITING: 1518 1.2 christos default: 1519 1.2 christos break; 1520 1.2 christos } 1521 1.2 christos 1522 1.2 christos /* when we are in close detect mode, a read error means that 1523 1.2 christos * the other side closed their connection. 1524 1.2 christos */ 1525 1.2 christos if (evcon->flags & EVHTTP_CON_CLOSEDETECT) { 1526 1.2 christos evcon->flags &= ~EVHTTP_CON_CLOSEDETECT; 1527 1.2 christos EVUTIL_ASSERT(evcon->http_server == NULL); 1528 1.2 christos /* For connections from the client, we just 1529 1.2 christos * reset the connection so that it becomes 1530 1.2 christos * disconnected. 1531 1.2 christos */ 1532 1.2 christos EVUTIL_ASSERT(evcon->state == EVCON_IDLE); 1533 1.4 christos evhttp_connection_reset_(evcon); 1534 1.4 christos 1535 1.4 christos /* 1536 1.4 christos * If we have no more requests that need completion 1537 1.4 christos * and we want to auto-free the connection when all 1538 1.4 christos * requests have been completed. 1539 1.4 christos */ 1540 1.4 christos if (TAILQ_FIRST(&evcon->requests) == NULL 1541 1.4 christos && (evcon->flags & EVHTTP_CON_OUTGOING) 1542 1.4 christos && (evcon->flags & EVHTTP_CON_AUTOFREE)) { 1543 1.4 christos evhttp_connection_free(evcon); 1544 1.4 christos } 1545 1.2 christos return; 1546 1.2 christos } 1547 1.2 christos 1548 1.2 christos if (what & BEV_EVENT_TIMEOUT) { 1549 1.4 christos evhttp_connection_fail_(evcon, EVREQ_HTTP_TIMEOUT); 1550 1.2 christos } else if (what & (BEV_EVENT_EOF|BEV_EVENT_ERROR)) { 1551 1.4 christos if (what & BEV_EVENT_WRITING && 1552 1.4 christos evcon->flags & EVHTTP_CON_READ_ON_WRITE_ERROR) { 1553 1.4 christos evhttp_connection_read_on_write_error(evcon, req); 1554 1.4 christos return; 1555 1.4 christos } 1556 1.4 christos 1557 1.5 christos if (what & BEV_EVENT_READING && 1558 1.5 christos evcon->flags & EVHTTP_CON_READ_ON_WRITE_ERROR && 1559 1.5 christos evbuffer_get_length(bufferevent_get_input(bufev))) { 1560 1.5 christos event_deferred_cb_schedule_(get_deferred_queue(evcon), 1561 1.5 christos &evcon->read_more_deferred_cb); 1562 1.5 christos return; 1563 1.5 christos } 1564 1.5 christos 1565 1.4 christos evhttp_connection_fail_(evcon, EVREQ_HTTP_EOF); 1566 1.4 christos } else if (what == BEV_EVENT_CONNECTED) { 1567 1.2 christos } else { 1568 1.4 christos evhttp_connection_fail_(evcon, EVREQ_HTTP_BUFFER_ERROR); 1569 1.2 christos } 1570 1.2 christos } 1571 1.2 christos 1572 1.2 christos /* 1573 1.2 christos * Event callback for asynchronous connection attempt. 1574 1.2 christos */ 1575 1.2 christos static void 1576 1.2 christos evhttp_connection_cb(struct bufferevent *bufev, short what, void *arg) 1577 1.2 christos { 1578 1.2 christos struct evhttp_connection *evcon = arg; 1579 1.2 christos int error; 1580 1.2 christos ev_socklen_t errsz = sizeof(error); 1581 1.2 christos 1582 1.4 christos if (evcon->fd == -1) 1583 1.4 christos evcon->fd = bufferevent_getfd(bufev); 1584 1.4 christos 1585 1.2 christos if (!(what & BEV_EVENT_CONNECTED)) { 1586 1.2 christos /* some operating systems return ECONNREFUSED immediately 1587 1.2 christos * when connecting to a local address. the cleanup is going 1588 1.2 christos * to reschedule this function call. 1589 1.2 christos */ 1590 1.4 christos #ifndef _WIN32 1591 1.2 christos if (errno == ECONNREFUSED) 1592 1.2 christos goto cleanup; 1593 1.2 christos #endif 1594 1.2 christos evhttp_error_cb(bufev, what, arg); 1595 1.2 christos return; 1596 1.2 christos } 1597 1.2 christos 1598 1.4 christos if (evcon->fd == -1) { 1599 1.4 christos event_debug(("%s: bufferevent_getfd returned -1", 1600 1.4 christos __func__)); 1601 1.4 christos goto cleanup; 1602 1.4 christos } 1603 1.4 christos 1604 1.2 christos /* Check if the connection completed */ 1605 1.2 christos if (getsockopt(evcon->fd, SOL_SOCKET, SO_ERROR, (void*)&error, 1606 1.2 christos &errsz) == -1) { 1607 1.2 christos event_debug(("%s: getsockopt for \"%s:%d\" on "EV_SOCK_FMT, 1608 1.2 christos __func__, evcon->address, evcon->port, 1609 1.2 christos EV_SOCK_ARG(evcon->fd))); 1610 1.2 christos goto cleanup; 1611 1.2 christos } 1612 1.2 christos 1613 1.2 christos if (error) { 1614 1.2 christos event_debug(("%s: connect failed for \"%s:%d\" on " 1615 1.2 christos EV_SOCK_FMT": %s", 1616 1.2 christos __func__, evcon->address, evcon->port, 1617 1.2 christos EV_SOCK_ARG(evcon->fd), 1618 1.2 christos evutil_socket_error_to_string(error))); 1619 1.2 christos goto cleanup; 1620 1.2 christos } 1621 1.2 christos 1622 1.2 christos /* We are connected to the server now */ 1623 1.2 christos event_debug(("%s: connected to \"%s:%d\" on "EV_SOCK_FMT"\n", 1624 1.2 christos __func__, evcon->address, evcon->port, 1625 1.2 christos EV_SOCK_ARG(evcon->fd))); 1626 1.2 christos 1627 1.2 christos /* Reset the retry count as we were successful in connecting */ 1628 1.2 christos evcon->retry_cnt = 0; 1629 1.2 christos evcon->state = EVCON_IDLE; 1630 1.2 christos 1631 1.2 christos /* reset the bufferevent cbs */ 1632 1.2 christos bufferevent_setcb(evcon->bufev, 1633 1.2 christos evhttp_read_cb, 1634 1.2 christos evhttp_write_cb, 1635 1.2 christos evhttp_error_cb, 1636 1.2 christos evcon); 1637 1.2 christos 1638 1.4 christos if (!evutil_timerisset(&evcon->timeout)) { 1639 1.4 christos const struct timeval read_tv = { HTTP_READ_TIMEOUT, 0 }; 1640 1.4 christos const struct timeval write_tv = { HTTP_WRITE_TIMEOUT, 0 }; 1641 1.4 christos bufferevent_set_timeouts(evcon->bufev, &read_tv, &write_tv); 1642 1.4 christos } else { 1643 1.4 christos bufferevent_set_timeouts(evcon->bufev, &evcon->timeout, &evcon->timeout); 1644 1.2 christos } 1645 1.2 christos 1646 1.2 christos /* try to start requests that have queued up on this connection */ 1647 1.2 christos evhttp_request_dispatch(evcon); 1648 1.2 christos return; 1649 1.2 christos 1650 1.2 christos cleanup: 1651 1.2 christos evhttp_connection_cb_cleanup(evcon); 1652 1.2 christos } 1653 1.2 christos 1654 1.2 christos /* 1655 1.2 christos * Check if we got a valid response code. 1656 1.2 christos */ 1657 1.2 christos 1658 1.2 christos static int 1659 1.2 christos evhttp_valid_response_code(int code) 1660 1.2 christos { 1661 1.2 christos if (code == 0) 1662 1.2 christos return (0); 1663 1.1 plunky 1664 1.1 plunky return (1); 1665 1.1 plunky } 1666 1.1 plunky 1667 1.2 christos static int 1668 1.2 christos evhttp_parse_http_version(const char *version, struct evhttp_request *req) 1669 1.2 christos { 1670 1.2 christos int major, minor; 1671 1.2 christos char ch; 1672 1.2 christos int n = sscanf(version, "HTTP/%d.%d%c", &major, &minor, &ch); 1673 1.2 christos if (n != 2 || major > 1) { 1674 1.2 christos event_debug(("%s: bad version %s on message %p from %s", 1675 1.2 christos __func__, version, req, req->remote_host)); 1676 1.2 christos return (-1); 1677 1.2 christos } 1678 1.2 christos req->major = major; 1679 1.2 christos req->minor = minor; 1680 1.2 christos return (0); 1681 1.2 christos } 1682 1.2 christos 1683 1.1 plunky /* Parses the status line of a web server */ 1684 1.1 plunky 1685 1.1 plunky static int 1686 1.1 plunky evhttp_parse_response_line(struct evhttp_request *req, char *line) 1687 1.1 plunky { 1688 1.1 plunky char *protocol; 1689 1.1 plunky char *number; 1690 1.2 christos const char *readable = ""; 1691 1.1 plunky 1692 1.1 plunky protocol = strsep(&line, " "); 1693 1.1 plunky if (line == NULL) 1694 1.1 plunky return (-1); 1695 1.1 plunky number = strsep(&line, " "); 1696 1.2 christos if (line != NULL) 1697 1.2 christos readable = line; 1698 1.1 plunky 1699 1.2 christos if (evhttp_parse_http_version(protocol, req) < 0) 1700 1.1 plunky return (-1); 1701 1.1 plunky 1702 1.1 plunky req->response_code = atoi(number); 1703 1.1 plunky if (!evhttp_valid_response_code(req->response_code)) { 1704 1.1 plunky event_debug(("%s: bad response code \"%s\"", 1705 1.1 plunky __func__, number)); 1706 1.1 plunky return (-1); 1707 1.1 plunky } 1708 1.1 plunky 1709 1.4 christos if (req->response_code_line != NULL) 1710 1.4 christos mm_free(req->response_code_line); 1711 1.2 christos if ((req->response_code_line = mm_strdup(readable)) == NULL) { 1712 1.2 christos event_warn("%s: strdup", __func__); 1713 1.2 christos return (-1); 1714 1.2 christos } 1715 1.1 plunky 1716 1.1 plunky return (0); 1717 1.1 plunky } 1718 1.1 plunky 1719 1.1 plunky /* Parse the first line of a HTTP request */ 1720 1.1 plunky 1721 1.1 plunky static int 1722 1.5 christos evhttp_parse_request_line(struct evhttp_request *req, char *line, size_t len) 1723 1.1 plunky { 1724 1.5 christos char *eos = line + len; 1725 1.1 plunky char *method; 1726 1.1 plunky char *uri; 1727 1.1 plunky char *version; 1728 1.2 christos const char *hostname; 1729 1.2 christos const char *scheme; 1730 1.4 christos size_t method_len; 1731 1.4 christos enum evhttp_cmd_type type; 1732 1.1 plunky 1733 1.5 christos while (eos > line && *(eos-1) == ' ') { 1734 1.5 christos *(eos-1) = '\0'; 1735 1.5 christos --eos; 1736 1.5 christos --len; 1737 1.5 christos } 1738 1.5 christos if (len < strlen("GET / HTTP/1.0")) 1739 1.5 christos return -1; 1740 1.5 christos 1741 1.1 plunky /* Parse the request line */ 1742 1.1 plunky method = strsep(&line, " "); 1743 1.5 christos if (!line) 1744 1.5 christos return -1; 1745 1.5 christos uri = line; 1746 1.5 christos version = strrchr(uri, ' '); 1747 1.5 christos if (!version || uri == version) 1748 1.5 christos return -1; 1749 1.5 christos *version = '\0'; 1750 1.5 christos version++; 1751 1.1 plunky 1752 1.4 christos method_len = (uri - method) - 1; 1753 1.4 christos type = EVHTTP_REQ_UNKNOWN_; 1754 1.4 christos 1755 1.1 plunky /* First line */ 1756 1.4 christos switch (method_len) { 1757 1.4 christos case 3: 1758 1.4 christos /* The length of the method string is 3, meaning it can only be one of two methods: GET or PUT */ 1759 1.4 christos 1760 1.4 christos /* Since both GET and PUT share the same character 'T' at the end, 1761 1.4 christos * if the string doesn't have 'T', we can immediately determine this 1762 1.4 christos * is an invalid HTTP method */ 1763 1.4 christos 1764 1.4 christos if (method[2] != 'T') { 1765 1.4 christos break; 1766 1.4 christos } 1767 1.4 christos 1768 1.4 christos switch (*method) { 1769 1.4 christos case 'G': 1770 1.4 christos /* This first byte is 'G', so make sure the next byte is 1771 1.4 christos * 'E', if it isn't then this isn't a valid method */ 1772 1.4 christos 1773 1.4 christos if (method[1] == 'E') { 1774 1.4 christos type = EVHTTP_REQ_GET; 1775 1.4 christos } 1776 1.4 christos 1777 1.4 christos break; 1778 1.4 christos case 'P': 1779 1.4 christos /* First byte is P, check second byte for 'U', if not, 1780 1.4 christos * we know it's an invalid method */ 1781 1.4 christos if (method[1] == 'U') { 1782 1.4 christos type = EVHTTP_REQ_PUT; 1783 1.4 christos } 1784 1.4 christos break; 1785 1.4 christos default: 1786 1.4 christos break; 1787 1.4 christos } 1788 1.4 christos break; 1789 1.4 christos case 4: 1790 1.4 christos /* The method length is 4 bytes, leaving only the methods "POST" and "HEAD" */ 1791 1.4 christos switch (*method) { 1792 1.4 christos case 'P': 1793 1.4 christos if (method[3] == 'T' && method[2] == 'S' && method[1] == 'O') { 1794 1.4 christos type = EVHTTP_REQ_POST; 1795 1.4 christos } 1796 1.4 christos break; 1797 1.4 christos case 'H': 1798 1.4 christos if (method[3] == 'D' && method[2] == 'A' && method[1] == 'E') { 1799 1.4 christos type = EVHTTP_REQ_HEAD; 1800 1.4 christos } 1801 1.4 christos break; 1802 1.4 christos default: 1803 1.4 christos break; 1804 1.4 christos } 1805 1.4 christos break; 1806 1.4 christos case 5: 1807 1.4 christos /* Method length is 5 bytes, which can only encompass PATCH and TRACE */ 1808 1.4 christos switch (*method) { 1809 1.4 christos case 'P': 1810 1.4 christos if (method[4] == 'H' && method[3] == 'C' && method[2] == 'T' && method[1] == 'A') { 1811 1.4 christos type = EVHTTP_REQ_PATCH; 1812 1.4 christos } 1813 1.4 christos break; 1814 1.4 christos case 'T': 1815 1.4 christos if (method[4] == 'E' && method[3] == 'C' && method[2] == 'A' && method[1] == 'R') { 1816 1.4 christos type = EVHTTP_REQ_TRACE; 1817 1.4 christos } 1818 1.4 christos 1819 1.4 christos break; 1820 1.4 christos default: 1821 1.4 christos break; 1822 1.4 christos } 1823 1.4 christos break; 1824 1.4 christos case 6: 1825 1.4 christos /* Method length is 6, only valid method 6 bytes in length is DELEte */ 1826 1.4 christos 1827 1.4 christos /* If the first byte isn't 'D' then it's invalid */ 1828 1.4 christos if (*method != 'D') { 1829 1.4 christos break; 1830 1.4 christos } 1831 1.4 christos 1832 1.4 christos if (method[5] == 'E' && method[4] == 'T' && method[3] == 'E' && method[2] == 'L' && method[1] == 'E') { 1833 1.4 christos type = EVHTTP_REQ_DELETE; 1834 1.4 christos } 1835 1.4 christos 1836 1.4 christos break; 1837 1.4 christos case 7: 1838 1.4 christos /* Method length is 7, only valid methods are "OPTIONS" and "CONNECT" */ 1839 1.4 christos switch (*method) { 1840 1.4 christos case 'O': 1841 1.4 christos if (method[6] == 'S' && method[5] == 'N' && method[4] == 'O' && 1842 1.4 christos method[3] == 'I' && method[2] == 'T' && method[1] == 'P') { 1843 1.4 christos type = EVHTTP_REQ_OPTIONS; 1844 1.4 christos } 1845 1.4 christos 1846 1.4 christos break; 1847 1.4 christos case 'C': 1848 1.4 christos if (method[6] == 'T' && method[5] == 'C' && method[4] == 'E' && 1849 1.4 christos method[3] == 'N' && method[2] == 'N' && method[1] == 'O') { 1850 1.4 christos type = EVHTTP_REQ_CONNECT; 1851 1.4 christos } 1852 1.4 christos 1853 1.4 christos break; 1854 1.4 christos default: 1855 1.4 christos break; 1856 1.4 christos } 1857 1.4 christos break; 1858 1.4 christos } /* switch */ 1859 1.4 christos 1860 1.4 christos if ((int)type == EVHTTP_REQ_UNKNOWN_) { 1861 1.4 christos event_debug(("%s: bad method %s on request %p from %s", 1862 1.1 plunky __func__, method, req, req->remote_host)); 1863 1.4 christos /* No error yet; we'll give a better error later when 1864 1.4 christos * we see that req->type is unsupported. */ 1865 1.2 christos } 1866 1.4 christos 1867 1.4 christos req->type = type; 1868 1.2 christos 1869 1.2 christos if (evhttp_parse_http_version(version, req) < 0) 1870 1.5 christos return -1; 1871 1.1 plunky 1872 1.2 christos if ((req->uri = mm_strdup(uri)) == NULL) { 1873 1.2 christos event_debug(("%s: mm_strdup", __func__)); 1874 1.5 christos return -1; 1875 1.1 plunky } 1876 1.1 plunky 1877 1.5 christos if (type == EVHTTP_REQ_CONNECT) { 1878 1.5 christos if ((req->uri_elems = evhttp_uri_parse_authority(req->uri)) == NULL) { 1879 1.5 christos return -1; 1880 1.5 christos } 1881 1.5 christos } else { 1882 1.5 christos if ((req->uri_elems = evhttp_uri_parse_with_flags(req->uri, 1883 1.5 christos EVHTTP_URI_NONCONFORMANT)) == NULL) { 1884 1.5 christos return -1; 1885 1.5 christos } 1886 1.1 plunky } 1887 1.1 plunky 1888 1.2 christos /* If we have an absolute-URI, check to see if it is an http request 1889 1.2 christos for a known vhost or server alias. If we don't know about this 1890 1.2 christos host, we consider it a proxy request. */ 1891 1.2 christos scheme = evhttp_uri_get_scheme(req->uri_elems); 1892 1.2 christos hostname = evhttp_uri_get_host(req->uri_elems); 1893 1.2 christos if (scheme && (!evutil_ascii_strcasecmp(scheme, "http") || 1894 1.2 christos !evutil_ascii_strcasecmp(scheme, "https")) && 1895 1.2 christos hostname && 1896 1.2 christos !evhttp_find_vhost(req->evcon->http_server, NULL, hostname)) 1897 1.1 plunky req->flags |= EVHTTP_PROXY_REQUEST; 1898 1.1 plunky 1899 1.5 christos return 0; 1900 1.1 plunky } 1901 1.1 plunky 1902 1.1 plunky const char * 1903 1.1 plunky evhttp_find_header(const struct evkeyvalq *headers, const char *key) 1904 1.1 plunky { 1905 1.1 plunky struct evkeyval *header; 1906 1.1 plunky 1907 1.1 plunky TAILQ_FOREACH(header, headers, next) { 1908 1.2 christos if (evutil_ascii_strcasecmp(header->key, key) == 0) 1909 1.1 plunky return (header->value); 1910 1.1 plunky } 1911 1.1 plunky 1912 1.1 plunky return (NULL); 1913 1.1 plunky } 1914 1.1 plunky 1915 1.1 plunky void 1916 1.1 plunky evhttp_clear_headers(struct evkeyvalq *headers) 1917 1.1 plunky { 1918 1.1 plunky struct evkeyval *header; 1919 1.1 plunky 1920 1.1 plunky for (header = TAILQ_FIRST(headers); 1921 1.1 plunky header != NULL; 1922 1.1 plunky header = TAILQ_FIRST(headers)) { 1923 1.1 plunky TAILQ_REMOVE(headers, header, next); 1924 1.2 christos mm_free(header->key); 1925 1.2 christos mm_free(header->value); 1926 1.2 christos mm_free(header); 1927 1.1 plunky } 1928 1.1 plunky } 1929 1.1 plunky 1930 1.1 plunky /* 1931 1.1 plunky * Returns 0, if the header was successfully removed. 1932 1.1 plunky * Returns -1, if the header could not be found. 1933 1.1 plunky */ 1934 1.1 plunky 1935 1.1 plunky int 1936 1.1 plunky evhttp_remove_header(struct evkeyvalq *headers, const char *key) 1937 1.1 plunky { 1938 1.1 plunky struct evkeyval *header; 1939 1.1 plunky 1940 1.1 plunky TAILQ_FOREACH(header, headers, next) { 1941 1.2 christos if (evutil_ascii_strcasecmp(header->key, key) == 0) 1942 1.1 plunky break; 1943 1.1 plunky } 1944 1.1 plunky 1945 1.1 plunky if (header == NULL) 1946 1.1 plunky return (-1); 1947 1.1 plunky 1948 1.1 plunky /* Free and remove the header that we found */ 1949 1.1 plunky TAILQ_REMOVE(headers, header, next); 1950 1.2 christos mm_free(header->key); 1951 1.2 christos mm_free(header->value); 1952 1.2 christos mm_free(header); 1953 1.1 plunky 1954 1.1 plunky return (0); 1955 1.1 plunky } 1956 1.1 plunky 1957 1.1 plunky static int 1958 1.1 plunky evhttp_header_is_valid_value(const char *value) 1959 1.1 plunky { 1960 1.1 plunky const char *p = value; 1961 1.1 plunky 1962 1.1 plunky while ((p = strpbrk(p, "\r\n")) != NULL) { 1963 1.1 plunky /* we really expect only one new line */ 1964 1.1 plunky p += strspn(p, "\r\n"); 1965 1.1 plunky /* we expect a space or tab for continuation */ 1966 1.1 plunky if (*p != ' ' && *p != '\t') 1967 1.1 plunky return (0); 1968 1.1 plunky } 1969 1.1 plunky return (1); 1970 1.1 plunky } 1971 1.1 plunky 1972 1.1 plunky int 1973 1.1 plunky evhttp_add_header(struct evkeyvalq *headers, 1974 1.1 plunky const char *key, const char *value) 1975 1.1 plunky { 1976 1.1 plunky event_debug(("%s: key: %s val: %s\n", __func__, key, value)); 1977 1.1 plunky 1978 1.1 plunky if (strchr(key, '\r') != NULL || strchr(key, '\n') != NULL) { 1979 1.1 plunky /* drop illegal headers */ 1980 1.1 plunky event_debug(("%s: dropping illegal header key\n", __func__)); 1981 1.1 plunky return (-1); 1982 1.1 plunky } 1983 1.2 christos 1984 1.1 plunky if (!evhttp_header_is_valid_value(value)) { 1985 1.1 plunky event_debug(("%s: dropping illegal header value\n", __func__)); 1986 1.1 plunky return (-1); 1987 1.1 plunky } 1988 1.1 plunky 1989 1.1 plunky return (evhttp_add_header_internal(headers, key, value)); 1990 1.1 plunky } 1991 1.1 plunky 1992 1.1 plunky static int 1993 1.1 plunky evhttp_add_header_internal(struct evkeyvalq *headers, 1994 1.1 plunky const char *key, const char *value) 1995 1.1 plunky { 1996 1.2 christos struct evkeyval *header = mm_calloc(1, sizeof(struct evkeyval)); 1997 1.1 plunky if (header == NULL) { 1998 1.1 plunky event_warn("%s: calloc", __func__); 1999 1.1 plunky return (-1); 2000 1.1 plunky } 2001 1.2 christos if ((header->key = mm_strdup(key)) == NULL) { 2002 1.2 christos mm_free(header); 2003 1.1 plunky event_warn("%s: strdup", __func__); 2004 1.1 plunky return (-1); 2005 1.1 plunky } 2006 1.2 christos if ((header->value = mm_strdup(value)) == NULL) { 2007 1.2 christos mm_free(header->key); 2008 1.2 christos mm_free(header); 2009 1.1 plunky event_warn("%s: strdup", __func__); 2010 1.1 plunky return (-1); 2011 1.1 plunky } 2012 1.1 plunky 2013 1.1 plunky TAILQ_INSERT_TAIL(headers, header, next); 2014 1.1 plunky 2015 1.1 plunky return (0); 2016 1.1 plunky } 2017 1.1 plunky 2018 1.1 plunky /* 2019 1.1 plunky * Parses header lines from a request or a response into the specified 2020 1.1 plunky * request object given an event buffer. 2021 1.1 plunky * 2022 1.1 plunky * Returns 2023 1.1 plunky * DATA_CORRUPTED on error 2024 1.1 plunky * MORE_DATA_EXPECTED when we need to read more headers 2025 1.1 plunky * ALL_DATA_READ when all headers have been read. 2026 1.1 plunky */ 2027 1.1 plunky 2028 1.1 plunky enum message_read_status 2029 1.4 christos evhttp_parse_firstline_(struct evhttp_request *req, struct evbuffer *buffer) 2030 1.1 plunky { 2031 1.1 plunky char *line; 2032 1.1 plunky enum message_read_status status = ALL_DATA_READ; 2033 1.1 plunky 2034 1.5 christos size_t len; 2035 1.2 christos /* XXX try */ 2036 1.5 christos line = evbuffer_readln(buffer, &len, EVBUFFER_EOL_CRLF); 2037 1.2 christos if (line == NULL) { 2038 1.2 christos if (req->evcon != NULL && 2039 1.2 christos evbuffer_get_length(buffer) > req->evcon->max_headers_size) 2040 1.2 christos return (DATA_TOO_LONG); 2041 1.2 christos else 2042 1.2 christos return (MORE_DATA_EXPECTED); 2043 1.2 christos } 2044 1.2 christos 2045 1.5 christos if (req->evcon != NULL && len > req->evcon->max_headers_size) { 2046 1.2 christos mm_free(line); 2047 1.2 christos return (DATA_TOO_LONG); 2048 1.2 christos } 2049 1.2 christos 2050 1.5 christos req->headers_size = len; 2051 1.1 plunky 2052 1.1 plunky switch (req->kind) { 2053 1.1 plunky case EVHTTP_REQUEST: 2054 1.5 christos if (evhttp_parse_request_line(req, line, len) == -1) 2055 1.1 plunky status = DATA_CORRUPTED; 2056 1.1 plunky break; 2057 1.1 plunky case EVHTTP_RESPONSE: 2058 1.1 plunky if (evhttp_parse_response_line(req, line) == -1) 2059 1.1 plunky status = DATA_CORRUPTED; 2060 1.1 plunky break; 2061 1.1 plunky default: 2062 1.1 plunky status = DATA_CORRUPTED; 2063 1.1 plunky } 2064 1.1 plunky 2065 1.2 christos mm_free(line); 2066 1.1 plunky return (status); 2067 1.1 plunky } 2068 1.1 plunky 2069 1.1 plunky static int 2070 1.4 christos evhttp_append_to_last_header(struct evkeyvalq *headers, char *line) 2071 1.1 plunky { 2072 1.1 plunky struct evkeyval *header = TAILQ_LAST(headers, evkeyvalq); 2073 1.1 plunky char *newval; 2074 1.1 plunky size_t old_len, line_len; 2075 1.1 plunky 2076 1.1 plunky if (header == NULL) 2077 1.1 plunky return (-1); 2078 1.1 plunky 2079 1.1 plunky old_len = strlen(header->value); 2080 1.4 christos 2081 1.4 christos /* Strip space from start and end of line. */ 2082 1.4 christos while (*line == ' ' || *line == '\t') 2083 1.4 christos ++line; 2084 1.4 christos evutil_rtrim_lws_(line); 2085 1.4 christos 2086 1.1 plunky line_len = strlen(line); 2087 1.1 plunky 2088 1.4 christos newval = mm_realloc(header->value, old_len + line_len + 2); 2089 1.1 plunky if (newval == NULL) 2090 1.1 plunky return (-1); 2091 1.1 plunky 2092 1.4 christos newval[old_len] = ' '; 2093 1.4 christos memcpy(newval + old_len + 1, line, line_len + 1); 2094 1.1 plunky header->value = newval; 2095 1.1 plunky 2096 1.1 plunky return (0); 2097 1.1 plunky } 2098 1.1 plunky 2099 1.1 plunky enum message_read_status 2100 1.4 christos evhttp_parse_headers_(struct evhttp_request *req, struct evbuffer* buffer) 2101 1.1 plunky { 2102 1.2 christos enum message_read_status errcode = DATA_CORRUPTED; 2103 1.1 plunky char *line; 2104 1.1 plunky enum message_read_status status = MORE_DATA_EXPECTED; 2105 1.1 plunky 2106 1.1 plunky struct evkeyvalq* headers = req->input_headers; 2107 1.5 christos size_t len; 2108 1.5 christos while ((line = evbuffer_readln(buffer, &len, EVBUFFER_EOL_CRLF)) 2109 1.1 plunky != NULL) { 2110 1.1 plunky char *skey, *svalue; 2111 1.1 plunky 2112 1.5 christos req->headers_size += len; 2113 1.2 christos 2114 1.2 christos if (req->evcon != NULL && 2115 1.2 christos req->headers_size > req->evcon->max_headers_size) { 2116 1.2 christos errcode = DATA_TOO_LONG; 2117 1.2 christos goto error; 2118 1.2 christos } 2119 1.2 christos 2120 1.1 plunky if (*line == '\0') { /* Last header - Done */ 2121 1.1 plunky status = ALL_DATA_READ; 2122 1.2 christos mm_free(line); 2123 1.1 plunky break; 2124 1.1 plunky } 2125 1.1 plunky 2126 1.1 plunky /* Check if this is a continuation line */ 2127 1.1 plunky if (*line == ' ' || *line == '\t') { 2128 1.1 plunky if (evhttp_append_to_last_header(headers, line) == -1) 2129 1.1 plunky goto error; 2130 1.2 christos mm_free(line); 2131 1.1 plunky continue; 2132 1.1 plunky } 2133 1.1 plunky 2134 1.1 plunky /* Processing of header lines */ 2135 1.1 plunky svalue = line; 2136 1.1 plunky skey = strsep(&svalue, ":"); 2137 1.1 plunky if (svalue == NULL) 2138 1.1 plunky goto error; 2139 1.1 plunky 2140 1.1 plunky svalue += strspn(svalue, " "); 2141 1.4 christos evutil_rtrim_lws_(svalue); 2142 1.1 plunky 2143 1.1 plunky if (evhttp_add_header(headers, skey, svalue) == -1) 2144 1.1 plunky goto error; 2145 1.1 plunky 2146 1.2 christos mm_free(line); 2147 1.2 christos } 2148 1.2 christos 2149 1.2 christos if (status == MORE_DATA_EXPECTED) { 2150 1.2 christos if (req->evcon != NULL && 2151 1.2 christos req->headers_size + evbuffer_get_length(buffer) > req->evcon->max_headers_size) 2152 1.2 christos return (DATA_TOO_LONG); 2153 1.1 plunky } 2154 1.1 plunky 2155 1.1 plunky return (status); 2156 1.1 plunky 2157 1.1 plunky error: 2158 1.2 christos mm_free(line); 2159 1.2 christos return (errcode); 2160 1.1 plunky } 2161 1.1 plunky 2162 1.1 plunky static int 2163 1.1 plunky evhttp_get_body_length(struct evhttp_request *req) 2164 1.1 plunky { 2165 1.1 plunky struct evkeyvalq *headers = req->input_headers; 2166 1.1 plunky const char *content_length; 2167 1.1 plunky const char *connection; 2168 1.1 plunky 2169 1.1 plunky content_length = evhttp_find_header(headers, "Content-Length"); 2170 1.1 plunky connection = evhttp_find_header(headers, "Connection"); 2171 1.2 christos 2172 1.1 plunky if (content_length == NULL && connection == NULL) 2173 1.1 plunky req->ntoread = -1; 2174 1.1 plunky else if (content_length == NULL && 2175 1.2 christos evutil_ascii_strcasecmp(connection, "Close") != 0) { 2176 1.5 christos req->ntoread = 0; 2177 1.1 plunky } else if (content_length == NULL) { 2178 1.1 plunky req->ntoread = -1; 2179 1.1 plunky } else { 2180 1.1 plunky char *endp; 2181 1.1 plunky ev_int64_t ntoread = evutil_strtoll(content_length, &endp, 10); 2182 1.1 plunky if (*content_length == '\0' || *endp != '\0' || ntoread < 0) { 2183 1.1 plunky event_debug(("%s: illegal content length: %s", 2184 1.1 plunky __func__, content_length)); 2185 1.1 plunky return (-1); 2186 1.1 plunky } 2187 1.1 plunky req->ntoread = ntoread; 2188 1.1 plunky } 2189 1.2 christos 2190 1.2 christos event_debug(("%s: bytes to read: "EV_I64_FMT" (in buffer "EV_SIZE_FMT")\n", 2191 1.2 christos __func__, EV_I64_ARG(req->ntoread), 2192 1.2 christos EV_SIZE_ARG(evbuffer_get_length(bufferevent_get_input(req->evcon->bufev))))); 2193 1.1 plunky 2194 1.1 plunky return (0); 2195 1.1 plunky } 2196 1.1 plunky 2197 1.2 christos static int 2198 1.2 christos evhttp_method_may_have_body(enum evhttp_cmd_type type) 2199 1.2 christos { 2200 1.2 christos switch (type) { 2201 1.2 christos case EVHTTP_REQ_POST: 2202 1.2 christos case EVHTTP_REQ_PUT: 2203 1.2 christos case EVHTTP_REQ_PATCH: 2204 1.5 christos 2205 1.2 christos case EVHTTP_REQ_GET: 2206 1.2 christos case EVHTTP_REQ_DELETE: 2207 1.2 christos case EVHTTP_REQ_OPTIONS: 2208 1.2 christos case EVHTTP_REQ_CONNECT: 2209 1.5 christos return 1; 2210 1.5 christos 2211 1.5 christos case EVHTTP_REQ_TRACE: 2212 1.5 christos case EVHTTP_REQ_HEAD: 2213 1.2 christos default: 2214 1.2 christos return 0; 2215 1.2 christos } 2216 1.2 christos } 2217 1.2 christos 2218 1.1 plunky static void 2219 1.1 plunky evhttp_get_body(struct evhttp_connection *evcon, struct evhttp_request *req) 2220 1.1 plunky { 2221 1.1 plunky const char *xfer_enc; 2222 1.2 christos 2223 1.1 plunky /* If this is a request without a body, then we are done */ 2224 1.2 christos if (req->kind == EVHTTP_REQUEST && 2225 1.2 christos !evhttp_method_may_have_body(req->type)) { 2226 1.1 plunky evhttp_connection_done(evcon); 2227 1.1 plunky return; 2228 1.1 plunky } 2229 1.1 plunky evcon->state = EVCON_READING_BODY; 2230 1.1 plunky xfer_enc = evhttp_find_header(req->input_headers, "Transfer-Encoding"); 2231 1.2 christos if (xfer_enc != NULL && evutil_ascii_strcasecmp(xfer_enc, "chunked") == 0) { 2232 1.1 plunky req->chunked = 1; 2233 1.1 plunky req->ntoread = -1; 2234 1.1 plunky } else { 2235 1.1 plunky if (evhttp_get_body_length(req) == -1) { 2236 1.4 christos evhttp_connection_fail_(evcon, EVREQ_HTTP_INVALID_HEADER); 2237 1.1 plunky return; 2238 1.1 plunky } 2239 1.2 christos if (req->kind == EVHTTP_REQUEST && req->ntoread < 1) { 2240 1.2 christos /* An incoming request with no content-length and no 2241 1.2 christos * transfer-encoding has no body. */ 2242 1.2 christos evhttp_connection_done(evcon); 2243 1.2 christos return; 2244 1.2 christos } 2245 1.2 christos } 2246 1.2 christos 2247 1.2 christos /* Should we send a 100 Continue status line? */ 2248 1.4 christos switch (evhttp_have_expect(req, 1)) { 2249 1.4 christos case CONTINUE: 2250 1.2 christos /* XXX It would be nice to do some sanity 2251 1.2 christos checking here. Does the resource exist? 2252 1.2 christos Should the resource accept post requests? If 2253 1.2 christos no, we should respond with an error. For 2254 1.2 christos now, just optimistically tell the client to 2255 1.2 christos send their message body. */ 2256 1.2 christos if (req->ntoread > 0) { 2257 1.2 christos /* ntoread is ev_int64_t, max_body_size is ev_uint64_t */ 2258 1.4 christos if ((req->evcon->max_body_size <= EV_INT64_MAX) && 2259 1.4 christos (ev_uint64_t)req->ntoread > req->evcon->max_body_size) { 2260 1.4 christos evhttp_lingering_fail(evcon, req); 2261 1.2 christos return; 2262 1.2 christos } 2263 1.2 christos } 2264 1.2 christos if (!evbuffer_get_length(bufferevent_get_input(evcon->bufev))) 2265 1.2 christos evhttp_send_continue(evcon, req); 2266 1.4 christos break; 2267 1.4 christos case OTHER: 2268 1.4 christos evhttp_send_error(req, HTTP_EXPECTATIONFAILED, NULL); 2269 1.4 christos return; 2270 1.4 christos case NO: break; 2271 1.1 plunky } 2272 1.2 christos 2273 1.1 plunky evhttp_read_body(evcon, req); 2274 1.2 christos /* note the request may have been freed in evhttp_read_body */ 2275 1.1 plunky } 2276 1.1 plunky 2277 1.1 plunky static void 2278 1.1 plunky evhttp_read_firstline(struct evhttp_connection *evcon, 2279 1.1 plunky struct evhttp_request *req) 2280 1.1 plunky { 2281 1.1 plunky enum message_read_status res; 2282 1.1 plunky 2283 1.4 christos res = evhttp_parse_firstline_(req, bufferevent_get_input(evcon->bufev)); 2284 1.2 christos if (res == DATA_CORRUPTED || res == DATA_TOO_LONG) { 2285 1.1 plunky /* Error while reading, terminate */ 2286 1.2 christos event_debug(("%s: bad header lines on "EV_SOCK_FMT"\n", 2287 1.2 christos __func__, EV_SOCK_ARG(evcon->fd))); 2288 1.4 christos evhttp_connection_fail_(evcon, EVREQ_HTTP_INVALID_HEADER); 2289 1.1 plunky return; 2290 1.1 plunky } else if (res == MORE_DATA_EXPECTED) { 2291 1.1 plunky /* Need more header lines */ 2292 1.1 plunky return; 2293 1.1 plunky } 2294 1.1 plunky 2295 1.1 plunky evcon->state = EVCON_READING_HEADERS; 2296 1.1 plunky evhttp_read_header(evcon, req); 2297 1.1 plunky } 2298 1.1 plunky 2299 1.1 plunky static void 2300 1.2 christos evhttp_read_header(struct evhttp_connection *evcon, 2301 1.2 christos struct evhttp_request *req) 2302 1.1 plunky { 2303 1.1 plunky enum message_read_status res; 2304 1.2 christos evutil_socket_t fd = evcon->fd; 2305 1.1 plunky 2306 1.4 christos res = evhttp_parse_headers_(req, bufferevent_get_input(evcon->bufev)); 2307 1.2 christos if (res == DATA_CORRUPTED || res == DATA_TOO_LONG) { 2308 1.1 plunky /* Error while reading, terminate */ 2309 1.2 christos event_debug(("%s: bad header lines on "EV_SOCK_FMT"\n", 2310 1.2 christos __func__, EV_SOCK_ARG(fd))); 2311 1.4 christos evhttp_connection_fail_(evcon, EVREQ_HTTP_INVALID_HEADER); 2312 1.1 plunky return; 2313 1.1 plunky } else if (res == MORE_DATA_EXPECTED) { 2314 1.1 plunky /* Need more header lines */ 2315 1.1 plunky return; 2316 1.1 plunky } 2317 1.1 plunky 2318 1.4 christos /* Callback can shut down connection with negative return value */ 2319 1.4 christos if (req->header_cb != NULL) { 2320 1.4 christos if ((*req->header_cb)(req, req->cb_arg) < 0) { 2321 1.4 christos evhttp_connection_fail_(evcon, EVREQ_HTTP_EOF); 2322 1.4 christos return; 2323 1.4 christos } 2324 1.4 christos } 2325 1.2 christos 2326 1.1 plunky /* Done reading headers, do the real work */ 2327 1.1 plunky switch (req->kind) { 2328 1.1 plunky case EVHTTP_REQUEST: 2329 1.2 christos event_debug(("%s: checking for post data on "EV_SOCK_FMT"\n", 2330 1.2 christos __func__, EV_SOCK_ARG(fd))); 2331 1.1 plunky evhttp_get_body(evcon, req); 2332 1.2 christos /* note the request may have been freed in evhttp_get_body */ 2333 1.1 plunky break; 2334 1.1 plunky 2335 1.1 plunky case EVHTTP_RESPONSE: 2336 1.2 christos /* Start over if we got a 100 Continue response. */ 2337 1.2 christos if (req->response_code == 100) { 2338 1.4 christos struct evbuffer *output = bufferevent_get_output(evcon->bufev); 2339 1.4 christos evbuffer_add_buffer(output, req->output_buffer); 2340 1.4 christos evhttp_start_write_(evcon); 2341 1.2 christos return; 2342 1.2 christos } 2343 1.2 christos if (!evhttp_response_needs_body(req)) { 2344 1.1 plunky event_debug(("%s: skipping body for code %d\n", 2345 1.1 plunky __func__, req->response_code)); 2346 1.1 plunky evhttp_connection_done(evcon); 2347 1.1 plunky } else { 2348 1.2 christos event_debug(("%s: start of read body for %s on " 2349 1.2 christos EV_SOCK_FMT"\n", 2350 1.2 christos __func__, req->remote_host, EV_SOCK_ARG(fd))); 2351 1.1 plunky evhttp_get_body(evcon, req); 2352 1.2 christos /* note the request may have been freed in 2353 1.2 christos * evhttp_get_body */ 2354 1.1 plunky } 2355 1.1 plunky break; 2356 1.1 plunky 2357 1.1 plunky default: 2358 1.2 christos event_warnx("%s: bad header on "EV_SOCK_FMT, __func__, 2359 1.2 christos EV_SOCK_ARG(fd)); 2360 1.4 christos evhttp_connection_fail_(evcon, EVREQ_HTTP_INVALID_HEADER); 2361 1.1 plunky break; 2362 1.1 plunky } 2363 1.2 christos /* request may have been freed above */ 2364 1.1 plunky } 2365 1.1 plunky 2366 1.1 plunky /* 2367 1.1 plunky * Creates a TCP connection to the specified port and executes a callback 2368 1.2 christos * when finished. Failure or success is indicate by the passed connection 2369 1.1 plunky * object. 2370 1.1 plunky * 2371 1.1 plunky * Although this interface accepts a hostname, it is intended to take 2372 1.1 plunky * only numeric hostnames so that non-blocking DNS resolution can 2373 1.1 plunky * happen elsewhere. 2374 1.1 plunky */ 2375 1.1 plunky 2376 1.1 plunky struct evhttp_connection * 2377 1.4 christos evhttp_connection_new(const char *address, ev_uint16_t port) 2378 1.1 plunky { 2379 1.2 christos return (evhttp_connection_base_new(NULL, NULL, address, port)); 2380 1.2 christos } 2381 1.2 christos 2382 1.2 christos struct evhttp_connection * 2383 1.4 christos evhttp_connection_base_bufferevent_new(struct event_base *base, struct evdns_base *dnsbase, struct bufferevent* bev, 2384 1.4 christos const char *address, ev_uint16_t port) 2385 1.2 christos { 2386 1.1 plunky struct evhttp_connection *evcon = NULL; 2387 1.2 christos 2388 1.1 plunky event_debug(("Attempting connection to %s:%d\n", address, port)); 2389 1.1 plunky 2390 1.2 christos if ((evcon = mm_calloc(1, sizeof(struct evhttp_connection))) == NULL) { 2391 1.1 plunky event_warn("%s: calloc failed", __func__); 2392 1.1 plunky goto error; 2393 1.1 plunky } 2394 1.1 plunky 2395 1.1 plunky evcon->fd = -1; 2396 1.1 plunky evcon->port = port; 2397 1.1 plunky 2398 1.2 christos evcon->max_headers_size = EV_SIZE_MAX; 2399 1.2 christos evcon->max_body_size = EV_SIZE_MAX; 2400 1.2 christos 2401 1.4 christos evutil_timerclear(&evcon->timeout); 2402 1.1 plunky evcon->retry_cnt = evcon->retry_max = 0; 2403 1.1 plunky 2404 1.2 christos if ((evcon->address = mm_strdup(address)) == NULL) { 2405 1.1 plunky event_warn("%s: strdup failed", __func__); 2406 1.1 plunky goto error; 2407 1.1 plunky } 2408 1.1 plunky 2409 1.4 christos if (bev == NULL) { 2410 1.4 christos if (!(bev = bufferevent_socket_new(base, -1, 0))) { 2411 1.4 christos event_warn("%s: bufferevent_socket_new failed", __func__); 2412 1.4 christos goto error; 2413 1.4 christos } 2414 1.1 plunky } 2415 1.1 plunky 2416 1.4 christos bufferevent_setcb(bev, evhttp_read_cb, evhttp_write_cb, evhttp_error_cb, evcon); 2417 1.4 christos evcon->bufev = bev; 2418 1.4 christos 2419 1.1 plunky evcon->state = EVCON_DISCONNECTED; 2420 1.1 plunky TAILQ_INIT(&evcon->requests); 2421 1.1 plunky 2422 1.4 christos evcon->initial_retry_timeout.tv_sec = 2; 2423 1.4 christos evcon->initial_retry_timeout.tv_usec = 0; 2424 1.4 christos 2425 1.2 christos if (base != NULL) { 2426 1.2 christos evcon->base = base; 2427 1.4 christos if (bufferevent_get_base(bev) != base) 2428 1.4 christos bufferevent_base_set(base, evcon->bufev); 2429 1.2 christos } 2430 1.2 christos 2431 1.4 christos event_deferred_cb_init_( 2432 1.4 christos &evcon->read_more_deferred_cb, 2433 1.4 christos bufferevent_get_priority(bev), 2434 1.2 christos evhttp_deferred_read_cb, evcon); 2435 1.2 christos 2436 1.2 christos evcon->dns_base = dnsbase; 2437 1.4 christos evcon->ai_family = AF_UNSPEC; 2438 1.2 christos 2439 1.1 plunky return (evcon); 2440 1.2 christos 2441 1.1 plunky error: 2442 1.1 plunky if (evcon != NULL) 2443 1.1 plunky evhttp_connection_free(evcon); 2444 1.1 plunky return (NULL); 2445 1.1 plunky } 2446 1.1 plunky 2447 1.4 christos struct bufferevent* evhttp_connection_get_bufferevent(struct evhttp_connection *evcon) 2448 1.2 christos { 2449 1.2 christos return evcon->bufev; 2450 1.2 christos } 2451 1.2 christos 2452 1.4 christos struct evhttp * 2453 1.4 christos evhttp_connection_get_server(struct evhttp_connection *evcon) 2454 1.4 christos { 2455 1.4 christos return evcon->http_server; 2456 1.4 christos } 2457 1.4 christos 2458 1.4 christos struct evhttp_connection * 2459 1.4 christos evhttp_connection_base_new(struct event_base *base, struct evdns_base *dnsbase, 2460 1.4 christos const char *address, ev_uint16_t port) 2461 1.4 christos { 2462 1.4 christos return evhttp_connection_base_bufferevent_new(base, dnsbase, NULL, address, port); 2463 1.4 christos } 2464 1.4 christos 2465 1.4 christos void evhttp_connection_set_family(struct evhttp_connection *evcon, 2466 1.4 christos int family) 2467 1.4 christos { 2468 1.4 christos evcon->ai_family = family; 2469 1.4 christos } 2470 1.4 christos 2471 1.4 christos int evhttp_connection_set_flags(struct evhttp_connection *evcon, 2472 1.4 christos int flags) 2473 1.4 christos { 2474 1.4 christos int avail_flags = 0; 2475 1.4 christos avail_flags |= EVHTTP_CON_REUSE_CONNECTED_ADDR; 2476 1.4 christos avail_flags |= EVHTTP_CON_READ_ON_WRITE_ERROR; 2477 1.4 christos 2478 1.4 christos if (flags & ~avail_flags || flags > EVHTTP_CON_PUBLIC_FLAGS_END) 2479 1.4 christos return 1; 2480 1.4 christos evcon->flags &= ~avail_flags; 2481 1.4 christos 2482 1.4 christos evcon->flags |= flags; 2483 1.4 christos 2484 1.4 christos return 0; 2485 1.4 christos } 2486 1.4 christos 2487 1.2 christos void 2488 1.2 christos evhttp_connection_set_base(struct evhttp_connection *evcon, 2489 1.1 plunky struct event_base *base) 2490 1.1 plunky { 2491 1.2 christos EVUTIL_ASSERT(evcon->base == NULL); 2492 1.2 christos EVUTIL_ASSERT(evcon->state == EVCON_DISCONNECTED); 2493 1.1 plunky evcon->base = base; 2494 1.2 christos bufferevent_base_set(base, evcon->bufev); 2495 1.1 plunky } 2496 1.1 plunky 2497 1.1 plunky void 2498 1.1 plunky evhttp_connection_set_timeout(struct evhttp_connection *evcon, 2499 1.1 plunky int timeout_in_secs) 2500 1.1 plunky { 2501 1.4 christos if (timeout_in_secs == -1) 2502 1.4 christos evhttp_connection_set_timeout_tv(evcon, NULL); 2503 1.4 christos else { 2504 1.4 christos struct timeval tv; 2505 1.4 christos tv.tv_sec = timeout_in_secs; 2506 1.4 christos tv.tv_usec = 0; 2507 1.4 christos evhttp_connection_set_timeout_tv(evcon, &tv); 2508 1.4 christos } 2509 1.4 christos } 2510 1.2 christos 2511 1.4 christos void 2512 1.4 christos evhttp_connection_set_timeout_tv(struct evhttp_connection *evcon, 2513 1.4 christos const struct timeval* tv) 2514 1.4 christos { 2515 1.4 christos if (tv) { 2516 1.4 christos evcon->timeout = *tv; 2517 1.4 christos bufferevent_set_timeouts(evcon->bufev, &evcon->timeout, &evcon->timeout); 2518 1.4 christos } else { 2519 1.4 christos const struct timeval read_tv = { HTTP_READ_TIMEOUT, 0 }; 2520 1.4 christos const struct timeval write_tv = { HTTP_WRITE_TIMEOUT, 0 }; 2521 1.4 christos evutil_timerclear(&evcon->timeout); 2522 1.4 christos bufferevent_set_timeouts(evcon->bufev, &read_tv, &write_tv); 2523 1.4 christos } 2524 1.4 christos } 2525 1.4 christos 2526 1.4 christos void 2527 1.4 christos evhttp_connection_set_initial_retry_tv(struct evhttp_connection *evcon, 2528 1.4 christos const struct timeval *tv) 2529 1.4 christos { 2530 1.4 christos if (tv) { 2531 1.4 christos evcon->initial_retry_timeout = *tv; 2532 1.4 christos } else { 2533 1.4 christos evutil_timerclear(&evcon->initial_retry_timeout); 2534 1.4 christos evcon->initial_retry_timeout.tv_sec = 2; 2535 1.4 christos } 2536 1.1 plunky } 2537 1.1 plunky 2538 1.1 plunky void 2539 1.1 plunky evhttp_connection_set_retries(struct evhttp_connection *evcon, 2540 1.1 plunky int retry_max) 2541 1.1 plunky { 2542 1.1 plunky evcon->retry_max = retry_max; 2543 1.1 plunky } 2544 1.1 plunky 2545 1.1 plunky void 2546 1.1 plunky evhttp_connection_set_closecb(struct evhttp_connection *evcon, 2547 1.1 plunky void (*cb)(struct evhttp_connection *, void *), void *cbarg) 2548 1.1 plunky { 2549 1.1 plunky evcon->closecb = cb; 2550 1.1 plunky evcon->closecb_arg = cbarg; 2551 1.1 plunky } 2552 1.1 plunky 2553 1.1 plunky void 2554 1.1 plunky evhttp_connection_get_peer(struct evhttp_connection *evcon, 2555 1.2 christos char **address, ev_uint16_t *port) 2556 1.1 plunky { 2557 1.1 plunky *address = evcon->address; 2558 1.1 plunky *port = evcon->port; 2559 1.1 plunky } 2560 1.1 plunky 2561 1.4 christos const struct sockaddr* 2562 1.4 christos evhttp_connection_get_addr(struct evhttp_connection *evcon) 2563 1.4 christos { 2564 1.4 christos return bufferevent_socket_get_conn_address_(evcon->bufev); 2565 1.4 christos } 2566 1.4 christos 2567 1.1 plunky int 2568 1.4 christos evhttp_connection_connect_(struct evhttp_connection *evcon) 2569 1.1 plunky { 2570 1.3 spz int old_state = evcon->state; 2571 1.4 christos const char *address = evcon->address; 2572 1.4 christos const struct sockaddr *sa = evhttp_connection_get_addr(evcon); 2573 1.4 christos int ret; 2574 1.3 spz 2575 1.1 plunky if (evcon->state == EVCON_CONNECTING) 2576 1.1 plunky return (0); 2577 1.2 christos 2578 1.4 christos evhttp_connection_reset_(evcon); 2579 1.1 plunky 2580 1.2 christos EVUTIL_ASSERT(!(evcon->flags & EVHTTP_CON_INCOMING)); 2581 1.1 plunky evcon->flags |= EVHTTP_CON_OUTGOING; 2582 1.2 christos 2583 1.4 christos if (evcon->bind_address || evcon->bind_port) { 2584 1.4 christos evcon->fd = bind_socket( 2585 1.4 christos evcon->bind_address, evcon->bind_port, 0 /*reuse*/); 2586 1.4 christos if (evcon->fd == -1) { 2587 1.4 christos event_debug(("%s: failed to bind to \"%s\"", 2588 1.4 christos __func__, evcon->bind_address)); 2589 1.4 christos return (-1); 2590 1.4 christos } 2591 1.4 christos 2592 1.5 christos if (bufferevent_setfd(evcon->bufev, evcon->fd)) 2593 1.5 christos return (-1); 2594 1.4 christos } else { 2595 1.5 christos if (bufferevent_setfd(evcon->bufev, -1)) 2596 1.5 christos return (-1); 2597 1.1 plunky } 2598 1.1 plunky 2599 1.2 christos /* Set up a callback for successful connection setup */ 2600 1.2 christos bufferevent_setcb(evcon->bufev, 2601 1.2 christos NULL /* evhttp_read_cb */, 2602 1.2 christos NULL /* evhttp_write_cb */, 2603 1.2 christos evhttp_connection_cb, 2604 1.2 christos evcon); 2605 1.4 christos if (!evutil_timerisset(&evcon->timeout)) { 2606 1.4 christos const struct timeval conn_tv = { HTTP_CONNECT_TIMEOUT, 0 }; 2607 1.4 christos bufferevent_set_timeouts(evcon->bufev, &conn_tv, &conn_tv); 2608 1.4 christos } else { 2609 1.4 christos bufferevent_set_timeouts(evcon->bufev, &evcon->timeout, &evcon->timeout); 2610 1.4 christos } 2611 1.2 christos /* make sure that we get a write callback */ 2612 1.5 christos if (bufferevent_enable(evcon->bufev, EV_WRITE)) 2613 1.5 christos return (-1); 2614 1.2 christos 2615 1.3 spz evcon->state = EVCON_CONNECTING; 2616 1.3 spz 2617 1.4 christos if (evcon->flags & EVHTTP_CON_REUSE_CONNECTED_ADDR && 2618 1.4 christos sa && 2619 1.4 christos (sa->sa_family == AF_INET || sa->sa_family == AF_INET6)) { 2620 1.4 christos int socklen = sizeof(struct sockaddr_in); 2621 1.4 christos if (sa->sa_family == AF_INET6) { 2622 1.4 christos socklen = sizeof(struct sockaddr_in6); 2623 1.4 christos } 2624 1.4 christos ret = bufferevent_socket_connect(evcon->bufev, sa, socklen); 2625 1.4 christos } else { 2626 1.4 christos ret = bufferevent_socket_connect_hostname(evcon->bufev, 2627 1.4 christos evcon->dns_base, evcon->ai_family, address, evcon->port); 2628 1.4 christos } 2629 1.4 christos 2630 1.4 christos if (ret < 0) { 2631 1.3 spz evcon->state = old_state; 2632 1.2 christos event_sock_warn(evcon->fd, "%s: connection to \"%s\" failed", 2633 1.2 christos __func__, evcon->address); 2634 1.2 christos /* some operating systems return ECONNREFUSED immediately 2635 1.2 christos * when connecting to a local address. the cleanup is going 2636 1.2 christos * to reschedule this function call. 2637 1.2 christos */ 2638 1.2 christos evhttp_connection_cb_cleanup(evcon); 2639 1.2 christos return (0); 2640 1.1 plunky } 2641 1.1 plunky 2642 1.1 plunky return (0); 2643 1.1 plunky } 2644 1.1 plunky 2645 1.1 plunky /* 2646 1.1 plunky * Starts an HTTP request on the provided evhttp_connection object. 2647 1.1 plunky * If the connection object is not connected to the web server already, 2648 1.1 plunky * this will start the connection. 2649 1.1 plunky */ 2650 1.1 plunky 2651 1.1 plunky int 2652 1.1 plunky evhttp_make_request(struct evhttp_connection *evcon, 2653 1.1 plunky struct evhttp_request *req, 2654 1.1 plunky enum evhttp_cmd_type type, const char *uri) 2655 1.1 plunky { 2656 1.1 plunky /* We are making a request */ 2657 1.1 plunky req->kind = EVHTTP_REQUEST; 2658 1.1 plunky req->type = type; 2659 1.1 plunky if (req->uri != NULL) 2660 1.2 christos mm_free(req->uri); 2661 1.2 christos if ((req->uri = mm_strdup(uri)) == NULL) { 2662 1.2 christos event_warn("%s: strdup", __func__); 2663 1.4 christos evhttp_request_free_auto(req); 2664 1.2 christos return (-1); 2665 1.2 christos } 2666 1.1 plunky 2667 1.1 plunky /* Set the protocol version if it is not supplied */ 2668 1.1 plunky if (!req->major && !req->minor) { 2669 1.1 plunky req->major = 1; 2670 1.1 plunky req->minor = 1; 2671 1.1 plunky } 2672 1.2 christos 2673 1.2 christos EVUTIL_ASSERT(req->evcon == NULL); 2674 1.1 plunky req->evcon = evcon; 2675 1.2 christos EVUTIL_ASSERT(!(req->flags & EVHTTP_REQ_OWN_CONNECTION)); 2676 1.2 christos 2677 1.4 christos TAILQ_INSERT_TAIL(&evcon->requests, req, next); 2678 1.1 plunky 2679 1.5 christos /* We do not want to conflict with retry_ev */ 2680 1.5 christos if (evcon->retry_cnt) 2681 1.5 christos return (0); 2682 1.5 christos 2683 1.1 plunky /* If the connection object is not connected; make it so */ 2684 1.2 christos if (!evhttp_connected(evcon)) { 2685 1.4 christos int res = evhttp_connection_connect_(evcon); 2686 1.4 christos /* evhttp_connection_fail_(), which is called through 2687 1.4 christos * evhttp_connection_connect_(), assumes that req lies in 2688 1.4 christos * evcon->requests. Thus, enqueue the request in advance and 2689 1.4 christos * remove it in the error case. */ 2690 1.4 christos if (res != 0) 2691 1.4 christos TAILQ_REMOVE(&evcon->requests, req, next); 2692 1.2 christos 2693 1.5 christos return (res); 2694 1.2 christos } 2695 1.1 plunky 2696 1.1 plunky /* 2697 1.1 plunky * If it's connected already and we are the first in the queue, 2698 1.1 plunky * then we can dispatch this request immediately. Otherwise, it 2699 1.1 plunky * will be dispatched once the pending requests are completed. 2700 1.1 plunky */ 2701 1.1 plunky if (TAILQ_FIRST(&evcon->requests) == req) 2702 1.1 plunky evhttp_request_dispatch(evcon); 2703 1.1 plunky 2704 1.1 plunky return (0); 2705 1.1 plunky } 2706 1.1 plunky 2707 1.2 christos void 2708 1.2 christos evhttp_cancel_request(struct evhttp_request *req) 2709 1.2 christos { 2710 1.2 christos struct evhttp_connection *evcon = req->evcon; 2711 1.2 christos if (evcon != NULL) { 2712 1.2 christos /* We need to remove it from the connection */ 2713 1.2 christos if (TAILQ_FIRST(&evcon->requests) == req) { 2714 1.2 christos /* it's currently being worked on, so reset 2715 1.2 christos * the connection. 2716 1.2 christos */ 2717 1.4 christos evhttp_connection_fail_(evcon, 2718 1.4 christos EVREQ_HTTP_REQUEST_CANCEL); 2719 1.2 christos 2720 1.2 christos /* connection fail freed the request */ 2721 1.2 christos return; 2722 1.2 christos } else { 2723 1.2 christos /* otherwise, we can just remove it from the 2724 1.2 christos * queue 2725 1.2 christos */ 2726 1.2 christos TAILQ_REMOVE(&evcon->requests, req, next); 2727 1.2 christos } 2728 1.2 christos } 2729 1.2 christos 2730 1.4 christos evhttp_request_free_auto(req); 2731 1.2 christos } 2732 1.2 christos 2733 1.1 plunky /* 2734 1.1 plunky * Reads data from file descriptor into request structure 2735 1.1 plunky * Request structure needs to be set up correctly. 2736 1.1 plunky */ 2737 1.1 plunky 2738 1.1 plunky void 2739 1.4 christos evhttp_start_read_(struct evhttp_connection *evcon) 2740 1.1 plunky { 2741 1.2 christos bufferevent_disable(evcon->bufev, EV_WRITE); 2742 1.2 christos bufferevent_enable(evcon->bufev, EV_READ); 2743 1.4 christos 2744 1.1 plunky evcon->state = EVCON_READING_FIRSTLINE; 2745 1.2 christos /* Reset the bufferevent callbacks */ 2746 1.2 christos bufferevent_setcb(evcon->bufev, 2747 1.2 christos evhttp_read_cb, 2748 1.2 christos evhttp_write_cb, 2749 1.2 christos evhttp_error_cb, 2750 1.2 christos evcon); 2751 1.2 christos 2752 1.2 christos /* If there's still data pending, process it next time through the 2753 1.2 christos * loop. Don't do it now; that could get recusive. */ 2754 1.2 christos if (evbuffer_get_length(bufferevent_get_input(evcon->bufev))) { 2755 1.4 christos event_deferred_cb_schedule_(get_deferred_queue(evcon), 2756 1.2 christos &evcon->read_more_deferred_cb); 2757 1.2 christos } 2758 1.1 plunky } 2759 1.1 plunky 2760 1.4 christos void 2761 1.4 christos evhttp_start_write_(struct evhttp_connection *evcon) 2762 1.4 christos { 2763 1.4 christos bufferevent_disable(evcon->bufev, EV_WRITE); 2764 1.4 christos bufferevent_enable(evcon->bufev, EV_READ); 2765 1.4 christos 2766 1.4 christos evcon->state = EVCON_WRITING; 2767 1.4 christos evhttp_write_buffer(evcon, evhttp_write_connectioncb, NULL); 2768 1.4 christos } 2769 1.4 christos 2770 1.1 plunky static void 2771 1.1 plunky evhttp_send_done(struct evhttp_connection *evcon, void *arg) 2772 1.1 plunky { 2773 1.1 plunky int need_close; 2774 1.1 plunky struct evhttp_request *req = TAILQ_FIRST(&evcon->requests); 2775 1.1 plunky TAILQ_REMOVE(&evcon->requests, req, next); 2776 1.1 plunky 2777 1.4 christos if (req->on_complete_cb != NULL) { 2778 1.4 christos req->on_complete_cb(req, req->on_complete_cb_arg); 2779 1.4 christos } 2780 1.4 christos 2781 1.1 plunky need_close = 2782 1.2 christos (REQ_VERSION_BEFORE(req, 1, 1) && 2783 1.4 christos !evhttp_is_connection_keepalive(req->input_headers)) || 2784 1.4 christos evhttp_is_request_connection_close(req); 2785 1.1 plunky 2786 1.2 christos EVUTIL_ASSERT(req->flags & EVHTTP_REQ_OWN_CONNECTION); 2787 1.1 plunky evhttp_request_free(req); 2788 1.1 plunky 2789 1.1 plunky if (need_close) { 2790 1.1 plunky evhttp_connection_free(evcon); 2791 1.1 plunky return; 2792 1.2 christos } 2793 1.1 plunky 2794 1.1 plunky /* we have a persistent connection; try to accept another request. */ 2795 1.2 christos if (evhttp_associate_new_request_with_connection(evcon) == -1) { 2796 1.1 plunky evhttp_connection_free(evcon); 2797 1.2 christos } 2798 1.1 plunky } 2799 1.1 plunky 2800 1.1 plunky /* 2801 1.1 plunky * Returns an error page. 2802 1.1 plunky */ 2803 1.1 plunky 2804 1.1 plunky void 2805 1.1 plunky evhttp_send_error(struct evhttp_request *req, int error, const char *reason) 2806 1.1 plunky { 2807 1.2 christos 2808 1.1 plunky #define ERR_FORMAT "<HTML><HEAD>\n" \ 2809 1.1 plunky "<TITLE>%d %s</TITLE>\n" \ 2810 1.1 plunky "</HEAD><BODY>\n" \ 2811 1.2 christos "<H1>%s</H1>\n" \ 2812 1.1 plunky "</BODY></HTML>\n" 2813 1.1 plunky 2814 1.1 plunky struct evbuffer *buf = evbuffer_new(); 2815 1.2 christos if (buf == NULL) { 2816 1.2 christos /* if we cannot allocate memory; we just drop the connection */ 2817 1.2 christos evhttp_connection_free(req->evcon); 2818 1.2 christos return; 2819 1.2 christos } 2820 1.2 christos if (reason == NULL) { 2821 1.2 christos reason = evhttp_response_phrase_internal(error); 2822 1.2 christos } 2823 1.1 plunky 2824 1.4 christos evhttp_response_code_(req, error, reason); 2825 1.1 plunky 2826 1.2 christos evbuffer_add_printf(buf, ERR_FORMAT, error, reason, reason); 2827 1.1 plunky 2828 1.4 christos evhttp_send_page_(req, buf); 2829 1.1 plunky 2830 1.1 plunky evbuffer_free(buf); 2831 1.1 plunky #undef ERR_FORMAT 2832 1.1 plunky } 2833 1.1 plunky 2834 1.1 plunky /* Requires that headers and response code are already set up */ 2835 1.1 plunky 2836 1.1 plunky static inline void 2837 1.1 plunky evhttp_send(struct evhttp_request *req, struct evbuffer *databuf) 2838 1.1 plunky { 2839 1.1 plunky struct evhttp_connection *evcon = req->evcon; 2840 1.1 plunky 2841 1.2 christos if (evcon == NULL) { 2842 1.2 christos evhttp_request_free(req); 2843 1.2 christos return; 2844 1.2 christos } 2845 1.2 christos 2846 1.2 christos EVUTIL_ASSERT(TAILQ_FIRST(&evcon->requests) == req); 2847 1.2 christos 2848 1.2 christos /* we expect no more calls form the user on this request */ 2849 1.2 christos req->userdone = 1; 2850 1.1 plunky 2851 1.1 plunky /* xxx: not sure if we really should expose the data buffer this way */ 2852 1.1 plunky if (databuf != NULL) 2853 1.1 plunky evbuffer_add_buffer(req->output_buffer, databuf); 2854 1.2 christos 2855 1.1 plunky /* Adds headers to the response */ 2856 1.1 plunky evhttp_make_header(evcon, req); 2857 1.1 plunky 2858 1.1 plunky evhttp_write_buffer(evcon, evhttp_send_done, NULL); 2859 1.1 plunky } 2860 1.1 plunky 2861 1.1 plunky void 2862 1.1 plunky evhttp_send_reply(struct evhttp_request *req, int code, const char *reason, 2863 1.1 plunky struct evbuffer *databuf) 2864 1.1 plunky { 2865 1.4 christos evhttp_response_code_(req, code, reason); 2866 1.2 christos 2867 1.1 plunky evhttp_send(req, databuf); 2868 1.1 plunky } 2869 1.1 plunky 2870 1.1 plunky void 2871 1.1 plunky evhttp_send_reply_start(struct evhttp_request *req, int code, 2872 1.1 plunky const char *reason) 2873 1.1 plunky { 2874 1.4 christos evhttp_response_code_(req, code, reason); 2875 1.5 christos 2876 1.5 christos if (req->evcon == NULL) 2877 1.5 christos return; 2878 1.5 christos 2879 1.2 christos if (evhttp_find_header(req->output_headers, "Content-Length") == NULL && 2880 1.2 christos REQ_VERSION_ATLEAST(req, 1, 1) && 2881 1.2 christos evhttp_response_needs_body(req)) { 2882 1.2 christos /* 2883 1.2 christos * prefer HTTP/1.1 chunked encoding to closing the connection; 2884 1.2 christos * note RFC 2616 section 4.4 forbids it with Content-Length: 2885 1.2 christos * and it's not necessary then anyway. 2886 1.2 christos */ 2887 1.1 plunky evhttp_add_header(req->output_headers, "Transfer-Encoding", 2888 1.1 plunky "chunked"); 2889 1.1 plunky req->chunked = 1; 2890 1.2 christos } else { 2891 1.2 christos req->chunked = 0; 2892 1.1 plunky } 2893 1.1 plunky evhttp_make_header(req->evcon, req); 2894 1.1 plunky evhttp_write_buffer(req->evcon, NULL, NULL); 2895 1.1 plunky } 2896 1.1 plunky 2897 1.1 plunky void 2898 1.4 christos evhttp_send_reply_chunk_with_cb(struct evhttp_request *req, struct evbuffer *databuf, 2899 1.4 christos void (*cb)(struct evhttp_connection *, void *), void *arg) 2900 1.1 plunky { 2901 1.2 christos struct evhttp_connection *evcon = req->evcon; 2902 1.2 christos struct evbuffer *output; 2903 1.2 christos 2904 1.2 christos if (evcon == NULL) 2905 1.2 christos return; 2906 1.2 christos 2907 1.2 christos output = bufferevent_get_output(evcon->bufev); 2908 1.2 christos 2909 1.2 christos if (evbuffer_get_length(databuf) == 0) 2910 1.2 christos return; 2911 1.2 christos if (!evhttp_response_needs_body(req)) 2912 1.2 christos return; 2913 1.1 plunky if (req->chunked) { 2914 1.2 christos evbuffer_add_printf(output, "%x\r\n", 2915 1.2 christos (unsigned)evbuffer_get_length(databuf)); 2916 1.1 plunky } 2917 1.2 christos evbuffer_add_buffer(output, databuf); 2918 1.1 plunky if (req->chunked) { 2919 1.2 christos evbuffer_add(output, "\r\n", 2); 2920 1.1 plunky } 2921 1.4 christos evhttp_write_buffer(evcon, cb, arg); 2922 1.1 plunky } 2923 1.1 plunky 2924 1.1 plunky void 2925 1.4 christos evhttp_send_reply_chunk(struct evhttp_request *req, struct evbuffer *databuf) 2926 1.4 christos { 2927 1.4 christos evhttp_send_reply_chunk_with_cb(req, databuf, NULL, NULL); 2928 1.4 christos } 2929 1.4 christos void 2930 1.1 plunky evhttp_send_reply_end(struct evhttp_request *req) 2931 1.1 plunky { 2932 1.1 plunky struct evhttp_connection *evcon = req->evcon; 2933 1.2 christos struct evbuffer *output; 2934 1.2 christos 2935 1.2 christos if (evcon == NULL) { 2936 1.2 christos evhttp_request_free(req); 2937 1.2 christos return; 2938 1.2 christos } 2939 1.2 christos 2940 1.2 christos output = bufferevent_get_output(evcon->bufev); 2941 1.2 christos 2942 1.2 christos /* we expect no more calls form the user on this request */ 2943 1.2 christos req->userdone = 1; 2944 1.1 plunky 2945 1.1 plunky if (req->chunked) { 2946 1.2 christos evbuffer_add(output, "0\r\n\r\n", 5); 2947 1.1 plunky evhttp_write_buffer(req->evcon, evhttp_send_done, NULL); 2948 1.1 plunky req->chunked = 0; 2949 1.2 christos } else if (evbuffer_get_length(output) == 0) { 2950 1.1 plunky /* let the connection know that we are done with the request */ 2951 1.1 plunky evhttp_send_done(evcon, NULL); 2952 1.1 plunky } else { 2953 1.1 plunky /* make the callback execute after all data has been written */ 2954 1.1 plunky evcon->cb = evhttp_send_done; 2955 1.1 plunky evcon->cb_arg = NULL; 2956 1.1 plunky } 2957 1.1 plunky } 2958 1.1 plunky 2959 1.2 christos static const char *informational_phrases[] = { 2960 1.2 christos /* 100 */ "Continue", 2961 1.2 christos /* 101 */ "Switching Protocols" 2962 1.2 christos }; 2963 1.2 christos 2964 1.2 christos static const char *success_phrases[] = { 2965 1.2 christos /* 200 */ "OK", 2966 1.2 christos /* 201 */ "Created", 2967 1.2 christos /* 202 */ "Accepted", 2968 1.2 christos /* 203 */ "Non-Authoritative Information", 2969 1.2 christos /* 204 */ "No Content", 2970 1.2 christos /* 205 */ "Reset Content", 2971 1.2 christos /* 206 */ "Partial Content" 2972 1.2 christos }; 2973 1.2 christos 2974 1.2 christos static const char *redirection_phrases[] = { 2975 1.2 christos /* 300 */ "Multiple Choices", 2976 1.2 christos /* 301 */ "Moved Permanently", 2977 1.2 christos /* 302 */ "Found", 2978 1.2 christos /* 303 */ "See Other", 2979 1.2 christos /* 304 */ "Not Modified", 2980 1.2 christos /* 305 */ "Use Proxy", 2981 1.2 christos /* 307 */ "Temporary Redirect" 2982 1.2 christos }; 2983 1.2 christos 2984 1.2 christos static const char *client_error_phrases[] = { 2985 1.2 christos /* 400 */ "Bad Request", 2986 1.2 christos /* 401 */ "Unauthorized", 2987 1.2 christos /* 402 */ "Payment Required", 2988 1.2 christos /* 403 */ "Forbidden", 2989 1.2 christos /* 404 */ "Not Found", 2990 1.2 christos /* 405 */ "Method Not Allowed", 2991 1.2 christos /* 406 */ "Not Acceptable", 2992 1.2 christos /* 407 */ "Proxy Authentication Required", 2993 1.2 christos /* 408 */ "Request Time-out", 2994 1.2 christos /* 409 */ "Conflict", 2995 1.2 christos /* 410 */ "Gone", 2996 1.2 christos /* 411 */ "Length Required", 2997 1.2 christos /* 412 */ "Precondition Failed", 2998 1.2 christos /* 413 */ "Request Entity Too Large", 2999 1.2 christos /* 414 */ "Request-URI Too Large", 3000 1.2 christos /* 415 */ "Unsupported Media Type", 3001 1.2 christos /* 416 */ "Requested range not satisfiable", 3002 1.2 christos /* 417 */ "Expectation Failed" 3003 1.2 christos }; 3004 1.2 christos 3005 1.2 christos static const char *server_error_phrases[] = { 3006 1.2 christos /* 500 */ "Internal Server Error", 3007 1.2 christos /* 501 */ "Not Implemented", 3008 1.2 christos /* 502 */ "Bad Gateway", 3009 1.2 christos /* 503 */ "Service Unavailable", 3010 1.2 christos /* 504 */ "Gateway Time-out", 3011 1.2 christos /* 505 */ "HTTP Version not supported" 3012 1.2 christos }; 3013 1.2 christos 3014 1.2 christos struct response_class { 3015 1.2 christos const char *name; 3016 1.2 christos size_t num_responses; 3017 1.2 christos const char **responses; 3018 1.2 christos }; 3019 1.2 christos 3020 1.2 christos #ifndef MEMBERSOF 3021 1.2 christos #define MEMBERSOF(x) (sizeof(x)/sizeof(x[0])) 3022 1.2 christos #endif 3023 1.2 christos 3024 1.2 christos static const struct response_class response_classes[] = { 3025 1.2 christos /* 1xx */ { "Informational", MEMBERSOF(informational_phrases), informational_phrases }, 3026 1.2 christos /* 2xx */ { "Success", MEMBERSOF(success_phrases), success_phrases }, 3027 1.2 christos /* 3xx */ { "Redirection", MEMBERSOF(redirection_phrases), redirection_phrases }, 3028 1.2 christos /* 4xx */ { "Client Error", MEMBERSOF(client_error_phrases), client_error_phrases }, 3029 1.2 christos /* 5xx */ { "Server Error", MEMBERSOF(server_error_phrases), server_error_phrases } 3030 1.2 christos }; 3031 1.2 christos 3032 1.2 christos static const char * 3033 1.2 christos evhttp_response_phrase_internal(int code) 3034 1.2 christos { 3035 1.2 christos int klass = code / 100 - 1; 3036 1.2 christos int subcode = code % 100; 3037 1.2 christos 3038 1.2 christos /* Unknown class - can't do any better here */ 3039 1.2 christos if (klass < 0 || klass >= (int) MEMBERSOF(response_classes)) 3040 1.2 christos return "Unknown Status Class"; 3041 1.2 christos 3042 1.2 christos /* Unknown sub-code, return class name at least */ 3043 1.2 christos if (subcode >= (int) response_classes[klass].num_responses) 3044 1.2 christos return response_classes[klass].name; 3045 1.2 christos 3046 1.2 christos return response_classes[klass].responses[subcode]; 3047 1.2 christos } 3048 1.2 christos 3049 1.1 plunky void 3050 1.4 christos evhttp_response_code_(struct evhttp_request *req, int code, const char *reason) 3051 1.1 plunky { 3052 1.1 plunky req->kind = EVHTTP_RESPONSE; 3053 1.1 plunky req->response_code = code; 3054 1.1 plunky if (req->response_code_line != NULL) 3055 1.2 christos mm_free(req->response_code_line); 3056 1.2 christos if (reason == NULL) 3057 1.2 christos reason = evhttp_response_phrase_internal(code); 3058 1.2 christos req->response_code_line = mm_strdup(reason); 3059 1.2 christos if (req->response_code_line == NULL) { 3060 1.2 christos event_warn("%s: strdup", __func__); 3061 1.2 christos /* XXX what else can we do? */ 3062 1.2 christos } 3063 1.1 plunky } 3064 1.1 plunky 3065 1.1 plunky void 3066 1.4 christos evhttp_send_page_(struct evhttp_request *req, struct evbuffer *databuf) 3067 1.1 plunky { 3068 1.1 plunky if (!req->major || !req->minor) { 3069 1.1 plunky req->major = 1; 3070 1.1 plunky req->minor = 1; 3071 1.1 plunky } 3072 1.2 christos 3073 1.1 plunky if (req->kind != EVHTTP_RESPONSE) 3074 1.4 christos evhttp_response_code_(req, 200, "OK"); 3075 1.1 plunky 3076 1.1 plunky evhttp_clear_headers(req->output_headers); 3077 1.1 plunky evhttp_add_header(req->output_headers, "Content-Type", "text/html"); 3078 1.1 plunky evhttp_add_header(req->output_headers, "Connection", "close"); 3079 1.1 plunky 3080 1.1 plunky evhttp_send(req, databuf); 3081 1.1 plunky } 3082 1.1 plunky 3083 1.1 plunky static const char uri_chars[256] = { 3084 1.2 christos /* 0 */ 3085 1.1 plunky 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3086 1.1 plunky 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3087 1.2 christos 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 3088 1.2 christos 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 3089 1.1 plunky /* 64 */ 3090 1.2 christos 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3091 1.1 plunky 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 3092 1.1 plunky 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3093 1.1 plunky 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 3094 1.1 plunky /* 128 */ 3095 1.1 plunky 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3096 1.1 plunky 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3097 1.1 plunky 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3098 1.1 plunky 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3099 1.1 plunky /* 192 */ 3100 1.1 plunky 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3101 1.1 plunky 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3102 1.1 plunky 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3103 1.1 plunky 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3104 1.1 plunky }; 3105 1.1 plunky 3106 1.2 christos #define CHAR_IS_UNRESERVED(c) \ 3107 1.2 christos (uri_chars[(unsigned char)(c)]) 3108 1.2 christos 3109 1.1 plunky /* 3110 1.2 christos * Helper functions to encode/decode a string for inclusion in a URI. 3111 1.1 plunky * The returned string must be freed by the caller. 3112 1.1 plunky */ 3113 1.1 plunky char * 3114 1.2 christos evhttp_uriencode(const char *uri, ev_ssize_t len, int space_as_plus) 3115 1.1 plunky { 3116 1.1 plunky struct evbuffer *buf = evbuffer_new(); 3117 1.2 christos const char *p, *end; 3118 1.5 christos char *result = NULL; 3119 1.2 christos 3120 1.5 christos if (!buf) { 3121 1.5 christos goto out; 3122 1.4 christos } 3123 1.4 christos 3124 1.4 christos if (len >= 0) { 3125 1.4 christos if (uri + len < uri) { 3126 1.5 christos goto out; 3127 1.4 christos } 3128 1.4 christos 3129 1.4 christos end = uri + len; 3130 1.4 christos } else { 3131 1.4 christos size_t slen = strlen(uri); 3132 1.4 christos 3133 1.4 christos if (slen >= EV_SSIZE_MAX) { 3134 1.4 christos /* we don't want to mix signed and unsigned */ 3135 1.5 christos goto out; 3136 1.4 christos } 3137 1.4 christos 3138 1.4 christos if (uri + slen < uri) { 3139 1.5 christos goto out; 3140 1.4 christos } 3141 1.2 christos 3142 1.4 christos end = uri + slen; 3143 1.4 christos } 3144 1.1 plunky 3145 1.2 christos for (p = uri; p < end; p++) { 3146 1.2 christos if (CHAR_IS_UNRESERVED(*p)) { 3147 1.1 plunky evbuffer_add(buf, p, 1); 3148 1.2 christos } else if (*p == ' ' && space_as_plus) { 3149 1.2 christos evbuffer_add(buf, "+", 1); 3150 1.1 plunky } else { 3151 1.2 christos evbuffer_add_printf(buf, "%%%02X", (unsigned char)(*p)); 3152 1.1 plunky } 3153 1.1 plunky } 3154 1.4 christos 3155 1.2 christos evbuffer_add(buf, "", 1); /* NUL-terminator. */ 3156 1.2 christos result = mm_malloc(evbuffer_get_length(buf)); 3157 1.4 christos 3158 1.2 christos if (result) 3159 1.2 christos evbuffer_remove(buf, result, evbuffer_get_length(buf)); 3160 1.4 christos 3161 1.5 christos out: 3162 1.5 christos if (buf) 3163 1.5 christos evbuffer_free(buf); 3164 1.5 christos return result; 3165 1.2 christos } 3166 1.2 christos 3167 1.2 christos char * 3168 1.2 christos evhttp_encode_uri(const char *str) 3169 1.2 christos { 3170 1.2 christos return evhttp_uriencode(str, -1, 0); 3171 1.1 plunky } 3172 1.1 plunky 3173 1.1 plunky /* 3174 1.2 christos * @param decode_plus_ctl: if 1, we decode plus into space. If 0, we don't. 3175 1.2 christos * If -1, when true we transform plus to space only after we've seen 3176 1.2 christos * a ?. -1 is deprecated. 3177 1.2 christos * @return the number of bytes written to 'ret'. 3178 1.1 plunky */ 3179 1.4 christos int 3180 1.1 plunky evhttp_decode_uri_internal( 3181 1.2 christos const char *uri, size_t length, char *ret, int decode_plus_ctl) 3182 1.1 plunky { 3183 1.1 plunky char c; 3184 1.2 christos int j; 3185 1.2 christos int decode_plus = (decode_plus_ctl == 1) ? 1: 0; 3186 1.2 christos unsigned i; 3187 1.2 christos 3188 1.2 christos for (i = j = 0; i < length; i++) { 3189 1.1 plunky c = uri[i]; 3190 1.1 plunky if (c == '?') { 3191 1.2 christos if (decode_plus_ctl < 0) 3192 1.2 christos decode_plus = 1; 3193 1.2 christos } else if (c == '+' && decode_plus) { 3194 1.1 plunky c = ' '; 3195 1.4 christos } else if ((i + 2) < length && c == '%' && 3196 1.4 christos EVUTIL_ISXDIGIT_(uri[i+1]) && EVUTIL_ISXDIGIT_(uri[i+2])) { 3197 1.2 christos char tmp[3]; 3198 1.2 christos tmp[0] = uri[i+1]; 3199 1.2 christos tmp[1] = uri[i+2]; 3200 1.2 christos tmp[2] = '\0'; 3201 1.1 plunky c = (char)strtol(tmp, NULL, 16); 3202 1.1 plunky i += 2; 3203 1.1 plunky } 3204 1.1 plunky ret[j++] = c; 3205 1.1 plunky } 3206 1.1 plunky ret[j] = '\0'; 3207 1.1 plunky 3208 1.1 plunky return (j); 3209 1.1 plunky } 3210 1.1 plunky 3211 1.2 christos /* deprecated */ 3212 1.1 plunky char * 3213 1.1 plunky evhttp_decode_uri(const char *uri) 3214 1.1 plunky { 3215 1.1 plunky char *ret; 3216 1.1 plunky 3217 1.2 christos if ((ret = mm_malloc(strlen(uri) + 1)) == NULL) { 3218 1.2 christos event_warn("%s: malloc(%lu)", __func__, 3219 1.1 plunky (unsigned long)(strlen(uri) + 1)); 3220 1.2 christos return (NULL); 3221 1.2 christos } 3222 1.1 plunky 3223 1.1 plunky evhttp_decode_uri_internal(uri, strlen(uri), 3224 1.2 christos ret, -1 /*always_decode_plus*/); 3225 1.1 plunky 3226 1.1 plunky return (ret); 3227 1.1 plunky } 3228 1.1 plunky 3229 1.2 christos char * 3230 1.2 christos evhttp_uridecode(const char *uri, int decode_plus, size_t *size_out) 3231 1.2 christos { 3232 1.2 christos char *ret; 3233 1.2 christos int n; 3234 1.2 christos 3235 1.2 christos if ((ret = mm_malloc(strlen(uri) + 1)) == NULL) { 3236 1.2 christos event_warn("%s: malloc(%lu)", __func__, 3237 1.2 christos (unsigned long)(strlen(uri) + 1)); 3238 1.2 christos return (NULL); 3239 1.2 christos } 3240 1.2 christos 3241 1.2 christos n = evhttp_decode_uri_internal(uri, strlen(uri), 3242 1.2 christos ret, !!decode_plus/*always_decode_plus*/); 3243 1.2 christos 3244 1.2 christos if (size_out) { 3245 1.2 christos EVUTIL_ASSERT(n >= 0); 3246 1.2 christos *size_out = (size_t)n; 3247 1.2 christos } 3248 1.2 christos 3249 1.2 christos return (ret); 3250 1.2 christos } 3251 1.2 christos 3252 1.2 christos /* 3253 1.1 plunky * Helper function to parse out arguments in a query. 3254 1.1 plunky * The arguments are separated by key and value. 3255 1.1 plunky */ 3256 1.1 plunky 3257 1.2 christos static int 3258 1.2 christos evhttp_parse_query_impl(const char *str, struct evkeyvalq *headers, 3259 1.2 christos int is_whole_uri) 3260 1.1 plunky { 3261 1.2 christos char *line=NULL; 3262 1.1 plunky char *argument; 3263 1.1 plunky char *p; 3264 1.2 christos const char *query_part; 3265 1.2 christos int result = -1; 3266 1.2 christos struct evhttp_uri *uri=NULL; 3267 1.1 plunky 3268 1.1 plunky TAILQ_INIT(headers); 3269 1.1 plunky 3270 1.2 christos if (is_whole_uri) { 3271 1.2 christos uri = evhttp_uri_parse(str); 3272 1.2 christos if (!uri) 3273 1.2 christos goto error; 3274 1.2 christos query_part = evhttp_uri_get_query(uri); 3275 1.2 christos } else { 3276 1.2 christos query_part = str; 3277 1.2 christos } 3278 1.2 christos 3279 1.1 plunky /* No arguments - we are done */ 3280 1.2 christos if (!query_part || !strlen(query_part)) { 3281 1.2 christos result = 0; 3282 1.2 christos goto done; 3283 1.2 christos } 3284 1.1 plunky 3285 1.2 christos if ((line = mm_strdup(query_part)) == NULL) { 3286 1.2 christos event_warn("%s: strdup", __func__); 3287 1.2 christos goto error; 3288 1.2 christos } 3289 1.1 plunky 3290 1.2 christos p = argument = line; 3291 1.1 plunky while (p != NULL && *p != '\0') { 3292 1.1 plunky char *key, *value, *decoded_value; 3293 1.5 christos int err; 3294 1.1 plunky argument = strsep(&p, "&"); 3295 1.1 plunky 3296 1.1 plunky value = argument; 3297 1.1 plunky key = strsep(&value, "="); 3298 1.2 christos if (value == NULL || *key == '\0') { 3299 1.1 plunky goto error; 3300 1.2 christos } 3301 1.1 plunky 3302 1.2 christos if ((decoded_value = mm_malloc(strlen(value) + 1)) == NULL) { 3303 1.2 christos event_warn("%s: mm_malloc", __func__); 3304 1.2 christos goto error; 3305 1.2 christos } 3306 1.1 plunky evhttp_decode_uri_internal(value, strlen(value), 3307 1.1 plunky decoded_value, 1 /*always_decode_plus*/); 3308 1.1 plunky event_debug(("Query Param: %s -> %s\n", key, decoded_value)); 3309 1.5 christos err = evhttp_add_header_internal(headers, key, decoded_value); 3310 1.2 christos mm_free(decoded_value); 3311 1.5 christos if (err) 3312 1.5 christos goto error; 3313 1.1 plunky } 3314 1.1 plunky 3315 1.2 christos result = 0; 3316 1.2 christos goto done; 3317 1.2 christos error: 3318 1.2 christos evhttp_clear_headers(headers); 3319 1.2 christos done: 3320 1.2 christos if (line) 3321 1.2 christos mm_free(line); 3322 1.2 christos if (uri) 3323 1.2 christos evhttp_uri_free(uri); 3324 1.2 christos return result; 3325 1.2 christos } 3326 1.2 christos 3327 1.2 christos int 3328 1.2 christos evhttp_parse_query(const char *uri, struct evkeyvalq *headers) 3329 1.2 christos { 3330 1.2 christos return evhttp_parse_query_impl(uri, headers, 1); 3331 1.2 christos } 3332 1.2 christos int 3333 1.2 christos evhttp_parse_query_str(const char *uri, struct evkeyvalq *headers) 3334 1.2 christos { 3335 1.2 christos return evhttp_parse_query_impl(uri, headers, 0); 3336 1.1 plunky } 3337 1.1 plunky 3338 1.1 plunky static struct evhttp_cb * 3339 1.1 plunky evhttp_dispatch_callback(struct httpcbq *callbacks, struct evhttp_request *req) 3340 1.1 plunky { 3341 1.1 plunky struct evhttp_cb *cb; 3342 1.1 plunky size_t offset = 0; 3343 1.2 christos char *translated; 3344 1.2 christos const char *path; 3345 1.1 plunky 3346 1.1 plunky /* Test for different URLs */ 3347 1.2 christos path = evhttp_uri_get_path(req->uri_elems); 3348 1.2 christos offset = strlen(path); 3349 1.2 christos if ((translated = mm_malloc(offset + 1)) == NULL) 3350 1.2 christos return (NULL); 3351 1.2 christos evhttp_decode_uri_internal(path, offset, translated, 3352 1.2 christos 0 /* decode_plus */); 3353 1.1 plunky 3354 1.1 plunky TAILQ_FOREACH(cb, callbacks, next) { 3355 1.2 christos if (!strcmp(cb->what, translated)) { 3356 1.2 christos mm_free(translated); 3357 1.2 christos return (cb); 3358 1.2 christos } 3359 1.2 christos } 3360 1.2 christos 3361 1.2 christos mm_free(translated); 3362 1.2 christos return (NULL); 3363 1.2 christos } 3364 1.2 christos 3365 1.2 christos 3366 1.2 christos static int 3367 1.2 christos prefix_suffix_match(const char *pattern, const char *name, int ignorecase) 3368 1.2 christos { 3369 1.2 christos char c; 3370 1.2 christos 3371 1.2 christos while (1) { 3372 1.2 christos switch (c = *pattern++) { 3373 1.2 christos case '\0': 3374 1.2 christos return *name == '\0'; 3375 1.2 christos 3376 1.2 christos case '*': 3377 1.2 christos while (*name != '\0') { 3378 1.2 christos if (prefix_suffix_match(pattern, name, 3379 1.2 christos ignorecase)) 3380 1.2 christos return (1); 3381 1.2 christos ++name; 3382 1.2 christos } 3383 1.2 christos return (0); 3384 1.2 christos default: 3385 1.2 christos if (c != *name) { 3386 1.2 christos if (!ignorecase || 3387 1.4 christos EVUTIL_TOLOWER_(c) != EVUTIL_TOLOWER_(*name)) 3388 1.2 christos return (0); 3389 1.2 christos } 3390 1.2 christos ++name; 3391 1.2 christos } 3392 1.2 christos } 3393 1.2 christos /* NOTREACHED */ 3394 1.2 christos } 3395 1.2 christos 3396 1.2 christos /* 3397 1.2 christos Search the vhost hierarchy beginning with http for a server alias 3398 1.2 christos matching hostname. If a match is found, and outhttp is non-null, 3399 1.2 christos outhttp is set to the matching http object and 1 is returned. 3400 1.2 christos */ 3401 1.2 christos 3402 1.2 christos static int 3403 1.2 christos evhttp_find_alias(struct evhttp *http, struct evhttp **outhttp, 3404 1.2 christos const char *hostname) 3405 1.2 christos { 3406 1.2 christos struct evhttp_server_alias *alias; 3407 1.2 christos struct evhttp *vhost; 3408 1.2 christos 3409 1.2 christos TAILQ_FOREACH(alias, &http->aliases, next) { 3410 1.2 christos /* XXX Do we need to handle IP addresses? */ 3411 1.2 christos if (!evutil_ascii_strcasecmp(alias->alias, hostname)) { 3412 1.2 christos if (outhttp) 3413 1.2 christos *outhttp = http; 3414 1.2 christos return 1; 3415 1.1 plunky } 3416 1.2 christos } 3417 1.1 plunky 3418 1.2 christos /* XXX It might be good to avoid recursion here, but I don't 3419 1.2 christos see a way to do that w/o a list. */ 3420 1.2 christos TAILQ_FOREACH(vhost, &http->virtualhosts, next_vhost) { 3421 1.2 christos if (evhttp_find_alias(vhost, outhttp, hostname)) 3422 1.2 christos return 1; 3423 1.1 plunky } 3424 1.1 plunky 3425 1.2 christos return 0; 3426 1.2 christos } 3427 1.2 christos 3428 1.2 christos /* 3429 1.2 christos Attempts to find the best http object to handle a request for a hostname. 3430 1.2 christos All aliases for the root http object and vhosts are searched for an exact 3431 1.2 christos match. Then, the vhost hierarchy is traversed again for a matching 3432 1.2 christos pattern. 3433 1.2 christos 3434 1.2 christos If an alias or vhost is matched, 1 is returned, and outhttp, if non-null, 3435 1.2 christos is set with the best matching http object. If there are no matches, the 3436 1.2 christos root http object is stored in outhttp and 0 is returned. 3437 1.2 christos */ 3438 1.2 christos 3439 1.2 christos static int 3440 1.2 christos evhttp_find_vhost(struct evhttp *http, struct evhttp **outhttp, 3441 1.2 christos const char *hostname) 3442 1.2 christos { 3443 1.2 christos struct evhttp *vhost; 3444 1.2 christos struct evhttp *oldhttp; 3445 1.2 christos int match_found = 0; 3446 1.2 christos 3447 1.2 christos if (evhttp_find_alias(http, outhttp, hostname)) 3448 1.2 christos return 1; 3449 1.2 christos 3450 1.2 christos do { 3451 1.2 christos oldhttp = http; 3452 1.2 christos TAILQ_FOREACH(vhost, &http->virtualhosts, next_vhost) { 3453 1.2 christos if (prefix_suffix_match(vhost->vhost_pattern, 3454 1.2 christos hostname, 1 /* ignorecase */)) { 3455 1.2 christos http = vhost; 3456 1.2 christos match_found = 1; 3457 1.2 christos break; 3458 1.2 christos } 3459 1.2 christos } 3460 1.2 christos } while (oldhttp != http); 3461 1.2 christos 3462 1.2 christos if (outhttp) 3463 1.2 christos *outhttp = http; 3464 1.2 christos 3465 1.2 christos return match_found; 3466 1.1 plunky } 3467 1.1 plunky 3468 1.1 plunky static void 3469 1.1 plunky evhttp_handle_request(struct evhttp_request *req, void *arg) 3470 1.1 plunky { 3471 1.1 plunky struct evhttp *http = arg; 3472 1.1 plunky struct evhttp_cb *cb = NULL; 3473 1.2 christos const char *hostname; 3474 1.2 christos 3475 1.2 christos /* we have a new request on which the user needs to take action */ 3476 1.2 christos req->userdone = 0; 3477 1.2 christos 3478 1.5 christos bufferevent_disable(req->evcon->bufev, EV_READ); 3479 1.5 christos 3480 1.2 christos if (req->type == 0 || req->uri == NULL) { 3481 1.4 christos evhttp_send_error(req, req->response_code, NULL); 3482 1.2 christos return; 3483 1.2 christos } 3484 1.1 plunky 3485 1.2 christos if ((http->allowed_methods & req->type) == 0) { 3486 1.2 christos event_debug(("Rejecting disallowed method %x (allowed: %x)\n", 3487 1.2 christos (unsigned)req->type, (unsigned)http->allowed_methods)); 3488 1.2 christos evhttp_send_error(req, HTTP_NOTIMPLEMENTED, NULL); 3489 1.1 plunky return; 3490 1.1 plunky } 3491 1.1 plunky 3492 1.2 christos /* handle potential virtual hosts */ 3493 1.2 christos hostname = evhttp_request_get_host(req); 3494 1.2 christos if (hostname != NULL) { 3495 1.2 christos evhttp_find_vhost(http, &http, hostname); 3496 1.2 christos } 3497 1.2 christos 3498 1.1 plunky if ((cb = evhttp_dispatch_callback(&http->callbacks, req)) != NULL) { 3499 1.1 plunky (*cb->cb)(req, cb->cbarg); 3500 1.1 plunky return; 3501 1.1 plunky } 3502 1.1 plunky 3503 1.1 plunky /* Generic call back */ 3504 1.1 plunky if (http->gencb) { 3505 1.1 plunky (*http->gencb)(req, http->gencbarg); 3506 1.1 plunky return; 3507 1.1 plunky } else { 3508 1.1 plunky /* We need to send a 404 here */ 3509 1.1 plunky #define ERR_FORMAT "<html><head>" \ 3510 1.1 plunky "<title>404 Not Found</title>" \ 3511 1.1 plunky "</head><body>" \ 3512 1.1 plunky "<h1>Not Found</h1>" \ 3513 1.1 plunky "<p>The requested URL %s was not found on this server.</p>"\ 3514 1.1 plunky "</body></html>\n" 3515 1.1 plunky 3516 1.2 christos char *escaped_html; 3517 1.2 christos struct evbuffer *buf; 3518 1.2 christos 3519 1.2 christos if ((escaped_html = evhttp_htmlescape(req->uri)) == NULL) { 3520 1.2 christos evhttp_connection_free(req->evcon); 3521 1.2 christos return; 3522 1.2 christos } 3523 1.2 christos 3524 1.2 christos if ((buf = evbuffer_new()) == NULL) { 3525 1.2 christos mm_free(escaped_html); 3526 1.2 christos evhttp_connection_free(req->evcon); 3527 1.2 christos return; 3528 1.2 christos } 3529 1.1 plunky 3530 1.4 christos evhttp_response_code_(req, HTTP_NOTFOUND, "Not Found"); 3531 1.1 plunky 3532 1.1 plunky evbuffer_add_printf(buf, ERR_FORMAT, escaped_html); 3533 1.1 plunky 3534 1.2 christos mm_free(escaped_html); 3535 1.1 plunky 3536 1.4 christos evhttp_send_page_(req, buf); 3537 1.1 plunky 3538 1.1 plunky evbuffer_free(buf); 3539 1.1 plunky #undef ERR_FORMAT 3540 1.1 plunky } 3541 1.1 plunky } 3542 1.1 plunky 3543 1.2 christos /* Listener callback when a connection arrives at a server. */ 3544 1.1 plunky static void 3545 1.2 christos accept_socket_cb(struct evconnlistener *listener, evutil_socket_t nfd, struct sockaddr *peer_sa, int peer_socklen, void *arg) 3546 1.1 plunky { 3547 1.1 plunky struct evhttp *http = arg; 3548 1.1 plunky 3549 1.2 christos evhttp_get_request(http, nfd, peer_sa, peer_socklen); 3550 1.2 christos } 3551 1.1 plunky 3552 1.2 christos int 3553 1.2 christos evhttp_bind_socket(struct evhttp *http, const char *address, ev_uint16_t port) 3554 1.2 christos { 3555 1.2 christos struct evhttp_bound_socket *bound = 3556 1.2 christos evhttp_bind_socket_with_handle(http, address, port); 3557 1.2 christos if (bound == NULL) 3558 1.2 christos return (-1); 3559 1.2 christos return (0); 3560 1.1 plunky } 3561 1.1 plunky 3562 1.2 christos struct evhttp_bound_socket * 3563 1.2 christos evhttp_bind_socket_with_handle(struct evhttp *http, const char *address, ev_uint16_t port) 3564 1.1 plunky { 3565 1.2 christos evutil_socket_t fd; 3566 1.2 christos struct evhttp_bound_socket *bound; 3567 1.5 christos int serrno; 3568 1.1 plunky 3569 1.1 plunky if ((fd = bind_socket(address, port, 1 /*reuse*/)) == -1) 3570 1.2 christos return (NULL); 3571 1.1 plunky 3572 1.1 plunky if (listen(fd, 128) == -1) { 3573 1.5 christos serrno = EVUTIL_SOCKET_ERROR(); 3574 1.2 christos event_sock_warn(fd, "%s: listen", __func__); 3575 1.2 christos evutil_closesocket(fd); 3576 1.5 christos EVUTIL_SET_SOCKET_ERROR(serrno); 3577 1.2 christos return (NULL); 3578 1.1 plunky } 3579 1.1 plunky 3580 1.2 christos bound = evhttp_accept_socket_with_handle(http, fd); 3581 1.2 christos 3582 1.2 christos if (bound != NULL) { 3583 1.1 plunky event_debug(("Bound to port %d - Awaiting connections ... ", 3584 1.1 plunky port)); 3585 1.2 christos return (bound); 3586 1.2 christos } 3587 1.1 plunky 3588 1.2 christos return (NULL); 3589 1.1 plunky } 3590 1.1 plunky 3591 1.1 plunky int 3592 1.2 christos evhttp_accept_socket(struct evhttp *http, evutil_socket_t fd) 3593 1.1 plunky { 3594 1.2 christos struct evhttp_bound_socket *bound = 3595 1.2 christos evhttp_accept_socket_with_handle(http, fd); 3596 1.1 plunky if (bound == NULL) 3597 1.1 plunky return (-1); 3598 1.2 christos return (0); 3599 1.2 christos } 3600 1.1 plunky 3601 1.4 christos void 3602 1.4 christos evhttp_foreach_bound_socket(struct evhttp *http, 3603 1.4 christos evhttp_bound_socket_foreach_fn *function, 3604 1.4 christos void *argument) 3605 1.4 christos { 3606 1.4 christos struct evhttp_bound_socket *bound; 3607 1.4 christos 3608 1.4 christos TAILQ_FOREACH(bound, &http->sockets, next) 3609 1.4 christos function(bound, argument); 3610 1.4 christos } 3611 1.1 plunky 3612 1.2 christos struct evhttp_bound_socket * 3613 1.2 christos evhttp_accept_socket_with_handle(struct evhttp *http, evutil_socket_t fd) 3614 1.2 christos { 3615 1.2 christos struct evhttp_bound_socket *bound; 3616 1.2 christos struct evconnlistener *listener; 3617 1.2 christos const int flags = 3618 1.2 christos LEV_OPT_REUSEABLE|LEV_OPT_CLOSE_ON_EXEC|LEV_OPT_CLOSE_ON_FREE; 3619 1.2 christos 3620 1.2 christos listener = evconnlistener_new(http->base, NULL, NULL, 3621 1.2 christos flags, 3622 1.2 christos 0, /* Backlog is '0' because we already said 'listen' */ 3623 1.2 christos fd); 3624 1.2 christos if (!listener) 3625 1.2 christos return (NULL); 3626 1.2 christos 3627 1.2 christos bound = evhttp_bind_listener(http, listener); 3628 1.2 christos if (!bound) { 3629 1.2 christos evconnlistener_free(listener); 3630 1.2 christos return (NULL); 3631 1.2 christos } 3632 1.2 christos return (bound); 3633 1.2 christos } 3634 1.1 plunky 3635 1.2 christos struct evhttp_bound_socket * 3636 1.2 christos evhttp_bind_listener(struct evhttp *http, struct evconnlistener *listener) 3637 1.2 christos { 3638 1.2 christos struct evhttp_bound_socket *bound; 3639 1.1 plunky 3640 1.2 christos bound = mm_malloc(sizeof(struct evhttp_bound_socket)); 3641 1.2 christos if (bound == NULL) 3642 1.2 christos return (NULL); 3643 1.1 plunky 3644 1.2 christos bound->listener = listener; 3645 1.1 plunky TAILQ_INSERT_TAIL(&http->sockets, bound, next); 3646 1.1 plunky 3647 1.2 christos evconnlistener_set_cb(listener, accept_socket_cb, http); 3648 1.2 christos return bound; 3649 1.2 christos } 3650 1.2 christos 3651 1.2 christos evutil_socket_t 3652 1.2 christos evhttp_bound_socket_get_fd(struct evhttp_bound_socket *bound) 3653 1.2 christos { 3654 1.2 christos return evconnlistener_get_fd(bound->listener); 3655 1.2 christos } 3656 1.2 christos 3657 1.2 christos struct evconnlistener * 3658 1.2 christos evhttp_bound_socket_get_listener(struct evhttp_bound_socket *bound) 3659 1.2 christos { 3660 1.2 christos return bound->listener; 3661 1.2 christos } 3662 1.2 christos 3663 1.2 christos void 3664 1.2 christos evhttp_del_accept_socket(struct evhttp *http, struct evhttp_bound_socket *bound) 3665 1.2 christos { 3666 1.2 christos TAILQ_REMOVE(&http->sockets, bound, next); 3667 1.2 christos evconnlistener_free(bound->listener); 3668 1.2 christos mm_free(bound); 3669 1.1 plunky } 3670 1.1 plunky 3671 1.1 plunky static struct evhttp* 3672 1.1 plunky evhttp_new_object(void) 3673 1.1 plunky { 3674 1.1 plunky struct evhttp *http = NULL; 3675 1.1 plunky 3676 1.2 christos if ((http = mm_calloc(1, sizeof(struct evhttp))) == NULL) { 3677 1.1 plunky event_warn("%s: calloc", __func__); 3678 1.1 plunky return (NULL); 3679 1.1 plunky } 3680 1.1 plunky 3681 1.4 christos evutil_timerclear(&http->timeout); 3682 1.2 christos evhttp_set_max_headers_size(http, EV_SIZE_MAX); 3683 1.2 christos evhttp_set_max_body_size(http, EV_SIZE_MAX); 3684 1.4 christos evhttp_set_default_content_type(http, "text/html; charset=ISO-8859-1"); 3685 1.2 christos evhttp_set_allowed_methods(http, 3686 1.2 christos EVHTTP_REQ_GET | 3687 1.2 christos EVHTTP_REQ_POST | 3688 1.2 christos EVHTTP_REQ_HEAD | 3689 1.2 christos EVHTTP_REQ_PUT | 3690 1.2 christos EVHTTP_REQ_DELETE); 3691 1.1 plunky 3692 1.1 plunky TAILQ_INIT(&http->sockets); 3693 1.1 plunky TAILQ_INIT(&http->callbacks); 3694 1.1 plunky TAILQ_INIT(&http->connections); 3695 1.2 christos TAILQ_INIT(&http->virtualhosts); 3696 1.2 christos TAILQ_INIT(&http->aliases); 3697 1.1 plunky 3698 1.1 plunky return (http); 3699 1.1 plunky } 3700 1.1 plunky 3701 1.1 plunky struct evhttp * 3702 1.1 plunky evhttp_new(struct event_base *base) 3703 1.1 plunky { 3704 1.2 christos struct evhttp *http = NULL; 3705 1.1 plunky 3706 1.2 christos http = evhttp_new_object(); 3707 1.2 christos if (http == NULL) 3708 1.2 christos return (NULL); 3709 1.1 plunky http->base = base; 3710 1.1 plunky 3711 1.1 plunky return (http); 3712 1.1 plunky } 3713 1.1 plunky 3714 1.1 plunky /* 3715 1.1 plunky * Start a web server on the specified address and port. 3716 1.1 plunky */ 3717 1.1 plunky 3718 1.1 plunky struct evhttp * 3719 1.4 christos evhttp_start(const char *address, ev_uint16_t port) 3720 1.1 plunky { 3721 1.2 christos struct evhttp *http = NULL; 3722 1.1 plunky 3723 1.2 christos http = evhttp_new_object(); 3724 1.2 christos if (http == NULL) 3725 1.2 christos return (NULL); 3726 1.1 plunky if (evhttp_bind_socket(http, address, port) == -1) { 3727 1.2 christos mm_free(http); 3728 1.1 plunky return (NULL); 3729 1.1 plunky } 3730 1.1 plunky 3731 1.1 plunky return (http); 3732 1.1 plunky } 3733 1.1 plunky 3734 1.1 plunky void 3735 1.1 plunky evhttp_free(struct evhttp* http) 3736 1.1 plunky { 3737 1.1 plunky struct evhttp_cb *http_cb; 3738 1.1 plunky struct evhttp_connection *evcon; 3739 1.1 plunky struct evhttp_bound_socket *bound; 3740 1.2 christos struct evhttp* vhost; 3741 1.2 christos struct evhttp_server_alias *alias; 3742 1.1 plunky 3743 1.1 plunky /* Remove the accepting part */ 3744 1.1 plunky while ((bound = TAILQ_FIRST(&http->sockets)) != NULL) { 3745 1.1 plunky TAILQ_REMOVE(&http->sockets, bound, next); 3746 1.1 plunky 3747 1.2 christos evconnlistener_free(bound->listener); 3748 1.1 plunky 3749 1.2 christos mm_free(bound); 3750 1.1 plunky } 3751 1.1 plunky 3752 1.1 plunky while ((evcon = TAILQ_FIRST(&http->connections)) != NULL) { 3753 1.1 plunky /* evhttp_connection_free removes the connection */ 3754 1.1 plunky evhttp_connection_free(evcon); 3755 1.1 plunky } 3756 1.1 plunky 3757 1.1 plunky while ((http_cb = TAILQ_FIRST(&http->callbacks)) != NULL) { 3758 1.1 plunky TAILQ_REMOVE(&http->callbacks, http_cb, next); 3759 1.2 christos mm_free(http_cb->what); 3760 1.2 christos mm_free(http_cb); 3761 1.2 christos } 3762 1.2 christos 3763 1.2 christos while ((vhost = TAILQ_FIRST(&http->virtualhosts)) != NULL) { 3764 1.2 christos TAILQ_REMOVE(&http->virtualhosts, vhost, next_vhost); 3765 1.2 christos 3766 1.2 christos evhttp_free(vhost); 3767 1.2 christos } 3768 1.2 christos 3769 1.2 christos if (http->vhost_pattern != NULL) 3770 1.2 christos mm_free(http->vhost_pattern); 3771 1.2 christos 3772 1.2 christos while ((alias = TAILQ_FIRST(&http->aliases)) != NULL) { 3773 1.2 christos TAILQ_REMOVE(&http->aliases, alias, next); 3774 1.2 christos mm_free(alias->alias); 3775 1.2 christos mm_free(alias); 3776 1.2 christos } 3777 1.2 christos 3778 1.2 christos mm_free(http); 3779 1.2 christos } 3780 1.2 christos 3781 1.2 christos int 3782 1.2 christos evhttp_add_virtual_host(struct evhttp* http, const char *pattern, 3783 1.2 christos struct evhttp* vhost) 3784 1.2 christos { 3785 1.2 christos /* a vhost can only be a vhost once and should not have bound sockets */ 3786 1.2 christos if (vhost->vhost_pattern != NULL || 3787 1.2 christos TAILQ_FIRST(&vhost->sockets) != NULL) 3788 1.2 christos return (-1); 3789 1.2 christos 3790 1.2 christos vhost->vhost_pattern = mm_strdup(pattern); 3791 1.2 christos if (vhost->vhost_pattern == NULL) 3792 1.2 christos return (-1); 3793 1.2 christos 3794 1.2 christos TAILQ_INSERT_TAIL(&http->virtualhosts, vhost, next_vhost); 3795 1.2 christos 3796 1.2 christos return (0); 3797 1.2 christos } 3798 1.2 christos 3799 1.2 christos int 3800 1.2 christos evhttp_remove_virtual_host(struct evhttp* http, struct evhttp* vhost) 3801 1.2 christos { 3802 1.2 christos if (vhost->vhost_pattern == NULL) 3803 1.2 christos return (-1); 3804 1.2 christos 3805 1.2 christos TAILQ_REMOVE(&http->virtualhosts, vhost, next_vhost); 3806 1.2 christos 3807 1.2 christos mm_free(vhost->vhost_pattern); 3808 1.2 christos vhost->vhost_pattern = NULL; 3809 1.2 christos 3810 1.2 christos return (0); 3811 1.2 christos } 3812 1.2 christos 3813 1.2 christos int 3814 1.2 christos evhttp_add_server_alias(struct evhttp *http, const char *alias) 3815 1.2 christos { 3816 1.2 christos struct evhttp_server_alias *evalias; 3817 1.2 christos 3818 1.2 christos evalias = mm_calloc(1, sizeof(*evalias)); 3819 1.2 christos if (!evalias) 3820 1.2 christos return -1; 3821 1.2 christos 3822 1.2 christos evalias->alias = mm_strdup(alias); 3823 1.2 christos if (!evalias->alias) { 3824 1.2 christos mm_free(evalias); 3825 1.2 christos return -1; 3826 1.2 christos } 3827 1.2 christos 3828 1.2 christos TAILQ_INSERT_TAIL(&http->aliases, evalias, next); 3829 1.2 christos 3830 1.2 christos return 0; 3831 1.2 christos } 3832 1.2 christos 3833 1.2 christos int 3834 1.2 christos evhttp_remove_server_alias(struct evhttp *http, const char *alias) 3835 1.2 christos { 3836 1.2 christos struct evhttp_server_alias *evalias; 3837 1.2 christos 3838 1.2 christos TAILQ_FOREACH(evalias, &http->aliases, next) { 3839 1.2 christos if (evutil_ascii_strcasecmp(evalias->alias, alias) == 0) { 3840 1.2 christos TAILQ_REMOVE(&http->aliases, evalias, next); 3841 1.2 christos mm_free(evalias->alias); 3842 1.2 christos mm_free(evalias); 3843 1.2 christos return 0; 3844 1.2 christos } 3845 1.1 plunky } 3846 1.2 christos 3847 1.2 christos return -1; 3848 1.1 plunky } 3849 1.1 plunky 3850 1.1 plunky void 3851 1.1 plunky evhttp_set_timeout(struct evhttp* http, int timeout_in_secs) 3852 1.1 plunky { 3853 1.4 christos if (timeout_in_secs == -1) { 3854 1.4 christos evhttp_set_timeout_tv(http, NULL); 3855 1.4 christos } else { 3856 1.4 christos struct timeval tv; 3857 1.4 christos tv.tv_sec = timeout_in_secs; 3858 1.4 christos tv.tv_usec = 0; 3859 1.4 christos evhttp_set_timeout_tv(http, &tv); 3860 1.4 christos } 3861 1.4 christos } 3862 1.4 christos 3863 1.4 christos void 3864 1.4 christos evhttp_set_timeout_tv(struct evhttp* http, const struct timeval* tv) 3865 1.4 christos { 3866 1.4 christos if (tv) { 3867 1.4 christos http->timeout = *tv; 3868 1.4 christos } else { 3869 1.4 christos evutil_timerclear(&http->timeout); 3870 1.4 christos } 3871 1.4 christos } 3872 1.4 christos 3873 1.4 christos int evhttp_set_flags(struct evhttp *http, int flags) 3874 1.4 christos { 3875 1.4 christos int avail_flags = 0; 3876 1.4 christos avail_flags |= EVHTTP_SERVER_LINGERING_CLOSE; 3877 1.4 christos 3878 1.4 christos if (flags & ~avail_flags) 3879 1.4 christos return 1; 3880 1.4 christos http->flags &= ~avail_flags; 3881 1.4 christos 3882 1.4 christos http->flags |= flags; 3883 1.4 christos 3884 1.4 christos return 0; 3885 1.1 plunky } 3886 1.1 plunky 3887 1.1 plunky void 3888 1.2 christos evhttp_set_max_headers_size(struct evhttp* http, ev_ssize_t max_headers_size) 3889 1.2 christos { 3890 1.2 christos if (max_headers_size < 0) 3891 1.2 christos http->default_max_headers_size = EV_SIZE_MAX; 3892 1.2 christos else 3893 1.2 christos http->default_max_headers_size = max_headers_size; 3894 1.2 christos } 3895 1.2 christos 3896 1.2 christos void 3897 1.2 christos evhttp_set_max_body_size(struct evhttp* http, ev_ssize_t max_body_size) 3898 1.2 christos { 3899 1.2 christos if (max_body_size < 0) 3900 1.2 christos http->default_max_body_size = EV_UINT64_MAX; 3901 1.2 christos else 3902 1.2 christos http->default_max_body_size = max_body_size; 3903 1.2 christos } 3904 1.2 christos 3905 1.2 christos void 3906 1.4 christos evhttp_set_default_content_type(struct evhttp *http, 3907 1.4 christos const char *content_type) { 3908 1.4 christos http->default_content_type = content_type; 3909 1.4 christos } 3910 1.4 christos 3911 1.4 christos void 3912 1.2 christos evhttp_set_allowed_methods(struct evhttp* http, ev_uint16_t methods) 3913 1.2 christos { 3914 1.2 christos http->allowed_methods = methods; 3915 1.2 christos } 3916 1.2 christos 3917 1.2 christos int 3918 1.1 plunky evhttp_set_cb(struct evhttp *http, const char *uri, 3919 1.1 plunky void (*cb)(struct evhttp_request *, void *), void *cbarg) 3920 1.1 plunky { 3921 1.1 plunky struct evhttp_cb *http_cb; 3922 1.1 plunky 3923 1.2 christos TAILQ_FOREACH(http_cb, &http->callbacks, next) { 3924 1.2 christos if (strcmp(http_cb->what, uri) == 0) 3925 1.2 christos return (-1); 3926 1.2 christos } 3927 1.2 christos 3928 1.2 christos if ((http_cb = mm_calloc(1, sizeof(struct evhttp_cb))) == NULL) { 3929 1.2 christos event_warn("%s: calloc", __func__); 3930 1.2 christos return (-2); 3931 1.2 christos } 3932 1.1 plunky 3933 1.2 christos http_cb->what = mm_strdup(uri); 3934 1.2 christos if (http_cb->what == NULL) { 3935 1.2 christos event_warn("%s: strdup", __func__); 3936 1.2 christos mm_free(http_cb); 3937 1.2 christos return (-3); 3938 1.2 christos } 3939 1.1 plunky http_cb->cb = cb; 3940 1.1 plunky http_cb->cbarg = cbarg; 3941 1.1 plunky 3942 1.1 plunky TAILQ_INSERT_TAIL(&http->callbacks, http_cb, next); 3943 1.2 christos 3944 1.2 christos return (0); 3945 1.1 plunky } 3946 1.1 plunky 3947 1.1 plunky int 3948 1.1 plunky evhttp_del_cb(struct evhttp *http, const char *uri) 3949 1.1 plunky { 3950 1.1 plunky struct evhttp_cb *http_cb; 3951 1.1 plunky 3952 1.1 plunky TAILQ_FOREACH(http_cb, &http->callbacks, next) { 3953 1.1 plunky if (strcmp(http_cb->what, uri) == 0) 3954 1.1 plunky break; 3955 1.1 plunky } 3956 1.1 plunky if (http_cb == NULL) 3957 1.1 plunky return (-1); 3958 1.1 plunky 3959 1.1 plunky TAILQ_REMOVE(&http->callbacks, http_cb, next); 3960 1.2 christos mm_free(http_cb->what); 3961 1.2 christos mm_free(http_cb); 3962 1.1 plunky 3963 1.1 plunky return (0); 3964 1.1 plunky } 3965 1.1 plunky 3966 1.1 plunky void 3967 1.1 plunky evhttp_set_gencb(struct evhttp *http, 3968 1.1 plunky void (*cb)(struct evhttp_request *, void *), void *cbarg) 3969 1.1 plunky { 3970 1.1 plunky http->gencb = cb; 3971 1.1 plunky http->gencbarg = cbarg; 3972 1.1 plunky } 3973 1.1 plunky 3974 1.4 christos void 3975 1.4 christos evhttp_set_bevcb(struct evhttp *http, 3976 1.4 christos struct bufferevent* (*cb)(struct event_base *, void *), void *cbarg) 3977 1.4 christos { 3978 1.4 christos http->bevcb = cb; 3979 1.4 christos http->bevcbarg = cbarg; 3980 1.4 christos } 3981 1.4 christos 3982 1.1 plunky /* 3983 1.1 plunky * Request related functions 3984 1.1 plunky */ 3985 1.1 plunky 3986 1.1 plunky struct evhttp_request * 3987 1.1 plunky evhttp_request_new(void (*cb)(struct evhttp_request *, void *), void *arg) 3988 1.1 plunky { 3989 1.1 plunky struct evhttp_request *req = NULL; 3990 1.1 plunky 3991 1.1 plunky /* Allocate request structure */ 3992 1.2 christos if ((req = mm_calloc(1, sizeof(struct evhttp_request))) == NULL) { 3993 1.1 plunky event_warn("%s: calloc", __func__); 3994 1.1 plunky goto error; 3995 1.1 plunky } 3996 1.1 plunky 3997 1.2 christos req->headers_size = 0; 3998 1.2 christos req->body_size = 0; 3999 1.2 christos 4000 1.1 plunky req->kind = EVHTTP_RESPONSE; 4001 1.2 christos req->input_headers = mm_calloc(1, sizeof(struct evkeyvalq)); 4002 1.1 plunky if (req->input_headers == NULL) { 4003 1.1 plunky event_warn("%s: calloc", __func__); 4004 1.1 plunky goto error; 4005 1.1 plunky } 4006 1.1 plunky TAILQ_INIT(req->input_headers); 4007 1.1 plunky 4008 1.2 christos req->output_headers = mm_calloc(1, sizeof(struct evkeyvalq)); 4009 1.1 plunky if (req->output_headers == NULL) { 4010 1.1 plunky event_warn("%s: calloc", __func__); 4011 1.1 plunky goto error; 4012 1.1 plunky } 4013 1.1 plunky TAILQ_INIT(req->output_headers); 4014 1.1 plunky 4015 1.1 plunky if ((req->input_buffer = evbuffer_new()) == NULL) { 4016 1.1 plunky event_warn("%s: evbuffer_new", __func__); 4017 1.1 plunky goto error; 4018 1.1 plunky } 4019 1.1 plunky 4020 1.1 plunky if ((req->output_buffer = evbuffer_new()) == NULL) { 4021 1.1 plunky event_warn("%s: evbuffer_new", __func__); 4022 1.1 plunky goto error; 4023 1.1 plunky } 4024 1.1 plunky 4025 1.1 plunky req->cb = cb; 4026 1.1 plunky req->cb_arg = arg; 4027 1.1 plunky 4028 1.1 plunky return (req); 4029 1.1 plunky 4030 1.1 plunky error: 4031 1.1 plunky if (req != NULL) 4032 1.1 plunky evhttp_request_free(req); 4033 1.1 plunky return (NULL); 4034 1.1 plunky } 4035 1.1 plunky 4036 1.1 plunky void 4037 1.1 plunky evhttp_request_free(struct evhttp_request *req) 4038 1.1 plunky { 4039 1.2 christos if ((req->flags & EVHTTP_REQ_DEFER_FREE) != 0) { 4040 1.2 christos req->flags |= EVHTTP_REQ_NEEDS_FREE; 4041 1.2 christos return; 4042 1.2 christos } 4043 1.2 christos 4044 1.1 plunky if (req->remote_host != NULL) 4045 1.2 christos mm_free(req->remote_host); 4046 1.1 plunky if (req->uri != NULL) 4047 1.2 christos mm_free(req->uri); 4048 1.2 christos if (req->uri_elems != NULL) 4049 1.2 christos evhttp_uri_free(req->uri_elems); 4050 1.1 plunky if (req->response_code_line != NULL) 4051 1.2 christos mm_free(req->response_code_line); 4052 1.2 christos if (req->host_cache != NULL) 4053 1.2 christos mm_free(req->host_cache); 4054 1.1 plunky 4055 1.1 plunky evhttp_clear_headers(req->input_headers); 4056 1.2 christos mm_free(req->input_headers); 4057 1.1 plunky 4058 1.1 plunky evhttp_clear_headers(req->output_headers); 4059 1.2 christos mm_free(req->output_headers); 4060 1.1 plunky 4061 1.1 plunky if (req->input_buffer != NULL) 4062 1.1 plunky evbuffer_free(req->input_buffer); 4063 1.1 plunky 4064 1.1 plunky if (req->output_buffer != NULL) 4065 1.1 plunky evbuffer_free(req->output_buffer); 4066 1.1 plunky 4067 1.2 christos mm_free(req); 4068 1.2 christos } 4069 1.2 christos 4070 1.2 christos void 4071 1.2 christos evhttp_request_own(struct evhttp_request *req) 4072 1.2 christos { 4073 1.2 christos req->flags |= EVHTTP_USER_OWNED; 4074 1.2 christos } 4075 1.2 christos 4076 1.2 christos int 4077 1.2 christos evhttp_request_is_owned(struct evhttp_request *req) 4078 1.2 christos { 4079 1.2 christos return (req->flags & EVHTTP_USER_OWNED) != 0; 4080 1.2 christos } 4081 1.2 christos 4082 1.2 christos struct evhttp_connection * 4083 1.2 christos evhttp_request_get_connection(struct evhttp_request *req) 4084 1.2 christos { 4085 1.2 christos return req->evcon; 4086 1.2 christos } 4087 1.2 christos 4088 1.2 christos struct event_base * 4089 1.2 christos evhttp_connection_get_base(struct evhttp_connection *conn) 4090 1.2 christos { 4091 1.2 christos return conn->base; 4092 1.1 plunky } 4093 1.1 plunky 4094 1.1 plunky void 4095 1.1 plunky evhttp_request_set_chunked_cb(struct evhttp_request *req, 4096 1.1 plunky void (*cb)(struct evhttp_request *, void *)) 4097 1.1 plunky { 4098 1.1 plunky req->chunk_cb = cb; 4099 1.1 plunky } 4100 1.1 plunky 4101 1.4 christos void 4102 1.4 christos evhttp_request_set_header_cb(struct evhttp_request *req, 4103 1.4 christos int (*cb)(struct evhttp_request *, void *)) 4104 1.4 christos { 4105 1.4 christos req->header_cb = cb; 4106 1.4 christos } 4107 1.4 christos 4108 1.4 christos void 4109 1.4 christos evhttp_request_set_error_cb(struct evhttp_request *req, 4110 1.4 christos void (*cb)(enum evhttp_request_error, void *)) 4111 1.4 christos { 4112 1.4 christos req->error_cb = cb; 4113 1.4 christos } 4114 1.4 christos 4115 1.4 christos void 4116 1.4 christos evhttp_request_set_on_complete_cb(struct evhttp_request *req, 4117 1.4 christos void (*cb)(struct evhttp_request *, void *), void *cb_arg) 4118 1.4 christos { 4119 1.4 christos req->on_complete_cb = cb; 4120 1.4 christos req->on_complete_cb_arg = cb_arg; 4121 1.4 christos } 4122 1.4 christos 4123 1.1 plunky /* 4124 1.1 plunky * Allows for inspection of the request URI 4125 1.1 plunky */ 4126 1.1 plunky 4127 1.1 plunky const char * 4128 1.2 christos evhttp_request_get_uri(const struct evhttp_request *req) { 4129 1.1 plunky if (req->uri == NULL) 4130 1.1 plunky event_debug(("%s: request %p has no uri\n", __func__, req)); 4131 1.1 plunky return (req->uri); 4132 1.1 plunky } 4133 1.1 plunky 4134 1.2 christos const struct evhttp_uri * 4135 1.2 christos evhttp_request_get_evhttp_uri(const struct evhttp_request *req) { 4136 1.2 christos if (req->uri_elems == NULL) 4137 1.2 christos event_debug(("%s: request %p has no uri elems\n", 4138 1.2 christos __func__, req)); 4139 1.2 christos return (req->uri_elems); 4140 1.2 christos } 4141 1.2 christos 4142 1.2 christos const char * 4143 1.2 christos evhttp_request_get_host(struct evhttp_request *req) 4144 1.2 christos { 4145 1.2 christos const char *host = NULL; 4146 1.2 christos 4147 1.2 christos if (req->host_cache) 4148 1.2 christos return req->host_cache; 4149 1.2 christos 4150 1.2 christos if (req->uri_elems) 4151 1.2 christos host = evhttp_uri_get_host(req->uri_elems); 4152 1.2 christos if (!host && req->input_headers) { 4153 1.2 christos const char *p; 4154 1.2 christos size_t len; 4155 1.2 christos 4156 1.2 christos host = evhttp_find_header(req->input_headers, "Host"); 4157 1.2 christos /* The Host: header may include a port. Remove it here 4158 1.2 christos to be consistent with uri_elems case above. */ 4159 1.2 christos if (host) { 4160 1.2 christos p = host + strlen(host) - 1; 4161 1.4 christos while (p > host && EVUTIL_ISDIGIT_(*p)) 4162 1.2 christos --p; 4163 1.2 christos if (p > host && *p == ':') { 4164 1.2 christos len = p - host; 4165 1.2 christos req->host_cache = mm_malloc(len + 1); 4166 1.2 christos if (!req->host_cache) { 4167 1.2 christos event_warn("%s: malloc", __func__); 4168 1.2 christos return NULL; 4169 1.2 christos } 4170 1.2 christos memcpy(req->host_cache, host, len); 4171 1.2 christos req->host_cache[len] = '\0'; 4172 1.2 christos host = req->host_cache; 4173 1.2 christos } 4174 1.2 christos } 4175 1.2 christos } 4176 1.2 christos 4177 1.2 christos return host; 4178 1.2 christos } 4179 1.2 christos 4180 1.2 christos enum evhttp_cmd_type 4181 1.2 christos evhttp_request_get_command(const struct evhttp_request *req) { 4182 1.2 christos return (req->type); 4183 1.2 christos } 4184 1.2 christos 4185 1.2 christos int 4186 1.2 christos evhttp_request_get_response_code(const struct evhttp_request *req) 4187 1.2 christos { 4188 1.2 christos return req->response_code; 4189 1.2 christos } 4190 1.2 christos 4191 1.4 christos const char * 4192 1.4 christos evhttp_request_get_response_code_line(const struct evhttp_request *req) 4193 1.4 christos { 4194 1.4 christos return req->response_code_line; 4195 1.4 christos } 4196 1.4 christos 4197 1.2 christos /** Returns the input headers */ 4198 1.2 christos struct evkeyvalq *evhttp_request_get_input_headers(struct evhttp_request *req) 4199 1.2 christos { 4200 1.2 christos return (req->input_headers); 4201 1.2 christos } 4202 1.2 christos 4203 1.2 christos /** Returns the output headers */ 4204 1.2 christos struct evkeyvalq *evhttp_request_get_output_headers(struct evhttp_request *req) 4205 1.2 christos { 4206 1.2 christos return (req->output_headers); 4207 1.2 christos } 4208 1.2 christos 4209 1.2 christos /** Returns the input buffer */ 4210 1.2 christos struct evbuffer *evhttp_request_get_input_buffer(struct evhttp_request *req) 4211 1.2 christos { 4212 1.2 christos return (req->input_buffer); 4213 1.2 christos } 4214 1.2 christos 4215 1.2 christos /** Returns the output buffer */ 4216 1.2 christos struct evbuffer *evhttp_request_get_output_buffer(struct evhttp_request *req) 4217 1.2 christos { 4218 1.2 christos return (req->output_buffer); 4219 1.2 christos } 4220 1.2 christos 4221 1.2 christos 4222 1.2 christos /* 4223 1.2 christos * Takes a file descriptor to read a request from. 4224 1.2 christos * The callback is executed once the whole request has been read. 4225 1.2 christos */ 4226 1.1 plunky 4227 1.1 plunky static struct evhttp_connection* 4228 1.1 plunky evhttp_get_request_connection( 4229 1.1 plunky struct evhttp* http, 4230 1.2 christos evutil_socket_t fd, struct sockaddr *sa, ev_socklen_t salen) 4231 1.1 plunky { 4232 1.1 plunky struct evhttp_connection *evcon; 4233 1.1 plunky char *hostname = NULL, *portname = NULL; 4234 1.4 christos struct bufferevent* bev = NULL; 4235 1.1 plunky 4236 1.5 christos #ifdef EVENT__HAVE_STRUCT_SOCKADDR_UN 4237 1.5 christos if (sa->sa_family == AF_UNIX) { 4238 1.5 christos struct sockaddr_un *sa_un = (struct sockaddr_un *)sa; 4239 1.5 christos sa_un->sun_path[0] = '\0'; 4240 1.5 christos } 4241 1.5 christos #endif 4242 1.5 christos 4243 1.1 plunky name_from_addr(sa, salen, &hostname, &portname); 4244 1.1 plunky if (hostname == NULL || portname == NULL) { 4245 1.2 christos if (hostname) mm_free(hostname); 4246 1.2 christos if (portname) mm_free(portname); 4247 1.1 plunky return (NULL); 4248 1.1 plunky } 4249 1.1 plunky 4250 1.2 christos event_debug(("%s: new request from %s:%s on "EV_SOCK_FMT"\n", 4251 1.2 christos __func__, hostname, portname, EV_SOCK_ARG(fd))); 4252 1.1 plunky 4253 1.1 plunky /* we need a connection object to put the http request on */ 4254 1.4 christos if (http->bevcb != NULL) { 4255 1.4 christos bev = (*http->bevcb)(http->base, http->bevcbarg); 4256 1.4 christos } 4257 1.4 christos evcon = evhttp_connection_base_bufferevent_new( 4258 1.4 christos http->base, NULL, bev, hostname, atoi(portname)); 4259 1.2 christos mm_free(hostname); 4260 1.2 christos mm_free(portname); 4261 1.1 plunky if (evcon == NULL) 4262 1.1 plunky return (NULL); 4263 1.1 plunky 4264 1.2 christos evcon->max_headers_size = http->default_max_headers_size; 4265 1.2 christos evcon->max_body_size = http->default_max_body_size; 4266 1.4 christos if (http->flags & EVHTTP_SERVER_LINGERING_CLOSE) 4267 1.4 christos evcon->flags |= EVHTTP_CON_LINGERING_CLOSE; 4268 1.1 plunky 4269 1.1 plunky evcon->flags |= EVHTTP_CON_INCOMING; 4270 1.1 plunky evcon->state = EVCON_READING_FIRSTLINE; 4271 1.2 christos 4272 1.1 plunky evcon->fd = fd; 4273 1.1 plunky 4274 1.5 christos if (bufferevent_setfd(evcon->bufev, fd)) 4275 1.5 christos goto err; 4276 1.5 christos if (bufferevent_enable(evcon->bufev, EV_READ)) 4277 1.5 christos goto err; 4278 1.5 christos if (bufferevent_disable(evcon->bufev, EV_WRITE)) 4279 1.5 christos goto err; 4280 1.5 christos bufferevent_socket_set_conn_address_(evcon->bufev, sa, salen); 4281 1.2 christos 4282 1.1 plunky return (evcon); 4283 1.5 christos 4284 1.5 christos err: 4285 1.5 christos evhttp_connection_free(evcon); 4286 1.5 christos return (NULL); 4287 1.1 plunky } 4288 1.1 plunky 4289 1.1 plunky static int 4290 1.1 plunky evhttp_associate_new_request_with_connection(struct evhttp_connection *evcon) 4291 1.1 plunky { 4292 1.1 plunky struct evhttp *http = evcon->http_server; 4293 1.1 plunky struct evhttp_request *req; 4294 1.1 plunky if ((req = evhttp_request_new(evhttp_handle_request, http)) == NULL) 4295 1.1 plunky return (-1); 4296 1.1 plunky 4297 1.2 christos if ((req->remote_host = mm_strdup(evcon->address)) == NULL) { 4298 1.2 christos event_warn("%s: strdup", __func__); 4299 1.2 christos evhttp_request_free(req); 4300 1.2 christos return (-1); 4301 1.2 christos } 4302 1.2 christos req->remote_port = evcon->port; 4303 1.2 christos 4304 1.1 plunky req->evcon = evcon; /* the request ends up owning the connection */ 4305 1.1 plunky req->flags |= EVHTTP_REQ_OWN_CONNECTION; 4306 1.2 christos 4307 1.2 christos /* We did not present the request to the user user yet, so treat it as 4308 1.2 christos * if the user was done with the request. This allows us to free the 4309 1.2 christos * request on a persistent connection if the client drops it without 4310 1.2 christos * sending a request. 4311 1.2 christos */ 4312 1.2 christos req->userdone = 1; 4313 1.2 christos 4314 1.1 plunky TAILQ_INSERT_TAIL(&evcon->requests, req, next); 4315 1.2 christos 4316 1.1 plunky req->kind = EVHTTP_REQUEST; 4317 1.2 christos 4318 1.1 plunky 4319 1.4 christos evhttp_start_read_(evcon); 4320 1.2 christos 4321 1.1 plunky return (0); 4322 1.1 plunky } 4323 1.1 plunky 4324 1.2 christos static void 4325 1.2 christos evhttp_get_request(struct evhttp *http, evutil_socket_t fd, 4326 1.2 christos struct sockaddr *sa, ev_socklen_t salen) 4327 1.1 plunky { 4328 1.1 plunky struct evhttp_connection *evcon; 4329 1.1 plunky 4330 1.1 plunky evcon = evhttp_get_request_connection(http, fd, sa, salen); 4331 1.2 christos if (evcon == NULL) { 4332 1.2 christos event_sock_warn(fd, "%s: cannot get connection on "EV_SOCK_FMT, 4333 1.2 christos __func__, EV_SOCK_ARG(fd)); 4334 1.2 christos evutil_closesocket(fd); 4335 1.1 plunky return; 4336 1.2 christos } 4337 1.1 plunky 4338 1.1 plunky /* the timeout can be used by the server to close idle connections */ 4339 1.4 christos if (evutil_timerisset(&http->timeout)) 4340 1.4 christos evhttp_connection_set_timeout_tv(evcon, &http->timeout); 4341 1.1 plunky 4342 1.2 christos /* 4343 1.1 plunky * if we want to accept more than one request on a connection, 4344 1.1 plunky * we need to know which http server it belongs to. 4345 1.1 plunky */ 4346 1.1 plunky evcon->http_server = http; 4347 1.1 plunky TAILQ_INSERT_TAIL(&http->connections, evcon, next); 4348 1.2 christos 4349 1.1 plunky if (evhttp_associate_new_request_with_connection(evcon) == -1) 4350 1.1 plunky evhttp_connection_free(evcon); 4351 1.1 plunky } 4352 1.1 plunky 4353 1.1 plunky 4354 1.1 plunky /* 4355 1.1 plunky * Network helper functions that we do not want to export to the rest of 4356 1.1 plunky * the world. 4357 1.1 plunky */ 4358 1.1 plunky 4359 1.1 plunky static void 4360 1.2 christos name_from_addr(struct sockaddr *sa, ev_socklen_t salen, 4361 1.1 plunky char **phost, char **pport) 4362 1.1 plunky { 4363 1.1 plunky char ntop[NI_MAXHOST]; 4364 1.1 plunky char strport[NI_MAXSERV]; 4365 1.1 plunky int ni_result; 4366 1.1 plunky 4367 1.4 christos #ifdef EVENT__HAVE_GETNAMEINFO 4368 1.1 plunky ni_result = getnameinfo(sa, salen, 4369 1.1 plunky ntop, sizeof(ntop), strport, sizeof(strport), 4370 1.1 plunky NI_NUMERICHOST|NI_NUMERICSERV); 4371 1.2 christos 4372 1.1 plunky if (ni_result != 0) { 4373 1.2 christos #ifdef EAI_SYSTEM 4374 1.2 christos /* Windows doesn't have an EAI_SYSTEM. */ 4375 1.1 plunky if (ni_result == EAI_SYSTEM) 4376 1.1 plunky event_err(1, "getnameinfo failed"); 4377 1.1 plunky else 4378 1.2 christos #endif 4379 1.1 plunky event_errx(1, "getnameinfo failed: %s", gai_strerror(ni_result)); 4380 1.1 plunky return; 4381 1.1 plunky } 4382 1.1 plunky #else 4383 1.1 plunky ni_result = fake_getnameinfo(sa, salen, 4384 1.1 plunky ntop, sizeof(ntop), strport, sizeof(strport), 4385 1.1 plunky NI_NUMERICHOST|NI_NUMERICSERV); 4386 1.1 plunky if (ni_result != 0) 4387 1.1 plunky return; 4388 1.1 plunky #endif 4389 1.2 christos 4390 1.2 christos *phost = mm_strdup(ntop); 4391 1.2 christos *pport = mm_strdup(strport); 4392 1.1 plunky } 4393 1.1 plunky 4394 1.1 plunky /* Create a non-blocking socket and bind it */ 4395 1.2 christos static evutil_socket_t 4396 1.5 christos create_bind_socket_nonblock(struct evutil_addrinfo *ai, int reuse) 4397 1.1 plunky { 4398 1.2 christos evutil_socket_t fd; 4399 1.2 christos 4400 1.2 christos int on = 1, r; 4401 1.1 plunky int serrno; 4402 1.1 plunky 4403 1.2 christos /* Create listen socket */ 4404 1.4 christos fd = evutil_socket_(ai ? ai->ai_family : AF_INET, 4405 1.4 christos SOCK_STREAM|EVUTIL_SOCK_NONBLOCK|EVUTIL_SOCK_CLOEXEC, 0); 4406 1.2 christos if (fd == -1) { 4407 1.2 christos event_sock_warn(-1, "socket"); 4408 1.2 christos return (-1); 4409 1.2 christos } 4410 1.1 plunky 4411 1.2 christos if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (void *)&on, sizeof(on))<0) 4412 1.2 christos goto out; 4413 1.1 plunky if (reuse) { 4414 1.2 christos if (evutil_make_listen_socket_reuseable(fd) < 0) 4415 1.2 christos goto out; 4416 1.1 plunky } 4417 1.1 plunky 4418 1.1 plunky if (ai != NULL) { 4419 1.2 christos r = bind(fd, ai->ai_addr, (ev_socklen_t)ai->ai_addrlen); 4420 1.1 plunky if (r == -1) 4421 1.1 plunky goto out; 4422 1.1 plunky } 4423 1.1 plunky 4424 1.1 plunky return (fd); 4425 1.1 plunky 4426 1.1 plunky out: 4427 1.1 plunky serrno = EVUTIL_SOCKET_ERROR(); 4428 1.2 christos evutil_closesocket(fd); 4429 1.1 plunky EVUTIL_SET_SOCKET_ERROR(serrno); 4430 1.1 plunky return (-1); 4431 1.1 plunky } 4432 1.1 plunky 4433 1.2 christos static struct evutil_addrinfo * 4434 1.2 christos make_addrinfo(const char *address, ev_uint16_t port) 4435 1.1 plunky { 4436 1.2 christos struct evutil_addrinfo *ai = NULL; 4437 1.1 plunky 4438 1.2 christos struct evutil_addrinfo hints; 4439 1.2 christos char strport[NI_MAXSERV]; 4440 1.2 christos int ai_result; 4441 1.1 plunky 4442 1.2 christos memset(&hints, 0, sizeof(hints)); 4443 1.2 christos hints.ai_family = AF_UNSPEC; 4444 1.2 christos hints.ai_socktype = SOCK_STREAM; 4445 1.2 christos /* turn NULL hostname into INADDR_ANY, and skip looking up any address 4446 1.2 christos * types we don't have an interface to connect to. */ 4447 1.2 christos hints.ai_flags = EVUTIL_AI_PASSIVE|EVUTIL_AI_ADDRCONFIG; 4448 1.2 christos evutil_snprintf(strport, sizeof(strport), "%d", port); 4449 1.2 christos if ((ai_result = evutil_getaddrinfo(address, strport, &hints, &ai)) 4450 1.2 christos != 0) { 4451 1.2 christos if (ai_result == EVUTIL_EAI_SYSTEM) 4452 1.2 christos event_warn("getaddrinfo"); 4453 1.2 christos else 4454 1.2 christos event_warnx("getaddrinfo: %s", 4455 1.2 christos evutil_gai_strerror(ai_result)); 4456 1.1 plunky return (NULL); 4457 1.1 plunky } 4458 1.1 plunky 4459 1.2 christos return (ai); 4460 1.1 plunky } 4461 1.1 plunky 4462 1.2 christos static evutil_socket_t 4463 1.2 christos bind_socket(const char *address, ev_uint16_t port, int reuse) 4464 1.1 plunky { 4465 1.2 christos evutil_socket_t fd; 4466 1.2 christos struct evutil_addrinfo *aitop = NULL; 4467 1.1 plunky 4468 1.1 plunky /* just create an unbound socket */ 4469 1.1 plunky if (address == NULL && port == 0) 4470 1.5 christos return create_bind_socket_nonblock(NULL, 0); 4471 1.2 christos 4472 1.1 plunky aitop = make_addrinfo(address, port); 4473 1.1 plunky 4474 1.1 plunky if (aitop == NULL) 4475 1.1 plunky return (-1); 4476 1.1 plunky 4477 1.5 christos fd = create_bind_socket_nonblock(aitop, reuse); 4478 1.1 plunky 4479 1.2 christos evutil_freeaddrinfo(aitop); 4480 1.1 plunky 4481 1.1 plunky return (fd); 4482 1.1 plunky } 4483 1.1 plunky 4484 1.2 christos struct evhttp_uri { 4485 1.2 christos unsigned flags; 4486 1.2 christos char *scheme; /* scheme; e.g http, ftp etc */ 4487 1.2 christos char *userinfo; /* userinfo (typically username:pass), or NULL */ 4488 1.2 christos char *host; /* hostname, IP address, or NULL */ 4489 1.2 christos int port; /* port, or zero */ 4490 1.2 christos char *path; /* path, or "". */ 4491 1.2 christos char *query; /* query, or NULL */ 4492 1.2 christos char *fragment; /* fragment or NULL */ 4493 1.2 christos }; 4494 1.2 christos 4495 1.2 christos struct evhttp_uri * 4496 1.2 christos evhttp_uri_new(void) 4497 1.2 christos { 4498 1.2 christos struct evhttp_uri *uri = mm_calloc(sizeof(struct evhttp_uri), 1); 4499 1.2 christos if (uri) 4500 1.2 christos uri->port = -1; 4501 1.2 christos return uri; 4502 1.2 christos } 4503 1.2 christos 4504 1.2 christos void 4505 1.2 christos evhttp_uri_set_flags(struct evhttp_uri *uri, unsigned flags) 4506 1.2 christos { 4507 1.2 christos uri->flags = flags; 4508 1.2 christos } 4509 1.2 christos 4510 1.2 christos /* Return true if the string starting at s and ending immediately before eos 4511 1.2 christos * is a valid URI scheme according to RFC3986 4512 1.2 christos */ 4513 1.2 christos static int 4514 1.2 christos scheme_ok(const char *s, const char *eos) 4515 1.2 christos { 4516 1.2 christos /* scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." ) */ 4517 1.2 christos EVUTIL_ASSERT(eos >= s); 4518 1.2 christos if (s == eos) 4519 1.2 christos return 0; 4520 1.4 christos if (!EVUTIL_ISALPHA_(*s)) 4521 1.2 christos return 0; 4522 1.2 christos while (++s < eos) { 4523 1.4 christos if (! EVUTIL_ISALNUM_(*s) && 4524 1.2 christos *s != '+' && *s != '-' && *s != '.') 4525 1.2 christos return 0; 4526 1.2 christos } 4527 1.2 christos return 1; 4528 1.2 christos } 4529 1.2 christos 4530 1.2 christos #define SUBDELIMS "!$&'()*+,;=" 4531 1.2 christos 4532 1.2 christos /* Return true iff [s..eos) is a valid userinfo */ 4533 1.2 christos static int 4534 1.2 christos userinfo_ok(const char *s, const char *eos) 4535 1.2 christos { 4536 1.2 christos while (s < eos) { 4537 1.2 christos if (CHAR_IS_UNRESERVED(*s) || 4538 1.2 christos strchr(SUBDELIMS, *s) || 4539 1.2 christos *s == ':') 4540 1.2 christos ++s; 4541 1.2 christos else if (*s == '%' && s+2 < eos && 4542 1.4 christos EVUTIL_ISXDIGIT_(s[1]) && 4543 1.4 christos EVUTIL_ISXDIGIT_(s[2])) 4544 1.2 christos s += 3; 4545 1.2 christos else 4546 1.2 christos return 0; 4547 1.2 christos } 4548 1.2 christos return 1; 4549 1.2 christos } 4550 1.2 christos 4551 1.2 christos static int 4552 1.2 christos regname_ok(const char *s, const char *eos) 4553 1.2 christos { 4554 1.2 christos while (s && s<eos) { 4555 1.2 christos if (CHAR_IS_UNRESERVED(*s) || 4556 1.2 christos strchr(SUBDELIMS, *s)) 4557 1.2 christos ++s; 4558 1.2 christos else if (*s == '%' && 4559 1.4 christos EVUTIL_ISXDIGIT_(s[1]) && 4560 1.4 christos EVUTIL_ISXDIGIT_(s[2])) 4561 1.2 christos s += 3; 4562 1.2 christos else 4563 1.2 christos return 0; 4564 1.2 christos } 4565 1.2 christos return 1; 4566 1.2 christos } 4567 1.2 christos 4568 1.2 christos static int 4569 1.2 christos parse_port(const char *s, const char *eos) 4570 1.2 christos { 4571 1.2 christos int portnum = 0; 4572 1.2 christos while (s < eos) { 4573 1.4 christos if (! EVUTIL_ISDIGIT_(*s)) 4574 1.2 christos return -1; 4575 1.2 christos portnum = (portnum * 10) + (*s - '0'); 4576 1.2 christos if (portnum < 0) 4577 1.2 christos return -1; 4578 1.4 christos if (portnum > 65535) 4579 1.4 christos return -1; 4580 1.2 christos ++s; 4581 1.2 christos } 4582 1.2 christos return portnum; 4583 1.2 christos } 4584 1.2 christos 4585 1.2 christos /* returns 0 for bad, 1 for ipv6, 2 for IPvFuture */ 4586 1.2 christos static int 4587 1.2 christos bracket_addr_ok(const char *s, const char *eos) 4588 1.2 christos { 4589 1.2 christos if (s + 3 > eos || *s != '[' || *(eos-1) != ']') 4590 1.2 christos return 0; 4591 1.2 christos if (s[1] == 'v') { 4592 1.2 christos /* IPvFuture, or junk. 4593 1.2 christos "v" 1*HEXDIG "." 1*( unreserved / sub-delims / ":" ) 4594 1.2 christos */ 4595 1.2 christos s += 2; /* skip [v */ 4596 1.2 christos --eos; 4597 1.4 christos if (!EVUTIL_ISXDIGIT_(*s)) /*require at least one*/ 4598 1.2 christos return 0; 4599 1.2 christos while (s < eos && *s != '.') { 4600 1.4 christos if (EVUTIL_ISXDIGIT_(*s)) 4601 1.2 christos ++s; 4602 1.2 christos else 4603 1.2 christos return 0; 4604 1.2 christos } 4605 1.2 christos if (*s != '.') 4606 1.2 christos return 0; 4607 1.2 christos ++s; 4608 1.2 christos while (s < eos) { 4609 1.2 christos if (CHAR_IS_UNRESERVED(*s) || 4610 1.2 christos strchr(SUBDELIMS, *s) || 4611 1.2 christos *s == ':') 4612 1.2 christos ++s; 4613 1.2 christos else 4614 1.2 christos return 0; 4615 1.2 christos } 4616 1.2 christos return 2; 4617 1.2 christos } else { 4618 1.2 christos /* IPv6, or junk */ 4619 1.2 christos char buf[64]; 4620 1.2 christos ev_ssize_t n_chars = eos-s-2; 4621 1.2 christos struct in6_addr in6; 4622 1.2 christos if (n_chars >= 64) /* way too long */ 4623 1.2 christos return 0; 4624 1.2 christos memcpy(buf, s+1, n_chars); 4625 1.2 christos buf[n_chars]='\0'; 4626 1.2 christos return (evutil_inet_pton(AF_INET6,buf,&in6)==1) ? 1 : 0; 4627 1.2 christos } 4628 1.2 christos } 4629 1.2 christos 4630 1.1 plunky static int 4631 1.2 christos parse_authority(struct evhttp_uri *uri, char *s, char *eos) 4632 1.1 plunky { 4633 1.2 christos char *cp, *port; 4634 1.2 christos EVUTIL_ASSERT(eos); 4635 1.2 christos if (eos == s) { 4636 1.2 christos uri->host = mm_strdup(""); 4637 1.2 christos if (uri->host == NULL) { 4638 1.2 christos event_warn("%s: strdup", __func__); 4639 1.2 christos return -1; 4640 1.2 christos } 4641 1.2 christos return 0; 4642 1.2 christos } 4643 1.1 plunky 4644 1.2 christos /* Optionally, we start with "userinfo@" */ 4645 1.2 christos 4646 1.2 christos cp = strchr(s, '@'); 4647 1.2 christos if (cp && cp < eos) { 4648 1.2 christos if (! userinfo_ok(s,cp)) 4649 1.2 christos return -1; 4650 1.2 christos *cp++ = '\0'; 4651 1.2 christos uri->userinfo = mm_strdup(s); 4652 1.2 christos if (uri->userinfo == NULL) { 4653 1.2 christos event_warn("%s: strdup", __func__); 4654 1.2 christos return -1; 4655 1.2 christos } 4656 1.2 christos } else { 4657 1.2 christos cp = s; 4658 1.2 christos } 4659 1.2 christos /* Optionally, we end with ":port" */ 4660 1.4 christos for (port=eos-1; port >= cp && EVUTIL_ISDIGIT_(*port); --port) 4661 1.2 christos ; 4662 1.2 christos if (port >= cp && *port == ':') { 4663 1.2 christos if (port+1 == eos) /* Leave port unspecified; the RFC allows a 4664 1.2 christos * nil port */ 4665 1.2 christos uri->port = -1; 4666 1.2 christos else if ((uri->port = parse_port(port+1, eos))<0) 4667 1.2 christos return -1; 4668 1.2 christos eos = port; 4669 1.2 christos } 4670 1.2 christos /* Now, cp..eos holds the "host" port, which can be an IPv4Address, 4671 1.2 christos * an IP-Literal, or a reg-name */ 4672 1.2 christos EVUTIL_ASSERT(eos >= cp); 4673 1.2 christos if (*cp == '[' && eos >= cp+2 && *(eos-1) == ']') { 4674 1.2 christos /* IPv6address, IP-Literal, or junk. */ 4675 1.2 christos if (! bracket_addr_ok(cp, eos)) 4676 1.2 christos return -1; 4677 1.2 christos } else { 4678 1.2 christos /* Make sure the host part is ok. */ 4679 1.2 christos if (! regname_ok(cp,eos)) /* Match IPv4Address or reg-name */ 4680 1.2 christos return -1; 4681 1.2 christos } 4682 1.2 christos uri->host = mm_malloc(eos-cp+1); 4683 1.2 christos if (uri->host == NULL) { 4684 1.2 christos event_warn("%s: malloc", __func__); 4685 1.2 christos return -1; 4686 1.2 christos } 4687 1.2 christos memcpy(uri->host, cp, eos-cp); 4688 1.2 christos uri->host[eos-cp] = '\0'; 4689 1.2 christos return 0; 4690 1.2 christos 4691 1.2 christos } 4692 1.2 christos 4693 1.2 christos static char * 4694 1.2 christos end_of_authority(char *cp) 4695 1.2 christos { 4696 1.2 christos while (*cp) { 4697 1.2 christos if (*cp == '?' || *cp == '#' || *cp == '/') 4698 1.2 christos return cp; 4699 1.2 christos ++cp; 4700 1.2 christos } 4701 1.2 christos return cp; 4702 1.2 christos } 4703 1.2 christos 4704 1.2 christos enum uri_part { 4705 1.2 christos PART_PATH, 4706 1.2 christos PART_QUERY, 4707 1.2 christos PART_FRAGMENT 4708 1.2 christos }; 4709 1.2 christos 4710 1.2 christos /* Return the character after the longest prefix of 'cp' that matches... 4711 1.2 christos * *pchar / "/" if allow_qchars is false, or 4712 1.2 christos * *(pchar / "/" / "?") if allow_qchars is true. 4713 1.2 christos */ 4714 1.2 christos static char * 4715 1.2 christos end_of_path(const char *cp, enum uri_part part, unsigned flags) 4716 1.2 christos { 4717 1.2 christos if (flags & EVHTTP_URI_NONCONFORMANT) { 4718 1.2 christos /* If NONCONFORMANT: 4719 1.2 christos * Path is everything up to a # or ? or nul. 4720 1.2 christos * Query is everything up a # or nul 4721 1.2 christos * Fragment is everything up to a nul. 4722 1.2 christos */ 4723 1.2 christos switch (part) { 4724 1.2 christos case PART_PATH: 4725 1.2 christos while (*cp && *cp != '#' && *cp != '?') 4726 1.2 christos ++cp; 4727 1.2 christos break; 4728 1.2 christos case PART_QUERY: 4729 1.2 christos while (*cp && *cp != '#') 4730 1.2 christos ++cp; 4731 1.2 christos break; 4732 1.2 christos case PART_FRAGMENT: 4733 1.2 christos cp += strlen(cp); 4734 1.2 christos break; 4735 1.2 christos }; 4736 1.2 christos return __UNCONST(cp); 4737 1.2 christos } 4738 1.2 christos 4739 1.2 christos while (*cp) { 4740 1.2 christos if (CHAR_IS_UNRESERVED(*cp) || 4741 1.2 christos strchr(SUBDELIMS, *cp) || 4742 1.2 christos *cp == ':' || *cp == '@' || *cp == '/') 4743 1.2 christos ++cp; 4744 1.4 christos else if (*cp == '%' && EVUTIL_ISXDIGIT_(cp[1]) && 4745 1.4 christos EVUTIL_ISXDIGIT_(cp[2])) 4746 1.2 christos cp += 3; 4747 1.2 christos else if (*cp == '?' && part != PART_PATH) 4748 1.2 christos ++cp; 4749 1.2 christos else 4750 1.2 christos return __UNCONST(cp); 4751 1.2 christos } 4752 1.2 christos return __UNCONST(cp); 4753 1.2 christos } 4754 1.2 christos 4755 1.2 christos static int 4756 1.2 christos path_matches_noscheme(const char *cp) 4757 1.2 christos { 4758 1.2 christos while (*cp) { 4759 1.2 christos if (*cp == ':') 4760 1.2 christos return 0; 4761 1.2 christos else if (*cp == '/') 4762 1.2 christos return 1; 4763 1.2 christos ++cp; 4764 1.2 christos } 4765 1.2 christos return 1; 4766 1.2 christos } 4767 1.2 christos 4768 1.2 christos struct evhttp_uri * 4769 1.2 christos evhttp_uri_parse(const char *source_uri) 4770 1.2 christos { 4771 1.2 christos return evhttp_uri_parse_with_flags(source_uri, 0); 4772 1.2 christos } 4773 1.2 christos 4774 1.2 christos struct evhttp_uri * 4775 1.2 christos evhttp_uri_parse_with_flags(const char *source_uri, unsigned flags) 4776 1.2 christos { 4777 1.2 christos char *readbuf = NULL, *readp = NULL, *token = NULL, *query = NULL; 4778 1.2 christos char *path = NULL, *fragment = NULL; 4779 1.2 christos int got_authority = 0; 4780 1.2 christos 4781 1.2 christos struct evhttp_uri *uri = mm_calloc(1, sizeof(struct evhttp_uri)); 4782 1.2 christos if (uri == NULL) { 4783 1.2 christos event_warn("%s: calloc", __func__); 4784 1.2 christos goto err; 4785 1.2 christos } 4786 1.2 christos uri->port = -1; 4787 1.2 christos uri->flags = flags; 4788 1.2 christos 4789 1.2 christos readbuf = mm_strdup(source_uri); 4790 1.2 christos if (readbuf == NULL) { 4791 1.2 christos event_warn("%s: strdup", __func__); 4792 1.2 christos goto err; 4793 1.2 christos } 4794 1.2 christos 4795 1.2 christos readp = readbuf; 4796 1.2 christos token = NULL; 4797 1.2 christos 4798 1.2 christos /* We try to follow RFC3986 here as much as we can, and match 4799 1.2 christos the productions 4800 1.2 christos 4801 1.2 christos URI = scheme ":" hier-part [ "?" query ] [ "#" fragment ] 4802 1.2 christos 4803 1.2 christos relative-ref = relative-part [ "?" query ] [ "#" fragment ] 4804 1.2 christos */ 4805 1.2 christos 4806 1.2 christos /* 1. scheme: */ 4807 1.2 christos token = strchr(readp, ':'); 4808 1.2 christos if (token && scheme_ok(readp,token)) { 4809 1.2 christos *token = '\0'; 4810 1.2 christos uri->scheme = mm_strdup(readp); 4811 1.2 christos if (uri->scheme == NULL) { 4812 1.2 christos event_warn("%s: strdup", __func__); 4813 1.2 christos goto err; 4814 1.2 christos } 4815 1.2 christos readp = token+1; /* eat : */ 4816 1.2 christos } 4817 1.2 christos 4818 1.2 christos /* 2. Optionally, "//" then an 'authority' part. */ 4819 1.2 christos if (readp[0]=='/' && readp[1] == '/') { 4820 1.2 christos char *authority; 4821 1.2 christos readp += 2; 4822 1.2 christos authority = readp; 4823 1.2 christos path = end_of_authority(readp); 4824 1.2 christos if (parse_authority(uri, authority, path) < 0) 4825 1.2 christos goto err; 4826 1.2 christos readp = path; 4827 1.2 christos got_authority = 1; 4828 1.2 christos } 4829 1.2 christos 4830 1.2 christos /* 3. Query: path-abempty, path-absolute, path-rootless, or path-empty 4831 1.2 christos */ 4832 1.2 christos path = readp; 4833 1.2 christos readp = end_of_path(path, PART_PATH, flags); 4834 1.2 christos 4835 1.2 christos /* Query */ 4836 1.2 christos if (*readp == '?') { 4837 1.2 christos *readp = '\0'; 4838 1.2 christos ++readp; 4839 1.2 christos query = readp; 4840 1.2 christos readp = end_of_path(readp, PART_QUERY, flags); 4841 1.2 christos } 4842 1.2 christos /* fragment */ 4843 1.2 christos if (*readp == '#') { 4844 1.2 christos *readp = '\0'; 4845 1.2 christos ++readp; 4846 1.2 christos fragment = readp; 4847 1.2 christos readp = end_of_path(readp, PART_FRAGMENT, flags); 4848 1.2 christos } 4849 1.2 christos if (*readp != '\0') { 4850 1.2 christos goto err; 4851 1.2 christos } 4852 1.2 christos 4853 1.2 christos /* These next two cases may be unreachable; I'm leaving them 4854 1.2 christos * in to be defensive. */ 4855 1.2 christos /* If you didn't get an authority, the path can't begin with "//" */ 4856 1.2 christos if (!got_authority && path[0]=='/' && path[1]=='/') 4857 1.2 christos goto err; 4858 1.2 christos /* If you did get an authority, the path must begin with "/" or be 4859 1.2 christos * empty. */ 4860 1.2 christos if (got_authority && path[0] != '/' && path[0] != '\0') 4861 1.2 christos goto err; 4862 1.2 christos /* (End of maybe-unreachable cases) */ 4863 1.2 christos 4864 1.2 christos /* If there was no scheme, the first part of the path (if any) must 4865 1.2 christos * have no colon in it. */ 4866 1.2 christos if (! uri->scheme && !path_matches_noscheme(path)) 4867 1.2 christos goto err; 4868 1.2 christos 4869 1.2 christos EVUTIL_ASSERT(path); 4870 1.2 christos uri->path = mm_strdup(path); 4871 1.2 christos if (uri->path == NULL) { 4872 1.2 christos event_warn("%s: strdup", __func__); 4873 1.2 christos goto err; 4874 1.1 plunky } 4875 1.1 plunky 4876 1.2 christos if (query) { 4877 1.2 christos uri->query = mm_strdup(query); 4878 1.2 christos if (uri->query == NULL) { 4879 1.2 christos event_warn("%s: strdup", __func__); 4880 1.2 christos goto err; 4881 1.2 christos } 4882 1.2 christos } 4883 1.2 christos if (fragment) { 4884 1.2 christos uri->fragment = mm_strdup(fragment); 4885 1.2 christos if (uri->fragment == NULL) { 4886 1.2 christos event_warn("%s: strdup", __func__); 4887 1.2 christos goto err; 4888 1.1 plunky } 4889 1.2 christos } 4890 1.2 christos 4891 1.2 christos mm_free(readbuf); 4892 1.2 christos 4893 1.2 christos return uri; 4894 1.2 christos err: 4895 1.2 christos if (uri) 4896 1.2 christos evhttp_uri_free(uri); 4897 1.2 christos if (readbuf) 4898 1.2 christos mm_free(readbuf); 4899 1.2 christos return NULL; 4900 1.2 christos } 4901 1.2 christos 4902 1.5 christos static struct evhttp_uri * 4903 1.5 christos evhttp_uri_parse_authority(char *source_uri) 4904 1.5 christos { 4905 1.5 christos struct evhttp_uri *uri = mm_calloc(1, sizeof(struct evhttp_uri)); 4906 1.5 christos char *end; 4907 1.5 christos 4908 1.5 christos if (uri == NULL) { 4909 1.5 christos event_warn("%s: calloc", __func__); 4910 1.5 christos goto err; 4911 1.5 christos } 4912 1.5 christos uri->port = -1; 4913 1.5 christos uri->flags = 0; 4914 1.5 christos 4915 1.5 christos end = end_of_authority(source_uri); 4916 1.5 christos if (parse_authority(uri, source_uri, end) < 0) 4917 1.5 christos goto err; 4918 1.5 christos 4919 1.5 christos uri->path = mm_strdup(""); 4920 1.5 christos if (uri->path == NULL) { 4921 1.5 christos event_warn("%s: strdup", __func__); 4922 1.5 christos goto err; 4923 1.5 christos } 4924 1.5 christos 4925 1.5 christos return uri; 4926 1.5 christos err: 4927 1.5 christos if (uri) 4928 1.5 christos evhttp_uri_free(uri); 4929 1.5 christos return NULL; 4930 1.5 christos } 4931 1.5 christos 4932 1.2 christos void 4933 1.2 christos evhttp_uri_free(struct evhttp_uri *uri) 4934 1.2 christos { 4935 1.4 christos #define URI_FREE_STR_(f) \ 4936 1.2 christos if (uri->f) { \ 4937 1.2 christos mm_free(uri->f); \ 4938 1.2 christos } 4939 1.2 christos 4940 1.4 christos URI_FREE_STR_(scheme); 4941 1.4 christos URI_FREE_STR_(userinfo); 4942 1.4 christos URI_FREE_STR_(host); 4943 1.4 christos URI_FREE_STR_(path); 4944 1.4 christos URI_FREE_STR_(query); 4945 1.4 christos URI_FREE_STR_(fragment); 4946 1.2 christos 4947 1.2 christos mm_free(uri); 4948 1.4 christos #undef URI_FREE_STR_ 4949 1.2 christos } 4950 1.2 christos 4951 1.2 christos char * 4952 1.2 christos evhttp_uri_join(struct evhttp_uri *uri, char *buf, size_t limit) 4953 1.2 christos { 4954 1.2 christos struct evbuffer *tmp = 0; 4955 1.2 christos size_t joined_size = 0; 4956 1.2 christos char *output = NULL; 4957 1.2 christos 4958 1.4 christos #define URI_ADD_(f) evbuffer_add(tmp, uri->f, strlen(uri->f)) 4959 1.2 christos 4960 1.2 christos if (!uri || !buf || !limit) 4961 1.2 christos return NULL; 4962 1.2 christos 4963 1.2 christos tmp = evbuffer_new(); 4964 1.2 christos if (!tmp) 4965 1.2 christos return NULL; 4966 1.2 christos 4967 1.2 christos if (uri->scheme) { 4968 1.4 christos URI_ADD_(scheme); 4969 1.2 christos evbuffer_add(tmp, ":", 1); 4970 1.2 christos } 4971 1.2 christos if (uri->host) { 4972 1.2 christos evbuffer_add(tmp, "//", 2); 4973 1.2 christos if (uri->userinfo) 4974 1.2 christos evbuffer_add_printf(tmp,"%s@", uri->userinfo); 4975 1.4 christos URI_ADD_(host); 4976 1.2 christos if (uri->port >= 0) 4977 1.2 christos evbuffer_add_printf(tmp,":%d", uri->port); 4978 1.2 christos 4979 1.2 christos if (uri->path && uri->path[0] != '/' && uri->path[0] != '\0') 4980 1.2 christos goto err; 4981 1.2 christos } 4982 1.2 christos 4983 1.2 christos if (uri->path) 4984 1.4 christos URI_ADD_(path); 4985 1.2 christos 4986 1.2 christos if (uri->query) { 4987 1.2 christos evbuffer_add(tmp, "?", 1); 4988 1.4 christos URI_ADD_(query); 4989 1.2 christos } 4990 1.2 christos 4991 1.2 christos if (uri->fragment) { 4992 1.2 christos evbuffer_add(tmp, "#", 1); 4993 1.4 christos URI_ADD_(fragment); 4994 1.2 christos } 4995 1.2 christos 4996 1.2 christos evbuffer_add(tmp, "\0", 1); /* NUL */ 4997 1.2 christos 4998 1.2 christos joined_size = evbuffer_get_length(tmp); 4999 1.2 christos 5000 1.2 christos if (joined_size > limit) { 5001 1.2 christos /* It doesn't fit. */ 5002 1.2 christos evbuffer_free(tmp); 5003 1.2 christos return NULL; 5004 1.2 christos } 5005 1.2 christos evbuffer_remove(tmp, buf, joined_size); 5006 1.2 christos 5007 1.2 christos output = buf; 5008 1.2 christos err: 5009 1.2 christos evbuffer_free(tmp); 5010 1.2 christos 5011 1.2 christos return output; 5012 1.4 christos #undef URI_ADD_ 5013 1.2 christos } 5014 1.2 christos 5015 1.2 christos const char * 5016 1.2 christos evhttp_uri_get_scheme(const struct evhttp_uri *uri) 5017 1.2 christos { 5018 1.2 christos return uri->scheme; 5019 1.2 christos } 5020 1.2 christos const char * 5021 1.2 christos evhttp_uri_get_userinfo(const struct evhttp_uri *uri) 5022 1.2 christos { 5023 1.2 christos return uri->userinfo; 5024 1.2 christos } 5025 1.2 christos const char * 5026 1.2 christos evhttp_uri_get_host(const struct evhttp_uri *uri) 5027 1.2 christos { 5028 1.2 christos return uri->host; 5029 1.2 christos } 5030 1.2 christos int 5031 1.2 christos evhttp_uri_get_port(const struct evhttp_uri *uri) 5032 1.2 christos { 5033 1.2 christos return uri->port; 5034 1.2 christos } 5035 1.2 christos const char * 5036 1.2 christos evhttp_uri_get_path(const struct evhttp_uri *uri) 5037 1.2 christos { 5038 1.2 christos return uri->path; 5039 1.2 christos } 5040 1.2 christos const char * 5041 1.2 christos evhttp_uri_get_query(const struct evhttp_uri *uri) 5042 1.2 christos { 5043 1.2 christos return uri->query; 5044 1.2 christos } 5045 1.2 christos const char * 5046 1.2 christos evhttp_uri_get_fragment(const struct evhttp_uri *uri) 5047 1.2 christos { 5048 1.2 christos return uri->fragment; 5049 1.2 christos } 5050 1.2 christos 5051 1.4 christos #define URI_SET_STR_(f) do { \ 5052 1.2 christos if (uri->f) \ 5053 1.2 christos mm_free(uri->f); \ 5054 1.2 christos if (f) { \ 5055 1.2 christos if ((uri->f = mm_strdup(f)) == NULL) { \ 5056 1.2 christos event_warn("%s: strdup()", __func__); \ 5057 1.2 christos return -1; \ 5058 1.2 christos } \ 5059 1.2 christos } else { \ 5060 1.2 christos uri->f = NULL; \ 5061 1.2 christos } \ 5062 1.2 christos } while(0) 5063 1.2 christos 5064 1.2 christos int 5065 1.2 christos evhttp_uri_set_scheme(struct evhttp_uri *uri, const char *scheme) 5066 1.2 christos { 5067 1.2 christos if (scheme && !scheme_ok(scheme, scheme+strlen(scheme))) 5068 1.2 christos return -1; 5069 1.2 christos 5070 1.4 christos URI_SET_STR_(scheme); 5071 1.2 christos return 0; 5072 1.2 christos } 5073 1.2 christos int 5074 1.2 christos evhttp_uri_set_userinfo(struct evhttp_uri *uri, const char *userinfo) 5075 1.2 christos { 5076 1.2 christos if (userinfo && !userinfo_ok(userinfo, userinfo+strlen(userinfo))) 5077 1.2 christos return -1; 5078 1.4 christos URI_SET_STR_(userinfo); 5079 1.2 christos return 0; 5080 1.2 christos } 5081 1.2 christos int 5082 1.2 christos evhttp_uri_set_host(struct evhttp_uri *uri, const char *host) 5083 1.2 christos { 5084 1.2 christos if (host) { 5085 1.2 christos if (host[0] == '[') { 5086 1.2 christos if (! bracket_addr_ok(host, host+strlen(host))) 5087 1.2 christos return -1; 5088 1.2 christos } else { 5089 1.2 christos if (! regname_ok(host, host+strlen(host))) 5090 1.2 christos return -1; 5091 1.1 plunky } 5092 1.1 plunky } 5093 1.1 plunky 5094 1.4 christos URI_SET_STR_(host); 5095 1.2 christos return 0; 5096 1.2 christos } 5097 1.2 christos int 5098 1.2 christos evhttp_uri_set_port(struct evhttp_uri *uri, int port) 5099 1.2 christos { 5100 1.2 christos if (port < -1) 5101 1.2 christos return -1; 5102 1.2 christos uri->port = port; 5103 1.2 christos return 0; 5104 1.2 christos } 5105 1.2 christos #define end_of_cpath(cp,p,f) \ 5106 1.2 christos ((const char*)(end_of_path(((const char*)(cp)), (p), (f)))) 5107 1.1 plunky 5108 1.2 christos int 5109 1.2 christos evhttp_uri_set_path(struct evhttp_uri *uri, const char *path) 5110 1.2 christos { 5111 1.2 christos if (path && end_of_cpath(path, PART_PATH, uri->flags) != path+strlen(path)) 5112 1.2 christos return -1; 5113 1.1 plunky 5114 1.4 christos URI_SET_STR_(path); 5115 1.2 christos return 0; 5116 1.2 christos } 5117 1.2 christos int 5118 1.2 christos evhttp_uri_set_query(struct evhttp_uri *uri, const char *query) 5119 1.2 christos { 5120 1.2 christos if (query && end_of_cpath(query, PART_QUERY, uri->flags) != query+strlen(query)) 5121 1.2 christos return -1; 5122 1.4 christos URI_SET_STR_(query); 5123 1.2 christos return 0; 5124 1.2 christos } 5125 1.2 christos int 5126 1.2 christos evhttp_uri_set_fragment(struct evhttp_uri *uri, const char *fragment) 5127 1.2 christos { 5128 1.2 christos if (fragment && end_of_cpath(fragment, PART_FRAGMENT, uri->flags) != fragment+strlen(fragment)) 5129 1.2 christos return -1; 5130 1.4 christos URI_SET_STR_(fragment); 5131 1.2 christos return 0; 5132 1.1 plunky } 5133