[Haskell-cafe] HTTP and file upload
Adam Smyczek
adam.smyczek at gmail.com
Fri Apr 18 16:22:00 EDT 2008
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
>
> 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 at haskell.org
>> http://www.haskell.org/mailman/listinfo/haskell-cafe
>
> _______________________________________________
> Haskell-Cafe mailing list
> Haskell-Cafe at haskell.org
> http://www.haskell.org/mailman/listinfo/haskell-cafe
More information about the Haskell-Cafe
mailing list