• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/impl/cookie/RFC2109Spec.java $
3  * $Revision: 677240 $
4  * $Date: 2008-07-16 04:25:47 -0700 (Wed, 16 Jul 2008) $
5  *
6  * ====================================================================
7  * Licensed to the Apache Software Foundation (ASF) under one
8  * or more contributor license agreements.  See the NOTICE file
9  * distributed with this work for additional information
10  * regarding copyright ownership.  The ASF licenses this file
11  * to you under the Apache License, Version 2.0 (the
12  * "License"); you may not use this file except in compliance
13  * with the License.  You may obtain a copy of the License at
14  *
15  *   http://www.apache.org/licenses/LICENSE-2.0
16  *
17  * Unless required by applicable law or agreed to in writing,
18  * software distributed under the License is distributed on an
19  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
20  * KIND, either express or implied.  See the License for the
21  * specific language governing permissions and limitations
22  * under the License.
23  * ====================================================================
24  *
25  * This software consists of voluntary contributions made by many
26  * individuals on behalf of the Apache Software Foundation.  For more
27  * information on the Apache Software Foundation, please see
28  * <http://www.apache.org/>.
29  *
30  */
31 
32 package org.apache.http.impl.cookie;
33 
34 import java.util.ArrayList;
35 import java.util.Collections;
36 import java.util.List;
37 
38 import org.apache.http.Header;
39 import org.apache.http.HeaderElement;
40 import org.apache.http.cookie.ClientCookie;
41 import org.apache.http.cookie.Cookie;
42 import org.apache.http.cookie.CookieOrigin;
43 import org.apache.http.cookie.CookiePathComparator;
44 import org.apache.http.cookie.MalformedCookieException;
45 import org.apache.http.cookie.SM;
46 import org.apache.http.message.BufferedHeader;
47 import org.apache.http.util.CharArrayBuffer;
48 
49 /**
50  * RFC 2109 compliant cookie policy
51  *
52  * @author  B.C. Holmes
53  * @author <a href="mailto:jericho@thinkfree.com">Park, Sung-Gu</a>
54  * @author <a href="mailto:dsale@us.britannica.com">Doug Sale</a>
55  * @author Rod Waldhoff
56  * @author dIon Gillard
57  * @author Sean C. Sullivan
58  * @author <a href="mailto:JEvans@Cyveillance.com">John Evans</a>
59  * @author Marc A. Saegesser
60  * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
61  * @author <a href="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a>
62  *
63  * @since 4.0
64  */
65 
66 public class RFC2109Spec extends CookieSpecBase {
67 
68     private final static CookiePathComparator PATH_COMPARATOR = new CookiePathComparator();
69 
70     private final static String[] DATE_PATTERNS = {
71         DateUtils.PATTERN_RFC1123,
72         DateUtils.PATTERN_RFC1036,
73         DateUtils.PATTERN_ASCTIME
74     };
75 
76     private final String[] datepatterns;
77     private final boolean oneHeader;
78 
79     /** Default constructor */
RFC2109Spec(final String[] datepatterns, boolean oneHeader)80     public RFC2109Spec(final String[] datepatterns, boolean oneHeader) {
81         super();
82         if (datepatterns != null) {
83             this.datepatterns = datepatterns.clone();
84         } else {
85             this.datepatterns = DATE_PATTERNS;
86         }
87         this.oneHeader = oneHeader;
88         registerAttribHandler(ClientCookie.VERSION_ATTR, new RFC2109VersionHandler());
89         registerAttribHandler(ClientCookie.PATH_ATTR, new BasicPathHandler());
90         registerAttribHandler(ClientCookie.DOMAIN_ATTR, new RFC2109DomainHandler());
91         registerAttribHandler(ClientCookie.MAX_AGE_ATTR, new BasicMaxAgeHandler());
92         registerAttribHandler(ClientCookie.SECURE_ATTR, new BasicSecureHandler());
93         registerAttribHandler(ClientCookie.COMMENT_ATTR, new BasicCommentHandler());
94         registerAttribHandler(ClientCookie.EXPIRES_ATTR, new BasicExpiresHandler(
95                 this.datepatterns));
96     }
97 
98     /** Default constructor */
RFC2109Spec()99     public RFC2109Spec() {
100         this(null, false);
101     }
102 
parse(final Header header, final CookieOrigin origin)103     public List<Cookie> parse(final Header header, final CookieOrigin origin)
104             throws MalformedCookieException {
105         if (header == null) {
106             throw new IllegalArgumentException("Header may not be null");
107         }
108         if (origin == null) {
109             throw new IllegalArgumentException("Cookie origin may not be null");
110         }
111         HeaderElement[] elems = header.getElements();
112         return parse(elems, origin);
113     }
114 
115     @Override
validate(final Cookie cookie, final CookieOrigin origin)116     public void validate(final Cookie cookie, final CookieOrigin origin)
117             throws MalformedCookieException {
118         if (cookie == null) {
119             throw new IllegalArgumentException("Cookie may not be null");
120         }
121         String name = cookie.getName();
122         if (name.indexOf(' ') != -1) {
123             throw new MalformedCookieException("Cookie name may not contain blanks");
124         }
125         if (name.startsWith("$")) {
126             throw new MalformedCookieException("Cookie name may not start with $");
127         }
128         super.validate(cookie, origin);
129     }
130 
formatCookies(List<Cookie> cookies)131     public List<Header> formatCookies(List<Cookie> cookies) {
132         if (cookies == null) {
133             throw new IllegalArgumentException("List of cookies may not be null");
134         }
135         if (cookies.isEmpty()) {
136             throw new IllegalArgumentException("List of cookies may not be empty");
137         }
138         if (cookies.size() > 1) {
139             // Create a mutable copy and sort the copy.
140             cookies = new ArrayList<Cookie>(cookies);
141             Collections.sort(cookies, PATH_COMPARATOR);
142         }
143         if (this.oneHeader) {
144             return doFormatOneHeader(cookies);
145         } else {
146             return doFormatManyHeaders(cookies);
147         }
148     }
149 
doFormatOneHeader(final List<Cookie> cookies)150     private List<Header> doFormatOneHeader(final List<Cookie> cookies) {
151         int version = Integer.MAX_VALUE;
152         // Pick the lowest common denominator
153         for (Cookie cookie : cookies) {
154             if (cookie.getVersion() < version) {
155                 version = cookie.getVersion();
156             }
157         }
158         CharArrayBuffer buffer = new CharArrayBuffer(40 * cookies.size());
159         buffer.append(SM.COOKIE);
160         buffer.append(": ");
161         buffer.append("$Version=");
162         buffer.append(Integer.toString(version));
163         for (Cookie cooky : cookies) {
164             buffer.append("; ");
165             Cookie cookie = cooky;
166             formatCookieAsVer(buffer, cookie, version);
167         }
168         List<Header> headers = new ArrayList<Header>(1);
169         headers.add(new BufferedHeader(buffer));
170         return headers;
171     }
172 
doFormatManyHeaders(final List<Cookie> cookies)173     private List<Header> doFormatManyHeaders(final List<Cookie> cookies) {
174         List<Header> headers = new ArrayList<Header>(cookies.size());
175         for (Cookie cookie : cookies) {
176             int version = cookie.getVersion();
177             CharArrayBuffer buffer = new CharArrayBuffer(40);
178             buffer.append("Cookie: ");
179             buffer.append("$Version=");
180             buffer.append(Integer.toString(version));
181             buffer.append("; ");
182             formatCookieAsVer(buffer, cookie, version);
183             headers.add(new BufferedHeader(buffer));
184         }
185         return headers;
186     }
187 
188     /**
189      * Return a name/value string suitable for sending in a <tt>"Cookie"</tt>
190      * header as defined in RFC 2109 for backward compatibility with cookie
191      * version 0
192      * @param buffer The char array buffer to use for output
193      * @param name The cookie name
194      * @param value The cookie value
195      * @param version The cookie version
196      */
formatParamAsVer(final CharArrayBuffer buffer, final String name, final String value, int version)197     protected void formatParamAsVer(final CharArrayBuffer buffer,
198             final String name, final String value, int version) {
199         buffer.append(name);
200         buffer.append("=");
201         if (value != null) {
202             if (version > 0) {
203                 buffer.append('\"');
204                 buffer.append(value);
205                 buffer.append('\"');
206             } else {
207                 buffer.append(value);
208             }
209         }
210     }
211 
212     /**
213      * Return a string suitable for sending in a <tt>"Cookie"</tt> header
214      * as defined in RFC 2109 for backward compatibility with cookie version 0
215      * @param buffer The char array buffer to use for output
216      * @param cookie The {@link Cookie} to be formatted as string
217      * @param version The version to use.
218      */
formatCookieAsVer(final CharArrayBuffer buffer, final Cookie cookie, int version)219     protected void formatCookieAsVer(final CharArrayBuffer buffer,
220             final Cookie cookie, int version) {
221         formatParamAsVer(buffer, cookie.getName(), cookie.getValue(), version);
222         if (cookie.getPath() != null) {
223             if (cookie instanceof ClientCookie
224                     && ((ClientCookie) cookie).containsAttribute(ClientCookie.PATH_ATTR)) {
225                 buffer.append("; ");
226                 formatParamAsVer(buffer, "$Path", cookie.getPath(), version);
227             }
228         }
229         if (cookie.getDomain() != null) {
230             if (cookie instanceof ClientCookie
231                     && ((ClientCookie) cookie).containsAttribute(ClientCookie.DOMAIN_ATTR)) {
232                 buffer.append("; ");
233                 formatParamAsVer(buffer, "$Domain", cookie.getDomain(), version);
234             }
235         }
236     }
237 
getVersion()238     public int getVersion() {
239         return 1;
240     }
241 
getVersionHeader()242     public Header getVersionHeader() {
243         return null;
244     }
245 
246 }
247