Fixed #3
This commit is contained in:
parent
a90e9b8a6a
commit
90f9cd40f9
49
httplib.h
49
httplib.h
@ -393,16 +393,55 @@ inline socket_t create_client_socket(const char* host, int port)
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool is_file(const std::string& s)
|
inline bool is_file(const std::string& path)
|
||||||
{
|
{
|
||||||
struct stat st;
|
struct stat st;
|
||||||
return stat(s.c_str(), &st) >= 0 && S_ISREG(st.st_mode);
|
return stat(path.c_str(), &st) >= 0 && S_ISREG(st.st_mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool is_dir(const std::string& s)
|
inline bool is_dir(const std::string& path)
|
||||||
{
|
{
|
||||||
struct stat st;
|
struct stat st;
|
||||||
return stat(s.c_str(), &st) >= 0 && S_ISDIR(st.st_mode);
|
return stat(path.c_str(), &st) >= 0 && S_ISDIR(st.st_mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool is_valid_path(const std::string& path) {
|
||||||
|
size_t level = 0;
|
||||||
|
size_t i = 0;
|
||||||
|
|
||||||
|
// Skip slash
|
||||||
|
while (i < path.size() && path[i] == '/') {
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (i < path.size()) {
|
||||||
|
// Read component
|
||||||
|
auto beg = i;
|
||||||
|
while (i < path.size() && path[i] != '/') {
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto len = i - beg;
|
||||||
|
assert(len > 0);
|
||||||
|
|
||||||
|
if (!path.compare(beg, len, ".")) {
|
||||||
|
;
|
||||||
|
} else if (!path.compare(beg, len, "..")) {
|
||||||
|
if (level == 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
level--;
|
||||||
|
} else {
|
||||||
|
level++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skip slash
|
||||||
|
while (i < path.size() && path[i] == '/') {
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void read_file(const std::string& path, std::string& out)
|
inline void read_file(const std::string& path, std::string& out)
|
||||||
@ -942,7 +981,7 @@ inline bool Server::read_request_line(Stream& strm, Request& req)
|
|||||||
|
|
||||||
inline bool Server::handle_file_request(Request& req, Response& res)
|
inline bool Server::handle_file_request(Request& req, Response& res)
|
||||||
{
|
{
|
||||||
if (!base_dir_.empty()) {
|
if (!base_dir_.empty() && detail::is_valid_path(req.path)) {
|
||||||
std::string path = base_dir_ + req.path;
|
std::string path = base_dir_ + req.path;
|
||||||
|
|
||||||
if (!path.empty() && path.back() == '/') {
|
if (!path.empty() && path.back() == '/') {
|
||||||
|
30
test/test.cc
30
test/test.cc
@ -293,6 +293,36 @@ TEST_F(ServerTest, GetMethodDirTest)
|
|||||||
EXPECT_EQ("test.html", res->body);
|
EXPECT_EQ("test.html", res->body);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(ServerTest, GetMethodDirTestWithDoubleDots)
|
||||||
|
{
|
||||||
|
auto res = cli_.get("/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, GetMethodInvalidPath)
|
||||||
|
{
|
||||||
|
auto res = cli_.get("/dir/../test.html");
|
||||||
|
ASSERT_TRUE(res != nullptr);
|
||||||
|
EXPECT_EQ(404, res->status);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ServerTest, GetMethodOutOfBaseDir)
|
||||||
|
{
|
||||||
|
auto res = cli_.get("/../www/dir/test.html");
|
||||||
|
ASSERT_TRUE(res != nullptr);
|
||||||
|
EXPECT_EQ(404, res->status);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ServerTest, GetMethodOutOfBaseDir2)
|
||||||
|
{
|
||||||
|
auto res = cli_.get("/dir/../../www/dir/test.html");
|
||||||
|
ASSERT_TRUE(res != nullptr);
|
||||||
|
EXPECT_EQ(404, res->status);
|
||||||
|
}
|
||||||
|
|
||||||
TEST_F(ServerTest, InvalidBaseDir)
|
TEST_F(ServerTest, InvalidBaseDir)
|
||||||
{
|
{
|
||||||
EXPECT_EQ(false, svr_.set_base_dir("invalid_dir"));
|
EXPECT_EQ(false, svr_.set_base_dir("invalid_dir"));
|
||||||
|
Loading…
x
Reference in New Issue
Block a user