[jboss-remoting-commits] JBoss Remoting SVN: r4002 - remoting3/trunk/http/src/main/java/org/jboss/cx/remoting/http/cookie.
jboss-remoting-commits at lists.jboss.org
jboss-remoting-commits at lists.jboss.org
Thu Apr 17 22:17:51 EDT 2008
Author: david.lloyd at jboss.com
Date: 2008-04-17 22:17:50 -0400 (Thu, 17 Apr 2008)
New Revision: 4002
Removed:
remoting3/trunk/http/src/main/java/org/jboss/cx/remoting/http/cookie/CookieDomain.java
Modified:
remoting3/trunk/http/src/main/java/org/jboss/cx/remoting/http/cookie/Cookie.java
remoting3/trunk/http/src/main/java/org/jboss/cx/remoting/http/cookie/CookieClientSession.java
remoting3/trunk/http/src/main/java/org/jboss/cx/remoting/http/cookie/CookieMatcher.java
remoting3/trunk/http/src/main/java/org/jboss/cx/remoting/http/cookie/CookieParser.java
remoting3/trunk/http/src/main/java/org/jboss/cx/remoting/http/cookie/CookieValidator.java
remoting3/trunk/http/src/main/java/org/jboss/cx/remoting/http/cookie/SimpleCookieMatcher.java
remoting3/trunk/http/src/main/java/org/jboss/cx/remoting/http/cookie/SimpleCookieParser.java
remoting3/trunk/http/src/main/java/org/jboss/cx/remoting/http/cookie/SimpleCookieValidator.java
Log:
Redo (and simplify) cookies
Modified: remoting3/trunk/http/src/main/java/org/jboss/cx/remoting/http/cookie/Cookie.java
===================================================================
--- remoting3/trunk/http/src/main/java/org/jboss/cx/remoting/http/cookie/Cookie.java 2008-04-17 03:03:00 UTC (rev 4001)
+++ remoting3/trunk/http/src/main/java/org/jboss/cx/remoting/http/cookie/Cookie.java 2008-04-18 02:17:50 UTC (rev 4002)
@@ -12,12 +12,12 @@
private final String value;
private final String name;
private final String path;
- private final CookieDomain domain;
+ private final String domain;
private final long expires;
private final boolean secure;
private final Key key;
- public Cookie(final String name, final String value, final String path, final CookieDomain domain, final long expires, final boolean secure) {
+ public Cookie(final String name, final String value, final String path, final String domain, final long expires, final boolean secure) {
this.expires = expires;
if (name == null) {
throw new NullPointerException("name is null");
@@ -34,7 +34,7 @@
this.name = name;
this.value = value;
this.path = path;
- this.domain = domain;
+ this.domain = domain.toLowerCase();
this.secure = secure;
key = new Key(name, path);
}
@@ -51,7 +51,7 @@
return path;
}
- public CookieDomain getDomain() {
+ public String getDomain() {
return domain;
}
Modified: remoting3/trunk/http/src/main/java/org/jboss/cx/remoting/http/cookie/CookieClientSession.java
===================================================================
--- remoting3/trunk/http/src/main/java/org/jboss/cx/remoting/http/cookie/CookieClientSession.java 2008-04-17 03:03:00 UTC (rev 4001)
+++ remoting3/trunk/http/src/main/java/org/jboss/cx/remoting/http/cookie/CookieClientSession.java 2008-04-18 02:17:50 UTC (rev 4002)
@@ -41,10 +41,9 @@
* @return the cookie header value
*/
public String getCookieHeader(String domain, String path, boolean secureRequest) {
- final CookieDomain cookieDomain = new CookieDomain(domain);
final SortedMap<Cookie.Key, Cookie> sortedValidatedCookies = new TreeMap<Cookie.Key, Cookie>();
for (final Cookie cookie : cookieMap.values()) {
- if (cookieMatcher.matches(cookie, cookieDomain, path, secureRequest)) {
+ if (cookieMatcher.matches(cookie, domain, path, secureRequest)) {
sortedValidatedCookies.put(cookie.getKey(), cookie);
}
}
@@ -66,15 +65,12 @@
* @param path the request path
*/
public void handleSetCookieHeader(String headerValue, String domain, String path) {
- final CookieDomain requestDomain = new CookieDomain(domain);
- final Cookie[] cookies = cookieParser.parseSetCookie(headerValue, requestDomain, path);
- for (Cookie cookie : cookies) {
- if (! cookieValidator.isValid(cookie, requestDomain)) {
- log.trace("Ignoring invalid cookie %s", cookie);
- } else {
- log.trace("Adding cookie '%s' from domain '%s'", cookie, requestDomain);
- cookieMap.put(cookie.getKey(), cookie);
- }
+ final Cookie cookie = cookieParser.parseSetCookie(headerValue, domain, path);
+ if (! cookieValidator.isValid(cookie, domain)) {
+ log.trace("Ignoring invalid cookie %s", cookie);
+ } else {
+ log.trace("Adding cookie '%s' from domain '%s'", cookie, domain);
+ cookieMap.put(cookie.getKey(), cookie);
}
}
}
Deleted: remoting3/trunk/http/src/main/java/org/jboss/cx/remoting/http/cookie/CookieDomain.java
===================================================================
--- remoting3/trunk/http/src/main/java/org/jboss/cx/remoting/http/cookie/CookieDomain.java 2008-04-17 03:03:00 UTC (rev 4001)
+++ remoting3/trunk/http/src/main/java/org/jboss/cx/remoting/http/cookie/CookieDomain.java 2008-04-18 02:17:50 UTC (rev 4002)
@@ -1,87 +0,0 @@
-package org.jboss.cx.remoting.http.cookie;
-
-import java.io.Serializable;
-import java.util.Arrays;
-import org.jboss.cx.remoting.util.CollectionUtil;
-import static org.jboss.cx.remoting.util.CollectionUtil.split;
-import static org.jboss.cx.remoting.util.CollectionUtil.toArrayReversed;
-
-/**
- *
- */
-public final class CookieDomain implements Serializable {
-
- public static final CookieDomain LOCAL = new CookieDomain(".local");
-
- private static final long serialVersionUID = 1L;
-
- private final String[] parts;
- private final boolean hostDomainName;
-
- private CookieDomain(String[] parts, boolean hostDomainName) {
- this.parts = parts;
- this.hostDomainName = hostDomainName;
- }
-
- public CookieDomain(String domain) {
- if (domain == null) {
- throw new NullPointerException("domain is null");
- }
- if (domain.length() == 0) {
- throw new IllegalArgumentException("domain is empty");
- }
- hostDomainName = domain.charAt(0) == '.';
- final String baseDomain = hostDomainName ? domain.substring(1).toLowerCase() : domain.toLowerCase();
- parts = toArrayReversed(split(".", baseDomain).iterator(), String.class);
- }
-
- public boolean equals(final CookieDomain other) {
- return other != null && hostDomainName == other.hostDomainName && Arrays.equals(parts, other.parts);
- }
-
- public boolean equals(final Object other) {
- return other instanceof CookieDomain && equals((CookieDomain)other);
- }
-
- public int hashCode() {
- return Arrays.hashCode(parts) + (hostDomainName ? 1 : 0);
- }
-
- public String toString() {
- final StringBuilder builder = new StringBuilder(40);
- builder.append("Domain: ");
- for (String x : parts) {
- builder.append(x);
- builder.append('/');
- }
- builder.setLength(builder.length() - 1);
- return builder.toString();
- }
-
- public boolean matches(final CookieDomain other) {
- // todo this doesn't quite match rfc 2965
- return other.hostDomainName ? CollectionUtil.arrayStartsWith(parts, other.parts) : Arrays.equals(other.parts, parts);
- }
-
- public int getPartCount() {
- return parts.length;
- }
-
- public String getPart(int index) {
- return parts[index];
- }
-
- public boolean hasParent() {
- return parts.length > 1;
- }
-
- public boolean isHostDomainName() {
- return hostDomainName;
- }
-
- public CookieDomain getParent() {
- final String[] parentParts = new String[parts.length - 1];
- System.arraycopy(parts, 0, parentParts, 0, parentParts.length);
- return new CookieDomain(parentParts, false);
- }
-}
Modified: remoting3/trunk/http/src/main/java/org/jboss/cx/remoting/http/cookie/CookieMatcher.java
===================================================================
--- remoting3/trunk/http/src/main/java/org/jboss/cx/remoting/http/cookie/CookieMatcher.java 2008-04-17 03:03:00 UTC (rev 4001)
+++ remoting3/trunk/http/src/main/java/org/jboss/cx/remoting/http/cookie/CookieMatcher.java 2008-04-18 02:17:50 UTC (rev 4002)
@@ -14,5 +14,5 @@
* @param secure whether the request is on a secure channel
* @return {@code true} if the cookie should be sent
*/
- boolean matches(Cookie cookie, CookieDomain requestDomain, String path, boolean secure);
+ boolean matches(Cookie cookie, String requestDomain, String path, boolean secure);
}
Modified: remoting3/trunk/http/src/main/java/org/jboss/cx/remoting/http/cookie/CookieParser.java
===================================================================
--- remoting3/trunk/http/src/main/java/org/jboss/cx/remoting/http/cookie/CookieParser.java 2008-04-17 03:03:00 UTC (rev 4001)
+++ remoting3/trunk/http/src/main/java/org/jboss/cx/remoting/http/cookie/CookieParser.java 2008-04-18 02:17:50 UTC (rev 4002)
@@ -4,5 +4,5 @@
*
*/
public interface CookieParser {
- Cookie[] parseSetCookie(String setCookie, CookieDomain defaultDomain, String defaultPath);
+ Cookie parseSetCookie(String setCookie, String defaultDomain, String defaultPath);
}
Modified: remoting3/trunk/http/src/main/java/org/jboss/cx/remoting/http/cookie/CookieValidator.java
===================================================================
--- remoting3/trunk/http/src/main/java/org/jboss/cx/remoting/http/cookie/CookieValidator.java 2008-04-17 03:03:00 UTC (rev 4001)
+++ remoting3/trunk/http/src/main/java/org/jboss/cx/remoting/http/cookie/CookieValidator.java 2008-04-18 02:17:50 UTC (rev 4002)
@@ -9,8 +9,8 @@
* Determine whether a cookie from a server is valid.
*
* @param cookie the cookie from the server
- * @param fromDomain the actual domain that the request was sent to
+ * @param requestDomain the domain that the request was sent to
* @return {@code true} if the cookie is valid
*/
- boolean isValid(Cookie cookie, CookieDomain fromDomain);
+ boolean isValid(Cookie cookie, String requestDomain);
}
Modified: remoting3/trunk/http/src/main/java/org/jboss/cx/remoting/http/cookie/SimpleCookieMatcher.java
===================================================================
--- remoting3/trunk/http/src/main/java/org/jboss/cx/remoting/http/cookie/SimpleCookieMatcher.java 2008-04-17 03:03:00 UTC (rev 4001)
+++ remoting3/trunk/http/src/main/java/org/jboss/cx/remoting/http/cookie/SimpleCookieMatcher.java 2008-04-18 02:17:50 UTC (rev 4002)
@@ -5,12 +5,12 @@
*/
public final class SimpleCookieMatcher implements CookieMatcher {
- public boolean matches(final Cookie cookie, final CookieDomain requestDomain, final String path, final boolean secure) {
+ public boolean matches(final Cookie cookie, final String requestDomain, final String path, final boolean secure) {
final boolean cookieSecure = cookie.isSecure();
if (cookieSecure && ! secure) {
return false;
}
- final CookieDomain cookieDomain = cookie.getDomain();
+ final String cookieDomain = cookie.getDomain();
final String cookiePath = cookie.getPath();
return requestDomain.matches(cookieDomain) && path.startsWith(cookiePath) && !cookie.isExpired();
}
Modified: remoting3/trunk/http/src/main/java/org/jboss/cx/remoting/http/cookie/SimpleCookieParser.java
===================================================================
--- remoting3/trunk/http/src/main/java/org/jboss/cx/remoting/http/cookie/SimpleCookieParser.java 2008-04-17 03:03:00 UTC (rev 4001)
+++ remoting3/trunk/http/src/main/java/org/jboss/cx/remoting/http/cookie/SimpleCookieParser.java 2008-04-18 02:17:50 UTC (rev 4002)
@@ -2,9 +2,9 @@
import java.text.ParseException;
import java.text.SimpleDateFormat;
-import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
import org.jboss.cx.remoting.log.Logger;
-import org.jboss.cx.remoting.util.CollectionUtil;
/**
*
@@ -26,7 +26,10 @@
}
}
- public Cookie[] parseSetCookie(final String setCookie, final CookieDomain defaultDomain, final String defaultPath) {
+ private static final String PAIR_PATTERN_STRING = "(\\s*+[^=;]*?)(?:\\s+=\\s*+([^;]*?)\\s+)(?:;|$)";
+ private static final Pattern PAIR_PATTERN = Pattern.compile(PAIR_PATTERN_STRING);
+
+ public Cookie parseSetCookie(final String setCookie, final String defaultDomain, final String defaultPath) {
if (setCookie == null) {
throw new NullPointerException("setCookie is null");
}
@@ -36,48 +39,46 @@
if (defaultPath == null) {
throw new NullPointerException("defaultPath is null");
}
+ final Matcher matcher = PAIR_PATTERN.matcher(setCookie);
+ if (! matcher.find()) {
+ return null; // no cookie!
+ }
+ final String name = matcher.group(1);
+ final String value = matcher.group(2);
+ if (name == null || value == null) {
+ return null; // no cookie!
+ }
boolean secure = false;
long expires = 0L;
- CookieDomain domain = defaultDomain;
String path = defaultPath;
- List<Pair> pairs = CollectionUtil.arrayList();
- for (final String s : CollectionUtil.split(";", setCookie)) {
- final String assignment = s.trim();
- final int equalsPos = assignment.indexOf('=');
- if (equalsPos == -1) {
- if (assignment.toLowerCase().equals("secure")) {
- secure = true;
- continue;
+ String domain = defaultDomain;
+ while (matcher.find()) {
+ final String attrName = matcher.group(1);
+ final String attrValue = matcher.group(2);
+ if ("secure".equalsIgnoreCase(attrName) && attrValue == null) {
+ secure = true;
+ } else if ("expires".equalsIgnoreCase(attrName) && attrValue != null) {
+ final int gmti = value.lastIndexOf(" GMT");
+ final String dateValue;
+ if (gmti != -1) {
+ dateValue = attrValue.substring(0, gmti);
+ } else {
+ dateValue = attrValue;
}
+ final SimpleDateFormat dateFormat = new SimpleDateFormat(DATE_FORMAT);
+ try {
+ expires = dateFormat.parse(dateValue).getTime();
+ } catch (ParseException e) {
+ log.trace("Invalid cookie expiration date '%s'", value);
+ }
+ } else if ("domain".equalsIgnoreCase(attrName) && attrValue != null) {
+ domain = attrValue;
+ } else if ("path".equalsIgnoreCase(attrName) && attrValue != null) {
+ path = attrValue;
} else {
- String name = assignment.substring(0, equalsPos).trim();
- String lowerName = name.toLowerCase();
- String value = assignment.substring(equalsPos + 1).trim();
- if (lowerName.equals("expires")) {
- final int gmti = value.lastIndexOf(" GMT");
- if (gmti != -1) {
- value = value.substring(0, gmti);
- }
- final SimpleDateFormat dateFormat = new SimpleDateFormat(DATE_FORMAT);
- try {
- expires = dateFormat.parse(value).getTime();
- } catch (ParseException e) {
- log.trace("Invalid cookie expiration date '%s'", value);
- }
- } else if (lowerName.equals("domain")) {
- domain = new CookieDomain(value);
- } else if (lowerName.equals("path")) {
- path = value;
- } else {
- pairs.add(new Pair(name, value));
- }
+ log.trace("Unknown cookie attribute-value pair: \"%s\"=\"%s\"", attrName, attrValue);
}
}
- Cookie[] cookies = new Cookie[pairs.size()];
- int i = 0;
- for (Pair pair : pairs) {
- cookies[i++] = new Cookie(pair.name, pair.value, path, domain, expires, secure);
- }
- return cookies;
+ return new Cookie(name, value, path, domain, expires, secure);
}
}
Modified: remoting3/trunk/http/src/main/java/org/jboss/cx/remoting/http/cookie/SimpleCookieValidator.java
===================================================================
--- remoting3/trunk/http/src/main/java/org/jboss/cx/remoting/http/cookie/SimpleCookieValidator.java 2008-04-17 03:03:00 UTC (rev 4001)
+++ remoting3/trunk/http/src/main/java/org/jboss/cx/remoting/http/cookie/SimpleCookieValidator.java 2008-04-18 02:17:50 UTC (rev 4002)
@@ -3,6 +3,8 @@
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
+import java.util.regex.Pattern;
+import org.jboss.cx.remoting.log.Logger;
/**
* Simple cookie validator. Validates a cookie coming down from a server. See
@@ -10,8 +12,13 @@
* for more info.
*/
public final class SimpleCookieValidator implements CookieValidator {
+ private static final String DOMAIN_PATTERN_STRING = "^(?:(?:[a-zA-Z0-9][a-zA-Z0-9]+)(?:-(?:[a-zA-Z0-9][a-zA-Z0-9]+))*(?:\\.(?:(?:[a-zA-Z0-9][a-zA-Z0-9]+)(?:-(?:[a-zA-Z0-9][a-zA-Z0-9]+))*)+$";
+ private static final Pattern DOMAIN_PATTERN = Pattern.compile(DOMAIN_PATTERN_STRING);
+
private static final Set<String> TLD_SET;
+ private static final Logger log = Logger.getLogger(SimpleCookieValidator.class);
+
static {
final HashSet<String> tldSet = new HashSet<String>();
tldSet.add("com");
@@ -24,29 +31,49 @@
TLD_SET = Collections.unmodifiableSet(tldSet);
}
- public boolean isValid(final Cookie cookie, final CookieDomain requestDomain) {
- final CookieDomain cookieDomain = cookie.getDomain();
- for (int i = 0; i < cookieDomain.getPartCount(); i++) {
- if (cookieDomain.getPart(i).length() == 0) {
- return false;
- }
+ private static void logReject(Cookie cookie, String requestDomain, String reason) {
+ log.trace("Rejecting cookie \"%s\" from request domain \"%s\": %s", cookie.getName(), requestDomain, reason);
+ }
+
+ public boolean isValid(final Cookie cookie, final String requestDomain) {
+
+ final String cookieDomain = cookie.getDomain();
+ final String matchDomain;
+ if (cookieDomain.length() == 0) {
+ logReject(cookie, requestDomain, "cookie domain length is zero");
+ return false;
}
- final int numParts = cookieDomain.getPartCount() + (cookieDomain.isHostDomainName() ? 1 : 0);
- final String tld = numParts == 0 ? null : cookieDomain.getPart(0);
- final int minSegments = TLD_SET.contains(tld) ? 3 : 4;
- if (numParts < minSegments) {
- // not valid: domain name is too short
+ if (cookieDomain.charAt(0) == '.') {
+ matchDomain = cookieDomain.substring(1);
+ } else {
+ matchDomain = cookieDomain;
+ }
+ if (! DOMAIN_PATTERN.matcher(matchDomain).matches()) {
+ logReject(cookie, requestDomain, "cookie has an invalid domain");
return false;
}
+ final String effectiveDomain;
+ if (matchDomain.indexOf('.') == -1) {
+ effectiveDomain = matchDomain + ".local";
+ } else {
+ effectiveDomain = matchDomain;
+ }
+ final String tld = effectiveDomain.substring(effectiveDomain.lastIndexOf('.') + 1);
+ final int minDots = TLD_SET.contains(tld) ? 1 : 2;
+ int dotCount = 0;
+ for (int p = effectiveDomain.indexOf('.', 0); p != -1; p = effectiveDomain.indexOf('.', p + 1)) {
+ dotCount ++;
+ }
+ if (dotCount < minDots) {
+ logReject(cookie, requestDomain, "cookie domain name is too short (see http://wp.netscape.com/newsref/std/cookie_spec.html)");
+ return false;
+ }
final String path = cookie.getPath();
if (path.length() == 0 || path.charAt(0) != '/') {
- // not valid: bad or missing path
+ logReject(cookie, requestDomain, "cookie path is invalid");
return false;
}
- if (! requestDomain.matches(cookieDomain)) {
- // wrong domain
- return false;
- }
+ log.trace("Accepting cookie \"%s\" from request domain \"%s\"", cookie.getName(), requestDomain);
return true;
}
}
More information about the jboss-remoting-commits
mailing list