A subclass of __basic_parser__ can be invoked directly, without using the provided stream operations. This could be useful for implementing algorithms on objects whose interface does not conform to __Stream__. For example, a [@http://zeromq.org/ *ZeroMQ* socket]. The basic parser interface is interactive; the caller invokes the function [link beast.ref.boost__beast__http__basic_parser.put `basic_parser::put`] repeatedly with buffers until an error occurs or the parsing is done. The function [link beast.ref.boost__beast__http__basic_parser.put_eof `basic_parser::put_eof`] Is used when the caller knows that there will never be more data (for example, if the underlying connection is closed),
A stream in the context of Beast and networking, represents a full-duplex connection between two programs or hosts, where data represented as bytes may be received reliably in the same order they were written. Streams may support any combination of synchronous and/or asynchronous reading and writing.
This library uses the [@http://cplusplus.github.io/networking-ts/draft.pdf Networking Technical Specification], scheduled to become an official part of C++ no sooner than the year 2023. Three implementations exist, with cosmetic differences but otherwise using the same function signatures and type declarations: Boost.Asio, stand-alone Asio, and networking-ts-impl. This table shows how a variable of type `io_context` is declared in each implementation by including the appropriate header and using a suitable namespace alias:
The implementations were originally driven by business needs of cryptocurrency server applications (e.g.[@https://github.com/ripple/rippled rippled]), written in C++. These needs were not met by existing solutions so Beast was written from scratch as a solution. Beast's design philosophy avoids flaws exhibited by other libraries:
Once a websocket session is established, messages can be sent unsolicited by either peer at any time. A message is made up of one or more ['messages frames]. Each frame is prefixed with the size of the payload in bytes, followed by the data. A frame also contains a flag (called 'fin') indicating whether or not it is the last frame of the message. When a message is made up from only one frame, it is possible to know immediately what the size of the message will be. Otherwise, the total size of the message can only be determined once the last frame is received.
For programs which need to modify either the outgoing WebSocket HTTP Upgrade request, the outgoing WebSocket HTTP Upgrade response, or both, the stream supports an optional property called a ['decorator]. This is a function pointer or callable object which is invoked before the implementation sends an HTTP message. The decorator receives a modifiable reference to the message, allowing for modifications. The interface to this system uses:
variablelist [[1. Synchronous Interface][ Beast offers full support for WebSockets using a synchronous interface. It uses the same style of interfaces found in Boost.Asio: versions that throw exceptions, or versions that return the error code in a reference parameter: [table [ [[@https://github.com/vinniefalco/Beast/blob/6c8b4b2f8dde72b01507e4ac7fde4ffea57ebc99/include/beast/websocket/stream.hpp#L774 Beast]] [websocketpp] ][ [``` template<class DynamicBuffer> void read(DynamicBuffer& dynabuf) ```] [ /<not available>/ ] ]]]] [[2. Connection Model][ websocketpp supports multiple transports by utilizing a trait, the `config::transport_type` ([@https://github.com/zaphoyd/websocketpp/blob/378437aecdcb1dfe62096ffd5d944bf1f640ccc3/websocketpp/transport/asio/connection.hpp#L60 asio transport example]) To get an idea of the complexity involved with implementing a transport, compare the asio transport to the [@https://github.com/zaphoyd/websocketpp/blob/378437aecdcb1dfe62096ffd5d944bf1f640ccc3/websocketpp/transport/iostream/connection.hpp#L59 `iostream` transport] (a layer that allows websocket communication over a `std::iostream`). In contrast, Beast abstracts the transport by defining just one [*`NextLayer`] template argument The type requirements for [*`NextLayer`] are already familiar to users as they are documented in Asio: __AsyncReadStream__, __AsyncWriteStream__, __SyncReadStream__, __SyncWriteStream__. The type requirements for instantiating `beast::websocket::stream` versus `websocketpp::connection` with user defined types are vastly reduced (18 functions versus 2). Note that websocketpp connections are passed by `shared_ptr`. Beast does not use `shared_ptr` anywhere in its public interface. A `beast::websocket::stream` is constructible and movable in a manner identical to a `boost::asio::ip::tcp::socket`. Callers can put such objects in a `shared_ptr` if they want to, but there is no requirement to do so. [table [ [[@https://github.com/vinniefalco/Beast/blob/6c8b4b2f8dde72b01507e4ac7fde4ffea57ebc99/include/beast/websocket/stream.hpp Beast]] [[@https://github.com/zaphoyd/websocketpp/blob/378437aecdcb1dfe62096ffd5d944bf1f640ccc3/websocketpp/connection.hpp#L234 websocketpp]] ][ [``` template<class NextLayer> class stream { NextLayer next_layer_; ... } ```] [``` template <typename config> class connection : public config::transport_type::transport_con_type , public config::connection_base { public: typedef lib::shared_ptr<type> ptr; ... } ```] ]]]] [[3. Client and Server Role][ websocketpp provides multi-role support through a hierarchy of different classes. A `beast::websocket::stream` is role-agnostic, it offers member functions to perform both client and server handshakes in the same class. The same types are used for client and server streams. [table [ [Beast] [[@https://github.com/zaphoyd/websocketpp/blob/378437aecdcb1dfe62096ffd5d944bf1f640ccc3/websocketpp/roles/server_endpoint.hpp#L39 websocketpp], [@https://github.com/zaphoyd/websocketpp/blob/378437aecdcb1dfe62096ffd5d944bf1f640ccc3/websocketpp/roles/client_endpoint.hpp#L42 also]] ][ [ /<not needed>/ ] [``` template <typename config> class client : public endpoint<connection<config>,config>; template <typename config> class server : public endpoint<connection<config>,config>; ```] ]]]] [[4. Thread Safety][ websocketpp uses mutexes to protect shared data from concurrent access. In contrast, Beast does not use mutexes anywhere in its implementation. Instead, it follows the Asio pattern. Calls to asynchronous initiation functions use the same method to invoke intermediate handlers as the method used to invoke the final handler, through the associated executor mechanism. The only requirement in Beast is that calls to asynchronous initiation functions are made from the same implicit or explicit strand. For example, if the `io_context` associated with a `beast::websocket::stream` is single threaded, this counts as an implicit strand and no performance costs associated with mutexes are incurred. [table [ [[@https://github.com/vinniefalco/Beast/blob/6c8b4b2f8dde72b01507e4ac7fde4ffea57ebc99/include/beast/websocket/impl/read_frame_op.ipp#L118 Beast]] [[@https://github.com/zaphoyd/websocketpp/blob/378437aecdcb1dfe62096ffd5d944bf1f640ccc3/websocketpp/transport/iostream/connection.hpp#L706 websocketpp]] ][ [``` mutex_type m_read_mutex; ```] ]]]] [[5. Callback Model][ websocketpp requires a one-time call to set the handler for each event in its interface (for example, upon message receipt). The handler is represented by a `std::function` equivalent. Its important to recognize that the websocketpp interface performs type-erasure on this handler. In comparison, Beast handlers are specified in a manner identical to Boost.Asio. They are function objects which can be copied or moved but most importantly they are not type erased. The compiler can see through the type directly to the implementation, permitting optimization. Furthermore, Beast follows the Asio rules for treatment of handlers. It respects any allocation, executors, cancellations associated with the handler through the use of argument dependent lookup overloads of functions such as `bind_allocaotr`. The Beast completion handler is provided at the call site. For each call to an asynchronous initiation function, it is guaranteed that there will be exactly one final call to the handler. This functions exactly the same way as the asynchronous initiation functions found in Boost.Asio, allowing the composition of higher level abstractions. [table [ [[@https://github.com/vinniefalco/Beast/blob/6c8b4b2f8dde72b01507e4ac7fde4ffea57ebc99/include/beast/websocket/stream.hpp#L834 Beast]] [[@https://github.com/zaphoyd/websocketpp/blob/378437aecdcb1dfe62096ffd5d944bf1f640ccc3/websocketpp/connection.hpp#L281 websocketpp], [@https://github.com/zaphoyd/websocketpp/blob/378437aecdcb1dfe62096ffd5d944bf1f640ccc3/websocketpp/connection.hpp#L473 also]] ][ [``` template< class DynamicBuffer,// Supports user defined types class ReadHandler// Handler is NOT type-erased > typename async_completion<// Return value customization ReadHandler,// supports futures and coroutines void(error_code) >::result_type async_read( DynamicBuffer& dynabuf, ReadHandler&& handler); ```] [``` typedef lib::function< void(connection_hdl,message_ptr) > message_handler; void set_message_handler(message_handler h); ```] ]]]] [[6. Extensible Asynchronous Model][ Beast fully supports the [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n3896.pdf Extensible Asynchronous Model] developed by Christopher Kohlhoff, author of Boost.Asio (see Section 8). Beast websocket asynchronous interfaces may be used seamlessly with `std::future` stackful/stackless coroutines, or user defined customizations. [table [ [[@https://github.com/vinniefalco/Beast/blob/6c8b4b2f8dde72b01507e4ac7fde4ffea57ebc99/include/beast/websocket/impl/stream.ipp#L378 Beast]] [websocketpp] ][ [``` beast::async_completion< ReadHandler, void(error_code)> completion{handler}; read_op< DynamicBuffer, decltype(completion.handler)>{ completion.handler, *this, op, buffer}; return completion.result.get();// Customization point ```] [ /<not available>/ ] ]]]] [[7. Message Buffering][ websocketpp defines a message buffer, passed in arguments by `shared_ptr`, and an associated message manager which permits aggregation and reuse of memory. The implementation of `websocketpp::message` uses a `std::string` to hold the payload. If an incoming message is broken up into multiple frames, the string may be reallocated for each continuation frame. The `std::string` always uses the standard allocator, it is not possible to customize the choice of allocator. Beast allows callers to specify the object for receiving the message or frame data, which is of any type meeting the requirements of __DynamicBuffer__ (modeled after `boost::asio::streambuf`). Beast comes with the class __basic_multi_buffer__, an efficient implementation of the __DynamicBuffer__ concept which makes use of multiple allocated octet arrays. If an incoming message is broken up into multiple pieces, no reallocation occurs. Instead, new allocations are appended to the sequence when existing allocations are filled. Beast does not impose any particular memory management model on callers. The __basic_multi_buffer__ provided by beast supports standard allocators through a template argument. Use the __DynamicBuffer__ that comes with beast, customize the allocator if you desire, or provide your own type that meets the requirements. [table [ [[@https://github.com/vinniefalco/Beast/blob/6c8b4b2f8dde72b01507e4ac7fde4ffea57ebc99/include/beast/websocket/stream.hpp#L774 Beast]] [[@https://github.com/zaphoyd/websocketpp/blob/378437aecdcb1dfe62096ffd5d944bf1f640ccc3/websocketpp/message_buffer/message.hpp#L78 websocketpp]] ][ [``` template<class DynamicBuffer> read(DynamicBuffer& dynabuf); ```] [``` template <template<class> class con_msg_manager> class message { public: typedef lib::shared_ptr<message> ptr; ... std::string m_payload; ... }; ```] ]]]] [[8. Sending Messages][ When sending a message, websocketpp requires that the payload is packaged in a `websocketpp::message` object using `std::string` as the storage, or it requires a copy of the caller provided buffer by constructing a new message object. Messages are placed onto an outgoing queue. An asynchronous write operation runs in the background to clear the queue. No user facing handler can be registered to be notified when messages or frames have completed sending. Beast doesn't allocate or make copies of buffers when sending data. The caller's buffers are sent in-place. You can use any object meeting the requirements of __ConstBufferSequence, permitting efficient scatter-gather I/O. The [*ConstBufferSequence] interface allows callers to send data from memory-mapped regions (not possible in websocketpp). Callers can also use the same buffers to send data to multiple streams, for example broadcasting common subscription data to many clients at once. For each call to `async_write` the completion handler is called once when the data finishes sending, in a manner identical to `boost::asio::async_write`. [table [ [[@https://github.com/vinniefalco/Beast/blob/6c8b4b2f8dde72b01507e4ac7fde4ffea57ebc99/include/beast/websocket/stream.hpp#L1048 Beast]] [[@https://github.com/zaphoyd/websocketpp/blob/378437aecdcb1dfe62096ffd5d944bf1f640ccc3/websocketpp/connection.hpp#L672 websocketpp]] ][ [``` template<class ConstBufferSequence> void write(ConstBufferSequence const& buffers); ```] [``` lib::error_code send(std::string const & payload, frame::opcode::value op = frame::opcode::text); ... lib::error_code send(message_ptr msg); ```] ]]]] [[9. Streaming Messages][ websocketpp requires that the entire message fit into memory, and that the size is known ahead of time. Beast allows callers to compose messages in individual frames. This is useful when the size of the data is not known ahead of time or if it is not desired to buffer the entire message in memory at once before sending it. For example, sending periodic output of a database query running on a coroutine. Or sending the contents of a file in pieces, without bringing it all into memory. [table [ [[@https://github.com/vinniefalco/Beast/blob/6c8b4b2f8dde72b01507e4ac7fde4ffea57ebc99/include/beast/websocket/stream.hpp#L1151 Beast]] [websocketpp] ][ [``` template<class ConstBufferSequence> void write_some(bool fin, ConstBufferSequence const& buffers); ```] [ /<not available>/ ] ]]]] [[10. Flow Control][ The websocketpp read implementation continuously reads asynchronously from the network and buffers message data. To prevent unbounded growth and leverage TCP/IP's flow control mechanism, callers can periodically turn this 'read pump' off and back on. In contrast a `beast::websocket::stream` does not independently begin background activity, nor does it buffer messages. It receives data only when there is a call to an asynchronous initiation function (for example `beast::websocket::stream::async_read`) with an associated handler. Applications do not need to implement explicit logic to regulate the flow of data. Instead, they follow the traditional model of issuing a read, receiving a read completion, processing the message, then issuing a new read and repeating the process. [table [ [Beast] [[@https://github.com/zaphoyd/websocketpp/blob/378437aecdcb1dfe62096ffd5d944bf1f640ccc3/websocketpp/connection.hpp#L728 websocketpp]] ][ [ /<implicit>/ ] [``` lib::error_code pause_reading(); lib::error_code resume_reading(); ```] ]]]] [[11. Connection Establishment][ websocketpp offers the `endpoint` class which can handle binding and listening to a port, and spawning connection objects. Beast does not reinvent the wheel here, callers use the interfaces already in `boost::asio` for receiving incoming connections resolving host names, or establishing outgoing connections. After the socket (or `boost::asio::ssl::stream`) is connected, the `beast::websocket::stream` is constructed around it and the WebSocket handshake can be performed. Beast users are free to implement their own "connection manager", but there is no requirement to do so. [table [ [[@http://www.boost.org/doc/html/boost_asio/reference/async_connect.html Beast], [@http://www.boost.org/doc/html/boost_asio/reference/basic_socket_acceptor/async_accept.html also]] [[@https://github.com/zaphoyd/websocketpp/blob/378437aecdcb1dfe62096ffd5d944bf1f640ccc3/websocketpp/transport/asio/endpoint.hpp#L52 websocketpp]] ][ [``` #include <boost/asio.hpp> ```] [``` template <typename config> class endpoint : public config::socket_type; ```] ]]]] [[12. WebSocket Handshaking][ Callers invoke `beast::websocket::accept` to perform the WebSocket handshake, but there is no requirement to use this function. Advanced users can perform the WebSocket handshake themselves. Beast WebSocket provides the tools for composing the request or response, and the Beast HTTP interface provides the container and algorithms for sending and receiving HTTP/1 messages including the necessary HTTP Upgrade request for establishing the WebSocket session. Beast allows the caller to pass the incoming HTTP Upgrade request for the cases where the caller has already received an HTTP message. This flexibility permits novel and robust implementations. For example, a listening socket that can handshake in multiple protocols on the same port. Sometimes callers want to read some bytes on the socket before reading the WebSocket HTTP Upgrade request. Beast allows these already-received bytes to be supplied to an overload of the accepting function to permit sophisticated features. For example, a listening socket that can accept both regular WebSocket and Secure WebSocket (SSL) connections. [table [ [[@https://github.com/vinniefalco/Beast/blob/6c8b4b2f8dde72b01507e4ac7fde4ffea57ebc99/include/beast/websocket/stream.hpp#L501 Beast], [@https://github.com/vinniefalco/Beast/blob/6c8b4b2f8dde72b01507e4ac7fde4ffea57ebc99/include/beast/websocket/stream.hpp#L401 also]] [websocketpp] ][ [``` template<class ConstBufferSequence> void accept(ConstBufferSequence const& buffers); template<class Allocator> void accept(http::header<true, http::basic_fields<Allocator>> const& req); ```] [ /<not available>/ ] ]]]]
To facilitate working with instances of the __ConstBufferSequence__ and __MutableBufferSequence__ concepts introduced in __Asio__, Beast treats those sequences as a special type of range. The following algorithms and wrappers are provided which transform these ranges efficiently using lazy evaluation. No memory allocations are used in the transformations; instead, they create lightweight iterators over the existing, unmodified memory buffers. Control of buffers is retained by the caller; ownership is not transferred.
An instance of [*RatePolicy] is associated with a [link beast.ref.boost__beast__basic_stream `basic_stream`], and controls the rate at which bytes may be independently sent and received. This may be used to achieve fine-grained bandwidth management and flow control.
Often when implementing network algorithms such as servers, it is necessary to interact with files on the system. Beast defines the __File__ concept and several models to facilitate cross-platform interaction with the underlying filesystem:
The WebSocket protocol requirements described in rfc6455 section 7.1.1 outline an operation described as [@https://tools.ietf.org/html/rfc6455#section-7.1.1 ['Close the WebSocket Connection]]. This operation cleanly discards bytes remaining at receiving endpoints and also closes the underlying TCP/IP connection. Orderly shutdowns are always preferred; for TLS or SSL streams, a protocol-level shutdown is desired. This presents a small issue for the [link beast.ref.boost__beast__websocket__stream `stream`] implementation: the stream's `NextLayer` template type requires only __SyncStream__ or __AsyncStream__, but those concepts do not support the operations to shut down the connection.
User-defined types are possible for the message body, where the type meets the __Body__ requirements. This simplified class declaration shows the customization points available to user-defined body types: ``` /// Defines a Body type struct body {
To set realistic expectations and prevent a litany of duplicate review statements, these notes address the most common questions and comments about Beast and other HTTP libraries that have gone through formal review.
While the parsers included in the library will handle a broad number of use-cases, the __basic_parser__ interface can be subclassed to implement custom strategies for storing parsed results: the basic parser processes input buffers into elements according to the HTTP/1 protocol specification, while the derived class decides what to do with those elements. Custom parsers will work with all of the HTTP stream read algorithms, as those algorithms use only the basic parser interface. Some use cases for implementing custom parsers are:
A [*BodyReader] provides an online algorithm to transfer a series of zero or more buffers containing parsed body octets into a message container. The __parser__ creates an instance of this type when needed, and calls into it zero or more times to transfer buffers. The interface of [*BodyReader] is intended to allow the conversion of buffers into these scenarios for representation:
While [link beast.ref.boost__beast__basic_stream `basic_stream`] and [link beast.ref.boost__beast__basic_stream `tcp_stream`] support timeouts on general logical operations, the websocket stream has a more sophisticated timeout mechanism built-in which may be enabled and configured. The timeout features of the TCP or basic stream should not be used when working with a websocket stream. The interface to these timeout features is shown in this table.
Keyboard shortcuts
Shortcut
Action
?
Open available keyboard shortcuts.
Alt + Home
Navigate to the first translation in the current search.
Alt + End
Navigate to the last translation in the current search.
Alt + PageUp or
Ctrl + ↑ or
Alt + ↑ or
Cmd + ↑ or
Navigate to the previous translation in the current search.
Alt + PageDown or
Ctrl + ↓ or
Alt + ↓ or
Cmd + ↓ or
Navigate to the next translation in the current search.
Ctrl + Enter or
Cmd + Enter
Submit current form; this works the same as pressing Save and continue while editing translation.
Ctrl + Shift + Enter or
Cmd + Shift +Enter
Unmark translation as Needing edit and submit it.
Alt + Enter or
Option + Enter
Submit the string as a suggestion; this works the same as pressing Suggest while editing translation.
Ctrl + E or
Cmd + E
Focus on translation editor.
Ctrl + U or
Cmd + U
Focus on comment editor.
Ctrl + M or
Cmd + M
Shows Automatic suggestions tab.
Ctrl + 1 to
Ctrl + 9 or
Cmd + 1 to
Cmd + 9
Copies placeable of a given number from source string.
Ctrl + M followed by
1 to 9 or
Cmd + M followed by
1 to
9
Copy the machine translation of a given number to current translation.
Ctrl + I followed by
1 to
9 or
Cmd + I followed by
1 to
9