diff --git a/include/boost/http_proto.hpp b/include/boost/http_proto.hpp index 8944aba9..aebdb669 100644 --- a/include/boost/http_proto.hpp +++ b/include/boost/http_proto.hpp @@ -24,16 +24,12 @@ #include #include #include -#include #include #include -#include #include #include #include #include -#include -#include #include #include #include diff --git a/include/boost/http_proto/fields_base.hpp b/include/boost/http_proto/fields_base.hpp index 01b96f04..d0615e1a 100644 --- a/include/boost/http_proto/fields_base.hpp +++ b/include/boost/http_proto/fields_base.hpp @@ -37,7 +37,7 @@ class fields_base detail::header h_; std::size_t max_cap_ = std::numeric_limits::max(); - bool external_storage_ = false; + bool view_ = false; using entry = detail::header::entry; @@ -46,6 +46,9 @@ class fields_base using table = detail::header::table; + struct view_tag_t {}; + static constexpr view_tag_t view_tag{}; + class op_t; class prefix_op_t { @@ -65,13 +68,11 @@ class fields_base friend class fields; friend class message_base; - friend class request_base; friend class request; - friend class static_request; - friend class response_base; friend class response; - friend class static_response; friend class parser; + friend class request_parser; + friend class response_parser; friend class serializer; BOOST_HTTP_PROTO_DECL @@ -79,12 +80,6 @@ class fields_base fields_base( detail::kind k) noexcept; - BOOST_HTTP_PROTO_DECL - fields_base( - detail::kind k, - void* storage, - std::size_t cap) noexcept; - BOOST_HTTP_PROTO_DECL fields_base( detail::kind k, @@ -101,9 +96,8 @@ class fields_base BOOST_HTTP_PROTO_DECL fields_base( - detail::header const& h, - void* storage, - std::size_t cap); + view_tag_t, + detail::header const& h); public: //-------------------------------------------- @@ -1349,6 +1343,9 @@ class fields_base copy_impl( detail::header const&); + void + clone_if_needed(); + BOOST_HTTP_PROTO_DECL void insert_impl( diff --git a/include/boost/http_proto/message_base.hpp b/include/boost/http_proto/message_base.hpp index 24e3a995..8d1fcfa9 100644 --- a/include/boost/http_proto/message_base.hpp +++ b/include/boost/http_proto/message_base.hpp @@ -18,8 +18,7 @@ namespace boost { namespace http_proto { -/** Mixin for modifing common metadata - in HTTP request and response messages. +/** Mixin for common metadata in HTTP request and response messages. This type is useful for modifying common properties shared by both requests @@ -28,15 +27,13 @@ namespace http_proto { @see @ref response, @ref request, - @ref static_response, - @ref static_request, @ref metadata. */ class message_base : public fields_base { - friend class request_base; - friend class response_base; + friend class request; + friend class response; using fields_base::fields_base; diff --git a/include/boost/http_proto/parser.hpp b/include/boost/http_proto/parser.hpp index 6af8c8dd..8d92206c 100644 --- a/include/boost/http_proto/parser.hpp +++ b/include/boost/http_proto/parser.hpp @@ -32,8 +32,6 @@ namespace http_proto { // Forward declaration class request_parser; class response_parser; -class static_request; -class static_response; /** A parser for HTTP/1 messages. @@ -624,11 +622,8 @@ class parser void start_impl(bool); - static_request const& - safe_get_request() const; - - static_response const& - safe_get_response() const; + detail::header const& + safe_get_header() const; BOOST_HTTP_PROTO_DECL detail::workspace& diff --git a/include/boost/http_proto/request.hpp b/include/boost/http_proto/request.hpp index 075d9bcb..ce11a4a3 100644 --- a/include/boost/http_proto/request.hpp +++ b/include/boost/http_proto/request.hpp @@ -1,4 +1,5 @@ // +// Copyright (c) 2021 Vinnie Falco (vinnie.falco@gmail.com) // Copyright (c) 2025 Mohammad Nejati // // Distributed under the Boost Software License, Version 1.0. (See accompanying @@ -10,12 +11,13 @@ #ifndef BOOST_HTTP_PROTO_REQUEST_HPP #define BOOST_HTTP_PROTO_REQUEST_HPP -#include +#include +#include namespace boost { namespace http_proto { -/** A modifiable container for HTTP requests. +/** A container for HTTP requests. This container owns a request, represented by a buffer which is managed by performing @@ -42,12 +44,21 @@ namespace http_proto { @endcode @see - @ref static_request, - @ref request_base. + @ref request_parser, + @ref response. */ class request - : public request_base + : public message_base { + friend class request_parser; + + request( + view_tag_t, + detail::header const& h) noexcept + : message_base(view_tag, h) + { + } + public: //-------------------------------------------- // @@ -73,7 +84,10 @@ class request @par Complexity Constant. */ - request() noexcept = default; + request() noexcept + : message_base(detail::kind::request) + { + } /** Constructor. @@ -112,7 +126,7 @@ class request explicit request( core::string_view s) - : request_base(s) + : message_base(detail::kind::request, s) { } @@ -143,7 +157,7 @@ class request http_proto::method m, core::string_view t, http_proto::version v) noexcept - : request() + : message_base(detail::kind::request) { set_start_line(m, t, v); } @@ -206,7 +220,7 @@ class request request( std::size_t cap, std::size_t max_cap = std::size_t(-1)) - : request() + : message_base(detail::kind::request) { reserve_bytes(cap); set_max_capacity_in_bytes(max_cap); @@ -233,7 +247,7 @@ class request */ request( request&& other) noexcept - : request() + : message_base(detail::kind::request) { swap(other); } @@ -259,30 +273,6 @@ class request request( request const& r) = default; - /** Constructor. - - The newly constructed object contains - a copy of `r`. - - @par Postconditions - @code - this->buffer() == r.buffer() && this->buffer.data() != r.buffer().data() - @endcode - - @par Complexity - Linear in `r.size()`. - - @par Exception Safety - Calls to allocate may throw. - - @param r The request to copy. - */ - request( - request_base const& r) - : request_base(r) - { - } - /** Assignment The contents of `r` are transferred to @@ -346,40 +336,6 @@ class request return *this; } - /** Assignment. - - The contents of `r` are copied and - the previous contents of `this` are - discarded. - - @par Postconditions - @code - this->buffer() == r.buffer() && this->buffer().data() != r.buffer().data() - @endcode - - @par Complexity - Linear in `r.size()`. - - @par Exception Safety - Strong guarantee. - Calls to allocate may throw. - Exception thrown if max capacity exceeded. - - @throw std::length_error - Max capacity would be exceeded. - - @param r The request to copy. - - @return A reference to this object. - */ - request& - operator=( - request_base const& r) - { - copy_impl(r.h_); - return *this; - } - //-------------------------------------------- /** Swap. @@ -409,6 +365,7 @@ class request { h_.swap(other.h_); std::swap(max_cap_, other.max_cap_); + std::swap(view_, other.view_); } /** Swap. @@ -450,6 +407,254 @@ class request { v0.swap(v1); } + + //-------------------------------------------- + // + // Observers + // + //-------------------------------------------- + + /** Return the method as a name constant. + + If the method returned is equal to + @ref method::unknown, the method may + be obtained as a string instead, by + calling @ref method_text. + */ + http_proto::method + method() const noexcept + { + return h_.req.method; + } + + /** Return the method as a string. + */ + core::string_view + method_text() const noexcept + { + return core::string_view( + h_.cbuf, + h_.req.method_len); + } + + /** Return the request-target string. + */ + core::string_view + target() const noexcept + { + return core::string_view( + h_.cbuf + + h_.req.method_len + 1, + h_.req.target_len); + } + + //-------------------------------------------- + // + // Modifiers + // + //-------------------------------------------- + + /** Set the method of the request to the enum. + + @par Exception Safety + Strong guarantee. + Calls to allocate may throw. + Exception thrown if max capacity exceeded. + + @throw std::length_error + Max capacity would be exceeded. + + @param m The method to set. + */ + void + set_method( + http_proto::method m) + { + set_start_line_impl( + m, + to_string(m), + target(), + version()); + } + + /** Set the method of the request to the string. + + @par Exception Safety + Strong guarantee. + Calls to allocate may throw. + Exception thrown on invalid input. + Exception thrown if max capacity exceeded. + + @throw system_error + Input is invalid. + + @throw std::length_error + Max capacity would be exceeded. + + @param s A string view representing the + method to set. + */ + void + set_method( + core::string_view s) + { + set_start_line_impl( + string_to_method(s), + s, + target(), + version()); + } + + /** Set the target string of the request. + + This function sets the request-target. + The caller is responsible for ensuring + that the string passed is syntactically + valid. + + @par Exception Safety + Strong guarantee. + Calls to allocate may throw. + Exception thrown on invalid input. + Exception thrown if max capacity exceeded. + + @throw system_error + Input is invalid. + + @throw std::length_error + Max capacity would be exceeded. + + @param s A string view representing the + target to set. + */ + void + set_target( + core::string_view s) + { + set_start_line_impl( + h_.req.method, + method_text(), + s, + version()); + } + + /** Set the HTTP version of the request. + + @par Exception Safety + Strong guarantee. + Calls to allocate may throw. + Exception thrown if max capacity exceeded. + + @throw std::length_error + Max capacity would be exceeded. + + @param v The version to set. + */ + void + set_version( + http_proto::version v) + { + set_start_line_impl( + h_.req.method, + method_text(), + target(), + v); + } + + /** Set the method, target, and version of the request. + + This is more efficient than setting the + properties individually. + + @par Exception Safety + Strong guarantee. + Calls to allocate may throw. + Exception thrown on invalid input. + Exception thrown if max capacity exceeded. + + @throw system_error + Input is invalid. + + @throw std::length_error + Max capacity would be exceeded. + + @param m The method to set. + + @param t A string view representing the + target to set. + + @param v The version to set. + */ + void + set_start_line( + http_proto::method m, + core::string_view t, + http_proto::version v = + http_proto::version::http_1_1) + { + set_start_line_impl(m, to_string(m), t, v); + } + + /** Set the method, target, and version of the request. + + This is more efficient than setting the + properties individually. + + @par Exception Safety + Strong guarantee. + Calls to allocate may throw. + Exception thrown on invalid input. + Exception thrown if max capacity exceeded. + + @throw system_error + Input is invalid. + + @throw std::length_error + Max capacity would be exceeded. + + @param m A string view representing the + method to set. + + @param t A string view representing the + target to set. + + @param v The version to set. + */ + void + set_start_line( + core::string_view m, + core::string_view t, + http_proto::version v = + http_proto::version::http_1_1) + { + set_start_line_impl(string_to_method(m), m, t, v); + } + + /** Set the `Expect: 100-continue` header. + + @par Exception Safety + Strong guarantee. + Calls to allocate may throw. + Exception thrown if max capacity exceeded. + + @throw std::length_error + Max capacity would be exceeded. + + @param b If `true` sets `Expect: 100-continue` + header otherwise erase it. + */ + BOOST_HTTP_PROTO_DECL + void + set_expect_100_continue(bool b); + +private: + BOOST_HTTP_PROTO_DECL + void + set_start_line_impl( + http_proto::method m, + core::string_view ms, + core::string_view t, + http_proto::version v); }; } // http_proto diff --git a/include/boost/http_proto/request_base.hpp b/include/boost/http_proto/request_base.hpp deleted file mode 100644 index 450158d3..00000000 --- a/include/boost/http_proto/request_base.hpp +++ /dev/null @@ -1,305 +0,0 @@ -// -// Copyright (c) 2021 Vinnie Falco (vinnie.falco@gmail.com) -// Copyright (c) 2025 Mohammad Nejati -// -// 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/cppalliance/http_proto -// - -#ifndef BOOST_HTTP_PROTO_REQUEST_BASE_HPP -#define BOOST_HTTP_PROTO_REQUEST_BASE_HPP - -#include -#include - -namespace boost { -namespace http_proto { - -/** Mixin for modifing HTTP requests. - - @see - @ref message_base, - @ref request, - @ref static_request. -*/ -class request_base - : public message_base -{ - friend class request; - friend class static_request; - - request_base() noexcept - : message_base(detail::kind::request) - { - } - - explicit - request_base(core::string_view s) - : message_base(detail::kind::request, s) - { - } - - request_base( - void* storage, - std::size_t cap) noexcept - : message_base( - detail::kind::request, storage, cap) - { - } - -public: - //-------------------------------------------- - // - // Observers - // - //-------------------------------------------- - - /** Return the method as a name constant. - - If the method returned is equal to - @ref method::unknown, the method may - be obtained as a string instead, by - calling @ref method_text. - */ - http_proto::method - method() const noexcept - { - return h_.req.method; - } - - /** Return the method as a string. - */ - core::string_view - method_text() const noexcept - { - return core::string_view( - h_.cbuf, - h_.req.method_len); - } - - /** Return the request-target string. - */ - core::string_view - target() const noexcept - { - return core::string_view( - h_.cbuf + - h_.req.method_len + 1, - h_.req.target_len); - } - - //-------------------------------------------- - // - // Modifiers - // - //-------------------------------------------- - - /** Set the method of the request to the enum. - - @par Exception Safety - Strong guarantee. - Calls to allocate may throw. - Exception thrown if max capacity exceeded. - - @throw std::length_error - Max capacity would be exceeded. - - @param m The method to set. - */ - void - set_method( - http_proto::method m) - { - set_start_line_impl( - m, - to_string(m), - target(), - version()); - } - - /** Set the method of the request to the string. - - @par Exception Safety - Strong guarantee. - Calls to allocate may throw. - Exception thrown on invalid input. - Exception thrown if max capacity exceeded. - - @throw system_error - Input is invalid. - - @throw std::length_error - Max capacity would be exceeded. - - @param s A string view representing the - method to set. - */ - void - set_method( - core::string_view s) - { - set_start_line_impl( - string_to_method(s), - s, - target(), - version()); - } - - /** Set the target string of the request. - - This function sets the request-target. - The caller is responsible for ensuring - that the string passed is syntactically - valid. - - @par Exception Safety - Strong guarantee. - Calls to allocate may throw. - Exception thrown on invalid input. - Exception thrown if max capacity exceeded. - - @throw system_error - Input is invalid. - - @throw std::length_error - Max capacity would be exceeded. - - @param s A string view representing the - target to set. - */ - void - set_target( - core::string_view s) - { - set_start_line_impl( - h_.req.method, - method_text(), - s, - version()); - } - - /** Set the HTTP version of the request. - - @par Exception Safety - Strong guarantee. - Calls to allocate may throw. - Exception thrown if max capacity exceeded. - - @throw std::length_error - Max capacity would be exceeded. - - @param v The version to set. - */ - void - set_version( - http_proto::version v) - { - set_start_line_impl( - h_.req.method, - method_text(), - target(), - v); - } - - /** Set the method, target, and version of the request. - - This is more efficient than setting the - properties individually. - - @par Exception Safety - Strong guarantee. - Calls to allocate may throw. - Exception thrown on invalid input. - Exception thrown if max capacity exceeded. - - @throw system_error - Input is invalid. - - @throw std::length_error - Max capacity would be exceeded. - - @param m The method to set. - - @param t A string view representing the - target to set. - - @param v The version to set. - */ - void - set_start_line( - http_proto::method m, - core::string_view t, - http_proto::version v = - http_proto::version::http_1_1) - { - set_start_line_impl(m, to_string(m), t, v); - } - - /** Set the method, target, and version of the request. - - This is more efficient than setting the - properties individually. - - @par Exception Safety - Strong guarantee. - Calls to allocate may throw. - Exception thrown on invalid input. - Exception thrown if max capacity exceeded. - - @throw system_error - Input is invalid. - - @throw std::length_error - Max capacity would be exceeded. - - @param m A string view representing the - method to set. - - @param t A string view representing the - target to set. - - @param v The version to set. - */ - void - set_start_line( - core::string_view m, - core::string_view t, - http_proto::version v = - http_proto::version::http_1_1) - { - set_start_line_impl(string_to_method(m), m, t, v); - } - - /** Set the `Expect: 100-continue` header. - - @par Exception Safety - Strong guarantee. - Calls to allocate may throw. - Exception thrown if max capacity exceeded. - - @throw std::length_error - Max capacity would be exceeded. - - @param b If `true` sets `Expect: 100-continue` - header otherwise erase it. - */ - BOOST_HTTP_PROTO_DECL - void - set_expect_100_continue(bool b); - -private: - BOOST_HTTP_PROTO_DECL - void - set_start_line_impl( - http_proto::method m, - core::string_view ms, - core::string_view t, - http_proto::version v); -}; - -} // http_proto -} // boost - -#endif diff --git a/include/boost/http_proto/request_parser.hpp b/include/boost/http_proto/request_parser.hpp index 9c4ef457..56683b8c 100644 --- a/include/boost/http_proto/request_parser.hpp +++ b/include/boost/http_proto/request_parser.hpp @@ -15,7 +15,7 @@ #include #include #include -#include +#include namespace boost { namespace http_proto { @@ -161,7 +161,7 @@ class request_parser @ref got_header. */ BOOST_HTTP_PROTO_DECL - static_request const& + request get() const; }; diff --git a/include/boost/http_proto/response.hpp b/include/boost/http_proto/response.hpp index e4086ec2..1d45cbcc 100644 --- a/include/boost/http_proto/response.hpp +++ b/include/boost/http_proto/response.hpp @@ -12,12 +12,14 @@ #ifndef BOOST_HTTP_PROTO_RESPONSE_HPP #define BOOST_HTTP_PROTO_RESPONSE_HPP -#include +#include +#include +#include namespace boost { namespace http_proto { -/** A modifiable container for HTTP responses. +/** A container for HTTP responses. This container owns a response, represented by a buffer which is managed by performing @@ -44,12 +46,21 @@ namespace http_proto { @endcode @see - @ref static_response, - @ref response_base. + @ref response_parser, + @ref request. */ class response - : public response_base + : public message_base { + friend class response_parser; + + response( + view_tag_t, + detail::header const& h) noexcept + : message_base(view_tag, h) + { + } + public: //-------------------------------------------- // @@ -75,7 +86,10 @@ class response @par Complexity Constant. */ - response() noexcept = default; + response() noexcept + : message_base(detail::kind::response) + { + } /** Constructor. @@ -114,7 +128,7 @@ class response explicit response( core::string_view s) - : response_base(s) + : message_base(detail::kind::response, s) { } @@ -255,29 +269,6 @@ class response */ response(response const&) = default; - /** Constructor. - - The newly constructed object contains - a copy of `r`. - - @par Postconditions - @code - this->buffer() == r.buffer() && this->buffer.data() != r.buffer().data() - @endcode - - @par Complexity - Linear in `r.size()`. - - @par Exception Safety - Calls to allocate may throw. - - @param r The response to copy. - */ - response(response_base const& r) - : response_base(r) - { - } - /** Assignment The contents of `r` are transferred to @@ -342,40 +333,6 @@ class response return *this; } - /** Assignment. - - The contents of `r` are copied and - the previous contents of `this` are - discarded. - - @par Postconditions - @code - this->buffer() == r.buffer() && this->buffer().data() != r.buffer().data() - @endcode - - @par Complexity - Linear in `r.size()`. - - @par Exception Safety - Strong guarantee. - Calls to allocate may throw. - Exception thrown if max capacity exceeded. - - @throw std::length_error - Max capacity would be exceeded. - - @param r The response to copy. - - @return A reference to this object. - */ - response& - operator=( - response_base const& r) - { - copy_impl(r.h_); - return *this; - } - //-------------------------------------------- /** Swap. @@ -405,6 +362,7 @@ class response { h_.swap(other.h_); std::swap(max_cap_, other.max_cap_); + std::swap(view_, other.view_); } /** Swap. @@ -446,6 +404,183 @@ class response { v0.swap(v1); } + + //-------------------------------------------- + // + // Observers + // + //-------------------------------------------- + + /** Return the reason string. + + This field is obsolete in HTTP/1 + and should only be used for display + purposes. + */ + core::string_view + reason() const noexcept + { + return core::string_view( + h_.cbuf + 13, + h_.prefix - 15); + } + + /** Return the status code. + */ + http_proto::status + status() const noexcept + { + return h_.res.status; + } + + /** Return the status code as an integral. + */ + unsigned short + status_int() const noexcept + { + return h_.res.status_int; + } + + //-------------------------------------------- + // + // Modifiers + // + //-------------------------------------------- + + /** Set the status code and version of the response. + + The reason-phrase will be set to the + standard text for the specified status + code. + + This is more efficient than setting the + properties individually. + + @par Exception Safety + Strong guarantee. + Calls to allocate may throw. + Exception thrown if max capacity exceeded. + + @throw std::length_error + Max capacity would be exceeded. + @throw std::invalid_argument + `sc == status::unknown` + + @param sc The status code to set. This + must not be @ref status::unknown. + + @param v The version to set. + */ + void + set_start_line( + http_proto::status sc, + http_proto::version v = + http_proto::version::http_1_1) + { + set_start_line_impl(sc, + static_cast(sc), + to_string(sc), v); + } + + /** Set the HTTP version of the response + + @par Exception Safety + Strong guarantee. + Calls to allocate may throw. + Exception thrown if maximum capacity exceeded. + + @throw std::length_error + Maximum capacity would be exceeded. + + @param v The version to set. + */ + BOOST_HTTP_PROTO_DECL + void + set_version( + http_proto::version v); + + /** Set the status code of the response. + + The reason-phrase will be set to the + standard text for the specified status + code. The version will remain unchanged. + + @par Exception Safety + Strong guarantee. + Calls to allocate may throw. + Exception thrown if maximum capacity exceeded. + + @throw std::length_error + Maximum capacity would be exceeded. + @throw std::invalid_argument + `sc == status::unknown` + + @param sc The status code to set. This + must not be @ref status::unknown. + */ + void + set_status( + http_proto::status sc) + { + if(sc == http_proto::status::unknown) + detail::throw_invalid_argument(); + set_start_line_impl(sc, + static_cast(sc), + to_string(sc), + version()); + } + + /** Set the status code and version of the response. + + The reason-phrase will be set to the + standard text for the specified status + code. + + This is more efficient than setting the + properties individually. + + @par Exception Safety + Strong guarantee. + Calls to allocate may throw. + Exception thrown on invalid input. + Exception thrown if max capacity exceeded. + + @throw system_error + Input is invalid. + + @throw std::length_error + Max capacity would be exceeded. + + @param si An integral representing the + status code to set. + + @param reason A string view representing the + reason string to set. + + @param v The version to set. + */ + void + set_start_line( + unsigned short si, + core::string_view reason, + http_proto::version v = + http_proto::version::http_1_1) + { + set_start_line_impl( + int_to_status(si), + si, + reason, + v); + } + +private: + BOOST_HTTP_PROTO_DECL + void + set_start_line_impl( + http_proto::status sc, + unsigned short si, + core::string_view reason, + http_proto::version v); }; } // http_proto diff --git a/include/boost/http_proto/response_base.hpp b/include/boost/http_proto/response_base.hpp deleted file mode 100644 index aea2ddb9..00000000 --- a/include/boost/http_proto/response_base.hpp +++ /dev/null @@ -1,236 +0,0 @@ -// -// Copyright (c) 2021 Vinnie Falco (vinnie.falco@gmail.com) -// Copyright (c) 2024 Christian Mazakas -// Copyright (c) 2025 Mohammad Nejati -// -// 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/cppalliance/http_proto -// - -#ifndef BOOST_HTTP_PROTO_RESPONSE_BASE_HPP -#define BOOST_HTTP_PROTO_RESPONSE_BASE_HPP - -#include -#include -#include - -namespace boost { -namespace http_proto { - -/** Mixin for modifing HTTP responses. - - @see - @ref message_base, - @ref response, - @ref static_response. -*/ -class response_base - : public message_base -{ - friend class response; - friend class static_response; - - response_base() noexcept - : message_base(detail::kind::response) - { - } - - explicit - response_base(core::string_view s) - : message_base(detail::kind::response, s) - { - } - - response_base( - void* storage, - std::size_t cap) noexcept - : message_base( - detail::kind::response, storage, cap) - { - } - -public: - //-------------------------------------------- - // - // Observers - // - //-------------------------------------------- - - /** Return the reason string. - - This field is obsolete in HTTP/1 - and should only be used for display - purposes. - */ - core::string_view - reason() const noexcept - { - return core::string_view( - h_.cbuf + 13, - h_.prefix - 15); - } - - /** Return the status code. - */ - http_proto::status - status() const noexcept - { - return h_.res.status; - } - - /** Return the status code as an integral. - */ - unsigned short - status_int() const noexcept - { - return h_.res.status_int; - } - - //-------------------------------------------- - // - // Modifiers - // - //-------------------------------------------- - - /** Set the status code and version of the response. - - The reason-phrase will be set to the - standard text for the specified status - code. - - This is more efficient than setting the - properties individually. - - @par Exception Safety - Strong guarantee. - Calls to allocate may throw. - Exception thrown if max capacity exceeded. - - @throw std::length_error - Max capacity would be exceeded. - @throw std::invalid_argument - `sc == status::unknown` - - @param sc The status code to set. This - must not be @ref status::unknown. - - @param v The version to set. - */ - void - set_start_line( - http_proto::status sc, - http_proto::version v = - http_proto::version::http_1_1) - { - set_start_line_impl(sc, - static_cast(sc), - to_string(sc), v); - } - - /** Set the HTTP version of the response - - @par Exception Safety - Strong guarantee. - Calls to allocate may throw. - Exception thrown if maximum capacity exceeded. - - @throw std::length_error - Maximum capacity would be exceeded. - - @param v The version to set. - */ - BOOST_HTTP_PROTO_DECL - void - set_version( - http_proto::version v); - - /** Set the status code of the response. - - The reason-phrase will be set to the - standard text for the specified status - code. The version will remain unchanged. - - @par Exception Safety - Strong guarantee. - Calls to allocate may throw. - Exception thrown if maximum capacity exceeded. - - @throw std::length_error - Maximum capacity would be exceeded. - @throw std::invalid_argument - `sc == status::unknown` - - @param sc The status code to set. This - must not be @ref status::unknown. - */ - void - set_status( - http_proto::status sc) - { - if(sc == http_proto::status::unknown) - detail::throw_invalid_argument(); - set_start_line_impl(sc, - static_cast(sc), - to_string(sc), - version()); - } - - /** Set the status code and version of the response. - - The reason-phrase will be set to the - standard text for the specified status - code. - - This is more efficient than setting the - properties individually. - - @par Exception Safety - Strong guarantee. - Calls to allocate may throw. - Exception thrown on invalid input. - Exception thrown if max capacity exceeded. - - @throw system_error - Input is invalid. - - @throw std::length_error - Max capacity would be exceeded. - - @param si An integral representing the - status code to set. - - @param reason A string view representing the - reason string to set. - - @param v The version to set. - */ - void - set_start_line( - unsigned short si, - core::string_view reason, - http_proto::version v = - http_proto::version::http_1_1) - { - set_start_line_impl( - int_to_status(si), - si, - reason, - v); - } - -private: - BOOST_HTTP_PROTO_DECL - void - set_start_line_impl( - http_proto::status sc, - unsigned short si, - core::string_view reason, - http_proto::version v); -}; - -} // http_proto -} // boost - -#endif diff --git a/include/boost/http_proto/response_parser.hpp b/include/boost/http_proto/response_parser.hpp index 97f935c5..129e5cb2 100644 --- a/include/boost/http_proto/response_parser.hpp +++ b/include/boost/http_proto/response_parser.hpp @@ -14,7 +14,7 @@ #include #include #include -#include +#include #include namespace boost { @@ -190,7 +190,7 @@ class response_parser @ref got_header. */ BOOST_HTTP_PROTO_DECL - static_response const& + response get() const; }; diff --git a/include/boost/http_proto/static_request.hpp b/include/boost/http_proto/static_request.hpp deleted file mode 100644 index b13ff1a4..00000000 --- a/include/boost/http_proto/static_request.hpp +++ /dev/null @@ -1,194 +0,0 @@ -// -// Copyright (c) 2025 Mohammad Nejati -// -// 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/cppalliance/http_proto -// - -#ifndef BOOST_HTTP_PROTO_STATIC_REQUEST_HPP -#define BOOST_HTTP_PROTO_STATIC_REQUEST_HPP - -#include - -namespace boost { -namespace http_proto { - -/** A modifiable static container for HTTP requests. - - This container uses an external memory - storage with fixed capacity. - The contents may be inspected and modified, - and the implementation maintains a useful - invariant: changes to the request always - leave it in a valid state. - - @par Example - @code - char buf[1024]; - static_request req(buf, sizeof(buf)); - - req.set_start_line(method::get, "/"); - req.set(field::host, "example.com"); - req.set(field::accept_encoding, "gzip, deflate, br"); - req.set(field::cache_control, "no-cache"); - - assert(req.buffer() == - "GET / HTTP/1.1\r\n" - "Host: example.com\r\n" - "Accept-Encoding: gzip, deflate, br\r\n" - "Cache-Control: no-cache\r\n" - "\r\n"); - @endcode - - @par Invariants - @code - this->capacity_in_bytes() == Capacity && this->max_capacity_in_bytes() == - Capacity - @endcode - - @tparam Capacity The maximum capacity in bytes. - - @see - @ref request, - @ref request_base. -*/ -class static_request - : public request_base -{ -public: - //-------------------------------------------- - // - // Special Members - // - //-------------------------------------------- - - /** Constructor. - - Constructs a request object that uses an - external memory storage and does not perform - any allocations during its lifetime. - - The caller is responsible for ensuring that the - lifetime of the storage extends until the - request object is destroyed. - - @par Postcondition - @code - this->capacity_in_bytes() == cap - this->max_capacity_in_bytes() == cap - @endcode - - @param storage The storage to use. - @param cap The capacity of the storage. - */ - static_request( - void* storage, - std::size_t cap) - : request_base(storage, cap) - { - } - - /** Constructor (deleted) - */ - static_request( - static_request const&) = delete; - - /** Constructor. - - The contents of `r` are transferred - to the newly constructed object, - which includes the underlying - character buffer. - After construction, the moved-from - object has a valid but unspecified - state where the only safe operation - is destruction. - - @par Complexity - Constant. - - @param r The request to move from. - */ - static_request( - static_request&& r) noexcept - : request_base() - { - h_.swap(r.h_); - external_storage_ = true; - max_cap_ = r.max_cap_; - r.max_cap_ = 0; - } - - /** Assignment. - - The contents of `r` are copied and - the previous contents of `this` are - discarded. - - @par Postconditions - @code - this->buffer() == r.buffer() && this->buffer().data() != r.buffer().data() - @endcode - - @par Complexity - Linear in `r.size()`. - - @par Exception Safety - Strong guarantee. - Exception thrown if max capacity exceeded. - - @throw std::length_error - Max capacity would be exceeded. - - @param r The request to copy. - - @return A reference to this object. - */ - static_request& - operator=( - static_request const& r) - { - copy_impl(r.h_); - return *this; - } - - /** Assignment. - - The contents of `r` are copied and - the previous contents of `this` are - discarded. - - @par Postconditions - @code - this->buffer() == r.buffer() && this->buffer().data() != r.buffer().data() - @endcode - - @par Complexity - Linear in `r.size()`. - - @par Exception Safety - Strong guarantee. - Exception thrown if max capacity exceeded. - - @throw std::length_error - Max capacity would be exceeded. - - @param r The request to copy. - - @return A reference to this object. - */ - static_request& - operator=( - request_base const& r) - { - copy_impl(r.h_); - return *this; - } -}; - -} // http_proto -} // boost - -#endif diff --git a/include/boost/http_proto/static_response.hpp b/include/boost/http_proto/static_response.hpp deleted file mode 100644 index 3a9e2702..00000000 --- a/include/boost/http_proto/static_response.hpp +++ /dev/null @@ -1,193 +0,0 @@ -// -// Copyright (c) 2025 Mohammad Nejati -// -// 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/cppalliance/http_proto -// - -#ifndef BOOST_HTTP_PROTO_STATIC_RESPONSE_HPP -#define BOOST_HTTP_PROTO_STATIC_RESPONSE_HPP - -#include - -namespace boost { -namespace http_proto { - -/** A modifiable static container for HTTP responses. - - This container uses an external memory - storage with fixed capacity. - The contents may be inspected and modified, - and the implementation maintains a useful - invariant: changes to the response always - leave it in a valid state. - - @par Example - @code - char buf[1024]; - static_response res(buf, sizeof(buf)); - - res.set_start_line(status::not_found); - res.set(field::server, "Boost.HttpProto"); - res.set(field::content_type, "text/plain"); - res.set_content_length(80); - - assert(res.buffer() == - "HTTP/1.1 404 Not Found\r\n" - "Server: Boost.HttpProto\r\n" - "Content-Type: text/plain\r\n" - "Content-Length: 80\r\n" - "\r\n"); - @endcode - - @par Invariants - @code - this->capacity_in_bytes() == Capacity && this->max_capacity_in_bytes() == Capacity - @endcode - - @tparam Capacity The maximum capacity in bytes. - - @see - @ref response, - @ref response_base. -*/ -class static_response - : public response_base -{ -public: - //-------------------------------------------- - // - // Special Members - // - //-------------------------------------------- - - /** Constructor. - - Constructs a response object that uses an - external memory storage and does not perform - any allocations during its lifetime. - - The caller is responsible for ensuring that the - lifetime of the storage extends until the - response object is destroyed. - - @par Postcondition - @code - this->capacity_in_bytes() == cap - this->max_capacity_in_bytes() == cap - @endcode - - @param storage The storage to use. - @param cap The capacity of the storage. - */ - static_response( - void* storage, - std::size_t cap) - : response_base(storage, cap) - { - } - - /** Constructor (deleted) - */ - static_response( - static_response const&) = delete; - - /** Constructor. - - The contents of `r` are transferred - to the newly constructed object, - which includes the underlying - character buffer. - After construction, the moved-from - object has a valid but unspecified - state where the only safe operation - is destruction. - - @par Complexity - Constant. - - @param r The response to move from. - */ - static_response( - static_response&& r) noexcept - : response_base() - { - h_.swap(r.h_); - external_storage_ = true; - max_cap_ = r.max_cap_; - r.max_cap_ = 0; - } - - /** Assignment. - - The contents of `r` are copied and - the previous contents of `this` are - discarded. - - @par Postconditions - @code - this->buffer() == r.buffer() && this->buffer().data() != r.buffer().data() - @endcode - - @par Complexity - Linear in `r.size()`. - - @par Exception Safety - Strong guarantee. - Exception thrown if max capacity exceeded. - - @throw std::length_error - Max capacity would be exceeded. - - @param r The response to copy. - - @return A reference to this object. - */ - static_response& - operator=( - static_response const& r) - { - copy_impl(r.h_); - return *this; - } - - /** Assignment. - - The contents of `r` are copied and - the previous contents of `this` are - discarded. - - @par Postconditions - @code - this->buffer() == r.buffer() && this->buffer().data() != r.buffer().data() - @endcode - - @par Complexity - Linear in `r.size()`. - - @par Exception Safety - Strong guarantee. - Exception thrown if max capacity exceeded. - - @throw std::length_error - Max capacity would be exceeded. - - @param r The response to copy. - - @return A reference to this object. - */ - static_response& - operator=( - response_base const& r) - { - copy_impl(r.h_); - return *this; - } -}; - -} // http_proto -} // boost - -#endif diff --git a/src/fields_base.cpp b/src/fields_base.cpp index ba62e591..b8b5a0a6 100644 --- a/src/fields_base.cpp +++ b/src/fields_base.cpp @@ -34,6 +34,7 @@ namespace http_proto { namespace { +/* std::size_t align_down( void * ptr, @@ -48,6 +49,7 @@ align_down( return 0; } +*/ void verify_field_name( @@ -310,16 +312,6 @@ fields_base( { } -fields_base:: -fields_base( - detail::kind k, - void* storage, - std::size_t cap) noexcept - : fields_base( - *detail::header::get_default(k), storage, cap) -{ -} - // copy s and parse it fields_base:: fields_base( @@ -369,32 +361,13 @@ fields_base( h.copy_table(h_.buf + h_.cap); } -// construct a complete copy of h fields_base:: fields_base( - detail::header const& h, - void* storage, - std::size_t cap) - : h_(h.kind) - , external_storage_(true) + view_tag_t, + detail::header const& h) + : h_(h) + , view_(true) { - h_.cbuf = static_cast(storage); - h_.buf = static_cast(storage); - h_.cap = align_down( - storage, - cap, - alignof(detail::header::entry)); - max_cap_ = h_.cap; - - if(detail::header::bytes_needed( - h.size, h.count) - >= h_.cap) - detail::throw_length_error(); - - h.assign_to(h_); - std::memcpy( - h_.buf, h.cbuf, h.size); - h.copy_table(h_.buf + h_.cap); } //------------------------------------------------ @@ -408,7 +381,7 @@ fields_base(fields_base const& other) fields_base:: ~fields_base() { - if(h_.buf && !external_storage_) + if(h_.buf && !view_) delete[] h_.buf; } @@ -422,6 +395,8 @@ void fields_base:: clear() noexcept { + clone_if_needed(); + if(! h_.buf) return; using H = @@ -441,6 +416,8 @@ fields_base:: reserve_bytes( std::size_t n) { + clone_if_needed(); + op_t op(*this); if(! op.reserve(n)) return; @@ -459,23 +436,23 @@ void fields_base:: shrink_to_fit() { + clone_if_needed(); + if(detail::header::bytes_needed( h_.size, h_.count) >= h_.cap) return; - if(external_storage_) - return; - fields_base tmp(h_); tmp.h_.swap(h_); } - void fields_base:: set_max_capacity_in_bytes(std::size_t n) { + clone_if_needed(); + if(n < h_.cap) detail::throw_invalid_argument(); max_cap_ = n; @@ -875,6 +852,8 @@ fields_base:: erase( iterator it) noexcept -> iterator { + clone_if_needed(); + auto const id = it->id.value_or( detail::header::unknown_field); raw_erase(it.i_); @@ -887,6 +866,8 @@ fields_base:: erase( field id) noexcept { + clone_if_needed(); + auto const i0 = h_.find(id); if(i0 == h_.count) return 0; @@ -898,6 +879,8 @@ fields_base:: erase( core::string_view name) noexcept { + clone_if_needed(); + auto const i0 = h_.find(name); if(i0 == h_.count) return 0; @@ -917,6 +900,8 @@ set( core::string_view value, system::error_code& ec) { + clone_if_needed(); + auto rv = verify_field_value(value); if(rv.has_error()) { @@ -1041,6 +1026,8 @@ set( core::string_view value, system::error_code& ec) { + clone_if_needed(); + auto rv = verify_field_value(value); if(rv.has_error()) { @@ -1083,6 +1070,8 @@ set( core::string_view value, system::error_code& ec) { + clone_if_needed(); + verify_field_name(name , ec); if(ec.failed()) return; @@ -1149,6 +1138,8 @@ insert( system::error_code& ec) -> iterator { + clone_if_needed(); + insert_impl( id, to_string(id), @@ -1181,6 +1172,8 @@ insert( system::error_code& ec) -> iterator { + clone_if_needed(); + insert_impl( string_to_field(name), name, @@ -1220,7 +1213,7 @@ copy_impl( auto const n = detail::header::bytes_needed( h.size, h.count); - if(n <= h_.cap && (!h.is_default() || external_storage_)) + if(n <= h_.cap && !view_ && !h.is_default()) { // no realloc h.assign_to(h_); @@ -1233,12 +1226,22 @@ copy_impl( return; } - // static storages cannot reallocate - if(external_storage_) - detail::throw_length_error(); - fields_base tmp(h); tmp.h_.swap(h_); + std::swap(tmp.view_, view_); +} + +void +fields_base:: +clone_if_needed() +{ + if(view_) + { + fields_base tmp(h_); + tmp.h_.swap(h_); + tmp.view_ = true; + view_ = false; + } } void diff --git a/src/parser.cpp b/src/parser.cpp index bd7fccfa..3afca4a2 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -11,8 +11,6 @@ #include #include #include -#include -#include #include #include @@ -538,7 +536,7 @@ class parser::impl parser_service& svc_; detail::workspace ws_; - static_request m_; + detail::header h_; std::uint64_t body_limit_; std::uint64_t body_total_; std::uint64_t payload_remain_; @@ -571,11 +569,10 @@ class parser::impl : ctx_(ctx) , svc_(ctx.get()) , ws_(svc_.space_needed) - , m_(ws_.data(), ws_.size()) + , h_(detail::empty{ k }) , state_(state::reset) , got_header_(false) { - m_.h_ = detail::header(detail::empty{ k }); } bool @@ -590,25 +587,14 @@ class parser::impl return state_ >= state::complete_in_place; } - static_request const& - safe_get_request() const + detail::header const& + safe_get_header() const { // headers must be received if(! got_header_) detail::throw_logic_error(); - return m_; - } - - static_response const& - safe_get_response() const - { - // headers must be received - if(! got_header_) - detail::throw_logic_error(); - - // TODO: use a union - return reinterpret_cast(m_); + return h_; } bool @@ -722,12 +708,12 @@ class parser::impl BOOST_ASSERT( head_response == false || - m_.h_.kind == detail::kind::response); + h_.kind == detail::kind::response); - m_.h_ = detail::header(detail::empty{m_.h_.kind}); - m_.h_.buf = reinterpret_cast(ws_.data()); - m_.h_.cbuf = m_.h_.buf; - m_.h_.cap = ws_.size(); + h_ = detail::header(detail::empty{h_.kind}); + h_.buf = reinterpret_cast(ws_.data()); + h_.cbuf = h_.buf; + h_.cap = ws_.size(); state_ = state::header; style_ = style::in_place; @@ -772,7 +758,7 @@ class parser::impl case state::header: { BOOST_ASSERT( - m_.h_.size < svc_.cfg.headers.max_size); + h_.size < svc_.cfg.headers.max_size); std::size_t n = fb_.capacity(); BOOST_ASSERT(n <= svc_.max_overread()); n = clamp(n, svc_.cfg.max_prepare); @@ -813,7 +799,7 @@ class parser::impl std::size_t n = cb0_.capacity(); n = clamp(n, svc_.cfg.max_prepare); - if(m_.payload() == payload::size) + if(h_.md.payload == payload::size) { if(n > payload_remain_) { @@ -827,7 +813,7 @@ class parser::impl else { BOOST_ASSERT( - m_.payload() == payload::to_eof); + h_.md.payload == payload::to_eof); // No more messages can be pipelined, so // limit the output buffer to the remaining // body limit plus one byte to detect @@ -849,7 +835,7 @@ class parser::impl std::size_t n = svc_.cfg.min_buffer; - if(m_.payload() == payload::size) + if(h_.md.payload == payload::size) { // Overreads are not allowed, or // else the caller will see extra @@ -859,7 +845,7 @@ class parser::impl else { BOOST_ASSERT( - m_.payload() == payload::to_eof); + h_.md.payload == payload::to_eof); // No more messages can be pipelined, so // limit the output buffer to the remaining // body limit plus one byte to detect @@ -1062,12 +1048,12 @@ class parser::impl case state::header: { - BOOST_ASSERT(m_.h_.buf == static_cast< + BOOST_ASSERT(h_.buf == static_cast< void const*>(ws_.data())); - BOOST_ASSERT(m_.h_.cbuf == static_cast< + BOOST_ASSERT(h_.cbuf == static_cast< void const*>(ws_.data())); - m_.h_.parse(fb_.size(), svc_.cfg.headers, ec); + h_.parse(fb_.size(), svc_.cfg.headers, ec); if(ec == condition::need_more_input) { @@ -1107,15 +1093,15 @@ class parser::impl got_header_ = true; // reserve headers + table - ws_.reserve_front(m_.h_.size); - ws_.reserve_back(m_.h_.table_space()); + ws_.reserve_front(h_.size); + ws_.reserve_back(h_.table_space()); // no payload - if(m_.payload() == payload::none || + if(h_.md.payload == payload::none || head_response_) { // octets of the next message - auto overread = fb_.size() - m_.h_.size; + auto overread = fb_.size() - h_.size; cb0_ = { ws_.data(), overread, overread }; ws_.reserve_front(overread); state_ = state::complete_in_place; @@ -1129,7 +1115,7 @@ class parser::impl case state::header_done: { // metadata error - if(m_.payload() == payload::error) + if(h_.md.payload == payload::error) { // VFALCO This needs looking at ec = BOOST_HTTP_PROTO_ERR( @@ -1143,7 +1129,7 @@ class parser::impl // this can include associated body octets for the // current message or octets of the next message in the // stream, e.g. pipelining is being used - auto const overread = fb_.size() - m_.h_.size; + auto const overread = fb_.size() - h_.size; BOOST_ASSERT(overread <= svc_.max_overread()); auto cap = fb_.capacity() + overread + @@ -1153,7 +1139,7 @@ class parser::impl // must be installed after them. auto const p = ws_.reserve_front(cap); - switch(m_.metadata().content_encoding.coding) + switch(h_.md.content_encoding.coding) { case content_coding::deflate: if(!svc_.cfg.apply_deflate_decoder) @@ -1200,17 +1186,17 @@ class parser::impl cb1_ = { p + n0 , n1 }; } - if(m_.payload() == payload::size) + if(h_.md.payload == payload::size) { if(!filter_ && - body_limit_ < m_.payload_size()) + body_limit_ < h_.md.payload_size) { ec = BOOST_HTTP_PROTO_ERR( error::body_too_large); state_ = state::reset; return; } - payload_remain_ = m_.payload_size(); + payload_remain_ = h_.md.payload_size; } state_ = state::body; @@ -1221,8 +1207,8 @@ class parser::impl { do_body: BOOST_ASSERT(state_ == state::body); - BOOST_ASSERT(m_.payload() != payload::none); - BOOST_ASSERT(m_.payload() != payload::error); + BOOST_ASSERT(h_.md.payload != payload::none); + BOOST_ASSERT(h_.md.payload != payload::error); auto set_state_to_complete = [&]() { @@ -1234,7 +1220,7 @@ class parser::impl state_ = state::complete; }; - if(m_.payload() == payload::chunked) + if(h_.md.payload == payload::chunked) { for(;;) { @@ -1416,7 +1402,7 @@ class parser::impl auto ret = cb0_.size(); if(!filter_) ret -= body_avail_; - if(m_.payload() == payload::size) + if(h_.md.payload == payload::size) return clamp(payload_remain_, ret); // payload::eof return ret; @@ -1424,7 +1410,7 @@ class parser::impl const bool is_complete = [&]() { - if(m_.payload() == payload::size) + if(h_.md.payload == payload::size) return payload_avail == payload_remain_; // payload::eof return got_eof_; @@ -1441,7 +1427,7 @@ class parser::impl { // plain body - if(m_.payload() == payload::to_eof) + if(h_.md.payload == payload::to_eof) { if(body_limit_remain() < payload_avail) { @@ -1522,7 +1508,7 @@ class parser::impl } } - if(m_.payload() == payload::size && got_eof_) + if(h_.md.payload == payload::size && got_eof_) { ec = BOOST_HTTP_PROTO_ERR( error::incomplete); @@ -1705,7 +1691,7 @@ class parser::impl is_plain() const noexcept { return ! filter_ && - m_.payload() != payload::chunked; + h_.md.payload != payload::chunked; } std::uint64_t @@ -2016,20 +2002,12 @@ start_impl(bool head_response) impl_->start(head_response); } -static_request const& -parser:: -safe_get_request() const -{ - BOOST_ASSERT(impl_); - return impl_->safe_get_request(); -} - -static_response const& +detail::header const& parser:: -safe_get_response() const +safe_get_header() const { BOOST_ASSERT(impl_); - return impl_->safe_get_response(); + return impl_->safe_get_header(); } detail::workspace& diff --git a/src/request_base.cpp b/src/request.cpp similarity index 96% rename from src/request_base.cpp rename to src/request.cpp index 85dc6fd2..fb4febec 100644 --- a/src/request_base.cpp +++ b/src/request.cpp @@ -9,7 +9,7 @@ // Official repository: https://github.com/cppalliance/http_proto // -#include +#include #include @@ -17,9 +17,11 @@ namespace boost { namespace http_proto { void -request_base:: +request:: set_expect_100_continue(bool b) { + clone_if_needed(); + if(h_.md.expect.count == 0) { BOOST_ASSERT( @@ -76,13 +78,15 @@ set_expect_100_continue(bool b) //------------------------------------------------ void -request_base:: +request:: set_start_line_impl( http_proto::method m, core::string_view ms, core::string_view t, http_proto::version v) { + clone_if_needed(); + // TODO: check validity auto const vs = to_string(v); auto const new_prefix = diff --git a/src/request_parser.cpp b/src/request_parser.cpp index 64c65edb..d11a2534 100644 --- a/src/request_parser.cpp +++ b/src/request_parser.cpp @@ -21,11 +21,11 @@ request_parser( { } -static_request const& +request request_parser:: get() const { - return safe_get_request(); + return { fields_base::view_tag, safe_get_header() }; } } // http_proto diff --git a/src/response_base.cpp b/src/response.cpp similarity index 95% rename from src/response_base.cpp rename to src/response.cpp index d6fd9a19..9523455d 100644 --- a/src/response_base.cpp +++ b/src/response.cpp @@ -7,7 +7,7 @@ // Official repository: https://github.com/cppalliance/http_proto // -#include +#include #include @@ -15,13 +15,15 @@ namespace boost { namespace http_proto { void -response_base:: +response:: set_start_line_impl( http_proto::status sc, unsigned short si, core::string_view rs, http_proto::version v) { + clone_if_needed(); + // TODO: check validity auto const vs = to_string(v); auto const new_prefix = @@ -58,10 +60,12 @@ set_start_line_impl( } void -response_base:: +response:: set_version( http_proto::version v) { + clone_if_needed(); + if(v == h_.version) return; if(h_.is_default()) diff --git a/src/response_parser.cpp b/src/response_parser.cpp index 277ba43e..7fbd0f5e 100644 --- a/src/response_parser.cpp +++ b/src/response_parser.cpp @@ -21,11 +21,11 @@ response_parser( { } -static_response const& +response response_parser:: get() const { - return safe_get_response(); + return { response::view_tag, safe_get_header() }; } } // http_proto diff --git a/test/unit/request.cpp b/test/unit/request.cpp index 3c008818..5ab74b91 100644 --- a/test/unit/request.cpp +++ b/test/unit/request.cpp @@ -115,7 +115,7 @@ struct request_test { { // default - request_base const& r1 = request(); + request r1; request r2(r1); check(r2, 0, "GET / HTTP/1.1\r\n" @@ -128,7 +128,7 @@ struct request_test r2.version() == version::http_1_1); } { - request_base const& r1 = request(cs); + request r1(cs); request r2(r1); check(r2, 2, cs); BOOST_TEST( @@ -219,27 +219,6 @@ struct request_test } } - // operator=(request_base const&) - { - { - request r1(cs); - request_base const& r2 = request(); - r1 = r2; - check(r1, 0, - "GET / HTTP/1.1\r\n" - "\r\n"); - BOOST_TEST( - r1.buffer().data() != - r2.buffer().data()); - BOOST_TEST( - r1.method() == method::get); - BOOST_TEST( - r1.method_text() == "GET"); - BOOST_TEST( - r1.version() == version::http_1_1); - } - } - // operator=(fields&&) { { diff --git a/test/unit/request_parser.cpp b/test/unit/request_parser.cpp index c48f898f..ae1b874b 100644 --- a/test/unit/request_parser.cpp +++ b/test/unit/request_parser.cpp @@ -344,7 +344,7 @@ struct request_parser_test pr.start(); feed(pr, s); - auto const& req = pr.get(); + auto req = pr.get(); BOOST_TEST( req.method() == method::get); BOOST_TEST( diff --git a/test/unit/response.cpp b/test/unit/response.cpp index 175d89b8..811e69eb 100644 --- a/test/unit/response.cpp +++ b/test/unit/response.cpp @@ -150,30 +150,6 @@ class response_test } } - // response(response_base const&) - { - { - response_base const& r1 = response(); - response r2 = response(r1); - check(r1, status::ok, 200, "OK", version::http_1_1); - check(r2, status::ok, 200, "OK", version::http_1_1); - BOOST_TEST( - r1.buffer().data() == r2.buffer().data()); - BOOST_TEST(r1.capacity_in_bytes() == 0); - BOOST_TEST(r2.capacity_in_bytes() == 0); - } - { - response_base const& r1 = response(status::not_found, version::http_1_0); - response r2 = response(r1); - check(r1, status::not_found, 404, "Not Found", version::http_1_0); - check(r2, status::not_found, 404, "Not Found", version::http_1_0); - BOOST_TEST( - r1.buffer().data() != r2.buffer().data()); - BOOST_TEST(r1.capacity_in_bytes() > 0); - BOOST_TEST(r2.capacity_in_bytes() > 0); - } - } - // operator=(response&&) { response r1; @@ -195,18 +171,6 @@ class response_test BOOST_TEST(r1.capacity_in_bytes() > 0); BOOST_TEST(r2.capacity_in_bytes() > 0); } - - // operator=(response_base const&) - { - response r1; - response_base const& r2 = response(status::not_found, version::http_1_0); - r1 = r2; - check(r1, status::not_found, 404, "Not Found", version::http_1_0); - BOOST_TEST( - r1.buffer().data() != r2.buffer().data()); - BOOST_TEST(r1.capacity_in_bytes() > 0); - BOOST_TEST(r2.capacity_in_bytes() > 0); - } } void diff --git a/test/unit/static_request.cpp b/test/unit/static_request.cpp deleted file mode 100644 index 78a1f9ec..00000000 --- a/test/unit/static_request.cpp +++ /dev/null @@ -1,124 +0,0 @@ -// -// Copyright (c) 2025 Mohammad Nejati -// -// 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/cppalliance/http_proto -// - -// Test that header file is self-contained. -#include - -#include - -#include - -#include "test_suite.hpp" - -namespace boost { -namespace http_proto { - -struct static_request_test -{ - void - testSpecial() - { - core::string_view const cs = - "POST /x HTTP/1.0\r\n" - "Content-Length: 42\r\n" - "User-Agent: boost\r\n" - "\r\n"; - - // static_request(void* storage, std::size_t cap) - { - char buf[64]; - static_request req(buf, sizeof(buf)); - BOOST_TEST( - req.method() == method::get); - BOOST_TEST( - req.method_text() == "GET"); - BOOST_TEST( - req.target() == "/"); - BOOST_TEST( - req.version() == version::http_1_1); - } - - // static_request(static_request&&) - { - char buf[64]; - static_request r1(buf, sizeof(buf)); - static_request r2(std::move(r1)); - BOOST_TEST( - r2.buffer().data() != r1.buffer().data()); - BOOST_TEST( - r2.buffer().data() == buf); - } - - // operator=(request_base const&) - { - char buf1[128]; - static_request r1(buf1, sizeof(buf1)); - const request r2(cs); - r1 = r2; - BOOST_TEST( - r1.buffer() == cs); - BOOST_TEST( - r1.buffer().data() != r2.buffer().data()); - } - - // operator=(static_request const&) - { - char buf1[128]; - static_request r1(buf1, sizeof(buf1)); - r1 = request(cs); - char buf2[128]; - static_request r2(buf2, sizeof(buf2)); - r2 = r1; - BOOST_TEST( - r2.buffer() == cs); - BOOST_TEST( - r2.buffer().data() != r1.buffer().data()); - } - } - - void - testCapacity() - { - char buf[96]; - static_request r(buf, sizeof(buf)); - - BOOST_TEST_EQ( - r.capacity_in_bytes(), 96); - BOOST_TEST_EQ( - r.max_capacity_in_bytes(), 96); - - r.append("T", "*"); - r.append("T", "*"); - r.append("T", "*"); - - BOOST_TEST_THROWS( - r.append("T", "*"), - std::length_error); - - BOOST_TEST_THROWS( - r.set_target("/index.html"), - std::length_error); - - r.set_target("/"); - } - - void - run() - { - testSpecial(); - testCapacity(); - } -}; - -TEST_SUITE( - static_request_test, - "boost.http_proto.static_request"); - -} // http_proto -} // boost diff --git a/test/unit/static_response.cpp b/test/unit/static_response.cpp deleted file mode 100644 index 70b27573..00000000 --- a/test/unit/static_response.cpp +++ /dev/null @@ -1,109 +0,0 @@ -// -// Copyright (c) 2025 Mohammad Nejati -// -// 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/cppalliance/http_proto -// - -// Test that header file is self-contained. -#include - -#include - -#include "test_suite.hpp" - -namespace boost { -namespace http_proto { - -class static_response_test -{ -public: - void - testSpecial() - { - core::string_view const cs = - "HTTP/1.1 101 Switching Protocols\r\n" - "Server: test\r\n" - "\r\n"; - - // static_response(void* storage, std::size_t cap) - { - char buf[64]; - static_response req(buf, sizeof(buf)); - BOOST_TEST( - req.status_int() == 200); - BOOST_TEST( - req.status() == status::ok); - BOOST_TEST( - req.version() == version::http_1_1); - } - - // static_response(static_response&&) - { - char buf[64]; - static_response r1(buf, sizeof(buf)); - static_response r2(std::move(r1)); - BOOST_TEST( - r2.buffer().data() != r1.buffer().data()); - BOOST_TEST( - r2.buffer().data() == buf); - } - - // operator=(response_base const&) - { - char buf1[128]; - static_response r1(buf1, sizeof(buf1)); - const response r2(cs); - r1 = r2; - BOOST_TEST( - r1.buffer() == cs); - BOOST_TEST( - r1.buffer().data() != r2.buffer().data()); - } - - // operator=(static_response const&) - { - char buf1[128]; - static_response r1(buf1, sizeof(buf1)); - r1 = response(cs); - char buf2[128]; - static_response r2(buf2, sizeof(buf2)); - r2 = r1; - BOOST_TEST( - r2.buffer() == cs); - BOOST_TEST( - r2.buffer().data() != r1.buffer().data()); - } - - } - - void - testCapacity() - { - char buf[32]; - static_response f(buf, sizeof(buf)); - BOOST_TEST_THROWS( - f.append(field::host, "www.google.com"), - std::length_error); - BOOST_TEST_EQ( - f.capacity_in_bytes(), 32); - BOOST_TEST_EQ( - f.max_capacity_in_bytes(), 32); - } - - void - run() - { - testSpecial(); - testCapacity(); - } -}; - -TEST_SUITE( - static_response_test, - "boost.http_proto.static_response"); - -} // http_proto -} // boost