X-Git-Url: http://git.cielonegro.org/gitweb.cgi?p=Lucu.git;a=blobdiff_plain;f=Network%2FHTTP%2FLucu%2FMultipartForm.hs;h=98699e43ca37d2e2a2978236130f50b6a705c04a;hp=882ff76668dc60bcb721eaefd83f1d4555d5303a;hb=90fca0675b1694e69b8e431c989343855cbd125d;hpb=bb41be0c967538a1014c87103a3a5d3840ad3e15 diff --git a/Network/HTTP/Lucu/MultipartForm.hs b/Network/HTTP/Lucu/MultipartForm.hs index 882ff76..98699e4 100644 --- a/Network/HTTP/Lucu/MultipartForm.hs +++ b/Network/HTTP/Lucu/MultipartForm.hs @@ -23,7 +23,7 @@ import Control.Applicative.Unicode hiding ((∅)) import Control.Monad.Error (MonadError, throwError) import Control.Monad.Unicode import Data.Ascii (Ascii, CIAscii, AsciiBuilder) -import qualified Data.Ascii as A +import Data.Attempt import Data.Attoparsec import qualified Data.Attoparsec.Lazy as LP import qualified Data.ByteString as BS @@ -33,17 +33,15 @@ import Data.Collections import Data.Convertible.Base import Data.Convertible.Instances.Ascii () import Data.Convertible.Utils +import Data.Default import Data.List (intercalate) import Data.Maybe import Data.Monoid.Unicode import Data.Sequence (Seq) import Data.Text (Text) -import qualified Data.Text as T import Network.HTTP.Lucu.Headers import Network.HTTP.Lucu.MIMEParams -import Network.HTTP.Lucu.MIMEType (MIMEType) -import qualified Network.HTTP.Lucu.MIMEType as MT -import Network.HTTP.Lucu.MIMEType.TH +import Network.HTTP.Lucu.MIMEType import Network.HTTP.Lucu.Parser import Network.HTTP.Lucu.Parser.Http import Network.HTTP.Lucu.Utils @@ -88,8 +86,8 @@ deriveAttempts [ ([t| ContDispo |], [t| Ascii |]) , ([t| ContDispo |], [t| AsciiBuilder |]) ] --- |Parse \"multipart/form-data\" and return either @'Left' err@ or --- @'Right' result@. Note that there are currently the following +-- |Parse \"multipart/form-data\" to a list of @(name, +-- formData)@. Note that there are currently the following -- limitations: -- -- * Multiple files embedded as \"multipart/mixed\" within the @@ -98,9 +96,9 @@ deriveAttempts [ ([t| ContDispo |], [t| Ascii |]) -- * \"Content-Transfer-Encoding\" is always ignored. -- -- * RFC 2388 () says --- that non-ASCII field names are encoded according to the method in --- RFC 2047 (), but they won't --- be decoded. +-- that non-ASCII field names are encoded according to the method +-- in RFC 2047 (), but this +-- function currently doesn't decode them. parseMultipartFormData ∷ Ascii -- ^boundary → LS.ByteString -- ^input → Either String [(Ascii, FormData)] @@ -136,7 +134,7 @@ prologue ∷ Ascii → Parser () prologue boundary = ( (string "--" "prefix") *> - (string (A.toByteString boundary) "boundary") + (string (cs boundary) "boundary") *> pure () ) @@ -171,7 +169,8 @@ parsePart boundary src defaultCType = [mimeType| text/plain |] partHeader ∷ Parser Headers -partHeader = crlf *> headers +{-# INLINE partHeader #-} +partHeader = crlf *> def getContDispo ∷ MonadError String m ⇒ Headers → m ContDispo {-# INLINEABLE getContDispo #-} @@ -180,16 +179,17 @@ getContDispo hdrs Nothing → throwError "Content-Disposition is missing" Just str - → case parseOnly (finishOff contentDisposition) $ A.toByteString str of + → case parseOnly (finishOff contentDisposition) $ cs str of Right d → return d Left err → throwError $ "malformed Content-Disposition: " - ⧺ A.toString str - ⧺ ": " - ⧺ err + ⊕ cs str + ⊕ ": " + ⊕ err contentDisposition ∷ Parser ContDispo +{-# INLINEABLE contentDisposition #-} contentDisposition - = (ContDispo <$> (A.toCIAscii <$> token) ⊛ mimeParams) + = (ContDispo <$> (cs <$> token) ⊛ def) "contentDisposition" @@ -200,19 +200,19 @@ getContType hdrs Nothing → return Nothing Just str - → case parseOnly (finishOff MT.mimeType) $ A.toByteString str of + → case parseOnly (finishOff def) $ cs str of Right d → return $ Just d Left err → throwError $ "malformed Content-Type: " - ⧺ A.toString str - ⧺ ": " - ⧺ err + ⊕ cs str + ⊕ ": " + ⊕ err getBody ∷ MonadError String m ⇒ Ascii → LS.ByteString → m (LS.ByteString, LS.ByteString) {-# INLINEABLE getBody #-} -getBody (("\r\n--" ⊕) ∘ A.toByteString → boundary) src +getBody (("\r\n--" ⊕) ∘ cs → boundary) src = case breakOn boundary src of (before, after) | LS.null after @@ -236,17 +236,16 @@ partToFormPair pt@(Part {..}) return (name, fd) | otherwise = throwError $ "disposition type is not \"form-data\": " - ⧺ A.toString (A.fromCIAscii $ dType ptContDispo) + ⊕ cs (dType ptContDispo) partName ∷ MonadError String m ⇒ Part → m Ascii {-# INLINEABLE partName #-} partName (Part {..}) = case lookup "name" $ dParams ptContDispo of Just name - → case A.fromText name of - Just a → return a - Nothing → throwError $ "Non-ascii part name: " - ⧺ T.unpack name + → case ca name of + Success a → return a + Failure e → throwError $ show e Nothing → throwError $ "form-data without name: " ⊕ convertSuccessVia ((⊥) ∷ Ascii) ptContDispo