mirror of
https://github.com/yhirose/cpp-httplib
synced 2024-11-21 14:29:10 -07:00
Fix #276
This commit is contained in:
parent
448de6a9c6
commit
295e4d58aa
6 changed files with 84 additions and 22 deletions
32
httplib.h
32
httplib.h
|
@ -129,8 +129,9 @@ using socket_t = int;
|
|||
#define INVALID_SOCKET (-1)
|
||||
#endif //_WIN32
|
||||
|
||||
#include <cassert>
|
||||
#include <array>
|
||||
#include <atomic>
|
||||
#include <cassert>
|
||||
#include <condition_variable>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
|
@ -145,7 +146,6 @@ using socket_t = int;
|
|||
#include <string>
|
||||
#include <sys/stat.h>
|
||||
#include <thread>
|
||||
#include <array>
|
||||
|
||||
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
|
||||
#include <openssl/err.h>
|
||||
|
@ -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<bool> is_running_;
|
||||
std::atomic<socket_t> svr_sock_;
|
||||
std::string base_dir_;
|
||||
std::vector<std::pair<std::string, std::string>> base_dirs_;
|
||||
Handler file_request_handler_;
|
||||
Handlers get_handlers_;
|
||||
Handlers post_handlers_;
|
||||
|
@ -2408,11 +2408,14 @@ 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;
|
||||
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,10 +2687,16 @@ 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);
|
||||
|
@ -2698,7 +2707,8 @@ inline bool Server::handle_file_request(Request &req, Response &res) {
|
|||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
40
test/test.cc
40
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) {
|
||||
|
|
8
test/www2/dir/index.html
Normal file
8
test/www2/dir/index.html
Normal file
|
@ -0,0 +1,8 @@
|
|||
<html>
|
||||
<head>
|
||||
</head>
|
||||
<body>
|
||||
<a href="/dir/test.html">Test</a>
|
||||
<a href="/hi">hi</a>
|
||||
</body>
|
||||
</html>
|
1
test/www2/dir/test.html
Normal file
1
test/www2/dir/test.html
Normal file
|
@ -0,0 +1 @@
|
|||
test.html
|
8
test/www3/dir/index.html
Normal file
8
test/www3/dir/index.html
Normal file
|
@ -0,0 +1,8 @@
|
|||
<html>
|
||||
<head>
|
||||
</head>
|
||||
<body>
|
||||
<a href="/dir/test.html">Test</a>
|
||||
<a href="/hi">hi</a>
|
||||
</body>
|
||||
</html>
|
1
test/www3/dir/test.html
Normal file
1
test/www3/dir/test.html
Normal file
|
@ -0,0 +1 @@
|
|||
test.html
|
Loading…
Reference in a new issue