一、前言
关于netty的netty-codec-http源码包中的io.netty.handler.codec.http.CookieDecoder、io.netty.handler.codec.http.CookieEncoder、io.netty.handler.codec.http.CookieUtil等cookie处理类,对cookie加密解密处理(对cookies数组、字符串写入数据等)、有效性校验验证等。
二、源码说明
1.Cookie接口类及默认DefaultCookie实现类
package io.netty.handler.codec.http.cookie;@b@@b@public abstract interface Cookie extends Comparable<Cookie>@b@{@b@ public static final long UNDEFINED_MAX_AGE = -9223372036854775808L;@b@@b@ public abstract String name();@b@@b@ public abstract String value();@b@@b@ public abstract void setValue(String paramString);@b@@b@ public abstract boolean wrap();@b@@b@ public abstract void setWrap(boolean paramBoolean);@b@@b@ public abstract String domain();@b@@b@ public abstract void setDomain(String paramString);@b@@b@ public abstract String path();@b@@b@ public abstract void setPath(String paramString);@b@@b@ public abstract long maxAge();@b@@b@ public abstract void setMaxAge(long paramLong);@b@@b@ public abstract boolean isSecure();@b@@b@ public abstract void setSecure(boolean paramBoolean);@b@@b@ public abstract boolean isHttpOnly();@b@@b@ public abstract void setHttpOnly(boolean paramBoolean);@b@}
package io.netty.handler.codec.http.cookie;@b@@b@import io.netty.util.internal.ObjectUtil;@b@@b@public class DefaultCookie@b@ implements Cookie@b@{@b@ private final String name;@b@ private String value;@b@ private boolean wrap;@b@ private String domain;@b@ private String path;@b@ private long maxAge = -9223372036854775808L;@b@ private boolean secure;@b@ private boolean httpOnly;@b@@b@ public DefaultCookie(String name, String value)@b@ {@b@ name = ((String)ObjectUtil.checkNotNull(name, "name")).trim();@b@ if (name.isEmpty())@b@ throw new IllegalArgumentException("empty name");@b@@b@ this.name = name;@b@ setValue(value);@b@ }@b@@b@ public String name()@b@ {@b@ return this.name;@b@ }@b@@b@ public String value()@b@ {@b@ return this.value;@b@ }@b@@b@ public void setValue(String value)@b@ {@b@ this.value = ((String)ObjectUtil.checkNotNull(value, "value"));@b@ }@b@@b@ public boolean wrap()@b@ {@b@ return this.wrap;@b@ }@b@@b@ public void setWrap(boolean wrap)@b@ {@b@ this.wrap = wrap;@b@ }@b@@b@ public String domain()@b@ {@b@ return this.domain;@b@ }@b@@b@ public void setDomain(String domain)@b@ {@b@ this.domain = CookieUtil.validateAttributeValue("domain", domain);@b@ }@b@@b@ public String path()@b@ {@b@ return this.path;@b@ }@b@@b@ public void setPath(String path)@b@ {@b@ this.path = CookieUtil.validateAttributeValue("path", path);@b@ }@b@@b@ public long maxAge()@b@ {@b@ return this.maxAge;@b@ }@b@@b@ public void setMaxAge(long maxAge)@b@ {@b@ this.maxAge = maxAge;@b@ }@b@@b@ public boolean isSecure()@b@ {@b@ return this.secure;@b@ }@b@@b@ public void setSecure(boolean secure)@b@ {@b@ this.secure = secure;@b@ }@b@@b@ public boolean isHttpOnly()@b@ {@b@ return this.httpOnly;@b@ }@b@@b@ public void setHttpOnly(boolean httpOnly)@b@ {@b@ this.httpOnly = httpOnly;@b@ }@b@@b@ public int hashCode()@b@ {@b@ return name().hashCode();@b@ }@b@@b@ public boolean equals(Object o)@b@ {@b@ if (this == o) {@b@ return true;@b@ }@b@@b@ if (!(o instanceof Cookie)) {@b@ return false;@b@ }@b@@b@ Cookie that = (Cookie)o;@b@ if (!(name().equals(that.name()))) {@b@ return false;@b@ }@b@@b@ if (path() == null) {@b@ if (that.path() == null) break label86;@b@ return false;@b@ }@b@ if (that.path() == null)@b@ return false;@b@ if (!(path().equals(that.path()))) {@b@ return false;@b@ }@b@@b@ if (domain() == null) {@b@ label86: if (that.domain() == null) break label118;@b@ return false;@b@ }@b@@b@ return domain().equalsIgnoreCase(that.domain());@b@@b@ label118: return true;@b@ }@b@@b@ public int compareTo(Cookie c)@b@ {@b@ int v = name().compareTo(c.name());@b@ if (v != 0) {@b@ return v;@b@ }@b@@b@ if (path() == null) {@b@ if (c.path() == null) break label69;@b@ return -1;@b@ }@b@ if (c.path() == null)@b@ return 1;@b@@b@ v = path().compareTo(c.path());@b@ if (v != 0) {@b@ return v;@b@ }@b@@b@ if (domain() == null) {@b@ label69: if (c.domain() == null) break label114;@b@ return -1;@b@ }@b@ if (c.domain() == null)@b@ return 1;@b@@b@ v = domain().compareToIgnoreCase(c.domain());@b@ return v;@b@@b@ label114: return 0;@b@ }@b@@b@ @Deprecated@b@ protected String validateValue(String name, String value)@b@ {@b@ return CookieUtil.validateAttributeValue(name, value);@b@ }@b@@b@ public String toString()@b@ {@b@ StringBuilder buf = CookieUtil.stringBuilder()@b@ .append(name())@b@ .append('=')@b@ .append(value());@b@ if (domain() != null)@b@ buf.append(", domain=")@b@ .append(domain());@b@@b@ if (path() != null)@b@ buf.append(", path=")@b@ .append(path());@b@@b@ if (maxAge() >= 0L) {@b@ buf.append(", maxAge=")@b@ .append(maxAge())@b@ .append('s');@b@ }@b@@b@ if (isSecure())@b@ buf.append(", secure");@b@@b@ if (isHttpOnly())@b@ buf.append(", HTTPOnly");@b@@b@ return buf.toString();@b@ }@b@}
2.加解密CookieEncoder、CookieDecoder类
package io.netty.handler.codec.http.cookie;@b@@b@public abstract class CookieEncoder@b@{@b@ protected final boolean strict;@b@@b@ protected CookieEncoder(boolean strict)@b@ {@b@ this.strict = strict;@b@ }@b@@b@ protected void validateCookie(String name, String value) {@b@ if (this.strict)@b@ {@b@ int pos;@b@ if ((pos = CookieUtil.firstInvalidCookieNameOctet(name)) >= 0) {@b@ throw new IllegalArgumentException("Cookie name contains an invalid char: " + name.charAt(pos));@b@ }@b@@b@ CharSequence unwrappedValue = CookieUtil.unwrapValue(value);@b@ if (unwrappedValue == null) {@b@ throw new IllegalArgumentException("Cookie value wrapping quotes are not balanced: " + value);@b@ }@b@@b@ if ((pos = CookieUtil.firstInvalidCookieValueOctet(unwrappedValue)) >= 0)@b@ throw new IllegalArgumentException("Cookie value contains an invalid char: " + value.charAt(pos));@b@ }@b@ }@b@}
package io.netty.handler.codec.http.cookie;@b@@b@import io.netty.util.internal.logging.InternalLogger;@b@import io.netty.util.internal.logging.InternalLoggerFactory;@b@import java.nio.CharBuffer;@b@@b@public abstract class CookieDecoder@b@{@b@ private final InternalLogger logger = InternalLoggerFactory.getInstance(super.getClass());@b@ private final boolean strict;@b@@b@ protected CookieDecoder(boolean strict)@b@ {@b@ this.strict = strict;@b@ }@b@@b@ protected DefaultCookie initCookie(String header, int nameBegin, int nameEnd, int valueBegin, int valueEnd) {@b@ int invalidOctetPos;@b@ if ((nameBegin == -1) || (nameBegin == nameEnd)) {@b@ this.logger.debug("Skipping cookie with null name");@b@ return null;@b@ }@b@@b@ if (valueBegin == -1) {@b@ this.logger.debug("Skipping cookie with null value");@b@ return null;@b@ }@b@@b@ CharSequence wrappedValue = CharBuffer.wrap(header, valueBegin, valueEnd);@b@ CharSequence unwrappedValue = CookieUtil.unwrapValue(wrappedValue);@b@ if (unwrappedValue == null) {@b@ this.logger.debug("Skipping cookie because starting quotes are not properly balanced in '{}'", wrappedValue);@b@@b@ return null;@b@ }@b@@b@ String name = header.substring(nameBegin, nameEnd);@b@@b@ if (this.strict) if ((invalidOctetPos = CookieUtil.firstInvalidCookieNameOctet(name)) >= 0) {@b@ if (this.logger.isDebugEnabled()) {@b@ this.logger.debug("Skipping cookie because name '{}' contains invalid char '{}'", name, @b@ Character.valueOf(name@b@ .charAt(invalidOctetPos)));@b@ }@b@@b@ return null;@b@ }@b@@b@ boolean wrap = unwrappedValue.length() != valueEnd - valueBegin;@b@@b@ if (this.strict) if ((invalidOctetPos = CookieUtil.firstInvalidCookieValueOctet(unwrappedValue)) >= 0) {@b@ if (this.logger.isDebugEnabled()) {@b@ this.logger.debug("Skipping cookie because value '{}' contains invalid char '{}'", unwrappedValue, @b@ Character.valueOf(unwrappedValue@b@ .charAt(invalidOctetPos)));@b@ }@b@@b@ return null;@b@ }@b@@b@ DefaultCookie cookie = new DefaultCookie(name, unwrappedValue.toString());@b@ cookie.setWrap(wrap);@b@ return cookie;@b@ }@b@}
3.CookieUtil工具类
package io.netty.handler.codec.http.cookie;@b@@b@import io.netty.util.internal.InternalThreadLocalMap;@b@import java.util.BitSet;@b@@b@final class CookieUtil@b@{@b@ private static final BitSet VALID_COOKIE_NAME_OCTETS = validCookieNameOctets();@b@ private static final BitSet VALID_COOKIE_VALUE_OCTETS = validCookieValueOctets();@b@ private static final BitSet VALID_COOKIE_ATTRIBUTE_VALUE_OCTETS = validCookieAttributeValueOctets();@b@@b@ private static BitSet validCookieNameOctets()@b@ {@b@ BitSet bits = new BitSet();@b@ for (int i = 32; i < 127; ++i)@b@ bits.set(i);@b@@b@ int[] separators = { 40, 41, 60, 62, 64, 44, 59, 58, 92, 34, 47, 91, 93, 63, 61, 123, 125, 32, 9 };@b@@b@ int[] arrayOfInt1 = separators; int i = arrayOfInt1.length; for (int j = 0; j < i; ++j) { int separator = arrayOfInt1[j];@b@ bits.set(separator, false);@b@ }@b@ return bits;@b@ }@b@@b@ private static BitSet validCookieValueOctets()@b@ {@b@ BitSet bits = new BitSet();@b@ bits.set(33);@b@ for (int i = 35; i <= 43; ++i)@b@ bits.set(i);@b@@b@ for (i = 45; i <= 58; ++i)@b@ bits.set(i);@b@@b@ for (i = 60; i <= 91; ++i)@b@ bits.set(i);@b@@b@ for (i = 93; i <= 126; ++i)@b@ bits.set(i);@b@@b@ return bits;@b@ }@b@@b@ private static BitSet validCookieAttributeValueOctets()@b@ {@b@ BitSet bits = new BitSet();@b@ for (int i = 32; i < 127; ++i)@b@ bits.set(i);@b@@b@ bits.set(59, false);@b@ return bits;@b@ }@b@@b@ static StringBuilder stringBuilder() {@b@ return InternalThreadLocalMap.get().stringBuilder();@b@ }@b@@b@ static String stripTrailingSeparatorOrNull(StringBuilder buf)@b@ {@b@ return ((buf.length() == 0) ? null : stripTrailingSeparator(buf));@b@ }@b@@b@ static String stripTrailingSeparator(StringBuilder buf) {@b@ if (buf.length() > 0)@b@ buf.setLength(buf.length() - 2);@b@@b@ return buf.toString();@b@ }@b@@b@ static void add(StringBuilder sb, String name, long val) {@b@ sb.append(name);@b@ sb.append('=');@b@ sb.append(val);@b@ sb.append(';');@b@ sb.append(' ');@b@ }@b@@b@ static void add(StringBuilder sb, String name, String val) {@b@ sb.append(name);@b@ sb.append('=');@b@ sb.append(val);@b@ sb.append(';');@b@ sb.append(' ');@b@ }@b@@b@ static void add(StringBuilder sb, String name) {@b@ sb.append(name);@b@ sb.append(';');@b@ sb.append(' ');@b@ }@b@@b@ static void addQuoted(StringBuilder sb, String name, String val) {@b@ if (val == null) {@b@ val = "";@b@ }@b@@b@ sb.append(name);@b@ sb.append('=');@b@ sb.append('"');@b@ sb.append(val);@b@ sb.append('"');@b@ sb.append(';');@b@ sb.append(' ');@b@ }@b@@b@ static int firstInvalidCookieNameOctet(CharSequence cs) {@b@ return firstInvalidOctet(cs, VALID_COOKIE_NAME_OCTETS);@b@ }@b@@b@ static int firstInvalidCookieValueOctet(CharSequence cs) {@b@ return firstInvalidOctet(cs, VALID_COOKIE_VALUE_OCTETS);@b@ }@b@@b@ static int firstInvalidOctet(CharSequence cs, BitSet bits) {@b@ for (int i = 0; i < cs.length(); ++i) {@b@ char c = cs.charAt(i);@b@ if (!(bits.get(c)))@b@ return i;@b@ }@b@@b@ return -1;@b@ }@b@@b@ static CharSequence unwrapValue(CharSequence cs) {@b@ int len = cs.length();@b@ if ((len > 0) && (cs.charAt(0) == '"')) {@b@ if ((len >= 2) && (cs.charAt(len - 1) == '"'))@b@ {@b@ return ((len == 2) ? "" : cs.subSequence(1, len - 1));@b@ }@b@ return null;@b@ }@b@@b@ return cs;@b@ }@b@@b@ static String validateAttributeValue(String name, String value) {@b@ if (value == null)@b@ return null;@b@@b@ value = value.trim();@b@ if (value.isEmpty())@b@ return null;@b@@b@ int i = firstInvalidOctet(value, VALID_COOKIE_ATTRIBUTE_VALUE_OCTETS);@b@ if (i != -1)@b@ throw new IllegalArgumentException(name + " contains the prohibited characters: " + value.charAt(i));@b@@b@ return value;@b@ }@b@}
4.对于服务端相关加解密类ServerCookieEncoder、ServerCookieDecoder及客户端加解密类ClientCookieEncoder、ClientCookieDecoder参见源码包