|
Packit |
acf257 |
{-# LANGUAGE TypeSynonymInstances #-}
|
|
Packit |
acf257 |
-----------------------------------------------------------------------------
|
|
Packit |
acf257 |
-- |
|
|
Packit |
acf257 |
-- Module : Network.BufferType
|
|
Packit |
acf257 |
-- Description : Abstract representation of request and response buffer types.
|
|
Packit |
acf257 |
-- Copyright : See LICENSE file
|
|
Packit |
acf257 |
-- License : BSD
|
|
Packit |
acf257 |
--
|
|
Packit |
acf257 |
-- Maintainer : Ganesh Sittampalam <ganesh@earth.li>
|
|
Packit |
acf257 |
-- Stability : experimental
|
|
Packit |
acf257 |
-- Portability : non-portable (not tested)
|
|
Packit |
acf257 |
--
|
|
Packit |
acf257 |
-- In order to give the user freedom in how request and response content
|
|
Packit |
acf257 |
-- is represented, a sufficiently abstract representation is needed of
|
|
Packit |
acf257 |
-- these internally. The "Network.BufferType" module provides this, defining
|
|
Packit |
acf257 |
-- the 'BufferType' class and its ad-hoc representation of buffer operations
|
|
Packit |
acf257 |
-- via the 'BufferOp' record.
|
|
Packit |
acf257 |
--
|
|
Packit |
acf257 |
-- This module provides definitions for the standard buffer types that the
|
|
Packit |
acf257 |
-- package supports, i.e., for @String@ and @ByteString@ (strict and lazy.)
|
|
Packit |
acf257 |
--
|
|
Packit |
acf257 |
-----------------------------------------------------------------------------
|
|
Packit |
acf257 |
module Network.BufferType
|
|
Packit |
acf257 |
(
|
|
Packit |
acf257 |
BufferType(..)
|
|
Packit |
acf257 |
|
|
Packit |
acf257 |
, BufferOp(..)
|
|
Packit |
acf257 |
, strictBufferOp
|
|
Packit |
acf257 |
, lazyBufferOp
|
|
Packit |
acf257 |
, stringBufferOp
|
|
Packit |
acf257 |
) where
|
|
Packit |
acf257 |
|
|
Packit |
acf257 |
|
|
Packit |
acf257 |
import qualified Data.ByteString as Strict hiding ( unpack, pack, span )
|
|
Packit |
acf257 |
import qualified Data.ByteString.Char8 as Strict ( unpack, pack, span )
|
|
Packit |
acf257 |
import qualified Data.ByteString.Lazy as Lazy hiding ( pack, unpack,span )
|
|
Packit |
acf257 |
import qualified Data.ByteString.Lazy.Char8 as Lazy ( pack, unpack, span )
|
|
Packit |
acf257 |
import System.IO ( Handle )
|
|
Packit |
acf257 |
import Data.Word ( Word8 )
|
|
Packit |
acf257 |
|
|
Packit |
acf257 |
import Network.HTTP.Utils ( crlf, lf )
|
|
Packit |
acf257 |
|
|
Packit |
acf257 |
-- | The @BufferType@ class encodes, in a mixed-mode way, the interface
|
|
Packit |
acf257 |
-- that the library requires to operate over data embedded in HTTP
|
|
Packit |
acf257 |
-- requests and responses. That is, we use explicit dictionaries
|
|
Packit |
acf257 |
-- for the operations, but overload the name of the dicts themselves.
|
|
Packit |
acf257 |
--
|
|
Packit |
acf257 |
class BufferType bufType where
|
|
Packit |
acf257 |
bufferOps :: BufferOp bufType
|
|
Packit |
acf257 |
|
|
Packit |
acf257 |
instance BufferType Lazy.ByteString where
|
|
Packit |
acf257 |
bufferOps = lazyBufferOp
|
|
Packit |
acf257 |
|
|
Packit |
acf257 |
instance BufferType Strict.ByteString where
|
|
Packit |
acf257 |
bufferOps = strictBufferOp
|
|
Packit |
acf257 |
|
|
Packit |
acf257 |
instance BufferType String where
|
|
Packit |
acf257 |
bufferOps = stringBufferOp
|
|
Packit |
acf257 |
|
|
Packit |
acf257 |
-- | @BufferOp@ encodes the I/O operations of the underlying buffer over
|
|
Packit |
acf257 |
-- a Handle in an (explicit) dictionary type. May not be needed, but gives
|
|
Packit |
acf257 |
-- us flexibility in explicit overriding and wrapping up of these methods.
|
|
Packit |
acf257 |
--
|
|
Packit |
acf257 |
-- Along with IO operations is an ad-hoc collection of functions for working
|
|
Packit |
acf257 |
-- with these abstract buffers, as needed by the internals of the code
|
|
Packit |
acf257 |
-- that processes requests and responses.
|
|
Packit |
acf257 |
--
|
|
Packit |
acf257 |
-- We supply three default @BufferOp@ values, for @String@ along with the
|
|
Packit |
acf257 |
-- strict and lazy versions of @ByteString@. To add others, provide @BufferOp@
|
|
Packit |
acf257 |
-- definitions for
|
|
Packit |
acf257 |
data BufferOp a
|
|
Packit |
acf257 |
= BufferOp
|
|
Packit |
acf257 |
{ buf_hGet :: Handle -> Int -> IO a
|
|
Packit |
acf257 |
, buf_hGetContents :: Handle -> IO a
|
|
Packit |
acf257 |
, buf_hPut :: Handle -> a -> IO ()
|
|
Packit |
acf257 |
, buf_hGetLine :: Handle -> IO a
|
|
Packit |
acf257 |
, buf_empty :: a
|
|
Packit |
acf257 |
, buf_append :: a -> a -> a
|
|
Packit |
acf257 |
, buf_concat :: [a] -> a
|
|
Packit |
acf257 |
, buf_fromStr :: String -> a
|
|
Packit |
acf257 |
, buf_toStr :: a -> String
|
|
Packit |
acf257 |
, buf_snoc :: a -> Word8 -> a
|
|
Packit |
acf257 |
, buf_splitAt :: Int -> a -> (a,a)
|
|
Packit |
acf257 |
, buf_span :: (Char -> Bool) -> a -> (a,a)
|
|
Packit |
acf257 |
, buf_isLineTerm :: a -> Bool
|
|
Packit |
acf257 |
, buf_isEmpty :: a -> Bool
|
|
Packit |
acf257 |
}
|
|
Packit |
acf257 |
|
|
Packit |
acf257 |
instance Eq (BufferOp a) where
|
|
Packit |
acf257 |
_ == _ = False
|
|
Packit |
acf257 |
|
|
Packit |
acf257 |
-- | @strictBufferOp@ is the 'BufferOp' definition over @ByteString@s,
|
|
Packit |
acf257 |
-- the non-lazy kind.
|
|
Packit |
acf257 |
strictBufferOp :: BufferOp Strict.ByteString
|
|
Packit |
acf257 |
strictBufferOp =
|
|
Packit |
acf257 |
BufferOp
|
|
Packit |
acf257 |
{ buf_hGet = Strict.hGet
|
|
Packit |
acf257 |
, buf_hGetContents = Strict.hGetContents
|
|
Packit |
acf257 |
, buf_hPut = Strict.hPut
|
|
Packit |
acf257 |
, buf_hGetLine = Strict.hGetLine
|
|
Packit |
acf257 |
, buf_append = Strict.append
|
|
Packit |
acf257 |
, buf_concat = Strict.concat
|
|
Packit |
acf257 |
, buf_fromStr = Strict.pack
|
|
Packit |
acf257 |
, buf_toStr = Strict.unpack
|
|
Packit |
acf257 |
, buf_snoc = Strict.snoc
|
|
Packit |
acf257 |
, buf_splitAt = Strict.splitAt
|
|
Packit |
acf257 |
, buf_span = Strict.span
|
|
Packit |
acf257 |
, buf_empty = Strict.empty
|
|
Packit |
acf257 |
, buf_isLineTerm = \ b -> Strict.length b == 2 && p_crlf == b ||
|
|
Packit |
acf257 |
Strict.length b == 1 && p_lf == b
|
|
Packit |
acf257 |
, buf_isEmpty = Strict.null
|
|
Packit |
acf257 |
}
|
|
Packit |
acf257 |
where
|
|
Packit |
acf257 |
p_crlf = Strict.pack crlf
|
|
Packit |
acf257 |
p_lf = Strict.pack lf
|
|
Packit |
acf257 |
|
|
Packit |
acf257 |
-- | @lazyBufferOp@ is the 'BufferOp' definition over @ByteString@s,
|
|
Packit |
acf257 |
-- the non-strict kind.
|
|
Packit |
acf257 |
lazyBufferOp :: BufferOp Lazy.ByteString
|
|
Packit |
acf257 |
lazyBufferOp =
|
|
Packit |
acf257 |
BufferOp
|
|
Packit |
acf257 |
{ buf_hGet = Lazy.hGet
|
|
Packit |
acf257 |
, buf_hGetContents = Lazy.hGetContents
|
|
Packit |
acf257 |
, buf_hPut = Lazy.hPut
|
|
Packit |
acf257 |
, buf_hGetLine = \ h -> Strict.hGetLine h >>= \ l -> return (Lazy.fromChunks [l])
|
|
Packit |
acf257 |
, buf_append = Lazy.append
|
|
Packit |
acf257 |
, buf_concat = Lazy.concat
|
|
Packit |
acf257 |
, buf_fromStr = Lazy.pack
|
|
Packit |
acf257 |
, buf_toStr = Lazy.unpack
|
|
Packit |
acf257 |
, buf_snoc = Lazy.snoc
|
|
Packit |
acf257 |
, buf_splitAt = \ i x -> Lazy.splitAt (fromIntegral i) x
|
|
Packit |
acf257 |
, buf_span = Lazy.span
|
|
Packit |
acf257 |
, buf_empty = Lazy.empty
|
|
Packit |
acf257 |
, buf_isLineTerm = \ b -> Lazy.length b == 2 && p_crlf == b ||
|
|
Packit |
acf257 |
Lazy.length b == 1 && p_lf == b
|
|
Packit |
acf257 |
, buf_isEmpty = Lazy.null
|
|
Packit |
acf257 |
}
|
|
Packit |
acf257 |
where
|
|
Packit |
acf257 |
p_crlf = Lazy.pack crlf
|
|
Packit |
acf257 |
p_lf = Lazy.pack lf
|
|
Packit |
acf257 |
|
|
Packit |
acf257 |
-- | @stringBufferOp@ is the 'BufferOp' definition over @String@s.
|
|
Packit |
acf257 |
-- It is defined in terms of @strictBufferOp@ operations,
|
|
Packit |
acf257 |
-- unpacking/converting to @String@ when needed.
|
|
Packit |
acf257 |
stringBufferOp :: BufferOp String
|
|
Packit |
acf257 |
stringBufferOp =BufferOp
|
|
Packit |
acf257 |
{ buf_hGet = \ h n -> buf_hGet strictBufferOp h n >>= return . Strict.unpack
|
|
Packit |
acf257 |
, buf_hGetContents = \ h -> buf_hGetContents strictBufferOp h >>= return . Strict.unpack
|
|
Packit |
acf257 |
, buf_hPut = \ h s -> buf_hPut strictBufferOp h (Strict.pack s)
|
|
Packit |
acf257 |
, buf_hGetLine = \ h -> buf_hGetLine strictBufferOp h >>= return . Strict.unpack
|
|
Packit |
acf257 |
, buf_append = (++)
|
|
Packit |
acf257 |
, buf_concat = concat
|
|
Packit |
acf257 |
, buf_fromStr = id
|
|
Packit |
acf257 |
, buf_toStr = id
|
|
Packit |
acf257 |
, buf_snoc = \ a x -> a ++ [toEnum (fromIntegral x)]
|
|
Packit |
acf257 |
, buf_splitAt = splitAt
|
|
Packit |
acf257 |
, buf_span = \ p a ->
|
|
Packit |
acf257 |
case Strict.span p (Strict.pack a) of
|
|
Packit |
acf257 |
(x,y) -> (Strict.unpack x, Strict.unpack y)
|
|
Packit |
acf257 |
, buf_empty = []
|
|
Packit |
acf257 |
, buf_isLineTerm = \ b -> b == crlf || b == lf
|
|
Packit |
acf257 |
, buf_isEmpty = null
|
|
Packit |
acf257 |
}
|
|
Packit |
acf257 |
|