1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.jboss.netty.handler.codec.http.cookie;
17
18 import org.jboss.netty.handler.codec.http.HttpHeaderDateFormat;
19
20 import java.text.ParsePosition;
21 import java.util.Date;
22
23
24
25
26
27
28
29
30
31 public final class ClientCookieDecoder extends CookieDecoder {
32
33
34
35
36
37 public static final ClientCookieDecoder STRICT = new ClientCookieDecoder(true);
38
39
40
41
42 public static final ClientCookieDecoder LAX = new ClientCookieDecoder(false);
43
44 private ClientCookieDecoder(boolean strict) {
45 super(strict);
46 }
47
48
49
50
51
52
53 public Cookie decode(String header) {
54 if (header == null) {
55 throw new NullPointerException("header");
56 }
57 final int headerLen = header.length();
58
59 if (headerLen == 0) {
60 return null;
61 }
62
63 CookieBuilder cookieBuilder = null;
64
65 loop: for (int i = 0;;) {
66
67
68 for (;;) {
69 if (i == headerLen) {
70 break loop;
71 }
72 char c = header.charAt(i);
73 if (c == ',') {
74
75
76 break loop;
77
78 } else if (c == '\t' || c == '\n' || c == 0x0b || c == '\f'
79 || c == '\r' || c == ' ' || c == ';') {
80 i++;
81 continue;
82 }
83 break;
84 }
85
86 int nameBegin = i;
87 int nameEnd = i;
88 int valueBegin = -1;
89 int valueEnd = -1;
90
91 if (i != headerLen) {
92 keyValLoop: for (;;) {
93
94 char curChar = header.charAt(i);
95 if (curChar == ';') {
96
97 nameEnd = i;
98 valueBegin = valueEnd = -1;
99 break keyValLoop;
100
101 } else if (curChar == '=') {
102
103 nameEnd = i;
104 i++;
105 if (i == headerLen) {
106
107 valueBegin = valueEnd = 0;
108 break keyValLoop;
109 }
110
111 valueBegin = i;
112
113 int semiPos = header.indexOf(';', i);
114 valueEnd = i = semiPos > 0 ? semiPos : headerLen;
115 break keyValLoop;
116 } else {
117 i++;
118 }
119
120 if (i == headerLen) {
121
122 nameEnd = headerLen;
123 valueBegin = valueEnd = -1;
124 break;
125 }
126 }
127 }
128
129 if (valueEnd > 0 && header.charAt(valueEnd - 1) == ',') {
130
131 valueEnd--;
132 }
133
134 if (cookieBuilder == null) {
135
136 DefaultCookie cookie = initCookie(header, nameBegin, nameEnd, valueBegin, valueEnd);
137
138 if (cookie == null) {
139 return null;
140 }
141
142 cookieBuilder = new CookieBuilder(cookie);
143 } else {
144
145 String attrValue = valueBegin == -1 ? null : header.substring(valueBegin, valueEnd);
146 cookieBuilder.appendAttribute(header, nameBegin, nameEnd, attrValue);
147 }
148 }
149 return cookieBuilder.cookie();
150 }
151
152 private static class CookieBuilder {
153
154 private final DefaultCookie cookie;
155 private String domain;
156 private String path;
157 private int maxAge = Integer.MIN_VALUE;
158 private String expires;
159 private boolean secure;
160 private boolean httpOnly;
161
162 public CookieBuilder(DefaultCookie cookie) {
163 this.cookie = cookie;
164 }
165
166 private int mergeMaxAgeAndExpire(int maxAge, String expires) {
167
168 if (maxAge != Integer.MIN_VALUE) {
169 return maxAge;
170 } else if (expires != null) {
171 Date expiresDate = HttpHeaderDateFormat.get().parse(expires, new ParsePosition(0));
172 if (expiresDate != null) {
173 long maxAgeMillis = expiresDate.getTime() - System.currentTimeMillis();
174 return (int) (maxAgeMillis / 1000 + (maxAgeMillis % 1000 != 0 ? 1 : 0));
175 }
176 }
177 return Integer.MIN_VALUE;
178 }
179
180 public Cookie cookie() {
181 cookie.setDomain(domain);
182 cookie.setPath(path);
183 cookie.setMaxAge(mergeMaxAgeAndExpire(maxAge, expires));
184 cookie.setSecure(secure);
185 cookie.setHttpOnly(httpOnly);
186 return cookie;
187 }
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202 public void appendAttribute(String header, int keyStart, int keyEnd,
203 String value) {
204 setCookieAttribute(header, keyStart, keyEnd, value);
205 }
206
207 private void setCookieAttribute(String header, int keyStart,
208 int keyEnd, String value) {
209 int length = keyEnd - keyStart;
210
211 if (length == 4) {
212 parse4(header, keyStart, value);
213 } else if (length == 6) {
214 parse6(header, keyStart, value);
215 } else if (length == 7) {
216 parse7(header, keyStart, value);
217 } else if (length == 8) {
218 parse8(header, keyStart, value);
219 }
220 }
221
222 private void parse4(String header, int nameStart, String value) {
223 if (header.regionMatches(true, nameStart, CookieHeaderNames.PATH, 0, 4)) {
224 path = value;
225 }
226 }
227
228 private void parse6(String header, int nameStart, String value) {
229 if (header.regionMatches(true, nameStart, CookieHeaderNames.DOMAIN, 0, 5)) {
230 domain = value.length() > 0 ? value.toString() : null;
231 } else if (header.regionMatches(true, nameStart, CookieHeaderNames.SECURE, 0, 5)) {
232 secure = true;
233 }
234 }
235
236 private void setExpire(String value) {
237 expires = value;
238 }
239
240 private void setMaxAge(String value) {
241 try {
242 maxAge = Math.max(Integer.valueOf(value), 0);
243 } catch (NumberFormatException e1) {
244
245 }
246 }
247
248 private void parse7(String header, int nameStart, String value) {
249 if (header.regionMatches(true, nameStart, CookieHeaderNames.EXPIRES, 0, 7)) {
250 setExpire(value);
251 } else if (header.regionMatches(true, nameStart, CookieHeaderNames.MAX_AGE, 0, 7)) {
252 setMaxAge(value);
253 }
254 }
255
256 private void parse8(String header, int nameStart, String value) {
257 if (header.regionMatches(true, nameStart, CookieHeaderNames.HTTPONLY, 0, 8)) {
258 httpOnly = true;
259 }
260 }
261 }
262 }