mirror of
https://github.com/boostorg/beast.git
synced 2025-07-29 20:37:31 +02:00
Make chunk_encode public:
fix #154, fix #156 This adds public interfaces for transforming buffer sequences into their chunk-encoded equivalents. The transformations are O(1) in space and time.
This commit is contained in:
@ -2,6 +2,8 @@
|
||||
|
||||
HTTP
|
||||
|
||||
* Make chunk_encode public
|
||||
|
||||
WebSocket
|
||||
|
||||
* Optimize utf8 validation
|
||||
|
@ -59,6 +59,8 @@
|
||||
<member><link linkend="beast.ref.http__async_parse">async_parse</link></member>
|
||||
<member><link linkend="beast.ref.http__async_read">async_read</link></member>
|
||||
<member><link linkend="beast.ref.http__async_write">async_write</link></member>
|
||||
<member><link linkend="beast.ref.http__chunk_encode">chunk_encode</link></member>
|
||||
<member><link linkend="beast.ref.http__chunk_encode_final">chunk_encode_final</link></member>
|
||||
<member><link linkend="beast.ref.http__is_keep_alive">is_keep_alive</link></member>
|
||||
<member><link linkend="beast.ref.http__is_upgrade">is_upgrade</link></member>
|
||||
<member><link linkend="beast.ref.http__parse">parse</link></member>
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include <beast/http/basic_headers.hpp>
|
||||
#include <beast/http/basic_parser_v1.hpp>
|
||||
#include <beast/http/body_type.hpp>
|
||||
#include <beast/http/chunk_encode.hpp>
|
||||
#include <beast/http/empty_body.hpp>
|
||||
#include <beast/http/headers.hpp>
|
||||
#include <beast/http/message.hpp>
|
||||
|
@ -11,7 +11,6 @@
|
||||
#include <beast/core/buffer_cat.hpp>
|
||||
#include <boost/asio/buffer.hpp>
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/logic/tribool.hpp>
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <cstddef>
|
||||
@ -20,7 +19,6 @@
|
||||
|
||||
namespace beast {
|
||||
namespace http {
|
||||
namespace detail {
|
||||
|
||||
class chunk_encode_text
|
||||
{
|
||||
@ -29,6 +27,14 @@ class chunk_encode_text
|
||||
// Storage for the longest hex string we might need, plus delimiters.
|
||||
std::array<char, 2 * sizeof(std::size_t) + 2> buf_;
|
||||
|
||||
template<class = void>
|
||||
void
|
||||
copy(chunk_encode_text const& other);
|
||||
|
||||
template<class = void>
|
||||
void
|
||||
setup(std::size_t n);
|
||||
|
||||
template<class OutIter>
|
||||
static
|
||||
OutIter
|
||||
@ -54,22 +60,13 @@ public:
|
||||
|
||||
chunk_encode_text(chunk_encode_text const& other)
|
||||
{
|
||||
auto const n =
|
||||
boost::asio::buffer_size(other.cb_);
|
||||
buf_ = other.buf_;
|
||||
cb_ = boost::asio::const_buffer(
|
||||
&buf_[buf_.size() - n], n);
|
||||
copy(other);
|
||||
}
|
||||
|
||||
explicit
|
||||
chunk_encode_text(std::size_t n)
|
||||
{
|
||||
buf_[buf_.size() - 2] = '\r';
|
||||
buf_[buf_.size() - 1] = '\n';
|
||||
auto it = to_hex(buf_.end() - 2, n);
|
||||
cb_ = boost::asio::const_buffer{&*it,
|
||||
static_cast<std::size_t>(
|
||||
std::distance(it, buf_.end()))};
|
||||
setup(n);
|
||||
}
|
||||
|
||||
const_iterator
|
||||
@ -84,12 +81,38 @@ public:
|
||||
return begin() + 1;
|
||||
}
|
||||
};
|
||||
template<class>
|
||||
void
|
||||
chunk_encode_text::
|
||||
copy(chunk_encode_text const& other)
|
||||
{
|
||||
auto const n =
|
||||
boost::asio::buffer_size(other.cb_);
|
||||
buf_ = other.buf_;
|
||||
cb_ = boost::asio::const_buffer(
|
||||
&buf_[buf_.size() - n], n);
|
||||
}
|
||||
|
||||
template<class>
|
||||
void
|
||||
chunk_encode_text::
|
||||
setup(std::size_t n)
|
||||
{
|
||||
buf_[buf_.size() - 2] = '\r';
|
||||
buf_[buf_.size() - 1] = '\n';
|
||||
auto it = to_hex(buf_.end() - 2, n);
|
||||
cb_ = boost::asio::const_buffer{&*it,
|
||||
static_cast<std::size_t>(
|
||||
std::distance(it, buf_.end()))};
|
||||
}
|
||||
|
||||
/** Returns a chunk-encoded ConstBufferSequence.
|
||||
|
||||
This returns a buffer sequence representing the
|
||||
first chunk of a chunked transfer coded body.
|
||||
|
||||
@param fin `true` if this is the last chunk.
|
||||
|
||||
@param buffers The input buffer sequence.
|
||||
|
||||
@return A chunk-encoded ConstBufferSequence representing the input.
|
||||
@ -103,16 +126,20 @@ implementation_defined
|
||||
beast::detail::buffer_cat_helper<boost::asio::const_buffer,
|
||||
chunk_encode_text, ConstBufferSequence, boost::asio::const_buffers_1>
|
||||
#endif
|
||||
chunk_encode(ConstBufferSequence const& buffers)
|
||||
chunk_encode(bool fin, ConstBufferSequence const& buffers)
|
||||
{
|
||||
using boost::asio::buffer_size;
|
||||
return buffer_cat(
|
||||
chunk_encode_text{buffer_size(buffers)},
|
||||
buffers,
|
||||
boost::asio::const_buffers_1{"\r\n", 2});
|
||||
fin ? boost::asio::const_buffers_1{"\r\n0\r\n\r\n", 7}
|
||||
: boost::asio::const_buffers_1{"\r\n", 2});
|
||||
}
|
||||
|
||||
/// Returns a chunked encoding final chunk.
|
||||
/** Returns a chunked encoding final chunk.
|
||||
|
||||
@see <a href=https://tools.ietf.org/html/rfc7230#section-4.1.3>rfc7230 section 4.1.3</a>
|
||||
*/
|
||||
inline
|
||||
#if GENERATING_DOCS
|
||||
implementation_defined
|
||||
@ -121,11 +148,9 @@ boost::asio::const_buffers_1
|
||||
#endif
|
||||
chunk_encode_final()
|
||||
{
|
||||
return boost::asio::const_buffers_1(
|
||||
"0\r\n\r\n", 5);
|
||||
return boost::asio::const_buffers_1{"0\r\n\r\n", 5};
|
||||
}
|
||||
|
||||
} // detail
|
||||
} // http
|
||||
} // beast
|
||||
|
@ -10,7 +10,7 @@
|
||||
|
||||
#include <beast/http/concepts.hpp>
|
||||
#include <beast/http/resume_context.hpp>
|
||||
#include <beast/http/detail/chunk_encode.hpp>
|
||||
#include <beast/http/chunk_encode.hpp>
|
||||
#include <beast/core/buffer_cat.hpp>
|
||||
#include <beast/core/bind_handler.hpp>
|
||||
#include <beast/core/buffer_concepts.hpp>
|
||||
@ -191,7 +191,7 @@ class write_op
|
||||
if(d.wp.chunked)
|
||||
boost::asio::async_write(d.s,
|
||||
buffer_cat(d.wp.sb.data(),
|
||||
detail::chunk_encode(buffers)),
|
||||
chunk_encode(false, buffers)),
|
||||
std::move(self_));
|
||||
else
|
||||
boost::asio::async_write(d.s,
|
||||
@ -218,7 +218,7 @@ class write_op
|
||||
// write body
|
||||
if(d.wp.chunked)
|
||||
boost::asio::async_write(d.s,
|
||||
detail::chunk_encode(buffers),
|
||||
chunk_encode(false, buffers),
|
||||
std::move(self_));
|
||||
else
|
||||
boost::asio::async_write(d.s,
|
||||
@ -243,7 +243,7 @@ public:
|
||||
d.resume = {
|
||||
[sp]() mutable
|
||||
{
|
||||
write_op self(std::move(sp));
|
||||
write_op self{std::move(sp)};
|
||||
self.d_->cont = false;
|
||||
auto& ios = self.d_->s.get_io_service();
|
||||
ios.dispatch(bind_handler(std::move(self),
|
||||
@ -383,7 +383,7 @@ operator()(error_code ec, std::size_t, bool again)
|
||||
// write final chunk
|
||||
d.state = 5;
|
||||
boost::asio::async_write(d.s,
|
||||
detail::chunk_encode_final(), std::move(*this));
|
||||
chunk_encode_final(), std::move(*this));
|
||||
return;
|
||||
|
||||
case 5:
|
||||
@ -425,7 +425,7 @@ public:
|
||||
// write headers and body
|
||||
if(chunked_)
|
||||
boost::asio::write(stream_, buffer_cat(
|
||||
sb_.data(), detail::chunk_encode(buffers)), ec_);
|
||||
sb_.data(), chunk_encode(false, buffers)), ec_);
|
||||
else
|
||||
boost::asio::write(stream_, buffer_cat(
|
||||
sb_.data(), buffers), ec_);
|
||||
@ -454,7 +454,7 @@ public:
|
||||
// write body
|
||||
if(chunked_)
|
||||
boost::asio::write(stream_,
|
||||
detail::chunk_encode(buffers), ec_);
|
||||
chunk_encode(false, buffers), ec_);
|
||||
else
|
||||
boost::asio::write(stream_, buffers, ec_);
|
||||
}
|
||||
@ -563,7 +563,7 @@ write(SyncWriteStream& stream,
|
||||
// final body chunk with the final chunk delimiter.
|
||||
//
|
||||
// write final chunk
|
||||
boost::asio::write(stream, detail::chunk_encode_final(), ec);
|
||||
boost::asio::write(stream, chunk_encode_final(), ec);
|
||||
if(ec)
|
||||
return;
|
||||
}
|
||||
|
@ -5,13 +5,14 @@
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
|
||||
#include <beast/http/detail/chunk_encode.hpp>
|
||||
// Test that header file is self-contained.
|
||||
#include <beast/http/chunk_encode.hpp>
|
||||
|
||||
#include <beast/core/to_string.hpp>
|
||||
#include <beast/unit_test/suite.hpp>
|
||||
|
||||
namespace beast {
|
||||
namespace http {
|
||||
namespace detail {
|
||||
|
||||
class chunk_encode_test : public beast::unit_test::suite
|
||||
{
|
||||
@ -35,8 +36,8 @@ public:
|
||||
{
|
||||
using boost::asio::buffer;
|
||||
if(! fc.s.empty())
|
||||
s.append(to_string(
|
||||
chunk_encode(buffer(fc.s.data(), fc.s.size()))));
|
||||
s.append(to_string(chunk_encode(
|
||||
false, buffer(fc.s.data(), fc.s.size()))));
|
||||
s.append(to_string(chunk_encode_final()));
|
||||
}
|
||||
|
||||
@ -45,8 +46,8 @@ public:
|
||||
encode1(std::string& s, std::string const& piece)
|
||||
{
|
||||
using boost::asio::buffer;
|
||||
s.append(to_string(
|
||||
chunk_encode(buffer(piece.data(), piece.size()))));
|
||||
s.append(to_string(chunk_encode(
|
||||
false, buffer(piece.data(), piece.size()))));
|
||||
}
|
||||
|
||||
static
|
||||
@ -122,11 +123,14 @@ public:
|
||||
"****\r\n"
|
||||
"0\r\n\r\n",
|
||||
"****", final_chunk{});
|
||||
|
||||
BEAST_EXPECT(to_string(chunk_encode(true,
|
||||
boost::asio::buffer("****", 4))) ==
|
||||
"4\r\n****\r\n0\r\n\r\n");
|
||||
}
|
||||
};
|
||||
|
||||
BEAST_DEFINE_TESTSUITE(chunk_encode,http,beast);
|
||||
|
||||
} // detail
|
||||
} // http
|
||||
} // beast
|
||||
|
Reference in New Issue
Block a user