{-# LANGUAGE OverloadedStrings , UnicodeSyntax #-} -- |This is an auxiliary parser utilities for parsing things related -- on HTTP protocol. -- -- In general you don't have to use this module directly. module Network.HTTP.Lucu.Parser.Http ( isCtl , isText , isSeparator , isChar , isToken , isSPHT , listOf , crlf , sp , lws , token , separators , quotedStr , qvalue ) where import Control.Applicative import Control.Monad import Data.Ascii (Ascii) import qualified Data.Ascii as A import Data.Attoparsec.Char8 import qualified Data.ByteString.Char8 as BS import Network.HTTP.Lucu.Parser import Prelude.Unicode -- |@'isCtl' c@ returns 'False' iff @0x20 <= c < 0x7F@. isCtl ∷ Char → Bool {-# INLINE isCtl #-} isCtl c | c ≤ '\x1f' = True | c > '\x7f' = True | otherwise = False -- |@'isText'@ is equivalent to @'not' '.' 'isCtl'@ isText ∷ Char → Bool {-# INLINE isText #-} isText = (¬) ∘ isCtl -- |@'isSeparator' c@ returns 'True' iff c is one of the HTTP -- separators. isSeparator ∷ Char → Bool {-# INLINE isSeparator #-} isSeparator = inClass "()<>@,;:\\\"/[]?={}\x20\x09" -- |@'isChar' c@ returns 'True' iff @c <= 0x7f@. isChar ∷ Char → Bool {-# INLINE isChar #-} isChar = (≤ '\x7F') -- |@'isToken' c@ is equivalent to @not ('isCtl' c '||' 'isSeparator' -- c)@ isToken ∷ Char → Bool {-# INLINE isToken #-} isToken c = (¬) (isCtl c ∨ isSeparator c) -- |@'listOf' p@ is similar to @'sepBy' p ('char' \',\')@ but it -- allows any occurrences of 'lws' before and after each tokens. listOf ∷ Parser a → Parser [a] {-# INLINEABLE listOf #-} listOf p = do skipMany lws p `sepBy` do skipMany lws void $ char ',' skipMany lws "listOf" -- |'token' is almost the same as @'takeWhile1' 'isToken'@ token ∷ Parser Ascii {-# INLINE token #-} token = (A.unsafeFromByteString <$> takeWhile1 isToken) "token" -- |The CRLF: 0x0D 0x0A. crlf ∷ Parser () {-# INLINE crlf #-} crlf = (string "\x0D\x0A" *> return ()) "crlf" -- |The SP: 0x20. sp ∷ Parser () {-# INLINE sp #-} sp = char '\x20' *> return () -- |HTTP LWS: crlf? (sp | ht)+ lws ∷ Parser () {-# INLINEABLE lws #-} lws = (option () crlf *> void (takeWhile1 isSPHT)) "lws" -- |Returns 'True' for SP and HT. isSPHT ∷ Char → Bool {-# INLINE isSPHT #-} isSPHT '\x20' = True isSPHT '\x09' = True isSPHT _ = False -- |@'separators'@ is almost the same as @'takeWhile1' 'isSeparator'@. separators ∷ Parser Ascii {-# INLINE separators #-} separators = (A.unsafeFromByteString <$> takeWhile1 isSeparator) "separators" -- |'quotedStr' accepts a string surrounded by double quotation -- marks. Quotes can be escaped by backslashes. quotedStr ∷ Parser Ascii {-# INLINEABLE quotedStr #-} quotedStr = do void $ char '"' xs ← many (qdtext <|> quotedPair) void $ char '"' return ∘ A.unsafeFromByteString $ BS.pack xs "quotedStr" where qdtext ∷ Parser Char {-# INLINE qdtext #-} qdtext = satisfy (\c → c ≢ '"' ∧ (¬) (isCtl c)) "qdtext" quotedPair ∷ Parser Char {-# INLINE quotedPair #-} quotedPair = (char '\\' *> satisfy isChar) "quotedPair" -- |'qvalue' accepts a so-called qvalue. qvalue ∷ Parser Double {-# INLINEABLE qvalue #-} qvalue = ( do x ← char '0' xs ← option "" $ do y ← char '.' ys ← atMost 3 digit return (y:ys) return $ read (x:xs) <|> do x ← char '1' xs ← option "" $ do y ← char '.' ys ← atMost 3 (char '0') return (y:ys) return $ read (x:xs) ) "qvalue"