{-# OPTIONS_GHC -fno-warn-deprecations #-}
module Network.Wai
    (
      
      Application
    , Middleware
    , ResponseReceived
      
    , Request
    , defaultRequest
    , RequestBodyLength (..)
      
    , requestMethod
    , httpVersion
    , rawPathInfo
    , rawQueryString
    , requestHeaders
    , isSecure
    , remoteHost
    , pathInfo
    , queryString
    , getRequestBodyChunk
    , requestBody
    , vault
    , requestBodyLength
    , requestHeaderHost
    , requestHeaderRange
    , requestHeaderReferer
    , requestHeaderUserAgent
    
    , strictRequestBody
    , consumeRequestBodyStrict
    , lazyRequestBody
    , consumeRequestBodyLazy
      
    , setRequestBodyChunks
    , mapRequestHeaders
      
    , Response
    , StreamingBody
    , FilePart (..)
      
    , responseFile
    , responseBuilder
    , responseLBS
    , responseStream
    , responseRaw
      
    , responseStatus
    , responseHeaders
      
    , responseToStream
    , mapResponseHeaders
    , mapResponseStatus
      
    , ifRequest
    , modifyRequest
    , modifyResponse
    ) where
import           Data.ByteString.Builder      (Builder, byteString, lazyByteString)
import           Control.Monad                (unless)
import qualified Data.ByteString              as B
import qualified Data.ByteString.Lazy         as L
import qualified Data.ByteString.Lazy.Internal as LI
import           Data.ByteString.Lazy.Internal (defaultChunkSize)
import           Data.Function                (fix)
import qualified Network.HTTP.Types           as H
import           Network.Socket               (SockAddr (SockAddrInet))
import           Network.Wai.Internal
import qualified System.IO                    as IO
import           System.IO.Unsafe             (unsafeInterleaveIO)
responseFile :: H.Status -> H.ResponseHeaders -> FilePath -> Maybe FilePart -> Response
responseFile :: Status -> ResponseHeaders -> FilePath -> Maybe FilePart -> Response
responseFile = Status -> ResponseHeaders -> FilePath -> Maybe FilePart -> Response
ResponseFile
responseBuilder :: H.Status -> H.ResponseHeaders -> Builder -> Response
responseBuilder :: Status -> ResponseHeaders -> Builder -> Response
responseBuilder = Status -> ResponseHeaders -> Builder -> Response
ResponseBuilder
responseLBS :: H.Status -> H.ResponseHeaders -> L.ByteString -> Response
responseLBS :: Status -> ResponseHeaders -> ByteString -> Response
responseLBS Status
s ResponseHeaders
h = Status -> ResponseHeaders -> Builder -> Response
ResponseBuilder Status
s ResponseHeaders
h (Builder -> Response)
-> (ByteString -> Builder) -> ByteString -> Response
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> Builder
lazyByteString
responseStream :: H.Status
               -> H.ResponseHeaders
               -> StreamingBody
               -> Response
responseStream :: Status -> ResponseHeaders -> StreamingBody -> Response
responseStream = Status -> ResponseHeaders -> StreamingBody -> Response
ResponseStream
responseRaw :: (IO B.ByteString -> (B.ByteString -> IO ()) -> IO ())
            -> Response
            -> Response
responseRaw :: (IO ByteString -> (ByteString -> IO ()) -> IO ())
-> Response -> Response
responseRaw = (IO ByteString -> (ByteString -> IO ()) -> IO ())
-> Response -> Response
ResponseRaw
responseStatus :: Response -> H.Status
responseStatus :: Response -> Status
responseStatus (ResponseFile    Status
s ResponseHeaders
_ FilePath
_ Maybe FilePart
_) = Status
s
responseStatus (ResponseBuilder Status
s ResponseHeaders
_ Builder
_  ) = Status
s
responseStatus (ResponseStream  Status
s ResponseHeaders
_ StreamingBody
_  ) = Status
s
responseStatus (ResponseRaw IO ByteString -> (ByteString -> IO ()) -> IO ()
_ Response
res      ) = Response -> Status
responseStatus Response
res
responseHeaders :: Response -> H.ResponseHeaders
 (ResponseFile    Status
_ ResponseHeaders
hs FilePath
_ Maybe FilePart
_) = ResponseHeaders
hs
responseHeaders (ResponseBuilder Status
_ ResponseHeaders
hs Builder
_  ) = ResponseHeaders
hs
responseHeaders (ResponseStream  Status
_ ResponseHeaders
hs StreamingBody
_  ) = ResponseHeaders
hs
responseHeaders (ResponseRaw IO ByteString -> (ByteString -> IO ()) -> IO ()
_ Response
res)        = Response -> ResponseHeaders
responseHeaders Response
res
responseToStream :: Response
                 -> ( H.Status
                    , H.ResponseHeaders
                    , (StreamingBody -> IO a) -> IO a
                    )
responseToStream :: forall a.
Response
-> (Status, ResponseHeaders, (StreamingBody -> IO a) -> IO a)
responseToStream (ResponseStream Status
s ResponseHeaders
h StreamingBody
b) = (Status
s, ResponseHeaders
h, ((StreamingBody -> IO a) -> StreamingBody -> IO a
forall a b. (a -> b) -> a -> b
$ StreamingBody
b))
responseToStream (ResponseFile Status
s ResponseHeaders
h FilePath
fp (Just FilePart
part)) =
    ( Status
s
    , ResponseHeaders
h
    , \StreamingBody -> IO a
withBody -> FilePath -> IOMode -> (Handle -> IO a) -> IO a
forall r. FilePath -> IOMode -> (Handle -> IO r) -> IO r
IO.withBinaryFile FilePath
fp IOMode
IO.ReadMode ((Handle -> IO a) -> IO a) -> (Handle -> IO a) -> IO a
forall a b. (a -> b) -> a -> b
$ \Handle
handle -> StreamingBody -> IO a
withBody (StreamingBody -> IO a) -> StreamingBody -> IO a
forall a b. (a -> b) -> a -> b
$ \Builder -> IO ()
sendChunk IO ()
_flush -> do
        Handle -> SeekMode -> Integer -> IO ()
IO.hSeek Handle
handle SeekMode
IO.AbsoluteSeek (Integer -> IO ()) -> Integer -> IO ()
forall a b. (a -> b) -> a -> b
$ FilePart -> Integer
filePartOffset FilePart
part
        let loop :: Int -> IO ()
loop Int
remaining | Int
remaining Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
0 = () -> IO ()
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return ()
            loop Int
remaining = do
                ByteString
bs <- Handle -> Int -> IO ByteString
B.hGetSome Handle
handle Int
defaultChunkSize
                Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
unless (ByteString -> Bool
B.null ByteString
bs) (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ do
                    let x :: ByteString
x = Int -> ByteString -> ByteString
B.take Int
remaining ByteString
bs
                    Builder -> IO ()
sendChunk (Builder -> IO ()) -> Builder -> IO ()
forall a b. (a -> b) -> a -> b
$ ByteString -> Builder
byteString ByteString
x
                    Int -> IO ()
loop (Int -> IO ()) -> Int -> IO ()
forall a b. (a -> b) -> a -> b
$ Int
remaining Int -> Int -> Int
forall a. Num a => a -> a -> a
- ByteString -> Int
B.length ByteString
x
        Int -> IO ()
loop (Int -> IO ()) -> Int -> IO ()
forall a b. (a -> b) -> a -> b
$ Integer -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Integer -> Int) -> Integer -> Int
forall a b. (a -> b) -> a -> b
$ FilePart -> Integer
filePartByteCount FilePart
part
    )
responseToStream (ResponseFile Status
s ResponseHeaders
h FilePath
fp Maybe FilePart
Nothing) =
    ( Status
s
    , ResponseHeaders
h
    , \StreamingBody -> IO a
withBody -> FilePath -> IOMode -> (Handle -> IO a) -> IO a
forall r. FilePath -> IOMode -> (Handle -> IO r) -> IO r
IO.withBinaryFile FilePath
fp IOMode
IO.ReadMode ((Handle -> IO a) -> IO a) -> (Handle -> IO a) -> IO a
forall a b. (a -> b) -> a -> b
$ \Handle
handle ->
       StreamingBody -> IO a
withBody (StreamingBody -> IO a) -> StreamingBody -> IO a
forall a b. (a -> b) -> a -> b
$ \Builder -> IO ()
sendChunk IO ()
_flush -> (IO () -> IO ()) -> IO ()
forall a. (a -> a) -> a
fix ((IO () -> IO ()) -> IO ()) -> (IO () -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \IO ()
loop -> do
            ByteString
bs <- Handle -> Int -> IO ByteString
B.hGetSome Handle
handle Int
defaultChunkSize
            Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
unless (ByteString -> Bool
B.null ByteString
bs) (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ do
                Builder -> IO ()
sendChunk (Builder -> IO ()) -> Builder -> IO ()
forall a b. (a -> b) -> a -> b
$ ByteString -> Builder
byteString ByteString
bs
                IO ()
loop
    )
responseToStream (ResponseBuilder Status
s ResponseHeaders
h Builder
b) =
    (Status
s, ResponseHeaders
h, \StreamingBody -> IO a
withBody -> StreamingBody -> IO a
withBody (StreamingBody -> IO a) -> StreamingBody -> IO a
forall a b. (a -> b) -> a -> b
$ \Builder -> IO ()
sendChunk IO ()
_flush -> Builder -> IO ()
sendChunk Builder
b)
responseToStream (ResponseRaw IO ByteString -> (ByteString -> IO ()) -> IO ()
_ Response
res) = Response
-> (Status, ResponseHeaders, (StreamingBody -> IO a) -> IO a)
forall a.
Response
-> (Status, ResponseHeaders, (StreamingBody -> IO a) -> IO a)
responseToStream Response
res
mapResponseHeaders :: (H.ResponseHeaders -> H.ResponseHeaders) -> Response -> Response
 ResponseHeaders -> ResponseHeaders
f (ResponseFile Status
s ResponseHeaders
h FilePath
b1 Maybe FilePart
b2) = Status -> ResponseHeaders -> FilePath -> Maybe FilePart -> Response
ResponseFile Status
s (ResponseHeaders -> ResponseHeaders
f ResponseHeaders
h) FilePath
b1 Maybe FilePart
b2
mapResponseHeaders ResponseHeaders -> ResponseHeaders
f (ResponseBuilder Status
s ResponseHeaders
h Builder
b) = Status -> ResponseHeaders -> Builder -> Response
ResponseBuilder Status
s (ResponseHeaders -> ResponseHeaders
f ResponseHeaders
h) Builder
b
mapResponseHeaders ResponseHeaders -> ResponseHeaders
f (ResponseStream Status
s ResponseHeaders
h StreamingBody
b) = Status -> ResponseHeaders -> StreamingBody -> Response
ResponseStream Status
s (ResponseHeaders -> ResponseHeaders
f ResponseHeaders
h) StreamingBody
b
mapResponseHeaders ResponseHeaders -> ResponseHeaders
_ r :: Response
r@(ResponseRaw IO ByteString -> (ByteString -> IO ()) -> IO ()
_ Response
_) = Response
r
mapResponseStatus :: (H.Status -> H.Status) -> Response -> Response
mapResponseStatus :: (Status -> Status) -> Response -> Response
mapResponseStatus Status -> Status
f (ResponseFile Status
s ResponseHeaders
h FilePath
b1 Maybe FilePart
b2) = Status -> ResponseHeaders -> FilePath -> Maybe FilePart -> Response
ResponseFile (Status -> Status
f Status
s) ResponseHeaders
h FilePath
b1 Maybe FilePart
b2
mapResponseStatus Status -> Status
f (ResponseBuilder Status
s ResponseHeaders
h Builder
b) = Status -> ResponseHeaders -> Builder -> Response
ResponseBuilder (Status -> Status
f Status
s) ResponseHeaders
h Builder
b
mapResponseStatus Status -> Status
f (ResponseStream Status
s ResponseHeaders
h StreamingBody
b) = Status -> ResponseHeaders -> StreamingBody -> Response
ResponseStream (Status -> Status
f Status
s) ResponseHeaders
h StreamingBody
b
mapResponseStatus Status -> Status
_ r :: Response
r@(ResponseRaw IO ByteString -> (ByteString -> IO ()) -> IO ()
_ Response
_) = Response
r
type Application = Request -> (Response -> IO ResponseReceived) -> IO ResponseReceived
defaultRequest :: Request
defaultRequest :: Request
defaultRequest = Request
    { requestMethod :: ByteString
requestMethod = ByteString
H.methodGet
    , httpVersion :: HttpVersion
httpVersion = HttpVersion
H.http10
    , rawPathInfo :: ByteString
rawPathInfo = ByteString
B.empty
    , rawQueryString :: ByteString
rawQueryString = ByteString
B.empty
    , requestHeaders :: ResponseHeaders
requestHeaders = []
    , isSecure :: Bool
isSecure = Bool
False
    , remoteHost :: SockAddr
remoteHost = PortNumber -> HostAddress -> SockAddr
SockAddrInet PortNumber
0 HostAddress
0
    , pathInfo :: [Text]
pathInfo = []
    , queryString :: Query
queryString = []
    , requestBody :: IO ByteString
requestBody = ByteString -> IO ByteString
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return ByteString
B.empty
    , vault :: Vault
vault = Vault
forall a. Monoid a => a
mempty
    , requestBodyLength :: RequestBodyLength
requestBodyLength = Word64 -> RequestBodyLength
KnownLength Word64
0
    , requestHeaderHost :: Maybe ByteString
requestHeaderHost = Maybe ByteString
forall a. Maybe a
Nothing
    , requestHeaderRange :: Maybe ByteString
requestHeaderRange = Maybe ByteString
forall a. Maybe a
Nothing
    , requestHeaderReferer :: Maybe ByteString
requestHeaderReferer = Maybe ByteString
forall a. Maybe a
Nothing
    , requestHeaderUserAgent :: Maybe ByteString
requestHeaderUserAgent = Maybe ByteString
forall a. Maybe a
Nothing
    }
type Middleware = Application -> Application
modifyRequest :: (Request -> Request) -> Middleware
modifyRequest :: (Request -> Request) -> Middleware
modifyRequest Request -> Request
f Application
app = Application
app Application -> (Request -> Request) -> Application
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Request -> Request
f
modifyResponse :: (Response -> Response) -> Middleware
modifyResponse :: (Response -> Response) -> Middleware
modifyResponse Response -> Response
f Application
app Request
req Response -> IO ResponseReceived
respond = Application
app Request
req ((Response -> IO ResponseReceived) -> IO ResponseReceived)
-> (Response -> IO ResponseReceived) -> IO ResponseReceived
forall a b. (a -> b) -> a -> b
$ Response -> IO ResponseReceived
respond (Response -> IO ResponseReceived)
-> (Response -> Response) -> Response -> IO ResponseReceived
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Response -> Response
f
ifRequest :: (Request -> Bool) -> Middleware -> Middleware
ifRequest :: (Request -> Bool) -> Middleware -> Middleware
ifRequest Request -> Bool
rpred Middleware
middle Application
app Request
req
    | Request -> Bool
rpred Request
req = Middleware
middle Application
app Request
req
    | Bool
otherwise =        Application
app Request
req
strictRequestBody :: Request -> IO L.ByteString
strictRequestBody :: Request -> IO ByteString
strictRequestBody Request
req =
    (ByteString -> ByteString) -> IO ByteString
forall {c}. (ByteString -> c) -> IO c
loop ByteString -> ByteString
forall a. a -> a
id
  where
    loop :: (ByteString -> c) -> IO c
loop ByteString -> c
front = do
        ByteString
bs <- Request -> IO ByteString
getRequestBodyChunk Request
req
        if ByteString -> Bool
B.null ByteString
bs
            then c -> IO c
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (c -> IO c) -> c -> IO c
forall a b. (a -> b) -> a -> b
$ ByteString -> c
front ByteString
LI.Empty
            else (ByteString -> c) -> IO c
loop (ByteString -> c
front (ByteString -> c) -> (ByteString -> ByteString) -> ByteString -> c
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> ByteString -> ByteString
LI.Chunk ByteString
bs)
consumeRequestBodyStrict :: Request -> IO L.ByteString
consumeRequestBodyStrict :: Request -> IO ByteString
consumeRequestBodyStrict = Request -> IO ByteString
strictRequestBody
lazyRequestBody :: Request -> IO L.ByteString
lazyRequestBody :: Request -> IO ByteString
lazyRequestBody Request
req =
    IO ByteString
loop
  where
    loop :: IO ByteString
loop = IO ByteString -> IO ByteString
forall a. IO a -> IO a
unsafeInterleaveIO (IO ByteString -> IO ByteString) -> IO ByteString -> IO ByteString
forall a b. (a -> b) -> a -> b
$ do
        ByteString
bs <- Request -> IO ByteString
getRequestBodyChunk Request
req
        if ByteString -> Bool
B.null ByteString
bs
            then ByteString -> IO ByteString
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return ByteString
LI.Empty
            else do
                ByteString
bss <- IO ByteString
loop
                ByteString -> IO ByteString
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (ByteString -> IO ByteString) -> ByteString -> IO ByteString
forall a b. (a -> b) -> a -> b
$ ByteString -> ByteString -> ByteString
LI.Chunk ByteString
bs ByteString
bss
consumeRequestBodyLazy :: Request -> IO L.ByteString
consumeRequestBodyLazy :: Request -> IO ByteString
consumeRequestBodyLazy = Request -> IO ByteString
lazyRequestBody
mapRequestHeaders :: (H.RequestHeaders -> H.RequestHeaders) -> Request -> Request
 ResponseHeaders -> ResponseHeaders
f Request
request = Request
request { requestHeaders = f (requestHeaders request) }