3

I've created the following login form and accompanying template:

main.rs

#[macro_use]
extern crate nickel;
extern crate mustache;
extern crate rustc_serialize;

use std::collections::HashMap;
use nickel::{Nickel, MediaType, HttpRouter};
use nickel::status::StatusCode;

fn main() {
    let mut server = Nickel::new();
    let mut router = Nickel::router();

    router.get("/", middleware!(|request, mut response| {
        response.set(StatusCode::Ok);
        response.set(MediaType::Html);
        return response.send_file("assets/login.tpl");
    }));

    router.post("/login", middleware!(|request, mut response| {
        response.set(StatusCode::Ok);
        response.set(MediaType::Html);

        let mut data: HashMap<&str, &str> = HashMap::new();
        data.insert("error", "hello");
        return response.render("assets/login.tpl", &data);
    }));

    server.utilize(router);
    server.listen("127.0.0.1:6767");
}

assets/login.tpl

<html lang="en">
    <head>
        <meta charset="utf8"/>
    </head>
    <body>
        <h1>Login</h1>
        <form method="post" action="login">
            <label for="email">Email</label>
            <input type="email" name="email"/>
            <br/>
            <label for="password">Password</label>
            <input type="password" name="password"/>
            <br/>
            <button type="submit">Login</button><br/>
            <a href="/register">Register</a>
        </form>
        {{error}}
    </body>
</html>

When I submit the form the first time, I see the "hello" message. If I submit the form again, I see "Not Found".

I can't figure out where the problem is.

tshepang
  • 12,111
  • 21
  • 91
  • 136
menawi
  • 399
  • 3
  • 13

1 Answers1

4

The issue is that you're sending POST data and it's not getting read, which bleeds into the next request (due to keepalive).

To fix, you can either ensure the body of the POST gets read, or add Connection: Close to the response headers to prevent keepalive.

FWIW: This is a known issue in hyper, but nickel should add it's own solution to prevent confusion here. If you want to follow updates on this, please subscribe to the issue Shepmaster logged on Github.

Rym
  • 650
  • 4
  • 16
  • I'm trying to do what you suggested by adding `response.set(Connection::close())` but when Cargo tries to compile hyper, it crashes because it can't find openssl.h. – menawi Apr 06 '16 at 17:29
  • What platform are you on? If you don't want ssl support, you might want to change your hyper dependency in your Cargo.toml file to something like `[dependencies.hyper] default-features = false version = "0.6" # or 0.8 if you're on that ` – Rym Apr 06 '16 at 20:47
  • Closing the connection solved my problem. Is there a cleaner way of writing this: `response.headers_mut().set_raw("Connection",vec![b"close".to_vec()]);` – menawi Apr 07 '16 at 18:35
  • You can use [`set`](http://docs.nickel.rs/nickel/struct.Response.html#method.set), e.g. `response.set(Connection::close())` where `Connection` is imported form `hyper::header` – Rym Apr 07 '16 at 21:55
  • I tried that, it complained that `Connection` didn't implement the trait `Modifier` even though I had nickel imported. – menawi Apr 08 '16 at 06:45
  • That sounds like an issue of the hyper version being different from that of the hyper version used by nickel. You will need to lock the versions in your Cargo.toml to compatible versions. If you're using nickel 0.7 then you should use hyper 0.6, if you're on nickel 0.8 then you can use hyper 0.8. – Rym Apr 09 '16 at 23:46