packages feed

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 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