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 import java.util.regex.Matcher;
25 import java.util.regex.Pattern;
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46 public class CookieDecoder {
47
48 private final static Pattern PATTERN =
49 Pattern.compile("(?:\\s|[;,])*\\$*([^;=]+)(?:=(?:[\"']((?:\\\\.|[^\"])*)[\"']|([^;,]*)))?(\\s*(?:[;,]+\\s*|$))");
50
51 private final static String COMMA = ",";
52
53
54
55
56 public CookieDecoder() {
57 super();
58 }
59
60
61
62
63
64
65 public Set<Cookie> decode(String header) {
66 List<String> names = new ArrayList<String>(8);
67 List<String> values = new ArrayList<String>(8);
68 extractKeyValuePairs(header, names, values);
69
70 if (names.isEmpty()) {
71 return Collections.emptySet();
72 }
73
74 int i;
75 int version = 0;
76
77
78
79 if (names.get(0).equalsIgnoreCase(CookieHeaderNames.VERSION)) {
80 try {
81 version = Integer.parseInt(values.get(0));
82 } catch (NumberFormatException e) {
83
84 }
85 i = 1;
86 } else {
87 i = 0;
88 }
89
90 if (names.size() <= i) {
91
92 return Collections.emptySet();
93 }
94
95 Set<Cookie> cookies = new TreeSet<Cookie>();
96 for (; i < names.size(); i ++) {
97 String name = names.get(i);
98 String value = values.get(i);
99 if (value == null) {
100 value = "";
101 }
102
103 Cookie c = new DefaultCookie(name, value);
104 cookies.add(c);
105
106 boolean discard = false;
107 boolean secure = false;
108 boolean httpOnly = false;
109 String comment = null;
110 String commentURL = null;
111 String domain = null;
112 String path = null;
113 int maxAge = -1;
114 List<Integer> ports = new ArrayList<Integer>(2);
115
116 for (int j = i + 1; j < names.size(); j++, i++) {
117 name = names.get(j);
118 value = values.get(j);
119
120 if (CookieHeaderNames.DISCARD.equalsIgnoreCase(name)) {
121 discard = true;
122 } else if (CookieHeaderNames.SECURE.equalsIgnoreCase(name)) {
123 secure = true;
124 } else if (CookieHeaderNames.HTTPONLY.equalsIgnoreCase(name)) {
125 httpOnly = true;
126 } else if (CookieHeaderNames.COMMENT.equalsIgnoreCase(name)) {
127 comment = value;
128 } else if (CookieHeaderNames.COMMENTURL.equalsIgnoreCase(name)) {
129 commentURL = value;
130 } else if (CookieHeaderNames.DOMAIN.equalsIgnoreCase(name)) {
131 domain = value;
132 } else if (CookieHeaderNames.PATH.equalsIgnoreCase(name)) {
133 path = value;
134 } else if (CookieHeaderNames.EXPIRES.equalsIgnoreCase(name)) {
135 try {
136 long maxAgeMillis =
137 new CookieDateFormat().parse(value).getTime() -
138 System.currentTimeMillis();
139 if (maxAgeMillis <= 0) {
140 maxAge = 0;
141 } else {
142 maxAge = (int) (maxAgeMillis / 1000) +
143 (maxAgeMillis % 1000 != 0? 1 : 0);
144 }
145 } catch (ParseException e) {
146
147 }
148 } else if (CookieHeaderNames.MAX_AGE.equalsIgnoreCase(name)) {
149 maxAge = Integer.parseInt(value);
150 } else if (CookieHeaderNames.VERSION.equalsIgnoreCase(name)) {
151 version = Integer.parseInt(value);
152 } else if (CookieHeaderNames.PORT.equalsIgnoreCase(name)) {
153 String[] portList = value.split(COMMA);
154 for (String s1: portList) {
155 try {
156 ports.add(Integer.valueOf(s1));
157 } catch (NumberFormatException e) {
158
159 }
160 }
161 } else {
162 break;
163 }
164 }
165
166 c.setVersion(version);
167 c.setMaxAge(maxAge);
168 c.setPath(path);
169 c.setDomain(domain);
170 c.setSecure(secure);
171 c.setHttpOnly(httpOnly);
172 if (version > 0) {
173 c.setComment(comment);
174 }
175 if (version > 1) {
176 c.setCommentUrl(commentURL);
177 c.setPorts(ports);
178 c.setDiscard(discard);
179 }
180 }
181
182 return cookies;
183 }
184
185 private void extractKeyValuePairs(
186 String header, List<String> names, List<String> values) {
187 Matcher m = PATTERN.matcher(header);
188 int pos = 0;
189 String name = null;
190 String value = null;
191 String separator = null;
192 while (m.find(pos)) {
193 pos = m.end();
194
195
196 String newName = m.group(1);
197 String newValue = m.group(3);
198 if (newValue == null) {
199 newValue = decodeValue(m.group(2));
200 }
201 String newSeparator = m.group(4);
202
203 if (name == null) {
204 name = newName;
205 value = newValue == null? "" : newValue;
206 separator = newSeparator;
207 continue;
208 }
209
210 if (newValue == null &&
211 !CookieHeaderNames.DISCARD.equalsIgnoreCase(newName) &&
212 !CookieHeaderNames.SECURE.equalsIgnoreCase(newName) &&
213 !CookieHeaderNames.HTTPONLY.equalsIgnoreCase(newName)) {
214 value = value + separator + newName;
215 separator = newSeparator;
216 continue;
217 }
218
219 names.add(name);
220 values.add(value);
221
222 name = newName;
223 value = newValue;
224 separator = newSeparator;
225 }
226
227
228 if (name != null) {
229 names.add(name);
230 values.add(value);
231 }
232 }
233
234 private String decodeValue(String value) {
235 if (value == null) {
236 return value;
237 }
238 return value.replace("\\\"", "\"").replace("\\\\", "\\");
239 }
240 }