From 295e4d58aa34e885324d4bd9746c095f1b0e9e46 Mon Sep 17 00:00:00 2001 From: yhirose Date: Fri, 29 Nov 2019 17:01:13 -0500 Subject: [PATCH] Fix #276 --- httplib.h | 48 ++++++++++++++++++++++++---------------- test/test.cc | 40 ++++++++++++++++++++++++++++++--- test/www2/dir/index.html | 8 +++++++ test/www2/dir/test.html | 1 + test/www3/dir/index.html | 8 +++++++ test/www3/dir/test.html | 1 + 6 files changed, 84 insertions(+), 22 deletions(-) create mode 100644 test/www2/dir/index.html create mode 100644 test/www2/dir/test.html create mode 100644 test/www3/dir/index.html create mode 100644 test/www3/dir/test.html diff --git a/httplib.h b/httplib.h index 002b874..41fbfb1 100644 --- a/httplib.h +++ b/httplib.h @@ -129,8 +129,9 @@ using socket_t = int; #define INVALID_SOCKET (-1) #endif //_WIN32 -#include +#include #include +#include #include #include #include @@ -145,7 +146,6 @@ using socket_t = int; #include #include #include -#include #ifdef CPPHTTPLIB_OPENSSL_SUPPORT #include @@ -507,7 +507,7 @@ public: Server &Delete(const char *pattern, Handler handler); Server &Options(const char *pattern, Handler handler); - bool set_base_dir(const char *path); + bool set_base_dir(const char *dir, const char *mount_point = nullptr); void set_file_request_handler(Handler handler); void set_error_handler(Handler handler); @@ -570,7 +570,7 @@ private: std::atomic is_running_; std::atomic svr_sock_; - std::string base_dir_; + std::vector> base_dirs_; Handler file_request_handler_; Handlers get_handlers_; Handlers post_handlers_; @@ -2408,10 +2408,13 @@ inline Server &Server::Options(const char *pattern, Handler handler) { return *this; } -inline bool Server::set_base_dir(const char *path) { - if (detail::is_dir(path)) { - base_dir_ = path; - return true; +inline bool Server::set_base_dir(const char *dir, const char *mount_point) { + if (detail::is_dir(dir)) { + std::string mnt = mount_point ? mount_point : "/"; + if (!mnt.empty() && mnt[0] == '/') { + base_dirs_.emplace_back(mnt, dir); + return true; + } } return false; } @@ -2684,21 +2687,28 @@ Server::read_content_with_content_receiver(Stream &strm, bool last_connection, } inline bool Server::handle_file_request(Request &req, Response &res) { - if (!base_dir_.empty() && detail::is_valid_path(req.path)) { - std::string path = base_dir_ + req.path; + for (const auto& kv: base_dirs_) { + const auto& mount_point = kv.first; + const auto& base_dir = kv.second; - if (!path.empty() && path.back() == '/') { path += "index.html"; } + // Prefix match + if (!req.path.find(mount_point)) { + std::string sub_path = "/" + req.path.substr(mount_point.size()); + if (detail::is_valid_path(sub_path)) { + auto path = base_dir + sub_path; + if (path.back() == '/') { path += "index.html"; } - if (detail::is_file(path)) { - detail::read_file(path, res.body); - auto type = detail::find_content_type(path); - if (type) { res.set_header("Content-Type", type); } - res.status = 200; - if (file_request_handler_) { file_request_handler_(req, res); } - return true; + if (detail::is_file(path)) { + detail::read_file(path, res.body); + auto type = detail::find_content_type(path); + if (type) { res.set_header("Content-Type", type); } + res.status = 200; + if (file_request_handler_) { file_request_handler_(req, res); } + return true; + } + } } } - return false; } diff --git a/test/test.cc b/test/test.cc index 5cbd36b..2779e4f 100644 --- a/test/test.cc +++ b/test/test.cc @@ -567,6 +567,7 @@ protected: virtual void SetUp() { svr_.set_base_dir("./www"); + svr_.set_base_dir("./www2", "/mount"); svr_.Get("/hi", [&](const Request & /*req*/, Response &res) { @@ -1003,9 +1004,42 @@ TEST_F(ServerTest, GetMethodOutOfBaseDir2) { EXPECT_EQ(404, res->status); } -TEST_F(ServerTest, InvalidBaseDir) { - EXPECT_EQ(false, svr_.set_base_dir("invalid_dir")); - EXPECT_EQ(true, svr_.set_base_dir(".")); +TEST_F(ServerTest, GetMethodDirMountTest) { + auto res = cli_.Get("/mount/dir/test.html"); + ASSERT_TRUE(res != nullptr); + EXPECT_EQ(200, res->status); + EXPECT_EQ("text/html", res->get_header_value("Content-Type")); + EXPECT_EQ("test.html", res->body); +} + +TEST_F(ServerTest, GetMethodDirMountTestWithDoubleDots) { + auto res = cli_.Get("/mount/dir/../dir/test.html"); + ASSERT_TRUE(res != nullptr); + EXPECT_EQ(200, res->status); + EXPECT_EQ("text/html", res->get_header_value("Content-Type")); + EXPECT_EQ("test.html", res->body); +} + +TEST_F(ServerTest, GetMethodInvalidMountPath) { + auto res = cli_.Get("/mount/dir/../test.html"); + ASSERT_TRUE(res != nullptr); + EXPECT_EQ(404, res->status); +} + +TEST_F(ServerTest, GetMethodOutOfBaseDirMount) { + auto res = cli_.Get("/mount/../www2/dir/test.html"); + ASSERT_TRUE(res != nullptr); + EXPECT_EQ(404, res->status); +} + +TEST_F(ServerTest, GetMethodOutOfBaseDirMount2) { + auto res = cli_.Get("/mount/dir/../../www2/dir/test.html"); + ASSERT_TRUE(res != nullptr); + EXPECT_EQ(404, res->status); +} + +TEST_F(ServerTest, InvalidBaseDirMount) { + EXPECT_EQ(false, svr_.set_base_dir("./www3", "invalid_mount_point")); } TEST_F(ServerTest, EmptyRequest) { diff --git a/test/www2/dir/index.html b/test/www2/dir/index.html new file mode 100644 index 0000000..be3c05f --- /dev/null +++ b/test/www2/dir/index.html @@ -0,0 +1,8 @@ + + + + + Test + hi + + diff --git a/test/www2/dir/test.html b/test/www2/dir/test.html new file mode 100644 index 0000000..6d70cd0 --- /dev/null +++ b/test/www2/dir/test.html @@ -0,0 +1 @@ +test.html \ No newline at end of file diff --git a/test/www3/dir/index.html b/test/www3/dir/index.html new file mode 100644 index 0000000..be3c05f --- /dev/null +++ b/test/www3/dir/index.html @@ -0,0 +1,8 @@ + + + + + Test + hi + + diff --git a/test/www3/dir/test.html b/test/www3/dir/test.html new file mode 100644 index 0000000..6d70cd0 --- /dev/null +++ b/test/www3/dir/test.html @@ -0,0 +1 @@ +test.html \ No newline at end of file