• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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