blob: 856b4aad9b92438efe7dc5c3f81251c2d49b4888 [file] [log] [blame]
/*
* 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());
}
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");
}
}