1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package io.netty.handler.codec.http.cookie;
17
18 import io.netty.handler.codec.http.HttpConstants;
19 import io.netty.util.internal.InternalThreadLocalMap;
20
21 import java.util.BitSet;
22
23 final class CookieUtil {
24
25 private static final BitSet VALID_COOKIE_NAME_OCTETS = validCookieNameOctets();
26
27 private static final BitSet VALID_COOKIE_VALUE_OCTETS = validCookieValueOctets();
28
29 private static final BitSet VALID_COOKIE_ATTRIBUTE_VALUE_OCTETS = validCookieAttributeValueOctets();
30
31
32
33
34
35
36 private static BitSet validCookieNameOctets() {
37 BitSet bits = new BitSet();
38 for (int i = 32; i < 127; i++) {
39 bits.set(i);
40 }
41 int[] separators = new int[]
42 { '(', ')', '<', '>', '@', ',', ';', ':', '\\', '"', '/', '[', ']', '?', '=', '{', '}', ' ', '\t' };
43 for (int separator : separators) {
44 bits.set(separator, false);
45 }
46 return bits;
47 }
48
49
50
51 private static BitSet validCookieValueOctets() {
52 BitSet bits = new BitSet();
53 bits.set(0x21);
54 for (int i = 0x23; i <= 0x2B; i++) {
55 bits.set(i);
56 }
57 for (int i = 0x2D; i <= 0x3A; i++) {
58 bits.set(i);
59 }
60 for (int i = 0x3C; i <= 0x5B; i++) {
61 bits.set(i);
62 }
63 for (int i = 0x5D; i <= 0x7E; i++) {
64 bits.set(i);
65 }
66 return bits;
67 }
68
69
70 private static BitSet validCookieAttributeValueOctets() {
71 BitSet bits = new BitSet();
72 for (int i = 32; i < 127; i++) {
73 bits.set(i);
74 }
75 bits.set(';', false);
76 return bits;
77 }
78
79 static StringBuilder stringBuilder() {
80 return InternalThreadLocalMap.get().stringBuilder();
81 }
82
83
84
85
86
87 static String stripTrailingSeparatorOrNull(StringBuilder buf) {
88 return buf.length() == 0 ? null : stripTrailingSeparator(buf);
89 }
90
91 static String stripTrailingSeparator(StringBuilder buf) {
92 if (buf.length() > 0) {
93 buf.setLength(buf.length() - 2);
94 }
95 return buf.toString();
96 }
97
98 static void add(StringBuilder sb, String name, long val) {
99 sb.append(name);
100 sb.append('=');
101 sb.append(val);
102 sb.append(';');
103 sb.append(HttpConstants.SP_CHAR);
104 }
105
106 static void add(StringBuilder sb, String name, String val) {
107 sb.append(name);
108 sb.append('=');
109 sb.append(val);
110 sb.append(';');
111 sb.append(HttpConstants.SP_CHAR);
112 }
113
114 static void add(StringBuilder sb, String name) {
115 sb.append(name);
116 sb.append(';');
117 sb.append(HttpConstants.SP_CHAR);
118 }
119
120 static void addQuoted(StringBuilder sb, String name, String val) {
121 if (val == null) {
122 val = "";
123 }
124
125 sb.append(name);
126 sb.append('=');
127 sb.append('"');
128 sb.append(val);
129 sb.append('"');
130 sb.append(';');
131 sb.append(HttpConstants.SP_CHAR);
132 }
133
134 static int firstInvalidCookieNameOctet(CharSequence cs) {
135 return firstInvalidOctet(cs, VALID_COOKIE_NAME_OCTETS);
136 }
137
138 static int firstInvalidCookieValueOctet(CharSequence cs) {
139 return firstInvalidOctet(cs, VALID_COOKIE_VALUE_OCTETS);
140 }
141
142 static int firstInvalidOctet(CharSequence cs, BitSet bits) {
143 for (int i = 0; i < cs.length(); i++) {
144 char c = cs.charAt(i);
145 if (!bits.get(c)) {
146 return i;
147 }
148 }
149 return -1;
150 }
151
152 static CharSequence unwrapValue(CharSequence cs) {
153 final int len = cs.length();
154 if (len > 0 && cs.charAt(0) == '"') {
155 if (len >= 2 && cs.charAt(len - 1) == '"') {
156
157 return len == 2 ? "" : cs.subSequence(1, len - 1);
158 } else {
159 return null;
160 }
161 }
162 return cs;
163 }
164
165 static String validateAttributeValue(String name, String value) {
166 if (value == null) {
167 return null;
168 }
169 value = value.trim();
170 if (value.isEmpty()) {
171 return null;
172 }
173 int i = firstInvalidOctet(value, VALID_COOKIE_ATTRIBUTE_VALUE_OCTETS);
174 if (i != -1) {
175 throw new IllegalArgumentException(name + " contains the prohibited characters: " + value.charAt(i));
176 }
177 return value;
178 }
179
180 private CookieUtil() {
181
182 }
183 }