packages feed

minion-0.1.0.0: src/Web/Minion/Static.hs

module Web.Minion.Static (StaticFileResponse, staticFiles, defaultExtsMap) where

import Data.ByteString qualified as Bytes
import Data.ByteString.Lazy qualified as Bytes.Lazy
import Data.Map.Strict qualified as Map
import Data.Void
import Network.HTTP.Media
import System.FilePath (takeExtension)
import Web.Minion
import Web.Minion.Introspect qualified as I
import Web.Minion.Response.Header qualified as Header

type StaticFileResponse = Header.AddHeaders '[Header.AddHeader "Content-Type" Header.RawHeaderValue] LazyBytes

{-# INLINE staticFiles #-}
staticFiles ::
  (Monad m, I.Introspection i I.Response StaticFileResponse) =>
  -- | Use 'defaultExtsMap'
  Map.Map String MediaType ->
  [(FilePath, Bytes.ByteString)] ->
  Router' i Void m
staticFiles extsMap = foldMap \(path, content) ->
  let contentType = getContentType extsMap (takeExtension path)
   in piece path /> handle GET do
        pure $
          Header.AddHeaders
            { headers = Header.AddHeader @"Content-Type" (Header.RawHeaderValue contentType) :# HNil
            , body = LazyBytes $ Bytes.Lazy.fromStrict content
            }

getContentType :: (RenderHeader a) => Map.Map String a -> FilePath -> Bytes.ByteString
getContentType extsMap path = maybe "application/octet-stream" renderHeader $ Map.lookup (takeExtension path) extsMap

defaultExtsMap :: Map.Map String MediaType
defaultExtsMap =
  Map.fromList
    [ ".aac" ~> "audio/aac"
    , ".abw" ~> "application/x-abiword"
    , ".arc" ~> "application/x-freearc"
    , ".avif" ~> "image/avif"
    , ".avi" ~> "video/x-msvideo"
    , ".azw" ~> "application/vnd.amazon.ebook"
    , ".bin" ~> "application/octet-stream"
    , ".bmp" ~> "image/bmp"
    , ".bz" ~> "application/x-bzip"
    , ".bz2" ~> "application/x-bzip2"
    , ".cda" ~> "application/x-cdf"
    , ".csh" ~> "application/x-csh"
    , ".css" ~> "text/css"
    , ".csv" ~> "text/csv"
    , ".doc" ~> "application/msword"
    , ".docx" ~> "application/vnd.openxmlformats-officedocument.wordprocessingml.document"
    , ".eot" ~> "application/vnd.ms-fontobject"
    , ".epub" ~> "application/epub+zip"
    , ".gz" ~> "application/gzip"
    , ".gif" ~> "image/gif"
    , ".htm" ~> "text/html"
    , ".ico" ~> "image/vnd.microsoft.icon"
    , ".ics" ~> "text/calendar"
    , ".jar" ~> "application/java-archive"
    , ".jpeg" ~> "image/jpeg"
    , ".jpg" ~> "image/jpeg"
    , ".js" ~> "text/javascript"
    , ".json" ~> "application/json"
    , ".jsonld" ~> "application/ld+json"
    , ".mid" ~> "audio/midi"
    , ".midi" ~> "audio/midi"
    , ".mjs" ~> "text/javascript"
    , ".mp3" ~> "audio/mpeg"
    , ".mp4" ~> "video/mp4"
    , ".mpeg" ~> "video/mpeg"
    , ".mpkg" ~> "application/vnd.apple.installer+xml"
    , ".odp" ~> "application/vnd.oasis.opendocument.presentation"
    , ".ods" ~> "application/vnd.oasis.opendocument.spreadsheet"
    , ".odt" ~> "application/vnd.oasis.opendocument.text"
    , ".oga" ~> "audio/ogg"
    , ".ogv" ~> "video/ogg"
    , ".ogx" ~> "application/ogg"
    , ".opus" ~> "audio/opus"
    , ".otf" ~> "font/otf"
    , ".png" ~> "image/png"
    , ".pdf" ~> "application/pdf"
    , ".php" ~> "application/x-httpd-php"
    , ".ppt" ~> "application/vnd.ms-powerpoint"
    , ".pptx" ~> "application/vnd.openxmlformats-officedocument.presentationml.presentation"
    , ".rar" ~> "application/vnd.rar"
    , ".rtf" ~> "application/rtf"
    , ".sh" ~> "application/x-sh"
    , ".svg" ~> "image/svg+xml"
    , ".tar" ~> "application/x-tar"
    , ".tif" ~> "image/tiff"
    , ".tiff" ~> "image/tiff"
    , ".ts" ~> "video/mp2t"
    , ".ttf" ~> "font/ttf"
    , ".txt" ~> "text/plain"
    , ".vsd" ~> "application/vnd.visio"
    , ".wav" ~> "audio/wav"
    , ".weba" ~> "audio/webm"
    , ".webm" ~> "video/webm"
    , ".webp" ~> "image/webp"
    , ".woff" ~> "font/woff"
    , ".woff2" ~> "font/woff2"
    , ".xhtml" ~> "application/xhtml+xml"
    , ".xls" ~> "application/vnd.ms-excel"
    , ".xlsx" ~> "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
    , ".xml" ~> "application/xml"
    , ".xul" ~> "application/vnd.mozilla.xul+xml"
    , ".zip" ~> "application/zip"
    , ".3gp" ~> "video/3gpp"
    , ".3g2" ~> "video/3gpp2"
    , ".7z" ~> "application/x-7z-compressed"
    ]
 where
  (~>) :: String -> MediaType -> (String, MediaType)
  (~>) = (,)