forked from boostorg/beast
Fields concept work
This commit is contained in:
@@ -7,6 +7,7 @@ Version 50
|
||||
* Use field in basic_fields and call sites
|
||||
* Use field in basic_parser
|
||||
* Tidy up basic_fields, header, and field concepts
|
||||
* Fields concept work
|
||||
|
||||
API Changes:
|
||||
|
||||
|
@@ -52,7 +52,8 @@
|
||||
[def __BodyReader__ [link beast.concept.BodyReader [*BodyReader]]]
|
||||
[def __BodyWriter__ [link beast.concept.BodyWriter [*BodyWriter]]]
|
||||
[def __DynamicBuffer__ [link beast.concept.DynamicBuffer [*DynamicBuffer]]]
|
||||
[def __FieldSequence__ [link beast.concept.FieldSequence [*FieldSequence]]]
|
||||
[def __Fields__ [link beast.concept.Fields [*Fields]]]
|
||||
[def __FieldsReader__ [link beast.concept.FieldsReader [*FieldsReader]]]
|
||||
[def __Stream__ [link beast.concept.streams [*Stream]]]
|
||||
[def __SyncStream__ [link beast.concept.streams.SyncStream [*SyncStream]]]
|
||||
|
||||
|
@@ -15,7 +15,8 @@
|
||||
[include concept/BufferSequence.qbk]
|
||||
[include concept/DynamicBuffer.qbk]
|
||||
[include concept/Field.qbk]
|
||||
[include concept/FieldSequence.qbk]
|
||||
[include concept/Fields.qbk]
|
||||
[include concept/FieldsReader.qbk]
|
||||
[include concept/Streams.qbk]
|
||||
|
||||
[endsect]
|
||||
|
@@ -19,7 +19,7 @@ In this table:
|
||||
[[expression][type][semantics, pre/post-conditions]]
|
||||
[
|
||||
[`a.name()`]
|
||||
[`boost::string_ref`]
|
||||
[[link beast.ref.string_view `string_view`]]
|
||||
[
|
||||
This function returns a value implicitly convertible to
|
||||
`boost::string_ref` containing the case-insensitive field
|
||||
@@ -28,7 +28,7 @@ In this table:
|
||||
]
|
||||
[
|
||||
[`a.value()`]
|
||||
[`boost::string_ref`]
|
||||
[[link beast.ref.string_view `string_view`]]
|
||||
[
|
||||
This function returns a value implicitly convertible to
|
||||
`boost::string_ref` containing the value for the field. The
|
||||
|
@@ -1,133 +0,0 @@
|
||||
[/
|
||||
Copyright (c) 2013-2017 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)
|
||||
]
|
||||
|
||||
[section:FieldSequence FieldSequence]
|
||||
|
||||
A [*FieldSequence] is an iterable container whose value type meets
|
||||
the requirements of [link beast.concept.Field [*Field]]. Objects that meet
|
||||
these requirements become serializable by the implementation.
|
||||
|
||||
In this table:
|
||||
|
||||
* `X` denotes a type that meets the requirements of [*FieldSequence].
|
||||
|
||||
* `c` is a value of type `X const`.
|
||||
|
||||
[table FieldSequence requirements
|
||||
[[expression][type][semantics, pre/post-conditions]]
|
||||
[
|
||||
[`X::value_type`]
|
||||
[]
|
||||
[
|
||||
A type that meets the requirements of
|
||||
[link beast.concept.Field [*Field]].
|
||||
]
|
||||
]
|
||||
[
|
||||
[`X::const_iterator`]
|
||||
[]
|
||||
[
|
||||
An iterator type whose `reference` type meets the
|
||||
requirements of [link beast.concept.Field [*Field]], and which
|
||||
satisfies all the requirements of [*ForwardIterator],
|
||||
except that:
|
||||
|
||||
[ordered_list
|
||||
[there is no requirement that `operator->` is provided, and]
|
||||
[there is no requirement that `reference` be a reference type.]
|
||||
]
|
||||
]
|
||||
]
|
||||
[
|
||||
[`c.begin()`]
|
||||
[`X::const_iterator`]
|
||||
[
|
||||
Returns an iterator to the beginning of the field sequence.
|
||||
]
|
||||
]
|
||||
[
|
||||
[`c.end()`]
|
||||
[`X::const_iterator`]
|
||||
[
|
||||
Returns an iterator to the end of the field sequence.
|
||||
]
|
||||
]
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
|
||||
[/
|
||||
|
||||
/** OutputFields
|
||||
|
||||
Can be serialized by `beast::http::serializer`
|
||||
*/
|
||||
public:
|
||||
// This algorithm produces a set of buffers
|
||||
// corresponding to the serialized representation
|
||||
// of the fields
|
||||
//
|
||||
struct reader
|
||||
{
|
||||
using const_buffers_type = implementation-defined
|
||||
|
||||
...
|
||||
};
|
||||
|
||||
protected:
|
||||
string_view method_impl() const;
|
||||
string_view target_impl() const;
|
||||
string_view reason_impl() const;
|
||||
|
||||
bool close_impl () const;
|
||||
bool chunked_impl () const;
|
||||
bool content_length_impl () const;
|
||||
|
||||
|
||||
|
||||
/** InputFields
|
||||
|
||||
Can be parsed by `beast::http::parser`
|
||||
*/
|
||||
public:
|
||||
void insert (field f, string_view value);
|
||||
void insert (string_view name, string_view value);
|
||||
|
||||
protected:
|
||||
void method_impl (string_view s);
|
||||
void target_impl (string_view s);
|
||||
void reason_impl (string_view s);
|
||||
|
||||
|
||||
/** Fields
|
||||
|
||||
Has a container interface and supports input and output.
|
||||
`beast::http:basic_fields` is a model.
|
||||
*/
|
||||
|
||||
public:
|
||||
bool exists(field f) const;
|
||||
bool exists(string_view s) const;
|
||||
|
||||
iterator find(field f) const;
|
||||
iterator find(string_view s);
|
||||
|
||||
std::size_t erase (field f);
|
||||
std::size_t erase (string_view s);
|
||||
iterator erase (iterator);
|
||||
|
||||
protected:
|
||||
void content_length_impl(std::uint64_t n);
|
||||
void connection_impl(close_t);
|
||||
void connection_impl(keep_alive_t);
|
||||
void connection_impl(upgrade_t);
|
||||
void chunked_impl();
|
||||
|
||||
|
||||
]
|
112
doc/concept/Fields.qbk
Normal file
112
doc/concept/Fields.qbk
Normal file
@@ -0,0 +1,112 @@
|
||||
[/
|
||||
Copyright (c) 2013-2017 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)
|
||||
]
|
||||
|
||||
[section:Fields Fields]
|
||||
|
||||
An instance of [*Fields] is a container for holding HTTP header fields
|
||||
and their values. The implementation also calls upon the container to
|
||||
store the request target and non-standard strings for method and obsolete
|
||||
reason phrase as needed. Types which meet these requirements can always
|
||||
be serialized.
|
||||
|
||||
In this table:
|
||||
|
||||
* `X` denotes a type that meets the requirements of [*Fields].
|
||||
|
||||
* `R` denotes a type meeting the requiremnets of __FieldsReader__.
|
||||
|
||||
* `a` denotes a value of type `X`.
|
||||
|
||||
* `c` denotes a (possibly const) value of type `X`.
|
||||
|
||||
* `s` is a value of type [link beast.ref.string_view `string_view`].
|
||||
|
||||
[table Fields requirements
|
||||
[[expression][type][semantics, pre/post-conditions]]
|
||||
[
|
||||
[`X::reader`]
|
||||
[`R`]
|
||||
[
|
||||
A type which meets the requirements of __FieldsReader__.
|
||||
]
|
||||
][
|
||||
[`c.has_close_impl()`]
|
||||
[`bool`]
|
||||
[
|
||||
Returns `true` if the value for Connection has "close" in the list.
|
||||
]
|
||||
][
|
||||
[`c.has_chunked_impl()`]
|
||||
[`bool`]
|
||||
[
|
||||
Returns `true` if "chunked" is the last Transfer-Encoding.
|
||||
]
|
||||
][
|
||||
[`c.has_content_length_impl()`]
|
||||
[`bool`]
|
||||
[
|
||||
Returns `true` if the Content-Length field is present.
|
||||
]
|
||||
][
|
||||
[`c.get_method_impl()`]
|
||||
[`string_view`]
|
||||
[
|
||||
Returns the method text.
|
||||
The implementation only calls this function for request
|
||||
headers when retrieving the method text previously set
|
||||
with a call to `set_method_impl` using a non-empty string.
|
||||
]
|
||||
][
|
||||
[`c.get_target_impl()`]
|
||||
[`string_view`]
|
||||
[
|
||||
Returns the target string.
|
||||
The implementation only calls this function for request headers.
|
||||
]
|
||||
][
|
||||
[`c.get_reason_impl()`]
|
||||
[`string_view`]
|
||||
[
|
||||
Returns the obsolete request text.
|
||||
The implementation only calls this for response headers when
|
||||
retrieving the reason text previously set with a call to
|
||||
`set_reason_impl` using a non-empty string.
|
||||
]
|
||||
][
|
||||
[`a.set_method_impl(s)`]
|
||||
[]
|
||||
[
|
||||
Stores a copy of `s` as the method text, or erases the previously
|
||||
stored value if `s` is empty.
|
||||
The implementation only calls this function for request headers.
|
||||
This function may throw `std::invalid_argument` if the operation
|
||||
is not supported by the container.
|
||||
]
|
||||
][
|
||||
[`a.set_target_impl(s)`]
|
||||
[]
|
||||
[
|
||||
Stores a copy of `s` as the target, or erases the previously
|
||||
stored value if `s` is empty.
|
||||
The implementation only calls this function for request headers.
|
||||
This function may throw `std::invalid_argument` if the operation
|
||||
is not supported by the container.
|
||||
]
|
||||
][
|
||||
[`a.set_reason_impl(s)`]
|
||||
[]
|
||||
[
|
||||
Stores a copy of `s` as the reason text, or erases the previously
|
||||
stored value of the reason text if `s` is empty.
|
||||
The implementation only calls this function for request headers.
|
||||
This function may throw `std::invalid_argument` if the operation
|
||||
is not supported by the container.
|
||||
]
|
||||
]
|
||||
]
|
||||
|
||||
[endsect]
|
78
doc/concept/FieldsReader.qbk
Normal file
78
doc/concept/FieldsReader.qbk
Normal file
@@ -0,0 +1,78 @@
|
||||
[/
|
||||
Copyright (c) 2013-2017 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)
|
||||
]
|
||||
|
||||
[section:FieldsReader FieldsReader]
|
||||
|
||||
A [*FieldsReader] provides a algorithm to obtain a sequence of buffers
|
||||
representing the complete serialized HTTP/1 header for a set of fields.
|
||||
The implementation constructs an instance of this type when needed, and
|
||||
calls into it once to retrieve the buffers.
|
||||
|
||||
In this table:
|
||||
|
||||
* `X` denotes a type that meets the requirements of [*FieldsReader].
|
||||
|
||||
* `F` denotes a __Fields__ where
|
||||
`std::is_same<X, F::reader>::value == `true`.
|
||||
|
||||
* `a` is a value of type `X`.
|
||||
|
||||
* `f` is a value of type `F`.
|
||||
|
||||
* `v` is an integer representing the HTTP version.
|
||||
|
||||
* `c` is an integer representing the HTTP status-code.
|
||||
|
||||
* `m` is a value of type [link beast.ref.http__verb `verb`].
|
||||
|
||||
[table FieldsReader requirements
|
||||
[[expression][type][semantics, pre/post-conditions]]
|
||||
[
|
||||
[`X::const_buffers_type`]
|
||||
[]
|
||||
[
|
||||
A type which meets the requirements of __ConstBufferSequence__.
|
||||
This is the type of buffer returned by `X::get`.
|
||||
]
|
||||
][
|
||||
[`X(f,v,m)`]
|
||||
[]
|
||||
[
|
||||
The implementatation uses this constructor to indicate
|
||||
that the fields being serialized form part of an HTTP
|
||||
request. The lifetime of `f` is guaranteed
|
||||
to end no earlier than after the `X` is destroyed.
|
||||
]
|
||||
][
|
||||
[`X(f,v,c)`]
|
||||
[]
|
||||
[
|
||||
The implementatation uses this constructor to indicate
|
||||
that the fields being serialized form part of an HTTP
|
||||
response. The lifetime of `f` is guaranteed
|
||||
to end no earlier than after the `X` is destroyed.
|
||||
]
|
||||
][
|
||||
[`a.get()`]
|
||||
[X::const_buffers_type]
|
||||
[
|
||||
Called once after construction, this function returns
|
||||
a constant buffer sequence containing the serialized
|
||||
representation of the HTTP request or response including
|
||||
the final carriage return linefeed sequence (`"\r\n"`).
|
||||
]
|
||||
][
|
||||
[`is_fields_reader<F>`]
|
||||
[`std::true_type`]
|
||||
[
|
||||
An alias for `std::true_type` for `F`, otherwise an alias
|
||||
for `std::false_type`.
|
||||
]
|
||||
]
|
||||
]
|
||||
|
||||
[endsect]
|
@@ -103,7 +103,8 @@
|
||||
<member><link linkend="beast.concept.BodyReader">BodyReader</link></member>
|
||||
<member><link linkend="beast.concept.BodyWriter">BodyWriter</link></member>
|
||||
<member><link linkend="beast.concept.Field">Field</link></member>
|
||||
<member><link linkend="beast.concept.FieldSequence">FieldSequence</link></member>
|
||||
<member><link linkend="beast.concept.Fields">Fields</link></member>
|
||||
<member><link linkend="beast.concept.FieldsReader">FieldsReader</link></member>
|
||||
</simplelist>
|
||||
</entry>
|
||||
<entry valign="top">
|
||||
|
@@ -21,6 +21,12 @@ namespace beast {
|
||||
template<class... Buffers>
|
||||
class buffer_cat_view
|
||||
{
|
||||
#if 0
|
||||
static_assert(
|
||||
detail::is_all_const_buffer_sequence<Buffers...>::value,
|
||||
"BufferSequence requirements not met");
|
||||
#endif
|
||||
|
||||
std::tuple<Buffers...> bn_;
|
||||
|
||||
public:
|
||||
|
@@ -24,6 +24,12 @@ namespace beast {
|
||||
template<class... Bn>
|
||||
class buffer_cat_view<Bn...>::const_iterator
|
||||
{
|
||||
#if 0
|
||||
static_assert(
|
||||
detail::is_all_const_buffer_sequence<Bn...>::value,
|
||||
"BufferSequence requirements not met");
|
||||
#endif
|
||||
|
||||
std::size_t n_;
|
||||
std::tuple<Bn...> const* bn_;
|
||||
std::array<char, detail::max_sizeof<
|
||||
|
@@ -13,6 +13,7 @@
|
||||
#include <beast/core/detail/ci_char_traits.hpp>
|
||||
#include <beast/http/connection.hpp>
|
||||
#include <beast/http/field.hpp>
|
||||
#include <boost/asio/buffer.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <boost/intrusive/list.hpp>
|
||||
#include <boost/intrusive/set.hpp>
|
||||
@@ -40,7 +41,7 @@ namespace http {
|
||||
as a `std::multiset`; there will be a separate value for each occurrence
|
||||
of the field name.
|
||||
|
||||
@note Meets the requirements of @b FieldSequence.
|
||||
@note Meets the requirements of @b Fields
|
||||
*/
|
||||
template<class Allocator>
|
||||
class basic_fields
|
||||
@@ -259,8 +260,6 @@ public:
|
||||
|
||||
@param f The known field constant.
|
||||
|
||||
@param name The name of the field.
|
||||
|
||||
@param value A string holding the value of the field.
|
||||
*/
|
||||
void
|
||||
@@ -337,54 +336,55 @@ public:
|
||||
void
|
||||
swap(basic_fields<Alloc>& lhs, basic_fields<Alloc>& rhs);
|
||||
|
||||
/// The algorithm used to serialize the header
|
||||
class reader;
|
||||
|
||||
protected:
|
||||
/// Returns `true` if the value for Connection has "close" in the list.
|
||||
bool has_close_impl() const;
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
// for serializing
|
||||
//
|
||||
/// Returns `true` if "chunked" is the last Transfer-Encoding
|
||||
bool has_chunked_impl() const;
|
||||
|
||||
/** Returns the stored request-method string.
|
||||
/// Returns `true` if the Content-Length field is present
|
||||
bool has_content_length_impl() const;
|
||||
|
||||
@note This is called by the @ref header implementation.
|
||||
*/
|
||||
string_view get_method_impl() const;
|
||||
/** Set or clear the method string.
|
||||
|
||||
/** Returns the stored request-target string.
|
||||
|
||||
@note This is called by the @ref header implementation.
|
||||
*/
|
||||
string_view get_target_impl() const;
|
||||
|
||||
/** Returns the stored obsolete reason-phrase string.
|
||||
|
||||
@note This is called by the @ref header implementation.
|
||||
*/
|
||||
string_view get_reason_impl() const;
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
// for parsing
|
||||
//
|
||||
|
||||
/** Set or clear the stored request-method string.
|
||||
|
||||
@note This is called by the @ref header implementation.
|
||||
@note Only called for requests.
|
||||
*/
|
||||
void set_method_impl(string_view s);
|
||||
|
||||
/** Set or clear the stored request-target string.
|
||||
/** Set or clear the target string.
|
||||
|
||||
@note This is called by the @ref header implementation.
|
||||
@note Only called for requests.
|
||||
*/
|
||||
void set_target_impl(string_view s);
|
||||
|
||||
/** Set or clear the stored obsolete reason-phrase string.
|
||||
/** Set or clear the reason string.
|
||||
|
||||
@note This is called by the @ref header implementation.
|
||||
@note Only called for responses.
|
||||
*/
|
||||
void set_reason_impl(string_view s);
|
||||
|
||||
/** Returns the request-method string.
|
||||
|
||||
@note Only called for requests.
|
||||
*/
|
||||
string_view get_method_impl() const;
|
||||
|
||||
/** Returns the request-target string.
|
||||
|
||||
@note Only called for requests.
|
||||
*/
|
||||
string_view get_target_impl() const;
|
||||
|
||||
/** Returns the response reason-phrase string.
|
||||
|
||||
@note Only called for responses.
|
||||
*/
|
||||
string_view get_reason_impl() const;
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
// for container
|
||||
@@ -418,7 +418,7 @@ protected:
|
||||
|
||||
@note This is called by the @ref header implementation.
|
||||
*/
|
||||
void chunked_impl();
|
||||
void set_chunked_impl(bool v);
|
||||
|
||||
private:
|
||||
class element
|
||||
@@ -441,6 +441,9 @@ private:
|
||||
string_view
|
||||
value() const;
|
||||
|
||||
boost::asio::const_buffer
|
||||
buffer() const;
|
||||
|
||||
value_type data;
|
||||
};
|
||||
|
||||
|
@@ -8,8 +8,13 @@
|
||||
#ifndef BEAST_HTTP_IMPL_FIELDS_IPP
|
||||
#define BEAST_HTTP_IMPL_FIELDS_IPP
|
||||
|
||||
#include <beast/core/buffer_cat.hpp>
|
||||
#include <beast/core/static_string.hpp>
|
||||
#include <beast/http/detail/rfc7230.hpp>
|
||||
#include <beast/core/detail/ci_char_traits.hpp>
|
||||
#include <beast/http/verb.hpp>
|
||||
#include <beast/http/rfc7230.hpp>
|
||||
#include <beast/http/status.hpp>
|
||||
#include <beast/http/detail/chunk_encode.hpp>
|
||||
#include <boost/throw_exception.hpp>
|
||||
#include <algorithm>
|
||||
|
||||
@@ -106,6 +111,177 @@ public:
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template<class Allocator>
|
||||
class basic_fields<Allocator>::reader
|
||||
{
|
||||
public:
|
||||
using iter_type = typename list_t::const_iterator;
|
||||
|
||||
struct field_iterator
|
||||
{
|
||||
iter_type it_;
|
||||
|
||||
using value_type = boost::asio::const_buffer;
|
||||
using pointer = value_type const*;
|
||||
using reference = value_type const;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using iterator_category =
|
||||
std::bidirectional_iterator_tag;
|
||||
|
||||
field_iterator() = default;
|
||||
field_iterator(field_iterator&& other) = default;
|
||||
field_iterator(field_iterator const& other) = default;
|
||||
field_iterator& operator=(field_iterator&& other) = default;
|
||||
field_iterator& operator=(field_iterator const& other) = default;
|
||||
|
||||
explicit
|
||||
field_iterator(iter_type it)
|
||||
: it_(it)
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
operator==(field_iterator const& other) const
|
||||
{
|
||||
return it_ == other.it_;
|
||||
}
|
||||
|
||||
bool
|
||||
operator!=(field_iterator const& other) const
|
||||
{
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
reference
|
||||
operator*() const
|
||||
{
|
||||
return it_->buffer();
|
||||
}
|
||||
|
||||
field_iterator&
|
||||
operator++()
|
||||
{
|
||||
++it_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
field_iterator
|
||||
operator++(int)
|
||||
{
|
||||
auto temp = *this;
|
||||
++(*this);
|
||||
return temp;
|
||||
}
|
||||
|
||||
field_iterator&
|
||||
operator--()
|
||||
{
|
||||
--it_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
field_iterator
|
||||
operator--(int)
|
||||
{
|
||||
auto temp = *this;
|
||||
--(*this);
|
||||
return temp;
|
||||
}
|
||||
};
|
||||
|
||||
class field_range
|
||||
{
|
||||
field_iterator first_;
|
||||
field_iterator last_;
|
||||
|
||||
public:
|
||||
using const_iterator =
|
||||
field_iterator;
|
||||
|
||||
using value_type =
|
||||
typename const_iterator::value_type;
|
||||
|
||||
field_range(field_range const&) = default;
|
||||
|
||||
field_range(iter_type first, iter_type last)
|
||||
: first_(first)
|
||||
, last_(last)
|
||||
{
|
||||
}
|
||||
|
||||
const_iterator
|
||||
begin() const
|
||||
{
|
||||
return first_;
|
||||
}
|
||||
|
||||
const_iterator
|
||||
end() const
|
||||
{
|
||||
return last_;
|
||||
}
|
||||
};
|
||||
|
||||
basic_fields const& f_;
|
||||
std::string s_;
|
||||
|
||||
public:
|
||||
using const_buffers_type =
|
||||
buffer_cat_view<
|
||||
boost::asio::const_buffers_1,
|
||||
field_range,
|
||||
boost::asio::const_buffers_1>;
|
||||
|
||||
reader(basic_fields const& f, int version, verb v)
|
||||
: f_(f)
|
||||
{
|
||||
s_ = v == verb::unknown ?
|
||||
f_.get_method_impl().to_string() :
|
||||
to_string(v).to_string();
|
||||
s_ += " ";
|
||||
s_ += f_.get_target_impl().to_string();
|
||||
if(version == 11)
|
||||
s_ += " HTTP/1.1";
|
||||
else if(version == 10)
|
||||
s_ += " HTTP/1.0";
|
||||
else
|
||||
s_ += " HTTP/" +
|
||||
std::to_string(version / 10) + "." +
|
||||
std::to_string(version % 10);
|
||||
s_ += "\r\n";
|
||||
}
|
||||
|
||||
reader(basic_fields const& f, int version, int code)
|
||||
: f_(f)
|
||||
{
|
||||
if(version == 11)
|
||||
s_ += "HTTP/1.1 ";
|
||||
else if(version == 10)
|
||||
s_ += "HTTP/1.0 ";
|
||||
else
|
||||
s_ += "HTTP/" +
|
||||
std::to_string(version / 10) + "." +
|
||||
std::to_string(version % 10) + " ";
|
||||
s_ += std::to_string(code) + " ";
|
||||
if(int_to_status(code) == status::unknown)
|
||||
s_ += f_.get_reason_impl().to_string();
|
||||
else
|
||||
s_ += obsolete_reason(int_to_status(code)).to_string();
|
||||
s_ += "\r\n";
|
||||
}
|
||||
|
||||
const_buffers_type
|
||||
get() const
|
||||
{
|
||||
return buffer_cat(
|
||||
boost::asio::buffer(s_.data(), s_.size()),
|
||||
field_range(f_.list_.begin(), f_.list_.end()),
|
||||
detail::chunk_crlf());
|
||||
}
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template<class Allocator>
|
||||
basic_fields<Allocator>::
|
||||
element::
|
||||
@@ -150,6 +326,18 @@ value() const
|
||||
static_cast<std::size_t>(len_)};
|
||||
}
|
||||
|
||||
template<class Allocator>
|
||||
inline
|
||||
boost::asio::const_buffer
|
||||
basic_fields<Allocator>::
|
||||
element::
|
||||
buffer() const
|
||||
{
|
||||
return boost::asio::const_buffer{
|
||||
reinterpret_cast<char const*>(this + 1),
|
||||
static_cast<std::size_t>(off_) + len_ + 2};
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template<class Allocator>
|
||||
@@ -361,31 +549,50 @@ replace(string_view name, string_view value)
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// Fields
|
||||
|
||||
template<class Allocator>
|
||||
inline
|
||||
string_view
|
||||
bool
|
||||
basic_fields<Allocator>::
|
||||
get_method_impl() const
|
||||
has_close_impl() const
|
||||
{
|
||||
return method_;
|
||||
auto const fit = set_.find(
|
||||
to_string(field::connection), less{});
|
||||
if(fit == set_.end())
|
||||
return false;
|
||||
return token_list{fit->value()}.exists("close");
|
||||
}
|
||||
|
||||
template<class Allocator>
|
||||
inline
|
||||
string_view
|
||||
bool
|
||||
basic_fields<Allocator>::
|
||||
get_target_impl() const
|
||||
has_chunked_impl() const
|
||||
{
|
||||
return target_or_reason_;
|
||||
auto const fit = set_.find(to_string(
|
||||
field::transfer_encoding), less{});
|
||||
if(fit == set_.end())
|
||||
return false;
|
||||
token_list const v{fit->value()};
|
||||
auto it = v.begin();
|
||||
if(it == v.end())
|
||||
return false;
|
||||
for(;;)
|
||||
{
|
||||
auto cur = it++;
|
||||
if(it == v.end())
|
||||
return beast::detail::ci_equal(
|
||||
*cur, "chunked");
|
||||
}
|
||||
}
|
||||
|
||||
template<class Allocator>
|
||||
inline
|
||||
string_view
|
||||
bool
|
||||
basic_fields<Allocator>::
|
||||
get_reason_impl() const
|
||||
has_content_length_impl() const
|
||||
{
|
||||
return target_or_reason_;
|
||||
auto const fit = set_.find(
|
||||
to_string(field::content_length), less{});
|
||||
return fit != set_.end();
|
||||
}
|
||||
|
||||
template<class Allocator>
|
||||
@@ -415,6 +622,33 @@ set_reason_impl(string_view s)
|
||||
realloc_string(target_or_reason_, s);
|
||||
}
|
||||
|
||||
template<class Allocator>
|
||||
inline
|
||||
string_view
|
||||
basic_fields<Allocator>::
|
||||
get_method_impl() const
|
||||
{
|
||||
return method_;
|
||||
}
|
||||
|
||||
template<class Allocator>
|
||||
inline
|
||||
string_view
|
||||
basic_fields<Allocator>::
|
||||
get_target_impl() const
|
||||
{
|
||||
return target_or_reason_;
|
||||
}
|
||||
|
||||
template<class Allocator>
|
||||
inline
|
||||
string_view
|
||||
basic_fields<Allocator>::
|
||||
get_reason_impl() const
|
||||
{
|
||||
return target_or_reason_;
|
||||
}
|
||||
|
||||
//---
|
||||
|
||||
template<class Allocator>
|
||||
@@ -474,8 +708,9 @@ template<class Allocator>
|
||||
inline
|
||||
void
|
||||
basic_fields<Allocator>::
|
||||
chunked_impl()
|
||||
set_chunked_impl(bool v)
|
||||
{
|
||||
BOOST_ASSERT(v);
|
||||
auto it = find("Transfer-Encoding");
|
||||
if(it == end())
|
||||
this->insert("Transfer-Encoding", "chunked");
|
||||
@@ -682,7 +917,6 @@ swap(basic_fields& other, std::false_type)
|
||||
swap(target_or_reason_, other.target_or_reason_);
|
||||
}
|
||||
|
||||
|
||||
} // http
|
||||
} // beast
|
||||
|
||||
|
@@ -61,7 +61,7 @@ method_string() const
|
||||
template<class Fields>
|
||||
void
|
||||
header<true, Fields>::
|
||||
method(string_view s)
|
||||
method_string(string_view s)
|
||||
{
|
||||
method_ = string_to_verb(s);
|
||||
if(method_ != verb::unknown)
|
||||
@@ -190,21 +190,85 @@ swap(
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template<bool isRequest, class Body, class Fields>
|
||||
template<class... Args>
|
||||
message<isRequest, Body, Fields>::
|
||||
message(header_type&& base, Args&&... args)
|
||||
: header_type(std::move(base))
|
||||
, body(std::forward<Args>(args)...)
|
||||
{
|
||||
}
|
||||
|
||||
template<bool isRequest, class Body, class Fields>
|
||||
template<class... Args>
|
||||
message<isRequest, Body, Fields>::
|
||||
message(header_type const& base, Args&&... args)
|
||||
: header_type(base)
|
||||
, body(std::forward<Args>(args)...)
|
||||
{
|
||||
}
|
||||
|
||||
template<bool isRequest, class Body, class Fields>
|
||||
template<class U, class>
|
||||
message<isRequest, Body, Fields>::
|
||||
message(U&& u)
|
||||
: body(std::forward<U>(u))
|
||||
{
|
||||
}
|
||||
|
||||
template<bool isRequest, class Body, class Fields>
|
||||
template<class U, class V, class>
|
||||
message<isRequest, Body, Fields>::
|
||||
message(U&& u, V&& v)
|
||||
: header_type(std::forward<V>(v))
|
||||
, body(std::forward<U>(u))
|
||||
{
|
||||
}
|
||||
|
||||
template<bool isRequest, class Body, class Fields>
|
||||
template<class... Un>
|
||||
message<isRequest, Body, Fields>::
|
||||
message(std::piecewise_construct_t, std::tuple<Un...> un)
|
||||
: message(std::piecewise_construct, un,
|
||||
beast::detail::make_index_sequence<sizeof...(Un)>{})
|
||||
{
|
||||
}
|
||||
|
||||
template<bool isRequest, class Body, class Fields>
|
||||
template<class... Un, class... Vn>
|
||||
message<isRequest, Body, Fields>::
|
||||
message(std::piecewise_construct_t,
|
||||
std::tuple<Un...>&& un, std::tuple<Vn...>&& vn)
|
||||
: message(std::piecewise_construct, un, vn,
|
||||
beast::detail::make_index_sequence<sizeof...(Un)>{},
|
||||
beast::detail::make_index_sequence<sizeof...(Vn)>{})
|
||||
{
|
||||
}
|
||||
|
||||
template<bool isRequest, class Body, class Fields>
|
||||
inline
|
||||
bool
|
||||
message<isRequest, Body, Fields>::
|
||||
chunked() const
|
||||
has_close() const
|
||||
{
|
||||
auto const it0 = this->find("Transfer-Encoding");
|
||||
if(it0 == this->end())
|
||||
return false;
|
||||
token_list value{*it0};
|
||||
for(auto it = value.begin(); it != value.end();)
|
||||
{
|
||||
auto cur = it++;
|
||||
if(it == value.end())
|
||||
return *cur == "chunked";
|
||||
}
|
||||
return false;
|
||||
return this->has_close_impl();
|
||||
}
|
||||
|
||||
template<bool isRequest, class Body, class Fields>
|
||||
inline
|
||||
bool
|
||||
message<isRequest, Body, Fields>::
|
||||
has_chunked() const
|
||||
{
|
||||
return this->has_chunked_impl();
|
||||
}
|
||||
|
||||
template<bool isRequest, class Body, class Fields>
|
||||
inline
|
||||
bool
|
||||
message<isRequest, Body, Fields>::
|
||||
has_content_length() const
|
||||
{
|
||||
return this->has_content_length_impl();
|
||||
}
|
||||
|
||||
template<bool isRequest, class Body, class Fields>
|
||||
@@ -326,7 +390,7 @@ prepare_payload(std::true_type)
|
||||
}
|
||||
else if(this->version >= 11)
|
||||
{
|
||||
this->chunked_impl();
|
||||
this->set_chunked_impl(true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -350,7 +414,7 @@ prepare_payload(std::false_type)
|
||||
if(n)
|
||||
this->content_length_impl(*n);
|
||||
else if(this->version >= 11)
|
||||
this->chunked_impl();
|
||||
this->set_chunked_impl(true);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
@@ -15,59 +15,27 @@
|
||||
|
||||
namespace beast {
|
||||
namespace http {
|
||||
namespace detail {
|
||||
|
||||
template<class Fields>
|
||||
template<bool isRequest, class Body, class Fields,
|
||||
class ChunkDecorator, class Allocator>
|
||||
void
|
||||
write_start_line(std::ostream& os,
|
||||
header<true, Fields> const& msg)
|
||||
serializer<isRequest, Body, Fields,
|
||||
ChunkDecorator, Allocator>::
|
||||
frdinit(std::true_type)
|
||||
{
|
||||
// VFALCO This should all be done without dynamic allocation
|
||||
BOOST_ASSERT(msg.version == 10 || msg.version == 11);
|
||||
os << msg.method() << " " << msg.target();
|
||||
switch(msg.version)
|
||||
{
|
||||
case 10: os << " HTTP/1.0\r\n"; break;
|
||||
case 11: os << " HTTP/1.1\r\n"; break;
|
||||
}
|
||||
frd_.emplace(m_, m_.version, m_.method());
|
||||
}
|
||||
|
||||
template<class Fields>
|
||||
template<bool isRequest, class Body, class Fields,
|
||||
class ChunkDecorator, class Allocator>
|
||||
void
|
||||
write_start_line(std::ostream& os,
|
||||
header<false, Fields> const& msg)
|
||||
serializer<isRequest, Body, Fields,
|
||||
ChunkDecorator, Allocator>::
|
||||
frdinit(std::false_type)
|
||||
{
|
||||
// VFALCO This should all be done without dynamic allocation
|
||||
BOOST_ASSERT(msg.version == 10 || msg.version == 11);
|
||||
switch(msg.version)
|
||||
{
|
||||
case 10: os << "HTTP/1.0 "; break;
|
||||
case 11: os << "HTTP/1.1 "; break;
|
||||
}
|
||||
os << msg.result_int() << " " << msg.reason() << "\r\n";
|
||||
frd_.emplace(m_, m_.version, m_.result_int());
|
||||
}
|
||||
|
||||
template<class FieldSequence>
|
||||
void
|
||||
write_fields(std::ostream& os,
|
||||
FieldSequence const& fields)
|
||||
{
|
||||
//static_assert(is_FieldSequence<FieldSequence>::value,
|
||||
// "FieldSequence requirements not met");
|
||||
for(auto const& field : fields)
|
||||
{
|
||||
auto const name = field.name();
|
||||
BOOST_ASSERT(! name.empty());
|
||||
if(name[0] == ':')
|
||||
continue;
|
||||
os << field.name() << ": " << field.value() << "\r\n";
|
||||
}
|
||||
}
|
||||
|
||||
} // detail
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template<bool isRequest, class Body, class Fields,
|
||||
class ChunkDecorator, class Allocator>
|
||||
serializer<isRequest, Body, Fields,
|
||||
@@ -76,7 +44,6 @@ serializer(message<isRequest, Body, Fields> const& m,
|
||||
ChunkDecorator const& d, Allocator const& alloc)
|
||||
: m_(m)
|
||||
, d_(d)
|
||||
, b_(1024, alloc)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -93,15 +60,11 @@ get(error_code& ec, Visit&& visit)
|
||||
{
|
||||
case do_construct:
|
||||
{
|
||||
chunked_ = token_list{
|
||||
m_["Transfer-Encoding"]}.exists("chunked");
|
||||
close_ = token_list{m_["Connection"]}.exists("close") ||
|
||||
(m_.version < 11 && ! m_.exists("Content-Length"));
|
||||
auto os = ostream(b_);
|
||||
detail::write_start_line(os, m_);
|
||||
detail::write_fields(os, m_);
|
||||
os << "\r\n";
|
||||
if(chunked_)
|
||||
frdinit(std::integral_constant<bool,
|
||||
isRequest>{});
|
||||
close_ = m_.has_close() || (
|
||||
m_.version < 11 && ! m_.has_content_length());
|
||||
if(m_.has_chunked())
|
||||
goto go_init_c;
|
||||
s_ = do_init;
|
||||
// [[fallthrough]]
|
||||
@@ -127,7 +90,7 @@ get(error_code& ec, Visit&& visit)
|
||||
more_ = result->second;
|
||||
v_ = cb0_t{
|
||||
boost::in_place_init,
|
||||
b_.data(),
|
||||
frd_->get(),
|
||||
result->first};
|
||||
s_ = do_header;
|
||||
// [[fallthrough]]
|
||||
@@ -138,9 +101,10 @@ get(error_code& ec, Visit&& visit)
|
||||
break;
|
||||
|
||||
go_header_only:
|
||||
v_ = ch_t{frd_->get()};
|
||||
s_ = do_header_only;
|
||||
case do_header_only:
|
||||
visit(ec, b_.data());
|
||||
visit(ec, boost::get<ch_t>(v_));
|
||||
break;
|
||||
|
||||
case do_body:
|
||||
@@ -193,7 +157,7 @@ get(error_code& ec, Visit&& visit)
|
||||
more_ = result->second;
|
||||
v_ = ch0_t{
|
||||
boost::in_place_init,
|
||||
b_.data(),
|
||||
frd_->get(),
|
||||
detail::chunk_header{
|
||||
buffer_size(result->first)},
|
||||
[&]()
|
||||
@@ -215,9 +179,10 @@ get(error_code& ec, Visit&& visit)
|
||||
break;
|
||||
|
||||
go_header_only_c:
|
||||
v_ = ch_t{frd_->get()};
|
||||
s_ = do_header_only_c;
|
||||
case do_header_only_c:
|
||||
visit(ec, b_.data());
|
||||
visit(ec, boost::get<ch_t>(v_));
|
||||
break;
|
||||
|
||||
case do_body_c:
|
||||
@@ -311,18 +276,18 @@ consume(std::size_t n)
|
||||
break;
|
||||
header_done_ = true;
|
||||
v_ = boost::blank{};
|
||||
b_.consume(b_.size()); // VFALCO delete b_?
|
||||
if(! more_)
|
||||
goto go_complete;
|
||||
s_ = do_body + 1;
|
||||
break;
|
||||
|
||||
case do_header_only:
|
||||
BOOST_ASSERT(n <= b_.size());
|
||||
b_.consume(n);
|
||||
if(buffer_size(b_.data()) > 0)
|
||||
BOOST_ASSERT(n <= buffer_size(
|
||||
boost::get<ch_t>(v_)));
|
||||
boost::get<ch_t>(v_).consume(n);
|
||||
if(buffer_size(boost::get<ch_t>(v_)) > 0)
|
||||
break;
|
||||
// VFALCO delete b_?
|
||||
frd_ = boost::none;
|
||||
header_done_ = true;
|
||||
if(! split_)
|
||||
goto go_complete;
|
||||
@@ -353,7 +318,6 @@ consume(std::size_t n)
|
||||
break;
|
||||
header_done_ = true;
|
||||
v_ = boost::blank{};
|
||||
b_.consume(b_.size()); // VFALCO delete b_?
|
||||
if(more_)
|
||||
s_ = do_body_c + 1;
|
||||
else
|
||||
@@ -362,11 +326,12 @@ consume(std::size_t n)
|
||||
|
||||
case do_header_only_c:
|
||||
{
|
||||
BOOST_ASSERT(n <= buffer_size(b_.data()));
|
||||
b_.consume(n);
|
||||
if(buffer_size(b_.data()) > 0)
|
||||
BOOST_ASSERT(n <= buffer_size(
|
||||
boost::get<ch_t>(v_)));
|
||||
boost::get<ch_t>(v_).consume(n);
|
||||
if(buffer_size(boost::get<ch_t>(v_)) > 0)
|
||||
break;
|
||||
// VFALCO delete b_?
|
||||
frd_ = boost::none;
|
||||
header_done_ = true;
|
||||
if(! split_)
|
||||
{
|
||||
|
@@ -822,16 +822,15 @@ public:
|
||||
|
||||
} // detail
|
||||
|
||||
#if 0
|
||||
template<bool isRequest, class Fields>
|
||||
std::ostream&
|
||||
operator<<(std::ostream& os,
|
||||
header<isRequest, Fields> const& msg)
|
||||
{
|
||||
detail::write_start_line(os, msg);
|
||||
detail::write_fields(os, msg);
|
||||
os << "\r\n";
|
||||
return os;
|
||||
// VFALCO TODO
|
||||
}
|
||||
#endif
|
||||
|
||||
template<bool isRequest, class Body, class Fields>
|
||||
std::ostream&
|
||||
|
@@ -119,7 +119,7 @@ struct header<true, Fields> : Fields
|
||||
verb
|
||||
method() const;
|
||||
|
||||
/** Set the request-method verb.
|
||||
/** Set the request-method.
|
||||
|
||||
This function will set the method for requests to a known verb.
|
||||
|
||||
@@ -127,11 +127,13 @@ struct header<true, Fields> : Fields
|
||||
This may not be @ref verb::unknown.
|
||||
|
||||
@throw std::invalid_argument when `v == verb::unknown`.
|
||||
|
||||
@note This function is only available when `isRequest == true`.
|
||||
*/
|
||||
void
|
||||
method(verb v);
|
||||
|
||||
/** Return the request-method string.
|
||||
/** Return the request-method as a string.
|
||||
|
||||
@note This function is only available when `isRequest == true`.
|
||||
|
||||
@@ -140,18 +142,18 @@ struct header<true, Fields> : Fields
|
||||
string_view
|
||||
method_string() const;
|
||||
|
||||
/** Set the request-method string.
|
||||
/** Set the request-method.
|
||||
|
||||
This function will set the method for requests to a verb
|
||||
if the string matches a known verb, otherwise it will
|
||||
store a copy of the passed string as the method.
|
||||
This function will set the request-method a known verb
|
||||
if the string matches, otherwise it will store a copy of
|
||||
the passed string.
|
||||
|
||||
@param s A string representing the request-method.
|
||||
|
||||
@note This function is only available when `isRequest == true`.
|
||||
*/
|
||||
void
|
||||
method(string_view s);
|
||||
method_string(string_view s);
|
||||
|
||||
/** Returns the request-target string.
|
||||
|
||||
@@ -382,31 +384,27 @@ struct message : header<isRequest, Fields>
|
||||
/// Copy assignment
|
||||
message& operator=(message const&) = default;
|
||||
|
||||
/** Construct a message from a header.
|
||||
/** Constructor.
|
||||
|
||||
Additional arguments, if any, are forwarded to
|
||||
the constructor of the body member.
|
||||
@param h The header to move construct from.
|
||||
|
||||
@param args Optional arguments forwarded
|
||||
to the body constructor.
|
||||
*/
|
||||
template<class... Args>
|
||||
explicit
|
||||
message(header_type&& base, Args&&... args)
|
||||
: header_type(std::move(base))
|
||||
, body(std::forward<Args>(args)...)
|
||||
{
|
||||
}
|
||||
message(header_type&& h, Args&&... args);
|
||||
|
||||
/** Construct a message from a header.
|
||||
/** Constructor.
|
||||
|
||||
Additional arguments, if any, are forwarded to
|
||||
the constructor of the body member.
|
||||
@param h The header to copy construct from.
|
||||
|
||||
@param args Optional arguments forwarded
|
||||
to the body constructor.
|
||||
*/
|
||||
template<class... Args>
|
||||
explicit
|
||||
message(header_type const& base, Args&&... args)
|
||||
: header_type(base)
|
||||
, body(std::forward<Args>(args)...)
|
||||
{
|
||||
}
|
||||
message(header_type const& h, Args&&... args);
|
||||
|
||||
/** Construct a message.
|
||||
|
||||
@@ -423,10 +421,7 @@ struct message : header<isRequest, Fields>
|
||||
#endif
|
||||
>
|
||||
explicit
|
||||
message(U&& u)
|
||||
: body(std::forward<U>(u))
|
||||
{
|
||||
}
|
||||
message(U&& u);
|
||||
|
||||
/** Construct a message.
|
||||
|
||||
@@ -443,22 +438,14 @@ struct message : header<isRequest, Fields>
|
||||
typename std::decay<U>::type, header_type>::value>::type
|
||||
#endif
|
||||
>
|
||||
message(U&& u, V&& v)
|
||||
: header_type(std::forward<V>(v))
|
||||
, body(std::forward<U>(u))
|
||||
{
|
||||
}
|
||||
message(U&& u, V&& v);
|
||||
|
||||
/** Construct a message.
|
||||
|
||||
@param un A tuple forwarded as a parameter pack to the body constructor.
|
||||
*/
|
||||
template<class... Un>
|
||||
message(std::piecewise_construct_t, std::tuple<Un...> un)
|
||||
: message(std::piecewise_construct, un,
|
||||
beast::detail::make_index_sequence<sizeof...(Un)>{})
|
||||
{
|
||||
}
|
||||
message(std::piecewise_construct_t, std::tuple<Un...> un);
|
||||
|
||||
/** Construct a message.
|
||||
|
||||
@@ -468,17 +455,25 @@ struct message : header<isRequest, Fields>
|
||||
*/
|
||||
template<class... Un, class... Vn>
|
||||
message(std::piecewise_construct_t,
|
||||
std::tuple<Un...>&& un, std::tuple<Vn...>&& vn)
|
||||
: message(std::piecewise_construct, un, vn,
|
||||
beast::detail::make_index_sequence<sizeof...(Un)>{},
|
||||
beast::detail::make_index_sequence<sizeof...(Vn)>{})
|
||||
{
|
||||
}
|
||||
std::tuple<Un...>&& un, std::tuple<Vn...>&& vn);
|
||||
|
||||
/** Returns `true` if Transfer-Encoding is present, and chunked appears last.
|
||||
/// Returns `true` if "close" is specified in the Connection field.
|
||||
bool
|
||||
has_close() const;
|
||||
|
||||
/// Returns `true` if "chunked" is the last Transfer-Encoding.
|
||||
bool
|
||||
has_chunked() const;
|
||||
|
||||
/** Returns `true` if the Content-Length field is present.
|
||||
|
||||
This function checks the fields to determine if the content
|
||||
length field is present, regardless of the actual value.
|
||||
|
||||
@note The contents of the body payload are not inspected.
|
||||
*/
|
||||
bool
|
||||
chunked() const;
|
||||
has_content_length() const;
|
||||
|
||||
/** Returns the payload size of the body in octets if possible.
|
||||
|
||||
|
@@ -189,7 +189,7 @@ private:
|
||||
if(method != verb::unknown)
|
||||
m_.method(method);
|
||||
else
|
||||
m_.method(method_str);
|
||||
m_.method_string(method_str);
|
||||
m_.version = version;
|
||||
}
|
||||
|
||||
@@ -241,17 +241,15 @@ private:
|
||||
}
|
||||
|
||||
void
|
||||
on_data(string_view s,
|
||||
error_code& ec)
|
||||
on_data(string_view s, error_code& ec)
|
||||
{
|
||||
wr_->put(boost::asio::buffer(
|
||||
s.data(), s.size()), ec);
|
||||
}
|
||||
|
||||
void
|
||||
on_chunk(
|
||||
std::uint64_t, string_view,
|
||||
error_code&)
|
||||
on_chunk(std::uint64_t,
|
||||
string_view, error_code&)
|
||||
{
|
||||
}
|
||||
|
||||
|
@@ -12,7 +12,6 @@
|
||||
#include <beast/core/async_result.hpp>
|
||||
#include <beast/core/buffer_cat.hpp>
|
||||
#include <beast/core/consuming_buffers.hpp>
|
||||
#include <beast/core/multi_buffer.hpp>
|
||||
#include <beast/core/string_view.hpp>
|
||||
#include <beast/core/type_traits.hpp>
|
||||
#include <beast/http/message.hpp>
|
||||
@@ -155,24 +154,26 @@ class serializer
|
||||
|
||||
void split(bool, std::true_type) {}
|
||||
void split(bool v, std::false_type) { split_ = v; }
|
||||
|
||||
using buffer_type =
|
||||
basic_multi_buffer<Allocator>;
|
||||
void frdinit(std::true_type);
|
||||
void frdinit(std::false_type);
|
||||
|
||||
using reader = typename Body::reader;
|
||||
|
||||
using is_deferred =
|
||||
typename reader::is_deferred;
|
||||
|
||||
using ch_t = consuming_buffers<typename
|
||||
Fields::reader::const_buffers_type>; // header
|
||||
|
||||
using cb0_t = consuming_buffers<buffer_cat_view<
|
||||
typename buffer_type::const_buffers_type, // header
|
||||
typename Fields::reader::const_buffers_type,// header
|
||||
typename reader::const_buffers_type>>; // body
|
||||
|
||||
using cb1_t = consuming_buffers<
|
||||
typename reader::const_buffers_type>; // body
|
||||
|
||||
using ch0_t = consuming_buffers<buffer_cat_view<
|
||||
typename buffer_type::const_buffers_type, // header
|
||||
typename Fields::reader::const_buffers_type,// header
|
||||
detail::chunk_header, // chunk-header
|
||||
boost::asio::const_buffers_1, // chunk-ext
|
||||
boost::asio::const_buffers_1, // crlf
|
||||
@@ -192,11 +193,11 @@ class serializer
|
||||
boost::asio::const_buffers_1>>; // crlf
|
||||
|
||||
message<isRequest, Body, Fields> const& m_;
|
||||
boost::optional<typename Fields::reader> frd_;
|
||||
ChunkDecorator d_;
|
||||
boost::optional<reader> rd_;
|
||||
buffer_type b_;
|
||||
boost::variant<boost::blank,
|
||||
cb0_t, cb1_t, ch0_t, ch1_t, ch2_t> v_;
|
||||
ch_t, cb0_t, cb1_t, ch0_t, ch1_t, ch2_t> v_;
|
||||
int s_ = do_construct;
|
||||
bool split_ = is_deferred::value;
|
||||
bool header_done_ = false;
|
||||
|
@@ -68,7 +68,7 @@ public:
|
||||
flat_buffer buffer;
|
||||
request<string_body> req;
|
||||
req.version = 11;
|
||||
req.method("POST");
|
||||
req.method_string("POST");
|
||||
req.target("/");
|
||||
req.insert(field::user_agent, "test");
|
||||
req.body = "Hello, world!";
|
||||
@@ -101,7 +101,7 @@ public:
|
||||
{
|
||||
request<string_body> req;
|
||||
req.version = 11;
|
||||
req.method("POST");
|
||||
req.method_string("POST");
|
||||
req.target("/");
|
||||
req.insert(field::user_agent, "test");
|
||||
req.body = "Hello, world!";
|
||||
|
@@ -134,7 +134,7 @@ public:
|
||||
m1.target("u");
|
||||
m1.body = "1";
|
||||
m1.insert("h", "v");
|
||||
m2.method("G");
|
||||
m2.method_string("G");
|
||||
m2.body = "2";
|
||||
swap(m1, m2);
|
||||
BEAST_EXPECT(m1.method_string() == "G");
|
||||
@@ -268,7 +268,7 @@ public:
|
||||
auto const scheck =
|
||||
[&](string_view s)
|
||||
{
|
||||
h.method(s);
|
||||
h.method_string(s);
|
||||
BEAST_EXPECT(h.method() == string_to_verb(s));
|
||||
BEAST_EXPECT(h.method_string() == s);
|
||||
};
|
||||
|
Reference in New Issue
Block a user