1 /*
2 * nghttp2 - HTTP/2 C Library
3 *
4 * Copyright (c) 2016 Tatsuhiro Tsujikawa
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining
7 * a copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sublicense, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be
15 * included in all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
21 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 */
25 #include "shrpx_worker_test.h"
26
27 #ifdef HAVE_UNISTD_H
28 # include <unistd.h>
29 #endif // HAVE_UNISTD_H
30
31 #include <cstdlib>
32
33 #include <CUnit/CUnit.h>
34
35 #include "shrpx_worker.h"
36 #include "shrpx_connect_blocker.h"
37 #include "shrpx_log.h"
38
39 namespace shrpx {
40
test_shrpx_worker_match_downstream_addr_group(void)41 void test_shrpx_worker_match_downstream_addr_group(void) {
42 auto groups = std::vector<std::shared_ptr<DownstreamAddrGroup>>();
43 for (auto &s : {"nghttp2.org/", "nghttp2.org/alpha/bravo/",
44 "nghttp2.org/alpha/charlie", "nghttp2.org/delta%3A",
45 "www.nghttp2.org/", "[::1]/", "nghttp2.org/alpha/bravo/delta",
46 // Check that match is done in the single node
47 "example.com/alpha/bravo", "192.168.0.1/alpha/", "/golf/"}) {
48 auto g = std::make_shared<DownstreamAddrGroup>();
49 g->pattern = ImmutableString(s);
50 groups.push_back(std::move(g));
51 }
52
53 BlockAllocator balloc(1024, 1024);
54 RouterConfig routerconf;
55
56 auto &router = routerconf.router;
57 auto &wcrouter = routerconf.rev_wildcard_router;
58 auto &wp = routerconf.wildcard_patterns;
59
60 for (size_t i = 0; i < groups.size(); ++i) {
61 auto &g = groups[i];
62 router.add_route(StringRef{g->pattern}, i);
63 }
64
65 CU_ASSERT(0 == match_downstream_addr_group(
66 routerconf, StringRef::from_lit("nghttp2.org"),
67 StringRef::from_lit("/"), groups, 255, balloc));
68
69 // port is removed
70 CU_ASSERT(0 == match_downstream_addr_group(
71 routerconf, StringRef::from_lit("nghttp2.org:8080"),
72 StringRef::from_lit("/"), groups, 255, balloc));
73
74 // host is case-insensitive
75 CU_ASSERT(4 == match_downstream_addr_group(
76 routerconf, StringRef::from_lit("WWW.nghttp2.org"),
77 StringRef::from_lit("/alpha"), groups, 255, balloc));
78
79 CU_ASSERT(1 == match_downstream_addr_group(
80 routerconf, StringRef::from_lit("nghttp2.org"),
81 StringRef::from_lit("/alpha/bravo/"), groups, 255,
82 balloc));
83
84 // /alpha/bravo also matches /alpha/bravo/
85 CU_ASSERT(1 == match_downstream_addr_group(
86 routerconf, StringRef::from_lit("nghttp2.org"),
87 StringRef::from_lit("/alpha/bravo"), groups, 255, balloc));
88
89 // path part is case-sensitive
90 CU_ASSERT(0 == match_downstream_addr_group(
91 routerconf, StringRef::from_lit("nghttp2.org"),
92 StringRef::from_lit("/Alpha/bravo"), groups, 255, balloc));
93
94 CU_ASSERT(1 == match_downstream_addr_group(
95 routerconf, StringRef::from_lit("nghttp2.org"),
96 StringRef::from_lit("/alpha/bravo/charlie"), groups, 255,
97 balloc));
98
99 CU_ASSERT(2 == match_downstream_addr_group(
100 routerconf, StringRef::from_lit("nghttp2.org"),
101 StringRef::from_lit("/alpha/charlie"), groups, 255,
102 balloc));
103
104 // pattern which does not end with '/' must match its entirely. So
105 // this matches to group 0, not group 2.
106 CU_ASSERT(0 == match_downstream_addr_group(
107 routerconf, StringRef::from_lit("nghttp2.org"),
108 StringRef::from_lit("/alpha/charlie/"), groups, 255,
109 balloc));
110
111 CU_ASSERT(255 == match_downstream_addr_group(
112 routerconf, StringRef::from_lit("example.org"),
113 StringRef::from_lit("/"), groups, 255, balloc));
114
115 CU_ASSERT(255 == match_downstream_addr_group(
116 routerconf, StringRef::from_lit(""),
117 StringRef::from_lit("/"), groups, 255, balloc));
118
119 CU_ASSERT(255 == match_downstream_addr_group(
120 routerconf, StringRef::from_lit(""),
121 StringRef::from_lit("alpha"), groups, 255, balloc));
122
123 CU_ASSERT(255 == match_downstream_addr_group(
124 routerconf, StringRef::from_lit("foo/bar"),
125 StringRef::from_lit("/"), groups, 255, balloc));
126
127 // If path is StringRef::from_lit("*", only match with host + "/").
128 CU_ASSERT(0 == match_downstream_addr_group(
129 routerconf, StringRef::from_lit("nghttp2.org"),
130 StringRef::from_lit("*"), groups, 255, balloc));
131
132 CU_ASSERT(5 == match_downstream_addr_group(
133 routerconf, StringRef::from_lit("[::1]"),
134 StringRef::from_lit("/"), groups, 255, balloc));
135 CU_ASSERT(5 == match_downstream_addr_group(
136 routerconf, StringRef::from_lit("[::1]:8080"),
137 StringRef::from_lit("/"), groups, 255, balloc));
138 CU_ASSERT(255 == match_downstream_addr_group(
139 routerconf, StringRef::from_lit("[::1"),
140 StringRef::from_lit("/"), groups, 255, balloc));
141 CU_ASSERT(255 == match_downstream_addr_group(
142 routerconf, StringRef::from_lit("[::1]8000"),
143 StringRef::from_lit("/"), groups, 255, balloc));
144
145 // Check the case where adding route extends tree
146 CU_ASSERT(6 == match_downstream_addr_group(
147 routerconf, StringRef::from_lit("nghttp2.org"),
148 StringRef::from_lit("/alpha/bravo/delta"), groups, 255,
149 balloc));
150
151 CU_ASSERT(1 == match_downstream_addr_group(
152 routerconf, StringRef::from_lit("nghttp2.org"),
153 StringRef::from_lit("/alpha/bravo/delta/"), groups, 255,
154 balloc));
155
156 // Check the case where query is done in a single node
157 CU_ASSERT(7 == match_downstream_addr_group(
158 routerconf, StringRef::from_lit("example.com"),
159 StringRef::from_lit("/alpha/bravo"), groups, 255, balloc));
160
161 CU_ASSERT(255 == match_downstream_addr_group(
162 routerconf, StringRef::from_lit("example.com"),
163 StringRef::from_lit("/alpha/bravo/"), groups, 255,
164 balloc));
165
166 CU_ASSERT(255 == match_downstream_addr_group(
167 routerconf, StringRef::from_lit("example.com"),
168 StringRef::from_lit("/alpha"), groups, 255, balloc));
169
170 // Check the case where quey is done in a single node
171 CU_ASSERT(8 == match_downstream_addr_group(
172 routerconf, StringRef::from_lit("192.168.0.1"),
173 StringRef::from_lit("/alpha"), groups, 255, balloc));
174
175 CU_ASSERT(8 == match_downstream_addr_group(
176 routerconf, StringRef::from_lit("192.168.0.1"),
177 StringRef::from_lit("/alpha/"), groups, 255, balloc));
178
179 CU_ASSERT(8 == match_downstream_addr_group(
180 routerconf, StringRef::from_lit("192.168.0.1"),
181 StringRef::from_lit("/alpha/bravo"), groups, 255, balloc));
182
183 CU_ASSERT(255 == match_downstream_addr_group(
184 routerconf, StringRef::from_lit("192.168.0.1"),
185 StringRef::from_lit("/alph"), groups, 255, balloc));
186
187 CU_ASSERT(255 == match_downstream_addr_group(
188 routerconf, StringRef::from_lit("192.168.0.1"),
189 StringRef::from_lit("/"), groups, 255, balloc));
190
191 // Test for wildcard hosts
192 auto g1 = std::make_shared<DownstreamAddrGroup>();
193 g1->pattern = ImmutableString::from_lit("git.nghttp2.org");
194 groups.push_back(std::move(g1));
195
196 auto g2 = std::make_shared<DownstreamAddrGroup>();
197 g2->pattern = ImmutableString::from_lit(".nghttp2.org");
198 groups.push_back(std::move(g2));
199
200 auto g3 = std::make_shared<DownstreamAddrGroup>();
201 g3->pattern = ImmutableString::from_lit(".local");
202 groups.push_back(std::move(g3));
203
204 wp.emplace_back(StringRef::from_lit("git.nghttp2.org"));
205 wcrouter.add_route(StringRef::from_lit("gro.2ptthgn.tig"), 0);
206 wp.back().router.add_route(StringRef::from_lit("/echo/"), 10);
207
208 wp.emplace_back(StringRef::from_lit(".nghttp2.org"));
209 wcrouter.add_route(StringRef::from_lit("gro.2ptthgn."), 1);
210 wp.back().router.add_route(StringRef::from_lit("/echo/"), 11);
211 wp.back().router.add_route(StringRef::from_lit("/echo/foxtrot"), 12);
212
213 wp.emplace_back(StringRef::from_lit(".local"));
214 wcrouter.add_route(StringRef::from_lit("lacol."), 2);
215 wp.back().router.add_route(StringRef::from_lit("/"), 13);
216
217 CU_ASSERT(11 == match_downstream_addr_group(
218 routerconf, StringRef::from_lit("git.nghttp2.org"),
219 StringRef::from_lit("/echo"), groups, 255, balloc));
220
221 CU_ASSERT(10 == match_downstream_addr_group(
222 routerconf, StringRef::from_lit("0git.nghttp2.org"),
223 StringRef::from_lit("/echo"), groups, 255, balloc));
224
225 CU_ASSERT(11 == match_downstream_addr_group(
226 routerconf, StringRef::from_lit("it.nghttp2.org"),
227 StringRef::from_lit("/echo"), groups, 255, balloc));
228
229 CU_ASSERT(255 == match_downstream_addr_group(
230 routerconf, StringRef::from_lit(".nghttp2.org"),
231 StringRef::from_lit("/echo/foxtrot"), groups, 255,
232 balloc));
233
234 CU_ASSERT(9 == match_downstream_addr_group(
235 routerconf, StringRef::from_lit("alpha.nghttp2.org"),
236 StringRef::from_lit("/golf"), groups, 255, balloc));
237
238 CU_ASSERT(0 == match_downstream_addr_group(
239 routerconf, StringRef::from_lit("nghttp2.org"),
240 StringRef::from_lit("/echo"), groups, 255, balloc));
241
242 CU_ASSERT(13 == match_downstream_addr_group(
243 routerconf, StringRef::from_lit("test.local"),
244 StringRef{}, groups, 255, balloc));
245 }
246
247 } // namespace shrpx
248