The following video presentation was delivered at [@https://cppcon.org/ CppCon] in 2017. The presentation provides a simplified explanation of the design process for the HTTP message container used in Beast. The slides and code used are available in the [@https://github.com/vinniefalco/CppCon2017 GitHub repository].
In this section we describe the problem of modeling HTTP messages and explain how the library arrived at its solution, with a discussion of the benefits and drawbacks of the design choices. The goal for creating a message model is to create a container with value semantics, possibly movable and/or copyable, that contains all the information needed to serialize, or all of the information captured during parsing. More formally, given:
We would also like our message container to have customization points permitting the following: allocator awareness, user-defined containers to represent header fields, and user-defined types and algorithms to represent the body. And finally, because requests and responses have different fields in the ['start-line], we would like the containers for requests and responses to be represented by different types for function overloading.
These containers are capable of representing everything in the model of HTTP requests and responses described in __rfc7230__. Request and response objects are different types. The user can choose the container used to represent the fields. And the user can choose the [*Body] type, which is a concept defining not only the type of `body` member but also the algorithms used to transfer information in and out of that member when performing serialization and parsing.
However, a problem arises. How do we write a function which can accept an object that is either a request or a response? As written, the only obvious solution is to make the message a template type. Additional traits classes would then be needed to make sure that the passed object has a valid type which meets the requirements. These unnecessary complexities are bypassed by making each container a partial specialization: ``` /// An HTTP message template<bool isRequest, class Fields, class Body> struct message;
Now we can declare a function which takes any message as a parameter: ``` template<bool isRequest, class Fields, class Body> void f(message<isRequest, Fields, Body>& msg); ```
This function can manipulate the fields common to requests and responses. If it needs to access the other fields, it can use overloads with partial specialization, or in C++17 a `constexpr` expression: ``` template<bool isRequest, class Fields, class Body> void f(message<isRequest, Fields, Body>& msg) {