beast/test/doc/exemplars.cpp
2019-03-05 20:15:07 -08:00

353 lines
7.9 KiB
C++

//
// 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/buffer_traits.hpp>
#include <boost/beast/core/error.hpp>
#include <boost/beast/core/file_base.hpp>
#include <boost/beast/http/message.hpp>
#include <boost/beast/http/type_traits.hpp>
#include <boost/optional.hpp>
#include <cstdint>
#include <utility>
namespace boost {
namespace beast {
namespace http {
class BodyWriter;
class BodyReader;
//[concept_Body
struct Body
{
// The type of message::body when used
struct value_type;
/// The algorithm used during parsing
class reader;
/// The algorithm used during serialization
class writer;
/// Returns the body's payload size
static
std::uint64_t
size(value_type const& body);
};
static_assert(is_body<Body>::value, "");
//]
struct Body_BodyWriter {
struct value_type{};
//[concept_BodyWriter
struct BodyWriter
{
public:
/// The type of buffer returned by `get`.
using const_buffers_type = net::const_buffer;
/** Construct the writer.
@param h The header for the message being serialized
@param body The body being serialized
*/
template<bool isRequest, class Fields>
BodyWriter(header<isRequest, Fields> const& h, value_type const& body);
/** Initialize the writer.
This is called after construction and before the first
call to `get`. The message is valid and complete upon
entry.
@param ec Set to the error, if any occurred.
*/
void
init(error_code& ec)
{
// The specification requires this to indicate "no error"
ec = {};
}
/** Returns the next buffer in the body.
@li If the return value is `boost::none` (unseated optional) and
`ec` does not contain an error, this indicates the end of the
body, no more buffers are present.
@li If the optional contains a value, the first element of the
pair represents a <em>ConstBufferSequence</em> containing one or
more octets of the body data. The second element indicates
whether or not there are additional octets of body data.
A value of `true` means there is more data, and that the
implementation will perform a subsequent call to `get`.
A value of `false` means there is no more body data.
@li If `ec` contains an error code, the return value is ignored.
@param ec Set to the error, if any occurred.
*/
boost::optional<std::pair<const_buffers_type, bool>>
get(error_code& ec)
{
// The specification requires this to indicate "no error"
ec = {};
return boost::none; // for exposition only
}
};
//]
using writer = BodyWriter;
};
static_assert(is_body_writer<Body_BodyWriter>::value, "");
struct Body_BodyReader {
struct value_type{};
//[concept_BodyReader
struct BodyReader
{
/** Construct the reader.
@param h The header for the message being parsed
@param body The body to store the parsed results into
*/
template<bool isRequest, class Fields>
BodyReader(header<isRequest, Fields>& h, value_type& body);
/** Initialize the reader.
This is called after construction and before the first
call to `put`. The message is valid and complete upon
entry.
@param ec Set to the error, if any occurred.
*/
void
init(
boost::optional<std::uint64_t> const& content_length,
error_code& ec)
{
boost::ignore_unused(content_length);
// The specification requires this to indicate "no error"
ec = {};
}
/** Store buffers.
This is called zero or more times with parsed body octets.
@param buffers The constant buffer sequence to store.
@param ec Set to the error, if any occurred.
@return The number of bytes transferred from the input buffers.
*/
template<class ConstBufferSequence>
std::size_t
put(ConstBufferSequence const& buffers, error_code& ec)
{
// The specification requires this to indicate "no error"
ec = {};
return buffer_bytes(buffers);
}
/** Called when the body is complete.
@param ec Set to the error, if any occurred.
*/
void
finish(error_code& ec)
{
// The specification requires this to indicate "no error"
ec = {};
}
};
//]
using reader = BodyReader;
};
static_assert(is_body_reader<Body_BodyReader>::value, "");
//[concept_Fields
class Fields
{
public:
/// Constructed as needed when fields are serialized
struct writer;
protected:
/** Returns the request-method string.
@note Only called for requests.
*/
string_view
get_method_impl() const;
/** Returns the request-target string.
@note Only called for requests.
*/
string_view
get_target_impl() const;
/** Returns the response reason-phrase string.
@note Only called for responses.
*/
string_view
get_reason_impl() const;
/** Returns the chunked Transfer-Encoding setting
*/
bool
get_chunked_impl() const;
/** Returns the keep-alive setting
*/
bool
get_keep_alive_impl(unsigned version) const;
/** Returns `true` if the Content-Length field is present.
*/
bool
has_content_length_impl() const;
/** Set or clear the method string.
@note Only called for requests.
*/
void
set_method_impl(string_view s);
/** Set or clear the target string.
@note Only called for requests.
*/
void
set_target_impl(string_view s);
/** Set or clear the reason string.
@note Only called for responses.
*/
void
set_reason_impl(string_view s);
/** Sets or clears the chunked Transfer-Encoding value
*/
void
set_chunked_impl(bool value);
/** Sets or clears the Content-Length field
*/
void
set_content_length_impl(boost::optional<std::uint64_t>);
/** Adjusts the Connection field
*/
void
set_keep_alive_impl(unsigned version, bool keep_alive);
};
static_assert(is_fields<Fields>::value,
"Fields type requirements not met");
//]
struct Fields_FieldsWriter {
using Fields = Fields_FieldsWriter;
//[concept_FieldsWriter
struct FieldsWriter
{
// The type of buffers returned by `get`
struct const_buffers_type;
// Constructor for requests
FieldsWriter(Fields const& f, unsigned version, verb method);
// Constructor for responses
FieldsWriter(Fields const& f, unsigned version, unsigned status);
// Returns the serialized header buffers
const_buffers_type
get();
};
//]
};
//[concept_File
struct File
{
/** Default constructor
There is no open file initially.
*/
File();
/** Destructor
If the file is open it is first closed.
*/
~File();
/// Returns `true` if the file is open
bool
is_open() const;
/// Close the file if open
void
close(error_code& ec);
/// Open a file at the given path with the specified mode
void
open(char const* path, file_mode mode, error_code& ec);
/// Return the size of the open file
std::uint64_t
size(error_code& ec) const;
/// Return the current position in the open file
std::uint64_t
pos(error_code& ec) const;
/// Adjust the current position in the open file
void
seek(std::uint64_t offset, error_code& ec);
/// Read from the open file
std::size_t
read(void* buffer, std::size_t n, error_code& ec) const;
/// Write to the open file
std::size_t
write(void const* buffer, std::size_t n, error_code& ec);
};
//]
} // http
} // beast
} // boost