packages feed

http-reverse-proxy 0.4.1.3 → 0.4.2

raw patch · 3 files changed

+103/−48 lines, 3 filesdep ~basePVP ok

version bump matches the API change (PVP)

Dependency ranges changed: base

API changes (from Hackage documentation)

+ Network.HTTP.ReverseProxy: data LocalWaiProxySettings
+ Network.HTTP.ReverseProxy: defaultLocalWaiProxySettings :: LocalWaiProxySettings
+ Network.HTTP.ReverseProxy: instance Default LocalWaiProxySettings
+ Network.HTTP.ReverseProxy: setLpsTimeBound :: Maybe Int -> LocalWaiProxySettings -> LocalWaiProxySettings
+ Network.HTTP.ReverseProxy: wpsGetDest :: WaiProxySettings -> Maybe (Request -> IO (LocalWaiProxySettings, WaiProxyResponse))

Files

ChangeLog.md view
@@ -1,3 +1,7 @@+## 0.4.2++*  Add configurable timeouts [#8](https://github.com/fpco/http-reverse-proxy/pull/8)+ ## 0.4.1.3  * Include README.md and ChangeLog.md
Network/HTTP/ReverseProxy.hs view
@@ -1,4 +1,9 @@-{-# LANGUAGE OverloadedStrings, FlexibleContexts, ScopedTypeVariables #-}+{-# LANGUAGE FlexibleContexts      #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE OverloadedStrings     #-}+{-# LANGUAGE ScopedTypeVariables   #-}+{-# LANGUAGE LambdaCase            #-}+{-# LANGUAGE TupleSections         #-} module Network.HTTP.ReverseProxy     ( -- * Types       ProxyDest (..)@@ -17,49 +22,55 @@     , wpsSetIpHeader     , wpsProcessBody     , wpsUpgradeToRaw+    , wpsGetDest     , SetIpHeader (..)+      -- *** Local settings+    , LocalWaiProxySettings+    , defaultLocalWaiProxySettings+    , setLpsTimeBound     {- FIXME       -- * WAI to Raw     , waiToRaw     -}     ) where -import Data.Conduit-import Data.Streaming.Network (readLens, AppData)-import Data.Functor.Identity (Identity (..))-import Data.Maybe (fromMaybe)-import Control.Monad.Trans.Control (MonadBaseControl)-import Data.Default.Class (def)-import qualified Network.Wai as WAI-import qualified Network.HTTP.Client as HC-import Network.HTTP.Client (BodyReader, brRead)-import Control.Exception (bracket)-import Blaze.ByteString.Builder (fromByteString)-import Data.Word8 (isSpace, _colon, _cr)-import qualified Data.ByteString as S-import qualified Data.ByteString.Char8 as S8-import qualified Network.HTTP.Types as HT-import qualified Data.CaseInsensitive as CI-import qualified Data.Text.Lazy.Encoding as TLE-import qualified Data.Text.Lazy as TL-import qualified Data.Conduit.Network as DCN-import Control.Concurrent.MVar.Lifted (newEmptyMVar, putMVar, takeMVar)-import Control.Concurrent.Lifted (fork, killThread)-import Data.Default.Class (Default (..))-import Network.Wai.Logger (showSockAddr)-import qualified Data.Set as Set-import Data.IORef-import qualified Data.ByteString.Lazy as L-import Control.Concurrent.Async (concurrently)-import Blaze.ByteString.Builder (Builder, toLazyByteString)-import Data.ByteString (ByteString)-import Control.Monad.IO.Class (MonadIO, liftIO)-import Control.Monad (unless, void)-import Data.Monoid (mappend, (<>), mconcat)-import Control.Exception.Lifted (try, SomeException, finally)-import Control.Applicative ((<$>), (<|>))-import Data.Set (Set)-import qualified Data.Conduit.List as CL+import           Blaze.ByteString.Builder       (Builder, fromByteString,+                                                 toLazyByteString)+import           Control.Applicative            ((<$>), (<|>))+import           Control.Concurrent.Async       (concurrently)+import           Control.Concurrent.Lifted      (fork, killThread)+import           Control.Concurrent.MVar.Lifted (newEmptyMVar, putMVar,+                                                 takeMVar)+import           Control.Exception              (bracket)+import           Control.Exception.Lifted       (SomeException, finally, try)+import           Control.Monad                  (unless, void)+import           Control.Monad.IO.Class         (MonadIO, liftIO)+import           Control.Monad.Trans.Control    (MonadBaseControl)+import           Data.ByteString                (ByteString)+import qualified Data.ByteString                as S+import qualified Data.ByteString.Char8          as S8+import qualified Data.ByteString.Lazy           as L+import qualified Data.CaseInsensitive           as CI+import           Data.Conduit+import qualified Data.Conduit.List              as CL+import qualified Data.Conduit.Network           as DCN+import           Data.Default.Class             (Default (..), def)+import           Data.Functor.Identity          (Identity (..))+import           Data.IORef+import           Data.Maybe                     (fromMaybe)+import           Data.Monoid                    (mappend, mconcat, (<>))+import           Data.Set                       (Set)+import qualified Data.Set                       as Set+import           Data.Streaming.Network         (AppData, readLens)+import qualified Data.Text.Lazy                 as TL+import qualified Data.Text.Lazy.Encoding        as TLE+import           Data.Word8                     (isSpace, _colon, _cr)+import           Network.HTTP.Client            (BodyReader, brRead)+import qualified Network.HTTP.Client            as HC+import qualified Network.HTTP.Types             as HT+import qualified Network.Wai                    as WAI+import           Network.Wai.Logger             (showSockAddr)+import           System.Timeout.Lifted          (timeout)  -- | Host\/port combination to which we want to proxy. data ProxyDest = ProxyDest@@ -174,6 +185,31 @@            -> WAI.Application waiProxyTo getDest onError = waiProxyToSettings getDest def { wpsOnExc = onError } +data LocalWaiProxySettings = LocalWaiProxySettings+    { lpsTimeBound :: Maybe Int+    -- ^ Allows to specify the maximum time allowed for the conection on per request basis.+    --+    -- Default: no timeouts+    --+    -- Since 0.4.2+    }+instance Default LocalWaiProxySettings where+    def = LocalWaiProxySettings Nothing++-- | Default value for 'LocalWaiProxySettings', same as 'def' but with a more explicit name.+--+-- Since 0.4.2+defaultLocalWaiProxySettings :: LocalWaiProxySettings+defaultLocalWaiProxySettings = def++-- | Allows to specify the maximum time allowed for the conection on per request basis.+--+-- Default: no timeouts+--+-- Since 0.4.2+setLpsTimeBound :: Maybe Int -> LocalWaiProxySettings -> LocalWaiProxySettings+setLpsTimeBound x s = s { lpsTimeBound = x }+ data WaiProxySettings = WaiProxySettings     { wpsOnExc :: SomeException -> WAI.Application     , wpsTimeout :: Maybe Int@@ -195,6 +231,14 @@     -- Default: check if the upgrade header is websocket.     --     -- Since 0.3.1+    , wpsGetDest :: Maybe (WAI.Request -> IO (LocalWaiProxySettings, WaiProxyResponse))+    -- ^ Allow to override proxy settings for each request.+    -- If you supply this field it will take precedence over+    -- getDest parameter in waiProxyToSettings+    --+    -- Default: have one global setting+    --+    -- Since 0.4.2     }  -- | How to set the X-Real-IP request header.@@ -212,6 +256,7 @@         , wpsProcessBody = const Nothing         , wpsUpgradeToRaw = \req ->             (CI.mk <$> lookup "upgrade" (WAI.requestHeaders req)) == Just "websocket"+        , wpsGetDest = Nothing         }  renderHeaders :: WAI.Request -> HT.RequestHeaders -> Builder@@ -282,16 +327,24 @@                    -> WaiProxySettings                    -> HC.Manager                    -> WAI.Application-waiProxyToSettings getDest wps manager req0 sendResponse = do-    edest' <- getDest req0+waiProxyToSettings getDest wps' manager req0 sendResponse = do+    let wps = wps'{wpsGetDest = wpsGetDest wps' <|> Just (fmap (LocalWaiProxySettings $ wpsTimeout wps',) . getDest)}+    (lps, edest') <- fromMaybe+        (const $ return (def, WPRResponse $ WAI.responseLBS HT.status500 [] "proxy not setup"))+        (wpsGetDest wps)+        req0     let edest =             case edest' of                 WPRResponse res -> Left $ \_req -> ($ res)                 WPRProxyDest pd -> Right (pd, req0)                 WPRModifiedRequest req pd -> Right (pd, req)                 WPRApplication app -> Left app+        timeBound us f =+            timeout us f >>= \case+                Just res -> return res+                Nothing -> sendResponse $ WAI.responseLBS HT.status500 [] "timeBound"     case edest of-        Left app -> app req0 sendResponse+        Left app -> maybe id timeBound (lpsTimeBound lps) $ app req0 sendResponse         Right (ProxyDest host port, req) -> tryWebSockets wps host port req sendResponse $ do             let req' = def                     { HC.method = WAI.requestMethod req@@ -303,7 +356,7 @@                     , HC.requestBody = body                     , HC.redirectCount = 0                     , HC.checkStatus = \_ _ _ -> Nothing-                    , HC.responseTimeout = wpsTimeout wps+                    , HC.responseTimeout = lpsTimeBound lps                     }                 body =                     case WAI.requestBodyLength req of@@ -314,14 +367,12 @@             bracket                 (try $ HC.responseOpen req' manager)                 (either (const $ return ()) HC.responseClose)-                $ \ex -> do-                case ex of+                $ \case                     Left e -> wpsOnExc wps e req sendResponse                     Right res -> do-                        let conduit =-                                case wpsProcessBody wps $ fmap (const ()) res of-                                    Nothing -> awaitForever (\bs -> yield (Chunk $ fromByteString bs) >> yield Flush)-                                    Just conduit' -> conduit'+                        let conduit = fromMaybe+                                        (awaitForever (\bs -> yield (Chunk $ fromByteString bs) >> yield Flush))+                                        (wpsProcessBody wps $ const () <$> res)                             src = bodyReaderSource $ HC.responseBody res                         sendResponse $ WAI.responseStream                             (HC.responseStatus res)
http-reverse-proxy.cabal view
@@ -1,5 +1,5 @@ name:                http-reverse-proxy-version:             0.4.1.3+version:             0.4.2 synopsis:            Reverse proxy HTTP requests, either over raw sockets or with WAI description:         Provides a simple means of reverse-proxying HTTP requests. The raw approach uses the same technique as leveraged by keter, whereas the WAI approach performs full request/response parsing via WAI and http-conduit. homepage:            https://github.com/fpco/http-reverse-proxy