123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466 |
- //
- // Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
- //
- // Distributed under the Boost Software License, Version 1.0. (See accompanying
- // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
- //
- // Official repository: https://github.com/boostorg/beast
- //
- #include <boost/beast/core.hpp>
- #include <boost/asio.hpp>
- #include <boost/config.hpp>
- #include <iostream>
- #include <thread>
- using namespace boost::beast;
- //[http_snippet_1
- #include <boost/beast/http.hpp>
- using namespace boost::beast::http;
- //]
- namespace doc_http_snippets {
- //[http_snippet_17
- // This function returns the buffer containing the next chunk body
- net::const_buffer get_next_chunk_body();
- //]
- net::const_buffer get_next_chunk_body()
- {
- return {nullptr, 0};
- }
- void fxx() {
- net::io_context ioc;
- auto work = net::make_work_guard(ioc);
- std::thread t{[&](){ ioc.run(); }};
- net::ip::tcp::socket sock{ioc};
- {
- //[http_snippet_2
- request<empty_body> req;
- req.version(11); // HTTP/1.1
- req.method(verb::get);
- req.target("/index.htm");
- req.set(field::accept, "text/html");
- req.set(field::user_agent, "Beast");
- //]
- }
- {
- //[http_snippet_3
- response<string_body> res;
- res.version(11); // HTTP/1.1
- res.result(status::ok);
- res.set(field::server, "Beast");
- res.body() = "Hello, world!";
- res.prepare_payload();
- //]
- }
- {
- //[http_snippet_4
- flat_buffer buffer; // (The parser is optimized for flat buffers)
- request<string_body> req;
- read(sock, buffer, req);
- //]
- }
- {
- //[http_snippet_5
- flat_buffer buffer;
- response<string_body> res;
- async_read(sock, buffer, res,
- [&](error_code ec, std::size_t bytes_transferred)
- {
- boost::ignore_unused(bytes_transferred);
- std::cerr << ec.message() << std::endl;
- });
- //]
- }
- {
- //[http_snippet_6
- // This buffer's max size is too small for much of anything
- flat_buffer buffer{10};
- // Try to read a request
- error_code ec;
- request<string_body> req;
- read(sock, buffer, req, ec);
- if(ec == http::error::buffer_overflow)
- std::cerr << "Buffer limit exceeded!" << std::endl;
- //]
- }
- {
- //[http_snippet_7
- response<string_body> res;
- res.version(11);
- res.result(status::ok);
- res.set(field::server, "Beast");
- res.body() = "Hello, world!";
- res.prepare_payload();
- error_code ec;
- write(sock, res, ec);
- //]
- //[http_snippet_8
- async_write(sock, res,
- [&](error_code ec, std::size_t bytes_transferred)
- {
- boost::ignore_unused(bytes_transferred);
- if(ec)
- std::cerr << ec.message() << std::endl;
- });
- //]
- }
- {
- //[http_snippet_10
- response<string_body> res;
- response_serializer<string_body> sr{res};
- //]
- }
- {
- //[http_snippet_18
- // Prepare an HTTP/1.1 response with a chunked body
- response<empty_body> res{status::ok, 11};
- res.set(field::server, "Beast");
- // Set Transfer-Encoding to "chunked".
- // If a Content-Length was present, it is removed.
- res.chunked(true);
- // Set up the serializer
- response_serializer<empty_body> sr{res};
- // Write the header first
- write_header(sock, sr);
- // Now manually emit three chunks:
- net::write(sock, make_chunk(get_next_chunk_body()));
- net::write(sock, make_chunk(get_next_chunk_body()));
- net::write(sock, make_chunk(get_next_chunk_body()));
- // We are responsible for sending the last chunk:
- net::write(sock, make_chunk_last());
- //]
- }
- {
- //[http_snippet_19
- // Prepare a set of chunk extension to emit with the body
- chunk_extensions ext;
- ext.insert("mp3");
- ext.insert("title", "Beale Street Blues");
- ext.insert("artist", "W.C. Handy");
- // Write the next chunk with the chunk extensions
- // The implementation will make a copy of the extensions object,
- // so the caller does not need to manage lifetime issues.
- net::write(sock, make_chunk(get_next_chunk_body(), ext));
- // Write the next chunk with the chunk extensions
- // The implementation will make a copy of the extensions object, storing the copy
- // using the custom allocator, so the caller does not need to manage lifetime issues.
- net::write(sock, make_chunk(get_next_chunk_body(), ext, std::allocator<char>{}));
- // Write the next chunk with the chunk extensions
- // The implementation allocates memory using the default allocator and takes ownership
- // of the extensions object, so the caller does not need to manage lifetime issues.
- // Note: ext is moved
- net::write(sock, make_chunk(get_next_chunk_body(), std::move(ext)));
- //]
- }
- {
- //[http_snippet_20
- // Manually specify the chunk extensions.
- // Some of the strings contain spaces and a period and must be quoted
- net::write(sock, make_chunk(get_next_chunk_body(),
- ";mp3"
- ";title=\"Danny Boy\""
- ";artist=\"Fred E. Weatherly\""
- ));
- //]
- }
- {
- //[http_snippet_21
- // Prepare a chunked HTTP/1.1 response with some trailer fields
- response<empty_body> res{status::ok, 11};
- res.set(field::server, "Beast");
- // Inform the client of the trailer fields we will send
- res.set(field::trailer, "Content-MD5, Expires");
- res.chunked(true);
- // Serialize the header and two chunks
- response_serializer<empty_body> sr{res};
- write_header(sock, sr);
- net::write(sock, make_chunk(get_next_chunk_body()));
- net::write(sock, make_chunk(get_next_chunk_body()));
- // Prepare the trailer
- fields trailer;
- trailer.set(field::content_md5, "f4a5c16584f03d90");
- trailer.set(field::expires, "never");
- // Emit the trailer in the last chunk.
- // The implementation will use the default allocator to create the storage for holding
- // the serialized fields.
- net::write(sock, make_chunk_last(trailer));
- //]
- }
- {
- //[http_snippet_22
- // Use a custom allocator for serializing the last chunk
- fields trailer;
- trailer.set(field::approved, "yes");
- net::write(sock, make_chunk_last(trailer, std::allocator<char>{}));
- //]
- }
- {
- //[http_snippet_23
- // Manually emit a trailer.
- // We are responsible for ensuring that the trailer format adheres to the specification.
- string_view ext =
- "Content-MD5: f4a5c16584f03d90\r\n"
- "Expires: never\r\n"
- "\r\n";
- net::write(sock, make_chunk_last(net::const_buffer{ext.data(), ext.size()}));
- //]
- }
- {
- //[http_snippet_24
- // Prepare a chunked HTTP/1.1 response and send the header
- response<empty_body> res{status::ok, 11};
- res.set(field::server, "Beast");
- res.chunked(true);
- response_serializer<empty_body> sr{res};
- write_header(sock, sr);
- // Obtain three body buffers up front
- auto const cb1 = get_next_chunk_body();
- auto const cb2 = get_next_chunk_body();
- auto const cb3 = get_next_chunk_body();
- // Manually emit a chunk by first writing the chunk-size header with the correct size
- net::write(sock, chunk_header{
- buffer_bytes(cb1) +
- buffer_bytes(cb2) +
- buffer_bytes(cb3)});
- // And then output the chunk body in three pieces ("chunk the chunk")
- net::write(sock, cb1);
- net::write(sock, cb2);
- net::write(sock, cb3);
- // When we go this deep, we are also responsible for the terminating CRLF
- net::write(sock, chunk_crlf{});
- //]
- }
- } // fxx()
- //[http_snippet_12
- /** Send a message to a stream synchronously.
- @param stream The stream to write to. This type must support
- the <em>SyncWriteStream</em> concept.
- @param m The message to send. The Body type must support
- the <em>BodyWriter</em> concept.
- */
- template<
- class SyncWriteStream,
- bool isRequest, class Body, class Fields>
- void
- send(
- SyncWriteStream& stream,
- message<isRequest, Body, Fields> const& m)
- {
- // Check the template types
- static_assert(is_sync_write_stream<SyncWriteStream>::value,
- "SyncWriteStream type requirements not met");
- static_assert(is_body_writer<Body>::value,
- "BodyWriter type requirements not met");
- // Create the instance of serializer for the message
- serializer<isRequest, Body, Fields> sr{m};
- // Loop until the serializer is finished
- do
- {
- // This call guarantees it will make some
- // forward progress, or otherwise return an error.
- write_some(stream, sr);
- }
- while(! sr.is_done());
- }
- //]
- //[http_snippet_13
- template<class SyncReadStream>
- void
- print_response(SyncReadStream& stream)
- {
- static_assert(is_sync_read_stream<SyncReadStream>::value,
- "SyncReadStream type requirements not met");
- // Declare a parser for an HTTP response
- response_parser<string_body> parser;
- // Read the entire message
- read(stream, parser);
- // Now print the message
- std::cout << parser.get() << std::endl;
- }
- //]
- #ifdef BOOST_MSVC
- //[http_snippet_14
- template<bool isRequest, class Body, class Fields>
- void
- print_cxx14(message<isRequest, Body, Fields> const& m)
- {
- error_code ec;
- serializer<isRequest, Body, Fields> sr{m};
- do
- {
- sr.next(ec,
- [&sr](error_code& ec, auto const& buffer)
- {
- ec = {};
- std::cout << make_printable(buffer);
- sr.consume(buffer_bytes(buffer));
- });
- }
- while(! ec && ! sr.is_done());
- if(! ec)
- std::cout << std::endl;
- else
- std::cerr << ec.message() << std::endl;
- }
- //]
- #endif
- //[http_snippet_15
- template<class Serializer>
- struct lambda
- {
- Serializer& sr;
- lambda(Serializer& sr_) : sr(sr_) {}
- template<class ConstBufferSequence>
- void operator()(error_code& ec, ConstBufferSequence const& buffer) const
- {
- ec = {};
- std::cout << make_printable(buffer);
- sr.consume(buffer_bytes(buffer));
- }
- };
- template<bool isRequest, class Body, class Fields>
- void
- print(message<isRequest, Body, Fields> const& m)
- {
- error_code ec;
- serializer<isRequest, Body, Fields> sr{m};
- do
- {
- sr.next(ec, lambda<decltype(sr)>{sr});
- }
- while(! ec && ! sr.is_done());
- if(! ec)
- std::cout << std::endl;
- else
- std::cerr << ec.message() << std::endl;
- }
- //]
- #ifdef BOOST_MSVC
- //[http_snippet_16
- template<bool isRequest, class Body, class Fields>
- void
- split_print_cxx14(message<isRequest, Body, Fields> const& m)
- {
- error_code ec;
- serializer<isRequest, Body, Fields> sr{m};
- sr.split(true);
- std::cout << "Header:" << std::endl;
- do
- {
- sr.next(ec,
- [&sr](error_code& ec, auto const& buffer)
- {
- ec = {};
- std::cout << make_printable(buffer);
- sr.consume(buffer_bytes(buffer));
- });
- }
- while(! sr.is_header_done());
- if(! ec && ! sr.is_done())
- {
- std::cout << "Body:" << std::endl;
- do
- {
- sr.next(ec,
- [&sr](error_code& ec, auto const& buffer)
- {
- ec = {};
- std::cout << make_printable(buffer);
- sr.consume(buffer_bytes(buffer));
- });
- }
- while(! ec && ! sr.is_done());
- }
- if(ec)
- std::cerr << ec.message() << std::endl;
- }
- //]
- #endif
- // Highest snippet:
- } // doc_http_snippets
|