Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file modified doc/modules/ROOT/images/ClassHierarchy.odg
Binary file not shown.
2 changes: 1 addition & 1 deletion doc/modules/ROOT/images/ClassHierarchy.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
10 changes: 2 additions & 8 deletions doc/modules/ROOT/nav.adoc
Original file line number Diff line number Diff line change
@@ -1,20 +1,14 @@
* xref:1.primer.adoc[]
* xref:2.messages.adoc[]
* xref:sans_io_philosophy.adoc[]

* xref:http_protocol_basics.adoc[]

* xref:header_containers.adoc[]

* xref:message_bodies.adoc[]

* Serializing

* Parsing

* xref:Message.adoc[]

* Design Requirements
** xref:design_requirements/serializer.adoc[Serializer]
** xref:design_requirements/parser.adoc[Parser]

// * xref:reference:boost/http_proto.adoc[Reference]
* xref:reference.adoc[Reference]
115 changes: 115 additions & 0 deletions doc/modules/ROOT/pages/1.primer.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
//
// Copyright (c) 2025 Vinnie Falco (vinnie.falco@gmail.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)
//
// Official repository: https://github.com/cppalliance/buffers
//

= HTTP Primer

HTTP is a stream-oriented protocol between two connected programs: one acting
as the client, the other as the server. While the connection is open, the client
sends an HTTP request, which the server reads and answers with an HTTP response.
These _messages_ are paired in order; each request has exactly one
corresponding response. This exchange of structured messages continues until
either peer closes the connection, whether normally or due to an error.

HTTP messages consist of three parts: the start line, the headers, and the
message body. The start line differs between requests and responses, while
the headers and body share the same structure. Headers are made up of zero
or more fields, each expressed as a name–value pair. Both the start line and
the header fields use a line-oriented text format, with each line terminated
by a CRLF sequence (carriage return followed by line feed, i.e. bytes
`0x0D 0x0A`). The message body is a sequence of bytes of defined length,
with content determined by the semantics of the start line and headers.

This diagram shows an actual HTTP request and HTTP response

[cols="1a,1a"]
|===
|HTTP Request|HTTP Response

|
[source]
----
GET /index.html HTTP/1.1\r\n
User-Agent: Boost\r\n
\r\n
----
|
[source]
----
HTTP/1.1 200 OK\r\n
Server: Boost.Http.Proto\r\n
Content-Length: 13\r\n
\r\n
Hello, world!
----

|===

More formally, the ABNF for HTTP messages is defined as follows:

[cols="1a,4a"]
|===
|Name|ABNF

|message
|[literal]
HTTP-message = request-line / status-line
*( header-field CRLF )
CRLF
[ message-body ]

|request-line
|[literal]
request-line = method SP request-target SP HTTP-version CRLF

|status-line
|[literal]
status-line = HTTP-version SP status-code SP reason-phrase CRLF

|===


Most HTTP header field values are domain-specific or application-defined, while
certain fields commonly recur. The library understands these fields and takes
appropriate action to ensure RFC compliance:

[cols="1a,4a"]
|===
|Field|Description

a|
https://tools.ietf.org/html/rfc7230#section-6.1[*Connection*] +
https://tools.ietf.org/html/rfc7230#appendix-A.1.2[*Proxy-Connection*]

|This field lets the sender specify control options for the current connection.
Typical values include close, keep-alive, and upgrade.

|https://tools.ietf.org/html/rfc7230#section-3.3.2[*Content-Length*]
|When present, this field tells the recipient the exact size of the message
body, measured in bytes, that follows the header.

|https://tools.ietf.org/html/rfc7230#section-3.3.1[*Transfer-Encoding*]
|This optional field specifies the sequence of transfer codings that have been,
or will be, applied to the content payload to produce the message body.

The library supports the
chunked,
gzip,
deflate, and
brotli
encoding schemes,
in any valid combination. Encodings can be automatically applied or removed
as needed by the caller.

|https://tools.ietf.org/html/rfc7230#section-6.7[*Upgrade*]
|The Upgrade header field provides a mechanism to transition from HTTP/1.1 to
another protocol on the same connection. For example, it is the mechanism used
by WebSocket's initial HTTP handshake to establish a WebSocket connection.

|===

134 changes: 134 additions & 0 deletions doc/modules/ROOT/pages/2.messages.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
//
// Copyright (c) 2023 Vinnie Falco (vinnie.falco@gmail.com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt)
//
// Official repository: https://github.com/cppalliance/http_proto
//

= Messages

The library provides both modifiable containers and immutable views for
requests, responses, and standalone field sets such as trailers. These can
be used to store incoming messages or construct outgoing ones. Unlike other
libraries, such as its predecessor Boost.Beast, the message body is kept
separate. In other words, the containers and views offered by this library
do not include the body.

NOTE: By omitting the body from its container and view types, the library avoids
the need for templates—unlike the message container in Boost.Beast. Experience
has shown that templated containers create poor ergonomics, a design flaw this
library corrects.

The following table lists the types used to model containers and views:

[cols="1a,4a"]
|===
|Type|Description

|cpp:fields[]
|A modifiable container of header fields.

|cpp:fields_view[]
|A read-only view to a cpp:fields[]

|cpp:message[]
|A modifiable container holding a start-line and header fields, with
accompanying metadata.

|cpp:message_view[]
|A read-only view to a cpp:message[]

|cpp:request[]
|A modifiable container holding a request-line and header fields, with
accompanying metadata.

|cpp:request_view[]
|A read-only view to a cpp:request[]

|cpp:response[]
|A modifiable container holding a status-line and header fields, with
accompanying metadata.

|cpp:response_view[]
|A read-only view to a cpp:response[]

|===

== Construction

All containers maintain the following invariants:

* The container’s contents are always stored in serialized form that is
syntactically valid.

* Any modification that would produce a malformed field or start line
throws an exception, with strong exception safety guaranteed.

To satisfy these invariants, default-constructed containers
initially consist of a start line:

[source,cpp]
----
request req;
response res;

assert(req->buffer() == "GET / HTTP/1.1\r\n\r\n");
assert(res->buffer() == "HTTP/1.1 200 OK\r\n\r\n");
----

The `buffer` function runs in constant time, never throws exceptions,
and returns a cpp:boost::core::string_view[] representing the complete
serialized object.

Each header field consists of a name and a value, both stored as strings,
with prescribed ABNF format:

[source]
----
field-name = token
field-value = *( field-content / obs-fold )
field-content = field-vchar [ 1*( SP / HTAB ) field-vchar ]
field-vchar = VCHAR / obs-text

obs-fold = CRLF 1*( SP / HTAB )
; obsolete line folding
----

Operations that create or modify fields throw an exception if the name or
value violates the syntactic requirements of the protocol.

Although fields may be identified by comparing their names, the library
provides the field enumeration, which defines a wide set of constants for
well-known field names. Internally, containers maintain a lookup table so
that specifying fields by enumeration replaces costly string comparisons
with efficient integer comparisons.

The following example builds an
https://tools.ietf.org/html/rfc7231#section-4.3.1[HTTP GET]
request:

[cols="1a,1a"]
|===
|Code|Serialized Result

|
[source,cpp]
----
request req( method::get, "/index.htm", version::http_1_1 );
req.append( field::accept, "text/html" );
req.append( "User-Agent", "Boost" );
----
|
[literal]
GET /index.htm HTTP/1.1\r\n
Accept: text/html\r\n
User-Agent: Boost\r\n
\r\n

|===

NOTE: Field-specific syntax (e.g., for date values) is not fully validated by
this library. It is the application’s responsibility to follow the relevant
specifications to ensure correct behavior.
45 changes: 45 additions & 0 deletions doc/modules/ROOT/pages/design_requirements/parser.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,51 @@

= Parser Design Requirements

== Design

=== Comparison to Boost.Beast

This library builds on the experiences learned from Boost.Beast's seven years
of success. Beast brings these unique design strengths:

* Body type named requirements
* First-class message container
* Individual parser and serializer objects

The message container suffers from these problems:

* Templated on the body type.
* Templated on Allocator
* Node-based implementation
* Serialization is too costly

Meanwhile parsers and serializes suffer from these problems:

* Buffer-at-a-time operation is clumsy.
* Objects are not easily re-used
* Parser is a class template because of body types

==== Message Container

In HTTP.Proto the message container implementation always stores the complete
message or fields in its correctly serialized form. Insertions and modifications
are performed in linear time. When the container is reused, the amortized cost
of reallocation becomes zero. A small lookup table is stored past the end of
the serialized message, permitting iteration in constant time.

==== Parser

The HTTP.Proto parser is designed to persist for the lifetime of the connection
or application. It allocates a fixed size memory buffer upon construction and
uses this memory region to perform type-erasure and apply or remove content
encodings to the body. The parser is a regular class instead of a class
template, which greatly improves its ease of use over the Beast parser design.

==== Serializer

As with the parser, the serializer is designed to persist for the lifetime of
the connection or application and also allocates a fixed size buffer.

== Memory Allocation and Memory Utilization

The `parser` must use a single block of memory allocated during construction and
Expand Down
1 change: 0 additions & 1 deletion doc/modules/ROOT/pages/header_containers.adoc

This file was deleted.

Loading
Loading