@@ -6,7 +6,9 @@ module Network.Wai.Application.Static
7 , defaultMimeType
7 , defaultMimeType
8 -- ** Mime type by file extension
8 -- ** Mime type by file extension
10 , defaultMimeTypes
12 , defaultMimeTypes
11 , mimeTypeByExt
13 , mimeTypeByExt
12 , defaultMimeTypeByExt
14 , defaultMimeTypeByExt
@@ -22,8 +24,6 @@ import qualified Network.Wai as W
22import Data.Map (Map)
24import Data.Map (Map)
23import qualified Data.Map as Map
25import qualified Data.Map as Map
24import Data.ByteString (ByteString)
26import Data.ByteString (ByteString)
25−import System.FilePath (takeExtensions)
26−import Data.Maybe (fromMaybe)
27import System.Directory (doesFileExist, doesDirectoryExist)
27import System.Directory (doesFileExist, doesDirectoryExist)
28import qualified Data.ByteString.Char8 as S8
28import qualified Data.ByteString.Char8 as S8
29import qualified Data.ByteString.Lazy as L
29import qualified Data.ByteString.Lazy as L
@@ -32,8 +32,16 @@ import Web.Routes.Base (decodePathInfo, encodePathInfo)
32import System.PosixCompat.Files (fileSize, getFileStatus)
32import System.PosixCompat.Files (fileSize, getFileStatus)
33import Control.Monad.IO.Class (liftIO)
33import Control.Monad.IO.Class (liftIO)
35+-- | A list of all possible extensions, starting from the largest.
36+takeExtensions :: FilePath -> [String]
38+ case break (== '.') s of
39+ (_, '.':x) -> x : takeExtensions x
35type MimeType = ByteString
42type MimeType = ByteString
43+type Extension = String
36−type MimeMap = Map FilePath MimeType
44+type MimeMap = Map Extension MimeType
38defaultMimeType :: MimeType
46defaultMimeType :: MimeType
39defaultMimeType = "application/octet-stream"
47defaultMimeType = "application/octet-stream"
@@ -41,67 +49,74 @@ defaultMimeType = "application/octet-stream"
41-- taken from snap-core Snap.Util.FileServer
49-- taken from snap-core Snap.Util.FileServer
42defaultMimeTypes :: MimeMap
50defaultMimeTypes :: MimeMap
43defaultMimeTypes = Map.fromList [
51defaultMimeTypes = Map.fromList [
44− ( ".asc" , "text/plain" ),
52+ ( "asc" , "text/plain" ),
45− ( ".asf" , "video/x-ms-asf" ),
53+ ( "asf" , "video/x-ms-asf" ),
46− ( ".asx" , "video/x-ms-asf" ),
54+ ( "asx" , "video/x-ms-asf" ),
47− ( ".avi" , "video/x-msvideo" ),
55+ ( "avi" , "video/x-msvideo" ),
48− ( ".bz2" , "application/x-bzip" ),
56+ ( "bz2" , "application/x-bzip" ),
49− ( ".c" , "text/plain" ),
57+ ( "c" , "text/plain" ),
50− ( ".class" , "application/octet-stream" ),
58+ ( "class" , "application/octet-stream" ),
51− ( ".conf" , "text/plain" ),
59+ ( "conf" , "text/plain" ),
52− ( ".cpp" , "text/plain" ),
60+ ( "cpp" , "text/plain" ),
53− ( ".css" , "text/css" ),
61+ ( "css" , "text/css" ),
54− ( ".cxx" , "text/plain" ),
62+ ( "cxx" , "text/plain" ),
55− ( ".dtd" , "text/xml" ),
63+ ( "dtd" , "text/xml" ),
56− ( ".dvi" , "application/x-dvi" ),
64+ ( "dvi" , "application/x-dvi" ),
57− ( ".gif" , "image/gif" ),
65+ ( "gif" , "image/gif" ),
58− ( ".gz" , "application/x-gzip" ),
66+ ( "gz" , "application/x-gzip" ),
59− ( ".hs" , "text/plain" ),
67+ ( "hs" , "text/plain" ),
60− ( ".htm" , "text/html" ),
68+ ( "htm" , "text/html" ),
61− ( ".html" , "text/html" ),
69+ ( "html" , "text/html" ),
62− ( ".jar" , "application/x-java-archive" ),
70+ ( "jar" , "application/x-java-archive" ),
63− ( ".jpeg" , "image/jpeg" ),
71+ ( "jpeg" , "image/jpeg" ),
64− ( ".jpg" , "image/jpeg" ),
72+ ( "jpg" , "image/jpeg" ),
65− ( ".js" , "text/javascript" ),
73+ ( "js" , "text/javascript" ),
66− ( ".log" , "text/plain" ),
74+ ( "log" , "text/plain" ),
67− ( ".m3u" , "audio/x-mpegurl" ),
75+ ( "m3u" , "audio/x-mpegurl" ),
68− ( ".mov" , "video/quicktime" ),
76+ ( "mov" , "video/quicktime" ),
69− ( ".mp3" , "audio/mpeg" ),
77+ ( "mp3" , "audio/mpeg" ),
70− ( ".mpeg" , "video/mpeg" ),
78+ ( "mpeg" , "video/mpeg" ),
71− ( ".mpg" , "video/mpeg" ),
79+ ( "mpg" , "video/mpeg" ),
72− ( ".ogg" , "application/ogg" ),
80+ ( "ogg" , "application/ogg" ),
73− ( ".pac" , "application/x-ns-proxy-autoconfig" ),
81+ ( "pac" , "application/x-ns-proxy-autoconfig" ),
74− ( ".pdf" , "application/pdf" ),
82+ ( "pdf" , "application/pdf" ),
75− ( ".png" , "image/png" ),
83+ ( "png" , "image/png" ),
76− ( ".ps" , "application/postscript" ),
84+ ( "ps" , "application/postscript" ),
77− ( ".qt" , "video/quicktime" ),
85+ ( "qt" , "video/quicktime" ),
78− ( ".sig" , "application/pgp-signature" ),
86+ ( "sig" , "application/pgp-signature" ),
79− ( ".spl" , "application/futuresplash" ),
87+ ( "spl" , "application/futuresplash" ),
80− ( ".swf" , "application/x-shockwave-flash" ),
88+ ( "swf" , "application/x-shockwave-flash" ),
81− ( ".tar" , "application/x-tar" ),
89+ ( "tar" , "application/x-tar" ),
82− ( ".tar.bz2" , "application/x-bzip-compressed-tar" ),
90+ ( "tar.bz2" , "application/x-bzip-compressed-tar" ),
83− ( ".tar.gz" , "application/x-tgz" ),
91+ ( "tar.gz" , "application/x-tgz" ),
84− ( ".tbz" , "application/x-bzip-compressed-tar" ),
92+ ( "tbz" , "application/x-bzip-compressed-tar" ),
85− ( ".text" , "text/plain" ),
93+ ( "text" , "text/plain" ),
86− ( ".tgz" , "application/x-tgz" ),
94+ ( "tgz" , "application/x-tgz" ),
87− ( ".torrent" , "application/x-bittorrent" ),
95+ ( "torrent" , "application/x-bittorrent" ),
88− ( ".ttf" , "application/x-font-truetype" ),
96+ ( "ttf" , "application/x-font-truetype" ),
89− ( ".txt" , "text/plain" ),
97+ ( "txt" , "text/plain" ),
90− ( ".wav" , "audio/x-wav" ),
98+ ( "wav" , "audio/x-wav" ),
91− ( ".wax" , "audio/x-ms-wax" ),
99+ ( "wax" , "audio/x-ms-wax" ),
92− ( ".wma" , "audio/x-ms-wma" ),
100+ ( "wma" , "audio/x-ms-wma" ),
93− ( ".wmv" , "video/x-ms-wmv" ),
101+ ( "wmv" , "video/x-ms-wmv" ),
94− ( ".xbm" , "image/x-xbitmap" ),
102+ ( "xbm" , "image/x-xbitmap" ),
95− ( ".xml" , "text/xml" ),
103+ ( "xml" , "text/xml" ),
96− ( ".xpm" , "image/x-xpixmap" ),
104+ ( "xpm" , "image/x-xpixmap" ),
97− ( ".xwd" , "image/x-xwindowdump" ),
105+ ( "xwd" , "image/x-xwindowdump" ),
98− ( ".zip" , "application/zip" )]
106+ ( "zip" , "application/zip" )]
100mimeTypeByExt :: MimeMap
108mimeTypeByExt :: MimeMap
101 -> MimeType -- ^ default mime type
109 -> MimeType -- ^ default mime type
102 -> FilePath
110 -> FilePath
103 -> MimeType
111 -> MimeType
104−mimeTypeByExt mm def fp = fromMaybe def $ Map.lookup (takeExtensions fp) mm
112+mimeTypeByExt mm def =
117+ case Map.lookup e mm of
106defaultMimeTypeByExt :: FilePath -> MimeType
121defaultMimeTypeByExt :: FilePath -> MimeType
107defaultMimeTypeByExt = mimeTypeByExt defaultMimeTypes defaultMimeType
122defaultMimeTypeByExt = mimeTypeByExt defaultMimeTypes defaultMimeType