29 import java.util.StringTokenizer; |
29 import java.util.StringTokenizer; |
30 import java.util.NoSuchElementException; |
30 import java.util.NoSuchElementException; |
31 import java.text.SimpleDateFormat; |
31 import java.text.SimpleDateFormat; |
32 import java.util.TimeZone; |
32 import java.util.TimeZone; |
33 import java.util.Date; |
33 import java.util.Date; |
34 |
|
35 import java.lang.NullPointerException; // for javadoc |
|
36 import java.util.Locale; |
34 import java.util.Locale; |
37 import java.util.Objects; |
35 import java.util.Objects; |
38 |
36 |
39 /** |
37 /** |
40 * An HttpCookie object represents an http cookie, which carries state |
38 * An HttpCookie object represents an HTTP cookie, which carries state |
41 * information between server and user agent. Cookie is widely adopted |
39 * information between server and user agent. Cookie is widely adopted |
42 * to create stateful sessions. |
40 * to create stateful sessions. |
43 * |
41 * |
44 * <p>There are 3 http cookie specifications: |
42 * <p> There are 3 HTTP cookie specifications: |
45 * <blockquote> |
43 * <blockquote> |
46 * Netscape draft<br> |
44 * Netscape draft<br> |
47 * RFC 2109 - <a href="http://www.ietf.org/rfc/rfc2109.txt"> |
45 * RFC 2109 - <a href="http://www.ietf.org/rfc/rfc2109.txt"> |
48 * <i>http://www.ietf.org/rfc/rfc2109.txt</i></a><br> |
46 * <i>http://www.ietf.org/rfc/rfc2109.txt</i></a><br> |
49 * RFC 2965 - <a href="http://www.ietf.org/rfc/rfc2965.txt"> |
47 * RFC 2965 - <a href="http://www.ietf.org/rfc/rfc2965.txt"> |
50 * <i>http://www.ietf.org/rfc/rfc2965.txt</i></a> |
48 * <i>http://www.ietf.org/rfc/rfc2965.txt</i></a> |
51 * </blockquote> |
49 * </blockquote> |
52 * |
50 * |
53 * <p>HttpCookie class can accept all these 3 forms of syntax. |
51 * <p> HttpCookie class can accept all these 3 forms of syntax. |
54 * |
52 * |
55 * @author Edward Wang |
53 * @author Edward Wang |
56 * @since 1.6 |
54 * @since 1.6 |
57 */ |
55 */ |
58 public final class HttpCookie implements Cloneable { |
56 public final class HttpCookie implements Cloneable { |
59 /* ---------------- Fields -------------- */ |
57 // ---------------- Fields -------------- |
60 |
58 |
61 // |
|
62 // The value of the cookie itself. |
59 // The value of the cookie itself. |
63 // |
60 private final String name; // NAME= ... "$Name" style is reserved |
64 |
|
65 private String name; // NAME= ... "$Name" style is reserved |
|
66 private String value; // value of NAME |
61 private String value; // value of NAME |
67 |
62 |
68 // |
|
69 // Attributes encoded in the header's cookie fields. |
63 // Attributes encoded in the header's cookie fields. |
70 // |
|
71 |
|
72 private String comment; // Comment=VALUE ... describes cookie's use |
64 private String comment; // Comment=VALUE ... describes cookie's use |
73 private String commentURL; // CommentURL="http URL" ... describes cookie's use |
65 private String commentURL; // CommentURL="http URL" ... describes cookie's use |
74 private boolean toDiscard; // Discard ... discard cookie unconditionally |
66 private boolean toDiscard; // Discard ... discard cookie unconditionally |
75 private String domain; // Domain=VALUE ... domain that sees cookie |
67 private String domain; // Domain=VALUE ... domain that sees cookie |
76 private long maxAge = MAX_AGE_UNSPECIFIED; // Max-Age=VALUE ... cookies auto-expire |
68 private long maxAge = MAX_AGE_UNSPECIFIED; // Max-Age=VALUE ... cookies auto-expire |
78 private String portlist; // Port[="portlist"] ... the port cookie may be returned to |
70 private String portlist; // Port[="portlist"] ... the port cookie may be returned to |
79 private boolean secure; // Secure ... e.g. use SSL |
71 private boolean secure; // Secure ... e.g. use SSL |
80 private boolean httpOnly; // HttpOnly ... i.e. not accessible to scripts |
72 private boolean httpOnly; // HttpOnly ... i.e. not accessible to scripts |
81 private int version = 1; // Version=1 ... RFC 2965 style |
73 private int version = 1; // Version=1 ... RFC 2965 style |
82 |
74 |
83 // |
|
84 // Hold the creation time (in seconds) of the http cookie for later |
75 // Hold the creation time (in seconds) of the http cookie for later |
85 // expiration calculation |
76 // expiration calculation |
86 // |
77 private final long whenCreated; |
87 private long whenCreated = 0; |
78 |
88 |
|
89 |
|
90 // |
|
91 // Since the positive and zero max-age have their meanings, |
79 // Since the positive and zero max-age have their meanings, |
92 // this value serves as a hint as 'not specify max-age' |
80 // this value serves as a hint as 'not specify max-age' |
93 // |
|
94 private final static long MAX_AGE_UNSPECIFIED = -1; |
81 private final static long MAX_AGE_UNSPECIFIED = -1; |
95 |
82 |
96 |
|
97 // |
|
98 // date formats used by Netscape's cookie draft |
83 // date formats used by Netscape's cookie draft |
99 // as well as formats seen on various sites |
84 // as well as formats seen on various sites |
100 // |
|
101 private final static String[] COOKIE_DATE_FORMATS = { |
85 private final static String[] COOKIE_DATE_FORMATS = { |
102 "EEE',' dd-MMM-yyyy HH:mm:ss 'GMT'", |
86 "EEE',' dd-MMM-yyyy HH:mm:ss 'GMT'", |
103 "EEE',' dd MMM yyyy HH:mm:ss 'GMT'", |
87 "EEE',' dd MMM yyyy HH:mm:ss 'GMT'", |
104 "EEE MMM dd yyyy HH:mm:ss 'GMT'Z" |
88 "EEE MMM dd yyyy HH:mm:ss 'GMT'Z" |
105 }; |
89 }; |
106 |
90 |
107 // |
|
108 // constant strings represent set-cookie header token |
91 // constant strings represent set-cookie header token |
109 // |
|
110 private final static String SET_COOKIE = "set-cookie:"; |
92 private final static String SET_COOKIE = "set-cookie:"; |
111 private final static String SET_COOKIE2 = "set-cookie2:"; |
93 private final static String SET_COOKIE2 = "set-cookie2:"; |
112 |
94 |
113 |
95 // ---------------- Ctors -------------- |
114 /* ---------------- Ctors -------------- */ |
|
115 |
96 |
116 /** |
97 /** |
117 * Constructs a cookie with a specified name and value. |
98 * Constructs a cookie with a specified name and value. |
118 * |
99 * |
119 * <p>The name must conform to RFC 2965. That means it can contain |
100 * <p> The name must conform to RFC 2965. That means it can contain |
120 * only ASCII alphanumeric characters and cannot contain commas, |
101 * only ASCII alphanumeric characters and cannot contain commas, |
121 * semicolons, or white space or begin with a $ character. The cookie's |
102 * semicolons, or white space or begin with a $ character. The cookie's |
122 * name cannot be changed after creation. |
103 * name cannot be changed after creation. |
123 * |
104 * |
124 * <p>The value can be anything the server chooses to send. Its |
105 * <p> The value can be anything the server chooses to send. Its |
125 * value is probably of interest only to the server. The cookie's |
106 * value is probably of interest only to the server. The cookie's |
126 * value can be changed after creation with the |
107 * value can be changed after creation with the |
127 * <code>setValue</code> method. |
108 * {@code setValue} method. |
128 * |
109 * |
129 * <p>By default, cookies are created according to the RFC 2965 |
110 * <p> By default, cookies are created according to the RFC 2965 |
130 * cookie specification. The version can be changed with the |
111 * cookie specification. The version can be changed with the |
131 * <code>setVersion</code> method. |
112 * {@code setVersion} method. |
132 * |
113 * |
133 * |
114 * |
134 * @param name a <code>String</code> specifying the name of the cookie |
115 * @param name |
135 * |
116 * a {@code String} specifying the name of the cookie |
136 * @param value a <code>String</code> specifying the value of the cookie |
117 * |
137 * |
118 * @param value |
138 * @throws IllegalArgumentException if the cookie name contains illegal characters |
119 * a {@code String} specifying the value of the cookie |
139 * or it is one of the tokens reserved for use |
120 * |
140 * by the cookie protocol |
121 * @throws IllegalArgumentException |
141 * @throws NullPointerException if <tt>name</tt> is <tt>null</tt> |
122 * if the cookie name contains illegal characters or it is one of |
|
123 * the tokens reserved for use by the cookie protocol |
|
124 * @throws NullPointerException |
|
125 * if {@code name} is {@code null} |
|
126 * |
142 * @see #setValue |
127 * @see #setValue |
143 * @see #setVersion |
128 * @see #setVersion |
144 * |
129 */ |
145 */ |
|
146 |
|
147 public HttpCookie(String name, String value) { |
130 public HttpCookie(String name, String value) { |
148 name = name.trim(); |
131 name = name.trim(); |
149 if (name.length() == 0 || !isToken(name) || isReserved(name)) { |
132 if (name.length() == 0 || !isToken(name) || isReserved(name)) { |
150 throw new IllegalArgumentException("Illegal cookie name"); |
133 throw new IllegalArgumentException("Illegal cookie name"); |
151 } |
134 } |
238 else |
218 else |
239 return false; |
219 return false; |
240 } |
220 } |
241 |
221 |
242 /** |
222 /** |
243 * |
|
244 * Specifies a comment that describes a cookie's purpose. |
223 * Specifies a comment that describes a cookie's purpose. |
245 * The comment is useful if the browser presents the cookie |
224 * The comment is useful if the browser presents the cookie |
246 * to the user. Comments |
225 * to the user. Comments are not supported by Netscape Version 0 cookies. |
247 * are not supported by Netscape Version 0 cookies. |
226 * |
248 * |
227 * @param purpose |
249 * @param purpose a <code>String</code> specifying the comment |
228 * a {@code String} specifying the comment to display to the user |
250 * to display to the user |
229 * |
251 * |
230 * @see #getComment |
252 * @see #getComment |
231 */ |
253 * |
|
254 */ |
|
255 |
|
256 public void setComment(String purpose) { |
232 public void setComment(String purpose) { |
257 comment = purpose; |
233 comment = purpose; |
258 } |
234 } |
259 |
235 |
260 |
|
261 |
|
262 |
|
263 /** |
236 /** |
264 * Returns the comment describing the purpose of this cookie, or |
237 * Returns the comment describing the purpose of this cookie, or |
265 * <code>null</code> if the cookie has no comment. |
238 * {@code null} if the cookie has no comment. |
266 * |
239 * |
267 * @return a <code>String</code> containing the comment, |
240 * @return a {@code String} containing the comment, or {@code null} if none |
268 * or <code>null</code> if none |
241 * |
269 * |
242 * @see #setComment |
270 * @see #setComment |
243 */ |
271 * |
|
272 */ |
|
273 |
|
274 public String getComment() { |
244 public String getComment() { |
275 return comment; |
245 return comment; |
276 } |
246 } |
277 |
247 |
278 |
248 /** |
279 /** |
249 * Specifies a comment URL that describes a cookie's purpose. |
280 * |
250 * The comment URL is useful if the browser presents the cookie |
281 * Specifies a comment url that describes a cookie's purpose. |
251 * to the user. Comment URL is RFC 2965 only. |
282 * The comment url is useful if the browser presents the cookie |
252 * |
283 * to the user. Comment url is RFC 2965 only. |
253 * @param purpose |
284 * |
254 * a {@code String} specifying the comment URL to display to the user |
285 * @param purpose a <code>String</code> specifying the comment url |
255 * |
286 * to display to the user |
256 * @see #getCommentURL |
287 * |
257 */ |
288 * @see #getCommentURL |
|
289 * |
|
290 */ |
|
291 |
|
292 public void setCommentURL(String purpose) { |
258 public void setCommentURL(String purpose) { |
293 commentURL = purpose; |
259 commentURL = purpose; |
294 } |
260 } |
295 |
261 |
296 |
262 /** |
297 |
263 * Returns the comment URL describing the purpose of this cookie, or |
298 |
264 * {@code null} if the cookie has no comment URL. |
299 /** |
265 * |
300 * Returns the comment url describing the purpose of this cookie, or |
266 * @return a {@code String} containing the comment URL, or {@code null} |
301 * <code>null</code> if the cookie has no comment url. |
267 * if none |
302 * |
268 * |
303 * @return a <code>String</code> containing the comment url, |
269 * @see #setCommentURL |
304 * or <code>null</code> if none |
270 */ |
305 * |
|
306 * @see #setCommentURL |
|
307 * |
|
308 */ |
|
309 |
|
310 public String getCommentURL() { |
271 public String getCommentURL() { |
311 return commentURL; |
272 return commentURL; |
312 } |
273 } |
313 |
274 |
314 |
|
315 /** |
275 /** |
316 * Specify whether user agent should discard the cookie unconditionally. |
276 * Specify whether user agent should discard the cookie unconditionally. |
317 * This is RFC 2965 only attribute. |
277 * This is RFC 2965 only attribute. |
318 * |
278 * |
319 * @param discard <tt>true</tt> indicates to discard cookie unconditionally |
279 * @param discard |
320 * |
280 * {@code true} indicates to discard cookie unconditionally |
321 * @see #getDiscard |
281 * |
322 */ |
282 * @see #getDiscard |
323 |
283 */ |
324 public void setDiscard(boolean discard) { |
284 public void setDiscard(boolean discard) { |
325 toDiscard = discard; |
285 toDiscard = discard; |
326 } |
286 } |
327 |
287 |
328 |
288 /** |
329 |
289 * Returns the discard attribute of the cookie |
330 |
290 * |
331 /** |
291 * @return a {@code boolean} to represent this cookie's discard attribute |
332 * Return the discard attribute of the cookie |
292 * |
333 * |
293 * @see #setDiscard |
334 * @return a <tt>boolean</tt> to represent this cookie's discard attribute |
294 */ |
335 * |
|
336 * @see #setDiscard |
|
337 */ |
|
338 |
|
339 public boolean getDiscard() { |
295 public boolean getDiscard() { |
340 return toDiscard; |
296 return toDiscard; |
341 } |
297 } |
342 |
298 |
343 |
|
344 /** |
299 /** |
345 * Specify the portlist of the cookie, which restricts the port(s) |
300 * Specify the portlist of the cookie, which restricts the port(s) |
346 * to which a cookie may be sent back in a Cookie header. |
301 * to which a cookie may be sent back in a Cookie header. |
347 * |
302 * |
348 * @param ports a <tt>String</tt> specify the port list, which is |
303 * @param ports |
349 * comma seperated series of digits |
304 * a {@code String} specify the port list, which is comma separated |
350 * @see #getPortlist |
305 * series of digits |
351 */ |
306 * |
352 |
307 * @see #getPortlist |
|
308 */ |
353 public void setPortlist(String ports) { |
309 public void setPortlist(String ports) { |
354 portlist = ports; |
310 portlist = ports; |
355 } |
311 } |
356 |
312 |
357 |
313 /** |
358 |
314 * Returns the port list attribute of the cookie |
359 |
315 * |
360 /** |
316 * @return a {@code String} contains the port list or {@code null} if none |
361 * Return the port list attribute of the cookie |
317 * |
362 * |
318 * @see #setPortlist |
363 * @return a <tt>String</tt> contains the port list |
319 */ |
364 * or <tt>null</tt> if none |
|
365 * @see #setPortlist |
|
366 */ |
|
367 |
|
368 public String getPortlist() { |
320 public String getPortlist() { |
369 return portlist; |
321 return portlist; |
370 } |
322 } |
371 |
323 |
372 /** |
324 /** |
373 * |
|
374 * Specifies the domain within which this cookie should be presented. |
325 * Specifies the domain within which this cookie should be presented. |
375 * |
326 * |
376 * <p>The form of the domain name is specified by RFC 2965. A domain |
327 * <p> The form of the domain name is specified by RFC 2965. A domain |
377 * name begins with a dot (<code>.foo.com</code>) and means that |
328 * name begins with a dot ({@code .foo.com}) and means that |
378 * the cookie is visible to servers in a specified Domain Name System |
329 * the cookie is visible to servers in a specified Domain Name System |
379 * (DNS) zone (for example, <code>www.foo.com</code>, but not |
330 * (DNS) zone (for example, {@code www.foo.com}, but not |
380 * <code>a.b.foo.com</code>). By default, cookies are only returned |
331 * {@code a.b.foo.com}). By default, cookies are only returned |
381 * to the server that sent them. |
332 * to the server that sent them. |
382 * |
333 * |
383 * |
334 * @param pattern |
384 * @param pattern a <code>String</code> containing the domain name |
335 * a {@code String} containing the domain name within which this |
385 * within which this cookie is visible; |
336 * cookie is visible; form is according to RFC 2965 |
386 * form is according to RFC 2965 |
337 * |
387 * |
338 * @see #getDomain |
388 * @see #getDomain |
339 */ |
389 * |
|
390 */ |
|
391 |
|
392 public void setDomain(String pattern) { |
340 public void setDomain(String pattern) { |
393 if (pattern != null) |
341 if (pattern != null) |
394 domain = pattern.toLowerCase(); |
342 domain = pattern.toLowerCase(); |
395 else |
343 else |
396 domain = pattern; |
344 domain = pattern; |
397 } |
345 } |
398 |
346 |
399 |
347 /** |
400 |
348 * Returns the domain name set for this cookie. The form of the domain name |
401 |
349 * is set by RFC 2965. |
402 |
350 * |
403 /** |
351 * @return a {@code String} containing the domain name |
404 * Returns the domain name set for this cookie. The form of |
352 * |
405 * the domain name is set by RFC 2965. |
353 * @see #setDomain |
406 * |
354 */ |
407 * @return a <code>String</code> containing the domain name |
|
408 * |
|
409 * @see #setDomain |
|
410 * |
|
411 */ |
|
412 |
|
413 public String getDomain() { |
355 public String getDomain() { |
414 return domain; |
356 return domain; |
415 } |
357 } |
416 |
358 |
417 |
|
418 /** |
359 /** |
419 * Sets the maximum age of the cookie in seconds. |
360 * Sets the maximum age of the cookie in seconds. |
420 * |
361 * |
421 * <p>A positive value indicates that the cookie will expire |
362 * <p> A positive value indicates that the cookie will expire |
422 * after that many seconds have passed. Note that the value is |
363 * after that many seconds have passed. Note that the value is |
423 * the <i>maximum</i> age when the cookie will expire, not the cookie's |
364 * the <i>maximum</i> age when the cookie will expire, not the cookie's |
424 * current age. |
365 * current age. |
425 * |
366 * |
426 * <p>A negative value means |
367 * <p> A negative value means that the cookie is not stored persistently |
427 * that the cookie is not stored persistently and will be deleted |
368 * and will be deleted when the Web browser exits. A zero value causes the |
428 * when the Web browser exits. A zero value causes the cookie |
369 * cookie to be deleted. |
429 * to be deleted. |
370 * |
430 * |
371 * @param expiry |
431 * @param expiry an integer specifying the maximum age of the |
372 * an integer specifying the maximum age of the cookie in seconds; |
432 * cookie in seconds; if zero, the cookie |
373 * if zero, the cookie should be discarded immediately; otherwise, |
433 * should be discarded immediately; |
374 * the cookie's max age is unspecified. |
434 * otherwise, the cookie's max age is unspecified. |
375 * |
435 * |
376 * @see #getMaxAge |
436 * @see #getMaxAge |
|
437 * |
|
438 */ |
377 */ |
439 public void setMaxAge(long expiry) { |
378 public void setMaxAge(long expiry) { |
440 maxAge = expiry; |
379 maxAge = expiry; |
441 } |
380 } |
442 |
381 |
443 |
382 /** |
444 |
383 * Returns the maximum age of the cookie, specified in seconds. By default, |
445 |
384 * {@code -1} indicating the cookie will persist until browser shutdown. |
446 /** |
385 * |
447 * Returns the maximum age of the cookie, specified in seconds. |
386 * @return an integer specifying the maximum age of the cookie in seconds |
448 * By default, <code>-1</code> indicating the cookie will persist |
387 * |
449 * until browser shutdown. |
388 * @see #setMaxAge |
450 * |
389 */ |
451 * |
|
452 * @return an integer specifying the maximum age of the |
|
453 * cookie in seconds |
|
454 * |
|
455 * |
|
456 * @see #setMaxAge |
|
457 * |
|
458 */ |
|
459 |
|
460 public long getMaxAge() { |
390 public long getMaxAge() { |
461 return maxAge; |
391 return maxAge; |
462 } |
392 } |
463 |
393 |
464 |
394 /** |
465 |
395 * Specifies a path for the cookie to which the client should return |
466 |
396 * the cookie. |
467 /** |
397 * |
468 * Specifies a path for the cookie |
398 * <p> The cookie is visible to all the pages in the directory |
469 * to which the client should return the cookie. |
|
470 * |
|
471 * <p>The cookie is visible to all the pages in the directory |
|
472 * you specify, and all the pages in that directory's subdirectories. |
399 * you specify, and all the pages in that directory's subdirectories. |
473 * A cookie's path must include the servlet that set the cookie, |
400 * A cookie's path must include the servlet that set the cookie, |
474 * for example, <i>/catalog</i>, which makes the cookie |
401 * for example, <i>/catalog</i>, which makes the cookie |
475 * visible to all directories on the server under <i>/catalog</i>. |
402 * visible to all directories on the server under <i>/catalog</i>. |
476 * |
403 * |
477 * <p>Consult RFC 2965 (available on the Internet) for more |
404 * <p> Consult RFC 2965 (available on the Internet) for more |
478 * information on setting path names for cookies. |
405 * information on setting path names for cookies. |
479 * |
406 * |
480 * |
407 * @param uri |
481 * @param uri a <code>String</code> specifying a path |
408 * a {@code String} specifying a path |
482 * |
409 * |
483 * |
410 * @see #getPath |
484 * @see #getPath |
411 */ |
485 * |
|
486 */ |
|
487 |
|
488 public void setPath(String uri) { |
412 public void setPath(String uri) { |
489 path = uri; |
413 path = uri; |
490 } |
414 } |
491 |
415 |
492 |
416 /** |
493 |
417 * Returns the path on the server to which the browser returns this cookie. |
494 |
418 * The cookie is visible to all subpaths on the server. |
495 /** |
419 * |
496 * Returns the path on the server |
420 * @return a {@code String} specifying a path that contains a servlet name, |
497 * to which the browser returns this cookie. The |
421 * for example, <i>/catalog</i> |
498 * cookie is visible to all subpaths on the server. |
422 * |
499 * |
423 * @see #setPath |
500 * |
424 */ |
501 * @return a <code>String</code> specifying a path that contains |
|
502 * a servlet name, for example, <i>/catalog</i> |
|
503 * |
|
504 * @see #setPath |
|
505 * |
|
506 */ |
|
507 |
|
508 public String getPath() { |
425 public String getPath() { |
509 return path; |
426 return path; |
510 } |
427 } |
511 |
428 |
512 |
|
513 |
|
514 |
|
515 |
|
516 /** |
429 /** |
517 * Indicates whether the cookie should only be sent using a secure protocol, |
430 * Indicates whether the cookie should only be sent using a secure protocol, |
518 * such as HTTPS or SSL. |
431 * such as HTTPS or SSL. |
519 * |
432 * |
520 * <p>The default value is <code>false</code>. |
433 * <p> The default value is {@code false}. |
521 * |
434 * |
522 * @param flag If <code>true</code>, the cookie can only be sent over |
435 * @param flag |
523 * a secure protocol like https. |
436 * If {@code true}, the cookie can only be sent over a secure |
524 * If <code>false</code>, it can be sent over any protocol. |
437 * protocol like HTTPS. If {@code false}, it can be sent over |
525 * |
438 * any protocol. |
526 * @see #getSecure |
439 * |
527 * |
440 * @see #getSecure |
528 */ |
441 */ |
529 |
|
530 public void setSecure(boolean flag) { |
442 public void setSecure(boolean flag) { |
531 secure = flag; |
443 secure = flag; |
532 } |
444 } |
533 |
445 |
534 |
446 /** |
535 |
447 * Returns {@code true} if sending this cookie should be restricted to a |
536 |
448 * secure protocol, or {@code false} if the it can be sent using any |
537 /** |
449 * protocol. |
538 * Returns <code>true</code> if sending this cookie should be |
450 * |
539 * restricted to a secure protocol, or <code>false</code> if the |
451 * @return {@code false} if the cookie can be sent over any standard |
540 * it can be sent using any protocol. |
452 * protocol; otherwise, <code>true</code> |
541 * |
453 * |
542 * @return <code>false</code> if the cookie can be sent over |
454 * @see #setSecure |
543 * any standard protocol; otherwise, <code>true</code> |
455 */ |
544 * |
|
545 * @see #setSecure |
|
546 * |
|
547 */ |
|
548 |
|
549 public boolean getSecure() { |
456 public boolean getSecure() { |
550 return secure; |
457 return secure; |
551 } |
458 } |
552 |
459 |
553 |
|
554 |
|
555 |
|
556 |
|
557 /** |
460 /** |
558 * Returns the name of the cookie. The name cannot be changed after |
461 * Returns the name of the cookie. The name cannot be changed after |
559 * creation. |
462 * creation. |
560 * |
463 * |
561 * @return a <code>String</code> specifying the cookie's name |
464 * @return a {@code String} specifying the cookie's name |
562 * |
465 */ |
563 */ |
|
564 |
|
565 public String getName() { |
466 public String getName() { |
566 return name; |
467 return name; |
567 } |
468 } |
568 |
469 |
569 |
470 /** |
570 |
|
571 |
|
572 |
|
573 /** |
|
574 * |
|
575 * Assigns a new value to a cookie after the cookie is created. |
471 * Assigns a new value to a cookie after the cookie is created. |
576 * If you use a binary value, you may want to use BASE64 encoding. |
472 * If you use a binary value, you may want to use BASE64 encoding. |
577 * |
473 * |
578 * <p>With Version 0 cookies, values should not contain white |
474 * <p> With Version 0 cookies, values should not contain white space, |
579 * space, brackets, parentheses, equals signs, commas, |
475 * brackets, parentheses, equals signs, commas, double quotes, slashes, |
580 * double quotes, slashes, question marks, at signs, colons, |
476 * question marks, at signs, colons, and semicolons. Empty values may not |
581 * and semicolons. Empty values may not behave the same way |
477 * behave the same way on all browsers. |
582 * on all browsers. |
478 * |
583 * |
479 * @param newValue |
584 * @param newValue a <code>String</code> specifying the new value |
480 * a {@code String} specifying the new value |
585 * |
481 * |
586 * |
482 * @see #getValue |
587 * @see #getValue |
483 */ |
588 * |
|
589 */ |
|
590 |
|
591 public void setValue(String newValue) { |
484 public void setValue(String newValue) { |
592 value = newValue; |
485 value = newValue; |
593 } |
486 } |
594 |
487 |
595 |
|
596 |
|
597 |
|
598 /** |
488 /** |
599 * Returns the value of the cookie. |
489 * Returns the value of the cookie. |
600 * |
490 * |
601 * @return a <code>String</code> containing the cookie's |
491 * @return a {@code String} containing the cookie's present value |
602 * present value |
492 * |
603 * |
493 * @see #setValue |
604 * @see #setValue |
494 */ |
605 * |
|
606 */ |
|
607 |
|
608 public String getValue() { |
495 public String getValue() { |
609 return value; |
496 return value; |
610 } |
497 } |
611 |
498 |
612 |
499 /** |
613 |
500 * Returns the version of the protocol this cookie complies with. Version 1 |
614 |
501 * complies with RFC 2965/2109, and version 0 complies with the original |
615 /** |
502 * cookie specification drafted by Netscape. Cookies provided by a browser |
616 * Returns the version of the protocol this cookie complies |
503 * use and identify the browser's cookie version. |
617 * with. Version 1 complies with RFC 2965/2109, |
504 * |
618 * and version 0 complies with the original |
505 * @return 0 if the cookie complies with the original Netscape |
619 * cookie specification drafted by Netscape. Cookies provided |
506 * specification; 1 if the cookie complies with RFC 2965/2109 |
620 * by a browser use and identify the browser's cookie version. |
507 * |
621 * |
508 * @see #setVersion |
622 * |
509 */ |
623 * @return 0 if the cookie complies with the |
|
624 * original Netscape specification; 1 |
|
625 * if the cookie complies with RFC 2965/2109 |
|
626 * |
|
627 * @see #setVersion |
|
628 * |
|
629 */ |
|
630 |
|
631 public int getVersion() { |
510 public int getVersion() { |
632 return version; |
511 return version; |
633 } |
512 } |
634 |
|
635 |
|
636 |
|
637 |
513 |
638 /** |
514 /** |
639 * Sets the version of the cookie protocol this cookie complies |
515 * Sets the version of the cookie protocol this cookie complies |
640 * with. Version 0 complies with the original Netscape cookie |
516 * with. Version 0 complies with the original Netscape cookie |
641 * specification. Version 1 complies with RFC 2965/2109. |
517 * specification. Version 1 complies with RFC 2965/2109. |
642 * |
518 * |
643 * |
519 * @param v |
644 * @param v 0 if the cookie should comply with |
520 * 0 if the cookie should comply with the original Netscape |
645 * the original Netscape specification; |
521 * specification; 1 if the cookie should comply with RFC 2965/2109 |
646 * 1 if the cookie should comply with RFC 2965/2109 |
522 * |
647 * |
523 * @throws IllegalArgumentException |
648 * @throws IllegalArgumentException if <tt>v</tt> is neither 0 nor 1 |
524 * if {@code v} is neither 0 nor 1 |
649 * |
525 * |
650 * @see #getVersion |
526 * @see #getVersion |
651 * |
527 */ |
652 */ |
|
653 |
|
654 public void setVersion(int v) { |
528 public void setVersion(int v) { |
655 if (v != 0 && v != 1) { |
529 if (v != 0 && v != 1) { |
656 throw new IllegalArgumentException("cookie version should be 0 or 1"); |
530 throw new IllegalArgumentException("cookie version should be 0 or 1"); |
657 } |
531 } |
658 |
532 |
972 } |
846 } |
973 |
847 |
974 return cookie; |
848 return cookie; |
975 } |
849 } |
976 |
850 |
977 |
|
978 /* |
851 /* |
979 * assign cookie attribute value to attribute name; |
852 * assign cookie attribute value to attribute name; |
980 * use a map to simulate method dispatch |
853 * use a map to simulate method dispatch |
981 */ |
854 */ |
982 static interface CookieAttributeAssignor { |
855 static interface CookieAttributeAssignor { |
983 public void assign(HttpCookie cookie, String attrName, String attrValue); |
856 public void assign(HttpCookie cookie, |
984 } |
857 String attrName, |
985 static java.util.Map<String, CookieAttributeAssignor> assignors = null; |
858 String attrValue); |
|
859 } |
|
860 static final java.util.Map<String, CookieAttributeAssignor> assignors = |
|
861 new java.util.HashMap<>(); |
986 static { |
862 static { |
987 assignors = new java.util.HashMap<String, CookieAttributeAssignor>(); |
863 assignors.put("comment", new CookieAttributeAssignor() { |
988 assignors.put("comment", new CookieAttributeAssignor(){ |
864 public void assign(HttpCookie cookie, |
989 public void assign(HttpCookie cookie, String attrName, String attrValue) { |
865 String attrName, |
990 if (cookie.getComment() == null) cookie.setComment(attrValue); |
866 String attrValue) { |
|
867 if (cookie.getComment() == null) |
|
868 cookie.setComment(attrValue); |
991 } |
869 } |
992 }); |
870 }); |
993 assignors.put("commenturl", new CookieAttributeAssignor(){ |
871 assignors.put("commenturl", new CookieAttributeAssignor() { |
994 public void assign(HttpCookie cookie, String attrName, String attrValue) { |
872 public void assign(HttpCookie cookie, |
995 if (cookie.getCommentURL() == null) cookie.setCommentURL(attrValue); |
873 String attrName, |
|
874 String attrValue) { |
|
875 if (cookie.getCommentURL() == null) |
|
876 cookie.setCommentURL(attrValue); |
996 } |
877 } |
997 }); |
878 }); |
998 assignors.put("discard", new CookieAttributeAssignor(){ |
879 assignors.put("discard", new CookieAttributeAssignor() { |
999 public void assign(HttpCookie cookie, String attrName, String attrValue) { |
880 public void assign(HttpCookie cookie, |
|
881 String attrName, |
|
882 String attrValue) { |
1000 cookie.setDiscard(true); |
883 cookie.setDiscard(true); |
1001 } |
884 } |
1002 }); |
885 }); |
1003 assignors.put("domain", new CookieAttributeAssignor(){ |
886 assignors.put("domain", new CookieAttributeAssignor(){ |
1004 public void assign(HttpCookie cookie, String attrName, String attrValue) { |
887 public void assign(HttpCookie cookie, |
1005 if (cookie.getDomain() == null) cookie.setDomain(attrValue); |
888 String attrName, |
|
889 String attrValue) { |
|
890 if (cookie.getDomain() == null) |
|
891 cookie.setDomain(attrValue); |
1006 } |
892 } |
1007 }); |
893 }); |
1008 assignors.put("max-age", new CookieAttributeAssignor(){ |
894 assignors.put("max-age", new CookieAttributeAssignor(){ |
1009 public void assign(HttpCookie cookie, String attrName, String attrValue) { |
895 public void assign(HttpCookie cookie, |
|
896 String attrName, |
|
897 String attrValue) { |
1010 try { |
898 try { |
1011 long maxage = Long.parseLong(attrValue); |
899 long maxage = Long.parseLong(attrValue); |
1012 if (cookie.getMaxAge() == MAX_AGE_UNSPECIFIED) cookie.setMaxAge(maxage); |
900 if (cookie.getMaxAge() == MAX_AGE_UNSPECIFIED) |
|
901 cookie.setMaxAge(maxage); |
1013 } catch (NumberFormatException ignored) { |
902 } catch (NumberFormatException ignored) { |
1014 throw new IllegalArgumentException("Illegal cookie max-age attribute"); |
903 throw new IllegalArgumentException( |
|
904 "Illegal cookie max-age attribute"); |
1015 } |
905 } |
1016 } |
906 } |
1017 }); |
907 }); |
1018 assignors.put("path", new CookieAttributeAssignor(){ |
908 assignors.put("path", new CookieAttributeAssignor(){ |
1019 public void assign(HttpCookie cookie, String attrName, String attrValue) { |
909 public void assign(HttpCookie cookie, |
1020 if (cookie.getPath() == null) cookie.setPath(attrValue); |
910 String attrName, |
|
911 String attrValue) { |
|
912 if (cookie.getPath() == null) |
|
913 cookie.setPath(attrValue); |
1021 } |
914 } |
1022 }); |
915 }); |
1023 assignors.put("port", new CookieAttributeAssignor(){ |
916 assignors.put("port", new CookieAttributeAssignor(){ |
1024 public void assign(HttpCookie cookie, String attrName, String attrValue) { |
917 public void assign(HttpCookie cookie, |
1025 if (cookie.getPortlist() == null) cookie.setPortlist(attrValue == null ? "" : attrValue); |
918 String attrName, |
|
919 String attrValue) { |
|
920 if (cookie.getPortlist() == null) |
|
921 cookie.setPortlist(attrValue == null ? "" : attrValue); |
1026 } |
922 } |
1027 }); |
923 }); |
1028 assignors.put("secure", new CookieAttributeAssignor(){ |
924 assignors.put("secure", new CookieAttributeAssignor(){ |
1029 public void assign(HttpCookie cookie, String attrName, String attrValue) { |
925 public void assign(HttpCookie cookie, |
|
926 String attrName, |
|
927 String attrValue) { |
1030 cookie.setSecure(true); |
928 cookie.setSecure(true); |
1031 } |
929 } |
1032 }); |
930 }); |
1033 assignors.put("httponly", new CookieAttributeAssignor(){ |
931 assignors.put("httponly", new CookieAttributeAssignor(){ |
1034 public void assign(HttpCookie cookie, String attrName, String attrValue) { |
932 public void assign(HttpCookie cookie, |
|
933 String attrName, |
|
934 String attrValue) { |
1035 cookie.setHttpOnly(true); |
935 cookie.setHttpOnly(true); |
1036 } |
936 } |
1037 }); |
937 }); |
1038 assignors.put("version", new CookieAttributeAssignor(){ |
938 assignors.put("version", new CookieAttributeAssignor(){ |
1039 public void assign(HttpCookie cookie, String attrName, String attrValue) { |
939 public void assign(HttpCookie cookie, |
|
940 String attrName, |
|
941 String attrValue) { |
1040 try { |
942 try { |
1041 int version = Integer.parseInt(attrValue); |
943 int version = Integer.parseInt(attrValue); |
1042 cookie.setVersion(version); |
944 cookie.setVersion(version); |
1043 } catch (NumberFormatException ignored) { |
945 } catch (NumberFormatException ignored) { |
1044 // Just ignore bogus version, it will default to 0 or 1 |
946 // Just ignore bogus version, it will default to 0 or 1 |
1045 } |
947 } |
1046 } |
948 } |
1047 }); |
949 }); |
1048 assignors.put("expires", new CookieAttributeAssignor(){ // Netscape only |
950 assignors.put("expires", new CookieAttributeAssignor(){ // Netscape only |
1049 public void assign(HttpCookie cookie, String attrName, String attrValue) { |
951 public void assign(HttpCookie cookie, |
|
952 String attrName, |
|
953 String attrValue) { |
1050 if (cookie.getMaxAge() == MAX_AGE_UNSPECIFIED) { |
954 if (cookie.getMaxAge() == MAX_AGE_UNSPECIFIED) { |
1051 cookie.setMaxAge(cookie.expiryDate2DeltaSeconds(attrValue)); |
955 cookie.setMaxAge(cookie.expiryDate2DeltaSeconds(attrValue)); |
1052 } |
956 } |
1053 } |
957 } |
1054 }); |
958 }); |
1055 } |
959 } |
1056 private static void assignAttribute(HttpCookie cookie, |
960 private static void assignAttribute(HttpCookie cookie, |
1057 String attrName, |
961 String attrName, |
1058 String attrValue) |
962 String attrValue) |
1059 { |
963 { |
1060 // strip off the surrounding "-sign if there's any |
964 // strip off the surrounding "-sign if there's any |
1061 attrValue = stripOffSurroundingQuote(attrValue); |
965 attrValue = stripOffSurroundingQuote(attrValue); |
1062 |
966 |
1063 CookieAttributeAssignor assignor = assignors.get(attrName.toLowerCase()); |
967 CookieAttributeAssignor assignor = assignors.get(attrName.toLowerCase()); |