Mime-Type configuration for Debian official Mirrors - best practices?
Javier Fernandez-Sanguino <[email protected]>
| Newsgroups | gmane.linux.debian.user.mirrors |
|---|---|
| Message-ID | <CAB9B7Us9B_Lof=c_Hmp0DZ_CVSotxObG3_iU1w=LTBP_VNOKrg@mail.gmail.com> |
Dear mirrors maintainers and colleagues, Are there any best practices for defining the mime-type of Debian mirrors when serving files over HTTP? I have been unable to find any guidance on how to best configure this. This week a user reached out to me, as maintainer of ftp.es.debian.org, asking me why they had to download some files to read them, and could not see in the web browser. This happened for some text files that lack an extension such as the README or the ChangeLog. For these files the web server listed the MIME-type as "application/octet-stream" After reviewing the behaviour of other official mirrors and after fiddling with our setup with lighttpd I ended up adding the attached file to /usr/local/bin/ and changing in lighttpd's conf file, this: include_shell "/usr/share/lighttpd/create-mime.assign.pl" to include_shell "/usr/local/bin/lighttpd-create-mimetypes.conf.pl" The attached Perl script, derived from a script for lighttpd 2, sets the mime types for some of the text filenames that are found in the archive. I opted to do this instead of setting as the default mime-type to "text/plain" to prevent binary files from being sent as text files. If other mirror admins can suggest better or alternative approaches I would be happy to hear about them. Best regards Javier
lighttpd-create-mimetypes.conf.pl
(application/octet-stream, 5.6 KB)
#!/usr/bin/perl -w # Based on create-mime.assign.pl in debian lighttpd (1.4.x) package # Creates an example mimetypes.conf from /etc/mime.types # # URL: https://github.com/lighttpd/lighttpd2/blob/master/contrib/create-mimetypes.conf.pl # Modified for lighttpd 1 by Javier Fernandez-Sanguino <[email protected]> # Also added mime-types for Debian mirrors use strict; my $verbose = 0; # Set to 1 to use verbose mode # text/* subtypes to serve as "text/...; charset=utf-8" # text/html IS NOT INCLUDED: html has its own method for defining charset # (<meta>), but the standards specify that content-type in HTTP wins over # the setting in the html document. my %text_utf8 = map { $_ => 1 } qw( css csv plain x-bibtex x-boo x-c++hdr x-c++src x-chdr x-csh x-csrc x-dsrc x-diff x-haskell x-java x-lilypond x-literate-haskell x-makefile x-moc x-pascal x-perl x-python x-scala x-sh x-tcl x-tex ); # map extension to hash which maps types to the type they should be replaced with my %manual_conflicts_resolve = ( '.ra' => { 'audio/x-pn-realaudio' => 'audio/x-realaudio', }, ); open MIMETYPES, "/etc/mime.types" or die "Can't open mime.types: $!"; my %extensions; sub set { my ($extension, $mimetype) = @_; $extensions{$extension} = $mimetype; } sub add { my ($extension, $mimetype) = @_; my $have = $extensions{$extension}; my $r = $manual_conflicts_resolve{$extension}; # update @_ too for calls to set $_[1] = $mimetype = $r->{$mimetype} if $r && $r->{$mimetype}; # mime.types can have same extension for different mime types if ($have) { # application/octet-stream means we couldn't resolve another conflict return if $have eq $mimetype || $have eq 'application/octet-stream'; my ($have_type, $have_subtype) = split /\//, $have, 2; my ($type, $subtype) = split /\//, $mimetype, 2; my $have_x = ($have_type =~ /^x-/ || $have_subtype =~ /^x-/); my $x = ($type =~ /^x-/ || $subtype =~ /^x-/); # entries without x- prefix in type/subtype win: if ($have_x && !$x) { return set @_; # overwrite } elsif ($x && !$have_x) { return; # ignore } # text/ wins over application/ for same subtype if ($subtype eq $have_subtype) { if ($type eq "text" && $have_type eq "application") { return set @_; # overwrite } elsif ($have_type eq "text" && $type eq "application") { return; # ignore } } print STDERR "Duplicate mimetype: '${extension}' => '${mimetype}' (already have '${have}'), merging to 'application/octet-stream'\n" if $verbose; set ($extension, 'application/octet-stream'); } else { set @_; } } sub print_type { my ($extension, $mimetype) = @_; if ($mimetype =~ /^text\/(.*)$/) { $mimetype .= "; charset=utf-8" if $text_utf8{$1}; } print "\t\t\"${extension}\" => \"${mimetype}\",\n"; } while (<MIMETYPES>) { chomp; s/\#.*//; next if /^\w*$/; if (/^([a-z0-9\/+-.]+)\s+((?:[a-z0-9.+-]+[ ]?)+)$/) { my $mimetype = $1; my @extensions = split / /, $2; foreach my $ext (@extensions) { add(".${ext}", $mimetype); } } } # missing in /etc/mime.types; # from http://www.iana.org/assignments/media-types/media-types.xhtml add(".dtd", "application/xml-dtd"); print <<EOF; # created by /usr/local/bin/lighttpd2-create-mimetypes.conf.pl mimetype.assign = ( # /etc/mime.types #and from http://www.iana.org/assignments/media-types/media-types.xhtml EOF # sort "x-" and "vnd." prefixed names after everything else sub mimecmpvalue { my ($mimetype) = @_; $mimetype =~ s/(^|\/)(x-|vnd\.)/~$1$2/g; return $mimetype; } for my $ext (sort { mimecmpvalue($extensions{$a}) cmp mimecmpvalue($extensions{$b}) || $a cmp $b } keys(%extensions)) { print_type($ext, $extensions{$ext}); } # array instead of hash to keep order as given here my @useful = ( ".tar.gz" , "application/x-gtar-compressed", ".gz" , "application/x-gzip", ".tbz" , "application/x-gtar-compressed", ".tar.bz2" , "application/x-gtar-compressed", ".bz2" , "application/x-bzip", ".log" , "text/plain", ".conf" , "text/plain", ".spec" , "text/plain", "README" , "text/plain", "Makefile" , "text/x-makefile", # Files found in Debian mirrors # Text files "Release" , "text/plain", "InRelease" , "text/plain", "MANIFEST" , "text/plain", "MANIFEST.udebs" , "text/plain", "ChangeLog", "text/plain", "README.CD-manufacture", "text/plain", "udeb.list" , "text/plain", "MD5SUMS" , "text/plain", "SHA256SUMS", "text/plain", "Index" , "text/plain", "config-debian" , "text/plain", ".list" , "text/plain", ".cfg" , "text/plain", ".lst" , "text/plain", ".mod" , "text/plain", # Signed files ".gpg" , "application/pgp-encrypted", ".asc" , "application/pgp-signature", ".pgp" , "application/pgp-encrypted", ".key" , "application/pgp-keys", # Binary files, can be listed easily by running # # find . -type f \! -name "*.*" | xargs file |grep -v ASCII | \ # perl -ne 'print # $1."\n" if /^\..*\/([a-z]+):\s+.*$/' | sort | uniq -c # which, as of June 2014, currently results in # 42 kernel # 60 linux # 8 vmlinux # 180 vmlinuz "kernel" , "application/octec-stream", "linux" , "application/octec-stream", "vmlinux" , "application/octec-stream", "vmlinuz" , "application/octec-stream", ); print <<EOF; # other useful mappings EOF while (my ($ext, $mimetype) = splice(@useful, 0, 2)) { print_type($ext, $mimetype) unless $extensions{$ext}; } print <<EOF; # custom - put your own entries here (overwriting mappings above) ) EOF