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:
Vinnie Falco
2016-11-07 16:57:41 -05:00
parent 50bc9a58cd
commit f98ec17121
6 changed files with 68 additions and 34 deletions

View File

@ -2,6 +2,8 @@
HTTP
* Make chunk_encode public
WebSocket
* Optimize utf8 validation

View File

@ -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>

View File

@ -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>

View File

@ -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

View File

@ -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;
}

View File

@ -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