packages feed

yesod-core 1.1.0.1 → 1.1.1

raw patch · 4 files changed

+147/−1 lines, 4 filesPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

API changes (from Hackage documentation)

+ Yesod.Core: runFakeHandler :: (Yesod master, MonadIO m) => SessionMap -> (master -> Logger) -> master -> GHandler master master a -> m (Either ErrorResponse a)
+ Yesod.Handler: handlerToIO :: MonadIO m => GHandler sub master (GHandler sub master a -> m a)
- Yesod.Core: class RenderRoute a => Yesod a where approot = ApprootRelative errorHandler = defaultErrorHandler defaultLayout w = do { p <- widgetToPageContent w; mmsg <- getMessage; hamletToRepHtml (\ _render_axBv -> do { id ((preEscapedText . pack) "<!DOCTYPE html>\ \<html><head><style type="text/css">#synopsis details:not([open]) > ul { visibility: hidden; }</style><title>"); id (toHtml (pageTitle p)); id ((preEscapedText . pack) "</title>"); asHtmlUrl (pageHead p) _render_axBv; id ((preEscapedText . pack) "</head><body>"); maybeH mmsg (\ msg_axBw -> do { id ((preEscapedText . pack) "<p class=\"message\">"); id (toHtml msg_axBw); id ((preEscapedText . pack) "</p>") }) Nothing; asHtmlUrl (pageBody p) _render_axBv; id ((preEscapedText . pack) "</body></html>") }) } urlRenderOverride _ _ = Nothing isAuthorized _ _ = return Authorized isWriteRequest _ = do { wai <- waiRequest; return $ requestMethod wai `notElem` ["GET", "HEAD", "OPTIONS", "TRACE"] } authRoute _ = Nothing cleanPath _ s = if corrected == s then Right s else Left corrected where corrected = filter (not . null) s joinPath _ ar pieces' qs' = fromText ar `mappend` encodePath pieces qs where pieces = if null pieces' then [""] else pieces' qs = map (encodeUtf8 *** go) qs' go "" = Nothing go x = Just $ encodeUtf8 x addStaticContent _ _ _ = return Nothing cookiePath _ = "/" cookieDomain _ = Nothing maximumContentLength _ _ = 2 * 1024 * 1024 getLogger _ = mkLogger True stdout messageLogger a logger loc level msg = if level < logLevel a then return () else formatLogMessage (loggerDate logger) loc level msg >>= loggerPutStr logger logLevel _ = LevelInfo gzipSettings _ = def jsLoader _ = BottomOfBody makeSessionBackend _ = do { key <- getKey defaultKeyFile; return $ Just $ clientSessionBackend key 120 } fileUpload _ size | size > 50000 = FileUploadDisk tempFileBackEnd | otherwise = FileUploadMemory lbsBackEnd
+ Yesod.Core: class RenderRoute a => Yesod a where approot = ApprootRelative errorHandler = defaultErrorHandler defaultLayout w = do { p <- widgetToPageContent w; mmsg <- getMessage; hamletToRepHtml (\ _render_axbW -> do { id ((preEscapedText . pack) "<!DOCTYPE html>\ \<html><head><style type="text/css">#synopsis details:not([open]) > ul { visibility: hidden; }</style><title>"); id (toHtml (pageTitle p)); id ((preEscapedText . pack) "</title>"); asHtmlUrl (pageHead p) _render_axbW; id ((preEscapedText . pack) "</head><body>"); maybeH mmsg (\ msg_axbX -> do { id ((preEscapedText . pack) "<p class=\"message\">"); id (toHtml msg_axbX); id ((preEscapedText . pack) "</p>") }) Nothing; asHtmlUrl (pageBody p) _render_axbW; id ((preEscapedText . pack) "</body></html>") }) } urlRenderOverride _ _ = Nothing isAuthorized _ _ = return Authorized isWriteRequest _ = do { wai <- waiRequest; return $ requestMethod wai `notElem` ["GET", "HEAD", "OPTIONS", "TRACE"] } authRoute _ = Nothing cleanPath _ s = if corrected == s then Right s else Left corrected where corrected = filter (not . null) s joinPath _ ar pieces' qs' = fromText ar `mappend` encodePath pieces qs where pieces = if null pieces' then [""] else pieces' qs = map (encodeUtf8 *** go) qs' go "" = Nothing go x = Just $ encodeUtf8 x addStaticContent _ _ _ = return Nothing cookiePath _ = "/" cookieDomain _ = Nothing maximumContentLength _ _ = 2 * 1024 * 1024 getLogger _ = mkLogger True stdout messageLogger a logger loc level msg = if level < logLevel a then return () else formatLogMessage (loggerDate logger) loc level msg >>= loggerPutStr logger logLevel _ = LevelInfo gzipSettings _ = def jsLoader _ = BottomOfBody makeSessionBackend _ = do { key <- getKey defaultKeyFile; return $ Just $ clientSessionBackend key 120 } fileUpload _ size | size > 50000 = FileUploadDisk tempFileBackEnd | otherwise = FileUploadMemory lbsBackEnd

Files

Yesod/Core.hs view
@@ -40,6 +40,7 @@       -- * Misc     , yesodVersion     , yesodRender+    , runFakeHandler       -- * Re-exports     , module Yesod.Content     , module Yesod.Dispatch
Yesod/Handler.hs view
@@ -95,6 +95,7 @@     , newIdent       -- * Lifting     , MonadLift (..)+    , handlerToIO       -- * i18n     , getMessageRender       -- * Per-request caching@@ -390,6 +391,68 @@ -- master site. getRouteToMaster :: GHandler sub master (Route sub -> Route master) getRouteToMaster = handlerToMaster `liftM` ask+++-- | Returns a function that runs 'GHandler' actions inside @IO@.+--+-- Sometimes you want to run an inner 'GHandler' action outside+-- the control flow of an HTTP request (on the outer 'GHandler'+-- action).  For example, you may want to spawn a new thread:+--+-- @+-- getFooR :: Handler RepHtml+-- getFooR = do+--   runInnerHandler <- handlerToIO+--   liftIO $ forkIO $ runInnerHandler $ do+--     /Code here runs inside GHandler but on a new thread./+--     /This is the inner GHandler./+--     ...+--   /Code here runs inside the request's control flow./+--   /This is the outer GHandler./+--   ...+-- @+--+-- Another use case for this function is creating a stream of+-- server-sent events using 'GHandler' actions (see+-- @yesod-eventsource@).+--+-- Most of the environment from the outer 'GHandler' is preserved+-- on the inner 'GHandler', however:+--+--  * The request body is cleared (otherwise it would be very+--  difficult to prevent huge memory leaks).+--+--  * The cache is cleared (see 'CacheKey').+--+-- Changes to the response made inside the inner 'GHandler' are+-- ignored (e.g., session variables, cookies, response headers).+-- This allows the inner 'GHandler' to outlive the outer+-- 'GHandler' (e.g., on the @forkIO@ example above, a response+-- may be sent to the client without killing the new thread).+handlerToIO :: MonadIO m => GHandler sub master (GHandler sub master a -> m a)+handlerToIO =+  GHandler $ \oldHandlerData -> do+    -- Let go of the request body, cache and response headers.+    let oldReq    = handlerRequest oldHandlerData+        oldWaiReq = reqWaiRequest oldReq+        newWaiReq = oldWaiReq { W.requestBody = mempty }+        newReq    = oldReq { reqWaiRequest = newWaiReq+                           , reqBodySize   = 0 }+    newState <- liftIO $ do+      oldState <- I.readIORef (handlerState oldHandlerData)+      return $ oldState { ghsRBC = Nothing+                        , ghsIdent = 1+                        , ghsCache = mempty+                        , ghsHeaders = mempty }++    -- Return GHandler running function.+    return $ \(GHandler f) -> liftIO $ do+      -- The state IORef needs to be created here, otherwise it+      -- will be shared by different invocations of this function.+      newStateIORef <- I.newIORef newState+      runResourceT $ f oldHandlerData { handlerRequest = newReq+                                      , handlerState   = newStateIORef }+  -- | Function used internally by Yesod in the process of converting a -- 'GHandler' into an 'W.Application'. Should not be needed by users.
Yesod/Internal/Core.hs view
@@ -36,6 +36,7 @@     , resolveApproot     , Approot (..)     , FileUpload (..)+    , runFakeHandler     ) where  import Yesod.Content@@ -55,6 +56,7 @@ import qualified Web.ClientSession as CS import qualified Data.ByteString.Char8 as S8 import qualified Data.ByteString.Lazy as L+import qualified Data.IORef as I import Data.Monoid import Text.Hamlet import Text.Julius@@ -64,6 +66,7 @@ import Data.Text.Lazy.Encoding (encodeUtf8) import Data.Maybe (fromMaybe, isJust) import Control.Monad.IO.Class (MonadIO (liftIO))+import Control.Monad.Trans.Resource (runResourceT) import Web.Cookie (parseCookies) import qualified Data.Map as Map import Data.Time@@ -752,3 +755,82 @@           expires = fromIntegral (timeout * 60) `addUTCTime` now'           sessionVal iv = encodeClientSession key iv expires host sess' ++-- | Run a 'GHandler' completely outside of Yesod.  This+-- function comes with many caveats and you shouldn't use it+-- unless you fully understand what it's doing and how it works.+--+-- As of now, there's only one reason to use this function at+-- all: in order to run unit tests of functions inside 'GHandler'+-- but that aren't easily testable with a full HTTP request.+-- Even so, it's better to use @wai-test@ or @yesod-test@ instead+-- of using this function.+--+-- This function will create a fake HTTP request (both @wai@'s+-- 'W.Request' and @yesod@'s 'Request') and feed it to the+-- @GHandler@.  The only useful information the @GHandler@ may+-- get from the request is the session map, which you must supply+-- as argument to @runFakeHandler@.  All other fields contain+-- fake information, which means that they can be accessed but+-- won't have any useful information.  The response of the+-- @GHandler@ is completely ignored, including changes to the+-- session, cookies or headers.  We only return you the+-- @GHandler@'s return value.+runFakeHandler :: (Yesod master, MonadIO m) =>+                  SessionMap+               -> (master -> Logger)+               -> master+               -> GHandler master master a+               -> m (Either ErrorResponse a)+runFakeHandler fakeSessionMap logger master handler = liftIO $ do+  ret <- I.newIORef (Left $ InternalError "runFakeHandler: no result")+  let handler' = do liftIO . I.writeIORef ret . Right =<< handler+                    return ()+  let YesodApp yapp =+        runHandler+          handler'+          (yesodRender master "")+          Nothing+          id+          master+          master+          (fileUpload master)+          (messageLogger master $ logger master)+      errHandler err =+        YesodApp $ \_ _ _ session -> do+          liftIO $ I.writeIORef ret (Left err)+          return $ YARPlain+                     H.status500+                     []+                     typePlain+                     (toContent ("runFakeHandler: errHandler" :: S8.ByteString))+                     session+      fakeWaiRequest =+        W.Request+          { W.requestMethod  = "POST"+          , W.httpVersion    = H.http11+          , W.rawPathInfo    = "/runFakeHandler/pathInfo"+          , W.rawQueryString = ""+          , W.serverName     = "runFakeHandler-serverName"+          , W.serverPort     = 80+          , W.requestHeaders = []+          , W.isSecure       = False+          , W.remoteHost     = error "runFakeHandler-remoteHost"+          , W.pathInfo       = ["runFakeHandler", "pathInfo"]+          , W.queryString    = []+          , W.requestBody    = mempty+          , W.vault          = mempty+          }+      fakeRequest =+        Request+          { reqGetParams  = []+          , reqCookies    = []+          , reqWaiRequest = fakeWaiRequest+          , reqLangs      = []+          , reqToken      = Just "NaN" -- not a nonce =)+          , reqBodySize   = 0+          }+      fakeContentType = []+  _ <- runResourceT $ yapp errHandler fakeRequest fakeContentType fakeSessionMap+  I.readIORef ret+{-# WARNING runFakeHandler "Usually you should *not* use runFakeHandler unless you really understand how it works and why you need it." #-}
yesod-core.cabal view
@@ -1,5 +1,5 @@ name:            yesod-core-version:         1.1.0.1+version:         1.1.1 license:         MIT license-file:    LICENSE author:          Michael Snoyman <michael@snoyman.com>