on master help sign in
wai-app-static: make ssAddTrailingSlash work in combination with ssIndices
commit04d4cc4afbaca24f32eabff4ff1558028259fc20 authorSönke Hahn <soenkehahn@gmail.com> dateSat 23 Jul 2016, 21:50 (10 years ago) parent33248e3
3 files changed+48−32
wai-app-static/Network/Wai/Application/Static.hs+36−32 wai-app-static/test/WaiAppStaticTest.hs+11 wai-app-static/wai-app-static.cabal+1
wai-app-static/Network/Wai/Application/Static.hs+36−32
@@ -87,14 +87,14 @@ serveFolder StaticSettings {..} pieces req folder@Folder {..} =
8787 Nothing -> return $ WaiResponse $ W.responseLBS H.status403
8888 [ ("Content-Type", "text/plain")
8989 ] "Directory listings disabled"
90+
91+addTrailingSlash :: W.Request -> Maybe ByteString
92+addTrailingSlash req
93+ | S8.null rp = Just "/"
94+ | S8.last rp == '/' = Nothing
95+ | otherwise = Just $ S8.snoc rp '/'
9096 where
91− addTrailingSlash :: W.Request -> Maybe ByteString
92− addTrailingSlash req
93− | S8.null rp = Just "/"
94− | S8.last rp == '/' = Nothing
95− | otherwise = Just $ S8.snoc rp '/'
96− where
97− rp = W.rawPathInfo req
97+ rp = W.rawPathInfo req
9898
9999checkPieces :: StaticSettings
100100 -> Pieces -- ^ parsed request
@@ -108,45 +108,49 @@ checkPieces _ pieces _ | any (T.null . fromPiece) $ safeInit pieces =
108108checkPieces ss@StaticSettings {..} pieces req = do
109109 res <- lookupResult
110110 case res of
111− Left location -> return $ RawRedirect $ TE.encodeUtf8 location
111+ Left location -> return $ RawRedirect location
112112 Right LRNotFound -> return NotFound
113113 Right (LRFile file) -> serveFile ss req file
114114 Right (LRFolder folder) -> serveFolder ss pieces req folder
115115 where
116− lookupResult :: IO (Either Text LookupResult)
116+ lookupResult :: IO (Either ByteString LookupResult)
117117 lookupResult = do
118118 nonIndexResult <- ssLookupFile pieces
119119 case nonIndexResult of
120120 LRFile{} -> return $ Right nonIndexResult
121121 _ -> do
122− indexResult <- lookupIndices (map (\ index -> dropLastIfNull pieces ++ [index]) ssIndices)
123− return $ case indexResult of
124− LRNotFound -> Right nonIndexResult
125− LRFile file | ssRedirectToIndex ->
126− let relPath =
127− case reverse pieces of
128− -- Served at root
129− [] -> fromPiece $ fileName file
130− lastSegment:_ ->
131− case fromPiece lastSegment of
132− -- Ends with a trailing slash
133− "" -> fromPiece $ fileName file
134− -- Lacks a trailing slash
135− lastSegment' -> T.concat
136− [ lastSegment'
137− , "/"
138− , fromPiece $ fileName file
139− ]
140− in Left relPath
141− _ -> Right indexResult
122+ eIndexResult <- lookupIndices (map (\ index -> dropLastIfNull pieces ++ [index]) ssIndices)
123+ return $ case eIndexResult of
124+ Left redirect -> Left redirect
125+ Right indexResult -> case indexResult of
126+ LRNotFound -> Right nonIndexResult
127+ LRFile file | ssRedirectToIndex ->
128+ let relPath =
129+ case reverse pieces of
130+ -- Served at root
131+ [] -> fromPiece $ fileName file
132+ lastSegment:_ ->
133+ case fromPiece lastSegment of
134+ -- Ends with a trailing slash
135+ "" -> fromPiece $ fileName file
136+ -- Lacks a trailing slash
137+ lastSegment' -> T.concat
138+ [ lastSegment'
139+ , "/"
140+ , fromPiece $ fileName file
141+ ]
142+ in Left $ TE.encodeUtf8 relPath
143+ _ -> Right indexResult
142144
143− lookupIndices :: [Pieces] -> IO LookupResult
145+ lookupIndices :: [Pieces] -> IO (Either ByteString LookupResult)
144146 lookupIndices (x : xs) = do
145147 res <- ssLookupFile x
146148 case res of
147149 LRNotFound -> lookupIndices xs
148− _ -> return res
149− lookupIndices [] = return LRNotFound
150+ _ -> return $ case (ssAddTrailingSlash, addTrailingSlash req) of
151+ (True, Just redirect) -> Left redirect
152+ _ -> Right res
153+ lookupIndices [] = return $ Right LRNotFound
150154
151155serveFile :: StaticSettings -> W.Request -> File -> IO StaticResponse
152156serveFile StaticSettings {..} req file
wai-app-static/test/WaiAppStaticTest.hs+11
@@ -5,6 +5,7 @@ import Network.Wai.Application.Static
55import WaiAppStatic.Types
66
77import Test.Hspec
8+import Test.Mockery.Directory
89import qualified Data.ByteString.Char8 as S8
910-- import qualified Data.ByteString.Lazy.Char8 as L8
1011import System.PosixCompat.Files (getFileStatus, modificationTime)
@@ -136,6 +137,16 @@ spec = do
136137 assertStatus 301 req
137138 assertHeader "Location" "/a/" req
138139
140+ it "works when an index.html is delivered" $ do
141+ let settings = (defaultFileServerSettings "."){
142+ ssAddTrailingSlash = True
143+ }
144+ inTempDirectory $ fileServerAppWithSettings settings $ do
145+ liftIO $ touch "foo/index.html"
146+ req <- request (setRawPathInfo defRequest "/foo")
147+ assertStatus 301 req
148+ assertHeader "Location" "/foo/" req
149+
139150 let urlMapApp = flip runSession $ \req send ->
140151 case pathInfo req of
141152 "subPath":rest ->
wai-app-static/wai-app-static.cabal+1
@@ -101,6 +101,7 @@ test-suite runtests
101101 , zlib
102102 , filepath
103103 , temporary
104+ , mockery
104105 -- , containers
105106 ghc-options: -Wall
106107