mirror of
https://github.com/XRPLF/rippled.git
synced 2025-12-06 17:27:55 +00:00
Merge subtree Beast 1.0.0-b6:
Merge commit '999e2fa0318b5982736d3ea01a418770ea802671'
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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>&
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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) ->
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
@@ -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>
|
||||
|
||||
95
src/beast/include/beast/http/basic_dynabuf_body.hpp
Normal file
95
src/beast/include/beast/http/basic_dynabuf_body.hpp
Normal 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
|
||||
@@ -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,
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
384
src/beast/include/beast/http/detail/rfc7230.hpp
Normal file
384
src/beast/include/beast/http/detail/rfc7230.hpp
Normal 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
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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
@@ -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");
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
548
src/beast/include/beast/http/impl/rfc7230.ipp
Normal file
548
src/beast/include/beast/http/impl/rfc7230.ipp
Normal 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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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";
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user