mirror of
https://github.com/boostorg/beast.git
synced 2025-07-31 05:17:26 +02:00
Documentation work
This commit is contained in:
@ -72,6 +72,8 @@
|
||||
[import ../examples/websocket_example.cpp]
|
||||
[import ../examples/echo_op.cpp]
|
||||
[import ../examples/doc_http_samples.hpp]
|
||||
[import ../test/core/doc_snippets.cpp]
|
||||
[import ../test/http/doc_snippets.cpp]
|
||||
|
||||
[include 1_overview.qbk]
|
||||
[include 2_examples.qbk]
|
||||
|
@ -17,21 +17,9 @@ lists these facilities by group, with descriptions.
|
||||
This documentation assumes familiarity with __Asio__. Sample
|
||||
code and identifiers used throughout are written as if the
|
||||
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;
|
||||
boost::asio::io_service work{ios};
|
||||
std::thread t{[&](){ ios.run(); }};
|
||||
|
||||
error_code ec;
|
||||
|
||||
```
|
||||
[snippet_core_1a]
|
||||
[snippet_core_1b]
|
||||
]
|
||||
|
||||
[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
|
||||
reminder of how to work
|
||||
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
|
||||
// host and may be used to perform stream operations.
|
||||
```
|
||||
[snippet_core_2]
|
||||
|
||||
Throughout this documentation identifiers with the following names have
|
||||
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
|
||||
behaviors. This example shows how a template function which writes to a
|
||||
synchronous stream may check its argument:
|
||||
```
|
||||
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()));
|
||||
}
|
||||
```
|
||||
|
||||
[snippet_core_3]
|
||||
|
||||
[endsect]
|
||||
|
@ -54,12 +54,6 @@ this echo operation:
|
||||
|
||||
[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
|
||||
directory.
|
||||
|
||||
|
@ -66,10 +66,8 @@ format using __Asio__. Specifically, the library provides:
|
||||
the HTTP protocol specification described in __rfc7230__. Sample
|
||||
code and identifiers mentioned in this section is written as if
|
||||
these declarations are in effect:
|
||||
```
|
||||
#include <beast/http.hpp>
|
||||
using namespace beast::http;
|
||||
```
|
||||
|
||||
[http_snippet_1]
|
||||
]
|
||||
|
||||
[include 4_01_primer.qbk]
|
||||
|
@ -116,42 +116,39 @@ the __Body__ requirements:
|
||||
[heading Usage]
|
||||
|
||||
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
|
||||
[[Statements] [Serialized Result]]
|
||||
[[
|
||||
```
|
||||
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");
|
||||
```
|
||||
[http_snippet_2]
|
||||
][
|
||||
```
|
||||
GET /index.htm HTTP/1.1\r\n
|
||||
Accept: text/html\r\n
|
||||
Connection: keep-alive\r\n
|
||||
User-Agent: Beast\r\n
|
||||
Connection: close\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
|
||||
[[Statements] [Serialized Result]]
|
||||
[[
|
||||
```
|
||||
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_snippet_3]
|
||||
][
|
||||
```
|
||||
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
|
||||
occurs this argument will be set to contain the error code.
|
||||
|
||||
|
||||
|
||||
[heading Reading]
|
||||
|
||||
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
|
||||
example we declare the buffer and a message variable, then read a complete
|
||||
HTTP request synchronously:
|
||||
```
|
||||
flat_buffer buffer; // (The parser is optimized for flat buffers)
|
||||
request<string_body> req;
|
||||
read(sock, buffer, req);
|
||||
```
|
||||
|
||||
[http_snippet_4]
|
||||
|
||||
In this example we used the __flat_buffer__. The parser in Beast is
|
||||
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
|
||||
asynchronously. When the operation completes the message in the error
|
||||
code indicating the result is printed:
|
||||
```
|
||||
flat_buffer buffer;
|
||||
response<string_body> res;
|
||||
async_read(sock, buffer,
|
||||
[&](error_code ec)
|
||||
{
|
||||
std::cerr << ec.message() << std::endl;
|
||||
});
|
||||
```
|
||||
|
||||
[http_snippet_5]
|
||||
|
||||
If a read stream algorithm cannot complete its operation without exceeding
|
||||
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
|
||||
HTTP message header for protection from buffer overflow attacks. The following
|
||||
code will generate an error:
|
||||
```
|
||||
// This buffer is too small for much of anything
|
||||
flat_buffer buffer{10};
|
||||
|
||||
// Try to read a request
|
||||
error_code ec;
|
||||
request<string_body> req;
|
||||
read(sock, buffer, req, ec);
|
||||
if(ec == error::buffer_overflow)
|
||||
std::cerr << "Buffer limit exceeded!" << std::endl;
|
||||
[http_snippet_6]
|
||||
|
||||
|
||||
```
|
||||
|
||||
[heading Writing]
|
||||
|
||||
A set of free functions allow serialization of an entire HTTP message to
|
||||
a stream. This function sends a message synchronously on the socket,
|
||||
throwing an exception if an error occurs:
|
||||
```
|
||||
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
|
||||
a stream. 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
|
||||
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
|
||||
constructs and sends a response whose body length is determined by
|
||||
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;
|
||||
write(sock, res, ec);
|
||||
if(ec == boost::asio::error::eof)
|
||||
sock.close();
|
||||
else
|
||||
BOOST_ASSERT(ec);
|
||||
}
|
||||
```
|
||||
[http_snippet_7]
|
||||
|
||||
An asynchronous version is also available:
|
||||
The asynchronous version could be used instead:
|
||||
|
||||
```
|
||||
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;
|
||||
});
|
||||
}
|
||||
```
|
||||
[http_snippet_8]
|
||||
|
||||
[endsect]
|
||||
|
@ -22,32 +22,20 @@ Sophisticated algorithms will need to do more:
|
||||
All of these operations require callers to manage the lifetime of state
|
||||
information associated with the operation, by constructing a __serializer__
|
||||
object with the message to be sent. The serializer type has this declaration:
|
||||
```
|
||||
template<
|
||||
bool isRequest,
|
||||
class Body,
|
||||
class Fields,
|
||||
class ChunkDecorator = no_chunk_decorator,
|
||||
class Allocator = std::allocator<char>
|
||||
>
|
||||
class serializer;
|
||||
```
|
||||
|
||||
[http_snippet_9]
|
||||
|
||||
The choices for template types must match the message passed on construction.
|
||||
This code creates an HTTP response and the corresponding serializer:
|
||||
```
|
||||
response<string_body> res;
|
||||
...
|
||||
serializer<false, string_body, fields> sr{res};
|
||||
```
|
||||
|
||||
[http_snippet_10]
|
||||
|
||||
The convenience function
|
||||
[link beast.ref.http__make_serializer `make_serializer`]
|
||||
is provided to avoid repetition of template argument types. The declaration
|
||||
for `sr` in the code above may be written as:
|
||||
```
|
||||
...
|
||||
auto sr = make_serializer(res);
|
||||
```
|
||||
|
||||
[http_snippet_11]
|
||||
|
||||
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
|
||||
synchronously. This performs the same operation as calling `write(stream, m)`:
|
||||
|
||||
```
|
||||
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());
|
||||
}
|
||||
```
|
||||
[http_snippet_12]
|
||||
|
||||
[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
|
||||
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:
|
||||
```
|
||||
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;
|
||||
}
|
||||
```
|
||||
[http_snippet_13]
|
||||
|
||||
[endsect]
|
||||
|
@ -30,63 +30,13 @@ expressed with a generic lambda. The function
|
||||
[link beast.ref.http__serializer.is_done `serializer::is_done`]
|
||||
will return `true` when all the buffers have been produced. This C++14
|
||||
example prints the buffers to standard output:
|
||||
```
|
||||
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,
|
||||
[&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;
|
||||
}
|
||||
```
|
||||
|
||||
[http_snippet_14]
|
||||
|
||||
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:
|
||||
```
|
||||
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;
|
||||
}
|
||||
```
|
||||
[http_snippet_15]
|
||||
|
||||
[heading Split Serialization]
|
||||
|
||||
@ -102,42 +52,8 @@ to the body. The function
|
||||
[link beast.ref.http__serializer.is_header_done `serializer::is_header_done`]
|
||||
informs the caller whether the header has completed serialization. In this
|
||||
C++14 example we print the header first, followed by the body:
|
||||
```
|
||||
template<bool isRequest, class Body, class Fields>
|
||||
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;
|
||||
}
|
||||
```
|
||||
|
||||
[http_snippet_16]
|
||||
|
||||
[heading Chunk Decorators]
|
||||
|
||||
@ -173,25 +89,7 @@ after subsequent calls.
|
||||
|
||||
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:
|
||||
```
|
||||
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";
|
||||
}
|
||||
};
|
||||
```
|
||||
[http_snippet_17]
|
||||
|
||||
[endsect]
|
||||
|
@ -143,6 +143,9 @@ public:
|
||||
|
||||
//[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>
|
||||
void echo_op<AsyncStream, Handler>::
|
||||
operator()(beast::error_code ec, std::size_t bytes_transferred)
|
||||
|
@ -24,6 +24,7 @@ unit-test core-tests :
|
||||
core/buffers_adapter.cpp
|
||||
core/clamp.cpp
|
||||
core/consuming_buffers.cpp
|
||||
core/doc_snippets.cpp
|
||||
core/error.cpp
|
||||
core/flat_buffer.cpp
|
||||
core/handler_alloc.cpp
|
||||
@ -44,6 +45,7 @@ unit-test http-tests :
|
||||
http/basic_parser.cpp
|
||||
http/buffer_body.cpp
|
||||
http/doc_http_samples.cpp
|
||||
http/doc_snippets.cpp
|
||||
http/dynamic_body.cpp
|
||||
http/error.cpp
|
||||
http/field.cpp
|
||||
|
@ -8,15 +8,16 @@ add_executable (core-tests
|
||||
${BEAST_INCLUDES}
|
||||
${EXTRAS_INCLUDES}
|
||||
../../extras/beast/unit_test/main.cpp
|
||||
buffer_test.hpp
|
||||
async_result.cpp
|
||||
bind_handler.cpp
|
||||
buffer_cat.cpp
|
||||
buffer_prefix.cpp
|
||||
buffer_test.hpp
|
||||
buffered_read_stream.cpp
|
||||
buffers_adapter.cpp
|
||||
clamp.cpp
|
||||
consuming_buffers.cpp
|
||||
buffered_read_stream.cpp
|
||||
doc_snippets.cpp
|
||||
error.cpp
|
||||
flat_buffer.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
|
||||
buffer_body.cpp
|
||||
doc_http_samples.cpp
|
||||
doc_snippets.cpp
|
||||
dynamic_body.cpp
|
||||
empty_body.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