Skip to content

Commit

Permalink
support out buf when request (#450)
Browse files Browse the repository at this point in the history
  • Loading branch information
qicosmos authored Sep 12, 2023
1 parent b9d6008 commit 72253d3
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 13 deletions.
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

0 comments on commit 72253d3

Please sign in to comment.