mirror of
https://github.com/boostorg/beast.git
synced 2025-07-29 20:37:31 +02:00
Enable split compilation in http::basic_fields
Moved functions,that are independent of template argument, into an *.ipp file. Signed-off-by: Damian Jarek <damian.jarek93@gmail.com>
This commit is contained in:
@ -3,6 +3,7 @@ Version 259:
|
||||
* Reduce the number of instantiations of filter_token_list
|
||||
* Remove the use of `static_string` from `http::fields`
|
||||
* Add gcc-9 to AzP CI test matrix
|
||||
* Enable split compilation in http::basic_fields
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
|
67
include/boost/beast/core/detail/impl/temporary_buffer.ipp
Normal file
67
include/boost/beast/core/detail/impl/temporary_buffer.ipp
Normal file
@ -0,0 +1,67 @@
|
||||
//
|
||||
// Copyright (c) 2019 Damian Jarek(damian.jarek93@gmail.com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// Official repository: https://github.com/boostorg/beast
|
||||
//
|
||||
|
||||
#ifndef BOOST_BEAST_DETAIL_IMPL_TEMPORARY_BUFFER_IPP
|
||||
#define BOOST_BEAST_DETAIL_IMPL_TEMPORARY_BUFFER_IPP
|
||||
|
||||
#include <boost/beast/core/detail/temporary_buffer.hpp>
|
||||
#include <boost/beast/core/detail/clamp.hpp>
|
||||
#include <boost/core/exchange.hpp>
|
||||
|
||||
#include <memory>
|
||||
#include <cstring>
|
||||
|
||||
namespace boost {
|
||||
namespace beast {
|
||||
namespace detail {
|
||||
|
||||
|
||||
void
|
||||
temporary_buffer::append(string_view sv)
|
||||
{
|
||||
grow(sv.size());
|
||||
unchecked_append(sv);
|
||||
}
|
||||
|
||||
void
|
||||
temporary_buffer::append(string_view sv1, string_view sv2)
|
||||
{
|
||||
grow(sv1.size() + sv2.size());
|
||||
unchecked_append(sv1);
|
||||
unchecked_append(sv2);
|
||||
}
|
||||
|
||||
void
|
||||
temporary_buffer::unchecked_append(string_view sv)
|
||||
{
|
||||
auto n = sv.size();
|
||||
std::memcpy(&data_[size_], sv.data(), n);
|
||||
size_ += n;
|
||||
}
|
||||
|
||||
void
|
||||
temporary_buffer::grow(std::size_t sv_size)
|
||||
{
|
||||
if (capacity_ - size_ >= sv_size)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
auto const new_cap = (sv_size + size_) * 2u;
|
||||
BOOST_ASSERT(!detail::sum_exceeds(sv_size, size_, new_cap));
|
||||
char* const p = new char[new_cap];
|
||||
std::memcpy(p, data_, size_);
|
||||
deallocate(boost::exchange(data_, p));
|
||||
capacity_ = new_cap;
|
||||
}
|
||||
} // detail
|
||||
} // beast
|
||||
} // boost
|
||||
|
||||
#endif
|
87
include/boost/beast/core/detail/temporary_buffer.hpp
Normal file
87
include/boost/beast/core/detail/temporary_buffer.hpp
Normal file
@ -0,0 +1,87 @@
|
||||
//
|
||||
// Copyright (c) 2019 Damian Jarek(damian.jarek93@gmail.com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// Official repository: https://github.com/boostorg/beast
|
||||
//
|
||||
|
||||
#ifndef BOOST_BEAST_DETAIL_TEMPORARY_BUFFER_HPP
|
||||
#define BOOST_BEAST_DETAIL_TEMPORARY_BUFFER_HPP
|
||||
|
||||
#include <boost/beast/core/detail/config.hpp>
|
||||
#include <boost/beast/core/string.hpp>
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace boost {
|
||||
namespace beast {
|
||||
namespace detail {
|
||||
|
||||
struct temporary_buffer
|
||||
{
|
||||
temporary_buffer() = default;
|
||||
|
||||
temporary_buffer(temporary_buffer const&) = delete;
|
||||
temporary_buffer(temporary_buffer&&) = delete;
|
||||
|
||||
temporary_buffer& operator=(temporary_buffer const&) = delete;
|
||||
temporary_buffer& operator=(temporary_buffer&&) = delete;
|
||||
|
||||
~temporary_buffer() noexcept
|
||||
{
|
||||
deallocate(data_);
|
||||
}
|
||||
|
||||
BOOST_BEAST_DECL
|
||||
void
|
||||
append(string_view sv);
|
||||
|
||||
BOOST_BEAST_DECL
|
||||
void
|
||||
append(string_view sv1, string_view sv2);
|
||||
|
||||
string_view
|
||||
view() const noexcept
|
||||
{
|
||||
return {data_, size_};
|
||||
}
|
||||
|
||||
bool
|
||||
empty() const noexcept
|
||||
{
|
||||
return size_ == 0;
|
||||
}
|
||||
|
||||
private:
|
||||
BOOST_BEAST_DECL
|
||||
void
|
||||
unchecked_append(string_view sv);
|
||||
|
||||
BOOST_BEAST_DECL
|
||||
void
|
||||
grow(std::size_t sv_size);
|
||||
|
||||
void
|
||||
deallocate(char* data) noexcept
|
||||
{
|
||||
if (data != buffer_)
|
||||
delete[] data;
|
||||
}
|
||||
|
||||
char buffer_[4096];
|
||||
char* data_ = buffer_;
|
||||
std::size_t capacity_ = sizeof(buffer_);
|
||||
std::size_t size_ = 0;
|
||||
};
|
||||
|
||||
} // detail
|
||||
} // beast
|
||||
} // boost
|
||||
|
||||
#ifdef BOOST_BEAST_HEADER_ONLY
|
||||
#include <boost/beast/core/detail/impl/temporary_buffer.ipp>
|
||||
#endif
|
||||
|
||||
#endif
|
@ -14,6 +14,7 @@
|
||||
#include <boost/beast/core/string.hpp>
|
||||
#include <boost/beast/core/detail/buffers_ref.hpp>
|
||||
#include <boost/beast/core/detail/clamp.hpp>
|
||||
#include <boost/beast/core/detail/temporary_buffer.hpp>
|
||||
#include <boost/beast/http/verb.hpp>
|
||||
#include <boost/beast/http/rfc7230.hpp>
|
||||
#include <boost/beast/http/status.hpp>
|
||||
@ -23,13 +24,6 @@
|
||||
#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 BOOST_BEAST_HTTP_NO_FIELDS_BASIC_STRING_ALLOCATOR
|
||||
#define BOOST_BEAST_HTTP_NO_FIELDS_BASIC_STRING_ALLOCATOR
|
||||
#endif
|
||||
#endif
|
||||
|
||||
namespace boost {
|
||||
namespace beast {
|
||||
namespace http {
|
||||
@ -750,160 +744,10 @@ equal_range(string_view name) const ->
|
||||
|
||||
namespace detail {
|
||||
|
||||
struct temporary_buffer
|
||||
{
|
||||
temporary_buffer() = default;
|
||||
|
||||
temporary_buffer(temporary_buffer const&) = delete;
|
||||
temporary_buffer(temporary_buffer&&) = delete;
|
||||
|
||||
temporary_buffer& operator=(temporary_buffer const&) = delete;
|
||||
temporary_buffer& operator=(temporary_buffer&&) = delete;
|
||||
|
||||
~temporary_buffer() noexcept
|
||||
{
|
||||
deallocate(data_);
|
||||
}
|
||||
|
||||
void append(string_view sv)
|
||||
{
|
||||
reserve(sv.size());
|
||||
unsafe_append(sv);
|
||||
}
|
||||
|
||||
void append(string_view sv1, string_view sv2)
|
||||
{
|
||||
reserve(sv1.size() + sv2.size());
|
||||
unsafe_append(sv1);
|
||||
unsafe_append(sv2);
|
||||
}
|
||||
|
||||
string_view view() const noexcept
|
||||
{
|
||||
return {data_, size_};
|
||||
}
|
||||
|
||||
std::size_t size() const noexcept
|
||||
{
|
||||
return size_;
|
||||
}
|
||||
|
||||
std::size_t capacity() const noexcept
|
||||
{
|
||||
return capacity_;
|
||||
}
|
||||
|
||||
bool empty() const noexcept
|
||||
{
|
||||
return size_ == 0;
|
||||
}
|
||||
|
||||
private:
|
||||
void unsafe_append(string_view sv)
|
||||
{
|
||||
auto n = sv.size();
|
||||
std::memcpy(&data_[size_], sv.data(), n);
|
||||
size_ += n;
|
||||
}
|
||||
|
||||
void reserve(std::size_t sv_size)
|
||||
{
|
||||
if (capacity_ - size_ < sv_size)
|
||||
{
|
||||
auto constexpr limit = (std::numeric_limits<std::size_t>::max)();
|
||||
if (limit/2 < capacity_ || limit - size_ < sv_size)
|
||||
{
|
||||
BOOST_THROW_EXCEPTION(
|
||||
std::length_error{"temporary_buffer::append"});
|
||||
}
|
||||
|
||||
auto const new_cap = (std::max)(size_ + sv_size, capacity_*2);
|
||||
char* const p = new char[new_cap];
|
||||
std::memcpy(p, data_, size_);
|
||||
deallocate(boost::exchange(data_, p));
|
||||
capacity_ = new_cap;
|
||||
}
|
||||
}
|
||||
|
||||
void deallocate(char* data) noexcept
|
||||
{
|
||||
if (data != buffer_)
|
||||
delete[] data;
|
||||
}
|
||||
|
||||
char buffer_[4096];
|
||||
char* data_ = buffer_;
|
||||
std::size_t capacity_ = sizeof(buffer_);
|
||||
std::size_t size_ = 0;
|
||||
};
|
||||
|
||||
// Filter a token list
|
||||
//
|
||||
template<class Pred>
|
||||
void
|
||||
filter_token_list(
|
||||
detail::temporary_buffer& s,
|
||||
string_view 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);
|
||||
while(++it != last)
|
||||
{
|
||||
if(! pred(*it))
|
||||
{
|
||||
s.append(", ", *it);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Filter the last item in a token list
|
||||
template<class Pred>
|
||||
void
|
||||
filter_token_list_last(
|
||||
detail::temporary_buffer& s,
|
||||
string_view 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);
|
||||
return;
|
||||
}
|
||||
s.append(*it);
|
||||
for(;;)
|
||||
{
|
||||
it = next;
|
||||
next = std::next(it);
|
||||
if(next == te.end())
|
||||
{
|
||||
if(! pred(*it))
|
||||
{
|
||||
s.append(", ", *it);
|
||||
}
|
||||
return;
|
||||
}
|
||||
s.append(", ", *it);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct iequals_predicate
|
||||
{
|
||||
bool operator()(string_view s)
|
||||
bool
|
||||
operator()(string_view s) const
|
||||
{
|
||||
return beast::iequals(s, sv1) || beast::iequals(s, sv2);
|
||||
}
|
||||
@ -912,51 +756,19 @@ struct iequals_predicate
|
||||
string_view sv2;
|
||||
};
|
||||
|
||||
inline
|
||||
// Filter the last item in a token list
|
||||
BOOST_BEAST_DECL
|
||||
void
|
||||
filter_token_list_last(
|
||||
beast::detail::temporary_buffer& s,
|
||||
string_view value,
|
||||
iequals_predicate const& pred);
|
||||
|
||||
BOOST_BEAST_DECL
|
||||
void
|
||||
keep_alive_impl(
|
||||
detail::temporary_buffer& s, string_view value,
|
||||
unsigned version, bool keep_alive)
|
||||
{
|
||||
if(version < 11)
|
||||
{
|
||||
if(keep_alive)
|
||||
{
|
||||
// remove close
|
||||
filter_token_list(s, value, iequals_predicate{"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,
|
||||
iequals_predicate{"close", "keep-alive"});
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(keep_alive)
|
||||
{
|
||||
// remove close and keep-alive
|
||||
filter_token_list(s, value,
|
||||
iequals_predicate{"close", "keep-alive"});
|
||||
}
|
||||
else
|
||||
{
|
||||
// remove keep-alive
|
||||
filter_token_list(s, value, iequals_predicate{"keep-alive"});
|
||||
// add close
|
||||
if(s.empty())
|
||||
s.append("close");
|
||||
else if(! token_list{value}.exists("close"))
|
||||
s.append(", close");
|
||||
}
|
||||
}
|
||||
}
|
||||
beast::detail::temporary_buffer& s, string_view value,
|
||||
unsigned version, bool keep_alive);
|
||||
|
||||
} // detail
|
||||
|
||||
@ -1073,7 +885,7 @@ void
|
||||
basic_fields<Allocator>::
|
||||
set_chunked_impl(bool value)
|
||||
{
|
||||
detail::temporary_buffer buf;
|
||||
beast::detail::temporary_buffer buf;
|
||||
auto it = find(field::transfer_encoding);
|
||||
if(value)
|
||||
{
|
||||
@ -1104,8 +916,7 @@ set_chunked_impl(bool value)
|
||||
if(it == end())
|
||||
return;
|
||||
|
||||
detail::filter_token_list_last(buf, it->value(),
|
||||
detail::iequals_predicate{"chunked"});
|
||||
detail::filter_token_list_last(buf, it->value(), {"chunked"});
|
||||
if(! buf.empty())
|
||||
set(field::transfer_encoding, buf.view());
|
||||
else
|
||||
@ -1132,7 +943,7 @@ set_keep_alive_impl(
|
||||
{
|
||||
// VFALCO What about Proxy-Connection ?
|
||||
auto const value = (*this)[field::connection];
|
||||
detail::temporary_buffer buf;
|
||||
beast::detail::temporary_buffer buf;
|
||||
detail::keep_alive_impl(buf, value, version, keep_alive);
|
||||
if(buf.empty())
|
||||
erase(field::connection);
|
||||
@ -1394,4 +1205,8 @@ swap(basic_fields& other, std::false_type)
|
||||
} // beast
|
||||
} // boost
|
||||
|
||||
#ifdef BOOST_BEAST_HEADER_ONLY
|
||||
#include <boost/beast/http/impl/fields.ipp>
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
138
include/boost/beast/http/impl/fields.ipp
Normal file
138
include/boost/beast/http/impl/fields.ipp
Normal file
@ -0,0 +1,138 @@
|
||||
//
|
||||
// Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// Official repository: https://github.com/boostorg/beast
|
||||
//
|
||||
|
||||
#ifndef BOOST_BEAST_HTTP_IMPL_FIELDS_IPP
|
||||
#define BOOST_BEAST_HTTP_IMPL_FIELDS_IPP
|
||||
|
||||
#include <boost/beast/http/fields.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace beast {
|
||||
namespace http {
|
||||
namespace detail {
|
||||
|
||||
// `basic_fields` assumes that `std::size_t` is larger than `uint16_t`, so we
|
||||
// verify it explicitly here, so that users that use split compilation don't
|
||||
// need to pay the (fairly small) price for this sanity check
|
||||
BOOST_STATIC_ASSERT((std::numeric_limits<std::size_t>::max)() >=
|
||||
(std::numeric_limits<std::uint32_t>::max)());
|
||||
|
||||
// Filter a token list
|
||||
//
|
||||
inline
|
||||
void
|
||||
filter_token_list(
|
||||
beast::detail::temporary_buffer& s,
|
||||
string_view value,
|
||||
iequals_predicate const& 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);
|
||||
while(++it != last)
|
||||
{
|
||||
if(! pred(*it))
|
||||
{
|
||||
s.append(", ", *it);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
filter_token_list_last(
|
||||
beast::detail::temporary_buffer& s,
|
||||
string_view value,
|
||||
iequals_predicate const& 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);
|
||||
return;
|
||||
}
|
||||
s.append(*it);
|
||||
for(;;)
|
||||
{
|
||||
it = next;
|
||||
next = std::next(it);
|
||||
if(next == te.end())
|
||||
{
|
||||
if(! pred(*it))
|
||||
{
|
||||
s.append(", ", *it);
|
||||
}
|
||||
return;
|
||||
}
|
||||
s.append(", ", *it);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
keep_alive_impl(
|
||||
beast::detail::temporary_buffer& s, string_view value,
|
||||
unsigned version, bool keep_alive)
|
||||
{
|
||||
if(version < 11)
|
||||
{
|
||||
if(keep_alive)
|
||||
{
|
||||
// remove close
|
||||
filter_token_list(s, value, iequals_predicate{"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,
|
||||
iequals_predicate{"close", "keep-alive"});
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(keep_alive)
|
||||
{
|
||||
// remove close and keep-alive
|
||||
filter_token_list(s, value,
|
||||
iequals_predicate{"close", "keep-alive"});
|
||||
}
|
||||
else
|
||||
{
|
||||
// remove keep-alive
|
||||
filter_token_list(s, value, iequals_predicate{"keep-alive"});
|
||||
// add close
|
||||
if(s.empty())
|
||||
s.append("close");
|
||||
else if(! token_list{value}.exists("close"))
|
||||
s.append(", close");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // detail
|
||||
} // http
|
||||
} // beast
|
||||
} // boost
|
||||
|
||||
#endif // BOOST_BEAST_HTTP_IMPL_FIELDS_IPP
|
@ -31,6 +31,7 @@ the program, with the macro BOOST_BEAST_SEPARATE_COMPILATION defined.
|
||||
|
||||
#include <boost/beast/core/detail/base64.ipp>
|
||||
#include <boost/beast/core/detail/sha1.ipp>
|
||||
#include <boost/beast/core/detail/impl/temporary_buffer.ipp>
|
||||
#include <boost/beast/core/impl/error.ipp>
|
||||
#include <boost/beast/core/impl/file_posix.ipp>
|
||||
#include <boost/beast/core/impl/file_stdio.ipp>
|
||||
@ -44,6 +45,7 @@ the program, with the macro BOOST_BEAST_SEPARATE_COMPILATION defined.
|
||||
#include <boost/beast/http/impl/basic_parser.ipp>
|
||||
#include <boost/beast/http/impl/error.ipp>
|
||||
#include <boost/beast/http/impl/field.ipp>
|
||||
#include <boost/beast/http/impl/fields.ipp>
|
||||
#include <boost/beast/http/impl/rfc7230.ipp>
|
||||
#include <boost/beast/http/impl/status.ipp>
|
||||
#include <boost/beast/http/impl/verb.ipp>
|
||||
|
@ -25,7 +25,7 @@ class fields_test : public beast::unit_test::suite
|
||||
{
|
||||
public:
|
||||
static constexpr std::size_t max_static_buffer =
|
||||
sizeof(http::detail::temporary_buffer);
|
||||
sizeof(beast::detail::temporary_buffer);
|
||||
|
||||
template<class T>
|
||||
class test_allocator
|
||||
|
Reference in New Issue
Block a user