Files
boost_beast/doc/4_03_streams.qbk
T
2017-07-20 08:12:18 -07:00

160 lines
5.2 KiB
Plaintext

[/
Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
Distributed under the Boost Software License, Version 1.0. (See accompanying
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
]
[section:streams Message Stream Operations]
Beast provides synchronous and asynchronous algorithms to serialize and
parse HTTP/1 wire format messages on streams. These functions form the
basic interface which works on the entire header or message at once,
requiring no separately managed state objects:
[table Basic Interface
[[Name][Description]]
[[
[link beast.ref.http__read.overload3 [*read]]
][
Parse a __message__ from a __SyncReadStream__.
]]
[[
[link beast.ref.http__async_read.overload2 [*async_read]]
][
Parse a __message__ from an __AsyncReadStream__.
]]
[[
[link beast.ref.http__write.overload1 [*write]]
][
Serialize a __message__ to a __SyncWriteStream__.
]]
[[
[link beast.ref.http__async_write [*async_write]]
][
Serialize a __message__ to an __AsyncWriteStream__.
]]
]
All synchronous stream operations come in two varieties. One which throws
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
messages from a stream may read past the end of a message for efficiency.
To hold this surplus data, all stream read operations use a passed-in
__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);
```
In this example we used the __flat_buffer__. The parser in Beast is
optimized for structured HTTP data located in a single contiguous memory
buffer ("flat buffer"). Any dynamic buffer will work with reads. However,
when not using a flat buffer the implementation may perform an additional
memory allocation to restructure the input into a single buffer.
[tip
User-defined implementations of __DynamicBuffer__ may avoid additional
parser memory allocation, if those implementations guarantee that
returned buffer sequences will always have length one.
]
Messages may also be read asynchronously. When performing asynchronous
stream read operations, the buffer and message variables must remain
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;
});
```
If a read stream algorithm cannot complete its operation without exceeding
the maximum specified size of the dynamic buffer provided, the error
[link beast.ref.http__error `buffer_overflow`]
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;
```
[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
the connection. When sending such a response, Beast will return the
error `boost::asio::error::eof` 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.fields.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);
}
```
An asynchronous version is also available:
```
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]