{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE CPP #-}
{-# LANGUAGE EmptyDataDecls #-}
{-# LANGUAGE ExistentialQuantification #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE ForeignFunctionInterface #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE Rank2Types #-}
{-# LANGUAGE TypeSynonymInstances #-}
module Snap.Internal.Http.Types where
import Control.Monad (unless)
import Data.ByteString (ByteString)
import Data.ByteString.Builder (Builder, byteString, toLazyByteString)
import qualified Data.ByteString.Char8 as S
import qualified Data.ByteString.Lazy.Char8 as L
import Data.CaseInsensitive (CI)
import qualified Data.CaseInsensitive as CI
import qualified Data.IntMap as IM
import Data.List hiding (take)
import Data.Map (Map)
import qualified Data.Map as Map
import Data.Maybe (Maybe (..), fromMaybe, maybe)
import Data.Monoid (mconcat)
import Data.Time.Clock (UTCTime)
import Data.Time.Clock.POSIX (utcTimeToPOSIXSeconds)
import Data.Word (Word64)
import Foreign.C.Types (CTime (..))
import Prelude (Bool (..), Eq (..), FilePath, IO, Int, Integral (..), Monad (..), Num ((-)), Ord (..), Ordering (..), Read (..), Show (..), String, fmap, fromInteger, fromIntegral, id, not, otherwise, truncate, ($), (.))
#ifdef PORTABLE
import Prelude (realToFrac, ($!))
#endif
import System.IO (IOMode (ReadMode), SeekMode (AbsoluteSeek), hSeek, withBinaryFile)
import System.IO.Streams (InputStream, OutputStream)
import qualified System.IO.Streams as Streams
import System.IO.Unsafe (unsafePerformIO)
#ifdef PORTABLE
import Data.Time.Clock.POSIX
import Data.Time.Clock.POSIX
import Data.Time.Format
import Data.Time.Locale.Compat (defaultTimeLocale)
import Data.Time.LocalTime
#else
import qualified Data.ByteString.Unsafe as S
import Data.Time.Format ()
import Foreign.C.String (CString)
import Foreign.Marshal.Alloc (mallocBytes)
#endif
import Snap.Types.Headers (Headers)
import qualified Snap.Types.Headers as H
#ifndef PORTABLE
foreign import ccall unsafe "set_c_locale"
set_c_locale :: IO ()
foreign import ccall unsafe "c_parse_http_time"
c_parse_http_time :: CString -> IO CTime
foreign import ccall unsafe "c_format_http_time"
c_format_http_time :: CTime -> CString -> IO ()
foreign import ccall unsafe "c_format_log_time"
c_format_log_time :: CTime -> CString -> IO ()
#endif
class a where
:: (Headers -> Headers) -> a -> a
:: a -> Headers
addHeader :: (HasHeaders a) => CI ByteString -> ByteString -> a -> a
CI ByteString
k ByteString
v = (Headers -> Headers) -> a -> a
forall a. HasHeaders a => (Headers -> Headers) -> a -> a
updateHeaders ((Headers -> Headers) -> a -> a) -> (Headers -> Headers) -> a -> a
forall a b. (a -> b) -> a -> b
$ CI ByteString -> ByteString -> Headers -> Headers
H.insert CI ByteString
k ByteString
v
setHeader :: (HasHeaders a) => CI ByteString -> ByteString -> a -> a
CI ByteString
k ByteString
v = (Headers -> Headers) -> a -> a
forall a. HasHeaders a => (Headers -> Headers) -> a -> a
updateHeaders ((Headers -> Headers) -> a -> a) -> (Headers -> Headers) -> a -> a
forall a b. (a -> b) -> a -> b
$ CI ByteString -> ByteString -> Headers -> Headers
H.set CI ByteString
k ByteString
v
getHeader :: (HasHeaders a) => CI ByteString -> a -> Maybe ByteString
CI ByteString
k a
a = CI ByteString -> Headers -> Maybe ByteString
H.lookup CI ByteString
k (Headers -> Maybe ByteString) -> Headers -> Maybe ByteString
forall a b. (a -> b) -> a -> b
$ a -> Headers
forall a. HasHeaders a => a -> Headers
headers a
a
listHeaders :: (HasHeaders a) => a -> [(CI ByteString, ByteString)]
= Headers -> [(CI ByteString, ByteString)]
H.toList (Headers -> [(CI ByteString, ByteString)])
-> (a -> Headers) -> a -> [(CI ByteString, ByteString)]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> Headers
forall a. HasHeaders a => a -> Headers
headers
deleteHeader :: (HasHeaders a) => CI ByteString -> a -> a
CI ByteString
k = (Headers -> Headers) -> a -> a
forall a. HasHeaders a => (Headers -> Headers) -> a -> a
updateHeaders ((Headers -> Headers) -> a -> a) -> (Headers -> Headers) -> a -> a
forall a b. (a -> b) -> a -> b
$ CI ByteString -> Headers -> Headers
H.delete CI ByteString
k
data Method = GET | HEAD | POST | PUT | DELETE | TRACE | OPTIONS | CONNECT |
PATCH | Method ByteString
deriving(Int -> Method -> ShowS
[Method] -> ShowS
Method -> String
(Int -> Method -> ShowS)
-> (Method -> String) -> ([Method] -> ShowS) -> Show Method
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Method] -> ShowS
$cshowList :: [Method] -> ShowS
show :: Method -> String
$cshow :: Method -> String
showsPrec :: Int -> Method -> ShowS
$cshowsPrec :: Int -> Method -> ShowS
Show, ReadPrec [Method]
ReadPrec Method
Int -> ReadS Method
ReadS [Method]
(Int -> ReadS Method)
-> ReadS [Method]
-> ReadPrec Method
-> ReadPrec [Method]
-> Read Method
forall a.
(Int -> ReadS a)
-> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
readListPrec :: ReadPrec [Method]
$creadListPrec :: ReadPrec [Method]
readPrec :: ReadPrec Method
$creadPrec :: ReadPrec Method
readList :: ReadS [Method]
$creadList :: ReadS [Method]
readsPrec :: Int -> ReadS Method
$creadsPrec :: Int -> ReadS Method
Read)
instance Eq Method where
Method
a == :: Method -> Method -> Bool
== Method
b =
Method -> Method
normalizeMethod Method
a Method -> Method -> Bool
`eq` Method -> Method
normalizeMethod Method
b
where
Method
GET eq :: Method -> Method -> Bool
`eq` Method
GET = Bool
True
Method
HEAD `eq` Method
HEAD = Bool
True
Method
POST `eq` Method
POST = Bool
True
Method
PUT `eq` Method
PUT = Bool
True
Method
DELETE `eq` Method
DELETE = Bool
True
Method
TRACE `eq` Method
TRACE = Bool
True
Method
OPTIONS `eq` Method
OPTIONS = Bool
True
Method
CONNECT `eq` Method
CONNECT = Bool
True
Method
PATCH `eq` Method
PATCH = Bool
True
Method ByteString
x1 `eq` Method ByteString
y1 = ByteString
x1 ByteString -> ByteString -> Bool
forall a. Eq a => a -> a -> Bool
== ByteString
y1
Method
_ `eq` Method
_ = Bool
False
instance Ord Method where
compare :: Method -> Method -> Ordering
compare Method
a Method
b =
Method -> Method -> Ordering
check (Method -> Method
normalizeMethod Method
a) (Method -> Method
normalizeMethod Method
b)
where
check :: Method -> Method -> Ordering
check Method
GET Method
GET = Ordering
EQ
check Method
HEAD Method
HEAD = Ordering
EQ
check Method
POST Method
POST = Ordering
EQ
check Method
PUT Method
PUT = Ordering
EQ
check Method
DELETE Method
DELETE = Ordering
EQ
check Method
TRACE Method
TRACE = Ordering
EQ
check Method
OPTIONS Method
OPTIONS = Ordering
EQ
check Method
CONNECT Method
CONNECT = Ordering
EQ
check Method
PATCH Method
PATCH = Ordering
EQ
check (Method ByteString
x1) (Method ByteString
y1) = ByteString -> ByteString -> Ordering
forall a. Ord a => a -> a -> Ordering
compare ByteString
x1 ByteString
y1
check Method
x Method
y = Int -> Int -> Ordering
forall a. Ord a => a -> a -> Ordering
compare (Method -> Int
tag Method
x) (Method -> Int
tag Method
y)
tag :: Method -> Int
tag :: Method -> Int
tag (GET{}) = Int
0
tag (HEAD{}) = Int
1
tag (POST{}) = Int
2
tag (PUT{}) = Int
3
tag (DELETE{}) = Int
4
tag (TRACE{}) = Int
5
tag (OPTIONS{}) = Int
6
tag (CONNECT{}) = Int
7
tag (PATCH{}) = Int
8
tag (Method{}) = Int
9
{-# INLINE normalizeMethod #-}
normalizeMethod :: Method -> Method
normalizeMethod :: Method -> Method
normalizeMethod m :: Method
m@(Method ByteString
name) = case ByteString
name of
ByteString
"GET" -> Method
GET
ByteString
"HEAD" -> Method
HEAD
ByteString
"POST" -> Method
POST
ByteString
"PUT" -> Method
PUT
ByteString
"DELETE" -> Method
DELETE
ByteString
"TRACE" -> Method
TRACE
ByteString
"OPTIONS" -> Method
OPTIONS
ByteString
"CONNECT" -> Method
CONNECT
ByteString
"PATCH" -> Method
PATCH
ByteString
_ -> Method
m
normalizeMethod Method
m = Method
m
type HttpVersion = (Int,Int)
data Cookie = Cookie {
Cookie -> ByteString
cookieName :: !ByteString
, Cookie -> ByteString
cookieValue :: !ByteString
, Cookie -> Maybe UTCTime
cookieExpires :: !(Maybe UTCTime)
, Cookie -> Maybe ByteString
cookieDomain :: !(Maybe ByteString)
, Cookie -> Maybe ByteString
cookiePath :: !(Maybe ByteString)
, Cookie -> Bool
cookieSecure :: !Bool
, Cookie -> Bool
cookieHttpOnly :: !Bool
} deriving (Cookie -> Cookie -> Bool
(Cookie -> Cookie -> Bool)
-> (Cookie -> Cookie -> Bool) -> Eq Cookie
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Cookie -> Cookie -> Bool
$c/= :: Cookie -> Cookie -> Bool
== :: Cookie -> Cookie -> Bool
$c== :: Cookie -> Cookie -> Bool
Eq, Int -> Cookie -> ShowS
[Cookie] -> ShowS
Cookie -> String
(Int -> Cookie -> ShowS)
-> (Cookie -> String) -> ([Cookie] -> ShowS) -> Show Cookie
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Cookie] -> ShowS
$cshowList :: [Cookie] -> ShowS
show :: Cookie -> String
$cshow :: Cookie -> String
showsPrec :: Int -> Cookie -> ShowS
$cshowsPrec :: Int -> Cookie -> ShowS
Show)
type Params = Map ByteString [ByteString]
data Request = Request
{
Request -> ByteString
rqHostName :: ByteString
, Request -> ByteString
rqClientAddr :: ByteString
, Request -> Int
rqClientPort :: {-# UNPACK #-} !Int
, Request -> ByteString
rqServerAddr :: ByteString
, Request -> Int
rqServerPort :: {-# UNPACK #-} !Int
, Request -> ByteString
rqLocalHostname :: ByteString
, Request -> Bool
rqIsSecure :: !Bool
, :: Headers
, Request -> InputStream ByteString
rqBody :: InputStream ByteString
, Request -> Maybe Word64
rqContentLength :: !(Maybe Word64)
, Request -> Method
rqMethod :: !Method
, Request -> HttpVersion
rqVersion :: {-# UNPACK #-} !HttpVersion
, Request -> [Cookie]
rqCookies :: [Cookie]
, Request -> ByteString
rqPathInfo :: ByteString
, Request -> ByteString
rqContextPath :: ByteString
, Request -> ByteString
rqURI :: ByteString
, Request -> ByteString
rqQueryString :: ByteString
, Request -> Params
rqParams :: Params
, Request -> Params
rqQueryParams :: Params
, Request -> Params
rqPostParams :: Params
}
instance Show Request where
show :: Request -> String
show Request
r = [String] -> String
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat [ String
method, String
" ", String
uri, String
" HTTP/", String
version, String
"\n"
, String
hdrs, String
"\n\n"
, String
"sn=\"", String
sname, String
"\" c=", String
clntAddr, String
" s=", String
srvAddr
, String
" ctx=", String
contextpath, String
" clen=", String
contentlength, String
secure
, String
params, String
cookies
]
where
method :: String
method = Method -> String
forall a. Show a => a -> String
show (Method -> String) -> Method -> String
forall a b. (a -> b) -> a -> b
$ Request -> Method
rqMethod Request
r
uri :: String
uri = ByteString -> String
S.unpack (ByteString -> String) -> ByteString -> String
forall a b. (a -> b) -> a -> b
$ Request -> ByteString
rqURI Request
r
version :: String
version = let (Int
mj, Int
mn) = Request -> HttpVersion
rqVersion Request
r in Int -> String
forall a. Show a => a -> String
show Int
mj String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
"." String -> ShowS
forall a. [a] -> [a] -> [a]
++ Int -> String
forall a. Show a => a -> String
show Int
mn
hdrs :: String
hdrs = String -> [String] -> String
forall a. [a] -> [[a]] -> [a]
intercalate String
"\n" ([String] -> String) -> [String] -> String
forall a b. (a -> b) -> a -> b
$ ((CI ByteString, ByteString) -> String)
-> [(CI ByteString, ByteString)] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map (CI ByteString, ByteString) -> String
showHdr (Headers -> [(CI ByteString, ByteString)]
H.toList (Headers -> [(CI ByteString, ByteString)])
-> Headers -> [(CI ByteString, ByteString)]
forall a b. (a -> b) -> a -> b
$ Request -> Headers
rqHeaders Request
r)
showHdr :: (CI ByteString, ByteString) -> String
showHdr (CI ByteString
a,ByteString
b) = (ByteString -> String
S.unpack (ByteString -> String) -> ByteString -> String
forall a b. (a -> b) -> a -> b
$ CI ByteString -> ByteString
forall s. CI s -> s
CI.original CI ByteString
a) String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
": " String -> ShowS
forall a. [a] -> [a] -> [a]
++ ByteString -> String
S.unpack ByteString
b
sname :: String
sname = ByteString -> String
S.unpack (ByteString -> String) -> ByteString -> String
forall a b. (a -> b) -> a -> b
$ Request -> ByteString
rqLocalHostname Request
r
clntAddr :: String
clntAddr = [String] -> String
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat [ByteString -> String
S.unpack (ByteString -> String) -> ByteString -> String
forall a b. (a -> b) -> a -> b
$ Request -> ByteString
rqClientAddr Request
r, String
":", Int -> String
forall a. Show a => a -> String
show (Int -> String) -> Int -> String
forall a b. (a -> b) -> a -> b
$ Request -> Int
rqClientPort Request
r]
srvAddr :: String
srvAddr = [String] -> String
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat [ByteString -> String
S.unpack (ByteString -> String) -> ByteString -> String
forall a b. (a -> b) -> a -> b
$ Request -> ByteString
rqServerAddr Request
r, String
":", Int -> String
forall a. Show a => a -> String
show (Int -> String) -> Int -> String
forall a b. (a -> b) -> a -> b
$ Request -> Int
rqServerPort Request
r]
contextpath :: String
contextpath = ByteString -> String
S.unpack (ByteString -> String) -> ByteString -> String
forall a b. (a -> b) -> a -> b
$ Request -> ByteString
rqContextPath Request
r
contentlength :: String
contentlength = String -> (Word64 -> String) -> Maybe Word64 -> String
forall b a. b -> (a -> b) -> Maybe a -> b
maybe String
"n/a" Word64 -> String
forall a. Show a => a -> String
show (Request -> Maybe Word64
rqContentLength Request
r)
secure :: String
secure = if Request -> Bool
rqIsSecure Request
r then String
" secure" else String
""
params :: String
params = String -> String -> [String] -> String
showFlds String
"\nparams: " String
", " ([String] -> String) -> [String] -> String
forall a b. (a -> b) -> a -> b
$
((ByteString, [ByteString]) -> String)
-> [(ByteString, [ByteString])] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map (\ (ByteString
a,[ByteString]
b) -> ByteString -> String
S.unpack ByteString
a String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
": " String -> ShowS
forall a. [a] -> [a] -> [a]
++ [ByteString] -> String
forall a. Show a => a -> String
show [ByteString]
b)
(Params -> [(ByteString, [ByteString])]
forall k a. Map k a -> [(k, a)]
Map.toAscList (Params -> [(ByteString, [ByteString])])
-> Params -> [(ByteString, [ByteString])]
forall a b. (a -> b) -> a -> b
$ Request -> Params
rqParams Request
r)
cookies :: String
cookies = String -> String -> [String] -> String
showFlds String
"\ncookies: " String
"\n " ([String] -> String) -> [String] -> String
forall a b. (a -> b) -> a -> b
$
(Cookie -> String) -> [Cookie] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map Cookie -> String
forall a. Show a => a -> String
show (Request -> [Cookie]
rqCookies Request
r)
showFlds :: String -> String -> [String] -> String
showFlds String
header String
delim [String]
lst
= if Bool -> Bool
not (Bool -> Bool) -> ([String] -> Bool) -> [String] -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [String] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null ([String] -> Bool) -> [String] -> Bool
forall a b. (a -> b) -> a -> b
$ [String]
lst then String
header String -> ShowS
forall a. [a] -> [a] -> [a]
++ (String -> [String] -> String
forall a. [a] -> [[a]] -> [a]
intercalate String
delim [String]
lst)
else String
"" :: String
instance HasHeaders Request where
headers :: Request -> Headers
headers = Request -> Headers
rqHeaders
updateHeaders :: (Headers -> Headers) -> Request -> Request
updateHeaders Headers -> Headers
f Request
r = Request
r { rqHeaders :: Headers
rqHeaders = Headers -> Headers
f (Request -> Headers
rqHeaders Request
r) }
instance HasHeaders Headers where
headers :: Headers -> Headers
headers = Headers -> Headers
forall a. a -> a
id
updateHeaders :: (Headers -> Headers) -> Headers -> Headers
updateHeaders = (Headers -> Headers) -> Headers -> Headers
forall a. a -> a
id
type StreamProc = OutputStream Builder -> IO (OutputStream Builder)
data ResponseBody = Stream (StreamProc)
| SendFile FilePath (Maybe (Word64, Word64))
rspBodyMap :: (StreamProc -> StreamProc) -> ResponseBody -> ResponseBody
rspBodyMap :: (StreamProc -> StreamProc) -> ResponseBody -> ResponseBody
rspBodyMap StreamProc -> StreamProc
f ResponseBody
b = StreamProc -> ResponseBody
Stream (StreamProc -> ResponseBody) -> StreamProc -> ResponseBody
forall a b. (a -> b) -> a -> b
$ StreamProc -> StreamProc
f (StreamProc -> StreamProc) -> StreamProc -> StreamProc
forall a b. (a -> b) -> a -> b
$ ResponseBody -> StreamProc
rspBodyToEnum ResponseBody
b
rspBodyToEnum :: ResponseBody -> StreamProc
rspBodyToEnum :: ResponseBody -> StreamProc
rspBodyToEnum (Stream StreamProc
e) = StreamProc
e
rspBodyToEnum (SendFile String
fp Maybe (Word64, Word64)
Nothing) = \OutputStream Builder
out ->
String
-> (InputStream ByteString -> IO (OutputStream Builder))
-> IO (OutputStream Builder)
forall a. String -> (InputStream ByteString -> IO a) -> IO a
Streams.withFileAsInput String
fp ((InputStream ByteString -> IO (OutputStream Builder))
-> IO (OutputStream Builder))
-> (InputStream ByteString -> IO (OutputStream Builder))
-> IO (OutputStream Builder)
forall a b. (a -> b) -> a -> b
$ \InputStream ByteString
is -> do
InputStream Builder
is' <- (ByteString -> IO Builder)
-> InputStream ByteString -> IO (InputStream Builder)
forall a b. (a -> IO b) -> InputStream a -> IO (InputStream b)
Streams.mapM (Builder -> IO Builder
forall (m :: * -> *) a. Monad m => a -> m a
return (Builder -> IO Builder)
-> (ByteString -> Builder) -> ByteString -> IO Builder
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> Builder
byteString) InputStream ByteString
is
InputStream Builder -> OutputStream Builder -> IO ()
forall a. InputStream a -> OutputStream a -> IO ()
Streams.connect InputStream Builder
is' OutputStream Builder
out
StreamProc
forall (m :: * -> *) a. Monad m => a -> m a
return OutputStream Builder
out
rspBodyToEnum (SendFile String
fp (Just (Word64
start, Word64
end))) = \OutputStream Builder
out ->
String
-> IOMode
-> (Handle -> IO (OutputStream Builder))
-> IO (OutputStream Builder)
forall r. String -> IOMode -> (Handle -> IO r) -> IO r
withBinaryFile String
fp IOMode
ReadMode ((Handle -> IO (OutputStream Builder))
-> IO (OutputStream Builder))
-> (Handle -> IO (OutputStream Builder))
-> IO (OutputStream Builder)
forall a b. (a -> b) -> a -> b
$ \Handle
handle -> do
Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
unless (Word64
start Word64 -> Word64 -> Bool
forall a. Eq a => a -> a -> Bool
== Word64
0) (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ Handle -> SeekMode -> Integer -> IO ()
hSeek Handle
handle SeekMode
AbsoluteSeek (Integer -> IO ()) -> Integer -> IO ()
forall a b. (a -> b) -> a -> b
$ Word64 -> Integer
forall a. Integral a => a -> Integer
toInteger Word64
start
InputStream ByteString
is <- Handle -> IO (InputStream ByteString)
Streams.handleToInputStream Handle
handle
InputStream Builder
is' <- Int64 -> InputStream ByteString -> IO (InputStream ByteString)
Streams.takeBytes (Word64 -> Int64
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word64 -> Int64) -> Word64 -> Int64
forall a b. (a -> b) -> a -> b
$ Word64
end Word64 -> Word64 -> Word64
forall a. Num a => a -> a -> a
- Word64
start) InputStream ByteString
is IO (InputStream ByteString)
-> (InputStream ByteString -> IO (InputStream Builder))
-> IO (InputStream Builder)
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>=
(ByteString -> IO Builder)
-> InputStream ByteString -> IO (InputStream Builder)
forall a b. (a -> IO b) -> InputStream a -> IO (InputStream b)
Streams.mapM (Builder -> IO Builder
forall (m :: * -> *) a. Monad m => a -> m a
return (Builder -> IO Builder)
-> (ByteString -> Builder) -> ByteString -> IO Builder
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> Builder
byteString)
InputStream Builder -> OutputStream Builder -> IO ()
forall a. InputStream a -> OutputStream a -> IO ()
Streams.connect InputStream Builder
is' OutputStream Builder
out
StreamProc
forall (m :: * -> *) a. Monad m => a -> m a
return OutputStream Builder
out
data Response = Response
{ :: Headers
, Response -> Map ByteString Cookie
rspCookies :: Map ByteString Cookie
, Response -> Maybe Word64
rspContentLength :: !(Maybe Word64)
, Response -> ResponseBody
rspBody :: ResponseBody
, Response -> Int
rspStatus :: !Int
, Response -> ByteString
rspStatusReason :: !ByteString
, Response -> Bool
rspTransformingRqBody :: !Bool
}
instance Show Response where
show :: Response -> String
show Response
r = [String] -> String
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat [ String
statusline
, String
hdrs
, String
contentLength
, String
"\r\n"
, String
body
]
where
statusline :: String
statusline = [String] -> String
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat [ String
"HTTP/1.1 "
, Int -> String
forall a. Show a => a -> String
show (Int -> String) -> Int -> String
forall a b. (a -> b) -> a -> b
$ Response -> Int
rspStatus Response
r
, String
" "
, ByteString -> String
S.unpack (ByteString -> String) -> ByteString -> String
forall a b. (a -> b) -> a -> b
$ Response -> ByteString
rspStatusReason Response
r
, String
"\r\n" ]
hdrs :: String
hdrs = ((CI ByteString, ByteString) -> String)
-> [(CI ByteString, ByteString)] -> String
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap (CI ByteString, ByteString) -> String
showHdr ([(CI ByteString, ByteString)] -> String)
-> [(CI ByteString, ByteString)] -> String
forall a b. (a -> b) -> a -> b
$ Headers -> [(CI ByteString, ByteString)]
H.toList (Headers -> [(CI ByteString, ByteString)])
-> Headers -> [(CI ByteString, ByteString)]
forall a b. (a -> b) -> a -> b
$ Response -> Headers -> Headers
renderCookies Response
r
(Headers -> Headers) -> Headers -> Headers
forall a b. (a -> b) -> a -> b
$ Response -> Headers
rspHeaders (Response -> Headers) -> Response -> Headers
forall a b. (a -> b) -> a -> b
$ Response -> Response
clearContentLength Response
r
contentLength :: String
contentLength = String -> (Word64 -> String) -> Maybe Word64 -> String
forall b a. b -> (a -> b) -> Maybe a -> b
maybe String
"" (\Word64
l -> [String] -> String
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat [String
"Content-Length: ", Word64 -> String
forall a. Show a => a -> String
show Word64
l, String
"\r\n"] ) (Response -> Maybe Word64
rspContentLength Response
r)
showHdr :: (CI ByteString, ByteString) -> String
showHdr (CI ByteString
k,ByteString
v) = [String] -> String
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat [ ByteString -> String
S.unpack (CI ByteString -> ByteString
forall s. CI s -> s
CI.original CI ByteString
k), String
": ", ByteString -> String
S.unpack ByteString
v, String
"\r\n" ]
body :: String
body = IO String -> String
forall a. IO a -> a
unsafePerformIO (IO String -> String) -> IO String -> String
forall a b. (a -> b) -> a -> b
$ do
(OutputStream Builder
os, IO [Builder]
grab) <- IO (OutputStream Builder, IO [Builder])
forall c. IO (OutputStream c, IO [c])
Streams.listOutputStream
let f :: StreamProc
f = ResponseBody -> StreamProc
rspBodyToEnum (ResponseBody -> StreamProc) -> ResponseBody -> StreamProc
forall a b. (a -> b) -> a -> b
$ Response -> ResponseBody
rspBody Response
r
OutputStream Builder
_ <- StreamProc
f OutputStream Builder
os
([Builder] -> String) -> IO [Builder] -> IO String
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (ByteString -> String
L.unpack (ByteString -> String)
-> ([Builder] -> ByteString) -> [Builder] -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Builder -> ByteString
toLazyByteString (Builder -> ByteString)
-> ([Builder] -> Builder) -> [Builder] -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Builder] -> Builder
forall a. Monoid a => [a] -> a
mconcat) IO [Builder]
grab
instance HasHeaders Response where
headers :: Response -> Headers
headers = Response -> Headers
rspHeaders
updateHeaders :: (Headers -> Headers) -> Response -> Response
updateHeaders Headers -> Headers
f Response
r = Response
r { rspHeaders :: Headers
rspHeaders = Headers -> Headers
f (Response -> Headers
rspHeaders Response
r) }
rqParam :: ByteString
-> Request
-> Maybe [ByteString]
rqParam :: ByteString -> Request -> Maybe [ByteString]
rqParam ByteString
k Request
rq = ByteString -> Params -> Maybe [ByteString]
forall k a. Ord k => k -> Map k a -> Maybe a
Map.lookup ByteString
k (Params -> Maybe [ByteString]) -> Params -> Maybe [ByteString]
forall a b. (a -> b) -> a -> b
$ Request -> Params
rqParams Request
rq
{-# INLINE rqParam #-}
rqPostParam :: ByteString
-> Request
-> Maybe [ByteString]
rqPostParam :: ByteString -> Request -> Maybe [ByteString]
rqPostParam ByteString
k Request
rq = ByteString -> Params -> Maybe [ByteString]
forall k a. Ord k => k -> Map k a -> Maybe a
Map.lookup ByteString
k (Params -> Maybe [ByteString]) -> Params -> Maybe [ByteString]
forall a b. (a -> b) -> a -> b
$ Request -> Params
rqPostParams Request
rq
{-# INLINE rqPostParam #-}
rqQueryParam :: ByteString
-> Request
-> Maybe [ByteString]
rqQueryParam :: ByteString -> Request -> Maybe [ByteString]
rqQueryParam ByteString
k Request
rq = ByteString -> Params -> Maybe [ByteString]
forall k a. Ord k => k -> Map k a -> Maybe a
Map.lookup ByteString
k (Params -> Maybe [ByteString]) -> Params -> Maybe [ByteString]
forall a b. (a -> b) -> a -> b
$ Request -> Params
rqQueryParams Request
rq
{-# INLINE rqQueryParam #-}
rqModifyParams :: (Params -> Params) -> Request -> Request
rqModifyParams :: (Params -> Params) -> Request -> Request
rqModifyParams Params -> Params
f Request
r = Request
r { rqParams :: Params
rqParams = Params
p }
where
p :: Params
p = Params -> Params
f (Params -> Params) -> Params -> Params
forall a b. (a -> b) -> a -> b
$ Request -> Params
rqParams Request
r
{-# INLINE rqModifyParams #-}
rqSetParam :: ByteString
-> [ByteString]
-> Request
-> Request
rqSetParam :: ByteString -> [ByteString] -> Request -> Request
rqSetParam ByteString
k [ByteString]
v = (Params -> Params) -> Request -> Request
rqModifyParams ((Params -> Params) -> Request -> Request)
-> (Params -> Params) -> Request -> Request
forall a b. (a -> b) -> a -> b
$ ByteString -> [ByteString] -> Params -> Params
forall k a. Ord k => k -> a -> Map k a -> Map k a
Map.insert ByteString
k [ByteString]
v
{-# INLINE rqSetParam #-}
emptyResponse :: Response
emptyResponse :: Response
emptyResponse = Headers
-> Map ByteString Cookie
-> Maybe Word64
-> ResponseBody
-> Int
-> ByteString
-> Bool
-> Response
Response Headers
H.empty Map ByteString Cookie
forall k a. Map k a
Map.empty Maybe Word64
forall a. Maybe a
Nothing
(StreamProc -> ResponseBody
Stream (StreamProc
forall (m :: * -> *) a. Monad m => a -> m a
return StreamProc
-> (OutputStream Builder -> OutputStream Builder) -> StreamProc
forall b c a. (b -> c) -> (a -> b) -> a -> c
. OutputStream Builder -> OutputStream Builder
forall a. a -> a
id))
Int
200 ByteString
"OK" Bool
False
setResponseBody :: (OutputStream Builder -> IO (OutputStream Builder))
-> Response
-> Response
setResponseBody :: StreamProc -> Response -> Response
setResponseBody StreamProc
e Response
r = Response
r { rspBody :: ResponseBody
rspBody = StreamProc -> ResponseBody
Stream StreamProc
e }
{-# INLINE setResponseBody #-}
setResponseStatus :: Int
-> ByteString
-> Response
-> Response
setResponseStatus :: Int -> ByteString -> Response -> Response
setResponseStatus Int
s ByteString
reason Response
r = Response
r { rspStatus :: Int
rspStatus=Int
s, rspStatusReason :: ByteString
rspStatusReason=ByteString
reason }
{-# INLINE setResponseStatus #-}
setResponseCode :: Int
-> Response
-> Response
setResponseCode :: Int -> Response -> Response
setResponseCode Int
s Response
r = Int -> ByteString -> Response -> Response
setResponseStatus Int
s ByteString
reason Response
r
where
reason :: ByteString
reason = ByteString -> Maybe ByteString -> ByteString
forall a. a -> Maybe a -> a
fromMaybe ByteString
"Unknown" (Int -> IntMap ByteString -> Maybe ByteString
forall a. Int -> IntMap a -> Maybe a
IM.lookup Int
s IntMap ByteString
statusReasonMap)
{-# INLINE setResponseCode #-}
modifyResponseBody :: ((OutputStream Builder -> IO (OutputStream Builder)) ->
(OutputStream Builder -> IO (OutputStream Builder)))
-> Response
-> Response
modifyResponseBody :: (StreamProc -> StreamProc) -> Response -> Response
modifyResponseBody StreamProc -> StreamProc
f Response
r = Response
r { rspBody :: ResponseBody
rspBody = (StreamProc -> StreamProc) -> ResponseBody -> ResponseBody
rspBodyMap StreamProc -> StreamProc
f (Response -> ResponseBody
rspBody Response
r) }
{-# INLINE modifyResponseBody #-}
setContentType :: ByteString -> Response -> Response
setContentType :: ByteString -> Response -> Response
setContentType = CI ByteString -> ByteString -> Response -> Response
forall a. HasHeaders a => CI ByteString -> ByteString -> a -> a
setHeader CI ByteString
"Content-Type"
{-# INLINE setContentType #-}
cookieToBS :: Cookie -> ByteString
cookieToBS :: Cookie -> ByteString
cookieToBS (Cookie ByteString
k ByteString
v Maybe UTCTime
mbExpTime Maybe ByteString
mbDomain Maybe ByteString
mbPath Bool
isSec Bool
isHOnly) = ByteString
cookie
where
cookie :: ByteString
cookie = [ByteString] -> ByteString
S.concat [ByteString
k, ByteString
"=", ByteString
v, ByteString
path, ByteString
exptime, ByteString
domain, ByteString
secure, ByteString
hOnly]
path :: ByteString
path = ByteString
-> (ByteString -> ByteString) -> Maybe ByteString -> ByteString
forall b a. b -> (a -> b) -> Maybe a -> b
maybe ByteString
"" (ByteString -> ByteString -> ByteString
S.append ByteString
"; path=") Maybe ByteString
mbPath
domain :: ByteString
domain = ByteString
-> (ByteString -> ByteString) -> Maybe ByteString -> ByteString
forall b a. b -> (a -> b) -> Maybe a -> b
maybe ByteString
"" (ByteString -> ByteString -> ByteString
S.append ByteString
"; domain=") Maybe ByteString
mbDomain
exptime :: ByteString
exptime = ByteString
-> (UTCTime -> ByteString) -> Maybe UTCTime -> ByteString
forall b a. b -> (a -> b) -> Maybe a -> b
maybe ByteString
"" (ByteString -> ByteString -> ByteString
S.append ByteString
"; expires=" (ByteString -> ByteString)
-> (UTCTime -> ByteString) -> UTCTime -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. UTCTime -> ByteString
fmt) Maybe UTCTime
mbExpTime
secure :: ByteString
secure = if Bool
isSec then ByteString
"; Secure" else ByteString
""
hOnly :: ByteString
hOnly = if Bool
isHOnly then ByteString
"; HttpOnly" else ByteString
""
fmt :: UTCTime -> ByteString
fmt = IO ByteString -> ByteString
forall a. IO a -> a
unsafePerformIO (IO ByteString -> ByteString)
-> (UTCTime -> IO ByteString) -> UTCTime -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. CTime -> IO ByteString
formatHttpTime (CTime -> IO ByteString)
-> (UTCTime -> CTime) -> UTCTime -> IO ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. UTCTime -> CTime
toCTime
toCTime :: UTCTime -> CTime
toCTime :: UTCTime -> CTime
toCTime = Integer -> CTime
forall a. Num a => Integer -> a
fromInteger (Integer -> CTime) -> (UTCTime -> Integer) -> UTCTime -> CTime
forall b c a. (b -> c) -> (a -> b) -> a -> c
. POSIXTime -> Integer
forall a b. (RealFrac a, Integral b) => a -> b
truncate (POSIXTime -> Integer)
-> (UTCTime -> POSIXTime) -> UTCTime -> Integer
forall b c a. (b -> c) -> (a -> b) -> a -> c
. UTCTime -> POSIXTime
utcTimeToPOSIXSeconds
renderCookies :: Response -> Headers -> Headers
renderCookies :: Response -> Headers -> Headers
renderCookies Response
r Headers
hdrs
| [ByteString] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [ByteString]
cookies = Headers
hdrs
| Bool
otherwise = (Headers -> ByteString -> Headers)
-> Headers -> [ByteString] -> Headers
forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
foldl' (\Headers
m ByteString
v -> ByteString -> ByteString -> Headers -> Headers
H.unsafeInsert ByteString
"set-cookie" ByteString
v Headers
m) Headers
hdrs [ByteString]
cookies
where
cookies :: [ByteString]
cookies = (Cookie -> ByteString) -> [Cookie] -> [ByteString]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Cookie -> ByteString
cookieToBS ([Cookie] -> [ByteString])
-> (Map ByteString Cookie -> [Cookie])
-> Map ByteString Cookie
-> [ByteString]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Map ByteString Cookie -> [Cookie]
forall k a. Map k a -> [a]
Map.elems (Map ByteString Cookie -> [ByteString])
-> Map ByteString Cookie -> [ByteString]
forall a b. (a -> b) -> a -> b
$ Response -> Map ByteString Cookie
rspCookies Response
r
addResponseCookie :: Cookie
-> Response
-> Response
addResponseCookie :: Cookie -> Response -> Response
addResponseCookie ck :: Cookie
ck@(Cookie ByteString
k ByteString
_ Maybe UTCTime
_ Maybe ByteString
_ Maybe ByteString
_ Bool
_ Bool
_) Response
r = Response
r { rspCookies :: Map ByteString Cookie
rspCookies = Map ByteString Cookie
cks' }
where
cks' :: Map ByteString Cookie
cks'= ByteString
-> Cookie -> Map ByteString Cookie -> Map ByteString Cookie
forall k a. Ord k => k -> a -> Map k a -> Map k a
Map.insert ByteString
k Cookie
ck (Map ByteString Cookie -> Map ByteString Cookie)
-> Map ByteString Cookie -> Map ByteString Cookie
forall a b. (a -> b) -> a -> b
$ Response -> Map ByteString Cookie
rspCookies Response
r
{-# INLINE addResponseCookie #-}
getResponseCookie :: ByteString
-> Response
-> Maybe Cookie
getResponseCookie :: ByteString -> Response -> Maybe Cookie
getResponseCookie ByteString
cn Response
r = ByteString -> Map ByteString Cookie -> Maybe Cookie
forall k a. Ord k => k -> Map k a -> Maybe a
Map.lookup ByteString
cn (Map ByteString Cookie -> Maybe Cookie)
-> Map ByteString Cookie -> Maybe Cookie
forall a b. (a -> b) -> a -> b
$ Response -> Map ByteString Cookie
rspCookies Response
r
{-# INLINE getResponseCookie #-}
getResponseCookies :: Response
-> [Cookie]
getResponseCookies :: Response -> [Cookie]
getResponseCookies = Map ByteString Cookie -> [Cookie]
forall k a. Map k a -> [a]
Map.elems (Map ByteString Cookie -> [Cookie])
-> (Response -> Map ByteString Cookie) -> Response -> [Cookie]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Response -> Map ByteString Cookie
rspCookies
{-# INLINE getResponseCookies #-}
deleteResponseCookie :: ByteString
-> Response
-> Response
deleteResponseCookie :: ByteString -> Response -> Response
deleteResponseCookie ByteString
cn Response
r = Response
r { rspCookies :: Map ByteString Cookie
rspCookies = Map ByteString Cookie
cks' }
where
cks' :: Map ByteString Cookie
cks'= ByteString -> Map ByteString Cookie -> Map ByteString Cookie
forall k a. Ord k => k -> Map k a -> Map k a
Map.delete ByteString
cn (Map ByteString Cookie -> Map ByteString Cookie)
-> Map ByteString Cookie -> Map ByteString Cookie
forall a b. (a -> b) -> a -> b
$ Response -> Map ByteString Cookie
rspCookies Response
r
{-# INLINE deleteResponseCookie #-}
modifyResponseCookie :: ByteString
-> (Cookie -> Cookie)
-> Response
-> Response
modifyResponseCookie :: ByteString -> (Cookie -> Cookie) -> Response -> Response
modifyResponseCookie ByteString
cn Cookie -> Cookie
f Response
r = Response -> (Cookie -> Response) -> Maybe Cookie -> Response
forall b a. b -> (a -> b) -> Maybe a -> b
maybe Response
r Cookie -> Response
modify (Maybe Cookie -> Response) -> Maybe Cookie -> Response
forall a b. (a -> b) -> a -> b
$ ByteString -> Response -> Maybe Cookie
getResponseCookie ByteString
cn Response
r
where
modify :: Cookie -> Response
modify Cookie
ck = Cookie -> Response -> Response
addResponseCookie (Cookie -> Cookie
f Cookie
ck) Response
r
{-# INLINE modifyResponseCookie #-}
setContentLength :: Word64 -> Response -> Response
setContentLength :: Word64 -> Response -> Response
setContentLength !Word64
l Response
r = Response
r { rspContentLength :: Maybe Word64
rspContentLength = Word64 -> Maybe Word64
forall a. a -> Maybe a
Just Word64
l }
{-# INLINE setContentLength #-}
clearContentLength :: Response -> Response
clearContentLength :: Response -> Response
clearContentLength Response
r = Response
r { rspContentLength :: Maybe Word64
rspContentLength = Maybe Word64
forall a. Maybe a
Nothing }
{-# INLINE clearContentLength #-}
formatHttpTime :: CTime -> IO ByteString
formatLogTime :: CTime -> IO ByteString
parseHttpTime :: ByteString -> IO CTime
#ifdef PORTABLE
fromStr :: String -> ByteString
fromStr = S.pack
{-# INLINE fromStr #-}
formatHttpTime = return . format . toUTCTime
where
format :: UTCTime -> ByteString
format = fromStr . formatTime defaultTimeLocale "%a, %d %b %Y %X GMT"
toUTCTime :: CTime -> UTCTime
toUTCTime = posixSecondsToUTCTime . realToFrac
formatLogTime ctime = do
t <- utcToLocalZonedTime $ toUTCTime ctime
return $! format t
where
format :: ZonedTime -> ByteString
format = fromStr . formatTime defaultTimeLocale "%d/%b/%Y:%H:%M:%S %z"
toUTCTime :: CTime -> UTCTime
toUTCTime = posixSecondsToUTCTime . realToFrac
parseHttpTime = return . toCTime . prs . S.unpack
where
prs :: String -> Maybe UTCTime
prs = parseTime defaultTimeLocale "%a, %d %b %Y %H:%M:%S GMT"
toCTime :: Maybe UTCTime -> CTime
toCTime (Just t) = fromInteger $ truncate $ utcTimeToPOSIXSeconds t
toCTime Nothing = fromInteger 0
#else
formatLogTime :: CTime -> IO ByteString
formatLogTime CTime
t = do
Ptr CChar
ptr <- Int -> IO (Ptr CChar)
forall a. Int -> IO (Ptr a)
mallocBytes Int
40
CTime -> Ptr CChar -> IO ()
c_format_log_time CTime
t Ptr CChar
ptr
Ptr CChar -> IO ByteString
S.unsafePackMallocCString Ptr CChar
ptr
formatHttpTime :: CTime -> IO ByteString
formatHttpTime CTime
t = do
Ptr CChar
ptr <- Int -> IO (Ptr CChar)
forall a. Int -> IO (Ptr a)
mallocBytes Int
40
CTime -> Ptr CChar -> IO ()
c_format_http_time CTime
t Ptr CChar
ptr
Ptr CChar -> IO ByteString
S.unsafePackMallocCString Ptr CChar
ptr
parseHttpTime :: ByteString -> IO CTime
parseHttpTime ByteString
s = ByteString -> (Ptr CChar -> IO CTime) -> IO CTime
forall a. ByteString -> (Ptr CChar -> IO a) -> IO a
S.unsafeUseAsCString ByteString
s ((Ptr CChar -> IO CTime) -> IO CTime)
-> (Ptr CChar -> IO CTime) -> IO CTime
forall a b. (a -> b) -> a -> b
$ \Ptr CChar
ptr ->
Ptr CChar -> IO CTime
c_parse_http_time Ptr CChar
ptr
#endif
statusReasonMap :: IM.IntMap ByteString
statusReasonMap :: IntMap ByteString
statusReasonMap = [(Int, ByteString)] -> IntMap ByteString
forall a. [(Int, a)] -> IntMap a
IM.fromList [
(Int
100, ByteString
"Continue"),
(Int
101, ByteString
"Switching Protocols"),
(Int
102, ByteString
"Processing"),
(Int
103, ByteString
"Early Hints"),
(Int
200, ByteString
"OK"),
(Int
201, ByteString
"Created"),
(Int
202, ByteString
"Accepted"),
(Int
203, ByteString
"Non-Authoritative Information"),
(Int
204, ByteString
"No Content"),
(Int
205, ByteString
"Reset Content"),
(Int
206, ByteString
"Partial Content"),
(Int
207, ByteString
"Multi-Status"),
(Int
208, ByteString
"Already Reported"),
(Int
226, ByteString
"IM Used"),
(Int
300, ByteString
"Multiple Choices"),
(Int
301, ByteString
"Moved Permanently"),
(Int
302, ByteString
"Found"),
(Int
303, ByteString
"See Other"),
(Int
304, ByteString
"Not Modified"),
(Int
305, ByteString
"Use Proxy"),
(Int
306, ByteString
"(Unused)"),
(Int
307, ByteString
"Temporary Redirect"),
(Int
308, ByteString
"Permanent Redirect"),
(Int
400, ByteString
"Bad Request"),
(Int
401, ByteString
"Unauthorized"),
(Int
402, ByteString
"Payment Required"),
(Int
403, ByteString
"Forbidden"),
(Int
404, ByteString
"Not Found"),
(Int
405, ByteString
"Method Not Allowed"),
(Int
406, ByteString
"Not Acceptable"),
(Int
407, ByteString
"Proxy Authentication Required"),
(Int
408, ByteString
"Request Timeout"),
(Int
409, ByteString
"Conflict"),
(Int
410, ByteString
"Gone"),
(Int
411, ByteString
"Length Required"),
(Int
412, ByteString
"Precondition Failed"),
(Int
413, ByteString
"Payload Too Large"),
(Int
414, ByteString
"URI Too Long"),
(Int
415, ByteString
"Unsupported Media Type"),
(Int
416, ByteString
"Range Not Satisfiable"),
(Int
417, ByteString
"Expectation Failed"),
(Int
421, ByteString
"Misdirected Request"),
(Int
422, ByteString
"Unprocessable Entity"),
(Int
423, ByteString
"Locked"),
(Int
424, ByteString
"Failed Dependency"),
(Int
425, ByteString
"Too Early"),
(Int
426, ByteString
"Upgrade Required"),
(Int
428, ByteString
"Precondition Required"),
(Int
429, ByteString
"Too Many Requests"),
(Int
431, ByteString
"Request Header Fields Too Large"),
(Int
451, ByteString
"Unavailable For Legal Reasons"),
(Int
500, ByteString
"Internal Server Error"),
(Int
501, ByteString
"Not Implemented"),
(Int
502, ByteString
"Bad Gateway"),
(Int
503, ByteString
"Service Unavailable"),
(Int
504, ByteString
"Gateway Timeout"),
(Int
505, ByteString
"HTTP Version Not Supported"),
(Int
506, ByteString
"Variant Also Negotiates"),
(Int
507, ByteString
"Insufficient Storage"),
(Int
508, ByteString
"Loop Detected"),
(Int
510, ByteString
"Not Extended"),
(Int
511, ByteString
"Network Authentication Required")
]
rqRemoteAddr :: Request -> ByteString
rqRemoteAddr :: Request -> ByteString
rqRemoteAddr = Request -> ByteString
rqClientAddr
{-# DEPRECATED rqRemoteAddr "(snap-core >= 1.0.0.0) please use 'rqClientAddr', this will be removed in 1.1.*" #-}
rqRemotePort :: Request -> Int
rqRemotePort :: Request -> Int
rqRemotePort = Request -> Int
rqClientPort
{-# DEPRECATED rqRemotePort "(snap-core >= 1.0.0.0) please use 'rqClientPort', this will be removed in 1.1.*" #-}