X-Git-Url: http://git.cielonegro.org/gitweb.cgi?p=Lucu.git;a=blobdiff_plain;f=Network%2FHTTP%2FLucu%2FHeaders.hs;h=d4c51d5e24ae7681e91aff273ae9c5bbc29b2e70;hp=8219624df47b052df0be224e37dbda10957927bc;hb=97295ba;hpb=09fe5429b2a1bcea6d6e57ab1c4a5178807cbacd diff --git a/Network/HTTP/Lucu/Headers.hs b/Network/HTTP/Lucu/Headers.hs index 8219624..d4c51d5 100644 --- a/Network/HTTP/Lucu/Headers.hs +++ b/Network/HTTP/Lucu/Headers.hs @@ -2,39 +2,42 @@ FlexibleInstances , GeneralizedNewtypeDeriving , MultiParamTypeClasses + , TemplateHaskell , TypeSynonymInstances , OverloadedStrings , UnicodeSyntax #-} +{-# OPTIONS_GHC -fno-warn-missing-methods #-} -- |An internal module for HTTP headers. module Network.HTTP.Lucu.Headers ( Headers , HasHeaders(..) - , headers - , printHeaders ) where -import Control.Applicative +import Control.Applicative hiding (empty) import Control.Applicative.Unicode hiding ((∅)) -import Control.Arrow import Control.Monad import Data.Ascii (Ascii, AsciiBuilder, CIAscii) import qualified Data.Ascii as A -import Data.Attoparsec.Char8 as P +import Data.Attoparsec.Char8 +import qualified Data.Collections.Newtype.TH as C +import Data.Convertible.Base +import Data.Convertible.Instances.Ascii () +import Data.Convertible.Utils import Data.List (intersperse) -import qualified Data.Map as M +import qualified Data.Map as M (Map) import Data.Collections import Data.Collections.BaseInstances () import Data.Monoid import Data.Monoid.Unicode import Network.HTTP.Lucu.Parser.Http -import Prelude hiding (filter, lookup, null) +import Prelude hiding (lookup, null) import Prelude.Unicode newtype Headers = Headers (M.Map CIAscii Ascii) - deriving (Eq, Monoid, Show) + deriving (Eq, Show) class HasHeaders a where getHeaders ∷ a → Headers @@ -68,56 +71,28 @@ instance HasHeaders Headers where getHeaders = id setHeaders _ = id +C.derive [d| instance Foldable Headers (CIAscii, Ascii) + instance Collection Headers (CIAscii, Ascii) + instance Indexed Headers CIAscii Ascii + instance Map Headers CIAscii Ascii + instance SortingCollection Headers (CIAscii, Ascii) + |] + -- |@'insert' (key, val)@ merges @val@ with an existing one if any. instance Unfoldable Headers (CIAscii, Ascii) where {-# INLINE insert #-} insert (key, val) (Headers m) = Headers $ insertWith merge key val m + {-# INLINE empty #-} + empty = Headers empty + {-# INLINE singleton #-} + singleton = Headers ∘ singleton -instance Foldable Headers (CIAscii, Ascii) where - {-# INLINE foldMap #-} - foldMap f (Headers m) = foldMap f m - -instance Collection Headers (CIAscii, Ascii) where - {-# INLINE filter #-} - filter f (Headers m) = Headers $ filter f m - -instance Indexed Headers CIAscii Ascii where - {-# INLINE index #-} - index k (Headers m) = index k m - {-# INLINE adjust #-} - adjust f k (Headers m) = Headers $ adjust f k m - {-# INLINE inDomain #-} - inDomain k (Headers m) = inDomain k m - -instance Map Headers CIAscii Ascii where - {-# INLINE lookup #-} - lookup k (Headers m) = lookup k m - {-# INLINE insertWith #-} - insertWith f k v (Headers m) - = Headers $ insertWith f k v m - {-# INLINE mapWithKey #-} - mapWithKey f (Headers m) - = Headers $ mapWithKey f m - {-# INLINE unionWith #-} - unionWith f (Headers α) (Headers β) - = Headers $ unionWith f α β - {-# INLINE intersectionWith #-} - intersectionWith f (Headers α) (Headers β) - = Headers $ intersectionWith f α β - {-# INLINE differenceWith #-} - differenceWith f (Headers α) (Headers β) - = Headers $ differenceWith f α β - {-# INLINE isSubmapBy #-} - isSubmapBy f (Headers α) (Headers β) - = isSubmapBy f α β - {-# INLINE isProperSubmapBy #-} - isProperSubmapBy f (Headers α) (Headers β) - = isProperSubmapBy f α β - -instance SortingCollection Headers (CIAscii, Ascii) where - {-# INLINE minView #-} - minView (Headers m) = second Headers <$> minView m +instance Monoid Headers where + {-# INLINE mempty #-} + mempty = empty + {-# INLINE mappend #-} + mappend = insertMany merge ∷ Ascii → Ascii → Ascii {-# INLINE merge #-} @@ -131,6 +106,26 @@ merge a b {-# INLINE nullA #-} nullA = null ∘ A.toByteString +instance ConvertSuccess Headers Ascii where + {-# INLINE convertSuccess #-} + convertSuccess = convertSuccessVia ((⊥) ∷ AsciiBuilder) + +instance ConvertSuccess Headers AsciiBuilder where + {-# INLINE convertSuccess #-} + convertSuccess (Headers m) + = mconcat (header <$> fromFoldable m) ⊕ cs ("\x0D\x0A" ∷ Ascii) + where + header ∷ (CIAscii, Ascii) → AsciiBuilder + header (name, value) + = cs name ⊕ + cs (": " ∷ Ascii) ⊕ + cs value ⊕ + cs ("\x0D\x0A" ∷ Ascii) + +deriveAttempts [ ([t| Headers |], [t| Ascii |]) + , ([t| Headers |], [t| AsciiBuilder |]) + ] + {- message-header = field-name ":" [ field-value ] field-name = token @@ -144,7 +139,7 @@ merge a b -} headers ∷ Parser Headers {-# INLINEABLE headers #-} -headers = do xs ← P.many header +headers = do xs ← many header crlf return $ fromFoldable xs where @@ -168,16 +163,4 @@ headers = do xs ← P.many header joinValues = A.fromAsciiBuilder ∘ mconcat ∘ intersperse (A.toAsciiBuilder "\x20") - ∘ map A.toAsciiBuilder - -printHeaders ∷ Headers → AsciiBuilder -printHeaders (Headers m) - = mconcat (map printHeader (fromFoldable m)) ⊕ - A.toAsciiBuilder "\x0D\x0A" - where - printHeader ∷ (CIAscii, Ascii) → AsciiBuilder - printHeader (name, value) - = A.toAsciiBuilder (A.fromCIAscii name) ⊕ - A.toAsciiBuilder ": " ⊕ - A.toAsciiBuilder value ⊕ - A.toAsciiBuilder "\x0D\x0A" + ∘ (A.toAsciiBuilder <$>)