wai-extra 3.1.9 → 3.1.10
raw patch · 5 files changed
+168/−3 lines, 5 filesdep ~http2
Dependency ranges changed: http2
Files
- ChangeLog.md +4/−0
- Network/Wai/Handler/CGI.hs +2/−2
- Network/Wai/Middleware/Select.hs +91/−0
- test/Network/Wai/Middleware/SelectSpec.hs +64/−0
- wai-extra.cabal +7/−1
ChangeLog.md view
@@ -1,5 +1,9 @@ # Changelog for wai-extra +## 3.1.10++* Added `Select` to choose between `Middleware`s [#878](https://github.com/yesodweb/wai/pull/878)+ ## 3.1.9 * Added `HealthCheckEndpoint` `Middleware`s for health check [#877](https://github.com/yesodweb/wai/pull/877)
Network/Wai/Handler/CGI.hs view
@@ -31,11 +31,11 @@ import Network.Socket (addrAddress, getAddrInfo) import Network.Wai import Network.Wai.Internal+import System.IO (Handle)+import qualified System.IO #if WINDOWS import System.Environment (getEnvironment) #else-import System.IO (Handle)-import qualified System.IO import qualified System.Posix.Env.ByteString as Env getEnvironment :: IO [(String, String)]
+ Network/Wai/Middleware/Select.hs view
@@ -0,0 +1,91 @@+---------------------------------------------------------+-- |+-- Module : Network.Wai.Middleware.Select+-- Copyright : Michael Snoyman+-- License : BSD3+--+-- Maintainer : Michael Snoyman <michael@snoyman.com>+-- Stability : Unstable+-- Portability : portable+--+-- Dynamically choose between Middlewares+--+-- It's useful when you want some 'Middleware's applied selectively.+--+-- Example: do not log health check calls:+--+-- > import Network.Wai+-- > import Network.Wai.Middleware.HealthCheckEndpoint+-- > import Network.Wai.Middleware.RequestLogger+-- >+-- > app' :: Application+-- > app' =+-- > selectMiddleware (selectMiddlewareExceptRawPathInfo "/_healthz" logStdout)+-- > $ healthCheck app+--+-- @since 3.1.10+--+---------------------------------------------------------+module Network.Wai.Middleware.Select+ ( -- * Middleware selection+ MiddlewareSelection (..),+ selectMiddleware,++ -- * Helpers+ selectMiddlewareOn,+ selectMiddlewareOnRawPathInfo,+ selectMiddlewareExceptRawPathInfo,+ passthroughMiddleware,+ )+where++import Control.Applicative ((<|>))+import Data.ByteString (ByteString)+import Data.Maybe (fromMaybe)+import Network.Wai++--------------------------------------------------+-- * Middleware selection+--------------------------------------------------++-- | Relevant Middleware for a given 'Request'.+newtype MiddlewareSelection = MiddlewareSelection+ { applySelectedMiddleware :: Request -> Maybe Middleware+ }++instance Semigroup MiddlewareSelection where+ MiddlewareSelection f <> MiddlewareSelection g =+ MiddlewareSelection $ \req -> f req <|> g req++instance Monoid MiddlewareSelection where+ mempty = MiddlewareSelection $ const Nothing++-- | Create the 'Middleware' dynamically applying 'MiddlewareSelection'.+selectMiddleware :: MiddlewareSelection -> Middleware+selectMiddleware selection app request respond =+ mw app request respond+ where+ mw :: Middleware+ mw = fromMaybe passthroughMiddleware (applySelectedMiddleware selection request)++--------------------------------------------------+-- * Helpers+--------------------------------------------------++passthroughMiddleware :: Middleware+passthroughMiddleware = id++-- | Use the 'Middleware' when the predicate holds.+selectMiddlewareOn :: (Request -> Bool) -> Middleware -> MiddlewareSelection+selectMiddlewareOn doesApply mw = MiddlewareSelection $ \request ->+ if doesApply request+ then Just mw+ else Nothing++-- | Use the `Middleware` for the given 'rawPathInfo'.+selectMiddlewareOnRawPathInfo :: ByteString -> Middleware -> MiddlewareSelection+selectMiddlewareOnRawPathInfo path = selectMiddlewareOn ((== path) . rawPathInfo)++-- | Use the `Middleware` for all 'rawPathInfo' except then given one.+selectMiddlewareExceptRawPathInfo :: ByteString -> Middleware -> MiddlewareSelection+selectMiddlewareExceptRawPathInfo path = selectMiddlewareOn ((/= path) . rawPathInfo)
+ test/Network/Wai/Middleware/SelectSpec.hs view
@@ -0,0 +1,64 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE OverloadedStrings #-}++module Network.Wai.Middleware.SelectSpec+ ( main,+ spec,+ )+where++import Data.ByteString (ByteString)+#if __GLASGOW_HASKELL__ < 804+import Data.Monoid ((<>))+#endif+import Network.HTTP.Types (Status, status200, status401, status500)+import Network.Wai+import Network.Wai.Middleware.Select+import Network.Wai.Test (SResponse (simpleStatus), request, runSession)+import Test.Hspec++main :: IO ()+main = hspec spec++spec :: Spec+spec = describe "Select" $ do+ it "With empty select should passthrough" $+ runApp (selectMiddleware mempty) "/" `shouldReturn` status200+ it "With other path select should passthrough" $+ runApp (selectMiddleware $ selectOverride "/_" status401) "/" `shouldReturn` status200+ it "With path select should hit override" $+ runApp (selectMiddleware $ selectOverride "/_" status401) "/_" `shouldReturn` status401+ it "With twice path select should hit first override" $+ runApp (selectMiddleware $ selectOverride "/_" status401 <> selectOverride "/_" status500) "/_"+ `shouldReturn` status401+ it "With two paths select should hit first matching (first)" $+ runApp (selectMiddleware $ selectOverride "/_" status401 <> selectOverride "/-" status500) "/_"+ `shouldReturn` status401+ it "With two paths select should hit first matching (last)" $+ runApp (selectMiddleware $ selectOverride "/_" status401 <> selectOverride "/-" status500) "/-"+ `shouldReturn` status500+ it "With other two paths select should passthrough" $+ runApp (selectMiddleware $ selectOverride "/_" status401 <> selectOverride "/-" status500) "/"+ `shouldReturn` status200+ it "With mempty then the path select should hit the pass" $+ runApp (selectMiddleware $ mempty <> selectOverride "/-" status500) "/-"+ `shouldReturn` status500++runApp :: Middleware -> ByteString -> IO Status+runApp mw path =+ fmap simpleStatus $+ runSession+ (request $ defaultRequest {rawPathInfo = path})+ $ mw app++app :: Application+app = constApp status200++constApp :: Status -> Application+constApp status _ respond = respond $ responseLBS status [] ""++overrideMiddleware :: Application -> Middleware+overrideMiddleware = const++selectOverride :: ByteString -> Status -> MiddlewareSelection+selectOverride path status = selectMiddlewareOnRawPathInfo path $ overrideMiddleware $ constApp status
wai-extra.cabal view
@@ -1,5 +1,5 @@ Name: wai-extra-Version: 3.1.9+Version: 3.1.10 Synopsis: Provides some basic WAI handlers and middleware. description: Provides basic WAI handler and middleware functionality:@@ -57,6 +57,10 @@ . Rewrite request path info based on a custom conversion rules. .+ * Select+ .+ Dynamically choose between Middlewares.+ . * Stream Files . Convert ResponseFile type responses into ResponseStream type.@@ -137,6 +141,7 @@ Network.Wai.Middleware.Local Network.Wai.Middleware.RequestLogger Network.Wai.Middleware.RequestLogger.JSON+ Network.Wai.Middleware.Select Network.Wai.Middleware.Gzip Network.Wai.Middleware.Jsonp Network.Wai.Middleware.MethodOverride@@ -192,6 +197,7 @@ Network.Wai.Middleware.RealIpSpec Network.Wai.Middleware.RequestSizeLimitSpec Network.Wai.Middleware.RoutedSpec+ Network.Wai.Middleware.SelectSpec Network.Wai.Middleware.StripHeadersSpec Network.Wai.Middleware.TimeoutSpec WaiExtraSpec