2 // ========================================================================
3 // Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
4 // ------------------------------------------------------------------------
5 // All rights reserved. This program and the accompanying materials
6 // are made available under the terms of the Eclipse Public License v1.0
7 // and Apache License v2.0 which accompanies this distribution.
9 // The Eclipse Public License is available at
10 // http://www.eclipse.org/legal/epl-v10.html
12 // The Apache License v2.0 is available at
13 // http://www.opensource.org/licenses/apache2.0.php
15 // You may elect to redistribute this code under either of these licenses.
16 // ========================================================================
19 package org.eclipse.jetty.http.pathmap;
21 import org.eclipse.jetty.util.URIUtil;
23 public class ServletPathSpec extends PathSpec
25 public ServletPathSpec(String servletPathSpec)
28 assertValidServletPathSpec(servletPathSpec);
31 if ((servletPathSpec == null) || (servletPathSpec.length() == 0))
34 super.pathDepth = -1; // force this to be at the end of the sort order
36 this.group = PathSpecGroup.ROOT;
40 // The Default Path Spec
41 if("/".equals(servletPathSpec))
44 super.pathDepth = -1; // force this to be at the end of the sort order
46 this.group = PathSpecGroup.DEFAULT;
50 this.specLength = servletPathSpec.length();
52 char lastChar = servletPathSpec.charAt(specLength - 1);
54 if ((servletPathSpec.charAt(0) == '/') && (specLength > 1) && (lastChar == '*'))
56 this.group = PathSpecGroup.PREFIX_GLOB;
59 else if (servletPathSpec.charAt(0) == '*')
61 this.group = PathSpecGroup.SUFFIX_GLOB;
65 this.group = PathSpecGroup.EXACT;
68 for (int i = 0; i < specLength; i++)
70 int cp = servletPathSpec.codePointAt(i);
83 super.pathSpec = servletPathSpec;
86 private void assertValidServletPathSpec(String servletPathSpec)
88 if ((servletPathSpec == null) || servletPathSpec.equals(""))
90 return; // empty path spec
93 int len = servletPathSpec.length();
94 // path spec must either start with '/' or '*.'
95 if (servletPathSpec.charAt(0) == '/')
100 return; // simple '/' path spec
102 int idx = servletPathSpec.indexOf('*');
105 return; // no hit on glob '*'
107 // only allowed to have '*' at the end of the path spec
108 if (idx != (len - 1))
110 throw new IllegalArgumentException("Servlet Spec 12.2 violation: glob '*' can only exist at end of prefix based matches: bad spec \""+ servletPathSpec +"\"");
113 else if (servletPathSpec.startsWith("*."))
116 int idx = servletPathSpec.indexOf('/');
117 // cannot have path separator
120 throw new IllegalArgumentException("Servlet Spec 12.2 violation: suffix based path spec cannot have path separators: bad spec \""+ servletPathSpec +"\"");
123 idx = servletPathSpec.indexOf('*',2);
124 // only allowed to have 1 glob '*', at the start of the path spec
127 throw new IllegalArgumentException("Servlet Spec 12.2 violation: suffix based path spec cannot have multiple glob '*': bad spec \""+ servletPathSpec +"\"");
132 throw new IllegalArgumentException("Servlet Spec 12.2 violation: path spec must start with \"/\" or \"*.\": bad spec \""+ servletPathSpec +"\"");
137 public String getPathInfo(String path)
139 // Path Info only valid for PREFIX_GLOB types
140 if (group == PathSpecGroup.PREFIX_GLOB)
142 if (path.length() == (specLength - 2))
146 return path.substring(specLength - 2);
153 public String getPathMatch(String path)
158 if (pathSpec.equals(path))
167 if (isWildcardMatch(path))
169 return path.substring(0,specLength - 2);
176 if (path.regionMatches(path.length() - (specLength - 1),pathSpec,1,specLength - 1))
192 public String getRelativePath(String base, String path)
194 String info = getPathInfo(path);
200 if (info.startsWith("./"))
202 info = info.substring(2);
204 if (base.endsWith(URIUtil.SLASH))
206 if (info.startsWith(URIUtil.SLASH))
208 path = base + info.substring(1);
215 else if (info.startsWith(URIUtil.SLASH))
221 path = base + URIUtil.SLASH + info;
226 private boolean isWildcardMatch(String path)
228 // For a spec of "/foo/*" match "/foo" , "/foo/..." but not "/foobar"
229 int cpl = specLength - 2;
230 if ((group == PathSpecGroup.PREFIX_GLOB) && (path.regionMatches(0,pathSpec,0,cpl)))
232 if ((path.length() == cpl) || ('/' == path.charAt(cpl)))
241 public boolean matches(String path)
246 return pathSpec.equals(path);
248 return isWildcardMatch(path);
250 return path.regionMatches((path.length() - specLength) + 1,pathSpec,1,specLength - 1);
253 return ("/".equals(path));
255 // If we reached this point, then everything matches