mirror of
https://github.com/boostorg/beast.git
synced 2025-08-01 05:44:38 +02:00
Documentation work
This commit is contained in:
@@ -72,6 +72,8 @@
|
|||||||
[import ../examples/websocket_example.cpp]
|
[import ../examples/websocket_example.cpp]
|
||||||
[import ../examples/echo_op.cpp]
|
[import ../examples/echo_op.cpp]
|
||||||
[import ../examples/doc_http_samples.hpp]
|
[import ../examples/doc_http_samples.hpp]
|
||||||
|
[import ../test/core/doc_snippets.cpp]
|
||||||
|
[import ../test/http/doc_snippets.cpp]
|
||||||
|
|
||||||
[include 1_overview.qbk]
|
[include 1_overview.qbk]
|
||||||
[include 2_examples.qbk]
|
[include 2_examples.qbk]
|
||||||
|
@@ -17,21 +17,9 @@ lists these facilities by group, with descriptions.
|
|||||||
This documentation assumes familiarity with __Asio__. Sample
|
This documentation assumes familiarity with __Asio__. Sample
|
||||||
code and identifiers used throughout are written as if the
|
code and identifiers used throughout are written as if the
|
||||||
following declarations are in effect:
|
following declarations are in effect:
|
||||||
```
|
|
||||||
#include <beast/core.hpp>
|
|
||||||
#include <boost/asio.hpp>
|
|
||||||
#include <iostream>
|
|
||||||
#include <thread>
|
|
||||||
|
|
||||||
using namespace beast;
|
|
||||||
|
|
||||||
boost::asio::io_service ios;
|
[snippet_core_1a]
|
||||||
boost::asio::io_service work{ios};
|
[snippet_core_1b]
|
||||||
std::thread t{[&](){ ios.run(); }};
|
|
||||||
|
|
||||||
error_code ec;
|
|
||||||
|
|
||||||
```
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[include 3_1_asio.qbk]
|
[include 3_1_asio.qbk]
|
||||||
|
@@ -20,16 +20,8 @@ or other object which meets the required stream concepts and already has
|
|||||||
communication established with an endpoint. This example is provided as a
|
communication established with an endpoint. This example is provided as a
|
||||||
reminder of how to work
|
reminder of how to work
|
||||||
with sockets:
|
with sockets:
|
||||||
```
|
|
||||||
auto host = "www.example.com";
|
|
||||||
boost::asio::ip::tcp::resolver r{ios};
|
|
||||||
boost::asio::ip::tcp::socket sock{ios};
|
|
||||||
boost::asio::connect(sock, r.resolve(
|
|
||||||
boost::asio::ip::tcp::resolver::query{host, "http"}));
|
|
||||||
|
|
||||||
// At this point `sock` is a connected to a remote
|
[snippet_core_2]
|
||||||
// host and may be used to perform stream operations.
|
|
||||||
```
|
|
||||||
|
|
||||||
Throughout this documentation identifiers with the following names have
|
Throughout this documentation identifiers with the following names have
|
||||||
special meaning:
|
special meaning:
|
||||||
|
@@ -118,14 +118,7 @@ Using the type checks with `static_assert` on function or class template
|
|||||||
types will provide users with helpful error messages and prevent undefined
|
types will provide users with helpful error messages and prevent undefined
|
||||||
behaviors. This example shows how a template function which writes to a
|
behaviors. This example shows how a template function which writes to a
|
||||||
synchronous stream may check its argument:
|
synchronous stream may check its argument:
|
||||||
```
|
|
||||||
template<class SyncWriteStream>
|
[snippet_core_3]
|
||||||
void write_string(SyncWriteStream& stream, string_view s)
|
|
||||||
{
|
|
||||||
static_assert(is_sync_write_stream<SyncWriteStream>::value,
|
|
||||||
"SyncWriteStream requirements not met");
|
|
||||||
boost::asio::write(stream, boost::asio::const_buffers_1(s.data(), s.size()));
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
[endsect]
|
[endsect]
|
||||||
|
@@ -54,12 +54,6 @@ this echo operation:
|
|||||||
|
|
||||||
[core_sample_echo_op_4]
|
[core_sample_echo_op_4]
|
||||||
|
|
||||||
```
|
|
||||||
// echo_op is callable with the signature void(error_code, bytes_transferred),
|
|
||||||
// allowing `*this` to be used as both a ReadHandler and a WriteHandler.
|
|
||||||
//
|
|
||||||
```
|
|
||||||
|
|
||||||
A complete, runnable version of this example may be found in the examples
|
A complete, runnable version of this example may be found in the examples
|
||||||
directory.
|
directory.
|
||||||
|
|
||||||
|
@@ -66,10 +66,8 @@ format using __Asio__. Specifically, the library provides:
|
|||||||
the HTTP protocol specification described in __rfc7230__. Sample
|
the HTTP protocol specification described in __rfc7230__. Sample
|
||||||
code and identifiers mentioned in this section is written as if
|
code and identifiers mentioned in this section is written as if
|
||||||
these declarations are in effect:
|
these declarations are in effect:
|
||||||
```
|
|
||||||
#include <beast/http.hpp>
|
[http_snippet_1]
|
||||||
using namespace beast::http;
|
|
||||||
```
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[include 4_01_primer.qbk]
|
[include 4_01_primer.qbk]
|
||||||
|
@@ -116,42 +116,39 @@ the __Body__ requirements:
|
|||||||
[heading Usage]
|
[heading Usage]
|
||||||
|
|
||||||
The code examples below show how to create and fill in request and response
|
The code examples below show how to create and fill in request and response
|
||||||
objects:
|
objects: Here is simple example of building an
|
||||||
|
[@https://tools.ietf.org/html/rfc7231#section-4.3.1 HTTP GET]
|
||||||
|
request. The function
|
||||||
|
[link beast.ref.http__message.prepare prepare]
|
||||||
|
allows for various connection options. The use of prepare is optional,
|
||||||
|
the Connection field may be set manually if desired.
|
||||||
|
|
||||||
[table Create Request
|
[table Create Request
|
||||||
[[Statements] [Serialized Result]]
|
[[Statements] [Serialized Result]]
|
||||||
[[
|
[[
|
||||||
```
|
[http_snippet_2]
|
||||||
request<string_body> req;
|
|
||||||
req.version = 11; // HTTP/1.1
|
|
||||||
req.method(verb::get);
|
|
||||||
req.target("/index.htm");
|
|
||||||
req.insert("Accept", "text/html");
|
|
||||||
req.insert("Connection", "keep-alive");
|
|
||||||
req.insert("User-Agent", "Beast");
|
|
||||||
```
|
|
||||||
][
|
][
|
||||||
```
|
```
|
||||||
GET /index.htm HTTP/1.1\r\n
|
GET /index.htm HTTP/1.1\r\n
|
||||||
Accept: text/html\r\n
|
Accept: text/html\r\n
|
||||||
Connection: keep-alive\r\n
|
|
||||||
User-Agent: Beast\r\n
|
User-Agent: Beast\r\n
|
||||||
|
Connection: close\r\n
|
||||||
\r\n
|
\r\n
|
||||||
```
|
```
|
||||||
]]
|
]]
|
||||||
]
|
]
|
||||||
|
|
||||||
|
Here we create an HTTP response indicating success. Note that this
|
||||||
|
message has a body. The function
|
||||||
|
[link beast.ref.http__message.prepare prepare]
|
||||||
|
automatically sets the Content-Length or Transfer-Encoding field
|
||||||
|
depending on the body type. The use of prepare is optional, the
|
||||||
|
Content-Length and other fields may be set manually if desired.
|
||||||
|
|
||||||
[table Create Response
|
[table Create Response
|
||||||
[[Statements] [Serialized Result]]
|
[[Statements] [Serialized Result]]
|
||||||
[[
|
[[
|
||||||
```
|
[http_snippet_3]
|
||||||
response<string_body> res;
|
|
||||||
res.version = 11; // HTTP/1.1
|
|
||||||
res.result(status::ok);
|
|
||||||
res.body = "Hello, world!";
|
|
||||||
res.insert("Server", "Beast");
|
|
||||||
res.insert("Content-Length", res.body.size());
|
|
||||||
```
|
|
||||||
][
|
][
|
||||||
```
|
```
|
||||||
HTTP/1.1 200 OK\r\n
|
HTTP/1.1 200 OK\r\n
|
||||||
|
@@ -41,6 +41,8 @@ an exception upon error, and another which accepts as the last parameter an
|
|||||||
argument of type [link beast.ref.error_code `error_code&`]. If an error
|
argument of type [link beast.ref.error_code `error_code&`]. If an error
|
||||||
occurs this argument will be set to contain the error code.
|
occurs this argument will be set to contain the error code.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
[heading Reading]
|
[heading Reading]
|
||||||
|
|
||||||
Because a serialized header is not length-prefixed, algorithms which parse
|
Because a serialized header is not length-prefixed, algorithms which parse
|
||||||
@@ -50,11 +52,8 @@ __DynamicBuffer__ which persists between calls. Each read operation may
|
|||||||
consume bytes remaining in the buffer, and leave behind new bytes. In this
|
consume bytes remaining in the buffer, and leave behind new bytes. In this
|
||||||
example we declare the buffer and a message variable, then read a complete
|
example we declare the buffer and a message variable, then read a complete
|
||||||
HTTP request synchronously:
|
HTTP request synchronously:
|
||||||
```
|
|
||||||
flat_buffer buffer; // (The parser is optimized for flat buffers)
|
[http_snippet_4]
|
||||||
request<string_body> req;
|
|
||||||
read(sock, buffer, req);
|
|
||||||
```
|
|
||||||
|
|
||||||
In this example we used the __flat_buffer__. The parser in Beast is
|
In this example we used the __flat_buffer__. The parser in Beast is
|
||||||
optimized for structured HTTP data located in a single contiguous memory
|
optimized for structured HTTP data located in a single contiguous memory
|
||||||
@@ -74,15 +73,8 @@ valid until the operation has completed. Beast asynchronous initiation
|
|||||||
functions use Asio's completion handler model. Here we read a message
|
functions use Asio's completion handler model. Here we read a message
|
||||||
asynchronously. When the operation completes the message in the error
|
asynchronously. When the operation completes the message in the error
|
||||||
code indicating the result is printed:
|
code indicating the result is printed:
|
||||||
```
|
|
||||||
flat_buffer buffer;
|
[http_snippet_5]
|
||||||
response<string_body> res;
|
|
||||||
async_read(sock, buffer,
|
|
||||||
[&](error_code ec)
|
|
||||||
{
|
|
||||||
std::cerr << ec.message() << std::endl;
|
|
||||||
});
|
|
||||||
```
|
|
||||||
|
|
||||||
If a read stream algorithm cannot complete its operation without exceeding
|
If a read stream algorithm cannot complete its operation without exceeding
|
||||||
the maximum specified size of the dynamic buffer provided, the error
|
the maximum specified size of the dynamic buffer provided, the error
|
||||||
@@ -90,70 +82,27 @@ the maximum specified size of the dynamic buffer provided, the error
|
|||||||
is returned. This may be used to impose a limit on the maximum size of an
|
is returned. This may be used to impose a limit on the maximum size of an
|
||||||
HTTP message header for protection from buffer overflow attacks. The following
|
HTTP message header for protection from buffer overflow attacks. The following
|
||||||
code will generate an error:
|
code will generate an error:
|
||||||
```
|
|
||||||
// This buffer is too small for much of anything
|
|
||||||
flat_buffer buffer{10};
|
|
||||||
|
|
||||||
// Try to read a request
|
[http_snippet_6]
|
||||||
error_code ec;
|
|
||||||
request<string_body> req;
|
|
||||||
read(sock, buffer, req, ec);
|
|
||||||
if(ec == error::buffer_overflow)
|
|
||||||
std::cerr << "Buffer limit exceeded!" << std::endl;
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
[heading Writing]
|
[heading Writing]
|
||||||
|
|
||||||
A set of free functions allow serialization of an entire HTTP message to
|
A set of free functions allow serialization of an entire HTTP message to
|
||||||
a stream. This function sends a message synchronously on the socket,
|
a stream. If a response has no declared content length, and no chunked
|
||||||
throwing an exception if an error occurs:
|
transfer encoding, the end of the message is indicated by the server closing
|
||||||
```
|
|
||||||
template<class Body, class Fields>
|
|
||||||
void send(response<Body, Fields> const& res)
|
|
||||||
{
|
|
||||||
write(sock, res);
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
If a response has no declared content length, and no chunked transfer
|
|
||||||
encoding, the end of the message is indicated by the server closing
|
|
||||||
the connection. When sending such a response, Beast will return the
|
the connection. When sending such a response, Beast will return the
|
||||||
error `boost::asio::error::eof` from the write algorithm to indicate
|
[link beast.ref.http__error `error::end_of_stream`]
|
||||||
|
from the write algorithm to indicate
|
||||||
to the caller that the connection should be closed. This example
|
to the caller that the connection should be closed. This example
|
||||||
constructs and sends a response whose body length is determined by
|
constructs and sends a response whose body length is determined by
|
||||||
the number of octets received prior to the server closing the connection:
|
the number of octets received prior to the server closing the connection:
|
||||||
```
|
|
||||||
void send()
|
|
||||||
{
|
|
||||||
response<string_body> res;
|
|
||||||
res.version = 11;
|
|
||||||
res.result(status::ok);
|
|
||||||
res.insert("Server", "Beast");
|
|
||||||
res.body = "Hello, world!";
|
|
||||||
|
|
||||||
error_code ec;
|
[http_snippet_7]
|
||||||
write(sock, res, ec);
|
|
||||||
if(ec == boost::asio::error::eof)
|
|
||||||
sock.close();
|
|
||||||
else
|
|
||||||
BOOST_ASSERT(ec);
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
An asynchronous version is also available:
|
The asynchronous version could be used instead:
|
||||||
|
|
||||||
```
|
[http_snippet_8]
|
||||||
template<class Body, class Fields>
|
|
||||||
void send_async(response<Body, Fields> const& res)
|
|
||||||
{
|
|
||||||
async_write(sock, res,
|
|
||||||
[&](error_code)
|
|
||||||
{
|
|
||||||
if(ec)
|
|
||||||
std::cerr << ec.message() << std::endl;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
[endsect]
|
[endsect]
|
||||||
|
@@ -22,32 +22,20 @@ Sophisticated algorithms will need to do more:
|
|||||||
All of these operations require callers to manage the lifetime of state
|
All of these operations require callers to manage the lifetime of state
|
||||||
information associated with the operation, by constructing a __serializer__
|
information associated with the operation, by constructing a __serializer__
|
||||||
object with the message to be sent. The serializer type has this declaration:
|
object with the message to be sent. The serializer type has this declaration:
|
||||||
```
|
|
||||||
template<
|
[http_snippet_9]
|
||||||
bool isRequest,
|
|
||||||
class Body,
|
|
||||||
class Fields,
|
|
||||||
class ChunkDecorator = no_chunk_decorator,
|
|
||||||
class Allocator = std::allocator<char>
|
|
||||||
>
|
|
||||||
class serializer;
|
|
||||||
```
|
|
||||||
|
|
||||||
The choices for template types must match the message passed on construction.
|
The choices for template types must match the message passed on construction.
|
||||||
This code creates an HTTP response and the corresponding serializer:
|
This code creates an HTTP response and the corresponding serializer:
|
||||||
```
|
|
||||||
response<string_body> res;
|
[http_snippet_10]
|
||||||
...
|
|
||||||
serializer<false, string_body, fields> sr{res};
|
|
||||||
```
|
|
||||||
The convenience function
|
The convenience function
|
||||||
[link beast.ref.http__make_serializer `make_serializer`]
|
[link beast.ref.http__make_serializer `make_serializer`]
|
||||||
is provided to avoid repetition of template argument types. The declaration
|
is provided to avoid repetition of template argument types. The declaration
|
||||||
for `sr` in the code above may be written as:
|
for `sr` in the code above may be written as:
|
||||||
```
|
|
||||||
...
|
[http_snippet_11]
|
||||||
auto sr = make_serializer(res);
|
|
||||||
```
|
|
||||||
|
|
||||||
The stream operations which work on serializers are:
|
The stream operations which work on serializers are:
|
||||||
|
|
||||||
@@ -88,19 +76,6 @@ The stream operations which work on serializers are:
|
|||||||
Here is an example of using a serializer to send a message on a stream
|
Here is an example of using a serializer to send a message on a stream
|
||||||
synchronously. This performs the same operation as calling `write(stream, m)`:
|
synchronously. This performs the same operation as calling `write(stream, m)`:
|
||||||
|
|
||||||
```
|
[http_snippet_12]
|
||||||
template<class SyncWriteStream, bool isRequest, class Body, class Fields>
|
|
||||||
void send(SyncWriteStream& stream, message<isRequest, Body, Fields> const& m)
|
|
||||||
{
|
|
||||||
static_assert(is_sync_write_stream<SyncWriteStream>::value,
|
|
||||||
"SyncWriteStream requirements not met");
|
|
||||||
serializer<isRequest, Body, Fields> sr{m};
|
|
||||||
do
|
|
||||||
{
|
|
||||||
write_some(stream, sr);
|
|
||||||
}
|
|
||||||
while(! sr.is_done());
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
[endsect]
|
[endsect]
|
||||||
|
@@ -114,22 +114,7 @@ accesses the contained object, and depending on the types used to instantiate
|
|||||||
the parser, it may be possible to acquire ownership of the header or message
|
the parser, it may be possible to acquire ownership of the header or message
|
||||||
captive object and destroy the parser. In this example we read an HTTP
|
captive object and destroy the parser. In this example we read an HTTP
|
||||||
response with a string body using a parser, then print the response:
|
response with a string body using a parser, then print the response:
|
||||||
```
|
|
||||||
template<class SyncReadStream>
|
|
||||||
void print_response(SyncReadStream& stream)
|
|
||||||
{
|
|
||||||
static_assert(is_sync_read_stream<SyncReadStream>::value,
|
|
||||||
"SyncReadStream requirements not met");
|
|
||||||
|
|
||||||
// Declare a parser for an HTTP response
|
[http_snippet_13]
|
||||||
response_parser<string_body> parser;
|
|
||||||
|
|
||||||
// Read the entire message
|
|
||||||
read(stream, parser);
|
|
||||||
|
|
||||||
// Now print the message
|
|
||||||
std::cout << parser.get() << std::endl;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
[endsect]
|
[endsect]
|
||||||
|
@@ -30,63 +30,13 @@ expressed with a generic lambda. The function
|
|||||||
[link beast.ref.http__serializer.is_done `serializer::is_done`]
|
[link beast.ref.http__serializer.is_done `serializer::is_done`]
|
||||||
will return `true` when all the buffers have been produced. This C++14
|
will return `true` when all the buffers have been produced. This C++14
|
||||||
example prints the buffers to standard output:
|
example prints the buffers to standard output:
|
||||||
```
|
|
||||||
template<bool isRequest, class Body, class Fields>
|
[http_snippet_14]
|
||||||
void print(message<isRequest, Body, Fields> const& m)
|
|
||||||
{
|
|
||||||
error_code ec;
|
|
||||||
serializer<isRequest, Body, Fields> sr{m};
|
|
||||||
do
|
|
||||||
{
|
|
||||||
sr.get(ec,
|
|
||||||
[&sr](error_code& ec, auto const& buffer)
|
|
||||||
{
|
|
||||||
std::cout << buffers(buffer);
|
|
||||||
sr.consume(boost::asio::buffer_size(buffer));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
while(! ec && ! sr.is_done());
|
|
||||||
if(! ec)
|
|
||||||
std::cout << std::endl;
|
|
||||||
else
|
|
||||||
std::cerr << ec.message() << std::endl;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Generic lambda expressions are only available in C++14 or later. A functor
|
Generic lambda expressions are only available in C++14 or later. A functor
|
||||||
with a templated function call operator is necessary to use C++11 as shown:
|
with a templated function call operator is necessary to use C++11 as shown:
|
||||||
```
|
|
||||||
template<class Serializer>
|
|
||||||
struct lambda
|
|
||||||
{
|
|
||||||
Serializer& sr;
|
|
||||||
|
|
||||||
lambda(Serializer& sr_) : sr(sr_) {}
|
[http_snippet_15]
|
||||||
|
|
||||||
template<class ConstBufferSequence>
|
|
||||||
void operator()(error_code& ec, ConstBufferSequence const& buffer)
|
|
||||||
{
|
|
||||||
std::cout << buffers(buffer);
|
|
||||||
sr.consume(boost::asio::buffer_size(buffer));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template<bool isRequest, class Body, class Fields>
|
|
||||||
void print(message<isRequest, Body, Fields> const& m)
|
|
||||||
{
|
|
||||||
error_code ec;
|
|
||||||
serializer<isRequest, Body, Fields> sr{m};
|
|
||||||
do
|
|
||||||
{
|
|
||||||
sr.get(ec, lambda<decltype(sr)>{sr});
|
|
||||||
}
|
|
||||||
while(! ec && ! sr.is_done());
|
|
||||||
if(! ec)
|
|
||||||
std::cout << std::endl;
|
|
||||||
else
|
|
||||||
std::cerr << ec.message() << std::endl;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
[heading Split Serialization]
|
[heading Split Serialization]
|
||||||
|
|
||||||
@@ -102,42 +52,8 @@ to the body. The function
|
|||||||
[link beast.ref.http__serializer.is_header_done `serializer::is_header_done`]
|
[link beast.ref.http__serializer.is_header_done `serializer::is_header_done`]
|
||||||
informs the caller whether the header has completed serialization. In this
|
informs the caller whether the header has completed serialization. In this
|
||||||
C++14 example we print the header first, followed by the body:
|
C++14 example we print the header first, followed by the body:
|
||||||
```
|
|
||||||
template<bool isRequest, class Body, class Fields>
|
[http_snippet_16]
|
||||||
void print(message<isRequest, Body, Fields> const& m)
|
|
||||||
{
|
|
||||||
error_code ec;
|
|
||||||
serializer<isRequest, Body, Fields> sr{m};
|
|
||||||
sr.split(true);
|
|
||||||
std::cout << "Header:" << std::endl;
|
|
||||||
do
|
|
||||||
{
|
|
||||||
sr.get(ec,
|
|
||||||
[&sr](error_code& ec, auto const& buffer)
|
|
||||||
{
|
|
||||||
std::cout << buffers(buffer);
|
|
||||||
sr.consume(boost::asio::buffer_size(buffer));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
while(! sr.is_header_done());
|
|
||||||
if(! ec && ! sr.is_done())
|
|
||||||
{
|
|
||||||
std::cout << "Body:" << std::endl;
|
|
||||||
do
|
|
||||||
{
|
|
||||||
sr.get(ec,
|
|
||||||
[&sr](error_code& ec, auto const& buffer)
|
|
||||||
{
|
|
||||||
std::cout << buffers(buffer);
|
|
||||||
sr.consume(boost::asio::buffer_size(buffer));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
while(! ec && ! sr.is_done());
|
|
||||||
}
|
|
||||||
if(ec)
|
|
||||||
std::cerr << ec.message() << std::endl;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
[heading Chunk Decorators]
|
[heading Chunk Decorators]
|
||||||
|
|
||||||
@@ -173,25 +89,7 @@ after subsequent calls.
|
|||||||
|
|
||||||
Here, we declare a decorator which sets an extension variable `x` equal
|
Here, we declare a decorator which sets an extension variable `x` equal
|
||||||
to the size of the chunk in bytes, and returns a single trailer field:
|
to the size of the chunk in bytes, and returns a single trailer field:
|
||||||
```
|
|
||||||
struct decorator
|
|
||||||
{
|
|
||||||
std::string s;
|
|
||||||
|
|
||||||
template<class ConstBufferSequence>
|
[http_snippet_17]
|
||||||
string_view
|
|
||||||
operator()(ConstBufferSequence const& buffers)
|
|
||||||
{
|
|
||||||
s = ";x=" + std::to_string(boost::asio::buffer_size(buffers));
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
string_view
|
|
||||||
operator()(boost::asio::null_buffers)
|
|
||||||
{
|
|
||||||
return "Result: OK\r\n";
|
|
||||||
}
|
|
||||||
};
|
|
||||||
```
|
|
||||||
|
|
||||||
[endsect]
|
[endsect]
|
||||||
|
@@ -143,6 +143,9 @@ public:
|
|||||||
|
|
||||||
//[core_sample_echo_op_4
|
//[core_sample_echo_op_4
|
||||||
|
|
||||||
|
// echo_op is callable with the signature void(error_code, bytes_transferred),
|
||||||
|
// allowing `*this` to be used as both a ReadHandler and a WriteHandler.
|
||||||
|
//
|
||||||
template<class AsyncStream, class Handler>
|
template<class AsyncStream, class Handler>
|
||||||
void echo_op<AsyncStream, Handler>::
|
void echo_op<AsyncStream, Handler>::
|
||||||
operator()(beast::error_code ec, std::size_t bytes_transferred)
|
operator()(beast::error_code ec, std::size_t bytes_transferred)
|
||||||
|
@@ -24,6 +24,7 @@ unit-test core-tests :
|
|||||||
core/buffers_adapter.cpp
|
core/buffers_adapter.cpp
|
||||||
core/clamp.cpp
|
core/clamp.cpp
|
||||||
core/consuming_buffers.cpp
|
core/consuming_buffers.cpp
|
||||||
|
core/doc_snippets.cpp
|
||||||
core/error.cpp
|
core/error.cpp
|
||||||
core/flat_buffer.cpp
|
core/flat_buffer.cpp
|
||||||
core/handler_alloc.cpp
|
core/handler_alloc.cpp
|
||||||
@@ -44,6 +45,7 @@ unit-test http-tests :
|
|||||||
http/basic_parser.cpp
|
http/basic_parser.cpp
|
||||||
http/buffer_body.cpp
|
http/buffer_body.cpp
|
||||||
http/doc_http_samples.cpp
|
http/doc_http_samples.cpp
|
||||||
|
http/doc_snippets.cpp
|
||||||
http/dynamic_body.cpp
|
http/dynamic_body.cpp
|
||||||
http/error.cpp
|
http/error.cpp
|
||||||
http/field.cpp
|
http/field.cpp
|
||||||
|
@@ -8,15 +8,16 @@ add_executable (core-tests
|
|||||||
${BEAST_INCLUDES}
|
${BEAST_INCLUDES}
|
||||||
${EXTRAS_INCLUDES}
|
${EXTRAS_INCLUDES}
|
||||||
../../extras/beast/unit_test/main.cpp
|
../../extras/beast/unit_test/main.cpp
|
||||||
buffer_test.hpp
|
|
||||||
async_result.cpp
|
async_result.cpp
|
||||||
bind_handler.cpp
|
bind_handler.cpp
|
||||||
buffer_cat.cpp
|
buffer_cat.cpp
|
||||||
buffer_prefix.cpp
|
buffer_prefix.cpp
|
||||||
|
buffer_test.hpp
|
||||||
|
buffered_read_stream.cpp
|
||||||
buffers_adapter.cpp
|
buffers_adapter.cpp
|
||||||
clamp.cpp
|
clamp.cpp
|
||||||
consuming_buffers.cpp
|
consuming_buffers.cpp
|
||||||
buffered_read_stream.cpp
|
doc_snippets.cpp
|
||||||
error.cpp
|
error.cpp
|
||||||
flat_buffer.cpp
|
flat_buffer.cpp
|
||||||
handler_alloc.cpp
|
handler_alloc.cpp
|
||||||
|
66
test/core/doc_snippets.cpp
Normal file
66
test/core/doc_snippets.cpp
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
//
|
||||||
|
// 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)
|
||||||
|
//
|
||||||
|
|
||||||
|
//[snippet_core_1a
|
||||||
|
|
||||||
|
#include <beast/core.hpp>
|
||||||
|
#include <boost/asio.hpp>
|
||||||
|
#include <iostream>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
|
//]
|
||||||
|
|
||||||
|
using namespace beast;
|
||||||
|
|
||||||
|
namespace doc_core_snippets {
|
||||||
|
|
||||||
|
void fxx()
|
||||||
|
{
|
||||||
|
|
||||||
|
//[snippet_core_1b
|
||||||
|
//
|
||||||
|
using namespace beast;
|
||||||
|
|
||||||
|
boost::asio::io_service ios;
|
||||||
|
boost::asio::io_service::work work{ios};
|
||||||
|
std::thread t{[&](){ ios.run(); }};
|
||||||
|
|
||||||
|
error_code ec;
|
||||||
|
boost::asio::ip::tcp::socket sock{ios};
|
||||||
|
|
||||||
|
//]
|
||||||
|
|
||||||
|
{
|
||||||
|
//[snippet_core_2
|
||||||
|
|
||||||
|
auto host = "www.example.com";
|
||||||
|
boost::asio::ip::tcp::resolver r{ios};
|
||||||
|
boost::asio::ip::tcp::socket stream{ios};
|
||||||
|
boost::asio::connect(stream, r.resolve(
|
||||||
|
boost::asio::ip::tcp::resolver::query{host, "http"}));
|
||||||
|
|
||||||
|
// At this point `stream` is a connected to a remote
|
||||||
|
// host and may be used to perform stream operations.
|
||||||
|
|
||||||
|
//]
|
||||||
|
}
|
||||||
|
|
||||||
|
} // fxx()
|
||||||
|
|
||||||
|
//[snippet_core_3
|
||||||
|
|
||||||
|
template<class SyncWriteStream>
|
||||||
|
void write_string(SyncWriteStream& stream, string_view s)
|
||||||
|
{
|
||||||
|
static_assert(is_sync_write_stream<SyncWriteStream>::value,
|
||||||
|
"SyncWriteStream requirements not met");
|
||||||
|
boost::asio::write(stream, boost::asio::const_buffers_1(s.data(), s.size()));
|
||||||
|
}
|
||||||
|
|
||||||
|
//]
|
||||||
|
|
||||||
|
} // doc_core_snippets
|
@@ -15,6 +15,7 @@ add_executable (http-tests
|
|||||||
basic_parser.cpp
|
basic_parser.cpp
|
||||||
buffer_body.cpp
|
buffer_body.cpp
|
||||||
doc_http_samples.cpp
|
doc_http_samples.cpp
|
||||||
|
doc_snippets.cpp
|
||||||
dynamic_body.cpp
|
dynamic_body.cpp
|
||||||
empty_body.cpp
|
empty_body.cpp
|
||||||
error.cpp
|
error.cpp
|
||||||
|
356
test/http/doc_snippets.cpp
Normal file
356
test/http/doc_snippets.cpp
Normal file
@@ -0,0 +1,356 @@
|
|||||||
|
//
|
||||||
|
// 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)
|
||||||
|
//
|
||||||
|
|
||||||
|
#include <beast/core.hpp>
|
||||||
|
#include <boost/asio.hpp>
|
||||||
|
#include <iostream>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
|
using namespace beast;
|
||||||
|
|
||||||
|
//[http_snippet_1
|
||||||
|
|
||||||
|
#include <beast/http.hpp>
|
||||||
|
using namespace beast::http;
|
||||||
|
|
||||||
|
//]
|
||||||
|
|
||||||
|
namespace doc_http_snippets {
|
||||||
|
|
||||||
|
void fxx() {
|
||||||
|
|
||||||
|
boost::asio::io_service ios;
|
||||||
|
boost::asio::io_service::work work{ios};
|
||||||
|
std::thread t{[&](){ ios.run(); }};
|
||||||
|
error_code ec;
|
||||||
|
boost::asio::ip::tcp::socket sock{ios};
|
||||||
|
|
||||||
|
{
|
||||||
|
//[http_snippet_2
|
||||||
|
|
||||||
|
request<string_body> req;
|
||||||
|
req.version = 11; // HTTP/1.1
|
||||||
|
req.method(verb::get);
|
||||||
|
req.target("/index.htm");
|
||||||
|
req.insert("Accept", "text/html");
|
||||||
|
req.insert("User-Agent", "Beast");
|
||||||
|
req.prepare(connection::close);
|
||||||
|
|
||||||
|
//]
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
//[http_snippet_3
|
||||||
|
|
||||||
|
response<string_body> res;
|
||||||
|
res.version = 11; // HTTP/1.1
|
||||||
|
res.result(status::ok);
|
||||||
|
res.insert("Server", "Beast");
|
||||||
|
res.body = "Hello, world!";
|
||||||
|
res.prepare();
|
||||||
|
|
||||||
|
//]
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
//[http_snippet_4
|
||||||
|
|
||||||
|
flat_buffer buffer; // (The parser is optimized for flat buffers)
|
||||||
|
request<string_body> req;
|
||||||
|
read(sock, buffer, req);
|
||||||
|
|
||||||
|
//]
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
//[http_snippet_5
|
||||||
|
|
||||||
|
flat_buffer buffer;
|
||||||
|
response<string_body> res;
|
||||||
|
async_read(sock, buffer, res,
|
||||||
|
[&](error_code ec)
|
||||||
|
{
|
||||||
|
std::cerr << ec.message() << std::endl;
|
||||||
|
});
|
||||||
|
|
||||||
|
//]
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
//[http_snippet_6
|
||||||
|
|
||||||
|
// This buffer's max size is too small for much of anything
|
||||||
|
flat_buffer buffer{10};
|
||||||
|
|
||||||
|
// Try to read a request
|
||||||
|
request<string_body> req;
|
||||||
|
read(sock, buffer, req, ec);
|
||||||
|
if(ec == error::buffer_overflow)
|
||||||
|
std::cerr << "Buffer limit exceeded!" << std::endl;
|
||||||
|
|
||||||
|
//]
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
//[http_snippet_7
|
||||||
|
|
||||||
|
response<string_body> res;
|
||||||
|
res.version = 11;
|
||||||
|
res.result(status::ok);
|
||||||
|
res.insert("Server", "Beast");
|
||||||
|
res.body = "Hello, world!";
|
||||||
|
|
||||||
|
write(sock, res, ec);
|
||||||
|
if(ec == error::end_of_stream)
|
||||||
|
sock.close();
|
||||||
|
//]
|
||||||
|
|
||||||
|
//[http_snippet_8
|
||||||
|
async_write(sock, res,
|
||||||
|
[&](error_code)
|
||||||
|
{
|
||||||
|
if(ec)
|
||||||
|
std::cerr << ec.message() << std::endl;
|
||||||
|
});
|
||||||
|
//]
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
//[http_snippet_10
|
||||||
|
|
||||||
|
response<string_body> res;
|
||||||
|
|
||||||
|
serializer<false, string_body, fields> sr{res};
|
||||||
|
|
||||||
|
//]
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
response<string_body> res;
|
||||||
|
//[http_snippet_11
|
||||||
|
|
||||||
|
auto sr = make_serializer(res);
|
||||||
|
|
||||||
|
//]
|
||||||
|
}
|
||||||
|
|
||||||
|
} // fxx()
|
||||||
|
|
||||||
|
//[http_snippet_12
|
||||||
|
|
||||||
|
/** Send a message to a stream synchronously.
|
||||||
|
|
||||||
|
@param stream The stream to write to. This type must support
|
||||||
|
the @b SyncWriteStream concept.
|
||||||
|
|
||||||
|
@param m The message to send. The Body type must support
|
||||||
|
the @b BodyReader concept.
|
||||||
|
*/
|
||||||
|
template<
|
||||||
|
class SyncWriteStream,
|
||||||
|
bool isRequest, class Body, class Fields>
|
||||||
|
void
|
||||||
|
send(
|
||||||
|
SyncWriteStream& stream,
|
||||||
|
message<isRequest, Body, Fields> const& m)
|
||||||
|
{
|
||||||
|
// Check the template types
|
||||||
|
static_assert(is_sync_write_stream<SyncWriteStream>::value,
|
||||||
|
"SyncWriteStream requirements not met");
|
||||||
|
static_assert(is_body_reader<Body>::value,
|
||||||
|
"BodyReader requirements not met");
|
||||||
|
|
||||||
|
// Create the instance of serializer for the message
|
||||||
|
serializer<isRequest, Body, Fields> sr{m};
|
||||||
|
|
||||||
|
// Loop until the serializer is finished
|
||||||
|
do
|
||||||
|
{
|
||||||
|
// This call guarantees it will make some
|
||||||
|
// forward progress, or otherwise return an error.
|
||||||
|
write_some(stream, sr);
|
||||||
|
}
|
||||||
|
while(! sr.is_done());
|
||||||
|
}
|
||||||
|
|
||||||
|
//]
|
||||||
|
|
||||||
|
//[http_snippet_13
|
||||||
|
|
||||||
|
template<
|
||||||
|
class SyncReadStream>
|
||||||
|
void
|
||||||
|
print_response(
|
||||||
|
SyncReadStream& stream)
|
||||||
|
{
|
||||||
|
static_assert(is_sync_read_stream<SyncReadStream>::value,
|
||||||
|
"SyncReadStream requirements not met");
|
||||||
|
|
||||||
|
// Declare a parser for an HTTP response
|
||||||
|
response_parser<string_body> parser;
|
||||||
|
|
||||||
|
// Read the entire message
|
||||||
|
read(stream, parser);
|
||||||
|
|
||||||
|
// Now print the message
|
||||||
|
std::cout << parser.get() << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
//]
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
//[http_snippet_14
|
||||||
|
|
||||||
|
template<bool isRequest, class Body, class Fields>
|
||||||
|
void
|
||||||
|
print_cxx14(message<isRequest, Body, Fields> const& m)
|
||||||
|
{
|
||||||
|
error_code ec;
|
||||||
|
serializer<isRequest, Body, Fields> sr{m};
|
||||||
|
do
|
||||||
|
{
|
||||||
|
sr.get(ec,
|
||||||
|
[&sr](error_code& ec, auto const& buffer)
|
||||||
|
{
|
||||||
|
std::cout << buffers(buffer);
|
||||||
|
sr.consume(boost::asio::buffer_size(buffer));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
while(! ec && ! sr.is_done());
|
||||||
|
if(! ec)
|
||||||
|
std::cout << std::endl;
|
||||||
|
else
|
||||||
|
std::cerr << ec.message() << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
//]
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//[http_snippet_15
|
||||||
|
|
||||||
|
template<class Serializer>
|
||||||
|
struct lambda
|
||||||
|
{
|
||||||
|
Serializer& sr;
|
||||||
|
|
||||||
|
lambda(Serializer& sr_) : sr(sr_) {}
|
||||||
|
|
||||||
|
template<class ConstBufferSequence>
|
||||||
|
void operator()(error_code& ec, ConstBufferSequence const& buffer)
|
||||||
|
{
|
||||||
|
std::cout << buffers(buffer);
|
||||||
|
sr.consume(boost::asio::buffer_size(buffer));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<bool isRequest, class Body, class Fields>
|
||||||
|
void
|
||||||
|
print(message<isRequest, Body, Fields> const& m)
|
||||||
|
{
|
||||||
|
error_code ec;
|
||||||
|
serializer<isRequest, Body, Fields> sr{m};
|
||||||
|
do
|
||||||
|
{
|
||||||
|
sr.get(ec, lambda<decltype(sr)>{sr});
|
||||||
|
}
|
||||||
|
while(! ec && ! sr.is_done());
|
||||||
|
if(! ec)
|
||||||
|
std::cout << std::endl;
|
||||||
|
else
|
||||||
|
std::cerr << ec.message() << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
//]
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
//[http_snippet_16
|
||||||
|
|
||||||
|
template<bool isRequest, class Body, class Fields>
|
||||||
|
void
|
||||||
|
split_print_cxx14(message<isRequest, Body, Fields> const& m)
|
||||||
|
{
|
||||||
|
error_code ec;
|
||||||
|
serializer<isRequest, Body, Fields> sr{m};
|
||||||
|
sr.split(true);
|
||||||
|
std::cout << "Header:" << std::endl;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
sr.get(ec,
|
||||||
|
[&sr](error_code& ec, auto const& buffer)
|
||||||
|
{
|
||||||
|
std::cout << buffers(buffer);
|
||||||
|
sr.consume(boost::asio::buffer_size(buffer));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
while(! sr.is_header_done());
|
||||||
|
if(! ec && ! sr.is_done())
|
||||||
|
{
|
||||||
|
std::cout << "Body:" << std::endl;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
sr.get(ec,
|
||||||
|
[&sr](error_code& ec, auto const& buffer)
|
||||||
|
{
|
||||||
|
std::cout << buffers(buffer);
|
||||||
|
sr.consume(boost::asio::buffer_size(buffer));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
while(! ec && ! sr.is_done());
|
||||||
|
}
|
||||||
|
if(ec)
|
||||||
|
std::cerr << ec.message() << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
//]
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//[http_snippet_17
|
||||||
|
|
||||||
|
struct decorator
|
||||||
|
{
|
||||||
|
std::string s;
|
||||||
|
|
||||||
|
template<class ConstBufferSequence>
|
||||||
|
string_view
|
||||||
|
operator()(ConstBufferSequence const& buffers)
|
||||||
|
{
|
||||||
|
s = ";x=" + std::to_string(boost::asio::buffer_size(buffers));
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
string_view
|
||||||
|
operator()(boost::asio::null_buffers)
|
||||||
|
{
|
||||||
|
return "Result: OK\r\n";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//]
|
||||||
|
|
||||||
|
} // doc_http_snippets
|
||||||
|
|
||||||
|
namespace beast {
|
||||||
|
namespace http {
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
//[http_snippet_9]
|
||||||
|
|
||||||
|
template<
|
||||||
|
bool isRequest,
|
||||||
|
class Body,
|
||||||
|
class Fields,
|
||||||
|
class ChunkDecorator = no_chunk_decorator,
|
||||||
|
class Allocator = std::allocator<char>
|
||||||
|
>
|
||||||
|
class serializer;
|
||||||
|
|
||||||
|
//]
|
||||||
|
#endif
|
||||||
|
|
||||||
|
} // http
|
||||||
|
} // beast
|
||||||
|
|
Reference in New Issue
Block a user