mirror of
https://github.com/yhirose/cpp-httplib.git
synced 2026-09-30 20:52:31 +07:00
Use detail::from_chars for out-of-range Content-Length check
Replace the strtoull + errno + cast-back dance in get_header_value_u64 with the existing hand-written detail::from_chars, which reports result_out_of_range at size_t width. This detects the 32-bit truncation case directly (instead of via a separate cast-back comparison), drops the reliance on the global errno, and keeps the parsing locale- independent and consistent with the rest of the codebase.
This commit is contained in:
@@ -2957,18 +2957,18 @@ inline size_t get_header_value_u64(const Headers &headers,
|
|||||||
std::advance(it, static_cast<ssize_t>(id));
|
std::advance(it, static_cast<ssize_t>(id));
|
||||||
if (it != rng.second) {
|
if (it != rng.second) {
|
||||||
if (is_numeric(it->second)) {
|
if (is_numeric(it->second)) {
|
||||||
errno = 0;
|
// Parse at size_t width so an out-of-range Content-Length is reported
|
||||||
auto val = std::strtoull(it->second.data(), nullptr, 10);
|
// rather than silently saturated/truncated (a value above 2^32 would
|
||||||
auto result = static_cast<size_t>(val);
|
// otherwise wrap to a small framing length on 32-bit builds). Flag it
|
||||||
// strtoull saturates to ULLONG_MAX on overflow, and the size_t cast
|
// and return SIZE_MAX so the existing oversized-value guards reject it.
|
||||||
// truncates a value that doesn't fit (a Content-Length above 2^32 wraps
|
size_t val = 0;
|
||||||
// to a small length on 32-bit builds). Either way the framing length
|
const auto &s = it->second;
|
||||||
// would be wrong, so flag it rather than return a bogus size.
|
auto r = from_chars(s.data(), s.data() + s.size(), val);
|
||||||
if (errno == ERANGE || static_cast<unsigned long long>(result) != val) {
|
if (r.ec == std::errc::result_out_of_range) {
|
||||||
is_invalid_value = true;
|
is_invalid_value = true;
|
||||||
return (std::numeric_limits<size_t>::max)();
|
return (std::numeric_limits<size_t>::max)();
|
||||||
}
|
}
|
||||||
return result;
|
return val;
|
||||||
} else {
|
} else {
|
||||||
is_invalid_value = true;
|
is_invalid_value = true;
|
||||||
}
|
}
|
||||||
|
|||||||
+7
-7
@@ -1302,9 +1302,9 @@ TEST(GetHeaderValueTest, RegularInvalidValueInt) {
|
|||||||
|
|
||||||
TEST(GetHeaderValueTest, OutOfRangeValueInt) {
|
TEST(GetHeaderValueTest, OutOfRangeValueInt) {
|
||||||
// An all-digit value that overflows size_t must be reported as invalid, not
|
// An all-digit value that overflows size_t must be reported as invalid, not
|
||||||
// silently saturated/truncated: strtoull would otherwise return ULLONG_MAX
|
// silently saturated/truncated: parsing at size_t width would otherwise wrap
|
||||||
// (or, on 32-bit builds, the cast would wrap a large length to a small one),
|
// a large length to a small one on 32-bit builds, leaving the framing length
|
||||||
// leaving the framing length wrong while is_invalid_value stayed false.
|
// wrong while is_invalid_value stayed false.
|
||||||
Headers headers = {{"Content-Length", "99999999999999999999999999"}};
|
Headers headers = {{"Content-Length", "99999999999999999999999999"}};
|
||||||
auto is_invalid_value = false;
|
auto is_invalid_value = false;
|
||||||
detail::get_header_value_u64(headers, "Content-Length", 0, 0,
|
detail::get_header_value_u64(headers, "Content-Length", 0, 0,
|
||||||
@@ -16094,10 +16094,10 @@ TEST(OpenStreamMalformedContentLength, OutOfRange) {
|
|||||||
ASSERT_GT(port, 0);
|
ASSERT_GT(port, 0);
|
||||||
|
|
||||||
// Historically std::stoull would throw std::out_of_range here and crash
|
// Historically std::stoull would throw std::out_of_range here and crash
|
||||||
// the process, then strtoull silently clamped to ULLONG_MAX and the
|
// the process, then parsing silently clamped to a bogus framing length and
|
||||||
// stream opened with a bogus framing length. Now the out-of-range value
|
// the stream opened anyway. Now the out-of-range value is flagged invalid,
|
||||||
// is flagged invalid, so the stream fails to open, matching the
|
// so the stream fails to open, matching the not-a-number case above. The
|
||||||
// not-a-number case above. The process still must NOT terminate.
|
// process still must NOT terminate.
|
||||||
Client cli("127.0.0.1", port);
|
Client cli("127.0.0.1", port);
|
||||||
auto handle = cli.open_stream("GET", "/");
|
auto handle = cli.open_stream("GET", "/");
|
||||||
EXPECT_FALSE(handle.is_valid());
|
EXPECT_FALSE(handle.is_valid());
|
||||||
|
|||||||
Reference in New Issue
Block a user