forked from boostorg/beast
160 lines
5.2 KiB
Plaintext
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]
|