Skip to content

Commit 85327e1

Browse files
committed
Fix #425
1 parent ed8efea commit 85327e1

File tree

2 files changed

+63
-6
lines changed

2 files changed

+63
-6
lines changed

httplib.h

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2524,6 +2524,17 @@ inline bool expect_content(const Request &req) {
25242524
return false;
25252525
}
25262526

2527+
inline bool has_crlf(const char* s) {
2528+
auto p = s;
2529+
while (*p) {
2530+
if (*p == '\r' || *p == '\n') {
2531+
return true;
2532+
}
2533+
p++;
2534+
}
2535+
return false;
2536+
}
2537+
25272538
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
25282539
template <typename CTX, typename Init, typename Update, typename Final>
25292540
inline std::string message_digest(const std::string &s, Init init,
@@ -2710,11 +2721,15 @@ inline size_t Request::get_header_value_count(const char *key) const {
27102721
}
27112722

27122723
inline void Request::set_header(const char *key, const char *val) {
2713-
headers.emplace(key, val);
2724+
if (!detail::has_crlf(key) && !detail::has_crlf(val)) {
2725+
headers.emplace(key, val);
2726+
}
27142727
}
27152728

27162729
inline void Request::set_header(const char *key, const std::string &val) {
2717-
headers.emplace(key, val);
2730+
if (!detail::has_crlf(key) && !detail::has_crlf(val.c_str())) {
2731+
headers.emplace(key, val);
2732+
}
27182733
}
27192734

27202735
inline bool Request::has_param(const char *key) const {
@@ -2764,16 +2779,22 @@ inline size_t Response::get_header_value_count(const char *key) const {
27642779
}
27652780

27662781
inline void Response::set_header(const char *key, const char *val) {
2767-
headers.emplace(key, val);
2782+
if (!detail::has_crlf(key) && !detail::has_crlf(val)) {
2783+
headers.emplace(key, val);
2784+
}
27682785
}
27692786

27702787
inline void Response::set_header(const char *key, const std::string &val) {
2771-
headers.emplace(key, val);
2788+
if (!detail::has_crlf(key) && !detail::has_crlf(val.c_str())) {
2789+
headers.emplace(key, val);
2790+
}
27722791
}
27732792

27742793
inline void Response::set_redirect(const char *url) {
2775-
set_header("Location", url);
2776-
status = 302;
2794+
if (!detail::has_crlf(url)) {
2795+
set_header("Location", url);
2796+
status = 302;
2797+
}
27772798
}
27782799

27792800
inline void Response::set_content(const char *s, size_t n,

test/test.cc

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -697,6 +697,36 @@ class ServerTest : public ::testing::Test {
697697
[&](const Request & /*req*/, Response &res) {
698698
res.set_content("Hello World!", "text/plain");
699699
})
700+
.Get("/http_response_splitting",
701+
[&](const Request & /*req*/, Response &res) {
702+
res.set_header("a", "1\r\nSet-Cookie: a=1");
703+
EXPECT_EQ(0, res.headers.size());
704+
EXPECT_FALSE(res.has_header("a"));
705+
706+
res.set_header("a", "1\nSet-Cookie: a=1");
707+
EXPECT_EQ(0, res.headers.size());
708+
EXPECT_FALSE(res.has_header("a"));
709+
710+
res.set_header("a", "1\rSet-Cookie: a=1");
711+
EXPECT_EQ(0, res.headers.size());
712+
EXPECT_FALSE(res.has_header("a"));
713+
714+
res.set_header("a\r\nb", "0");
715+
EXPECT_EQ(0, res.headers.size());
716+
EXPECT_FALSE(res.has_header("a"));
717+
718+
res.set_header("a\rb", "0");
719+
EXPECT_EQ(0, res.headers.size());
720+
EXPECT_FALSE(res.has_header("a"));
721+
722+
res.set_header("a\nb", "0");
723+
EXPECT_EQ(0, res.headers.size());
724+
EXPECT_FALSE(res.has_header("a"));
725+
726+
res.set_redirect("1\r\nSet-Cookie: a=1");
727+
EXPECT_EQ(0, res.headers.size());
728+
EXPECT_FALSE(res.has_header("Location"));
729+
})
700730
.Get("/slow",
701731
[&](const Request & /*req*/, Response &res) {
702732
std::this_thread::sleep_for(std::chrono::seconds(2));
@@ -1685,6 +1715,12 @@ TEST_F(ServerTest, GetMethodRemoteAddr) {
16851715
EXPECT_TRUE(res->body == "::1" || res->body == "127.0.0.1");
16861716
}
16871717

1718+
TEST_F(ServerTest, HTTPResponseSplitting) {
1719+
auto res = cli_.Get("/http_response_splitting");
1720+
ASSERT_TRUE(res != nullptr);
1721+
EXPECT_EQ(200, res->status);
1722+
}
1723+
16881724
TEST_F(ServerTest, SlowRequest) {
16891725
request_threads_.push_back(
16901726
std::thread([=]() { auto res = cli_.Get("/slow"); }));

0 commit comments

Comments
 (0)