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:
Vinnie Falco committed 2017-07-20 08:15:27 -07:00
1 parent f9f6e1e0cc
commit 56a561da9a
20 files changed
+398 -114

No files matched your search

+106 -18
View File
@@ -9,6 +9,7 @@
#define BEAST_HTTP_IMPL_FIELDS_IPP
#include <beast/core/buffer_cat.hpp>
#include <beast/core/string.hpp>
#include <beast/core/static_string.hpp>
#include <beast/http/verb.hpp>
#include <beast/http/rfc7230.hpp>
@@ -149,7 +150,7 @@ public:
unsigned version, unsigned code);
basic_fields const& f_;
static_string<max_static_start_line> ss_;
static_string<max_static_buffer> ss_;
string_view sv_;
std::string s_;
bool chunked_;
@@ -199,7 +200,7 @@ get_chunked() const
f_[field::transfer_encoding]};
for(auto it = te.begin(); it != te.end();)
{
auto next = std::next(it);
auto const next = std::next(it);
if(next == te.end())
return iequals(*it, "chunked");
it = next;
@@ -866,32 +867,119 @@ get_reason_impl() const
return target_or_reason_;
}
//---
namespace detail {
template<class Allocator>
inline
// Builds a new string with "chunked" maybe taken off the end
template<class String>
void
basic_fields<Allocator>::
content_length_impl(std::uint64_t n)
without_chunked_last(String& s, string_view const& tokens)
{
erase(field::content_length);
insert(field::content_length, n);
token_list te{tokens};
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>
inline
void
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
BOOST_ASSERT(v);
auto it = find(field::transfer_encoding);
if(it == end())
insert(field::transfer_encoding, "chunked");
if(chunked)
{
BOOST_ASSERT(! size);
erase(field::content_length);
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
set(field::transfer_encoding,
it->value().to_string() + ", chunked");
{
clear_chunked();
erase(field::content_length);
}
}
//------------------------------------------------------------------------------
+30 -42
View File
@@ -252,69 +252,53 @@ message(std::piecewise_construct_t,
template<bool isRequest, class Body, class Fields>
boost::optional<std::uint64_t>
message<isRequest, Body, Fields>::
size() const
payload_size() const
{
static_assert(is_body_reader<Body>::value,
"BodyReader requirements not met");
return size(detail::is_body_sized<Body>{});
return payload_size(detail::is_body_sized<Body>{});
}
template<bool isRequest, class Body, class Fields>
void
message<isRequest, Body, Fields>::
content_length(std::uint64_t n)
prepare_payload(std::true_type)
{
this->content_length_impl(n);
}
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))
auto const n = payload_size();
if(this->method() == verb::trace && (! n || *n > 0))
BOOST_THROW_EXCEPTION(std::invalid_argument{
"invalid request body"});
if(n)
{
if(*n > 0 ||
this->method_ == verb::options ||
this->method_ == verb::put ||
this->method_ == verb::post
)
this->method() == verb::options ||
this->method() == verb::put ||
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)
{
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>
inline
void
message<isRequest, Body, Fields>::
prepare(std::false_type)
prepare_payload(std::false_type)
{
auto const n = size();
if((status_class(this->result_) ==
status_class::informational ||
this->result_ == status::no_content ||
this->result_ == status::not_modified))
auto const n = payload_size();
if((status_class(this->result()) == status_class::informational ||
this->result() == status::no_content ||
this->result() == status::not_modified))
{
if(! n || *n > 0)
// The response body MUST BE empty for this case
@@ -322,9 +306,13 @@ prepare(std::false_type)
"invalid response body"});
}
if(n)
this->content_length_impl(*n);
else if(this->version >= 11)
this->set_chunked_impl(true);
{
this->prepare_payload_impl(false, *n);
}
else
{
this->prepare_payload_impl(true, boost::none);
}
}
//------------------------------------------------------------------------------