http_snippets.cpp 11 KB

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