module Network.Salvia.Handler.Close ( hCloseConn , hKeepAlive , emptyQueue ) where import Control.Monad.State import Data.Maybe import Data.Record.Label import Network.Protocol.Http import Network.Salvia.Interface import Network.Salvia.Handler.Error import System.IO -- | Run a handler once and close the connection afterwards. hCloseConn :: (HandleM m, MonadIO m) => m a -> m () hCloseConn h = h >> handle >>= flip catchIO () . hClose {- | Run a handler and keep the connection open for potential consecutive requests. The connection will only be closed after a request finished and one or more of the following criteria are met: * There is no `contentLength` set in the response headers. When this is the case the connection cannot be kept alive. * The client has set the `connection` header field to 'close'. * The connection has already been closed, possible due to IO errors. * The HTTP version is HTTP/1.0. -} hKeepAlive :: (QueueM m, HandleM m, HttpM' m, MonadIO m) => m a -> m () hKeepAlive handler = do _ <- handler h <- handle conn <- request (getM connection) ver <- request (getM version) len <- response (getM contentLength) closed <- liftIO (hIsClosed h) if or [ closed , conn == Just "Close" , isNothing (len :: Maybe Integer) , ver == http10 ] then catchIO (hClose h) () else resetContext >> hKeepAlive handler resetContext :: (HttpM' m, QueueM m) => m () resetContext = do request (put emptyRequest) response (put emptyResponse) emptyQueue -- | Empty the send queue. emptyQueue :: QueueM m => m () emptyQueue = dequeue >>= return () `maybe` const emptyQueue