001 /*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements. See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership. The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License. You may obtain a copy of the License at
009 *
010 * http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing,
013 * software distributed under the License is distributed on an
014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015 * KIND, either express or implied. See the License for the
016 * specific language governing permissions and limitations
017 * under the License.
018 */
019
020 //
021 // This source code implements specifications defined by the Java
022 // Community Process. In order to remain compliant with the specification
023 // DO NOT add / change / or delete method signatures!
024 //
025
026 package javax.servlet.http;
027
028 import java.text.MessageFormat;
029 import java.util.ResourceBundle;
030
031 /**
032 * Creates a cookie, a small amount of information sent by a servlet to
033 * a Web browser, saved by the browser, and later sent back to the server.
034 * A cookie's value can uniquely
035 * identify a client, so cookies are commonly used for session management.
036 *
037 * <p>A cookie has a name, a single value, and optional attributes
038 * such as a comment, path and domain qualifiers, a maximum age, and a
039 * version number. Some Web browsers have bugs in how they handle the
040 * optional attributes, so use them sparingly to improve the interoperability
041 * of your servlets.
042 *
043 * <p>The servlet sends cookies to the browser by using the
044 * {@link HttpServletResponse#addCookie} method, which adds
045 * fields to HTTP response headers to send cookies to the
046 * browser, one at a time. The browser is expected to
047 * support 20 cookies for each Web server, 300 cookies total, and
048 * may limit cookie size to 4 KB each.
049 *
050 * <p>The browser returns cookies to the servlet by adding
051 * fields to HTTP request headers. Cookies can be retrieved
052 * from a request by using the {@link HttpServletRequest#getCookies} method.
053 * Several cookies might have the same name but different path attributes.
054 *
055 * <p>Cookies affect the caching of the Web pages that use them.
056 * HTTP 1.0 does not cache pages that use cookies created with
057 * this class. This class does not support the cache control
058 * defined with HTTP 1.1.
059 *
060 * <p>This class supports both the Version 0 (by Netscape) and Version 1
061 * (by RFC 2109) cookie specifications. By default, cookies are
062 * created using Version 0 to ensure the best interoperability.
063 *
064 * @version $Rev: 467553 $ $Date: 2006-10-24 21:01:51 -0700 (Tue, 24 Oct 2006) $
065 */
066
067 // XXX would implement java.io.Serializable too, but can't do that
068 // so long as sun.servlet.* must run on older JDK 1.02 JVMs which
069 // don't include that support.
070
071 public class Cookie implements Cloneable {
072 private static final String LSTRING_FILE = "javax.servlet.http.LocalStrings";
073 private static ResourceBundle lStrings = ResourceBundle.getBundle(LSTRING_FILE);
074
075 //
076 // The value of the cookie itself.
077 //
078
079 private String name; // NAME= ... "$Name" style is reserved
080 private String value; // value of NAME
081
082 //
083 // Attributes encoded in the header's cookie fields.
084 //
085
086 private String comment; // ;Comment=VALUE ... describes cookie's use
087 // ;Discard ... implied by maxAge < 0
088 private String domain; // ;Domain=VALUE ... domain that sees cookie
089 private int maxAge = -1; // ;Max-Age=VALUE ... cookies auto-expire
090 private String path; // ;Path=VALUE ... URLs that see the cookie
091 private boolean secure; // ;Secure ... e.g. use SSL
092 private int version = 0; // ;Version=1 ... means RFC 2109++ style
093
094
095 /**
096 * Constructs a cookie with a specified name and value.
097 *
098 * <p>The name must conform to RFC 2109. That means it can contain
099 * only ASCII alphanumeric characters and cannot contain commas,
100 * semicolons, or white space or begin with a $ character. The cookie's
101 * name cannot be changed after creation.
102 *
103 * <p>The value can be anything the server chooses to send. Its
104 * value is probably of interest only to the server. The cookie's
105 * value can be changed after creation with the
106 * <code>setValue</code> method.
107 *
108 * <p>By default, cookies are created according to the Netscape
109 * cookie specification. The version can be changed with the
110 * <code>setVersion</code> method.
111 *
112 *
113 * @param name a <code>String</code> specifying the name of the cookie
114 *
115 * @param value a <code>String</code> specifying the value of the cookie
116 *
117 * @throws IllegalArgumentException if the cookie name contains illegal characters
118 * (for example, a comma, space, or semicolon) or it is one of the tokens reserved for use
119 * by the cookie protocol
120 *
121 * @see #setValue
122 * @see #setVersion
123 */
124 public Cookie(String name, String value) {
125 if (!isToken(name)
126 || name.equalsIgnoreCase("Comment") // rfc2019
127 || name.equalsIgnoreCase("Discard") // 2019++
128 || name.equalsIgnoreCase("Domain")
129 || name.equalsIgnoreCase("Expires") // (old cookies)
130 || name.equalsIgnoreCase("Max-Age") // rfc2019
131 || name.equalsIgnoreCase("Path")
132 || name.equalsIgnoreCase("Secure")
133 || name.equalsIgnoreCase("Version")
134 || name.startsWith("$")
135 ) {
136 String errMsg = lStrings.getString("err.cookie_name_is_token");
137 Object[] errArgs = new Object[1];
138 errArgs[0] = name;
139 errMsg = MessageFormat.format(errMsg, errArgs);
140 throw new IllegalArgumentException(errMsg);
141 }
142
143 this.name = name;
144 this.value = value;
145 }
146
147 /**
148 * Specifies a comment that describes a cookie's purpose.
149 * The comment is useful if the browser presents the cookie
150 * to the user. Comments
151 * are not supported by Netscape Version 0 cookies.
152 *
153 * @param purpose a <code>String</code> specifying the comment
154 * to display to the user
155 *
156 * @see #getComment
157 */
158 public void setComment(String purpose) {
159 comment = purpose;
160 }
161
162 /**
163 * Returns the comment describing the purpose of this cookie, or
164 * <code>null</code> if the cookie has no comment.
165 *
166 * @return a <code>String</code> containing the comment,
167 * or <code>null</code> if none
168 *
169 * @see #setComment
170 */
171 public String getComment() {
172 return comment;
173 }
174
175 /**
176 * Specifies the domain within which this cookie should be presented.
177 *
178 * <p>The form of the domain name is specified by RFC 2109. A domain
179 * name begins with a dot (<code>.foo.com</code>) and means that
180 * the cookie is visible to servers in a specified Domain Name System
181 * (DNS) zone (for example, <code>www.foo.com</code>, but not
182 * <code>a.b.foo.com</code>). By default, cookies are only returned
183 * to the server that sent them.
184 *
185 * @param pattern a <code>String</code> containing the domain name
186 * within which this cookie is visible; form is according to RFC 2109
187 *
188 * @see #getDomain
189 */
190 public void setDomain(String pattern) {
191 domain = pattern.toLowerCase(); // IE allegedly needs this
192 }
193
194 /**
195 * Returns the domain name set for this cookie. The form of
196 * the domain name is set by RFC 2109.
197 *
198 * @return a <code>String</code> containing the domain name
199 *
200 * @see #setDomain
201 */
202 public String getDomain() {
203 return domain;
204 }
205
206 /**
207 * Sets the maximum age of the cookie in seconds.
208 *
209 * <p>A positive value indicates that the cookie will expire
210 * after that many seconds have passed. Note that the value is
211 * the <i>maximum</i> age when the cookie will expire, not the cookie's
212 * current age.
213 *
214 * <p>A negative value means
215 * that the cookie is not stored persistently and will be deleted
216 * when the Web browser exits. A zero value causes the cookie
217 * to be deleted.
218 *
219 * @param expiry an integer specifying the maximum age of the
220 * cookie in seconds; if negative, means the cookie is not stored;
221 * if zero, deletes the cookie
222 *
223 * @see #getMaxAge
224 */
225 public void setMaxAge(int expiry) {
226 maxAge = expiry;
227 }
228
229 /**
230 * Returns the maximum age of the cookie, specified in seconds,
231 * By default, <code>-1</code> indicating the cookie will persist
232 * until browser shutdown.
233 *
234 * @return an integer specifying the maximum age of the
235 * cookie in seconds; if negative, means the cookie persists
236 * until browser shutdown
237 *
238 * @see #setMaxAge
239 */
240 public int getMaxAge() {
241 return maxAge;
242 }
243
244 /**
245 * Specifies a path for the cookie
246 * to which the client should return the cookie.
247 *
248 * <p>The cookie is visible to all the pages in the directory
249 * you specify, and all the pages in that directory's subdirectories.
250 * A cookie's path must include the servlet that set the cookie,
251 * for example, <i>/catalog</i>, which makes the cookie
252 * visible to all directories on the server under <i>/catalog</i>.
253 *
254 * <p>Consult RFC 2109 (available on the Internet) for more
255 * information on setting path names for cookies.
256 *
257 * @param uri a <code>String</code> specifying a path
258 *
259 * @see #getPath
260 */
261 public void setPath(String uri) {
262 path = uri;
263 }
264
265 /**
266 * Returns the path on the server
267 * to which the browser returns this cookie. The
268 * cookie is visible to all subpaths on the server.
269 *
270 * @return a <code>String</code> specifying a path that contains
271 * a servlet name, for example, <i>/catalog</i>
272 *
273 * @see #setPath
274 */
275 public String getPath() {
276 return path;
277 }
278
279 /**
280 * Indicates to the browser whether the cookie should only be sent
281 * using a secure protocol, such as HTTPS or SSL.
282 *
283 * <p>The default value is <code>false</code>.
284 *
285 * @param flag if <code>true</code>, sends the cookie from the browser
286 * to the server only when using a secure protocol; if <code>false</code>,
287 * sent on any protocol
288 *
289 * @see #getSecure
290 */
291 public void setSecure(boolean flag) {
292 secure = flag;
293 }
294
295 /**
296 * Returns <code>true</code> if the browser is sending cookies
297 * only over a secure protocol, or <code>false</code> if the
298 * browser can send cookies using any protocol.
299 *
300 * @return <code>true</code> if the browser uses a secure protocol;
301 * otherwise, <code>true</code>
302 *
303 * @see #setSecure
304 */
305 public boolean getSecure() {
306 return secure;
307 }
308
309 /**
310 * Returns the name of the cookie. The name cannot be changed after
311 * creation.
312 *
313 * @return a <code>String</code> specifying the cookie's name
314 */
315 public String getName() {
316 return name;
317 }
318
319 /**
320 * Assigns a new value to a cookie after the cookie is created.
321 * If you use a binary value, you may want to use BASE64 encoding.
322 *
323 * <p>With Version 0 cookies, values should not contain white
324 * space, brackets, parentheses, equals signs, commas,
325 * double quotes, slashes, question marks, at signs, colons,
326 * and semicolons. Empty values may not behave the same way
327 * on all browsers.
328 *
329 * @param newValue a <code>String</code> specifying the new value
330 *
331 * @see #getValue
332 * @see Cookie
333 */
334 public void setValue(String newValue) {
335 value = newValue;
336 }
337
338 /**
339 * Returns the value of the cookie.
340 *
341 * @return a <code>String</code> containing the cookie's
342 * present value
343 *
344 * @see #setValue
345 * @see Cookie
346 */
347 public String getValue() {
348 return value;
349 }
350
351 /**
352 * Returns the version of the protocol this cookie complies
353 * with. Version 1 complies with RFC 2109,
354 * and version 0 complies with the original
355 * cookie specification drafted by Netscape. Cookies provided
356 * by a browser use and identify the browser's cookie version.
357 *
358 * @return 0 if the cookie complies with the original Netscape
359 * specification; 1 if the cookie complies with RFC 2109
360 *
361 * @see #setVersion
362 */
363 public int getVersion() {
364 return version;
365 }
366
367 /**
368 * Sets the version of the cookie protocol this cookie complies
369 * with. Version 0 complies with the original Netscape cookie
370 * specification. Version 1 complies with RFC 2109.
371 *
372 * <p>Since RFC 2109 is still somewhat new, consider
373 * version 1 as experimental; do not use it yet on production sites.
374 *
375 * @param v 0 if the cookie should comply with the original Netscape
376 * specification; 1 if the cookie should comply with RFC 2109
377 *
378 * @see #getVersion
379 */
380 public void setVersion(int v) {
381 version = v;
382 }
383
384 // Note -- disabled for now to allow full Netscape compatibility
385 // from RFC 2068, token special case characters
386 //
387 // private static final String tspecials = "()<>@,;:\\\"/[]?={} \t";
388
389 private static final String tspecials = ",; ";
390
391 /**
392 * Tests a string and returns true if the string counts as a
393 * reserved token in the Java language.
394 *
395 * @param value the <code>String</code> to be tested
396 *
397 * @return <code>true</code> if the <code>String</code> is
398 * a reserved token; <code>false</code> if it is not
399 */
400 private boolean isToken(String value) {
401 int len = value.length();
402
403 for (int i = 0; i < len; i++) {
404 char c = value.charAt(i);
405
406 if (c < 0x20 || c >= 0x7f || tspecials.indexOf(c) != -1)
407 return false;
408 }
409 return true;
410 }
411
412 /**
413 * Overrides the standard <code>java.lang.Object.clone</code>
414 * method to return a copy of this cookie.
415 */
416 public Object clone() {
417 try {
418 return super.clone();
419 } catch (CloneNotSupportedException e) {
420 throw new RuntimeException(e.getMessage());
421 }
422 }
423 }
424