CookiesTest.java revision 9531eea15052eccc004b5f853ab4452becf7a8ab
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 java.io.IOException;
20import java.net.CookieHandler;
21import java.net.CookieManager;
22import static java.net.CookiePolicy.ACCEPT_ORIGINAL_SERVER;
23import java.net.CookieStore;
24import java.net.HttpCookie;
25import java.net.HttpURLConnection;
26import java.net.URI;
27import java.net.URISyntaxException;
28import java.net.URLConnection;
29import java.util.ArrayList;
30import java.util.Arrays;
31import java.util.Collection;
32import java.util.Collections;
33import java.util.Comparator;
34import java.util.HashMap;
35import java.util.List;
36import java.util.Locale;
37import java.util.Map;
38import junit.framework.TestCase;
39import tests.http.MockResponse;
40import tests.http.MockWebServer;
41import tests.http.RecordedRequest;
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 of both
306     * user-specified and derived headers like {@code Content-Length}. Headers named {@code Cookie}
307     * or {@code Cookie2} that are returned by the cookie manager should show up in the request and
308     * in {@code getRequestProperties}.
309     */
310    public void testHeadersSentToCookieHandler() throws IOException, InterruptedException {
311        final Map<String, List<String>> cookieHandlerHeaders = new HashMap<String, List<String>>();
312        CookieHandler.setDefault(new CookieManager() {
313            @Override public Map<String, List<String>> get(URI uri,
314                    Map<String, List<String>> requestHeaders) throws IOException {
315                cookieHandlerHeaders.putAll(requestHeaders);
316                Map<String, List<String>> result = new HashMap<String, List<String>>();
317                result.put("Cookie", Collections.singletonList("Bar=bar"));
318                result.put("Cookie2", Collections.singletonList("Baz=baz"));
319                result.put("Quux", Collections.singletonList("quux"));
320                return result;
321            }
322        });
323        MockWebServer server = new MockWebServer();
324        server.enqueue(new MockResponse());
325        server.play();
326
327        HttpURLConnection connection = (HttpURLConnection) server.getUrl("/").openConnection();
328        assertEquals(Collections.<String, List<String>>emptyMap(),
329                connection.getRequestProperties());
330
331        connection.setRequestProperty("Foo", "foo");
332        connection.setDoOutput(true);
333        connection.getOutputStream().write(5);
334        connection.getOutputStream().close();
335        connection.getInputStream().close();
336
337        RecordedRequest request = server.takeRequest();
338
339        assertContainsAll(cookieHandlerHeaders.keySet(), "Foo");
340        assertContainsAll(cookieHandlerHeaders.keySet(),
341                "Content-Type", "Content-Length", "User-Agent", "Connection", "Host");
342        assertFalse(cookieHandlerHeaders.containsKey("Cookie"));
343
344        /*
345         * The API specifies that calling getRequestProperties() on a connected instance should fail
346         * with an IllegalStateException, but the RI violates the spec and returns a valid map.
347         * http://www.mail-archive.com/net-dev@openjdk.java.net/msg01768.html
348         */
349        try {
350            assertContainsAll(connection.getRequestProperties().keySet(), "Foo");
351            assertContainsAll(connection.getRequestProperties().keySet(),
352                    "Content-Type", "Content-Length", "User-Agent", "Connection", "Host");
353            assertContainsAll(connection.getRequestProperties().keySet(), "Cookie", "Cookie2");
354            assertFalse(connection.getRequestProperties().containsKey("Quux"));
355        } catch (IllegalStateException expected) {
356        }
357
358        assertContainsAll(request.getHeaders(), "Foo: foo", "Cookie: Bar=bar", "Cookie2: Baz=baz");
359        assertFalse(request.getHeaders().contains("Quux: quux"));
360    }
361
362    public void testCookiesSentIgnoresCase() throws Exception {
363        CookieHandler.setDefault(new CookieManager() {
364            @Override public Map<String, List<String>> get(URI uri,
365                    Map<String, List<String>> requestHeaders) throws IOException {
366                Map<String, List<String>> result = new HashMap<String, List<String>>();
367                result.put("COOKIE", Collections.singletonList("Bar=bar"));
368                result.put("cooKIE2", Collections.singletonList("Baz=baz"));
369                return result;
370            }
371        });
372        MockWebServer server = new MockWebServer();
373        server.enqueue(new MockResponse());
374        server.play();
375
376        get(server, "/");
377
378        RecordedRequest request = server.takeRequest();
379        assertContainsAll(request.getHeaders(), "COOKIE: Bar=bar", "cooKIE2: Baz=baz");
380        assertFalse(request.getHeaders().contains("Quux: quux"));
381    }
382
383    /**
384     * RFC 2109 and RFC 2965 disagree here. 2109 says two equals strings match only if they are
385     * fully-qualified domain names. 2965 says two equal strings always match. We're testing for
386     * 2109 behavior because it's more widely used, it's more conservative, and it's what the RI
387     * does.
388     */
389    public void testDomainMatchesOnLocalAddresses() {
390        assertFalse(HttpCookie.domainMatches("localhost", "localhost"));
391        assertFalse(HttpCookie.domainMatches("b", "b"));
392    }
393
394    public void testDomainMatchesOnIpAddress() {
395        assertTrue(HttpCookie.domainMatches("127.0.0.1", "127.0.0.1"));
396        assertFalse(HttpCookie.domainMatches("127.0.0.1", "127.0.0.0"));
397        assertFalse(HttpCookie.domainMatches("127.0.0.1", "localhost"));
398    }
399
400    public void testDomainMatchesCaseMapping() {
401        testDomainMatchesCaseMapping(Locale.US);
402    }
403
404    public void testDomainMatchesCaseMappingExoticLocale() {
405        testDomainMatchesCaseMapping(new Locale("tr", "TR"));
406    }
407
408    private void testDomainMatchesCaseMapping(Locale locale) {
409        Locale defaultLocale = Locale.getDefault();
410        Locale.setDefault(locale);
411        try {
412            assertTrue(HttpCookie.domainMatches(".android.com", "WWW.ANDROID.COM"));
413            assertFalse(HttpCookie.domainMatches("android.com", "WWW.ANDROID.COM"));
414        } finally {
415            Locale.setDefault(defaultLocale);
416        }
417    }
418
419    /**
420     * From the spec, "If an explicitly specified value does not start with a dot, the user agent
421     * supplies a leading dot.". This prepending doesn't happen in setDomain.
422     */
423    public void testDomainNotAutomaticallyPrefixedWithDot() {
424        HttpCookie cookie = new HttpCookie("Foo", "foo");
425        cookie.setDomain("localhost");
426        assertEquals("localhost", cookie.getDomain());
427    }
428
429    public void testCookieStoreNullUris() {
430        CookieStore cookieStore = new CookieManager().getCookieStore();
431        HttpCookie cookieA = new HttpCookie("a", "android");
432        cookieA.setDomain(".android.com");
433        cookieA.setPath("/source");
434        HttpCookie cookieB = new HttpCookie("b", "banana");
435        cookieA.setDomain("code.google.com");
436        cookieA.setPath("/p/android");
437
438        try {
439            cookieStore.add(null, cookieA);
440        } catch (NullPointerException expected) {
441            // the RI crashes even though the cookie does get added to the store; sigh
442            expected.printStackTrace();
443        }
444        assertEquals(Arrays.asList(cookieA), cookieStore.getCookies());
445        try {
446            cookieStore.add(null, cookieB);
447        } catch (NullPointerException expected) {
448        }
449        assertEquals(Arrays.asList(cookieA, cookieB), cookieStore.getCookies());
450
451        try {
452            cookieStore.get(null);
453            fail();
454        } catch (NullPointerException expected) {
455        }
456
457        assertEquals(Collections.<URI>emptyList(), cookieStore.getURIs());
458        assertTrue(cookieStore.remove(null, cookieA));
459        assertEquals(Arrays.asList(cookieB), cookieStore.getCookies());
460
461        assertTrue(cookieStore.removeAll());
462        assertEquals(Collections.<URI>emptyList(), cookieStore.getURIs());
463        assertEquals(Collections.<HttpCookie>emptyList(), cookieStore.getCookies());
464    }
465
466    public void testCookieStoreRemoveAll() throws URISyntaxException {
467        CookieStore cookieStore = new CookieManager().getCookieStore();
468        cookieStore.add(new URI("http://code.google.com/"), new HttpCookie("a", "android"));
469        assertTrue(cookieStore.removeAll());
470        assertEquals(Collections.<URI>emptyList(), cookieStore.getURIs());
471        assertEquals(Collections.<HttpCookie>emptyList(), cookieStore.getCookies());
472        assertFalse("Expected removeAll() to return false when the call doesn't mutate the store",
473                cookieStore.removeAll());  // RI6 fails this
474    }
475
476    public void testCookieStoreAddAcceptsConflictingUri() throws URISyntaxException {
477        CookieStore cookieStore = new CookieManager().getCookieStore();
478        HttpCookie cookieA = new HttpCookie("a", "android");
479        cookieA.setDomain(".android.com");
480        cookieA.setPath("/source/");
481        cookieStore.add(new URI("http://google.com/source/"), cookieA);
482        assertEquals(Arrays.asList(cookieA), cookieStore.getCookies());
483    }
484
485    public void testCookieStoreRemoveRequiresUri() throws URISyntaxException {
486        CookieStore cookieStore = new CookieManager().getCookieStore();
487        HttpCookie cookieA = new HttpCookie("a", "android");
488        cookieStore.add(new URI("http://android.com/source/"), cookieA);
489        assertFalse("Expected remove() to take the cookie URI into account.", // RI6 fails this
490                cookieStore.remove(new URI("http://code.google.com/"), cookieA));
491        assertEquals(Arrays.asList(cookieA), cookieStore.getCookies());
492    }
493
494    public void testCookieStoreUriUsesHttpSchemeAlways() throws URISyntaxException {
495        CookieStore cookieStore = new CookieManager().getCookieStore();
496        cookieStore.add(new URI("https://a.com/"), new HttpCookie("a", "android"));
497        assertEquals(Arrays.asList(new URI("http://a.com")), cookieStore.getURIs());
498    }
499
500    public void testCookieStoreUriDropsUserInfo() throws URISyntaxException {
501        CookieStore cookieStore = new CookieManager().getCookieStore();
502        cookieStore.add(new URI("http://jesse:secret@a.com/"), new HttpCookie("a", "android"));
503        assertEquals(Arrays.asList(new URI("http://a.com")), cookieStore.getURIs());
504    }
505
506    public void testCookieStoreUriKeepsHost() throws URISyntaxException {
507        CookieStore cookieStore = new CookieManager().getCookieStore();
508        cookieStore.add(new URI("http://b.com/"), new HttpCookie("a", "android"));
509        assertEquals(Arrays.asList(new URI("http://b.com")), cookieStore.getURIs());
510    }
511
512    public void testCookieStoreUriDropsPort() throws URISyntaxException {
513        CookieStore cookieStore = new CookieManager().getCookieStore();
514        cookieStore.add(new URI("http://a.com:443/"), new HttpCookie("a", "android"));
515        assertEquals(Arrays.asList(new URI("http://a.com")), cookieStore.getURIs());
516    }
517
518    public void testCookieStoreUriDropsPath() throws URISyntaxException {
519        CookieStore cookieStore = new CookieManager().getCookieStore();
520        cookieStore.add(new URI("http://a.com/a/"), new HttpCookie("a", "android"));
521        assertEquals(Arrays.asList(new URI("http://a.com")), cookieStore.getURIs());
522    }
523
524    public void testCookieStoreUriDropsFragment() throws URISyntaxException {
525        CookieStore cookieStore = new CookieManager().getCookieStore();
526        cookieStore.add(new URI("http://a.com/a/foo#fragment"), new HttpCookie("a", "android"));
527        assertEquals(Arrays.asList(new URI("http://a.com")), cookieStore.getURIs());
528    }
529
530    public void testCookieStoreUriDropsQuery() throws URISyntaxException {
531        CookieStore cookieStore = new CookieManager().getCookieStore();
532        cookieStore.add(new URI("http://a.com/a/foo?query=value"), new HttpCookie("a", "android"));
533        assertEquals(Arrays.asList(new URI("http://a.com")), cookieStore.getURIs());
534    }
535
536    private void assertContains(Collection<String> collection, String element) {
537        for (String c : collection) {
538            if (c != null && c.equalsIgnoreCase(element)) {
539                return;
540            }
541        }
542        fail("No " + element + " in " + collection);
543    }
544
545    private void assertContainsAll(Collection<String> collection, String... toFind) {
546        for (String s : toFind) {
547            assertContains(collection, s);
548        }
549    }
550
551    private List<HttpCookie> sortedCopy(List<HttpCookie> cookies) {
552        List<HttpCookie> result = new ArrayList<HttpCookie>(cookies);
553        Collections.sort(result, new Comparator<HttpCookie>() {
554            public int compare(HttpCookie a, HttpCookie b) {
555                return a.getName().compareTo(b.getName());
556            }
557        });
558        return result;
559    }
560
561    private Map<String,List<String>> get(MockWebServer server, String path) throws Exception {
562        URLConnection connection = server.getUrl(path).openConnection();
563        Map<String, List<String>> headers = connection.getHeaderFields();
564        connection.getInputStream().close();
565        return headers;
566    }
567
568    private Map<String, List<String>> cookieHeaders(String... headers) {
569        return Collections.singletonMap("Set-Cookie", Arrays.asList(headers));
570    }
571
572    static class TestCookieStore implements CookieStore {
573        private final List<HttpCookie> cookies = new ArrayList<HttpCookie>();
574
575        public void add(URI uri, HttpCookie cookie) {
576            cookies.add(cookie);
577        }
578
579        public HttpCookie getCookie(String name) {
580            for (HttpCookie cookie : cookies) {
581                if (cookie.getName().equals(name)) {
582                    return cookie;
583                }
584            }
585            throw new IllegalArgumentException("No cookie " + name + " in " + cookies);
586        }
587
588        public List<HttpCookie> get(URI uri) {
589            throw new UnsupportedOperationException();
590        }
591
592        public List<HttpCookie> getCookies() {
593            throw new UnsupportedOperationException();
594        }
595
596        public List<URI> getURIs() {
597            throw new UnsupportedOperationException();
598        }
599
600        public boolean remove(URI uri, HttpCookie cookie) {
601            throw new UnsupportedOperationException();
602        }
603
604        public boolean removeAll() {
605            throw new UnsupportedOperationException();
606        }
607    }
608}
609