]> WPIA git - gigi.git/blobdiff - lib/jetty/org/eclipse/jetty/server/CookieCutter.java
Importing upstream Jetty jetty-9.2.1.v20140609
[gigi.git] / lib / jetty / org / eclipse / jetty / server / CookieCutter.java
diff --git a/lib/jetty/org/eclipse/jetty/server/CookieCutter.java b/lib/jetty/org/eclipse/jetty/server/CookieCutter.java
new file mode 100644 (file)
index 0000000..703f804
--- /dev/null
@@ -0,0 +1,328 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+package org.eclipse.jetty.server;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Locale;
+
+import javax.servlet.http.Cookie;
+
+import org.eclipse.jetty.util.QuotedStringTokenizer;
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.log.Logger;
+
+
+/* ------------------------------------------------------------ */
+/** Cookie parser
+ * <p>Optimized stateful cookie parser.  Cookies fields are added with the
+ * {@link #addCookieField(String)} method and parsed on the next subsequent
+ * call to {@link #getCookies()}.
+ * If the added fields are identical to those last added (as strings), then the 
+ * cookies are not re parsed.
+ * 
+ *
+ */
+public class CookieCutter
+{
+    private static final Logger LOG = Log.getLogger(CookieCutter.class);
+
+    private Cookie[] _cookies;
+    private Cookie[] _lastCookies;
+    private final List<String> _fieldList = new ArrayList<>();
+    int _fields;
+    
+    public CookieCutter()
+    {  
+    }
+    
+    public Cookie[] getCookies()
+    {
+        if (_cookies!=null)
+            return _cookies;
+        
+        if (_lastCookies!=null && _fields==_fieldList.size())
+            _cookies=_lastCookies;
+        else
+            parseFields();
+        _lastCookies=_cookies;
+        return _cookies;
+    }
+    
+    public void setCookies(Cookie[] cookies)
+    {
+        _cookies=cookies;
+        _lastCookies=null;
+        _fieldList.clear();
+        _fields=0;
+    }
+    
+    public void reset()
+    {
+        _cookies=null;
+        _fields=0;
+    }
+    
+    public void addCookieField(String f)
+    {
+        if (f==null)
+            return;
+        f=f.trim();
+        if (f.length()==0)
+            return;
+            
+        if (_fieldList.size()>_fields)
+        {
+            if (f.equals(_fieldList.get(_fields)))
+            {
+                _fields++;
+                return;
+            }
+            
+            while (_fieldList.size()>_fields)
+                _fieldList.remove(_fields);
+        }
+        _cookies=null;
+        _lastCookies=null;
+        _fieldList.add(_fields++,f);
+    }
+    
+    
+    protected void parseFields()
+    {
+        _lastCookies=null;
+        _cookies=null;
+        
+        List<Cookie> cookies = new ArrayList<>();
+
+        int version = 0;
+
+        // delete excess fields
+        while (_fieldList.size()>_fields)
+            _fieldList.remove(_fields);
+        
+        // For each cookie field
+        for (String hdr : _fieldList)
+        {
+            // Parse the header
+            String name = null;
+            String value = null;
+
+            Cookie cookie = null;
+
+            boolean invalue=false;
+            boolean quoted=false;
+            boolean escaped=false;
+            int tokenstart=-1;
+            int tokenend=-1;
+            for (int i = 0, length = hdr.length(), last=length-1; i < length; i++)
+            {
+                char c = hdr.charAt(i);
+                
+                // Handle quoted values for name or value
+                if (quoted)
+                {
+                    if (escaped)
+                    {
+                        escaped=false;
+                        continue;
+                    }
+                    
+                    switch (c)
+                    {
+                        case '"':
+                            tokenend=i;
+                            quoted=false;
+
+                            // handle quote as last character specially
+                            if (i==last)
+                            {
+                                if (invalue)
+                                    value = hdr.substring(tokenstart, tokenend+1);
+                                else
+                                {
+                                    name = hdr.substring(tokenstart, tokenend+1);
+                                    value = "";
+                                }
+                            }
+                            break;
+                            
+                        case '\\':
+                            escaped=true;
+                            continue;
+                        default:
+                            continue;
+                    }
+                }
+                else
+                {
+                    // Handle name and value state machines
+                    if (invalue)
+                    {
+                        // parse the value
+                        switch (c)
+                        {
+                            case ' ':
+                            case '\t':
+                                continue;
+                                
+                            case '"':
+                                if (tokenstart<0)
+                                {
+                                    quoted=true;
+                                    tokenstart=i;
+                                }
+                                tokenend=i;
+                                if (i==last)
+                                {
+                                    value = hdr.substring(tokenstart, tokenend+1);
+                                    break;
+                                }
+                                continue;
+
+                            case ';':
+                                if (tokenstart>=0)
+                                    value = hdr.substring(tokenstart, tokenend+1);
+                                else
+                                    value="";
+                                tokenstart = -1;
+                                invalue=false;
+                                break;
+                                
+                            default:
+                                if (tokenstart<0)
+                                    tokenstart=i;
+                                tokenend=i;
+                                if (i==last)
+                                {
+                                    value = hdr.substring(tokenstart, tokenend+1);
+                                    break;
+                                }
+                                continue;
+                        }
+                    }
+                    else
+                    {
+                        // parse the name
+                        switch (c)
+                        {
+                            case ' ':
+                            case '\t':
+                                continue;
+                                
+                            case '"':
+                                if (tokenstart<0)
+                                {
+                                    quoted=true;
+                                    tokenstart=i;
+                                }
+                                tokenend=i;
+                                if (i==last)
+                                {
+                                    name = hdr.substring(tokenstart, tokenend+1);
+                                    value = "";
+                                    break;
+                                }
+                                continue;
+
+                            case ';':
+                                if (tokenstart>=0)
+                                {
+                                    name = hdr.substring(tokenstart, tokenend+1);
+                                    value = "";
+                                }
+                                tokenstart = -1;
+                                break;
+
+                            case '=':
+                                if (tokenstart>=0)
+                                    name = hdr.substring(tokenstart, tokenend+1);
+                                tokenstart = -1;
+                                invalue=true;
+                                continue;
+                                
+                            default:
+                                if (tokenstart<0)
+                                    tokenstart=i;
+                                tokenend=i;
+                                if (i==last)
+                                {
+                                    name = hdr.substring(tokenstart, tokenend+1);
+                                    value = "";
+                                    break;
+                                }
+                                continue;
+                        }
+                    }
+                }
+
+                // If after processing the current character we have a value and a name, then it is a cookie
+                if (value!=null && name!=null)
+                {
+                    name=QuotedStringTokenizer.unquoteOnly(name);
+                    value=QuotedStringTokenizer.unquoteOnly(value);
+                    
+                    try
+                    {
+                        if (name.startsWith("$"))
+                        {
+                            String lowercaseName = name.toLowerCase(Locale.ENGLISH);
+                            if ("$path".equals(lowercaseName))
+                            {
+                                if (cookie!=null)
+                                    cookie.setPath(value);
+                            }
+                            else if ("$domain".equals(lowercaseName))
+                            {
+                                if (cookie!=null)
+                                    cookie.setDomain(value);
+                            }
+                            else if ("$port".equals(lowercaseName))
+                            {
+                                if (cookie!=null)
+                                    cookie.setComment("$port="+value);
+                            }
+                            else if ("$version".equals(lowercaseName))
+                            {
+                                version = Integer.parseInt(value);
+                            }
+                        }
+                        else
+                        {
+                            cookie = new Cookie(name, value);
+                            if (version > 0)
+                                cookie.setVersion(version);
+                            cookies.add(cookie);
+                        }
+                    }
+                    catch (Exception e)
+                    {
+                        LOG.debug(e);
+                    }
+
+                    name = null;
+                    value = null;
+                }
+            }
+        }
+
+        _cookies = (Cookie[]) cookies.toArray(new Cookie[cookies.size()]);
+        _lastCookies=_cookies;
+    }
+    
+}