Files
rippled/doc/http.qbk
2016-04-20 12:01:26 -04:00

213 lines
7.4 KiB
Plaintext

[/
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 <boost/asio.hpp>
#include <beast/http.hpp>
using namespace beast;
using namespace boost::asio;
```
Create a HTTP request:
```
http::request<http::empty_body> req({http::method_t::http_get, "/", 11});
req.headers.insert("Host", "127.0.0.1:80");
req.headers.insert("User-Agent", "Beast.HTTP");
```
When sending a message, the Content-Length and Transfer-Encoding are set
automatically based on the properties of the body. Depending on the HTTP
version of the message and properties of the message body, the implementation
will automaticaly chunk-encode the data sent on the wire:
```
ip::tcp::socket sock(ios);
...
http::response<http::string_body> resp({200, "OK", 11});
resp.headers.insert("Server", "Beast.HTTP");
resp.body = "The command was successful";
write(sock, resp);
}
```
Receiving a message is simple, declare a value of type message and call `read`.
This example reads a message, builds a response, and sends it.
```
void handle_connection(ip::tcp::socket& sock)
{
request<string_body> req;
read(sock, req);
response<string_body> resp;
...
write(sock, resp);
}
```
[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]