{-# LANGUAGE RecordWildCards #-}
{-# OPTIONS_HADDOCK not-home #-}

-- | Internal constructors and helper functions. Note that no guarantees are
-- given for stability of these interfaces.
module Network.Wai.Internal where

import qualified Data.ByteString as B
import Data.ByteString.Builder (Builder)
import Data.List (intercalate)
import Data.Text (Text)
import Data.Vault.Lazy (Vault)
import Data.Word (Word64)
import qualified Network.HTTP.Types as H
import Network.Socket (SockAddr)

-- | Information on the request sent by the client. This abstracts away the
-- details of the underlying implementation.
{-# DEPRECATED
    requestBody
    "requestBody's name is misleading because it only gets a partial chunk of the body. Use getRequestBodyChunk instead when getting the field, and setRequestBodyChunks when setting the field."
    #-}

data Request = Request
    { Request -> Method
requestMethod :: H.Method
    -- ^ Request method such as GET.
    , Request -> HttpVersion
httpVersion :: H.HttpVersion
    -- ^ HTTP version such as 1.1.
    , Request -> Method
rawPathInfo :: B.ByteString
    -- ^ Extra path information sent by the client. The meaning varies slightly
    -- depending on backend; in a standalone server setting, this is most likely
    -- all information after the domain name. In a CGI application, this would be
    -- the information following the path to the CGI executable itself.
    --
    -- Middlewares and routing tools should not modify this raw value, as it may
    -- be used for such things as creating redirect destinations by applications.
    -- Instead, if you are writing a middleware or routing framework, modify the
    -- @pathInfo@ instead. This is the approach taken by systems like Yesod
    -- subsites.
    --
    -- /Note/: At the time of writing this documentation, there is at least one
    -- system (@Network.Wai.UrlMap@ from @wai-extra@) that does not follow the
    -- above recommendation. Therefore, it is recommended that you test the
    -- behavior of your application when using @rawPathInfo@ and any form of
    -- library that might modify the @Request@.
    , Request -> Method
rawQueryString :: B.ByteString
    -- ^ If no query string was specified, this should be empty. This value
    -- /will/ include the leading question mark.
    -- Do not modify this raw value - modify queryString instead.
    , Request -> RequestHeaders
requestHeaders :: H.RequestHeaders
    -- ^ A list of headers (a pair of key and value) in an HTTP request.
    , Request -> Bool
isSecure :: Bool
    -- ^ Was this request made over an SSL connection?
    --
    -- Note that this value will /not/ tell you if the client originally made
    -- this request over SSL, but rather whether the current connection is SSL.
    -- The distinction lies with reverse proxies. In many cases, the client will
    -- connect to a load balancer over SSL, but connect to the WAI handler
    -- without SSL. In such a case, 'isSecure' will be 'False', but from a user
    -- perspective, there is a secure connection.
    , Request -> SockAddr
remoteHost :: SockAddr
    -- ^ The client\'s host information.
    , Request -> [Text]
pathInfo :: [Text]
    -- ^ Path info in individual pieces - the URL without a hostname/port and
    -- without a query string, split on forward slashes.
    , Request -> Query
queryString :: H.Query
    -- ^ Parsed query string information.
    , Request -> IO Method
requestBody :: IO B.ByteString
    -- ^ Get the next chunk of the body. Returns 'B.empty' when the
    -- body is fully consumed. Since 3.2.2, this is deprecated in favor of 'getRequestBodyChunk'.
    , Request -> Vault
vault :: Vault
    -- ^ A location for arbitrary data to be shared by applications and middleware.
    , Request -> RequestBodyLength
requestBodyLength :: RequestBodyLength
    -- ^ The size of the request body. In the case of a chunked request body,
    -- this may be unknown.
    --
    -- @since 1.4.0
    , Request -> Maybe Method
requestHeaderHost :: Maybe B.ByteString
    -- ^ The value of the Host header in a HTTP request.
    --
    -- @since 2.0.0
    , Request -> Maybe Method
requestHeaderRange :: Maybe B.ByteString
    -- ^ The value of the Range header in a HTTP request.
    --
    -- @since 2.0.0
    , Request -> Maybe Method
requestHeaderReferer :: Maybe B.ByteString
    -- ^ The value of the Referer header in a HTTP request.
    --
    -- @since 3.2.0
    , Request -> Maybe Method
requestHeaderUserAgent :: Maybe B.ByteString
    -- ^ The value of the User-Agent header in a HTTP request.
    --
    -- @since 3.2.0
    , Request -> RequestHeaders -> IO ()
requestSendEarlyHints :: H.ResponseHeaders -> IO ()
    -- ^ Send a @103 Early Hints@ informational response carrying the given
    -- headers, ahead of the final response. This lets a client (typically over
    -- HTTP\/2) start fetching resources named in @Link@ headers while the final
    -- response is still being produced.
    --
    -- A handler (e.g. Warp over HTTP\/2) that supports early hints installs an
    -- action here; otherwise it is a no-op.
    --
    -- @since 3.2.5
    }

-- | Get the next chunk of the body. Returns 'B.empty' when the
-- body is fully consumed.
--
-- @since 3.2.2
getRequestBodyChunk :: Request -> IO B.ByteString
getRequestBodyChunk :: Request -> IO Method
getRequestBodyChunk = Request -> IO Method
requestBody

-- | Set the 'requestBody' attribute on a request without triggering a
-- deprecation warning.
--
-- The supplied IO action should return the next chunk of the body each time it
-- is called and 'B.empty' when it has been fully consumed.
--
-- @since 3.2.4
setRequestBodyChunks :: IO B.ByteString -> Request -> Request
setRequestBodyChunks :: IO Method -> Request -> Request
setRequestBodyChunks IO Method
requestBody Request
r =
    Request
r{requestBody = requestBody}

instance Show Request where
    show :: Request -> String
show Request{Bool
Query
RequestHeaders
[Text]
Maybe Method
IO Method
Method
HttpVersion
SockAddr
Vault
RequestBodyLength
RequestHeaders -> IO ()
requestMethod :: Request -> Method
httpVersion :: Request -> HttpVersion
rawPathInfo :: Request -> Method
rawQueryString :: Request -> Method
requestHeaders :: Request -> RequestHeaders
isSecure :: Request -> Bool
remoteHost :: Request -> SockAddr
pathInfo :: Request -> [Text]
queryString :: Request -> Query
requestBody :: Request -> IO Method
vault :: Request -> Vault
requestBodyLength :: Request -> RequestBodyLength
requestHeaderHost :: Request -> Maybe Method
requestHeaderRange :: Request -> Maybe Method
requestHeaderReferer :: Request -> Maybe Method
requestHeaderUserAgent :: Request -> Maybe Method
requestSendEarlyHints :: Request -> RequestHeaders -> IO ()
requestMethod :: Method
httpVersion :: HttpVersion
rawPathInfo :: Method
rawQueryString :: Method
requestHeaders :: RequestHeaders
isSecure :: Bool
remoteHost :: SockAddr
pathInfo :: [Text]
queryString :: Query
requestBody :: IO Method
vault :: Vault
requestBodyLength :: RequestBodyLength
requestHeaderHost :: Maybe Method
requestHeaderRange :: Maybe Method
requestHeaderReferer :: Maybe Method
requestHeaderUserAgent :: Maybe Method
requestSendEarlyHints :: RequestHeaders -> IO ()
..} = String
"Request {" String -> ShowS
forall a. [a] -> [a] -> [a]
++ String -> [String] -> String
forall a. [a] -> [[a]] -> [a]
intercalate String
", " [String
a String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
" = " String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
b | (String
a, String
b) <- [(String, String)]
fields] String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
"}"
      where
        fields :: [(String, String)]
fields =
            [ (String
"requestMethod", Method -> String
forall a. Show a => a -> String
show Method
requestMethod)
            , (String
"httpVersion", HttpVersion -> String
forall a. Show a => a -> String
show HttpVersion
httpVersion)
            , (String
"rawPathInfo", Method -> String
forall a. Show a => a -> String
show Method
rawPathInfo)
            , (String
"rawQueryString", Method -> String
forall a. Show a => a -> String
show Method
rawQueryString)
            , (String
"requestHeaders", RequestHeaders -> String
forall a. Show a => a -> String
show RequestHeaders
requestHeaders)
            , (String
"isSecure", Bool -> String
forall a. Show a => a -> String
show Bool
isSecure)
            , (String
"remoteHost", SockAddr -> String
forall a. Show a => a -> String
show SockAddr
remoteHost)
            , (String
"pathInfo", [Text] -> String
forall a. Show a => a -> String
show [Text]
pathInfo)
            , (String
"queryString", Query -> String
forall a. Show a => a -> String
show Query
queryString)
            , (String
"requestBody", String
"<IO ByteString>")
            , (String
"vault", String
"<Vault>")
            , (String
"requestBodyLength", RequestBodyLength -> String
forall a. Show a => a -> String
show RequestBodyLength
requestBodyLength)
            , (String
"requestHeaderHost", Maybe Method -> String
forall a. Show a => a -> String
show Maybe Method
requestHeaderHost)
            , (String
"requestHeaderRange", Maybe Method -> String
forall a. Show a => a -> String
show Maybe Method
requestHeaderRange)
            ]

data Response
    = ResponseFile H.Status H.ResponseHeaders FilePath (Maybe FilePart)
    | ResponseBuilder H.Status H.ResponseHeaders Builder
    | ResponseStream H.Status H.ResponseHeaders StreamingBody
    | ResponseRaw (IO B.ByteString -> (B.ByteString -> IO ()) -> IO ()) Response

-- | Represents a streaming HTTP response body. It's a function of two
-- parameters; the first parameter provides a means of sending another chunk of
-- data, and the second parameter provides a means of flushing the data to the
-- client.
--
-- @since 3.0.0
type StreamingBody = (Builder -> IO ()) -> IO () -> IO ()

-- | The size of the request body. In the case of chunked bodies, the size will
-- not be known.
--
-- @since 1.4.0
data RequestBodyLength = ChunkedBody | KnownLength Word64 deriving (Int -> RequestBodyLength -> ShowS
[RequestBodyLength] -> ShowS
RequestBodyLength -> String
(Int -> RequestBodyLength -> ShowS)
-> (RequestBodyLength -> String)
-> ([RequestBodyLength] -> ShowS)
-> Show RequestBodyLength
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> RequestBodyLength -> ShowS
showsPrec :: Int -> RequestBodyLength -> ShowS
$cshow :: RequestBodyLength -> String
show :: RequestBodyLength -> String
$cshowList :: [RequestBodyLength] -> ShowS
showList :: [RequestBodyLength] -> ShowS
Show)

-- | Information on which part to be sent.
--   Sophisticated application handles Range (and If-Range) then
--   create 'FilePart'.
--
-- @since 0.4.0
data FilePart = FilePart
    { FilePart -> Integer
filePartOffset :: Integer
    , FilePart -> Integer
filePartByteCount :: Integer
    , FilePart -> Integer
filePartFileSize :: Integer
    }
    deriving (Int -> FilePart -> ShowS
[FilePart] -> ShowS
FilePart -> String
(Int -> FilePart -> ShowS)
-> (FilePart -> String) -> ([FilePart] -> ShowS) -> Show FilePart
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> FilePart -> ShowS
showsPrec :: Int -> FilePart -> ShowS
$cshow :: FilePart -> String
show :: FilePart -> String
$cshowList :: [FilePart] -> ShowS
showList :: [FilePart] -> ShowS
Show)

-- | A special datatype to indicate that the WAI handler has received the
-- response. This is to avoid the need for Rank2Types in the definition of
-- Application.
--
-- It is /highly/ advised that only WAI handlers import and use the data
-- constructor for this data type.
--
-- @since 3.0.0
data ResponseReceived = ResponseReceived