Documentation work

This commit is contained in:
Vinnie Falco
2017-06-03 09:45:09 -07:00
parent 00667f3cf2
commit 78d9e3bbce
11 changed files with 665 additions and 351 deletions

View File

@@ -93,9 +93,13 @@ of redirects, gzipped transfer encodings, caching, or proxying (to name
a few) are not directly provided, but nothing stops users from creating a few) are not directly provided, but nothing stops users from creating
these features using Beast's HTTP message types. these features using Beast's HTTP message types.
The library is intended to be the foundation upon which other networking [important
libraries are built. It is a goal that other architects will build Beast is not an HTTP client or HTTP server, but it can be used to
interoperable solutions on top of Beast. build both. The library is intended to be a foundation upon which
new libraries may be built. It is a goal that other architects will
build interoperable solutions on top of Beast. The provided example
code shows how a client or server may be built.
]
[heading Credits] [heading Credits]

View File

@@ -80,14 +80,14 @@ The stream operations which work on parsers are:
[table Parser Stream Operations [table Parser Stream Operations
[[Name][Description]] [[Name][Description]]
[[ [[
[link beast.ref.http__read_some.overload1 [*read_some]] [link beast.ref.http__read.overload1 [*read]]
][ ][
Read some octets into a parser from a __SyncReadStream__. Read everything into a parser from a __SyncWriteStream__.
]] ]]
[[ [[
[link beast.ref.http__async_read_some [*async_read_some]] [link beast.ref.http__async_read.overload1 [*async_read]]
][ ][
Read some octets into a parser asynchronously from an __AsyncWriteStream__. Read everything into a parser asynchronously from an __AsyncWriteStream__.
]] ]]
[[ [[
[link beast.ref.http__read_header.overload1 [*read_header]] [link beast.ref.http__read_header.overload1 [*read_header]]
@@ -100,14 +100,14 @@ The stream operations which work on parsers are:
Read only the header octets into a parser asynchronously from an __AsyncWriteStream__. Read only the header octets into a parser asynchronously from an __AsyncWriteStream__.
]] ]]
[[ [[
[link beast.ref.http__read.overload1 [*read]] [link beast.ref.http__read_some.overload1 [*read_some]]
][ ][
Read everything into a parser from a __SyncWriteStream__. Read some octets into a parser from a __SyncReadStream__.
]] ]]
[[ [[
[link beast.ref.http__async_read.overload1 [*async_read]] [link beast.ref.http__async_read_some [*async_read_some]]
][ ][
Read everything into a parser asynchronously from an __AsyncWriteStream__. Read some octets into a parser asynchronously from an __AsyncWriteStream__.
]] ]]
] ]

View File

@@ -12,7 +12,6 @@ and invoke its methods directly instead of using the provided stream
algorithms. This could be useful for implementing algorithms on streams algorithms. This could be useful for implementing algorithms on streams
whose interface does not conform to __Stream__. For example, a whose interface does not conform to __Stream__. For example, a
[@https://github.com/libuv/libuv *libuv* socket]. [@https://github.com/libuv/libuv *libuv* socket].
The serializer interface is interactive; the caller invokes it repeatedly to The serializer interface is interactive; the caller invokes it repeatedly to
produce buffers until all of the buffers have been generated. Then the produce buffers until all of the buffers have been generated. Then the
serializer is destroyed. serializer is destroyed.

View File

@@ -13,7 +13,6 @@ invoke its methods directly instead of using the provided stream algorithms.
This could be useful for implementing algorithms on streams whose interface This could be useful for implementing algorithms on streams whose interface
does not conform to any __Stream__. For example, a does not conform to any __Stream__. For example, a
[@http://zeromq.org/ *ZeroMQ* socket]. [@http://zeromq.org/ *ZeroMQ* socket].
The basic parser interface is interactive; the caller invokes the function The basic parser interface is interactive; the caller invokes the function
[link beast.ref.http__basic_parser.put `basic_parser::put`] [link beast.ref.http__basic_parser.put `basic_parser::put`]
repeatedly with buffers until an error occurs or the parsing is done. The repeatedly with buffers until an error occurs or the parsing is done. The
@@ -22,9 +21,44 @@ function
Is used when the caller knows that there will never be more data (for example, Is used when the caller knows that there will never be more data (for example,
if the underlying connection is closed), if the underlying connection is closed),
[heading Split Parsing] [heading Parser Options]
[heading Eager Parsing] The parser provides two options which may be set before parsing begins:
[table Parser Options
[[Name][Default][Description]]
[[
[link beast.ref.http__basic_parser.eager.overload2 `eager`]
][
`false`
][
Normally the parser returns after successfully parsing a structured
element (header, chunk header, or chunk body) even if there are octets
remaining in the input. This is necessary when attempting to parse the
header first, or when the caller wants to inspect information which may
be invalidated by subsequent parsing, such as a chunk extension. The
`eager` option controls whether the parser keeps going after parsing
structured element if there are octets remaining in the buffer and no
error occurs. This option is automatically set or cleared during certain
stream operations to improve performance with no change in functionality.
]]
[[
[link beast.ref.http__basic_parser.skip.overload2 `skip`]
][
`false`
][
This option controls whether or not the parser expects to see an HTTP
body, regardless of the presence or absence of certain fields such as
Content-Length or a chunked Transfer-Encoding. Depending on the request,
some responses do not carry a body. For example, a 200 response to a
[@https://tools.ietf.org/html/rfc7231#section-4.3.6 CONNECT] request
from a tunneling proxy, or a response to a
[@https://tools.ietf.org/html/rfc7231#section-4.3.2 HEAD] request.
In these cases, callers may use this function inform the parser that
no body is expected. The parser will consider the message complete
after the header has been received.
]]
]
[heading Example: Parsing from a std::istream] [heading Example: Parsing from a std::istream]

View File

@@ -7,4 +7,103 @@
[section:custom_parsers Custom Parsers] [section:custom_parsers Custom Parsers]
While the parsers included in the library will handle a broad number of
use-cases, the __basic_parser__ interface can be subclassed to implement
custom parsing strategies: the parser processes the incoming octets into
elements according to the HTTP/1 protocol specification, while the derived
class decides what to do with those elements. In particular, users who
create exotic containers for [*Fields] may need to also create their own
parser. Custom parsers will work with all of the stream read operations
that work on parsers, as those algorithms use only the basic parser interface.
The basic parser uses the Curiously Recurring Template Pattern
([@https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern CRTP]).
To declare your user defined parser, first derive it from __basic_parser__:
```
template<bool isRequest>
class custom_parser
: public basic_parser<isRequest, custom_parser<isRequest>>
{
friend class basic_parser<isRequest, custom_parser>;
...
```
The interface to the parser is event-driven. Member functions of the derived
class (termed "callbacks" in this context) are invoked with parsed elements
as they become available, requiring either the `friend` declaration as shown
above or that the member functions are declared public (not recommended).
Buffers provided by the parser are non-owning references, it is the
responsibility of the derived class to copy any information it needs before
returning from the callback.
```
template<bool isRequest>
class custom_parser
: public basic_parser<isRequest, custom_parser<isRequest>>
{
friend class basic_parser<isRequest, custom_parser>;
/// Called after receiving the request-line (isRequest == true).
void
on_request(
string_view method, // The method
string_view target, // The request-target
int version, // The HTTP-version
error_code& ec); // The error returned to the caller, if any
/// Called after receiving the start-line (isRequest == false).
void
on_response(
int status, // The status-code
string_view reason, // The obsolete reason-phrase
int version, // The HTTP-version
error_code& ec); // The error returned to the caller, if any
/// Called after receiving a header field.
void
on_field(
string_view name, // The field name
string_view value, // The field value
error_code& ec); // The error returned to the caller, if any
/// Called after the complete header is received.
void
on_header(
error_code& ec); // The error returned to the caller, if any
/// Called just before processing the body, if a body exists.
void
on_body(boost::optional<
std::uint64_t> const&
content_length, // Content length if known, else `boost::none`
error_code& ec); // The error returned to the caller, if any
/// Called for each piece of the body, if a body exists.
//
// If present, the chunked Transfer-Encoding will be removed
// before this callback is invoked.
//
void
on_data(
string_view s, // A portion of the body
error_code& ec); // The error returned to the caller, if any
/// Called for each chunk header.
void
on_chunk(
std::uint64_t size, // The size of the upcoming chunk
string_view extension, // The chunk-extension (may be empty)
error_code& ec); // The error returned to the caller, if any
/// Called when the complete message is parsed.
void
on_complete(error_code& ec);
public:
custom_parser() = default;
};
```
[endsect] [endsect]

View File

@@ -26,20 +26,20 @@ The meaning of the nested types is as follows
declared with this [*Body] will have those operations defined. declared with this [*Body] will have those operations defined.
] ]
][ ][
[`body_writer`] [`reader`]
[
An optional nested type meeting the requirements of
[link beast.ref.BodyReader [*BodyReader]]. If present, this defines
the algorithm used to obtain buffers representing a body of this type.
]
][
[`writer`]
[ [
An optional nested type meeting the requirements of An optional nested type meeting the requirements of
[link beast.ref.BodyWriter [*BodyWriter]]. If present, this defines the [link beast.ref.BodyWriter [*BodyWriter]]. If present, this defines the
algorithm used to transfer parsed octets into buffers representing the algorithm used to transfer parsed octets into buffers representing the
body. body.
] ]
][
[`body_reader`]
[
An optional nested type meeting the requirements of
[link beast.ref.BodyReader [*BodyReader]]. If present, this defines
the algorithm used to obtain buffers representing a body of this type.
]
] ]
] ]

View File

@@ -29,95 +29,6 @@ namespace http {
state. It will handle chunked encoding and it understands state. It will handle chunked encoding and it understands
the semantics of the Connection, Content-Length, and Upgrade the semantics of the Connection, Content-Length, and Upgrade
fields. fields.
The interface uses CRTP (Curiously Recurring Template Pattern).
To use this class, derive from @ref basic_parser. When bytes
are presented, the implementation will make a series of zero
or more calls to derived class members functions (referred to
as "callbacks" from here on) matching a specific signature.
Every callback must be provided by the derived class, or else
a compilation error will be generated. This exemplar shows
the signature and description of the callbacks required in
the derived class.
@par Derived Example
@code
template<bool isRequest>
struct derived
: basic_parser<isRequest, derived<isRequest>>
{
// When isRequest == true, called
// after the Request Line is received.
//
void
on_request(
string_view method,
string_view target,
int version,
error_code& ec);
// When isRequest == false, called
// after the Status Line is received.
//
void
on_response(
int status,
string_view reason,
int version,
error_code& ec);
// Called after receiving a field/value pair.
//
void
on_field(
string_view name,
string_view value,
error_code& ec);
// Called after the header is complete.
//
void
on_header(
error_code& ec);
// Called once before the body, if any, is started.
//
void
on_body(
boost::optional<std::uint64_t> content_length,
error_code& ec);
// Called zero or more times to provide body data.
//
void
on_data(
string_view s,
error_code& ec);
// If the Transfer-Encoding is specified, and the
// last item in the list of encodings is "chunked",
// called after receiving a chunk header or a final
// chunk.
//
void
on_chunk(
std::uint64_t length, // Length of this chunk
string_view const& ext, // The chunk extensions, if any
error_code& ec);
// Called once when the message is complete.
// This will be called even if there is no body.
//
void
on_complete(error_code& ec);
};
@endcode
If a callback sets the error code, the error will be propagated
to the caller of the parser.
The parser is optimized for the case where the input buffer The parser is optimized for the case where the input buffer
sequence consists of a single contiguous buffer. The sequence consists of a single contiguous buffer. The
@ref beast::flat_buffer class is provided, which guarantees @ref beast::flat_buffer class is provided, which guarantees
@@ -130,6 +41,88 @@ namespace http {
the structured portion of the HTTP message (header or chunk header) the structured portion of the HTTP message (header or chunk header)
is contained in a linear buffer. is contained in a linear buffer.
The interface uses CRTP (Curiously Recurring Template Pattern).
To use this class directly, derive from @ref basic_parser. When
bytes are presented, the implementation will make a series of zero
or more calls to derived class members functions (termed "callbacks"
in this context) matching a specific signature.
Every callback must be provided by the derived class, or else
a compilation error will be generated. This exemplar shows
the signature and description of the callbacks required in
the derived class. If a callback sets the error code, the error
will be propagated to the caller of the parser.
@par Example
@code
template<bool isRequest>
class custom_parser
: public basic_parser<isRequest, custom_parser<isRequest>>
{
friend class basic_parser<isRequest, custom_parser>;
/// Called after receiving the request-line (isRequest == true).
void
on_request(
string_view method, // The method
string_view target, // The request-target
int version, // The HTTP-version
error_code& ec); // The error returned to the caller, if any
/// Called after receiving the start-line (isRequest == false).
void
on_response(
int status, // The status-code
string_view reason, // The obsolete reason-phrase
int version, // The HTTP-version
error_code& ec); // The error returned to the caller, if any
/// Called after receiving a header field.
void
on_field(
string_view name, // The field name
string_view value, // The field value
error_code& ec); // The error returned to the caller, if any
/// Called after the complete header is received.
void
on_header(
error_code& ec); // The error returned to the caller, if any
/// Called just before processing the body, if a body exists.
void
on_body(boost::optional<
std::uint64_t> const&
content_length, // Content length if known, else `boost::none`
error_code& ec); // The error returned to the caller, if any
/// Called for each piece of the body, if a body exists.
//
// If present, the chunked Transfer-Encoding will be removed
// before this callback is invoked.
//
void
on_data(
string_view s, // A portion of the body
error_code& ec); // The error returned to the caller, if any
/// Called for each chunk header.
void
on_chunk(
std::uint64_t size, // The size of the upcoming chunk
string_view extension, // The chunk-extension (may be empty)
error_code& ec); // The error returned to the caller, if any
/// Called when the complete message is parsed.
void
on_complete(error_code& ec);
public:
custom_parser() = default;
};
@endcode
@tparam isRequest A `bool` indicating whether the parser will be @tparam isRequest A `bool` indicating whether the parser will be
presented with request or response message. presented with request or response message.
@@ -319,16 +312,19 @@ public:
/** Set the eager parse option. /** Set the eager parse option.
This option controls whether or not the parser will attempt Normally the parser returns after successfully parsing a structured
to consume all of the octets provided during parsing, or element (header, chunk header, or chunk body) even if there are octets
if it will stop when it reaches one of the following positions remaining in the input. This is necessary when attempting to parse the
within the serialized message: header first, or when the caller wants to inspect information which may
be invalidated by subsequent parsing, such as a chunk extension. The
`eager` option controls whether the parser keeps going after parsing
structured element if there are octets remaining in the buffer and no
error occurs. This option is automatically set or cleared during certain
stream operations to improve performance with no change in functionality.
@li Immediately after the header The default setting is `false`.
@li Immediately after any chunk header @param v `true` to set the eager parse option or `false` to disable it.
The default is to stop after the header or any chunk header.
*/ */
void void
eager(bool v) eager(bool v)
@@ -339,25 +335,25 @@ public:
f_ &= ~flagEager; f_ &= ~flagEager;
} }
/// Returns `true` if the parser will ignore the message body. /// Returns `true` if the skip parse option is set.
bool bool
skip() skip()
{ {
return (f_ & flagSkipBody) != 0; return (f_ & flagSkipBody) != 0;
} }
/** Set the skip body option. /** Set the skip parse option.
The option controls whether or not the parser expects to This option controls whether or not the parser expects to see an HTTP
see an HTTP body, regardless of the presence or absence of body, regardless of the presence or absence of certain fields such as
certain fields such as Content-Length. Content-Length or a chunked Transfer-Encoding. Depending on the request,
some responses do not carry a body. For example, a 200 response to a
CONNECT request from a tunneling proxy, or a response to a HEAD request.
In these cases, callers may use this function inform the parser that
no body is expected. The parser will consider the message complete
after the header has been received.
Depending on the request, some responses do not carry a @param v `true` to set the skip body option or `false` to disable it.
body. For example, a 200 response to a CONNECT request
from a tunneling proxy. In these cases, callers may use
this function inform the parser that no body is expected.
The parser will consider the message complete after the
header has been received.
@note This function must called before any bytes are processed. @note This function must called before any bytes are processed.
*/ */

View File

@@ -227,10 +227,8 @@ class parser
using base_type = basic_parser<isRequest, using base_type = basic_parser<isRequest,
parser<isRequest, Body, Fields>>; parser<isRequest, Body, Fields>>;
using writer_type = typename Body::writer;
message<isRequest, Body, Fields> m_; message<isRequest, Body, Fields> m_;
boost::optional<writer_type> wr_; boost::optional<typename Body::writer> wr_;
public: public:
/// The type of message returned by the parser /// The type of message returned by the parser
@@ -329,8 +327,7 @@ public:
} }
private: private:
friend class basic_parser< friend class basic_parser<isRequest, parser>;
isRequest, parser>;
void void
on_request( on_request(

View File

@@ -17,35 +17,30 @@
namespace beast { namespace beast {
namespace http { namespace http {
/** Read some HTTP/1 message data from a stream. /** Read part of a message from a stream using a parser.
This function synchronously advances the state of the This function is used to read part of a message from a stream into a
parser using the provided dynamic buffer and reading subclass of @ref basic_parser.
from the input stream as needed. The call will block The call will block until one of the following conditions is true:
until one of the following conditions is true:
@li When expecting a message header, and the complete @li A call to @ref basic_parser::put with a non-empty buffer sequence
header is received. is successful.
@li When expecting a chunk header, and the complete @li An error occurs.
chunk header is received.
@li When expecting body octets, one or more body octets This operation is implemented in terms of one or
are received. more calls to the stream's `read_some` function.
The implementation may read additional octets that lie past the
end of the message being read. This additional data is stored
in the dynamic buffer, which must be retained for subsequent reads.
@li An error occurs in the stream or parser. If the stream returns the error `boost::asio::error::eof` indicating the
end of file during a read, the error returned from this function will be:
This function is implemented in terms of one or more calls @li @ref error::end_of_stream if no octets were parsed, or
to the stream's `read_some` function. The implementation may
read additional octets that lie past the end of the object @li @ref error::partial_message if any octets were parsed.
being parsed. This additional data is stored in the dynamic
buffer, which may be used in subsequent calls.
If the end of the stream is reached during the read, the
value @ref error::partial_message is indicated as the
error if bytes have been processed, else the error
@ref error::end_of_stream is indicated.
@param stream The stream from which the data is to be read. @param stream The stream from which the data is to be read.
The type must support the @b SyncReadStream concept. The type must support the @b SyncReadStream concept.
@@ -57,9 +52,9 @@ namespace http {
@param parser The parser to use. @param parser The parser to use.
@return The number of bytes processed from the dynamic @return The number of octets processed from the dynamic buffer.
buffer. The caller should remove these bytes by calling The octets should be removed by calling `consume` on the dynamic
`consume` on the dynamic buffer. buffer after the read completes, regardless of any error.
@throws system_error Thrown on failure. @throws system_error Thrown on failure.
*/ */
@@ -73,34 +68,33 @@ read_some(
DynamicBuffer& buffer, DynamicBuffer& buffer,
basic_parser<isRequest, Derived>& parser); basic_parser<isRequest, Derived>& parser);
/** Read some HTTP/1 message data from a stream. /** Read part of a message from a stream using a parser.
This function synchronously advances the state of the This function is used to read part of a message from a stream into a
parser using the provided dynamic buffer and reading subclass of @ref basic_parser.
from the input stream as needed. The call will block The call will block until one of the following conditions is true:
until one of the following conditions is true:
@li When expecting a message header, and the complete @li A call to @ref basic_parser::put with a non-empty buffer sequence
header is received. is successful.
@li When expecting a chunk header, and the complete @li An error occurs.
chunk header is received.
@li When expecting body octets, one or more body octets This operation is implemented in terms of one or
are received. more calls to the stream's `read_some` function.
The implementation may read additional octets that lie past the
end of the message being read. This additional data is stored
in the dynamic buffer, which must be retained for subsequent reads.
@li An error occurs in the stream or parser. If the stream returns the error `boost::asio::error::eof` indicating the
end of file during a read, the error returned from this function will be:
This function is implemented in terms of one or more calls @li @ref error::end_of_stream if no octets were parsed, or
to the stream's `read_some` function. The implementation may
read additional octets that lie past the end of the object
being parsed. This additional data is stored in the dynamic
buffer, which may be used in subsequent calls.
If the end of the stream is reached during the read, the @li @ref error::partial_message if any octets were parsed.
value @ref error::partial_message is indicated as the
error if bytes have been processed, else the error The function returns the number of bytes processed from the dynamic
@ref error::end_of_stream is indicated. buffer. The caller should remove these bytes by calling `consume` on
the dynamic buffer, regardless of any error.
@param stream The stream from which the data is to be read. @param stream The stream from which the data is to be read.
The type must support the @b SyncReadStream concept. The type must support the @b SyncReadStream concept.
@@ -115,9 +109,9 @@ read_some(
@param ec Set to the error, if any occurred. @param ec Set to the error, if any occurred.
@return The number of bytes processed from the dynamic @return The number of octets processed from the dynamic buffer.
buffer. The caller should remove these bytes by calling The octets should be removed by calling `consume` on the dynamic
`consume` on the dynamic buffer. buffer after the read completes, regardless of any error.
*/ */
template< template<
class SyncReadStream, class SyncReadStream,
@@ -130,24 +124,17 @@ read_some(
basic_parser<isRequest, Derived>& parser, basic_parser<isRequest, Derived>& parser,
error_code& ec); error_code& ec);
/** Start an asynchronous operation to read some HTTP/1 message data from a stream. /** Read part of a message asynchronously from a stream using a parser.
This function asynchronously advances the state of the This function is used to asynchronously read part of a message from
parser using the provided dynamic buffer and reading from a stream into a subclass of @ref basic_parser.
the input stream as needed. The function call always The function call always returns immediately. The asynchronous operation
returns immediately. The asynchronous operation will will continue until one of the following conditions is true:
continue until one of the following conditions is true:
@li When expecting a message header, and the complete @li A call to @ref basic_parser::put with a non-empty buffer sequence
header is received. is successful.
@li When expecting a chunk header, and the complete @li An error occurs.
chunk header is received.
@li When expecting body octets, one or more body octets
are received.
@li An error occurs in the stream or parser.
This operation is implemented in terms of zero or more calls to This operation is implemented in terms of zero or more calls to
the next layer's `async_read_some` function, and is known as a the next layer's `async_read_some` function, and is known as a
@@ -157,14 +144,12 @@ read_some(
end of the object being parsed. This additional data is stored end of the object being parsed. This additional data is stored
in the stream buffer, which may be used in subsequent calls. in the stream buffer, which may be used in subsequent calls.
The completion handler will be called with the number of bytes If the stream returns the error `boost::asio::error::eof` indicating the
processed from the dynamic buffer. The caller should remove end of file during a read, the error returned from this function will be:
these bytes by calling `consume` on the dynamic buffer.
If the end of the stream is reached during the read, the @li @ref error::end_of_stream if no octets were parsed, or
value @ref error::partial_message is indicated as the
error if bytes have been processed, else the error @li @ref error::partial_message if any octets were parsed.
@ref error::end_of_stream is indicated.
@param stream The stream from which the data is to be read. @param stream The stream from which the data is to be read.
The type must support the @b AsyncReadStream concept. The type must support the @b AsyncReadStream concept.
@@ -176,6 +161,8 @@ read_some(
first. first.
@param parser The parser to use. @param parser The parser to use.
The object must remain valid at least until the
handler is called; ownership is not transferred.
@param handler The handler to be called when the request @param handler The handler to be called when the request
completes. Copies will be made of the handler as required. completes. Copies will be made of the handler as required.
@@ -188,6 +175,11 @@ read_some(
immediately or not, the handler will not be invoked from within immediately or not, the handler will not be invoked from within
this function. Invocation of the handler will be performed in a this function. Invocation of the handler will be performed in a
manner equivalent to using `boost::asio::io_service::post`. manner equivalent to using `boost::asio::io_service::post`.
The completion handler will receive as a parameter the number
of octets processed from the dynamic buffer. The octets should
be removed by calling `consume` on the dynamic buffer after
the read completes, regardless of any error.
*/ */
template< template<
class AsyncReadStream, class AsyncReadStream,
@@ -208,26 +200,28 @@ async_read_some(
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
/** Read a header into an HTTP/1 parser from a stream. /** Read a header from a stream using a parser.
This function synchronously reads from a stream and passes This function is used to read a header from a stream into a subclass
data to the specified parser. The call will block until one of @ref basic_parser.
of the following conditions is true: The call will block until one of the following conditions is true:
@li The parser indicates that the complete header is received @li @ref basic_parser::is_header_done returns `true`
@li An error occurs in the stream or parser. @li An error occurs.
This function is implemented in terms of one or more calls This operation is implemented in terms of one or
to the stream's `read_some` function. The implementation may more calls to the stream's `read_some` function.
read additional octets that lie past the end of the object The implementation may read additional octets that lie past the
being parsed. This additional data is stored in the dynamic end of the message being read. This additional data is stored
buffer, which may be used in subsequent calls. in the dynamic buffer, which must be retained for subsequent reads.
If the end of the stream is reached during the read, the If the stream returns the error `boost::asio::error::eof` indicating the
value @ref error::partial_message is indicated as the end of file during a read, the error returned from this function will be:
error if bytes have been processed, else the error
@ref error::end_of_stream is indicated. @li @ref error::end_of_stream if no octets were parsed, or
@li @ref error::partial_message if any octets were parsed.
@param stream The stream from which the data is to be read. @param stream The stream from which the data is to be read.
The type must support the @b SyncReadStream concept. The type must support the @b SyncReadStream concept.
@@ -255,26 +249,28 @@ read_header(
DynamicBuffer& buffer, DynamicBuffer& buffer,
basic_parser<isRequest, Derived>& parser); basic_parser<isRequest, Derived>& parser);
/** Read a header into an HTTP/1 parser from a stream. /** Read a header from a stream using a parser.
This function synchronously reads from a stream and passes This function is used to read a header from a stream into a subclass
data to the specified parser. The call will block until one of @ref basic_parser.
of the following conditions is true: The call will block until one of the following conditions is true:
@li The parser indicates that the complete header is received @li @ref basic_parser::is_header_done returns `true`
@li An error occurs in the stream or parser. @li An error occurs.
This function is implemented in terms of one or more calls This operation is implemented in terms of one or
to the stream's `read_some` function. The implementation may more calls to the stream's `read_some` function.
read additional octets that lie past the end of the object The implementation may read additional octets that lie past the
being parsed. This additional data is stored in the dynamic end of the message being read. This additional data is stored
buffer, which may be used in subsequent calls. in the dynamic buffer, which must be retained for subsequent reads.
If the end of the stream is reached during the read, the If the stream returns the error `boost::asio::error::eof` indicating the
value @ref error::partial_message is indicated as the end of file during a read, the error returned from this function will be:
error if bytes have been processed, else the error
@ref error::end_of_stream is indicated. @li @ref error::end_of_stream if no octets were parsed, or
@li @ref error::partial_message if any octets were parsed.
@param stream The stream from which the data is to be read. @param stream The stream from which the data is to be read.
The type must support the @b SyncReadStream concept. The type must support the @b SyncReadStream concept.
@@ -303,29 +299,31 @@ read_header(
basic_parser<isRequest, Derived>& parser, basic_parser<isRequest, Derived>& parser,
error_code& ec); error_code& ec);
/** Read a header into an HTTP/1 parser asynchronously from a stream. /** Read a header from a stream asynchronously using a parser.
This function is used to asynchronously read from a stream and This function is used to asynchronously read a header from a stream
pass the data to the specified parser. The function call always into a subclass of @ref basic_parser.
returns immediately. The asynchronous operation will continue The function call always returns immediately. The asynchronous operation
until one of the following conditions is true: will continue until one of the following conditions is true:
@li The parser indicates that the complete header is received @li @ref basic_parser::is_header_done returns `true`
@li An error occurs in the stream or parser. @li An error occurs.
This operation is implemented in terms of one or more calls to This operation is implemented in terms of one or more calls to
the next layer's `async_read_some` function, and is known as a the stream's `async_read_some` function, and is known as a
<em>composed operation</em>. The program must ensure that the <em>composed operation</em>. The program must ensure that the
stream performs no other operations until this operation completes. stream performs no other operations until this operation completes.
The implementation may read additional octets that lie past the The implementation may read additional octets that lie past the
end of the object being parsed. This additional data is stored end of the message being read. This additional data is stored
in the stream buffer, which may be used in subsequent calls. in the dynamic buffer, which must be retained for subsequent reads.
If the end of the stream is reached during the read, the If the stream returns the error `boost::asio::error::eof` indicating the
value @ref error::partial_message is indicated as the end of file during a read, the error returned from this function will be:
error if bytes have been processed, else the error
@ref error::end_of_stream is indicated. @li @ref error::end_of_stream if no octets were parsed, or
@li @ref error::partial_message if any octets were parsed.
@param stream The stream from which the data is to be read. @param stream The stream from which the data is to be read.
The type must support the @b AsyncReadStream concept. The type must support the @b AsyncReadStream concept.
@@ -337,6 +335,8 @@ read_header(
first. first.
@param parser The parser to use. @param parser The parser to use.
The object must remain valid at least until the
handler is called; ownership is not transferred.
@param handler The handler to be called when the request @param handler The handler to be called when the request
completes. Copies will be made of the handler as required. completes. Copies will be made of the handler as required.
@@ -371,26 +371,28 @@ async_read_header(
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
/** Read into an HTTP/1 parser from a stream. /** Read a complete message from a stream using a parser.
This function synchronously reads from a stream and passes This function is used to read a complete message from a stream into a
data to the specified parser. The call will block until one subclass of @ref basic_parser.
of the following conditions is true: The call will block until one of the following conditions is true:
@li The parser indicates no more additional data is needed. @li @ref basic_parser::is_done returns `true`
@li An error occurs in the stream or parser. @li An error occurs.
This function is implemented in terms of one or more calls This operation is implemented in terms of one or
to the stream's `read_some` function. The implementation may more calls to the stream's `read_some` function.
read additional octets that lie past the end of the object The implementation may read additional octets that lie past the
being parsed. This additional data is stored in the dynamic end of the message being read. This additional data is stored
buffer, which may be used in subsequent calls. in the dynamic buffer, which must be retained for subsequent reads.
If the end of the stream is reached during the read, the If the stream returns the error `boost::asio::error::eof` indicating the
value @ref error::partial_message is indicated as the end of file during a read, the error returned from this function will be:
error if bytes have been processed, else the error
@ref error::end_of_stream is indicated. @li @ref error::end_of_stream if no octets were parsed, or
@li @ref error::partial_message if any octets were parsed.
@param stream The stream from which the data is to be read. @param stream The stream from which the data is to be read.
The type must support the @b SyncReadStream concept. The type must support the @b SyncReadStream concept.
@@ -418,26 +420,28 @@ read(
DynamicBuffer& buffer, DynamicBuffer& buffer,
basic_parser<isRequest, Derived>& parser); basic_parser<isRequest, Derived>& parser);
/** Read into an HTTP/1 parser from a stream. /** Read a complete message from a stream using a parser.
This function synchronously reads from a stream and passes This function is used to read a complete message from a stream into a
data to the specified parser. The call will block until one subclass of @ref basic_parser.
of the following conditions is true: The call will block until one of the following conditions is true:
@li The parser indicates that no more data is needed. @li @ref basic_parser::is_done returns `true`
@li An error occurs in the stream or parser. @li An error occurs.
This function is implemented in terms of one or more calls This operation is implemented in terms of one or
to the stream's `read_some` function. The implementation may more calls to the stream's `read_some` function.
read additional octets that lie past the end of the object The implementation may read additional octets that lie past the
being parsed. This additional data is stored in the dynamic end of the message being read. This additional data is stored
buffer, which may be used in subsequent calls. in the dynamic buffer, which must be retained for subsequent reads.
If the end of the stream is reached during the read, the If the stream returns the error `boost::asio::error::eof` indicating the
value @ref error::partial_message is indicated as the end of file during a read, the error returned from this function will be:
error if bytes have been processed, else the error
@ref error::end_of_stream is indicated. @li @ref error::end_of_stream if no octets were parsed, or
@li @ref error::partial_message if any octets were parsed.
@param stream The stream from which the data is to be read. @param stream The stream from which the data is to be read.
The type must support the @b SyncReadStream concept. The type must support the @b SyncReadStream concept.
@@ -466,29 +470,31 @@ read(
basic_parser<isRequest, Derived>& parser, basic_parser<isRequest, Derived>& parser,
error_code& ec); error_code& ec);
/** Read into an HTTP/1 parser asynchronously from a stream. /** Read a complete message from a stream asynchronously using a parser.
This function is used to asynchronously read from a stream and This function is used to asynchronously read a complete message from a
pass the data to the specified parser. The function call always stream into a subclass of @ref basic_parser.
returns immediately. The asynchronous operation will continue The function call always returns immediately. The asynchronous operation
until one of the following conditions is true: will continue until one of the following conditions is true:
@li The parser indicates that no more data is needed. @li @ref basic_parser::is_done returns `true`
@li An error occurs in the stream or parser. @li An error occurs.
This operation is implemented in terms of one or more calls to This operation is implemented in terms of one or more calls to
the next layer's `async_read_some` function, and is known as a the stream's `async_read_some` function, and is known as a
<em>composed operation</em>. The program must ensure that the <em>composed operation</em>. The program must ensure that the
stream performs no other operations until this operation completes. stream performs no other operations until this operation completes.
The implementation may read additional octets that lie past the The implementation may read additional octets that lie past the
end of the object being parsed. This additional data is stored end of the message being read. This additional data is stored
in the stream buffer, which may be used in subsequent calls. in the dynamic buffer, which must be retained for subsequent reads.
If the end of the stream is reached during the read, the If the stream returns the error `boost::asio::error::eof` indicating the
value @ref error::partial_message is indicated as the end of file during a read, the error returned from this function will be:
error if bytes have been processed, else the error
@ref error::end_of_stream is indicated. @li @ref error::end_of_stream if no octets were parsed, or
@li @ref error::partial_message if any octets were parsed.
@param stream The stream from which the data is to be read. @param stream The stream from which the data is to be read.
The type must support the @b AsyncReadStream concept. The type must support the @b AsyncReadStream concept.
@@ -500,6 +506,8 @@ read(
first. first.
@param parser The parser to use. @param parser The parser to use.
The object must remain valid at least until the
handler is called; ownership is not transferred.
@param handler The handler to be called when the request @param handler The handler to be called when the request
completes. Copies will be made of the handler as required. completes. Copies will be made of the handler as required.
@@ -534,26 +542,27 @@ async_read(
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
/** Read an HTTP/1 message from a stream. /** Read a complete message from a stream.
This function is used to synchronously read a message from This function is used to read a complete message from a stream using HTTP/1.
a stream. The call blocks until one of the following conditions The call will block until one of the following conditions is true:
is true:
@li A complete message is read in. @li The entire message is read.
@li An error occurs in the stream or parser. @li An error occurs.
This function is implemented in terms of one or more calls This operation is implemented in terms of one or
to the stream's `read_some` function. The implementation may more calls to the stream's `read_some` function.
read additional octets that lie past the end of the message The implementation may read additional octets that lie past the
being parsed. This additional data is stored in the dynamic end of the message being read. This additional data is stored
buffer, which may be used in subsequent calls. in the dynamic buffer, which must be retained for subsequent reads.
If the end of the stream is reached during the read, the If the stream returns the error `boost::asio::error::eof` indicating the
value @ref error::partial_message is indicated as the end of file during a read, the error returned from this function will be:
error if bytes have been processed, else the error
@ref error::end_of_stream is indicated. @li @ref error::end_of_stream if no octets were parsed, or
@li @ref error::partial_message if any octets were parsed.
@param stream The stream from which the data is to be read. @param stream The stream from which the data is to be read.
The type must support the @b SyncReadStream concept. The type must support the @b SyncReadStream concept.
@@ -564,9 +573,8 @@ async_read(
dynamic buffer's input sequence will be given to the parser dynamic buffer's input sequence will be given to the parser
first. first.
@param msg An object used to store the message. Any @param msg An object used to store the message. Any contents will
contents will be overwritten. The type must support be overwritten. The type must support copy or move assignment.
copy assignment or move assignment.
@throws system_error Thrown on failure. @throws system_error Thrown on failure.
*/ */
@@ -580,26 +588,27 @@ read(
DynamicBuffer& buffer, DynamicBuffer& buffer,
message<isRequest, Body, Fields>& msg); message<isRequest, Body, Fields>& msg);
/** Read an HTTP/1 message from a stream. /** Read a complete message from a stream.
This function is used to synchronously read a message from This function is used to read a complete message from a stream using HTTP/1.
a stream. The call blocks until one of the following conditions The call will block until one of the following conditions is true:
is true:
@li A complete message is read in. @li The entire message is read.
@li An error occurs in the stream or parser. @li An error occurs.
This function is implemented in terms of one or more calls This operation is implemented in terms of one or
to the stream's `read_some` function. The implementation may more calls to the stream's `read_some` function.
read additional octets that lie past the end of the message The implementation may read additional octets that lie past the
being parsed. This additional data is stored in the dynamic end of the message being read. This additional data is stored
buffer, which may be used in subsequent calls. in the dynamic buffer, which must be retained for subsequent reads.
If the end of the stream is reached during the read, the If the stream returns the error `boost::asio::error::eof` indicating the
value @ref error::partial_message is indicated as the end of file during a read, the error returned from this function will be:
error if bytes have been processed, else the error
@ref error::end_of_stream is indicated. @li @ref error::end_of_stream if no octets were parsed, or
@li @ref error::partial_message if any octets were parsed.
@param stream The stream from which the data is to be read. @param stream The stream from which the data is to be read.
The type must support the @b SyncReadStream concept. The type must support the @b SyncReadStream concept.
@@ -610,9 +619,8 @@ read(
dynamic buffer's input sequence will be given to the parser dynamic buffer's input sequence will be given to the parser
first. first.
@param msg An object used to store the message. Any @param msg An object used to store the message. Any contents will
contents will be overwritten. The type must support be overwritten. The type must support copy or move assignment.
copy assignment or move assignment.
@param ec Set to the error, if any occurred. @param ec Set to the error, if any occurred.
*/ */
@@ -627,31 +635,33 @@ read(
message<isRequest, Body, Fields>& msg, message<isRequest, Body, Fields>& msg,
error_code& ec); error_code& ec);
/** Read an HTTP/1 message asynchronously from a stream. /** Read a complete message from a stream asynchronously.
This function is used to asynchronously read a message from This function is used to asynchronously read a complete message from a
a stream. The function call always returns immediately. The stream using HTTP/1.
asynchronous operation will continue until one of the following The function call always returns immediately. The asynchronous operation
conditions is true: will continue until one of the following conditions is true:
@li A complete message is read in. @li The entire message is read.
@li An error occurs in the stream or parser. @li An error occurs.
This operation is implemented in terms of one or more calls to This operation is implemented in terms of one or more calls to
the stream's `async_read_some` function, and is known as a the stream's `async_read_some` function, and is known as a
<em>composed operation</em>. The program must ensure that the <em>composed operation</em>. The program must ensure that the
stream performs no other operations until this operation completes. stream performs no other operations until this operation completes.
The implementation may read additional octets that lie past the The implementation may read additional octets that lie past the
end of the message being parsed. This additional data is stored end of the message being read. This additional data is stored
in the dynamic buffer, which may be used in subsequent calls. in the dynamic buffer, which must be retained for subsequent reads.
If the end of the stream is reached during the read, the If the stream returns the error `boost::asio::error::eof` indicating the
value @ref error::partial_message is indicated as the end of file during a read, the error returned from this function will be:
error if bytes have been processed, else the error
@ref error::end_of_stream is indicated.
@param stream The stream to read the message from. @li @ref error::end_of_stream if no octets were parsed, or
@li @ref error::partial_message if any octets were parsed.
@param stream The stream from which the data is to be read.
The type must support the @b AsyncReadStream concept. The type must support the @b AsyncReadStream concept.
@param buffer A @b DynamicBuffer holding additional bytes @param buffer A @b DynamicBuffer holding additional bytes
@@ -660,10 +670,10 @@ read(
dynamic buffer's input sequence will be given to the parser dynamic buffer's input sequence will be given to the parser
first. first.
@param msg An object used to store the header. Any contents @param msg An object used to store the message. Any contents will
will be overwritten. The type must support copy assignment or be overwritten. The type must support copy or move assignment.
move assignment. The object must remain valid at least until The object must remain valid at least until the
the completion handler is called; ownership is not transferred. handler is called; ownership is not transferred.
@param handler The handler to be called when the operation @param handler The handler to be called when the operation
completes. Copies will be made of the handler as required. completes. Copies will be made of the handler as required.

View File

@@ -131,6 +131,8 @@ write_some(SyncWriteStream& stream, serializer<
The type must support the @b AsyncWriteStream concept. The type must support the @b AsyncWriteStream concept.
@param sr The serializer to use. @param sr The serializer to use.
The object must remain valid at least until the
handler is called; ownership is not transferred.
@param handler The handler to be called when the operation @param handler The handler to be called when the operation
completes. Copies will be made of the handler as required. completes. Copies will be made of the handler as required.
@@ -244,6 +246,8 @@ write_header(SyncWriteStream& stream, serializer<
The type must support the @b AsyncWriteStream concept. The type must support the @b AsyncWriteStream concept.
@param sr The serializer to use. @param sr The serializer to use.
The object must remain valid at least until the
handler is called; ownership is not transferred.
@param handler The handler to be called when the operation @param handler The handler to be called when the operation
completes. Copies will be made of the handler as required. completes. Copies will be made of the handler as required.
@@ -354,6 +358,8 @@ write(SyncWriteStream& stream, serializer<
The type must support the @b AsyncWriteStream concept. The type must support the @b AsyncWriteStream concept.
@param sr The serializer to use. @param sr The serializer to use.
The object must remain valid at least until the
handler is called; ownership is not transferred.
@param handler The handler to be called when the operation @param handler The handler to be called when the operation
completes. Copies will be made of the handler as required. completes. Copies will be made of the handler as required.
@@ -465,8 +471,9 @@ write(SyncWriteStream& stream,
@param stream The stream to which the data is to be written. @param stream The stream to which the data is to be written.
The type must support the @b AsyncWriteStream concept. The type must support the @b AsyncWriteStream concept.
@param msg The message to write. The object must remain valid at least @param msg The message to write.
until the completion handler is called; ownership is not transferred. The object must remain valid at least until the
handler is called; ownership is not transferred.
@param handler The handler to be called when the operation @param handler The handler to be called when the operation
completes. Copies will be made of the handler as required. completes. Copies will be made of the handler as required.

View File

@@ -21,6 +21,130 @@
namespace beast { namespace beast {
namespace http { namespace http {
namespace design {
//--------------------------------------------------------------------------
//
// Example: Custom Parser
//
//--------------------------------------------------------------------------
template<bool isRequest>
class custom_parser
: public basic_parser<isRequest, custom_parser<isRequest>>
{
friend class basic_parser<isRequest, custom_parser>;
/// Called after receiving the request-line (isRequest == true).
void
on_request(
string_view method, // The method
string_view target, // The request-target
int version, // The HTTP-version
error_code& ec); // The error returned to the caller, if any
/// Called after receiving the start-line (isRequest == false).
void
on_response(
int status, // The status-code
string_view reason, // The obsolete reason-phrase
int version, // The HTTP-version
error_code& ec); // The error returned to the caller, if any
/// Called after receiving a header field.
void
on_field(
string_view name, // The field name
string_view value, // The field value
error_code& ec); // The error returned to the caller, if any
/// Called after the complete header is received.
void
on_header(
error_code& ec); // The error returned to the caller, if any
/// Called just before processing the body, if a body exists.
void
on_body(boost::optional<
std::uint64_t> const&
content_length, // Content length if known, else `boost::none`
error_code& ec); // The error returned to the caller, if any
/// Called for each piece of the body, if a body exists.
//
// If present, the chunked Transfer-Encoding will be removed
// before this callback is invoked.
//
void
on_data(
string_view s, // A portion of the body
error_code& ec); // The error returned to the caller, if any
/// Called for each chunk header.
void
on_chunk(
std::uint64_t size, // The size of the upcoming chunk
string_view extension, // The chunk-extension (may be empty)
error_code& ec); // The error returned to the caller, if any
/// Called when the complete message is parsed.
void
on_complete(error_code& ec);
public:
custom_parser() = default;
};
template<bool isRequest>
void custom_parser<isRequest>::
on_request(string_view method, string_view path, int version, error_code& ec)
{
}
template<bool isRequest>
void custom_parser<isRequest>::
on_response(int status, string_view reason, int version, error_code& ec)
{
}
template<bool isRequest>
void custom_parser<isRequest>::
on_field(string_view name, string_view value, error_code& ec)
{
}
template<bool isRequest>
void custom_parser<isRequest>::
on_header(error_code& ec)
{
}
template<bool isRequest>
void custom_parser<isRequest>::
on_body(boost::optional<std::uint64_t> const& content_length, error_code& ec)
{
}
template<bool isRequest>
void custom_parser<isRequest>::
on_data(string_view s, error_code& ec)
{
}
template<bool isRequest>
void custom_parser<isRequest>::
on_chunk(std::uint64_t size, string_view extension, error_code& ec)
{
}
template<bool isRequest>
void custom_parser<isRequest>::
on_complete(error_code& ec)
{
}
} // design
class design_test class design_test
: public beast::unit_test::suite : public beast::unit_test::suite
, public beast::test::enable_yield_to , public beast::test::enable_yield_to
@@ -618,6 +742,48 @@ public:
BEAST_EXPECTS(! ec, ec.message()); BEAST_EXPECTS(! ec, ec.message());
} }
//--------------------------------------------------------------------------
//
// Example: Custom Parser
//
//--------------------------------------------------------------------------
void
doCustomParser()
{
{
string_view s{
"POST / HTTP/1.1\r\n"
"User-Agent: test\r\n"
"Content-Length: 13\r\n"
"\r\n"
"Hello, world!"
};
error_code ec;
design::custom_parser<true> p;
p.put(boost::asio::buffer(
s.data(), s.size()), ec);
BEAST_EXPECTS(! ec, ec.message());
}
{
string_view s{
"HTTP/1.1 200 OK\r\n"
"Server: test\r\n"
"Transfer-Encoding: chunked\r\n"
"\r\n"
"d\r\n"
"Hello, world!"
"\r\n"
"0\r\n\r\n"
};
error_code ec;
design::custom_parser<false> p;
p.put(boost::asio::buffer(
s.data(), s.size()), ec);
BEAST_EXPECTS(! ec, ec.message());
}
}
//-------------------------------------------------------------------------- //--------------------------------------------------------------------------
// //
// Deferred Body type commitment // Deferred Body type commitment
@@ -788,6 +954,8 @@ public:
doCgiResponse(); doCgiResponse();
doRelay(); doRelay();
doParseStdStream(); doParseStdStream();
doCustomParser();
doDeferredBody(); doDeferredBody();
} }
}; };