mirror of
https://github.com/boostorg/beast.git
synced 2025-07-30 12:57: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
|
unexpected end-of-file condition is encountered while trying
|
||||||
to read from the file.
|
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
|
} // http
|
||||||
|
@ -10,9 +10,10 @@
|
|||||||
#ifndef BOOST_BEAST_HTTP_FIELDS_HPP
|
#ifndef BOOST_BEAST_HTTP_FIELDS_HPP
|
||||||
#define 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/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/beast/http/field.hpp>
|
||||||
#include <boost/asio/buffer.hpp>
|
#include <boost/asio/buffer.hpp>
|
||||||
#include <boost/core/empty_value.hpp>
|
#include <boost/core/empty_value.hpp>
|
||||||
@ -218,6 +219,14 @@ private:
|
|||||||
|
|
||||||
|
|
||||||
public:
|
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
|
/// Destructor
|
||||||
~basic_fields();
|
~basic_fields();
|
||||||
|
|
||||||
@ -434,13 +443,15 @@ public:
|
|||||||
|
|
||||||
@param name The field name.
|
@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
|
void
|
||||||
insert(field name, string_view const& value);
|
insert(field name, string_view value);
|
||||||
|
|
||||||
/* Set a field from a null pointer (deleted).
|
|
||||||
*/
|
|
||||||
void
|
void
|
||||||
insert(field, std::nullptr_t) = delete;
|
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 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
|
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
|
void
|
||||||
insert(string_view, std::nullptr_t) = delete;
|
insert(string_view, std::nullptr_t) = delete;
|
||||||
|
|
||||||
@ -477,15 +492,50 @@ public:
|
|||||||
must be equal to `to_string(name)` using a case-insensitive
|
must be equal to `to_string(name)` using a case-insensitive
|
||||||
comparison, otherwise the behavior is undefined.
|
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
|
void
|
||||||
insert(field name, string_view name_string,
|
insert(field name, string_view name_string,
|
||||||
string_view const& value);
|
string_view value);
|
||||||
|
|
||||||
void
|
void
|
||||||
insert(field, string_view, std::nullptr_t) = delete;
|
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.
|
/** Set a field value, removing any other instances of that field.
|
||||||
|
|
||||||
First removes any values with matching field names, then
|
First removes any values with matching field names, then
|
||||||
@ -493,13 +543,14 @@ public:
|
|||||||
|
|
||||||
@param name The field name.
|
@param name The field name.
|
||||||
|
|
||||||
@param value The value of the field, as a @ref boost::beast::string_view
|
@param value The field value.
|
||||||
|
|
||||||
@return 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
|
void
|
||||||
set(field name, string_view const& value);
|
set(field name, string_view value);
|
||||||
|
|
||||||
void
|
void
|
||||||
set(field, std::nullptr_t) = delete;
|
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 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
|
void
|
||||||
set(string_view name, string_view const& value);
|
set(string_view name, string_view value);
|
||||||
|
|
||||||
void
|
void
|
||||||
set(string_view, std::nullptr_t) = delete;
|
set(string_view, std::nullptr_t) = delete;
|
||||||
|
|
||||||
/** Remove a field.
|
/** Remove a field.
|
||||||
|
|
||||||
References and iterators to the erased elements are
|
References and iterators to the erased elements are
|
||||||
invalidated. Other references and iterators are not
|
invalidated. Other references and iterators are not
|
||||||
@ -744,9 +801,21 @@ private:
|
|||||||
template<class OtherAlloc>
|
template<class OtherAlloc>
|
||||||
friend class basic_fields;
|
friend class basic_fields;
|
||||||
|
|
||||||
|
element*
|
||||||
|
try_create_new_element(
|
||||||
|
field name,
|
||||||
|
string_view sname,
|
||||||
|
string_view value,
|
||||||
|
error_code& ec);
|
||||||
|
|
||||||
element&
|
element&
|
||||||
new_element(field name,
|
new_element(
|
||||||
string_view sname, string_view value);
|
field name,
|
||||||
|
string_view sname,
|
||||||
|
string_view value);
|
||||||
|
|
||||||
|
void
|
||||||
|
insert_element(element& e);
|
||||||
|
|
||||||
void
|
void
|
||||||
delete_element(element& e);
|
delete_element(element& e);
|
||||||
|
@ -61,6 +61,8 @@ public:
|
|||||||
case error::multiple_content_length: return "multiple Content-Length";
|
case error::multiple_content_length: return "multiple Content-Length";
|
||||||
case error::stale_parser: return "stale parser";
|
case error::stale_parser: return "stale parser";
|
||||||
case error::short_read: return "unexpected eof in body";
|
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:
|
default:
|
||||||
return "beast.http error";
|
return "beast.http error";
|
||||||
|
@ -537,7 +537,7 @@ template<class Allocator>
|
|||||||
inline
|
inline
|
||||||
void
|
void
|
||||||
basic_fields<Allocator>::
|
basic_fields<Allocator>::
|
||||||
insert(field name, string_view const& value)
|
insert(field name, string_view value)
|
||||||
{
|
{
|
||||||
BOOST_ASSERT(name != field::unknown);
|
BOOST_ASSERT(name != field::unknown);
|
||||||
insert(name, to_string(name), value);
|
insert(name, to_string(name), value);
|
||||||
@ -546,58 +546,52 @@ insert(field name, string_view const& value)
|
|||||||
template<class Allocator>
|
template<class Allocator>
|
||||||
void
|
void
|
||||||
basic_fields<Allocator>::
|
basic_fields<Allocator>::
|
||||||
insert(string_view sname, string_view const& value)
|
insert(string_view sname, string_view value)
|
||||||
{
|
{
|
||||||
auto const name =
|
insert(
|
||||||
string_to_field(sname);
|
string_to_field(sname), sname, value);
|
||||||
insert(name, 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>
|
template<class Allocator>
|
||||||
void
|
void
|
||||||
basic_fields<Allocator>::
|
basic_fields<Allocator>::
|
||||||
insert(field name,
|
insert(field name,
|
||||||
string_view sname, string_view const& value)
|
string_view sname, string_view value)
|
||||||
{
|
{
|
||||||
auto& e = new_element(name, sname,
|
insert_element(
|
||||||
static_cast<string_view>(value));
|
new_element(name, sname, 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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class Allocator>
|
template<class Allocator>
|
||||||
void
|
void
|
||||||
basic_fields<Allocator>::
|
basic_fields<Allocator>::
|
||||||
set(field name, string_view const& value)
|
set(field name, string_view value)
|
||||||
{
|
{
|
||||||
BOOST_ASSERT(name != field::unknown);
|
BOOST_ASSERT(name != field::unknown);
|
||||||
set_element(new_element(name, to_string(name),
|
set_element(
|
||||||
static_cast<string_view>(value)));
|
new_element(name, to_string(name), value));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class Allocator>
|
template<class Allocator>
|
||||||
void
|
void
|
||||||
basic_fields<Allocator>::
|
basic_fields<Allocator>::
|
||||||
set(string_view sname, string_view const& value)
|
set(string_view sname, string_view value)
|
||||||
{
|
{
|
||||||
set_element(new_element(
|
set_element(new_element(
|
||||||
string_to_field(sname), sname, value));
|
string_to_field(sname), sname, value));
|
||||||
@ -953,18 +947,22 @@ set_keep_alive_impl(
|
|||||||
template<class Allocator>
|
template<class Allocator>
|
||||||
auto
|
auto
|
||||||
basic_fields<Allocator>::
|
basic_fields<Allocator>::
|
||||||
new_element(field name,
|
try_create_new_element(
|
||||||
string_view sname, string_view value) ->
|
field name,
|
||||||
element&
|
string_view sname,
|
||||||
|
string_view value,
|
||||||
|
error_code& ec) -> element*
|
||||||
{
|
{
|
||||||
if(sname.size() + 2 >
|
if(sname.size() > max_name_size)
|
||||||
(std::numeric_limits<off_t>::max)())
|
{
|
||||||
BOOST_THROW_EXCEPTION(std::length_error{
|
BOOST_BEAST_ASSIGN_EC(ec, error::header_field_name_too_large);
|
||||||
"field name too large"});
|
return nullptr;
|
||||||
if(value.size() + 2 >
|
}
|
||||||
(std::numeric_limits<off_t>::max)())
|
if(value.size() > max_value_size)
|
||||||
BOOST_THROW_EXCEPTION(std::length_error{
|
{
|
||||||
"field value too large"});
|
BOOST_BEAST_ASSIGN_EC(ec, error::header_field_value_too_large);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
value = detail::trim(value);
|
value = detail::trim(value);
|
||||||
std::uint16_t const off =
|
std::uint16_t const off =
|
||||||
static_cast<off_t>(sname.size() + 2);
|
static_cast<off_t>(sname.size() + 2);
|
||||||
@ -974,7 +972,50 @@ new_element(field name,
|
|||||||
auto const p = alloc_traits::allocate(a,
|
auto const p = alloc_traits::allocate(a,
|
||||||
(sizeof(element) + off + len + 2 + sizeof(align_type) - 1) /
|
(sizeof(element) + off + len + 2 + sizeof(align_type) - 1) /
|
||||||
sizeof(align_type));
|
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>
|
template<class Allocator>
|
||||||
|
@ -72,6 +72,9 @@ public:
|
|||||||
|
|
||||||
check("beast.http", error::stale_parser);
|
check("beast.http", error::stale_parser);
|
||||||
check("beast.http", error::short_read);
|
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, 1)->value() == "4");
|
||||||
BEAST_EXPECT(std::next(rng.first, 2)->value() == "6");
|
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
|
struct sized_body
|
||||||
|
Reference in New Issue
Block a user