mirror of
https://github.com/boostorg/beast.git
synced 2025-08-02 22:34:32 +02:00
message::prepare_payload replaces message::prepare (API Change):
Actions Required: * Change calls to msg.prepare to msg.prepare_payload. For messages with a user-defined Fields, provide the function prepare_payload_impl in the fields type according to the Fields requirements.
This commit is contained in:
@@ -12,6 +12,7 @@ API Changes:
|
|||||||
|
|
||||||
* parser requires basic_fields
|
* parser requires basic_fields
|
||||||
* Refine FieldsReader concept
|
* Refine FieldsReader concept
|
||||||
|
* message::prepare_payload replaces message::prepare
|
||||||
|
|
||||||
Actions Required:
|
Actions Required:
|
||||||
|
|
||||||
@@ -21,6 +22,10 @@ Actions Required:
|
|||||||
|
|
||||||
* Implement chunked() and keep_alive() for user defined FieldsReader types.
|
* Implement chunked() and keep_alive() for user defined FieldsReader types.
|
||||||
|
|
||||||
|
* Change calls to msg.prepare to msg.prepare_payload. For messages
|
||||||
|
with a user-defined Fields, provide the function prepare_payload_impl
|
||||||
|
in the fields type according to the Fields requirements.
|
||||||
|
|
||||||
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
Version 61:
|
Version 61:
|
||||||
|
@@ -151,7 +151,7 @@ request.
|
|||||||
|
|
||||||
Here we create an HTTP response indicating success. Note that this
|
Here we create an HTTP response indicating success. Note that this
|
||||||
message has a body. The function
|
message has a body. The function
|
||||||
[link beast.ref.beast__http__message.prepare prepare]
|
[link beast.ref.beast__http__message.prepare_payload `message::prepare_payload`]
|
||||||
automatically sets the Content-Length or Transfer-Encoding field
|
automatically sets the Content-Length or Transfer-Encoding field
|
||||||
depending on the content and type of the `body` member. The use
|
depending on the content and type of the `body` member. The use
|
||||||
of prepare is optional; these fields may also be set explicitly.
|
of prepare is optional; these fields may also be set explicitly.
|
||||||
|
@@ -53,7 +53,7 @@ In this table:
|
|||||||
[
|
[
|
||||||
If present, returns the serialized size of `v` not including
|
If present, returns the serialized size of `v` not including
|
||||||
any chunked transfer encoding. When this function is provided,
|
any chunked transfer encoding. When this function is provided,
|
||||||
[link beast.ref.beast__http__message.prepare `message::prepare`]
|
[link beast.ref.beast__http__message.prepare_payload `message::prepare_payload`]
|
||||||
will automatically set the content length field based on the
|
will automatically set the content length field based on the
|
||||||
value. Otherwise, the chunked transfer encoding will be set.
|
value. Otherwise, the chunked transfer encoding will be set.
|
||||||
]
|
]
|
||||||
|
@@ -25,6 +25,10 @@ In this table:
|
|||||||
|
|
||||||
* `s` is a value of type [link beast.ref.beast__string_view `string_view`].
|
* `s` is a value of type [link beast.ref.beast__string_view `string_view`].
|
||||||
|
|
||||||
|
* `b` is a value of type `bool`
|
||||||
|
|
||||||
|
* `n` is a value of type `boost::optional<std::uint64_t>`.
|
||||||
|
|
||||||
[table Fields requirements
|
[table Fields requirements
|
||||||
[[expression][type][semantics, pre/post-conditions]]
|
[[expression][type][semantics, pre/post-conditions]]
|
||||||
[
|
[
|
||||||
@@ -88,6 +92,29 @@ In this table:
|
|||||||
This function may throw `std::invalid_argument` if the operation
|
This function may throw `std::invalid_argument` if the operation
|
||||||
is not supported by the container.
|
is not supported by the container.
|
||||||
]
|
]
|
||||||
|
][
|
||||||
|
[`a.prepare_payload_impl(b,n)`]
|
||||||
|
[]
|
||||||
|
[
|
||||||
|
Adjusts the Content-Length and Transfer-Encoding fields to
|
||||||
|
account for the payload metadata indicated by `b` and `n` as
|
||||||
|
follows:
|
||||||
|
|
||||||
|
* If `b` is `true`, the chunked Transfer-Encoding should be applied
|
||||||
|
to the end of the list of encodings if it is not already there
|
||||||
|
or if the field was not present. Any Content-Length fields should
|
||||||
|
be removed.
|
||||||
|
|
||||||
|
* If `b` is `false` and `n` contains a value, set the Content-Length
|
||||||
|
field to `*n`, replacing any previous Content-Length fields. Remove
|
||||||
|
the chunked encoding from the end of the Transfer-Encoding field
|
||||||
|
if the field is present ahd chunked is the last encoding.
|
||||||
|
|
||||||
|
* If `b` is `false` and `n` contains no value, remove all Content-Length
|
||||||
|
fields, and remove the chunked encoding from the end of the
|
||||||
|
Transfer-Encoding field if the field is present ahd chunked is the
|
||||||
|
last encoding.
|
||||||
|
]
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -132,6 +159,14 @@ protected:
|
|||||||
@note Only called for responses.
|
@note Only called for responses.
|
||||||
*/
|
*/
|
||||||
string_view get_reason_impl() const;
|
string_view get_reason_impl() const;
|
||||||
|
|
||||||
|
/** Updates the payload metadata.
|
||||||
|
|
||||||
|
@param b `true` if chunked
|
||||||
|
|
||||||
|
@param n The content length if known, otherwise `boost::none`
|
||||||
|
*/
|
||||||
|
void prepare_payload_impl(bool b, boost::optional<std::uint64_t> n)
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@@ -320,7 +320,7 @@ void do_server_head(
|
|||||||
// set of headers that would be sent for a GET request,
|
// set of headers that would be sent for a GET request,
|
||||||
// including the Content-Length, except for the body.
|
// including the Content-Length, except for the body.
|
||||||
res.result(status::ok);
|
res.result(status::ok);
|
||||||
res.content_length(payload.size());
|
res.set(field::content_length, payload.size());
|
||||||
|
|
||||||
// For GET requests, we include the body
|
// For GET requests, we include the body
|
||||||
if(req.method() == verb::get)
|
if(req.method() == verb::get)
|
||||||
|
@@ -64,7 +64,7 @@ int main()
|
|||||||
req.set(http::field::host, host + ":" +
|
req.set(http::field::host, host + ":" +
|
||||||
boost::lexical_cast<std::string>(sock.remote_endpoint().port()));
|
boost::lexical_cast<std::string>(sock.remote_endpoint().port()));
|
||||||
req.set(http::field::user_agent, "Beast");
|
req.set(http::field::user_agent, "Beast");
|
||||||
req.prepare();
|
req.prepare_payload();
|
||||||
|
|
||||||
// Write the HTTP request to the remote host
|
// Write the HTTP request to the remote host
|
||||||
http::write(stream, req, ec);
|
http::write(stream, req, ec);
|
||||||
|
@@ -55,7 +55,7 @@ int main()
|
|||||||
req.set(http::field::host, host + ":" +
|
req.set(http::field::host, host + ":" +
|
||||||
boost::lexical_cast<std::string>(sock.remote_endpoint().port()));
|
boost::lexical_cast<std::string>(sock.remote_endpoint().port()));
|
||||||
req.set(http::field::user_agent, "Beast");
|
req.set(http::field::user_agent, "Beast");
|
||||||
req.prepare();
|
req.prepare_payload();
|
||||||
|
|
||||||
// Write the HTTP request to the remote host
|
// Write the HTTP request to the remote host
|
||||||
http::write(sock, req, ec);
|
http::write(sock, req, ec);
|
||||||
|
@@ -225,7 +225,7 @@ private:
|
|||||||
res.set(beast::http::field::server, server_);
|
res.set(beast::http::field::server, server_);
|
||||||
res.set(beast::http::field::content_type, "text/html");
|
res.set(beast::http::field::content_type, "text/html");
|
||||||
res.body = "The file was not found"; // VFALCO append rel_path
|
res.body = "The file was not found"; // VFALCO append rel_path
|
||||||
res.prepare();
|
res.prepare_payload();
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -243,7 +243,7 @@ private:
|
|||||||
res.set(beast::http::field::server, server_);
|
res.set(beast::http::field::server, server_);
|
||||||
res.set(beast::http::field::content_type, mime_type(full_path));
|
res.set(beast::http::field::content_type, mime_type(full_path));
|
||||||
res.body = full_path;
|
res.body = full_path;
|
||||||
res.prepare();
|
res.prepare_payload();
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -50,7 +50,7 @@ protected:
|
|||||||
res.set(beast::http::field::server, server_name_);
|
res.set(beast::http::field::server, server_name_);
|
||||||
res.set(beast::http::field::content_type, "text/html");
|
res.set(beast::http::field::content_type, "text/html");
|
||||||
res.body = "Bad request";
|
res.body = "Bad request";
|
||||||
res.prepare();
|
res.prepare_payload();
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -38,7 +38,7 @@ struct empty_body
|
|||||||
/// Returns the content length of the body in a message.
|
/// Returns the content length of the body in a message.
|
||||||
static
|
static
|
||||||
std::uint64_t
|
std::uint64_t
|
||||||
size(empty_body)
|
size(value_type)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@@ -15,6 +15,7 @@
|
|||||||
#include <boost/asio/buffer.hpp>
|
#include <boost/asio/buffer.hpp>
|
||||||
#include <boost/intrusive/list.hpp>
|
#include <boost/intrusive/list.hpp>
|
||||||
#include <boost/intrusive/set.hpp>
|
#include <boost/intrusive/set.hpp>
|
||||||
|
#include <boost/optional.hpp>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cctype>
|
#include <cctype>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
@@ -39,7 +40,6 @@ namespace http {
|
|||||||
as a `std::multiset`; there will be a separate value for each occurrence
|
as a `std::multiset`; there will be a separate value for each occurrence
|
||||||
of the field name.
|
of the field name.
|
||||||
|
|
||||||
|
|
||||||
Meets the requirements of @b Fields
|
Meets the requirements of @b Fields
|
||||||
|
|
||||||
@tparam Allocator The allocator to use. This must meet the
|
@tparam Allocator The allocator to use. This must meet the
|
||||||
@@ -48,7 +48,7 @@ namespace http {
|
|||||||
template<class Allocator>
|
template<class Allocator>
|
||||||
class basic_fields
|
class basic_fields
|
||||||
{
|
{
|
||||||
static std::size_t constexpr max_static_start_line = 4096;
|
static std::size_t constexpr max_static_buffer = 4096;
|
||||||
|
|
||||||
using off_t = std::uint16_t;
|
using off_t = std::uint16_t;
|
||||||
|
|
||||||
@@ -591,22 +591,11 @@ protected:
|
|||||||
*/
|
*/
|
||||||
string_view get_reason_impl() const;
|
string_view get_reason_impl() const;
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
/** Adjusts the payload related fields
|
||||||
//
|
|
||||||
// for container
|
|
||||||
//
|
|
||||||
|
|
||||||
/** Set the Content-Length field to the specified value.
|
|
||||||
|
|
||||||
@note This is called by the @ref header implementation.
|
|
||||||
*/
|
*/
|
||||||
void content_length_impl(std::uint64_t n);
|
void
|
||||||
|
prepare_payload_impl(bool chunked,
|
||||||
/** Add chunked to the Transfer-Encoding field.
|
boost::optional<std::uint64_t> size);
|
||||||
|
|
||||||
@note This is called by the @ref header implementation.
|
|
||||||
*/
|
|
||||||
void set_chunked_impl(bool v);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
template<class OtherAlloc>
|
template<class OtherAlloc>
|
||||||
|
@@ -9,6 +9,7 @@
|
|||||||
#define BEAST_HTTP_IMPL_FIELDS_IPP
|
#define BEAST_HTTP_IMPL_FIELDS_IPP
|
||||||
|
|
||||||
#include <beast/core/buffer_cat.hpp>
|
#include <beast/core/buffer_cat.hpp>
|
||||||
|
#include <beast/core/string.hpp>
|
||||||
#include <beast/core/static_string.hpp>
|
#include <beast/core/static_string.hpp>
|
||||||
#include <beast/http/verb.hpp>
|
#include <beast/http/verb.hpp>
|
||||||
#include <beast/http/rfc7230.hpp>
|
#include <beast/http/rfc7230.hpp>
|
||||||
@@ -149,7 +150,7 @@ public:
|
|||||||
unsigned version, unsigned code);
|
unsigned version, unsigned code);
|
||||||
|
|
||||||
basic_fields const& f_;
|
basic_fields const& f_;
|
||||||
static_string<max_static_start_line> ss_;
|
static_string<max_static_buffer> ss_;
|
||||||
string_view sv_;
|
string_view sv_;
|
||||||
std::string s_;
|
std::string s_;
|
||||||
bool chunked_;
|
bool chunked_;
|
||||||
@@ -199,7 +200,7 @@ get_chunked() const
|
|||||||
f_[field::transfer_encoding]};
|
f_[field::transfer_encoding]};
|
||||||
for(auto it = te.begin(); it != te.end();)
|
for(auto it = te.begin(); it != te.end();)
|
||||||
{
|
{
|
||||||
auto next = std::next(it);
|
auto const next = std::next(it);
|
||||||
if(next == te.end())
|
if(next == te.end())
|
||||||
return iequals(*it, "chunked");
|
return iequals(*it, "chunked");
|
||||||
it = next;
|
it = next;
|
||||||
@@ -866,32 +867,119 @@ get_reason_impl() const
|
|||||||
return target_or_reason_;
|
return target_or_reason_;
|
||||||
}
|
}
|
||||||
|
|
||||||
//---
|
namespace detail {
|
||||||
|
|
||||||
template<class Allocator>
|
// Builds a new string with "chunked" maybe taken off the end
|
||||||
inline
|
template<class String>
|
||||||
void
|
void
|
||||||
basic_fields<Allocator>::
|
without_chunked_last(String& s, string_view const& tokens)
|
||||||
content_length_impl(std::uint64_t n)
|
|
||||||
{
|
{
|
||||||
erase(field::content_length);
|
token_list te{tokens};
|
||||||
insert(field::content_length, n);
|
if(te.begin() != te.end())
|
||||||
|
{
|
||||||
|
auto it = te.begin();
|
||||||
|
auto next = std::next(it);
|
||||||
|
if(next == te.end())
|
||||||
|
{
|
||||||
|
if(! iequals(*it, "chunked"))
|
||||||
|
s.append(it->data(), it->size());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
s.append(it->data(), it->size());
|
||||||
|
for(;;)
|
||||||
|
{
|
||||||
|
it = next;
|
||||||
|
next = std::next(it);
|
||||||
|
if(next == te.end())
|
||||||
|
{
|
||||||
|
if(! iequals(*it, "chunked"))
|
||||||
|
{
|
||||||
|
s.append(", ");
|
||||||
|
s.append(it->data(), it->size());
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
s.append(", ");
|
||||||
|
s.append(it->data(), it->size());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} // detail
|
||||||
|
|
||||||
template<class Allocator>
|
template<class Allocator>
|
||||||
inline
|
|
||||||
void
|
void
|
||||||
basic_fields<Allocator>::
|
basic_fields<Allocator>::
|
||||||
set_chunked_impl(bool v)
|
prepare_payload_impl(bool chunked,
|
||||||
|
boost::optional<std::uint64_t> size)
|
||||||
{
|
{
|
||||||
// VFALCO We need to handle removing the chunked as well
|
if(chunked)
|
||||||
BOOST_ASSERT(v);
|
{
|
||||||
auto it = find(field::transfer_encoding);
|
BOOST_ASSERT(! size);
|
||||||
if(it == end())
|
erase(field::content_length);
|
||||||
insert(field::transfer_encoding, "chunked");
|
auto it = find(field::transfer_encoding);
|
||||||
|
if(it == end())
|
||||||
|
{
|
||||||
|
set(field::transfer_encoding, "chunked");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
static_string<max_static_buffer> temp;
|
||||||
|
if(it->value().size() <= temp.size() + 9)
|
||||||
|
{
|
||||||
|
temp.append(it->value().data(), it->value().size());
|
||||||
|
temp.append(", chunked", 9);
|
||||||
|
set(field::transfer_encoding, temp);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
std::string s;
|
||||||
|
s.reserve(it->value().size() + 9);
|
||||||
|
s.append(it->value().data(), it->value().size());
|
||||||
|
s.append(", chunked", 9);
|
||||||
|
set(field::transfer_encoding, s);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto const clear_chunked =
|
||||||
|
[this]()
|
||||||
|
{
|
||||||
|
auto it = find(field::transfer_encoding);
|
||||||
|
if(it == end())
|
||||||
|
return;
|
||||||
|
|
||||||
|
// We have to just try it because we can't
|
||||||
|
// know ahead of time if there's enough room.
|
||||||
|
try
|
||||||
|
{
|
||||||
|
static_string<max_static_buffer> temp;
|
||||||
|
detail::without_chunked_last(temp, it->value());
|
||||||
|
if(! temp.empty())
|
||||||
|
set(field::transfer_encoding, temp);
|
||||||
|
else
|
||||||
|
erase(field::transfer_encoding);
|
||||||
|
}
|
||||||
|
catch(std::length_error const&)
|
||||||
|
{
|
||||||
|
std::string s;
|
||||||
|
s.reserve(it->value().size());
|
||||||
|
detail::without_chunked_last(s, it->value());
|
||||||
|
if(! s.empty())
|
||||||
|
set(field::transfer_encoding, s);
|
||||||
|
else
|
||||||
|
erase(field::transfer_encoding);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if(size)
|
||||||
|
{
|
||||||
|
clear_chunked();
|
||||||
|
set(field::content_length, *size);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
set(field::transfer_encoding,
|
{
|
||||||
it->value().to_string() + ", chunked");
|
clear_chunked();
|
||||||
|
erase(field::content_length);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
@@ -252,69 +252,53 @@ message(std::piecewise_construct_t,
|
|||||||
template<bool isRequest, class Body, class Fields>
|
template<bool isRequest, class Body, class Fields>
|
||||||
boost::optional<std::uint64_t>
|
boost::optional<std::uint64_t>
|
||||||
message<isRequest, Body, Fields>::
|
message<isRequest, Body, Fields>::
|
||||||
size() const
|
payload_size() const
|
||||||
{
|
{
|
||||||
static_assert(is_body_reader<Body>::value,
|
return payload_size(detail::is_body_sized<Body>{});
|
||||||
"BodyReader requirements not met");
|
|
||||||
|
|
||||||
return size(detail::is_body_sized<Body>{});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<bool isRequest, class Body, class Fields>
|
template<bool isRequest, class Body, class Fields>
|
||||||
void
|
void
|
||||||
message<isRequest, Body, Fields>::
|
message<isRequest, Body, Fields>::
|
||||||
content_length(std::uint64_t n)
|
prepare_payload(std::true_type)
|
||||||
{
|
{
|
||||||
this->content_length_impl(n);
|
auto const n = payload_size();
|
||||||
}
|
if(this->method() == verb::trace && (! n || *n > 0))
|
||||||
|
|
||||||
template<bool isRequest, class Body, class Fields>
|
|
||||||
void
|
|
||||||
message<isRequest, Body, Fields>::
|
|
||||||
prepare()
|
|
||||||
{
|
|
||||||
prepare(typename header_type::is_request{});
|
|
||||||
}
|
|
||||||
|
|
||||||
template<bool isRequest, class Body, class Fields>
|
|
||||||
inline
|
|
||||||
void
|
|
||||||
message<isRequest, Body, Fields>::
|
|
||||||
prepare(std::true_type)
|
|
||||||
{
|
|
||||||
auto const n = size();
|
|
||||||
if(this->method_ == verb::trace && (
|
|
||||||
! n || *n > 0))
|
|
||||||
BOOST_THROW_EXCEPTION(std::invalid_argument{
|
BOOST_THROW_EXCEPTION(std::invalid_argument{
|
||||||
"invalid request body"});
|
"invalid request body"});
|
||||||
if(n)
|
if(n)
|
||||||
{
|
{
|
||||||
if(*n > 0 ||
|
if(*n > 0 ||
|
||||||
this->method_ == verb::options ||
|
this->method() == verb::options ||
|
||||||
this->method_ == verb::put ||
|
this->method() == verb::put ||
|
||||||
this->method_ == verb::post
|
this->method() == verb::post)
|
||||||
)
|
|
||||||
{
|
{
|
||||||
this->content_length_impl(*n);
|
this->prepare_payload_impl(false, *n);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this->prepare_payload_impl(false, boost::none);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if(this->version >= 11)
|
else if(this->version >= 11)
|
||||||
{
|
{
|
||||||
this->set_chunked_impl(true);
|
this->prepare_payload_impl(true, boost::none);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this->prepare_payload_impl(false, boost::none);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template<bool isRequest, class Body, class Fields>
|
template<bool isRequest, class Body, class Fields>
|
||||||
inline
|
|
||||||
void
|
void
|
||||||
message<isRequest, Body, Fields>::
|
message<isRequest, Body, Fields>::
|
||||||
prepare(std::false_type)
|
prepare_payload(std::false_type)
|
||||||
{
|
{
|
||||||
auto const n = size();
|
auto const n = payload_size();
|
||||||
if((status_class(this->result_) ==
|
if((status_class(this->result()) == status_class::informational ||
|
||||||
status_class::informational ||
|
this->result() == status::no_content ||
|
||||||
this->result_ == status::no_content ||
|
this->result() == status::not_modified))
|
||||||
this->result_ == status::not_modified))
|
|
||||||
{
|
{
|
||||||
if(! n || *n > 0)
|
if(! n || *n > 0)
|
||||||
// The response body MUST BE empty for this case
|
// The response body MUST BE empty for this case
|
||||||
@@ -322,9 +306,13 @@ prepare(std::false_type)
|
|||||||
"invalid response body"});
|
"invalid response body"});
|
||||||
}
|
}
|
||||||
if(n)
|
if(n)
|
||||||
this->content_length_impl(*n);
|
{
|
||||||
else if(this->version >= 11)
|
this->prepare_payload_impl(false, *n);
|
||||||
this->set_chunked_impl(true);
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this->prepare_payload_impl(true, boost::none);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
@@ -496,17 +496,8 @@ struct message : header<isRequest, Fields>
|
|||||||
is not inspected.
|
is not inspected.
|
||||||
*/
|
*/
|
||||||
boost::optional<std::uint64_t>
|
boost::optional<std::uint64_t>
|
||||||
size() const;
|
payload_size() const;
|
||||||
|
|
||||||
/** Set the Content-Length field.
|
|
||||||
|
|
||||||
The value of the Content-Length field will be unconditionally
|
|
||||||
set to the specified number of octets.
|
|
||||||
|
|
||||||
@param n The number of octets to set for the Content-Length field.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
content_length(std::uint64_t n);
|
|
||||||
|
|
||||||
/** Prepare the message payload fields for the body.
|
/** Prepare the message payload fields for the body.
|
||||||
|
|
||||||
@@ -522,11 +513,14 @@ struct message : header<isRequest, Fields>
|
|||||||
req.target("/");
|
req.target("/");
|
||||||
req.set(field::user_agent, "Beast");
|
req.set(field::user_agent, "Beast");
|
||||||
req.body = "Hello, world!";
|
req.body = "Hello, world!";
|
||||||
req.prepare();
|
req.prepare_payload();
|
||||||
@endcode
|
@endcode
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
prepare();
|
prepare_payload()
|
||||||
|
{
|
||||||
|
prepare_payload(typename header_type::is_request{});
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static_assert(is_body<Body>::value,
|
static_assert(is_body<Body>::value,
|
||||||
@@ -552,22 +546,22 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
boost::optional<std::uint64_t>
|
boost::optional<std::uint64_t>
|
||||||
size(std::true_type) const
|
payload_size(std::true_type) const
|
||||||
{
|
{
|
||||||
return Body::size(body);
|
return Body::size(body);
|
||||||
}
|
}
|
||||||
|
|
||||||
boost::optional<std::uint64_t>
|
boost::optional<std::uint64_t>
|
||||||
size(std::false_type) const
|
payload_size(std::false_type) const
|
||||||
{
|
{
|
||||||
return boost::none;
|
return boost::none;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
prepare(std::true_type);
|
prepare_payload(std::true_type);
|
||||||
|
|
||||||
void
|
void
|
||||||
prepare(std::false_type);
|
prepare_payload(std::false_type);
|
||||||
};
|
};
|
||||||
|
|
||||||
/// A typical HTTP request
|
/// A typical HTTP request
|
||||||
|
@@ -218,7 +218,7 @@ build_response(http::header<true,
|
|||||||
res.version = req.version;
|
res.version = req.version;
|
||||||
res.result(http::status::bad_request);
|
res.result(http::status::bad_request);
|
||||||
res.body = text;
|
res.body = text;
|
||||||
res.prepare();
|
res.prepare_payload();
|
||||||
decorate(res);
|
decorate(res);
|
||||||
return res;
|
return res;
|
||||||
};
|
};
|
||||||
@@ -248,7 +248,7 @@ build_response(http::header<true,
|
|||||||
res.result(http::status::upgrade_required);
|
res.result(http::status::upgrade_required);
|
||||||
res.version = req.version;
|
res.version = req.version;
|
||||||
res.set(http::field::sec_websocket_version, "13");
|
res.set(http::field::sec_websocket_version, "13");
|
||||||
res.prepare();
|
res.prepare_payload();
|
||||||
decorate(res);
|
decorate(res);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
@@ -73,7 +73,7 @@ public:
|
|||||||
req.target("/");
|
req.target("/");
|
||||||
req.insert(field::user_agent, "test");
|
req.insert(field::user_agent, "test");
|
||||||
req.body = "Hello, world!";
|
req.body = "Hello, world!";
|
||||||
req.prepare();
|
req.prepare_payload();
|
||||||
|
|
||||||
error_code ec;
|
error_code ec;
|
||||||
send_expect_100_continue(
|
send_expect_100_continue(
|
||||||
@@ -106,7 +106,7 @@ public:
|
|||||||
req.target("/");
|
req.target("/");
|
||||||
req.insert(field::user_agent, "test");
|
req.insert(field::user_agent, "test");
|
||||||
req.body = "Hello, world!";
|
req.body = "Hello, world!";
|
||||||
req.prepare();
|
req.prepare_payload();
|
||||||
|
|
||||||
test::pipe downstream{ios_};
|
test::pipe downstream{ios_};
|
||||||
downstream.server.read_size(3);
|
downstream.server.read_size(3);
|
||||||
@@ -272,7 +272,7 @@ public:
|
|||||||
req.method(verb::put);
|
req.method(verb::put);
|
||||||
req.target("/");
|
req.target("/");
|
||||||
req.body = body;
|
req.body = body;
|
||||||
req.prepare();
|
req.prepare_payload();
|
||||||
write(c.client, req);
|
write(c.client, req);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
@@ -293,7 +293,7 @@ public:
|
|||||||
res.result(status::ok);
|
res.result(status::ok);
|
||||||
res.insert(field::server, "test");
|
res.insert(field::server, "test");
|
||||||
res.body = path;
|
res.body = path;
|
||||||
res.prepare();
|
res.prepare_payload();
|
||||||
write(c.server, res);
|
write(c.server, res);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
|
@@ -49,7 +49,7 @@ void fxx() {
|
|||||||
res.result(status::ok);
|
res.result(status::ok);
|
||||||
res.set(field::server, "Beast");
|
res.set(field::server, "Beast");
|
||||||
res.body = "Hello, world!";
|
res.body = "Hello, world!";
|
||||||
res.prepare();
|
res.prepare_payload();
|
||||||
|
|
||||||
//]
|
//]
|
||||||
}
|
}
|
||||||
|
@@ -8,6 +8,8 @@
|
|||||||
// Test that header file is self-contained.
|
// Test that header file is self-contained.
|
||||||
#include <beast/http/fields.hpp>
|
#include <beast/http/fields.hpp>
|
||||||
|
|
||||||
|
#include <beast/http/empty_body.hpp>
|
||||||
|
#include <beast/http/message.hpp>
|
||||||
#include <beast/test/test_allocator.hpp>
|
#include <beast/test/test_allocator.hpp>
|
||||||
#include <beast/unit_test/suite.hpp>
|
#include <beast/unit_test/suite.hpp>
|
||||||
#include <boost/lexical_cast.hpp>
|
#include <boost/lexical_cast.hpp>
|
||||||
@@ -397,6 +399,188 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct sized_body
|
||||||
|
{
|
||||||
|
using value_type = std::uint64_t;
|
||||||
|
|
||||||
|
static
|
||||||
|
std::uint64_t
|
||||||
|
size(value_type const& v)
|
||||||
|
{
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct unsized_body
|
||||||
|
{
|
||||||
|
struct value_type {};
|
||||||
|
};
|
||||||
|
|
||||||
|
void
|
||||||
|
testPreparePayload()
|
||||||
|
{
|
||||||
|
// GET, empty
|
||||||
|
{
|
||||||
|
request<empty_body> req;
|
||||||
|
req.version = 11;
|
||||||
|
req.method(verb::get);
|
||||||
|
|
||||||
|
req.prepare_payload();
|
||||||
|
BEAST_EXPECT(req.count(field::content_length) == 0);
|
||||||
|
BEAST_EXPECT(req.count(field::transfer_encoding) == 0);
|
||||||
|
|
||||||
|
req.set(field::content_length, "0");
|
||||||
|
req.set(field::transfer_encoding, "chunked");
|
||||||
|
req.prepare_payload();
|
||||||
|
|
||||||
|
BEAST_EXPECT(req.count(field::content_length) == 0);
|
||||||
|
BEAST_EXPECT(req.count(field::transfer_encoding) == 0);
|
||||||
|
|
||||||
|
req.set(field::transfer_encoding, "deflate");
|
||||||
|
req.prepare_payload();
|
||||||
|
BEAST_EXPECT(req.count(field::content_length) == 0);
|
||||||
|
BEAST_EXPECT(req[field::transfer_encoding] == "deflate");
|
||||||
|
|
||||||
|
req.set(field::transfer_encoding, "deflate, chunked");
|
||||||
|
req.prepare_payload();
|
||||||
|
BEAST_EXPECT(req.count(field::content_length) == 0);
|
||||||
|
BEAST_EXPECT(req[field::transfer_encoding] == "deflate");
|
||||||
|
}
|
||||||
|
|
||||||
|
// GET, sized
|
||||||
|
{
|
||||||
|
request<sized_body> req;
|
||||||
|
req.version = 11;
|
||||||
|
req.method(verb::get);
|
||||||
|
req.body = 50;
|
||||||
|
|
||||||
|
req.prepare_payload();
|
||||||
|
BEAST_EXPECT(req[field::content_length] == "50");
|
||||||
|
BEAST_EXPECT(req[field::transfer_encoding] == "");
|
||||||
|
|
||||||
|
req.set(field::content_length, "0");
|
||||||
|
req.set(field::transfer_encoding, "chunked");
|
||||||
|
req.prepare_payload();
|
||||||
|
BEAST_EXPECT(req[field::content_length] == "50");
|
||||||
|
BEAST_EXPECT(req.count(field::transfer_encoding) == 0);
|
||||||
|
|
||||||
|
req.set(field::transfer_encoding, "deflate, chunked");
|
||||||
|
req.prepare_payload();
|
||||||
|
BEAST_EXPECT(req[field::content_length] == "50");
|
||||||
|
BEAST_EXPECT(req[field::transfer_encoding] == "deflate");
|
||||||
|
}
|
||||||
|
|
||||||
|
// PUT, empty
|
||||||
|
{
|
||||||
|
request<empty_body> req;
|
||||||
|
req.version = 11;
|
||||||
|
req.method(verb::put);
|
||||||
|
|
||||||
|
req.prepare_payload();
|
||||||
|
BEAST_EXPECT(req[field::content_length] == "0");
|
||||||
|
BEAST_EXPECT(req.count(field::transfer_encoding) == 0);
|
||||||
|
|
||||||
|
req.set(field::content_length, "50");
|
||||||
|
req.set(field::transfer_encoding, "deflate, chunked");
|
||||||
|
req.prepare_payload();
|
||||||
|
BEAST_EXPECT(req[field::content_length] == "0");
|
||||||
|
BEAST_EXPECT(req[field::transfer_encoding] == "deflate");
|
||||||
|
}
|
||||||
|
|
||||||
|
// PUT, sized
|
||||||
|
{
|
||||||
|
request<sized_body> req;
|
||||||
|
req.version = 11;
|
||||||
|
req.method(verb::put);
|
||||||
|
req.body = 50;
|
||||||
|
|
||||||
|
req.prepare_payload();
|
||||||
|
BEAST_EXPECT(req[field::content_length] == "50");
|
||||||
|
BEAST_EXPECT(req.count(field::transfer_encoding) == 0);
|
||||||
|
|
||||||
|
req.set(field::content_length, "25");
|
||||||
|
req.set(field::transfer_encoding, "deflate, chunked");
|
||||||
|
req.prepare_payload();
|
||||||
|
BEAST_EXPECT(req[field::content_length] == "50");
|
||||||
|
BEAST_EXPECT(req[field::transfer_encoding] == "deflate");
|
||||||
|
}
|
||||||
|
|
||||||
|
// POST, unsized
|
||||||
|
{
|
||||||
|
request<unsized_body> req;
|
||||||
|
req.version = 11;
|
||||||
|
req.method(verb::post);
|
||||||
|
|
||||||
|
req.prepare_payload();
|
||||||
|
BEAST_EXPECT(req.count(field::content_length) == 0);
|
||||||
|
BEAST_EXPECT(req[field::transfer_encoding] == "chunked");
|
||||||
|
|
||||||
|
req.set(field::transfer_encoding, "deflate");
|
||||||
|
req.prepare_payload();
|
||||||
|
BEAST_EXPECT(req.count(field::content_length) == 0);
|
||||||
|
BEAST_EXPECT(req[field::transfer_encoding] == "deflate, chunked");
|
||||||
|
}
|
||||||
|
|
||||||
|
// POST, unsized HTTP/1.0
|
||||||
|
{
|
||||||
|
request<unsized_body> req;
|
||||||
|
req.version = 10;
|
||||||
|
req.method(verb::post);
|
||||||
|
|
||||||
|
req.prepare_payload();
|
||||||
|
BEAST_EXPECT(req.count(field::content_length) == 0);
|
||||||
|
BEAST_EXPECT(req.count(field::transfer_encoding) == 0);
|
||||||
|
|
||||||
|
req.set(field::transfer_encoding, "deflate");
|
||||||
|
req.prepare_payload();
|
||||||
|
BEAST_EXPECT(req.count(field::content_length) == 0);
|
||||||
|
BEAST_EXPECT(req[field::transfer_encoding] == "deflate");
|
||||||
|
}
|
||||||
|
|
||||||
|
// OK, empty
|
||||||
|
{
|
||||||
|
response<empty_body> res;
|
||||||
|
res.version = 11;
|
||||||
|
|
||||||
|
res.prepare_payload();
|
||||||
|
BEAST_EXPECT(res[field::content_length] == "0");
|
||||||
|
BEAST_EXPECT(res.count(field::transfer_encoding) == 0);
|
||||||
|
|
||||||
|
res.erase(field::content_length);
|
||||||
|
res.set(field::transfer_encoding, "chunked");
|
||||||
|
res.prepare_payload();
|
||||||
|
BEAST_EXPECT(res[field::content_length] == "0");
|
||||||
|
BEAST_EXPECT(res.count(field::transfer_encoding) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// OK, sized
|
||||||
|
{
|
||||||
|
response<sized_body> res;
|
||||||
|
res.version = 11;
|
||||||
|
res.body = 50;
|
||||||
|
|
||||||
|
res.prepare_payload();
|
||||||
|
BEAST_EXPECT(res[field::content_length] == "50");
|
||||||
|
BEAST_EXPECT(res.count(field::transfer_encoding) == 0);
|
||||||
|
|
||||||
|
res.erase(field::content_length);
|
||||||
|
res.set(field::transfer_encoding, "chunked");
|
||||||
|
res.prepare_payload();
|
||||||
|
BEAST_EXPECT(res[field::content_length] == "50");
|
||||||
|
BEAST_EXPECT(res.count(field::transfer_encoding) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// OK, unsized
|
||||||
|
{
|
||||||
|
response<unsized_body> res;
|
||||||
|
res.version = 11;
|
||||||
|
|
||||||
|
res.prepare_payload();
|
||||||
|
BEAST_EXPECT(res.count(field::content_length) == 0);
|
||||||
|
BEAST_EXPECT(res[field::transfer_encoding] == "chunked");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void run() override
|
void run() override
|
||||||
{
|
{
|
||||||
testMembers();
|
testMembers();
|
||||||
@@ -404,6 +588,7 @@ public:
|
|||||||
testRFC2616();
|
testRFC2616();
|
||||||
testErase();
|
testErase();
|
||||||
testContainer();
|
testContainer();
|
||||||
|
testPreparePayload();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -31,7 +31,7 @@ public:
|
|||||||
req.version = 11;
|
req.version = 11;
|
||||||
req.method(verb::post);
|
req.method(verb::post);
|
||||||
req.target("/");
|
req.target("/");
|
||||||
req.prepare();
|
req.prepare_payload();
|
||||||
static_buffer_n<512> b;
|
static_buffer_n<512> b;
|
||||||
ostream(b) << req;
|
ostream(b) << req;
|
||||||
string_view const s{
|
string_view const s{
|
||||||
|
@@ -532,7 +532,7 @@ public:
|
|||||||
m.version = 10;
|
m.version = 10;
|
||||||
m.insert(field::user_agent, "test");
|
m.insert(field::user_agent, "test");
|
||||||
m.body = "*";
|
m.body = "*";
|
||||||
m.prepare();
|
m.prepare_payload();
|
||||||
BEAST_EXPECT(str(m) ==
|
BEAST_EXPECT(str(m) ==
|
||||||
"GET / HTTP/1.0\r\n"
|
"GET / HTTP/1.0\r\n"
|
||||||
"User-Agent: test\r\n"
|
"User-Agent: test\r\n"
|
||||||
@@ -549,7 +549,7 @@ public:
|
|||||||
m.version = 10;
|
m.version = 10;
|
||||||
m.insert(field::user_agent, "test");
|
m.insert(field::user_agent, "test");
|
||||||
m.body = "*";
|
m.body = "*";
|
||||||
m.prepare();
|
m.prepare_payload();
|
||||||
test::string_ostream ss(ios_);
|
test::string_ostream ss(ios_);
|
||||||
error_code ec;
|
error_code ec;
|
||||||
write(ss, m, ec);
|
write(ss, m, ec);
|
||||||
@@ -569,7 +569,7 @@ public:
|
|||||||
m.version = 11;
|
m.version = 11;
|
||||||
m.insert(field::user_agent, "test");
|
m.insert(field::user_agent, "test");
|
||||||
m.body = "*";
|
m.body = "*";
|
||||||
m.prepare();
|
m.prepare_payload();
|
||||||
BEAST_EXPECT(str(m) ==
|
BEAST_EXPECT(str(m) ==
|
||||||
"GET / HTTP/1.1\r\n"
|
"GET / HTTP/1.1\r\n"
|
||||||
"User-Agent: test\r\n"
|
"User-Agent: test\r\n"
|
||||||
@@ -586,7 +586,7 @@ public:
|
|||||||
m.version = 11;
|
m.version = 11;
|
||||||
m.insert(field::user_agent, "test");
|
m.insert(field::user_agent, "test");
|
||||||
m.body = "*";
|
m.body = "*";
|
||||||
m.prepare();
|
m.prepare_payload();
|
||||||
test::string_ostream ss(ios_);
|
test::string_ostream ss(ios_);
|
||||||
error_code ec;
|
error_code ec;
|
||||||
write(ss, m, ec);
|
write(ss, m, ec);
|
||||||
|
Reference in New Issue
Block a user