View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.juneau.rest;
18  
19  import org.apache.http.client.config.*;
20  import org.apache.juneau.*;
21  import org.apache.juneau.collections.*;
22  import org.apache.juneau.http.annotation.*;
23  import org.apache.juneau.rest.annotation.*;
24  import org.apache.juneau.rest.mock.*;
25  import org.junit.jupiter.api.*;
26  
27  class Paths_Test extends TestBase {
28  
29  	//------------------------------------------------------------------------------------------------------------------
30  	// Setup
31  	//------------------------------------------------------------------------------------------------------------------
32  
33  	static JsonMap getPaths(RestRequest req) {
34  		return JsonMap.create()
35  			.append("pathInfo", req.getPathInfo())
36  			.append("pathRemainder", req.getPathParams().getRemainder().orElse(null))
37  			.append("pathRemainderUndecoded", req.getPathParams().getRemainderUndecoded().orElse(null))
38  			.append("requestURI", req.getRequestURI())
39  			.append("requestParentURI", req.getUriContext().getRootRelativePathInfoParent())
40  			.append("requestURL", req.getRequestURL())
41  			.append("servletPath", req.getServletPath())
42  			.append("servletURI", req.getUriContext().getRootRelativeServletPath())
43  			.append("servletParentURI", req.getUriContext().getRootRelativeServletPathParent());
44  	}
45  
46  	//------------------------------------------------------------------------------------------------------------------
47  	// No subpath
48  	//------------------------------------------------------------------------------------------------------------------
49  
50  	@Rest
51  	public static class A {
52  		@RestGet(path="/*")
53  		public JsonMap get(RestRequest req, @Path("/*") String r) {
54  			return getPaths(req).append("pathRemainder2", r).append("method",1);
55  		}
56  	}
57  	static MockRestClient a = MockRestClient.create(A.class).contextPath("/cp").servletPath("/sp").defaultRequestConfig(RequestConfig.custom().setNormalizeUri(false).build()).build();
58  
59  	@Test void a01() throws Exception {
60  		a.get("http://localhost/cp/sp").run()
61  			.assertContent().isContains("pathInfo:null")
62  			.assertContent().isContains("pathRemainder:null")
63  			.assertContent().isContains("pathRemainderUndecoded:null")
64  			.assertContent().isContains("pathRemainder2:null")
65  			.assertContent().isContains("requestURI:'/cp/sp'")
66  			.assertContent().isContains("requestParentURI:'/cp'")
67  			.assertContent().isContains("requestURL:'http://localhost/cp/sp'")
68  			.assertContent().isContains("servletPath:'/sp'")
69  			.assertContent().isContains("servletURI:'/cp/sp'")
70  			.assertContent().isContains("method:1")
71  		;
72  	}
73  	@Test void a02() throws Exception {
74  		a.get("http://localhost/cp/sp/").run()
75  			.assertContent().isContains("pathInfo:'/'")
76  			.assertContent().isContains("pathRemainder:''")
77  			.assertContent().isContains("pathRemainderUndecoded:''")
78  			.assertContent().isContains("pathRemainder2:''")
79  			.assertContent().isContains("requestURI:'/cp/sp/'")
80  			.assertContent().isContains("requestParentURI:'/cp'")
81  			.assertContent().isContains("requestURL:'http://localhost/cp/sp/'")
82  			.assertContent().isContains("servletPath:'/sp'")
83  			.assertContent().isContains("servletURI:'/cp/sp'")
84  			.assertContent().isContains("method:1")
85  		;
86  	}
87  	@Test void a03() throws Exception {
88  		a.get("http://localhost/cp/sp//").run()
89  			.assertContent().isContains("pathInfo:'//'")
90  			.assertContent().isContains("pathRemainder:'/'")
91  			.assertContent().isContains("pathRemainderUndecoded:'/'")
92  			.assertContent().isContains("pathRemainder2:'/'")
93  			.assertContent().isContains("requestURI:'/cp/sp//'")
94  			.assertContent().isContains("requestParentURI:'/cp'")
95  			.assertContent().isContains("requestURL:'http://localhost/cp/sp//'")
96  			.assertContent().isContains("servletPath:'/sp'")
97  			.assertContent().isContains("servletURI:'/cp/sp'")
98  			.assertContent().isContains("method:1")
99  		;
100 	}
101 	@Test void a04() throws Exception {
102 		a.get("http://localhost/cp/sp///").run()
103 			.assertContent().isContains("pathInfo:'///'")
104 			.assertContent().isContains("pathRemainder:'//'")
105 			.assertContent().isContains("pathRemainderUndecoded:'//'")
106 			.assertContent().isContains("pathRemainder2:'//'")
107 			.assertContent().isContains("requestURI:'/cp/sp///'")
108 			.assertContent().isContains("requestParentURI:'/cp'")
109 			.assertContent().isContains("requestURL:'http://localhost/cp/sp///'")
110 			.assertContent().isContains("servletPath:'/sp'")
111 			.assertContent().isContains("servletURI:'/cp/sp'")
112 			.assertContent().isContains("method:1")
113 		;
114 	}
115 	@Test void a05() throws Exception {
116 		a.get("http://localhost/cp/sp/foo/bar").run()
117 			.assertContent().isContains("pathInfo:'/foo/bar'")
118 			.assertContent().isContains("pathRemainder:'foo/bar'")
119 			.assertContent().isContains("pathRemainderUndecoded:'foo/bar'")
120 			.assertContent().isContains("pathRemainder2:'foo/bar'")
121 			.assertContent().isContains("requestURI:'/cp/sp/foo/bar'")
122 			.assertContent().isContains("requestParentURI:'/cp/sp/foo'")
123 			.assertContent().isContains("requestURL:'http://localhost/cp/sp/foo/bar'")
124 			.assertContent().isContains("servletPath:'/sp'")
125 			.assertContent().isContains("servletURI:'/cp/sp'")
126 			.assertContent().isContains("method:1")
127 		;
128 	}
129 	@Test void a06() throws Exception {
130 		a.get("http://localhost/cp/sp/foo/bar/").run()
131 			.assertContent().isContains("pathInfo:'/foo/bar/'")
132 			.assertContent().isContains("pathRemainder:'foo/bar/'")
133 			.assertContent().isContains("pathRemainderUndecoded:'foo/bar/'")
134 			.assertContent().isContains("pathRemainder2:'foo/bar/'")
135 			.assertContent().isContains("requestURI:'/cp/sp/foo/bar/'")
136 			.assertContent().isContains("requestParentURI:'/cp/sp/foo'")
137 			.assertContent().isContains("requestURL:'http://localhost/cp/sp/foo/bar/'")
138 			.assertContent().isContains("servletPath:'/sp'")
139 			.assertContent().isContains("servletURI:'/cp/sp'")
140 			.assertContent().isContains("method:1")
141 		;
142 	}
143 	@Test void a07() throws Exception {
144 		a.get("http://localhost/cp/sp//foo//bar//").run()
145 			.assertContent().isContains("pathInfo:'//foo//bar//'")
146 			.assertContent().isContains("pathRemainder:'/foo//bar//'")
147 			.assertContent().isContains("pathRemainderUndecoded:'/foo//bar//'")
148 			.assertContent().isContains("pathRemainder2:'/foo//bar//'")
149 			.assertContent().isContains("requestURI:'/cp/sp//foo//bar//'")
150 			.assertContent().isContains("requestParentURI:'/cp/sp/foo/'")
151 			.assertContent().isContains("requestURL:'http://localhost/cp/sp//foo//bar//'")
152 			.assertContent().isContains("servletPath:'/sp'")
153 			.assertContent().isContains("servletURI:'/cp/sp'")
154 			.assertContent().isContains("method:1")
155 		;
156 	}
157 	@Test void a08() throws Exception {
158 		a.get("http://localhost/cp/sp/%20").run()
159 			.assertContent().isContains("pathInfo:'/ '")
160 			.assertContent().isContains("pathRemainder:' '")
161 			.assertContent().isContains("pathRemainderUndecoded:'%20'")
162 			.assertContent().isContains("pathRemainder2:' '")
163 			.assertContent().isContains("requestURI:'/cp/sp/%20'")
164 			.assertContent().isContains("requestParentURI:'/cp/sp")
165 			.assertContent().isContains("requestURL:'http://localhost/cp/sp/%20'")
166 			.assertContent().isContains("servletPath:'/sp'")
167 			.assertContent().isContains("servletURI:'/cp/sp'")
168 			.assertContent().isContains("method:1")
169 		;
170 	}
171 	@Test void a09() throws Exception {
172 		a.get("http://localhost/cp/sp/+").run()
173 			.assertContent().isContains("pathInfo:'/ '")
174 			.assertContent().isContains("pathRemainder:' '")
175 			.assertContent().isContains("pathRemainderUndecoded:'+'")
176 			.assertContent().isContains("pathRemainder2:' '")
177 			.assertContent().isContains("requestURI:'/cp/sp/+'")
178 			.assertContent().isContains("requestParentURI:'/cp/sp")
179 			.assertContent().isContains("requestURL:'http://localhost/cp/sp/+'")
180 			.assertContent().isContains("servletPath:'/sp'")
181 			.assertContent().isContains("servletURI:'/cp/sp'")
182 			.assertContent().isContains("method:1")
183 		;
184 	}
185 
186 	//------------------------------------------------------------------------------------------------------------------
187 	// Subpath in method
188 	//------------------------------------------------------------------------------------------------------------------
189 
190 	public static class B {
191 		@RestGet(path="/subpath/*")
192 		public JsonMap get(RestRequest req, @Path("/*") String r) {
193 			return getPaths(req).append("pathRemainder2", r).append("method",2);
194 		}
195 	}
196 	static MockRestClient b = MockRestClient.create(B.class).contextPath("/cp").servletPath("/sp").defaultRequestConfig(RequestConfig.custom().setNormalizeUri(false).build()).build();
197 
198 	@Test void b01() throws Exception {
199 		b.get("http://localhost/cp/sp/subpath").run()
200 			.assertContent().isContains("pathInfo:'/subpath'")
201 			.assertContent().isContains("pathRemainder:null")
202 			.assertContent().isContains("pathRemainderUndecoded:null")
203 			.assertContent().isContains("pathRemainder2:null")
204 			.assertContent().isContains("requestURI:'/cp/sp/subpath'")
205 			.assertContent().isContains("requestParentURI:'/cp/sp'")
206 			.assertContent().isContains("requestURL:'http://localhost/cp/sp/subpath'")
207 			.assertContent().isContains("servletPath:'/sp'")
208 			.assertContent().isContains("servletURI:'/cp/sp'")
209 			.assertContent().isContains("method:2")
210 		;
211 	}
212 	@Test void b02() throws Exception {
213 		b.get("http://localhost/cp/sp/subpath/").run()
214 			.assertContent().isContains("pathInfo:'/subpath/'")
215 			.assertContent().isContains("pathRemainder:''")
216 			.assertContent().isContains("pathRemainderUndecoded:''")
217 			.assertContent().isContains("pathRemainder2:''")
218 			.assertContent().isContains("requestURI:'/cp/sp/subpath/'")
219 			.assertContent().isContains("requestParentURI:'/cp/sp'")
220 			.assertContent().isContains("requestURL:'http://localhost/cp/sp/subpath/'")
221 			.assertContent().isContains("servletPath:'/sp'")
222 			.assertContent().isContains("servletURI:'/cp/sp'")
223 			.assertContent().isContains("method:2")
224 		;
225 	}
226 	@Test void b03() throws Exception {
227 		b.get("http://localhost/cp/sp/subpath//").run()
228 			.assertContent().isContains("pathInfo:'/subpath//'")
229 			.assertContent().isContains("pathRemainder:'/'")
230 			.assertContent().isContains("pathRemainderUndecoded:'/'")
231 			.assertContent().isContains("pathRemainder2:'/'")
232 			.assertContent().isContains("requestURI:'/cp/sp/subpath//'")
233 			.assertContent().isContains("requestParentURI:'/cp/sp'")
234 			.assertContent().isContains("requestURL:'http://localhost/cp/sp/subpath//'")
235 			.assertContent().isContains("servletPath:'/sp'")
236 			.assertContent().isContains("servletURI:'/cp/sp'")
237 			.assertContent().isContains("method:2")
238 		;
239 	}
240 	@Test void b04() throws Exception {
241 		b.get("http://localhost/cp/sp/subpath///").run()
242 			.assertContent().isContains("pathInfo:'/subpath///'")
243 			.assertContent().isContains("pathRemainder:'//'")
244 			.assertContent().isContains("pathRemainderUndecoded:'//'")
245 			.assertContent().isContains("pathRemainder2:'//'")
246 			.assertContent().isContains("requestURI:'/cp/sp/subpath///'")
247 			.assertContent().isContains("requestParentURI:'/cp/sp'")
248 			.assertContent().isContains("requestURL:'http://localhost/cp/sp/subpath///'")
249 			.assertContent().isContains("servletPath:'/sp'")
250 			.assertContent().isContains("servletURI:'/cp/sp'")
251 			.assertContent().isContains("method:2")
252 		;
253 	}
254 	@Test void b05() throws Exception {
255 		b.get("http://localhost/cp/sp/subpath/foo/bar").run()
256 			.assertContent().isContains("pathInfo:'/subpath/foo/bar'")
257 			.assertContent().isContains("pathRemainder:'foo/bar'")
258 			.assertContent().isContains("pathRemainderUndecoded:'foo/bar'")
259 			.assertContent().isContains("pathRemainder2:'foo/bar'")
260 			.assertContent().isContains("requestURI:'/cp/sp/subpath/foo/bar'")
261 			.assertContent().isContains("requestParentURI:'/cp/sp/subpath/foo'")
262 			.assertContent().isContains("requestURL:'http://localhost/cp/sp/subpath/foo/bar'")
263 			.assertContent().isContains("servletPath:'/sp'")
264 			.assertContent().isContains("servletURI:'/cp/sp'")
265 			.assertContent().isContains("method:2")
266 		;
267 	}
268 	@Test void b06() throws Exception {
269 		b.get("http://localhost/cp/sp/subpath/foo/bar/").run()
270 			.assertContent().isContains("pathInfo:'/subpath/foo/bar/'")
271 			.assertContent().isContains("pathRemainder:'foo/bar/'")
272 			.assertContent().isContains("pathRemainderUndecoded:'foo/bar/'")
273 			.assertContent().isContains("pathRemainder2:'foo/bar/'")
274 			.assertContent().isContains("requestURI:'/cp/sp/subpath/foo/bar/'")
275 			.assertContent().isContains("requestParentURI:'/cp/sp/subpath/foo'")
276 			.assertContent().isContains("requestURL:'http://localhost/cp/sp/subpath/foo/bar/'")
277 			.assertContent().isContains("servletPath:'/sp'")
278 			.assertContent().isContains("servletURI:'/cp/sp'")
279 			.assertContent().isContains("method:2")
280 		;
281 	}
282 	@Test void b07() throws Exception {
283 		b.get("http://localhost/cp/sp/subpath//foo//bar//").run()
284 			.assertContent().isContains("pathInfo:'/subpath//foo//bar//'")
285 			.assertContent().isContains("pathRemainder:'/foo//bar//'")
286 			.assertContent().isContains("pathRemainderUndecoded:'/foo//bar//'")
287 			.assertContent().isContains("pathRemainder2:'/foo//bar//'")
288 			.assertContent().isContains("requestURI:'/cp/sp/subpath//foo//bar//'")
289 			.assertContent().isContains("requestParentURI:'/cp/sp/subpath//foo/'")
290 			.assertContent().isContains("requestURL:'http://localhost/cp/sp/subpath//foo//bar//'")
291 			.assertContent().isContains("servletPath:'/sp'")
292 			.assertContent().isContains("servletURI:'/cp/sp'")
293 			.assertContent().isContains("method:2")
294 		;
295 	}
296 	@Test void b08() throws Exception {
297 		b.get("http://localhost/cp/sp/subpath/%20").run()
298 			.assertContent().isContains("pathInfo:'/subpath/ '")
299 			.assertContent().isContains("pathRemainder:' '")
300 			.assertContent().isContains("pathRemainderUndecoded:'%20'")
301 			.assertContent().isContains("pathRemainder2:' '")
302 			.assertContent().isContains("requestURI:'/cp/sp/subpath/%20'")
303 			.assertContent().isContains("requestParentURI:'/cp/sp/subpath")
304 			.assertContent().isContains("requestURL:'http://localhost/cp/sp/subpath/%20'")
305 			.assertContent().isContains("servletPath:'/sp'")
306 			.assertContent().isContains("servletURI:'/cp/sp'")
307 			.assertContent().isContains("method:2")
308 		;
309 	}
310 	@Test void b09() throws Exception {
311 		b.get("http://localhost/cp/sp/subpath/+").run()
312 			.assertContent().isContains("pathInfo:'/subpath/ '")
313 			.assertContent().isContains("pathRemainder:' '")
314 			.assertContent().isContains("pathRemainderUndecoded:'+'")
315 			.assertContent().isContains("pathRemainder2:' '")
316 			.assertContent().isContains("requestURI:'/cp/sp/subpath/+'")
317 			.assertContent().isContains("requestParentURI:'/cp/sp/subpath")
318 			.assertContent().isContains("requestURL:'http://localhost/cp/sp/subpath/+'")
319 			.assertContent().isContains("servletPath:'/sp'")
320 			.assertContent().isContains("servletURI:'/cp/sp'")
321 			.assertContent().isContains("method:2")
322 		;
323 	}
324 
325 	//------------------------------------------------------------------------------------------------------------------
326 	// Child resource
327 	//------------------------------------------------------------------------------------------------------------------
328 
329 	@Rest(children={C1.class})
330 	public static class C {}
331 
332 	@Rest(path="/a")
333 	public static class C1 {
334 		@RestGet(path="/*")
335 		public JsonMap get(RestRequest req, @Path("/*") String r) {
336 			return getPaths(req).append("pathRemainder2", r).append("method",3);
337 		}
338 	}
339 	static MockRestClient c = MockRestClient.create(C.class).contextPath("/cp").servletPath("/sp").defaultRequestConfig(RequestConfig.custom().setNormalizeUri(false).build()).build();
340 
341 	@Test void c01() throws Exception {
342 		c.get("http://localhost/cp/sp/a").run()
343 			.assertContent().isContains("pathInfo:null")
344 			.assertContent().isContains("pathRemainder:null")
345 			.assertContent().isContains("pathRemainderUndecoded:null")
346 			.assertContent().isContains("pathRemainder2:null")
347 			.assertContent().isContains("requestURI:'/cp/sp/a'")
348 			.assertContent().isContains("requestParentURI:'/cp/sp")
349 			.assertContent().isContains("requestURL:'http://localhost/cp/sp/a'")
350 			.assertContent().isContains("servletPath:'/sp/a'")
351 			.assertContent().isContains("servletURI:'/cp/sp/a'")
352 			.assertContent().isContains("method:3")
353 		;
354 	}
355 	@Test void c02() throws Exception {
356 		c.get("http://localhost/cp/sp/a/").run()
357 			.assertContent().isContains("pathInfo:'/'")
358 			.assertContent().isContains("pathRemainder:''")
359 			.assertContent().isContains("pathRemainderUndecoded:''")
360 			.assertContent().isContains("pathRemainder2:''")
361 			.assertContent().isContains("requestURI:'/cp/sp/a/'")
362 			.assertContent().isContains("requestParentURI:'/cp/sp")
363 			.assertContent().isContains("requestURL:'http://localhost/cp/sp/a/'")
364 			.assertContent().isContains("servletPath:'/sp/a'")
365 			.assertContent().isContains("servletURI:'/cp/sp/a'")
366 			.assertContent().isContains("method:3")
367 		;
368 	}
369 	@Test void c03() throws Exception {
370 		c.get("http://localhost/cp/sp/a//").run()
371 			.assertContent().isContains("pathInfo:'//'")
372 			.assertContent().isContains("pathRemainder:'/'")
373 			.assertContent().isContains("pathRemainderUndecoded:'/'")
374 			.assertContent().isContains("pathRemainder2:'/'")
375 			.assertContent().isContains("requestURI:'/cp/sp/a//'")
376 			.assertContent().isContains("requestParentURI:'/cp/sp")
377 			.assertContent().isContains("requestURL:'http://localhost/cp/sp/a//'")
378 			.assertContent().isContains("servletPath:'/sp/a'")
379 			.assertContent().isContains("servletURI:'/cp/sp/a'")
380 			.assertContent().isContains("method:3")
381 		;
382 	}
383 	@Test void c04() throws Exception {
384 		c.get("http://localhost/cp/sp/a///").run()
385 			.assertContent().isContains("pathInfo:'///'")
386 			.assertContent().isContains("pathRemainder:'//'")
387 			.assertContent().isContains("pathRemainderUndecoded:'//'")
388 			.assertContent().isContains("pathRemainder2:'//'")
389 			.assertContent().isContains("requestURI:'/cp/sp/a///'")
390 			.assertContent().isContains("requestParentURI:'/cp/sp")
391 			.assertContent().isContains("requestURL:'http://localhost/cp/sp/a///'")
392 			.assertContent().isContains("servletPath:'/sp/a'")
393 			.assertContent().isContains("servletURI:'/cp/sp/a'")
394 			.assertContent().isContains("method:3")
395 		;
396 	}
397 	@Test void c05() throws Exception {
398 		c.get("http://localhost/cp/sp/a/foo/bar").run()
399 			.assertContent().isContains("pathInfo:'/foo/bar'")
400 			.assertContent().isContains("pathRemainder:'foo/bar'")
401 			.assertContent().isContains("pathRemainderUndecoded:'foo/bar'")
402 			.assertContent().isContains("pathRemainder2:'foo/bar'")
403 			.assertContent().isContains("requestURI:'/cp/sp/a/foo/bar'")
404 			.assertContent().isContains("requestParentURI:'/cp/sp/a/foo")
405 			.assertContent().isContains("requestURL:'http://localhost/cp/sp/a/foo/bar'")
406 			.assertContent().isContains("servletPath:'/sp/a'")
407 			.assertContent().isContains("servletURI:'/cp/sp/a'")
408 			.assertContent().isContains("method:3")
409 		;
410 	}
411 	@Test void c06() throws Exception {
412 		c.get("http://localhost/cp/sp/a/foo/bar/").run()
413 			.assertContent().isContains("pathInfo:'/foo/bar/'")
414 			.assertContent().isContains("pathRemainder:'foo/bar/'")
415 			.assertContent().isContains("pathRemainderUndecoded:'foo/bar/'")
416 			.assertContent().isContains("pathRemainder2:'foo/bar/'")
417 			.assertContent().isContains("requestURI:'/cp/sp/a/foo/bar/'")
418 			.assertContent().isContains("requestParentURI:'/cp/sp/a/foo")
419 			.assertContent().isContains("requestURL:'http://localhost/cp/sp/a/foo/bar/'")
420 			.assertContent().isContains("servletPath:'/sp/a'")
421 			.assertContent().isContains("servletURI:'/cp/sp/a'")
422 			.assertContent().isContains("method:3")
423 		;
424 	}
425 	@Test void c07() throws Exception {
426 		c.get("http://localhost/cp/sp/a//foo//bar//").run()
427 			.assertContent().isContains("pathInfo:'//foo//bar//'")
428 			.assertContent().isContains("pathRemainder:'/foo//bar//'")
429 			.assertContent().isContains("pathRemainderUndecoded:'/foo//bar//'")
430 			.assertContent().isContains("pathRemainder2:'/foo//bar//'")
431 			.assertContent().isContains("requestURI:'/cp/sp/a//foo//bar//'")
432 			.assertContent().isContains("requestParentURI:'/cp/sp/a/foo/")
433 			.assertContent().isContains("requestURL:'http://localhost/cp/sp/a//foo//bar//'")
434 			.assertContent().isContains("servletPath:'/sp/a'")
435 			.assertContent().isContains("servletURI:'/cp/sp/a'")
436 			.assertContent().isContains("method:3")
437 		;
438 	}
439 	@Test void c08() throws Exception {
440 		c.get("http://localhost/cp/sp/a/%20").run()
441 			.assertContent().isContains("pathInfo:'/ '")
442 			.assertContent().isContains("pathRemainder:' '")
443 			.assertContent().isContains("pathRemainderUndecoded:'%20'")
444 			.assertContent().isContains("pathRemainder2:' '")
445 			.assertContent().isContains("requestURI:'/cp/sp/a/%20'")
446 			.assertContent().isContains("requestParentURI:'/cp/sp/a")
447 			.assertContent().isContains("requestURL:'http://localhost/cp/sp/a/%20'")
448 			.assertContent().isContains("servletPath:'/sp/a'")
449 			.assertContent().isContains("servletURI:'/cp/sp/a'")
450 			.assertContent().isContains("method:3")
451 		;
452 	}
453 	@Test void c09() throws Exception {
454 		c.get("http://localhost/cp/sp/a/+").run()
455 			.assertContent().isContains("pathInfo:'/ '")
456 			.assertContent().isContains("pathRemainder:' '")
457 			.assertContent().isContains("pathRemainderUndecoded:'+'")
458 			.assertContent().isContains("pathRemainder2:' '")
459 			.assertContent().isContains("requestURI:'/cp/sp/a/+'")
460 			.assertContent().isContains("requestParentURI:'/cp/sp/a")
461 			.assertContent().isContains("requestURL:'http://localhost/cp/sp/a/+'")
462 			.assertContent().isContains("servletPath:'/sp/a'")
463 			.assertContent().isContains("servletURI:'/cp/sp/a'")
464 			.assertContent().isContains("method:3")
465 		;
466 	}
467 
468 	//------------------------------------------------------------------------------------------------------------------
469 	// Child resource and subpath in method
470 	//------------------------------------------------------------------------------------------------------------------
471 
472 	@Rest(children={D1.class})
473 	public static class D {}
474 
475 	@Rest(path="/a")
476 	public static class D1 {
477 		@RestGet(path="/subpath/*")
478 		public JsonMap get(RestRequest req, @Path("/*") String r) {
479 			return getPaths(req).append("pathRemainder2", r).append("method",4);
480 		}
481 	}
482 	static MockRestClient d = MockRestClient.create(D.class).contextPath("/cp").servletPath("/sp").defaultRequestConfig(RequestConfig.custom().setNormalizeUri(false).build()).build();
483 
484 	@Test void d01() throws Exception {
485 		d.get("http://localhost/cp/sp/a/subpath").run()
486 			.assertContent().isContains("pathInfo:'/subpath'")
487 			.assertContent().isContains("pathRemainder:null")
488 			.assertContent().isContains("pathRemainderUndecoded:null")
489 			.assertContent().isContains("pathRemainder2:null")
490 			.assertContent().isContains("requestURI:'/cp/sp/a/subpath'")
491 			.assertContent().isContains("requestParentURI:'/cp/sp/a")
492 			.assertContent().isContains("requestURL:'http://localhost/cp/sp/a/subpath'")
493 			.assertContent().isContains("servletPath:'/sp/a'")
494 			.assertContent().isContains("servletURI:'/cp/sp/a'")
495 			.assertContent().isContains("method:4")
496 		;
497 	}
498 	@Test void d02() throws Exception {
499 		d.get("http://localhost/cp/sp/a/subpath/").run()
500 			.assertContent().isContains("pathInfo:'/subpath/'")
501 			.assertContent().isContains("pathRemainder:''")
502 			.assertContent().isContains("pathRemainderUndecoded:''")
503 			.assertContent().isContains("pathRemainder2:''")
504 			.assertContent().isContains("requestURI:'/cp/sp/a/subpath/'")
505 			.assertContent().isContains("requestParentURI:'/cp/sp/a")
506 			.assertContent().isContains("requestURL:'http://localhost/cp/sp/a/subpath/'")
507 			.assertContent().isContains("servletPath:'/sp/a'")
508 			.assertContent().isContains("servletURI:'/cp/sp/a'")
509 			.assertContent().isContains("method:4")
510 		;
511 	}
512 	@Test void d03() throws Exception {
513 		d.get("http://localhost/cp/sp/a/subpath//").run()
514 			.assertContent().isContains("pathInfo:'/subpath//'")
515 			.assertContent().isContains("pathRemainder:'/'")
516 			.assertContent().isContains("pathRemainderUndecoded:'/'")
517 			.assertContent().isContains("pathRemainder2:'/'")
518 			.assertContent().isContains("requestURI:'/cp/sp/a/subpath//'")
519 			.assertContent().isContains("requestParentURI:'/cp/sp/a")
520 			.assertContent().isContains("requestURL:'http://localhost/cp/sp/a/subpath//'")
521 			.assertContent().isContains("servletPath:'/sp/a'")
522 			.assertContent().isContains("servletURI:'/cp/sp/a'")
523 			.assertContent().isContains("method:4")
524 		;
525 	}
526 	@Test void d04() throws Exception {
527 		d.get("http://localhost/cp/sp/a/subpath///").run()
528 			.assertContent().isContains("pathInfo:'/subpath///'")
529 			.assertContent().isContains("pathRemainder:'//'")
530 			.assertContent().isContains("pathRemainderUndecoded:'//'")
531 			.assertContent().isContains("pathRemainder2:'//'")
532 			.assertContent().isContains("requestURI:'/cp/sp/a/subpath///'")
533 			.assertContent().isContains("requestParentURI:'/cp/sp/a")
534 			.assertContent().isContains("requestURL:'http://localhost/cp/sp/a/subpath///'")
535 			.assertContent().isContains("servletPath:'/sp/a'")
536 			.assertContent().isContains("servletURI:'/cp/sp/a'")
537 			.assertContent().isContains("method:4")
538 		;
539 	}
540 	@Test void d05() throws Exception {
541 		d.get("http://localhost/cp/sp/a/subpath/foo/bar").run()
542 			.assertContent().isContains("pathInfo:'/subpath/foo/bar'")
543 			.assertContent().isContains("pathRemainder:'foo/bar'")
544 			.assertContent().isContains("pathRemainderUndecoded:'foo/bar'")
545 			.assertContent().isContains("pathRemainder2:'foo/bar'")
546 			.assertContent().isContains("requestURI:'/cp/sp/a/subpath/foo/bar'")
547 			.assertContent().isContains("requestParentURI:'/cp/sp/a/subpath/foo")
548 			.assertContent().isContains("requestURL:'http://localhost/cp/sp/a/subpath/foo/bar'")
549 			.assertContent().isContains("servletPath:'/sp/a'")
550 			.assertContent().isContains("servletURI:'/cp/sp/a'")
551 			.assertContent().isContains("method:4")
552 		;
553 	}
554 	@Test void d06() throws Exception {
555 		d.get("http://localhost/cp/sp/a/subpath/foo/bar/").run()
556 			.assertContent().isContains("pathInfo:'/subpath/foo/bar/'")
557 			.assertContent().isContains("pathRemainder:'foo/bar/'")
558 			.assertContent().isContains("pathRemainderUndecoded:'foo/bar/'")
559 			.assertContent().isContains("pathRemainder2:'foo/bar/'")
560 			.assertContent().isContains("requestURI:'/cp/sp/a/subpath/foo/bar/'")
561 			.assertContent().isContains("requestParentURI:'/cp/sp/a/subpath/foo")
562 			.assertContent().isContains("requestURL:'http://localhost/cp/sp/a/subpath/foo/bar/'")
563 			.assertContent().isContains("servletPath:'/sp/a'")
564 			.assertContent().isContains("servletURI:'/cp/sp/a'")
565 			.assertContent().isContains("method:4")
566 		;
567 	}
568 	@Test void d07() throws Exception {
569 		d.get("http://localhost/cp/sp/a/subpath//foo//bar//").run()
570 			.assertContent().isContains("pathInfo:'/subpath//foo//bar//'")
571 			.assertContent().isContains("pathRemainder:'/foo//bar//'")
572 			.assertContent().isContains("pathRemainderUndecoded:'/foo//bar//'")
573 			.assertContent().isContains("pathRemainder2:'/foo//bar//'")
574 			.assertContent().isContains("requestURI:'/cp/sp/a/subpath//foo//bar//'")
575 			.assertContent().isContains("requestParentURI:'/cp/sp/a/subpath//foo/")
576 			.assertContent().isContains("requestURL:'http://localhost/cp/sp/a/subpath//foo//bar//'")
577 			.assertContent().isContains("servletPath:'/sp/a'")
578 			.assertContent().isContains("servletURI:'/cp/sp/a'")
579 			.assertContent().isContains("method:4")
580 		;
581 	}
582 	@Test void d08() throws Exception {
583 		d.get("http://localhost/cp/sp/a/subpath/%20").run()
584 			.assertContent().isContains("pathInfo:'/subpath/ '")
585 			.assertContent().isContains("pathRemainder:' '")
586 			.assertContent().isContains("pathRemainderUndecoded:'%20'")
587 			.assertContent().isContains("pathRemainder2:' '")
588 			.assertContent().isContains("requestURI:'/cp/sp/a/subpath/%20'")
589 			.assertContent().isContains("requestParentURI:'/cp/sp/a/subpath")
590 			.assertContent().isContains("requestURL:'http://localhost/cp/sp/a/subpath/%20'")
591 			.assertContent().isContains("servletPath:'/sp/a'")
592 			.assertContent().isContains("servletURI:'/cp/sp/a'")
593 			.assertContent().isContains("method:4")
594 		;
595 	}
596 	@Test void d09() throws Exception {
597 		d.get("http://localhost/cp/sp/a/subpath/+").run()
598 			.assertContent().isContains("pathInfo:'/subpath/ '")
599 			.assertContent().isContains("pathRemainder:' '")
600 			.assertContent().isContains("pathRemainderUndecoded:'+'")
601 			.assertContent().isContains("pathRemainder2:' '")
602 			.assertContent().isContains("requestURI:'/cp/sp/a/subpath/+'")
603 			.assertContent().isContains("requestParentURI:'/cp/sp/a/subpath")
604 			.assertContent().isContains("requestURL:'http://localhost/cp/sp/a/subpath/+'")
605 			.assertContent().isContains("servletPath:'/sp/a'")
606 			.assertContent().isContains("servletURI:'/cp/sp/a'")
607 			.assertContent().isContains("method:4")
608 		;
609 	}
610 }