mirror of
https://github.com/boostorg/beast.git
synced 2025-06-25 03:51:36 +02:00
493 lines
16 KiB
C++
493 lines
16 KiB
C++
//------------------------------------------------------------------------------
|
|
/*
|
|
This file is part of Beast: https://github.com/vinniefalco/Beast
|
|
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
|
|
|
Permission to use, copy, modify, and/or distribute this software for any
|
|
purpose with or without fee is hereby granted, provided that the above
|
|
copyright notice and this permission notice appear in all copies.
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
*/
|
|
//==============================================================================
|
|
|
|
#ifndef BEAST_HTTP_STREAM_H_INCLUDED
|
|
#define BEAST_HTTP_STREAM_H_INCLUDED
|
|
|
|
#include <beast/http.hpp>
|
|
#include <beast/async_completion.hpp>
|
|
#include <beast/basic_streambuf.hpp>
|
|
#include <boost/asio/io_service.hpp>
|
|
#include <boost/intrusive/list.hpp>
|
|
#include <memory>
|
|
|
|
namespace beast {
|
|
namespace http {
|
|
|
|
namespace detail {
|
|
|
|
class stream_base
|
|
{
|
|
protected:
|
|
struct op
|
|
: boost::intrusive::list_base_hook<
|
|
boost::intrusive::link_mode<
|
|
boost::intrusive::normal_link>>
|
|
{
|
|
virtual ~op() = default;
|
|
virtual void operator()() = 0;
|
|
virtual void cancel() = 0;
|
|
};
|
|
|
|
using op_list = typename boost::intrusive::make_list<
|
|
op, boost::intrusive::constant_time_size<false>>::type;
|
|
|
|
op_list wr_q_;
|
|
bool wr_active_ = false;
|
|
};
|
|
|
|
} // detail
|
|
|
|
/** Provides message-oriented functionality using HTTP.
|
|
|
|
The stream class template provides asynchronous and blocking
|
|
message-oriented functionality necessary for clients and servers
|
|
to utilize the HTTP protocol.
|
|
|
|
@par Thread Safety
|
|
@e Distinct @e objects: Safe.@n
|
|
@e Shared @e objects: Unsafe. The application must ensure that
|
|
all asynchronous operations are performed within the same
|
|
implicit or explicit strand.
|
|
|
|
@par Example
|
|
|
|
To use the class template with an `ip::tcp::socket`, you would write:
|
|
|
|
@code
|
|
http::stream<ip::tcp::socket> hs(io_service);
|
|
@endcode
|
|
Alternatively, you can write:
|
|
@code
|
|
ip::tcp::socket sock(io_service);
|
|
http::stream<ip::tcp::socket&> hs(sock);
|
|
@endcode
|
|
|
|
@note A stream object must not be destroyed while there are
|
|
pending asynchronous operations associated with it.
|
|
|
|
@par Concepts
|
|
AsyncReadStream, AsyncWriteStream, Stream, SyncReadStream, SyncWriteStream.
|
|
*/
|
|
template<class NextLayer,
|
|
class Allocator = std::allocator<char>>
|
|
class stream : public detail::stream_base
|
|
{
|
|
NextLayer next_layer_;
|
|
basic_streambuf<Allocator> rd_buf_;
|
|
|
|
public:
|
|
/// The type of the next layer.
|
|
using next_layer_type =
|
|
typename std::remove_reference<NextLayer>::type;
|
|
|
|
/// The type of the lowest layer.
|
|
using lowest_layer_type =
|
|
typename next_layer_type::lowest_layer_type;
|
|
|
|
/// The type of endpoint of the lowest layer.
|
|
using endpoint_type =
|
|
typename lowest_layer_type::endpoint_type;
|
|
|
|
/// The protocol of the next layer.
|
|
using protocol_type =
|
|
typename lowest_layer_type::protocol_type;
|
|
|
|
/// The type of resolver of the next layer.
|
|
using resolver_type =
|
|
typename protocol_type::resolver;
|
|
|
|
/** Destructor.
|
|
|
|
@note A stream object must not be destroyed while there
|
|
are pending asynchronous operations associated with it.
|
|
*/
|
|
~stream();
|
|
|
|
/** Move constructor.
|
|
|
|
Undefined behavior if operations are active or pending.
|
|
*/
|
|
stream(stream&&) = default;
|
|
|
|
/** Move assignment.
|
|
|
|
Undefined behavior if operations are active or pending.
|
|
*/
|
|
stream& operator=(stream&&) = default;
|
|
|
|
/** Construct a HTTP stream.
|
|
|
|
This constructor creates a HTTP stream and initialises
|
|
the next layer.
|
|
|
|
@throws Any exceptions thrown by the Stream constructor.
|
|
|
|
@param args The arguments to be passed to initialise the
|
|
next layer. The arguments are forwarded to the next layer's
|
|
constructor.
|
|
*/
|
|
template<class... Args>
|
|
explicit
|
|
stream(Args&&... args);
|
|
|
|
/** Get the io_service associated with the stream.
|
|
|
|
This function may be used to obtain the io_service object
|
|
that the stream uses to dispatch handlers for asynchronous
|
|
operations.
|
|
|
|
@return A reference to the io_service object that the stream
|
|
will use to dispatch handlers. Ownership is not transferred
|
|
to the caller.
|
|
*/
|
|
boost::asio::io_service&
|
|
get_io_service()
|
|
{
|
|
return next_layer_.lowest_layer().get_io_service();
|
|
}
|
|
|
|
/** Get a reference to the next layer.
|
|
|
|
This function returns a reference to the next layer
|
|
in a stack of stream layers.
|
|
|
|
@return A reference to the next layer in the stack of
|
|
stream layers. Ownership is not transferred to the caller.
|
|
*/
|
|
next_layer_type&
|
|
next_layer()
|
|
{
|
|
return next_layer_;
|
|
}
|
|
|
|
/** Get a reference to the next layer.
|
|
|
|
This function returns a reference to the next layer in a
|
|
stack of stream layers.
|
|
|
|
@return A reference to the next layer in the stack of
|
|
stream layers. Ownership is not transferred to the caller.
|
|
*/
|
|
next_layer_type const&
|
|
next_layer() const
|
|
{
|
|
return next_layer_;
|
|
}
|
|
|
|
/** Get a reference to the lowest layer.
|
|
|
|
This function returns a reference to the lowest layer
|
|
in a stack of stream layers.
|
|
|
|
@return A reference to the lowest layer in the stack of
|
|
stream layers. Ownership is not transferred to the caller.
|
|
*/
|
|
lowest_layer_type&
|
|
lowest_layer()
|
|
{
|
|
return next_layer_.lowest_layer();
|
|
}
|
|
|
|
/** Get a reference to the lowest layer.
|
|
|
|
This function returns a reference to the lowest layer
|
|
in a stack of stream layers.
|
|
|
|
@return A reference to the lowest layer in the stack of
|
|
stream layers. Ownership is not transferred to the caller.
|
|
*/
|
|
lowest_layer_type const&
|
|
lowest_layer() const
|
|
{
|
|
return next_layer_.lowest_layer();
|
|
}
|
|
|
|
/** Cancel pending operations.
|
|
|
|
This will cancel all of the asynchronous operations pending,
|
|
including pipelined writes that have not been started. Handlers for
|
|
canceled writes will be called with
|
|
`boost::asio::error::operation_aborted`.
|
|
|
|
@throws boost::system::system_error Thrown on failure.
|
|
*/
|
|
void
|
|
cancel()
|
|
{
|
|
error_code ec;
|
|
cancel(ec);
|
|
if(ec)
|
|
throw boost::system::system_error{ec};
|
|
}
|
|
|
|
/** Cancel pending operations.
|
|
|
|
This will cancel all of the asynchronous operations pending,
|
|
including pipelined writes that have not been started. Handlers for
|
|
canceled writes will be called with
|
|
`boost::asio::error::operation_aborted`.
|
|
|
|
@param ec Set to indicate what error occurred, if any.
|
|
*/
|
|
void
|
|
cancel(error_code& ec);
|
|
|
|
/** Read a HTTP message from the stream.
|
|
|
|
This function is used to read a single HTTP message from the stream.
|
|
The call will block until one of the followign conditions is true:
|
|
|
|
@li A message has been read.
|
|
|
|
@li An error occurred.
|
|
|
|
The operation is implemented in terms of zero or more calls to the
|
|
next layer's `read_some` function.
|
|
|
|
@param msg An object used to store the message. The previous
|
|
contents of the object will be overwritten.
|
|
|
|
@throws boost::system::system_error Thrown on failure.
|
|
*/
|
|
template<bool isRequest, class Body, class Headers>
|
|
void
|
|
read(message<isRequest, Body, Headers>& msg)
|
|
{
|
|
error_code ec;
|
|
read(msg, ec);
|
|
if(ec)
|
|
throw boost::system::system_error{ec};
|
|
}
|
|
|
|
/** Read a HTTP message from the stream.
|
|
|
|
This function is used to read a single HTTP message from the stream.
|
|
The call will block until one of the followign conditions is true:
|
|
|
|
@li A message has been read.
|
|
|
|
@li An error occurred.
|
|
|
|
The operation is implemented in terms of zero or more calls to the
|
|
next layer's `read_some` function.
|
|
|
|
@param msg An object used to store the message. The previous
|
|
contents of the object will be overwritten.
|
|
|
|
@param ec Set to indicate what error occurred, if any.
|
|
*/
|
|
template<bool isRequest, class Body, class Headers>
|
|
void
|
|
read(message<isRequest, Body, Headers>& msg,
|
|
error_code& ec);
|
|
|
|
/** Start reading a HTTP message from the stream asynchronously.
|
|
|
|
This function is used to asynchronously read a single HTTP message
|
|
from the stream. The function call always returns immediately. The
|
|
asynchronous operation will continue until one of the following
|
|
conditions is true:
|
|
|
|
@li The message has been written.
|
|
|
|
@li An error occurred.
|
|
|
|
This operation is implemented in terms of zero or more calls to the
|
|
next layer's async_read_some function, and is known as a composed
|
|
operation. The program must ensure that the stream performs no other
|
|
read operations or any other composed operations that perform reads
|
|
until this operation completes.
|
|
|
|
@param msg An object used to store the message. The previous
|
|
contents of the object will be overwritten. Ownership of the message
|
|
is not transferred; the caller must guarantee that the object remains
|
|
valid until the handler is called.
|
|
|
|
@param handler The handler to be called when the request 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<bool isRequest, class Body, class Headers,
|
|
class ReadHandler>
|
|
#if GENERATING_DOCS
|
|
void_or_deduced
|
|
#else
|
|
typename async_completion<
|
|
ReadHandler, void(error_code)>::result_type
|
|
#endif
|
|
async_read(message<isRequest, Body, Headers>& msg,
|
|
ReadHandler&& handler);
|
|
|
|
/** Write a HTTP message to the stream.
|
|
|
|
This function is used to write a single HTTP message to the
|
|
stream. The call will block until one of the following conditions
|
|
is true:
|
|
|
|
@li The entire message is sent.
|
|
|
|
@li An error occurred.
|
|
|
|
If the semantics of the message require that the connection is
|
|
closed to indicate the end of the content body,
|
|
`boost::asio::error::eof` is thrown after the message is sent.
|
|
successfuly. The caller is responsible for actually closing the
|
|
connection. For regular TCP/IP streams this means shutting down the
|
|
send side, while SSL streams may call the SSL shutdown function.
|
|
|
|
@param msg The message to send.
|
|
|
|
@throws boost::system::system_error Thrown on failure.
|
|
*/
|
|
template<bool isRequest, class Body, class Headers>
|
|
void
|
|
write(message<isRequest, Body, Headers> const& msg)
|
|
{
|
|
error_code ec;
|
|
write(msg, ec);
|
|
if(ec)
|
|
throw boost::system::system_error{ec};
|
|
}
|
|
|
|
/** Write a HTTP message to the stream.
|
|
|
|
This function is used to write a single HTTP message to the
|
|
stream. The call will block until one of the following conditions
|
|
is true:
|
|
|
|
@li The entire message is sent.
|
|
|
|
@li An error occurred.
|
|
|
|
If the semantics of the message require that the connection is
|
|
closed to indicate the end of the content body,
|
|
`boost::asio::error::eof` is returned after the message is sent.
|
|
successfuly. The caller is responsible for actually closing the
|
|
connection. For regular TCP/IP streams this means shutting down the
|
|
send side, while SSL streams may call the SSL shutdown function.
|
|
|
|
@param msg The message to send.
|
|
|
|
@param ec Set to the error, if any occurred.
|
|
*/
|
|
template<bool isRequest, class Body, class Headers>
|
|
void
|
|
write(message<isRequest, Body, Headers> const& msg,
|
|
error_code& ec);
|
|
|
|
/** Start pipelining a HTTP message to the stream asynchronously.
|
|
|
|
This function is used to queue a message to be sent on the stream.
|
|
Unlike the free function, this version will place the message on an
|
|
outgoing message queue if there is already a write pending.
|
|
|
|
If the semantics of the message require that the connection is
|
|
closed to indicate the end of the content body, the handler
|
|
is called with the error `boost::asio::error::eof` after the message
|
|
has been sent successfully. The caller is responsible for actually
|
|
closing the connection. For regular TCP/IP streams this means
|
|
shutting down the send side, while SSL streams may call the SSL
|
|
`async_shutdown` function.
|
|
|
|
@param msg The message to send. A copy of the message will be made.
|
|
|
|
@param handler The handler to be called when the request 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<bool isRequest, class Body, class Headers,
|
|
class WriteHandler>
|
|
#if GENERATING_DOCS
|
|
void_or_deduced
|
|
#else
|
|
typename async_completion<
|
|
WriteHandler, void(error_code)>::result_type
|
|
#endif
|
|
async_write(message<isRequest, Body, Headers> const& msg,
|
|
WriteHandler&& handler);
|
|
|
|
/** Start pipelining a HTTP message to the stream asynchronously.
|
|
|
|
This function is used to queue a message to be sent on the stream.
|
|
Unlike the free function, this version will place the message on an
|
|
outgoing message queue if there is already a write pending.
|
|
|
|
If the semantics of the message require that the connection is
|
|
closed to indicate the end of the content body, the handler
|
|
is called with the error boost::asio::error::eof. The caller is
|
|
responsible for actually closing the connection. For regular
|
|
TCP/IP streams this means shutting down the send side, while SSL
|
|
streams may call the SSL async_shutdown function.
|
|
|
|
@param msg The message to send. Ownership of the message, which
|
|
must be movable, is transferred to the implementation. The message
|
|
will not be destroyed until the asynchronous operation completes.
|
|
|
|
@param handler The handler to be called when the request 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<bool isRequest, class Body, class Headers,
|
|
class WriteHandler>
|
|
#if GENERATING_DOCS
|
|
void_or_deduced
|
|
#else
|
|
typename async_completion<
|
|
WriteHandler, void(error_code)>::result_type
|
|
#endif
|
|
async_write(message<isRequest, Body, Headers>&& msg,
|
|
WriteHandler&& handler);
|
|
|
|
private:
|
|
template<bool, class, class, class> class read_op;
|
|
template<bool, class, class, class> class write_op;
|
|
|
|
void
|
|
cancel_all();
|
|
};
|
|
|
|
} // http
|
|
} // beast
|
|
|
|
#include "http_stream.ipp"
|
|
|
|
#endif
|