Serve files without mapping them on POSIX

Files have been read with pread() since 44658e6, so the mapping went
unused. Keep only the descriptor, open it close-on-exec and without
waiting on a FIFO, and accept only a regular file, so that a device is
no longer served as an empty body.
This commit is contained in:
yhirose committed 2026-10-16 21:38:40 -04:00
1 parent a10338a6ee
commit 35342285a0
2 files changed
+61 -44

No files matched your search

+46 -10
View File
@@ -12195,24 +12195,60 @@ TEST(MmapTest, OpenWhileFileHeldForWriting) {
detail::mmap m(path);
ASSERT_TRUE(m.is_open());
EXPECT_EQ(strlen(content), m.size());
EXPECT_EQ(0, std::memcmp(content, m.data(), strlen(content)));
char buf[8];
ASSERT_EQ(strlen(content), m.read(0, buf, sizeof(buf)));
EXPECT_EQ(0, std::memcmp(content, buf, strlen(content)));
}
#endif
#ifndef _WIN32
// A failed ::mmap() must not be reported as an open mapping, otherwise data()
// hands the caller the MAP_FAILED sentinel. A directory is the easiest way to
// reach it, since ::open() and fstat() succeed for one but ::mmap() doesn't.
TEST(MmapTest, FailedMappingIsNotOpen) {
const char *path = "./mmap_failed_mapping_test_dir";
// A directory or a device has no size to serve.
TEST(MmapTest, OnlyRegularFilesAreOpened) {
const char *path = "./mmap_not_regular_test_dir";
ASSERT_EQ(0, ::mkdir(path, 0755));
auto dir_cleanup = detail::scope_exit([&] { ::rmdir(path); });
for (auto p : {path, "/dev/null"}) {
detail::mmap m(p);
EXPECT_FALSE(m.is_open()) << p;
EXPECT_EQ(0U, m.size()) << p;
}
Server svr;
svr.Get("/null", [](const Request & /*req*/, Response &res) {
res.set_file_content("/dev/null");
});
auto port = svr.bind_to_any_port(HOST);
thread t = thread([&] { svr.listen_after_bind(); });
auto se = detail::scope_exit([&] {
svr.stop();
t.join();
});
svr.wait_until_ready();
auto res = Client(HOST, port).Get("/null");
ASSERT_TRUE(res);
EXPECT_EQ(StatusCode::NotFound_404, res->status);
}
#endif
#ifdef __linux__
// Nothing of the file stays mapped, where a truncation would raise SIGBUS.
TEST(MmapTest, FileIsNotMapped) {
const char *path = "mmap_not_mapped_test.txt";
{
std::ofstream f(path, std::ios::binary);
f << "hello";
}
auto file_cleanup = detail::scope_exit([&] { std::remove(path); });
detail::mmap m(path);
EXPECT_FALSE(m.is_open());
EXPECT_EQ(0U, m.size());
EXPECT_NE(static_cast<const void *>(m.data()),
static_cast<const void *>(MAP_FAILED));
ASSERT_TRUE(m.is_open());
std::ifstream maps("/proc/self/maps");
std::string mappings((std::istreambuf_iterator<char>(maps)),
std::istreambuf_iterator<char>());
EXPECT_EQ(std::string::npos, mappings.find(path));
}
#endif