1/* $NetBSD: content-bozo.c,v 1.10 2014/05/17 05:50:01 mrg Exp $ */ 2 3/* $eterna: content-bozo.c,v 1.17 2011/11/18 09:21:15 mrg Exp $ */ 4 5/* 6 * Copyright (c) 1997-2014 Matthew R. Green 7 * All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer and 16 * dedication in the documentation and/or other materials provided 17 * with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 24 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 26 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 27 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 * 31 */ 32 33/* this code implements content-type handling for bozohttpd */ 34 35#include <sys/param.h> 36 37#include <errno.h> 38#include <string.h> 39 40#include "bozohttpd.h" 41 42/* 43 * this map and the functions below map between filenames and the 44 * content type and content encoding definitions. this should become 45 * a configuration file, perhaps like apache's mime.types (but that 46 * has less info per-entry). 47 */ 48 49static bozo_content_map_t static_content_map[] = { 50 { ".html", 5, "text/html", "", "", NULL }, 51 { ".htm", 4, "text/html", "", "", NULL }, 52 { ".gif", 4, "image/gif", "", "", NULL }, 53 { ".jpeg", 5, "image/jpeg", "", "", NULL }, 54 { ".jpg", 4, "image/jpeg", "", "", NULL }, 55 { ".jpe", 4, "image/jpeg", "", "", NULL }, 56 { ".png", 4, "image/png", "", "", NULL }, 57 { ".mp3", 4, "audio/mpeg", "", "", NULL }, 58 { ".css", 4, "text/css", "", "", NULL }, 59 { ".txt", 4, "text/plain", "", "", NULL }, 60 { ".swf", 4, "application/x-shockwave-flash","", "", NULL }, 61 { ".dcr", 4, "application/x-director", "", "", NULL }, 62 { ".pac", 4, "application/x-ns-proxy-autoconfig", "", "", NULL }, 63 { ".pa", 3, "application/x-ns-proxy-autoconfig", "", "", NULL }, 64 { ".tar", 4, "multipart/x-tar", "", "", NULL }, 65 { ".gtar", 5, "multipart/x-gtar", "", "", NULL }, 66 { ".tar.Z", 6, "multipart/x-tar", "x-compress", "compress", NULL }, 67 { ".tar.gz", 7, "multipart/x-tar", "x-gzip", "gzip", NULL }, 68 { ".taz", 4, "multipart/x-tar", "x-gzip", "gzip", NULL }, 69 { ".tgz", 4, "multipart/x-tar", "x-gzip", "gzip", NULL }, 70 { ".tar.z", 6, "multipart/x-tar", "x-pack", "x-pack", NULL }, 71 { ".Z", 2, "application/x-compress", "x-compress", "compress", NULL }, 72 { ".gz", 3, "application/x-gzip", "x-gzip", "gzip", NULL }, 73 { ".z", 2, "unknown", "x-pack", "x-pack", NULL }, 74 { ".bz2", 4, "application/x-bzip2", "x-bzip2", "x-bzip2", NULL }, 75 { ".ogg", 4, "application/x-ogg", "", "", NULL }, 76 { ".mkv", 4, "video/x-matroska", "", "", NULL }, 77 { ".xbel", 5, "text/xml", "", "", NULL }, 78 { ".xml", 4, "text/xml", "", "", NULL }, 79 { ".xsl", 4, "text/xml", "", "", NULL }, 80 { ".hqx", 4, "application/mac-binhex40", "", "", NULL }, 81 { ".cpt", 4, "application/mac-compactpro","", "", NULL }, 82 { ".doc", 4, "application/msword", "", "", NULL }, 83 { ".bin", 4, "application/octet-stream", "", "", NULL }, 84 { ".dms", 4, "application/octet-stream", "", "", NULL }, 85 { ".lha", 4, "application/octet-stream", "", "", NULL }, 86 { ".lzh", 4, "application/octet-stream", "", "", NULL }, 87 { ".exe", 4, "application/octet-stream", "", "", NULL }, 88 { ".class", 6, "application/octet-stream", "", "", NULL }, 89 { ".oda", 4, "application/oda", "", "", NULL }, 90 { ".pdf", 4, "application/pdf", "", "", NULL }, 91 { ".ai", 3, "application/postscript", "", "", NULL }, 92 { ".eps", 4, "application/postscript", "", "", NULL }, 93 { ".ps", 3, "application/postscript", "", "", NULL }, 94 { ".ppt", 4, "application/powerpoint", "", "", NULL }, 95 { ".rtf", 4, "application/rtf", "", "", NULL }, 96 { ".bcpio", 6, "application/x-bcpio", "", "", NULL }, 97 { ".torrent", 8, "application/x-bittorrent", "", "", NULL }, 98 { ".vcd", 4, "application/x-cdlink", "", "", NULL }, 99 { ".cpio", 5, "application/x-cpio", "", "", NULL }, 100 { ".csh", 4, "application/x-csh", "", "", NULL }, 101 { ".dir", 4, "application/x-director", "", "", NULL }, 102 { ".dxr", 4, "application/x-director", "", "", NULL }, 103 { ".dvi", 4, "application/x-dvi", "", "", NULL }, 104 { ".hdf", 4, "application/x-hdf", "", "", NULL }, 105 { ".cgi", 4, "application/x-httpd-cgi", "", "", NULL }, 106 { ".skp", 4, "application/x-koan", "", "", NULL }, 107 { ".skd", 4, "application/x-koan", "", "", NULL }, 108 { ".skt", 4, "application/x-koan", "", "", NULL }, 109 { ".skm", 4, "application/x-koan", "", "", NULL }, 110 { ".latex", 6, "application/x-latex", "", "", NULL }, 111 { ".mif", 4, "application/x-mif", "", "", NULL }, 112 { ".nc", 3, "application/x-netcdf", "", "", NULL }, 113 { ".cdf", 4, "application/x-netcdf", "", "", NULL }, 114 { ".patch", 6, "application/x-patch", "", "", NULL }, 115 { ".sh", 3, "application/x-sh", "", "", NULL }, 116 { ".shar", 5, "application/x-shar", "", "", NULL }, 117 { ".sit", 4, "application/x-stuffit", "", "", NULL }, 118 { ".sv4cpio", 8, "application/x-sv4cpio", "", "", NULL }, 119 { ".sv4crc", 7, "application/x-sv4crc", "", "", NULL }, 120 { ".tar", 4, "application/x-tar", "", "", NULL }, 121 { ".tcl", 4, "application/x-tcl", "", "", NULL }, 122 { ".tex", 4, "application/x-tex", "", "", NULL }, 123 { ".texinfo", 8, "application/x-texinfo", "", "", NULL }, 124 { ".texi", 5, "application/x-texinfo", "", "", NULL }, 125 { ".t", 2, "application/x-troff", "", "", NULL }, 126 { ".tr", 3, "application/x-troff", "", "", NULL }, 127 { ".roff", 5, "application/x-troff", "", "", NULL }, 128 { ".man", 4, "application/x-troff-man", "", "", NULL }, 129 { ".me", 3, "application/x-troff-me", "", "", NULL }, 130 { ".ms", 3, "application/x-troff-ms", "", "", NULL }, 131 { ".ustar", 6, "application/x-ustar", "", "", NULL }, 132 { ".src", 4, "application/x-wais-source", "", "", NULL }, 133 { ".zip", 4, "application/zip", "", "", NULL }, 134 { ".au", 3, "audio/basic", "", "", NULL }, 135 { ".snd", 4, "audio/basic", "", "", NULL }, 136 { ".mpga", 5, "audio/mpeg", "", "", NULL }, 137 { ".mp2", 4, "audio/mpeg", "", "", NULL }, 138 { ".aif", 4, "audio/x-aiff", "", "", NULL }, 139 { ".aiff", 5, "audio/x-aiff", "", "", NULL }, 140 { ".aifc", 5, "audio/x-aiff", "", "", NULL }, 141 { ".ram", 4, "audio/x-pn-realaudio", "", "", NULL }, 142 { ".rpm", 4, "audio/x-pn-realaudio-plugin","", "", NULL }, 143 { ".ra", 3, "audio/x-realaudio", "", "", NULL }, 144 { ".wav", 4, "audio/x-wav", "", "", NULL }, 145 { ".pdb", 4, "chemical/x-pdb", "", "", NULL }, 146 { ".xyz", 4, "chemical/x-pdb", "", "", NULL }, 147 { ".ief", 4, "image/ief", "", "", NULL }, 148 { ".tiff", 5, "image/tiff", "", "", NULL }, 149 { ".tif", 4, "image/tiff", "", "", NULL }, 150 { ".ras", 4, "image/x-cmu-raster", "", "", NULL }, 151 { ".pnm", 4, "image/x-portable-anymap", "", "", NULL }, 152 { ".pbm", 4, "image/x-portable-bitmap", "", "", NULL }, 153 { ".pgm", 4, "image/x-portable-graymap", "", "", NULL }, 154 { ".ppm", 4, "image/x-portable-pixmap", "", "", NULL }, 155 { ".rgb", 4, "image/x-rgb", "", "", NULL }, 156 { ".xbm", 4, "image/x-xbitmap", "", "", NULL }, 157 { ".xpm", 4, "image/x-xpixmap", "", "", NULL }, 158 { ".xwd", 4, "image/x-xwindowdump", "", "", NULL }, 159 { ".rtx", 4, "text/richtext", "", "", NULL }, 160 { ".tsv", 4, "text/tab-separated-values", "", "", NULL }, 161 { ".etx", 4, "text/x-setext", "", "", NULL }, 162 { ".sgml", 5, "text/x-sgml", "", "", NULL }, 163 { ".sgm", 4, "text/x-sgml", "", "", NULL }, 164 { ".mpeg", 5, "video/mpeg", "", "", NULL }, 165 { ".mpg", 4, "video/mpeg", "", "", NULL }, 166 { ".mpe", 4, "video/mpeg", "", "", NULL }, 167 { ".mp4", 4, "video/mp4", "", "", NULL }, 168 { ".qt", 3, "video/quicktime", "", "", NULL }, 169 { ".mov", 4, "video/quicktime", "", "", NULL }, 170 { ".avi", 4, "video/x-msvideo", "", "", NULL }, 171 { ".movie", 6, "video/x-sgi-movie", "", "", NULL }, 172 { ".ice", 4, "x-conference/x-cooltalk", "", "", NULL }, 173 { ".wrl", 4, "x-world/x-vrml", "", "", NULL }, 174 { ".vrml", 5, "x-world/x-vrml", "", "", NULL }, 175 { ".svg", 5, "image/svg+xml", "", "", NULL }, 176 { NULL, 0, NULL, NULL, NULL, NULL } 177}; 178 179static bozo_content_map_t * 180search_map(bozo_content_map_t *map, const char *name, size_t len) 181{ 182 for ( ; map && map->name; map++) { 183 if (map->namelen < len && 184 strcasecmp(map->name, name + (len - map->namelen)) == 0) 185 return map; 186 } 187 return NULL; 188} 189 190/* match a suffix on a file - dynamiconly means no static content search */ 191bozo_content_map_t * 192bozo_match_content_map(bozohttpd_t *httpd, const char *name, 193 const int dynamiconly) 194{ 195 bozo_content_map_t *map; 196 size_t len; 197 198 len = strlen(name); 199 if ((map = search_map(httpd->dynamic_content_map, name, len)) != NULL) { 200 return map; 201 } 202 if (!dynamiconly) { 203 if ((map = search_map(static_content_map, name, len)) != NULL) { 204 return map; 205 } 206 } 207 return NULL; 208} 209 210/* 211 * given the file name, return a valid Content-Type: value. 212 */ 213/* ARGSUSED */ 214const char * 215bozo_content_type(bozo_httpreq_t *request, const char *file) 216{ 217 bozohttpd_t *httpd = request->hr_httpd; 218 bozo_content_map_t *map; 219 220 map = bozo_match_content_map(httpd, file, 0); 221 if (map) 222 return map->type; 223 return httpd->consts.text_plain; 224} 225 226/* 227 * given the file name, return a valid Content-Encoding: value. 228 */ 229const char * 230bozo_content_encoding(bozo_httpreq_t *request, const char *file) 231{ 232 bozohttpd_t *httpd = request->hr_httpd; 233 bozo_content_map_t *map; 234 235 map = bozo_match_content_map(httpd, file, 0); 236 if (map) 237 return (request->hr_proto == httpd->consts.http_11) ? 238 map->encoding11 : map->encoding; 239 return NULL; 240} 241 242#ifndef NO_DYNAMIC_CONTENT 243 244bozo_content_map_t * 245bozo_get_content_map(bozohttpd_t *httpd, const char *name) 246{ 247 bozo_content_map_t *map; 248 249 if ((map = bozo_match_content_map(httpd, name, 1)) != NULL) 250 return map; 251 252 httpd->dynamic_content_map_size++; 253 httpd->dynamic_content_map = bozorealloc(httpd, 254 httpd->dynamic_content_map, 255 (httpd->dynamic_content_map_size + 1) * sizeof *map); 256 if (httpd->dynamic_content_map == NULL) 257 bozo_err(httpd, 1, "out of memory allocating content map"); 258 map = &httpd->dynamic_content_map[httpd->dynamic_content_map_size]; 259 map->name = map->type = map->encoding = map->encoding11 = 260 map->cgihandler = NULL; 261 map->namelen = 0; 262 map--; 263 264 return map; 265} 266 267/* 268 * mime content maps look like: 269 * ".name type encoding encoding11" 270 * where any of type, encoding or encoding11 a dash "-" means "". 271 * eg the .gtar, .tar.Z from above could be written like: 272 * ".gtar multipart/x-gtar - -" 273 * ".tar.Z multipart/x-tar x-compress compress" 274 * or 275 * ".gtar multipart/x-gtar" 276 * ".tar.Z multipart/x-tar x-compress compress" 277 * NOTE: we destroy 'arg' 278 */ 279void 280bozo_add_content_map_mime(bozohttpd_t *httpd, const char *cmap0, 281 const char *cmap1, const char *cmap2, const char *cmap3) 282{ 283 bozo_content_map_t *map; 284 285 debug((httpd, DEBUG_FAT, 286 "add_content_map: name %s type %s enc %s enc11 %s ", 287 cmap0, cmap1, cmap2, cmap3)); 288 289 map = bozo_get_content_map(httpd, cmap0); 290#define CHECKMAP(s) (!s || ((s)[0] == '-' && (s)[1] == '\0') ? "" : (s)) 291 map->name = CHECKMAP(cmap0); 292 map->namelen = strlen(map->name); 293 map->type = CHECKMAP(cmap1); 294 map->encoding = CHECKMAP(cmap2); 295 map->encoding11 = CHECKMAP(cmap3); 296#undef CHECKMAP 297 map->cgihandler = NULL; 298} 299#endif /* NO_DYNAMIC_CONTENT */ 300