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