Annotation of embedaddon/mpd/src/contrib/libpdel/http/http_response.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/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>