You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by ma...@apache.org on 2014/09/02 15:40:44 UTC
svn commit: r1621982 -
/tomcat/trunk/java/org/apache/tomcat/util/http/parser/Cookie.java
Author: markt
Date: Tue Sep 2 13:40:43 2014
New Revision: 1621982
URL: http://svn.apache.org/r1621982
Log:
Initial implementation of RFC2109 parser
Modified:
tomcat/trunk/java/org/apache/tomcat/util/http/parser/Cookie.java
Modified: tomcat/trunk/java/org/apache/tomcat/util/http/parser/Cookie.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/util/http/parser/Cookie.java?rev=1621982&r1=1621981&r2=1621982&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/tomcat/util/http/parser/Cookie.java (original)
+++ tomcat/trunk/java/org/apache/tomcat/util/http/parser/Cookie.java Tue Sep 2 13:40:43 2014
@@ -47,12 +47,16 @@ public class Cookie {
StringManager.getManager("org.apache.tomcat.util.http.parser");
private static final boolean isCookieOctet[] = new boolean[256];
+ private static final boolean isText[] = new boolean[256];
private static final byte[] VERSION_BYTES = "$Version".getBytes(StandardCharsets.ISO_8859_1);
+ private static final byte[] PATH_BYTES = "$Path".getBytes(StandardCharsets.ISO_8859_1);
+ private static final byte[] DOMAIN_BYTES = "$Domain".getBytes(StandardCharsets.ISO_8859_1);
private static final byte[] EMPTY_BYTES = new byte[0];
private static final byte TAB_BYTE = (byte) 0x09;
private static final byte SPACE_BYTE = (byte) 0x20;
private static final byte QUOTE_BYTE = (byte) 0x22;
private static final byte COMMA_BYTE = (byte) 0x2C;
+ private static final byte FORWARDSLASH_BYTE = (byte) 0x2F;
private static final byte SEMICOLON_BYTE = (byte) 0x3B;
private static final byte EQUALS_BYTE = (byte) 0x3D;
private static final byte SLASH_BYTE = (byte) 0x5C;
@@ -70,6 +74,13 @@ public class Cookie {
isCookieOctet[i] = true;
}
}
+ for (int i = 0; i < 256; i++) {
+ if (i < 0x21 || i == DEL_BYTE) {
+ isText[i] = false;
+ } else {
+ isText[i] = true;
+ }
+ }
}
@@ -118,7 +129,11 @@ public class Cookie {
if (value != null && value.remaining() == 1) {
if (value.get() == (byte) 49) {
// $Version=1 -> RFC2109
- parseCookieRfc2109(bb, serverCookies);
+ skipLWS(bb);
+ byte b = bb.get();
+ if (b == SEMICOLON_BYTE || b == COMMA_BYTE) {
+ parseCookieRfc2109(bb, serverCookies);
+ }
return;
} else {
// Unrecognised version.
@@ -134,6 +149,37 @@ public class Cookie {
}
+ public static String unescapeCookieValueRfc2109(String input) {
+ if (input == null || input.length() < 2) {
+ return input;
+ }
+ if (input.charAt(0) != '"' && input.charAt(input.length() - 1) != '"') {
+ return input;
+ }
+
+ StringBuilder sb = new StringBuilder(input.length());
+ char[] chars = input.toCharArray();
+ boolean escaped = false;
+
+ for (int i = 1; i < input.length() - 1; i++) {
+ if (chars[i] == '\\') {
+ escaped = true;
+ } else if (escaped) {
+ escaped = false;
+ if (chars[i] < 128) {
+ sb.append(chars[i]);
+ } else {
+ sb.append('\\');
+ sb.append(chars[i]);
+ }
+ } else {
+ sb.append(chars[i]);
+ }
+ }
+ return sb.toString();
+ }
+
+
private static void parseCookieRfc6265(ByteBuffer bb, ServerCookies serverCookies) {
boolean moreToProcess = true;
@@ -181,14 +227,147 @@ public class Cookie {
sc.getValue().setBytes(value.array(), value.position(), value.remaining());
}
}
-
}
}
private static void parseCookieRfc2109(ByteBuffer bb, ServerCookies serverCookies) {
- System.out.println("Parse with RFC 2109");
- // TODO
+
+ boolean moreToProcess = true;
+
+ while (moreToProcess) {
+ skipLWS(bb);
+
+ boolean parseAttributes = true;
+
+ ByteBuffer name = readToken(bb);
+ ByteBuffer value = null;
+ ByteBuffer path = null;
+ ByteBuffer domain = null;
+
+ skipLWS(bb);
+
+ SkipResult skipResult = skipByte(bb, EQUALS_BYTE);
+ if (skipResult == SkipResult.FOUND) {
+ skipLWS(bb);
+ value = readCookieValueRfc2109(bb, false);
+ if (value == null) {
+ logInvalidHeader(bb);
+ // Invalid cookie value. Skip to the next semi-colon
+ skipUntilSemiColon(bb);
+ continue;
+ }
+ skipLWS(bb);
+ }
+
+ skipResult = skipByte(bb, COMMA_BYTE);
+ if (skipResult == SkipResult.FOUND) {
+ parseAttributes = false;
+ }
+ skipResult = skipByte(bb, SEMICOLON_BYTE);
+ if (skipResult == SkipResult.EOF) {
+ parseAttributes = false;
+ moreToProcess = false;
+ } else if (skipResult == SkipResult.NOT_FOUND) {
+ logInvalidHeader(bb);
+ // Invalid cookie value. Skip to the next semi-colon
+ // TODO Could be a comma
+ skipUntilSemiColon(bb);
+ continue;
+ }
+
+ if (parseAttributes) {
+ skipResult = skipBytes(bb, PATH_BYTES);
+ if (skipResult == SkipResult.FOUND) {
+ skipLWS(bb);
+ skipResult = skipByte(bb, EQUALS_BYTE);
+ if (skipResult != SkipResult.FOUND) {
+ logInvalidHeader(bb);
+ // Invalid cookie value. Skip to the next semi-colon
+ // TODO Could be a comma
+ skipUntilSemiColon(bb);
+ continue;
+ }
+ path = readCookieValueRfc2109(bb, true);
+ if (path == null) {
+ logInvalidHeader(bb);
+ // Invalid cookie value. Skip to the next semi-colon
+ // TODO Could be a comma
+ skipUntilSemiColon(bb);
+ continue;
+ }
+ skipLWS(bb);
+
+ skipResult = skipByte(bb, COMMA_BYTE);
+ if (skipResult == SkipResult.FOUND) {
+ parseAttributes = false;
+ }
+ skipResult = skipByte(bb, SEMICOLON_BYTE);
+ if (skipResult == SkipResult.EOF) {
+ parseAttributes = false;
+ moreToProcess = false;
+ } else if (skipResult == SkipResult.NOT_FOUND) {
+ logInvalidHeader(bb);
+ // Invalid cookie value. Skip to the next semi-colon
+ // TODO Could be a comma
+ skipUntilSemiColon(bb);
+ continue;
+ }
+ }
+ }
+
+ if (parseAttributes) {
+ skipResult = skipBytes(bb, DOMAIN_BYTES);
+ if (skipResult == SkipResult.FOUND) {
+ skipLWS(bb);
+ skipResult = skipByte(bb, EQUALS_BYTE);
+ if (skipResult != SkipResult.FOUND) {
+ logInvalidHeader(bb);
+ // Invalid cookie value. Skip to the next semi-colon
+ // TODO Could be a comma
+ skipUntilSemiColon(bb);
+ continue;
+ }
+ domain = readCookieValueRfc2109(bb, false);
+ if (domain == null) {
+ logInvalidHeader(bb);
+ // Invalid cookie value. Skip to the next semi-colon
+ // TODO Could be a comma
+ skipUntilSemiColon(bb);
+ continue;
+ }
+
+ skipResult = skipByte(bb, COMMA_BYTE);
+ if (skipResult == SkipResult.FOUND) {
+ parseAttributes = false;
+ }
+ skipResult = skipByte(bb, SEMICOLON_BYTE);
+ if (skipResult == SkipResult.EOF) {
+ parseAttributes = false;
+ moreToProcess = false;
+ } else if (skipResult == SkipResult.NOT_FOUND) {
+ logInvalidHeader(bb);
+ // Invalid cookie value. Skip to the next semi-colon
+ // TODO Could be a comma
+ skipUntilSemiColon(bb);
+ continue;
+ }
+ }
+ }
+
+ if (name.hasRemaining() && value != null && value.hasRemaining()) {
+ ServerCookie sc = serverCookies.addCookie();
+ sc.setVersion(1);
+ sc.getName().setBytes(name.array(), name.position(), name.remaining());
+ sc.getValue().setBytes(value.array(), value.position(), value.remaining());
+ if (domain != null) {
+ sc.getDomain().setBytes(domain.array(), domain.position(), domain.remaining());
+ }
+ if (path != null) {
+ sc.getPath().setBytes(path.array(), path.position(), path.remaining());
+ }
+ }
+ }
}
@@ -315,6 +494,23 @@ public class Cookie {
}
+ private static ByteBuffer readCookieValueRfc2109(ByteBuffer bb, boolean allowForwardSlash) {
+ if (!bb.hasRemaining()) {
+ return null;
+ }
+
+ if (bb.peek() == QUOTE_BYTE) {
+ return readQuotedString(bb);
+ } else {
+ if (allowForwardSlash) {
+ return readTokenAllowForwardSlash(bb);
+ } else {
+ return readToken(bb);
+ }
+ }
+ }
+
+
private static ByteBuffer readToken(ByteBuffer bb) {
final int start = bb.position();
int end = bb.limit();
@@ -330,6 +526,48 @@ public class Cookie {
}
+ private static ByteBuffer readTokenAllowForwardSlash(ByteBuffer bb) {
+ final int start = bb.position();
+ int end = bb.limit();
+ while (bb.hasRemaining()) {
+ byte b = bb.get();
+ if (b != FORWARDSLASH_BYTE && !HttpParser.isToken(b)) {
+ end = bb.position() - 1;
+ bb.position(end);
+ break;
+ }
+ }
+
+ return new ByteBuffer(bb.bytes, start, end - start);
+ }
+
+
+ private static ByteBuffer readQuotedString(ByteBuffer bb) {
+ int start = bb.position();
+
+ // Read the opening quote
+ bb.get();
+ boolean escaped = false;
+ while (bb.hasRemaining()) {
+ byte b = bb.get();
+ if (b == SLASH_BYTE) {
+ // Escaping another character
+ escaped = true;
+ } else if (escaped && b > (byte) -1) {
+ escaped = false;
+ } else if (b == QUOTE_BYTE) {
+ return new ByteBuffer(bb.bytes, start, bb.position() - start);
+ } else if (isText[b & 0xFF]) {
+ escaped = false;
+ } else {
+ return null;
+ }
+ }
+
+ return null;
+ }
+
+
private static void logInvalidHeader(ByteBuffer bb) {
UserDataHelper.Mode logMode = invalidCookieLog.getNextMode();
if (logMode != null) {
@@ -415,6 +653,10 @@ public class Cookie {
return bytes[position++];
}
+ public byte peek() {
+ return bytes[position];
+ }
+
public void rewind() {
position--;
}
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org