1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.jboss.netty.handler.codec.http;
17
18 import java.text.ParseException;
19 import java.util.ArrayList;
20 import java.util.Collections;
21 import java.util.List;
22 import java.util.Set;
23 import java.util.TreeSet;
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40 public class CookieDecoder {
41
42 private static final String COMMA = ",";
43
44
45
46
47 public CookieDecoder() {
48 super();
49 }
50
51
52
53
54 @Deprecated
55 public CookieDecoder(@SuppressWarnings("unused") boolean lenient) {
56 super();
57 }
58
59
60
61
62
63
64 public Set<Cookie> decode(String header) {
65 List<String> names = new ArrayList<String>(8);
66 List<String> values = new ArrayList<String>(8);
67 extractKeyValuePairs(header, names, values);
68
69 if (names.isEmpty()) {
70 return Collections.emptySet();
71 }
72
73 int i;
74 int version = 0;
75
76
77
78 if (names.get(0).equalsIgnoreCase(CookieHeaderNames.VERSION)) {
79 try {
80 version = Integer.parseInt(values.get(0));
81 } catch (NumberFormatException e) {
82
83 }
84 i = 1;
85 } else {
86 i = 0;
87 }
88
89 if (names.size() <= i) {
90
91 return Collections.emptySet();
92 }
93
94 Set<Cookie> cookies = new TreeSet<Cookie>();
95 for (; i < names.size(); i ++) {
96 String name = names.get(i);
97 String value = values.get(i);
98 if (value == null) {
99 value = "";
100 }
101
102 Cookie c = new DefaultCookie(name, value);
103
104 boolean discard = false;
105 boolean secure = false;
106 boolean httpOnly = false;
107 String comment = null;
108 String commentURL = null;
109 String domain = null;
110 String path = null;
111 int maxAge = Integer.MIN_VALUE;
112 List<Integer> ports = new ArrayList<Integer>(2);
113
114 for (int j = i + 1; j < names.size(); j++, i++) {
115 name = names.get(j);
116 value = values.get(j);
117
118 if (CookieHeaderNames.DISCARD.equalsIgnoreCase(name)) {
119 discard = true;
120 } else if (CookieHeaderNames.SECURE.equalsIgnoreCase(name)) {
121 secure = true;
122 } else if (CookieHeaderNames.HTTPONLY.equalsIgnoreCase(name)) {
123 httpOnly = true;
124 } else if (CookieHeaderNames.COMMENT.equalsIgnoreCase(name)) {
125 comment = value;
126 } else if (CookieHeaderNames.COMMENTURL.equalsIgnoreCase(name)) {
127 commentURL = value;
128 } else if (CookieHeaderNames.DOMAIN.equalsIgnoreCase(name)) {
129 domain = value;
130 } else if (CookieHeaderNames.PATH.equalsIgnoreCase(name)) {
131 path = value;
132 } else if (CookieHeaderNames.EXPIRES.equalsIgnoreCase(name)) {
133 try {
134 long maxAgeMillis =
135 new CookieDateFormat().parse(value).getTime() -
136 System.currentTimeMillis();
137 if (maxAgeMillis <= 0) {
138 maxAge = 0;
139 } else {
140 maxAge = (int) (maxAgeMillis / 1000) +
141 (maxAgeMillis % 1000 != 0? 1 : 0);
142 }
143 } catch (ParseException e) {
144
145 }
146 } else if (CookieHeaderNames.MAX_AGE.equalsIgnoreCase(name)) {
147 maxAge = Integer.parseInt(value);
148 } else if (CookieHeaderNames.VERSION.equalsIgnoreCase(name)) {
149 version = Integer.parseInt(value);
150 } else if (CookieHeaderNames.PORT.equalsIgnoreCase(name)) {
151 String[] portList = value.split(COMMA);
152 for (String s1: portList) {
153 try {
154 ports.add(Integer.valueOf(s1));
155 } catch (NumberFormatException e) {
156
157 }
158 }
159 } else {
160 break;
161 }
162 }
163
164 c.setVersion(version);
165 c.setMaxAge(maxAge);
166 c.setPath(path);
167 c.setDomain(domain);
168 c.setSecure(secure);
169 c.setHttpOnly(httpOnly);
170 if (version > 0) {
171 c.setComment(comment);
172 }
173 if (version > 1) {
174 c.setCommentUrl(commentURL);
175 c.setPorts(ports);
176 c.setDiscard(discard);
177 }
178
179 cookies.add(c);
180 }
181
182 return cookies;
183 }
184
185
186 private static void extractKeyValuePairs(
187 final String header, final List<String> names, final List<String> values) {
188
189 final int headerLen = header.length();
190 loop: for (int i = 0;;) {
191
192
193 for (;;) {
194 if (i == headerLen) {
195 break loop;
196 }
197 switch (header.charAt(i)) {
198 case '\t': case '\n': case 0x0b: case '\f': case '\r':
199 case ' ': case ',': case ';':
200 i ++;
201 continue;
202 }
203 break;
204 }
205
206
207 for (;;) {
208 if (i == headerLen) {
209 break loop;
210 }
211 if (header.charAt(i) == '$') {
212 i ++;
213 continue;
214 }
215 break;
216 }
217
218 String name;
219 String value;
220
221 if (i == headerLen) {
222 name = null;
223 value = null;
224 } else {
225 int newNameStart = i;
226 keyValLoop: for (;;) {
227 switch (header.charAt(i)) {
228 case ';':
229
230 name = header.substring(newNameStart, i);
231 value = null;
232 break keyValLoop;
233 case '=':
234
235 name = header.substring(newNameStart, i);
236 i ++;
237 if (i == headerLen) {
238
239 value = "";
240 break keyValLoop;
241 }
242
243 int newValueStart = i;
244 char c = header.charAt(i);
245 if (c == '"' || c == '\'') {
246
247 StringBuilder newValueBuf = new StringBuilder(header.length() - i);
248 final char q = c;
249 boolean hadBackslash = false;
250 i ++;
251 for (;;) {
252 if (i == headerLen) {
253 value = newValueBuf.toString();
254 break keyValLoop;
255 }
256 if (hadBackslash) {
257 hadBackslash = false;
258 c = header.charAt(i ++);
259 switch (c) {
260 case '\\': case '"': case '\'':
261
262 newValueBuf.setCharAt(newValueBuf.length() - 1, c);
263 break;
264 default:
265
266 newValueBuf.append(c);
267 }
268 } else {
269 c = header.charAt(i ++);
270 if (c == q) {
271 value = newValueBuf.toString();
272 break keyValLoop;
273 }
274 newValueBuf.append(c);
275 if (c == '\\') {
276 hadBackslash = true;
277 }
278 }
279 }
280 } else {
281
282 int semiPos = header.indexOf(';', i);
283 if (semiPos > 0) {
284 value = header.substring(newValueStart, semiPos);
285 i = semiPos;
286 } else {
287 value = header.substring(newValueStart);
288 i = headerLen;
289 }
290 }
291 break keyValLoop;
292 default:
293 i ++;
294 }
295
296 if (i == headerLen) {
297
298 name = header.substring(newNameStart);
299 value = null;
300 break;
301 }
302 }
303 }
304
305 names.add(name);
306 values.add(value);
307 }
308 }
309 }