Annotation of embedaddon/libpdel/http/http_response.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/param.h>
                     43: #include <sys/queue.h>
                     44: 
                     45: #include <netinet/in.h>
                     46: 
                     47: #include <stdio.h>
                     48: #include <stdlib.h>
                     49: #include <stdarg.h>
                     50: #include <string.h>
                     51: #include <pthread.h>
                     52: #include <limits.h>
                     53: #include <ctype.h>
                     54: #include <syslog.h>
                     55: #include <errno.h>
                     56: #include <assert.h>
                     57: 
                     58: #include <openssl/ssl.h>
                     59: 
                     60: #include "structs/structs.h"
                     61: #include "structs/type/array.h"
                     62: 
                     63: #include "http/http_defs.h"
                     64: #include "http/http_server.h"
                     65: #include "http/http_internal.h"
                     66: #include "util/typed_mem.h"
                     67: 
                     68: struct suffix_map {
                     69:        const char      *suffix;
                     70:        const char      *mime;
                     71: };
                     72: 
                     73: /* error responses */
                     74: #define MALFORMED_RESPONSE_MSG "Malformed response"
                     75: #define TIMEOUT_RESPONSE_MSG   "Server timed out"
                     76: 
                     77: /*
                     78:  * Internal functions
                     79:  */
                     80: static int     suffix_cmp(const void *v1, const void *v2);
                     81: 
                     82: /* Filename suffix -> MIME encoding (list is sorted case insensitively) */
                     83: static const struct suffix_map mime_encodings[] = {
                     84:        { "gz",         "gzip" },
                     85:        { "uu",         "x-uuencode" },
                     86:        { "Z",          "compress" },
                     87: };
                     88: static const int num_mime_encodings
                     89:                    = sizeof(mime_encodings) / sizeof(*mime_encodings);
                     90: 
                     91: /* Filename suffix -> MIME type (list is sorted case insensitively) */
                     92: static const struct suffix_map mime_types[] = {
                     93:        { "a",          "application/octet-stream" },
                     94:        { "aab",        "application/x-authorware-bin" },
                     95:        { "aam",        "application/x-authorware-map" },
                     96:        { "aas",        "application/x-authorware-seg" },
                     97:        { "ai",         "application/postscript" },
                     98:        { "aif",        "audio/x-aiff" },
                     99:        { "aifc",       "audio/x-aiff" },
                    100:        { "aiff",       "audio/x-aiff" },
                    101:        { "au",         "audio/basic" },
                    102:        { "avi",        "video/x-msvideo" },
                    103:        { "bcpio",      "application/x-bcpio" },
                    104:        { "bin",        "application/octet-stream" },
                    105:        { "cdf",        "application/x-netcdf" },
                    106:        { "class",      "application/java" },
                    107:        { "cpio",       "application/x-cpio" },
                    108:        { "css",        "text/css" },
                    109:        { "dcr",        "application/x-director" },
                    110:        { "dir",        "application/x-director" },
                    111:        { "doc",        "application/msword" },
                    112:        { "dtd",        "text/xml" },
                    113:        { "dump",       "application/octet-stream" },
                    114:        { "dvi",        "application/x-dvi" },
                    115:        { "dxr",        "application/x-director" },
                    116:        { "eps",        "application/postscript" },
                    117:        { "etx",        "text/x-setext" },
                    118:        { "exe",        "application/octet-stream" },
                    119:        { "fgd",        "application/x-director" },
                    120:        { "fh",         "image/x-freehand" },
                    121:        { "fh4",        "image/x-freehand" },
                    122:        { "fh5",        "image/x-freehand" },
                    123:        { "fh7",        "image/x-freehand" },
                    124:        { "fhc",        "image/x-freehand" },
                    125:        { "gif",        "image/gif" },
                    126:        { "gtar",       "application/x-gtar" },
                    127:        { "hdf",        "application/x-hdf" },
                    128:        { "hqx",        "application/mac-binhex40" },
                    129:        { "htm",        "text/html" },
                    130:        { "html",       "text/html" },
                    131:        { "ief",        "image/ief" },
                    132:        { "iv",         "application/x-inventor" },
                    133:        { "jfif",       "image/jpeg" },
                    134:        { "jpe",        "image/jpeg" },
                    135:        { "jpeg",       "image/jpeg" },
                    136:        { "jpg",        "image/jpeg" },
                    137:        { "js",         "application/x-javascript" },
                    138:        { "kar",        "audio/midi" },
                    139:        { "latex",      "application/x-latex" },
                    140:        { "man",        "application/x-troff-man" },
                    141:        { "man",        "application/x-troff-man" },
                    142:        { "me",         "application/x-troff-me" },
                    143:        { "me",         "application/x-troff-me" },
                    144:        { "mid",        "audio/midi" },
                    145:        { "midi",       "audio/midi" },
                    146:        { "mif",        "application/x-mif" },
                    147:        { "mime",       "message/rfc822" },
                    148:        { "mmf",        "application/x-www-urlformencoded" },
                    149:        { "mov",        "video/quicktime" },
                    150:        { "movie",      "video/x-sgi-movie" },
                    151:        { "mp2",        "audio/mpeg" },
                    152:        { "mp3",        "audio/mpeg" },
                    153:        { "mpe",        "video/mpeg" },
                    154:        { "mpeg",       "video/mpeg" },
                    155:        { "mpg",        "video/mpeg" },
                    156:        { "mpga",       "audio/mpeg" },
                    157:        { "ms",         "application/x-troff-ms" },
                    158:        { "ms",         "application/x-troff-ms" },
                    159:        { "mv",         "video/x-sgi-movie" },
                    160:        { "nc",         "application/x-netcdf" },
                    161:        { "o",          "application/octet-stream" },
                    162:        { "oda",        "application/oda" },
                    163:        { "pac",        "application/x-ns-proxy-autoconfig" },
                    164:        { "pbm",        "image/x-portable-bitmap" },
                    165:        { "pdf",        "application/pdf" },
                    166:        { "pgm",        "image/x-portable-graymap" },
                    167:        { "png",        "image/png" },
                    168:        { "pnm",        "image/x-portable-anymap" },
                    169:        { "ppm",        "image/x-portable-pixmap" },
                    170:        { "ppt",        "application/powerpoint" },
                    171:        { "ps",         "application/postscript" },
                    172:        { "qt",         "video/quicktime" },
                    173:        { "ra",         "audio/x-pn-realaudio" },
                    174:        { "ram",        "audio/x-pn-realaudio" },
                    175:        { "rm",         "audio/x-pn-realaudio" },
                    176:        { "roff",       "application/x-troff" },
                    177:        { "rpm",        "audio/x-pn-realaudio-plugin" },
                    178:        { "rtf",        "application/rtf" },
                    179:        { "rtx",        "text/richtext" },
                    180:        { "sh",         "application/x-shar" },
                    181:        { "shar",       "application/x-shar" },
                    182:        { "sit",        "application/x-stuffit" },
                    183:        { "snd",        "audio/basic" },
                    184:        { "spl",        "application/futuresplash" },
                    185:        { "sv4cpio",    "application/x-sv4cpio" },
                    186:        { "sv4crc",     "application/x-sv4crc" },
                    187:        { "swf",        "application/x-shockwave-flash" },
                    188:        { "tar",        "application/x-tar" },
                    189:        { "tex",        "application/x-tex" },
                    190:        { "texi",       "application/x-texinfo" },
                    191:        { "texinfo",    "application/x-texinfo" },
                    192:        { "tif",        "image/tiff" },
                    193:        { "tiff",       "image/tiff" },
                    194:        { "tmpl",       "text/plain" },         /* template file input */
                    195:        { "tr",         "application/x-troff" },
                    196:        { "tsp",        "application/dsptype" },
                    197:        { "tsv",        "text/tab-separated-values" },
                    198:        { "txt",        "text/plain" },
                    199:        { "ustar",      "application/x-ustar" },
                    200:        { "vrml",       "model/vrml" },
                    201:        { "vx",         "video/x-rad-screenplay" },
                    202:        { "wav",        "audio/wav" },
                    203:        { "wbmp",       "image/vnd.wap.wbmp" },
                    204:        { "wml",        "text/vnd.wap.wml" },
                    205:        { "wmlc",       "application/vnd.wap.wmlc" },
                    206:        { "wmls",       "text/vnd.wap.wmlscript" },
                    207:        { "wmlsc",      "application/vnd.wap.wmlscriptc" },
                    208:        { "wrl",        "model/vrml" },
                    209:        { "wsrc",       "application/x-wais-source" },
                    210:        { "xbm",        "image/x-xbitmap" },
                    211:        { "xml",        "text/xml" },
                    212:        { "xpm",        "image/x-xpixmap" },
                    213:        { "xwd",        "image/x-xwindowdump" },
                    214:        { "zip",        "application/x-zip-compressed" },
                    215: };
                    216: static const int num_mime_types = sizeof(mime_types) / sizeof(*mime_types);
                    217: 
                    218: /*********************************************************************
                    219:                        MAIN ROUTINES
                    220: *********************************************************************/
                    221: 
                    222: /*
                    223:  * Create a new response structure.
                    224:  */
                    225: int
                    226: _http_response_new(struct http_connection *conn)
                    227: {
                    228:        struct http_response *resp;
                    229: 
                    230:        /* Create response structure */
                    231:        assert(conn->resp == NULL);
                    232:        if ((resp = MALLOC("http_response", sizeof(*resp))) == NULL) {
                    233:                (*conn->logger)(LOG_ERR, "%s: %s", "malloc", strerror(errno));
                    234:                return (-1);
                    235:        }
                    236:        memset(resp, 0, sizeof(*resp));
                    237: 
                    238:        /* Attach message structure */
                    239:        if ((resp->msg = _http_message_new()) == NULL) {
                    240:                (*conn->logger)(LOG_ERR, "%s: %s", "malloc", strerror(errno));
                    241:                FREE("http_response", resp);
                    242:                return (-1);
                    243:        }
                    244: 
                    245:        /* Link it up */
                    246:        resp->msg->conn = conn;
                    247:        conn->resp = resp;
                    248:        return (0);
                    249: }
                    250: 
                    251: /*
                    252:  * Read in, validate, and prep an HTTP response from a connection.
                    253:  *
                    254:  * In all cases, fill in the error message buffer.
                    255:  */
                    256: int
                    257: _http_response_read(struct http_connection *conn, char *errbuf, int size)
                    258: {
                    259:        struct http_response *const resp = conn->resp;
                    260:        const char *hval;
                    261: 
                    262:        /* Load in message from HTTP connection */
                    263:        if (_http_message_read(resp->msg, 0) == -1) {
                    264:                switch (errno) {
                    265:                case EINVAL:
                    266:                        strlcpy(errbuf, MALFORMED_RESPONSE_MSG, size);
                    267:                        break;
                    268: 
                    269:                case ETIMEDOUT:
                    270:                        strlcpy(errbuf, TIMEOUT_RESPONSE_MSG, size);
                    271:                        break;
                    272: 
                    273:                default:
                    274:                        strlcpy(errbuf, strerror(errno), size);
                    275:                        break;
                    276:                }
                    277: 
                    278:                /* fix errno now that we've used it */
                    279:                conn->keep_alive = 0;
                    280:                errno = EINVAL;
                    281:                return (-1);
                    282:        }
                    283: 
                    284:        /* Set code */
                    285:        hval = http_response_get_header(resp, HDR_REPLY_STATUS);
                    286:        if (sscanf(hval, "%u", &resp->code) != 1) {
                    287:                snprintf(errbuf, size, "Invalid response code ``%s''", hval);
                    288:                conn->keep_alive = 0;
                    289:                errno = EINVAL;
                    290:                return (-1);
                    291:        }
                    292: 
                    293:        /* Expect no body from certain responses */
                    294:        if (http_response_no_body(resp->code)) {
                    295:                resp->msg->input_len = 0;
                    296:                resp->msg->no_body = 1;
                    297:        } else if (resp->msg->input_len == UINT_MAX
                    298:            && _http_head_want_keepalive(resp->msg->head)) {
                    299:                snprintf(errbuf, size,
                    300:                    "Keep-Alive requres %s", HTTP_HEADER_CONTENT_LENGTH);
                    301:                conn->keep_alive = 0;
                    302:                errno = EINVAL;
                    303:                return (-1);
                    304:        }
                    305: 
                    306:        /* Turn off keep alive if not specified by remote side */
                    307:        if (!_http_head_want_keepalive(resp->msg->head))
                    308:                conn->keep_alive = 0;
                    309: 
                    310:        /* Done */
                    311:        strlcpy(errbuf, http_response_get_header(resp, HDR_REPLY_REASON), size);
                    312:        return (0);
                    313: }
                    314: 
                    315: /*
                    316:  * Free a response
                    317:  */
                    318: void
                    319: _http_response_free(struct http_response **respp)
                    320: {
                    321:        struct http_response *const resp = *respp;
                    322: 
                    323:        if (resp == NULL)
                    324:                return;
                    325:        _http_message_free(&resp->msg);
                    326:        FREE("http_response", resp);
                    327:        *respp = NULL;
                    328: }
                    329: 
                    330: /*
                    331:  * Get response code.
                    332:  */
                    333: int
                    334: http_response_get_code(struct http_response *resp)
                    335: {
                    336:        return (resp->code);
                    337: }
                    338: 
                    339: /*********************************************************************
                    340:                        MESSAGE WRAPPERS
                    341: *********************************************************************/
                    342: 
                    343: /*
                    344:  * Set a response header.
                    345:  */
                    346: int
                    347: http_response_set_header(struct http_response *resp, int append,
                    348:        const char *name, const char *valfmt, ...)
                    349: {
                    350:        va_list args;
                    351:        int ret;
                    352: 
                    353:        /* Set header */
                    354:        va_start(args, valfmt);
                    355:        ret = _http_message_vset_header(resp->msg, append, name, valfmt, args);
                    356:        va_end(args);
                    357:        if (ret == -1)
                    358:                return (-1);
                    359: 
                    360:        /* Remember response code */
                    361:        if (name == HDR_REPLY_STATUS) {
                    362:                resp->code = atoi(http_response_get_header(resp, name));
                    363:                resp->msg->no_body = http_response_no_body(resp->code);
                    364:        }
                    365: 
                    366:        /* Done */
                    367:        return (0);
                    368: }
                    369: 
                    370: /*
                    371:  * Get a response header.
                    372:  *
                    373:  * For headers listed multiple times, this only gets the first instance.
                    374:  */
                    375: const char *
                    376: http_response_get_header(struct http_response *resp, const char *name)
                    377: {
                    378:        return (_http_head_get(resp->msg->head, name));
                    379: }
                    380: 
                    381: /*
                    382:  * Get the number of headers
                    383:  */
                    384: int
                    385: http_response_num_headers(struct http_response *resp)
                    386: {
                    387:        return (_http_head_num_headers(resp->msg->head));
                    388: }
                    389: 
                    390: /*
                    391:  * Get header by index.
                    392:  */
                    393: int
                    394: http_response_get_header_by_index(struct http_response *resp,
                    395:        u_int index, const char **namep, const char **valuep)
                    396: {
                    397:        return (_http_head_get_by_index(resp->msg->head, index, namep, valuep));
                    398: }
                    399: 
                    400: /*
                    401:  * Remove a header.
                    402:  */
                    403: int
                    404: http_response_remove_header(struct http_response *resp, const char *name)
                    405: {
                    406:        return (_http_message_remove_header(resp->msg, name));
                    407: }
                    408: 
                    409: /*
                    410:  * Send response headers, if not sent already.
                    411:  */
                    412: int
                    413: http_response_send_headers(struct http_response *resp, int unbuffer)
                    414: {
                    415:        _http_message_send_headers(resp->msg, unbuffer);
                    416:        return (0);
                    417: }
                    418: 
                    419: /*
                    420:  * Get response input stream.
                    421:  */
                    422: FILE *
                    423: http_response_get_input(struct http_response *resp)
                    424: {
                    425:        if (resp->msg->conn->server) {
                    426:                errno = EINVAL;
                    427:                return (NULL);
                    428:        }
                    429:        return (resp->msg->input);
                    430: }
                    431: 
                    432: /*
                    433:  * Get response output stream.
                    434:  */
                    435: FILE *
                    436: http_response_get_output(struct http_response *resp, int buffer)
                    437: {
                    438:        if (!resp->msg->conn->server) {
                    439:                errno = EINVAL;
                    440:                return (NULL);
                    441:        }
                    442:        return (_http_message_get_output(resp->msg, buffer));
                    443: }
                    444: 
                    445: /*
                    446:  * Get raw i/o stream as a file descriptor.
                    447:  */
                    448: int
                    449: http_response_get_raw_socket(struct http_response *resp)
                    450: {
                    451:        return (_http_message_get_raw_socket(resp->msg));
                    452: }
                    453: 
                    454: /*
                    455:  * Get remote IP address.
                    456:  */
                    457: struct in_addr
                    458: http_response_get_remote_ip(struct http_response *resp)
                    459: {
                    460:        return (_http_message_get_remote_ip(resp->msg));
                    461: }
                    462: 
                    463: /*
                    464:  * Get remote port.
                    465:  */
                    466: u_int16_t
                    467: http_response_get_remote_port(struct http_response *resp)
                    468: {
                    469:        return (_http_message_get_remote_port(resp->msg));
                    470: }
                    471: 
                    472: /*
                    473:  * Get SSL context.
                    474:  */
                    475: SSL_CTX *
                    476: http_response_get_ssl(struct http_response *resp)
                    477: {
                    478:        return (resp->msg->conn->ssl);
                    479: }
                    480: 
                    481: /*********************************************************************
                    482:                        SERVLET HELPERS
                    483: *********************************************************************/
                    484: 
                    485: /*
                    486:  * Send an HTTP redirect.
                    487:  */
                    488: void
                    489: http_response_send_redirect(struct http_response *resp, const char *url)
                    490: {
                    491:        const char *name;
                    492:        const char *value;
                    493: 
                    494:        while (_http_head_get_by_index(resp->msg->head, 0, &name, &value) == 0)
                    495:                _http_head_remove(resp->msg->head, name);
                    496:        http_response_set_header(resp, 0, HDR_REPLY_STATUS,
                    497:              "%d", HTTP_STATUS_MOVED_PERMANENTLY);
                    498:        http_response_set_header(resp, 0, HDR_REPLY_REASON,
                    499:              "%s", http_response_status_msg(HTTP_STATUS_MOVED_PERMANENTLY));
                    500:        http_response_set_header(resp, 0, "Location", "%s", url);
                    501: }
                    502: 
                    503: /*
                    504:  * Send an HTTP authorization failed response.
                    505:  */
                    506: void
                    507: http_response_send_basic_auth(struct http_response *resp, const char *realm)
                    508: {
                    509:        http_response_set_header(resp, 0, HTTP_HEADER_WWW_AUTHENTICATE,
                    510:            "Basic realm=\"%s\"", realm);
                    511:        _http_head_remove(resp->msg->head, HTTP_HEADER_LAST_MODIFIED);
                    512:        http_response_send_error(resp, HTTP_STATUS_UNAUTHORIZED, NULL);
                    513: }
                    514: 
                    515: /*
                    516:  * Convert 'errno' into an HTTP error response.
                    517:  */
                    518: void
                    519: http_response_send_errno_error(struct http_response *resp)
                    520: {
                    521:        int code;
                    522: 
                    523:        switch (errno) {
                    524:        case ENOENT:
                    525:        case ENOTDIR:
                    526:                code = HTTP_STATUS_NOT_FOUND;
                    527:                break;
                    528:        case EPERM:
                    529:        case EACCES:
                    530:                code = HTTP_STATUS_FORBIDDEN;
                    531:                break;
                    532:        default:
                    533:                code = HTTP_STATUS_INTERNAL_SERVER_ERROR;
                    534:                break;
                    535:        }
                    536:        http_response_send_error(resp, code, "%s", strerror(errno));
                    537: }
                    538: 
                    539: /*
                    540:  * Send back a simple error page
                    541:  */
                    542: void
                    543: http_response_send_error(struct http_response *resp,
                    544:        int code, const char *fmt, ...)
                    545: {
                    546:        struct http_request *const req = resp->msg->conn->req;
                    547:        const char *ua;
                    548:        FILE *fp;
                    549:        int i;
                    550: 
                    551:        /* Check headers already sent */
                    552:        if (resp->msg->hdrs_sent)
                    553:                return;
                    554: 
                    555:        /* Set response line info */
                    556:        http_response_set_header(resp, 0, HDR_REPLY_STATUS, "%d", code);
                    557:        http_response_set_header(resp, 0, HDR_REPLY_REASON,
                    558:              "%s", http_response_status_msg(code));
                    559: 
                    560:        /* Set additional headers */
                    561:        http_response_set_header(resp, 0, HTTP_HEADER_CONTENT_TYPE,
                    562:                "text/html; charset=iso-8859-1");
                    563: 
                    564:        /* Close connection for real errors */
                    565:        if (code >= 400) {
                    566:                http_response_set_header(resp,
                    567:                    0, _http_message_connection_header(resp->msg), "close");
                    568:        }
                    569: 
                    570:        /* Send error page body */
                    571:        if ((fp = http_response_get_output(resp, 1)) == NULL)
                    572:                return;
                    573:        fprintf(fp, "<HTML>\n<HEAD>\n<TITLE>%d %s</TITLE></HEAD>\n",
                    574:            code, http_response_status_msg(code));
                    575:        fprintf(fp, "<BODY BGCOLOR=\"#FFFFFF\">\n<H3>%d %s</H3>\n",
                    576:            code, http_response_status_msg(code));
                    577:        if (fmt != NULL) {
                    578:                va_list args;
                    579: 
                    580:                fprintf(fp, "<B>");
                    581:                va_start(args, fmt);
                    582:                vfprintf(fp, fmt, args);
                    583:                va_end(args);
                    584:                fprintf(fp, "</B>\n");
                    585:        }
                    586: #if 0
                    587:        fprintf(fp, "<P></P>\n<HR>\n");
                    588:        fprintf(fp, "<FONT SIZE=\"-1\"><EM>%s</EM></FONT>\n",
                    589:            serv->server_name);
                    590: #endif
                    591: 
                    592:        /* Add fillter for IE */
                    593:        if ((ua = http_request_get_header(req, HTTP_HEADER_USER_AGENT)) != NULL
                    594:            && strstr(ua, "IE") != NULL) {
                    595:                for (i = 0; i < 20; i++) {
                    596:                        fprintf(fp, "<!-- FILLER TO MAKE INTERNET EXPLORER SHOW"
                    597:                            " THIS PAGE INSTEAD OF ITS OWN PAGE -->\n");
                    598:                }
                    599:        }
                    600:        fprintf(fp, "</BODY>\n</HTML>\n");
                    601: }
                    602: 
                    603: /*
                    604:  * Try to guess MIME type and encoding from filename suffix.
                    605:  */
                    606: void
                    607: http_response_guess_mime(const char *path,
                    608:        const char **ctype, const char **cencs, int maxencs)
                    609: {
                    610:        static char buf[MAXPATHLEN];
                    611:        struct suffix_map *mime;
                    612:        int matched_ctype = -1;
                    613:        struct suffix_map key;
                    614:        const char *slash;
                    615:        char *tokctx;
                    616:        char *s;
                    617:        int i;
                    618: 
                    619:        /* Set defaults */
                    620:        *ctype = "text/plain; charset=iso-8859-1";
                    621:        memset(cencs, 0, maxencs * sizeof(*cencs));
                    622: 
                    623:        /* Strip directories */
                    624:        if ((slash = strrchr(path, '/')) != NULL)
                    625:                path = slash + 1;
                    626:        strlcpy(buf, path, sizeof(buf));
                    627: 
                    628:        /* Search for suffixes matching MIME types table entry */
                    629:        for (i = 0, s = strtok_r(buf, ".", &tokctx);
                    630:            s != NULL; i++, s = strtok_r(NULL, ".", &tokctx)) {
                    631:                key.suffix = s;
                    632:                if ((mime = bsearch(&key, mime_types, num_mime_types,
                    633:                    sizeof(*mime_types), suffix_cmp)) != NULL) {
                    634:                        *ctype = mime->mime;
                    635:                        matched_ctype = i;
                    636:                }
                    637:        }
                    638:        if (matched_ctype == -1)
                    639:                return;
                    640: 
                    641:        /* Skip to the suffix after the last MIME type suffix */
                    642:        for (i = 0, s = strtok_r(buf, ".", &tokctx);
                    643:            i <= matched_ctype; i++, s = strtok_r(NULL, ".", &tokctx));
                    644: 
                    645:        /* Get encoding(s) */
                    646:        for (i = 0; i < maxencs - 1
                    647:            && (s = strtok_r(NULL, ".", &tokctx)) != NULL; i++) {
                    648:                key.suffix = s;
                    649:                if ((mime = bsearch(&key, mime_encodings, num_mime_encodings,
                    650:                    sizeof(*mime_encodings), suffix_cmp)) == NULL)
                    651:                        break;
                    652:                cencs[i] = mime->mime;
                    653:        }
                    654: }
                    655: 
                    656: /*
                    657:  * Compare two entries in MIME type/encoding array
                    658:  */
                    659: static int
                    660: suffix_cmp(const void *v1, const void *v2)
                    661: {
                    662:        const struct suffix_map *const map1 = v1;
                    663:        const struct suffix_map *const map2 = v2;
                    664: 
                    665:        return (strcasecmp(map1->suffix, map2->suffix));
                    666: }
                    667: 
                    668: /*********************************************************************
                    669:                        MISC ROUTINES
                    670: *********************************************************************/
                    671: 
                    672: /*
                    673:  * Certain response codes are required to not have any body.
                    674:  */
                    675: int
                    676: http_response_no_body(int code)
                    677: {
                    678:        switch (code) {
                    679:        case HTTP_STATUS_NO_CONTENT:
                    680:        case HTTP_STATUS_NOT_MODIFIED:
                    681:                return (1);
                    682:        }
                    683:        return (0);
                    684: }
                    685: 

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