Annotation of embedaddon/mpd/src/contrib/libpdel/http/http_message.c, revision 1.1.1.2

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 <pthread.h>
                     51: #include <limits.h>
                     52: #include <syslog.h>
                     53: #include <errno.h>
                     54: #include <ctype.h>
                     55: 
                     56: #include <openssl/ssl.h>
                     57: 
                     58: #include "structs/structs.h"
                     59: #include "structs/type/array.h"
                     60: 
                     61: #include "util/typed_mem.h"
                     62: #include "http/http_defs.h"
                     63: #include "http/http_server.h"
                     64: #include "http/http_internal.h"
                     65: 
                     66: /*
                     67:  * Internal functions
                     68:  */
                     69: static int     http_message_input_read(void *cookie, char *buf, int len);
                     70: static int     http_message_input_close(void *cookie);
                     71: static int     http_message_output_write(void *cookie,
                     72:                        const char *buf, int len);
                     73: static int     http_message_output_close(void *cookie);
                     74: 
                     75: /*********************************************************************
                     76:                        MAIN ROUTINES
                     77: *********************************************************************/
                     78: 
                     79: /*
                     80:  * Create a new message structure.
                     81:  */
                     82: struct http_message *
                     83: _http_message_new(void)
                     84: {
                     85:        struct http_message *msg;
                     86: 
                     87:        if ((msg = MALLOC("http_message", sizeof(*msg))) == NULL)
                     88:                return (NULL);
                     89:        memset(msg, 0, sizeof(*msg));
                     90:        if ((msg->head = _http_head_new()) == NULL) {
                     91:                FREE("http_message", msg);
                     92:                return (NULL);
                     93:        }
                     94:        return (msg);
                     95: }
                     96: 
                     97: /*
                     98:  * Initialize a message by loading in HTTP headers from a stream,
                     99:  * and set msg->input to be the entity input stream.
                    100:  *
                    101:  * This reads any Content-Length header and sets msg->input_len
                    102:  * accordingly, or UINT_MAX if none found. Messages that by definition
                    103:  * have no body must reset msg->input_len to zero.
                    104:  */
                    105: int
                    106: _http_message_read(struct http_message *msg, int req)
                    107: {
                    108:        struct http_connection *const conn = msg->conn;
                    109:        const char *s;
                    110: 
                    111:        /* Slurp in HTTP headers */
                    112:        if (_http_head_read(msg->head, conn->fp, req) == -1)
                    113:                return (-1);
                    114: 
                    115:        /* Get content length, if any */
                    116:        msg->input_len = UINT_MAX;
                    117:        if ((s = _http_head_get(msg->head,
                    118:            HTTP_HEADER_CONTENT_LENGTH)) != NULL) {
                    119:                if (sscanf(s, "%u", &msg->input_len) != 1) {
                    120:                        errno = EINVAL;
                    121:                        return (-1);
                    122:                }
                    123:        }
                    124: 
                    125:        /* Create input stream */
                    126:        if ((msg->input = funopen(msg, http_message_input_read,
                    127:            NULL, NULL, http_message_input_close)) == NULL)
                    128:                return (-1);
                    129: 
                    130:        /* Debugging */
                    131:        if (PDEL_DEBUG_ENABLED(HTTP_HDRS)) {
                    132:                DBG(HTTP_HDRS, "dumping %s headers:",
                    133:                    msg->conn->server ? "REQUEST" : "RESPONSE");
                    134:                _http_head_write(msg->head, stdout);
                    135:        }
                    136: 
                    137:        /* Done */
                    138:        return (0);
                    139: }
                    140: 
                    141: /*
                    142:  * Free a message structure.
                    143:  */
                    144: void
                    145: _http_message_free(struct http_message **msgp)
                    146: {
                    147:        struct http_message *const msg = *msgp;
                    148: 
                    149:        if (msg == NULL)
                    150:                return;
                    151:        _http_head_free(&msg->head);
                    152:        if (msg->input != NULL)
                    153:                fclose(msg->input);
                    154:        if (msg->output != NULL)
                    155:                fclose(msg->output);
                    156:        if (msg->output_buf != NULL)
                    157:                FREE("http_message.output_buf", msg->output_buf);
                    158:        FREE("http_message.query", msg->query);
                    159:        FREE("http_message.host", msg->host);
                    160:        FREE("http_message.path", msg->path);
                    161:        FREE("http_message", msg);
                    162:        *msgp = NULL;
                    163: }
                    164: 
                    165: /*
                    166:  * Get message output stream.
                    167:  *
                    168:  * If "buffer" is true, the entire output will be buffered unless
                    169:  * the headers have already been sent.
                    170:  */
                    171: FILE *
                    172: _http_message_get_output(struct http_message *msg, int buffer)
                    173: {
                    174:        if (msg->output == NULL) {
                    175:                if ((msg->output = funopen(msg, NULL,
                    176:                    http_message_output_write, NULL,
                    177:                    http_message_output_close)) == NULL)
                    178:                        return (NULL);
                    179:                msg->buffered = buffer;
                    180:        }
                    181:        return (msg->output);
                    182: }
                    183: 
                    184: /*
                    185:  * Get raw i/o stream as a file descriptor.
                    186:  */
                    187: int
                    188: _http_message_get_raw_socket(struct http_message *msg)
                    189: {
                    190:        if (msg->conn->ssl != NULL) {
                    191:                errno = EPROTOTYPE;
                    192:                return (-1);
                    193:        }
                    194:        return (msg->conn->sock);
                    195: }
                    196: 
                    197: /*
                    198:  * Send message headers, if not sent already.
                    199:  */
                    200: void
                    201: _http_message_send_headers(struct http_message *msg, int unbuffer)
                    202: {
                    203:        /* Do nothing if nothing to do */
                    204:        if (msg->hdrs_sent)
                    205:                return;
                    206: 
                    207:        /* If we're unbuffering message, turn off buffered flag */
                    208:        if (!msg->buffered)
                    209:                unbuffer = 0;
                    210:        else if (unbuffer) {
                    211:                if (msg->output != NULL)
                    212:                        fflush(msg->output);
                    213:                msg->buffered = 0;
                    214:        }
                    215: 
                    216:        /* In buffered mode, set Content-Length header from buffer length.
                    217:           In non-buffed mode, turn off connection keep-alive. If no body,
                    218:           remove content related headers. */
                    219:        if (msg->no_body) {
                    220:                _http_head_remove(msg->head, HTTP_HEADER_CONTENT_ENCODING);
                    221:                _http_head_remove(msg->head, HTTP_HEADER_CONTENT_LENGTH);
                    222:                _http_head_remove(msg->head, HTTP_HEADER_CONTENT_TYPE);
                    223:                _http_head_remove(msg->head, HTTP_HEADER_LAST_MODIFIED);
                    224:        } else if (msg->buffered) {
                    225:                if (msg->output != NULL)
                    226:                        fflush(msg->output);
                    227:                _http_head_set(msg->head, 0, HTTP_HEADER_CONTENT_LENGTH,
                    228:                    "%u", msg->output_len);
                    229:        } else if (_http_head_get(msg->head,
                    230:            HTTP_HEADER_CONTENT_LENGTH) == NULL) {
                    231:                _http_head_set(msg->head, 0,
                    232:                    _http_message_connection_header(msg), "Close");
                    233:        }
                    234: 
                    235:        /* Debugging */
                    236:        if (PDEL_DEBUG_ENABLED(HTTP_HDRS)) {
                    237:                DBG(HTTP_HDRS, "dumping %s headers:",
                    238:                    msg->conn->server ? "RESPONSE" : "REQUEST");
                    239:                _http_head_write(msg->head, stdout);
                    240:        }
                    241: 
                    242:        /* Send headers */
                    243:        if (!msg->no_headers)
                    244:                _http_head_write(msg->head, msg->conn->fp);
                    245:        msg->hdrs_sent = 1;
                    246: 
                    247:        /* If unbuffering, send and release any output buffered so far */
                    248:        if (unbuffer) {
                    249:                _http_message_send_body(msg);
                    250:                FREE("http_message.output_buf", msg->output_buf);
                    251:                msg->output_buf = NULL;
                    252:                msg->output_len = 0;
                    253:        }
                    254: }
                    255: 
                    256: /*
                    257:  * Send message body.
                    258:  */
                    259: void
                    260: _http_message_send_body(struct http_message *msg)
                    261: {
                    262:        struct http_connection *const conn = msg->conn;
                    263: 
                    264:        /* Flush output stream data */
                    265:        if (msg->output != NULL)
                    266:                fflush(msg->output);
                    267: 
                    268:        /* Send buffered output (if it was buffered) */
                    269:        if (msg->output_buf != NULL) {
                    270:                if (!msg->skip_body)
                    271:                        fwrite(msg->output_buf, 1, msg->output_len, conn->fp);
                    272:                fflush(conn->fp);
                    273:        }
                    274: }
                    275: 
                    276: /*
                    277:  * Set a message header.
                    278:  */
                    279: int
                    280: _http_message_vset_header(struct http_message *msg, int append,
                    281:        const char *name, const char *valfmt, va_list args)
                    282: {
                    283: 
                    284:        /* Check if we already sent the headers */
                    285:        if (msg->hdrs_sent) {
                    286:                errno = EALREADY;
                    287:                return (-1);
                    288:        }
                    289: 
                    290:        /* Set header */
                    291:        return (_http_head_vset(msg->head, append, name, valfmt, args));
                    292: }
                    293: 
                    294: /*
                    295:  * Remove a message header.
                    296:  */
                    297: int
                    298: _http_message_remove_header(struct http_message *msg, const char *name)
                    299: {
                    300:        return (_http_head_remove(msg->head, name));
                    301: }
                    302: 
                    303: /*
                    304:  * Get the "Connection" header name, which will be either "Connection"
                    305:  * or "Proxy-Connection".
                    306:  */
                    307: const char *
                    308: _http_message_connection_header(struct http_message *msg)
                    309: {
                    310:        struct http_connection *const conn = msg->conn;
                    311:        const char *hval;
                    312: 
                    313:        if (!conn->proxy
                    314:            || (hval = _http_head_get(msg->head, conn->server ?
                    315:              HDR_REQUEST_VERSION : HDR_REPLY_VERSION)) == NULL
                    316:            || strcmp(hval, HTTP_PROTO_1_1) >= 0)
                    317:                return (HTTP_HEADER_CONNECTION);
                    318:        return (HTTP_HEADER_PROXY_CONNECTION);
                    319: }
                    320: 
                    321: /*
                    322:  * Get remote IP address.
                    323:  */
                    324: struct in_addr
                    325: _http_message_get_remote_ip(struct http_message *msg)
                    326: {
                    327:        return (msg->conn->remote_ip);
                    328: }
                    329: 
                    330: /*
                    331:  * Get remote port.
                    332:  */
                    333: u_int16_t
                    334: _http_message_get_remote_port(struct http_message *msg)
                    335: {
                    336:        return (msg->conn->remote_port);
                    337: }
                    338: 
                    339: /*
                    340:  * Figure out whether anything is in the message at all.
                    341:  */
                    342: int
                    343: _http_message_has_anything(struct http_message *msg)
                    344: {
                    345:        return (_http_head_has_anything(msg->head));
                    346: }
                    347: 
                    348: /*********************************************************************
                    349:                        INPUT STREAM METHODS
                    350: *********************************************************************/
                    351: 
                    352: /*
                    353:  * Read message input stream.
                    354:  */
                    355: static int
                    356: http_message_input_read(void *cookie, char *buf, int len)
                    357: {
                    358:        struct http_message *const msg = cookie;
                    359:        int ret;
                    360: 
                    361:        if (msg->input_read == msg->input_len || len < 0)
                    362:                return (0);
1.1.1.2 ! misho     363:        if ((unsigned)len > msg->input_len - msg->input_read)
1.1       misho     364:                len = msg->input_len - msg->input_read;
                    365:        if ((ret = fread(buf, 1, len, msg->conn->fp)) != len) {
                    366:                if (ferror(msg->conn->fp))
                    367:                        return (-1);
                    368:        }
                    369:        msg->input_read += ret;
                    370:        return (ret);
                    371: }
                    372: 
                    373: /*
                    374:  * Close message input stream.
                    375:  */
                    376: static int
                    377: http_message_input_close(void *cookie)
                    378: {
                    379:        struct http_message *const msg = cookie;
                    380: 
                    381:        msg->input = NULL;
                    382:        return (0);
                    383: }
                    384: 
                    385: /*********************************************************************
                    386:                        OUTPUT STREAM METHODS
                    387: *********************************************************************/
                    388: 
                    389: /*
                    390:  * Write to message output stream.
                    391:  */
                    392: static int
                    393: http_message_output_write(void *cookie, const char *buf, int len)
                    394: {
                    395:        struct http_message *const msg = cookie;
                    396:        struct http_connection *const conn = msg->conn;
                    397:        int totlen;
                    398:        int ret;
                    399:        void *mem;
                    400: 
                    401:        /* Ignore zero length writes */
                    402:        if (len == 0)
                    403:                return (0);
                    404: 
                    405:        /* Check whether to allow an entity body at all */
                    406:        if (msg->no_body) {
                    407:                errno = EINVAL;
                    408:                return (-1);
                    409:        }
                    410: 
                    411:        /* If not buffered, check if headers have been sent then write data */
                    412:        if (!msg->buffered) {
                    413:                if (!msg->hdrs_sent)
                    414:                        _http_message_send_headers(msg, 0);
                    415:                if (msg->skip_body)
                    416:                        return (len);
                    417:                if ((ret = fwrite(buf, 1, len, conn->fp)) != len)
                    418:                        return (-1);
                    419:                return (ret);
                    420:        }
                    421: 
                    422:        /* Expand buffer and write data into it */
                    423:        totlen = msg->output_len + len;
                    424:        if ((mem = REALLOC("http_message.output_buf",
                    425:            msg->output_buf, totlen)) == NULL) {
                    426:                (*conn->logger)(LOG_ERR, "%s: %s", "realloc", strerror(errno));
                    427:                return (-1);
                    428:        }
                    429:        msg->output_buf = mem;
                    430:        memcpy(msg->output_buf + msg->output_len, buf, len);
                    431:        msg->output_len += len;
                    432:        return (len);
                    433: }
                    434: 
                    435: /*
                    436:  * Close message output stream.
                    437:  */
                    438: static int
                    439: http_message_output_close(void *cookie)
                    440: {
                    441:        struct http_message *const msg = cookie;
                    442: 
                    443:        msg->output = NULL;
                    444:        return (0);
                    445: }
                    446: 

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