Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Removed '?' and '#' as valid path segment characters in UrlPattern to…

… conform better with IETF RFC 3986, section 3.3-path. Made '{format}' a first-class element for matching URL route patterns (by using 'format' instead of a regex to match).
  • Loading branch information...
commit 27938a8083a42cb4c2b30c0f01a88d856961432d 1 parent 32a3e1f
@tfredrich tfredrich authored
View
24 src/java/com/strategicgains/restexpress/url/UrlPattern.java
@@ -40,7 +40,10 @@
* <li>/api/{version}/search/users/{userid}</li>
* </ul>
*
- * RestExpress accepts URIs with the following BNF values taken from the URI Generic Syntax IETF RFC 3986 as follows:
+ * RestExpress parses URI paths which is described in the URI Generic Syntax IETF RFC 3986 specifcation,
+ * section 3.3 (http://tools.ietf.org/html/rfc3986#section-3.3). RestExpress parses paths into segments
+ * separated by slashes ("/"), the segments of which are composed of unreserved, percent encoded,
+ * sub-delimiters, colon (":") or asperand ("@"), each of which are defined below (from the spec):
* <p/>
* pct-encoded = "%" HEXDIG HEXDIG
* <p/>
@@ -49,6 +52,9 @@
* gen-delims = ":" / "/" / "?" / "#" / "[" / "]" / "@"</br>
* sub-delims = "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / ";" / "=" *
* <p/>
+ * In other words, RestExpress accepts path segments containing: [A-Z] [a-z] [0-9] % - . _ ~ ! $ & ' ( ) * + , ; = : @
+ * <p/>
+ * RestExpress also accepts square brackets ('[' and ']'), but this is deprecated and not recommended.
*
* @author toddf
* @since Apr 28, 2010
@@ -61,15 +67,15 @@
// Finds parameters in the URL pattern string.
private static final String URL_PARAM_REGEX = "\\{(\\w*?)\\}";
-
+
// Replaces parameter names in the URL pattern string to match parameters in URLs.
- private static final String URL_PARAM_MATCH_REGEX = "\\([%\\\\w-.\\\\~!\\$&'\\\\(\\\\)\\\\*\\\\+,;=:\\\\?#\\\\[\\\\]@]+?\\)";
-
+ private static final String URL_PARAM_MATCH_REGEX = "\\([%\\\\w-.\\\\~!\\$&'\\\\(\\\\)\\\\*\\\\+,;=:\\\\[\\\\]@]+?\\)";
+
// Pattern to match URL pattern parameter names.
private static final Pattern URL_PARAM_PATTERN = Pattern.compile(URL_PARAM_REGEX);
- // Finds the format portion of the URL pattern string.
- private static final String URL_FORMAT_REGEX = "(?:\\.\\{(\\w+)\\})$";
+ // Finds the 'format' portion of the URL pattern string.
+ private static final String URL_FORMAT_REGEX = "(?:\\.\\{format\\})$";
// Replaces the format parameter name in the URL pattern string to match the format specifier in URLs. Appended to the end of the regex string
// when a URL pattern contains a format parameter.
@@ -184,9 +190,7 @@ public void compile()
acquireParameterNames();
String parsedPattern = getUrlPattern().replaceFirst(URL_FORMAT_REGEX, URL_FORMAT_MATCH_REGEX);
parsedPattern = parsedPattern.replaceAll(URL_PARAM_REGEX, URL_PARAM_MATCH_REGEX);
- @SuppressWarnings("unused")
- String completePattern = parsedPattern + URL_QUERY_STRING_REGEX;
- compiledUrl = Pattern.compile(parsedPattern + URL_QUERY_STRING_REGEX);
+ this.compiledUrl = Pattern.compile(parsedPattern + URL_QUERY_STRING_REGEX);
}
/**
@@ -204,7 +208,7 @@ private void acquireParameterNames()
}
/**
- * Extracts parameter values from a Matcher instance.
+ * Extracts parameter values from a Matcher instance using the regular expression groupings.
*
* @param matcher
* @return a Map containing parameter values indexed by their corresponding parameter name.
View
13 test/java/com/strategicgains/restexpress/url/UrlPatternTest.java
@@ -51,6 +51,8 @@ public void shouldMatchUrlWithFormat()
assertTrue(pFormat.matches("/xxx/toddf/yyy/jose.%20json"));
assertTrue(pFormat.matches("/xxx/toddf/yyy/jose.%json"));
assertTrue(pFormat.matches("/xxx/$-_@&+-[]/yyy/!*'(),.json"));
+ assertTrue(pFormat.matches("/xxx/toddf/yyy/.json"));
+ assertTrue(pFormat.matches("/xxx/.toddf/yyy/.json?a=foo"));
}
@Test
@@ -63,11 +65,14 @@ public void shouldMatchUrlWithoutFormat()
assertTrue(p.matches("/xxx/12345/yyy/67890"));
assertTrue(p.matches("/xxx/toddf/yyy/joez"));
assertTrue(p.matches("/xxx/toddf/yyy/joez?x=y&a=b"));
+ assertTrue(p.matches("/xxx/toddf/yyy/.json"));
+ assertTrue(p.matches("/xxx/.toddf/yyy/.json"));
}
@Test
public void shouldNotMatchUrlWithFormat()
{
+ assertFalse(pFormat.matches("/xxx/toddf/yyy/?a=foo"));
assertFalse(pFormat.matches("/xxx/toddf/yyy/joez/"));
assertFalse(pFormat.matches("/xxx/todd.fredrich/yyy/joez/"));
assertFalse(pFormat.matches("/aaa/toddf/yyy/joez.json"));
@@ -99,10 +104,10 @@ public void shouldParseParametersWithFormat()
@Test
public void shouldParseSpecialParametersWithFormat()
{
- UrlMatch match = pFormat.match("/xxx/~?#,;=$-_@&+-[toddf]:12345/yyy/!*'(fredt),.json");
+ UrlMatch match = pFormat.match("/xxx/~,;=$-_@&+-[toddf]:12345/yyy/!*'(fredt),.json");
assertNotNull(match);
assertEquals("json", match.get("format"));
- assertEquals("~?#,;=$-_@&+-[toddf]:12345", match.get("a_id"));
+ assertEquals("~,;=$-_@&+-[toddf]:12345", match.get("a_id"));
assertEquals("!*'(fredt),", match.get("b_id"));
}
@@ -119,10 +124,10 @@ public void shouldParseParametersWithoutFormat()
@Test
public void shouldParseSpecialParametersWithoutFormat()
{
- UrlMatch match = p.match("/xxx/~?#,;=$-_@&+-[toddf]:12345/yyy/!*'(fredt),");
+ UrlMatch match = p.match("/xxx/~,;=$-_@&+-[toddf]:12345/yyy/!*'(fredt),");
assertNotNull(match);
assertNull(match.get("format"));
- assertEquals("~?#,;=$-_@&+-[toddf]:12345", match.get("a_id"));
+ assertEquals("~,;=$-_@&+-[toddf]:12345", match.get("a_id"));
assertEquals("!*'(fredt),", match.get("b_id"));
}
Please sign in to comment.
Something went wrong with that request. Please try again.