1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/ipc/chromium/src/third_party/libevent/http.c Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,4526 @@ 1.4 +/* 1.5 + * Copyright (c) 2002-2007 Niels Provos <provos@citi.umich.edu> 1.6 + * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson 1.7 + * 1.8 + * Redistribution and use in source and binary forms, with or without 1.9 + * modification, are permitted provided that the following conditions 1.10 + * are met: 1.11 + * 1. Redistributions of source code must retain the above copyright 1.12 + * notice, this list of conditions and the following disclaimer. 1.13 + * 2. Redistributions in binary form must reproduce the above copyright 1.14 + * notice, this list of conditions and the following disclaimer in the 1.15 + * documentation and/or other materials provided with the distribution. 1.16 + * 3. The name of the author may not be used to endorse or promote products 1.17 + * derived from this software without specific prior written permission. 1.18 + * 1.19 + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 1.20 + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1.21 + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 1.22 + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 1.23 + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 1.24 + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 1.25 + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 1.26 + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 1.27 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 1.28 + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 1.29 + */ 1.30 + 1.31 +#include "event2/event-config.h" 1.32 + 1.33 +#ifdef _EVENT_HAVE_SYS_PARAM_H 1.34 +#include <sys/param.h> 1.35 +#endif 1.36 +#ifdef _EVENT_HAVE_SYS_TYPES_H 1.37 +#include <sys/types.h> 1.38 +#endif 1.39 + 1.40 +#ifdef _EVENT_HAVE_SYS_TIME_H 1.41 +#include <sys/time.h> 1.42 +#endif 1.43 +#ifdef HAVE_SYS_IOCCOM_H 1.44 +#include <sys/ioccom.h> 1.45 +#endif 1.46 + 1.47 +#ifndef WIN32 1.48 +#include <sys/resource.h> 1.49 +#include <sys/socket.h> 1.50 +#include <sys/stat.h> 1.51 +#include <sys/wait.h> 1.52 +#else 1.53 +#include <winsock2.h> 1.54 +#include <ws2tcpip.h> 1.55 +#endif 1.56 + 1.57 +#include <sys/queue.h> 1.58 + 1.59 +#ifdef _EVENT_HAVE_NETINET_IN_H 1.60 +#include <netinet/in.h> 1.61 +#endif 1.62 +#ifdef _EVENT_HAVE_ARPA_INET_H 1.63 +#include <arpa/inet.h> 1.64 +#endif 1.65 +#ifdef _EVENT_HAVE_NETDB_H 1.66 +#include <netdb.h> 1.67 +#endif 1.68 + 1.69 +#ifdef WIN32 1.70 +#include <winsock2.h> 1.71 +#endif 1.72 + 1.73 +#include <errno.h> 1.74 +#include <stdio.h> 1.75 +#include <stdlib.h> 1.76 +#include <string.h> 1.77 +#ifndef WIN32 1.78 +#include <syslog.h> 1.79 +#endif 1.80 +#include <signal.h> 1.81 +#include <time.h> 1.82 +#ifdef _EVENT_HAVE_UNISTD_H 1.83 +#include <unistd.h> 1.84 +#endif 1.85 +#ifdef _EVENT_HAVE_FCNTL_H 1.86 +#include <fcntl.h> 1.87 +#endif 1.88 + 1.89 +#undef timeout_pending 1.90 +#undef timeout_initialized 1.91 + 1.92 +#include "strlcpy-internal.h" 1.93 +#include "event2/http.h" 1.94 +#include "event2/event.h" 1.95 +#include "event2/buffer.h" 1.96 +#include "event2/bufferevent.h" 1.97 +#include "event2/bufferevent_compat.h" 1.98 +#include "event2/http_struct.h" 1.99 +#include "event2/http_compat.h" 1.100 +#include "event2/util.h" 1.101 +#include "event2/listener.h" 1.102 +#include "log-internal.h" 1.103 +#include "util-internal.h" 1.104 +#include "http-internal.h" 1.105 +#include "mm-internal.h" 1.106 +#include "bufferevent-internal.h" 1.107 + 1.108 +#ifndef _EVENT_HAVE_GETNAMEINFO 1.109 +#define NI_MAXSERV 32 1.110 +#define NI_MAXHOST 1025 1.111 + 1.112 +#ifndef NI_NUMERICHOST 1.113 +#define NI_NUMERICHOST 1 1.114 +#endif 1.115 + 1.116 +#ifndef NI_NUMERICSERV 1.117 +#define NI_NUMERICSERV 2 1.118 +#endif 1.119 + 1.120 +static int 1.121 +fake_getnameinfo(const struct sockaddr *sa, size_t salen, char *host, 1.122 + size_t hostlen, char *serv, size_t servlen, int flags) 1.123 +{ 1.124 + struct sockaddr_in *sin = (struct sockaddr_in *)sa; 1.125 + 1.126 + if (serv != NULL) { 1.127 + char tmpserv[16]; 1.128 + evutil_snprintf(tmpserv, sizeof(tmpserv), 1.129 + "%d", ntohs(sin->sin_port)); 1.130 + if (strlcpy(serv, tmpserv, servlen) >= servlen) 1.131 + return (-1); 1.132 + } 1.133 + 1.134 + if (host != NULL) { 1.135 + if (flags & NI_NUMERICHOST) { 1.136 + if (strlcpy(host, inet_ntoa(sin->sin_addr), 1.137 + hostlen) >= hostlen) 1.138 + return (-1); 1.139 + else 1.140 + return (0); 1.141 + } else { 1.142 + struct hostent *hp; 1.143 + hp = gethostbyaddr((char *)&sin->sin_addr, 1.144 + sizeof(struct in_addr), AF_INET); 1.145 + if (hp == NULL) 1.146 + return (-2); 1.147 + 1.148 + if (strlcpy(host, hp->h_name, hostlen) >= hostlen) 1.149 + return (-1); 1.150 + else 1.151 + return (0); 1.152 + } 1.153 + } 1.154 + return (0); 1.155 +} 1.156 + 1.157 +#endif 1.158 + 1.159 +#define REQ_VERSION_BEFORE(req, major_v, minor_v) \ 1.160 + ((req)->major < (major_v) || \ 1.161 + ((req)->major == (major_v) && (req)->minor < (minor_v))) 1.162 + 1.163 +#define REQ_VERSION_ATLEAST(req, major_v, minor_v) \ 1.164 + ((req)->major > (major_v) || \ 1.165 + ((req)->major == (major_v) && (req)->minor >= (minor_v))) 1.166 + 1.167 +#ifndef MIN 1.168 +#define MIN(a,b) (((a)<(b))?(a):(b)) 1.169 +#endif 1.170 + 1.171 +extern int debug; 1.172 + 1.173 +static evutil_socket_t bind_socket_ai(struct evutil_addrinfo *, int reuse); 1.174 +static evutil_socket_t bind_socket(const char *, ev_uint16_t, int reuse); 1.175 +static void name_from_addr(struct sockaddr *, ev_socklen_t, char **, char **); 1.176 +static int evhttp_associate_new_request_with_connection( 1.177 + struct evhttp_connection *evcon); 1.178 +static void evhttp_connection_start_detectclose( 1.179 + struct evhttp_connection *evcon); 1.180 +static void evhttp_connection_stop_detectclose( 1.181 + struct evhttp_connection *evcon); 1.182 +static void evhttp_request_dispatch(struct evhttp_connection* evcon); 1.183 +static void evhttp_read_firstline(struct evhttp_connection *evcon, 1.184 + struct evhttp_request *req); 1.185 +static void evhttp_read_header(struct evhttp_connection *evcon, 1.186 + struct evhttp_request *req); 1.187 +static int evhttp_add_header_internal(struct evkeyvalq *headers, 1.188 + const char *key, const char *value); 1.189 +static const char *evhttp_response_phrase_internal(int code); 1.190 +static void evhttp_get_request(struct evhttp *, evutil_socket_t, struct sockaddr *, ev_socklen_t); 1.191 +static void evhttp_write_buffer(struct evhttp_connection *, 1.192 + void (*)(struct evhttp_connection *, void *), void *); 1.193 +static void evhttp_make_header(struct evhttp_connection *, struct evhttp_request *); 1.194 + 1.195 +/* callbacks for bufferevent */ 1.196 +static void evhttp_read_cb(struct bufferevent *, void *); 1.197 +static void evhttp_write_cb(struct bufferevent *, void *); 1.198 +static void evhttp_error_cb(struct bufferevent *bufev, short what, void *arg); 1.199 +static int evhttp_decode_uri_internal(const char *uri, size_t length, 1.200 + char *ret, int decode_plus); 1.201 +static int evhttp_find_vhost(struct evhttp *http, struct evhttp **outhttp, 1.202 + const char *hostname); 1.203 + 1.204 +#ifndef _EVENT_HAVE_STRSEP 1.205 +/* strsep replacement for platforms that lack it. Only works if 1.206 + * del is one character long. */ 1.207 +static char * 1.208 +strsep(char **s, const char *del) 1.209 +{ 1.210 + char *d, *tok; 1.211 + EVUTIL_ASSERT(strlen(del) == 1); 1.212 + if (!s || !*s) 1.213 + return NULL; 1.214 + tok = *s; 1.215 + d = strstr(tok, del); 1.216 + if (d) { 1.217 + *d = '\0'; 1.218 + *s = d + 1; 1.219 + } else 1.220 + *s = NULL; 1.221 + return tok; 1.222 +} 1.223 +#endif 1.224 + 1.225 +static size_t 1.226 +html_replace(const char ch, const char **escaped) 1.227 +{ 1.228 + switch (ch) { 1.229 + case '<': 1.230 + *escaped = "<"; 1.231 + return 4; 1.232 + case '>': 1.233 + *escaped = ">"; 1.234 + return 4; 1.235 + case '"': 1.236 + *escaped = """; 1.237 + return 6; 1.238 + case '\'': 1.239 + *escaped = "'"; 1.240 + return 6; 1.241 + case '&': 1.242 + *escaped = "&"; 1.243 + return 5; 1.244 + default: 1.245 + break; 1.246 + } 1.247 + 1.248 + return 1; 1.249 +} 1.250 + 1.251 +/* 1.252 + * Replaces <, >, ", ' and & with <, >, ", 1.253 + * ' and & correspondingly. 1.254 + * 1.255 + * The returned string needs to be freed by the caller. 1.256 + */ 1.257 + 1.258 +char * 1.259 +evhttp_htmlescape(const char *html) 1.260 +{ 1.261 + size_t i; 1.262 + size_t new_size = 0, old_size = 0; 1.263 + char *escaped_html, *p; 1.264 + 1.265 + if (html == NULL) 1.266 + return (NULL); 1.267 + 1.268 + old_size = strlen(html); 1.269 + for (i = 0; i < old_size; ++i) { 1.270 + const char *replaced = NULL; 1.271 + const size_t replace_size = html_replace(html[i], &replaced); 1.272 + if (replace_size > EV_SIZE_MAX - new_size) { 1.273 + event_warn("%s: html_replace overflow", __func__); 1.274 + return (NULL); 1.275 + } 1.276 + new_size += replace_size; 1.277 + } 1.278 + 1.279 + if (new_size == EV_SIZE_MAX) 1.280 + return (NULL); 1.281 + p = escaped_html = mm_malloc(new_size + 1); 1.282 + if (escaped_html == NULL) { 1.283 + event_warn("%s: malloc(%lu)", __func__, 1.284 + (unsigned long)(new_size + 1)); 1.285 + return (NULL); 1.286 + } 1.287 + for (i = 0; i < old_size; ++i) { 1.288 + const char *replaced = &html[i]; 1.289 + const size_t len = html_replace(html[i], &replaced); 1.290 + memcpy(p, replaced, len); 1.291 + p += len; 1.292 + } 1.293 + 1.294 + *p = '\0'; 1.295 + 1.296 + return (escaped_html); 1.297 +} 1.298 + 1.299 +/** Given an evhttp_cmd_type, returns a constant string containing the 1.300 + * equivalent HTTP command, or NULL if the evhttp_command_type is 1.301 + * unrecognized. */ 1.302 +static const char * 1.303 +evhttp_method(enum evhttp_cmd_type type) 1.304 +{ 1.305 + const char *method; 1.306 + 1.307 + switch (type) { 1.308 + case EVHTTP_REQ_GET: 1.309 + method = "GET"; 1.310 + break; 1.311 + case EVHTTP_REQ_POST: 1.312 + method = "POST"; 1.313 + break; 1.314 + case EVHTTP_REQ_HEAD: 1.315 + method = "HEAD"; 1.316 + break; 1.317 + case EVHTTP_REQ_PUT: 1.318 + method = "PUT"; 1.319 + break; 1.320 + case EVHTTP_REQ_DELETE: 1.321 + method = "DELETE"; 1.322 + break; 1.323 + case EVHTTP_REQ_OPTIONS: 1.324 + method = "OPTIONS"; 1.325 + break; 1.326 + case EVHTTP_REQ_TRACE: 1.327 + method = "TRACE"; 1.328 + break; 1.329 + case EVHTTP_REQ_CONNECT: 1.330 + method = "CONNECT"; 1.331 + break; 1.332 + case EVHTTP_REQ_PATCH: 1.333 + method = "PATCH"; 1.334 + break; 1.335 + default: 1.336 + method = NULL; 1.337 + break; 1.338 + } 1.339 + 1.340 + return (method); 1.341 +} 1.342 + 1.343 +/** 1.344 + * Determines if a response should have a body. 1.345 + * Follows the rules in RFC 2616 section 4.3. 1.346 + * @return 1 if the response MUST have a body; 0 if the response MUST NOT have 1.347 + * a body. 1.348 + */ 1.349 +static int 1.350 +evhttp_response_needs_body(struct evhttp_request *req) 1.351 +{ 1.352 + return (req->response_code != HTTP_NOCONTENT && 1.353 + req->response_code != HTTP_NOTMODIFIED && 1.354 + (req->response_code < 100 || req->response_code >= 200) && 1.355 + req->type != EVHTTP_REQ_HEAD); 1.356 +} 1.357 + 1.358 +/** Helper: adds the event 'ev' with the timeout 'timeout', or with 1.359 + * default_timeout if timeout is -1. 1.360 + */ 1.361 +static int 1.362 +evhttp_add_event(struct event *ev, int timeout, int default_timeout) 1.363 +{ 1.364 + if (timeout != 0) { 1.365 + struct timeval tv; 1.366 + 1.367 + evutil_timerclear(&tv); 1.368 + tv.tv_sec = timeout != -1 ? timeout : default_timeout; 1.369 + return event_add(ev, &tv); 1.370 + } else { 1.371 + return event_add(ev, NULL); 1.372 + } 1.373 +} 1.374 + 1.375 +/** Helper: called after we've added some data to an evcon's bufferevent's 1.376 + * output buffer. Sets the evconn's writing-is-done callback, and puts 1.377 + * the bufferevent into writing mode. 1.378 + */ 1.379 +static void 1.380 +evhttp_write_buffer(struct evhttp_connection *evcon, 1.381 + void (*cb)(struct evhttp_connection *, void *), void *arg) 1.382 +{ 1.383 + event_debug(("%s: preparing to write buffer\n", __func__)); 1.384 + 1.385 + /* Set call back */ 1.386 + evcon->cb = cb; 1.387 + evcon->cb_arg = arg; 1.388 + 1.389 + bufferevent_enable(evcon->bufev, EV_WRITE); 1.390 + 1.391 + /* Disable the read callback: we don't actually care about data; 1.392 + * we only care about close detection. (We don't disable reading, 1.393 + * since we *do* want to learn about any close events.) */ 1.394 + bufferevent_setcb(evcon->bufev, 1.395 + NULL, /*read*/ 1.396 + evhttp_write_cb, 1.397 + evhttp_error_cb, 1.398 + evcon); 1.399 +} 1.400 + 1.401 +static void 1.402 +evhttp_send_continue_done(struct evhttp_connection *evcon, void *arg) 1.403 +{ 1.404 + bufferevent_disable(evcon->bufev, EV_WRITE); 1.405 +} 1.406 + 1.407 +static void 1.408 +evhttp_send_continue(struct evhttp_connection *evcon, 1.409 + struct evhttp_request *req) 1.410 +{ 1.411 + bufferevent_enable(evcon->bufev, EV_WRITE); 1.412 + evbuffer_add_printf(bufferevent_get_output(evcon->bufev), 1.413 + "HTTP/%d.%d 100 Continue\r\n\r\n", 1.414 + req->major, req->minor); 1.415 + evcon->cb = evhttp_send_continue_done; 1.416 + evcon->cb_arg = NULL; 1.417 + bufferevent_setcb(evcon->bufev, 1.418 + evhttp_read_cb, 1.419 + evhttp_write_cb, 1.420 + evhttp_error_cb, 1.421 + evcon); 1.422 +} 1.423 + 1.424 +/** Helper: returns true iff evconn is in any connected state. */ 1.425 +static int 1.426 +evhttp_connected(struct evhttp_connection *evcon) 1.427 +{ 1.428 + switch (evcon->state) { 1.429 + case EVCON_DISCONNECTED: 1.430 + case EVCON_CONNECTING: 1.431 + return (0); 1.432 + case EVCON_IDLE: 1.433 + case EVCON_READING_FIRSTLINE: 1.434 + case EVCON_READING_HEADERS: 1.435 + case EVCON_READING_BODY: 1.436 + case EVCON_READING_TRAILER: 1.437 + case EVCON_WRITING: 1.438 + default: 1.439 + return (1); 1.440 + } 1.441 +} 1.442 + 1.443 +/* Create the headers needed for an outgoing HTTP request, adds them to 1.444 + * the request's header list, and writes the request line to the 1.445 + * connection's output buffer. 1.446 + */ 1.447 +static void 1.448 +evhttp_make_header_request(struct evhttp_connection *evcon, 1.449 + struct evhttp_request *req) 1.450 +{ 1.451 + const char *method; 1.452 + 1.453 + evhttp_remove_header(req->output_headers, "Proxy-Connection"); 1.454 + 1.455 + /* Generate request line */ 1.456 + method = evhttp_method(req->type); 1.457 + evbuffer_add_printf(bufferevent_get_output(evcon->bufev), 1.458 + "%s %s HTTP/%d.%d\r\n", 1.459 + method, req->uri, req->major, req->minor); 1.460 + 1.461 + /* Add the content length on a post or put request if missing */ 1.462 + if ((req->type == EVHTTP_REQ_POST || req->type == EVHTTP_REQ_PUT) && 1.463 + evhttp_find_header(req->output_headers, "Content-Length") == NULL){ 1.464 + char size[22]; 1.465 + evutil_snprintf(size, sizeof(size), EV_SIZE_FMT, 1.466 + EV_SIZE_ARG(evbuffer_get_length(req->output_buffer))); 1.467 + evhttp_add_header(req->output_headers, "Content-Length", size); 1.468 + } 1.469 +} 1.470 + 1.471 +/** Return true if the list of headers in 'headers', intepreted with respect 1.472 + * to flags, means that we should send a "connection: close" when the request 1.473 + * is done. */ 1.474 +static int 1.475 +evhttp_is_connection_close(int flags, struct evkeyvalq* headers) 1.476 +{ 1.477 + if (flags & EVHTTP_PROXY_REQUEST) { 1.478 + /* proxy connection */ 1.479 + const char *connection = evhttp_find_header(headers, "Proxy-Connection"); 1.480 + return (connection == NULL || evutil_ascii_strcasecmp(connection, "keep-alive") != 0); 1.481 + } else { 1.482 + const char *connection = evhttp_find_header(headers, "Connection"); 1.483 + return (connection != NULL && evutil_ascii_strcasecmp(connection, "close") == 0); 1.484 + } 1.485 +} 1.486 + 1.487 +/* Return true iff 'headers' contains 'Connection: keep-alive' */ 1.488 +static int 1.489 +evhttp_is_connection_keepalive(struct evkeyvalq* headers) 1.490 +{ 1.491 + const char *connection = evhttp_find_header(headers, "Connection"); 1.492 + return (connection != NULL 1.493 + && evutil_ascii_strncasecmp(connection, "keep-alive", 10) == 0); 1.494 +} 1.495 + 1.496 +/* Add a correct "Date" header to headers, unless it already has one. */ 1.497 +static void 1.498 +evhttp_maybe_add_date_header(struct evkeyvalq *headers) 1.499 +{ 1.500 + if (evhttp_find_header(headers, "Date") == NULL) { 1.501 + char date[50]; 1.502 +#ifndef WIN32 1.503 + struct tm cur; 1.504 +#endif 1.505 + struct tm *cur_p; 1.506 + time_t t = time(NULL); 1.507 +#ifdef WIN32 1.508 + cur_p = gmtime(&t); 1.509 +#else 1.510 + gmtime_r(&t, &cur); 1.511 + cur_p = &cur; 1.512 +#endif 1.513 + if (strftime(date, sizeof(date), 1.514 + "%a, %d %b %Y %H:%M:%S GMT", cur_p) != 0) { 1.515 + evhttp_add_header(headers, "Date", date); 1.516 + } 1.517 + } 1.518 +} 1.519 + 1.520 +/* Add a "Content-Length" header with value 'content_length' to headers, 1.521 + * unless it already has a content-length or transfer-encoding header. */ 1.522 +static void 1.523 +evhttp_maybe_add_content_length_header(struct evkeyvalq *headers, 1.524 + size_t content_length) 1.525 +{ 1.526 + if (evhttp_find_header(headers, "Transfer-Encoding") == NULL && 1.527 + evhttp_find_header(headers, "Content-Length") == NULL) { 1.528 + char len[22]; 1.529 + evutil_snprintf(len, sizeof(len), EV_SIZE_FMT, 1.530 + EV_SIZE_ARG(content_length)); 1.531 + evhttp_add_header(headers, "Content-Length", len); 1.532 + } 1.533 +} 1.534 + 1.535 +/* 1.536 + * Create the headers needed for an HTTP reply in req->output_headers, 1.537 + * and write the first HTTP response for req line to evcon. 1.538 + */ 1.539 +static void 1.540 +evhttp_make_header_response(struct evhttp_connection *evcon, 1.541 + struct evhttp_request *req) 1.542 +{ 1.543 + int is_keepalive = evhttp_is_connection_keepalive(req->input_headers); 1.544 + evbuffer_add_printf(bufferevent_get_output(evcon->bufev), 1.545 + "HTTP/%d.%d %d %s\r\n", 1.546 + req->major, req->minor, req->response_code, 1.547 + req->response_code_line); 1.548 + 1.549 + if (req->major == 1) { 1.550 + if (req->minor >= 1) 1.551 + evhttp_maybe_add_date_header(req->output_headers); 1.552 + 1.553 + /* 1.554 + * if the protocol is 1.0; and the connection was keep-alive 1.555 + * we need to add a keep-alive header, too. 1.556 + */ 1.557 + if (req->minor == 0 && is_keepalive) 1.558 + evhttp_add_header(req->output_headers, 1.559 + "Connection", "keep-alive"); 1.560 + 1.561 + if ((req->minor >= 1 || is_keepalive) && 1.562 + evhttp_response_needs_body(req)) { 1.563 + /* 1.564 + * we need to add the content length if the 1.565 + * user did not give it, this is required for 1.566 + * persistent connections to work. 1.567 + */ 1.568 + evhttp_maybe_add_content_length_header( 1.569 + req->output_headers, 1.570 + evbuffer_get_length(req->output_buffer)); 1.571 + } 1.572 + } 1.573 + 1.574 + /* Potentially add headers for unidentified content. */ 1.575 + if (evhttp_response_needs_body(req)) { 1.576 + if (evhttp_find_header(req->output_headers, 1.577 + "Content-Type") == NULL) { 1.578 + evhttp_add_header(req->output_headers, 1.579 + "Content-Type", "text/html; charset=ISO-8859-1"); 1.580 + } 1.581 + } 1.582 + 1.583 + /* if the request asked for a close, we send a close, too */ 1.584 + if (evhttp_is_connection_close(req->flags, req->input_headers)) { 1.585 + evhttp_remove_header(req->output_headers, "Connection"); 1.586 + if (!(req->flags & EVHTTP_PROXY_REQUEST)) 1.587 + evhttp_add_header(req->output_headers, "Connection", "close"); 1.588 + evhttp_remove_header(req->output_headers, "Proxy-Connection"); 1.589 + } 1.590 +} 1.591 + 1.592 +/** Generate all headers appropriate for sending the http request in req (or 1.593 + * the response, if we're sending a response), and write them to evcon's 1.594 + * bufferevent. Also writes all data from req->output_buffer */ 1.595 +static void 1.596 +evhttp_make_header(struct evhttp_connection *evcon, struct evhttp_request *req) 1.597 +{ 1.598 + struct evkeyval *header; 1.599 + struct evbuffer *output = bufferevent_get_output(evcon->bufev); 1.600 + 1.601 + /* 1.602 + * Depending if this is a HTTP request or response, we might need to 1.603 + * add some new headers or remove existing headers. 1.604 + */ 1.605 + if (req->kind == EVHTTP_REQUEST) { 1.606 + evhttp_make_header_request(evcon, req); 1.607 + } else { 1.608 + evhttp_make_header_response(evcon, req); 1.609 + } 1.610 + 1.611 + TAILQ_FOREACH(header, req->output_headers, next) { 1.612 + evbuffer_add_printf(output, "%s: %s\r\n", 1.613 + header->key, header->value); 1.614 + } 1.615 + evbuffer_add(output, "\r\n", 2); 1.616 + 1.617 + if (evbuffer_get_length(req->output_buffer) > 0) { 1.618 + /* 1.619 + * For a request, we add the POST data, for a reply, this 1.620 + * is the regular data. 1.621 + */ 1.622 + /* XXX We might want to support waiting (a limited amount of 1.623 + time) for a continue status line from the server before 1.624 + sending POST/PUT message bodies. */ 1.625 + evbuffer_add_buffer(output, req->output_buffer); 1.626 + } 1.627 +} 1.628 + 1.629 +void 1.630 +evhttp_connection_set_max_headers_size(struct evhttp_connection *evcon, 1.631 + ev_ssize_t new_max_headers_size) 1.632 +{ 1.633 + if (new_max_headers_size<0) 1.634 + evcon->max_headers_size = EV_SIZE_MAX; 1.635 + else 1.636 + evcon->max_headers_size = new_max_headers_size; 1.637 +} 1.638 +void 1.639 +evhttp_connection_set_max_body_size(struct evhttp_connection* evcon, 1.640 + ev_ssize_t new_max_body_size) 1.641 +{ 1.642 + if (new_max_body_size<0) 1.643 + evcon->max_body_size = EV_UINT64_MAX; 1.644 + else 1.645 + evcon->max_body_size = new_max_body_size; 1.646 +} 1.647 + 1.648 +static int 1.649 +evhttp_connection_incoming_fail(struct evhttp_request *req, 1.650 + enum evhttp_connection_error error) 1.651 +{ 1.652 + switch (error) { 1.653 + case EVCON_HTTP_TIMEOUT: 1.654 + case EVCON_HTTP_EOF: 1.655 + /* 1.656 + * these are cases in which we probably should just 1.657 + * close the connection and not send a reply. this 1.658 + * case may happen when a browser keeps a persistent 1.659 + * connection open and we timeout on the read. when 1.660 + * the request is still being used for sending, we 1.661 + * need to disassociated it from the connection here. 1.662 + */ 1.663 + if (!req->userdone) { 1.664 + /* remove it so that it will not be freed */ 1.665 + TAILQ_REMOVE(&req->evcon->requests, req, next); 1.666 + /* indicate that this request no longer has a 1.667 + * connection object 1.668 + */ 1.669 + req->evcon = NULL; 1.670 + } 1.671 + return (-1); 1.672 + case EVCON_HTTP_INVALID_HEADER: 1.673 + case EVCON_HTTP_BUFFER_ERROR: 1.674 + case EVCON_HTTP_REQUEST_CANCEL: 1.675 + default: /* xxx: probably should just error on default */ 1.676 + /* the callback looks at the uri to determine errors */ 1.677 + if (req->uri) { 1.678 + mm_free(req->uri); 1.679 + req->uri = NULL; 1.680 + } 1.681 + if (req->uri_elems) { 1.682 + evhttp_uri_free(req->uri_elems); 1.683 + req->uri_elems = NULL; 1.684 + } 1.685 + 1.686 + /* 1.687 + * the callback needs to send a reply, once the reply has 1.688 + * been send, the connection should get freed. 1.689 + */ 1.690 + (*req->cb)(req, req->cb_arg); 1.691 + } 1.692 + 1.693 + return (0); 1.694 +} 1.695 + 1.696 +/* Called when evcon has experienced a (non-recoverable? -NM) error, as 1.697 + * given in error. If it's an outgoing connection, reset the connection, 1.698 + * retry any pending requests, and inform the user. If it's incoming, 1.699 + * delegates to evhttp_connection_incoming_fail(). */ 1.700 +void 1.701 +evhttp_connection_fail(struct evhttp_connection *evcon, 1.702 + enum evhttp_connection_error error) 1.703 +{ 1.704 + struct evhttp_request* req = TAILQ_FIRST(&evcon->requests); 1.705 + void (*cb)(struct evhttp_request *, void *); 1.706 + void *cb_arg; 1.707 + EVUTIL_ASSERT(req != NULL); 1.708 + 1.709 + bufferevent_disable(evcon->bufev, EV_READ|EV_WRITE); 1.710 + 1.711 + if (evcon->flags & EVHTTP_CON_INCOMING) { 1.712 + /* 1.713 + * for incoming requests, there are two different 1.714 + * failure cases. it's either a network level error 1.715 + * or an http layer error. for problems on the network 1.716 + * layer like timeouts we just drop the connections. 1.717 + * For HTTP problems, we might have to send back a 1.718 + * reply before the connection can be freed. 1.719 + */ 1.720 + if (evhttp_connection_incoming_fail(req, error) == -1) 1.721 + evhttp_connection_free(evcon); 1.722 + return; 1.723 + } 1.724 + 1.725 + /* when the request was canceled, the callback is not executed */ 1.726 + if (error != EVCON_HTTP_REQUEST_CANCEL) { 1.727 + /* save the callback for later; the cb might free our object */ 1.728 + cb = req->cb; 1.729 + cb_arg = req->cb_arg; 1.730 + } else { 1.731 + cb = NULL; 1.732 + cb_arg = NULL; 1.733 + } 1.734 + 1.735 + /* do not fail all requests; the next request is going to get 1.736 + * send over a new connection. when a user cancels a request, 1.737 + * all other pending requests should be processed as normal 1.738 + */ 1.739 + TAILQ_REMOVE(&evcon->requests, req, next); 1.740 + evhttp_request_free(req); 1.741 + 1.742 + /* reset the connection */ 1.743 + evhttp_connection_reset(evcon); 1.744 + 1.745 + /* We are trying the next request that was queued on us */ 1.746 + if (TAILQ_FIRST(&evcon->requests) != NULL) 1.747 + evhttp_connection_connect(evcon); 1.748 + 1.749 + /* inform the user */ 1.750 + if (cb != NULL) 1.751 + (*cb)(NULL, cb_arg); 1.752 +} 1.753 + 1.754 +/* Bufferevent callback: invoked when any data has been written from an 1.755 + * http connection's bufferevent */ 1.756 +static void 1.757 +evhttp_write_cb(struct bufferevent *bufev, void *arg) 1.758 +{ 1.759 + struct evhttp_connection *evcon = arg; 1.760 + 1.761 + /* Activate our call back */ 1.762 + if (evcon->cb != NULL) 1.763 + (*evcon->cb)(evcon, evcon->cb_arg); 1.764 +} 1.765 + 1.766 +/** 1.767 + * Advance the connection state. 1.768 + * - If this is an outgoing connection, we've just processed the response; 1.769 + * idle or close the connection. 1.770 + * - If this is an incoming connection, we've just processed the request; 1.771 + * respond. 1.772 + */ 1.773 +static void 1.774 +evhttp_connection_done(struct evhttp_connection *evcon) 1.775 +{ 1.776 + struct evhttp_request *req = TAILQ_FIRST(&evcon->requests); 1.777 + int con_outgoing = evcon->flags & EVHTTP_CON_OUTGOING; 1.778 + 1.779 + if (con_outgoing) { 1.780 + /* idle or close the connection */ 1.781 + int need_close; 1.782 + TAILQ_REMOVE(&evcon->requests, req, next); 1.783 + req->evcon = NULL; 1.784 + 1.785 + evcon->state = EVCON_IDLE; 1.786 + 1.787 + need_close = 1.788 + evhttp_is_connection_close(req->flags, req->input_headers)|| 1.789 + evhttp_is_connection_close(req->flags, req->output_headers); 1.790 + 1.791 + /* check if we got asked to close the connection */ 1.792 + if (need_close) 1.793 + evhttp_connection_reset(evcon); 1.794 + 1.795 + if (TAILQ_FIRST(&evcon->requests) != NULL) { 1.796 + /* 1.797 + * We have more requests; reset the connection 1.798 + * and deal with the next request. 1.799 + */ 1.800 + if (!evhttp_connected(evcon)) 1.801 + evhttp_connection_connect(evcon); 1.802 + else 1.803 + evhttp_request_dispatch(evcon); 1.804 + } else if (!need_close) { 1.805 + /* 1.806 + * The connection is going to be persistent, but we 1.807 + * need to detect if the other side closes it. 1.808 + */ 1.809 + evhttp_connection_start_detectclose(evcon); 1.810 + } 1.811 + } else { 1.812 + /* 1.813 + * incoming connection - we need to leave the request on the 1.814 + * connection so that we can reply to it. 1.815 + */ 1.816 + evcon->state = EVCON_WRITING; 1.817 + } 1.818 + 1.819 + /* notify the user of the request */ 1.820 + (*req->cb)(req, req->cb_arg); 1.821 + 1.822 + /* if this was an outgoing request, we own and it's done. so free it. 1.823 + * unless the callback specifically requested to own the request. 1.824 + */ 1.825 + if (con_outgoing && ((req->flags & EVHTTP_USER_OWNED) == 0)) { 1.826 + evhttp_request_free(req); 1.827 + } 1.828 +} 1.829 + 1.830 +/* 1.831 + * Handles reading from a chunked request. 1.832 + * return ALL_DATA_READ: 1.833 + * all data has been read 1.834 + * return MORE_DATA_EXPECTED: 1.835 + * more data is expected 1.836 + * return DATA_CORRUPTED: 1.837 + * data is corrupted 1.838 + * return REQUEST_CANCELED: 1.839 + * request was canceled by the user calling evhttp_cancel_request 1.840 + * return DATA_TOO_LONG: 1.841 + * ran over the maximum limit 1.842 + */ 1.843 + 1.844 +static enum message_read_status 1.845 +evhttp_handle_chunked_read(struct evhttp_request *req, struct evbuffer *buf) 1.846 +{ 1.847 + if (req == NULL || buf == NULL) { 1.848 + return DATA_CORRUPTED; 1.849 + } 1.850 + 1.851 + while (1) { 1.852 + size_t buflen; 1.853 + 1.854 + if ((buflen = evbuffer_get_length(buf)) == 0) { 1.855 + break; 1.856 + } 1.857 + 1.858 + /* evbuffer_get_length returns size_t, but len variable is ssize_t, 1.859 + * check for overflow conditions */ 1.860 + if (buflen > EV_SSIZE_MAX) { 1.861 + return DATA_CORRUPTED; 1.862 + } 1.863 + 1.864 + if (req->ntoread < 0) { 1.865 + /* Read chunk size */ 1.866 + ev_int64_t ntoread; 1.867 + char *p = evbuffer_readln(buf, NULL, EVBUFFER_EOL_CRLF); 1.868 + char *endp; 1.869 + int error; 1.870 + if (p == NULL) 1.871 + break; 1.872 + /* the last chunk is on a new line? */ 1.873 + if (strlen(p) == 0) { 1.874 + mm_free(p); 1.875 + continue; 1.876 + } 1.877 + ntoread = evutil_strtoll(p, &endp, 16); 1.878 + error = (*p == '\0' || 1.879 + (*endp != '\0' && *endp != ' ') || 1.880 + ntoread < 0); 1.881 + mm_free(p); 1.882 + if (error) { 1.883 + /* could not get chunk size */ 1.884 + return (DATA_CORRUPTED); 1.885 + } 1.886 + 1.887 + /* ntoread is signed int64, body_size is unsigned size_t, check for under/overflow conditions */ 1.888 + if ((ev_uint64_t)ntoread > EV_SIZE_MAX - req->body_size) { 1.889 + return DATA_CORRUPTED; 1.890 + } 1.891 + 1.892 + if (req->body_size + (size_t)ntoread > req->evcon->max_body_size) { 1.893 + /* failed body length test */ 1.894 + event_debug(("Request body is too long")); 1.895 + return (DATA_TOO_LONG); 1.896 + } 1.897 + 1.898 + req->body_size += (size_t)ntoread; 1.899 + req->ntoread = ntoread; 1.900 + if (req->ntoread == 0) { 1.901 + /* Last chunk */ 1.902 + return (ALL_DATA_READ); 1.903 + } 1.904 + continue; 1.905 + } 1.906 + 1.907 + /* req->ntoread is signed int64, len is ssize_t, based on arch, 1.908 + * ssize_t could only be 32b, check for these conditions */ 1.909 + if (req->ntoread > EV_SSIZE_MAX) { 1.910 + return DATA_CORRUPTED; 1.911 + } 1.912 + 1.913 + /* don't have enough to complete a chunk; wait for more */ 1.914 + if (req->ntoread > 0 && buflen < (ev_uint64_t)req->ntoread) 1.915 + return (MORE_DATA_EXPECTED); 1.916 + 1.917 + /* Completed chunk */ 1.918 + evbuffer_remove_buffer(buf, req->input_buffer, (size_t)req->ntoread); 1.919 + req->ntoread = -1; 1.920 + if (req->chunk_cb != NULL) { 1.921 + req->flags |= EVHTTP_REQ_DEFER_FREE; 1.922 + (*req->chunk_cb)(req, req->cb_arg); 1.923 + evbuffer_drain(req->input_buffer, 1.924 + evbuffer_get_length(req->input_buffer)); 1.925 + req->flags &= ~EVHTTP_REQ_DEFER_FREE; 1.926 + if ((req->flags & EVHTTP_REQ_NEEDS_FREE) != 0) { 1.927 + return (REQUEST_CANCELED); 1.928 + } 1.929 + } 1.930 + } 1.931 + 1.932 + return (MORE_DATA_EXPECTED); 1.933 +} 1.934 + 1.935 +static void 1.936 +evhttp_read_trailer(struct evhttp_connection *evcon, struct evhttp_request *req) 1.937 +{ 1.938 + struct evbuffer *buf = bufferevent_get_input(evcon->bufev); 1.939 + 1.940 + switch (evhttp_parse_headers(req, buf)) { 1.941 + case DATA_CORRUPTED: 1.942 + case DATA_TOO_LONG: 1.943 + evhttp_connection_fail(evcon, EVCON_HTTP_INVALID_HEADER); 1.944 + break; 1.945 + case ALL_DATA_READ: 1.946 + bufferevent_disable(evcon->bufev, EV_READ); 1.947 + evhttp_connection_done(evcon); 1.948 + break; 1.949 + case MORE_DATA_EXPECTED: 1.950 + case REQUEST_CANCELED: /* ??? */ 1.951 + default: 1.952 + bufferevent_enable(evcon->bufev, EV_READ); 1.953 + break; 1.954 + } 1.955 +} 1.956 + 1.957 +static void 1.958 +evhttp_read_body(struct evhttp_connection *evcon, struct evhttp_request *req) 1.959 +{ 1.960 + struct evbuffer *buf = bufferevent_get_input(evcon->bufev); 1.961 + 1.962 + if (req->chunked) { 1.963 + switch (evhttp_handle_chunked_read(req, buf)) { 1.964 + case ALL_DATA_READ: 1.965 + /* finished last chunk */ 1.966 + evcon->state = EVCON_READING_TRAILER; 1.967 + evhttp_read_trailer(evcon, req); 1.968 + return; 1.969 + case DATA_CORRUPTED: 1.970 + case DATA_TOO_LONG:/*separate error for this? XXX */ 1.971 + /* corrupted data */ 1.972 + evhttp_connection_fail(evcon, 1.973 + EVCON_HTTP_INVALID_HEADER); 1.974 + return; 1.975 + case REQUEST_CANCELED: 1.976 + /* request canceled */ 1.977 + evhttp_request_free(req); 1.978 + return; 1.979 + case MORE_DATA_EXPECTED: 1.980 + default: 1.981 + break; 1.982 + } 1.983 + } else if (req->ntoread < 0) { 1.984 + /* Read until connection close. */ 1.985 + if ((size_t)(req->body_size + evbuffer_get_length(buf)) < req->body_size) { 1.986 + evhttp_connection_fail(evcon, EVCON_HTTP_INVALID_HEADER); 1.987 + return; 1.988 + } 1.989 + 1.990 + req->body_size += evbuffer_get_length(buf); 1.991 + evbuffer_add_buffer(req->input_buffer, buf); 1.992 + } else if (req->chunk_cb != NULL || evbuffer_get_length(buf) >= (size_t)req->ntoread) { 1.993 + /* XXX: the above get_length comparison has to be fixed for overflow conditions! */ 1.994 + /* We've postponed moving the data until now, but we're 1.995 + * about to use it. */ 1.996 + size_t n = evbuffer_get_length(buf); 1.997 + 1.998 + if (n > (size_t) req->ntoread) 1.999 + n = (size_t) req->ntoread; 1.1000 + req->ntoread -= n; 1.1001 + req->body_size += n; 1.1002 + evbuffer_remove_buffer(buf, req->input_buffer, n); 1.1003 + } 1.1004 + 1.1005 + if (req->body_size > req->evcon->max_body_size || 1.1006 + (!req->chunked && req->ntoread >= 0 && 1.1007 + (size_t)req->ntoread > req->evcon->max_body_size)) { 1.1008 + /* XXX: The above casted comparison must checked for overflow */ 1.1009 + /* failed body length test */ 1.1010 + event_debug(("Request body is too long")); 1.1011 + evhttp_connection_fail(evcon, 1.1012 + EVCON_HTTP_INVALID_HEADER); 1.1013 + return; 1.1014 + } 1.1015 + 1.1016 + if (evbuffer_get_length(req->input_buffer) > 0 && req->chunk_cb != NULL) { 1.1017 + req->flags |= EVHTTP_REQ_DEFER_FREE; 1.1018 + (*req->chunk_cb)(req, req->cb_arg); 1.1019 + req->flags &= ~EVHTTP_REQ_DEFER_FREE; 1.1020 + evbuffer_drain(req->input_buffer, 1.1021 + evbuffer_get_length(req->input_buffer)); 1.1022 + if ((req->flags & EVHTTP_REQ_NEEDS_FREE) != 0) { 1.1023 + evhttp_request_free(req); 1.1024 + return; 1.1025 + } 1.1026 + } 1.1027 + 1.1028 + if (req->ntoread == 0) { 1.1029 + bufferevent_disable(evcon->bufev, EV_READ); 1.1030 + /* Completed content length */ 1.1031 + evhttp_connection_done(evcon); 1.1032 + return; 1.1033 + } 1.1034 + 1.1035 + /* Read more! */ 1.1036 + bufferevent_enable(evcon->bufev, EV_READ); 1.1037 +} 1.1038 + 1.1039 +#define get_deferred_queue(evcon) \ 1.1040 + (event_base_get_deferred_cb_queue((evcon)->base)) 1.1041 + 1.1042 +/* 1.1043 + * Gets called when more data becomes available 1.1044 + */ 1.1045 + 1.1046 +static void 1.1047 +evhttp_read_cb(struct bufferevent *bufev, void *arg) 1.1048 +{ 1.1049 + struct evhttp_connection *evcon = arg; 1.1050 + struct evhttp_request *req = TAILQ_FIRST(&evcon->requests); 1.1051 + 1.1052 + /* Cancel if it's pending. */ 1.1053 + event_deferred_cb_cancel(get_deferred_queue(evcon), 1.1054 + &evcon->read_more_deferred_cb); 1.1055 + 1.1056 + switch (evcon->state) { 1.1057 + case EVCON_READING_FIRSTLINE: 1.1058 + evhttp_read_firstline(evcon, req); 1.1059 + /* note the request may have been freed in 1.1060 + * evhttp_read_body */ 1.1061 + break; 1.1062 + case EVCON_READING_HEADERS: 1.1063 + evhttp_read_header(evcon, req); 1.1064 + /* note the request may have been freed in 1.1065 + * evhttp_read_body */ 1.1066 + break; 1.1067 + case EVCON_READING_BODY: 1.1068 + evhttp_read_body(evcon, req); 1.1069 + /* note the request may have been freed in 1.1070 + * evhttp_read_body */ 1.1071 + break; 1.1072 + case EVCON_READING_TRAILER: 1.1073 + evhttp_read_trailer(evcon, req); 1.1074 + break; 1.1075 + case EVCON_IDLE: 1.1076 + { 1.1077 +#ifdef USE_DEBUG 1.1078 + struct evbuffer *input; 1.1079 + size_t total_len; 1.1080 + 1.1081 + input = bufferevent_get_input(evcon->bufev); 1.1082 + total_len = evbuffer_get_length(input); 1.1083 + event_debug(("%s: read "EV_SIZE_FMT 1.1084 + " bytes in EVCON_IDLE state," 1.1085 + " resetting connection", 1.1086 + __func__, EV_SIZE_ARG(total_len))); 1.1087 +#endif 1.1088 + 1.1089 + evhttp_connection_reset(evcon); 1.1090 + } 1.1091 + break; 1.1092 + case EVCON_DISCONNECTED: 1.1093 + case EVCON_CONNECTING: 1.1094 + case EVCON_WRITING: 1.1095 + default: 1.1096 + event_errx(1, "%s: illegal connection state %d", 1.1097 + __func__, evcon->state); 1.1098 + } 1.1099 +} 1.1100 + 1.1101 +static void 1.1102 +evhttp_deferred_read_cb(struct deferred_cb *cb, void *data) 1.1103 +{ 1.1104 + struct evhttp_connection *evcon = data; 1.1105 + evhttp_read_cb(evcon->bufev, evcon); 1.1106 +} 1.1107 + 1.1108 +static void 1.1109 +evhttp_write_connectioncb(struct evhttp_connection *evcon, void *arg) 1.1110 +{ 1.1111 + /* This is after writing the request to the server */ 1.1112 + struct evhttp_request *req = TAILQ_FIRST(&evcon->requests); 1.1113 + EVUTIL_ASSERT(req != NULL); 1.1114 + 1.1115 + EVUTIL_ASSERT(evcon->state == EVCON_WRITING); 1.1116 + 1.1117 + /* We are done writing our header and are now expecting the response */ 1.1118 + req->kind = EVHTTP_RESPONSE; 1.1119 + 1.1120 + evhttp_start_read(evcon); 1.1121 +} 1.1122 + 1.1123 +/* 1.1124 + * Clean up a connection object 1.1125 + */ 1.1126 + 1.1127 +void 1.1128 +evhttp_connection_free(struct evhttp_connection *evcon) 1.1129 +{ 1.1130 + struct evhttp_request *req; 1.1131 + 1.1132 + /* notify interested parties that this connection is going down */ 1.1133 + if (evcon->fd != -1) { 1.1134 + if (evhttp_connected(evcon) && evcon->closecb != NULL) 1.1135 + (*evcon->closecb)(evcon, evcon->closecb_arg); 1.1136 + } 1.1137 + 1.1138 + /* remove all requests that might be queued on this 1.1139 + * connection. for server connections, this should be empty. 1.1140 + * because it gets dequeued either in evhttp_connection_done or 1.1141 + * evhttp_connection_fail. 1.1142 + */ 1.1143 + while ((req = TAILQ_FIRST(&evcon->requests)) != NULL) { 1.1144 + TAILQ_REMOVE(&evcon->requests, req, next); 1.1145 + evhttp_request_free(req); 1.1146 + } 1.1147 + 1.1148 + if (evcon->http_server != NULL) { 1.1149 + struct evhttp *http = evcon->http_server; 1.1150 + TAILQ_REMOVE(&http->connections, evcon, next); 1.1151 + } 1.1152 + 1.1153 + if (event_initialized(&evcon->retry_ev)) { 1.1154 + event_del(&evcon->retry_ev); 1.1155 + event_debug_unassign(&evcon->retry_ev); 1.1156 + } 1.1157 + 1.1158 + if (evcon->bufev != NULL) 1.1159 + bufferevent_free(evcon->bufev); 1.1160 + 1.1161 + event_deferred_cb_cancel(get_deferred_queue(evcon), 1.1162 + &evcon->read_more_deferred_cb); 1.1163 + 1.1164 + if (evcon->fd != -1) { 1.1165 + shutdown(evcon->fd, EVUTIL_SHUT_WR); 1.1166 + evutil_closesocket(evcon->fd); 1.1167 + } 1.1168 + 1.1169 + if (evcon->bind_address != NULL) 1.1170 + mm_free(evcon->bind_address); 1.1171 + 1.1172 + if (evcon->address != NULL) 1.1173 + mm_free(evcon->address); 1.1174 + 1.1175 + mm_free(evcon); 1.1176 +} 1.1177 + 1.1178 +void 1.1179 +evhttp_connection_set_local_address(struct evhttp_connection *evcon, 1.1180 + const char *address) 1.1181 +{ 1.1182 + EVUTIL_ASSERT(evcon->state == EVCON_DISCONNECTED); 1.1183 + if (evcon->bind_address) 1.1184 + mm_free(evcon->bind_address); 1.1185 + if ((evcon->bind_address = mm_strdup(address)) == NULL) 1.1186 + event_warn("%s: strdup", __func__); 1.1187 +} 1.1188 + 1.1189 +void 1.1190 +evhttp_connection_set_local_port(struct evhttp_connection *evcon, 1.1191 + ev_uint16_t port) 1.1192 +{ 1.1193 + EVUTIL_ASSERT(evcon->state == EVCON_DISCONNECTED); 1.1194 + evcon->bind_port = port; 1.1195 +} 1.1196 + 1.1197 +static void 1.1198 +evhttp_request_dispatch(struct evhttp_connection* evcon) 1.1199 +{ 1.1200 + struct evhttp_request *req = TAILQ_FIRST(&evcon->requests); 1.1201 + 1.1202 + /* this should not usually happy but it's possible */ 1.1203 + if (req == NULL) 1.1204 + return; 1.1205 + 1.1206 + /* delete possible close detection events */ 1.1207 + evhttp_connection_stop_detectclose(evcon); 1.1208 + 1.1209 + /* we assume that the connection is connected already */ 1.1210 + EVUTIL_ASSERT(evcon->state == EVCON_IDLE); 1.1211 + 1.1212 + evcon->state = EVCON_WRITING; 1.1213 + 1.1214 + /* Create the header from the store arguments */ 1.1215 + evhttp_make_header(evcon, req); 1.1216 + 1.1217 + evhttp_write_buffer(evcon, evhttp_write_connectioncb, NULL); 1.1218 +} 1.1219 + 1.1220 +/* Reset our connection state: disables reading/writing, closes our fd (if 1.1221 +* any), clears out buffers, and puts us in state DISCONNECTED. */ 1.1222 +void 1.1223 +evhttp_connection_reset(struct evhttp_connection *evcon) 1.1224 +{ 1.1225 + struct evbuffer *tmp; 1.1226 + 1.1227 + /* XXXX This is not actually an optimal fix. Instead we ought to have 1.1228 + an API for "stop connecting", or use bufferevent_setfd to turn off 1.1229 + connecting. But for Libevent 2.0, this seems like a minimal change 1.1230 + least likely to disrupt the rest of the bufferevent and http code. 1.1231 + 1.1232 + Why is this here? If the fd is set in the bufferevent, and the 1.1233 + bufferevent is connecting, then you can't actually stop the 1.1234 + bufferevent from trying to connect with bufferevent_disable(). The 1.1235 + connect will never trigger, since we close the fd, but the timeout 1.1236 + might. That caused an assertion failure in evhttp_connection_fail. 1.1237 + */ 1.1238 + bufferevent_disable_hard(evcon->bufev, EV_READ|EV_WRITE); 1.1239 + 1.1240 + if (evcon->fd != -1) { 1.1241 + /* inform interested parties about connection close */ 1.1242 + if (evhttp_connected(evcon) && evcon->closecb != NULL) 1.1243 + (*evcon->closecb)(evcon, evcon->closecb_arg); 1.1244 + 1.1245 + shutdown(evcon->fd, EVUTIL_SHUT_WR); 1.1246 + evutil_closesocket(evcon->fd); 1.1247 + evcon->fd = -1; 1.1248 + } 1.1249 + 1.1250 + /* we need to clean up any buffered data */ 1.1251 + tmp = bufferevent_get_output(evcon->bufev); 1.1252 + evbuffer_drain(tmp, evbuffer_get_length(tmp)); 1.1253 + tmp = bufferevent_get_input(evcon->bufev); 1.1254 + evbuffer_drain(tmp, evbuffer_get_length(tmp)); 1.1255 + 1.1256 + evcon->state = EVCON_DISCONNECTED; 1.1257 +} 1.1258 + 1.1259 +static void 1.1260 +evhttp_connection_start_detectclose(struct evhttp_connection *evcon) 1.1261 +{ 1.1262 + evcon->flags |= EVHTTP_CON_CLOSEDETECT; 1.1263 + 1.1264 + bufferevent_enable(evcon->bufev, EV_READ); 1.1265 +} 1.1266 + 1.1267 +static void 1.1268 +evhttp_connection_stop_detectclose(struct evhttp_connection *evcon) 1.1269 +{ 1.1270 + evcon->flags &= ~EVHTTP_CON_CLOSEDETECT; 1.1271 + 1.1272 + bufferevent_disable(evcon->bufev, EV_READ); 1.1273 +} 1.1274 + 1.1275 +static void 1.1276 +evhttp_connection_retry(evutil_socket_t fd, short what, void *arg) 1.1277 +{ 1.1278 + struct evhttp_connection *evcon = arg; 1.1279 + 1.1280 + evcon->state = EVCON_DISCONNECTED; 1.1281 + evhttp_connection_connect(evcon); 1.1282 +} 1.1283 + 1.1284 +static void 1.1285 +evhttp_connection_cb_cleanup(struct evhttp_connection *evcon) 1.1286 +{ 1.1287 + struct evcon_requestq requests; 1.1288 + 1.1289 + if (evcon->retry_max < 0 || evcon->retry_cnt < evcon->retry_max) { 1.1290 + evtimer_assign(&evcon->retry_ev, evcon->base, evhttp_connection_retry, evcon); 1.1291 + /* XXXX handle failure from evhttp_add_event */ 1.1292 + evhttp_add_event(&evcon->retry_ev, 1.1293 + MIN(3600, 2 << evcon->retry_cnt), 1.1294 + HTTP_CONNECT_TIMEOUT); 1.1295 + evcon->retry_cnt++; 1.1296 + return; 1.1297 + } 1.1298 + evhttp_connection_reset(evcon); 1.1299 + 1.1300 + /* 1.1301 + * User callback can do evhttp_make_request() on the same 1.1302 + * evcon so new request will be added to evcon->requests. To 1.1303 + * avoid freeing it prematurely we iterate over the copy of 1.1304 + * the queue. 1.1305 + */ 1.1306 + TAILQ_INIT(&requests); 1.1307 + while (TAILQ_FIRST(&evcon->requests) != NULL) { 1.1308 + struct evhttp_request *request = TAILQ_FIRST(&evcon->requests); 1.1309 + TAILQ_REMOVE(&evcon->requests, request, next); 1.1310 + TAILQ_INSERT_TAIL(&requests, request, next); 1.1311 + } 1.1312 + 1.1313 + /* for now, we just signal all requests by executing their callbacks */ 1.1314 + while (TAILQ_FIRST(&requests) != NULL) { 1.1315 + struct evhttp_request *request = TAILQ_FIRST(&requests); 1.1316 + TAILQ_REMOVE(&requests, request, next); 1.1317 + request->evcon = NULL; 1.1318 + 1.1319 + /* we might want to set an error here */ 1.1320 + request->cb(request, request->cb_arg); 1.1321 + evhttp_request_free(request); 1.1322 + } 1.1323 +} 1.1324 + 1.1325 +static void 1.1326 +evhttp_error_cb(struct bufferevent *bufev, short what, void *arg) 1.1327 +{ 1.1328 + struct evhttp_connection *evcon = arg; 1.1329 + struct evhttp_request *req = TAILQ_FIRST(&evcon->requests); 1.1330 + 1.1331 + switch (evcon->state) { 1.1332 + case EVCON_CONNECTING: 1.1333 + if (what & BEV_EVENT_TIMEOUT) { 1.1334 + event_debug(("%s: connection timeout for \"%s:%d\" on " 1.1335 + EV_SOCK_FMT, 1.1336 + __func__, evcon->address, evcon->port, 1.1337 + EV_SOCK_ARG(evcon->fd))); 1.1338 + evhttp_connection_cb_cleanup(evcon); 1.1339 + return; 1.1340 + } 1.1341 + break; 1.1342 + 1.1343 + case EVCON_READING_BODY: 1.1344 + if (!req->chunked && req->ntoread < 0 1.1345 + && what == (BEV_EVENT_READING|BEV_EVENT_EOF)) { 1.1346 + /* EOF on read can be benign */ 1.1347 + evhttp_connection_done(evcon); 1.1348 + return; 1.1349 + } 1.1350 + break; 1.1351 + 1.1352 + case EVCON_DISCONNECTED: 1.1353 + case EVCON_IDLE: 1.1354 + case EVCON_READING_FIRSTLINE: 1.1355 + case EVCON_READING_HEADERS: 1.1356 + case EVCON_READING_TRAILER: 1.1357 + case EVCON_WRITING: 1.1358 + default: 1.1359 + break; 1.1360 + } 1.1361 + 1.1362 + /* when we are in close detect mode, a read error means that 1.1363 + * the other side closed their connection. 1.1364 + */ 1.1365 + if (evcon->flags & EVHTTP_CON_CLOSEDETECT) { 1.1366 + evcon->flags &= ~EVHTTP_CON_CLOSEDETECT; 1.1367 + EVUTIL_ASSERT(evcon->http_server == NULL); 1.1368 + /* For connections from the client, we just 1.1369 + * reset the connection so that it becomes 1.1370 + * disconnected. 1.1371 + */ 1.1372 + EVUTIL_ASSERT(evcon->state == EVCON_IDLE); 1.1373 + evhttp_connection_reset(evcon); 1.1374 + return; 1.1375 + } 1.1376 + 1.1377 + if (what & BEV_EVENT_TIMEOUT) { 1.1378 + evhttp_connection_fail(evcon, EVCON_HTTP_TIMEOUT); 1.1379 + } else if (what & (BEV_EVENT_EOF|BEV_EVENT_ERROR)) { 1.1380 + evhttp_connection_fail(evcon, EVCON_HTTP_EOF); 1.1381 + } else { 1.1382 + evhttp_connection_fail(evcon, EVCON_HTTP_BUFFER_ERROR); 1.1383 + } 1.1384 +} 1.1385 + 1.1386 +/* 1.1387 + * Event callback for asynchronous connection attempt. 1.1388 + */ 1.1389 +static void 1.1390 +evhttp_connection_cb(struct bufferevent *bufev, short what, void *arg) 1.1391 +{ 1.1392 + struct evhttp_connection *evcon = arg; 1.1393 + int error; 1.1394 + ev_socklen_t errsz = sizeof(error); 1.1395 + 1.1396 + if (!(what & BEV_EVENT_CONNECTED)) { 1.1397 + /* some operating systems return ECONNREFUSED immediately 1.1398 + * when connecting to a local address. the cleanup is going 1.1399 + * to reschedule this function call. 1.1400 + */ 1.1401 +#ifndef WIN32 1.1402 + if (errno == ECONNREFUSED) 1.1403 + goto cleanup; 1.1404 +#endif 1.1405 + evhttp_error_cb(bufev, what, arg); 1.1406 + return; 1.1407 + } 1.1408 + 1.1409 + /* Check if the connection completed */ 1.1410 + if (getsockopt(evcon->fd, SOL_SOCKET, SO_ERROR, (void*)&error, 1.1411 + &errsz) == -1) { 1.1412 + event_debug(("%s: getsockopt for \"%s:%d\" on "EV_SOCK_FMT, 1.1413 + __func__, evcon->address, evcon->port, 1.1414 + EV_SOCK_ARG(evcon->fd))); 1.1415 + goto cleanup; 1.1416 + } 1.1417 + 1.1418 + if (error) { 1.1419 + event_debug(("%s: connect failed for \"%s:%d\" on " 1.1420 + EV_SOCK_FMT": %s", 1.1421 + __func__, evcon->address, evcon->port, 1.1422 + EV_SOCK_ARG(evcon->fd), 1.1423 + evutil_socket_error_to_string(error))); 1.1424 + goto cleanup; 1.1425 + } 1.1426 + 1.1427 + /* We are connected to the server now */ 1.1428 + event_debug(("%s: connected to \"%s:%d\" on "EV_SOCK_FMT"\n", 1.1429 + __func__, evcon->address, evcon->port, 1.1430 + EV_SOCK_ARG(evcon->fd))); 1.1431 + 1.1432 + /* Reset the retry count as we were successful in connecting */ 1.1433 + evcon->retry_cnt = 0; 1.1434 + evcon->state = EVCON_IDLE; 1.1435 + 1.1436 + /* reset the bufferevent cbs */ 1.1437 + bufferevent_setcb(evcon->bufev, 1.1438 + evhttp_read_cb, 1.1439 + evhttp_write_cb, 1.1440 + evhttp_error_cb, 1.1441 + evcon); 1.1442 + 1.1443 + if (evcon->timeout == -1) 1.1444 + bufferevent_settimeout(evcon->bufev, 1.1445 + HTTP_READ_TIMEOUT, HTTP_WRITE_TIMEOUT); 1.1446 + else { 1.1447 + struct timeval tv; 1.1448 + tv.tv_sec = evcon->timeout; 1.1449 + tv.tv_usec = 0; 1.1450 + bufferevent_set_timeouts(evcon->bufev, &tv, &tv); 1.1451 + } 1.1452 + 1.1453 + /* try to start requests that have queued up on this connection */ 1.1454 + evhttp_request_dispatch(evcon); 1.1455 + return; 1.1456 + 1.1457 + cleanup: 1.1458 + evhttp_connection_cb_cleanup(evcon); 1.1459 +} 1.1460 + 1.1461 +/* 1.1462 + * Check if we got a valid response code. 1.1463 + */ 1.1464 + 1.1465 +static int 1.1466 +evhttp_valid_response_code(int code) 1.1467 +{ 1.1468 + if (code == 0) 1.1469 + return (0); 1.1470 + 1.1471 + return (1); 1.1472 +} 1.1473 + 1.1474 +static int 1.1475 +evhttp_parse_http_version(const char *version, struct evhttp_request *req) 1.1476 +{ 1.1477 + int major, minor; 1.1478 + char ch; 1.1479 + int n = sscanf(version, "HTTP/%d.%d%c", &major, &minor, &ch); 1.1480 + if (n != 2 || major > 1) { 1.1481 + event_debug(("%s: bad version %s on message %p from %s", 1.1482 + __func__, version, req, req->remote_host)); 1.1483 + return (-1); 1.1484 + } 1.1485 + req->major = major; 1.1486 + req->minor = minor; 1.1487 + return (0); 1.1488 +} 1.1489 + 1.1490 +/* Parses the status line of a web server */ 1.1491 + 1.1492 +static int 1.1493 +evhttp_parse_response_line(struct evhttp_request *req, char *line) 1.1494 +{ 1.1495 + char *protocol; 1.1496 + char *number; 1.1497 + const char *readable = ""; 1.1498 + 1.1499 + protocol = strsep(&line, " "); 1.1500 + if (line == NULL) 1.1501 + return (-1); 1.1502 + number = strsep(&line, " "); 1.1503 + if (line != NULL) 1.1504 + readable = line; 1.1505 + 1.1506 + if (evhttp_parse_http_version(protocol, req) < 0) 1.1507 + return (-1); 1.1508 + 1.1509 + req->response_code = atoi(number); 1.1510 + if (!evhttp_valid_response_code(req->response_code)) { 1.1511 + event_debug(("%s: bad response code \"%s\"", 1.1512 + __func__, number)); 1.1513 + return (-1); 1.1514 + } 1.1515 + 1.1516 + if ((req->response_code_line = mm_strdup(readable)) == NULL) { 1.1517 + event_warn("%s: strdup", __func__); 1.1518 + return (-1); 1.1519 + } 1.1520 + 1.1521 + return (0); 1.1522 +} 1.1523 + 1.1524 +/* Parse the first line of a HTTP request */ 1.1525 + 1.1526 +static int 1.1527 +evhttp_parse_request_line(struct evhttp_request *req, char *line) 1.1528 +{ 1.1529 + char *method; 1.1530 + char *uri; 1.1531 + char *version; 1.1532 + const char *hostname; 1.1533 + const char *scheme; 1.1534 + 1.1535 + /* Parse the request line */ 1.1536 + method = strsep(&line, " "); 1.1537 + if (line == NULL) 1.1538 + return (-1); 1.1539 + uri = strsep(&line, " "); 1.1540 + if (line == NULL) 1.1541 + return (-1); 1.1542 + version = strsep(&line, " "); 1.1543 + if (line != NULL) 1.1544 + return (-1); 1.1545 + 1.1546 + /* First line */ 1.1547 + if (strcmp(method, "GET") == 0) { 1.1548 + req->type = EVHTTP_REQ_GET; 1.1549 + } else if (strcmp(method, "POST") == 0) { 1.1550 + req->type = EVHTTP_REQ_POST; 1.1551 + } else if (strcmp(method, "HEAD") == 0) { 1.1552 + req->type = EVHTTP_REQ_HEAD; 1.1553 + } else if (strcmp(method, "PUT") == 0) { 1.1554 + req->type = EVHTTP_REQ_PUT; 1.1555 + } else if (strcmp(method, "DELETE") == 0) { 1.1556 + req->type = EVHTTP_REQ_DELETE; 1.1557 + } else if (strcmp(method, "OPTIONS") == 0) { 1.1558 + req->type = EVHTTP_REQ_OPTIONS; 1.1559 + } else if (strcmp(method, "TRACE") == 0) { 1.1560 + req->type = EVHTTP_REQ_TRACE; 1.1561 + } else if (strcmp(method, "PATCH") == 0) { 1.1562 + req->type = EVHTTP_REQ_PATCH; 1.1563 + } else { 1.1564 + req->type = _EVHTTP_REQ_UNKNOWN; 1.1565 + event_debug(("%s: bad method %s on request %p from %s", 1.1566 + __func__, method, req, req->remote_host)); 1.1567 + /* No error yet; we'll give a better error later when 1.1568 + * we see that req->type is unsupported. */ 1.1569 + } 1.1570 + 1.1571 + if (evhttp_parse_http_version(version, req) < 0) 1.1572 + return (-1); 1.1573 + 1.1574 + if ((req->uri = mm_strdup(uri)) == NULL) { 1.1575 + event_debug(("%s: mm_strdup", __func__)); 1.1576 + return (-1); 1.1577 + } 1.1578 + 1.1579 + if ((req->uri_elems = evhttp_uri_parse_with_flags(req->uri, 1.1580 + EVHTTP_URI_NONCONFORMANT)) == NULL) { 1.1581 + return -1; 1.1582 + } 1.1583 + 1.1584 + /* If we have an absolute-URI, check to see if it is an http request 1.1585 + for a known vhost or server alias. If we don't know about this 1.1586 + host, we consider it a proxy request. */ 1.1587 + scheme = evhttp_uri_get_scheme(req->uri_elems); 1.1588 + hostname = evhttp_uri_get_host(req->uri_elems); 1.1589 + if (scheme && (!evutil_ascii_strcasecmp(scheme, "http") || 1.1590 + !evutil_ascii_strcasecmp(scheme, "https")) && 1.1591 + hostname && 1.1592 + !evhttp_find_vhost(req->evcon->http_server, NULL, hostname)) 1.1593 + req->flags |= EVHTTP_PROXY_REQUEST; 1.1594 + 1.1595 + return (0); 1.1596 +} 1.1597 + 1.1598 +const char * 1.1599 +evhttp_find_header(const struct evkeyvalq *headers, const char *key) 1.1600 +{ 1.1601 + struct evkeyval *header; 1.1602 + 1.1603 + TAILQ_FOREACH(header, headers, next) { 1.1604 + if (evutil_ascii_strcasecmp(header->key, key) == 0) 1.1605 + return (header->value); 1.1606 + } 1.1607 + 1.1608 + return (NULL); 1.1609 +} 1.1610 + 1.1611 +void 1.1612 +evhttp_clear_headers(struct evkeyvalq *headers) 1.1613 +{ 1.1614 + struct evkeyval *header; 1.1615 + 1.1616 + for (header = TAILQ_FIRST(headers); 1.1617 + header != NULL; 1.1618 + header = TAILQ_FIRST(headers)) { 1.1619 + TAILQ_REMOVE(headers, header, next); 1.1620 + mm_free(header->key); 1.1621 + mm_free(header->value); 1.1622 + mm_free(header); 1.1623 + } 1.1624 +} 1.1625 + 1.1626 +/* 1.1627 + * Returns 0, if the header was successfully removed. 1.1628 + * Returns -1, if the header could not be found. 1.1629 + */ 1.1630 + 1.1631 +int 1.1632 +evhttp_remove_header(struct evkeyvalq *headers, const char *key) 1.1633 +{ 1.1634 + struct evkeyval *header; 1.1635 + 1.1636 + TAILQ_FOREACH(header, headers, next) { 1.1637 + if (evutil_ascii_strcasecmp(header->key, key) == 0) 1.1638 + break; 1.1639 + } 1.1640 + 1.1641 + if (header == NULL) 1.1642 + return (-1); 1.1643 + 1.1644 + /* Free and remove the header that we found */ 1.1645 + TAILQ_REMOVE(headers, header, next); 1.1646 + mm_free(header->key); 1.1647 + mm_free(header->value); 1.1648 + mm_free(header); 1.1649 + 1.1650 + return (0); 1.1651 +} 1.1652 + 1.1653 +static int 1.1654 +evhttp_header_is_valid_value(const char *value) 1.1655 +{ 1.1656 + const char *p = value; 1.1657 + 1.1658 + while ((p = strpbrk(p, "\r\n")) != NULL) { 1.1659 + /* we really expect only one new line */ 1.1660 + p += strspn(p, "\r\n"); 1.1661 + /* we expect a space or tab for continuation */ 1.1662 + if (*p != ' ' && *p != '\t') 1.1663 + return (0); 1.1664 + } 1.1665 + return (1); 1.1666 +} 1.1667 + 1.1668 +int 1.1669 +evhttp_add_header(struct evkeyvalq *headers, 1.1670 + const char *key, const char *value) 1.1671 +{ 1.1672 + event_debug(("%s: key: %s val: %s\n", __func__, key, value)); 1.1673 + 1.1674 + if (strchr(key, '\r') != NULL || strchr(key, '\n') != NULL) { 1.1675 + /* drop illegal headers */ 1.1676 + event_debug(("%s: dropping illegal header key\n", __func__)); 1.1677 + return (-1); 1.1678 + } 1.1679 + 1.1680 + if (!evhttp_header_is_valid_value(value)) { 1.1681 + event_debug(("%s: dropping illegal header value\n", __func__)); 1.1682 + return (-1); 1.1683 + } 1.1684 + 1.1685 + return (evhttp_add_header_internal(headers, key, value)); 1.1686 +} 1.1687 + 1.1688 +static int 1.1689 +evhttp_add_header_internal(struct evkeyvalq *headers, 1.1690 + const char *key, const char *value) 1.1691 +{ 1.1692 + struct evkeyval *header = mm_calloc(1, sizeof(struct evkeyval)); 1.1693 + if (header == NULL) { 1.1694 + event_warn("%s: calloc", __func__); 1.1695 + return (-1); 1.1696 + } 1.1697 + if ((header->key = mm_strdup(key)) == NULL) { 1.1698 + mm_free(header); 1.1699 + event_warn("%s: strdup", __func__); 1.1700 + return (-1); 1.1701 + } 1.1702 + if ((header->value = mm_strdup(value)) == NULL) { 1.1703 + mm_free(header->key); 1.1704 + mm_free(header); 1.1705 + event_warn("%s: strdup", __func__); 1.1706 + return (-1); 1.1707 + } 1.1708 + 1.1709 + TAILQ_INSERT_TAIL(headers, header, next); 1.1710 + 1.1711 + return (0); 1.1712 +} 1.1713 + 1.1714 +/* 1.1715 + * Parses header lines from a request or a response into the specified 1.1716 + * request object given an event buffer. 1.1717 + * 1.1718 + * Returns 1.1719 + * DATA_CORRUPTED on error 1.1720 + * MORE_DATA_EXPECTED when we need to read more headers 1.1721 + * ALL_DATA_READ when all headers have been read. 1.1722 + */ 1.1723 + 1.1724 +enum message_read_status 1.1725 +evhttp_parse_firstline(struct evhttp_request *req, struct evbuffer *buffer) 1.1726 +{ 1.1727 + char *line; 1.1728 + enum message_read_status status = ALL_DATA_READ; 1.1729 + 1.1730 + size_t line_length; 1.1731 + /* XXX try */ 1.1732 + line = evbuffer_readln(buffer, &line_length, EVBUFFER_EOL_CRLF); 1.1733 + if (line == NULL) { 1.1734 + if (req->evcon != NULL && 1.1735 + evbuffer_get_length(buffer) > req->evcon->max_headers_size) 1.1736 + return (DATA_TOO_LONG); 1.1737 + else 1.1738 + return (MORE_DATA_EXPECTED); 1.1739 + } 1.1740 + 1.1741 + if (req->evcon != NULL && 1.1742 + line_length > req->evcon->max_headers_size) { 1.1743 + mm_free(line); 1.1744 + return (DATA_TOO_LONG); 1.1745 + } 1.1746 + 1.1747 + req->headers_size = line_length; 1.1748 + 1.1749 + switch (req->kind) { 1.1750 + case EVHTTP_REQUEST: 1.1751 + if (evhttp_parse_request_line(req, line) == -1) 1.1752 + status = DATA_CORRUPTED; 1.1753 + break; 1.1754 + case EVHTTP_RESPONSE: 1.1755 + if (evhttp_parse_response_line(req, line) == -1) 1.1756 + status = DATA_CORRUPTED; 1.1757 + break; 1.1758 + default: 1.1759 + status = DATA_CORRUPTED; 1.1760 + } 1.1761 + 1.1762 + mm_free(line); 1.1763 + return (status); 1.1764 +} 1.1765 + 1.1766 +static int 1.1767 +evhttp_append_to_last_header(struct evkeyvalq *headers, const char *line) 1.1768 +{ 1.1769 + struct evkeyval *header = TAILQ_LAST(headers, evkeyvalq); 1.1770 + char *newval; 1.1771 + size_t old_len, line_len; 1.1772 + 1.1773 + if (header == NULL) 1.1774 + return (-1); 1.1775 + 1.1776 + old_len = strlen(header->value); 1.1777 + line_len = strlen(line); 1.1778 + 1.1779 + newval = mm_realloc(header->value, old_len + line_len + 1); 1.1780 + if (newval == NULL) 1.1781 + return (-1); 1.1782 + 1.1783 + memcpy(newval + old_len, line, line_len + 1); 1.1784 + header->value = newval; 1.1785 + 1.1786 + return (0); 1.1787 +} 1.1788 + 1.1789 +enum message_read_status 1.1790 +evhttp_parse_headers(struct evhttp_request *req, struct evbuffer* buffer) 1.1791 +{ 1.1792 + enum message_read_status errcode = DATA_CORRUPTED; 1.1793 + char *line; 1.1794 + enum message_read_status status = MORE_DATA_EXPECTED; 1.1795 + 1.1796 + struct evkeyvalq* headers = req->input_headers; 1.1797 + size_t line_length; 1.1798 + while ((line = evbuffer_readln(buffer, &line_length, EVBUFFER_EOL_CRLF)) 1.1799 + != NULL) { 1.1800 + char *skey, *svalue; 1.1801 + 1.1802 + req->headers_size += line_length; 1.1803 + 1.1804 + if (req->evcon != NULL && 1.1805 + req->headers_size > req->evcon->max_headers_size) { 1.1806 + errcode = DATA_TOO_LONG; 1.1807 + goto error; 1.1808 + } 1.1809 + 1.1810 + if (*line == '\0') { /* Last header - Done */ 1.1811 + status = ALL_DATA_READ; 1.1812 + mm_free(line); 1.1813 + break; 1.1814 + } 1.1815 + 1.1816 + /* Check if this is a continuation line */ 1.1817 + if (*line == ' ' || *line == '\t') { 1.1818 + if (evhttp_append_to_last_header(headers, line) == -1) 1.1819 + goto error; 1.1820 + mm_free(line); 1.1821 + continue; 1.1822 + } 1.1823 + 1.1824 + /* Processing of header lines */ 1.1825 + svalue = line; 1.1826 + skey = strsep(&svalue, ":"); 1.1827 + if (svalue == NULL) 1.1828 + goto error; 1.1829 + 1.1830 + svalue += strspn(svalue, " "); 1.1831 + 1.1832 + if (evhttp_add_header(headers, skey, svalue) == -1) 1.1833 + goto error; 1.1834 + 1.1835 + mm_free(line); 1.1836 + } 1.1837 + 1.1838 + if (status == MORE_DATA_EXPECTED) { 1.1839 + if (req->evcon != NULL && 1.1840 + req->headers_size + evbuffer_get_length(buffer) > req->evcon->max_headers_size) 1.1841 + return (DATA_TOO_LONG); 1.1842 + } 1.1843 + 1.1844 + return (status); 1.1845 + 1.1846 + error: 1.1847 + mm_free(line); 1.1848 + return (errcode); 1.1849 +} 1.1850 + 1.1851 +static int 1.1852 +evhttp_get_body_length(struct evhttp_request *req) 1.1853 +{ 1.1854 + struct evkeyvalq *headers = req->input_headers; 1.1855 + const char *content_length; 1.1856 + const char *connection; 1.1857 + 1.1858 + content_length = evhttp_find_header(headers, "Content-Length"); 1.1859 + connection = evhttp_find_header(headers, "Connection"); 1.1860 + 1.1861 + if (content_length == NULL && connection == NULL) 1.1862 + req->ntoread = -1; 1.1863 + else if (content_length == NULL && 1.1864 + evutil_ascii_strcasecmp(connection, "Close") != 0) { 1.1865 + /* Bad combination, we don't know when it will end */ 1.1866 + event_warnx("%s: we got no content length, but the " 1.1867 + "server wants to keep the connection open: %s.", 1.1868 + __func__, connection); 1.1869 + return (-1); 1.1870 + } else if (content_length == NULL) { 1.1871 + req->ntoread = -1; 1.1872 + } else { 1.1873 + char *endp; 1.1874 + ev_int64_t ntoread = evutil_strtoll(content_length, &endp, 10); 1.1875 + if (*content_length == '\0' || *endp != '\0' || ntoread < 0) { 1.1876 + event_debug(("%s: illegal content length: %s", 1.1877 + __func__, content_length)); 1.1878 + return (-1); 1.1879 + } 1.1880 + req->ntoread = ntoread; 1.1881 + } 1.1882 + 1.1883 + event_debug(("%s: bytes to read: "EV_I64_FMT" (in buffer "EV_SIZE_FMT")\n", 1.1884 + __func__, EV_I64_ARG(req->ntoread), 1.1885 + EV_SIZE_ARG(evbuffer_get_length(bufferevent_get_input(req->evcon->bufev))))); 1.1886 + 1.1887 + return (0); 1.1888 +} 1.1889 + 1.1890 +static int 1.1891 +evhttp_method_may_have_body(enum evhttp_cmd_type type) 1.1892 +{ 1.1893 + switch (type) { 1.1894 + case EVHTTP_REQ_POST: 1.1895 + case EVHTTP_REQ_PUT: 1.1896 + case EVHTTP_REQ_PATCH: 1.1897 + return 1; 1.1898 + case EVHTTP_REQ_TRACE: 1.1899 + return 0; 1.1900 + /* XXX May any of the below methods have a body? */ 1.1901 + case EVHTTP_REQ_GET: 1.1902 + case EVHTTP_REQ_HEAD: 1.1903 + case EVHTTP_REQ_DELETE: 1.1904 + case EVHTTP_REQ_OPTIONS: 1.1905 + case EVHTTP_REQ_CONNECT: 1.1906 + return 0; 1.1907 + default: 1.1908 + return 0; 1.1909 + } 1.1910 +} 1.1911 + 1.1912 +static void 1.1913 +evhttp_get_body(struct evhttp_connection *evcon, struct evhttp_request *req) 1.1914 +{ 1.1915 + const char *xfer_enc; 1.1916 + 1.1917 + /* If this is a request without a body, then we are done */ 1.1918 + if (req->kind == EVHTTP_REQUEST && 1.1919 + !evhttp_method_may_have_body(req->type)) { 1.1920 + evhttp_connection_done(evcon); 1.1921 + return; 1.1922 + } 1.1923 + evcon->state = EVCON_READING_BODY; 1.1924 + xfer_enc = evhttp_find_header(req->input_headers, "Transfer-Encoding"); 1.1925 + if (xfer_enc != NULL && evutil_ascii_strcasecmp(xfer_enc, "chunked") == 0) { 1.1926 + req->chunked = 1; 1.1927 + req->ntoread = -1; 1.1928 + } else { 1.1929 + if (evhttp_get_body_length(req) == -1) { 1.1930 + evhttp_connection_fail(evcon, 1.1931 + EVCON_HTTP_INVALID_HEADER); 1.1932 + return; 1.1933 + } 1.1934 + if (req->kind == EVHTTP_REQUEST && req->ntoread < 1) { 1.1935 + /* An incoming request with no content-length and no 1.1936 + * transfer-encoding has no body. */ 1.1937 + evhttp_connection_done(evcon); 1.1938 + return; 1.1939 + } 1.1940 + } 1.1941 + 1.1942 + /* Should we send a 100 Continue status line? */ 1.1943 + if (req->kind == EVHTTP_REQUEST && REQ_VERSION_ATLEAST(req, 1, 1)) { 1.1944 + const char *expect; 1.1945 + 1.1946 + expect = evhttp_find_header(req->input_headers, "Expect"); 1.1947 + if (expect) { 1.1948 + if (!evutil_ascii_strcasecmp(expect, "100-continue")) { 1.1949 + /* XXX It would be nice to do some sanity 1.1950 + checking here. Does the resource exist? 1.1951 + Should the resource accept post requests? If 1.1952 + no, we should respond with an error. For 1.1953 + now, just optimistically tell the client to 1.1954 + send their message body. */ 1.1955 + if (req->ntoread > 0) { 1.1956 + /* ntoread is ev_int64_t, max_body_size is ev_uint64_t */ 1.1957 + if ((req->evcon->max_body_size <= EV_INT64_MAX) && (ev_uint64_t)req->ntoread > req->evcon->max_body_size) { 1.1958 + evhttp_send_error(req, HTTP_ENTITYTOOLARGE, NULL); 1.1959 + return; 1.1960 + } 1.1961 + } 1.1962 + if (!evbuffer_get_length(bufferevent_get_input(evcon->bufev))) 1.1963 + evhttp_send_continue(evcon, req); 1.1964 + } else { 1.1965 + evhttp_send_error(req, HTTP_EXPECTATIONFAILED, 1.1966 + NULL); 1.1967 + return; 1.1968 + } 1.1969 + } 1.1970 + } 1.1971 + 1.1972 + evhttp_read_body(evcon, req); 1.1973 + /* note the request may have been freed in evhttp_read_body */ 1.1974 +} 1.1975 + 1.1976 +static void 1.1977 +evhttp_read_firstline(struct evhttp_connection *evcon, 1.1978 + struct evhttp_request *req) 1.1979 +{ 1.1980 + enum message_read_status res; 1.1981 + 1.1982 + res = evhttp_parse_firstline(req, bufferevent_get_input(evcon->bufev)); 1.1983 + if (res == DATA_CORRUPTED || res == DATA_TOO_LONG) { 1.1984 + /* Error while reading, terminate */ 1.1985 + event_debug(("%s: bad header lines on "EV_SOCK_FMT"\n", 1.1986 + __func__, EV_SOCK_ARG(evcon->fd))); 1.1987 + evhttp_connection_fail(evcon, EVCON_HTTP_INVALID_HEADER); 1.1988 + return; 1.1989 + } else if (res == MORE_DATA_EXPECTED) { 1.1990 + /* Need more header lines */ 1.1991 + return; 1.1992 + } 1.1993 + 1.1994 + evcon->state = EVCON_READING_HEADERS; 1.1995 + evhttp_read_header(evcon, req); 1.1996 +} 1.1997 + 1.1998 +static void 1.1999 +evhttp_read_header(struct evhttp_connection *evcon, 1.2000 + struct evhttp_request *req) 1.2001 +{ 1.2002 + enum message_read_status res; 1.2003 + evutil_socket_t fd = evcon->fd; 1.2004 + 1.2005 + res = evhttp_parse_headers(req, bufferevent_get_input(evcon->bufev)); 1.2006 + if (res == DATA_CORRUPTED || res == DATA_TOO_LONG) { 1.2007 + /* Error while reading, terminate */ 1.2008 + event_debug(("%s: bad header lines on "EV_SOCK_FMT"\n", 1.2009 + __func__, EV_SOCK_ARG(fd))); 1.2010 + evhttp_connection_fail(evcon, EVCON_HTTP_INVALID_HEADER); 1.2011 + return; 1.2012 + } else if (res == MORE_DATA_EXPECTED) { 1.2013 + /* Need more header lines */ 1.2014 + return; 1.2015 + } 1.2016 + 1.2017 + /* Disable reading for now */ 1.2018 + bufferevent_disable(evcon->bufev, EV_READ); 1.2019 + 1.2020 + /* Done reading headers, do the real work */ 1.2021 + switch (req->kind) { 1.2022 + case EVHTTP_REQUEST: 1.2023 + event_debug(("%s: checking for post data on "EV_SOCK_FMT"\n", 1.2024 + __func__, EV_SOCK_ARG(fd))); 1.2025 + evhttp_get_body(evcon, req); 1.2026 + /* note the request may have been freed in evhttp_get_body */ 1.2027 + break; 1.2028 + 1.2029 + case EVHTTP_RESPONSE: 1.2030 + /* Start over if we got a 100 Continue response. */ 1.2031 + if (req->response_code == 100) { 1.2032 + evhttp_start_read(evcon); 1.2033 + return; 1.2034 + } 1.2035 + if (!evhttp_response_needs_body(req)) { 1.2036 + event_debug(("%s: skipping body for code %d\n", 1.2037 + __func__, req->response_code)); 1.2038 + evhttp_connection_done(evcon); 1.2039 + } else { 1.2040 + event_debug(("%s: start of read body for %s on " 1.2041 + EV_SOCK_FMT"\n", 1.2042 + __func__, req->remote_host, EV_SOCK_ARG(fd))); 1.2043 + evhttp_get_body(evcon, req); 1.2044 + /* note the request may have been freed in 1.2045 + * evhttp_get_body */ 1.2046 + } 1.2047 + break; 1.2048 + 1.2049 + default: 1.2050 + event_warnx("%s: bad header on "EV_SOCK_FMT, __func__, 1.2051 + EV_SOCK_ARG(fd)); 1.2052 + evhttp_connection_fail(evcon, EVCON_HTTP_INVALID_HEADER); 1.2053 + break; 1.2054 + } 1.2055 + /* request may have been freed above */ 1.2056 +} 1.2057 + 1.2058 +/* 1.2059 + * Creates a TCP connection to the specified port and executes a callback 1.2060 + * when finished. Failure or success is indicate by the passed connection 1.2061 + * object. 1.2062 + * 1.2063 + * Although this interface accepts a hostname, it is intended to take 1.2064 + * only numeric hostnames so that non-blocking DNS resolution can 1.2065 + * happen elsewhere. 1.2066 + */ 1.2067 + 1.2068 +struct evhttp_connection * 1.2069 +evhttp_connection_new(const char *address, unsigned short port) 1.2070 +{ 1.2071 + return (evhttp_connection_base_new(NULL, NULL, address, port)); 1.2072 +} 1.2073 + 1.2074 +struct evhttp_connection * 1.2075 +evhttp_connection_base_new(struct event_base *base, struct evdns_base *dnsbase, 1.2076 + const char *address, unsigned short port) 1.2077 +{ 1.2078 + struct evhttp_connection *evcon = NULL; 1.2079 + 1.2080 + event_debug(("Attempting connection to %s:%d\n", address, port)); 1.2081 + 1.2082 + if ((evcon = mm_calloc(1, sizeof(struct evhttp_connection))) == NULL) { 1.2083 + event_warn("%s: calloc failed", __func__); 1.2084 + goto error; 1.2085 + } 1.2086 + 1.2087 + evcon->fd = -1; 1.2088 + evcon->port = port; 1.2089 + 1.2090 + evcon->max_headers_size = EV_SIZE_MAX; 1.2091 + evcon->max_body_size = EV_SIZE_MAX; 1.2092 + 1.2093 + evcon->timeout = -1; 1.2094 + evcon->retry_cnt = evcon->retry_max = 0; 1.2095 + 1.2096 + if ((evcon->address = mm_strdup(address)) == NULL) { 1.2097 + event_warn("%s: strdup failed", __func__); 1.2098 + goto error; 1.2099 + } 1.2100 + 1.2101 + if ((evcon->bufev = bufferevent_new(-1, 1.2102 + evhttp_read_cb, 1.2103 + evhttp_write_cb, 1.2104 + evhttp_error_cb, evcon)) == NULL) { 1.2105 + event_warn("%s: bufferevent_new failed", __func__); 1.2106 + goto error; 1.2107 + } 1.2108 + 1.2109 + evcon->state = EVCON_DISCONNECTED; 1.2110 + TAILQ_INIT(&evcon->requests); 1.2111 + 1.2112 + if (base != NULL) { 1.2113 + evcon->base = base; 1.2114 + bufferevent_base_set(base, evcon->bufev); 1.2115 + } 1.2116 + 1.2117 + 1.2118 + event_deferred_cb_init(&evcon->read_more_deferred_cb, 1.2119 + evhttp_deferred_read_cb, evcon); 1.2120 + 1.2121 + evcon->dns_base = dnsbase; 1.2122 + 1.2123 + return (evcon); 1.2124 + 1.2125 + error: 1.2126 + if (evcon != NULL) 1.2127 + evhttp_connection_free(evcon); 1.2128 + return (NULL); 1.2129 +} 1.2130 + 1.2131 +struct bufferevent * 1.2132 +evhttp_connection_get_bufferevent(struct evhttp_connection *evcon) 1.2133 +{ 1.2134 + return evcon->bufev; 1.2135 +} 1.2136 + 1.2137 +void 1.2138 +evhttp_connection_set_base(struct evhttp_connection *evcon, 1.2139 + struct event_base *base) 1.2140 +{ 1.2141 + EVUTIL_ASSERT(evcon->base == NULL); 1.2142 + EVUTIL_ASSERT(evcon->state == EVCON_DISCONNECTED); 1.2143 + evcon->base = base; 1.2144 + bufferevent_base_set(base, evcon->bufev); 1.2145 +} 1.2146 + 1.2147 +void 1.2148 +evhttp_connection_set_timeout(struct evhttp_connection *evcon, 1.2149 + int timeout_in_secs) 1.2150 +{ 1.2151 + evcon->timeout = timeout_in_secs; 1.2152 + 1.2153 + if (evcon->timeout == -1) 1.2154 + bufferevent_settimeout(evcon->bufev, 1.2155 + HTTP_READ_TIMEOUT, HTTP_WRITE_TIMEOUT); 1.2156 + else 1.2157 + bufferevent_settimeout(evcon->bufev, 1.2158 + evcon->timeout, evcon->timeout); 1.2159 +} 1.2160 + 1.2161 +void 1.2162 +evhttp_connection_set_retries(struct evhttp_connection *evcon, 1.2163 + int retry_max) 1.2164 +{ 1.2165 + evcon->retry_max = retry_max; 1.2166 +} 1.2167 + 1.2168 +void 1.2169 +evhttp_connection_set_closecb(struct evhttp_connection *evcon, 1.2170 + void (*cb)(struct evhttp_connection *, void *), void *cbarg) 1.2171 +{ 1.2172 + evcon->closecb = cb; 1.2173 + evcon->closecb_arg = cbarg; 1.2174 +} 1.2175 + 1.2176 +void 1.2177 +evhttp_connection_get_peer(struct evhttp_connection *evcon, 1.2178 + char **address, ev_uint16_t *port) 1.2179 +{ 1.2180 + *address = evcon->address; 1.2181 + *port = evcon->port; 1.2182 +} 1.2183 + 1.2184 +int 1.2185 +evhttp_connection_connect(struct evhttp_connection *evcon) 1.2186 +{ 1.2187 + if (evcon->state == EVCON_CONNECTING) 1.2188 + return (0); 1.2189 + 1.2190 + evhttp_connection_reset(evcon); 1.2191 + 1.2192 + EVUTIL_ASSERT(!(evcon->flags & EVHTTP_CON_INCOMING)); 1.2193 + evcon->flags |= EVHTTP_CON_OUTGOING; 1.2194 + 1.2195 + evcon->fd = bind_socket( 1.2196 + evcon->bind_address, evcon->bind_port, 0 /*reuse*/); 1.2197 + if (evcon->fd == -1) { 1.2198 + event_debug(("%s: failed to bind to \"%s\"", 1.2199 + __func__, evcon->bind_address)); 1.2200 + return (-1); 1.2201 + } 1.2202 + 1.2203 + /* Set up a callback for successful connection setup */ 1.2204 + bufferevent_setfd(evcon->bufev, evcon->fd); 1.2205 + bufferevent_setcb(evcon->bufev, 1.2206 + NULL /* evhttp_read_cb */, 1.2207 + NULL /* evhttp_write_cb */, 1.2208 + evhttp_connection_cb, 1.2209 + evcon); 1.2210 + bufferevent_settimeout(evcon->bufev, 0, 1.2211 + evcon->timeout != -1 ? evcon->timeout : HTTP_CONNECT_TIMEOUT); 1.2212 + /* make sure that we get a write callback */ 1.2213 + bufferevent_enable(evcon->bufev, EV_WRITE); 1.2214 + 1.2215 + if (bufferevent_socket_connect_hostname(evcon->bufev, evcon->dns_base, 1.2216 + AF_UNSPEC, evcon->address, evcon->port) < 0) { 1.2217 + event_sock_warn(evcon->fd, "%s: connection to \"%s\" failed", 1.2218 + __func__, evcon->address); 1.2219 + /* some operating systems return ECONNREFUSED immediately 1.2220 + * when connecting to a local address. the cleanup is going 1.2221 + * to reschedule this function call. 1.2222 + */ 1.2223 + evhttp_connection_cb_cleanup(evcon); 1.2224 + return (0); 1.2225 + } 1.2226 + 1.2227 + evcon->state = EVCON_CONNECTING; 1.2228 + 1.2229 + return (0); 1.2230 +} 1.2231 + 1.2232 +/* 1.2233 + * Starts an HTTP request on the provided evhttp_connection object. 1.2234 + * If the connection object is not connected to the web server already, 1.2235 + * this will start the connection. 1.2236 + */ 1.2237 + 1.2238 +int 1.2239 +evhttp_make_request(struct evhttp_connection *evcon, 1.2240 + struct evhttp_request *req, 1.2241 + enum evhttp_cmd_type type, const char *uri) 1.2242 +{ 1.2243 + /* We are making a request */ 1.2244 + req->kind = EVHTTP_REQUEST; 1.2245 + req->type = type; 1.2246 + if (req->uri != NULL) 1.2247 + mm_free(req->uri); 1.2248 + if ((req->uri = mm_strdup(uri)) == NULL) { 1.2249 + event_warn("%s: strdup", __func__); 1.2250 + evhttp_request_free(req); 1.2251 + return (-1); 1.2252 + } 1.2253 + 1.2254 + /* Set the protocol version if it is not supplied */ 1.2255 + if (!req->major && !req->minor) { 1.2256 + req->major = 1; 1.2257 + req->minor = 1; 1.2258 + } 1.2259 + 1.2260 + EVUTIL_ASSERT(req->evcon == NULL); 1.2261 + req->evcon = evcon; 1.2262 + EVUTIL_ASSERT(!(req->flags & EVHTTP_REQ_OWN_CONNECTION)); 1.2263 + 1.2264 + TAILQ_INSERT_TAIL(&evcon->requests, req, next); 1.2265 + 1.2266 + /* If the connection object is not connected; make it so */ 1.2267 + if (!evhttp_connected(evcon)) { 1.2268 + int res = evhttp_connection_connect(evcon); 1.2269 + /* evhttp_connection_fail(), which is called through 1.2270 + * evhttp_connection_connect(), assumes that req lies in 1.2271 + * evcon->requests. Thus, enqueue the request in advance and r 1.2272 + * it in the error case. */ 1.2273 + if (res != 0) 1.2274 + TAILQ_REMOVE(&evcon->requests, req, next); 1.2275 + 1.2276 + return res; 1.2277 + } 1.2278 + 1.2279 + /* 1.2280 + * If it's connected already and we are the first in the queue, 1.2281 + * then we can dispatch this request immediately. Otherwise, it 1.2282 + * will be dispatched once the pending requests are completed. 1.2283 + */ 1.2284 + if (TAILQ_FIRST(&evcon->requests) == req) 1.2285 + evhttp_request_dispatch(evcon); 1.2286 + 1.2287 + return (0); 1.2288 +} 1.2289 + 1.2290 +void 1.2291 +evhttp_cancel_request(struct evhttp_request *req) 1.2292 +{ 1.2293 + struct evhttp_connection *evcon = req->evcon; 1.2294 + if (evcon != NULL) { 1.2295 + /* We need to remove it from the connection */ 1.2296 + if (TAILQ_FIRST(&evcon->requests) == req) { 1.2297 + /* it's currently being worked on, so reset 1.2298 + * the connection. 1.2299 + */ 1.2300 + evhttp_connection_fail(evcon, 1.2301 + EVCON_HTTP_REQUEST_CANCEL); 1.2302 + 1.2303 + /* connection fail freed the request */ 1.2304 + return; 1.2305 + } else { 1.2306 + /* otherwise, we can just remove it from the 1.2307 + * queue 1.2308 + */ 1.2309 + TAILQ_REMOVE(&evcon->requests, req, next); 1.2310 + } 1.2311 + } 1.2312 + 1.2313 + evhttp_request_free(req); 1.2314 +} 1.2315 + 1.2316 +/* 1.2317 + * Reads data from file descriptor into request structure 1.2318 + * Request structure needs to be set up correctly. 1.2319 + */ 1.2320 + 1.2321 +void 1.2322 +evhttp_start_read(struct evhttp_connection *evcon) 1.2323 +{ 1.2324 + /* Set up an event to read the headers */ 1.2325 + bufferevent_disable(evcon->bufev, EV_WRITE); 1.2326 + bufferevent_enable(evcon->bufev, EV_READ); 1.2327 + evcon->state = EVCON_READING_FIRSTLINE; 1.2328 + /* Reset the bufferevent callbacks */ 1.2329 + bufferevent_setcb(evcon->bufev, 1.2330 + evhttp_read_cb, 1.2331 + evhttp_write_cb, 1.2332 + evhttp_error_cb, 1.2333 + evcon); 1.2334 + 1.2335 + /* If there's still data pending, process it next time through the 1.2336 + * loop. Don't do it now; that could get recusive. */ 1.2337 + if (evbuffer_get_length(bufferevent_get_input(evcon->bufev))) { 1.2338 + event_deferred_cb_schedule(get_deferred_queue(evcon), 1.2339 + &evcon->read_more_deferred_cb); 1.2340 + } 1.2341 +} 1.2342 + 1.2343 +static void 1.2344 +evhttp_send_done(struct evhttp_connection *evcon, void *arg) 1.2345 +{ 1.2346 + int need_close; 1.2347 + struct evhttp_request *req = TAILQ_FIRST(&evcon->requests); 1.2348 + TAILQ_REMOVE(&evcon->requests, req, next); 1.2349 + 1.2350 + need_close = 1.2351 + (REQ_VERSION_BEFORE(req, 1, 1) && 1.2352 + !evhttp_is_connection_keepalive(req->input_headers))|| 1.2353 + evhttp_is_connection_close(req->flags, req->input_headers) || 1.2354 + evhttp_is_connection_close(req->flags, req->output_headers); 1.2355 + 1.2356 + EVUTIL_ASSERT(req->flags & EVHTTP_REQ_OWN_CONNECTION); 1.2357 + evhttp_request_free(req); 1.2358 + 1.2359 + if (need_close) { 1.2360 + evhttp_connection_free(evcon); 1.2361 + return; 1.2362 + } 1.2363 + 1.2364 + /* we have a persistent connection; try to accept another request. */ 1.2365 + if (evhttp_associate_new_request_with_connection(evcon) == -1) { 1.2366 + evhttp_connection_free(evcon); 1.2367 + } 1.2368 +} 1.2369 + 1.2370 +/* 1.2371 + * Returns an error page. 1.2372 + */ 1.2373 + 1.2374 +void 1.2375 +evhttp_send_error(struct evhttp_request *req, int error, const char *reason) 1.2376 +{ 1.2377 + 1.2378 +#define ERR_FORMAT "<HTML><HEAD>\n" \ 1.2379 + "<TITLE>%d %s</TITLE>\n" \ 1.2380 + "</HEAD><BODY>\n" \ 1.2381 + "<H1>%s</H1>\n" \ 1.2382 + "</BODY></HTML>\n" 1.2383 + 1.2384 + struct evbuffer *buf = evbuffer_new(); 1.2385 + if (buf == NULL) { 1.2386 + /* if we cannot allocate memory; we just drop the connection */ 1.2387 + evhttp_connection_free(req->evcon); 1.2388 + return; 1.2389 + } 1.2390 + if (reason == NULL) { 1.2391 + reason = evhttp_response_phrase_internal(error); 1.2392 + } 1.2393 + 1.2394 + evhttp_response_code(req, error, reason); 1.2395 + 1.2396 + evbuffer_add_printf(buf, ERR_FORMAT, error, reason, reason); 1.2397 + 1.2398 + evhttp_send_page(req, buf); 1.2399 + 1.2400 + evbuffer_free(buf); 1.2401 +#undef ERR_FORMAT 1.2402 +} 1.2403 + 1.2404 +/* Requires that headers and response code are already set up */ 1.2405 + 1.2406 +static inline void 1.2407 +evhttp_send(struct evhttp_request *req, struct evbuffer *databuf) 1.2408 +{ 1.2409 + struct evhttp_connection *evcon = req->evcon; 1.2410 + 1.2411 + if (evcon == NULL) { 1.2412 + evhttp_request_free(req); 1.2413 + return; 1.2414 + } 1.2415 + 1.2416 + EVUTIL_ASSERT(TAILQ_FIRST(&evcon->requests) == req); 1.2417 + 1.2418 + /* we expect no more calls form the user on this request */ 1.2419 + req->userdone = 1; 1.2420 + 1.2421 + /* xxx: not sure if we really should expose the data buffer this way */ 1.2422 + if (databuf != NULL) 1.2423 + evbuffer_add_buffer(req->output_buffer, databuf); 1.2424 + 1.2425 + /* Adds headers to the response */ 1.2426 + evhttp_make_header(evcon, req); 1.2427 + 1.2428 + evhttp_write_buffer(evcon, evhttp_send_done, NULL); 1.2429 +} 1.2430 + 1.2431 +void 1.2432 +evhttp_send_reply(struct evhttp_request *req, int code, const char *reason, 1.2433 + struct evbuffer *databuf) 1.2434 +{ 1.2435 + evhttp_response_code(req, code, reason); 1.2436 + 1.2437 + evhttp_send(req, databuf); 1.2438 +} 1.2439 + 1.2440 +void 1.2441 +evhttp_send_reply_start(struct evhttp_request *req, int code, 1.2442 + const char *reason) 1.2443 +{ 1.2444 + evhttp_response_code(req, code, reason); 1.2445 + if (evhttp_find_header(req->output_headers, "Content-Length") == NULL && 1.2446 + REQ_VERSION_ATLEAST(req, 1, 1) && 1.2447 + evhttp_response_needs_body(req)) { 1.2448 + /* 1.2449 + * prefer HTTP/1.1 chunked encoding to closing the connection; 1.2450 + * note RFC 2616 section 4.4 forbids it with Content-Length: 1.2451 + * and it's not necessary then anyway. 1.2452 + */ 1.2453 + evhttp_add_header(req->output_headers, "Transfer-Encoding", 1.2454 + "chunked"); 1.2455 + req->chunked = 1; 1.2456 + } else { 1.2457 + req->chunked = 0; 1.2458 + } 1.2459 + evhttp_make_header(req->evcon, req); 1.2460 + evhttp_write_buffer(req->evcon, NULL, NULL); 1.2461 +} 1.2462 + 1.2463 +void 1.2464 +evhttp_send_reply_chunk(struct evhttp_request *req, struct evbuffer *databuf) 1.2465 +{ 1.2466 + struct evhttp_connection *evcon = req->evcon; 1.2467 + struct evbuffer *output; 1.2468 + 1.2469 + if (evcon == NULL) 1.2470 + return; 1.2471 + 1.2472 + output = bufferevent_get_output(evcon->bufev); 1.2473 + 1.2474 + if (evbuffer_get_length(databuf) == 0) 1.2475 + return; 1.2476 + if (!evhttp_response_needs_body(req)) 1.2477 + return; 1.2478 + if (req->chunked) { 1.2479 + evbuffer_add_printf(output, "%x\r\n", 1.2480 + (unsigned)evbuffer_get_length(databuf)); 1.2481 + } 1.2482 + evbuffer_add_buffer(output, databuf); 1.2483 + if (req->chunked) { 1.2484 + evbuffer_add(output, "\r\n", 2); 1.2485 + } 1.2486 + evhttp_write_buffer(evcon, NULL, NULL); 1.2487 +} 1.2488 + 1.2489 +void 1.2490 +evhttp_send_reply_end(struct evhttp_request *req) 1.2491 +{ 1.2492 + struct evhttp_connection *evcon = req->evcon; 1.2493 + struct evbuffer *output; 1.2494 + 1.2495 + if (evcon == NULL) { 1.2496 + evhttp_request_free(req); 1.2497 + return; 1.2498 + } 1.2499 + 1.2500 + output = bufferevent_get_output(evcon->bufev); 1.2501 + 1.2502 + /* we expect no more calls form the user on this request */ 1.2503 + req->userdone = 1; 1.2504 + 1.2505 + if (req->chunked) { 1.2506 + evbuffer_add(output, "0\r\n\r\n", 5); 1.2507 + evhttp_write_buffer(req->evcon, evhttp_send_done, NULL); 1.2508 + req->chunked = 0; 1.2509 + } else if (evbuffer_get_length(output) == 0) { 1.2510 + /* let the connection know that we are done with the request */ 1.2511 + evhttp_send_done(evcon, NULL); 1.2512 + } else { 1.2513 + /* make the callback execute after all data has been written */ 1.2514 + evcon->cb = evhttp_send_done; 1.2515 + evcon->cb_arg = NULL; 1.2516 + } 1.2517 +} 1.2518 + 1.2519 +static const char *informational_phrases[] = { 1.2520 + /* 100 */ "Continue", 1.2521 + /* 101 */ "Switching Protocols" 1.2522 +}; 1.2523 + 1.2524 +static const char *success_phrases[] = { 1.2525 + /* 200 */ "OK", 1.2526 + /* 201 */ "Created", 1.2527 + /* 202 */ "Accepted", 1.2528 + /* 203 */ "Non-Authoritative Information", 1.2529 + /* 204 */ "No Content", 1.2530 + /* 205 */ "Reset Content", 1.2531 + /* 206 */ "Partial Content" 1.2532 +}; 1.2533 + 1.2534 +static const char *redirection_phrases[] = { 1.2535 + /* 300 */ "Multiple Choices", 1.2536 + /* 301 */ "Moved Permanently", 1.2537 + /* 302 */ "Found", 1.2538 + /* 303 */ "See Other", 1.2539 + /* 304 */ "Not Modified", 1.2540 + /* 305 */ "Use Proxy", 1.2541 + /* 307 */ "Temporary Redirect" 1.2542 +}; 1.2543 + 1.2544 +static const char *client_error_phrases[] = { 1.2545 + /* 400 */ "Bad Request", 1.2546 + /* 401 */ "Unauthorized", 1.2547 + /* 402 */ "Payment Required", 1.2548 + /* 403 */ "Forbidden", 1.2549 + /* 404 */ "Not Found", 1.2550 + /* 405 */ "Method Not Allowed", 1.2551 + /* 406 */ "Not Acceptable", 1.2552 + /* 407 */ "Proxy Authentication Required", 1.2553 + /* 408 */ "Request Time-out", 1.2554 + /* 409 */ "Conflict", 1.2555 + /* 410 */ "Gone", 1.2556 + /* 411 */ "Length Required", 1.2557 + /* 412 */ "Precondition Failed", 1.2558 + /* 413 */ "Request Entity Too Large", 1.2559 + /* 414 */ "Request-URI Too Large", 1.2560 + /* 415 */ "Unsupported Media Type", 1.2561 + /* 416 */ "Requested range not satisfiable", 1.2562 + /* 417 */ "Expectation Failed" 1.2563 +}; 1.2564 + 1.2565 +static const char *server_error_phrases[] = { 1.2566 + /* 500 */ "Internal Server Error", 1.2567 + /* 501 */ "Not Implemented", 1.2568 + /* 502 */ "Bad Gateway", 1.2569 + /* 503 */ "Service Unavailable", 1.2570 + /* 504 */ "Gateway Time-out", 1.2571 + /* 505 */ "HTTP Version not supported" 1.2572 +}; 1.2573 + 1.2574 +struct response_class { 1.2575 + const char *name; 1.2576 + size_t num_responses; 1.2577 + const char **responses; 1.2578 +}; 1.2579 + 1.2580 +#ifndef MEMBERSOF 1.2581 +#define MEMBERSOF(x) (sizeof(x)/sizeof(x[0])) 1.2582 +#endif 1.2583 + 1.2584 +static const struct response_class response_classes[] = { 1.2585 + /* 1xx */ { "Informational", MEMBERSOF(informational_phrases), informational_phrases }, 1.2586 + /* 2xx */ { "Success", MEMBERSOF(success_phrases), success_phrases }, 1.2587 + /* 3xx */ { "Redirection", MEMBERSOF(redirection_phrases), redirection_phrases }, 1.2588 + /* 4xx */ { "Client Error", MEMBERSOF(client_error_phrases), client_error_phrases }, 1.2589 + /* 5xx */ { "Server Error", MEMBERSOF(server_error_phrases), server_error_phrases } 1.2590 +}; 1.2591 + 1.2592 +static const char * 1.2593 +evhttp_response_phrase_internal(int code) 1.2594 +{ 1.2595 + int klass = code / 100 - 1; 1.2596 + int subcode = code % 100; 1.2597 + 1.2598 + /* Unknown class - can't do any better here */ 1.2599 + if (klass < 0 || klass >= (int) MEMBERSOF(response_classes)) 1.2600 + return "Unknown Status Class"; 1.2601 + 1.2602 + /* Unknown sub-code, return class name at least */ 1.2603 + if (subcode >= (int) response_classes[klass].num_responses) 1.2604 + return response_classes[klass].name; 1.2605 + 1.2606 + return response_classes[klass].responses[subcode]; 1.2607 +} 1.2608 + 1.2609 +void 1.2610 +evhttp_response_code(struct evhttp_request *req, int code, const char *reason) 1.2611 +{ 1.2612 + req->kind = EVHTTP_RESPONSE; 1.2613 + req->response_code = code; 1.2614 + if (req->response_code_line != NULL) 1.2615 + mm_free(req->response_code_line); 1.2616 + if (reason == NULL) 1.2617 + reason = evhttp_response_phrase_internal(code); 1.2618 + req->response_code_line = mm_strdup(reason); 1.2619 + if (req->response_code_line == NULL) { 1.2620 + event_warn("%s: strdup", __func__); 1.2621 + /* XXX what else can we do? */ 1.2622 + } 1.2623 +} 1.2624 + 1.2625 +void 1.2626 +evhttp_send_page(struct evhttp_request *req, struct evbuffer *databuf) 1.2627 +{ 1.2628 + if (!req->major || !req->minor) { 1.2629 + req->major = 1; 1.2630 + req->minor = 1; 1.2631 + } 1.2632 + 1.2633 + if (req->kind != EVHTTP_RESPONSE) 1.2634 + evhttp_response_code(req, 200, "OK"); 1.2635 + 1.2636 + evhttp_clear_headers(req->output_headers); 1.2637 + evhttp_add_header(req->output_headers, "Content-Type", "text/html"); 1.2638 + evhttp_add_header(req->output_headers, "Connection", "close"); 1.2639 + 1.2640 + evhttp_send(req, databuf); 1.2641 +} 1.2642 + 1.2643 +static const char uri_chars[256] = { 1.2644 + /* 0 */ 1.2645 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1.2646 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1.2647 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1.2648 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1.2649 + /* 64 */ 1.2650 + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1.2651 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1.2652 + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1.2653 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 1.2654 + /* 128 */ 1.2655 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1.2656 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1.2657 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1.2658 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1.2659 + /* 192 */ 1.2660 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1.2661 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1.2662 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1.2663 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1.2664 +}; 1.2665 + 1.2666 +#define CHAR_IS_UNRESERVED(c) \ 1.2667 + (uri_chars[(unsigned char)(c)]) 1.2668 + 1.2669 +/* 1.2670 + * Helper functions to encode/decode a string for inclusion in a URI. 1.2671 + * The returned string must be freed by the caller. 1.2672 + */ 1.2673 +char * 1.2674 +evhttp_uriencode(const char *uri, ev_ssize_t len, int space_as_plus) 1.2675 +{ 1.2676 + struct evbuffer *buf = evbuffer_new(); 1.2677 + const char *p, *end; 1.2678 + char *result; 1.2679 + 1.2680 + if (buf == NULL) 1.2681 + return (NULL); 1.2682 + 1.2683 + if (len >= 0) 1.2684 + end = uri+len; 1.2685 + else 1.2686 + end = uri+strlen(uri); 1.2687 + 1.2688 + for (p = uri; p < end; p++) { 1.2689 + if (CHAR_IS_UNRESERVED(*p)) { 1.2690 + evbuffer_add(buf, p, 1); 1.2691 + } else if (*p == ' ' && space_as_plus) { 1.2692 + evbuffer_add(buf, "+", 1); 1.2693 + } else { 1.2694 + evbuffer_add_printf(buf, "%%%02X", (unsigned char)(*p)); 1.2695 + } 1.2696 + } 1.2697 + evbuffer_add(buf, "", 1); /* NUL-terminator. */ 1.2698 + result = mm_malloc(evbuffer_get_length(buf)); 1.2699 + if (result) 1.2700 + evbuffer_remove(buf, result, evbuffer_get_length(buf)); 1.2701 + evbuffer_free(buf); 1.2702 + 1.2703 + return (result); 1.2704 +} 1.2705 + 1.2706 +char * 1.2707 +evhttp_encode_uri(const char *str) 1.2708 +{ 1.2709 + return evhttp_uriencode(str, -1, 0); 1.2710 +} 1.2711 + 1.2712 +/* 1.2713 + * @param decode_plus_ctl: if 1, we decode plus into space. If 0, we don't. 1.2714 + * If -1, when true we transform plus to space only after we've seen 1.2715 + * a ?. -1 is deprecated. 1.2716 + * @return the number of bytes written to 'ret'. 1.2717 + */ 1.2718 +static int 1.2719 +evhttp_decode_uri_internal( 1.2720 + const char *uri, size_t length, char *ret, int decode_plus_ctl) 1.2721 +{ 1.2722 + char c; 1.2723 + int j; 1.2724 + int decode_plus = (decode_plus_ctl == 1) ? 1: 0; 1.2725 + unsigned i; 1.2726 + 1.2727 + for (i = j = 0; i < length; i++) { 1.2728 + c = uri[i]; 1.2729 + if (c == '?') { 1.2730 + if (decode_plus_ctl < 0) 1.2731 + decode_plus = 1; 1.2732 + } else if (c == '+' && decode_plus) { 1.2733 + c = ' '; 1.2734 + } else if (c == '%' && EVUTIL_ISXDIGIT(uri[i+1]) && 1.2735 + EVUTIL_ISXDIGIT(uri[i+2])) { 1.2736 + char tmp[3]; 1.2737 + tmp[0] = uri[i+1]; 1.2738 + tmp[1] = uri[i+2]; 1.2739 + tmp[2] = '\0'; 1.2740 + c = (char)strtol(tmp, NULL, 16); 1.2741 + i += 2; 1.2742 + } 1.2743 + ret[j++] = c; 1.2744 + } 1.2745 + ret[j] = '\0'; 1.2746 + 1.2747 + return (j); 1.2748 +} 1.2749 + 1.2750 +/* deprecated */ 1.2751 +char * 1.2752 +evhttp_decode_uri(const char *uri) 1.2753 +{ 1.2754 + char *ret; 1.2755 + 1.2756 + if ((ret = mm_malloc(strlen(uri) + 1)) == NULL) { 1.2757 + event_warn("%s: malloc(%lu)", __func__, 1.2758 + (unsigned long)(strlen(uri) + 1)); 1.2759 + return (NULL); 1.2760 + } 1.2761 + 1.2762 + evhttp_decode_uri_internal(uri, strlen(uri), 1.2763 + ret, -1 /*always_decode_plus*/); 1.2764 + 1.2765 + return (ret); 1.2766 +} 1.2767 + 1.2768 +char * 1.2769 +evhttp_uridecode(const char *uri, int decode_plus, size_t *size_out) 1.2770 +{ 1.2771 + char *ret; 1.2772 + int n; 1.2773 + 1.2774 + if ((ret = mm_malloc(strlen(uri) + 1)) == NULL) { 1.2775 + event_warn("%s: malloc(%lu)", __func__, 1.2776 + (unsigned long)(strlen(uri) + 1)); 1.2777 + return (NULL); 1.2778 + } 1.2779 + 1.2780 + n = evhttp_decode_uri_internal(uri, strlen(uri), 1.2781 + ret, !!decode_plus/*always_decode_plus*/); 1.2782 + 1.2783 + if (size_out) { 1.2784 + EVUTIL_ASSERT(n >= 0); 1.2785 + *size_out = (size_t)n; 1.2786 + } 1.2787 + 1.2788 + return (ret); 1.2789 +} 1.2790 + 1.2791 +/* 1.2792 + * Helper function to parse out arguments in a query. 1.2793 + * The arguments are separated by key and value. 1.2794 + */ 1.2795 + 1.2796 +static int 1.2797 +evhttp_parse_query_impl(const char *str, struct evkeyvalq *headers, 1.2798 + int is_whole_uri) 1.2799 +{ 1.2800 + char *line=NULL; 1.2801 + char *argument; 1.2802 + char *p; 1.2803 + const char *query_part; 1.2804 + int result = -1; 1.2805 + struct evhttp_uri *uri=NULL; 1.2806 + 1.2807 + TAILQ_INIT(headers); 1.2808 + 1.2809 + if (is_whole_uri) { 1.2810 + uri = evhttp_uri_parse(str); 1.2811 + if (!uri) 1.2812 + goto error; 1.2813 + query_part = evhttp_uri_get_query(uri); 1.2814 + } else { 1.2815 + query_part = str; 1.2816 + } 1.2817 + 1.2818 + /* No arguments - we are done */ 1.2819 + if (!query_part || !strlen(query_part)) { 1.2820 + result = 0; 1.2821 + goto done; 1.2822 + } 1.2823 + 1.2824 + if ((line = mm_strdup(query_part)) == NULL) { 1.2825 + event_warn("%s: strdup", __func__); 1.2826 + goto error; 1.2827 + } 1.2828 + 1.2829 + p = argument = line; 1.2830 + while (p != NULL && *p != '\0') { 1.2831 + char *key, *value, *decoded_value; 1.2832 + argument = strsep(&p, "&"); 1.2833 + 1.2834 + value = argument; 1.2835 + key = strsep(&value, "="); 1.2836 + if (value == NULL || *key == '\0') { 1.2837 + goto error; 1.2838 + } 1.2839 + 1.2840 + if ((decoded_value = mm_malloc(strlen(value) + 1)) == NULL) { 1.2841 + event_warn("%s: mm_malloc", __func__); 1.2842 + goto error; 1.2843 + } 1.2844 + evhttp_decode_uri_internal(value, strlen(value), 1.2845 + decoded_value, 1 /*always_decode_plus*/); 1.2846 + event_debug(("Query Param: %s -> %s\n", key, decoded_value)); 1.2847 + evhttp_add_header_internal(headers, key, decoded_value); 1.2848 + mm_free(decoded_value); 1.2849 + } 1.2850 + 1.2851 + result = 0; 1.2852 + goto done; 1.2853 +error: 1.2854 + evhttp_clear_headers(headers); 1.2855 +done: 1.2856 + if (line) 1.2857 + mm_free(line); 1.2858 + if (uri) 1.2859 + evhttp_uri_free(uri); 1.2860 + return result; 1.2861 +} 1.2862 + 1.2863 +int 1.2864 +evhttp_parse_query(const char *uri, struct evkeyvalq *headers) 1.2865 +{ 1.2866 + return evhttp_parse_query_impl(uri, headers, 1); 1.2867 +} 1.2868 +int 1.2869 +evhttp_parse_query_str(const char *uri, struct evkeyvalq *headers) 1.2870 +{ 1.2871 + return evhttp_parse_query_impl(uri, headers, 0); 1.2872 +} 1.2873 + 1.2874 +static struct evhttp_cb * 1.2875 +evhttp_dispatch_callback(struct httpcbq *callbacks, struct evhttp_request *req) 1.2876 +{ 1.2877 + struct evhttp_cb *cb; 1.2878 + size_t offset = 0; 1.2879 + char *translated; 1.2880 + const char *path; 1.2881 + 1.2882 + /* Test for different URLs */ 1.2883 + path = evhttp_uri_get_path(req->uri_elems); 1.2884 + offset = strlen(path); 1.2885 + if ((translated = mm_malloc(offset + 1)) == NULL) 1.2886 + return (NULL); 1.2887 + evhttp_decode_uri_internal(path, offset, translated, 1.2888 + 0 /* decode_plus */); 1.2889 + 1.2890 + TAILQ_FOREACH(cb, callbacks, next) { 1.2891 + if (!strcmp(cb->what, translated)) { 1.2892 + mm_free(translated); 1.2893 + return (cb); 1.2894 + } 1.2895 + } 1.2896 + 1.2897 + mm_free(translated); 1.2898 + return (NULL); 1.2899 +} 1.2900 + 1.2901 + 1.2902 +static int 1.2903 +prefix_suffix_match(const char *pattern, const char *name, int ignorecase) 1.2904 +{ 1.2905 + char c; 1.2906 + 1.2907 + while (1) { 1.2908 + switch (c = *pattern++) { 1.2909 + case '\0': 1.2910 + return *name == '\0'; 1.2911 + 1.2912 + case '*': 1.2913 + while (*name != '\0') { 1.2914 + if (prefix_suffix_match(pattern, name, 1.2915 + ignorecase)) 1.2916 + return (1); 1.2917 + ++name; 1.2918 + } 1.2919 + return (0); 1.2920 + default: 1.2921 + if (c != *name) { 1.2922 + if (!ignorecase || 1.2923 + EVUTIL_TOLOWER(c) != EVUTIL_TOLOWER(*name)) 1.2924 + return (0); 1.2925 + } 1.2926 + ++name; 1.2927 + } 1.2928 + } 1.2929 + /* NOTREACHED */ 1.2930 +} 1.2931 + 1.2932 +/* 1.2933 + Search the vhost hierarchy beginning with http for a server alias 1.2934 + matching hostname. If a match is found, and outhttp is non-null, 1.2935 + outhttp is set to the matching http object and 1 is returned. 1.2936 +*/ 1.2937 + 1.2938 +static int 1.2939 +evhttp_find_alias(struct evhttp *http, struct evhttp **outhttp, 1.2940 + const char *hostname) 1.2941 +{ 1.2942 + struct evhttp_server_alias *alias; 1.2943 + struct evhttp *vhost; 1.2944 + 1.2945 + TAILQ_FOREACH(alias, &http->aliases, next) { 1.2946 + /* XXX Do we need to handle IP addresses? */ 1.2947 + if (!evutil_ascii_strcasecmp(alias->alias, hostname)) { 1.2948 + if (outhttp) 1.2949 + *outhttp = http; 1.2950 + return 1; 1.2951 + } 1.2952 + } 1.2953 + 1.2954 + /* XXX It might be good to avoid recursion here, but I don't 1.2955 + see a way to do that w/o a list. */ 1.2956 + TAILQ_FOREACH(vhost, &http->virtualhosts, next_vhost) { 1.2957 + if (evhttp_find_alias(vhost, outhttp, hostname)) 1.2958 + return 1; 1.2959 + } 1.2960 + 1.2961 + return 0; 1.2962 +} 1.2963 + 1.2964 +/* 1.2965 + Attempts to find the best http object to handle a request for a hostname. 1.2966 + All aliases for the root http object and vhosts are searched for an exact 1.2967 + match. Then, the vhost hierarchy is traversed again for a matching 1.2968 + pattern. 1.2969 + 1.2970 + If an alias or vhost is matched, 1 is returned, and outhttp, if non-null, 1.2971 + is set with the best matching http object. If there are no matches, the 1.2972 + root http object is stored in outhttp and 0 is returned. 1.2973 +*/ 1.2974 + 1.2975 +static int 1.2976 +evhttp_find_vhost(struct evhttp *http, struct evhttp **outhttp, 1.2977 + const char *hostname) 1.2978 +{ 1.2979 + struct evhttp *vhost; 1.2980 + struct evhttp *oldhttp; 1.2981 + int match_found = 0; 1.2982 + 1.2983 + if (evhttp_find_alias(http, outhttp, hostname)) 1.2984 + return 1; 1.2985 + 1.2986 + do { 1.2987 + oldhttp = http; 1.2988 + TAILQ_FOREACH(vhost, &http->virtualhosts, next_vhost) { 1.2989 + if (prefix_suffix_match(vhost->vhost_pattern, 1.2990 + hostname, 1 /* ignorecase */)) { 1.2991 + http = vhost; 1.2992 + match_found = 1; 1.2993 + break; 1.2994 + } 1.2995 + } 1.2996 + } while (oldhttp != http); 1.2997 + 1.2998 + if (outhttp) 1.2999 + *outhttp = http; 1.3000 + 1.3001 + return match_found; 1.3002 +} 1.3003 + 1.3004 +static void 1.3005 +evhttp_handle_request(struct evhttp_request *req, void *arg) 1.3006 +{ 1.3007 + struct evhttp *http = arg; 1.3008 + struct evhttp_cb *cb = NULL; 1.3009 + const char *hostname; 1.3010 + 1.3011 + /* we have a new request on which the user needs to take action */ 1.3012 + req->userdone = 0; 1.3013 + 1.3014 + if (req->type == 0 || req->uri == NULL) { 1.3015 + evhttp_send_error(req, HTTP_BADREQUEST, NULL); 1.3016 + return; 1.3017 + } 1.3018 + 1.3019 + if ((http->allowed_methods & req->type) == 0) { 1.3020 + event_debug(("Rejecting disallowed method %x (allowed: %x)\n", 1.3021 + (unsigned)req->type, (unsigned)http->allowed_methods)); 1.3022 + evhttp_send_error(req, HTTP_NOTIMPLEMENTED, NULL); 1.3023 + return; 1.3024 + } 1.3025 + 1.3026 + /* handle potential virtual hosts */ 1.3027 + hostname = evhttp_request_get_host(req); 1.3028 + if (hostname != NULL) { 1.3029 + evhttp_find_vhost(http, &http, hostname); 1.3030 + } 1.3031 + 1.3032 + if ((cb = evhttp_dispatch_callback(&http->callbacks, req)) != NULL) { 1.3033 + (*cb->cb)(req, cb->cbarg); 1.3034 + return; 1.3035 + } 1.3036 + 1.3037 + /* Generic call back */ 1.3038 + if (http->gencb) { 1.3039 + (*http->gencb)(req, http->gencbarg); 1.3040 + return; 1.3041 + } else { 1.3042 + /* We need to send a 404 here */ 1.3043 +#define ERR_FORMAT "<html><head>" \ 1.3044 + "<title>404 Not Found</title>" \ 1.3045 + "</head><body>" \ 1.3046 + "<h1>Not Found</h1>" \ 1.3047 + "<p>The requested URL %s was not found on this server.</p>"\ 1.3048 + "</body></html>\n" 1.3049 + 1.3050 + char *escaped_html; 1.3051 + struct evbuffer *buf; 1.3052 + 1.3053 + if ((escaped_html = evhttp_htmlescape(req->uri)) == NULL) { 1.3054 + evhttp_connection_free(req->evcon); 1.3055 + return; 1.3056 + } 1.3057 + 1.3058 + if ((buf = evbuffer_new()) == NULL) { 1.3059 + mm_free(escaped_html); 1.3060 + evhttp_connection_free(req->evcon); 1.3061 + return; 1.3062 + } 1.3063 + 1.3064 + evhttp_response_code(req, HTTP_NOTFOUND, "Not Found"); 1.3065 + 1.3066 + evbuffer_add_printf(buf, ERR_FORMAT, escaped_html); 1.3067 + 1.3068 + mm_free(escaped_html); 1.3069 + 1.3070 + evhttp_send_page(req, buf); 1.3071 + 1.3072 + evbuffer_free(buf); 1.3073 +#undef ERR_FORMAT 1.3074 + } 1.3075 +} 1.3076 + 1.3077 +/* Listener callback when a connection arrives at a server. */ 1.3078 +static void 1.3079 +accept_socket_cb(struct evconnlistener *listener, evutil_socket_t nfd, struct sockaddr *peer_sa, int peer_socklen, void *arg) 1.3080 +{ 1.3081 + struct evhttp *http = arg; 1.3082 + 1.3083 + evhttp_get_request(http, nfd, peer_sa, peer_socklen); 1.3084 +} 1.3085 + 1.3086 +int 1.3087 +evhttp_bind_socket(struct evhttp *http, const char *address, ev_uint16_t port) 1.3088 +{ 1.3089 + struct evhttp_bound_socket *bound = 1.3090 + evhttp_bind_socket_with_handle(http, address, port); 1.3091 + if (bound == NULL) 1.3092 + return (-1); 1.3093 + return (0); 1.3094 +} 1.3095 + 1.3096 +struct evhttp_bound_socket * 1.3097 +evhttp_bind_socket_with_handle(struct evhttp *http, const char *address, ev_uint16_t port) 1.3098 +{ 1.3099 + evutil_socket_t fd; 1.3100 + struct evhttp_bound_socket *bound; 1.3101 + 1.3102 + if ((fd = bind_socket(address, port, 1 /*reuse*/)) == -1) 1.3103 + return (NULL); 1.3104 + 1.3105 + if (listen(fd, 128) == -1) { 1.3106 + event_sock_warn(fd, "%s: listen", __func__); 1.3107 + evutil_closesocket(fd); 1.3108 + return (NULL); 1.3109 + } 1.3110 + 1.3111 + bound = evhttp_accept_socket_with_handle(http, fd); 1.3112 + 1.3113 + if (bound != NULL) { 1.3114 + event_debug(("Bound to port %d - Awaiting connections ... ", 1.3115 + port)); 1.3116 + return (bound); 1.3117 + } 1.3118 + 1.3119 + return (NULL); 1.3120 +} 1.3121 + 1.3122 +int 1.3123 +evhttp_accept_socket(struct evhttp *http, evutil_socket_t fd) 1.3124 +{ 1.3125 + struct evhttp_bound_socket *bound = 1.3126 + evhttp_accept_socket_with_handle(http, fd); 1.3127 + if (bound == NULL) 1.3128 + return (-1); 1.3129 + return (0); 1.3130 +} 1.3131 + 1.3132 + 1.3133 +struct evhttp_bound_socket * 1.3134 +evhttp_accept_socket_with_handle(struct evhttp *http, evutil_socket_t fd) 1.3135 +{ 1.3136 + struct evhttp_bound_socket *bound; 1.3137 + struct evconnlistener *listener; 1.3138 + const int flags = 1.3139 + LEV_OPT_REUSEABLE|LEV_OPT_CLOSE_ON_EXEC|LEV_OPT_CLOSE_ON_FREE; 1.3140 + 1.3141 + listener = evconnlistener_new(http->base, NULL, NULL, 1.3142 + flags, 1.3143 + 0, /* Backlog is '0' because we already said 'listen' */ 1.3144 + fd); 1.3145 + if (!listener) 1.3146 + return (NULL); 1.3147 + 1.3148 + bound = evhttp_bind_listener(http, listener); 1.3149 + if (!bound) { 1.3150 + evconnlistener_free(listener); 1.3151 + return (NULL); 1.3152 + } 1.3153 + return (bound); 1.3154 +} 1.3155 + 1.3156 +struct evhttp_bound_socket * 1.3157 +evhttp_bind_listener(struct evhttp *http, struct evconnlistener *listener) 1.3158 +{ 1.3159 + struct evhttp_bound_socket *bound; 1.3160 + 1.3161 + bound = mm_malloc(sizeof(struct evhttp_bound_socket)); 1.3162 + if (bound == NULL) 1.3163 + return (NULL); 1.3164 + 1.3165 + bound->listener = listener; 1.3166 + TAILQ_INSERT_TAIL(&http->sockets, bound, next); 1.3167 + 1.3168 + evconnlistener_set_cb(listener, accept_socket_cb, http); 1.3169 + return bound; 1.3170 +} 1.3171 + 1.3172 +evutil_socket_t 1.3173 +evhttp_bound_socket_get_fd(struct evhttp_bound_socket *bound) 1.3174 +{ 1.3175 + return evconnlistener_get_fd(bound->listener); 1.3176 +} 1.3177 + 1.3178 +struct evconnlistener * 1.3179 +evhttp_bound_socket_get_listener(struct evhttp_bound_socket *bound) 1.3180 +{ 1.3181 + return bound->listener; 1.3182 +} 1.3183 + 1.3184 +void 1.3185 +evhttp_del_accept_socket(struct evhttp *http, struct evhttp_bound_socket *bound) 1.3186 +{ 1.3187 + TAILQ_REMOVE(&http->sockets, bound, next); 1.3188 + evconnlistener_free(bound->listener); 1.3189 + mm_free(bound); 1.3190 +} 1.3191 + 1.3192 +static struct evhttp* 1.3193 +evhttp_new_object(void) 1.3194 +{ 1.3195 + struct evhttp *http = NULL; 1.3196 + 1.3197 + if ((http = mm_calloc(1, sizeof(struct evhttp))) == NULL) { 1.3198 + event_warn("%s: calloc", __func__); 1.3199 + return (NULL); 1.3200 + } 1.3201 + 1.3202 + http->timeout = -1; 1.3203 + evhttp_set_max_headers_size(http, EV_SIZE_MAX); 1.3204 + evhttp_set_max_body_size(http, EV_SIZE_MAX); 1.3205 + evhttp_set_allowed_methods(http, 1.3206 + EVHTTP_REQ_GET | 1.3207 + EVHTTP_REQ_POST | 1.3208 + EVHTTP_REQ_HEAD | 1.3209 + EVHTTP_REQ_PUT | 1.3210 + EVHTTP_REQ_DELETE); 1.3211 + 1.3212 + TAILQ_INIT(&http->sockets); 1.3213 + TAILQ_INIT(&http->callbacks); 1.3214 + TAILQ_INIT(&http->connections); 1.3215 + TAILQ_INIT(&http->virtualhosts); 1.3216 + TAILQ_INIT(&http->aliases); 1.3217 + 1.3218 + return (http); 1.3219 +} 1.3220 + 1.3221 +struct evhttp * 1.3222 +evhttp_new(struct event_base *base) 1.3223 +{ 1.3224 + struct evhttp *http = NULL; 1.3225 + 1.3226 + http = evhttp_new_object(); 1.3227 + if (http == NULL) 1.3228 + return (NULL); 1.3229 + http->base = base; 1.3230 + 1.3231 + return (http); 1.3232 +} 1.3233 + 1.3234 +/* 1.3235 + * Start a web server on the specified address and port. 1.3236 + */ 1.3237 + 1.3238 +struct evhttp * 1.3239 +evhttp_start(const char *address, unsigned short port) 1.3240 +{ 1.3241 + struct evhttp *http = NULL; 1.3242 + 1.3243 + http = evhttp_new_object(); 1.3244 + if (http == NULL) 1.3245 + return (NULL); 1.3246 + if (evhttp_bind_socket(http, address, port) == -1) { 1.3247 + mm_free(http); 1.3248 + return (NULL); 1.3249 + } 1.3250 + 1.3251 + return (http); 1.3252 +} 1.3253 + 1.3254 +void 1.3255 +evhttp_free(struct evhttp* http) 1.3256 +{ 1.3257 + struct evhttp_cb *http_cb; 1.3258 + struct evhttp_connection *evcon; 1.3259 + struct evhttp_bound_socket *bound; 1.3260 + struct evhttp* vhost; 1.3261 + struct evhttp_server_alias *alias; 1.3262 + 1.3263 + /* Remove the accepting part */ 1.3264 + while ((bound = TAILQ_FIRST(&http->sockets)) != NULL) { 1.3265 + TAILQ_REMOVE(&http->sockets, bound, next); 1.3266 + 1.3267 + evconnlistener_free(bound->listener); 1.3268 + 1.3269 + mm_free(bound); 1.3270 + } 1.3271 + 1.3272 + while ((evcon = TAILQ_FIRST(&http->connections)) != NULL) { 1.3273 + /* evhttp_connection_free removes the connection */ 1.3274 + evhttp_connection_free(evcon); 1.3275 + } 1.3276 + 1.3277 + while ((http_cb = TAILQ_FIRST(&http->callbacks)) != NULL) { 1.3278 + TAILQ_REMOVE(&http->callbacks, http_cb, next); 1.3279 + mm_free(http_cb->what); 1.3280 + mm_free(http_cb); 1.3281 + } 1.3282 + 1.3283 + while ((vhost = TAILQ_FIRST(&http->virtualhosts)) != NULL) { 1.3284 + TAILQ_REMOVE(&http->virtualhosts, vhost, next_vhost); 1.3285 + 1.3286 + evhttp_free(vhost); 1.3287 + } 1.3288 + 1.3289 + if (http->vhost_pattern != NULL) 1.3290 + mm_free(http->vhost_pattern); 1.3291 + 1.3292 + while ((alias = TAILQ_FIRST(&http->aliases)) != NULL) { 1.3293 + TAILQ_REMOVE(&http->aliases, alias, next); 1.3294 + mm_free(alias->alias); 1.3295 + mm_free(alias); 1.3296 + } 1.3297 + 1.3298 + mm_free(http); 1.3299 +} 1.3300 + 1.3301 +int 1.3302 +evhttp_add_virtual_host(struct evhttp* http, const char *pattern, 1.3303 + struct evhttp* vhost) 1.3304 +{ 1.3305 + /* a vhost can only be a vhost once and should not have bound sockets */ 1.3306 + if (vhost->vhost_pattern != NULL || 1.3307 + TAILQ_FIRST(&vhost->sockets) != NULL) 1.3308 + return (-1); 1.3309 + 1.3310 + vhost->vhost_pattern = mm_strdup(pattern); 1.3311 + if (vhost->vhost_pattern == NULL) 1.3312 + return (-1); 1.3313 + 1.3314 + TAILQ_INSERT_TAIL(&http->virtualhosts, vhost, next_vhost); 1.3315 + 1.3316 + return (0); 1.3317 +} 1.3318 + 1.3319 +int 1.3320 +evhttp_remove_virtual_host(struct evhttp* http, struct evhttp* vhost) 1.3321 +{ 1.3322 + if (vhost->vhost_pattern == NULL) 1.3323 + return (-1); 1.3324 + 1.3325 + TAILQ_REMOVE(&http->virtualhosts, vhost, next_vhost); 1.3326 + 1.3327 + mm_free(vhost->vhost_pattern); 1.3328 + vhost->vhost_pattern = NULL; 1.3329 + 1.3330 + return (0); 1.3331 +} 1.3332 + 1.3333 +int 1.3334 +evhttp_add_server_alias(struct evhttp *http, const char *alias) 1.3335 +{ 1.3336 + struct evhttp_server_alias *evalias; 1.3337 + 1.3338 + evalias = mm_calloc(1, sizeof(*evalias)); 1.3339 + if (!evalias) 1.3340 + return -1; 1.3341 + 1.3342 + evalias->alias = mm_strdup(alias); 1.3343 + if (!evalias->alias) { 1.3344 + mm_free(evalias); 1.3345 + return -1; 1.3346 + } 1.3347 + 1.3348 + TAILQ_INSERT_TAIL(&http->aliases, evalias, next); 1.3349 + 1.3350 + return 0; 1.3351 +} 1.3352 + 1.3353 +int 1.3354 +evhttp_remove_server_alias(struct evhttp *http, const char *alias) 1.3355 +{ 1.3356 + struct evhttp_server_alias *evalias; 1.3357 + 1.3358 + TAILQ_FOREACH(evalias, &http->aliases, next) { 1.3359 + if (evutil_ascii_strcasecmp(evalias->alias, alias) == 0) { 1.3360 + TAILQ_REMOVE(&http->aliases, evalias, next); 1.3361 + mm_free(evalias->alias); 1.3362 + mm_free(evalias); 1.3363 + return 0; 1.3364 + } 1.3365 + } 1.3366 + 1.3367 + return -1; 1.3368 +} 1.3369 + 1.3370 +void 1.3371 +evhttp_set_timeout(struct evhttp* http, int timeout_in_secs) 1.3372 +{ 1.3373 + http->timeout = timeout_in_secs; 1.3374 +} 1.3375 + 1.3376 +void 1.3377 +evhttp_set_max_headers_size(struct evhttp* http, ev_ssize_t max_headers_size) 1.3378 +{ 1.3379 + if (max_headers_size < 0) 1.3380 + http->default_max_headers_size = EV_SIZE_MAX; 1.3381 + else 1.3382 + http->default_max_headers_size = max_headers_size; 1.3383 +} 1.3384 + 1.3385 +void 1.3386 +evhttp_set_max_body_size(struct evhttp* http, ev_ssize_t max_body_size) 1.3387 +{ 1.3388 + if (max_body_size < 0) 1.3389 + http->default_max_body_size = EV_UINT64_MAX; 1.3390 + else 1.3391 + http->default_max_body_size = max_body_size; 1.3392 +} 1.3393 + 1.3394 +void 1.3395 +evhttp_set_allowed_methods(struct evhttp* http, ev_uint16_t methods) 1.3396 +{ 1.3397 + http->allowed_methods = methods; 1.3398 +} 1.3399 + 1.3400 +int 1.3401 +evhttp_set_cb(struct evhttp *http, const char *uri, 1.3402 + void (*cb)(struct evhttp_request *, void *), void *cbarg) 1.3403 +{ 1.3404 + struct evhttp_cb *http_cb; 1.3405 + 1.3406 + TAILQ_FOREACH(http_cb, &http->callbacks, next) { 1.3407 + if (strcmp(http_cb->what, uri) == 0) 1.3408 + return (-1); 1.3409 + } 1.3410 + 1.3411 + if ((http_cb = mm_calloc(1, sizeof(struct evhttp_cb))) == NULL) { 1.3412 + event_warn("%s: calloc", __func__); 1.3413 + return (-2); 1.3414 + } 1.3415 + 1.3416 + http_cb->what = mm_strdup(uri); 1.3417 + if (http_cb->what == NULL) { 1.3418 + event_warn("%s: strdup", __func__); 1.3419 + mm_free(http_cb); 1.3420 + return (-3); 1.3421 + } 1.3422 + http_cb->cb = cb; 1.3423 + http_cb->cbarg = cbarg; 1.3424 + 1.3425 + TAILQ_INSERT_TAIL(&http->callbacks, http_cb, next); 1.3426 + 1.3427 + return (0); 1.3428 +} 1.3429 + 1.3430 +int 1.3431 +evhttp_del_cb(struct evhttp *http, const char *uri) 1.3432 +{ 1.3433 + struct evhttp_cb *http_cb; 1.3434 + 1.3435 + TAILQ_FOREACH(http_cb, &http->callbacks, next) { 1.3436 + if (strcmp(http_cb->what, uri) == 0) 1.3437 + break; 1.3438 + } 1.3439 + if (http_cb == NULL) 1.3440 + return (-1); 1.3441 + 1.3442 + TAILQ_REMOVE(&http->callbacks, http_cb, next); 1.3443 + mm_free(http_cb->what); 1.3444 + mm_free(http_cb); 1.3445 + 1.3446 + return (0); 1.3447 +} 1.3448 + 1.3449 +void 1.3450 +evhttp_set_gencb(struct evhttp *http, 1.3451 + void (*cb)(struct evhttp_request *, void *), void *cbarg) 1.3452 +{ 1.3453 + http->gencb = cb; 1.3454 + http->gencbarg = cbarg; 1.3455 +} 1.3456 + 1.3457 +/* 1.3458 + * Request related functions 1.3459 + */ 1.3460 + 1.3461 +struct evhttp_request * 1.3462 +evhttp_request_new(void (*cb)(struct evhttp_request *, void *), void *arg) 1.3463 +{ 1.3464 + struct evhttp_request *req = NULL; 1.3465 + 1.3466 + /* Allocate request structure */ 1.3467 + if ((req = mm_calloc(1, sizeof(struct evhttp_request))) == NULL) { 1.3468 + event_warn("%s: calloc", __func__); 1.3469 + goto error; 1.3470 + } 1.3471 + 1.3472 + req->headers_size = 0; 1.3473 + req->body_size = 0; 1.3474 + 1.3475 + req->kind = EVHTTP_RESPONSE; 1.3476 + req->input_headers = mm_calloc(1, sizeof(struct evkeyvalq)); 1.3477 + if (req->input_headers == NULL) { 1.3478 + event_warn("%s: calloc", __func__); 1.3479 + goto error; 1.3480 + } 1.3481 + TAILQ_INIT(req->input_headers); 1.3482 + 1.3483 + req->output_headers = mm_calloc(1, sizeof(struct evkeyvalq)); 1.3484 + if (req->output_headers == NULL) { 1.3485 + event_warn("%s: calloc", __func__); 1.3486 + goto error; 1.3487 + } 1.3488 + TAILQ_INIT(req->output_headers); 1.3489 + 1.3490 + if ((req->input_buffer = evbuffer_new()) == NULL) { 1.3491 + event_warn("%s: evbuffer_new", __func__); 1.3492 + goto error; 1.3493 + } 1.3494 + 1.3495 + if ((req->output_buffer = evbuffer_new()) == NULL) { 1.3496 + event_warn("%s: evbuffer_new", __func__); 1.3497 + goto error; 1.3498 + } 1.3499 + 1.3500 + req->cb = cb; 1.3501 + req->cb_arg = arg; 1.3502 + 1.3503 + return (req); 1.3504 + 1.3505 + error: 1.3506 + if (req != NULL) 1.3507 + evhttp_request_free(req); 1.3508 + return (NULL); 1.3509 +} 1.3510 + 1.3511 +void 1.3512 +evhttp_request_free(struct evhttp_request *req) 1.3513 +{ 1.3514 + if ((req->flags & EVHTTP_REQ_DEFER_FREE) != 0) { 1.3515 + req->flags |= EVHTTP_REQ_NEEDS_FREE; 1.3516 + return; 1.3517 + } 1.3518 + 1.3519 + if (req->remote_host != NULL) 1.3520 + mm_free(req->remote_host); 1.3521 + if (req->uri != NULL) 1.3522 + mm_free(req->uri); 1.3523 + if (req->uri_elems != NULL) 1.3524 + evhttp_uri_free(req->uri_elems); 1.3525 + if (req->response_code_line != NULL) 1.3526 + mm_free(req->response_code_line); 1.3527 + if (req->host_cache != NULL) 1.3528 + mm_free(req->host_cache); 1.3529 + 1.3530 + evhttp_clear_headers(req->input_headers); 1.3531 + mm_free(req->input_headers); 1.3532 + 1.3533 + evhttp_clear_headers(req->output_headers); 1.3534 + mm_free(req->output_headers); 1.3535 + 1.3536 + if (req->input_buffer != NULL) 1.3537 + evbuffer_free(req->input_buffer); 1.3538 + 1.3539 + if (req->output_buffer != NULL) 1.3540 + evbuffer_free(req->output_buffer); 1.3541 + 1.3542 + mm_free(req); 1.3543 +} 1.3544 + 1.3545 +void 1.3546 +evhttp_request_own(struct evhttp_request *req) 1.3547 +{ 1.3548 + req->flags |= EVHTTP_USER_OWNED; 1.3549 +} 1.3550 + 1.3551 +int 1.3552 +evhttp_request_is_owned(struct evhttp_request *req) 1.3553 +{ 1.3554 + return (req->flags & EVHTTP_USER_OWNED) != 0; 1.3555 +} 1.3556 + 1.3557 +struct evhttp_connection * 1.3558 +evhttp_request_get_connection(struct evhttp_request *req) 1.3559 +{ 1.3560 + return req->evcon; 1.3561 +} 1.3562 + 1.3563 +struct event_base * 1.3564 +evhttp_connection_get_base(struct evhttp_connection *conn) 1.3565 +{ 1.3566 + return conn->base; 1.3567 +} 1.3568 + 1.3569 +void 1.3570 +evhttp_request_set_chunked_cb(struct evhttp_request *req, 1.3571 + void (*cb)(struct evhttp_request *, void *)) 1.3572 +{ 1.3573 + req->chunk_cb = cb; 1.3574 +} 1.3575 + 1.3576 +/* 1.3577 + * Allows for inspection of the request URI 1.3578 + */ 1.3579 + 1.3580 +const char * 1.3581 +evhttp_request_get_uri(const struct evhttp_request *req) { 1.3582 + if (req->uri == NULL) 1.3583 + event_debug(("%s: request %p has no uri\n", __func__, req)); 1.3584 + return (req->uri); 1.3585 +} 1.3586 + 1.3587 +const struct evhttp_uri * 1.3588 +evhttp_request_get_evhttp_uri(const struct evhttp_request *req) { 1.3589 + if (req->uri_elems == NULL) 1.3590 + event_debug(("%s: request %p has no uri elems\n", 1.3591 + __func__, req)); 1.3592 + return (req->uri_elems); 1.3593 +} 1.3594 + 1.3595 +const char * 1.3596 +evhttp_request_get_host(struct evhttp_request *req) 1.3597 +{ 1.3598 + const char *host = NULL; 1.3599 + 1.3600 + if (req->host_cache) 1.3601 + return req->host_cache; 1.3602 + 1.3603 + if (req->uri_elems) 1.3604 + host = evhttp_uri_get_host(req->uri_elems); 1.3605 + if (!host && req->input_headers) { 1.3606 + const char *p; 1.3607 + size_t len; 1.3608 + 1.3609 + host = evhttp_find_header(req->input_headers, "Host"); 1.3610 + /* The Host: header may include a port. Remove it here 1.3611 + to be consistent with uri_elems case above. */ 1.3612 + if (host) { 1.3613 + p = host + strlen(host) - 1; 1.3614 + while (p > host && EVUTIL_ISDIGIT(*p)) 1.3615 + --p; 1.3616 + if (p > host && *p == ':') { 1.3617 + len = p - host; 1.3618 + req->host_cache = mm_malloc(len + 1); 1.3619 + if (!req->host_cache) { 1.3620 + event_warn("%s: malloc", __func__); 1.3621 + return NULL; 1.3622 + } 1.3623 + memcpy(req->host_cache, host, len); 1.3624 + req->host_cache[len] = '\0'; 1.3625 + host = req->host_cache; 1.3626 + } 1.3627 + } 1.3628 + } 1.3629 + 1.3630 + return host; 1.3631 +} 1.3632 + 1.3633 +enum evhttp_cmd_type 1.3634 +evhttp_request_get_command(const struct evhttp_request *req) { 1.3635 + return (req->type); 1.3636 +} 1.3637 + 1.3638 +int 1.3639 +evhttp_request_get_response_code(const struct evhttp_request *req) 1.3640 +{ 1.3641 + return req->response_code; 1.3642 +} 1.3643 + 1.3644 +/** Returns the input headers */ 1.3645 +struct evkeyvalq *evhttp_request_get_input_headers(struct evhttp_request *req) 1.3646 +{ 1.3647 + return (req->input_headers); 1.3648 +} 1.3649 + 1.3650 +/** Returns the output headers */ 1.3651 +struct evkeyvalq *evhttp_request_get_output_headers(struct evhttp_request *req) 1.3652 +{ 1.3653 + return (req->output_headers); 1.3654 +} 1.3655 + 1.3656 +/** Returns the input buffer */ 1.3657 +struct evbuffer *evhttp_request_get_input_buffer(struct evhttp_request *req) 1.3658 +{ 1.3659 + return (req->input_buffer); 1.3660 +} 1.3661 + 1.3662 +/** Returns the output buffer */ 1.3663 +struct evbuffer *evhttp_request_get_output_buffer(struct evhttp_request *req) 1.3664 +{ 1.3665 + return (req->output_buffer); 1.3666 +} 1.3667 + 1.3668 + 1.3669 +/* 1.3670 + * Takes a file descriptor to read a request from. 1.3671 + * The callback is executed once the whole request has been read. 1.3672 + */ 1.3673 + 1.3674 +static struct evhttp_connection* 1.3675 +evhttp_get_request_connection( 1.3676 + struct evhttp* http, 1.3677 + evutil_socket_t fd, struct sockaddr *sa, ev_socklen_t salen) 1.3678 +{ 1.3679 + struct evhttp_connection *evcon; 1.3680 + char *hostname = NULL, *portname = NULL; 1.3681 + 1.3682 + name_from_addr(sa, salen, &hostname, &portname); 1.3683 + if (hostname == NULL || portname == NULL) { 1.3684 + if (hostname) mm_free(hostname); 1.3685 + if (portname) mm_free(portname); 1.3686 + return (NULL); 1.3687 + } 1.3688 + 1.3689 + event_debug(("%s: new request from %s:%s on "EV_SOCK_FMT"\n", 1.3690 + __func__, hostname, portname, EV_SOCK_ARG(fd))); 1.3691 + 1.3692 + /* we need a connection object to put the http request on */ 1.3693 + evcon = evhttp_connection_base_new( 1.3694 + http->base, NULL, hostname, atoi(portname)); 1.3695 + mm_free(hostname); 1.3696 + mm_free(portname); 1.3697 + if (evcon == NULL) 1.3698 + return (NULL); 1.3699 + 1.3700 + evcon->max_headers_size = http->default_max_headers_size; 1.3701 + evcon->max_body_size = http->default_max_body_size; 1.3702 + 1.3703 + evcon->flags |= EVHTTP_CON_INCOMING; 1.3704 + evcon->state = EVCON_READING_FIRSTLINE; 1.3705 + 1.3706 + evcon->fd = fd; 1.3707 + 1.3708 + bufferevent_setfd(evcon->bufev, fd); 1.3709 + 1.3710 + return (evcon); 1.3711 +} 1.3712 + 1.3713 +static int 1.3714 +evhttp_associate_new_request_with_connection(struct evhttp_connection *evcon) 1.3715 +{ 1.3716 + struct evhttp *http = evcon->http_server; 1.3717 + struct evhttp_request *req; 1.3718 + if ((req = evhttp_request_new(evhttp_handle_request, http)) == NULL) 1.3719 + return (-1); 1.3720 + 1.3721 + if ((req->remote_host = mm_strdup(evcon->address)) == NULL) { 1.3722 + event_warn("%s: strdup", __func__); 1.3723 + evhttp_request_free(req); 1.3724 + return (-1); 1.3725 + } 1.3726 + req->remote_port = evcon->port; 1.3727 + 1.3728 + req->evcon = evcon; /* the request ends up owning the connection */ 1.3729 + req->flags |= EVHTTP_REQ_OWN_CONNECTION; 1.3730 + 1.3731 + /* We did not present the request to the user user yet, so treat it as 1.3732 + * if the user was done with the request. This allows us to free the 1.3733 + * request on a persistent connection if the client drops it without 1.3734 + * sending a request. 1.3735 + */ 1.3736 + req->userdone = 1; 1.3737 + 1.3738 + TAILQ_INSERT_TAIL(&evcon->requests, req, next); 1.3739 + 1.3740 + req->kind = EVHTTP_REQUEST; 1.3741 + 1.3742 + 1.3743 + evhttp_start_read(evcon); 1.3744 + 1.3745 + return (0); 1.3746 +} 1.3747 + 1.3748 +static void 1.3749 +evhttp_get_request(struct evhttp *http, evutil_socket_t fd, 1.3750 + struct sockaddr *sa, ev_socklen_t salen) 1.3751 +{ 1.3752 + struct evhttp_connection *evcon; 1.3753 + 1.3754 + evcon = evhttp_get_request_connection(http, fd, sa, salen); 1.3755 + if (evcon == NULL) { 1.3756 + event_sock_warn(fd, "%s: cannot get connection on "EV_SOCK_FMT, 1.3757 + __func__, EV_SOCK_ARG(fd)); 1.3758 + evutil_closesocket(fd); 1.3759 + return; 1.3760 + } 1.3761 + 1.3762 + /* the timeout can be used by the server to close idle connections */ 1.3763 + if (http->timeout != -1) 1.3764 + evhttp_connection_set_timeout(evcon, http->timeout); 1.3765 + 1.3766 + /* 1.3767 + * if we want to accept more than one request on a connection, 1.3768 + * we need to know which http server it belongs to. 1.3769 + */ 1.3770 + evcon->http_server = http; 1.3771 + TAILQ_INSERT_TAIL(&http->connections, evcon, next); 1.3772 + 1.3773 + if (evhttp_associate_new_request_with_connection(evcon) == -1) 1.3774 + evhttp_connection_free(evcon); 1.3775 +} 1.3776 + 1.3777 + 1.3778 +/* 1.3779 + * Network helper functions that we do not want to export to the rest of 1.3780 + * the world. 1.3781 + */ 1.3782 + 1.3783 +static void 1.3784 +name_from_addr(struct sockaddr *sa, ev_socklen_t salen, 1.3785 + char **phost, char **pport) 1.3786 +{ 1.3787 + char ntop[NI_MAXHOST]; 1.3788 + char strport[NI_MAXSERV]; 1.3789 + int ni_result; 1.3790 + 1.3791 +#ifdef _EVENT_HAVE_GETNAMEINFO 1.3792 + ni_result = getnameinfo(sa, salen, 1.3793 + ntop, sizeof(ntop), strport, sizeof(strport), 1.3794 + NI_NUMERICHOST|NI_NUMERICSERV); 1.3795 + 1.3796 + if (ni_result != 0) { 1.3797 +#ifdef EAI_SYSTEM 1.3798 + /* Windows doesn't have an EAI_SYSTEM. */ 1.3799 + if (ni_result == EAI_SYSTEM) 1.3800 + event_err(1, "getnameinfo failed"); 1.3801 + else 1.3802 +#endif 1.3803 + event_errx(1, "getnameinfo failed: %s", gai_strerror(ni_result)); 1.3804 + return; 1.3805 + } 1.3806 +#else 1.3807 + ni_result = fake_getnameinfo(sa, salen, 1.3808 + ntop, sizeof(ntop), strport, sizeof(strport), 1.3809 + NI_NUMERICHOST|NI_NUMERICSERV); 1.3810 + if (ni_result != 0) 1.3811 + return; 1.3812 +#endif 1.3813 + 1.3814 + *phost = mm_strdup(ntop); 1.3815 + *pport = mm_strdup(strport); 1.3816 +} 1.3817 + 1.3818 +/* Create a non-blocking socket and bind it */ 1.3819 +/* todo: rename this function */ 1.3820 +static evutil_socket_t 1.3821 +bind_socket_ai(struct evutil_addrinfo *ai, int reuse) 1.3822 +{ 1.3823 + evutil_socket_t fd; 1.3824 + 1.3825 + int on = 1, r; 1.3826 + int serrno; 1.3827 + 1.3828 + /* Create listen socket */ 1.3829 + fd = socket(ai ? ai->ai_family : AF_INET, SOCK_STREAM, 0); 1.3830 + if (fd == -1) { 1.3831 + event_sock_warn(-1, "socket"); 1.3832 + return (-1); 1.3833 + } 1.3834 + 1.3835 + if (evutil_make_socket_nonblocking(fd) < 0) 1.3836 + goto out; 1.3837 + if (evutil_make_socket_closeonexec(fd) < 0) 1.3838 + goto out; 1.3839 + 1.3840 + if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (void *)&on, sizeof(on))<0) 1.3841 + goto out; 1.3842 + if (reuse) { 1.3843 + if (evutil_make_listen_socket_reuseable(fd) < 0) 1.3844 + goto out; 1.3845 + } 1.3846 + 1.3847 + if (ai != NULL) { 1.3848 + r = bind(fd, ai->ai_addr, (ev_socklen_t)ai->ai_addrlen); 1.3849 + if (r == -1) 1.3850 + goto out; 1.3851 + } 1.3852 + 1.3853 + return (fd); 1.3854 + 1.3855 + out: 1.3856 + serrno = EVUTIL_SOCKET_ERROR(); 1.3857 + evutil_closesocket(fd); 1.3858 + EVUTIL_SET_SOCKET_ERROR(serrno); 1.3859 + return (-1); 1.3860 +} 1.3861 + 1.3862 +static struct evutil_addrinfo * 1.3863 +make_addrinfo(const char *address, ev_uint16_t port) 1.3864 +{ 1.3865 + struct evutil_addrinfo *ai = NULL; 1.3866 + 1.3867 + struct evutil_addrinfo hints; 1.3868 + char strport[NI_MAXSERV]; 1.3869 + int ai_result; 1.3870 + 1.3871 + memset(&hints, 0, sizeof(hints)); 1.3872 + hints.ai_family = AF_UNSPEC; 1.3873 + hints.ai_socktype = SOCK_STREAM; 1.3874 + /* turn NULL hostname into INADDR_ANY, and skip looking up any address 1.3875 + * types we don't have an interface to connect to. */ 1.3876 + hints.ai_flags = EVUTIL_AI_PASSIVE|EVUTIL_AI_ADDRCONFIG; 1.3877 + evutil_snprintf(strport, sizeof(strport), "%d", port); 1.3878 + if ((ai_result = evutil_getaddrinfo(address, strport, &hints, &ai)) 1.3879 + != 0) { 1.3880 + if (ai_result == EVUTIL_EAI_SYSTEM) 1.3881 + event_warn("getaddrinfo"); 1.3882 + else 1.3883 + event_warnx("getaddrinfo: %s", 1.3884 + evutil_gai_strerror(ai_result)); 1.3885 + return (NULL); 1.3886 + } 1.3887 + 1.3888 + return (ai); 1.3889 +} 1.3890 + 1.3891 +static evutil_socket_t 1.3892 +bind_socket(const char *address, ev_uint16_t port, int reuse) 1.3893 +{ 1.3894 + evutil_socket_t fd; 1.3895 + struct evutil_addrinfo *aitop = NULL; 1.3896 + 1.3897 + /* just create an unbound socket */ 1.3898 + if (address == NULL && port == 0) 1.3899 + return bind_socket_ai(NULL, 0); 1.3900 + 1.3901 + aitop = make_addrinfo(address, port); 1.3902 + 1.3903 + if (aitop == NULL) 1.3904 + return (-1); 1.3905 + 1.3906 + fd = bind_socket_ai(aitop, reuse); 1.3907 + 1.3908 + evutil_freeaddrinfo(aitop); 1.3909 + 1.3910 + return (fd); 1.3911 +} 1.3912 + 1.3913 +struct evhttp_uri { 1.3914 + unsigned flags; 1.3915 + char *scheme; /* scheme; e.g http, ftp etc */ 1.3916 + char *userinfo; /* userinfo (typically username:pass), or NULL */ 1.3917 + char *host; /* hostname, IP address, or NULL */ 1.3918 + int port; /* port, or zero */ 1.3919 + char *path; /* path, or "". */ 1.3920 + char *query; /* query, or NULL */ 1.3921 + char *fragment; /* fragment or NULL */ 1.3922 +}; 1.3923 + 1.3924 +struct evhttp_uri * 1.3925 +evhttp_uri_new(void) 1.3926 +{ 1.3927 + struct evhttp_uri *uri = mm_calloc(sizeof(struct evhttp_uri), 1); 1.3928 + if (uri) 1.3929 + uri->port = -1; 1.3930 + return uri; 1.3931 +} 1.3932 + 1.3933 +void 1.3934 +evhttp_uri_set_flags(struct evhttp_uri *uri, unsigned flags) 1.3935 +{ 1.3936 + uri->flags = flags; 1.3937 +} 1.3938 + 1.3939 +/* Return true if the string starting at s and ending immediately before eos 1.3940 + * is a valid URI scheme according to RFC3986 1.3941 + */ 1.3942 +static int 1.3943 +scheme_ok(const char *s, const char *eos) 1.3944 +{ 1.3945 + /* scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." ) */ 1.3946 + EVUTIL_ASSERT(eos >= s); 1.3947 + if (s == eos) 1.3948 + return 0; 1.3949 + if (!EVUTIL_ISALPHA(*s)) 1.3950 + return 0; 1.3951 + while (++s < eos) { 1.3952 + if (! EVUTIL_ISALNUM(*s) && 1.3953 + *s != '+' && *s != '-' && *s != '.') 1.3954 + return 0; 1.3955 + } 1.3956 + return 1; 1.3957 +} 1.3958 + 1.3959 +#define SUBDELIMS "!$&'()*+,;=" 1.3960 + 1.3961 +/* Return true iff [s..eos) is a valid userinfo */ 1.3962 +static int 1.3963 +userinfo_ok(const char *s, const char *eos) 1.3964 +{ 1.3965 + while (s < eos) { 1.3966 + if (CHAR_IS_UNRESERVED(*s) || 1.3967 + strchr(SUBDELIMS, *s) || 1.3968 + *s == ':') 1.3969 + ++s; 1.3970 + else if (*s == '%' && s+2 < eos && 1.3971 + EVUTIL_ISXDIGIT(s[1]) && 1.3972 + EVUTIL_ISXDIGIT(s[2])) 1.3973 + s += 3; 1.3974 + else 1.3975 + return 0; 1.3976 + } 1.3977 + return 1; 1.3978 +} 1.3979 + 1.3980 +static int 1.3981 +regname_ok(const char *s, const char *eos) 1.3982 +{ 1.3983 + while (s && s<eos) { 1.3984 + if (CHAR_IS_UNRESERVED(*s) || 1.3985 + strchr(SUBDELIMS, *s)) 1.3986 + ++s; 1.3987 + else if (*s == '%' && 1.3988 + EVUTIL_ISXDIGIT(s[1]) && 1.3989 + EVUTIL_ISXDIGIT(s[2])) 1.3990 + s += 3; 1.3991 + else 1.3992 + return 0; 1.3993 + } 1.3994 + return 1; 1.3995 +} 1.3996 + 1.3997 +static int 1.3998 +parse_port(const char *s, const char *eos) 1.3999 +{ 1.4000 + int portnum = 0; 1.4001 + while (s < eos) { 1.4002 + if (! EVUTIL_ISDIGIT(*s)) 1.4003 + return -1; 1.4004 + portnum = (portnum * 10) + (*s - '0'); 1.4005 + if (portnum < 0) 1.4006 + return -1; 1.4007 + ++s; 1.4008 + } 1.4009 + return portnum; 1.4010 +} 1.4011 + 1.4012 +/* returns 0 for bad, 1 for ipv6, 2 for IPvFuture */ 1.4013 +static int 1.4014 +bracket_addr_ok(const char *s, const char *eos) 1.4015 +{ 1.4016 + if (s + 3 > eos || *s != '[' || *(eos-1) != ']') 1.4017 + return 0; 1.4018 + if (s[1] == 'v') { 1.4019 + /* IPvFuture, or junk. 1.4020 + "v" 1*HEXDIG "." 1*( unreserved / sub-delims / ":" ) 1.4021 + */ 1.4022 + s += 2; /* skip [v */ 1.4023 + --eos; 1.4024 + if (!EVUTIL_ISXDIGIT(*s)) /*require at least one*/ 1.4025 + return 0; 1.4026 + while (s < eos && *s != '.') { 1.4027 + if (EVUTIL_ISXDIGIT(*s)) 1.4028 + ++s; 1.4029 + else 1.4030 + return 0; 1.4031 + } 1.4032 + if (*s != '.') 1.4033 + return 0; 1.4034 + ++s; 1.4035 + while (s < eos) { 1.4036 + if (CHAR_IS_UNRESERVED(*s) || 1.4037 + strchr(SUBDELIMS, *s) || 1.4038 + *s == ':') 1.4039 + ++s; 1.4040 + else 1.4041 + return 0; 1.4042 + } 1.4043 + return 2; 1.4044 + } else { 1.4045 + /* IPv6, or junk */ 1.4046 + char buf[64]; 1.4047 + ev_ssize_t n_chars = eos-s-2; 1.4048 + struct in6_addr in6; 1.4049 + if (n_chars >= 64) /* way too long */ 1.4050 + return 0; 1.4051 + memcpy(buf, s+1, n_chars); 1.4052 + buf[n_chars]='\0'; 1.4053 + return (evutil_inet_pton(AF_INET6,buf,&in6)==1) ? 1 : 0; 1.4054 + } 1.4055 +} 1.4056 + 1.4057 +static int 1.4058 +parse_authority(struct evhttp_uri *uri, char *s, char *eos) 1.4059 +{ 1.4060 + char *cp, *port; 1.4061 + EVUTIL_ASSERT(eos); 1.4062 + if (eos == s) { 1.4063 + uri->host = mm_strdup(""); 1.4064 + if (uri->host == NULL) { 1.4065 + event_warn("%s: strdup", __func__); 1.4066 + return -1; 1.4067 + } 1.4068 + return 0; 1.4069 + } 1.4070 + 1.4071 + /* Optionally, we start with "userinfo@" */ 1.4072 + 1.4073 + cp = strchr(s, '@'); 1.4074 + if (cp && cp < eos) { 1.4075 + if (! userinfo_ok(s,cp)) 1.4076 + return -1; 1.4077 + *cp++ = '\0'; 1.4078 + uri->userinfo = mm_strdup(s); 1.4079 + if (uri->userinfo == NULL) { 1.4080 + event_warn("%s: strdup", __func__); 1.4081 + return -1; 1.4082 + } 1.4083 + } else { 1.4084 + cp = s; 1.4085 + } 1.4086 + /* Optionally, we end with ":port" */ 1.4087 + for (port=eos-1; port >= cp && EVUTIL_ISDIGIT(*port); --port) 1.4088 + ; 1.4089 + if (port >= cp && *port == ':') { 1.4090 + if (port+1 == eos) /* Leave port unspecified; the RFC allows a 1.4091 + * nil port */ 1.4092 + uri->port = -1; 1.4093 + else if ((uri->port = parse_port(port+1, eos))<0) 1.4094 + return -1; 1.4095 + eos = port; 1.4096 + } 1.4097 + /* Now, cp..eos holds the "host" port, which can be an IPv4Address, 1.4098 + * an IP-Literal, or a reg-name */ 1.4099 + EVUTIL_ASSERT(eos >= cp); 1.4100 + if (*cp == '[' && eos >= cp+2 && *(eos-1) == ']') { 1.4101 + /* IPv6address, IP-Literal, or junk. */ 1.4102 + if (! bracket_addr_ok(cp, eos)) 1.4103 + return -1; 1.4104 + } else { 1.4105 + /* Make sure the host part is ok. */ 1.4106 + if (! regname_ok(cp,eos)) /* Match IPv4Address or reg-name */ 1.4107 + return -1; 1.4108 + } 1.4109 + uri->host = mm_malloc(eos-cp+1); 1.4110 + if (uri->host == NULL) { 1.4111 + event_warn("%s: malloc", __func__); 1.4112 + return -1; 1.4113 + } 1.4114 + memcpy(uri->host, cp, eos-cp); 1.4115 + uri->host[eos-cp] = '\0'; 1.4116 + return 0; 1.4117 + 1.4118 +} 1.4119 + 1.4120 +static char * 1.4121 +end_of_authority(char *cp) 1.4122 +{ 1.4123 + while (*cp) { 1.4124 + if (*cp == '?' || *cp == '#' || *cp == '/') 1.4125 + return cp; 1.4126 + ++cp; 1.4127 + } 1.4128 + return cp; 1.4129 +} 1.4130 + 1.4131 +enum uri_part { 1.4132 + PART_PATH, 1.4133 + PART_QUERY, 1.4134 + PART_FRAGMENT 1.4135 +}; 1.4136 + 1.4137 +/* Return the character after the longest prefix of 'cp' that matches... 1.4138 + * *pchar / "/" if allow_qchars is false, or 1.4139 + * *(pchar / "/" / "?") if allow_qchars is true. 1.4140 + */ 1.4141 +static char * 1.4142 +end_of_path(char *cp, enum uri_part part, unsigned flags) 1.4143 +{ 1.4144 + if (flags & EVHTTP_URI_NONCONFORMANT) { 1.4145 + /* If NONCONFORMANT: 1.4146 + * Path is everything up to a # or ? or nul. 1.4147 + * Query is everything up a # or nul 1.4148 + * Fragment is everything up to a nul. 1.4149 + */ 1.4150 + switch (part) { 1.4151 + case PART_PATH: 1.4152 + while (*cp && *cp != '#' && *cp != '?') 1.4153 + ++cp; 1.4154 + break; 1.4155 + case PART_QUERY: 1.4156 + while (*cp && *cp != '#') 1.4157 + ++cp; 1.4158 + break; 1.4159 + case PART_FRAGMENT: 1.4160 + cp += strlen(cp); 1.4161 + break; 1.4162 + }; 1.4163 + return cp; 1.4164 + } 1.4165 + 1.4166 + while (*cp) { 1.4167 + if (CHAR_IS_UNRESERVED(*cp) || 1.4168 + strchr(SUBDELIMS, *cp) || 1.4169 + *cp == ':' || *cp == '@' || *cp == '/') 1.4170 + ++cp; 1.4171 + else if (*cp == '%' && EVUTIL_ISXDIGIT(cp[1]) && 1.4172 + EVUTIL_ISXDIGIT(cp[2])) 1.4173 + cp += 3; 1.4174 + else if (*cp == '?' && part != PART_PATH) 1.4175 + ++cp; 1.4176 + else 1.4177 + return cp; 1.4178 + } 1.4179 + return cp; 1.4180 +} 1.4181 + 1.4182 +static int 1.4183 +path_matches_noscheme(const char *cp) 1.4184 +{ 1.4185 + while (*cp) { 1.4186 + if (*cp == ':') 1.4187 + return 0; 1.4188 + else if (*cp == '/') 1.4189 + return 1; 1.4190 + ++cp; 1.4191 + } 1.4192 + return 1; 1.4193 +} 1.4194 + 1.4195 +struct evhttp_uri * 1.4196 +evhttp_uri_parse(const char *source_uri) 1.4197 +{ 1.4198 + return evhttp_uri_parse_with_flags(source_uri, 0); 1.4199 +} 1.4200 + 1.4201 +struct evhttp_uri * 1.4202 +evhttp_uri_parse_with_flags(const char *source_uri, unsigned flags) 1.4203 +{ 1.4204 + char *readbuf = NULL, *readp = NULL, *token = NULL, *query = NULL; 1.4205 + char *path = NULL, *fragment = NULL; 1.4206 + int got_authority = 0; 1.4207 + 1.4208 + struct evhttp_uri *uri = mm_calloc(1, sizeof(struct evhttp_uri)); 1.4209 + if (uri == NULL) { 1.4210 + event_warn("%s: calloc", __func__); 1.4211 + goto err; 1.4212 + } 1.4213 + uri->port = -1; 1.4214 + uri->flags = flags; 1.4215 + 1.4216 + readbuf = mm_strdup(source_uri); 1.4217 + if (readbuf == NULL) { 1.4218 + event_warn("%s: strdup", __func__); 1.4219 + goto err; 1.4220 + } 1.4221 + 1.4222 + readp = readbuf; 1.4223 + token = NULL; 1.4224 + 1.4225 + /* We try to follow RFC3986 here as much as we can, and match 1.4226 + the productions 1.4227 + 1.4228 + URI = scheme ":" hier-part [ "?" query ] [ "#" fragment ] 1.4229 + 1.4230 + relative-ref = relative-part [ "?" query ] [ "#" fragment ] 1.4231 + */ 1.4232 + 1.4233 + /* 1. scheme: */ 1.4234 + token = strchr(readp, ':'); 1.4235 + if (token && scheme_ok(readp,token)) { 1.4236 + *token = '\0'; 1.4237 + uri->scheme = mm_strdup(readp); 1.4238 + if (uri->scheme == NULL) { 1.4239 + event_warn("%s: strdup", __func__); 1.4240 + goto err; 1.4241 + } 1.4242 + readp = token+1; /* eat : */ 1.4243 + } 1.4244 + 1.4245 + /* 2. Optionally, "//" then an 'authority' part. */ 1.4246 + if (readp[0]=='/' && readp[1] == '/') { 1.4247 + char *authority; 1.4248 + readp += 2; 1.4249 + authority = readp; 1.4250 + path = end_of_authority(readp); 1.4251 + if (parse_authority(uri, authority, path) < 0) 1.4252 + goto err; 1.4253 + readp = path; 1.4254 + got_authority = 1; 1.4255 + } 1.4256 + 1.4257 + /* 3. Query: path-abempty, path-absolute, path-rootless, or path-empty 1.4258 + */ 1.4259 + path = readp; 1.4260 + readp = end_of_path(path, PART_PATH, flags); 1.4261 + 1.4262 + /* Query */ 1.4263 + if (*readp == '?') { 1.4264 + *readp = '\0'; 1.4265 + ++readp; 1.4266 + query = readp; 1.4267 + readp = end_of_path(readp, PART_QUERY, flags); 1.4268 + } 1.4269 + /* fragment */ 1.4270 + if (*readp == '#') { 1.4271 + *readp = '\0'; 1.4272 + ++readp; 1.4273 + fragment = readp; 1.4274 + readp = end_of_path(readp, PART_FRAGMENT, flags); 1.4275 + } 1.4276 + if (*readp != '\0') { 1.4277 + goto err; 1.4278 + } 1.4279 + 1.4280 + /* These next two cases may be unreachable; I'm leaving them 1.4281 + * in to be defensive. */ 1.4282 + /* If you didn't get an authority, the path can't begin with "//" */ 1.4283 + if (!got_authority && path[0]=='/' && path[1]=='/') 1.4284 + goto err; 1.4285 + /* If you did get an authority, the path must begin with "/" or be 1.4286 + * empty. */ 1.4287 + if (got_authority && path[0] != '/' && path[0] != '\0') 1.4288 + goto err; 1.4289 + /* (End of maybe-unreachable cases) */ 1.4290 + 1.4291 + /* If there was no scheme, the first part of the path (if any) must 1.4292 + * have no colon in it. */ 1.4293 + if (! uri->scheme && !path_matches_noscheme(path)) 1.4294 + goto err; 1.4295 + 1.4296 + EVUTIL_ASSERT(path); 1.4297 + uri->path = mm_strdup(path); 1.4298 + if (uri->path == NULL) { 1.4299 + event_warn("%s: strdup", __func__); 1.4300 + goto err; 1.4301 + } 1.4302 + 1.4303 + if (query) { 1.4304 + uri->query = mm_strdup(query); 1.4305 + if (uri->query == NULL) { 1.4306 + event_warn("%s: strdup", __func__); 1.4307 + goto err; 1.4308 + } 1.4309 + } 1.4310 + if (fragment) { 1.4311 + uri->fragment = mm_strdup(fragment); 1.4312 + if (uri->fragment == NULL) { 1.4313 + event_warn("%s: strdup", __func__); 1.4314 + goto err; 1.4315 + } 1.4316 + } 1.4317 + 1.4318 + mm_free(readbuf); 1.4319 + 1.4320 + return uri; 1.4321 +err: 1.4322 + if (uri) 1.4323 + evhttp_uri_free(uri); 1.4324 + if (readbuf) 1.4325 + mm_free(readbuf); 1.4326 + return NULL; 1.4327 +} 1.4328 + 1.4329 +void 1.4330 +evhttp_uri_free(struct evhttp_uri *uri) 1.4331 +{ 1.4332 +#define _URI_FREE_STR(f) \ 1.4333 + if (uri->f) { \ 1.4334 + mm_free(uri->f); \ 1.4335 + } 1.4336 + 1.4337 + _URI_FREE_STR(scheme); 1.4338 + _URI_FREE_STR(userinfo); 1.4339 + _URI_FREE_STR(host); 1.4340 + _URI_FREE_STR(path); 1.4341 + _URI_FREE_STR(query); 1.4342 + _URI_FREE_STR(fragment); 1.4343 + 1.4344 + mm_free(uri); 1.4345 +#undef _URI_FREE_STR 1.4346 +} 1.4347 + 1.4348 +char * 1.4349 +evhttp_uri_join(struct evhttp_uri *uri, char *buf, size_t limit) 1.4350 +{ 1.4351 + struct evbuffer *tmp = 0; 1.4352 + size_t joined_size = 0; 1.4353 + char *output = NULL; 1.4354 + 1.4355 +#define _URI_ADD(f) evbuffer_add(tmp, uri->f, strlen(uri->f)) 1.4356 + 1.4357 + if (!uri || !buf || !limit) 1.4358 + return NULL; 1.4359 + 1.4360 + tmp = evbuffer_new(); 1.4361 + if (!tmp) 1.4362 + return NULL; 1.4363 + 1.4364 + if (uri->scheme) { 1.4365 + _URI_ADD(scheme); 1.4366 + evbuffer_add(tmp, ":", 1); 1.4367 + } 1.4368 + if (uri->host) { 1.4369 + evbuffer_add(tmp, "//", 2); 1.4370 + if (uri->userinfo) 1.4371 + evbuffer_add_printf(tmp,"%s@", uri->userinfo); 1.4372 + _URI_ADD(host); 1.4373 + if (uri->port >= 0) 1.4374 + evbuffer_add_printf(tmp,":%d", uri->port); 1.4375 + 1.4376 + if (uri->path && uri->path[0] != '/' && uri->path[0] != '\0') 1.4377 + goto err; 1.4378 + } 1.4379 + 1.4380 + if (uri->path) 1.4381 + _URI_ADD(path); 1.4382 + 1.4383 + if (uri->query) { 1.4384 + evbuffer_add(tmp, "?", 1); 1.4385 + _URI_ADD(query); 1.4386 + } 1.4387 + 1.4388 + if (uri->fragment) { 1.4389 + evbuffer_add(tmp, "#", 1); 1.4390 + _URI_ADD(fragment); 1.4391 + } 1.4392 + 1.4393 + evbuffer_add(tmp, "\0", 1); /* NUL */ 1.4394 + 1.4395 + joined_size = evbuffer_get_length(tmp); 1.4396 + 1.4397 + if (joined_size > limit) { 1.4398 + /* It doesn't fit. */ 1.4399 + evbuffer_free(tmp); 1.4400 + return NULL; 1.4401 + } 1.4402 + evbuffer_remove(tmp, buf, joined_size); 1.4403 + 1.4404 + output = buf; 1.4405 +err: 1.4406 + evbuffer_free(tmp); 1.4407 + 1.4408 + return output; 1.4409 +#undef _URI_ADD 1.4410 +} 1.4411 + 1.4412 +const char * 1.4413 +evhttp_uri_get_scheme(const struct evhttp_uri *uri) 1.4414 +{ 1.4415 + return uri->scheme; 1.4416 +} 1.4417 +const char * 1.4418 +evhttp_uri_get_userinfo(const struct evhttp_uri *uri) 1.4419 +{ 1.4420 + return uri->userinfo; 1.4421 +} 1.4422 +const char * 1.4423 +evhttp_uri_get_host(const struct evhttp_uri *uri) 1.4424 +{ 1.4425 + return uri->host; 1.4426 +} 1.4427 +int 1.4428 +evhttp_uri_get_port(const struct evhttp_uri *uri) 1.4429 +{ 1.4430 + return uri->port; 1.4431 +} 1.4432 +const char * 1.4433 +evhttp_uri_get_path(const struct evhttp_uri *uri) 1.4434 +{ 1.4435 + return uri->path; 1.4436 +} 1.4437 +const char * 1.4438 +evhttp_uri_get_query(const struct evhttp_uri *uri) 1.4439 +{ 1.4440 + return uri->query; 1.4441 +} 1.4442 +const char * 1.4443 +evhttp_uri_get_fragment(const struct evhttp_uri *uri) 1.4444 +{ 1.4445 + return uri->fragment; 1.4446 +} 1.4447 + 1.4448 +#define _URI_SET_STR(f) do { \ 1.4449 + if (uri->f) \ 1.4450 + mm_free(uri->f); \ 1.4451 + if (f) { \ 1.4452 + if ((uri->f = mm_strdup(f)) == NULL) { \ 1.4453 + event_warn("%s: strdup()", __func__); \ 1.4454 + return -1; \ 1.4455 + } \ 1.4456 + } else { \ 1.4457 + uri->f = NULL; \ 1.4458 + } \ 1.4459 + } while(0) 1.4460 + 1.4461 +int 1.4462 +evhttp_uri_set_scheme(struct evhttp_uri *uri, const char *scheme) 1.4463 +{ 1.4464 + if (scheme && !scheme_ok(scheme, scheme+strlen(scheme))) 1.4465 + return -1; 1.4466 + 1.4467 + _URI_SET_STR(scheme); 1.4468 + return 0; 1.4469 +} 1.4470 +int 1.4471 +evhttp_uri_set_userinfo(struct evhttp_uri *uri, const char *userinfo) 1.4472 +{ 1.4473 + if (userinfo && !userinfo_ok(userinfo, userinfo+strlen(userinfo))) 1.4474 + return -1; 1.4475 + _URI_SET_STR(userinfo); 1.4476 + return 0; 1.4477 +} 1.4478 +int 1.4479 +evhttp_uri_set_host(struct evhttp_uri *uri, const char *host) 1.4480 +{ 1.4481 + if (host) { 1.4482 + if (host[0] == '[') { 1.4483 + if (! bracket_addr_ok(host, host+strlen(host))) 1.4484 + return -1; 1.4485 + } else { 1.4486 + if (! regname_ok(host, host+strlen(host))) 1.4487 + return -1; 1.4488 + } 1.4489 + } 1.4490 + 1.4491 + _URI_SET_STR(host); 1.4492 + return 0; 1.4493 +} 1.4494 +int 1.4495 +evhttp_uri_set_port(struct evhttp_uri *uri, int port) 1.4496 +{ 1.4497 + if (port < -1) 1.4498 + return -1; 1.4499 + uri->port = port; 1.4500 + return 0; 1.4501 +} 1.4502 +#define end_of_cpath(cp,p,f) \ 1.4503 + ((const char*)(end_of_path(((char*)(cp)), (p), (f)))) 1.4504 + 1.4505 +int 1.4506 +evhttp_uri_set_path(struct evhttp_uri *uri, const char *path) 1.4507 +{ 1.4508 + if (path && end_of_cpath(path, PART_PATH, uri->flags) != path+strlen(path)) 1.4509 + return -1; 1.4510 + 1.4511 + _URI_SET_STR(path); 1.4512 + return 0; 1.4513 +} 1.4514 +int 1.4515 +evhttp_uri_set_query(struct evhttp_uri *uri, const char *query) 1.4516 +{ 1.4517 + if (query && end_of_cpath(query, PART_QUERY, uri->flags) != query+strlen(query)) 1.4518 + return -1; 1.4519 + _URI_SET_STR(query); 1.4520 + return 0; 1.4521 +} 1.4522 +int 1.4523 +evhttp_uri_set_fragment(struct evhttp_uri *uri, const char *fragment) 1.4524 +{ 1.4525 + if (fragment && end_of_cpath(fragment, PART_FRAGMENT, uri->flags) != fragment+strlen(fragment)) 1.4526 + return -1; 1.4527 + _URI_SET_STR(fragment); 1.4528 + return 0; 1.4529 +}