Merge pull request #1243 from mschristiansen/master

Cleanup of yesod-core code
This commit is contained in:
Michael Snoyman 2016-06-28 11:13:50 +03:00 committed by GitHub
commit 8bbe91cbfe
25 changed files with 143 additions and 169 deletions

View File

@ -1,4 +1,3 @@
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE FlexibleContexts #-}
@ -134,11 +133,10 @@ import Text.Blaze.Html (Html, toHtml, preEscapedToMarkup)
import Control.Monad.Logger
import Control.Monad.Trans.Class (MonadTrans (..))
import Yesod.Core.Internal.Session
import Yesod.Core.Internal.Run (yesodRunner)
import Yesod.Core.Internal.Run (yesodRunner, yesodRender)
import Yesod.Core.Class.Yesod
import Yesod.Core.Class.Dispatch
import Yesod.Core.Class.Breadcrumbs
import Yesod.Core.Internal.Run (yesodRender)
import qualified Yesod.Core.Internal.Run
import qualified Paths_yesod_core
import Data.Version (showVersion)

View File

@ -1,7 +1,6 @@
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ViewPatterns #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE FlexibleContexts #-}
@ -25,10 +24,9 @@ class YesodSubDispatch sub m where
-> W.Application
instance YesodSubDispatch WaiSubsite master where
yesodSubDispatch YesodSubRunnerEnv {..} req =
app req
yesodSubDispatch YesodSubRunnerEnv {..} = app
where
WaiSubsite app = ysreGetSub $ yreSite $ ysreParentEnv
WaiSubsite app = ysreGetSub $ yreSite ysreParentEnv
-- | A helper function for creating YesodSubDispatch instances, used by the
-- internal generated code. This function has been exported since 1.4.11.

View File

@ -5,7 +5,6 @@
{-# LANGUAGE CPP #-}
module Yesod.Core.Class.Yesod where
import Control.Monad.Logger (logErrorS)
import Yesod.Core.Content
import Yesod.Core.Handler
@ -15,16 +14,18 @@ import Blaze.ByteString.Builder (Builder)
import Blaze.ByteString.Builder.Char.Utf8 (fromText)
import Control.Arrow ((***), second)
import Control.Exception (bracket)
#if __GLASGOW_HASKELL__ < 710
import Control.Applicative ((<$>))
#endif
import Control.Monad (forM, when, void)
import Control.Monad.IO.Class (MonadIO (liftIO))
import Control.Monad.Logger (LogLevel (LevelInfo, LevelOther),
LogSource)
LogSource, logErrorS)
import Control.Monad.Trans.Resource (InternalState, createInternalState, closeInternalState)
import qualified Data.ByteString.Char8 as S8
import qualified Data.ByteString.Lazy as L
import Data.Aeson (object, (.=))
import Data.List (foldl')
import Data.List (nub)
import Data.List (foldl', nub)
import qualified Data.Map as Map
import Data.Monoid
import Data.Text (Text)
@ -43,14 +44,13 @@ import Network.Wai.Parse (lbsBackEnd,
import Network.Wai.Logger (ZonedDate, clockDateCacher)
import System.Log.FastLogger
import Text.Blaze (customAttribute, textTag,
toValue, (!))
import Text.Blaze (preEscapedToMarkup)
toValue, (!),
preEscapedToMarkup)
import qualified Text.Blaze.Html5 as TBH
import Text.Hamlet
import Text.Julius
import qualified Web.ClientSession as CS
import Web.Cookie (parseCookies)
import Web.Cookie (SetCookie (..))
import Web.Cookie (SetCookie (..), parseCookies)
import Yesod.Core.Types
import Yesod.Core.Internal.Session
import Yesod.Core.Widget
@ -237,7 +237,7 @@ class RenderRoute site => Yesod site where
--
-- Default: Uses clientsession with a 2 hour timeout.
makeSessionBackend :: site -> IO (Maybe SessionBackend)
makeSessionBackend _ = fmap Just $ defaultClientSessionBackend 120 CS.defaultKeyFile
makeSessionBackend _ = Just <$> defaultClientSessionBackend 120 CS.defaultKeyFile
-- | How to store uploaded files.
--
@ -388,8 +388,7 @@ sslOnlyMiddleware timeout handler = do
--
-- Since 1.2.0
authorizationCheck :: Yesod site => HandlerT site IO ()
authorizationCheck = do
getCurrentRoute >>= maybe (return ()) checkUrl
authorizationCheck = getCurrentRoute >>= maybe (return ()) checkUrl
where
checkUrl url = do
isWrite <- isWriteRequest url
@ -399,21 +398,21 @@ authorizationCheck = do
AuthenticationRequired -> do
master <- getYesod
case authRoute master of
Nothing -> void $ notAuthenticated
Just url' -> do
Nothing -> void notAuthenticated
Just url' ->
void $ selectRep $ do
provideRepType typeHtml $ do
setUltDestCurrent
void $ redirect url'
provideRepType typeJson $
void $ notAuthenticated
void notAuthenticated
Unauthorized s' -> permissionDenied s'
-- | Calls 'csrfCheckMiddleware' with 'isWriteRequest', 'defaultCsrfHeaderName', and 'defaultCsrfParamName' as parameters.
--
-- Since 1.4.14
defaultCsrfCheckMiddleware :: Yesod site => HandlerT site IO res -> HandlerT site IO res
defaultCsrfCheckMiddleware handler = do
defaultCsrfCheckMiddleware handler =
csrfCheckMiddleware
handler
(getCurrentRoute >>= maybe (return False) isWriteRequest)
@ -592,12 +591,9 @@ defaultErrorHandler NotAuthenticated = selectRep $ do
-- The client will just use the authentication_url in the JSON
site <- getYesod
rend <- getUrlRender
return $ object $ [
"message" .= ("Not logged in"::Text)
] ++
case authRoute site of
Nothing -> []
Just url -> ["authentication_url" .= rend url]
let apair u = ["authentication_url" .= rend u]
content = maybe [] apair (authRoute site)
return $ object $ ("message" .= ("Not logged in"::Text)):content
defaultErrorHandler (PermissionDenied msg) = selectRep $ do
provideRep $ defaultLayout $ do
@ -607,9 +603,7 @@ defaultErrorHandler (PermissionDenied msg) = selectRep $ do
<p>#{msg}
|]
provideRep $
return $ object $ [
"message" .= ("Permission Denied. " <> msg)
]
return $ object ["message" .= ("Permission Denied. " <> msg)]
defaultErrorHandler (InvalidArgs ia) = selectRep $ do
provideRep $ defaultLayout $ do
@ -641,8 +635,8 @@ defaultErrorHandler (BadMethod m) = selectRep $ do
provideRep $ return $ object ["message" .= ("Bad method" :: Text), "method" .= TE.decodeUtf8With TEE.lenientDecode m]
asyncHelper :: (url -> [x] -> Text)
-> [Script (url)]
-> Maybe (JavascriptUrl (url))
-> [Script url]
-> Maybe (JavascriptUrl url)
-> Maybe Text
-> (Maybe (HtmlUrl url), [Text])
asyncHelper render scripts jscript jsLoc =
@ -732,8 +726,7 @@ defaultClientSessionBackend :: Int -- ^ minutes
-> IO SessionBackend
defaultClientSessionBackend minutes fp = do
key <- CS.getKey fp
let timeout = fromIntegral (minutes * 60)
(getCachedDate, _closeDateCacher) <- clientSessionDateCacher timeout
(getCachedDate, _closeDateCacher) <- clientSessionDateCacher (minToSec minutes)
return $ clientSessionBackend key getCachedDate
-- | Create a @SessionBackend@ which reads the session key from the named
@ -759,10 +752,12 @@ envClientSessionBackend :: Int -- ^ minutes
-> IO SessionBackend
envClientSessionBackend minutes name = do
key <- CS.getKeyEnv name
let timeout = fromIntegral (minutes * 60)
(getCachedDate, _closeDateCacher) <- clientSessionDateCacher timeout
(getCachedDate, _closeDateCacher) <- clientSessionDateCacher $ minToSec minutes
return $ clientSessionBackend key getCachedDate
minToSec :: (Integral a, Num b) => a -> b
minToSec minutes = fromIntegral (minutes * 60)
jsToHtml :: Javascript -> Html
jsToHtml (Javascript b) = preEscapedToMarkup $ toLazyText b
@ -818,8 +813,14 @@ loadClientSession key getCachedDate sessionName req = load
-- turn the TH Loc loaction information into a human readable string
-- leaving out the loc_end parameter
fileLocationToString :: Loc -> String
fileLocationToString loc = (loc_package loc) ++ ':' : (loc_module loc) ++
' ' : (loc_filename loc) ++ ':' : (line loc) ++ ':' : (char loc)
fileLocationToString loc =
concat
[ loc_package loc
, ':' : loc_module loc
, ' ' : loc_filename loc
, ':' : line loc
, ':' : char loc
]
where
line = show . fst . loc_start
char = show . snd . loc_start

View File

@ -53,8 +53,6 @@ import qualified Data.ByteString as B
import qualified Data.ByteString.Lazy as L
import Data.Text.Lazy (Text, pack)
import qualified Data.Text as T
import Control.Monad (liftM)
import Blaze.ByteString.Builder (Builder, fromByteString, fromLazyByteString)
#if __GLASGOW_HASKELL__ < 710
import Data.Monoid (mempty)
@ -62,6 +60,7 @@ import Data.Monoid (mempty)
import Text.Hamlet (Html)
import Text.Blaze.Html.Renderer.Utf8 (renderHtmlBuilder)
import Data.Conduit (Source, Flush (Chunk), ResumableSource, mapOutput)
import Control.Monad (liftM)
import Control.Monad.Trans.Resource (ResourceT)
import Data.Conduit.Internal (ResumableSource (ResumableSource))
import qualified Data.Conduit.Internal as CI

View File

@ -85,7 +85,7 @@ toWaiAppPlain site = do
sb <- makeSessionBackend site
gen <- MWC.createSystemRandom
getMaxExpires <- getGetMaxExpires
return $ toWaiAppYre $ YesodRunnerEnv
return $ toWaiAppYre YesodRunnerEnv
{ yreLogger = logger
, yreSite = site
, yreSessionBackend = sb
@ -119,8 +119,8 @@ toWaiAppYre yre req =
dest' =
if S.null (W.rawQueryString env)
then dest
else (dest `mappend`
Blaze.ByteString.Builder.fromByteString (W.rawQueryString env))
else dest `mappend`
Blaze.ByteString.Builder.fromByteString (W.rawQueryString env)
-- | Same as 'toWaiAppPlain', but provides a default set of middlewares. This
-- set may change with future releases, but currently covers:
@ -184,7 +184,7 @@ warp port site = do
$(qLocation >>= liftLoc)
"yesod-core"
LevelError
(toLogStr $ "Exception from Warp: " ++ show e)) $
(toLogStr $ "Exception from Warp: " ++ show e))
Network.Wai.Handler.Warp.defaultSettings)
where
shouldLog' = Network.Wai.Handler.Warp.defaultShouldDisplayException
@ -231,7 +231,7 @@ warpEnv :: YesodDispatch site => site -> IO ()
warpEnv site = do
env <- getEnvironment
case lookup "PORT" env of
Nothing -> error $ "warpEnv: no PORT environment variable found"
Nothing -> error "warpEnv: no PORT environment variable found"
Just portS ->
case readMay portS of
Nothing -> error $ "warpEnv: invalid PORT environment variable: " ++ show portS

View File

@ -189,10 +189,10 @@ import Control.Applicative ((<$>))
import Data.Monoid (mempty, mappend)
#endif
import Control.Applicative ((<|>))
import Control.Exception (evaluate, SomeException)
import Control.Exception (evaluate, SomeException, throwIO)
import Control.Exception.Lifted (handle)
import Control.Monad (liftM, void)
import Control.Monad (void, liftM, unless)
import qualified Control.Monad.Trans.Writer as Writer
import Control.Monad.IO.Class (MonadIO, liftIO)
@ -235,24 +235,19 @@ import Web.PathPieces (PathPiece(..))
import Yesod.Core.Class.Handler
import Yesod.Core.Types
import Yesod.Routes.Class (Route)
import Control.Exception (throwIO)
import Blaze.ByteString.Builder (Builder)
import Safe (headMay)
import Data.CaseInsensitive (CI)
import Blaze.ByteString.Builder (Builder)
import Safe (headMay)
import Data.CaseInsensitive (CI)
import qualified Data.Conduit.List as CL
import Control.Monad (unless)
import Control.Monad.Trans.Resource (MonadResource, InternalState, runResourceT, withInternalState, getInternalState, liftResourceT, resourceForkIO
)
import Control.Monad.Trans.Resource (MonadResource, InternalState, runResourceT, withInternalState, getInternalState, liftResourceT, resourceForkIO)
import qualified System.PosixCompat.Files as PC
import Control.Monad.Trans.Control (control, MonadBaseControl)
import Data.Conduit (Source, transPipe, Flush (Flush), yield, Producer
, Sink
)
import Control.Monad.Trans.Control (control, MonadBaseControl)
import Data.Conduit (Source, transPipe, Flush (Flush), yield, Producer, Sink)
import qualified Yesod.Core.TypeCache as Cache
import qualified Data.Word8 as W8
import qualified Data.Foldable as Fold
import Data.Default
import Control.Monad.Logger (MonadLogger, logWarnS)
import Data.Default
import Control.Monad.Logger (MonadLogger, logWarnS)
get :: MonadHandler m => m GHState
get = liftHandlerT $ HandlerT $ I.readIORef . handlerState
@ -305,7 +300,7 @@ rbHelper' :: NWP.BackEnd x
-> W.Request
-> IO ([(Text, Text)], [(Text, FileInfo)])
rbHelper' backend mkFI req =
(map fix1 *** mapMaybe fix2) <$> (NWP.parseRequestBody backend req)
(map fix1 *** mapMaybe fix2) <$> NWP.parseRequestBody backend req
where
fix1 = go *** go
fix2 (x, NWP.FileInfo a' b c)
@ -324,29 +319,29 @@ askHandlerEnv = liftHandlerT $ HandlerT $ return . handlerEnv
-- | Get the master site application argument.
getYesod :: MonadHandler m => m (HandlerSite m)
getYesod = rheSite `liftM` askHandlerEnv
getYesod = rheSite <$> askHandlerEnv
-- | Get a specific component of the master site application argument.
-- Analogous to the 'gets' function for operating on 'StateT'.
getsYesod :: MonadHandler m => (HandlerSite m -> a) -> m a
getsYesod f = (f . rheSite) `liftM` askHandlerEnv
getsYesod f = (f . rheSite) <$> askHandlerEnv
-- | Get the URL rendering function.
getUrlRender :: MonadHandler m => m (Route (HandlerSite m) -> Text)
getUrlRender = do
x <- rheRender `liftM` askHandlerEnv
x <- rheRender <$> askHandlerEnv
return $ flip x []
-- | The URL rendering function with query-string parameters.
getUrlRenderParams
:: MonadHandler m
=> m (Route (HandlerSite m) -> [(Text, Text)] -> Text)
getUrlRenderParams = rheRender `liftM` askHandlerEnv
getUrlRenderParams = rheRender <$> askHandlerEnv
-- | Get the route requested by the user. If this is a 404 response- where the
-- user requested an invalid route- this function will return 'Nothing'.
getCurrentRoute :: MonadHandler m => m (Maybe (Route (HandlerSite m)))
getCurrentRoute = rheRoute `liftM` askHandlerEnv
getCurrentRoute = rheRoute <$> askHandlerEnv
-- | Returns a function that runs 'HandlerT' actions inside @IO@.
--
@ -487,7 +482,7 @@ setUltDestCurrent = do
case route of
Nothing -> return ()
Just r -> do
gets' <- reqGetParams `liftM` getRequest
gets' <- reqGetParams <$> getRequest
setUltDest (r, gets')
-- | Sets the ultimate destination to the referer request header, if present.
@ -541,7 +536,7 @@ addMessage status msg = do
addMsg = maybe msg' (S.append msg' . S.cons W8._nul)
msg' = S.append
(encodeUtf8 status)
(W8._nul `S.cons` (L.toStrict $ renderHtml msg))
(W8._nul `S.cons` L.toStrict (renderHtml msg))
-- | Adds a message in the user's session but uses RenderMessage to allow for i18n
--
@ -568,7 +563,7 @@ getMessages = do
where
enlist = pairup . S.split W8._nul
pairup [] = []
pairup [x] = []
pairup [_] = []
pairup (s:v:xs) = (decode s, preEscapedToHtml (decode v)) : pairup xs
decode = decodeUtf8With lenientDecode
@ -584,7 +579,7 @@ setMessageI = addMessageI ""
-- | Gets just the last message in the user's session,
-- discards the rest and the status
getMessage :: MonadHandler m => m (Maybe Html)
getMessage = (return . fmap snd . headMay) =<< getMessages
getMessage = fmap (fmap snd . headMay) getMessages
-- | Bypass remaining handler code and output the given file.
--
@ -657,7 +652,7 @@ sendRawResponseNoConduit
-> m a
sendRawResponseNoConduit raw = control $ \runInIO ->
liftIO $ throwIO $ HCWai $ flip W.responseRaw fallback
$ \src sink -> runInIO (raw src sink) >> return ()
$ \src sink -> void $ runInIO (raw src sink)
where
fallback = W.responseLBS H.status500 [("Content-Type", "text/plain")]
"sendRawResponse: backend does not support raw responses"
@ -672,7 +667,7 @@ sendRawResponse :: (MonadHandler m, MonadBaseControl IO m)
-> m a
sendRawResponse raw = control $ \runInIO ->
liftIO $ throwIO $ HCWai $ flip W.responseRaw fallback
$ \src sink -> runInIO (raw (src' src) (CL.mapM_ sink)) >> return ()
$ \src sink -> void $ runInIO $ raw (src' src) (CL.mapM_ sink)
where
fallback = W.responseLBS H.status500 [("Content-Type", "text/plain")]
"sendRawResponse: backend does not support raw responses"
@ -901,17 +896,17 @@ instance (RedirectUrl master a, PathPiece b) => RedirectUrl master (Fragment a b
-- | Lookup for session data.
lookupSession :: MonadHandler m => Text -> m (Maybe Text)
lookupSession = (liftM . fmap) (decodeUtf8With lenientDecode) . lookupSessionBS
lookupSession = (fmap . fmap) (decodeUtf8With lenientDecode) . lookupSessionBS
-- | Lookup for session data in binary format.
lookupSessionBS :: MonadHandler m => Text -> m (Maybe S.ByteString)
lookupSessionBS n = do
m <- liftM ghsSession get
m <- fmap ghsSession get
return $ Map.lookup n m
-- | Get all session variables.
getSession :: MonadHandler m => m SessionMap
getSession = liftM ghsSession get
getSession = fmap ghsSession get
-- | Get a unique identifier.
newIdent :: MonadHandler m => m Text
@ -976,13 +971,13 @@ withUrlRenderer f = do
-- | Get the request\'s 'W.Request' value.
waiRequest :: MonadHandler m => m W.Request
waiRequest = reqWaiRequest `liftM` getRequest
waiRequest = reqWaiRequest <$> getRequest
getMessageRender :: (MonadHandler m, RenderMessage (HandlerSite m) message)
=> m (message -> Text)
getMessageRender = do
env <- askHandlerEnv
l <- reqLangs `liftM` getRequest
l <- reqLangs <$> getRequest
return $ renderMessage (rheSite env) l
-- | Use a per-request cache to avoid performing the same action multiple times.
@ -1045,7 +1040,7 @@ cachedBy k action = do
--
-- This is handled by parseWaiRequest (not exposed).
languages :: MonadHandler m => m [Text]
languages = reqLangs `liftM` getRequest
languages = reqLangs <$> getRequest
lookup' :: Eq a => a -> [(a, b)] -> [b]
lookup' a = map snd . filter (\x -> a == fst x)
@ -1054,7 +1049,7 @@ lookup' a = map snd . filter (\x -> a == fst x)
--
-- Since 1.2.2
lookupHeader :: MonadHandler m => CI S8.ByteString -> m (Maybe S8.ByteString)
lookupHeader = liftM listToMaybe . lookupHeaders
lookupHeader = fmap listToMaybe . lookupHeaders
-- | Lookup a request header.
--
@ -1069,11 +1064,9 @@ lookupHeaders key = do
--
-- Since 1.4.9
lookupBasicAuth :: (MonadHandler m) => m (Maybe (Text, Text))
lookupBasicAuth = fmap (>>= getBA)
(lookupHeader "Authorization")
lookupBasicAuth = fmap (>>= getBA) (lookupHeader "Authorization")
where
getBA bs = (\(x, y) -> ( decodeUtf8With lenientDecode x
, decodeUtf8With lenientDecode y))
getBA bs = (decodeUtf8With lenientDecode *** decodeUtf8With lenientDecode)
<$> extractBasicAuth bs
-- | Lookup bearer authentication datafrom __Authorization__ header of
@ -1096,7 +1089,7 @@ lookupGetParams pn = do
-- | Lookup for GET parameters.
lookupGetParam :: MonadHandler m => Text -> m (Maybe Text)
lookupGetParam = liftM listToMaybe . lookupGetParams
lookupGetParam = fmap listToMaybe . lookupGetParams
-- | Lookup for POST parameters.
lookupPostParams :: (MonadResource m, MonadHandler m) => Text -> m [Text]
@ -1107,13 +1100,13 @@ lookupPostParams pn = do
lookupPostParam :: (MonadResource m, MonadHandler m)
=> Text
-> m (Maybe Text)
lookupPostParam = liftM listToMaybe . lookupPostParams
lookupPostParam = fmap listToMaybe . lookupPostParams
-- | Lookup for POSTed files.
lookupFile :: (MonadHandler m, MonadResource m)
=> Text
-> m (Maybe FileInfo)
lookupFile = liftM listToMaybe . lookupFiles
lookupFile = fmap listToMaybe . lookupFiles
-- | Lookup for POSTed files.
lookupFiles :: (MonadHandler m, MonadResource m)
@ -1125,7 +1118,7 @@ lookupFiles pn = do
-- | Lookup for cookie data.
lookupCookie :: MonadHandler m => Text -> m (Maybe Text)
lookupCookie = liftM listToMaybe . lookupCookies
lookupCookie = fmap listToMaybe . lookupCookies
-- | Lookup for cookie data.
lookupCookies :: MonadHandler m => Text -> m [Text]
@ -1160,7 +1153,7 @@ selectRep :: MonadHandler m
selectRep w = do
-- the content types are already sorted by q values
-- which have been stripped
cts <- liftM reqAccept getRequest
cts <- fmap reqAccept getRequest
case mapMaybe tryAccept cts of
[] ->
@ -1175,8 +1168,7 @@ selectRep w = do
explainUnaccepted :: Text
explainUnaccepted = "no match found for accept header"
returnRep (ProvidedRep ct mcontent) =
mcontent >>= return . TypedContent ct
returnRep (ProvidedRep ct mcontent) = fmap (TypedContent ct) mcontent
reps = appEndo (Writer.execWriter w) []
@ -1235,7 +1227,7 @@ provideRepType :: (Monad m, ToContent a)
-> m a
-> Writer.Writer (Endo [ProvidedRep m]) ()
provideRepType ct handler =
Writer.tell $ Endo $ (ProvidedRep ct (liftM toContent handler):)
Writer.tell $ Endo (ProvidedRep ct (liftM toContent handler):)
-- | Stream in the raw request body without any parsing.
--

View File

@ -1,5 +1,4 @@
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE CPP #-}
{-# LANGUAGE OverloadedStrings, CPP #-}
module Yesod.Core.Internal.Request
( parseWaiRequest
, RequestBodyContents
@ -37,7 +36,7 @@ import Data.Text.Encoding.Error (lenientDecode)
import Data.Conduit
import Data.Conduit.List (sourceList)
import Data.Conduit.Binary (sourceFile, sinkFile)
import Data.Word (Word64)
import Data.Word (Word8, Word64)
import Control.Monad.Trans.Resource (runResourceT, ResourceT)
import Control.Exception (throwIO)
import Control.Monad ((<=<), liftM)
@ -47,7 +46,6 @@ import Data.IORef
import qualified System.Random.MWC as MWC
import Control.Monad.Primitive (PrimMonad, PrimState)
import qualified Data.Vector.Storable as V
import Data.Word (Word8)
import Data.ByteString.Internal (ByteString (PS))
import qualified Data.Word8 as Word8
@ -78,7 +76,7 @@ parseWaiRequest :: W.Request
-> SessionMap
-> Bool
-> Maybe Word64 -- ^ max body size
-> (Either (IO YesodRequest) (MWC.GenIO -> IO YesodRequest))
-> Either (IO YesodRequest) (MWC.GenIO -> IO YesodRequest)
parseWaiRequest env session useToken mmaxBodySize =
-- In most cases, we won't need to generate any random values. Therefore,
-- we split our results: if we need a random generator, return a Right
@ -147,7 +145,7 @@ httpAccept = NWP.parseHttpAccept
addTwoLetters :: ([Text] -> [Text], Set.Set Text) -> [Text] -> [Text]
addTwoLetters (toAdd, exist) [] =
filter (flip Set.notMember exist) $ toAdd []
filter (`Set.notMember` exist) $ toAdd []
addTwoLetters (toAdd, exist) (l:ls) =
l : addTwoLetters (toAdd', exist') ls
where
@ -177,7 +175,8 @@ fromByteVector v =
{-# INLINE fromByteVector #-}
mkFileInfoLBS :: Text -> Text -> L.ByteString -> FileInfo
mkFileInfoLBS name ct lbs = FileInfo name ct (sourceList $ L.toChunks lbs) (\fp -> L.writeFile fp lbs)
mkFileInfoLBS name ct lbs =
FileInfo name ct (sourceList $ L.toChunks lbs) (`L.writeFile` lbs)
mkFileInfoFile :: Text -> Text -> FilePath -> FileInfo
mkFileInfoFile name ct fp = FileInfo name ct (sourceFile fp) (\dst -> runResourceT $ sourceFile fp $$ sinkFile dst)

View File

@ -1,19 +1,15 @@
{-# LANGUAGE CPP #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE PatternGuards #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE TemplateHaskell #-}
module Yesod.Core.Internal.Response where
import Blaze.ByteString.Builder (toByteString)
import Data.ByteString (ByteString)
import qualified Data.ByteString as S
import qualified Data.ByteString.Char8 as S8
import Data.CaseInsensitive (CI)
import qualified Data.CaseInsensitive as CI
import Network.Wai
import Data.Conduit (transPipe)
import Control.Monad (mplus)
import Control.Monad.Trans.Resource (runInternalState, InternalState)
import Network.Wai.Internal
#if !MIN_VERSION_base(4, 6, 0)
@ -26,12 +22,12 @@ import qualified Network.HTTP.Types as H
import qualified Data.Text as T
import Control.Exception (SomeException, handle)
import Blaze.ByteString.Builder (fromLazyByteString,
toLazyByteString)
toLazyByteString, toByteString)
import qualified Data.ByteString.Lazy as L
import qualified Data.Map as Map
import Yesod.Core.Internal.Request (tokenKey)
import Data.Text.Encoding (encodeUtf8)
import Data.Conduit (Flush (..), ($$))
import Data.Conduit (Flush (..), ($$), transPipe)
import qualified Data.Conduit.List as CL
yarToResponse :: YesodResponse
@ -58,11 +54,10 @@ yarToResponse (YRPlain s' hs ct c newSess) saveSession yreq _req is sendResponse
let go (ContentBuilder b mlen) = do
let hs' = maybe finalHeaders finalHeaders' mlen
sendResponse $ ResponseBuilder s hs' b
go (ContentFile fp p) = do
sendResponse $ ResponseFile s finalHeaders fp p
go (ContentFile fp p) = sendResponse $ ResponseFile s finalHeaders fp p
go (ContentSource body) = sendResponse $ responseStream s finalHeaders
$ \sendChunk flush -> do
transPipe (flip runInternalState is) body
$ \sendChunk flush ->
transPipe (`runInternalState` is) body
$$ CL.mapM_ (\mchunk ->
case mchunk of
Flush -> flush
@ -91,7 +86,7 @@ defaultStatus = H.mkStatus (-1) "INVALID DEFAULT STATUS"
headerToPair :: Header
-> (CI ByteString, ByteString)
headerToPair (AddCookie sc) =
("Set-Cookie", toByteString $ renderSetCookie $ sc)
("Set-Cookie", toByteString $ renderSetCookie sc)
headerToPair (DeleteCookie key path) =
( "Set-Cookie"
, S.concat
@ -107,7 +102,7 @@ evaluateContent :: Content -> IO (Either ErrorResponse Content)
evaluateContent (ContentBuilder b mlen) = handle f $ do
let lbs = toLazyByteString b
len = L.length lbs
mlen' = maybe (Just $ fromIntegral len) Just mlen
mlen' = mlen `mplus` Just (fromIntegral len)
len `seq` return (Right $ ContentBuilder (fromLazyByteString lbs) mlen')
where
f :: SomeException -> IO (Either ErrorResponse Content)

View File

@ -11,6 +11,7 @@ module Yesod.Core.Internal.Run where
#if __GLASGOW_HASKELL__ < 710
import Data.Monoid (Monoid, mempty)
import Control.Applicative ((<$>))
#endif
import Yesod.Core.Internal.Response
import Blaze.ByteString.Builder (toByteString)
@ -102,7 +103,7 @@ basicRunHandler rhe handler yreq resState = do
(\e ->
case fromException e of
Just e' -> return e'
Nothing -> fmap HCError $ toErrorHandler e)
Nothing -> HCError <$> toErrorHandler e)
-- Get the raw state and return
state <- I.readIORef istate
@ -330,7 +331,7 @@ yesodRunner handler' YesodRunnerEnv {..} route req sendResponse
| otherwise = do
let dontSaveSession _ = return []
(session, saveSession) <- liftIO $
maybe (return (Map.empty, dontSaveSession)) (\sb -> sbLoadSession sb req) yreSessionBackend
maybe (return (Map.empty, dontSaveSession)) (`sbLoadSession` req) yreSessionBackend
maxExpires <- yreGetMaxExpires
let mkYesodReq = parseWaiRequest req session (isJust yreSessionBackend) mmaxLen
let yreq =

View File

@ -11,11 +11,9 @@ import qualified Web.ClientSession as CS
import Data.Serialize
import Data.Time
import Data.ByteString (ByteString)
import Control.Concurrent (forkIO, killThread, threadDelay)
import Control.Monad (forever, guard)
import Control.Monad (guard)
import Yesod.Core.Types
import Yesod.Core.Internal.Util
import qualified Data.IORef as I
import Control.AutoUpdate
encodeClientSession :: CS.Key
@ -63,7 +61,7 @@ clientSessionDateCacher validity = do
, updateFreq = 10000000 -- 10s
}
return $! (getClientSessionDateCache, return ())
return (getClientSessionDateCache, return ())
where
getUpdated = do
now <- getCurrentTime

View File

@ -16,7 +16,10 @@ import qualified Network.Wai as W
import Data.ByteString.Lazy.Char8 ()
import Data.List (foldl')
import Control.Monad (replicateM)
#if __GLASGOW_HASKELL__ < 710
import Control.Applicative ((<$>))
#endif
import Control.Monad (replicateM, void)
import Data.Either (partitionEithers)
import Yesod.Routes.TH
@ -45,15 +48,15 @@ mkYesodWith name args = fmap (uncurry (++)) . mkYesodGeneral name args False ret
-- monolithic file into smaller parts. Use this function, paired with
-- 'mkYesodDispatch', to do just that.
mkYesodData :: String -> [ResourceTree String] -> Q [Dec]
mkYesodData name res = mkYesodDataGeneral name False res
mkYesodData name = mkYesodDataGeneral name False
mkYesodSubData :: String -> [ResourceTree String] -> Q [Dec]
mkYesodSubData name res = mkYesodDataGeneral name True res
mkYesodSubData name = mkYesodDataGeneral name True
mkYesodDataGeneral :: String -> Bool -> [ResourceTree String] -> Q [Dec]
mkYesodDataGeneral name isSub res = do
let (name':rest) = words name
fmap fst $ mkYesodGeneral name' (fmap Left rest) isSub return res
fst <$> mkYesodGeneral name' (fmap Left rest) isSub return res
-- | See 'mkYesodData'.
mkYesodDispatch :: String -> [ResourceTree String] -> Q [Dec]
@ -150,8 +153,8 @@ mkMDS f rh = MkDispatchSettings
, mdsGetPathInfo = [|W.pathInfo|]
, mdsSetPathInfo = [|\p r -> r { W.pathInfo = p }|]
, mdsMethod = [|W.requestMethod|]
, mds404 = [|notFound >> return ()|]
, mds405 = [|badMethod >> return ()|]
, mds404 = [|void notFound|]
, mds405 = [|void badMethod|]
, mdsGetHandler = defaultGetHandler
, mdsUnwrapper = f
}

View File

@ -14,8 +14,6 @@ import qualified Data.Text as T
import Data.Time (Day (ModifiedJulianDay, toModifiedJulianDay),
DiffTime, UTCTime (..), formatTime,
getCurrentTime, addUTCTime)
import Control.Monad (liftM)
#if MIN_VERSION_time(1,5,0)
import Data.Time (defaultTimeLocale)
#else
@ -58,4 +56,4 @@ formatRFC822 = T.pack . formatTime defaultTimeLocale "%a, %d %b %Y %H:%M:%S %z"
date on a resource that never expires. See RFC 2616 section 14.21 for details.
-}
getCurrentMaxExpiresRFC1123 :: IO T.Text
getCurrentMaxExpiresRFC1123 = liftM (formatRFC1123 . addUTCTime (60*60*24*365)) getCurrentTime
getCurrentMaxExpiresRFC1123 = fmap (formatRFC1123 . addUTCTime (60*60*24*365)) getCurrentTime

View File

@ -20,8 +20,7 @@ import Control.Arrow (first)
import Control.Exception (Exception)
import Control.Monad (liftM, ap)
import Control.Monad.Base (MonadBase (liftBase))
import Control.Monad.Catch (MonadCatch (..))
import Control.Monad.Catch (MonadMask (..))
import Control.Monad.Catch (MonadMask (..), MonadCatch (..))
import Control.Monad.IO.Class (MonadIO (liftIO))
import Control.Monad.Logger (LogLevel, LogSource,
MonadLogger (..))
@ -172,7 +171,7 @@ data ScriptLoadPosition master
type BottomOfHeadAsync master
= [Text] -- ^ urls to load asynchronously
-> Maybe (HtmlUrl (Route master)) -- ^ widget of js to run on async completion
-> (HtmlUrl (Route master)) -- ^ widget to insert at the bottom of <head>
-> HtmlUrl (Route master) -- ^ widget to insert at the bottom of <head>
type Texts = [Text]
@ -264,7 +263,7 @@ instance (a ~ (), Monad m) => Semigroup (WidgetT site m a)
-- @getHomeR = do defaultLayout "Widget text"@
instance (Monad m, a ~ ()) => IsString (WidgetT site m a) where
fromString = toWidget . toHtml . T.pack
where toWidget x = WidgetT $ const $ return $ ((), GWData (Body (const x))
where toWidget x = WidgetT $ const $ return ((), GWData (Body (const x))
mempty mempty mempty mempty mempty mempty)
type RY master = Route master -> [(Text, Text)] -> Text
@ -422,15 +421,15 @@ instance MonadBaseControl b m => MonadBaseControl b (WidgetT site m) where
type StM (WidgetT site m) a = StM m (a, GWData (Route site))
liftBaseWith f = WidgetT $ \reader' ->
liftBaseWith $ \runInBase ->
liftM (\x -> (x, mempty))
fmap (\x -> (x, mempty))
(f $ runInBase . flip unWidgetT reader')
restoreM = WidgetT . const . restoreM
#else
data StM (WidgetT site m) a = StW (StM m (a, GWData (Route site)))
liftBaseWith f = WidgetT $ \reader' ->
liftBaseWith $ \runInBase ->
liftM (\x -> (x, mempty))
(f $ liftM StW . runInBase . flip unWidgetT reader')
fmap (\x -> (x, mempty))
(f $ fmap StW . runInBase . flip unWidgetT reader')
restoreM (StW base) = WidgetT $ const $ restoreM base
#endif
instance Monad m => MonadReader site (WidgetT site m) where
@ -464,11 +463,11 @@ instance MonadMask m => MonadMask (WidgetT site m) where
where q u (WidgetT b) = WidgetT (u . b)
instance (Applicative m, MonadIO m, MonadBase IO m, MonadThrow m) => MonadResource (WidgetT site m) where
liftResourceT f = WidgetT $ \hd -> liftIO $ fmap (, mempty) $ runInternalState f (handlerResource hd)
liftResourceT f = WidgetT $ \hd -> liftIO $ (, mempty) <$> runInternalState f (handlerResource hd)
instance MonadIO m => MonadLogger (WidgetT site m) where
monadLoggerLog a b c d = WidgetT $ \hd ->
liftIO $ fmap (, mempty) $ rheLog (handlerEnv hd) a b c (toLogStr d)
liftIO $ (, mempty) <$> rheLog (handlerEnv hd) a b c (toLogStr d)
#if MIN_VERSION_monad_logger(0, 3, 10)
instance MonadIO m => MonadLoggerIO (WidgetT site m) where
@ -522,7 +521,7 @@ instance MonadBaseControl b m => MonadBaseControl b (HandlerT site m) where
data StM (HandlerT site m) a = StH (StM m a)
liftBaseWith f = HandlerT $ \reader' ->
liftBaseWith $ \runInBase ->
f $ liftM StH . runInBase . (\(HandlerT r) -> r reader')
f $ fmap StH . runInBase . (\(HandlerT r) -> r reader')
restoreM (StH base) = HandlerT $ const $ restoreM base
#endif

View File

@ -57,9 +57,12 @@ import Text.Cassius
import Text.Julius
import Yesod.Routes.Class
import Yesod.Core.Handler (getMessageRender, getUrlRenderParams)
#if __GLASGOW_HASKELL__ < 710
import Control.Applicative ((<$>))
#endif
import Control.Monad (liftM)
import Control.Monad.IO.Class (MonadIO, liftIO)
import Text.Shakespeare.I18N (RenderMessage)
import Control.Monad (liftM)
import Data.Text (Text)
import qualified Data.Map as Map
import Language.Haskell.TH.Quote (QuasiQuoter)
@ -232,7 +235,7 @@ rules = do
let ur f = do
let env = NP.Env
(Just $ helper [|getUrlRenderParams|])
(Just $ helper [|liftM (toHtml .) getMessageRender|])
(Just $ helper [|fmap (toHtml .) getMessageRender|])
f env
return $ NP.HamletRules ah ur $ \_ b -> return $ ah `AppE` b
@ -272,16 +275,16 @@ widgetToParentWidget (WidgetT f) = HandlerT $ \hd -> do
liftGWD :: (child -> parent) -> GWData child -> GWData parent
liftGWD tp gwd = GWData
{ gwdBody = fixBody $ gwdBody gwd
, gwdTitle = gwdTitle gwd
, gwdScripts = fixUnique fixScript $ gwdScripts gwd
{ gwdBody = fixBody $ gwdBody gwd
, gwdTitle = gwdTitle gwd
, gwdScripts = fixUnique fixScript $ gwdScripts gwd
, gwdStylesheets = fixUnique fixStyle $ gwdStylesheets gwd
, gwdCss = fmap fixCss $ gwdCss gwd
, gwdJavascript = fmap fixJS $ gwdJavascript gwd
, gwdHead = fixHead $ gwdHead gwd
, gwdCss = fixCss <$> gwdCss gwd
, gwdJavascript = fixJS <$> gwdJavascript gwd
, gwdHead = fixHead $ gwdHead gwd
}
where
fixRender f route params = f (tp route) params
fixRender f route = f (tp route)
fixBody (Body h) = Body $ h . fixRender
fixHead (Head h) = Head $ h . fixRender

View File

@ -1,4 +1,3 @@
{-# LANGUAGE TemplateHaskell #-}
module Yesod.Routes.TH
( module Yesod.Routes.TH.Types
-- * Functions

View File

@ -55,7 +55,7 @@ mkRouteCons rttypes =
where
con = NormalC (mkName name)
$ map (\x -> (notStrict, x))
$ concat [singles, [ConT $ mkName name]]
$ singles ++ [ConT $ mkName name]
singles = concatMap toSingle pieces
toSingle Static{} = []
@ -99,7 +99,7 @@ mkRenderRouteClauses =
dyns <- replicateM cnt $ newName "dyn"
sub <-
case resourceDispatch res of
Subsite{} -> fmap return $ newName "sub"
Subsite{} -> return <$> newName "sub"
_ -> return []
let pat = ConP (mkName $ resourceName res) $ map VarP $ dyns ++ sub
@ -136,7 +136,7 @@ mkRenderRouteClauses =
mkPieces _ _ [] _ = []
mkPieces toText tsp (Static s:ps) dyns = toText s : mkPieces toText tsp ps dyns
mkPieces toText tsp (Dynamic{}:ps) (d:dyns) = tsp `AppE` VarE d : mkPieces toText tsp ps dyns
mkPieces _ _ ((Dynamic _) : _) [] = error "mkPieces 120"
mkPieces _ _ (Dynamic _ : _) [] = error "mkPieces 120"
-- | Generate the 'RenderRoute' instance.
--

View File

@ -10,6 +10,9 @@ import Yesod.Routes.Class
import Language.Haskell.TH.Syntax
import Data.Set (fromList)
import Data.Text (pack)
#if __GLASGOW_HASKELL__ < 710
import Control.Applicative ((<$>))
#endif
mkRouteAttrsInstance :: Type -> [ResourceTree a] -> Q Dec
mkRouteAttrsInstance typ ress = do
@ -19,11 +22,11 @@ mkRouteAttrsInstance typ ress = do
]
goTree :: (Pat -> Pat) -> ResourceTree a -> Q [Clause]
goTree front (ResourceLeaf res) = fmap return $ goRes front res
goTree front (ResourceLeaf res) = return <$> goRes front res
goTree front (ResourceParent name _check pieces trees) =
fmap concat $ mapM (goTree front') trees
concat <$> mapM (goTree front') trees
where
ignored = ((replicate toIgnore WildP ++) . return)
ignored = (replicate toIgnore WildP ++) . return
toIgnore = length $ filter isDynamic pieces
isDynamic Dynamic{} = True
isDynamic Static{} = False

View File

@ -53,11 +53,11 @@ data Piece typ = Static String | Dynamic typ
deriving Show
instance Functor Piece where
fmap _ (Static s) = (Static s)
fmap _ (Static s) = Static s
fmap f (Dynamic t) = Dynamic (f t)
instance Lift t => Lift (Piece t) where
lift (Static s) = [|Static $(lift s)|]
lift (Static s) = [|Static $(lift s)|]
lift (Dynamic t) = [|Dynamic $(lift t)|]
data Dispatch typ =

View File

@ -13,8 +13,6 @@ import Yesod.Core
import Data.IORef.Lifted
import Data.Typeable (Typeable)
import qualified Data.ByteString.Lazy.Char8 as L8
import Data.Text (Text)
import Data.Text.Encoding (encodeUtf8)
data C = C

View File

@ -9,11 +9,10 @@ import Yesod.Core
import Test.Hspec
import Network.Wai
import Network.Wai.Test
import Text.Hamlet (hamlet)
import qualified Data.ByteString.Lazy as L
import qualified Data.ByteString.Char8 as S8
import Control.Exception (SomeException, try)
import Network.HTTP.Types (mkStatus)
import Network.HTTP.Types (Status, mkStatus)
import Blaze.ByteString.Builder (Builder, fromByteString, toLazyByteString)
import Data.Monoid (mconcat)
import Data.Text (Text, pack)
@ -40,6 +39,7 @@ mkYesod "App" [parseRoutes|
/good-builder GoodBuilderR GET
|]
overrideStatus :: Status
overrideStatus = mkStatus 15 "OVERRIDE"
instance Yesod App where

View File

@ -2,10 +2,7 @@
module YesodCoreTest.InternalRequest (internalRequestTest) where
import Data.List (nub)
import System.Random (StdGen, mkStdGen)
import Network.Wai as W
import Network.Wai.Test
import Yesod.Core.Internal (randomString, parseWaiRequest)
import Test.Hspec
import Data.Monoid (mempty)

View File

@ -6,7 +6,6 @@ module YesodCoreTest.Links (linksTest, Widget) where
import Test.Hspec
import Yesod.Core
import Text.Hamlet
import Network.Wai
import Network.Wai.Test
import Data.Text (Text)

View File

@ -8,7 +8,6 @@ import Test.Hspec
import Yesod.Core
import Network.Wai
import Network.Wai.Test
import Text.Lucius
import YesodCoreTest.MediaData
mkYesodDispatch "Y" resourcesY

View File

@ -8,7 +8,6 @@
module YesodCoreTest.NoOverloadedStringsSub where
import Yesod.Core
import Network.Wai
import Yesod.Core.Types
data Subsite = Subsite (forall master. Yesod master => YesodSubRunnerEnv Subsite master (HandlerT master IO) -> Application)

View File

@ -6,10 +6,6 @@ module YesodCoreTest.Widget (widgetTest) where
import Test.Hspec
import Yesod.Core
import Text.Julius
import Text.Lucius
import Text.Hamlet
import Network.Wai
import Network.Wai.Test