Index: modules/luni/src/test/java/org/apache/harmony/luni/tests/java/net/CookieManagerTest.java =================================================================== --- modules/luni/src/test/java/org/apache/harmony/luni/tests/java/net/CookieManagerTest.java (revision 0) +++ modules/luni/src/test/java/org/apache/harmony/luni/tests/java/net/CookieManagerTest.java (revision 0) @@ -0,0 +1,306 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.harmony.luni.tests.java.net; + +import java.io.IOException; +import java.net.CookieManager; +import java.net.CookiePolicy; +import java.net.CookieStore; +import java.net.HttpCookie; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.TreeMap; + +import junit.framework.TestCase; + +public class CookieManagerTest extends TestCase { + + private static void checkValidParams4Get(URI uri, + Map> map) throws IOException { + CookieManager manager = new CookieManager(); + try { + manager.get(uri, map); + fail("Should throw IllegalArgumentException"); + } catch (IllegalArgumentException e) { + // expected + } + + } + + private static void checkValidParams4Put(URI uri, + Map> map) throws IOException { + CookieManager manager = new CookieManager(); + try { + manager.put(uri, map); + fail("Should throw IllegalArgumentException"); + } catch (IllegalArgumentException e) { + // expected + } + + } + + /** + * @tests {@link java.net.CookieManager#get(java.net.URI, java.util.Map)} & + * @tests {@link java.net.CookieManager#put(java.net.URI, java.util.Map)} + * IllegalArgumentException + * @since 1.6 + */ + public void test_Put_Get_LURI_LMap_exception() throws IOException, + URISyntaxException { + // get + checkValidParams4Get(new URI(""), null); + checkValidParams4Get(new URI("http://www.test.com"), null); + checkValidParams4Get(null, null); + checkValidParams4Get(null, new HashMap>()); + + // put + checkValidParams4Put(new URI(""), null); + checkValidParams4Put(new URI("http://www.test.com"), null); + checkValidParams4Put(null, null); + checkValidParams4Put(null, new HashMap>()); + } + + private static Map> addCookie(String[][] cookies) { + Map> responseHeaders = new TreeMap>(); + for (int i = 0; i < cookies.length; i++) { + List fields = new ArrayList(); + for (int j = 1; j < cookies[i].length; j += 2) { + fields.add(cookies[i][j]); + } + responseHeaders.put(cookies[i][0], fields); + } + return responseHeaders; + } + + private static CookieManager store(String[][] cookies, + Map> responseHeaders, CookiePolicy policy) + throws IOException, URISyntaxException { + CookieManager manager = new CookieManager(null, policy); + // Put all cookies into manager + for (int i = 0; i < cookies.length; i++) { + for (int j = 2; j < cookies[i].length; j += 2) { + URI uri = new URI(cookies[i][j]); + manager.put(uri, responseHeaders); + } + } + return manager; + } + + /** + * @tests {@link java.net.CookieManager#get(java.net.URI, java.util.Map)} & + * @tests {@link java.net.CookieManager#put(java.net.URI, java.util.Map)} + * + * @since 1.6 + */ + public void test_Put_Get_LURI_LMap() throws IOException, URISyntaxException { + // cookie-key | (content, URI)... + String[][] cookies = { + { "Set-cookie", + "Set-cookie:PREF=test;path=/;domain=.b.c;", "http://a.b.c/", + "Set-cookie:PREF1=test2;path=/;domain=.beg.com;", "http://a.b.c/"}, + + { "Set-cookie2", + "Set-cookie2:NAME1=VALUE1;path=/te;domain=.b.c;", "http://a.b.c/test"}, + + { "Set-cookie", + "Set-cookie2:NAME=VALUE;path=/;domain=.beg.com;", "http://a.beg.com/test", + "Set-cookie2:NAME1=VALUE1;path=/;domain=.beg.com;", "http://a.beg.com/test"}, + + { "Set-cookie2", + "Set-cookie3:NAME=VALUE;path=/;domain=.test.org;", "http://a.test.org/test"}, + + { null, + "Set-cookie3:NAME=VALUE;path=/te;domain=.test.org;", "http://a.test.org/test"}, + + { "Set-cookie2", + "lala", "http://a.test.org/test"} + + }; + + // requires path of cookie is the prefix of uri + // domain of cookie must match that of uri + Map> responseHeaders = addCookie(new String[][] { + cookies[0], cookies[1] }); + CookieManager manager = store( + new String[][] { cookies[0], cookies[1] }, responseHeaders, + null); + + HashMap> dummyMap = new HashMap>(); + Map> map = manager.get(new URI("http://a.b.c/"), + dummyMap); + + assertEquals(1, map.size()); + List list = map.get("Cookie"); + assertEquals(1, list.size()); + + // requires path of cookie is the prefix of uri + map = manager.get(new URI("http://a.b.c/te"), dummyMap); + list = map.get("Cookie"); + assertEquals(2, list.size()); + + // If all cookies are of version 1, then $version=1 will be added + // ,no matter the value cookie-key + responseHeaders = addCookie(new String[][] { cookies[2] }); + manager = store(new String[][] { cookies[2] }, responseHeaders, null); + map = manager.get(new URI("http://a.beg.com/test"), dummyMap); + list = map.get("Cookie"); + assertEquals("$Version=\"1\"", list.get(0)); + assertEquals(3, list.size()); + + // cookie-key will not have effect on determining cookie version + responseHeaders = addCookie(new String[][] { cookies[3] }); + manager = store(new String[][] { cookies[3] }, responseHeaders, null); + map = manager.get(new URI("http://a.test.org/"), responseHeaders); + list = map.get("Cookie"); + assertEquals(1, list.size()); + assertEquals("Set-cookie3:NAME=VALUE", list.get(0)); + + // When key is null, no cookie can be stored/retrieved, even if policy = + // ACCEPT_ALL + responseHeaders = addCookie(new String[][] { cookies[4] }); + manager = store(new String[][] { cookies[4] }, responseHeaders, + CookiePolicy.ACCEPT_ALL); + map = manager.get(new URI("http://a.test.org/"), responseHeaders); + list = map.get("Cookie"); + assertEquals(0, list.size()); + + // All cookies will be rejected if policy == ACCEPT_NONE + responseHeaders = addCookie(new String[][] { cookies[3] }); + manager = store(new String[][] { cookies[3] }, responseHeaders, + CookiePolicy.ACCEPT_NONE); + map = manager.get(new URI("http://a.test.org/"), responseHeaders); + list = map.get("Cookie"); + assertEquals(0, list.size()); + + responseHeaders = addCookie(new String[][] { cookies[5] }); + manager = store(new String[][] { cookies[5] }, responseHeaders, + CookiePolicy.ACCEPT_ALL); + list = map.get("Cookie"); + assertEquals(0, list.size()); + + try { + map.put(null, null); + fail("Should throw UnsupportedOperationException"); + } catch (UnsupportedOperationException e) { + // expected + } + + } + + /** + * @tests {@link java.net.CookieManager#CookieManager()} + * + * @since 1.6 + */ + public void test_CookieManager() { + CookieManager cookieManager = new CookieManager(); + assertNotNull(cookieManager); + assertNotNull(cookieManager.getCookieStore()); + } + + /** + * @tests {@link java.net.CookieManager#CookieManager(java.net.CookieStore, java.net.CookiePolicy)} + * + * @since 1.6 + */ + public void testCookieManager_LCookieStore_LCookiePolicy() { + class DummyStore implements CookieStore { + public String getName() { + return "A dummy store"; + } + + public void add(URI uri, HttpCookie cookie) { + // expected + } + + public List get(URI uri) { + return null; + } + + public List getCookies() { + return null; + } + + public List getURIs() { + return null; + } + + public boolean remove(URI uri, HttpCookie cookie) { + return false; + } + + public boolean removeAll() { + return false; + } + } + CookieStore store = new DummyStore(); + CookieManager cookieManager = new CookieManager(store, + CookiePolicy.ACCEPT_ALL); + assertEquals("A dummy store", ((DummyStore) cookieManager + .getCookieStore()).getName()); + assertSame(store, cookieManager.getCookieStore()); + } + + /** + * @tests {@link java.net.CookieManager#setCookiePolicy(java.net.CookiePolicy)} + * + * @since 1.6 + */ + public void test_SetCookiePolicy_LCookiePolicy() throws URISyntaxException, + IOException { + + // Policy = ACCEPT_NONE + CookieManager manager = new CookieManager(); + manager.setCookiePolicy(CookiePolicy.ACCEPT_NONE); + Map> responseHeaders = new TreeMap>(); + URI uri = new URI("http://a.b.c"); + manager.put(uri, responseHeaders); + Map> map = manager.get(uri, + new HashMap>()); + + assertEquals(1, map.size()); + assertTrue(map.get("Cookie").isEmpty()); + Object key = map.keySet().toArray()[0]; + assertNotNull(key); + assertEquals("Cookie", key); + + // Policy = ACCEPT_ALL + manager.setCookiePolicy(CookiePolicy.ACCEPT_ALL); + responseHeaders = new TreeMap>(); + ArrayList list = new ArrayList(); + list.add("test=null"); + responseHeaders.put("Set-cookie", list); + manager.put(new URI("http://b.c.d"), responseHeaders); + map = manager.get(uri, new HashMap>()); + assertEquals(1, map.size()); + } + + /** + * @tests {@link java.net.CookieManager#getCookieStore()} + * + * @since 1.6 + */ + public void test_GetCookieStore() { + CookieManager cookieManager = new CookieManager(); + CookieStore store = cookieManager.getCookieStore(); + assertNotNull(store); + } + +} Index: modules/luni/src/main/java/java/net/CookieManager.java =================================================================== --- modules/luni/src/main/java/java/net/CookieManager.java (revision 0) +++ modules/luni/src/main/java/java/net/CookieManager.java (revision 0) @@ -0,0 +1,229 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package java.net; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Collections; + +import org.apache.harmony.luni.util.Msg; + +/** + * This class provides a concrete implementation of CookieHandler. It separates + * the storage of cookies from the policy which decides to accept or deny + * cookies. The constructor can have two arguments: a CookieStore and a + * CookiePolicy. The former is in charge of cookie storage and the latter makes + * decision on acceptance/rejection. + * + * CookieHandler is in the center of cookie management. User can make use of + * CookieHandler.setDefault to set a CookieManager as the default one used. + * + * CookieManager.put uses CookiePolicy.shouldAccept to decide whether to put + * some cookies into a cookie store. Three built-in CookiePolicy is defined: + * ACCEPT_ALL, ACCEPT_NONE and ACCEPT_ORIGINAL_SERVER. Users can also customize + * the policy by implementing CookiePolicy. Any accepted HTTP cookie is stored + * in CookieStore and users can also have their own implementation. Up to now, + * Only add(URI, HttpCookie) and get(URI) are used by CookieManager. Other + * methods in this class may probably be used in a more complicated + * implementation. + * + * There are many ways to customize user's own HTTP cookie management: + * + * First, call CookieHandler.setDefault to set a new CookieHandler + * implementation. Second, call CookieHandler.getDefault to use CookieManager. + * The CookiePolicy and CookieStore used are customized. Third, use the + * customized CookiePolicy and the CookieStore. + * + * This implementation conforms to RFC 2965, section 3.3. + * + * @since 1.6 + */ + +public class CookieManager extends CookieHandler { + private CookieStore store; + + private CookiePolicy policy; + + private static final String VERSION_ZERO_HEADER = "Set-cookie"; //$NON-NLS-1$ + + private static final String VERSION_ONE_HEADER = "Set-cookie2"; //$NON-NLS-1$ + + /** + * Constructs a new cookie manager. + * + * The invocation of this constructor is the same as the invocation of + * CookieManager(null, null). + * + */ + public CookieManager() { + this(null, null); + } + + /** + * Constructs a new cookie manager using a specified cookie store and a + * cookie policy. + * + * @param store + * a CookieStore to be used by cookie manager. The manager will + * use a default one if the arg is null. + * @param cookiePolicy + * a CookiePolicy to be used by cookie manager + * ACCEPT_ORIGINAL_SERVER will be used if the arg is null. + */ + public CookieManager(CookieStore s, CookiePolicy cookiePolicy) { + store = s == null ? new CookieStoreImpl() : s; + policy = cookiePolicy == null ? CookiePolicy.ACCEPT_ORIGINAL_SERVER + : cookiePolicy; + } + + /** + * Searchs and gets all cookies in the cache by the specified uri in the + * request header. + * + * @param uri + * the specified uri to search for + * @param requestHeaders + * a list of request headers + * @return a map that record all such cookies, the map is unchangeable + * @throws IOException + * if some error of I/O operation occurs + */ + @Override + public Map> get(URI uri, + Map> requestHeaders) throws IOException { + if (uri == null || requestHeaders == null) { + throw new IllegalArgumentException(Msg.getString("KB004")); //$NON-NLS-1$ + } + List cookies = store.get(uri); + for (int i = 0; i < cookies.size(); i++) { + HttpCookie cookie = cookies.get(i); + String uriPath = uri.getPath(); + String cookiePath = cookie.getPath(); + // if the uri's path does not path-match cookie's path, remove + // cookies from the list + if (cookiePath == null || uriPath.length() == 0 + || !uriPath.startsWith(cookiePath)) { + cookies.remove(i); + } + } + // TODO parse cookies into Map and so far requesterHeaders are not used + return getCookieMap(cookies, requestHeaders); + } + + private static Map> getCookieMap( + List cookies, Map> requestHeaders) { + HashMap> map = new HashMap>(); + ArrayList cookieStr = new ArrayList(); + // If all cookies are version 1, add a "$Version="1"" header + boolean versionOne = true; + for (HttpCookie cookie : cookies) { + if (cookie.getVersion() == 0) { + versionOne = false; + break; + } + } + if (versionOne && !cookies.isEmpty()) { + cookieStr.add("$Version=\"1\""); //$NON-NLS-1$ + } + // add every cookie's string representation into map + for (HttpCookie cookie : cookies) { + cookieStr.add(cookie.toString()); + } + //TODO So far only "Cookie" head detected + map.put("Cookie", cookieStr); //$NON-NLS-1$ + return Collections.unmodifiableMap(map); + } + + /** + * Sets cookies according to uri and responseHeaders + * + * @param uri + * the specified uri + * @param responseHeaders + * a list of request headers + * @throws IOException + * if some error of I/O operation occurs + */ + @Override + public void put(URI uri, Map> responseHeaders) + throws IOException { + if (uri == null || responseHeaders == null) { + throw new IllegalArgumentException(Msg.getString("KA019")); //$NON-NLS-1$ + } + // parse and construct cookies according to the map + List cookies = parseCookie(responseHeaders); + for (HttpCookie cookie : cookies) { + // if the cookie conforms to the policy and matches the uri's path, + // add it into the store + if (policy.shouldAccept(uri, cookie)) { + store.add(uri, cookie); + } + } + } + + private static List parseCookie( + Map> responseHeaders) { + List cookies = new ArrayList(); + for (Map.Entry> entry : responseHeaders.entrySet()) { + String key = entry.getKey(); + // Only "Set-cookie" and "Set-cookie2" pair will be parsed + if (key != null + && (key.equalsIgnoreCase(VERSION_ZERO_HEADER) || key + .equalsIgnoreCase(VERSION_ONE_HEADER))) { + // parse list elements one by one + for (String cookieStr : entry.getValue()) { + try { + for (HttpCookie cookie : HttpCookie.parse(cookieStr)) { + cookies.add(cookie); + } + } catch (IllegalArgumentException e) { + // this string is invalid, jump to the next one. + } + } + } + } + return cookies; + } + + /** + * Sets the cookie policy of this cookie manager. + * + * ACCEPT_ORIGINAL_SERVER is the default policy for CookieManager. + * + * @param cookiePolicy + * the cookie policy. if null, the original policy will not be + * changed. + */ + public void setCookiePolicy(CookiePolicy cookiePolicy) { + if (cookiePolicy != null) { + policy = cookiePolicy; + } + } + + /** + * Gets current cookie store. + * + * @return the cookie store currently used by cookie manager. + */ + public CookieStore getCookieStore() { + return store; + } + +}