Add ! to allowed cookie value chars
Motivation: ! is missing from allowed cookie value chars, as per https://tools.ietf.org/html/rfc6265#section-4.1.1. Issue was originally reported on Play!, see https://github.com/playframework/playframework/issues/4460#issuecomment-198177302. Modifications: Stick to RFC6265 ranges. Result: RFC6265 compliance, ! is supported
This commit is contained in:
parent
0320ccb59f
commit
d747438366
@ -24,19 +24,25 @@ final class CookieUtil {
|
|||||||
|
|
||||||
private static final BitSet VALID_COOKIE_VALUE_OCTETS = validCookieValueOctets();
|
private static final BitSet VALID_COOKIE_VALUE_OCTETS = validCookieValueOctets();
|
||||||
|
|
||||||
private static final BitSet VALID_COOKIE_NAME_OCTETS = validCookieNameOctets(VALID_COOKIE_VALUE_OCTETS);
|
private static final BitSet VALID_COOKIE_NAME_OCTETS = validCookieNameOctets();
|
||||||
|
|
||||||
|
// cookie-octet = %x21 / %x23-2B / %x2D-3A / %x3C-5B / %x5D-7E
|
||||||
// US-ASCII characters excluding CTLs, whitespace, DQUOTE, comma, semicolon, and backslash
|
// US-ASCII characters excluding CTLs, whitespace, DQUOTE, comma, semicolon, and backslash
|
||||||
private static BitSet validCookieValueOctets() {
|
private static BitSet validCookieValueOctets() {
|
||||||
BitSet bits = new BitSet(8);
|
BitSet bits = new BitSet();
|
||||||
for (int i = 35; i < 127; i++) {
|
bits.set(0x21);
|
||||||
// US-ASCII characters excluding CTLs (%x00-1F / %x7F)
|
for (int i = 0x23; i <= 0x2B; i++) {
|
||||||
|
bits.set(i);
|
||||||
|
}
|
||||||
|
for (int i = 0x2D; i <= 0x3A; i++) {
|
||||||
|
bits.set(i);
|
||||||
|
}
|
||||||
|
for (int i = 0x3C; i <= 0x5B; i++) {
|
||||||
|
bits.set(i);
|
||||||
|
}
|
||||||
|
for (int i = 0x5D; i <= 0x7E; i++) {
|
||||||
bits.set(i);
|
bits.set(i);
|
||||||
}
|
}
|
||||||
bits.set('"', false); // exclude DQUOTE = %x22
|
|
||||||
bits.set(',', false); // exclude comma = %x2C
|
|
||||||
bits.set(';', false); // exclude semicolon = %x3B
|
|
||||||
bits.set('\\', false); // exclude backslash = %x5C
|
|
||||||
return bits;
|
return bits;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -45,24 +51,16 @@ final class CookieUtil {
|
|||||||
// | "," | ";" | ":" | "\" | <">
|
// | "," | ";" | ":" | "\" | <">
|
||||||
// | "/" | "[" | "]" | "?" | "="
|
// | "/" | "[" | "]" | "?" | "="
|
||||||
// | "{" | "}" | SP | HT
|
// | "{" | "}" | SP | HT
|
||||||
private static BitSet validCookieNameOctets(BitSet validCookieValueOctets) {
|
private static BitSet validCookieNameOctets() {
|
||||||
BitSet bits = new BitSet(8);
|
BitSet bits = new BitSet();
|
||||||
bits.or(validCookieValueOctets);
|
for (int i = 32; i < 127; i++) {
|
||||||
bits.set('(', false);
|
bits.set(i);
|
||||||
bits.set(')', false);
|
}
|
||||||
bits.set('<', false);
|
int[] separators = new int[]
|
||||||
bits.set('>', false);
|
{ '(', ')', '<', '>', '@', ',', ';', ':', '\\', '"', '/', '[', ']', '?', '=', '{', '}', ' ', '\t' };
|
||||||
bits.set('@', false);
|
for (int separator : separators) {
|
||||||
bits.set(':', false);
|
bits.set(separator, false);
|
||||||
bits.set('/', false);
|
}
|
||||||
bits.set('[', false);
|
|
||||||
bits.set(']', false);
|
|
||||||
bits.set('?', false);
|
|
||||||
bits.set('=', false);
|
|
||||||
bits.set('{', false);
|
|
||||||
bits.set('}', false);
|
|
||||||
bits.set(' ', false);
|
|
||||||
bits.set('\t', false);
|
|
||||||
return bits;
|
return bits;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,7 +24,9 @@ import io.netty.handler.codec.http.HttpHeaderDateFormat;
|
|||||||
import java.text.ParseException;
|
import java.text.ParseException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
@ -76,6 +78,34 @@ public class ServerCookieEncoderTest {
|
|||||||
assertEquals(result, encodedCookies);
|
assertEquals(result, encodedCookies);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void illegalCharInCookieValueMakesStrictEncoderThrowsException() {
|
||||||
|
|
||||||
|
Set<Character> illegalChars = new HashSet<Character>();
|
||||||
|
// CTLs
|
||||||
|
for (int i = 0x00; i <= 0x1F; i++) {
|
||||||
|
illegalChars.add((char) i);
|
||||||
|
}
|
||||||
|
illegalChars.add((char) 0x7F);
|
||||||
|
// whitespace, DQUOTE, comma, semicolon, and backslash
|
||||||
|
for (char c : new char[] { ' ', '"', ',', ';', '\\' }) {
|
||||||
|
illegalChars.add(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
int exceptions = 0;
|
||||||
|
|
||||||
|
for (char c : illegalChars) {
|
||||||
|
Cookie cookie = new DefaultCookie("name", "value" + c);
|
||||||
|
try {
|
||||||
|
ServerCookieEncoder.STRICT.encode(cookie);
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
exceptions++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assertEquals(illegalChars.size(), exceptions);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testEncodingMultipleCookiesLax() {
|
public void testEncodingMultipleCookiesLax() {
|
||||||
List<String> result = new ArrayList<String>();
|
List<String> result = new ArrayList<String>();
|
||||||
|
Loading…
Reference in New Issue
Block a user