g-upload
This example shows an upload form at http://localhost:8080, which allows sending multiple files. When they are sent, the example responds with a page listing their file sizes:
let home request =
<html>
<body>
<%s! Dream.form_tag ~action:"/" ~enctype:`Multipart_form_data request %>
<input name="files" type="file" multiple>
<button>Submit!</button>
</form>
</body>
</html>
let report files =
<html>
<body>
% files |> List.iter begin fun (name, content) ->
<p><%s name %>: <%i String.length content %> bytes</p>
% end;
</body>
</html>
let () =
Dream.run
@@ Dream.logger
@@ Dream.memory_sessions
@@ Dream.router [
Dream.get "/" (fun request ->
Dream.respond (home request));
Dream.post "/" (fun request ->
match%lwt Dream.multipart request with
| `Ok ["files", `Files files] -> Dream.respond (report files)
| _ -> Dream.empty `Bad_Request);
]
@@ Dream.not_found
$ dune exec --root . ./upload.exe
The page shown after uploading looks like this:
foo.png, 663959 bytes
bar.png, 1807 bytes
This example uses
Dream.multipart (named
after Content-Type: multipart/form-data).
Dream.multipart receives
entire files into strings. Size limits will be added in one of the early alphas.
However, this is only good for rare, small uploads, such as user avatars, or for
prototyping.
For more heavy usage, see
Dream.upload for
streaming file uploads.
Security
Dream.multipart behaves just
like Dream.form when it comes to
CSRF protection.
See example d-form. We still use
Dream.form_tag to generate
the form in the template. The only difference is that we now pass it
~enctype:`Multipart_form_data to make its output look like this:
<form method="POST" action="/" enctype="multipart/form-data">
<input name="dream.csrf" type="hidden" value="...">
<!-- Our fields -->
<input name="files" type="file" multiple>
<button>Submit!</button>
</form>
By contrast with
Dream.multipart,
Dream.upload offers no
built-in CSRF protection at all at present. You can, however, still use
Dream.form_tag, and manually
call
Dream.verify_csrf_token
when you stream a dream.csrf field. You'll then have to decide what to do
about files already received.
Next steps: