1 // ========================================================================
2 // Copyright (c) 2004-2009 Mort Bay Consulting Pty. Ltd.
3 // ------------------------------------------------------------------------
4 // All rights reserved. This program and the accompanying materials
5 // are made available under the terms of the Eclipse Public License v1.0
6 // and Apache License v2.0 which accompanies this distribution.
7 // The Eclipse Public License is available at
8 // http://www.eclipse.org/legal/epl-v10.html
9 // The Apache License v2.0 is available at
10 // http://www.opensource.org/licenses/apache2.0.php
11 // You may elect to redistribute this code under either of these licenses.
12 // ========================================================================
13
14 package org.eclipse.jetty.server;
15 import javax.servlet.http.Cookie;
16 import javax.servlet.http.HttpServletRequest;
17
18 import org.eclipse.jetty.util.LazyList;
19 import org.eclipse.jetty.util.URIUtil;
20 import org.eclipse.jetty.util.log.Log;
21
22
23 /* ------------------------------------------------------------ */
24 /** Cookie parser
25 * <p>Optimized stateful cookie parser. Cookies fields are added with the
26 * {@link #addCookieField(String)} method and parsed on the next subsequent
27 * call to {@link #getCookies()}.
28 * If the added fields are identical to those last added (as strings), then the
29 * cookies are not re parsed.
30 *
31 *
32 */
33 public class CookieCutter
34 {
35 private static final byte STATE_DELIMITER = 1;
36 private static final byte STATE_NAME = 2;
37 private static final byte STATE_VALUE = 4;
38 private static final byte STATE_QUOTED_VALUE = 8;
39 private static final byte STATE_UNQUOTED_VALUE = 16;
40
41 private Cookie[] _cookies;
42 private String[] _fields;
43 int _added=0;
44 boolean _dirty;
45 HttpServletRequest _request;
46
47 public CookieCutter()
48 {
49
50 }
51
52 public CookieCutter(HttpServletRequest request)
53 {
54 _request = request;
55 }
56
57 public Cookie[] getCookies()
58 {
59 if (_added>0)
60 {
61 if (!_dirty && _added==_fields.length)
62 {
63 // same cookies as last time!
64 _added=0;
65 return _cookies;
66 }
67
68 parseFields();
69 }
70 return _cookies;
71 }
72
73 public void setCookies(Cookie[] cookies)
74 {
75 _dirty=false;
76 _added=0;
77 _cookies=cookies;
78 }
79
80 public void reset()
81 {
82 _fields=null;
83 _cookies=null;
84 }
85
86 public void addCookieField(String f)
87 {
88 if (!_dirty &&
89 _fields!=null &&
90 _fields.length>_added &&
91 _fields[_added].equals(f))
92 {
93 _added++;
94 return;
95 }
96
97 if (_dirty)
98 {
99 _added++;
100 _fields=(String[])LazyList.addToArray(_fields,f,String.class);
101 }
102 else
103 {
104 _dirty=true;
105 if (_added>0)
106 {
107 String[] fields=new String[_added+1];
108 System.arraycopy(_fields,0,fields,0,_added);
109 fields[_added++]=f;
110 _fields=fields;
111 }
112 else
113 {
114 _fields = new String[]{f};
115 _added=1;
116 }
117
118 }
119 }
120
121 protected void parseFields()
122 {
123 Object cookies = null;
124
125 int version = 0;
126
127 // For each cookie field
128 for (int f=0;f<_added;f++)
129 {
130 String hdr = _fields[f];
131
132 // Parse the header
133 String name = null;
134 String value = null;
135
136 Cookie cookie = null;
137
138 byte state = STATE_NAME;
139 for (int i = 0, tokenstart = 0, length = hdr.length(); i < length; i++)
140 {
141 char c = hdr.charAt(i);
142 switch (c)
143 {
144 case ',':
145 case ';':
146 switch (state)
147 {
148 case STATE_DELIMITER:
149 state = STATE_NAME;
150 tokenstart = i + 1;
151 break;
152 case STATE_UNQUOTED_VALUE:
153 state = STATE_NAME;
154 value = hdr.substring(tokenstart, i).trim();
155 if(_request!=null && _request.isRequestedSessionIdFromURL())
156 value = URIUtil.decodePath(value);
157 tokenstart = i + 1;
158 break;
159 case STATE_NAME:
160 name = hdr.substring(tokenstart, i);
161 value = "";
162 tokenstart = i + 1;
163 break;
164 case STATE_VALUE:
165 state = STATE_NAME;
166 value = "";
167 tokenstart = i + 1;
168 break;
169 }
170 break;
171 case '=':
172 switch (state)
173 {
174 case STATE_NAME:
175 state = STATE_VALUE;
176 name = hdr.substring(tokenstart, i);
177 tokenstart = i + 1;
178 break;
179 case STATE_VALUE:
180 state = STATE_UNQUOTED_VALUE;
181 tokenstart = i;
182 break;
183 }
184 break;
185 case '"':
186 switch (state)
187 {
188 case STATE_VALUE:
189 state = STATE_QUOTED_VALUE;
190 tokenstart = i + 1;
191 break;
192 case STATE_QUOTED_VALUE:
193 state = STATE_DELIMITER;
194 value = hdr.substring(tokenstart, i);
195 break;
196 }
197 break;
198 case ' ':
199 case '\t':
200 break;
201 default:
202 switch (state)
203 {
204 case STATE_VALUE:
205 state = STATE_UNQUOTED_VALUE;
206 tokenstart = i;
207 break;
208 case STATE_DELIMITER:
209 state = STATE_NAME;
210 tokenstart = i;
211 break;
212 }
213 }
214
215 if (i + 1 == length)
216 {
217 switch (state)
218 {
219 case STATE_UNQUOTED_VALUE:
220 value = hdr.substring(tokenstart).trim();
221 if(_request!=null && _request.isRequestedSessionIdFromURL())
222 value = URIUtil.decodePath(value);
223 break;
224 case STATE_NAME:
225 name = hdr.substring(tokenstart);
226 value = "";
227 break;
228 case STATE_VALUE:
229 value = "";
230 break;
231 }
232 }
233
234 if (name != null && value != null)
235 {
236 name = name.trim();
237
238 try
239 {
240 if (name.startsWith("$"))
241 {
242 String lowercaseName = name.toLowerCase();
243 if ("$path".equals(lowercaseName))
244 {
245 cookie.setPath(value);
246 }
247 else if ("$domain".equals(lowercaseName))
248 {
249 cookie.setDomain(value);
250 }
251 else if ("$version".equals(lowercaseName))
252 {
253 version = Integer.parseInt(value);
254 }
255 }
256 else
257 {
258 cookie = new Cookie(name, value);
259
260 if (version > 0)
261 {
262 cookie.setVersion(version);
263 }
264
265 cookies = LazyList.add(cookies, cookie);
266 }
267 }
268 catch (Exception e)
269 {
270 Log.ignore(e);
271 }
272
273 name = null;
274 value = null;
275 }
276 }
277 }
278
279 int l = LazyList.size(cookies);
280 if (l>0)
281 {
282 if (_cookies != null && _cookies.length == l)
283 {
284 for (int i = 0; i < l; i++)
285 _cookies[i] = (Cookie) LazyList.get(cookies, i);
286 }
287 else
288 _cookies = (Cookie[]) LazyList.toArray(cookies,Cookie.class);
289 }
290
291 _added=0;
292 _dirty=false;
293
294 }
295
296 }