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
32package org.apache.http.impl.cookie;
33
34import java.util.ArrayList;
35import java.util.Collections;
36import java.util.List;
37
38import org.apache.http.Header;
39import org.apache.http.HeaderElement;
40import org.apache.http.cookie.ClientCookie;
41import org.apache.http.cookie.Cookie;
42import org.apache.http.cookie.CookieOrigin;
43import org.apache.http.cookie.CookiePathComparator;
44import org.apache.http.cookie.MalformedCookieException;
45import org.apache.http.cookie.SM;
46import org.apache.http.message.BufferedHeader;
47import 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 * @deprecated Please use {@link java.net.URL#openConnection} instead.
66 *     Please visit <a href="http://android-developers.blogspot.com/2011/09/androids-http-clients.html">this webpage</a>
67 *     for further details.
68 */
69
70@Deprecated
71public class RFC2109Spec extends CookieSpecBase {
72
73    private final static CookiePathComparator PATH_COMPARATOR = new CookiePathComparator();
74
75    private final static String[] DATE_PATTERNS = {
76        DateUtils.PATTERN_RFC1123,
77        DateUtils.PATTERN_RFC1036,
78        DateUtils.PATTERN_ASCTIME
79    };
80
81    private final String[] datepatterns;
82    private final boolean oneHeader;
83
84    /** Default constructor */
85    public RFC2109Spec(final String[] datepatterns, boolean oneHeader) {
86        super();
87        if (datepatterns != null) {
88            this.datepatterns = datepatterns.clone();
89        } else {
90            this.datepatterns = DATE_PATTERNS;
91        }
92        this.oneHeader = oneHeader;
93        registerAttribHandler(ClientCookie.VERSION_ATTR, new RFC2109VersionHandler());
94        registerAttribHandler(ClientCookie.PATH_ATTR, new BasicPathHandler());
95        registerAttribHandler(ClientCookie.DOMAIN_ATTR, new RFC2109DomainHandler());
96        registerAttribHandler(ClientCookie.MAX_AGE_ATTR, new BasicMaxAgeHandler());
97        registerAttribHandler(ClientCookie.SECURE_ATTR, new BasicSecureHandler());
98        registerAttribHandler(ClientCookie.COMMENT_ATTR, new BasicCommentHandler());
99        registerAttribHandler(ClientCookie.EXPIRES_ATTR, new BasicExpiresHandler(
100                this.datepatterns));
101    }
102
103    /** Default constructor */
104    public RFC2109Spec() {
105        this(null, false);
106    }
107
108    public List<Cookie> parse(final Header header, final CookieOrigin origin)
109            throws MalformedCookieException {
110        if (header == null) {
111            throw new IllegalArgumentException("Header may not be null");
112        }
113        if (origin == null) {
114            throw new IllegalArgumentException("Cookie origin may not be null");
115        }
116        HeaderElement[] elems = header.getElements();
117        return parse(elems, origin);
118    }
119
120    @Override
121    public void validate(final Cookie cookie, final CookieOrigin origin)
122            throws MalformedCookieException {
123        if (cookie == null) {
124            throw new IllegalArgumentException("Cookie may not be null");
125        }
126        String name = cookie.getName();
127        if (name.indexOf(' ') != -1) {
128            throw new MalformedCookieException("Cookie name may not contain blanks");
129        }
130        if (name.startsWith("$")) {
131            throw new MalformedCookieException("Cookie name may not start with $");
132        }
133        super.validate(cookie, origin);
134    }
135
136    public List<Header> formatCookies(List<Cookie> cookies) {
137        if (cookies == null) {
138            throw new IllegalArgumentException("List of cookies may not be null");
139        }
140        if (cookies.isEmpty()) {
141            throw new IllegalArgumentException("List of cookies may not be empty");
142        }
143        if (cookies.size() > 1) {
144            // Create a mutable copy and sort the copy.
145            cookies = new ArrayList<Cookie>(cookies);
146            Collections.sort(cookies, PATH_COMPARATOR);
147        }
148        if (this.oneHeader) {
149            return doFormatOneHeader(cookies);
150        } else {
151            return doFormatManyHeaders(cookies);
152        }
153    }
154
155    private List<Header> doFormatOneHeader(final List<Cookie> cookies) {
156        int version = Integer.MAX_VALUE;
157        // Pick the lowest common denominator
158        for (Cookie cookie : cookies) {
159            if (cookie.getVersion() < version) {
160                version = cookie.getVersion();
161            }
162        }
163        CharArrayBuffer buffer = new CharArrayBuffer(40 * cookies.size());
164        buffer.append(SM.COOKIE);
165        buffer.append(": ");
166        buffer.append("$Version=");
167        buffer.append(Integer.toString(version));
168        for (Cookie cooky : cookies) {
169            buffer.append("; ");
170            Cookie cookie = cooky;
171            formatCookieAsVer(buffer, cookie, version);
172        }
173        List<Header> headers = new ArrayList<Header>(1);
174        headers.add(new BufferedHeader(buffer));
175        return headers;
176    }
177
178    private List<Header> doFormatManyHeaders(final List<Cookie> cookies) {
179        List<Header> headers = new ArrayList<Header>(cookies.size());
180        for (Cookie cookie : cookies) {
181            int version = cookie.getVersion();
182            CharArrayBuffer buffer = new CharArrayBuffer(40);
183            buffer.append("Cookie: ");
184            buffer.append("$Version=");
185            buffer.append(Integer.toString(version));
186            buffer.append("; ");
187            formatCookieAsVer(buffer, cookie, version);
188            headers.add(new BufferedHeader(buffer));
189        }
190        return headers;
191    }
192
193    /**
194     * Return a name/value string suitable for sending in a <tt>"Cookie"</tt>
195     * header as defined in RFC 2109 for backward compatibility with cookie
196     * version 0
197     * @param buffer The char array buffer to use for output
198     * @param name The cookie name
199     * @param value The cookie value
200     * @param version The cookie version
201     */
202    protected void formatParamAsVer(final CharArrayBuffer buffer,
203            final String name, final String value, int version) {
204        buffer.append(name);
205        buffer.append("=");
206        if (value != null) {
207            if (version > 0) {
208                buffer.append('\"');
209                buffer.append(value);
210                buffer.append('\"');
211            } else {
212                buffer.append(value);
213            }
214        }
215    }
216
217    /**
218     * Return a string suitable for sending in a <tt>"Cookie"</tt> header
219     * as defined in RFC 2109 for backward compatibility with cookie version 0
220     * @param buffer The char array buffer to use for output
221     * @param cookie The {@link Cookie} to be formatted as string
222     * @param version The version to use.
223     */
224    protected void formatCookieAsVer(final CharArrayBuffer buffer,
225            final Cookie cookie, int version) {
226        formatParamAsVer(buffer, cookie.getName(), cookie.getValue(), version);
227        if (cookie.getPath() != null) {
228            if (cookie instanceof ClientCookie
229                    && ((ClientCookie) cookie).containsAttribute(ClientCookie.PATH_ATTR)) {
230                buffer.append("; ");
231                formatParamAsVer(buffer, "$Path", cookie.getPath(), version);
232            }
233        }
234        if (cookie.getDomain() != null) {
235            if (cookie instanceof ClientCookie
236                    && ((ClientCookie) cookie).containsAttribute(ClientCookie.DOMAIN_ATTR)) {
237                buffer.append("; ");
238                formatParamAsVer(buffer, "$Domain", cookie.getDomain(), version);
239            }
240        }
241    }
242
243    public int getVersion() {
244        return 1;
245    }
246
247    public Header getVersionHeader() {
248        return null;
249    }
250
251}
252