--- #prune
+{-# LANGUAGE
+ OverloadedStrings
+ , UnicodeSyntax
+ #-}
--- |Manipulation of MIME Types.
+-- |MIME Types
module Network.HTTP.Lucu.MIMEType
( MIMEType(..)
+ , mkMIMEType
+
, parseMIMEType
+ , printMIMEType
+
, mimeTypeP
, mimeTypeListP
)
where
+import Control.Applicative
+import Data.Ascii (Ascii, AsciiBuilder, CIAscii)
+import qualified Data.Ascii as A
+import Data.Attoparsec.Char8 as P
+import Data.Map (Map)
+import Data.Monoid.Unicode
+import Data.Text (Text)
+import Network.HTTP.Lucu.Parser.Http
+import Network.HTTP.Lucu.RFC2231
+import Prelude hiding (min)
+import Prelude.Unicode
-import Network.HTTP.Lucu.Parser
-import Network.HTTP.Lucu.Parser.Http
-import Network.HTTP.Lucu.Utils
-
--- |@'MIMEType' \"major\" \"minor\" [(\"name\", \"value\")]@
--- represents \"major\/minor; name=value\".
+-- |@'MIMEType' \"major\" \"minor\" [(\"name\", \"value\"), ...]@
+-- represents \"major\/minor; name=value; ...\".
data MIMEType = MIMEType {
- mtMajor :: !String
- , mtMinor :: !String
- , mtParams :: ![ (String, String) ]
+ mtMajor ∷ !CIAscii
+ , mtMinor ∷ !CIAscii
+ , mtParams ∷ !(Map CIAscii Text)
} deriving (Eq)
-
instance Show MIMEType where
- show (MIMEType maj min params)
- = maj ++ "/" ++ min ++
- if null params then
- ""
- else
- "; " ++ joinWith "; " (map showPair params)
- where
- showPair :: (String, String) -> String
- showPair (name, value)
- = name ++ "=" ++ if any (not . isToken) value then
- quoteStr value
- else
- value
+ show = A.toString ∘ A.fromAsciiBuilder ∘ printMIMEType
+-- |@'mkMIMEType' major minor@ returns a 'MIMEType' with the given
+-- @major@ and @minor@ types but without any parameters.
+mkMIMEType ∷ CIAscii → CIAscii → MIMEType
+{-# INLINE mkMIMEType #-}
+mkMIMEType maj min
+ = MIMEType maj min (∅)
-instance Read MIMEType where
- readsPrec _ s = [(parseMIMEType s, "")]
+-- |Convert a 'MIMEType' to an 'AsciiBuilder'.
+printMIMEType ∷ MIMEType → AsciiBuilder
+{-# INLINEABLE printMIMEType #-}
+printMIMEType (MIMEType maj min params)
+ = A.toAsciiBuilder (A.fromCIAscii maj) ⊕
+ A.toAsciiBuilder "/" ⊕
+ A.toAsciiBuilder (A.fromCIAscii min) ⊕
+ printParams params
--- |Parse 'MIMEType' from a 'Prelude.String'. This function throws an
+-- |Parse 'MIMEType' from an 'Ascii'. This function throws an
-- exception for parse error.
-parseMIMEType :: String -> MIMEType
-parseMIMEType str = case parseStr mimeTypeP str of
- (Success t, _) -> t
- _ -> error ("Unparsable MIME Type: " ++ str)
-
+parseMIMEType ∷ Ascii → MIMEType
+{-# INLINEABLE parseMIMEType #-}
+parseMIMEType str
+ = case parseOnly p $ A.toByteString str of
+ Right t → t
+ Left err → error ("unparsable MIME Type: " ⧺ A.toString str ⧺ ": " ⧺ err)
+ where
+ p ∷ Parser MIMEType
+ {-# INLINE p #-}
+ p = do t ← mimeTypeP
+ endOfInput
+ return t
-mimeTypeP :: Parser MIMEType
-mimeTypeP = allowEOF $!
- do maj <- token
- char '/'
- min <- token
- params <- many paramP
+-- |'Parser' for an 'MIMEType'.
+mimeTypeP ∷ Parser MIMEType
+{-# INLINEABLE mimeTypeP #-}
+mimeTypeP = do maj ← A.toCIAscii <$> token
+ _ ← char '/'
+ min ← A.toCIAscii <$> token
+ params ← paramsP
return $ MIMEType maj min params
- where
- paramP :: Parser (String, String)
- paramP = do many lws
- char ';'
- many lws
- name <- token
- char '='
- value <- token <|> quotedStr
- return (name, value)
-mimeTypeListP :: Parser [MIMEType]
-mimeTypeListP = allowEOF $! listOf mimeTypeP
+-- |'Parser' for a list of 'MIMEType's.
+mimeTypeListP ∷ Parser [MIMEType]
+{-# INLINE mimeTypeListP #-}
+mimeTypeListP = listOf mimeTypeP