title: Efficient large file upload with Yesod
body: <p>I want to implement large file upload with my Yesod application. Right now I have:</p>
  
  <pre><code>module Handler.File where
  
  import Import
  
  import System.Random
  import System.FilePath
  import Control.Monad
  import qualified Data.ByteString.Lazy as LBS
  import qualified Data.Text.Encoding
  
  -- upload
  
  uploadDirectory :: FilePath -- FIXME: make this configurable
  uploadDirectory = "incoming"
  
  randomFileName :: IO FilePath
  randomFileName = do
    fname'base &lt;- replicateM 20 (randomRIO ('a','z'))
    let fname = uploadDirectory &lt;/&gt; fname'base &lt;.&gt; "bin"
    return fname
  
  fileUploadForm :: Form (FileInfo, Textarea)
  fileUploadForm = renderDivs $ (,)
      &lt;$&gt; fileAFormReq "Choose a file"
      &lt;*&gt; areq textareaField "What's on the file?" Nothing
  
  getFileNewR :: Handler RepHtml
  getFileNewR = do
    (formWidget, formEnctype) &lt;- generateFormPost fileUploadForm
    defaultLayout $ do
         setTitle "Upload new file."
         $(widgetFile "file-new")
  
  postFileNewR :: Handler RepHtml
  postFileNewR = do
    user &lt;- requireAuth
    ((result, formWidget), formEnctype) &lt;- runFormPost fileUploadForm
    case result of
      FormSuccess (fi,info) -&gt; do
                   fn &lt;- liftIO randomFileName
                   liftIO (LBS.writeFile fn (fileContent fi))
                   let newFile = File (entityKey user) fn info (fileName fi) (fileContentType fi)
                   fid &lt;- runDB $ insert newFile
                   redirect (FileViewR fid)
      _ -&gt; return ()
  
    defaultLayout $ do
         setTitle "Upload new file."
         $(widgetFile "file-new")
  </code></pre>
  
  <p>It is mostly fine, except few issues:</p>
  
  <ol>
  <li><p>Maximum size of a file is around 2 megabytes. I have a fix, but is it right way to do this? My fix is overriding default implementation of maximumContentLength method in Yesod instance for my app, like this:</p>
  
  <p>maximumContentLength _ (Just (FileNewR _)) = 2 * 1024 * 1024 * 1024 -- 2 gigabytes
  maximumContentLength _ _ = 2 * 1024 * 1024 -- 2 megabytes</p></li>
  <li><p>The amount of memory used is equal to the size of a file. This is really suboptimal. I would like to use tempFileBackEnd from <a href="http://hackage.haskell.org/packages/archive/wai-extra/1.2.0.4/doc/html/Network-Wai-Parse.html" rel="noreferrer">http://hackage.haskell.org/packages/archive/wai-extra/1.2.0.4/doc/html/Network-Wai-Parse.html</a> but I have no idea how to actually wire that into my request and make it work with forms logic (hidden _token field etc.).</p></li>
  <li><p>The upload is 'single shot': any examples of how to make it work with Flash/Html5 based uploaders that show progress to user?</p></li>
  </ol>