Using wai-app-static (not sure if it will stick yet), does not fully work

This commit is contained in:
Michael Snoyman 2011-01-20 23:55:05 +02:00
parent 3b2a3881e6
commit 2db05e2055
2 changed files with 18 additions and 68 deletions

View File

@ -29,10 +29,8 @@ module Yesod.Helpers.Static
Static (..) Static (..)
, StaticRoute (..) , StaticRoute (..)
-- * Lookup files in filesystem -- * Lookup files in filesystem
, fileLookupDir
, staticFiles , staticFiles
-- * Embed files -- * Embed files
, mkEmbedFiles
, getStaticHandler , getStaticHandler
-- * Hashing -- * Hashing
, base64md5 , base64md5
@ -48,8 +46,10 @@ import Data.Maybe (fromMaybe)
import Yesod.Handler import Yesod.Handler
import Yesod.Content import Yesod.Content
import Yesod.Core import Yesod.Core
import Yesod.Request
import Control.Monad.IO.Class (liftIO) import Control.Monad.IO.Class (liftIO)
import qualified Control.Monad.Trans.Class as Trans
import Data.List (intercalate) import Data.List (intercalate)
import Language.Haskell.TH import Language.Haskell.TH
@ -62,6 +62,9 @@ import qualified Data.ByteString.Base64
import qualified Data.ByteString.Char8 as S8 import qualified Data.ByteString.Char8 as S8
import qualified Data.Serialize import qualified Data.Serialize
import Network.Wai.Application.Static
(defaultMimeTypeByExt, StaticSettings (..), staticApp, defaultListing)
#if TEST #if TEST
import Test.Framework (testGroup, Test) import Test.Framework (testGroup, Test)
import Test.Framework.Providers.HUnit import Test.Framework.Providers.HUnit
@ -71,9 +74,8 @@ import Test.HUnit hiding (Test)
-- | A function for looking up file contents. For serving from the file system, -- | A function for looking up file contents. For serving from the file system,
-- see 'fileLookupDir'. -- see 'fileLookupDir'.
data Static = Static data Static = Static
{ staticLookup :: FilePath -> IO (Maybe (Either FilePath Content)) { staticPrefix :: FilePath
-- | Mapping from file extension to content type. See 'typeByExt'. -- FIXME why not just put in a StaticSettings here?
, staticTypes :: [(String, ContentType)]
} }
-- | Manually construct a static route. -- | Manually construct a static route.
@ -92,54 +94,21 @@ instance YesodSubSite Static master where
getSubSite = Site getSubSite = Site
{ handleSite = \_ (StaticRoute ps _) m -> { handleSite = \_ (StaticRoute ps _) m ->
case m of case m of
"GET" -> Just $ fmap chooseRep $ getStaticRoute ps "GET" -> Just $ do
Static prefix <- getYesodSub
req <- waiRequest
res <- Trans.lift $ staticApp StaticSettings
{ ssFolder = prefix
, ssIndices = []
, ssListing = Just defaultListing
, ssGetMimeType = return . defaultMimeTypeByExt
} req
sendWaiResponse res
_ -> Nothing _ -> Nothing
, formatPathSegments = \(StaticRoute x y) -> (x, y) , formatPathSegments = \(StaticRoute x y) -> (x, y)
, parsePathSegments = \x -> Right $ StaticRoute x [] , parsePathSegments = \x -> Right $ StaticRoute x []
} }
-- | Lookup files in a specific directory.
--
-- If you are just using this in combination with the static subsite (you
-- probably are), the handler itself checks that no unsafe paths are being
-- requested. In particular, no path segments may begin with a single period,
-- so hidden files and parent directories are safe.
--
-- For the second argument to this function, you can just use 'typeByExt'.
fileLookupDir :: FilePath -> [(String, ContentType)] -> Static
fileLookupDir dir = Static $ \fp -> do
let fp' = dir ++ '/' : fp
exists <- doesFileExist fp'
if exists
then return $ Just $ Left fp'
else return Nothing
-- | Lookup files in a specific directory, and embed them into the haskell source.
--
-- A variation of fileLookupDir which allows subsites distributed via cabal to include
-- static content. You can still use staticFiles to generate route identifiers. See getStaticHandler
-- for dispatching static content for a subsite.
mkEmbedFiles :: FilePath -> Q Exp
mkEmbedFiles d = do
fs <- qRunIO $ getFileList d
clauses <- mapM (mkClause . intercalate "/") fs
defC <- defaultClause
return $ static $ clauses ++ [defC]
where static clauses = LetE [fun clauses] $ ConE 'Static `AppE` VarE f
f = mkName "f"
fun clauses = FunD f clauses
defaultClause = do
b <- [| return Nothing |]
return $ Clause [WildP] (NormalB b) []
mkClause p = do
content <- qRunIO $ readFile $ d ++ '/':p
let pat = LitP $ StringL p
foldAppE = foldl1 AppE
content' = return $ LitE $ StringL $ content
body <- normalB [| return $ Just $ Right $ toContent ($content' :: [Char]) |]
return $ Clause [pat] body []
-- | Dispatch static route for a subsite -- | Dispatch static route for a subsite
-- --
-- Subsites with static routes can't (yet) define Static routes the same way "master" sites can. -- Subsites with static routes can't (yet) define Static routes the same way "master" sites can.
@ -160,26 +129,6 @@ getStaticHandler static toSubR pieces = do
staticSite = getSubSite :: Site (Route Static) (String -> Maybe (GHandler Static y ChooseRep)) staticSite = getSubSite :: Site (Route Static) (String -> Maybe (GHandler Static y ChooseRep))
handler = fromMaybe notFound $ handleSite staticSite undefined route "GET" handler = fromMaybe notFound $ handleSite staticSite undefined route "GET"
getStaticRoute :: [String]
-> GHandler Static master (ContentType, Content)
getStaticRoute fp' = do
Static fl ctypes <- getYesodSub
when (any isUnsafe fp') notFound
let fp = intercalate "/" fp'
content <- liftIO $ fl fp
case content of
Nothing -> notFound
Just (Left fp'') -> do
let ctype = fromMaybe typeOctet $ lookup (ext fp'') ctypes
sendFile ctype fp''
Just (Right bs) -> do
let ctype = fromMaybe typeOctet $ lookup (ext fp) ctypes
return (ctype, bs)
where
isUnsafe [] = True
isUnsafe ('.':_) = True
isUnsafe _ = False
notHidden :: FilePath -> Bool notHidden :: FilePath -> Bool
notHidden ('.':_) = False notHidden ('.':_) = False
notHidden "tmp" = False notHidden "tmp" = False

View File

@ -26,6 +26,7 @@ library
, template-haskell , template-haskell
, directory >= 1.0 && < 1.2 , directory >= 1.0 && < 1.2
, transformers >= 0.2 && < 0.3 , transformers >= 0.2 && < 0.3
, wai-app-static >= 0.0 && < 0.1
exposed-modules: Yesod.Helpers.Static exposed-modules: Yesod.Helpers.Static
ghc-options: -Wall ghc-options: -Wall