All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.sun.xml.ws.transport.http.client.InMemoryCookieStore Maven / Gradle / Ivy

There is a newer version: 4.0.2
Show newest version
/*
 * Copyright (c) 2006, 2018 Oracle and/or its affiliates. All rights reserved.
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Distribution License v. 1.0, which is available at
 * http://www.eclipse.org/org/documents/edl-v10.php.
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */

package com.sun.xml.ws.transport.http.client;

import java.net.URI;
import java.net.URISyntaxException;
import java.util.List;
import java.util.Map;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Collections;
import java.util.Iterator;
import java.util.Map.Entry;
import java.util.concurrent.locks.ReentrantLock;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * A simple in-memory java.net.CookieStore implementation
 *
 * @version %I%, %E%
 * @author Edward Wang
 * @since 1.6
 */
class InMemoryCookieStore implements CookieStore {
    
    private static final Logger LOGGER = Logger.getLogger(HttpTransportPipe.class.getName());
    
    // the in-memory representation of cookies
    private List cookieJar = null;

    // the cookies are indexed by its domain and associated uri (if present)
    // CAUTION: when a cookie removed from main data structure (i.e. cookieJar),
    //          it won't be cleared in domainIndex & uriIndex. Double-check the
    //          presence of cookie when retrieve one form index store.
    private Map> domainIndex = null;
    private Map> uriIndex = null;

    // use ReentrantLock instead of syncronized for scalability
    private ReentrantLock lock = null;


    /**
     * The default ctor
     */
    InMemoryCookieStore() {
        cookieJar = new ArrayList();
        domainIndex = new HashMap>();
        uriIndex = new HashMap>();

        lock = new ReentrantLock(false);
    }

    /**
     * Add one cookie into cookie store.
     */
    @Override
    public void add(URI uri, HttpCookie cookie) {
        // pre-condition : argument can't be null
        if (cookie == null) {
            throw new NullPointerException("cookie is null");
        }


        lock.lock();
        try {
            // remove the ole cookie if there has had one
            cookieJar.remove(cookie);

            // add new cookie if it has a non-zero max-age
            if (cookie.getMaxAge() != 0) {
                cookieJar.add(cookie);
                // and add it to domain index
                if (cookie.getDomain() != null) {
                    addIndex(domainIndex, cookie.getDomain(), cookie);
                }
                // add it to uri index, too
                addIndex(uriIndex, getEffectiveURI(uri), cookie);
            }
        } finally {
            lock.unlock();
        }
    }


    /**
     * Get all cookies, which:
     *  1) given uri domain-matches with, or, associated with
     *     given uri when added to the cookie store.
     *  3) not expired.
     * See RFC 2965 sec. 3.3.4 for more detail.
     */
    @Override
    public List get(URI uri) {
        // argument can't be null
        if (uri == null) {
            throw new NullPointerException("uri is null");
        }

        List cookies = new ArrayList();
        boolean secureLink = "https".equalsIgnoreCase(uri.getScheme());
        lock.lock();
        try {
            // check domainIndex first
            getInternal1(cookies, domainIndex, uri.getHost(), secureLink);
            // check uriIndex then
            getInternal2(cookies, uriIndex, getEffectiveURI(uri), secureLink);
        } finally {
            lock.unlock();
        }

        return cookies;
    }

    /**
     * Get all cookies in cookie store, except those have expired
     */
    @Override
    public List getCookies() {
        List rt;

        lock.lock();
        try {
            Iterator it = cookieJar.iterator();
            while (it.hasNext()) {
                if (it.next().hasExpired()) {
                    it.remove();
                }
            }
            rt = Collections.unmodifiableList(cookieJar);
        } catch (Exception e) {
            rt = Collections.unmodifiableList(cookieJar);
            LOGGER.log(Level.INFO, null, e);
        } finally {
            lock.unlock();
        }

        return rt;
    }

    /**
     * Get all URIs, which are associated with at least one cookie
     * of this cookie store.
     */
    @Override
    public List getURIs() {
        List uris;

        lock.lock();
        try {
            Iterator it = uriIndex.keySet().iterator();
            while (it.hasNext()) {
                URI uri = it.next();
                List cookies = uriIndex.get(uri);
                if (cookies == null || cookies.size() == 0) {
                    // no cookies list or an empty list associated with
                    // this uri entry, delete it
                    it.remove();
                }
            }
            uris = new ArrayList(uriIndex.keySet());
        } catch (Exception e) {
            uris = new ArrayList(uriIndex.keySet());
            LOGGER.log(Level.INFO, null, e);
        } finally {
            lock.unlock();
        }

        return uris;
    }


    /**
     * Remove a cookie from store
     */
    @Override
    public boolean remove(URI uri, HttpCookie ck) {
        // argument can't be null
        if (ck == null) {
            throw new NullPointerException("cookie is null");
        }

        boolean modified = false;
        lock.lock();
        try {
            modified = cookieJar.remove(ck);
        } finally {
            lock.unlock();
        }

        return modified;
    }


    /**
     * Remove all cookies in this cookie store.
     */
    @Override
    public boolean removeAll() {
        lock.lock();
        try {
            cookieJar.clear();
            domainIndex.clear();
            uriIndex.clear();
        } finally {
            lock.unlock();
        }

        return true;
    }


    /* ---------------- Private operations -------------- */


    /*
     * This is almost the same as HttpCookie.domainMatches except for
     * one difference: It won't reject cookies when the 'H' part of the
     * domain contains a dot ('.').
     * I.E.: RFC 2965 section 3.3.2 says that if host is x.y.domain.com
     * and the cookie domain is .domain.com, then it should be rejected.
     * However that's not how the real world works. Browsers don't reject and
     * some sites, like yahoo.com do actually expect these cookies to be
     * passed along.
     * And should be used for 'old' style cookies (aka Netscape type of cookies)
     */
    private boolean netscapeDomainMatches(String domain, String host)
    {
        if (domain == null || host == null) {
            return false;
        }

        // if there's no embedded dot in domain and domain is not .local
        boolean isLocalDomain = ".local".equalsIgnoreCase(domain);
        int embeddedDotInDomain = domain.indexOf('.');
        if (embeddedDotInDomain == 0) {
            embeddedDotInDomain = domain.indexOf('.', 1);
        }
        if (!isLocalDomain && (embeddedDotInDomain == -1 || embeddedDotInDomain == domain.length() - 1)) {
            return false;
        }

        // if the host name contains no dot and the domain name is .local
        int firstDotInHost = host.indexOf('.');
        if (firstDotInHost == -1 && isLocalDomain) {
            return true;
        }

        int domainLength = domain.length();
        int lengthDiff = host.length() - domainLength;
        if (lengthDiff == 0) {
            // if the host name and the domain name are just string-compare euqal
            return host.equalsIgnoreCase(domain);
        } else if (lengthDiff > 0) {
            // need to check H & D component
//            String H = host.substring(0, lengthDiff);
            String D = host.substring(lengthDiff);

            return (D.equalsIgnoreCase(domain));
        } else if (lengthDiff == -1) {
            // if domain is actually .host
            return (domain.charAt(0) == '.' &&
                    host.equalsIgnoreCase(domain.substring(1)));
        }

        return false;
    }

    private void getInternal1(List cookies, Map> cookieIndex,
            String host, boolean secureLink) {
        // Use a separate list to handle cookies that need to be removed so
        // that there is no conflict with iterators.
        ArrayList toRemove = new ArrayList();
        for (Map.Entry> entry : cookieIndex.entrySet()) {
            String domain = entry.getKey();
            List lst = entry.getValue();
            for (HttpCookie c : lst) {
                if ((c.getVersion() == 0 && netscapeDomainMatches(domain, host)) ||
                        (c.getVersion() == 1 && HttpCookie.domainMatches(domain, host))) {
                    if ((cookieJar.indexOf(c) != -1)) {
                        // the cookie still in main cookie store
                        if (!c.hasExpired()) {
                            // don't add twice and make sure it's the proper
                            // security level
                            if ((secureLink || !c.getSecure()) &&
                                    !cookies.contains(c)) {
                                cookies.add(c);
                            }
                        } else {
                            toRemove.add(c);
                        }
                    } else {
                        // the cookie has been removed from main store,
                        // so also remove it from domain indexed store
                        toRemove.add(c);
                    }
                }
            }
            // Clear up the cookies that need to be removed
            for (HttpCookie c : toRemove) {
                lst.remove(c);
                cookieJar.remove(c);

            }
            toRemove.clear();
        }
    }

    // @param cookies           [OUT] contains the found cookies
    // @param cookieIndex       the index
    // @param comparator        the prediction to decide whether or not
    //                          a cookie in index should be returned
    private  void getInternal2(List cookies,
                                Map> cookieIndex,
                                Comparable comparator, boolean secureLink)
    {
        for (Entry> entry : cookieIndex.entrySet()) {
            T index = entry.getKey();
            if (comparator.compareTo(index) == 0) {
                List indexedCookies = entry.getValue();
                // check the list of cookies associated with this domain
                if (indexedCookies != null) {
                    Iterator it = indexedCookies.iterator();
                    while (it.hasNext()) {
                        HttpCookie ck = it.next();
                        if (cookieJar.indexOf(ck) != -1) {
                            // the cookie still in main cookie store
                            if (!ck.hasExpired()) {
                                // don't add twice
                                if ((secureLink || !ck.getSecure()) &&
                                        !cookies.contains(ck)) {
                                    cookies.add(ck);
                                }
                            } else {
                                it.remove();
                                cookieJar.remove(ck);
                            }
                        } else {
                            // the cookie has beed removed from main store,
                            // so also remove it from domain indexed store
                            it.remove();
                        }
                    }
                } // end of indexedCookies != null
            } // end of comparator.compareTo(index) == 0
        } // end of cookieIndex iteration
    }

    // add 'cookie' indexed by 'index' into 'indexStore'
    private  void addIndex(Map> indexStore,
                              T index,
                              HttpCookie cookie)
    {
        if (index != null) {
            List cookies = indexStore.get(index);
            if (cookies != null) {
                // there may already have the same cookie, so remove it first
                cookies.remove(cookie);

                cookies.add(cookie);
            } else {
                cookies = new ArrayList();
                cookies.add(cookie);
                indexStore.put(index, cookies);
            }
        }
    }


    //
    // for cookie purpose, the effective uri should only be http://host
    // the path will be taken into account when path-match algorithm applied
    //
    private URI getEffectiveURI(URI uri) {
        URI effectiveURI;
        try {
            effectiveURI = new URI("http",
                                   uri.getHost(),
                                   null,  // path component
                                   null,  // query component
                                   null   // fragment component
                                  );
        } catch (URISyntaxException ignored) {
            effectiveURI = uri;
        }

        return effectiveURI;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy