support out buf when request (#450)

This commit is contained in:
qicosmos 2023-09-12 10:27:04 +08:00 committed by GitHub
parent b9d6008481
commit 72253d30e7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 77 additions and 13 deletions

View File

@ -31,6 +31,7 @@ using coro_http_client = cinatra::coro_http_client;
using req_content_type = cinatra::req_content_type; using req_content_type = cinatra::req_content_type;
using resp_data = cinatra::resp_data; using resp_data = cinatra::resp_data;
using http_method = cinatra::http_method; 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>; using req_context = cinatra::req_context<String>;
} // namespace coro_http } // namespace coro_http

View File

@ -7,6 +7,7 @@
#include <future> #include <future>
#include <memory> #include <memory>
#include <optional> #include <optional>
#include <span>
#include <string_view> #include <string_view>
#include <system_error> #include <system_error>
#include <thread> #include <thread>
@ -825,17 +826,25 @@ class coro_http_client {
template <typename S, typename String> template <typename S, typename String>
async_simple::coro::Lazy<resp_data> async_request( async_simple::coro::Lazy<resp_data> async_request(
S uri, http_method method, req_context<String> ctx, 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()) { if (!resp_chunk_str_.empty()) {
resp_chunk_str_.clear(); resp_chunk_str_.clear();
} }
if (!body_.empty()) { if (!body_.empty()) {
body_.clear(); body_.clear();
} }
if (!out_buf.empty()) {
out_buf_ = out_buf;
}
std::shared_ptr<int> guard(nullptr, [this](auto) { std::shared_ptr<int> guard(nullptr, [this](auto) {
if (!req_headers_.empty()) { if (!req_headers_.empty()) {
req_headers_.clear(); req_headers_.clear();
} }
if (!out_buf_.empty()) {
out_buf_ = {};
}
}); });
resp_data data{}; resp_data data{};
@ -1220,13 +1229,27 @@ class coro_http_client {
total_len_ = parser_.total_len(); total_len_ = parser_.total_len();
#endif #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. // Now get entire content, additional data will discard.
// copy body. // copy body.
if (content_len > 0) { if (content_len > 0) {
detail::resize(body_, content_len);
auto data_ptr = asio::buffer_cast<const char *>(read_buf_.data()); auto data_ptr = asio::buffer_cast<const char *>(read_buf_.data());
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); memcpy(body_.data(), data_ptr, content_len);
}
read_buf_.consume(read_buf_.size()); read_buf_.consume(read_buf_.size());
} }
co_await handle_entire_content(data, content_len, is_ranges, ctx); co_await handle_entire_content(data, content_len, is_ranges, ctx);
@ -1237,17 +1260,33 @@ class coro_http_client {
size_t part_size = read_buf_.size(); size_t part_size = read_buf_.size();
size_t size_to_read = content_len - part_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()); auto data_ptr = asio::buffer_cast<const char *>(read_buf_.data());
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); memcpy(body_.data(), data_ptr, part_size);
}
read_buf_.consume(part_size); read_buf_.consume(part_size);
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( if (std::tie(ec, size) = co_await async_read(
asio::buffer(body_.data() + part_size, size_to_read), asio::buffer(body_.data() + part_size, size_to_read),
size_to_read); size_to_read);
ec) { ec) {
break; break;
} }
}
// Now get entire content, additional data will discard. // Now get entire content, additional data will discard.
co_await handle_entire_content(data, content_len, is_ranges, ctx); co_await handle_entire_content(data, content_len, is_ranges, ctx);
@ -1268,8 +1307,13 @@ class coro_http_client {
if (content_len > 0) { if (content_len > 0) {
const char *data_ptr; const char *data_ptr;
if (read_buf_.size() == 0) { if (read_buf_.size() == 0) {
if (out_buf_.empty()) {
data_ptr = body_.data(); data_ptr = body_.data();
} }
else {
data_ptr = out_buf_.data();
}
}
else { else {
data_ptr = asio::buffer_cast<const char *>(read_buf_.data()); data_ptr = asio::buffer_cast<const char *>(read_buf_.data());
} }
@ -1698,6 +1742,7 @@ class coro_http_client {
std::chrono::seconds(60); std::chrono::seconds(60);
bool enable_tcp_no_delay_ = false; bool enable_tcp_no_delay_ = false;
std::string resp_chunk_str_; std::string resp_chunk_str_;
std::span<char> out_buf_;
#ifdef BENCHMARK_TEST #ifdef BENCHMARK_TEST
std::string req_str_; std::string req_str_;

View File

@ -141,8 +141,26 @@ async_simple::coro::Lazy<void> ranges_download_files(
std::cout << result.status << "\n"; 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() { int main() {
test_sync_client(); test_sync_client();
use_out_buf();
coro_http::coro_http_client client{}; coro_http::coro_http_client client{};
async_simple::coro::syncAwait(test_async_client(client)); async_simple::coro::syncAwait(test_async_client(client));