diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,20 @@
+Copyright (c) 2012 Michael Snoyman, http://www.yesodweb.com/
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/Network/Mime.hs b/Network/Mime.hs
new file mode 100644
--- /dev/null
+++ b/Network/Mime.hs
@@ -0,0 +1,139 @@
+{-# LANGUAGE OverloadedStrings #-}
+module Network.Mime
+    ( -- * Lookups
+      mimeByExt
+    , defaultMimeLookup
+      -- * Defaults
+    , defaultMimeType
+    , defaultMimeMap
+      -- * Utilities
+    , fileNameExtensions
+      -- * Types
+    , FileName
+    , MimeType
+    , MimeMap
+    , Extension
+    ) where
+
+import Data.Text (Text)
+import qualified Data.Text as T
+import Data.ByteString (ByteString)
+import Data.ByteString.Char8 ()
+import qualified Data.Map as Map
+
+-- | Maps extensions to mime types.
+type MimeMap = Map.Map Extension MimeType
+
+-- | The filename component of a filepath, leaving off the directory but
+-- keeping all extensions.
+type FileName = Text
+
+-- | Individual mime type for be served over the wire.
+type MimeType = ByteString
+
+-- | The default fallback mime type \"application/octet-stream\".
+defaultMimeType :: MimeType
+defaultMimeType = "application/octet-stream"
+
+-- | A default mapping from filename extension to mime type.
+--
+-- taken from snap-core Snap.Util.FileServer
+defaultMimeMap :: MimeMap
+defaultMimeMap = Map.fromList [
+  ( "apk"     , "application/vnd.android.package-archive" ),
+  ( "asc"     , "text/plain"                        ),
+  ( "asf"     , "video/x-ms-asf"                    ),
+  ( "asx"     , "video/x-ms-asf"                    ),
+  ( "avi"     , "video/x-msvideo"                   ),
+  ( "bz2"     , "application/x-bzip"                ),
+  ( "c"       , "text/plain"                        ),
+  ( "class"   , "application/octet-stream"          ),
+  ( "conf"    , "text/plain"                        ),
+  ( "cpp"     , "text/plain"                        ),
+  ( "css"     , "text/css"                          ),
+  ( "cxx"     , "text/plain"                        ),
+  ( "dtd"     , "text/xml"                          ),
+  ( "dvi"     , "application/x-dvi"                 ),
+  ( "epub"    , "application/epub+zip"              ),
+  ( "gif"     , "image/gif"                         ),
+  ( "gz"      , "application/x-gzip"                ),
+  ( "hs"      , "text/plain"                        ),
+  ( "htm"     , "text/html"                         ),
+  ( "html"    , "text/html"                         ),
+  ( "ico"     , "image/vnd.microsoft.icon"          ),
+  ( "jar"     , "application/x-java-archive"        ),
+  ( "jpeg"    , "image/jpeg"                        ),
+  ( "jpg"     , "image/jpeg"                        ),
+  ( "js"      , "text/javascript"                   ),
+  ( "json"    , "application/json"                  ),
+  ( "log"     , "text/plain"                        ),
+  ( "manifest", "text/cache-manifest"               ),
+  ( "m3u"     , "audio/x-mpegurl"                   ),
+  ( "mov"     , "video/quicktime"                   ),
+  ( "mp3"     , "audio/mpeg"                        ),
+  ( "mpeg"    , "video/mpeg"                        ),
+  ( "mpg"     , "video/mpeg"                        ),
+  ( "ogg"     , "application/ogg"                   ),
+  ( "pac"     , "application/x-ns-proxy-autoconfig" ),
+  ( "pdf"     , "application/pdf"                   ),
+  ( "png"     , "image/png"                         ),
+  ( "bmp"     , "image/bmp"                         ),
+  ( "ps"      , "application/postscript"            ),
+  ( "qt"      , "video/quicktime"                   ),
+  ( "sig"     , "application/pgp-signature"         ),
+  ( "spl"     , "application/futuresplash"          ),
+  ( "svg"     , "image/svg+xml"                     ),
+  ( "swf"     , "application/x-shockwave-flash"     ),
+  ( "tar"     , "application/x-tar"                 ),
+  ( "tar.bz2" , "application/x-bzip-compressed-tar" ),
+  ( "tar.gz"  , "application/x-tgz"                 ),
+  ( "tbz"     , "application/x-bzip-compressed-tar" ),
+  ( "text"    , "text/plain"                        ),
+  ( "tgz"     , "application/x-tgz"                 ),
+  ( "torrent" , "application/x-bittorrent"          ),
+  ( "ttf"     , "application/x-font-truetype"       ),
+  ( "txt"     , "text/plain"                        ),
+  ( "wav"     , "audio/x-wav"                       ),
+  ( "wax"     , "audio/x-ms-wax"                    ),
+  ( "wma"     , "audio/x-ms-wma"                    ),
+  ( "wmv"     , "video/x-ms-wmv"                    ),
+  ( "xbm"     , "image/x-xbitmap"                   ),
+  ( "xhtml"   , "application/xhtml+xml"             ),
+  ( "xml"     , "text/xml"                          ),
+  ( "xpm"     , "image/x-xpixmap"                   ),
+  ( "xwd"     , "image/x-xwindowdump"               ),
+  ( "zip"     , "application/zip"                   )]
+
+-- | Look up a mime type from the given mime map and default mime type.
+mimeByExt :: MimeMap
+          -> MimeType -- ^ default mime type
+          -> FileName
+          -> MimeType
+mimeByExt mm def =
+    go . fileNameExtensions
+  where
+    go [] = def
+    go (e:es) =
+        case Map.lookup e mm of
+            Nothing -> go es
+            Just mt -> mt
+
+-- | @mimeByExt@ applied to @defaultMimeType@ and @defaultMimeMap@.
+defaultMimeLookup :: FileName -> MimeType
+defaultMimeLookup = mimeByExt defaultMimeMap defaultMimeType
+
+-- | Get a list of all of the file name extensions from a piece.
+--
+-- > pieceExtensions "foo.tar.gz" == ["tar.gz", "gz"]
+fileNameExtensions :: FileName -> [Extension]
+fileNameExtensions =
+    go
+  where
+    go t
+        | T.null e = []
+        | otherwise = e : go e
+      where
+        e = T.drop 1 $ T.dropWhile (/= '.') t
+
+-- | Path extension. May include multiple components, e.g. tar.gz
+type Extension = Text
diff --git a/Setup.lhs b/Setup.lhs
new file mode 100644
--- /dev/null
+++ b/Setup.lhs
@@ -0,0 +1,7 @@
+#!/usr/bin/env runhaskell
+
+> module Main where
+> import Distribution.Simple
+
+> main :: IO ()
+> main = defaultMain
diff --git a/mime-types.cabal b/mime-types.cabal
new file mode 100644
--- /dev/null
+++ b/mime-types.cabal
@@ -0,0 +1,23 @@
+name:                mime-types
+version:             0.1.0.0
+synopsis:            Basic mime-type handling types and functions
+description:         Basic mime-type handling types and functions
+homepage:            https://github.com/yesodweb/wai
+license:             MIT
+license-file:        LICENSE
+author:              Michael Snoyman
+maintainer:          michael@snoyman.com
+category:            Web
+build-type:          Simple
+cabal-version:       >=1.8
+
+library
+  exposed-modules:     Network.Mime
+  build-depends:       base           >= 4      && < 5
+                     , containers
+                     , text
+                     , bytestring
+
+source-repository head
+  type:     git
+  location: git://github.com/yesodweb/wai.git
