diff --git a/Makefile.am b/Makefile.am index c5beae820..83a2964c0 100644 --- a/Makefile.am +++ b/Makefile.am @@ -580,6 +580,7 @@ include_bitcoin_network_messages_HEADERS = \ include_bitcoin_network_messages_httpdir = ${includedir}/bitcoin/network/messages/http include_bitcoin_network_messages_http_HEADERS = \ include/bitcoin/network/messages/http/fields.hpp \ + include/bitcoin/network/messages/http/file_writer.hpp \ include/bitcoin/network/messages/http/http.hpp include_bitcoin_network_messages_http_enumsdir = ${includedir}/bitcoin/network/messages/http/enums diff --git a/builds/msvc/vs2022/libbitcoin-network/libbitcoin-network.vcxproj b/builds/msvc/vs2022/libbitcoin-network/libbitcoin-network.vcxproj index 18f16a7ac..d51267951 100644 --- a/builds/msvc/vs2022/libbitcoin-network/libbitcoin-network.vcxproj +++ b/builds/msvc/vs2022/libbitcoin-network/libbitcoin-network.vcxproj @@ -338,6 +338,7 @@ + diff --git a/builds/msvc/vs2022/libbitcoin-network/libbitcoin-network.vcxproj.filters b/builds/msvc/vs2022/libbitcoin-network/libbitcoin-network.vcxproj.filters index e66de30ca..2b28f9ac3 100644 --- a/builds/msvc/vs2022/libbitcoin-network/libbitcoin-network.vcxproj.filters +++ b/builds/msvc/vs2022/libbitcoin-network/libbitcoin-network.vcxproj.filters @@ -779,6 +779,9 @@ include\bitcoin\network\messages\http + + include\bitcoin\network\messages\http + include\bitcoin\network\messages\http diff --git a/builds/msvc/vs2026/libbitcoin-network/libbitcoin-network.vcxproj b/builds/msvc/vs2026/libbitcoin-network/libbitcoin-network.vcxproj index 5bcdaee0e..4b85360f2 100644 --- a/builds/msvc/vs2026/libbitcoin-network/libbitcoin-network.vcxproj +++ b/builds/msvc/vs2026/libbitcoin-network/libbitcoin-network.vcxproj @@ -338,6 +338,7 @@ + diff --git a/builds/msvc/vs2026/libbitcoin-network/libbitcoin-network.vcxproj.filters b/builds/msvc/vs2026/libbitcoin-network/libbitcoin-network.vcxproj.filters index e66de30ca..2b28f9ac3 100644 --- a/builds/msvc/vs2026/libbitcoin-network/libbitcoin-network.vcxproj.filters +++ b/builds/msvc/vs2026/libbitcoin-network/libbitcoin-network.vcxproj.filters @@ -779,6 +779,9 @@ include\bitcoin\network\messages\http + + include\bitcoin\network\messages\http + include\bitcoin\network\messages\http diff --git a/include/bitcoin/network.hpp b/include/bitcoin/network.hpp index 417be723f..03499bdf3 100644 --- a/include/bitcoin/network.hpp +++ b/include/bitcoin/network.hpp @@ -67,6 +67,7 @@ #include #include #include +#include #include #include #include @@ -162,7 +163,6 @@ #include #include #include -#if WITH_SSL #include #include #include @@ -291,6 +291,5 @@ #include #include #include -#endif #endif diff --git a/include/bitcoin/network/beast.hpp b/include/bitcoin/network/beast.hpp index 06c25611d..b81a07e7a 100644 --- a/include/bitcoin/network/beast.hpp +++ b/include/bitcoin/network/beast.hpp @@ -52,8 +52,9 @@ namespace http using chunk_body = boost::beast::http::vector_body>; + // This is wrapped for http_body. /// beast::http::file_body - using file_body = boost::beast::http::file_body; + ////using file_body = boost::beast::http::file_body; /// beast::http::span_body /// Must cast write span uint8_t* to non-const. @@ -67,7 +68,7 @@ namespace http using string_body = boost::beast::http::string_body; /// general purpose - using file = file_body::value_type; + using file = boost::beast::http::file_body::value_type; using field = boost::beast::http::field; using fields = boost::beast::http::fields; using flat_buffer = boost::beast::flat_buffer; diff --git a/include/bitcoin/network/messages/http/file_writer.hpp b/include/bitcoin/network/messages/http/file_writer.hpp new file mode 100644 index 000000000..b7eb19d2b --- /dev/null +++ b/include/bitcoin/network/messages/http/file_writer.hpp @@ -0,0 +1,90 @@ +/** + * Copyright (c) 2011-2026 libbitcoin developers (see AUTHORS) + * + * This file is part of libbitcoin. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +#ifndef LIBBITCOIN_NETWORK_MESSAGES_HTTP_FILE_WRITER_HPP +#define LIBBITCOIN_NETWORK_MESSAGES_HTTP_FILE_WRITER_HPP + +#include +#include + +namespace libbitcoin { +namespace network { +namespace http { + +/// BOOST_BEAST_FILE_BUFFER_SIZE reduced from 4k to 1k in beast.hpp. +/// beast_body::writer would eat up 1k in variant so wrap in this custom body. +struct file_body +{ + using beast_body = boost::beast::http::file_body; + using value_type = beast_body::value_type; + using reader = beast_body::reader; + + struct writer + { + using const_buffers_type = asio::const_buffer; + using out_buffer = http::get_buffer; + + template + explicit writer(http::message_header& header, + beast_body::value_type& value) NOEXCEPT + : writer_(std::make_unique(header, value)) + { + } + + inline void init(boost_code& ec) NOEXCEPT + { + try + { + writer_->init(ec); + } + catch (...) + { + using namespace error; + ec = to_http_code(http_error_t::end_of_stream); + } + } + + inline out_buffer get(boost_code& ec) NOEXCEPT + { + try + { + return writer_->get(ec); + } + catch (...) + { + using namespace error; + ec = to_http_code(http_error_t::end_of_stream); + return {}; + } + } + + private: + std::unique_ptr writer_; + }; + + static inline uint64_t size(value_type const& body) NOEXCEPT + { + return beast_body::size(body); + } +}; + +} // namespace http +} // namespace network +} // namespace libbitcoin + +#endif diff --git a/include/bitcoin/network/messages/http/http.hpp b/include/bitcoin/network/messages/http/http.hpp index 1e42978da..d4576eaaf 100644 --- a/include/bitcoin/network/messages/http/http.hpp +++ b/include/bitcoin/network/messages/http/http.hpp @@ -19,11 +19,12 @@ #ifndef LIBBITCOIN_NETWORK_MESSAGES_HTTP_HTTP_HPP #define LIBBITCOIN_NETWORK_MESSAGES_HTTP_HTTP_HPP - #include - #include - #include - #include - #include - #include +#include +#include +#include +#include +#include +#include +#include #endif diff --git a/include/bitcoin/network/messages/http_body.hpp b/include/bitcoin/network/messages/http_body.hpp index 1efd31987..97be9a1ee 100644 --- a/include/bitcoin/network/messages/http_body.hpp +++ b/include/bitcoin/network/messages/http_body.hpp @@ -40,19 +40,17 @@ using string_reader = http::string_body::reader; using json_reader = http::json_body::reader; using body_reader = std::variant < - std::monostate, - empty_reader, - data_reader, - file_reader, - span_reader, - buffer_reader, - string_reader, - json_reader, - rpc::reader + std::monostate, // 1 byte + empty_reader, // 1 bytes + data_reader, // 8 bytes + file_reader, // 8 bytes + span_reader, // 8 bytes + buffer_reader, // 8 bytes + string_reader, // 8 bytes + json_reader, // 320 bytes! + rpc::reader // 328 bytes! >; -// TODO: file_writer is eating 4k stack for each type. -// BOOST_BEAST_FILE_BUFFER_SIZE set to 1024 in beast.hpp. using empty_writer = http::empty_body::writer; using data_writer = http::chunk_body::writer; using file_writer = http::file_body::writer; @@ -65,7 +63,7 @@ using body_writer = std::variant std::monostate, // 1 byte empty_writer, // 1 byte data_writer, // 8 bytes - file_writer, // 1,040 bytes! (4,112 bytes by default) + file_writer, // 8 bytes span_writer, // 8 bytes buffer_writer, // 16 bytes string_writer, // 8 bytes diff --git a/src/messages/http/enums/target.cpp b/src/messages/http/enums/target.cpp index ff546e6f6..25b816d7f 100644 --- a/src/messages/http/enums/target.cpp +++ b/src/messages/http/enums/target.cpp @@ -219,7 +219,7 @@ http::file get_file_body(const std::filesystem::path& path) NOEXCEPT // http::file::open accepts a "utf-8 encoded path to the file" on win32. const auto utf8_path = from_path(path); - http::file_body::value_type file{}; + http::file file{}; try {