]> WPIA git - gigi.git/blob - lib/jetty/org/eclipse/jetty/http/pathmap/ServletPathSpec.java
updating jetty to jetty-9.2.16.v2016040
[gigi.git] / lib / jetty / org / eclipse / jetty / http / pathmap / ServletPathSpec.java
1 //
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.
8 //
9 //      The Eclipse Public License is available at
10 //      http://www.eclipse.org/legal/epl-v10.html
11 //
12 //      The Apache License v2.0 is available at
13 //      http://www.opensource.org/licenses/apache2.0.php
14 //
15 //  You may elect to redistribute this code under either of these licenses.
16 //  ========================================================================
17 //
18
19 package org.eclipse.jetty.http.pathmap;
20
21 import org.eclipse.jetty.util.URIUtil;
22
23 public class ServletPathSpec extends PathSpec
24 {
25     public ServletPathSpec(String servletPathSpec)
26     {
27         super();
28         assertValidServletPathSpec(servletPathSpec);
29
30         // The Root Path Spec
31         if ((servletPathSpec == null) || (servletPathSpec.length() == 0))
32         {
33             super.pathSpec = "";
34             super.pathDepth = -1; // force this to be at the end of the sort order
35             this.specLength = 1;
36             this.group = PathSpecGroup.ROOT;
37             return;
38         }
39
40         // The Default Path Spec
41         if("/".equals(servletPathSpec))
42         {
43             super.pathSpec = "/";
44             super.pathDepth = -1; // force this to be at the end of the sort order
45             this.specLength = 1;
46             this.group = PathSpecGroup.DEFAULT;
47             return;
48         }
49         
50         this.specLength = servletPathSpec.length();
51         super.pathDepth = 0;
52         char lastChar = servletPathSpec.charAt(specLength - 1);
53         // prefix based
54         if ((servletPathSpec.charAt(0) == '/') && (specLength > 1) && (lastChar == '*'))
55         {
56             this.group = PathSpecGroup.PREFIX_GLOB;
57         }
58         // suffix based
59         else if (servletPathSpec.charAt(0) == '*')
60         {
61             this.group = PathSpecGroup.SUFFIX_GLOB;
62         }
63         else
64         {
65             this.group = PathSpecGroup.EXACT;
66         }
67
68         for (int i = 0; i < specLength; i++)
69         {
70             int cp = servletPathSpec.codePointAt(i);
71             if (cp < 128)
72             {
73                 char c = (char)cp;
74                 switch (c)
75                 {
76                     case '/':
77                         super.pathDepth++;
78                         break;
79                 }
80             }
81         }
82
83         super.pathSpec = servletPathSpec;
84     }
85
86     private void assertValidServletPathSpec(String servletPathSpec)
87     {
88         if ((servletPathSpec == null) || servletPathSpec.equals(""))
89         {
90             return; // empty path spec
91         }
92
93         int len = servletPathSpec.length();
94         // path spec must either start with '/' or '*.'
95         if (servletPathSpec.charAt(0) == '/')
96         {
97             // Prefix Based
98             if (len == 1)
99             {
100                 return; // simple '/' path spec
101             }
102             int idx = servletPathSpec.indexOf('*');
103             if (idx < 0)
104             {
105                 return; // no hit on glob '*'
106             }
107             // only allowed to have '*' at the end of the path spec
108             if (idx != (len - 1))
109             {
110                 throw new IllegalArgumentException("Servlet Spec 12.2 violation: glob '*' can only exist at end of prefix based matches: bad spec \""+ servletPathSpec +"\"");
111             }
112         }
113         else if (servletPathSpec.startsWith("*."))
114         {
115             // Suffix Based
116             int idx = servletPathSpec.indexOf('/');
117             // cannot have path separator
118             if (idx >= 0)
119             {
120                 throw new IllegalArgumentException("Servlet Spec 12.2 violation: suffix based path spec cannot have path separators: bad spec \""+ servletPathSpec +"\"");
121             }
122
123             idx = servletPathSpec.indexOf('*',2);
124             // only allowed to have 1 glob '*', at the start of the path spec
125             if (idx >= 1)
126             {
127                 throw new IllegalArgumentException("Servlet Spec 12.2 violation: suffix based path spec cannot have multiple glob '*': bad spec \""+ servletPathSpec +"\"");
128             }
129         }
130         else
131         {
132             throw new IllegalArgumentException("Servlet Spec 12.2 violation: path spec must start with \"/\" or \"*.\": bad spec \""+ servletPathSpec +"\"");
133         }
134     }
135
136     @Override
137     public String getPathInfo(String path)
138     {
139         // Path Info only valid for PREFIX_GLOB types
140         if (group == PathSpecGroup.PREFIX_GLOB)
141         {
142             if (path.length() == (specLength - 2))
143             {
144                 return null;
145             }
146             return path.substring(specLength - 2);
147         }
148
149         return null;
150     }
151
152     @Override
153     public String getPathMatch(String path)
154     {
155         switch (group)
156         {
157             case EXACT:
158                 if (pathSpec.equals(path))
159                 {
160                     return path;
161                 }
162                 else
163                 {
164                     return null;
165                 }
166             case PREFIX_GLOB:
167                 if (isWildcardMatch(path))
168                 {
169                     return path.substring(0,specLength - 2);
170                 }
171                 else
172                 {
173                     return null;
174                 }
175             case SUFFIX_GLOB:
176                 if (path.regionMatches(path.length() - (specLength - 1),pathSpec,1,specLength - 1))
177                 {
178                     return path;
179                 }
180                 else
181                 {
182                     return null;
183                 }
184             case DEFAULT:
185                 return path;
186             default:
187                 return null;
188         }
189     }
190
191     @Override
192     public String getRelativePath(String base, String path)
193     {
194         String info = getPathInfo(path);
195         if (info == null)
196         {
197             info = path;
198         }
199
200         if (info.startsWith("./"))
201         {
202             info = info.substring(2);
203         }
204         if (base.endsWith(URIUtil.SLASH))
205         {
206             if (info.startsWith(URIUtil.SLASH))
207             {
208                 path = base + info.substring(1);
209             }
210             else
211             {
212                 path = base + info;
213             }
214         }
215         else if (info.startsWith(URIUtil.SLASH))
216         {
217             path = base + info;
218         }
219         else
220         {
221             path = base + URIUtil.SLASH + info;
222         }
223         return path;
224     }
225
226     private boolean isWildcardMatch(String path)
227     {
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)))
231         {
232             if ((path.length() == cpl) || ('/' == path.charAt(cpl)))
233             {
234                 return true;
235             }
236         }
237         return false;
238     }
239
240     @Override
241     public boolean matches(String path)
242     {
243         switch (group)
244         {
245             case EXACT:
246                 return pathSpec.equals(path);
247             case PREFIX_GLOB:
248                 return isWildcardMatch(path);
249             case SUFFIX_GLOB:
250                 return path.regionMatches((path.length() - specLength) + 1,pathSpec,1,specLength - 1);
251             case ROOT:
252                 // Only "/" matches
253                 return ("/".equals(path));
254             case DEFAULT:
255                 // If we reached this point, then everything matches
256                 return true;
257             default:
258                 return false;
259         }
260     }
261 }