{-# OPTIONS_HADDOCK not-home #-}
{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE CPP #-}
{-# LANGUAGE RankNTypes #-}
-- | Internal constructors and helper functions. Note that no guarantees are
-- given for stability of these interfaces.
module Network.Wai.Internal where

import           Blaze.ByteString.Builder     (Builder)
import qualified Data.ByteString              as B
import qualified Data.Conduit                 as C
import           Data.Text                    (Text)
import           Data.Typeable                (Typeable)
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.
data Request = Request {
  -- | Request method such as GET.
     requestMethod        :: H.Method
  -- | HTTP version such as 1.1.
  ,  httpVersion          :: H.HttpVersion
  -- | 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.
  -- Do not modify this raw value- modify pathInfo instead.
  ,  rawPathInfo          :: 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.
  ,  rawQueryString       :: B.ByteString
  -- | A list of header (a pair of key and value) in an HTTP request.
  ,  requestHeaders       :: H.RequestHeaders
  -- | 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.
  ,  isSecure             :: Bool
  -- | The client\'s host information.
  ,  remoteHost           :: SockAddr
  -- | Path info in individual pieces- the url without a hostname/port and
  -- without a query string, split on forward slashes.
  ,  pathInfo             :: [Text]
  -- | Parsed query string information
  ,  queryString          :: H.Query
  -- | A request body provided as 'Source'.
  ,  requestBody          :: C.Source IO B.ByteString
  -- | A location for arbitrary data to be shared by applications and middleware.
  ,  vault                 :: Vault
  -- | The size of the request body. In the case of a chunked request body,
  -- this may be unknown.
  --
  -- Since 1.4.0
  ,  requestBodyLength     :: RequestBodyLength
  -- | The value of the Host header in a HTTP request.
  --
  -- Since 2.0.0
  ,  requestHeaderHost     :: Maybe B.ByteString
  -- | The value of the Range header in a HTTP request.
  --
  -- Since 2.0.0
  ,  requestHeaderRange   :: Maybe B.ByteString
  }
  deriving (Typeable)

-- | The strange structure of the third field or ResponseSource is to allow for
-- exception-safe resource allocation. As an example:
--
-- > app :: Application
-- > app _ = return $ ResponseSource status200 [] $ \f -> bracket
-- >     (putStrLn "Allocation" >> return 5)
-- >     (\i -> putStrLn $ "Cleaning up: " ++ show i)
-- >     (\_ -> f $ do
-- >         yield $ Chunk $ fromByteString "Hello "
-- >         yield $ Chunk $ fromByteString "World!")
data Response
    = ResponseFile H.Status H.ResponseHeaders FilePath (Maybe FilePart)
    | ResponseBuilder H.Status H.ResponseHeaders Builder
    | ResponseSource H.Status H.ResponseHeaders (forall b. WithSource IO (C.Flush Builder) b)
    | ResponseRaw (forall b. WithRawApp b) Response
  deriving Typeable

type RawApp = C.Source IO B.ByteString -> C.Sink B.ByteString IO () -> IO ()
type WithRawApp b = (RawApp -> IO b) -> IO b

-- | Auxiliary type for 'ResponseSource'.
type WithSource m a b = (C.Source m a -> m b) -> m b

-- | 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

-- | Information on which part to be sent.
--   Sophisticated application handles Range (and If-Range) then
--   create 'FilePart'.
data FilePart = FilePart
    { filePartOffset    :: Integer
    , filePartByteCount :: Integer
    , filePartFileSize  :: Integer
    } deriving Show