View Javadoc

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