module Yesod.Session.Cookie.Logic
  ( setCookie
  , CookieContext (..)
  ) where

import Internal.Prelude

import Yesod.Core.Types (Header)
import Yesod.Session.Cookie.SetCookie
import Yesod.Session.Options
import Yesod.Session.SaveResult
import Yesod.Session.SessionType

data CookieContext = CookieContext
  { CookieContext -> Maybe ByteString
cookie :: Maybe ByteString
  , CookieContext -> Maybe Session
load :: Maybe Session
  , CookieContext -> SaveResult Session
save :: SaveResult Session
  }

setCookie :: Options tx m -> CookieContext -> [Header]
setCookie :: forall (tx :: * -> *) (m :: * -> *).
Options tx m -> CookieContext -> [Header]
setCookie Options tx m
options = \case
  CookieContext {$sel:save:CookieContext :: CookieContext -> SaveResult Session
save = SaveResult Session
Frozen} ->
    -- Never send anything when a freeze was requested.
    []
  CookieContext {$sel:save:CookieContext :: CookieContext -> SaveResult Session
save = SaveResult Session
Deleted} ->
    -- There was a session but it's now gone; send deletion
    -- cookies so the client can forget all about it.
    Maybe Session -> [Header]
cookiesForSession Maybe Session
forall a. Maybe a
Nothing
  CookieContext {$sel:save:CookieContext :: CookieContext -> SaveResult Session
save = Saved Session
s} ->
    -- Any time a session was saved, send cookies.
    -- At the very least this will probably be wanted to give
    -- the client a new expiration time.
    Maybe Session -> [Header]
cookiesForSession (Session -> Maybe Session
forall a. a -> Maybe a
Just Session
s)
  CookieContext {$sel:save:CookieContext :: CookieContext -> SaveResult Session
save = SaveResult Session
NoChange, $sel:load:CookieContext :: CookieContext -> Maybe Session
load = Just Session
s} ->
    -- There was a session loaded but change saved; send cookies
    -- for the session that was loaded. This is probably superfluous.
    -- It will only be useful if the server's timeout settings
    -- have changed. But it's low cost, so might as well do it.
    Maybe Session -> [Header]
cookiesForSession (Session -> Maybe Session
forall a. a -> Maybe a
Just Session
s)
  CookieContext {$sel:save:CookieContext :: CookieContext -> SaveResult Session
save = SaveResult Session
NoChange, $sel:load:CookieContext :: CookieContext -> Maybe Session
load = Maybe Session
Nothing, $sel:cookie:CookieContext :: CookieContext -> Maybe ByteString
cookie = Maybe ByteString
Nothing} ->
    -- No cookie was sent, no session was loaded, no change was saved.
    -- There is nothing to send.
    []
  CookieContext {$sel:save:CookieContext :: CookieContext -> SaveResult Session
save = SaveResult Session
NoChange, $sel:load:CookieContext :: CookieContext -> Maybe Session
load = Maybe Session
Nothing, $sel:cookie:CookieContext :: CookieContext -> Maybe ByteString
cookie = Just ByteString
_} ->
    -- The client sent a cookie but it did not result in a session load,
    -- and there is no new session key to send. Send a deletion to put
    -- this worthless session cookie out of its misery.
    Maybe Session -> [Header]
cookiesForSession Maybe Session
forall a. Maybe a
Nothing
 where
  cookiesForSession :: Maybe Session -> [Header]
  cookiesForSession :: Maybe Session -> [Header]
cookiesForSession = Options tx m -> Maybe (SessionKey, Time UTCTime) -> [Header]
forall (tx :: * -> *) (m :: * -> *).
Options tx m -> Maybe (SessionKey, Time UTCTime) -> [Header]
makeSetCookieHeaders Options tx m
options (Maybe (SessionKey, Time UTCTime) -> [Header])
-> (Maybe Session -> Maybe (SessionKey, Time UTCTime))
-> Maybe Session
-> [Header]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Session -> (SessionKey, Time UTCTime))
-> Maybe Session -> Maybe (SessionKey, Time UTCTime)
forall a b. (a -> b) -> Maybe a -> Maybe b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (\Session
s -> (Session
s.key, Session
s.time))