1#!/usr/bin/perl -w 2 3# Based on create-mime.assign.pl in debian lighttpd (1.4.x) package 4# Creates an example mime.conf from /etc/mime.types 5 6use strict; 7 8# text/* subtypes to serve as "text/...; charset=utf-8" 9# text/html IS NOT INCLUDED: html has its own method for defining charset 10# (<meta>), but the standards specify that content-type in HTTP wins over 11# the setting in the html document. 12# text/markdown doesn't have an official default charset, but requires 13# one being specified - it seems reasonable to hardcode it to UTF-8 14my %text_utf8 = map { $_ => 1 } qw( 15 css 16 csv 17 markdown 18 plain 19 x-bibtex 20 x-boo 21 x-c++hdr 22 x-c++src 23 x-chdr 24 x-csh 25 x-csrc 26 x-dsrc 27 x-diff 28 x-haskell 29 x-java 30 x-lilypond 31 x-literate-haskell 32 x-makefile 33 x-moc 34 x-pascal 35 x-perl 36 x-python 37 x-scala 38 x-sh 39 x-tcl 40 x-tex 41); 42 43# map extension to hash which maps types to the type they should be replaced with 44my %manual_conflicts_resolve = ( 45 '.ra' => { 46 'audio/x-pn-realaudio' => 'audio/x-realaudio', 47 }, 48 # use font media types from iana registry 49 '.otf' => { 50 'application/font-sfnt' => 'font/ttf', 51 'font/sfnt' => 'font/ttf', 52 'font/ttf' => 'font/ttf', 53 }, 54 '.ttf' => { 55 'application/font-sfnt' => 'font/ttf', 56 'font/otf' => 'font/ttf', 57 'font/sfnt' => 'font/ttf', 58 }, 59 '.woff' => { 60 'application/font-woff' => 'font/woff', 61 }, 62 # end of fonts 63 '.asn' => { 64 'chemical/x-ncbi-asn1-spec' => 'application/octet-stream', 65 }, 66 '.ent' => { 67 'chemical/x-ncbi-asn1-ascii' => 'application/octet-stream', 68 }, 69); 70 71open MIMETYPES, "/etc/mime.types" or die "Can't open /etc/mime.types: $!"; 72 73my %extensions; 74sub set { 75 my ($extension, $mimetype) = @_; 76 $extensions{$extension} = $mimetype; 77} 78sub add { 79 my ($extension, $mimetype) = @_; 80 my $have = $extensions{$extension}; 81 82 my $r = $manual_conflicts_resolve{$extension}; 83 # update @_ too for calls to set 84 $_[1] = $mimetype = $r->{$mimetype} if $r && $r->{$mimetype}; 85 86 # mime.types can have same extension for different mime types 87 if ($have) { 88 # application/octet-stream means we couldn't resolve another conflict 89 return if $have eq $mimetype || $have eq 'application/octet-stream'; 90 91 my ($have_type, $have_subtype) = split /\//, $have, 2; 92 my ($type, $subtype) = split /\//, $mimetype, 2; 93 94 my $have_x = ($have_type =~ /^x-/ || $have_subtype =~ /^x-/); 95 my $x = ($type =~ /^x-/ || $subtype =~ /^x-/); 96 97 # entries without x- prefix in type/subtype win: 98 if ($have_x && !$x) { 99 return set @_; # overwrite 100 } elsif ($x && !$have_x) { 101 return; # ignore 102 } 103 104 # text/ wins over application/ for same subtype 105 if ($subtype eq $have_subtype) { 106 if ($type eq "text" && $have_type eq "application") { 107 return set @_; # overwrite 108 } elsif ($have_type eq "text" && $type eq "application") { 109 return; # ignore 110 } 111 } 112 113 print STDERR "Duplicate mimetype: '${extension}' => '${mimetype}' (already have '${have}'), merging to 'application/octet-stream'\n"; 114 set ($extension, 'application/octet-stream'); 115 } else { 116 set @_; 117 } 118} 119 120sub print_type { 121 my ($extension, $mimetype) = @_; 122 if ($mimetype =~ /^text\/(.*)$/) { 123 $mimetype .= "; charset=utf-8" if $text_utf8{$1}; 124 } 125 126 print "\t\"${extension}\" => \"${mimetype}\",\n"; 127} 128 129while (<MIMETYPES>) { 130 chomp; 131 s/\#.*//; 132 next if /^\w*$/; 133 if (/^([a-z0-9\/+.-]+)\s+((?:[a-z0-9+.-]+[ ]?)+)$/i) { 134 my $mimetype = $1; 135 my @extensions = split / /, $2; 136 137 foreach my $ext (@extensions) { 138 add(".${ext}", $mimetype); 139 } 140 } 141} 142 143# missing in /etc/mime.types; 144# from http://www.iana.org/assignments/media-types/media-types.xhtml 145add(".dtd", "application/xml-dtd"); 146 147# other useful mappings 148my %useful = ( 149 ".tar.gz" => "application/x-gtar-compressed", 150 ".gz" => "application/x-gzip", 151 ".tbz" => "application/x-gtar-compressed", 152 ".tar.bz2" => "application/x-gtar-compressed", 153 ".bz2" => "application/x-bzip", 154 ".log" => "text/plain", 155 ".conf" => "text/plain", 156 ".spec" => "text/plain", 157 "README" => "text/plain", 158 "Makefile" => "text/x-makefile", 159); 160 161while (my ($ext, $mimetype) = each %useful) { 162 add($ext, $mimetype) unless $extensions{$ext}; 163} 164 165 166print <<EOF; 167# created by create-mime.conf.pl 168 169####################################################################### 170## 171## MimeType handling 172## ------------------- 173## 174## https://redmine.lighttpd.net/projects/lighttpd/wiki/Mimetype_assignDetails 175 176## 177## mimetype.xattr-name 178## Set the extended file attribute name used to obtain mime type 179## (must also set mimetype.use-xattr = "enable") 180## 181## Default value is "Content-Type" 182## 183## freedesktop.org Shared MIME-info Database specification suggests 184## user-defined value ("user.mime_type") as name for extended file attribute 185#mimetype.xattr-name = "user.mime_type" 186 187## 188## Use extended attribute named in mimetype.xattr-name (default "Content-Type") 189## to obtain mime type if possible 190## 191## Disabled by default 192## 193#mimetype.use-xattr = "enable" 194 195## 196## mimetype ("Content-Type" HTTP header) mapping for static file handling 197## 198## The first matching suffix is used. If no mapping is found 199## 'application/octet-stream' is used, and caching (etag/last-modified handling) 200## is disabled to prevent clients from caching "unknown" mime types. 201## 202## Therefore the last mapping is: 203## "" => "application/octet-stream" 204## This matches all extensions and acts as default mime type, and enables 205## caching for those. 206mimetype.assign = ( 207EOF 208 209# sort "x-" and "vnd." prefixed names after everything else 210sub mimecmpvalue { 211 my ($mimetype) = @_; 212 $mimetype =~ s/(^|\/)(x-|vnd\.)/~$1$2/g; 213 return $mimetype; 214} 215sub countdots { 216 my ($s) = @_; 217 return scalar(() = $s =~ /\./g); 218} 219# the first matching suffix wins, so we have to sort by "length" 220# as all extensions start with "." we use the number of "."s as length 221# the exceptions are "README" and "Makefile" which are assumed not to conflict 222# (i.e. are not a suffix of any other extension) 223for my $ext (sort { countdots($b) <=> countdots($a) || mimecmpvalue($extensions{$a}) cmp mimecmpvalue($extensions{$b}) || $a cmp $b } keys(%extensions)) { 224 print_type($ext, $extensions{$ext}); 225} 226 227print <<EOF; 228 229 # enable caching for unknown mime types: 230 "" => "application/octet-stream" 231) 232EOF 233