Skip to content

Commit

Permalink
remove trailing slash redirects
Browse files Browse the repository at this point in the history
  • Loading branch information
ibraheemdev committed Feb 3, 2024
1 parent 7766d45 commit f7cd626
Show file tree
Hide file tree
Showing 4 changed files with 201 additions and 269 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ in under 200 nanoseconds, an order of magnitude faster than most other routers.

```text
Compare Routers/matchit
time: [197.57 ns 198.74 ns 199.83 ns]
time: [175.96 ns 176.39 ns 176.84 ns]
Compare Routers/actix
time: [26.805 us 26.811 us 26.816 us]
Expand Down
32 changes: 1 addition & 31 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,16 +86,6 @@ impl InsertError {
/// router.insert("/home", "Welcome!")?;
/// router.insert("/blog/", "Our blog.")?;
///
/// // a route exists without the trailing slash
/// if let Err(err) = router.at("/home/") {
/// assert_eq!(err, MatchError::ExtraTrailingSlash);
/// }
///
/// // a route exists with a trailing slash
/// if let Err(err) = router.at("/blog") {
/// assert_eq!(err, MatchError::MissingTrailingSlash);
/// }
///
/// // no routes match
/// if let Err(err) = router.at("/foobar") {
/// assert_eq!(err, MatchError::NotFound);
Expand All @@ -104,33 +94,13 @@ impl InsertError {
/// # }
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum MatchError {

Check warning on line 96 in src/error.rs

View workflow job for this annotation

GitHub Actions / Clippy Lints

item name ends with its containing module's name
/// The path was missing a trailing slash.
MissingTrailingSlash,
/// The path had an extra trailing slash.
ExtraTrailingSlash,
/// No matching route was found.
NotFound,
}

impl MatchError {
pub(crate) fn unsure(full_path: &[u8]) -> Self {
if full_path[full_path.len() - 1] == b'/' {
MatchError::ExtraTrailingSlash
} else {
MatchError::MissingTrailingSlash
}
}
}

impl fmt::Display for MatchError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let msg = match self {
MatchError::MissingTrailingSlash => "match error: expected trailing slash",
MatchError::ExtraTrailingSlash => "match error: found extra trailing slash",
MatchError::NotFound => "match error: route not found",
};

write!(f, "{}", msg)
write!(f, "matching route not found")
}
}

Expand Down
78 changes: 5 additions & 73 deletions src/tree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -363,14 +363,6 @@ impl<T> Node<T> {
});
}

// child won't match because of an extra trailing slash
if path == b"/"
&& current.children[i].prefix != b"/"
&& current.value.is_some()
{
return Err(MatchError::ExtraTrailingSlash);
}

// continue with the child node
current = &current.children[i];
continue 'walk;
Expand All @@ -379,15 +371,8 @@ impl<T> Node<T> {

// we didn't find a match and there are no children with wildcards, there is no match
if !current.wild_child {
// extra trailing slash
if path == b"/" && current.value.is_some() {
return Err(MatchError::ExtraTrailingSlash);
}

// try backtracking
if path != b"/" {
try_backtrack!();
}
try_backtrack!();

// nothing found
return Err(MatchError::NotFound);
Expand All @@ -404,14 +389,6 @@ impl<T> Node<T> {
let (param, rest) = path.split_at(i);

if let [child] = current.children.as_slice() {
// child won't match because of an extra trailing slash
if rest == b"/"
&& child.prefix != b"/"
&& current.value.is_some()
{
return Err(MatchError::ExtraTrailingSlash);
}

// store the parameter value
params.push(&current.prefix[1..], param);

Expand All @@ -422,16 +399,8 @@ impl<T> Node<T> {
continue 'walk;
}

// this node has no children yet the path has more segments...
// either the path has an extra trailing slash or there is no match
if path.len() == i + 1 {
return Err(MatchError::ExtraTrailingSlash);
}

// try backtracking
if path != b"/" {
try_backtrack!();
}
try_backtrack!();

return Err(MatchError::NotFound);
}
Expand All @@ -450,22 +419,8 @@ impl<T> Node<T> {
return Ok((value, params));
}

// check the child node in case the path is missing a trailing slash
if let [child] = current.children.as_slice() {
current = child;

if (current.prefix == b"/" && current.value.is_some())
|| (current.prefix.is_empty()
&& current.indices == b"/")
{
return Err(MatchError::MissingTrailingSlash);
}

// no match, try backtracking
if path != b"/" {
try_backtrack!();
}
}
// no match, try backtracking
try_backtrack!();

// this node doesn't have the value, no match
return Err(MatchError::NotFound);
Expand Down Expand Up @@ -506,34 +461,11 @@ impl<T> Node<T> {
// nope, try backtracking
try_backtrack!();

// TODO: does this *always* means there is an extra trailing slash?
if path == b"/" && current.wild_child && current.node_type != NodeType::Root {
return Err(MatchError::unsure(full_path));
}

if !backtracking {
// check if the path is missing a trailing slash
if let Some(i) = current.indices.iter().position(|&c| c == b'/') {
current = &current.children[i];

if current.prefix.len() == 1 && current.value.is_some() {
return Err(MatchError::MissingTrailingSlash);
}
}
}

return Err(MatchError::NotFound);
}

// nothing matches, check for a missing trailing slash
if current.prefix.split_last() == Some((&b'/', path)) && current.value.is_some() {
return Err(MatchError::MissingTrailingSlash);
}

// last chance, try backtracking
if path != b"/" {
try_backtrack!();
}
try_backtrack!();

return Err(MatchError::NotFound);
}
Expand Down
Loading

0 comments on commit f7cd626

Please sign in to comment.