1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.shiro.util;
20
21
22
23
24
25
26
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 public class AntPathMatcher implements PatternMatcher {
61
62
63
64
65
66
67 public static final String DEFAULT_PATH_SEPARATOR = "/";
68
69 private String pathSeparator = DEFAULT_PATH_SEPARATOR;
70
71
72
73
74
75
76 public void setPathSeparator(String pathSeparator) {
77 this.pathSeparator = (pathSeparator != null ? pathSeparator : DEFAULT_PATH_SEPARATOR);
78 }
79
80
81 public boolean isPattern(String path) {
82 return (path.indexOf('*') != -1 || path.indexOf('?') != -1);
83 }
84
85 public boolean matches(String pattern, String source) {
86 return match(pattern, source);
87 }
88
89 public boolean match(String pattern, String path) {
90 return doMatch(pattern, path, true);
91 }
92
93 public boolean matchStart(String pattern, String path) {
94 return doMatch(pattern, path, false);
95 }
96
97
98
99
100
101
102
103
104
105
106
107
108 protected boolean doMatch(String pattern, String path, boolean fullMatch) {
109 if (path.startsWith(this.pathSeparator) != pattern.startsWith(this.pathSeparator)) {
110 return false;
111 }
112
113 String[] pattDirs = StringUtils.tokenizeToStringArray(pattern, this.pathSeparator);
114 String[] pathDirs = StringUtils.tokenizeToStringArray(path, this.pathSeparator);
115
116 int pattIdxStart = 0;
117 int pattIdxEnd = pattDirs.length - 1;
118 int pathIdxStart = 0;
119 int pathIdxEnd = pathDirs.length - 1;
120
121
122 while (pattIdxStart <= pattIdxEnd && pathIdxStart <= pathIdxEnd) {
123 String patDir = pattDirs[pattIdxStart];
124 if ("**".equals(patDir)) {
125 break;
126 }
127 if (!matchStrings(patDir, pathDirs[pathIdxStart])) {
128 return false;
129 }
130 pattIdxStart++;
131 pathIdxStart++;
132 }
133
134 if (pathIdxStart > pathIdxEnd) {
135
136 if (pattIdxStart > pattIdxEnd) {
137 return (pattern.endsWith(this.pathSeparator) ?
138 path.endsWith(this.pathSeparator) : !path.endsWith(this.pathSeparator));
139 }
140 if (!fullMatch) {
141 return true;
142 }
143 if (pattIdxStart == pattIdxEnd && pattDirs[pattIdxStart].equals("*") &&
144 path.endsWith(this.pathSeparator)) {
145 return true;
146 }
147 for (int i = pattIdxStart; i <= pattIdxEnd; i++) {
148 if (!pattDirs[i].equals("**")) {
149 return false;
150 }
151 }
152 return true;
153 } else if (pattIdxStart > pattIdxEnd) {
154
155 return false;
156 } else if (!fullMatch && "**".equals(pattDirs[pattIdxStart])) {
157
158 return true;
159 }
160
161
162 while (pattIdxStart <= pattIdxEnd && pathIdxStart <= pathIdxEnd) {
163 String patDir = pattDirs[pattIdxEnd];
164 if (patDir.equals("**")) {
165 break;
166 }
167 if (!matchStrings(patDir, pathDirs[pathIdxEnd])) {
168 return false;
169 }
170 pattIdxEnd--;
171 pathIdxEnd--;
172 }
173 if (pathIdxStart > pathIdxEnd) {
174
175 for (int i = pattIdxStart; i <= pattIdxEnd; i++) {
176 if (!pattDirs[i].equals("**")) {
177 return false;
178 }
179 }
180 return true;
181 }
182
183 while (pattIdxStart != pattIdxEnd && pathIdxStart <= pathIdxEnd) {
184 int patIdxTmp = -1;
185 for (int i = pattIdxStart + 1; i <= pattIdxEnd; i++) {
186 if (pattDirs[i].equals("**")) {
187 patIdxTmp = i;
188 break;
189 }
190 }
191 if (patIdxTmp == pattIdxStart + 1) {
192
193 pattIdxStart++;
194 continue;
195 }
196
197
198 int patLength = (patIdxTmp - pattIdxStart - 1);
199 int strLength = (pathIdxEnd - pathIdxStart + 1);
200 int foundIdx = -1;
201
202 strLoop:
203 for (int i = 0; i <= strLength - patLength; i++) {
204 for (int j = 0; j < patLength; j++) {
205 String subPat = (String) pattDirs[pattIdxStart + j + 1];
206 String subStr = (String) pathDirs[pathIdxStart + i + j];
207 if (!matchStrings(subPat, subStr)) {
208 continue strLoop;
209 }
210 }
211 foundIdx = pathIdxStart + i;
212 break;
213 }
214
215 if (foundIdx == -1) {
216 return false;
217 }
218
219 pattIdxStart = patIdxTmp;
220 pathIdxStart = foundIdx + patLength;
221 }
222
223 for (int i = pattIdxStart; i <= pattIdxEnd; i++) {
224 if (!pattDirs[i].equals("**")) {
225 return false;
226 }
227 }
228
229 return true;
230 }
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245 private boolean matchStrings(String pattern, String str) {
246 char[] patArr = pattern.toCharArray();
247 char[] strArr = str.toCharArray();
248 int patIdxStart = 0;
249 int patIdxEnd = patArr.length - 1;
250 int strIdxStart = 0;
251 int strIdxEnd = strArr.length - 1;
252 char ch;
253
254 boolean containsStar = false;
255 for (char aPatArr : patArr) {
256 if (aPatArr == '*') {
257 containsStar = true;
258 break;
259 }
260 }
261
262 if (!containsStar) {
263
264 if (patIdxEnd != strIdxEnd) {
265 return false;
266 }
267 for (int i = 0; i <= patIdxEnd; i++) {
268 ch = patArr[i];
269 if (ch != '?') {
270 if (ch != strArr[i]) {
271 return false;
272 }
273 }
274 }
275 return true;
276 }
277
278
279 if (patIdxEnd == 0) {
280 return true;
281 }
282
283
284 while ((ch = patArr[patIdxStart]) != '*' && strIdxStart <= strIdxEnd) {
285 if (ch != '?') {
286 if (ch != strArr[strIdxStart]) {
287 return false;
288 }
289 }
290 patIdxStart++;
291 strIdxStart++;
292 }
293 if (strIdxStart > strIdxEnd) {
294
295
296 for (int i = patIdxStart; i <= patIdxEnd; i++) {
297 if (patArr[i] != '*') {
298 return false;
299 }
300 }
301 return true;
302 }
303
304
305 while ((ch = patArr[patIdxEnd]) != '*' && strIdxStart <= strIdxEnd) {
306 if (ch != '?') {
307 if (ch != strArr[strIdxEnd]) {
308 return false;
309 }
310 }
311 patIdxEnd--;
312 strIdxEnd--;
313 }
314 if (strIdxStart > strIdxEnd) {
315
316
317 for (int i = patIdxStart; i <= patIdxEnd; i++) {
318 if (patArr[i] != '*') {
319 return false;
320 }
321 }
322 return true;
323 }
324
325
326
327 while (patIdxStart != patIdxEnd && strIdxStart <= strIdxEnd) {
328 int patIdxTmp = -1;
329 for (int i = patIdxStart + 1; i <= patIdxEnd; i++) {
330 if (patArr[i] == '*') {
331 patIdxTmp = i;
332 break;
333 }
334 }
335 if (patIdxTmp == patIdxStart + 1) {
336
337 patIdxStart++;
338 continue;
339 }
340
341
342 int patLength = (patIdxTmp - patIdxStart - 1);
343 int strLength = (strIdxEnd - strIdxStart + 1);
344 int foundIdx = -1;
345 strLoop:
346 for (int i = 0; i <= strLength - patLength; i++) {
347 for (int j = 0; j < patLength; j++) {
348 ch = patArr[patIdxStart + j + 1];
349 if (ch != '?') {
350 if (ch != strArr[strIdxStart + i + j]) {
351 continue strLoop;
352 }
353 }
354 }
355
356 foundIdx = strIdxStart + i;
357 break;
358 }
359
360 if (foundIdx == -1) {
361 return false;
362 }
363
364 patIdxStart = patIdxTmp;
365 strIdxStart = foundIdx + patLength;
366 }
367
368
369
370 for (int i = patIdxStart; i <= patIdxEnd; i++) {
371 if (patArr[i] != '*') {
372 return false;
373 }
374 }
375
376 return true;
377 }
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395 public String extractPathWithinPattern(String pattern, String path) {
396 String[] patternParts = StringUtils.tokenizeToStringArray(pattern, this.pathSeparator);
397 String[] pathParts = StringUtils.tokenizeToStringArray(path, this.pathSeparator);
398
399 StringBuilder buffer = new StringBuilder();
400
401
402 int puts = 0;
403 for (int i = 0; i < patternParts.length; i++) {
404 String patternPart = patternParts[i];
405 if ((patternPart.indexOf('*') > -1 || patternPart.indexOf('?') > -1) && pathParts.length >= i + 1) {
406 if (puts > 0 || (i == 0 && !pattern.startsWith(this.pathSeparator))) {
407 buffer.append(this.pathSeparator);
408 }
409 buffer.append(pathParts[i]);
410 puts++;
411 }
412 }
413
414
415 for (int i = patternParts.length; i < pathParts.length; i++) {
416 if (puts > 0 || i > 0) {
417 buffer.append(this.pathSeparator);
418 }
419 buffer.append(pathParts[i]);
420 }
421
422 return buffer.toString();
423 }
424
425 }