module Main (main) where
import Control.Applicative
import Control.Monad
-import qualified Data.Ascii as A
+import Data.Ascii (Ascii)
+import Data.Attempt
import Data.Char
+import Data.Convertible.Base
+import Data.Convertible.Utils
import Data.Maybe
import Language.Haskell.TH.PprLib
import Language.Haskell.TH.Syntax
= case mimeTypeOpts of
[] → Nothing
OptMIMEType ty:[]
- → case A.fromChars ty of
- Just a → Just $ parseMIMEType a
- Nothing → error "MIME types must not contain any non-ASCII letters."
+ → case convertAttemptVia ((⊥) ∷ Ascii) ty of
+ Success a → Just a
+ Failure e → error (show e)
_ → error "too many --mime-type options."
where
mimeTypeOpts ∷ [CmdOpt]
strToETag ∷ String → ETag
strToETag str
- = case A.fromChars str of
- Just a → strongETag a
- Nothing → error "ETag must not contain any non-ASCII letters."
+ = case ca str of
+ Success a → strongETag a
+ Failure e → error (show e)
openOutput ∷ [CmdOpt] → IO Handle
openOutput opts
-- *** MIME Type
, MIMEType(..)
, MIMEParams
- , parseMIMEType
, mimeType
-- *** Authentication
convertSuccess = convertSuccessVia ((⊥) ∷ AsciiBuilder)
instance ConvertSuccess Headers AsciiBuilder where
- {-# INLINE convertSuccess #-}
+ {-# INLINEABLE convertSuccess #-}
convertSuccess (Headers m)
= mconcat (header <$> fromFoldable m) ⊕ cs ("\x0D\x0A" ∷ Ascii)
where
header ∷ (CIAscii, Ascii) → AsciiBuilder
+ {-# INLINE header #-}
header (name, value)
= cs name ⊕
cs (": " ∷ Ascii) ⊕
{-# LANGUAGE
DoAndIfThenElse
+ , FlexibleContexts
+ , MultiParamTypeClasses
, OverloadedStrings
, RecordWildCards
, TemplateHaskell
import Codec.Compression.GZip
import Control.Monad
import Data.Ascii (Ascii, CIAscii)
-import qualified Data.Ascii as A
import qualified Data.ByteString.Lazy as L
import Data.Char
import Data.Collections
+import Data.Convertible.Base
import Data.Convertible.Utils
import Data.List (intersperse)
import Data.Monoid
]
else
text " Compression: disabled"
- , text " MIME Type:" <+> mimeTypeToDoc iType
- , text " ETag:" <+> eTagToDoc iETag
+ , text " MIME Type:" <+> toDoc iType
+ , text " ETag:" <+> toDoc iETag
, text " Last Modified:" <+> text (show iLastMod)
]
, text " -}"
, text "{-# LANGUAGE MagicHash #-}"
]
where
- eTagToDoc ∷ ETag → Doc
- eTagToDoc = text ∘ convertSuccessVia ((⊥) ∷ Ascii)
-
- mimeTypeToDoc ∷ MIMEType → Doc
- mimeTypeToDoc = text ∘ A.toString ∘ A.fromAsciiBuilder ∘ printMIMEType
+ toDoc ∷ ConvertSuccess α Ascii ⇒ α → Doc
+ toDoc = text ∘ convertSuccessVia ((⊥) ∷ Ascii)
moduleDecl ∷ ModName → Name → Doc
moduleDecl modName symName
convertSuccess = convertSuccessVia ((⊥) ∷ AsciiBuilder)
instance ConvertSuccess MIMEParams AsciiBuilder where
- {-# INLINE convertSuccess #-}
+ {-# INLINEABLE convertSuccess #-}
convertSuccess = foldl' f (∅)
where
f ∷ AsciiBuilder → (CIAscii, Text) → AsciiBuilder
| otherwise = toEnum $ fromIntegral
$ fromEnum 'A' + fromIntegral (h - 0x0A)
+deriveAttempts [ ([t| MIMEParams |], [t| Ascii |])
+ , ([t| MIMEParams |], [t| AsciiBuilder |])
+ ]
+
data ExtendedParam
= InitialEncodedParam {
epName ∷ !CIAscii
{-# LANGUAGE
DeriveDataTypeable
+ , FlexibleInstances
+ , MultiParamTypeClasses
, OverloadedStrings
, RecordWildCards
, TemplateHaskell
-- (<http://tools.ietf.org/html/rfc2046>).
module Network.HTTP.Lucu.MIMEType
( MIMEType(..)
-
- , parseMIMEType
- , printMIMEType
-
, mimeType
, mimeTypeList
)
}
|]
--- |Convert a 'MIMEType' to an 'AsciiBuilder'.
-printMIMEType ∷ MIMEType → AsciiBuilder
-{-# INLINEABLE printMIMEType #-}
-printMIMEType (MIMEType {..})
- = A.toAsciiBuilder (A.fromCIAscii mtMedia) ⊕
- A.toAsciiBuilder "/" ⊕
- A.toAsciiBuilder (A.fromCIAscii mtSub) ⊕
- cs mtParams
+instance ConvertSuccess MIMEType Ascii where
+ {-# INLINE convertSuccess #-}
+ convertSuccess = convertSuccessVia ((⊥) ∷ AsciiBuilder)
+
+instance ConvertSuccess MIMEType AsciiBuilder where
+ {-# INLINEABLE convertSuccess #-}
+ convertSuccess (MIMEType {..})
+ = cs mtMedia ⊕
+ cs ("/" ∷ Ascii) ⊕
+ cs mtSub ⊕
+ cs mtParams
+
+deriveAttempts [ ([t| MIMEType |], [t| Ascii |])
+ , ([t| MIMEType |], [t| AsciiBuilder |])
+ ]
--- |Parse 'MIMEType' from an 'Ascii'. This function throws an
--- exception for parse error. For literals consider using
--- 'Network.HTTP.Lucu.MIMEType.TH.mimeType'.
-parseMIMEType ∷ Ascii → MIMEType
-{-# INLINEABLE parseMIMEType #-}
-parseMIMEType str
- = case parseOnly (finishOff mimeType) $ A.toByteString str of
- Right t → t
- Left err → error ("Unparsable MIME Type: " ⧺ A.toString str ⧺ ": " ⧺ err)
+-- |Parse 'MIMEType' from an 'Ascii'. For MIME type literals, consider
+-- using 'Network.HTTP.Lucu.MIMEType.TH.mimeType'.
+instance ConvertAttempt Ascii MIMEType where
+ {-# INLINEABLE convertAttempt #-}
+ convertAttempt str
+ = case parseOnly (finishOff mimeType) (cs str) of
+ Right t → return t
+ Left err → fail ("Unparsable MIME Type: " ⧺ cs str ⧺ ": " ⧺ err)
-- |'Parser' for an 'MIMEType'.
mimeType ∷ Parser MIMEType
where
import Control.Monad.Unicode
import Data.Ascii (Ascii)
-import qualified Data.Ascii as A
+import Data.Attempt
+import Data.Convertible.Base
import Language.Haskell.TH.Syntax
import Language.Haskell.TH.Quote
import Network.HTTP.Lucu.MIMEType hiding (mimeType)
-- @
mimeType ∷ QuasiQuoter
mimeType = QuasiQuoter {
- quoteExp = (lift ∘ parseMIMEType =≪) ∘ toAscii
+ quoteExp = (lift =≪) ∘ (parse =≪) ∘ toAscii
, quotePat = const unsupported
, quoteType = const unsupported
, quoteDec = const unsupported
}
where
+ parse ∷ Monad m ⇒ Ascii → m MIMEType
+ parse a
+ = case ca a of
+ Success t → return t
+ Failure e → fail (show e)
+
toAscii ∷ Monad m ⇒ String → m Ascii
- toAscii (A.fromChars ∘ trim → Just a) = return a
- toAscii str = fail $ "Malformed MIME Type: " ⧺ str
+ toAscii (trim → s)
+ = case ca s of
+ Success a → return a
+ Failure e → fail (show e)
unsupported ∷ Monad m ⇒ m α
unsupported = fail "Unsupported usage of mimeType quasi-quoter."
import qualified Data.ByteString.Lazy as LS
import Data.ByteString.Lazy.Search
import Data.Collections
+import Data.Convertible.Base
+import Data.Convertible.Instances.Ascii ()
+import Data.Convertible.Utils
import Data.List (intercalate)
import Data.Maybe
import Data.Monoid.Unicode
, dParams ∷ !MIMEParams
}
+-- FIXME
printContDispo ∷ ContDispo → Ascii
printContDispo d
= A.fromAsciiBuilder
( A.toAsciiBuilder (A.fromCIAscii $ dType d)
⊕
- printMIMEParams (dParams d) )
+ cs (dParams d) )
-- |Parse \"multipart/form-data\" and return either @'Left' err@ or
-- @'Right' result@. Note that there are currently the following
→ readMultipartFormData params
Just cType
→ abort $ mkAbortion' UnsupportedMediaType
- $ A.toText
- $ A.fromAsciiBuilder
- $ A.toAsciiBuilder "Unsupported media type: "
- ⊕ MT.printMIMEType cType
+ $ cs
+ $ ("Unsupported media type: " ∷ Ascii)
+ ⊕ cs cType
where
readWWWFormURLEncoded
= (map toPairWithFormData ∘ parseWWWFormURLEncoded)
-- \"Content-Type\" as @mType@. Declaring \"Content-Type\" is
-- mandatory for sending a response body.
setContentType ∷ MIMEType → Rsrc ()
-setContentType
- = setHeader "Content-Type" ∘ A.fromAsciiBuilder ∘ MT.printMIMEType
+setContentType = setHeader "Content-Type" ∘ cs
-- |@'setLocation' uri@ declares the response header \"Location\" as
-- @uri@. You usually don't need to call this function directly.