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 "&lt;";
        !           249:        case '>':
        !           250:                return "&gt;";
        !           251:        case '"':
        !           252:                return "&quot;";
        !           253:        case '\'':
        !           254:                return "&#039;";
        !           255:        case '&':
        !           256:                return "&amp;";
        !           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 &lt;, &gt;, &quot;,
        !           270:  * &#039; and &amp; 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>