mirror of
https://github.com/BlackMATov/curly.hpp.git
synced 2025-12-13 03:29:37 +07:00
@@ -51,9 +51,22 @@ endif()
|
||||
# library
|
||||
#
|
||||
|
||||
file(GLOB_RECURSE CURLY_HPP_HEADERS
|
||||
headers/curly.hpp/*.hpp
|
||||
headers/curly.hpp/*.inl)
|
||||
|
||||
file(GLOB_RECURSE CURLY_HPP_SOURCES
|
||||
sources/curly.hpp/*.cpp
|
||||
sources/curly.hpp/*.hpp
|
||||
sources/curly.hpp/*.inl)
|
||||
|
||||
add_library(${PROJECT_NAME} STATIC
|
||||
headers/curly.hpp/curly.hpp
|
||||
sources/curly.cpp)
|
||||
${CURLY_HPP_HEADERS}
|
||||
${CURLY_HPP_SOURCES})
|
||||
|
||||
source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} FILES
|
||||
${CURLY_HPP_HEADERS}
|
||||
${CURLY_HPP_SOURCES})
|
||||
|
||||
target_include_directories(${PROJECT_NAME}
|
||||
PUBLIC headers)
|
||||
|
||||
20
README.md
20
README.md
@@ -56,7 +56,7 @@ target_link_libraries(your_project_target curly.hpp)
|
||||
namespace net = curly_hpp;
|
||||
|
||||
// creates and hold a separate thread for automatically update async requests
|
||||
net::auto_performer performer;
|
||||
net::performer performer;
|
||||
|
||||
// also, you can update requests manually from your favorite thread
|
||||
net::perform();
|
||||
@@ -67,12 +67,12 @@ net::perform();
|
||||
```cpp
|
||||
// makes a GET request and async send it
|
||||
auto request = net::request_builder()
|
||||
.method(net::methods::get)
|
||||
.method(net::http_method::GET)
|
||||
.url("http://www.httpbin.org/get")
|
||||
.send();
|
||||
|
||||
// synchronous waits and get a response
|
||||
auto response = request.get();
|
||||
// synchronous waits and take a response
|
||||
auto response = request.take();
|
||||
|
||||
// prints results
|
||||
std::cout << "Status code: " << response.http_code() << std::endl;
|
||||
@@ -97,13 +97,13 @@ std::cout << "Body content: " << response.content.as_string_view() << std::endl;
|
||||
|
||||
```cpp
|
||||
auto request = net::request_builder()
|
||||
.method(net::methods::post)
|
||||
.method(net::http_method::POST)
|
||||
.url("http://www.httpbin.org/post")
|
||||
.header("Content-Type", "application/json")
|
||||
.content(R"({"hello" : "world"})")
|
||||
.send();
|
||||
|
||||
auto response = request.get();
|
||||
auto response = request.take();
|
||||
std::cout << "Body content: " << response.content.as_string_view() << std::endl;
|
||||
std::cout << "Content Length: " << response.headers["content-length"] << std::endl;
|
||||
|
||||
@@ -138,11 +138,11 @@ auto request = net::request_builder()
|
||||
request.wait();
|
||||
|
||||
if ( request.is_done() ) {
|
||||
auto response = request.get();
|
||||
auto response = request.take();
|
||||
std::cout << "Status code: " << response.http_code() << std::endl;
|
||||
} else {
|
||||
// throws net::exception because a response is unavailable
|
||||
// auto response = request.get();
|
||||
// auto response = request.take();
|
||||
|
||||
std::cout << "Error message: " << request.get_error() << std::endl;
|
||||
}
|
||||
@@ -156,7 +156,7 @@ if ( request.is_done() ) {
|
||||
auto request = net::request_builder("http://www.httpbin.org/get")
|
||||
.callback([](net::request request){
|
||||
if ( request.is_done() ) {
|
||||
auto response = request.get();
|
||||
auto response = request.take();
|
||||
std::cout << "Status code: " << response.http_code() << std::endl;
|
||||
} else {
|
||||
std::cout << "Error message: " << request.get_error() << std::endl;
|
||||
@@ -217,7 +217,7 @@ private:
|
||||
};
|
||||
|
||||
net::request_builder()
|
||||
.method(net::methods::post)
|
||||
.method(net::http_method::POST)
|
||||
.url("https://httpbin.org/anything")
|
||||
.uploader<file_uploader>("image.jpeg")
|
||||
.send().wait();
|
||||
|
||||
@@ -6,51 +6,48 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cctype>
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstddef>
|
||||
|
||||
#include <atomic>
|
||||
#include <chrono>
|
||||
#include <thread>
|
||||
|
||||
#include <map>
|
||||
#include <chrono>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <utility>
|
||||
#include <algorithm>
|
||||
#include <stdexcept>
|
||||
#include <functional>
|
||||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
namespace curly_hpp
|
||||
{
|
||||
class exception final : public std::runtime_error {
|
||||
public:
|
||||
explicit exception(const char* what);
|
||||
explicit exception(const std::string& what);
|
||||
};
|
||||
|
||||
struct icase_string_compare final {
|
||||
using is_transparent = void;
|
||||
bool operator()(
|
||||
std::string_view l,
|
||||
std::string_view r) const noexcept;
|
||||
};
|
||||
|
||||
enum class methods {
|
||||
put,
|
||||
get,
|
||||
head,
|
||||
post
|
||||
};
|
||||
class request;
|
||||
class response;
|
||||
class request_builder;
|
||||
|
||||
using http_code_t = std::uint16_t;
|
||||
using headers_t = std::map<std::string, std::string, icase_string_compare>;
|
||||
|
||||
using time_sec_t = std::chrono::seconds;
|
||||
using time_ms_t = std::chrono::milliseconds;
|
||||
using time_point_t = std::chrono::steady_clock::time_point;
|
||||
|
||||
class request;
|
||||
using callback_t = std::function<void(request)>;
|
||||
enum class http_method {
|
||||
DEL,
|
||||
PUT,
|
||||
GET,
|
||||
HEAD,
|
||||
POST,
|
||||
PATCH,
|
||||
OPTIONS
|
||||
};
|
||||
|
||||
class upload_handler {
|
||||
public:
|
||||
@@ -65,8 +62,51 @@ namespace curly_hpp
|
||||
virtual std::size_t write(const char* src, std::size_t size) = 0;
|
||||
};
|
||||
|
||||
class progress_handler {
|
||||
public:
|
||||
virtual ~progress_handler() {}
|
||||
virtual float update(
|
||||
std::size_t dnow, std::size_t dtotal,
|
||||
std::size_t unow, std::size_t utotal) = 0;
|
||||
};
|
||||
|
||||
using callback_t = std::function<void(request)>;
|
||||
using uploader_uptr = std::unique_ptr<upload_handler>;
|
||||
using downloader_uptr = std::unique_ptr<download_handler>;
|
||||
using progressor_uptr = std::unique_ptr<progress_handler>;
|
||||
}
|
||||
|
||||
namespace curly_hpp
|
||||
{
|
||||
class exception final : public std::runtime_error {
|
||||
public:
|
||||
explicit exception(const char* what)
|
||||
: std::runtime_error(what) {}
|
||||
|
||||
explicit exception(const std::string& what)
|
||||
: std::runtime_error(what) {}
|
||||
};
|
||||
}
|
||||
|
||||
namespace curly_hpp
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
struct icase_string_compare final {
|
||||
using is_transparent = void;
|
||||
bool operator()(std::string_view l, std::string_view r) const noexcept {
|
||||
return std::lexicographical_compare(
|
||||
l.begin(), l.end(), r.begin(), r.end(),
|
||||
[](const char lc, const char rc) noexcept {
|
||||
return std::tolower(lc) < std::tolower(rc);
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
using headers_t = std::map<
|
||||
std::string, std::string,
|
||||
detail::icase_string_compare>;
|
||||
}
|
||||
|
||||
namespace curly_hpp
|
||||
@@ -81,15 +121,31 @@ namespace curly_hpp
|
||||
content_t(const content_t&) = default;
|
||||
content_t& operator=(const content_t&) = default;
|
||||
|
||||
content_t(std::string_view data);
|
||||
content_t(std::vector<char> data) noexcept;
|
||||
content_t(std::string_view data)
|
||||
: data_(data.cbegin(), data.cend() ) {}
|
||||
|
||||
std::size_t size() const noexcept;
|
||||
std::vector<char>& data() noexcept;
|
||||
const std::vector<char>& data() const noexcept;
|
||||
content_t(std::vector<char> data) noexcept
|
||||
: data_(std::move(data)) {}
|
||||
|
||||
std::string as_string_copy() const;
|
||||
std::string_view as_string_view() const noexcept;
|
||||
std::size_t size() const noexcept {
|
||||
return data_.size();
|
||||
}
|
||||
|
||||
std::vector<char>& data() noexcept {
|
||||
return data_;
|
||||
}
|
||||
|
||||
const std::vector<char>& data() const noexcept {
|
||||
return data_;
|
||||
}
|
||||
|
||||
std::string as_string_copy() const {
|
||||
return {data_.data(), data_.size()};
|
||||
}
|
||||
|
||||
std::string_view as_string_view() const noexcept {
|
||||
return {data_.data(), data_.size()};
|
||||
}
|
||||
private:
|
||||
std::vector<char> data_;
|
||||
};
|
||||
@@ -107,15 +163,22 @@ namespace curly_hpp
|
||||
response(const response&) = delete;
|
||||
response& operator=(const response&) = delete;
|
||||
|
||||
explicit response(http_code_t c) noexcept;
|
||||
explicit response(http_code_t c) noexcept
|
||||
: http_code_(c) {}
|
||||
|
||||
bool is_http_error() const noexcept;
|
||||
http_code_t http_code() const noexcept;
|
||||
bool is_http_error() const noexcept {
|
||||
return http_code_ >= 400u;
|
||||
}
|
||||
|
||||
http_code_t http_code() const noexcept {
|
||||
return http_code_;
|
||||
}
|
||||
public:
|
||||
content_t content;
|
||||
headers_t headers;
|
||||
uploader_uptr uploader;
|
||||
downloader_uptr downloader;
|
||||
progressor_uptr progressor;
|
||||
private:
|
||||
http_code_t http_code_{0u};
|
||||
};
|
||||
@@ -123,16 +186,16 @@ namespace curly_hpp
|
||||
|
||||
namespace curly_hpp
|
||||
{
|
||||
enum class req_status {
|
||||
done,
|
||||
empty,
|
||||
failed,
|
||||
timeout,
|
||||
pending,
|
||||
canceled
|
||||
};
|
||||
|
||||
class request final {
|
||||
public:
|
||||
enum class statuses {
|
||||
done,
|
||||
empty,
|
||||
failed,
|
||||
timeout,
|
||||
pending,
|
||||
canceled
|
||||
};
|
||||
public:
|
||||
class internal_state;
|
||||
using internal_state_ptr = std::shared_ptr<internal_state>;
|
||||
@@ -140,20 +203,21 @@ namespace curly_hpp
|
||||
request(internal_state_ptr);
|
||||
|
||||
bool cancel() noexcept;
|
||||
statuses status() const noexcept;
|
||||
float progress() const noexcept;
|
||||
req_status status() const noexcept;
|
||||
|
||||
bool is_done() const noexcept;
|
||||
bool is_pending() const noexcept;
|
||||
|
||||
statuses wait() const noexcept;
|
||||
statuses wait_for(time_ms_t ms) const noexcept;
|
||||
statuses wait_until(time_point_t tp) const noexcept;
|
||||
req_status wait() const noexcept;
|
||||
req_status wait_for(time_ms_t ms) const noexcept;
|
||||
req_status wait_until(time_point_t tp) const noexcept;
|
||||
|
||||
statuses wait_callback() const noexcept;
|
||||
statuses wait_callback_for(time_ms_t ms) const noexcept;
|
||||
statuses wait_callback_until(time_point_t tp) const noexcept;
|
||||
req_status wait_callback() const noexcept;
|
||||
req_status wait_callback_for(time_ms_t ms) const noexcept;
|
||||
req_status wait_callback_until(time_point_t tp) const noexcept;
|
||||
|
||||
response get();
|
||||
response take();
|
||||
const std::string& get_error() const noexcept;
|
||||
std::exception_ptr get_callback_exception() const noexcept;
|
||||
private:
|
||||
@@ -173,12 +237,12 @@ namespace curly_hpp
|
||||
request_builder(const request_builder&) = delete;
|
||||
request_builder& operator=(const request_builder&) = delete;
|
||||
|
||||
explicit request_builder(methods m) noexcept;
|
||||
explicit request_builder(http_method m) noexcept;
|
||||
explicit request_builder(std::string u) noexcept;
|
||||
explicit request_builder(methods m, std::string u) noexcept;
|
||||
explicit request_builder(http_method m, std::string u) noexcept;
|
||||
|
||||
request_builder& url(std::string u) noexcept;
|
||||
request_builder& method(methods m) noexcept;
|
||||
request_builder& method(http_method m) noexcept;
|
||||
request_builder& header(std::string key, std::string value);
|
||||
|
||||
request_builder& verbose(bool v) noexcept;
|
||||
@@ -193,9 +257,10 @@ namespace curly_hpp
|
||||
request_builder& callback(callback_t c) noexcept;
|
||||
request_builder& uploader(uploader_uptr u) noexcept;
|
||||
request_builder& downloader(downloader_uptr d) noexcept;
|
||||
request_builder& progressor(progressor_uptr p) noexcept;
|
||||
|
||||
const std::string& url() const noexcept;
|
||||
methods method() const noexcept;
|
||||
http_method method() const noexcept;
|
||||
const headers_t& headers() const noexcept;
|
||||
|
||||
bool verbose() const noexcept;
|
||||
@@ -217,6 +282,9 @@ namespace curly_hpp
|
||||
downloader_uptr& downloader() noexcept;
|
||||
const downloader_uptr& downloader() const noexcept;
|
||||
|
||||
progressor_uptr& progressor() noexcept;
|
||||
const progressor_uptr& progressor() const noexcept;
|
||||
|
||||
request send();
|
||||
|
||||
template < typename Callback >
|
||||
@@ -236,9 +304,15 @@ namespace curly_hpp
|
||||
static_assert(std::is_base_of_v<download_handler, Downloader>);
|
||||
return downloader(std::make_unique<Downloader>(std::forward<Args>(args)...));
|
||||
}
|
||||
|
||||
template < typename Progressor, typename... Args >
|
||||
request_builder& progressor(Args&&... args) {
|
||||
static_assert(std::is_base_of_v<progress_handler, Progressor>);
|
||||
return progressor(std::make_unique<Progressor>(std::forward<Args>(args)...));
|
||||
}
|
||||
private:
|
||||
std::string url_;
|
||||
methods method_{methods::get};
|
||||
http_method method_{http_method::GET};
|
||||
headers_t headers_;
|
||||
bool verbose_{false};
|
||||
bool verification_{false};
|
||||
@@ -251,15 +325,16 @@ namespace curly_hpp
|
||||
callback_t callback_;
|
||||
uploader_uptr uploader_;
|
||||
downloader_uptr downloader_;
|
||||
progressor_uptr progressor_;
|
||||
};
|
||||
}
|
||||
|
||||
namespace curly_hpp
|
||||
{
|
||||
class auto_performer final {
|
||||
class performer final {
|
||||
public:
|
||||
auto_performer();
|
||||
~auto_performer() noexcept;
|
||||
performer();
|
||||
~performer() noexcept;
|
||||
|
||||
time_ms_t wait_activity() const noexcept;
|
||||
void wait_activity(time_ms_t ms) noexcept;
|
||||
|
||||
@@ -6,13 +6,9 @@
|
||||
|
||||
#include <curly.hpp/curly.hpp>
|
||||
|
||||
#include <cctype>
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
|
||||
#include <mutex>
|
||||
#include <queue>
|
||||
#include <algorithm>
|
||||
#include <type_traits>
|
||||
#include <condition_variable>
|
||||
|
||||
#ifndef NOMINMAX
|
||||
@@ -81,6 +77,23 @@ namespace
|
||||
private:
|
||||
data_t& data_;
|
||||
};
|
||||
|
||||
class default_progressor final : public progress_handler {
|
||||
public:
|
||||
default_progressor() = default;
|
||||
|
||||
float update(
|
||||
std::size_t dnow, std::size_t dtotal,
|
||||
std::size_t unow, std::size_t utotal) override
|
||||
{
|
||||
double now_d = static_cast<double>(dnow + unow);
|
||||
double total_d = static_cast<double>(dtotal + utotal);
|
||||
double progress_d = total_d > 0.0
|
||||
? static_cast<float>(now_d / total_d)
|
||||
: 0.f;
|
||||
return static_cast<float>(std::min(std::max(progress_d, 0.0), 1.0));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
@@ -96,18 +109,26 @@ namespace
|
||||
template < typename T >
|
||||
class mt_queue final {
|
||||
public:
|
||||
void enqueue(T v) {
|
||||
void enqueue(T&& v) {
|
||||
std::lock_guard<std::mutex> guard(mutex_);
|
||||
queue_.push(std::move(v));
|
||||
cvar_.notify_all();
|
||||
}
|
||||
|
||||
bool try_dequeue(T& v) {
|
||||
void enqueue(const T& v) {
|
||||
std::lock_guard<std::mutex> guard(mutex_);
|
||||
queue_.push(v);
|
||||
cvar_.notify_all();
|
||||
}
|
||||
|
||||
bool try_dequeue(T& v) noexcept(
|
||||
std::is_nothrow_move_assignable_v<T>)
|
||||
{
|
||||
std::lock_guard<std::mutex> guard(mutex_);
|
||||
if ( queue_.empty() ) {
|
||||
return false;
|
||||
}
|
||||
v = queue_.front();
|
||||
v = std::move(queue_.front());
|
||||
queue_.pop();
|
||||
return true;
|
||||
}
|
||||
@@ -117,9 +138,25 @@ namespace
|
||||
return queue_.empty();
|
||||
}
|
||||
|
||||
bool wait_content_for(time_ms_t ms) const noexcept {
|
||||
void wait() const noexcept {
|
||||
std::unique_lock<std::mutex> lock(mutex_);
|
||||
return cvar_.wait_for(lock, ms, [this](){
|
||||
cvar_.wait(lock, [this](){
|
||||
return !queue_.empty();
|
||||
});
|
||||
}
|
||||
|
||||
template < typename Rep, typename Period >
|
||||
bool wait_for(const std::chrono::duration<Rep, Period> duration) const noexcept {
|
||||
std::unique_lock<std::mutex> lock(mutex_);
|
||||
return cvar_.wait_for(lock, duration, [this](){
|
||||
return !queue_.empty();
|
||||
});
|
||||
}
|
||||
|
||||
template < typename Clock, typename Duration >
|
||||
bool wait_until(const std::chrono::time_point<Clock, Duration>& time) const {
|
||||
std::unique_lock<std::mutex> lock(mutex_);
|
||||
return cvar_.wait_until(lock, time, [this](){
|
||||
return !queue_.empty();
|
||||
});
|
||||
}
|
||||
@@ -213,96 +250,6 @@ namespace
|
||||
std::unique_ptr<curl_state> curl_state::self_;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
//
|
||||
// exception
|
||||
//
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
namespace curly_hpp
|
||||
{
|
||||
exception::exception(const char* what)
|
||||
: std::runtime_error(what) {}
|
||||
|
||||
exception::exception(const std::string& what)
|
||||
: std::runtime_error(what) {}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
//
|
||||
// icase_string_compare
|
||||
//
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
namespace curly_hpp
|
||||
{
|
||||
bool icase_string_compare::operator()(
|
||||
std::string_view l,
|
||||
std::string_view r) const noexcept
|
||||
{
|
||||
return std::lexicographical_compare(
|
||||
l.begin(), l.end(), r.begin(), r.end(),
|
||||
[](const auto lc, const auto rc) noexcept {
|
||||
return std::tolower(lc) < std::tolower(rc);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
//
|
||||
// content_t
|
||||
//
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
namespace curly_hpp
|
||||
{
|
||||
content_t::content_t(std::string_view data)
|
||||
: data_(data.cbegin(), data.cend() ) {}
|
||||
|
||||
content_t::content_t(std::vector<char> data) noexcept
|
||||
: data_(std::move(data)) {}
|
||||
|
||||
std::size_t content_t::size() const noexcept {
|
||||
return data_.size();
|
||||
}
|
||||
|
||||
std::vector<char>& content_t::data() noexcept {
|
||||
return data_;
|
||||
}
|
||||
|
||||
const std::vector<char>& content_t::data() const noexcept {
|
||||
return data_;
|
||||
}
|
||||
|
||||
std::string content_t::as_string_copy() const {
|
||||
return {data_.data(), data_.size()};
|
||||
}
|
||||
|
||||
std::string_view content_t::as_string_view() const noexcept {
|
||||
return {data_.data(), data_.size()};
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
//
|
||||
// response
|
||||
//
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
namespace curly_hpp
|
||||
{
|
||||
response::response(http_code_t c) noexcept
|
||||
: http_code_(c) {}
|
||||
|
||||
bool response::is_http_error() const noexcept {
|
||||
return http_code_ >= 400u;
|
||||
}
|
||||
|
||||
http_code_t response::http_code() const noexcept {
|
||||
return http_code_;
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
//
|
||||
// request
|
||||
@@ -323,6 +270,10 @@ namespace curly_hpp
|
||||
if ( !breq_.downloader() ) {
|
||||
breq_.downloader<default_downloader>(&response_content_);
|
||||
}
|
||||
|
||||
if ( !breq_.progressor() ) {
|
||||
breq_.progressor<default_progressor>();
|
||||
}
|
||||
}
|
||||
|
||||
void enqueue(CURLM* curlm) {
|
||||
@@ -357,6 +308,10 @@ namespace curly_hpp
|
||||
curl_easy_setopt(curlh_.get(), CURLOPT_WRITEDATA, this);
|
||||
curl_easy_setopt(curlh_.get(), CURLOPT_WRITEFUNCTION, &s_download_callback_);
|
||||
|
||||
curl_easy_setopt(curlh_.get(), CURLOPT_NOPROGRESS, 0l);
|
||||
curl_easy_setopt(curlh_.get(), CURLOPT_XFERINFODATA, this);
|
||||
curl_easy_setopt(curlh_.get(), CURLOPT_XFERINFOFUNCTION, &s_progress_callback_);
|
||||
|
||||
curl_easy_setopt(curlh_.get(), CURLOPT_HEADERDATA, this);
|
||||
curl_easy_setopt(curlh_.get(), CURLOPT_HEADERFUNCTION, &s_header_callback_);
|
||||
|
||||
@@ -365,22 +320,38 @@ namespace curly_hpp
|
||||
curl_easy_setopt(curlh_.get(), CURLOPT_VERBOSE, breq_.verbose() ? 1l : 0l);
|
||||
|
||||
switch ( breq_.method() ) {
|
||||
case methods::put:
|
||||
case http_method::DEL:
|
||||
curl_easy_setopt(curlh_.get(), CURLOPT_CUSTOMREQUEST, "DELETE");
|
||||
curl_easy_setopt(curlh_.get(), CURLOPT_POST, 1l);
|
||||
curl_easy_setopt(curlh_.get(), CURLOPT_POSTFIELDSIZE_LARGE,
|
||||
static_cast<curl_off_t>(breq_.uploader()->size()));
|
||||
break;
|
||||
case http_method::PUT:
|
||||
curl_easy_setopt(curlh_.get(), CURLOPT_UPLOAD, 1l);
|
||||
curl_easy_setopt(curlh_.get(), CURLOPT_INFILESIZE_LARGE,
|
||||
static_cast<curl_off_t>(breq_.uploader()->size()));
|
||||
break;
|
||||
case methods::get:
|
||||
case http_method::GET:
|
||||
curl_easy_setopt(curlh_.get(), CURLOPT_HTTPGET, 1l);
|
||||
break;
|
||||
case methods::head:
|
||||
case http_method::HEAD:
|
||||
curl_easy_setopt(curlh_.get(), CURLOPT_NOBODY, 1l);
|
||||
break;
|
||||
case methods::post:
|
||||
case http_method::POST:
|
||||
curl_easy_setopt(curlh_.get(), CURLOPT_POST, 1l);
|
||||
curl_easy_setopt(curlh_.get(), CURLOPT_POSTFIELDSIZE_LARGE,
|
||||
static_cast<curl_off_t>(breq_.uploader()->size()));
|
||||
break;
|
||||
case http_method::PATCH:
|
||||
curl_easy_setopt(curlh_.get(), CURLOPT_CUSTOMREQUEST, "PATCH");
|
||||
curl_easy_setopt(curlh_.get(), CURLOPT_UPLOAD, 1l);
|
||||
curl_easy_setopt(curlh_.get(), CURLOPT_INFILESIZE_LARGE,
|
||||
static_cast<curl_off_t>(breq_.uploader()->size()));
|
||||
break;
|
||||
case http_method::OPTIONS:
|
||||
curl_easy_setopt(curlh_.get(), CURLOPT_CUSTOMREQUEST, "OPTIONS");
|
||||
curl_easy_setopt(curlh_.get(), CURLOPT_NOBODY, 1l);
|
||||
break;
|
||||
default:
|
||||
throw exception("curly_hpp: unexpected request method");
|
||||
}
|
||||
@@ -418,6 +389,21 @@ namespace curly_hpp
|
||||
void dequeue(CURLM* curlm) noexcept {
|
||||
std::lock_guard<std::mutex> guard(mutex_);
|
||||
if ( curlh_ ) {
|
||||
curl_easy_setopt(curlh_.get(), CURLOPT_PRIVATE, nullptr);
|
||||
|
||||
curl_easy_setopt(curlh_.get(), CURLOPT_READDATA, nullptr);
|
||||
curl_easy_setopt(curlh_.get(), CURLOPT_READFUNCTION, nullptr);
|
||||
|
||||
curl_easy_setopt(curlh_.get(), CURLOPT_WRITEDATA, nullptr);
|
||||
curl_easy_setopt(curlh_.get(), CURLOPT_WRITEFUNCTION, nullptr);
|
||||
|
||||
curl_easy_setopt(curlh_.get(), CURLOPT_NOPROGRESS, 1l);
|
||||
curl_easy_setopt(curlh_.get(), CURLOPT_XFERINFODATA, nullptr);
|
||||
curl_easy_setopt(curlh_.get(), CURLOPT_XFERINFOFUNCTION, nullptr);
|
||||
|
||||
curl_easy_setopt(curlh_.get(), CURLOPT_HEADERDATA, nullptr);
|
||||
curl_easy_setopt(curlh_.get(), CURLOPT_HEADERFUNCTION, nullptr);
|
||||
|
||||
curl_multi_remove_handle(curlm, curlh_.get());
|
||||
curlh_.reset();
|
||||
}
|
||||
@@ -425,7 +411,7 @@ namespace curly_hpp
|
||||
|
||||
bool done() noexcept {
|
||||
std::lock_guard<std::mutex> guard(mutex_);
|
||||
if ( status_ != statuses::pending ) {
|
||||
if ( status_ != req_status::pending ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -435,7 +421,7 @@ namespace curly_hpp
|
||||
CURLINFO_RESPONSE_CODE,
|
||||
&http_code) || !http_code )
|
||||
{
|
||||
status_ = statuses::failed;
|
||||
status_ = req_status::failed;
|
||||
cvar_.notify_all();
|
||||
return false;
|
||||
}
|
||||
@@ -446,13 +432,15 @@ namespace curly_hpp
|
||||
response_.headers = std::move(response_headers_);
|
||||
response_.uploader = std::move(breq_.uploader());
|
||||
response_.downloader = std::move(breq_.downloader());
|
||||
response_.progressor = std::move(breq_.progressor());
|
||||
} catch (...) {
|
||||
status_ = statuses::failed;
|
||||
status_ = req_status::failed;
|
||||
cvar_.notify_all();
|
||||
return false;
|
||||
}
|
||||
|
||||
status_ = statuses::done;
|
||||
progress_ = 1.f;
|
||||
status_ = req_status::done;
|
||||
error_.clear();
|
||||
|
||||
cvar_.notify_all();
|
||||
@@ -461,21 +449,21 @@ namespace curly_hpp
|
||||
|
||||
bool fail(CURLcode err) noexcept {
|
||||
std::lock_guard<std::mutex> guard(mutex_);
|
||||
if ( status_ != statuses::pending ) {
|
||||
if ( status_ != req_status::pending ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
switch ( err ) {
|
||||
case CURLE_OPERATION_TIMEDOUT:
|
||||
status_ = statuses::timeout;
|
||||
status_ = req_status::timeout;
|
||||
break;
|
||||
case CURLE_READ_ERROR:
|
||||
case CURLE_WRITE_ERROR:
|
||||
case CURLE_ABORTED_BY_CALLBACK:
|
||||
status_ = statuses::canceled;
|
||||
status_ = req_status::canceled;
|
||||
break;
|
||||
default:
|
||||
status_ = statuses::failed;
|
||||
status_ = req_status::failed;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -491,75 +479,80 @@ namespace curly_hpp
|
||||
|
||||
bool cancel() noexcept {
|
||||
std::lock_guard<std::mutex> guard(mutex_);
|
||||
if ( status_ != statuses::pending ) {
|
||||
if ( status_ != req_status::pending ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
status_ = statuses::canceled;
|
||||
status_ = req_status::canceled;
|
||||
error_.clear();
|
||||
|
||||
cvar_.notify_all();
|
||||
return true;
|
||||
}
|
||||
|
||||
statuses status() const noexcept {
|
||||
float progress() const noexcept {
|
||||
std::lock_guard<std::mutex> guard(mutex_);
|
||||
return progress_;
|
||||
}
|
||||
|
||||
req_status status() const noexcept {
|
||||
std::lock_guard<std::mutex> guard(mutex_);
|
||||
return status_;
|
||||
}
|
||||
|
||||
bool is_done() const noexcept {
|
||||
std::lock_guard<std::mutex> guard(mutex_);
|
||||
return status_ == statuses::done;
|
||||
return status_ == req_status::done;
|
||||
}
|
||||
|
||||
bool is_pending() const noexcept {
|
||||
std::lock_guard<std::mutex> guard(mutex_);
|
||||
return status_ == statuses::pending;
|
||||
return status_ == req_status::pending;
|
||||
}
|
||||
|
||||
statuses wait(bool wait_callback) const noexcept {
|
||||
req_status wait(bool wait_callback) const noexcept {
|
||||
std::unique_lock<std::mutex> lock(mutex_);
|
||||
cvar_.wait(lock, [this, wait_callback](){
|
||||
return (status_ != statuses::pending)
|
||||
return (status_ != req_status::pending)
|
||||
&& (!wait_callback || callbacked_);
|
||||
});
|
||||
return status_;
|
||||
}
|
||||
|
||||
statuses wait_for(time_ms_t ms, bool wait_callback) const noexcept {
|
||||
req_status wait_for(time_ms_t ms, bool wait_callback) const noexcept {
|
||||
std::unique_lock<std::mutex> lock(mutex_);
|
||||
cvar_.wait_for(lock, ms, [this, wait_callback](){
|
||||
return (status_ != statuses::pending)
|
||||
return (status_ != req_status::pending)
|
||||
&& (!wait_callback || callbacked_);
|
||||
});
|
||||
return status_;
|
||||
}
|
||||
|
||||
statuses wait_until(time_point_t tp, bool wait_callback) const noexcept {
|
||||
req_status wait_until(time_point_t tp, bool wait_callback) const noexcept {
|
||||
std::unique_lock<std::mutex> lock(mutex_);
|
||||
cvar_.wait_until(lock, tp, [this, wait_callback](){
|
||||
return (status_ != statuses::pending)
|
||||
return (status_ != req_status::pending)
|
||||
&& (!wait_callback || callbacked_);
|
||||
});
|
||||
return status_;
|
||||
}
|
||||
|
||||
response get() {
|
||||
response take() {
|
||||
std::unique_lock<std::mutex> lock(mutex_);
|
||||
cvar_.wait(lock, [this](){
|
||||
return status_ != statuses::pending;
|
||||
return status_ != req_status::pending;
|
||||
});
|
||||
if ( status_ != statuses::done ) {
|
||||
if ( status_ != req_status::done ) {
|
||||
throw exception("curly_hpp: response is unavailable");
|
||||
}
|
||||
status_ = statuses::empty;
|
||||
status_ = req_status::empty;
|
||||
return std::move(response_);
|
||||
}
|
||||
|
||||
const std::string& get_error() const noexcept {
|
||||
std::unique_lock<std::mutex> lock(mutex_);
|
||||
cvar_.wait(lock, [this](){
|
||||
return status_ != statuses::pending;
|
||||
return status_ != req_status::pending;
|
||||
});
|
||||
return error_;
|
||||
}
|
||||
@@ -583,7 +576,7 @@ namespace curly_hpp
|
||||
callback_exception_ = std::current_exception();
|
||||
}
|
||||
std::lock_guard<std::mutex> guard(mutex_);
|
||||
assert(!callbacked_ && status_ != statuses::pending);
|
||||
assert(!callbacked_ && status_ != req_status::pending);
|
||||
callbacked_ = true;
|
||||
cvar_.notify_all();
|
||||
}
|
||||
@@ -607,6 +600,13 @@ namespace curly_hpp
|
||||
return self->download_callback_(ptr, size * nmemb);
|
||||
}
|
||||
|
||||
static int s_progress_callback_(
|
||||
void* clientp, curl_off_t dltotal, curl_off_t dlnow, curl_off_t ultotal, curl_off_t ulnow) noexcept
|
||||
{
|
||||
auto* self = static_cast<internal_state*>(clientp);
|
||||
return self->progress_callback(dlnow, dltotal, ulnow, ultotal);
|
||||
}
|
||||
|
||||
static std::size_t s_header_callback_(
|
||||
char* buffer, std::size_t size, std::size_t nitems, void* userdata) noexcept
|
||||
{
|
||||
@@ -643,6 +643,26 @@ namespace curly_hpp
|
||||
}
|
||||
}
|
||||
|
||||
int progress_callback(
|
||||
curl_off_t dlnow, curl_off_t dltotal,
|
||||
curl_off_t ulnow, curl_off_t ultotal) noexcept
|
||||
{
|
||||
try {
|
||||
std::lock_guard<std::mutex> guard(mutex_);
|
||||
|
||||
std::size_t dnow_sz = dlnow > 0 ? static_cast<std::size_t>(dlnow) : 0u;
|
||||
std::size_t dtotal_sz = dltotal > 0 ? static_cast<std::size_t>(dltotal) : 0u;
|
||||
|
||||
std::size_t unow_sz = ulnow > 0 ? static_cast<std::size_t>(ulnow) : 0u;
|
||||
std::size_t utotal_sz = ultotal > 0 ? static_cast<std::size_t>(ultotal) : 0u;
|
||||
|
||||
progress_ = breq_.progressor()->update(dnow_sz, dtotal_sz, unow_sz, utotal_sz);
|
||||
return 0;
|
||||
} catch (...) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
std::size_t header_callback_(const char* src, std::size_t size) noexcept {
|
||||
try {
|
||||
std::lock_guard<std::mutex> guard(mutex_);
|
||||
@@ -685,7 +705,8 @@ namespace curly_hpp
|
||||
bool callbacked_{false};
|
||||
std::exception_ptr callback_exception_{nullptr};
|
||||
private:
|
||||
statuses status_{statuses::pending};
|
||||
float progress_{0.f};
|
||||
req_status status_{req_status::pending};
|
||||
std::string error_{"Unknown error"};
|
||||
private:
|
||||
mutable std::mutex mutex_;
|
||||
@@ -704,7 +725,11 @@ namespace curly_hpp
|
||||
return state_->cancel();
|
||||
}
|
||||
|
||||
request::statuses request::status() const noexcept {
|
||||
float request::progress() const noexcept {
|
||||
return state_->progress();
|
||||
}
|
||||
|
||||
req_status request::status() const noexcept {
|
||||
return state_->status();
|
||||
}
|
||||
|
||||
@@ -716,32 +741,32 @@ namespace curly_hpp
|
||||
return state_->is_pending();
|
||||
}
|
||||
|
||||
request::statuses request::wait() const noexcept {
|
||||
req_status request::wait() const noexcept {
|
||||
return state_->wait(false);
|
||||
}
|
||||
|
||||
request::statuses request::wait_for(time_ms_t ms) const noexcept {
|
||||
req_status request::wait_for(time_ms_t ms) const noexcept {
|
||||
return state_->wait_for(ms, false);
|
||||
}
|
||||
|
||||
request::statuses request::wait_until(time_point_t tp) const noexcept {
|
||||
req_status request::wait_until(time_point_t tp) const noexcept {
|
||||
return state_->wait_until(tp, false);
|
||||
}
|
||||
|
||||
request::statuses request::wait_callback() const noexcept {
|
||||
req_status request::wait_callback() const noexcept {
|
||||
return state_->wait(true);
|
||||
}
|
||||
|
||||
request::statuses request::wait_callback_for(time_ms_t ms) const noexcept {
|
||||
req_status request::wait_callback_for(time_ms_t ms) const noexcept {
|
||||
return state_->wait_for(ms, true);
|
||||
}
|
||||
|
||||
request::statuses request::wait_callback_until(time_point_t tp) const noexcept {
|
||||
req_status request::wait_callback_until(time_point_t tp) const noexcept {
|
||||
return state_->wait_until(tp, true);
|
||||
}
|
||||
|
||||
response request::get() {
|
||||
return state_->get();
|
||||
response request::take() {
|
||||
return state_->take();
|
||||
}
|
||||
|
||||
const std::string& request::get_error() const noexcept {
|
||||
@@ -761,13 +786,13 @@ namespace curly_hpp
|
||||
|
||||
namespace curly_hpp
|
||||
{
|
||||
request_builder::request_builder(methods m) noexcept
|
||||
request_builder::request_builder(http_method m) noexcept
|
||||
: method_(m) {}
|
||||
|
||||
request_builder::request_builder(std::string u) noexcept
|
||||
: url_(std::move(u)) {}
|
||||
|
||||
request_builder::request_builder(methods m, std::string u) noexcept
|
||||
request_builder::request_builder(http_method m, std::string u) noexcept
|
||||
: url_(std::move(u))
|
||||
, method_(m) {}
|
||||
|
||||
@@ -776,7 +801,7 @@ namespace curly_hpp
|
||||
return *this;
|
||||
}
|
||||
|
||||
request_builder& request_builder::method(methods m) noexcept {
|
||||
request_builder& request_builder::method(http_method m) noexcept {
|
||||
method_ = m;
|
||||
return *this;
|
||||
}
|
||||
@@ -841,11 +866,16 @@ namespace curly_hpp
|
||||
return *this;
|
||||
}
|
||||
|
||||
request_builder& request_builder::progressor(progressor_uptr p) noexcept {
|
||||
progressor_ = std::move(p);
|
||||
return *this;
|
||||
}
|
||||
|
||||
const std::string& request_builder::url() const noexcept {
|
||||
return url_;
|
||||
}
|
||||
|
||||
methods request_builder::method() const noexcept {
|
||||
http_method request_builder::method() const noexcept {
|
||||
return method_;
|
||||
}
|
||||
|
||||
@@ -909,6 +939,14 @@ namespace curly_hpp
|
||||
return downloader_;
|
||||
}
|
||||
|
||||
progressor_uptr& request_builder::progressor() noexcept {
|
||||
return progressor_;
|
||||
}
|
||||
|
||||
const progressor_uptr& request_builder::progressor() const noexcept {
|
||||
return progressor_;
|
||||
}
|
||||
|
||||
request request_builder::send() {
|
||||
auto sreq = std::make_shared<request::internal_state>(std::move(*this));
|
||||
new_handles.enqueue(sreq);
|
||||
@@ -918,13 +956,13 @@ namespace curly_hpp
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
//
|
||||
// auto_performer
|
||||
// performer
|
||||
//
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
namespace curly_hpp
|
||||
{
|
||||
auto_performer::auto_performer() {
|
||||
performer::performer() {
|
||||
thread_ = std::thread([this](){
|
||||
while ( !done_ ) {
|
||||
curly_hpp::perform();
|
||||
@@ -933,18 +971,18 @@ namespace curly_hpp
|
||||
});
|
||||
}
|
||||
|
||||
auto_performer::~auto_performer() noexcept {
|
||||
performer::~performer() noexcept {
|
||||
done_.store(true);
|
||||
if ( thread_.joinable() ) {
|
||||
thread_.join();
|
||||
}
|
||||
}
|
||||
|
||||
time_ms_t auto_performer::wait_activity() const noexcept {
|
||||
time_ms_t performer::wait_activity() const noexcept {
|
||||
return wait_activity_;
|
||||
}
|
||||
|
||||
void auto_performer::wait_activity(time_ms_t ms) noexcept {
|
||||
void performer::wait_activity(time_ms_t ms) noexcept {
|
||||
wait_activity_ = ms;
|
||||
}
|
||||
}
|
||||
@@ -1022,7 +1060,7 @@ namespace curly_hpp
|
||||
void wait_activity(time_ms_t ms) {
|
||||
curl_state::with([ms](CURLM* curlm){
|
||||
if ( active_handles.empty() ) {
|
||||
new_handles.wait_content_for(ms);
|
||||
new_handles.wait_for(ms);
|
||||
} else if ( new_handles.empty() ) {
|
||||
const int timeout_ms = static_cast<int>(ms.count());
|
||||
if ( CURLM_OK != curl_multi_wait(curlm, nullptr, 0, timeout_ms, nullptr) ) {
|
||||
@@ -58,6 +58,22 @@ namespace
|
||||
}
|
||||
};
|
||||
|
||||
class canceled_progressor : public net::progress_handler {
|
||||
public:
|
||||
canceled_progressor() = default;
|
||||
|
||||
float update(
|
||||
std::size_t dnow, std::size_t dtotal,
|
||||
std::size_t unow, std::size_t utotal) override
|
||||
{
|
||||
(void)dnow;
|
||||
(void)dtotal;
|
||||
(void)unow;
|
||||
(void)utotal;
|
||||
throw std::exception();
|
||||
}
|
||||
};
|
||||
|
||||
netex::promise<net::content_t> download(std::string url) {
|
||||
return netex::make_promise<net::content_t>([
|
||||
url = std::move(url)
|
||||
@@ -68,7 +84,7 @@ namespace
|
||||
reject(net::exception("network error"));
|
||||
return;
|
||||
}
|
||||
net::response response = request.get();
|
||||
net::response response = request.take();
|
||||
if ( response.is_http_error() ) {
|
||||
reject(net::exception("server error"));
|
||||
return;
|
||||
@@ -80,39 +96,39 @@ namespace
|
||||
}
|
||||
|
||||
TEST_CASE("curly") {
|
||||
net::auto_performer performer;
|
||||
net::performer performer;
|
||||
performer.wait_activity(net::time_ms_t(10));
|
||||
|
||||
SECTION("wait") {
|
||||
{
|
||||
auto req = net::request_builder("https://httpbin.org/delay/1").send();
|
||||
REQUIRE(req.status() == net::request::statuses::pending);
|
||||
REQUIRE(req.wait() == net::request::statuses::done);
|
||||
REQUIRE(req.status() == net::request::statuses::done);
|
||||
auto resp = req.get();
|
||||
REQUIRE(req.status() == net::req_status::pending);
|
||||
REQUIRE(req.wait() == net::req_status::done);
|
||||
REQUIRE(req.status() == net::req_status::done);
|
||||
auto resp = req.take();
|
||||
REQUIRE(resp.http_code() == 200u);
|
||||
REQUIRE(req.status() == net::request::statuses::empty);
|
||||
REQUIRE(req.status() == net::req_status::empty);
|
||||
}
|
||||
{
|
||||
auto req = net::request_builder("https://httpbin.org/delay/2").send();
|
||||
REQUIRE(req.wait_for(net::time_sec_t(1)) == net::request::statuses::pending);
|
||||
REQUIRE(req.wait_for(net::time_sec_t(5)) == net::request::statuses::done);
|
||||
REQUIRE(req.get().http_code() == 200u);
|
||||
REQUIRE(req.wait_for(net::time_sec_t(1)) == net::req_status::pending);
|
||||
REQUIRE(req.wait_for(net::time_sec_t(5)) == net::req_status::done);
|
||||
REQUIRE(req.take().http_code() == 200u);
|
||||
}
|
||||
{
|
||||
auto req = net::request_builder("https://httpbin.org/delay/2").send();
|
||||
REQUIRE(req.wait_until(net::time_point_t::clock::now() + net::time_sec_t(1))
|
||||
== net::request::statuses::pending);
|
||||
== net::req_status::pending);
|
||||
REQUIRE(req.wait_until(net::time_point_t::clock::now() + net::time_sec_t(5))
|
||||
== net::request::statuses::done);
|
||||
REQUIRE(req.get().http_code() == 200u);
|
||||
== net::req_status::done);
|
||||
REQUIRE(req.take().http_code() == 200u);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("error") {
|
||||
auto req = net::request_builder("|||").send();
|
||||
REQUIRE(req.wait() == net::request::statuses::failed);
|
||||
REQUIRE(req.status() == net::request::statuses::failed);
|
||||
REQUIRE(req.wait() == net::req_status::failed);
|
||||
REQUIRE(req.status() == net::req_status::failed);
|
||||
REQUIRE_FALSE(req.get_error().empty());
|
||||
}
|
||||
|
||||
@@ -120,21 +136,21 @@ TEST_CASE("curly") {
|
||||
{
|
||||
auto req = net::request_builder("https://httpbin.org/delay/1").send();
|
||||
REQUIRE(req.cancel());
|
||||
REQUIRE(req.status() == net::request::statuses::canceled);
|
||||
REQUIRE(req.status() == net::req_status::canceled);
|
||||
REQUIRE(req.get_error().empty());
|
||||
}
|
||||
{
|
||||
auto req = net::request_builder("https://httpbin.org/status/200").send();
|
||||
REQUIRE(req.wait() == net::request::statuses::done);
|
||||
REQUIRE(req.wait() == net::req_status::done);
|
||||
REQUIRE_FALSE(req.cancel());
|
||||
REQUIRE(req.status() == net::request::statuses::done);
|
||||
REQUIRE(req.status() == net::req_status::done);
|
||||
REQUIRE(req.get_error().empty());
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("is_done/is_pending") {
|
||||
{
|
||||
auto req = net::request_builder(net::methods::get)
|
||||
auto req = net::request_builder(net::http_method::GET)
|
||||
.url("https://httpbin.org/delay/1")
|
||||
.send();
|
||||
REQUIRE_FALSE(req.is_done());
|
||||
@@ -144,7 +160,7 @@ TEST_CASE("curly") {
|
||||
REQUIRE_FALSE(req.is_pending());
|
||||
}
|
||||
{
|
||||
auto req = net::request_builder(net::methods::post, "http://www.httpbin.org/post")
|
||||
auto req = net::request_builder(net::http_method::POST, "http://www.httpbin.org/post")
|
||||
.url("https://httpbin.org/delay/2")
|
||||
.request_timeout(net::time_sec_t(1))
|
||||
.send();
|
||||
@@ -160,23 +176,23 @@ TEST_CASE("curly") {
|
||||
SECTION("get") {
|
||||
{
|
||||
auto req = net::request_builder("https://httpbin.org/status/204").send();
|
||||
auto resp = req.get();
|
||||
REQUIRE(req.status() == net::request::statuses::empty);
|
||||
auto resp = req.take();
|
||||
REQUIRE(req.status() == net::req_status::empty);
|
||||
REQUIRE(resp.http_code() == 204u);
|
||||
}
|
||||
{
|
||||
auto req = net::request_builder("https://httpbin.org/delay/2").send();
|
||||
REQUIRE(req.cancel());
|
||||
REQUIRE_THROWS_AS(req.get(), net::exception);
|
||||
REQUIRE(req.status() == net::request::statuses::canceled);
|
||||
REQUIRE_THROWS_AS(req.take(), net::exception);
|
||||
REQUIRE(req.status() == net::req_status::canceled);
|
||||
}
|
||||
{
|
||||
auto req = net::request_builder("https://httpbin.org/delay/2")
|
||||
.response_timeout(net::time_sec_t(0))
|
||||
.send();
|
||||
REQUIRE(req.wait() == net::request::statuses::timeout);
|
||||
REQUIRE_THROWS_AS(req.get(), net::exception);
|
||||
REQUIRE(req.status() == net::request::statuses::timeout);
|
||||
REQUIRE(req.wait() == net::req_status::timeout);
|
||||
REQUIRE_THROWS_AS(req.take(), net::exception);
|
||||
REQUIRE(req.status() == net::req_status::timeout);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -184,77 +200,128 @@ TEST_CASE("curly") {
|
||||
{
|
||||
auto req0 = net::request_builder()
|
||||
.url("https://httpbin.org/put")
|
||||
.method(net::methods::put)
|
||||
.method(net::http_method::PUT)
|
||||
.send();
|
||||
REQUIRE(req0.get().http_code() == 200u);
|
||||
REQUIRE(req0.take().http_code() == 200u);
|
||||
|
||||
auto req1 = net::request_builder()
|
||||
.url("https://httpbin.org/put")
|
||||
.method(net::methods::get)
|
||||
.method(net::http_method::GET)
|
||||
.send();
|
||||
REQUIRE(req1.get().http_code() == 405u);
|
||||
REQUIRE(req1.take().http_code() == 405u);
|
||||
|
||||
auto req2 = net::request_builder()
|
||||
.url("https://httpbin.org/put")
|
||||
.method(net::methods::head)
|
||||
.method(net::http_method::HEAD)
|
||||
.send();
|
||||
REQUIRE(req2.get().http_code() == 405u);
|
||||
REQUIRE(req2.take().http_code() == 405u);
|
||||
|
||||
auto req3 = net::request_builder()
|
||||
.url("https://httpbin.org/put")
|
||||
.method(net::methods::post)
|
||||
.method(net::http_method::POST)
|
||||
.send();
|
||||
REQUIRE(req3.get().http_code() == 405u);
|
||||
REQUIRE(req3.take().http_code() == 405u);
|
||||
|
||||
auto req4 = net::request_builder()
|
||||
.url("https://httpbin.org/put")
|
||||
.method(net::http_method::PATCH)
|
||||
.send();
|
||||
REQUIRE(req4.take().http_code() == 405u);
|
||||
|
||||
auto req5 = net::request_builder()
|
||||
.url("https://httpbin.org/put")
|
||||
.method(net::http_method::DEL)
|
||||
.send();
|
||||
REQUIRE(req5.take().http_code() == 405u);
|
||||
}
|
||||
{
|
||||
auto req0 = net::request_builder()
|
||||
.url("https://httpbin.org/get")
|
||||
.method(net::methods::put)
|
||||
.method(net::http_method::PUT)
|
||||
.send();
|
||||
REQUIRE(req0.get().http_code() == 405u);
|
||||
REQUIRE(req0.take().http_code() == 405u);
|
||||
|
||||
auto req1 = net::request_builder()
|
||||
.url("https://httpbin.org/get")
|
||||
.method(net::methods::get)
|
||||
.method(net::http_method::GET)
|
||||
.send();
|
||||
REQUIRE(req1.get().http_code() == 200u);
|
||||
REQUIRE(req1.take().http_code() == 200u);
|
||||
|
||||
auto req2 = net::request_builder()
|
||||
.url("https://httpbin.org/get")
|
||||
.method(net::methods::head)
|
||||
.method(net::http_method::HEAD)
|
||||
.send();
|
||||
REQUIRE(req2.get().http_code() == 200u);
|
||||
REQUIRE(req2.take().http_code() == 200u);
|
||||
|
||||
auto req3 = net::request_builder()
|
||||
.url("https://httpbin.org/get")
|
||||
.method(net::methods::post)
|
||||
.method(net::http_method::POST)
|
||||
.send();
|
||||
REQUIRE(req3.get().http_code() == 405u);
|
||||
REQUIRE(req3.take().http_code() == 405u);
|
||||
|
||||
auto req4 = net::request_builder()
|
||||
.url("https://httpbin.org/get")
|
||||
.method(net::http_method::PATCH)
|
||||
.send();
|
||||
REQUIRE(req4.take().http_code() == 405u);
|
||||
|
||||
auto req5 = net::request_builder()
|
||||
.url("https://httpbin.org/get")
|
||||
.method(net::http_method::DEL)
|
||||
.send();
|
||||
REQUIRE(req5.take().http_code() == 405u);
|
||||
}
|
||||
{
|
||||
auto req0 = net::request_builder()
|
||||
.url("https://httpbin.org/post")
|
||||
.method(net::methods::put)
|
||||
.method(net::http_method::PUT)
|
||||
.send();
|
||||
REQUIRE(req0.get().http_code() == 405u);
|
||||
REQUIRE(req0.take().http_code() == 405u);
|
||||
|
||||
auto req1 = net::request_builder()
|
||||
.url("https://httpbin.org/post")
|
||||
.method(net::methods::get)
|
||||
.method(net::http_method::GET)
|
||||
.send();
|
||||
REQUIRE(req1.get().http_code() == 405u);
|
||||
REQUIRE(req1.take().http_code() == 405u);
|
||||
|
||||
auto req2 = net::request_builder()
|
||||
.url("https://httpbin.org/post")
|
||||
.method(net::methods::head)
|
||||
.method(net::http_method::HEAD)
|
||||
.send();
|
||||
REQUIRE(req2.get().http_code() == 405u);
|
||||
REQUIRE(req2.take().http_code() == 405u);
|
||||
|
||||
auto req3 = net::request_builder()
|
||||
.url("https://httpbin.org/post")
|
||||
.method(net::methods::post)
|
||||
.method(net::http_method::POST)
|
||||
.send();
|
||||
REQUIRE(req3.get().http_code() == 200u);
|
||||
REQUIRE(req3.take().http_code() == 200u);
|
||||
|
||||
auto req4 = net::request_builder()
|
||||
.url("https://httpbin.org/post")
|
||||
.method(net::http_method::PATCH)
|
||||
.send();
|
||||
REQUIRE(req4.take().http_code() == 405u);
|
||||
|
||||
auto req5 = net::request_builder()
|
||||
.url("https://httpbin.org/post")
|
||||
.method(net::http_method::DEL)
|
||||
.send();
|
||||
REQUIRE(req5.take().http_code() == 405u);
|
||||
}
|
||||
{
|
||||
auto req1 = net::request_builder()
|
||||
.url("https://httpbin.org/put")
|
||||
.method(net::http_method::OPTIONS)
|
||||
.send();
|
||||
const auto allow1 = req1.take().headers.at("Allow");
|
||||
REQUIRE((allow1 == "PUT, OPTIONS" || allow1 == "OPTIONS, PUT"));
|
||||
|
||||
auto req2 = net::request_builder()
|
||||
.url("https://httpbin.org/post")
|
||||
.method(net::http_method::OPTIONS)
|
||||
.send();
|
||||
const auto allow2 = req2.take().headers.at("Allow");
|
||||
REQUIRE((allow2 == "POST, OPTIONS" || allow2 == "OPTIONS, POST"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -262,30 +329,44 @@ TEST_CASE("curly") {
|
||||
{
|
||||
auto req = net::request_builder()
|
||||
.url("https://httpbin.org/status/200")
|
||||
.method(net::methods::put)
|
||||
.method(net::http_method::PUT)
|
||||
.send();
|
||||
REQUIRE(req.get().http_code() == 200u);
|
||||
REQUIRE(req.take().http_code() == 200u);
|
||||
}
|
||||
{
|
||||
auto req = net::request_builder()
|
||||
.url("https://httpbin.org/status/201")
|
||||
.method(net::methods::get)
|
||||
.method(net::http_method::GET)
|
||||
.send();
|
||||
REQUIRE(req.get().http_code() == 201u);
|
||||
REQUIRE(req.take().http_code() == 201u);
|
||||
}
|
||||
{
|
||||
auto req = net::request_builder()
|
||||
.url("https://httpbin.org/status/202")
|
||||
.method(net::methods::head)
|
||||
.method(net::http_method::HEAD)
|
||||
.send();
|
||||
REQUIRE(req.get().http_code() == 202u);
|
||||
REQUIRE(req.take().http_code() == 202u);
|
||||
}
|
||||
{
|
||||
auto req = net::request_builder()
|
||||
.url("https://httpbin.org/status/203")
|
||||
.method(net::methods::post)
|
||||
.method(net::http_method::POST)
|
||||
.send();
|
||||
REQUIRE(req.get().http_code() == 203u);
|
||||
REQUIRE(req.take().http_code() == 203u);
|
||||
}
|
||||
{
|
||||
auto req = net::request_builder()
|
||||
.url("https://httpbin.org/status/203")
|
||||
.method(net::http_method::PATCH)
|
||||
.send();
|
||||
REQUIRE(req.take().http_code() == 203u);
|
||||
}
|
||||
{
|
||||
auto req = net::request_builder()
|
||||
.url("https://httpbin.org/status/203")
|
||||
.method(net::http_method::DEL)
|
||||
.send();
|
||||
REQUIRE(req.take().http_code() == 203u);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -296,7 +377,7 @@ TEST_CASE("curly") {
|
||||
.header("Custom-Header-2", "custom header value 2")
|
||||
.header("Custom-Header-3", std::string())
|
||||
.send();
|
||||
const auto resp = req.get();
|
||||
const auto resp = req.take();
|
||||
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-2"] == "custom header value 2");
|
||||
@@ -307,9 +388,9 @@ TEST_CASE("curly") {
|
||||
{
|
||||
auto req = net::request_builder()
|
||||
.url("https://httpbin.org/response-headers?hello=world&world=hello")
|
||||
.method(net::methods::get)
|
||||
.method(net::http_method::GET)
|
||||
.send();
|
||||
const auto resp = req.get();
|
||||
const auto resp = req.take();
|
||||
const auto content_j = json_parse(resp.content.as_string_view());
|
||||
REQUIRE(content_j["hello"] == "world");
|
||||
REQUIRE(content_j["world"] == "hello");
|
||||
@@ -317,9 +398,9 @@ TEST_CASE("curly") {
|
||||
{
|
||||
auto req = net::request_builder()
|
||||
.url("https://httpbin.org/response-headers?hello=world&world=hello")
|
||||
.method(net::methods::post)
|
||||
.method(net::http_method::POST)
|
||||
.send();
|
||||
const auto resp = req.get();
|
||||
const auto resp = req.take();
|
||||
const auto content_j = json_parse(resp.content.as_string_copy());
|
||||
REQUIRE(content_j["hello"] == "world");
|
||||
REQUIRE(content_j["world"] == "hello");
|
||||
@@ -331,7 +412,7 @@ TEST_CASE("curly") {
|
||||
auto req = net::request_builder()
|
||||
.url("https://httpbin.org/base64/SFRUUEJJTiBpcyBhd2Vzb21l")
|
||||
.send();
|
||||
const auto resp = req.get();
|
||||
const auto resp = req.take();
|
||||
REQUIRE(resp.content.as_string_view() == "HTTPBIN is awesome");
|
||||
REQUIRE(req.get_error().empty());
|
||||
}
|
||||
@@ -340,14 +421,14 @@ TEST_CASE("curly") {
|
||||
.url("https://httpbin.org/delay/10")
|
||||
.request_timeout(net::time_sec_t(0))
|
||||
.send();
|
||||
REQUIRE(req0.wait() == net::request::statuses::timeout);
|
||||
REQUIRE(req0.wait() == net::req_status::timeout);
|
||||
REQUIRE_FALSE(req0.get_error().empty());
|
||||
|
||||
auto req1 = net::request_builder()
|
||||
.url("https://httpbin.org/delay/10")
|
||||
.response_timeout(net::time_sec_t(0))
|
||||
.send();
|
||||
REQUIRE(req1.wait() == net::request::statuses::timeout);
|
||||
REQUIRE(req1.wait() == net::req_status::timeout);
|
||||
REQUIRE_FALSE(req1.get_error().empty());
|
||||
}
|
||||
{
|
||||
@@ -355,14 +436,14 @@ TEST_CASE("curly") {
|
||||
.url("https://httpbin.org/delay/10")
|
||||
.request_timeout(net::time_sec_t(1))
|
||||
.send();
|
||||
REQUIRE(req0.wait() == net::request::statuses::timeout);
|
||||
REQUIRE(req0.wait() == net::req_status::timeout);
|
||||
REQUIRE_FALSE(req0.get_error().empty());
|
||||
|
||||
auto req1 = net::request_builder()
|
||||
.url("https://httpbin.org/delay/10")
|
||||
.response_timeout(net::time_sec_t(1))
|
||||
.send();
|
||||
REQUIRE(req1.wait() == net::request::statuses::timeout);
|
||||
REQUIRE(req1.wait() == net::req_status::timeout);
|
||||
REQUIRE_FALSE(req1.get_error().empty());
|
||||
}
|
||||
}
|
||||
@@ -371,11 +452,25 @@ TEST_CASE("curly") {
|
||||
{
|
||||
auto resp = net::request_builder()
|
||||
.url("https://httpbin.org/image/png")
|
||||
.method(net::methods::get)
|
||||
.send().get();
|
||||
.method(net::http_method::HEAD)
|
||||
.send().take();
|
||||
REQUIRE(resp.http_code() == 200u);
|
||||
REQUIRE(resp.headers.count("Content-Type"));
|
||||
REQUIRE(resp.headers.count("Content-Length"));
|
||||
REQUIRE(resp.headers.at("Content-Type") == "image/png");
|
||||
REQUIRE(resp.headers.at("Content-Length") == std::to_string(untests::png_data_length));
|
||||
REQUIRE_FALSE(resp.content.size());
|
||||
}
|
||||
{
|
||||
auto resp = net::request_builder()
|
||||
.url("https://httpbin.org/image/png")
|
||||
.method(net::http_method::GET)
|
||||
.send().take();
|
||||
REQUIRE(resp.http_code() == 200u);
|
||||
REQUIRE(resp.headers.count("Content-Type"));
|
||||
REQUIRE(resp.headers.count("Content-Length"));
|
||||
REQUIRE(resp.headers.at("Content-Type") == "image/png");
|
||||
REQUIRE(resp.headers.at("Content-Length") == std::to_string(untests::png_data_length));
|
||||
REQUIRE(untests::png_data_length == resp.content.size());
|
||||
REQUIRE(!std::memcmp(
|
||||
std::move(resp.content).data().data(),
|
||||
@@ -384,11 +479,25 @@ TEST_CASE("curly") {
|
||||
{
|
||||
auto resp = net::request_builder()
|
||||
.url("https://httpbin.org/image/jpeg")
|
||||
.method(net::methods::get)
|
||||
.send().get();
|
||||
.method(net::http_method::HEAD)
|
||||
.send().take();
|
||||
REQUIRE(resp.http_code() == 200u);
|
||||
REQUIRE(resp.headers.count("Content-Type"));
|
||||
REQUIRE(resp.headers.count("Content-Length"));
|
||||
REQUIRE(resp.headers.at("Content-Type") == "image/jpeg");
|
||||
REQUIRE(resp.headers.at("Content-Length") == std::to_string(untests::jpeg_data_length));
|
||||
REQUIRE_FALSE(resp.content.size());
|
||||
}
|
||||
{
|
||||
auto resp = net::request_builder()
|
||||
.url("https://httpbin.org/image/jpeg")
|
||||
.method(net::http_method::GET)
|
||||
.send().take();
|
||||
REQUIRE(resp.http_code() == 200u);
|
||||
REQUIRE(resp.headers.count("Content-Type"));
|
||||
REQUIRE(resp.headers.count("Content-Length"));
|
||||
REQUIRE(resp.headers.at("Content-Type") == "image/jpeg");
|
||||
REQUIRE(resp.headers.at("Content-Length") == std::to_string(untests::jpeg_data_length));
|
||||
REQUIRE(untests::jpeg_data_length == resp.content.size());
|
||||
REQUIRE(!std::memcmp(
|
||||
std::as_const(resp.content).data().data(),
|
||||
@@ -401,57 +510,57 @@ TEST_CASE("curly") {
|
||||
{
|
||||
auto req = net::request_builder()
|
||||
.url("https://httpbin.org/redirect/2")
|
||||
.method(net::methods::get)
|
||||
.method(net::http_method::GET)
|
||||
.send();
|
||||
REQUIRE(req.get().http_code() == 200u);
|
||||
REQUIRE(req.take().http_code() == 200u);
|
||||
}
|
||||
{
|
||||
auto req = net::request_builder()
|
||||
.url("https://httpbin.org/absolute-redirect/2")
|
||||
.method(net::methods::get)
|
||||
.method(net::http_method::GET)
|
||||
.send();
|
||||
REQUIRE(req.get().http_code() == 200u);
|
||||
REQUIRE(req.take().http_code() == 200u);
|
||||
}
|
||||
{
|
||||
auto req = net::request_builder()
|
||||
.url("https://httpbin.org/relative-redirect/2")
|
||||
.method(net::methods::get)
|
||||
.method(net::http_method::GET)
|
||||
.send();
|
||||
REQUIRE(req.get().http_code() == 200u);
|
||||
REQUIRE(req.take().http_code() == 200u);
|
||||
}
|
||||
}
|
||||
{
|
||||
{
|
||||
auto req = net::request_builder()
|
||||
.url("https://httpbin.org/redirect/3")
|
||||
.method(net::methods::get)
|
||||
.method(net::http_method::GET)
|
||||
.redirections(0)
|
||||
.send();
|
||||
REQUIRE(req.get().http_code() == 302u);
|
||||
REQUIRE(req.take().http_code() == 302u);
|
||||
}
|
||||
{
|
||||
auto req = net::request_builder()
|
||||
.url("https://httpbin.org/redirect/3")
|
||||
.method(net::methods::get)
|
||||
.method(net::http_method::GET)
|
||||
.redirections(1)
|
||||
.send();
|
||||
REQUIRE(req.wait() == net::request::statuses::failed);
|
||||
REQUIRE(req.wait() == net::req_status::failed);
|
||||
}
|
||||
{
|
||||
auto req = net::request_builder()
|
||||
.url("https://httpbin.org/redirect/3")
|
||||
.method(net::methods::get)
|
||||
.method(net::http_method::GET)
|
||||
.redirections(2)
|
||||
.send();
|
||||
REQUIRE(req.wait() == net::request::statuses::failed);
|
||||
REQUIRE(req.wait() == net::req_status::failed);
|
||||
}
|
||||
{
|
||||
auto req = net::request_builder()
|
||||
.url("https://httpbin.org/redirect/3")
|
||||
.method(net::methods::get)
|
||||
.method(net::http_method::GET)
|
||||
.redirections(3)
|
||||
.send();
|
||||
REQUIRE(req.get().http_code() == 200u);
|
||||
REQUIRE(req.take().http_code() == 200u);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -460,30 +569,50 @@ TEST_CASE("curly") {
|
||||
{
|
||||
auto resp = net::request_builder()
|
||||
.url("https://httpbin.org/anything")
|
||||
.method(net::methods::put)
|
||||
.method(net::http_method::PUT)
|
||||
.header("Content-Type", "application/json")
|
||||
.content(R"({"hello":"world"})")
|
||||
.send().get();
|
||||
.send().take();
|
||||
const auto content_j = json_parse(resp.content.as_string_view());
|
||||
REQUIRE(content_j["data"] == R"({"hello":"world"})");
|
||||
}
|
||||
{
|
||||
auto resp = net::request_builder()
|
||||
.url("https://httpbin.org/anything")
|
||||
.method(net::methods::post)
|
||||
.method(net::http_method::PATCH)
|
||||
.header("Content-Type", "application/json")
|
||||
.content(R"({"hello":"world"})")
|
||||
.send().get();
|
||||
.send().take();
|
||||
const auto content_j = json_parse(resp.content.as_string_view());
|
||||
REQUIRE(content_j["data"] == R"({"hello":"world"})");
|
||||
}
|
||||
{
|
||||
auto resp = net::request_builder()
|
||||
.url("https://httpbin.org/anything")
|
||||
.method(net::methods::post)
|
||||
.method(net::http_method::DEL)
|
||||
.header("Content-Type", "application/json")
|
||||
.content(R"({"hello":"world"})")
|
||||
.send().take();
|
||||
const auto content_j = json_parse(resp.content.as_string_view());
|
||||
REQUIRE(content_j["data"] == R"({"hello":"world"})");
|
||||
}
|
||||
{
|
||||
auto resp = net::request_builder()
|
||||
.url("https://httpbin.org/anything")
|
||||
.method(net::http_method::POST)
|
||||
.header("Content-Type", "application/json")
|
||||
.content(R"({"hello":"world"})")
|
||||
.send().take();
|
||||
const auto content_j = json_parse(resp.content.as_string_view());
|
||||
REQUIRE(content_j["data"] == R"({"hello":"world"})");
|
||||
}
|
||||
{
|
||||
auto resp = net::request_builder()
|
||||
.url("https://httpbin.org/anything")
|
||||
.method(net::http_method::POST)
|
||||
.header("Content-Type", "application/x-www-form-urlencoded")
|
||||
.content("hello=world&world=hello")
|
||||
.send().get();
|
||||
.send().take();
|
||||
const auto content_j = json_parse(resp.content.as_string_view());
|
||||
REQUIRE(content_j["form"]["hello"] == "world");
|
||||
REQUIRE(content_j["form"]["world"] == "hello");
|
||||
@@ -493,53 +622,53 @@ TEST_CASE("curly") {
|
||||
SECTION("ssl_verification") {
|
||||
{
|
||||
auto req0 = net::request_builder("https://expired.badssl.com")
|
||||
.method(net::methods::head)
|
||||
.method(net::http_method::HEAD)
|
||||
.verification(true)
|
||||
.send();
|
||||
REQUIRE(req0.wait() == net::request::statuses::failed);
|
||||
REQUIRE(req0.wait() == net::req_status::failed);
|
||||
|
||||
auto req1 = net::request_builder("https://wrong.host.badssl.com")
|
||||
.method(net::methods::head)
|
||||
.method(net::http_method::HEAD)
|
||||
.verification(true)
|
||||
.send();
|
||||
REQUIRE(req1.wait() == net::request::statuses::failed);
|
||||
REQUIRE(req1.wait() == net::req_status::failed);
|
||||
|
||||
auto req2 = net::request_builder("https://self-signed.badssl.com")
|
||||
.method(net::methods::head)
|
||||
.method(net::http_method::HEAD)
|
||||
.verification(true)
|
||||
.send();
|
||||
REQUIRE(req2.wait() == net::request::statuses::failed);
|
||||
REQUIRE(req2.wait() == net::req_status::failed);
|
||||
|
||||
auto req3 = net::request_builder("https://untrusted-root.badssl.com")
|
||||
.method(net::methods::head)
|
||||
.method(net::http_method::HEAD)
|
||||
.verification(true)
|
||||
.send();
|
||||
REQUIRE(req3.wait() == net::request::statuses::failed);
|
||||
REQUIRE(req3.wait() == net::req_status::failed);
|
||||
}
|
||||
{
|
||||
auto req0 = net::request_builder("https://expired.badssl.com")
|
||||
.method(net::methods::head)
|
||||
.method(net::http_method::HEAD)
|
||||
.verification(false)
|
||||
.send();
|
||||
REQUIRE(req0.wait() == net::request::statuses::done);
|
||||
REQUIRE(req0.wait() == net::req_status::done);
|
||||
|
||||
auto req1 = net::request_builder("https://wrong.host.badssl.com")
|
||||
.method(net::methods::head)
|
||||
.method(net::http_method::HEAD)
|
||||
.verification(false)
|
||||
.send();
|
||||
REQUIRE(req1.wait() == net::request::statuses::done);
|
||||
REQUIRE(req1.wait() == net::req_status::done);
|
||||
|
||||
auto req2 = net::request_builder("https://self-signed.badssl.com")
|
||||
.method(net::methods::head)
|
||||
.method(net::http_method::HEAD)
|
||||
.verification(false)
|
||||
.send();
|
||||
REQUIRE(req2.wait() == net::request::statuses::done);
|
||||
REQUIRE(req2.wait() == net::req_status::done);
|
||||
|
||||
auto req3 = net::request_builder("https://untrusted-root.badssl.com")
|
||||
.method(net::methods::head)
|
||||
.method(net::http_method::HEAD)
|
||||
.verification(false)
|
||||
.send();
|
||||
REQUIRE(req3.wait() == net::request::statuses::done);
|
||||
REQUIRE(req3.wait() == net::req_status::done);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -547,18 +676,26 @@ TEST_CASE("curly") {
|
||||
{
|
||||
auto req = net::request_builder("https://httpbin.org/anything")
|
||||
.verbose(true)
|
||||
.method(net::methods::post)
|
||||
.method(net::http_method::POST)
|
||||
.uploader<canceled_uploader>()
|
||||
.send();
|
||||
REQUIRE(req.wait() == net::request::statuses::canceled);
|
||||
REQUIRE(req.wait() == net::req_status::canceled);
|
||||
}
|
||||
{
|
||||
auto req = net::request_builder("https://httpbin.org/anything")
|
||||
.verbose(true)
|
||||
.method(net::methods::get)
|
||||
.method(net::http_method::GET)
|
||||
.downloader<canceled_downloader>()
|
||||
.send();
|
||||
REQUIRE(req.wait() == net::request::statuses::canceled);
|
||||
REQUIRE(req.wait() == net::req_status::canceled);
|
||||
}
|
||||
{
|
||||
auto req = net::request_builder("https://httpbin.org/anything")
|
||||
.verbose(true)
|
||||
.method(net::http_method::GET)
|
||||
.progressor<canceled_progressor>()
|
||||
.send();
|
||||
REQUIRE(req.wait() == net::req_status::canceled);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -570,10 +707,10 @@ TEST_CASE("curly") {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||
++call_once;
|
||||
REQUIRE(request.is_done());
|
||||
REQUIRE(request.status() == net::request::statuses::done);
|
||||
REQUIRE(request.get().http_code() == 200u);
|
||||
REQUIRE(request.status() == net::req_status::done);
|
||||
REQUIRE(request.take().http_code() == 200u);
|
||||
}).send();
|
||||
REQUIRE(req.wait_callback() == net::request::statuses::empty);
|
||||
REQUIRE(req.wait_callback() == net::req_status::empty);
|
||||
REQUIRE_FALSE(req.get_callback_exception());
|
||||
REQUIRE(call_once.load() == 1u);
|
||||
}
|
||||
@@ -584,10 +721,10 @@ TEST_CASE("curly") {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||
++call_once;
|
||||
REQUIRE_FALSE(request.is_done());
|
||||
REQUIRE(request.status() == net::request::statuses::failed);
|
||||
REQUIRE(request.status() == net::req_status::failed);
|
||||
REQUIRE_FALSE(request.get_error().empty());
|
||||
}).send();
|
||||
REQUIRE(req.wait_callback() == net::request::statuses::failed);
|
||||
REQUIRE(req.wait_callback() == net::req_status::failed);
|
||||
REQUIRE_FALSE(req.get_callback_exception());
|
||||
REQUIRE(call_once.load() == 1u);
|
||||
}
|
||||
@@ -599,10 +736,10 @@ TEST_CASE("curly") {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||
++call_once;
|
||||
REQUIRE_FALSE(request.is_done());
|
||||
REQUIRE(request.status() == net::request::statuses::timeout);
|
||||
REQUIRE(request.status() == net::req_status::timeout);
|
||||
REQUIRE_FALSE(request.get_error().empty());
|
||||
}).send();
|
||||
REQUIRE(req.wait_callback() == net::request::statuses::timeout);
|
||||
REQUIRE(req.wait_callback() == net::req_status::timeout);
|
||||
REQUIRE_FALSE(req.get_callback_exception());
|
||||
REQUIRE(call_once.load() == 1u);
|
||||
}
|
||||
@@ -613,11 +750,11 @@ TEST_CASE("curly") {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||
++call_once;
|
||||
REQUIRE_FALSE(request.is_done());
|
||||
REQUIRE(request.status() == net::request::statuses::canceled);
|
||||
REQUIRE(request.status() == net::req_status::canceled);
|
||||
REQUIRE(request.get_error().empty());
|
||||
}).send();
|
||||
REQUIRE(req.cancel());
|
||||
REQUIRE(req.wait_callback() == net::request::statuses::canceled);
|
||||
REQUIRE(req.wait_callback() == net::req_status::canceled);
|
||||
REQUIRE_FALSE(req.get_callback_exception());
|
||||
REQUIRE(call_once.load() == 1u);
|
||||
}
|
||||
@@ -627,11 +764,11 @@ TEST_CASE("curly") {
|
||||
auto req = net::request_builder("http://www.httpbin.org/post")
|
||||
.callback([](net::request request){
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||
if ( request.get().is_http_error() ) {
|
||||
if ( request.take().is_http_error() ) {
|
||||
throw std::logic_error("my_logic_error");
|
||||
}
|
||||
}).send();
|
||||
REQUIRE(req.wait_callback() == net::request::statuses::empty);
|
||||
REQUIRE(req.wait_callback() == net::req_status::empty);
|
||||
REQUIRE(req.get_callback_exception());
|
||||
try {
|
||||
std::rethrow_exception(req.get_callback_exception());
|
||||
@@ -642,17 +779,17 @@ TEST_CASE("curly") {
|
||||
}
|
||||
|
||||
TEST_CASE("curly_examples") {
|
||||
net::auto_performer performer;
|
||||
net::performer performer;
|
||||
|
||||
SECTION("Get Requests") {
|
||||
// makes a GET request and async send it
|
||||
auto request = net::request_builder()
|
||||
.method(net::methods::get)
|
||||
.method(net::http_method::GET)
|
||||
.url("http://www.httpbin.org/get")
|
||||
.send();
|
||||
|
||||
// synchronous waits and get a response
|
||||
auto response = request.get();
|
||||
// synchronous waits and take a response
|
||||
auto response = request.take();
|
||||
|
||||
// prints results
|
||||
std::cout << "Status code: " << response.http_code() << std::endl;
|
||||
@@ -675,13 +812,13 @@ TEST_CASE("curly_examples") {
|
||||
|
||||
SECTION("Post Requests") {
|
||||
auto request = net::request_builder()
|
||||
.method(net::methods::post)
|
||||
.method(net::http_method::POST)
|
||||
.url("http://www.httpbin.org/post")
|
||||
.header("Content-Type", "application/json")
|
||||
.content(R"({"hello" : "world"})")
|
||||
.send();
|
||||
|
||||
auto response = request.get();
|
||||
auto response = request.take();
|
||||
std::cout << "Body content: " << response.content.as_string_view() << std::endl;
|
||||
std::cout << "Content Length: " << response.headers["content-length"] << std::endl;
|
||||
|
||||
@@ -714,11 +851,11 @@ TEST_CASE("curly_examples") {
|
||||
request.wait();
|
||||
|
||||
if ( request.is_done() ) {
|
||||
auto response = request.get();
|
||||
auto response = request.take();
|
||||
std::cout << "Status code: " << response.http_code() << std::endl;
|
||||
} else {
|
||||
// throws net::exception because a response is unavailable
|
||||
// auto response = request.get();
|
||||
// auto response = request.take();
|
||||
|
||||
std::cout << "Error message: " << request.get_error() << std::endl;
|
||||
}
|
||||
@@ -730,7 +867,7 @@ TEST_CASE("curly_examples") {
|
||||
auto request = net::request_builder("http://www.httpbin.org/get")
|
||||
.callback([](net::request request){
|
||||
if ( request.is_done() ) {
|
||||
auto response = request.get();
|
||||
auto response = request.take();
|
||||
std::cout << "Status code: " << response.http_code() << std::endl;
|
||||
} else {
|
||||
std::cout << "Error message: " << request.get_error() << std::endl;
|
||||
@@ -759,7 +896,7 @@ TEST_CASE("curly_examples") {
|
||||
net::request_builder()
|
||||
.url("https://httpbin.org/image/jpeg")
|
||||
.downloader<file_dowloader>("image.jpeg")
|
||||
.send().get();
|
||||
.send().take();
|
||||
}
|
||||
{
|
||||
class file_uploader : public net::upload_handler {
|
||||
@@ -785,10 +922,10 @@ TEST_CASE("curly_examples") {
|
||||
};
|
||||
|
||||
net::request_builder()
|
||||
.method(net::methods::post)
|
||||
.method(net::http_method::POST)
|
||||
.url("https://httpbin.org/anything")
|
||||
.uploader<file_uploader>("image.jpeg")
|
||||
.send().get();
|
||||
.send().take();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user