package org.glassfish.grizzly.http.util;
import static org.glassfish.grizzly.http.util.CookieUtils.ALWAYS_ADD_EXPIRES;
import static org.glassfish.grizzly.http.util.CookieUtils.COOKIE_VERSION_ONE_STRICT_COMPLIANCE;
import static org.glassfish.grizzly.http.util.CookieUtils.OLD_COOKIE_FORMAT;
import static org.glassfish.grizzly.http.util.CookieUtils.RFC_6265_SUPPORT_ENABLED;
import static org.glassfish.grizzly.http.util.CookieUtils.ancientDate;
import static org.glassfish.grizzly.http.util.CookieUtils.containsCTL;
import static org.glassfish.grizzly.http.util.CookieUtils.isToken;
import static org.glassfish.grizzly.http.util.CookieUtils.isToken2;
import static org.glassfish.grizzly.http.util.CookieUtils.tspecials2NoSlash;
import java.nio.BufferOverflowException;
import java.util.Date;
import org.glassfish.grizzly.Buffer;
import org.glassfish.grizzly.http.Cookie;
public class CookieSerializerUtils {
public static void serializeServerCookie(StringBuilder buf, Cookie cookie) {
serializeServerCookie(buf, COOKIE_VERSION_ONE_STRICT_COMPLIANCE, RFC_6265_SUPPORT_ENABLED, ALWAYS_ADD_EXPIRES, cookie);
}
public static void serializeServerCookie(final StringBuilder buf, final boolean versionOneStrictCompliance, final boolean rfc6265Support,
final boolean alwaysAddExpires, final Cookie cookie) {
serializeServerCookie(buf, versionOneStrictCompliance, rfc6265Support, alwaysAddExpires, cookie.getName(), cookie.getValue(), cookie.getVersion(),
cookie.getPath(), cookie.getDomain(), cookie.getComment(), cookie.getMaxAge(), cookie.isSecure(), cookie.isHttpOnly());
}
public static void serializeServerCookie(final StringBuilder buf, final boolean versionOneStrictCompliance, final boolean rfc6265Support,
final boolean alwaysAddExpires, final String name, final String value, int version, String path, final String domain, final String comment,
final int maxAge, final boolean isSecure, final boolean isHttpOnly) {
buf.append(name);
buf.append('=');
version = maybeQuote2(version, buf, value, true, rfc6265Support);
if (version == 1) {
buf.append("; Version=1");
if (comment != null) {
buf.append("; Comment=");
maybeQuote2(version, buf, comment, versionOneStrictCompliance, rfc6265Support);
}
}
if (domain != null) {
buf.append("; Domain=");
maybeQuote2(version, buf, domain, versionOneStrictCompliance, rfc6265Support);
}
if (maxAge >= 0) {
if (version > 0) {
buf.append("; Max-Age=");
buf.append(maxAge);
}
if (version == 0 || alwaysAddExpires) {
buf.append("; Expires=");
if (maxAge == 0) {
buf.append(ancientDate);
} else {
buf.append(OLD_COOKIE_FORMAT.get().format(new Date(System.currentTimeMillis() + maxAge * 1000L)));
}
}
}
if (path != null) {
buf.append("; Path=");
UEncoder encoder = new UEncoder();
encoder.addSafeCharacter('/');
encoder.addSafeCharacter('"');
path = encoder.encodeURL(path, true);
if (version == 0) {
maybeQuote2(version, buf, path, versionOneStrictCompliance, rfc6265Support);
} else {
maybeQuote2(version, buf, path, tspecials2NoSlash, false, versionOneStrictCompliance, rfc6265Support);
}
}
if (isSecure) {
buf.append("; Secure");
}
if (isHttpOnly) {
buf.append("; HttpOnly");
}
}
public static void serializeServerCookie(Buffer buf, Cookie cookie) {
serializeServerCookie(buf, COOKIE_VERSION_ONE_STRICT_COMPLIANCE, ALWAYS_ADD_EXPIRES, cookie);
}
public static void serializeServerCookie(Buffer buf, boolean versionOneStrictCompliance, boolean alwaysAddExpires, Cookie cookie) {
serializeServerCookie(buf, versionOneStrictCompliance, alwaysAddExpires, cookie.getName(), cookie.getValue(), cookie.getVersion(), cookie.getPath(),
cookie.getDomain(), cookie.getComment(), cookie.getMaxAge(), cookie.isSecure(), cookie.isHttpOnly());
}
public static void serializeServerCookie(final Buffer buf, final boolean versionOneStrictCompliance, final boolean alwaysAddExpires, final String name,
final String value, int version, String path, final String domain, final String comment, final int maxAge, final boolean isSecure,
final boolean isHttpOnly) {
put(buf, name);
put(buf, '=');
version = maybeQuote2(version, buf, value, true);
if (version == 1) {
put(buf, "; Version=1");
if (comment != null) {
put(buf, "; Comment=");
maybeQuote2(version, buf, comment, versionOneStrictCompliance);
}
}
if (domain != null) {
put(buf, "; Domain=");
maybeQuote2(version, buf, domain, versionOneStrictCompliance);
}
if (maxAge >= 0) {
if (version > 0) {
put(buf, "; Max-Age=");
putInt(buf, maxAge);
}
if (version == 0 || alwaysAddExpires) {
put(buf, "; Expires=");
if (maxAge == 0) {
put(buf, ancientDate);
} else {
put(buf, OLD_COOKIE_FORMAT.get().format(new Date(System.currentTimeMillis() + maxAge * 1000L)));
}
}
}
if (path != null) {
put(buf, "; Path=");
UEncoder encoder = new UEncoder();
encoder.addSafeCharacter('/');
encoder.addSafeCharacter('"');
path = encoder.encodeURL(path, true);
if (version == 0) {
maybeQuote2(version, buf, path, versionOneStrictCompliance);
} else {
maybeQuote2(version, buf, path, tspecials2NoSlash, false, versionOneStrictCompliance);
}
}
if (isSecure) {
put(buf, "; Secure");
}
if (isHttpOnly) {
put(buf, "; HttpOnly");
}
}
public static void serializeClientCookies(StringBuilder buf, Cookie... cookies) {
serializeClientCookies(buf, COOKIE_VERSION_ONE_STRICT_COMPLIANCE, RFC_6265_SUPPORT_ENABLED, cookies);
}
public static void serializeClientCookies(StringBuilder buf, boolean versionOneStrictCompliance, boolean rfc6265Support, Cookie... cookies) {
if (cookies.length == 0) {
return;
}
final int version = cookies[0].getVersion();
if (!rfc6265Support && version == 1) {
buf.append("$Version=\"1\"; ");
}
for (int i = 0; i < cookies.length; i++) {
final Cookie cookie = cookies[i];
buf.append(cookie.getName());
buf.append('=');
maybeQuote2(version, buf, cookie.getValue(), true, rfc6265Support);
if (!rfc6265Support && version == 1) {
final String domain = cookie.getDomain();
if (domain != null) {
buf.append("; $Domain=");
maybeQuote2(version, buf, domain, versionOneStrictCompliance, rfc6265Support);
}
String path = cookie.getPath();
if (path != null) {
buf.append("; $Path=");
UEncoder encoder = new UEncoder();
encoder.addSafeCharacter('/');
encoder.addSafeCharacter('"');
path = encoder.encodeURL(path, true);
maybeQuote2(version, buf, path, tspecials2NoSlash, false, versionOneStrictCompliance, rfc6265Support);
}
}
if (i < cookies.length - 1) {
buf.append("; ");
}
}
}
public static void serializeClientCookies(Buffer buf, Cookie... cookies) {
serializeClientCookies(buf, COOKIE_VERSION_ONE_STRICT_COMPLIANCE, cookies);
}
public static void serializeClientCookies(Buffer buf, boolean versionOneStrictCompliance, Cookie... cookies) {
if (cookies.length == 0) {
return;
}
final int version = cookies[0].getVersion();
if (version == 1) {
put(buf, "$Version=\"1\"; ");
}
for (int i = 0; i < cookies.length; i++) {
final Cookie cookie = cookies[i];
put(buf, cookie.getName());
put(buf, "=");
maybeQuote2(version, buf, cookie.getValue(), true);
if (version == 1) {
final String domain = cookie.getDomain();
if (domain != null) {
put(buf, "; $Domain=");
maybeQuote2(version, buf, domain, versionOneStrictCompliance);
}
String path = cookie.getPath();
if (path != null) {
put(buf, "; $Path=");
UEncoder encoder = new UEncoder();
encoder.addSafeCharacter('/');
encoder.addSafeCharacter('"');
path = encoder.encodeURL(path, true);
maybeQuote2(version, buf, path, tspecials2NoSlash, false, versionOneStrictCompliance);
}
}
if (i < cookies.length - 1) {
put(buf, "; ");
}
}
}
public static int maybeQuote2(int version, StringBuilder buf, String value, boolean versionOneStrictCompliance, boolean rfc6265Enabled) {
return maybeQuote2(version, buf, value, false, versionOneStrictCompliance, rfc6265Enabled);
}
public static int maybeQuote2(int version, StringBuilder buf, String value, boolean allowVersionSwitch, boolean versionOneStrictCompliance,
boolean rfc6265Enabled) {
return maybeQuote2(version, buf, value, null, allowVersionSwitch, versionOneStrictCompliance, rfc6265Enabled);
}
public static int maybeQuote2(int version, StringBuilder buf, String value, String literals, boolean allowVersionSwitch, boolean versionOneStrictCompliance,
boolean rfc6265Enabled) {
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 (allowVersionSwitch && versionOneStrictCompliance && version == 0 && !isToken2(value, literals)) {
buf.append('"');
buf.append(escapeDoubleQuotes(value, 0, value.length()));
buf.append('"');
version = 1;
} else if (version == 0 && !isToken(value, literals)) {
buf.append('"');
buf.append(escapeDoubleQuotes(value, 0, value.length()));
buf.append('"');
} else if (version == 1 && !isToken2(value, literals)) {
buf.append('"');
buf.append(escapeDoubleQuotes(value, 0, value.length()));
buf.append('"');
} else if (version < 0 && rfc6265Enabled) {
buf.append('"');
buf.append(escapeDoubleQuotes(value, 0, value.length()));
buf.append('"');
} else {
buf.append(value);
}
return version;
}
public static int maybeQuote2(int version, Buffer buf, String value, boolean versionOneStrictCompliance) {
return maybeQuote2(version, buf, value, false, versionOneStrictCompliance);
}
public static int maybeQuote2(int version, Buffer buf, String value, boolean allowVersionSwitch, boolean versionOneStrictCompliance) {
return maybeQuote2(version, buf, value, null, allowVersionSwitch, versionOneStrictCompliance);
}
public static int maybeQuote2(int version, Buffer buf, String value, String literals, boolean allowVersionSwitch, boolean versionOneStrictCompliance) {
if (value == null || value.length() == 0) {
put(buf, "\"\"");
} else if (containsCTL(value, version)) {
throw new IllegalArgumentException("Control character in cookie value, consider BASE64 encoding your value");
} else if (alreadyQuoted(value)) {
put(buf, '"');
put(buf, escapeDoubleQuotes(value, 1, value.length() - 1));
put(buf, '"');
} else if (allowVersionSwitch && versionOneStrictCompliance && version == 0 && !isToken2(value, literals)) {
put(buf, '"');
put(buf, escapeDoubleQuotes(value, 0, value.length()));
put(buf, '"');
version = 1;
} else if (version == 0 && !isToken(value, literals)) {
put(buf, '"');
put(buf, escapeDoubleQuotes(value, 0, value.length()));
put(buf, '"');
} else if (version == 1 && !isToken2(value, literals)) {
put(buf, '"');
put(buf, escapeDoubleQuotes(value, 0, value.length()));
put(buf, '"');
} else {
put(buf, value);
}
return version;
}
private static String escapeDoubleQuotes(String s, int beginIndex, int endIndex) {
if (s == null || s.length() == 0 || s.indexOf('"') == -1) {
return s;
}
StringBuilder b = new StringBuilder();
for (int i = beginIndex; i < endIndex; i++) {
char c = s.charAt(i);
if (c == '\\') {
b.append(c);
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);
}
}
return b.toString();
}
public static boolean alreadyQuoted(String value) {
return !(value == null || value.length() == 0) && value.charAt(0) == '\"' && value.charAt(value.length() - 1) == '\"';
}
static void put(Buffer dstBuffer, int c) {
dstBuffer.put((byte) c);
}
static void putInt(Buffer dstBuffer, int intValue) {
put(dstBuffer, Integer.toString(intValue));
}
static void put(Buffer dstBuffer, String s) {
final int size = s.length();
if (dstBuffer.remaining() < size) {
throw new BufferOverflowException();
}
for (int i = 0; i < size; i++) {
dstBuffer.put((byte) s.charAt(i));
}
}
static void put(StringBuilder dstBuffer, int c) {
dstBuffer.append((char) c);
}
static void putInt(StringBuilder dstBuffer, int intValue) {
dstBuffer.append(intValue);
}
static void put(StringBuilder dstBuffer, String s) {
dstBuffer.append(s);
}
}