2021-04-08 09:14:59 +03:00
..
2021-03-27 09:19:06 +03:00
2021-03-25 01:59:19 +03:00
2021-04-08 09:14:59 +03:00
2021-04-08 09:14:59 +03:00

d-form


With the session middleware from example b-session, we can build a secure form:

let show_form ?message request =
  <html>
    <body>
%     begin match message with
%     | None -> ()
%     | Some message ->
        <p>You entered: <b><%s message %>!</b></p>
%     end;
      <%s! Dream.form_tag ~action:"/" request %>
        <input name="message" autofocus>
      </form>
    </body>
  </html>

let () =
  Dream.run
  @@ Dream.logger
  @@ Dream.memory_sessions
  @@ Dream.router [

    Dream.get  "/"
      (fun request ->
        Dream.respond (show_form request));

    Dream.post "/"
      (fun request ->
        match%lwt Dream.form request with
        | `Ok ["message", message] ->
          Dream.respond (show_form ~message request)
        | _ ->
          Dream.empty `Bad_Request);

  ]
  @@ Dream.not_found
$ dune exec --root . ./form.exe

We didn't write a literal <form> tag in the template. Instead, we used Dream.form_tag to generate the tag. Dream.form_tag also snuck in a hidden <input> field containing a CSRF token:

<form method="POST" action="/">
  <input name="dream.csrf" type="hidden" value="j8vjZ6...">

  <!-- The rest we actually wrote ourselves in the template! -->
  <input name="message" autofocus>
</form>

This hidden dream.csrf field helps to prevent CSRF attacks attacks against the form.

Dream.form expects dream.csrf and checks it. If there is anything wrong with the token, Dream.form will return a value other than `Ok _.


The form fields carried inside `Ok _ are returned in sorted order, so you can reliably pattern-match on them.

The bad token results, like `Expired _, also carry the form fields. You can add handling for them to recover. For example, if you receive an expired form, you may want to resend it with some of the fields pre-filled to received values, so that the user can try again quickly.

However, do not send back any sensitive data, because any result other than `Ok _ might indicate an attack in progress. That said, `Expired _ and `Wrong_session _ do often occur during normal user activity. The other constructors typically correspond to bugs or attacks, only.


Next steps:

  • e-json receives and sends JSON.
  • f-static serves static files from a local directory.

Up to the tutorial index