Merge subtree Beast 1.0.0-b6:

Merge commit '999e2fa0318b5982736d3ea01a418770ea802671'
This commit is contained in:
Vinnie Falco
2016-06-03 17:03:35 -04:00
84 changed files with 4584 additions and 2805 deletions

View File

@@ -24,8 +24,8 @@
#include <beast/core/static_string.hpp>
#include <beast/core/stream_concepts.hpp>
#include <beast/core/streambuf.hpp>
#include <beast/core/streambuf_readstream.hpp>
#include <beast/core/dynabuf_readstream.hpp>
#include <beast/core/to_string.hpp>
#include <beast/core/write_streambuf.hpp>
#include <beast/core/write_dynabuf.hpp>
#endif

View File

@@ -18,14 +18,14 @@
namespace beast {
/** A @b `Streambuf` that uses multiple buffers internally.
/** A @b `DynamicBuffer` that uses multiple buffers internally.
The implementation uses a sequence of one or more character arrays
of varying sizes. Additional character array objects are appended to
the sequence to accommodate changes in the size of the character
sequence.
@note Meets the requirements of @b Streambuf.
@note Meets the requirements of @b `DynamicBuffer`.
@tparam Allocator The allocator to use for managing memory.
*/
@@ -202,26 +202,37 @@ public:
basic_streambuf(std::size_t alloc_size = 1024,
Allocator const& alloc = allocator_type{});
/// Get the associated allocator
/// Returns a copy of the associated allocator.
allocator_type
get_allocator() const
{
return this->member();
}
/// Get the maximum size of the basic_streambuf.
/// Returns the size of the input sequence.
size_type
size() const
{
return in_size_;
}
/// Returns the permitted maximum sum of the sizes of the input and output sequence.
size_type
max_size() const
{
return std::numeric_limits<std::size_t>::max();
}
/// Get the size of the input sequence.
size_type
size() const
{
return in_size_;
}
/// Returns the maximum sum of the sizes of the input sequence and output sequence the buffer can hold without requiring reallocation.
std::size_t
capacity() const;
/** Get a list of buffers that represents the input sequence.
@note These buffers remain valid across subsequent calls to `prepare`.
*/
const_buffers_type
data() const;
/** Get a list of buffers that represents the output sequence, with the given size.
@@ -239,22 +250,11 @@ public:
void
commit(size_type n);
/** Get a list of buffers that represents the input sequence.
@note These buffers remain valid across subsequent calls to `prepare`.
*/
const_buffers_type
data() const;
/// Remove bytes from the input sequence.
void
consume(size_type n);
/// Clear everything.
void
clear();
// Helper for read_until
// Helper for boost::asio::read_until
template<class OtherAllocator>
friend
std::size_t
@@ -262,6 +262,9 @@ public:
OtherAllocator> const& streambuf, std::size_t max_size);
private:
void
clear();
void
move_assign(basic_streambuf& other, std::false_type);
@@ -277,20 +280,17 @@ private:
void
delete_list();
std::size_t
prepare_size() const;
void
debug_check() const;
};
/** Format output to a stream buffer.
/** Format output to a @ref basic_streambuf.
@param streambuf The streambuf to write to.
@param streambuf The @ref basic_streambuf to write to.
@param t The object to write.
@return The stream buffer.
@return A reference to the @ref basic_streambuf.
*/
template<class Allocator, class T>
basic_streambuf<Allocator>&

View File

@@ -35,6 +35,16 @@ struct is_ConstBufferSequence :
{
};
/// Determine if `T` meets the requirements of @b `DynamicBuffer`.
template<class T>
#if GENERATING_DOCS
struct is_DynamicBuffer : std::integral_constant<bool, ...>
#else
struct is_DynamicBuffer : detail::is_DynamicBuffer<T>::type
#endif
{
};
/// Determine if `T` meets the requirements of @b `MutableBufferSequence`.
template<class T>
#if GENERATING_DOCS
@@ -46,16 +56,6 @@ struct is_MutableBufferSequence :
{
};
/// Determine if `T` meets the requirements of @b `Streambuf`.
template<class T>
#if GENERATING_DOCS
struct is_Streambuf : std::integral_constant<bool, ...>
#else
struct is_Streambuf : detail::is_Streambuf<T>::type
#endif
{
};
} // beast
#endif

View File

@@ -86,7 +86,7 @@ public:
};
template<class T>
class is_Streambuf
class is_DynamicBuffer
{
template<class U, class R = std::integral_constant<
bool, is_BufferSequence<decltype(

View File

@@ -8,76 +8,96 @@
#ifndef BEAST_DETAIL_CI_CHAR_TRAITS_HPP
#define BEAST_DETAIL_CI_CHAR_TRAITS_HPP
#include <boost/range/algorithm/equal.hpp>
#include <boost/utility/string_ref.hpp>
#include <algorithm>
#include <type_traits>
#include <cctype>
#include <iterator>
#include <string>
#include <utility>
#include <array>
#include <cstdint>
namespace beast {
namespace detail {
/** Case-insensitive function object for performing less than comparisons. */
inline
char
tolower(char c)
{
static std::array<std::uint8_t, 256> constexpr tab = {{
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
64, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 91, 92, 93, 94, 95,
96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127,
128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143,
144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159,
160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175,
176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191,
192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207,
208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223,
224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239,
240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255
}};
return static_cast<char>(tab[static_cast<std::uint8_t>(c)]);
}
template<std::size_t N>
inline
boost::string_ref
string_helper(const char (&s)[N])
{
return boost::string_ref{s, N-1};
}
template<class T>
inline
T const&
string_helper(T const& t)
{
return t;
}
// Case-insensitive less
struct ci_less
{
static bool const is_transparent = true;
template<class S1, class S2>
bool
operator()(boost::string_ref const& lhs,
boost::string_ref const& rhs) const noexcept
operator()(S1 const& lhs, S2 const& rhs) const noexcept
{
using std::begin;
using std::end;
auto const s1 = string_helper(lhs);
auto const s2 = string_helper(rhs);
return std::lexicographical_compare(
begin(lhs), end(lhs), begin(rhs), end(rhs),
begin(s1), end(s1), begin(s2), end(s2),
[](char lhs, char rhs)
{
return std::tolower(lhs) < std::tolower(rhs);
return tolower(lhs) < tolower(rhs);
}
);
}
};
inline
// Case-insensitive equal
struct ci_equal_pred
{
bool
operator()(char c1, char c2) const noexcept
{
return tolower(c1) == tolower(c2);
}
};
// Case-insensitive equal
template<class S1, class S2>
bool
ci_equal(std::pair<const char*, std::size_t> lhs,
std::pair<const char*, std::size_t> rhs)
ci_equal(S1 const& lhs, S2 const& rhs)
{
if(lhs.second != rhs.second)
return false;
return std::equal (lhs.first, lhs.first + lhs.second,
rhs.first,
[] (char lhs, char rhs)
{
return std::tolower(lhs) == std::tolower(rhs);
}
);
}
template <size_t N>
inline
std::pair<const char*, std::size_t>
view(const char (&s)[N])
{
return {s, N-1};
}
inline
std::pair<const char*, std::size_t>
view(std::string const& s)
{
return {s.data(), s.size()};
}
/** Returns `true` if strings are case-insensitive equal. */
template <class String1, class String2>
inline
bool
ci_equal(String1 const& lhs, String2 const& rhs)
{
return ci_equal(view(lhs), view(rhs));
return boost::range::equal(
string_helper(lhs), string_helper(rhs),
ci_equal_pred{});
}
} // detail

View File

@@ -5,8 +5,8 @@
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef BEAST_DETAIL_WRITE_STREAMBUF_HPP
#define BEAST_DETAIL_WRITE_STREAMBUF_HPP
#ifndef BEAST_DETAIL_WRITE_DYNABUF_HPP
#define BEAST_DETAIL_WRITE_DYNABUF_HPP
#include <beast/core/buffer_concepts.hpp>
#include <boost/asio/buffer.hpp>
@@ -42,73 +42,73 @@ public:
! is_string_literal<T>::value;
};
template<class Streambuf>
template<class DynamicBuffer>
void
write_streambuf(Streambuf& streambuf,
write_dynabuf(DynamicBuffer& dynabuf,
boost::asio::const_buffer const& buffer)
{
using boost::asio::buffer_copy;
using boost::asio::buffer_size;
streambuf.commit(buffer_copy(
streambuf.prepare(buffer_size(buffer)),
dynabuf.commit(buffer_copy(
dynabuf.prepare(buffer_size(buffer)),
buffer));
}
template<class Streambuf>
template<class DynamicBuffer>
void
write_streambuf(Streambuf& streambuf,
write_dynabuf(DynamicBuffer& dynabuf,
boost::asio::mutable_buffer const& buffer)
{
using boost::asio::buffer_copy;
using boost::asio::buffer_size;
streambuf.commit(buffer_copy(
streambuf.prepare(buffer_size(buffer)),
dynabuf.commit(buffer_copy(
dynabuf.prepare(buffer_size(buffer)),
buffer));
}
template<class Streambuf, class T>
template<class DynamicBuffer, class T>
typename std::enable_if<
is_BufferConvertible<T>::value &&
! std::is_convertible<T, boost::asio::const_buffer>::value &&
! std::is_convertible<T, boost::asio::mutable_buffer>::value
>::type
write_streambuf(Streambuf& streambuf, T const& t)
write_dynabuf(DynamicBuffer& dynabuf, T const& t)
{
using boost::asio::buffer_copy;
using boost::asio::buffer_size;
auto const buffers = boost::asio::buffer(t);
streambuf.commit(buffer_copy(
streambuf.prepare(buffer_size(buffers)),
dynabuf.commit(buffer_copy(
dynabuf.prepare(buffer_size(buffers)),
buffers));
}
template<class Streambuf, class Buffers>
template<class DynamicBuffer, class Buffers>
typename std::enable_if<
is_ConstBufferSequence<Buffers>::value &&
! is_BufferConvertible<Buffers>::value &&
! std::is_convertible<Buffers, boost::asio::const_buffer>::value &&
! std::is_convertible<Buffers, boost::asio::mutable_buffer>::value
>::type
write_streambuf(Streambuf& streambuf, Buffers const& buffers)
write_dynabuf(DynamicBuffer& dynabuf, Buffers const& buffers)
{
using boost::asio::buffer_copy;
using boost::asio::buffer_size;
streambuf.commit(buffer_copy(
streambuf.prepare(buffer_size(buffers)),
dynabuf.commit(buffer_copy(
dynabuf.prepare(buffer_size(buffers)),
buffers));
}
template<class Streambuf, std::size_t N>
template<class DynamicBuffer, std::size_t N>
void
write_streambuf(Streambuf& streambuf, const char (&s)[N])
write_dynabuf(DynamicBuffer& dynabuf, const char (&s)[N])
{
using boost::asio::buffer_copy;
streambuf.commit(buffer_copy(
streambuf.prepare(N - 1),
dynabuf.commit(buffer_copy(
dynabuf.prepare(N - 1),
boost::asio::buffer(s, N - 1)));
}
template<class Streambuf, class T>
template<class DynamicBuffer, class T>
typename std::enable_if<
! is_string_literal<T>::value &&
! is_ConstBufferSequence<T>::value &&
@@ -116,22 +116,22 @@ typename std::enable_if<
! std::is_convertible<T, boost::asio::const_buffer>::value &&
! std::is_convertible<T, boost::asio::mutable_buffer>::value
>::type
write_streambuf(Streambuf& streambuf, T const& t)
write_dynabuf(DynamicBuffer& dynabuf, T const& t)
{
using boost::asio::buffer;
using boost::asio::buffer_copy;
auto const s = boost::lexical_cast<std::string>(t);
streambuf.commit(buffer_copy(
streambuf.prepare(s.size()), buffer(s)));
dynabuf.commit(buffer_copy(
dynabuf.prepare(s.size()), buffer(s)));
}
template<class Streambuf, class T0, class T1, class... TN>
template<class DynamicBuffer, class T0, class T1, class... TN>
void
write_streambuf(Streambuf& streambuf,
write_dynabuf(DynamicBuffer& dynabuf,
T0 const& t0, T1 const& t1, TN const&... tn)
{
write_streambuf(streambuf, t0);
write_streambuf(streambuf, t1, tn...);
write_dynabuf(dynabuf, t0);
write_dynabuf(dynabuf, t1, tn...);
}
} // detail

View File

@@ -5,8 +5,8 @@
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef BEAST_STREAMBUF_READSTREAM_HPP
#define BEAST_STREAMBUF_READSTREAM_HPP
#ifndef BEAST_DYNABUF_READSTREAM_HPP
#define BEAST_DYNABUF_READSTREAM_HPP
#include <beast/core/async_completion.hpp>
#include <beast/core/buffer_concepts.hpp>
@@ -22,11 +22,11 @@
namespace beast {
/** A @b `Stream` with attached @b `Streambuf` to buffer reads.
/** A @b `Stream` with attached @b `DynamicBuffer` to buffer reads.
This wraps a @b `Stream` implementation so that calls to write are
passed through to the underlying stream, while calls to read will
first consume the input sequence stored in a @b `Streambuf` which
first consume the input sequence stored in a @b `DynamicBuffer` which
is part of the object.
The use-case for this class is different than that of the
@@ -50,9 +50,9 @@ namespace beast {
// Process the next HTTP headers on the stream,
// leaving excess bytes behind for the next call.
//
template<class Streambuf>
template<class DynamicBuffer>
void process_http_message(
streambuf_readstream<Streambuf>& stream)
dynabuf_readstream<DynamicBuffer>& stream)
{
// Read up to and including the end of the HTTP
// headers, leaving the sequence in the stream's
@@ -85,26 +85,24 @@ namespace beast {
@tparam Stream The type of stream to wrap.
@tparam Streambuf The type of stream buffer to use.
@tparam DynamicBuffer The type of stream buffer to use.
*/
template<class Stream, class Streambuf>
class streambuf_readstream
template<class Stream, class DynamicBuffer>
class dynabuf_readstream
{
static_assert(is_Streambuf<Streambuf>::value,
"Streambuf requirements not met");
using error_code = boost::system::error_code;
static_assert(is_DynamicBuffer<DynamicBuffer>::value,
"DynamicBuffer requirements not met");
template<class Buffers, class Handler>
class read_some_op;
Streambuf sb_;
DynamicBuffer sb_;
std::size_t capacity_ = 0;
Stream next_layer_;
public:
/// The type of the internal buffer
using streambuf_type = Streambuf;
using dynabuf_type = DynamicBuffer;
/// The type of the next layer.
using next_layer_type =
@@ -124,14 +122,14 @@ public:
@note The behavior of move assignment on or from streams
with active or pending operations is undefined.
*/
streambuf_readstream(streambuf_readstream&&) = default;
dynabuf_readstream(dynabuf_readstream&&) = default;
/** Move assignment.
@note The behavior of move assignment on or from streams
with active or pending operations is undefined.
*/
streambuf_readstream& operator=(streambuf_readstream&&) = default;
dynabuf_readstream& operator=(dynabuf_readstream&&) = default;
/** Construct the wrapping stream.
@@ -139,7 +137,7 @@ public:
*/
template<class... Args>
explicit
streambuf_readstream(Args&&... args);
dynabuf_readstream(Args&&... args);
/// Get a reference to the next layer.
next_layer_type&
@@ -176,7 +174,7 @@ public:
by causing the internal buffer size to increase beyond
the caller defined maximum.
*/
Streambuf&
DynamicBuffer&
buffer()
{
return sb_;
@@ -189,7 +187,7 @@ public:
by causing the internal buffer size to increase beyond
the caller defined maximum.
*/
Streambuf const&
DynamicBuffer const&
buffer() const
{
return sb_;
@@ -277,6 +275,6 @@ public:
} // beast
#include <beast/core/impl/streambuf_readstream.ipp>
#include <beast/core/impl/dynabuf_readstream.ipp>
#endif

View File

@@ -8,7 +8,7 @@
#ifndef BEAST_IMPL_BASIC_STREAMBUF_IPP
#define BEAST_IMPL_BASIC_STREAMBUF_IPP
#include <beast/core/detail/write_streambuf.hpp>
#include <beast/core/detail/write_dynabuf.hpp>
#include <algorithm>
#include <cassert>
#include <exception>
@@ -527,6 +527,28 @@ basic_streambuf<Allocator>::basic_streambuf(
"basic_streambuf: invalid alloc_size");
}
template<class Allocator>
std::size_t
basic_streambuf<Allocator>::capacity() const
{
auto pos = out_;
if(pos == list_.end())
return 0;
auto n = pos->size() - out_pos_;
while(++pos != list_.end())
n += pos->size();
return in_size_ + n;
}
template<class Allocator>
auto
basic_streambuf<Allocator>::
data() const ->
const_buffers_type
{
return const_buffers_type(*this);
}
template<class Allocator>
auto
basic_streambuf<Allocator>::prepare(size_type n) ->
@@ -646,14 +668,6 @@ basic_streambuf<Allocator>::commit(size_type n)
debug_check();
}
template<class Allocator>
auto
basic_streambuf<Allocator>::data() const ->
const_buffers_type
{
return const_buffers_type(*this);
}
template<class Allocator>
void
basic_streambuf<Allocator>::consume(size_type n)
@@ -717,7 +731,8 @@ basic_streambuf<Allocator>::consume(size_type n)
template<class Allocator>
void
basic_streambuf<Allocator>::clear()
basic_streambuf<Allocator>::
clear()
{
delete_list();
list_.clear();
@@ -795,21 +810,6 @@ basic_streambuf<Allocator>::delete_list()
}
}
// Returns the number of bytes which can be
// prepared without causing a memory allocation.
template<class Allocator>
std::size_t
basic_streambuf<Allocator>::prepare_size() const
{
auto pos = out_;
if(pos == list_.end())
return 0;
auto n = pos->size() - out_pos_;
while(++pos != list_.end())
n += pos->size();
return n;
}
template<class Allocator>
void
basic_streambuf<Allocator>::debug_check() const
@@ -855,7 +855,7 @@ std::size_t
read_size_helper(basic_streambuf<
Allocator> const& streambuf, std::size_t max_size)
{
auto const avail = streambuf.prepare_size();
auto const avail = streambuf.capacity() - streambuf.size();
if(avail == 0)
return std::min(max_size,
std::max<std::size_t>(512, streambuf.alloc_size_));
@@ -866,7 +866,7 @@ template<class Alloc, class T>
basic_streambuf<Alloc>&
operator<<(basic_streambuf<Alloc>& streambuf, T const& t)
{
detail::write_streambuf(streambuf, t);
detail::write_dynabuf(streambuf, t);
return streambuf;
}

View File

@@ -5,8 +5,8 @@
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef BEAST_IMPL_STREAMBUF_READSTREAM_IPP
#define BEAST_IMPL_STREAMBUF_READSTREAM_IPP
#ifndef BEAST_IMPL_DYNABUF_READSTREAM_HPP
#define BEAST_IMPL_DYNABUF_READSTREAM_HPP
#include <beast/core/bind_handler.hpp>
#include <beast/core/handler_concepts.hpp>
@@ -16,24 +16,24 @@
namespace beast {
template<class Stream, class Streambuf>
template<class Stream, class DynamicBuffer>
template<class MutableBufferSequence, class Handler>
class streambuf_readstream<
Stream, Streambuf>::read_some_op
class dynabuf_readstream<
Stream, DynamicBuffer>::read_some_op
{
using alloc_type =
handler_alloc<char, Handler>;
struct data
{
streambuf_readstream& srs;
dynabuf_readstream& srs;
MutableBufferSequence bs;
Handler h;
int state = 0;
template<class DeducedHandler>
data(DeducedHandler&& h_,
streambuf_readstream& srs_,
dynabuf_readstream& srs_,
MutableBufferSequence const& bs_)
: srs(srs_)
, bs(bs_)
@@ -50,7 +50,7 @@ public:
template<class DeducedHandler, class... Args>
read_some_op(DeducedHandler&& h,
streambuf_readstream& srs, Args&&... args)
dynabuf_readstream& srs, Args&&... args)
: d_(std::allocate_shared<data>(alloc_type{h},
std::forward<DeducedHandler>(h), srs,
std::forward<Args>(args)...))
@@ -94,10 +94,10 @@ public:
}
};
template<class Stream, class Streambuf>
template<class Stream, class DynamicBuffer>
template<class MutableBufferSequence, class Handler>
void
streambuf_readstream<Stream, Streambuf>::
dynabuf_readstream<Stream, DynamicBuffer>::
read_some_op<MutableBufferSequence, Handler>::operator()(
error_code const& ec, std::size_t bytes_transferred)
{
@@ -155,18 +155,18 @@ read_some_op<MutableBufferSequence, Handler>::operator()(
//------------------------------------------------------------------------------
template<class Stream, class Streambuf>
template<class Stream, class DynamicBuffer>
template<class... Args>
streambuf_readstream<Stream, Streambuf>::
streambuf_readstream(Args&&... args)
dynabuf_readstream<Stream, DynamicBuffer>::
dynabuf_readstream(Args&&... args)
: next_layer_(std::forward<Args>(args)...)
{
}
template<class Stream, class Streambuf>
template<class Stream, class DynamicBuffer>
template<class ConstBufferSequence, class WriteHandler>
auto
streambuf_readstream<Stream, Streambuf>::
dynabuf_readstream<Stream, DynamicBuffer>::
async_write_some(ConstBufferSequence const& buffers,
WriteHandler&& handler) ->
typename async_completion<
@@ -184,10 +184,10 @@ async_write_some(ConstBufferSequence const& buffers,
std::forward<WriteHandler>(handler));
}
template<class Stream, class Streambuf>
template<class Stream, class DynamicBuffer>
template<class MutableBufferSequence>
std::size_t
streambuf_readstream<Stream, Streambuf>::
dynabuf_readstream<Stream, DynamicBuffer>::
read_some(
MutableBufferSequence const& buffers)
{
@@ -203,10 +203,10 @@ read_some(
return n;
}
template<class Stream, class Streambuf>
template<class Stream, class DynamicBuffer>
template<class MutableBufferSequence>
std::size_t
streambuf_readstream<Stream, Streambuf>::
dynabuf_readstream<Stream, DynamicBuffer>::
read_some(MutableBufferSequence const& buffers,
error_code& ec)
{
@@ -232,10 +232,10 @@ read_some(MutableBufferSequence const& buffers,
return bytes_transferred;
}
template<class Stream, class Streambuf>
template<class Stream, class DynamicBuffer>
template<class MutableBufferSequence, class ReadHandler>
auto
streambuf_readstream<Stream, Streambuf>::
dynabuf_readstream<Stream, DynamicBuffer>::
async_read_some(
MutableBufferSequence const& buffers,
ReadHandler&& handler) ->

View File

@@ -15,7 +15,7 @@
namespace beast {
/** A @b `Streambuf` with a fixed size internal buffer.
/** A @b `DynamicBuffer` with a fixed size internal buffer.
Ownership of the underlying storage belongs to the derived class.

View File

@@ -506,8 +506,6 @@ compare(
} // detail
#if ! GENERATING_DOCS
template<std::size_t N, std::size_t M, class CharT, class Traits>
bool
operator==(
@@ -672,8 +670,6 @@ operator>=(
return detail::compare(lhs, s) >= 0;
}
#endif
} // beast
#endif

View File

@@ -25,15 +25,16 @@ namespace beast {
@return A string representing the contents of the input area.
@note This function participates in overload resolution only if
the streambuf parameter meets the requirements of @b `Streambuf`.
the buffers parameter meets the requirements of @b `ConstBufferSequence`.
*/
template<class ConstBufferSequence
#if ! GENERATING_DOCS
,class = std::enable_if<is_ConstBufferSequence<
ConstBufferSequence>::value>
#endif
>
template<class ConstBufferSequence>
#if GENERATING_DOCS
std::string
#else
typename std::enable_if<
is_ConstBufferSequence<ConstBufferSequence>::value,
std::string>::type
#endif
to_string(ConstBufferSequence const& buffers)
{
using boost::asio::buffer_cast;

View File

@@ -5,20 +5,20 @@
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef BEAST_WRITE_STREAMBUF_HPP
#define BEAST_WRITE_STREAMBUF_HPP
#ifndef BEAST_WRITE_DYNABUF_HPP
#define BEAST_WRITE_DYNABUF_HPP
#include <beast/core/buffer_concepts.hpp>
#include <beast/core/detail/write_streambuf.hpp>
#include <beast/core/detail/write_dynabuf.hpp>
#include <type_traits>
#include <utility>
namespace beast {
/** Write to a Streambuf.
/** Write to a @b `DynamicBuffer`.
This function appends the serialized representation of each provided
argument into the stream buffer. It is capable of converting the
argument into the dynamic buffer. It is capable of converting the
following types of arguments:
@li `boost::asio::const_buffer`
@@ -33,29 +33,29 @@ namespace beast {
For all types not listed above, the function will invoke
`boost::lexical_cast` on the argument in an attempt to convert to
a string, which is then appended to the stream buffer.
a string, which is then appended to the dynamic buffer.
When this function serializes numbers, it converts them to
their text representation as if by a call to `std::to_string`.
@param streambuf The stream buffer to write to.
@param dynabuf The dynamic buffer to write to.
@param args A list of one or more arguments to write.
@throws unspecified Any exceptions thrown by `boost::lexical_cast`.
@note This function participates in overload resolution only if
the `streambuf` parameter meets the requirements of @b `Streambuf`.
the `dynabuf` parameter meets the requirements of @b `DynamicBuffer`.
*/
template<class Streambuf, class... Args>
template<class DynamicBuffer, class... Args>
#if GENERATING_DOCS
void
#else
typename std::enable_if<is_Streambuf<Streambuf>::value>::type
typename std::enable_if<is_DynamicBuffer<DynamicBuffer>::value>::type
#endif
write(Streambuf& streambuf, Args const&... args)
write(DynamicBuffer& dynabuf, Args const&... args)
{
detail::write_streambuf(streambuf, args...);
detail::write_dynabuf(dynabuf, args...);
}
} // beast

View File

@@ -20,7 +20,7 @@
#include <beast/http/read.hpp>
#include <beast/http/reason.hpp>
#include <beast/http/resume_context.hpp>
#include <beast/http/rfc2616.hpp>
#include <beast/http/rfc7230.hpp>
#include <beast/http/streambuf_body.hpp>
#include <beast/http/string_body.hpp>
#include <beast/http/write.hpp>

View File

@@ -0,0 +1,95 @@
//
// Copyright (c) 2013-2016 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)
//
#ifndef BEAST_HTTP_BASIC_DYNABUF_BODY_HPP
#define BEAST_HTTP_BASIC_DYNABUF_BODY_HPP
#include <beast/http/body_type.hpp>
#include <boost/asio/buffer.hpp>
namespace beast {
namespace http {
/** A message body represented by a @b `DynamicBuffer`
Meets the requirements of @b `Body`.
*/
template<class DynamicBuffer>
struct basic_dynabuf_body
{
/// The type of the `message::body` member
using value_type = DynamicBuffer;
#if GENERATING_DOCS
private:
#endif
class reader
{
value_type& sb_;
public:
template<bool isRequest, class Headers>
explicit
reader(message<isRequest,
basic_dynabuf_body, Headers>& m) noexcept
: sb_(m.body)
{
}
void
write(void const* data,
std::size_t size, error_code&) noexcept
{
using boost::asio::buffer;
using boost::asio::buffer_copy;
sb_.commit(buffer_copy(
sb_.prepare(size), buffer(data, size)));
}
};
class writer
{
DynamicBuffer const& body_;
public:
writer(writer const&) = delete;
writer& operator=(writer const&) = delete;
template<bool isRequest, class Headers>
explicit
writer(message<
isRequest, basic_dynabuf_body, Headers> const& m)
: body_(m.body)
{
}
void
init(error_code& ec)
{
}
std::uint64_t
content_length() const
{
return body_.size();
}
template<class Write>
boost::tribool
operator()(resume_context&&, error_code&, Write&& write)
{
write(body_.data());
return true;
}
};
};
} // http
} // beast
#endif

View File

@@ -246,8 +246,7 @@ public:
Field names are stored as-is, but comparison are case-insensitive.
The container preserves the order of insertion of fields with
different names. For fields with the same name, the implementation
concatenates values inserted with duplicate names as per the
rules in rfc2616 section 4.2.
concatenates values inserted with duplicate names as per rfc7230.
@note Meets the requirements of @b `FieldSequence`.
*/
@@ -393,18 +392,16 @@ public:
*/
// VFALCO TODO Consider allowing rvalue references for std::move?
void
insert(boost::string_ref const& name,
boost::string_ref const& value);
insert(boost::string_ref const& name, boost::string_ref value);
/** Insert a field value.
If a field value already exists the new value will be
extended as per RFC2616 Section 4.2.
*/
template<class T,
class = typename std::enable_if<
! std::is_constructible<boost::string_ref, T>::value>::type>
void
template<class T>
typename std::enable_if<
! std::is_constructible<boost::string_ref, T>::value>::type
insert(boost::string_ref name, T const& value)
{
insert(name,
@@ -414,21 +411,19 @@ public:
/** Replace a field value.
The current field value, if any, is removed. Then the
specified value is inserted as if by insert(field, value).
specified value is inserted as if by `insert(field, value)`.
*/
void
replace(boost::string_ref const& name,
boost::string_ref const& value);
replace(boost::string_ref const& name, boost::string_ref value);
/** Replace a field value.
The current field value, if any, is removed. Then the
specified value is inserted as if by insert(field, value).
specified value is inserted as if by `insert(field, value)`.
*/
template<class T,
class = typename std::enable_if<
! std::is_constructible<boost::string_ref, T>::value>::type>
void
template<class T>
typename std::enable_if<
! std::is_constructible<boost::string_ref, T>::value>::type
replace(boost::string_ref const& name, T const& value)
{
replace(name,

View File

@@ -25,17 +25,65 @@ namespace http {
namespace parse_flag {
enum values
{
chunked = 1 << 0,
connection_keep_alive = 1 << 1,
connection_close = 1 << 2,
connection_upgrade = 1 << 3,
trailing = 1 << 4,
upgrade = 1 << 5,
skipbody = 1 << 6,
contentlength = 1 << 7
chunked = 1,
connection_keep_alive = 2,
connection_close = 4,
connection_upgrade = 8,
trailing = 16,
upgrade = 32,
skipbody = 64,
contentlength = 128
};
} // parse_flag
/** Headers maximum size option.
Sets the maximum number of cumulative bytes allowed
including all header octets. A value of zero indicates
no limit on the number of header octets
The default headers maximum size is 16KB (16,384 bytes).
@note Objects of this type are passed to @ref set_option.
*/
struct headers_max_size
{
std::size_t value;
explicit
headers_max_size(std::size_t v)
: value(v)
{
}
};
/** Body maximum size option.
Sets the maximum number of cumulative bytes allowed including
all body octets. Octets in chunk-encoded bodies are counted
after decoding. A value of zero indicates no limit on
the number of body octets.
The default body maximum size for requests is 4MB (four
megabytes or 4,194,304 bytes) and unlimited for responses.
@note Objects of this type are passed to @ref set_option.
*/
struct body_max_size
{
std::size_t value;
explicit
body_max_size(std::size_t v)
: value(v)
{
}
};
/// The value returned when no content length is known or applicable.
static std::uint64_t constexpr no_content_length =
std::numeric_limits<std::uint64_t>::max();
/** A parser for decoding HTTP/1 wire format messages.
This parser is designed to efficiently parse messages in the
@@ -85,7 +133,7 @@ enum values
Called for each piece of the current header value.
@li `int on_headers(error_code&)`
@li `int on_headers(std::uint64_t content_length, error_code&)`
Called when all the headers have been parsed successfully.
@@ -126,90 +174,12 @@ enum values
presented with request or response message.
*/
template<bool isRequest, class Derived>
class basic_parser_v1
class basic_parser_v1 : public detail::parser_base
{
private:
using self = basic_parser_v1;
typedef void(self::*pmf_t)(error_code&, boost::string_ref const&);
static std::uint64_t constexpr no_content_length =
std::numeric_limits<std::uint64_t>::max();
enum state : std::uint8_t
{
s_closed = 1,
s_req_start,
s_req_method_start,
s_req_method,
s_req_space_before_url,
s_req_url_start,
s_req_url,
s_req_http_start,
s_req_http_H,
s_req_http_HT,
s_req_http_HTT,
s_req_http_HTTP,
s_req_major_start,
s_req_major,
s_req_minor_start,
s_req_minor,
s_req_line_end,
s_res_start,
s_res_H,
s_res_HT,
s_res_HTT,
s_res_HTTP,
s_res_major_start,
s_res_major,
s_res_minor_start,
s_res_minor,
s_res_status_code_start,
s_res_status_code,
s_res_status_start,
s_res_status,
s_res_line_almost_done,
s_res_line_done,
s_header_field_start,
s_header_field,
s_header_value_start,
s_header_value_discard_lWs0,
s_header_value_discard_ws0,
s_header_value_almost_done0,
s_header_value_text_start,
s_header_value_discard_lWs,
s_header_value_discard_ws,
s_header_value_text,
s_header_value_almost_done,
s_headers_almost_done,
s_headers_done,
s_chunk_size_start,
s_chunk_size,
s_chunk_parameters,
s_chunk_size_almost_done,
// states below do not count towards
// the limit on the size of the message
s_body_identity0,
s_body_identity,
s_body_identity_eof0,
s_body_identity_eof,
s_chunk_data_start,
s_chunk_data,
s_chunk_data_almost_done,
s_chunk_data_done,
s_complete,
s_restart,
s_closed_complete
};
enum field_state : std::uint8_t
{
h_general = 0,
@@ -224,25 +194,36 @@ private:
h_matching_upgrade,
h_connection,
h_content_length0,
h_content_length,
h_content_length_ows,
h_transfer_encoding,
h_upgrade,
h_matching_transfer_encoding_chunked,
h_matching_connection_token_start,
h_matching_transfer_encoding_general,
h_matching_connection_keep_alive,
h_matching_connection_close,
h_matching_connection_upgrade,
h_matching_connection_token,
h_transfer_encoding_chunked,
h_transfer_encoding_chunked_ows,
h_connection_keep_alive,
h_connection_keep_alive_ows,
h_connection_close,
h_connection_close_ows,
h_connection_upgrade,
h_connection_upgrade_ows,
h_connection_token,
h_connection_token_ows
};
std::size_t h_max_;
std::size_t h_left_;
std::size_t b_max_;
std::size_t b_left_;
std::uint64_t content_length_;
std::uint64_t nread_;
pmf_t cb_;
state s_ : 8;
unsigned flags_ : 8;
@@ -260,10 +241,42 @@ public:
/// Copy assignment.
basic_parser_v1& operator=(basic_parser_v1 const&) = default;
/// Constructor
basic_parser_v1()
/// Default constructor
basic_parser_v1();
/** Set options on the parser.
@param args One or more parser options to set.
*/
#if GENERATING_DOCS
template<class... Args>
void
set_option(Args&&... args)
#else
template<class A1, class A2, class... An>
void
set_option(A1&& a1, A2&& a2, An&&... an)
#endif
{
init(std::integral_constant<bool, isRequest>{});
set_option(std::forward<A1>(a1));
set_option(std::forward<A2>(a2),
std::forward<An>(an)...);
}
/// Set the headers maximum size option
void
set_option(headers_max_size const& o)
{
h_max_ = o.value;
h_left_ = h_max_;
}
/// Set the body maximum size option
void
set_option(body_max_size const& o)
{
b_max_ = o.value;
b_left_ = b_max_;
}
/// Returns internal flags associated with the parser.
@@ -373,14 +386,14 @@ public:
@return The number of bytes consumed in the input sequence.
*/
template<class ConstBufferSequence>
#if GENERATING_DOCS
#if GENERATING_DOCS
std::size_t
#else
#else
typename std::enable_if<
! std::is_convertible<ConstBufferSequence,
boost::asio::const_buffer>::value,
std::size_t>::type
#endif
#endif
write(ConstBufferSequence const& buffers, error_code& ec);
/** Write a single buffer of data to the parser.
@@ -413,17 +426,48 @@ private:
}
void
init(std::true_type)
reset(std::true_type)
{
s_ = s_req_start;
}
void
init(std::false_type)
reset(std::false_type)
{
s_ = s_res_start;
}
void
reset()
{
h_left_ = h_max_;
b_left_ = b_max_;
reset(std::integral_constant<bool, isRequest>{});
}
void
init(std::true_type)
{
// 16KB max headers, 4MB max body
h_max_ = 16 * 1024;
b_max_ = 4 * 1024 * 1024;
}
void
init(std::false_type)
{
// 16KB max headers, unlimited body
h_max_ = 16 * 1024;
b_max_ = 0;
}
void
init()
{
init(std::integral_constant<bool, isRequest>{});
reset();
}
bool
needs_eof(std::true_type) const;
@@ -584,7 +628,7 @@ private:
{
template<class T, class R = std::is_same<int,
decltype(std::declval<T>().on_headers(
std::declval<error_code&>()))>>
std::declval<std::uint64_t>(), std::declval<error_code&>()))>>
static R check(int);
template <class>
static std::false_type check(...);
@@ -661,8 +705,16 @@ private:
void call_on_method(error_code& ec,
boost::string_ref const& s)
{
call_on_method(ec, s, std::integral_constant<bool,
isRequest && has_on_method<Derived>::value>{});
if(! h_max_ || s.size() <= h_left_)
{
h_left_ -= s.size();
call_on_method(ec, s, std::integral_constant<bool,
isRequest && has_on_method<Derived>::value>{});
}
else
{
ec = parse_error::headers_too_big;
}
}
void call_on_uri(error_code& ec,
@@ -678,8 +730,16 @@ private:
void call_on_uri(error_code& ec, boost::string_ref const& s)
{
call_on_uri(ec, s, std::integral_constant<bool,
isRequest && has_on_uri<Derived>::value>{});
if(! h_max_ || s.size() <= h_left_)
{
h_left_ -= s.size();
call_on_uri(ec, s, std::integral_constant<bool,
isRequest && has_on_uri<Derived>::value>{});
}
else
{
ec = parse_error::headers_too_big;
}
}
void call_on_reason(error_code& ec,
@@ -695,8 +755,16 @@ private:
void call_on_reason(error_code& ec, boost::string_ref const& s)
{
call_on_reason(ec, s, std::integral_constant<bool,
! isRequest && has_on_reason<Derived>::value>{});
if(! h_max_ || s.size() <= h_left_)
{
h_left_ -= s.size();
call_on_reason(ec, s, std::integral_constant<bool,
! isRequest && has_on_reason<Derived>::value>{});
}
else
{
ec = parse_error::headers_too_big;
}
}
void call_on_request(error_code& ec, std::true_type)
@@ -742,7 +810,15 @@ private:
void call_on_field(error_code& ec, boost::string_ref const& s)
{
call_on_field(ec, s, has_on_field<Derived>{});
if(! h_max_ || s.size() <= h_left_)
{
h_left_ -= s.size();
call_on_field(ec, s, has_on_field<Derived>{});
}
else
{
ec = parse_error::headers_too_big;
}
}
void call_on_value(error_code& ec,
@@ -758,22 +834,32 @@ private:
void call_on_value(error_code& ec, boost::string_ref const& s)
{
call_on_value(ec, s, has_on_value<Derived>{});
if(! h_max_ || s.size() <= h_left_)
{
h_left_ -= s.size();
call_on_value(ec, s, has_on_value<Derived>{});
}
else
{
ec = parse_error::headers_too_big;
}
}
int call_on_headers(error_code& ec, std::true_type)
int call_on_headers(error_code& ec,
std::uint64_t content_length, std::true_type)
{
return impl().on_headers(ec);
return impl().on_headers(content_length, ec);
}
int call_on_headers(error_code& ec, std::false_type)
int call_on_headers(error_code& ec, std::uint64_t, std::false_type)
{
return 0;
}
int call_on_headers(error_code& ec)
{
return call_on_headers(ec, has_on_headers<Derived>{});
return call_on_headers(ec, content_length_,
has_on_headers<Derived>{});
}
void call_on_body(error_code& ec,
@@ -789,7 +875,15 @@ private:
void call_on_body(error_code& ec, boost::string_ref const& s)
{
call_on_body(ec, s, has_on_body<Derived>{});
if(! b_max_ || s.size() <= b_left_)
{
b_left_ -= s.size();
call_on_body(ec, s, has_on_body<Derived>{});
}
else
{
ec = parse_error::body_too_big;
}
}
void call_on_complete(error_code& ec, std::true_type)

View File

@@ -17,137 +17,6 @@ namespace beast {
namespace http {
namespace detail {
// '0'...'9'
inline
bool
is_digit(char c)
{
return c >= '0' && c <= '9';
}
inline
bool
is_token(char c)
{
/* token = 1*<any CHAR except CTLs or separators>
CHAR = <any US-ASCII character (octets 0 - 127)>
sep = "(" | ")" | "<" | ">" | "@"
| "," | ";" | ":" | "\" | <">
| "/" | "[" | "]" | "?" | "="
| "{" | "}" | SP | HT
*/
static std::array<char, 256> constexpr tab = {{
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 16
0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, // 32
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, // 48
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 64
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, // 80
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 96
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, // 112
}};
return tab[static_cast<std::uint8_t>(c)] != 0;
}
inline
bool
is_text(char c)
{
// TEXT = <any OCTET except CTLs, but including LWS>
static std::array<char, 256> constexpr tab = {{
0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, // 0
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 16
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 32
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 48
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 64
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 80
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 96
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, // 112
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 128
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 144
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 160
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 176
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 192
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 208
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 224
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // 240
}};
return tab[static_cast<std::uint8_t>(c)] != 0;
}
// converts to lower case,
// returns 0 if not a valid token char
//
inline
char
to_field_char(char c)
{
/* token = 1*<any CHAR except CTLs or separators>
CHAR = <any US-ASCII character (octets 0 - 127)>
sep = "(" | ")" | "<" | ">" | "@"
| "," | ";" | ":" | "\" | <">
| "/" | "[" | "]" | "?" | "="
| "{" | "}" | SP | HT
*/
static std::array<char, 256> constexpr tab = {{
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, '!', 0, '#', '$', '%', '&', '\'', 0, 0, '*', '+', 0, '-', '.', 0,
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 0, 0, 0, 0, 0, 0,
0, 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 0, 0, 0, '^', '_',
'`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 0, '|', 0, '~', 0
}};
return tab[static_cast<std::uint8_t>(c)];
}
// converts to lower case,
// returns 0 if not a valid text char
//
inline
char
to_value_char(char c)
{
// TEXT = <any OCTET except CTLs, but including LWS>
static std::array<std::uint8_t, 256> constexpr tab = {{
0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, // 0
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 16
32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, // 32
48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, // 48
64, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, // 64
112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 91, 92, 93, 94, 95, // 80
96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, // 96
112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 0, // 112
128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, // 128
144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, // 144
160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, // 160
176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, // 176
192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, // 192
208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, // 208
224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, // 224
240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255 // 240
}};
return static_cast<char>(tab[static_cast<std::uint8_t>(c)]);
}
inline
std::int8_t
unhex(char c)
{
static std::array<std::int8_t, 256> constexpr tab = {{
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 0
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 16
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 32
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, // 48
-1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 64
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 80
-1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 96
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 // 112
}};
return tab[static_cast<std::uint8_t>(c)];
}
template<class = void>
struct parser_str_t
{
@@ -196,6 +65,82 @@ parser_str_t<_>::transfer_encoding[18];
using parser_str = parser_str_t<>;
class parser_base
{
protected:
enum state : std::uint8_t
{
s_dead = 1,
s_req_start,
s_req_method0,
s_req_method,
s_req_url0,
s_req_url,
s_req_http,
s_req_http_H,
s_req_http_HT,
s_req_http_HTT,
s_req_http_HTTP,
s_req_major,
s_req_dot,
s_req_minor,
s_req_cr,
s_req_lf,
s_res_start,
s_res_H,
s_res_HT,
s_res_HTT,
s_res_HTTP,
s_res_major,
s_res_dot,
s_res_minor,
s_res_space_1,
s_res_status0,
s_res_status1,
s_res_status2,
s_res_space_2,
s_res_reason0,
s_res_reason,
s_res_line_lf,
s_res_line_done,
s_header_name0,
s_header_name,
s_header_value0_lf,
s_header_value0_almost_done,
s_header_value0,
s_header_value,
s_header_value_lf,
s_header_value_almost_done,
s_header_value_unfold,
s_headers_almost_done,
s_headers_done,
s_chunk_size0,
s_chunk_size,
s_chunk_ext_name0,
s_chunk_ext_name,
s_chunk_ext_val,
s_chunk_size_lf,
s_chunk_data0,
s_chunk_data,
s_chunk_data_cr,
s_chunk_data_lf,
s_body_identity0,
s_body_identity,
s_body_identity_eof0,
s_body_identity_eof,
s_complete,
s_restart,
s_closed_complete
};
};
} // detail
} // http
} // beast

View File

@@ -0,0 +1,384 @@
//
// Copyright (c) 2013-2016 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)
//
#ifndef BEAST_HTTP_DETAIL_RFC7230_HPP
#define BEAST_HTTP_DETAIL_RFC7230_HPP
#include <boost/utility/string_ref.hpp>
#include <array>
#include <iterator>
#include <utility>
namespace beast {
namespace http {
namespace detail {
inline
bool
is_digit(char c)
{
return c >= '0' && c <= '9';
}
inline
bool
is_alpha(char c)
{
static std::array<char, 256> constexpr tab = {{
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 16
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 32
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 48
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 64
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, // 80
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 96
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, // 112
}};
return tab[static_cast<std::uint8_t>(c)] != 0;
}
inline
bool
is_text(char c)
{
// TEXT = <any OCTET except CTLs, but including LWS>
static std::array<char, 256> constexpr tab = {{
0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, // 0
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 16
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 32
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 48
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 64
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 80
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 96
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, // 112
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 128
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 144
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 160
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 176
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 192
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 208
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 224
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // 240
}};
return tab[static_cast<std::uint8_t>(c)] != 0;
}
inline
bool
is_tchar(char c)
{
/*
tchar = "!" | "#" | "$" | "%" | "&" |
"'" | "*" | "+" | "-" | "." |
"^" | "_" | "`" | "|" | "~" |
DIGIT | ALPHA
*/
static std::array<char, 256> constexpr tab = {{
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 16
0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, // 32
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, // 48
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 64
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, // 80
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 96
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, // 112
}};
return tab[static_cast<std::uint8_t>(c)] != 0;
}
inline
bool
is_qdchar(char c)
{
/*
qdtext = HTAB / SP / "!" / %x23-5B ; '#'-'[' / %x5D-7E ; ']'-'~' / obs-text
*/
static std::array<bool, 256> constexpr tab = {{
0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, // 0
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 16
1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 32
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 48
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 64
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, // 80
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 96
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, // 112
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 128
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 144
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 160
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 176
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 192
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 208
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 224
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // 240
}};
return tab[static_cast<std::uint8_t>(c)];
}
inline
bool
is_qpchar(char c)
{
/*
quoted-pair = "\" ( HTAB / SP / VCHAR / obs-text )
obs-text = %x80-FF
*/
static std::array<bool, 256> constexpr tab = {{
0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, // 0
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 16
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 32
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 48
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 64
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 80
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 96
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, // 112
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 128
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 144
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 160
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 176
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 192
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 208
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 224
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // 240
}};
return tab[static_cast<std::uint8_t>(c)];
}
// converts to lower case,
// returns 0 if not a valid token char
//
inline
char
to_field_char(char c)
{
/* token = 1*<any CHAR except CTLs or separators>
CHAR = <any US-ASCII character (octets 0 - 127)>
sep = "(" | ")" | "<" | ">" | "@"
| "," | ";" | ":" | "\" | <">
| "/" | "[" | "]" | "?" | "="
| "{" | "}" | SP | HT
*/
static std::array<char, 256> constexpr tab = {{
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, '!', 0, '#', '$', '%', '&', '\'', 0, 0, '*', '+', 0, '-', '.', 0,
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 0, 0, 0, 0, 0, 0,
0, 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 0, 0, 0, '^', '_',
'`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 0, '|', 0, '~', 0
}};
return tab[static_cast<std::uint8_t>(c)];
}
// converts to lower case,
// returns 0 if not a valid text char
//
inline
char
to_value_char(char c)
{
// TEXT = <any OCTET except CTLs, but including LWS>
static std::array<std::uint8_t, 256> constexpr tab = {{
0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, // 0
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 16
32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, // 32
48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, // 48
64, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, // 64
112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 91, 92, 93, 94, 95, // 80
96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, // 96
112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 0, // 112
128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, // 128
144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, // 144
160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, // 160
176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, // 176
192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, // 192
208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, // 208
224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, // 224
240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255 // 240
}};
return static_cast<char>(tab[static_cast<std::uint8_t>(c)]);
}
inline
std::int8_t
unhex(char c)
{
static std::array<std::int8_t, 256> constexpr tab = {{
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 0
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 16
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 32
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, // 48
-1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 64
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 80
-1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 96
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 // 112
}};
return tab[static_cast<std::uint8_t>(c)];
}
template<class FwdIt>
void
skip_ows(FwdIt& it, FwdIt const& end)
{
while(it != end)
{
auto const c = *it;
if(c != ' ' && c != '\t')
break;
++it;
}
}
inline
boost::string_ref
trim(boost::string_ref const& s)
{
auto first = s.begin();
auto last = s.end();
skip_ows(first, last);
while(first != last)
{
auto const c = *std::prev(last);
if(c != ' ' && c != '\t')
break;
--last;
}
if(first == last)
return {};
return {&*first,
static_cast<std::size_t>(last - first)};
}
struct param_iter
{
using iter_type = boost::string_ref::const_iterator;
iter_type it;
iter_type begin;
iter_type end;
std::pair<boost::string_ref, boost::string_ref> v;
bool
empty() const
{
return begin == it;
}
template<class = void>
void
increment();
};
template<class>
void
param_iter::
increment()
{
/*
ext-list = *( "," OWS ) ext *( OWS "," [ OWS ext ] )
ext = token param-list
param-list = *( OWS ";" OWS param )
param = token OWS "=" OWS ( token / quoted-string )
quoted-string = DQUOTE *( qdtext / quoted-pair ) DQUOTE
qdtext = HTAB / SP / "!" / %x23-5B ; '#'-'[' / %x5D-7E ; ']'-'~' / obs-text
quoted-pair = "\" ( HTAB / SP / VCHAR / obs-text )
obs-text = %x80-FF
Example:
chunked;a=b;i=j,gzip;windowBits=12
x,y
*/
auto const err =
[&]
{
it = begin;
};
v.first.clear();
v.second.clear();
detail::skip_ows(it, end);
begin = it;
if(it == end)
return err();
if(*it != ';')
return err();
++it;
detail::skip_ows(it, end);
if(it == end)
return err();
// param
if(! detail::is_tchar(*it))
return err();
auto const p0 = it;
for(;;)
{
++it;
if(it == end)
return err();
if(! detail::is_tchar(*it))
break;
}
auto const p1 = it;
detail::skip_ows(it, end);
if(it == end)
return err();
if(*it != '=')
return err();
++it;
detail::skip_ows(it, end);
if(it == end)
return err();
if(*it == '"')
{
// quoted-string
auto const p2 = it;
++it;
for(;;)
{
if(it == end)
return err();
auto c = *it++;
if(c == '"')
break;
if(detail::is_qdchar(c))
continue;
if(c != '\\')
return err();
if(it == end)
return err();
c = *it++;
if(! detail::is_qpchar(c))
return err();
}
v.first = { &*p0, static_cast<std::size_t>(p1 - p0) };
v.second = { &*p2, static_cast<std::size_t>(it - p2) };
}
else
{
// token
if(! detail::is_tchar(*it))
return err();
auto const p2 = it;
for(;;)
{
it++;
if(it == end)
break;
if(! detail::is_tchar(*it))
break;
}
v.first = { &*p0, static_cast<std::size_t>(p1 - p0) };
v.second = { &*p2, static_cast<std::size_t>(it - p2) };
}
}
} // detail
} // http
} // beast
#endif

View File

@@ -9,7 +9,6 @@
#define BEAST_HTTP_EMPTY_BODY_HPP
#include <beast/http/body_type.hpp>
#include <beast/core/streambuf.hpp>
#include <boost/asio/buffer.hpp>
#include <memory>
#include <string>

View File

@@ -8,6 +8,8 @@
#ifndef BEAST_HTTP_IMPL_BASIC_HEADERS_IPP
#define BEAST_HTTP_IMPL_BASIC_HEADERS_IPP
#include <beast/http/detail/rfc7230.hpp>
namespace beast {
namespace http {
@@ -257,12 +259,13 @@ template<class Allocator>
void
basic_headers<Allocator>::
insert(boost::string_ref const& name,
boost::string_ref const& value)
boost::string_ref value)
{
value = detail::trim(value);
typename set_t::insert_commit_data d;
auto const result =
set_.insert_check(name, less{}, d);
if (result.second)
if(result.second)
{
auto const p = alloc_traits::allocate(
this->member(), 1);
@@ -284,8 +287,9 @@ template<class Allocator>
void
basic_headers<Allocator>::
replace(boost::string_ref const& name,
boost::string_ref const& value)
boost::string_ref value)
{
value = detail::trim(value);
erase(name);
insert(name, value);
}

File diff suppressed because it is too large Load Diff

View File

@@ -8,7 +8,7 @@
#ifndef BEAST_HTTP_IMPL_MESSAGE_V1_IPP
#define BEAST_HTTP_IMPL_MESSAGE_V1_IPP
#include <beast/http/rfc2616.hpp>
#include <beast/http/rfc7230.hpp>
#include <beast/http/detail/has_content_length.hpp>
#include <boost/optional.hpp>
#include <stdexcept>
@@ -22,13 +22,11 @@ is_keep_alive(message_v1<isRequest, Body, Headers> const& msg)
{
if(msg.version >= 11)
{
if(rfc2616::token_in_list(
msg.headers["Connection"], "close"))
if(token_list{msg.headers["Connection"]}.exists("close"))
return false;
return true;
}
if(rfc2616::token_in_list(
msg.headers["Connection"], "keep-alive"))
if(token_list{msg.headers["Connection"]}.exists("keep-alive"))
return true;
return false;
}
@@ -39,8 +37,7 @@ is_upgrade(message_v1<isRequest, Body, Headers> const& msg)
{
if(msg.version < 11)
return false;
if(rfc2616::token_in_list(
msg.headers["Connection"], "upgrade"))
if(token_list{msg.headers["Connection"]}.exists("upgrade"))
return true;
return false;
}
@@ -129,8 +126,7 @@ prepare(message_v1<isRequest, Body, Headers>& msg,
throw std::invalid_argument(
"prepare called with Content-Length field set");
if(rfc2616::token_in_list(
msg.headers["Transfer-Encoding"], "chunked"))
if(token_list{msg.headers["Transfer-Encoding"]}.exists("chunked"))
throw std::invalid_argument(
"prepare called with Transfer-Encoding: chunked set");
@@ -175,8 +171,8 @@ prepare(message_v1<isRequest, Body, Headers>& msg,
}
// rfc7230 6.7.
if(msg.version < 11 && rfc2616::token_in_list(
msg.headers["Connection"], "upgrade"))
if(msg.version < 11 && token_list{
msg.headers["Connection"]}.exists("upgrade"))
throw std::invalid_argument(
"invalid version for Connection: upgrade");
}

View File

@@ -21,7 +21,7 @@ namespace http {
namespace detail {
template<class Stream,
class Streambuf, class Parser, class Handler>
class DynamicBuffer, class Parser, class Handler>
class parse_op
{
using alloc_type =
@@ -30,7 +30,7 @@ class parse_op
struct data
{
Stream& s;
Streambuf& sb;
DynamicBuffer& db;
Parser& p;
Handler h;
bool started = false;
@@ -39,9 +39,9 @@ class parse_op
template<class DeducedHandler>
data(DeducedHandler&& h_, Stream& s_,
Streambuf& sb_, Parser& p_)
DynamicBuffer& sb_, Parser& p_)
: s(s_)
, sb(sb_)
, db(sb_)
, p(p_)
, h(std::forward<DeducedHandler>(h_))
, cont(boost_asio_handler_cont_helpers::
@@ -101,9 +101,9 @@ public:
};
template<class Stream,
class Streambuf, class Parser, class Handler>
class DynamicBuffer, class Parser, class Handler>
void
parse_op<Stream, Streambuf, Parser, Handler>::
parse_op<Stream, DynamicBuffer, Parser, Handler>::
operator()(error_code ec, std::size_t bytes_transferred, bool again)
{
auto& d = *d_;
@@ -115,7 +115,7 @@ operator()(error_code ec, std::size_t bytes_transferred, bool again)
case 0:
{
auto const used =
d.p.write(d.sb.data(), ec);
d.p.write(d.db.data(), ec);
if(ec)
{
// call handler
@@ -126,7 +126,7 @@ operator()(error_code ec, std::size_t bytes_transferred, bool again)
}
if(used > 0)
d.started = true;
d.sb.consume(used);
d.db.consume(used);
if(d.p.complete())
{
// call handler
@@ -142,8 +142,8 @@ operator()(error_code ec, std::size_t bytes_transferred, bool again)
case 1:
// read
d.state = 2;
d.s.async_read_some(d.sb.prepare(
read_size_helper(d.sb, 65536)),
d.s.async_read_some(d.db.prepare(
read_size_helper(d.db, 65536)),
std::move(*this));
return;
@@ -172,8 +172,8 @@ operator()(error_code ec, std::size_t bytes_transferred, bool again)
d.state = 99;
break;
}
d.sb.commit(bytes_transferred);
auto const used = d.p.write(d.sb.data(), ec);
d.db.commit(bytes_transferred);
auto const used = d.p.write(d.db.data(), ec);
if(ec)
{
// call handler
@@ -182,7 +182,7 @@ operator()(error_code ec, std::size_t bytes_transferred, bool again)
}
if(used > 0)
d.started = true;
d.sb.consume(used);
d.db.consume(used);
if(d.p.complete())
{
// call handler
@@ -199,7 +199,7 @@ operator()(error_code ec, std::size_t bytes_transferred, bool again)
//------------------------------------------------------------------------------
template<class Stream, class Streambuf,
template<class Stream, class DynamicBuffer,
bool isRequest, class Body, class Headers,
class Handler>
class read_op
@@ -216,7 +216,7 @@ class read_op
struct data
{
Stream& s;
Streambuf& sb;
DynamicBuffer& db;
message_type& m;
parser_type p;
Handler h;
@@ -226,9 +226,9 @@ class read_op
template<class DeducedHandler>
data(DeducedHandler&& h_, Stream& s_,
Streambuf& sb_, message_type& m_)
DynamicBuffer& sb_, message_type& m_)
: s(s_)
, sb(sb_)
, db(sb_)
, m(m_)
, h(std::forward<DeducedHandler>(h_))
, cont(boost_asio_handler_cont_helpers::
@@ -286,11 +286,11 @@ public:
}
};
template<class Stream, class Streambuf,
template<class Stream, class DynamicBuffer,
bool isRequest, class Body, class Headers,
class Handler>
void
read_op<Stream, Streambuf, isRequest, Body, Headers, Handler>::
read_op<Stream, DynamicBuffer, isRequest, Body, Headers, Handler>::
operator()(error_code ec, bool again)
{
auto& d = *d_;
@@ -301,7 +301,7 @@ operator()(error_code ec, bool again)
{
case 0:
d.state = 1;
async_parse(d.s, d.sb, d.p, std::move(*this));
async_parse(d.s, d.db, d.p, std::move(*this));
return;
case 1:
@@ -318,49 +318,49 @@ operator()(error_code ec, bool again)
//------------------------------------------------------------------------------
template<class SyncReadStream, class Streambuf, class Parser>
template<class SyncReadStream, class DynamicBuffer, class Parser>
void
parse(SyncReadStream& stream,
Streambuf& streambuf, Parser& parser)
DynamicBuffer& dynabuf, Parser& parser)
{
static_assert(is_SyncReadStream<SyncReadStream>::value,
"SyncReadStream requirements not met");
static_assert(is_Streambuf<Streambuf>::value,
"Streambuf requirements not met");
static_assert(is_DynamicBuffer<DynamicBuffer>::value,
"DynamicBuffer requirements not met");
static_assert(is_Parser<Parser>::value,
"Parser requirements not met");
error_code ec;
parse(stream, streambuf, parser, ec);
parse(stream, dynabuf, parser, ec);
if(ec)
throw boost::system::system_error{ec};
}
template<class SyncReadStream, class Streambuf, class Parser>
template<class SyncReadStream, class DynamicBuffer, class Parser>
void
parse(SyncReadStream& stream, Streambuf& streambuf,
parse(SyncReadStream& stream, DynamicBuffer& dynabuf,
Parser& parser, error_code& ec)
{
static_assert(is_SyncReadStream<SyncReadStream>::value,
"SyncReadStream requirements not met");
static_assert(is_Streambuf<Streambuf>::value,
"Streambuf requirements not met");
static_assert(is_DynamicBuffer<DynamicBuffer>::value,
"DynamicBuffer requirements not met");
static_assert(is_Parser<Parser>::value,
"Parser requirements not met");
bool started = false;
for(;;)
{
auto used =
parser.write(streambuf.data(), ec);
parser.write(dynabuf.data(), ec);
if(ec)
return;
streambuf.consume(used);
dynabuf.consume(used);
if(used > 0)
started = true;
if(parser.complete())
break;
streambuf.commit(stream.read_some(
streambuf.prepare(read_size_helper(
streambuf, 65536)), ec));
dynabuf.commit(stream.read_some(
dynabuf.prepare(read_size_helper(
dynabuf, 65536)), ec));
if(ec && ec != boost::asio::error::eof)
return;
if(ec == boost::asio::error::eof)
@@ -379,86 +379,86 @@ parse(SyncReadStream& stream, Streambuf& streambuf,
}
template<class AsyncReadStream,
class Streambuf, class Parser, class ReadHandler>
class DynamicBuffer, class Parser, class ReadHandler>
typename async_completion<
ReadHandler, void(error_code)>::result_type
async_parse(AsyncReadStream& stream,
Streambuf& streambuf, Parser& parser, ReadHandler&& handler)
DynamicBuffer& dynabuf, Parser& parser, ReadHandler&& handler)
{
static_assert(is_AsyncReadStream<AsyncReadStream>::value,
"AsyncReadStream requirements not met");
static_assert(is_Streambuf<Streambuf>::value,
"Streambuf requirements not met");
static_assert(is_DynamicBuffer<DynamicBuffer>::value,
"DynamicBuffer requirements not met");
static_assert(is_Parser<Parser>::value,
"Parser requirements not met");
beast::async_completion<ReadHandler,
void(error_code)> completion(handler);
detail::parse_op<AsyncReadStream, Streambuf,
detail::parse_op<AsyncReadStream, DynamicBuffer,
Parser, decltype(completion.handler)>{
completion.handler, stream, streambuf, parser};
completion.handler, stream, dynabuf, parser};
return completion.result.get();
}
template<class SyncReadStream, class Streambuf,
template<class SyncReadStream, class DynamicBuffer,
bool isRequest, class Body, class Headers>
void
read(SyncReadStream& stream, Streambuf& streambuf,
read(SyncReadStream& stream, DynamicBuffer& dynabuf,
message_v1<isRequest, Body, Headers>& msg)
{
static_assert(is_SyncReadStream<SyncReadStream>::value,
"SyncReadStream requirements not met");
static_assert(is_Streambuf<Streambuf>::value,
"Streambuf requirements not met");
static_assert(is_DynamicBuffer<DynamicBuffer>::value,
"DynamicBuffer requirements not met");
static_assert(is_ReadableBody<Body>::value,
"ReadableBody requirements not met");
error_code ec;
read(stream, streambuf, msg, ec);
read(stream, dynabuf, msg, ec);
if(ec)
throw system_error{ec};
}
template<class SyncReadStream, class Streambuf,
template<class SyncReadStream, class DynamicBuffer,
bool isRequest, class Body, class Headers>
void
read(SyncReadStream& stream, Streambuf& streambuf,
read(SyncReadStream& stream, DynamicBuffer& dynabuf,
message_v1<isRequest, Body, Headers>& m,
error_code& ec)
{
static_assert(is_SyncReadStream<SyncReadStream>::value,
"SyncReadStream requirements not met");
static_assert(is_Streambuf<Streambuf>::value,
"Streambuf requirements not met");
static_assert(is_DynamicBuffer<DynamicBuffer>::value,
"DynamicBuffer requirements not met");
static_assert(is_ReadableBody<Body>::value,
"ReadableBody requirements not met");
parser_v1<isRequest, Body, Headers> p;
parse(stream, streambuf, p, ec);
parse(stream, dynabuf, p, ec);
if(ec)
return;
assert(p.complete());
m = p.release();
}
template<class AsyncReadStream, class Streambuf,
template<class AsyncReadStream, class DynamicBuffer,
bool isRequest, class Body, class Headers,
class ReadHandler>
typename async_completion<
ReadHandler, void(error_code)>::result_type
async_read(AsyncReadStream& stream, Streambuf& streambuf,
async_read(AsyncReadStream& stream, DynamicBuffer& dynabuf,
message_v1<isRequest, Body, Headers>& m,
ReadHandler&& handler)
{
static_assert(is_AsyncReadStream<AsyncReadStream>::value,
"AsyncReadStream requirements not met");
static_assert(is_Streambuf<Streambuf>::value,
"Streambuf requirements not met");
static_assert(is_DynamicBuffer<DynamicBuffer>::value,
"DynamicBuffer requirements not met");
static_assert(is_ReadableBody<Body>::value,
"ReadableBody requirements not met");
beast::async_completion<ReadHandler,
void(error_code)> completion(handler);
detail::read_op<AsyncReadStream, Streambuf,
detail::read_op<AsyncReadStream, DynamicBuffer,
isRequest, Body, Headers, decltype(
completion.handler)>{completion.handler,
stream, streambuf, m};
stream, dynabuf, m};
return completion.result.get();
}

View File

@@ -0,0 +1,548 @@
//
// Copyright (c) 2013-2016 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)
//
#ifndef BEAST_HTTP_IMPL_RFC7230_IPP
#define BEAST_HTTP_IMPL_RFC7230_IPP
#include <beast/core/detail/ci_char_traits.hpp>
#include <beast/http/detail/rfc7230.hpp>
#include <iterator>
namespace beast {
namespace http {
class param_list::const_iterator
{
using iter_type = boost::string_ref::const_iterator;
std::string s_;
detail::param_iter pi_;
public:
using value_type = param_list::value_type;
using pointer = value_type const*;
using reference = value_type const&;
using difference_type = std::ptrdiff_t;
using iterator_category = std::input_iterator_tag;
const_iterator() = default;
bool
operator==(const_iterator const& other) const
{
return
other.pi_.it == pi_.it &&
other.pi_.end == pi_.end &&
other.pi_.begin == pi_.begin;
}
bool
operator!=(const_iterator const& other) const
{
return !(*this == other);
}
reference
operator*() const
{
return pi_.v;
}
pointer
operator->() const
{
return &*(*this);
}
const_iterator&
operator++()
{
increment();
return *this;
}
const_iterator
operator++(int)
{
auto temp = *this;
++(*this);
return temp;
}
private:
friend class param_list;
const_iterator(iter_type begin, iter_type end)
{
pi_.it = begin;
pi_.begin = begin;
pi_.end = end;
increment();
}
template<class = void>
static
std::string
unquote(boost::string_ref const& sr);
template<class = void>
void
increment();
};
inline
auto
param_list::
begin() const ->
const_iterator
{
return const_iterator{s_.begin(), s_.end()};
}
inline
auto
param_list::
end() const ->
const_iterator
{
return const_iterator{s_.end(), s_.end()};
}
inline
auto
param_list::
cbegin() const ->
const_iterator
{
return const_iterator{s_.begin(), s_.end()};
}
inline
auto
param_list::
cend() const ->
const_iterator
{
return const_iterator{s_.end(), s_.end()};
}
template<class>
std::string
param_list::const_iterator::
unquote(boost::string_ref const& sr)
{
std::string s;
s.reserve(sr.size());
auto it = sr.begin() + 1;
auto end = sr.end() - 1;
while(it != end)
{
if(*it == '\\')
++it;
s.push_back(*it);
++it;
}
return s;
}
template<class>
void
param_list::const_iterator::
increment()
{
s_.clear();
pi_.increment();
if(pi_.empty())
{
pi_.it = pi_.end;
pi_.begin = pi_.end;
}
else if(pi_.v.second.front() == '"')
{
s_ = unquote(pi_.v.second);
pi_.v.second = boost::string_ref{
s_.data(), s_.size()};
}
}
//------------------------------------------------------------------------------
class ext_list::const_iterator
{
ext_list::value_type v_;
iter_type it_;
iter_type begin_;
iter_type end_;
public:
using value_type = ext_list::value_type;
using pointer = value_type const*;
using reference = value_type const&;
using difference_type = std::ptrdiff_t;
using iterator_category = std::forward_iterator_tag;
const_iterator() = default;
bool
operator==(const_iterator const& other) const
{
return
other.it_ == it_ &&
other.begin_ == begin_ &&
other.end_ == end_;
}
bool
operator!=(const_iterator const& other) const
{
return !(*this == other);
}
reference
operator*() const
{
return v_;
}
pointer
operator->() const
{
return &*(*this);
}
const_iterator&
operator++()
{
increment();
return *this;
}
const_iterator
operator++(int)
{
auto temp = *this;
++(*this);
return temp;
}
private:
friend class ext_list;
const_iterator(iter_type begin, iter_type end)
{
it_ = begin;
begin_ = begin;
end_ = end;
increment();
}
template<class = void>
void
increment();
};
inline
auto
ext_list::
begin() const ->
const_iterator
{
return const_iterator{s_.begin(), s_.end()};
}
inline
auto
ext_list::
end() const ->
const_iterator
{
return const_iterator{s_.end(), s_.end()};
}
inline
auto
ext_list::
cbegin() const ->
const_iterator
{
return const_iterator{s_.begin(), s_.end()};
}
inline
auto
ext_list::
cend() const ->
const_iterator
{
return const_iterator{s_.end(), s_.end()};
}
template<class T>
auto
ext_list::
find(T const& s) ->
const_iterator
{
return std::find_if(begin(), end(),
[&s](value_type const& v)
{
return beast::detail::ci_equal(s, v.first);
});
}
template<class T>
bool
ext_list::
exists(T const& s)
{
return find(s) != end();
}
template<class>
void
ext_list::const_iterator::
increment()
{
/*
ext-list = *( "," OWS ) ext *( OWS "," [ OWS ext ] )
ext = token param-list
param-list = *( OWS ";" OWS param )
param = token OWS "=" OWS ( token / quoted-string )
chunked;a=b;i=j,gzip;windowBits=12
x,y
,,,,,chameleon
*/
auto const err =
[&]
{
it_ = end_;
begin_ = end_;
};
auto need_comma = it_ != begin_;
v_.first = {};
begin_ = it_;
for(;;)
{
detail::skip_ows(it_, end_);
if(it_ == end_)
return err();
auto const c = *it_;
if(detail::is_tchar(c))
{
if(need_comma)
return err();
auto const p0 = it_;
for(;;)
{
++it_;
if(it_ == end_)
break;
if(! detail::is_tchar(*it_))
break;
}
v_.first = boost::string_ref{&*p0,
static_cast<std::size_t>(it_ - p0)};
detail::param_iter pi;
pi.it = it_;
pi.begin = it_;
pi.end = end_;
for(;;)
{
pi.increment();
if(pi.empty())
break;
}
v_.second = param_list{boost::string_ref{&*it_,
static_cast<std::size_t>(pi.it - it_)}};
it_ = pi.it;
return;
}
if(c != ',')
return err();
need_comma = false;
++it_;
}
}
//------------------------------------------------------------------------------
class token_list::const_iterator
{
token_list::value_type v_;
iter_type it_;
iter_type begin_;
iter_type end_;
public:
using value_type = token_list::value_type;
using pointer = value_type const*;
using reference = value_type const&;
using difference_type = std::ptrdiff_t;
using iterator_category = std::forward_iterator_tag;
const_iterator() = default;
bool
operator==(const_iterator const& other) const
{
return
other.it_ == it_ &&
other.begin_ == begin_ &&
other.end_ == end_;
}
bool
operator!=(const_iterator const& other) const
{
return !(*this == other);
}
reference
operator*() const
{
return v_;
}
pointer
operator->() const
{
return &*(*this);
}
const_iterator&
operator++()
{
increment();
return *this;
}
const_iterator
operator++(int)
{
auto temp = *this;
++(*this);
return temp;
}
private:
friend class token_list;
const_iterator(iter_type begin, iter_type end)
{
it_ = begin;
begin_ = begin;
end_ = end;
increment();
}
template<class = void>
void
increment();
};
inline
auto
token_list::
begin() const ->
const_iterator
{
return const_iterator{s_.begin(), s_.end()};
}
inline
auto
token_list::
end() const ->
const_iterator
{
return const_iterator{s_.end(), s_.end()};
}
inline
auto
token_list::
cbegin() const ->
const_iterator
{
return const_iterator{s_.begin(), s_.end()};
}
inline
auto
token_list::
cend() const ->
const_iterator
{
return const_iterator{s_.end(), s_.end()};
}
template<class>
void
token_list::const_iterator::
increment()
{
/*
token-list = *( "," OWS ) token *( OWS "," [ OWS ext ] )
*/
auto const err =
[&]
{
it_ = end_;
begin_ = end_;
};
auto need_comma = it_ != begin_;
v_ = {};
begin_ = it_;
for(;;)
{
detail::skip_ows(it_, end_);
if(it_ == end_)
return err();
auto const c = *it_;
if(detail::is_tchar(c))
{
if(need_comma)
return err();
auto const p0 = it_;
for(;;)
{
++it_;
if(it_ == end_)
break;
if(! detail::is_tchar(*it_))
break;
}
v_ = boost::string_ref{&*p0,
static_cast<std::size_t>(it_ - p0)};
return;
}
if(c != ',')
return err();
need_comma = false;
++it_;
}
}
template<class T>
bool
token_list::
exists(T const& s)
{
return std::find_if(begin(), end(),
[&s](value_type const& v)
{
return beast::detail::ci_equal(s, v);
}
) != end();
}
} // http
} // beast
#endif

View File

@@ -18,7 +18,7 @@
#include <beast/core/handler_alloc.hpp>
#include <beast/core/stream_concepts.hpp>
#include <beast/core/streambuf.hpp>
#include <beast/core/write_streambuf.hpp>
#include <beast/core/write_dynabuf.hpp>
#include <boost/asio/write.hpp>
#include <boost/logic/tribool.hpp>
#include <condition_variable>
@@ -32,51 +32,51 @@ namespace http {
namespace detail {
template<class Streambuf, class Body, class Headers>
template<class DynamicBuffer, class Body, class Headers>
void
write_firstline(Streambuf& streambuf,
write_firstline(DynamicBuffer& dynabuf,
message_v1<true, Body, Headers> const& msg)
{
write(streambuf, msg.method);
write(streambuf, " ");
write(streambuf, msg.url);
write(streambuf, " HTTP/");
write(streambuf, msg.version / 10);
write(streambuf, ".");
write(streambuf, msg.version % 10);
write(streambuf, "\r\n");
write(dynabuf, msg.method);
write(dynabuf, " ");
write(dynabuf, msg.url);
write(dynabuf, " HTTP/");
write(dynabuf, msg.version / 10);
write(dynabuf, ".");
write(dynabuf, msg.version % 10);
write(dynabuf, "\r\n");
}
template<class Streambuf, class Body, class Headers>
template<class DynamicBuffer, class Body, class Headers>
void
write_firstline(Streambuf& streambuf,
write_firstline(DynamicBuffer& dynabuf,
message_v1<false, Body, Headers> const& msg)
{
write(streambuf, "HTTP/");
write(streambuf, msg.version / 10);
write(streambuf, ".");
write(streambuf, msg.version % 10);
write(streambuf, " ");
write(streambuf, msg.status);
write(streambuf, " ");
write(streambuf, msg.reason);
write(streambuf, "\r\n");
write(dynabuf, "HTTP/");
write(dynabuf, msg.version / 10);
write(dynabuf, ".");
write(dynabuf, msg.version % 10);
write(dynabuf, " ");
write(dynabuf, msg.status);
write(dynabuf, " ");
write(dynabuf, msg.reason);
write(dynabuf, "\r\n");
}
template<class Streambuf, class FieldSequence>
template<class DynamicBuffer, class FieldSequence>
void
write_fields(Streambuf& streambuf, FieldSequence const& fields)
write_fields(DynamicBuffer& dynabuf, FieldSequence const& fields)
{
static_assert(is_Streambuf<Streambuf>::value,
"Streambuf requirements not met");
static_assert(is_DynamicBuffer<DynamicBuffer>::value,
"DynamicBuffer requirements not met");
//static_assert(is_FieldSequence<FieldSequence>::value,
// "FieldSequence requirements not met");
for(auto const& field : fields)
{
write(streambuf, field.name());
write(streambuf, ": ");
write(streambuf, field.value());
write(streambuf, "\r\n");
write(dynabuf, field.name());
write(dynabuf, ": ");
write(dynabuf, field.value());
write(dynabuf, "\r\n");
}
}
@@ -97,10 +97,10 @@ struct write_preparation
message_v1<isRequest, Body, Headers> const& msg_)
: msg(msg_)
, w(msg)
, chunked(rfc2616::token_in_list(
msg.headers["Transfer-Encoding"], "chunked"))
, close(rfc2616::token_in_list(
msg.headers["Connection"], "close") ||
, chunked(token_list{
msg.headers["Transfer-Encoding"]}.exists("chunked"))
, close(token_list{
msg.headers["Connection"]}.exists("close") ||
(msg.version < 11 && ! msg.headers.exists(
"Content-Length")))
{
@@ -378,17 +378,17 @@ operator()(error_code ec, std::size_t, bool again)
d.copy = {};
}
template<class SyncWriteStream, class Streambuf>
template<class SyncWriteStream, class DynamicBuffer>
class writef0_lambda
{
Streambuf const& sb_;
DynamicBuffer const& sb_;
SyncWriteStream& stream_;
bool chunked_;
error_code& ec_;
public:
writef0_lambda(SyncWriteStream& stream,
Streambuf const& sb, bool chunked, error_code& ec)
DynamicBuffer const& sb, bool chunked, error_code& ec)
: sb_(sb)
, stream_(stream)
, chunked_(chunked)
@@ -548,9 +548,8 @@ async_write(AsyncWriteStream& stream,
message_v1<isRequest, Body, Headers> const& msg,
WriteHandler&& handler)
{
static_assert(
is_AsyncWriteStream<AsyncWriteStream>::value,
"AsyncWriteStream requirements not met");
static_assert(is_AsyncWriteStream<AsyncWriteStream>::value,
"AsyncWriteStream requirements not met");
static_assert(is_WritableBody<Body>::value,
"WritableBody requirements not met");
beast::async_completion<WriteHandler,

View File

@@ -24,12 +24,30 @@ struct request_fields
{
std::string method;
std::string url;
protected:
void
swap(request_fields& other)
{
using std::swap;
swap(method, other.method);
swap(url, other.url);
}
};
struct response_fields
{
int status;
std::string reason;
protected:
void
swap(response_fields& other)
{
using std::swap;
swap(status, other.status);
swap(reason, other.reason);
}
};
} // detail
@@ -125,7 +143,14 @@ struct message
{
}
/// Swap this message for another message.
void
swap(message& other);
private:
using base = typename std::conditional<isRequest,
detail::request_fields, detail::response_fields>::type;
template<class... Un, size_t... IUn>
message(std::piecewise_construct_t,
std::tuple<Un...>& tu, beast::detail::index_sequence<IUn...>)
@@ -145,7 +170,26 @@ private:
}
};
#if ! GENERATING_DOCS
template<bool isRequest, class Body, class Headers>
void
message<isRequest, Body, Headers>::
swap(message& other)
{
using std::swap;
base::swap(other);
swap(headers, other.headers);
swap(body, other.body);
}
/// Swap one message for another message.
template<bool isRequest, class Body, class Headers>
inline
void
swap(message<isRequest, Body, Headers>& lhs,
message<isRequest, Body, Headers>& rhs)
{
lhs.swap(rhs);
}
/// A typical HTTP request
template<class Body,
@@ -157,8 +201,6 @@ template<class Body,
class Headers = basic_headers<std::allocator<char>>>
using response = message<false, Body, Headers>;
#endif
} // http
} // beast

View File

@@ -48,9 +48,31 @@ struct message_v1 : message<isRequest, Body, Headers>
std::forward<Argn>(argn)...)
{
}
/// Swap this message for another message.
void
swap(message_v1& other);
};
#if ! GENERATING_DOCS
template<bool isRequest, class Body, class Headers>
void
message_v1<isRequest, Body, Headers>::
swap(message_v1& other)
{
using std::swap;
message<isRequest, Body, Headers>::swap(other);
swap(version, other.version);
}
/// Swap one message for another message.
template<bool isRequest, class Body, class Headers>
inline
void
swap(message_v1<isRequest, Body, Headers>& lhs,
message_v1<isRequest, Body, Headers>& rhs)
{
lhs.swap(rhs);
}
/// A typical HTTP/1 request
template<class Body,
@@ -62,8 +84,6 @@ template<class Body,
class Headers = basic_headers<std::allocator<char>>>
using response_v1 = message_v1<false, Body, Headers>;
#endif
/// Returns `true` if a HTTP/1 message indicates a keep alive
template<bool isRequest, class Body, class Headers>
bool

View File

@@ -23,8 +23,8 @@ enum class parse_error
bad_crlf,
bad_request,
bad_status_code,
bad_status,
bad_reason,
bad_field,
bad_value,
@@ -33,7 +33,11 @@ enum class parse_error
bad_on_headers_rv,
invalid_chunk_size,
invalid_ext_name,
invalid_ext_val,
headers_too_big,
body_too_big,
short_read,
general
@@ -60,7 +64,7 @@ public:
return "bad method";
case parse_error::bad_uri:
return "bad Request-URI";
return "bad request-target";
case parse_error::bad_version:
return "bad HTTP-Version";
@@ -69,13 +73,13 @@ public:
return "missing CRLF";
case parse_error::bad_request:
return "bad Request-Line";
case parse_error::bad_status_code:
return "bad Status-Code";
return "bad reason-phrase";
case parse_error::bad_status:
return "bad Status-Line";
return "bad status-code";
case parse_error::bad_reason:
return "bad reason-phrase";
case parse_error::bad_field:
return "bad field token";
@@ -95,6 +99,18 @@ public:
case parse_error::invalid_chunk_size:
return "invalid chunk size";
case parse_error::invalid_ext_name:
return "invalid ext name";
case parse_error::invalid_ext_val:
return "invalid ext val";
case parse_error::headers_too_big:
return "headers size limit exceeded";
case parse_error::body_too_big:
return "body size limit exceeded";
case parse_error::short_read:
return "unexpected end of data";

View File

@@ -124,8 +124,6 @@ private:
{
if(! value_.empty())
{
rfc2616::trim_right_in_place(value_);
// VFALCO could std::move
m_.headers.insert(field_, value_);
field_.clear();
value_.clear();
@@ -174,7 +172,7 @@ private:
m_.reason = std::move(this->reason_);
}
int on_headers(error_code&)
int on_headers(std::uint64_t, error_code&)
{
flush();
m_.version = 10 * this->http_major() + this->http_minor();

View File

@@ -12,7 +12,6 @@
#include <beast/core/error.hpp>
#include <beast/core/async_completion.hpp>
#include <boost/asio/buffer.hpp>
#include <boost/system/error_code.hpp>
namespace beast {
namespace http {
@@ -36,7 +35,7 @@ namespace http {
@param stream The stream from which the data is to be read.
The type must support the @b `SyncReadStream` concept.
@param streambuf A `Streambuf` holding additional bytes
@param dynabuf A @b `DynamicBuffer` holding additional bytes
read by the implementation from the stream. This is both
an input and an output parameter; on entry, any data in the
stream buffer's input sequence will be given to the parser
@@ -47,10 +46,10 @@ namespace http {
@throws boost::system::system_error on failure.
*/
template<class SyncReadStream, class Streambuf, class Parser>
template<class SyncReadStream, class DynamicBuffer, class Parser>
void
parse(SyncReadStream& stream,
Streambuf& streambuf, Parser& parser);
DynamicBuffer& dynabuf, Parser& parser);
/** Parse a HTTP/1 message from a stream.
@@ -71,7 +70,7 @@ parse(SyncReadStream& stream,
@param stream The stream from which the data is to be read.
The type must support the @b `SyncReadStream` concept.
@param streambuf A `Streambuf` holding additional bytes
@param dynabuf A @b `DynamicBuffer` holding additional bytes
read by the implementation from the stream. This is both
an input and an output parameter; on entry, any data in the
stream buffer's input sequence will be given to the parser
@@ -82,10 +81,10 @@ parse(SyncReadStream& stream,
@param ec Set to the error, if any occurred.
*/
template<class SyncReadStream, class Streambuf, class Parser>
template<class SyncReadStream, class DynamicBuffer, class Parser>
void
parse(SyncReadStream& stream,
Streambuf& streambuf, Parser& parser, error_code& ec);
DynamicBuffer& dynabuf, Parser& parser, error_code& ec);
/** Start an asynchronous operation to parse a HTTP/1 message from a stream.
@@ -106,7 +105,7 @@ parse(SyncReadStream& stream,
@param stream The stream from which the data is to be read.
The type must support the @b `AsyncReadStream` concept.
@param streambuf A `Streambuf` holding additional bytes
@param dynabuf A @b `DynamicBuffer` holding additional bytes
read by the implementation from the stream. This is both
an input and an output parameter; on entry, any data in the
stream buffer's input sequence will be given to the parser
@@ -128,14 +127,14 @@ parse(SyncReadStream& stream,
manner equivalent to using `boost::asio::io_service::post`.
*/
template<class AsyncReadStream,
class Streambuf, class Parser, class ReadHandler>
class DynamicBuffer, class Parser, class ReadHandler>
#if GENERATING_DOCS
void_or_deduced
#else
typename async_completion<
ReadHandler, void(error_code)>::result_type
#endif
async_parse(AsyncReadStream& stream, Streambuf& streambuf,
async_parse(AsyncReadStream& stream, DynamicBuffer& dynabuf,
Parser& parser, ReadHandler&& handler);
/** Read a HTTP/1 message from a stream.
@@ -157,7 +156,7 @@ async_parse(AsyncReadStream& stream, Streambuf& streambuf,
@param stream The stream from which the data is to be read.
The type must support the @b `SyncReadStream` concept.
@param streambuf A `Streambuf` holding additional bytes
@param dynabuf A @b `DynamicBuffer` holding additional bytes
read by the implementation from the stream. This is both
an input and an output parameter; on entry, any data in the
stream buffer's input sequence will be given to the parser
@@ -168,10 +167,10 @@ async_parse(AsyncReadStream& stream, Streambuf& streambuf,
@throws boost::system::system_error Thrown on failure.
*/
template<class SyncReadStream, class Streambuf,
template<class SyncReadStream, class DynamicBuffer,
bool isRequest, class Body, class Headers>
void
read(SyncReadStream& stream, Streambuf& streambuf,
read(SyncReadStream& stream, DynamicBuffer& dynabuf,
message_v1<isRequest, Body, Headers>& msg);
/** Read a HTTP/1 message from a stream.
@@ -193,7 +192,7 @@ read(SyncReadStream& stream, Streambuf& streambuf,
@param stream The stream from which the data is to be read.
The type must support the @b `SyncReadStream` concept.
@param streambuf A `Streambuf` holding additional bytes
@param dynabuf A @b `DynamicBuffer` holding additional bytes
read by the implementation from the stream. This is both
an input and an output parameter; on entry, any data in the
stream buffer's input sequence will be given to the parser
@@ -204,10 +203,10 @@ read(SyncReadStream& stream, Streambuf& streambuf,
@param ec Set to the error, if any occurred.
*/
template<class SyncReadStream, class Streambuf,
template<class SyncReadStream, class DynamicBuffer,
bool isRequest, class Body, class Headers>
void
read(SyncReadStream& stream, Streambuf& streambuf,
read(SyncReadStream& stream, DynamicBuffer& dynabuf,
message_v1<isRequest, Body, Headers>& msg,
error_code& ec);
@@ -229,7 +228,7 @@ read(SyncReadStream& stream, Streambuf& streambuf,
@param stream The stream to read the message from.
The type must support the @b `AsyncReadStream` concept.
@param streambuf A `Streambuf` holding additional bytes
@param dynabuf A @b `DynamicBuffer` holding additional bytes
read by the implementation from the stream. This is both
an input and an output parameter; on entry, any data in the
stream buffer's input sequence will be given to the parser
@@ -249,7 +248,7 @@ read(SyncReadStream& stream, Streambuf& streambuf,
this function. Invocation of the handler will be performed in a
manner equivalent to using `boost::asio::io_service::post`.
*/
template<class AsyncReadStream, class Streambuf,
template<class AsyncReadStream, class DynamicBuffer,
bool isRequest, class Body, class Headers,
class ReadHandler>
#if GENERATING_DOCS
@@ -258,7 +257,7 @@ void_or_deduced
typename async_completion<
ReadHandler, void(error_code)>::result_type
#endif
async_read(AsyncReadStream& stream, Streambuf& streambuf,
async_read(AsyncReadStream& stream, DynamicBuffer& dynabuf,
message_v1<isRequest, Body, Headers>& msg,
ReadHandler&& handler);

View File

@@ -1,464 +0,0 @@
//
// Copyright (c) 2013-2016 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)
//
#ifndef BEAST_HTTP_RFC2616_HPP
#define BEAST_HTTP_RFC2616_HPP
#include <boost/range/algorithm/equal.hpp>
#include <boost/range/iterator_range.hpp>
#include <boost/utility/string_ref.hpp>
#include <algorithm>
#include <cctype>
#include <string>
#include <iterator>
#include <tuple> // for std::tie, remove ASAP
#include <utility>
#include <vector>
namespace beast {
#if ! GENERATING_DOCS
/** Routines for performing RFC2616 compliance.
RFC2616:
Hypertext Transfer Protocol -- HTTP/1.1
http://www.w3.org/Protocols/rfc2616/rfc2616
*/
namespace rfc2616 {
namespace detail {
struct ci_equal_pred
{
bool operator()(char c1, char c2)
{
// VFALCO TODO Use a table lookup here
return std::tolower(c1) == std::tolower(c2);
}
};
} // detail
/** Returns `true` if `c` is linear white space.
This excludes the CRLF sequence allowed for line continuations.
*/
inline
bool
is_lws(char c)
{
return c == ' ' || c == '\t';
}
/** Returns `true` if `c` is any whitespace character. */
inline
bool
is_white(char c)
{
switch (c)
{
case ' ': case '\f': case '\n':
case '\r': case '\t': case '\v':
return true;
};
return false;
}
/** Returns `true` if `c` is a control character. */
inline
bool
is_control(char c)
{
return c <= 31 || c >= 127;
}
/** Returns `true` if `c` is a separator. */
inline
bool
is_separator(char c)
{
// VFALCO Could use a static table
switch (c)
{
case '(': case ')': case '<': case '>': case '@':
case ',': case ';': case ':': case '\\': case '"':
case '{': case '}': case ' ': case '\t':
return true;
};
return false;
}
/** Returns `true` if `c` is a character. */
inline
bool
is_char(char c)
{
return c >= 0 && c <= 127;
}
template <class FwdIter>
FwdIter
trim_left (FwdIter first, FwdIter last)
{
return std::find_if_not (first, last,
is_white);
}
template <class FwdIter>
FwdIter
trim_right (FwdIter first, FwdIter last)
{
if (first == last)
return last;
do
{
--last;
if (! is_white (*last))
return ++last;
}
while (last != first);
return first;
}
template <class CharT, class Traits, class Allocator>
void
trim_right_in_place (std::basic_string <
CharT, Traits, Allocator>& s)
{
s.resize (std::distance (s.begin(),
trim_right (s.begin(), s.end())));
}
template <class FwdIter>
std::pair <FwdIter, FwdIter>
trim (FwdIter first, FwdIter last)
{
first = trim_left (first, last);
last = trim_right (first, last);
return std::make_pair (first, last);
}
template <class String>
String
trim (String const& s)
{
using std::begin;
using std::end;
auto first = begin(s);
auto last = end(s);
std::tie (first, last) = trim (first, last);
return { first, last };
}
template <class String>
String
trim_right (String const& s)
{
using std::begin;
using std::end;
auto first (begin(s));
auto last (end(s));
last = trim_right (first, last);
return { first, last };
}
inline
std::string
trim (std::string const& s)
{
return trim <std::string> (s);
}
/** Parse a character sequence of values separated by commas.
Double quotes and escape sequences will be converted. Excess white
space, commas, double quotes, and empty elements are not copied.
Format:
#(token|quoted-string)
Reference:
http://www.w3.org/Protocols/rfc2616/rfc2616-sec2.html#sec2
*/
template <class FwdIt,
class Result = std::vector<
std::basic_string<typename
std::iterator_traits<FwdIt>::value_type>>,
class Char>
Result
split(FwdIt first, FwdIt last, Char delim)
{
Result result;
using string = typename Result::value_type;
FwdIt iter = first;
string e;
while (iter != last)
{
if (*iter == '"')
{
// quoted-string
++iter;
while (iter != last)
{
if (*iter == '"')
{
++iter;
break;
}
if (*iter == '\\')
{
// quoted-pair
++iter;
if (iter != last)
e.append (1, *iter++);
}
else
{
// qdtext
e.append (1, *iter++);
}
}
if (! e.empty())
{
result.emplace_back(std::move(e));
e.clear();
}
}
else if (*iter == delim)
{
e = trim_right (e);
if (! e.empty())
{
result.emplace_back(std::move(e));
e.clear();
}
++iter;
}
else if (is_lws (*iter))
{
++iter;
}
else
{
e.append (1, *iter++);
}
}
if (! e.empty())
{
e = trim_right (e);
if (! e.empty())
result.emplace_back(std::move(e));
}
return result;
}
template <class FwdIt,
class Result = std::vector<
std::basic_string<typename std::iterator_traits<
FwdIt>::value_type>>>
Result
split_commas(FwdIt first, FwdIt last)
{
return split(first, last, ',');
}
template <class Result = std::vector<std::string>>
Result
split_commas(boost::string_ref const& s)
{
return split_commas(s.begin(), s.end());
}
//------------------------------------------------------------------------------
/** Iterates through a comma separated list.
Meets the requirements of ForwardIterator.
List defined in rfc2616 2.1.
@note Values returned may contain backslash escapes.
*/
class list_iterator
{
using iter_type = boost::string_ref::const_iterator;
iter_type it_;
iter_type end_;
boost::string_ref value_;
public:
using value_type = boost::string_ref;
using pointer = value_type const*;
using reference = value_type const&;
using difference_type = std::ptrdiff_t;
using iterator_category =
std::forward_iterator_tag;
list_iterator(iter_type begin, iter_type end)
: it_(begin)
, end_(end)
{
if(it_ != end_)
increment();
}
bool
operator==(list_iterator const& other) const
{
return other.it_ == it_ && other.end_ == end_
&& other.value_.size() == value_.size();
}
bool
operator!=(list_iterator const& other) const
{
return !(*this == other);
}
reference
operator*() const
{
return value_;
}
pointer
operator->() const
{
return &*(*this);
}
list_iterator&
operator++()
{
increment();
return *this;
}
list_iterator
operator++(int)
{
auto temp = *this;
++(*this);
return temp;
}
private:
template<class = void>
void
increment();
};
template<class>
void
list_iterator::increment()
{
value_.clear();
while(it_ != end_)
{
if(*it_ == '"')
{
// quoted-string
++it_;
if(it_ == end_)
return;
if(*it_ != '"')
{
auto start = it_;
for(;;)
{
++it_;
if(it_ == end_)
{
value_ = boost::string_ref(
&*start, std::distance(start, it_));
return;
}
if(*it_ == '"')
{
value_ = boost::string_ref(
&*start, std::distance(start, it_));
++it_;
return;
}
}
}
++it_;
}
else if(*it_ == ',')
{
it_++;
continue;
}
else if(is_lws(*it_))
{
++it_;
continue;
}
else
{
auto start = it_;
for(;;)
{
++it_;
if(it_ == end_ ||
*it_ == ',' ||
is_lws(*it_))
{
value_ = boost::string_ref(
&*start, std::distance(start, it_));
return;
}
}
}
}
}
/** Returns true if two strings are equal.
A case-insensitive comparison is used.
*/
inline
bool
ci_equal(boost::string_ref s1, boost::string_ref s2)
{
return boost::range::equal(s1, s2,
detail::ci_equal_pred{});
}
/** Returns a range representing the list. */
inline
boost::iterator_range<list_iterator>
make_list(boost::string_ref const& field)
{
return boost::iterator_range<list_iterator>{
list_iterator{field.begin(), field.end()},
list_iterator{field.end(), field.end()}};
}
/** Returns true if the specified token exists in the list.
A case-insensitive comparison is used.
*/
template<class = void>
bool
token_in_list(boost::string_ref const& value,
boost::string_ref const& token)
{
for(auto const& item : make_list(value))
if(ci_equal(item, token))
return true;
return false;
}
} // rfc2616
#endif
} // beast
#endif

View File

@@ -8,16 +8,238 @@
#ifndef BEAST_HTTP_RFC7230_HPP
#define BEAST_HTTP_RFC7230_HPP
#include <array>
#include <cstdint>
#include <beast/http/detail/rfc7230.hpp>
namespace beast {
namespace rfc7230 {
namespace http {
/** A list of parameters in a HTTP extension field value.
This container allows iteration of the parameter list
in a HTTP extension. The parameter list is a series
of "name = value" pairs with each pair starting with
a semicolon.
} // rfc7230
BNF:
@code
param-list = *( OWS ";" OWS param )
param = token OWS "=" OWS ( token / quoted-string )
@endcode
If a parsing error is encountered while iterating the string,
the behavior of the container will be as if a string containing
only characters up to but excluding the first invalid character
was used to construct the list.
*/
class param_list
{
boost::string_ref s_;
public:
/** The type of each element in the list.
The first string in the pair is the name of the
parameter, and the second string in the pair is its value.
*/
using value_type =
std::pair<boost::string_ref, boost::string_ref>;
/// A constant iterator to the list
#if GENERATING_DOCS
using const_iterator = implementation_defined;
#else
class const_iterator;
#endif
/// Default constructor.
param_list() = default;
/** Construct a list.
@param s A string containing the list contents. The string
must remain valid for the lifetime of the container.
*/
explicit
param_list(boost::string_ref const& s)
: s_(s)
{
}
/// Return a const iterator to the beginning of the list
const_iterator begin() const;
/// Return a const iterator to the end of the list
const_iterator end() const;
/// Return a const iterator to the beginning of the list
const_iterator cbegin() const;
/// Return a const iterator to the end of the list
const_iterator cend() const;
};
//------------------------------------------------------------------------------
/** A list of extensions in a comma separated HTTP field value.
This container allows iteration of the extensions in a HTTP
field value. The extension list is a comma separated list of
token parameter list pairs.
BNF:
@code
ext-list = *( "," OWS ) ext *( OWS "," [ OWS ext ] )
ext = token param-list
param-list = *( OWS ";" OWS param )
param = token OWS "=" OWS ( token / quoted-string )
@endcode
If a parsing error is encountered while iterating the string,
the behavior of the container will be as if a string containing
only characters up to but excluding the first invalid character
was used to construct the list.
*/
class ext_list
{
using iter_type = boost::string_ref::const_iterator;
boost::string_ref s_;
public:
/** The type of each element in the list.
The first element of the pair is the extension token, and the
second element of the pair is an iterable container holding the
extension's name/value parameters.
*/
using value_type = std::pair<boost::string_ref, param_list>;
/// A constant iterator to the list
#if GENERATING_DOCS
using const_iterator = implementation_defined;
#else
class const_iterator;
#endif
/** Construct a list.
@param s A string containing the list contents. The string
must remain valid for the lifetime of the container.
*/
explicit
ext_list(boost::string_ref const& s)
: s_(s)
{
}
/// Return a const iterator to the beginning of the list
const_iterator begin() const;
/// Return a const iterator to the end of the list
const_iterator end() const;
/// Return a const iterator to the beginning of the list
const_iterator cbegin() const;
/// Return a const iterator to the end of the list
const_iterator cend() const;
/** Find a token in the list.
@param s The token to find. A case-insensitive comparison is used.
@return An iterator to the matching token, or `end()` if no
token exists.
*/
template<class T>
const_iterator
find(T const& s);
/** Return `true` if a token is present in the list.
@param s The token to find. A case-insensitive comparison is used.
*/
template<class T>
bool
exists(T const& s);
};
//------------------------------------------------------------------------------
/** A list of tokens in a comma separated HTTP field value.
This container allows iteration of the extensions in a HTTP
field value. The extension list is a comma separated list of
token parameter list pairs.
BNF:
@code
token-list = *( "," OWS ) token *( OWS "," [ OWS ext ] )
@endcode
If a parsing error is encountered while iterating the string,
the behavior of the container will be as if a string containing
only characters up to but excluding the first invalid character
was used to construct the list.
*/
class token_list
{
using iter_type = boost::string_ref::const_iterator;
boost::string_ref s_;
public:
/** The type of each element in the token list.
The first element of the pair is the extension token, and the
second element of the pair is an iterable container holding the
extension's name/value parameters.
*/
using value_type = boost::string_ref;
/// A constant iterator to the list
#if GENERATING_DOCS
using const_iterator = implementation_defined;
#else
class const_iterator;
#endif
/** Construct a list.
@param s A string containing the list contents. The string
must remain valid for the lifetime of the container.
*/
explicit
token_list(boost::string_ref const& s)
: s_(s)
{
}
/// Return a const iterator to the beginning of the list
const_iterator begin() const;
/// Return a const iterator to the end of the list
const_iterator end() const;
/// Return a const iterator to the beginning of the list
const_iterator cbegin() const;
/// Return a const iterator to the end of the list
const_iterator cend() const;
/** Return `true` if a token is present in the list.
@param s The token to find. A case-insensitive comparison is used.
*/
template<class T>
bool
exists(T const& s);
};
} // http
} // beast
#include <beast/http/impl/rfc7230.ipp>
#endif

View File

@@ -8,91 +8,17 @@
#ifndef BEAST_HTTP_STREAMBUF_BODY_HPP
#define BEAST_HTTP_STREAMBUF_BODY_HPP
#include <beast/http/body_type.hpp>
#include <beast/core/buffer_cat.hpp>
#include <beast/http/basic_dynabuf_body.hpp>
#include <beast/core/streambuf.hpp>
#include <memory>
#include <string>
namespace beast {
namespace http {
/** A message body represented by a Streambuf
/** A message body represented by a @ref streambuf
Meets the requirements of @b `Body`.
*/
template<class Streambuf>
struct basic_streambuf_body
{
/// The type of the `message::body` member
using value_type = Streambuf;
#if GENERATING_DOCS
private:
#endif
class reader
{
value_type& sb_;
public:
template<bool isRequest, class Headers>
explicit
reader(message<isRequest,
basic_streambuf_body, Headers>& m) noexcept
: sb_(m.body)
{
}
void
write(void const* data,
std::size_t size, error_code&) noexcept
{
using boost::asio::buffer;
using boost::asio::buffer_copy;
sb_.commit(buffer_copy(
sb_.prepare(size), buffer(data, size)));
}
};
class writer
{
Streambuf const& body_;
public:
writer(writer const&) = delete;
writer& operator=(writer const&) = delete;
template<bool isRequest, class Headers>
explicit
writer(message<
isRequest, basic_streambuf_body, Headers> const& m)
: body_(m.body)
{
}
void
init(error_code& ec)
{
}
std::uint64_t
content_length() const
{
return body_.size();
}
template<class Write>
boost::tribool
operator()(resume_context&&, error_code&, Write&& write)
{
write(body_.data());
return true;
}
};
};
using streambuf_body = basic_streambuf_body<streambuf>;
using streambuf_body = basic_dynabuf_body<streambuf>;
} // http
} // beast

View File

@@ -9,8 +9,7 @@
#define BEAST_HTTP_STRING_BODY_HPP
#include <beast/http/body_type.hpp>
#include <beast/core/buffer_cat.hpp>
#include <beast/core/streambuf.hpp>
#include <boost/asio/buffer.hpp>
#include <memory>
#include <string>

View File

@@ -14,8 +14,8 @@
// BEAST_VERSION / 100 % 1000 is the minor version
// BEAST_VERSION / 100000 is the major version
//
#define BEAST_VERSION 100000
#define BEAST_VERSION 100006
#define BEAST_VERSION_STRING "1.0.0-b5"
#define BEAST_VERSION_STRING "1.0.0-b6"
#endif

View File

@@ -117,11 +117,11 @@ is_valid(close_code::value code)
//------------------------------------------------------------------------------
// Write frame header to streambuf
// Write frame header to dynamic buffer
//
template<class Streambuf>
template<class DynamicBuffer>
void
write(Streambuf& sb, frame_header const& fh)
write(DynamicBuffer& db, frame_header const& fh)
{
using boost::asio::buffer;
using boost::asio::buffer_copy;
@@ -159,24 +159,24 @@ write(Streambuf& sb, frame_header const& fh)
native_to_little_uint32(fh.key, &b[n]);
n += 4;
}
sb.commit(buffer_copy(
sb.prepare(n), buffer(b)));
db.commit(buffer_copy(
db.prepare(n), buffer(b)));
}
// Read fixed frame header
// Requires at least 2 bytes
//
template<class Streambuf>
template<class DynamicBuffer>
std::size_t
read_fh1(frame_header& fh, Streambuf& sb,
read_fh1(frame_header& fh, DynamicBuffer& db,
role_type role, close_code::value& code)
{
using boost::asio::buffer;
using boost::asio::buffer_copy;
using boost::asio::buffer_size;
std::uint8_t b[2];
assert(buffer_size(sb.data()) >= sizeof(b));
sb.consume(buffer_copy(buffer(b), sb.data()));
assert(buffer_size(db.data()) >= sizeof(b));
db.consume(buffer_copy(buffer(b), db.data()));
std::size_t need;
fh.len = b[1] & 0x7f;
switch(fh.len)
@@ -236,9 +236,9 @@ read_fh1(frame_header& fh, Streambuf& sb,
// Decode variable frame header from stream
//
template<class Streambuf>
template<class DynamicBuffer>
void
read_fh2(frame_header& fh, Streambuf& sb,
read_fh2(frame_header& fh, DynamicBuffer& db,
role_type role, close_code::value& code)
{
using boost::asio::buffer;
@@ -250,8 +250,8 @@ read_fh2(frame_header& fh, Streambuf& sb,
case 126:
{
std::uint8_t b[2];
assert(buffer_size(sb.data()) >= sizeof(b));
sb.consume(buffer_copy(buffer(b), sb.data()));
assert(buffer_size(db.data()) >= sizeof(b));
db.consume(buffer_copy(buffer(b), db.data()));
fh.len = big_uint16_to_native(&b[0]);
// length not canonical
if(fh.len < 126)
@@ -264,8 +264,8 @@ read_fh2(frame_header& fh, Streambuf& sb,
case 127:
{
std::uint8_t b[8];
assert(buffer_size(sb.data()) >= sizeof(b));
sb.consume(buffer_copy(buffer(b), sb.data()));
assert(buffer_size(db.data()) >= sizeof(b));
db.consume(buffer_copy(buffer(b), db.data()));
fh.len = big_uint64_to_native(&b[0]);
// length not canonical
if(fh.len < 65536)
@@ -279,8 +279,8 @@ read_fh2(frame_header& fh, Streambuf& sb,
if(fh.mask)
{
std::uint8_t b[4];
assert(buffer_size(sb.data()) >= sizeof(b));
sb.consume(buffer_copy(buffer(b), sb.data()));
assert(buffer_size(db.data()) >= sizeof(b));
db.consume(buffer_copy(buffer(b), db.data()));
fh.key = little_uint32_to_native(&b[0]);
}
else

View File

@@ -18,7 +18,6 @@
#include <beast/http/empty_body.hpp>
#include <beast/http/message.hpp>
#include <beast/http/string_body.hpp>
#include <beast/core/streambuf.hpp>
#include <boost/asio/error.hpp>
#include <cassert>
#include <cstdint>
@@ -107,15 +106,13 @@ protected:
void
prepare_fh(close_code::value& code);
template<class Streambuf>
template<class DynamicBuffer>
void
write_close(Streambuf& sb,
close_reason const& rc);
write_close(DynamicBuffer& db, close_reason const& rc);
template<class Streambuf>
template<class DynamicBuffer>
void
write_ping(Streambuf& sb, opcode op,
ping_data const& data);
write_ping(DynamicBuffer& db, opcode op, ping_data const& data);
};
} // detail

View File

@@ -23,7 +23,7 @@ namespace websocket {
// processes any received control frames.
//
template<class NextLayer>
template<class Streambuf, class Handler>
template<class DynamicBuffer, class Handler>
class stream<NextLayer>::read_frame_op
{
using alloc_type =
@@ -35,27 +35,27 @@ class stream<NextLayer>::read_frame_op
using fmb_type =
typename fb_type::mutable_buffers_type;
using smb_type =
typename Streambuf::mutable_buffers_type;
using dmb_type =
typename DynamicBuffer::mutable_buffers_type;
struct data : op
{
stream<NextLayer>& ws;
frame_info& fi;
Streambuf& sb;
DynamicBuffer& db;
Handler h;
fb_type fb;
boost::optional<smb_type> smb;
boost::optional<dmb_type> dmb;
boost::optional<fmb_type> fmb;
bool cont;
int state = 0;
template<class DeducedHandler>
data(DeducedHandler&& h_, stream<NextLayer>& ws_,
frame_info& fi_, Streambuf& sb_)
frame_info& fi_, DynamicBuffer& sb_)
: ws(ws_)
, fi(fi_)
, sb(sb_)
, db(sb_)
, h(std::forward<DeducedHandler>(h_))
, cont(boost_asio_handler_cont_helpers::
is_continuation(h))
@@ -127,9 +127,9 @@ public:
};
template<class NextLayer>
template<class Buffers, class Handler>
template<class DynamicBuffer, class Handler>
void
stream<NextLayer>::read_frame_op<Buffers, Handler>::
stream<NextLayer>::read_frame_op<DynamicBuffer, Handler>::
operator()(error_code ec, std::size_t bytes_transferred)
{
auto& d = *d_;
@@ -139,9 +139,9 @@ operator()(error_code ec, std::size_t bytes_transferred)
}
template<class NextLayer>
template<class Buffers, class Handler>
template<class DynamicBuffer, class Handler>
void
stream<NextLayer>::read_frame_op<Buffers, Handler>::
stream<NextLayer>::read_frame_op<DynamicBuffer, Handler>::
operator()(error_code ec,std::size_t bytes_transferred, bool again)
{
enum
@@ -187,18 +187,18 @@ operator()(error_code ec,std::size_t bytes_transferred, bool again)
case do_read_payload:
d.state = do_read_payload + 1;
d.smb = d.sb.prepare(
d.dmb = d.db.prepare(
detail::clamp(d.ws.rd_need_));
// receive payload data
d.ws.stream_.async_read_some(
*d.smb, std::move(*this));
*d.dmb, std::move(*this));
return;
case do_read_payload + 1:
{
d.ws.rd_need_ -= bytes_transferred;
auto const pb = prepare_buffers(
bytes_transferred, *d.smb);
bytes_transferred, *d.dmb);
if(d.ws.rd_fh_.mask)
detail::mask_inplace(pb, d.ws.rd_key_);
if(d.ws.rd_opcode_ == opcode::text)
@@ -213,7 +213,7 @@ operator()(error_code ec,std::size_t bytes_transferred, bool again)
break;
}
}
d.sb.commit(bytes_transferred);
d.db.commit(bytes_transferred);
if(d.ws.rd_need_ > 0)
{
d.state = do_read_payload;

View File

@@ -17,7 +17,7 @@ namespace websocket {
// read an entire message
//
template<class NextLayer>
template<class Streambuf, class Handler>
template<class DynamicBuffer, class Handler>
class stream<NextLayer>::read_op
{
using alloc_type =
@@ -27,7 +27,7 @@ class stream<NextLayer>::read_op
{
stream<NextLayer>& ws;
opcode& op;
Streambuf& sb;
DynamicBuffer& db;
Handler h;
frame_info fi;
bool cont;
@@ -36,10 +36,10 @@ class stream<NextLayer>::read_op
template<class DeducedHandler>
data(DeducedHandler&& h_,
stream<NextLayer>& ws_, opcode& op_,
Streambuf& sb_)
DynamicBuffer& sb_)
: ws(ws_)
, op(op_)
, sb(sb_)
, db(sb_)
, h(std::forward<DeducedHandler>(h_))
, cont(boost_asio_handler_cont_helpers::
is_continuation(h))
@@ -98,9 +98,9 @@ public:
};
template<class NextLayer>
template<class Streambuf, class Handler>
template<class DynamicBuffer, class Handler>
void
stream<NextLayer>::read_op<Streambuf, Handler>::
stream<NextLayer>::read_op<DynamicBuffer, Handler>::
operator()(error_code const& ec, bool again)
{
auto& d = *d_;
@@ -117,9 +117,9 @@ operator()(error_code const& ec, bool again)
// the handler is moved from the data block
// before asio_handler_deallocate is called.
d.ws.async_read_frame(
d.fi, d.sb, std::move(*this));
d.fi, d.db, std::move(*this));
#else
d.ws.async_read_frame(d.fi, d.sb, *this);
d.ws.async_read_frame(d.fi, d.db, *this);
#endif
return;

View File

@@ -22,14 +22,13 @@
#include <beast/http/read.hpp>
#include <beast/http/write.hpp>
#include <beast/http/reason.hpp>
#include <beast/http/rfc2616.hpp>
#include <beast/http/rfc7230.hpp>
#include <beast/core/buffer_cat.hpp>
#include <beast/core/buffer_concepts.hpp>
#include <beast/core/consuming_buffers.hpp>
#include <beast/core/prepare_buffers.hpp>
#include <beast/core/static_streambuf.hpp>
#include <beast/core/stream_concepts.hpp>
#include <beast/core/streambuf.hpp>
#include <boost/endian/buffers.hpp>
#include <algorithm>
#include <cassert>
@@ -94,10 +93,10 @@ stream_base::prepare_fh(close_code::value& code)
}
}
template<class Streambuf>
template<class DynamicBuffer>
void
stream_base::write_close(
Streambuf& sb, close_reason const& cr)
DynamicBuffer& db, close_reason const& cr)
{
using namespace boost::endian;
frame_header fh;
@@ -111,7 +110,7 @@ stream_base::write_close(
fh.mask = role_ == detail::role_type::client;
if(fh.mask)
fh.key = maskgen_();
detail::write(sb, fh);
detail::write(db, fh);
if(cr.code != close_code::none)
{
detail::prepared_key_type key;
@@ -121,29 +120,29 @@ stream_base::write_close(
std::uint8_t b[2];
::new(&b[0]) big_uint16_buf_t{
(std::uint16_t)cr.code};
auto d = sb.prepare(2);
auto d = db.prepare(2);
boost::asio::buffer_copy(d,
boost::asio::buffer(b));
if(fh.mask)
detail::mask_inplace(d, key);
sb.commit(2);
db.commit(2);
}
if(! cr.reason.empty())
{
auto d = sb.prepare(cr.reason.size());
auto d = db.prepare(cr.reason.size());
boost::asio::buffer_copy(d,
boost::asio::const_buffer(
cr.reason.data(), cr.reason.size()));
if(fh.mask)
detail::mask_inplace(d, key);
sb.commit(cr.reason.size());
db.commit(cr.reason.size());
}
}
}
template<class Streambuf>
template<class DynamicBuffer>
void
stream_base::write_ping(Streambuf& sb,
stream_base::write_ping(DynamicBuffer& db,
opcode op, ping_data const& data)
{
frame_header fh;
@@ -156,19 +155,19 @@ stream_base::write_ping(Streambuf& sb,
fh.mask = role_ == role_type::client;
if(fh.mask)
fh.key = maskgen_();
detail::write(sb, fh);
detail::write(db, fh);
if(data.empty())
return;
detail::prepared_key_type key;
if(fh.mask)
detail::prepare_key(key, fh.key);
auto d = sb.prepare(data.size());
auto d = db.prepare(data.size());
boost::asio::buffer_copy(d,
boost::asio::const_buffers_1(
data.data(), data.size()));
if(fh.mask)
detail::mask_inplace(d, key);
sb.commit(data.size());
db.commit(data.size());
}
} // detail
@@ -453,10 +452,10 @@ void
stream<NextLayer>::
ping(ping_data const& payload, error_code& ec)
{
detail::frame_streambuf sb;
detail::frame_streambuf db;
write_ping<static_streambuf>(
sb, opcode::ping, payload);
boost::asio::write(stream_, sb.data(), ec);
db, opcode::ping, payload);
boost::asio::write(stream_, db.data(), ec);
}
template<class NextLayer>
@@ -477,31 +476,35 @@ async_ping(ping_data const& payload, PingHandler&& handler)
}
template<class NextLayer>
template<class Streambuf>
template<class DynamicBuffer>
void
stream<NextLayer>::
read(opcode& op, Streambuf& streambuf)
read(opcode& op, DynamicBuffer& dynabuf)
{
static_assert(is_SyncStream<next_layer_type>::value,
"SyncStream requirements not met");
static_assert(beast::is_DynamicBuffer<DynamicBuffer>::value,
"DynamicBuffer requirements not met");
error_code ec;
read(op, streambuf, ec);
read(op, dynabuf, ec);
if(ec)
throw system_error{ec};
}
template<class NextLayer>
template<class Streambuf>
template<class DynamicBuffer>
void
stream<NextLayer>::
read(opcode& op, Streambuf& streambuf, error_code& ec)
read(opcode& op, DynamicBuffer& dynabuf, error_code& ec)
{
static_assert(is_SyncStream<next_layer_type>::value,
"SyncStream requirements not met");
static_assert(beast::is_DynamicBuffer<DynamicBuffer>::value,
"DynamicBuffer requirements not met");
frame_info fi;
for(;;)
{
read_frame(fi, streambuf, ec);
read_frame(fi, dynabuf, ec);
if(ec)
break;
op = fi.op;
@@ -511,47 +514,51 @@ read(opcode& op, Streambuf& streambuf, error_code& ec)
}
template<class NextLayer>
template<class Streambuf, class ReadHandler>
template<class DynamicBuffer, class ReadHandler>
typename async_completion<
ReadHandler, void(error_code)>::result_type
stream<NextLayer>::
async_read(opcode& op,
Streambuf& streambuf, ReadHandler&& handler)
DynamicBuffer& dynabuf, ReadHandler&& handler)
{
static_assert(is_AsyncStream<next_layer_type>::value,
"AsyncStream requirements requirements not met");
static_assert(beast::is_Streambuf<Streambuf>::value,
"Streambuf requirements not met");
static_assert(beast::is_DynamicBuffer<DynamicBuffer>::value,
"DynamicBuffer requirements not met");
beast::async_completion<
ReadHandler, void(error_code)
> completion(handler);
read_op<Streambuf, decltype(completion.handler)>{
completion.handler, *this, op, streambuf};
read_op<DynamicBuffer, decltype(completion.handler)>{
completion.handler, *this, op, dynabuf};
return completion.result.get();
}
template<class NextLayer>
template<class Streambuf>
template<class DynamicBuffer>
void
stream<NextLayer>::
read_frame(frame_info& fi, Streambuf& streambuf)
read_frame(frame_info& fi, DynamicBuffer& dynabuf)
{
static_assert(is_SyncStream<next_layer_type>::value,
"SyncStream requirements not met");
static_assert(beast::is_DynamicBuffer<DynamicBuffer>::value,
"DynamicBuffer requirements not met");
error_code ec;
read_frame(fi, streambuf, ec);
read_frame(fi, dynabuf, ec);
if(ec)
throw system_error{ec};
}
template<class NextLayer>
template<class Streambuf>
template<class DynamicBuffer>
void
stream<NextLayer>::
read_frame(frame_info& fi, Streambuf& streambuf, error_code& ec)
read_frame(frame_info& fi, DynamicBuffer& dynabuf, error_code& ec)
{
static_assert(is_SyncStream<next_layer_type>::value,
"SyncStream requirements not met");
static_assert(beast::is_DynamicBuffer<DynamicBuffer>::value,
"DynamicBuffer requirements not met");
close_code::value code{};
for(;;)
{
@@ -630,7 +637,7 @@ read_frame(frame_info& fi, Streambuf& streambuf, error_code& ec)
}
}
// read payload
auto smb = streambuf.prepare(
auto smb = dynabuf.prepare(
detail::clamp(rd_need_));
auto const bytes_transferred =
stream_.read_some(smb, ec);
@@ -652,7 +659,7 @@ read_frame(frame_info& fi, Streambuf& streambuf, error_code& ec)
break;
}
}
streambuf.commit(bytes_transferred);
dynabuf.commit(bytes_transferred);
fi.op = rd_opcode_;
fi.fin = rd_fh_.fin && rd_need_ == 0;
return;
@@ -686,21 +693,21 @@ read_frame(frame_info& fi, Streambuf& streambuf, error_code& ec)
}
template<class NextLayer>
template<class Streambuf, class ReadHandler>
template<class DynamicBuffer, class ReadHandler>
typename async_completion<
ReadHandler, void(error_code)>::result_type
stream<NextLayer>::
async_read_frame(frame_info& fi,
Streambuf& streambuf, ReadHandler&& handler)
DynamicBuffer& dynabuf, ReadHandler&& handler)
{
static_assert(is_AsyncStream<next_layer_type>::value,
"AsyncStream requirements requirements not met");
static_assert(beast::is_Streambuf<Streambuf>::value,
"Streambuf requirements not met");
static_assert(beast::is_DynamicBuffer<DynamicBuffer>::value,
"DynamicBuffer requirements not met");
beast::async_completion<
ReadHandler, void(error_code)> completion(handler);
read_frame_op<Streambuf, decltype(completion.handler)>{
completion.handler, *this, fi, streambuf};
read_frame_op<DynamicBuffer, decltype(completion.handler)>{
completion.handler, *this, fi, dynabuf};
return completion.result.get();
}
@@ -712,6 +719,9 @@ write(ConstBufferSequence const& buffers)
{
static_assert(is_SyncStream<next_layer_type>::value,
"SyncStream requirements not met");
static_assert(beast::is_ConstBufferSequence<
ConstBufferSequence>::value,
"ConstBufferSequence requirements not met");
error_code ec;
write(buffers, ec);
if(ec)
@@ -774,6 +784,9 @@ write_frame(bool fin, ConstBufferSequence const& buffers)
{
static_assert(is_SyncStream<next_layer_type>::value,
"SyncStream requirements not met");
static_assert(beast::is_ConstBufferSequence<
ConstBufferSequence>::value,
"ConstBufferSequence requirements not met");
error_code ec;
write_frame(fin, buffers, ec);
if(ec)
@@ -951,8 +964,7 @@ build_response(http::request_v1<Body, Headers> const& req)
return err("Missing Host");
if(! req.headers.exists("Sec-WebSocket-Key"))
return err("Missing Sec-WebSocket-Key");
if(! rfc2616::token_in_list(
req.headers["Upgrade"], "websocket"))
if(! http::token_list{req.headers["Upgrade"]}.exists("websocket"))
return err("Missing websocket Upgrade token");
{
auto const version =
@@ -1005,8 +1017,7 @@ do_response(http::response_v1<Body, Headers> const& res,
return fail();
if(! is_upgrade(res))
return fail();
if(! rfc2616::ci_equal(
res.headers["Upgrade"], "websocket"))
if(! http::token_list{res.headers["Upgrade"]}.exists("websocket"))
return fail();
if(! res.headers.exists("Sec-WebSocket-Accept"))
return fail();

View File

@@ -120,7 +120,7 @@ decorate(Decorator&& d)
This setting only affects the behavior of HTTP requests that
implicitly or explicitly ask for a keepalive. For HTTP requests
that indicate the connection should be closed, the connection is
closed as per rfc2616.
closed as per rfc7230.
The default setting is to close connections after a failed
upgrade request.

View File

@@ -12,7 +12,7 @@
#include <beast/websocket/detail/stream_base.hpp>
#include <beast/http/message_v1.hpp>
#include <beast/http/string_body.hpp>
#include <beast/core/streambuf_readstream.hpp>
#include <beast/core/dynabuf_readstream.hpp>
#include <beast/core/async_completion.hpp>
#include <beast/core/detail/get_lowest_layer.hpp>
#include <boost/asio.hpp>
@@ -78,7 +78,7 @@ struct frame_info
@par Concepts
@b `AsyncStream`,
@b `Decorator`,
@b `Streambuf`,
@b `DynamicBuffer`,
@b `SyncStream`
*/
template<class NextLayer>
@@ -86,7 +86,7 @@ class stream : public detail::stream_base
{
friend class stream_test;
streambuf_readstream<NextLayer, streambuf> stream_;
dynabuf_readstream<NextLayer, streambuf> stream_;
public:
/// The type of the next layer.
@@ -95,12 +95,12 @@ public:
/// The type of the lowest layer.
using lowest_layer_type =
#if GENERATING_DOCS
#if GENERATING_DOCS
implementation_defined;
#else
#else
typename beast::detail::get_lowest_layer<
next_layer_type>::type;
#endif
#endif
/** Move-construct a stream.
@@ -404,12 +404,12 @@ public:
manner equivalent to using `boost::asio::io_service::post`.
*/
template<class AcceptHandler>
#if GENERATING_DOCS
#if GENERATING_DOCS
void_or_deduced
#else
#else
typename async_completion<
AcceptHandler, void(error_code)>::result_type
#endif
#endif
async_accept(AcceptHandler&& handler);
/** Read and respond to a WebSocket HTTP Upgrade request.
@@ -530,12 +530,12 @@ public:
manner equivalent to using `boost::asio::io_service::post`.
*/
template<class ConstBufferSequence, class AcceptHandler>
#if GENERATING_DOCS
#if GENERATING_DOCS
void_or_deduced
#else
#else
typename async_completion<
AcceptHandler, void(error_code)>::result_type
#endif
#endif
async_accept(ConstBufferSequence const& buffers,
AcceptHandler&& handler);
@@ -567,7 +567,7 @@ public:
@throws boost::system::system_error Thrown on failure.
*/
// VFALCO TODO This should also take a streambuf with any leftover bytes.
// VFALCO TODO This should also take a DynamicBuffer with any leftover bytes.
template<class Body, class Headers>
void
accept(http::request_v1<Body, Headers> const& request);
@@ -647,12 +647,12 @@ public:
manner equivalent to using `boost::asio::io_service::post`.
*/
template<class Body, class Headers, class AcceptHandler>
#if GENERATING_DOCS
#if GENERATING_DOCS
void_or_deduced
#else
#else
typename async_completion<
AcceptHandler, void(error_code)>::result_type
#endif
#endif
async_accept(http::request_v1<Body, Headers> const& request,
AcceptHandler&& handler);
@@ -784,12 +784,12 @@ public:
manner equivalent to using `boost::asio::io_service::post`.
*/
template<class HandshakeHandler>
#if GENERATING_DOCS
#if GENERATING_DOCS
void_or_deduced
#else
#else
typename async_completion<
HandshakeHandler, void(error_code)>::result_type
#endif
#endif
async_handshake(boost::string_ref const& host,
boost::string_ref const& resource, HandshakeHandler&& h);
@@ -895,12 +895,12 @@ public:
manner equivalent to using `boost::asio::io_service::post`.
*/
template<class CloseHandler>
#if GENERATING_DOCS
#if GENERATING_DOCS
void_or_deduced
#else
#else
typename async_completion<
CloseHandler, void(error_code)>::result_type
#endif
#endif
async_close(close_reason const& cr, CloseHandler&& handler);
/** Send a WebSocket ping frame.
@@ -973,12 +973,12 @@ public:
manner equivalent to using `boost::asio::io_service::post`.
*/
template<class PingHandler>
#if GENERATING_DOCS
#if GENERATING_DOCS
void_or_deduced
#else
#else
typename async_completion<
PingHandler, void(error_code)>::result_type
#endif
#endif
async_ping(ping_data const& payload, PingHandler&& handler);
/** Read a message from the stream.
@@ -1007,14 +1007,14 @@ public:
@param op A value to receive the message type.
This object must remain valid until the handler is called.
@param streambuf A stream buffer to hold the message data.
This object must remain valid until the handler is called.
@param dynabuf A dynamic buffer to hold the message data after
any masking or decompression has been applied.
@throws boost::system::system_error Thrown on failure.
*/
template<class Streambuf>
template<class DynamicBuffer>
void
read(opcode& op, Streambuf& streambuf);
read(opcode& op, DynamicBuffer& dynabuf);
/** Read a message from the stream.
@@ -1042,15 +1042,14 @@ public:
@param op A value to receive the message type.
This object must remain valid until the handler is called.
@param streambuf A stream buffer to hold the message data.
This object must remain valid until the handler is called.
@param dynabuf A dynamic buffer to hold the message data after
any masking or decompression has been applied.
@param ec Set to indicate what error occurred, if any.
*/
template<class Streambuf>
template<class DynamicBuffer>
void
read(opcode& op,
Streambuf& streambuf, error_code& ec);
read(opcode& op, DynamicBuffer& dynabuf, error_code& ec);
/** Start an asynchronous operation to read a message from the stream.
@@ -1086,8 +1085,9 @@ public:
@param op A value to receive the message type.
This object must remain valid until the handler is called.
@param streambuf A stream buffer to hold the message data.
This object must remain valid until the handler is called.
@param dynabuf A dynamic buffer to hold the message data after
any masking or decompression has been applied. This object must
remain valid until the handler is called.
@param handler The handler to be called when the read operation
completes. Copies will be made of the handler as required. The
@@ -1102,15 +1102,14 @@ public:
this function. Invocation of the handler will be performed in a
manner equivalent to using `boost::asio::io_service::post`.
*/
template<class Streambuf, class ReadHandler>
#if GENERATING_DOCS
template<class DynamicBuffer, class ReadHandler>
#if GENERATING_DOCS
void_or_deduced
#else
#else
typename async_completion<
ReadHandler, void(error_code)>::result_type
#endif
async_read(opcode& op,
Streambuf& streambuf, ReadHandler&& handler);
#endif
async_read(opcode& op, DynamicBuffer& dynabuf, ReadHandler&& handler);
/** Read a message frame from the stream.
@@ -1141,13 +1140,14 @@ public:
@param fi An object to store metadata about the message.
@param streambuf A stream buffer to hold the message data.
@param dynabuf A dynamic buffer to hold the message data after
any masking or decompression has been applied.
@throws boost::system::system_error Thrown on failure.
*/
template<class Streambuf>
template<class DynamicBuffer>
void
read_frame(frame_info& fi, Streambuf& streambuf);
read_frame(frame_info& fi, DynamicBuffer& dynabuf);
/** Read a message frame from the stream.
@@ -1178,13 +1178,14 @@ public:
@param fi An object to store metadata about the message.
@param streambuf A stream buffer to hold the message data.
@param dynabuf A dynamic buffer to hold the message data after
any masking or decompression has been applied.
@param ec Set to indicate what error occurred, if any.
*/
template<class Streambuf>
template<class DynamicBuffer>
void
read_frame(frame_info& fi, Streambuf& streambuf, error_code& ec);
read_frame(frame_info& fi, DynamicBuffer& dynabuf, error_code& ec);
/** Start an asynchronous operation to read a message frame from the stream.
@@ -1225,7 +1226,7 @@ public:
@param fi An object to store metadata about the message.
This object must remain valid until the handler is called.
@param streambuf A stream buffer to hold the message data after
@param dynabuf A dynamic buffer to hold the message data after
any masking or decompression has been applied. This object must
remain valid until the handler is called.
@@ -1242,15 +1243,15 @@ public:
this function. Invocation of the handler will be performed in a
manner equivalent to using boost::asio::io_service::post().
*/
template<class Streambuf, class ReadHandler>
#if GENERATING_DOCS
template<class DynamicBuffer, class ReadHandler>
#if GENERATING_DOCS
void_or_deduced
#else
#else
typename async_completion<
ReadHandler, void(error_code)>::result_type
#endif
#endif
async_read_frame(frame_info& fi,
Streambuf& streambuf, ReadHandler&& handler);
DynamicBuffer& dynabuf, ReadHandler&& handler);
/** Write a message to the stream.
@@ -1369,12 +1370,12 @@ public:
manner equivalent to using `boost::asio::io_service::post`.
*/
template<class ConstBufferSequence, class WriteHandler>
#if GENERATING_DOCS
#if GENERATING_DOCS
void_or_deduced
#else
#else
typename async_completion<
WriteHandler, void(error_code)>::result_type
#endif
#endif
async_write(ConstBufferSequence const& buffers,
WriteHandler&& handler);
@@ -1478,12 +1479,12 @@ public:
); @endcode
*/
template<class ConstBufferSequence, class WriteHandler>
#if GENERATING_DOCS
#if GENERATING_DOCS
void_or_deduced
#else
#else
typename async_completion<
WriteHandler, void(error_code)>::result_type
#endif
#endif
async_write_frame(bool fin,
ConstBufferSequence const& buffers, WriteHandler&& handler);
@@ -1495,8 +1496,8 @@ private:
template<class Handler> class response_op;
template<class Buffers, class Handler> class write_op;
template<class Buffers, class Handler> class write_frame_op;
template<class Streambuf, class Handler> class read_op;
template<class Streambuf, class Handler> class read_frame_op;
template<class DynamicBuffer, class Handler> class read_op;
template<class DynamicBuffer, class Handler> class read_frame_op;
void
reset();