forked from boostorg/beast
Add message keep_alive, chunked, content_length members
This commit is contained in:
1 parent
aa473a6da4
commit
6a46e48424
15 files changed
+1025
-325
No files matched your search
@@ -53,13 +53,17 @@ struct fields_model
|
||||
string_view target() const;
|
||||
|
||||
protected:
|
||||
void set_method_impl(string_view s);
|
||||
void set_target_impl(string_view s);
|
||||
void set_reason_impl(string_view s);
|
||||
string_view get_method_impl() const;
|
||||
string_view get_target_impl() const;
|
||||
string_view get_reason_impl() const;
|
||||
void prepare_payload_impl(bool b, boost::optional<std::uint64_t> n);
|
||||
bool get_chunked_impl() const;
|
||||
bool get_keep_alive_impl(unsigned) const;
|
||||
void set_method_impl(string_view);
|
||||
void set_target_impl(string_view);
|
||||
void set_reason_impl(string_view);
|
||||
void set_chunked_impl(bool);
|
||||
void set_content_length_impl(boost::optional<std::uint64_t>);
|
||||
void set_keep_alive_impl(unsigned, bool);
|
||||
};
|
||||
|
||||
template<class T, class = beast::detail::void_t<>>
|
||||
@@ -91,60 +95,90 @@ struct is_fields_helper : T
|
||||
{
|
||||
template<class U = is_fields_helper>
|
||||
static auto f1(int) -> decltype(
|
||||
void(std::declval<U&>().set_method_impl(std::declval<string_view>())),
|
||||
std::declval<string_view&>() = std::declval<U const&>().get_method_impl(),
|
||||
std::true_type());
|
||||
static auto f1(...) -> std::false_type;
|
||||
using t1 = decltype(f1(0));
|
||||
|
||||
template<class U = is_fields_helper>
|
||||
static auto f2(int) -> decltype(
|
||||
void(std::declval<U&>().set_target_impl(std::declval<string_view>())),
|
||||
std::declval<string_view&>() = std::declval<U const&>().get_target_impl(),
|
||||
std::true_type());
|
||||
static auto f2(...) -> std::false_type;
|
||||
using t2 = decltype(f2(0));
|
||||
|
||||
template<class U = is_fields_helper>
|
||||
static auto f3(int) -> decltype(
|
||||
void(std::declval<U&>().set_reason_impl(std::declval<string_view>())),
|
||||
std::declval<string_view&>() = std::declval<U const&>().get_reason_impl(),
|
||||
std::true_type());
|
||||
static auto f3(...) -> std::false_type;
|
||||
using t3 = decltype(f3(0));
|
||||
|
||||
template<class U = is_fields_helper>
|
||||
static auto f4(int) -> decltype(
|
||||
std::declval<string_view&>() = std::declval<U&>().get_method_impl(),
|
||||
std::declval<bool&>() = std::declval<U const&>().get_chunked_impl(),
|
||||
std::true_type());
|
||||
static auto f4(...) -> std::false_type;
|
||||
using t4 = decltype(f4(0));
|
||||
|
||||
template<class U = is_fields_helper>
|
||||
static auto f5(int) -> decltype(
|
||||
std::declval<string_view&>() = std::declval<U&>().get_target_impl(),
|
||||
std::declval<bool&>() = std::declval<U const&>().get_keep_alive_impl(
|
||||
std::declval<unsigned>()),
|
||||
std::true_type());
|
||||
static auto f5(...) -> std::false_type;
|
||||
using t5 = decltype(f5(0));
|
||||
|
||||
template<class U = is_fields_helper>
|
||||
static auto f6(int) -> decltype(
|
||||
std::declval<string_view&>() = std::declval<U&>().get_reason_impl(),
|
||||
void(std::declval<U&>().set_method_impl(std::declval<string_view>())),
|
||||
std::true_type());
|
||||
static auto f6(...) -> std::false_type;
|
||||
using t6 = decltype(f6(0));
|
||||
|
||||
template<class U = is_fields_helper>
|
||||
static auto f7(int) -> decltype(
|
||||
void(std::declval<U&>().prepare_payload_impl(
|
||||
std::declval<bool>(),
|
||||
std::declval<boost::optional<std::uint64_t>>())),
|
||||
void(std::declval<U&>().set_target_impl(std::declval<string_view>())),
|
||||
std::true_type());
|
||||
static auto f7(...) -> std::false_type;
|
||||
using t7 = decltype(f7(0));
|
||||
|
||||
template<class U = is_fields_helper>
|
||||
static auto f8(int) -> decltype(
|
||||
void(std::declval<U&>().set_reason_impl(std::declval<string_view>())),
|
||||
std::true_type());
|
||||
static auto f8(...) -> std::false_type;
|
||||
using t8 = decltype(f8(0));
|
||||
|
||||
template<class U = is_fields_helper>
|
||||
static auto f9(int) -> decltype(
|
||||
void(std::declval<U&>().set_chunked_impl(std::declval<bool>())),
|
||||
std::true_type());
|
||||
static auto f9(...) -> std::false_type;
|
||||
using t9 = decltype(f9(0));
|
||||
|
||||
template<class U = is_fields_helper>
|
||||
static auto f10(int) -> decltype(
|
||||
void(std::declval<U&>().set_content_length_impl(
|
||||
std::declval<boost::optional<std::uint64_t>>())),
|
||||
std::true_type());
|
||||
static auto f10(...) -> std::false_type;
|
||||
using t10 = decltype(f10(0));
|
||||
|
||||
template<class U = is_fields_helper>
|
||||
static auto f11(int) -> decltype(
|
||||
void(std::declval<U&>().set_keep_alive_impl(
|
||||
std::declval<unsigned>(),
|
||||
std::declval<bool>())),
|
||||
std::true_type());
|
||||
static auto f11(...) -> std::false_type;
|
||||
using t11 = decltype(f11(0));
|
||||
|
||||
using type = std::integral_constant<bool,
|
||||
t1::value && t2::value && t3::value &&
|
||||
t4::value && t5::value && t6::value &&
|
||||
t7::value
|
||||
>;
|
||||
t1::value && t2::value && t3::value &&
|
||||
t4::value && t5::value && t6::value &&
|
||||
t7::value && t8::value && t9::value &&
|
||||
t10::value && t11::value>;
|
||||
};
|
||||
|
||||
} // detail
|
||||
|
||||
@@ -567,47 +567,74 @@ public:
|
||||
}
|
||||
|
||||
protected:
|
||||
/** 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);
|
||||
|
||||
/** Returns the request-method string.
|
||||
|
||||
@note Only called for requests.
|
||||
*/
|
||||
string_view get_method_impl() const;
|
||||
string_view
|
||||
get_method_impl() const;
|
||||
|
||||
/** Returns the request-target string.
|
||||
|
||||
@note Only called for requests.
|
||||
*/
|
||||
string_view get_target_impl() const;
|
||||
string_view
|
||||
get_target_impl() const;
|
||||
|
||||
/** Returns the response reason-phrase string.
|
||||
|
||||
@note Only called for responses.
|
||||
*/
|
||||
string_view get_reason_impl() const;
|
||||
string_view
|
||||
get_reason_impl() const;
|
||||
|
||||
/** Adjusts the payload related fields
|
||||
/** Returns the chunked Transfer-Encoding setting
|
||||
*/
|
||||
bool
|
||||
get_chunked_impl() const;
|
||||
|
||||
/** Returns the keep-alive setting
|
||||
*/
|
||||
bool
|
||||
get_keep_alive_impl(unsigned version) const;
|
||||
|
||||
/** Set or clear the method string.
|
||||
|
||||
@note Only called for requests.
|
||||
*/
|
||||
void
|
||||
prepare_payload_impl(bool chunked,
|
||||
boost::optional<std::uint64_t> size);
|
||||
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);
|
||||
|
||||
/** Adjusts 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> const& value);
|
||||
|
||||
/** Adjusts the Connection field
|
||||
*/
|
||||
void
|
||||
set_keep_alive_impl(
|
||||
unsigned version, bool keep_alive);
|
||||
|
||||
private:
|
||||
template<class OtherAlloc>
|
||||
|
||||
+324
-167
@@ -19,6 +19,13 @@
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
#if defined(BOOST_LIBSTDCXX_VERSION) && BOOST_LIBSTDCXX_VERSION < 60000
|
||||
// Workaround for https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56437
|
||||
#ifndef BEAST_HTTP_NO_FIELDS_BASIC_STRING_ALLOCATOR
|
||||
#define BEAST_HTTP_NO_FIELDS_BASIC_STRING_ALLOCATOR
|
||||
#endif
|
||||
#endif
|
||||
|
||||
namespace beast {
|
||||
namespace http {
|
||||
|
||||
@@ -133,17 +140,9 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
bool
|
||||
get_chunked() const;
|
||||
|
||||
bool
|
||||
get_keep_alive(int version) const;
|
||||
|
||||
basic_fields const& f_;
|
||||
boost::asio::const_buffer cb_[3];
|
||||
char buf_[13];
|
||||
bool chunked_;
|
||||
bool keep_alive_;
|
||||
|
||||
public:
|
||||
using const_buffers_type =
|
||||
@@ -160,18 +159,6 @@ public:
|
||||
reader(basic_fields const& f,
|
||||
unsigned version, unsigned code);
|
||||
|
||||
bool
|
||||
chunked()
|
||||
{
|
||||
return chunked_;
|
||||
}
|
||||
|
||||
bool
|
||||
keep_alive()
|
||||
{
|
||||
return keep_alive_;
|
||||
}
|
||||
|
||||
const_buffers_type
|
||||
get() const
|
||||
{
|
||||
@@ -184,48 +171,11 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
template<class Allocator>
|
||||
bool
|
||||
basic_fields<Allocator>::reader::
|
||||
get_chunked() const
|
||||
{
|
||||
auto const te = token_list{
|
||||
f_[field::transfer_encoding]};
|
||||
for(auto it = te.begin(); it != te.end();)
|
||||
{
|
||||
auto const next = std::next(it);
|
||||
if(next == te.end())
|
||||
return iequals(*it, "chunked");
|
||||
it = next;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
template<class Allocator>
|
||||
bool
|
||||
basic_fields<Allocator>::reader::
|
||||
get_keep_alive(int version) const
|
||||
{
|
||||
if(version < 11)
|
||||
{
|
||||
auto const it = f_.find(field::connection);
|
||||
if(it == f_.end())
|
||||
return false;
|
||||
return token_list{it->value()}.exists("keep-alive");
|
||||
}
|
||||
auto const it = f_.find(field::connection);
|
||||
if(it == f_.end())
|
||||
return true;
|
||||
return ! token_list{it->value()}.exists("close");
|
||||
}
|
||||
|
||||
template<class Allocator>
|
||||
basic_fields<Allocator>::reader::
|
||||
reader(basic_fields const& f,
|
||||
unsigned version, verb v)
|
||||
: f_(f)
|
||||
, chunked_(get_chunked())
|
||||
, keep_alive_(get_keep_alive(version))
|
||||
{
|
||||
/*
|
||||
request
|
||||
@@ -264,8 +214,6 @@ basic_fields<Allocator>::reader::
|
||||
reader(basic_fields const& f,
|
||||
unsigned version, unsigned code)
|
||||
: f_(f)
|
||||
, chunked_(get_chunked())
|
||||
, keep_alive_(get_keep_alive(version))
|
||||
{
|
||||
/*
|
||||
response
|
||||
@@ -761,37 +709,145 @@ equal_range(string_view name) const ->
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace detail {
|
||||
|
||||
// Filter a token list
|
||||
//
|
||||
template<class String, class Pred>
|
||||
void
|
||||
filter_token_list(
|
||||
String& s,
|
||||
string_view const& value,
|
||||
Pred&& pred)
|
||||
{
|
||||
token_list te{value};
|
||||
auto it = te.begin();
|
||||
auto last = te.end();
|
||||
if(it == last)
|
||||
return;
|
||||
while(pred(*it))
|
||||
if(++it == last)
|
||||
return;
|
||||
s.append(it->data(), it->size());
|
||||
while(++it != last)
|
||||
{
|
||||
if(! pred(*it))
|
||||
{
|
||||
s.append(", ");
|
||||
s.append(it->data(), it->size());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Filter the last item in a token list
|
||||
template<class String, class Pred>
|
||||
void
|
||||
filter_token_list_last(
|
||||
String& s,
|
||||
string_view const& value,
|
||||
Pred&& pred)
|
||||
{
|
||||
token_list te{value};
|
||||
if(te.begin() != te.end())
|
||||
{
|
||||
auto it = te.begin();
|
||||
auto next = std::next(it);
|
||||
if(next == te.end())
|
||||
{
|
||||
if(! pred(*it))
|
||||
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(! pred(*it))
|
||||
{
|
||||
s.append(", ");
|
||||
s.append(it->data(), it->size());
|
||||
}
|
||||
return;
|
||||
}
|
||||
s.append(", ");
|
||||
s.append(it->data(), it->size());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<class String>
|
||||
void
|
||||
keep_alive_impl(
|
||||
String& s, string_view const& value,
|
||||
unsigned version, bool keep_alive)
|
||||
{
|
||||
if(version < 11)
|
||||
{
|
||||
if(keep_alive)
|
||||
{
|
||||
// remove close
|
||||
filter_token_list(s, value,
|
||||
[](string_view s)
|
||||
{
|
||||
return iequals(s, "close");
|
||||
});
|
||||
// add keep-alive
|
||||
if(s.empty())
|
||||
s.append("keep-alive");
|
||||
else if(! token_list{value}.exists("keep-alive"))
|
||||
s.append(", keep-alive");
|
||||
}
|
||||
else
|
||||
{
|
||||
// remove close and keep-alive
|
||||
filter_token_list(s, value,
|
||||
[](string_view s)
|
||||
{
|
||||
return
|
||||
iequals(s, "close") ||
|
||||
iequals(s, "keep-alive");
|
||||
});
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(keep_alive)
|
||||
{
|
||||
// remove close and keep-alive
|
||||
filter_token_list(s, value,
|
||||
[](string_view s)
|
||||
{
|
||||
return
|
||||
iequals(s, "close") ||
|
||||
iequals(s, "keep-alive");
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
// remove keep-alive
|
||||
filter_token_list(s, value,
|
||||
[](string_view s)
|
||||
{
|
||||
return iequals(s, "keep-alive");
|
||||
});
|
||||
// add close
|
||||
if(s.empty())
|
||||
s.append("close");
|
||||
else if(! token_list{value}.exists("close"))
|
||||
s.append(", close");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // detail
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// Fields
|
||||
|
||||
template<class Allocator>
|
||||
inline
|
||||
void
|
||||
basic_fields<Allocator>::
|
||||
set_method_impl(string_view s)
|
||||
{
|
||||
realloc_string(method_, s);
|
||||
}
|
||||
|
||||
template<class Allocator>
|
||||
inline
|
||||
void
|
||||
basic_fields<Allocator>::
|
||||
set_target_impl(string_view s)
|
||||
{
|
||||
realloc_target(
|
||||
target_or_reason_, s);
|
||||
}
|
||||
|
||||
template<class Allocator>
|
||||
inline
|
||||
void
|
||||
basic_fields<Allocator>::
|
||||
set_reason_impl(string_view s)
|
||||
{
|
||||
realloc_string(
|
||||
target_or_reason_, s);
|
||||
}
|
||||
|
||||
template<class Allocator>
|
||||
inline
|
||||
string_view
|
||||
@@ -823,73 +879,118 @@ get_reason_impl() const
|
||||
return target_or_reason_;
|
||||
}
|
||||
|
||||
namespace detail {
|
||||
|
||||
// Builds a new string with "chunked" taken off the end if present
|
||||
template<class String>
|
||||
void
|
||||
without_chunked_last(String& s, string_view const& tokens)
|
||||
template<class Allocator>
|
||||
bool
|
||||
basic_fields<Allocator>::
|
||||
get_chunked_impl() const
|
||||
{
|
||||
token_list te{tokens};
|
||||
if(te.begin() != te.end())
|
||||
auto const te = token_list{
|
||||
(*this)[field::transfer_encoding]};
|
||||
for(auto it = te.begin(); it != te.end();)
|
||||
{
|
||||
auto it = te.begin();
|
||||
auto next = std::next(it);
|
||||
auto const 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());
|
||||
}
|
||||
return iequals(*it, "chunked");
|
||||
it = next;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
} // detail
|
||||
template<class Allocator>
|
||||
bool
|
||||
basic_fields<Allocator>::
|
||||
get_keep_alive_impl(unsigned version) const
|
||||
{
|
||||
auto const it = find(field::connection);
|
||||
if(version < 11)
|
||||
{
|
||||
if(it == end())
|
||||
return false;
|
||||
return token_list{
|
||||
it->value()}.exists("keep-alive");
|
||||
}
|
||||
if(it == end())
|
||||
return true;
|
||||
return ! token_list{
|
||||
it->value()}.exists("close");
|
||||
}
|
||||
|
||||
template<class Allocator>
|
||||
inline
|
||||
void
|
||||
basic_fields<Allocator>::
|
||||
set_method_impl(string_view s)
|
||||
{
|
||||
realloc_string(method_, s);
|
||||
}
|
||||
|
||||
template<class Allocator>
|
||||
inline
|
||||
void
|
||||
basic_fields<Allocator>::
|
||||
set_target_impl(string_view s)
|
||||
{
|
||||
realloc_target(
|
||||
target_or_reason_, s);
|
||||
}
|
||||
|
||||
template<class Allocator>
|
||||
inline
|
||||
void
|
||||
basic_fields<Allocator>::
|
||||
set_reason_impl(string_view s)
|
||||
{
|
||||
realloc_string(
|
||||
target_or_reason_, s);
|
||||
}
|
||||
|
||||
template<class Allocator>
|
||||
void
|
||||
basic_fields<Allocator>::
|
||||
prepare_payload_impl(bool chunked,
|
||||
boost::optional<std::uint64_t> size)
|
||||
set_chunked_impl(bool value)
|
||||
{
|
||||
if(chunked)
|
||||
auto it = find(field::transfer_encoding);
|
||||
if(value)
|
||||
{
|
||||
BOOST_ASSERT(! size);
|
||||
erase(field::content_length);
|
||||
auto it = find(field::transfer_encoding);
|
||||
// append "chunked"
|
||||
if(it == end())
|
||||
{
|
||||
set(field::transfer_encoding, "chunked");
|
||||
return;
|
||||
}
|
||||
|
||||
static_string<max_static_buffer> temp;
|
||||
if(it->value().size() <= temp.size() + 9)
|
||||
auto const te = token_list{it->value()};
|
||||
for(auto itt = te.begin();;)
|
||||
{
|
||||
temp.append(it->value().data(), it->value().size());
|
||||
temp.append(", chunked", 9);
|
||||
set(field::transfer_encoding, temp);
|
||||
auto const next = std::next(itt);
|
||||
if(next == te.end())
|
||||
{
|
||||
if(iequals(*itt, "chunked"))
|
||||
return; // already set
|
||||
break;
|
||||
}
|
||||
itt = next;
|
||||
}
|
||||
static_string<max_static_buffer> buf;
|
||||
if(it->value().size() <= buf.size() + 9)
|
||||
{
|
||||
buf.append(it->value().data(), it->value().size());
|
||||
buf.append(", chunked", 9);
|
||||
set(field::transfer_encoding, buf);
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef BEAST_HTTP_NO_FIELDS_BASIC_STRING_ALLOCATOR
|
||||
// Workaround for https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56437
|
||||
std::string s;
|
||||
#else
|
||||
using rebind_type =
|
||||
typename std::allocator_traits<
|
||||
Allocator>::template rebind_alloc<char>;
|
||||
std::basic_string<
|
||||
char,
|
||||
std::char_traits<char>,
|
||||
rebind_type> s{rebind_type{alloc_}};
|
||||
#endif
|
||||
s.reserve(it->value().size() + 9);
|
||||
s.append(it->value().data(), it->value().size());
|
||||
s.append(", chunked", 9);
|
||||
@@ -897,44 +998,100 @@ prepare_payload_impl(bool chunked,
|
||||
}
|
||||
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)
|
||||
// filter "chunked"
|
||||
if(it == end())
|
||||
return;
|
||||
try
|
||||
{
|
||||
clear_chunked();
|
||||
set(field::content_length, *size);
|
||||
static_string<max_static_buffer> buf;
|
||||
detail::filter_token_list_last(buf, it->value(),
|
||||
[](string_view const& s)
|
||||
{
|
||||
return iequals(s, "chunked");
|
||||
});
|
||||
if(! buf.empty())
|
||||
set(field::transfer_encoding, buf);
|
||||
else
|
||||
erase(field::transfer_encoding);
|
||||
}
|
||||
else
|
||||
catch(std::length_error const&)
|
||||
{
|
||||
clear_chunked();
|
||||
#ifdef BEAST_HTTP_NO_FIELDS_BASIC_STRING_ALLOCATOR
|
||||
// Workaround for https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56437
|
||||
std::string s;
|
||||
#else
|
||||
using rebind_type =
|
||||
typename std::allocator_traits<
|
||||
Allocator>::template rebind_alloc<char>;
|
||||
std::basic_string<
|
||||
char,
|
||||
std::char_traits<char>,
|
||||
rebind_type> s{rebind_type{alloc_}};
|
||||
#endif
|
||||
s.reserve(it->value().size());
|
||||
detail::filter_token_list_last(s, it->value(),
|
||||
[](string_view const& s)
|
||||
{
|
||||
return iequals(s, "chunked");
|
||||
});
|
||||
if(! s.empty())
|
||||
set(field::transfer_encoding, s);
|
||||
else
|
||||
erase(field::transfer_encoding);
|
||||
}
|
||||
}
|
||||
|
||||
template<class Allocator>
|
||||
void
|
||||
basic_fields<Allocator>::
|
||||
set_content_length_impl(
|
||||
boost::optional<std::uint64_t> const& value)
|
||||
{
|
||||
if(! value)
|
||||
erase(field::content_length);
|
||||
else
|
||||
set(field::content_length, *value);
|
||||
}
|
||||
|
||||
template<class Allocator>
|
||||
void
|
||||
basic_fields<Allocator>::
|
||||
set_keep_alive_impl(
|
||||
unsigned version, bool keep_alive)
|
||||
{
|
||||
// VFALCO What about Proxy-Connection ?
|
||||
auto const value = (*this)[field::connection];
|
||||
try
|
||||
{
|
||||
static_string<max_static_buffer> buf;
|
||||
detail::keep_alive_impl(
|
||||
buf, value, version, keep_alive);
|
||||
if(buf.empty())
|
||||
erase(field::connection);
|
||||
else
|
||||
set(field::connection, buf);
|
||||
}
|
||||
catch(std::length_error const&)
|
||||
{
|
||||
#ifdef BEAST_HTTP_NO_FIELDS_BASIC_STRING_ALLOCATOR
|
||||
// Workaround for https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56437
|
||||
std::string s;
|
||||
#else
|
||||
using rebind_type =
|
||||
typename std::allocator_traits<
|
||||
Allocator>::template rebind_alloc<char>;
|
||||
std::basic_string<
|
||||
char,
|
||||
std::char_traits<char>,
|
||||
rebind_type> s{rebind_type{alloc_}};
|
||||
#endif
|
||||
s.reserve(value.size());
|
||||
detail::keep_alive_impl(
|
||||
s, value, version, keep_alive);
|
||||
if(s.empty())
|
||||
erase(field::connection);
|
||||
else
|
||||
set(field::connection, s);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -313,40 +313,25 @@ message(std::piecewise_construct_t,
|
||||
{
|
||||
}
|
||||
|
||||
#if 0
|
||||
template<bool isRequest, class Body, class Fields>
|
||||
template<class BodyArg, class>
|
||||
void
|
||||
message<isRequest, Body, Fields>::
|
||||
message(BodyArg&& body_arg)
|
||||
: body(std::forward<BodyArg>(body_arg))
|
||||
chunked(bool value)
|
||||
{
|
||||
this->set_chunked_impl(value);
|
||||
this->set_content_length_impl(boost::none);
|
||||
}
|
||||
|
||||
template<bool isRequest, class Body, class Fields>
|
||||
template<class BodyArg, class HeaderArg, class>
|
||||
void
|
||||
message<isRequest, Body, Fields>::
|
||||
message(BodyArg&& body_arg, HeaderArg&& header_arg)
|
||||
: header_type(std::forward<HeaderArg>(header_arg))
|
||||
, body(std::forward<BodyArg>(body_arg))
|
||||
content_length(
|
||||
boost::optional<std::uint64_t> const& value)
|
||||
{
|
||||
this->set_content_length_impl(value);
|
||||
this->set_chunked_impl(false);
|
||||
}
|
||||
|
||||
template<bool isRequest, class Body, class Fields>
|
||||
template<class... BodyArgs, class... HeaderArgs>
|
||||
message<isRequest, Body, Fields>::
|
||||
message(std::piecewise_construct_t,
|
||||
std::tuple<BodyArgs...>&& body_args,
|
||||
std::tuple<HeaderArgs...>&& header_args)
|
||||
: message(std::piecewise_construct,
|
||||
body_args, header_args,
|
||||
beast::detail::make_index_sequence<
|
||||
sizeof...(BodyArgs)>{},
|
||||
beast::detail::make_index_sequence<
|
||||
sizeof...(HeaderArgs)>{})
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
template<bool isRequest, class Body, class Fields>
|
||||
boost::optional<std::uint64_t>
|
||||
message<isRequest, Body, Fields>::
|
||||
@@ -371,20 +356,20 @@ prepare_payload(std::true_type)
|
||||
this->method() == verb::put ||
|
||||
this->method() == verb::post)
|
||||
{
|
||||
this->prepare_payload_impl(false, *n);
|
||||
this->content_length(n);
|
||||
}
|
||||
else
|
||||
{
|
||||
this->prepare_payload_impl(false, boost::none);
|
||||
this->chunked(false);
|
||||
}
|
||||
}
|
||||
else if(this->version >= 11)
|
||||
{
|
||||
this->prepare_payload_impl(true, boost::none);
|
||||
this->chunked(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
this->prepare_payload_impl(false, boost::none);
|
||||
this->chunked(false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -404,13 +389,9 @@ prepare_payload(std::false_type)
|
||||
"invalid response body"});
|
||||
}
|
||||
if(n)
|
||||
{
|
||||
this->prepare_payload_impl(false, *n);
|
||||
}
|
||||
this->content_length(n);
|
||||
else
|
||||
{
|
||||
this->prepare_payload_impl(true, boost::none);
|
||||
}
|
||||
this->chunked(true);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
@@ -88,8 +88,8 @@ next(error_code& ec, Visit&& visit)
|
||||
{
|
||||
frdinit(std::integral_constant<bool,
|
||||
isRequest>{});
|
||||
keep_alive_ = frd_->keep_alive();
|
||||
chunked_ = frd_->chunked();
|
||||
keep_alive_ = m_.keep_alive();
|
||||
chunked_ = m_.chunked();
|
||||
if(chunked_)
|
||||
goto go_init_c;
|
||||
s_ = do_init;
|
||||
|
||||
@@ -642,6 +642,72 @@ struct message : header<isRequest, Fields>
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Returns `true` if the chunked Transfer-Encoding is specified
|
||||
bool
|
||||
chunked() const
|
||||
{
|
||||
return this->get_chunked_impl();
|
||||
}
|
||||
|
||||
/** Set or clear the chunked Transfer-Encoding
|
||||
|
||||
This function will set or removed the "chunked" transfer
|
||||
encoding as the last item in the list of encodings in the
|
||||
field.
|
||||
|
||||
If the result of removing the chunked token results in an
|
||||
empty string, the field is erased.
|
||||
|
||||
The Content-Length field is erased unconditionally.
|
||||
*/
|
||||
void
|
||||
chunked(bool value);
|
||||
|
||||
/** Set or clear the Content-Length field
|
||||
|
||||
This function adjusts the Content-Length field as follows:
|
||||
|
||||
@li If `value` specifies a value, the Content-Length field
|
||||
is set to the value. Otherwise
|
||||
|
||||
@li The Content-Length field is erased.
|
||||
|
||||
If "chunked" token appears as the last item in the
|
||||
Transfer-Encoding field it is unconditionally removed.
|
||||
|
||||
@param value The value to set for Content-Length.
|
||||
*/
|
||||
void
|
||||
content_length(boost::optional<std::uint64_t> const& value);
|
||||
|
||||
/** Returns `true` if the message semantics indicate keep-alive
|
||||
|
||||
The value depends on the version in the message, which must
|
||||
be set to the final value before this function is called or
|
||||
else the return value is unreliable.
|
||||
*/
|
||||
bool
|
||||
keep_alive() const
|
||||
{
|
||||
return this->get_keep_alive_impl(this->version);
|
||||
}
|
||||
|
||||
/** Set the keep-alive message semantic option
|
||||
|
||||
This function adjusts the Connection field to indicate
|
||||
whether or not the connection should be kept open after
|
||||
the corresponding response. The result depends on the
|
||||
version set on the message, which must be set to the
|
||||
final value before making this call.
|
||||
|
||||
@param value `true` if the connection should persist.
|
||||
*/
|
||||
void
|
||||
keep_alive(bool value)
|
||||
{
|
||||
this->set_keep_alive_impl(this->version, value);
|
||||
}
|
||||
|
||||
/** Returns the payload size of the body in octets if possible.
|
||||
|
||||
This function invokes the @b Body algorithm to measure
|
||||
|
||||
Reference in new issue
Block a user