Skip to content

fixes #1409: internal server error with two slashes at the end of the URL #1410

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jun 5, 2021
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 28 additions & 1 deletion src/web/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ use iron::{
};
use page::TemplateData;
use postgres::Client;
use router::NoRoute;
use router::{NoRoute, TrailingSlash};
use semver::{Version, VersionReq};
use serde::Serialize;
use std::{borrow::Cow, fmt, net::SocketAddr, sync::Arc};
Expand Down Expand Up @@ -167,6 +167,18 @@ impl Handler for MainHandler {
}
}

fn pass_iron_errors_with_redirect(e: IronError) -> IronResult<Response> {
// in some cases the iron router will return a redirect as an `IronError`.
// Here we convert these into an `Ok(Response)`.
if e.error.downcast_ref::<TrailingSlash>().is_some()
|| e.response.status == Some(status::MovedPermanently)
{
Ok(e.response)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why will there still be a response if there's an error? Also, why does this also handle MovedPermanently? That seems like a change in behavior.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure I follow.

In our own code we do redirects by returning an Ok(Response). Our code expects this and passes this through.

For this specific case (URL without slash at the end has a match, see the iron source), iron returns an IronError(Response).

Since for us the redirect is fine, and not an error, I want to convert this.

( of course I could be missing something)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, I think I see - we have our own error handler on top of iron's built-in error handlers. And our error handler expects to recognized every possible error, that's what the last or_else on line 197 is doing. Since iron has its own built-in error handlers, some of its errors (but not ours) will actually be valid HTTP responses that we can serve without changes.

} else {
Err(e)
}
}

// This is kind of a mess.
//
// Almost all files should be served through the `router_handler`; eventually
Expand All @@ -183,6 +195,7 @@ impl Handler for MainHandler {
self.shared_resource_handler
.handle(req)
.or_else(|e| if_404(e, || self.router_handler.handle(req)))
.or_else(pass_iron_errors_with_redirect)
.or_else(|e| {
let err = if let Some(err) = e.error.downcast_ref::<error::Nope>() {
*err
Expand Down Expand Up @@ -740,6 +753,20 @@ mod test {
})
}

#[test]
fn double_slash_does_redirect_and_remove_slash() {
wrapper(|env| {
env.fake_release()
.name("bat")
.version("0.2.0")
.create()
.unwrap();
let web = env.frontend();
assert_redirect("/bat//", "/bat/0.2.0/bat/", web)?;
Ok(())
})
}

#[test]
fn binary_docs_redirect_to_crate() {
wrapper(|env| {
Expand Down