1/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17/* Licensed to the Apache Software Foundation (ASF) under one or more
18 * contributor license agreements.  See the NOTICE file distributed with
19 * this work for additional information regarding copyright ownership.
20 * The ASF licenses this file to You under the Apache License, Version 2.0
21 * (the "License"); you may not use this file except in compliance with
22 * the License.  You may obtain a copy of the License at
23 *
24 *     http://www.apache.org/licenses/LICENSE-2.0
25 *
26 * Unless required by applicable law or agreed to in writing, software
27 * distributed under the License is distributed on an "AS IS" BASIS,
28 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
29 * See the License for the specific language governing permissions and
30 * limitations under the License.
31 */
32
33package libcore.java.net;
34
35import com.google.mockwebserver.MockResponse;
36import com.google.mockwebserver.MockWebServer;
37import com.google.mockwebserver.RecordedRequest;
38import java.io.IOException;
39import java.net.CookieHandler;
40import java.net.CookieManager;
41import static java.net.CookiePolicy.ACCEPT_ORIGINAL_SERVER;
42
43import java.net.CookiePolicy;
44import java.net.CookieStore;
45import java.net.HttpCookie;
46import java.net.HttpURLConnection;
47import java.net.URI;
48import java.net.URISyntaxException;
49import java.net.URLConnection;
50import java.util.ArrayList;
51import java.util.Arrays;
52import java.util.Collection;
53import java.util.Collections;
54import java.util.Comparator;
55import java.util.HashMap;
56import java.util.LinkedHashMap;
57import java.util.List;
58import java.util.Locale;
59import java.util.Map;
60import java.util.RandomAccess;
61import java.util.TreeMap;
62
63import junit.framework.TestCase;
64
65public abstract class AbstractCookiesTest extends TestCase {
66
67    private static final Map<String, List<String>> EMPTY_COOKIES_MAP = Collections.emptyMap();
68
69    private CookieHandler defaultHandler;
70    private CookieManager cookieManager;
71    private CookieStore cookieStore;
72    private MockWebServer server;
73
74
75    @Override public void setUp() throws Exception {
76        super.setUp();
77        server = new MockWebServer();
78        defaultHandler = CookieHandler.getDefault();
79        cookieManager = new CookieManager(createCookieStore(), null);
80        cookieStore = cookieManager.getCookieStore();
81    }
82
83    @Override public void tearDown() throws Exception {
84        CookieHandler.setDefault(defaultHandler);
85        server.shutdown();
86        super.tearDown();
87    }
88
89    protected abstract CookieStore createCookieStore();
90
91    public void testNetscapeResponse() throws Exception {
92        CookieManager cookieManager = new CookieManager(createCookieStore(),
93                ACCEPT_ORIGINAL_SERVER);
94        CookieHandler.setDefault(cookieManager);
95        server.play();
96
97        server.enqueue(new MockResponse().addHeader("Set-Cookie: a=android; "
98                + "expires=Fri, 31-Dec-9999 23:59:59 GMT; "
99                + "path=/path; "
100                + "domain=" + server.getCookieDomain() + "; "
101                + "secure"));
102        get(server, "/path/foo");
103
104        List<HttpCookie> cookies = cookieManager.getCookieStore().getCookies();
105        assertEquals(1, cookies.size());
106        HttpCookie cookie = cookies.get(0);
107        assertEquals("a", cookie.getName());
108        assertEquals("android", cookie.getValue());
109        assertEquals(null, cookie.getComment());
110        assertEquals(null, cookie.getCommentURL());
111        assertEquals(false, cookie.getDiscard());
112        assertEquals(server.getCookieDomain(), cookie.getDomain());
113        assertTrue(cookie.getMaxAge() > 100000000000L);
114        assertEquals("/path", cookie.getPath());
115        assertEquals(true, cookie.getSecure());
116        assertEquals(0, cookie.getVersion());
117    }
118
119    public void testRfc2109Response() throws Exception {
120        CookieManager cookieManager = new CookieManager(createCookieStore(),
121                ACCEPT_ORIGINAL_SERVER);
122        CookieHandler.setDefault(cookieManager);
123        server.play();
124
125        server.enqueue(new MockResponse().addHeader("Set-Cookie: a=android; "
126                + "Comment=this cookie is delicious; "
127                + "Domain=" + server.getCookieDomain() + "; "
128                + "Max-Age=60; "
129                + "Path=/path; "
130                + "Secure; "
131                + "Version=1"));
132        get(server, "/path/foo");
133
134        List<HttpCookie> cookies = cookieManager.getCookieStore().getCookies();
135        assertEquals(1, cookies.size());
136        HttpCookie cookie = cookies.get(0);
137        assertEquals("a", cookie.getName());
138        assertEquals("android", cookie.getValue());
139        assertEquals("this cookie is delicious", cookie.getComment());
140        assertEquals(null, cookie.getCommentURL());
141        assertEquals(false, cookie.getDiscard());
142        assertEquals(server.getCookieDomain(), cookie.getDomain());
143        assertEquals(60, cookie.getMaxAge());
144        assertEquals("/path", cookie.getPath());
145        assertEquals(true, cookie.getSecure());
146        assertEquals(1, cookie.getVersion());
147    }
148
149    public void testRfc2965Response() throws Exception {
150        CookieManager cookieManager = new CookieManager(createCookieStore(),
151                ACCEPT_ORIGINAL_SERVER);
152        CookieHandler.setDefault(cookieManager);
153        server.play();
154
155        server.enqueue(new MockResponse().addHeader("Set-Cookie2: a=android; "
156                + "Comment=this cookie is delicious; "
157                + "CommentURL=http://google.com/; "
158                + "Discard; "
159                + "Domain=" + server.getCookieDomain() + "; "
160                + "Max-Age=60; "
161                + "Path=/path; "
162                + "Port=\"80,443," + server.getPort() + "\"; "
163                + "Secure; "
164                + "Version=1"));
165        get(server, "/path/foo");
166
167        List<HttpCookie> cookies = cookieManager.getCookieStore().getCookies();
168        assertEquals(1, cookies.size());
169        HttpCookie cookie = cookies.get(0);
170        assertEquals("a", cookie.getName());
171        assertEquals("android", cookie.getValue());
172        assertEquals("this cookie is delicious", cookie.getComment());
173        assertEquals("http://google.com/", cookie.getCommentURL());
174        assertEquals(true, cookie.getDiscard());
175        assertEquals(server.getCookieDomain(), cookie.getDomain());
176        assertEquals(60, cookie.getMaxAge());
177        assertEquals("/path", cookie.getPath());
178        assertEquals("80,443," + server.getPort(), cookie.getPortlist());
179        assertEquals(true, cookie.getSecure());
180        assertEquals(1, cookie.getVersion());
181    }
182
183    public void testQuotedAttributeValues() throws Exception {
184        CookieManager cookieManager = new CookieManager(createCookieStore(),
185                ACCEPT_ORIGINAL_SERVER);
186
187        CookieHandler.setDefault(cookieManager);
188        server.play();
189
190        server.enqueue(new MockResponse().addHeader("Set-Cookie2: a=\"android\"; "
191                + "Comment=\"this cookie is delicious\"; "
192                + "CommentURL=\"http://google.com/\"; "
193                + "Discard; "
194                + "Domain=\"" + server.getCookieDomain() + "\"; "
195                + "Max-Age=\"60\"; "
196                + "Path=\"/path\"; "
197                + "Port=\"80,443," + server.getPort() + "\"; "
198                + "Secure; "
199                + "Version=\"1\""));
200        get(server, "/path/foo");
201
202        List<HttpCookie> cookies = cookieManager.getCookieStore().getCookies();
203        assertEquals(1, cookies.size());
204        HttpCookie cookie = cookies.get(0);
205        assertEquals("a", cookie.getName());
206        assertEquals("android", cookie.getValue());
207        assertEquals("this cookie is delicious", cookie.getComment());
208        assertEquals("http://google.com/", cookie.getCommentURL());
209        assertEquals(true, cookie.getDiscard());
210        assertEquals(server.getCookieDomain(), cookie.getDomain());
211        assertEquals(60, cookie.getMaxAge());
212        assertEquals("/path", cookie.getPath());
213        assertEquals("80,443," + server.getPort(), cookie.getPortlist());
214        assertEquals(true, cookie.getSecure());
215        assertEquals(1, cookie.getVersion());
216    }
217
218    public void testResponseWithMultipleCookieHeaderLines() throws Exception {
219        TestCookieStore cookieStore = new TestCookieStore();
220        CookieManager cookieManager = new CookieManager(cookieStore, ACCEPT_ORIGINAL_SERVER);
221        cookieManager.put(new URI("http://android.com"), cookieHeaders("a=android", "b=banana"));
222        List<HttpCookie> cookies = sortedCopy(cookieStore.cookies);
223        assertEquals(2, cookies.size());
224        HttpCookie cookieA = cookies.get(0);
225        assertEquals("a", cookieA.getName());
226        assertEquals("android", cookieA.getValue());
227        HttpCookie cookieB = cookies.get(1);
228        assertEquals("b", cookieB.getName());
229        assertEquals("banana", cookieB.getValue());
230    }
231
232    public void testDomainDefaulting() throws Exception {
233        TestCookieStore cookieStore = new TestCookieStore();
234        CookieManager cookieManager = new CookieManager(cookieStore, ACCEPT_ORIGINAL_SERVER);
235        cookieManager.put(new URI("http://android.com/"), cookieHeaders("a=android"));
236        assertEquals("android.com", cookieStore.getCookie("a").getDomain());
237    }
238
239    public void testNonMatchingDomainsRejected() throws Exception {
240        TestCookieStore cookieStore = new TestCookieStore();
241        CookieManager cookieManager = new CookieManager(cookieStore, ACCEPT_ORIGINAL_SERVER);
242        cookieManager.put(new URI("http://android.com/"),
243                cookieHeaders("a=android;domain=google.com"));
244        assertEquals(Collections.<HttpCookie>emptyList(), cookieStore.cookies);
245    }
246
247    public void testMatchingDomainsAccepted() throws Exception {
248        TestCookieStore cookieStore = new TestCookieStore();
249        CookieManager cookieManager = new CookieManager(cookieStore, ACCEPT_ORIGINAL_SERVER);
250        cookieManager.put(new URI("http://www.android.com/"),
251                cookieHeaders("a=android;domain=.android.com"));
252        assertEquals(".android.com", cookieStore.getCookie("a").getDomain());
253    }
254
255    public void testPathDefaulting() throws Exception {
256        TestCookieStore cookieStore = new TestCookieStore();
257        CookieManager cookieManager = new CookieManager(cookieStore, ACCEPT_ORIGINAL_SERVER);
258        cookieManager.put(new URI("http://android.com/foo/bar"), cookieHeaders("a=android"));
259        assertEquals("/foo/", cookieStore.getCookie("a").getPath());
260        cookieManager.put(new URI("http://android.com/"), cookieHeaders("b=banana"));
261        assertEquals("/", cookieStore.getCookie("b").getPath());
262        cookieManager.put(new URI("http://android.com/foo/"), cookieHeaders("c=carrot"));
263        assertEquals("/foo/", cookieStore.getCookie("c").getPath());
264    }
265
266    public void testNonMatchingPathsRejected() throws Exception {
267        TestCookieStore cookieStore = new TestCookieStore();
268        CookieManager cookieManager = new CookieManager(cookieStore, ACCEPT_ORIGINAL_SERVER);
269        cookieManager.put(new URI("http://android.com/foo/bar"),
270                cookieHeaders("a=android;path=/baz/bar"));
271        assertEquals("Expected to reject cookies whose path is not a prefix of the request path",
272                Collections.<HttpCookie>emptyList(), cookieStore.cookies); // RI6 fails this
273    }
274
275    public void testMatchingPathsAccepted() throws Exception {
276        TestCookieStore cookieStore = new TestCookieStore();
277        CookieManager cookieManager = new CookieManager(cookieStore, ACCEPT_ORIGINAL_SERVER);
278        cookieManager.put(new URI("http://android.com/foo/bar/"),
279                cookieHeaders("a=android;path=/foo"));
280        assertEquals("/foo", cookieStore.getCookie("a").getPath());
281    }
282
283    public void testNoCookieHeaderSentIfNoCookiesMatch() throws IOException, URISyntaxException {
284        CookieManager cookieManager = new CookieManager(null, ACCEPT_ORIGINAL_SERVER);
285        Map<String, List<String>> cookieHeaders = cookieManager.get(
286                new URI("http://android.com/foo/bar/"), EMPTY_COOKIES_MAP);
287        assertTrue(cookieHeaders.toString(), cookieHeaders.isEmpty()
288                || (cookieHeaders.size() == 1 && cookieHeaders.get("Cookie").isEmpty()));
289    }
290
291    public void testCookieManagerGet_schemeChecks() throws Exception {
292        CookieManager cookieManager = new CookieManager(createCookieStore(), null);
293
294        cookieManager.put(new URI("http://a.com/"), cookieHeaders("a1=android"));
295        cookieManager.put(new URI("https://a.com/"), cookieHeaders("a2=android"));
296        cookieManager.put(new URI("https://a.com/"), cookieHeaders("a3=android; Secure"));
297
298        assertManagerCookiesMatch(cookieManager, "http://a.com/", "a1=android; a2=android");
299        assertManagerCookiesMatch(cookieManager, "https://a.com/",
300                "a1=android; a2=android; a3=android");
301    }
302
303    public void testCookieManagerGet_hostChecks() throws Exception {
304        CookieManager cookieManager = new CookieManager(createCookieStore(), null);
305
306        cookieManager.put(new URI("http://a.com/"), cookieHeaders("a1=android"));
307        cookieManager.put(new URI("http://b.com/"), cookieHeaders("b1=android"));
308
309        assertManagerCookiesMatch(cookieManager, "http://a.com/", "a1=android");
310        assertManagerCookiesMatch(cookieManager, "http://b.com/", "b1=android");
311    }
312
313    public void testCookieManagerGet_portChecks() throws Exception {
314        CookieManager cookieManager = new CookieManager(createCookieStore(), null);
315
316        cookieManager.put(new URI("http://a.com:443/"), cookieHeaders("a1=android"));
317        cookieManager.put(new URI("http://a.com:8080/"), cookieHeaders("a2=android"));
318        cookieManager.put(new URI("http://a.com:8080/"), cookieHeaders("a3=android; Port=8080"));
319
320        assertManagerCookiesMatch(cookieManager, "http://a.com/", "a1=android; a2=android");
321        assertManagerCookiesMatch(cookieManager, "http://a.com:8080/",
322                "a1=android; a2=android; a3=android");
323    }
324
325    public void testCookieManagerGet_pathChecks() throws Exception {
326        CookieManager cookieManager = new CookieManager(createCookieStore(), null);
327
328        cookieManager.put(new URI("http://a.com/"), cookieHeaders("a1=android"));
329        cookieManager.put(new URI("http://a.com/path1"),
330                cookieHeaders("a2=android; Path=\"/path1\""));
331        cookieManager.put(new URI("http://a.com/path2"),
332                cookieHeaders("a3=android; Path=\"/path2\""));
333
334        assertManagerCookiesMatch(cookieManager, "http://a.com/notpath", "a1=android");
335        assertManagerCookiesMatch(cookieManager, "http://a.com/path1", "a1=android; a2=android");
336    }
337
338    public void testSendingCookiesFromStore() throws Exception {
339        server.enqueue(new MockResponse());
340        server.play();
341
342        CookieManager cookieManager = new CookieManager(createCookieStore(),
343                ACCEPT_ORIGINAL_SERVER);
344        HttpCookie cookieA = createCookie("a", "android", server.getCookieDomain(), "/");
345        cookieManager.getCookieStore().add(server.getUrl("/").toURI(), cookieA);
346        HttpCookie cookieB = createCookie("b", "banana", server.getCookieDomain(), "/");
347        cookieManager.getCookieStore().add(server.getUrl("/").toURI(), cookieB);
348        CookieHandler.setDefault(cookieManager);
349
350        get(server, "/");
351        RecordedRequest request = server.takeRequest();
352
353        List<String> receivedHeaders = request.getHeaders();
354        assertContains(receivedHeaders, "Cookie: $Version=\"1\"; "
355                + "a=\"android\";$Path=\"/\";$Domain=\"" + server.getCookieDomain() + "\"; "
356                + "b=\"banana\";$Path=\"/\";$Domain=\"" + server.getCookieDomain() + "\"");
357    }
358
359    public void testRedirectsDoNotIncludeTooManyCookies() throws Exception {
360        MockWebServer redirectTarget = new MockWebServer();
361        redirectTarget.enqueue(new MockResponse().setBody("A"));
362        redirectTarget.play();
363
364        MockWebServer redirectSource = new MockWebServer();
365        redirectSource.enqueue(new MockResponse()
366                .setResponseCode(HttpURLConnection.HTTP_MOVED_TEMP)
367                .addHeader("Location: " + redirectTarget.getUrl("/")));
368        redirectSource.play();
369
370        CookieManager cookieManager = new CookieManager(createCookieStore(),
371                ACCEPT_ORIGINAL_SERVER);
372        HttpCookie cookie = createCookie("c", "cookie", redirectSource.getCookieDomain(), "/");
373        String portList = Integer.toString(redirectSource.getPort());
374        cookie.setPortlist(portList);
375        cookieManager.getCookieStore().add(redirectSource.getUrl("/").toURI(), cookie);
376        CookieHandler.setDefault(cookieManager);
377
378        get(redirectSource, "/");
379        RecordedRequest request = redirectSource.takeRequest();
380
381        assertContains(request.getHeaders(), "Cookie: $Version=\"1\"; "
382                + "c=\"cookie\";$Path=\"/\";$Domain=\"" + redirectSource.getCookieDomain()
383                + "\";$Port=\"" + portList + "\"");
384
385        for (String header : redirectTarget.takeRequest().getHeaders()) {
386            if (header.startsWith("Cookie")) {
387                fail(header);
388            }
389        }
390        redirectSource.shutdown();
391        redirectTarget.shutdown();
392    }
393
394    /**
395     * Test which headers show up where. The cookie manager should be notified
396     * of both user-specified and derived headers like {@code Host}. Headers
397     * named {@code Cookie} or {@code Cookie2} that are returned by the cookie
398     * manager should show up in the request and in {@code
399     * getRequestProperties}.
400     */
401    public void testHeadersSentToCookieHandler() throws IOException, InterruptedException {
402        final Map<String, List<String>> cookieHandlerHeaders = new HashMap<String, List<String>>();
403        CookieHandler.setDefault(new CookieManager(createCookieStore(), null) {
404            @Override
405            public Map<String, List<String>> get(URI uri,
406                    Map<String, List<String>> requestHeaders) throws IOException {
407                cookieHandlerHeaders.putAll(requestHeaders);
408                Map<String, List<String>> result = new HashMap<String, List<String>>();
409                result.put("Cookie", Collections.singletonList("Bar=bar"));
410                result.put("Cookie2", Collections.singletonList("Baz=baz"));
411                result.put("Quux", Collections.singletonList("quux"));
412                return result;
413            }
414        });
415        server.enqueue(new MockResponse());
416        server.play();
417
418        HttpURLConnection connection = (HttpURLConnection) server.getUrl("/").openConnection();
419        assertEquals(Collections.<String, List<String>>emptyMap(),
420                connection.getRequestProperties());
421
422        connection.setRequestProperty("Foo", "foo");
423        connection.setDoOutput(true);
424        connection.getOutputStream().write(5);
425        connection.getOutputStream().close();
426        connection.getInputStream().close();
427
428        RecordedRequest request = server.takeRequest();
429
430        assertContainsAll(cookieHandlerHeaders.keySet(), "Foo");
431        assertContainsAll(cookieHandlerHeaders.keySet(),
432                "Content-Type", "User-Agent", "Connection", "Host");
433        assertFalse(cookieHandlerHeaders.containsKey("Cookie"));
434
435        /*
436         * The API specifies that calling getRequestProperties() on a connected instance should fail
437         * with an IllegalStateException, but the RI violates the spec and returns a valid map.
438         * http://www.mail-archive.com/net-dev@openjdk.java.net/msg01768.html
439         */
440        try {
441            assertContainsAll(connection.getRequestProperties().keySet(), "Foo");
442            assertContainsAll(connection.getRequestProperties().keySet(),
443                    "Content-Type", "Content-Length", "User-Agent", "Connection", "Host");
444            assertContainsAll(connection.getRequestProperties().keySet(), "Cookie", "Cookie2");
445            assertFalse(connection.getRequestProperties().containsKey("Quux"));
446        } catch (IllegalStateException expected) {
447        }
448
449        assertContainsAll(request.getHeaders(), "Foo: foo", "Cookie: Bar=bar", "Cookie2: Baz=baz");
450        assertFalse(request.getHeaders().contains("Quux: quux"));
451    }
452
453    public void testCookiesSentIgnoresCase() throws Exception {
454        CookieHandler.setDefault(new CookieManager(createCookieStore(), null) {
455            @Override public Map<String, List<String>> get(URI uri,
456                    Map<String, List<String>> requestHeaders) throws IOException {
457                Map<String, List<String>> result = new HashMap<String, List<String>>();
458                result.put("COOKIE", Collections.singletonList("Bar=bar"));
459                result.put("cooKIE2", Collections.singletonList("Baz=baz"));
460                return result;
461            }
462        });
463        server. enqueue(new MockResponse());
464        server.play();
465
466        get(server, "/");
467
468        RecordedRequest request = server.takeRequest();
469        assertContainsAll(request.getHeaders(), "COOKIE: Bar=bar", "cooKIE2: Baz=baz");
470        assertFalse(request.getHeaders().contains("Quux: quux"));
471    }
472
473    /**
474     * RFC 2109 and RFC 2965 disagree here. 2109 says two equals strings match only if they are
475     * fully-qualified domain names. 2965 says two equal strings always match. We're testing for
476     * 2109 behavior because it's more widely used, it's more conservative, and it's what the RI
477     * does.
478     */
479    public void testDomainMatchesOnLocalAddresses() {
480        assertFalse(HttpCookie.domainMatches("localhost", "localhost"));
481        assertFalse(HttpCookie.domainMatches("b", "b"));
482    }
483
484    public void testDomainMatchesOnIpAddress() {
485        assertTrue(HttpCookie.domainMatches("127.0.0.1", "127.0.0.1"));
486        assertFalse(HttpCookie.domainMatches("127.0.0.1", "127.0.0.0"));
487        assertFalse(HttpCookie.domainMatches("127.0.0.1", "localhost"));
488    }
489
490    public void testDomainMatchesCaseMapping() {
491        testDomainMatchesCaseMapping(Locale.US);
492    }
493
494    public void testDomainMatchesCaseMappingExoticLocale() {
495        testDomainMatchesCaseMapping(new Locale("tr", "TR"));
496    }
497
498    private void testDomainMatchesCaseMapping(Locale locale) {
499        Locale defaultLocale = Locale.getDefault();
500        Locale.setDefault(locale);
501        try {
502            assertTrue(HttpCookie.domainMatches(".android.com", "WWW.ANDROID.COM"));
503            assertFalse(HttpCookie.domainMatches("android.com", "WWW.ANDROID.COM"));
504        } finally {
505            Locale.setDefault(defaultLocale);
506        }
507    }
508
509    /**
510     * From the spec, "If an explicitly specified value does not start with a dot, the user agent
511     * supplies a leading dot.". This prepending doesn't happen in setDomain.
512     */
513    public void testDomainNotAutomaticallyPrefixedWithDot() {
514        HttpCookie cookie = new HttpCookie("Foo", "foo");
515        cookie.setDomain("localhost");
516        assertEquals("localhost", cookie.getDomain());
517    }
518
519    public void testCookieStoreNullUris() {
520        CookieStore cookieStore = new CookieManager(createCookieStore(), null).getCookieStore();
521        HttpCookie cookieA = createCookie("a", "android", ".android.com", "/source");
522        HttpCookie cookieB = createCookie("b", "banana", "code.google.com", "/p/android");
523
524        try {
525            cookieStore.add(null, cookieA);
526        } catch (NullPointerException expected) {
527            // the RI crashes even though the cookie does get added to the store; sigh
528            expected.printStackTrace();
529        }
530        assertEquals(Arrays.asList(cookieA), cookieStore.getCookies());
531        try {
532            cookieStore.add(null, cookieB);
533        } catch (NullPointerException expected) {
534        }
535        assertEquals(Arrays.asList(cookieA, cookieB), cookieStore.getCookies());
536
537        try {
538            cookieStore.get(null);
539            fail();
540        } catch (NullPointerException expected) {
541        }
542
543        assertEquals(Collections.<URI>emptyList(), cookieStore.getURIs());
544        assertTrue(cookieStore.remove(null, cookieA));
545        assertEquals(Arrays.asList(cookieB), cookieStore.getCookies());
546
547        assertTrue(cookieStore.removeAll());
548        assertEquals(Collections.<URI>emptyList(), cookieStore.getURIs());
549        assertEquals(Collections.<HttpCookie>emptyList(), cookieStore.getCookies());
550    }
551
552    public void testCookieStoreRemoveAll() throws URISyntaxException {
553        CookieStore cookieStore = new CookieManager(createCookieStore(), null).getCookieStore();
554        cookieStore.add(new URI("http://code.google.com/"), new HttpCookie("a", "android"));
555        assertTrue(cookieStore.removeAll());
556        assertEquals(Collections.<URI>emptyList(), cookieStore.getURIs());
557        assertEquals(Collections.<HttpCookie>emptyList(), cookieStore.getCookies());
558        assertFalse("Expected removeAll() to return false when the call doesn't mutate the store",
559                cookieStore.removeAll());  // RI6 fails this
560    }
561
562    public void testCookieStoreAddAcceptsConflictingUri() throws URISyntaxException {
563        CookieStore cookieStore = new CookieManager().getCookieStore();
564        HttpCookie cookieA = createCookie("a", "android", ".android.com", "/source/");
565        cookieStore.add(new URI("http://google.com/source/"), cookieA);
566        assertEquals(Arrays.asList(cookieA), cookieStore.getCookies());
567    }
568
569    public void testCookieStoreRemoveRequiresUri() throws URISyntaxException {
570        CookieStore cookieStore = new CookieManager(createCookieStore(), null).getCookieStore();
571        HttpCookie cookieA = new HttpCookie("a", "android");
572        cookieStore.add(new URI("http://android.com/source/"), cookieA);
573        assertFalse("Expected remove() to take the cookie URI into account.", // RI6 fails this
574                cookieStore.remove(new URI("http://code.google.com/"), cookieA));
575        assertEquals(Arrays.asList(cookieA), cookieStore.getCookies());
576    }
577
578    public void testCookieStoreUriUsesHttpSchemeAlways() throws URISyntaxException {
579        CookieStore cookieStore = new CookieManager(createCookieStore(), null).getCookieStore();
580        cookieStore.add(new URI("https://a.com/"), new HttpCookie("a", "android"));
581        assertEquals(Arrays.asList(new URI("http://a.com")), cookieStore.getURIs());
582    }
583
584    public void testCookieStoreUriDropsUserInfo() throws URISyntaxException {
585        CookieStore cookieStore = new CookieManager(createCookieStore(), null).getCookieStore();
586        cookieStore.add(new URI("http://jesse:secret@a.com/"), new HttpCookie("a", "android"));
587        assertEquals(Arrays.asList(new URI("http://a.com")), cookieStore.getURIs());
588    }
589
590    public void testCookieStoreUriKeepsHost() throws URISyntaxException {
591        CookieStore cookieStore = new CookieManager(createCookieStore(), null).getCookieStore();
592        cookieStore.add(new URI("http://b.com/"), new HttpCookie("a", "android"));
593        assertEquals(Arrays.asList(new URI("http://b.com")), cookieStore.getURIs());
594    }
595
596    public void testCookieStoreUriDropsPort() throws URISyntaxException {
597        CookieStore cookieStore = new CookieManager(createCookieStore(), null).getCookieStore();
598        cookieStore.add(new URI("http://a.com:443/"), new HttpCookie("a", "android"));
599        assertEquals(Arrays.asList(new URI("http://a.com")), cookieStore.getURIs());
600    }
601
602    public void testCookieStoreUriDropsPath() throws URISyntaxException {
603        CookieStore cookieStore = new CookieManager(createCookieStore(), null).getCookieStore();
604        cookieStore.add(new URI("http://a.com/a/"), new HttpCookie("a", "android"));
605        assertEquals(Arrays.asList(new URI("http://a.com")), cookieStore.getURIs());
606    }
607
608    public void testCookieStoreUriDropsFragment() throws URISyntaxException {
609        CookieStore cookieStore = new CookieManager(createCookieStore(), null).getCookieStore();
610        cookieStore.add(new URI("http://a.com/a/foo#fragment"), new HttpCookie("a", "android"));
611        assertEquals(Arrays.asList(new URI("http://a.com")), cookieStore.getURIs());
612    }
613
614    public void testCookieStoreUriDropsQuery() throws URISyntaxException {
615        CookieStore cookieStore = new CookieManager(createCookieStore(), null).getCookieStore();
616        cookieStore.add(new URI("http://a.com/a/foo?query=value"), new HttpCookie("a", "android"));
617        assertEquals(Arrays.asList(new URI("http://a.com")), cookieStore.getURIs());
618    }
619
620    public void testCookieStoreGet() throws Exception {
621        CookieStore cookieStore = new CookieManager(createCookieStore(), null).getCookieStore();
622        HttpCookie cookiePort1 = createCookie("a1", "android", "a.com", "/path1");
623        HttpCookie cookiePort2 = createCookie("a2", "android", "a.com", "/path2");
624        HttpCookie secureCookie = createCookie("a3", "android", "a.com", "/path3");
625        secureCookie.setSecure(true);
626        HttpCookie notSecureCookie = createCookie("a4", "android", "a.com", "/path4");
627
628        HttpCookie bCookie = createCookie("b1", "android", "b.com", "/path5");
629
630        cookieStore.add(new URI("http://a.com:443/path1"), cookiePort1);
631        cookieStore.add(new URI("http://a.com:8080/path2"), cookiePort2);
632        cookieStore.add(new URI("https://a.com:443/path3"), secureCookie);
633        cookieStore.add(new URI("https://a.com:443/path4"), notSecureCookie);
634        cookieStore.add(new URI("https://b.com:8080/path5"), bCookie);
635
636        List<HttpCookie> expectedStoreCookies = new ArrayList<>();
637        expectedStoreCookies.add(cookiePort1);
638        expectedStoreCookies.add(cookiePort2);
639        expectedStoreCookies.add(secureCookie);
640        expectedStoreCookies.add(notSecureCookie);
641
642        // The default CookieStore implementation on Android is currently responsible for matching
643        // the host/domain but not handling other cookie rules: it ignores the scheme (e.g. "secure"
644        // checks), port and path.
645        // The tests below fail on the RI. It looks like in the RI it is CookieStoreImpl that is
646        // enforcing "secure" checks.
647        assertEquals(expectedStoreCookies, cookieStore.get(new URI("http://a.com:443/anypath")));
648        assertEquals(expectedStoreCookies, cookieStore.get(new URI("http://a.com:8080/anypath")));
649        assertEquals(expectedStoreCookies, cookieStore.get(new URI("https://a.com/anypath")));
650        assertEquals(expectedStoreCookies, cookieStore.get(new URI("http://a.com/anypath")));
651    }
652
653    /**
654     * Regression test for http://b/25682357 /
655     * https://code.google.com/p/android/issues/detail?id=193475
656     * CookieStoreImpl.get(URI) not handling ports properly in the absence of an explicit cookie
657     * Domain.
658     */
659    public void testCookieStoreGetWithPort() throws Exception {
660        CookieStore cookieStore = new CookieManager(createCookieStore(), null).getCookieStore();
661        HttpCookie cookie = new HttpCookie("theme", "light");
662        // Deliberately not setting the cookie domain or path.
663        cookieStore.add(new URI("http://a.com:12345"), cookie);
664
665        // CookieStoreImpl must ignore the port during retrieval when domain is not set.
666        assertEquals(1, cookieStore.get(new URI("http://a.com:12345/path1")).size());
667        assertEquals(1, cookieStore.get(new URI("http://a.com/path1")).size());
668    }
669
670    public void testCookieStoreGetWithSecure() throws Exception {
671        CookieStore cookieStore = new CookieManager(createCookieStore(), null).getCookieStore();
672        HttpCookie cookie = createCookie("theme", "light", "a.com", "/path");
673        cookie.setSecure(true);
674        cookieStore.add(new URI("https://a.com/path"), cookie);
675
676        // CookieStoreImpl on Android ignores the "Secure" attribute. The RI implements the secure
677        // check in CookieStoreImpl. For safety / app compatibility, if this is changed Android
678        // should probably implement it in both places.
679        assertEquals(1, cookieStore.get(new URI("http://a.com/path")).size());
680        assertEquals(1, cookieStore.get(new URI("https://a.com/path")).size());
681    }
682
683    public void testCookieStoreEviction() throws Exception {
684        CookieStore cookieStore = new CookieManager(createCookieStore(), null).getCookieStore();
685        HttpCookie themeCookie = createCookie("theme", "light", "a.com", "/");
686        cookieStore.add(new URI("http://a.com/"), themeCookie);
687
688        HttpCookie sidCookie = createCookie("sid", "mysid", "a.com", "/");
689        cookieStore.add(new URI("http://a.com/"), sidCookie);
690
691        HttpCookie replacementThemeCookie = createCookie("theme", "dark", "a.com", "/");
692        cookieStore.add(new URI("http://a.com/"), replacementThemeCookie);
693
694        // toString() is used below to avoid confusion with assertEquals():
695        // HttpCookie.equals() is implemented so that it only checks name, path and domain
696        // attributes but we also want to check the value.
697        assertEquals(
698                "[sid=\"mysid\";$Path=\"/\";$Domain=\"a.com\", "
699                        + "theme=\"dark\";$Path=\"/\";$Domain=\"a.com\"]",
700                cookieStore.get(new URI("http://a.com/")).toString());
701
702        HttpCookie replacementSidCookie = createCookie("sid", "mynewsid", "A.cOm", "/");
703        cookieStore.add(new URI("http://a.com/"), replacementSidCookie);
704
705        assertEquals(
706                "[theme=\"dark\";$Path=\"/\";$Domain=\"a.com\", "
707                        + "sid=\"mynewsid\";$Path=\"/\";$Domain=\"a.com\"]",
708                cookieStore.get(new URI("http://a.com/")).toString());
709    }
710
711    /**
712     * CookieStoreImpl has a strict requirement on HttpCookie.equals() to enable replacement of
713     * cookies with the same name.
714     */
715    public void testCookieEquality() throws Exception {
716        HttpCookie baseCookie = createCookie("theme", "light", "a.com", "/");
717
718        // None of the attributes immediately below should affect equality otherwise CookieStoreImpl
719        // eviction will not work as intended.
720        HttpCookie valueCookie = createCookie("theme", "light", "a.com", "/");
721        valueCookie.setValue("dark");
722        valueCookie.setPortlist("1234");
723        valueCookie.setSecure(true);
724        valueCookie.setComment("comment");
725        valueCookie.setCommentURL("commentURL");
726        valueCookie.setDiscard(true);
727        valueCookie.setMaxAge(12345L);
728        valueCookie.setVersion(1);
729        assertEquals(baseCookie, valueCookie);
730
731        // Changing any of the 3 main identity attributes should render cookies unequal.
732        assertNotEquals(createCookie("theme2", "light", "a.com", "/"), baseCookie);
733        assertNotEquals(createCookie("theme", "light", "b.com", "/"), baseCookie);
734        assertNotEquals(createCookie("theme", "light", "a.com", "/path"), baseCookie);
735    }
736
737    private static void assertNotEquals(HttpCookie one, HttpCookie two) {
738        assertFalse(one.equals(two));
739        assertFalse(two.equals(one));
740    }
741
742    private void assertContains(Collection<String> collection, String element) {
743        for (String c : collection) {
744            if (c != null && c.equalsIgnoreCase(element)) {
745                return;
746            }
747        }
748        fail("No " + element + " in " + collection);
749    }
750
751    private void assertContainsAll(Collection<String> collection, String... toFind) {
752        for (String s : toFind) {
753            assertContains(collection, s);
754        }
755    }
756
757    private List<HttpCookie> sortedCopy(List<HttpCookie> cookies) {
758        List<HttpCookie> result = new ArrayList<HttpCookie>(cookies);
759        Collections.sort(result, new Comparator<HttpCookie>() {
760            public int compare(HttpCookie a, HttpCookie b) {
761                return a.getName().compareTo(b.getName());
762            }
763        });
764        return result;
765    }
766
767    private Map<String,List<String>> get(MockWebServer server, String path) throws Exception {
768        URLConnection connection = server.getUrl(path).openConnection();
769        Map<String, List<String>> headers = connection.getHeaderFields();
770        connection.getInputStream().close();
771        return headers;
772    }
773
774    private static Map<String, List<String>> cookieHeaders(String... headers) {
775        return Collections.singletonMap("Set-Cookie", Arrays.asList(headers));
776    }
777
778    static class TestCookieStore implements CookieStore {
779        private final List<HttpCookie> cookies = new ArrayList<HttpCookie>();
780
781        public void add(URI uri, HttpCookie cookie) {
782            cookies.add(cookie);
783        }
784
785        public HttpCookie getCookie(String name) {
786            for (HttpCookie cookie : cookies) {
787                if (cookie.getName().equals(name)) {
788                    return cookie;
789                }
790            }
791            throw new IllegalArgumentException("No cookie " + name + " in " + cookies);
792        }
793
794        public List<HttpCookie> get(URI uri) {
795            throw new UnsupportedOperationException();
796        }
797
798        public List<HttpCookie> getCookies() {
799            throw new UnsupportedOperationException();
800        }
801
802        public List<URI> getURIs() {
803            throw new UnsupportedOperationException();
804        }
805
806        public boolean remove(URI uri, HttpCookie cookie) {
807            throw new UnsupportedOperationException();
808        }
809
810        public boolean removeAll() {
811            throw new UnsupportedOperationException();
812        }
813    }
814
815    private static void assertManagerCookiesMatch(CookieManager cookieManager, String url,
816        String expectedCookieRequestHeader) throws Exception {
817
818        Map<String, List<String>> cookieHeaders =
819                cookieManager.get(new URI(url), EMPTY_COOKIES_MAP);
820        if (expectedCookieRequestHeader == null) {
821            assertTrue(cookieHeaders.isEmpty());
822            return;
823        }
824
825        assertEquals(1, cookieHeaders.size());
826        List<String> actualCookieHeaderStrings = cookieHeaders.get("Cookie");
827
828        // For simplicity, we concatenate the cookie header strings if there are multiple ones.
829        String actualCookieRequestHeader = actualCookieHeaderStrings.get(0);
830        for (int i = 1; i < actualCookieHeaderStrings.size(); i++) {
831            actualCookieRequestHeader += "; " + actualCookieHeaderStrings.get(i);
832        }
833        assertEquals(expectedCookieRequestHeader, actualCookieRequestHeader);
834    }
835
836    /**
837     * Creates a well-formed cookie. The behavior when domain is unset varies between
838     * RFC 2965 and RFC 6265. CookieStoreImpl assumes these values are set "correctly" by the time
839     * it receives the HttpCookie instance.
840     */
841    private static HttpCookie createCookie(String name, String value, String domain, String path) {
842        HttpCookie cookie = new HttpCookie(name, value);
843        cookie.setDomain(domain);
844        cookie.setPath(path);
845        return cookie;
846    }
847
848    //
849    // Start of org.apache.harmony.tests.java.net.CookieManagerTest.
850    //
851
852    /**
853     * java.net.CookieStore#add(URI, HttpCookie)
854     * @since 1.6
855     */
856    public void test_add_LURI_LHttpCookie() throws URISyntaxException {
857        URI uri = new URI("http://harmony.test.unit.org");
858        HttpCookie cookie = new HttpCookie("name1", "value1");
859        cookie.setDiscard(true);
860
861        // This needn't throw. We should use the cookie's domain, if set.
862        // If no domain is set, this cookie will languish in the store until
863        // it expires.
864        cookieStore.add(null, cookie);
865
866        try {
867            cookieStore.add(uri, null);
868            fail("should throw NullPointerException");
869        } catch (NullPointerException e) {
870            // expected
871        }
872
873        try {
874            cookieStore.add(null, null);
875            fail("should throw NullPointerException");
876        } catch (NullPointerException e) {
877            // expected
878        }
879
880        cookieStore.add(uri, cookie);
881        List<HttpCookie> list = cookieStore.get(uri);
882        assertEquals(1, list.size());
883        assertTrue(list.contains(cookie));
884
885        HttpCookie cookie2 = new HttpCookie("  NaME1   ", "  TESTVALUE1   ");
886        cookieStore.add(uri, cookie2);
887        list = cookieStore.get(uri);
888        assertEquals(1, list.size());
889        assertEquals("  TESTVALUE1   ", list.get(0).getValue());
890        assertTrue(list.contains(cookie2));
891
892        // domain and path attributes works
893        HttpCookie anotherCookie = new HttpCookie("name1", "value1");
894        anotherCookie.setDomain("domain");
895        anotherCookie.setPath("Path");
896        cookieStore.add(uri, anotherCookie);
897        list = cookieStore.get(uri);
898        assertEquals(2, list.size());
899        assertNull(list.get(0).getDomain());
900        assertEquals("domain", list.get(1).getDomain());
901        assertEquals("Path", list.get(1).getPath());
902
903        URI uri2 = new URI("http://.test.unit.org");
904        HttpCookie cookie3 = new HttpCookie("NaME2", "VALUE2");
905        cookieStore.add(uri2, cookie3);
906        list = cookieStore.get(uri2);
907        assertEquals(1, list.size());
908        assertEquals("VALUE2", list.get(0).getValue());
909        list = cookieStore.getCookies();
910        assertEquals(3, list.size());
911
912        // expired cookie won't be selected.
913        HttpCookie cookie4 = new HttpCookie("cookie4", "value4");
914        cookie4.setMaxAge(-2);
915        assertTrue(cookie4.hasExpired());
916        cookieStore.add(uri2, cookie4);
917        list = cookieStore.getCookies();
918        assertEquals(3, list.size());
919        assertFalse(cookieStore.remove(uri2, cookie4));
920
921        cookie4.setMaxAge(3000);
922        cookie4.setDomain("domain");
923        cookie4.setPath("path");
924        cookieStore.add(uri2, cookie4);
925        list = cookieStore.get(uri2);
926        assertEquals(2, list.size());
927
928        cookieStore.add(uri, cookie4);
929        list = cookieStore.get(uri);
930        assertEquals(3, list.size());
931        list = cookieStore.get(uri2);
932        assertEquals(2, list.size());
933        list = cookieStore.getCookies();
934        assertEquals(4, list.size());
935
936        URI baduri = new URI("bad_url");
937        HttpCookie cookie6 = new HttpCookie("cookie5", "value5");
938        cookieStore.add(baduri, cookie6);
939        list = cookieStore.get(baduri);
940        assertTrue(list.contains(cookie6));
941    }
942
943    /**
944     * java.net.CookieStore#get(URI)
945     * @since 1.6
946     */
947    public void test_get_LURI() throws URISyntaxException {
948        try {
949            cookieStore.get(null);
950            fail("should throw NullPointerException");
951        } catch (NullPointerException e) {
952            // expected
953        }
954
955        URI uri1 = new URI("http://get.uri1.test.org");
956        List<HttpCookie> list = cookieStore.get(uri1);
957        assertTrue(list.isEmpty());
958
959        HttpCookie cookie1 = new HttpCookie("cookie_name1", "cookie_value1");
960        HttpCookie cookie2 = new HttpCookie("cookie_name2", "cookie_value2");
961        cookieStore.add(uri1, cookie1);
962        cookieStore.add(uri1, cookie2);
963        URI uri2 = new URI("http://get.uri2.test.org");
964        HttpCookie cookie3 = new HttpCookie("cookie_name3", "cookie_value3");
965        cookieStore.add(uri2, cookie3);
966        list = cookieStore.get(uri1);
967        assertEquals(2, list.size());
968        list = cookieStore.get(uri2);
969        assertEquals(1, list.size());
970
971        // domain-match cookies also be selected.
972        HttpCookie cookie4 = new HttpCookie("cookie_name4", "cookie_value4");
973        cookie4.setDomain(".uri1.test.org");
974        cookieStore.add(uri2, cookie4);
975        list = cookieStore.get(uri1);
976        assertEquals(3, list.size());
977
978        cookieStore.add(uri1, cookie4);
979        list = cookieStore.get(uri1);
980        assertEquals(3, list.size());
981        list = cookieStore.get(uri2);
982        assertEquals(2, list.size());
983
984        // expired cookie won't be selected.
985        HttpCookie cookie5 = new HttpCookie("cookie_name5", "cookie_value5");
986        cookie5.setMaxAge(-333);
987        assertTrue(cookie5.hasExpired());
988        cookieStore.add(uri1, cookie5);
989        list = cookieStore.get(uri1);
990        assertEquals(3, list.size());
991        assertFalse(cookieStore.remove(uri1, cookie5));
992        list = cookieStore.getCookies();
993        assertEquals(4, list.size());
994
995        cookie4.setMaxAge(-123);
996        list = cookieStore.get(uri1);
997        assertEquals(2, list.size());
998        list = cookieStore.getCookies();
999        assertEquals(3, list.size());
1000        // expired cookies are also deleted even if it domain-matches the URI
1001        HttpCookie cookie6 = new HttpCookie("cookie_name6", "cookie_value6");
1002        cookie6.setMaxAge(-2);
1003        cookie6.setDomain(".uri1.test.org");
1004        cookieStore.add(uri2, cookie6);
1005        list = cookieStore.get(uri1);
1006        assertEquals(2, list.size());
1007        assertFalse(cookieStore.remove(null, cookie6));
1008
1009        URI uri3 = new URI("http://get.uri3.test.org");
1010        assertTrue(cookieStore.get(uri3).isEmpty());
1011        URI baduri = new URI("invalid_uri");
1012        assertTrue(cookieStore.get(baduri).isEmpty());
1013    }
1014
1015    /**
1016     * java.net.CookieStore#getCookies()
1017     * @since 1.6
1018     */
1019    public void test_getCookies() throws URISyntaxException {
1020        List<HttpCookie> list = cookieStore.getCookies();
1021        assertTrue(list.isEmpty());
1022        assertTrue(list instanceof RandomAccess);
1023
1024        HttpCookie cookie1 = new HttpCookie("cookie_name", "cookie_value");
1025        URI uri1 = new URI("http://getcookies1.test.org");
1026        cookieStore.add(uri1, cookie1);
1027        list = cookieStore.getCookies();
1028        assertTrue(list.contains(cookie1));
1029
1030        HttpCookie cookie2 = new HttpCookie("cookie_name2", "cookie_value2");
1031        URI uri2 = new URI("http://getcookies2.test.org");
1032        cookieStore.add(uri2, cookie2);
1033        list = cookieStore.getCookies();
1034        assertEquals(2, list.size());
1035        assertTrue(list.contains(cookie1));
1036        assertTrue(list.contains(cookie2));
1037
1038        // duplicated cookie won't be selected.
1039        cookieStore.add(uri2, cookie1);
1040        list = cookieStore.getCookies();
1041        assertEquals(2, list.size());
1042        // expired cookie won't be selected.
1043        HttpCookie cookie3 = new HttpCookie("cookie_name3", "cookie_value3");
1044        cookie3.setMaxAge(-1357);
1045        cookieStore.add(uri1, cookie3);
1046        list = cookieStore.getCookies();
1047        assertEquals(2, list.size());
1048
1049        try {
1050            list.add(new HttpCookie("readOnlyName", "readOnlyValue"));
1051            fail("should throw UnsupportedOperationException");
1052        } catch (UnsupportedOperationException e) {
1053            // expected
1054        }
1055
1056        try {
1057            list.remove(new HttpCookie("readOnlyName", "readOnlyValue"));
1058            fail("should throw UnsupportedOperationException");
1059        } catch (UnsupportedOperationException e) {
1060            // expected
1061        }
1062    }
1063
1064    /**
1065     * java.net.CookieStore#getURIs()
1066     * @since 1.6
1067     */
1068    public void test_getURIs() throws URISyntaxException {
1069        List<URI> list = cookieStore.getURIs();
1070        assertTrue(list.isEmpty());
1071
1072        URI uri1 = new URI("http://geturis1.test.com");
1073        HttpCookie cookie1 = new HttpCookie("cookie_name1", "cookie_value1");
1074        cookieStore.add(uri1, cookie1);
1075        list = cookieStore.getURIs();
1076        assertEquals("geturis1.test.com", list.get(0).getHost());
1077
1078        HttpCookie cookie2 = new HttpCookie("cookie_name2", "cookie_value2");
1079        cookieStore.add(uri1, cookie2);
1080        list = cookieStore.getURIs();
1081        assertEquals(1, list.size());
1082
1083        URI uri2 = new URI("http://geturis2.test.com");
1084        cookieStore.add(uri2, cookie2);
1085        list = cookieStore.getURIs();
1086        assertEquals(2, list.size());
1087        assertTrue(list.contains(uri1));
1088        assertTrue(list.contains(uri2));
1089    }
1090
1091    /**
1092     * java.net.CookieStore#remove(URI, HttpCookie)
1093     * @since 1.6
1094     */
1095    public void test_remove_LURI_LHttpCookie() throws URISyntaxException {
1096        URI uri1 = new URI("http://remove1.test.com");
1097        HttpCookie cookie1 = new HttpCookie("cookie_name1", "cookie_value1");
1098        try {
1099            cookieStore.remove(uri1, null);
1100            fail("should throw NullPointerException");
1101        } catch (NullPointerException e) {
1102            // expected
1103        }
1104        assertFalse(cookieStore.remove(uri1, cookie1));
1105        assertFalse(cookieStore.remove(null, cookie1));
1106
1107        cookieStore.add(uri1, cookie1);
1108        URI uri2 = new URI("http://remove2.test.com");
1109        HttpCookie cookie2 = new HttpCookie("cookie_name2", "cookie_value2");
1110        cookieStore.add(uri2, cookie2);
1111        assertTrue(cookieStore.remove(uri1, cookie1));
1112        assertFalse(cookieStore.remove(uri1, cookie1));
1113        assertEquals(2, cookieStore.getURIs().size());
1114        assertEquals(1, cookieStore.getCookies().size());
1115        assertTrue(cookieStore.remove(uri2, cookie2));
1116        assertFalse(cookieStore.remove(uri2, cookie2));
1117        assertEquals(2, cookieStore.getURIs().size());
1118        assertEquals(0, cookieStore.getCookies().size());
1119
1120        assertTrue(cookieStore.removeAll());
1121        cookieStore.add(uri1, cookie1);
1122        cookieStore.add(uri2, cookie2);
1123        HttpCookie cookie3 = new HttpCookie("cookie_name3", "cookie_value3");
1124        assertFalse(cookieStore.remove(null, cookie3));
1125        // No guarantees on behavior if we call remove with a different
1126        // uri from the one originally associated with the cookie.
1127        assertFalse(cookieStore.remove(null, cookie1));
1128        assertTrue(cookieStore.remove(uri1, cookie1));
1129        assertFalse(cookieStore.remove(uri1, cookie1));
1130
1131        assertEquals(2, cookieStore.getURIs().size());
1132        assertEquals(1, cookieStore.getCookies().size());
1133        assertTrue(cookieStore.remove(uri2, cookie2));
1134        assertFalse(cookieStore.remove(uri2, cookie2));
1135        assertEquals(2, cookieStore.getURIs().size());
1136        assertEquals(0, cookieStore.getCookies().size());
1137
1138        cookieStore.removeAll();
1139        // expired cookies can also be deleted.
1140        cookie2.setMaxAge(-34857);
1141        cookieStore.add(uri2, cookie2);
1142        assertTrue(cookieStore.remove(uri2, cookie2));
1143        assertFalse(cookieStore.remove(uri2, cookie2));
1144        assertEquals(0, cookieStore.getCookies().size());
1145
1146        cookie2.setMaxAge(34857);
1147        cookieStore.add(uri1, cookie1);
1148        cookieStore.add(uri2, cookie1);
1149        cookieStore.add(uri2, cookie2);
1150        assertTrue(cookieStore.remove(uri1, cookie1));
1151        assertFalse(cookieStore.remove(uri1, cookie1));
1152        assertTrue(cookieStore.get(uri2).contains(cookie1));
1153        assertTrue(cookieStore.get(uri2).contains(cookie2));
1154        assertEquals(0, cookieStore.get(uri1).size());
1155        cookieStore.remove(uri2, cookie2);
1156
1157        cookieStore.removeAll();
1158        cookieStore.add(uri2, cookie2);
1159        cookieStore.add(uri1, cookie1);
1160        assertEquals(2, cookieStore.getCookies().size());
1161        assertFalse(cookieStore.remove(uri2, cookie1));
1162        assertTrue(cookieStore.remove(uri1, cookie1));
1163        assertEquals(2, cookieStore.getURIs().size());
1164        assertEquals(1, cookieStore.getCookies().size());
1165        assertTrue(cookieStore.getCookies().contains(cookie2));
1166
1167        cookieStore.removeAll();
1168        URI uri3 = new URI("http://remove3.test.com");
1169        URI uri4 = new URI("http://test.com");
1170        HttpCookie cookie4 = new HttpCookie("cookie_name4", "cookie_value4");
1171        cookie4.setDomain(".test.com");
1172        cookie2.setMaxAge(-34857);
1173        cookie3.setMaxAge(-22);
1174        cookie4.setMaxAge(-45);
1175        cookieStore.add(uri1, cookie1);
1176        cookieStore.add(uri2, cookie2);
1177        cookieStore.add(uri3, cookie3);
1178        cookieStore.add(uri4, cookie4);
1179        assertEquals(0, cookieStore.get(uri2).size());
1180        assertFalse(cookieStore.remove(uri2, cookie2));
1181        assertTrue(cookieStore.remove(uri3, cookie3));
1182        assertFalse(cookieStore.remove(uri4, cookie4));
1183    }
1184
1185    /**
1186     * java.net.CookieStore#test_removeAll()
1187     * @since 1.6
1188     */
1189    public void test_removeAll() throws URISyntaxException {
1190        assertFalse(cookieStore.removeAll());
1191
1192        URI uri1 = new URI("http://removeAll1.test.com");
1193        HttpCookie cookie1 = new HttpCookie("cookie_name1", "cookie_value1");
1194        cookieStore.add(uri1, cookie1);
1195        URI uri2 = new URI("http://removeAll2.test.com");
1196        HttpCookie cookie2 = new HttpCookie("cookie_name2", "cookie_value2");
1197        cookieStore.add(uri2, cookie2);
1198
1199        assertTrue(cookieStore.removeAll());
1200        assertTrue(cookieStore.getURIs().isEmpty());
1201        assertTrue(cookieStore.getCookies().isEmpty());
1202
1203        assertFalse(cookieStore.removeAll());
1204    }
1205
1206    //
1207    // Start of org.apache.harmony.tests.java.net.CookieStoreTest.
1208    //
1209
1210    private void checkValidParams4Get(URI uri,
1211                                             Map<String, List<String>> map) throws IOException {
1212        CookieManager manager = new CookieManager(createCookieStore(), null);
1213        try {
1214            manager.get(uri, map);
1215            fail("Should throw IllegalArgumentException");
1216        } catch (IllegalArgumentException e) {
1217            // expected
1218        }
1219
1220    }
1221
1222    private void checkValidParams4Put(URI uri,
1223                                             Map<String, List<String>> map) throws IOException {
1224        CookieManager manager = new CookieManager(createCookieStore(), null);
1225        try {
1226            manager.put(uri, map);
1227            fail("Should throw IllegalArgumentException");
1228        } catch (IllegalArgumentException e) {
1229            // expected
1230        }
1231
1232    }
1233
1234    /**
1235     * {@link java.net.CookieManager#get(java.net.URI, java.util.Map)} &
1236     * {@link java.net.CookieManager#put(java.net.URI, java.util.Map)}
1237     * IllegalArgumentException
1238     * @since 1.6
1239     */
1240    public void test_Put_Get_LURI_LMap_exception() throws IOException,
1241            URISyntaxException {
1242        // get
1243        checkValidParams4Get(new URI(""), null);
1244        checkValidParams4Get(new URI("http://www.test.com"), null);
1245        checkValidParams4Get(null, null);
1246        checkValidParams4Get(null, new HashMap<String, List<String>>());
1247
1248        // put
1249        checkValidParams4Put(new URI(""), null);
1250        checkValidParams4Put(new URI("http://www.test.com"), null);
1251        checkValidParams4Put(null, null);
1252        checkValidParams4Put(null, new HashMap<String, List<String>>());
1253    }
1254
1255    private static Map<String, List<String>> addCookie(String[][] cookies) {
1256        Map<String, List<String>> responseHeaders = new LinkedHashMap<String, List<String>>();
1257        for (int i = 0; i < cookies.length; i++) {
1258            List<String> fields = new ArrayList<String>();
1259            for (int j = 1; j < cookies[i].length; j += 2) {
1260                fields.add(cookies[i][j]);
1261            }
1262            responseHeaders.put(cookies[i][0], fields);
1263        }
1264        return responseHeaders;
1265    }
1266
1267    private CookieManager store(String[][] cookies,
1268                                       Map<String, List<String>> responseHeaders, CookiePolicy policy)
1269            throws IOException, URISyntaxException {
1270        CookieManager manager = new CookieManager(createCookieStore(), policy);
1271        // Put all cookies into manager
1272        for (int i = 0; i < cookies.length; i++) {
1273            for (int j = 2; j < cookies[i].length; j += 2) {
1274                URI uri = new URI(cookies[i][j]);
1275                manager.put(uri, responseHeaders);
1276            }
1277        }
1278        return manager;
1279    }
1280
1281    /**
1282     * Unlike the RI, we flatten all matching cookies into a single Cookie header
1283     * instead of sending down multiple cookie headers. Also, when no cookies match
1284     * a given URI, we leave the requestHeaders unmodified.
1285     *
1286     * @since 1.6
1287     */
1288    public void test_Put_Get_LURI_LMap() throws IOException, URISyntaxException {
1289        // cookie-key | (content, URI)...
1290        String[][] cookies = {
1291                { "Set-cookie",
1292                        "Set-cookie:PREF=test;path=/;domain=.b.c;", "http://a.b.c/",
1293                        "Set-cookie:PREF1=test2;path=/;domain=.beg.com;", "http://a.b.c/" },
1294
1295                { "Set-cookie2",
1296                        "Set-cookie2:NAME1=VALUE1;path=/te;domain=.b.c;", "http://a.b.c/test" },
1297
1298                { "Set-cookie",
1299                        "Set-cookie2:NAME=VALUE;path=/;domain=.beg.com;", "http://a.beg.com/test",
1300                        "Set-cookie2:NAME1=VALUE1;path=/;domain=.beg.com;", "http://a.beg.com/test" },
1301
1302                { "Set-cookie2",
1303                        "Set-cookie3:NAME=VALUE;path=/;domain=.test.org;", "http://a.test.org/test" },
1304
1305                { null,
1306                        "Set-cookie3:NAME=VALUE;path=/te;domain=.test.org;", "http://a.test.org/test" },
1307
1308                { "Set-cookie2",
1309                        "lala", "http://a.test.org/test" }
1310
1311        };
1312
1313        // requires path of cookie is the prefix of uri
1314        // domain of cookie must match that of uri
1315        Map<String, List<String>> responseHeaders = addCookie(new String[][] {
1316                cookies[0], cookies[1] });
1317        CookieManager manager = store(
1318                new String[][] { cookies[0], cookies[1] }, responseHeaders,
1319                null);
1320
1321        HashMap<String, List<String>> dummyMap = new HashMap<String, List<String>>();
1322        Map<String, List<String>> map = manager.get(new URI("http://a.b.c/"),
1323                dummyMap);
1324
1325        assertEquals(1, map.size());
1326        List<String> list = map.get("Cookie");
1327        assertEquals(1, list.size());
1328
1329        // requires path of cookie is the prefix of uri
1330        map = manager.get(new URI("http://a.b.c/te"), dummyMap);
1331        list = map.get("Cookie");
1332        assertEquals(1, list.size());
1333        assertTrue(list.get(0).contains("PREF=test"));
1334        // Cookies from "/test" should *not* match the URI "/te".
1335        assertFalse(list.get(0).contains("NAME=VALUE"));
1336
1337        // If all cookies are of version 1, then $version=1 will be added
1338        // ,no matter the value cookie-key
1339        responseHeaders = addCookie(new String[][] { cookies[2] });
1340        manager = store(new String[][] { cookies[2] }, responseHeaders, null);
1341        map = manager.get(new URI("http://a.beg.com/test"), dummyMap);
1342        list = map.get("Cookie");
1343        assertEquals(1, list.size());
1344        assertTrue(list.get(0).startsWith("$Version=\"1\""));
1345
1346        // cookie-key will not have effect on determining cookie version
1347        responseHeaders = addCookie(new String[][] { cookies[3] });
1348        manager = store(new String[][] { cookies[3] }, responseHeaders, null);
1349        map = manager.get(new URI("http://a.test.org/"), responseHeaders);
1350        list = map.get("Cookie");
1351        assertEquals(1, list.size());
1352        assertEquals("Set-cookie3:NAME=VALUE", list.get(0));
1353
1354        // When key is null, no cookie can be stored/retrieved, even if policy =
1355        // ACCEPT_ALL
1356        responseHeaders = addCookie(new String[][] { cookies[4] });
1357        manager = store(new String[][] { cookies[4] }, responseHeaders,
1358                CookiePolicy.ACCEPT_ALL);
1359        map = manager.get(new URI("http://a.test.org/"), responseHeaders);
1360        list = map.get("Cookie");
1361        assertNull(list);
1362
1363        // All cookies will be rejected if policy == ACCEPT_NONE
1364        responseHeaders = addCookie(new String[][] { cookies[3] });
1365        manager = store(new String[][] { cookies[3] }, responseHeaders,
1366                CookiePolicy.ACCEPT_NONE);
1367        map = manager.get(new URI("http://a.test.org/"), responseHeaders);
1368        list = map.get("Cookie");
1369        assertNull(list);
1370
1371        responseHeaders = addCookie(new String[][] { cookies[5] });
1372        manager = store(new String[][] { cookies[5] }, responseHeaders,
1373                CookiePolicy.ACCEPT_ALL);
1374        list = map.get("Cookie");
1375        assertNull(list);
1376
1377        try {
1378            map.put(null, null);
1379            fail("Should throw UnsupportedOperationException");
1380        } catch (UnsupportedOperationException e) {
1381            // expected
1382        }
1383
1384    }
1385
1386    /**
1387     * {@link java.net.CookieManager#CookieManager()}
1388     * @since 1.6
1389     */
1390    public void test_CookieManager() {
1391        CookieManager cookieManager = new CookieManager();
1392        assertNotNull(cookieManager);
1393        assertNotNull(cookieManager.getCookieStore());
1394    }
1395
1396    /**
1397     * {@link java.net.CookieManager#CookieManager(java.net.CookieStore, java.net.CookiePolicy)}
1398     * @since 1.6
1399     */
1400    public void testCookieManager_LCookieStore_LCookiePolicy() {
1401        class DummyStore implements CookieStore {
1402            public String getName() {
1403                return "A dummy store";
1404            }
1405
1406            public void add(URI uri, HttpCookie cookie) {
1407                // expected
1408            }
1409
1410            public List<HttpCookie> get(URI uri) {
1411                return null;
1412            }
1413
1414            public List<HttpCookie> getCookies() {
1415                return null;
1416            }
1417
1418            public List<URI> getURIs() {
1419                return null;
1420            }
1421
1422            public boolean remove(URI uri, HttpCookie cookie) {
1423                return false;
1424            }
1425
1426            public boolean removeAll() {
1427                return false;
1428            }
1429        }
1430        CookieStore store = new DummyStore();
1431        CookieManager cookieManager = new CookieManager(store,
1432                CookiePolicy.ACCEPT_ALL);
1433        assertEquals("A dummy store", ((DummyStore) cookieManager
1434                .getCookieStore()).getName());
1435        assertSame(store, cookieManager.getCookieStore());
1436    }
1437
1438    /**
1439     * {@link java.net.CookieManager#setCookiePolicy(java.net.CookiePolicy)}
1440     * @since 1.6
1441     */
1442    public void test_SetCookiePolicy_LCookiePolicy() throws URISyntaxException,
1443            IOException {
1444
1445        // Policy = ACCEPT_NONE
1446        CookieManager manager = new CookieManager(createCookieStore(), null);
1447        manager.setCookiePolicy(CookiePolicy.ACCEPT_NONE);
1448        Map<String, List<String>> responseHeaders = new TreeMap<String, List<String>>();
1449        URI uri = new URI("http://a.b.c");
1450        manager.put(uri, responseHeaders);
1451        Map<String, List<String>> map = manager.get(uri,
1452                new HashMap<String, List<String>>());
1453
1454        assertEquals(0, map.size());
1455
1456        // Policy = ACCEPT_ALL
1457        manager.setCookiePolicy(CookiePolicy.ACCEPT_ALL);
1458        responseHeaders = new TreeMap<String, List<String>>();
1459        ArrayList<String> list = new ArrayList<String>();
1460        list.add("test=null");
1461        responseHeaders.put("Set-cookie", list);
1462        uri = new URI("http://b.c.d");
1463        manager.put(uri, responseHeaders);
1464        map = manager.get(uri, new HashMap<String, List<String>>());
1465        assertEquals(1, map.size());
1466    }
1467
1468    /**
1469     * {@link java.net.CookieManager#getCookieStore()}
1470     * @since 1.6
1471     */
1472    public void test_GetCookieStore() {
1473        CookieManager cookieManager = new CookieManager(createCookieStore(), null);
1474        CookieStore store = cookieManager.getCookieStore();
1475        assertNotNull(store);
1476    }
1477
1478    // http://b/25763487
1479    public void testCookieWithNullPath() throws Exception {
1480        FakeSingleCookieStore fscs = new FakeSingleCookieStore();
1481        CookieManager cm = new CookieManager(fscs, CookiePolicy.ACCEPT_ALL);
1482
1483        HttpCookie cookie = new HttpCookie("foo", "bar");
1484        cookie.setDomain("http://www.foo.com");
1485        cookie.setVersion(0);
1486
1487        fscs.setNextCookie(cookie);
1488
1489        Map<String, List<String>> cookieHeaders = cm.get(
1490                new URI("http://www.foo.com/log/me/in"), Collections.EMPTY_MAP);
1491
1492        List<String> cookies = cookieHeaders.get("Cookie");
1493        assertEquals("foo=bar", cookies.get(0));
1494    }
1495
1496    /**
1497     * A cookie store that always returns one cookie per URI (without any sort of
1498     * rule matching). The cookie that's returned is provided via a call to setNextCookie
1499     */
1500    public static class FakeSingleCookieStore implements CookieStore {
1501        private List<HttpCookie> cookies;
1502
1503        void setNextCookie(HttpCookie cookie) {
1504            cookies = Collections.singletonList(cookie);
1505        }
1506
1507        @Override
1508        public void add(URI uri, HttpCookie cookie) {
1509        }
1510
1511        @Override
1512        public List<HttpCookie> get(URI uri) {
1513            return cookies;
1514        }
1515
1516        @Override
1517        public List<HttpCookie> getCookies() {
1518            return cookies;
1519        }
1520
1521        @Override
1522        public List<URI> getURIs() {
1523            return null;
1524        }
1525
1526        @Override
1527        public boolean remove(URI uri, HttpCookie cookie) {
1528            cookies = Collections.EMPTY_LIST;
1529            return true;
1530        }
1531
1532        @Override
1533        public boolean removeAll() {
1534            cookies = Collections.EMPTY_LIST;
1535            return true;
1536        }
1537    }
1538}
1539