From de06db215a29cc157415e47e68ff3259673ee4e8 Mon Sep 17 00:00:00 2001 From: Mohammad Nejati Date: Fri, 27 Jun 2025 16:11:37 +0000 Subject: [PATCH] `serializer` uses configuration service Closes #142 --- include/boost/http_proto/parser.hpp | 19 +- include/boost/http_proto/serializer.hpp | 90 +++++++- .../boost/http_proto/service/zlib_service.hpp | 2 +- src/detail/zlib_filter.cpp | 127 +++++++++++ src/detail/zlib_filter.hpp | 82 +++++-- src/parser.cpp | 214 +++++++----------- src/serializer.cpp | 176 +++++++------- src/source.cpp | 4 +- test/unit/serializer.cpp | 39 ++-- test/unit/zlib.cpp | 8 +- 10 files changed, 466 insertions(+), 295 deletions(-) create mode 100644 src/detail/zlib_filter.cpp diff --git a/include/boost/http_proto/parser.hpp b/include/boost/http_proto/parser.hpp index 13be40aa..6ad9485f 100644 --- a/include/boost/http_proto/parser.hpp +++ b/include/boost/http_proto/parser.hpp @@ -93,22 +93,33 @@ class parser */ std::uint64_t body_limit = 64 * 1024; - /** True if parser can decode deflate transfer and content encodings. + /** True if parser can decode deflate Content-Encoding. - The zlib service must already be + The @ref zlib::inflate_service must already be installed thusly, or else an exception is thrown. */ bool apply_deflate_decoder = false; - /** True if parser can decode gzip transfer and content encodings. + /** True if parser can decode gzip Content-Encoding. - The zlib service must already be + The @ref zlib::inflate_service must already be installed thusly, or else an exception is thrown. */ bool apply_gzip_decoder = false; + /** Specifies the zlib windows bits 9..15. + + The windows bits must be greater than or equal to + the windows bits value used for compression. + + If a compressed message has a larger window size, + parsing ends with @ref zlib::error::data_err instead + of allocating a bigger window. + */ + int zlib_window_bits = 15; + /** Minimum space for payload buffering. This value controls the following diff --git a/include/boost/http_proto/serializer.hpp b/include/boost/http_proto/serializer.hpp index 7beaed74..10dcab7d 100644 --- a/include/boost/http_proto/serializer.hpp +++ b/include/boost/http_proto/serializer.hpp @@ -33,6 +33,7 @@ namespace boost { namespace http_proto { #ifndef BOOST_HTTP_PROTO_DOCS +class serializer_service; class message_view_base; #endif @@ -66,6 +67,73 @@ class serializer using const_buffers_type = buffers::const_buffer_span; + /** Serializer configuration settings. + */ + struct config + { + /** True if serializer can encode deflate Content-Encoding. + + The @ref zlib::deflate_service must already be + installed thusly, or else an exception + is thrown. + */ + bool apply_deflate_encoder = false; + + /** True if serializer can encode gzip Content-Encoding. + + The @ref zlib::deflate_service must already be + installed thusly, or else an exception + is thrown. + */ + bool apply_gzip_encoder = false; + + /** Specifies the zlib compression level 0..9. + + A compression level of 1 provides the fastest speed, + while level 9 offers the best compression. Level 0 + applies no compression at all. + */ + int zlib_comp_level = 6; + + /** Specifies the zlib windows bits 9..15. + + The windows bits controls the size of the history + buffer used when compressing data. Larger values + produce better compression at the expense of + greater memory usage. + */ + int zlib_window_bits = 15; + + /** Specifies the zlib memory level 1..9. + + The memory level controls the amount of memory + used for the internal compression state. Larger + values use more memory, but are faster and + produce smaller output. + */ + int zlib_mem_level = 8; + + /** Minimum space for payload buffering. + + This cannot be zero. + */ + std::size_t payload_buffer = 8192; + + /** Space to reserve for type-erasure. + + This space is used for the following + purposes: + + @li Storing an instance of the user-provided + @ref source objects. + + @li Storing an instance of the user-provided + ConstBufferSequence. + + */ + std::size_t max_type_erase = 1024; + }; + struct stream; /** Destructor @@ -82,19 +150,12 @@ class serializer /** Constructor @param ctx The serializer will access services - registered with this context. + registered with this context. */ BOOST_HTTP_PROTO_DECL serializer( context& ctx); - /** Constructor - */ - BOOST_HTTP_PROTO_DECL - serializer( - context& ctx, - std::size_t buffer_size); - //-------------------------------------------- /** Prepare the serializer for a new stream @@ -216,6 +277,7 @@ class serializer consume(std::size_t n); private: + friend class serializer_service; class filter; class const_buf_gen_base; template @@ -282,6 +344,8 @@ class serializer }; context& ctx_; + serializer_service& svc_; + detail::workspace ws_; const_buf_gen_base* buf_gen_; @@ -304,6 +368,16 @@ class serializer //------------------------------------------------ +/** Install the serializer service. +*/ +BOOST_HTTP_PROTO_DECL +void +install_serializer_service( + context& ctx, + serializer::config const& cfg); + +//------------------------------------------------ + /** The type used for caller-provided body data during serialization. diff --git a/include/boost/http_proto/service/zlib_service.hpp b/include/boost/http_proto/service/zlib_service.hpp index d6e83b46..49840b14 100644 --- a/include/boost/http_proto/service/zlib_service.hpp +++ b/include/boost/http_proto/service/zlib_service.hpp @@ -34,7 +34,7 @@ struct stream unsigned int avail_out; // remaining free space at next_out unsigned long total_out; // total number of bytes output so far - char* msg; // last error message, NULL if no error + char* msg; // last error message, NULL if no error void* state; // not visible by applications alloc_func zalloc; // used to allocate internal state diff --git a/src/detail/zlib_filter.cpp b/src/detail/zlib_filter.cpp new file mode 100644 index 00000000..b3347235 --- /dev/null +++ b/src/detail/zlib_filter.cpp @@ -0,0 +1,127 @@ +// +// Copyright (c) 2023 Vinnie Falco (vinnie.falco@gmail.com) +// Copyright (c) 2024 Mohammad Nejati +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/cppalliance/buffers +// + +#include "src/detail/zlib_filter.hpp" + +#include +#include +#include + +namespace boost { +namespace http_proto { +namespace detail { + +namespace { + +void* +zalloc( + void* opaque, + unsigned items, + unsigned size) noexcept +{ + return reinterpret_cast(opaque) + ->try_reserve_front(items * size); +} + +void +zfree( + void* /* opaque */, + void* /* addr */) noexcept +{ + // no-op +} + +unsigned int +saturate_cast(std::size_t n) noexcept +{ + if(n >= std::numeric_limits::max()) + return std::numeric_limits::max(); + return static_cast(n); +} + +} // namespace + +zlib_filter:: +zlib_filter(workspace& ws) +{ + strm_.zalloc = &zalloc; + strm_.zfree = &zfree; + strm_.opaque = &ws; +} + +auto +zlib_filter:: +process( + buffers::mutable_buffer_subspan out, + buffers::const_buffer_pair in, + bool more, + bool force_flush) -> results +{ + results rv; + auto flush = zlib::no_flush; + for(;;) + { + auto ob = buffers::front(out); + auto ib = buffers::front(in); + + if(!more && flush != zlib::finish && in[1].size() == 0) + { + if(buffers::size(out) < min_out_buffer()) + { + rv.out_short = true; + return rv; + } + flush = zlib::finish; + } + + strm_.next_in = static_cast(const_cast(ib.data())); + strm_.avail_in = saturate_cast(ib.size()); + strm_.next_out = static_cast(ob.data()); + strm_.avail_out = saturate_cast(ob.size()); + + auto ec = BOOST_HTTP_PROTO_ERR( + do_process(flush)); + + const std::size_t in_bytes = saturate_cast(ib.size()) - strm_.avail_in; + const std::size_t out_bytes = saturate_cast(ob.size()) - strm_.avail_out; + + rv.in_bytes += in_bytes; + rv.out_bytes += out_bytes; + + if(ec.failed()) + return rv; + + if(ec == zlib::error::stream_end) + { + rv.finished = true; + return rv; + } + + out = buffers::sans_prefix(out, out_bytes); + in = buffers::sans_prefix(in, in_bytes); + + if(buffers::size(out) == 0) + return rv; + + if(buffers::size(in) == 0 && strm_.avail_out != 0) + { + if(force_flush && rv.out_bytes == 0) + { + flush = zlib::block; + continue; + } + return rv; + } + } +} + +} // detail +} // http_proto +} // boost diff --git a/src/detail/zlib_filter.hpp b/src/detail/zlib_filter.hpp index 0dd84bbc..b0d13344 100644 --- a/src/detail/zlib_filter.hpp +++ b/src/detail/zlib_filter.hpp @@ -12,41 +12,75 @@ #define BOOST_HTTP_PROTO_DETAIL_ZLIB_FILTER_HPP #include +#include + +#include +#include namespace boost { namespace http_proto { namespace detail { -/** utilities for zlib filter +/** Base class for zlib filters */ class zlib_filter { -protected: - static - void* zalloc( - void* opaque, - unsigned items, - unsigned size) noexcept +public: + /** The results of processing the filter. + */ + struct results { - return reinterpret_cast< - detail::workspace*>(opaque)->try_reserve_front(items * size); - } + /** The number of bytes produced in the output. - static - void - zfree(void* /* opaque */, void* /* addr */) noexcept - { - // no-op - } + This may be less than the total number + of bytes available for writing in the + destination buffers. + */ + std::size_t out_bytes = 0; - static - unsigned int - saturate_cast(std::size_t n) noexcept - { - if(n >= std::numeric_limits::max()) - return std::numeric_limits::max(); - return static_cast(n); - } + /** The number of bytes consumed from the input. + + This may be less than the total number + of bytes available for reading in the + source buffers. + */ + std::size_t in_bytes = 0; + + /** The error, if any occurred. + */ + system::error_code ec; + + /** True if the output buffer is too + small to make progress. + + This can only happen in deflate operation. + */ + bool out_short = false; + + /** True if there will be no more output. + */ + bool finished = false; + }; + + zlib_filter(workspace& ws); + + results + process( + buffers::mutable_buffer_subspan out, + buffers::const_buffer_pair in, + bool more, + bool force_flush = false); + +protected: + zlib::stream strm_; + + virtual + std::size_t + min_out_buffer() const noexcept = 0; + + virtual + zlib::error + do_process(zlib::flush) noexcept = 0; }; } // detail diff --git a/src/parser.cpp b/src/parser.cpp index a9f51187..e0d586c8 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -137,7 +137,7 @@ class chained_sequence if(pos_ < end_) return pos_; - // swap with the second range + // bring the second range if(begin_b_ != end_b_) { pos_ = begin_b_; @@ -152,7 +152,7 @@ class chained_sequence } bool - empty() const noexcept + is_empty() const noexcept { return pos_ == end_; } @@ -177,7 +177,7 @@ parse_hex( { std::uint64_t v = 0; std::size_t init_size = cs.size(); - while(!cs.empty()) + while(!cs.is_empty()) { auto n = grammar::hexdig_value(cs.value()); if(n < 0) @@ -212,7 +212,7 @@ find_eol( chained_sequence& cs, system::error_code& ec) noexcept { - while(!cs.empty()) + while(!cs.is_empty()) { if(cs.value() == '\r') { @@ -259,7 +259,7 @@ skip_trailer_headers( chained_sequence& cs, system::error_code& ec) noexcept { - while(!cs.empty()) + while(!cs.is_empty()) { if(cs.value() == '\r') { @@ -300,80 +300,35 @@ class parser::filter : public detail::zlib_filter { zlib::inflate_service& svc_; - zlib::stream strm_; public: - struct results - { - std::size_t out_bytes = 0; - std::size_t in_bytes = 0; - bool finished = false; - system::error_code ec; - }; - filter( context& ctx, http_proto::detail::workspace& ws, - bool gzip) - : svc_(ctx.get_service()) + int window_bits) + : zlib_filter(ws) + , svc_(ctx.get_service()) { - strm_.zalloc = &zalloc; - strm_.zfree = &zfree; - strm_.opaque = &ws; system::error_code ec = static_cast( - svc_.init2(strm_, gzip ? 31 : 15)); + svc_.init2(strm_, window_bits)); if(ec != zlib::error::ok) detail::throw_system_error(ec); } - results - process( - buffers::mutable_buffer_subspan out, - buffers::const_buffer_pair in, - bool more) +private: + virtual + std::size_t + min_out_buffer() const noexcept override { - results rv; - auto flush = zlib::no_flush; - for(;;) - { - const auto ob = buffers::front(out); - const auto ib = buffers::front(in); - - if(!more && in[1].size() == 0) - flush = zlib::finish; - - strm_.next_in = static_cast(const_cast(ib.data())); - strm_.avail_in = saturate_cast(ib.size()); - strm_.next_out = static_cast(ob.data()); - strm_.avail_out = saturate_cast(ob.size()); - - auto ec = BOOST_HTTP_PROTO_ERR( - static_cast(svc_.inflate(strm_, flush))); - - const std::size_t in_bytes = saturate_cast(ib.size()) - strm_.avail_in; - const std::size_t out_bytes = saturate_cast(ob.size()) - strm_.avail_out; - - rv.in_bytes += in_bytes; - rv.out_bytes += out_bytes; - - if(ec.failed()) - return rv; - - if(ec == zlib::error::stream_end) - { - rv.finished = true; - return rv; - } - - out = buffers::sans_prefix(out, out_bytes); - in = buffers::sans_prefix(in, in_bytes); - - if(buffers::size(out) == 0) - return rv; + return 0; + } - if(buffers::size(in) == 0 && strm_.avail_out != 0) - return rv; - } + virtual + zlib::error + do_process(zlib::flush flush) noexcept override + { + return static_cast< + zlib::error>(svc_.inflate(strm_, flush)); } }; @@ -386,73 +341,58 @@ class parser_service std::size_t max_codec = 0; parser_service( - context& ctx, - parser::config_base const& cfg_); - - std::size_t - max_overread() const noexcept - { - return - cfg.headers.max_size + - cfg.min_buffer; - } -}; - -parser_service:: -parser_service( - context& /* ctx */, - parser::config_base const& cfg_) + context&, + parser::config_base const& cfg_) : cfg(cfg_) -{ -/* - | fb | cb0 | cb1 | C | T | f | - - fb flat_buffer headers.max_size - cb0 circular_buffer min_buffer - cb1 circular_buffer min_buffer - C codec max_codec - T body max_type_erase - f table max_table_space - -*/ - // validate - //if(cfg.min_prepare > cfg.max_prepare) - //detail::throw_invalid_argument(); - - if(cfg.max_prepare < 1) - detail::throw_invalid_argument(); - - // VFALCO TODO OVERFLOW CHECING { - //fb_.size() - h_.size + - //svc_.cfg.min_buffer + - //svc_.cfg.min_buffer + - //svc_.max_codec; - } + /* + | fb | cb0 | cb1 | C | T | f | + + fb flat_buffer headers.max_size + cb0 circular_buffer min_buffer + cb1 circular_buffer min_buffer + C codec max_codec + T body max_type_erase + f table max_table_space + + */ + // validate + //if(cfg.min_prepare > cfg.max_prepare) + //detail::throw_invalid_argument(); + + if(cfg.max_prepare < 1) + detail::throw_invalid_argument(); + + // VFALCO TODO OVERFLOW CHECING + { + //fb_.size() - h_.size + + //svc_.cfg.min_buffer + + //svc_.cfg.min_buffer + + //svc_.max_codec; + } - // VFALCO OVERFLOW CHECKING ON THIS - space_needed += - cfg.headers.valid_space_needed(); + // VFALCO OVERFLOW CHECKING ON THIS + space_needed += + cfg.headers.valid_space_needed(); - // cb0_, cb1_ - // VFALCO OVERFLOW CHECKING ON THIS - space_needed += - cfg.min_buffer + - cfg.min_buffer; + // cb0_, cb1_ + // VFALCO OVERFLOW CHECKING ON THIS + space_needed += + cfg.min_buffer + + cfg.min_buffer; - // T - space_needed += cfg.max_type_erase; + // T + space_needed += cfg.max_type_erase; - // max_codec - { - if(cfg.apply_deflate_decoder) + // max_codec + if(cfg.apply_deflate_decoder || cfg.apply_gzip_decoder) { // TODO: Account for the number of allocations and // their overhead in the workspace. // https://www.zlib.net/zlib_tech.html std::size_t n = - (1 << 15) + // window_bits + (1 << cfg.zlib_window_bits) + (7 * 1024) + #ifdef __s390x__ 5768 + @@ -463,15 +403,23 @@ parser_service( if(max_codec < n) max_codec = n; } + space_needed += max_codec; + + // round up to alignof(detail::header::entry) + auto const al = alignof( + detail::header::entry); + space_needed = al * (( + space_needed + al - 1) / al); } - space_needed += max_codec; - // round up to alignof(detail::header::entry) - auto const al = alignof( - detail::header::entry); - space_needed = al * (( - space_needed + al - 1) / al); -} + std::size_t + max_overread() const noexcept + { + return + cfg.headers.max_size + + cfg.min_buffer; + } +}; void install_parser_service( @@ -492,13 +440,11 @@ parser:: parser(context& ctx, detail::kind k) : ctx_(ctx) , svc_(ctx.get_service()) + , ws_(svc_.space_needed) , h_(detail::empty{ k }) , st_(state::reset) , got_header_(false) { - auto const n = svc_.space_needed; - ws_.allocate(n); - h_.cap = n; } parser:: @@ -1067,12 +1013,14 @@ parse( if(svc_.cfg.apply_deflate_decoder && h_.md.content_encoding.encoding == encoding::deflate) { - filter_ = &ws_.emplace(ctx_, ws_, false); + filter_ = &ws_.emplace( + ctx_, ws_, svc_.cfg.zlib_window_bits); } else if(svc_.cfg.apply_gzip_decoder && h_.md.content_encoding.encoding == encoding::gzip) { - filter_ = &ws_.emplace(ctx_, ws_, true); + filter_ = &ws_.emplace( + ctx_, ws_, svc_.cfg.zlib_window_bits + 16); } else { diff --git a/src/serializer.cpp b/src/serializer.cpp index 1d54cef3..da384f4e 100644 --- a/src/serializer.cpp +++ b/src/serializer.cpp @@ -189,106 +189,90 @@ class serializer::filter : public detail::zlib_filter { zlib::deflate_service& svc_; - zlib::stream strm_; public: - struct results - { - std::size_t out_bytes = 0; - std::size_t in_bytes = 0; - bool out_short = false; - bool finished = false; - system::error_code ec; - }; - filter( context& ctx, http_proto::detail::workspace& ws, - bool gzip) - : svc_(ctx.get_service()) + int comp_level, + int window_bits, + int mem_level) + : zlib_filter(ws) + , svc_(ctx.get_service()) { - strm_.zalloc = &zalloc; - strm_.zfree = &zfree; - strm_.opaque = &ws; system::error_code ec = static_cast(svc_.init2( strm_, - zlib::default_compression, + comp_level, zlib::deflated, - gzip ? 31 : 15, - 8, + window_bits, + mem_level, zlib::default_strategy)); if(ec != zlib::error::ok) detail::throw_system_error(ec); } - results - process( - buffers::mutable_buffer_pair out, - buffers::const_buffer_pair in, - bool more, - bool force_flush = false) +private: + virtual + std::size_t + min_out_buffer() const noexcept override { - results rv; - auto flush = zlib::no_flush; - for(;;) - { - auto ob = buffers::front(out); - auto ib = buffers::front(in); - - if(!more && flush != zlib::finish && in[1].size() == 0) - { - // Prevent deflate from producing - // zero output due to small buffer - if(buffers::size(out) < 8) - { - rv.out_short = true; - return rv; - } - flush = zlib::finish; - } - - strm_.next_in = static_cast(const_cast(ib.data())); - strm_.avail_in = saturate_cast(ib.size()); - strm_.next_out = static_cast(ob.data()); - strm_.avail_out = saturate_cast(ob.size()); - - auto ec = BOOST_HTTP_PROTO_ERR( - static_cast(svc_.deflate(strm_, flush))); - - const std::size_t in_bytes = saturate_cast(ib.size()) - strm_.avail_in; - const std::size_t out_bytes = saturate_cast(ob.size()) - strm_.avail_out; - - rv.in_bytes += in_bytes; - rv.out_bytes += out_bytes; - - if(ec.failed()) - return rv; + // Prevents deflate from producing + // zero output due to small buffer + return 8; + } - if(ec == zlib::error::stream_end) - { - rv.finished = true; - return rv; - } + virtual + zlib::error + do_process(zlib::flush flush) noexcept override + { + return static_cast< + zlib::error>(svc_.deflate(strm_, flush)); + } +}; - out = buffers::sans_prefix(out, out_bytes); - in = buffers::sans_prefix(in, in_bytes); +class serializer_service + : public service +{ +public: + serializer::config cfg; + std::size_t space_needed = 0; - if(buffers::size(out) == 0) - return rv; + serializer_service( + context&, + serializer::config const& cfg_) + : cfg(cfg_) + { + space_needed += cfg.payload_buffer; + space_needed += cfg.max_type_erase; - if(buffers::size(in) == 0 && strm_.avail_out != 0) - { - if(force_flush && rv.out_bytes == 0) - { - flush = zlib::block; - continue; - } - return rv; - } + if(cfg.apply_deflate_encoder || cfg.apply_gzip_encoder) + { + // TODO: Account for the number of allocations and + // their overhead in the workspace. + + // https://www.zlib.net/zlib_tech.html + space_needed += + (1 << (cfg.zlib_window_bits + 2)) + + (1 << (cfg.zlib_mem_level + 9)) + + (6 * 1024) + + #ifdef __s390x__ + 5768 + + #endif + detail::workspace::space_needed< + serializer::filter>(); } } }; +void +install_serializer_service( + context& ctx, + serializer::config const& cfg) +{ + ctx.make_service< + serializer_service>(cfg); +} + serializer:: ~serializer() { @@ -299,18 +283,10 @@ serializer( serializer&&) noexcept = default; serializer:: -serializer( - context& ctx) - : serializer(ctx, 65536) -{ -} - -serializer:: -serializer( - context& ctx, - std::size_t buffer_size) +serializer(context& ctx) : ctx_(ctx) - , ws_(buffer_size) + , svc_(ctx.get_service()) + , ws_(svc_.space_needed) { } @@ -446,7 +422,7 @@ prepare() -> } const auto rs = filter_->process( - apndr.prepare(), + buffers::mutable_buffer_span(apndr.prepare()), { tmp_, {} }, more_input_); @@ -488,7 +464,7 @@ prepare() -> } const auto rs = filter_->process( - apndr.prepare(), + buffers::mutable_buffer_span(apndr.prepare()), cb1_.data(), more_input_); @@ -529,7 +505,7 @@ prepare() -> } const auto rs = filter_->process( - apndr.prepare(), + buffers::mutable_buffer_span(apndr.prepare()), cb1_.data(), more_input_, prepped_.empty()); // force_flush @@ -645,13 +621,21 @@ start_init( auto const& ce = md.content_encoding; if(ce.encoding == encoding::deflate) { - filter_ = &ws_.emplace< - filter>(ctx_, ws_, false); + filter_ = &ws_.emplace( + ctx_, + ws_, + svc_.cfg.zlib_comp_level, + svc_.cfg.zlib_window_bits, + svc_.cfg.zlib_mem_level); } else if(ce.encoding == encoding::gzip) { - filter_ = &ws_.emplace< - filter>(ctx_, ws_, true); + filter_ = &ws_.emplace( + ctx_, + ws_, + svc_.cfg.zlib_comp_level, + svc_.cfg.zlib_window_bits + 16, + svc_.cfg.zlib_mem_level); } } @@ -1018,7 +1002,5 @@ close() const sr_->cb0_.commit(final_chunk_len); } -//------------------------------------------------ - } // http_proto } // boost diff --git a/src/source.cpp b/src/source.cpp index ca7abc93..7b535085 100644 --- a/src/source.cpp +++ b/src/source.cpp @@ -33,8 +33,8 @@ on_read( return rv; if(rs.finished) break; - // Source must fill the entire buffer - // unless it has finished + // source must fill the entire buffer + // if it is not finished if(b.size() != rs.bytes) detail::throw_logic_error(); } diff --git a/test/unit/serializer.cpp b/test/unit/serializer.cpp index 5d970de6..cd531c6a 100644 --- a/test/unit/serializer.cpp +++ b/test/unit/serializer.cpp @@ -176,7 +176,8 @@ struct serializer_test testSyntax() { context ctx; - serializer sr(ctx, 1024); + install_serializer_service(ctx, {}); + serializer sr(ctx); response res; sr.start(res); @@ -203,7 +204,6 @@ struct serializer_test sr.start_stream(res); sr.reset(); - serializer(ctx, 65536); #ifdef BOOST_HTTP_PROTO_HAS_ZLIB #if 0 serializer(65536, gzip_decoder); @@ -225,6 +225,7 @@ struct serializer_test { response res(headers); context ctx; + install_serializer_service(ctx, {}); serializer sr(ctx); sr.start(res); std::string s = read(sr); @@ -281,6 +282,7 @@ struct serializer_test } context ctx; + install_serializer_service(ctx, {}); serializer sr(ctx); buffers::const_buffer_span cbs( buf.data(), buf.size()); @@ -308,35 +310,29 @@ struct serializer_test // we limit the buffer size of the serializer, requiring // it to make multiple calls to source::read context ctx; - serializer sr(ctx, 1024); + install_serializer_service(ctx, {}); + serializer sr(ctx); sr.start(res, std::forward< Source>(src)); std::string s = read(sr); f(s); } - struct check_stream_opts - { - std::size_t sr_capacity = 1024; - }; - template void check_stream( core::string_view headers, core::string_view body, - check_stream_opts const& opts, F f) { - auto sr_capacity = opts.sr_capacity; - response res(headers); - context ctx; - serializer sr(ctx, sr_capacity); + install_serializer_service(ctx, {}); + serializer sr(ctx); auto stream = sr.start_stream(res); - BOOST_TEST_GT(stream.capacity(), 0); - BOOST_TEST_LE(stream.capacity(), sr_capacity); + BOOST_TEST_GT( + stream.capacity(), + serializer::config{}.payload_buffer); std::vector s; // stores complete output @@ -511,6 +507,7 @@ struct serializer_test "HTTP/1.1 200 OK\r\n" "\r\n"); context ctx; + install_serializer_service(ctx, {}); serializer sr(ctx); sr.start( @@ -559,13 +556,11 @@ struct serializer_test // empty stream { - check_stream_opts opts; check_stream( "HTTP/1.1 200 OK\r\n" "Server: test\r\n" "\r\n", std::string(0, '*'), - opts, [](core::string_view s) { core::string_view expected_header = @@ -580,14 +575,12 @@ struct serializer_test // empty stream, chunked { - check_stream_opts opts; check_stream( "HTTP/1.1 200 OK\r\n" "Server: test\r\n" "Transfer-Encoding: chunked\r\n" "\r\n", std::string(0, '*'), - opts, [](core::string_view s) { core::string_view expected_header = @@ -603,14 +596,12 @@ struct serializer_test // stream { - check_stream_opts opts; check_stream( "HTTP/1.1 200 OK\r\n" "Server: test\r\n" "Content-Length: 13370\r\n" "\r\n", std::string(13370, '*'), - opts, [](core::string_view s){ core::string_view expected_header = "HTTP/1.1 200 OK\r\n" @@ -629,14 +620,12 @@ struct serializer_test // stream, chunked { - check_stream_opts opts; check_stream( "HTTP/1.1 200 OK\r\n" "Server: test\r\n" "Transfer-Encoding: chunked\r\n" "\r\n", std::string(13370, '*'), - opts, [](core::string_view s) { core::string_view expected_header = @@ -659,6 +648,7 @@ struct serializer_test // request { context ctx; + install_serializer_service(ctx, {}); serializer sr(ctx); request req( "GET / HTTP/1.1\r\n" @@ -704,6 +694,7 @@ struct serializer_test // empty body { context ctx; + install_serializer_service(ctx, {}); serializer sr(ctx); request req( "GET / HTTP/1.1\r\n" @@ -748,6 +739,7 @@ struct serializer_test "\r\n"; context ctx; + install_serializer_service(ctx, {}); serializer sr(ctx); response res(sv); sr.start(res, "12345"); @@ -771,6 +763,7 @@ struct serializer_test "\r\n"; response res(sv); context ctx; + install_serializer_service(ctx, {}); serializer sr(ctx); auto stream = sr.start_stream(res); diff --git a/test/unit/zlib.cpp b/test/unit/zlib.cpp index 9ea6cd5a..31b3377b 100644 --- a/test/unit/zlib.cpp +++ b/test/unit/zlib.cpp @@ -335,9 +335,11 @@ struct zlib_test { context ctx; zlib::install_deflate_service(ctx); - serializer sr( - ctx, - 512 * 1024); + serializer::config cfg; + cfg.apply_deflate_encoder = true; + cfg.apply_gzip_encoder = true; + install_serializer_service(ctx, cfg); + serializer sr(ctx); // prove we can reuse the serializer successfully for( int i = 0; i < 2; ++i )