yhirose 7 달 전
부모
커밋
cfb56c0b78
2개의 변경된 파일297개의 추가작업 그리고 0개의 파일을 삭제
  1. 108 0
      httplib.h
  2. 189 0
      test/test.cc

+ 108 - 0
httplib.h

@@ -1319,6 +1319,7 @@ public:
   Result Post(const std::string &path, const Headers &headers, const MultipartFormDataItemsForClientInput &items, UploadProgress progress = nullptr);
   Result Post(const std::string &path, const Headers &headers, const MultipartFormDataItemsForClientInput &items, const std::string &boundary, UploadProgress progress = nullptr);
   Result Post(const std::string &path, const Headers &headers, const MultipartFormDataItemsForClientInput &items, const MultipartFormDataProviderItems &provider_items, UploadProgress progress = nullptr);
+  Result Post(const std::string &path, const Headers &headers, const std::string &body, const std::string &content_type, ContentReceiver content_receiver, DownloadProgress progress = nullptr);
 
   Result Put(const std::string &path);
   Result Put(const std::string &path, const char *body, size_t content_length, const std::string &content_type, UploadProgress progress = nullptr);
@@ -1336,6 +1337,7 @@ public:
   Result Put(const std::string &path, const Headers &headers, const MultipartFormDataItemsForClientInput &items, UploadProgress progress = nullptr);
   Result Put(const std::string &path, const Headers &headers, const MultipartFormDataItemsForClientInput &items, const std::string &boundary, UploadProgress progress = nullptr);
   Result Put(const std::string &path, const Headers &headers, const MultipartFormDataItemsForClientInput &items, const MultipartFormDataProviderItems &provider_items, UploadProgress progress = nullptr);
+  Result Put(const std::string &path, const Headers &headers, const std::string &body, const std::string &content_type, ContentReceiver content_receiver, DownloadProgress progress = nullptr);
 
   Result Patch(const std::string &path);
   Result Patch(const std::string &path, const char *body, size_t content_length, const std::string &content_type, UploadProgress progress = nullptr);
@@ -1353,6 +1355,7 @@ public:
   Result Patch(const std::string &path, const Headers &headers, const MultipartFormDataItemsForClientInput &items, UploadProgress progress = nullptr);
   Result Patch(const std::string &path, const Headers &headers, const MultipartFormDataItemsForClientInput &items, const std::string &boundary, UploadProgress progress = nullptr);
   Result Patch(const std::string &path, const Headers &headers, const MultipartFormDataItemsForClientInput &items, const MultipartFormDataProviderItems &provider_items, UploadProgress progress = nullptr);
+  Result Patch(const std::string &path, const Headers &headers, const std::string &body, const std::string &content_type, ContentReceiver content_receiver, DownloadProgress progress = nullptr);
 
   Result Delete(const std::string &path, DownloadProgress progress = nullptr);
   Result Delete(const std::string &path, const char *body, size_t content_length, const std::string &content_type, DownloadProgress progress = nullptr);
@@ -1662,6 +1665,7 @@ public:
   Result Post(const std::string &path, const Headers &headers, const MultipartFormDataItemsForClientInput &items, UploadProgress progress = nullptr);
   Result Post(const std::string &path, const Headers &headers, const MultipartFormDataItemsForClientInput &items, const std::string &boundary, UploadProgress progress = nullptr);
   Result Post(const std::string &path, const Headers &headers, const MultipartFormDataItemsForClientInput &items, const MultipartFormDataProviderItems &provider_items, UploadProgress progress = nullptr);
+  Result Post(const std::string &path, const Headers &headers, const std::string &body, const std::string &content_type, ContentReceiver content_receiver, DownloadProgress progress = nullptr);
 
   Result Put(const std::string &path);
   Result Put(const std::string &path, const char *body, size_t content_length, const std::string &content_type, UploadProgress progress = nullptr);
@@ -1679,6 +1683,7 @@ public:
   Result Put(const std::string &path, const Headers &headers, const MultipartFormDataItemsForClientInput &items, UploadProgress progress = nullptr);
   Result Put(const std::string &path, const Headers &headers, const MultipartFormDataItemsForClientInput &items, const std::string &boundary, UploadProgress progress = nullptr);
   Result Put(const std::string &path, const Headers &headers, const MultipartFormDataItemsForClientInput &items, const MultipartFormDataProviderItems &provider_items, UploadProgress progress = nullptr);
+  Result Put(const std::string &path, const Headers &headers, const std::string &body, const std::string &content_type, ContentReceiver content_receiver, DownloadProgress progress = nullptr);
 
   Result Patch(const std::string &path);
   Result Patch(const std::string &path, const char *body, size_t content_length, const std::string &content_type, UploadProgress progress = nullptr);
@@ -1696,6 +1701,7 @@ public:
   Result Patch(const std::string &path, const Headers &headers, const MultipartFormDataItemsForClientInput &items, UploadProgress progress = nullptr);
   Result Patch(const std::string &path, const Headers &headers, const MultipartFormDataItemsForClientInput &items, const std::string &boundary, UploadProgress progress = nullptr);
   Result Patch(const std::string &path, const Headers &headers, const MultipartFormDataItemsForClientInput &items, const MultipartFormDataProviderItems &provider_items, UploadProgress progress = nullptr);
+  Result Patch(const std::string &path, const Headers &headers, const std::string &body, const std::string &content_type, ContentReceiver content_receiver, DownloadProgress progress = nullptr);
 
   Result Delete(const std::string &path, DownloadProgress progress = nullptr);
   Result Delete(const std::string &path, const char *body, size_t content_length, const std::string &content_type, DownloadProgress progress = nullptr);
@@ -9115,6 +9121,32 @@ ClientImpl::Post(const std::string &path, const Headers &headers,
       content_type, progress);
 }
 
+inline Result ClientImpl::Post(const std::string &path, const Headers &headers,
+                               const std::string &body,
+                               const std::string &content_type,
+                               ContentReceiver content_receiver,
+                               DownloadProgress progress) {
+  Request req;
+  req.method = "POST";
+  req.path = path;
+  req.headers = headers;
+  req.body = body;
+  req.content_receiver =
+      [content_receiver](const char *data, size_t data_length,
+                         uint64_t /*offset*/, uint64_t /*total_length*/) {
+        return content_receiver(data, data_length);
+      };
+  req.download_progress = std::move(progress);
+
+  if (max_timeout_msec_ > 0) {
+    req.start_time_ = std::chrono::steady_clock::now();
+  }
+
+  if (!content_type.empty()) { req.set_header("Content-Type", content_type); }
+
+  return send_(std::move(req));
+}
+
 inline Result ClientImpl::Put(const std::string &path) {
   return Put(path, std::string(), std::string());
 }
@@ -9242,6 +9274,32 @@ ClientImpl::Put(const std::string &path, const Headers &headers,
       content_type, progress);
 }
 
+inline Result ClientImpl::Put(const std::string &path, const Headers &headers,
+                              const std::string &body,
+                              const std::string &content_type,
+                              ContentReceiver content_receiver,
+                              DownloadProgress progress) {
+  Request req;
+  req.method = "PUT";
+  req.path = path;
+  req.headers = headers;
+  req.body = body;
+  req.content_receiver =
+      [content_receiver](const char *data, size_t data_length,
+                         uint64_t /*offset*/, uint64_t /*total_length*/) {
+        return content_receiver(data, data_length);
+      };
+  req.download_progress = std::move(progress);
+
+  if (max_timeout_msec_ > 0) {
+    req.start_time_ = std::chrono::steady_clock::now();
+  }
+
+  if (!content_type.empty()) { req.set_header("Content-Type", content_type); }
+
+  return send_(std::move(req));
+}
+
 inline Result ClientImpl::Patch(const std::string &path) {
   return Patch(path, std::string(), std::string());
 }
@@ -9374,6 +9432,32 @@ ClientImpl::Patch(const std::string &path, const Headers &headers,
       content_type, progress);
 }
 
+inline Result ClientImpl::Patch(const std::string &path, const Headers &headers,
+                                const std::string &body,
+                                const std::string &content_type,
+                                ContentReceiver content_receiver,
+                                DownloadProgress progress) {
+  Request req;
+  req.method = "PATCH";
+  req.path = path;
+  req.headers = headers;
+  req.body = body;
+  req.content_receiver =
+      [content_receiver](const char *data, size_t data_length,
+                         uint64_t /*offset*/, uint64_t /*total_length*/) {
+        return content_receiver(data, data_length);
+      };
+  req.download_progress = std::move(progress);
+
+  if (max_timeout_msec_ > 0) {
+    req.start_time_ = std::chrono::steady_clock::now();
+  }
+
+  if (!content_type.empty()) { req.set_header("Content-Type", content_type); }
+
+  return send_(std::move(req));
+}
+
 inline Result ClientImpl::Delete(const std::string &path,
                                  DownloadProgress progress) {
   return Delete(path, Headers(), std::string(), std::string(), progress);
@@ -10679,6 +10763,14 @@ inline Result Client::Post(const std::string &path, const Headers &headers,
                            UploadProgress progress) {
   return cli_->Post(path, headers, items, provider_items, progress);
 }
+inline Result Client::Post(const std::string &path, const Headers &headers,
+                           const std::string &body,
+                           const std::string &content_type,
+                           ContentReceiver content_receiver,
+                           DownloadProgress progress) {
+  return cli_->Post(path, headers, body, content_type, content_receiver,
+                    progress);
+}
 
 inline Result Client::Put(const std::string &path) { return cli_->Put(path); }
 inline Result Client::Put(const std::string &path, const Headers &headers) {
@@ -10764,6 +10856,14 @@ inline Result Client::Put(const std::string &path, const Headers &headers,
                           UploadProgress progress) {
   return cli_->Put(path, headers, items, provider_items, progress);
 }
+inline Result Client::Put(const std::string &path, const Headers &headers,
+                          const std::string &body,
+                          const std::string &content_type,
+                          ContentReceiver content_receiver,
+                          DownloadProgress progress) {
+  return cli_->Put(path, headers, body, content_type, content_receiver,
+                   progress);
+}
 
 inline Result Client::Patch(const std::string &path) {
   return cli_->Patch(path);
@@ -10853,6 +10953,14 @@ Client::Patch(const std::string &path, const Headers &headers,
               UploadProgress progress) {
   return cli_->Patch(path, headers, items, provider_items, progress);
 }
+inline Result Client::Patch(const std::string &path, const Headers &headers,
+                            const std::string &body,
+                            const std::string &content_type,
+                            ContentReceiver content_receiver,
+                            DownloadProgress progress) {
+  return cli_->Patch(path, headers, body, content_type, content_receiver,
+                     progress);
+}
 
 inline Result Client::Delete(const std::string &path,
                              DownloadProgress progress) {

+ 189 - 0
test/test.cc

@@ -5302,6 +5302,195 @@ TEST_F(ServerTest, PatchContentReceiver) {
   ASSERT_EQ("content", res->body);
 }
 
+template<typename ClientType>
+void TestWithHeadersAndContentReceiver(
+    ClientType& cli,
+    std::function<Result(ClientType&, const std::string&, const Headers&, const std::string&, const std::string&,
+                        ContentReceiver, DownloadProgress)> request_func) {
+  Headers headers;
+  headers.emplace("X-Custom-Header", "test-value");
+
+  std::string received_body;
+  auto res = request_func(
+      cli, "/content_receiver", headers, "content", "application/json",
+      [&](const char *data, size_t data_length) {
+        received_body.append(data, data_length);
+        return true;
+      }, nullptr);
+
+  ASSERT_TRUE(res);
+  EXPECT_EQ(StatusCode::OK_200, res->status);
+  EXPECT_EQ("content", received_body);
+}
+
+TEST_F(ServerTest, PostWithHeadersAndContentReceiver) {
+#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
+  using ClientT = SSLClient;
+#else
+  using ClientT = Client;
+#endif
+  TestWithHeadersAndContentReceiver<ClientT>(cli_, 
+    [](ClientT& cli, const std::string& path, const Headers& headers, const std::string& body, 
+       const std::string& content_type, ContentReceiver receiver, DownloadProgress progress) {
+      return cli.Post(path, headers, body, content_type, receiver, progress);
+    });
+}
+
+TEST_F(ServerTest, PutWithHeadersAndContentReceiver) {
+#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
+  using ClientT = SSLClient;
+#else
+  using ClientT = Client;
+#endif
+  TestWithHeadersAndContentReceiver<ClientT>(cli_, 
+    [](ClientT& cli, const std::string& path, const Headers& headers, const std::string& body, 
+       const std::string& content_type, ContentReceiver receiver, DownloadProgress progress) {
+      return cli.Put(path, headers, body, content_type, receiver, progress);
+    });
+}
+
+TEST_F(ServerTest, PatchWithHeadersAndContentReceiver) {
+#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
+  using ClientT = SSLClient;
+#else
+  using ClientT = Client;
+#endif
+  TestWithHeadersAndContentReceiver<ClientT>(cli_, 
+    [](ClientT& cli, const std::string& path, const Headers& headers, const std::string& body, 
+       const std::string& content_type, ContentReceiver receiver, DownloadProgress progress) {
+      return cli.Patch(path, headers, body, content_type, receiver, progress);
+    });
+}
+
+template<typename ClientType>
+void TestWithHeadersAndContentReceiverWithProgress(
+    ClientType& cli,
+    std::function<Result(ClientType&, const std::string&, const Headers&, const std::string&, const std::string&,
+                        ContentReceiver, DownloadProgress)> request_func) {
+  Headers headers;
+  headers.emplace("X-Test-Header", "progress-test");
+
+  std::string received_body;
+  auto progress_called = false;
+
+  auto res = request_func(
+      cli, "/content_receiver", headers, "content", "text/plain",
+      [&](const char *data, size_t data_length) {
+        received_body.append(data, data_length);
+        return true;
+      },
+      [&](uint64_t /*current*/, uint64_t /*total*/) {
+        progress_called = true;
+        return true;
+      });
+
+  ASSERT_TRUE(res);
+  EXPECT_EQ(StatusCode::OK_200, res->status);
+  EXPECT_EQ("content", received_body);
+  EXPECT_TRUE(progress_called);
+}
+
+TEST_F(ServerTest, PostWithHeadersAndContentReceiverWithProgress) {
+#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
+  using ClientT = SSLClient;
+#else
+  using ClientT = Client;
+#endif
+  TestWithHeadersAndContentReceiverWithProgress<ClientT>(cli_, 
+    [](ClientT& cli, const std::string& path, const Headers& headers, const std::string& body, 
+       const std::string& content_type, ContentReceiver receiver, DownloadProgress progress) {
+      return cli.Post(path, headers, body, content_type, receiver, progress);
+    });
+}
+
+TEST_F(ServerTest, PutWithHeadersAndContentReceiverWithProgress) {
+#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
+  using ClientT = SSLClient;
+#else
+  using ClientT = Client;
+#endif
+  TestWithHeadersAndContentReceiverWithProgress<ClientT>(cli_, 
+    [](ClientT& cli, const std::string& path, const Headers& headers, const std::string& body, 
+       const std::string& content_type, ContentReceiver receiver, DownloadProgress progress) {
+      return cli.Put(path, headers, body, content_type, receiver, progress);
+    });
+}
+
+TEST_F(ServerTest, PatchWithHeadersAndContentReceiverWithProgress) {
+#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
+  using ClientT = SSLClient;
+#else
+  using ClientT = Client;
+#endif
+  TestWithHeadersAndContentReceiverWithProgress<ClientT>(cli_, 
+    [](ClientT& cli, const std::string& path, const Headers& headers, const std::string& body, 
+       const std::string& content_type, ContentReceiver receiver, DownloadProgress progress) {
+      return cli.Patch(path, headers, body, content_type, receiver, progress);
+    });
+}
+
+template<typename ClientType>
+void TestWithHeadersAndContentReceiverError(
+    ClientType& cli,
+    std::function<Result(ClientType&, const std::string&, const Headers&, const std::string&, const std::string&,
+                        ContentReceiver)> request_func) {
+  Headers headers;
+  headers.emplace("X-Error-Test", "true");
+
+  std::string received_body;
+  auto receiver_failed = false;
+
+  auto res = request_func(
+      cli, "/content_receiver", headers, "content", "text/plain",
+      [&](const char *data, size_t data_length) {
+        received_body.append(data, data_length);
+        receiver_failed = true;
+        return false;
+      });
+
+  ASSERT_FALSE(res);
+  EXPECT_TRUE(receiver_failed);
+}
+
+TEST_F(ServerTest, PostWithHeadersAndContentReceiverError) {
+#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
+  using ClientT = SSLClient;
+#else
+  using ClientT = Client;
+#endif
+  TestWithHeadersAndContentReceiverError<ClientT>(cli_, 
+    [](ClientT& cli, const std::string& path, const Headers& headers, const std::string& body, 
+       const std::string& content_type, ContentReceiver receiver) {
+      return cli.Post(path, headers, body, content_type, receiver);
+    });
+}
+
+TEST_F(ServerTest, PuttWithHeadersAndContentReceiverError) {
+#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
+  using ClientT = SSLClient;
+#else
+  using ClientT = Client;
+#endif
+  TestWithHeadersAndContentReceiverError<ClientT>(cli_, 
+    [](ClientT& cli, const std::string& path, const Headers& headers, const std::string& body, 
+       const std::string& content_type, ContentReceiver receiver) {
+      return cli.Put(path, headers, body, content_type, receiver);
+    });
+}
+
+TEST_F(ServerTest, PatchWithHeadersAndContentReceiverError) {
+#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
+  using ClientT = SSLClient;
+#else
+  using ClientT = Client;
+#endif
+  TestWithHeadersAndContentReceiverError<ClientT>(cli_, 
+    [](ClientT& cli, const std::string& path, const Headers& headers, const std::string& body, 
+       const std::string& content_type, ContentReceiver receiver) {
+      return cli.Patch(path, headers, body, content_type, receiver);
+    });
+}
+
 TEST_F(ServerTest, PostQueryStringAndBody) {
   auto res =
       cli_.Post("/query-string-and-body?key=value", "content", "text/plain");