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