View Javadoc

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 }