Files
boost_beast/example/common/write_msg.hpp

231 lines
7.0 KiB
C++
Raw Normal View History

//
2017-07-24 09:42:36 -07:00
// Copyright (c) 2016-2017 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)
//
2017-07-20 13:40:34 -07:00
// Official repository: https://github.com/boostorg/beast
//
2017-07-20 13:40:34 -07:00
#ifndef BOOST_BEAST_EXAMPLE_COMMON_WRITE_MSG_HPP
#define BOOST_BEAST_EXAMPLE_COMMON_WRITE_MSG_HPP
2017-07-20 13:40:34 -07:00
#include <boost/beast/core/async_result.hpp>
#include <boost/beast/core/handler_ptr.hpp>
#include <boost/beast/core/type_traits.hpp>
#include <boost/beast/http/message.hpp>
#include <boost/beast/http/write.hpp>
#include <boost/beast/http/type_traits.hpp>
#include <boost/asio/handler_alloc_hook.hpp>
#include <boost/asio/handler_continuation_hook.hpp>
#include <boost/asio/handler_invoke_hook.hpp>
namespace detail {
/** Composed operation to send an HTTP message
This implements the composed operation needed for the
@ref async_write_msg function.
*/
template<
class AsyncWriteStream,
class Handler,
bool isRequest, class Body, class Fields>
class write_msg_op
{
2017-06-17 10:20:45 -07:00
// This composed operation has a state which is not trivial
// to copy (msg) so we need to store the state in an allocated
// object.
//
struct data
{
2017-06-17 10:20:45 -07:00
// The stream we are writing to
AsyncWriteStream& stream;
2017-06-17 10:20:45 -07:00
// The message we are sending. Note that this composed
// operation takes ownership of the message and destroys
// it when it is done.
//
2017-07-20 13:40:34 -07:00
boost::beast::http::message<isRequest, Body, Fields> msg;
2017-07-07 23:25:23 -07:00
// Serializer for the message
2017-07-20 13:40:34 -07:00
boost::beast::http::serializer<isRequest, Body, Fields> sr;
2017-07-07 23:25:23 -07:00
data(
Handler& handler,
AsyncWriteStream& stream_,
2017-07-20 13:40:34 -07:00
boost::beast::http::message<isRequest, Body, Fields>&& msg_)
: stream(stream_)
, msg(std::move(msg_))
2017-07-07 23:25:23 -07:00
, sr(msg)
{
2017-06-22 10:27:45 -07:00
boost::ignore_unused(handler);
}
};
2017-06-17 10:20:45 -07:00
// `handler_ptr` is a utility which helps to manage a composed
// operation's state. It is similar to a shared pointer, but
// it uses handler allocation hooks to allocate and free memory,
// and it also helps to meet Asio's deallocate-before-invocation
// guarantee.
//
2017-07-20 13:40:34 -07:00
boost::beast::handler_ptr<data, Handler> d_;
public:
2017-06-17 10:20:45 -07:00
// Asio can move and copy the handler, we support both
write_msg_op(write_msg_op&&) = default;
write_msg_op(write_msg_op const&) = default;
2017-06-17 10:20:45 -07:00
// Constructor
//
// We take the handler as a template type to
// support both const and rvalue references.
//
template<
class DeducedHandler,
class... Args>
write_msg_op(
DeducedHandler&& h,
AsyncWriteStream& s,
Args&&... args)
: d_(std::forward<DeducedHandler>(h),
s, std::forward<Args>(args)...)
{
}
2017-06-17 10:20:45 -07:00
// Entry point
//
// The initiation function calls this to start the operation
//
void
operator()()
{
auto& d = *d_;
2017-07-20 13:40:34 -07:00
boost::beast::http::async_write(
2017-07-07 23:25:23 -07:00
d.stream, d.sr, std::move(*this));
}
2017-06-17 10:20:45 -07:00
// Completion handler
//
2017-07-20 13:40:34 -07:00
// This gets called when boost::beast::http::async_write completes
2017-06-17 10:20:45 -07:00
//
void
2017-07-20 13:40:34 -07:00
operator()(boost::beast::error_code ec)
{
d_.invoke(ec);
}
2017-06-17 10:20:45 -07:00
//
// These hooks are necessary for Asio
//
// The meaning is explained in the Beast documentation
//
friend
void* asio_handler_allocate(
std::size_t size, write_msg_op* op)
{
using boost::asio::asio_handler_allocate;
return asio_handler_allocate(
size, std::addressof(op->d_.handler()));
}
friend
void asio_handler_deallocate(
void* p, std::size_t size, write_msg_op* op)
{
using boost::asio::asio_handler_deallocate;
asio_handler_deallocate(
p, size, std::addressof(op->d_.handler()));
}
friend
bool asio_handler_is_continuation(write_msg_op* op)
{
using boost::asio::asio_handler_is_continuation;
return asio_handler_is_continuation(std::addressof(op->d_.handler()));
}
template<class Function>
friend
void asio_handler_invoke(Function&& f, write_msg_op* op)
{
using boost::asio::asio_handler_invoke;
asio_handler_invoke(
f, std::addressof(op->d_.handler()));
}
};
} // detail
/** Write an HTTP message to a stream asynchronously
This function is used to write a complete message to a stream asynchronously
using HTTP/1. The function call always returns immediately. The asynchronous
operation will continue until one of the following conditions is true:
@li The entire message is written.
@li An error occurs.
This operation is implemented in terms of zero or more calls to the stream's
`async_write_some` function, and is known as a <em>composed operation</em>.
The program must ensure that the stream performs no other write operations
until this operation completes. The algorithm will use a temporary
Refactor chunked-encoding serialization: New buffer sequence classes are provided to allow full control over the serialization of chunk-encoded message payloads: * chunk_header A ConstBufferSequence representing the chunk header. It includes a hexadecimal-encoded size, an optional set of chunk extensions, and the trailing CRLF required to denote the end of the chunk header. This allows the caller to manually serialize the chunk body in one or more calls to a stream output function. The caller must also output an object of type `chunk_crlf` to the stream to indicate the end of the chunk body. * chunk_crlf A small ConstBufferSequence that simply represents the two character sequence "\r\n" (CRLF). This is needed for the case where the caller wants to output a chunk body as a series of buffers (i.e. "chunking a chunk"). * chunk_body A ConstBufferSequence representing a complete chunk. This includes the size, an optional set of chunk extensions, a caller provided buffer containing the body, and the required CRLF that follows. * chunk_final A ConstBufferSequence representing a final chunk. It includes an optional set of caller-provided field trailers * chunk_extensions A container for building a set of chunk extensions to use during serialization. The use of the container is optional, callers may provide their own buffer containing a correctly formatted set of chunk extensions, or they may use their own convenience container which meets the requirements. The basic_fields container is modified to allow construction outside the context of a message. The container can be used to provide trailers to `chunk_final`. Actions Required: * Remove references to ChunkDecorators. Use the new chunk-encoding buffer sequences to manually produce a chunked payload body in the case where control over the chunk-extensions and/or trailers is required.
2017-07-09 20:09:30 -07:00
@ref serializer to produce buffers. If the semantics of the message
indicate that the connection should be closed after the message is sent,
the error delivered by this function
will be @ref error::end_of_stream
@param stream The stream to which the data is to be written.
The type must support the @b AsyncWriteStream concept.
@param msg The message to write. The function will take ownership
of the object as if by move constrction.
@param handler The handler to be called when the operation
completes. Copies will be made of the handler as required.
The equivalent function signature of the handler must be:
@code void handler(
error_code const& error // result of operation
); @endcode
Regardless of whether the asynchronous operation completes
immediately or not, the handler will not be invoked from within
this function. Invocation of the handler will be performed in a
manner equivalent to using `boost::asio::io_service::post`.
*/
template<
class AsyncWriteStream,
bool isRequest, class Body, class Fields,
class WriteHandler>
2017-07-20 13:40:34 -07:00
boost::beast::async_return_type<WriteHandler, void(boost::beast::error_code)>
async_write_msg(
AsyncWriteStream& stream,
2017-07-20 13:40:34 -07:00
boost::beast::http::message<isRequest, Body, Fields>&& msg,
WriteHandler&& handler)
{
static_assert(
2017-07-20 13:40:34 -07:00
boost::beast::is_async_write_stream<AsyncWriteStream>::value,
"AsyncWriteStream requirements not met");
2017-07-20 13:40:34 -07:00
static_assert(boost::beast::http::is_body<Body>::value,
"Body requirements not met");
2017-07-20 13:40:34 -07:00
static_assert(boost::beast::http::is_body_reader<Body>::value,
"BodyReader requirements not met");
2017-07-20 13:40:34 -07:00
boost::beast::async_completion<WriteHandler, void(boost::beast::error_code)> init{handler};
2017-06-24 22:24:39 -07:00
::detail::write_msg_op<
AsyncWriteStream,
2017-07-20 13:40:34 -07:00
boost::beast::handler_type<WriteHandler, void(boost::beast::error_code)>,
isRequest, Body, Fields>{
init.completion_handler,
stream,
std::move(msg)}();
return init.result.get();
}
#endif