cookie.setSecure(true);
}
}
+
+ protected String unescape(String s) {
+ if (s==null) return null;
+ if (s.indexOf('\\') == -1) return s;
+ StringBuffer buf = new StringBuffer();
+ for (int i=0; i<s.length(); i++) {
+ char c = s.charAt(i);
+ if (c!='\\') buf.append(c);
+ else {
+ if (++i >= s.length()) throw new IllegalArgumentException();//invalid escape, hence invalid cookie
+ c = s.charAt(i);
+ buf.append(c);
+ }
+ }
+ return buf.toString();
+ }
/**
* Parse cookies.
for (int i = 0; i < count; i++) {
ServerCookie scookie = serverCookies.getCookie(i);
try {
- Cookie cookie = new Cookie(scookie.getName().toString(),
- scookie.getValue().toString());
- cookie.setPath(scookie.getPath().toString());
- cookie.setVersion(scookie.getVersion());
+ /*
+ we must unescape the '\\' escape character
+ */
+ Cookie cookie = new Cookie(scookie.getName().toString(),null);
+ int version = scookie.getVersion();
+ cookie.setVersion(version);
+ cookie.setValue(unescape(scookie.getValue().toString()));
+ cookie.setPath(unescape(scookie.getPath().toString()));
String domain = scookie.getDomain().toString();
- if (domain != null) {
- cookie.setDomain(scookie.getDomain().toString());
- }
+ if (domain!=null) cookie.setDomain(unescape(domain));//avoid NPE
+ String comment = scookie.getComment().toString();
+ cookie.setComment(version==1?unescape(comment):null);
cookies[idx++] = cookie;
} catch(IllegalArgumentException e) {
// Ignore bad cookie
for (int i = 0; i < len; i++) {
char c = value.charAt(i);
- if (c < 0x20 || c >= 0x7f || tspecials.indexOf(c) != -1)
+ 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) {
if( value==null) return true;
int len = value.length();
for (int i = 0; i < len; i++) {
char c = value.charAt(i);
-
- if (c < 0x20 || c >= 0x7f || tspecials2.indexOf(c) != -1)
+ if (tspecials2.indexOf(c) != -1)
return false;
}
return true;
DateTool.formatOldCookie(new Date(10000));
// TODO RFC2965 fields also need to be passed
- public static void appendCookieValue( StringBuffer buf,
+ public static void appendCookieValue( StringBuffer headerBuf,
int version,
String name,
String value,
int maxAge,
boolean isSecure )
{
+ StringBuffer buf = new StringBuffer();
// Servlet implementation checks name
buf.append( name );
buf.append("=");
buf.append ("; Secure");
}
-
+ headerBuf.append(buf);
}
/**
* @deprecated - Not used
*/
- public static void maybeQuote (int version, StringBuffer buf,
- String value) {
+ @Deprecated
+ public static void maybeQuote (int version, StringBuffer buf,String value) {
// special case - a \n or \r shouldn't happen in any case
if (isToken(value)) {
buf.append(value);
} else {
buf.append('"');
- buf.append(escapeDoubleQuotes(value));
+ buf.append(escapeDoubleQuotes(value,0,value.length()));
buf.append('"');
}
}
+ 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 void maybeQuote2 (int version, StringBuffer buf,
- String value) {
- // special case - a \n or \r shouldn't happen in any case
- if (version == 0 && isToken(value) || version == 1 && isToken2(value)) {
- buf.append(value);
- } else {
+ public static void maybeQuote2 (int version, StringBuffer buf, String value) {
+ 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 (version==0 && !isToken(value)) {
buf.append('"');
- buf.append(escapeDoubleQuotes(value));
+ buf.append(escapeDoubleQuotes(value,0,value.length()));
buf.append('"');
+ } else if (version==1 && !isToken2(value)) {
+ buf.append('"');
+ buf.append(escapeDoubleQuotes(value,0,value.length()));
+ buf.append('"');
+ }else {
+ buf.append(value);
}
}
* 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) {
+ 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 = 0; i < s.length(); i++) {
+ for (int i = beginIndex; i < endIndex; i++) {
char c = s.charAt(i);
- if (c == '"')
+ 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);