Annotation of embedaddon/libevent/http.c, revision 1.1
1.1 ! misho 1: /*
! 2: * Copyright (c) 2002-2006 Niels Provos <provos@citi.umich.edu>
! 3: * All rights reserved.
! 4: *
! 5: * Redistribution and use in source and binary forms, with or without
! 6: * modification, are permitted provided that the following conditions
! 7: * are met:
! 8: * 1. Redistributions of source code must retain the above copyright
! 9: * notice, this list of conditions and the following disclaimer.
! 10: * 2. Redistributions in binary form must reproduce the above copyright
! 11: * notice, this list of conditions and the following disclaimer in the
! 12: * documentation and/or other materials provided with the distribution.
! 13: * 3. The name of the author may not be used to endorse or promote products
! 14: * derived from this software without specific prior written permission.
! 15: *
! 16: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
! 17: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
! 18: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
! 19: * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
! 20: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
! 21: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
! 22: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
! 23: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
! 24: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
! 25: * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
! 26: */
! 27:
! 28: #ifdef HAVE_CONFIG_H
! 29: #include "config.h"
! 30: #endif
! 31:
! 32: #ifdef HAVE_SYS_PARAM_H
! 33: #include <sys/param.h>
! 34: #endif
! 35: #ifdef HAVE_SYS_TYPES_H
! 36: #include <sys/types.h>
! 37: #endif
! 38:
! 39: #ifdef HAVE_SYS_TIME_H
! 40: #include <sys/time.h>
! 41: #endif
! 42: #ifdef HAVE_SYS_IOCCOM_H
! 43: #include <sys/ioccom.h>
! 44: #endif
! 45:
! 46: #ifndef WIN32
! 47: #include <sys/resource.h>
! 48: #include <sys/socket.h>
! 49: #include <sys/stat.h>
! 50: #include <sys/wait.h>
! 51: #endif
! 52:
! 53: #include <sys/queue.h>
! 54:
! 55: #ifndef WIN32
! 56: #include <netinet/in.h>
! 57: #include <netdb.h>
! 58: #endif
! 59:
! 60: #ifdef WIN32
! 61: #include <winsock2.h>
! 62: #endif
! 63:
! 64: #include <assert.h>
! 65: #include <ctype.h>
! 66: #include <errno.h>
! 67: #include <stdio.h>
! 68: #include <stdlib.h>
! 69: #include <string.h>
! 70: #ifndef WIN32
! 71: #include <syslog.h>
! 72: #endif
! 73: #include <signal.h>
! 74: #include <time.h>
! 75: #ifdef HAVE_UNISTD_H
! 76: #include <unistd.h>
! 77: #endif
! 78: #ifdef HAVE_FCNTL_H
! 79: #include <fcntl.h>
! 80: #endif
! 81:
! 82: #undef timeout_pending
! 83: #undef timeout_initialized
! 84:
! 85: #include "strlcpy-internal.h"
! 86: #include "event.h"
! 87: #include "evhttp.h"
! 88: #include "evutil.h"
! 89: #include "log.h"
! 90: #include "http-internal.h"
! 91:
! 92: #ifdef WIN32
! 93: #define strcasecmp _stricmp
! 94: #define strncasecmp _strnicmp
! 95: #define strdup _strdup
! 96: #endif
! 97:
! 98: #ifndef HAVE_GETNAMEINFO
! 99: #define NI_MAXSERV 32
! 100: #define NI_MAXHOST 1025
! 101:
! 102: #define NI_NUMERICHOST 1
! 103: #define NI_NUMERICSERV 2
! 104:
! 105: static int
! 106: fake_getnameinfo(const struct sockaddr *sa, size_t salen, char *host,
! 107: size_t hostlen, char *serv, size_t servlen, int flags)
! 108: {
! 109: struct sockaddr_in *sin = (struct sockaddr_in *)sa;
! 110:
! 111: if (serv != NULL) {
! 112: char tmpserv[16];
! 113: evutil_snprintf(tmpserv, sizeof(tmpserv),
! 114: "%d", ntohs(sin->sin_port));
! 115: if (strlcpy(serv, tmpserv, servlen) >= servlen)
! 116: return (-1);
! 117: }
! 118:
! 119: if (host != NULL) {
! 120: if (flags & NI_NUMERICHOST) {
! 121: if (strlcpy(host, inet_ntoa(sin->sin_addr),
! 122: hostlen) >= hostlen)
! 123: return (-1);
! 124: else
! 125: return (0);
! 126: } else {
! 127: struct hostent *hp;
! 128: hp = gethostbyaddr((char *)&sin->sin_addr,
! 129: sizeof(struct in_addr), AF_INET);
! 130: if (hp == NULL)
! 131: return (-2);
! 132:
! 133: if (strlcpy(host, hp->h_name, hostlen) >= hostlen)
! 134: return (-1);
! 135: else
! 136: return (0);
! 137: }
! 138: }
! 139: return (0);
! 140: }
! 141:
! 142: #endif
! 143:
! 144: #ifndef HAVE_GETADDRINFO
! 145: struct addrinfo {
! 146: int ai_family;
! 147: int ai_socktype;
! 148: int ai_protocol;
! 149: size_t ai_addrlen;
! 150: struct sockaddr *ai_addr;
! 151: struct addrinfo *ai_next;
! 152: };
! 153: static int
! 154: fake_getaddrinfo(const char *hostname, struct addrinfo *ai)
! 155: {
! 156: struct hostent *he = NULL;
! 157: struct sockaddr_in *sa;
! 158: if (hostname) {
! 159: he = gethostbyname(hostname);
! 160: if (!he)
! 161: return (-1);
! 162: }
! 163: ai->ai_family = he ? he->h_addrtype : AF_INET;
! 164: ai->ai_socktype = SOCK_STREAM;
! 165: ai->ai_protocol = 0;
! 166: ai->ai_addrlen = sizeof(struct sockaddr_in);
! 167: if (NULL == (ai->ai_addr = malloc(ai->ai_addrlen)))
! 168: return (-1);
! 169: sa = (struct sockaddr_in*)ai->ai_addr;
! 170: memset(sa, 0, ai->ai_addrlen);
! 171: if (he) {
! 172: sa->sin_family = he->h_addrtype;
! 173: memcpy(&sa->sin_addr, he->h_addr_list[0], he->h_length);
! 174: } else {
! 175: sa->sin_family = AF_INET;
! 176: sa->sin_addr.s_addr = INADDR_ANY;
! 177: }
! 178: ai->ai_next = NULL;
! 179: return (0);
! 180: }
! 181: static void
! 182: fake_freeaddrinfo(struct addrinfo *ai)
! 183: {
! 184: free(ai->ai_addr);
! 185: }
! 186: #endif
! 187:
! 188: #ifndef MIN
! 189: #define MIN(a,b) (((a)<(b))?(a):(b))
! 190: #endif
! 191:
! 192: /* wrapper for setting the base from the http server */
! 193: #define EVHTTP_BASE_SET(x, y) do { \
! 194: if ((x)->base != NULL) event_base_set((x)->base, y); \
! 195: } while (0)
! 196:
! 197: extern int debug;
! 198:
! 199: static int socket_connect(int fd, const char *address, unsigned short port);
! 200: static int bind_socket_ai(struct addrinfo *, int reuse);
! 201: static int bind_socket(const char *, u_short, int reuse);
! 202: static void name_from_addr(struct sockaddr *, socklen_t, char **, char **);
! 203: static int evhttp_associate_new_request_with_connection(
! 204: struct evhttp_connection *evcon);
! 205: static void evhttp_connection_start_detectclose(
! 206: struct evhttp_connection *evcon);
! 207: static void evhttp_connection_stop_detectclose(
! 208: struct evhttp_connection *evcon);
! 209: static void evhttp_request_dispatch(struct evhttp_connection* evcon);
! 210: static void evhttp_read_firstline(struct evhttp_connection *evcon,
! 211: struct evhttp_request *req);
! 212: static void evhttp_read_header(struct evhttp_connection *evcon,
! 213: struct evhttp_request *req);
! 214: static int evhttp_add_header_internal(struct evkeyvalq *headers,
! 215: const char *key, const char *value);
! 216: static int evhttp_decode_uri_internal(const char *uri, size_t length,
! 217: char *ret, int always_decode_plus);
! 218:
! 219: void evhttp_read(int, short, void *);
! 220: void evhttp_write(int, short, void *);
! 221:
! 222: #ifndef HAVE_STRSEP
! 223: /* strsep replacement for platforms that lack it. Only works if
! 224: * del is one character long. */
! 225: static char *
! 226: strsep(char **s, const char *del)
! 227: {
! 228: char *d, *tok;
! 229: assert(strlen(del) == 1);
! 230: if (!s || !*s)
! 231: return NULL;
! 232: tok = *s;
! 233: d = strstr(tok, del);
! 234: if (d) {
! 235: *d = '\0';
! 236: *s = d + 1;
! 237: } else
! 238: *s = NULL;
! 239: return tok;
! 240: }
! 241: #endif
! 242:
! 243: static const char *
! 244: html_replace(char ch, char *buf)
! 245: {
! 246: switch (ch) {
! 247: case '<':
! 248: return "<";
! 249: case '>':
! 250: return ">";
! 251: case '"':
! 252: return """;
! 253: case '\'':
! 254: return "'";
! 255: case '&':
! 256: return "&";
! 257: default:
! 258: break;
! 259: }
! 260:
! 261: /* Echo the character back */
! 262: buf[0] = ch;
! 263: buf[1] = '\0';
! 264:
! 265: return buf;
! 266: }
! 267:
! 268: /*
! 269: * Replaces <, >, ", ' and & with <, >, ",
! 270: * ' and & correspondingly.
! 271: *
! 272: * The returned string needs to be freed by the caller.
! 273: */
! 274:
! 275: char *
! 276: evhttp_htmlescape(const char *html)
! 277: {
! 278: int i, new_size = 0, old_size = strlen(html);
! 279: char *escaped_html, *p;
! 280: char scratch_space[2];
! 281:
! 282: for (i = 0; i < old_size; ++i)
! 283: new_size += strlen(html_replace(html[i], scratch_space));
! 284:
! 285: p = escaped_html = malloc(new_size + 1);
! 286: if (escaped_html == NULL)
! 287: event_err(1, "%s: malloc(%d)", __func__, new_size + 1);
! 288: for (i = 0; i < old_size; ++i) {
! 289: const char *replaced = html_replace(html[i], scratch_space);
! 290: /* this is length checked */
! 291: strcpy(p, replaced);
! 292: p += strlen(replaced);
! 293: }
! 294:
! 295: *p = '\0';
! 296:
! 297: return (escaped_html);
! 298: }
! 299:
! 300: static const char *
! 301: evhttp_method(enum evhttp_cmd_type type)
! 302: {
! 303: const char *method;
! 304:
! 305: switch (type) {
! 306: case EVHTTP_REQ_GET:
! 307: method = "GET";
! 308: break;
! 309: case EVHTTP_REQ_POST:
! 310: method = "POST";
! 311: break;
! 312: case EVHTTP_REQ_HEAD:
! 313: method = "HEAD";
! 314: break;
! 315: default:
! 316: method = NULL;
! 317: break;
! 318: }
! 319:
! 320: return (method);
! 321: }
! 322:
! 323: static void
! 324: evhttp_add_event(struct event *ev, int timeout, int default_timeout)
! 325: {
! 326: if (timeout != 0) {
! 327: struct timeval tv;
! 328:
! 329: evutil_timerclear(&tv);
! 330: tv.tv_sec = timeout != -1 ? timeout : default_timeout;
! 331: event_add(ev, &tv);
! 332: } else {
! 333: event_add(ev, NULL);
! 334: }
! 335: }
! 336:
! 337: void
! 338: evhttp_write_buffer(struct evhttp_connection *evcon,
! 339: void (*cb)(struct evhttp_connection *, void *), void *arg)
! 340: {
! 341: event_debug(("%s: preparing to write buffer\n", __func__));
! 342:
! 343: /* Set call back */
! 344: evcon->cb = cb;
! 345: evcon->cb_arg = arg;
! 346:
! 347: /* check if the event is already pending */
! 348: if (event_pending(&evcon->ev, EV_WRITE|EV_TIMEOUT, NULL))
! 349: event_del(&evcon->ev);
! 350:
! 351: event_set(&evcon->ev, evcon->fd, EV_WRITE, evhttp_write, evcon);
! 352: EVHTTP_BASE_SET(evcon, &evcon->ev);
! 353: evhttp_add_event(&evcon->ev, evcon->timeout, HTTP_WRITE_TIMEOUT);
! 354: }
! 355:
! 356: static int
! 357: evhttp_connected(struct evhttp_connection *evcon)
! 358: {
! 359: switch (evcon->state) {
! 360: case EVCON_DISCONNECTED:
! 361: case EVCON_CONNECTING:
! 362: return (0);
! 363: case EVCON_IDLE:
! 364: case EVCON_READING_FIRSTLINE:
! 365: case EVCON_READING_HEADERS:
! 366: case EVCON_READING_BODY:
! 367: case EVCON_READING_TRAILER:
! 368: case EVCON_WRITING:
! 369: default:
! 370: return (1);
! 371: }
! 372: }
! 373:
! 374: /*
! 375: * Create the headers needed for an HTTP request
! 376: */
! 377: static void
! 378: evhttp_make_header_request(struct evhttp_connection *evcon,
! 379: struct evhttp_request *req)
! 380: {
! 381: const char *method;
! 382:
! 383: evhttp_remove_header(req->output_headers, "Proxy-Connection");
! 384:
! 385: /* Generate request line */
! 386: method = evhttp_method(req->type);
! 387: evbuffer_add_printf(evcon->output_buffer, "%s %s HTTP/%d.%d\r\n",
! 388: method, req->uri, req->major, req->minor);
! 389:
! 390: /* Add the content length on a post request if missing */
! 391: if (req->type == EVHTTP_REQ_POST &&
! 392: evhttp_find_header(req->output_headers, "Content-Length") == NULL){
! 393: char size[12];
! 394: evutil_snprintf(size, sizeof(size), "%ld",
! 395: (long)EVBUFFER_LENGTH(req->output_buffer));
! 396: evhttp_add_header(req->output_headers, "Content-Length", size);
! 397: }
! 398: }
! 399:
! 400: static int
! 401: evhttp_is_connection_close(int flags, struct evkeyvalq* headers)
! 402: {
! 403: if (flags & EVHTTP_PROXY_REQUEST) {
! 404: /* proxy connection */
! 405: const char *connection = evhttp_find_header(headers, "Proxy-Connection");
! 406: return (connection == NULL || strcasecmp(connection, "keep-alive") != 0);
! 407: } else {
! 408: const char *connection = evhttp_find_header(headers, "Connection");
! 409: return (connection != NULL && strcasecmp(connection, "close") == 0);
! 410: }
! 411: }
! 412:
! 413: static int
! 414: evhttp_is_connection_keepalive(struct evkeyvalq* headers)
! 415: {
! 416: const char *connection = evhttp_find_header(headers, "Connection");
! 417: return (connection != NULL
! 418: && strncasecmp(connection, "keep-alive", 10) == 0);
! 419: }
! 420:
! 421: static void
! 422: evhttp_maybe_add_date_header(struct evkeyvalq *headers)
! 423: {
! 424: if (evhttp_find_header(headers, "Date") == NULL) {
! 425: char date[50];
! 426: #ifndef WIN32
! 427: struct tm cur;
! 428: #endif
! 429: struct tm *cur_p;
! 430: time_t t = time(NULL);
! 431: #ifdef WIN32
! 432: cur_p = gmtime(&t);
! 433: #else
! 434: gmtime_r(&t, &cur);
! 435: cur_p = &cur;
! 436: #endif
! 437: if (strftime(date, sizeof(date),
! 438: "%a, %d %b %Y %H:%M:%S GMT", cur_p) != 0) {
! 439: evhttp_add_header(headers, "Date", date);
! 440: }
! 441: }
! 442: }
! 443:
! 444: static void
! 445: evhttp_maybe_add_content_length_header(struct evkeyvalq *headers,
! 446: long content_length)
! 447: {
! 448: if (evhttp_find_header(headers, "Transfer-Encoding") == NULL &&
! 449: evhttp_find_header(headers, "Content-Length") == NULL) {
! 450: char len[12];
! 451: evutil_snprintf(len, sizeof(len), "%ld", content_length);
! 452: evhttp_add_header(headers, "Content-Length", len);
! 453: }
! 454: }
! 455:
! 456: /*
! 457: * Create the headers needed for an HTTP reply
! 458: */
! 459:
! 460: static void
! 461: evhttp_make_header_response(struct evhttp_connection *evcon,
! 462: struct evhttp_request *req)
! 463: {
! 464: int is_keepalive = evhttp_is_connection_keepalive(req->input_headers);
! 465: evbuffer_add_printf(evcon->output_buffer, "HTTP/%d.%d %d %s\r\n",
! 466: req->major, req->minor, req->response_code,
! 467: req->response_code_line);
! 468:
! 469: if (req->major == 1) {
! 470: if (req->minor == 1)
! 471: evhttp_maybe_add_date_header(req->output_headers);
! 472:
! 473: /*
! 474: * if the protocol is 1.0; and the connection was keep-alive
! 475: * we need to add a keep-alive header, too.
! 476: */
! 477: if (req->minor == 0 && is_keepalive)
! 478: evhttp_add_header(req->output_headers,
! 479: "Connection", "keep-alive");
! 480:
! 481: if (req->minor == 1 || is_keepalive) {
! 482: /*
! 483: * we need to add the content length if the
! 484: * user did not give it, this is required for
! 485: * persistent connections to work.
! 486: */
! 487: evhttp_maybe_add_content_length_header(
! 488: req->output_headers,
! 489: (long)EVBUFFER_LENGTH(req->output_buffer));
! 490: }
! 491: }
! 492:
! 493: /* Potentially add headers for unidentified content. */
! 494: if (EVBUFFER_LENGTH(req->output_buffer)) {
! 495: if (evhttp_find_header(req->output_headers,
! 496: "Content-Type") == NULL) {
! 497: evhttp_add_header(req->output_headers,
! 498: "Content-Type", "text/html; charset=ISO-8859-1");
! 499: }
! 500: }
! 501:
! 502: /* if the request asked for a close, we send a close, too */
! 503: if (evhttp_is_connection_close(req->flags, req->input_headers)) {
! 504: evhttp_remove_header(req->output_headers, "Connection");
! 505: if (!(req->flags & EVHTTP_PROXY_REQUEST))
! 506: evhttp_add_header(req->output_headers, "Connection", "close");
! 507: evhttp_remove_header(req->output_headers, "Proxy-Connection");
! 508: }
! 509: }
! 510:
! 511: void
! 512: evhttp_make_header(struct evhttp_connection *evcon, struct evhttp_request *req)
! 513: {
! 514: struct evkeyval *header;
! 515:
! 516: /*
! 517: * Depending if this is a HTTP request or response, we might need to
! 518: * add some new headers or remove existing headers.
! 519: */
! 520: if (req->kind == EVHTTP_REQUEST) {
! 521: evhttp_make_header_request(evcon, req);
! 522: } else {
! 523: evhttp_make_header_response(evcon, req);
! 524: }
! 525:
! 526: TAILQ_FOREACH(header, req->output_headers, next) {
! 527: evbuffer_add_printf(evcon->output_buffer, "%s: %s\r\n",
! 528: header->key, header->value);
! 529: }
! 530: evbuffer_add(evcon->output_buffer, "\r\n", 2);
! 531:
! 532: if (EVBUFFER_LENGTH(req->output_buffer) > 0) {
! 533: /*
! 534: * For a request, we add the POST data, for a reply, this
! 535: * is the regular data.
! 536: */
! 537: evbuffer_add_buffer(evcon->output_buffer, req->output_buffer);
! 538: }
! 539: }
! 540:
! 541: /* Separated host, port and file from URI */
! 542:
! 543: int
! 544: evhttp_hostportfile(char *url, char **phost, u_short *pport, char **pfile)
! 545: {
! 546: /* XXX not threadsafe. */
! 547: static char host[1024];
! 548: static char file[1024];
! 549: char *p;
! 550: const char *p2;
! 551: int len;
! 552: u_short port;
! 553:
! 554: len = strlen(HTTP_PREFIX);
! 555: if (strncasecmp(url, HTTP_PREFIX, len))
! 556: return (-1);
! 557:
! 558: url += len;
! 559:
! 560: /* We might overrun */
! 561: if (strlcpy(host, url, sizeof (host)) >= sizeof(host))
! 562: return (-1);
! 563:
! 564: p = strchr(host, '/');
! 565: if (p != NULL) {
! 566: *p = '\0';
! 567: p2 = p + 1;
! 568: } else
! 569: p2 = NULL;
! 570:
! 571: if (pfile != NULL) {
! 572: /* Generate request file */
! 573: if (p2 == NULL)
! 574: p2 = "";
! 575: evutil_snprintf(file, sizeof(file), "/%s", p2);
! 576: }
! 577:
! 578: p = strchr(host, ':');
! 579: if (p != NULL) {
! 580: *p = '\0';
! 581: port = atoi(p + 1);
! 582:
! 583: if (port == 0)
! 584: return (-1);
! 585: } else
! 586: port = HTTP_DEFAULTPORT;
! 587:
! 588: if (phost != NULL)
! 589: *phost = host;
! 590: if (pport != NULL)
! 591: *pport = port;
! 592: if (pfile != NULL)
! 593: *pfile = file;
! 594:
! 595: return (0);
! 596: }
! 597:
! 598: static int
! 599: evhttp_connection_incoming_fail(struct evhttp_request *req,
! 600: enum evhttp_connection_error error)
! 601: {
! 602: switch (error) {
! 603: case EVCON_HTTP_TIMEOUT:
! 604: case EVCON_HTTP_EOF:
! 605: /*
! 606: * these are cases in which we probably should just
! 607: * close the connection and not send a reply. this
! 608: * case may happen when a browser keeps a persistent
! 609: * connection open and we timeout on the read. when
! 610: * the request is still being used for sending, we
! 611: * need to disassociated it from the connection here.
! 612: */
! 613: if (!req->userdone) {
! 614: /* remove it so that it will not be freed */
! 615: TAILQ_REMOVE(&req->evcon->requests, req, next);
! 616: /* indicate that this request no longer has a
! 617: * connection object
! 618: */
! 619: req->evcon = NULL;
! 620: }
! 621: return (-1);
! 622: case EVCON_HTTP_INVALID_HEADER:
! 623: default: /* xxx: probably should just error on default */
! 624: /* the callback looks at the uri to determine errors */
! 625: if (req->uri) {
! 626: free(req->uri);
! 627: req->uri = NULL;
! 628: }
! 629:
! 630: /*
! 631: * the callback needs to send a reply, once the reply has
! 632: * been send, the connection should get freed.
! 633: */
! 634: (*req->cb)(req, req->cb_arg);
! 635: }
! 636:
! 637: return (0);
! 638: }
! 639:
! 640: void
! 641: evhttp_connection_fail(struct evhttp_connection *evcon,
! 642: enum evhttp_connection_error error)
! 643: {
! 644: struct evhttp_request* req = TAILQ_FIRST(&evcon->requests);
! 645: void (*cb)(struct evhttp_request *, void *);
! 646: void *cb_arg;
! 647: assert(req != NULL);
! 648:
! 649: if (evcon->flags & EVHTTP_CON_INCOMING) {
! 650: /*
! 651: * for incoming requests, there are two different
! 652: * failure cases. it's either a network level error
! 653: * or an http layer error. for problems on the network
! 654: * layer like timeouts we just drop the connections.
! 655: * For HTTP problems, we might have to send back a
! 656: * reply before the connection can be freed.
! 657: */
! 658: if (evhttp_connection_incoming_fail(req, error) == -1)
! 659: evhttp_connection_free(evcon);
! 660: return;
! 661: }
! 662:
! 663: /* save the callback for later; the cb might free our object */
! 664: cb = req->cb;
! 665: cb_arg = req->cb_arg;
! 666:
! 667: /* do not fail all requests; the next request is going to get
! 668: * send over a new connection. when a user cancels a request,
! 669: * all other pending requests should be processed as normal
! 670: */
! 671: TAILQ_REMOVE(&evcon->requests, req, next);
! 672: evhttp_request_free(req);
! 673:
! 674: /* reset the connection */
! 675: evhttp_connection_reset(evcon);
! 676:
! 677: /* We are trying the next request that was queued on us */
! 678: if (TAILQ_FIRST(&evcon->requests) != NULL)
! 679: evhttp_connection_connect(evcon);
! 680:
! 681: /* inform the user */
! 682: if (cb != NULL)
! 683: (*cb)(NULL, cb_arg);
! 684: }
! 685:
! 686: void
! 687: evhttp_write(int fd, short what, void *arg)
! 688: {
! 689: struct evhttp_connection *evcon = arg;
! 690: int n;
! 691:
! 692: if (what == EV_TIMEOUT) {
! 693: evhttp_connection_fail(evcon, EVCON_HTTP_TIMEOUT);
! 694: return;
! 695: }
! 696:
! 697: n = evbuffer_write(evcon->output_buffer, fd);
! 698: if (n == -1) {
! 699: event_debug(("%s: evbuffer_write", __func__));
! 700: evhttp_connection_fail(evcon, EVCON_HTTP_EOF);
! 701: return;
! 702: }
! 703:
! 704: if (n == 0) {
! 705: event_debug(("%s: write nothing", __func__));
! 706: evhttp_connection_fail(evcon, EVCON_HTTP_EOF);
! 707: return;
! 708: }
! 709:
! 710: if (EVBUFFER_LENGTH(evcon->output_buffer) != 0) {
! 711: evhttp_add_event(&evcon->ev,
! 712: evcon->timeout, HTTP_WRITE_TIMEOUT);
! 713: return;
! 714: }
! 715:
! 716: /* Activate our call back */
! 717: if (evcon->cb != NULL)
! 718: (*evcon->cb)(evcon, evcon->cb_arg);
! 719: }
! 720:
! 721: /**
! 722: * Advance the connection state.
! 723: * - If this is an outgoing connection, we've just processed the response;
! 724: * idle or close the connection.
! 725: * - If this is an incoming connection, we've just processed the request;
! 726: * respond.
! 727: */
! 728: static void
! 729: evhttp_connection_done(struct evhttp_connection *evcon)
! 730: {
! 731: struct evhttp_request *req = TAILQ_FIRST(&evcon->requests);
! 732: int con_outgoing = evcon->flags & EVHTTP_CON_OUTGOING;
! 733:
! 734: if (con_outgoing) {
! 735: /* idle or close the connection */
! 736: int need_close;
! 737: TAILQ_REMOVE(&evcon->requests, req, next);
! 738: req->evcon = NULL;
! 739:
! 740: evcon->state = EVCON_IDLE;
! 741:
! 742: need_close =
! 743: evhttp_is_connection_close(req->flags, req->input_headers)||
! 744: evhttp_is_connection_close(req->flags, req->output_headers);
! 745:
! 746: /* check if we got asked to close the connection */
! 747: if (need_close)
! 748: evhttp_connection_reset(evcon);
! 749:
! 750: if (TAILQ_FIRST(&evcon->requests) != NULL) {
! 751: /*
! 752: * We have more requests; reset the connection
! 753: * and deal with the next request.
! 754: */
! 755: if (!evhttp_connected(evcon))
! 756: evhttp_connection_connect(evcon);
! 757: else
! 758: evhttp_request_dispatch(evcon);
! 759: } else if (!need_close) {
! 760: /*
! 761: * The connection is going to be persistent, but we
! 762: * need to detect if the other side closes it.
! 763: */
! 764: evhttp_connection_start_detectclose(evcon);
! 765: }
! 766: } else if (evcon->state != EVCON_DISCONNECTED) {
! 767: /*
! 768: * incoming connection - we need to leave the request on the
! 769: * connection so that we can reply to it.
! 770: */
! 771: evcon->state = EVCON_WRITING;
! 772: }
! 773:
! 774: /* notify the user of the request */
! 775: (*req->cb)(req, req->cb_arg);
! 776:
! 777: /* if this was an outgoing request, we own and it's done. so free it */
! 778: if (con_outgoing) {
! 779: evhttp_request_free(req);
! 780: }
! 781: }
! 782:
! 783: /*
! 784: * Handles reading from a chunked request.
! 785: * return ALL_DATA_READ:
! 786: * all data has been read
! 787: * return MORE_DATA_EXPECTED:
! 788: * more data is expected
! 789: * return DATA_CORRUPTED:
! 790: * data is corrupted
! 791: * return REQUEST_CANCLED:
! 792: * request was canceled by the user calling evhttp_cancel_request
! 793: */
! 794:
! 795: static enum message_read_status
! 796: evhttp_handle_chunked_read(struct evhttp_request *req, struct evbuffer *buf)
! 797: {
! 798: int len;
! 799:
! 800: while ((len = EVBUFFER_LENGTH(buf)) > 0) {
! 801: if (req->ntoread < 0) {
! 802: /* Read chunk size */
! 803: ev_int64_t ntoread;
! 804: char *p = evbuffer_readline(buf);
! 805: char *endp;
! 806: int error;
! 807: if (p == NULL)
! 808: break;
! 809: /* the last chunk is on a new line? */
! 810: if (strlen(p) == 0) {
! 811: free(p);
! 812: continue;
! 813: }
! 814: ntoread = evutil_strtoll(p, &endp, 16);
! 815: error = (*p == '\0' ||
! 816: (*endp != '\0' && *endp != ' ') ||
! 817: ntoread < 0);
! 818: free(p);
! 819: if (error) {
! 820: /* could not get chunk size */
! 821: return (DATA_CORRUPTED);
! 822: }
! 823: req->ntoread = ntoread;
! 824: if (req->ntoread == 0) {
! 825: /* Last chunk */
! 826: return (ALL_DATA_READ);
! 827: }
! 828: continue;
! 829: }
! 830:
! 831: /* don't have enough to complete a chunk; wait for more */
! 832: if (len < req->ntoread)
! 833: return (MORE_DATA_EXPECTED);
! 834:
! 835: /* Completed chunk */
! 836: evbuffer_add(req->input_buffer,
! 837: EVBUFFER_DATA(buf), (size_t)req->ntoread);
! 838: evbuffer_drain(buf, (size_t)req->ntoread);
! 839: req->ntoread = -1;
! 840: if (req->chunk_cb != NULL) {
! 841: (*req->chunk_cb)(req, req->cb_arg);
! 842: evbuffer_drain(req->input_buffer,
! 843: EVBUFFER_LENGTH(req->input_buffer));
! 844: }
! 845: }
! 846:
! 847: return (MORE_DATA_EXPECTED);
! 848: }
! 849:
! 850: static void
! 851: evhttp_read_trailer(struct evhttp_connection *evcon, struct evhttp_request *req)
! 852: {
! 853: struct evbuffer *buf = evcon->input_buffer;
! 854:
! 855: switch (evhttp_parse_headers(req, buf)) {
! 856: case DATA_CORRUPTED:
! 857: evhttp_connection_fail(evcon, EVCON_HTTP_INVALID_HEADER);
! 858: break;
! 859: case ALL_DATA_READ:
! 860: event_del(&evcon->ev);
! 861: evhttp_connection_done(evcon);
! 862: break;
! 863: case MORE_DATA_EXPECTED:
! 864: default:
! 865: evhttp_add_event(&evcon->ev, evcon->timeout,
! 866: HTTP_READ_TIMEOUT);
! 867: break;
! 868: }
! 869: }
! 870:
! 871: static void
! 872: evhttp_read_body(struct evhttp_connection *evcon, struct evhttp_request *req)
! 873: {
! 874: struct evbuffer *buf = evcon->input_buffer;
! 875:
! 876: if (req->chunked) {
! 877: switch (evhttp_handle_chunked_read(req, buf)) {
! 878: case ALL_DATA_READ:
! 879: /* finished last chunk */
! 880: evcon->state = EVCON_READING_TRAILER;
! 881: evhttp_read_trailer(evcon, req);
! 882: return;
! 883: case DATA_CORRUPTED:
! 884: /* corrupted data */
! 885: evhttp_connection_fail(evcon,
! 886: EVCON_HTTP_INVALID_HEADER);
! 887: return;
! 888: case REQUEST_CANCELED:
! 889: /* request canceled */
! 890: evhttp_request_free(req);
! 891: return;
! 892: case MORE_DATA_EXPECTED:
! 893: default:
! 894: break;
! 895: }
! 896: } else if (req->ntoread < 0) {
! 897: /* Read until connection close. */
! 898: evbuffer_add_buffer(req->input_buffer, buf);
! 899: } else if (EVBUFFER_LENGTH(buf) >= req->ntoread) {
! 900: /* Completed content length */
! 901: evbuffer_add(req->input_buffer, EVBUFFER_DATA(buf),
! 902: (size_t)req->ntoread);
! 903: evbuffer_drain(buf, (size_t)req->ntoread);
! 904: req->ntoread = 0;
! 905: evhttp_connection_done(evcon);
! 906: return;
! 907: }
! 908: /* Read more! */
! 909: event_set(&evcon->ev, evcon->fd, EV_READ, evhttp_read, evcon);
! 910: EVHTTP_BASE_SET(evcon, &evcon->ev);
! 911: evhttp_add_event(&evcon->ev, evcon->timeout, HTTP_READ_TIMEOUT);
! 912: }
! 913:
! 914: /*
! 915: * Reads data into a buffer structure until no more data
! 916: * can be read on the file descriptor or we have read all
! 917: * the data that we wanted to read.
! 918: * Execute callback when done.
! 919: */
! 920:
! 921: void
! 922: evhttp_read(int fd, short what, void *arg)
! 923: {
! 924: struct evhttp_connection *evcon = arg;
! 925: struct evhttp_request *req = TAILQ_FIRST(&evcon->requests);
! 926: struct evbuffer *buf = evcon->input_buffer;
! 927: int n, len;
! 928:
! 929: if (what == EV_TIMEOUT) {
! 930: evhttp_connection_fail(evcon, EVCON_HTTP_TIMEOUT);
! 931: return;
! 932: }
! 933: n = evbuffer_read(buf, fd, -1);
! 934: len = EVBUFFER_LENGTH(buf);
! 935: event_debug(("%s: got %d on %d\n", __func__, n, fd));
! 936:
! 937: if (n == -1) {
! 938: if (errno != EINTR && errno != EAGAIN) {
! 939: event_debug(("%s: evbuffer_read", __func__));
! 940: evhttp_connection_fail(evcon, EVCON_HTTP_EOF);
! 941: } else {
! 942: evhttp_add_event(&evcon->ev, evcon->timeout,
! 943: HTTP_READ_TIMEOUT);
! 944: }
! 945: return;
! 946: } else if (n == 0) {
! 947: /* Connection closed */
! 948: evcon->state = EVCON_DISCONNECTED;
! 949: evhttp_connection_done(evcon);
! 950: return;
! 951: }
! 952:
! 953: switch (evcon->state) {
! 954: case EVCON_READING_FIRSTLINE:
! 955: evhttp_read_firstline(evcon, req);
! 956: break;
! 957: case EVCON_READING_HEADERS:
! 958: evhttp_read_header(evcon, req);
! 959: break;
! 960: case EVCON_READING_BODY:
! 961: evhttp_read_body(evcon, req);
! 962: break;
! 963: case EVCON_READING_TRAILER:
! 964: evhttp_read_trailer(evcon, req);
! 965: break;
! 966: case EVCON_DISCONNECTED:
! 967: case EVCON_CONNECTING:
! 968: case EVCON_IDLE:
! 969: case EVCON_WRITING:
! 970: default:
! 971: event_errx(1, "%s: illegal connection state %d",
! 972: __func__, evcon->state);
! 973: }
! 974: }
! 975:
! 976: static void
! 977: evhttp_write_connectioncb(struct evhttp_connection *evcon, void *arg)
! 978: {
! 979: /* This is after writing the request to the server */
! 980: struct evhttp_request *req = TAILQ_FIRST(&evcon->requests);
! 981: assert(req != NULL);
! 982:
! 983: assert(evcon->state == EVCON_WRITING);
! 984:
! 985: /* We are done writing our header and are now expecting the response */
! 986: req->kind = EVHTTP_RESPONSE;
! 987:
! 988: evhttp_start_read(evcon);
! 989: }
! 990:
! 991: /*
! 992: * Clean up a connection object
! 993: */
! 994:
! 995: void
! 996: evhttp_connection_free(struct evhttp_connection *evcon)
! 997: {
! 998: struct evhttp_request *req;
! 999:
! 1000: /* notify interested parties that this connection is going down */
! 1001: if (evcon->fd != -1) {
! 1002: if (evhttp_connected(evcon) && evcon->closecb != NULL)
! 1003: (*evcon->closecb)(evcon, evcon->closecb_arg);
! 1004: }
! 1005:
! 1006: /* remove all requests that might be queued on this
! 1007: * connection. for server connections, this should be empty.
! 1008: * because it gets dequeued either in evhttp_connection_done or
! 1009: * evhttp_connection_fail.
! 1010: */
! 1011: while ((req = TAILQ_FIRST(&evcon->requests)) != NULL) {
! 1012: TAILQ_REMOVE(&evcon->requests, req, next);
! 1013: evhttp_request_free(req);
! 1014: }
! 1015:
! 1016: if (evcon->http_server != NULL) {
! 1017: struct evhttp *http = evcon->http_server;
! 1018: TAILQ_REMOVE(&http->connections, evcon, next);
! 1019: }
! 1020:
! 1021: if (event_initialized(&evcon->close_ev))
! 1022: event_del(&evcon->close_ev);
! 1023:
! 1024: if (event_initialized(&evcon->ev))
! 1025: event_del(&evcon->ev);
! 1026:
! 1027: if (evcon->fd != -1)
! 1028: EVUTIL_CLOSESOCKET(evcon->fd);
! 1029:
! 1030: if (evcon->bind_address != NULL)
! 1031: free(evcon->bind_address);
! 1032:
! 1033: if (evcon->address != NULL)
! 1034: free(evcon->address);
! 1035:
! 1036: if (evcon->input_buffer != NULL)
! 1037: evbuffer_free(evcon->input_buffer);
! 1038:
! 1039: if (evcon->output_buffer != NULL)
! 1040: evbuffer_free(evcon->output_buffer);
! 1041:
! 1042: free(evcon);
! 1043: }
! 1044:
! 1045: void
! 1046: evhttp_connection_set_local_address(struct evhttp_connection *evcon,
! 1047: const char *address)
! 1048: {
! 1049: assert(evcon->state == EVCON_DISCONNECTED);
! 1050: if (evcon->bind_address)
! 1051: free(evcon->bind_address);
! 1052: if ((evcon->bind_address = strdup(address)) == NULL)
! 1053: event_err(1, "%s: strdup", __func__);
! 1054: }
! 1055:
! 1056: void
! 1057: evhttp_connection_set_local_port(struct evhttp_connection *evcon,
! 1058: unsigned short port)
! 1059: {
! 1060: assert(evcon->state == EVCON_DISCONNECTED);
! 1061: evcon->bind_port = port;
! 1062: }
! 1063:
! 1064: static void
! 1065: evhttp_request_dispatch(struct evhttp_connection* evcon)
! 1066: {
! 1067: struct evhttp_request *req = TAILQ_FIRST(&evcon->requests);
! 1068:
! 1069: /* this should not usually happy but it's possible */
! 1070: if (req == NULL)
! 1071: return;
! 1072:
! 1073: /* delete possible close detection events */
! 1074: evhttp_connection_stop_detectclose(evcon);
! 1075:
! 1076: /* we assume that the connection is connected already */
! 1077: assert(evcon->state == EVCON_IDLE);
! 1078:
! 1079: evcon->state = EVCON_WRITING;
! 1080:
! 1081: /* Create the header from the store arguments */
! 1082: evhttp_make_header(evcon, req);
! 1083:
! 1084: evhttp_write_buffer(evcon, evhttp_write_connectioncb, NULL);
! 1085: }
! 1086:
! 1087: /* Reset our connection state */
! 1088: void
! 1089: evhttp_connection_reset(struct evhttp_connection *evcon)
! 1090: {
! 1091: if (event_initialized(&evcon->ev))
! 1092: event_del(&evcon->ev);
! 1093:
! 1094: if (evcon->fd != -1) {
! 1095: /* inform interested parties about connection close */
! 1096: if (evhttp_connected(evcon) && evcon->closecb != NULL)
! 1097: (*evcon->closecb)(evcon, evcon->closecb_arg);
! 1098:
! 1099: EVUTIL_CLOSESOCKET(evcon->fd);
! 1100: evcon->fd = -1;
! 1101: }
! 1102: evcon->state = EVCON_DISCONNECTED;
! 1103:
! 1104: evbuffer_drain(evcon->input_buffer,
! 1105: EVBUFFER_LENGTH(evcon->input_buffer));
! 1106: evbuffer_drain(evcon->output_buffer,
! 1107: EVBUFFER_LENGTH(evcon->output_buffer));
! 1108: }
! 1109:
! 1110: static void
! 1111: evhttp_detect_close_cb(int fd, short what, void *arg)
! 1112: {
! 1113: struct evhttp_connection *evcon = arg;
! 1114: evhttp_connection_reset(evcon);
! 1115: }
! 1116:
! 1117: static void
! 1118: evhttp_connection_start_detectclose(struct evhttp_connection *evcon)
! 1119: {
! 1120: evcon->flags |= EVHTTP_CON_CLOSEDETECT;
! 1121:
! 1122: if (event_initialized(&evcon->close_ev))
! 1123: event_del(&evcon->close_ev);
! 1124: event_set(&evcon->close_ev, evcon->fd, EV_READ,
! 1125: evhttp_detect_close_cb, evcon);
! 1126: EVHTTP_BASE_SET(evcon, &evcon->close_ev);
! 1127: event_add(&evcon->close_ev, NULL);
! 1128: }
! 1129:
! 1130: static void
! 1131: evhttp_connection_stop_detectclose(struct evhttp_connection *evcon)
! 1132: {
! 1133: evcon->flags &= ~EVHTTP_CON_CLOSEDETECT;
! 1134: event_del(&evcon->close_ev);
! 1135: }
! 1136:
! 1137: static void
! 1138: evhttp_connection_retry(int fd, short what, void *arg)
! 1139: {
! 1140: struct evhttp_connection *evcon = arg;
! 1141:
! 1142: evcon->state = EVCON_DISCONNECTED;
! 1143: evhttp_connection_connect(evcon);
! 1144: }
! 1145:
! 1146: /*
! 1147: * Call back for asynchronous connection attempt.
! 1148: */
! 1149:
! 1150: static void
! 1151: evhttp_connectioncb(int fd, short what, void *arg)
! 1152: {
! 1153: struct evhttp_connection *evcon = arg;
! 1154: int error;
! 1155: socklen_t errsz = sizeof(error);
! 1156:
! 1157: if (what == EV_TIMEOUT) {
! 1158: event_debug(("%s: connection timeout for \"%s:%d\" on %d",
! 1159: __func__, evcon->address, evcon->port, evcon->fd));
! 1160: goto cleanup;
! 1161: }
! 1162:
! 1163: /* Check if the connection completed */
! 1164: if (getsockopt(evcon->fd, SOL_SOCKET, SO_ERROR, (void*)&error,
! 1165: &errsz) == -1) {
! 1166: event_debug(("%s: getsockopt for \"%s:%d\" on %d",
! 1167: __func__, evcon->address, evcon->port, evcon->fd));
! 1168: goto cleanup;
! 1169: }
! 1170:
! 1171: if (error) {
! 1172: event_debug(("%s: connect failed for \"%s:%d\" on %d: %s",
! 1173: __func__, evcon->address, evcon->port, evcon->fd,
! 1174: strerror(error)));
! 1175: goto cleanup;
! 1176: }
! 1177:
! 1178: /* We are connected to the server now */
! 1179: event_debug(("%s: connected to \"%s:%d\" on %d\n",
! 1180: __func__, evcon->address, evcon->port, evcon->fd));
! 1181:
! 1182: /* Reset the retry count as we were successful in connecting */
! 1183: evcon->retry_cnt = 0;
! 1184: evcon->state = EVCON_IDLE;
! 1185:
! 1186: /* try to start requests that have queued up on this connection */
! 1187: evhttp_request_dispatch(evcon);
! 1188: return;
! 1189:
! 1190: cleanup:
! 1191: if (evcon->retry_max < 0 || evcon->retry_cnt < evcon->retry_max) {
! 1192: evtimer_set(&evcon->ev, evhttp_connection_retry, evcon);
! 1193: EVHTTP_BASE_SET(evcon, &evcon->ev);
! 1194: evhttp_add_event(&evcon->ev, MIN(3600, 2 << evcon->retry_cnt),
! 1195: HTTP_CONNECT_TIMEOUT);
! 1196: evcon->retry_cnt++;
! 1197: return;
! 1198: }
! 1199: evhttp_connection_reset(evcon);
! 1200:
! 1201: /* for now, we just signal all requests by executing their callbacks */
! 1202: while (TAILQ_FIRST(&evcon->requests) != NULL) {
! 1203: struct evhttp_request *request = TAILQ_FIRST(&evcon->requests);
! 1204: TAILQ_REMOVE(&evcon->requests, request, next);
! 1205: request->evcon = NULL;
! 1206:
! 1207: /* we might want to set an error here */
! 1208: request->cb(request, request->cb_arg);
! 1209: evhttp_request_free(request);
! 1210: }
! 1211: }
! 1212:
! 1213: /*
! 1214: * Check if we got a valid response code.
! 1215: */
! 1216:
! 1217: static int
! 1218: evhttp_valid_response_code(int code)
! 1219: {
! 1220: if (code == 0)
! 1221: return (0);
! 1222:
! 1223: return (1);
! 1224: }
! 1225:
! 1226: /* Parses the status line of a web server */
! 1227:
! 1228: static int
! 1229: evhttp_parse_response_line(struct evhttp_request *req, char *line)
! 1230: {
! 1231: char *protocol;
! 1232: char *number;
! 1233: const char *readable = "";
! 1234:
! 1235: protocol = strsep(&line, " ");
! 1236: if (line == NULL)
! 1237: return (-1);
! 1238: number = strsep(&line, " ");
! 1239: if (line != NULL)
! 1240: readable = line;
! 1241:
! 1242: if (strcmp(protocol, "HTTP/1.0") == 0) {
! 1243: req->major = 1;
! 1244: req->minor = 0;
! 1245: } else if (strcmp(protocol, "HTTP/1.1") == 0) {
! 1246: req->major = 1;
! 1247: req->minor = 1;
! 1248: } else {
! 1249: event_debug(("%s: bad protocol \"%s\"",
! 1250: __func__, protocol));
! 1251: return (-1);
! 1252: }
! 1253:
! 1254: req->response_code = atoi(number);
! 1255: if (!evhttp_valid_response_code(req->response_code)) {
! 1256: event_debug(("%s: bad response code \"%s\"",
! 1257: __func__, number));
! 1258: return (-1);
! 1259: }
! 1260:
! 1261: if ((req->response_code_line = strdup(readable)) == NULL)
! 1262: event_err(1, "%s: strdup", __func__);
! 1263:
! 1264: return (0);
! 1265: }
! 1266:
! 1267: /* Parse the first line of a HTTP request */
! 1268:
! 1269: static int
! 1270: evhttp_parse_request_line(struct evhttp_request *req, char *line)
! 1271: {
! 1272: char *method;
! 1273: char *uri;
! 1274: char *version;
! 1275:
! 1276: /* Parse the request line */
! 1277: method = strsep(&line, " ");
! 1278: if (line == NULL)
! 1279: return (-1);
! 1280: uri = strsep(&line, " ");
! 1281: if (line == NULL)
! 1282: return (-1);
! 1283: version = strsep(&line, " ");
! 1284: if (line != NULL)
! 1285: return (-1);
! 1286:
! 1287: /* First line */
! 1288: if (strcmp(method, "GET") == 0) {
! 1289: req->type = EVHTTP_REQ_GET;
! 1290: } else if (strcmp(method, "POST") == 0) {
! 1291: req->type = EVHTTP_REQ_POST;
! 1292: } else if (strcmp(method, "HEAD") == 0) {
! 1293: req->type = EVHTTP_REQ_HEAD;
! 1294: } else {
! 1295: event_debug(("%s: bad method %s on request %p from %s",
! 1296: __func__, method, req, req->remote_host));
! 1297: return (-1);
! 1298: }
! 1299:
! 1300: if (strcmp(version, "HTTP/1.0") == 0) {
! 1301: req->major = 1;
! 1302: req->minor = 0;
! 1303: } else if (strcmp(version, "HTTP/1.1") == 0) {
! 1304: req->major = 1;
! 1305: req->minor = 1;
! 1306: } else {
! 1307: event_debug(("%s: bad version %s on request %p from %s",
! 1308: __func__, version, req, req->remote_host));
! 1309: return (-1);
! 1310: }
! 1311:
! 1312: if ((req->uri = strdup(uri)) == NULL) {
! 1313: event_debug(("%s: strdup", __func__));
! 1314: return (-1);
! 1315: }
! 1316:
! 1317: /* determine if it's a proxy request */
! 1318: if (strlen(req->uri) > 0 && req->uri[0] != '/')
! 1319: req->flags |= EVHTTP_PROXY_REQUEST;
! 1320:
! 1321: return (0);
! 1322: }
! 1323:
! 1324: const char *
! 1325: evhttp_find_header(const struct evkeyvalq *headers, const char *key)
! 1326: {
! 1327: struct evkeyval *header;
! 1328:
! 1329: TAILQ_FOREACH(header, headers, next) {
! 1330: if (strcasecmp(header->key, key) == 0)
! 1331: return (header->value);
! 1332: }
! 1333:
! 1334: return (NULL);
! 1335: }
! 1336:
! 1337: void
! 1338: evhttp_clear_headers(struct evkeyvalq *headers)
! 1339: {
! 1340: struct evkeyval *header;
! 1341:
! 1342: for (header = TAILQ_FIRST(headers);
! 1343: header != NULL;
! 1344: header = TAILQ_FIRST(headers)) {
! 1345: TAILQ_REMOVE(headers, header, next);
! 1346: free(header->key);
! 1347: free(header->value);
! 1348: free(header);
! 1349: }
! 1350: }
! 1351:
! 1352: /*
! 1353: * Returns 0, if the header was successfully removed.
! 1354: * Returns -1, if the header could not be found.
! 1355: */
! 1356:
! 1357: int
! 1358: evhttp_remove_header(struct evkeyvalq *headers, const char *key)
! 1359: {
! 1360: struct evkeyval *header;
! 1361:
! 1362: TAILQ_FOREACH(header, headers, next) {
! 1363: if (strcasecmp(header->key, key) == 0)
! 1364: break;
! 1365: }
! 1366:
! 1367: if (header == NULL)
! 1368: return (-1);
! 1369:
! 1370: /* Free and remove the header that we found */
! 1371: TAILQ_REMOVE(headers, header, next);
! 1372: free(header->key);
! 1373: free(header->value);
! 1374: free(header);
! 1375:
! 1376: return (0);
! 1377: }
! 1378:
! 1379: static int
! 1380: evhttp_header_is_valid_value(const char *value)
! 1381: {
! 1382: const char *p = value;
! 1383:
! 1384: while ((p = strpbrk(p, "\r\n")) != NULL) {
! 1385: /* we really expect only one new line */
! 1386: p += strspn(p, "\r\n");
! 1387: /* we expect a space or tab for continuation */
! 1388: if (*p != ' ' && *p != '\t')
! 1389: return (0);
! 1390: }
! 1391: return (1);
! 1392: }
! 1393:
! 1394: int
! 1395: evhttp_add_header(struct evkeyvalq *headers,
! 1396: const char *key, const char *value)
! 1397: {
! 1398: event_debug(("%s: key: %s val: %s\n", __func__, key, value));
! 1399:
! 1400: if (strchr(key, '\r') != NULL || strchr(key, '\n') != NULL) {
! 1401: /* drop illegal headers */
! 1402: event_debug(("%s: dropping illegal header key\n", __func__));
! 1403: return (-1);
! 1404: }
! 1405:
! 1406: if (!evhttp_header_is_valid_value(value)) {
! 1407: event_debug(("%s: dropping illegal header value\n", __func__));
! 1408: return (-1);
! 1409: }
! 1410:
! 1411: return (evhttp_add_header_internal(headers, key, value));
! 1412: }
! 1413:
! 1414: static int
! 1415: evhttp_add_header_internal(struct evkeyvalq *headers,
! 1416: const char *key, const char *value)
! 1417: {
! 1418: struct evkeyval *header = calloc(1, sizeof(struct evkeyval));
! 1419: if (header == NULL) {
! 1420: event_warn("%s: calloc", __func__);
! 1421: return (-1);
! 1422: }
! 1423: if ((header->key = strdup(key)) == NULL) {
! 1424: free(header);
! 1425: event_warn("%s: strdup", __func__);
! 1426: return (-1);
! 1427: }
! 1428: if ((header->value = strdup(value)) == NULL) {
! 1429: free(header->key);
! 1430: free(header);
! 1431: event_warn("%s: strdup", __func__);
! 1432: return (-1);
! 1433: }
! 1434:
! 1435: TAILQ_INSERT_TAIL(headers, header, next);
! 1436:
! 1437: return (0);
! 1438: }
! 1439:
! 1440: /*
! 1441: * Parses header lines from a request or a response into the specified
! 1442: * request object given an event buffer.
! 1443: *
! 1444: * Returns
! 1445: * DATA_CORRUPTED on error
! 1446: * MORE_DATA_EXPECTED when we need to read more headers
! 1447: * ALL_DATA_READ when all headers have been read.
! 1448: */
! 1449:
! 1450: enum message_read_status
! 1451: evhttp_parse_firstline(struct evhttp_request *req, struct evbuffer *buffer)
! 1452: {
! 1453: char *line;
! 1454: enum message_read_status status = ALL_DATA_READ;
! 1455:
! 1456: line = evbuffer_readline(buffer);
! 1457: if (line == NULL)
! 1458: return (MORE_DATA_EXPECTED);
! 1459:
! 1460: switch (req->kind) {
! 1461: case EVHTTP_REQUEST:
! 1462: if (evhttp_parse_request_line(req, line) == -1)
! 1463: status = DATA_CORRUPTED;
! 1464: break;
! 1465: case EVHTTP_RESPONSE:
! 1466: if (evhttp_parse_response_line(req, line) == -1)
! 1467: status = DATA_CORRUPTED;
! 1468: break;
! 1469: default:
! 1470: status = DATA_CORRUPTED;
! 1471: }
! 1472:
! 1473: free(line);
! 1474: return (status);
! 1475: }
! 1476:
! 1477: static int
! 1478: evhttp_append_to_last_header(struct evkeyvalq *headers, const char *line)
! 1479: {
! 1480: struct evkeyval *header = TAILQ_LAST(headers, evkeyvalq);
! 1481: char *newval;
! 1482: size_t old_len, line_len;
! 1483:
! 1484: if (header == NULL)
! 1485: return (-1);
! 1486:
! 1487: old_len = strlen(header->value);
! 1488: line_len = strlen(line);
! 1489:
! 1490: newval = realloc(header->value, old_len + line_len + 1);
! 1491: if (newval == NULL)
! 1492: return (-1);
! 1493:
! 1494: memcpy(newval + old_len, line, line_len + 1);
! 1495: header->value = newval;
! 1496:
! 1497: return (0);
! 1498: }
! 1499:
! 1500: enum message_read_status
! 1501: evhttp_parse_headers(struct evhttp_request *req, struct evbuffer* buffer)
! 1502: {
! 1503: char *line;
! 1504: enum message_read_status status = MORE_DATA_EXPECTED;
! 1505:
! 1506: struct evkeyvalq* headers = req->input_headers;
! 1507: while ((line = evbuffer_readline(buffer))
! 1508: != NULL) {
! 1509: char *skey, *svalue;
! 1510:
! 1511: if (*line == '\0') { /* Last header - Done */
! 1512: status = ALL_DATA_READ;
! 1513: free(line);
! 1514: break;
! 1515: }
! 1516:
! 1517: /* Check if this is a continuation line */
! 1518: if (*line == ' ' || *line == '\t') {
! 1519: if (evhttp_append_to_last_header(headers, line) == -1)
! 1520: goto error;
! 1521: free(line);
! 1522: continue;
! 1523: }
! 1524:
! 1525: /* Processing of header lines */
! 1526: svalue = line;
! 1527: skey = strsep(&svalue, ":");
! 1528: if (svalue == NULL)
! 1529: goto error;
! 1530:
! 1531: svalue += strspn(svalue, " ");
! 1532:
! 1533: if (evhttp_add_header(headers, skey, svalue) == -1)
! 1534: goto error;
! 1535:
! 1536: free(line);
! 1537: }
! 1538:
! 1539: return (status);
! 1540:
! 1541: error:
! 1542: free(line);
! 1543: return (DATA_CORRUPTED);
! 1544: }
! 1545:
! 1546: static int
! 1547: evhttp_get_body_length(struct evhttp_request *req)
! 1548: {
! 1549: struct evkeyvalq *headers = req->input_headers;
! 1550: const char *content_length;
! 1551: const char *connection;
! 1552:
! 1553: content_length = evhttp_find_header(headers, "Content-Length");
! 1554: connection = evhttp_find_header(headers, "Connection");
! 1555:
! 1556: if (content_length == NULL && connection == NULL)
! 1557: req->ntoread = -1;
! 1558: else if (content_length == NULL &&
! 1559: strcasecmp(connection, "Close") != 0) {
! 1560: /* Bad combination, we don't know when it will end */
! 1561: event_warnx("%s: we got no content length, but the "
! 1562: "server wants to keep the connection open: %s.",
! 1563: __func__, connection);
! 1564: return (-1);
! 1565: } else if (content_length == NULL) {
! 1566: req->ntoread = -1;
! 1567: } else {
! 1568: char *endp;
! 1569: ev_int64_t ntoread = evutil_strtoll(content_length, &endp, 10);
! 1570: if (*content_length == '\0' || *endp != '\0' || ntoread < 0) {
! 1571: event_debug(("%s: illegal content length: %s",
! 1572: __func__, content_length));
! 1573: return (-1);
! 1574: }
! 1575: req->ntoread = ntoread;
! 1576: }
! 1577:
! 1578: event_debug(("%s: bytes to read: %lld (in buffer %ld)\n",
! 1579: __func__, req->ntoread,
! 1580: EVBUFFER_LENGTH(req->evcon->input_buffer)));
! 1581:
! 1582: return (0);
! 1583: }
! 1584:
! 1585: static void
! 1586: evhttp_get_body(struct evhttp_connection *evcon, struct evhttp_request *req)
! 1587: {
! 1588: const char *xfer_enc;
! 1589:
! 1590: /* If this is a request without a body, then we are done */
! 1591: if (req->kind == EVHTTP_REQUEST && req->type != EVHTTP_REQ_POST) {
! 1592: evhttp_connection_done(evcon);
! 1593: return;
! 1594: }
! 1595: evcon->state = EVCON_READING_BODY;
! 1596: xfer_enc = evhttp_find_header(req->input_headers, "Transfer-Encoding");
! 1597: if (xfer_enc != NULL && strcasecmp(xfer_enc, "chunked") == 0) {
! 1598: req->chunked = 1;
! 1599: req->ntoread = -1;
! 1600: } else {
! 1601: if (evhttp_get_body_length(req) == -1) {
! 1602: evhttp_connection_fail(evcon,
! 1603: EVCON_HTTP_INVALID_HEADER);
! 1604: return;
! 1605: }
! 1606: }
! 1607: evhttp_read_body(evcon, req);
! 1608: }
! 1609:
! 1610: static void
! 1611: evhttp_read_firstline(struct evhttp_connection *evcon,
! 1612: struct evhttp_request *req)
! 1613: {
! 1614: enum message_read_status res;
! 1615:
! 1616: res = evhttp_parse_firstline(req, evcon->input_buffer);
! 1617: if (res == DATA_CORRUPTED) {
! 1618: /* Error while reading, terminate */
! 1619: event_debug(("%s: bad header lines on %d\n",
! 1620: __func__, evcon->fd));
! 1621: evhttp_connection_fail(evcon, EVCON_HTTP_INVALID_HEADER);
! 1622: return;
! 1623: } else if (res == MORE_DATA_EXPECTED) {
! 1624: /* Need more header lines */
! 1625: evhttp_add_event(&evcon->ev,
! 1626: evcon->timeout, HTTP_READ_TIMEOUT);
! 1627: return;
! 1628: }
! 1629:
! 1630: evcon->state = EVCON_READING_HEADERS;
! 1631: evhttp_read_header(evcon, req);
! 1632: }
! 1633:
! 1634: static void
! 1635: evhttp_read_header(struct evhttp_connection *evcon, struct evhttp_request *req)
! 1636: {
! 1637: enum message_read_status res;
! 1638: int fd = evcon->fd;
! 1639:
! 1640: res = evhttp_parse_headers(req, evcon->input_buffer);
! 1641: if (res == DATA_CORRUPTED) {
! 1642: /* Error while reading, terminate */
! 1643: event_debug(("%s: bad header lines on %d\n", __func__, fd));
! 1644: evhttp_connection_fail(evcon, EVCON_HTTP_INVALID_HEADER);
! 1645: return;
! 1646: } else if (res == MORE_DATA_EXPECTED) {
! 1647: /* Need more header lines */
! 1648: evhttp_add_event(&evcon->ev,
! 1649: evcon->timeout, HTTP_READ_TIMEOUT);
! 1650: return;
! 1651: }
! 1652:
! 1653: /* Done reading headers, do the real work */
! 1654: switch (req->kind) {
! 1655: case EVHTTP_REQUEST:
! 1656: event_debug(("%s: checking for post data on %d\n",
! 1657: __func__, fd));
! 1658: evhttp_get_body(evcon, req);
! 1659: break;
! 1660:
! 1661: case EVHTTP_RESPONSE:
! 1662: if (req->response_code == HTTP_NOCONTENT ||
! 1663: req->response_code == HTTP_NOTMODIFIED ||
! 1664: (req->response_code >= 100 && req->response_code < 200)) {
! 1665: event_debug(("%s: skipping body for code %d\n",
! 1666: __func__, req->response_code));
! 1667: evhttp_connection_done(evcon);
! 1668: } else {
! 1669: event_debug(("%s: start of read body for %s on %d\n",
! 1670: __func__, req->remote_host, fd));
! 1671: evhttp_get_body(evcon, req);
! 1672: }
! 1673: break;
! 1674:
! 1675: default:
! 1676: event_warnx("%s: bad header on %d", __func__, fd);
! 1677: evhttp_connection_fail(evcon, EVCON_HTTP_INVALID_HEADER);
! 1678: break;
! 1679: }
! 1680: }
! 1681:
! 1682: /*
! 1683: * Creates a TCP connection to the specified port and executes a callback
! 1684: * when finished. Failure or sucess is indicate by the passed connection
! 1685: * object.
! 1686: *
! 1687: * Although this interface accepts a hostname, it is intended to take
! 1688: * only numeric hostnames so that non-blocking DNS resolution can
! 1689: * happen elsewhere.
! 1690: */
! 1691:
! 1692: struct evhttp_connection *
! 1693: evhttp_connection_new(const char *address, unsigned short port)
! 1694: {
! 1695: struct evhttp_connection *evcon = NULL;
! 1696:
! 1697: event_debug(("Attempting connection to %s:%d\n", address, port));
! 1698:
! 1699: if ((evcon = calloc(1, sizeof(struct evhttp_connection))) == NULL) {
! 1700: event_warn("%s: calloc failed", __func__);
! 1701: goto error;
! 1702: }
! 1703:
! 1704: evcon->fd = -1;
! 1705: evcon->port = port;
! 1706:
! 1707: evcon->timeout = -1;
! 1708: evcon->retry_cnt = evcon->retry_max = 0;
! 1709:
! 1710: if ((evcon->address = strdup(address)) == NULL) {
! 1711: event_warn("%s: strdup failed", __func__);
! 1712: goto error;
! 1713: }
! 1714:
! 1715: if ((evcon->input_buffer = evbuffer_new()) == NULL) {
! 1716: event_warn("%s: evbuffer_new failed", __func__);
! 1717: goto error;
! 1718: }
! 1719:
! 1720: if ((evcon->output_buffer = evbuffer_new()) == NULL) {
! 1721: event_warn("%s: evbuffer_new failed", __func__);
! 1722: goto error;
! 1723: }
! 1724:
! 1725: evcon->state = EVCON_DISCONNECTED;
! 1726: TAILQ_INIT(&evcon->requests);
! 1727:
! 1728: return (evcon);
! 1729:
! 1730: error:
! 1731: if (evcon != NULL)
! 1732: evhttp_connection_free(evcon);
! 1733: return (NULL);
! 1734: }
! 1735:
! 1736: void evhttp_connection_set_base(struct evhttp_connection *evcon,
! 1737: struct event_base *base)
! 1738: {
! 1739: assert(evcon->base == NULL);
! 1740: assert(evcon->state == EVCON_DISCONNECTED);
! 1741: evcon->base = base;
! 1742: }
! 1743:
! 1744: void
! 1745: evhttp_connection_set_timeout(struct evhttp_connection *evcon,
! 1746: int timeout_in_secs)
! 1747: {
! 1748: evcon->timeout = timeout_in_secs;
! 1749: }
! 1750:
! 1751: void
! 1752: evhttp_connection_set_retries(struct evhttp_connection *evcon,
! 1753: int retry_max)
! 1754: {
! 1755: evcon->retry_max = retry_max;
! 1756: }
! 1757:
! 1758: void
! 1759: evhttp_connection_set_closecb(struct evhttp_connection *evcon,
! 1760: void (*cb)(struct evhttp_connection *, void *), void *cbarg)
! 1761: {
! 1762: evcon->closecb = cb;
! 1763: evcon->closecb_arg = cbarg;
! 1764: }
! 1765:
! 1766: void
! 1767: evhttp_connection_get_peer(struct evhttp_connection *evcon,
! 1768: char **address, u_short *port)
! 1769: {
! 1770: *address = evcon->address;
! 1771: *port = evcon->port;
! 1772: }
! 1773:
! 1774: int
! 1775: evhttp_connection_connect(struct evhttp_connection *evcon)
! 1776: {
! 1777: if (evcon->state == EVCON_CONNECTING)
! 1778: return (0);
! 1779:
! 1780: evhttp_connection_reset(evcon);
! 1781:
! 1782: assert(!(evcon->flags & EVHTTP_CON_INCOMING));
! 1783: evcon->flags |= EVHTTP_CON_OUTGOING;
! 1784:
! 1785: evcon->fd = bind_socket(
! 1786: evcon->bind_address, evcon->bind_port, 0 /*reuse*/);
! 1787: if (evcon->fd == -1) {
! 1788: event_debug(("%s: failed to bind to \"%s\"",
! 1789: __func__, evcon->bind_address));
! 1790: return (-1);
! 1791: }
! 1792:
! 1793: if (socket_connect(evcon->fd, evcon->address, evcon->port) == -1) {
! 1794: EVUTIL_CLOSESOCKET(evcon->fd); evcon->fd = -1;
! 1795: return (-1);
! 1796: }
! 1797:
! 1798: /* Set up a callback for successful connection setup */
! 1799: event_set(&evcon->ev, evcon->fd, EV_WRITE, evhttp_connectioncb, evcon);
! 1800: EVHTTP_BASE_SET(evcon, &evcon->ev);
! 1801: evhttp_add_event(&evcon->ev, evcon->timeout, HTTP_CONNECT_TIMEOUT);
! 1802:
! 1803: evcon->state = EVCON_CONNECTING;
! 1804:
! 1805: return (0);
! 1806: }
! 1807:
! 1808: /*
! 1809: * Starts an HTTP request on the provided evhttp_connection object.
! 1810: * If the connection object is not connected to the web server already,
! 1811: * this will start the connection.
! 1812: */
! 1813:
! 1814: int
! 1815: evhttp_make_request(struct evhttp_connection *evcon,
! 1816: struct evhttp_request *req,
! 1817: enum evhttp_cmd_type type, const char *uri)
! 1818: {
! 1819: /* We are making a request */
! 1820: req->kind = EVHTTP_REQUEST;
! 1821: req->type = type;
! 1822: if (req->uri != NULL)
! 1823: free(req->uri);
! 1824: if ((req->uri = strdup(uri)) == NULL)
! 1825: event_err(1, "%s: strdup", __func__);
! 1826:
! 1827: /* Set the protocol version if it is not supplied */
! 1828: if (!req->major && !req->minor) {
! 1829: req->major = 1;
! 1830: req->minor = 1;
! 1831: }
! 1832:
! 1833: assert(req->evcon == NULL);
! 1834: req->evcon = evcon;
! 1835: assert(!(req->flags & EVHTTP_REQ_OWN_CONNECTION));
! 1836:
! 1837: TAILQ_INSERT_TAIL(&evcon->requests, req, next);
! 1838:
! 1839: /* If the connection object is not connected; make it so */
! 1840: if (!evhttp_connected(evcon))
! 1841: return (evhttp_connection_connect(evcon));
! 1842:
! 1843: /*
! 1844: * If it's connected already and we are the first in the queue,
! 1845: * then we can dispatch this request immediately. Otherwise, it
! 1846: * will be dispatched once the pending requests are completed.
! 1847: */
! 1848: if (TAILQ_FIRST(&evcon->requests) == req)
! 1849: evhttp_request_dispatch(evcon);
! 1850:
! 1851: return (0);
! 1852: }
! 1853:
! 1854: /*
! 1855: * Reads data from file descriptor into request structure
! 1856: * Request structure needs to be set up correctly.
! 1857: */
! 1858:
! 1859: void
! 1860: evhttp_start_read(struct evhttp_connection *evcon)
! 1861: {
! 1862: /* Set up an event to read the headers */
! 1863: if (event_initialized(&evcon->ev))
! 1864: event_del(&evcon->ev);
! 1865: event_set(&evcon->ev, evcon->fd, EV_READ, evhttp_read, evcon);
! 1866: EVHTTP_BASE_SET(evcon, &evcon->ev);
! 1867:
! 1868: evhttp_add_event(&evcon->ev, evcon->timeout, HTTP_READ_TIMEOUT);
! 1869: evcon->state = EVCON_READING_FIRSTLINE;
! 1870: }
! 1871:
! 1872: static void
! 1873: evhttp_send_done(struct evhttp_connection *evcon, void *arg)
! 1874: {
! 1875: int need_close;
! 1876: struct evhttp_request *req = TAILQ_FIRST(&evcon->requests);
! 1877: TAILQ_REMOVE(&evcon->requests, req, next);
! 1878:
! 1879: /* delete possible close detection events */
! 1880: evhttp_connection_stop_detectclose(evcon);
! 1881:
! 1882: need_close =
! 1883: (req->minor == 0 &&
! 1884: !evhttp_is_connection_keepalive(req->input_headers))||
! 1885: evhttp_is_connection_close(req->flags, req->input_headers) ||
! 1886: evhttp_is_connection_close(req->flags, req->output_headers);
! 1887:
! 1888: assert(req->flags & EVHTTP_REQ_OWN_CONNECTION);
! 1889: evhttp_request_free(req);
! 1890:
! 1891: if (need_close) {
! 1892: evhttp_connection_free(evcon);
! 1893: return;
! 1894: }
! 1895:
! 1896: /* we have a persistent connection; try to accept another request. */
! 1897: if (evhttp_associate_new_request_with_connection(evcon) == -1)
! 1898: evhttp_connection_free(evcon);
! 1899: }
! 1900:
! 1901: /*
! 1902: * Returns an error page.
! 1903: */
! 1904:
! 1905: void
! 1906: evhttp_send_error(struct evhttp_request *req, int error, const char *reason)
! 1907: {
! 1908: #define ERR_FORMAT "<HTML><HEAD>\n" \
! 1909: "<TITLE>%d %s</TITLE>\n" \
! 1910: "</HEAD><BODY>\n" \
! 1911: "<H1>Method Not Implemented</H1>\n" \
! 1912: "Invalid method in request<P>\n" \
! 1913: "</BODY></HTML>\n"
! 1914:
! 1915: struct evbuffer *buf = evbuffer_new();
! 1916:
! 1917: /* close the connection on error */
! 1918: evhttp_add_header(req->output_headers, "Connection", "close");
! 1919:
! 1920: evhttp_response_code(req, error, reason);
! 1921:
! 1922: evbuffer_add_printf(buf, ERR_FORMAT, error, reason);
! 1923:
! 1924: evhttp_send_page(req, buf);
! 1925:
! 1926: evbuffer_free(buf);
! 1927: #undef ERR_FORMAT
! 1928: }
! 1929:
! 1930: /* Requires that headers and response code are already set up */
! 1931:
! 1932: static inline void
! 1933: evhttp_send(struct evhttp_request *req, struct evbuffer *databuf)
! 1934: {
! 1935: struct evhttp_connection *evcon = req->evcon;
! 1936:
! 1937: if (evcon == NULL) {
! 1938: evhttp_request_free(req);
! 1939: return;
! 1940: }
! 1941:
! 1942: assert(TAILQ_FIRST(&evcon->requests) == req);
! 1943:
! 1944: /* we expect no more calls form the user on this request */
! 1945: req->userdone = 1;
! 1946:
! 1947: /* xxx: not sure if we really should expose the data buffer this way */
! 1948: if (databuf != NULL)
! 1949: evbuffer_add_buffer(req->output_buffer, databuf);
! 1950:
! 1951: /* Adds headers to the response */
! 1952: evhttp_make_header(evcon, req);
! 1953:
! 1954: evhttp_write_buffer(evcon, evhttp_send_done, NULL);
! 1955: }
! 1956:
! 1957: void
! 1958: evhttp_send_reply(struct evhttp_request *req, int code, const char *reason,
! 1959: struct evbuffer *databuf)
! 1960: {
! 1961: evhttp_response_code(req, code, reason);
! 1962:
! 1963: evhttp_send(req, databuf);
! 1964: }
! 1965:
! 1966: void
! 1967: evhttp_send_reply_start(struct evhttp_request *req, int code,
! 1968: const char *reason)
! 1969: {
! 1970: evhttp_response_code(req, code, reason);
! 1971: if (req->major == 1 && req->minor == 1) {
! 1972: /* use chunked encoding for HTTP/1.1 */
! 1973: evhttp_add_header(req->output_headers, "Transfer-Encoding",
! 1974: "chunked");
! 1975: req->chunked = 1;
! 1976: }
! 1977: evhttp_make_header(req->evcon, req);
! 1978: evhttp_write_buffer(req->evcon, NULL, NULL);
! 1979: }
! 1980:
! 1981: void
! 1982: evhttp_send_reply_chunk(struct evhttp_request *req, struct evbuffer *databuf)
! 1983: {
! 1984: struct evhttp_connection *evcon = req->evcon;
! 1985:
! 1986: if (evcon == NULL)
! 1987: return;
! 1988:
! 1989: if (req->chunked) {
! 1990: evbuffer_add_printf(evcon->output_buffer, "%x\r\n",
! 1991: (unsigned)EVBUFFER_LENGTH(databuf));
! 1992: }
! 1993: evbuffer_add_buffer(evcon->output_buffer, databuf);
! 1994: if (req->chunked) {
! 1995: evbuffer_add(evcon->output_buffer, "\r\n", 2);
! 1996: }
! 1997: evhttp_write_buffer(evcon, NULL, NULL);
! 1998: }
! 1999:
! 2000: void
! 2001: evhttp_send_reply_end(struct evhttp_request *req)
! 2002: {
! 2003: struct evhttp_connection *evcon = req->evcon;
! 2004:
! 2005: if (evcon == NULL) {
! 2006: evhttp_request_free(req);
! 2007: return;
! 2008: }
! 2009:
! 2010: /* we expect no more calls form the user on this request */
! 2011: req->userdone = 1;
! 2012:
! 2013: if (req->chunked) {
! 2014: evbuffer_add(req->evcon->output_buffer, "0\r\n\r\n", 5);
! 2015: evhttp_write_buffer(req->evcon, evhttp_send_done, NULL);
! 2016: req->chunked = 0;
! 2017: } else if (!event_pending(&evcon->ev, EV_WRITE|EV_TIMEOUT, NULL)) {
! 2018: /* let the connection know that we are done with the request */
! 2019: evhttp_send_done(evcon, NULL);
! 2020: } else {
! 2021: /* make the callback execute after all data has been written */
! 2022: evcon->cb = evhttp_send_done;
! 2023: evcon->cb_arg = NULL;
! 2024: }
! 2025: }
! 2026:
! 2027: void
! 2028: evhttp_response_code(struct evhttp_request *req, int code, const char *reason)
! 2029: {
! 2030: req->kind = EVHTTP_RESPONSE;
! 2031: req->response_code = code;
! 2032: if (req->response_code_line != NULL)
! 2033: free(req->response_code_line);
! 2034: req->response_code_line = strdup(reason);
! 2035: }
! 2036:
! 2037: void
! 2038: evhttp_send_page(struct evhttp_request *req, struct evbuffer *databuf)
! 2039: {
! 2040: if (!req->major || !req->minor) {
! 2041: req->major = 1;
! 2042: req->minor = 1;
! 2043: }
! 2044:
! 2045: if (req->kind != EVHTTP_RESPONSE)
! 2046: evhttp_response_code(req, 200, "OK");
! 2047:
! 2048: evhttp_clear_headers(req->output_headers);
! 2049: evhttp_add_header(req->output_headers, "Content-Type", "text/html");
! 2050: evhttp_add_header(req->output_headers, "Connection", "close");
! 2051:
! 2052: evhttp_send(req, databuf);
! 2053: }
! 2054:
! 2055: static const char uri_chars[256] = {
! 2056: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
! 2057: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
! 2058: 0, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1,
! 2059: 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0,
! 2060: /* 64 */
! 2061: 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
! 2062: 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
! 2063: 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
! 2064: 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0,
! 2065: /* 128 */
! 2066: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
! 2067: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
! 2068: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
! 2069: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
! 2070: /* 192 */
! 2071: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
! 2072: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
! 2073: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
! 2074: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
! 2075: };
! 2076:
! 2077: /*
! 2078: * Helper functions to encode/decode a URI.
! 2079: * The returned string must be freed by the caller.
! 2080: */
! 2081: char *
! 2082: evhttp_encode_uri(const char *uri)
! 2083: {
! 2084: struct evbuffer *buf = evbuffer_new();
! 2085: char *p;
! 2086:
! 2087: for (p = (char *)uri; *p != '\0'; p++) {
! 2088: if (uri_chars[(u_char)(*p)]) {
! 2089: evbuffer_add(buf, p, 1);
! 2090: } else {
! 2091: evbuffer_add_printf(buf, "%%%02X", (u_char)(*p));
! 2092: }
! 2093: }
! 2094: evbuffer_add(buf, "", 1);
! 2095: p = strdup((char *)EVBUFFER_DATA(buf));
! 2096: evbuffer_free(buf);
! 2097:
! 2098: return (p);
! 2099: }
! 2100:
! 2101: /*
! 2102: * @param always_decode_plus: when true we transform plus to space even
! 2103: * if we have not seen a ?.
! 2104: */
! 2105: static int
! 2106: evhttp_decode_uri_internal(
! 2107: const char *uri, size_t length, char *ret, int always_decode_plus)
! 2108: {
! 2109: char c;
! 2110: int i, j, in_query = always_decode_plus;
! 2111:
! 2112: for (i = j = 0; uri[i] != '\0'; i++) {
! 2113: c = uri[i];
! 2114: if (c == '?') {
! 2115: in_query = 1;
! 2116: } else if (c == '+' && in_query) {
! 2117: c = ' ';
! 2118: } else if (c == '%' && isxdigit((unsigned char)uri[i+1]) &&
! 2119: isxdigit((unsigned char)uri[i+2])) {
! 2120: char tmp[] = { uri[i+1], uri[i+2], '\0' };
! 2121: c = (char)strtol(tmp, NULL, 16);
! 2122: i += 2;
! 2123: }
! 2124: ret[j++] = c;
! 2125: }
! 2126: ret[j] = '\0';
! 2127:
! 2128: return (j);
! 2129: }
! 2130:
! 2131: char *
! 2132: evhttp_decode_uri(const char *uri)
! 2133: {
! 2134: char *ret;
! 2135:
! 2136: if ((ret = malloc(strlen(uri) + 1)) == NULL)
! 2137: event_err(1, "%s: malloc(%lu)", __func__,
! 2138: (unsigned long)(strlen(uri) + 1));
! 2139:
! 2140: evhttp_decode_uri_internal(uri, strlen(uri),
! 2141: ret, 0 /*always_decode_plus*/);
! 2142:
! 2143: return (ret);
! 2144: }
! 2145:
! 2146: /*
! 2147: * Helper function to parse out arguments in a query.
! 2148: * The arguments are separated by key and value.
! 2149: */
! 2150:
! 2151: void
! 2152: evhttp_parse_query(const char *uri, struct evkeyvalq *headers)
! 2153: {
! 2154: char *line;
! 2155: char *argument;
! 2156: char *p;
! 2157:
! 2158: TAILQ_INIT(headers);
! 2159:
! 2160: /* No arguments - we are done */
! 2161: if (strchr(uri, '?') == NULL)
! 2162: return;
! 2163:
! 2164: if ((line = strdup(uri)) == NULL)
! 2165: event_err(1, "%s: strdup", __func__);
! 2166:
! 2167:
! 2168: argument = line;
! 2169:
! 2170: /* We already know that there has to be a ? */
! 2171: strsep(&argument, "?");
! 2172:
! 2173: p = argument;
! 2174: while (p != NULL && *p != '\0') {
! 2175: char *key, *value, *decoded_value;
! 2176: argument = strsep(&p, "&");
! 2177:
! 2178: value = argument;
! 2179: key = strsep(&value, "=");
! 2180: if (value == NULL)
! 2181: goto error;
! 2182:
! 2183: if ((decoded_value = malloc(strlen(value) + 1)) == NULL)
! 2184: event_err(1, "%s: malloc", __func__);
! 2185:
! 2186: evhttp_decode_uri_internal(value, strlen(value),
! 2187: decoded_value, 1 /*always_decode_plus*/);
! 2188: event_debug(("Query Param: %s -> %s\n", key, decoded_value));
! 2189: evhttp_add_header_internal(headers, key, decoded_value);
! 2190: free(decoded_value);
! 2191: }
! 2192:
! 2193: error:
! 2194: free(line);
! 2195: }
! 2196:
! 2197: static struct evhttp_cb *
! 2198: evhttp_dispatch_callback(struct httpcbq *callbacks, struct evhttp_request *req)
! 2199: {
! 2200: struct evhttp_cb *cb;
! 2201: size_t offset = 0;
! 2202:
! 2203: /* Test for different URLs */
! 2204: char *p = strchr(req->uri, '?');
! 2205: if (p != NULL)
! 2206: offset = (size_t)(p - req->uri);
! 2207:
! 2208: TAILQ_FOREACH(cb, callbacks, next) {
! 2209: int res = 0;
! 2210: if (p == NULL) {
! 2211: res = strcmp(cb->what, req->uri) == 0;
! 2212: } else {
! 2213: res = ((strncmp(cb->what, req->uri, offset) == 0) &&
! 2214: (cb->what[offset] == '\0'));
! 2215: }
! 2216:
! 2217: if (res)
! 2218: return (cb);
! 2219: }
! 2220:
! 2221: return (NULL);
! 2222: }
! 2223:
! 2224: static void
! 2225: evhttp_handle_request(struct evhttp_request *req, void *arg)
! 2226: {
! 2227: struct evhttp *http = arg;
! 2228: struct evhttp_cb *cb = NULL;
! 2229:
! 2230: event_debug(("%s: req->uri=%s", __func__, req->uri));
! 2231: if (req->uri == NULL) {
! 2232: event_debug(("%s: bad request", __func__));
! 2233: if (req->evcon->state == EVCON_DISCONNECTED) {
! 2234: evhttp_connection_fail(req->evcon, EVCON_HTTP_EOF);
! 2235: } else {
! 2236: event_debug(("%s: sending error", __func__));
! 2237: evhttp_send_error(req, HTTP_BADREQUEST, "Bad Request");
! 2238: }
! 2239: return;
! 2240: }
! 2241:
! 2242: if ((cb = evhttp_dispatch_callback(&http->callbacks, req)) != NULL) {
! 2243: (*cb->cb)(req, cb->cbarg);
! 2244: return;
! 2245: }
! 2246:
! 2247: /* Generic call back */
! 2248: if (http->gencb) {
! 2249: (*http->gencb)(req, http->gencbarg);
! 2250: return;
! 2251: } else {
! 2252: /* We need to send a 404 here */
! 2253: #define ERR_FORMAT "<html><head>" \
! 2254: "<title>404 Not Found</title>" \
! 2255: "</head><body>" \
! 2256: "<h1>Not Found</h1>" \
! 2257: "<p>The requested URL %s was not found on this server.</p>"\
! 2258: "</body></html>\n"
! 2259:
! 2260: char *escaped_html = evhttp_htmlescape(req->uri);
! 2261: struct evbuffer *buf = evbuffer_new();
! 2262:
! 2263: evhttp_response_code(req, HTTP_NOTFOUND, "Not Found");
! 2264:
! 2265: evbuffer_add_printf(buf, ERR_FORMAT, escaped_html);
! 2266:
! 2267: free(escaped_html);
! 2268:
! 2269: evhttp_send_page(req, buf);
! 2270:
! 2271: evbuffer_free(buf);
! 2272: #undef ERR_FORMAT
! 2273: }
! 2274: }
! 2275:
! 2276: static void
! 2277: accept_socket(int fd, short what, void *arg)
! 2278: {
! 2279: struct evhttp *http = arg;
! 2280: struct sockaddr_storage ss;
! 2281: socklen_t addrlen = sizeof(ss);
! 2282: int nfd;
! 2283:
! 2284: if ((nfd = accept(fd, (struct sockaddr *)&ss, &addrlen)) == -1) {
! 2285: if (errno != EAGAIN && errno != EINTR)
! 2286: event_warn("%s: bad accept", __func__);
! 2287: return;
! 2288: }
! 2289: if (evutil_make_socket_nonblocking(nfd) < 0)
! 2290: return;
! 2291:
! 2292: evhttp_get_request(http, nfd, (struct sockaddr *)&ss, addrlen);
! 2293: }
! 2294:
! 2295: int
! 2296: evhttp_bind_socket(struct evhttp *http, const char *address, u_short port)
! 2297: {
! 2298: int fd;
! 2299: int res;
! 2300:
! 2301: if ((fd = bind_socket(address, port, 1 /*reuse*/)) == -1)
! 2302: return (-1);
! 2303:
! 2304: if (listen(fd, 128) == -1) {
! 2305: event_warn("%s: listen", __func__);
! 2306: EVUTIL_CLOSESOCKET(fd);
! 2307: return (-1);
! 2308: }
! 2309:
! 2310: res = evhttp_accept_socket(http, fd);
! 2311:
! 2312: if (res != -1)
! 2313: event_debug(("Bound to port %d - Awaiting connections ... ",
! 2314: port));
! 2315:
! 2316: return (res);
! 2317: }
! 2318:
! 2319: int
! 2320: evhttp_accept_socket(struct evhttp *http, int fd)
! 2321: {
! 2322: struct evhttp_bound_socket *bound;
! 2323: struct event *ev;
! 2324: int res;
! 2325:
! 2326: bound = malloc(sizeof(struct evhttp_bound_socket));
! 2327: if (bound == NULL)
! 2328: return (-1);
! 2329:
! 2330: ev = &bound->bind_ev;
! 2331:
! 2332: /* Schedule the socket for accepting */
! 2333: event_set(ev, fd, EV_READ | EV_PERSIST, accept_socket, http);
! 2334: EVHTTP_BASE_SET(http, ev);
! 2335:
! 2336: res = event_add(ev, NULL);
! 2337:
! 2338: if (res == -1) {
! 2339: free(bound);
! 2340: return (-1);
! 2341: }
! 2342:
! 2343: TAILQ_INSERT_TAIL(&http->sockets, bound, next);
! 2344:
! 2345: return (0);
! 2346: }
! 2347:
! 2348: static struct evhttp*
! 2349: evhttp_new_object(void)
! 2350: {
! 2351: struct evhttp *http = NULL;
! 2352:
! 2353: if ((http = calloc(1, sizeof(struct evhttp))) == NULL) {
! 2354: event_warn("%s: calloc", __func__);
! 2355: return (NULL);
! 2356: }
! 2357:
! 2358: http->timeout = -1;
! 2359:
! 2360: TAILQ_INIT(&http->sockets);
! 2361: TAILQ_INIT(&http->callbacks);
! 2362: TAILQ_INIT(&http->connections);
! 2363:
! 2364: return (http);
! 2365: }
! 2366:
! 2367: struct evhttp *
! 2368: evhttp_new(struct event_base *base)
! 2369: {
! 2370: struct evhttp *http = evhttp_new_object();
! 2371:
! 2372: http->base = base;
! 2373:
! 2374: return (http);
! 2375: }
! 2376:
! 2377: /*
! 2378: * Start a web server on the specified address and port.
! 2379: */
! 2380:
! 2381: struct evhttp *
! 2382: evhttp_start(const char *address, u_short port)
! 2383: {
! 2384: struct evhttp *http = evhttp_new_object();
! 2385:
! 2386: if (evhttp_bind_socket(http, address, port) == -1) {
! 2387: free(http);
! 2388: return (NULL);
! 2389: }
! 2390:
! 2391: return (http);
! 2392: }
! 2393:
! 2394: void
! 2395: evhttp_free(struct evhttp* http)
! 2396: {
! 2397: struct evhttp_cb *http_cb;
! 2398: struct evhttp_connection *evcon;
! 2399: struct evhttp_bound_socket *bound;
! 2400: int fd;
! 2401:
! 2402: /* Remove the accepting part */
! 2403: while ((bound = TAILQ_FIRST(&http->sockets)) != NULL) {
! 2404: TAILQ_REMOVE(&http->sockets, bound, next);
! 2405:
! 2406: fd = bound->bind_ev.ev_fd;
! 2407: event_del(&bound->bind_ev);
! 2408: EVUTIL_CLOSESOCKET(fd);
! 2409:
! 2410: free(bound);
! 2411: }
! 2412:
! 2413: while ((evcon = TAILQ_FIRST(&http->connections)) != NULL) {
! 2414: /* evhttp_connection_free removes the connection */
! 2415: evhttp_connection_free(evcon);
! 2416: }
! 2417:
! 2418: while ((http_cb = TAILQ_FIRST(&http->callbacks)) != NULL) {
! 2419: TAILQ_REMOVE(&http->callbacks, http_cb, next);
! 2420: free(http_cb->what);
! 2421: free(http_cb);
! 2422: }
! 2423:
! 2424: free(http);
! 2425: }
! 2426:
! 2427: void
! 2428: evhttp_set_timeout(struct evhttp* http, int timeout_in_secs)
! 2429: {
! 2430: http->timeout = timeout_in_secs;
! 2431: }
! 2432:
! 2433: void
! 2434: evhttp_set_cb(struct evhttp *http, const char *uri,
! 2435: void (*cb)(struct evhttp_request *, void *), void *cbarg)
! 2436: {
! 2437: struct evhttp_cb *http_cb;
! 2438:
! 2439: if ((http_cb = calloc(1, sizeof(struct evhttp_cb))) == NULL)
! 2440: event_err(1, "%s: calloc", __func__);
! 2441:
! 2442: http_cb->what = strdup(uri);
! 2443: http_cb->cb = cb;
! 2444: http_cb->cbarg = cbarg;
! 2445:
! 2446: TAILQ_INSERT_TAIL(&http->callbacks, http_cb, next);
! 2447: }
! 2448:
! 2449: int
! 2450: evhttp_del_cb(struct evhttp *http, const char *uri)
! 2451: {
! 2452: struct evhttp_cb *http_cb;
! 2453:
! 2454: TAILQ_FOREACH(http_cb, &http->callbacks, next) {
! 2455: if (strcmp(http_cb->what, uri) == 0)
! 2456: break;
! 2457: }
! 2458: if (http_cb == NULL)
! 2459: return (-1);
! 2460:
! 2461: TAILQ_REMOVE(&http->callbacks, http_cb, next);
! 2462: free(http_cb->what);
! 2463: free(http_cb);
! 2464:
! 2465: return (0);
! 2466: }
! 2467:
! 2468: void
! 2469: evhttp_set_gencb(struct evhttp *http,
! 2470: void (*cb)(struct evhttp_request *, void *), void *cbarg)
! 2471: {
! 2472: http->gencb = cb;
! 2473: http->gencbarg = cbarg;
! 2474: }
! 2475:
! 2476: /*
! 2477: * Request related functions
! 2478: */
! 2479:
! 2480: struct evhttp_request *
! 2481: evhttp_request_new(void (*cb)(struct evhttp_request *, void *), void *arg)
! 2482: {
! 2483: struct evhttp_request *req = NULL;
! 2484:
! 2485: /* Allocate request structure */
! 2486: if ((req = calloc(1, sizeof(struct evhttp_request))) == NULL) {
! 2487: event_warn("%s: calloc", __func__);
! 2488: goto error;
! 2489: }
! 2490:
! 2491: req->kind = EVHTTP_RESPONSE;
! 2492: req->input_headers = calloc(1, sizeof(struct evkeyvalq));
! 2493: if (req->input_headers == NULL) {
! 2494: event_warn("%s: calloc", __func__);
! 2495: goto error;
! 2496: }
! 2497: TAILQ_INIT(req->input_headers);
! 2498:
! 2499: req->output_headers = calloc(1, sizeof(struct evkeyvalq));
! 2500: if (req->output_headers == NULL) {
! 2501: event_warn("%s: calloc", __func__);
! 2502: goto error;
! 2503: }
! 2504: TAILQ_INIT(req->output_headers);
! 2505:
! 2506: if ((req->input_buffer = evbuffer_new()) == NULL) {
! 2507: event_warn("%s: evbuffer_new", __func__);
! 2508: goto error;
! 2509: }
! 2510:
! 2511: if ((req->output_buffer = evbuffer_new()) == NULL) {
! 2512: event_warn("%s: evbuffer_new", __func__);
! 2513: goto error;
! 2514: }
! 2515:
! 2516: req->cb = cb;
! 2517: req->cb_arg = arg;
! 2518:
! 2519: return (req);
! 2520:
! 2521: error:
! 2522: if (req != NULL)
! 2523: evhttp_request_free(req);
! 2524: return (NULL);
! 2525: }
! 2526:
! 2527: void
! 2528: evhttp_request_free(struct evhttp_request *req)
! 2529: {
! 2530: if (req->remote_host != NULL)
! 2531: free(req->remote_host);
! 2532: if (req->uri != NULL)
! 2533: free(req->uri);
! 2534: if (req->response_code_line != NULL)
! 2535: free(req->response_code_line);
! 2536:
! 2537: evhttp_clear_headers(req->input_headers);
! 2538: free(req->input_headers);
! 2539:
! 2540: evhttp_clear_headers(req->output_headers);
! 2541: free(req->output_headers);
! 2542:
! 2543: if (req->input_buffer != NULL)
! 2544: evbuffer_free(req->input_buffer);
! 2545:
! 2546: if (req->output_buffer != NULL)
! 2547: evbuffer_free(req->output_buffer);
! 2548:
! 2549: free(req);
! 2550: }
! 2551:
! 2552: struct evhttp_connection *
! 2553: evhttp_request_get_connection(struct evhttp_request *req)
! 2554: {
! 2555: return req->evcon;
! 2556: }
! 2557:
! 2558:
! 2559: void
! 2560: evhttp_request_set_chunked_cb(struct evhttp_request *req,
! 2561: void (*cb)(struct evhttp_request *, void *))
! 2562: {
! 2563: req->chunk_cb = cb;
! 2564: }
! 2565:
! 2566: /*
! 2567: * Allows for inspection of the request URI
! 2568: */
! 2569:
! 2570: const char *
! 2571: evhttp_request_uri(struct evhttp_request *req) {
! 2572: if (req->uri == NULL)
! 2573: event_debug(("%s: request %p has no uri\n", __func__, req));
! 2574: return (req->uri);
! 2575: }
! 2576:
! 2577: /*
! 2578: * Takes a file descriptor to read a request from.
! 2579: * The callback is executed once the whole request has been read.
! 2580: */
! 2581:
! 2582: static struct evhttp_connection*
! 2583: evhttp_get_request_connection(
! 2584: struct evhttp* http,
! 2585: int fd, struct sockaddr *sa, socklen_t salen)
! 2586: {
! 2587: struct evhttp_connection *evcon;
! 2588: char *hostname = NULL, *portname = NULL;
! 2589:
! 2590: name_from_addr(sa, salen, &hostname, &portname);
! 2591: if (hostname == NULL || portname == NULL) {
! 2592: if (hostname) free(hostname);
! 2593: if (portname) free(portname);
! 2594: return (NULL);
! 2595: }
! 2596:
! 2597: event_debug(("%s: new request from %s:%s on %d\n",
! 2598: __func__, hostname, portname, fd));
! 2599:
! 2600: /* we need a connection object to put the http request on */
! 2601: evcon = evhttp_connection_new(hostname, atoi(portname));
! 2602: free(hostname);
! 2603: free(portname);
! 2604: if (evcon == NULL)
! 2605: return (NULL);
! 2606:
! 2607: /* associate the base if we have one*/
! 2608: evhttp_connection_set_base(evcon, http->base);
! 2609:
! 2610: evcon->flags |= EVHTTP_CON_INCOMING;
! 2611: evcon->state = EVCON_READING_FIRSTLINE;
! 2612:
! 2613: evcon->fd = fd;
! 2614:
! 2615: return (evcon);
! 2616: }
! 2617:
! 2618: static int
! 2619: evhttp_associate_new_request_with_connection(struct evhttp_connection *evcon)
! 2620: {
! 2621: struct evhttp *http = evcon->http_server;
! 2622: struct evhttp_request *req;
! 2623: if ((req = evhttp_request_new(evhttp_handle_request, http)) == NULL)
! 2624: return (-1);
! 2625:
! 2626: req->evcon = evcon; /* the request ends up owning the connection */
! 2627: req->flags |= EVHTTP_REQ_OWN_CONNECTION;
! 2628:
! 2629: TAILQ_INSERT_TAIL(&evcon->requests, req, next);
! 2630:
! 2631: req->kind = EVHTTP_REQUEST;
! 2632:
! 2633: if ((req->remote_host = strdup(evcon->address)) == NULL)
! 2634: event_err(1, "%s: strdup", __func__);
! 2635: req->remote_port = evcon->port;
! 2636:
! 2637: evhttp_start_read(evcon);
! 2638:
! 2639: return (0);
! 2640: }
! 2641:
! 2642: void
! 2643: evhttp_get_request(struct evhttp *http, int fd,
! 2644: struct sockaddr *sa, socklen_t salen)
! 2645: {
! 2646: struct evhttp_connection *evcon;
! 2647:
! 2648: evcon = evhttp_get_request_connection(http, fd, sa, salen);
! 2649: if (evcon == NULL)
! 2650: return;
! 2651:
! 2652: /* the timeout can be used by the server to close idle connections */
! 2653: if (http->timeout != -1)
! 2654: evhttp_connection_set_timeout(evcon, http->timeout);
! 2655:
! 2656: /*
! 2657: * if we want to accept more than one request on a connection,
! 2658: * we need to know which http server it belongs to.
! 2659: */
! 2660: evcon->http_server = http;
! 2661: TAILQ_INSERT_TAIL(&http->connections, evcon, next);
! 2662:
! 2663: if (evhttp_associate_new_request_with_connection(evcon) == -1)
! 2664: evhttp_connection_free(evcon);
! 2665: }
! 2666:
! 2667:
! 2668: /*
! 2669: * Network helper functions that we do not want to export to the rest of
! 2670: * the world.
! 2671: */
! 2672: #if 0 /* Unused */
! 2673: static struct addrinfo *
! 2674: addr_from_name(char *address)
! 2675: {
! 2676: #ifdef HAVE_GETADDRINFO
! 2677: struct addrinfo ai, *aitop;
! 2678: int ai_result;
! 2679:
! 2680: memset(&ai, 0, sizeof(ai));
! 2681: ai.ai_family = AF_INET;
! 2682: ai.ai_socktype = SOCK_RAW;
! 2683: ai.ai_flags = 0;
! 2684: if ((ai_result = getaddrinfo(address, NULL, &ai, &aitop)) != 0) {
! 2685: if ( ai_result == EAI_SYSTEM )
! 2686: event_warn("getaddrinfo");
! 2687: else
! 2688: event_warnx("getaddrinfo: %s", gai_strerror(ai_result));
! 2689: }
! 2690:
! 2691: return (aitop);
! 2692: #else
! 2693: assert(0);
! 2694: return NULL; /* XXXXX Use gethostbyname, if this function is ever used. */
! 2695: #endif
! 2696: }
! 2697: #endif
! 2698:
! 2699: static void
! 2700: name_from_addr(struct sockaddr *sa, socklen_t salen,
! 2701: char **phost, char **pport)
! 2702: {
! 2703: char ntop[NI_MAXHOST];
! 2704: char strport[NI_MAXSERV];
! 2705: int ni_result;
! 2706:
! 2707: #ifdef HAVE_GETNAMEINFO
! 2708: ni_result = getnameinfo(sa, salen,
! 2709: ntop, sizeof(ntop), strport, sizeof(strport),
! 2710: NI_NUMERICHOST|NI_NUMERICSERV);
! 2711:
! 2712: if (ni_result != 0) {
! 2713: if (ni_result == EAI_SYSTEM)
! 2714: event_err(1, "getnameinfo failed");
! 2715: else
! 2716: event_errx(1, "getnameinfo failed: %s", gai_strerror(ni_result));
! 2717: return;
! 2718: }
! 2719: #else
! 2720: ni_result = fake_getnameinfo(sa, salen,
! 2721: ntop, sizeof(ntop), strport, sizeof(strport),
! 2722: NI_NUMERICHOST|NI_NUMERICSERV);
! 2723: if (ni_result != 0)
! 2724: return;
! 2725: #endif
! 2726: *phost = strdup(ntop);
! 2727: *pport = strdup(strport);
! 2728: }
! 2729:
! 2730: /* Create a non-blocking socket and bind it */
! 2731: /* todo: rename this function */
! 2732: static int
! 2733: bind_socket_ai(struct addrinfo *ai, int reuse)
! 2734: {
! 2735: int fd, on = 1, r;
! 2736: int serrno;
! 2737:
! 2738: /* Create listen socket */
! 2739: fd = socket(AF_INET, SOCK_STREAM, 0);
! 2740: if (fd == -1) {
! 2741: event_warn("socket");
! 2742: return (-1);
! 2743: }
! 2744:
! 2745: if (evutil_make_socket_nonblocking(fd) < 0)
! 2746: goto out;
! 2747:
! 2748: #ifndef WIN32
! 2749: if (fcntl(fd, F_SETFD, 1) == -1) {
! 2750: event_warn("fcntl(F_SETFD)");
! 2751: goto out;
! 2752: }
! 2753: #endif
! 2754:
! 2755: setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (void *)&on, sizeof(on));
! 2756: if (reuse) {
! 2757: setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
! 2758: (void *)&on, sizeof(on));
! 2759: }
! 2760:
! 2761: if (ai != NULL) {
! 2762: r = bind(fd, ai->ai_addr, ai->ai_addrlen);
! 2763: if (r == -1)
! 2764: goto out;
! 2765: }
! 2766:
! 2767: return (fd);
! 2768:
! 2769: out:
! 2770: serrno = EVUTIL_SOCKET_ERROR();
! 2771: EVUTIL_CLOSESOCKET(fd);
! 2772: EVUTIL_SET_SOCKET_ERROR(serrno);
! 2773: return (-1);
! 2774: }
! 2775:
! 2776: static struct addrinfo *
! 2777: make_addrinfo(const char *address, u_short port)
! 2778: {
! 2779: struct addrinfo *aitop = NULL;
! 2780:
! 2781: #ifdef HAVE_GETADDRINFO
! 2782: struct addrinfo ai;
! 2783: char strport[NI_MAXSERV];
! 2784: int ai_result;
! 2785:
! 2786: memset(&ai, 0, sizeof(ai));
! 2787: ai.ai_family = AF_INET;
! 2788: ai.ai_socktype = SOCK_STREAM;
! 2789: ai.ai_flags = AI_PASSIVE; /* turn NULL host name into INADDR_ANY */
! 2790: evutil_snprintf(strport, sizeof(strport), "%d", port);
! 2791: if ((ai_result = getaddrinfo(address, strport, &ai, &aitop)) != 0) {
! 2792: if ( ai_result == EAI_SYSTEM )
! 2793: event_warn("getaddrinfo");
! 2794: else
! 2795: event_warnx("getaddrinfo: %s", gai_strerror(ai_result));
! 2796: return (NULL);
! 2797: }
! 2798: #else
! 2799: static int cur;
! 2800: static struct addrinfo ai[2]; /* We will be returning the address of some of this memory so it has to last even after this call. */
! 2801: if (++cur == 2) cur = 0; /* allow calling this function twice */
! 2802:
! 2803: if (fake_getaddrinfo(address, &ai[cur]) < 0) {
! 2804: event_warn("fake_getaddrinfo");
! 2805: return (NULL);
! 2806: }
! 2807: aitop = &ai[cur];
! 2808: ((struct sockaddr_in *) aitop->ai_addr)->sin_port = htons(port);
! 2809: #endif
! 2810:
! 2811: return (aitop);
! 2812: }
! 2813:
! 2814: static int
! 2815: bind_socket(const char *address, u_short port, int reuse)
! 2816: {
! 2817: int fd;
! 2818: struct addrinfo *aitop = NULL;
! 2819:
! 2820: /* just create an unbound socket */
! 2821: if (address == NULL && port == 0)
! 2822: return bind_socket_ai(NULL, 0);
! 2823:
! 2824: aitop = make_addrinfo(address, port);
! 2825:
! 2826: if (aitop == NULL)
! 2827: return (-1);
! 2828:
! 2829: fd = bind_socket_ai(aitop, reuse);
! 2830:
! 2831: #ifdef HAVE_GETADDRINFO
! 2832: freeaddrinfo(aitop);
! 2833: #else
! 2834: fake_freeaddrinfo(aitop);
! 2835: #endif
! 2836:
! 2837: return (fd);
! 2838: }
! 2839:
! 2840: static int
! 2841: socket_connect(int fd, const char *address, unsigned short port)
! 2842: {
! 2843: struct addrinfo *ai = make_addrinfo(address, port);
! 2844: int res = -1;
! 2845:
! 2846: if (ai == NULL) {
! 2847: event_debug(("%s: make_addrinfo: \"%s:%d\"",
! 2848: __func__, address, port));
! 2849: return (-1);
! 2850: }
! 2851:
! 2852: if (connect(fd, ai->ai_addr, ai->ai_addrlen) == -1) {
! 2853: #ifdef WIN32
! 2854: int tmp_error = WSAGetLastError();
! 2855: if (tmp_error != WSAEWOULDBLOCK && tmp_error != WSAEINVAL &&
! 2856: tmp_error != WSAEINPROGRESS) {
! 2857: goto out;
! 2858: }
! 2859: #else
! 2860: if (errno != EINPROGRESS) {
! 2861: goto out;
! 2862: }
! 2863: #endif
! 2864: }
! 2865:
! 2866: /* everything is fine */
! 2867: res = 0;
! 2868:
! 2869: out:
! 2870: #ifdef HAVE_GETADDRINFO
! 2871: freeaddrinfo(ai);
! 2872: #else
! 2873: fake_freeaddrinfo(ai);
! 2874: #endif
! 2875:
! 2876: return (res);
! 2877: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>