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