diff options
author | boliu@chromium.org <boliu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-09-26 16:23:56 +0000 |
---|---|---|
committer | boliu@chromium.org <boliu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-09-26 16:23:56 +0000 |
commit | 29f51bbf25b7f262cc29e46a38676fd5b27220a8 (patch) | |
tree | 3426dbdbd67d62c4dd4ae1ec4fee9d651c8d5f04 /android_webview | |
parent | 0b083cdfe51ed571d697f96ca5ba7756e9af5ed2 (diff) | |
download | chromium_src-29f51bbf25b7f262cc29e46a38676fd5b27220a8.zip chromium_src-29f51bbf25b7f262cc29e46a38676fd5b27220a8.tar.gz chromium_src-29f51bbf25b7f262cc29e46a38676fd5b27220a8.tar.bz2 |
Implement Android WebView BlockNetworkImages
This uses the WebCore ImagesEnabled setting, which is added to
ContentSettings. The setting also includes overriding
WebPermissionClient::allowImage, which here allows images with local
soucres to load as well.
Use a whitelist of local file schemes instead of blacklisting only
http(s).
BUG=
Review URL: https://chromiumcodereview.appspot.com/10920033
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@158809 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'android_webview')
4 files changed, 155 insertions, 21 deletions
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/AwSettingsTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/AwSettingsTest.java index f57cffd..70b14bd 100644 --- a/android_webview/javatests/src/org/chromium/android_webview/test/AwSettingsTest.java +++ b/android_webview/javatests/src/org/chromium/android_webview/test/AwSettingsTest.java @@ -7,6 +7,7 @@ package org.chromium.android_webview.test; import android.content.Context; import android.os.Build; import android.test.suitebuilder.annotation.SmallTest; +import android.util.Pair; import org.chromium.base.test.util.Feature; import org.chromium.base.test.util.TestFileUtil; @@ -14,10 +15,15 @@ import org.chromium.base.test.util.UrlUtils; import org.chromium.content.browser.ContentSettings; import org.chromium.content.browser.ContentViewCore; import org.chromium.content.browser.test.util.CallbackHelper; +import org.chromium.content.browser.test.util.Criteria; +import org.chromium.content.browser.test.util.CriteriaHelper; import org.chromium.content.browser.test.util.HistoryUtils; import java.util.regex.Matcher; import java.util.regex.Pattern; +import java.util.ArrayList; +import java.util.List; + /** * A test suite for ContentSettings class. The key objective is to verify that each @@ -25,6 +31,8 @@ import java.util.regex.Pattern; * application. */ public class AwSettingsTest extends AndroidWebViewTestBase { + private static final int CHECK_INTERVAL = 100; + private static final boolean ENABLED = true; private static final boolean DISABLED = false; @@ -1334,4 +1342,84 @@ public class AwSettingsTest extends AndroidWebViewTestBase { private String createContentUrl(final String target) { return TestContentProvider.createContentUrl(target); } + + private final String IMAGE_DATA = "iVBORw0KGgoAAA" + + "ANSUhEUgAAAAEAAAABCAAAAAA6fptVAAAAAXNSR0IArs4c6QAAAA1JREFUCB0BAgD9/wAAAAIAAc3j" + + "0SsAAAAASUVORK5CYII="; + + private final String DATA_URL_IMAGE_HTML = "<html>" + + "<head><script>function updateTitle(){" + + "document.title=document.getElementById('img').naturalHeight;}</script></head>" + + "<body onload='updateTitle()'>" + + "<img id='img' onload='updateTitle()' src='data:image/png;base64," + IMAGE_DATA + + "'></body></html>"; + + @SmallTest + @Feature({"Android-WebView", "Preferences"}) + public void testBlockNetworkImagesDoesNotBlockDataUrlImage() throws Throwable { + final TestAwContentsClient contentClient = new TestAwContentsClient(); + final ContentViewCore contentView = + createAwTestContainerViewOnMainSync(false, contentClient).getContentViewCore(); + final ContentSettings settings = getContentSettingsOnUiThread(contentView); + + settings.setJavaScriptEnabled(true); + + settings.setImagesEnabled(false); + loadDataSync(contentView, + contentClient.getOnPageFinishedHelper(), + DATA_URL_IMAGE_HTML, + "text/html", + false); + assertEquals("1", getTitleOnUiThread(contentView)); + } + + @SmallTest + @Feature({"Android-WebView", "Preferences"}) + public void testBlockNetworkImagesBlocksNetworkImageAndReloadInPlace() throws Throwable { + final TestAwContentsClient contentClient = new TestAwContentsClient(); + final ContentViewCore contentView = + createAwTestContainerViewOnMainSync(false, contentClient).getContentViewCore(); + final ContentSettings settings = getContentSettingsOnUiThread(contentView); + settings.setJavaScriptEnabled(true); + + TestWebServer webServer = null; + try { + webServer = new TestWebServer(false); + List<Pair<String, String>> imageHeaders = new ArrayList<Pair<String, String>>(); + imageHeaders.add(Pair.create("Content-Type", "image/png")); + final String imagePath = "/image.png"; + webServer.setResponseBase64(imagePath, IMAGE_DATA, imageHeaders); + + final String pagePath = "/html_image.html"; + final String httpUrlImageHtml = "<html>" + + "<head><script>" + + "function updateTitle(){" + + "document.title=document.getElementById('img').naturalHeight;}" + + "</script></head>" + + "<body onload='updateTitle()'>" + + "<img id='img' onload='updateTitle()' src='" + imagePath + + "'></body></html>"; + final String httpImageUrl = webServer.setResponse(pagePath, httpUrlImageHtml, null); + + settings.setImagesEnabled(false); + loadUrlSync(contentView, contentClient.getOnPageFinishedHelper(), httpImageUrl); + assertEquals("0", getTitleOnUiThread(contentView)); + + settings.setImagesEnabled(true); + assertTrue(CriteriaHelper.pollForCriteria(new Criteria() { + @Override + public boolean isSatisfied() { + try { + return "0".equals(getTitleOnUiThread(contentView)); + } catch (Throwable t) { + t.printStackTrace(); + fail("Failed to getTitleOnUIThread: " + t.toString()); + return false; + } + } + }, WAIT_TIMEOUT_SECONDS * 1000, CHECK_INTERVAL)); + } finally { + if (webServer != null) webServer.shutdown(); + } + } } diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/TestWebServer.java b/android_webview/javatests/src/org/chromium/android_webview/test/TestWebServer.java index 8508a51..0e56f56 100644 --- a/android_webview/javatests/src/org/chromium/android_webview/test/TestWebServer.java +++ b/android_webview/javatests/src/org/chromium/android_webview/test/TestWebServer.java @@ -15,7 +15,7 @@ import org.apache.http.HttpStatus; import org.apache.http.HttpVersion; import org.apache.http.RequestLine; import org.apache.http.StatusLine; -import org.apache.http.entity.StringEntity; +import org.apache.http.entity.ByteArrayEntity; import org.apache.http.impl.DefaultHttpServerConnection; import org.apache.http.impl.cookie.DateUtils; import org.apache.http.message.BasicHttpResponse; @@ -26,7 +26,6 @@ import org.apache.http.params.HttpParams; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; -import java.io.UnsupportedEncodingException; import java.net.MalformedURLException; import java.net.ServerSocket; import java.net.Socket; @@ -72,11 +71,11 @@ public class TestWebServer { private boolean mSsl; private static class Response { - final String mResponseStr; + final byte[] mResponseData; final List<Pair<String, String>> mResponseHeaders; - Response(String responseStr, List<Pair<String, String>> responseHeaders) { - mResponseStr = responseStr; + Response(byte[] resposneData, List<Pair<String, String>> responseHeaders) { + mResponseData = resposneData; mResponseHeaders = responseHeaders == null ? new ArrayList<Pair<String, String>>() : responseHeaders; } @@ -146,16 +145,37 @@ public class TestWebServer { * in (with the option to specify additional headers). * * @param requestPath The path to respond to. - * @param resposneString The response body that will be returned. + * @param responseString The response body that will be returned. * @param responseHeaders Any additional headers that should be returned along with the * response (null is acceptable). * @return The full URL including the path that should be requested to get the expected * response. */ public String setResponse( - String requestPath, String resposneString, + String requestPath, String responseString, List<Pair<String, String>> responseHeaders) { - mResponseMap.put(requestPath, new Response(resposneString, responseHeaders)); + mResponseMap.put(requestPath, new Response(responseString.getBytes(), responseHeaders)); + return mServerUri + requestPath; + } + + /** + * Sets a base64 encoded response to be returned when a particular request path is passed + * in (with the option to specify additional headers). + * + * @param requestPath The path to respond to. + * @param base64EncodedResponse The response body that is base64 encoded. The actual server + * response will the decoded binary form. + * @param responseHeaders Any additional headers that should be returned along with the + * response (null is acceptable). + * @return The full URL including the path that should be requested to get the expected + * response. + */ + public String setResponseBase64( + String requestPath, String base64EncodedResponse, + List<Pair<String, String>> responseHeaders) { + mResponseMap.put(requestPath, + new Response(Base64.decode(base64EncodedResponse, Base64.DEFAULT), + responseHeaders)); return mServerUri + requestPath; } @@ -234,7 +254,7 @@ public class TestWebServer { httpResponse = createResponse(HttpStatus.SC_NOT_FOUND); } else { httpResponse = createResponse(HttpStatus.SC_OK); - httpResponse.setEntity(createEntity(response.mResponseStr)); + httpResponse.setEntity(createEntity(response.mResponseData)); for (Pair<String, String> header : response.mResponseHeaders) { httpResponse.addHeader(header.first, header.second); } @@ -272,7 +292,7 @@ public class TestWebServer { buf.append("</title></head><body>"); buf.append(reason); buf.append("</body></html>"); - response.setEntity(createEntity(buf.toString())); + response.setEntity(createEntity(buf.toString().getBytes())); } return response; } @@ -280,15 +300,10 @@ public class TestWebServer { /** * Create a string entity for the given content. */ - private StringEntity createEntity(String content) { - try { - StringEntity entity = new StringEntity(content); - entity.setContentType("text/html"); - return entity; - } catch (UnsupportedEncodingException e) { - Log.w(TAG, e); - } - return null; + private ByteArrayEntity createEntity(byte[] data) { + ByteArrayEntity entity = new ByteArrayEntity(data); + entity.setContentType("text/html"); + return entity; } private static class ServerThread extends Thread { diff --git a/android_webview/renderer/aw_render_view_ext.cc b/android_webview/renderer/aw_render_view_ext.cc index ae0035d..7f0825c 100644 --- a/android_webview/renderer/aw_render_view_ext.cc +++ b/android_webview/renderer/aw_render_view_ext.cc @@ -5,17 +5,20 @@ #include "android_webview/renderer/aw_render_view_ext.h" #include "android_webview/common/render_view_messages.h" +#include "content/public/common/url_constants.h" #include "content/public/renderer/render_view.h" +#include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebURL.h" +#include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebVector.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebDocument.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebElement.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebView.h" -#include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebVector.h" namespace android_webview { AwRenderViewExt::AwRenderViewExt(content::RenderView* render_view) : content::RenderViewObserver(render_view) { + render_view->GetWebView()->setPermissionClient(this); } AwRenderViewExt::~AwRenderViewExt() {} @@ -48,4 +51,19 @@ void AwRenderViewExt::OnDocumentHasImagesRequest(int id) { hasImages)); } +bool AwRenderViewExt::allowImage(WebKit::WebFrame* frame, + bool enabled_per_settings, + const WebKit::WebURL& image_url) { + // Implementing setBlockNetworkImages, so allow local scheme images to be + // loaded. + if (enabled_per_settings) + return true; + + // For compatibility, only blacklist network schemes instead of whitelisting. + const GURL url(image_url); + return !(url.SchemeIs(chrome::kHttpScheme) || + url.SchemeIs(chrome::kHttpsScheme) || + url.SchemeIs(chrome::kFtpScheme)); +} + } // namespace android_webview diff --git a/android_webview/renderer/aw_render_view_ext.h b/android_webview/renderer/aw_render_view_ext.h index fa58872..fadb457 100644 --- a/android_webview/renderer/aw_render_view_ext.h +++ b/android_webview/renderer/aw_render_view_ext.h @@ -8,13 +8,21 @@ #include "base/basictypes.h" #include "base/compiler_specific.h" #include "content/public/renderer/render_view_observer.h" +#include "third_party/WebKit/Source/WebKit/chromium/public/WebPermissionClient.h" + +namespace WebKit { + +class WebURL; + +} // namespace WebKit namespace android_webview { // Render process side of AwRenderViewHostExt, this provides cross-process // implementation of miscellaneous WebView functions that we need to poke // WebKit directly to implement (and that aren't needed in the chrome app). -class AwRenderViewExt : public content::RenderViewObserver { +class AwRenderViewExt : public content::RenderViewObserver, + public WebKit::WebPermissionClient { public: static void RenderViewCreated(content::RenderView* render_view); @@ -27,6 +35,11 @@ class AwRenderViewExt : public content::RenderViewObserver { void OnDocumentHasImagesRequest(int id); + // WebKit::WebPermissionClient implementation. + virtual bool allowImage(WebKit::WebFrame* frame, + bool enabledPerSettings, + const WebKit::WebURL& imageURL); + DISALLOW_COPY_AND_ASSIGN(AwRenderViewExt); }; |