diff --git a/httplib.h b/httplib.h index 7cf8c454..d69c0079 100644 --- a/httplib.h +++ b/httplib.h @@ -5319,8 +5319,9 @@ inline bool mmap::open(const char *path) { auto wpath = u8string_to_wstring(path); if (wpath.empty()) { return false; } - hFile_ = ::CreateFile2(wpath.c_str(), GENERIC_READ, FILE_SHARE_READ, - OPEN_EXISTING, NULL); + hFile_ = + ::CreateFile2(wpath.c_str(), GENERIC_READ, + FILE_SHARE_READ | FILE_SHARE_WRITE, OPEN_EXISTING, NULL); if (hFile_ == INVALID_HANDLE_VALUE) { return false; } diff --git a/test/test.cc b/test/test.cc index c708e79f..4a781986 100644 --- a/test/test.cc +++ b/test/test.cc @@ -7939,6 +7939,31 @@ TEST(MountTest, MultibytesPathName) { EXPECT_EQ(U8("日本語コンテンツ"), res->body); } +#ifdef _WIN32 +// Issue #2435: mmap::open() must succeed even when another handle holds +// the file open for writing (e.g. an active log file). +TEST(MmapTest, OpenWhileFileHeldForWriting) { + const char *path = "mmap_concurrent_writer_test.txt"; + const char *content = "hello"; + + { + std::ofstream f(path, std::ios::binary); + f.write(content, static_cast(strlen(content))); + } + auto file_cleanup = detail::scope_exit([&] { std::remove(path); }); + + HANDLE writer = ::CreateFileA(path, GENERIC_WRITE, FILE_SHARE_READ, NULL, + OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + ASSERT_NE(INVALID_HANDLE_VALUE, writer); + auto handle_cleanup = detail::scope_exit([&] { ::CloseHandle(writer); }); + + 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))); +} +#endif + TEST(KeepAliveTest, ReadTimeout) { Server svr;