1
0
Эх сурвалжийг харах

Fix problem with PayloadMaxLengthTest.NoContentLengthPayloadLimit

yhirose 1 сар өмнө
parent
commit
f69737a838
1 өөрчлөгдсөн 27 нэмэгдсэн , 28 устгасан
  1. 27 28
      httplib.h

+ 27 - 28
httplib.h

@@ -9855,41 +9855,40 @@ inline bool Server::read_content_core(
   // are true (no Transfer-Encoding and no Content-Length), then the message
   // body length is zero (no message body is present).
   //
-  // For non-SSL builds, peek into the socket to detect clients that send a
-  // body without a Content-Length header (raw HTTP over TCP). If there is
-  // pending data that exceeds the configured payload limit, treat this as an
-  // oversized request and fail early (causing connection close). For SSL
-  // builds we cannot reliably peek the decrypted application bytes, so keep
-  // the original behaviour.
+  // For non-SSL builds, detect clients that send a body without a
+  // Content-Length header (raw HTTP over TCP). Check both the stream's
+  // internal read buffer (data already read from the socket during header
+  // parsing) and the socket itself for pending data. If data is found and
+  // exceeds the configured payload limit, reject with 413.
+  // For SSL builds we cannot reliably peek the decrypted application bytes,
+  // so keep the original behaviour.
 #if !defined(CPPHTTPLIB_SSL_ENABLED)
   if (!req.has_header("Content-Length") &&
       !detail::is_chunked_transfer_encoding(req.headers)) {
-    // Only peek if payload_max_length is set to a finite value
+    // Only check if payload_max_length is set to a finite value
     if (payload_max_length_ > 0 &&
         payload_max_length_ < (std::numeric_limits<size_t>::max)()) {
-      socket_t s = strm.socket();
-      if (s != INVALID_SOCKET) {
-        // Use a non-blocking check to see if there is any pending data.
-        // A blocking recv(MSG_PEEK) would deadlock when the client is
-        // waiting for the response (e.g. POST with Connection: close and
-        // no body).
-        if (detail::select_read(s, 0, 0) > 0) {
-          char peekbuf[1];
-          ssize_t n = ::recv(s, peekbuf, 1, MSG_PEEK);
-          if (n > 0) {
-            // There is data, so read it with payload limit enforcement
-            auto result = detail::read_content_without_length(
-                strm, payload_max_length_, out);
-            if (result == detail::ReadContentResult::PayloadTooLarge) {
-              res.status = StatusCode::PayloadTooLarge_413;
-              return false;
-            } else if (result != detail::ReadContentResult::Success) {
-              return false;
-            }
-            return true;
-          }
+      // Check if there is data already buffered in the stream (read during
+      // header parsing) or pending on the socket. Use a non-blocking socket
+      // check to avoid deadlock when the client sends no body.
+      bool has_data = strm.is_readable();
+      if (!has_data) {
+        socket_t s = strm.socket();
+        if (s != INVALID_SOCKET) {
+          has_data = detail::select_read(s, 0, 0) > 0;
         }
       }
+      if (has_data) {
+        auto result =
+            detail::read_content_without_length(strm, payload_max_length_, out);
+        if (result == detail::ReadContentResult::PayloadTooLarge) {
+          res.status = StatusCode::PayloadTooLarge_413;
+          return false;
+        } else if (result != detail::ReadContentResult::Success) {
+          return false;
+        }
+        return true;
+      }
     }
     return true;
   }