Annotation of embedaddon/mpd/src/contrib/libpdel/http/http_request.c, revision 1.1

1.1     ! misho       1: 
        !             2: /*
        !             3:  * Copyright (c) 2001-2002 Packet Design, LLC.
        !             4:  * All rights reserved.
        !             5:  * 
        !             6:  * Subject to the following obligations and disclaimer of warranty,
        !             7:  * use and redistribution of this software, in source or object code
        !             8:  * forms, with or without modifications are expressly permitted by
        !             9:  * Packet Design; provided, however, that:
        !            10:  * 
        !            11:  *    (i)  Any and all reproductions of the source or object code
        !            12:  *         must include the copyright notice above and the following
        !            13:  *         disclaimer of warranties; and
        !            14:  *    (ii) No rights are granted, in any manner or form, to use
        !            15:  *         Packet Design trademarks, including the mark "PACKET DESIGN"
        !            16:  *         on advertising, endorsements, or otherwise except as such
        !            17:  *         appears in the above copyright notice or in the software.
        !            18:  * 
        !            19:  * THIS SOFTWARE IS BEING PROVIDED BY PACKET DESIGN "AS IS", AND
        !            20:  * TO THE MAXIMUM EXTENT PERMITTED BY LAW, PACKET DESIGN MAKES NO
        !            21:  * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING
        !            22:  * THIS SOFTWARE, INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED
        !            23:  * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE,
        !            24:  * OR NON-INFRINGEMENT.  PACKET DESIGN DOES NOT WARRANT, GUARANTEE,
        !            25:  * OR MAKE ANY REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS
        !            26:  * OF THE USE OF THIS SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY,
        !            27:  * RELIABILITY OR OTHERWISE.  IN NO EVENT SHALL PACKET DESIGN BE
        !            28:  * LIABLE FOR ANY DAMAGES RESULTING FROM OR ARISING OUT OF ANY USE
        !            29:  * OF THIS SOFTWARE, INCLUDING WITHOUT LIMITATION, ANY DIRECT,
        !            30:  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, PUNITIVE, OR CONSEQUENTIAL
        !            31:  * DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, LOSS OF
        !            32:  * USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY THEORY OF
        !            33:  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
        !            34:  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
        !            35:  * THE USE OF THIS SOFTWARE, EVEN IF PACKET DESIGN IS ADVISED OF
        !            36:  * THE POSSIBILITY OF SUCH DAMAGE.
        !            37:  *
        !            38:  * Author: Archie Cobbs <archie@freebsd.org>
        !            39:  */
        !            40: 
        !            41: #include <sys/types.h>
        !            42: #include <sys/queue.h>
        !            43: 
        !            44: #include <netinet/in.h>
        !            45: 
        !            46: #include <stdio.h>
        !            47: #include <stdlib.h>
        !            48: #include <stdarg.h>
        !            49: #include <string.h>
        !            50: #include <limits.h>
        !            51: #include <pthread.h>
        !            52: #include <ctype.h>
        !            53: #include <syslog.h>
        !            54: #include <errno.h>
        !            55: #include <assert.h>
        !            56: 
        !            57: #include <openssl/ssl.h>
        !            58: 
        !            59: #include "structs/structs.h"
        !            60: #include "structs/type/array.h"
        !            61: 
        !            62: #include "http/http_defs.h"
        !            63: #include "http/http_server.h"
        !            64: #include "http/http_internal.h"
        !            65: #include "util/typed_mem.h"
        !            66: 
        !            67: #define MAX_NVP_LEN            (8 * 1024)
        !            68: #define MAX_NVP_DATA           (64 * 1024)
        !            69: 
        !            70: /*
        !            71:  * Error strings
        !            72:  */
        !            73: #define PARSE_REQUST_MSG       "Error parsing request header"
        !            74: #define REQUEST_TIMEOUT_MSG    "Press reload to reestablish a connection"
        !            75: 
        !            76: /*
        !            77:  * Internal functions
        !            78:  */
        !            79: static int     http_request_decode_query(struct http_request *req);
        !            80: static int     nvp_cmp(const void *v1, const void *v2);
        !            81: static char    *read_string_until(const char *mtype,
        !            82:                        FILE *fp, const char *term);
        !            83: static int     http_request_add_nvp(struct http_request *req, int encoded,
        !            84:                        const char *ename, const char *evalue);
        !            85: static void    http_request_decode_auth(struct http_request *req);
        !            86: 
        !            87: /*
        !            88:  * Internal variables
        !            89:  */
        !            90: static const   char base64[65]
        !            91:     = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
        !            92: 
        !            93: /*********************************************************************
        !            94:                        MAIN ROUTINES
        !            95: *********************************************************************/
        !            96: 
        !            97: /*
        !            98:  * Create a new request structure.
        !            99:  */
        !           100: int
        !           101: _http_request_new(struct http_connection *conn)
        !           102: {
        !           103:        struct http_request *req;
        !           104: 
        !           105:        /* Create request structure */
        !           106:        assert(conn->req == NULL);
        !           107:        if ((req = MALLOC("http_request", sizeof(*req))) == NULL) {
        !           108:                (*conn->logger)(LOG_ERR, "%s: %s", "malloc", strerror(errno));
        !           109:                return (-1);
        !           110:        }
        !           111:        memset(req, 0, sizeof(*req));
        !           112: 
        !           113:        /* Attach message structure */
        !           114:        if ((req->msg = _http_message_new()) == NULL) {
        !           115:                (*conn->logger)(LOG_ERR, "%s: %s", "malloc", strerror(errno));
        !           116:                FREE("http_request", req);
        !           117:                return (-1);
        !           118:        }
        !           119: 
        !           120:        /* Link it up */
        !           121:        req->msg->conn = conn;
        !           122:        conn->req = req;
        !           123:        return (0);
        !           124: }
        !           125: 
        !           126: /*
        !           127:  * Read in, validate, and prep an HTTP request from a connection.
        !           128:  *
        !           129:  * If there is a problem, load an error response page if appropriate.
        !           130:  */
        !           131: int
        !           132: _http_request_read(struct http_connection *conn)
        !           133: {
        !           134:        struct http_request *const req = conn->req;
        !           135:        struct http_response *const resp = conn->resp;
        !           136:        struct http_message *const msg = req->msg;
        !           137:        const char *path = NULL;
        !           138:        const char *method;
        !           139:        const char *colon;
        !           140:        const char *slash;
        !           141:        const char *proto;
        !           142:        const char *uri;
        !           143:        const char *s;
        !           144:        char scheme[32];
        !           145:        int plen = -1;
        !           146:        int hlen;
        !           147: 
        !           148:        /* Load in message from HTTP connection */
        !           149:        if (_http_message_read(msg, 1) == -1) {
        !           150:                const int errno_save = errno;
        !           151: 
        !           152:                /* If nothing read, the peer must have closed the connection */
        !           153:                if (!_http_message_has_anything(msg)) {
        !           154:                        errno = ENOTCONN;
        !           155:                        return (-1);
        !           156:                }
        !           157: 
        !           158:                /* Return an appropriate error message */
        !           159:                switch (errno) {
        !           160:                case EINVAL:
        !           161:                        http_response_send_error(resp, HTTP_STATUS_BAD_REQUEST,
        !           162:                            PARSE_REQUST_MSG);
        !           163:                        break;
        !           164: 
        !           165:                case ETIMEDOUT:
        !           166:                        http_response_send_error(resp,
        !           167:                            HTTP_STATUS_REQUEST_TIME_OUT, REQUEST_TIMEOUT_MSG);
        !           168:                        break;
        !           169: 
        !           170:                default:
        !           171:                        http_response_send_error(resp,
        !           172:                            HTTP_STATUS_INTERNAL_SERVER_ERROR,
        !           173:                            "%s", strerror(errno));
        !           174:                        break;
        !           175:                }
        !           176: 
        !           177:                /* in all cases return -1 */
        !           178:                errno = errno_save;
        !           179:                return (-1);
        !           180:        }
        !           181: 
        !           182:        /* Get method, URI, and protocol */
        !           183:        method = _http_head_get(msg->head, HDR_REQUEST_METHOD);
        !           184:        uri = _http_head_get(msg->head, HDR_REQUEST_URI);
        !           185:        proto = _http_head_get(msg->head, HDR_REQUEST_VERSION);
        !           186: 
        !           187:        /* Check method and reset input length if not POST */
        !           188:        if (strcmp(method, HTTP_METHOD_GET) == 0
        !           189:            || strcmp(method, HTTP_METHOD_HEAD) == 0
        !           190:            || strcmp(method, HTTP_METHOD_POST) == 0
        !           191:            || strcmp(method, HTTP_METHOD_CONNECT) == 0)
        !           192:                ;                                               /* ok */
        !           193:        else if (strcmp(method, HTTP_METHOD_OPTIONS) == 0
        !           194:            || strcmp(method, HTTP_METHOD_PUT) == 0
        !           195:            || strcmp(method, HTTP_METHOD_DELETE) == 0
        !           196:            || strcmp(method, HTTP_METHOD_TRACE) == 0) {
        !           197:                http_response_send_error(resp,
        !           198:                    HTTP_STATUS_METHOD_NOT_ALLOWED, NULL);
        !           199:                return (-1);
        !           200:        } else {
        !           201:                http_response_send_error(resp,
        !           202:                    HTTP_STATUS_NOT_IMPLEMENTED, NULL);
        !           203:                return (-1);
        !           204:        }
        !           205: 
        !           206:        /* If request was HEAD, omit sending the body */
        !           207:        if (strcasecmp(method, HTTP_METHOD_HEAD) == 0)
        !           208:                resp->msg->skip_body = 1;
        !           209: 
        !           210:        /* Check protocol is known */
        !           211:        if (strcmp(proto, HTTP_PROTO_0_9) != 0
        !           212:            && strcmp(proto, HTTP_PROTO_1_0) != 0
        !           213:            && strcmp(proto, HTTP_PROTO_1_1) != 0) {
        !           214:                http_response_send_error(resp,
        !           215:                    HTTP_STATUS_HTTP_VERSION_NOT_SUPPORTED, NULL);
        !           216:                return (-1);
        !           217:        }
        !           218: 
        !           219:        /* If protocol is HTTP/0.9, don't send back any headers */
        !           220:        if (strcmp(proto, HTTP_PROTO_0_9) == 0)
        !           221:                resp->msg->no_headers = 1;
        !           222: 
        !           223:        /* Check for CONNECT method */
        !           224:        if (strcmp(method, HTTP_METHOD_CONNECT) == 0) {
        !           225:                if ((msg->host = STRDUP("http_message.host", uri)) == NULL)
        !           226:                        goto malloc_fail;
        !           227:                conn->proxy = 1;
        !           228:                goto no_path;
        !           229:        }
        !           230: 
        !           231:        /* Get explicit scheme, if any */
        !           232:        colon = strchr(uri, ':');
        !           233:        slash = strchr(uri, '/');
        !           234:        if (colon != NULL && slash != NULL && colon < slash) {
        !           235:                char *c;
        !           236: 
        !           237:                strlcpy(scheme, uri, sizeof(scheme));
        !           238:                if ((c = strchr(scheme, ':')) != NULL)
        !           239:                        *c = '\0';
        !           240:                conn->proxy = 1;        /* explicit scheme => proxy request */
        !           241:        } else
        !           242:                strlcpy(scheme, "http", sizeof(scheme));
        !           243: 
        !           244:        /* We only support HTTP */
        !           245:        if (strcasecmp(scheme, "http") != 0) {
        !           246:                http_response_send_error(resp, HTTP_STATUS_BAD_REQUEST,
        !           247:                    "Unsupported scheme \"%s\"", scheme);
        !           248:                return (-1);
        !           249:        }
        !           250: 
        !           251:        /* Separate out host, path and query parts from URI */
        !           252:        if (strncasecmp(uri, "http://", 7) == 0) {
        !           253:                if ((path = strchr(uri + 7, '/')) == NULL) {
        !           254:                        http_response_send_error(resp, HTTP_STATUS_BAD_REQUEST,
        !           255:                            "Request URI has no path component");
        !           256:                        return (-1);
        !           257:                }
        !           258:                hlen = path - (uri + 7);
        !           259:                if ((msg->host = MALLOC("http_message.host", hlen + 1)) == NULL)
        !           260:                        goto malloc_fail;
        !           261:                memcpy(msg->host, uri + 7, hlen);
        !           262:                msg->host[hlen] = '\0';
        !           263:                conn->proxy = 1;
        !           264:        } else if (*uri != '/') {
        !           265:                http_response_send_error(resp,
        !           266:                    HTTP_STATUS_BAD_REQUEST, "Bogus non-absolute URI");
        !           267:                return (-1);
        !           268:        } else
        !           269:                path = uri;
        !           270:        if ((s = strchr(path, '?')) == NULL)
        !           271:                plen = strlen(path);
        !           272:        else {
        !           273:                plen = s - path;
        !           274:                if ((msg->query = STRDUP("http_message.query", s + 1)) == NULL)
        !           275:                        goto malloc_fail;
        !           276:        }
        !           277: 
        !           278: no_path:
        !           279:        /* Check body input length for POST, all others have no input body */
        !           280:        if (strcmp(method, HTTP_METHOD_POST) == 0) {
        !           281:                if (msg->input_len == UINT_MAX
        !           282:                    && _http_head_want_keepalive(req->msg->head)) {
        !           283:                        http_response_send_error(resp, HTTP_STATUS_BAD_REQUEST,
        !           284:                            "Keep-Alive requires %s",
        !           285:                            HTTP_HEADER_CONTENT_LENGTH);
        !           286:                        return (-1);
        !           287:                }
        !           288:        } else
        !           289:                msg->input_len = 0;                     /* ignore C-L header */
        !           290: 
        !           291:        /* Decode URL path part */
        !           292:        if (path == NULL)
        !           293:                goto no_path2;
        !           294:        if ((msg->path = MALLOC("http_message.path", plen + 1)) == NULL) {
        !           295: malloc_fail:
        !           296:                (*conn->logger)(LOG_ERR, "%s: %s", "malloc", strerror(errno));
        !           297:                http_response_send_error(resp,
        !           298:                    HTTP_STATUS_INTERNAL_SERVER_ERROR, "%s", strerror(errno));
        !           299:                return (-1);
        !           300:        }
        !           301:        memcpy(msg->path, path, plen);
        !           302:        msg->path[plen] = '\0';
        !           303:        http_request_url_decode(msg->path, msg->path);
        !           304: 
        !           305: no_path2:
        !           306:        /* Check Host: header specified in a HTTP/1.1 request */
        !           307:        if (strcmp(proto, HTTP_PROTO_1_1) == 0
        !           308:            && msg->host == NULL
        !           309:            && _http_head_get(msg->head, HTTP_HEADER_HOST) == NULL) {
        !           310:                http_response_send_error(resp,
        !           311:                    HTTP_STATUS_BAD_REQUEST, "No host specified");
        !           312:                return (-1);
        !           313:        }
        !           314: 
        !           315:        /* Decode name, value pairs from query string */
        !           316:        if (msg->query != NULL)
        !           317:                http_request_decode_query(req);
        !           318: 
        !           319:        /* Done */
        !           320:        return (0);
        !           321: }
        !           322: 
        !           323: /*
        !           324:  * Free a request structure.
        !           325:  */
        !           326: void
        !           327: _http_request_free(struct http_request **reqp)
        !           328: {
        !           329:        struct http_request *const req = *reqp;
        !           330:        int i;
        !           331: 
        !           332:        if (req == NULL)
        !           333:                return;
        !           334:        _http_message_free(&req->msg);
        !           335:        FREE("http_request.username", req->username);
        !           336:        FREE("http_request.password", req->password);
        !           337:        for (i = 0; i < req->num_nvp; i++) {
        !           338:                struct http_nvp *const nvp = &req->nvp[i];
        !           339: 
        !           340:                FREE("http_request.nvp.name", nvp->name);
        !           341:                FREE("http_request.nvp.value", nvp->value);
        !           342:        }
        !           343:        FREE("http_request.nvp", req->nvp);
        !           344:        FREE("http_request", req);
        !           345:        *reqp = NULL;
        !           346: }
        !           347: 
        !           348: /*********************************************************************
        !           349:                        MESSAGE WRAPPER ROUTINES
        !           350: *********************************************************************/
        !           351: 
        !           352: /*
        !           353:  * Get a request header.
        !           354:  *
        !           355:  * For headers listed multiple times, this only gets the first instance.
        !           356:  */
        !           357: const char *
        !           358: http_request_get_header(struct http_request *req, const char *name)
        !           359: {
        !           360:        return (_http_head_get(req->msg->head, name));
        !           361: }
        !           362: 
        !           363: /*
        !           364:  * Get the number of headers
        !           365:  */
        !           366: int
        !           367: http_request_num_headers(struct http_request *req)
        !           368: {
        !           369:        return (_http_head_num_headers(req->msg->head));
        !           370: }
        !           371: 
        !           372: /*
        !           373:  * Get header by index.
        !           374:  */
        !           375: int
        !           376: http_request_get_header_by_index(struct http_request *req,
        !           377:        u_int index, const char **namep, const char **valuep)
        !           378: {
        !           379:        return (_http_head_get_by_index(req->msg->head, index, namep, valuep));
        !           380: }
        !           381: 
        !           382: /*
        !           383:  * Set a request header.
        !           384:  */
        !           385: int
        !           386: http_request_set_header(struct http_request *req, int append,
        !           387:        const char *name, const char *valfmt, ...)
        !           388: {
        !           389:        va_list args;
        !           390:        int ret;
        !           391: 
        !           392:        /* Set header */
        !           393:        va_start(args, valfmt);
        !           394:        ret = _http_message_vset_header(req->msg, append, name, valfmt, args);
        !           395:        va_end(args);
        !           396:        return (ret);
        !           397: }
        !           398: 
        !           399: /*
        !           400:  * Remove a header.
        !           401:  */
        !           402: int
        !           403: http_request_remove_header(struct http_request *req, const char *name)
        !           404: {
        !           405:        return (_http_message_remove_header(req->msg, name));
        !           406: }
        !           407: 
        !           408: /*
        !           409:  * Send request headers to peer.
        !           410:  */
        !           411: int
        !           412: http_request_send_headers(struct http_request *req)
        !           413: {
        !           414:        const char *const method = http_request_get_method(req);
        !           415:        const char *const path = http_request_get_path(req);
        !           416:        const char *const uri = http_request_get_uri(req);
        !           417:        char *epath;
        !           418: 
        !           419:        /* Sanity checks */
        !           420:        if (req->msg->hdrs_sent)
        !           421:                return (0);
        !           422:        if (method == NULL || (path == NULL && uri == NULL)) {
        !           423:                errno = EINVAL;
        !           424:                return (-1);
        !           425:        }
        !           426: 
        !           427:        /* If request is GET, put name, value pairs in the query string */
        !           428:        if (strcmp(method, HTTP_METHOD_GET) == 0
        !           429:            && http_request_set_query_from_values(req) == -1)
        !           430:                return (-1);
        !           431: 
        !           432:        /* Set request URI */
        !           433:        if (uri == NULL) {
        !           434:                if ((epath = http_request_url_encode(
        !           435:                    TYPED_MEM_TEMP, path)) == NULL)
        !           436:                        return (-1);
        !           437:                if (http_request_set_header(req, 0,
        !           438:                    HDR_REQUEST_URI, "%s%s%s", epath,
        !           439:                    req->msg->query != NULL ? "?" : "",
        !           440:                    req->msg->query != NULL ? req->msg->query : "") == -1) {
        !           441:                        FREE(TYPED_MEM_TEMP, epath);
        !           442:                        return (-1);
        !           443:                }
        !           444:                FREE(TYPED_MEM_TEMP, epath);
        !           445:        }
        !           446: 
        !           447:        /* Set other headers */
        !           448:        if (http_request_set_header(req, 0, HDR_REQUEST_METHOD,
        !           449:            "%s", http_request_get_method(req)) == -1)
        !           450:                return (-1);
        !           451:        if (http_request_set_header(req, 0, HDR_REQUEST_VERSION,
        !           452:            "%s", HTTP_PROTO_1_0) == -1)
        !           453:                return (-1);
        !           454:        if (http_request_set_header(req, 0,
        !           455:            _http_message_connection_header(req->msg), "%s",
        !           456:            req->msg->conn->keep_alive ? "Keep-Alive" : "Close") == -1)
        !           457:                return (-1);
        !           458: 
        !           459:        /* Send headers */
        !           460:        _http_message_send_headers(req->msg, 0);
        !           461:        return (0);
        !           462: }
        !           463: 
        !           464: /*
        !           465:  * Get the encoded query string.
        !           466:  */
        !           467: const char *
        !           468: http_request_get_query_string(struct http_request *req)
        !           469: {
        !           470:        return (req->msg->query == NULL ? "" : req->msg->query);
        !           471: }
        !           472: 
        !           473: /*
        !           474:  * Get specified host, if any.
        !           475:  */
        !           476: const char *
        !           477: http_request_get_host(struct http_request *req)
        !           478: {
        !           479:        struct http_connection *const conn = req->msg->conn;
        !           480:        const char *host;
        !           481: 
        !           482:        if (!conn->proxy
        !           483:            && (host = http_request_get_header(req, HTTP_HEADER_HOST)) != NULL)
        !           484:                return (host);
        !           485:        return (req->msg->host);
        !           486: }
        !           487: 
        !           488: /*
        !           489:  * Get query method.
        !           490:  */
        !           491: const char *
        !           492: http_request_get_method(struct http_request *req)
        !           493: {
        !           494:        return (http_request_get_header(req, HDR_REQUEST_METHOD));
        !           495: }
        !           496: 
        !           497: /*
        !           498:  * Get query URI.
        !           499:  */
        !           500: const char *
        !           501: http_request_get_uri(struct http_request *req)
        !           502: {
        !           503:        return (http_request_get_header(req, HDR_REQUEST_URI));
        !           504: }
        !           505: 
        !           506: /*
        !           507:  * Get query version.
        !           508:  */
        !           509: const char *
        !           510: http_request_get_version(struct http_request *req)
        !           511: {
        !           512:        return (http_request_get_header(req, HDR_REQUEST_VERSION));
        !           513: }
        !           514: 
        !           515: /*
        !           516:  * Set query method.
        !           517:  */
        !           518: int
        !           519: http_request_set_method(struct http_request *req, const char *method)
        !           520: {
        !           521:        /* Must be GET, POST, or HEAD for now */
        !           522:        if (strcmp(method, HTTP_METHOD_GET) != 0
        !           523:            && strcmp(method, HTTP_METHOD_POST) != 0
        !           524:            && strcmp(method, HTTP_METHOD_HEAD) != 0) {
        !           525:                errno = EINVAL;
        !           526:                return (-1);
        !           527:        }
        !           528: 
        !           529:        /* Set method */
        !           530:        if (http_request_set_header(req, 0,
        !           531:            HDR_REQUEST_METHOD, "%s", method) == -1)
        !           532:                return (-1);
        !           533: 
        !           534:        /* Only POST is allowed to have a body */
        !           535:        req->msg->no_body = (strcmp(method, HTTP_METHOD_POST) != 0);
        !           536:        return (0);
        !           537: }
        !           538: 
        !           539: /*
        !           540:  * Set proxy request bit.
        !           541:  */
        !           542: void
        !           543: http_request_set_proxy(struct http_request *req, int whether)
        !           544: {
        !           545:        struct http_connection *const conn = req->msg->conn;
        !           546: 
        !           547:        conn->proxy = !!whether;
        !           548: }
        !           549: 
        !           550: /*
        !           551:  * Get the URL path.
        !           552:  */
        !           553: const char *
        !           554: http_request_get_path(struct http_request *req)
        !           555: {
        !           556:        return (req->msg->path);
        !           557: }
        !           558: 
        !           559: /*
        !           560:  * Set the URL path.
        !           561:  */
        !           562: int
        !           563: http_request_set_path(struct http_request *req, const char *path)
        !           564: {
        !           565:        char *copy;
        !           566: 
        !           567:        if (path == NULL || *path != '/') {
        !           568:                errno = EINVAL;
        !           569:                return (-1);
        !           570:        }
        !           571:        if ((copy = STRDUP("http_message.path", path)) == NULL)
        !           572:                return (-1);
        !           573:        FREE("http_message.path", req->msg->path);
        !           574:        req->msg->path = copy;
        !           575:        return (0);
        !           576: }
        !           577: 
        !           578: /*
        !           579:  * Get SSL context.
        !           580:  */
        !           581: SSL_CTX *
        !           582: http_request_get_ssl(struct http_request *req)
        !           583: {
        !           584:        return (req->msg->conn->ssl);
        !           585: }
        !           586: 
        !           587: /*
        !           588:  * Get request input stream.
        !           589:  */
        !           590: FILE *
        !           591: http_request_get_input(struct http_request *req)
        !           592: {
        !           593:        if (!req->msg->conn->server) {
        !           594:                errno = EINVAL;
        !           595:                return (NULL);
        !           596:        }
        !           597:        return (req->msg->input);
        !           598: }
        !           599: 
        !           600: /*
        !           601:  * Get raw i/o stream as a file descriptor.
        !           602:  */
        !           603: int
        !           604: http_request_get_raw_socket(struct http_request *req)
        !           605: {
        !           606:        return (_http_message_get_raw_socket(req->msg));
        !           607: }
        !           608: 
        !           609: /*
        !           610:  * Get request output stream.
        !           611:  *
        !           612:  * If "buffer" is true, the entire output will be buffered unless
        !           613:  * the headers have already been sent.
        !           614:  */
        !           615: FILE *
        !           616: http_request_get_output(struct http_request *req, int buffer)
        !           617: {
        !           618:        if (req->msg->conn->server) {
        !           619:                errno = EINVAL;
        !           620:                return (NULL);
        !           621:        }
        !           622:        return (_http_message_get_output(req->msg, buffer));
        !           623: }
        !           624: 
        !           625: /*
        !           626:  * Get remote IP address.
        !           627:  */
        !           628: struct in_addr
        !           629: http_request_get_remote_ip(struct http_request *req)
        !           630: {
        !           631:        return (_http_message_get_remote_ip(req->msg));
        !           632: }
        !           633: 
        !           634: /*
        !           635:  * Get remote port.
        !           636:  */
        !           637: u_int16_t
        !           638: http_request_get_remote_port(struct http_request *req)
        !           639: {
        !           640:        return (_http_message_get_remote_port(req->msg));
        !           641: }
        !           642: 
        !           643: /*********************************************************************
        !           644:                        AUTHORIZATION ROUTINES
        !           645: *********************************************************************/
        !           646: 
        !           647: /*
        !           648:  * Get request remote username.
        !           649:  *
        !           650:  * Returns NULL if none specified.
        !           651:  */
        !           652: const char *
        !           653: http_request_get_username(struct http_request *req)
        !           654: {
        !           655:        if (req->username == NULL)
        !           656:                http_request_decode_auth(req);
        !           657:        return (req->username);
        !           658: }
        !           659: 
        !           660: /*
        !           661:  * Get request remote password
        !           662:  *
        !           663:  * Returns NULL if none specified.
        !           664:  */
        !           665: const char *
        !           666: http_request_get_password(struct http_request *req)
        !           667: {
        !           668:        if (req->password == NULL)
        !           669:                http_request_decode_auth(req);
        !           670:        return (req->password);
        !           671: }
        !           672: 
        !           673: /*
        !           674:  * Compute base64 encoded username and password, suitable for
        !           675:  * passing in a basic authentication header.
        !           676:  */
        !           677: char *
        !           678: http_request_encode_basic_auth(const char *mtype,
        !           679:        const char *username, const char *password)
        !           680: {
        !           681:        char *buf;
        !           682:        char *auth;
        !           683:        int len;
        !           684:        int i, j;
        !           685: 
        !           686:        /* Get raw data buffer */
        !           687:        len = strlen(username) + 1 + strlen(password) + 1;
        !           688:        if ((buf = MALLOC(TYPED_MEM_TEMP, len)) == NULL)
        !           689:                return (NULL);
        !           690:        strcpy(buf, username);
        !           691:        strcat(buf, ":");
        !           692:        strcat(buf, password);
        !           693: 
        !           694:        /* Get encoded buffer */
        !           695:        len = (4 * len) / 3 + 32;
        !           696:        if ((auth = MALLOC(mtype, len)) == NULL) {
        !           697:                FREE(TYPED_MEM_TEMP, buf);
        !           698:                return (NULL);
        !           699:        }
        !           700: 
        !           701:        /* Encode bits */
        !           702:        len = strlen(buf);
        !           703:        for (j = i = 0; i < len; i += 3) {
        !           704:                const u_char b0 = ((u_char *)buf)[i];
        !           705:                const u_char b1 = (i < len - 1) ? ((u_char *)buf)[i + 1] : 0;
        !           706:                const u_char b2 = (i < len - 2) ? ((u_char *)buf)[i + 2] : 0;
        !           707: 
        !           708:                auth[j++] = base64[(b0 >> 2) & 0x3f];
        !           709:                auth[j++] = base64[((b0 << 4) & 0x30) | ((b1 >> 4) & 0x0f)];
        !           710:                if (i == len - 1)
        !           711:                        break;
        !           712:                auth[j++] = base64[((b1 << 2) & 0x3c) | ((b2 >> 6) & 0x03)];
        !           713:                if (i == len - 2)
        !           714:                        break;
        !           715:                auth[j++] = base64[b2 & 0x3f];
        !           716:        }
        !           717:        FREE(TYPED_MEM_TEMP, buf);
        !           718: 
        !           719:        /* Pad encoding to an even multiple with equals signs */
        !           720:        switch (len % 3) {
        !           721:        case 1: auth[j++] = '=';                /* fall through */
        !           722:        case 2: auth[j++] = '=';
        !           723:        case 0: break;
        !           724:        }
        !           725:        auth[j] = '\0';
        !           726: 
        !           727:        /* Done */
        !           728:        return (auth);
        !           729: }
        !           730: 
        !           731: /*
        !           732:  * Decode basic Authorization: header.
        !           733:  */
        !           734: static void
        !           735: http_request_decode_auth(struct http_request *req)
        !           736: {
        !           737:        static u_char table[256];
        !           738:        u_int val, pval = 0;
        !           739:        const char *s;
        !           740:        char buf[128];
        !           741:        char *pw;
        !           742:        int step;
        !           743:        int len;
        !           744: 
        !           745:        /* Initialize table (first time only) */
        !           746:        if (table[0] == 0) {
        !           747:                for (val = 0; val < 0x100; val++) {
        !           748:                        table[val] = ((s = strchr(base64, (char)val)) != NULL) ?
        !           749:                            s - base64 : 0xff;
        !           750:                }
        !           751:        }
        !           752: 
        !           753:        /* Get basic authentication header */
        !           754:        if ((s = http_request_get_header(req,
        !           755:              HTTP_HEADER_AUTHORIZATION)) == NULL
        !           756:            || strncmp(s, "Basic ", 6) != 0)
        !           757:                return;
        !           758: 
        !           759:        /* Decode it */
        !           760:        for (len = step = 0, s += 6; len < sizeof(buf) - 1 && *s != '\0'; s++) {
        !           761: 
        !           762:                /* Decode character */
        !           763:                if ((val = table[(u_char)*s]) == 0xff)
        !           764:                        continue;
        !           765: 
        !           766:                /* Glom on bits */
        !           767:                switch (step % 4) {
        !           768:                case 1:
        !           769:                        buf[len++] = (pval << 2) | ((val & 0x30) >> 4);
        !           770:                        break;
        !           771:                case 2:
        !           772:                        buf[len++] = ((pval & 0x0f) << 4) | ((val & 0x3c) >> 2);
        !           773:                        break;
        !           774:                case 3:
        !           775:                        buf[len++] = ((pval & 0x03) << 6) | val;
        !           776:                        break;
        !           777:                }
        !           778:                pval = val;
        !           779:                step++;
        !           780:        }
        !           781:        buf[len] = '\0';
        !           782: 
        !           783:        /* Find password */
        !           784:        if ((pw = strchr(buf, ':')) == NULL)
        !           785:                return;
        !           786:        *pw++ = '\0';
        !           787: 
        !           788:        /* Allocate strings */
        !           789:        if ((req->username = STRDUP("http_request.username", buf)) == NULL)
        !           790:                return;
        !           791:        if ((req->password = STRDUP("http_request.password", pw)) == NULL) {
        !           792:                FREE("http_request.username", req->username);
        !           793:                req->username = NULL;
        !           794:                return;
        !           795:        }
        !           796: }
        !           797: 
        !           798: /*********************************************************************
        !           799:                        FORM FILE UPLOAD
        !           800: *********************************************************************/
        !           801: 
        !           802: #define WHITESPACE             " \t\r\n\f\v"
        !           803: 
        !           804: struct upload_info {
        !           805:        const char      *field;
        !           806:        FILE            *fp;
        !           807:        int             error;
        !           808:        size_t          max;
        !           809: };
        !           810: 
        !           811: static http_mime_handler_t http_request_file_upload_handler;
        !           812: 
        !           813: /*
        !           814:  * Read an HTTP POST containing MIME multipart data and write
        !           815:  * the contents of the named field into the supplied stream.
        !           816:  * The stream is NOT closed.
        !           817:  *
        !           818:  * If "max" is non-zero and more than "max" bytes are read,
        !           819:  * an error is returned with errno = EFBIG.
        !           820:  *
        !           821:  * Returns zero if successful, otherwise -1 and sets errno.
        !           822:  */
        !           823: int
        !           824: http_request_file_upload(struct http_request *req,
        !           825:        const char *field, FILE *fp, size_t max)
        !           826: {
        !           827:        struct upload_info info;
        !           828:        const char *hval;
        !           829:        char *s;
        !           830: 
        !           831:        /* Verify proper submit was done */
        !           832:        if ((hval = http_request_get_header(req,
        !           833:            HTTP_HEADER_CONTENT_TYPE)) == NULL) {
        !           834:                errno = EINVAL;
        !           835:                return (-1);
        !           836:        }
        !           837:        if ((s = strchr(hval, ';')) == NULL
        !           838:            || strncasecmp(hval,
        !           839:              HTTP_CTYPE_MULTIPART_FORMDATA, s - hval) != 0) {
        !           840:                errno = EINVAL;
        !           841:                return (-1);
        !           842:        }
        !           843: 
        !           844:        /* Read form data into file */
        !           845:        memset(&info, 0, sizeof(info));
        !           846:        info.field = field;
        !           847:        info.fp = fp;
        !           848:        info.max = max;
        !           849:        if (http_request_get_mime_multiparts(req,
        !           850:            http_request_file_upload_handler, &info) < 0) {
        !           851:                if (info.error == 0)
        !           852:                        info.error = errno;
        !           853:        }
        !           854:        if (info.error != 0) {
        !           855:                errno = info.error;
        !           856:                return (-1);
        !           857:        }
        !           858: 
        !           859:        /* Done */
        !           860:        return (0);
        !           861: }
        !           862: 
        !           863: static int
        !           864: http_request_file_upload_handler(void *arg, struct mime_part *part, FILE *fp)
        !           865: {
        !           866:        struct upload_info *const info = arg;
        !           867:        const char *hval = http_mime_part_get_header(part,
        !           868:            HTTP_HEADER_CONTENT_DISPOSITION);
        !           869:        char buf[256];
        !           870:        char *tokctx;
        !           871:        char *s, *t;
        !           872:        size_t len;
        !           873:        size_t nr;
        !           874: 
        !           875:        /* Parse content dispostion to get the field name */
        !           876:        strlcpy(buf, hval, sizeof(buf));
        !           877:        for (s = strtok_r(buf, WHITESPACE ";", &tokctx);
        !           878:            s != NULL;
        !           879:            s = strtok_r(NULL, WHITESPACE ";", &tokctx)) {
        !           880:                if (strncmp(s, "name=\"", 6) != 0)
        !           881:                        continue;
        !           882:                s += 6;
        !           883:                if ((t = strchr(s, '"')) == NULL)
        !           884:                        continue;
        !           885:                *t = '\0';
        !           886:                if (strcmp(s, info->field) == 0)        /* is this the field? */
        !           887:                        break;
        !           888:        }
        !           889:        if (s == NULL)                                  /* wrong field */
        !           890:                return (0);
        !           891: 
        !           892:        /* Read data and write it to caller-supplied stream */
        !           893:        for (len = 0; (nr = fread(buf, 1, sizeof(buf), fp)) != 0; len += nr) {
        !           894:                if (info->max != 0 && len + nr > info->max) {
        !           895:                        errno = EFBIG;
        !           896:                        goto fail;
        !           897:                }
        !           898:                if (fwrite(buf, 1, nr, info->fp) != nr)
        !           899:                        goto fail;
        !           900:        }
        !           901:        if (ferror(fp)) {
        !           902: fail:          info->error = errno;
        !           903:                return (-1);
        !           904:        }
        !           905: 
        !           906:        /* Done */
        !           907:        return (0);
        !           908: }
        !           909: 
        !           910: /*********************************************************************
        !           911:                        NAME VALUE PAIR ROUTINES
        !           912: *********************************************************************/
        !           913: 
        !           914: /*
        !           915:  * Get a value from a request.
        !           916:  */
        !           917: const char *
        !           918: http_request_get_value(struct http_request *req, const char *name, int instance)
        !           919: {
        !           920:        struct http_nvp key;
        !           921:        struct http_nvp *nvp;
        !           922: 
        !           923:        key.name = (char *)name;
        !           924:        if ((nvp = bsearch(&key,
        !           925:            req->nvp, req->num_nvp, sizeof(*req->nvp), nvp_cmp)) == NULL)
        !           926:                return (NULL);
        !           927:        while (instance-- > 0) {
        !           928:                if (++nvp - req->nvp >= req->num_nvp
        !           929:                    || strcmp(nvp->name, name) != 0)
        !           930:                        return (NULL);
        !           931:        }
        !           932:        return (nvp->value);
        !           933: }
        !           934: 
        !           935: /*
        !           936:  * Set a value associated with a query.
        !           937:  */
        !           938: int
        !           939: http_request_set_value(struct http_request *req,
        !           940:        const char *name, const char *value)
        !           941: {
        !           942:        int ret;
        !           943: 
        !           944:        if ((ret = http_request_add_nvp(req, 0, name, value)) == -1)
        !           945:                return (-1);
        !           946:        mergesort(req->nvp, req->num_nvp, sizeof(*req->nvp), nvp_cmp);
        !           947:        return (0);
        !           948: }
        !           949: 
        !           950: /*
        !           951:  * Get the number of NVP's.
        !           952:  */
        !           953: int
        !           954: http_request_get_num_values(struct http_request *req)
        !           955: {
        !           956:        return (req->num_nvp);
        !           957: }
        !           958: 
        !           959: /*
        !           960:  * Get the name of an NVP by index.
        !           961:  */
        !           962: int
        !           963: http_request_get_value_by_index(struct http_request *req, int i,
        !           964:        const char **name, const char **value)
        !           965: {
        !           966:        if (i < 0 || i >= req->num_nvp) {
        !           967:                errno = EINVAL;
        !           968:                return (-1);
        !           969:        }
        !           970:        if (name != NULL)
        !           971:                *name = req->nvp[i].name;
        !           972:        if (value != NULL)
        !           973:                *value = req->nvp[i].value;
        !           974:        return (0);
        !           975: }
        !           976: 
        !           977: /*
        !           978:  * Reset the query string from the list of name, value pairs.
        !           979:  */
        !           980: int
        !           981: http_request_set_query_from_values(struct http_request *req)
        !           982: {
        !           983:        char *buf;
        !           984:        int qlen;
        !           985:        int i;
        !           986: 
        !           987:        /* If no values, no query string */
        !           988:        if (req->num_nvp == 0) {
        !           989:                buf = NULL;
        !           990:                goto done;
        !           991:        }
        !           992: 
        !           993:        /* Get bound on encoded query string length */
        !           994:        for (qlen = i = 0; i < req->num_nvp; i++) {
        !           995:                const struct http_nvp *const nvp = &req->nvp[i];
        !           996: 
        !           997:                qlen += strlen(nvp->name) * 3 + 1 + strlen(nvp->value) * 3;
        !           998:        }
        !           999: 
        !          1000:        /* Allocate new buffer */
        !          1001:        if ((buf = MALLOC("http_message.query", qlen + 1)) == NULL)
        !          1002:                return (-1);
        !          1003: 
        !          1004:        /* Encode name, value pairs into buffer */
        !          1005:        for (qlen = i = 0; i < req->num_nvp; i++) {
        !          1006:                const struct http_nvp *const nvp = &req->nvp[i];
        !          1007:                char *ename;
        !          1008:                char *evalue;
        !          1009: 
        !          1010:                if ((ename = http_request_url_encode(TYPED_MEM_TEMP,
        !          1011:                    nvp->name)) == NULL) {
        !          1012:                        FREE("http_message.query", buf);
        !          1013:                        return (-1);
        !          1014:                }
        !          1015:                if ((evalue = http_request_url_encode(TYPED_MEM_TEMP,
        !          1016:                    nvp->value)) == NULL) {
        !          1017:                        FREE(TYPED_MEM_TEMP, ename);
        !          1018:                        FREE("http_message.query", buf);
        !          1019:                        return (-1);
        !          1020:                }
        !          1021:                qlen += sprintf(buf + qlen, "%s%s=%s",
        !          1022:                    i > 0 ? "&" : "", ename, evalue);
        !          1023:                FREE(TYPED_MEM_TEMP, ename);
        !          1024:                FREE(TYPED_MEM_TEMP, evalue);
        !          1025:        }
        !          1026: 
        !          1027: done:
        !          1028:        /* Set new query string */
        !          1029:        FREE("http_message.query", req->msg->query);
        !          1030:        req->msg->query = buf;
        !          1031:        return (0);
        !          1032: }
        !          1033: 
        !          1034: /*
        !          1035:  * Read in name, value pairs as URL-encoded form data.
        !          1036:  * Typically this is used for receiving POST requests.
        !          1037:  */
        !          1038: int
        !          1039: http_request_read_url_encoded_values(struct http_request *req)
        !          1040: {
        !          1041:        FILE *input;
        !          1042:        char *name;
        !          1043:        char *value;
        !          1044:        int count;
        !          1045:        int totlen;
        !          1046:        int ret;
        !          1047:        int ch;
        !          1048: 
        !          1049:        /* Get input stream */
        !          1050:        if ((input = http_request_get_input(req)) == NULL)
        !          1051:                return (-1);
        !          1052: 
        !          1053:        /* Read in URL-encoded name, value pairs */
        !          1054:        for (count = totlen = 0; totlen < MAX_NVP_DATA; totlen++) {
        !          1055: 
        !          1056:                /* Read name */
        !          1057:                if ((name = read_string_until(TYPED_MEM_TEMP,
        !          1058:                    req->msg->input, "&=")) == NULL)
        !          1059:                        return (-1);
        !          1060: 
        !          1061:                /* Read value, if any */
        !          1062:                if ((ch = getc(req->msg->input)) == '=') {
        !          1063:                        if ((value = read_string_until(TYPED_MEM_TEMP,
        !          1064:                            req->msg->input, "&")) == NULL) {
        !          1065:                                FREE(TYPED_MEM_TEMP, name);
        !          1066:                                return (-1);
        !          1067:                        }
        !          1068:                } else
        !          1069:                        value = NULL;
        !          1070: 
        !          1071:                /* Slurp next char */
        !          1072:                (void)getc(req->msg->input);
        !          1073: 
        !          1074:                /* Add name, value pair */
        !          1075:                ret = 0;
        !          1076:                if (*name != '\0') {
        !          1077:                        ret = http_request_add_nvp(req, 1,
        !          1078:                            name, (value != NULL) ? value : "");
        !          1079:                        count++;
        !          1080:                }
        !          1081:                FREE(TYPED_MEM_TEMP, name);
        !          1082:                FREE(TYPED_MEM_TEMP, value);
        !          1083:                if (ret == -1)
        !          1084:                        return (-1);
        !          1085:        }
        !          1086: 
        !          1087:        /* Sort name using mergesort() which preserves order of duplicates */
        !          1088:        if (mergesort(req->nvp, req->num_nvp, sizeof(*req->nvp), nvp_cmp) == -1)
        !          1089:                return (-1);
        !          1090: 
        !          1091:        /* Done */
        !          1092:        return (count);
        !          1093: }
        !          1094: 
        !          1095: /*
        !          1096:  * Write out name, value pairs as URL-encoded form data.
        !          1097:  * Typically this is used for sending POST requests.
        !          1098:  */
        !          1099: int
        !          1100: http_request_write_url_encoded_values(struct http_request *req)
        !          1101: {
        !          1102:        int i;
        !          1103: 
        !          1104:        /* Get output stream */
        !          1105:        if (req->msg->output == NULL) {
        !          1106:                errno = EINVAL;
        !          1107:                return (-1);
        !          1108:        }
        !          1109: 
        !          1110:        /* Encode name, value pairs into buffer */
        !          1111:        for (i = 0; i < req->num_nvp; i++) {
        !          1112:                const struct http_nvp *const nvp = &req->nvp[i];
        !          1113:                char *ename;
        !          1114:                char *evalue;
        !          1115: 
        !          1116:                if ((ename = http_request_url_encode(TYPED_MEM_TEMP,
        !          1117:                    nvp->name)) == NULL)
        !          1118:                        return (-1);
        !          1119:                if ((evalue = http_request_url_encode(TYPED_MEM_TEMP,
        !          1120:                    nvp->value)) == NULL) {
        !          1121:                        FREE(TYPED_MEM_TEMP, ename);
        !          1122:                        return (-1);
        !          1123:                }
        !          1124:                fprintf(req->msg->output, "%s%s=%s",
        !          1125:                    i > 0 ? "&" : "", ename, evalue);
        !          1126:                FREE(TYPED_MEM_TEMP, ename);
        !          1127:                FREE(TYPED_MEM_TEMP, evalue);
        !          1128:        }
        !          1129:        return (0);
        !          1130: }
        !          1131: 
        !          1132: /*
        !          1133:  * Parse out query string into name, value pairs.
        !          1134:  */
        !          1135: static int
        !          1136: http_request_decode_query(struct http_request *req)
        !          1137: {
        !          1138:        char *tokctx;
        !          1139:        char *qbuf;
        !          1140:        char *name;
        !          1141:        char *value;
        !          1142: 
        !          1143:        /* Sanity */
        !          1144:        if (req->msg->query == NULL)
        !          1145:                return (0);
        !          1146: 
        !          1147:        /* Copy original encoded query string */
        !          1148:        if ((qbuf = STRDUP(TYPED_MEM_TEMP, req->msg->query)) == NULL)
        !          1149:                return (-1);
        !          1150: 
        !          1151:        /* Separate out and decode name, value pairs */
        !          1152:        for (name = strtok_r(qbuf, "&", &tokctx);
        !          1153:            name != NULL;
        !          1154:            name = strtok_r(NULL, "&", &tokctx)) {
        !          1155: 
        !          1156:                /* Find value */
        !          1157:                if ((value = strchr(name, '=')) == NULL)
        !          1158:                        continue;
        !          1159:                *value++ = '\0';
        !          1160: 
        !          1161:                /* Add name, value pair */
        !          1162:                if (http_request_add_nvp(req, 1, name, value) == -1) {
        !          1163:                        FREE(TYPED_MEM_TEMP, qbuf);
        !          1164:                        return (-1);
        !          1165:                }
        !          1166:        }
        !          1167:        FREE(TYPED_MEM_TEMP, qbuf);
        !          1168: 
        !          1169:        /* Sort name using mergesort() which preserves order of duplicates */
        !          1170:        if (mergesort(req->nvp, req->num_nvp, sizeof(*req->nvp), nvp_cmp) == -1)
        !          1171:                return (-1);
        !          1172:        return (0);
        !          1173: }
        !          1174: 
        !          1175: /*
        !          1176:  * Add an (optionally URL-encoded) name, value pair.
        !          1177:  *
        !          1178:  * Array must be sorted again by caller.
        !          1179:  */
        !          1180: static int
        !          1181: http_request_add_nvp(struct http_request *req, int encoded,
        !          1182:        const char *ename, const char *evalue)
        !          1183: {
        !          1184:        char *name;
        !          1185:        char *value;
        !          1186:        void *mem;
        !          1187: 
        !          1188:        /* Create buffers */
        !          1189:        if ((name = MALLOC("http_request.nvp.name", strlen(ename) + 1)) == NULL)
        !          1190:                return (-1);
        !          1191:        if ((value = MALLOC("http_request.nvp.value",
        !          1192:            strlen(evalue) + 1)) == NULL) {
        !          1193:                FREE("http_request.nvp.name", name);
        !          1194:                return (-1);
        !          1195:        }
        !          1196: 
        !          1197:        /* URL-decode name and value */
        !          1198:        if (encoded) {
        !          1199:                http_request_url_decode(ename, name);
        !          1200:                http_request_url_decode(evalue, value);
        !          1201:        } else {
        !          1202:                strcpy(name, ename);
        !          1203:                strcpy(value, evalue);
        !          1204:        }
        !          1205: 
        !          1206:        /* Add new pointer struct */
        !          1207:        if ((mem = REALLOC("http_request.nvp", req->nvp,
        !          1208:            (req->num_nvp + 1) * sizeof(*req->nvp))) == NULL) {
        !          1209:                FREE("http_request.nvp.name", name);
        !          1210:                FREE("http_request.nvp.value", value);
        !          1211:                return (-1);
        !          1212:        }
        !          1213:        req->nvp = mem;
        !          1214:        req->nvp[req->num_nvp].name = name;
        !          1215:        req->nvp[req->num_nvp].value = value;
        !          1216:        req->num_nvp++;
        !          1217:        return (0);
        !          1218: }
        !          1219: 
        !          1220: /*
        !          1221:  * Comparator for name, value pairs
        !          1222:  */
        !          1223: static int
        !          1224: nvp_cmp(const void *v1, const void *v2)
        !          1225: {
        !          1226:        const struct http_nvp *const q1 = v1;
        !          1227:        const struct http_nvp *const q2 = v2;
        !          1228: 
        !          1229:        return (strcmp(q1->name, q2->name));
        !          1230: }
        !          1231: 
        !          1232: /*
        !          1233:  * Read a string until a terminating character or EOF is seen.
        !          1234:  */
        !          1235: static char *
        !          1236: read_string_until(const char *mtype, FILE *fp, const char *term)
        !          1237: {
        !          1238:        size_t alloc = 32;
        !          1239:        void *mem;
        !          1240:        char *s;
        !          1241:        int len = 0;
        !          1242:        int ch;
        !          1243: 
        !          1244:        if ((s = MALLOC(mtype, alloc)) == NULL)
        !          1245:                return (NULL);
        !          1246:        while (len < MAX_NVP_LEN) {
        !          1247:                if ((ch = getc(fp)) == EOF) {
        !          1248:                        s[len] = '\0';
        !          1249:                        return (s);
        !          1250:                }
        !          1251:                if (strchr(term, ch) != NULL && ch != '\0') {
        !          1252:                        ungetc(ch, fp);
        !          1253:                        s[len] = '\0';
        !          1254:                        return (s);
        !          1255:                }
        !          1256:                s[len++] = ch;
        !          1257:                if (len == alloc) {
        !          1258:                        alloc <<= 1;
        !          1259:                        if ((mem = REALLOC(mtype, s, alloc)) == NULL)
        !          1260:                                goto fail;
        !          1261:                        s = mem;
        !          1262:                }
        !          1263:        }
        !          1264:        errno = E2BIG;
        !          1265: fail:
        !          1266:        FREE(mtype, s);
        !          1267:        return (NULL);
        !          1268: }
        !          1269: 
        !          1270: /*********************************************************************
        !          1271:                        MISC ROUTINES
        !          1272: *********************************************************************/
        !          1273: 
        !          1274: /*
        !          1275:  * URL-encode a string.
        !          1276:  */
        !          1277: char *
        !          1278: http_request_url_encode(const char *mtype, const char *s)
        !          1279: {
        !          1280:        char *enc;
        !          1281:        char *t;
        !          1282: 
        !          1283:        if ((enc = MALLOC(mtype, (strlen(s) * 3) + 1)) == NULL)
        !          1284:                return (NULL);
        !          1285:        for (t = enc; *s != '\0'; s++) {
        !          1286:                if (!isalnum((u_char)*s) && strchr("-_.!~*'()/:", *s) == NULL)
        !          1287:                        t += sprintf(t, "%%%02x", (u_char)*s);
        !          1288:                else
        !          1289:                        *t++ = *s;
        !          1290:        }
        !          1291:        *t = '\0';
        !          1292:        return (enc);
        !          1293: }
        !          1294: 
        !          1295: /*
        !          1296:  * URL-decode a string.
        !          1297:  */
        !          1298: void
        !          1299: http_request_url_decode(const char *s, char *t)
        !          1300: {
        !          1301:        for (; *s != '\0'; s++, t++) {
        !          1302:                switch (s[0]) {
        !          1303:                case '+':
        !          1304:                        *t = ' ';
        !          1305:                        break;
        !          1306:                case '%':
        !          1307:                        if (isxdigit((u_char)s[1]) && isxdigit((u_char)s[2])) {
        !          1308:                                *t = isdigit((u_char)s[1]) ?
        !          1309:                                    s[1] - '0' : tolower(s[1]) - 'a' + 10;
        !          1310:                                *t <<= 4;
        !          1311:                                *t |= isdigit((u_char)s[2]) ?
        !          1312:                                    s[2] - '0' : tolower(s[2]) - 'a' + 10;
        !          1313:                                s += 2;
        !          1314:                                break;
        !          1315:                        }
        !          1316:                        /* fall through */
        !          1317:                default:
        !          1318:                        *t = *s;
        !          1319:                        break;
        !          1320:                }
        !          1321:        }
        !          1322:        *t = '\0';
        !          1323: }
        !          1324: 
        !          1325: /*
        !          1326:  * Parse an HTTP time string.
        !          1327:  *
        !          1328:  * Returns (time_t)-1 if there was an error.
        !          1329:  */
        !          1330: time_t
        !          1331: http_request_parse_time(const char *string)
        !          1332: {
        !          1333:        static const char *fmts[] = {
        !          1334:                HTTP_TIME_FMT_RFC1123,
        !          1335:                HTTP_TIME_FMT_RFC850,
        !          1336:                HTTP_TIME_FMT_CTIME,
        !          1337:        };
        !          1338:        struct tm whentm;
        !          1339:        time_t when;
        !          1340:        int i;
        !          1341: 
        !          1342:        for (i = 0; i < sizeof(fmts) / sizeof(*fmts); i++) {
        !          1343:                memset(&whentm, 0, sizeof(whentm));
        !          1344:                if (strptime(string, fmts[i], &whentm) != NULL
        !          1345:                    && (when = timegm(&whentm)) != (time_t)-1)
        !          1346:                        return (when);
        !          1347:        }
        !          1348:        return ((time_t)-1);
        !          1349: }
        !          1350: 

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>