GCC Code Coverage Report


Directory: ./
File: libs/http/src/server/detail/router_base.cpp
Date: 2026-01-20 00:11:35
Exec Total Coverage
Lines: 60 68 88.2%
Functions: 10 11 90.9%
Branches: 34 42 81.0%

Line Branch Exec Source
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
2/2
✓ Branch 0 taken 102 times.
✓ Branch 1 taken 80 times.
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 router_base::
64 operator=(
65 router_base&& other) noexcept
66 {
67 delete impl_;
68 impl_ = other.impl_;
69 other.impl_ = 0;
70 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
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 27 times.
27 if(pattern.empty())
80 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
4/6
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 24 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 27 times.
30 if(! impl_->layers.empty() &&
85 3 impl_->layers.back().entries.empty())
86 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
2/2
✓ Branch 1 taken 22 times.
✓ Branch 2 taken 67 times.
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
2/2
✓ Branch 5 taken 98 times.
✓ Branch 6 taken 88 times.
186 for(auto& entry : lay.entries)
122
2/2
✓ Branch 1 taken 40 times.
✓ Branch 2 taken 58 times.
98 if(entry.h->kind == is_router)
123
1/2
✓ Branch 2 taken 40 times.
✗ Branch 3 not taken.
40 if(auto* r = entry.h->get_router())
124
1/1
✓ Branch 1 taken 39 times.
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
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 22 times.
22 if(verb == http::method::unknown)
136 detail::throw_invalid_argument();
137
138 22 l.entries.reserve(l.entries.size() + hn.n);
139
2/2
✓ Branch 0 taken 23 times.
✓ Branch 1 taken 22 times.
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
2/2
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 2 times.
8 if(verb_str.empty())
154 {
155 // all
156
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 6 times.
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
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
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
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 265 times.
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
2/2
✓ Branch 5 taken 265 times.
✓ Branch 6 taken 250 times.
515 for(auto& layer : impl_->layers)
178
2/2
✓ Branch 5 taken 265 times.
✓ Branch 6 taken 250 times.
515 for(auto& entry : layer.entries)
179
2/2
✓ Branch 1 taken 226 times.
✓ Branch 2 taken 39 times.
265 if(entry.h->kind == is_router)
180
1/2
✓ Branch 2 taken 226 times.
✗ Branch 3 not taken.
226 if(auto* r = entry.h->get_router())
181
1/1
✓ Branch 1 taken 211 times.
226 r->set_nested_depth(d);
182 250 }
183
184 } // detail
185 } // http
186 } // boost
187
188