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 org.apache.http.annotation.Contract;
031import org.apache.http.annotation.ThreadingBehavior;
032import org.apache.http.conn.util.PublicSuffixMatcher;
033import org.apache.http.cookie.Cookie;
034import org.apache.http.cookie.CookieOrigin;
035import org.apache.http.cookie.CookieSpec;
036import org.apache.http.cookie.CookieSpecProvider;
037import org.apache.http.cookie.MalformedCookieException;
038import org.apache.http.protocol.HttpContext;
039
040/**
041 * {@link org.apache.http.cookie.CookieSpecProvider} implementation that provides an instance of
042 * {@link org.apache.http.impl.cookie.DefaultCookieSpec}. The instance returned by this factory can
043 * be shared by multiple threads.
044 *
045 * @since 4.4
046 */
047@Contract(threading = ThreadingBehavior.IMMUTABLE)
048public class DefaultCookieSpecProvider implements CookieSpecProvider {
049
050    public enum CompatibilityLevel {
051        DEFAULT,
052        IE_MEDIUM_SECURITY
053    }
054
055    private final CompatibilityLevel compatibilityLevel;
056    private final PublicSuffixMatcher publicSuffixMatcher;
057    private final String[] datepatterns;
058    private final boolean oneHeader;
059
060    private volatile CookieSpec cookieSpec;
061
062    public DefaultCookieSpecProvider(
063            final CompatibilityLevel compatibilityLevel,
064            final PublicSuffixMatcher publicSuffixMatcher,
065            final String[] datepatterns,
066            final boolean oneHeader) {
067        super();
068        this.compatibilityLevel = compatibilityLevel != null ? compatibilityLevel : CompatibilityLevel.DEFAULT;
069        this.publicSuffixMatcher = publicSuffixMatcher;
070        this.datepatterns = datepatterns;
071        this.oneHeader = oneHeader;
072    }
073
074    public DefaultCookieSpecProvider(
075            final CompatibilityLevel compatibilityLevel,
076            final PublicSuffixMatcher publicSuffixMatcher) {
077        this(compatibilityLevel, publicSuffixMatcher, null, false);
078    }
079
080    public DefaultCookieSpecProvider(final PublicSuffixMatcher publicSuffixMatcher) {
081        this(CompatibilityLevel.DEFAULT, publicSuffixMatcher, null, false);
082    }
083
084    public DefaultCookieSpecProvider() {
085        this(CompatibilityLevel.DEFAULT, null, null, false);
086    }
087
088    @Override
089    public CookieSpec create(final HttpContext context) {
090        if (cookieSpec == null) {
091            synchronized (this) {
092                if (cookieSpec == null) {
093                    final RFC2965Spec strict = new RFC2965Spec(this.oneHeader,
094                            new RFC2965VersionAttributeHandler(),
095                            new BasicPathHandler(),
096                            PublicSuffixDomainFilter.decorate(
097                                    new RFC2965DomainAttributeHandler(), this.publicSuffixMatcher),
098                            new RFC2965PortAttributeHandler(),
099                            new BasicMaxAgeHandler(),
100                            new BasicSecureHandler(),
101                            new BasicCommentHandler(),
102                            new RFC2965CommentUrlAttributeHandler(),
103                            new RFC2965DiscardAttributeHandler());
104                    final RFC2109Spec obsoleteStrict = new RFC2109Spec(this.oneHeader,
105                            new RFC2109VersionHandler(),
106                            new BasicPathHandler(),
107                            PublicSuffixDomainFilter.decorate(
108                                    new RFC2109DomainHandler(), this.publicSuffixMatcher),
109                            new BasicMaxAgeHandler(),
110                            new BasicSecureHandler(),
111                            new BasicCommentHandler());
112                    final NetscapeDraftSpec netscapeDraft = new NetscapeDraftSpec(
113                            PublicSuffixDomainFilter.decorate(
114                                    new BasicDomainHandler(), this.publicSuffixMatcher),
115                            this.compatibilityLevel == CompatibilityLevel.IE_MEDIUM_SECURITY ?
116                                    new BasicPathHandler() {
117                                        @Override
118                                        public void validate(
119                                                final Cookie cookie,
120                                                final CookieOrigin origin) throws MalformedCookieException {
121                                            // No validation
122                                        }
123                                    } : new BasicPathHandler(),
124                            new BasicSecureHandler(),
125                            new BasicCommentHandler(),
126                            new BasicExpiresHandler(this.datepatterns != null ? this.datepatterns.clone() :
127                                    new String[]{NetscapeDraftSpec.EXPIRES_PATTERN}));
128                    this.cookieSpec = new DefaultCookieSpec(strict, obsoleteStrict, netscapeDraft);
129                }
130            }
131        }
132        return this.cookieSpec;
133    }
134
135}