Author: markt Date: Sat Nov 3 15:26:21 2012 New Revision: 1405357 URL: http://svn.apache.org/viewvc?rev=1405357&view=rev Log: Refactor HttpParser2 not to throw exceptions on invalid input
Modified: tomcat/trunk/java/org/apache/catalina/authenticator/DigestAuthenticator.java tomcat/trunk/java/org/apache/tomcat/util/http/parser/HttpParser2.java tomcat/trunk/test/org/apache/tomcat/util/http/parser/TestHttpParser2.java Modified: tomcat/trunk/java/org/apache/catalina/authenticator/DigestAuthenticator.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/authenticator/DigestAuthenticator.java?rev=1405357&r1=1405356&r2=1405357&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/catalina/authenticator/DigestAuthenticator.java (original) +++ tomcat/trunk/java/org/apache/catalina/authenticator/DigestAuthenticator.java Sat Nov 3 15:26:21 2012 @@ -481,7 +481,11 @@ public class DigestAuthenticator extends try { directives = HttpParser2.parseAuthorizationDigest( new StringReader(authorization)); - } catch (IllegalArgumentException | IOException e) { + } catch (IOException e) { + return false; + } + + if (directives == null) { return false; } Modified: tomcat/trunk/java/org/apache/tomcat/util/http/parser/HttpParser2.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/util/http/parser/HttpParser2.java?rev=1405357&r1=1405356&r2=1405357&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/tomcat/util/http/parser/HttpParser2.java (original) +++ tomcat/trunk/java/org/apache/tomcat/util/http/parser/HttpParser2.java Sat Nov 3 15:26:21 2012 @@ -98,7 +98,8 @@ public class HttpParser2 { * * @param input The header value to parse * - * @return A map of directives and values as {@link String}s. Although the + * @return A map of directives and values as {@link String}s or + * <code>null</code> if a parsing error occurs. Although the * values returned are {@link String}s they will have been * validated to ensure that they conform to RFC 2617. * @@ -111,13 +112,20 @@ public class HttpParser2 { Map<String,String> result = new HashMap<>(); - swallowConstant(input, "Digest", false); + if (!skipConstant(input, "Digest", false)) { + return null; + } skipLws(input); // All field names are valid tokens String field = readToken(input); - while (field != null) { + if (field == null) { + return null; + } + while (!field.equals("")) { skipLws(input); - swallowConstant(input, "=", false); + if (!skipConstant(input, "=", false)) { + return null; + } skipLws(input); String value = null; Integer type = fieldTypes.get(field.toLowerCase(Locale.US)); @@ -152,34 +160,40 @@ public class HttpParser2 { "TODO i18n: Unsupported type"); } + if (value == null) { + return null; + } result.put(field, value); skipLws(input); - if (!swallowConstant(input, ",", true)) { - break; + if (!skipConstant(input, ",", true)) { + return null; } skipLws(input); field = readToken(input); + if (field == null) { + return null; + } } return result; } - private static boolean swallowConstant(StringReader input, String constant, - boolean optional) throws IOException { + /** + * @return <code>true</code> if the constant is found or if no data is + * present and EOF is allowed otherwise returns <code>false</code> + */ + private static boolean skipConstant(StringReader input, String constant, + boolean eofOk) throws IOException { int len = constant.length(); for (int i = 0; i < len; i++) { int c = input.read(); + if (i == 0 && c == -1 && eofOk) { + return true; + } if (c != constant.charAt(i)) { - if (optional) { - input.skip(-(i+1)); - return false; - } else { - throw new IllegalArgumentException( - "TODO I18N: Failed to parse input for [" + constant + - "]"); - } + return false; } } return true; @@ -195,6 +209,11 @@ public class HttpParser2 { input.skip(-1); } + /** + * @return the token if one was found, the empty string if no data was + * available to read or <code>null</code> if data other than a + * token was found + */ private static String readToken(StringReader input) throws IOException { StringBuilder result = new StringBuilder(); @@ -206,16 +225,24 @@ public class HttpParser2 { // Skip back so non-token character is available for next read input.skip(-1); - return result.toString(); + if (c != -1 && result.length() == 0) { + return null; + } else { + return result.toString(); + } } + /** + * @return the quoted string if one was found, null if data other than a + * quoted string was found or null if the end of data was reached + * before the quoted string was terminated + */ private static String readQuotedString(StringReader input) throws IOException { int c = input.read(); if (c != '"') { - throw new IllegalArgumentException( - "TODO i18n: Quoted string must start with a quote"); + return null; } StringBuilder result = new StringBuilder(); @@ -223,8 +250,7 @@ public class HttpParser2 { c = input.read(); while (c != '"') { if (c == -1) { - throw new IllegalArgumentException( - "TODO i18n: Quoted string must end with a quote"); + return null; } else if (c == '\\') { c = input.read(); result.append(c); @@ -249,9 +275,12 @@ public class HttpParser2 { } } - /* + /** * Parses lower case hex but permits upper case hex to be used (converting * it to lower case before returning). + * + * @return the lower case hex if present or <code>null</code> if data other + * than lower case hex was found */ private static String readLhex(StringReader input) throws IOException { StringBuilder result = new StringBuilder(); @@ -264,15 +293,19 @@ public class HttpParser2 { // Skip back so non-hex character is available for next read input.skip(-1); - return result.toString().toLowerCase(); + if (result.length() == 0) { + return null; + } else { + return result.toString().toLowerCase(); + } } private static String readQuotedLhex(StringReader input) throws IOException { - swallowConstant(input, "\"", false); + skipConstant(input, "\"", false); String result = readLhex(input); - swallowConstant(input, "\"", false); + skipConstant(input, "\"", false); return result; } Modified: tomcat/trunk/test/org/apache/tomcat/util/http/parser/TestHttpParser2.java URL: http://svn.apache.org/viewvc/tomcat/trunk/test/org/apache/tomcat/util/http/parser/TestHttpParser2.java?rev=1405357&r1=1405356&r2=1405357&view=diff ============================================================================== --- tomcat/trunk/test/org/apache/tomcat/util/http/parser/TestHttpParser2.java (original) +++ tomcat/trunk/test/org/apache/tomcat/util/http/parser/TestHttpParser2.java Sat Nov 3 15:26:21 2012 @@ -125,31 +125,34 @@ public class TestHttpParser2 { Assert.assertEquals("00000001", result.get("nc")); } - @Test(expected=IllegalArgumentException.class) + @Test public void testUnclosedQuotedString1() throws Exception { String header = "Digest username=\"test"; StringReader input = new StringReader(header); - HttpParser2.parseAuthorizationDigest(input); + Map<String,String> result = HttpParser2.parseAuthorizationDigest(input); + Assert.assertNull(result); } - @Test(expected=IllegalArgumentException.class) + @Test public void testUnclosedQuotedString2() throws Exception { String header = "Digest username=\"test\\"; StringReader input = new StringReader(header); - HttpParser2.parseAuthorizationDigest(input); + Map<String,String> result = HttpParser2.parseAuthorizationDigest(input); + Assert.assertNull(result); } - @Test(expected=IllegalArgumentException.class) + @Test public void testNonTokenDirective() throws Exception { String header = "Digest user{name=\"test\""; StringReader input = new StringReader(header); - HttpParser2.parseAuthorizationDigest(input); + Map<String,String> result = HttpParser2.parseAuthorizationDigest(input); + Assert.assertNull(result); } } --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org