1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.eclipse.jetty.websocket.server.pathmap;
20
21 import org.eclipse.jetty.util.URIUtil;
22
23 public class ServletPathSpec extends PathSpec
24 {
25 public static final String PATH_SPEC_SEPARATORS = ":,";
26
27
28
29
30
31
32
33
34 public static ServletPathSpec[] getMultiPathSpecs(String servletPathSpec)
35 {
36 String pathSpecs[] = servletPathSpec.split(PATH_SPEC_SEPARATORS);
37 int len = pathSpecs.length;
38 ServletPathSpec sps[] = new ServletPathSpec[len];
39 for (int i = 0; i < len; i++)
40 {
41 sps[i] = new ServletPathSpec(pathSpecs[i]);
42 }
43 return sps;
44 }
45
46 public ServletPathSpec(String servletPathSpec)
47 {
48 super();
49 assertValidServletPathSpec(servletPathSpec);
50
51
52 if ((servletPathSpec == null) || (servletPathSpec.length() == 0) || "/".equals(servletPathSpec))
53 {
54 super.pathSpec = "/";
55 super.pathDepth = -1;
56 this.specLength = 1;
57 this.group = PathSpecGroup.DEFAULT;
58 return;
59 }
60
61 this.specLength = servletPathSpec.length();
62 super.pathDepth = 0;
63 char lastChar = servletPathSpec.charAt(specLength - 1);
64
65 if ((servletPathSpec.charAt(0) == '/') && (specLength > 1) && (lastChar == '*'))
66 {
67 this.group = PathSpecGroup.PREFIX_GLOB;
68 }
69
70 else if (servletPathSpec.charAt(0) == '*')
71 {
72 this.group = PathSpecGroup.SUFFIX_GLOB;
73 }
74 else
75 {
76 this.group = PathSpecGroup.EXACT;
77 }
78
79 for (int i = 0; i < specLength; i++)
80 {
81 int cp = servletPathSpec.codePointAt(i);
82 if (cp < 128)
83 {
84 char c = (char)cp;
85 switch (c)
86 {
87 case '/':
88 super.pathDepth++;
89 break;
90 }
91 }
92 }
93
94 super.pathSpec = servletPathSpec;
95 }
96
97 private void assertValidServletPathSpec(String servletPathSpec)
98 {
99 if ((servletPathSpec == null) || servletPathSpec.equals(""))
100 {
101 return;
102 }
103
104
105 for (char c : PATH_SPEC_SEPARATORS.toCharArray())
106 {
107 if (servletPathSpec.indexOf(c) >= 0)
108 {
109 throw new IllegalArgumentException("Servlet Spec 12.2 violation: encountered Path Spec Separator [" + PATH_SPEC_SEPARATORS
110 + "] within specified path spec. did you forget to split this path spec up?");
111 }
112 }
113
114 int len = servletPathSpec.length();
115
116 if (servletPathSpec.charAt(0) == '/')
117 {
118
119 if (len == 1)
120 {
121 return;
122 }
123 int idx = servletPathSpec.indexOf('*');
124 if (idx < 0)
125 {
126 return;
127 }
128
129 if (idx != (len - 1))
130 {
131 throw new IllegalArgumentException("Servlet Spec 12.2 violation: glob '*' can only exist at end of prefix based matches");
132 }
133 }
134 else if (servletPathSpec.startsWith("*."))
135 {
136
137 int idx = servletPathSpec.indexOf('/');
138
139 if (idx >= 0)
140 {
141 throw new IllegalArgumentException("Servlet Spec 12.2 violation: suffix based path spec cannot have path separators");
142 }
143
144 idx = servletPathSpec.indexOf('*',2);
145
146 if (idx >= 1)
147 {
148 throw new IllegalArgumentException("Servlet Spec 12.2 violation: suffix based path spec cannot have multiple glob '*'");
149 }
150 }
151 else
152 {
153 throw new IllegalArgumentException("Servlet Spec 12.2 violation: path spec must start with \"/\" or \"*.\"");
154 }
155 }
156
157 @Override
158 public String getPathInfo(String path)
159 {
160
161 if (group == PathSpecGroup.PREFIX_GLOB)
162 {
163 if (path.length() == (specLength - 2))
164 {
165 return null;
166 }
167 return path.substring(specLength - 2);
168 }
169
170 return null;
171 }
172
173 @Override
174 public String getPathMatch(String path)
175 {
176 switch (group)
177 {
178 case EXACT:
179 if (pathSpec.equals(path))
180 {
181 return path;
182 }
183 else
184 {
185 return null;
186 }
187 case PREFIX_GLOB:
188 if (isWildcardMatch(path))
189 {
190 return path.substring(0,specLength - 2);
191 }
192 else
193 {
194 return null;
195 }
196 case SUFFIX_GLOB:
197 if (path.regionMatches(path.length() - (specLength - 1),pathSpec,1,specLength - 1))
198 {
199 return path;
200 }
201 else
202 {
203 return null;
204 }
205 case DEFAULT:
206 return path;
207 default:
208 return null;
209 }
210 }
211
212 @Override
213 public String getRelativePath(String base, String path)
214 {
215 String info = getPathInfo(path);
216 if (info == null)
217 {
218 info = path;
219 }
220
221 if (info.startsWith("./"))
222 {
223 info = info.substring(2);
224 }
225 if (base.endsWith(URIUtil.SLASH))
226 {
227 if (info.startsWith(URIUtil.SLASH))
228 {
229 path = base + info.substring(1);
230 }
231 else
232 {
233 path = base + info;
234 }
235 }
236 else if (info.startsWith(URIUtil.SLASH))
237 {
238 path = base + info;
239 }
240 else
241 {
242 path = base + URIUtil.SLASH + info;
243 }
244 return path;
245 }
246
247 private boolean isExactMatch(String path)
248 {
249 if (group == PathSpecGroup.EXACT)
250 {
251 if (pathSpec.equals(path))
252 {
253 return true;
254 }
255 return (path.charAt(path.length() - 1) == '/') && (path.equals(pathSpec + '/'));
256 }
257 return false;
258 }
259
260 private boolean isWildcardMatch(String path)
261 {
262
263 int cpl = specLength - 2;
264 if ((group == PathSpecGroup.PREFIX_GLOB) && (path.regionMatches(0,pathSpec,0,cpl)))
265 {
266 if ((path.length() == cpl) || ('/' == path.charAt(cpl)))
267 {
268 return true;
269 }
270 }
271 return false;
272 }
273
274 @Override
275 public boolean matches(String path)
276 {
277 switch (group)
278 {
279 case EXACT:
280 return isExactMatch(path);
281 case PREFIX_GLOB:
282 return isWildcardMatch(path);
283 case SUFFIX_GLOB:
284 return path.regionMatches((path.length() - specLength) + 1,pathSpec,1,specLength - 1);
285 case DEFAULT:
286 return true;
287 default:
288 return false;
289 }
290 }
291 }