X-Git-Url: http://git.cielonegro.org/gitweb.cgi?p=Lucu.git;a=blobdiff_plain;f=Network%2FHTTP%2FLucu%2FHeaders.hs;h=80b9b1339501d95a08c80511645e3603a5b1d9ea;hp=424145586253bd0544f8070d540cad9c83e502ff;hb=cc074d0ce3f7df2544bc2baddca4e7730ecdf0a0;hpb=02d702c138d918386135245021d5778676ee6d0e diff --git a/Network/HTTP/Lucu/Headers.hs b/Network/HTTP/Lucu/Headers.hs index 4241455..80b9b13 100644 --- a/Network/HTTP/Lucu/Headers.hs +++ b/Network/HTTP/Lucu/Headers.hs @@ -1,32 +1,35 @@ {-# LANGUAGE - BangPatterns - , GeneralizedNewtypeDeriving + GeneralizedNewtypeDeriving , OverloadedStrings , UnicodeSyntax #-} +-- |An internal module for HTTP headers. module Network.HTTP.Lucu.Headers ( Headers , HasHeaders(..) + , singleton + , toHeaders , fromHeaders - , headersP - , hPutHeaders + , headers + , printHeaders ) where import Control.Applicative -import Data.Ascii (Ascii, CIAscii) +import Control.Monad +import Data.Ascii (Ascii, AsciiBuilder, CIAscii) import qualified Data.Ascii as A import Data.Attoparsec.Char8 as P import qualified Data.ByteString as BS +import Data.List import Data.Map (Map) import qualified Data.Map as M +import qualified Data.Map.Unicode as M import Data.Monoid import Data.Monoid.Unicode -import Network.HTTP.Lucu.HandleLike import Network.HTTP.Lucu.Parser.Http -import Network.HTTP.Lucu.Utils import Prelude.Unicode newtype Headers @@ -38,21 +41,31 @@ class HasHeaders a where setHeaders ∷ a → Headers → a getHeader ∷ CIAscii → a → Maybe Ascii - {-# INLINE getHeader #-} - getHeader !key !a + getHeader key a = case getHeaders a of Headers m → M.lookup key m + hasHeader ∷ CIAscii → a → Bool + {-# INLINE hasHeader #-} + hasHeader key a + = case getHeaders a of + Headers m → key M.∈ m + + getCIHeader ∷ CIAscii → a → Maybe CIAscii + {-# INLINE getCIHeader #-} + getCIHeader key a + = A.toCIAscii <$> getHeader key a + deleteHeader ∷ CIAscii → a → a {-# INLINE deleteHeader #-} - deleteHeader !key !a + deleteHeader key a = case getHeaders a of Headers m → setHeaders a $ Headers $ M.delete key m setHeader ∷ CIAscii → Ascii → a → a {-# INLINE setHeader #-} - setHeader !key !val !a + setHeader key val a = case getHeaders a of Headers m → setHeaders a $ Headers $ M.insert key val m @@ -61,6 +74,11 @@ instance HasHeaders Headers where getHeaders = id setHeaders _ = id +singleton ∷ CIAscii → Ascii → Headers +{-# INLINE singleton #-} +singleton key val + = Headers $ M.singleton key val + toHeaders ∷ [(CIAscii, Ascii)] → Headers {-# INLINE toHeaders #-} toHeaders = flip mkHeaders (∅) @@ -99,19 +117,18 @@ fromHeaders (Headers m) = M.toList m field-value の先頭および末尾にある LWS は全て削除され、それ以外の LWS は單一の SP に變換される。 -} -headersP ∷ Parser Headers -{-# INLINEABLE headersP #-} -headersP = do xs ← P.many header - crlf - return $ toHeaders xs +headers ∷ Parser Headers +{-# INLINEABLE headers #-} +headers = do xs ← P.many header + crlf + return $ toHeaders xs where header ∷ Parser (CIAscii, Ascii) - header = try $ - do name ← A.toCIAscii <$> token - _ ← char ':' - skipMany lws - values ← sepBy content lws + header = do name ← A.toCIAscii <$> token + void $ char ':' skipMany lws + values ← content `sepBy` try lws + skipMany (try lws) crlf return (name, joinValues values) @@ -119,19 +136,23 @@ headersP = do xs ← P.many header {-# INLINE content #-} content = A.unsafeFromByteString <$> - takeWhile1 (\c → ((¬) (isSPHT c)) ∧ isText c) + takeWhile1 (\c → isText c ∧ c ≢ '\x20') joinValues ∷ [Ascii] → Ascii {-# INLINE joinValues #-} - joinValues = A.fromAsciiBuilder ∘ joinWith "\x20" ∘ map A.toAsciiBuilder - -hPutHeaders ∷ HandleLike h => h → Headers → IO () -hPutHeaders !h !(Headers m) - = mapM_ putH (M.toList m) >> hPutBS h "\r\n" + joinValues = A.fromAsciiBuilder + ∘ mconcat + ∘ intersperse (A.toAsciiBuilder "\x20") + ∘ map A.toAsciiBuilder + +printHeaders ∷ Headers → AsciiBuilder +printHeaders (Headers m) + = mconcat (map printHeader (M.toList m)) ⊕ + A.toAsciiBuilder "\x0D\x0A" where - putH ∷ (CIAscii, Ascii) → IO () - putH (!name, !value) - = do hPutBS h (A.ciToByteString name) - hPutBS h ": " - hPutBS h (A.toByteString value) - hPutBS h "\r\n" + printHeader ∷ (CIAscii, Ascii) → AsciiBuilder + printHeader (name, value) + = A.toAsciiBuilder (A.fromCIAscii name) ⊕ + A.toAsciiBuilder ": " ⊕ + A.toAsciiBuilder value ⊕ + A.toAsciiBuilder "\x0D\x0A"