diff --git a/httplib.h b/httplib.h index ab8fc07..e2e6428 100644 --- a/httplib.h +++ b/httplib.h @@ -2957,18 +2957,18 @@ inline size_t get_header_value_u64(const Headers &headers, std::advance(it, static_cast(id)); if (it != rng.second) { if (is_numeric(it->second)) { - errno = 0; - auto val = std::strtoull(it->second.data(), nullptr, 10); - auto result = static_cast(val); - // strtoull saturates to ULLONG_MAX on overflow, and the size_t cast - // truncates a value that doesn't fit (a Content-Length above 2^32 wraps - // to a small length on 32-bit builds). Either way the framing length - // would be wrong, so flag it rather than return a bogus size. - if (errno == ERANGE || static_cast(result) != val) { + // Parse at size_t width so an out-of-range Content-Length is reported + // rather than silently saturated/truncated (a value above 2^32 would + // otherwise wrap to a small framing length on 32-bit builds). Flag it + // and return SIZE_MAX so the existing oversized-value guards reject it. + size_t val = 0; + const auto &s = it->second; + auto r = from_chars(s.data(), s.data() + s.size(), val); + if (r.ec == std::errc::result_out_of_range) { is_invalid_value = true; return (std::numeric_limits::max)(); } - return result; + return val; } else { is_invalid_value = true; } diff --git a/test/test.cc b/test/test.cc index 8a894a5..e5dd95e 100644 --- a/test/test.cc +++ b/test/test.cc @@ -1302,9 +1302,9 @@ TEST(GetHeaderValueTest, RegularInvalidValueInt) { TEST(GetHeaderValueTest, OutOfRangeValueInt) { // An all-digit value that overflows size_t must be reported as invalid, not - // silently saturated/truncated: strtoull would otherwise return ULLONG_MAX - // (or, on 32-bit builds, the cast would wrap a large length to a small one), - // leaving the framing length wrong while is_invalid_value stayed false. + // silently saturated/truncated: parsing at size_t width would otherwise wrap + // a large length to a small one on 32-bit builds, leaving the framing length + // wrong while is_invalid_value stayed false. Headers headers = {{"Content-Length", "99999999999999999999999999"}}; auto is_invalid_value = false; detail::get_header_value_u64(headers, "Content-Length", 0, 0, @@ -16094,10 +16094,10 @@ TEST(OpenStreamMalformedContentLength, OutOfRange) { ASSERT_GT(port, 0); // Historically std::stoull would throw std::out_of_range here and crash - // the process, then strtoull silently clamped to ULLONG_MAX and the - // stream opened with a bogus framing length. Now the out-of-range value - // is flagged invalid, so the stream fails to open, matching the - // not-a-number case above. The process still must NOT terminate. + // the process, then parsing silently clamped to a bogus framing length and + // the stream opened anyway. Now the out-of-range value is flagged invalid, + // so the stream fails to open, matching the not-a-number case above. The + // process still must NOT terminate. Client cli("127.0.0.1", port); auto handle = cli.open_stream("GET", "/"); EXPECT_FALSE(handle.is_valid());