WAI 2.0 updates

This commit is contained in:
Michael Snoyman 2013-11-10 16:49:26 +02:00
parent 6f495fc758
commit d34c3f26dc
7 changed files with 77 additions and 45 deletions

View File

@ -67,7 +67,12 @@ import qualified Config as GHC
import Data.Conduit.Network (HostPreference (HostIPv4), import Data.Conduit.Network (HostPreference (HostIPv4),
bindPort) bindPort)
import Network (withSocketsDo) import Network (withSocketsDo)
#if MIN_VERSION_http_conduit(2, 0, 0)
import Network.HTTP.Conduit (conduitManagerSettings, newManager)
import Data.Default (def)
#else
import Network.HTTP.Conduit (def, newManager) import Network.HTTP.Conduit (def, newManager)
#endif
import Network.HTTP.ReverseProxy (ProxyDest (ProxyDest), import Network.HTTP.ReverseProxy (ProxyDest (ProxyDest),
waiProxyToSettings, wpsTimeout, wpsOnExc) waiProxyToSettings, wpsTimeout, wpsOnExc)
#if MIN_VERSION_http_reverse_proxy(0, 2, 0) #if MIN_VERSION_http_reverse_proxy(0, 2, 0)
@ -121,7 +126,11 @@ cabalProgram opts | isCabalDev opts = "cabal-dev"
-- 3001, give an appropriate message to the user. -- 3001, give an appropriate message to the user.
reverseProxy :: DevelOpts -> I.IORef Int -> IO () reverseProxy :: DevelOpts -> I.IORef Int -> IO ()
reverseProxy opts iappPort = do reverseProxy opts iappPort = do
#if MIN_VERSION_http_conduit(2, 0, 0)
manager <- newManager conduitManagerSettings
#else
manager <- newManager def manager <- newManager def
#endif
let loop = forever $ do let loop = forever $ do
run (develPort opts) $ waiProxyToSettings run (develPort opts) $ waiProxyToSettings
(const $ do (const $ do

View File

@ -87,6 +87,7 @@ executable yesod
, transformers , transformers
, warp >= 1.3.7.5 , warp >= 1.3.7.5
, wai >= 1.4 , wai >= 1.4
, data-default
ghc-options: -Wall -threaded ghc-options: -Wall -threaded
main-is: main.hs main-is: main.hs

View File

@ -146,6 +146,7 @@ warp :: YesodDispatch site => Int -> site -> IO ()
warp port site = toWaiApp site >>= Network.Wai.Handler.Warp.runSettings warp port site = toWaiApp site >>= Network.Wai.Handler.Warp.runSettings
Network.Wai.Handler.Warp.defaultSettings Network.Wai.Handler.Warp.defaultSettings
{ Network.Wai.Handler.Warp.settingsPort = port { Network.Wai.Handler.Warp.settingsPort = port
{- FIXME
, Network.Wai.Handler.Warp.settingsServerName = S8.pack $ concat , Network.Wai.Handler.Warp.settingsServerName = S8.pack $ concat
[ "Warp/" [ "Warp/"
, Network.Wai.Handler.Warp.warpVersion , Network.Wai.Handler.Warp.warpVersion
@ -153,6 +154,7 @@ warp port site = toWaiApp site >>= Network.Wai.Handler.Warp.runSettings
, showVersion Paths_yesod_core.version , showVersion Paths_yesod_core.version
, " (core)" , " (core)"
] ]
-}
} }
-- | A default set of middlewares. -- | A default set of middlewares.

View File

@ -195,6 +195,9 @@ import Control.Failure (failure)
import Blaze.ByteString.Builder (Builder) import Blaze.ByteString.Builder (Builder)
import Safe (headMay) import Safe (headMay)
import Data.CaseInsensitive (CI) import Data.CaseInsensitive (CI)
#if MIN_VERSION_wai(2, 0, 0)
import qualified System.PosixCompat.Files as PC
#endif
get :: MonadHandler m => m GHState get :: MonadHandler m => m GHState
get = liftHandlerT $ HandlerT $ I.readIORef . handlerState get = liftHandlerT $ HandlerT $ I.readIORef . handlerState
@ -499,8 +502,17 @@ sendFilePart :: MonadHandler m
-> Integer -- ^ offset -> Integer -- ^ offset
-> Integer -- ^ count -> Integer -- ^ count
-> m a -> m a
sendFilePart ct fp off count = sendFilePart ct fp off count = do
#if MIN_VERSION_wai(2, 0, 0)
fs <- liftIO $ PC.getFileStatus fp
handlerError $ HCSendFile ct fp $ Just W.FilePart
{ W.filePartOffset = off
, W.filePartByteCount = count
, W.filePartFileSize = fromIntegral $ PC.fileSize fs
}
#else
handlerError $ HCSendFile ct fp $ Just $ W.FilePart off count handlerError $ HCSendFile ct fp $ Just $ W.FilePart off count
#endif
-- | Bypass remaining handler code and output the given content with a 200 -- | Bypass remaining handler code and output the given content with a 200
-- status code. -- status code.

View File

@ -15,8 +15,10 @@ import qualified Data.CaseInsensitive as CI
import Network.Wai import Network.Wai
#if MIN_VERSION_wai(2, 0, 0) #if MIN_VERSION_wai(2, 0, 0)
import Data.Conduit (transPipe) import Data.Conduit (transPipe)
import Control.Monad.Trans.Resource (runInternalState) import Control.Monad.Trans.Resource (runInternalState, getInternalState, runResourceT, InternalState, closeInternalState)
import Control.Monad.Trans.Class (lift)
import Network.Wai.Internal import Network.Wai.Internal
import Control.Exception (finally)
#endif #endif
import Prelude hiding (catch) import Prelude hiding (catch)
import Web.Cookie (renderSetCookie) import Web.Cookie (renderSetCookie)
@ -32,14 +34,30 @@ import qualified Data.Map as Map
import Yesod.Core.Internal.Request (tokenKey) import Yesod.Core.Internal.Request (tokenKey)
import Data.Text.Encoding (encodeUtf8) import Data.Text.Encoding (encodeUtf8)
yarToResponse :: Monad m yarToResponse :: YesodResponse
=> YesodResponse -> (SessionMap -> IO [Header]) -- ^ save session
-> (SessionMap -> m [Header]) -- ^ save session
-> YesodRequest -> YesodRequest
-> Request -> Request
-> m Response #if MIN_VERSION_wai(2, 0, 0)
-> InternalState
#endif
-> IO Response
#if MIN_VERSION_wai(2, 0, 0)
yarToResponse (YRWai a) _ _ _ is =
case a of
ResponseSource s hs w -> return $ ResponseSource s hs $ \f ->
w f `finally` closeInternalState is
_ -> do
closeInternalState is
return a
#else
yarToResponse (YRWai a) _ _ _ = return a yarToResponse (YRWai a) _ _ _ = return a
yarToResponse (YRPlain s' hs ct c newSess) saveSession yreq req = do #endif
yarToResponse (YRPlain s' hs ct c newSess) saveSession yreq req
#if MIN_VERSION_wai(2, 0, 0)
is
#endif
= do
extraHeaders <- do extraHeaders <- do
let nsToken = maybe let nsToken = maybe
newSess newSess
@ -50,17 +68,29 @@ yarToResponse (YRPlain s' hs ct c newSess) saveSession yreq req = do
let finalHeaders = extraHeaders ++ map headerToPair hs let finalHeaders = extraHeaders ++ map headerToPair hs
finalHeaders' len = ("Content-Length", S8.pack $ show len) finalHeaders' len = ("Content-Length", S8.pack $ show len)
: finalHeaders : finalHeaders
#if MIN_VERSION_wai(2, 0, 0)
let go (ContentBuilder b mlen) = do
let hs' = maybe finalHeaders finalHeaders' mlen
closeInternalState is
return $ ResponseBuilder s hs' b
go (ContentFile fp p) = do
closeInternalState is
return $ ResponseFile s finalHeaders fp p
go (ContentSource body) = return $ ResponseSource s finalHeaders $ \f ->
f (transPipe (flip runInternalState is) body) `finally`
closeInternalState is
go (ContentDontEvaluate c') = go c'
go c
#else
let go (ContentBuilder b mlen) = let go (ContentBuilder b mlen) =
let hs' = maybe finalHeaders finalHeaders' mlen let hs' = maybe finalHeaders finalHeaders' mlen
in ResponseBuilder s hs' b in ResponseBuilder s hs' b
go (ContentFile fp p) = ResponseFile s finalHeaders fp p go (ContentFile fp p) = ResponseFile s finalHeaders fp p
#if MIN_VERSION_wai(2, 0, 0)
go (ContentSource body) = ResponseSource s finalHeaders $ transPipe (flip runInternalState $ resourceInternalState req) body
#else
go (ContentSource body) = ResponseSource s finalHeaders body go (ContentSource body) = ResponseSource s finalHeaders body
#endif
go (ContentDontEvaluate c') = go c' go (ContentDontEvaluate c') = go c'
return $ go c return $ go c
#endif
where where
s s
| s' == defaultStatus = H.status200 | s' == defaultStatus = H.status200

View File

@ -10,13 +10,13 @@ module Yesod.Core.Internal.Run where
import Yesod.Core.Internal.Response import Yesod.Core.Internal.Response
import Blaze.ByteString.Builder (toByteString) import Blaze.ByteString.Builder (toByteString)
import Control.Applicative ((<$>)) import Control.Applicative ((<$>))
import Control.Exception (fromException) import Control.Exception (fromException, bracketOnError)
import Control.Exception.Lifted (catch) import Control.Exception.Lifted (catch)
import Control.Monad.IO.Class (MonadIO) import Control.Monad.IO.Class (MonadIO)
import Control.Monad.IO.Class (liftIO) import Control.Monad.IO.Class (liftIO)
import Control.Monad.Logger (LogLevel (LevelError), LogSource, import Control.Monad.Logger (LogLevel (LevelError), LogSource,
liftLoc) liftLoc)
import Control.Monad.Trans.Resource (runResourceT, withInternalState, runInternalState, getInternalState) import Control.Monad.Trans.Resource (runResourceT, withInternalState, runInternalState, createInternalState, closeInternalState)
import qualified Data.ByteString as S import qualified Data.ByteString as S
import qualified Data.ByteString.Char8 as S8 import qualified Data.ByteString.Char8 as S8
import qualified Data.IORef as I import qualified Data.IORef as I
@ -165,16 +165,9 @@ runFakeHandler fakeSessionMap logger site handler = liftIO $ do
ret <- I.newIORef (Left $ InternalError "runFakeHandler: no result") ret <- I.newIORef (Left $ InternalError "runFakeHandler: no result")
let handler' = do liftIO . I.writeIORef ret . Right =<< handler let handler' = do liftIO . I.writeIORef ret . Right =<< handler
return () return ()
#if MIN_VERSION_wai(2, 0, 0)
let yapp internalState = runHandler
#else
let yapp = runHandler let yapp = runHandler
#endif
RunHandlerEnv RunHandlerEnv
{ rheRender = yesodRender site $ resolveApproot site $ fakeWaiRequest { rheRender = yesodRender site $ resolveApproot site fakeWaiRequest
#if MIN_VERSION_wai(2, 0, 0)
internalState
#endif
, rheRoute = Nothing , rheRoute = Nothing
, rheSite = site , rheSite = site
, rheUpload = fileUpload site , rheUpload = fileUpload site
@ -190,18 +183,13 @@ runFakeHandler fakeSessionMap logger site handler = liftIO $ do
typePlain typePlain
(toContent ("runFakeHandler: errHandler" :: S8.ByteString)) (toContent ("runFakeHandler: errHandler" :: S8.ByteString))
(reqSession req) (reqSession req)
fakeWaiRequest fakeWaiRequest = Request
#if MIN_VERSION_wai(2, 0, 0)
internalState
#endif
=
Request
{ requestMethod = "POST" { requestMethod = "POST"
, httpVersion = H.http11 , httpVersion = H.http11
, rawPathInfo = "/runFakeHandler/pathInfo" , rawPathInfo = "/runFakeHandler/pathInfo"
, rawQueryString = "" , rawQueryString = ""
#if MIN_VERSION_wai(2, 0, 0) #if MIN_VERSION_wai(2, 0, 0)
, resourceInternalState = internalState , requestHeaderHost = Nothing
#else #else
, serverName = "runFakeHandler-serverName" , serverName = "runFakeHandler-serverName"
, serverPort = 80 , serverPort = 80
@ -215,30 +203,17 @@ runFakeHandler fakeSessionMap logger site handler = liftIO $ do
, vault = mempty , vault = mempty
, requestBodyLength = KnownLength 0 , requestBodyLength = KnownLength 0
} }
#if MIN_VERSION_wai(2, 0, 0)
fakeRequest internalState =
#else
fakeRequest = fakeRequest =
#endif
YesodRequest YesodRequest
{ reqGetParams = [] { reqGetParams = []
, reqCookies = [] , reqCookies = []
, reqWaiRequest = fakeWaiRequest , reqWaiRequest = fakeWaiRequest
#if MIN_VERSION_wai(2, 0, 0)
internalState
#endif
, reqLangs = [] , reqLangs = []
, reqToken = Just "NaN" -- not a nonce =) , reqToken = Just "NaN" -- not a nonce =)
, reqAccept = [] , reqAccept = []
, reqSession = fakeSessionMap , reqSession = fakeSessionMap
} }
#if MIN_VERSION_wai(2, 0, 0)
_ <- runResourceT $ do
is <- getInternalState
yapp is $ fakeRequest is
#else
_ <- runResourceT $ yapp fakeRequest _ <- runResourceT $ yapp fakeRequest
#endif
I.readIORef ret I.readIORef ret
{-# WARNING runFakeHandler "Usually you should *not* use runFakeHandler unless you really understand how it works and why you need it." #-} {-# WARNING runFakeHandler "Usually you should *not* use runFakeHandler unless you really understand how it works and why you need it." #-}
@ -275,12 +250,14 @@ yesodRunner handler' YesodRunnerEnv {..} route req
rhe = rheSafe rhe = rheSafe
{ rheOnError = runHandler rheSafe . errorHandler { rheOnError = runHandler rheSafe . errorHandler
} }
yar <-
#if MIN_VERSION_wai(2, 0, 0) #if MIN_VERSION_wai(2, 0, 0)
flip runInternalState (resourceInternalState req) $ bracketOnError createInternalState closeInternalState $ \is -> do
#endif yar <- runInternalState (runHandler rhe handler yreq) is
runHandler rhe handler yreq liftIO $ yarToResponse yar saveSession yreq req is
#else
yar <- runHandler rhe handler yreq
liftIO $ yarToResponse yar saveSession yreq req liftIO $ yarToResponse yar saveSession yreq req
#endif
where where
mmaxLen = maximumContentLength yreSite route mmaxLen = maximumContentLength yreSite route
handler = yesodMiddleware handler' handler = yesodMiddleware handler'

View File

@ -65,6 +65,7 @@ library
, data-default , data-default
, safe , safe
, warp >= 1.3.8 , warp >= 1.3.8
, unix-compat
exposed-modules: Yesod.Core exposed-modules: Yesod.Core
Yesod.Core.Content Yesod.Core.Content