From eb4becc2b70415bd66ba40b098455b433ef6ea6c Mon Sep 17 00:00:00 2001 From: qicosmos Date: Tue, 9 Jul 2024 18:44:06 +0800 Subject: [PATCH] fix sendfile (#615) --- include/cinatra/coro_http_client.hpp | 37 +++++++++++-------------- include/cinatra/ylt/coro_io/coro_io.hpp | 32 ++++++++++++++++----- 2 files changed, 41 insertions(+), 28 deletions(-) diff --git a/include/cinatra/coro_http_client.hpp b/include/cinatra/coro_http_client.hpp index 67c81782..7473c7de 100644 --- a/include/cinatra/coro_http_client.hpp +++ b/include/cinatra/coro_http_client.hpp @@ -893,13 +893,11 @@ class coro_http_client : public std::enable_shared_from_this { file_data.data(), std::min(file_data.size(), length)); ec) { // bad request, file may smaller than content-length - close(); break; } length -= size; if (length > 0 && file.eof()) { // bad request, file may smaller than content-length - close(); ec = std::make_error_code(std::errc::invalid_argument); break; } @@ -936,7 +934,6 @@ class coro_http_client : public std::enable_shared_from_this { } if (actual_len != length) [[unlikely]] { // bad request, file is smaller than content-length - close(); ec = std::make_error_code(std::errc::invalid_argument); co_return; } @@ -972,7 +969,6 @@ class coro_http_client : public std::enable_shared_from_this { } if (actual_len != len) [[unlikely]] { // bad request, file is smaller than content-length - close(); ec = std::make_error_code(std::errc::invalid_argument); co_return; } @@ -1013,14 +1009,19 @@ class coro_http_client : public std::enable_shared_from_this { int64_t content_length = -1, req_content_type content_type = req_content_type::text, std::unordered_map headers = {}) { - std::shared_ptr guard(nullptr, [this](auto) { + std::error_code ec{}; + size_t size = 0; + bool is_keep_alive = true; + req_context<> ctx{content_type}; + resp_data data{}; + + std::shared_ptr guard(nullptr, [&, this](auto) { if (!req_headers_.empty()) { req_headers_.clear(); } + handle_result(data, ec, is_keep_alive); }); - req_context<> ctx{content_type}; - resp_data data{}; auto [ok, u] = handle_uri(data, uri); if (!ok) { co_return resp_data{std::make_error_code(std::errc::protocol_error), 404}; @@ -1064,9 +1065,6 @@ class coro_http_client : public std::enable_shared_from_this { std::string header_str = build_request_header(u, method, ctx, true, std::move(headers)); - std::error_code ec{}; - size_t size = 0; - if (socket_->has_closed_) { { auto guard = timer_guard(this, conn_timeout_duration_, "connect timer"); @@ -1109,7 +1107,6 @@ class coro_http_client : public std::enable_shared_from_this { if (!ec && content_length > 0) { // bad request, file is smaller than content-length ec = std::make_error_code(std::errc::invalid_argument); - close(); } } else if constexpr (std::is_same_v || @@ -1147,7 +1144,6 @@ class coro_http_client : public std::enable_shared_from_this { else if (result.eof) [[unlikely]] { // bad request, file is smaller than content-length ec = std::make_error_code(std::errc::invalid_argument); - close(); break; } } @@ -1159,13 +1155,11 @@ class coro_http_client : public std::enable_shared_from_this { co_return resp_data{ec, 404}; } - bool is_keep_alive = true; data = co_await handle_read(ec, size, is_keep_alive, std::move(ctx), http_method::POST); if (ec && socket_->is_timeout_) { ec = std::make_error_code(std::errc::timed_out); } - handle_result(data, ec, is_keep_alive); co_return data; } @@ -1174,18 +1168,23 @@ class coro_http_client : public std::enable_shared_from_this { S uri, http_method method, Source source, req_content_type content_type = req_content_type::text, std::unordered_map headers = {}) { - std::shared_ptr guard(nullptr, [this](auto) { + req_context<> ctx{content_type}; + resp_data data{}; + std::error_code ec{}; + size_t size = 0; + bool is_keep_alive = true; + + std::shared_ptr guard(nullptr, [&, this](auto) { if (!req_headers_.empty()) { req_headers_.clear(); } + handle_result(data, ec, is_keep_alive); }); if (!resp_chunk_str_.empty()) { resp_chunk_str_.clear(); } - req_context<> ctx{content_type}; - resp_data data{}; auto [ok, u] = handle_uri(data, uri); if (!ok) { co_return resp_data{std::make_error_code(std::errc::protocol_error), 404}; @@ -1216,9 +1215,6 @@ class coro_http_client : public std::enable_shared_from_this { std::string header_str = build_request_header(u, method, ctx, true, std::move(headers)); - std::error_code ec{}; - size_t size = 0; - if (socket_->has_closed_) { { auto guard = timer_guard(this, conn_timeout_duration_, "connect timer"); @@ -1296,7 +1292,6 @@ class coro_http_client : public std::enable_shared_from_this { co_return resp_data{ec, 404}; } - bool is_keep_alive = true; data = co_await handle_read(ec, size, is_keep_alive, std::move(ctx), http_method::POST); if (ec && socket_->is_timeout_) { diff --git a/include/cinatra/ylt/coro_io/coro_io.hpp b/include/cinatra/ylt/coro_io/coro_io.hpp index 08a3cb67..f22b9144 100644 --- a/include/cinatra/ylt/coro_io/coro_io.hpp +++ b/include/cinatra/ylt/coro_io/coro_io.hpp @@ -1,17 +1,30 @@ +/* + * Copyright (c) 2023, Alibaba Group Holding Limited; + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ #pragma once + #include +#include #include #include #include -#include "async_simple/coro/Collect.h" - #if defined(YLT_ENABLE_SSL) || defined(CINATRA_ENABLE_SSL) #include #endif -#include - #include #include #include @@ -23,8 +36,12 @@ #include #include -#include "../util/type_traits.h" #include "io_context_pool.hpp" +#if __has_include("ylt/util/type_traits.h") +#include "ylt/util/type_traits.h" +#else +#include "../util/type_traits.h" +#endif #ifdef __linux__ #include #endif @@ -254,7 +271,7 @@ inline async_simple::coro::Lazy async_close(Socket &socket) noexcept { }); } -#if defined(ENABLE_SSL) || defined(CINATRA_ENABLE_SSL) +#if defined(YLT_ENABLE_SSL) || defined(CINATRA_ENABLE_SSL) inline async_simple::coro::Lazy async_handshake( auto &ssl_stream, asio::ssl::stream_base::handshake_type type) noexcept { callback_awaitor awaitor; @@ -524,6 +541,8 @@ inline auto pipe_signal_handler = [] { return 0; }(); +// FIXME: this function may not thread-safe if it not running in socket's +// executor inline async_simple::coro::Lazy> async_sendfile(asio::ip::tcp::socket &socket, int fd, off_t offset, size_t size) noexcept { @@ -559,7 +578,6 @@ async_sendfile(asio::ip::tcp::socket &socket, int fd, off_t offset, handler.set_value_then_resume(ec); }); }); - continue; } if (ec || n == 0 || least_bytes == 0) [[unlikely]] { // End of File break;