1 +
//
 
2 +
// Copyright (c) 2025 Vinnie Falco (vinnie.falco@gmail.com)
 
3 +
//
 
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)
 
6 +
//
 
7 +
// Official repository: https://github.com/cppalliance/http
 
8 +
//
 
9 +

 
10 +
#ifndef BOOST_HTTP_SRC_SERVER_DETAIL_ROUTER_BASE_HPP
 
11 +
#define BOOST_HTTP_SRC_SERVER_DETAIL_ROUTER_BASE_HPP
 
12 +

 
13 +
#include <boost/http/server/detail/router_base.hpp>
 
14 +
#include <boost/http/detail/except.hpp>
 
15 +
#include "src/server/detail/route_match.hpp"
 
16 +
#include <mutex>
 
17 +

 
18 +
namespace boost {
 
19 +
namespace http {
 
20 +
namespace detail {
 
21 +

 
22 +
struct router_base::entry
 
23 +
{
 
24 +
    // ~32 bytes (SSO string)
 
25 +
    std::string verb_str;
 
26 +

 
27 +
    // 8 bytes each
 
28 +
    handler_ptr h;
 
29 +
    std::size_t matcher_idx = 0;
 
30 +

 
31 +
    // 4 bytes
 
32 +
    http::method verb = http::method::unknown;
 
33 +

 
34 +
    // 1 byte (+ 3 bytes padding)
 
35 +
    bool all;
 
36 +

 
37 +
    // all methods
 
38 +
    explicit entry(
 
39 +
        handler_ptr h_) noexcept
 
40 +
        : h(std::move(h_))
 
41 +
        , all(true)
 
42 +
    {
 
43 +
    }
 
44 +

 
45 +
    // known verb match
 
46 +
    entry(
 
47 +
        http::method verb_,
 
48 +
        handler_ptr h_) noexcept
 
49 +
        : h(std::move(h_))
 
50 +
        , verb(verb_)
 
51 +
        , all(false)
 
52 +
    {
 
53 +
        BOOST_ASSERT(verb !=
 
54 +
            http::method::unknown);
 
55 +
    }
 
56 +

 
57 +
    // string verb match
 
58 +
    entry(
 
59 +
        std::string_view verb_str_,
 
60 +
        handler_ptr h_) noexcept
 
61 +
        : h(std::move(h_))
 
62 +
        , verb(http::string_to_method(verb_str_))
 
63 +
        , all(false)
 
64 +
    {
 
65 +
        if(verb != http::method::unknown)
 
66 +
            return;
 
67 +
        verb_str = verb_str_;
 
68 +
    }
 
69 +

 
70 +
    bool match_method(
 
71 +
        route_params& rp) const noexcept
 
72 +
    {
 
73 +
        route_params_access RP{rp};
 
74 +
        if(all)
 
75 +
            return true;
 
76 +
        if(verb != http::method::unknown)
 
77 +
            return RP->verb_ == verb;
 
78 +
        if(RP->verb_ != http::method::unknown)
 
79 +
            return false;
 
80 +
        return RP->verb_str_ == verb_str;
 
81 +
    }
 
82 +
};
 
83 +

 
84 +
struct router_base::impl
 
85 +
{
 
86 +
    std::vector<entry> entries;
 
87 +
    std::vector<matcher> matchers;
 
88 +

 
89 +
    std::size_t pending_route_ = SIZE_MAX;
 
90 +
    mutable std::once_flag finalized_;
 
91 +

 
92 +
    options_handler_ptr options_handler_;
 
93 +
    std::uint64_t global_methods_ = 0;
 
94 +
    std::vector<std::string> global_custom_verbs_;
 
95 +
    std::string global_allow_header_;
 
96 +

 
97 +
    opt_flags opt_;
 
98 +
    std::size_t depth_ = 0;
 
99 +

 
100 +
    explicit impl(
 
101 +
        opt_flags opt) noexcept
 
102 +
        : opt_(opt)
 
103 +
    {
 
104 +
    }
 
105 +

 
106 +
    void finalize_pending();
 
107 +

 
108 +
    // Thread-safe lazy finalization for dispatch
 
109 +
    void ensure_finalized() const
 
110 +
    {
 
111 +
        std::call_once(finalized_, [this]() {
 
112 +
            const_cast<impl*>(this)->finalize_pending();
 
113 +
        });
 
114 +
    }
 
115 +

 
116 +
    void update_allow_for_entry(
 
117 +
        matcher& m,
 
118 +
        entry const& e);
 
119 +

 
120 +
    void rebuild_global_allow_header();
 
121 +

 
122 +
    route_task
 
123 +
    dispatch_loop(
 
124 +
        route_params& p,
 
125 +
        bool is_options) const;
 
126 +

 
127 +
    static std::string
 
128 +
    build_allow_header(
 
129 +
        std::uint64_t methods,
 
130 +
        std::vector<std::string> const& custom);
 
131 +

 
132 +
    static opt_flags
 
133 +
    compute_effective_opts(
 
134 +
        opt_flags parent,
 
135 +
        opt_flags child);
 
136 +

 
137 +
    static void
 
138 +
    restore_path(
 
139 +
        route_params& p,
 
140 +
        std::size_t base_len);
 
141 +
};
 
142 +

 
143 +
} // detail
 
144 +
} // http
 
145 +
} // boost
 
146 +

 
147 +
#endif