packages feed

wai-app-static 0.3.1.1 → 0.3.3

raw patch · 2 files changed

+64/−35 lines, 2 filesdep ~hspecdep ~timePVP: major bump suggested

API removals or changes: PVP suggests a major version bump

Dependency ranges changed: hspec, time

API changes (from Hackage documentation)

+ Network.Wai.Application.Static: type ETagLookup = FilePath -> IO (Maybe ByteString)
+ Network.Wai.Application.Static: webAppSettingsWithLookup :: FilePath -> ETagLookup -> StaticSettings
- Network.Wai.Application.Static: File :: Int -> (Status -> ResponseHeaders -> Response) -> FilePath -> Maybe (IO ByteString) -> Maybe EpochTime -> File
+ Network.Wai.Application.Static: File :: Int -> (Status -> ResponseHeaders -> Response) -> FilePath -> IO (Maybe ByteString) -> Maybe EpochTime -> File
- Network.Wai.Application.Static: fileGetHash :: File -> Maybe (IO ByteString)
+ Network.Wai.Application.Static: fileGetHash :: File -> IO (Maybe ByteString)
- Network.Wai.Application.Static: fileSystemLookupHash :: (FilePath -> Maybe (IO ByteString)) -> FilePath -> Pieces -> IO FileLookup
+ Network.Wai.Application.Static: fileSystemLookupHash :: ETagLookup -> FilePath -> Pieces -> IO FileLookup

Files

Network/Wai/Application/Static.hs view
@@ -6,6 +6,7 @@       staticApp       -- ** Settings     , defaultWebAppSettings+    , webAppSettingsWithLookup      , defaultFileServerSettings     , StaticSettings     , ssFolder@@ -47,6 +48,7 @@     , toFilePath     , fromFilePath     , MaxAge (..)+    , ETagLookup     ) where  import Prelude hiding (FilePath)@@ -229,10 +231,12 @@ nullFilePath :: FilePath -> Bool nullFilePath = T.null . unFilePath +{- stripTrailingSlash :: FilePath -> FilePath stripTrailingSlash fp@(FilePath t)     | T.null t || T.last t /= '/' = fp     | otherwise = FilePath $ T.init t+    -}  type Pieces = [FilePath] @@ -304,31 +308,32 @@     handleCache file =       if not useHash then lastModifiedCache file         else do-          let mGetHash  = fileGetHash file           let etagParam = lookup "etag" queryString -          case (etagParam, mGetHash) of-            (Just mEtag, Just getHash) -> do-                hash <- getHash-                if isJust mEtag && hash == fromJust mEtag-                  then return $ FileResponse file $ ("ETag", hash):cacheControl-                  else return $ Redirect pieces (Just hash)-            -- a file used to have an etag parameter, but no longer does-            (Just _, Nothing) -> return $ Redirect pieces Nothing+          case etagParam of+            Nothing -> do -- no query parameter. Set appropriate ETag headers+                mHash <- fileGetHash file+                case mHash of+                    Nothing -> lastModifiedCache file+                    Just hash ->+                        case lookup "if-none-match" headers of+                            Just lastHash ->+                              if hash == lastHash+                                  then return NotModified+                                  else return $ FileResponse file $ [("ETag", hash)]+                            Nothing -> return $ FileResponse file $ [("ETag", hash)] -            _ -> -                case (lookup "if-none-match" headers, mGetHash) of-                    -- etag-                    (mLastHash, Just getHash) -> do-                        hash <- getHash-                        case mLastHash of-                          Just lastHash ->-                            if hash == lastHash-                                then return NotModified-                                else return $ FileResponse file $ [("ETag", hash)]-                          Nothing -> return $ FileResponse file $ [("ETag", hash)]-                    (_, Nothing) -> lastModifiedCache file+            Just mEtag -> do+                mHash <- fileGetHash file+                case mHash of+                  -- a file used to have an etag parameter, but no longer does+                  Nothing -> return $ Redirect pieces Nothing+                  Just hash ->+                    if isJust mEtag && hash == fromJust mEtag+                      then return $ FileResponse file $ ("ETag", hash):cacheControl+                      else return $ Redirect pieces (Just hash) +     lastModifiedCache file =       case (lookup "if-modified-since" headers >>= parseHTTPDate, fileGetModified file) of           (mLastSent, Just modified) -> do@@ -375,12 +380,12 @@     { fileGetSize :: Int     , fileToResponse :: H.Status -> H.ResponseHeaders -> W.Response     , fileName :: FilePath-    , fileGetHash :: Maybe (IO ByteString)+    , fileGetHash :: IO (Maybe ByteString)     , fileGetModified :: Maybe EpochTime     }  data StaticSettings = StaticSettings-    { ssFolder :: Pieces -> IO FileLookup+    { ssFolder :: Pieces -> IO FileLookup -- TODO: not a folder, so rename     , ssMkRedirect :: Pieces -> ByteString -> ByteString     , ssGetMimeType :: File -> IO MimeType     , ssListing :: Maybe Listing@@ -400,9 +405,14 @@   where     relDir = TE.encodeUtf8 (relativeDirFromPieces pieces) +webAppSettingsWithLookup :: FilePath -> ETagLookup -> StaticSettings+webAppSettingsWithLookup dir etagLookup =+  defaultWebAppSettings { ssFolder = webAppLookup etagLookup dir}++ defaultWebAppSettings :: StaticSettings defaultWebAppSettings = StaticSettings-    { ssFolder = fileSystemLookup "static"+    { ssFolder = webAppLookup hashFileIfExists "static"     , ssMkRedirect  = defaultMkRedirect     , ssGetMimeType = return . defaultMimeTypeByExt . fileName     , ssMaxAge  = MaxAgeForever@@ -422,7 +432,7 @@     , ssUseHash = False     } -fileHelper :: (FilePath -> Maybe (IO ByteString)) -- ^ hash function+fileHelper :: ETagLookup            -> FilePath -> FilePath -> IO File fileHelper hashFunc fp name = do     fs <- getFileStatus $ fromFilePath fp@@ -434,17 +444,36 @@         , fileGetModified = Just $ modificationTime fs         } -defaultFileSystemHash :: FilePath -> Maybe (IO ByteString)-defaultFileSystemHash fp = Just $ do-    -- FIXME replace lazy IO with enumerators-    -- FIXME let's use a dictionary to cache these values?+type ETagLookup = (FilePath -> IO (Maybe ByteString))++webAppLookup :: ETagLookup -> FilePath -> Pieces -> IO FileLookup+webAppLookup cachedLookupHash prefix pieces = do+    file <- fileHelper cachedLookupHash fp (last pieces)+    return $ Just $ Right $ file+  where+    fp = pathFromPieces prefix pieces++defaultFileSystemHash :: ETagLookup+defaultFileSystemHash fp = fmap Just $ hashFile fp++-- FIXME replace lazy IO with enumerators+-- FIXME let's use a dictionary to cache these values?+hashFile :: FilePath -> IO ByteString+hashFile fp = do     l <- L.readFile $ fromFilePath fp     return $ runHashL l +hashFileIfExists :: ETagLookup+hashFileIfExists fp = do+    fe <- doesFileExist $ fromFilePath fp+    if fe+      then return Nothing+      else defaultFileSystemHash fp+ fileSystemLookup :: FilePath -> Pieces -> IO FileLookup fileSystemLookup = fileSystemLookupHash defaultFileSystemHash -fileSystemLookupHash :: (FilePath -> Maybe (IO ByteString)) -- ^ hash function+fileSystemLookupHash :: ETagLookup                      -> FilePath -> Pieces -> IO FileLookup fileSystemLookupHash hashFunc prefix pieces = do     let fp = pathFromPieces prefix pieces@@ -494,7 +523,7 @@     { fileGetSize = S8.length bs     , fileToResponse = \s h -> W.ResponseBuilder s h $ fromByteString bs     , fileName = name-    , fileGetHash = Just $ return $ runHash bs+    , fileGetHash = return $ Just $ runHash bs     , fileGetModified = Nothing     } @@ -525,7 +554,7 @@     { fileGetSize = S8.length bs     , fileToResponse = \s h -> W.ResponseBuilder s h $ fromByteString bs     , fileName = name-    , fileGetHash = Just $ return $ runHash bs+    , fileGetHash = return $ Just $ runHash bs     , fileGetModified = Nothing     } 
wai-app-static.cabal view
@@ -1,5 +1,5 @@ name:            wai-app-static-version:         0.3.1.1+version:         0.3.3 license:         BSD3 license-file:    LICENSE author:          Michael Snoyman <michael@snoyman.com>@@ -48,10 +48,10 @@     type: exitcode-stdio-1.0      build-depends:   base                      >= 4        && < 5-                   , hspec >= 0.6+                   , hspec >= 0.6.1 && < 0.7                    , HUnit                    , unix-compat               >= 0.2      && < 0.3-                   , time                      >= 1.1.4    && < 1.3+                   , time                      >= 1.1.4    && < 1.4                    , old-locale                >= 1.0.0.2  && < 1.1                    , http-date                    , Cabal