Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 15 additions & 4 deletions include/boost/http_proto/parser.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
90 changes: 82 additions & 8 deletions include/boost/http_proto/serializer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ namespace boost {
namespace http_proto {

#ifndef BOOST_HTTP_PROTO_DOCS
class serializer_service;
class message_view_base;
#endif

Expand Down Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -216,6 +277,7 @@ class serializer
consume(std::size_t n);

private:
friend class serializer_service;
class filter;
class const_buf_gen_base;
template<class>
Expand Down Expand Up @@ -282,6 +344,8 @@ class serializer
};

context& ctx_;
serializer_service& svc_;

detail::workspace ws_;

const_buf_gen_base* buf_gen_;
Expand All @@ -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.

Expand Down
2 changes: 1 addition & 1 deletion include/boost/http_proto/service/zlib_service.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
127 changes: 127 additions & 0 deletions src/detail/zlib_filter.cpp
Original file line number Diff line number Diff line change
@@ -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 <boost/buffers/front.hpp>
#include <boost/buffers/sans_prefix.hpp>
#include <boost/buffers/size.hpp>

namespace boost {
namespace http_proto {
namespace detail {

namespace {

void*
zalloc(
void* opaque,
unsigned items,
unsigned size) noexcept
{
return reinterpret_cast<workspace*>(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<unsigned int>::max())
return std::numeric_limits<unsigned int>::max();
return static_cast<unsigned int>(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<unsigned char*>(const_cast<void *>(ib.data()));
strm_.avail_in = saturate_cast(ib.size());
strm_.next_out = static_cast<unsigned char*>(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
Loading
Loading