Annotation of embedaddon/libpdel/http/http_message.c, revision 1.1

1.1     ! misho       1: 
        !             2: /*
        !             3:  * Copyright (c) 2001-2002 Packet Design, LLC.
        !             4:  * All rights reserved.
        !             5:  * 
        !             6:  * Subject to the following obligations and disclaimer of warranty,
        !             7:  * use and redistribution of this software, in source or object code
        !             8:  * forms, with or without modifications are expressly permitted by
        !             9:  * Packet Design; provided, however, that:
        !            10:  * 
        !            11:  *    (i)  Any and all reproductions of the source or object code
        !            12:  *         must include the copyright notice above and the following
        !            13:  *         disclaimer of warranties; and
        !            14:  *    (ii) No rights are granted, in any manner or form, to use
        !            15:  *         Packet Design trademarks, including the mark "PACKET DESIGN"
        !            16:  *         on advertising, endorsements, or otherwise except as such
        !            17:  *         appears in the above copyright notice or in the software.
        !            18:  * 
        !            19:  * THIS SOFTWARE IS BEING PROVIDED BY PACKET DESIGN "AS IS", AND
        !            20:  * TO THE MAXIMUM EXTENT PERMITTED BY LAW, PACKET DESIGN MAKES NO
        !            21:  * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING
        !            22:  * THIS SOFTWARE, INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED
        !            23:  * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE,
        !            24:  * OR NON-INFRINGEMENT.  PACKET DESIGN DOES NOT WARRANT, GUARANTEE,
        !            25:  * OR MAKE ANY REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS
        !            26:  * OF THE USE OF THIS SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY,
        !            27:  * RELIABILITY OR OTHERWISE.  IN NO EVENT SHALL PACKET DESIGN BE
        !            28:  * LIABLE FOR ANY DAMAGES RESULTING FROM OR ARISING OUT OF ANY USE
        !            29:  * OF THIS SOFTWARE, INCLUDING WITHOUT LIMITATION, ANY DIRECT,
        !            30:  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, PUNITIVE, OR CONSEQUENTIAL
        !            31:  * DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, LOSS OF
        !            32:  * USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY THEORY OF
        !            33:  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
        !            34:  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
        !            35:  * THE USE OF THIS SOFTWARE, EVEN IF PACKET DESIGN IS ADVISED OF
        !            36:  * THE POSSIBILITY OF SUCH DAMAGE.
        !            37:  *
        !            38:  * Author: Archie Cobbs <archie@freebsd.org>
        !            39:  */
        !            40: 
        !            41: #include <sys/types.h>
        !            42: #include <sys/queue.h>
        !            43: 
        !            44: #include <netinet/in.h>
        !            45: 
        !            46: #include <stdio.h>
        !            47: #include <stdlib.h>
        !            48: #include <stdarg.h>
        !            49: #include <string.h>
        !            50: #include <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);
        !           363:        if (len > msg->input_len - msg->input_read)
        !           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>