Made sure the encoded cookie conforms to the RFC

This commit is contained in:
Trustin Lee 2009-03-14 13:35:10 +00:00
parent eaca45eb8a
commit 701d8a8aaa
4 changed files with 46 additions and 22 deletions

View File

@ -35,18 +35,9 @@ public class CookieEncoder {
private final Set<Cookie> cookies = new TreeSet<Cookie>(); private final Set<Cookie> cookies = new TreeSet<Cookie>();
private final boolean server; private final boolean server;
private final String charset;
public CookieEncoder(boolean server) { public CookieEncoder(boolean server) {
this(server, QueryStringDecoder.DEFAULT_CHARSET);
}
public CookieEncoder(boolean server, String charset) {
if (charset == null) {
throw new NullPointerException("charset");
}
this.server = server; this.server = server;
this.charset = charset;
} }
public void addCookie(String name, String value) { public void addCookie(String name, String value) {
@ -69,11 +60,11 @@ public class CookieEncoder {
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
for (Cookie cookie: cookies) { for (Cookie cookie: cookies) {
add(sb, cookie.getName(), QueryStringEncoder.encodeComponent(cookie.getValue(), charset)); add(sb, cookie.getName(), cookie.getValue());
if (cookie.getMaxAge() >= 0) { if (cookie.getMaxAge() >= 0) {
if (cookie.getVersion() == 0) { if (cookie.getVersion() == 0) {
add(sb, CookieHeaderNames.EXPIRES, addUnquoted(sb, CookieHeaderNames.EXPIRES,
new CookieDateFormat().format( new CookieDateFormat().format(
new Date(System.currentTimeMillis() + new Date(System.currentTimeMillis() +
cookie.getMaxAge() * 1000L))); cookie.getMaxAge() * 1000L)));
@ -83,11 +74,19 @@ public class CookieEncoder {
} }
if (cookie.getPath() != null) { if (cookie.getPath() != null) {
add(sb, CookieHeaderNames.PATH, cookie.getPath()); if (cookie.getVersion() > 0) {
add(sb, CookieHeaderNames.PATH, cookie.getPath());
} else {
addUnquoted(sb, CookieHeaderNames.PATH, cookie.getPath());
}
} }
if (cookie.getDomain() != null) { if (cookie.getDomain() != null) {
add(sb, CookieHeaderNames.DOMAIN, cookie.getDomain()); if (cookie.getVersion() > 0) {
add(sb, CookieHeaderNames.DOMAIN, cookie.getDomain());
} else {
addUnquoted(sb, CookieHeaderNames.DOMAIN, cookie.getDomain());
}
} }
if (cookie.isSecure()) { if (cookie.isSecure()) {
sb.append(CookieHeaderNames.SECURE); sb.append(CookieHeaderNames.SECURE);
@ -134,7 +133,7 @@ public class CookieEncoder {
add(sb, '$' + CookieHeaderNames.VERSION, 1); add(sb, '$' + CookieHeaderNames.VERSION, 1);
} }
add(sb, cookie.getName(), QueryStringEncoder.encodeComponent(cookie.getValue(), charset)); add(sb, cookie.getName(), cookie.getValue());
if (cookie.getPath() != null) { if (cookie.getPath() != null) {
add(sb, '$' + CookieHeaderNames.PATH, cookie.getPath()); add(sb, '$' + CookieHeaderNames.PATH, cookie.getPath());
@ -165,6 +164,27 @@ public class CookieEncoder {
} }
private static void add(StringBuilder sb, String name, String val) { private static void add(StringBuilder sb, String name, String val) {
if (val == null) {
addQuoted(sb, name, "");
return;
}
for (int i = 0; i < val.length(); i ++) {
char c = val.charAt(i);
switch (c) {
case '(': case ')': case '<': case '>': case '@': case ',':
case ';': case ':': case '"': case '/': case '[': case ']':
case '?': case '=': case '{': case '}': case ' ':
case '\t': case '\\':
addQuoted(sb, name, val);
return;
}
}
addUnquoted(sb, name, val);
}
private static void addUnquoted(StringBuilder sb, String name, String val) {
sb.append(name); sb.append(name);
sb.append((char) HttpCodecUtil.EQUALS); sb.append((char) HttpCodecUtil.EQUALS);
sb.append(val); sb.append(val);
@ -172,10 +192,14 @@ public class CookieEncoder {
} }
private static void addQuoted(StringBuilder sb, String name, String val) { private static void addQuoted(StringBuilder sb, String name, String val) {
if (val == null) {
val = "";
}
sb.append(name); sb.append(name);
sb.append((char) HttpCodecUtil.EQUALS); sb.append((char) HttpCodecUtil.EQUALS);
sb.append((char) HttpCodecUtil.DOUBLE_QUOTE); sb.append((char) HttpCodecUtil.DOUBLE_QUOTE);
sb.append(val); sb.append(val.replace("\\", "\\\\").replace("\"", "\\\""));
sb.append((char) HttpCodecUtil.DOUBLE_QUOTE); sb.append((char) HttpCodecUtil.DOUBLE_QUOTE);
sb.append((char) HttpCodecUtil.SEMICOLON); sb.append((char) HttpCodecUtil.SEMICOLON);
} }

View File

@ -128,7 +128,7 @@ public class QueryStringDecoder {
} }
} }
static String decodeComponent(String s, String charset) { private static String decodeComponent(String s, String charset) {
try { try {
return URLDecoder.decode(s, charset); return URLDecoder.decode(s, charset);
} catch (UnsupportedEncodingException e) { } catch (UnsupportedEncodingException e) {

View File

@ -92,7 +92,7 @@ public class QueryStringEncoder {
} }
} }
static String encodeComponent(String s, String charset) { private static String encodeComponent(String s, String charset) {
try { try {
return URLEncoder.encode(s, charset).replaceAll("\\+", "%20"); return URLEncoder.encode(s, charset).replaceAll("\\+", "%20");
} catch (UnsupportedEncodingException e) { } catch (UnsupportedEncodingException e) {

View File

@ -52,7 +52,7 @@ public class CookieEncoderTest {
cookie.setPorts(80, 8080); cookie.setPorts(80, 8080);
cookie.setSecure(true); cookie.setSecure(true);
String encodedCookie = encoder.encode(); String encodedCookie = encoder.encode();
System.out.println(encodedCookie);
long currentTime = System.currentTimeMillis(); long currentTime = System.currentTimeMillis();
assertTrue( assertTrue(
encodedCookie.equals(result.replace("XXX", df.format(new Date(currentTime + 50000)))) || encodedCookie.equals(result.replace("XXX", df.format(new Date(currentTime + 50000)))) ||
@ -61,7 +61,7 @@ public class CookieEncoderTest {
} }
@Test @Test
public void testEncodingSingleCookieV1() { public void testEncodingSingleCookieV1() {
String result = "myCookie=myValue;Max-Age=50;Path=/apathsomewhere;Domain=.adomainsomewhere;Secure;Comment=this is a Comment;Version=1"; String result = "myCookie=myValue;Max-Age=50;Path=\"/apathsomewhere\";Domain=.adomainsomewhere;Secure;Comment=\"this is a Comment\";Version=1";
Cookie cookie = new DefaultCookie("myCookie", "myValue"); Cookie cookie = new DefaultCookie("myCookie", "myValue");
CookieEncoder encoder = new CookieEncoder(true); CookieEncoder encoder = new CookieEncoder(true);
encoder.addCookie(cookie); encoder.addCookie(cookie);
@ -76,7 +76,7 @@ public class CookieEncoderTest {
} }
@Test @Test
public void testEncodingSingleCookieV2() { public void testEncodingSingleCookieV2() {
String result = "myCookie=myValue;Max-Age=50;Path=/apathsomewhere;Domain=.adomainsomewhere;Secure;Comment=this is a Comment;Version=1;CommentURL=\"http://aurl.com\";Port=\"80,8080\";Discard"; String result = "myCookie=myValue;Max-Age=50;Path=\"/apathsomewhere\";Domain=.adomainsomewhere;Secure;Comment=\"this is a Comment\";Version=1;CommentURL=\"http://aurl.com\";Port=\"80,8080\";Discard";
Cookie cookie = new DefaultCookie("myCookie", "myValue"); Cookie cookie = new DefaultCookie("myCookie", "myValue");
CookieEncoder encoder = new CookieEncoder(true); CookieEncoder encoder = new CookieEncoder(true);
encoder.addCookie(cookie); encoder.addCookie(cookie);
@ -95,8 +95,8 @@ public class CookieEncoderTest {
@Test @Test
public void testEncodingMultipleCookies() { public void testEncodingMultipleCookies() {
String c1 = "myCookie=myValue;Max-Age=50;Path=/apathsomewhere;Domain=.adomainsomewhere;Secure;Comment=this is a Comment;Version=1;CommentURL=\"http://aurl.com\";Port=\"80,8080\";Discard;"; String c1 = "myCookie=myValue;Max-Age=50;Path=\"/apathsomewhere\";Domain=.adomainsomewhere;Secure;Comment=\"this is a Comment\";Version=1;CommentURL=\"http://aurl.com\";Port=\"80,8080\";Discard;";
String c2 = "myCookie2=myValue2;Path=/anotherpathsomewhere;Domain=.anotherdomainsomewhere;Comment=this is another Comment;Version=1;CommentURL=\"http://anotherurl.com\";"; String c2 = "myCookie2=myValue2;Path=\"/anotherpathsomewhere\";Domain=.anotherdomainsomewhere;Comment=\"this is another Comment\";Version=1;CommentURL=\"http://anotherurl.com\";";
String c3 = "myCookie3=myValue3;Version=1"; String c3 = "myCookie3=myValue3;Version=1";
CookieEncoder encoder = new CookieEncoder(true); CookieEncoder encoder = new CookieEncoder(true);
Cookie cookie = new DefaultCookie("myCookie", "myValue"); Cookie cookie = new DefaultCookie("myCookie", "myValue");