Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# Environment
language: cpp
os:
- linux
- osx

# Compiler selection
Expand Down
31 changes: 21 additions & 10 deletions httplib.h
Original file line number Diff line number Diff line change
Expand Up @@ -528,6 +528,8 @@ class Server {
Server &Options(const char *pattern, Handler handler);

bool set_base_dir(const char *dir, const char *mount_point = nullptr);
void set_file_extension_and_mimetype_mapping(const char *ext,
const char *mime);
void set_file_request_handler(Handler handler);

void set_error_handler(Handler handler);
Expand Down Expand Up @@ -597,6 +599,7 @@ class Server {
std::atomic<bool> is_running_;
std::atomic<socket_t> svr_sock_;
std::vector<std::pair<std::string, std::string>> base_dirs_;
std::map<std::string, std::string> file_extension_and_mimetype_map_;
Handler file_request_handler_;
Handlers get_handlers_;
Handlers post_handlers_;
Expand Down Expand Up @@ -1526,8 +1529,14 @@ inline std::string get_remote_addr(socket_t sock) {
return std::string();
}

inline const char *find_content_type(const std::string &path) {
inline const char *
find_content_type(const std::string &path,
const std::map<std::string, std::string> &user_data) {
auto ext = file_extension(path);

auto it = user_data.find(ext);
if (it != user_data.end()) { return it->second.c_str(); }

if (ext == "txt") {
return "text/plain";
} else if (ext == "html" || ext == "htm") {
Expand All @@ -1550,6 +1559,8 @@ inline const char *find_content_type(const std::string &path) {
return "application/pdf";
} else if (ext == "js") {
return "application/javascript";
} else if (ext == "wasm") {
return "application/wasm";
} else if (ext == "xml") {
return "application/xml";
} else if (ext == "xhtml") {
Expand Down Expand Up @@ -1967,7 +1978,7 @@ inline std::string encode_url(const std::string &s) {
case '\n': result += "%0A"; break;
case '\'': result += "%27"; break;
case ',': result += "%2C"; break;
case ':': result += "%3A"; break;
// case ':': result += "%3A"; break; // ok? probably...
case ';': result += "%3B"; break;
default:
auto c = static_cast<uint8_t>(s[i]);
Expand Down Expand Up @@ -2860,6 +2871,11 @@ inline bool Server::set_base_dir(const char *dir, const char *mount_point) {
return false;
}

inline void Server::set_file_extension_and_mimetype_mapping(const char *ext,
const char *mime) {
file_extension_and_mimetype_map_[ext] = mime;
}

inline void Server::set_file_request_handler(Handler handler) {
file_request_handler_ = std::move(handler);
}
Expand Down Expand Up @@ -3178,7 +3194,8 @@ inline bool Server::handle_file_request(Request &req, Response &res) {

if (detail::is_file(path)) {
detail::read_file(path, res.body);
auto type = detail::find_content_type(path);
auto type =
detail::find_content_type(path, file_extension_and_mimetype_map_);
if (type) { res.set_header("Content-Type", type); }
res.status = 200;
if (file_request_handler_) { file_request_handler_(req, res); }
Expand Down Expand Up @@ -3666,13 +3683,7 @@ inline bool Client::write_request(Stream &strm, const Request &req,
BufferStream bstrm;

// Request line
const static std::regex re(
R"(^((?:[^:/?#]+://)?(?:[^/?#]*)?)?([^?#]*(?:\?[^#]*)?(?:#.*)?))");

std::smatch m;
if (!regex_match(req.path, m, re)) { return false; }

auto path = m[1].str() + detail::encode_url(m[2].str());
const auto &path = detail::encode_url(req.path);

bstrm.write_format("%s %s HTTP/1.1\r\n", req.method.c_str(), path.c_str());

Expand Down
9 changes: 9 additions & 0 deletions test/test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -647,6 +647,7 @@ class ServerTest : public ::testing::Test {
virtual void SetUp() {
svr_.set_base_dir("./www");
svr_.set_base_dir("./www2", "/mount");
svr_.set_file_extension_and_mimetype_mapping("abcde", "text/abcde");

svr_.Get("/hi",
[&](const Request & /*req*/, Response &res) {
Expand Down Expand Up @@ -1161,6 +1162,14 @@ TEST_F(ServerTest, GetMethodOutOfBaseDirMount2) {
EXPECT_EQ(404, res->status);
}

TEST_F(ServerTest, UserDefinedMIMETypeMapping) {
auto res = cli_.Get("/dir/test.abcde");
ASSERT_TRUE(res != nullptr);
EXPECT_EQ(200, res->status);
EXPECT_EQ("text/abcde", res->get_header_value("Content-Type"));
EXPECT_EQ("abcde\n", res->body);
}

TEST_F(ServerTest, InvalidBaseDirMount) {
EXPECT_EQ(false, svr_.set_base_dir("./www3", "invalid_mount_point"));
}
Expand Down
1 change: 1 addition & 0 deletions test/www/dir/test.abcde
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
abcde