wai-app-static changes, got directory listing working

This commit is contained in:
Michael Snoyman 2011-07-22 11:19:43 +03:00
parent 5cb8e4a605
commit 240a61a484

View File

@ -4,9 +4,10 @@
{-# LANGUAGE CPP #-} {-# LANGUAGE CPP #-}
{-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE OverloadedStrings #-}
--------------------------------------------------------- ---------------------------------------------------------
-- --
-- Module : Yesod.Helpers.Static -- Module : Yesod.Static
-- Copyright : Michael Snoyman -- Copyright : Michael Snoyman
-- License : BSD3 -- License : BSD3
-- --
@ -37,6 +38,8 @@ module Yesod.Static
, base64md5 , base64md5
) where ) where
import Prelude hiding (FilePath)
import qualified Prelude
import System.Directory import System.Directory
--import qualified System.Time --import qualified System.Time
import Control.Monad import Control.Monad
@ -58,8 +61,11 @@ import Data.Text (Text, pack)
import Data.Monoid (mempty) import Data.Monoid (mempty)
import qualified Data.Map as M import qualified Data.Map as M
--import Data.IORef (readIORef, newIORef, writeIORef) --import Data.IORef (readIORef, newIORef, writeIORef)
import Network.Wai (pathInfo) import Network.Wai (pathInfo, rawPathInfo, responseLBS)
import Data.Char (isLower, isDigit) import Data.Char (isLower, isDigit)
import Data.List (foldl')
import qualified Data.ByteString as S
import Network.HTTP.Types (status301)
import Network.Wai.Application.Static import Network.Wai.Application.Static
( StaticSettings (..) ( StaticSettings (..)
@ -69,8 +75,7 @@ import Network.Wai.Application.Static
, embeddedLookup , embeddedLookup
, toEmbedded , toEmbedded
, pathFromPieces , pathFromPieces
, toPiece , toFilePath
, fixPathName
) )
newtype Static = Static StaticSettings newtype Static = Static StaticSettings
@ -79,28 +84,28 @@ newtype Static = Static StaticSettings
-- --
-- Does not have index files, uses default directory listings and default mime -- Does not have index files, uses default directory listings and default mime
-- type list. -- type list.
static :: FilePath -> Static static :: Prelude.FilePath -> Static
static fp = static fp =
--hashes <- mkHashMap fp --hashes <- mkHashMap fp
Static $ defaultWebAppSettings { Static $ defaultWebAppSettings {
ssFolder = fileSystemLookup fp ssFolder = fileSystemLookup $ toFilePath fp
} }
-- | Produces a 'Static' based on embedding file contents in the executable at -- | Produces a 'Static' based on embedding file contents in the executable at
-- compile time. -- compile time.
embed :: FilePath -> Q Exp embed :: Prelude.FilePath -> Q Exp
embed fp = embed fp =
[|Static (defaultWebAppSettings [|Static (defaultWebAppSettings
{ ssFolder = embeddedLookup (toEmbedded $(embedDir fp)) { ssFolder = embeddedLookup (toEmbedded $(embedDir fp))
})|] })|]
{- {-
publicProduction :: String -> FilePath -> IO Public publicProduction :: String -> Prelude.FilePath -> IO Public
publicProduction root fp = do publicProduction root fp = do
etags <- mkPublicProductionEtag fp etags <- mkPublicProductionEtag fp
return $ public root fp etags return $ public root fp etags
publicDevel :: String -> FilePath -> IO Public publicDevel :: String -> Prelude.FilePath -> IO Public
publicDevel root fp = do publicDevel root fp = do
etags <- mkPublicDevelEtag fp etags <- mkPublicDevelEtag fp
return $ public root fp etags return $ public root fp etags
@ -123,15 +128,19 @@ instance RenderRoute StaticRoute where
renderRoute (StaticRoute x y) = (x, y) renderRoute (StaticRoute x y) = (x, y)
instance Yesod master => YesodDispatch Static master where instance Yesod master => YesodDispatch Static master where
-- Need to append trailing slash to make relative links work
yesodDispatch _ _ [] _ _ = Just $
\req -> return $ responseLBS status301 [("Location", rawPathInfo req `S.append` "/")] ""
yesodDispatch (Static set) _ textPieces _ _ = Just $ yesodDispatch (Static set) _ textPieces _ _ = Just $
\req -> staticApp set req { pathInfo = textPieces } \req -> staticApp set req { pathInfo = textPieces }
notHidden :: FilePath -> Bool notHidden :: Prelude.FilePath -> Bool
notHidden ('.':_) = False notHidden ('.':_) = False
notHidden "tmp" = False notHidden "tmp" = False
notHidden _ = True notHidden _ = True
getFileListPieces :: FilePath -> IO [[String]] getFileListPieces :: Prelude.FilePath -> IO [[String]]
getFileListPieces = flip go id getFileListPieces = flip go id
where where
go :: String -> ([String] -> [String]) -> IO [[String]] go :: String -> ([String] -> [String]) -> IO [[String]]
@ -149,32 +158,38 @@ getFileListPieces = flip go id
-- --
-- > style_css = StaticRoute ["style.css"] [] -- > style_css = StaticRoute ["style.css"] []
-- > js_script_js = StaticRoute ["js/script.js"] [] -- > js_script_js = StaticRoute ["js/script.js"] []
staticFiles :: FilePath -> Q [Dec] staticFiles :: Prelude.FilePath -> Q [Dec]
staticFiles dir = mkStaticFiles dir staticFiles dir = mkStaticFiles dir
{- {-
publicFiles :: FilePath -> Q [Dec] publicFiles :: Prelude.FilePath -> Q [Dec]
publicFiles dir = mkStaticFiles dir PublicSite publicFiles dir = mkStaticFiles dir PublicSite
-} -}
mkHashMap :: FilePath -> IO (M.Map FilePath S8.ByteString) mkHashMap :: Prelude.FilePath -> IO (M.Map Prelude.FilePath S8.ByteString)
mkHashMap dir = do mkHashMap dir = do
fs <- getFileListPieces dir fs <- getFileListPieces dir
hashAlist fs >>= return . M.fromList hashAlist fs >>= return . M.fromList
where where
hashAlist :: [[String]] -> IO [(FilePath, S8.ByteString)] hashAlist :: [[String]] -> IO [(Prelude.FilePath, S8.ByteString)]
hashAlist fs = mapM hashPair fs hashAlist fs = mapM hashPair fs
where where
hashPair :: [String] -> IO (FilePath, S8.ByteString) hashPair :: [String] -> IO (Prelude.FilePath, S8.ByteString)
hashPair pieces = do let file = pathFromRawPieces dir pieces hashPair pieces = do let file = pathFromRawPieces dir pieces
h <- base64md5File file h <- base64md5File file
return (file, S8.pack h) return (file, S8.pack h)
pathFromRawPieces :: Prelude.FilePath -> [String] -> Prelude.FilePath
pathFromRawPieces =
foldl' append
where
append a b = a ++ '/' : b
{- {-
mkPublicDevelEtag :: FilePath -> IO StaticSettings mkPublicDevelEtag :: Prelude.FilePath -> IO StaticSettings
mkPublicDevelEtag dir = do mkPublicDevelEtag dir = do
etags <- mkHashMap dir etags <- mkHashMap dir
mtimeVar <- newIORef (M.empty :: M.Map FilePath System.Time.ClockTime) mtimeVar <- newIORef (M.empty :: M.Map Prelude.FilePath System.Time.ClockTime)
return $ ETag $ \f -> return $ ETag $ \f ->
case M.lookup f etags of case M.lookup f etags of
Nothing -> return Nothing Nothing -> return Nothing
@ -187,17 +202,17 @@ mkPublicDevelEtag dir = do
return $ if newt /= oldt then Nothing else Just checksum return $ if newt /= oldt then Nothing else Just checksum
mkPublicProductionEtag :: FilePath -> IO StaticSettings mkPublicProductionEtag :: Prelude.FilePath -> IO StaticSettings
mkPublicProductionEtag dir = do mkPublicProductionEtag dir = do
etags <- mkHashMap dir etags <- mkHashMap dir
return $ ETag $ \f -> return . M.lookup f $ etags return $ ETag $ \f -> return . M.lookup f $ etags
-} -}
data StaticSite = StaticSite | PublicSite data StaticSite = StaticSite | PublicSite
mkStaticFiles :: FilePath -> Q [Dec] mkStaticFiles :: Prelude.FilePath -> Q [Dec]
mkStaticFiles fp = mkStaticFiles' fp "StaticRoute" True mkStaticFiles fp = mkStaticFiles' fp "StaticRoute" True
mkStaticFiles' :: FilePath -- ^ static directory mkStaticFiles' :: Prelude.FilePath -- ^ static directory
-> String -- ^ route constructor "StaticRoute" -> String -- ^ route constructor "StaticRoute"
-> Bool -- ^ append checksum query parameter -> Bool -- ^ append checksum query parameter
-> Q [Dec] -> Q [Dec]
@ -234,7 +249,7 @@ mkStaticFiles' fp routeConName makeHash = do
] ]
] ]
base64md5File :: FilePath -> IO String base64md5File :: Prelude.FilePath -> IO String
base64md5File file = do base64md5File file = do
contents <- L.readFile file contents <- L.readFile file
return $ base64md5 contents return $ base64md5 contents
@ -279,14 +294,10 @@ getStaticHandler static toSubR pieces = do
{- {-
calcHash :: FilePath -> IO String calcHash :: Prelude.FilePath -> IO String
calcHash fname = calcHash fname =
withBinaryFile fname ReadMode hashHandle withBinaryFile fname ReadMode hashHandle
where where
hashHandle h = do s <- L.hGetContents h hashHandle h = do s <- L.hGetContents h
return $! base64md5 s return $! base64md5 s
-} -}
-- FIXME Greg: Is this correct? Where is this function supposed to be?
pathFromRawPieces :: FilePath -> [String] -> FilePath
pathFromRawPieces fp = pathFromPieces fp . map (toPiece . pack . fixPathName)