diff --git a/CHANGELOG.md b/CHANGELOG.md index 59e5b412..329e2969 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,11 +6,14 @@ API Changes: * Remove serializer::keep_alive * Remove serializer::chunked +* Add has_content_length_impl to Fields +* Add message::has_content_length Actions Required: * Call message::keep_alive instead of serializer::keep_alive * Call serializer::get::chunked instead of serializer::chunked +* Implement has_content_length_impl for user-defined Fields -------------------------------------------------------------------------------- diff --git a/doc/qbk/07_concepts/Fields.qbk b/doc/qbk/07_concepts/Fields.qbk index 05e626e5..59def1af 100644 --- a/doc/qbk/07_concepts/Fields.qbk +++ b/doc/qbk/07_concepts/Fields.qbk @@ -101,6 +101,14 @@ In this table: function returns `true`. ]] ] +][ + [`c.has_content_length()`] + [`bool`] + [ + Returns `true` if the + [@https://tools.ietf.org/html/rfc7230#section-3.3.2 [*Content-Length]] + field is present. + ] ][ [`a.set_method_impl(s)`] [] @@ -137,7 +145,7 @@ In this table: [ Adjusts the [@https://tools.ietf.org/html/rfc7230#section-3.3.1 [*Transfer-Encoding]] - field as follows: + field value as follows: [itemized_list [ @@ -153,6 +161,9 @@ In this table: empty, the Transfer-Encoding field shall not appear when the associated __FieldsReader__ serializes the fields. ]] + + If the result of adjusting the field value produces an empty + string, the field is removed from the container. ] ][ @@ -161,7 +172,7 @@ In this table: [ Adjusts the [@https://tools.ietf.org/html/rfc7230#section-3.3.2 [*Content-Length]] - field as follows: + field value as follows: [itemized_list [ @@ -203,6 +214,9 @@ In this table: in the value are removed, and the "close" token is added to the value if it is not already present. ]] + + If the result of adjusting the field value produces an empty + string, the field is removed from the container. ] ]] diff --git a/include/boost/beast/http/detail/type_traits.hpp b/include/boost/beast/http/detail/type_traits.hpp index fe783026..ff9cf3fd 100644 --- a/include/boost/beast/http/detail/type_traits.hpp +++ b/include/boost/beast/http/detail/type_traits.hpp @@ -61,6 +61,7 @@ protected: string_view get_reason_impl() const; bool get_chunked_impl() const; bool get_keep_alive_impl(unsigned) const; + bool has_content_length_impl() const; void set_method_impl(string_view); void set_target_impl(string_view); void set_reason_impl(string_view); @@ -134,54 +135,61 @@ struct is_fields_helper : T template static auto f6(int) -> decltype( - void(std::declval().set_method_impl(std::declval())), + std::declval() = std::declval().has_content_length_impl(), std::true_type()); static auto f6(...) -> std::false_type; using t6 = decltype(f6(0)); template static auto f7(int) -> decltype( - void(std::declval().set_target_impl(std::declval())), + void(std::declval().set_method_impl(std::declval())), std::true_type()); static auto f7(...) -> std::false_type; using t7 = decltype(f7(0)); template static auto f8(int) -> decltype( - void(std::declval().set_reason_impl(std::declval())), + void(std::declval().set_target_impl(std::declval())), std::true_type()); static auto f8(...) -> std::false_type; using t8 = decltype(f8(0)); template static auto f9(int) -> decltype( - void(std::declval().set_chunked_impl(std::declval())), + void(std::declval().set_reason_impl(std::declval())), std::true_type()); static auto f9(...) -> std::false_type; using t9 = decltype(f9(0)); template static auto f10(int) -> decltype( - void(std::declval().set_content_length_impl( - std::declval>())), + void(std::declval().set_chunked_impl(std::declval())), std::true_type()); static auto f10(...) -> std::false_type; using t10 = decltype(f10(0)); template static auto f11(int) -> decltype( + void(std::declval().set_content_length_impl( + std::declval>())), + std::true_type()); + static auto f11(...) -> std::false_type; + using t11 = decltype(f11(0)); + + template + static auto f12(int) -> decltype( void(std::declval().set_keep_alive_impl( std::declval(), std::declval())), std::true_type()); - static auto f11(...) -> std::false_type; - using t11 = decltype(f11(0)); + static auto f12(...) -> std::false_type; + using t12 = decltype(f12(0)); using type = std::integral_constant; + t10::value && t11::value && t12::value>; }; } // detail diff --git a/include/boost/beast/http/fields.hpp b/include/boost/beast/http/fields.hpp index d86f43cc..3ce63723 100644 --- a/include/boost/beast/http/fields.hpp +++ b/include/boost/beast/http/fields.hpp @@ -634,6 +634,11 @@ protected: bool get_keep_alive_impl(unsigned version) const; + /** Returns `true` if the Content-Length field is present. + */ + bool + has_content_length_impl() const; + /** Set or clear the method string. @note Only called for requests. diff --git a/include/boost/beast/http/impl/fields.ipp b/include/boost/beast/http/impl/fields.ipp index 64bf7f14..dd712d8a 100644 --- a/include/boost/beast/http/impl/fields.ipp +++ b/include/boost/beast/http/impl/fields.ipp @@ -938,6 +938,14 @@ get_keep_alive_impl(unsigned version) const it->value()}.exists("close"); } +template +bool +basic_fields:: +has_content_length_impl() const +{ + return count(field::content_length) > 0; +} + template inline void diff --git a/include/boost/beast/http/message.hpp b/include/boost/beast/http/message.hpp index 7453d8d6..94d389d9 100644 --- a/include/boost/beast/http/message.hpp +++ b/include/boost/beast/http/message.hpp @@ -723,6 +723,18 @@ struct message void chunked(bool value); + /** Returns `true` if the Content-Length field is present. + + This function inspects the fields and returns `true` if + the Content-Length field is present. The properties of the + body are not checked, this only looks for the field. + */ + bool + has_content_length() const + { + return this->has_content_length_impl(); + } + /** Set or clear the Content-Length field This function adjusts the Content-Length field as follows: diff --git a/test/beast/http/message.cpp b/test/beast/http/message.cpp index b7b83177..7f32bacc 100644 --- a/test/beast/http/message.cpp +++ b/test/beast/http/message.cpp @@ -203,6 +203,7 @@ public: string_view get_reason_impl() const { return {}; } bool get_chunked_impl() const { return false; } bool get_keep_alive_impl(unsigned) const { return true; } + bool has_content_length_impl() const { return false; } void set_method_impl(string_view) {} void set_target_impl(string_view s) { target = s.to_string(); } void set_reason_impl(string_view) {} @@ -240,6 +241,7 @@ public: BEAST_EXPECT(req.method() == verb::get); BEAST_EXPECT(req.target() == "/"); BEAST_EXPECT(req.body() == "Hello"); + BEAST_EXPECT(! req.has_content_length()); } { response res; @@ -267,6 +269,7 @@ public: BEAST_EXPECT(res.result() == status::bad_request); BEAST_EXPECT(res.reason() == "Bad Request"); BEAST_EXPECT(res.body() == "Hello"); + BEAST_EXPECT(! res.has_content_length()); } } diff --git a/test/doc/exemplars.cpp b/test/doc/exemplars.cpp index e97d6852..2099a7f8 100644 --- a/test/doc/exemplars.cpp +++ b/test/doc/exemplars.cpp @@ -224,6 +224,11 @@ protected: bool get_keep_alive_impl(unsigned version) const; + /** Returns `true` if the Content-Length field is present. + */ + bool + has_content_length_impl() const; + /** Set or clear the method string. @note Only called for requests.