mirror of
https://github.com/yhirose/cpp-httplib.git
synced 2026-10-20 11:29:38 +00:00
Bound the number of interim responses a client skips
A server sending "102 Processing" without end kept the client reading them unless max_timeout was set. Skip at most CPPHTTPLIB_INTERIM_RESPONSE_MAX_COUNT (100) and fail with Error::Read past it.
This commit is contained in:
1 parent
560126bffc
commit
8ca46a4db5
2 files changed
+32
-1
No files matched your search
@@ -130,6 +130,10 @@
|
|||||||
#define CPPHTTPLIB_REDIRECT_MAX_COUNT 20
|
#define CPPHTTPLIB_REDIRECT_MAX_COUNT 20
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef CPPHTTPLIB_INTERIM_RESPONSE_MAX_COUNT
|
||||||
|
#define CPPHTTPLIB_INTERIM_RESPONSE_MAX_COUNT 100
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef CPPHTTPLIB_MULTIPART_FORM_DATA_FILE_MAX_COUNT
|
#ifndef CPPHTTPLIB_MULTIPART_FORM_DATA_FILE_MAX_COUNT
|
||||||
#define CPPHTTPLIB_MULTIPART_FORM_DATA_FILE_MAX_COUNT 1024
|
#define CPPHTTPLIB_MULTIPART_FORM_DATA_FILE_MAX_COUNT 1024
|
||||||
#endif
|
#endif
|
||||||
@@ -15438,10 +15442,15 @@ inline bool ClientImpl::read_response_line(Stream &strm, const Request &req,
|
|||||||
|
|
||||||
// Skip interim (1xx) responses along with their header fields, except a 100
|
// Skip interim (1xx) responses along with their header fields, except a 100
|
||||||
// Continue the caller handles itself for Expect: 100-continue. 101 ends
|
// Continue the caller handles itself for Expect: 100-continue. 101 ends
|
||||||
// HTTP on the connection, so it is final.
|
// HTTP on the connection, so it is final. A server sending them without end
|
||||||
|
// would hold the client, so there may be only so many.
|
||||||
|
size_t interim_count = 0;
|
||||||
while (100 <= res.status && res.status < 200 &&
|
while (100 <= res.status && res.status < 200 &&
|
||||||
res.status != StatusCode::SwitchingProtocol_101 &&
|
res.status != StatusCode::SwitchingProtocol_101 &&
|
||||||
(skip_100_continue || res.status != StatusCode::Continue_100)) {
|
(skip_100_continue || res.status != StatusCode::Continue_100)) {
|
||||||
|
if (++interim_count > CPPHTTPLIB_INTERIM_RESPONSE_MAX_COUNT) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
Headers interim_headers;
|
Headers interim_headers;
|
||||||
if (!detail::read_headers(strm, interim_headers)) { return false; }
|
if (!detail::read_headers(strm, interim_headers)) { return false; }
|
||||||
if (!line_reader.getline()) { return false; } // next response line
|
if (!line_reader.getline()) { return false; } // next response line
|
||||||
|
|||||||
@@ -23031,6 +23031,28 @@ TEST(InterimResponseTest, SkippedWithTheirHeaderFields) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(InterimResponseTest, OnlySoManyAreSkipped) {
|
||||||
|
const std::string interim = "HTTP/1.1 102 Processing\r\n\r\n";
|
||||||
|
const std::string final_response =
|
||||||
|
"HTTP/1.1 200 OK\r\nContent-Length: 2\r\n\r\nok";
|
||||||
|
std::string interims;
|
||||||
|
for (auto i = 0; i < CPPHTTPLIB_INTERIM_RESPONSE_MAX_COUNT; i++) {
|
||||||
|
interims += interim;
|
||||||
|
}
|
||||||
|
|
||||||
|
with_single_response(interims + final_response, [](Client &cli) {
|
||||||
|
auto res = cli.Get("/");
|
||||||
|
ASSERT_TRUE(res) << "Error: " << to_string(res.error());
|
||||||
|
EXPECT_EQ("ok", res->body);
|
||||||
|
});
|
||||||
|
|
||||||
|
with_single_response(interims + interim + final_response, [](Client &cli) {
|
||||||
|
auto res = cli.Get("/");
|
||||||
|
ASSERT_FALSE(res);
|
||||||
|
EXPECT_EQ(Error::Read, res.error());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
TEST(ExpectContinueTest, EarlyFinalResponseClosesConnection) {
|
TEST(ExpectContinueTest, EarlyFinalResponseClosesConnection) {
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
signal(SIGPIPE, SIG_IGN);
|
signal(SIGPIPE, SIG_IGN);
|
||||||
|
|||||||
Reference in new issue
Block a user