Source code: com/sonalb/net/http/cookie/Cookie.java
1 /*
2 * -*- mode: java; c-basic-indent: 4; indent-tabs-mode: nil -*-
3 * :indentSize=4:noTabs=true:tabSize=4:indentOnTab=true:indentOnEnter=true:mode=java:
4 * ex: set tabstop=4 expandtab:
5 *
6 * MrPostman - webmail <-> email gateway
7 * Copyright (C) 2002-2003 MrPostman Development Group
8 * Projectpage: http://mrbook.org/mrpostman/
9 *
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 * In particular, this implies that users are responsible for
21 * using MrPostman after reading the terms and conditions given
22 * by their web-mail provider.
23 *
24 * You should have received a copy of the GNU General Public License
25 * Named LICENSE in the base directory of this distribution,
26 * if not, write to the Free Software
27 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
28 */
29
30 package com.sonalb.net.http.cookie;
31
32 import com.sonalb.Utils;
33
34 import java.net.URL;
35
36 import java.util.Date;
37
38
39 /*
40
41 /1.) Portlist determination from requestURL
42
43 /2.) MaxAge setting requires Base time
44
45 /3.) Expires is null only if maxage=0
46
47 /4.) secure determined from Protocol (HTTPS eg.)
48
49 /5.) maxage is -ve only if version=0
50
51 /6.) Right now an IP address instead of Fully Qualified Domain Name would
52
53 throw spanner in domain matching ... must discern between IP and name.
54
55 7.) Path matching is case-sensitive. Follows from "Cookie Management" section of RFC2965.
56
57 8.) If max-age is set to value other than 0 then discard should be false, unless explicitly set.
58
59
60
61 NOTE:
62
63 1.) A cookie with domain=.foo.com will be sent by client to host=y.x.foo.com . However,
64
65 a cookie sent by y.x.foo.com with Domain=.foo.com will be rejected.
66
67 2.) sendWith(URL) should not take into consideration whether cookie has expired. Document this.
68
69 3.) Calling setExpires(Date) explicitly causes Cookie version to be reset to '0'
70
71 3.1) Fixed ... USOE thrown if version=1 and setExpires called (To maintain consistency). getExpires is allowed for Version 1.
72
73 4.) Right now an UnsupportedOpExc is thrown only when get/setMaxAge is called on a Version 0 cookie.
74
75 V0 also does not support comment,commentURL,discard,port. Do we need to throw exc for these ?
76
77 4.1) Made tough cookie ... throws USOE now. However, comment & commentURL field is allowed for version 0 cookie. Just in
78
79 case some extra info is required to be stored.
80
81 5.) According to RFC2965, if Set-Cookie and set-cookie2 both describe the same cookie, then sc2 should be used.
82
83 This distinction has not been incorporated.
84
85
86
87 */
88
89 /**
90
91 * The data structure representing a cookie. Supports both Netscape (Version 0) and RFC2965 (Version 1)
92
93 * cookies. The fields common to both these versions are listed below:
94
95 * <ul>
96
97 * <li>NAME - Must be set, no default value</li>
98
99 * <li>VALUE - Default value: Empty</li>
100
101 * <li>Domain - Must be set, default: Local</li>
102
103 * <li>Path - Must be set, default: / (root)</li>
104
105 * <li>Secure - Optional, default: false</li>
106
107 * </ul>
108
109 * @author Sonal Bansal
110
111 */
112 public class Cookie implements Cloneable, java.io.Serializable, Comparable {
113 public static final String CVSID = "$Id: Cookie.java,v 1.5 2003/02/09 23:38:11 lbruand Exp $";
114 private String name;
115 private String value;
116 private String comment;
117 private URL commentURL;
118 private boolean discard;
119 private String domain;
120 private int maxage;
121 private String path;
122 private String portList;
123 private boolean secure;
124 private String version;
125 private Date expires;
126 private Object lockSecure;
127 private Object lockDiscard;
128 private Object lockMaxage;
129 private boolean bExplicitDomain;
130 private boolean bExplicitExpires;
131 private boolean bExplicitMaxage;
132 private boolean bExplicitPath;
133 private boolean bExplicitPort;
134 private boolean bPortListSpecified;
135
136 /**
137
138 * Creates cookie instance.
139
140 *
141
142 * @param name the Cookie name
143
144 * @param value the Cookie value
145
146 * @param domain the domain in which this Cookie is valid
147
148 * @param path the path for this Cookie
149
150 */
151 public Cookie(String name, String value, String domain, String path) {
152 this(name, value, domain, path, null);
153 }
154
155 /**
156
157 * Creates cookie instance. The path and domain are picked up from the request URL.
158
159 * @param name the Cookie name
160
161 * @param value the Cookie value
162
163 * @param requestURL the request URL which resulted in this cookie being received
164
165 */
166 public Cookie(String name, String value, URL requestURL) {
167 this(name, value, null, null, requestURL);
168 }
169
170 protected Cookie(String name, String value, String domain, String path, URL requestURL) {
171 initializeFields();
172
173 setName(name);
174
175 setValue(value);
176
177 setDomain(domain, requestURL);
178
179 setPath(path, requestURL);
180
181 if (requestURL != null) {
182 setPort(requestURL.getPort());
183
184 String protocol = requestURL.getProtocol();
185
186 if (!Utils.isNullOrWhiteSpace(protocol)) {
187 protocol = protocol.toLowerCase();
188
189 if ("https".equals(protocol) || "shttp".equals(protocol)) {
190 secure = true;
191 }
192 }
193 }
194 }
195
196 Cookie() {
197 initializeFields();
198 }
199
200 private void initializeFields() {
201 name = new String();
202
203 value = new String();
204
205 comment = new String();
206
207 commentURL = null;
208
209 discard = false;
210
211 domain = new String();
212
213 maxage = -1;
214
215 path = new String();
216
217 portList = new String();
218
219 secure = false;
220
221 version = "1";
222
223 expires = new Date(0);
224
225 lockSecure = new Object();
226
227 lockDiscard = new Object();
228
229 lockMaxage = new Object();
230
231 bExplicitDomain = bExplicitExpires = bExplicitMaxage = bExplicitPath = bExplicitPort = bPortListSpecified = false;
232 }
233
234 public Object clone() throws CloneNotSupportedException {
235 return (super.clone());
236 }
237
238 /**
239
240 * Compares one Cookie with another. The natural ordering is such that it follows the path
241
242 * specificity rule laid down in RFC2695. Thus more specific path ("/acme/corp") comes
243
244 * before ("is less than") less specific path ("/acme").
245
246 */
247 public int compareTo(Object o) {
248 if ((o == null) || !(o instanceof Cookie)) {
249 throw new ClassCastException("Object is null or not a Cookie");
250 }
251
252 if (equals(o)) {
253 return (0);
254 }
255
256 Cookie c = (Cookie) o;
257
258 if (!isValid() || !c.isValid()) {
259 throw new IllegalArgumentException("Either I am an invalid cookie or the argument is.");
260 }
261
262 int mySlashes;
263 int hisSlashes;
264
265 mySlashes = Utils.countInstances(getPath(), '/');
266
267 hisSlashes = Utils.countInstances(c.getPath(), '/');
268
269 if (mySlashes == hisSlashes) {
270 if (mySlashes == 1) {
271 boolean bMine = "/".equals(getPath());
272
273 boolean bHis = "/".equals(c.getPath());
274
275 if (bMine || bHis) {
276 if (!(bMine && bHis)) {
277 if (bMine) {
278 return (1);
279 } else {
280 return (-1);
281 }
282 }
283 }
284 }
285
286 return (0);
287 } else if (mySlashes > hisSlashes) {
288 return (-1);
289 }
290
291 return (1);
292 }
293
294 protected boolean isValid() {
295 synchronized (name) {
296 synchronized (domain) {
297 synchronized (path) {
298 if (Utils.isNullOrWhiteSpace(name) || Utils.isNullOrWhiteSpace(domain)
299 || Utils.isNullOrWhiteSpace(path)) {
300 return (false);
301 }
302
303 return (true);
304 }
305 }
306 }
307 }
308
309 /**
310
311 * Sets the Cookie name.
312
313 * @param name the Cookie name
314
315 */
316 public void setName(String name) {
317 if (Utils.isNullOrWhiteSpace(name)) {
318 throw new IllegalArgumentException("Cookie can't have empty name.");
319 }
320
321 synchronized (this.name) {
322 this.name = name;
323 }
324 }
325
326 /**
327
328 * Sets the Cookie value.
329
330 * @param value the Cookie value
331
332 */
333 public void setValue(String value) {
334 synchronized (this.value) {
335 this.value = (value == null) ? "" : value;
336 }
337 }
338
339 protected void setMaxAge(int maxage, Date base, boolean bInsider) {
340 if (!bInsider) {
341 if ("0".equals(version)) {
342 throw new UnsupportedOperationException("Version 0 cookies do not support Max-Age");
343 }
344
345 if ((maxage < 0) || (base == null)) {
346 throw new IllegalArgumentException("Can't set max age");
347 }
348 }
349
350 if (maxage == 0) {
351 synchronized (this.lockMaxage) {
352 synchronized (this.expires) {
353 synchronized (this.lockDiscard) {
354 bExplicitMaxage = true;
355
356 this.maxage = 0;
357
358 bExplicitExpires = false;
359
360 expires = new Date(0);
361
362 discard = true;
363 }
364 }
365 }
366
367 return;
368 }
369
370 synchronized (this.lockMaxage) {
371 synchronized (this.expires) {
372 bExplicitMaxage = true;
373
374 this.maxage = maxage;
375
376 long expiry = base.getTime() + (maxage * 1000);
377
378 expires = new Date(expiry);
379
380 bExplicitExpires = true;
381 }
382 }
383 }
384
385 /**
386
387 * Sets the lifetime of this Cookie. Applicable only to Version 1 cookies.
388
389 * @param maxage the number of seconds from now that this Cookie is valid (delta-t)
390
391 * @throws UnsupportedOperationException when called on a Version 0 cookie
392
393 */
394 public void setMaxAge(int maxage) {
395 setMaxAge(maxage, new Date());
396 }
397
398 /**
399
400 * Sets the lifetime of this Cookie. Applicable only to Version 1 cookies.
401
402 * @param maxage the number of seconds from base that this Cookie is valid (delta-t)
403
404 * @param base the Date from which the delta-t should be counted
405
406 * @throws UnsupportedOperationException when called on a Version 0 cookie
407
408 */
409 public void setMaxAge(int maxage, Date base) {
410 setMaxAge(maxage, base, false);
411 }
412
413 protected boolean explicitDomain() {
414 return (bExplicitDomain);
415 }
416
417 protected boolean explicitPath() {
418 return (bExplicitPath);
419 }
420
421 protected boolean explicitPort() {
422 return (bExplicitPort);
423 }
424
425 protected boolean explicitExpires() {
426 return (bExplicitExpires);
427 }
428
429 protected boolean explicitMaxage() {
430 return (bExplicitMaxage);
431 }
432
433 protected boolean portListSpecified() {
434 return (bPortListSpecified);
435 }
436
437 /**
438
439 * Gets the amount of time this Cookie is valid, measured in seconds from the time the value was set.
440
441 * Applicable only to Version 0 cookies.
442
443 *
444
445 * @return the delta-t that this Cookie holds valid
446
447 * @throws UnsupportedOperationException if this method is called on a Version 0 cookie
448
449 */
450 public int getMaxAge() {
451 if ("0".equals(version)) {
452 throw new UnsupportedOperationException("Version 0 cookies do not support Max-Age");
453 }
454
455 if (!bExplicitMaxage) {
456 return (-1);
457 }
458
459 synchronized (lockMaxage) {
460 return (maxage);
461 }
462 }
463
464 /**
465
466 * Sets the date-time when this cookie expires. Applicable only to Version 0 cookies.
467
468 * @param expires the Date when this cookie expires
469
470 * @throws UnsupportedOperationException when called on a Version 1 cookie
471
472 */
473 public void setExpires(Date expires) {
474 if ("1".equals(version)) {
475 throw new UnsupportedOperationException("Version 1 cookies do not support Expires. Use Max-Age.");
476 }
477
478 synchronized (this.expires) {
479 if (expires == null) {
480 bExplicitExpires = false;
481
482 this.expires = new Date(0);
483 } else {
484 bExplicitExpires = true;
485
486 this.expires = expires;
487 }
488 }
489 }
490
491 /**
492
493 * Sets the Cookie version. The version determines what fields and methods are valid for a
494
495 * Cookie instance. It also determines the format in which the Cookie is sent with a request.
496
497 * @param version the Cookie version. Either "0" or "1"
498
499 */
500 public void setVersion(String version) {
501 if (!("0".equals(version) || "1".equals(version))) {
502 throw new IllegalArgumentException("Unsupported cookie version");
503 }
504
505 synchronized (this.version) {
506 this.version = version;
507 }
508
509 if ("0".equals(version)) {
510 bExplicitMaxage = false;
511 } else if (maxage == -1) {
512 bExplicitMaxage = false;
513 }
514 }
515
516 /**
517
518 * Gets the version of this Cookie.
519
520 * @return the version; either "0" or "1"
521
522 */
523 public String getVersion() {
524 synchronized (version) {
525 return (version);
526 }
527 }
528
529 protected void setPath(String path, URL requestURL) {
530 if (!Utils.isNullOrWhiteSpace(path)) {
531 synchronized (this.path) {
532 bExplicitPath = true;
533
534 path = path.trim();
535
536 if (path.charAt(0) != '/') {
537 path = "/" + path;
538 }
539
540 this.path = path;
541 }
542 } else {
543 synchronized (this.path) {
544 bExplicitPath = false;
545
546 this.path = (requestURL == null) ? null : requestURL.getPath();
547
548 if (Utils.isNullOrWhiteSpace(this.path)) {
549 this.path = "/";
550 }
551
552 if (this.path.charAt(this.path.length() - 1) != '/') {
553 this.path = this.path.substring(0, this.path.lastIndexOf('/') + 1);
554 }
555 }
556 }
557 }
558
559 /**
560
561 * Sets the path for this Cookie.
562
563 * @param path the Path for this Cookie
564
565 */
566 public void setPath(String path) {
567 setPath(path, null);
568 }
569
570 /**
571
572 * Sets the path for this Cookie. Path is extracted from the URL.
573
574 * @param requestURL the request URL which caused this Cookie to be sent.
575
576 */
577 public void setPath(URL requestURL) {
578 setPath(null, requestURL);
579 }
580
581 protected void setDomain(String domain, URL requestURL) {
582 synchronized (this.domain) {
583 if (!Utils.isNullOrWhiteSpace(domain)) {
584 bExplicitDomain = true;
585
586 domain = domain.trim();
587
588 if (!Utils.isIPAddress(domain)) {
589 if (domain.charAt(0) != '.') {
590 domain = "." + domain;
591 }
592 }
593
594 this.domain = domain;
595 } else {
596 bExplicitDomain = false;
597
598 this.domain = (requestURL == null) ? null : requestURL.getHost();
599
600 if (Utils.isNullOrWhiteSpace(this.domain)) {
601 throw new IllegalArgumentException("Could not determine cookie domain.");
602 }
603 }
604
605 if (this.domain.indexOf('.') == -1) {
606 this.domain += ".local";
607 }
608 }
609 }
610
611 /**
612
613 * Sets the domain for this Cookie. The domain determines which hosts can receive this Cookie.
614
615 * @param domain the Cookie domain
616
617 */
618 public void setDomain(String domain) {
619 setDomain(domain, null);
620 }
621
622 /**
623
624 * Sets the domain for this Cookie. The domain determines which hosts can receive this Cookie.
625
626 * @param requestURL the request URL which caused this cookie to be sent
627
628 */
629 public void setDomain(URL requestURL) {
630 setDomain(null, requestURL);
631 }
632
633 /**
634
635 * Sets the list of ports to which this Cookie can be sent. Applicable only to Version 1 cookies.
636
637 * @param ports the valid ports as array of int; non-positive values ignored
638
639 * @throws UnsupportedException when called on a Version 0 cookie
640
641 */
642 public void setPortList(int[] ports) {
643 if ("0".equals(version)) {
644 throw new UnsupportedOperationException("Version 0 cookies do not support Port Matching");
645 }
646
647 StringBuffer sb = new StringBuffer();
648
649 for (int i = 0; i < ports.length; i++) {
650 if (ports[i] > 0) {
651 sb.append(ports[i]);
652
653 sb.append(',');
654 }
655 }
656
657 sb.deleteCharAt(sb.length() - 1);
658
659 if (sb.length() <= 0) {
660 bExplicitPort = false;
661 }
662
663 synchronized (portList) {
664 bExplicitPort = true;
665
666 bPortListSpecified = true;
667
668 portList = sb.toString();
669 }
670 }
671
672 /**
673
674 * Sets the port to which this cookie can be sent. Applicable only to Version 1 cookies.
675
676 * @param p the Port
677
678 * @throws UnsupportedOperationException when called on a Version 0 cookie
679
680 */
681 public void setPort(int p) {
682 setPort(p, null);
683 }
684
685 /**
686
687 * Sets the port to which this cookie can be sent. Port is extracted from URL.
688
689 * Applicable only to Version 1 cookies.
690
691 * @param url the request URL
692
693 * @throws UnsupportedOperationException when called on a Version 0 cookie
694
695 */
696 public void setPort(URL url) {
697 setPort(-1, url);
698 }
699
700 protected void setPort(int p, URL url) {
701 if ("0".equals(version)) {
702 throw new UnsupportedOperationException("Version 0 cookies do not support Port Matching.");
703 }
704
705 if (p < 0) {
706 p = ((url == null) ? 80 : ((url.getPort() == -1) ? 80 : url.getPort()));
707
708 bExplicitPort = false;
709 }
710
711 synchronized (portList) {
712 bExplicitPort = true;
713
714 portList = String.valueOf(p);
715 }
716 }
717
718 /**
719
720 * Gets the list of ports to which this cookie can be sent.
721
722 * Applicable only to Version 1 cookies.
723
724 * @return the comma-separated list of valid ports
725
726 * @throws UnsupportedOperationException when called on a Version 0 cookie
727
728 */
729 public String getPortList() {
730 if ("0".equals(version)) {
731 throw new UnsupportedOperationException("Version 0 cookies do not support Port Matching");
732 }
733
734 synchronized (portList) {
735 return (portList);
736 }
737 }
738
739 /**
740
741 * Sets whether this cookie should be sent only over secure channels.
742
743 * @param bSecure secure or not ?
744
745 */
746 public void setSecure(boolean bSecure) {
747 synchronized (this.lockSecure) {
748 this.secure = bSecure;
749 }
750 }
751
752 /**
753
754 * Gets the name of this cookie.
755
756 * @return the cookie name
757
758 */
759 public String getName() {
760 synchronized (name) {
761 return (name);
762 }
763 }
764
765 /**
766
767 * Gets the value of this cookie.
768
769 * @return the cookie value
770
771 */
772 public String getValue() {
773 synchronized (value) {
774 return (value);
775 }
776 }
777
778 /**
779
780 * Gets the comment for this cookie.
781
782 * @return the comment
783
784 */
785 public String getComment() {
786 synchronized (comment) {
787 return (comment);
788 }
789 }
790
791 /**
792
793 * Sets the comment for this cookie. Comment has no functional value.
794
795 * @param comment the comment
796
797 */
798 public void setComment(String comment) {
799 synchronized (this.comment) {
800 this.comment = comment;
801 }
802 }
803
804 /**
805
806 * Sets the comment URL for this cookie. URL has no functional value.
807
808 * @param url the URL
809
810 */
811 public void setCommentURL(URL url) {
812 synchronized (this.commentURL) {
813 commentURL = url;
814 }
815 }
816
817 /**
818
819 * Gets the comment URL for this cookie.
820
821 * @return the comment URL
822
823 */
824 public URL getCommentURL() {
825 synchronized (commentURL) {
826 return (commentURL);
827 }
828 }
829
830 /**
831
832 * Gets the date-time when this cookie expires. Note that this can be called on both Version 0 AND
833
834 * Version 1 cookies.
835
836 * @return the date-time when this cookie expires
837
838 */
839 public Date getExpires() {
840 if (!bExplicitExpires) {
841 return (null);
842 }
843
844 synchronized (expires) {
845 return (expires);
846 }
847 }
848
849 /**
850
851 * Checks whether this cookie can be discarded once the session is over. This is different from the
852
853 * lifetime of the cookie.
854
855 * @return discardable or not ?
856
857 */
858 public boolean isDiscardable() {
859 if ("0".equals(version)) {
860 throw new UnsupportedOperationException(
861 "Version 0 cookies do not support Discard. Use hasExpired() instead");
862 }
863
864 synchronized (this.lockDiscard) {
865 synchronized (lockMaxage) {
866 return (discard || (maxage == 0));
867 }
868 }
869 }
870
871 /**
872
873 * Sets the discard status of this cookie. This determines whether the cookie is valid after the session
874
875 * is over. It is different from lifetime. Applicable only to Version 1 cookies.
876
877 * @param bDiscard discardable or not ?
878
879 * @throws UnsupportedOperationException when called on a Version 0 cookie
880
881 */
882 public void setDiscard(boolean bDiscard) {
883 if ("0".equals(version)) {
884 throw new UnsupportedOperationException("Version 0 cookies do not support Discard.");
885 }
886
887 synchronized (this.lockDiscard) {
888 discard = bDiscard;
889 }
890 }
891
892 /**
893
894 * Gets the domain in which this cookie is valid.
895
896 * @return the domain
897
898 */
899 public String getDomain() {
900 synchronized (domain) {
901 return (domain);
902 }
903 }
904
905 /**
906
907 * Gets the path for this cookie.
908
909 * @return the path
910
911 */
912 public String getPath() {
913 synchronized (path) {
914 return (path);
915 }
916 }
917
918 /**
919
920 * Checks whether this cookie will be sent over secure channels only.
921
922 * @return secure or not ?
923
924 */
925 public boolean isSecure() {
926 synchronized (this.lockSecure) {
927 return (secure);
928 }
929 }
930
931 /**
932
933 * Checks whether this cookie's lifetime has expired or not. The lifetime has expired if:
934
935 * <ul>
936
937 * <li>The Max-Age (for Version 1 cookie) was explicitly set to 0
938
939 * <li>The delta-t seconds set by Max-Age have passed
940
941 * <li>The date-time now is greater than what was set to be the expiry date-time
942
943 * </ul>
944
945 * The current system time is used for lifetime calculation.<br>
946
947 * If none of these conditions are satisfied, or if no explicit lifetime information was set
948
949 * the cookie is deemed to not have expired.
950
951 * @return expired or not ?
952
953 */
954 public boolean hasExpired() {
955 return (hasExpired(new Date()));
956 }
957
958 /**
959
960 * Checks whether this cookie's lifetime has expired or not. The lifetime has expired if:
961
962 * <ul>
963
964 * <li>The Max-Age (for Version 1 cookie) was explicitly set to 0
965
966 * <li>The delta-t seconds set by Max-Age have passed
967
968 * <li>The date-time as specified by the input is greater than what was set to be the expiry date-time
969
970 * </ul>
971
972 * The input date-time is used for lifetime calculation.<br>
973
974 * If none of these conditions are satisfied, or if no explicit lifetime information was set
975
976 * the cookie is deemed to not have expired.
977
978 * @return expired or not ?
979
980 */
981 public boolean hasExpired(Date d) {
982 if (d == null) {
983 return (hasExpired());
984 }
985
986 synchronized (expires) {
987 if (bExplicitExpires == false) {
988 if (bExplicitMaxage && (maxage == 0)) {
989 return (true);
990 }
991
992 return (false);
993 }
994
995 if ("0".equals(version)) {
996 if (expires.getTime() < d.getTime()) {
997 return (true);
998 }
999
1000 return (false);
1001 } else {
1002 if (expires.getTime() < d.getTime()) {
1003 return (true);
1004 }
1005
1006 return (false);
1007 }
1008 }
1009 }
1010
1011 /**
1012
1013 * Checks whether two cookies are equal. Two cookies are deemed to be equal, when all of the
1014
1015 * following conditions are satisfied:
1016
1017 * <ul>
1018
1019 * <li>They have the same name</li>
1020
1021 * <li>They have the same domain</li>
1022
1023 * <li>They have the same path</li>
1024
1025 * </ul>
1026
1027 * Note that the cookie value is NOT used for equality determination.
1028
1029 */
1030 public boolean equals(Object obj) {
1031 if ((obj != null) && (obj instanceof Cookie)) {
1032 Cookie other = (Cookie) obj;
1033
1034 return (name.equalsIgnoreCase(other.getName()) && domain.equalsIgnoreCase(other.getDomain())
1035 && path.equals(other.getPath()));
1036 }
1037
1038 return (false);
1039 }
1040
1041 public String toString() {
1042 StringBuffer sb = new StringBuffer();
1043
1044 sb.append("[");
1045
1046 sb.append("VERSION=\"");
1047
1048 sb.append(version);
1049
1050 sb.append("\" ; NAME=\"");
1051
1052 sb.append(name);
1053
1054 sb.append("\" ; VALUE=\"");
1055
1056 sb.append(value);
1057
1058 sb.append("\" ; DOMAIN=\"");
1059
1060 sb.append(domain);
1061
1062 if ("1".equals(version)) {
1063 sb.append("\" ; PORTLIST=\"");
1064
1065 sb.append(portList);
1066 }
1067
1068 sb.append("\" ; PATH=\"");
1069
1070 sb.append(path);
1071
1072 if ("1".equals(version)) {
1073 sb.append("\" ; MAX-AGE=\"");
1074
1075 sb.append(maxage);
1076
1077 sb.append("\" ; DISCARD=\"");
1078
1079 sb.append(discard);
1080
1081 sb.append("\" ; COMMENT=\"");
1082
1083 sb.append(comment);
1084
1085 sb.append("\" ; COMMENTURL=\"");
1086
1087 sb.append((commentURL == null) ? "null" : commentURL.toString());
1088 }
1089
1090 sb.append("\" ; SECURE=\"");
1091
1092 sb.append(secure);
1093
1094 sb.append("\" ; EXPIRES=\"");
1095
1096 sb.append((bExplicitExpires ? expires.toString() : "null"));
1097
1098 sb.append("\"]");
1099
1100 return (sb.toString());
1101 }
1102}