How do I upload a file to my web server from a browser? The server is written in Haskell, using Scotty. Here is what I have tried:
Server:
{-# LANGUAGE OverloadedStrings #-}
module Main where
import qualified Data.ByteString.Lazy as BL
import qualified Web.Scotty as Scot
import qualified Control.Monad.IO.Class as Cm
import qualified Data.Digest.Pure.SHA as Dps
dir :: String
dir = "/home/t/fileUpload/"
main :: IO ()
main =
Scot.scotty 3000 $ do
Scot.get "/" $ Scot.file $ dir ++ "index.html"
Scot.post "/upload" $ do
contents <- Scot.body
let fileName = Dps.showDigest $ Dps.sha256 contents
Cm.liftIO $ BL.writeFile (dir ++ fileName) contents
index.html:
<!DOCTYPE html>
<html lang="en-US">
<head>
<meta charset="utf-8">
</head>
<body>
<form enctype="multipart/form-data" action="/upload" method="post">
<input type="file"> <input type="submit" value="Submit"></form>
</body>
</html>
When I visit http://localhost:3000 in my browser, I click on the Browse button, choose a file, and click on Submit. Then it takes me to a blank page called http://localhost:3000/upload, and a file gets saved to "/home/t/fileUpload/somelonghash". That is fine, but the problem is that the saved file only contains something like this:
-----------------------------172368540915173703481121109126--
which is not the contents of the original file.
-----------------------------172368540915173703481121109126--
That's a multipart/form-data
field boundary. If this is all you get, it means the form didn't contain any data to post to the server. I expect you can get your file to show up by giving it a name:
<input type="file" name="myfile">
Even if you do this, you'll still get boundaries and headers in your response body, alongside your actual file contents. What you need to do is parse the multipart/form-data
and extract the file contents from there. I think Scotty will do this for you if you use the files
function, rather than using body
.