boost/beast/http/detail/chunk_encode.hpp
//
// Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// 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/boostorg/beast
//
#ifndef BOOST_BEAST_HTTP_DETAIL_CHUNK_ENCODE_HPP
#define BOOST_BEAST_HTTP_DETAIL_CHUNK_ENCODE_HPP
#include <boost/beast/http/type_traits.hpp>
#include <boost/asio/buffer.hpp>
#include <algorithm>
#include <array>
#include <cstddef>
#include <memory>
namespace boost {
namespace beast {
namespace http {
namespace detail {
struct chunk_extensions
{
virtual ~chunk_extensions() = default;
virtual net::const_buffer str() = 0;
};
template<class ChunkExtensions>
struct chunk_extensions_impl : chunk_extensions
{
ChunkExtensions ext_;
chunk_extensions_impl(ChunkExtensions&& ext) noexcept
: ext_(std::move(ext))
{
}
chunk_extensions_impl(ChunkExtensions const& ext)
: ext_(ext)
{
}
net::const_buffer
str() override
{
auto const s = ext_.str();
return {s.data(), s.size()};
}
};
template<class T, class = void>
struct is_chunk_extensions : std::false_type {};
template<class T>
struct is_chunk_extensions<T, beast::detail::void_t<decltype(
std::declval<string_view&>() = std::declval<T&>().str()
)>> : std::true_type
{
};
//------------------------------------------------------------------------------
/** A buffer sequence containing a chunk-encoding header
*/
class chunk_size
{
template<class OutIter>
static
OutIter
to_hex(OutIter last, std::size_t n)
{
if(n == 0)
{
*--last = '0';
return last;
}
while(n)
{
*--last = "0123456789abcdef"[n&0xf];
n>>=4;
}
return last;
}
struct sequence
{
net::const_buffer b;
char data[1 + 2 * sizeof(std::size_t)];
explicit
sequence(std::size_t n)
{
char* it0 = data + sizeof(data);
auto it = to_hex(it0, n);
b = {it,
static_cast<std::size_t>(it0 - it)};
}
};
std::shared_ptr<sequence> sp_;
public:
using value_type = net::const_buffer;
using const_iterator = value_type const*;
chunk_size(chunk_size const& other) = default;
/** Construct a chunk header
@param n The number of octets in this chunk.
*/
chunk_size(std::size_t n)
: sp_(std::make_shared<sequence>(n))
{
}
const_iterator
begin() const
{
return &sp_->b;
}
const_iterator
end() const
{
return begin() + 1;
}
};
//------------------------------------------------------------------------------
/// Returns a buffer sequence holding a CRLF for chunk encoding
inline
net::const_buffer const&
chunk_crlf()
{
static net::const_buffer const cb{"\r\n", 2};
return cb;
}
/// Returns a buffer sequence holding a final chunk header
inline
net::const_buffer const&
chunk_last()
{
static net::const_buffer const cb{"0\r\n", 3};
return cb;
}
//------------------------------------------------------------------------------
#if 0
template<class = void>
struct chunk_crlf_iter_type
{
class value_type
{
char const s[2] = {'\r', '\n'};
public:
value_type() = default;
operator
net::const_buffer() const
{
return {s, sizeof(s)};
}
};
static value_type value;
};
template<class T>
typename chunk_crlf_iter_type<T>::value_type
chunk_crlf_iter_type<T>::value;
using chunk_crlf_iter = chunk_crlf_iter_type<void>;
#endif
//------------------------------------------------------------------------------
struct chunk_size0
{
using value_type = net::const_buffer;
using const_iterator = value_type const*;
const_iterator
begin() const
{
return &chunk_last();
}
const_iterator
end() const
{
return begin() + 1;
}
};
//------------------------------------------------------------------------------
template<class T,
bool = is_fields<T>::value>
struct buffers_or_fields
{
using type = typename
T::writer::const_buffers_type;
};
template<class T>
struct buffers_or_fields<T, false>
{
using type = T;
};
} // detail
} // http
} // beast
} // boost
#endif