Compare commits

..

3 Commits

Author SHA1 Message Date
yhirose 3409c00e6f Fixed warnings 2023-05-27 01:10:21 +09:00
yhirose f8ef5fab64 Release v0.12.4 2023-05-27 00:57:43 +09:00
yhirose 5b397d455d Fix more CRLF injection problems. 2023-05-22 22:56:16 +09:00
2 changed files with 71 additions and 28 deletions
+18 -22
View File
@@ -8,7 +8,7 @@
#ifndef CPPHTTPLIB_HTTPLIB_H
#define CPPHTTPLIB_HTTPLIB_H
#define CPPHTTPLIB_VERSION "0.12.3"
#define CPPHTTPLIB_VERSION "0.12.4"
/*
* Configuration
@@ -5925,8 +5925,8 @@ inline void Server::apply_ranges(const Request &req, Response &res,
res.headers.erase(it);
}
res.headers.emplace("Content-Type",
"multipart/byteranges; boundary=" + boundary);
res.set_header("Content-Type",
"multipart/byteranges; boundary=" + boundary);
}
auto type = detail::encoding_type(req, res);
@@ -6616,32 +6616,32 @@ inline bool ClientImpl::write_request(Stream &strm, Request &req,
// Prepare additional headers
if (close_connection) {
if (!req.has_header("Connection")) {
req.headers.emplace("Connection", "close");
req.set_header("Connection", "close");
}
}
if (!req.has_header("Host")) {
if (is_ssl()) {
if (port_ == 443) {
req.headers.emplace("Host", host_);
req.set_header("Host", host_);
} else {
req.headers.emplace("Host", host_and_port_);
req.set_header("Host", host_and_port_);
}
} else {
if (port_ == 80) {
req.headers.emplace("Host", host_);
req.set_header("Host", host_);
} else {
req.headers.emplace("Host", host_and_port_);
req.set_header("Host", host_and_port_);
}
}
}
if (!req.has_header("Accept")) { req.headers.emplace("Accept", "*/*"); }
if (!req.has_header("Accept")) { req.set_header("Accept", "*/*"); }
#ifndef CPPHTTPLIB_NO_DEFAULT_USER_AGENT
if (!req.has_header("User-Agent")) {
auto agent = std::string("cpp-httplib/") + CPPHTTPLIB_VERSION;
req.headers.emplace("User-Agent", agent);
req.set_header("User-Agent", agent);
}
#endif
@@ -6650,23 +6650,23 @@ inline bool ClientImpl::write_request(Stream &strm, Request &req,
if (!req.is_chunked_content_provider_) {
if (!req.has_header("Content-Length")) {
auto length = std::to_string(req.content_length_);
req.headers.emplace("Content-Length", length);
req.set_header("Content-Length", length);
}
}
} else {
if (req.method == "POST" || req.method == "PUT" ||
req.method == "PATCH") {
req.headers.emplace("Content-Length", "0");
req.set_header("Content-Length", "0");
}
}
} else {
if (!req.has_header("Content-Type")) {
req.headers.emplace("Content-Type", "text/plain");
req.set_header("Content-Type", "text/plain");
}
if (!req.has_header("Content-Length")) {
auto length = std::to_string(req.body.size());
req.headers.emplace("Content-Length", length);
req.set_header("Content-Length", length);
}
}
@@ -6734,12 +6734,10 @@ inline std::unique_ptr<Response> ClientImpl::send_with_content_provider(
ContentProvider content_provider,
ContentProviderWithoutLength content_provider_without_length,
const std::string &content_type, Error &error) {
if (!content_type.empty()) {
req.headers.emplace("Content-Type", content_type);
}
if (!content_type.empty()) { req.set_header("Content-Type", content_type); }
#ifdef CPPHTTPLIB_ZLIB_SUPPORT
if (compress_) { req.headers.emplace("Content-Encoding", "gzip"); }
if (compress_) { req.set_header("Content-Encoding", "gzip"); }
#endif
#ifdef CPPHTTPLIB_ZLIB_SUPPORT
@@ -6800,7 +6798,7 @@ inline std::unique_ptr<Response> ClientImpl::send_with_content_provider(
req.content_provider_ = detail::ContentProviderAdapter(
std::move(content_provider_without_length));
req.is_chunked_content_provider_ = true;
req.headers.emplace("Transfer-Encoding", "chunked");
req.set_header("Transfer-Encoding", "chunked");
} else {
req.body.assign(body, content_length);
;
@@ -7423,9 +7421,7 @@ inline Result ClientImpl::Delete(const std::string &path,
req.headers = headers;
req.path = path;
if (!content_type.empty()) {
req.headers.emplace("Content-Type", content_type);
}
if (!content_type.empty()) { req.set_header("Content-Type", content_type); }
req.body.assign(body, content_length);
return send_(std::move(req));
+53 -6
View File
@@ -1843,21 +1843,21 @@ protected:
{
const auto &text_value = req.get_file_values("text");
EXPECT_EQ(text_value.size(), 1);
EXPECT_EQ(1u, text_value.size());
auto &text = text_value[0];
EXPECT_TRUE(text.filename.empty());
EXPECT_EQ("default text", text.content);
}
{
const auto &text1_values = req.get_file_values("multi_text1");
EXPECT_EQ(text1_values.size(), 2);
EXPECT_EQ(2u, text1_values.size());
EXPECT_EQ("aaaaa", text1_values[0].content);
EXPECT_EQ("bbbbb", text1_values[1].content);
}
{
const auto &file1_values = req.get_file_values("multi_file1");
EXPECT_EQ(file1_values.size(), 2);
EXPECT_EQ(2u, file1_values.size());
auto file1 = file1_values[0];
EXPECT_EQ(file1.filename, "hello.txt");
EXPECT_EQ(file1.content_type, "text/plain");
@@ -3921,9 +3921,10 @@ TEST(ServerStopTest, StopServerWithChunkedTransmission) {
res.set_header("Cache-Control", "no-cache");
res.set_chunked_content_provider("text/event-stream", [](size_t offset,
DataSink &sink) {
char buffer[27];
auto size = static_cast<size_t>(sprintf(buffer, "data:%zd\n\n", offset));
auto ret = sink.write(buffer, size);
std::string s = "data:";
s += std::to_string(offset);
s += "\n\n";
auto ret = sink.write(s.data(), s.size());
EXPECT_TRUE(ret);
std::this_thread::sleep_for(std::chrono::seconds(1));
return true;
@@ -6116,3 +6117,49 @@ TEST(RedirectTest, RedirectToUrlWithQueryParameters) {
EXPECT_EQ("val&key2=val2", res->body);
}
}
TEST(VulnerabilityTest, CRLFInjection) {
Server svr;
svr.Post("/test1", [](const Request &/*req*/, Response &res) {
res.set_content("Hello 1", "text/plain");
});
svr.Delete("/test2", [](const Request &/*req*/, Response &res) {
res.set_content("Hello 2", "text/plain");
});
svr.Put("/test3", [](const Request &/*req*/, Response &res) {
res.set_content("Hello 3", "text/plain");
});
svr.Patch("/test4", [](const Request &/*req*/, Response &res) {
res.set_content("Hello 4", "text/plain");
});
svr.set_logger([](const Request &req, const Response & /*res*/) {
for (const auto &x : req.headers) {
auto key = x.first;
EXPECT_STRNE("evil", key.c_str());
}
});
auto thread = std::thread([&]() { svr.listen(HOST, PORT); });
auto se = detail::scope_exit([&] {
svr.stop();
thread.join();
ASSERT_FALSE(svr.is_running());
});
std::this_thread::sleep_for(std::chrono::seconds(1));
{
Client cli(HOST, PORT);
cli.Post("/test1", "A=B",
"application/x-www-form-urlencoded\r\nevil: hello1");
cli.Delete("/test2", "A=B", "text/plain\r\nevil: hello2");
cli.Put("/test3", "text", "text/plain\r\nevil: hello3");
cli.Patch("/test4", "content", "text/plain\r\nevil: hello4");
}
}