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