    {-# LANGUAGE BangPatterns #-}
    {-# LANGUAGE RecordWildCards #-}
    {-# LANGUAGE ScopedTypeVariables #-}

    module Network.Wai.Handler.Warp.HTTP2.PushPromise where

    import qualified Control.Exception as E
    import qualified Network.HTTP.Types as H
    import qualified Network.HTTP2.Server as H2

    import Network.Wai
    import Network.Wai.Handler.Warp.FileInfoCache
    import Network.Wai.Handler.Warp.HTTP2.Request (getHTTP2Data)
    import Network.Wai.Handler.Warp.HTTP2.Types
    import Network.Wai.Handler.Warp.Imports
    import Network.Wai.Handler.Warp.Types

    fromPushPromises :: InternalInfo -> Request -> IO [H2.PushPromise]
    fromPushPromises :: InternalInfo -> Request -> IO [PushPromise]
    fromPushPromises ii :: InternalInfo
    ii req :: Request
    req = do
        Maybe HTTP2Data
    mh2data <- Request -> IO (Maybe HTTP2Data)
    getHTTP2Data Request
    req
        let pp :: [PushPromise]
    pp = case Maybe HTTP2Data
    mh2data of
              Nothing     -> []
              Just h2data :: HTTP2Data
    h2data -> HTTP2Data -> [PushPromise]
    http2dataPushPromise HTTP2Data
    h2data
        [Maybe PushPromise] -> [PushPromise]
    forall a. [Maybe a] -> [a]
    catMaybes ([Maybe PushPromise] -> [PushPromise])
    -> IO [Maybe PushPromise] -> IO [PushPromise]
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> (PushPromise -> IO (Maybe PushPromise))
    -> [PushPromise] -> IO [Maybe PushPromise]
    forall (t :: * -> *) (m :: * -> *) a b.
    (Traversable t, Monad m) =>
    (a -> m b) -> t a -> m (t b)
    mapM (InternalInfo -> PushPromise -> IO (Maybe PushPromise)
    fromPushPromise InternalInfo
    ii) [PushPromise]
    pp

    fromPushPromise :: InternalInfo -> PushPromise -> IO (Maybe H2.PushPromise)
    fromPushPromise :: InternalInfo -> PushPromise -> IO (Maybe PushPromise)
    fromPushPromise ii :: InternalInfo
    ii (PushPromise path :: ByteString
    path file :: FilePath
    file rsphdr :: ResponseHeaders
    rsphdr w :: Weight
    w) = do
        Either IOException FileInfo
    efinfo <- IO FileInfo -> IO (Either IOException FileInfo)
    forall e a. Exception e => IO a -> IO (Either e a)
    E.try (IO FileInfo -> IO (Either IOException FileInfo))
    -> IO FileInfo -> IO (Either IOException FileInfo)
    forall a b. (a -> b) -> a -> b
    $ InternalInfo -> FilePath -> IO FileInfo
    getFileInfo InternalInfo
    ii FilePath
    file
        case Either IOException FileInfo
    efinfo of
          Left (IOException
    _ex :: E.IOException) -> Maybe PushPromise -> IO (Maybe PushPromise)
    forall (m :: * -> *) a. Monad m => a -> m a
    return Maybe PushPromise
    forall a. Maybe a
    Nothing
          Right finfo :: FileInfo
    finfo -> do
              let !siz :: ByteCount
    siz = Integer -> ByteCount
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral (Integer -> ByteCount) -> Integer -> ByteCount
    forall a b. (a -> b) -> a -> b
    $ FileInfo -> Integer
    fileInfoSize FileInfo
    finfo
                  !fileSpec :: FileSpec
    fileSpec = FilePath -> ByteCount -> ByteCount -> FileSpec
    H2.FileSpec FilePath
    file 0 ByteCount
    siz
                  !rsp :: Response
    rsp = Status -> ResponseHeaders -> FileSpec -> Response
    H2.responseFile Status
    H.ok200 ResponseHeaders
    rsphdr FileSpec
    fileSpec
                  !pp :: PushPromise
    pp = ByteString -> Response -> Weight -> PushPromise
    H2.pushPromise ByteString
    path Response
    rsp Weight
    w
              Maybe PushPromise -> IO (Maybe PushPromise)
    forall (m :: * -> *) a. Monad m => a -> m a
    return (Maybe PushPromise -> IO (Maybe PushPromise))
    -> Maybe PushPromise -> IO (Maybe PushPromise)
    forall a b. (a -> b) -> a -> b
    $ PushPromise -> Maybe PushPromise
    forall a. a -> Maybe a
    Just PushPromise
    pp