| /* |
| * Copyright (C) 2009 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package android.webkit.cts; |
| |
| import android.cts.util.NullWebViewUtils; |
| import android.cts.util.PollingCheck; |
| import android.test.ActivityInstrumentationTestCase2; |
| import android.webkit.CookieManager; |
| import android.webkit.CookieSyncManager; |
| import android.webkit.WebView; |
| import android.webkit.ValueCallback; |
| |
| import java.util.concurrent.Semaphore; |
| import java.util.concurrent.TimeUnit; |
| import java.util.concurrent.atomic.AtomicBoolean; |
| |
| import java.util.Date; |
| import java.util.regex.Matcher; |
| import java.util.regex.Pattern; |
| |
| public class CookieManagerTest extends |
| ActivityInstrumentationTestCase2<CookieSyncManagerCtsActivity> { |
| |
| private static final int TEST_TIMEOUT = 5000; |
| |
| private WebView mWebView; |
| private CookieManager mCookieManager; |
| private WebViewOnUiThread mOnUiThread; |
| |
| public CookieManagerTest() { |
| super("com.android.cts.webkit", CookieSyncManagerCtsActivity.class); |
| } |
| |
| @Override |
| protected void setUp() throws Exception { |
| super.setUp(); |
| mWebView = getActivity().getWebView(); |
| if (mWebView != null) { |
| mOnUiThread = new WebViewOnUiThread(this, mWebView); |
| |
| mCookieManager = CookieManager.getInstance(); |
| assertNotNull(mCookieManager); |
| |
| // We start with no cookies. |
| mCookieManager.removeAllCookie(); |
| assertFalse(mCookieManager.hasCookies()); |
| |
| // But accepting cookies. |
| mCookieManager.setAcceptCookie(false); |
| assertFalse(mCookieManager.acceptCookie()); |
| } |
| } |
| |
| public void testGetInstance() { |
| if (!NullWebViewUtils.isWebViewAvailable()) { |
| return; |
| } |
| mOnUiThread.cleanUp(); |
| CookieManager c1 = CookieManager.getInstance(); |
| CookieManager c2 = CookieManager.getInstance(); |
| |
| assertSame(c1, c2); |
| } |
| |
| public void testClone() { |
| if (!NullWebViewUtils.isWebViewAvailable()) { |
| return; |
| } |
| } |
| |
| public void testFlush() { |
| if (!NullWebViewUtils.isWebViewAvailable()) { |
| return; |
| } |
| mCookieManager.flush(); |
| } |
| |
| public void testAcceptCookie() throws Exception { |
| if (!NullWebViewUtils.isWebViewAvailable()) { |
| return; |
| } |
| |
| mCookieManager.setAcceptCookie(false); |
| assertFalse(mCookieManager.acceptCookie()); |
| |
| CtsTestServer server = new CtsTestServer(getActivity(), false); |
| String url = server.getCookieUrl("conquest.html"); |
| mOnUiThread.loadUrlAndWaitForCompletion(url); |
| assertEquals("0", mOnUiThread.getTitle()); // no cookies passed |
| Thread.sleep(500); |
| assertNull(mCookieManager.getCookie(url)); |
| |
| mCookieManager.setAcceptCookie(true); |
| assertTrue(mCookieManager.acceptCookie()); |
| |
| url = server.getCookieUrl("war.html"); |
| mOnUiThread.loadUrlAndWaitForCompletion(url); |
| assertEquals("0", mOnUiThread.getTitle()); // no cookies passed |
| waitForCookie(url); |
| String cookie = mCookieManager.getCookie(url); |
| assertNotNull(cookie); |
| // 'count' value of the returned cookie is 0 |
| final Pattern pat = Pattern.compile("count=(\\d+)"); |
| Matcher m = pat.matcher(cookie); |
| assertTrue(m.matches()); |
| assertEquals("0", m.group(1)); |
| |
| url = server.getCookieUrl("famine.html"); |
| mOnUiThread.loadUrlAndWaitForCompletion(url); |
| assertEquals("1|count=0", mOnUiThread.getTitle()); // outgoing cookie |
| waitForCookie(url); |
| cookie = mCookieManager.getCookie(url); |
| assertNotNull(cookie); |
| m = pat.matcher(cookie); |
| assertTrue(m.matches()); |
| assertEquals("1", m.group(1)); // value got incremented |
| |
| url = server.getCookieUrl("death.html"); |
| mCookieManager.setCookie(url, "count=41"); |
| mOnUiThread.loadUrlAndWaitForCompletion(url); |
| assertEquals("1|count=41", mOnUiThread.getTitle()); // outgoing cookie |
| waitForCookie(url); |
| cookie = mCookieManager.getCookie(url); |
| assertNotNull(cookie); |
| m = pat.matcher(cookie); |
| assertTrue(m.matches()); |
| assertEquals("42", m.group(1)); // value got incremented |
| } |
| |
| public void testSetCookie() { |
| if (!NullWebViewUtils.isWebViewAvailable()) { |
| return; |
| } |
| |
| String url = "http://www.example.com"; |
| String cookie = "name=test"; |
| mCookieManager.setCookie(url, cookie); |
| assertEquals(cookie, mCookieManager.getCookie(url)); |
| assertTrue(mCookieManager.hasCookies()); |
| } |
| |
| public void testSetCookieNullCallback() { |
| if (!NullWebViewUtils.isWebViewAvailable()) { |
| return; |
| } |
| |
| final String url = "http://www.example.com"; |
| final String cookie = "name=test"; |
| mCookieManager.setCookie(url, cookie, null); |
| new PollingCheck(TEST_TIMEOUT) { |
| @Override |
| protected boolean check() { |
| String c = mCookieManager.getCookie(url); |
| return mCookieManager.getCookie(url).contains(cookie); |
| } |
| }.run(); |
| } |
| |
| public void testSetCookieCallback() throws Throwable { |
| if (!NullWebViewUtils.isWebViewAvailable()) { |
| return; |
| } |
| |
| final Semaphore s = new Semaphore(0); |
| final AtomicBoolean status = new AtomicBoolean(); |
| final ValueCallback<Boolean> callback = new ValueCallback<Boolean>() { |
| @Override |
| public void onReceiveValue(Boolean success) { |
| status.set(success); |
| s.release(); |
| } |
| }; |
| } |
| |
| public void testRemoveCookies() throws InterruptedException { |
| if (!NullWebViewUtils.isWebViewAvailable()) { |
| return; |
| } |
| |
| final String url = "http://www.example.com"; |
| final String sessionCookie = "cookie1=peter"; |
| final String longCookie = "cookie2=sue"; |
| final String quickCookie = "cookie3=marc"; |
| |
| mCookieManager.setCookie(url, sessionCookie); |
| mCookieManager.setCookie(url, makeExpiringCookie(longCookie, 600)); |
| mCookieManager.setCookie(url, makeExpiringCookieMs(quickCookie, 1500)); |
| |
| String allCookies = mCookieManager.getCookie(url); |
| assertTrue(allCookies.contains(sessionCookie)); |
| assertTrue(allCookies.contains(longCookie)); |
| assertTrue(allCookies.contains(quickCookie)); |
| |
| mCookieManager.removeSessionCookie(); |
| allCookies = mCookieManager.getCookie(url); |
| assertFalse(allCookies.contains(sessionCookie)); |
| assertTrue(allCookies.contains(longCookie)); |
| assertTrue(allCookies.contains(quickCookie)); |
| |
| Thread.sleep(2000); // wait for quick cookie to expire |
| mCookieManager.removeExpiredCookie(); |
| allCookies = mCookieManager.getCookie(url); |
| assertFalse(allCookies.contains(sessionCookie)); |
| assertTrue(allCookies.contains(longCookie)); |
| assertFalse(allCookies.contains(quickCookie)); |
| |
| mCookieManager.removeAllCookie(); |
| assertNull(mCookieManager.getCookie(url)); |
| assertFalse(mCookieManager.hasCookies()); |
| } |
| |
| public void testRemoveCookiesNullCallback() throws InterruptedException { |
| if (!NullWebViewUtils.isWebViewAvailable()) { |
| return; |
| } |
| |
| final String url = "http://www.example.com"; |
| final String sessionCookie = "cookie1=peter"; |
| final String longCookie = "cookie2=sue"; |
| final String quickCookie = "cookie3=marc"; |
| |
| mCookieManager.setCookie(url, sessionCookie); |
| mCookieManager.setCookie(url, makeExpiringCookie(longCookie, 600)); |
| mCookieManager.setCookie(url, makeExpiringCookieMs(quickCookie, 1500)); |
| |
| String allCookies = mCookieManager.getCookie(url); |
| assertTrue(allCookies.contains(sessionCookie)); |
| assertTrue(allCookies.contains(longCookie)); |
| assertTrue(allCookies.contains(quickCookie)); |
| |
| mCookieManager.removeSessionCookies(null); |
| allCookies = mCookieManager.getCookie(url); |
| new PollingCheck(TEST_TIMEOUT) { |
| @Override |
| protected boolean check() { |
| String c = mCookieManager.getCookie(url); |
| return !c.contains(sessionCookie) && |
| c.contains(longCookie) && |
| c.contains(quickCookie); |
| } |
| }.run(); |
| |
| mCookieManager.removeAllCookies(null); |
| new PollingCheck(TEST_TIMEOUT) { |
| @Override |
| protected boolean check() { |
| return !mCookieManager.hasCookies(); |
| } |
| }.run(); |
| assertNull(mCookieManager.getCookie(url)); |
| } |
| |
| public void testRemoveCookiesCallback() throws InterruptedException { |
| if (!NullWebViewUtils.isWebViewAvailable()) { |
| return; |
| } |
| |
| final Semaphore s = new Semaphore(0); |
| final AtomicBoolean anyDeleted = new AtomicBoolean(); |
| final ValueCallback<Boolean> callback = new ValueCallback<Boolean>() { |
| @Override |
| public void onReceiveValue(Boolean n) { |
| anyDeleted.set(n); |
| s.release(); |
| } |
| }; |
| |
| final String url = "http://www.example.com"; |
| final String sessionCookie = "cookie1=peter"; |
| final String normalCookie = "cookie2=sue"; |
| |
| // We set one session cookie and one normal cookie. |
| mCookieManager.setCookie(url, sessionCookie); |
| mCookieManager.setCookie(url, makeExpiringCookie(normalCookie, 600)); |
| |
| String allCookies = mCookieManager.getCookie(url); |
| assertTrue(allCookies.contains(sessionCookie)); |
| assertTrue(allCookies.contains(normalCookie)); |
| |
| // When we remove session cookies there are some to remove. |
| removeSessionCookiesOnUiThread(callback); |
| assertTrue(s.tryAcquire(TEST_TIMEOUT, TimeUnit.MILLISECONDS)); |
| assertTrue(anyDeleted.get()); |
| |
| // The normal cookie is not removed. |
| assertTrue(mCookieManager.getCookie(url).contains(normalCookie)); |
| |
| // When we remove session cookies again there are none to remove. |
| removeSessionCookiesOnUiThread(callback); |
| assertTrue(s.tryAcquire(TEST_TIMEOUT, TimeUnit.MILLISECONDS)); |
| assertFalse(anyDeleted.get()); |
| |
| // When we remove all cookies there are some to remove. |
| removeAllCookiesOnUiThread(callback); |
| assertTrue(s.tryAcquire(TEST_TIMEOUT, TimeUnit.MILLISECONDS)); |
| assertTrue(anyDeleted.get()); |
| |
| // Now we have no cookies. |
| assertFalse(mCookieManager.hasCookies()); |
| assertNull(mCookieManager.getCookie(url)); |
| |
| // When we remove all cookies again there are none to remove. |
| removeAllCookiesOnUiThread(callback); |
| assertTrue(s.tryAcquire(TEST_TIMEOUT, TimeUnit.MILLISECONDS)); |
| assertFalse(anyDeleted.get()); |
| } |
| |
| /* |
| TODO: uncomment when acceptThirdPartyCookies implementation lands |
| public void testThirdPartyCookie() throws Throwable { |
| if (!NullWebViewUtils.isWebViewAvailable()) { |
| return; |
| } |
| CtsTestServer server = null; |
| try { |
| // In theory we need two servers to test this, one server ('the first party') |
| // which returns a response with a link to a second server ('the third party') |
| // at different origin. This second server attempts to set a cookie which should |
| // fail if AcceptThirdPartyCookie() is false. |
| // Strictly according to the letter of RFC6454 it should be possible to set this |
| // situation up with two TestServers on different ports (these count as having |
| // different origins) but Chrome is not strict about this and does not check the |
| // port. Instead we cheat making some of the urls come from localhost and some |
| // from 127.0.0.1 which count (both in theory and pratice) as having different |
| // origins. |
| server = new CtsTestServer(getActivity()); |
| |
| // Turn on Javascript (otherwise <script> aren't fetched spoiling the test). |
| mOnUiThread.getSettings().setJavaScriptEnabled(true); |
| |
| // Turn global allow on. |
| mCookieManager.setAcceptCookie(true); |
| assertTrue(mCookieManager.acceptCookie()); |
| |
| // When third party cookies are disabled... |
| mOnUiThread.setAcceptThirdPartyCookies(false); |
| assertFalse(mOnUiThread.acceptThirdPartyCookies()); |
| |
| // ...we can't set third party cookies. |
| // First on the third party server we get a url which tries to set a cookie. |
| String cookieUrl = toThirdPartyUrl( |
| server.getSetCookieUrl("cookie_1.js", "test1", "value1")); |
| // Then we create a url on the first party server which links to the first url. |
| String url = server.getLinkedScriptUrl("/content_1.html", cookieUrl); |
| mOnUiThread.loadUrlAndWaitForCompletion(url); |
| assertNull(mCookieManager.getCookie(cookieUrl)); |
| |
| // When third party cookies are enabled... |
| mOnUiThread.setAcceptThirdPartyCookies(true); |
| assertTrue(mOnUiThread.acceptThirdPartyCookies()); |
| |
| // ...we can set third party cookies. |
| cookieUrl = toThirdPartyUrl( |
| server.getSetCookieUrl("/cookie_2.js", "test2", "value2")); |
| url = server.getLinkedScriptUrl("/content_2.html", cookieUrl); |
| mOnUiThread.loadUrlAndWaitForCompletion(url); |
| waitForCookie(cookieUrl); |
| String cookie = mCookieManager.getCookie(cookieUrl); |
| assertNotNull(cookie); |
| assertTrue(cookie.contains("test2")); |
| } finally { |
| if (server != null) server.shutdown(); |
| mOnUiThread.getSettings().setJavaScriptEnabled(false); |
| } |
| } |
| */ |
| |
| public void testb3167208() throws Exception { |
| if (!NullWebViewUtils.isWebViewAvailable()) { |
| return; |
| } |
| String uri = "http://host.android.com/path/"; |
| // note the space after the domain= |
| String problemCookie = "foo=bar; domain= .android.com; path=/"; |
| mCookieManager.setCookie(uri, problemCookie); |
| String cookie = mCookieManager.getCookie(uri); |
| assertNotNull(cookie); |
| assertTrue(cookie.contains("foo=bar")); |
| } |
| |
| private void waitForCookie(final String url) { |
| new PollingCheck(TEST_TIMEOUT) { |
| @Override |
| protected boolean check() { |
| return mCookieManager.getCookie(url) != null; |
| } |
| }.run(); |
| } |
| |
| @SuppressWarnings("deprecation") |
| private String makeExpiringCookie(String cookie, int secondsTillExpiry) { |
| return makeExpiringCookieMs(cookie, 1000*secondsTillExpiry); |
| } |
| |
| @SuppressWarnings("deprecation") |
| private String makeExpiringCookieMs(String cookie, int millisecondsTillExpiry) { |
| Date date = new Date(); |
| date.setTime(date.getTime() + millisecondsTillExpiry); |
| return cookie + "; expires=" + date.toGMTString(); |
| } |
| |
| private void removeAllCookiesOnUiThread(final ValueCallback<Boolean> callback) { |
| runTestOnUiThreadAndCatch(new Runnable() { |
| @Override |
| public void run() { |
| mCookieManager.removeAllCookies(callback); |
| } |
| }); |
| } |
| |
| private void removeSessionCookiesOnUiThread(final ValueCallback<Boolean> callback) { |
| runTestOnUiThreadAndCatch(new Runnable() { |
| @Override |
| public void run() { |
| mCookieManager.removeSessionCookies(callback); |
| } |
| }); |
| } |
| |
| private void setCookieOnUiThread(final String url, final String cookie, |
| final ValueCallback<Boolean> callback) { |
| runTestOnUiThreadAndCatch(new Runnable() { |
| @Override |
| public void run() { |
| mCookieManager.setCookie(url, cookie, callback); |
| } |
| }); |
| } |
| |
| private void runTestOnUiThreadAndCatch(Runnable runnable) { |
| try { |
| runTestOnUiThread(runnable); |
| } catch (Throwable t) { |
| fail("Unexpected error while running on UI thread: " + t.getMessage()); |
| } |
| } |
| |
| /** |
| * Makes a url look as if it comes from a different host. |
| * @param url the url to fake. |
| * @return the resulting url after faking. |
| */ |
| public String toThirdPartyUrl(String url) { |
| return url.replace("localhost", "127.0.0.1"); |
| } |
| } |