94.12% Lines (32/34)
100.00% Functions (7/7)
| TLA | Baseline | Branch | ||||||
|---|---|---|---|---|---|---|---|---|
| Line | Hits | Code | Line | Hits | Code | |||
| 1 | // | 1 | // | |||||
| 2 | // Copyright (c) 2025 Vinnie Falco (vinnie.falco@gmail.com) | 2 | // Copyright (c) 2025 Vinnie Falco (vinnie.falco@gmail.com) | |||||
| 3 | // | 3 | // | |||||
| 4 | // Distributed under the Boost Software License, Version 1.0. (See accompanying | 4 | // Distributed under the Boost Software License, Version 1.0. (See accompanying | |||||
| 5 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) | 5 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) | |||||
| 6 | // | 6 | // | |||||
| 7 | // Official repository: https://github.com/cppalliance/http | 7 | // Official repository: https://github.com/cppalliance/http | |||||
| 8 | // | 8 | // | |||||
| 9 | 9 | |||||||
| 10 | #ifndef BOOST_HTTP_SRC_SERVER_DETAIL_ANY_ROUTER_HPP | 10 | #ifndef BOOST_HTTP_SRC_SERVER_DETAIL_ANY_ROUTER_HPP | |||||
| 11 | #define BOOST_HTTP_SRC_SERVER_DETAIL_ANY_ROUTER_HPP | 11 | #define BOOST_HTTP_SRC_SERVER_DETAIL_ANY_ROUTER_HPP | |||||
| 12 | 12 | |||||||
| 13 | #include <boost/http/server/detail/router_base.hpp> | 13 | #include <boost/http/server/detail/router_base.hpp> | |||||
| 14 | #include <boost/http/detail/except.hpp> | 14 | #include <boost/http/detail/except.hpp> | |||||
| 15 | #include "src/server/detail/route_match.hpp" | 15 | #include "src/server/detail/route_match.hpp" | |||||
| 16 | #include <mutex> | 16 | #include <mutex> | |||||
| 17 | 17 | |||||||
| 18 | namespace boost { | 18 | namespace boost { | |||||
| 19 | namespace http { | 19 | namespace http { | |||||
| 20 | namespace detail { | 20 | namespace detail { | |||||
| 21 | 21 | |||||||
| 22 | struct router_base::entry | 22 | struct router_base::entry | |||||
| 23 | { | 23 | { | |||||
| 24 | // ~32 bytes (SSO string) | 24 | // ~32 bytes (SSO string) | |||||
| 25 | std::string verb_str; | 25 | std::string verb_str; | |||||
| 26 | 26 | |||||||
| 27 | // 8 bytes each | 27 | // 8 bytes each | |||||
| 28 | handler_ptr h; | 28 | handler_ptr h; | |||||
| 29 | std::size_t matcher_idx = 0; | 29 | std::size_t matcher_idx = 0; | |||||
| 30 | 30 | |||||||
| 31 | // 4 bytes | 31 | // 4 bytes | |||||
| 32 | http::method verb = http::method::unknown; | 32 | http::method verb = http::method::unknown; | |||||
| 33 | 33 | |||||||
| 34 | // 1 byte (+ 3 bytes padding) | 34 | // 1 byte (+ 3 bytes padding) | |||||
| 35 | bool all; | 35 | bool all; | |||||
| 36 | 36 | |||||||
| 37 | // all methods | 37 | // all methods | |||||
| HITCBC | 38 | 82 | explicit entry( | 38 | 82 | explicit entry( | ||
| 39 | handler_ptr h_) noexcept | 39 | handler_ptr h_) noexcept | |||||
| HITCBC | 40 | 82 | : h(std::move(h_)) | 40 | 82 | : h(std::move(h_)) | ||
| HITCBC | 41 | 82 | , all(true) | 41 | 82 | , all(true) | ||
| 42 | { | 42 | { | |||||
| HITCBC | 43 | 82 | } | 43 | 82 | } | ||
| 44 | 44 | |||||||
| 45 | // known verb match | 45 | // known verb match | |||||
| HITCBC | 46 | 58 | entry( | 46 | 58 | entry( | ||
| 47 | http::method verb_, | 47 | http::method verb_, | |||||
| 48 | handler_ptr h_) noexcept | 48 | handler_ptr h_) noexcept | |||||
| HITCBC | 49 | 58 | : h(std::move(h_)) | 49 | 58 | : h(std::move(h_)) | ||
| HITCBC | 50 | 58 | , verb(verb_) | 50 | 58 | , verb(verb_) | ||
| HITCBC | 51 | 58 | , all(false) | 51 | 58 | , all(false) | ||
| 52 | { | 52 | { | |||||
| HITCBC | 53 | 58 | BOOST_ASSERT(verb != | 53 | 58 | BOOST_ASSERT(verb != | ||
| 54 | http::method::unknown); | 54 | http::method::unknown); | |||||
| HITCBC | 55 | 58 | } | 55 | 58 | } | ||
| 56 | 56 | |||||||
| 57 | // string verb match | 57 | // string verb match | |||||
| HITCBC | 58 | 2 | entry( | 58 | 2 | entry( | ||
| 59 | std::string_view verb_str_, | 59 | std::string_view verb_str_, | |||||
| 60 | handler_ptr h_) noexcept | 60 | handler_ptr h_) noexcept | |||||
| HITCBC | 61 | 2 | : h(std::move(h_)) | 61 | 2 | : h(std::move(h_)) | ||
| HITCBC | 62 | 2 | , verb(http::string_to_method(verb_str_)) | 62 | 2 | , verb(http::string_to_method(verb_str_)) | ||
| HITCBC | 63 | 4 | , all(false) | 63 | 4 | , all(false) | ||
| 64 | { | 64 | { | |||||
| HITCBC | 65 | 2 | if(verb != http::method::unknown) | 65 | 2 | if(verb != http::method::unknown) | ||
| MISUBC | 66 | ✗ | return; | 66 | ✗ | return; | ||
| HITCBC | 67 | 2 | verb_str = verb_str_; | 67 | 2 | verb_str = verb_str_; | ||
| 68 | } | 68 | } | |||||
| 69 | 69 | |||||||
| HITCBC | 70 | 69 | bool match_method( | 70 | 69 | bool match_method( | ||
| 71 | route_params& rp) const noexcept | 71 | route_params& rp) const noexcept | |||||
| 72 | { | 72 | { | |||||
| HITCBC | 73 | 69 | route_params_access RP{rp}; | 73 | 69 | route_params_access RP{rp}; | ||
| HITCBC | 74 | 69 | if(all) | 74 | 69 | if(all) | ||
| HITCBC | 75 | 9 | return true; | 75 | 9 | return true; | ||
| HITCBC | 76 | 60 | if(verb != http::method::unknown) | 76 | 60 | if(verb != http::method::unknown) | ||
| HITCBC | 77 | 58 | return RP->verb_ == verb; | 77 | 58 | return RP->verb_ == verb; | ||
| HITCBC | 78 | 2 | if(RP->verb_ != http::method::unknown) | 78 | 2 | if(RP->verb_ != http::method::unknown) | ||
| MISUBC | 79 | ✗ | return false; | 79 | ✗ | return false; | ||
| HITCBC | 80 | 2 | return RP->verb_str_ == verb_str; | 80 | 2 | return RP->verb_str_ == verb_str; | ||
| 81 | } | 81 | } | |||||
| 82 | }; | 82 | }; | |||||
| 83 | 83 | |||||||
| 84 | struct router_base::impl | 84 | struct router_base::impl | |||||
| 85 | { | 85 | { | |||||
| 86 | std::vector<entry> entries; | 86 | std::vector<entry> entries; | |||||
| 87 | std::vector<matcher> matchers; | 87 | std::vector<matcher> matchers; | |||||
| 88 | 88 | |||||||
| 89 | std::size_t pending_route_ = SIZE_MAX; | 89 | std::size_t pending_route_ = SIZE_MAX; | |||||
| 90 | mutable std::once_flag finalized_; | 90 | mutable std::once_flag finalized_; | |||||
| 91 | 91 | |||||||
| 92 | options_handler_ptr options_handler_; | 92 | options_handler_ptr options_handler_; | |||||
| 93 | std::uint64_t global_methods_ = 0; | 93 | std::uint64_t global_methods_ = 0; | |||||
| 94 | std::vector<std::string> global_custom_verbs_; | 94 | std::vector<std::string> global_custom_verbs_; | |||||
| 95 | std::string global_allow_header_; | 95 | std::string global_allow_header_; | |||||
| 96 | 96 | |||||||
| 97 | opt_flags opt_; | 97 | opt_flags opt_; | |||||
| 98 | std::size_t depth_ = 0; | 98 | std::size_t depth_ = 0; | |||||
| 99 | 99 | |||||||
| HITCBC | 100 | 168 | explicit impl( | 100 | 168 | explicit impl( | ||
| 101 | opt_flags opt) noexcept | 101 | opt_flags opt) noexcept | |||||
| HITCBC | 102 | 168 | : opt_(opt) | 102 | 168 | : opt_(opt) | ||
| 103 | { | 103 | { | |||||
| HITCBC | 104 | 168 | } | 104 | 168 | } | ||
| 105 | 105 | |||||||
| 106 | void finalize_pending(); | 106 | void finalize_pending(); | |||||
| 107 | 107 | |||||||
| 108 | // Thread-safe lazy finalization for dispatch | 108 | // Thread-safe lazy finalization for dispatch | |||||
| HITCBC | 109 | 113 | void ensure_finalized() const | 109 | 113 | void ensure_finalized() const | ||
| 110 | { | 110 | { | |||||
| HITCBC | 111 | 113 | std::call_once(finalized_, [this]() { | 111 | 113 | std::call_once(finalized_, [this]() { | ||
| HITCBC | 112 | 99 | const_cast<impl*>(this)->finalize_pending(); | 112 | 99 | const_cast<impl*>(this)->finalize_pending(); | ||
| HITCBC | 113 | 99 | }); | 113 | 99 | }); | ||
| HITCBC | 114 | 113 | } | 114 | 113 | } | ||
| 115 | 115 | |||||||
| 116 | void update_allow_for_entry( | 116 | void update_allow_for_entry( | |||||
| 117 | matcher& m, | 117 | matcher& m, | |||||
| 118 | entry const& e); | 118 | entry const& e); | |||||
| 119 | 119 | |||||||
| 120 | void rebuild_global_allow_header(); | 120 | void rebuild_global_allow_header(); | |||||
| 121 | 121 | |||||||
| 122 | route_task | 122 | route_task | |||||
| 123 | dispatch_loop( | 123 | dispatch_loop( | |||||
| 124 | route_params& p, | 124 | route_params& p, | |||||
| 125 | bool is_options) const; | 125 | bool is_options) const; | |||||
| 126 | 126 | |||||||
| 127 | static std::string | 127 | static std::string | |||||
| 128 | build_allow_header( | 128 | build_allow_header( | |||||
| 129 | std::uint64_t methods, | 129 | std::uint64_t methods, | |||||
| 130 | std::vector<std::string> const& custom); | 130 | std::vector<std::string> const& custom); | |||||
| 131 | 131 | |||||||
| 132 | static opt_flags | 132 | static opt_flags | |||||
| 133 | compute_effective_opts( | 133 | compute_effective_opts( | |||||
| 134 | opt_flags parent, | 134 | opt_flags parent, | |||||
| 135 | opt_flags child); | 135 | opt_flags child); | |||||
| 136 | 136 | |||||||
| 137 | static void | 137 | static void | |||||
| 138 | restore_path( | 138 | restore_path( | |||||
| 139 | route_params& p, | 139 | route_params& p, | |||||
| 140 | std::size_t base_len); | 140 | std::size_t base_len); | |||||
| 141 | }; | 141 | }; | |||||
| 142 | 142 | |||||||
| 143 | } // detail | 143 | } // detail | |||||
| 144 | } // http | 144 | } // http | |||||
| 145 | } // boost | 145 | } // boost | |||||
| 146 | 146 | |||||||
| 147 | #endif | 147 | #endif | |||||