Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
  /*
   *  Licensed to the Apache Software Foundation (ASF) under one or more
   *  contributor license agreements.  See the NOTICE file distributed with
   *  this work for additional information regarding copyright ownership.
   *  The ASF licenses this file to You under the Apache License, Version 2.0
   *  (the "License"); you may not use this file except in compliance with
   *  the License.  You may obtain a copy of the License at
   *
   *      http://www.apache.org/licenses/LICENSE-2.0
  *
  *  Unless required by applicable law or agreed to in writing, software
  *  distributed under the License is distributed on an "AS IS" BASIS,
  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  *  See the License for the specific language governing permissions and
  *  limitations under the License.
  */
 
 package org.apache.tomcat.util.http;
 
 
A collection of cookies - reusable and tuned for server side performance. Based on RFC2965 ( and 2109 ) This class is not synchronized.

Author(s):
Costin Manolache
kevin seguin
 
 public final class Cookies { // extends MultiMap {
 
     // expected average number of cookies per request
     public static final int INITIAL_SIZE=4; 
     int cookieCount=0;
     boolean unprocessed=true;
 
     MimeHeaders headers;

    
Construct a new cookie collection, that will extract the information from headers.

Parameters:
headers Cookies are lazy-evaluated and will extract the information from the provided headers.
 
     public Cookies(MimeHeaders headers) {
         this.=headers;
     }

    
Recycle.
 
     public void recycle() {
             forint i=0; ii++ ) {
             if[i]!=null )
                 [i].recycle();
         }
         =0;
         =true;
     }

    
EXPENSIVE!!! only for debugging.
 
     @Override
     public String toString() {
         StringWriter sw = new StringWriter();
         PrintWriter pw = new PrintWriter(sw);
         pw.println("=== Cookies ===");
         int count = getCookieCount();
         for (int i = 0; i < count; ++i) {
             pw.println(getCookie(i).toString());
         }
         return sw.toString();
     }
 
     // -------------------- Indexed access --------------------
     
     public ServerCookie getCookieint idx ) {
         if ) {
             getCookieCount(); // will also update the cookies
         }
         return [idx];
     }
 
     public int getCookieCount() {
         if ) {
             =false;
             processCookies();
         }
         return ;
     }
    // -------------------- Adding cookies --------------------

    
Register a new, initialized cookie. Cookies are recycled, and most of the time an existing ServerCookie object is returned. The caller can set the name/value and attributes for the cookie
    private ServerCookie addCookie() {
        if >= .  ) {
            ServerCookie scookiesTmp[]=new ServerCookie[2*];
            System.arraycopy, 0, scookiesTmp, 0, );
            =scookiesTmp;
        }
        
        ServerCookie c = [];
        ifc==null ) {
            cnew ServerCookie();
            []=c;
        }
        ++;
        return c;
    }
    // code from CookieTools 

    
Add all Cookie found in the headers of a request.
    public  void processCookiesMimeHeaders headers ) {
        ifheaders==null )
            return;// nothing to process
        // process each "cookie" header
        int pos=0;
        whilepos>=0 ) {
            // Cookie2: version ? not needed
            pos=headers.findHeader"Cookie"pos );
            // no more cookie headers headers
            ifpos<0 ) break;
            MessageBytes cookieValue=headers.getValuepos );
            ifcookieValue==null || cookieValue.isNull() ) {
                pos++;
                continue;
            }
            // Uncomment to test the new parsing code
            ifcookieValue.getType() != . ) {
                cookieValue.toBytes();
            }
            ByteChunk bc=cookieValue.getByteChunk();
            if (.) {
                int len = bc.getLength();
                if (len > 0) {
                    byte[] buf = new byte[len];
                    System.arraycopy(bc.getBytes(), bc.getOffset(), buf, 0, len);
                    processCookieHeader(buf, 0, len);
                }
            } else {
                processCookieHeaderbc.getBytes(),
                        bc.getOffset(),
                        bc.getLength());
            }
            pos++;// search from the next position
        }
    }
    private static boolean equalsString sbyte b[], int startint end) {
        int blen = end-start;
        if (b == null || blen != s.length()) {
            return false;
        }
        int boff = start;
        for (int i = 0; i < bleni++) {
            if (b[boff++] != s.charAt(i)) {
                return false;
            }
        }
        return true;
    }
    

    
Returns true if the byte is a whitespace character as defined in RFC2619 JVK
    private static final boolean isWhiteSpace(final byte c) {
        // This switch statement is slightly slower
        // for my vm than the if statement.
        // Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0_07-164)
        /* 
        switch (c) {
        case ' ':;
        case '\t':;
        case '\n':;
        case '\r':;
        case '\f':;
            return true;
        default:;
            return false;
        }
        */
       if (c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '\f')
           return true;
       else
           return false;
    }

    
Unescapes any double quotes in the given cookie value.

Parameters:
bc The cookie value to modify
    private static void unescapeDoubleQuotes(ByteChunk bc) {
        if (bc == null || bc.getLength() == 0 || bc.indexOf('"', 0) == -1) {
            return;
        }
        int src = bc.getStart();
        int end = bc.getEnd();
        int dest = src;
        byte[] buffer = bc.getBuffer();
        
        while (src < end) {
            if (buffer[src] == '\\' && src < end && buffer[src+1]  == '"') {
                src++;
            }
            buffer[dest] = buffer[src];
            dest ++;
            src ++;
        }
        bc.setEnd(dest);
    }

    
Parses a cookie header after the initial "Cookie:" [WS][$]token[WS]=[WS](token|QV)[;|,] RFC 2965 JVK
    protected final void processCookieHeader(byte bytes[], int offint len){
        iflen<=0 || bytes==null ) return;
        int end=off+len;
        int pos=off;
        int nameStart=0;
        int nameEnd=0;
        int valueStart=0;
        int valueEnd=0;
        int version = 0;
        ServerCookie sc=null;
        boolean isSpecial;
        boolean isQuoted;
        while (pos < end) {
            isSpecial = false;
            isQuoted = false;
            // Skip whitespace and non-token characters (separators)
            while (pos < end && 
                   (CookieSupport.isHttpSeparator((charbytes[pos]) &&
                           !. ||
                    CookieSupport.isV0Separator((charbytes[pos]) ||
                    isWhiteSpace(bytes[pos]))) 
                {pos++; } 
            if (pos >= end)
                return;
            // Detect Special cookies
            if (bytes[pos] == '$') {
                isSpecial = true;
                pos++;
            }
            // Get the cookie/attribute name. This must be a token            
            valueEnd = valueStart = nameStart = pos
            pos = nameEnd = getTokenEndPosition(bytes,pos,end,version,true);
            // Skip whitespace
            while (pos < end && isWhiteSpace(bytes[pos])) {pos++; } 
         
            // Check for an '=' -- This could also be a name-only
            // cookie at the end of the cookie header, so if we
            // are past the end of the header, but we have a name
            // skip to the name-only part.
            if (pos < (end - 1) && bytes[pos] == '=') {                
                // Skip whitespace
                do {
                    pos++;
                } while (pos < end && isWhiteSpace(bytes[pos])); 
                if (pos >= end)
                    return;
                // Determine what type of value this is, quoted value,
                // token, name-only with an '=', or other (bad)
                switch (bytes[pos]) {
                case '"'// Quoted Value
                    isQuoted = true;
                    valueStart=pos + 1; // strip "
                    // getQuotedValue returns the position before 
                    // at the last quote. This must be dealt with
                    // when the bytes are copied into the cookie
                    valueEnd=getQuotedValueEndPosition(bytes
                                                       valueStartend);
                    // We need pos to advance
                    pos = valueEnd
                    // Handles cases where the quoted value is 
                    // unterminated and at the end of the header, 
                    // e.g. [myname="value]
                    if (pos >= end)
                        return;
                    break;
                case ';':
                case ',':
                    // Name-only cookie with an '=' after the name token
                    // This may not be RFC compliant
                    valueStart = valueEnd = -1;
                    // The position is OK (On a delimiter)
                    break;
                default:
                    if (version == 0 &&
                                !CookieSupport.isV0Separator((char)bytes[pos]) &&
                                . ||
                            !CookieSupport.isHttpSeparator((char)bytes[pos]) ||
                            bytes[pos] == '=' && .) {
                        // Token
                        valueStart=pos;
                        // getToken returns the position at the delimiter
                        // or other non-token character
                        valueEnd=getTokenEndPosition(bytesvalueStartend,
                                versionfalse);
                        // We need pos to advance
                        pos = valueEnd;
                    } else  {
                        // INVALID COOKIE, advance to next delimiter
                        // The starting character of the cookie value was
                        // not valid.
                        ..invalidCookieHeader(new String(bytesofflen));
                        while (pos < end && bytes[pos] != ';' && 
                               bytes[pos] != ','
                            {pos++; }
                        pos++;
                        // Make sure no special avpairs can be attributed to 
                        // the previous cookie by setting the current cookie
                        // to null
                        sc = null;
                        continue;                        
                    }
                }
            } else {
                // Name only cookie
                valueStart = valueEnd = -1;
                pos = nameEnd;
            }
          
            // We should have an avpair or name-only cookie at this
            // point. Perform some basic checks to make sure we are
            // in a good state.
  
            // Skip whitespace
            while (pos < end && isWhiteSpace(bytes[pos])) {pos++; }
            // Make sure that after the cookie we have a separator. This
            // is only important if this is not the last cookie pair
            while (pos < end && bytes[pos] != ';' && bytes[pos] != ',') { 
                pos++;
            }
            
            pos++;
            // All checks passed. Add the cookie, start with the 
            // special avpairs first
            if (isSpecial) {
                isSpecial = false;
                // $Version must be the first avpair in the cookie header
                // (sc must be null)
                if (equals"Version"bytesnameStartnameEnd) && 
                    sc == null) {
                    // Set version
                    ifbytes[valueStart] =='1' && valueEnd == (valueStart+1)) {
                        version=1;
                    } else {
                        // unknown version (Versioning is not very strict)
                    }
                    continue;
                } 
                
                // We need an active cookie for Path/Port/etc.
                if (sc == null) {
                    continue;
                }
                // Domain is more common, so it goes first
                if (equals"Domain"bytesnameStartnameEnd)) {
                    sc.getDomain().setBytesbytes,
                                           valueStart,
                                           valueEnd-valueStart);
                    continue;
                } 
                if (equals"Path"bytesnameStartnameEnd)) {
                    sc.getPath().setBytesbytes,
                                           valueStart,
                                           valueEnd-valueStart);
                    continue;
                } 
                // v2 cookie attributes - skip them
                if (equals"Port"bytesnameStartnameEnd)) {
                    continue;
                } 
                if (equals"CommentURL"bytesnameStartnameEnd)) {
                    continue;
                } 
                // Unknown cookie, complain
                ..invalidSpecialCookie(new String(bytesnameStartnameEnd - nameStart));
            } else { // Normal Cookie
                sc = addCookie();
                sc.setVersionversion );
                sc.getName().setBytesbytesnameStart,
                                       nameEnd-nameStart);
                
                if (valueStart != -1) { // Normal AVPair
                    sc.getValue().setBytesbytesvalueStart,
                            valueEnd-valueStart);
                    if (isQuoted) {
                        // We know this is a byte value so this is safe
                        unescapeDoubleQuotes(sc.getValue().getByteChunk());
                    }
                } else {
                    // Name Only
                    sc.getValue().setString(""); 
                }
                continue;
            }
        }
    }

    
Given the starting position of a token, this gets the end of the token, with no separator characters in between. JVK
    private static final int getTokenEndPosition(byte bytes[], int offint end,
            int versionboolean isName){
        int pos = off;
        while (pos < end &&
                (!CookieSupport.isHttpSeparator((char)bytes[pos]) ||
                 version == 0 &&
                        . &&
                        bytes[pos] != '=' &&
                        !CookieSupport.isV0Separator((char)bytes[pos]) ||
                 !isName && bytes[pos] == '=' &&
                         .)) {
            pos++;
        }
        
        if (pos > end)
            return end;
        return pos;
    }

    
Given a starting position after an initial quote character, this gets the position of the end quote. This escapes anything after a '\' char JVK RFC 2616
    private static final int getQuotedValueEndPosition(byte bytes[], int offint end){
        int pos = off;
        while (pos < end) {
            if (bytes[pos] == '"') {
                return pos;                
            } else if (bytes[pos] == '\\' && pos < (end - 1)) {
                pos+=2;
            } else {
                pos++;
            }
        }
        // Error, we have reached the end of the header w/o a end quote
        return end;
    }
New to GrepCode? Check out our FAQ X