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_fields and call sites
|
||||||
* Use field in basic_parser
|
* Use field in basic_parser
|
||||||
* Tidy up basic_fields, header, and field concepts
|
* Tidy up basic_fields, header, and field concepts
|
||||||
|
* Fields concept work
|
||||||
|
|
||||||
API Changes:
|
API Changes:
|
||||||
|
|
||||||
|
@@ -52,7 +52,8 @@
|
|||||||
[def __BodyReader__ [link beast.concept.BodyReader [*BodyReader]]]
|
[def __BodyReader__ [link beast.concept.BodyReader [*BodyReader]]]
|
||||||
[def __BodyWriter__ [link beast.concept.BodyWriter [*BodyWriter]]]
|
[def __BodyWriter__ [link beast.concept.BodyWriter [*BodyWriter]]]
|
||||||
[def __DynamicBuffer__ [link beast.concept.DynamicBuffer [*DynamicBuffer]]]
|
[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 __Stream__ [link beast.concept.streams [*Stream]]]
|
||||||
[def __SyncStream__ [link beast.concept.streams.SyncStream [*SyncStream]]]
|
[def __SyncStream__ [link beast.concept.streams.SyncStream [*SyncStream]]]
|
||||||
|
|
||||||
|
@@ -15,7 +15,8 @@
|
|||||||
[include concept/BufferSequence.qbk]
|
[include concept/BufferSequence.qbk]
|
||||||
[include concept/DynamicBuffer.qbk]
|
[include concept/DynamicBuffer.qbk]
|
||||||
[include concept/Field.qbk]
|
[include concept/Field.qbk]
|
||||||
[include concept/FieldSequence.qbk]
|
[include concept/Fields.qbk]
|
||||||
|
[include concept/FieldsReader.qbk]
|
||||||
[include concept/Streams.qbk]
|
[include concept/Streams.qbk]
|
||||||
|
|
||||||
[endsect]
|
[endsect]
|
||||||
|
@@ -19,7 +19,7 @@ In this table:
|
|||||||
[[expression][type][semantics, pre/post-conditions]]
|
[[expression][type][semantics, pre/post-conditions]]
|
||||||
[
|
[
|
||||||
[`a.name()`]
|
[`a.name()`]
|
||||||
[`boost::string_ref`]
|
[[link beast.ref.string_view `string_view`]]
|
||||||
[
|
[
|
||||||
This function returns a value implicitly convertible to
|
This function returns a value implicitly convertible to
|
||||||
`boost::string_ref` containing the case-insensitive field
|
`boost::string_ref` containing the case-insensitive field
|
||||||
@@ -28,7 +28,7 @@ In this table:
|
|||||||
]
|
]
|
||||||
[
|
[
|
||||||
[`a.value()`]
|
[`a.value()`]
|
||||||
[`boost::string_ref`]
|
[[link beast.ref.string_view `string_view`]]
|
||||||
[
|
[
|
||||||
This function returns a value implicitly convertible to
|
This function returns a value implicitly convertible to
|
||||||
`boost::string_ref` containing the value for the field. The
|
`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.BodyReader">BodyReader</link></member>
|
||||||
<member><link linkend="beast.concept.BodyWriter">BodyWriter</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.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>
|
</simplelist>
|
||||||
</entry>
|
</entry>
|
||||||
<entry valign="top">
|
<entry valign="top">
|
||||||
|
@@ -21,6 +21,12 @@ namespace beast {
|
|||||||
template<class... Buffers>
|
template<class... Buffers>
|
||||||
class buffer_cat_view
|
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_;
|
std::tuple<Buffers...> bn_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@@ -24,6 +24,12 @@ namespace beast {
|
|||||||
template<class... Bn>
|
template<class... Bn>
|
||||||
class buffer_cat_view<Bn...>::const_iterator
|
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::size_t n_;
|
||||||
std::tuple<Bn...> const* bn_;
|
std::tuple<Bn...> const* bn_;
|
||||||
std::array<char, detail::max_sizeof<
|
std::array<char, detail::max_sizeof<
|
||||||
|
@@ -13,6 +13,7 @@
|
|||||||
#include <beast/core/detail/ci_char_traits.hpp>
|
#include <beast/core/detail/ci_char_traits.hpp>
|
||||||
#include <beast/http/connection.hpp>
|
#include <beast/http/connection.hpp>
|
||||||
#include <beast/http/field.hpp>
|
#include <beast/http/field.hpp>
|
||||||
|
#include <boost/asio/buffer.hpp>
|
||||||
#include <boost/lexical_cast.hpp>
|
#include <boost/lexical_cast.hpp>
|
||||||
#include <boost/intrusive/list.hpp>
|
#include <boost/intrusive/list.hpp>
|
||||||
#include <boost/intrusive/set.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
|
as a `std::multiset`; there will be a separate value for each occurrence
|
||||||
of the field name.
|
of the field name.
|
||||||
|
|
||||||
@note Meets the requirements of @b FieldSequence.
|
@note Meets the requirements of @b Fields
|
||||||
*/
|
*/
|
||||||
template<class Allocator>
|
template<class Allocator>
|
||||||
class basic_fields
|
class basic_fields
|
||||||
@@ -259,8 +260,6 @@ public:
|
|||||||
|
|
||||||
@param f The known field constant.
|
@param f The known field constant.
|
||||||
|
|
||||||
@param name The name of the field.
|
|
||||||
|
|
||||||
@param value A string holding the value of the field.
|
@param value A string holding the value of the field.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
@@ -337,54 +336,55 @@ public:
|
|||||||
void
|
void
|
||||||
swap(basic_fields<Alloc>& lhs, basic_fields<Alloc>& rhs);
|
swap(basic_fields<Alloc>& lhs, basic_fields<Alloc>& rhs);
|
||||||
|
|
||||||
|
/// The algorithm used to serialize the header
|
||||||
|
class reader;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
/// Returns `true` if the value for Connection has "close" in the list.
|
||||||
|
bool has_close_impl() const;
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
/// Returns `true` if "chunked" is the last Transfer-Encoding
|
||||||
//
|
bool has_chunked_impl() const;
|
||||||
// for serializing
|
|
||||||
//
|
|
||||||
|
|
||||||
/** 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.
|
/** Set or clear the method string.
|
||||||
*/
|
|
||||||
string_view get_method_impl() const;
|
|
||||||
|
|
||||||
/** Returns the stored request-target string.
|
@note Only called for requests.
|
||||||
|
|
||||||
@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.
|
|
||||||
*/
|
*/
|
||||||
void set_method_impl(string_view s);
|
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);
|
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);
|
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
|
// for container
|
||||||
@@ -418,7 +418,7 @@ protected:
|
|||||||
|
|
||||||
@note This is called by the @ref header implementation.
|
@note This is called by the @ref header implementation.
|
||||||
*/
|
*/
|
||||||
void chunked_impl();
|
void set_chunked_impl(bool v);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
class element
|
class element
|
||||||
@@ -441,6 +441,9 @@ private:
|
|||||||
string_view
|
string_view
|
||||||
value() const;
|
value() const;
|
||||||
|
|
||||||
|
boost::asio::const_buffer
|
||||||
|
buffer() const;
|
||||||
|
|
||||||
value_type data;
|
value_type data;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -8,8 +8,13 @@
|
|||||||
#ifndef BEAST_HTTP_IMPL_FIELDS_IPP
|
#ifndef BEAST_HTTP_IMPL_FIELDS_IPP
|
||||||
#define 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/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 <boost/throw_exception.hpp>
|
||||||
#include <algorithm>
|
#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>
|
template<class Allocator>
|
||||||
basic_fields<Allocator>::
|
basic_fields<Allocator>::
|
||||||
element::
|
element::
|
||||||
@@ -150,6 +326,18 @@ value() const
|
|||||||
static_cast<std::size_t>(len_)};
|
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>
|
template<class Allocator>
|
||||||
@@ -361,31 +549,50 @@ replace(string_view name, string_view value)
|
|||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// Fields
|
||||||
|
|
||||||
template<class Allocator>
|
template<class Allocator>
|
||||||
inline
|
bool
|
||||||
string_view
|
|
||||||
basic_fields<Allocator>::
|
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>
|
template<class Allocator>
|
||||||
inline
|
bool
|
||||||
string_view
|
|
||||||
basic_fields<Allocator>::
|
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>
|
template<class Allocator>
|
||||||
inline
|
bool
|
||||||
string_view
|
|
||||||
basic_fields<Allocator>::
|
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>
|
template<class Allocator>
|
||||||
@@ -415,6 +622,33 @@ set_reason_impl(string_view s)
|
|||||||
realloc_string(target_or_reason_, 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>
|
template<class Allocator>
|
||||||
@@ -474,8 +708,9 @@ template<class Allocator>
|
|||||||
inline
|
inline
|
||||||
void
|
void
|
||||||
basic_fields<Allocator>::
|
basic_fields<Allocator>::
|
||||||
chunked_impl()
|
set_chunked_impl(bool v)
|
||||||
{
|
{
|
||||||
|
BOOST_ASSERT(v);
|
||||||
auto it = find("Transfer-Encoding");
|
auto it = find("Transfer-Encoding");
|
||||||
if(it == end())
|
if(it == end())
|
||||||
this->insert("Transfer-Encoding", "chunked");
|
this->insert("Transfer-Encoding", "chunked");
|
||||||
@@ -682,7 +917,6 @@ swap(basic_fields& other, std::false_type)
|
|||||||
swap(target_or_reason_, other.target_or_reason_);
|
swap(target_or_reason_, other.target_or_reason_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
} // http
|
} // http
|
||||||
} // beast
|
} // beast
|
||||||
|
|
||||||
|
@@ -61,7 +61,7 @@ method_string() const
|
|||||||
template<class Fields>
|
template<class Fields>
|
||||||
void
|
void
|
||||||
header<true, Fields>::
|
header<true, Fields>::
|
||||||
method(string_view s)
|
method_string(string_view s)
|
||||||
{
|
{
|
||||||
method_ = string_to_verb(s);
|
method_ = string_to_verb(s);
|
||||||
if(method_ != verb::unknown)
|
if(method_ != verb::unknown)
|
||||||
@@ -190,21 +190,85 @@ swap(
|
|||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
template<bool isRequest, class Body, class Fields>
|
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
|
bool
|
||||||
message<isRequest, Body, Fields>::
|
message<isRequest, Body, Fields>::
|
||||||
chunked() const
|
has_close() const
|
||||||
{
|
{
|
||||||
auto const it0 = this->find("Transfer-Encoding");
|
return this->has_close_impl();
|
||||||
if(it0 == this->end())
|
}
|
||||||
return false;
|
|
||||||
token_list value{*it0};
|
template<bool isRequest, class Body, class Fields>
|
||||||
for(auto it = value.begin(); it != value.end();)
|
inline
|
||||||
{
|
bool
|
||||||
auto cur = it++;
|
message<isRequest, Body, Fields>::
|
||||||
if(it == value.end())
|
has_chunked() const
|
||||||
return *cur == "chunked";
|
{
|
||||||
}
|
return this->has_chunked_impl();
|
||||||
return false;
|
}
|
||||||
|
|
||||||
|
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>
|
template<bool isRequest, class Body, class Fields>
|
||||||
@@ -326,7 +390,7 @@ prepare_payload(std::true_type)
|
|||||||
}
|
}
|
||||||
else if(this->version >= 11)
|
else if(this->version >= 11)
|
||||||
{
|
{
|
||||||
this->chunked_impl();
|
this->set_chunked_impl(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -350,7 +414,7 @@ prepare_payload(std::false_type)
|
|||||||
if(n)
|
if(n)
|
||||||
this->content_length_impl(*n);
|
this->content_length_impl(*n);
|
||||||
else if(this->version >= 11)
|
else if(this->version >= 11)
|
||||||
this->chunked_impl();
|
this->set_chunked_impl(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
@@ -15,59 +15,27 @@
|
|||||||
|
|
||||||
namespace beast {
|
namespace beast {
|
||||||
namespace http {
|
namespace http {
|
||||||
namespace detail {
|
|
||||||
|
|
||||||
template<class Fields>
|
template<bool isRequest, class Body, class Fields,
|
||||||
|
class ChunkDecorator, class Allocator>
|
||||||
void
|
void
|
||||||
write_start_line(std::ostream& os,
|
serializer<isRequest, Body, Fields,
|
||||||
header<true, Fields> const& msg)
|
ChunkDecorator, Allocator>::
|
||||||
|
frdinit(std::true_type)
|
||||||
{
|
{
|
||||||
// VFALCO This should all be done without dynamic allocation
|
frd_.emplace(m_, m_.version, m_.method());
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class Fields>
|
template<bool isRequest, class Body, class Fields,
|
||||||
|
class ChunkDecorator, class Allocator>
|
||||||
void
|
void
|
||||||
write_start_line(std::ostream& os,
|
serializer<isRequest, Body, Fields,
|
||||||
header<false, Fields> const& msg)
|
ChunkDecorator, Allocator>::
|
||||||
|
frdinit(std::false_type)
|
||||||
{
|
{
|
||||||
// VFALCO This should all be done without dynamic allocation
|
frd_.emplace(m_, m_.version, m_.result_int());
|
||||||
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";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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,
|
template<bool isRequest, class Body, class Fields,
|
||||||
class ChunkDecorator, class Allocator>
|
class ChunkDecorator, class Allocator>
|
||||||
serializer<isRequest, Body, Fields,
|
serializer<isRequest, Body, Fields,
|
||||||
@@ -76,7 +44,6 @@ serializer(message<isRequest, Body, Fields> const& m,
|
|||||||
ChunkDecorator const& d, Allocator const& alloc)
|
ChunkDecorator const& d, Allocator const& alloc)
|
||||||
: m_(m)
|
: m_(m)
|
||||||
, d_(d)
|
, d_(d)
|
||||||
, b_(1024, alloc)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -93,15 +60,11 @@ get(error_code& ec, Visit&& visit)
|
|||||||
{
|
{
|
||||||
case do_construct:
|
case do_construct:
|
||||||
{
|
{
|
||||||
chunked_ = token_list{
|
frdinit(std::integral_constant<bool,
|
||||||
m_["Transfer-Encoding"]}.exists("chunked");
|
isRequest>{});
|
||||||
close_ = token_list{m_["Connection"]}.exists("close") ||
|
close_ = m_.has_close() || (
|
||||||
(m_.version < 11 && ! m_.exists("Content-Length"));
|
m_.version < 11 && ! m_.has_content_length());
|
||||||
auto os = ostream(b_);
|
if(m_.has_chunked())
|
||||||
detail::write_start_line(os, m_);
|
|
||||||
detail::write_fields(os, m_);
|
|
||||||
os << "\r\n";
|
|
||||||
if(chunked_)
|
|
||||||
goto go_init_c;
|
goto go_init_c;
|
||||||
s_ = do_init;
|
s_ = do_init;
|
||||||
// [[fallthrough]]
|
// [[fallthrough]]
|
||||||
@@ -127,7 +90,7 @@ get(error_code& ec, Visit&& visit)
|
|||||||
more_ = result->second;
|
more_ = result->second;
|
||||||
v_ = cb0_t{
|
v_ = cb0_t{
|
||||||
boost::in_place_init,
|
boost::in_place_init,
|
||||||
b_.data(),
|
frd_->get(),
|
||||||
result->first};
|
result->first};
|
||||||
s_ = do_header;
|
s_ = do_header;
|
||||||
// [[fallthrough]]
|
// [[fallthrough]]
|
||||||
@@ -137,10 +100,11 @@ get(error_code& ec, Visit&& visit)
|
|||||||
visit(ec, boost::get<cb0_t>(v_));
|
visit(ec, boost::get<cb0_t>(v_));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
go_header_only:
|
go_header_only:
|
||||||
s_ = do_header_only;
|
v_ = ch_t{frd_->get()};
|
||||||
|
s_ = do_header_only;
|
||||||
case do_header_only:
|
case do_header_only:
|
||||||
visit(ec, b_.data());
|
visit(ec, boost::get<ch_t>(v_));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case do_body:
|
case do_body:
|
||||||
@@ -193,7 +157,7 @@ get(error_code& ec, Visit&& visit)
|
|||||||
more_ = result->second;
|
more_ = result->second;
|
||||||
v_ = ch0_t{
|
v_ = ch0_t{
|
||||||
boost::in_place_init,
|
boost::in_place_init,
|
||||||
b_.data(),
|
frd_->get(),
|
||||||
detail::chunk_header{
|
detail::chunk_header{
|
||||||
buffer_size(result->first)},
|
buffer_size(result->first)},
|
||||||
[&]()
|
[&]()
|
||||||
@@ -214,10 +178,11 @@ get(error_code& ec, Visit&& visit)
|
|||||||
visit(ec, boost::get<ch0_t>(v_));
|
visit(ec, boost::get<ch0_t>(v_));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
go_header_only_c:
|
go_header_only_c:
|
||||||
s_ = do_header_only_c;
|
v_ = ch_t{frd_->get()};
|
||||||
|
s_ = do_header_only_c;
|
||||||
case do_header_only_c:
|
case do_header_only_c:
|
||||||
visit(ec, b_.data());
|
visit(ec, boost::get<ch_t>(v_));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case do_body_c:
|
case do_body_c:
|
||||||
@@ -311,18 +276,18 @@ consume(std::size_t n)
|
|||||||
break;
|
break;
|
||||||
header_done_ = true;
|
header_done_ = true;
|
||||||
v_ = boost::blank{};
|
v_ = boost::blank{};
|
||||||
b_.consume(b_.size()); // VFALCO delete b_?
|
|
||||||
if(! more_)
|
if(! more_)
|
||||||
goto go_complete;
|
goto go_complete;
|
||||||
s_ = do_body + 1;
|
s_ = do_body + 1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case do_header_only:
|
case do_header_only:
|
||||||
BOOST_ASSERT(n <= b_.size());
|
BOOST_ASSERT(n <= buffer_size(
|
||||||
b_.consume(n);
|
boost::get<ch_t>(v_)));
|
||||||
if(buffer_size(b_.data()) > 0)
|
boost::get<ch_t>(v_).consume(n);
|
||||||
|
if(buffer_size(boost::get<ch_t>(v_)) > 0)
|
||||||
break;
|
break;
|
||||||
// VFALCO delete b_?
|
frd_ = boost::none;
|
||||||
header_done_ = true;
|
header_done_ = true;
|
||||||
if(! split_)
|
if(! split_)
|
||||||
goto go_complete;
|
goto go_complete;
|
||||||
@@ -353,7 +318,6 @@ consume(std::size_t n)
|
|||||||
break;
|
break;
|
||||||
header_done_ = true;
|
header_done_ = true;
|
||||||
v_ = boost::blank{};
|
v_ = boost::blank{};
|
||||||
b_.consume(b_.size()); // VFALCO delete b_?
|
|
||||||
if(more_)
|
if(more_)
|
||||||
s_ = do_body_c + 1;
|
s_ = do_body_c + 1;
|
||||||
else
|
else
|
||||||
@@ -362,11 +326,12 @@ consume(std::size_t n)
|
|||||||
|
|
||||||
case do_header_only_c:
|
case do_header_only_c:
|
||||||
{
|
{
|
||||||
BOOST_ASSERT(n <= buffer_size(b_.data()));
|
BOOST_ASSERT(n <= buffer_size(
|
||||||
b_.consume(n);
|
boost::get<ch_t>(v_)));
|
||||||
if(buffer_size(b_.data()) > 0)
|
boost::get<ch_t>(v_).consume(n);
|
||||||
|
if(buffer_size(boost::get<ch_t>(v_)) > 0)
|
||||||
break;
|
break;
|
||||||
// VFALCO delete b_?
|
frd_ = boost::none;
|
||||||
header_done_ = true;
|
header_done_ = true;
|
||||||
if(! split_)
|
if(! split_)
|
||||||
{
|
{
|
||||||
|
@@ -822,16 +822,15 @@ public:
|
|||||||
|
|
||||||
} // detail
|
} // detail
|
||||||
|
|
||||||
|
#if 0
|
||||||
template<bool isRequest, class Fields>
|
template<bool isRequest, class Fields>
|
||||||
std::ostream&
|
std::ostream&
|
||||||
operator<<(std::ostream& os,
|
operator<<(std::ostream& os,
|
||||||
header<isRequest, Fields> const& msg)
|
header<isRequest, Fields> const& msg)
|
||||||
{
|
{
|
||||||
detail::write_start_line(os, msg);
|
// VFALCO TODO
|
||||||
detail::write_fields(os, msg);
|
|
||||||
os << "\r\n";
|
|
||||||
return os;
|
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
template<bool isRequest, class Body, class Fields>
|
template<bool isRequest, class Body, class Fields>
|
||||||
std::ostream&
|
std::ostream&
|
||||||
|
@@ -119,7 +119,7 @@ struct header<true, Fields> : Fields
|
|||||||
verb
|
verb
|
||||||
method() const;
|
method() const;
|
||||||
|
|
||||||
/** Set the request-method verb.
|
/** Set the request-method.
|
||||||
|
|
||||||
This function will set the method for requests to a known verb.
|
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.
|
This may not be @ref verb::unknown.
|
||||||
|
|
||||||
@throw std::invalid_argument when `v == verb::unknown`.
|
@throw std::invalid_argument when `v == verb::unknown`.
|
||||||
|
|
||||||
|
@note This function is only available when `isRequest == true`.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
method(verb v);
|
method(verb v);
|
||||||
|
|
||||||
/** Return the request-method string.
|
/** Return the request-method as a string.
|
||||||
|
|
||||||
@note This function is only available when `isRequest == true`.
|
@note This function is only available when `isRequest == true`.
|
||||||
|
|
||||||
@@ -140,18 +142,18 @@ struct header<true, Fields> : Fields
|
|||||||
string_view
|
string_view
|
||||||
method_string() const;
|
method_string() const;
|
||||||
|
|
||||||
/** Set the request-method string.
|
/** Set the request-method.
|
||||||
|
|
||||||
This function will set the method for requests to a verb
|
This function will set the request-method a known verb
|
||||||
if the string matches a known verb, otherwise it will
|
if the string matches, otherwise it will store a copy of
|
||||||
store a copy of the passed string as the method.
|
the passed string.
|
||||||
|
|
||||||
@param s A string representing the request-method.
|
@param s A string representing the request-method.
|
||||||
|
|
||||||
@note This function is only available when `isRequest == true`.
|
@note This function is only available when `isRequest == true`.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
method(string_view s);
|
method_string(string_view s);
|
||||||
|
|
||||||
/** Returns the request-target string.
|
/** Returns the request-target string.
|
||||||
|
|
||||||
@@ -382,31 +384,27 @@ struct message : header<isRequest, Fields>
|
|||||||
/// Copy assignment
|
/// Copy assignment
|
||||||
message& operator=(message const&) = default;
|
message& operator=(message const&) = default;
|
||||||
|
|
||||||
/** Construct a message from a header.
|
/** Constructor.
|
||||||
|
|
||||||
Additional arguments, if any, are forwarded to
|
@param h The header to move construct from.
|
||||||
the constructor of the body member.
|
|
||||||
|
@param args Optional arguments forwarded
|
||||||
|
to the body constructor.
|
||||||
*/
|
*/
|
||||||
template<class... Args>
|
template<class... Args>
|
||||||
explicit
|
explicit
|
||||||
message(header_type&& base, Args&&... args)
|
message(header_type&& h, Args&&... args);
|
||||||
: header_type(std::move(base))
|
|
||||||
, body(std::forward<Args>(args)...)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Construct a message from a header.
|
/** Constructor.
|
||||||
|
|
||||||
Additional arguments, if any, are forwarded to
|
@param h The header to copy construct from.
|
||||||
the constructor of the body member.
|
|
||||||
|
@param args Optional arguments forwarded
|
||||||
|
to the body constructor.
|
||||||
*/
|
*/
|
||||||
template<class... Args>
|
template<class... Args>
|
||||||
explicit
|
explicit
|
||||||
message(header_type const& base, Args&&... args)
|
message(header_type const& h, Args&&... args);
|
||||||
: header_type(base)
|
|
||||||
, body(std::forward<Args>(args)...)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Construct a message.
|
/** Construct a message.
|
||||||
|
|
||||||
@@ -423,10 +421,7 @@ struct message : header<isRequest, Fields>
|
|||||||
#endif
|
#endif
|
||||||
>
|
>
|
||||||
explicit
|
explicit
|
||||||
message(U&& u)
|
message(U&& u);
|
||||||
: body(std::forward<U>(u))
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Construct a message.
|
/** Construct a message.
|
||||||
|
|
||||||
@@ -443,22 +438,14 @@ struct message : header<isRequest, Fields>
|
|||||||
typename std::decay<U>::type, header_type>::value>::type
|
typename std::decay<U>::type, header_type>::value>::type
|
||||||
#endif
|
#endif
|
||||||
>
|
>
|
||||||
message(U&& u, V&& v)
|
message(U&& u, V&& v);
|
||||||
: header_type(std::forward<V>(v))
|
|
||||||
, body(std::forward<U>(u))
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Construct a message.
|
/** Construct a message.
|
||||||
|
|
||||||
@param un A tuple forwarded as a parameter pack to the body constructor.
|
@param un A tuple forwarded as a parameter pack to the body constructor.
|
||||||
*/
|
*/
|
||||||
template<class... Un>
|
template<class... Un>
|
||||||
message(std::piecewise_construct_t, std::tuple<Un...> un)
|
message(std::piecewise_construct_t, std::tuple<Un...> un);
|
||||||
: message(std::piecewise_construct, un,
|
|
||||||
beast::detail::make_index_sequence<sizeof...(Un)>{})
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Construct a message.
|
/** Construct a message.
|
||||||
|
|
||||||
@@ -468,17 +455,25 @@ struct message : header<isRequest, Fields>
|
|||||||
*/
|
*/
|
||||||
template<class... Un, class... Vn>
|
template<class... Un, class... Vn>
|
||||||
message(std::piecewise_construct_t,
|
message(std::piecewise_construct_t,
|
||||||
std::tuple<Un...>&& un, std::tuple<Vn...>&& vn)
|
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)>{})
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 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
|
bool
|
||||||
chunked() const;
|
has_content_length() const;
|
||||||
|
|
||||||
/** Returns the payload size of the body in octets if possible.
|
/** Returns the payload size of the body in octets if possible.
|
||||||
|
|
||||||
|
@@ -189,7 +189,7 @@ private:
|
|||||||
if(method != verb::unknown)
|
if(method != verb::unknown)
|
||||||
m_.method(method);
|
m_.method(method);
|
||||||
else
|
else
|
||||||
m_.method(method_str);
|
m_.method_string(method_str);
|
||||||
m_.version = version;
|
m_.version = version;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -241,17 +241,15 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
on_data(string_view s,
|
on_data(string_view s, error_code& ec)
|
||||||
error_code& ec)
|
|
||||||
{
|
{
|
||||||
wr_->put(boost::asio::buffer(
|
wr_->put(boost::asio::buffer(
|
||||||
s.data(), s.size()), ec);
|
s.data(), s.size()), ec);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
on_chunk(
|
on_chunk(std::uint64_t,
|
||||||
std::uint64_t, string_view,
|
string_view, error_code&)
|
||||||
error_code&)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -12,7 +12,6 @@
|
|||||||
#include <beast/core/async_result.hpp>
|
#include <beast/core/async_result.hpp>
|
||||||
#include <beast/core/buffer_cat.hpp>
|
#include <beast/core/buffer_cat.hpp>
|
||||||
#include <beast/core/consuming_buffers.hpp>
|
#include <beast/core/consuming_buffers.hpp>
|
||||||
#include <beast/core/multi_buffer.hpp>
|
|
||||||
#include <beast/core/string_view.hpp>
|
#include <beast/core/string_view.hpp>
|
||||||
#include <beast/core/type_traits.hpp>
|
#include <beast/core/type_traits.hpp>
|
||||||
#include <beast/http/message.hpp>
|
#include <beast/http/message.hpp>
|
||||||
@@ -155,24 +154,26 @@ class serializer
|
|||||||
|
|
||||||
void split(bool, std::true_type) {}
|
void split(bool, std::true_type) {}
|
||||||
void split(bool v, std::false_type) { split_ = v; }
|
void split(bool v, std::false_type) { split_ = v; }
|
||||||
|
void frdinit(std::true_type);
|
||||||
using buffer_type =
|
void frdinit(std::false_type);
|
||||||
basic_multi_buffer<Allocator>;
|
|
||||||
|
|
||||||
using reader = typename Body::reader;
|
using reader = typename Body::reader;
|
||||||
|
|
||||||
using is_deferred =
|
using is_deferred =
|
||||||
typename reader::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<
|
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
|
typename reader::const_buffers_type>>; // body
|
||||||
|
|
||||||
using cb1_t = consuming_buffers<
|
using cb1_t = consuming_buffers<
|
||||||
typename reader::const_buffers_type>; // body
|
typename reader::const_buffers_type>; // body
|
||||||
|
|
||||||
using ch0_t = consuming_buffers<buffer_cat_view<
|
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
|
detail::chunk_header, // chunk-header
|
||||||
boost::asio::const_buffers_1, // chunk-ext
|
boost::asio::const_buffers_1, // chunk-ext
|
||||||
boost::asio::const_buffers_1, // crlf
|
boost::asio::const_buffers_1, // crlf
|
||||||
@@ -192,11 +193,11 @@ class serializer
|
|||||||
boost::asio::const_buffers_1>>; // crlf
|
boost::asio::const_buffers_1>>; // crlf
|
||||||
|
|
||||||
message<isRequest, Body, Fields> const& m_;
|
message<isRequest, Body, Fields> const& m_;
|
||||||
|
boost::optional<typename Fields::reader> frd_;
|
||||||
ChunkDecorator d_;
|
ChunkDecorator d_;
|
||||||
boost::optional<reader> rd_;
|
boost::optional<reader> rd_;
|
||||||
buffer_type b_;
|
|
||||||
boost::variant<boost::blank,
|
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;
|
int s_ = do_construct;
|
||||||
bool split_ = is_deferred::value;
|
bool split_ = is_deferred::value;
|
||||||
bool header_done_ = false;
|
bool header_done_ = false;
|
||||||
|
@@ -68,7 +68,7 @@ public:
|
|||||||
flat_buffer buffer;
|
flat_buffer buffer;
|
||||||
request<string_body> req;
|
request<string_body> req;
|
||||||
req.version = 11;
|
req.version = 11;
|
||||||
req.method("POST");
|
req.method_string("POST");
|
||||||
req.target("/");
|
req.target("/");
|
||||||
req.insert(field::user_agent, "test");
|
req.insert(field::user_agent, "test");
|
||||||
req.body = "Hello, world!";
|
req.body = "Hello, world!";
|
||||||
@@ -101,7 +101,7 @@ public:
|
|||||||
{
|
{
|
||||||
request<string_body> req;
|
request<string_body> req;
|
||||||
req.version = 11;
|
req.version = 11;
|
||||||
req.method("POST");
|
req.method_string("POST");
|
||||||
req.target("/");
|
req.target("/");
|
||||||
req.insert(field::user_agent, "test");
|
req.insert(field::user_agent, "test");
|
||||||
req.body = "Hello, world!";
|
req.body = "Hello, world!";
|
||||||
|
@@ -134,7 +134,7 @@ public:
|
|||||||
m1.target("u");
|
m1.target("u");
|
||||||
m1.body = "1";
|
m1.body = "1";
|
||||||
m1.insert("h", "v");
|
m1.insert("h", "v");
|
||||||
m2.method("G");
|
m2.method_string("G");
|
||||||
m2.body = "2";
|
m2.body = "2";
|
||||||
swap(m1, m2);
|
swap(m1, m2);
|
||||||
BEAST_EXPECT(m1.method_string() == "G");
|
BEAST_EXPECT(m1.method_string() == "G");
|
||||||
@@ -268,7 +268,7 @@ public:
|
|||||||
auto const scheck =
|
auto const scheck =
|
||||||
[&](string_view s)
|
[&](string_view s)
|
||||||
{
|
{
|
||||||
h.method(s);
|
h.method_string(s);
|
||||||
BEAST_EXPECT(h.method() == string_to_verb(s));
|
BEAST_EXPECT(h.method() == string_to_verb(s));
|
||||||
BEAST_EXPECT(h.method_string() == s);
|
BEAST_EXPECT(h.method_string() == s);
|
||||||
};
|
};
|
||||||
|
Reference in New Issue
Block a user