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