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