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
{