http2-tls-0.5.0: Network/HTTP2/TLS/Server.hs
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RecordWildCards #-}
module Network.HTTP2.TLS.Server (
-- * Runners
run,
runWithSocket,
runH2C,
runH2CWithSocket,
Server,
HostName,
PortNumber,
runTLS,
runTLSWithSocket,
-- * Settings
Settings,
defaultSettings,
settingsTimeout,
settingsSendBufferSize,
settingsSlowlorisSize,
settingsReadBufferSize,
settingsReadBufferLowerLimit,
settingsKeyLogger,
settingsNumberOfWorkers,
settingsConcurrentStreams,
settingsConnectionWindowSize,
settingsStreamWindowSize,
settingsSessionManager,
settingsEarlyDataSize,
-- ** Rate limits
settingsPingRateLimit,
settingsEmptyFrameRateLimit,
settingsSettingsRateLimit,
settingsRstRateLimit,
-- * IO backend
IOBackend,
send,
sendMany,
recv,
requestSock,
mySockAddr,
peerSockAddr,
-- * Internal
runIO,
runIOH2C,
Stream,
ServerIO (..),
) where
import qualified Control.Exception as E
import Data.ByteString (ByteString)
import Network.HTTP2.Server (
Server,
connectionWindowSize,
defaultServerConfig,
emptyFrameRateLimit,
initialWindowSize,
maxConcurrentStreams,
pingRateLimit,
rstRateLimit,
settings,
settingsRateLimit,
)
import qualified Network.HTTP2.Server as H2Server
import Network.HTTP2.Server.Internal (ServerIO, Stream)
import qualified Network.HTTP2.Server.Internal as H2I
import Network.Run.TCP.Timeout
import Network.Socket (
HostName,
PortNumber,
Socket,
)
import Network.TLS hiding (HostName)
import qualified System.TimeManager as T
import Network.HTTP2.TLS.Config
import Network.HTTP2.TLS.IO
import Network.HTTP2.TLS.Server.Settings
import Network.HTTP2.TLS.Supported
-- | Running a TLS client.
-- 'IOBackend' provides sending and receiving functions
-- with timeout based on 'Settings'.
runTLS
:: Settings
-> Credentials
-> HostName
-> PortNumber
-> ByteString
-- ^ ALPN
-> (T.Manager -> IOBackend -> IO ())
-> IO ()
runTLS settings creds host port alpn action =
runTCPServer
(settingsTimeout settings)
(Just host)
(show port)
$ \mgr th sock -> do
backend <- mkBackend settings sock
ctx <- contextNew backend params
handshake ctx
iobackend <- timeoutIOBackend th settings <$> tlsIOBackend ctx sock
action mgr iobackend
bye ctx
where
params = getServerParams settings creds alpn
-- | Running a TLS client.
-- 'IOBackend' provides sending and receiving functions
-- with timeout based on 'Settings'.
runTLSWithSocket
:: Settings
-> Credentials
-> Socket
-> ByteString
-- ^ ALPN
-> (T.Manager -> IOBackend -> IO ())
-> IO ()
runTLSWithSocket settings creds s alpn action =
runTCPServerWithSocket
(settingsTimeout settings)
s
$ \mgr th sock -> do
backend <- mkBackend settings sock
ctx <- contextNew backend params
handshake ctx
iobackend <- timeoutIOBackend th settings <$> tlsIOBackend ctx sock
r <- action mgr iobackend
bye ctx
return r
where
params = getServerParams settings creds alpn
-- | Running an HTTP\/2 client over TLS (over TCP).
-- ALPN is "h2".
run :: Settings -> Credentials -> HostName -> PortNumber -> Server -> IO ()
run settings creds host port server =
runTLS settings creds host port "h2" $ run' settings server
-- | Running an HTTP\/2 client over TLS (over TCP).
-- ALPN is "h2".
runWithSocket :: Settings -> Credentials -> Socket -> Server -> IO ()
runWithSocket settings creds s server =
runTLSWithSocket settings creds s "h2" $ run' settings server
-- | Running an HTTP\/2 client over TCP.
runH2C :: Settings -> HostName -> PortNumber -> Server -> IO ()
runH2C settings@Settings{..} host port server =
runTCPServer
settingsTimeout
(Just host)
(show port)
$ \mgr th sock -> do
iobackend0 <- tcpIOBackend settings sock
let iobackend = timeoutIOBackend th settings iobackend0
run' settings server mgr iobackend
-- | Running an HTTP\/2 client over TCP.
runH2CWithSocket :: Settings -> Socket -> Server -> IO ()
runH2CWithSocket settings@Settings{..} s server =
runTCPServerWithSocket
settingsTimeout
s
$ \mgr th sock -> do
iobackend0 <- tcpIOBackend settings sock
let iobackend = timeoutIOBackend th settings iobackend0
run' settings server mgr iobackend
run' :: Settings -> Server -> T.Manager -> IOBackend -> IO ()
run' settings0@Settings{..} server mgr IOBackend{..} =
E.bracket
(allocConfigForServer settings0 mgr send recv mySockAddr peerSockAddr)
freeConfigForServer
(\conf -> H2Server.run sconf conf server)
where
sconf =
defaultServerConfig
{ connectionWindowSize = settingsConnectionWindowSize
, settings =
(settings defaultServerConfig)
{ initialWindowSize = settingsStreamWindowSize
, maxConcurrentStreams = Just settingsConcurrentStreams
, pingRateLimit = settingsPingRateLimit
, emptyFrameRateLimit = settingsEmptyFrameRateLimit
, settingsRateLimit = settingsSettingsRateLimit
, rstRateLimit = settingsRstRateLimit
}
}
runIO
:: Settings
-> Credentials
-> Socket
-> (ServerIO Stream -> IO (IO ()))
-> IO ()
runIO settings creds s action =
runTLSWithSocket settings creds s "h2" $ \mgr iobackend ->
runIO' settings action mgr iobackend
runIO'
:: Settings -> (ServerIO Stream -> IO (IO ())) -> T.Manager -> IOBackend -> IO ()
runIO' settings0@Settings{..} action mgr IOBackend{..} =
E.bracket
(allocConfigForServer settings0 mgr send recv mySockAddr peerSockAddr)
freeConfigForServer
(\conf -> H2I.runIO sconf conf action)
where
sconf =
defaultServerConfig
{ connectionWindowSize = settingsConnectionWindowSize
, settings =
(settings defaultServerConfig)
{ initialWindowSize = settingsStreamWindowSize
, maxConcurrentStreams = Just settingsConcurrentStreams
, pingRateLimit = settingsPingRateLimit
, emptyFrameRateLimit = settingsEmptyFrameRateLimit
, settingsRateLimit = settingsSettingsRateLimit
, rstRateLimit = settingsRstRateLimit
}
}
runIOH2C
:: Settings -> Socket -> (ServerIO Stream -> IO (IO ())) -> IO ()
runIOH2C settings0@Settings{..} s action =
runTCPServerWithSocket
settingsTimeout
s
$ \mgr th sock -> do
iobackend0 <- tcpIOBackend settings0 sock
let iobackend = timeoutIOBackend th settings0 iobackend0
runIO' settings0 action mgr iobackend
----------------------------------------------------------------
getServerParams
:: Settings
-> Credentials
-> ByteString
-> ServerParams
getServerParams Settings{..} creds alpn =
defaultParamsServer
{ serverSupported = supported
, serverShared = shared
, serverHooks = hooks
, serverDebug = debug
, serverEarlyDataSize = settingsEarlyDataSize
}
where
shared =
defaultShared
{ sharedCredentials = creds
, sharedSessionManager = settingsSessionManager
}
supported = strongSupported
hooks =
defaultServerHooks
{ onALPNClientSuggest = Just $ selectALPN alpn
}
debug =
defaultDebugParams
{ debugKeyLogger = settingsKeyLogger
}
selectALPN :: ByteString -> [ByteString] -> IO ByteString
selectALPN key xs
| key `elem` xs = return key
| otherwise = return ""