Refactor type_traits (API Change):

fix #373

* concepts.hpp is renamed to type_traits.hpp

* Body reader and writer concepts are renamed
This commit is contained in:
Vinnie Falco
2017-05-28 09:05:29 -07:00
parent 3664329ea7
commit 75b0571e83
32 changed files with 435 additions and 462 deletions

View File

@@ -6,6 +6,7 @@ API Changes:
* Remove HTTP header aliases * Remove HTTP header aliases
* Refactor HTTP serialization * Refactor HTTP serialization
* Refactor type traits
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------

View File

@@ -13,10 +13,10 @@ the algorithms used during parsing and serialization.
In this table: In this table:
* `X` is a type meeting the requirements of [*`Body`]. * `X` is a type meeting the requirements of [*Body].
[table Body requirements [table Body requirements
[[operation] [type] [semantics, pre/post-conditions]] [[expression] [type] [semantics, pre/post-conditions]]
[ [
[`X::value_type`] [`X::value_type`]
[] []
@@ -26,22 +26,34 @@ In this table:
will be not movable or not copyable. will be not movable or not copyable.
] ]
] ]
[
[`X::reader`]
[]
[
If present, a type meeting the requirements of
[link beast.ref.Reader [*`Reader`]].
Provides an implementation to parse the body.
]
]
[ [
[`X::writer`] [`X::writer`]
[] []
[ [
If present, a type meeting the requirements of If present, indicates that the body can hold a message body
[link beast.ref.Writer [*`Writer`]]. parsing result. The type must meet the requirements of
Provides an implementation to serialize the body. [link beast.ref.BodyWriter [*BodyWriter]]. The implementation
constructs an object of this type to obtain buffers into which
parsed body octets are placed.
]
]
[
[`X::reader`]
[]
[
If present, indicates that the body is serializable.
The type must meet the requirements of
[link beast.ref.BodyReader [*BodyReader]]. The implementation
constructs an object of this type to obtain buffers representing
the message body for serialization.
]
]
[
[`is_body<X>`]
[`std::true_type`]
[
An alias for `std::true_type` for `X`, otherwise an alias
for `std::false_type`.
] ]
] ]
] ]

View File

@@ -5,44 +5,53 @@
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
] ]
[section:Writer Writer requirements] [section:BodyReader BodyReader requirements]
A [*Writer] provides an online algorithm to obtain a sequence of zero A [*BodyReader] provides an online algorithm to obtain a sequence of zero
or more buffers from a body during serialization. The implementation creates or more buffers from a body during serialization. The implementation creates
an instance of this type when needed, and calls into it zero or more times to an instance of this type when needed, and calls into it one or more times to
retrieve buffers with body octets. The interface of [*Writer] is intended to retrieve buffers holding body octets. The interface of [*BodyReader] is
allow serialization in these scenarios: intended to obtain buffers for these scenarios:
* A body that does not entirely fit in memory. * A body that does not entirely fit in memory.
* A body produced incrementally from coroutine output. * A body produced incrementally from coroutine output.
* A body represented by zero or more buffers already in memory. * A body represented by zero or more buffers already in memory.
* A body as a series of buffers when the content size is not known ahead of time. * A body whose size is not known ahead of time.
* Body data generated on demand from other threads. * Body data generated dynamically from other threads.
* Body data computed algorithmically. * Body data computed algorithmically.
In this table: In this table:
* `X` denotes a type meeting the requirements of [*Writer]. * `X` denotes a type meeting the requirements of [*BodyReader].
* `B` denotes a __Body__ where
`std::is_same<X, B::reader>::value == true`.
* `a` denotes a value of type `X`. * `a` denotes a value of type `X`.
* `m` denotes a value of type `message const&` where * `m` denotes a value of type `message const&` where
`std::is_same<decltype(m.body), Body::value_type>:value == true`. `std::is_same<decltype(m.body), Body::value_type>:value == true`.
* `ec` is a value of type [link beast.ref.error_code `error_code&`]. * `ec` is a value of type [link beast.ref.error_code `error_code&`].
* `B<T>` is the type `boost::optional<std::pair<T, bool>>`. * `R<T>` is the type `boost::optional<std::pair<T, bool>>`.
[table Writer requirements [table BodyReader requirements
[[operation] [type] [semantics, pre/post-conditions]] [[expression] [type] [semantics, pre/post-conditions]]
[ [
[`X::const_buffers_type`] [`X::const_buffers_type`]
[] []
[ [
A nested type which meets the requirements of __ConstBufferSequence__. A type which meets the requirements of __ConstBufferSequence__.
This is the type of buffer returned by `X::get`. This is the type of buffer returned by `X::get`.
] ]
] ]
[
[`X::is_deferred`]
[]
[
]
]
[ [
[`X(m);`] [`X(m);`]
[] []
@@ -53,7 +62,7 @@ In this table:
] ]
[ [
[`a.init(ec)`] [`a.init(ec)`]
[`void`] []
[ [
Called immediately after construction. If the function sets an Called immediately after construction. If the function sets an
error code in `ec`, the serialization is aborted and the error error code in `ec`, the serialization is aborted and the error
@@ -77,7 +86,7 @@ In this table:
] ]
[ [
[`a.get(ec)`] [`a.get(ec)`]
[`B<X::const_buffers_type>`] [`R<X::const_buffers_type>`]
[ [
Called repeatedly after `init` succeeds. This function returns Called repeatedly after `init` succeeds. This function returns
`boost::none` if all buffers representing the body have been `boost::none` if all buffers representing the body have been
@@ -92,23 +101,24 @@ In this table:
] ]
] ]
[ [
[`http::is_Writer<X>`] [`is_body_reader<B>`]
[`std::true_type`] [`std::true_type`]
[ [
An alias for `std::true_type` for `X`, otherwise an An alias for `std::true_type` for `B`, otherwise an alias
alias for `std::false_type`. for `std::false_type`.
] ]
] ]
] ]
[note [note
Definitions for required `Writer` member functions should be declared Definitions for required [*BodyReader] member functions should
inline so the generated code can become part of the implementation. be declared inline so the generated code can become part of the
implementation.
] ]
Exemplar: Exemplar:
``` ```
struct writer struct reader
{ {
public: public:
/** Controls when the implementation requests buffers. /** Controls when the implementation requests buffers.
@@ -124,22 +134,19 @@ public:
*/ */
using const_buffers_type = boost::asio::const_buffers_1; using const_buffers_type = boost::asio::const_buffers_1;
/** Construct the writer. /** Construct the reader.
The msg object is guaranteed to exist for the lifetime of the writer.
@param msg The message whose body is to be written. @param msg The message whose body is to be written.
*/ */
template<bool isRequest, class Body, class Headers> template<bool isRequest, class Body, class Headers>
explicit explicit
writer(message<isRequest, Body, Headers> const& msg); reader(message<isRequest, Body, Headers> const& msg);
/** Initialize the writer. /** Initialization.
Called once immediately after construction. Called once immediately after construction.
The writer can perform initialization which may fail.
@param ec Contains the error code if any errors occur. @param ec Set to the error, if any occurred.
*/ */
void void
init(error_code& ec); init(error_code& ec);
@@ -147,9 +154,9 @@ public:
/** Returns the content length. /** Returns the content length.
If this member is present, the implementation will set the If this member is present, the implementation will set the
Content-Length field accordingly. If absent, the implementation will Content-Length field accordingly. If absent, the implementation
use chunk-encoding or terminate the connection to indicate the end will use chunk-encoding or terminate the connection to indicate
of the message. the end of the message.
*/ */
std::uint64_t std::uint64_t
content_length(); content_length();
@@ -170,7 +177,6 @@ public:
@li If `ec` contains an error code, the return value is ignored. @li If `ec` contains an error code, the return value is ignored.
*/ */
template<class WriteFunction>
boost::optional<std::pair<const_buffers_type, bool>> boost::optional<std::pair<const_buffers_type, bool>>
get(error_code& ec); get(error_code& ec);
}; };

View File

@@ -5,25 +5,25 @@
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
] ]
[section:Reader Reader requirements] [section:BodyWriter BodyWriter requirements]
Parsers provided by the implementation will construct the corresponding When HTTP messages are parsed, the implementation constructs a
`reader` object during parsing. This customization point allows the [*BodyWriter] object to provide the means for transferring parsed body
Body to determine the strategy for storing incoming message body data. octets into the message container. These body writers come in two flavors,
Readers come in two flavors, direct and indirect: direct and indirect:
Direct readers provide a buffer to callers, in which body data is placed. Direct writers provide a buffer to callers, into which body data is placed.
This type of reader is used when the bytes corresponding to the body data This type of writer is used when the bytes corresponding to the body data
are stored without transformation. The parse algorithm performs stream or are stored without transformation. The parse algorithm performs stream or
socket reads directly into the reader-provided buffer, hence the name socket reads directly into the buffer provided by the writer, hence the name
"direct." This model avoids an unnecessary buffer copy. An example of "direct." This model avoids an unnecessary buffer copy. An example of
a [*Body] type with a direct reader is a __Body__ type with a direct writer is
[link beast.ref.http__string_body `string_body`]. [link beast.ref.http__string_body `string_body`].
Indirect readers are passed body data in a buffer managed by the parser Indirect writers are passed body data in a buffer managed by the parsing
algorithm. This reader is appropriate when the body data is transformed algorithm. This writer is appropriate when the body data is transformed
or not otherwised stored verbatim. Some examples of when an indirect or not otherwised stored verbatim. Some examples of when an indirect
reader is appropriate: writer is appropriate:
* When bytes corresponding to the body are written to a file * When bytes corresponding to the body are written to a file
as they are parsed. as they are parsed.
@@ -33,7 +33,10 @@ reader is appropriate:
In the tables below: In the tables below:
* `X` denotes a type meeting the requirements of [*`Reader`]. * `X` denotes a type meeting the requirements of [*Writer].
* `B` denotes a __Body__ where
`std::is_same<X, B::writer>::value == true`.
* `a` denotes a value of type `X`. * `a` denotes a value of type `X`.
@@ -41,31 +44,28 @@ In the tables below:
* `v` is a value convertible to `std::uint64_t` without loss of precision. * `v` is a value convertible to `std::uint64_t` without loss of precision.
* `s` is a value of type `boost::string_ref`. * `s` is a value of type [link beast.ref.string_view `string_view`].
* `ec` is a value of type [link beast.ref.error_code `error_code&`]. * `ec` is a value of type [link beast.ref.error_code `error_code&`].
* `m` denotes a value of type `message&` where * `m` denotes a value of type `message&` where
`std::is_same<decltype(m.body), Body::value_type>::value == true`. `std::is_same<decltype(m.body), Body::value_type>::value == true`.
[table Direct Reader requirements [table Direct Writer requirements
[[operation] [type] [semantics, pre/post-conditions]] [[expression] [type] [semantics, pre/post-conditions]]
[ [
[`X::is_direct`] [`X::is_direct`]
[`bool`] [`bool`]
[ [
This static constant must be set to `true` to indicate that This static constant must be set to `true` to indicate this
the reader is a direct reader. is a direct writer.
] ]
] ]
[ [
[`X::mutable_buffers_type`] [`X::mutable_buffers_type`]
[] []
[ [
This member type must be present, and meet the requirements A type which meets the requirements of __MutableBufferSequence__.
of [*MutableBufferSequence]. It represents the type of
the writable buffers returned by the reader, in which
bytes representing the body are stored by the implementation.
] ]
] ]
[ [
@@ -85,7 +85,7 @@ In the tables below:
[] []
[ [
This function is called once before any bytes corresponding This function is called once before any bytes corresponding
to the body are presented to the reader, for messages whose to the body are presented to the writer, for messages whose
body is determined by the end-of-file marker on a stream, body is determined by the end-of-file marker on a stream,
or for messages where the chunked Transfer-Encoding is or for messages where the chunked Transfer-Encoding is
specified. specified.
@@ -96,14 +96,14 @@ In the tables below:
[] []
[ [
This function is called once before any bytes corresponding This function is called once before any bytes corresponding
to the body are presented to the reader, for messages where to the body are presented to the writer, for messages where
the Content-Length is specified. The value of `v` will be the Content-Length is specified. The value of `v` will be
set to the number of bytes indicated by the content length. set to the number of bytes indicated by the content length.
] ]
] ]
[ [
[`a.prepare(n)`] [`a.prepare(n)`]
[`mutable_buffers_type`] [`X::mutable_buffers_type`]
[ [
The implementation calls this function to obtain a mutable The implementation calls this function to obtain a mutable
buffer sequence of up to `n` bytes in size in which to place buffer sequence of up to `n` bytes in size in which to place
@@ -116,7 +116,7 @@ In the tables below:
[] []
[ [
The implementation calls this function to indicate to the The implementation calls this function to indicate to the
reader that `n` bytes of data have been successfully placed writer that `n` bytes of data have been successfully placed
into the buffer obtained through a prior call to `prepare`. into the buffer obtained through a prior call to `prepare`.
The value of `n` will be less than or equal to the size of The value of `n` will be less than or equal to the size of
the buffer returned in the previous call to `prepare`. the buffer returned in the previous call to `prepare`.
@@ -130,16 +130,24 @@ In the tables below:
to the body have been written to the buffers and committed. to the body have been written to the buffers and committed.
] ]
] ]
[
[`is_body_writer<B>`]
[`std::true_type`]
[
An alias for `std::true_type` for `B`, otherwise an alias
for `std::false_type`.
]
]
] ]
[table Indirect Reader requirements [table Indirect Writer requirements
[[operation] [type] [semantics, pre/post-conditions]] [[expression] [type] [semantics, pre/post-conditions]]
[ [
[`X::is_direct`] [`X::is_direct`]
[`bool`] [`bool`]
[ [
This static constant must be set to `false` to indicate that This static constant must be set to `false` to indicate this
the reader is an indirect reader. is an indirect writer.
] ]
] ]
[ [
@@ -159,7 +167,7 @@ In the tables below:
[] []
[ [
This function is called once before any bytes corresponding This function is called once before any bytes corresponding
to the body are presented to the reader, for messages whose to the body are presented to the writer, for messages whose
body is determined by the end-of-file market on a stream, body is determined by the end-of-file market on a stream,
or for messages where the chunked Transfer-Encoding is or for messages where the chunked Transfer-Encoding is
specified. specified.
@@ -173,7 +181,7 @@ In the tables below:
[] []
[ [
This function is called once before any bytes corresponding This function is called once before any bytes corresponding
to the body are presented to the reader, for messages where to the body are presented to the writer, for messages where
the Content-Length is specified. The value of `v` will be the Content-Length is specified. The value of `v` will be
set to the number of bytes indicated by the content length. set to the number of bytes indicated by the content length.
If `ec` is set before returning, parsing will stop If `ec` is set before returning, parsing will stop
@@ -201,9 +209,17 @@ In the tables below:
and the error will be returned to the caller. and the error will be returned to the caller.
] ]
] ]
[
[`is_body_writer<B>`]
[`std::true_type`]
[
An alias for `std::true_type` for `B`, otherwise an alias
for `std::false_type`.
]
]
] ]
[note [note
Definitions for required `Reader` member functions should be declared Definitions for required [*Writer] member functions should be declared
inline so the generated code can become part of the implementation. inline so the generated code can become part of the implementation.
] ]

View File

@@ -41,7 +41,7 @@ In the table below:
* `U` denotes a type meeting the requirements for __MutableBufferSequence__. * `U` denotes a type meeting the requirements for __MutableBufferSequence__.
[table DynamicBuffer requirements [table DynamicBuffer requirements
[[operation] [type] [semantics, pre/post-conditions]] [[expression] [type] [semantics, pre/post-conditions]]
[ [
[`X::const_buffers_type`] [`X::const_buffers_type`]
[`T`] [`T`]

View File

@@ -7,16 +7,16 @@
[section:Field Field requirements] [section:Field Field requirements]
A [*`Field`] represents a single HTTP header field/value pair. A [*Field] represents a single HTTP header field/value pair.
In this table: In this table:
* `X` denotes a type meeting the requirements of [*`Field`]. * `X` denotes a type meeting the requirements of [*Field].
* `a` denotes a value of type `X`. * `a` denotes a value of type `X`.
[table Field requirements [table Field requirements
[[operation][type][semantics, pre/post-conditions]] [[expression][type][semantics, pre/post-conditions]]
[ [
[`a.name()`] [`a.name()`]
[`boost::string_ref`] [`boost::string_ref`]

View File

@@ -18,7 +18,7 @@ In this table:
* `c` is a value of type `X const`. * `c` is a value of type `X const`.
[table FieldSequence requirements [table FieldSequence requirements
[[operation][type][semantics, pre/post-conditions]] [[expression][type][semantics, pre/post-conditions]]
[ [
[`X::value_type`] [`X::value_type`]
[] []

View File

@@ -12,21 +12,21 @@ asynchronous I/O. They are based on concepts from `boost::asio`.
[heading:Stream Stream] [heading:Stream Stream]
A type modeling [*`Stream`] meets either or both of the following requirements: A type modeling [*Stream] meets either or both of the following requirements:
* [*`AsyncStream`] * [*AsyncStream]
* [*`SyncStream`] * [*SyncStream]
[heading:AsyncStream AsyncStream] [heading:AsyncStream AsyncStream]
A type modeling [*`AsyncStream`] meets the following requirements: A type modeling [*AsyncStream] meets the following requirements:
* __AsyncReadStream__ * __AsyncReadStream__
* __AsyncWriteStream__ * __AsyncWriteStream__
[heading:SyncStream SyncStream] [heading:SyncStream SyncStream]
A type modeling [*`SyncStream`] meets the following requirements: A type modeling [*SyncStream] meets the following requirements:
* __SyncReadStream__ * __SyncReadStream__
* __SyncWriteStream__ * __SyncWriteStream__

View File

@@ -111,7 +111,7 @@ If it needs to access the other fields, it can do so using tag dispatch
with an object of type `std::integral_constant<bool, isRequest>`. with an object of type `std::integral_constant<bool, isRequest>`.
Often, in non-trivial HTTP applications, we want to read the HTTP header Often, in non-trivial HTTP applications, we want to read the HTTP header
and examine its contents before choosing a top for [*Body]. To accomplish and examine its contents before choosing a type for [*Body]. To accomplish
this, there needs to be a way to model the header portion of a message. this, there needs to be a way to model the header portion of a message.
And we'd like to do this in a way that allows functions which take the And we'd like to do this in a way that allows functions which take the
header as a parameter, to also accept a type representing the whole header as a parameter, to also accept a type representing the whole

View File

@@ -213,17 +213,18 @@ shows the customization points available to user-defined body types:
* [*`value_type`]: Determines the type of the * [*`value_type`]: Determines the type of the
[link beast.ref.http__message.body `message::body`] member. If this [link beast.ref.http__message.body `message::body`] member. If this
type defines default construction, move, copy, or swap, then message objects type defines default construction, move, copy, or swap, then message objects
declared with this [*`Body`] will have those operations defined. declared with this [*Body] will have those operations defined.
* [*`reader`]: An optional nested type meeting the requirements of * [*`body_writer`]: An optional nested type meeting the requirements of
[link beast.ref.Reader [*`Reader`]]. If present, this defines the algorithm [link beast.ref.BodyWriter [*BodyWriter]]. If present, this defines the
used for parsing bodies of this type. algorithm used to transfer parsed octets into buffers representing the
body.
* [*`writer`]: An optional nested type meeting the requirements of * [*`body_reader`]: An optional nested type meeting the requirements of
[link beast.ref.Writer [*`Writer`]]. If present, this defines the algorithm [link beast.ref.BodyReader [*BodyReader]]. If present, this defines
used for serializing bodies of this type. the algorithm used to obtain buffers representing a body of this type.
The examples included with this library provide a Body implementation that The examples included with this library provide a [*Body] implementation that
serializing message bodies that come from a file. serializing message bodies that come from a file.
[endsect] [endsect]

View File

@@ -43,10 +43,9 @@
[def __SyncReadStream__ [@http://www.boost.org/doc/html/boost_asio/reference/SyncReadStream.html [*SyncReadStream]]] [def __SyncReadStream__ [@http://www.boost.org/doc/html/boost_asio/reference/SyncReadStream.html [*SyncReadStream]]]
[def __SyncWriteStream__ [@http://www.boost.org/doc/html/boost_asio/reference/SyncWriteStream.html [*SyncWriteStream]]] [def __SyncWriteStream__ [@http://www.boost.org/doc/html/boost_asio/reference/SyncWriteStream.html [*SyncWriteStream]]]
[def __Body__ [link beast.ref.Body [*`Body`]]] [def __Body__ [link beast.ref.Body [*Body]]]
[def __DynamicBuffer__ [link beast.ref.DynamicBuffer [*DynamicBuffer]]] [def __DynamicBuffer__ [link beast.ref.DynamicBuffer [*DynamicBuffer]]]
[def __FieldSequence__ [link beast.ref.FieldSequence [*FieldSequence]]] [def __FieldSequence__ [link beast.ref.FieldSequence [*FieldSequence]]]
[def __Parser__ [link beast.ref.Parser [*`Parser`]]]
[def __basic_fields__ [link beast.ref.http__basic_fields `basic_fields`]] [def __basic_fields__ [link beast.ref.http__basic_fields `basic_fields`]]
[def __fields__ [link beast.ref.http__fields `fields`]] [def __fields__ [link beast.ref.http__fields `fields`]]
@@ -113,13 +112,13 @@ provides implementations of the HTTP and WebSocket protocols.
[section:ref Reference] [section:ref Reference]
[xinclude quickref.xml] [xinclude quickref.xml]
[include concept/Body.qbk] [include concept/Body.qbk]
[include concept/BodyReader.qbk]
[include concept/BodyWriter.qbk]
[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/FieldSequence.qbk]
[include concept/Reader.qbk]
[include concept/Streams.qbk] [include concept/Streams.qbk]
[include concept/Writer.qbk]
[include reference.qbk] [include reference.qbk]
[endsect] [endsect]

View File

@@ -74,11 +74,9 @@
</simplelist> </simplelist>
<bridgehead renderas="sect3">Type Traits</bridgehead> <bridgehead renderas="sect3">Type Traits</bridgehead>
<simplelist type="vert" columns="1"> <simplelist type="vert" columns="1">
<member><link linkend="beast.ref.http__is_Body">is_Body</link></member> <member><link linkend="beast.ref.http__is_body">is_body</link></member>
<member><link linkend="beast.ref.http__is_Reader">is_Reader</link></member> <member><link linkend="beast.ref.http__is_body_writer">is_body_writer</link></member>
<member><link linkend="beast.ref.http__is_Writer">is_Writer</link></member> <member><link linkend="beast.ref.http__is_body_reader">is_body_reader</link></member>
<member><link linkend="beast.ref.http__has_reader">has_reader</link></member>
<member><link linkend="beast.ref.http__has_writer">has_writer</link></member>
</simplelist> </simplelist>
</entry> </entry>
<entry valign="top"> <entry valign="top">
@@ -90,10 +88,10 @@
<bridgehead renderas="sect3">Concepts</bridgehead> <bridgehead renderas="sect3">Concepts</bridgehead>
<simplelist type="vert" columns="1"> <simplelist type="vert" columns="1">
<member><link linkend="beast.ref.Body">Body</link></member> <member><link linkend="beast.ref.Body">Body</link></member>
<member><link linkend="beast.ref.BodyReader">BodyReader</link></member>
<member><link linkend="beast.ref.BodyWriter">BodyWriter</link></member>
<member><link linkend="beast.ref.Field">Field</link></member> <member><link linkend="beast.ref.Field">Field</link></member>
<member><link linkend="beast.ref.FieldSequence">FieldSequence</link></member> <member><link linkend="beast.ref.FieldSequence">FieldSequence</link></member>
<member><link linkend="beast.ref.Reader">Reader</link></member>
<member><link linkend="beast.ref.Writer">Writer</link></member>
</simplelist> </simplelist>
</entry> </entry>
<entry valign="top"> <entry valign="top">

View File

@@ -584,7 +584,7 @@ the fragments:
Because calls to read data may return a variable amount of bytes, the Because calls to read data may return a variable amount of bytes, the
interface to calls that read data require an object that meets the requirements interface to calls that read data require an object that meets the requirements
of [link beast.ref.DynamicBuffer [*`DynamicBuffer`]]. This concept is modeled on of __DynamicBuffer__. This concept is modeled on
[@http://www.boost.org/doc/html/boost_asio/reference/basic_streambuf.html `boost::asio::basic_streambuf`]. [@http://www.boost.org/doc/html/boost_asio/reference/basic_streambuf.html `boost::asio::basic_streambuf`].
The implementation does not perform queueing or buffering of messages. If The implementation does not perform queueing or buffering of messages. If

View File

@@ -24,7 +24,7 @@ struct file_body
{ {
using value_type = std::string; using value_type = std::string;
class writer class reader
{ {
std::uint64_t size_ = 0; std::uint64_t size_ = 0;
std::uint64_t offset_ = 0; std::uint64_t offset_ = 0;
@@ -39,18 +39,18 @@ struct file_body
using const_buffers_type = using const_buffers_type =
boost::asio::const_buffers_1; boost::asio::const_buffers_1;
writer(writer&&) = default; reader(reader&&) = default;
writer(writer const&) = delete; reader(reader const&) = delete;
writer& operator=(writer const&) = delete; reader& operator=(reader const&) = delete;
template<bool isRequest, class Fields> template<bool isRequest, class Fields>
writer(message<isRequest, reader(message<isRequest,
file_body, Fields> const& m) file_body, Fields> const& m)
: path_(m.body) : path_(m.body)
{ {
} }
~writer() ~reader()
{ {
if(file_) if(file_)
fclose(file_); fclose(file_);

View File

@@ -12,10 +12,10 @@
namespace beast { namespace beast {
/// The type of string_view used by the library /// The type of string view used by the library
using string_view = boost::string_ref; using string_view = boost::string_ref;
/// The type of basic_string_view used by the library /// The type of basic string view used by the library
template<class CharT, class Traits> template<class CharT, class Traits>
using basic_string_view = using basic_string_view =
boost::basic_string_ref<CharT, Traits>; boost::basic_string_ref<CharT, Traits>;

View File

@@ -8,7 +8,7 @@
#ifndef BEAST_HTTP_BUFFER_BODY_HPP #ifndef BEAST_HTTP_BUFFER_BODY_HPP
#define BEAST_HTTP_BUFFER_BODY_HPP #define BEAST_HTTP_BUFFER_BODY_HPP
#include <beast/http/concepts.hpp> #include <beast/http/type_traits.hpp>
#include <beast/http/error.hpp> #include <beast/http/error.hpp>
#include <beast/http/message.hpp> #include <beast/http/message.hpp>
#include <boost/optional.hpp> #include <boost/optional.hpp>
@@ -68,10 +68,10 @@ struct buffer_body
std::pair<boost::optional<ConstBufferSequence>, bool>; std::pair<boost::optional<ConstBufferSequence>, bool>;
#if BEAST_DOXYGEN #if BEAST_DOXYGEN
/// The algorithm used when serializing this body /// The algorithm to obtain buffers representing the body
using writer = implementation_defined; using reader = implementation_defined;
#else #else
class writer class reader
{ {
bool toggle_ = false; bool toggle_ = false;
value_type const& body_; value_type const& body_;
@@ -84,7 +84,7 @@ struct buffer_body
template<bool isRequest, class Fields> template<bool isRequest, class Fields>
explicit explicit
writer(message<isRequest, buffer_body, reader(message<isRequest, buffer_body,
Fields> const& msg) Fields> const& msg)
: body_(msg.body) : body_(msg.body)
{ {

View File

@@ -1,183 +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)
//
#ifndef BEAST_HTTP_CONCEPTS_HPP
#define BEAST_HTTP_CONCEPTS_HPP
#include <beast/config.hpp>
#include <beast/core/error.hpp>
#include <beast/core/string_view.hpp>
#include <beast/core/type_traits.hpp>
#include <boost/asio/buffer.hpp>
#include <boost/optional.hpp>
#include <type_traits>
#include <utility>
namespace beast {
namespace http {
template<bool, class, class>
struct message;
namespace detail {
struct fields_model
{
string_view method() const;
string_view reason() const;
string_view target() const;
};
struct write_function
{
template<class ConstBufferSequence>
void
operator()(ConstBufferSequence const&);
};
template<class T, class = beast::detail::void_t<>>
struct has_value_type : std::false_type {};
template<class T>
struct has_value_type<T, beast::detail::void_t<
typename T::value_type
> > : std::true_type {};
template<class T, class = beast::detail::void_t<>>
struct has_content_length : std::false_type {};
template<class T>
struct has_content_length<T, beast::detail::void_t<decltype(
std::declval<T>().content_length()
)> > : std::true_type
{
static_assert(std::is_convertible<
decltype(std::declval<T>().content_length()),
std::uint64_t>::value,
"Writer::content_length requirements not met");
};
} // detail
/// Determine if `T` meets the requirements of @b Body.
template<class T>
#if BEAST_DOXYGEN
struct is_Body : std::integral_constant<bool, ...>{};
#else
using is_Body = detail::has_value_type<T>;
#endif
/** Determine if a @b Body has a nested type `reader`.
@tparam T The type to check, which must meet the
requirements of @b Body.
*/
#if BEAST_DOXYGEN
template<class T>
struct has_reader : std::integral_constant<bool, ...>{};
#else
template<class T, class = beast::detail::void_t<>>
struct has_reader : std::false_type {};
template<class T>
struct has_reader<T, beast::detail::void_t<
typename T::reader
> > : std::true_type {};
#endif
/** Determine if a @b Body has a nested type `writer`.
@tparam T The type to check, which must meet the
requirements of @b Body.
*/
#if BEAST_DOXYGEN
template<class T>
struct has_writer : std::integral_constant<bool, ...>{};
#else
template<class T, class = beast::detail::void_t<>>
struct has_writer : std::false_type {};
template<class T>
struct has_writer<T, beast::detail::void_t<
typename T::writer
> > : std::true_type {};
#endif
/** Determine if `T` meets the requirements of @b Reader for `M`.
@tparam T The type to test.
@tparam M The message type to test with, which must be of
type `message`.
*/
#if BEAST_DOXYGEN
template<class T, class M>
struct is_Reader : std::integral_constant<bool, ...> {};
#else
template<class T, class M, class = beast::detail::void_t<>>
struct is_Reader : std::true_type {};
template<class T, class M>
struct is_Reader<T, M, beast::detail::void_t<decltype(
std::declval<typename T::mutable_buffers_type>(),
std::declval<T>().init(
std::declval<boost::optional<std::uint64_t>>()),
std::declval<T>().prepare(
std::declval<std::size_t>()),
std::declval<T>().commit(
std::declval<std::size_t>()),
std::declval<T>().finish()
)> > : std::integral_constant<bool,
is_mutable_buffer_sequence<
typename T::mutable_buffers_type>::value &&
std::is_convertible<decltype(
std::declval<T>().prepare(
std::declval<std::size_t>())),
typename T::mutable_buffers_type
>::value>
{
static_assert(std::is_same<
typename M::body_type::reader, T>::value,
"Mismatched reader and message");
};
#endif
/** Determine if a @b Body type has a writer which meets requirements.
@tparam T The body type to test.
*/
#if BEAST_DOXYGEN
template<class T>
struct is_Writer : std::integral_constant<bool, ...> {};
#else
template<class T, class = void>
struct is_Writer : std::false_type {};
template<class T>
struct is_Writer<T, beast::detail::void_t<
typename T::writer,
typename T::writer::const_buffers_type,
decltype(
std::declval<typename T::writer&>().init(std::declval<error_code&>()),
std::declval<boost::optional<std::pair<
typename T::writer::const_buffers_type, bool>>&>() =
std::declval<typename T::writer>().get(std::declval<error_code&>()),
(void)0)>> : std::integral_constant<bool,
is_const_buffer_sequence<
typename T::writer::const_buffers_type>::value &&
std::is_constructible<typename T::writer,
message<true, T, detail::fields_model> const& >::value
>
{
};
#endif
} // http
} // beast
#endif

View File

@@ -29,10 +29,10 @@ struct basic_dynamic_body
using value_type = DynamicBuffer; using value_type = DynamicBuffer;
#if BEAST_DOXYGEN #if BEAST_DOXYGEN
/// The algorithm used when parsing this body. /// The algorithm used store buffers in this body
using reader = implementation_defined; using writer = implementation_defined;
#else #else
class reader class writer
{ {
value_type& body_; value_type& body_;
@@ -44,7 +44,7 @@ struct basic_dynamic_body
template<bool isRequest, class Fields> template<bool isRequest, class Fields>
explicit explicit
reader(message<isRequest, writer(message<isRequest,
basic_dynamic_body, Fields>& msg) basic_dynamic_body, Fields>& msg)
: body_(msg.body) : body_(msg.body)
{ {
@@ -80,10 +80,10 @@ struct basic_dynamic_body
#endif #endif
#if BEAST_DOXYGEN #if BEAST_DOXYGEN
/// The algorithm used when serializing this body. /// The algorithm to obtain buffers representing the body
using writer = implementation_defined; using reader = implementation_defined;
#else #else
class writer class reader
{ {
DynamicBuffer const& body_; DynamicBuffer const& body_;
@@ -95,7 +95,7 @@ struct basic_dynamic_body
template<bool isRequest, class Fields> template<bool isRequest, class Fields>
explicit explicit
writer(message< reader(message<
isRequest, basic_dynamic_body, Fields> const& m) isRequest, basic_dynamic_body, Fields> const& m)
: body_(m.body) : body_(m.body)
{ {

View File

@@ -29,10 +29,10 @@ struct empty_body
}; };
#if BEAST_DOXYGEN #if BEAST_DOXYGEN
/// The algorithm used when serializing this body. /// The algorithm to obtain buffers representing the body
using writer = implementation_defined; using reader = implementation_defined;
#else #else
struct writer struct reader
{ {
using is_deferred = std::false_type; using is_deferred = std::false_type;
@@ -41,7 +41,7 @@ struct empty_body
template<bool isRequest, class Fields> template<bool isRequest, class Fields>
explicit explicit
writer(message< reader(message<
isRequest, empty_body, Fields> const&) isRequest, empty_body, Fields> const&)
{ {
} }

View File

@@ -8,7 +8,7 @@
#ifndef BEAST_HTTP_IMPL_ASYNC_READ_IPP_HPP #ifndef BEAST_HTTP_IMPL_ASYNC_READ_IPP_HPP
#define BEAST_HTTP_IMPL_ASYNC_READ_IPP_HPP #define BEAST_HTTP_IMPL_ASYNC_READ_IPP_HPP
#include <beast/http/concepts.hpp> #include <beast/http/type_traits.hpp>
#include <beast/http/error.hpp> #include <beast/http/error.hpp>
#include <beast/http/message_parser.hpp> #include <beast/http/message_parser.hpp>
#include <beast/http/read.hpp> #include <beast/http/read.hpp>
@@ -714,13 +714,10 @@ async_read(
"AsyncReadStream requirements not met"); "AsyncReadStream requirements not met");
static_assert(is_dynamic_buffer<DynamicBuffer>::value, static_assert(is_dynamic_buffer<DynamicBuffer>::value,
"DynamicBuffer requirements not met"); "DynamicBuffer requirements not met");
static_assert(is_Body<Body>::value, static_assert(is_body<Body>::value,
"Body requirements not met"); "Body requirements not met");
static_assert(has_reader<Body>::value, static_assert(is_body_writer<Body>::value,
"Body has no reader"); "BodyWriter requirements not met");
static_assert(is_Reader<typename Body::reader,
message<isRequest, Body, Fields>>::value,
"Reader requirements not met");
async_completion<ReadHandler, async_completion<ReadHandler,
void(error_code)> init{handler}; void(error_code)> init{handler};
detail::read_message_op<AsyncReadStream, DynamicBuffer, detail::read_message_op<AsyncReadStream, DynamicBuffer,

View File

@@ -10,7 +10,7 @@
#include <beast/core/error.hpp> #include <beast/core/error.hpp>
#include <beast/core/string_view.hpp> #include <beast/core/string_view.hpp>
#include <beast/http/concepts.hpp> #include <beast/http/type_traits.hpp>
#include <beast/http/rfc7230.hpp> #include <beast/http/rfc7230.hpp>
#include <beast/core/detail/ci_char_traits.hpp> #include <beast/core/detail/ci_char_traits.hpp>
#include <beast/core/detail/type_traits.hpp> #include <beast/core/detail/type_traits.hpp>
@@ -130,7 +130,7 @@ prepare_content_length(prepare_info& pi,
message<isRequest, Body, Fields> const& msg, message<isRequest, Body, Fields> const& msg,
std::true_type) std::true_type)
{ {
typename Body::writer w(msg); typename Body::reader w{msg};
// VFALCO This is a design problem! // VFALCO This is a design problem!
error_code ec; error_code ec;
w.init(ec); w.init(ec);
@@ -159,15 +159,13 @@ prepare(message<isRequest, Body, Fields>& msg,
Options&&... options) Options&&... options)
{ {
// VFALCO TODO // VFALCO TODO
static_assert(is_Body<Body>::value, static_assert(is_body<Body>::value,
"Body requirements not met"); "Body requirements not met");
static_assert(has_writer<Body>::value, static_assert(is_body_reader<Body>::value,
"Body has no writer"); "BodyReader requirements not met");
static_assert(is_Writer<Body>::value,
"Writer requirements not met");
detail::prepare_info pi; detail::prepare_info pi;
detail::prepare_content_length(pi, msg, detail::prepare_content_length(pi, msg,
detail::has_content_length<typename Body::writer>{}); detail::has_content_length<typename Body::reader>{});
detail::prepare_options(pi, msg, detail::prepare_options(pi, msg,
std::forward<Options>(options)...); std::forward<Options>(options)...);

View File

@@ -8,7 +8,7 @@
#ifndef BEAST_HTTP_IMPL_READ_IPP_HPP #ifndef BEAST_HTTP_IMPL_READ_IPP_HPP
#define BEAST_HTTP_IMPL_READ_IPP_HPP #define BEAST_HTTP_IMPL_READ_IPP_HPP
#include <beast/http/concepts.hpp> #include <beast/http/type_traits.hpp>
#include <beast/http/error.hpp> #include <beast/http/error.hpp>
#include <beast/http/message_parser.hpp> #include <beast/http/message_parser.hpp>
#include <beast/http/read.hpp> #include <beast/http/read.hpp>
@@ -291,13 +291,10 @@ read(
"SyncReadStream requirements not met"); "SyncReadStream requirements not met");
static_assert(is_dynamic_buffer<DynamicBuffer>::value, static_assert(is_dynamic_buffer<DynamicBuffer>::value,
"DynamicBuffer requirements not met"); "DynamicBuffer requirements not met");
static_assert(is_Body<Body>::value, static_assert(is_body<Body>::value,
"Body requirements not met"); "Body requirements not met");
static_assert(has_reader<Body>::value, static_assert(is_body_writer<Body>::value,
"Body has no reader"); "BodyWriter requirements not met");
static_assert(is_Reader<typename Body::reader,
message<isRequest, Body, Fields>>::value,
"Reader requirements not met");
error_code ec; error_code ec;
beast::http::read(stream, buffer, msg, ec); beast::http::read(stream, buffer, msg, ec);
if(ec) if(ec)
@@ -319,13 +316,10 @@ read(
"SyncReadStream requirements not met"); "SyncReadStream requirements not met");
static_assert(is_dynamic_buffer<DynamicBuffer>::value, static_assert(is_dynamic_buffer<DynamicBuffer>::value,
"DynamicBuffer requirements not met"); "DynamicBuffer requirements not met");
static_assert(is_Body<Body>::value, static_assert(is_body<Body>::value,
"Body requirements not met"); "Body requirements not met");
static_assert(has_reader<Body>::value, static_assert(is_body_writer<Body>::value,
"Body has no reader"); "BodyWriter requirements not met");
static_assert(is_Reader<typename Body::reader,
message<isRequest, Body, Fields>>::value,
"Reader requirements not met");
message_parser<isRequest, Body, Fields> p; message_parser<isRequest, Body, Fields> p;
beast::http::read(stream, buffer, p, ec); beast::http::read(stream, buffer, p, ec);
if(ec) if(ec)

View File

@@ -8,7 +8,7 @@
#ifndef BEAST_HTTP_IMPL_WRITE_IPP #ifndef BEAST_HTTP_IMPL_WRITE_IPP
#define BEAST_HTTP_IMPL_WRITE_IPP #define BEAST_HTTP_IMPL_WRITE_IPP
#include <beast/http/concepts.hpp> #include <beast/http/type_traits.hpp>
#include <beast/http/error.hpp> #include <beast/http/error.hpp>
#include <beast/core/buffer_cat.hpp> #include <beast/core/buffer_cat.hpp>
#include <beast/core/buffer_prefix.hpp> #include <beast/core/buffer_prefix.hpp>
@@ -183,12 +183,12 @@ operator()(error_code ec,
{ {
if(w_.split_) if(w_.split_)
goto go_header_only; goto go_header_only;
w_.wr_.emplace(w_.m_); w_.rd_.emplace(w_.m_);
w_.wr_->init(ec); w_.rd_->init(ec);
if(ec) if(ec)
return s_.get_io_service().post( return s_.get_io_service().post(
bind_handler(std::move(*this), ec, 0)); bind_handler(std::move(*this), ec, 0));
auto result = w_.wr_->get(ec); auto result = w_.rd_->get(ec);
if(ec) if(ec)
{ {
// Can't use need_more when ! is_deferred // Can't use need_more when ! is_deferred
@@ -248,9 +248,9 @@ operator()(error_code ec,
w_.header_done_ = true; w_.header_done_ = true;
if(! is_deferred::value) if(! is_deferred::value)
goto go_complete; goto go_complete;
BOOST_ASSERT(! w_.wr_); BOOST_ASSERT(! w_.rd_);
w_.wr_.emplace(w_.m_); w_.rd_.emplace(w_.m_);
w_.wr_->init(ec); w_.rd_->init(ec);
if(ec) if(ec)
goto upcall; goto upcall;
w_.s_ = do_body; w_.s_ = do_body;
@@ -258,7 +258,7 @@ operator()(error_code ec,
case do_body: case do_body:
{ {
auto result = w_.wr_->get(ec); auto result = w_.rd_->get(ec);
if(ec) if(ec)
return s_.get_io_service().post( return s_.get_io_service().post(
bind_handler(std::move(*this), ec, 0)); bind_handler(std::move(*this), ec, 0));
@@ -303,12 +303,12 @@ operator()(error_code ec,
{ {
if(w_.split_) if(w_.split_)
goto go_header_only_c; goto go_header_only_c;
w_.wr_.emplace(w_.m_); w_.rd_.emplace(w_.m_);
w_.wr_->init(ec); w_.rd_->init(ec);
if(ec) if(ec)
return s_.get_io_service().post( return s_.get_io_service().post(
bind_handler(std::move(*this), ec, 0)); bind_handler(std::move(*this), ec, 0));
auto result = w_.wr_->get(ec); auto result = w_.rd_->get(ec);
if(ec) if(ec)
{ {
// Can't use need_more when ! is_deferred // Can't use need_more when ! is_deferred
@@ -382,9 +382,9 @@ operator()(error_code ec,
w_.s_ = do_final_c; w_.s_ = do_final_c;
break; break;
} }
BOOST_ASSERT(! w_.wr_); BOOST_ASSERT(! w_.rd_);
w_.wr_.emplace(w_.m_); w_.rd_.emplace(w_.m_);
w_.wr_->init(ec); w_.rd_->init(ec);
if(ec) if(ec)
goto upcall; goto upcall;
w_.s_ = do_body_c; w_.s_ = do_body_c;
@@ -392,7 +392,7 @@ operator()(error_code ec,
case do_body_c: case do_body_c:
{ {
auto result = w_.wr_->get(ec); auto result = w_.rd_->get(ec);
if(ec) if(ec)
return s_.get_io_service().post( return s_.get_io_service().post(
bind_handler(std::move(*this), bind_handler(std::move(*this),
@@ -528,12 +528,10 @@ write_some(SyncWriteStream& stream)
static_assert( static_assert(
is_sync_write_stream<SyncWriteStream>::value, is_sync_write_stream<SyncWriteStream>::value,
"SyncWriteStream requirements not met"); "SyncWriteStream requirements not met");
static_assert(is_Body<Body>::value, static_assert(is_body<Body>::value,
"Body requirements not met"); "Body requirements not met");
static_assert(has_writer<Body>::value, static_assert(is_body_reader<Body>::value,
"Body::writer requirements not met"); "BodyReader requirements not met");
static_assert(is_Writer<Body>::value,
"Writer requirements not met");
error_code ec; error_code ec;
write_some(stream, ec); write_some(stream, ec);
if(ec) if(ec)
@@ -551,12 +549,10 @@ write_some(SyncWriteStream& stream, error_code &ec)
static_assert( static_assert(
is_sync_write_stream<SyncWriteStream>::value, is_sync_write_stream<SyncWriteStream>::value,
"SyncWriteStream requirements not met"); "SyncWriteStream requirements not met");
static_assert(is_Body<Body>::value, static_assert(is_body<Body>::value,
"Body requirements not met"); "Body requirements not met");
static_assert(has_writer<Body>::value, static_assert(is_body_reader<Body>::value,
"Body::writer requirements not met"); "BodyReader requirements not met");
static_assert(is_Writer<Body>::value,
"Writer requirements not met");
using boost::asio::buffer_size; using boost::asio::buffer_size;
switch(s_) switch(s_)
@@ -565,11 +561,11 @@ write_some(SyncWriteStream& stream, error_code &ec)
{ {
if(split_) if(split_)
goto go_header_only; goto go_header_only;
wr_.emplace(m_); rd_.emplace(m_);
wr_->init(ec); rd_->init(ec);
if(ec) if(ec)
return; return;
auto result = wr_->get(ec); auto result = rd_->get(ec);
if(ec) if(ec)
{ {
// Can't use need_more when ! is_deferred // Can't use need_more when ! is_deferred
@@ -624,9 +620,9 @@ write_some(SyncWriteStream& stream, error_code &ec)
header_done_ = true; header_done_ = true;
if(! is_deferred::value) if(! is_deferred::value)
goto go_complete; goto go_complete;
BOOST_ASSERT(! wr_); BOOST_ASSERT(! rd_);
wr_.emplace(m_); rd_.emplace(m_);
wr_->init(ec); rd_->init(ec);
if(ec) if(ec)
return; return;
s_ = do_body; s_ = do_body;
@@ -635,7 +631,7 @@ write_some(SyncWriteStream& stream, error_code &ec)
case do_body: case do_body:
{ {
auto result = wr_->get(ec); auto result = rd_->get(ec);
if(ec) if(ec)
return; return;
if(! result) if(! result)
@@ -670,11 +666,11 @@ write_some(SyncWriteStream& stream, error_code &ec)
{ {
if(split_) if(split_)
goto go_header_only_c; goto go_header_only_c;
wr_.emplace(m_); rd_.emplace(m_);
wr_->init(ec); rd_->init(ec);
if(ec) if(ec)
return; return;
auto result = wr_->get(ec); auto result = rd_->get(ec);
if(ec) if(ec)
{ {
// Can't use need_more when ! is_deferred // Can't use need_more when ! is_deferred
@@ -742,9 +738,9 @@ write_some(SyncWriteStream& stream, error_code &ec)
s_ = do_final_c; s_ = do_final_c;
break; break;
} }
BOOST_ASSERT(! wr_); BOOST_ASSERT(! rd_);
wr_.emplace(m_); rd_.emplace(m_);
wr_->init(ec); rd_->init(ec);
if(ec) if(ec)
return; return;
s_ = do_body_c; s_ = do_body_c;
@@ -753,7 +749,7 @@ write_some(SyncWriteStream& stream, error_code &ec)
case do_body_c: case do_body_c:
{ {
auto result = wr_->get(ec); auto result = rd_->get(ec);
if(ec) if(ec)
return; return;
if(! result) if(! result)
@@ -856,12 +852,10 @@ async_write_some(AsyncWriteStream& stream,
{ {
static_assert(is_async_write_stream<AsyncWriteStream>::value, static_assert(is_async_write_stream<AsyncWriteStream>::value,
"AsyncWriteStream requirements not met"); "AsyncWriteStream requirements not met");
static_assert(is_Body<Body>::value, static_assert(is_body<Body>::value,
"Body requirements not met"); "Body requirements not met");
static_assert(has_writer<Body>::value, static_assert(is_body_reader<Body>::value,
"Body::writer requirements not met"); "BodyReader requirements not met");
static_assert(is_Writer<Body>::value,
"Writer requirements not met");
async_completion<WriteHandler, async_completion<WriteHandler,
void(error_code)> init{handler}; void(error_code)> init{handler};
async_op<AsyncWriteStream, handler_type< async_op<AsyncWriteStream, handler_type<
@@ -984,12 +978,10 @@ write(SyncWriteStream& stream,
{ {
static_assert(is_sync_write_stream<SyncWriteStream>::value, static_assert(is_sync_write_stream<SyncWriteStream>::value,
"SyncWriteStream requirements not met"); "SyncWriteStream requirements not met");
static_assert(is_Body<Body>::value, static_assert(is_body<Body>::value,
"Body requirements not met"); "Body requirements not met");
static_assert(has_writer<Body>::value, static_assert(is_body_reader<Body>::value,
"Body has no writer"); "BodyReader requirements not met");
static_assert(is_Writer<Body>::value,
"Writer requirements not met");
error_code ec; error_code ec;
write(stream, msg, ec); write(stream, msg, ec);
if(ec) if(ec)
@@ -1005,12 +997,10 @@ write(SyncWriteStream& stream,
{ {
static_assert(is_sync_write_stream<SyncWriteStream>::value, static_assert(is_sync_write_stream<SyncWriteStream>::value,
"SyncWriteStream requirements not met"); "SyncWriteStream requirements not met");
static_assert(is_Body<Body>::value, static_assert(is_body<Body>::value,
"Body requirements not met"); "Body requirements not met");
static_assert(has_writer<Body>::value, static_assert(is_body_reader<Body>::value,
"Body has no writer"); "BodyReader requirements not met");
static_assert(is_Writer<Body>::value,
"Writer requirements not met");
auto ws = make_write_stream(msg); auto ws = make_write_stream(msg);
for(;;) for(;;)
{ {
@@ -1034,12 +1024,10 @@ async_write(AsyncWriteStream& stream,
static_assert( static_assert(
is_async_write_stream<AsyncWriteStream>::value, is_async_write_stream<AsyncWriteStream>::value,
"AsyncWriteStream requirements not met"); "AsyncWriteStream requirements not met");
static_assert(is_Body<Body>::value, static_assert(is_body<Body>::value,
"Body requirements not met"); "Body requirements not met");
static_assert(has_writer<Body>::value, static_assert(is_body_reader<Body>::value,
"Body has no writer"); "BodyReader requirements not met");
static_assert(is_Writer<Body>::value,
"Writer requirements not met");
async_completion<WriteHandler, async_completion<WriteHandler,
void(error_code)> init{handler}; void(error_code)> init{handler};
detail::write_op<AsyncWriteStream, handler_type< detail::write_op<AsyncWriteStream, handler_type<
@@ -1068,12 +1056,10 @@ std::ostream&
operator<<(std::ostream& os, operator<<(std::ostream& os,
message<isRequest, Body, Fields> const& msg) message<isRequest, Body, Fields> const& msg)
{ {
static_assert(is_Body<Body>::value, static_assert(is_body<Body>::value,
"Body requirements not met"); "Body requirements not met");
static_assert(has_writer<Body>::value, static_assert(is_body_reader<Body>::value,
"Body has no writer"); "BodyReader requirements not met");
static_assert(is_Writer<Body>::value,
"Writer requirements not met");
beast::detail::sync_ostream oss{os}; beast::detail::sync_ostream oss{os};
error_code ec; error_code ec;
write(oss, msg, ec); write(oss, msg, ec);

View File

@@ -37,16 +37,16 @@ namespace http {
template<bool isRequest, class Body, class Fields> template<bool isRequest, class Body, class Fields>
class message_parser class message_parser
: public basic_parser<isRequest, : public basic_parser<isRequest,
Body::reader::is_direct, Body::writer::is_direct,
message_parser<isRequest, Body, Fields>> message_parser<isRequest, Body, Fields>>
{ {
using base_type = basic_parser<isRequest, true, using base_type = basic_parser<isRequest, true,
message_parser<isRequest, Body, Fields>>; message_parser<isRequest, Body, Fields>>;
using reader_type = typename Body::reader; using writer_type = typename Body::writer;
message<isRequest, Body, Fields> m_; message<isRequest, Body, Fields> m_;
boost::optional<typename Body::reader> r_; boost::optional<writer_type> wr_;
public: public:
/// The type of message returned by the parser /// The type of message returned by the parser
@@ -54,7 +54,7 @@ public:
/// The type of buffer sequence representing the body /// The type of buffer sequence representing the body
using mutable_buffers_type = using mutable_buffers_type =
typename reader_type::mutable_buffers_type; typename writer_type::mutable_buffers_type;
/// Constructor (default) /// Constructor (default)
message_parser() = default; message_parser() = default;
@@ -152,7 +152,7 @@ public:
private: private:
friend class basic_parser< friend class basic_parser<
isRequest, Body::reader::is_direct, isRequest, Body::writer::is_direct,
message_parser>; message_parser>;
void void
@@ -192,22 +192,22 @@ private:
void void
on_body() on_body()
{ {
r_.emplace(m_); wr_.emplace(m_);
r_->init(); wr_->init();
} }
void void
on_body(std::uint64_t content_length) on_body(std::uint64_t content_length)
{ {
r_.emplace(m_); wr_.emplace(m_);
r_->init(content_length); wr_->init(content_length);
} }
void void
on_body(error_code& ec) on_body(error_code& ec)
{ {
r_.emplace(m_); wr_.emplace(m_);
r_->init(ec); wr_->init(ec);
if(ec) if(ec)
return; return;
} }
@@ -216,8 +216,8 @@ private:
on_body(std::uint64_t content_length, on_body(std::uint64_t content_length,
error_code& ec) error_code& ec)
{ {
r_.emplace(m_); wr_.emplace(m_);
r_->init(content_length, ec); wr_->init(content_length, ec);
if(ec) if(ec)
return; return;
} }
@@ -226,20 +226,20 @@ private:
on_data(string_view const& s, on_data(string_view const& s,
error_code& ec) error_code& ec)
{ {
BOOST_STATIC_ASSERT(! Body::reader::is_direct); BOOST_STATIC_ASSERT(! Body::writer::is_direct);
r_->write(s, ec); wr_->write(s, ec);
} }
mutable_buffers_type mutable_buffers_type
on_prepare(std::size_t n) on_prepare(std::size_t n)
{ {
return r_->prepare(n); return wr_->prepare(n);
} }
void void
on_commit(std::size_t n) on_commit(std::size_t n)
{ {
r_->commit(n); wr_->commit(n);
} }
void void
@@ -252,24 +252,24 @@ private:
void void
on_complete(error_code& ec) on_complete(error_code& ec)
{ {
if(r_) if(wr_)
do_on_complete(ec, do_on_complete(ec,
std::integral_constant<bool, std::integral_constant<bool,
Body::reader::is_direct>{}); Body::writer::is_direct>{});
} }
void void
do_on_complete( do_on_complete(
error_code& ec, std::true_type) error_code& ec, std::true_type)
{ {
r_->finish(); wr_->finish();
} }
void void
do_on_complete( do_on_complete(
error_code& ec, std::false_type) error_code& ec, std::false_type)
{ {
r_->finish(ec); wr_->finish(ec);
if(ec) if(ec)
return; return;
} }

View File

@@ -31,10 +31,10 @@ struct string_body
using value_type = std::string; using value_type = std::string;
#if BEAST_DOXYGEN #if BEAST_DOXYGEN
/// The algorithm used when parsing this body. /// The algorithm used store buffers in this body
using reader = implementation_defined; using writer = implementation_defined;
#else #else
class reader class writer
{ {
value_type& body_; value_type& body_;
std::size_t len_ = 0; std::size_t len_ = 0;
@@ -47,7 +47,7 @@ struct string_body
template<bool isRequest, class Fields> template<bool isRequest, class Fields>
explicit explicit
reader(message<isRequest, writer(message<isRequest,
string_body, Fields>& m) string_body, Fields>& m)
: body_(m.body) : body_(m.body)
{ {
@@ -93,10 +93,10 @@ struct string_body
#endif #endif
#if BEAST_DOXYGEN #if BEAST_DOXYGEN
/// The algorithm used when serializing this body. /// The algorithm to obtain buffers representing the body
using writer = implementation_defined; using reader = implementation_defined;
#else #else
class writer class reader
{ {
value_type const& body_; value_type const& body_;
@@ -108,7 +108,7 @@ struct string_body
template<bool isRequest, class Fields> template<bool isRequest, class Fields>
explicit explicit
writer(message< reader(message<
isRequest, string_body, Fields> const& msg) isRequest, string_body, Fields> const& msg)
: body_(msg.body) : body_(msg.body)
{ {

View File

@@ -0,0 +1,146 @@
//
// 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)
//
#ifndef BEAST_HTTP_TYPE_TRAITS_HPP
#define BEAST_HTTP_TYPE_TRAITS_HPP
#include <beast/config.hpp>
#include <beast/core/error.hpp>
#include <beast/core/string_view.hpp>
#include <beast/core/type_traits.hpp>
#include <boost/asio/buffer.hpp>
#include <boost/optional.hpp>
#include <type_traits>
#include <utility>
namespace beast {
namespace http {
template<bool, class, class>
struct message;
namespace detail {
struct fields_model
{
string_view method() const;
string_view reason() const;
string_view target() const;
};
template<class T, class = beast::detail::void_t<>>
struct has_value_type : std::false_type {};
template<class T>
struct has_value_type<T, beast::detail::void_t<
typename T::value_type
> > : std::true_type {};
template<class T, class = beast::detail::void_t<>>
struct has_content_length : std::false_type {};
template<class T>
struct has_content_length<T, beast::detail::void_t<decltype(
std::declval<T>().content_length()
)> > : std::true_type
{
static_assert(std::is_convertible<
decltype(std::declval<T>().content_length()),
std::uint64_t>::value,
"Writer::content_length requirements not met");
};
} // detail
/// Determine if `T` meets the requirements of @b Body.
template<class T>
#if BEAST_DOXYGEN
struct is_body : std::integral_constant<bool, ...>{};
#else
using is_body = detail::has_value_type<T>;
#endif
/** Determine if a @b Body type has a reader.
This metafunction is equivalent to `std::true_type` if:
@li @b T has a nested type named `reader`
@li The nested type meets the requirements of @b BodyReader.
@tparam T The body type to test.
*/
#if BEAST_DOXYGEN
template<class T>
struct is_body_reader : std::integral_constant<bool, ...> {};
#else
template<class T, class = void>
struct is_body_reader : std::false_type {};
template<class T>
struct is_body_reader<T, beast::detail::void_t<
typename T::reader,
typename T::reader::const_buffers_type,
decltype(
std::declval<typename T::reader&>().init(std::declval<error_code&>()),
std::declval<boost::optional<std::pair<
typename T::reader::const_buffers_type, bool>>&>() =
std::declval<typename T::reader>().get(std::declval<error_code&>()),
(void)0)>> : std::integral_constant<bool,
is_const_buffer_sequence<
typename T::reader::const_buffers_type>::value &&
std::is_constructible<typename T::reader,
message<true, T, detail::fields_model> const& >::value
>
{
};
#endif
/** Determine if a @b Body type has a writer.
This metafunction is equivalent to `std::true_type` if:
@li @b T has a nested type named `writer`
@li The nested type meets the requirements of @b BodyWriter.
@tparam T The body type to test.
*/
#if BEAST_DOXYGEN
template<class T>
struct is_body_writer : std::integral_constant<bool, ...> {};
#else
template<class T, class = beast::detail::void_t<>>
struct is_body_writer : std::true_type {};
template<class T>
struct is_body_writer<T, beast::detail::void_t<decltype(
std::declval<typename T::writer::mutable_buffers_type>(),
std::declval<T::writer>().init(
std::declval<boost::optional<std::uint64_t>>()),
std::declval<T::writer>().prepare(
std::declval<std::size_t>()),
std::declval<T::writer>().commit(
std::declval<std::size_t>()),
std::declval<T::writer>().finish()
)> > : std::integral_constant<bool,
is_mutable_buffer_sequence<
typename T::writer::mutable_buffers_type>::value &&
std::is_convertible<decltype(
std::declval<T::writer>().prepare(
std::declval<std::size_t>())),
typename T::writer::mutable_buffers_type
>::value>
{
};
#endif
} // http
} // beast
#endif

View File

@@ -190,27 +190,29 @@ class serializer
using buffer_type = using buffer_type =
basic_multi_buffer<Allocator>; basic_multi_buffer<Allocator>;
using reader = typename Body::reader;
using is_deferred = using is_deferred =
typename Body::writer::is_deferred; typename reader::is_deferred;
using cb0_t = consuming_buffers<buffers_view< using cb0_t = consuming_buffers<buffers_view<
typename buffer_type::const_buffers_type, // header typename buffer_type::const_buffers_type, // header
typename Body::writer::const_buffers_type>>;// body typename reader::const_buffers_type>>; // body
using cb1_t = consuming_buffers< using cb1_t = consuming_buffers<
typename Body::writer::const_buffers_type>; // body typename reader::const_buffers_type>; // body
using ch0_t = consuming_buffers<buffers_view< using ch0_t = consuming_buffers<buffers_view<
typename buffer_type::const_buffers_type, // header typename buffer_type::const_buffers_type, // header
detail::chunk_header, // chunk-header detail::chunk_header, // chunk-header
boost::asio::const_buffers_1, // chunk-ext+\r\n boost::asio::const_buffers_1, // chunk-ext+\r\n
typename Body::writer::const_buffers_type, // body typename reader::const_buffers_type, // body
boost::asio::const_buffers_1>>; // crlf boost::asio::const_buffers_1>>; // crlf
using ch1_t = consuming_buffers<buffers_view< using ch1_t = consuming_buffers<buffers_view<
detail::chunk_header, // chunk-header detail::chunk_header, // chunk-header
boost::asio::const_buffers_1, // chunk-ext+\r\n boost::asio::const_buffers_1, // chunk-ext+\r\n
typename Body::writer::const_buffers_type, // body typename reader::const_buffers_type, // body
boost::asio::const_buffers_1>>; // crlf boost::asio::const_buffers_1>>; // crlf
using ch2_t = consuming_buffers<buffers_view< using ch2_t = consuming_buffers<buffers_view<
@@ -222,7 +224,7 @@ class serializer
Decorator d_; Decorator d_;
std::size_t limit_ = std::size_t limit_ =
(std::numeric_limits<std::size_t>::max)(); (std::numeric_limits<std::size_t>::max)();
boost::optional<typename Body::writer> wr_; boost::optional<reader> rd_;
buffer_type b_; buffer_type b_;
boost::variant<boost::blank, boost::variant<boost::blank,
cb0_t, cb1_t, ch0_t, ch1_t, ch2_t> v_; cb0_t, cb1_t, ch0_t, ch1_t, ch2_t> v_;

View File

@@ -43,7 +43,6 @@ unit-test http-tests :
../extras/beast/unit_test/main.cpp ../extras/beast/unit_test/main.cpp
http/basic_parser.cpp http/basic_parser.cpp
http/buffer_body.cpp http/buffer_body.cpp
http/concepts.cpp
http/design.cpp http/design.cpp
http/dynamic_body.cpp http/dynamic_body.cpp
http/error.cpp http/error.cpp
@@ -54,6 +53,7 @@ unit-test http-tests :
http/read.cpp http/read.cpp
http/rfc7230.cpp http/rfc7230.cpp
http/string_body.cpp http/string_body.cpp
http/type_traits.cpp
http/write.cpp http/write.cpp
; ;

View File

@@ -12,7 +12,6 @@ add_executable (http-tests
../../extras/beast/unit_test/main.cpp ../../extras/beast/unit_test/main.cpp
basic_parser.cpp basic_parser.cpp
buffer_body.cpp buffer_body.cpp
concepts.cpp
design.cpp design.cpp
dynamic_body.cpp dynamic_body.cpp
empty_body.cpp empty_body.cpp
@@ -24,6 +23,7 @@ add_executable (http-tests
read.cpp read.cpp
rfc7230.cpp rfc7230.cpp
string_body.cpp string_body.cpp
type_traits.cpp
write.cpp write.cpp
) )

View File

@@ -203,7 +203,7 @@ public:
{ {
using value_type = std::string; using value_type = std::string;
class reader class writer
{ {
value_type& body_; value_type& body_;
std::size_t len_ = 0; std::size_t len_ = 0;
@@ -216,7 +216,7 @@ public:
template<bool isRequest, class Fields> template<bool isRequest, class Fields>
explicit explicit
reader(message<isRequest, direct_body, Fields>& m) writer(message<isRequest, direct_body, Fields>& m)
: body_(m.body) : body_(m.body)
{ {
} }
@@ -315,7 +315,7 @@ public:
{ {
using value_type = std::string; using value_type = std::string;
class reader class writer
{ {
value_type& body_; value_type& body_;
@@ -327,7 +327,7 @@ public:
template<bool isRequest, class Fields> template<bool isRequest, class Fields>
explicit explicit
reader(message<isRequest, indirect_body, Fields>& m) writer(message<isRequest, indirect_body, Fields>& m)
: body_(m.body) : body_(m.body)
{ {
} }

View File

@@ -6,16 +6,16 @@
// //
// Test that header file is self-contained. // Test that header file is self-contained.
#include <beast/http/concepts.hpp> #include <beast/http/type_traits.hpp>
#include <beast/http/empty_body.hpp> #include <beast/http/empty_body.hpp>
namespace beast { namespace beast {
namespace http { namespace http {
BOOST_STATIC_ASSERT(! is_Writer<int>::value); BOOST_STATIC_ASSERT(! is_body_reader<int>::value);
BOOST_STATIC_ASSERT(is_Writer<empty_body>::value); BOOST_STATIC_ASSERT(is_body_reader<empty_body>::value);
} // http } // http
} // beast } // beast

View File

@@ -37,7 +37,7 @@ public:
{ {
using value_type = std::string; using value_type = std::string;
class writer class reader
{ {
value_type const& body_; value_type const& body_;
@@ -49,7 +49,7 @@ public:
template<bool isRequest, class Allocator> template<bool isRequest, class Allocator>
explicit explicit
writer(message<isRequest, unsized_body, Allocator> const& msg) reader(message<isRequest, unsized_body, Allocator> const& msg)
: body_(msg.body) : body_(msg.body)
{ {
} }
@@ -82,7 +82,7 @@ public:
bool mutable read = false; bool mutable read = false;
}; };
class writer class reader
{ {
int step_ = 0; int step_ = 0;
value_type const& body_; value_type const& body_;
@@ -96,7 +96,7 @@ public:
template<bool isRequest, class Fields> template<bool isRequest, class Fields>
explicit explicit
writer(message<isRequest, test_body, reader(message<isRequest, test_body,
Fields> const& msg) Fields> const& msg)
: body_(msg.body) : body_(msg.body)
{ {
@@ -196,11 +196,11 @@ public:
struct fail_body struct fail_body
{ {
class writer; class reader;
class value_type class value_type
{ {
friend class writer; friend class reader;
std::string s_; std::string s_;
test::fail_counter& fc_; test::fail_counter& fc_;
@@ -220,7 +220,7 @@ public:
} }
}; };
class writer class reader
{ {
std::size_t n_ = 0; std::size_t n_ = 0;
value_type const& body_; value_type const& body_;
@@ -233,7 +233,7 @@ public:
template<bool isRequest, class Allocator> template<bool isRequest, class Allocator>
explicit explicit
writer(message<isRequest, fail_body, Allocator> const& msg) reader(message<isRequest, fail_body, Allocator> const& msg)
: body_(msg.body) : body_(msg.body)
{ {
} }