1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.juneau;
18
19 import static org.apache.juneau.UriRelativity.*;
20 import static org.apache.juneau.UriResolution.*;
21 import static org.apache.juneau.commons.utils.StringUtils.*;
22 import static org.apache.juneau.commons.utils.ThrowableUtils.*;
23 import static org.apache.juneau.commons.utils.Utils.*;
24
25 import java.io.*;
26 import java.net.*;
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61 public class UriResolver {
62
63
64
65
66
67
68
69
70
71 public static UriResolver of(UriResolution resolution, UriRelativity relativity, UriContext uriContext) {
72 return new UriResolver(resolution, relativity, uriContext);
73 }
74
75 private static boolean hasDotSegments(String s) {
76 if (s == null)
77 return false;
78 for (var i = 0; i < s.length() - 1; i++) {
79 var c = s.charAt(i);
80 if ((i == 0 && c == '/') || (c == '/' && s.charAt(i + 1) == '.'))
81 return true;
82 }
83 return false;
84 }
85
86 private static boolean isSpecialUri(String s) {
87 if (s == null || s.isEmpty())
88 return false;
89 var c = s.charAt(0);
90 if (c != 's' && c != 'c' && c != 'r')
91 return false;
92 return s.startsWith("servlet:") || s.startsWith("context:") || s.startsWith("request:");
93 }
94
95 private static String normalize(String s) {
96 s = URI.create(s).normalize().toString();
97 if (s.length() > 1 && s.charAt(s.length() - 1) == '/')
98 s = s.substring(0, s.length() - 1);
99 return s;
100 }
101
102 private final UriResolution resolution;
103
104 private final UriRelativity relativity;
105
106 private final String authority, contextRoot, servletPath, pathInfo, parentPath;
107
108
109
110
111
112
113
114
115 public UriResolver(UriResolution resolution, UriRelativity relativity, UriContext uriContext) {
116 this.resolution = resolution;
117 this.relativity = relativity;
118 this.authority = uriContext.authority;
119 this.contextRoot = uriContext.contextRoot;
120 this.servletPath = uriContext.servletPath;
121 this.pathInfo = uriContext.pathInfo;
122 this.parentPath = uriContext.parentPath;
123 }
124
125
126
127
128
129
130
131
132 public Appendable append(Appendable a, Object o) {
133
134 try {
135 var uri = s(o);
136 uri = nullIfEmpty(uri);
137 var needsNormalize = hasDotSegments(uri) && nn(resolution);
138
139
140 if (isAbsoluteUri(uri))
141 return a.append(needsNormalize ? normalize(uri) : uri);
142 if (resolution == NONE && ! isSpecialUri(uri))
143 return a.append(emptyIfNull(uri));
144 if (resolution == ROOT_RELATIVE && startsWith(uri, '/'))
145 return a.append(needsNormalize ? normalize(uri) : uri);
146
147 var a2 = needsNormalize ? new StringBuilder() : a;
148
149
150 if (startsWith(uri, '/')) {
151 if (nn(authority))
152 a2.append(authority);
153 if (uri.length() != 1)
154 a2.append(uri);
155 else if (authority == null)
156 a2.append('/');
157 }
158
159
160 else if (nn(uri) && uri.startsWith("context:")) {
161 if (resolution == ABSOLUTE && nn(authority))
162 a2.append(authority);
163 var hasContext = nn(contextRoot) && ! contextRoot.isEmpty();
164 if (hasContext)
165 a2.append('/').append(contextRoot);
166 if (uri.length() > 8) {
167 var remainder = uri.substring(8);
168
169 if (remainder.equals("/") && (hasContext || (resolution == ABSOLUTE && nn(authority)))) {
170
171 } else if (! remainder.isEmpty() && remainder.charAt(0) != '/' && remainder.charAt(0) != '?' && remainder.charAt(0) != '#') {
172 a2.append('/').append(remainder);
173 } else {
174 a2.append(remainder);
175 }
176 } else if (! hasContext && (authority == null || resolution != ABSOLUTE))
177 a2.append('/');
178 }
179
180
181 else if (nn(uri) && uri.startsWith("servlet:")) {
182 if (resolution == ABSOLUTE && nn(authority))
183 a2.append(authority);
184 var hasContext = nn(contextRoot) && ! contextRoot.isEmpty();
185 var hasServlet = nn(servletPath) && ! servletPath.isEmpty();
186 if (hasContext)
187 a2.append('/').append(contextRoot);
188 if (hasServlet)
189 a2.append('/').append(servletPath);
190 if (uri.length() > 8) {
191 var remainder = uri.substring(8);
192
193 if (remainder.equals("/") && (hasContext || hasServlet || (resolution == ABSOLUTE && nn(authority)))) {
194
195 } else if (! remainder.isEmpty() && remainder.charAt(0) != '/' && remainder.charAt(0) != '?' && remainder.charAt(0) != '#') {
196 a2.append('/').append(remainder);
197 } else {
198 a2.append(remainder);
199 }
200 } else if (! hasServlet && ! hasContext && (authority == null || resolution != ABSOLUTE))
201 a2.append('/');
202 }
203
204
205 else if (nn(uri) && uri.startsWith("request:")) {
206 if (resolution == ABSOLUTE && nn(authority))
207 a2.append(authority);
208 var hasContext = nn(contextRoot) && ! contextRoot.isEmpty();
209 var hasServlet = nn(servletPath) && ! servletPath.isEmpty();
210 var hasPath = nn(pathInfo) && ! pathInfo.isEmpty();
211 if (hasContext)
212 a2.append('/').append(contextRoot);
213 if (hasServlet)
214 a2.append('/').append(servletPath);
215 if (hasPath)
216 a2.append('/').append(pathInfo);
217 if (uri.length() > 8) {
218 var remainder = uri.substring(8);
219
220 if (remainder.equals("/") && (hasContext || hasServlet || hasPath || (resolution == ABSOLUTE && nn(authority)))) {
221
222 } else if (! remainder.isEmpty() && remainder.charAt(0) != '/' && remainder.charAt(0) != '?' && remainder.charAt(0) != '#') {
223 a2.append('/').append(remainder);
224 } else {
225 a2.append(remainder);
226 }
227 } else if (! hasServlet && ! hasContext && ! hasPath && (authority == null || resolution != ABSOLUTE))
228 a2.append('/');
229 }
230
231
232 else {
233 if (resolution == ABSOLUTE && nn(authority))
234 a2.append(authority);
235 if (nn(contextRoot))
236 a2.append('/').append(contextRoot);
237 if (nn(servletPath))
238 a2.append('/').append(servletPath);
239 if (relativity == RESOURCE && nn(uri))
240 a2.append('/').append(uri);
241 else if (relativity == PATH_INFO) {
242 if (uri == null) {
243 if (nn(pathInfo))
244 a2.append('/').append(pathInfo);
245 } else {
246 if (nn(parentPath))
247 a2.append('/').append(parentPath);
248 a2.append('/').append(uri);
249 }
250 } else if (uri == null && contextRoot == null && servletPath == null && (authority == null || resolution != ABSOLUTE))
251 a2.append('/');
252 }
253
254 if (needsNormalize)
255 a.append(normalize(a2.toString()));
256
257 return a;
258 } catch (IOException e) {
259 throw toRex(e);
260 }
261 }
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281 public String relativize(Object relativeTo, Object uri) {
282 var r = resolve(relativeTo, ABSOLUTE);
283 var s = resolve(uri, ABSOLUTE);
284 return URI.create(r).relativize(URI.create(s)).toString();
285 }
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317 public String resolve(Object uri) {
318 return resolve(uri, resolution);
319 }
320
321 private String resolve(Object uri, UriResolution res) {
322 var s = s(uri);
323 if (isAbsoluteUri(s))
324 return hasDotSegments(s) && res != NONE ? normalize(s) : s;
325 if (res == ROOT_RELATIVE && startsWith(s, '/'))
326 return hasDotSegments(s) ? normalize(s) : s;
327 if (res == NONE && ! isSpecialUri(s))
328 return s;
329 return append(new StringBuilder(), s).toString();
330 }
331 }