1 /**
2  * Copyright (C) 2008 Google Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.google.inject.servlet;
17 
18 import java.util.regex.Matcher;
19 import java.util.regex.Pattern;
20 
21 /**
22  * An enumeration of the available URI-pattern matching styles
23  *
24  * @since 3.0
25  */
26 public enum UriPatternType {
27   SERVLET, REGEX;
28 
get(UriPatternType type, String pattern)29   static UriPatternMatcher get(UriPatternType type, String pattern) {
30     switch (type) {
31       case SERVLET:
32         return new ServletStyleUriPatternMatcher(pattern);
33       case REGEX:
34         return new RegexUriPatternMatcher(pattern);
35       default:
36         return null;
37     }
38   }
39 
getUri(String uri)40   private static String getUri(String uri) {
41     // Strip out the query, if it existed in the URI.  See issue 379.
42     int queryIdx = uri.indexOf('?');
43     if (queryIdx != -1) {
44       uri = uri.substring(0, queryIdx);
45     }
46     return uri;
47   }
48 
49   /**
50    * Matches URIs using the pattern grammar of the Servlet API and web.xml.
51    *
52    * @author dhanji@gmail.com (Dhanji R. Prasanna)
53    */
54   private static class ServletStyleUriPatternMatcher implements UriPatternMatcher {
55     private final String pattern;
56     private final Kind patternKind;
57 
58     private static enum Kind { PREFIX, SUFFIX, LITERAL, }
59 
ServletStyleUriPatternMatcher(String pattern)60     public ServletStyleUriPatternMatcher(String pattern) {
61       if (pattern.startsWith("*")) {
62         this.pattern = pattern.substring(1);
63         this.patternKind = Kind.PREFIX;
64       } else if (pattern.endsWith("*")) {
65         this.pattern = pattern.substring(0, pattern.length() - 1);
66         this.patternKind = Kind.SUFFIX;
67       } else {
68         this.pattern = pattern;
69         this.patternKind = Kind.LITERAL;
70       }
71     }
72 
matches(String uri)73     public boolean matches(String uri) {
74       if (null == uri) {
75         return false;
76       }
77 
78       uri = getUri(uri);
79       if (patternKind == Kind.PREFIX) {
80         return uri.endsWith(pattern);
81       } else if (patternKind == Kind.SUFFIX) {
82         return uri.startsWith(pattern);
83       }
84 
85       //else treat as a literal
86       return pattern.equals(uri);
87     }
88 
extractPath(String path)89     public String extractPath(String path) {
90       if (patternKind == Kind.PREFIX) {
91         return null;
92       } else if (patternKind == Kind.SUFFIX) {
93         String extract = pattern;
94 
95         //trim the trailing '/'
96         if (extract.endsWith("/")) {
97           extract = extract.substring(0, extract.length() - 1);
98         }
99 
100         return extract;
101       }
102 
103       //else treat as literal
104       return path;
105     }
106 
getPatternType()107     public UriPatternType getPatternType() {
108       return UriPatternType.SERVLET;
109     }
110   }
111 
112   /**
113    * Matches URIs using a regular expression.
114    *
115    * @author dhanji@gmail.com (Dhanji R. Prasanna)
116    */
117   private static class RegexUriPatternMatcher implements UriPatternMatcher {
118     private final Pattern pattern;
119 
RegexUriPatternMatcher(String pattern)120     public RegexUriPatternMatcher(String pattern) {
121       this.pattern = Pattern.compile(pattern);
122     }
123 
matches(String uri)124     public boolean matches(String uri) {
125       return null != uri && this.pattern.matcher(getUri(uri)).matches();
126     }
127 
extractPath(String path)128     public String extractPath(String path) {
129       Matcher matcher = pattern.matcher(path);
130       if (matcher.matches() && matcher.groupCount() >= 1) {
131 
132         // Try to capture the everything before the regex begins to match
133         // the path. This is a rough approximation to try and get parity
134         // with the servlet style mapping where the path is a capture of
135         // the URI before the wildcard.
136         int end = matcher.start(1);
137         if (end < path.length()) {
138           return path.substring(0, end);
139         }
140       }
141       return null;
142     }
143 
getPatternType()144     public UriPatternType getPatternType() {
145       return UriPatternType.REGEX;
146     }
147   }
148 }
149