Annotation of embedaddon/mpd/src/contrib/libpdel/http/http_request.c, revision 1.1.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>