From 82fc7d5591237b49e3cb87e13ec4aec55c39a98b Mon Sep 17 00:00:00 2001 From: Thomas Tissot Date: Mon, 6 Aug 2018 11:54:52 +0200 Subject: [PATCH] Request cancelation feature This commit modifies the signature of the `Progress` callback so that its return value will indicate whether the request shall continue to be processed by returning `true`, or if it shall be aborted by returning `false`. Such modification will allow one to cancel an ongoing request before it has completed. When migrating, developers should modify there `Progress` callbacks to always return `true` by default in case there do not want to benefit from the cancelation feature. A few unit tests use cases were provided, but anyone should feel free to provide additional uses cases that they find relevant. --- httplib.h | 6 ++++-- test/test.cc | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+), 2 deletions(-) diff --git a/httplib.h b/httplib.h index bffdf91..dff8aad 100644 --- a/httplib.h +++ b/httplib.h @@ -107,7 +107,7 @@ std::pair make_range_header(uint64_t value, Args... ar typedef std::multimap Params; typedef std::smatch Match; -typedef std::function Progress; +typedef std::function Progress; struct MultipartFile { std::string filename; @@ -804,7 +804,9 @@ inline bool read_content_with_length(Stream& strm, std::string& out, size_t len, r += n; if (progress) { - progress(r, len); + if (!progress(r, len)) { + return false; + } } } diff --git a/test/test.cc b/test/test.cc index ca0c6e0..6169b60 100644 --- a/test/test.cc +++ b/test/test.cc @@ -230,6 +230,66 @@ TEST(ConnectionErrorTest, Timeout) ASSERT_TRUE(res == nullptr); } +TEST(CancelTest, NoCancel) { + auto host = "httpbin.org"; + auto sec = 5; + +#ifdef CPPHTTPLIB_OPENSSL_SUPPORT + auto port = 443; + httplib::SSLClient cli(host, port, sec); +#else + auto port = 80; + httplib::Client cli(host, port, sec); +#endif + + httplib::Headers headers; + auto res = cli.Get("/range/32", headers, [](uint64_t, uint64_t) { + return true; + }); + ASSERT_TRUE(res != nullptr); + EXPECT_EQ(res->body, "abcdefghijklmnopqrstuvwxyzabcdef"); + EXPECT_EQ(200, res->status); +} + +TEST(CancelTest, WithCancelSmallPayload) { + auto host = "httpbin.org"; + auto sec = 5; + +#ifdef CPPHTTPLIB_OPENSSL_SUPPORT + auto port = 443; + httplib::SSLClient cli(host, port, sec); +#else + auto port = 80; + httplib::Client cli(host, port, sec); +#endif + + httplib::Headers headers; + auto res = cli.Get("/range/32", headers, [](uint64_t, uint64_t) { + return false; + }); + ASSERT_TRUE(res == nullptr); +} + +TEST(CancelTest, WithCancelLargePayload) { + auto host = "httpbin.org"; + auto sec = 5; + +#ifdef CPPHTTPLIB_OPENSSL_SUPPORT + auto port = 443; + httplib::SSLClient cli(host, port, sec); +#else + auto port = 80; + httplib::Client cli(host, port, sec); +#endif + + uint32_t count = 0; + httplib::Headers headers; + auto res = cli.Get("/range/65536", headers, [&count](uint64_t, uint64_t) { + return (count++ == 0); + }); + ASSERT_TRUE(res == nullptr); +} + TEST(Server, BindAndListenSeparately) { Server svr; int port = svr.bind_to_any_port("localhost");