Chromium Code Reviews| Index: android_webview/javatests/src/org/chromium/android_webview/test/SafeBrowsingTest.java |
| diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/SafeBrowsingTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/SafeBrowsingTest.java |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..d49a5d1547efeb75e5e9d57183f17c7a0875744c |
| --- /dev/null |
| +++ b/android_webview/javatests/src/org/chromium/android_webview/test/SafeBrowsingTest.java |
| @@ -0,0 +1,174 @@ |
| +// Copyright 2017 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +package org.chromium.android_webview.test; |
| + |
| +import android.content.Context; |
| +import android.content.SharedPreferences; |
| +import android.graphics.Bitmap; |
| +import android.support.test.filters.SmallTest; |
| +import android.util.AndroidRuntimeException; |
| + |
| +import org.chromium.android_webview.AwBrowserContext; |
| +import org.chromium.android_webview.AwContents; |
| +import org.chromium.android_webview.test.util.GraphicsTestUtils; |
| +import org.chromium.base.test.util.Feature; |
| +import org.chromium.base.test.util.InMemorySharedPreferences; |
| +import org.chromium.components.safe_browsing.SafeBrowsingApiBridge; |
| +import org.chromium.components.safe_browsing.SafeBrowsingApiHandler; |
| +import org.chromium.net.test.util.TestWebServer; |
| + |
| +import java.util.regex.Pattern; |
| + |
| +/** |
| + * Test suite for SafeBrowsing. |
| + * |
| + * Ensures that interstitials can be successfully created for malicous pages. |
| + */ |
| +public class SafeBrowsingTest extends AwTestBase { |
| + private TestAwContentsClient mContentsClient; |
| + private AwTestContainerView mContainerView; |
| + private AwContents mAwContents; |
| + private MockAwBrowserContext mBrowserContext; |
| + |
| + // The background color of the safebrowsing interstitial HTML |
| + private static final int INTERSTITIAL_COLOR = 0xffce3426; |
| + |
| + private static final String SIMPLE_RESPONSE_DATA = "<html></html>"; |
| + private static final int WAIT_TIMEOUT_MS = 10000; |
| + private static final String SAFE_URL = "/safe"; |
| + private static final String MALWARE_URL = "/malware"; |
| + |
| + /** |
| + * A fake SafeBrowsingApiHandler which treats URLs ending in SAFE_URL as safe and those ending |
| + * in MALWARE_URL as malicious URLs that should be blocked. |
| + */ |
| + public static class MockSafeBrowsingApiHandler implements SafeBrowsingApiHandler { |
| + private Observer mObserver; |
| + private static final String SAFE_METADATA = "{}"; |
| + private static final String MALWARE_METADATA = "{\"matches\":[{\"threat_type\":\"5\"}]}"; |
| + |
| + @Override |
| + public boolean init(Context context, Observer result) { |
| + mObserver = result; |
| + return true; |
| + } |
| + |
| + @Override |
| + public void startUriLookup(long callbackId, String uri, int[] threatsOfInterest) { |
| + int resultStatus = STATUS_SUCCESS; |
| + String metadata = isMaliciousUrl(uri) ? MALWARE_METADATA : SAFE_METADATA; |
| + |
| + mObserver.onUrlCheckDone(callbackId, resultStatus, metadata); |
| + } |
| + |
| + private static boolean isMaliciousUrl(String uri) { |
| + return Pattern.compile(".*" + MALWARE_URL).matcher(uri).matches(); |
|
boliu
2017/02/14 02:34:32
endsWith good enough?
Nate Fischer
2017/02/14 17:17:55
That's better, thanks. Done
|
| + } |
| + } |
| + |
| + /** |
| + * A fake AwBrowserContext which loads the MockSafeBrowsingApiHandler instead of the real one. |
| + */ |
| + private static class MockAwBrowserContext extends AwBrowserContext { |
| + public MockAwBrowserContext( |
| + SharedPreferences sharedPreferences, Context applicationContext) { |
| + super(sharedPreferences, applicationContext); |
| + SafeBrowsingApiBridge.setSafeBrowsingHandlerType(MockSafeBrowsingApiHandler.class); |
| + } |
| + } |
| + |
| + @Override |
| + public void setUp() throws Exception { |
| + super.setUp(); |
| + mContentsClient = new TestAwContentsClient(); |
| + mContainerView = createAwTestContainerViewOnMainSync(mContentsClient); |
| + mAwContents = mContainerView.getAwContents(); |
| + } |
| + |
| + /** |
| + * Creates a special BrowserContext that has a safebrowsing api handler which always says |
| + * sites are malicious |
| + */ |
| + @Override |
| + protected void createAwBrowserContext() { |
| + if (mBrowserContext != null) { |
| + throw new AndroidRuntimeException("There should only be one browser context."); |
| + } |
| + getActivity(); // The Activity must be launched in order to load native code |
| + final InMemorySharedPreferences prefs = new InMemorySharedPreferences(); |
| + final Context appContext = getInstrumentation().getTargetContext().getApplicationContext(); |
|
boliu
2017/02/14 02:34:31
this is a lot of copied code, meaning AwTestBase i
Nate Fischer
2017/02/14 17:17:55
I broke it into 3 methods. The intermediate method
|
| + getInstrumentation().runOnMainSync(new Runnable() { |
| + @Override |
| + public void run() { |
| + mBrowserContext = new MockAwBrowserContext(prefs, appContext); |
| + } |
| + }); |
| + } |
| + |
| + private boolean isShowingInterstitial() { |
| + Bitmap bitmap = GraphicsTestUtils.drawAwContentsOnUiThread( |
| + mAwContents, mContainerView.getWidth(), mContainerView.getHeight()); |
| + return (bitmap.getPixel(0, 0) == INTERSTITIAL_COLOR); |
|
boliu
2017/02/14 02:34:31
where is this color from?
Nate Fischer
2017/02/14 17:17:55
It's the background color of the interstitial HTML
boliu
2017/02/14 18:31:40
It's not ok to depend on arbitrary values in far o
|
| + } |
| + |
| + @SmallTest |
| + @Feature({"AndroidWebView"}) |
| + public void testSafeBrowsingDoesNotBlockSafePages() throws Throwable { |
| + TestWebServer webServer = TestWebServer.start(); |
| + |
| + final String responseUrl = webServer.setResponse(SAFE_URL, SIMPLE_RESPONSE_DATA, null); |
| + try { |
| + loadUrlSync(mAwContents, mContentsClient.getOnPageFinishedHelper(), responseUrl); |
| + } finally { |
| + webServer.shutdown(); |
| + } |
| + |
| + assertFalse("Should not create an interstitial", isShowingInterstitial()); |
| + } |
| + |
| + @SmallTest |
| + @Feature({"AndroidWebView"}) |
| + public void testSafeBrowsingShowsInterstitialForMalware() throws Throwable { |
| + TestWebServer webServer = TestWebServer.start(); |
| + |
| + final String responseUrl = webServer.setResponse(MALWARE_URL, SIMPLE_RESPONSE_DATA, null); |
| + try { |
| + // loadUrlSync never finishes if an interstitial gets shown, so we have to call the |
| + // async version |
| + loadUrlAsync(mAwContents, responseUrl); |
| + Thread.sleep(WAIT_TIMEOUT_MS); |
|
boliu
2017/02/14 02:34:32
no sleeps
you can wait for startUriLookup to be c
Nate Fischer
2017/02/14 17:17:55
I wasn't sure how to implement what you suggested,
|
| + } finally { |
| + webServer.shutdown(); |
| + } |
| + |
| + assertTrue("Should create an interstitial", isShowingInterstitial()); |
| + } |
| + |
| + @SmallTest |
| + @Feature({"AndroidWebView"}) |
| + public void testSafeBrowsingMaliciousSubresourceShowsInterstitial() throws Throwable { |
| + TestWebServer webServer = TestWebServer.start(); |
| + |
| + final String iframeUrl = webServer.setResponse(MALWARE_URL, SIMPLE_RESPONSE_DATA, null); |
| + |
| + final String responseData = "<html>" |
| + + " <body bgcolor=\"#E6E6FA\">" |
| + + " <p>This is outside the iframe</p>" |
| + + " <iframe src=\"" + iframeUrl + "\"></iframe>" |
| + + " </body>" |
| + + "</html>"; |
| + final String responseUrl = webServer.setResponse(SAFE_URL, responseData, null); |
| + try { |
| + // loadUrlSync never finishes if an interstitial gets shown, so we have to call the |
| + // async version |
| + loadUrlAsync(mAwContents, responseUrl); |
| + Thread.sleep(WAIT_TIMEOUT_MS); |
|
boliu
2017/02/14 02:34:32
ditto
Nate Fischer
2017/02/14 17:17:55
Done
|
| + } finally { |
| + webServer.shutdown(); |
| + } |
| + |
| + assertTrue("Should create an interstitial", isShowingInterstitial()); |
| + } |
| +} |