summaryrefslogtreecommitdiffstats
path: root/android_webview
diff options
context:
space:
mode:
authorboliu@chromium.org <boliu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-09-26 16:23:56 +0000
committerboliu@chromium.org <boliu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-09-26 16:23:56 +0000
commit29f51bbf25b7f262cc29e46a38676fd5b27220a8 (patch)
tree3426dbdbd67d62c4dd4ae1ec4fee9d651c8d5f04 /android_webview
parent0b083cdfe51ed571d697f96ca5ba7756e9af5ed2 (diff)
downloadchromium_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')
-rw-r--r--android_webview/javatests/src/org/chromium/android_webview/test/AwSettingsTest.java88
-rw-r--r--android_webview/javatests/src/org/chromium/android_webview/test/TestWebServer.java53
-rw-r--r--android_webview/renderer/aw_render_view_ext.cc20
-rw-r--r--android_webview/renderer/aw_render_view_ext.h15
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);
};