Просмотр исходного кода

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.
yhirose 2 месяцев назад
Родитель
Сommit
3adc525cec
2 измененных файлов с 16 добавлено и 16 удалено
  1. 9 9
      httplib.h
  2. 7 7
      test/test.cc

+ 9 - 9
httplib.h

@@ -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;
-      auto val = std::strtoull(it->second.data(), nullptr, 10);
-      auto result = static_cast<size_t>(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<unsigned long long>(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;
         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
test/test.cc

@@ -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
-  // (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"}};
   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
-  // 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);
   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());