CookiesTest.java revision d9624e23a39f2ddf32dc51c3dabf60998567e762
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
17package libcore.java.net;
18
19import com.google.mockwebserver.MockResponse;
20import com.google.mockwebserver.MockWebServer;
21import com.google.mockwebserver.RecordedRequest;
22import java.io.IOException;
23import java.net.CookieHandler;
24import java.net.CookieManager;
25import static java.net.CookiePolicy.ACCEPT_ORIGINAL_SERVER;
26import java.net.CookieStore;
27import java.net.HttpCookie;
28import java.net.HttpURLConnection;
29import java.net.URI;
30import java.net.URISyntaxException;
31import java.net.URLConnection;
32import java.util.ArrayList;
33import java.util.Arrays;
34import java.util.Collection;
35import java.util.Collections;
36import java.util.Comparator;
37import java.util.HashMap;
38import java.util.List;
39import java.util.Locale;
40import java.util.Map;
41import junit.framework.TestCase;
42
43public class CookiesTest extends TestCase {
44
45    private static final Map<String, List<String>> EMPTY_COOKIES_MAP = Collections.emptyMap();
46
47    public void testNetscapeResponse() throws Exception {
48        CookieManager cookieManager = new CookieManager(null, ACCEPT_ORIGINAL_SERVER);
49        CookieHandler.setDefault(cookieManager);
50        MockWebServer server = new MockWebServer();
51        server.play();
52
53        server.enqueue(new MockResponse().addHeader("Set-Cookie: a=android; "
54                + "expires=Fri, 31-Dec-9999 23:59:59 GMT; "
55                + "path=/path; "
56                + "domain=.local; "
57                + "secure"));
58        get(server, "/path/foo");
59
60        List<HttpCookie> cookies = cookieManager.getCookieStore().getCookies();
61        assertEquals(1, cookies.size());
62        HttpCookie cookie = cookies.get(0);
63        assertEquals("a", cookie.getName());
64        assertEquals("android", cookie.getValue());
65        assertEquals(null, cookie.getComment());
66        assertEquals(null, cookie.getCommentURL());
67        assertEquals(false, cookie.getDiscard());
68        assertEquals(".local", cookie.getDomain());
69        assertTrue(cookie.getMaxAge() > 100000000000L);
70        assertEquals("/path", cookie.getPath());
71        assertEquals(true, cookie.getSecure());
72        assertEquals(0, cookie.getVersion());
73    }
74
75    public void testRfc2109Response() throws Exception {
76        CookieManager cookieManager = new CookieManager(null, ACCEPT_ORIGINAL_SERVER);
77        CookieHandler.setDefault(cookieManager);
78        MockWebServer server = new MockWebServer();
79        server.play();
80
81        server.enqueue(new MockResponse().addHeader("Set-Cookie: a=android; "
82                + "Comment=this cookie is delicious; "
83                + "Domain=.local; "
84                + "Max-Age=60; "
85                + "Path=/path; "
86                + "Secure; "
87                + "Version=1"));
88        get(server, "/path/foo");
89
90        List<HttpCookie> cookies = cookieManager.getCookieStore().getCookies();
91        assertEquals(1, cookies.size());
92        HttpCookie cookie = cookies.get(0);
93        assertEquals("a", cookie.getName());
94        assertEquals("android", cookie.getValue());
95        assertEquals("this cookie is delicious", cookie.getComment());
96        assertEquals(null, cookie.getCommentURL());
97        assertEquals(false, cookie.getDiscard());
98        assertEquals(".local", cookie.getDomain());
99        assertEquals(60, cookie.getMaxAge());
100        assertEquals("/path", cookie.getPath());
101        assertEquals(true, cookie.getSecure());
102        assertEquals(1, cookie.getVersion());
103    }
104
105    public void testRfc2965Response() throws Exception {
106        CookieManager cookieManager = new CookieManager(null, ACCEPT_ORIGINAL_SERVER);
107        CookieHandler.setDefault(cookieManager);
108        MockWebServer server = new MockWebServer();
109        server.play();
110
111        server.enqueue(new MockResponse().addHeader("Set-Cookie2: a=android; "
112                + "Comment=this cookie is delicious; "
113                + "CommentURL=http://google.com/; "
114                + "Discard; "
115                + "Domain=.local; "
116                + "Max-Age=60; "
117                + "Path=/path; "
118                + "Port=\"80,443," + server.getPort() + "\"; "
119                + "Secure; "
120                + "Version=1"));
121        get(server, "/path/foo");
122
123        List<HttpCookie> cookies = cookieManager.getCookieStore().getCookies();
124        assertEquals(1, cookies.size());
125        HttpCookie cookie = cookies.get(0);
126        assertEquals("a", cookie.getName());
127        assertEquals("android", cookie.getValue());
128        assertEquals("this cookie is delicious", cookie.getComment());
129        assertEquals("http://google.com/", cookie.getCommentURL());
130        assertEquals(true, cookie.getDiscard());
131        assertEquals(".local", cookie.getDomain());
132        assertEquals(60, cookie.getMaxAge());
133        assertEquals("/path", cookie.getPath());
134        assertEquals("80,443," + server.getPort(), cookie.getPortlist());
135        assertEquals(true, cookie.getSecure());
136        assertEquals(1, cookie.getVersion());
137    }
138
139    public void testQuotedAttributeValues() throws Exception {
140        CookieManager cookieManager = new CookieManager(null, ACCEPT_ORIGINAL_SERVER);
141        CookieHandler.setDefault(cookieManager);
142        MockWebServer server = new MockWebServer();
143        server.play();
144
145        server.enqueue(new MockResponse().addHeader("Set-Cookie2: a=\"android\"; "
146                + "Comment=\"this cookie is delicious\"; "
147                + "CommentURL=\"http://google.com/\"; "
148                + "Discard; "
149                + "Domain=\".local\"; "
150                + "Max-Age=\"60\"; "
151                + "Path=\"/path\"; "
152                + "Port=\"80,443," + server.getPort() + "\"; "
153                + "Secure; "
154                + "Version=\"1\""));
155        get(server, "/path/foo");
156
157        List<HttpCookie> cookies = cookieManager.getCookieStore().getCookies();
158        assertEquals(1, cookies.size());
159        HttpCookie cookie = cookies.get(0);
160        assertEquals("a", cookie.getName());
161        assertEquals("android", cookie.getValue());
162        assertEquals("this cookie is delicious", cookie.getComment());
163        assertEquals("http://google.com/", cookie.getCommentURL());
164        assertEquals(true, cookie.getDiscard());
165        assertEquals(".local", cookie.getDomain());
166        assertEquals(60, cookie.getMaxAge());
167        assertEquals("/path", cookie.getPath());
168        assertEquals("80,443," + server.getPort(), cookie.getPortlist());
169        assertEquals(true, cookie.getSecure());
170        assertEquals(1, cookie.getVersion());
171    }
172
173    public void testResponseWithMultipleCookieHeaderLines() throws Exception {
174        TestCookieStore cookieStore = new TestCookieStore();
175        CookieManager cookieManager = new CookieManager(cookieStore, ACCEPT_ORIGINAL_SERVER);
176        cookieManager.put(new URI("http://android.com"), cookieHeaders("a=android", "b=banana"));
177        List<HttpCookie> cookies = sortedCopy(cookieStore.cookies);
178        assertEquals(2, cookies.size());
179        HttpCookie cookieA = cookies.get(0);
180        assertEquals("a", cookieA.getName());
181        assertEquals("android", cookieA.getValue());
182        HttpCookie cookieB = cookies.get(1);
183        assertEquals("b", cookieB.getName());
184        assertEquals("banana", cookieB.getValue());
185    }
186
187    public void testDomainDefaulting() throws Exception {
188        TestCookieStore cookieStore = new TestCookieStore();
189        CookieManager cookieManager = new CookieManager(cookieStore, ACCEPT_ORIGINAL_SERVER);
190        cookieManager.put(new URI("http://android.com/"), cookieHeaders("a=android"));
191        assertEquals("android.com", cookieStore.getCookie("a").getDomain());
192    }
193
194    public void testNonMatchingDomainsRejected() throws Exception {
195        TestCookieStore cookieStore = new TestCookieStore();
196        CookieManager cookieManager = new CookieManager(cookieStore, ACCEPT_ORIGINAL_SERVER);
197        cookieManager.put(new URI("http://android.com/"),
198                cookieHeaders("a=android;domain=google.com"));
199        assertEquals(Collections.<HttpCookie>emptyList(), cookieStore.cookies);
200    }
201
202    public void testMatchingDomainsAccepted() throws Exception {
203        TestCookieStore cookieStore = new TestCookieStore();
204        CookieManager cookieManager = new CookieManager(cookieStore, ACCEPT_ORIGINAL_SERVER);
205        cookieManager.put(new URI("http://www.android.com/"),
206                cookieHeaders("a=android;domain=.android.com"));
207        assertEquals(".android.com", cookieStore.getCookie("a").getDomain());
208    }
209
210    public void testPathDefaulting() throws Exception {
211        TestCookieStore cookieStore = new TestCookieStore();
212        CookieManager cookieManager = new CookieManager(cookieStore, ACCEPT_ORIGINAL_SERVER);
213        cookieManager.put(new URI("http://android.com/foo/bar"), cookieHeaders("a=android"));
214        assertEquals("/foo/", cookieStore.getCookie("a").getPath());
215        cookieManager.put(new URI("http://android.com/"), cookieHeaders("b=banana"));
216        assertEquals("/", cookieStore.getCookie("b").getPath());
217        cookieManager.put(new URI("http://android.com/foo/"), cookieHeaders("c=carrot"));
218        assertEquals("/foo/", cookieStore.getCookie("c").getPath());
219    }
220
221    public void testNonMatchingPathsRejected() throws Exception {
222        TestCookieStore cookieStore = new TestCookieStore();
223        CookieManager cookieManager = new CookieManager(cookieStore, ACCEPT_ORIGINAL_SERVER);
224        cookieManager.put(new URI("http://android.com/foo/bar"),
225                cookieHeaders("a=android;path=/baz/bar"));
226        assertEquals("Expected to reject cookies whose path is not a prefix of the request path",
227                Collections.<HttpCookie>emptyList(), cookieStore.cookies); // RI6 fails this
228    }
229
230    public void testMatchingPathsAccepted() throws Exception {
231        TestCookieStore cookieStore = new TestCookieStore();
232        CookieManager cookieManager = new CookieManager(cookieStore, ACCEPT_ORIGINAL_SERVER);
233        cookieManager.put(new URI("http://android.com/foo/bar/"),
234                cookieHeaders("a=android;path=/foo"));
235        assertEquals("/foo", cookieStore.getCookie("a").getPath());
236    }
237
238    public void testNoCookieHeaderSentIfNoCookiesMatch() throws IOException, URISyntaxException {
239        CookieManager cookieManager = new CookieManager(null, ACCEPT_ORIGINAL_SERVER);
240        Map<String, List<String>> cookieHeaders = cookieManager.get(
241                new URI("http://android.com/foo/bar/"), EMPTY_COOKIES_MAP);
242        assertTrue(cookieHeaders.toString(), cookieHeaders.isEmpty()
243                || (cookieHeaders.size() == 1 && cookieHeaders.get("Cookie").isEmpty()));
244    }
245
246    public void testSendingCookiesFromStore() throws Exception {
247        MockWebServer server = new MockWebServer();
248        server.enqueue(new MockResponse());
249        server.play();
250
251        CookieManager cookieManager = new CookieManager(null, ACCEPT_ORIGINAL_SERVER);
252        HttpCookie cookieA = new HttpCookie("a", "android");
253        cookieA.setDomain(".local");
254        cookieA.setPath("/");
255        cookieManager.getCookieStore().add(server.getUrl("/").toURI(), cookieA);
256        HttpCookie cookieB = new HttpCookie("b", "banana");
257        cookieB.setDomain(".local");
258        cookieB.setPath("/");
259        cookieManager.getCookieStore().add(server.getUrl("/").toURI(), cookieB);
260        CookieHandler.setDefault(cookieManager);
261
262        get(server, "/");
263        RecordedRequest request = server.takeRequest();
264
265        List<String> receivedHeaders = request.getHeaders();
266        assertContains(receivedHeaders, "Cookie: $Version=\"1\"; "
267                + "a=\"android\";$Path=\"/\";$Domain=\".local\"; "
268                + "b=\"banana\";$Path=\"/\";$Domain=\".local\"");
269    }
270
271    public void testRedirectsDoNotIncludeTooManyCookies() throws Exception {
272        MockWebServer redirectTarget = new MockWebServer();
273        redirectTarget.enqueue(new MockResponse().setBody("A"));
274        redirectTarget.play();
275
276        MockWebServer redirectSource = new MockWebServer();
277        redirectSource.enqueue(new MockResponse()
278                .setResponseCode(HttpURLConnection.HTTP_MOVED_TEMP)
279                .addHeader("Location: " + redirectTarget.getUrl("/")));
280        redirectSource.play();
281
282        CookieManager cookieManager = new CookieManager(null, ACCEPT_ORIGINAL_SERVER);
283        HttpCookie cookie = new HttpCookie("c", "cookie");
284        cookie.setDomain(".local");
285        cookie.setPath("/");
286        String portList = Integer.toString(redirectSource.getPort());
287        cookie.setPortlist(portList);
288        cookieManager.getCookieStore().add(redirectSource.getUrl("/").toURI(), cookie);
289        CookieHandler.setDefault(cookieManager);
290
291        get(redirectSource, "/");
292        RecordedRequest request = redirectSource.takeRequest();
293
294        assertContains(request.getHeaders(), "Cookie: $Version=\"1\"; "
295                + "c=\"cookie\";$Path=\"/\";$Domain=\".local\";$Port=\"" + portList + "\"");
296
297        for (String header : redirectTarget.takeRequest().getHeaders()) {
298            if (header.startsWith("Cookie")) {
299                fail(header);
300            }
301        }
302    }
303
304    /**
305     * Test which headers show up where. The cookie manager should be notified
306     * of both user-specified and derived headers like {@code Host}. Headers
307     * named {@code Cookie} or {@code Cookie2} that are returned by the cookie
308     * manager should show up in the request and in {@code
309     * getRequestProperties}.
310     */
311    public void     testHeadersSentToCookieHandler() throws IOException, InterruptedException {
312        final Map<String, List<String>> cookieHandlerHeaders = new HashMap<String, List<String>>();
313        CookieHandler.setDefault(new CookieManager() {
314            @Override public Map<String, List<String>> get(URI uri,
315                    Map<String, List<String>> requestHeaders) throws IOException {
316                cookieHandlerHeaders.putAll(requestHeaders);
317                Map<String, List<String>> result = new HashMap<String, List<String>>();
318                result.put("Cookie", Collections.singletonList("Bar=bar"));
319                result.put("Cookie2", Collections.singletonList("Baz=baz"));
320                result.put("Quux", Collections.singletonList("quux"));
321                return result;
322            }
323        });
324        MockWebServer server = new MockWebServer();
325        server.enqueue(new MockResponse());
326        server.play();
327
328        HttpURLConnection connection = (HttpURLConnection) server.getUrl("/").openConnection();
329        assertEquals(Collections.<String, List<String>>emptyMap(),
330                connection.getRequestProperties());
331
332        connection.setRequestProperty("Foo", "foo");
333        connection.setDoOutput(true);
334        connection.getOutputStream().write(5);
335        connection.getOutputStream().close();
336        connection.getInputStream().close();
337
338        RecordedRequest request = server.takeRequest();
339
340        assertContainsAll(cookieHandlerHeaders.keySet(), "Foo");
341        assertContainsAll(cookieHandlerHeaders.keySet(),
342                "Content-Type", "User-Agent", "Connection", "Host");
343        assertFalse(cookieHandlerHeaders.containsKey("Cookie"));
344
345        /*
346         * The API specifies that calling getRequestProperties() on a connected instance should fail
347         * with an IllegalStateException, but the RI violates the spec and returns a valid map.
348         * http://www.mail-archive.com/net-dev@openjdk.java.net/msg01768.html
349         */
350        try {
351            assertContainsAll(connection.getRequestProperties().keySet(), "Foo");
352            assertContainsAll(connection.getRequestProperties().keySet(),
353                    "Content-Type", "Content-Length", "User-Agent", "Connection", "Host");
354            assertContainsAll(connection.getRequestProperties().keySet(), "Cookie", "Cookie2");
355            assertFalse(connection.getRequestProperties().containsKey("Quux"));
356        } catch (IllegalStateException expected) {
357        }
358
359        assertContainsAll(request.getHeaders(), "Foo: foo", "Cookie: Bar=bar", "Cookie2: Baz=baz");
360        assertFalse(request.getHeaders().contains("Quux: quux"));
361    }
362
363    public void testCookiesSentIgnoresCase() throws Exception {
364        CookieHandler.setDefault(new CookieManager() {
365            @Override public Map<String, List<String>> get(URI uri,
366                    Map<String, List<String>> requestHeaders) throws IOException {
367                Map<String, List<String>> result = new HashMap<String, List<String>>();
368                result.put("COOKIE", Collections.singletonList("Bar=bar"));
369                result.put("cooKIE2", Collections.singletonList("Baz=baz"));
370                return result;
371            }
372        });
373        MockWebServer server = new MockWebServer();
374        server. enqueue(new MockResponse());
375        server.play();
376
377        get(server, "/");
378
379        RecordedRequest request = server.takeRequest();
380        assertContainsAll(request.getHeaders(), "COOKIE: Bar=bar", "cooKIE2: Baz=baz");
381        assertFalse(request.getHeaders().contains("Quux: quux"));
382    }
383
384    /**
385     * RFC 2109 and RFC 2965 disagree here. 2109 says two equals strings match only if they are
386     * fully-qualified domain names. 2965 says two equal strings always match. We're testing for
387     * 2109 behavior because it's more widely used, it's more conservative, and it's what the RI
388     * does.
389     */
390    public void testDomainMatchesOnLocalAddresses() {
391        assertFalse(HttpCookie.domainMatches("localhost", "localhost"));
392        assertFalse(HttpCookie.domainMatches("b", "b"));
393    }
394
395    public void testDomainMatchesOnIpAddress() {
396        assertTrue(HttpCookie.domainMatches("127.0.0.1", "127.0.0.1"));
397        assertFalse(HttpCookie.domainMatches("127.0.0.1", "127.0.0.0"));
398        assertFalse(HttpCookie.domainMatches("127.0.0.1", "localhost"));
399    }
400
401    public void testDomainMatchesCaseMapping() {
402        testDomainMatchesCaseMapping(Locale.US);
403    }
404
405    public void testDomainMatchesCaseMappingExoticLocale() {
406        testDomainMatchesCaseMapping(new Locale("tr", "TR"));
407    }
408
409    private void testDomainMatchesCaseMapping(Locale locale) {
410        Locale defaultLocale = Locale.getDefault();
411        Locale.setDefault(locale);
412        try {
413            assertTrue(HttpCookie.domainMatches(".android.com", "WWW.ANDROID.COM"));
414            assertFalse(HttpCookie.domainMatches("android.com", "WWW.ANDROID.COM"));
415        } finally {
416            Locale.setDefault(defaultLocale);
417        }
418    }
419
420    /**
421     * From the spec, "If an explicitly specified value does not start with a dot, the user agent
422     * supplies a leading dot.". This prepending doesn't happen in setDomain.
423     */
424    public void testDomainNotAutomaticallyPrefixedWithDot() {
425        HttpCookie cookie = new HttpCookie("Foo", "foo");
426        cookie.setDomain("localhost");
427        assertEquals("localhost", cookie.getDomain());
428    }
429
430    public void testCookieStoreNullUris() {
431        CookieStore cookieStore = new CookieManager().getCookieStore();
432        HttpCookie cookieA = new HttpCookie("a", "android");
433        cookieA.setDomain(".android.com");
434        cookieA.setPath("/source");
435        HttpCookie cookieB = new HttpCookie("b", "banana");
436        cookieA.setDomain("code.google.com");
437        cookieA.setPath("/p/android");
438
439        try {
440            cookieStore.add(null, cookieA);
441        } catch (NullPointerException expected) {
442            // the RI crashes even though the cookie does get added to the store; sigh
443            expected.printStackTrace();
444        }
445        assertEquals(Arrays.asList(cookieA), cookieStore.getCookies());
446        try {
447            cookieStore.add(null, cookieB);
448        } catch (NullPointerException expected) {
449        }
450        assertEquals(Arrays.asList(cookieA, cookieB), cookieStore.getCookies());
451
452        try {
453            cookieStore.get(null);
454            fail();
455        } catch (NullPointerException expected) {
456        }
457
458        assertEquals(Collections.<URI>emptyList(), cookieStore.getURIs());
459        assertTrue(cookieStore.remove(null, cookieA));
460        assertEquals(Arrays.asList(cookieB), cookieStore.getCookies());
461
462        assertTrue(cookieStore.removeAll());
463        assertEquals(Collections.<URI>emptyList(), cookieStore.getURIs());
464        assertEquals(Collections.<HttpCookie>emptyList(), cookieStore.getCookies());
465    }
466
467    public void testCookieStoreRemoveAll() throws URISyntaxException {
468        CookieStore cookieStore = new CookieManager().getCookieStore();
469        cookieStore.add(new URI("http://code.google.com/"), new HttpCookie("a", "android"));
470        assertTrue(cookieStore.removeAll());
471        assertEquals(Collections.<URI>emptyList(), cookieStore.getURIs());
472        assertEquals(Collections.<HttpCookie>emptyList(), cookieStore.getCookies());
473        assertFalse("Expected removeAll() to return false when the call doesn't mutate the store",
474                cookieStore.removeAll());  // RI6 fails this
475    }
476
477    public void testCookieStoreAddAcceptsConflictingUri() throws URISyntaxException {
478        CookieStore cookieStore = new CookieManager().getCookieStore();
479        HttpCookie cookieA = new HttpCookie("a", "android");
480        cookieA.setDomain(".android.com");
481        cookieA.setPath("/source/");
482        cookieStore.add(new URI("http://google.com/source/"), cookieA);
483        assertEquals(Arrays.asList(cookieA), cookieStore.getCookies());
484    }
485
486    public void testCookieStoreRemoveRequiresUri() throws URISyntaxException {
487        CookieStore cookieStore = new CookieManager().getCookieStore();
488        HttpCookie cookieA = new HttpCookie("a", "android");
489        cookieStore.add(new URI("http://android.com/source/"), cookieA);
490        assertFalse("Expected remove() to take the cookie URI into account.", // RI6 fails this
491                cookieStore.remove(new URI("http://code.google.com/"), cookieA));
492        assertEquals(Arrays.asList(cookieA), cookieStore.getCookies());
493    }
494
495    public void testCookieStoreUriUsesHttpSchemeAlways() throws URISyntaxException {
496        CookieStore cookieStore = new CookieManager().getCookieStore();
497        cookieStore.add(new URI("https://a.com/"), new HttpCookie("a", "android"));
498        assertEquals(Arrays.asList(new URI("http://a.com")), cookieStore.getURIs());
499    }
500
501    public void testCookieStoreUriDropsUserInfo() throws URISyntaxException {
502        CookieStore cookieStore = new CookieManager().getCookieStore();
503        cookieStore.add(new URI("http://jesse:secret@a.com/"), new HttpCookie("a", "android"));
504        assertEquals(Arrays.asList(new URI("http://a.com")), cookieStore.getURIs());
505    }
506
507    public void testCookieStoreUriKeepsHost() throws URISyntaxException {
508        CookieStore cookieStore = new CookieManager().getCookieStore();
509        cookieStore.add(new URI("http://b.com/"), new HttpCookie("a", "android"));
510        assertEquals(Arrays.asList(new URI("http://b.com")), cookieStore.getURIs());
511    }
512
513    public void testCookieStoreUriDropsPort() throws URISyntaxException {
514        CookieStore cookieStore = new CookieManager().getCookieStore();
515        cookieStore.add(new URI("http://a.com:443/"), new HttpCookie("a", "android"));
516        assertEquals(Arrays.asList(new URI("http://a.com")), cookieStore.getURIs());
517    }
518
519    public void testCookieStoreUriDropsPath() throws URISyntaxException {
520        CookieStore cookieStore = new CookieManager().getCookieStore();
521        cookieStore.add(new URI("http://a.com/a/"), new HttpCookie("a", "android"));
522        assertEquals(Arrays.asList(new URI("http://a.com")), cookieStore.getURIs());
523    }
524
525    public void testCookieStoreUriDropsFragment() throws URISyntaxException {
526        CookieStore cookieStore = new CookieManager().getCookieStore();
527        cookieStore.add(new URI("http://a.com/a/foo#fragment"), new HttpCookie("a", "android"));
528        assertEquals(Arrays.asList(new URI("http://a.com")), cookieStore.getURIs());
529    }
530
531    public void testCookieStoreUriDropsQuery() throws URISyntaxException {
532        CookieStore cookieStore = new CookieManager().getCookieStore();
533        cookieStore.add(new URI("http://a.com/a/foo?query=value"), new HttpCookie("a", "android"));
534        assertEquals(Arrays.asList(new URI("http://a.com")), cookieStore.getURIs());
535    }
536
537    private void assertContains(Collection<String> collection, String element) {
538        for (String c : collection) {
539            if (c != null && c.equalsIgnoreCase(element)) {
540                return;
541            }
542        }
543        fail("No " + element + " in " + collection);
544    }
545
546    private void assertContainsAll(Collection<String> collection, String... toFind) {
547        for (String s : toFind) {
548            assertContains(collection, s);
549        }
550    }
551
552    private List<HttpCookie> sortedCopy(List<HttpCookie> cookies) {
553        List<HttpCookie> result = new ArrayList<HttpCookie>(cookies);
554        Collections.sort(result, new Comparator<HttpCookie>() {
555            public int compare(HttpCookie a, HttpCookie b) {
556                return a.getName().compareTo(b.getName());
557            }
558        });
559        return result;
560    }
561
562    private Map<String,List<String>> get(MockWebServer server, String path) throws Exception {
563        URLConnection connection = server.getUrl(path).openConnection();
564        Map<String, List<String>> headers = connection.getHeaderFields();
565        connection.getInputStream().close();
566        return headers;
567    }
568
569    private Map<String, List<String>> cookieHeaders(String... headers) {
570        return Collections.singletonMap("Set-Cookie", Arrays.asList(headers));
571    }
572
573    static class TestCookieStore implements CookieStore {
574        private final List<HttpCookie> cookies = new ArrayList<HttpCookie>();
575
576        public void add(URI uri, HttpCookie cookie) {
577            cookies.add(cookie);
578        }
579
580        public HttpCookie getCookie(String name) {
581            for (HttpCookie cookie : cookies) {
582                if (cookie.getName().equals(name)) {
583                    return cookie;
584                }
585            }
586            throw new IllegalArgumentException("No cookie " + name + " in " + cookies);
587        }
588
589        public List<HttpCookie> get(URI uri) {
590            throw new UnsupportedOperationException();
591        }
592
593        public List<HttpCookie> getCookies() {
594            throw new UnsupportedOperationException();
595        }
596
597        public List<URI> getURIs() {
598            throw new UnsupportedOperationException();
599        }
600
601        public boolean remove(URI uri, HttpCookie cookie) {
602            throw new UnsupportedOperationException();
603        }
604
605        public boolean removeAll() {
606            throw new UnsupportedOperationException();
607        }
608    }
609}
610