]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | [/ |
2 | Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com) | |
3 | ||
4 | Distributed under the Boost Software License, Version 1.0. (See accompanying | |
5 | file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) | |
6 | ] | |
7 | ||
8 | [/ | |
9 | ideas: | |
10 | - complete send request walkthrough (client) | |
11 | - complete receive response walkthrough (client) | |
12 | - complete receive request walkthrough (server) | |
13 | - complete send response walkthrough (server) | |
14 | ||
15 | - Introduce concepts from simple to complex | |
16 | - Smooth progression of new ideas building on the previous ideas | |
17 | ||
18 | - do we show a simplified message with collapsed fields? | |
19 | - do we introduce `header` or `message` first? | |
20 | ||
21 | ||
22 | contents: | |
23 | Message (and header, fields) | |
24 | Create request | |
25 | Create response | |
26 | Algorithms | |
27 | Write | |
28 | Read | |
29 | Examples | |
30 | Send Request | |
31 | Receive Response | |
32 | Receive Request | |
33 | Send Response | |
34 | Advanced | |
35 | Responding to HEAD | |
36 | Expect: 100-continue | |
37 | Body (user defined) | |
38 | ||
39 | ||
40 | section beast.http.examples Examples | |
41 | ||
42 | note | |
43 | In the example code which follows, `socket` refers to an object of type | |
44 | `boost::asio::ip::tcp::socket` which is currently connected to a remote peer. | |
45 | ] | |
46 | ||
47 | ||
48 | ||
49 | [section:http Using HTTP] | |
50 | ||
51 | [block ''' | |
52 | <informaltable frame="all"><tgroup cols="1"><colspec colname="a"/><tbody><row><entry valign="top"><simplelist> | |
53 | <member><link linkend="beast.http.message">Message</link></member> | |
54 | <member><link linkend="beast.http.fields">Fields</link></member> | |
55 | <member><link linkend="beast.http.body">Body</link></member> | |
56 | <member><link linkend="beast.http.algorithms">Algorithms</link></member> | |
57 | </simplelist></entry></row></tbody></tgroup></informaltable> | |
58 | '''] | |
59 | ||
60 | Beast offers programmers simple and performant models of HTTP messages and | |
61 | their associated operations including synchronous and asynchronous reading and | |
62 | writing of messages and headers in the HTTP/1 wire format using Boost.Asio. | |
63 | ||
64 | [note | |
65 | The following documentation assumes familiarity with both Boost.Asio | |
66 | and the HTTP protocol specification described in __rfc7230__. Sample code | |
67 | and identifiers mentioned in this section are written as if the following | |
68 | declarations are in effect: | |
69 | ``` | |
70 | #include <beast/core.hpp> | |
71 | #include <beast/http.hpp> | |
72 | using namespace beast; | |
73 | using namespace beast::http; | |
74 | ``` | |
75 | ] | |
76 | ||
77 | ||
78 | ||
79 | ||
80 | ||
81 | [section:message Message] | |
82 | ||
83 | The HTTP protocol defines the client and server roles: clients send messages | |
84 | called requests and servers send back messages called responses. A HTTP message | |
85 | (referred to hereafter as "message") contains request or response specific | |
86 | attributes (contained in the "Start Line"), a series of zero or more name/value | |
87 | pairs (collectively termed "Fields"), and an optional series of octets called | |
88 | the message body which may be zero in length. The start line for a HTTP request | |
89 | includes a string called the method, a string called the URL, and a version | |
90 | number indicating HTTP/1.0 or HTTP/1.1. For a response, the start line contains | |
91 | an integer status code and a string called the reason phrase. Alternatively, a | |
92 | HTTP message can be viewed as two parts: a header, followed by a body. | |
93 | ||
94 | [note | |
95 | The Reason-Phrase is obsolete as of rfc7230. | |
96 | ] | |
97 | ||
98 | The __header__ class template models the header for HTTP/1 and HTTP/2 messages. | |
99 | This class template is a family of specializations, one for requests and one | |
100 | for responses, depending on the [*`isRequest`] template value. | |
101 | The [*`Fields`] template type determines the type of associative container | |
102 | used to store the field values. The provided __basic_fields__ class template | |
103 | and __fields__ type alias are typical choices for the [*`Fields`] type, but | |
104 | advanced applications may supply user defined types which meet the requirements. | |
105 | The __message__ class template models the header and optional body for HTTP/1 | |
106 | and HTTP/2 requests and responses. It is derived from the __header__ class | |
107 | template with the same shared template parameters, and adds the `body` data | |
108 | member. The message class template requires an additional template argument | |
109 | type [*`Body`]. This type controls the container used to represent the body, | |
110 | if any, as well as the algorithms needed to serialize and parse bodies of | |
111 | that type. | |
112 | ||
113 | This illustration shows the declarations and members of the __header__ and | |
114 | __message__ class templates, as well as the inheritance relationship: | |
115 | ||
116 | [$images/message.png [width 650px] [height 390px]] | |
117 | ||
118 | For notational convenience, these template type aliases are provided which | |
119 | supply typical choices for the [*`Fields`] type: | |
120 | ``` | |
121 | using request_header = header<true, fields>; | |
122 | using response_header = header<false, fields>; | |
123 | ||
124 | template<class Body, class Fields = fields> | |
125 | using request = message<true, Body, Fields>; | |
126 | ||
127 | template<class Body, class Fields = fields> | |
128 | using response = message<false, Body, Fields>; | |
129 | ``` | |
130 | ||
131 | The code examples below show how to create and fill in a request and response | |
132 | object: | |
133 | ||
134 | [table Create Message | |
135 | [[HTTP Request] [HTTP Response]] | |
136 | [[ | |
137 | ``` | |
138 | request<string_body> req; | |
139 | req.version = 11; // HTTP/1.1 | |
140 | req.method = "GET"; | |
141 | req.url = "/index.htm" | |
142 | req.fields.insert("Accept", "text/html"); | |
143 | req.fields.insert("Connection", "keep-alive"); | |
144 | req.fields.insert("User-Agent", "Beast"); | |
145 | ``` | |
146 | ][ | |
147 | ``` | |
148 | response<string_body> res; | |
149 | res.version = 11; // HTTP/1.1 | |
150 | res.status = 200; | |
151 | res.reason = "OK"; | |
152 | res.fields.insert("Sever", "Beast"); | |
153 | res.fields.insert("Content-Length", 4); | |
154 | res.body = "****"; | |
155 | ``` | |
156 | ]]] | |
157 | ||
158 | In the serialized format of a HTTP message, the header is represented as a | |
159 | series of text lines ending in CRLF (`"\r\n"`). The end of the header is | |
160 | indicated by a line containing only CRLF. Here are examples of serialized HTTP | |
161 | request and response objects. The objects created above will produce these | |
162 | results when serialized. Note that only the response has a body: | |
163 | ||
164 | [table Serialized HTTP Request and Response | |
165 | [[HTTP Request] [HTTP Response]] | |
166 | [[ | |
167 | ``` | |
168 | GET /index.htm HTTP/1.1\r\n | |
169 | Accept: text/html\r\n | |
170 | Connection: keep-alive\r\n | |
171 | User-Agent: Beast\r\n | |
172 | \r\n | |
173 | ``` | |
174 | ][ | |
175 | ``` | |
176 | 200 OK HTTP/1.1\r\n | |
177 | Server: Beast\r\n | |
178 | Content-Length: 4\r\n | |
179 | \r\n | |
180 | **** | |
181 | ``` | |
182 | ]]] | |
183 | ||
184 | ||
185 | ||
186 | ||
187 | [endsect] | |
188 | ||
189 | ||
190 | ||
191 | ||
192 | [section:fields Fields] | |
193 | ||
194 | The [*`Fields`] type represents a container that can set or retrieve the | |
195 | fields in a message. Beast provides the | |
196 | [link beast.ref.http__basic_fields `basic_fields`] class which serves | |
197 | the needs for most users. It supports modification and inspection of values. | |
198 | The field names are not case-sensitive. | |
199 | ||
200 | These statements change the values of the headers in the message passed: | |
201 | ``` | |
202 | template<class Body> | |
203 | void set_fields(request<Body>& req) | |
204 | { | |
205 | if(! req.exists("User-Agent")) | |
206 | req.insert("User-Agent", "myWebClient"); | |
207 | ||
208 | if(req.exists("Accept-Charset")) | |
209 | req.erase("Accept-Charset"); | |
210 | ||
211 | req.replace("Accept", "text/plain"); | |
212 | } | |
213 | ``` | |
214 | ||
215 | User defined [*`Fields`] types are possible. To support serialization, the | |
216 | type must meet the requirements of __FieldSequence__. To support parsing using | |
217 | the provided parser, the type must provide the `insert` member function. | |
218 | ||
219 | [endsect] | |
220 | ||
221 | ||
222 | ||
223 | [section:body Body] | |
224 | ||
225 | The message [*`Body`] template parameter controls both the type of the data | |
226 | member of the resulting message object, and the algorithms used during parsing | |
227 | and serialization. Beast provides three very common [*`Body`] types: | |
228 | ||
229 | * [link beast.ref.http__string_body [*`string_body`:]] A body with a | |
230 | `value_type` as `std::string`. Useful for quickly putting together a request | |
231 | or response with simple text in the message body (such as an error message). | |
232 | Has the same insertion complexity of `std::string`. This is the type of body | |
233 | used in the examples: | |
234 | ``` | |
235 | response<string_body> res; | |
236 | static_assert(std::is_same<decltype(res.body), std::string>::value); | |
237 | res.body = "Here is the data you requested"; | |
238 | ``` | |
239 | ||
240 | * [link beast.ref.http__streambuf_body [*`streambuf_body`:]] A body with a | |
241 | `value_type` of [link beast.ref.streambuf `streambuf`]: an efficient storage | |
242 | object which uses multiple octet arrays of varying lengths to represent data. | |
243 | ||
244 | [heading Advanced] | |
245 | ||
246 | User-defined types are possible for the message body, where the type meets the | |
247 | [link beast.ref.Body [*`Body`]] requirements. This simplified class declaration | |
248 | shows the customization points available to user-defined body types: | |
249 | ||
250 | [$images/body.png [width 510px] [height 210px]] | |
251 | ||
252 | * [*`value_type`]: Determines the type of the | |
253 | [link beast.ref.http__message.body `message::body`] member. If this | |
254 | type defines default construction, move, copy, or swap, then message objects | |
255 | declared with this [*`Body`] will have those operations defined. | |
256 | ||
257 | * [*`reader`]: An optional nested type meeting the requirements of | |
258 | [link beast.ref.Reader [*`Reader`]]. If present, this defines the algorithm | |
259 | used for parsing bodies of this type. | |
260 | ||
261 | * [*`writer`]: An optional nested type meeting the requirements of | |
262 | [link beast.ref.Writer [*`Writer`]]. If present, this defines the algorithm | |
263 | used for serializing bodies of this type. | |
264 | ||
265 | The examples included with this library provide a Body implementation that | |
266 | serializing message bodies that come from a file. | |
267 | ||
268 | [endsect] | |
269 | ||
270 | ||
271 | ||
272 | [section:algorithms Algorithms] | |
273 | ||
274 | Algorithms are provided to serialize and deserialize HTTP/1 messages on | |
275 | streams. | |
276 | ||
277 | * [link beast.ref.http__read [*read]]: Deserialize a HTTP/1 __header__ or __message__ from a stream. | |
278 | * [link beast.ref.http__write [*write]]: Serialize a HTTP/1 __header__ or __message__ to a stream. | |
279 | ||
280 | Asynchronous versions of these algorithms are also available: | |
281 | ||
282 | * [link beast.ref.http__async_read [*async_read]]: Deserialize a HTTP/1 __header__ or __message__ asynchronously from a stream. | |
283 | * [link beast.ref.http__async_write [*async_write]]: Serialize a HTTP/1 __header__ or __message__ asynchronously to a stream. | |
284 | ||
285 | [heading Using Sockets] | |
286 | ||
287 | The free function algorithms are modeled after Boost.Asio to send and receive | |
288 | messages on TCP/IP sockets, SSL streams, or any object which meets the | |
289 | Boost.Asio type requirements (__SyncReadStream__, __SyncWriteStream__, | |
290 | __AsyncReadStream__, and __AsyncWriteStream__ depending on the types of | |
291 | operations performed). To send messages synchronously, use one of the | |
292 | [link beast.ref.http__write `write`] functions: | |
293 | ``` | |
294 | void send_request(boost::asio::ip::tcp::socket& sock) | |
295 | { | |
296 | request<string_body> req; | |
297 | req.version = 11; | |
298 | req.method = "GET"; | |
299 | req.url = "/index.html"; | |
300 | ... | |
301 | write(sock, req); // Throws exception on error | |
302 | ... | |
303 | // Alternatively | |
304 | boost::system::error:code ec; | |
305 | write(sock, req, ec); | |
306 | if(ec) | |
307 | std::cerr << "error writing http message: " << ec.message(); | |
308 | } | |
309 | ``` | |
310 | ||
311 | An asynchronous interface is available: | |
312 | ``` | |
313 | void handle_write(boost::system::error_code); | |
314 | ... | |
315 | request<string_body> req; | |
316 | ... | |
317 | async_write(sock, req, std::bind(&handle_write, std::placeholders::_1)); | |
318 | ``` | |
319 | ||
320 | When the implementation reads messages from a socket, it can read bytes lying | |
321 | after the end of the message if they are present (the alternative is to read | |
322 | a single byte at a time which is unsuitable for performance reasons). To | |
323 | store and re-use these extra bytes on subsequent messages, the read interface | |
324 | requires an additional parameter: a [link beast.ref.DynamicBuffer [*`DynamicBuffer`]] | |
325 | object. This example reads a message from the socket, with the extra bytes | |
326 | stored in the streambuf parameter for use in a subsequent call to read: | |
327 | ``` | |
328 | boost::asio::streambuf sb; | |
329 | ... | |
330 | response<string_body> res; | |
331 | read(sock, sb, res); // Throws exception on error | |
332 | ... | |
333 | // Alternatively | |
334 | boost::system::error:code ec; | |
335 | read(sock, sb, res, ec); | |
336 | if(ec) | |
337 | std::cerr << "error reading http message: " << ec.message(); | |
338 | ``` | |
339 | ||
340 | As with the write function, an asynchronous interface is available. The | |
341 | stream buffer parameter must remain valid until the completion handler is | |
342 | called: | |
343 | ``` | |
344 | void handle_read(boost::system::error_code); | |
345 | ... | |
346 | boost::asio::streambuf sb; | |
347 | response<string_body> res; | |
348 | ... | |
349 | async_read(sock, res, std::bind(&handle_read, std::placeholders::_1)); | |
350 | ``` | |
351 | ||
352 | An alternative to using a `boost::asio::streambuf` is to use a | |
353 | __streambuf__, which meets the requirements of __DynamicBuffer__ and | |
354 | is optimized for performance: | |
355 | ``` | |
356 | void handle_read(boost::system::error_code); | |
357 | ... | |
358 | beast::streambuf sb; | |
359 | response<string_body> res; | |
360 | read(sock, sb, res); | |
361 | ``` | |
362 | ||
363 | The `read` implementation can use any object meeting the requirements of | |
364 | __DynamicBuffer__, allowing callers to define custom | |
365 | memory management strategies used by the implementation. | |
366 | ||
367 | [endsect] | |
368 | ||
369 | ||
370 | ||
371 | [endsect] |