[/ 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 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 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 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 void send(response 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 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 void send_async(response const& res) { async_write(sock, res, [&](error_code) { if(ec) std::cerr << ec.message() << std::endl; }); } ``` [endsect]