1290001Sglebius/* 2290001Sglebius * Copyright (c) 2002-2007 Niels Provos <provos@citi.umich.edu> 3290001Sglebius * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson 4290001Sglebius * 5290001Sglebius * Redistribution and use in source and binary forms, with or without 6290001Sglebius * modification, are permitted provided that the following conditions 7290001Sglebius * are met: 8290001Sglebius * 1. Redistributions of source code must retain the above copyright 9290001Sglebius * notice, this list of conditions and the following disclaimer. 10290001Sglebius * 2. Redistributions in binary form must reproduce the above copyright 11290001Sglebius * notice, this list of conditions and the following disclaimer in the 12290001Sglebius * documentation and/or other materials provided with the distribution. 13290001Sglebius * 3. The name of the author may not be used to endorse or promote products 14290001Sglebius * derived from this software without specific prior written permission. 15290001Sglebius * 16290001Sglebius * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17290001Sglebius * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18290001Sglebius * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19290001Sglebius * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20290001Sglebius * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21290001Sglebius * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22290001Sglebius * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23290001Sglebius * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24290001Sglebius * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25290001Sglebius * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26290001Sglebius */ 27290001Sglebius 28290001Sglebius#include "event2/event-config.h" 29290001Sglebius#include "evconfig-private.h" 30290001Sglebius 31290001Sglebius#ifdef EVENT__HAVE_SYS_PARAM_H 32290001Sglebius#include <sys/param.h> 33290001Sglebius#endif 34290001Sglebius#ifdef EVENT__HAVE_SYS_TYPES_H 35290001Sglebius#include <sys/types.h> 36290001Sglebius#endif 37290001Sglebius 38290001Sglebius#ifdef EVENT__HAVE_SYS_TIME_H 39290001Sglebius#include <sys/time.h> 40290001Sglebius#endif 41290001Sglebius#ifdef HAVE_SYS_IOCCOM_H 42290001Sglebius#include <sys/ioccom.h> 43290001Sglebius#endif 44290001Sglebius 45290001Sglebius#ifndef _WIN32 46290001Sglebius#include <sys/resource.h> 47290001Sglebius#include <sys/socket.h> 48290001Sglebius#include <sys/stat.h> 49290001Sglebius#include <sys/wait.h> 50290001Sglebius#else 51290001Sglebius#include <winsock2.h> 52290001Sglebius#include <ws2tcpip.h> 53290001Sglebius#endif 54290001Sglebius 55290001Sglebius#include <sys/queue.h> 56290001Sglebius 57290001Sglebius#ifdef EVENT__HAVE_NETINET_IN_H 58290001Sglebius#include <netinet/in.h> 59290001Sglebius#endif 60290001Sglebius#ifdef EVENT__HAVE_ARPA_INET_H 61290001Sglebius#include <arpa/inet.h> 62290001Sglebius#endif 63290001Sglebius#ifdef EVENT__HAVE_NETDB_H 64290001Sglebius#include <netdb.h> 65290001Sglebius#endif 66290001Sglebius 67290001Sglebius#ifdef _WIN32 68290001Sglebius#include <winsock2.h> 69290001Sglebius#endif 70290001Sglebius 71290001Sglebius#include <errno.h> 72290001Sglebius#include <stdio.h> 73290001Sglebius#include <stdlib.h> 74290001Sglebius#include <string.h> 75290001Sglebius#ifndef _WIN32 76290001Sglebius#include <syslog.h> 77290001Sglebius#endif 78290001Sglebius#include <signal.h> 79290001Sglebius#include <time.h> 80290001Sglebius#ifdef EVENT__HAVE_UNISTD_H 81290001Sglebius#include <unistd.h> 82290001Sglebius#endif 83290001Sglebius#ifdef EVENT__HAVE_FCNTL_H 84290001Sglebius#include <fcntl.h> 85290001Sglebius#endif 86290001Sglebius 87290001Sglebius#undef timeout_pending 88290001Sglebius#undef timeout_initialized 89290001Sglebius 90290001Sglebius#include "strlcpy-internal.h" 91290001Sglebius#include "event2/http.h" 92290001Sglebius#include "event2/event.h" 93290001Sglebius#include "event2/buffer.h" 94290001Sglebius#include "event2/bufferevent.h" 95290001Sglebius#include "event2/http_struct.h" 96290001Sglebius#include "event2/http_compat.h" 97290001Sglebius#include "event2/util.h" 98290001Sglebius#include "event2/listener.h" 99290001Sglebius#include "log-internal.h" 100290001Sglebius#include "util-internal.h" 101290001Sglebius#include "http-internal.h" 102290001Sglebius#include "mm-internal.h" 103290001Sglebius#include "bufferevent-internal.h" 104290001Sglebius 105290001Sglebius#ifndef EVENT__HAVE_GETNAMEINFO 106290001Sglebius#define NI_MAXSERV 32 107290001Sglebius#define NI_MAXHOST 1025 108290001Sglebius 109290001Sglebius#ifndef NI_NUMERICHOST 110290001Sglebius#define NI_NUMERICHOST 1 111290001Sglebius#endif 112290001Sglebius 113290001Sglebius#ifndef NI_NUMERICSERV 114290001Sglebius#define NI_NUMERICSERV 2 115290001Sglebius#endif 116290001Sglebius 117290001Sglebiusstatic int 118290001Sglebiusfake_getnameinfo(const struct sockaddr *sa, size_t salen, char *host, 119290001Sglebius size_t hostlen, char *serv, size_t servlen, int flags) 120290001Sglebius{ 121290001Sglebius struct sockaddr_in *sin = (struct sockaddr_in *)sa; 122290001Sglebius 123290001Sglebius if (serv != NULL) { 124290001Sglebius char tmpserv[16]; 125290001Sglebius evutil_snprintf(tmpserv, sizeof(tmpserv), 126290001Sglebius "%d", ntohs(sin->sin_port)); 127290001Sglebius if (strlcpy(serv, tmpserv, servlen) >= servlen) 128290001Sglebius return (-1); 129290001Sglebius } 130290001Sglebius 131290001Sglebius if (host != NULL) { 132290001Sglebius if (flags & NI_NUMERICHOST) { 133290001Sglebius if (strlcpy(host, inet_ntoa(sin->sin_addr), 134290001Sglebius hostlen) >= hostlen) 135290001Sglebius return (-1); 136290001Sglebius else 137290001Sglebius return (0); 138290001Sglebius } else { 139290001Sglebius struct hostent *hp; 140290001Sglebius hp = gethostbyaddr((char *)&sin->sin_addr, 141290001Sglebius sizeof(struct in_addr), AF_INET); 142290001Sglebius if (hp == NULL) 143290001Sglebius return (-2); 144290001Sglebius 145290001Sglebius if (strlcpy(host, hp->h_name, hostlen) >= hostlen) 146290001Sglebius return (-1); 147290001Sglebius else 148290001Sglebius return (0); 149290001Sglebius } 150290001Sglebius } 151290001Sglebius return (0); 152290001Sglebius} 153290001Sglebius 154290001Sglebius#endif 155290001Sglebius 156290001Sglebius#define REQ_VERSION_BEFORE(req, major_v, minor_v) \ 157290001Sglebius ((req)->major < (major_v) || \ 158290001Sglebius ((req)->major == (major_v) && (req)->minor < (minor_v))) 159290001Sglebius 160290001Sglebius#define REQ_VERSION_ATLEAST(req, major_v, minor_v) \ 161290001Sglebius ((req)->major > (major_v) || \ 162290001Sglebius ((req)->major == (major_v) && (req)->minor >= (minor_v))) 163290001Sglebius 164290001Sglebius#ifndef MIN 165290001Sglebius#define MIN(a,b) (((a)<(b))?(a):(b)) 166290001Sglebius#endif 167290001Sglebius 168290001Sglebiusextern int debug; 169290001Sglebius 170290001Sglebiusstatic evutil_socket_t bind_socket_ai(struct evutil_addrinfo *, int reuse); 171290001Sglebiusstatic evutil_socket_t bind_socket(const char *, ev_uint16_t, int reuse); 172290001Sglebiusstatic void name_from_addr(struct sockaddr *, ev_socklen_t, char **, char **); 173290001Sglebiusstatic int evhttp_associate_new_request_with_connection( 174290001Sglebius struct evhttp_connection *evcon); 175290001Sglebiusstatic void evhttp_connection_start_detectclose( 176290001Sglebius struct evhttp_connection *evcon); 177290001Sglebiusstatic void evhttp_connection_stop_detectclose( 178290001Sglebius struct evhttp_connection *evcon); 179290001Sglebiusstatic void evhttp_request_dispatch(struct evhttp_connection* evcon); 180290001Sglebiusstatic void evhttp_read_firstline(struct evhttp_connection *evcon, 181290001Sglebius struct evhttp_request *req); 182290001Sglebiusstatic void evhttp_read_header(struct evhttp_connection *evcon, 183290001Sglebius struct evhttp_request *req); 184290001Sglebiusstatic int evhttp_add_header_internal(struct evkeyvalq *headers, 185290001Sglebius const char *key, const char *value); 186290001Sglebiusstatic const char *evhttp_response_phrase_internal(int code); 187290001Sglebiusstatic void evhttp_get_request(struct evhttp *, evutil_socket_t, struct sockaddr *, ev_socklen_t); 188290001Sglebiusstatic void evhttp_write_buffer(struct evhttp_connection *, 189290001Sglebius void (*)(struct evhttp_connection *, void *), void *); 190290001Sglebiusstatic void evhttp_make_header(struct evhttp_connection *, struct evhttp_request *); 191290001Sglebius 192290001Sglebius/* callbacks for bufferevent */ 193290001Sglebiusstatic void evhttp_read_cb(struct bufferevent *, void *); 194290001Sglebiusstatic void evhttp_write_cb(struct bufferevent *, void *); 195290001Sglebiusstatic void evhttp_error_cb(struct bufferevent *bufev, short what, void *arg); 196290001Sglebiusstatic int evhttp_find_vhost(struct evhttp *http, struct evhttp **outhttp, 197290001Sglebius const char *hostname); 198290001Sglebius 199290001Sglebius#ifndef EVENT__HAVE_STRSEP 200290001Sglebius/* strsep replacement for platforms that lack it. Only works if 201290001Sglebius * del is one character long. */ 202290001Sglebiusstatic char * 203290001Sglebiusstrsep(char **s, const char *del) 204290001Sglebius{ 205290001Sglebius char *d, *tok; 206290001Sglebius EVUTIL_ASSERT(strlen(del) == 1); 207290001Sglebius if (!s || !*s) 208290001Sglebius return NULL; 209290001Sglebius tok = *s; 210290001Sglebius d = strstr(tok, del); 211290001Sglebius if (d) { 212290001Sglebius *d = '\0'; 213290001Sglebius *s = d + 1; 214290001Sglebius } else 215290001Sglebius *s = NULL; 216290001Sglebius return tok; 217290001Sglebius} 218290001Sglebius#endif 219290001Sglebius 220290001Sglebiusstatic size_t 221290001Sglebiushtml_replace(const char ch, const char **escaped) 222290001Sglebius{ 223290001Sglebius switch (ch) { 224290001Sglebius case '<': 225290001Sglebius *escaped = "<"; 226290001Sglebius return 4; 227290001Sglebius case '>': 228290001Sglebius *escaped = ">"; 229290001Sglebius return 4; 230290001Sglebius case '"': 231290001Sglebius *escaped = """; 232290001Sglebius return 6; 233290001Sglebius case '\'': 234290001Sglebius *escaped = "'"; 235290001Sglebius return 6; 236290001Sglebius case '&': 237290001Sglebius *escaped = "&"; 238290001Sglebius return 5; 239290001Sglebius default: 240290001Sglebius break; 241290001Sglebius } 242290001Sglebius 243290001Sglebius return 1; 244290001Sglebius} 245290001Sglebius 246290001Sglebius/* 247290001Sglebius * Replaces <, >, ", ' and & with <, >, ", 248290001Sglebius * ' and & correspondingly. 249290001Sglebius * 250290001Sglebius * The returned string needs to be freed by the caller. 251290001Sglebius */ 252290001Sglebius 253290001Sglebiuschar * 254290001Sglebiusevhttp_htmlescape(const char *html) 255290001Sglebius{ 256290001Sglebius size_t i; 257290001Sglebius size_t new_size = 0, old_size = 0; 258290001Sglebius char *escaped_html, *p; 259290001Sglebius 260290001Sglebius if (html == NULL) 261290001Sglebius return (NULL); 262290001Sglebius 263290001Sglebius old_size = strlen(html); 264290001Sglebius for (i = 0; i < old_size; ++i) { 265290001Sglebius const char *replaced = NULL; 266290001Sglebius const size_t replace_size = html_replace(html[i], &replaced); 267290001Sglebius if (replace_size > EV_SIZE_MAX - new_size) { 268290001Sglebius event_warn("%s: html_replace overflow", __func__); 269290001Sglebius return (NULL); 270290001Sglebius } 271290001Sglebius new_size += replace_size; 272290001Sglebius } 273290001Sglebius 274290001Sglebius if (new_size == EV_SIZE_MAX) 275290001Sglebius return (NULL); 276290001Sglebius p = escaped_html = mm_malloc(new_size + 1); 277290001Sglebius if (escaped_html == NULL) { 278290001Sglebius event_warn("%s: malloc(%lu)", __func__, 279290001Sglebius (unsigned long)(new_size + 1)); 280290001Sglebius return (NULL); 281290001Sglebius } 282290001Sglebius for (i = 0; i < old_size; ++i) { 283290001Sglebius const char *replaced = &html[i]; 284290001Sglebius const size_t len = html_replace(html[i], &replaced); 285290001Sglebius memcpy(p, replaced, len); 286290001Sglebius p += len; 287290001Sglebius } 288290001Sglebius 289290001Sglebius *p = '\0'; 290290001Sglebius 291290001Sglebius return (escaped_html); 292290001Sglebius} 293290001Sglebius 294290001Sglebius/** Given an evhttp_cmd_type, returns a constant string containing the 295290001Sglebius * equivalent HTTP command, or NULL if the evhttp_command_type is 296290001Sglebius * unrecognized. */ 297290001Sglebiusstatic const char * 298290001Sglebiusevhttp_method(enum evhttp_cmd_type type) 299290001Sglebius{ 300290001Sglebius const char *method; 301290001Sglebius 302290001Sglebius switch (type) { 303290001Sglebius case EVHTTP_REQ_GET: 304290001Sglebius method = "GET"; 305290001Sglebius break; 306290001Sglebius case EVHTTP_REQ_POST: 307290001Sglebius method = "POST"; 308290001Sglebius break; 309290001Sglebius case EVHTTP_REQ_HEAD: 310290001Sglebius method = "HEAD"; 311290001Sglebius break; 312290001Sglebius case EVHTTP_REQ_PUT: 313290001Sglebius method = "PUT"; 314290001Sglebius break; 315290001Sglebius case EVHTTP_REQ_DELETE: 316290001Sglebius method = "DELETE"; 317290001Sglebius break; 318290001Sglebius case EVHTTP_REQ_OPTIONS: 319290001Sglebius method = "OPTIONS"; 320290001Sglebius break; 321290001Sglebius case EVHTTP_REQ_TRACE: 322290001Sglebius method = "TRACE"; 323290001Sglebius break; 324290001Sglebius case EVHTTP_REQ_CONNECT: 325290001Sglebius method = "CONNECT"; 326290001Sglebius break; 327290001Sglebius case EVHTTP_REQ_PATCH: 328290001Sglebius method = "PATCH"; 329290001Sglebius break; 330290001Sglebius default: 331290001Sglebius method = NULL; 332290001Sglebius break; 333290001Sglebius } 334290001Sglebius 335290001Sglebius return (method); 336290001Sglebius} 337290001Sglebius 338290001Sglebius/** 339290001Sglebius * Determines if a response should have a body. 340290001Sglebius * Follows the rules in RFC 2616 section 4.3. 341290001Sglebius * @return 1 if the response MUST have a body; 0 if the response MUST NOT have 342290001Sglebius * a body. 343290001Sglebius */ 344290001Sglebiusstatic int 345290001Sglebiusevhttp_response_needs_body(struct evhttp_request *req) 346290001Sglebius{ 347290001Sglebius return (req->response_code != HTTP_NOCONTENT && 348290001Sglebius req->response_code != HTTP_NOTMODIFIED && 349290001Sglebius (req->response_code < 100 || req->response_code >= 200) && 350290001Sglebius req->type != EVHTTP_REQ_HEAD); 351290001Sglebius} 352290001Sglebius 353290001Sglebius/** Helper: called after we've added some data to an evcon's bufferevent's 354290001Sglebius * output buffer. Sets the evconn's writing-is-done callback, and puts 355290001Sglebius * the bufferevent into writing mode. 356290001Sglebius */ 357290001Sglebiusstatic void 358290001Sglebiusevhttp_write_buffer(struct evhttp_connection *evcon, 359290001Sglebius void (*cb)(struct evhttp_connection *, void *), void *arg) 360290001Sglebius{ 361290001Sglebius event_debug(("%s: preparing to write buffer\n", __func__)); 362290001Sglebius 363290001Sglebius /* Set call back */ 364290001Sglebius evcon->cb = cb; 365290001Sglebius evcon->cb_arg = arg; 366290001Sglebius 367290001Sglebius /* Disable the read callback: we don't actually care about data; 368290001Sglebius * we only care about close detection. (We don't disable reading, 369290001Sglebius * since we *do* want to learn about any close events.) */ 370290001Sglebius bufferevent_setcb(evcon->bufev, 371290001Sglebius NULL, /*read*/ 372290001Sglebius evhttp_write_cb, 373290001Sglebius evhttp_error_cb, 374290001Sglebius evcon); 375290001Sglebius 376290001Sglebius bufferevent_enable(evcon->bufev, EV_WRITE); 377290001Sglebius} 378290001Sglebius 379290001Sglebiusstatic void 380290001Sglebiusevhttp_send_continue_done(struct evhttp_connection *evcon, void *arg) 381290001Sglebius{ 382290001Sglebius bufferevent_disable(evcon->bufev, EV_WRITE); 383290001Sglebius} 384290001Sglebius 385290001Sglebiusstatic void 386290001Sglebiusevhttp_send_continue(struct evhttp_connection *evcon, 387290001Sglebius struct evhttp_request *req) 388290001Sglebius{ 389290001Sglebius bufferevent_enable(evcon->bufev, EV_WRITE); 390290001Sglebius evbuffer_add_printf(bufferevent_get_output(evcon->bufev), 391290001Sglebius "HTTP/%d.%d 100 Continue\r\n\r\n", 392290001Sglebius req->major, req->minor); 393290001Sglebius evcon->cb = evhttp_send_continue_done; 394290001Sglebius evcon->cb_arg = NULL; 395290001Sglebius bufferevent_setcb(evcon->bufev, 396290001Sglebius evhttp_read_cb, 397290001Sglebius evhttp_write_cb, 398290001Sglebius evhttp_error_cb, 399290001Sglebius evcon); 400290001Sglebius} 401290001Sglebius 402290001Sglebius/** Helper: returns true iff evconn is in any connected state. */ 403290001Sglebiusstatic int 404290001Sglebiusevhttp_connected(struct evhttp_connection *evcon) 405290001Sglebius{ 406290001Sglebius switch (evcon->state) { 407290001Sglebius case EVCON_DISCONNECTED: 408290001Sglebius case EVCON_CONNECTING: 409290001Sglebius return (0); 410290001Sglebius case EVCON_IDLE: 411290001Sglebius case EVCON_READING_FIRSTLINE: 412290001Sglebius case EVCON_READING_HEADERS: 413290001Sglebius case EVCON_READING_BODY: 414290001Sglebius case EVCON_READING_TRAILER: 415290001Sglebius case EVCON_WRITING: 416290001Sglebius default: 417290001Sglebius return (1); 418290001Sglebius } 419290001Sglebius} 420290001Sglebius 421290001Sglebius/* Create the headers needed for an outgoing HTTP request, adds them to 422290001Sglebius * the request's header list, and writes the request line to the 423290001Sglebius * connection's output buffer. 424290001Sglebius */ 425290001Sglebiusstatic void 426290001Sglebiusevhttp_make_header_request(struct evhttp_connection *evcon, 427290001Sglebius struct evhttp_request *req) 428290001Sglebius{ 429290001Sglebius const char *method; 430290001Sglebius 431290001Sglebius evhttp_remove_header(req->output_headers, "Proxy-Connection"); 432290001Sglebius 433290001Sglebius /* Generate request line */ 434290001Sglebius method = evhttp_method(req->type); 435290001Sglebius evbuffer_add_printf(bufferevent_get_output(evcon->bufev), 436290001Sglebius "%s %s HTTP/%d.%d\r\n", 437290001Sglebius method, req->uri, req->major, req->minor); 438290001Sglebius 439290001Sglebius /* Add the content length on a post or put request if missing */ 440290001Sglebius if ((req->type == EVHTTP_REQ_POST || req->type == EVHTTP_REQ_PUT) && 441290001Sglebius evhttp_find_header(req->output_headers, "Content-Length") == NULL){ 442290001Sglebius char size[22]; 443290001Sglebius evutil_snprintf(size, sizeof(size), EV_SIZE_FMT, 444290001Sglebius EV_SIZE_ARG(evbuffer_get_length(req->output_buffer))); 445290001Sglebius evhttp_add_header(req->output_headers, "Content-Length", size); 446290001Sglebius } 447290001Sglebius} 448290001Sglebius 449290001Sglebius/** Return true if the list of headers in 'headers', intepreted with respect 450290001Sglebius * to flags, means that we should send a "connection: close" when the request 451290001Sglebius * is done. */ 452290001Sglebiusstatic int 453290001Sglebiusevhttp_is_connection_close(int flags, struct evkeyvalq* headers) 454290001Sglebius{ 455290001Sglebius if (flags & EVHTTP_PROXY_REQUEST) { 456290001Sglebius /* proxy connection */ 457290001Sglebius const char *connection = evhttp_find_header(headers, "Proxy-Connection"); 458290001Sglebius return (connection == NULL || evutil_ascii_strcasecmp(connection, "keep-alive") != 0); 459290001Sglebius } else { 460290001Sglebius const char *connection = evhttp_find_header(headers, "Connection"); 461290001Sglebius return (connection != NULL && evutil_ascii_strcasecmp(connection, "close") == 0); 462290001Sglebius } 463290001Sglebius} 464290001Sglebius 465290001Sglebius/* Return true iff 'headers' contains 'Connection: keep-alive' */ 466290001Sglebiusstatic int 467290001Sglebiusevhttp_is_connection_keepalive(struct evkeyvalq* headers) 468290001Sglebius{ 469290001Sglebius const char *connection = evhttp_find_header(headers, "Connection"); 470290001Sglebius return (connection != NULL 471290001Sglebius && evutil_ascii_strncasecmp(connection, "keep-alive", 10) == 0); 472290001Sglebius} 473290001Sglebius 474290001Sglebius/* Add a correct "Date" header to headers, unless it already has one. */ 475290001Sglebiusstatic void 476290001Sglebiusevhttp_maybe_add_date_header(struct evkeyvalq *headers) 477290001Sglebius{ 478290001Sglebius if (evhttp_find_header(headers, "Date") == NULL) { 479290001Sglebius char date[50]; 480290001Sglebius#ifndef _WIN32 481290001Sglebius struct tm cur; 482290001Sglebius#endif 483290001Sglebius struct tm *cur_p; 484290001Sglebius time_t t = time(NULL); 485290001Sglebius#ifdef _WIN32 486290001Sglebius cur_p = gmtime(&t); 487290001Sglebius#else 488290001Sglebius gmtime_r(&t, &cur); 489290001Sglebius cur_p = &cur; 490290001Sglebius#endif 491290001Sglebius if (strftime(date, sizeof(date), 492290001Sglebius "%a, %d %b %Y %H:%M:%S GMT", cur_p) != 0) { 493290001Sglebius evhttp_add_header(headers, "Date", date); 494290001Sglebius } 495290001Sglebius } 496290001Sglebius} 497290001Sglebius 498290001Sglebius/* Add a "Content-Length" header with value 'content_length' to headers, 499290001Sglebius * unless it already has a content-length or transfer-encoding header. */ 500290001Sglebiusstatic void 501290001Sglebiusevhttp_maybe_add_content_length_header(struct evkeyvalq *headers, 502290001Sglebius size_t content_length) 503290001Sglebius{ 504290001Sglebius if (evhttp_find_header(headers, "Transfer-Encoding") == NULL && 505290001Sglebius evhttp_find_header(headers, "Content-Length") == NULL) { 506290001Sglebius char len[22]; 507290001Sglebius evutil_snprintf(len, sizeof(len), EV_SIZE_FMT, 508290001Sglebius EV_SIZE_ARG(content_length)); 509290001Sglebius evhttp_add_header(headers, "Content-Length", len); 510290001Sglebius } 511290001Sglebius} 512290001Sglebius 513290001Sglebius/* 514290001Sglebius * Create the headers needed for an HTTP reply in req->output_headers, 515290001Sglebius * and write the first HTTP response for req line to evcon. 516290001Sglebius */ 517290001Sglebiusstatic void 518290001Sglebiusevhttp_make_header_response(struct evhttp_connection *evcon, 519290001Sglebius struct evhttp_request *req) 520290001Sglebius{ 521290001Sglebius int is_keepalive = evhttp_is_connection_keepalive(req->input_headers); 522290001Sglebius evbuffer_add_printf(bufferevent_get_output(evcon->bufev), 523290001Sglebius "HTTP/%d.%d %d %s\r\n", 524290001Sglebius req->major, req->minor, req->response_code, 525290001Sglebius req->response_code_line); 526290001Sglebius 527290001Sglebius if (req->major == 1) { 528290001Sglebius if (req->minor >= 1) 529290001Sglebius evhttp_maybe_add_date_header(req->output_headers); 530290001Sglebius 531290001Sglebius /* 532290001Sglebius * if the protocol is 1.0; and the connection was keep-alive 533290001Sglebius * we need to add a keep-alive header, too. 534290001Sglebius */ 535290001Sglebius if (req->minor == 0 && is_keepalive) 536290001Sglebius evhttp_add_header(req->output_headers, 537290001Sglebius "Connection", "keep-alive"); 538290001Sglebius 539290001Sglebius if ((req->minor >= 1 || is_keepalive) && 540290001Sglebius evhttp_response_needs_body(req)) { 541290001Sglebius /* 542290001Sglebius * we need to add the content length if the 543290001Sglebius * user did not give it, this is required for 544290001Sglebius * persistent connections to work. 545290001Sglebius */ 546290001Sglebius evhttp_maybe_add_content_length_header( 547290001Sglebius req->output_headers, 548290001Sglebius evbuffer_get_length(req->output_buffer)); 549290001Sglebius } 550290001Sglebius } 551290001Sglebius 552290001Sglebius /* Potentially add headers for unidentified content. */ 553290001Sglebius if (evhttp_response_needs_body(req)) { 554290001Sglebius if (evhttp_find_header(req->output_headers, 555290001Sglebius "Content-Type") == NULL 556290001Sglebius && evcon->http_server->default_content_type) { 557290001Sglebius evhttp_add_header(req->output_headers, 558290001Sglebius "Content-Type", 559290001Sglebius evcon->http_server->default_content_type); 560290001Sglebius } 561290001Sglebius } 562290001Sglebius 563290001Sglebius /* if the request asked for a close, we send a close, too */ 564290001Sglebius if (evhttp_is_connection_close(req->flags, req->input_headers)) { 565290001Sglebius evhttp_remove_header(req->output_headers, "Connection"); 566290001Sglebius if (!(req->flags & EVHTTP_PROXY_REQUEST)) 567290001Sglebius evhttp_add_header(req->output_headers, "Connection", "close"); 568290001Sglebius evhttp_remove_header(req->output_headers, "Proxy-Connection"); 569290001Sglebius } 570290001Sglebius} 571290001Sglebius 572290001Sglebius/** Generate all headers appropriate for sending the http request in req (or 573290001Sglebius * the response, if we're sending a response), and write them to evcon's 574290001Sglebius * bufferevent. Also writes all data from req->output_buffer */ 575290001Sglebiusstatic void 576290001Sglebiusevhttp_make_header(struct evhttp_connection *evcon, struct evhttp_request *req) 577290001Sglebius{ 578290001Sglebius struct evkeyval *header; 579290001Sglebius struct evbuffer *output = bufferevent_get_output(evcon->bufev); 580290001Sglebius 581290001Sglebius /* 582290001Sglebius * Depending if this is a HTTP request or response, we might need to 583290001Sglebius * add some new headers or remove existing headers. 584290001Sglebius */ 585290001Sglebius if (req->kind == EVHTTP_REQUEST) { 586290001Sglebius evhttp_make_header_request(evcon, req); 587290001Sglebius } else { 588290001Sglebius evhttp_make_header_response(evcon, req); 589290001Sglebius } 590290001Sglebius 591290001Sglebius TAILQ_FOREACH(header, req->output_headers, next) { 592290001Sglebius evbuffer_add_printf(output, "%s: %s\r\n", 593290001Sglebius header->key, header->value); 594290001Sglebius } 595290001Sglebius evbuffer_add(output, "\r\n", 2); 596290001Sglebius 597290001Sglebius if (evbuffer_get_length(req->output_buffer) > 0) { 598290001Sglebius /* 599290001Sglebius * For a request, we add the POST data, for a reply, this 600290001Sglebius * is the regular data. 601290001Sglebius */ 602290001Sglebius /* XXX We might want to support waiting (a limited amount of 603290001Sglebius time) for a continue status line from the server before 604290001Sglebius sending POST/PUT message bodies. */ 605290001Sglebius evbuffer_add_buffer(output, req->output_buffer); 606290001Sglebius } 607290001Sglebius} 608290001Sglebius 609290001Sglebiusvoid 610290001Sglebiusevhttp_connection_set_max_headers_size(struct evhttp_connection *evcon, 611290001Sglebius ev_ssize_t new_max_headers_size) 612290001Sglebius{ 613290001Sglebius if (new_max_headers_size<0) 614290001Sglebius evcon->max_headers_size = EV_SIZE_MAX; 615290001Sglebius else 616290001Sglebius evcon->max_headers_size = new_max_headers_size; 617290001Sglebius} 618290001Sglebiusvoid 619290001Sglebiusevhttp_connection_set_max_body_size(struct evhttp_connection* evcon, 620290001Sglebius ev_ssize_t new_max_body_size) 621290001Sglebius{ 622290001Sglebius if (new_max_body_size<0) 623290001Sglebius evcon->max_body_size = EV_UINT64_MAX; 624290001Sglebius else 625290001Sglebius evcon->max_body_size = new_max_body_size; 626290001Sglebius} 627290001Sglebius 628290001Sglebiusstatic int 629290001Sglebiusevhttp_connection_incoming_fail(struct evhttp_request *req, 630290001Sglebius enum evhttp_request_error error) 631290001Sglebius{ 632290001Sglebius switch (error) { 633290001Sglebius case EVREQ_HTTP_TIMEOUT: 634290001Sglebius case EVREQ_HTTP_EOF: 635290001Sglebius /* 636290001Sglebius * these are cases in which we probably should just 637290001Sglebius * close the connection and not send a reply. this 638290001Sglebius * case may happen when a browser keeps a persistent 639290001Sglebius * connection open and we timeout on the read. when 640290001Sglebius * the request is still being used for sending, we 641290001Sglebius * need to disassociated it from the connection here. 642290001Sglebius */ 643290001Sglebius if (!req->userdone) { 644290001Sglebius /* remove it so that it will not be freed */ 645290001Sglebius TAILQ_REMOVE(&req->evcon->requests, req, next); 646290001Sglebius /* indicate that this request no longer has a 647290001Sglebius * connection object 648290001Sglebius */ 649290001Sglebius req->evcon = NULL; 650290001Sglebius } 651290001Sglebius return (-1); 652290001Sglebius case EVREQ_HTTP_INVALID_HEADER: 653290001Sglebius case EVREQ_HTTP_BUFFER_ERROR: 654290001Sglebius case EVREQ_HTTP_REQUEST_CANCEL: 655290001Sglebius case EVREQ_HTTP_DATA_TOO_LONG: 656290001Sglebius default: /* xxx: probably should just error on default */ 657290001Sglebius /* the callback looks at the uri to determine errors */ 658290001Sglebius if (req->uri) { 659290001Sglebius mm_free(req->uri); 660290001Sglebius req->uri = NULL; 661290001Sglebius } 662290001Sglebius if (req->uri_elems) { 663290001Sglebius evhttp_uri_free(req->uri_elems); 664290001Sglebius req->uri_elems = NULL; 665290001Sglebius } 666290001Sglebius 667290001Sglebius /* 668290001Sglebius * the callback needs to send a reply, once the reply has 669290001Sglebius * been send, the connection should get freed. 670290001Sglebius */ 671290001Sglebius (*req->cb)(req, req->cb_arg); 672290001Sglebius } 673290001Sglebius 674290001Sglebius return (0); 675290001Sglebius} 676290001Sglebius 677290001Sglebius/* Called when evcon has experienced a (non-recoverable? -NM) error, as 678290001Sglebius * given in error. If it's an outgoing connection, reset the connection, 679290001Sglebius * retry any pending requests, and inform the user. If it's incoming, 680290001Sglebius * delegates to evhttp_connection_incoming_fail(). */ 681290001Sglebiusvoid 682290001Sglebiusevhttp_connection_fail_(struct evhttp_connection *evcon, 683290001Sglebius enum evhttp_request_error error) 684290001Sglebius{ 685290001Sglebius const int errsave = EVUTIL_SOCKET_ERROR(); 686290001Sglebius struct evhttp_request* req = TAILQ_FIRST(&evcon->requests); 687290001Sglebius void (*cb)(struct evhttp_request *, void *); 688290001Sglebius void *cb_arg; 689290001Sglebius void (*error_cb)(enum evhttp_request_error, void *); 690290001Sglebius void *error_cb_arg; 691290001Sglebius EVUTIL_ASSERT(req != NULL); 692290001Sglebius 693290001Sglebius bufferevent_disable(evcon->bufev, EV_READ|EV_WRITE); 694290001Sglebius 695290001Sglebius if (evcon->flags & EVHTTP_CON_INCOMING) { 696290001Sglebius /* 697290001Sglebius * for incoming requests, there are two different 698290001Sglebius * failure cases. it's either a network level error 699290001Sglebius * or an http layer error. for problems on the network 700290001Sglebius * layer like timeouts we just drop the connections. 701290001Sglebius * For HTTP problems, we might have to send back a 702290001Sglebius * reply before the connection can be freed. 703290001Sglebius */ 704290001Sglebius if (evhttp_connection_incoming_fail(req, error) == -1) 705290001Sglebius evhttp_connection_free(evcon); 706290001Sglebius return; 707290001Sglebius } 708290001Sglebius 709290001Sglebius error_cb = req->error_cb; 710290001Sglebius error_cb_arg = req->cb_arg; 711290001Sglebius /* when the request was canceled, the callback is not executed */ 712290001Sglebius if (error != EVREQ_HTTP_REQUEST_CANCEL) { 713290001Sglebius /* save the callback for later; the cb might free our object */ 714290001Sglebius cb = req->cb; 715290001Sglebius cb_arg = req->cb_arg; 716290001Sglebius } else { 717290001Sglebius cb = NULL; 718290001Sglebius cb_arg = NULL; 719290001Sglebius } 720290001Sglebius 721290001Sglebius /* do not fail all requests; the next request is going to get 722290001Sglebius * send over a new connection. when a user cancels a request, 723290001Sglebius * all other pending requests should be processed as normal 724290001Sglebius */ 725290001Sglebius TAILQ_REMOVE(&evcon->requests, req, next); 726290001Sglebius evhttp_request_free(req); 727290001Sglebius 728290001Sglebius /* reset the connection */ 729290001Sglebius evhttp_connection_reset_(evcon); 730290001Sglebius 731290001Sglebius /* We are trying the next request that was queued on us */ 732290001Sglebius if (TAILQ_FIRST(&evcon->requests) != NULL) 733290001Sglebius evhttp_connection_connect_(evcon); 734290001Sglebius 735290001Sglebius /* The call to evhttp_connection_reset_ overwrote errno. 736290001Sglebius * Let's restore the original errno, so that the user's 737290001Sglebius * callback can have a better idea of what the error was. 738290001Sglebius */ 739290001Sglebius EVUTIL_SET_SOCKET_ERROR(errsave); 740290001Sglebius 741290001Sglebius /* inform the user */ 742290001Sglebius if (error_cb != NULL) 743290001Sglebius error_cb(error, error_cb_arg); 744290001Sglebius if (cb != NULL) 745290001Sglebius (*cb)(NULL, cb_arg); 746290001Sglebius} 747290001Sglebius 748290001Sglebius/* Bufferevent callback: invoked when any data has been written from an 749290001Sglebius * http connection's bufferevent */ 750290001Sglebiusstatic void 751290001Sglebiusevhttp_write_cb(struct bufferevent *bufev, void *arg) 752290001Sglebius{ 753290001Sglebius struct evhttp_connection *evcon = arg; 754290001Sglebius 755290001Sglebius /* Activate our call back */ 756290001Sglebius if (evcon->cb != NULL) 757290001Sglebius (*evcon->cb)(evcon, evcon->cb_arg); 758290001Sglebius} 759290001Sglebius 760290001Sglebius/** 761290001Sglebius * Advance the connection state. 762290001Sglebius * - If this is an outgoing connection, we've just processed the response; 763290001Sglebius * idle or close the connection. 764290001Sglebius * - If this is an incoming connection, we've just processed the request; 765290001Sglebius * respond. 766290001Sglebius */ 767290001Sglebiusstatic void 768290001Sglebiusevhttp_connection_done(struct evhttp_connection *evcon) 769290001Sglebius{ 770290001Sglebius struct evhttp_request *req = TAILQ_FIRST(&evcon->requests); 771290001Sglebius int con_outgoing = evcon->flags & EVHTTP_CON_OUTGOING; 772290001Sglebius int free_evcon = 0; 773290001Sglebius 774290001Sglebius if (con_outgoing) { 775290001Sglebius /* idle or close the connection */ 776290001Sglebius int need_close; 777290001Sglebius TAILQ_REMOVE(&evcon->requests, req, next); 778290001Sglebius req->evcon = NULL; 779290001Sglebius 780290001Sglebius evcon->state = EVCON_IDLE; 781290001Sglebius 782290001Sglebius need_close = 783290001Sglebius evhttp_is_connection_close(req->flags, req->input_headers)|| 784290001Sglebius evhttp_is_connection_close(req->flags, req->output_headers); 785290001Sglebius 786290001Sglebius /* check if we got asked to close the connection */ 787290001Sglebius if (need_close) 788290001Sglebius evhttp_connection_reset_(evcon); 789290001Sglebius 790290001Sglebius if (TAILQ_FIRST(&evcon->requests) != NULL) { 791290001Sglebius /* 792290001Sglebius * We have more requests; reset the connection 793290001Sglebius * and deal with the next request. 794290001Sglebius */ 795290001Sglebius if (!evhttp_connected(evcon)) 796290001Sglebius evhttp_connection_connect_(evcon); 797290001Sglebius else 798290001Sglebius evhttp_request_dispatch(evcon); 799290001Sglebius } else if (!need_close) { 800290001Sglebius /* 801290001Sglebius * The connection is going to be persistent, but we 802290001Sglebius * need to detect if the other side closes it. 803290001Sglebius */ 804290001Sglebius evhttp_connection_start_detectclose(evcon); 805290001Sglebius } else if ((evcon->flags & EVHTTP_CON_AUTOFREE)) { 806290001Sglebius /* 807290001Sglebius * If we have no more requests that need completion 808290001Sglebius * and we're not waiting for the connection to close 809290001Sglebius */ 810290001Sglebius free_evcon = 1; 811290001Sglebius } 812290001Sglebius } else { 813290001Sglebius /* 814290001Sglebius * incoming connection - we need to leave the request on the 815290001Sglebius * connection so that we can reply to it. 816290001Sglebius */ 817290001Sglebius evcon->state = EVCON_WRITING; 818290001Sglebius } 819290001Sglebius 820290001Sglebius /* notify the user of the request */ 821290001Sglebius (*req->cb)(req, req->cb_arg); 822290001Sglebius 823290001Sglebius /* if this was an outgoing request, we own and it's done. so free it. 824290001Sglebius * unless the callback specifically requested to own the request. 825290001Sglebius */ 826290001Sglebius if (con_outgoing && ((req->flags & EVHTTP_USER_OWNED) == 0)) { 827290001Sglebius evhttp_request_free(req); 828290001Sglebius } 829290001Sglebius 830290001Sglebius /* If this was the last request of an outgoing connection and we're 831290001Sglebius * not waiting to receive a connection close event and we want to 832290001Sglebius * automatically free the connection. We check to ensure our request 833290001Sglebius * list is empty one last time just in case our callback added a 834290001Sglebius * new request. 835290001Sglebius */ 836290001Sglebius if (free_evcon && TAILQ_FIRST(&evcon->requests) == NULL) { 837290001Sglebius evhttp_connection_free(evcon); 838290001Sglebius } 839290001Sglebius} 840290001Sglebius 841290001Sglebius/* 842290001Sglebius * Handles reading from a chunked request. 843290001Sglebius * return ALL_DATA_READ: 844290001Sglebius * all data has been read 845290001Sglebius * return MORE_DATA_EXPECTED: 846290001Sglebius * more data is expected 847290001Sglebius * return DATA_CORRUPTED: 848290001Sglebius * data is corrupted 849290001Sglebius * return REQUEST_CANCELED: 850290001Sglebius * request was canceled by the user calling evhttp_cancel_request 851290001Sglebius * return DATA_TOO_LONG: 852290001Sglebius * ran over the maximum limit 853290001Sglebius */ 854290001Sglebius 855290001Sglebiusstatic enum message_read_status 856290001Sglebiusevhttp_handle_chunked_read(struct evhttp_request *req, struct evbuffer *buf) 857290001Sglebius{ 858290001Sglebius if (req == NULL || buf == NULL) { 859290001Sglebius return DATA_CORRUPTED; 860290001Sglebius } 861290001Sglebius 862290001Sglebius while (1) { 863290001Sglebius size_t buflen; 864290001Sglebius 865290001Sglebius if ((buflen = evbuffer_get_length(buf)) == 0) { 866290001Sglebius break; 867290001Sglebius } 868290001Sglebius 869290001Sglebius /* evbuffer_get_length returns size_t, but len variable is ssize_t, 870290001Sglebius * check for overflow conditions */ 871290001Sglebius if (buflen > EV_SSIZE_MAX) { 872290001Sglebius return DATA_CORRUPTED; 873290001Sglebius } 874290001Sglebius 875290001Sglebius if (req->ntoread < 0) { 876290001Sglebius /* Read chunk size */ 877290001Sglebius ev_int64_t ntoread; 878290001Sglebius char *p = evbuffer_readln(buf, NULL, EVBUFFER_EOL_CRLF); 879290001Sglebius char *endp; 880290001Sglebius int error; 881290001Sglebius if (p == NULL) 882290001Sglebius break; 883290001Sglebius /* the last chunk is on a new line? */ 884290001Sglebius if (strlen(p) == 0) { 885290001Sglebius mm_free(p); 886290001Sglebius continue; 887290001Sglebius } 888290001Sglebius ntoread = evutil_strtoll(p, &endp, 16); 889290001Sglebius error = (*p == '\0' || 890290001Sglebius (*endp != '\0' && *endp != ' ') || 891290001Sglebius ntoread < 0); 892290001Sglebius mm_free(p); 893290001Sglebius if (error) { 894290001Sglebius /* could not get chunk size */ 895290001Sglebius return (DATA_CORRUPTED); 896290001Sglebius } 897290001Sglebius 898290001Sglebius /* ntoread is signed int64, body_size is unsigned size_t, check for under/overflow conditions */ 899290001Sglebius if ((ev_uint64_t)ntoread > EV_SIZE_MAX - req->body_size) { 900290001Sglebius return DATA_CORRUPTED; 901290001Sglebius } 902290001Sglebius 903290001Sglebius if (req->body_size + (size_t)ntoread > req->evcon->max_body_size) { 904290001Sglebius /* failed body length test */ 905290001Sglebius event_debug(("Request body is too long")); 906290001Sglebius return (DATA_TOO_LONG); 907290001Sglebius } 908290001Sglebius 909290001Sglebius req->body_size += (size_t)ntoread; 910290001Sglebius req->ntoread = ntoread; 911290001Sglebius if (req->ntoread == 0) { 912290001Sglebius /* Last chunk */ 913290001Sglebius return (ALL_DATA_READ); 914290001Sglebius } 915290001Sglebius continue; 916290001Sglebius } 917290001Sglebius 918290001Sglebius /* req->ntoread is signed int64, len is ssize_t, based on arch, 919290001Sglebius * ssize_t could only be 32b, check for these conditions */ 920290001Sglebius if (req->ntoread > EV_SSIZE_MAX) { 921290001Sglebius return DATA_CORRUPTED; 922290001Sglebius } 923290001Sglebius 924290001Sglebius /* don't have enough to complete a chunk; wait for more */ 925290001Sglebius if (req->ntoread > 0 && buflen < (ev_uint64_t)req->ntoread) 926290001Sglebius return (MORE_DATA_EXPECTED); 927290001Sglebius 928290001Sglebius /* Completed chunk */ 929290001Sglebius evbuffer_remove_buffer(buf, req->input_buffer, (size_t)req->ntoread); 930290001Sglebius req->ntoread = -1; 931290001Sglebius if (req->chunk_cb != NULL) { 932290001Sglebius req->flags |= EVHTTP_REQ_DEFER_FREE; 933290001Sglebius (*req->chunk_cb)(req, req->cb_arg); 934290001Sglebius evbuffer_drain(req->input_buffer, 935290001Sglebius evbuffer_get_length(req->input_buffer)); 936290001Sglebius req->flags &= ~EVHTTP_REQ_DEFER_FREE; 937290001Sglebius if ((req->flags & EVHTTP_REQ_NEEDS_FREE) != 0) { 938290001Sglebius return (REQUEST_CANCELED); 939290001Sglebius } 940290001Sglebius } 941290001Sglebius } 942290001Sglebius 943290001Sglebius return (MORE_DATA_EXPECTED); 944290001Sglebius} 945290001Sglebius 946290001Sglebiusstatic void 947290001Sglebiusevhttp_read_trailer(struct evhttp_connection *evcon, struct evhttp_request *req) 948290001Sglebius{ 949290001Sglebius struct evbuffer *buf = bufferevent_get_input(evcon->bufev); 950290001Sglebius 951290001Sglebius switch (evhttp_parse_headers_(req, buf)) { 952290001Sglebius case DATA_CORRUPTED: 953290001Sglebius case DATA_TOO_LONG: 954290001Sglebius evhttp_connection_fail_(evcon, EVREQ_HTTP_DATA_TOO_LONG); 955290001Sglebius break; 956290001Sglebius case ALL_DATA_READ: 957290001Sglebius bufferevent_disable(evcon->bufev, EV_READ); 958290001Sglebius evhttp_connection_done(evcon); 959290001Sglebius break; 960290001Sglebius case MORE_DATA_EXPECTED: 961290001Sglebius case REQUEST_CANCELED: /* ??? */ 962290001Sglebius default: 963290001Sglebius bufferevent_enable(evcon->bufev, EV_READ); 964290001Sglebius break; 965290001Sglebius } 966290001Sglebius} 967290001Sglebius 968290001Sglebiusstatic void 969290001Sglebiusevhttp_read_body(struct evhttp_connection *evcon, struct evhttp_request *req) 970290001Sglebius{ 971290001Sglebius struct evbuffer *buf = bufferevent_get_input(evcon->bufev); 972290001Sglebius 973290001Sglebius if (req->chunked) { 974290001Sglebius switch (evhttp_handle_chunked_read(req, buf)) { 975290001Sglebius case ALL_DATA_READ: 976290001Sglebius /* finished last chunk */ 977290001Sglebius evcon->state = EVCON_READING_TRAILER; 978290001Sglebius evhttp_read_trailer(evcon, req); 979290001Sglebius return; 980290001Sglebius case DATA_CORRUPTED: 981290001Sglebius case DATA_TOO_LONG: 982290001Sglebius /* corrupted data */ 983290001Sglebius evhttp_connection_fail_(evcon, 984290001Sglebius EVREQ_HTTP_DATA_TOO_LONG); 985290001Sglebius return; 986290001Sglebius case REQUEST_CANCELED: 987290001Sglebius /* request canceled */ 988290001Sglebius evhttp_request_free(req); 989290001Sglebius return; 990290001Sglebius case MORE_DATA_EXPECTED: 991290001Sglebius default: 992290001Sglebius break; 993290001Sglebius } 994290001Sglebius } else if (req->ntoread < 0) { 995290001Sglebius /* Read until connection close. */ 996290001Sglebius if ((size_t)(req->body_size + evbuffer_get_length(buf)) < req->body_size) { 997290001Sglebius evhttp_connection_fail_(evcon, EVREQ_HTTP_INVALID_HEADER); 998290001Sglebius return; 999290001Sglebius } 1000290001Sglebius 1001290001Sglebius req->body_size += evbuffer_get_length(buf); 1002290001Sglebius evbuffer_add_buffer(req->input_buffer, buf); 1003290001Sglebius } else if (req->chunk_cb != NULL || evbuffer_get_length(buf) >= (size_t)req->ntoread) { 1004290001Sglebius /* XXX: the above get_length comparison has to be fixed for overflow conditions! */ 1005290001Sglebius /* We've postponed moving the data until now, but we're 1006290001Sglebius * about to use it. */ 1007290001Sglebius size_t n = evbuffer_get_length(buf); 1008290001Sglebius 1009290001Sglebius if (n > (size_t) req->ntoread) 1010290001Sglebius n = (size_t) req->ntoread; 1011290001Sglebius req->ntoread -= n; 1012290001Sglebius req->body_size += n; 1013290001Sglebius evbuffer_remove_buffer(buf, req->input_buffer, n); 1014290001Sglebius } 1015290001Sglebius 1016290001Sglebius if (req->body_size > req->evcon->max_body_size || 1017290001Sglebius (!req->chunked && req->ntoread >= 0 && 1018290001Sglebius (size_t)req->ntoread > req->evcon->max_body_size)) { 1019290001Sglebius /* XXX: The above casted comparison must checked for overflow */ 1020290001Sglebius /* failed body length test */ 1021290001Sglebius event_debug(("Request body is too long")); 1022290001Sglebius evhttp_connection_fail_(evcon, 1023290001Sglebius EVREQ_HTTP_DATA_TOO_LONG); 1024290001Sglebius return; 1025290001Sglebius } 1026290001Sglebius 1027290001Sglebius if (evbuffer_get_length(req->input_buffer) > 0 && req->chunk_cb != NULL) { 1028290001Sglebius req->flags |= EVHTTP_REQ_DEFER_FREE; 1029290001Sglebius (*req->chunk_cb)(req, req->cb_arg); 1030290001Sglebius req->flags &= ~EVHTTP_REQ_DEFER_FREE; 1031290001Sglebius evbuffer_drain(req->input_buffer, 1032290001Sglebius evbuffer_get_length(req->input_buffer)); 1033290001Sglebius if ((req->flags & EVHTTP_REQ_NEEDS_FREE) != 0) { 1034290001Sglebius evhttp_request_free(req); 1035290001Sglebius return; 1036290001Sglebius } 1037290001Sglebius } 1038290001Sglebius 1039290001Sglebius if (req->ntoread == 0) { 1040290001Sglebius bufferevent_disable(evcon->bufev, EV_READ); 1041290001Sglebius /* Completed content length */ 1042290001Sglebius evhttp_connection_done(evcon); 1043290001Sglebius return; 1044290001Sglebius } 1045290001Sglebius 1046290001Sglebius /* Read more! */ 1047290001Sglebius bufferevent_enable(evcon->bufev, EV_READ); 1048290001Sglebius} 1049290001Sglebius 1050290001Sglebius#define get_deferred_queue(evcon) \ 1051290001Sglebius ((evcon)->base) 1052290001Sglebius 1053290001Sglebius/* 1054290001Sglebius * Gets called when more data becomes available 1055290001Sglebius */ 1056290001Sglebius 1057290001Sglebiusstatic void 1058290001Sglebiusevhttp_read_cb(struct bufferevent *bufev, void *arg) 1059290001Sglebius{ 1060290001Sglebius struct evhttp_connection *evcon = arg; 1061290001Sglebius struct evhttp_request *req = TAILQ_FIRST(&evcon->requests); 1062290001Sglebius 1063290001Sglebius /* Cancel if it's pending. */ 1064290001Sglebius event_deferred_cb_cancel_(get_deferred_queue(evcon), 1065290001Sglebius &evcon->read_more_deferred_cb); 1066290001Sglebius 1067290001Sglebius switch (evcon->state) { 1068290001Sglebius case EVCON_READING_FIRSTLINE: 1069290001Sglebius evhttp_read_firstline(evcon, req); 1070290001Sglebius /* note the request may have been freed in 1071290001Sglebius * evhttp_read_body */ 1072290001Sglebius break; 1073290001Sglebius case EVCON_READING_HEADERS: 1074290001Sglebius evhttp_read_header(evcon, req); 1075290001Sglebius /* note the request may have been freed in 1076290001Sglebius * evhttp_read_body */ 1077290001Sglebius break; 1078290001Sglebius case EVCON_READING_BODY: 1079290001Sglebius evhttp_read_body(evcon, req); 1080290001Sglebius /* note the request may have been freed in 1081290001Sglebius * evhttp_read_body */ 1082290001Sglebius break; 1083290001Sglebius case EVCON_READING_TRAILER: 1084290001Sglebius evhttp_read_trailer(evcon, req); 1085290001Sglebius break; 1086290001Sglebius case EVCON_IDLE: 1087290001Sglebius { 1088290001Sglebius#ifdef USE_DEBUG 1089290001Sglebius struct evbuffer *input; 1090290001Sglebius size_t total_len; 1091290001Sglebius 1092290001Sglebius input = bufferevent_get_input(evcon->bufev); 1093290001Sglebius total_len = evbuffer_get_length(input); 1094290001Sglebius event_debug(("%s: read "EV_SIZE_FMT 1095290001Sglebius " bytes in EVCON_IDLE state," 1096290001Sglebius " resetting connection", 1097290001Sglebius __func__, EV_SIZE_ARG(total_len))); 1098290001Sglebius#endif 1099290001Sglebius 1100290001Sglebius evhttp_connection_reset_(evcon); 1101290001Sglebius } 1102290001Sglebius break; 1103290001Sglebius case EVCON_DISCONNECTED: 1104290001Sglebius case EVCON_CONNECTING: 1105290001Sglebius case EVCON_WRITING: 1106290001Sglebius default: 1107290001Sglebius event_errx(1, "%s: illegal connection state %d", 1108290001Sglebius __func__, evcon->state); 1109290001Sglebius } 1110290001Sglebius} 1111290001Sglebius 1112290001Sglebiusstatic void 1113290001Sglebiusevhttp_deferred_read_cb(struct event_callback *cb, void *data) 1114290001Sglebius{ 1115290001Sglebius struct evhttp_connection *evcon = data; 1116290001Sglebius evhttp_read_cb(evcon->bufev, evcon); 1117290001Sglebius} 1118290001Sglebius 1119290001Sglebiusstatic void 1120290001Sglebiusevhttp_write_connectioncb(struct evhttp_connection *evcon, void *arg) 1121290001Sglebius{ 1122290001Sglebius /* This is after writing the request to the server */ 1123290001Sglebius struct evhttp_request *req = TAILQ_FIRST(&evcon->requests); 1124290001Sglebius EVUTIL_ASSERT(req != NULL); 1125290001Sglebius 1126290001Sglebius EVUTIL_ASSERT(evcon->state == EVCON_WRITING); 1127290001Sglebius 1128290001Sglebius /* We are done writing our header and are now expecting the response */ 1129290001Sglebius req->kind = EVHTTP_RESPONSE; 1130290001Sglebius 1131290001Sglebius evhttp_start_read_(evcon); 1132290001Sglebius} 1133290001Sglebius 1134290001Sglebius/* 1135290001Sglebius * Clean up a connection object 1136290001Sglebius */ 1137290001Sglebius 1138290001Sglebiusvoid 1139290001Sglebiusevhttp_connection_free(struct evhttp_connection *evcon) 1140290001Sglebius{ 1141290001Sglebius struct evhttp_request *req; 1142290001Sglebius 1143290001Sglebius /* notify interested parties that this connection is going down */ 1144290001Sglebius if (evcon->fd != -1) { 1145290001Sglebius if (evhttp_connected(evcon) && evcon->closecb != NULL) 1146290001Sglebius (*evcon->closecb)(evcon, evcon->closecb_arg); 1147290001Sglebius } 1148290001Sglebius 1149290001Sglebius /* remove all requests that might be queued on this 1150290001Sglebius * connection. for server connections, this should be empty. 1151290001Sglebius * because it gets dequeued either in evhttp_connection_done or 1152290001Sglebius * evhttp_connection_fail_. 1153290001Sglebius */ 1154290001Sglebius while ((req = TAILQ_FIRST(&evcon->requests)) != NULL) { 1155290001Sglebius TAILQ_REMOVE(&evcon->requests, req, next); 1156290001Sglebius evhttp_request_free(req); 1157290001Sglebius } 1158290001Sglebius 1159290001Sglebius if (evcon->http_server != NULL) { 1160290001Sglebius struct evhttp *http = evcon->http_server; 1161290001Sglebius TAILQ_REMOVE(&http->connections, evcon, next); 1162290001Sglebius } 1163290001Sglebius 1164290001Sglebius if (event_initialized(&evcon->retry_ev)) { 1165290001Sglebius event_del(&evcon->retry_ev); 1166290001Sglebius event_debug_unassign(&evcon->retry_ev); 1167290001Sglebius } 1168290001Sglebius 1169290001Sglebius if (evcon->bufev != NULL) 1170290001Sglebius bufferevent_free(evcon->bufev); 1171290001Sglebius 1172290001Sglebius event_deferred_cb_cancel_(get_deferred_queue(evcon), 1173290001Sglebius &evcon->read_more_deferred_cb); 1174290001Sglebius 1175290001Sglebius if (evcon->fd != -1) { 1176290001Sglebius shutdown(evcon->fd, EVUTIL_SHUT_WR); 1177290001Sglebius if (!(bufferevent_get_options_(evcon->bufev) & BEV_OPT_CLOSE_ON_FREE)) { 1178290001Sglebius evutil_closesocket(evcon->fd); 1179290001Sglebius } 1180290001Sglebius } 1181290001Sglebius 1182290001Sglebius if (evcon->bind_address != NULL) 1183290001Sglebius mm_free(evcon->bind_address); 1184290001Sglebius 1185290001Sglebius if (evcon->address != NULL) 1186290001Sglebius mm_free(evcon->address); 1187290001Sglebius 1188290001Sglebius if (evcon->conn_address != NULL) 1189290001Sglebius mm_free(evcon->conn_address); 1190290001Sglebius 1191290001Sglebius mm_free(evcon); 1192290001Sglebius} 1193290001Sglebius 1194290001Sglebiusvoid 1195290001Sglebiusevhttp_connection_free_on_completion(struct evhttp_connection *evcon) { 1196290001Sglebius evcon->flags |= EVHTTP_CON_AUTOFREE; 1197290001Sglebius} 1198290001Sglebius 1199290001Sglebiusvoid 1200290001Sglebiusevhttp_connection_set_local_address(struct evhttp_connection *evcon, 1201290001Sglebius const char *address) 1202290001Sglebius{ 1203290001Sglebius EVUTIL_ASSERT(evcon->state == EVCON_DISCONNECTED); 1204290001Sglebius if (evcon->bind_address) 1205290001Sglebius mm_free(evcon->bind_address); 1206290001Sglebius if ((evcon->bind_address = mm_strdup(address)) == NULL) 1207290001Sglebius event_warn("%s: strdup", __func__); 1208290001Sglebius} 1209290001Sglebius 1210290001Sglebiusvoid 1211290001Sglebiusevhttp_connection_set_local_port(struct evhttp_connection *evcon, 1212290001Sglebius ev_uint16_t port) 1213290001Sglebius{ 1214290001Sglebius EVUTIL_ASSERT(evcon->state == EVCON_DISCONNECTED); 1215290001Sglebius evcon->bind_port = port; 1216290001Sglebius} 1217290001Sglebius 1218290001Sglebiusstatic void 1219290001Sglebiusevhttp_request_dispatch(struct evhttp_connection* evcon) 1220290001Sglebius{ 1221290001Sglebius struct evhttp_request *req = TAILQ_FIRST(&evcon->requests); 1222290001Sglebius 1223290001Sglebius /* this should not usually happy but it's possible */ 1224290001Sglebius if (req == NULL) 1225290001Sglebius return; 1226290001Sglebius 1227290001Sglebius /* delete possible close detection events */ 1228290001Sglebius evhttp_connection_stop_detectclose(evcon); 1229290001Sglebius 1230290001Sglebius /* we assume that the connection is connected already */ 1231290001Sglebius EVUTIL_ASSERT(evcon->state == EVCON_IDLE); 1232290001Sglebius 1233290001Sglebius evcon->state = EVCON_WRITING; 1234290001Sglebius 1235290001Sglebius /* Create the header from the store arguments */ 1236290001Sglebius evhttp_make_header(evcon, req); 1237290001Sglebius 1238290001Sglebius evhttp_write_buffer(evcon, evhttp_write_connectioncb, NULL); 1239290001Sglebius} 1240290001Sglebius 1241290001Sglebius/* Reset our connection state: disables reading/writing, closes our fd (if 1242290001Sglebius* any), clears out buffers, and puts us in state DISCONNECTED. */ 1243290001Sglebiusvoid 1244290001Sglebiusevhttp_connection_reset_(struct evhttp_connection *evcon) 1245290001Sglebius{ 1246290001Sglebius struct evbuffer *tmp; 1247290001Sglebius 1248290001Sglebius /* XXXX This is not actually an optimal fix. Instead we ought to have 1249290001Sglebius an API for "stop connecting", or use bufferevent_setfd to turn off 1250290001Sglebius connecting. But for Libevent 2.0, this seems like a minimal change 1251290001Sglebius least likely to disrupt the rest of the bufferevent and http code. 1252290001Sglebius 1253290001Sglebius Why is this here? If the fd is set in the bufferevent, and the 1254290001Sglebius bufferevent is connecting, then you can't actually stop the 1255290001Sglebius bufferevent from trying to connect with bufferevent_disable(). The 1256290001Sglebius connect will never trigger, since we close the fd, but the timeout 1257290001Sglebius might. That caused an assertion failure in evhttp_connection_fail_. 1258290001Sglebius */ 1259290001Sglebius bufferevent_disable_hard_(evcon->bufev, EV_READ|EV_WRITE); 1260290001Sglebius 1261290001Sglebius if (evcon->fd != -1) { 1262290001Sglebius /* inform interested parties about connection close */ 1263290001Sglebius if (evhttp_connected(evcon) && evcon->closecb != NULL) 1264290001Sglebius (*evcon->closecb)(evcon, evcon->closecb_arg); 1265290001Sglebius 1266290001Sglebius shutdown(evcon->fd, EVUTIL_SHUT_WR); 1267290001Sglebius evutil_closesocket(evcon->fd); 1268290001Sglebius bufferevent_setfd(evcon->bufev, -1); 1269290001Sglebius evcon->fd = -1; 1270290001Sglebius } 1271290001Sglebius 1272290001Sglebius /* we need to clean up any buffered data */ 1273290001Sglebius tmp = bufferevent_get_output(evcon->bufev); 1274290001Sglebius evbuffer_drain(tmp, evbuffer_get_length(tmp)); 1275290001Sglebius tmp = bufferevent_get_input(evcon->bufev); 1276290001Sglebius evbuffer_drain(tmp, evbuffer_get_length(tmp)); 1277290001Sglebius 1278290001Sglebius evcon->state = EVCON_DISCONNECTED; 1279290001Sglebius} 1280290001Sglebius 1281290001Sglebiusstatic void 1282290001Sglebiusevhttp_connection_start_detectclose(struct evhttp_connection *evcon) 1283290001Sglebius{ 1284290001Sglebius evcon->flags |= EVHTTP_CON_CLOSEDETECT; 1285290001Sglebius 1286290001Sglebius bufferevent_enable(evcon->bufev, EV_READ); 1287290001Sglebius} 1288290001Sglebius 1289290001Sglebiusstatic void 1290290001Sglebiusevhttp_connection_stop_detectclose(struct evhttp_connection *evcon) 1291290001Sglebius{ 1292290001Sglebius evcon->flags &= ~EVHTTP_CON_CLOSEDETECT; 1293290001Sglebius 1294290001Sglebius bufferevent_disable(evcon->bufev, EV_READ); 1295290001Sglebius} 1296290001Sglebius 1297290001Sglebiusstatic void 1298290001Sglebiusevhttp_connection_retry(evutil_socket_t fd, short what, void *arg) 1299290001Sglebius{ 1300290001Sglebius struct evhttp_connection *evcon = arg; 1301290001Sglebius 1302290001Sglebius evcon->state = EVCON_DISCONNECTED; 1303290001Sglebius evhttp_connection_connect_(evcon); 1304290001Sglebius} 1305290001Sglebius 1306290001Sglebiusstatic void 1307290001Sglebiusevhttp_connection_cb_cleanup(struct evhttp_connection *evcon) 1308290001Sglebius{ 1309290001Sglebius struct evcon_requestq requests; 1310290001Sglebius 1311290001Sglebius evhttp_connection_reset_(evcon); 1312290001Sglebius if (evcon->retry_max < 0 || evcon->retry_cnt < evcon->retry_max) { 1313290001Sglebius struct timeval tv_retry = evcon->initial_retry_timeout; 1314290001Sglebius int i; 1315290001Sglebius evtimer_assign(&evcon->retry_ev, evcon->base, evhttp_connection_retry, evcon); 1316290001Sglebius /* XXXX handle failure from evhttp_add_event */ 1317290001Sglebius for (i=0; i < evcon->retry_cnt; ++i) { 1318290001Sglebius tv_retry.tv_usec *= 2; 1319290001Sglebius if (tv_retry.tv_usec > 1000000) { 1320290001Sglebius tv_retry.tv_usec -= 1000000; 1321290001Sglebius tv_retry.tv_sec += 1; 1322290001Sglebius } 1323290001Sglebius tv_retry.tv_sec *= 2; 1324290001Sglebius if (tv_retry.tv_sec > 3600) { 1325290001Sglebius tv_retry.tv_sec = 3600; 1326290001Sglebius tv_retry.tv_usec = 0; 1327290001Sglebius } 1328290001Sglebius } 1329290001Sglebius event_add(&evcon->retry_ev, &tv_retry); 1330290001Sglebius evcon->retry_cnt++; 1331290001Sglebius return; 1332290001Sglebius } 1333290001Sglebius 1334290001Sglebius /* 1335290001Sglebius * User callback can do evhttp_make_request() on the same 1336290001Sglebius * evcon so new request will be added to evcon->requests. To 1337290001Sglebius * avoid freeing it prematurely we iterate over the copy of 1338290001Sglebius * the queue. 1339290001Sglebius */ 1340290001Sglebius TAILQ_INIT(&requests); 1341290001Sglebius while (TAILQ_FIRST(&evcon->requests) != NULL) { 1342290001Sglebius struct evhttp_request *request = TAILQ_FIRST(&evcon->requests); 1343290001Sglebius TAILQ_REMOVE(&evcon->requests, request, next); 1344290001Sglebius TAILQ_INSERT_TAIL(&requests, request, next); 1345290001Sglebius } 1346290001Sglebius 1347290001Sglebius /* for now, we just signal all requests by executing their callbacks */ 1348290001Sglebius while (TAILQ_FIRST(&requests) != NULL) { 1349290001Sglebius struct evhttp_request *request = TAILQ_FIRST(&requests); 1350290001Sglebius TAILQ_REMOVE(&requests, request, next); 1351290001Sglebius request->evcon = NULL; 1352290001Sglebius 1353290001Sglebius /* we might want to set an error here */ 1354290001Sglebius request->cb(request, request->cb_arg); 1355290001Sglebius evhttp_request_free(request); 1356290001Sglebius } 1357290001Sglebius} 1358290001Sglebius 1359290001Sglebiusstatic void 1360290001Sglebiusevhttp_error_cb(struct bufferevent *bufev, short what, void *arg) 1361290001Sglebius{ 1362290001Sglebius struct evhttp_connection *evcon = arg; 1363290001Sglebius struct evhttp_request *req = TAILQ_FIRST(&evcon->requests); 1364290001Sglebius 1365290001Sglebius if (evcon->fd == -1) 1366290001Sglebius evcon->fd = bufferevent_getfd(bufev); 1367290001Sglebius 1368290001Sglebius switch (evcon->state) { 1369290001Sglebius case EVCON_CONNECTING: 1370290001Sglebius if (what & BEV_EVENT_TIMEOUT) { 1371290001Sglebius event_debug(("%s: connection timeout for \"%s:%d\" on " 1372290001Sglebius EV_SOCK_FMT, 1373290001Sglebius __func__, evcon->address, evcon->port, 1374290001Sglebius EV_SOCK_ARG(evcon->fd))); 1375290001Sglebius evhttp_connection_cb_cleanup(evcon); 1376290001Sglebius return; 1377290001Sglebius } 1378290001Sglebius break; 1379290001Sglebius 1380290001Sglebius case EVCON_READING_BODY: 1381290001Sglebius if (!req->chunked && req->ntoread < 0 1382290001Sglebius && what == (BEV_EVENT_READING|BEV_EVENT_EOF)) { 1383290001Sglebius /* EOF on read can be benign */ 1384290001Sglebius evhttp_connection_done(evcon); 1385290001Sglebius return; 1386290001Sglebius } 1387290001Sglebius break; 1388290001Sglebius 1389290001Sglebius case EVCON_DISCONNECTED: 1390290001Sglebius case EVCON_IDLE: 1391290001Sglebius case EVCON_READING_FIRSTLINE: 1392290001Sglebius case EVCON_READING_HEADERS: 1393290001Sglebius case EVCON_READING_TRAILER: 1394290001Sglebius case EVCON_WRITING: 1395290001Sglebius default: 1396290001Sglebius break; 1397290001Sglebius } 1398290001Sglebius 1399290001Sglebius /* when we are in close detect mode, a read error means that 1400290001Sglebius * the other side closed their connection. 1401290001Sglebius */ 1402290001Sglebius if (evcon->flags & EVHTTP_CON_CLOSEDETECT) { 1403290001Sglebius evcon->flags &= ~EVHTTP_CON_CLOSEDETECT; 1404290001Sglebius EVUTIL_ASSERT(evcon->http_server == NULL); 1405290001Sglebius /* For connections from the client, we just 1406290001Sglebius * reset the connection so that it becomes 1407290001Sglebius * disconnected. 1408290001Sglebius */ 1409290001Sglebius EVUTIL_ASSERT(evcon->state == EVCON_IDLE); 1410290001Sglebius evhttp_connection_reset_(evcon); 1411290001Sglebius 1412290001Sglebius /* 1413290001Sglebius * If we have no more requests that need completion 1414290001Sglebius * and we want to auto-free the connection when all 1415290001Sglebius * requests have been completed. 1416290001Sglebius */ 1417290001Sglebius if (TAILQ_FIRST(&evcon->requests) == NULL 1418290001Sglebius && (evcon->flags & EVHTTP_CON_OUTGOING) 1419290001Sglebius && (evcon->flags & EVHTTP_CON_AUTOFREE)) { 1420290001Sglebius evhttp_connection_free(evcon); 1421290001Sglebius } 1422290001Sglebius return; 1423290001Sglebius } 1424290001Sglebius 1425290001Sglebius if (what & BEV_EVENT_TIMEOUT) { 1426290001Sglebius evhttp_connection_fail_(evcon, EVREQ_HTTP_TIMEOUT); 1427290001Sglebius } else if (what & (BEV_EVENT_EOF|BEV_EVENT_ERROR)) { 1428290001Sglebius evhttp_connection_fail_(evcon, EVREQ_HTTP_EOF); 1429290001Sglebius } else if (what == BEV_EVENT_CONNECTED) { 1430290001Sglebius } else { 1431290001Sglebius evhttp_connection_fail_(evcon, EVREQ_HTTP_BUFFER_ERROR); 1432290001Sglebius } 1433290001Sglebius} 1434290001Sglebius 1435290001Sglebius/* 1436290001Sglebius * Event callback for asynchronous connection attempt. 1437290001Sglebius */ 1438290001Sglebiusstatic void 1439290001Sglebiusevhttp_connection_cb(struct bufferevent *bufev, short what, void *arg) 1440290001Sglebius{ 1441290001Sglebius struct evhttp_connection *evcon = arg; 1442290001Sglebius int error; 1443290001Sglebius ev_socklen_t errsz = sizeof(error); 1444290001Sglebius socklen_t conn_address_len = sizeof(*evcon->conn_address); 1445290001Sglebius 1446290001Sglebius if (evcon->fd == -1) 1447290001Sglebius evcon->fd = bufferevent_getfd(bufev); 1448290001Sglebius 1449290001Sglebius if (!(what & BEV_EVENT_CONNECTED)) { 1450290001Sglebius /* some operating systems return ECONNREFUSED immediately 1451290001Sglebius * when connecting to a local address. the cleanup is going 1452290001Sglebius * to reschedule this function call. 1453290001Sglebius */ 1454290001Sglebius#ifndef _WIN32 1455290001Sglebius if (errno == ECONNREFUSED) 1456290001Sglebius goto cleanup; 1457290001Sglebius#endif 1458290001Sglebius evhttp_error_cb(bufev, what, arg); 1459290001Sglebius return; 1460290001Sglebius } 1461290001Sglebius 1462290001Sglebius if (evcon->fd == -1) { 1463290001Sglebius event_debug(("%s: bufferevent_getfd returned -1", 1464290001Sglebius __func__)); 1465290001Sglebius goto cleanup; 1466290001Sglebius } 1467290001Sglebius 1468290001Sglebius /* Check if the connection completed */ 1469290001Sglebius if (getsockopt(evcon->fd, SOL_SOCKET, SO_ERROR, (void*)&error, 1470290001Sglebius &errsz) == -1) { 1471290001Sglebius event_debug(("%s: getsockopt for \"%s:%d\" on "EV_SOCK_FMT, 1472290001Sglebius __func__, evcon->address, evcon->port, 1473290001Sglebius EV_SOCK_ARG(evcon->fd))); 1474290001Sglebius goto cleanup; 1475290001Sglebius } 1476290001Sglebius 1477290001Sglebius if (error) { 1478290001Sglebius event_debug(("%s: connect failed for \"%s:%d\" on " 1479290001Sglebius EV_SOCK_FMT": %s", 1480290001Sglebius __func__, evcon->address, evcon->port, 1481290001Sglebius EV_SOCK_ARG(evcon->fd), 1482290001Sglebius evutil_socket_error_to_string(error))); 1483290001Sglebius goto cleanup; 1484290001Sglebius } 1485290001Sglebius 1486290001Sglebius /* We are connected to the server now */ 1487290001Sglebius event_debug(("%s: connected to \"%s:%d\" on "EV_SOCK_FMT"\n", 1488290001Sglebius __func__, evcon->address, evcon->port, 1489290001Sglebius EV_SOCK_ARG(evcon->fd))); 1490290001Sglebius 1491290001Sglebius /* Reset the retry count as we were successful in connecting */ 1492290001Sglebius evcon->retry_cnt = 0; 1493290001Sglebius evcon->state = EVCON_IDLE; 1494290001Sglebius 1495290001Sglebius if (!evcon->conn_address) { 1496290001Sglebius evcon->conn_address = mm_malloc(sizeof(*evcon->conn_address)); 1497290001Sglebius } 1498290001Sglebius if (getpeername(evcon->fd, (struct sockaddr *)evcon->conn_address, &conn_address_len)) { 1499290001Sglebius mm_free(evcon->conn_address); 1500290001Sglebius evcon->conn_address = NULL; 1501290001Sglebius } 1502290001Sglebius 1503290001Sglebius /* reset the bufferevent cbs */ 1504290001Sglebius bufferevent_setcb(evcon->bufev, 1505290001Sglebius evhttp_read_cb, 1506290001Sglebius evhttp_write_cb, 1507290001Sglebius evhttp_error_cb, 1508290001Sglebius evcon); 1509290001Sglebius 1510290001Sglebius if (!evutil_timerisset(&evcon->timeout)) { 1511290001Sglebius const struct timeval read_tv = { HTTP_READ_TIMEOUT, 0 }; 1512290001Sglebius const struct timeval write_tv = { HTTP_WRITE_TIMEOUT, 0 }; 1513290001Sglebius bufferevent_set_timeouts(evcon->bufev, &read_tv, &write_tv); 1514290001Sglebius } else { 1515290001Sglebius bufferevent_set_timeouts(evcon->bufev, &evcon->timeout, &evcon->timeout); 1516290001Sglebius } 1517290001Sglebius 1518290001Sglebius /* try to start requests that have queued up on this connection */ 1519290001Sglebius evhttp_request_dispatch(evcon); 1520290001Sglebius return; 1521290001Sglebius 1522290001Sglebius cleanup: 1523290001Sglebius evhttp_connection_cb_cleanup(evcon); 1524290001Sglebius} 1525290001Sglebius 1526290001Sglebius/* 1527290001Sglebius * Check if we got a valid response code. 1528290001Sglebius */ 1529290001Sglebius 1530290001Sglebiusstatic int 1531290001Sglebiusevhttp_valid_response_code(int code) 1532290001Sglebius{ 1533290001Sglebius if (code == 0) 1534290001Sglebius return (0); 1535290001Sglebius 1536290001Sglebius return (1); 1537290001Sglebius} 1538290001Sglebius 1539290001Sglebiusstatic int 1540290001Sglebiusevhttp_parse_http_version(const char *version, struct evhttp_request *req) 1541290001Sglebius{ 1542290001Sglebius int major, minor; 1543290001Sglebius char ch; 1544290001Sglebius int n = sscanf(version, "HTTP/%d.%d%c", &major, &minor, &ch); 1545290001Sglebius if (n != 2 || major > 1) { 1546290001Sglebius event_debug(("%s: bad version %s on message %p from %s", 1547290001Sglebius __func__, version, req, req->remote_host)); 1548290001Sglebius return (-1); 1549290001Sglebius } 1550290001Sglebius req->major = major; 1551290001Sglebius req->minor = minor; 1552290001Sglebius return (0); 1553290001Sglebius} 1554290001Sglebius 1555290001Sglebius/* Parses the status line of a web server */ 1556290001Sglebius 1557290001Sglebiusstatic int 1558290001Sglebiusevhttp_parse_response_line(struct evhttp_request *req, char *line) 1559290001Sglebius{ 1560290001Sglebius char *protocol; 1561290001Sglebius char *number; 1562290001Sglebius const char *readable = ""; 1563290001Sglebius 1564290001Sglebius protocol = strsep(&line, " "); 1565290001Sglebius if (line == NULL) 1566290001Sglebius return (-1); 1567290001Sglebius number = strsep(&line, " "); 1568290001Sglebius if (line != NULL) 1569290001Sglebius readable = line; 1570290001Sglebius 1571290001Sglebius if (evhttp_parse_http_version(protocol, req) < 0) 1572290001Sglebius return (-1); 1573290001Sglebius 1574290001Sglebius req->response_code = atoi(number); 1575290001Sglebius if (!evhttp_valid_response_code(req->response_code)) { 1576290001Sglebius event_debug(("%s: bad response code \"%s\"", 1577290001Sglebius __func__, number)); 1578290001Sglebius return (-1); 1579290001Sglebius } 1580290001Sglebius 1581290001Sglebius if ((req->response_code_line = mm_strdup(readable)) == NULL) { 1582290001Sglebius event_warn("%s: strdup", __func__); 1583290001Sglebius return (-1); 1584290001Sglebius } 1585290001Sglebius 1586290001Sglebius return (0); 1587290001Sglebius} 1588290001Sglebius 1589290001Sglebius/* Parse the first line of a HTTP request */ 1590290001Sglebius 1591290001Sglebiusstatic int 1592290001Sglebiusevhttp_parse_request_line(struct evhttp_request *req, char *line) 1593290001Sglebius{ 1594290001Sglebius char *method; 1595290001Sglebius char *uri; 1596290001Sglebius char *version; 1597290001Sglebius const char *hostname; 1598290001Sglebius const char *scheme; 1599290001Sglebius size_t method_len; 1600290001Sglebius enum evhttp_cmd_type type; 1601290001Sglebius 1602290001Sglebius /* Parse the request line */ 1603290001Sglebius method = strsep(&line, " "); 1604290001Sglebius if (line == NULL) 1605290001Sglebius return (-1); 1606290001Sglebius uri = strsep(&line, " "); 1607290001Sglebius if (line == NULL) 1608290001Sglebius return (-1); 1609290001Sglebius version = strsep(&line, " "); 1610290001Sglebius if (line != NULL) 1611290001Sglebius return (-1); 1612290001Sglebius 1613290001Sglebius method_len = (uri - method) - 1; 1614290001Sglebius type = EVHTTP_REQ_UNKNOWN_; 1615290001Sglebius 1616290001Sglebius /* First line */ 1617290001Sglebius switch (method_len) { 1618290001Sglebius case 3: 1619290001Sglebius /* The length of the method string is 3, meaning it can only be one of two methods: GET or PUT */ 1620290001Sglebius 1621290001Sglebius /* Since both GET and PUT share the same character 'T' at the end, 1622290001Sglebius * if the string doesn't have 'T', we can immediately determine this 1623290001Sglebius * is an invalid HTTP method */ 1624290001Sglebius 1625290001Sglebius if (method[2] != 'T') { 1626290001Sglebius break; 1627290001Sglebius } 1628290001Sglebius 1629290001Sglebius switch (*method) { 1630290001Sglebius case 'G': 1631290001Sglebius /* This first byte is 'G', so make sure the next byte is 1632290001Sglebius * 'E', if it isn't then this isn't a valid method */ 1633290001Sglebius 1634290001Sglebius if (method[1] == 'E') { 1635290001Sglebius type = EVHTTP_REQ_GET; 1636290001Sglebius } 1637290001Sglebius 1638290001Sglebius break; 1639290001Sglebius case 'P': 1640290001Sglebius /* First byte is P, check second byte for 'U', if not, 1641290001Sglebius * we know it's an invalid method */ 1642290001Sglebius if (method[1] == 'U') { 1643290001Sglebius type = EVHTTP_REQ_PUT; 1644290001Sglebius } 1645290001Sglebius break; 1646290001Sglebius default: 1647290001Sglebius break; 1648290001Sglebius } 1649290001Sglebius break; 1650290001Sglebius case 4: 1651290001Sglebius /* The method length is 4 bytes, leaving only the methods "POST" and "HEAD" */ 1652290001Sglebius switch (*method) { 1653290001Sglebius case 'P': 1654290001Sglebius if (method[3] == 'T' && method[2] == 'S' && method[1] == 'O') { 1655290001Sglebius type = EVHTTP_REQ_POST; 1656290001Sglebius } 1657290001Sglebius break; 1658290001Sglebius case 'H': 1659290001Sglebius if (method[3] == 'D' && method[2] == 'A' && method[1] == 'E') { 1660290001Sglebius type = EVHTTP_REQ_HEAD; 1661290001Sglebius } 1662290001Sglebius break; 1663290001Sglebius default: 1664290001Sglebius break; 1665290001Sglebius } 1666290001Sglebius break; 1667290001Sglebius case 5: 1668290001Sglebius /* Method length is 5 bytes, which can only encompass PATCH and TRACE */ 1669290001Sglebius switch (*method) { 1670290001Sglebius case 'P': 1671290001Sglebius if (method[4] == 'H' && method[3] == 'C' && method[2] == 'T' && method[1] == 'A') { 1672290001Sglebius type = EVHTTP_REQ_PATCH; 1673290001Sglebius } 1674290001Sglebius break; 1675290001Sglebius case 'T': 1676290001Sglebius if (method[4] == 'E' && method[3] == 'C' && method[2] == 'A' && method[1] == 'R') { 1677290001Sglebius type = EVHTTP_REQ_TRACE; 1678290001Sglebius } 1679290001Sglebius 1680290001Sglebius break; 1681290001Sglebius default: 1682290001Sglebius break; 1683290001Sglebius } 1684290001Sglebius break; 1685290001Sglebius case 6: 1686290001Sglebius /* Method length is 6, only valid method 6 bytes in length is DELEte */ 1687290001Sglebius 1688290001Sglebius /* If the first byte isn't 'D' then it's invalid */ 1689290001Sglebius if (*method != 'D') { 1690290001Sglebius break; 1691290001Sglebius } 1692290001Sglebius 1693290001Sglebius if (method[5] == 'E' && method[4] == 'T' && method[3] == 'E' && method[2] == 'L' && method[1] == 'E') { 1694290001Sglebius type = EVHTTP_REQ_DELETE; 1695290001Sglebius } 1696290001Sglebius 1697290001Sglebius break; 1698290001Sglebius case 7: 1699290001Sglebius /* Method length is 7, only valid methods are "OPTIONS" and "CONNECT" */ 1700290001Sglebius switch (*method) { 1701290001Sglebius case 'O': 1702290001Sglebius if (method[6] == 'S' && method[5] == 'N' && method[4] == 'O' && 1703290001Sglebius method[3] == 'I' && method[2] == 'T' && method[1] == 'P') { 1704290001Sglebius type = EVHTTP_REQ_OPTIONS; 1705290001Sglebius } 1706290001Sglebius 1707290001Sglebius break; 1708290001Sglebius case 'C': 1709290001Sglebius if (method[6] == 'T' && method[5] == 'C' && method[4] == 'E' && 1710290001Sglebius method[3] == 'N' && method[2] == 'N' && method[1] == 'O') { 1711290001Sglebius type = EVHTTP_REQ_CONNECT; 1712290001Sglebius } 1713290001Sglebius 1714290001Sglebius break; 1715290001Sglebius default: 1716290001Sglebius break; 1717290001Sglebius } 1718290001Sglebius break; 1719290001Sglebius } /* switch */ 1720290001Sglebius 1721290001Sglebius if ((int)type == EVHTTP_REQ_UNKNOWN_) { 1722290001Sglebius event_debug(("%s: bad method %s on request %p from %s", 1723290001Sglebius __func__, method, req, req->remote_host)); 1724290001Sglebius /* No error yet; we'll give a better error later when 1725290001Sglebius * we see that req->type is unsupported. */ 1726290001Sglebius } 1727290001Sglebius 1728290001Sglebius req->type = type; 1729290001Sglebius 1730290001Sglebius if (evhttp_parse_http_version(version, req) < 0) 1731290001Sglebius return (-1); 1732290001Sglebius 1733290001Sglebius if ((req->uri = mm_strdup(uri)) == NULL) { 1734290001Sglebius event_debug(("%s: mm_strdup", __func__)); 1735290001Sglebius return (-1); 1736290001Sglebius } 1737290001Sglebius 1738290001Sglebius if ((req->uri_elems = evhttp_uri_parse_with_flags(req->uri, 1739290001Sglebius EVHTTP_URI_NONCONFORMANT)) == NULL) { 1740290001Sglebius return -1; 1741290001Sglebius } 1742290001Sglebius 1743290001Sglebius /* If we have an absolute-URI, check to see if it is an http request 1744290001Sglebius for a known vhost or server alias. If we don't know about this 1745290001Sglebius host, we consider it a proxy request. */ 1746290001Sglebius scheme = evhttp_uri_get_scheme(req->uri_elems); 1747290001Sglebius hostname = evhttp_uri_get_host(req->uri_elems); 1748290001Sglebius if (scheme && (!evutil_ascii_strcasecmp(scheme, "http") || 1749290001Sglebius !evutil_ascii_strcasecmp(scheme, "https")) && 1750290001Sglebius hostname && 1751290001Sglebius !evhttp_find_vhost(req->evcon->http_server, NULL, hostname)) 1752290001Sglebius req->flags |= EVHTTP_PROXY_REQUEST; 1753290001Sglebius 1754290001Sglebius return (0); 1755290001Sglebius} 1756290001Sglebius 1757290001Sglebiusconst char * 1758290001Sglebiusevhttp_find_header(const struct evkeyvalq *headers, const char *key) 1759290001Sglebius{ 1760290001Sglebius struct evkeyval *header; 1761290001Sglebius 1762290001Sglebius TAILQ_FOREACH(header, headers, next) { 1763290001Sglebius if (evutil_ascii_strcasecmp(header->key, key) == 0) 1764290001Sglebius return (header->value); 1765290001Sglebius } 1766290001Sglebius 1767290001Sglebius return (NULL); 1768290001Sglebius} 1769290001Sglebius 1770290001Sglebiusvoid 1771290001Sglebiusevhttp_clear_headers(struct evkeyvalq *headers) 1772290001Sglebius{ 1773290001Sglebius struct evkeyval *header; 1774290001Sglebius 1775290001Sglebius for (header = TAILQ_FIRST(headers); 1776290001Sglebius header != NULL; 1777290001Sglebius header = TAILQ_FIRST(headers)) { 1778290001Sglebius TAILQ_REMOVE(headers, header, next); 1779290001Sglebius mm_free(header->key); 1780290001Sglebius mm_free(header->value); 1781290001Sglebius mm_free(header); 1782290001Sglebius } 1783290001Sglebius} 1784290001Sglebius 1785290001Sglebius/* 1786290001Sglebius * Returns 0, if the header was successfully removed. 1787290001Sglebius * Returns -1, if the header could not be found. 1788290001Sglebius */ 1789290001Sglebius 1790290001Sglebiusint 1791290001Sglebiusevhttp_remove_header(struct evkeyvalq *headers, const char *key) 1792290001Sglebius{ 1793290001Sglebius struct evkeyval *header; 1794290001Sglebius 1795290001Sglebius TAILQ_FOREACH(header, headers, next) { 1796290001Sglebius if (evutil_ascii_strcasecmp(header->key, key) == 0) 1797290001Sglebius break; 1798290001Sglebius } 1799290001Sglebius 1800290001Sglebius if (header == NULL) 1801290001Sglebius return (-1); 1802290001Sglebius 1803290001Sglebius /* Free and remove the header that we found */ 1804290001Sglebius TAILQ_REMOVE(headers, header, next); 1805290001Sglebius mm_free(header->key); 1806290001Sglebius mm_free(header->value); 1807290001Sglebius mm_free(header); 1808290001Sglebius 1809290001Sglebius return (0); 1810290001Sglebius} 1811290001Sglebius 1812290001Sglebiusstatic int 1813290001Sglebiusevhttp_header_is_valid_value(const char *value) 1814290001Sglebius{ 1815290001Sglebius const char *p = value; 1816290001Sglebius 1817290001Sglebius while ((p = strpbrk(p, "\r\n")) != NULL) { 1818290001Sglebius /* we really expect only one new line */ 1819290001Sglebius p += strspn(p, "\r\n"); 1820290001Sglebius /* we expect a space or tab for continuation */ 1821290001Sglebius if (*p != ' ' && *p != '\t') 1822290001Sglebius return (0); 1823290001Sglebius } 1824290001Sglebius return (1); 1825290001Sglebius} 1826290001Sglebius 1827290001Sglebiusint 1828290001Sglebiusevhttp_add_header(struct evkeyvalq *headers, 1829290001Sglebius const char *key, const char *value) 1830290001Sglebius{ 1831290001Sglebius event_debug(("%s: key: %s val: %s\n", __func__, key, value)); 1832290001Sglebius 1833290001Sglebius if (strchr(key, '\r') != NULL || strchr(key, '\n') != NULL) { 1834290001Sglebius /* drop illegal headers */ 1835290001Sglebius event_debug(("%s: dropping illegal header key\n", __func__)); 1836290001Sglebius return (-1); 1837290001Sglebius } 1838290001Sglebius 1839290001Sglebius if (!evhttp_header_is_valid_value(value)) { 1840290001Sglebius event_debug(("%s: dropping illegal header value\n", __func__)); 1841290001Sglebius return (-1); 1842290001Sglebius } 1843290001Sglebius 1844290001Sglebius return (evhttp_add_header_internal(headers, key, value)); 1845290001Sglebius} 1846290001Sglebius 1847290001Sglebiusstatic int 1848290001Sglebiusevhttp_add_header_internal(struct evkeyvalq *headers, 1849290001Sglebius const char *key, const char *value) 1850290001Sglebius{ 1851290001Sglebius struct evkeyval *header = mm_calloc(1, sizeof(struct evkeyval)); 1852290001Sglebius if (header == NULL) { 1853290001Sglebius event_warn("%s: calloc", __func__); 1854290001Sglebius return (-1); 1855290001Sglebius } 1856290001Sglebius if ((header->key = mm_strdup(key)) == NULL) { 1857290001Sglebius mm_free(header); 1858290001Sglebius event_warn("%s: strdup", __func__); 1859290001Sglebius return (-1); 1860290001Sglebius } 1861290001Sglebius if ((header->value = mm_strdup(value)) == NULL) { 1862290001Sglebius mm_free(header->key); 1863290001Sglebius mm_free(header); 1864290001Sglebius event_warn("%s: strdup", __func__); 1865290001Sglebius return (-1); 1866290001Sglebius } 1867290001Sglebius 1868290001Sglebius TAILQ_INSERT_TAIL(headers, header, next); 1869290001Sglebius 1870290001Sglebius return (0); 1871290001Sglebius} 1872290001Sglebius 1873290001Sglebius/* 1874290001Sglebius * Parses header lines from a request or a response into the specified 1875290001Sglebius * request object given an event buffer. 1876290001Sglebius * 1877290001Sglebius * Returns 1878290001Sglebius * DATA_CORRUPTED on error 1879290001Sglebius * MORE_DATA_EXPECTED when we need to read more headers 1880290001Sglebius * ALL_DATA_READ when all headers have been read. 1881290001Sglebius */ 1882290001Sglebius 1883290001Sglebiusenum message_read_status 1884290001Sglebiusevhttp_parse_firstline_(struct evhttp_request *req, struct evbuffer *buffer) 1885290001Sglebius{ 1886290001Sglebius char *line; 1887290001Sglebius enum message_read_status status = ALL_DATA_READ; 1888290001Sglebius 1889290001Sglebius size_t line_length; 1890290001Sglebius /* XXX try */ 1891290001Sglebius line = evbuffer_readln(buffer, &line_length, EVBUFFER_EOL_CRLF); 1892290001Sglebius if (line == NULL) { 1893290001Sglebius if (req->evcon != NULL && 1894290001Sglebius evbuffer_get_length(buffer) > req->evcon->max_headers_size) 1895290001Sglebius return (DATA_TOO_LONG); 1896290001Sglebius else 1897290001Sglebius return (MORE_DATA_EXPECTED); 1898290001Sglebius } 1899290001Sglebius 1900290001Sglebius if (req->evcon != NULL && 1901290001Sglebius line_length > req->evcon->max_headers_size) { 1902290001Sglebius mm_free(line); 1903290001Sglebius return (DATA_TOO_LONG); 1904290001Sglebius } 1905290001Sglebius 1906290001Sglebius req->headers_size = line_length; 1907290001Sglebius 1908290001Sglebius switch (req->kind) { 1909290001Sglebius case EVHTTP_REQUEST: 1910290001Sglebius if (evhttp_parse_request_line(req, line) == -1) 1911290001Sglebius status = DATA_CORRUPTED; 1912290001Sglebius break; 1913290001Sglebius case EVHTTP_RESPONSE: 1914290001Sglebius if (evhttp_parse_response_line(req, line) == -1) 1915290001Sglebius status = DATA_CORRUPTED; 1916290001Sglebius break; 1917290001Sglebius default: 1918290001Sglebius status = DATA_CORRUPTED; 1919290001Sglebius } 1920290001Sglebius 1921290001Sglebius mm_free(line); 1922290001Sglebius return (status); 1923290001Sglebius} 1924290001Sglebius 1925290001Sglebiusstatic int 1926290001Sglebiusevhttp_append_to_last_header(struct evkeyvalq *headers, char *line) 1927290001Sglebius{ 1928290001Sglebius struct evkeyval *header = TAILQ_LAST(headers, evkeyvalq); 1929290001Sglebius char *newval; 1930290001Sglebius size_t old_len, line_len; 1931290001Sglebius 1932290001Sglebius if (header == NULL) 1933290001Sglebius return (-1); 1934290001Sglebius 1935290001Sglebius old_len = strlen(header->value); 1936290001Sglebius 1937290001Sglebius /* Strip space from start and end of line. */ 1938290001Sglebius while (*line == ' ' || *line == '\t') 1939290001Sglebius ++line; 1940290001Sglebius evutil_rtrim_lws_(line); 1941290001Sglebius 1942290001Sglebius line_len = strlen(line); 1943290001Sglebius 1944290001Sglebius newval = mm_realloc(header->value, old_len + line_len + 2); 1945290001Sglebius if (newval == NULL) 1946290001Sglebius return (-1); 1947290001Sglebius 1948290001Sglebius newval[old_len] = ' '; 1949290001Sglebius memcpy(newval + old_len + 1, line, line_len + 1); 1950290001Sglebius header->value = newval; 1951290001Sglebius 1952290001Sglebius return (0); 1953290001Sglebius} 1954290001Sglebius 1955290001Sglebiusenum message_read_status 1956290001Sglebiusevhttp_parse_headers_(struct evhttp_request *req, struct evbuffer* buffer) 1957290001Sglebius{ 1958290001Sglebius enum message_read_status errcode = DATA_CORRUPTED; 1959290001Sglebius char *line; 1960290001Sglebius enum message_read_status status = MORE_DATA_EXPECTED; 1961290001Sglebius 1962290001Sglebius struct evkeyvalq* headers = req->input_headers; 1963290001Sglebius size_t line_length; 1964290001Sglebius while ((line = evbuffer_readln(buffer, &line_length, EVBUFFER_EOL_CRLF)) 1965290001Sglebius != NULL) { 1966290001Sglebius char *skey, *svalue; 1967290001Sglebius 1968290001Sglebius req->headers_size += line_length; 1969290001Sglebius 1970290001Sglebius if (req->evcon != NULL && 1971290001Sglebius req->headers_size > req->evcon->max_headers_size) { 1972290001Sglebius errcode = DATA_TOO_LONG; 1973290001Sglebius goto error; 1974290001Sglebius } 1975290001Sglebius 1976290001Sglebius if (*line == '\0') { /* Last header - Done */ 1977290001Sglebius status = ALL_DATA_READ; 1978290001Sglebius mm_free(line); 1979290001Sglebius break; 1980290001Sglebius } 1981290001Sglebius 1982290001Sglebius /* Check if this is a continuation line */ 1983290001Sglebius if (*line == ' ' || *line == '\t') { 1984290001Sglebius if (evhttp_append_to_last_header(headers, line) == -1) 1985290001Sglebius goto error; 1986290001Sglebius mm_free(line); 1987290001Sglebius continue; 1988290001Sglebius } 1989290001Sglebius 1990290001Sglebius /* Processing of header lines */ 1991290001Sglebius svalue = line; 1992290001Sglebius skey = strsep(&svalue, ":"); 1993290001Sglebius if (svalue == NULL) 1994290001Sglebius goto error; 1995290001Sglebius 1996290001Sglebius svalue += strspn(svalue, " "); 1997290001Sglebius evutil_rtrim_lws_(svalue); 1998290001Sglebius 1999290001Sglebius if (evhttp_add_header(headers, skey, svalue) == -1) 2000290001Sglebius goto error; 2001290001Sglebius 2002290001Sglebius mm_free(line); 2003290001Sglebius } 2004290001Sglebius 2005290001Sglebius if (status == MORE_DATA_EXPECTED) { 2006290001Sglebius if (req->evcon != NULL && 2007290001Sglebius req->headers_size + evbuffer_get_length(buffer) > req->evcon->max_headers_size) 2008290001Sglebius return (DATA_TOO_LONG); 2009290001Sglebius } 2010290001Sglebius 2011290001Sglebius return (status); 2012290001Sglebius 2013290001Sglebius error: 2014290001Sglebius mm_free(line); 2015290001Sglebius return (errcode); 2016290001Sglebius} 2017290001Sglebius 2018290001Sglebiusstatic int 2019290001Sglebiusevhttp_get_body_length(struct evhttp_request *req) 2020290001Sglebius{ 2021290001Sglebius struct evkeyvalq *headers = req->input_headers; 2022290001Sglebius const char *content_length; 2023290001Sglebius const char *connection; 2024290001Sglebius 2025290001Sglebius content_length = evhttp_find_header(headers, "Content-Length"); 2026290001Sglebius connection = evhttp_find_header(headers, "Connection"); 2027290001Sglebius 2028290001Sglebius if (content_length == NULL && connection == NULL) 2029290001Sglebius req->ntoread = -1; 2030290001Sglebius else if (content_length == NULL && 2031290001Sglebius evutil_ascii_strcasecmp(connection, "Close") != 0) { 2032290001Sglebius /* Bad combination, we don't know when it will end */ 2033290001Sglebius event_warnx("%s: we got no content length, but the " 2034290001Sglebius "server wants to keep the connection open: %s.", 2035290001Sglebius __func__, connection); 2036290001Sglebius return (-1); 2037290001Sglebius } else if (content_length == NULL) { 2038290001Sglebius req->ntoread = -1; 2039290001Sglebius } else { 2040290001Sglebius char *endp; 2041290001Sglebius ev_int64_t ntoread = evutil_strtoll(content_length, &endp, 10); 2042290001Sglebius if (*content_length == '\0' || *endp != '\0' || ntoread < 0) { 2043290001Sglebius event_debug(("%s: illegal content length: %s", 2044290001Sglebius __func__, content_length)); 2045290001Sglebius return (-1); 2046290001Sglebius } 2047290001Sglebius req->ntoread = ntoread; 2048290001Sglebius } 2049290001Sglebius 2050290001Sglebius event_debug(("%s: bytes to read: "EV_I64_FMT" (in buffer "EV_SIZE_FMT")\n", 2051290001Sglebius __func__, EV_I64_ARG(req->ntoread), 2052290001Sglebius EV_SIZE_ARG(evbuffer_get_length(bufferevent_get_input(req->evcon->bufev))))); 2053290001Sglebius 2054290001Sglebius return (0); 2055290001Sglebius} 2056290001Sglebius 2057290001Sglebiusstatic int 2058290001Sglebiusevhttp_method_may_have_body(enum evhttp_cmd_type type) 2059290001Sglebius{ 2060290001Sglebius switch (type) { 2061290001Sglebius case EVHTTP_REQ_POST: 2062290001Sglebius case EVHTTP_REQ_PUT: 2063290001Sglebius case EVHTTP_REQ_PATCH: 2064290001Sglebius return 1; 2065290001Sglebius case EVHTTP_REQ_TRACE: 2066290001Sglebius return 0; 2067290001Sglebius /* XXX May any of the below methods have a body? */ 2068290001Sglebius case EVHTTP_REQ_GET: 2069290001Sglebius case EVHTTP_REQ_HEAD: 2070290001Sglebius case EVHTTP_REQ_DELETE: 2071290001Sglebius case EVHTTP_REQ_OPTIONS: 2072290001Sglebius case EVHTTP_REQ_CONNECT: 2073290001Sglebius return 0; 2074290001Sglebius default: 2075290001Sglebius return 0; 2076290001Sglebius } 2077290001Sglebius} 2078290001Sglebius 2079290001Sglebiusstatic void 2080290001Sglebiusevhttp_get_body(struct evhttp_connection *evcon, struct evhttp_request *req) 2081290001Sglebius{ 2082290001Sglebius const char *xfer_enc; 2083290001Sglebius 2084290001Sglebius /* If this is a request without a body, then we are done */ 2085290001Sglebius if (req->kind == EVHTTP_REQUEST && 2086290001Sglebius !evhttp_method_may_have_body(req->type)) { 2087290001Sglebius evhttp_connection_done(evcon); 2088290001Sglebius return; 2089290001Sglebius } 2090290001Sglebius evcon->state = EVCON_READING_BODY; 2091290001Sglebius xfer_enc = evhttp_find_header(req->input_headers, "Transfer-Encoding"); 2092290001Sglebius if (xfer_enc != NULL && evutil_ascii_strcasecmp(xfer_enc, "chunked") == 0) { 2093290001Sglebius req->chunked = 1; 2094290001Sglebius req->ntoread = -1; 2095290001Sglebius } else { 2096290001Sglebius if (evhttp_get_body_length(req) == -1) { 2097290001Sglebius evhttp_connection_fail_(evcon, 2098290001Sglebius EVREQ_HTTP_INVALID_HEADER); 2099290001Sglebius return; 2100290001Sglebius } 2101290001Sglebius if (req->kind == EVHTTP_REQUEST && req->ntoread < 1) { 2102290001Sglebius /* An incoming request with no content-length and no 2103290001Sglebius * transfer-encoding has no body. */ 2104290001Sglebius evhttp_connection_done(evcon); 2105290001Sglebius return; 2106290001Sglebius } 2107290001Sglebius } 2108290001Sglebius 2109290001Sglebius /* Should we send a 100 Continue status line? */ 2110290001Sglebius if (req->kind == EVHTTP_REQUEST && REQ_VERSION_ATLEAST(req, 1, 1)) { 2111290001Sglebius const char *expect; 2112290001Sglebius 2113290001Sglebius expect = evhttp_find_header(req->input_headers, "Expect"); 2114290001Sglebius if (expect) { 2115290001Sglebius if (!evutil_ascii_strcasecmp(expect, "100-continue")) { 2116290001Sglebius /* XXX It would be nice to do some sanity 2117290001Sglebius checking here. Does the resource exist? 2118290001Sglebius Should the resource accept post requests? If 2119290001Sglebius no, we should respond with an error. For 2120290001Sglebius now, just optimistically tell the client to 2121290001Sglebius send their message body. */ 2122290001Sglebius if (req->ntoread > 0) { 2123290001Sglebius /* ntoread is ev_int64_t, max_body_size is ev_uint64_t */ 2124290001Sglebius if ((req->evcon->max_body_size <= EV_INT64_MAX) && (ev_uint64_t)req->ntoread > req->evcon->max_body_size) { 2125290001Sglebius evhttp_send_error(req, HTTP_ENTITYTOOLARGE, NULL); 2126290001Sglebius return; 2127290001Sglebius } 2128290001Sglebius } 2129290001Sglebius if (!evbuffer_get_length(bufferevent_get_input(evcon->bufev))) 2130290001Sglebius evhttp_send_continue(evcon, req); 2131290001Sglebius } else { 2132290001Sglebius evhttp_send_error(req, HTTP_EXPECTATIONFAILED, 2133290001Sglebius NULL); 2134290001Sglebius return; 2135290001Sglebius } 2136290001Sglebius } 2137290001Sglebius } 2138290001Sglebius 2139290001Sglebius evhttp_read_body(evcon, req); 2140290001Sglebius /* note the request may have been freed in evhttp_read_body */ 2141290001Sglebius} 2142290001Sglebius 2143290001Sglebiusstatic void 2144290001Sglebiusevhttp_read_firstline(struct evhttp_connection *evcon, 2145290001Sglebius struct evhttp_request *req) 2146290001Sglebius{ 2147290001Sglebius enum message_read_status res; 2148290001Sglebius 2149290001Sglebius res = evhttp_parse_firstline_(req, bufferevent_get_input(evcon->bufev)); 2150290001Sglebius if (res == DATA_CORRUPTED || res == DATA_TOO_LONG) { 2151290001Sglebius /* Error while reading, terminate */ 2152290001Sglebius event_debug(("%s: bad header lines on "EV_SOCK_FMT"\n", 2153290001Sglebius __func__, EV_SOCK_ARG(evcon->fd))); 2154290001Sglebius evhttp_connection_fail_(evcon, EVREQ_HTTP_INVALID_HEADER); 2155290001Sglebius return; 2156290001Sglebius } else if (res == MORE_DATA_EXPECTED) { 2157290001Sglebius /* Need more header lines */ 2158290001Sglebius return; 2159290001Sglebius } 2160290001Sglebius 2161290001Sglebius evcon->state = EVCON_READING_HEADERS; 2162290001Sglebius evhttp_read_header(evcon, req); 2163290001Sglebius} 2164290001Sglebius 2165290001Sglebiusstatic void 2166290001Sglebiusevhttp_read_header(struct evhttp_connection *evcon, 2167290001Sglebius struct evhttp_request *req) 2168290001Sglebius{ 2169290001Sglebius enum message_read_status res; 2170290001Sglebius evutil_socket_t fd = evcon->fd; 2171290001Sglebius 2172290001Sglebius res = evhttp_parse_headers_(req, bufferevent_get_input(evcon->bufev)); 2173290001Sglebius if (res == DATA_CORRUPTED || res == DATA_TOO_LONG) { 2174290001Sglebius /* Error while reading, terminate */ 2175290001Sglebius event_debug(("%s: bad header lines on "EV_SOCK_FMT"\n", 2176290001Sglebius __func__, EV_SOCK_ARG(fd))); 2177290001Sglebius evhttp_connection_fail_(evcon, EVREQ_HTTP_INVALID_HEADER); 2178290001Sglebius return; 2179290001Sglebius } else if (res == MORE_DATA_EXPECTED) { 2180290001Sglebius /* Need more header lines */ 2181290001Sglebius return; 2182290001Sglebius } 2183290001Sglebius 2184290001Sglebius /* Disable reading for now */ 2185290001Sglebius bufferevent_disable(evcon->bufev, EV_READ); 2186290001Sglebius 2187290001Sglebius /* Callback can shut down connection with negative return value */ 2188290001Sglebius if (req->header_cb != NULL) { 2189290001Sglebius if ((*req->header_cb)(req, req->cb_arg) < 0) { 2190290001Sglebius evhttp_connection_fail_(evcon, EVREQ_HTTP_EOF); 2191290001Sglebius return; 2192290001Sglebius } 2193290001Sglebius } 2194290001Sglebius 2195290001Sglebius /* Done reading headers, do the real work */ 2196290001Sglebius switch (req->kind) { 2197290001Sglebius case EVHTTP_REQUEST: 2198290001Sglebius event_debug(("%s: checking for post data on "EV_SOCK_FMT"\n", 2199290001Sglebius __func__, EV_SOCK_ARG(fd))); 2200290001Sglebius evhttp_get_body(evcon, req); 2201290001Sglebius /* note the request may have been freed in evhttp_get_body */ 2202290001Sglebius break; 2203290001Sglebius 2204290001Sglebius case EVHTTP_RESPONSE: 2205290001Sglebius /* Start over if we got a 100 Continue response. */ 2206290001Sglebius if (req->response_code == 100) { 2207290001Sglebius evhttp_start_read_(evcon); 2208290001Sglebius return; 2209290001Sglebius } 2210290001Sglebius if (!evhttp_response_needs_body(req)) { 2211290001Sglebius event_debug(("%s: skipping body for code %d\n", 2212290001Sglebius __func__, req->response_code)); 2213290001Sglebius evhttp_connection_done(evcon); 2214290001Sglebius } else { 2215290001Sglebius event_debug(("%s: start of read body for %s on " 2216290001Sglebius EV_SOCK_FMT"\n", 2217290001Sglebius __func__, req->remote_host, EV_SOCK_ARG(fd))); 2218290001Sglebius evhttp_get_body(evcon, req); 2219290001Sglebius /* note the request may have been freed in 2220290001Sglebius * evhttp_get_body */ 2221290001Sglebius } 2222290001Sglebius break; 2223290001Sglebius 2224290001Sglebius default: 2225290001Sglebius event_warnx("%s: bad header on "EV_SOCK_FMT, __func__, 2226290001Sglebius EV_SOCK_ARG(fd)); 2227290001Sglebius evhttp_connection_fail_(evcon, EVREQ_HTTP_INVALID_HEADER); 2228290001Sglebius break; 2229290001Sglebius } 2230290001Sglebius /* request may have been freed above */ 2231290001Sglebius} 2232290001Sglebius 2233290001Sglebius/* 2234290001Sglebius * Creates a TCP connection to the specified port and executes a callback 2235290001Sglebius * when finished. Failure or success is indicate by the passed connection 2236290001Sglebius * object. 2237290001Sglebius * 2238290001Sglebius * Although this interface accepts a hostname, it is intended to take 2239290001Sglebius * only numeric hostnames so that non-blocking DNS resolution can 2240290001Sglebius * happen elsewhere. 2241290001Sglebius */ 2242290001Sglebius 2243290001Sglebiusstruct evhttp_connection * 2244290001Sglebiusevhttp_connection_new(const char *address, unsigned short port) 2245290001Sglebius{ 2246290001Sglebius return (evhttp_connection_base_new(NULL, NULL, address, port)); 2247290001Sglebius} 2248290001Sglebius 2249290001Sglebiusstruct evhttp_connection * 2250290001Sglebiusevhttp_connection_base_bufferevent_new(struct event_base *base, struct evdns_base *dnsbase, struct bufferevent* bev, 2251290001Sglebius const char *address, unsigned short port) 2252290001Sglebius{ 2253290001Sglebius struct evhttp_connection *evcon = NULL; 2254290001Sglebius 2255290001Sglebius event_debug(("Attempting connection to %s:%d\n", address, port)); 2256290001Sglebius 2257290001Sglebius if ((evcon = mm_calloc(1, sizeof(struct evhttp_connection))) == NULL) { 2258290001Sglebius event_warn("%s: calloc failed", __func__); 2259290001Sglebius goto error; 2260290001Sglebius } 2261290001Sglebius 2262290001Sglebius evcon->fd = -1; 2263290001Sglebius evcon->port = port; 2264290001Sglebius 2265290001Sglebius evcon->max_headers_size = EV_SIZE_MAX; 2266290001Sglebius evcon->max_body_size = EV_SIZE_MAX; 2267290001Sglebius 2268290001Sglebius evutil_timerclear(&evcon->timeout); 2269290001Sglebius evcon->retry_cnt = evcon->retry_max = 0; 2270290001Sglebius 2271290001Sglebius if ((evcon->address = mm_strdup(address)) == NULL) { 2272290001Sglebius event_warn("%s: strdup failed", __func__); 2273290001Sglebius goto error; 2274290001Sglebius } 2275290001Sglebius 2276290001Sglebius if (bev == NULL) { 2277290001Sglebius if (!(bev = bufferevent_socket_new(base, -1, 0))) { 2278290001Sglebius event_warn("%s: bufferevent_socket_new failed", __func__); 2279290001Sglebius goto error; 2280290001Sglebius } 2281290001Sglebius } 2282290001Sglebius 2283290001Sglebius bufferevent_setcb(bev, evhttp_read_cb, evhttp_write_cb, evhttp_error_cb, evcon); 2284290001Sglebius evcon->bufev = bev; 2285290001Sglebius 2286290001Sglebius evcon->state = EVCON_DISCONNECTED; 2287290001Sglebius TAILQ_INIT(&evcon->requests); 2288290001Sglebius 2289290001Sglebius evcon->initial_retry_timeout.tv_sec = 2; 2290290001Sglebius evcon->initial_retry_timeout.tv_usec = 0; 2291290001Sglebius 2292290001Sglebius if (base != NULL) { 2293290001Sglebius evcon->base = base; 2294290001Sglebius if (bufferevent_get_base(bev) != base) 2295290001Sglebius bufferevent_base_set(base, evcon->bufev); 2296290001Sglebius } 2297290001Sglebius 2298290001Sglebius event_deferred_cb_init_( 2299290001Sglebius &evcon->read_more_deferred_cb, 2300290001Sglebius bufferevent_get_priority(bev), 2301290001Sglebius evhttp_deferred_read_cb, evcon); 2302290001Sglebius 2303290001Sglebius evcon->dns_base = dnsbase; 2304290001Sglebius evcon->ai_family = AF_UNSPEC; 2305290001Sglebius 2306290001Sglebius return (evcon); 2307290001Sglebius 2308290001Sglebius error: 2309290001Sglebius if (evcon != NULL) 2310290001Sglebius evhttp_connection_free(evcon); 2311290001Sglebius return (NULL); 2312290001Sglebius} 2313290001Sglebius 2314290001Sglebiusstruct bufferevent* evhttp_connection_get_bufferevent(struct evhttp_connection *evcon) 2315290001Sglebius{ 2316290001Sglebius return evcon->bufev; 2317290001Sglebius} 2318290001Sglebius 2319290001Sglebiusstruct evhttp * 2320290001Sglebiusevhttp_connection_get_server(struct evhttp_connection *evcon) 2321290001Sglebius{ 2322290001Sglebius return evcon->http_server; 2323290001Sglebius} 2324290001Sglebius 2325290001Sglebiusstruct evhttp_connection * 2326290001Sglebiusevhttp_connection_base_new(struct event_base *base, struct evdns_base *dnsbase, 2327290001Sglebius const char *address, unsigned short port) 2328290001Sglebius{ 2329290001Sglebius return evhttp_connection_base_bufferevent_new(base, dnsbase, NULL, address, port); 2330290001Sglebius} 2331290001Sglebius 2332290001Sglebiusvoid evhttp_connection_set_family(struct evhttp_connection *evcon, 2333290001Sglebius int family) 2334290001Sglebius{ 2335290001Sglebius evcon->ai_family = family; 2336290001Sglebius} 2337290001Sglebius 2338290001Sglebiusvoid 2339290001Sglebiusevhttp_connection_set_base(struct evhttp_connection *evcon, 2340290001Sglebius struct event_base *base) 2341290001Sglebius{ 2342290001Sglebius EVUTIL_ASSERT(evcon->base == NULL); 2343290001Sglebius EVUTIL_ASSERT(evcon->state == EVCON_DISCONNECTED); 2344290001Sglebius evcon->base = base; 2345290001Sglebius bufferevent_base_set(base, evcon->bufev); 2346290001Sglebius} 2347290001Sglebius 2348290001Sglebiusvoid 2349290001Sglebiusevhttp_connection_set_timeout(struct evhttp_connection *evcon, 2350290001Sglebius int timeout_in_secs) 2351290001Sglebius{ 2352290001Sglebius if (timeout_in_secs == -1) 2353290001Sglebius evhttp_connection_set_timeout_tv(evcon, NULL); 2354290001Sglebius else { 2355290001Sglebius struct timeval tv; 2356290001Sglebius tv.tv_sec = timeout_in_secs; 2357290001Sglebius tv.tv_usec = 0; 2358290001Sglebius evhttp_connection_set_timeout_tv(evcon, &tv); 2359290001Sglebius } 2360290001Sglebius} 2361290001Sglebius 2362290001Sglebiusvoid 2363290001Sglebiusevhttp_connection_set_timeout_tv(struct evhttp_connection *evcon, 2364290001Sglebius const struct timeval* tv) 2365290001Sglebius{ 2366290001Sglebius if (tv) { 2367290001Sglebius evcon->timeout = *tv; 2368290001Sglebius bufferevent_set_timeouts(evcon->bufev, &evcon->timeout, &evcon->timeout); 2369290001Sglebius } else { 2370290001Sglebius const struct timeval read_tv = { HTTP_READ_TIMEOUT, 0 }; 2371290001Sglebius const struct timeval write_tv = { HTTP_WRITE_TIMEOUT, 0 }; 2372290001Sglebius evutil_timerclear(&evcon->timeout); 2373290001Sglebius bufferevent_set_timeouts(evcon->bufev, &read_tv, &write_tv); 2374290001Sglebius } 2375290001Sglebius} 2376290001Sglebius 2377290001Sglebiusvoid 2378290001Sglebiusevhttp_connection_set_initial_retry_tv(struct evhttp_connection *evcon, 2379290001Sglebius const struct timeval *tv) 2380290001Sglebius{ 2381290001Sglebius if (tv) { 2382290001Sglebius evcon->initial_retry_timeout = *tv; 2383290001Sglebius } else { 2384290001Sglebius evutil_timerclear(&evcon->initial_retry_timeout); 2385290001Sglebius evcon->initial_retry_timeout.tv_sec = 2; 2386290001Sglebius } 2387290001Sglebius} 2388290001Sglebius 2389290001Sglebiusvoid 2390290001Sglebiusevhttp_connection_set_retries(struct evhttp_connection *evcon, 2391290001Sglebius int retry_max) 2392290001Sglebius{ 2393290001Sglebius evcon->retry_max = retry_max; 2394290001Sglebius} 2395290001Sglebius 2396290001Sglebiusvoid 2397290001Sglebiusevhttp_connection_set_closecb(struct evhttp_connection *evcon, 2398290001Sglebius void (*cb)(struct evhttp_connection *, void *), void *cbarg) 2399290001Sglebius{ 2400290001Sglebius evcon->closecb = cb; 2401290001Sglebius evcon->closecb_arg = cbarg; 2402290001Sglebius} 2403290001Sglebius 2404290001Sglebiusvoid 2405290001Sglebiusevhttp_connection_get_peer(struct evhttp_connection *evcon, 2406290001Sglebius char **address, ev_uint16_t *port) 2407290001Sglebius{ 2408290001Sglebius *address = evcon->address; 2409290001Sglebius *port = evcon->port; 2410290001Sglebius} 2411290001Sglebius 2412290001Sglebiusconst struct sockaddr* 2413290001Sglebiusevhttp_connection_get_addr(struct evhttp_connection *evcon) 2414290001Sglebius{ 2415290001Sglebius return (struct sockaddr *)evcon->conn_address; 2416290001Sglebius} 2417290001Sglebius 2418290001Sglebiusint 2419290001Sglebiusevhttp_connection_connect_(struct evhttp_connection *evcon) 2420290001Sglebius{ 2421290001Sglebius int old_state = evcon->state; 2422290001Sglebius 2423290001Sglebius if (evcon->state == EVCON_CONNECTING) 2424290001Sglebius return (0); 2425290001Sglebius 2426290001Sglebius evhttp_connection_reset_(evcon); 2427290001Sglebius 2428290001Sglebius EVUTIL_ASSERT(!(evcon->flags & EVHTTP_CON_INCOMING)); 2429290001Sglebius evcon->flags |= EVHTTP_CON_OUTGOING; 2430290001Sglebius 2431290001Sglebius if (evcon->bind_address || evcon->bind_port) { 2432290001Sglebius evcon->fd = bind_socket( 2433290001Sglebius evcon->bind_address, evcon->bind_port, 0 /*reuse*/); 2434290001Sglebius if (evcon->fd == -1) { 2435290001Sglebius event_debug(("%s: failed to bind to \"%s\"", 2436290001Sglebius __func__, evcon->bind_address)); 2437290001Sglebius return (-1); 2438290001Sglebius } 2439290001Sglebius 2440290001Sglebius bufferevent_setfd(evcon->bufev, evcon->fd); 2441290001Sglebius } else { 2442290001Sglebius bufferevent_setfd(evcon->bufev, -1); 2443290001Sglebius } 2444290001Sglebius 2445290001Sglebius /* Set up a callback for successful connection setup */ 2446290001Sglebius bufferevent_setcb(evcon->bufev, 2447290001Sglebius NULL /* evhttp_read_cb */, 2448290001Sglebius NULL /* evhttp_write_cb */, 2449290001Sglebius evhttp_connection_cb, 2450290001Sglebius evcon); 2451290001Sglebius if (!evutil_timerisset(&evcon->timeout)) { 2452290001Sglebius const struct timeval conn_tv = { HTTP_CONNECT_TIMEOUT, 0 }; 2453290001Sglebius bufferevent_set_timeouts(evcon->bufev, NULL, &conn_tv); 2454290001Sglebius } else { 2455290001Sglebius bufferevent_set_timeouts(evcon->bufev, NULL, &evcon->timeout); 2456290001Sglebius } 2457290001Sglebius /* make sure that we get a write callback */ 2458290001Sglebius bufferevent_enable(evcon->bufev, EV_WRITE); 2459290001Sglebius 2460290001Sglebius evcon->state = EVCON_CONNECTING; 2461290001Sglebius 2462290001Sglebius if (bufferevent_socket_connect_hostname(evcon->bufev, evcon->dns_base, 2463290001Sglebius evcon->ai_family, evcon->address, evcon->port) < 0) { 2464290001Sglebius evcon->state = old_state; 2465290001Sglebius event_sock_warn(evcon->fd, "%s: connection to \"%s\" failed", 2466290001Sglebius __func__, evcon->address); 2467290001Sglebius /* some operating systems return ECONNREFUSED immediately 2468290001Sglebius * when connecting to a local address. the cleanup is going 2469290001Sglebius * to reschedule this function call. 2470290001Sglebius */ 2471290001Sglebius evhttp_connection_cb_cleanup(evcon); 2472290001Sglebius return (0); 2473290001Sglebius } 2474290001Sglebius 2475290001Sglebius return (0); 2476290001Sglebius} 2477290001Sglebius 2478290001Sglebius/* 2479290001Sglebius * Starts an HTTP request on the provided evhttp_connection object. 2480290001Sglebius * If the connection object is not connected to the web server already, 2481290001Sglebius * this will start the connection. 2482290001Sglebius */ 2483290001Sglebius 2484290001Sglebiusint 2485290001Sglebiusevhttp_make_request(struct evhttp_connection *evcon, 2486290001Sglebius struct evhttp_request *req, 2487290001Sglebius enum evhttp_cmd_type type, const char *uri) 2488290001Sglebius{ 2489290001Sglebius /* We are making a request */ 2490290001Sglebius req->kind = EVHTTP_REQUEST; 2491290001Sglebius req->type = type; 2492290001Sglebius if (req->uri != NULL) 2493290001Sglebius mm_free(req->uri); 2494290001Sglebius if ((req->uri = mm_strdup(uri)) == NULL) { 2495290001Sglebius event_warn("%s: strdup", __func__); 2496290001Sglebius evhttp_request_free(req); 2497290001Sglebius return (-1); 2498290001Sglebius } 2499290001Sglebius 2500290001Sglebius /* Set the protocol version if it is not supplied */ 2501290001Sglebius if (!req->major && !req->minor) { 2502290001Sglebius req->major = 1; 2503290001Sglebius req->minor = 1; 2504290001Sglebius } 2505290001Sglebius 2506290001Sglebius EVUTIL_ASSERT(req->evcon == NULL); 2507290001Sglebius req->evcon = evcon; 2508290001Sglebius EVUTIL_ASSERT(!(req->flags & EVHTTP_REQ_OWN_CONNECTION)); 2509290001Sglebius 2510290001Sglebius TAILQ_INSERT_TAIL(&evcon->requests, req, next); 2511290001Sglebius 2512290001Sglebius /* If the connection object is not connected; make it so */ 2513290001Sglebius if (!evhttp_connected(evcon)) { 2514290001Sglebius int res = evhttp_connection_connect_(evcon); 2515290001Sglebius /* evhttp_connection_fail_(), which is called through 2516290001Sglebius * evhttp_connection_connect_(), assumes that req lies in 2517290001Sglebius * evcon->requests. Thus, enqueue the request in advance and 2518290001Sglebius * remove it in the error case. */ 2519290001Sglebius if (res != 0) 2520290001Sglebius TAILQ_REMOVE(&evcon->requests, req, next); 2521290001Sglebius 2522290001Sglebius return res; 2523290001Sglebius } 2524290001Sglebius 2525290001Sglebius /* 2526290001Sglebius * If it's connected already and we are the first in the queue, 2527290001Sglebius * then we can dispatch this request immediately. Otherwise, it 2528290001Sglebius * will be dispatched once the pending requests are completed. 2529290001Sglebius */ 2530290001Sglebius if (TAILQ_FIRST(&evcon->requests) == req) 2531290001Sglebius evhttp_request_dispatch(evcon); 2532290001Sglebius 2533290001Sglebius return (0); 2534290001Sglebius} 2535290001Sglebius 2536290001Sglebiusvoid 2537290001Sglebiusevhttp_cancel_request(struct evhttp_request *req) 2538290001Sglebius{ 2539290001Sglebius struct evhttp_connection *evcon = req->evcon; 2540290001Sglebius if (evcon != NULL) { 2541290001Sglebius /* We need to remove it from the connection */ 2542290001Sglebius if (TAILQ_FIRST(&evcon->requests) == req) { 2543290001Sglebius /* it's currently being worked on, so reset 2544290001Sglebius * the connection. 2545290001Sglebius */ 2546290001Sglebius evhttp_connection_fail_(evcon, 2547290001Sglebius EVREQ_HTTP_REQUEST_CANCEL); 2548290001Sglebius 2549290001Sglebius /* connection fail freed the request */ 2550290001Sglebius return; 2551290001Sglebius } else { 2552290001Sglebius /* otherwise, we can just remove it from the 2553290001Sglebius * queue 2554290001Sglebius */ 2555290001Sglebius TAILQ_REMOVE(&evcon->requests, req, next); 2556290001Sglebius } 2557290001Sglebius } 2558290001Sglebius 2559290001Sglebius evhttp_request_free(req); 2560290001Sglebius} 2561290001Sglebius 2562290001Sglebius/* 2563290001Sglebius * Reads data from file descriptor into request structure 2564290001Sglebius * Request structure needs to be set up correctly. 2565290001Sglebius */ 2566290001Sglebius 2567290001Sglebiusvoid 2568290001Sglebiusevhttp_start_read_(struct evhttp_connection *evcon) 2569290001Sglebius{ 2570290001Sglebius /* Set up an event to read the headers */ 2571290001Sglebius bufferevent_disable(evcon->bufev, EV_WRITE); 2572290001Sglebius bufferevent_enable(evcon->bufev, EV_READ); 2573290001Sglebius evcon->state = EVCON_READING_FIRSTLINE; 2574290001Sglebius /* Reset the bufferevent callbacks */ 2575290001Sglebius bufferevent_setcb(evcon->bufev, 2576290001Sglebius evhttp_read_cb, 2577290001Sglebius evhttp_write_cb, 2578290001Sglebius evhttp_error_cb, 2579290001Sglebius evcon); 2580290001Sglebius 2581290001Sglebius /* If there's still data pending, process it next time through the 2582290001Sglebius * loop. Don't do it now; that could get recusive. */ 2583290001Sglebius if (evbuffer_get_length(bufferevent_get_input(evcon->bufev))) { 2584290001Sglebius event_deferred_cb_schedule_(get_deferred_queue(evcon), 2585290001Sglebius &evcon->read_more_deferred_cb); 2586290001Sglebius } 2587290001Sglebius} 2588290001Sglebius 2589290001Sglebiusstatic void 2590290001Sglebiusevhttp_send_done(struct evhttp_connection *evcon, void *arg) 2591290001Sglebius{ 2592290001Sglebius int need_close; 2593290001Sglebius struct evhttp_request *req = TAILQ_FIRST(&evcon->requests); 2594290001Sglebius TAILQ_REMOVE(&evcon->requests, req, next); 2595290001Sglebius 2596290001Sglebius if (req->on_complete_cb != NULL) { 2597290001Sglebius req->on_complete_cb(req, req->on_complete_cb_arg); 2598290001Sglebius } 2599290001Sglebius 2600290001Sglebius need_close = 2601290001Sglebius (REQ_VERSION_BEFORE(req, 1, 1) && 2602290001Sglebius !evhttp_is_connection_keepalive(req->input_headers))|| 2603290001Sglebius evhttp_is_connection_close(req->flags, req->input_headers) || 2604290001Sglebius evhttp_is_connection_close(req->flags, req->output_headers); 2605290001Sglebius 2606290001Sglebius EVUTIL_ASSERT(req->flags & EVHTTP_REQ_OWN_CONNECTION); 2607290001Sglebius evhttp_request_free(req); 2608290001Sglebius 2609290001Sglebius if (need_close) { 2610290001Sglebius evhttp_connection_free(evcon); 2611290001Sglebius return; 2612290001Sglebius } 2613290001Sglebius 2614290001Sglebius /* we have a persistent connection; try to accept another request. */ 2615290001Sglebius if (evhttp_associate_new_request_with_connection(evcon) == -1) { 2616290001Sglebius evhttp_connection_free(evcon); 2617290001Sglebius } 2618290001Sglebius} 2619290001Sglebius 2620290001Sglebius/* 2621290001Sglebius * Returns an error page. 2622290001Sglebius */ 2623290001Sglebius 2624290001Sglebiusvoid 2625290001Sglebiusevhttp_send_error(struct evhttp_request *req, int error, const char *reason) 2626290001Sglebius{ 2627290001Sglebius 2628290001Sglebius#define ERR_FORMAT "<HTML><HEAD>\n" \ 2629290001Sglebius "<TITLE>%d %s</TITLE>\n" \ 2630290001Sglebius "</HEAD><BODY>\n" \ 2631290001Sglebius "<H1>%s</H1>\n" \ 2632290001Sglebius "</BODY></HTML>\n" 2633290001Sglebius 2634290001Sglebius struct evbuffer *buf = evbuffer_new(); 2635290001Sglebius if (buf == NULL) { 2636290001Sglebius /* if we cannot allocate memory; we just drop the connection */ 2637290001Sglebius evhttp_connection_free(req->evcon); 2638290001Sglebius return; 2639290001Sglebius } 2640290001Sglebius if (reason == NULL) { 2641290001Sglebius reason = evhttp_response_phrase_internal(error); 2642290001Sglebius } 2643290001Sglebius 2644290001Sglebius evhttp_response_code_(req, error, reason); 2645290001Sglebius 2646290001Sglebius evbuffer_add_printf(buf, ERR_FORMAT, error, reason, reason); 2647290001Sglebius 2648290001Sglebius evhttp_send_page_(req, buf); 2649290001Sglebius 2650290001Sglebius evbuffer_free(buf); 2651290001Sglebius#undef ERR_FORMAT 2652290001Sglebius} 2653290001Sglebius 2654290001Sglebius/* Requires that headers and response code are already set up */ 2655290001Sglebius 2656290001Sglebiusstatic inline void 2657290001Sglebiusevhttp_send(struct evhttp_request *req, struct evbuffer *databuf) 2658290001Sglebius{ 2659290001Sglebius struct evhttp_connection *evcon = req->evcon; 2660290001Sglebius 2661290001Sglebius if (evcon == NULL) { 2662290001Sglebius evhttp_request_free(req); 2663290001Sglebius return; 2664290001Sglebius } 2665290001Sglebius 2666290001Sglebius EVUTIL_ASSERT(TAILQ_FIRST(&evcon->requests) == req); 2667290001Sglebius 2668290001Sglebius /* we expect no more calls form the user on this request */ 2669290001Sglebius req->userdone = 1; 2670290001Sglebius 2671290001Sglebius /* xxx: not sure if we really should expose the data buffer this way */ 2672290001Sglebius if (databuf != NULL) 2673290001Sglebius evbuffer_add_buffer(req->output_buffer, databuf); 2674290001Sglebius 2675290001Sglebius /* Adds headers to the response */ 2676290001Sglebius evhttp_make_header(evcon, req); 2677290001Sglebius 2678290001Sglebius evhttp_write_buffer(evcon, evhttp_send_done, NULL); 2679290001Sglebius} 2680290001Sglebius 2681290001Sglebiusvoid 2682290001Sglebiusevhttp_send_reply(struct evhttp_request *req, int code, const char *reason, 2683290001Sglebius struct evbuffer *databuf) 2684290001Sglebius{ 2685290001Sglebius evhttp_response_code_(req, code, reason); 2686290001Sglebius 2687290001Sglebius evhttp_send(req, databuf); 2688290001Sglebius} 2689290001Sglebius 2690290001Sglebiusvoid 2691290001Sglebiusevhttp_send_reply_start(struct evhttp_request *req, int code, 2692290001Sglebius const char *reason) 2693290001Sglebius{ 2694290001Sglebius evhttp_response_code_(req, code, reason); 2695290001Sglebius if (evhttp_find_header(req->output_headers, "Content-Length") == NULL && 2696290001Sglebius REQ_VERSION_ATLEAST(req, 1, 1) && 2697290001Sglebius evhttp_response_needs_body(req)) { 2698290001Sglebius /* 2699290001Sglebius * prefer HTTP/1.1 chunked encoding to closing the connection; 2700290001Sglebius * note RFC 2616 section 4.4 forbids it with Content-Length: 2701290001Sglebius * and it's not necessary then anyway. 2702290001Sglebius */ 2703290001Sglebius evhttp_add_header(req->output_headers, "Transfer-Encoding", 2704290001Sglebius "chunked"); 2705290001Sglebius req->chunked = 1; 2706290001Sglebius } else { 2707290001Sglebius req->chunked = 0; 2708290001Sglebius } 2709290001Sglebius evhttp_make_header(req->evcon, req); 2710290001Sglebius evhttp_write_buffer(req->evcon, NULL, NULL); 2711290001Sglebius} 2712290001Sglebius 2713290001Sglebiusvoid 2714290001Sglebiusevhttp_send_reply_chunk_with_cb(struct evhttp_request *req, struct evbuffer *databuf, 2715290001Sglebius void (*cb)(struct evhttp_connection *, void *), void *arg) 2716290001Sglebius{ 2717290001Sglebius struct evhttp_connection *evcon = req->evcon; 2718290001Sglebius struct evbuffer *output; 2719290001Sglebius 2720290001Sglebius if (evcon == NULL) 2721290001Sglebius return; 2722290001Sglebius 2723290001Sglebius output = bufferevent_get_output(evcon->bufev); 2724290001Sglebius 2725290001Sglebius if (evbuffer_get_length(databuf) == 0) 2726290001Sglebius return; 2727290001Sglebius if (!evhttp_response_needs_body(req)) 2728290001Sglebius return; 2729290001Sglebius if (req->chunked) { 2730290001Sglebius evbuffer_add_printf(output, "%x\r\n", 2731290001Sglebius (unsigned)evbuffer_get_length(databuf)); 2732290001Sglebius } 2733290001Sglebius evbuffer_add_buffer(output, databuf); 2734290001Sglebius if (req->chunked) { 2735290001Sglebius evbuffer_add(output, "\r\n", 2); 2736290001Sglebius } 2737290001Sglebius evhttp_write_buffer(evcon, cb, arg); 2738290001Sglebius} 2739290001Sglebius 2740290001Sglebiusvoid 2741290001Sglebiusevhttp_send_reply_chunk(struct evhttp_request *req, struct evbuffer *databuf) 2742290001Sglebius{ 2743290001Sglebius evhttp_send_reply_chunk_with_cb(req, databuf, NULL, NULL); 2744290001Sglebius} 2745290001Sglebiusvoid 2746290001Sglebiusevhttp_send_reply_end(struct evhttp_request *req) 2747290001Sglebius{ 2748290001Sglebius struct evhttp_connection *evcon = req->evcon; 2749290001Sglebius struct evbuffer *output; 2750290001Sglebius 2751290001Sglebius if (evcon == NULL) { 2752290001Sglebius evhttp_request_free(req); 2753290001Sglebius return; 2754290001Sglebius } 2755290001Sglebius 2756290001Sglebius output = bufferevent_get_output(evcon->bufev); 2757290001Sglebius 2758290001Sglebius /* we expect no more calls form the user on this request */ 2759290001Sglebius req->userdone = 1; 2760290001Sglebius 2761290001Sglebius if (req->chunked) { 2762290001Sglebius evbuffer_add(output, "0\r\n\r\n", 5); 2763290001Sglebius evhttp_write_buffer(req->evcon, evhttp_send_done, NULL); 2764290001Sglebius req->chunked = 0; 2765290001Sglebius } else if (evbuffer_get_length(output) == 0) { 2766290001Sglebius /* let the connection know that we are done with the request */ 2767290001Sglebius evhttp_send_done(evcon, NULL); 2768290001Sglebius } else { 2769290001Sglebius /* make the callback execute after all data has been written */ 2770290001Sglebius evcon->cb = evhttp_send_done; 2771290001Sglebius evcon->cb_arg = NULL; 2772290001Sglebius } 2773290001Sglebius} 2774290001Sglebius 2775290001Sglebiusstatic const char *informational_phrases[] = { 2776290001Sglebius /* 100 */ "Continue", 2777290001Sglebius /* 101 */ "Switching Protocols" 2778290001Sglebius}; 2779290001Sglebius 2780290001Sglebiusstatic const char *success_phrases[] = { 2781290001Sglebius /* 200 */ "OK", 2782290001Sglebius /* 201 */ "Created", 2783290001Sglebius /* 202 */ "Accepted", 2784290001Sglebius /* 203 */ "Non-Authoritative Information", 2785290001Sglebius /* 204 */ "No Content", 2786290001Sglebius /* 205 */ "Reset Content", 2787290001Sglebius /* 206 */ "Partial Content" 2788290001Sglebius}; 2789290001Sglebius 2790290001Sglebiusstatic const char *redirection_phrases[] = { 2791290001Sglebius /* 300 */ "Multiple Choices", 2792290001Sglebius /* 301 */ "Moved Permanently", 2793290001Sglebius /* 302 */ "Found", 2794290001Sglebius /* 303 */ "See Other", 2795290001Sglebius /* 304 */ "Not Modified", 2796290001Sglebius /* 305 */ "Use Proxy", 2797290001Sglebius /* 307 */ "Temporary Redirect" 2798290001Sglebius}; 2799290001Sglebius 2800290001Sglebiusstatic const char *client_error_phrases[] = { 2801290001Sglebius /* 400 */ "Bad Request", 2802290001Sglebius /* 401 */ "Unauthorized", 2803290001Sglebius /* 402 */ "Payment Required", 2804290001Sglebius /* 403 */ "Forbidden", 2805290001Sglebius /* 404 */ "Not Found", 2806290001Sglebius /* 405 */ "Method Not Allowed", 2807290001Sglebius /* 406 */ "Not Acceptable", 2808290001Sglebius /* 407 */ "Proxy Authentication Required", 2809290001Sglebius /* 408 */ "Request Time-out", 2810290001Sglebius /* 409 */ "Conflict", 2811290001Sglebius /* 410 */ "Gone", 2812290001Sglebius /* 411 */ "Length Required", 2813290001Sglebius /* 412 */ "Precondition Failed", 2814290001Sglebius /* 413 */ "Request Entity Too Large", 2815290001Sglebius /* 414 */ "Request-URI Too Large", 2816290001Sglebius /* 415 */ "Unsupported Media Type", 2817290001Sglebius /* 416 */ "Requested range not satisfiable", 2818290001Sglebius /* 417 */ "Expectation Failed" 2819290001Sglebius}; 2820290001Sglebius 2821290001Sglebiusstatic const char *server_error_phrases[] = { 2822290001Sglebius /* 500 */ "Internal Server Error", 2823290001Sglebius /* 501 */ "Not Implemented", 2824290001Sglebius /* 502 */ "Bad Gateway", 2825290001Sglebius /* 503 */ "Service Unavailable", 2826290001Sglebius /* 504 */ "Gateway Time-out", 2827290001Sglebius /* 505 */ "HTTP Version not supported" 2828290001Sglebius}; 2829290001Sglebius 2830290001Sglebiusstruct response_class { 2831290001Sglebius const char *name; 2832290001Sglebius size_t num_responses; 2833290001Sglebius const char **responses; 2834290001Sglebius}; 2835290001Sglebius 2836290001Sglebius#ifndef MEMBERSOF 2837290001Sglebius#define MEMBERSOF(x) (sizeof(x)/sizeof(x[0])) 2838290001Sglebius#endif 2839290001Sglebius 2840290001Sglebiusstatic const struct response_class response_classes[] = { 2841290001Sglebius /* 1xx */ { "Informational", MEMBERSOF(informational_phrases), informational_phrases }, 2842290001Sglebius /* 2xx */ { "Success", MEMBERSOF(success_phrases), success_phrases }, 2843290001Sglebius /* 3xx */ { "Redirection", MEMBERSOF(redirection_phrases), redirection_phrases }, 2844290001Sglebius /* 4xx */ { "Client Error", MEMBERSOF(client_error_phrases), client_error_phrases }, 2845290001Sglebius /* 5xx */ { "Server Error", MEMBERSOF(server_error_phrases), server_error_phrases } 2846290001Sglebius}; 2847290001Sglebius 2848290001Sglebiusstatic const char * 2849290001Sglebiusevhttp_response_phrase_internal(int code) 2850290001Sglebius{ 2851290001Sglebius int klass = code / 100 - 1; 2852290001Sglebius int subcode = code % 100; 2853290001Sglebius 2854290001Sglebius /* Unknown class - can't do any better here */ 2855290001Sglebius if (klass < 0 || klass >= (int) MEMBERSOF(response_classes)) 2856290001Sglebius return "Unknown Status Class"; 2857290001Sglebius 2858290001Sglebius /* Unknown sub-code, return class name at least */ 2859290001Sglebius if (subcode >= (int) response_classes[klass].num_responses) 2860290001Sglebius return response_classes[klass].name; 2861290001Sglebius 2862290001Sglebius return response_classes[klass].responses[subcode]; 2863290001Sglebius} 2864290001Sglebius 2865290001Sglebiusvoid 2866290001Sglebiusevhttp_response_code_(struct evhttp_request *req, int code, const char *reason) 2867290001Sglebius{ 2868290001Sglebius req->kind = EVHTTP_RESPONSE; 2869290001Sglebius req->response_code = code; 2870290001Sglebius if (req->response_code_line != NULL) 2871290001Sglebius mm_free(req->response_code_line); 2872290001Sglebius if (reason == NULL) 2873290001Sglebius reason = evhttp_response_phrase_internal(code); 2874290001Sglebius req->response_code_line = mm_strdup(reason); 2875290001Sglebius if (req->response_code_line == NULL) { 2876290001Sglebius event_warn("%s: strdup", __func__); 2877290001Sglebius /* XXX what else can we do? */ 2878290001Sglebius } 2879290001Sglebius} 2880290001Sglebius 2881290001Sglebiusvoid 2882290001Sglebiusevhttp_send_page_(struct evhttp_request *req, struct evbuffer *databuf) 2883290001Sglebius{ 2884290001Sglebius if (!req->major || !req->minor) { 2885290001Sglebius req->major = 1; 2886290001Sglebius req->minor = 1; 2887290001Sglebius } 2888290001Sglebius 2889290001Sglebius if (req->kind != EVHTTP_RESPONSE) 2890290001Sglebius evhttp_response_code_(req, 200, "OK"); 2891290001Sglebius 2892290001Sglebius evhttp_clear_headers(req->output_headers); 2893290001Sglebius evhttp_add_header(req->output_headers, "Content-Type", "text/html"); 2894290001Sglebius evhttp_add_header(req->output_headers, "Connection", "close"); 2895290001Sglebius 2896290001Sglebius evhttp_send(req, databuf); 2897290001Sglebius} 2898290001Sglebius 2899290001Sglebiusstatic const char uri_chars[256] = { 2900290001Sglebius /* 0 */ 2901290001Sglebius 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2902290001Sglebius 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2903290001Sglebius 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 2904290001Sglebius 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 2905290001Sglebius /* 64 */ 2906290001Sglebius 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2907290001Sglebius 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 2908290001Sglebius 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2909290001Sglebius 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 2910290001Sglebius /* 128 */ 2911290001Sglebius 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2912290001Sglebius 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2913290001Sglebius 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2914290001Sglebius 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2915290001Sglebius /* 192 */ 2916290001Sglebius 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2917290001Sglebius 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2918290001Sglebius 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2919290001Sglebius 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2920290001Sglebius}; 2921290001Sglebius 2922290001Sglebius#define CHAR_IS_UNRESERVED(c) \ 2923290001Sglebius (uri_chars[(unsigned char)(c)]) 2924290001Sglebius 2925290001Sglebius/* 2926290001Sglebius * Helper functions to encode/decode a string for inclusion in a URI. 2927290001Sglebius * The returned string must be freed by the caller. 2928290001Sglebius */ 2929290001Sglebiuschar * 2930290001Sglebiusevhttp_uriencode(const char *uri, ev_ssize_t len, int space_as_plus) 2931290001Sglebius{ 2932290001Sglebius struct evbuffer *buf = evbuffer_new(); 2933290001Sglebius const char *p, *end; 2934290001Sglebius char *result; 2935290001Sglebius 2936290001Sglebius if (buf == NULL) 2937290001Sglebius return (NULL); 2938290001Sglebius 2939290001Sglebius if (len >= 0) 2940290001Sglebius end = uri+len; 2941290001Sglebius else 2942290001Sglebius end = uri+strlen(uri); 2943290001Sglebius 2944290001Sglebius for (p = uri; p < end; p++) { 2945290001Sglebius if (CHAR_IS_UNRESERVED(*p)) { 2946290001Sglebius evbuffer_add(buf, p, 1); 2947290001Sglebius } else if (*p == ' ' && space_as_plus) { 2948290001Sglebius evbuffer_add(buf, "+", 1); 2949290001Sglebius } else { 2950290001Sglebius evbuffer_add_printf(buf, "%%%02X", (unsigned char)(*p)); 2951290001Sglebius } 2952290001Sglebius } 2953290001Sglebius evbuffer_add(buf, "", 1); /* NUL-terminator. */ 2954290001Sglebius result = mm_malloc(evbuffer_get_length(buf)); 2955290001Sglebius if (result) 2956290001Sglebius evbuffer_remove(buf, result, evbuffer_get_length(buf)); 2957290001Sglebius evbuffer_free(buf); 2958290001Sglebius 2959290001Sglebius return (result); 2960290001Sglebius} 2961290001Sglebius 2962290001Sglebiuschar * 2963290001Sglebiusevhttp_encode_uri(const char *str) 2964290001Sglebius{ 2965290001Sglebius return evhttp_uriencode(str, -1, 0); 2966290001Sglebius} 2967290001Sglebius 2968290001Sglebius/* 2969290001Sglebius * @param decode_plus_ctl: if 1, we decode plus into space. If 0, we don't. 2970290001Sglebius * If -1, when true we transform plus to space only after we've seen 2971290001Sglebius * a ?. -1 is deprecated. 2972290001Sglebius * @return the number of bytes written to 'ret'. 2973290001Sglebius */ 2974290001Sglebiusint 2975290001Sglebiusevhttp_decode_uri_internal( 2976290001Sglebius const char *uri, size_t length, char *ret, int decode_plus_ctl) 2977290001Sglebius{ 2978290001Sglebius char c; 2979290001Sglebius int j; 2980290001Sglebius int decode_plus = (decode_plus_ctl == 1) ? 1: 0; 2981290001Sglebius unsigned i; 2982290001Sglebius 2983290001Sglebius for (i = j = 0; i < length; i++) { 2984290001Sglebius c = uri[i]; 2985290001Sglebius if (c == '?') { 2986290001Sglebius if (decode_plus_ctl < 0) 2987290001Sglebius decode_plus = 1; 2988290001Sglebius } else if (c == '+' && decode_plus) { 2989290001Sglebius c = ' '; 2990290001Sglebius } else if ((i + 2) < length && c == '%' && 2991290001Sglebius EVUTIL_ISXDIGIT_(uri[i+1]) && EVUTIL_ISXDIGIT_(uri[i+2])) { 2992290001Sglebius char tmp[3]; 2993290001Sglebius tmp[0] = uri[i+1]; 2994290001Sglebius tmp[1] = uri[i+2]; 2995290001Sglebius tmp[2] = '\0'; 2996290001Sglebius c = (char)strtol(tmp, NULL, 16); 2997290001Sglebius i += 2; 2998290001Sglebius } 2999290001Sglebius ret[j++] = c; 3000290001Sglebius } 3001290001Sglebius ret[j] = '\0'; 3002290001Sglebius 3003290001Sglebius return (j); 3004290001Sglebius} 3005290001Sglebius 3006290001Sglebius/* deprecated */ 3007290001Sglebiuschar * 3008290001Sglebiusevhttp_decode_uri(const char *uri) 3009290001Sglebius{ 3010290001Sglebius char *ret; 3011290001Sglebius 3012290001Sglebius if ((ret = mm_malloc(strlen(uri) + 1)) == NULL) { 3013290001Sglebius event_warn("%s: malloc(%lu)", __func__, 3014290001Sglebius (unsigned long)(strlen(uri) + 1)); 3015290001Sglebius return (NULL); 3016290001Sglebius } 3017290001Sglebius 3018290001Sglebius evhttp_decode_uri_internal(uri, strlen(uri), 3019290001Sglebius ret, -1 /*always_decode_plus*/); 3020290001Sglebius 3021290001Sglebius return (ret); 3022290001Sglebius} 3023290001Sglebius 3024290001Sglebiuschar * 3025290001Sglebiusevhttp_uridecode(const char *uri, int decode_plus, size_t *size_out) 3026290001Sglebius{ 3027290001Sglebius char *ret; 3028290001Sglebius int n; 3029290001Sglebius 3030290001Sglebius if ((ret = mm_malloc(strlen(uri) + 1)) == NULL) { 3031290001Sglebius event_warn("%s: malloc(%lu)", __func__, 3032290001Sglebius (unsigned long)(strlen(uri) + 1)); 3033290001Sglebius return (NULL); 3034290001Sglebius } 3035290001Sglebius 3036290001Sglebius n = evhttp_decode_uri_internal(uri, strlen(uri), 3037290001Sglebius ret, !!decode_plus/*always_decode_plus*/); 3038290001Sglebius 3039290001Sglebius if (size_out) { 3040290001Sglebius EVUTIL_ASSERT(n >= 0); 3041290001Sglebius *size_out = (size_t)n; 3042290001Sglebius } 3043290001Sglebius 3044290001Sglebius return (ret); 3045290001Sglebius} 3046290001Sglebius 3047290001Sglebius/* 3048290001Sglebius * Helper function to parse out arguments in a query. 3049290001Sglebius * The arguments are separated by key and value. 3050290001Sglebius */ 3051290001Sglebius 3052290001Sglebiusstatic int 3053290001Sglebiusevhttp_parse_query_impl(const char *str, struct evkeyvalq *headers, 3054290001Sglebius int is_whole_uri) 3055290001Sglebius{ 3056290001Sglebius char *line=NULL; 3057290001Sglebius char *argument; 3058290001Sglebius char *p; 3059290001Sglebius const char *query_part; 3060290001Sglebius int result = -1; 3061290001Sglebius struct evhttp_uri *uri=NULL; 3062290001Sglebius 3063290001Sglebius TAILQ_INIT(headers); 3064290001Sglebius 3065290001Sglebius if (is_whole_uri) { 3066290001Sglebius uri = evhttp_uri_parse(str); 3067290001Sglebius if (!uri) 3068290001Sglebius goto error; 3069290001Sglebius query_part = evhttp_uri_get_query(uri); 3070290001Sglebius } else { 3071290001Sglebius query_part = str; 3072290001Sglebius } 3073290001Sglebius 3074290001Sglebius /* No arguments - we are done */ 3075290001Sglebius if (!query_part || !strlen(query_part)) { 3076290001Sglebius result = 0; 3077290001Sglebius goto done; 3078290001Sglebius } 3079290001Sglebius 3080290001Sglebius if ((line = mm_strdup(query_part)) == NULL) { 3081290001Sglebius event_warn("%s: strdup", __func__); 3082290001Sglebius goto error; 3083290001Sglebius } 3084290001Sglebius 3085290001Sglebius p = argument = line; 3086290001Sglebius while (p != NULL && *p != '\0') { 3087290001Sglebius char *key, *value, *decoded_value; 3088290001Sglebius argument = strsep(&p, "&"); 3089290001Sglebius 3090290001Sglebius value = argument; 3091290001Sglebius key = strsep(&value, "="); 3092290001Sglebius if (value == NULL || *key == '\0') { 3093290001Sglebius goto error; 3094290001Sglebius } 3095290001Sglebius 3096290001Sglebius if ((decoded_value = mm_malloc(strlen(value) + 1)) == NULL) { 3097290001Sglebius event_warn("%s: mm_malloc", __func__); 3098290001Sglebius goto error; 3099290001Sglebius } 3100290001Sglebius evhttp_decode_uri_internal(value, strlen(value), 3101290001Sglebius decoded_value, 1 /*always_decode_plus*/); 3102290001Sglebius event_debug(("Query Param: %s -> %s\n", key, decoded_value)); 3103290001Sglebius evhttp_add_header_internal(headers, key, decoded_value); 3104290001Sglebius mm_free(decoded_value); 3105290001Sglebius } 3106290001Sglebius 3107290001Sglebius result = 0; 3108290001Sglebius goto done; 3109290001Sglebiuserror: 3110290001Sglebius evhttp_clear_headers(headers); 3111290001Sglebiusdone: 3112290001Sglebius if (line) 3113290001Sglebius mm_free(line); 3114290001Sglebius if (uri) 3115290001Sglebius evhttp_uri_free(uri); 3116290001Sglebius return result; 3117290001Sglebius} 3118290001Sglebius 3119290001Sglebiusint 3120290001Sglebiusevhttp_parse_query(const char *uri, struct evkeyvalq *headers) 3121290001Sglebius{ 3122290001Sglebius return evhttp_parse_query_impl(uri, headers, 1); 3123290001Sglebius} 3124290001Sglebiusint 3125290001Sglebiusevhttp_parse_query_str(const char *uri, struct evkeyvalq *headers) 3126290001Sglebius{ 3127290001Sglebius return evhttp_parse_query_impl(uri, headers, 0); 3128290001Sglebius} 3129290001Sglebius 3130290001Sglebiusstatic struct evhttp_cb * 3131290001Sglebiusevhttp_dispatch_callback(struct httpcbq *callbacks, struct evhttp_request *req) 3132290001Sglebius{ 3133290001Sglebius struct evhttp_cb *cb; 3134290001Sglebius size_t offset = 0; 3135290001Sglebius char *translated; 3136290001Sglebius const char *path; 3137290001Sglebius 3138290001Sglebius /* Test for different URLs */ 3139290001Sglebius path = evhttp_uri_get_path(req->uri_elems); 3140290001Sglebius offset = strlen(path); 3141290001Sglebius if ((translated = mm_malloc(offset + 1)) == NULL) 3142290001Sglebius return (NULL); 3143290001Sglebius evhttp_decode_uri_internal(path, offset, translated, 3144290001Sglebius 0 /* decode_plus */); 3145290001Sglebius 3146290001Sglebius TAILQ_FOREACH(cb, callbacks, next) { 3147290001Sglebius if (!strcmp(cb->what, translated)) { 3148290001Sglebius mm_free(translated); 3149290001Sglebius return (cb); 3150290001Sglebius } 3151290001Sglebius } 3152290001Sglebius 3153290001Sglebius mm_free(translated); 3154290001Sglebius return (NULL); 3155290001Sglebius} 3156290001Sglebius 3157290001Sglebius 3158290001Sglebiusstatic int 3159290001Sglebiusprefix_suffix_match(const char *pattern, const char *name, int ignorecase) 3160290001Sglebius{ 3161290001Sglebius char c; 3162290001Sglebius 3163290001Sglebius while (1) { 3164290001Sglebius switch (c = *pattern++) { 3165290001Sglebius case '\0': 3166290001Sglebius return *name == '\0'; 3167290001Sglebius 3168290001Sglebius case '*': 3169290001Sglebius while (*name != '\0') { 3170290001Sglebius if (prefix_suffix_match(pattern, name, 3171290001Sglebius ignorecase)) 3172290001Sglebius return (1); 3173290001Sglebius ++name; 3174290001Sglebius } 3175290001Sglebius return (0); 3176290001Sglebius default: 3177290001Sglebius if (c != *name) { 3178290001Sglebius if (!ignorecase || 3179290001Sglebius EVUTIL_TOLOWER_(c) != EVUTIL_TOLOWER_(*name)) 3180290001Sglebius return (0); 3181290001Sglebius } 3182290001Sglebius ++name; 3183290001Sglebius } 3184290001Sglebius } 3185290001Sglebius /* NOTREACHED */ 3186290001Sglebius} 3187290001Sglebius 3188290001Sglebius/* 3189290001Sglebius Search the vhost hierarchy beginning with http for a server alias 3190290001Sglebius matching hostname. If a match is found, and outhttp is non-null, 3191290001Sglebius outhttp is set to the matching http object and 1 is returned. 3192290001Sglebius*/ 3193290001Sglebius 3194290001Sglebiusstatic int 3195290001Sglebiusevhttp_find_alias(struct evhttp *http, struct evhttp **outhttp, 3196290001Sglebius const char *hostname) 3197290001Sglebius{ 3198290001Sglebius struct evhttp_server_alias *alias; 3199290001Sglebius struct evhttp *vhost; 3200290001Sglebius 3201290001Sglebius TAILQ_FOREACH(alias, &http->aliases, next) { 3202290001Sglebius /* XXX Do we need to handle IP addresses? */ 3203290001Sglebius if (!evutil_ascii_strcasecmp(alias->alias, hostname)) { 3204290001Sglebius if (outhttp) 3205290001Sglebius *outhttp = http; 3206290001Sglebius return 1; 3207290001Sglebius } 3208290001Sglebius } 3209290001Sglebius 3210290001Sglebius /* XXX It might be good to avoid recursion here, but I don't 3211290001Sglebius see a way to do that w/o a list. */ 3212290001Sglebius TAILQ_FOREACH(vhost, &http->virtualhosts, next_vhost) { 3213290001Sglebius if (evhttp_find_alias(vhost, outhttp, hostname)) 3214290001Sglebius return 1; 3215290001Sglebius } 3216290001Sglebius 3217290001Sglebius return 0; 3218290001Sglebius} 3219290001Sglebius 3220290001Sglebius/* 3221290001Sglebius Attempts to find the best http object to handle a request for a hostname. 3222290001Sglebius All aliases for the root http object and vhosts are searched for an exact 3223290001Sglebius match. Then, the vhost hierarchy is traversed again for a matching 3224290001Sglebius pattern. 3225290001Sglebius 3226290001Sglebius If an alias or vhost is matched, 1 is returned, and outhttp, if non-null, 3227290001Sglebius is set with the best matching http object. If there are no matches, the 3228290001Sglebius root http object is stored in outhttp and 0 is returned. 3229290001Sglebius*/ 3230290001Sglebius 3231290001Sglebiusstatic int 3232290001Sglebiusevhttp_find_vhost(struct evhttp *http, struct evhttp **outhttp, 3233290001Sglebius const char *hostname) 3234290001Sglebius{ 3235290001Sglebius struct evhttp *vhost; 3236290001Sglebius struct evhttp *oldhttp; 3237290001Sglebius int match_found = 0; 3238290001Sglebius 3239290001Sglebius if (evhttp_find_alias(http, outhttp, hostname)) 3240290001Sglebius return 1; 3241290001Sglebius 3242290001Sglebius do { 3243290001Sglebius oldhttp = http; 3244290001Sglebius TAILQ_FOREACH(vhost, &http->virtualhosts, next_vhost) { 3245290001Sglebius if (prefix_suffix_match(vhost->vhost_pattern, 3246290001Sglebius hostname, 1 /* ignorecase */)) { 3247290001Sglebius http = vhost; 3248290001Sglebius match_found = 1; 3249290001Sglebius break; 3250290001Sglebius } 3251290001Sglebius } 3252290001Sglebius } while (oldhttp != http); 3253290001Sglebius 3254290001Sglebius if (outhttp) 3255290001Sglebius *outhttp = http; 3256290001Sglebius 3257290001Sglebius return match_found; 3258290001Sglebius} 3259290001Sglebius 3260290001Sglebiusstatic void 3261290001Sglebiusevhttp_handle_request(struct evhttp_request *req, void *arg) 3262290001Sglebius{ 3263290001Sglebius struct evhttp *http = arg; 3264290001Sglebius struct evhttp_cb *cb = NULL; 3265290001Sglebius const char *hostname; 3266290001Sglebius 3267290001Sglebius /* we have a new request on which the user needs to take action */ 3268290001Sglebius req->userdone = 0; 3269290001Sglebius 3270290001Sglebius if (req->type == 0 || req->uri == NULL) { 3271290001Sglebius evhttp_send_error(req, HTTP_BADREQUEST, NULL); 3272290001Sglebius return; 3273290001Sglebius } 3274290001Sglebius 3275290001Sglebius if ((http->allowed_methods & req->type) == 0) { 3276290001Sglebius event_debug(("Rejecting disallowed method %x (allowed: %x)\n", 3277290001Sglebius (unsigned)req->type, (unsigned)http->allowed_methods)); 3278290001Sglebius evhttp_send_error(req, HTTP_NOTIMPLEMENTED, NULL); 3279290001Sglebius return; 3280290001Sglebius } 3281290001Sglebius 3282290001Sglebius /* handle potential virtual hosts */ 3283290001Sglebius hostname = evhttp_request_get_host(req); 3284290001Sglebius if (hostname != NULL) { 3285290001Sglebius evhttp_find_vhost(http, &http, hostname); 3286290001Sglebius } 3287290001Sglebius 3288290001Sglebius if ((cb = evhttp_dispatch_callback(&http->callbacks, req)) != NULL) { 3289290001Sglebius (*cb->cb)(req, cb->cbarg); 3290290001Sglebius return; 3291290001Sglebius } 3292290001Sglebius 3293290001Sglebius /* Generic call back */ 3294290001Sglebius if (http->gencb) { 3295290001Sglebius (*http->gencb)(req, http->gencbarg); 3296290001Sglebius return; 3297290001Sglebius } else { 3298290001Sglebius /* We need to send a 404 here */ 3299290001Sglebius#define ERR_FORMAT "<html><head>" \ 3300290001Sglebius "<title>404 Not Found</title>" \ 3301290001Sglebius "</head><body>" \ 3302290001Sglebius "<h1>Not Found</h1>" \ 3303290001Sglebius "<p>The requested URL %s was not found on this server.</p>"\ 3304290001Sglebius "</body></html>\n" 3305290001Sglebius 3306290001Sglebius char *escaped_html; 3307290001Sglebius struct evbuffer *buf; 3308290001Sglebius 3309290001Sglebius if ((escaped_html = evhttp_htmlescape(req->uri)) == NULL) { 3310290001Sglebius evhttp_connection_free(req->evcon); 3311290001Sglebius return; 3312290001Sglebius } 3313290001Sglebius 3314290001Sglebius if ((buf = evbuffer_new()) == NULL) { 3315290001Sglebius mm_free(escaped_html); 3316290001Sglebius evhttp_connection_free(req->evcon); 3317290001Sglebius return; 3318290001Sglebius } 3319290001Sglebius 3320290001Sglebius evhttp_response_code_(req, HTTP_NOTFOUND, "Not Found"); 3321290001Sglebius 3322290001Sglebius evbuffer_add_printf(buf, ERR_FORMAT, escaped_html); 3323290001Sglebius 3324290001Sglebius mm_free(escaped_html); 3325290001Sglebius 3326290001Sglebius evhttp_send_page_(req, buf); 3327290001Sglebius 3328290001Sglebius evbuffer_free(buf); 3329290001Sglebius#undef ERR_FORMAT 3330290001Sglebius } 3331290001Sglebius} 3332290001Sglebius 3333290001Sglebius/* Listener callback when a connection arrives at a server. */ 3334290001Sglebiusstatic void 3335290001Sglebiusaccept_socket_cb(struct evconnlistener *listener, evutil_socket_t nfd, struct sockaddr *peer_sa, int peer_socklen, void *arg) 3336290001Sglebius{ 3337290001Sglebius struct evhttp *http = arg; 3338290001Sglebius 3339290001Sglebius evhttp_get_request(http, nfd, peer_sa, peer_socklen); 3340290001Sglebius} 3341290001Sglebius 3342290001Sglebiusint 3343290001Sglebiusevhttp_bind_socket(struct evhttp *http, const char *address, ev_uint16_t port) 3344290001Sglebius{ 3345290001Sglebius struct evhttp_bound_socket *bound = 3346290001Sglebius evhttp_bind_socket_with_handle(http, address, port); 3347290001Sglebius if (bound == NULL) 3348290001Sglebius return (-1); 3349290001Sglebius return (0); 3350290001Sglebius} 3351290001Sglebius 3352290001Sglebiusstruct evhttp_bound_socket * 3353290001Sglebiusevhttp_bind_socket_with_handle(struct evhttp *http, const char *address, ev_uint16_t port) 3354290001Sglebius{ 3355290001Sglebius evutil_socket_t fd; 3356290001Sglebius struct evhttp_bound_socket *bound; 3357290001Sglebius 3358290001Sglebius if ((fd = bind_socket(address, port, 1 /*reuse*/)) == -1) 3359290001Sglebius return (NULL); 3360290001Sglebius 3361290001Sglebius if (listen(fd, 128) == -1) { 3362290001Sglebius event_sock_warn(fd, "%s: listen", __func__); 3363290001Sglebius evutil_closesocket(fd); 3364290001Sglebius return (NULL); 3365290001Sglebius } 3366290001Sglebius 3367290001Sglebius bound = evhttp_accept_socket_with_handle(http, fd); 3368290001Sglebius 3369290001Sglebius if (bound != NULL) { 3370290001Sglebius event_debug(("Bound to port %d - Awaiting connections ... ", 3371290001Sglebius port)); 3372290001Sglebius return (bound); 3373290001Sglebius } 3374290001Sglebius 3375290001Sglebius return (NULL); 3376290001Sglebius} 3377290001Sglebius 3378290001Sglebiusint 3379290001Sglebiusevhttp_accept_socket(struct evhttp *http, evutil_socket_t fd) 3380290001Sglebius{ 3381290001Sglebius struct evhttp_bound_socket *bound = 3382290001Sglebius evhttp_accept_socket_with_handle(http, fd); 3383290001Sglebius if (bound == NULL) 3384290001Sglebius return (-1); 3385290001Sglebius return (0); 3386290001Sglebius} 3387290001Sglebius 3388290001Sglebiusvoid 3389290001Sglebiusevhttp_foreach_bound_socket(struct evhttp *http, 3390290001Sglebius evhttp_bound_socket_foreach_fn *function, 3391290001Sglebius void *argument) 3392290001Sglebius{ 3393290001Sglebius struct evhttp_bound_socket *bound; 3394290001Sglebius 3395290001Sglebius TAILQ_FOREACH(bound, &http->sockets, next) 3396290001Sglebius function(bound, argument); 3397290001Sglebius} 3398290001Sglebius 3399290001Sglebiusstruct evhttp_bound_socket * 3400290001Sglebiusevhttp_accept_socket_with_handle(struct evhttp *http, evutil_socket_t fd) 3401290001Sglebius{ 3402290001Sglebius struct evhttp_bound_socket *bound; 3403290001Sglebius struct evconnlistener *listener; 3404290001Sglebius const int flags = 3405290001Sglebius LEV_OPT_REUSEABLE|LEV_OPT_CLOSE_ON_EXEC|LEV_OPT_CLOSE_ON_FREE; 3406290001Sglebius 3407290001Sglebius listener = evconnlistener_new(http->base, NULL, NULL, 3408290001Sglebius flags, 3409290001Sglebius 0, /* Backlog is '0' because we already said 'listen' */ 3410290001Sglebius fd); 3411290001Sglebius if (!listener) 3412290001Sglebius return (NULL); 3413290001Sglebius 3414290001Sglebius bound = evhttp_bind_listener(http, listener); 3415290001Sglebius if (!bound) { 3416290001Sglebius evconnlistener_free(listener); 3417290001Sglebius return (NULL); 3418290001Sglebius } 3419290001Sglebius return (bound); 3420290001Sglebius} 3421290001Sglebius 3422290001Sglebiusstruct evhttp_bound_socket * 3423290001Sglebiusevhttp_bind_listener(struct evhttp *http, struct evconnlistener *listener) 3424290001Sglebius{ 3425290001Sglebius struct evhttp_bound_socket *bound; 3426290001Sglebius 3427290001Sglebius bound = mm_malloc(sizeof(struct evhttp_bound_socket)); 3428290001Sglebius if (bound == NULL) 3429290001Sglebius return (NULL); 3430290001Sglebius 3431290001Sglebius bound->listener = listener; 3432290001Sglebius TAILQ_INSERT_TAIL(&http->sockets, bound, next); 3433290001Sglebius 3434290001Sglebius evconnlistener_set_cb(listener, accept_socket_cb, http); 3435290001Sglebius return bound; 3436290001Sglebius} 3437290001Sglebius 3438290001Sglebiusevutil_socket_t 3439290001Sglebiusevhttp_bound_socket_get_fd(struct evhttp_bound_socket *bound) 3440290001Sglebius{ 3441290001Sglebius return evconnlistener_get_fd(bound->listener); 3442290001Sglebius} 3443290001Sglebius 3444290001Sglebiusstruct evconnlistener * 3445290001Sglebiusevhttp_bound_socket_get_listener(struct evhttp_bound_socket *bound) 3446290001Sglebius{ 3447290001Sglebius return bound->listener; 3448290001Sglebius} 3449290001Sglebius 3450290001Sglebiusvoid 3451290001Sglebiusevhttp_del_accept_socket(struct evhttp *http, struct evhttp_bound_socket *bound) 3452290001Sglebius{ 3453290001Sglebius TAILQ_REMOVE(&http->sockets, bound, next); 3454290001Sglebius evconnlistener_free(bound->listener); 3455290001Sglebius mm_free(bound); 3456290001Sglebius} 3457290001Sglebius 3458290001Sglebiusstatic struct evhttp* 3459290001Sglebiusevhttp_new_object(void) 3460290001Sglebius{ 3461290001Sglebius struct evhttp *http = NULL; 3462290001Sglebius 3463290001Sglebius if ((http = mm_calloc(1, sizeof(struct evhttp))) == NULL) { 3464290001Sglebius event_warn("%s: calloc", __func__); 3465290001Sglebius return (NULL); 3466290001Sglebius } 3467290001Sglebius 3468290001Sglebius evutil_timerclear(&http->timeout); 3469290001Sglebius evhttp_set_max_headers_size(http, EV_SIZE_MAX); 3470290001Sglebius evhttp_set_max_body_size(http, EV_SIZE_MAX); 3471290001Sglebius evhttp_set_default_content_type(http, "text/html; charset=ISO-8859-1"); 3472290001Sglebius evhttp_set_allowed_methods(http, 3473290001Sglebius EVHTTP_REQ_GET | 3474290001Sglebius EVHTTP_REQ_POST | 3475290001Sglebius EVHTTP_REQ_HEAD | 3476290001Sglebius EVHTTP_REQ_PUT | 3477290001Sglebius EVHTTP_REQ_DELETE); 3478290001Sglebius 3479290001Sglebius TAILQ_INIT(&http->sockets); 3480290001Sglebius TAILQ_INIT(&http->callbacks); 3481290001Sglebius TAILQ_INIT(&http->connections); 3482290001Sglebius TAILQ_INIT(&http->virtualhosts); 3483290001Sglebius TAILQ_INIT(&http->aliases); 3484290001Sglebius 3485290001Sglebius return (http); 3486290001Sglebius} 3487290001Sglebius 3488290001Sglebiusstruct evhttp * 3489290001Sglebiusevhttp_new(struct event_base *base) 3490290001Sglebius{ 3491290001Sglebius struct evhttp *http = NULL; 3492290001Sglebius 3493290001Sglebius http = evhttp_new_object(); 3494290001Sglebius if (http == NULL) 3495290001Sglebius return (NULL); 3496290001Sglebius http->base = base; 3497290001Sglebius 3498290001Sglebius return (http); 3499290001Sglebius} 3500290001Sglebius 3501290001Sglebius/* 3502290001Sglebius * Start a web server on the specified address and port. 3503290001Sglebius */ 3504290001Sglebius 3505290001Sglebiusstruct evhttp * 3506290001Sglebiusevhttp_start(const char *address, unsigned short port) 3507290001Sglebius{ 3508290001Sglebius struct evhttp *http = NULL; 3509290001Sglebius 3510290001Sglebius http = evhttp_new_object(); 3511290001Sglebius if (http == NULL) 3512290001Sglebius return (NULL); 3513290001Sglebius if (evhttp_bind_socket(http, address, port) == -1) { 3514290001Sglebius mm_free(http); 3515290001Sglebius return (NULL); 3516290001Sglebius } 3517290001Sglebius 3518290001Sglebius return (http); 3519290001Sglebius} 3520290001Sglebius 3521290001Sglebiusvoid 3522290001Sglebiusevhttp_free(struct evhttp* http) 3523290001Sglebius{ 3524290001Sglebius struct evhttp_cb *http_cb; 3525290001Sglebius struct evhttp_connection *evcon; 3526290001Sglebius struct evhttp_bound_socket *bound; 3527290001Sglebius struct evhttp* vhost; 3528290001Sglebius struct evhttp_server_alias *alias; 3529290001Sglebius 3530290001Sglebius /* Remove the accepting part */ 3531290001Sglebius while ((bound = TAILQ_FIRST(&http->sockets)) != NULL) { 3532290001Sglebius TAILQ_REMOVE(&http->sockets, bound, next); 3533290001Sglebius 3534290001Sglebius evconnlistener_free(bound->listener); 3535290001Sglebius 3536290001Sglebius mm_free(bound); 3537290001Sglebius } 3538290001Sglebius 3539290001Sglebius while ((evcon = TAILQ_FIRST(&http->connections)) != NULL) { 3540290001Sglebius /* evhttp_connection_free removes the connection */ 3541290001Sglebius evhttp_connection_free(evcon); 3542290001Sglebius } 3543290001Sglebius 3544290001Sglebius while ((http_cb = TAILQ_FIRST(&http->callbacks)) != NULL) { 3545290001Sglebius TAILQ_REMOVE(&http->callbacks, http_cb, next); 3546290001Sglebius mm_free(http_cb->what); 3547290001Sglebius mm_free(http_cb); 3548290001Sglebius } 3549290001Sglebius 3550290001Sglebius while ((vhost = TAILQ_FIRST(&http->virtualhosts)) != NULL) { 3551290001Sglebius TAILQ_REMOVE(&http->virtualhosts, vhost, next_vhost); 3552290001Sglebius 3553290001Sglebius evhttp_free(vhost); 3554290001Sglebius } 3555290001Sglebius 3556290001Sglebius if (http->vhost_pattern != NULL) 3557290001Sglebius mm_free(http->vhost_pattern); 3558290001Sglebius 3559290001Sglebius while ((alias = TAILQ_FIRST(&http->aliases)) != NULL) { 3560290001Sglebius TAILQ_REMOVE(&http->aliases, alias, next); 3561290001Sglebius mm_free(alias->alias); 3562290001Sglebius mm_free(alias); 3563290001Sglebius } 3564290001Sglebius 3565290001Sglebius mm_free(http); 3566290001Sglebius} 3567290001Sglebius 3568290001Sglebiusint 3569290001Sglebiusevhttp_add_virtual_host(struct evhttp* http, const char *pattern, 3570290001Sglebius struct evhttp* vhost) 3571290001Sglebius{ 3572290001Sglebius /* a vhost can only be a vhost once and should not have bound sockets */ 3573290001Sglebius if (vhost->vhost_pattern != NULL || 3574290001Sglebius TAILQ_FIRST(&vhost->sockets) != NULL) 3575290001Sglebius return (-1); 3576290001Sglebius 3577290001Sglebius vhost->vhost_pattern = mm_strdup(pattern); 3578290001Sglebius if (vhost->vhost_pattern == NULL) 3579290001Sglebius return (-1); 3580290001Sglebius 3581290001Sglebius TAILQ_INSERT_TAIL(&http->virtualhosts, vhost, next_vhost); 3582290001Sglebius 3583290001Sglebius return (0); 3584290001Sglebius} 3585290001Sglebius 3586290001Sglebiusint 3587290001Sglebiusevhttp_remove_virtual_host(struct evhttp* http, struct evhttp* vhost) 3588290001Sglebius{ 3589290001Sglebius if (vhost->vhost_pattern == NULL) 3590290001Sglebius return (-1); 3591290001Sglebius 3592290001Sglebius TAILQ_REMOVE(&http->virtualhosts, vhost, next_vhost); 3593290001Sglebius 3594290001Sglebius mm_free(vhost->vhost_pattern); 3595290001Sglebius vhost->vhost_pattern = NULL; 3596290001Sglebius 3597290001Sglebius return (0); 3598290001Sglebius} 3599290001Sglebius 3600290001Sglebiusint 3601290001Sglebiusevhttp_add_server_alias(struct evhttp *http, const char *alias) 3602290001Sglebius{ 3603290001Sglebius struct evhttp_server_alias *evalias; 3604290001Sglebius 3605290001Sglebius evalias = mm_calloc(1, sizeof(*evalias)); 3606290001Sglebius if (!evalias) 3607290001Sglebius return -1; 3608290001Sglebius 3609290001Sglebius evalias->alias = mm_strdup(alias); 3610290001Sglebius if (!evalias->alias) { 3611290001Sglebius mm_free(evalias); 3612290001Sglebius return -1; 3613290001Sglebius } 3614290001Sglebius 3615290001Sglebius TAILQ_INSERT_TAIL(&http->aliases, evalias, next); 3616290001Sglebius 3617290001Sglebius return 0; 3618290001Sglebius} 3619290001Sglebius 3620290001Sglebiusint 3621290001Sglebiusevhttp_remove_server_alias(struct evhttp *http, const char *alias) 3622290001Sglebius{ 3623290001Sglebius struct evhttp_server_alias *evalias; 3624290001Sglebius 3625290001Sglebius TAILQ_FOREACH(evalias, &http->aliases, next) { 3626290001Sglebius if (evutil_ascii_strcasecmp(evalias->alias, alias) == 0) { 3627290001Sglebius TAILQ_REMOVE(&http->aliases, evalias, next); 3628290001Sglebius mm_free(evalias->alias); 3629290001Sglebius mm_free(evalias); 3630290001Sglebius return 0; 3631290001Sglebius } 3632290001Sglebius } 3633290001Sglebius 3634290001Sglebius return -1; 3635290001Sglebius} 3636290001Sglebius 3637290001Sglebiusvoid 3638290001Sglebiusevhttp_set_timeout(struct evhttp* http, int timeout_in_secs) 3639290001Sglebius{ 3640290001Sglebius if (timeout_in_secs == -1) { 3641290001Sglebius evhttp_set_timeout_tv(http, NULL); 3642290001Sglebius } else { 3643290001Sglebius struct timeval tv; 3644290001Sglebius tv.tv_sec = timeout_in_secs; 3645290001Sglebius tv.tv_usec = 0; 3646290001Sglebius evhttp_set_timeout_tv(http, &tv); 3647290001Sglebius } 3648290001Sglebius} 3649290001Sglebius 3650290001Sglebiusvoid 3651290001Sglebiusevhttp_set_timeout_tv(struct evhttp* http, const struct timeval* tv) 3652290001Sglebius{ 3653290001Sglebius if (tv) { 3654290001Sglebius http->timeout = *tv; 3655290001Sglebius } else { 3656290001Sglebius evutil_timerclear(&http->timeout); 3657290001Sglebius } 3658290001Sglebius} 3659290001Sglebius 3660290001Sglebiusvoid 3661290001Sglebiusevhttp_set_max_headers_size(struct evhttp* http, ev_ssize_t max_headers_size) 3662290001Sglebius{ 3663290001Sglebius if (max_headers_size < 0) 3664290001Sglebius http->default_max_headers_size = EV_SIZE_MAX; 3665290001Sglebius else 3666290001Sglebius http->default_max_headers_size = max_headers_size; 3667290001Sglebius} 3668290001Sglebius 3669290001Sglebiusvoid 3670290001Sglebiusevhttp_set_max_body_size(struct evhttp* http, ev_ssize_t max_body_size) 3671290001Sglebius{ 3672290001Sglebius if (max_body_size < 0) 3673290001Sglebius http->default_max_body_size = EV_UINT64_MAX; 3674290001Sglebius else 3675290001Sglebius http->default_max_body_size = max_body_size; 3676290001Sglebius} 3677290001Sglebius 3678290001Sglebiusvoid 3679290001Sglebiusevhttp_set_default_content_type(struct evhttp *http, 3680290001Sglebius const char *content_type) { 3681290001Sglebius http->default_content_type = content_type; 3682290001Sglebius} 3683290001Sglebius 3684290001Sglebiusvoid 3685290001Sglebiusevhttp_set_allowed_methods(struct evhttp* http, ev_uint16_t methods) 3686290001Sglebius{ 3687290001Sglebius http->allowed_methods = methods; 3688290001Sglebius} 3689290001Sglebius 3690290001Sglebiusint 3691290001Sglebiusevhttp_set_cb(struct evhttp *http, const char *uri, 3692290001Sglebius void (*cb)(struct evhttp_request *, void *), void *cbarg) 3693290001Sglebius{ 3694290001Sglebius struct evhttp_cb *http_cb; 3695290001Sglebius 3696290001Sglebius TAILQ_FOREACH(http_cb, &http->callbacks, next) { 3697290001Sglebius if (strcmp(http_cb->what, uri) == 0) 3698290001Sglebius return (-1); 3699290001Sglebius } 3700290001Sglebius 3701290001Sglebius if ((http_cb = mm_calloc(1, sizeof(struct evhttp_cb))) == NULL) { 3702290001Sglebius event_warn("%s: calloc", __func__); 3703290001Sglebius return (-2); 3704290001Sglebius } 3705290001Sglebius 3706290001Sglebius http_cb->what = mm_strdup(uri); 3707290001Sglebius if (http_cb->what == NULL) { 3708290001Sglebius event_warn("%s: strdup", __func__); 3709290001Sglebius mm_free(http_cb); 3710290001Sglebius return (-3); 3711290001Sglebius } 3712290001Sglebius http_cb->cb = cb; 3713290001Sglebius http_cb->cbarg = cbarg; 3714290001Sglebius 3715290001Sglebius TAILQ_INSERT_TAIL(&http->callbacks, http_cb, next); 3716290001Sglebius 3717290001Sglebius return (0); 3718290001Sglebius} 3719290001Sglebius 3720290001Sglebiusint 3721290001Sglebiusevhttp_del_cb(struct evhttp *http, const char *uri) 3722290001Sglebius{ 3723290001Sglebius struct evhttp_cb *http_cb; 3724290001Sglebius 3725290001Sglebius TAILQ_FOREACH(http_cb, &http->callbacks, next) { 3726290001Sglebius if (strcmp(http_cb->what, uri) == 0) 3727290001Sglebius break; 3728290001Sglebius } 3729290001Sglebius if (http_cb == NULL) 3730290001Sglebius return (-1); 3731290001Sglebius 3732290001Sglebius TAILQ_REMOVE(&http->callbacks, http_cb, next); 3733290001Sglebius mm_free(http_cb->what); 3734290001Sglebius mm_free(http_cb); 3735290001Sglebius 3736290001Sglebius return (0); 3737290001Sglebius} 3738290001Sglebius 3739290001Sglebiusvoid 3740290001Sglebiusevhttp_set_gencb(struct evhttp *http, 3741290001Sglebius void (*cb)(struct evhttp_request *, void *), void *cbarg) 3742290001Sglebius{ 3743290001Sglebius http->gencb = cb; 3744290001Sglebius http->gencbarg = cbarg; 3745290001Sglebius} 3746290001Sglebius 3747290001Sglebiusvoid 3748290001Sglebiusevhttp_set_bevcb(struct evhttp *http, 3749290001Sglebius struct bufferevent* (*cb)(struct event_base *, void *), void *cbarg) 3750290001Sglebius{ 3751290001Sglebius http->bevcb = cb; 3752290001Sglebius http->bevcbarg = cbarg; 3753290001Sglebius} 3754290001Sglebius 3755290001Sglebius/* 3756290001Sglebius * Request related functions 3757290001Sglebius */ 3758290001Sglebius 3759290001Sglebiusstruct evhttp_request * 3760290001Sglebiusevhttp_request_new(void (*cb)(struct evhttp_request *, void *), void *arg) 3761290001Sglebius{ 3762290001Sglebius struct evhttp_request *req = NULL; 3763290001Sglebius 3764290001Sglebius /* Allocate request structure */ 3765290001Sglebius if ((req = mm_calloc(1, sizeof(struct evhttp_request))) == NULL) { 3766290001Sglebius event_warn("%s: calloc", __func__); 3767290001Sglebius goto error; 3768290001Sglebius } 3769290001Sglebius 3770290001Sglebius req->headers_size = 0; 3771290001Sglebius req->body_size = 0; 3772290001Sglebius 3773290001Sglebius req->kind = EVHTTP_RESPONSE; 3774290001Sglebius req->input_headers = mm_calloc(1, sizeof(struct evkeyvalq)); 3775290001Sglebius if (req->input_headers == NULL) { 3776290001Sglebius event_warn("%s: calloc", __func__); 3777290001Sglebius goto error; 3778290001Sglebius } 3779290001Sglebius TAILQ_INIT(req->input_headers); 3780290001Sglebius 3781290001Sglebius req->output_headers = mm_calloc(1, sizeof(struct evkeyvalq)); 3782290001Sglebius if (req->output_headers == NULL) { 3783290001Sglebius event_warn("%s: calloc", __func__); 3784290001Sglebius goto error; 3785290001Sglebius } 3786290001Sglebius TAILQ_INIT(req->output_headers); 3787290001Sglebius 3788290001Sglebius if ((req->input_buffer = evbuffer_new()) == NULL) { 3789290001Sglebius event_warn("%s: evbuffer_new", __func__); 3790290001Sglebius goto error; 3791290001Sglebius } 3792290001Sglebius 3793290001Sglebius if ((req->output_buffer = evbuffer_new()) == NULL) { 3794290001Sglebius event_warn("%s: evbuffer_new", __func__); 3795290001Sglebius goto error; 3796290001Sglebius } 3797290001Sglebius 3798290001Sglebius req->cb = cb; 3799290001Sglebius req->cb_arg = arg; 3800290001Sglebius 3801290001Sglebius return (req); 3802290001Sglebius 3803290001Sglebius error: 3804290001Sglebius if (req != NULL) 3805290001Sglebius evhttp_request_free(req); 3806290001Sglebius return (NULL); 3807290001Sglebius} 3808290001Sglebius 3809290001Sglebiusvoid 3810290001Sglebiusevhttp_request_free(struct evhttp_request *req) 3811290001Sglebius{ 3812290001Sglebius if ((req->flags & EVHTTP_REQ_DEFER_FREE) != 0) { 3813290001Sglebius req->flags |= EVHTTP_REQ_NEEDS_FREE; 3814290001Sglebius return; 3815290001Sglebius } 3816290001Sglebius 3817290001Sglebius if (req->remote_host != NULL) 3818290001Sglebius mm_free(req->remote_host); 3819290001Sglebius if (req->uri != NULL) 3820290001Sglebius mm_free(req->uri); 3821290001Sglebius if (req->uri_elems != NULL) 3822290001Sglebius evhttp_uri_free(req->uri_elems); 3823290001Sglebius if (req->response_code_line != NULL) 3824290001Sglebius mm_free(req->response_code_line); 3825290001Sglebius if (req->host_cache != NULL) 3826290001Sglebius mm_free(req->host_cache); 3827290001Sglebius 3828290001Sglebius evhttp_clear_headers(req->input_headers); 3829290001Sglebius mm_free(req->input_headers); 3830290001Sglebius 3831290001Sglebius evhttp_clear_headers(req->output_headers); 3832290001Sglebius mm_free(req->output_headers); 3833290001Sglebius 3834290001Sglebius if (req->input_buffer != NULL) 3835290001Sglebius evbuffer_free(req->input_buffer); 3836290001Sglebius 3837290001Sglebius if (req->output_buffer != NULL) 3838290001Sglebius evbuffer_free(req->output_buffer); 3839290001Sglebius 3840290001Sglebius mm_free(req); 3841290001Sglebius} 3842290001Sglebius 3843290001Sglebiusvoid 3844290001Sglebiusevhttp_request_own(struct evhttp_request *req) 3845290001Sglebius{ 3846290001Sglebius req->flags |= EVHTTP_USER_OWNED; 3847290001Sglebius} 3848290001Sglebius 3849290001Sglebiusint 3850290001Sglebiusevhttp_request_is_owned(struct evhttp_request *req) 3851290001Sglebius{ 3852290001Sglebius return (req->flags & EVHTTP_USER_OWNED) != 0; 3853290001Sglebius} 3854290001Sglebius 3855290001Sglebiusstruct evhttp_connection * 3856290001Sglebiusevhttp_request_get_connection(struct evhttp_request *req) 3857290001Sglebius{ 3858290001Sglebius return req->evcon; 3859290001Sglebius} 3860290001Sglebius 3861290001Sglebiusstruct event_base * 3862290001Sglebiusevhttp_connection_get_base(struct evhttp_connection *conn) 3863290001Sglebius{ 3864290001Sglebius return conn->base; 3865290001Sglebius} 3866290001Sglebius 3867290001Sglebiusvoid 3868290001Sglebiusevhttp_request_set_chunked_cb(struct evhttp_request *req, 3869290001Sglebius void (*cb)(struct evhttp_request *, void *)) 3870290001Sglebius{ 3871290001Sglebius req->chunk_cb = cb; 3872290001Sglebius} 3873290001Sglebius 3874290001Sglebiusvoid 3875290001Sglebiusevhttp_request_set_header_cb(struct evhttp_request *req, 3876290001Sglebius int (*cb)(struct evhttp_request *, void *)) 3877290001Sglebius{ 3878290001Sglebius req->header_cb = cb; 3879290001Sglebius} 3880290001Sglebius 3881290001Sglebiusvoid 3882290001Sglebiusevhttp_request_set_error_cb(struct evhttp_request *req, 3883290001Sglebius void (*cb)(enum evhttp_request_error, void *)) 3884290001Sglebius{ 3885290001Sglebius req->error_cb = cb; 3886290001Sglebius} 3887290001Sglebius 3888290001Sglebiusvoid 3889290001Sglebiusevhttp_request_set_on_complete_cb(struct evhttp_request *req, 3890290001Sglebius void (*cb)(struct evhttp_request *, void *), void *cb_arg) 3891290001Sglebius{ 3892290001Sglebius req->on_complete_cb = cb; 3893290001Sglebius req->on_complete_cb_arg = cb_arg; 3894290001Sglebius} 3895290001Sglebius 3896290001Sglebius/* 3897290001Sglebius * Allows for inspection of the request URI 3898290001Sglebius */ 3899290001Sglebius 3900290001Sglebiusconst char * 3901290001Sglebiusevhttp_request_get_uri(const struct evhttp_request *req) { 3902290001Sglebius if (req->uri == NULL) 3903290001Sglebius event_debug(("%s: request %p has no uri\n", __func__, req)); 3904290001Sglebius return (req->uri); 3905290001Sglebius} 3906290001Sglebius 3907290001Sglebiusconst struct evhttp_uri * 3908290001Sglebiusevhttp_request_get_evhttp_uri(const struct evhttp_request *req) { 3909290001Sglebius if (req->uri_elems == NULL) 3910290001Sglebius event_debug(("%s: request %p has no uri elems\n", 3911290001Sglebius __func__, req)); 3912290001Sglebius return (req->uri_elems); 3913290001Sglebius} 3914290001Sglebius 3915290001Sglebiusconst char * 3916290001Sglebiusevhttp_request_get_host(struct evhttp_request *req) 3917290001Sglebius{ 3918290001Sglebius const char *host = NULL; 3919290001Sglebius 3920290001Sglebius if (req->host_cache) 3921290001Sglebius return req->host_cache; 3922290001Sglebius 3923290001Sglebius if (req->uri_elems) 3924290001Sglebius host = evhttp_uri_get_host(req->uri_elems); 3925290001Sglebius if (!host && req->input_headers) { 3926290001Sglebius const char *p; 3927290001Sglebius size_t len; 3928290001Sglebius 3929290001Sglebius host = evhttp_find_header(req->input_headers, "Host"); 3930290001Sglebius /* The Host: header may include a port. Remove it here 3931290001Sglebius to be consistent with uri_elems case above. */ 3932290001Sglebius if (host) { 3933290001Sglebius p = host + strlen(host) - 1; 3934290001Sglebius while (p > host && EVUTIL_ISDIGIT_(*p)) 3935290001Sglebius --p; 3936290001Sglebius if (p > host && *p == ':') { 3937290001Sglebius len = p - host; 3938290001Sglebius req->host_cache = mm_malloc(len + 1); 3939290001Sglebius if (!req->host_cache) { 3940290001Sglebius event_warn("%s: malloc", __func__); 3941290001Sglebius return NULL; 3942290001Sglebius } 3943290001Sglebius memcpy(req->host_cache, host, len); 3944290001Sglebius req->host_cache[len] = '\0'; 3945290001Sglebius host = req->host_cache; 3946290001Sglebius } 3947290001Sglebius } 3948290001Sglebius } 3949290001Sglebius 3950290001Sglebius return host; 3951290001Sglebius} 3952290001Sglebius 3953290001Sglebiusenum evhttp_cmd_type 3954290001Sglebiusevhttp_request_get_command(const struct evhttp_request *req) { 3955290001Sglebius return (req->type); 3956290001Sglebius} 3957290001Sglebius 3958290001Sglebiusint 3959290001Sglebiusevhttp_request_get_response_code(const struct evhttp_request *req) 3960290001Sglebius{ 3961290001Sglebius return req->response_code; 3962290001Sglebius} 3963290001Sglebius 3964290001Sglebiusconst char * 3965290001Sglebiusevhttp_request_get_response_code_line(const struct evhttp_request *req) 3966290001Sglebius{ 3967290001Sglebius return req->response_code_line; 3968290001Sglebius} 3969290001Sglebius 3970290001Sglebius/** Returns the input headers */ 3971290001Sglebiusstruct evkeyvalq *evhttp_request_get_input_headers(struct evhttp_request *req) 3972290001Sglebius{ 3973290001Sglebius return (req->input_headers); 3974290001Sglebius} 3975290001Sglebius 3976290001Sglebius/** Returns the output headers */ 3977290001Sglebiusstruct evkeyvalq *evhttp_request_get_output_headers(struct evhttp_request *req) 3978290001Sglebius{ 3979290001Sglebius return (req->output_headers); 3980290001Sglebius} 3981290001Sglebius 3982290001Sglebius/** Returns the input buffer */ 3983290001Sglebiusstruct evbuffer *evhttp_request_get_input_buffer(struct evhttp_request *req) 3984290001Sglebius{ 3985290001Sglebius return (req->input_buffer); 3986290001Sglebius} 3987290001Sglebius 3988290001Sglebius/** Returns the output buffer */ 3989290001Sglebiusstruct evbuffer *evhttp_request_get_output_buffer(struct evhttp_request *req) 3990290001Sglebius{ 3991290001Sglebius return (req->output_buffer); 3992290001Sglebius} 3993290001Sglebius 3994290001Sglebius 3995290001Sglebius/* 3996290001Sglebius * Takes a file descriptor to read a request from. 3997290001Sglebius * The callback is executed once the whole request has been read. 3998290001Sglebius */ 3999290001Sglebius 4000290001Sglebiusstatic struct evhttp_connection* 4001290001Sglebiusevhttp_get_request_connection( 4002290001Sglebius struct evhttp* http, 4003290001Sglebius evutil_socket_t fd, struct sockaddr *sa, ev_socklen_t salen) 4004290001Sglebius{ 4005290001Sglebius struct evhttp_connection *evcon; 4006290001Sglebius char *hostname = NULL, *portname = NULL; 4007290001Sglebius struct bufferevent* bev = NULL; 4008290001Sglebius 4009290001Sglebius name_from_addr(sa, salen, &hostname, &portname); 4010290001Sglebius if (hostname == NULL || portname == NULL) { 4011290001Sglebius if (hostname) mm_free(hostname); 4012290001Sglebius if (portname) mm_free(portname); 4013290001Sglebius return (NULL); 4014290001Sglebius } 4015290001Sglebius 4016290001Sglebius event_debug(("%s: new request from %s:%s on "EV_SOCK_FMT"\n", 4017290001Sglebius __func__, hostname, portname, EV_SOCK_ARG(fd))); 4018290001Sglebius 4019290001Sglebius /* we need a connection object to put the http request on */ 4020290001Sglebius if (http->bevcb != NULL) { 4021290001Sglebius bev = (*http->bevcb)(http->base, http->bevcbarg); 4022290001Sglebius } 4023290001Sglebius evcon = evhttp_connection_base_bufferevent_new( 4024290001Sglebius http->base, NULL, bev, hostname, atoi(portname)); 4025290001Sglebius mm_free(hostname); 4026290001Sglebius mm_free(portname); 4027290001Sglebius if (evcon == NULL) 4028290001Sglebius return (NULL); 4029290001Sglebius 4030290001Sglebius evcon->max_headers_size = http->default_max_headers_size; 4031290001Sglebius evcon->max_body_size = http->default_max_body_size; 4032290001Sglebius 4033290001Sglebius evcon->flags |= EVHTTP_CON_INCOMING; 4034290001Sglebius evcon->state = EVCON_READING_FIRSTLINE; 4035290001Sglebius 4036290001Sglebius evcon->fd = fd; 4037290001Sglebius 4038290001Sglebius bufferevent_setfd(evcon->bufev, fd); 4039290001Sglebius 4040290001Sglebius return (evcon); 4041290001Sglebius} 4042290001Sglebius 4043290001Sglebiusstatic int 4044290001Sglebiusevhttp_associate_new_request_with_connection(struct evhttp_connection *evcon) 4045290001Sglebius{ 4046290001Sglebius struct evhttp *http = evcon->http_server; 4047290001Sglebius struct evhttp_request *req; 4048290001Sglebius if ((req = evhttp_request_new(evhttp_handle_request, http)) == NULL) 4049290001Sglebius return (-1); 4050290001Sglebius 4051290001Sglebius if ((req->remote_host = mm_strdup(evcon->address)) == NULL) { 4052290001Sglebius event_warn("%s: strdup", __func__); 4053290001Sglebius evhttp_request_free(req); 4054290001Sglebius return (-1); 4055290001Sglebius } 4056290001Sglebius req->remote_port = evcon->port; 4057290001Sglebius 4058290001Sglebius req->evcon = evcon; /* the request ends up owning the connection */ 4059290001Sglebius req->flags |= EVHTTP_REQ_OWN_CONNECTION; 4060290001Sglebius 4061290001Sglebius /* We did not present the request to the user user yet, so treat it as 4062290001Sglebius * if the user was done with the request. This allows us to free the 4063290001Sglebius * request on a persistent connection if the client drops it without 4064290001Sglebius * sending a request. 4065290001Sglebius */ 4066290001Sglebius req->userdone = 1; 4067290001Sglebius 4068290001Sglebius TAILQ_INSERT_TAIL(&evcon->requests, req, next); 4069290001Sglebius 4070290001Sglebius req->kind = EVHTTP_REQUEST; 4071290001Sglebius 4072290001Sglebius 4073290001Sglebius evhttp_start_read_(evcon); 4074290001Sglebius 4075290001Sglebius return (0); 4076290001Sglebius} 4077290001Sglebius 4078290001Sglebiusstatic void 4079290001Sglebiusevhttp_get_request(struct evhttp *http, evutil_socket_t fd, 4080290001Sglebius struct sockaddr *sa, ev_socklen_t salen) 4081290001Sglebius{ 4082290001Sglebius struct evhttp_connection *evcon; 4083290001Sglebius 4084290001Sglebius evcon = evhttp_get_request_connection(http, fd, sa, salen); 4085290001Sglebius if (evcon == NULL) { 4086290001Sglebius event_sock_warn(fd, "%s: cannot get connection on "EV_SOCK_FMT, 4087290001Sglebius __func__, EV_SOCK_ARG(fd)); 4088290001Sglebius evutil_closesocket(fd); 4089290001Sglebius return; 4090290001Sglebius } 4091290001Sglebius 4092290001Sglebius /* the timeout can be used by the server to close idle connections */ 4093290001Sglebius if (evutil_timerisset(&http->timeout)) 4094290001Sglebius evhttp_connection_set_timeout_tv(evcon, &http->timeout); 4095290001Sglebius 4096290001Sglebius /* 4097290001Sglebius * if we want to accept more than one request on a connection, 4098290001Sglebius * we need to know which http server it belongs to. 4099290001Sglebius */ 4100290001Sglebius evcon->http_server = http; 4101290001Sglebius TAILQ_INSERT_TAIL(&http->connections, evcon, next); 4102290001Sglebius 4103290001Sglebius if (evhttp_associate_new_request_with_connection(evcon) == -1) 4104290001Sglebius evhttp_connection_free(evcon); 4105290001Sglebius} 4106290001Sglebius 4107290001Sglebius 4108290001Sglebius/* 4109290001Sglebius * Network helper functions that we do not want to export to the rest of 4110290001Sglebius * the world. 4111290001Sglebius */ 4112290001Sglebius 4113290001Sglebiusstatic void 4114290001Sglebiusname_from_addr(struct sockaddr *sa, ev_socklen_t salen, 4115290001Sglebius char **phost, char **pport) 4116290001Sglebius{ 4117290001Sglebius char ntop[NI_MAXHOST]; 4118290001Sglebius char strport[NI_MAXSERV]; 4119290001Sglebius int ni_result; 4120290001Sglebius 4121290001Sglebius#ifdef EVENT__HAVE_GETNAMEINFO 4122290001Sglebius ni_result = getnameinfo(sa, salen, 4123290001Sglebius ntop, sizeof(ntop), strport, sizeof(strport), 4124290001Sglebius NI_NUMERICHOST|NI_NUMERICSERV); 4125290001Sglebius 4126290001Sglebius if (ni_result != 0) { 4127290001Sglebius#ifdef EAI_SYSTEM 4128290001Sglebius /* Windows doesn't have an EAI_SYSTEM. */ 4129290001Sglebius if (ni_result == EAI_SYSTEM) 4130290001Sglebius event_err(1, "getnameinfo failed"); 4131290001Sglebius else 4132290001Sglebius#endif 4133290001Sglebius event_errx(1, "getnameinfo failed: %s", gai_strerror(ni_result)); 4134290001Sglebius return; 4135290001Sglebius } 4136290001Sglebius#else 4137290001Sglebius ni_result = fake_getnameinfo(sa, salen, 4138290001Sglebius ntop, sizeof(ntop), strport, sizeof(strport), 4139290001Sglebius NI_NUMERICHOST|NI_NUMERICSERV); 4140290001Sglebius if (ni_result != 0) 4141290001Sglebius return; 4142290001Sglebius#endif 4143290001Sglebius 4144290001Sglebius *phost = mm_strdup(ntop); 4145290001Sglebius *pport = mm_strdup(strport); 4146290001Sglebius} 4147290001Sglebius 4148290001Sglebius/* Create a non-blocking socket and bind it */ 4149290001Sglebius/* todo: rename this function */ 4150290001Sglebiusstatic evutil_socket_t 4151290001Sglebiusbind_socket_ai(struct evutil_addrinfo *ai, int reuse) 4152290001Sglebius{ 4153290001Sglebius evutil_socket_t fd; 4154290001Sglebius 4155290001Sglebius int on = 1, r; 4156290001Sglebius int serrno; 4157290001Sglebius 4158290001Sglebius /* Create listen socket */ 4159290001Sglebius fd = evutil_socket_(ai ? ai->ai_family : AF_INET, 4160290001Sglebius SOCK_STREAM|EVUTIL_SOCK_NONBLOCK|EVUTIL_SOCK_CLOEXEC, 0); 4161290001Sglebius if (fd == -1) { 4162290001Sglebius event_sock_warn(-1, "socket"); 4163290001Sglebius return (-1); 4164290001Sglebius } 4165290001Sglebius 4166290001Sglebius if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (void *)&on, sizeof(on))<0) 4167290001Sglebius goto out; 4168290001Sglebius if (reuse) { 4169290001Sglebius if (evutil_make_listen_socket_reuseable(fd) < 0) 4170290001Sglebius goto out; 4171290001Sglebius } 4172290001Sglebius 4173290001Sglebius if (ai != NULL) { 4174290001Sglebius r = bind(fd, ai->ai_addr, (ev_socklen_t)ai->ai_addrlen); 4175290001Sglebius if (r == -1) 4176290001Sglebius goto out; 4177290001Sglebius } 4178290001Sglebius 4179290001Sglebius return (fd); 4180290001Sglebius 4181290001Sglebius out: 4182290001Sglebius serrno = EVUTIL_SOCKET_ERROR(); 4183290001Sglebius evutil_closesocket(fd); 4184290001Sglebius EVUTIL_SET_SOCKET_ERROR(serrno); 4185290001Sglebius return (-1); 4186290001Sglebius} 4187290001Sglebius 4188290001Sglebiusstatic struct evutil_addrinfo * 4189290001Sglebiusmake_addrinfo(const char *address, ev_uint16_t port) 4190290001Sglebius{ 4191290001Sglebius struct evutil_addrinfo *ai = NULL; 4192290001Sglebius 4193290001Sglebius struct evutil_addrinfo hints; 4194290001Sglebius char strport[NI_MAXSERV]; 4195290001Sglebius int ai_result; 4196290001Sglebius 4197290001Sglebius memset(&hints, 0, sizeof(hints)); 4198290001Sglebius hints.ai_family = AF_UNSPEC; 4199290001Sglebius hints.ai_socktype = SOCK_STREAM; 4200290001Sglebius /* turn NULL hostname into INADDR_ANY, and skip looking up any address 4201290001Sglebius * types we don't have an interface to connect to. */ 4202290001Sglebius hints.ai_flags = EVUTIL_AI_PASSIVE|EVUTIL_AI_ADDRCONFIG; 4203290001Sglebius evutil_snprintf(strport, sizeof(strport), "%d", port); 4204290001Sglebius if ((ai_result = evutil_getaddrinfo(address, strport, &hints, &ai)) 4205290001Sglebius != 0) { 4206290001Sglebius if (ai_result == EVUTIL_EAI_SYSTEM) 4207290001Sglebius event_warn("getaddrinfo"); 4208290001Sglebius else 4209290001Sglebius event_warnx("getaddrinfo: %s", 4210290001Sglebius evutil_gai_strerror(ai_result)); 4211290001Sglebius return (NULL); 4212290001Sglebius } 4213290001Sglebius 4214290001Sglebius return (ai); 4215290001Sglebius} 4216290001Sglebius 4217290001Sglebiusstatic evutil_socket_t 4218290001Sglebiusbind_socket(const char *address, ev_uint16_t port, int reuse) 4219290001Sglebius{ 4220290001Sglebius evutil_socket_t fd; 4221290001Sglebius struct evutil_addrinfo *aitop = NULL; 4222290001Sglebius 4223290001Sglebius /* just create an unbound socket */ 4224290001Sglebius if (address == NULL && port == 0) 4225290001Sglebius return bind_socket_ai(NULL, 0); 4226290001Sglebius 4227290001Sglebius aitop = make_addrinfo(address, port); 4228290001Sglebius 4229290001Sglebius if (aitop == NULL) 4230290001Sglebius return (-1); 4231290001Sglebius 4232290001Sglebius fd = bind_socket_ai(aitop, reuse); 4233290001Sglebius 4234290001Sglebius evutil_freeaddrinfo(aitop); 4235290001Sglebius 4236290001Sglebius return (fd); 4237290001Sglebius} 4238290001Sglebius 4239290001Sglebiusstruct evhttp_uri { 4240290001Sglebius unsigned flags; 4241290001Sglebius char *scheme; /* scheme; e.g http, ftp etc */ 4242290001Sglebius char *userinfo; /* userinfo (typically username:pass), or NULL */ 4243290001Sglebius char *host; /* hostname, IP address, or NULL */ 4244290001Sglebius int port; /* port, or zero */ 4245290001Sglebius char *path; /* path, or "". */ 4246290001Sglebius char *query; /* query, or NULL */ 4247290001Sglebius char *fragment; /* fragment or NULL */ 4248290001Sglebius}; 4249290001Sglebius 4250290001Sglebiusstruct evhttp_uri * 4251290001Sglebiusevhttp_uri_new(void) 4252290001Sglebius{ 4253290001Sglebius struct evhttp_uri *uri = mm_calloc(sizeof(struct evhttp_uri), 1); 4254290001Sglebius if (uri) 4255290001Sglebius uri->port = -1; 4256290001Sglebius return uri; 4257290001Sglebius} 4258290001Sglebius 4259290001Sglebiusvoid 4260290001Sglebiusevhttp_uri_set_flags(struct evhttp_uri *uri, unsigned flags) 4261290001Sglebius{ 4262290001Sglebius uri->flags = flags; 4263290001Sglebius} 4264290001Sglebius 4265290001Sglebius/* Return true if the string starting at s and ending immediately before eos 4266290001Sglebius * is a valid URI scheme according to RFC3986 4267290001Sglebius */ 4268290001Sglebiusstatic int 4269290001Sglebiusscheme_ok(const char *s, const char *eos) 4270290001Sglebius{ 4271290001Sglebius /* scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." ) */ 4272290001Sglebius EVUTIL_ASSERT(eos >= s); 4273290001Sglebius if (s == eos) 4274290001Sglebius return 0; 4275290001Sglebius if (!EVUTIL_ISALPHA_(*s)) 4276290001Sglebius return 0; 4277290001Sglebius while (++s < eos) { 4278290001Sglebius if (! EVUTIL_ISALNUM_(*s) && 4279290001Sglebius *s != '+' && *s != '-' && *s != '.') 4280290001Sglebius return 0; 4281290001Sglebius } 4282290001Sglebius return 1; 4283290001Sglebius} 4284290001Sglebius 4285290001Sglebius#define SUBDELIMS "!$&'()*+,;=" 4286290001Sglebius 4287290001Sglebius/* Return true iff [s..eos) is a valid userinfo */ 4288290001Sglebiusstatic int 4289290001Sglebiususerinfo_ok(const char *s, const char *eos) 4290290001Sglebius{ 4291290001Sglebius while (s < eos) { 4292290001Sglebius if (CHAR_IS_UNRESERVED(*s) || 4293290001Sglebius strchr(SUBDELIMS, *s) || 4294290001Sglebius *s == ':') 4295290001Sglebius ++s; 4296290001Sglebius else if (*s == '%' && s+2 < eos && 4297290001Sglebius EVUTIL_ISXDIGIT_(s[1]) && 4298290001Sglebius EVUTIL_ISXDIGIT_(s[2])) 4299290001Sglebius s += 3; 4300290001Sglebius else 4301290001Sglebius return 0; 4302290001Sglebius } 4303290001Sglebius return 1; 4304290001Sglebius} 4305290001Sglebius 4306290001Sglebiusstatic int 4307290001Sglebiusregname_ok(const char *s, const char *eos) 4308290001Sglebius{ 4309290001Sglebius while (s && s<eos) { 4310290001Sglebius if (CHAR_IS_UNRESERVED(*s) || 4311290001Sglebius strchr(SUBDELIMS, *s)) 4312290001Sglebius ++s; 4313290001Sglebius else if (*s == '%' && 4314290001Sglebius EVUTIL_ISXDIGIT_(s[1]) && 4315290001Sglebius EVUTIL_ISXDIGIT_(s[2])) 4316290001Sglebius s += 3; 4317290001Sglebius else 4318290001Sglebius return 0; 4319290001Sglebius } 4320290001Sglebius return 1; 4321290001Sglebius} 4322290001Sglebius 4323290001Sglebiusstatic int 4324290001Sglebiusparse_port(const char *s, const char *eos) 4325290001Sglebius{ 4326290001Sglebius int portnum = 0; 4327290001Sglebius while (s < eos) { 4328290001Sglebius if (! EVUTIL_ISDIGIT_(*s)) 4329290001Sglebius return -1; 4330290001Sglebius portnum = (portnum * 10) + (*s - '0'); 4331290001Sglebius if (portnum < 0) 4332290001Sglebius return -1; 4333290001Sglebius if (portnum > 65535) 4334290001Sglebius return -1; 4335290001Sglebius ++s; 4336290001Sglebius } 4337290001Sglebius return portnum; 4338290001Sglebius} 4339290001Sglebius 4340290001Sglebius/* returns 0 for bad, 1 for ipv6, 2 for IPvFuture */ 4341290001Sglebiusstatic int 4342290001Sglebiusbracket_addr_ok(const char *s, const char *eos) 4343290001Sglebius{ 4344290001Sglebius if (s + 3 > eos || *s != '[' || *(eos-1) != ']') 4345290001Sglebius return 0; 4346290001Sglebius if (s[1] == 'v') { 4347290001Sglebius /* IPvFuture, or junk. 4348290001Sglebius "v" 1*HEXDIG "." 1*( unreserved / sub-delims / ":" ) 4349290001Sglebius */ 4350290001Sglebius s += 2; /* skip [v */ 4351290001Sglebius --eos; 4352290001Sglebius if (!EVUTIL_ISXDIGIT_(*s)) /*require at least one*/ 4353290001Sglebius return 0; 4354290001Sglebius while (s < eos && *s != '.') { 4355290001Sglebius if (EVUTIL_ISXDIGIT_(*s)) 4356290001Sglebius ++s; 4357290001Sglebius else 4358290001Sglebius return 0; 4359290001Sglebius } 4360290001Sglebius if (*s != '.') 4361290001Sglebius return 0; 4362290001Sglebius ++s; 4363290001Sglebius while (s < eos) { 4364290001Sglebius if (CHAR_IS_UNRESERVED(*s) || 4365290001Sglebius strchr(SUBDELIMS, *s) || 4366290001Sglebius *s == ':') 4367290001Sglebius ++s; 4368290001Sglebius else 4369290001Sglebius return 0; 4370290001Sglebius } 4371290001Sglebius return 2; 4372290001Sglebius } else { 4373290001Sglebius /* IPv6, or junk */ 4374290001Sglebius char buf[64]; 4375290001Sglebius ev_ssize_t n_chars = eos-s-2; 4376290001Sglebius struct in6_addr in6; 4377290001Sglebius if (n_chars >= 64) /* way too long */ 4378290001Sglebius return 0; 4379290001Sglebius memcpy(buf, s+1, n_chars); 4380290001Sglebius buf[n_chars]='\0'; 4381290001Sglebius return (evutil_inet_pton(AF_INET6,buf,&in6)==1) ? 1 : 0; 4382290001Sglebius } 4383290001Sglebius} 4384290001Sglebius 4385290001Sglebiusstatic int 4386290001Sglebiusparse_authority(struct evhttp_uri *uri, char *s, char *eos) 4387290001Sglebius{ 4388290001Sglebius char *cp, *port; 4389290001Sglebius EVUTIL_ASSERT(eos); 4390290001Sglebius if (eos == s) { 4391290001Sglebius uri->host = mm_strdup(""); 4392290001Sglebius if (uri->host == NULL) { 4393290001Sglebius event_warn("%s: strdup", __func__); 4394290001Sglebius return -1; 4395290001Sglebius } 4396290001Sglebius return 0; 4397290001Sglebius } 4398290001Sglebius 4399290001Sglebius /* Optionally, we start with "userinfo@" */ 4400290001Sglebius 4401290001Sglebius cp = strchr(s, '@'); 4402290001Sglebius if (cp && cp < eos) { 4403290001Sglebius if (! userinfo_ok(s,cp)) 4404290001Sglebius return -1; 4405290001Sglebius *cp++ = '\0'; 4406290001Sglebius uri->userinfo = mm_strdup(s); 4407290001Sglebius if (uri->userinfo == NULL) { 4408290001Sglebius event_warn("%s: strdup", __func__); 4409290001Sglebius return -1; 4410290001Sglebius } 4411290001Sglebius } else { 4412290001Sglebius cp = s; 4413290001Sglebius } 4414290001Sglebius /* Optionally, we end with ":port" */ 4415290001Sglebius for (port=eos-1; port >= cp && EVUTIL_ISDIGIT_(*port); --port) 4416290001Sglebius ; 4417290001Sglebius if (port >= cp && *port == ':') { 4418290001Sglebius if (port+1 == eos) /* Leave port unspecified; the RFC allows a 4419290001Sglebius * nil port */ 4420290001Sglebius uri->port = -1; 4421290001Sglebius else if ((uri->port = parse_port(port+1, eos))<0) 4422290001Sglebius return -1; 4423290001Sglebius eos = port; 4424290001Sglebius } 4425290001Sglebius /* Now, cp..eos holds the "host" port, which can be an IPv4Address, 4426290001Sglebius * an IP-Literal, or a reg-name */ 4427290001Sglebius EVUTIL_ASSERT(eos >= cp); 4428290001Sglebius if (*cp == '[' && eos >= cp+2 && *(eos-1) == ']') { 4429290001Sglebius /* IPv6address, IP-Literal, or junk. */ 4430290001Sglebius if (! bracket_addr_ok(cp, eos)) 4431290001Sglebius return -1; 4432290001Sglebius } else { 4433290001Sglebius /* Make sure the host part is ok. */ 4434290001Sglebius if (! regname_ok(cp,eos)) /* Match IPv4Address or reg-name */ 4435290001Sglebius return -1; 4436290001Sglebius } 4437290001Sglebius uri->host = mm_malloc(eos-cp+1); 4438290001Sglebius if (uri->host == NULL) { 4439290001Sglebius event_warn("%s: malloc", __func__); 4440290001Sglebius return -1; 4441290001Sglebius } 4442290001Sglebius memcpy(uri->host, cp, eos-cp); 4443290001Sglebius uri->host[eos-cp] = '\0'; 4444290001Sglebius return 0; 4445290001Sglebius 4446290001Sglebius} 4447290001Sglebius 4448290001Sglebiusstatic char * 4449290001Sglebiusend_of_authority(char *cp) 4450290001Sglebius{ 4451290001Sglebius while (*cp) { 4452290001Sglebius if (*cp == '?' || *cp == '#' || *cp == '/') 4453290001Sglebius return cp; 4454290001Sglebius ++cp; 4455290001Sglebius } 4456290001Sglebius return cp; 4457290001Sglebius} 4458290001Sglebius 4459290001Sglebiusenum uri_part { 4460290001Sglebius PART_PATH, 4461290001Sglebius PART_QUERY, 4462290001Sglebius PART_FRAGMENT 4463290001Sglebius}; 4464290001Sglebius 4465290001Sglebius/* Return the character after the longest prefix of 'cp' that matches... 4466290001Sglebius * *pchar / "/" if allow_qchars is false, or 4467290001Sglebius * *(pchar / "/" / "?") if allow_qchars is true. 4468290001Sglebius */ 4469290001Sglebiusstatic char * 4470290001Sglebiusend_of_path(char *cp, enum uri_part part, unsigned flags) 4471290001Sglebius{ 4472290001Sglebius if (flags & EVHTTP_URI_NONCONFORMANT) { 4473290001Sglebius /* If NONCONFORMANT: 4474290001Sglebius * Path is everything up to a # or ? or nul. 4475290001Sglebius * Query is everything up a # or nul 4476290001Sglebius * Fragment is everything up to a nul. 4477290001Sglebius */ 4478290001Sglebius switch (part) { 4479290001Sglebius case PART_PATH: 4480290001Sglebius while (*cp && *cp != '#' && *cp != '?') 4481290001Sglebius ++cp; 4482290001Sglebius break; 4483290001Sglebius case PART_QUERY: 4484290001Sglebius while (*cp && *cp != '#') 4485290001Sglebius ++cp; 4486290001Sglebius break; 4487290001Sglebius case PART_FRAGMENT: 4488290001Sglebius cp += strlen(cp); 4489290001Sglebius break; 4490290001Sglebius }; 4491290001Sglebius return cp; 4492290001Sglebius } 4493290001Sglebius 4494290001Sglebius while (*cp) { 4495290001Sglebius if (CHAR_IS_UNRESERVED(*cp) || 4496290001Sglebius strchr(SUBDELIMS, *cp) || 4497290001Sglebius *cp == ':' || *cp == '@' || *cp == '/') 4498290001Sglebius ++cp; 4499290001Sglebius else if (*cp == '%' && EVUTIL_ISXDIGIT_(cp[1]) && 4500290001Sglebius EVUTIL_ISXDIGIT_(cp[2])) 4501290001Sglebius cp += 3; 4502290001Sglebius else if (*cp == '?' && part != PART_PATH) 4503290001Sglebius ++cp; 4504290001Sglebius else 4505290001Sglebius return cp; 4506290001Sglebius } 4507290001Sglebius return cp; 4508290001Sglebius} 4509290001Sglebius 4510290001Sglebiusstatic int 4511290001Sglebiuspath_matches_noscheme(const char *cp) 4512290001Sglebius{ 4513290001Sglebius while (*cp) { 4514290001Sglebius if (*cp == ':') 4515290001Sglebius return 0; 4516290001Sglebius else if (*cp == '/') 4517290001Sglebius return 1; 4518290001Sglebius ++cp; 4519290001Sglebius } 4520290001Sglebius return 1; 4521290001Sglebius} 4522290001Sglebius 4523290001Sglebiusstruct evhttp_uri * 4524290001Sglebiusevhttp_uri_parse(const char *source_uri) 4525290001Sglebius{ 4526290001Sglebius return evhttp_uri_parse_with_flags(source_uri, 0); 4527290001Sglebius} 4528290001Sglebius 4529290001Sglebiusstruct evhttp_uri * 4530290001Sglebiusevhttp_uri_parse_with_flags(const char *source_uri, unsigned flags) 4531290001Sglebius{ 4532290001Sglebius char *readbuf = NULL, *readp = NULL, *token = NULL, *query = NULL; 4533290001Sglebius char *path = NULL, *fragment = NULL; 4534290001Sglebius int got_authority = 0; 4535290001Sglebius 4536290001Sglebius struct evhttp_uri *uri = mm_calloc(1, sizeof(struct evhttp_uri)); 4537290001Sglebius if (uri == NULL) { 4538290001Sglebius event_warn("%s: calloc", __func__); 4539290001Sglebius goto err; 4540290001Sglebius } 4541290001Sglebius uri->port = -1; 4542290001Sglebius uri->flags = flags; 4543290001Sglebius 4544290001Sglebius readbuf = mm_strdup(source_uri); 4545290001Sglebius if (readbuf == NULL) { 4546290001Sglebius event_warn("%s: strdup", __func__); 4547290001Sglebius goto err; 4548290001Sglebius } 4549290001Sglebius 4550290001Sglebius readp = readbuf; 4551290001Sglebius token = NULL; 4552290001Sglebius 4553290001Sglebius /* We try to follow RFC3986 here as much as we can, and match 4554290001Sglebius the productions 4555290001Sglebius 4556290001Sglebius URI = scheme ":" hier-part [ "?" query ] [ "#" fragment ] 4557290001Sglebius 4558290001Sglebius relative-ref = relative-part [ "?" query ] [ "#" fragment ] 4559290001Sglebius */ 4560290001Sglebius 4561290001Sglebius /* 1. scheme: */ 4562290001Sglebius token = strchr(readp, ':'); 4563290001Sglebius if (token && scheme_ok(readp,token)) { 4564290001Sglebius *token = '\0'; 4565290001Sglebius uri->scheme = mm_strdup(readp); 4566290001Sglebius if (uri->scheme == NULL) { 4567290001Sglebius event_warn("%s: strdup", __func__); 4568290001Sglebius goto err; 4569290001Sglebius } 4570290001Sglebius readp = token+1; /* eat : */ 4571290001Sglebius } 4572290001Sglebius 4573290001Sglebius /* 2. Optionally, "//" then an 'authority' part. */ 4574290001Sglebius if (readp[0]=='/' && readp[1] == '/') { 4575290001Sglebius char *authority; 4576290001Sglebius readp += 2; 4577290001Sglebius authority = readp; 4578290001Sglebius path = end_of_authority(readp); 4579290001Sglebius if (parse_authority(uri, authority, path) < 0) 4580290001Sglebius goto err; 4581290001Sglebius readp = path; 4582290001Sglebius got_authority = 1; 4583290001Sglebius } 4584290001Sglebius 4585290001Sglebius /* 3. Query: path-abempty, path-absolute, path-rootless, or path-empty 4586290001Sglebius */ 4587290001Sglebius path = readp; 4588290001Sglebius readp = end_of_path(path, PART_PATH, flags); 4589290001Sglebius 4590290001Sglebius /* Query */ 4591290001Sglebius if (*readp == '?') { 4592290001Sglebius *readp = '\0'; 4593290001Sglebius ++readp; 4594290001Sglebius query = readp; 4595290001Sglebius readp = end_of_path(readp, PART_QUERY, flags); 4596290001Sglebius } 4597290001Sglebius /* fragment */ 4598290001Sglebius if (*readp == '#') { 4599290001Sglebius *readp = '\0'; 4600290001Sglebius ++readp; 4601290001Sglebius fragment = readp; 4602290001Sglebius readp = end_of_path(readp, PART_FRAGMENT, flags); 4603290001Sglebius } 4604290001Sglebius if (*readp != '\0') { 4605290001Sglebius goto err; 4606290001Sglebius } 4607290001Sglebius 4608290001Sglebius /* These next two cases may be unreachable; I'm leaving them 4609290001Sglebius * in to be defensive. */ 4610290001Sglebius /* If you didn't get an authority, the path can't begin with "//" */ 4611290001Sglebius if (!got_authority && path[0]=='/' && path[1]=='/') 4612290001Sglebius goto err; 4613290001Sglebius /* If you did get an authority, the path must begin with "/" or be 4614290001Sglebius * empty. */ 4615290001Sglebius if (got_authority && path[0] != '/' && path[0] != '\0') 4616290001Sglebius goto err; 4617290001Sglebius /* (End of maybe-unreachable cases) */ 4618290001Sglebius 4619290001Sglebius /* If there was no scheme, the first part of the path (if any) must 4620290001Sglebius * have no colon in it. */ 4621290001Sglebius if (! uri->scheme && !path_matches_noscheme(path)) 4622290001Sglebius goto err; 4623290001Sglebius 4624290001Sglebius EVUTIL_ASSERT(path); 4625290001Sglebius uri->path = mm_strdup(path); 4626290001Sglebius if (uri->path == NULL) { 4627290001Sglebius event_warn("%s: strdup", __func__); 4628290001Sglebius goto err; 4629290001Sglebius } 4630290001Sglebius 4631290001Sglebius if (query) { 4632290001Sglebius uri->query = mm_strdup(query); 4633290001Sglebius if (uri->query == NULL) { 4634290001Sglebius event_warn("%s: strdup", __func__); 4635290001Sglebius goto err; 4636290001Sglebius } 4637290001Sglebius } 4638290001Sglebius if (fragment) { 4639290001Sglebius uri->fragment = mm_strdup(fragment); 4640290001Sglebius if (uri->fragment == NULL) { 4641290001Sglebius event_warn("%s: strdup", __func__); 4642290001Sglebius goto err; 4643290001Sglebius } 4644290001Sglebius } 4645290001Sglebius 4646290001Sglebius mm_free(readbuf); 4647290001Sglebius 4648290001Sglebius return uri; 4649290001Sglebiuserr: 4650290001Sglebius if (uri) 4651290001Sglebius evhttp_uri_free(uri); 4652290001Sglebius if (readbuf) 4653290001Sglebius mm_free(readbuf); 4654290001Sglebius return NULL; 4655290001Sglebius} 4656290001Sglebius 4657290001Sglebiusvoid 4658290001Sglebiusevhttp_uri_free(struct evhttp_uri *uri) 4659290001Sglebius{ 4660290001Sglebius#define URI_FREE_STR_(f) \ 4661290001Sglebius if (uri->f) { \ 4662290001Sglebius mm_free(uri->f); \ 4663290001Sglebius } 4664290001Sglebius 4665290001Sglebius URI_FREE_STR_(scheme); 4666290001Sglebius URI_FREE_STR_(userinfo); 4667290001Sglebius URI_FREE_STR_(host); 4668290001Sglebius URI_FREE_STR_(path); 4669290001Sglebius URI_FREE_STR_(query); 4670290001Sglebius URI_FREE_STR_(fragment); 4671290001Sglebius 4672290001Sglebius mm_free(uri); 4673290001Sglebius#undef URI_FREE_STR_ 4674290001Sglebius} 4675290001Sglebius 4676290001Sglebiuschar * 4677290001Sglebiusevhttp_uri_join(struct evhttp_uri *uri, char *buf, size_t limit) 4678290001Sglebius{ 4679290001Sglebius struct evbuffer *tmp = 0; 4680290001Sglebius size_t joined_size = 0; 4681290001Sglebius char *output = NULL; 4682290001Sglebius 4683290001Sglebius#define URI_ADD_(f) evbuffer_add(tmp, uri->f, strlen(uri->f)) 4684290001Sglebius 4685290001Sglebius if (!uri || !buf || !limit) 4686290001Sglebius return NULL; 4687290001Sglebius 4688290001Sglebius tmp = evbuffer_new(); 4689290001Sglebius if (!tmp) 4690290001Sglebius return NULL; 4691290001Sglebius 4692290001Sglebius if (uri->scheme) { 4693290001Sglebius URI_ADD_(scheme); 4694290001Sglebius evbuffer_add(tmp, ":", 1); 4695290001Sglebius } 4696290001Sglebius if (uri->host) { 4697290001Sglebius evbuffer_add(tmp, "//", 2); 4698290001Sglebius if (uri->userinfo) 4699290001Sglebius evbuffer_add_printf(tmp,"%s@", uri->userinfo); 4700290001Sglebius URI_ADD_(host); 4701290001Sglebius if (uri->port >= 0) 4702290001Sglebius evbuffer_add_printf(tmp,":%d", uri->port); 4703290001Sglebius 4704290001Sglebius if (uri->path && uri->path[0] != '/' && uri->path[0] != '\0') 4705290001Sglebius goto err; 4706290001Sglebius } 4707290001Sglebius 4708290001Sglebius if (uri->path) 4709290001Sglebius URI_ADD_(path); 4710290001Sglebius 4711290001Sglebius if (uri->query) { 4712290001Sglebius evbuffer_add(tmp, "?", 1); 4713290001Sglebius URI_ADD_(query); 4714290001Sglebius } 4715290001Sglebius 4716290001Sglebius if (uri->fragment) { 4717290001Sglebius evbuffer_add(tmp, "#", 1); 4718290001Sglebius URI_ADD_(fragment); 4719290001Sglebius } 4720290001Sglebius 4721290001Sglebius evbuffer_add(tmp, "\0", 1); /* NUL */ 4722290001Sglebius 4723290001Sglebius joined_size = evbuffer_get_length(tmp); 4724290001Sglebius 4725290001Sglebius if (joined_size > limit) { 4726290001Sglebius /* It doesn't fit. */ 4727290001Sglebius evbuffer_free(tmp); 4728290001Sglebius return NULL; 4729290001Sglebius } 4730290001Sglebius evbuffer_remove(tmp, buf, joined_size); 4731290001Sglebius 4732290001Sglebius output = buf; 4733290001Sglebiuserr: 4734290001Sglebius evbuffer_free(tmp); 4735290001Sglebius 4736290001Sglebius return output; 4737290001Sglebius#undef URI_ADD_ 4738290001Sglebius} 4739290001Sglebius 4740290001Sglebiusconst char * 4741290001Sglebiusevhttp_uri_get_scheme(const struct evhttp_uri *uri) 4742290001Sglebius{ 4743290001Sglebius return uri->scheme; 4744290001Sglebius} 4745290001Sglebiusconst char * 4746290001Sglebiusevhttp_uri_get_userinfo(const struct evhttp_uri *uri) 4747290001Sglebius{ 4748290001Sglebius return uri->userinfo; 4749290001Sglebius} 4750290001Sglebiusconst char * 4751290001Sglebiusevhttp_uri_get_host(const struct evhttp_uri *uri) 4752290001Sglebius{ 4753290001Sglebius return uri->host; 4754290001Sglebius} 4755290001Sglebiusint 4756290001Sglebiusevhttp_uri_get_port(const struct evhttp_uri *uri) 4757290001Sglebius{ 4758290001Sglebius return uri->port; 4759290001Sglebius} 4760290001Sglebiusconst char * 4761290001Sglebiusevhttp_uri_get_path(const struct evhttp_uri *uri) 4762290001Sglebius{ 4763290001Sglebius return uri->path; 4764290001Sglebius} 4765290001Sglebiusconst char * 4766290001Sglebiusevhttp_uri_get_query(const struct evhttp_uri *uri) 4767290001Sglebius{ 4768290001Sglebius return uri->query; 4769290001Sglebius} 4770290001Sglebiusconst char * 4771290001Sglebiusevhttp_uri_get_fragment(const struct evhttp_uri *uri) 4772290001Sglebius{ 4773290001Sglebius return uri->fragment; 4774290001Sglebius} 4775290001Sglebius 4776290001Sglebius#define URI_SET_STR_(f) do { \ 4777290001Sglebius if (uri->f) \ 4778290001Sglebius mm_free(uri->f); \ 4779290001Sglebius if (f) { \ 4780290001Sglebius if ((uri->f = mm_strdup(f)) == NULL) { \ 4781290001Sglebius event_warn("%s: strdup()", __func__); \ 4782290001Sglebius return -1; \ 4783290001Sglebius } \ 4784290001Sglebius } else { \ 4785290001Sglebius uri->f = NULL; \ 4786290001Sglebius } \ 4787290001Sglebius } while(0) 4788290001Sglebius 4789290001Sglebiusint 4790290001Sglebiusevhttp_uri_set_scheme(struct evhttp_uri *uri, const char *scheme) 4791290001Sglebius{ 4792290001Sglebius if (scheme && !scheme_ok(scheme, scheme+strlen(scheme))) 4793290001Sglebius return -1; 4794290001Sglebius 4795290001Sglebius URI_SET_STR_(scheme); 4796290001Sglebius return 0; 4797290001Sglebius} 4798290001Sglebiusint 4799290001Sglebiusevhttp_uri_set_userinfo(struct evhttp_uri *uri, const char *userinfo) 4800290001Sglebius{ 4801290001Sglebius if (userinfo && !userinfo_ok(userinfo, userinfo+strlen(userinfo))) 4802290001Sglebius return -1; 4803290001Sglebius URI_SET_STR_(userinfo); 4804290001Sglebius return 0; 4805290001Sglebius} 4806290001Sglebiusint 4807290001Sglebiusevhttp_uri_set_host(struct evhttp_uri *uri, const char *host) 4808290001Sglebius{ 4809290001Sglebius if (host) { 4810290001Sglebius if (host[0] == '[') { 4811290001Sglebius if (! bracket_addr_ok(host, host+strlen(host))) 4812290001Sglebius return -1; 4813290001Sglebius } else { 4814290001Sglebius if (! regname_ok(host, host+strlen(host))) 4815290001Sglebius return -1; 4816290001Sglebius } 4817290001Sglebius } 4818290001Sglebius 4819290001Sglebius URI_SET_STR_(host); 4820290001Sglebius return 0; 4821290001Sglebius} 4822290001Sglebiusint 4823290001Sglebiusevhttp_uri_set_port(struct evhttp_uri *uri, int port) 4824290001Sglebius{ 4825290001Sglebius if (port < -1) 4826290001Sglebius return -1; 4827290001Sglebius uri->port = port; 4828290001Sglebius return 0; 4829290001Sglebius} 4830290001Sglebius#define end_of_cpath(cp,p,f) \ 4831290001Sglebius ((const char*)(end_of_path(((char*)(cp)), (p), (f)))) 4832290001Sglebius 4833290001Sglebiusint 4834290001Sglebiusevhttp_uri_set_path(struct evhttp_uri *uri, const char *path) 4835290001Sglebius{ 4836290001Sglebius if (path && end_of_cpath(path, PART_PATH, uri->flags) != path+strlen(path)) 4837290001Sglebius return -1; 4838290001Sglebius 4839290001Sglebius URI_SET_STR_(path); 4840290001Sglebius return 0; 4841290001Sglebius} 4842290001Sglebiusint 4843290001Sglebiusevhttp_uri_set_query(struct evhttp_uri *uri, const char *query) 4844290001Sglebius{ 4845290001Sglebius if (query && end_of_cpath(query, PART_QUERY, uri->flags) != query+strlen(query)) 4846290001Sglebius return -1; 4847290001Sglebius URI_SET_STR_(query); 4848290001Sglebius return 0; 4849290001Sglebius} 4850290001Sglebiusint 4851290001Sglebiusevhttp_uri_set_fragment(struct evhttp_uri *uri, const char *fragment) 4852290001Sglebius{ 4853290001Sglebius if (fragment && end_of_cpath(fragment, PART_FRAGMENT, uri->flags) != fragment+strlen(fragment)) 4854290001Sglebius return -1; 4855290001Sglebius URI_SET_STR_(fragment); 4856290001Sglebius return 0; 4857290001Sglebius} 4858