Browse Source

Don't fail chunked read if buffer not yet filled

Scott Graham 7 years ago
parent
commit
889041f05f
2 changed files with 37 additions and 4 deletions
  1. 2 4
      httplib.h
  2. 35 0
      test/test.cc

+ 2 - 4
httplib.h

@@ -817,10 +817,8 @@ bool read_content_chunked(Stream& strm, std::string& out)
     auto chunk_len = std::stoi(reader.ptr(), 0, 16);
     auto chunk_len = std::stoi(reader.ptr(), 0, 16);
 
 
     while (chunk_len > 0){
     while (chunk_len > 0){
-        std::string chunk(chunk_len, 0);
-
-        auto n = strm.read(&chunk[0], chunk_len);
-        if (n <= 0) {
+        std::string chunk;
+        if (!read_content_with_length(strm, chunk, chunk_len, nullptr)) {
             return false;
             return false;
         }
         }
 
 

+ 35 - 0
test/test.cc

@@ -295,6 +295,10 @@ protected:
             .post("/chunked", [&](const Request& req, Response& /*res*/) {
             .post("/chunked", [&](const Request& req, Response& /*res*/) {
                 EXPECT_EQ(req.body, "dechunked post body");
                 EXPECT_EQ(req.body, "dechunked post body");
             })
             })
+            .post("/largechunked", [&](const Request& req, Response& /*res*/) {
+                std::string expected(6 * 30 * 1024u, 'a');
+                EXPECT_EQ(req.body, expected);
+            })
             .post("/multipart", [&](const Request& req, Response& /*res*/) {
             .post("/multipart", [&](const Request& req, Response& /*res*/) {
                 EXPECT_EQ(5u, req.files.size());
                 EXPECT_EQ(5u, req.files.size());
                 ASSERT_TRUE(!req.has_file("???"));
                 ASSERT_TRUE(!req.has_file("???"));
@@ -690,6 +694,37 @@ TEST_F(ServerTest, CaseInsensitiveTransferEncoding)
 	EXPECT_EQ(200, res->status);
 	EXPECT_EQ(200, res->status);
 }
 }
 
 
+TEST_F(ServerTest, LargeChunkedPost) {
+    Request req;
+    req.method = "POST";
+    req.path = "/largechunked";
+
+    std::string host_and_port;
+    host_and_port += HOST;
+    host_and_port += ":";
+    host_and_port += std::to_string(PORT);
+
+    req.headers.emplace("Host", host_and_port.c_str());
+    req.headers.emplace("Accept", "*/*");
+    req.headers.emplace("User-Agent", "cpp-httplib/0.1");
+    req.headers.emplace("Content-Type", "text/plain");
+    req.headers.emplace("Content-Length", "0");
+    req.headers.emplace("Transfer-Encoding", "chunked");
+
+    std::string long_string(30 * 1024u, 'a');
+    std::string chunk = "7800\r\n" + long_string + "\r\n";
+
+    // Attempt to make a large enough post to exceed OS buffers, to test that
+    // the server handles short reads if the full chunk data isn't available.
+    req.body = chunk + chunk + chunk + chunk + chunk + chunk + "0\r\n\r\n";
+
+    auto res = std::make_shared<Response>();
+    auto ret = cli_.send(req, *res);
+
+	ASSERT_TRUE(ret);
+	EXPECT_EQ(200, res->status);
+}
+
 TEST_F(ServerTest, GetMethodRemoteAddr)
 TEST_F(ServerTest, GetMethodRemoteAddr)
 {
 {
     auto res = cli_.get("/remote_addr");
     auto res = cli_.get("/remote_addr");