Переглянути джерело

Treat a zero WebSocket payload limit as none

CPPHTTPLIB_WEBSOCKET_MAX_PAYLOAD_LENGTH = 0 rejected every frame with a
payload, while 0 means no limit for payload_max_length. Make it mean the
same here, and refuse a length that size_t cannot hold.
yhirose 1 день тому
батько
коміт
0116be0a2b
3 змінених файлів з 28 додано та 3 видалено
  1. 1 1
      README-websocket.md
  2. 7 2
      httplib.h
  3. 20 0
      test/test.cc

+ 1 - 1
README-websocket.md

@@ -435,7 +435,7 @@ if (ws.connect()) {
 
 | Macro                                       | Default           | Description                                              |
 |---------------------------------------------|-------------------|----------------------------------------------------------|
-| `CPPHTTPLIB_WEBSOCKET_MAX_PAYLOAD_LENGTH`   | `16777216` (16MB) | Maximum payload size per message                         |
+| `CPPHTTPLIB_WEBSOCKET_MAX_PAYLOAD_LENGTH`   | `16777216` (16MB) | Maximum payload size per message (`0` means no limit)    |
 | `CPPHTTPLIB_WEBSOCKET_CLIENT_READ_TIMEOUT_SECOND` | `0`         | Client read timeout (seconds); `0` waits forever         |
 | `CPPHTTPLIB_WEBSOCKET_SERVER_READ_TIMEOUT_SECOND` | `300`       | Server read timeout (seconds)                            |
 | `CPPHTTPLIB_WEBSOCKET_CLOSE_TIMEOUT_SECOND` | `5`               | Timeout for waiting peer's Close response (seconds)      |

+ 7 - 2
httplib.h

@@ -5758,7 +5758,11 @@ inline FrameRead read_websocket_frame(Stream &strm, Opcode &opcode,
     }
   }
 
-  if (payload_len > max_len) { return FrameRead::Fail; }
+  // A max_len of 0 means no limit, as payload_max_length does.
+  if ((max_len > 0 && payload_len > max_len) ||
+      payload_len > (std::numeric_limits<size_t>::max)()) {
+    return FrameRead::Fail;
+  }
 
   // Read mask key if present
   uint8_t mask_key[4] = {0};
@@ -22887,7 +22891,8 @@ inline ReadResult WebSocket::read(std::string &msg) {
             return Fail;
           }
           msg += cont_payload;
-          if (msg.size() > CPPHTTPLIB_WEBSOCKET_MAX_PAYLOAD_LENGTH) {
+          if (CPPHTTPLIB_WEBSOCKET_MAX_PAYLOAD_LENGTH > 0 &&
+              msg.size() > CPPHTTPLIB_WEBSOCKET_MAX_PAYLOAD_LENGTH) {
             closed_ = true;
             return Fail;
           }

+ 20 - 0
test/test.cc

@@ -25811,6 +25811,26 @@ TEST(WebSocketFrameTest, MultiByteFieldsSplitAcrossReads) {
   EXPECT_EQ(payload, body);
 }
 
+TEST(WebSocketFrameTest, ZeroMaxLenMeansNoLimit) {
+  std::string body(2000, 'x');
+  std::string frame;
+  frame += static_cast<char>(0x82); // FIN + Binary
+  frame += static_cast<char>(126);  // 16-bit length follows
+  frame += static_cast<char>(body.size() >> 8);
+  frame += static_cast<char>(body.size() & 0xff);
+  frame += body;
+
+  detail::BufferStream strm;
+  strm.write(frame.data(), frame.size());
+  ws::Opcode opcode;
+  std::string payload;
+  bool fin;
+  EXPECT_EQ(
+      ws::impl::read_websocket_frame(strm, opcode, payload, fin, false, 0),
+      ws::impl::FrameRead::Ok);
+  EXPECT_EQ(body, payload);
+}
+
 TEST(WebSocketFrameTest, PayloadGrowsOnlyAsItArrives) {
   // The header announces the largest payload allowed, and only 3 bytes of it
   // ever arrive.