lookupSessionBS/setSessionBS (#235)

This commit is contained in:
Michael Snoyman 2012-01-24 18:43:30 +02:00
parent 61efa0e1af
commit fec0d42827
4 changed files with 33 additions and 14 deletions

View File

@ -70,8 +70,10 @@ module Yesod.Handler
-- * Session -- * Session
, SessionMap , SessionMap
, lookupSession , lookupSession
, lookupSessionBS
, getSession , getSession
, setSession , setSession
, setSessionBS
, deleteSession , deleteSession
-- ** Ultimate destination -- ** Ultimate destination
, setUltDest , setUltDest
@ -272,7 +274,7 @@ data GHState = GHState
, ghsHeaders :: Endo [Header] , ghsHeaders :: Endo [Header]
} }
type SessionMap = Map.Map Text Text type SessionMap = Map.Map Text S.ByteString
-- | An extension of the basic WAI 'W.Application' datatype to provide extra -- | An extension of the basic WAI 'W.Application' datatype to provide extra
-- features needed by Yesod. Users should never need to use this directly, as -- features needed by Yesod. Users should never need to use this directly, as
@ -678,7 +680,13 @@ expiresAt = setHeader "Expires" . formatRFC1123
setSession :: Text -- ^ key setSession :: Text -- ^ key
-> Text -- ^ value -> Text -- ^ value
-> GHandler sub master () -> GHandler sub master ()
setSession k = modify . modSession . Map.insert k setSession k = setSessionBS k . encodeUtf8
-- | Same as 'setSession', but uses binary data for the value.
setSessionBS :: Text
-> S.ByteString
-> GHandler sub master ()
setSessionBS k = modify . modSession . Map.insert k
-- | Unsets a session variable. See 'setSession'. -- | Unsets a session variable. See 'setSession'.
deleteSession :: Text -> GHandler sub master () deleteSession :: Text -> GHandler sub master ()
@ -725,7 +733,11 @@ localNoCurrent =
-- | Lookup for session data. -- | Lookup for session data.
lookupSession :: Text -> GHandler s m (Maybe Text) lookupSession :: Text -> GHandler s m (Maybe Text)
lookupSession n = do lookupSession = (fmap . fmap) (decodeUtf8With lenientDecode) . lookupSessionBS
-- | Lookup for session data in binary format.
lookupSessionBS :: Text -> GHandler s m (Maybe S.ByteString)
lookupSessionBS n = do
m <- liftM ghsSession get m <- liftM ghsSession get
return $ Map.lookup n m return $ Map.lookup n m

View File

@ -402,7 +402,7 @@ defaultYesodRunner handler master sub murl toMasterRoute mkey req = do
(Just key, Just nonce) (Just key, Just nonce)
-> encodeSession key iv exp' host -> encodeSession key iv exp' host
$ Map.toList $ Map.toList
$ Map.insert nonceKey nonce sm $ Map.insert nonceKey (TE.encodeUtf8 nonce) sm
_ -> mempty _ -> mempty
hs' = hs' =
case mkey of case mkey of

View File

@ -17,6 +17,7 @@ import Yesod.Internal
import qualified Network.Wai as W import qualified Network.Wai as W
import System.Random (RandomGen, newStdGen, randomRs) import System.Random (RandomGen, newStdGen, randomRs)
import Web.Cookie (parseCookiesText) import Web.Cookie (parseCookiesText)
import Data.ByteString (ByteString)
import qualified Data.ByteString.Char8 as S8 import qualified Data.ByteString.Char8 as S8
import Data.Text (Text, pack) import Data.Text (Text, pack)
import Network.HTTP.Types (queryToQueryText) import Network.HTTP.Types (queryToQueryText)
@ -25,6 +26,8 @@ import Data.Maybe (fromMaybe, catMaybes)
import qualified Data.ByteString.Lazy as L import qualified Data.ByteString.Lazy as L
import qualified Data.Set as Set import qualified Data.Set as Set
import qualified Data.Text as T import qualified Data.Text as T
import Data.Text.Encoding (decodeUtf8With)
import Data.Text.Encoding.Error (lenientDecode)
-- | The parsed request information. -- | The parsed request information.
data Request = Request data Request = Request
@ -38,14 +41,14 @@ data Request = Request
} }
parseWaiRequest :: W.Request parseWaiRequest :: W.Request
-> [(Text, Text)] -- ^ session -> [(Text, ByteString)] -- ^ session
-> Maybe a -> Maybe a
-> IO Request -> IO Request
parseWaiRequest env session' key' = parseWaiRequest' env session' key' <$> newStdGen parseWaiRequest env session' key' = parseWaiRequest' env session' key' <$> newStdGen
parseWaiRequest' :: RandomGen g parseWaiRequest' :: RandomGen g
=> W.Request => W.Request
-> [(Text, Text)] -- ^ session -> [(Text, ByteString)] -- ^ session
-> Maybe a -> Maybe a
-> g -> g
-> Request -> Request
@ -57,10 +60,13 @@ parseWaiRequest' env session' key' gen = Request gets'' cookies' env langs'' non
cookies' = maybe [] parseCookiesText reqCookie cookies' = maybe [] parseCookiesText reqCookie
acceptLang = lookup "Accept-Language" $ W.requestHeaders env acceptLang = lookup "Accept-Language" $ W.requestHeaders env
langs = map (pack . S8.unpack) $ maybe [] NWP.parseHttpAccept acceptLang langs = map (pack . S8.unpack) $ maybe [] NWP.parseHttpAccept acceptLang
lookupText k = fmap (decodeUtf8With lenientDecode) . lookup k
-- The language preferences are prioritized as follows: -- The language preferences are prioritized as follows:
langs' = catMaybes [ join $ lookup langKey gets' -- Query _LANG langs' = catMaybes [ join $ lookup langKey gets' -- Query _LANG
, lookup langKey cookies' -- Cookie _LANG , lookup langKey cookies' -- Cookie _LANG
, lookup langKey session' -- Session _LANG , lookupText langKey session' -- Session _LANG
] ++ langs -- Accept-Language(s) ] ++ langs -- Accept-Language(s)
-- Github issue #195. We want to add an extra two-letter version of any -- Github issue #195. We want to add an extra two-letter version of any
@ -73,7 +79,7 @@ parseWaiRequest' env session' key' gen = Request gets'' cookies' env langs'' non
-- generated. -- generated.
nonce = case (key', lookup nonceKey session') of nonce = case (key', lookup nonceKey session') of
(Nothing, _) -> Nothing (Nothing, _) -> Nothing
(_, Just x) -> Just x (_, Just x) -> Just $ decodeUtf8With lenientDecode x
_ -> Just $ pack $ randomString 10 gen _ -> Just $ pack $ randomString 10 gen
addTwoLetters :: ([Text] -> [Text], Set.Set Text) -> [Text] -> [Text] addTwoLetters :: ([Text] -> [Text], Set.Set Text) -> [Text] -> [Text]

View File

@ -9,13 +9,14 @@ import Data.Time
import Data.ByteString (ByteString) import Data.ByteString (ByteString)
import Control.Monad (guard) import Control.Monad (guard)
import Data.Text (Text, pack, unpack) import Data.Text (Text, pack, unpack)
import Control.Arrow ((***)) import Control.Arrow (first)
import Control.Applicative ((<$>))
encodeSession :: CS.Key encodeSession :: CS.Key
-> CS.IV -> CS.IV
-> UTCTime -- ^ expire time -> UTCTime -- ^ expire time
-> ByteString -- ^ remote host -> ByteString -- ^ remote host
-> [(Text, Text)] -- ^ session -> [(Text, ByteString)] -- ^ session
-> ByteString -- ^ cookie value -> ByteString -- ^ cookie value
encodeSession key iv expire rhost session' = encodeSession key iv expire rhost session' =
CS.encrypt key iv $ encode $ SessionCookie expire rhost session' CS.encrypt key iv $ encode $ SessionCookie expire rhost session'
@ -24,7 +25,7 @@ decodeSession :: CS.Key
-> UTCTime -- ^ current time -> UTCTime -- ^ current time
-> ByteString -- ^ remote host field -> ByteString -- ^ remote host field
-> ByteString -- ^ cookie value -> ByteString -- ^ cookie value
-> Maybe [(Text, Text)] -> Maybe [(Text, ByteString)]
decodeSession key now rhost encrypted = do decodeSession key now rhost encrypted = do
decrypted <- CS.decrypt key encrypted decrypted <- CS.decrypt key encrypted
SessionCookie expire rhost' session' <- SessionCookie expire rhost' session' <-
@ -33,14 +34,14 @@ decodeSession key now rhost encrypted = do
guard $ rhost' == rhost guard $ rhost' == rhost
return session' return session'
data SessionCookie = SessionCookie UTCTime ByteString [(Text, Text)] data SessionCookie = SessionCookie UTCTime ByteString [(Text, ByteString)]
deriving (Show, Read) deriving (Show, Read)
instance Serialize SessionCookie where instance Serialize SessionCookie where
put (SessionCookie a b c) = putTime a >> put b >> put (map (unpack *** unpack) c) put (SessionCookie a b c) = putTime a >> put b >> put (map (first unpack) c)
get = do get = do
a <- getTime a <- getTime
b <- get b <- get
c <- map (pack *** pack) `fmap` get c <- map (first pack) <$> get
return $ SessionCookie a b c return $ SessionCookie a b c
putTime :: Putter UTCTime putTime :: Putter UTCTime