# HG changeset patch # User chegar # Date 1253287466 -3600 # Node ID ea9c34fc8590a33382fdc1b26bf3ce9797e1f433 # Parent 47b5ce137a2b532ccc9ce6a7328fe4de0d89c3ba 6882609: Move default InMemoryCookieStore to java.net Summary: remove static dependency on sun.net.www.protocol.http Reviewed-by: alanb, jccollet diff -r 47b5ce137a2b -r ea9c34fc8590 jdk/make/sun/net/FILES_java.gmk --- a/jdk/make/sun/net/FILES_java.gmk Thu Sep 10 19:04:25 2009 +0100 +++ b/jdk/make/sun/net/FILES_java.gmk Fri Sep 18 16:24:26 2009 +0100 @@ -123,8 +123,7 @@ sun/net/idn/UCharacterEnums.java \ sun/net/idn/UCharacterDirection.java \ sun/net/idn/StringPrepDataReader.java \ - sun/net/idn/StringPrep.java \ - sun/net/www/protocol/http/InMemoryCookieStore.java + sun/net/idn/StringPrep.java ifeq ($(PLATFORM), windows) FILES_java += sun/net/www/protocol/http/NTLMAuthSequence.java diff -r 47b5ce137a2b -r ea9c34fc8590 jdk/src/share/classes/java/net/CookieManager.java --- a/jdk/src/share/classes/java/net/CookieManager.java Thu Sep 10 19:04:25 2009 +0100 +++ b/jdk/src/share/classes/java/net/CookieManager.java Fri Sep 18 16:24:26 2009 +0100 @@ -157,7 +157,7 @@ // if not specify CookieStore to use, use default one if (store == null) { - cookieJar = new sun.net.www.protocol.http.InMemoryCookieStore(); + cookieJar = new InMemoryCookieStore(); } else { cookieJar = store; } diff -r 47b5ce137a2b -r ea9c34fc8590 jdk/src/share/classes/java/net/InMemoryCookieStore.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/java/net/InMemoryCookieStore.java Fri Sep 18 16:24:26 2009 +0100 @@ -0,0 +1,393 @@ +/* + * Copyright 2005-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package java.net; + +import java.net.URI; +import java.net.CookieStore; +import java.net.HttpCookie; +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.concurrent.locks.ReentrantLock; + +/** + * A simple in-memory java.net.CookieStore implementation + * + * @author Edward Wang + * @since 1.6 + */ +class InMemoryCookieStore implements CookieStore { + // 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 + */ + public InMemoryCookieStore() { + cookieJar = new ArrayList(); + domainIndex = new HashMap>(); + uriIndex = new HashMap>(); + + lock = new ReentrantLock(false); + } + + /** + * Add one cookie into cookie store. + */ + 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. + */ + 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 + */ + public List getCookies() { + List rt; + + lock.lock(); + try { + Iterator it = cookieJar.iterator(); + while (it.hasNext()) { + if (it.next().hasExpired()) { + it.remove(); + } + } + } finally { + rt = Collections.unmodifiableList(cookieJar); + lock.unlock(); + } + + return rt; + } + + /** + * Get all URIs, which are associated with at least one cookie + * of this cookie store. + */ + public List getURIs() { + List uris = new ArrayList(); + + 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(); + } + } + } finally { + uris.addAll(uriIndex.keySet()); + lock.unlock(); + } + + return uris; + } + + + /** + * Remove a cookie from store + */ + 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. + */ + 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 beed 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 (T index : cookieIndex.keySet()) { + if (comparator.compareTo(index) == 0) { + List indexedCookies = cookieIndex.get(index); + // 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 = null; + try { + effectiveURI = new URI("http", + uri.getHost(), + null, // path component + null, // query component + null // fragment component + ); + } catch (URISyntaxException ignored) { + effectiveURI = uri; + } + + return effectiveURI; + } +} diff -r 47b5ce137a2b -r ea9c34fc8590 jdk/src/share/classes/sun/net/www/protocol/http/InMemoryCookieStore.java --- a/jdk/src/share/classes/sun/net/www/protocol/http/InMemoryCookieStore.java Thu Sep 10 19:04:25 2009 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,393 +0,0 @@ -/* - * Copyright 2005-2008 Sun Microsystems, Inc. All Rights Reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Sun designates this - * particular file as subject to the "Classpath" exception as provided - * by Sun in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - */ - -package sun.net.www.protocol.http; - -import java.net.URI; -import java.net.CookieStore; -import java.net.HttpCookie; -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.concurrent.locks.ReentrantLock; - -/** - * A simple in-memory java.net.CookieStore implementation - * - * @author Edward Wang - * @since 1.6 - */ -public class InMemoryCookieStore implements CookieStore { - // 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 - */ - public InMemoryCookieStore() { - cookieJar = new ArrayList(); - domainIndex = new HashMap>(); - uriIndex = new HashMap>(); - - lock = new ReentrantLock(false); - } - - /** - * Add one cookie into cookie store. - */ - 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. - */ - 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 - */ - public List getCookies() { - List rt; - - lock.lock(); - try { - Iterator it = cookieJar.iterator(); - while (it.hasNext()) { - if (it.next().hasExpired()) { - it.remove(); - } - } - } finally { - rt = Collections.unmodifiableList(cookieJar); - lock.unlock(); - } - - return rt; - } - - /** - * Get all URIs, which are associated with at least one cookie - * of this cookie store. - */ - public List getURIs() { - List uris = new ArrayList(); - - 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(); - } - } - } finally { - uris.addAll(uriIndex.keySet()); - lock.unlock(); - } - - return uris; - } - - - /** - * Remove a cookie from store - */ - 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. - */ - 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 beed 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 (T index : cookieIndex.keySet()) { - if (comparator.compareTo(index) == 0) { - List indexedCookies = cookieIndex.get(index); - // 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 = null; - try { - effectiveURI = new URI("http", - uri.getHost(), - null, // path component - null, // query component - null // fragment component - ); - } catch (URISyntaxException ignored) { - effectiveURI = uri; - } - - return effectiveURI; - } -}