Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[coro_http_client][feat]support out buf when request #450

Merged
merged 1 commit into from
Sep 12, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion include/ylt/coro_http/coro_http_client.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ using coro_http_client = cinatra::coro_http_client;
using req_content_type = cinatra::req_content_type;
using resp_data = cinatra::resp_data;
using http_method = cinatra::http_method;
template <typename String>
using http_header = cinatra::http_header;
template <typename String = std::string>
using req_context = cinatra::req_context<String>;
} // namespace coro_http
69 changes: 57 additions & 12 deletions include/ylt/thirdparty/cinatra/coro_http_client.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include <future>
#include <memory>
#include <optional>
#include <span>
#include <string_view>
#include <system_error>
#include <thread>
Expand Down Expand Up @@ -825,17 +826,25 @@ class coro_http_client {
template <typename S, typename String>
async_simple::coro::Lazy<resp_data> async_request(
S uri, http_method method, req_context<String> ctx,
std::unordered_map<std::string, std::string> headers = {}) {
std::unordered_map<std::string, std::string> headers = {},
std::span<char> out_buf = {}) {
if (!resp_chunk_str_.empty()) {
resp_chunk_str_.clear();
}
if (!body_.empty()) {
body_.clear();
}
if (!out_buf.empty()) {
out_buf_ = out_buf;
}

std::shared_ptr<int> guard(nullptr, [this](auto) {
if (!req_headers_.empty()) {
req_headers_.clear();
}
if (!out_buf_.empty()) {
out_buf_ = {};
}
});

resp_data data{};
Expand Down Expand Up @@ -1220,13 +1229,27 @@ class coro_http_client {
total_len_ = parser_.total_len();
#endif

if ((size_t)parser_.body_len() <= read_buf_.size()) {
bool is_out_buf = !out_buf_.empty();
if (is_out_buf) {
if (content_len > 0 && out_buf_.size() < content_len) {
data.status = 404;
data.net_err = std::make_error_code(std::errc::no_buffer_space);
co_return data;
}
}

if (content_len <= read_buf_.size()) {
// Now get entire content, additional data will discard.
// copy body.
if (content_len > 0) {
detail::resize(body_, content_len);
auto data_ptr = asio::buffer_cast<const char *>(read_buf_.data());
memcpy(body_.data(), data_ptr, content_len);
if (is_out_buf) {
memcpy(out_buf_.data(), data_ptr, content_len);
}
else {
detail::resize(body_, content_len);
memcpy(body_.data(), data_ptr, content_len);
}
read_buf_.consume(read_buf_.size());
}
co_await handle_entire_content(data, content_len, is_ranges, ctx);
Expand All @@ -1237,16 +1260,32 @@ class coro_http_client {
size_t part_size = read_buf_.size();
size_t size_to_read = content_len - part_size;

detail::resize(body_, content_len);
auto data_ptr = asio::buffer_cast<const char *>(read_buf_.data());
memcpy(body_.data(), data_ptr, part_size);
if (is_out_buf) {
memcpy(out_buf_.data(), data_ptr, part_size);
}
else {
detail::resize(body_, content_len);
memcpy(body_.data(), data_ptr, part_size);
}

read_buf_.consume(part_size);

if (std::tie(ec, size) = co_await async_read(
asio::buffer(body_.data() + part_size, size_to_read),
size_to_read);
ec) {
break;
if (is_out_buf) {
if (std::tie(ec, size) = co_await async_read(
asio::buffer(out_buf_.data() + part_size, size_to_read),
size_to_read);
ec) {
break;
}
}
else {
if (std::tie(ec, size) = co_await async_read(
asio::buffer(body_.data() + part_size, size_to_read),
size_to_read);
ec) {
break;
}
}

// Now get entire content, additional data will discard.
Expand All @@ -1268,7 +1307,12 @@ class coro_http_client {
if (content_len > 0) {
const char *data_ptr;
if (read_buf_.size() == 0) {
data_ptr = body_.data();
if (out_buf_.empty()) {
data_ptr = body_.data();
}
else {
data_ptr = out_buf_.data();
}
}
else {
data_ptr = asio::buffer_cast<const char *>(read_buf_.data());
Expand Down Expand Up @@ -1698,6 +1742,7 @@ class coro_http_client {
std::chrono::seconds(60);
bool enable_tcp_no_delay_ = false;
std::string resp_chunk_str_;
std::span<char> out_buf_;

#ifdef BENCHMARK_TEST
std::string req_str_;
Expand Down
18 changes: 18 additions & 0 deletions src/coro_http/examples/example.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -141,8 +141,26 @@ async_simple::coro::Lazy<void> ranges_download_files(
std::cout << result.status << "\n";
}

void use_out_buf() {
using namespace coro_http;
std::string str;
str.resize(10);
std::string url = "http://cn.bing.com";

str.resize(6400);
coro_http_client client;
auto ret = client.async_request(url, http_method::GET, req_context<>{}, {},
std::span<char>{str.data(), str.size()});
auto result = async_simple::coro::syncAwait(ret);
bool ok = result.status == 200 || result.status == 301;
assert(ok);
std::string_view sv(str.data(), result.resp_body.size());
assert(result.resp_body == sv);
}

int main() {
test_sync_client();
use_out_buf();

coro_http::coro_http_client client{};
async_simple::coro::syncAwait(test_async_client(client));
Expand Down
Loading