{-# LANGUAGE Rank2Types, ImpredicativeTypes #-}

------------------------------------------------------------------------
-- |
-- Module      :  Network.Wai
-- Copyright   :  (c) Johan Tibell 2008
-- License     :  BSD3-style (see LICENSE)
--
-- Maintainer  :  johan.tibell@gmail.com
-- Stability   :  experimental
-- Portability :  not portable, uses 2-rank types
--
-- Defines the interface implemented by all web applications.
--
-- Example application:
--
-- > module Main where
-- >
-- > import qualified Data.ByteString as S
-- > import qualified Data.ByteString.Char8 as C (pack, unpack)
-- > import Network.Wai (Application(..), Enumerator(..))
-- > import System.Directory (getCurrentDirectory)
-- > import System.FilePath ((</>), makeRelative)
-- > import System.IO
-- >
-- > sendFile :: FilePath -> IO Enumerator
-- > sendFile fname = do
-- >   cwd <- getCurrentDirectory
-- >   h <- openBinaryFile (cwd </> makeRelative "/" fname) ReadMode
-- >   let yieldBlock f z = do
-- >              block <- S.hGetNonBlocking h 1024
-- >              if S.null block then hClose h >> return z
-- >                else do
-- >                  z' <- f z block
-- >                  case z' of
-- >                    Left z''  -> hClose h >> return z''
-- >                    Right z'' -> yieldBlock f z''
-- >   return yieldBlock
-- >
-- > fileServer :: Application
-- > fileServer environ = do
-- >   -- Here you should add security checks, etc.
-- >   let contentType = (C.pack "Content-Type",
-- >                      C.pack "application/octet-stream")
-- >   enumerator <- sendFile $ C.unpack $ pathInfo environ
-- >   return (200, pack "OK", [contentType], enumerator)
--
------------------------------------------------------------------------

module Network.Wai
    ( -- * The Application type
      Application,
      Enumerator,
      Environment(..),
      Headers,
      Method(..)
    ) where

import qualified Data.ByteString as S

-- | The HTTP request headers.
type Headers = [(S.ByteString, S.ByteString)]

-- | The HTTP request method.
data Method = Options | Get | Head | Post | Put | Delete | Trace | Connect
              deriving (Eq, Show)

-- | An environment providing information regarding the request.
data Environment = Environment
    { requestMethod   :: Method
    -- ^ The HTTP request method, such as \"GET\" or \"POST\".
    , scriptName      :: S.ByteString
    -- ^ The initial portion of the request URL's \"path\" that
    -- corresponds to the application, so that the application knows
    -- its virtual \"location\".  This may be an empty string, if the
    -- application corresponds to the \"root\" of the server.
    , pathInfo        :: S.ByteString
    -- ^ The remainder of the request URL's \"path\", designating the
    -- virtual \"location\" of the request's target within the
    -- application.  This may be an empty string, if the request URL
    -- targets the application root and does not have a trailing
    -- slash.
    , queryString     :: Maybe (S.ByteString)
    -- ^ The portion of the request URL that follows the @\"?\"@, if
    -- any.  May be empty or absent.
    , requestProtocol :: (Int, Int)
    -- ^ The version of the protocol the client used to send the
    -- request.  Typically this will be @(1, 0)@ or @(1, 1)@ and may
    -- be used by the application to determine how to treat any HTTP
    -- request headers.
    , headers         :: Headers
    -- ^ The client-supplied HTTP request headers.
    , input           :: Enumerator
    -- ^ An 'Enumerator' from which the HTTP body can be read.
    , errors          :: String -> IO ()
    -- ^ A function with which error output can be written, for the
    -- purpose of recording program or other errors in a standardized
    -- and possibly centralized location.  This function will not add
    -- a trailing newline to the string.
    }

-- | A left-fold enumerator.
type Enumerator = forall a. (a -> S.ByteString -> IO (Either a a)) -> a -> IO a

-- | An application takes an environment and returns a HTTP status
-- code, a sequence of headers and an 'Enumerator' containing the
-- response body.
type Application = Environment -> IO (Int, S.ByteString, Headers, Enumerator)