353 lines
7.9 KiB
C++
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
|