Browse Source

Resolve #1973 (#1976)

* Fix #1973

* Fixed problems with 'Language for non-Unicode programs' setting on Windows

* Fix problems on English locale
yhirose 1 year ago
parent
commit
9dd565b6e3
3 changed files with 54 additions and 8 deletions
  1. 27 4
      httplib.h
  2. 26 4
      test/test.cc
  3. 1 0
      test/www/日本語Dir/日本語File.txt

+ 27 - 4
httplib.h

@@ -2258,13 +2258,33 @@ make_basic_authentication_header(const std::string &username,
 
 
 namespace detail {
 namespace detail {
 
 
+#if defined(_WIN32)
+std::wstring u8string_to_wstring(const char *s) {
+  std::wstring ws;
+  auto len = static_cast<int>(strlen(s));
+  auto wlen = ::MultiByteToWideChar(CP_UTF8, 0, s, len, nullptr, 0);
+  if (wlen > 0) {
+    ws.resize(wlen);
+    wlen = ::MultiByteToWideChar(CP_UTF8, 0, s, len, const_cast<LPWSTR>(reinterpret_cast<LPCWSTR>(ws.data())), wlen);
+    if (wlen != ws.size()) {
+      ws.clear(); 
+    }
+  }
+  return ws;
+}
+#endif
+
 struct FileStat {
 struct FileStat {
   FileStat(const std::string &path);
   FileStat(const std::string &path);
   bool is_file() const;
   bool is_file() const;
   bool is_dir() const;
   bool is_dir() const;
 
 
 private:
 private:
+#if defined(_WIN32)
+  struct _stat st_;
+#else
   struct stat st_;
   struct stat st_;
+#endif
   int ret_ = -1;
   int ret_ = -1;
 };
 };
 
 
@@ -2639,7 +2659,12 @@ inline bool is_valid_path(const std::string &path) {
 }
 }
 
 
 inline FileStat::FileStat(const std::string &path) {
 inline FileStat::FileStat(const std::string &path) {
+#if defined(_WIN32)
+  auto wpath = u8string_to_wstring(path.c_str());
+  ret_ = _wstat(wpath.c_str(), &st_);
+#else
   ret_ = stat(path.c_str(), &st_);
   ret_ = stat(path.c_str(), &st_);
+#endif
 }
 }
 inline bool FileStat::is_file() const {
 inline bool FileStat::is_file() const {
   return ret_ >= 0 && S_ISREG(st_.st_mode);
   return ret_ >= 0 && S_ISREG(st_.st_mode);
@@ -2909,10 +2934,8 @@ inline bool mmap::open(const char *path) {
   close();
   close();
 
 
 #if defined(_WIN32)
 #if defined(_WIN32)
-  std::wstring wpath;
-  for (size_t i = 0; i < strlen(path); i++) {
-    wpath += path[i];
-  }
+  auto wpath = u8string_to_wstring(path);
+  if (wpath.empty()) { return false; }
 
 
 #if _WIN32_WINNT >= _WIN32_WINNT_WIN8
 #if _WIN32_WINNT >= _WIN32_WINNT_WIN8
   hFile_ = ::CreateFile2(wpath.c_str(), GENERIC_READ, FILE_SHARE_READ,
   hFile_ = ::CreateFile2(wpath.c_str(), GENERIC_READ, FILE_SHARE_READ,

+ 26 - 4
test/test.cc

@@ -1,3 +1,4 @@
+// NOTE: This file should be saved as UTF-8 w/ BOM
 #include <httplib.h>
 #include <httplib.h>
 #include <signal.h>
 #include <signal.h>
 
 
@@ -241,7 +242,7 @@ TEST(DecodeURLTest, PercentCharacter) {
       detail::decode_url(
       detail::decode_url(
           R"(descrip=Gastos%20%C3%A1%C3%A9%C3%AD%C3%B3%C3%BA%C3%B1%C3%91%206)",
           R"(descrip=Gastos%20%C3%A1%C3%A9%C3%AD%C3%B3%C3%BA%C3%B1%C3%91%206)",
           false),
           false),
-      R"(descrip=Gastos áéíóúñÑ 6)");
+      u8"descrip=Gastos áéíóúñÑ 6");
 }
 }
 
 
 TEST(DecodeURLTest, PercentCharacterNUL) {
 TEST(DecodeURLTest, PercentCharacterNUL) {
@@ -267,9 +268,9 @@ TEST(EncodeQueryParamTest, ParseReservedCharactersTest) {
 }
 }
 
 
 TEST(EncodeQueryParamTest, TestUTF8Characters) {
 TEST(EncodeQueryParamTest, TestUTF8Characters) {
-  string chineseCharacters = "中国語";
-  string russianCharacters = "дом";
-  string brazilianCharacters = "óculos";
+  string chineseCharacters = u8"中国語";
+  string russianCharacters = u8"дом";
+  string brazilianCharacters = u8"óculos";
 
 
   EXPECT_EQ(detail::encode_query_param(chineseCharacters),
   EXPECT_EQ(detail::encode_query_param(chineseCharacters),
             "%E4%B8%AD%E5%9B%BD%E8%AA%9E");
             "%E4%B8%AD%E5%9B%BD%E8%AA%9E");
@@ -5271,6 +5272,27 @@ TEST(MountTest, Redicect) {
   EXPECT_EQ(StatusCode::OK_200, res->status);
   EXPECT_EQ(StatusCode::OK_200, res->status);
 }
 }
 
 
+TEST(MountTest, MultibytesPathName) {
+  Server svr;
+
+  auto listen_thread = std::thread([&svr]() { svr.listen("localhost", PORT); });
+  auto se = detail::scope_exit([&] {
+    svr.stop();
+    listen_thread.join();
+    ASSERT_FALSE(svr.is_running());
+  });
+
+  svr.set_mount_point("/", "./www");
+  svr.wait_until_ready();
+
+  Client cli("localhost", PORT);
+
+  auto res = cli.Get(u8"/日本語Dir/日本語File.txt");
+  ASSERT_TRUE(res);
+  EXPECT_EQ(StatusCode::OK_200, res->status);
+  EXPECT_EQ(u8"日本語コンテンツ", res->body);
+}
+
 TEST(KeepAliveTest, ReadTimeout) {
 TEST(KeepAliveTest, ReadTimeout) {
   Server svr;
   Server svr;
 
 

+ 1 - 0
test/www/日本語Dir/日本語File.txt

@@ -0,0 +1 @@
+日本語コンテンツ