{-# LANGUAGE DeriveDataTypeable, RankNTypes, RecordWildCards #-} module Acme.Types where import Control.Exception.Extensible (Exception) import Data.ByteString (ByteString) import qualified Data.ByteString.Char8 as C import Data.ByteString.Internal (c2w) import Data.Data (Data, Typeable) import Text.PrettyPrint.HughesPJ (Doc, ($$), (<+>), ($+$), (<>), char, nest, text, vcat) import Data.Word (Word8) ------------------------------------------------------------------------------ -- HTTPVersion ------------------------------------------------------------------------------ data HTTPVersion = HTTP10 | HTTP11 deriving (Eq, Ord, Read, Show, Data, Typeable) ppHTTPVersion :: HTTPVersion -> Doc ppHTTPVersion HTTP10 = text "HTTP/1.0" ppHTTPVersion HTTP11 = text "HTTP/1.1" ------------------------------------------------------------------------------ -- Method ------------------------------------------------------------------------------ data Method = OPTIONS | GET | GETONLY | HEAD | POST | PUT | DELETE | TRACE | CONNECT | EXTENSION ByteString deriving (Eq, Ord, Read, Show, Data, Typeable) ppMethod :: Method -> Doc ppMethod OPTIONS = text "OPTIONS" ppMethod GET = text "GET" ppMethod GETONLY = text "GETONLY" ppMethod HEAD = text "HEAD" ppMethod POST = text "POST" ppMethod PUT = text "PUT" ppMethod DELETE = text "DELETE" ppMethod TRACE = text "TRACE" ppMethod CONNECT = text "CONNECT" ppMethod (EXTENSION ext) = text (C.unpack ext) ------------------------------------------------------------------------------ -- Request ------------------------------------------------------------------------------ data Request = Request { rqMethod :: !Method , rqURIbs :: !ByteString , rqHTTPVersion :: !HTTPVersion , rqHeaders :: ![(ByteString, ByteString)] , rqSecure :: !Bool , rqBody :: !ByteString } deriving Typeable instance Show Request where show = show . ppRequest ppRequest :: Request -> Doc ppRequest Request{..} = text "Request {" $+$ nest 2 ( vcat [ field " rqMethod" (ppMethod rqMethod) , field ", rqURIbs" (bytestring rqURIbs) , field ", rqHTTPVersion" (ppHTTPVersion rqHTTPVersion) , field ", rqHeaders" (vcat $ map ppHeader rqHeaders) , field ", rqSecure" (text $ show rqSecure) ]) $+$ text "}" ------------------------------------------------------------------------------ -- Response ------------------------------------------------------------------------------ data Response = PongResponse -- ^ return PONG in the request body | ByteStringResponse { rsCode :: !Int , rsHeaders :: ![(ByteString, ByteString)] , rsBody :: !ByteString } ppResponse :: Response -> Doc ppResponse PongResponse = text "PongResponse" ppResponse ByteStringResponse{..} = text "Response {" $+$ nest 2 (vcat [ field "rsCode" (text $ show rsCode) , field "rsHeaders" (text $ show rsCode) , field "rsBody" (text $ show rsBody) ]) $+$ text "}" instance Show Response where show = show . ppResponse ------------------------------------------------------------------------------ -- Exceptions ------------------------------------------------------------------------------ -- | thrown when the remote-side closes the connection data ConnectionClosed = ConnectionClosed deriving (Typeable, Show) instance Exception ConnectionClosed ------------------------------------------------------------------------------ -- pretty-print helpers ------------------------------------------------------------------------------ -- | render a 'ByteString' to 'Doc' bytestring :: ByteString -> Doc bytestring = text . C.unpack -- | render, field = value field :: String -- ^ field name -> Doc -- ^ field value -> Doc field name doc = text name $$ nest 15 (char '=' <+> doc) -- | pretty-print an HTTP header ppHeader :: (ByteString, ByteString) -> Doc ppHeader (fieldName, fieldValue) = bytestring fieldName <> char ':' <> bytestring fieldValue ------------------------------------------------------------------------------ -- 'Word8' constants for popular characters ------------------------------------------------------------------------------ colon, cr, nl, space :: Word8 colon = c2w ':' cr = c2w '\r' nl = c2w '\n' space = c2w ' '