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 import java.util.regex.PatternSyntaxException; 21 22 /** 23 * An enumeration of the available URI-pattern matching styles 24 * 25 * @since 3.0 26 */ 27 public enum UriPatternType { 28 SERVLET, 29 REGEX; 30 get(UriPatternType type, String pattern)31 static UriPatternMatcher get(UriPatternType type, String pattern) { 32 switch (type) { 33 case SERVLET: 34 return new ServletStyleUriPatternMatcher(pattern); 35 case REGEX: 36 return new RegexUriPatternMatcher(pattern); 37 default: 38 return null; 39 } 40 } 41 getUri(String uri)42 private static String getUri(String uri) { 43 // Strip out the query, if it existed in the URI. See issue 379. 44 int queryIdx = uri.indexOf('?'); 45 if (queryIdx != -1) { 46 uri = uri.substring(0, queryIdx); 47 } 48 return uri; 49 } 50 51 /** 52 * Matches URIs using the pattern grammar of the Servlet API and web.xml. 53 * 54 * @author dhanji@gmail.com (Dhanji R. Prasanna) 55 */ 56 private static class ServletStyleUriPatternMatcher implements UriPatternMatcher { 57 private final String literal; 58 private final String originalPattern; 59 private final Kind patternKind; 60 61 private static enum Kind { 62 PREFIX, 63 SUFFIX, 64 LITERAL, 65 } 66 ServletStyleUriPatternMatcher(String pattern)67 public ServletStyleUriPatternMatcher(String pattern) { 68 this.originalPattern = pattern; 69 if (pattern.startsWith("*")) { 70 this.literal = pattern.substring(1); 71 this.patternKind = Kind.PREFIX; 72 } else if (pattern.endsWith("*")) { 73 this.literal = pattern.substring(0, pattern.length() - 1); 74 this.patternKind = Kind.SUFFIX; 75 } else { 76 this.literal = pattern; 77 this.patternKind = Kind.LITERAL; 78 } 79 String normalized = ServletUtils.normalizePath(literal); 80 if (patternKind == Kind.PREFIX) { 81 normalized = "*" + normalized; 82 } else if (patternKind == Kind.SUFFIX) { 83 normalized = normalized + "*"; 84 } 85 if (!pattern.equals(normalized)) { 86 throw new IllegalArgumentException( 87 "Servlet patterns cannot contain escape patterns. Registered pattern: '" 88 + pattern 89 + "' normalizes to: '" 90 + normalized 91 + "'"); 92 } 93 } 94 95 @Override matches(String uri)96 public boolean matches(String uri) { 97 if (null == uri) { 98 return false; 99 } 100 101 uri = getUri(uri); 102 if (patternKind == Kind.PREFIX) { 103 return uri.endsWith(literal); 104 } else if (patternKind == Kind.SUFFIX) { 105 return uri.startsWith(literal); 106 } 107 108 //else we need a complete match 109 return literal.equals(uri); 110 } 111 112 @Override extractPath(String path)113 public String extractPath(String path) { 114 if (patternKind == Kind.PREFIX) { 115 return null; 116 } else if (patternKind == Kind.SUFFIX) { 117 String extract = literal; 118 119 //trim the trailing '/' 120 if (extract.endsWith("/")) { 121 extract = extract.substring(0, extract.length() - 1); 122 } 123 124 return extract; 125 } 126 127 //else treat as literal 128 return path; 129 } 130 131 @Override getPatternType()132 public UriPatternType getPatternType() { 133 return UriPatternType.SERVLET; 134 } 135 136 @Override getOriginalPattern()137 public String getOriginalPattern() { 138 return originalPattern; 139 } 140 } 141 142 /** 143 * Matches URIs using a regular expression. 144 * 145 * @author dhanji@gmail.com (Dhanji R. Prasanna) 146 */ 147 private static class RegexUriPatternMatcher implements UriPatternMatcher { 148 private final Pattern pattern; 149 private final String originalPattern; 150 RegexUriPatternMatcher(String pattern)151 public RegexUriPatternMatcher(String pattern) { 152 this.originalPattern = pattern; 153 try { 154 this.pattern = Pattern.compile(pattern); 155 } catch (PatternSyntaxException pse) { 156 throw new IllegalArgumentException("Invalid regex pattern: " + pse.getMessage()); 157 } 158 } 159 160 @Override matches(String uri)161 public boolean matches(String uri) { 162 return null != uri && this.pattern.matcher(getUri(uri)).matches(); 163 } 164 165 @Override extractPath(String path)166 public String extractPath(String path) { 167 Matcher matcher = pattern.matcher(path); 168 if (matcher.matches() && matcher.groupCount() >= 1) { 169 170 // Try to capture the everything before the regex begins to match 171 // the path. This is a rough approximation to try and get parity 172 // with the servlet style mapping where the path is a capture of 173 // the URI before the wildcard. 174 int end = matcher.start(1); 175 if (end < path.length()) { 176 return path.substring(0, end); 177 } 178 } 179 return null; 180 } 181 182 @Override getPatternType()183 public UriPatternType getPatternType() { 184 return UriPatternType.REGEX; 185 } 186 187 @Override getOriginalPattern()188 public String getOriginalPattern() { 189 return originalPattern; 190 } 191 } 192 } 193