1 //
2 // Copyright (c) 2016-2019 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 // Official repository: https://github.com/boostorg/beast
8 //
9
10 #include <boost/beast/core.hpp>
11 #include <boost/asio.hpp>
12 #include <boost/config.hpp>
13 #include <iostream>
14 #include <thread>
15
16 using namespace boost::beast;
17
18 //[http_snippet_1
19
20 #include <boost/beast/http.hpp>
21 using namespace boost::beast::http;
22
23 //]
24
25 namespace doc_http_snippets {
26
27 //[http_snippet_17
28 // This function returns the buffer containing the next chunk body
29 net::const_buffer get_next_chunk_body();
30 //]
31
get_next_chunk_body()32 net::const_buffer get_next_chunk_body()
33 {
34 return {nullptr, 0};
35 }
36
fxx()37 void fxx() {
38
39 net::io_context ioc;
40 net::any_io_executor work =
41 net::require(
42 ioc.get_executor(),
43 net::execution::outstanding_work.tracked);
44 std::thread t{[&](){ ioc.run(); }};
45 net::ip::tcp::socket sock{ioc};
46
47 {
48 //[http_snippet_2
49
50 request<empty_body> req;
51 req.version(11); // HTTP/1.1
52 req.method(verb::get);
53 req.target("/index.htm");
54 req.set(field::accept, "text/html");
55 req.set(field::user_agent, "Beast");
56
57 //]
58 }
59
60 {
61 //[http_snippet_3
62
63 response<string_body> res;
64 res.version(11); // HTTP/1.1
65 res.result(status::ok);
66 res.set(field::server, "Beast");
67 res.body() = "Hello, world!";
68 res.prepare_payload();
69
70 //]
71 }
72
73 {
74 //[http_snippet_4
75
76 flat_buffer buffer; // (The parser is optimized for flat buffers)
77 request<string_body> req;
78 read(sock, buffer, req);
79
80 //]
81 }
82
83 {
84 //[http_snippet_5
85
86 flat_buffer buffer;
87 response<string_body> res;
88 async_read(sock, buffer, res,
89 [&](error_code ec, std::size_t bytes_transferred)
90 {
91 boost::ignore_unused(bytes_transferred);
92 std::cerr << ec.message() << std::endl;
93 });
94
95 //]
96 }
97
98 {
99 //[http_snippet_6
100
101 // This buffer's max size is too small for much of anything
102 flat_buffer buffer{10};
103
104 // Try to read a request
105 error_code ec;
106 request<string_body> req;
107 read(sock, buffer, req, ec);
108 if(ec == http::error::buffer_overflow)
109 std::cerr << "Buffer limit exceeded!" << std::endl;
110
111 //]
112 }
113
114 {
115 //[http_snippet_7
116
117 response<string_body> res;
118 res.version(11);
119 res.result(status::ok);
120 res.set(field::server, "Beast");
121 res.body() = "Hello, world!";
122 res.prepare_payload();
123
124 error_code ec;
125 write(sock, res, ec);
126 //]
127
128 //[http_snippet_8
129 async_write(sock, res,
130 [&](error_code ec, std::size_t bytes_transferred)
131 {
132 boost::ignore_unused(bytes_transferred);
133 if(ec)
134 std::cerr << ec.message() << std::endl;
135 });
136 //]
137 }
138
139 {
140 //[http_snippet_10
141
142 response<string_body> res;
143
144 response_serializer<string_body> sr{res};
145
146 //]
147 }
148
149 {
150 //[http_snippet_18
151 // Prepare an HTTP/1.1 response with a chunked body
152 response<empty_body> res{status::ok, 11};
153 res.set(field::server, "Beast");
154
155 // Set Transfer-Encoding to "chunked".
156 // If a Content-Length was present, it is removed.
157 res.chunked(true);
158
159 // Set up the serializer
160 response_serializer<empty_body> sr{res};
161
162 // Write the header first
163 write_header(sock, sr);
164
165 // Now manually emit three chunks:
166 net::write(sock, make_chunk(get_next_chunk_body()));
167 net::write(sock, make_chunk(get_next_chunk_body()));
168 net::write(sock, make_chunk(get_next_chunk_body()));
169
170 // We are responsible for sending the last chunk:
171 net::write(sock, make_chunk_last());
172 //]
173 }
174
175 {
176 //[http_snippet_19
177 // Prepare a set of chunk extension to emit with the body
178 chunk_extensions ext;
179 ext.insert("mp3");
180 ext.insert("title", "Beale Street Blues");
181 ext.insert("artist", "W.C. Handy");
182
183 // Write the next chunk with the chunk extensions
184 // The implementation will make a copy of the extensions object,
185 // so the caller does not need to manage lifetime issues.
186 net::write(sock, make_chunk(get_next_chunk_body(), ext));
187
188 // Write the next chunk with the chunk extensions
189 // The implementation will make a copy of the extensions object, storing the copy
190 // using the custom allocator, so the caller does not need to manage lifetime issues.
191 net::write(sock, make_chunk(get_next_chunk_body(), ext, std::allocator<char>{}));
192
193 // Write the next chunk with the chunk extensions
194 // The implementation allocates memory using the default allocator and takes ownership
195 // of the extensions object, so the caller does not need to manage lifetime issues.
196 // Note: ext is moved
197 net::write(sock, make_chunk(get_next_chunk_body(), std::move(ext)));
198 //]
199 }
200
201 {
202 //[http_snippet_20
203 // Manually specify the chunk extensions.
204 // Some of the strings contain spaces and a period and must be quoted
205 net::write(sock, make_chunk(get_next_chunk_body(),
206 ";mp3"
207 ";title=\"Danny Boy\""
208 ";artist=\"Fred E. Weatherly\""
209 ));
210 //]
211 }
212
213 {
214 //[http_snippet_21
215 // Prepare a chunked HTTP/1.1 response with some trailer fields
216 response<empty_body> res{status::ok, 11};
217 res.set(field::server, "Beast");
218
219 // Inform the client of the trailer fields we will send
220 res.set(field::trailer, "Content-MD5, Expires");
221
222 res.chunked(true);
223
224 // Serialize the header and two chunks
225 response_serializer<empty_body> sr{res};
226 write_header(sock, sr);
227 net::write(sock, make_chunk(get_next_chunk_body()));
228 net::write(sock, make_chunk(get_next_chunk_body()));
229
230 // Prepare the trailer
231 fields trailer;
232 trailer.set(field::content_md5, "f4a5c16584f03d90");
233 trailer.set(field::expires, "never");
234
235 // Emit the trailer in the last chunk.
236 // The implementation will use the default allocator to create the storage for holding
237 // the serialized fields.
238 net::write(sock, make_chunk_last(trailer));
239 //]
240 }
241
242 {
243 //[http_snippet_22
244 // Use a custom allocator for serializing the last chunk
245 fields trailer;
246 trailer.set(field::approved, "yes");
247 net::write(sock, make_chunk_last(trailer, std::allocator<char>{}));
248 //]
249 }
250
251 {
252 //[http_snippet_23
253 // Manually emit a trailer.
254 // We are responsible for ensuring that the trailer format adheres to the specification.
255 string_view ext =
256 "Content-MD5: f4a5c16584f03d90\r\n"
257 "Expires: never\r\n"
258 "\r\n";
259 net::write(sock, make_chunk_last(net::const_buffer{ext.data(), ext.size()}));
260 //]
261 }
262
263 {
264 //[http_snippet_24
265 // Prepare a chunked HTTP/1.1 response and send the header
266 response<empty_body> res{status::ok, 11};
267 res.set(field::server, "Beast");
268 res.chunked(true);
269 response_serializer<empty_body> sr{res};
270 write_header(sock, sr);
271
272 // Obtain three body buffers up front
273 auto const cb1 = get_next_chunk_body();
274 auto const cb2 = get_next_chunk_body();
275 auto const cb3 = get_next_chunk_body();
276
277 // Manually emit a chunk by first writing the chunk-size header with the correct size
278 net::write(sock, chunk_header{
279 buffer_bytes(cb1) +
280 buffer_bytes(cb2) +
281 buffer_bytes(cb3)});
282
283 // And then output the chunk body in three pieces ("chunk the chunk")
284 net::write(sock, cb1);
285 net::write(sock, cb2);
286 net::write(sock, cb3);
287
288 // When we go this deep, we are also responsible for the terminating CRLF
289 net::write(sock, chunk_crlf{});
290 //]
291 }
292
293 } // fxx()
294
295
296
297 //[http_snippet_12
298
299 /** Send a message to a stream synchronously.
300
301 @param stream The stream to write to. This type must support
302 the <em>SyncWriteStream</em> concept.
303
304 @param m The message to send. The Body type must support
305 the <em>BodyWriter</em> concept.
306 */
307 template<
308 class SyncWriteStream,
309 bool isRequest, class Body, class Fields>
310 void
send(SyncWriteStream & stream,message<isRequest,Body,Fields> const & m)311 send(
312 SyncWriteStream& stream,
313 message<isRequest, Body, Fields> const& m)
314 {
315 // Check the template types
316 static_assert(is_sync_write_stream<SyncWriteStream>::value,
317 "SyncWriteStream type requirements not met");
318 static_assert(is_body_writer<Body>::value,
319 "BodyWriter type requirements not met");
320
321 // Create the instance of serializer for the message
322 serializer<isRequest, Body, Fields> sr{m};
323
324 // Loop until the serializer is finished
325 do
326 {
327 // This call guarantees it will make some
328 // forward progress, or otherwise return an error.
329 write_some(stream, sr);
330 }
331 while(! sr.is_done());
332 }
333
334 //]
335
336 //[http_snippet_13
337
338 template<class SyncReadStream>
339 void
print_response(SyncReadStream & stream)340 print_response(SyncReadStream& stream)
341 {
342 static_assert(is_sync_read_stream<SyncReadStream>::value,
343 "SyncReadStream type requirements not met");
344
345 // Declare a parser for an HTTP response
346 response_parser<string_body> parser;
347
348 // Read the entire message
349 read(stream, parser);
350
351 // Now print the message
352 std::cout << parser.get() << std::endl;
353 }
354
355 //]
356
357 #ifdef BOOST_MSVC
358 //[http_snippet_14
359
360 template<bool isRequest, class Body, class Fields>
361 void
print_cxx14(message<isRequest,Body,Fields> const & m)362 print_cxx14(message<isRequest, Body, Fields> const& m)
363 {
364 error_code ec;
365 serializer<isRequest, Body, Fields> sr{m};
366 do
367 {
368 sr.next(ec,
369 [&sr](error_code& ec, auto const& buffer)
370 {
371 ec = {};
372 std::cout << make_printable(buffer);
373 sr.consume(buffer_bytes(buffer));
374 });
375 }
376 while(! ec && ! sr.is_done());
377 if(! ec)
378 std::cout << std::endl;
379 else
380 std::cerr << ec.message() << std::endl;
381 }
382
383 //]
384 #endif
385
386 //[http_snippet_15
387
388 template<class Serializer>
389 struct lambda
390 {
391 Serializer& sr;
392
lambdadoc_http_snippets::lambda393 lambda(Serializer& sr_) : sr(sr_) {}
394
395 template<class ConstBufferSequence>
operator ()doc_http_snippets::lambda396 void operator()(error_code& ec, ConstBufferSequence const& buffer) const
397 {
398 ec = {};
399 std::cout << make_printable(buffer);
400 sr.consume(buffer_bytes(buffer));
401 }
402 };
403
404 template<bool isRequest, class Body, class Fields>
405 void
print(message<isRequest,Body,Fields> const & m)406 print(message<isRequest, Body, Fields> const& m)
407 {
408 error_code ec;
409 serializer<isRequest, Body, Fields> sr{m};
410 do
411 {
412 sr.next(ec, lambda<decltype(sr)>{sr});
413 }
414 while(! ec && ! sr.is_done());
415 if(! ec)
416 std::cout << std::endl;
417 else
418 std::cerr << ec.message() << std::endl;
419 }
420
421 //]
422
423 #ifdef BOOST_MSVC
424 //[http_snippet_16
425
426 template<bool isRequest, class Body, class Fields>
427 void
split_print_cxx14(message<isRequest,Body,Fields> const & m)428 split_print_cxx14(message<isRequest, Body, Fields> const& m)
429 {
430 error_code ec;
431 serializer<isRequest, Body, Fields> sr{m};
432 sr.split(true);
433 std::cout << "Header:" << std::endl;
434 do
435 {
436 sr.next(ec,
437 [&sr](error_code& ec, auto const& buffer)
438 {
439 ec = {};
440 std::cout << make_printable(buffer);
441 sr.consume(buffer_bytes(buffer));
442 });
443 }
444 while(! sr.is_header_done());
445 if(! ec && ! sr.is_done())
446 {
447 std::cout << "Body:" << std::endl;
448 do
449 {
450 sr.next(ec,
451 [&sr](error_code& ec, auto const& buffer)
452 {
453 ec = {};
454 std::cout << make_printable(buffer);
455 sr.consume(buffer_bytes(buffer));
456 });
457 }
458 while(! ec && ! sr.is_done());
459 }
460 if(ec)
461 std::cerr << ec.message() << std::endl;
462 }
463
464 //]
465 #endif
466
467 // Highest snippet:
468
469 } // doc_http_snippets
470