Author: markt
Date: Sat Mar 16 20:02:37 2013
New Revision: 1457299
URL: http://svn.apache.org/r1457299
Log:
Fix https://issues.apache.org/bugzilla/show_bug.cgi?id=54707
Relax parsing of LHEX and <">LHEX<"> to allow either whenever one is expected
Additionally:
- improve comments
- move back one char when parsing in a consistent manner
- fix edge case bug if first character of quoted token was not valid (it was
incorrectly accepted)
Modified:
tomcat/trunk/java/org/apache/tomcat/util/http/parser/HttpParser.java
Modified: tomcat/trunk/java/org/apache/tomcat/util/http/parser/HttpParser.java
URL:
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/util/http/parser/HttpParser.java?rev=1457299&r1=1457298&r2=1457299&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/tomcat/util/http/parser/HttpParser.java
(original)
+++ tomcat/trunk/java/org/apache/tomcat/util/http/parser/HttpParser.java Sat
Mar 16 20:02:37 2013
@@ -48,8 +48,7 @@ public class HttpParser {
private static final Integer FIELD_TYPE_QUOTED_STRING = Integer.valueOf(1);
private static final Integer FIELD_TYPE_TOKEN_OR_QUOTED_STRING =
Integer.valueOf(2);
private static final Integer FIELD_TYPE_LHEX = Integer.valueOf(3);
- private static final Integer FIELD_TYPE_QUOTED_LHEX = Integer.valueOf(4);
- private static final Integer FIELD_TYPE_QUOTED_TOKEN = Integer.valueOf(5);
+ private static final Integer FIELD_TYPE_QUOTED_TOKEN = Integer.valueOf(4);
private static final Map<String,Integer> fieldTypes = new HashMap<>();
@@ -58,16 +57,23 @@ public class HttpParser {
private static final boolean isHex[] = new boolean[128];
static {
- // Digest field types
+ // Digest field types.
+ // Note: These are more relaxed than RFC2617. This adheres to the
+ // recommendation of RFC2616 that servers are tolerant of buggy
+ // clients when they can be so without ambiguity.
fieldTypes.put("username", FIELD_TYPE_QUOTED_STRING);
fieldTypes.put("realm", FIELD_TYPE_QUOTED_STRING);
fieldTypes.put("nonce", FIELD_TYPE_QUOTED_STRING);
fieldTypes.put("digest-uri", FIELD_TYPE_QUOTED_STRING);
- fieldTypes.put("response", FIELD_TYPE_QUOTED_LHEX);
+ // RFC2617 says response is <">32LHEX<">. 32LHEX will also be accepted
+ fieldTypes.put("response", FIELD_TYPE_LHEX);
+ // RFC2617 says algorithm is token. <">token<"> will also be accepted
fieldTypes.put("algorithm", FIELD_TYPE_QUOTED_TOKEN);
fieldTypes.put("cnonce", FIELD_TYPE_QUOTED_STRING);
fieldTypes.put("opaque", FIELD_TYPE_QUOTED_STRING);
+ // RFC2617 says qop is token. <">token<"> will also be accepted
fieldTypes.put("qop", FIELD_TYPE_QUOTED_TOKEN);
+ // RFC2617 says nc is 8LHEX. <">8LHEX<"> will also be accepted
fieldTypes.put("nc", FIELD_TYPE_LHEX);
// Setup the flag arrays
@@ -144,14 +150,10 @@ public class HttpParser {
value = readTokenOrQuotedString(input, false);
break;
case 3:
- // FIELD_TYPE_LHEX
+ // FIELD_TYPE_QUOTED_LHEX
value = readLhex(input);
break;
case 4:
- // FIELD_TYPE_QUOTED_LHEX
- value = readQuotedLhex(input);
- break;
- case 5:
// FIELD_TYPE_QUOTED_TOKEN
value = readQuotedToken(input);
break;
@@ -263,6 +265,8 @@ public class HttpParser {
int len = constant.length();
int c = input.read();
+
+ // Skip lws
while (c == 32 || c == 9) {
c = input.read();
}
@@ -359,9 +363,10 @@ public class HttpParser {
private static String readTokenOrQuotedString(StringReader input,
boolean returnQuoted) throws IOException {
- input.mark(1);
+
int c = input.read();
- input.reset();
+ // Skip back so first character is available to be read again
+ input.skip(-1);
if (c == '"') {
return readQuotedString(input, returnQuoted);
@@ -371,9 +376,12 @@ public class HttpParser {
}
/**
+ * Token can be read unambiguously with or without surrounding quotes so
+ * this parsing method for token permits optional surrounding double
quotes.
* This is not defined in any RFC. It is a special case to handle data from
- * buggy clients (known buggy clients include Microsoft IE 8 & 9, Apple
- * Safari for OSX and iOS) that add quotes to values that should be tokens.
+ * buggy clients (known buggy clients for DIGEST auth include Microsoft IE
8
+ * & 9, Apple Safari for OSX and iOS) that add quotes to values that should
+ * be tokens.
*
* @return the token if one was found, null if data other than a token or
* quoted token was found or null if the end of data was reached
@@ -394,7 +402,7 @@ public class HttpParser {
if (c == '"') {
quoted = true;
- } else if (c == -1) {
+ } else if (c == -1 || !isToken(c)) {
return null;
} else {
result.append((char) c);
@@ -423,14 +431,19 @@ public class HttpParser {
}
/**
- * Parses lower case hex but permits upper case hex to be used (converting
- * it to lower case before returning).
+ * LHEX can be read unambiguously with or without surrounding quotes so
this
+ * parsing method for LHEX permits optional surrounding double quotes. Some
+ * buggy clients (libwww-perl for DIGEST auth) are known to send quoted
LHEX
+ * when the specification requires just LHEX.
*
- * @return the lower case hex if present or <code>null</code> if data other
- * than lower case hex was found
+ * @return the sequence of LHEX (minus any surrounding quotes) if any was
+ * found, or <code>null</code> if data other LHEX was found
*/
- private static String readLhex(StringReader input) throws IOException {
+ private static String readLhex(StringReader input)
+ throws IOException {
+
StringBuilder result = new StringBuilder();
+ boolean quoted = false;
int c = input.read();
@@ -439,32 +452,34 @@ public class HttpParser {
c = input.read();
}
+ if (c == '"') {
+ quoted = true;
+ } else if (c == -1 || !isHex(c)) {
+ return null;
+ } else {
+ result.append((char) c);
+ }
+ c = input.read();
+
while (c != -1 && isHex(c)) {
result.append((char) c);
c = input.read();
}
- // Skip back so non-hex character is available for next read
- input.skip(-1);
- if (result.length() == 0) {
- return null;
+ if (quoted) {
+ if (c != '"') {
+ return null;
+ }
} else {
- return result.toString().toLowerCase(Locale.US);
+ // Skip back so non-token character is available for next read
+ input.skip(-1);
}
- }
- private static String readQuotedLhex(StringReader input)
- throws IOException {
-
- if (skipConstant(input, "\"") != SkipConstantResult.FOUND) {
- return null;
- }
- String result = readLhex(input);
- if (skipConstant(input, "\"") == SkipConstantResult.NOT_FOUND) {
+ if (c != -1 && result.length() == 0) {
return null;
+ } else {
+ return result.toString().toLowerCase(Locale.US);
}
-
- return result;
}
private static enum SkipConstantResult {
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]