Added:
tomcat/trunk/modules/tomcat-lite/java/org/apache/tomcat/lite/http/ServerCookie.java
URL:
http://svn.apache.org/viewvc/tomcat/trunk/modules/tomcat-lite/java/org/apache/tomcat/lite/http/ServerCookie.java?rev=884412&view=auto
==============================================================================
---
tomcat/trunk/modules/tomcat-lite/java/org/apache/tomcat/lite/http/ServerCookie.java
(added)
+++
tomcat/trunk/modules/tomcat-lite/java/org/apache/tomcat/lite/http/ServerCookie.java
Thu Nov 26 06:41:00 2009
@@ -0,0 +1,819 @@
+/*
+ * 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.lite.http;
+
+import java.io.Serializable;
+import java.text.DateFormat;
+import java.text.FieldPosition;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.List;
+import java.util.Locale;
+import java.util.TimeZone;
+
+import org.apache.tomcat.lite.io.BBuffer;
+import org.apache.tomcat.lite.io.CBuffer;
+
+
+/**
+ * Server-side cookie representation.
+ * Allows recycling and uses MessageBytes as low-level
+ * representation ( and thus the byte-> char conversion can be delayed
+ * until we know the charset ).
+ *
+ * Tomcat.core uses this recyclable object to represent cookies,
+ * and the facade will convert it to the external representation.
+ */
+public class ServerCookie implements Serializable {
+
+ // Version 0 (Netscape) attributes
+ private BBuffer name = BBuffer.allocate();
+ private BBuffer value = BBuffer.allocate();
+
+ private CBuffer nameC = CBuffer.newInstance();
+
+ // Expires - Not stored explicitly. Generated from Max-Age (see V1)
+ private BBuffer path = BBuffer.allocate();
+ private BBuffer domain = BBuffer.allocate();
+ private boolean secure;
+
+ // Version 1 (RFC2109) attributes
+ private BBuffer comment = BBuffer.allocate();
+ private int maxAge = -1;
+ private int version = 0;
+
+ // Other fields
+ private static final String OLD_COOKIE_PATTERN =
+ "EEE, dd-MMM-yyyy HH:mm:ss z";
+ private static final ThreadLocal<DateFormat> OLD_COOKIE_FORMAT =
+ new ThreadLocal<DateFormat>() {
+ protected DateFormat initialValue() {
+ DateFormat df =
+ new SimpleDateFormat(OLD_COOKIE_PATTERN, Locale.US);
+ df.setTimeZone(TimeZone.getTimeZone("GMT"));
+ return df;
+ }
+ };
+
+ private static final String ancientDate;
+
+
+ static {
+ ancientDate = OLD_COOKIE_FORMAT.get().format(new Date(10000));
+ }
+
+ /**
+ * If set to true, we parse cookies according to the servlet spec,
+ */
+ public static final boolean STRICT_SERVLET_COMPLIANCE =
+
Boolean.valueOf(System.getProperty("org.apache.catalina.STRICT_SERVLET_COMPLIANCE",
"false")).booleanValue();
+
+ /**
+ * If set to false, we don't use the IE6/7 Max-Age/Expires work around
+ */
+ public static final boolean ALWAYS_ADD_EXPIRES =
+
Boolean.valueOf(System.getProperty("org.apache.tomcat.util.http.ServerCookie.ALWAYS_ADD_EXPIRES",
"true")).booleanValue();
+
+ // Note: Servlet Spec =< 2.5 only refers to Netscape and RFC2109,
+ // not RFC2965
+
+ // Version 1 (RFC2965) attributes
+ // TODO Add support for CommentURL
+ // Discard - implied by maxAge <0
+ // TODO Add support for Port
+
+ public ServerCookie() {
+ }
+
+ public void recycle() {
+ path.recycle();
+ name.recycle();
+ value.recycle();
+ comment.recycle();
+ maxAge=-1;
+ path.recycle();
+ domain.recycle();
+ version=0;
+ secure=false;
+ }
+
+ public BBuffer getComment() {
+ return comment;
+ }
+
+ public BBuffer getDomain() {
+ return domain;
+ }
+
+ public void setMaxAge(int expiry) {
+ maxAge = expiry;
+ }
+
+ public int getMaxAge() {
+ return maxAge;
+ }
+
+ public BBuffer getPath() {
+ return path;
+ }
+
+ public void setSecure(boolean flag) {
+ secure = flag;
+ }
+
+ public boolean getSecure() {
+ return secure;
+ }
+
+ public BBuffer getName() {
+ return name;
+ }
+
+ public BBuffer getValue() {
+ return value;
+ }
+
+ public int getVersion() {
+ return version;
+ }
+
+ public void setVersion(int v) {
+ version = v;
+ }
+
+
+ // -------------------- utils --------------------
+
+ public String toString() {
+ return "Cookie " + getName() + "=" + getValue() + " ; "
+ + getVersion() + " " + getPath() + " " + getDomain();
+ }
+
+ private static final String tspecials = ",; ";
+ private static final String tspecials2 = "()<>@,;:\\\"/[]?={} \t";
+ private static final String tspecials2NoSlash = "()<>@,;:\\\"[]?={} \t";
+
+ /*
+ * Tests a string and returns true if the string counts as a
+ * reserved token in the Java language.
+ *
+ * @param value the <code>String</code> to be tested
+ *
+ * @return <code>true</code> if the <code>String</code> is a reserved
+ * token; <code>false</code> if it is not
+ */
+ public static boolean isToken(String value) {
+ return isToken(value,null);
+ }
+
+ public static boolean isToken(String value, String literals) {
+ String tspecials = (literals==null?ServerCookie.tspecials:literals);
+ if( value==null) return true;
+ int len = value.length();
+
+ for (int i = 0; i < len; i++) {
+ char c = value.charAt(i);
+
+ if (tspecials.indexOf(c) != -1)
+ return false;
+ }
+ return true;
+ }
+
+ public static boolean containsCTL(String value, int version) {
+ if( value==null) return false;
+ int len = value.length();
+ for (int i = 0; i < len; i++) {
+ char c = value.charAt(i);
+ if (c < 0x20 || c >= 0x7f) {
+ if (c == 0x09)
+ continue; //allow horizontal tabs
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public static boolean isToken2(String value) {
+ return isToken2(value,null);
+ }
+
+ public static boolean isToken2(String value, String literals) {
+ String tspecials2 = (literals==null?ServerCookie.tspecials2:literals);
+ if( value==null) return true;
+ int len = value.length();
+
+ for (int i = 0; i < len; i++) {
+ char c = value.charAt(i);
+ if (tspecials2.indexOf(c) != -1)
+ return false;
+ }
+ return true;
+ }
+
+ // -------------------- Cookie parsing tools
+
+
+ /**
+ * Return the header name to set the cookie, based on cookie version.
+ */
+ public String getCookieHeaderName() {
+ return getCookieHeaderName(version);
+ }
+
+ /**
+ * Return the header name to set the cookie, based on cookie version.
+ */
+ public static String getCookieHeaderName(int version) {
+ // TODO Re-enable logging when RFC2965 is implemented
+ // log( (version==1) ? "Set-Cookie2" : "Set-Cookie");
+ if (version == 1) {
+ // XXX RFC2965 not referenced in Servlet Spec
+ // Set-Cookie2 is not supported by Netscape 4, 6, IE 3, 5
+ // Set-Cookie2 is supported by Lynx and Opera
+ // Need to check on later IE and FF releases but for now...
+ // RFC2109
+ return "Set-Cookie";
+ // return "Set-Cookie2";
+ } else {
+ // Old Netscape
+ return "Set-Cookie";
+ }
+ }
+
+ // TODO RFC2965 fields also need to be passed
+ public static void appendCookieValue( StringBuffer headerBuf,
+ int version,
+ String name,
+ String value,
+ String path,
+ String domain,
+ String comment,
+ int maxAge,
+ boolean isSecure,
+ boolean isHttpOnly)
+ {
+ StringBuffer buf = new StringBuffer();
+ // Servlet implementation checks name
+ buf.append( name );
+ buf.append("=");
+ // Servlet implementation does not check anything else
+
+ version = maybeQuote2(version, buf, value,true);
+
+ // Add version 1 specific information
+ if (version == 1) {
+ // Version=1 ... required
+ buf.append ("; Version=1");
+
+ // Comment=comment
+ if ( comment!=null ) {
+ buf.append ("; Comment=");
+ maybeQuote2(version, buf, comment);
+ }
+ }
+
+ // Add domain information, if present
+ if (domain!=null) {
+ buf.append("; Domain=");
+ maybeQuote2(version, buf, domain);
+ }
+
+ // Max-Age=secs ... or use old "Expires" format
+ // TODO RFC2965 Discard
+ if (maxAge >= 0) {
+ if (version > 0) {
+ buf.append ("; Max-Age=");
+ buf.append (maxAge);
+ }
+ // IE6, IE7 and possibly other browsers don't understand Max-Age.
+ // They do understand Expires, even with V1 cookies!
+ if (version == 0 || ALWAYS_ADD_EXPIRES) {
+ // Wdy, DD-Mon-YY HH:MM:SS GMT ( Expires Netscape format )
+ buf.append ("; Expires=");
+ // To expire immediately we need to set the time in past
+ if (maxAge == 0)
+ buf.append( ancientDate );
+ else
+ OLD_COOKIE_FORMAT.get().format(
+ new Date(System.currentTimeMillis() +
+ maxAge*1000L),
+ buf, new FieldPosition(0));
+ }
+ }
+
+ // Path=path
+ if (path!=null) {
+ buf.append ("; Path=");
+ if (version==0) {
+ maybeQuote2(version, buf, path);
+ } else {
+ maybeQuote2(version, buf, path,
ServerCookie.tspecials2NoSlash, false);
+ }
+ }
+
+ // Secure
+ if (isSecure) {
+ buf.append ("; Secure");
+ }
+
+ // HttpOnly
+ if (isHttpOnly) {
+ buf.append("; HttpOnly");
+ }
+ headerBuf.append(buf);
+ }
+
+ public static boolean alreadyQuoted (String value) {
+ if (value==null || value.length()==0) return false;
+ return (value.charAt(0)=='\"' && value.charAt(value.length()-1)=='\"');
+ }
+
+ /**
+ * Quotes values using rules that vary depending on Cookie version.
+ * @param version
+ * @param buf
+ * @param value
+ */
+ public static int maybeQuote2 (int version, StringBuffer buf, String
value) {
+ return maybeQuote2(version,buf,value,false);
+ }
+
+ public static int maybeQuote2 (int version, StringBuffer buf, String
value, boolean allowVersionSwitch) {
+ return maybeQuote2(version,buf,value,null,allowVersionSwitch);
+ }
+
+ public static int maybeQuote2 (int version, StringBuffer buf, String
value, String literals, boolean allowVersionSwitch) {
+ if (value==null || value.length()==0) {
+ buf.append("\"\"");
+ }else if (containsCTL(value,version))
+ throw new IllegalArgumentException("Control character in cookie
value, consider BASE64 encoding your value");
+ else if (alreadyQuoted(value)) {
+ buf.append('"');
+ buf.append(escapeDoubleQuotes(value,1,value.length()-1));
+ buf.append('"');
+ } else if (allowVersionSwitch && (!STRICT_SERVLET_COMPLIANCE) &&
version==0 && !isToken2(value, literals)) {
+ buf.append('"');
+ buf.append(escapeDoubleQuotes(value,0,value.length()));
+ buf.append('"');
+ version = 1;
+ } else if (version==0 && !isToken(value,literals)) {
+ buf.append('"');
+ buf.append(escapeDoubleQuotes(value,0,value.length()));
+ buf.append('"');
+ } else if (version==1 && !isToken2(value,literals)) {
+ buf.append('"');
+ buf.append(escapeDoubleQuotes(value,0,value.length()));
+ buf.append('"');
+ }else {
+ buf.append(value);
+ }
+ return version;
+ }
+
+
+ /**
+ * Escapes any double quotes in the given string.
+ *
+ * @param s the input string
+ * @param beginIndex start index inclusive
+ * @param endIndex exclusive
+ * @return The (possibly) escaped string
+ */
+ private static String escapeDoubleQuotes(String s, int beginIndex, int
endIndex) {
+
+ if (s == null || s.length() == 0 || s.indexOf('"') == -1) {
+ return s;
+ }
+
+ StringBuffer b = new StringBuffer();
+ for (int i = beginIndex; i < endIndex; i++) {
+ char c = s.charAt(i);
+ if (c == '\\' ) {
+ b.append(c);
+ //ignore the character after an escape, just append it
+ if (++i>=endIndex) throw new IllegalArgumentException("Invalid
escape character in cookie value.");
+ b.append(s.charAt(i));
+ } else if (c == '"')
+ b.append('\\').append('"');
+ else
+ b.append(c);
+ }
+
+ return b.toString();
+ }
+
+ /**
+ * Unescapes any double quotes in the given cookie value.
+ *
+ * @param bc The cookie value to modify
+ */
+ public static void unescapeDoubleQuotes(BBuffer 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.array();
+
+ while (src < end) {
+ if (buffer[src] == '\\' && src < end && buffer[src+1] == '"') {
+ src++;
+ }
+ buffer[dest] = buffer[src];
+ dest ++;
+ src ++;
+ }
+ bc.setEnd(dest);
+ }
+
+ /*
+ List of Separator Characters (see isSeparator())
+ Excluding the '/' char violates the RFC, but
+ it looks like a lot of people put '/'
+ in unquoted values: '/': ; //47
+ '\t':9 ' ':32 '\"':34 '\'':39 '(':40 ')':41 ',':44 ':':58 ';':59 '<':60
+ '=':61 '>':62 '?':63 '@':64 '[':91 '\\':92 ']':93 '{':123 '}':125
+ */
+ public static final char SEPARATORS[] = { '\t', ' ', '\"', '\'', '(', ')',
',',
+ ':', ';', '<', '=', '>', '?', '@', '[', '\\', ']', '{', '}' };
+
+ protected static final boolean separators[] = new boolean[128];
+ static {
+ for (int i = 0; i < 128; i++) {
+ separators[i] = false;
+ }
+ for (int i = 0; i < SEPARATORS.length; i++) {
+ separators[SEPARATORS[i]] = true;
+ }
+ }
+
+ /** Add all Cookie found in the headers of a request.
+ */
+ public static void processCookies(List<ServerCookie> cookies,
+ List<ServerCookie> cookiesCache,
+ HttpMessage.HttpMessageBytes msgBytes ) {
+
+ // process each "cookie" header
+ for (int i = 0; i < msgBytes.headerCount; i++) {
+ if (msgBytes.getHeaderName(i).equalsIgnoreCase("Cookie")) {
+ BBuffer bc = msgBytes.getHeaderValue(i);
+ if (bc.remaining() == 0) {
+ continue;
+ }
+ processCookieHeader(cookies, cookiesCache,
+ bc.array(),
+ bc.getOffset(),
+ bc.getLength());
+
+ }
+
+ }
+ }
+
+ /**
+ * Returns true if the byte is a separator character as
+ * defined in RFC2619. Since this is called often, this
+ * function should be organized with the most probable
+ * outcomes first.
+ * JVK
+ */
+ private static final boolean isSeparator(final byte c) {
+ if (c > 0 && c < 126)
+ return separators[c];
+ else
+ return false;
+ }
+
+ /**
+ * 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;
+ }
+
+ /**
+ * Parses a cookie header after the initial "Cookie:"
+ * [WS][$]token[WS]=[WS](token|QV)[;|,]
+ * RFC 2965
+ * JVK
+ */
+ public static final void processCookieHeader(
+ List<ServerCookie> cookies,
+ List<ServerCookie> cookiesCache,
+ byte bytes[], int off, int len){
+ if( len<=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 &&
+ (isSeparator(bytes[pos]) || isWhiteSpace(bytes[pos])))
+ {pos++; }
+
+ if (pos >= end)
+ return;
+
+ // Detect Special cookies
+ if (bytes[pos] == '$') {
+ isSpecial = true;
+ pos++;
+ }
+
+ // Get the cookie name. This must be a token
+ valueEnd = valueStart = nameStart = pos;
+ pos = nameEnd = getTokenEndPosition(bytes,pos,end);
+
+ // 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 && 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 qoute. This must be dealt with
+ // when the bytes are copied into the cookie
+ valueEnd=getQuotedValueEndPosition(bytes,
+ valueStart, end);
+ // 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 (!isSeparator(bytes[pos])) {
+ // Token
+ valueStart=pos;
+ // getToken returns the position at the delimeter
+ // or other non-token character
+ valueEnd=getTokenEndPosition(bytes, valueStart, end);
+ // We need pos to advance
+ pos = valueEnd;
+ } else {
+ // INVALID COOKIE, advance to next delimiter
+ // The starting character of the cookie value was
+ // not valid.
+ //log("Invalid cookie. Value not a token or quoted
value");
+ 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++;
+
+ /*
+ if (nameEnd <= nameStart || valueEnd < valueStart ) {
+ // Something is wrong, but this may be a case
+ // of having two ';' characters in a row.
+ // log("Cookie name/value does not conform to RFC 2965");
+ // Advance to next delimiter (ignoring everything else)
+ while (pos < end && bytes[pos] != ';' && bytes[pos] != ',')
+ { pos++; };
+ pos++;
+ // Make sure no special cookies can be attributed to
+ // the previous cookie by setting the current cookie
+ // to null
+ sc = null;
+ continue;
+ }
+ */
+
+ // 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", bytes, nameStart, nameEnd) &&
+ sc == null) {
+ // Set version
+ if( bytes[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", bytes, nameStart, nameEnd)) {
+ sc.getDomain().setBytes( bytes,
+ valueStart,
+ valueEnd-valueStart);
+ continue;
+ }
+
+ if (equals( "Path", bytes, nameStart, nameEnd)) {
+ sc.getPath().setBytes( bytes,
+ valueStart,
+ valueEnd-valueStart);
+ continue;
+ }
+
+
+ if (equals( "Port", bytes, nameStart, nameEnd)) {
+ // sc.getPort is not currently implemented.
+ // sc.getPort().setBytes( bytes,
+ // valueStart,
+ // valueEnd-valueStart );
+ continue;
+ }
+
+ // Unknown cookie, complain
+ //log("Unknown Special Cookie");
+
+ } else { // Normal Cookie
+ // use a previous value from cache, if any (to avoid GC -
tomcat
+ // legacy )
+ if (cookiesCache.size() > cookies.size()) {
+ sc = cookiesCache.get(cookies.size());
+ cookies.add(sc);
+ } else {
+ sc = new ServerCookie();
+ cookiesCache.add(sc);
+ cookies.add(sc);
+ }
+ sc.setVersion( version );
+ sc.getName().append( bytes, nameStart,
+ nameEnd-nameStart);
+
+ if (valueStart != -1) { // Normal AVPair
+ sc.getValue().append( bytes, valueStart,
+ valueEnd-valueStart);
+ if (isQuoted) {
+ // We know this is a byte value so this is safe
+ ServerCookie.unescapeDoubleQuotes(
+ sc.getValue());
+ }
+ } else {
+ // Name Only
+ sc.getValue().recycle();
+ }
+ sc.nameC.recycle();
+ sc.nameC.append(sc.getName());
+ 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 off, int
end){
+ int pos = off;
+ while (pos < end && !isSeparator(bytes[pos])) {pos++; }
+
+ if (pos > end)
+ return end;
+ return pos;
+ }
+
+ /**
+ * Given a starting position after an initial quote chracter, 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 off,
int 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;
+ }
+
+
+ public static boolean equals( String s, byte b[], int start, int end) {
+ int blen = end-start;
+ if (b == null || blen != s.length()) {
+ return false;
+ }
+ int boff = start;
+ for (int i = 0; i < blen; i++) {
+ if (b[boff++] != s.charAt(i)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+}
+
Propchange:
tomcat/trunk/modules/tomcat-lite/java/org/apache/tomcat/lite/http/ServerCookie.java
------------------------------------------------------------------------------
svn:eol-style = native
Added:
tomcat/trunk/modules/tomcat-lite/java/org/apache/tomcat/lite/http/package.html
URL:
http://svn.apache.org/viewvc/tomcat/trunk/modules/tomcat-lite/java/org/apache/tomcat/lite/http/package.html?rev=884412&view=auto
==============================================================================
(empty)
Propchange:
tomcat/trunk/modules/tomcat-lite/java/org/apache/tomcat/lite/http/package.html
------------------------------------------------------------------------------
svn:eol-style = native
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]