001/*
002 * ====================================================================
003 * Licensed to the Apache Software Foundation (ASF) under one
004 * or more contributor license agreements.  See the NOTICE file
005 * distributed with this work for additional information
006 * regarding copyright ownership.  The ASF licenses this file
007 * to you under the Apache License, Version 2.0 (the
008 * "License"); you may not use this file except in compliance
009 * with the License.  You may obtain a copy of the License at
010 *
011 *   http://www.apache.org/licenses/LICENSE-2.0
012 *
013 * Unless required by applicable law or agreed to in writing,
014 * software distributed under the License is distributed on an
015 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
016 * KIND, either express or implied.  See the License for the
017 * specific language governing permissions and limitations
018 * under the License.
019 * ====================================================================
020 *
021 * This software consists of voluntary contributions made by many
022 * individuals on behalf of the Apache Software Foundation.  For more
023 * information on the Apache Software Foundation, please see
024 * <http://www.apache.org/>.
025 *
026 */
027
028package org.apache.http.impl.cookie;
029
030import java.util.ArrayList;
031import java.util.List;
032
033import org.apache.http.FormattedHeader;
034import org.apache.http.Header;
035import org.apache.http.HeaderElement;
036import org.apache.http.annotation.Contract;
037import org.apache.http.annotation.Obsolete;
038import org.apache.http.annotation.ThreadingBehavior;
039import org.apache.http.cookie.CommonCookieAttributeHandler;
040import org.apache.http.cookie.Cookie;
041import org.apache.http.cookie.CookieOrigin;
042import org.apache.http.cookie.MalformedCookieException;
043import org.apache.http.cookie.SM;
044import org.apache.http.message.BufferedHeader;
045import org.apache.http.message.ParserCursor;
046import org.apache.http.util.Args;
047import org.apache.http.util.CharArrayBuffer;
048
049/**
050 * This {@link org.apache.http.cookie.CookieSpec} implementation conforms to
051 * the original draft specification published by Netscape Communications.
052 * It should be avoided unless absolutely necessary for compatibility with
053 * legacy applications.
054 * <p>
055 * Rendered obsolete by {@link org.apache.http.impl.cookie.RFC6265LaxSpec}.
056 *
057 * @since 4.0
058 * @see org.apache.http.impl.cookie.RFC6265LaxSpec
059 */
060@Obsolete
061@Contract(threading = ThreadingBehavior.SAFE)
062public class NetscapeDraftSpec extends CookieSpecBase {
063
064    protected static final String EXPIRES_PATTERN = "EEE, dd-MMM-yy HH:mm:ss z";
065
066    /** Default constructor */
067    public NetscapeDraftSpec(final String[] datepatterns) {
068        super(new BasicPathHandler(),
069                new NetscapeDomainHandler(),
070                new BasicSecureHandler(),
071                new BasicCommentHandler(),
072                new BasicExpiresHandler(
073                        datepatterns != null ? datepatterns.clone() : new String[]{EXPIRES_PATTERN}));
074    }
075
076    NetscapeDraftSpec(final CommonCookieAttributeHandler... handlers) {
077        super(handlers);
078    }
079
080    public NetscapeDraftSpec() {
081        this((String[]) null);
082    }
083
084    /**
085      * Parses the Set-Cookie value into an array of {@code Cookie}s.
086      *
087      * <p>Syntax of the Set-Cookie HTTP Response Header:</p>
088      *
089      * <p>This is the format a CGI script would use to add to
090      * the HTTP headers a new piece of data which is to be stored by
091      * the client for later retrieval.</p>
092      *
093      * <PRE>
094      *  Set-Cookie: NAME=VALUE; expires=DATE; path=PATH; domain=DOMAIN_NAME; secure
095      * </PRE>
096      *
097      * <p>Please note that the Netscape draft specification does not fully conform to the HTTP
098      * header format. Comma character if present in {@code Set-Cookie} will not be treated
099      * as a header element separator</p>
100      *
101      * @see <a href="http://web.archive.org/web/20020803110822/http://wp.netscape.com/newsref/std/cookie_spec.html">
102      *  The Cookie Spec.</a>
103      *
104      * @param header the {@code Set-Cookie} received from the server
105      * @return an array of {@code Cookie}s parsed from the Set-Cookie value
106      * @throws MalformedCookieException if an exception occurs during parsing
107      */
108    @Override
109    public List<Cookie> parse(final Header header, final CookieOrigin origin)
110            throws MalformedCookieException {
111        Args.notNull(header, "Header");
112        Args.notNull(origin, "Cookie origin");
113        if (!header.getName().equalsIgnoreCase(SM.SET_COOKIE)) {
114            throw new MalformedCookieException("Unrecognized cookie header '"
115                    + header.toString() + "'");
116        }
117        final NetscapeDraftHeaderParser parser = NetscapeDraftHeaderParser.DEFAULT;
118        final CharArrayBuffer buffer;
119        final ParserCursor cursor;
120        if (header instanceof FormattedHeader) {
121            buffer = ((FormattedHeader) header).getBuffer();
122            cursor = new ParserCursor(
123                    ((FormattedHeader) header).getValuePos(),
124                    buffer.length());
125        } else {
126            final String s = header.getValue();
127            if (s == null) {
128                throw new MalformedCookieException("Header value is null");
129            }
130            buffer = new CharArrayBuffer(s.length());
131            buffer.append(s);
132            cursor = new ParserCursor(0, buffer.length());
133        }
134        return parse(new HeaderElement[] { parser.parseHeader(buffer, cursor) }, origin);
135    }
136
137    @Override
138    public List<Header> formatCookies(final List<Cookie> cookies) {
139        Args.notEmpty(cookies, "List of cookies");
140        final CharArrayBuffer buffer = new CharArrayBuffer(20 * cookies.size());
141        buffer.append(SM.COOKIE);
142        buffer.append(": ");
143        for (int i = 0; i < cookies.size(); i++) {
144            final Cookie cookie = cookies.get(i);
145            if (i > 0) {
146                buffer.append("; ");
147            }
148            buffer.append(cookie.getName());
149            final String s = cookie.getValue();
150            if (s != null) {
151                buffer.append("=");
152                buffer.append(s);
153            }
154        }
155        final List<Header> headers = new ArrayList<Header>(1);
156        headers.add(new BufferedHeader(buffer));
157        return headers;
158    }
159
160    @Override
161    public int getVersion() {
162        return 0;
163    }
164
165    @Override
166    public Header getVersionHeader() {
167        return null;
168    }
169
170    @Override
171    public String toString() {
172        return "netscape";
173    }
174
175}