Redirect a directory request with a relative Location (#2630)

* Redirect a directory request with a relative Location

The trailing-slash redirect used the request path as-is, so a path
starting with "//" produced a Location that clients read as a
network-path reference to another host. Name only the last segment,
percent-encoded and prefixed with "./", so the target always resolves
against the request URL, whatever the mount point or any prefix a
proxy put in front of it.

* Shorten the relative redirect comment
This commit is contained in:
yhirose authored and GitHub committed 2026-10-14 16:00:03 -04:00
1 parent 924b5cecf0
commit 2c918f27ee
2 files changed
+13 -2

No files matched your search

+5 -1
View File
@@ -13869,7 +13869,11 @@ inline bool Server::handle_file_request(Request &req, Response &res) {
detail::FileStat stat(path);
if (stat.is_dir()) {
res.set_redirect(req.path + "/", StatusCode::MovedPermanently_301);
// Relative, so "//dir" cannot name another host; "./" keeps a ':'
// in the name from reading as a scheme.
auto name = req.path.substr(req.path.rfind('/') + 1);
res.set_redirect("./" + encode_path_component(name) + "/",
StatusCode::MovedPermanently_301);
return true;
}
+8 -1
View File
@@ -6664,7 +6664,14 @@ TEST_F(ServerTest, GetMethodDirMountWithoutTrailingSlash) {
auto res = cli_.Get("/mount/dir");
ASSERT_TRUE(res) << "Error: " << to_string(res.error());
EXPECT_EQ(StatusCode::MovedPermanently_301, res->status);
EXPECT_EQ("/mount/dir/", res->get_header_value("Location"));
EXPECT_EQ("./dir/", res->get_header_value("Location"));
}
TEST_F(ServerTest, GetMethodDirWithLeadingDoubleSlash) {
auto res = cli_.Get("//dir");
ASSERT_TRUE(res) << "Error: " << to_string(res.error());
EXPECT_EQ(StatusCode::MovedPermanently_301, res->status);
EXPECT_EQ("./dir/", res->get_header_value("Location"));
}
TEST_F(ServerTest, PostMethod303) {