Beast.WebSocket:

Beast.WebSocket provides developers with a robust WebSocket
implementation built on Boost.Asio with a consistent asynchronous
model using a modern C++ approach.
This commit is contained in:
Vinnie Falco
2016-02-25 16:17:19 -05:00
parent 2e302a43aa
commit 54f6f0ceba
80 changed files with 13296 additions and 13 deletions

4
doc/.gitignore vendored Normal file
View File

@@ -0,0 +1,4 @@
html
temp
reference.qbk
out.txt

83
doc/Jamfile Normal file
View File

@@ -0,0 +1,83 @@
#
# Copyright (c) 2013-2016 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)
#
import os ;
local broot = [ os.environ BOOST_ROOT ] ;
project beast/doc ;
using boostbook ;
using quickbook ;
using doxygen ;
xml beast_boostbook : beast.qbk ;
path-constant out : . ;
install stylesheets
:
$(broot)/doc/src/boostbook.css
:
<location>$(out)/html
;
explicit stylesheets ;
install images
:
[ glob $(broot)/doc/src/images/*.png ]
images/beast.png
images/body.png
images/message.png
:
<location>$(out)/html/images
;
explicit images ;
install callouts
:
[ glob $(broot)/doc/src/images/callouts/*.png ]
:
<location>$(out)/html/images/callouts
;
explicit callout ;
boostbook doc
:
beast_boostbook
:
<xsl:param>chapter.autolabel=0
<xsl:param>boost.image.src=images/beast.png
<xsl:param>boost.image.alt="Beast Logo"
<xsl:param>boost.image.w=1007
<xsl:param>boost.image.h=107
<xsl:param>boost.root=$(broot)
<xsl:param>chapter.autolabel=0
<xsl:param>chunk.first.sections=1 # Chunk the first top-level section?
<xsl:param>chunk.section.depth=8 # Depth to which sections should be chunked
<xsl:param>generate.section.toc.level=1 # Control depth of TOC generation in sections
<xsl:param>toc.max.depth=2 # How many levels should be created for each TOC?
<xsl:param>toc.section.depth=2 # How deep should recursive sections appear in the TOC?
:
<location>temp
<dependency>stylesheets
<dependency>images
;
#explicit doc ;
# <xsl:param>nav.layout=none
# <format>html:<xsl:param>location=../bin/doc/html
# <xsl:param>generate.toc="chapter nop section nop"
# <xsl:param>root.filename=index
# <xsl:param>output-root="../bin/html"
#[include reference.qbk]
#[xinclude index.xml]

363
doc/beast.dox Normal file
View File

@@ -0,0 +1,363 @@
#---------------------------------------------------------------------------
# Project related configuration options
#---------------------------------------------------------------------------
DOXYFILE_ENCODING = UTF-8
PROJECT_NAME = "Beast"
PROJECT_NUMBER =
PROJECT_BRIEF = C++ Library
PROJECT_LOGO = images/beast.png
OUTPUT_DIRECTORY =
CREATE_SUBDIRS = NO
ALLOW_UNICODE_NAMES = NO
OUTPUT_LANGUAGE = English
BRIEF_MEMBER_DESC = YES
REPEAT_BRIEF = YES
ABBREVIATE_BRIEF =
ALWAYS_DETAILED_SEC = NO
INLINE_INHERITED_MEMB = YES
FULL_PATH_NAMES = NO
STRIP_FROM_PATH =
STRIP_FROM_INC_PATH =
SHORT_NAMES = NO
JAVADOC_AUTOBRIEF = YES
QT_AUTOBRIEF = NO
MULTILINE_CPP_IS_BRIEF = NO
INHERIT_DOCS = YES
SEPARATE_MEMBER_PAGES = NO
TAB_SIZE = 4
ALIASES =
TCL_SUBST =
OPTIMIZE_OUTPUT_FOR_C = NO
OPTIMIZE_OUTPUT_JAVA = NO
OPTIMIZE_FOR_FORTRAN = NO
OPTIMIZE_OUTPUT_VHDL = NO
EXTENSION_MAPPING =
MARKDOWN_SUPPORT = YES
AUTOLINK_SUPPORT = YES
BUILTIN_STL_SUPPORT = NO
CPP_CLI_SUPPORT = NO
SIP_SUPPORT = NO
IDL_PROPERTY_SUPPORT = YES
DISTRIBUTE_GROUP_DOC = NO
GROUP_NESTED_COMPOUNDS = NO
SUBGROUPING = YES
INLINE_GROUPED_CLASSES = NO
INLINE_SIMPLE_STRUCTS = NO
TYPEDEF_HIDES_STRUCT = NO
LOOKUP_CACHE_SIZE = 0
#---------------------------------------------------------------------------
# Build related configuration options
#---------------------------------------------------------------------------
EXTRACT_ALL = YES
EXTRACT_PRIVATE = YES
EXTRACT_PACKAGE = YES
EXTRACT_STATIC = YES
EXTRACT_LOCAL_CLASSES = NO
EXTRACT_LOCAL_METHODS = NO
EXTRACT_ANON_NSPACES = NO
HIDE_UNDOC_MEMBERS = NO
HIDE_UNDOC_CLASSES = YES
HIDE_FRIEND_COMPOUNDS = NO
HIDE_IN_BODY_DOCS = NO
INTERNAL_DOCS = NO
CASE_SENSE_NAMES = YES
HIDE_SCOPE_NAMES = NO
HIDE_COMPOUND_REFERENCE= NO
SHOW_INCLUDE_FILES = NO
SHOW_GROUPED_MEMB_INC = NO
FORCE_LOCAL_INCLUDES = NO
INLINE_INFO = NO
SORT_MEMBER_DOCS = NO
SORT_BRIEF_DOCS = NO
SORT_MEMBERS_CTORS_1ST = YES
SORT_GROUP_NAMES = NO
SORT_BY_SCOPE_NAME = NO
STRICT_PROTO_MATCHING = NO
GENERATE_TODOLIST = NO
GENERATE_TESTLIST = NO
GENERATE_BUGLIST = NO
GENERATE_DEPRECATEDLIST= NO
ENABLED_SECTIONS =
MAX_INITIALIZER_LINES = 30
SHOW_USED_FILES = NO
SHOW_FILES = NO
SHOW_NAMESPACES = NO
FILE_VERSION_FILTER =
LAYOUT_FILE =
CITE_BIB_FILES =
#---------------------------------------------------------------------------
# Configuration options related to warning and progress messages
#---------------------------------------------------------------------------
QUIET = NO
WARNINGS = YES
WARN_IF_UNDOCUMENTED = YES
WARN_IF_DOC_ERROR = YES
WARN_NO_PARAMDOC = NO
WARN_AS_ERROR = NO
WARN_FORMAT = "$file:$line: $text"
WARN_LOGFILE =
#---------------------------------------------------------------------------
# Configuration options related to the input files
#---------------------------------------------------------------------------
INPUT = \
../beast/asio/append_buffers.h \
../beast/asio/async_completion.h \
../beast/asio/basic_streambuf.h \
../beast/asio/bind_handler.h \
../beast/asio/buffers_adapter.h \
../beast/asio/consuming_buffers.h \
../beast/asio/handler_alloc.h \
../beast/asio/prepare_buffers.h \
../beast/asio/static_streambuf.h \
../beast/asio/streambuf.h \
../beast/asio/streambuf_readstream.h \
../beast/asio/type_check.h \
../beast/http/basic_headers.h \
../beast/http/basic_parser.h \
../beast/http/chunk_encode.h \
../beast/http/empty_body.h \
../beast/http/error.h \
../beast/http/message.h \
../beast/http/parser.h \
../beast/http/read.h \
../beast/http/resume_context.h \
../beast/http/stream.h \
../beast/http/streambuf_body.h \
../beast/http/string_body.h \
../beast/http/type_check.h \
../beast/http/write.h \
../beast/wsproto/error.h \
../beast/wsproto/option.h \
../beast/wsproto/rfc6455.h \
../beast/wsproto/socket.h \
../beast/wsproto/static_string.h \
../beast/wsproto/teardown.h \
INPUT_ENCODING = UTF-8
FILE_PATTERNS =
RECURSIVE = NO
EXCLUDE = ../beast/http/URL.h
EXCLUDE_SYMLINKS = NO
EXCLUDE_PATTERNS =
EXCLUDE_SYMBOLS =
EXAMPLE_PATH =
EXAMPLE_PATTERNS =
EXAMPLE_RECURSIVE = NO
IMAGE_PATH =
INPUT_FILTER =
FILTER_PATTERNS =
FILTER_SOURCE_FILES = NO
FILTER_SOURCE_PATTERNS =
USE_MDFILE_AS_MAINPAGE =
#---------------------------------------------------------------------------
# Configuration options related to source browsing
#---------------------------------------------------------------------------
SOURCE_BROWSER = NO
INLINE_SOURCES = NO
STRIP_CODE_COMMENTS = YES
REFERENCED_BY_RELATION = NO
REFERENCES_RELATION = NO
REFERENCES_LINK_SOURCE = YES
SOURCE_TOOLTIPS = YES
USE_HTAGS = NO
VERBATIM_HEADERS = YES
CLANG_ASSISTED_PARSING = NO
CLANG_OPTIONS =
#---------------------------------------------------------------------------
# Configuration options related to the alphabetical class index
#---------------------------------------------------------------------------
ALPHABETICAL_INDEX = YES
COLS_IN_ALPHA_INDEX = 5
IGNORE_PREFIX =
#---------------------------------------------------------------------------
# Configuration options related to the HTML output
#---------------------------------------------------------------------------
GENERATE_HTML = NO
HTML_OUTPUT = dhtm
HTML_FILE_EXTENSION = .html
HTML_HEADER =
HTML_FOOTER =
HTML_STYLESHEET =
HTML_EXTRA_STYLESHEET =
HTML_EXTRA_FILES =
HTML_COLORSTYLE_HUE = 220
HTML_COLORSTYLE_SAT = 100
HTML_COLORSTYLE_GAMMA = 80
HTML_TIMESTAMP = NO
HTML_DYNAMIC_SECTIONS = NO
HTML_INDEX_NUM_ENTRIES = 100
GENERATE_DOCSET = NO
DOCSET_FEEDNAME = "Doxygen generated docs"
DOCSET_BUNDLE_ID = org.doxygen.Project
DOCSET_PUBLISHER_ID = org.doxygen.Publisher
DOCSET_PUBLISHER_NAME = Publisher
GENERATE_HTMLHELP = NO
CHM_FILE =
HHC_LOCATION =
GENERATE_CHI = NO
CHM_INDEX_ENCODING =
BINARY_TOC = NO
TOC_EXPAND = NO
GENERATE_QHP = NO
QCH_FILE =
QHP_NAMESPACE = org.doxygen.Project
QHP_VIRTUAL_FOLDER = doc
QHP_CUST_FILTER_NAME =
QHP_CUST_FILTER_ATTRS =
QHP_SECT_FILTER_ATTRS =
QHG_LOCATION =
GENERATE_ECLIPSEHELP = NO
ECLIPSE_DOC_ID = org.doxygen.Project
DISABLE_INDEX = NO
GENERATE_TREEVIEW = NO
ENUM_VALUES_PER_LINE = 4
TREEVIEW_WIDTH = 250
EXT_LINKS_IN_WINDOW = NO
FORMULA_FONTSIZE = 10
FORMULA_TRANSPARENT = YES
USE_MATHJAX = NO
MATHJAX_FORMAT = HTML-CSS
MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest
MATHJAX_EXTENSIONS =
MATHJAX_CODEFILE =
SEARCHENGINE = YES
SERVER_BASED_SEARCH = NO
EXTERNAL_SEARCH = NO
SEARCHENGINE_URL =
SEARCHDATA_FILE = searchdata.xml
EXTERNAL_SEARCH_ID =
EXTRA_SEARCH_MAPPINGS =
#---------------------------------------------------------------------------
# Configuration options related to the LaTeX output
#---------------------------------------------------------------------------
GENERATE_LATEX = NO
LATEX_OUTPUT = latex
LATEX_CMD_NAME = latex
MAKEINDEX_CMD_NAME = makeindex
COMPACT_LATEX = NO
PAPER_TYPE = a4
EXTRA_PACKAGES =
LATEX_HEADER =
LATEX_FOOTER =
LATEX_EXTRA_STYLESHEET =
LATEX_EXTRA_FILES =
PDF_HYPERLINKS = YES
USE_PDFLATEX = YES
LATEX_BATCHMODE = NO
LATEX_HIDE_INDICES = NO
LATEX_SOURCE_CODE = NO
LATEX_BIB_STYLE = plain
LATEX_TIMESTAMP = NO
#---------------------------------------------------------------------------
# Configuration options related to the RTF output
#---------------------------------------------------------------------------
GENERATE_RTF = NO
RTF_OUTPUT = rtf
COMPACT_RTF = NO
RTF_HYPERLINKS = NO
RTF_STYLESHEET_FILE =
RTF_EXTENSIONS_FILE =
RTF_SOURCE_CODE = NO
#---------------------------------------------------------------------------
# Configuration options related to the man page output
#---------------------------------------------------------------------------
GENERATE_MAN = NO
MAN_OUTPUT = man
MAN_EXTENSION = .3
MAN_SUBDIR =
MAN_LINKS = NO
#---------------------------------------------------------------------------
# Configuration options related to the XML output
#---------------------------------------------------------------------------
GENERATE_XML = YES
XML_OUTPUT = ../bin/doc/xml
XML_PROGRAMLISTING = YES
#---------------------------------------------------------------------------
# Configuration options related to the DOCBOOK output
#---------------------------------------------------------------------------
GENERATE_DOCBOOK = NO
DOCBOOK_OUTPUT = docbook
DOCBOOK_PROGRAMLISTING = NO
#---------------------------------------------------------------------------
# Configuration options for the AutoGen Definitions output
#---------------------------------------------------------------------------
GENERATE_AUTOGEN_DEF = NO
GENERATE_PERLMOD = NO
PERLMOD_LATEX = NO
PERLMOD_PRETTY = YES
PERLMOD_MAKEVAR_PREFIX =
#---------------------------------------------------------------------------
# Configuration options related to the preprocessor
#---------------------------------------------------------------------------
ENABLE_PREPROCESSING = YES
MACRO_EXPANSION = YES
EXPAND_ONLY_PREDEF = YES
SEARCH_INCLUDES = YES
INCLUDE_PATH = ../
INCLUDE_FILE_PATTERNS =
PREDEFINED = DOXYGEN \
GENERATING_DOCS
EXPAND_AS_DEFINED =
SKIP_FUNCTION_MACROS = YES
#---------------------------------------------------------------------------
# Configuration options related to external references
#---------------------------------------------------------------------------
TAGFILES =
GENERATE_TAGFILE =
ALLEXTERNALS = NO
EXTERNAL_GROUPS = YES
EXTERNAL_PAGES = YES
PERL_PATH = /usr/bin/perl
#---------------------------------------------------------------------------
# Configuration options related to the dot tool
#---------------------------------------------------------------------------
CLASS_DIAGRAMS = NO
MSCGEN_PATH =
DIA_PATH =
HIDE_UNDOC_RELATIONS = YES
HAVE_DOT = NO
DOT_NUM_THREADS = 0
DOT_FONTNAME = Helvetica
DOT_FONTSIZE = 10
DOT_FONTPATH =
CLASS_GRAPH = YES
COLLABORATION_GRAPH = YES
GROUP_GRAPHS = YES
UML_LOOK = NO
UML_LIMIT_NUM_FIELDS = 10
TEMPLATE_RELATIONS = NO
INCLUDE_GRAPH = YES
INCLUDED_BY_GRAPH = YES
CALL_GRAPH = NO
CALLER_GRAPH = NO
GRAPHICAL_HIERARCHY = YES
DIRECTORY_GRAPH = YES
DOT_IMAGE_FORMAT = png
INTERACTIVE_SVG = NO
DOT_PATH =
DOTFILE_DIRS =
MSCFILE_DIRS =
DIAFILE_DIRS =
PLANTUML_JAR_PATH =
PLANTUML_INCLUDE_PATH =
DOT_GRAPH_MAX_NODES = 50
MAX_DOT_GRAPH_DEPTH = 0
DOT_TRANSPARENT = NO
DOT_MULTI_TARGETS = NO
GENERATE_LEGEND = YES
DOT_CLEANUP = YES

177
doc/beast.qbk Normal file
View File

@@ -0,0 +1,177 @@
[/
Copyright (c) 2013-2016 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)
]
[library Beast
[quickbook 1.6]
[copyright 2013 - 2016 Vinnie Falco]
[purpose C++ Library]
[license
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])
]
[authors [Falco, Vinnie]]
[category template]
[category generic]
]
[template mdash[] '''&mdash; ''']
[template indexterm1[term1] '''<indexterm><primary>'''[term1]'''</primary></indexterm>''']
[template indexterm2[term1 term2] '''<indexterm><primary>'''[term1]'''</primary><secondary>'''[term2]'''</secondary></indexterm>''']
[template ticket[number]'''<ulink url="https://svn.boost.org/trac/boost/ticket/'''[number]'''">'''#[number]'''</ulink>''']
[def __POSIX__ /POSIX/]
[def __Windows__ /Windows/]
[def __accept__ [@http://www.opengroup.org/onlinepubs/000095399/functions/accept.html `accept()`]]
[def __connect__ [@http://www.opengroup.org/onlinepubs/000095399/functions/connect.html `connect()`]]
[def __getpeername__ [@http://www.opengroup.org/onlinepubs/000095399/functions/getpeername.html `getpeername()`]]
[def __getsockname__ [@http://www.opengroup.org/onlinepubs/000095399/functions/getsockname.html `getsockname()`]]
[def __getsockopt__ [@http://www.opengroup.org/onlinepubs/000095399/functions/getsockopt.html `getsockopt()`]]
[def __ioctl__ [@http://www.opengroup.org/onlinepubs/000095399/functions/ioctl.html `ioctl()`]]
[def __recvfrom__ [@http://www.opengroup.org/onlinepubs/000095399/functions/recvfrom.html `recvfrom()`]]
[def __sendto__ [@http://www.opengroup.org/onlinepubs/000095399/functions/sendto.html `sendto()`]]
[def __setsockopt__ [@http://www.opengroup.org/onlinepubs/000095399/functions/setsockopt.html `setsockopt()`]]
[def __socket__ [@http://www.opengroup.org/onlinepubs/000095399/functions/socket.html `socket()`]]
[section:intro Introduction]
Beast is a cross-platform C++ library built on Boost, containing two modules
implementing widely used network protocols. Beast.HTTP offers a universal
model for describing, sending, and receiving HTTP messages while Beast.WSProto
provides a complete implementation of the WebSocket protocol. Their design
achieves these goals:
* [*Symmetry.] Interfaces are role-agnostic; the same interfaces can be
used to build clients, servers, or both.
* [*Ease of Use.] HTTP messages are modeled using simple, readily
accessible objects. Functions and classes used to send and receive HTTP
or WebSocket messages are designed to resemble Boost.Asio as closely as
possible. Users familiar with Boost.Asio will be immediately comfortable
using this library.
* [*Flexibility.] Interfaces do not mandate specific implementation
strategies; important decisions such as buffer or thread management are
left to users of the library.
* [*Performance.] The implementation performs competitively, making it a
realistic choice for building a high performance network server.
* [*Scalability.] Development of network applications that scale to thousands
of concurrent connections is possible with the implementation.
* [*Basis for further abstraction.] The interfaces facilitate the
development of other libraries that provide higher levels of abstraction.
[section:requirements Requirements]
Beast requires:
* [*C++11.] A minimum of C++11 is needed.
* [*Boost.] Beast is built on Boost, especially Boost.Asio.
* [*OpenSSL.] If using TLS/Secure sockets (optional).
[note Tested compilers: msvc-14+, gcc 5+, clang 3.6+]
Most of the library is header-only; however, the HTTP parser used is written
in C. To link an application that uses Beast, it is necessary to add a single
.cpp file from beast into your project's build script.
[endsect]
[section:example Examples]
These usage examples are intended to quickly impress upon readers the
flavor of the library.
[note
All examples and identifiers mentioned in this document are written as
if the following statements are in effect:
```
#include <beast/http.h>
#include <beast/wsproto.h>
using namespace beast;
using namespace beast::http;
using namespace boost::asio;
using namespace boost::asio::ip;
```
]
Use HTTP to request the root page from a website and receive the response:
```
std::string const host = "boost.org";
io_service ios;
tcp::resolver r(ios);
tcp::socket sock(ios);
connect(sock, r.resolve(tcp::resolver::query{host, "http"}));
request<empty_body> req(method_t::http_get, "/", 11);
req.headers.replace("Host", host + ":" + std::to_string(sock.remote_endpoint().port()));
req.headers.replace("User-Agent", "Beast");
write(sock, prepare(req, connection(close)));
parsed_response<streambuf_body> resp;
read(sock, resp);
...
```
Establish a WebSocket connection, send a message and receive the reply:
```
std::string const host = "boost.org";
io_service ios;
tcp::resolver r(ios);
tcp::socket sock(ios);
connect(sock, r.resolve(tcp::resolver::query{host, "ws"}));
wsproto::socket<tcp::socket&> ws(sock);
ws.handshake();
ws.write(ws, buffer("Hello, world!"));
streambuf sb;
wsproto::opcode op;
ws.read(ws, op, sb);
ws.close(); // WebSocket protocol close
```
[endsect]
[section:credits Credits]
Beast would not be possible without the considerable time and patience
contributed by David Schwartz, Edward Hennis, Howard Hinnant, Miguel Portilla,
Nikolaos Bougalis, Scott Determan, Scott Schurr, and Ripple Labs for
supporting its development. Thanks also to Christopher Kohloff, whose Asio
C++ library is the inspiration behind which much of the design and
documentation is based.
[endsect]
[endsect]
[include http.qbk]
[include wsproto.qbk]
[include types.qbk]
[include design.qbk]
[section:quickref Quick Reference]
[xinclude quickref.xml]
[endsect]
[include reference.qbk]
[section:idx Index]
[xinclude index.xml]
[endsect]

439
doc/boostbook.dtd Normal file
View File

@@ -0,0 +1,439 @@
<!--
BoostBook DTD - development version
For further information, see: http://www.crystalclearsoftware.com/cgi-bin/boost_wiki/wiki.pl?Boost_Documentation_Format
Copyright (c) 2002 by Peter Simons <simons@cryp.to>
Copyright (c) 2003-2004 by Douglas Gregor <doug.gregor -at- gmail.com>
Copyright (c) 2007 by Frank Mori Hess <fmhess@users.sourceforge.net>
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)
The latest stable DTD module is identified by the PUBLIC and SYSTEM identifiers:
PUBLIC "-//Boost//DTD BoostBook XML V1.1//EN"
SYSTEM "http://www.boost.org/tools/boostbook/dtd/1.1/boostbook.dtd"
$Revision$
$Date$
-->
<!--========== Define XInclude features. ==========-->
<!-- This is not really integrated into the DTD yet. Needs more
research. -->
<!--
<!ELEMENT xi:include (xi:fallback)?>
<!ATTLIST xi:include
xmlns:xi CDATA #FIXED "http://www.w3.org/2001/XInclude"
href CDATA #REQUIRED
parse (xml|text) "xml"
encoding CDATA #IMPLIED>
<!ELEMENT xi:fallback ANY>
<!ATTLIST xi:fallback
xmlns:xi CDATA #FIXED "http://www.w3.org/2001/XInclude">
-->
<!ENTITY % local.common.attrib "last-revision CDATA #IMPLIED">
<!--========== Define the BoostBook extensions ==========-->
<!ENTITY % boost.common.attrib "%local.common.attrib;
id CDATA #IMPLIED">
<!ENTITY % boost.namespace.mix
"class|class-specialization|struct|struct-specialization|
union|union-specialization|typedef|enum|
free-function-group|function|overloaded-function|
namespace">
<!ENTITY % boost.template.mix
"template-type-parameter|template-nontype-parameter|template-varargs">
<!ENTITY % boost.class.members
"static-constant|typedef|enum|
copy-assignment|constructor|destructor|method-group|
method|overloaded-method|data-member|class|class-specialization|struct|
struct-specialization|union|union-specialization">
<!ENTITY % boost.class.mix
"%boost.class.members;|free-function-group|function|overloaded-function">
<!ENTITY % boost.class.content
"template?, inherit*, purpose?, description?,
(%boost.class.mix;|access)*">
<!ENTITY % boost.class-specialization.content
"template?, specialization?, inherit?, purpose?, description?,
(%boost.class.mix;|access)*">
<!ENTITY % boost.function.semantics
"purpose?, description?, requires?, effects?, postconditions?,
returns?, throws?, complexity?, notes?, rationale?">
<!ENTITY % library.content
"libraryinfo, (title, ((section|library-reference|testsuite))+)?">
<!ELEMENT library (%library.content;)>
<!ATTLIST library
name CDATA #REQUIRED
dirname CDATA #REQUIRED
html-only CDATA #IMPLIED
url CDATA #IMPLIED
%boost.common.attrib;>
<!ELEMENT boostbook (title, (chapter|library)*)>
<!ATTLIST boostbook %boost.common.attrib;>
<!ELEMENT libraryinfo (author+, copyright*, legalnotice*, librarypurpose, librarycategory*)>
<!ATTLIST libraryinfo %boost.common.attrib;>
<!ELEMENT librarypurpose (#PCDATA|code|ulink|functionname|methodname|classname|macroname|headername|enumname|globalname)*>
<!ATTLIST librarypurpose %boost.common.attrib;>
<!ELEMENT librarycategory (#PCDATA)>
<!ATTLIST librarycategory
name CDATA #REQUIRED
%boost.common.attrib;>
<!ELEMENT libraryname (#PCDATA)>
<!ATTLIST libraryname %boost.common.attrib;>
<!ELEMENT library-reference ANY>
<!ATTLIST library-reference
%boost.common.attrib;>
<!ELEMENT librarylist EMPTY>
<!ATTLIST librarylist %boost.common.attrib;>
<!ELEMENT librarycategorylist (librarycategorydef)*>
<!ATTLIST librarycategorylist %boost.common.attrib;>
<!ELEMENT librarycategorydef (#PCDATA)>
<!ATTLIST librarycategorydef
name CDATA #REQUIRED
%boost.common.attrib;>
<!ELEMENT header ANY>
<!ATTLIST header
name CDATA #REQUIRED
%boost.common.attrib;>
<!ELEMENT namespace (%boost.namespace.mix;)*>
<!ATTLIST namespace
name CDATA #REQUIRED
%boost.common.attrib;>
<!ELEMENT class (%boost.class.content;)>
<!ATTLIST class
name CDATA #REQUIRED
%boost.common.attrib;>
<!ELEMENT struct (%boost.class.content;)>
<!ATTLIST struct
name CDATA #REQUIRED
%boost.common.attrib;>
<!ELEMENT union (%boost.class.content;)>
<!ATTLIST union
name CDATA #REQUIRED
%boost.common.attrib;>
<!ELEMENT class-specialization (%boost.class-specialization.content;)>
<!ATTLIST class-specialization
name CDATA #REQUIRED
%boost.common.attrib;>
<!ELEMENT struct-specialization (%boost.class-specialization.content;)>
<!ATTLIST struct-specialization
name CDATA #REQUIRED
%boost.common.attrib;>
<!ELEMENT union-specialization (%boost.class-specialization.content;)>
<!ATTLIST union-specialization
name CDATA #REQUIRED
%boost.common.attrib;>
<!ELEMENT access (%boost.class.members;)+>
<!ATTLIST access
name CDATA #REQUIRED
%boost.common.attrib;>
<!--========= C++ Templates =========-->
<!ELEMENT template (%boost.template.mix;)*>
<!ATTLIST template %boost.common.attrib;>
<!ELEMENT template-type-parameter (default?, purpose?)>
<!ATTLIST template-type-parameter
name CDATA #REQUIRED
pack CDATA #IMPLIED
%boost.common.attrib;>
<!ELEMENT template-nontype-parameter (type, default?, purpose?)>
<!ATTLIST template-nontype-parameter
name CDATA #REQUIRED
pack CDATA #IMPLIED
%boost.common.attrib;>
<!ELEMENT template-varargs EMPTY>
<!ATTLIST template-varargs %boost.common.attrib;>
<!ELEMENT specialization (template-arg)*>
<!ATTLIST specialization %boost.common.attrib;>
<!ELEMENT template-arg ANY>
<!ATTLIST template-arg
pack CDATA #IMPLIED
%boost.common.attrib;>
<!ELEMENT default ANY>
<!ATTLIST default %boost.common.attrib;>
<!ELEMENT inherit (type, purpose?)>
<!ATTLIST inherit
access CDATA #IMPLIED
pack CDATA #IMPLIED
%boost.common.attrib;>
<!ELEMENT purpose ANY>
<!ATTLIST purpose %boost.common.attrib;>
<!ELEMENT description ANY>
<!ATTLIST description %boost.common.attrib;>
<!ELEMENT type ANY>
<!ATTLIST type %boost.common.attrib;>
<!ELEMENT typedef (type, purpose?, description?)>
<!ATTLIST typedef
name CDATA #REQUIRED
%boost.common.attrib;>
<!ELEMENT enum (enumvalue*, purpose?, description?)>
<!ATTLIST enum
name CDATA #REQUIRED
%boost.common.attrib;>
<!ELEMENT enumvalue (default?, purpose?, description?)>
<!ATTLIST enumvalue
name CDATA #REQUIRED
%boost.common.attrib;>
<!ELEMENT static-constant (type, default, purpose?, description?)>
<!ATTLIST static-constant
name CDATA #REQUIRED
%boost.common.attrib;>
<!ELEMENT data-member (type, purpose?, description?)>
<!ATTLIST data-member
name CDATA #REQUIRED
specifiers CDATA #IMPLIED
%boost.common.attrib;>
<!ELEMENT paramtype ANY>
<!ATTLIST paramtype %boost.common.attrib;>
<!ELEMENT effects ANY>
<!ATTLIST effects %boost.common.attrib;>
<!ELEMENT postconditions ANY>
<!ATTLIST postconditions %boost.common.attrib;>
<!ELEMENT method-group (method|overloaded-method)*>
<!ATTLIST method-group
name CDATA #REQUIRED
%boost.common.attrib;>
<!ELEMENT constructor (template?, parameter*, %boost.function.semantics;)>
<!ATTLIST constructor
specifiers CDATA #IMPLIED
%boost.common.attrib;>
<!ELEMENT destructor (%boost.function.semantics;)>
<!ATTLIST destructor
specifiers CDATA #IMPLIED
%boost.common.attrib;>
<!ELEMENT method (template?, type, parameter*, %boost.function.semantics;)>
<!ATTLIST method
name CDATA #REQUIRED
cv CDATA #IMPLIED
specifiers CDATA #IMPLIED
%boost.common.attrib;>
<!ELEMENT function (template?, type, parameter*, %boost.function.semantics;)>
<!ATTLIST function
name CDATA #REQUIRED
specifiers CDATA #IMPLIED
%boost.common.attrib;>
<!ELEMENT overloaded-method (signature*, %boost.function.semantics;)>
<!ATTLIST overloaded-method
name CDATA #REQUIRED
%boost.common.attrib;>
<!ELEMENT overloaded-function (signature*, %boost.function.semantics;)>
<!ATTLIST overloaded-function
name CDATA #REQUIRED
%boost.common.attrib;>
<!ELEMENT signature (template?, type, parameter*)>
<!ATTLIST signature
cv CDATA #IMPLIED
specifiers CDATA #IMPLIED
%boost.common.attrib;>
<!ELEMENT requires ANY>
<!ATTLIST requires %boost.common.attrib;>
<!ELEMENT returns ANY>
<!ATTLIST returns %boost.common.attrib;>
<!ELEMENT throws ANY>
<!ATTLIST throws %boost.common.attrib;>
<!ELEMENT complexity ANY>
<!ATTLIST complexity %boost.common.attrib;>
<!ELEMENT notes ANY>
<!ATTLIST notes %boost.common.attrib;>
<!ELEMENT rationale ANY>
<!ATTLIST rationale %boost.common.attrib;>
<!ELEMENT functionname (#PCDATA)>
<!ATTLIST functionname
alt CDATA #IMPLIED
%boost.common.attrib;>
<!ELEMENT enumname (#PCDATA)>
<!ATTLIST enumname
alt CDATA #IMPLIED
%boost.common.attrib;>
<!ELEMENT macroname (#PCDATA)>
<!ATTLIST macroname
alt CDATA #IMPLIED
%boost.common.attrib;>
<!ELEMENT headername (#PCDATA)>
<!ATTLIST headername
alt CDATA #IMPLIED
%boost.common.attrib;>
<!ELEMENT globalname (#PCDATA)>
<!ATTLIST globalname
alt CDATA #IMPLIED
%boost.common.attrib;>
<!ELEMENT copy-assignment
(template?, type?, parameter*, %boost.function.semantics;)>
<!ATTLIST copy-assignment
cv CDATA #IMPLIED
specifiers CDATA #IMPLIED
%boost.common.attrib;>
<!ELEMENT free-function-group (function|overloaded-function)*>
<!ATTLIST free-function-group
name CDATA #REQUIRED
%boost.common.attrib;>
<!ELEMENT precondition ANY>
<!ATTLIST precondition %boost.common.attrib;>
<!ELEMENT code ANY>
<!ATTLIST code %boost.common.attrib;>
<!ELEMENT using-namespace EMPTY>
<!ATTLIST using-namespace
name CDATA #REQUIRED
%boost.common.attrib;>
<!ELEMENT using-class EMPTY>
<!ATTLIST using-class
name CDATA #REQUIRED
%boost.common.attrib;>
<!--========== Boost Testsuite Extensions ==========-->
<!ENTITY % boost.testsuite.tests
"compile-test|link-test|run-test|
compile-fail-test|link-fail-test|run-fail-test">
<!ENTITY % boost.testsuite.test.content
"source*, lib*, requirement*, purpose, if-fails?">
<!ELEMENT testsuite ((%boost.testsuite.tests;)+)>
<!ATTLIST testsuite %boost.common.attrib;>
<!ELEMENT compile-test (%boost.testsuite.test.content;)>
<!ATTLIST compile-test
filename CDATA #REQUIRED
name CDATA #IMPLIED>
<!ELEMENT link-test (%boost.testsuite.test.content;)>
<!ATTLIST link-test
filename CDATA #REQUIRED
name CDATA #IMPLIED>
<!ELEMENT run-test (%boost.testsuite.test.content;)>
<!ATTLIST run-test
filename CDATA #REQUIRED
name CDATA #IMPLIED>
<!ELEMENT compile-fail-test (%boost.testsuite.test.content;)>
<!ATTLIST compile-fail-test
filename CDATA #REQUIRED
name CDATA #IMPLIED>
<!ELEMENT link-fail-test (%boost.testsuite.test.content;)>
<!ATTLIST link-fail-test
filename CDATA #REQUIRED
name CDATA #IMPLIED>
<!ELEMENT run-fail-test (%boost.testsuite.test.content;)>
<!ATTLIST run-fail-test
filename CDATA #REQUIRED
name CDATA #IMPLIED>
<!ELEMENT source (#PCDATA|snippet)*>
<!ELEMENT snippet EMPTY>
<!ATTLIST snippet
name CDATA #REQUIRED>
<!ELEMENT lib (#PCDATA)>
<!ELEMENT requirement (#PCDATA)>
<!ATTLIST requirement
name CDATA #REQUIRED>
<!ELEMENT if-fails ANY>
<!ELEMENT parameter (paramtype, default?, description?)>
<!ATTLIST parameter
name CDATA #IMPLIED
pack CDATA #IMPLIED>
<!ELEMENT programlisting ANY>
<!ATTLIST programlisting
name CDATA #IMPLIED>
<!--========== Customize the DocBook DTD ==========-->
<!ENTITY % local.tech.char.class "|functionname|libraryname|enumname|headername|macroname|code">
<!ENTITY % local.para.class
"|using-namespace|using-class|librarylist|librarycategorylist">
<!ENTITY % local.descobj.class "|libraryinfo">
<!ENTITY % local.classname.attrib "alt CDATA #IMPLIED">
<!ENTITY % local.methodname.attrib "alt CDATA #IMPLIED">
<!ENTITY % local.refentry.class "|library-reference|testsuite">
<!ENTITY % local.title.char.mix "">
<!ENTITY % programlisting.module "IGNORE">
<!ENTITY % parameter.module "IGNORE">
<!ENTITY % function.module "IGNORE">
<!ENTITY % type.module "IGNORE">
<!--========== Import DocBook DTD ==========-->
<!ENTITY % DocBook PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
%DocBook;

213
doc/design.qbk Normal file
View File

@@ -0,0 +1,213 @@
[/
Copyright (c) 2013-2016 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:design Design choices]
The implementations are driven by business needs of cryptocurrency server
applications ([link https://ripple.com Ripple] written in C++. These
needs were not met by existing solutions so new code was written. The new
code tries to avoid design flaws encountered in the already-existing software
libraries:
* Don't sacrifice performance.
* Don't do too much, otherwise interfaces become rigid.
* Symmetric interfaces (client and server the same, or close to it).
* Emulate Boost.Asio interfaces as much as possible, since Asio is
proven and it is familiar to users.
* Let library users make the important decisions such as how to
allocate memory or how to leverage flow control.
Beast formalizes the [link beast.types.Streambuf [*`Streambuf`]] concept,
and relies heavily on the Boost.Asio [*`ConstBufferSequence`] and
[*`MutableBufferSequence`] concepts for passing buffers to functions.
The authors have found the `Streambuf` and buffer sequence interfaces
to be optimal for interacting with Asio, and for other tasks such as
incremental parsing of data in buffers (for example, parsing websocket
frames stored in a [link beast.ref.static_streambuf `static_streambuf`]).
During the development of Beast the authors have studied other software
packages and in particular the comments left during the Boost Review process
of other packages offering similar functionality. In this section we attempt
to address those issues.
[variablelist
[[
"I would also like to see instances of this library being used
in production. That would give some evidence that the design
works in practice.""
][
Beast.HTTP and Beast.WebSocket will be used in [*rippled], an
asynchronous peer to peer server that implements the
[*Ripple Consensus Protocol]. These servers are deployed in multiple
production environments, with banks in many countries running client
applications that connect to [*rippled].
]]
]
[section:http HTTP]
For HTTP we to model the message to maximize flexibility of implementation
strategies while allowing familiar verbs such as [*`read`] and [*`write`].
The HTTP interface is further driven by the needs of the WebSocket module,
as a WebSocket session requires a HTTP Upgrade handshake exchange at the
start. Other design goals:
* Don't try to invent a complete web server or client
* Have simple free functions to send and receive messages.
* Allow the message object to be customized,
[variablelist
[[
"Some more advanced examples, e.g. including TLS with client/server
certificates would help.""
][
The HTTP interface doesn't try to reinvent the wheel, it just uses
the `boost::asio::ip::tcp::socket` or `boost::asio::ssl::stream` that
you set up beforehand. Callers use the interfaces already existing
on those objects to make outgoing connections, accept incoming connections,
or establish TLS sessions with certificates. We find the available Asio
examples for performing these tasks sufficient.
]]
[[
"A built-in router?"
][
We presume this means a facility to match expressions against the URI
in HTTP requests, and dispatch them to calling code. The authors feel
that this is a responsibility of higher level code. Beast.HTTP does
not try to offer a web server.
]]
[[
"Cookies? Forms/File Uploads?""
][
Cookies, or managing these types of HTTP headers in general, is the
responsibility of higher levels. Beast.HTTP just tries to get complete
messages to and from the calling code. It deals in the HTTP headers just
enough to process the message body and leaves the rest to callers. However,
for forms and file uploads the symmetric interface of the message class
allows HTTP requests to include arbitrary body types including those needed
to upload a file or fill out a form.
]]
[[
"...supporting TLS (is this a feature? If not this would be a show-stopper),
etc.
][
Beast.HTTP does not provide direct facilities for implementing TLS
connections; however, the interfaces already existing on the
`boost::asio::ssl::stream` are available and can be used to establish
secure connections. Then, functions like `http::read` or `http::async_write`
can work with those encrypted connections with no problem.
]]
[[
"There should also be more examples of how to integrate the http service
with getting files from the file system, generating responses CGI-style"
][
The design goal for the library is to not try to invent a web server.
We feel that there is a strong need for a basic implementation that
models the HTTP message and provides functions to send and receive them
over Asio. Such an implementation should serve as a building block upon
which higher abstractions such as the aforementioned HTTP service or
cgi-gateway can be built.
]]
[[
"You should send a 100-continue to ask for the rest of the body if required."
][
These behaviors are best left to the calling software. A future library
can build on Beast.HTTP to provide these behaviors.
]]
[[
"What about HTTP/2?""
][
Many reviewers feel that HTTP/2 support is an essential feature of
a HTTP library. The authors agree that HTTP/2 is important but also
feel that the most sensible implementation is one that does not re-use
the same network reading and writing interface for 2 as that for 1.0
and 1.1.
The Beast.HTTP message model is suitable for HTTP/2 and can be re-used.
The IEFT HTTP Working Group adopted message compatiblity with HTTP/1.x
as an explicit goal. A parser can simply emit full headers after
decoding the compressed HTTP/2 headers. The stream ID is not logicaly
part of the message but rather message metadata and should be
communicated out-of-band (see below). HTTP/2 sessions begin with a
traditional HTTP/1.1 Upgrade similar in fashion to the WebSocket
upgrade. A HTTP/2 implementation can use existing Beast.HTTP primitives
to perform this handshake.
Free functions for HTTP/2 sessions are not possible because of the
requirement to maintain per-session state. For example, to decode the
compressed headers. Or to remember and respect the remote peer's window
settings. The authors propose that a HTTP/2 implementation be written
as a separate class template, similar to the `websocket::stream` but with
additional interfaces to support version 2 features. We feel that
Beast.HTTP offers enough useful functionality to justify inclusion,
so that developers can take advantage of it right away instead of
waiting.
]]
]
[endsect]
[section:websocket WebSocket]
[variablelist
[[
What about message compression?
][
The feature is not currently present in the library, but the choice
of type requirements for buffers passed to the read functions have been
made with compression in mind. There is the plan to add this feature;
however, we feel that even without compression users can begin taking
advantage of the WebSocket protocol immediately with this library.
]]
[[
Where is the TLS/SSL interface?
][
The `websocket::stream` just wraps the socket or stream that you
provide (for example, a `boost::asio::ip::tcp::socket` or a
`boost::asio::ssl::stream`). You establish your TLS connection
using the interface on `ssl::stream` like shown in all of the Asio
examples, they construct your `websocket::stream` around it.
It works perfectly fine - Beast.WebSocket doesn't try to reinvent the
wheel or put a fresh coat of interface paint on the `ssl::stream`.
The WebSocket implementation [*does] provides support for shutting down
the TLS connection through the use of the ADL compile-time virtual functions
[link beast.ref.wsproto__teardown `teardown`] and
[link beast.ref.wsproto__async_teardown `async_teardown`]. These will
properly close the connection as per rfc6455 and overloads are available
for TLS streams. Callers may provide their own overloads of these functions
for user-defined next layer types.
]]
]
[endsect]
[endsect]

215
doc/http.qbk Normal file
View File

@@ -0,0 +1,215 @@
[/
Copyright (c) 2013-2016 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:http HTTP]
Beast.HTTP offers programmers simple and performant models of HTTP messages and
their associated operations including synchronous and asynchronous reading and
writing using Boost.Asio.
The HTTP protocol is described fully in
[@https://tools.ietf.org/html/rfc2616 rfc2616]
[section:motivation Motivation]
The HTTP protocol is pervasive in network applications. As C++ is a logical
choice for high performance network servers, there is great utility in solid
building blocks for manipulating, sending, and receiving HTTP messages
compliant with the Hypertext Transfer Protocol and the supplements that
follow. Unfortunately reliable implementations or industry standards do not
exist in C++.
Beast.HTTP is built on Boost.Asio and uses HTTP parser from NodeJS, which is
extensively field tested and exceptionally robust. A proposal to add networking
functionality to the C++ standard library, based on Boost.Asio, is under
consideration by the standards committee. Since the final approved networking
interface for the C++ standard library will likely closely resemble the current
interface of Boost.Asio, it is logical for Beast.HTTP to use Boost.Asio as its
network transport.
[note The documentation which follows assumes familiarity with
both Boost.Asio and the HTTP protocol specification described in
[@https://tools.ietf.org/html/rfc2616 rfc2616] ]
[endsect]
[section:example Example]
All examples and identifiers mentioned in this document are written as
if the following declarations are in effect:
```
#include <beast/http.h>
using namespace beast::http;
using namespace boost::asio;
```
Create a HTTP request:
```
request<string_body> req({method_t::http_get, "/", 11});
req.headers.insert("Host", "127.0.0.1:80");
req.headers.insert("User-Agent", "Beast.HTTP");
```
To send a message it must first be prepared through a call to `prepare`. This
customization point transforms the `message` into a `prepared_message`,
filling in some standard HTTP behavior and allowing the Body associated with
the message to perform preparatory steps. For example, a string body may set
the Content-Length and Content-Type appropriately.
```
void send_request(ip::tcp::socket& sock,
request<string_body>&& req)
{
// Send the request on the socket
write(sock, prepare(req, connection(keep_alive));
}
```
Messages can be read from the network and parsed into a `parsed_message` object,
which extends the `message` by adding parse-specific metadata such as the
keep-alive which is context sensitive (depending on the HTTP version for
example). When preparing a response for sending, `prepare` must be called with
an additional parameter, the corresponding parsed request. The implementation
inspects the contents of the request to set dependent fields of the response.
This example reads a message, builds a response, and sends it.
```
void handle_connection(ip::tcp::socket& sock)
{
parsed_request<string_body> req;
read(sock, req);
response<string_body> resp;
...
write(sock, prepare(resp, req));
}
```
[endsect]
[section:message Message model]
A HTTP message (referred to hereafter as "message") contains a request or
response line, a series of zero or more name/value pairs (collectively
termed "headers"), and a series of octets called the message body which may
be zero in length. Applications using HTTP often perform these operations
on messages:
* [*Parse] a new message from a series of octets.
* [*Assemble] a new message from scratch or from an existing message.
* [*Serialize] a message into a series of octets.
* [*Read] a message from a stream. This can be thought of as a compound
operation; a network read, followed by a [*parse].
* [*Write] a message to a stream. This can be thought of as a compound
operation: a [*serialize] followed by a network write.
The spectrum of hardware and software platforms which perform these typical
HTTP operations is vast, ranging from powerful servers in large datacenters
to tiny resource-limited embedded devices. No single concrete implementation
of a class intended to model messages can efficiently serve all needs.
For example, an object that minimizes resources during parsing may not be
able to edit and change headers dynamically. A message that represents the
message body as a disk file may support sending but not parsing. Many efficient
and correct models of messages exist, supporting some or all of the
operations listed above.
To support a variety of implementation strategies, we introduce customization
points for the header and body via class template arguments. This illustration
shows the message class template (boilerplate present in the actual
declaration has been removed for clarity):
[$images/message.png [width 580px] [height 225px]]
The default constructor, move special members, and copy special members are
all defaulted. A message is movable, copyable, or default constructible based
on the capabilities of its template arguments.
Messages modeled in this fashion are ['complete], containing all of the
information required to perform the supported set of operations. They are
['first-class types], returnable from functions and composable. HTTP
requests and responses are distinct types, allowing functions to be
overloaded on the type of message.
[endsect]
[section:body Body parameter]
The `Body` template argument in the `message` class must meet the
[link beast.types.Body [*`Body`] requirements]. It provides customization
of the data member in the message, the algorithm for parsing, and the
algorithm for serialization:
[$images/body.png [width 510px] [height 210px]]
The following types, provided by the library, meet the `Body` requirements:
* [link beast.ref.http__empty_body [*`empty_body`:]] An empty message body.
Used in GET requests where there is no message body.
* [link beast.ref.http__string_body [*`string_body`:]] A body with a
`value_type` of `std::string`. Useful for quickly putting together a request
or response with simple text in the message body (such as an error message).
Subject to the performance limit of strings if large amounts of data are
inserted.
* [link beast.ref.http__basic_streambuf_body [*`basic_streambuf_body`:]] A body with a
`value_type` of `streambuf`. A streambuf is an efficient storage object which
uses multiple octet arrays of varying lengths to represent data.
Instances of the optional nested types `writer` and `reader` perform
serialization and deserialization of the message body. If either or
both of these types are present, the message becomes serializable, parsable,
or both. They model [link beast.types.Reader [*`Reader`]] and
[link beast.types.Writer [*`Writer`]] respectively.
For specialized applications, users may implement their own types which
meet the requirements. The examples included with this library provide a
Body implementation used to serve files in a HTTP server.
[endsect]
[section:headers Headers container]
The `Headers` type represents the field/value pairs present in every HTTP
message. These types implement the
[link beast.types.FieldSequence [*`FieldSequence`]]
concept. The value type of a field sequence is an object meeting the
requirements of [link beast.types.Field [*`Field`]]. The implementation can
serialize any instance of `Headers` that meets the field sequence requirements.
This example shows a function which returns `true` if the specified field
sequence has a connect field:
```
template<class FieldSequence>
bool
has_connect(FieldSequence const& fs)
{
return std::find_if(fs.begin(), fs.end(),
[&](auto const& field)
{
return ci_equal(field.name(), "Connect");
});
}
```
[endsect]
[endsect]

BIN
doc/images/beast.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

BIN
doc/images/beast.psd Normal file

Binary file not shown.

BIN
doc/images/body.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

BIN
doc/images/body.psd Normal file

Binary file not shown.

BIN
doc/images/message.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.3 KiB

BIN
doc/images/message.psd Normal file

Binary file not shown.

13
doc/index.xml Normal file
View File

@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE library PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN" "boostbook.dtd">
<!--
Copyright (c) 2013-2016 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 id="index">
<index/>
</section>

13
doc/makeqbk.sh Normal file
View File

@@ -0,0 +1,13 @@
#!/usr/bin/bash
# Copyright (c) 2013-2016 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)
mkdir -p ../bin/doc/xml
doxygen beast.dox
cd ../bin/doc/xml
xsltproc combine.xslt index.xml > all.xml
cd ../../../doc
xsltproc reference.xsl ../bin/doc/xml/all.xml > reference.qbk

163
doc/quickref.xml Normal file
View File

@@ -0,0 +1,163 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE library PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN" "boostbook.dtd">
<!--
Copyright (c) 2013-2016 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)
-->
<informaltable frame="all">
<tgroup cols="4">
<colspec colname="a"/>
<colspec colname="b"/>
<colspec colname="c"/>
<colspec colname="d"/>
<thead>
<row>
<entry valign="center" namest="a" nameend="b">
<bridgehead renderas="sect2">HTTP</bridgehead>
</entry>
<entry valign="center" namest="c" nameend="d">
<bridgehead renderas="sect2">WebSocket</bridgehead>
</entry>
</row>
</thead>
<tbody>
<row>
<entry valign="top">
<bridgehead renderas="sect3">Classes</bridgehead>
<simplelist type="vert" columns="1">
<member><link linkend="beast.ref.http__basic_headers">basic_headers</link></member>
<member><link linkend="beast.ref.http__basic_parser">basic_parser</link></member>
<member><link linkend="beast.ref.http__basic_streambuf_body">basic_streambuf_body</link></member>
<member><link linkend="beast.ref.http__empty_body">empty_body</link></member>
<member><link linkend="beast.ref.http__error_code">error_code</link></member>
<member><link linkend="beast.ref.http__message">message</link></member>
<member><link linkend="beast.ref.http__resume_context">resume_context</link></member>
<member><link linkend="beast.ref.http__stream">stream</link></member>
<member><link linkend="beast.ref.http__streambuf_body">streambuf_body</link></member>
<member><link linkend="beast.ref.http__string_body">string_body</link></member>
</simplelist>
<bridgehead renderas="sect3">Type Traits</bridgehead>
<simplelist type="vert" columns="1">
<member><link linkend="beast.ref.http__is_Body">is_Body</link></member>
</simplelist>
</entry>
<entry valign="top">
<bridgehead renderas="sect3">Functions</bridgehead>
<simplelist type="vert" columns="1">
<member><link linkend="beast.ref.http__async_read">async_read</link></member>
<member><link linkend="beast.ref.http__async_write">async_write</link></member>
<member><link linkend="beast.ref.http__chunk_encode">chunk_encode</link></member>
<member><link linkend="beast.ref.http__chunk_encode_final">chunk_encode_final</link></member>
<member><link linkend="beast.ref.http__read">read</link></member>
<member><link linkend="beast.ref.http__write">write</link></member>
</simplelist>
<bridgehead renderas="sect3">Concepts</bridgehead>
<simplelist type="vert" columns="1">
<member><link linkend="beast.types.Body">Body</link></member>
<member><link linkend="beast.types.Field">Field</link></member>
<member><link linkend="beast.types.FieldSequence">FieldSequence</link></member>
<member><link linkend="beast.types.Reader">Reader</link></member>
<member><link linkend="beast.types.Writer">Writer</link></member>
</simplelist>
</entry>
<entry valign="top">
<bridgehead renderas="sect3">Classes</bridgehead>
<simplelist type="vert" columns="1">
<member><link linkend="beast.ref.wsproto__close_reason">close_reason</link></member>
<member><link linkend="beast.ref.wsproto__socket">socket</link></member>
<member><link linkend="beast.ref.wsproto__static_string">static_string</link></member>
</simplelist>
<bridgehead renderas="sect3">Options</bridgehead>
<simplelist type="vert" columns="1">
<member><link linkend="beast.ref.wsproto__auto_fragment_size">auto_fragment_size</link></member>
<member><link linkend="beast.ref.wsproto__decorate">decorate</link></member>
<member><link linkend="beast.ref.wsproto__keep_alive">keep_alive</link></member>
<member><link linkend="beast.ref.wsproto__read_buffer_size">read_buffer_size</link></member>
<member><link linkend="beast.ref.wsproto__read_message_max">read_message_max</link></member>
<member><link linkend="beast.ref.wsproto__write_buffer_size">write_buffer_size</link></member>
</simplelist>
</entry>
<entry valign="top">
<bridgehead renderas="sect3">Functions</bridgehead>
<simplelist type="vert" columns="1">
<member><link linkend="beast.ref.wsproto__async_teardown">async_teardown</link></member>
<member><link linkend="beast.ref.wsproto__teardown">teardown</link></member>
</simplelist>
<bridgehead renderas="sect3">Constants</bridgehead>
<simplelist type="vert" columns="1">
<member><link linkend="beast.ref.wsproto__close_code">close_code</link></member>
<member><link linkend="beast.ref.wsproto__opcode">opcode</link></member>
</simplelist>
</entry>
</row>
</tbody>
</tgroup>
<tgroup cols="4">
<colspec colname="a"/>
<colspec colname="b"/>
<colspec colname="c"/>
<colspec colname="d"/>
<thead>
<row>
<entry valign="center" namest="a" nameend="d">
<bridgehead renderas="sect2">Core</bridgehead>
</entry>
</row>
</thead>
<tbody>
<row>
<entry valign="top">
<bridgehead renderas="sect3">Classes</bridgehead>
<simplelist type="vert" columns="1">
<member><link linkend="beast.ref.async_completion">async_completion</link></member>
<member><link linkend="beast.ref.basic_streambuf">basic_streambuf</link></member>
<member><link linkend="beast.ref.buffers_adapter">buffers_adapter</link></member>
<member><link linkend="beast.ref.consuming_buffers">consuming_buffers</link></member>
<member><link linkend="beast.ref.handler_alloc">handler_alloc</link></member>
<member><link linkend="beast.ref.prepared_buffers">prepared_buffers</link></member>
<member><link linkend="beast.ref.static_streambuf">static_streambuf</link></member>
<member><link linkend="beast.ref.static_streambuf_n">static_streambuf_n</link></member>
<member><link linkend="beast.ref.streambuf">streambuf</link></member>
<member><link linkend="beast.ref.streambuf_readstream">streambuf_readstream</link></member>
</simplelist>
</entry>
<entry valign="top">
<bridgehead renderas="sect3">Functions</bridgehead>
<simplelist type="vert" columns="1">
<member><link linkend="beast.ref.append_buffers">append_buffers</link></member>
<member><link linkend="beast.ref.bind_handler">bind_handler</link></member>
<member><link linkend="beast.ref.prepare_buffer">prepare_buffer</link></member>
<member><link linkend="beast.ref.prepare_buffers">prepare_buffers</link></member>
</simplelist>
</entry>
<entry valign="top">
<bridgehead renderas="sect3">Type Traits</bridgehead>
<simplelist type="vert" columns="1">
<member><link linkend="beast.ref.is_AsyncReadStream">is_AsyncReadStream</link></member>
<member><link linkend="beast.ref.is_AsyncWriteStream">is_AsyncWriteStream</link></member>
<member><link linkend="beast.ref.is_BufferSequence">is_BufferSequence</link></member>
<member><link linkend="beast.ref.is_ConstBufferSequence">is_ConstBufferSequence</link></member>
<member><link linkend="beast.ref.is_Handler">is_Handler</link></member>
<member><link linkend="beast.ref.is_MutableBufferSequence">is_MutableBufferSequence</link></member>
<member><link linkend="beast.ref.is_Stream">is_Stream</link></member>
<member><link linkend="beast.ref.is_Streambuf">is_Streambuf</link></member>
<member><link linkend="beast.ref.is_SyncReadStream">is_SyncReadStream</link></member>
<member><link linkend="beast.ref.is_SyncWriteStream">is_SyncWriteStream</link></member>
</simplelist>
</entry>
<entry valign="top">
<bridgehead renderas="sect3">Concepts</bridgehead>
<simplelist type="vert" columns="1">
<member><link linkend="beast.types.BufferSequence">BufferSequence</link></member>
<member><link linkend="beast.types.Stream">Stream</link></member>
<member><link linkend="beast.types.Streambuf">Streambuf</link></member>
</simplelist>
</entry>
</row>
</tbody>
</tgroup>
</informaltable>

1725
doc/reference.xsl Normal file

File diff suppressed because it is too large Load Diff

446
doc/types.qbk Normal file
View File

@@ -0,0 +1,446 @@
[/
Copyright (c) 2013-2016 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:types Type Requirements]
[section:Body Body]
In this table:
* `X` is a type meeting the requirements of [*`Body`].
[table Body requirements
[[operation] [type] [semantics, pre/post-conditions]]
[
[`X::value_type`]
[]
[
The type of the `message::body` member.
If this is not movable or not copyable, the containing message
will be not movable or not copyable.
]
]
[
[`X:value_type{}`]
[]
[`DefaultConstructible`]
]
[
[`Body::reader`]
[]
[
If present, a type meeting the requirements of
[link beast.types.Reader [*`Reader`]].
Provides an implementation to parse the body.
]
]
[
[`Body::writer`]
[]
[
If present, a type meeting the requirements of
[link beast.types.Writer [*`Writer`]].
Provides an implementation to serialize the body.
]
]
]
[endsect]
[section:BufferSequence BufferSequence]
A `BufferSequence` meets [*one of] the following requirements:
* `ConstBufferSequence`
* `MutableBufferSequence`
[endsect]
[section:Field Field]
A [*`Field`] represents a single HTTP header field/value pair.
In this table:
* `X` denotes a type meeting the requirements of [*`Field`].
* `a` denotes a value of type `X`.
[table Field requirements
[[operation][type][semantics, pre/post-conditions]]
[
[`a.name()`]
[`boost::string_ref`]
[
This function returns a value implicitly convertible to
`boost::string_ref` containing the case-insensitve field
name, without leading or trailing white space.
]
]
[
[`a.value()`]
[`boost::string_ref`]
[
This function returns a value implicitly convertible to
`boost::string_ref` containing the value for the field. The
value is considered canonical if there is no leading or
trailing whitespace.
]
]
]
[endsect]
[section:FieldSequence FieldSequence]
A [*`FieldSequence`] is an iterable container whose value type meets
the requirements of [link beast.types.Field [*`Field`]].
In this table:
* `X` denotes a type that meets the requirements of [*`FieldSequence`].
* `a` is a value of type `X`.
[table FieldSequence requirements
[[operation][type][semantics, pre/post-conditions]]
[
[`X::value_type`]
[]
[
A type that meets the requirements of `Field`.
]
]
[
[`X::const_iterator`]
[]
[
A type that meets the requirements of `ForwardIterator`.
]
]
[
[`a.begin()`]
[`X::const_iterator`]
[
Returns an iterator to the beginning of the field sequence.
]
]
[
[`a.end()`]
[`X::const_iterator`]
[
Returns an iterator to the end of the field sequence.
]
]
]
[endsect]
[section:Reader Reader]
Parser implementations will construct the corresponding `reader` object
during the parse. This customization point allows the Body to determine
the strategy for storing incoming message body data.
In this table:
* `X` denotes a type meeting the requirements of [*`Reader`].
* `a` denotes a value of type `X`.
* `p` is any pointer.
* `n` is a value convertible to `std::size_t`.
* `ec` is a value of type `error_code&`.
* `m` denotes a value of type `message const&` where
`std::is_same<decltype(m.body), Body::value_type>:value == true`
[table Reader requirements
[[operation] [type] [semantics, pre/post-conditions]]
[
[`X a(m);`]
[]
[
`a` is constructible from `m`. The lifetime of `m` is
guaranteed to end no earlier than after `a` is destroyed.
]
]
[
[`a.write(p, n, ec)`]
[`void`]
[
Deserializes the input sequence into the body.
If `ec` is set, the deserialization is aborted and the error
is returned to the caller.
]
]
]
[note Definitions for required `Reader` member functions should be declared
inline so the generated code becomes part of the implementation. ]
[endsect]
[section:Writer Writer]
A `Writer` serializes the message body. The implementation creates an instance
of this type when serializing a message, and calls into it zero or more times
to provide buffers containing the data. The interface of `Writer` is intended
to allow serialization in these scenarios:
* A body that does not entirely fit in memory.
* A body produced incrementally from coroutine output.
* A body represented by zero or more buffers already in memory.
* A body as a series of buffers when the content size is not known ahead of time.
* Body data generated on demand from other threads.
* Body data computed algorithmically.
In this table:
* `X` denotes a type meeting the requirements of `Writer`.
* `a` denotes a value of type `X`.
* `m` denotes a value of type `message const&` where
`std::is_same<decltype(m.body), Body::value_type>:value == true`.
* `rc` is an object of type [link beast.reference.http__resume_context resume_context].
* `ec` is a value of type `error_code&`.
* `wf` is a [*write function]: a function object of unspecified type provided
by the implementation which accepts any value meeting the requirements
of `ConstBufferSequence` as its single parameter.
[table Writer requirements
[[operation] [type] [semantics, pre/post-conditions]]
[
[`X a(m);`]
[]
[
`a` is constructible from `m`. The lifetime of `m` is
guaranteed to end no earlier than after `a` is destroyed.
]
]
[
[`a.init(ec)`]
[`void`]
[
Called immediately after construction.
If `ec` is set, the serialization is aborted and the error
is propagated to the caller.
]
]
[
[`a.content_length()`]
[`std::size_t`]
[
If this member is present, it is called after initialization
and before calls to provide buffers. The serialized message will
have the Content-Length field set to the value returned from
this function. If this member is absent, the serialized message
body will be chunk-encoded for HTTP versions 1.1 and later, else
the serialized message body will be sent unmodified, with the
error `boost::asio::error::eof` returned to the caller, to notify
they should close the connection to indicate the end of the message.
]
]
[
[`a(rc, ec, wf)`]
[`boost::tribool`]
[
Called repeatedly after `init` succeeds.
`wf` is a function object which takes as its single parameter,
any value meeting the requirements of `ConstBufferSequence`.
Buffers provided by the `writer` to this [*write function] must
remain valid until the next member function of `writer` is
invoked (which may be the destructor). This function returns `true`
to indicate all message body data has been written, or `false`
if there is more body data. If the return value is
`boost::indeterminate`, the implementation will suspend the operation
until the writer invokes `rc`. It is the writers responsibility when
returning `boost::indeterminate`, to acquire ownership of the
`resume_context` via move construction and eventually call it or else
undefined behavior results.
]
]
]
[note Definitions for required `Writer` member functions should be declared
inline so the generated code becomes part of the implementation. ]
Exemplar:
```
struct writer
{
public:
/** Construct the writer.
The msg object is guaranteed to exist for the lifetime of the writer.
Exceptions:
No-throw guarantee.
@param msg The message whose body is to be written.
*/
template<bool isRequest, class Body, class Headers>
explicit
writer(message<isRequest, Body, Headers> const& msg);
/** Initialize the writer.
Called once immediately after construction.
The writer can perform initialization which may fail.
@param ec Contains the error code if any errors occur.
*/
void
init(error_code& ec);
/** Returns the content length.
If this member is present, the implementation will set the
Content-Length field accordingly. If absent, the implementation will
use chunk-encoding or terminate the connection to indicate the end
of the message.
*/
std::size_t
content_length() const;
/** Write zero or one buffer representing the message body.
Postconditions:
If return value is `true`:
* Callee does not take ownership of resume.
* Callee made zero or one calls to `write`.
* There is no more data remaining to write.
If return value is `false`:
* Callee does not take ownership of resume.
* Callee made one call to `write`.
If return value is boost::indeterminate:
* Callee takes ownership of `resume`.
* Caller suspends the write operation
until `resume` is invoked.
When the caller takes ownership of resume, the
asynchronous operation will not complete until the
caller destroys the object.
@param resume A functor to call to resume the write operation
after the writer has returned boost::indeterminate.
@param ec Set to indicate an error. This will cause an
asynchronous write operation to complete with the error.
@param write A functor the writer will call to provide the next
set of buffers. Ownership of the buffers is not transferred,
the writer must guarantee that the buffers remain valid until the
next member function is invoked, which may be the destructor.
@return `true` if there is data, `false` when done,
boost::indeterminate to suspend.
@note Undefined behavior if the callee takes ownership
of resume but does not return boost::indeterminate.
*/
template<class WriteFunction>
boost::tribool
operator()(resume_context&&, error_code&, WriteFunction&& write);
};
```
[endsect]
[section:Stream Stream]
A `Stream` meets the following requirements:
* `SyncReadStream`
* `SyncWriteStream`
* `AsyncReadStream`
* `AsyncWriteStream`
[endsect]
[section:Streambuf Streambuf]
In the table below, `X` denotes a class, `a` denotes a value
of type `X`, `n` denotes a value convertible to `std::size_t`,
and `U` and `T` denote unspecified types.
[table Streambuf requirements
[[operation] [type] [semantics, pre/post-conditions]]
[
[`X::const_buffers_type`]
[`T`]
[`T` meets the requirements for `ConstBufferSequence`.]
]
[
[`X::mutable_buffers_type`]
[`U`]
[`U` meets the requirements for `MutableBufferSequence`.]
]
[
[`a.commit(n)`]
[`void`]
[Moves bytes from the output sequence to the input sequence.]
]
[
[`a.consume(n)`]
[`void`]
[Removes bytes from the input sequence.]
]
[
[`a.data()`]
[`T`]
[Returns a list of buffers that represents the input sequence.]
]
[
[`a.prepare(n)`]
[`U`]
[Returns a list of buffers that represents the output sequence, with
the given size.]
]
[
[`a.size()`]
[`std::size_t`]
[Returns the size of the input sequence.]
]
[
[`a.max_size()`]
[`std::size_t`]
[Returns the maximum size of the `Streambuf`.]
]
]
[endsect]
[endsect]

391
doc/wsproto.qbk Normal file
View File

@@ -0,0 +1,391 @@
[/
Copyright (c) 2013-2016 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:wsproto WSProto]
The WebSocket Protocol enables two-way communication between a client
running untrusted code in a controlled environment to a remote host that has
opted-in to communications from that code. The protocol consists of an opening
handshake followed by basic message framing, layered over TCP. The goal of
this technology is to provide a mechanism for browser-based applications that
need two-way communication with servers that does not rely on opening multiple
HTTP connections.
Beast.WSProto provides developers with a robust WebSocket implementation
built on Boost.Asio with a consistent asynchronous model using a modern
C++ approach.
The WebSocket protocol is described fully in
[@https://tools.ietf.org/html/rfc6455 rfc6455]
[section:motivation Motivation]
Today's web applications increasingly rely on alternatives to standard HTTP
to achieve performance and/or responsiveness. While WebSocket implementations
are widely available in common web development languages such as Javascript,
good implementations in C++ are scarce. A survey of existing C++ WebSocket
solutions reveals interfaces which lack symmetry, impose performance penalties,
and needlessly restrict implementation strategies.
Beast.WSProto is built on Boost.Asio, a robust cross platform networking
framework that is part of Boost and also offered as a standalone library.
A proposal to add networking functionality to the C++ standard library,
based on Boost.Asio, is under consideration by the standards committee.
Since the final approved networking interface for the C++ standard library
will likely closely resemble the current interface of Boost.Asio, it is
logical for Beast.WSProto to use Boost.Asio as its network transport.
Beast.WSProto takes advantage of Boost.Asio's extensible asynchronous
model, handler allocation, and handler invocation hooks. Calls to
Beast.WSProto asynchronous initiation functions allow callers the choice
of using a completion handler, stackful or stackless coroutines, futures,
or user defined customizations (for example, Boost.Fiber). The
implementation uses handler invocation hooks (`asio_handler_invoke`),
providing execution guarantees on composed operations in a manner
identical to Boost.Asio. The implementation also uses handler allocation
hooks (`asio_handler_allocate`) when allocating memory internally for
composed operations.
There is no need for inheritance or virtual members in `wsproto::socket`.
All operations are templated and transparent to the compiler, allowing for
maximum inlining and optimization.
[note The documentation which follows assumes familiarity with
both Boost.Asio and the WebSocket protocol specification described in
[@https://tools.ietf.org/html/rfc6455 rfc6455] ]
[endsect]
[section:creating Creating the socket]
The interface to Beast's WebSocket implementation is a single template
class which wraps an object meeting the requirements of `SyncStream` if
synchronous operations are performed, `AsyncStream` if asynchronous
operations are performed, or both. Arguments supplied during construction
are passed to the `Stream` constructor. Here we declare two websockets
which contain the underlying stream:
```
io_service ios;
wsproto::socket<tcp::socket> ws(ios);
ssl::context ctx(ssl::context::sslv23);
wsproto::socket<ssl::stream<tcp::socket>> wss(ios, ctx);
```
For servers that can handshake in multiple protocols, it may be desired
to wrap a socket that already exists. The socket can be moved in:
```
tcp::socket&& sock;
...
wsproto::socket<tcp::socket> ws(std::move(sock));
```
Or, the wrapper can be constructed with a non-owning reference. In
this case, the caller is responsible for managing the lifetime of the
underlying socket being wrapped:
```
tcp::socket sock;
...
wsproto::socket<tcp::socket&> ws(sock);
```
The stream being wrapped can be accessed through the websocket's "next layer",
permitting callers to interact directly with its interface.
```
ssl::context ctx(ssl::context::sslv23);
wsproto::socket<ssl::stream<tcp::socket>> ws(ios, ctx);
...
ws.next_layer().shutdown(); // ssl::stream shutdown
```
[important Initiating read and write operations on the next layer while
websocket operations are being performed can break invariants, and
result in undefined behavior. ]
[endsect]
[section:connecting Making connections]
Connections are established by using the interfaces which already exist for
the wrapped stream. For example, making an outgoing connection:
```
std::string const host = "mywebapp.com";
io_service ios;
tcp::resolver r(ios);
wsproto::socket<tcp::socket> ws(ios);
connect(ws.next_layer(), r.resolve(tcp::resolver::query{host, "ws"}));
```
Accepting an incoming connection:
```
void do_accept(tcp::acceptor& acceptor)
{
wsproto::socket<tcp::socket> ws(acceptor.get_io_service());
acceptor.accept(ws.next_layer());
}
```
[note Examples use synchronous interfaces for clarity of exposition. ]
[endsect]
[section:handshaking Handshaking]
A WebSocket session begins when one side sends the HTTP Upgrade request
for websocket, and the other side sends an appropriate HTTP response
indicating that the request was accepted and that the connection has
been upgraded. The HTTP Upgrade request must include the Host HTTP field,
and the URI of the resource to request. `wsproto::socket::hanshake` is
used to send the request with the required host and resource strings.
```
wsproto::socket<tcp::socket> ws(ios);
...
ws.set_option(wsproto::keep_alive(true));
ws.handshake("ws.mywebapp.com:80", "/cgi-bin/bitcoin-prices");
```
The `wsproto::socket` automatically handles receiving and processing
the HTTP response to the handshake request. The call to handshake is
successful if a HTTP response is received with the 101 "Switching Protocols"
status code. On failure, an error is returned or an exception is thrown.
Depending on the keep alive setting, the socket may remain open for a
subsequent handshake attempt
Performing a handshake for an incoming websocket upgrade request operates
similarly. If the handshake fails, an error is returned or exception thrown:
```
wsproto::socket<tcp::socket> ws(ios);
...
ws.accept();
```
Servers that can handshake in multiple protocols may have already read data
on the connection, or might have already received an entire HTTP request
containing the upgrade request. Overloads of `accept` allow callers to
pass in this additional buffered handshake data.
```
void do_accept(tcp::socket& sock)
{
boost::asio::streambuf sb;
read_until(sock, sb, "\r\n\r\n");
...
wsproto::socket<tcp::socket&> ws(sock);
ws.accept(sb.data());
...
}
```
Alternatively, the caller can pass an entire HTTP request if it was
obtained elsewhere:
```
void do_accept(tcp::socket& sock)
{
boost::asio::streambuf sb;
http::parsed_request<http::empty_body> request;
http::read(sock, request);
...
wsproto::socket<tcp::socket&> ws(sock);
ws.accept(request);
...
}
```
[note Identifiers in the `http` namespace are part of Beast.HTTP. ]
[endsect]
[section:messages Messages]
After the WebSocket handshake is accomplished, callers may send and receive
messages using the message oriented interface. This interface requires that
all of the buffers representing the message are known ahead of time:
```
void echo(wsproto::socket<ip::tcp::socket>& ws)
{
streambuf sb;
wsproto::opcode::value op;
ws.read(sb);
ws.set_option(wsproto::message_type(op));
wsproto::write(ws, sb.data());
sb.consume(sb.size());
}
```
[important Calls to `wsproto::socket::set_option` must be made from the same
implicit or explicit strand as that used to perform other operations. ]
[endsect]
[section:frames Frames]
Some use-cases make it impractical or impossible to buffer the entire
message ahead of time:
* Streaming multimedia to an endpoint.
* Sending a message that does not fit in memory at once.
* Providing incremental results as they become available.
For these cases, the frame oriented interface may be used. This
example reads and echoes a complete message using this interface:
```
void echo(wsproto::socket<ip::tcp::socket>& ws)
{
beast::streambuf sb;
wsproto::frame_info fi;
for(;;)
{
ws.read_frame(fi, sb);
if(fi.fin)
break;
}
ws.set_option(wsproto::message_type(fi.op));
beast::consuming_buffers<streambuf::const_buffers_type> cb(sb.data());
for(;;)
{
using boost::asio::buffer_size;
std::size_t size = std::min(buffer_size(cb));
if(size > 512)
{
ws.write_frame(false, beast::prepare_buffers(512, cb));
cb.consume(512);
}
else
{
ws.write_frame(true, cb);
break;
}
}
}
```
[endsect]
[section:controlframes Control frames]
During read operations, the implementation automatically reads and processes
WebSocket control frames such as ping, pong, and close. Pings are replied
to as soon as possible, pongs are noted. The receipt of a close frame
initiates the WebSocket close procedure, eventually resulting in the
error code `wsproto::error::closed` being delivered to the caller in
a subsequent read operation, assuming no other error takes place.
To ensure timely delivery of control frames, large messages are broken up
into smaller sized frames. The implementation chooses the size and number
of the frames making up the message. The automatic fragment size option
gives callers control over the size of these frames:
```
...
ws.set_option(wsproto::auto_fragment_size(8192));
```
The WebSocket protocol defines a procedure and control message for initiating
a close of the session. Handling of close initiated by the remote end of the
connection is performed automatically. To manually initiate a close, use
`wsproto::socket::close`:
```
ws.close();
```
[note To receive the `wsproto::error::closed` error, a read operation
is required. ]
[endsect]
[section:buffers Buffers]
Because calls to read data may return a variable amount of bytes, the
interface to calls that read data require an object that meets the requirements
of `Streambuf`. This concept is modeled on `boost::asio::basic_streambuf`.
The implementation does not perform queueing or buffering of messages. If
desired, these features should be provided by callers. The impact of this
design is that library users are in full control of the allocation strategy
used to store data and the back-pressure applied on the read and write side
of the underlying TCP/IP connection.
[endsect]
[section:async Asynchronous interface]
Asynchronous versions are available for all functions:
```
wsproto::opcode op;
ws.async_read(op, sb,
[](boost::system::error_code const& ec)
{
...
});
```
Calls to asynchronous initiation functions support the extensible asynchronous
model developed by the Boost.Asio author, allowing for traditional completion
handlers, stackful or stackless coroutines, and even futures:
```
void echo(wsproto::socket<ip::tcp::socket>& ws,
boost::asio::yield_context yield)
{
ws.async_read(sb, yield);
std::future<wsproto::error_code> fut =
ws.async_write, sb.data(), boost::use_future);
...
}
```
[endsect]
[section:io_service io_service]
The creation and operation of the `boost::asio::io_service` associated with
the underlying stream is left to the callers, permitting any implementation
strategy including one that does not require threads for environments where
threads are unavailable. Beast.WSProto itself does not use or require threads.
[endsect]
[section:safety Thread Safety]
Like a regular asio socket, a `wsproto::socket` is not thread safe. Callers
are responsible for synchronizing operations on the socket using an implicit
or explicit strand, as per the Asio documentation. The asynchronous interface
supports one active read and one active write simultaneously. Undefined
behavior results if two or more reads or two or more writes are attempted
concurrently. Caller initiated WebSocket ping, pong, and close operations
each count as an active write.
The implementation uses composed asynchronous operations internally; a high
level read can cause both reads and writes to take place on the underlying
stream. This behavior is transparent to callers.
[endsect]
[endsect]
[include quickref.xml]