aantron/dream

Dream.form seems to be failing to extract two fields and is replying with bad request

slipalong opened this issue · 2 comments

Hi am trying to use Dream for a simple website and am getting stuck with a simple login page.
browser is posting form with a username and password fields but the match is failing and issues a 400.
`

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

@@ Dream.router [

Dream.get  "/"
  (fun request ->
    Dream.log "Index page triggered so rendering login";
    Dream.html (Login_form.render request)
    );

Dream.post "/login" (fun request ->
match%lwt Dream.form request with
|Ok ["username", username; "password", password] -> ( match Dream.session_field request "username" with | None -> let%lwt () = Dream.invalidate_session request in let%lwt () = Dream.set_session_field request "username" username in let%lwt () = Dream.set_session_field request "password" password in let message = Printf.sprintf "Got Username: %s and password: %s!" (Dream.html_escape username) (Dream.html_escape password) in Dream.html (Home_page.render ~message:message request) | Some username -> let message = Printf.sprintf "%s!" (Dream.html_escape username) in Dream.html (Home_page.render ~message:message request) ); | _ -> Dream.log "Failed to parse login form"; Dream.empty Bad_Request);

]`

Workaround: List of form items need to be in reverse order to match.

Hi! The issue is not that the forms have to be listed in reverse order, but that Dream sorts the form fields in alphabetical order when they are returned from Dream.form. This is because browsers, and especially scripts, can transmit the form fields back to the Web app in an arbitrary and unpredictable order, regardless of the order you put them in the HTML. I've clarified the docs of Dream.form to try to explain that better.