View Javadoc

1   /*
2    * $Header: /home/cvs/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/Cookie.java,v 1.38.2.4 2004/06/05 16:32:01 olegk Exp $
3    * $Revision: 1.38.2.4 $
4    * $Date: 2004/06/05 16:32:01 $
5    *
6    * ====================================================================
7    *
8    *  Copyright 1999-2004 The Apache Software Foundation
9    *
10   *  Licensed under the Apache License, Version 2.0 (the "License");
11   *  you may not use this file except in compliance with the License.
12   *  You may obtain a copy of the License at
13   *
14   *      http://www.apache.org/licenses/LICENSE-2.0
15   *
16   *  Unless required by applicable law or agreed to in writing, software
17   *  distributed under the License is distributed on an "AS IS" BASIS,
18   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19   *  See the License for the specific language governing permissions and
20   *  limitations under the License.
21   * ====================================================================
22   *
23   * This software consists of voluntary contributions made by many
24   * individuals on behalf of the Apache Software Foundation.  For more
25   * information on the Apache Software Foundation, please see
26   * <http://www.apache.org/>.
27   *
28   * [Additional notices, if required by prior licensing conditions]
29   *
30   */
31  
32  package org.apache.commons.httpclient;
33  
34  import java.io.Serializable;
35  import java.text.RuleBasedCollator;
36  import java.util.Comparator;
37  import java.util.Date;
38  import java.util.Locale;
39  
40  import org.apache.commons.httpclient.cookie.CookiePolicy;
41  import org.apache.commons.httpclient.cookie.CookieSpec;
42  import org.apache.commons.logging.Log;
43  import org.apache.commons.logging.LogFactory;
44  
45  
46  /***
47   * <p>
48   * HTTP "magic-cookie" represents a piece of state information
49   * that the HTTP agent and the target server can exchange to maintain 
50   * a session.
51   * </p>
52   * 
53   * @author B.C. Holmes
54   * @author <a href="mailto:jericho@thinkfree.com">Park, Sung-Gu</a>
55   * @author <a href="mailto:dsale@us.britannica.com">Doug Sale</a>
56   * @author Rod Waldhoff
57   * @author dIon Gillard
58   * @author Sean C. Sullivan
59   * @author <a href="mailto:JEvans@Cyveillance.com">John Evans</a>
60   * @author Marc A. Saegesser
61   * @author <a href="mailto:oleg@ural.ru">Oleg Kalnichevski</a>
62   * @author <a href="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a>
63   * 
64   * @version $Revision: 1.38.2.4 $ $Date: 2004/06/05 16:32:01 $
65   */
66  
67  public class Cookie extends NameValuePair implements Serializable, Comparator {
68  
69      // ----------------------------------------------------------- Constructors
70  
71      /***
72       * Default constructor. Creates a blank cookie 
73       */
74  
75      public Cookie() {
76          this(null, "noname", null, null, null, false);
77      }
78  
79      /***
80       * Creates a cookie with the given name, value and domain attribute.
81       *
82       * @param name    the cookie name
83       * @param value   the cookie value
84       * @param domain  the domain this cookie can be sent to
85       */
86      public Cookie(String domain, String name, String value) {
87          this(domain, name, value, null, null, false);
88      }
89  
90      /***
91       * Creates a cookie with the given name, value, domain attribute,
92       * path attribute, expiration attribute, and secure attribute 
93       *
94       * @param name    the cookie name
95       * @param value   the cookie value
96       * @param domain  the domain this cookie can be sent to
97       * @param path    the path prefix for which this cookie can be sent
98       * @param expires the {@link Date} at which this cookie expires,
99       *                or <tt>null</tt> if the cookie expires at the end
100      *                of the session
101      * @param secure if true this cookie can only be sent over secure
102      * connections
103      * @throws IllegalArgumentException If cookie name is null or blank,
104      *   cookie name contains a blank, or cookie name starts with character $
105      *   
106      */
107     public Cookie(String domain, String name, String value, 
108         String path, Date expires, boolean secure) {
109             
110         super(name, value);
111         LOG.trace("enter Cookie(String, String, String, String, Date, boolean)");
112         if (name == null) {
113             throw new IllegalArgumentException("Cookie name may not be null");
114         }
115         if (name.trim().equals("")) {
116             throw new IllegalArgumentException("Cookie name may not be blank");
117         }
118         this.setPath(path);
119         this.setDomain(domain);
120         this.setExpiryDate(expires);
121         this.setSecure(secure);
122     }
123 
124     /***
125      * Creates a cookie with the given name, value, domain attribute,
126      * path attribute, maximum age attribute, and secure attribute 
127      *
128      * @param name   the cookie name
129      * @param value  the cookie value
130      * @param domain the domain this cookie can be sent to
131      * @param path   the path prefix for which this cookie can be sent
132      * @param maxAge the number of seconds for which this cookie is valid.
133      *               maxAge is expected to be a non-negative number. 
134      *               <tt>-1</tt> signifies that the cookie should never expire.
135      * @param secure if <tt>true</tt> this cookie can only be sent over secure
136      * connections
137      */
138     public Cookie(String domain, String name, String value, String path, 
139         int maxAge, boolean secure) {
140             
141         this(domain, name, value, path, null, secure);
142         if (maxAge < -1) {
143             throw new IllegalArgumentException("Invalid max age:  " + Integer.toString(maxAge));
144         }            
145         if (maxAge >= 0) {
146             setExpiryDate(new Date(System.currentTimeMillis() + maxAge * 1000L));
147         }
148     }
149 
150     /***
151      * Returns the comment describing the purpose of this cookie, or
152      * <tt>null</tt> if no such comment has been defined.
153      * 
154      * @return comment 
155      *
156      * @see #setComment(String)
157      */
158     public String getComment() {
159         return cookieComment;
160     }
161 
162     /***
163      * If a user agent (web browser) presents this cookie to a user, the
164      * cookie's purpose will be described using this comment.
165      * 
166      * @param comment
167      *  
168      * @see #getComment()
169      */
170     public void setComment(String comment) {
171         cookieComment = comment;
172     }
173 
174     /***
175      * Returns the expiration {@link Date} of the cookie, or <tt>null</tt>
176      * if none exists.
177      * <p><strong>Note:</strong> the object returned by this method is 
178      * considered immutable. Changing it (e.g. using setTime()) could result
179      * in undefined behaviour. Do so at your peril. </p>
180      * @return Expiration {@link Date}, or <tt>null</tt>.
181      *
182      * @see #setExpiryDate(java.util.Date)
183      *
184      */
185     public Date getExpiryDate() {
186         return cookieExpiryDate;
187     }
188 
189     /***
190      * Sets expiration date.
191      * <p><strong>Note:</strong> the object returned by this method is considered
192      * immutable. Changing it (e.g. using setTime()) could result in undefined 
193      * behaviour. Do so at your peril.</p>
194      *
195      * @param expiryDate the {@link Date} after which this cookie is no longer valid.
196      *
197      * @see #getExpiryDate
198      *
199      */
200     public void setExpiryDate (Date expiryDate) {
201         cookieExpiryDate = expiryDate;
202     }
203 
204 
205     /***
206      * Returns <tt>false</tt> if the cookie should be discarded at the end
207      * of the "session"; <tt>true</tt> otherwise.
208      *
209      * @return <tt>false</tt> if the cookie should be discarded at the end
210      *         of the "session"; <tt>true</tt> otherwise
211      */
212     public boolean isPersistent() {
213         return (null != cookieExpiryDate);
214     }
215 
216 
217     /***
218      * Returns domain attribute of the cookie.
219      * 
220      * @return the value of the domain attribute
221      *
222      * @see #setDomain(java.lang.String)
223      */
224     public String getDomain() {
225         return cookieDomain;
226     }
227 
228     /***
229      * Sets the domain attribute.
230      * 
231      * @param domain The value of the domain attribute
232      *
233      * @see #getDomain
234      */
235     public void setDomain(String domain) {
236         if (domain != null) {
237             int ndx = domain.indexOf(":");
238             if (ndx != -1) {
239               domain = domain.substring(0, ndx);
240             }
241             cookieDomain = domain.toLowerCase();
242         }
243     }
244 
245 
246     /***
247      * Returns the path attribute of the cookie
248      * 
249      * @return The value of the path attribute.
250      * 
251      * @see #setPath(java.lang.String)
252      */
253     public String getPath() {
254         return cookiePath;
255     }
256 
257     /***
258      * Sets the path attribute.
259      *
260      * @param path The value of the path attribute
261      *
262      * @see #getPath
263      *
264      */
265     public void setPath(String path) {
266         cookiePath = path;
267     }
268 
269     /***
270      * @return <code>true</code> if this cookie should only be sent over secure connections.
271      * @see #setSecure(boolean)
272      */
273     public boolean getSecure() {
274         return isSecure;
275     }
276 
277     /***
278      * Sets the secure attribute of the cookie.
279      * <p>
280      * When <tt>true</tt> the cookie should only be sent
281      * using a secure protocol (https).  This should only be set when
282      * the cookie's originating server used a secure protocol to set the
283      * cookie's value.
284      *
285      * @param secure The value of the secure attribute
286      * 
287      * @see #getSecure()
288      */
289     public void setSecure (boolean secure) {
290         isSecure = secure;
291     }
292 
293     /***
294      * Returns the version of the cookie specification to which this
295      * cookie conforms.
296      *
297      * @return the version of the cookie.
298      * 
299      * @see #setVersion(int)
300      *
301      */
302     public int getVersion() {
303         return cookieVersion;
304     }
305 
306     /***
307      * Sets the version of the cookie specification to which this
308      * cookie conforms. 
309      *
310      * @param version the version of the cookie.
311      * 
312      * @see #getVersion
313      */
314     public void setVersion(int version) {
315         cookieVersion = version;
316     }
317 
318     /***
319      * Returns true if this cookie has expired.
320      * 
321      * @return <tt>true</tt> if the cookie has expired.
322      */
323     public boolean isExpired() {
324         return (cookieExpiryDate != null  
325             && cookieExpiryDate.getTime() <= System.currentTimeMillis());
326     }
327 
328     /***
329      * Returns true if this cookie has expired according to the time passed in.
330      * 
331      * @param now The current time.
332      * 
333      * @return <tt>true</tt> if the cookie expired.
334      */
335     public boolean isExpired(Date now) {
336         return (cookieExpiryDate != null  
337             && cookieExpiryDate.getTime() <= now.getTime());
338     }
339 
340 
341     /***
342      * Indicates whether the cookie had a path specified in a 
343      * path attribute of the <tt>Set-Cookie</tt> header. This value
344      * is important for generating the <tt>Cookie</tt> header because 
345      * some cookie specifications require that the <tt>Cookie</tt> header 
346      * should only include a path attribute if the cookie's path 
347      * was specified in the <tt>Set-Cookie</tt> header.
348      *
349      * @param value <tt>true</tt> if the cookie's path was explicitly 
350      * set, <tt>false</tt> otherwise.
351      * 
352      * @see #isPathAttributeSpecified
353      */
354     public void setPathAttributeSpecified(boolean value) {
355         hasPathAttribute = value;
356     }
357 
358     /***
359      * Returns <tt>true</tt> if cookie's path was set via a path attribute
360      * in the <tt>Set-Cookie</tt> header.
361      *
362      * @return value <tt>true</tt> if the cookie's path was explicitly 
363      * set, <tt>false</tt> otherwise.
364      * 
365      * @see #setPathAttributeSpecified
366      */
367     public boolean isPathAttributeSpecified() {
368         return hasPathAttribute;
369     }
370 
371     /***
372      * Indicates whether the cookie had a domain specified in a 
373      * domain attribute of the <tt>Set-Cookie</tt> header. This value
374      * is important for generating the <tt>Cookie</tt> header because 
375      * some cookie specifications require that the <tt>Cookie</tt> header 
376      * should only include a domain attribute if the cookie's domain 
377      * was specified in the <tt>Set-Cookie</tt> header.
378      *
379      * @param value <tt>true</tt> if the cookie's domain was explicitly 
380      * set, <tt>false</tt> otherwise.
381      *
382      * @see #isDomainAttributeSpecified
383      */
384     public void setDomainAttributeSpecified(boolean value) {
385         hasDomainAttribute = value;
386     }
387 
388     /***
389      * Returns <tt>true</tt> if cookie's domain was set via a domain 
390      * attribute in the <tt>Set-Cookie</tt> header.
391      *
392      * @return value <tt>true</tt> if the cookie's domain was explicitly 
393      * set, <tt>false</tt> otherwise.
394      *
395      * @see #setDomainAttributeSpecified
396      */
397     public boolean isDomainAttributeSpecified() {
398         return hasDomainAttribute;
399     }
400 
401     /***
402      * Returns a hash code in keeping with the
403      * {@link Object#hashCode} general hashCode contract.
404      * @return A hash code
405      */
406     public int hashCode() {
407         return super.hashCode()
408             ^ (null == cookiePath ? 0 : cookiePath.hashCode())
409             ^ (null == cookieDomain ? 0 : cookieDomain.hashCode());
410     }
411 
412 
413     /***
414      * Two cookies are equal if the name, path and domain match.
415      * @param obj The object to compare against.
416      * @return true if the two objects are equal.
417      */
418     public boolean equals(Object obj) {
419         LOG.trace("enter Cookie.equals(Object)");
420         
421         if ((obj != null) && (obj instanceof Cookie)) {
422             Cookie that = (Cookie) obj;
423             return 
424                 (null == this.getName() 
425                     ? null == that.getName() 
426                     : this.getName().equals(that.getName())) 
427                 && (null == this.getPath() 
428                     ? null == that.getPath() 
429                     : this.getPath().equals(that.getPath())) 
430                 && (null == this.getDomain() 
431                     ? null == that.getDomain() 
432                     : this.getDomain().equals(that.getDomain()));
433         } else {
434             return false;
435         }
436     }
437 
438 
439     /***
440      * Returns a textual representation of the cookie.
441      * 
442      * @return string .
443      */
444     public String toExternalForm() {
445         return CookiePolicy.getSpecByVersion(
446             getVersion()).formatCookie(this);
447     }
448 
449     /***
450      * Return <tt>true</tt> if I should be submitted with a request with given
451      * attributes, <tt>false</tt> otherwise.
452      * @param domain the host to which the request is being submitted
453      * @param port the port to which the request is being submitted (currently
454      * ignored)
455      * @param path the path to which the request is being submitted
456      * @param secure <tt>true</tt> if the request is using the HTTPS protocol
457      * @param date the time at which the request is submitted
458      * @return true if the cookie matches
459      * 
460      * @deprecated use {@link CookieSpec} interface
461      */
462     public boolean matches(
463         String domain, int port, String path, boolean secure, Date date) {
464             
465         LOG.trace("enter Cookie.matches(Strinng, int, String, boolean, Date");
466         CookieSpec matcher = CookiePolicy.getDefaultSpec();
467         return matcher.match(domain, port, path, secure, this);
468     }
469 
470     /***
471      * Return <tt>true</tt> if I should be submitted with a request with given
472      * attributes, <tt>false</tt> otherwise.
473      * @param domain the host to which the request is being submitted
474      * @param port the port to which the request is being submitted (currently
475      * ignored)
476      * @param path the path to which the request is being submitted
477      * @param secure True if this cookie has the secure flag set
478      * @return true if I should be submitted as above.
479      * @deprecated use {@link CookieSpec} interface
480      */
481     public boolean matches(
482         String domain, int port, String path, boolean secure) {
483         LOG.trace("enter Cookie.matches(String, int, String, boolean");
484         return matches(domain, port, path, secure, new Date());
485     }
486 
487     /***
488      * Create a <tt>Cookie</tt> header containing
489      * all non-expired cookies in <i>cookies</i>,
490      * associated with the given <i>domain</i> and
491      * <i>path</i>, assuming the connection is not
492      * secure.
493      * <p>
494      * If no cookies match, returns null.
495      * 
496      * @param domain The domain
497      * @param path The path
498      * @param cookies The cookies to use
499      * @return The new header.
500      * @deprecated use {@link CookieSpec} interface
501      */
502     public static Header createCookieHeader(String domain, String path, 
503         Cookie[] cookies) {
504             
505         LOG.trace("enter Cookie.createCookieHeader(String,String,Cookie[])");
506         return Cookie.createCookieHeader(domain, path, false, cookies);
507     }
508 
509     /***
510      * Create a <tt>Cookie</tt> header containing
511      * all non-expired cookies in <i>cookies</i>,
512      * associated with the given <i>domain</i>, <i>path</i> and
513      * <i>https</i> setting.
514      * <p>
515      * If no cookies match, returns null.
516      * 
517      * @param domain The domain
518      * @param path The path
519      * @param secure True if this cookie has the secure flag set
520      * @param cookies The cookies to use.
521      * @return The new header
522      * @exception IllegalArgumentException if domain or path is null
523      * 
524      * @deprecated use {@link CookieSpec} interface
525      */
526     public static Header createCookieHeader(String domain, String path, 
527         boolean secure, Cookie[] cookies)
528         throws IllegalArgumentException {
529             
530         LOG.trace("enter Cookie.createCookieHeader("
531             + "String, String, boolean, Cookie[])");
532 
533         // Make sure domain isn't null here.  Path will be validated in 
534         // subsequent call to createCookieHeader
535         if (domain == null) {
536             throw new IllegalArgumentException("null domain in "
537                 + "createCookieHeader.");
538         }
539         // parse port from domain, if any
540         int port = secure ? 443 : 80;
541         int ndx = domain.indexOf(":");
542         if (ndx != -1) {
543             try {
544                 port = Integer.parseInt(domain.substring(ndx + 1, 
545                     domain.length()));
546             } catch (NumberFormatException e) {
547                 // ignore?, but at least LOG
548                 LOG.warn("Cookie.createCookieHeader():  "
549                     + "Invalid port number in domain " + domain);
550             }
551         }
552         return Cookie.createCookieHeader(domain, port, path, secure, cookies);
553     }
554 
555     /***
556      * Create a <tt>Cookie</tt> header containing
557      * all non-expired cookies in <i>cookies</i>,
558      * associated with the given <i>domain</i>, <i>port</i>,
559      * <i>path</i> and <i>https</i> setting.
560      * <p>
561      * If no cookies match, returns null.
562      * 
563      * @param domain The domain
564      * @param port The port
565      * @param path The path
566      * @param secure True if this cookie has the secure flag set
567      * @param cookies The cookies to use.
568      * @return The new header
569      * @throws IllegalArgumentException if domain or path is null
570      * 
571      * @deprecated use {@link CookieSpec} interface
572      */
573     public static Header createCookieHeader(String domain, int port, 
574         String path, boolean secure, Cookie[] cookies) 
575         throws IllegalArgumentException {
576         LOG.trace("enter Cookie.createCookieHeader(String, int, String, boolean, Cookie[])");
577         return Cookie.createCookieHeader(domain, port, path, secure, new Date(), cookies);
578     }
579 
580     /***
581      * Create a <tt>Cookie</tt> header containing all cookies in <i>cookies</i>,
582      * associated with the given <i>domain</i>, <i>port</i>, <i>path</i> and
583      * <i>https</i> setting, and which are not expired according to the given
584      * <i>date</i>.
585      * <p>
586      * If no cookies match, returns null.
587      * 
588      * @param domain The domain
589      * @param port The port
590      * @param path The path
591      * @param secure True if this cookie has the secure flag set
592      * @param now The date to check for expiry
593      * @param cookies The cookies to use.
594      * @return The new header
595      * @throws IllegalArgumentException if domain or path is null
596      * 
597      * @deprecated use {@link CookieSpec} interface
598      */
599 
600     public static Header createCookieHeader(
601         String domain, int port, String path, boolean secure, 
602         Date now, Cookie[] cookies) 
603         throws IllegalArgumentException {
604             
605         LOG.trace("enter Cookie.createCookieHeader(String, int, String, boolean, Date, Cookie[])");
606         CookieSpec matcher = CookiePolicy.getDefaultSpec();
607         cookies = matcher.match(domain, port, path, secure, cookies);
608         if ((cookies != null) && (cookies.length > 0)) {
609             return matcher.formatCookieHeader(cookies);
610         } else {
611             return null;
612         } 
613     }
614 
615     /***
616      * <p>Compares two cookies to determine order for cookie header.</p>
617      * <p>Most specific should be first. </p>
618      * <p>This method is implemented so a cookie can be used as a comparator for
619      * a SortedSet of cookies. Specifically it's used above in the 
620      * createCookieHeader method.</p>
621      * @param o1 The first object to be compared
622      * @param o2 The second object to be compared
623      * @return See {@link java.util.Comparator#compare(Object,Object)}
624      */
625     public int compare(Object o1, Object o2) {
626         LOG.trace("enter Cookie.compare(Object, Object)");
627 
628         if (!(o1 instanceof Cookie)) {
629             throw new ClassCastException(o1.getClass().getName());
630         }
631         if (!(o2 instanceof Cookie)) {
632             throw new ClassCastException(o2.getClass().getName());
633         }
634         Cookie c1 = (Cookie) o1;
635         Cookie c2 = (Cookie) o2;
636         if (c1.getPath() == null && c2.getPath() == null) {
637             return 0;
638         } else if (c1.getPath() == null) {
639             // null is assumed to be "/"
640             if (c2.getPath().equals(CookieSpec.PATH_DELIM)) {
641                 return 0;
642             } else {
643                 return -1;
644             }
645         } else if (c2.getPath() == null) {
646             // null is assumed to be "/"
647             if (c1.getPath().equals(CookieSpec.PATH_DELIM)) {
648                 return 0;
649             } else {
650                 return 1;
651             }
652         } else {
653             return STRING_COLLATOR.compare(c1.getPath(), c2.getPath());
654         }
655     }
656 
657     /***
658      * Return a textual representation of the cookie.
659      * @see #toExternalForm
660      */
661     public String toString() {
662         return toExternalForm();
663     }
664 
665     /***
666      * Parses the Set-Cookie {@link Header} into an array of
667      * <tt>Cookie</tt>s, assuming that the cookies were recieved
668      * on an insecure channel.
669      *
670      * @param domain the domain from which the {@link Header} was received
671      * @param port the port from which the {@link Header} was received
672      * (currently ignored)
673      * @param path the path from which the {@link Header} was received
674      * @param setCookie the <tt>Set-Cookie</tt> {@link Header} received from the
675      * server
676      * @return an array of <tt>Cookie</tt>s parsed from the Set-Cookie {@link
677      * Header}
678      * @throws HttpException if an exception occurs during parsing
679      * @throws IllegalArgumentException if domain or path are null
680      * 
681      * @deprecated use {@link CookieSpec} interface
682      */
683     public static Cookie[] parse(
684         String domain, int port, String path, Header setCookie) 
685         throws HttpException, IllegalArgumentException {
686             
687         LOG.trace("enter Cookie.parse(String, int, String, Header)");
688         return Cookie.parse(domain, port, path, false, setCookie);
689     }
690 
691     /***
692      * Parses the Set-Cookie {@link Header} into an array of
693      * <tt>Cookie</tt>s, assuming that the cookies were recieved
694      * on an insecure channel.
695      *
696      * @param domain the domain from which the {@link Header} was received
697      * @param path the path from which the {@link Header} was received
698      * @param setCookie the <tt>Set-Cookie</tt> {@link Header} received from the
699      * server
700      * @return an array of <tt>Cookie</tt>s parsed from the Set-Cookie {@link
701      * Header}
702      * @throws HttpException if an exception occurs during parsing
703      * @throws IllegalArgumentException if domain or path are null
704      * 
705      * @deprecated use {@link CookieSpec} interface
706      */
707     public static Cookie[] parse(String domain, String path, Header setCookie) 
708     throws HttpException, IllegalArgumentException {
709         LOG.trace("enter Cookie.parse(String, String, Header)");
710         return Cookie.parse (domain, 80, path, false, setCookie);
711     }
712 
713     /***
714      * Parses the Set-Cookie {@link Header} into an array of
715      * <tt>Cookie</tt>s.
716      *
717      * @param domain the domain from which the {@link Header} was received
718      * @param path the path from which the {@link Header} was received
719      * @param secure <tt>true</tt> when the header was recieved over a secure
720      * channel
721      * @param setCookie the <tt>Set-Cookie</tt> {@link Header} received from the
722      * server
723      * @return an array of <tt>Cookie</tt>s parsed from the Set-Cookie {@link
724      * Header}
725      * @throws HttpException if an exception occurs during parsing
726      * @throws IllegalArgumentException if domain or path are null
727      * 
728      * @deprecated use {@link CookieSpec} interface
729      */
730     public static Cookie[] parse(String domain, String path, 
731         boolean secure, Header setCookie) 
732         throws HttpException, IllegalArgumentException {
733             
734         LOG.trace ("enter Cookie.parse(String, String, boolean, Header)");
735         return Cookie.parse (
736             domain, (secure ? 443 : 80), path, secure, setCookie);
737     }
738 
739     /***
740       * Parses the Set-Cookie {@link Header} into an array of
741       * <tt>Cookie</tt>s.
742       *
743       * <P>The syntax for the Set-Cookie response header is:
744       *
745       * <PRE>
746       * set-cookie      =    "Set-Cookie:" cookies
747       * cookies         =    1#cookie
748       * cookie          =    NAME "=" VALUE * (";" cookie-av)
749       * NAME            =    attr
750       * VALUE           =    value
751       * cookie-av       =    "Comment" "=" value
752       *                 |    "Domain" "=" value
753       *                 |    "Max-Age" "=" value
754       *                 |    "Path" "=" value
755       *                 |    "Secure"
756       *                 |    "Version" "=" 1*DIGIT
757       * </PRE>
758       *
759       * @param domain the domain from which the {@link Header} was received
760       * @param port The port from which the {@link Header} was received.
761       * @param path the path from which the {@link Header} was received
762       * @param secure <tt>true</tt> when the {@link Header} was received over
763       * HTTPS
764       * @param setCookie the <tt>Set-Cookie</tt> {@link Header} received from
765       * the server
766       * @return an array of <tt>Cookie</tt>s parsed from the Set-Cookie {@link
767       * Header}
768       * @throws HttpException if an exception occurs during parsing
769       * 
770       * @deprecated use {@link CookieSpec} interface
771       */
772     public static Cookie[] parse(String domain, int port, String path, 
773         boolean secure, Header setCookie) 
774         throws HttpException {
775             
776         LOG.trace("enter Cookie.parse(String, int, String, boolean, Header)");
777 
778         CookieSpec parser = CookiePolicy.getDefaultSpec();
779         Cookie[] cookies = parser.parse(domain, port, path, secure, setCookie);
780 
781         for (int i = 0; i < cookies.length; i++) {
782             final Cookie cookie = cookies[i];
783             final CookieSpec validator 
784                 = CookiePolicy.getSpecByVersion(cookie.getVersion());
785             validator.validate(domain, port, path, secure, cookie);
786         }
787         return cookies;
788     }
789 
790    // ----------------------------------------------------- Instance Variables
791 
792    /*** Comment attribute. */
793    private String  cookieComment;
794 
795    /*** Domain attribute. */
796    private String  cookieDomain;
797 
798    /*** Expiration {@link Date}. */
799    private Date    cookieExpiryDate;
800 
801    /*** Path attribute. */
802    private String  cookiePath;
803 
804    /*** My secure flag. */
805    private boolean isSecure;
806 
807    /***
808     * Specifies if the set-cookie header included a Path attribute for this
809     * cookie
810     */
811    private boolean hasPathAttribute = false;
812 
813    /***
814     * Specifies if the set-cookie header included a Domain attribute for this
815     * cookie
816     */
817    private boolean hasDomainAttribute = false;
818 
819    /*** The version of the cookie specification I was created from. */
820    private int     cookieVersion = 0;
821 
822    // -------------------------------------------------------------- Constants
823 
824    /*** 
825     * Collator for Cookie comparisons.  Could be replaced with references to
826     * specific Locales.
827     */
828    private static final RuleBasedCollator STRING_COLLATOR =
829         (RuleBasedCollator) RuleBasedCollator.getInstance(
830                                                 new Locale("en", "US", ""));
831 
832    /*** Log object for this class */
833    private static final Log LOG = LogFactory.getLog(Cookie.class);
834 
835 }
836