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