ipc/chromium/src/third_party/libevent/http.c

changeset 0
6474c204b198
     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 = "&lt;";
   1.231 +		return 4;
   1.232 +	case '>':
   1.233 +		*escaped = "&gt;";
   1.234 +		return 4;
   1.235 +	case '"':
   1.236 +		*escaped = "&quot;";
   1.237 +		return 6;
   1.238 +	case '\'':
   1.239 +		*escaped = "&#039;";
   1.240 +		return 6;
   1.241 +	case '&':
   1.242 +		*escaped = "&amp;";
   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 &lt;, &gt;, &quot;,
   1.253 + * &#039; and &amp; 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 +}

mercurial