module Network.Wai
(
Method
, HttpVersion
, http09
, http10
, http11
, CIByteString (..)
, mkCIByteString
, RequestHeader
, RequestHeaders
, ResponseHeader
, ResponseHeaders
, Status (..)
, status200, statusOK
, status201, statusCreated
, status206, statusPartialContent
, status301, statusMovedPermanently
, status302, statusFound
, status303, statusSeeOther
, status400, statusBadRequest
, status401, statusUnauthorized
, status403, statusForbidden
, status404, statusNotFound
, status405, statusNotAllowed
, status500, statusServerError
, Request (..)
, Response (..)
, ResponseEnumerator
, responseEnumerator
, Application
, Middleware
, responseLBS
) where
import qualified Data.ByteString as B
import qualified Data.ByteString.Char8 as B8
import qualified Data.ByteString.Lazy as L
import Data.Char (toLower)
import Data.String (IsString (..))
import Data.Typeable (Typeable)
import Data.Enumerator (Iteratee, ($$), joinI, run_)
import qualified Data.Enumerator as E
import Data.Enumerator.IO (enumFile)
import Blaze.ByteString.Builder (Builder, fromByteString, fromLazyByteString)
import Data.Data (Data)
import Network.Socket (SockAddr)
type Method = B.ByteString
type HttpVersion = B.ByteString
http09 :: HttpVersion
http09 = B8.pack "0.9"
http10 :: HttpVersion
http10 = B8.pack "1.0"
http11 :: HttpVersion
http11 = B8.pack "1.1"
data CIByteString = CIByteString
{ ciOriginal :: !B.ByteString
, ciLowerCase :: !B.ByteString
}
deriving (Data, Typeable)
mkCIByteString :: B.ByteString -> CIByteString
mkCIByteString bs = CIByteString bs $ B8.map toLower bs
instance Show CIByteString where
show = show . ciOriginal
instance Read CIByteString where
readsPrec i = map (\(x, y) -> (mkCIByteString x, y)) . readsPrec i
instance Eq CIByteString where
x == y = ciLowerCase x == ciLowerCase y
instance Ord CIByteString where
x <= y = ciLowerCase x <= ciLowerCase y
instance IsString CIByteString where
fromString = mkCIByteString . fromString
type RequestHeader = CIByteString
type RequestHeaders = [(RequestHeader, B.ByteString)]
type ResponseHeader = CIByteString
type ResponseHeaders = [(ResponseHeader, B.ByteString)]
data Status = Status { statusCode :: Int, statusMessage :: B.ByteString }
deriving Show
instance Eq Status where
x == y = statusCode x == statusCode y
status200, statusOK :: Status
status200 = Status 200 $ B8.pack "OK"
statusOK = status200
status201, statusCreated :: Status
status201 = Status 201 $ B8.pack "Created"
statusCreated = status201
status206, statusPartialContent :: Status
status206 = Status 206 $ B8.pack "Partial Content"
statusPartialContent = status206
status301, statusMovedPermanently :: Status
status301 = Status 301 $ B8.pack "Moved Permanently"
statusMovedPermanently = status301
status302, statusFound :: Status
status302 = Status 302 $ B8.pack "Found"
statusFound = status302
status303, statusSeeOther :: Status
status303 = Status 303 $ B8.pack "See Other"
statusSeeOther = status303
status400, statusBadRequest :: Status
status400 = Status 400 $ B8.pack "Bad Request"
statusBadRequest = status400
status401, statusUnauthorized :: Status
status401 = Status 401 $ B8.pack "Unauthorized"
statusUnauthorized = status401
status403, statusForbidden :: Status
status403 = Status 403 $ B8.pack "Forbidden"
statusForbidden = status403
status404, statusNotFound :: Status
status404 = Status 404 $ B8.pack "Not Found"
statusNotFound = status404
status405, statusNotAllowed :: Status
status405 = Status 405 $ B8.pack "Method Not Allowed"
statusNotAllowed = status405
status500, statusServerError :: Status
status500 = Status 500 $ B8.pack "Internal Server Error"
statusServerError = status500
data Request = Request
{ requestMethod :: Method
, httpVersion :: HttpVersion
, pathInfo :: B.ByteString
, queryString :: B.ByteString
, serverName :: B.ByteString
, serverPort :: Int
, requestHeaders :: [(RequestHeader, B.ByteString)]
, isSecure :: Bool
, errorHandler :: String -> IO ()
, remoteHost :: SockAddr
}
deriving Typeable
data Response
= ResponseFile Status ResponseHeaders FilePath
| ResponseBuilder Status ResponseHeaders Builder
| ResponseEnumerator (forall a. ResponseEnumerator a)
deriving Typeable
type ResponseEnumerator a =
(Status -> ResponseHeaders -> Iteratee Builder IO a) -> IO a
responseEnumerator :: Response -> ResponseEnumerator a
responseEnumerator (ResponseEnumerator e) f = e f
responseEnumerator (ResponseFile s h fp) f =
run_ $ enumFile fp $$ joinI $ E.map fromByteString $$ f s h
responseEnumerator (ResponseBuilder s h b) f = run_ $ do
E.yield () $ E.Chunks [b]
f s h
responseLBS :: Status -> ResponseHeaders -> L.ByteString -> Response
responseLBS s h = ResponseBuilder s h . fromLazyByteString
type Application = Request -> Iteratee B.ByteString IO Response
type Middleware = Application -> Application