mirror of
https://github.com/boostorg/beast.git
synced 2025-07-29 20:37:31 +02:00
Add overload for basic_fields::insert() to set error_code
This commit is contained in:
committed by
Mohammad Nejati
parent
848e20680f
commit
2e6d9bb491
@ -164,7 +164,13 @@ enum class error
|
||||
unexpected end-of-file condition is encountered while trying
|
||||
to read from the file.
|
||||
*/
|
||||
short_read
|
||||
short_read,
|
||||
|
||||
/// Header field name exceeds @ref basic_fields::max_name_size.
|
||||
header_field_name_too_large,
|
||||
|
||||
/// Header field value exceeds @ref basic_fields::max_value_size.
|
||||
header_field_value_too_large
|
||||
};
|
||||
|
||||
} // http
|
||||
|
@ -10,9 +10,10 @@
|
||||
#ifndef BOOST_BEAST_HTTP_FIELDS_HPP
|
||||
#define BOOST_BEAST_HTTP_FIELDS_HPP
|
||||
|
||||
#include <boost/beast/core/detail/config.hpp>
|
||||
#include <boost/beast/core/string.hpp>
|
||||
#include <boost/beast/core/detail/allocator.hpp>
|
||||
#include <boost/beast/core/detail/config.hpp>
|
||||
#include <boost/beast/core/error.hpp>
|
||||
#include <boost/beast/core/string.hpp>
|
||||
#include <boost/beast/http/field.hpp>
|
||||
#include <boost/asio/buffer.hpp>
|
||||
#include <boost/core/empty_value.hpp>
|
||||
@ -218,6 +219,14 @@ private:
|
||||
|
||||
|
||||
public:
|
||||
/// Maximum field name size
|
||||
static std::size_t constexpr max_name_size =
|
||||
(std::numeric_limits<std::uint16_t>::max)() - 2;
|
||||
|
||||
/// Maximum field value size
|
||||
static std::size_t constexpr max_value_size =
|
||||
(std::numeric_limits<std::uint16_t>::max)() - 2;
|
||||
|
||||
/// Destructor
|
||||
~basic_fields();
|
||||
|
||||
@ -434,13 +443,15 @@ public:
|
||||
|
||||
@param name The field name.
|
||||
|
||||
@param value The value of the field, as a @ref boost::beast::string_view
|
||||
@param value The field value.
|
||||
|
||||
@throws boost::system::system_error Thrown if an error occurs:
|
||||
@li If the size of @c value exceeds @ref max_value_size, the
|
||||
error code will be @ref error::header_field_value_too_large.
|
||||
*/
|
||||
void
|
||||
insert(field name, string_view const& value);
|
||||
insert(field name, string_view value);
|
||||
|
||||
/* Set a field from a null pointer (deleted).
|
||||
*/
|
||||
void
|
||||
insert(field, std::nullptr_t) = delete;
|
||||
|
||||
@ -453,13 +464,17 @@ public:
|
||||
|
||||
@param name The field name. It is interpreted as a case-insensitive string.
|
||||
|
||||
@param value The value of the field, as a @ref boost::beast::string_view
|
||||
@param value The field value.
|
||||
|
||||
@throws boost::system::system_error Thrown if an error occurs:
|
||||
@li If the size of @c name exceeds @ref max_name_size, the
|
||||
error code will be @ref error::header_field_name_too_large.
|
||||
@li If the size of @c value exceeds @ref max_value_size, the
|
||||
error code will be @ref error::header_field_value_too_large.
|
||||
*/
|
||||
void
|
||||
insert(string_view name, string_view const& value);
|
||||
insert(string_view name, string_view value);
|
||||
|
||||
/* Insert a field from a null pointer (deleted).
|
||||
*/
|
||||
void
|
||||
insert(string_view, std::nullptr_t) = delete;
|
||||
|
||||
@ -477,15 +492,50 @@ public:
|
||||
must be equal to `to_string(name)` using a case-insensitive
|
||||
comparison, otherwise the behavior is undefined.
|
||||
|
||||
@param value The value of the field, as a @ref boost::beast::string_view
|
||||
@param value The field value.
|
||||
|
||||
@throws boost::system::system_error Thrown if an error occurs:
|
||||
@li If the size of @c name_string exceeds @ref max_name_size,
|
||||
the error code will be @ref error::header_field_name_too_large.
|
||||
@li If the size of @c value exceeds @ref max_value_size, the
|
||||
error code will be @ref error::header_field_value_too_large.
|
||||
*/
|
||||
void
|
||||
insert(field name, string_view name_string,
|
||||
string_view const& value);
|
||||
string_view value);
|
||||
|
||||
void
|
||||
insert(field, string_view, std::nullptr_t) = delete;
|
||||
|
||||
/** Insert a field.
|
||||
|
||||
If one or more fields with the same name already exist,
|
||||
the new field will be inserted after the last field with
|
||||
the matching name, in serialization order.
|
||||
The value can be an empty string.
|
||||
|
||||
@param name The field name.
|
||||
|
||||
@param name_string The literal text corresponding to the
|
||||
field name. If `name != field::unknown`, then this value
|
||||
must be equal to `to_string(name)` using a case-insensitive
|
||||
comparison, otherwise the behavior is undefined.
|
||||
|
||||
@param value The field value.
|
||||
|
||||
@param ec Set to indicate what error occurred:
|
||||
@li If the size of @c name_string exceeds @ref max_name_size,
|
||||
the error code will be @ref error::header_field_name_too_large.
|
||||
@li If the size of @c value exceeds @ref max_value_size, the
|
||||
error code will be @ref error::header_field_value_too_large.
|
||||
*/
|
||||
void
|
||||
insert(field name, string_view name_string,
|
||||
string_view value, error_code& ec);
|
||||
|
||||
void
|
||||
insert(field, string_view, std::nullptr_t, error_code& ec) = delete;
|
||||
|
||||
/** Set a field value, removing any other instances of that field.
|
||||
|
||||
First removes any values with matching field names, then
|
||||
@ -493,13 +543,14 @@ public:
|
||||
|
||||
@param name The field name.
|
||||
|
||||
@param value The value of the field, as a @ref boost::beast::string_view
|
||||
|
||||
@return The field value.
|
||||
@param value The field value.
|
||||
|
||||
@throws boost::system::system_error Thrown if an error occurs:
|
||||
@li If the size of @c value exceeds @ref max_value_size, the
|
||||
error code will be @ref error::header_field_value_too_large.
|
||||
*/
|
||||
void
|
||||
set(field name, string_view const& value);
|
||||
set(field name, string_view value);
|
||||
|
||||
void
|
||||
set(field, std::nullptr_t) = delete;
|
||||
@ -511,15 +562,21 @@ public:
|
||||
|
||||
@param name The field name. It is interpreted as a case-insensitive string.
|
||||
|
||||
@param value The value of the field, as a @ref boost::beast::string_view
|
||||
@param value The field value.
|
||||
|
||||
@throws boost::system::system_error Thrown if an error occurs:
|
||||
@li If the size of @c name exceeds @ref max_name_size, the
|
||||
error code will be @ref error::header_field_name_too_large.
|
||||
@li If the size of @c value exceeds @ref max_value_size, the
|
||||
error code will be @ref error::header_field_value_too_large.
|
||||
*/
|
||||
void
|
||||
set(string_view name, string_view const& value);
|
||||
set(string_view name, string_view value);
|
||||
|
||||
void
|
||||
set(string_view, std::nullptr_t) = delete;
|
||||
|
||||
/** Remove a field.
|
||||
/** Remove a field.
|
||||
|
||||
References and iterators to the erased elements are
|
||||
invalidated. Other references and iterators are not
|
||||
@ -744,9 +801,21 @@ private:
|
||||
template<class OtherAlloc>
|
||||
friend class basic_fields;
|
||||
|
||||
element*
|
||||
try_create_new_element(
|
||||
field name,
|
||||
string_view sname,
|
||||
string_view value,
|
||||
error_code& ec);
|
||||
|
||||
element&
|
||||
new_element(field name,
|
||||
string_view sname, string_view value);
|
||||
new_element(
|
||||
field name,
|
||||
string_view sname,
|
||||
string_view value);
|
||||
|
||||
void
|
||||
insert_element(element& e);
|
||||
|
||||
void
|
||||
delete_element(element& e);
|
||||
|
@ -61,6 +61,8 @@ public:
|
||||
case error::multiple_content_length: return "multiple Content-Length";
|
||||
case error::stale_parser: return "stale parser";
|
||||
case error::short_read: return "unexpected eof in body";
|
||||
case error::header_field_name_too_large: return "header field name too large";
|
||||
case error::header_field_value_too_large: return "header field value too large";
|
||||
|
||||
default:
|
||||
return "beast.http error";
|
||||
|
@ -537,7 +537,7 @@ template<class Allocator>
|
||||
inline
|
||||
void
|
||||
basic_fields<Allocator>::
|
||||
insert(field name, string_view const& value)
|
||||
insert(field name, string_view value)
|
||||
{
|
||||
BOOST_ASSERT(name != field::unknown);
|
||||
insert(name, to_string(name), value);
|
||||
@ -546,58 +546,52 @@ insert(field name, string_view const& value)
|
||||
template<class Allocator>
|
||||
void
|
||||
basic_fields<Allocator>::
|
||||
insert(string_view sname, string_view const& value)
|
||||
insert(string_view sname, string_view value)
|
||||
{
|
||||
auto const name =
|
||||
string_to_field(sname);
|
||||
insert(name, sname, value);
|
||||
insert(
|
||||
string_to_field(sname), sname, value);
|
||||
}
|
||||
|
||||
template<class Allocator>
|
||||
void
|
||||
basic_fields<Allocator>::
|
||||
insert(
|
||||
field name,
|
||||
string_view sname,
|
||||
string_view value,
|
||||
error_code& ec)
|
||||
{
|
||||
ec = {};
|
||||
auto* e = try_create_new_element(name, sname, value, ec);
|
||||
if(ec.failed())
|
||||
return;
|
||||
insert_element(*e);
|
||||
}
|
||||
|
||||
template<class Allocator>
|
||||
void
|
||||
basic_fields<Allocator>::
|
||||
insert(field name,
|
||||
string_view sname, string_view const& value)
|
||||
string_view sname, string_view value)
|
||||
{
|
||||
auto& e = new_element(name, sname,
|
||||
static_cast<string_view>(value));
|
||||
auto const before =
|
||||
set_.upper_bound(sname, key_compare{});
|
||||
if(before == set_.begin())
|
||||
{
|
||||
BOOST_ASSERT(count(sname) == 0);
|
||||
set_.insert_before(before, e);
|
||||
list_.push_back(e);
|
||||
return;
|
||||
}
|
||||
auto const last = std::prev(before);
|
||||
// VFALCO is it worth comparing `field name` first?
|
||||
if(! beast::iequals(sname, last->name_string()))
|
||||
{
|
||||
BOOST_ASSERT(count(sname) == 0);
|
||||
set_.insert_before(before, e);
|
||||
list_.push_back(e);
|
||||
return;
|
||||
}
|
||||
// keep duplicate fields together in the list
|
||||
set_.insert_before(before, e);
|
||||
list_.insert(++list_.iterator_to(*last), e);
|
||||
insert_element(
|
||||
new_element(name, sname, value));
|
||||
}
|
||||
|
||||
template<class Allocator>
|
||||
void
|
||||
basic_fields<Allocator>::
|
||||
set(field name, string_view const& value)
|
||||
set(field name, string_view value)
|
||||
{
|
||||
BOOST_ASSERT(name != field::unknown);
|
||||
set_element(new_element(name, to_string(name),
|
||||
static_cast<string_view>(value)));
|
||||
set_element(
|
||||
new_element(name, to_string(name), value));
|
||||
}
|
||||
|
||||
template<class Allocator>
|
||||
void
|
||||
basic_fields<Allocator>::
|
||||
set(string_view sname, string_view const& value)
|
||||
set(string_view sname, string_view value)
|
||||
{
|
||||
set_element(new_element(
|
||||
string_to_field(sname), sname, value));
|
||||
@ -953,18 +947,22 @@ set_keep_alive_impl(
|
||||
template<class Allocator>
|
||||
auto
|
||||
basic_fields<Allocator>::
|
||||
new_element(field name,
|
||||
string_view sname, string_view value) ->
|
||||
element&
|
||||
try_create_new_element(
|
||||
field name,
|
||||
string_view sname,
|
||||
string_view value,
|
||||
error_code& ec) -> element*
|
||||
{
|
||||
if(sname.size() + 2 >
|
||||
(std::numeric_limits<off_t>::max)())
|
||||
BOOST_THROW_EXCEPTION(std::length_error{
|
||||
"field name too large"});
|
||||
if(value.size() + 2 >
|
||||
(std::numeric_limits<off_t>::max)())
|
||||
BOOST_THROW_EXCEPTION(std::length_error{
|
||||
"field value too large"});
|
||||
if(sname.size() > max_name_size)
|
||||
{
|
||||
BOOST_BEAST_ASSIGN_EC(ec, error::header_field_name_too_large);
|
||||
return nullptr;
|
||||
}
|
||||
if(value.size() > max_value_size)
|
||||
{
|
||||
BOOST_BEAST_ASSIGN_EC(ec, error::header_field_value_too_large);
|
||||
return nullptr;
|
||||
}
|
||||
value = detail::trim(value);
|
||||
std::uint16_t const off =
|
||||
static_cast<off_t>(sname.size() + 2);
|
||||
@ -974,7 +972,50 @@ new_element(field name,
|
||||
auto const p = alloc_traits::allocate(a,
|
||||
(sizeof(element) + off + len + 2 + sizeof(align_type) - 1) /
|
||||
sizeof(align_type));
|
||||
return *(::new(p) element(name, sname, value));
|
||||
return ::new(p) element(name, sname, value);
|
||||
}
|
||||
|
||||
template<class Allocator>
|
||||
auto
|
||||
basic_fields<Allocator>::
|
||||
new_element(
|
||||
field name,
|
||||
string_view sname,
|
||||
string_view value) -> element&
|
||||
{
|
||||
error_code ec;
|
||||
auto* e = try_create_new_element(name, sname, value, ec);
|
||||
if(ec.failed())
|
||||
BOOST_THROW_EXCEPTION(system_error{ec});
|
||||
return *e;
|
||||
}
|
||||
|
||||
template<class Allocator>
|
||||
void
|
||||
basic_fields<Allocator>::
|
||||
insert_element(element& e)
|
||||
{
|
||||
auto const before =
|
||||
set_.upper_bound(e.name_string(), key_compare{});
|
||||
if(before == set_.begin())
|
||||
{
|
||||
BOOST_ASSERT(count(e.name_string()) == 0);
|
||||
set_.insert_before(before, e);
|
||||
list_.push_back(e);
|
||||
return;
|
||||
}
|
||||
auto const last = std::prev(before);
|
||||
// VFALCO is it worth comparing `field name` first?
|
||||
if(! beast::iequals(e.name_string(), last->name_string()))
|
||||
{
|
||||
BOOST_ASSERT(count(e.name_string()) == 0);
|
||||
set_.insert_before(before, e);
|
||||
list_.push_back(e);
|
||||
return;
|
||||
}
|
||||
// keep duplicate fields together in the list
|
||||
set_.insert_before(before, e);
|
||||
list_.insert(++list_.iterator_to(*last), e);
|
||||
}
|
||||
|
||||
template<class Allocator>
|
||||
|
@ -72,6 +72,9 @@ public:
|
||||
|
||||
check("beast.http", error::stale_parser);
|
||||
check("beast.http", error::short_read);
|
||||
|
||||
check("beast.http", error::header_field_name_too_large);
|
||||
check("beast.http", error::header_field_value_too_large);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -445,6 +445,33 @@ public:
|
||||
BEAST_EXPECT(std::next(rng.first, 1)->value() == "4");
|
||||
BEAST_EXPECT(std::next(rng.first, 2)->value() == "6");
|
||||
}
|
||||
|
||||
// max field name and max field value
|
||||
{
|
||||
fields f;
|
||||
error_code ec;
|
||||
auto fit_name = std::string(fields::max_name_size, 'a');
|
||||
auto big_name = std::string(fields::max_name_size + 1, 'a');
|
||||
auto fit_value = std::string(fields::max_value_size, 'a');
|
||||
auto big_value = std::string(fields::max_value_size + 1, 'a');
|
||||
|
||||
f.insert(fit_name, fit_value);
|
||||
f.set(fit_name, fit_value);
|
||||
|
||||
f.insert(field::age, big_name, "", ec);
|
||||
BEAST_EXPECT(ec == error::header_field_name_too_large);
|
||||
f.insert(field::age, "", big_value, ec);
|
||||
BEAST_EXPECT(ec == error::header_field_value_too_large);
|
||||
|
||||
BEAST_THROWS(f.insert(field::age, big_value), boost::system::system_error);
|
||||
BEAST_THROWS(f.insert(field::age, big_name, ""), boost::system::system_error);
|
||||
BEAST_THROWS(f.insert(field::age, "", big_value), boost::system::system_error);
|
||||
BEAST_THROWS(f.insert(big_name, ""), boost::system::system_error);
|
||||
BEAST_THROWS(f.insert("", big_value), boost::system::system_error);
|
||||
BEAST_THROWS(f.set(field::age, big_value), boost::system::system_error);
|
||||
BEAST_THROWS(f.set(big_name, ""), boost::system::system_error);
|
||||
BEAST_THROWS(f.set("", big_value), boost::system::system_error);
|
||||
}
|
||||
}
|
||||
|
||||
struct sized_body
|
||||
|
Reference in New Issue
Block a user