wai-app-static 1.2.0.3 → 1.2.0.4
raw patch · 3 files changed
+51/−39 lines, 3 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
Files
- Network/Wai/Application/Static.hs +49/−37
- test/WaiAppStaticTest.hs +1/−1
- wai-app-static.cabal +1/−1
Network/Wai/Application/Static.hs view
@@ -99,7 +99,7 @@ import Data.Ord (comparing) import qualified Data.ByteString.Base64 as B64 import Data.Either (rights)-import Data.Maybe (isJust, fromJust)+import Data.Maybe (isJust, fromJust, mapMaybe) import Network.HTTP.Date (parseHTTPDate, epochTimeToHTTPDate, formatHTTPDate) import Data.String (IsString (..)) @@ -114,7 +114,7 @@ -- | A list of all possible extensions, starting from the largest. takeExtensions :: FilePath -> [FilePath] takeExtensions (FilePath s) =- case T.break (== '.') s of+ case T.breakOn (".") s of (_, "") -> [] (_, x) -> FilePath (T.drop 1 x) : takeExtensions (FilePath $ T.drop 1 x) @@ -192,37 +192,26 @@ ( "xwd" , "image/x-xwindowdump" ), ( "zip" , "application/zip" )] +-- similar to Safe package+headDef :: a -> [a] -> a+headDef _ (x:_) = x+headDef def [] = def++-- similar to Safe package+initSafe :: [a] -> [a]+initSafe [] = []+initSafe xs = init xs+ mimeTypeByExt :: MimeMap -> MimeType -- ^ default mime type -> FilePath -> MimeType mimeTypeByExt mm def =- go . takeExtensions- where- go [] = def- go (e:es) =- case Map.lookup e mm of- Nothing -> go es- Just mt -> mt+ headDef def . mapMaybe (flip Map.lookup mm) . takeExtensions defaultMimeTypeByExt :: FilePath -> MimeType defaultMimeTypeByExt = mimeTypeByExt defaultMimeTypes defaultMimeType -data CheckPieces =- -- | Just the etag hash or Nothing for no etag hash- Redirect Pieces (Maybe ByteString)- | Forbidden- | NotFound- | FileResponse File H.ResponseHeaders- | NotModified- | DirectoryResponse Folder- -- TODO: add file size- | SendContent MimeType L.ByteString--safeInit :: [a] -> [a]-safeInit [] = []-safeInit xs = init xs- filterButLast :: (a -> Bool) -> [a] -> [a] filterButLast _ [] = [] filterButLast _ [x] = [x]@@ -231,8 +220,8 @@ | otherwise = filterButLast f xs -unsafe :: FilePath -> Bool-unsafe (FilePath s)+unsafePiece :: FilePath -> Bool+unsafePiece (FilePath s) | T.null s = False | T.head s == '.' = True | otherwise = T.any (== '/') s@@ -262,6 +251,17 @@ Just $ SendContent "image/png" $ L.fromChunks [$(embedFile "images/haskell.png")] checkSpecialDirListing _ = Nothing +data CheckPieces =+ -- | Just the etag hash or Nothing for no etag hash+ Redirect Pieces (Maybe ByteString)+ | Forbidden+ | NotFound+ | FileResponse File H.ResponseHeaders+ | NotModified+ | DirectoryResponse Folder+ -- TODO: add file size+ | SendContent MimeType L.ByteString+ checkPieces :: (Pieces -> IO FileLookup) -- ^ file lookup function -> [FilePath] -- ^ List of default index files. Cannot contain slashes. -> Pieces -- ^ parsed request@@ -271,16 +271,14 @@ -> Bool -- ^ Redirect to Index? -> IO CheckPieces checkPieces fileLookup indices pieces req maxAge useHash redirectToIndex- | any unsafe pieces = return Forbidden- | any nullFilePath $ safeInit pieces =+ | any unsafePiece pieces = return Forbidden+ | any nullFilePath $ initSafe pieces = return $ Redirect (filterButLast (not . nullFilePath) pieces) Nothing | otherwise = do let (isFile, isFolder) =- case () of- ()- | null pieces -> (True, True)- | nullFilePath (last pieces) -> (False, True)- | otherwise -> (True, False)+ if null pieces then (True, True)+ else if nullFilePath (last pieces) then (False, True)+ else (True, False) fl <- fileLookup pieces case (fl, isFile) of@@ -368,9 +366,7 @@ checkIndices :: [FilePath] -> Maybe FilePath checkIndices contents = find (flip elem indices) contents - cacheControl = case ccInt of- Nothing -> []- Just i -> [("Cache-Control", S8.append "max-age=" $ S8.pack $ show i)]+ cacheControl = headerCacheControl $ headerExpires [] where ccInt = case maxAge of@@ -380,6 +376,16 @@ oneYear :: Int oneYear = 60 * 60 * 24 * 365 + headerCacheControl =+ case ccInt of+ Nothing -> id+ Just i -> (:) ("Cache-Control", S8.append "public, max-age=" $ S8.pack $ show i)+ headerExpires =+ case maxAge of+ NoMaxAge -> id+ MaxAgeSeconds _ -> id -- FIXME+ MaxAgeForever -> (:) ("Expires", "Thu, 31 Dec 2037 23:55:55 GMT")+ type Listing = (Pieces -> Folder -> IO L.ByteString) @@ -613,7 +619,13 @@ let indices = ssIndices ss case checkSpecialDirListing pieces of Just res -> response res- Nothing -> checkPieces (ssFolder ss) (map FilePath indices) pieces req (ssMaxAge ss) (ssUseHash ss) (ssRedirectToIndex ss) >>= response+ Nothing -> response =<< checkPieces (ssFolder ss)+ (map FilePath indices)+ pieces+ req+ (ssMaxAge ss)+ (ssUseHash ss)+ (ssRedirectToIndex ss) where response cp = case cp of FileResponse file ch -> do
test/WaiAppStaticTest.hs view
@@ -90,7 +90,7 @@ it "Cache-Control set when etag parameter is correct" $ webApp $ do req <- request statFile { queryString = [("etag", Just etag)] } assertStatus 200 req- assertHeader "Cache-Control" "max-age=31536000" req+ assertHeader "Cache-Control" "public, max-age=31536000" req assertNoHeader "Last-Modified" req it "200 when invalid in-none-match sent" $ webApp $
wai-app-static.cabal view
@@ -1,5 +1,5 @@ name: wai-app-static-version: 1.2.0.3+version: 1.2.0.4 license: MIT license-file: LICENSE author: Michael Snoyman <michael@snoyman.com>