
Is form based file upload supported in HTTP module (HTTP-3001.0.4)? Adam

Yes http://hpaste.org/6990 Am 14.04.2008 um 19:07 schrieb Adam Smyczek:
Is form based file upload supported in HTTP module (HTTP-3001.0.4)?
Adam
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe

Thanks for the snippet. Sorry, but my question was somehow mis-formulated. I was looking for a client-side implementation how to upload a file to any server using Haskell (mainly using the Browser module from HTTP package). Going through the Browser.hs source code a little, I and came up with the following implementation and your hpaste helped me to test it. The following code is just a small wrapper around the Browser module that adds support for multipart/form-data content type. It's more or less a prototype but works fine for me. Looking forward to suggestions how to improve it. Be gentle, it's beginner code :) Adam ------------------------------------------------------------------------ ----- -- | -- Wrapper around Network.Browser module with -- support for multipart/form-data content type -- ------------------------------------------------------------------------ ----- module ReviewBoard.Browser ( formToRequest, FormVar(..), Form(..) ) where import qualified Network.Browser as HB import Network.HTTP import Network.URI import Data.Char import Control.Monad.Writer import System.Random -- | Form to request for typed form variables -- formToRequest :: Form -> HB.BrowserAction Request formToRequest (Form m u vs) -- Use multipart/form-data content type when -- the form contains at least one FileUpload variable | or (map isFileUpload vs) = do bnd <- HB.ioAction mkBoundary (_, enc) <- HB.ioAction $ runWriterT $ multipartUrlEncodeVars bnd vs let body = concat enc return Request { rqMethod=POST , rqHeaders= [ Header HdrContentType $ "multipart/form-data; boundary=" ++ bnd, Header HdrContentLength (show . length $ body) ] , rqBody= body , rqURI=u } -- Otherwise fall back to Network.Browser | otherwise = return $ HB.formToRequest (HB.Form m u $ map toHVar vs) where -- Convert typed variables to Network.Browser variables toHVar (TextField n v) = (n, v) toHVar (FileUpload n f) = (n, f) toHVar (Checkbox n v) = (n, map toLower $ show v) -- Is file upload isFileUpload (FileUpload _ _) = True isFileUpload _ = False -- Create random boundary string mkBoundary = do rand <- randomRIO (100000000000 :: Integer, 999999999999) return $ "--------------------" ++ show rand -- | Encode variables, add boundary header and footer -- multipartUrlEncodeVars :: String -> [FormVar] -> RqsWriter () multipartUrlEncodeVars bnd vs = do mapM (\v -> tell ["--", bnd, "\r\n"] >> encodeVar v) vs tell ["--", bnd, "--", "\r\n"] -- | Encode variable based on type -- encodeVar :: FormVar -> RqsWriter () encodeVar (TextField n v) = defaultEncVar n v encodeVar (Checkbox n True) = defaultEncVar n "true" encodeVar (Checkbox n False) = defaultEncVar n "false" encodeVar (FileUpload n f) = do fc <- liftIO $ readFile f tell [ "Content-Disposition: form-data; name=\"", n, "\"; filename=\"", f, "\"\r\n" , "Content-Type: text/plain\r\n" -- TODO: add support for different types , "\r\n" , fc , "\r\n"] -- | Default encode method for name/value as string -- defaultEncVar :: String -> String -> RqsWriter () defaultEncVar n v = tell [ "Content-Disposition: form-data; name=\"", n, "\"\r\n" , "\r\n" , v , "\r\n"] -- ------------------------------------------------------------------------ --- -- Types -- | Request writer -- type RqsWriter a = WriterT [String] IO a -- | Typed form vars -- data FormVar = TextField String String | FileUpload String FilePath | Checkbox String Bool deriving Show -- | And the typed form -- data Form = Form RequestMethod URI [FormVar] On Apr 15, 2008, at 1:38 AM, Adrian Neumann wrote:
Yes
Am 14.04.2008 um 19:07 schrieb Adam Smyczek:
Is form based file upload supported in HTTP module (HTTP-3001.0.4)?
Adam
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe

On Fri, 2008-04-18 at 13:22 -0700, Adam Smyczek wrote:
The following code is just a small wrapper around the Browser module that adds support for multipart/form-data content type. It's more or less a prototype but works fine for me. Looking forward to suggestions how to improve it. Be gentle, it's beginner code :)
You may like to compare it with the code that 'cabal upload' uses for uploading tarballs to hackage: http://darcs.haskell.org/cabal-install/Hackage/Upload.hs I don't claim our code is perfect, you may have some suggestions for us! :-) Duncan
participants (3)
-
Adam Smyczek
-
Adrian Neumann
-
Duncan Coutts