View Javadoc

1   /**
2    *
3    * Copyright 2003-2004 The Apache Software Foundation
4    *
5    *  Licensed under the Apache License, Version 2.0 (the "License");
6    *  you may not use this file except in compliance with the License.
7    *  You may obtain a copy of the License at
8    *
9    *     http://www.apache.org/licenses/LICENSE-2.0
10   *
11   *  Unless required by applicable law or agreed to in writing, software
12   *  distributed under the License is distributed on an "AS IS" BASIS,
13   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   *  See the License for the specific language governing permissions and
15   *  limitations under the License.
16   */
17  
18  //
19  // This source code implements specifications defined by the Java
20  // Community Process. In order to remain compliant with the specification
21  // DO NOT add / change / or delete method signatures!
22  //
23  
24  package javax.servlet.http;
25  
26  import java.text.MessageFormat;
27  import java.util.ResourceBundle;
28  
29  /**
30   * Creates a cookie, a small amount of information sent by a servlet to
31   * a Web browser, saved by the browser, and later sent back to the server.
32   * A cookie's value can uniquely
33   * identify a client, so cookies are commonly used for session management.
34   *
35   * <p>A cookie has a name, a single value, and optional attributes
36   * such as a comment, path and domain qualifiers, a maximum age, and a
37   * version number. Some Web browsers have bugs in how they handle the
38   * optional attributes, so use them sparingly to improve the interoperability
39   * of your servlets.
40   *
41   * <p>The servlet sends cookies to the browser by using the
42   * {@link HttpServletResponse#addCookie} method, which adds
43   * fields to HTTP response headers to send cookies to the
44   * browser, one at a time. The browser is expected to
45   * support 20 cookies for each Web server, 300 cookies total, and
46   * may limit cookie size to 4 KB each.
47   *
48   * <p>The browser returns cookies to the servlet by adding
49   * fields to HTTP request headers. Cookies can be retrieved
50   * from a request by using the {@link HttpServletRequest#getCookies} method.
51   * Several cookies might have the same name but different path attributes.
52   *
53   * <p>Cookies affect the caching of the Web pages that use them.
54   * HTTP 1.0 does not cache pages that use cookies created with
55   * this class. This class does not support the cache control
56   * defined with HTTP 1.1.
57   *
58   * <p>This class supports both the Version 0 (by Netscape) and Version 1
59   * (by RFC 2109) cookie specifications. By default, cookies are
60   * created using Version 0 to ensure the best interoperability.
61   *
62   * @version $Rev: 46019 $ $Date: 2004-09-14 02:56:06 -0700 (Tue, 14 Sep 2004) $
63   */
64  
65  // XXX would implement java.io.Serializable too, but can't do that
66  // so long as sun.servlet.* must run on older JDK 1.02 JVMs which
67  // don't include that support.
68  
69  public class Cookie implements Cloneable {
70      private static final String LSTRING_FILE = "javax.servlet.http.LocalStrings";
71      private static ResourceBundle lStrings = ResourceBundle.getBundle(LSTRING_FILE);
72  
73      //
74      // The value of the cookie itself.
75      //
76  
77      private String name; // NAME= ... "$Name" style is reserved
78      private String value; // value of NAME
79  
80      //
81      // Attributes encoded in the header's cookie fields.
82      //
83  
84      private String comment; // ;Comment=VALUE ... describes cookie's use
85      // ;Discard ... implied by maxAge < 0
86      private String domain; // ;Domain=VALUE ... domain that sees cookie
87      private int maxAge = -1; // ;Max-Age=VALUE ... cookies auto-expire
88      private String path; // ;Path=VALUE ... URLs that see the cookie
89      private boolean secure; // ;Secure ... e.g. use SSL
90      private int version = 0; // ;Version=1 ... means RFC 2109++ style
91  
92  
93      /**
94       * Constructs a cookie with a specified name and value.
95       *
96       * <p>The name must conform to RFC 2109. That means it can contain
97       * only ASCII alphanumeric characters and cannot contain commas,
98       * semicolons, or white space or begin with a $ character. The cookie's
99       * name cannot be changed after creation.
100      *
101      * <p>The value can be anything the server chooses to send. Its
102      * value is probably of interest only to the server. The cookie's
103      * value can be changed after creation with the
104      * <code>setValue</code> method.
105      *
106      * <p>By default, cookies are created according to the Netscape
107      * cookie specification. The version can be changed with the
108      * <code>setVersion</code> method.
109      *
110      *
111      * @param name a <code>String</code> specifying the name of the cookie
112      *
113      * @param value a <code>String</code> specifying the value of the cookie
114      *
115      * @throws IllegalArgumentException if the cookie name contains illegal characters
116      * (for example, a comma, space, or semicolon) or it is one of the tokens reserved for use
117      * by the cookie protocol
118      *
119      * @see #setValue
120      * @see #setVersion
121      */
122     public Cookie(String name, String value) {
123         if (!isToken(name)
124                 || name.equalsIgnoreCase("Comment") // rfc2019
125                 || name.equalsIgnoreCase("Discard") // 2019++
126                 || name.equalsIgnoreCase("Domain")
127                 || name.equalsIgnoreCase("Expires") // (old cookies)
128                 || name.equalsIgnoreCase("Max-Age") // rfc2019
129                 || name.equalsIgnoreCase("Path")
130                 || name.equalsIgnoreCase("Secure")
131                 || name.equalsIgnoreCase("Version")
132                 || name.startsWith("$")
133         ) {
134             String errMsg = lStrings.getString("err.cookie_name_is_token");
135             Object[] errArgs = new Object[1];
136             errArgs[0] = name;
137             errMsg = MessageFormat.format(errMsg, errArgs);
138             throw new IllegalArgumentException(errMsg);
139         }
140 
141         this.name = name;
142         this.value = value;
143     }
144 
145     /**
146      * Specifies a comment that describes a cookie's purpose.
147      * The comment is useful if the browser presents the cookie
148      * to the user. Comments
149      * are not supported by Netscape Version 0 cookies.
150      *
151      * @param purpose a <code>String</code> specifying the comment
152      * to display to the user
153      *
154      * @see #getComment
155      */
156     public void setComment(String purpose) {
157         comment = purpose;
158     }
159 
160     /**
161      * Returns the comment describing the purpose of this cookie, or
162      * <code>null</code> if the cookie has no comment.
163      *
164      * @return a <code>String</code> containing the comment,
165      * or <code>null</code> if none
166      *
167      * @see #setComment
168      */
169     public String getComment() {
170         return comment;
171     }
172 
173     /**
174      * Specifies the domain within which this cookie should be presented.
175      *
176      * <p>The form of the domain name is specified by RFC 2109. A domain
177      * name begins with a dot (<code>.foo.com</code>) and means that
178      * the cookie is visible to servers in a specified Domain Name System
179      * (DNS) zone (for example, <code>www.foo.com</code>, but not
180      * <code>a.b.foo.com</code>). By default, cookies are only returned
181      * to the server that sent them.
182      *
183      * @param pattern a <code>String</code> containing the domain name
184      * within which this cookie is visible; form is according to RFC 2109
185      *
186      * @see #getDomain
187      */
188     public void setDomain(String pattern) {
189         domain = pattern.toLowerCase(); // IE allegedly needs this
190     }
191 
192     /**
193      * Returns the domain name set for this cookie. The form of
194      * the domain name is set by RFC 2109.
195      *
196      * @return a <code>String</code> containing the domain name
197      *
198      * @see #setDomain
199      */
200     public String getDomain() {
201         return domain;
202     }
203 
204     /**
205      * Sets the maximum age of the cookie in seconds.
206      *
207      * <p>A positive value indicates that the cookie will expire
208      * after that many seconds have passed. Note that the value is
209      * the <i>maximum</i> age when the cookie will expire, not the cookie's
210      * current age.
211      *
212      * <p>A negative value means
213      * that the cookie is not stored persistently and will be deleted
214      * when the Web browser exits. A zero value causes the cookie
215      * to be deleted.
216      *
217      * @param expiry an integer specifying the maximum age of the
218      * cookie in seconds; if negative, means the cookie is not stored;
219      * if zero, deletes the cookie
220      *
221      * @see #getMaxAge
222      */
223     public void setMaxAge(int expiry) {
224         maxAge = expiry;
225     }
226 
227     /**
228      * Returns the maximum age of the cookie, specified in seconds,
229      * By default, <code>-1</code> indicating the cookie will persist
230      * until browser shutdown.
231      *
232      * @return an integer specifying the maximum age of the
233      * cookie in seconds; if negative, means the cookie persists
234      * until browser shutdown
235      *
236      * @see #setMaxAge
237      */
238     public int getMaxAge() {
239         return maxAge;
240     }
241 
242     /**
243      * Specifies a path for the cookie
244      * to which the client should return the cookie.
245      *
246      * <p>The cookie is visible to all the pages in the directory
247      * you specify, and all the pages in that directory's subdirectories.
248      * A cookie's path must include the servlet that set the cookie,
249      * for example, <i>/catalog</i>, which makes the cookie
250      * visible to all directories on the server under <i>/catalog</i>.
251      *
252      * <p>Consult RFC 2109 (available on the Internet) for more
253      * information on setting path names for cookies.
254      *
255      * @param uri a <code>String</code> specifying a path
256      *
257      * @see #getPath
258      */
259     public void setPath(String uri) {
260         path = uri;
261     }
262 
263     /**
264      * Returns the path on the server
265      * to which the browser returns this cookie. The
266      * cookie is visible to all subpaths on the server.
267      *
268      * @return a <code>String</code> specifying a path that contains
269      * a servlet name, for example, <i>/catalog</i>
270      *
271      * @see #setPath
272      */
273     public String getPath() {
274         return path;
275     }
276 
277     /**
278      * Indicates to the browser whether the cookie should only be sent
279      * using a secure protocol, such as HTTPS or SSL.
280      *
281      * <p>The default value is <code>false</code>.
282      *
283      * @param flag if <code>true</code>, sends the cookie from the browser
284      * to the server only when using a secure protocol; if <code>false</code>,
285      * sent on any protocol
286      *
287      * @see #getSecure
288      */
289     public void setSecure(boolean flag) {
290         secure = flag;
291     }
292 
293     /**
294      * Returns <code>true</code> if the browser is sending cookies
295      * only over a secure protocol, or <code>false</code> if the
296      * browser can send cookies using any protocol.
297      *
298      * @return <code>true</code> if the browser uses a secure protocol;
299      * otherwise, <code>true</code>
300      *
301      * @see #setSecure
302      */
303     public boolean getSecure() {
304         return secure;
305     }
306 
307     /**
308      * Returns the name of the cookie. The name cannot be changed after
309      * creation.
310      *
311      * @return a <code>String</code> specifying the cookie's name
312      */
313     public String getName() {
314         return name;
315     }
316 
317     /**
318      * Assigns a new value to a cookie after the cookie is created.
319      * If you use a binary value, you may want to use BASE64 encoding.
320      *
321      * <p>With Version 0 cookies, values should not contain white
322      * space, brackets, parentheses, equals signs, commas,
323      * double quotes, slashes, question marks, at signs, colons,
324      * and semicolons. Empty values may not behave the same way
325      * on all browsers.
326      *
327      * @param newValue a <code>String</code> specifying the new value
328      *
329      * @see #getValue
330      * @see Cookie
331      */
332     public void setValue(String newValue) {
333         value = newValue;
334     }
335 
336     /**
337      * Returns the value of the cookie.
338      *
339      * @return a <code>String</code> containing the cookie's
340      * present value
341      *
342      * @see #setValue
343      * @see Cookie
344      */
345     public String getValue() {
346         return value;
347     }
348 
349     /**
350      * Returns the version of the protocol this cookie complies
351      * with. Version 1 complies with RFC 2109,
352      * and version 0 complies with the original
353      * cookie specification drafted by Netscape. Cookies provided
354      * by a browser use and identify the browser's cookie version.
355      *
356      * @return 0 if the cookie complies with the original Netscape
357      * specification; 1 if the cookie complies with RFC 2109
358      *
359      * @see #setVersion
360      */
361     public int getVersion() {
362         return version;
363     }
364 
365     /**
366      * Sets the version of the cookie protocol this cookie complies
367      * with. Version 0 complies with the original Netscape cookie
368      * specification. Version 1 complies with RFC 2109.
369      *
370      * <p>Since RFC 2109 is still somewhat new, consider
371      * version 1 as experimental; do not use it yet on production sites.
372      *
373      * @param v 0 if the cookie should comply with the original Netscape
374      * specification; 1 if the cookie should comply with RFC 2109
375      *
376      * @see #getVersion
377      */
378     public void setVersion(int v) {
379         version = v;
380     }
381 
382     // Note -- disabled for now to allow full Netscape compatibility
383     // from RFC 2068, token special case characters
384     //
385     // private static final String tspecials = "()<>@,;:\\\"/[]?={} \t";
386 
387     private static final String tspecials = ",; ";
388 
389     /**
390      * Tests a string and returns true if the string counts as a
391      * reserved token in the Java language.
392      *
393      * @param value the <code>String</code> to be tested
394      *
395      * @return <code>true</code> if the <code>String</code> is
396      * a reserved token; <code>false</code> if it is not
397      */
398     private boolean isToken(String value) {
399         int len = value.length();
400 
401         for (int i = 0; i < len; i++) {
402             char c = value.charAt(i);
403 
404             if (c < 0x20 || c >= 0x7f || tspecials.indexOf(c) != -1)
405                 return false;
406         }
407         return true;
408     }
409 
410     /**
411      * Overrides the standard <code>java.lang.Object.clone</code>
412      * method to return a copy of this cookie.
413      */
414     public Object clone() {
415         try {
416             return super.clone();
417         } catch (CloneNotSupportedException e) {
418             throw new RuntimeException(e.getMessage());
419         }
420     }
421 }
422