Skip to content
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

Fixes redirect loop in serve-static. #761

Merged
merged 1 commit into from
Apr 29, 2024

Conversation

gckzl
Copy link
Contributor

@gckzl gckzl commented Apr 29, 2024

When using serve-static with static_embed and defaults:

Router::with_path("<**>").get(static_embed::().defaults("index.html"));

with a non-root folder with a default file ("index.html"):

├─ index.html
└─ foo/
└─ index.html

trying to GET the "/foo" path results in a redirect loop, with salvo adding an extra "/" after each iteration: "/foo//////////////////".

This is because of the code in embed.rs that tries to redirect from "/foo" to "/foo/":

135 | if embedded_file.is_some() && !req_path.ends_with('/') && !req_path.is_empty() {
136 | redirect_to_dir_url(req.uri(), res);
137 | return;
138 | }

where req_path was built with:

123 | let req_path = format_url_path_safely(&req_path);

but format_url_path_safely() always strips the final slash(es), which means the !req_path.ends_with('/') check always succeeds, and redirect_to_dir_url() is called on req.uri() (not req_path), which still has all its slashes. redirect_to_dir_url() then unconditionally adds another slash, and the loop repeats.

This commit breaks the loop by having format_url_path_safely() keep one final slash if it was already present, so the check on line 135 now works as expected.

When using serve-static with static_embed and defaults:

  Router::with_path("<**>").get(static_embed::<Assets>().defaults("index.html"));

with a non-root folder with a default file ("index.html"):

  ├─ index.html
  └─ foo/
     └─ index.html

trying to GET the "/foo" path results in a redirect loop, with salvo
adding an extra "/" after each iteration: "/foo//////////////////".

This is because of the code in embed.rs that tries to redirect from
"/foo" to "/foo/":

  135 |     if embedded_file.is_some() && !req_path.ends_with('/') && !req_path.is_empty() {
  136 |         redirect_to_dir_url(req.uri(), res);
  137 |         return;
  138 |     }

where req_path was built with:

  123 |  let req_path = format_url_path_safely(&req_path);

but `format_url_path_safely()` always strips the final slash(es), which
means the `!req_path.ends_with('/')` check always succeeds, and
`redirect_to_dir_url()` is called on `req.uri()` (not `req_path`), which
still has all its slashes.  `redirect_to_dir_url()` then unconditionally
adds another slash, and the loop repeats.

This commit breaks the loop by having `format_url_path_safely()` keep
one final slash if it was already present, so the check on line 135 now
works as expected.
@chrislearn chrislearn merged commit 2cc5c06 into salvo-rs:main Apr 29, 2024
@gckzl gckzl deleted the fix-redirect-loop branch April 30, 2024 09:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants