{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE CPP #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TupleSections #-}
{-# OPTIONS_GHC -fno-warn-deprecations #-}
module Network.Wai.Handler.Warp.Run where
import Control.Arrow (first)
import Control.Exception (allowInterrupt)
import qualified Control.Exception
import qualified UnliftIO
import UnliftIO (toException)
import qualified Data.ByteString as S
import Data.IORef (newIORef, readIORef)
import Data.Streaming.Network (bindPortTCP)
import Foreign.C.Error (Errno(..), eCONNABORTED, eMFILE)
import GHC.IO.Exception (IOException(..), IOErrorType(..))
import Network.Socket (Socket, close, accept, withSocketsDo, SockAddr, setSocketOption, SocketOption(..))
#if MIN_VERSION_network(3,1,1)
import Network.Socket (gracefulClose)
#endif
import qualified Network.Socket.ByteString as Sock
import Network.Wai
import System.Environment (lookupEnv)
import System.IO.Error (ioeGetErrorType)
import qualified System.TimeManager as T
import System.Timeout (timeout)
import Network.Wai.Handler.Warp.Buffer
import Network.Wai.Handler.Warp.Counter
import qualified Network.Wai.Handler.Warp.Date as D
import qualified Network.Wai.Handler.Warp.FdCache as F
import qualified Network.Wai.Handler.Warp.FileInfoCache as I
import Network.Wai.Handler.Warp.HTTP1 (http1)
import Network.Wai.Handler.Warp.HTTP2 (http2)
import Network.Wai.Handler.Warp.HTTP2.Types (isHTTP2)
import Network.Wai.Handler.Warp.Imports hiding (readInt)
import Network.Wai.Handler.Warp.Recv
import Network.Wai.Handler.Warp.SendFile
import Network.Wai.Handler.Warp.Settings
import Network.Wai.Handler.Warp.Types
#if WINDOWS
import Network.Wai.Handler.Warp.Windows
#else
import Network.Socket (fdSocket)
#endif
socketConnection :: Settings -> Socket -> IO Connection
#if MIN_VERSION_network(3,1,1)
socketConnection :: Settings -> Socket -> IO Connection
socketConnection Settings
set Socket
s = do
#else
socketConnection _ s = do
#endif
BufferPool
bufferPool <- IO BufferPool
newBufferPool
Buffer
writeBuf <- Int -> IO Buffer
allocateBuffer Int
bufferSize
let sendall :: ByteString -> IO ()
sendall = Socket -> ByteString -> IO ()
sendAll' Socket
s
IORef Bool
isH2 <- Bool -> IO (IORef Bool)
forall a. a -> IO (IORef a)
newIORef Bool
False
Connection -> IO Connection
forall (m :: * -> *) a. Monad m => a -> m a
return Connection :: ([ByteString] -> IO ())
-> (ByteString -> IO ())
-> SendFile
-> IO ()
-> IO ()
-> Recv
-> RecvBuf
-> Buffer
-> Int
-> IORef Bool
-> Connection
Connection {
connSendMany :: [ByteString] -> IO ()
connSendMany = Socket -> [ByteString] -> IO ()
Sock.sendMany Socket
s
, connSendAll :: ByteString -> IO ()
connSendAll = ByteString -> IO ()
sendall
, connSendFile :: SendFile
connSendFile = Socket -> Buffer -> Int -> (ByteString -> IO ()) -> SendFile
sendFile Socket
s Buffer
writeBuf Int
bufferSize ByteString -> IO ()
sendall
#if MIN_VERSION_network(3,1,1)
, connClose :: IO ()
connClose = do
Bool
h2 <- IORef Bool -> IO Bool
forall a. IORef a -> IO a
readIORef IORef Bool
isH2
let tm :: Int
tm = if Bool
h2 then Settings -> Int
settingsGracefulCloseTimeout2 Settings
set
else Settings -> Int
settingsGracefulCloseTimeout1 Settings
set
if Int
tm Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
0 then
Socket -> IO ()
close Socket
s
else
Socket -> Int -> IO ()
gracefulClose Socket
s Int
tm IO () -> (SomeException -> IO ()) -> IO ()
forall (m :: * -> *) a.
MonadUnliftIO m =>
m a -> (SomeException -> m a) -> m a
`UnliftIO.catchAny` \(UnliftIO.SomeException e
_) -> () -> IO ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()
#else
, connClose = close s
#endif
, connFree :: IO ()
connFree = Buffer -> IO ()
freeBuffer Buffer
writeBuf
, connRecv :: Recv
connRecv = Socket -> BufferPool -> Recv
receive Socket
s BufferPool
bufferPool
, connRecvBuf :: RecvBuf
connRecvBuf = Socket -> RecvBuf
receiveBuf Socket
s
, connWriteBuffer :: Buffer
connWriteBuffer = Buffer
writeBuf
, connBufferSize :: Int
connBufferSize = Int
bufferSize
, connHTTP2 :: IORef Bool
connHTTP2 = IORef Bool
isH2
}
where
sendAll' :: Socket -> ByteString -> IO ()
sendAll' Socket
sock ByteString
bs = (IOError -> Maybe InvalidRequest)
-> (InvalidRequest -> IO ()) -> IO () -> IO ()
forall (m :: * -> *) e b a.
(MonadUnliftIO m, Exception e) =>
(e -> Maybe b) -> (b -> m a) -> m a -> m a
UnliftIO.handleJust
(\ IOError
e -> if IOError -> IOErrorType
ioeGetErrorType IOError
e IOErrorType -> IOErrorType -> Bool
forall a. Eq a => a -> a -> Bool
== IOErrorType
ResourceVanished
then InvalidRequest -> Maybe InvalidRequest
forall a. a -> Maybe a
Just InvalidRequest
ConnectionClosedByPeer
else Maybe InvalidRequest
forall a. Maybe a
Nothing)
InvalidRequest -> IO ()
forall (m :: * -> *) e a. (MonadIO m, Exception e) => e -> m a
UnliftIO.throwIO
(IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ Socket -> ByteString -> IO ()
Sock.sendAll Socket
sock ByteString
bs
run :: Port -> Application -> IO ()
run :: Int -> Application -> IO ()
run Int
p = Settings -> Application -> IO ()
runSettings Settings
defaultSettings { settingsPort :: Int
settingsPort = Int
p }
runEnv :: Port -> Application -> IO ()
runEnv :: Int -> Application -> IO ()
runEnv Int
p Application
app = do
Maybe String
mp <- String -> IO (Maybe String)
lookupEnv String
"PORT"
IO () -> (String -> IO ()) -> Maybe String -> IO ()
forall b a. b -> (a -> b) -> Maybe a -> b
maybe (Int -> Application -> IO ()
run Int
p Application
app) String -> IO ()
runReadPort Maybe String
mp
where
runReadPort :: String -> IO ()
runReadPort :: String -> IO ()
runReadPort String
sp = case ReadS Int
forall a. Read a => ReadS a
reads String
sp of
((Int
p', String
_):[(Int, String)]
_) -> Int -> Application -> IO ()
run Int
p' Application
app
[(Int, String)]
_ -> String -> IO ()
forall (m :: * -> *) a. MonadFail m => String -> m a
fail (String -> IO ()) -> String -> IO ()
forall a b. (a -> b) -> a -> b
$ String
"Invalid value in $PORT: " String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
sp
runSettings :: Settings -> Application -> IO ()
runSettings :: Settings -> Application -> IO ()
runSettings Settings
set Application
app = IO () -> IO ()
forall a. IO a -> IO a
withSocketsDo (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$
IO Socket -> (Socket -> IO ()) -> (Socket -> IO ()) -> IO ()
forall (m :: * -> *) a b c.
MonadUnliftIO m =>
m a -> (a -> m b) -> (a -> m c) -> m c
UnliftIO.bracket
(Int -> HostPreference -> IO Socket
bindPortTCP (Settings -> Int
settingsPort Settings
set) (Settings -> HostPreference
settingsHost Settings
set))
Socket -> IO ()
close
(\Socket
socket -> do
Socket -> IO ()
setSocketCloseOnExec Socket
socket
Settings -> Socket -> Application -> IO ()
runSettingsSocket Settings
set Socket
socket Application
app)
runSettingsSocket :: Settings -> Socket -> Application -> IO ()
runSettingsSocket :: Settings -> Socket -> Application -> IO ()
runSettingsSocket Settings
set Socket
socket Application
app = do
Settings -> IO () -> IO ()
settingsInstallShutdownHandler Settings
set IO ()
closeListenSocket
Settings -> IO (Connection, SockAddr) -> Application -> IO ()
runSettingsConnection Settings
set IO (Connection, SockAddr)
getConn Application
app
where
getConn :: IO (Connection, SockAddr)
getConn = do
#if WINDOWS
(s, sa) <- windowsThreadBlockHack $ accept socket
#else
(Socket
s, SockAddr
sa) <- Socket -> IO (Socket, SockAddr)
accept Socket
socket
#endif
Socket -> IO ()
setSocketCloseOnExec Socket
s
Socket -> SocketOption -> Int -> IO ()
setSocketOption Socket
s SocketOption
NoDelay Int
1 IO () -> (SomeException -> IO ()) -> IO ()
forall (m :: * -> *) a.
MonadUnliftIO m =>
m a -> (SomeException -> m a) -> m a
`UnliftIO.catchAny` \(UnliftIO.SomeException e
_) -> () -> IO ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()
Connection
conn <- Settings -> Socket -> IO Connection
socketConnection Settings
set Socket
s
(Connection, SockAddr) -> IO (Connection, SockAddr)
forall (m :: * -> *) a. Monad m => a -> m a
return (Connection
conn, SockAddr
sa)
closeListenSocket :: IO ()
closeListenSocket = Socket -> IO ()
close Socket
socket
runSettingsConnection :: Settings -> IO (Connection, SockAddr) -> Application -> IO ()
runSettingsConnection :: Settings -> IO (Connection, SockAddr) -> Application -> IO ()
runSettingsConnection Settings
set IO (Connection, SockAddr)
getConn Application
app = Settings -> IO (IO Connection, SockAddr) -> Application -> IO ()
runSettingsConnectionMaker Settings
set IO (IO Connection, SockAddr)
getConnMaker Application
app
where
getConnMaker :: IO (IO Connection, SockAddr)
getConnMaker = do
(Connection
conn, SockAddr
sa) <- IO (Connection, SockAddr)
getConn
(IO Connection, SockAddr) -> IO (IO Connection, SockAddr)
forall (m :: * -> *) a. Monad m => a -> m a
return (Connection -> IO Connection
forall (m :: * -> *) a. Monad m => a -> m a
return Connection
conn, SockAddr
sa)
runSettingsConnectionMaker :: Settings -> IO (IO Connection, SockAddr) -> Application -> IO ()
runSettingsConnectionMaker :: Settings -> IO (IO Connection, SockAddr) -> Application -> IO ()
runSettingsConnectionMaker Settings
x IO (IO Connection, SockAddr)
y =
Settings
-> IO (IO (Connection, Transport), SockAddr)
-> Application
-> IO ()
runSettingsConnectionMakerSecure Settings
x ((IO Connection, SockAddr) -> (IO (Connection, Transport), SockAddr)
forall t d. (IO t, d) -> (IO (t, Transport), d)
toTCP ((IO Connection, SockAddr)
-> (IO (Connection, Transport), SockAddr))
-> IO (IO Connection, SockAddr)
-> IO (IO (Connection, Transport), SockAddr)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> IO (IO Connection, SockAddr)
y)
where
toTCP :: (IO t, d) -> (IO (t, Transport), d)
toTCP = (IO t -> IO (t, Transport)) -> (IO t, d) -> (IO (t, Transport), d)
forall (a :: * -> * -> *) b c d.
Arrow a =>
a b c -> a (b, d) (c, d)
first ((, Transport
TCP) (t -> (t, Transport)) -> IO t -> IO (t, Transport)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$>)
runSettingsConnectionMakerSecure :: Settings -> IO (IO (Connection, Transport), SockAddr) -> Application -> IO ()
runSettingsConnectionMakerSecure :: Settings
-> IO (IO (Connection, Transport), SockAddr)
-> Application
-> IO ()
runSettingsConnectionMakerSecure Settings
set IO (IO (Connection, Transport), SockAddr)
getConnMaker Application
app = do
Settings -> IO ()
settingsBeforeMainLoop Settings
set
Counter
counter <- IO Counter
newCounter
Settings -> (InternalInfo -> IO ()) -> IO ()
forall a. Settings -> (InternalInfo -> IO a) -> IO a
withII Settings
set ((InternalInfo -> IO ()) -> IO ())
-> (InternalInfo -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ Settings
-> IO (IO (Connection, Transport), SockAddr)
-> Application
-> Counter
-> InternalInfo
-> IO ()
acceptConnection Settings
set IO (IO (Connection, Transport), SockAddr)
getConnMaker Application
app Counter
counter
withII :: Settings -> (InternalInfo -> IO a) -> IO a
withII :: Settings -> (InternalInfo -> IO a) -> IO a
withII Settings
set InternalInfo -> IO a
action =
(Manager -> IO a) -> IO a
forall c. (Manager -> IO c) -> IO c
withTimeoutManager ((Manager -> IO a) -> IO a) -> (Manager -> IO a) -> IO a
forall a b. (a -> b) -> a -> b
$ \Manager
tm ->
(Recv -> IO a) -> IO a
forall a. (Recv -> IO a) -> IO a
D.withDateCache ((Recv -> IO a) -> IO a) -> (Recv -> IO a) -> IO a
forall a b. (a -> b) -> a -> b
$ \Recv
dc ->
Int -> ((String -> IO (Maybe Fd, IO ())) -> IO a) -> IO a
forall a. Int -> ((String -> IO (Maybe Fd, IO ())) -> IO a) -> IO a
F.withFdCache Int
fdCacheDurationInSeconds (((String -> IO (Maybe Fd, IO ())) -> IO a) -> IO a)
-> ((String -> IO (Maybe Fd, IO ())) -> IO a) -> IO a
forall a b. (a -> b) -> a -> b
$ \String -> IO (Maybe Fd, IO ())
fdc ->
Int -> ((String -> IO FileInfo) -> IO a) -> IO a
forall a. Int -> ((String -> IO FileInfo) -> IO a) -> IO a
I.withFileInfoCache Int
fdFileInfoDurationInSeconds (((String -> IO FileInfo) -> IO a) -> IO a)
-> ((String -> IO FileInfo) -> IO a) -> IO a
forall a b. (a -> b) -> a -> b
$ \String -> IO FileInfo
fic -> do
let ii :: InternalInfo
ii = Manager
-> Recv
-> (String -> IO (Maybe Fd, IO ()))
-> (String -> IO FileInfo)
-> InternalInfo
InternalInfo Manager
tm Recv
dc String -> IO (Maybe Fd, IO ())
fdc String -> IO FileInfo
fic
InternalInfo -> IO a
action InternalInfo
ii
where
!fdCacheDurationInSeconds :: Int
fdCacheDurationInSeconds = Settings -> Int
settingsFdCacheDuration Settings
set Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
1000000
!fdFileInfoDurationInSeconds :: Int
fdFileInfoDurationInSeconds = Settings -> Int
settingsFileInfoCacheDuration Settings
set Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
1000000
!timeoutInSeconds :: Int
timeoutInSeconds = Settings -> Int
settingsTimeout Settings
set Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
1000000
withTimeoutManager :: (Manager -> IO c) -> IO c
withTimeoutManager Manager -> IO c
f = case Settings -> Maybe Manager
settingsManager Settings
set of
Just Manager
tm -> Manager -> IO c
f Manager
tm
Maybe Manager
Nothing -> IO Manager -> (Manager -> IO ()) -> (Manager -> IO c) -> IO c
forall (m :: * -> *) a b c.
MonadUnliftIO m =>
m a -> (a -> m b) -> (a -> m c) -> m c
UnliftIO.bracket
(Int -> IO Manager
T.initialize Int
timeoutInSeconds)
Manager -> IO ()
T.stopManager
Manager -> IO c
f
acceptConnection :: Settings
-> IO (IO (Connection, Transport), SockAddr)
-> Application
-> Counter
-> InternalInfo
-> IO ()
acceptConnection :: Settings
-> IO (IO (Connection, Transport), SockAddr)
-> Application
-> Counter
-> InternalInfo
-> IO ()
acceptConnection Settings
set IO (IO (Connection, Transport), SockAddr)
getConnMaker Application
app Counter
counter InternalInfo
ii = do
IO () -> IO ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ IO () -> IO ()
forall (m :: * -> *) a. MonadUnliftIO m => m a -> m a
UnliftIO.mask_ IO ()
acceptLoop
Settings -> Counter -> IO ()
gracefulShutdown Settings
set Counter
counter
where
acceptLoop :: IO ()
acceptLoop = do
IO ()
allowInterrupt
Maybe (IO (Connection, Transport), SockAddr)
mx <- IO (Maybe (IO (Connection, Transport), SockAddr))
acceptNewConnection
case Maybe (IO (Connection, Transport), SockAddr)
mx of
Maybe (IO (Connection, Transport), SockAddr)
Nothing -> () -> IO ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()
Just (IO (Connection, Transport)
mkConn, SockAddr
addr) -> do
Settings
-> IO (Connection, Transport)
-> SockAddr
-> Application
-> Counter
-> InternalInfo
-> IO ()
fork Settings
set IO (Connection, Transport)
mkConn SockAddr
addr Application
app Counter
counter InternalInfo
ii
IO ()
acceptLoop
acceptNewConnection :: IO (Maybe (IO (Connection, Transport), SockAddr))
acceptNewConnection = do
Either IOError (IO (Connection, Transport), SockAddr)
ex <- IO (IO (Connection, Transport), SockAddr)
-> IO (Either IOError (IO (Connection, Transport), SockAddr))
forall (m :: * -> *) a.
MonadUnliftIO m =>
m a -> m (Either IOError a)
UnliftIO.tryIO IO (IO (Connection, Transport), SockAddr)
getConnMaker
case Either IOError (IO (Connection, Transport), SockAddr)
ex of
Right (IO (Connection, Transport), SockAddr)
x -> Maybe (IO (Connection, Transport), SockAddr)
-> IO (Maybe (IO (Connection, Transport), SockAddr))
forall (m :: * -> *) a. Monad m => a -> m a
return (Maybe (IO (Connection, Transport), SockAddr)
-> IO (Maybe (IO (Connection, Transport), SockAddr)))
-> Maybe (IO (Connection, Transport), SockAddr)
-> IO (Maybe (IO (Connection, Transport), SockAddr))
forall a b. (a -> b) -> a -> b
$ (IO (Connection, Transport), SockAddr)
-> Maybe (IO (Connection, Transport), SockAddr)
forall a. a -> Maybe a
Just (IO (Connection, Transport), SockAddr)
x
Left IOError
e -> do
let getErrno :: Errno -> CInt
getErrno (Errno CInt
cInt) = CInt
cInt
eConnAborted :: CInt
eConnAborted = Errno -> CInt
getErrno Errno
eCONNABORTED
eMfile :: CInt
eMfile = Errno -> CInt
getErrno Errno
eMFILE
merrno :: Maybe CInt
merrno = IOError -> Maybe CInt
ioe_errno IOError
e
if Maybe CInt
merrno Maybe CInt -> Maybe CInt -> Bool
forall a. Eq a => a -> a -> Bool
== CInt -> Maybe CInt
forall a. a -> Maybe a
Just CInt
eConnAborted Bool -> Bool -> Bool
|| Maybe CInt
merrno Maybe CInt -> Maybe CInt -> Bool
forall a. Eq a => a -> a -> Bool
== CInt -> Maybe CInt
forall a. a -> Maybe a
Just CInt
eMfile
then IO (Maybe (IO (Connection, Transport), SockAddr))
acceptNewConnection
else do
Settings -> Maybe Request -> SomeException -> IO ()
settingsOnException Settings
set Maybe Request
forall a. Maybe a
Nothing (SomeException -> IO ()) -> SomeException -> IO ()
forall a b. (a -> b) -> a -> b
$ IOError -> SomeException
forall e. Exception e => e -> SomeException
toException IOError
e
Maybe (IO (Connection, Transport), SockAddr)
-> IO (Maybe (IO (Connection, Transport), SockAddr))
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe (IO (Connection, Transport), SockAddr)
forall a. Maybe a
Nothing
fork :: Settings
-> IO (Connection, Transport)
-> SockAddr
-> Application
-> Counter
-> InternalInfo
-> IO ()
fork :: Settings
-> IO (Connection, Transport)
-> SockAddr
-> Application
-> Counter
-> InternalInfo
-> IO ()
fork Settings
set IO (Connection, Transport)
mkConn SockAddr
addr Application
app Counter
counter InternalInfo
ii = Settings -> ((forall a. IO a -> IO a) -> IO ()) -> IO ()
settingsFork Settings
set (((forall a. IO a -> IO a) -> IO ()) -> IO ())
-> ((forall a. IO a -> IO a) -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \forall a. IO a -> IO a
unmask ->
(SomeException -> IO ()) -> IO () -> IO ()
forall e a. Exception e => (e -> IO a) -> IO a -> IO a
Control.Exception.handle (Settings -> Maybe Request -> SomeException -> IO ()
settingsOnException Settings
set Maybe Request
forall a. Maybe a
Nothing) (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$
IO (Connection, Transport)
-> ((Connection, Transport) -> IO ())
-> ((Connection, Transport) -> IO ())
-> IO ()
forall (m :: * -> *) a b c.
MonadUnliftIO m =>
m a -> (a -> m b) -> (a -> m c) -> m c
UnliftIO.bracket IO (Connection, Transport)
mkConn (Connection, Transport) -> IO ()
forall b. (Connection, b) -> IO ()
cleanUp ((IO () -> IO ()) -> (Connection, Transport) -> IO ()
forall c. (IO () -> IO c) -> (Connection, Transport) -> IO c
serve IO () -> IO ()
forall a. IO a -> IO a
unmask)
where
cleanUp :: (Connection, b) -> IO ()
cleanUp (Connection
conn, b
_) = Connection -> IO ()
connClose Connection
conn IO () -> IO () -> IO ()
forall (m :: * -> *) a b. MonadUnliftIO m => m a -> m b -> m a
`UnliftIO.finally` Connection -> IO ()
connFree Connection
conn
serve :: (IO () -> IO c) -> (Connection, Transport) -> IO c
serve IO () -> IO c
unmask (Connection
conn, Transport
transport) = IO Handle -> (Handle -> IO ()) -> (Handle -> IO c) -> IO c
forall (m :: * -> *) a b c.
MonadUnliftIO m =>
m a -> (a -> m b) -> (a -> m c) -> m c
UnliftIO.bracket IO Handle
register Handle -> IO ()
cancel ((Handle -> IO c) -> IO c) -> (Handle -> IO c) -> IO c
forall a b. (a -> b) -> a -> b
$ \Handle
th -> do
IO () -> IO c
unmask (IO () -> IO c)
-> ((Bool -> IO ()) -> IO ()) -> (Bool -> IO ()) -> IO c
forall b c a. (b -> c) -> (a -> b) -> a -> c
.
IO Bool -> (Bool -> IO ()) -> (Bool -> IO ()) -> IO ()
forall (m :: * -> *) a b c.
MonadUnliftIO m =>
m a -> (a -> m b) -> (a -> m c) -> m c
UnliftIO.bracket (SockAddr -> IO Bool
onOpen SockAddr
addr) (SockAddr -> Bool -> IO ()
forall p. SockAddr -> p -> IO ()
onClose SockAddr
addr) ((Bool -> IO ()) -> IO c) -> (Bool -> IO ()) -> IO c
forall a b. (a -> b) -> a -> b
$ \Bool
goingon ->
Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when Bool
goingon (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ Connection
-> InternalInfo
-> Handle
-> SockAddr
-> Transport
-> Settings
-> Application
-> IO ()
serveConnection Connection
conn InternalInfo
ii Handle
th SockAddr
addr Transport
transport Settings
set Application
app
where
register :: IO Handle
register = Manager -> IO () -> IO Handle
T.registerKillThread (InternalInfo -> Manager
timeoutManager InternalInfo
ii) (Connection -> IO ()
connClose Connection
conn)
cancel :: Handle -> IO ()
cancel = Handle -> IO ()
T.cancel
onOpen :: SockAddr -> IO Bool
onOpen SockAddr
adr = Counter -> IO ()
increase Counter
counter IO () -> IO Bool -> IO Bool
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> Settings -> SockAddr -> IO Bool
settingsOnOpen Settings
set SockAddr
adr
onClose :: SockAddr -> p -> IO ()
onClose SockAddr
adr p
_ = Counter -> IO ()
decrease Counter
counter IO () -> IO () -> IO ()
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> Settings -> SockAddr -> IO ()
settingsOnClose Settings
set SockAddr
adr
serveConnection :: Connection
-> InternalInfo
-> T.Handle
-> SockAddr
-> Transport
-> Settings
-> Application
-> IO ()
serveConnection :: Connection
-> InternalInfo
-> Handle
-> SockAddr
-> Transport
-> Settings
-> Application
-> IO ()
serveConnection Connection
conn InternalInfo
ii Handle
th SockAddr
origAddr Transport
transport Settings
settings Application
app = do
(Bool
h2,ByteString
bs) <- if Transport -> Bool
isHTTP2 Transport
transport then
(Bool, ByteString) -> IO (Bool, ByteString)
forall (m :: * -> *) a. Monad m => a -> m a
return (Bool
True, ByteString
"")
else do
ByteString
bs0 <- Connection -> Recv
connRecv Connection
conn
if ByteString -> Int
S.length ByteString
bs0 Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int
4 Bool -> Bool -> Bool
&& ByteString
"PRI " ByteString -> ByteString -> Bool
`S.isPrefixOf` ByteString
bs0 then
(Bool, ByteString) -> IO (Bool, ByteString)
forall (m :: * -> *) a. Monad m => a -> m a
return (Bool
True, ByteString
bs0)
else
(Bool, ByteString) -> IO (Bool, ByteString)
forall (m :: * -> *) a. Monad m => a -> m a
return (Bool
False, ByteString
bs0)
if Settings -> Bool
settingsHTTP2Enabled Settings
settings Bool -> Bool -> Bool
&& Bool
h2 then do
Settings
-> InternalInfo
-> Connection
-> Transport
-> Application
-> SockAddr
-> Handle
-> ByteString
-> IO ()
http2 Settings
settings InternalInfo
ii Connection
conn Transport
transport Application
app SockAddr
origAddr Handle
th ByteString
bs
else do
Settings
-> InternalInfo
-> Connection
-> Transport
-> Application
-> SockAddr
-> Handle
-> ByteString
-> IO ()
http1 Settings
settings InternalInfo
ii Connection
conn Transport
transport Application
app SockAddr
origAddr Handle
th ByteString
bs
setSocketCloseOnExec :: Socket -> IO ()
#if WINDOWS
setSocketCloseOnExec _ = return ()
#else
setSocketCloseOnExec :: Socket -> IO ()
setSocketCloseOnExec Socket
socket = do
#if MIN_VERSION_network(3,0,0)
CInt
fd <- Socket -> IO CInt
fdSocket Socket
socket
#else
let fd = fdSocket socket
#endif
Fd -> IO ()
F.setFileCloseOnExec (Fd -> IO ()) -> Fd -> IO ()
forall a b. (a -> b) -> a -> b
$ CInt -> Fd
forall a b. (Integral a, Num b) => a -> b
fromIntegral CInt
fd
#endif
gracefulShutdown :: Settings -> Counter -> IO ()
gracefulShutdown :: Settings -> Counter -> IO ()
gracefulShutdown Settings
set Counter
counter =
case Settings -> Maybe Int
settingsGracefulShutdownTimeout Settings
set of
Maybe Int
Nothing ->
Counter -> IO ()
waitForZero Counter
counter
(Just Int
seconds) ->
IO (Maybe ()) -> IO ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (Int -> IO () -> IO (Maybe ())
forall a. Int -> IO a -> IO (Maybe a)
timeout (Int
seconds Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
microsPerSecond) (Counter -> IO ()
waitForZero Counter
counter))
where microsPerSecond :: Int
microsPerSecond = Int
1000000