iron / router

Router middleware for the Iron web framework.
165 stars 74 forks source link

Not allowing a trailing slash is a bad idea #82

Open bvinc opened 9 years ago

bvinc commented 9 years ago

A trailing slash in a URL is important. A URL with a trailing slash is a completely different URL from a URL without a trailing slash. For example, relative links are treated differently.

The router should allow users to treat these URLs differently.

More information: https://cdivilly.wordpress.com/2014/03/11/why-trailing-slashes-on-uris-are-important/

bvinc commented 9 years ago

Separately, the 301 Moved responses are using absolute URLs, but those URLs are wrong in the case that the router is under a mount. For example, when requesting http://localhost/mount/route/, I get redirected to http://localhost/route.

Hopefully, we can agree to remove the 301 Moved responses entirely and this won't be an issue.

bvinc commented 9 years ago

Looking at how other routers handle this issue, the general consensus is that:

reem commented 9 years ago

Sorry for not posting on this for so long. I think you are right, and the current behavior is incorrect, at least as a default. We should move to implement something along the lines of what you outlined in your last post.

reem commented 9 years ago

This should be fixed by #84, @bvinc does that patch address your concerns?

freiguy1 commented 9 years ago

I'm now redirected to a url without the trailing slash, however if my router is behind a mount, the mounted part of the url disappears.

For instance:

let mut router = Router::new();
router.get("/bar", ...somehandler...);

let mut mount = Mount::new();
mount.mount("/foo", router);

If I navigate to http://url.com/foo/bar/, I'll get redirected to http://url.com/bar.

reem commented 9 years ago

Hmm, this is because router doesn't current respect mount's OriginalUrl extension... I will have to think about this.

dbrgn commented 8 years ago

I have the same problem. This is the proof-of-error:

extern crate iron;
extern crate router;
extern crate mount;

use iron::{Iron, Request, Response, IronResult, status};
use router::Router;
use mount::Mount;
use std::net::Ipv4Addr;

fn handler(_: &mut Request) -> IronResult<Response> {
    println!("Handled request");
    Ok(Response::with((status::Ok, "Ok")))
}

fn main() {
    let mut router = Router::new();
    router.get("/", handler);
    router.get("/foo", handler);

    let mut mount = Mount::new();
    mount.mount("/api/v1/", router);

    Iron::new(mount).http((Ipv4Addr::new(127, 0, 0, 1), 8080)).unwrap();
}

A request to /api/v1/foo works, but a request to /api/v1/foo/ results in a redirect to /. The mount is ignored.

This issue should probably be labelled as bug.

Regarding the trailing slash in general, I think it should be configurable whether or not it should redirect. The config options could be something like this:

pub enum TrailingSlashConfig {
    // When the trailing slash is missing and no route matches, append the trailing slash
    Require,
    // When a trailing slash is present and no route matches, remove the trailing slash
    Strip,
    // Handle present and absent trailing slashes with the same handler, no redirects
    Ignore,
    // Handle present and absent trailing slashes as two different endpoints
    Discern,
}