Browse Source

Implemented #946 in a different way

yhirose 4 years ago
parent
commit
5a43bb8149
3 changed files with 55 additions and 7 deletions
  1. 1 1
      README.md
  2. 8 4
      httplib.h
  3. 46 2
      test/test.cc

+ 1 - 1
README.md

@@ -266,7 +266,7 @@ svr.Get("/stream", [&](const Request &req, Response &res) {
       sink.write(&d[offset], std::min(length, DATA_CHUNK_SIZE));
       sink.write(&d[offset], std::min(length, DATA_CHUNK_SIZE));
       return true; // return 'false' if you want to cancel the process.
       return true; // return 'false' if you want to cancel the process.
     },
     },
-    [data] { delete data; });
+    [data](bool success) { delete data; });
 });
 });
 ```
 ```
 
 

+ 8 - 4
httplib.h

@@ -337,7 +337,7 @@ using ContentProvider =
 using ContentProviderWithoutLength =
 using ContentProviderWithoutLength =
     std::function<bool(size_t offset, DataSink &sink)>;
     std::function<bool(size_t offset, DataSink &sink)>;
 
 
-using ContentProviderResourceReleaser = std::function<void()>;
+using ContentProviderResourceReleaser = std::function<void(bool success)>;
 
 
 using ContentReceiverWithProgress =
 using ContentReceiverWithProgress =
     std::function<bool(const char *data, size_t data_length, uint64_t offset,
     std::function<bool(const char *data, size_t data_length, uint64_t offset,
@@ -465,7 +465,7 @@ struct Response {
   Response &operator=(Response &&) = default;
   Response &operator=(Response &&) = default;
   ~Response() {
   ~Response() {
     if (content_provider_resource_releaser_) {
     if (content_provider_resource_releaser_) {
-      content_provider_resource_releaser_();
+      content_provider_resource_releaser_(content_provider_success_);
     }
     }
   }
   }
 
 
@@ -474,6 +474,7 @@ struct Response {
   ContentProvider content_provider_;
   ContentProvider content_provider_;
   ContentProviderResourceReleaser content_provider_resource_releaser_;
   ContentProviderResourceReleaser content_provider_resource_releaser_;
   bool is_chunked_content_provider_ = false;
   bool is_chunked_content_provider_ = false;
+  bool content_provider_success_ = false;
 };
 };
 
 
 class Stream {
 class Stream {
@@ -4614,8 +4615,11 @@ inline bool Server::write_response_core(Stream &strm, bool close_connection,
     if (!res.body.empty()) {
     if (!res.body.empty()) {
       if (!strm.write(res.body)) { ret = false; }
       if (!strm.write(res.body)) { ret = false; }
     } else if (res.content_provider_) {
     } else if (res.content_provider_) {
-      if (!write_content_with_provider(strm, req, res, boundary,
-                                       content_type)) {
+      if (write_content_with_provider(strm, req, res, boundary,
+                                      content_type)) {
+        res.content_provider_success_ = true;
+      } else {
+        res.content_provider_success_ = false;
         ret = false;
         ret = false;
       }
       }
     }
     }

+ 46 - 2
test/test.cc

@@ -1378,7 +1378,10 @@ protected:
                      (*i)++;
                      (*i)++;
                      return true;
                      return true;
                    },
                    },
-                   [i] { delete i; });
+                   [i](bool success) {
+                     EXPECT_TRUE(success);
+                     delete i;
+                   });
              })
              })
         .Get("/streamed",
         .Get("/streamed",
              [&](const Request & /*req*/, Response &res) {
              [&](const Request & /*req*/, Response &res) {
@@ -1405,7 +1408,10 @@ protected:
                      EXPECT_TRUE(ret);
                      EXPECT_TRUE(ret);
                      return true;
                      return true;
                    },
                    },
-                   [data] { delete data; });
+                   [data](bool success) {
+                     EXPECT_TRUE(success);
+                     delete data;
+                   });
              })
              })
         .Get("/streamed-cancel",
         .Get("/streamed-cancel",
              [&](const Request & /*req*/, Response &res) {
              [&](const Request & /*req*/, Response &res) {
@@ -3567,6 +3573,44 @@ TEST(KeepAliveTest, ReadTimeout) {
   ASSERT_FALSE(svr.is_running());
   ASSERT_FALSE(svr.is_running());
 }
 }
 
 
+TEST(ClientProblemDetectionTest, ContentProvider) {
+  Server svr;
+
+  size_t content_length = 1024 * 1024;
+
+  svr.Get("/hi", [&](const Request & /*req*/, Response &res) {
+    res.set_content_provider(
+        content_length, "text/plain",
+        [&](size_t offset, size_t length, DataSink &sink) {
+          auto out_len = std::min(length, static_cast<size_t>(1024));
+          std::string out(out_len, '@');
+          sink.write(out.data(), out_len);
+          return offset < 4096;
+        },
+        [](bool success) { ASSERT_FALSE(success); });
+  });
+
+  auto listen_thread = std::thread([&svr]() { svr.listen("localhost", PORT); });
+  while (!svr.is_running()) {
+    std::this_thread::sleep_for(std::chrono::milliseconds(1));
+  }
+
+  // Give GET time to get a few messages.
+  std::this_thread::sleep_for(std::chrono::seconds(1));
+
+  Client cli("localhost", PORT);
+
+  auto res = cli.Get("/hi", [&](const char * /*data*/, size_t /*data_length*/) {
+    return false;
+  });
+
+  ASSERT_FALSE(res);
+
+  svr.stop();
+  listen_thread.join();
+  ASSERT_FALSE(svr.is_running());
+}
+
 TEST(ErrorHandlerWithContentProviderTest, ErrorHandler) {
 TEST(ErrorHandlerWithContentProviderTest, ErrorHandler) {
   Server svr;
   Server svr;