X-Git-Url: http://git.cielonegro.org/gitweb.cgi?a=blobdiff_plain;f=Network%2FHTTP%2FLucu%2FMultipartForm.hs;h=c4631300e9efae3b3d14ac57917597ef685032fd;hb=70bf5bd248aa426ca4e410b3fb9a0529354aedaf;hp=8903d7f88d3c4736faccf4aaacf6c3d8361c98cd;hpb=3d017dd65ddede9a11c5b7a34a91e04340e67bc4;p=Lucu.git diff --git a/Network/HTTP/Lucu/MultipartForm.hs b/Network/HTTP/Lucu/MultipartForm.hs index 8903d7f..c463130 100644 --- a/Network/HTTP/Lucu/MultipartForm.hs +++ b/Network/HTTP/Lucu/MultipartForm.hs @@ -1,5 +1,10 @@ +{-# LANGUAGE + UnboxedTuples + , UnicodeSyntax + #-} module Network.HTTP.Lucu.MultipartForm - ( multipartFormP + ( FormData(..) + , multipartFormP ) where @@ -15,7 +20,15 @@ import Network.HTTP.Lucu.Response import Network.HTTP.Lucu.Utils -data Part = Part Headers String +data Part = Part Headers L8.ByteString + +-- |This data type represents a form value and possibly an uploaded +-- file name. +data FormData + = FormData { + fdFileName :: Maybe String + , fdContent :: L8.ByteString + } instance HasHeaders Part where getHeaders (Part hs _) = hs @@ -40,40 +53,81 @@ instance Show ContDispo where value -multipartFormP :: String -> Parser [(String, String)] +multipartFormP :: String -> Parser [(String, FormData)] multipartFormP boundary = do parts <- many (partP boundary) - string "--" - string boundary - string "--" - crlf + _ <- string "--" + _ <- string boundary + _ <- string "--" + _ <- crlf eof - return $ map partToPair parts + return $ map partToFormPair parts partP :: String -> Parser Part partP boundary - = do string "--" - string boundary - crlf -- バウンダリの末尾に -- が付いてゐたらここで fail する。 + = do _ <- string "--" + _ <- string boundary + _ <- crlf -- バウンダリの末尾に -- が付いてゐたらここで fail する。 hs <- headersP body <- bodyP boundary return $ Part hs body -bodyP :: String -> Parser String +bodyP :: String -> Parser L8.ByteString bodyP boundary - = do body <- many $ - do notFollowedBy $ do crlf - string "--" - string boundary + = do body <- manyChar $ + do notFollowedBy $ ( crlf >> + string "--" >> + string boundary ) anyChar - crlf + _ <- crlf return body -partToPair :: Part -> (String, String) -partToPair part@(Part _ body) +partToFormPair :: Part -> (String, FormData) +partToFormPair part@(Part _ body) + = let name = partName part + fname = partFileName part + fd = FormData { + fdFileName = fname + , fdContent = body + } + in (name, fd) + +partName :: Part -> String +partName = getName' . getContDispoFormData + where + getName' :: ContDispo -> String + getName' dispo@(ContDispo _ dParams) + = case find ((== "name") . map toLower . fst) dParams of + Just (_, name) -> name + Nothing + -> abortPurely BadRequest [] + (Just $ "form-data without name: " ++ show dispo) + + +partFileName :: Part -> Maybe String +partFileName = getFileName' . getContDispoFormData + where + getFileName' :: ContDispo -> Maybe String + getFileName' (ContDispo _ dParams) + = do (_, fileName) <- find ((== "filename") . map toLower . fst) dParams + return fileName + +getContDispoFormData :: Part -> ContDispo +getContDispoFormData part + = let dispo@(ContDispo dType _) = getContDispo part + in + if map toLower dType == "form-data" then + dispo + else + abortPurely BadRequest [] + (Just $ "Content-Disposition type is not form-data: " ++ dType) + + +getContDispo :: Part -> ContDispo +getContDispo part = case getHeader (C8.pack "Content-Disposition") part of Nothing -> abortPurely BadRequest [] @@ -81,22 +135,10 @@ partToPair part@(Part _ body) Just dispoStr -> case parse contDispoP (L8.fromChunks [dispoStr]) of (# Success dispo, _ #) - -> (getName dispo, body) + -> dispo (# _, _ #) -> abortPurely BadRequest [] (Just $ "Unparsable Content-Disposition: " ++ C8.unpack dispoStr) - where - getName :: ContDispo -> String - getName dispo@(ContDispo dType dParams) - | map toLower dType == "form-data" - = case find ((== "name") . map toLower . fst) dParams of - Just (_, name) -> name - Nothing - -> abortPurely BadRequest [] - (Just $ "form-data without name: " ++ show dispo) - | otherwise - = abortPurely BadRequest [] - (Just $ "Content-Disposition type is not form-data: " ++ dType) contDispoP :: Parser ContDispo @@ -105,10 +147,10 @@ contDispoP = do dispoType <- token return $ ContDispo dispoType params where paramP :: Parser (String, String) - paramP = do many lws - char ';' - many lws - name <- token - char '=' + paramP = do _ <- many lws + _ <- char ';' + _ <- many lws + name <- token + _ <- char '=' value <- token <|> quotedStr return (name, value)