empty request after response get

This commit is contained in:
2019-06-26 05:59:00 +07:00
parent 6193e0487c
commit 5bf2d47e64
3 changed files with 170 additions and 108 deletions

View File

@@ -100,8 +100,8 @@ namespace curly_hpp
response(response&&) = default; response(response&&) = default;
response& operator=(response&&) = default; response& operator=(response&&) = default;
response(const response&) = default; response(const response&) = delete;
response& operator=(const response&) = default; response& operator=(const response&) = delete;
explicit response(response_code_t rc) noexcept; explicit response(response_code_t rc) noexcept;
response(response_code_t rc, headers_t h) noexcept; response(response_code_t rc, headers_t h) noexcept;
@@ -115,10 +115,18 @@ namespace curly_hpp
headers_t& headers() noexcept; headers_t& headers() noexcept;
const headers_t& headers() const noexcept; const headers_t& headers() const noexcept;
uploader_uptr& uploader() noexcept;
const uploader_uptr& uploader() const noexcept;
downloader_uptr& downloader() noexcept;
const downloader_uptr& downloader() const noexcept;
private: private:
response_code_t code_{0u}; response_code_t code_{0u};
content_t content_; content_t content_;
headers_t headers_; headers_t headers_;
uploader_uptr uploader_;
downloader_uptr downloader_;
}; };
} }
@@ -128,6 +136,7 @@ namespace curly_hpp
public: public:
enum class statuses { enum class statuses {
done, done,
empty,
failed, failed,
timeout, timeout,
pending, pending,
@@ -143,7 +152,7 @@ namespace curly_hpp
statuses wait() const noexcept; statuses wait() const noexcept;
statuses status() const noexcept; statuses status() const noexcept;
const response& get() const; response get();
const std::string& error() const noexcept; const std::string& error() const noexcept;
private: private:
internal_state_ptr state_; internal_state_ptr state_;
@@ -181,24 +190,36 @@ namespace curly_hpp
request_builder& uploader(uploader_uptr u) noexcept; request_builder& uploader(uploader_uptr u) noexcept;
request_builder& downloader(downloader_uptr d) noexcept; request_builder& downloader(downloader_uptr d) noexcept;
[[nodiscard]] const std::string& url() const noexcept; const std::string& url() const noexcept;
[[nodiscard]] methods method() const noexcept; methods method() const noexcept;
[[nodiscard]] const headers_t& headers() const noexcept; const headers_t& headers() const noexcept;
[[nodiscard]] bool verbose() const noexcept; bool verbose() const noexcept;
[[nodiscard]] bool verification() const noexcept; bool verification() const noexcept;
[[nodiscard]] std::uint32_t redirections() const noexcept; std::uint32_t redirections() const noexcept;
[[nodiscard]] time_sec_t response_timeout() const noexcept; time_sec_t response_timeout() const noexcept;
[[nodiscard]] time_sec_t connection_timeout() const noexcept; time_sec_t connection_timeout() const noexcept;
[[nodiscard]] content_t& content() noexcept; content_t& content() noexcept;
[[nodiscard]] const content_t& content() const noexcept; const content_t& content() const noexcept;
[[nodiscard]] uploader_uptr& uploader() noexcept; uploader_uptr& uploader() noexcept;
[[nodiscard]] const uploader_uptr& uploader() const noexcept; const uploader_uptr& uploader() const noexcept;
[[nodiscard]] downloader_uptr& downloader() noexcept; downloader_uptr& downloader() noexcept;
[[nodiscard]] const downloader_uptr& downloader() const noexcept; const downloader_uptr& downloader() const noexcept;
request perform();
template < typename Uploader, typename... Args >
request_builder& uploader(Args&&... args) {
return uploader(std::make_unique<Uploader>(std::forward<Args>(args)...));
}
template < typename Downloader, typename... Args >
request_builder& downloader(Args&&... args) {
return downloader(std::make_unique<Downloader>(std::forward<Args>(args)...));
}
private: private:
std::string url_; std::string url_;
methods method_{methods::get}; methods method_{methods::get};

View File

@@ -262,6 +262,22 @@ namespace curly_hpp
const headers_t& response::headers() const noexcept { const headers_t& response::headers() const noexcept {
return headers_; return headers_;
} }
uploader_uptr& response::uploader() noexcept {
return uploader_;
}
const uploader_uptr& response::uploader() const noexcept {
return uploader_;
}
downloader_uptr& response::downloader() noexcept {
return downloader_;
}
const downloader_uptr& response::downloader() const noexcept {
return downloader_;
}
} }
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
@@ -424,7 +440,7 @@ namespace curly_hpp
return status_; return status_;
} }
const response& get() const { response get() {
std::unique_lock<std::mutex> lock(mutex_); std::unique_lock<std::mutex> lock(mutex_);
cond_var_.wait(lock, [this](){ cond_var_.wait(lock, [this](){
return status_ != statuses::pending; return status_ != statuses::pending;
@@ -432,7 +448,8 @@ namespace curly_hpp
if ( status_ != statuses::done ) { if ( status_ != statuses::done ) {
throw exception("curly_hpp: response is unavailable"); throw exception("curly_hpp: response is unavailable");
} }
return response_; status_ = statuses::empty;
return std::move(response_);
} }
const std::string& error() const noexcept { const std::string& error() const noexcept {
@@ -556,7 +573,7 @@ namespace curly_hpp
return state_->status(); return state_->status();
} }
const response& request::get() const { response request::get() {
return state_->get(); return state_->get();
} }
@@ -698,6 +715,10 @@ namespace curly_hpp
const downloader_uptr& request_builder::downloader() const noexcept { const downloader_uptr& request_builder::downloader() const noexcept {
return downloader_; return downloader_;
} }
request request_builder::perform() {
return ::perform(*this);
}
} }
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------

View File

@@ -51,16 +51,17 @@ TEST_CASE("curly"){
net::auto_updater updater; net::auto_updater updater;
SECTION("wait") { SECTION("wait") {
auto req = net::perform(net::request_builder("https://httpbin.org/status/200")); auto req = net::request_builder("https://httpbin.org/delay/1").perform();
REQUIRE(req.status() == net::request::statuses::pending); REQUIRE(req.status() == net::request::statuses::pending);
REQUIRE(req.wait() == net::request::statuses::done); REQUIRE(req.wait() == net::request::statuses::done);
REQUIRE(req.status() == net::request::statuses::done); REQUIRE(req.status() == net::request::statuses::done);
REQUIRE(req.get().code() == 200u); auto resp = req.get();
REQUIRE(req.error().empty()); REQUIRE(resp.code() == 200u);
REQUIRE(req.status() == net::request::statuses::empty);
} }
SECTION("error") { SECTION("error") {
auto req = net::perform(net::request_builder("|||")); auto req = net::request_builder("|||").perform();
REQUIRE(req.wait() == net::request::statuses::failed); REQUIRE(req.wait() == net::request::statuses::failed);
REQUIRE(req.status() == net::request::statuses::failed); REQUIRE(req.status() == net::request::statuses::failed);
REQUIRE_FALSE(req.error().empty()); REQUIRE_FALSE(req.error().empty());
@@ -68,15 +69,13 @@ TEST_CASE("curly"){
SECTION("cancel") { SECTION("cancel") {
{ {
auto req = net::perform(net::request_builder() auto req = net::request_builder("https://httpbin.org/delay/1").perform();
.url("https://httpbin.org/delay/2"));
REQUIRE(req.cancel()); REQUIRE(req.cancel());
REQUIRE(req.status() == net::request::statuses::canceled); REQUIRE(req.status() == net::request::statuses::canceled);
REQUIRE(req.error().empty()); REQUIRE(req.error().empty());
} }
{ {
auto req = net::perform(net::request_builder() auto req = net::request_builder("https://httpbin.org/status/200").perform();
.url("https://httpbin.org/status/200"));
REQUIRE(req.wait() == net::request::statuses::done); REQUIRE(req.wait() == net::request::statuses::done);
REQUIRE_FALSE(req.cancel()); REQUIRE_FALSE(req.cancel());
REQUIRE(req.status() == net::request::statuses::done); REQUIRE(req.status() == net::request::statuses::done);
@@ -86,124 +85,142 @@ TEST_CASE("curly"){
SECTION("get") { SECTION("get") {
{ {
auto req = net::perform(net::request_builder("https://httpbin.org/status/204")); auto req = net::request_builder("https://httpbin.org/status/204").perform();
auto resp = req.get(); auto resp = req.get();
REQUIRE(req.status() == net::request::statuses::done); REQUIRE(req.status() == net::request::statuses::empty);
REQUIRE(resp.code() == 204u); REQUIRE(resp.code() == 204u);
} }
{ {
auto req = net::perform(net::request_builder() auto req = net::request_builder("https://httpbin.org/delay/2").perform();
.url("https://httpbin.org/delay/2"));
REQUIRE(req.cancel()); REQUIRE(req.cancel());
REQUIRE_THROWS_AS(req.get(), net::exception); REQUIRE_THROWS_AS(req.get(), net::exception);
REQUIRE(req.status() == net::request::statuses::canceled);
} }
{ {
auto req = net::perform(net::request_builder() auto req = net::request_builder("https://httpbin.org/delay/2")
.url("https://httpbin.org/delay/2") .response_timeout(net::time_sec_t(0))
.response_timeout(net::time_sec_t(0))); .perform();
REQUIRE(req.wait() == net::request::statuses::timeout); REQUIRE(req.wait() == net::request::statuses::timeout);
REQUIRE_THROWS_AS(req.get(), net::exception); REQUIRE_THROWS_AS(req.get(), net::exception);
REQUIRE(req.status() == net::request::statuses::timeout);
} }
} }
SECTION("http_methods") { SECTION("http_methods") {
{ {
auto req0 = net::perform(net::request_builder() auto req0 = net::request_builder()
.url("https://httpbin.org/put") .url("https://httpbin.org/put")
.method(net::methods::put)); .method(net::methods::put)
.perform();
REQUIRE(req0.get().code() == 200u); REQUIRE(req0.get().code() == 200u);
auto req1 = net::perform(net::request_builder() auto req1 = net::request_builder()
.url("https://httpbin.org/put") .url("https://httpbin.org/put")
.method(net::methods::get)); .method(net::methods::get)
.perform();
REQUIRE(req1.get().code() == 405u); REQUIRE(req1.get().code() == 405u);
auto req2 = net::perform(net::request_builder() auto req2 = net::request_builder()
.url("https://httpbin.org/put") .url("https://httpbin.org/put")
.method(net::methods::head)); .method(net::methods::head)
.perform();
REQUIRE(req2.get().code() == 405u); REQUIRE(req2.get().code() == 405u);
auto req3 = net::perform(net::request_builder() auto req3 = net::request_builder()
.url("https://httpbin.org/put") .url("https://httpbin.org/put")
.method(net::methods::post)); .method(net::methods::post)
.perform();
REQUIRE(req3.get().code() == 405u); REQUIRE(req3.get().code() == 405u);
} }
{ {
auto req0 = net::perform(net::request_builder() auto req0 = net::request_builder()
.url("https://httpbin.org/get") .url("https://httpbin.org/get")
.method(net::methods::put)); .method(net::methods::put)
.perform();
REQUIRE(req0.get().code() == 405u); REQUIRE(req0.get().code() == 405u);
auto req1 = net::perform(net::request_builder() auto req1 = net::request_builder()
.url("https://httpbin.org/get") .url("https://httpbin.org/get")
.method(net::methods::get)); .method(net::methods::get)
.perform();
REQUIRE(req1.get().code() == 200u); REQUIRE(req1.get().code() == 200u);
auto req2 = net::perform(net::request_builder() auto req2 = net::request_builder()
.url("https://httpbin.org/get") .url("https://httpbin.org/get")
.method(net::methods::head)); .method(net::methods::head)
.perform();
REQUIRE(req2.get().code() == 200u); REQUIRE(req2.get().code() == 200u);
auto req3 = net::perform(net::request_builder() auto req3 = net::request_builder()
.url("https://httpbin.org/get") .url("https://httpbin.org/get")
.method(net::methods::post)); .method(net::methods::post)
.perform();
REQUIRE(req3.get().code() == 405u); REQUIRE(req3.get().code() == 405u);
} }
{ {
auto req0 = net::perform(net::request_builder() auto req0 = net::request_builder()
.url("https://httpbin.org/post") .url("https://httpbin.org/post")
.method(net::methods::put)); .method(net::methods::put)
.perform();
REQUIRE(req0.get().code() == 405u); REQUIRE(req0.get().code() == 405u);
auto req1 = net::perform(net::request_builder() auto req1 = net::request_builder()
.url("https://httpbin.org/post") .url("https://httpbin.org/post")
.method(net::methods::get)); .method(net::methods::get)
.perform();
REQUIRE(req1.get().code() == 405u); REQUIRE(req1.get().code() == 405u);
auto req2 = net::perform(net::request_builder() auto req2 = net::request_builder()
.url("https://httpbin.org/post") .url("https://httpbin.org/post")
.method(net::methods::head)); .method(net::methods::head)
.perform();
REQUIRE(req2.get().code() == 405u); REQUIRE(req2.get().code() == 405u);
auto req3 = net::perform(net::request_builder() auto req3 = net::request_builder()
.url("https://httpbin.org/post") .url("https://httpbin.org/post")
.method(net::methods::post)); .method(net::methods::post)
.perform();
REQUIRE(req3.get().code() == 200u); REQUIRE(req3.get().code() == 200u);
} }
} }
SECTION("status_codes") { SECTION("status_codes") {
{ {
auto req = net::perform(net::request_builder() auto req = net::request_builder()
.url("https://httpbin.org/status/200") .url("https://httpbin.org/status/200")
.method(net::methods::put)); .method(net::methods::put)
.perform();
REQUIRE(req.get().code() == 200u); REQUIRE(req.get().code() == 200u);
} }
{ {
auto req = net::perform(net::request_builder() auto req = net::request_builder()
.url("https://httpbin.org/status/201") .url("https://httpbin.org/status/201")
.method(net::methods::get)); .method(net::methods::get)
.perform();
REQUIRE(req.get().code() == 201u); REQUIRE(req.get().code() == 201u);
} }
{ {
auto req = net::perform(net::request_builder() auto req = net::request_builder()
.url("https://httpbin.org/status/202") .url("https://httpbin.org/status/202")
.method(net::methods::head)); .method(net::methods::head)
.perform();
REQUIRE(req.get().code() == 202u); REQUIRE(req.get().code() == 202u);
} }
{ {
auto req = net::perform(net::request_builder() auto req = net::request_builder()
.url("https://httpbin.org/status/203") .url("https://httpbin.org/status/203")
.method(net::methods::post)); .method(net::methods::post)
.perform();
REQUIRE(req.get().code() == 203u); REQUIRE(req.get().code() == 203u);
} }
} }
SECTION("request_inspection") { SECTION("request_inspection") {
auto req = net::perform(net::request_builder() auto req = net::request_builder()
.url("https://httpbin.org/headers") .url("https://httpbin.org/headers")
.header("Custom-Header-1", "custom_header_value_1") .header("Custom-Header-1", "custom_header_value_1")
.header("Custom-Header-2", "custom header value 2")); .header("Custom-Header-2", "custom header value 2")
.perform();
const auto resp = req.get(); const auto resp = req.get();
const auto content_j = json::parse(resp.content().as_string_view()); const auto content_j = json::parse(resp.content().as_string_view());
REQUIRE(content_j["headers"]["Custom-Header-1"] == "custom_header_value_1"); REQUIRE(content_j["headers"]["Custom-Header-1"] == "custom_header_value_1");
@@ -212,17 +229,20 @@ TEST_CASE("curly"){
SECTION("response_inspection") { SECTION("response_inspection") {
{ {
auto req = net::perform(net::request_builder() auto req = net::request_builder()
.url("https://httpbin.org/response-headers?hello=world&world=hello")); .url("https://httpbin.org/response-headers?hello=world&world=hello")
.method(net::methods::get)
.perform();
const auto resp = req.get(); const auto resp = req.get();
const auto content_j = json::parse(resp.content().as_string_view()); const auto content_j = json::parse(resp.content().as_string_view());
REQUIRE(content_j["hello"] == "world"); REQUIRE(content_j["hello"] == "world");
REQUIRE(content_j["world"] == "hello"); REQUIRE(content_j["world"] == "hello");
} }
{ {
auto req = net::perform(net::request_builder() auto req = net::request_builder()
.url("https://httpbin.org/response-headers?hello=world&world=hello") .url("https://httpbin.org/response-headers?hello=world&world=hello")
.method(net::methods::post)); .method(net::methods::post)
.perform();
const auto resp = req.get(); const auto resp = req.get();
const auto content_j = json::parse(resp.content().as_string_view()); const auto content_j = json::parse(resp.content().as_string_view());
REQUIRE(content_j["hello"] == "world"); REQUIRE(content_j["hello"] == "world");
@@ -232,23 +252,26 @@ TEST_CASE("curly"){
SECTION("dynamic_data") { SECTION("dynamic_data") {
{ {
auto req = net::perform(net::request_builder() auto req = net::request_builder()
.url("https://httpbin.org/base64/SFRUUEJJTiBpcyBhd2Vzb21l")); .url("https://httpbin.org/base64/SFRUUEJJTiBpcyBhd2Vzb21l")
.perform();
const auto resp = req.get(); const auto resp = req.get();
REQUIRE(resp.content().as_string_view() == "HTTPBIN is awesome"); REQUIRE(resp.content().as_string_view() == "HTTPBIN is awesome");
REQUIRE(req.error().empty()); REQUIRE(req.error().empty());
} }
{ {
auto req = net::perform(net::request_builder() auto req = net::request_builder()
.url("https://httpbin.org/delay/10") .url("https://httpbin.org/delay/10")
.response_timeout(net::time_sec_t(0))); .response_timeout(net::time_sec_t(0))
.perform();
REQUIRE(req.wait() == net::request::statuses::timeout); REQUIRE(req.wait() == net::request::statuses::timeout);
REQUIRE_FALSE(req.error().empty()); REQUIRE_FALSE(req.error().empty());
} }
{ {
auto req = net::perform(net::request_builder() auto req = net::request_builder()
.url("https://httpbin.org/delay/10") .url("https://httpbin.org/delay/10")
.response_timeout(net::time_sec_t(1))); .response_timeout(net::time_sec_t(1))
.perform();
REQUIRE(req.wait() == net::request::statuses::timeout); REQUIRE(req.wait() == net::request::statuses::timeout);
REQUIRE_FALSE(req.error().empty()); REQUIRE_FALSE(req.error().empty());
} }
@@ -256,84 +279,81 @@ TEST_CASE("curly"){
SECTION("binary") { SECTION("binary") {
{ {
auto req = net::perform(net::request_builder() auto resp = net::request_builder()
.url("https://httpbin.org/image/png") .url("https://httpbin.org/image/png")
.method(net::methods::get)); .method(net::methods::get)
const auto resp = req.get(); .perform().get();
REQUIRE(resp.code() == 200u); REQUIRE(resp.code() == 200u);
REQUIRE(resp.headers().count("Content-Type")); REQUIRE(resp.headers().count("Content-Type"));
REQUIRE(resp.headers().at("Content-Type") == "image/png"); REQUIRE(resp.headers().at("Content-Type") == "image/png");
REQUIRE(untests::png_data_length == resp.content().size()); REQUIRE(untests::png_data_length == resp.content().size());
REQUIRE(!std::memcmp( REQUIRE(!std::memcmp(resp.content().data().data(), untests::png_data, untests::png_data_length));
resp.content().data().data(),
untests::png_data,
untests::png_data_length));
} }
{ {
auto req = net::perform(net::request_builder() auto resp = net::request_builder()
.url("https://httpbin.org/image/jpeg") .url("https://httpbin.org/image/jpeg")
.method(net::methods::get)); .method(net::methods::get)
const auto resp = req.get(); .perform().get();
REQUIRE(resp.code() == 200u); REQUIRE(resp.code() == 200u);
REQUIRE(resp.headers().count("Content-Type")); REQUIRE(resp.headers().count("Content-Type"));
REQUIRE(resp.headers().at("Content-Type") == "image/jpeg"); REQUIRE(resp.headers().at("Content-Type") == "image/jpeg");
REQUIRE(untests::jpeg_data_length == resp.content().size()); REQUIRE(untests::jpeg_data_length == resp.content().size());
REQUIRE(!std::memcmp( REQUIRE(!std::memcmp(resp.content().data().data(), untests::jpeg_data, untests::jpeg_data_length));
resp.content().data().data(),
untests::jpeg_data,
untests::jpeg_data_length));
} }
} }
SECTION("redirects") { SECTION("redirects") {
{ {
auto req = net::perform(net::request_builder() auto req = net::request_builder()
.url("https://httpbin.org/redirect/2") .url("https://httpbin.org/redirect/2")
.method(net::methods::get)); .method(net::methods::get)
.perform();
REQUIRE(req.get().code() == 200u); REQUIRE(req.get().code() == 200u);
} }
{ {
auto req = net::perform(net::request_builder() auto req = net::request_builder()
.url("https://httpbin.org/absolute-redirect/2") .url("https://httpbin.org/absolute-redirect/2")
.method(net::methods::get)); .method(net::methods::get)
.perform();
REQUIRE(req.get().code() == 200u); REQUIRE(req.get().code() == 200u);
} }
{ {
auto req = net::perform(net::request_builder() auto req = net::request_builder()
.url("https://httpbin.org/relative-redirect/2") .url("https://httpbin.org/relative-redirect/2")
.method(net::methods::get)); .method(net::methods::get)
.perform();
REQUIRE(req.get().code() == 200u); REQUIRE(req.get().code() == 200u);
} }
} }
SECTION("request_body") { SECTION("request_body") {
{ {
auto req = net::perform(net::request_builder() auto resp = net::request_builder()
.url("https://httpbin.org/anything") .url("https://httpbin.org/anything")
.method(net::methods::put) .method(net::methods::put)
.header("Content-Type", "application/json") .header("Content-Type", "application/json")
.content(R"({"hello":"world"})")); .content(R"({"hello":"world"})")
const auto resp = req.get(); .perform().get();
const auto content_j = json::parse(resp.content().as_string_view()); const auto content_j = json::parse(resp.content().as_string_view());
REQUIRE(content_j["data"] == R"({"hello":"world"})"); REQUIRE(content_j["data"] == R"({"hello":"world"})");
} }
{ {
auto req = net::perform(net::request_builder() auto resp = net::request_builder()
.url("https://httpbin.org/anything") .url("https://httpbin.org/anything")
.method(net::methods::post) .method(net::methods::post)
.header("Content-Type", "application/json") .header("Content-Type", "application/json")
.content(R"({"hello":"world"})")); .content(R"({"hello":"world"})")
const auto resp = req.get(); .perform().get();
const auto content_j = json::parse(resp.content().as_string_view()); const auto content_j = json::parse(resp.content().as_string_view());
REQUIRE(content_j["data"] == R"({"hello":"world"})"); REQUIRE(content_j["data"] == R"({"hello":"world"})");
} }
{ {
auto req = net::perform(net::request_builder() auto resp = net::request_builder()
.url("https://httpbin.org/anything") .url("https://httpbin.org/anything")
.method(net::methods::post) .method(net::methods::post)
.header("Content-Type", "application/x-www-form-urlencoded") .header("Content-Type", "application/x-www-form-urlencoded")
.content("hello=world&world=hello")); .content("hello=world&world=hello")
const auto resp = req.get(); .perform().get();
const auto content_j = json::parse(resp.content().as_string_view()); const auto content_j = json::parse(resp.content().as_string_view());
REQUIRE(content_j["form"]["hello"] == "world"); REQUIRE(content_j["form"]["hello"] == "world");
REQUIRE(content_j["form"]["world"] == "hello"); REQUIRE(content_j["form"]["world"] == "hello");