Line data Source code
1 : //
2 : // Copyright (c) 2025 Vinnie Falco (vinnie dot falco at gmail dot 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 : #include "src/server/detail/router_base.hpp"
11 : #include <boost/http/server/detail/router_base.hpp>
12 : #include <boost/http/server/flat_router.hpp>
13 : #include <boost/http/server/route_handler.hpp>
14 : #include <boost/http/detail/except.hpp>
15 : #include <boost/url/grammar/ci_string.hpp>
16 : #include <boost/url/grammar/hexdig_chars.hpp>
17 : #include "src/server/detail/route_match.hpp"
18 : #include "src/server/detail/route_rule.hpp"
19 :
20 : /*
21 :
22 : pattern target path(use) path(get)
23 : -------------------------------------------------
24 : / / /
25 : / /api /api
26 : /api /api / /api
27 : /api /api/ / /api/
28 : /api /api/ / no-match strict
29 : /api /api/v0 /v0 no-match
30 : /api/ /api / /api
31 : /api/ /api / no-match strict
32 : /api/ /api/ / /api/
33 : /api/ /api/v0 /v0 no-match
34 :
35 : */
36 :
37 : namespace boost {
38 : namespace http {
39 : namespace detail {
40 :
41 182 : router_base::
42 : ~router_base()
43 : {
44 182 : delete impl_;
45 182 : }
46 :
47 102 : router_base::
48 : router_base(
49 102 : opt_flags opt)
50 102 : : impl_(new impl(opt))
51 : {
52 102 : }
53 :
54 80 : router_base::
55 : router_base(
56 80 : router_base&& other) noexcept
57 80 : :impl_(other.impl_)
58 : {
59 80 : other.impl_ = nullptr;
60 80 : }
61 :
62 : router_base&
63 0 : router_base::
64 : operator=(
65 : router_base&& other) noexcept
66 : {
67 0 : delete impl_;
68 0 : impl_ = other.impl_;
69 0 : other.impl_ = 0;
70 0 : return *this;
71 : }
72 :
73 : auto
74 27 : router_base::
75 : new_layer(
76 : std::string_view pattern) -> layer&
77 : {
78 : // the pattern must not be empty
79 27 : if(pattern.empty())
80 0 : detail::throw_invalid_argument();
81 : // delete the last route if it is empty,
82 : // this happens if they call route() without
83 : // adding anything
84 30 : if(! impl_->layers.empty() &&
85 3 : impl_->layers.back().entries.empty())
86 0 : impl_->layers.pop_back();
87 27 : impl_->layers.emplace_back(pattern);
88 27 : return impl_->layers.back();
89 : };
90 :
91 : std::size_t
92 27 : router_base::
93 : new_layer_idx(
94 : std::string_view pattern)
95 : {
96 27 : new_layer(pattern);
97 27 : return impl_->layers.size() - 1;
98 : }
99 :
100 : auto
101 30 : router_base::
102 : get_layer(
103 : std::size_t idx) -> layer&
104 : {
105 30 : return impl_->layers[idx];
106 : }
107 :
108 : void
109 89 : router_base::
110 : add_impl(
111 : std::string_view pattern,
112 : handlers hn)
113 : {
114 89 : if( pattern.empty())
115 22 : pattern = "/";
116 89 : impl_->layers.emplace_back(
117 : pattern, hn);
118 :
119 : // Validate depth for any nested routers
120 89 : auto& lay = impl_->layers.back();
121 186 : for(auto& entry : lay.entries)
122 98 : if(entry.h->kind == is_router)
123 40 : if(auto* r = entry.h->get_router())
124 40 : r->set_nested_depth(impl_->depth_);
125 88 : }
126 :
127 : void
128 22 : router_base::
129 : add_impl(
130 : layer& l,
131 : http::method verb,
132 : handlers hn)
133 : {
134 : // cannot be unknown
135 22 : if(verb == http::method::unknown)
136 0 : detail::throw_invalid_argument();
137 :
138 22 : l.entries.reserve(l.entries.size() + hn.n);
139 45 : for(std::size_t i = 0; i < hn.n; ++i)
140 23 : l.entries.emplace_back(verb,
141 23 : std::move(hn.p[i]));
142 22 : }
143 :
144 : void
145 8 : router_base::
146 : add_impl(
147 : layer& l,
148 : std::string_view verb_str,
149 : handlers hn)
150 : {
151 8 : l.entries.reserve(l.entries.size() + hn.n);
152 :
153 8 : if(verb_str.empty())
154 : {
155 : // all
156 12 : for(std::size_t i = 0; i < hn.n; ++i)
157 6 : l.entries.emplace_back(std::move(hn.p[i]));
158 6 : return;
159 : }
160 :
161 : // possibly custom string
162 4 : for(std::size_t i = 0; i < hn.n; ++i)
163 2 : l.entries.emplace_back(verb_str,
164 2 : std::move(hn.p[i]));
165 : }
166 :
167 : void
168 266 : router_base::
169 : set_nested_depth(
170 : std::size_t parent_depth)
171 : {
172 266 : std::size_t d = parent_depth + 1;
173 266 : if(d >= max_path_depth)
174 1 : detail::throw_length_error(
175 : "router nesting depth exceeds max_path_depth");
176 265 : impl_->depth_ = d;
177 515 : for(auto& layer : impl_->layers)
178 515 : for(auto& entry : layer.entries)
179 265 : if(entry.h->kind == is_router)
180 226 : if(auto* r = entry.h->get_router())
181 226 : r->set_nested_depth(d);
182 250 : }
183 :
184 : } // detail
185 : } // http
186 : } // boost
187 :
|