Fixed parsing and validation of RFC2109 compliant Set-Cookie headers by the Best-Match cookie spec

git-svn-id: https://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk@708579 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Oleg Kalnichevski 2008-10-28 14:05:58 +00:00
parent 1fb53e28c2
commit c3b6c426ca
3 changed files with 53 additions and 13 deletions

View File

@ -1,6 +1,10 @@
Changes since 4.0 beta 1 Changes since 4.0 beta 1
------------------- -------------------
* Fixed parsing and validation of RFC2109 compliant Set-Cookie headers
by the Best-Match cookie spec.
Contributed by Oleg Kalnichevski <olegk at apache.org>
* Fixed bug that can cause a managed connection to be returned from the * Fixed bug that can cause a managed connection to be returned from the
pool in an inconsistent state. pool in an inconsistent state.
Contributed by Oleg Kalnichevski <olegk at apache.org> Contributed by Oleg Kalnichevski <olegk at apache.org>

View File

@ -39,6 +39,8 @@ import org.apache.http.cookie.Cookie;
import org.apache.http.cookie.CookieOrigin; import org.apache.http.cookie.CookieOrigin;
import org.apache.http.cookie.CookieSpec; import org.apache.http.cookie.CookieSpec;
import org.apache.http.cookie.MalformedCookieException; import org.apache.http.cookie.MalformedCookieException;
import org.apache.http.cookie.SM;
import org.apache.http.cookie.SetCookie2;
/** /**
* 'Meta' cookie specification that selects a cookie policy depending * 'Meta' cookie specification that selects a cookie policy depending
@ -54,6 +56,7 @@ public class BestMatchSpec implements CookieSpec {
private final boolean oneHeader; private final boolean oneHeader;
private RFC2965Spec strict; private RFC2965Spec strict;
private RFC2109Spec obsoleteStrict;
private BrowserCompatSpec compat; private BrowserCompatSpec compat;
private NetscapeDraftSpec netscape; private NetscapeDraftSpec netscape;
@ -74,6 +77,13 @@ public class BestMatchSpec implements CookieSpec {
return strict; return strict;
} }
private RFC2109Spec getObsoleteStrict() {
if (this.obsoleteStrict == null) {
this.obsoleteStrict = new RFC2109Spec(this.datepatterns, this.oneHeader);
}
return obsoleteStrict;
}
private BrowserCompatSpec getCompat() { private BrowserCompatSpec getCompat() {
if (this.compat == null) { if (this.compat == null) {
this.compat = new BrowserCompatSpec(this.datepatterns); this.compat = new BrowserCompatSpec(this.datepatterns);
@ -111,13 +121,14 @@ public class BestMatchSpec implements CookieSpec {
if (helem.getParameterByName("expires") != null) { if (helem.getParameterByName("expires") != null) {
netscape = true; netscape = true;
} }
}
if (netscape) {
} }
// Do we have a cookie with a version attribute? // Do we have a cookie with a version attribute?
if (versioned) { if (versioned) {
return getStrict().parse(helems, origin); if (SM.SET_COOKIE2.equals(header.getName())) {
return getStrict().parse(helems, origin);
} else {
return getObsoleteStrict().parse(helems, origin);
}
} else if (netscape) { } else if (netscape) {
// Need to parse the header again, // Need to parse the header again,
// because Netscape draft cannot handle // because Netscape draft cannot handle
@ -138,7 +149,11 @@ public class BestMatchSpec implements CookieSpec {
throw new IllegalArgumentException("Cookie origin may not be null"); throw new IllegalArgumentException("Cookie origin may not be null");
} }
if (cookie.getVersion() > 0) { if (cookie.getVersion() > 0) {
getStrict().validate(cookie, origin); if (cookie instanceof SetCookie2) {
getStrict().validate(cookie, origin);
} else {
getObsoleteStrict().validate(cookie, origin);
}
} else { } else {
getCompat().validate(cookie, origin); getCompat().validate(cookie, origin);
} }
@ -152,7 +167,11 @@ public class BestMatchSpec implements CookieSpec {
throw new IllegalArgumentException("Cookie origin may not be null"); throw new IllegalArgumentException("Cookie origin may not be null");
} }
if (cookie.getVersion() > 0) { if (cookie.getVersion() > 0) {
return getStrict().match(cookie, origin); if (cookie instanceof SetCookie2) {
return getStrict().match(cookie, origin);
} else {
return getObsoleteStrict().match(cookie, origin);
}
} else { } else {
return getCompat().match(cookie, origin); return getCompat().match(cookie, origin);
} }
@ -163,13 +182,21 @@ public class BestMatchSpec implements CookieSpec {
throw new IllegalArgumentException("List of cookie may not be null"); throw new IllegalArgumentException("List of cookie may not be null");
} }
int version = Integer.MAX_VALUE; int version = Integer.MAX_VALUE;
boolean isSetCookie2 = true;
for (Cookie cookie: cookies) { for (Cookie cookie: cookies) {
if (!(cookie instanceof SetCookie2)) {
isSetCookie2 = false;
}
if (cookie.getVersion() < version) { if (cookie.getVersion() < version) {
version = cookie.getVersion(); version = cookie.getVersion();
} }
} }
if (version > 0) { if (version > 0) {
return getStrict().formatCookies(cookies); if (isSetCookie2) {
return getStrict().formatCookies(cookies);
} else {
return getObsoleteStrict().formatCookies(cookies);
}
} else { } else {
return getCompat().formatCookies(cookies); return getCompat().formatCookies(cookies);
} }

View File

@ -106,15 +106,24 @@ public class TestCookieBestMatchSpec extends TestCase {
CookieOrigin origin = new CookieOrigin("a.b.domain.com", 80, "/", false); CookieOrigin origin = new CookieOrigin("a.b.domain.com", 80, "/", false);
// Make sure the strict (RFC2965) cookie parsing // Make sure the strict (RFC2965) cookie parsing
// and validation is used for version 1 cookies // and validation is used for version 1 Set-Cookie2 headers
Header header = new BasicHeader("Set-Cookie", "name=value;path=/;domain=b.domain.com; version=1"); Header header = new BasicHeader("Set-Cookie2", "name=value;path=/;domain=b.domain.com; version=1");
List<Cookie> cookies = cookiespec.parse(header, origin); List<Cookie> cookies = cookiespec.parse(header, origin);
for (int i = 0; i < cookies.size(); i++) { for (int i = 0; i < cookies.size(); i++) {
cookiespec.validate(cookies.get(i), origin); cookiespec.validate(cookies.get(i), origin);
} }
header = new BasicHeader("Set-Cookie", "name=value;path=/;domain=domain.com; version=1"); // Make sure the strict (RFC2109) cookie parsing
// and validation is used for version 1 Set-Cookie headers
header = new BasicHeader("Set-Cookie", "name=value;path=/;domain=.b.domain.com; version=1");
cookies = cookiespec.parse(header, origin);
for (int i = 0; i < cookies.size(); i++) {
cookiespec.validate(cookies.get(i), origin);
}
header = new BasicHeader("Set-Cookie2", "name=value;path=/;domain=domain.com; version=1");
try { try {
cookies = cookiespec.parse(header, origin); cookies = cookiespec.parse(header, origin);
cookiespec.validate(cookies.get(0), origin); cookiespec.validate(cookies.get(0), origin);
@ -134,8 +143,8 @@ public class TestCookieBestMatchSpec extends TestCase {
for (int i = 0; i < cookies.size(); i++) { for (int i = 0; i < cookies.size(); i++) {
Cookie cookie = cookies.get(i); Cookie cookie = cookies.get(i);
cookiespec.validate(cookie, origin); cookiespec.validate(cookie, origin);
assertEquals("localhost.local", cookie.getDomain()); assertEquals("localhost", cookie.getDomain());
assertTrue(cookie instanceof SetCookie2); assertFalse(cookie instanceof SetCookie2);
} }
} }
@ -175,7 +184,7 @@ public class TestCookieBestMatchSpec extends TestCase {
// Make sure the strict (RFC2965) cookie matching // Make sure the strict (RFC2965) cookie matching
// is used for version 1 cookies // is used for version 1 cookies
BasicClientCookie cookie = new BasicClientCookie("name", "value"); BasicClientCookie2 cookie = new BasicClientCookie2("name", "value");
cookie.setVersion(1); cookie.setVersion(1);
cookie.setDomain(".domain.com"); cookie.setDomain(".domain.com");
cookie.setAttribute(ClientCookie.DOMAIN_ATTR, cookie.getDomain()); cookie.setAttribute(ClientCookie.DOMAIN_ATTR, cookie.getDomain());