Skip to content

Commit 5b397d4

Browse files
committed
Fix more CRLF injection problems.
1 parent f977558 commit 5b397d4

File tree

2 files changed

+63
-21
lines changed

2 files changed

+63
-21
lines changed

httplib.h

Lines changed: 17 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -5925,8 +5925,8 @@ inline void Server::apply_ranges(const Request &req, Response &res,
59255925
res.headers.erase(it);
59265926
}
59275927

5928-
res.headers.emplace("Content-Type",
5929-
"multipart/byteranges; boundary=" + boundary);
5928+
res.set_header("Content-Type",
5929+
"multipart/byteranges; boundary=" + boundary);
59305930
}
59315931

59325932
auto type = detail::encoding_type(req, res);
@@ -6616,32 +6616,32 @@ inline bool ClientImpl::write_request(Stream &strm, Request &req,
66166616
// Prepare additional headers
66176617
if (close_connection) {
66186618
if (!req.has_header("Connection")) {
6619-
req.headers.emplace("Connection", "close");
6619+
req.set_header("Connection", "close");
66206620
}
66216621
}
66226622

66236623
if (!req.has_header("Host")) {
66246624
if (is_ssl()) {
66256625
if (port_ == 443) {
6626-
req.headers.emplace("Host", host_);
6626+
req.set_header("Host", host_);
66276627
} else {
6628-
req.headers.emplace("Host", host_and_port_);
6628+
req.set_header("Host", host_and_port_);
66296629
}
66306630
} else {
66316631
if (port_ == 80) {
6632-
req.headers.emplace("Host", host_);
6632+
req.set_header("Host", host_);
66336633
} else {
6634-
req.headers.emplace("Host", host_and_port_);
6634+
req.set_header("Host", host_and_port_);
66356635
}
66366636
}
66376637
}
66386638

6639-
if (!req.has_header("Accept")) { req.headers.emplace("Accept", "*/*"); }
6639+
if (!req.has_header("Accept")) { req.set_header("Accept", "*/*"); }
66406640

66416641
#ifndef CPPHTTPLIB_NO_DEFAULT_USER_AGENT
66426642
if (!req.has_header("User-Agent")) {
66436643
auto agent = std::string("cpp-httplib/") + CPPHTTPLIB_VERSION;
6644-
req.headers.emplace("User-Agent", agent);
6644+
req.set_header("User-Agent", agent);
66456645
}
66466646
#endif
66476647

@@ -6650,23 +6650,23 @@ inline bool ClientImpl::write_request(Stream &strm, Request &req,
66506650
if (!req.is_chunked_content_provider_) {
66516651
if (!req.has_header("Content-Length")) {
66526652
auto length = std::to_string(req.content_length_);
6653-
req.headers.emplace("Content-Length", length);
6653+
req.set_header("Content-Length", length);
66546654
}
66556655
}
66566656
} else {
66576657
if (req.method == "POST" || req.method == "PUT" ||
66586658
req.method == "PATCH") {
6659-
req.headers.emplace("Content-Length", "0");
6659+
req.set_header("Content-Length", "0");
66606660
}
66616661
}
66626662
} else {
66636663
if (!req.has_header("Content-Type")) {
6664-
req.headers.emplace("Content-Type", "text/plain");
6664+
req.set_header("Content-Type", "text/plain");
66656665
}
66666666

66676667
if (!req.has_header("Content-Length")) {
66686668
auto length = std::to_string(req.body.size());
6669-
req.headers.emplace("Content-Length", length);
6669+
req.set_header("Content-Length", length);
66706670
}
66716671
}
66726672

@@ -6734,12 +6734,10 @@ inline std::unique_ptr<Response> ClientImpl::send_with_content_provider(
67346734
ContentProvider content_provider,
67356735
ContentProviderWithoutLength content_provider_without_length,
67366736
const std::string &content_type, Error &error) {
6737-
if (!content_type.empty()) {
6738-
req.headers.emplace("Content-Type", content_type);
6739-
}
6737+
if (!content_type.empty()) { req.set_header("Content-Type", content_type); }
67406738

67416739
#ifdef CPPHTTPLIB_ZLIB_SUPPORT
6742-
if (compress_) { req.headers.emplace("Content-Encoding", "gzip"); }
6740+
if (compress_) { req.set_header("Content-Encoding", "gzip"); }
67436741
#endif
67446742

67456743
#ifdef CPPHTTPLIB_ZLIB_SUPPORT
@@ -6800,7 +6798,7 @@ inline std::unique_ptr<Response> ClientImpl::send_with_content_provider(
68006798
req.content_provider_ = detail::ContentProviderAdapter(
68016799
std::move(content_provider_without_length));
68026800
req.is_chunked_content_provider_ = true;
6803-
req.headers.emplace("Transfer-Encoding", "chunked");
6801+
req.set_header("Transfer-Encoding", "chunked");
68046802
} else {
68056803
req.body.assign(body, content_length);
68066804
;
@@ -7423,9 +7421,7 @@ inline Result ClientImpl::Delete(const std::string &path,
74237421
req.headers = headers;
74247422
req.path = path;
74257423

7426-
if (!content_type.empty()) {
7427-
req.headers.emplace("Content-Type", content_type);
7428-
}
7424+
if (!content_type.empty()) { req.set_header("Content-Type", content_type); }
74297425
req.body.assign(body, content_length);
74307426

74317427
return send_(std::move(req));

test/test.cc

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6116,3 +6116,49 @@ TEST(RedirectTest, RedirectToUrlWithQueryParameters) {
61166116
EXPECT_EQ("val&key2=val2", res->body);
61176117
}
61186118
}
6119+
6120+
TEST(VulnerabilityTest, CRLFInjection) {
6121+
Server svr;
6122+
6123+
svr.Post("/test1", [](const Request &/*req*/, Response &res) {
6124+
res.set_content("Hello 1", "text/plain");
6125+
});
6126+
6127+
svr.Delete("/test2", [](const Request &/*req*/, Response &res) {
6128+
res.set_content("Hello 2", "text/plain");
6129+
});
6130+
6131+
svr.Put("/test3", [](const Request &/*req*/, Response &res) {
6132+
res.set_content("Hello 3", "text/plain");
6133+
});
6134+
6135+
svr.Patch("/test4", [](const Request &/*req*/, Response &res) {
6136+
res.set_content("Hello 4", "text/plain");
6137+
});
6138+
6139+
svr.set_logger([](const Request &req, const Response & /*res*/) {
6140+
for (const auto &x : req.headers) {
6141+
auto key = x.first;
6142+
EXPECT_STRNE("evil", key.c_str());
6143+
}
6144+
});
6145+
6146+
auto thread = std::thread([&]() { svr.listen(HOST, PORT); });
6147+
auto se = detail::scope_exit([&] {
6148+
svr.stop();
6149+
thread.join();
6150+
ASSERT_FALSE(svr.is_running());
6151+
});
6152+
6153+
std::this_thread::sleep_for(std::chrono::seconds(1));
6154+
6155+
{
6156+
Client cli(HOST, PORT);
6157+
6158+
cli.Post("/test1", "A=B",
6159+
"application/x-www-form-urlencoded\r\nevil: hello1");
6160+
cli.Delete("/test2", "A=B", "text/plain\r\nevil: hello2");
6161+
cli.Put("/test3", "text", "text/plain\r\nevil: hello3");
6162+
cli.Patch("/test4", "content", "text/plain\r\nevil: hello4");
6163+
}
6164+
}

0 commit comments

Comments
 (0)