diff --git a/CHANGELOG.md b/CHANGELOG.md
index d6798571..e4795b56 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,8 @@
HTTP
+* Make chunk_encode public
+
WebSocket
* Optimize utf8 validation
diff --git a/doc/quickref.xml b/doc/quickref.xml
index 8811e848..839000cd 100644
--- a/doc/quickref.xml
+++ b/doc/quickref.xml
@@ -59,6 +59,8 @@
async_parse
async_read
async_write
+ chunk_encode
+ chunk_encode_final
is_keep_alive
is_upgrade
parse
diff --git a/include/beast/http.hpp b/include/beast/http.hpp
index 516dc69b..02cb4b0d 100644
--- a/include/beast/http.hpp
+++ b/include/beast/http.hpp
@@ -11,6 +11,7 @@
#include
#include
#include
+#include
#include
#include
#include
diff --git a/include/beast/http/detail/chunk_encode.hpp b/include/beast/http/chunk_encode.hpp
similarity index 67%
rename from include/beast/http/detail/chunk_encode.hpp
rename to include/beast/http/chunk_encode.hpp
index 3c03dca1..51749316 100644
--- a/include/beast/http/detail/chunk_encode.hpp
+++ b/include/beast/http/chunk_encode.hpp
@@ -11,7 +11,6 @@
#include
#include
#include
-#include
#include
#include
#include
@@ -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 buf_;
+ template
+ void
+ copy(chunk_encode_text const& other);
+
+ template
+ void
+ setup(std::size_t n);
+
template
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::distance(it, buf_.end()))};
+ setup(n);
}
const_iterator
@@ -84,12 +81,38 @@ public:
return begin() + 1;
}
};
+template
+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
+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::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
#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 rfc7230 section 4.1.3
+*/
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
diff --git a/include/beast/http/impl/write.ipp b/include/beast/http/impl/write.ipp
index de443d7f..11e7bc4b 100644
--- a/include/beast/http/impl/write.ipp
+++ b/include/beast/http/impl/write.ipp
@@ -10,7 +10,7 @@
#include
#include
-#include
+#include
#include
#include
#include
@@ -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;
}
diff --git a/test/http/chunk_encode.cpp b/test/http/chunk_encode.cpp
index f44e3eca..cff31cbd 100644
--- a/test/http/chunk_encode.cpp
+++ b/test/http/chunk_encode.cpp
@@ -5,13 +5,14 @@
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
-#include
+// Test that header file is self-contained.
+#include
+
#include
#include
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