1 // Copyright 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 package org.chromium.android_webview.test;
7 import android.graphics.Bitmap;
8 import android.test.suitebuilder.annotation.SmallTest;
10 import org.chromium.android_webview.AwContents;
11 import org.chromium.android_webview.AwSettings;
12 import org.chromium.android_webview.test.util.CommonResources;
13 import org.chromium.base.test.util.DisabledTest;
14 import org.chromium.base.test.util.Feature;
15 import org.chromium.content.browser.ContentViewCore;
16 import org.chromium.content.browser.test.util.HistoryUtils;
17 import org.chromium.content.browser.test.util.TestCallbackHelperContainer;
18 import org.chromium.net.test.util.TestWebServer;
21 import java.io.FileOutputStream;
22 import java.util.concurrent.Callable;
25 * Tests for the {@link android.webkit.WebView#loadDataWithBaseURL(String, String, String, String,
28 public class LoadDataWithBaseUrlTest extends AwTestBase {
30 private TestAwContentsClient mContentsClient;
31 private AwContents mAwContents;
32 private ContentViewCore mContentViewCore;
35 public void setUp() throws Exception {
37 mContentsClient = new TestAwContentsClient();
38 final AwTestContainerView testContainerView =
39 createAwTestContainerViewOnMainSync(mContentsClient);
40 mAwContents = testContainerView.getAwContents();
41 mContentViewCore = testContainerView.getContentViewCore();
44 protected void loadDataWithBaseUrlSync(
45 final String data, final String mimeType, final boolean isBase64Encoded,
46 final String baseUrl, final String historyUrl) throws Throwable {
47 loadDataWithBaseUrlSync(mAwContents, mContentsClient.getOnPageFinishedHelper(),
48 data, mimeType, isBase64Encoded, baseUrl, historyUrl);
51 private static final String SCRIPT_FILE = "/script.js";
52 private static final String SCRIPT_LOADED = "Loaded";
53 private static final String SCRIPT_NOT_LOADED = "Not loaded";
54 private static final String SCRIPT_JS = "script_was_loaded = true;";
56 private String getScriptFileTestPageHtml(final String scriptUrl) {
59 " <title>" + SCRIPT_NOT_LOADED + "</title>" +
60 " <script src='" + scriptUrl + "'></script>" +
62 " <body onload=\"if(script_was_loaded) document.title='" + SCRIPT_LOADED + "'\">" +
67 private String getCrossOriginAccessTestPageHtml(final String iframeUrl) {
71 " function onload() {" +
73 " document.title = " +
74 " document.getElementById('frame').contentWindow.location.href;" +
76 " document.title = 'Exception';" +
81 " <body onload='onload()'>" +
82 " <iframe id='frame' src='" + iframeUrl + "'></iframe>" +
89 @Feature({"AndroidWebView"})
90 public void testImageLoad() throws Throwable {
91 TestWebServer webServer = null;
93 webServer = new TestWebServer(false);
94 webServer.setResponseBase64("/" + CommonResources.FAVICON_FILENAME,
95 CommonResources.FAVICON_DATA_BASE64, CommonResources.getImagePngHeaders(true));
97 AwSettings contentSettings = getAwSettingsOnUiThread(mAwContents);
98 contentSettings.setImagesEnabled(true);
99 contentSettings.setJavaScriptEnabled(true);
101 loadDataWithBaseUrlSync(
102 CommonResources.getOnImageLoadedHtml(CommonResources.FAVICON_FILENAME),
103 "text/html", false, webServer.getBaseUrl(), null);
105 assertEquals("5", getTitleOnUiThread(mAwContents));
107 if (webServer != null) webServer.shutdown();
112 @Feature({"AndroidWebView"})
113 public void testScriptLoad() throws Throwable {
114 TestWebServer webServer = null;
116 webServer = new TestWebServer(false);
118 final String scriptUrl = webServer.setResponse(SCRIPT_FILE, SCRIPT_JS,
119 CommonResources.getTextJavascriptHeaders(true));
120 final String pageHtml = getScriptFileTestPageHtml(scriptUrl);
122 getAwSettingsOnUiThread(mAwContents).setJavaScriptEnabled(true);
123 loadDataWithBaseUrlSync(pageHtml, "text/html", false, webServer.getBaseUrl(), null);
124 assertEquals(SCRIPT_LOADED, getTitleOnUiThread(mAwContents));
127 if (webServer != null) webServer.shutdown();
132 @Feature({"AndroidWebView"})
133 public void testSameOrigin() throws Throwable {
134 TestWebServer webServer = null;
136 webServer = new TestWebServer(false);
137 final String frameUrl = webServer.setResponse("/" + CommonResources.ABOUT_FILENAME,
138 CommonResources.ABOUT_HTML, CommonResources.getTextHtmlHeaders(true));
139 final String html = getCrossOriginAccessTestPageHtml(frameUrl);
141 getAwSettingsOnUiThread(mAwContents).setJavaScriptEnabled(true);
142 loadDataWithBaseUrlSync(html, "text/html", false, webServer.getBaseUrl(), null);
143 assertEquals(frameUrl, getTitleOnUiThread(mAwContents));
146 if (webServer != null) webServer.shutdown();
151 @Feature({"AndroidWebView"})
152 public void testCrossOrigin() throws Throwable {
153 TestWebServer webServer = null;
155 webServer = new TestWebServer(false);
156 final String frameUrl = webServer.setResponse("/" + CommonResources.ABOUT_FILENAME,
157 CommonResources.ABOUT_HTML, CommonResources.getTextHtmlHeaders(true));
158 final String html = getCrossOriginAccessTestPageHtml(frameUrl);
159 final String baseUrl = webServer.getBaseUrl().replaceFirst("localhost", "127.0.0.1");
161 getAwSettingsOnUiThread(mAwContents).setJavaScriptEnabled(true);
162 loadDataWithBaseUrlSync(html, "text/html", false, baseUrl, null);
164 assertEquals("Exception", getTitleOnUiThread(mAwContents));
167 if (webServer != null) webServer.shutdown();
172 @Feature({"AndroidWebView"})
173 public void testNullBaseUrl() throws Throwable {
174 getAwSettingsOnUiThread(mAwContents).setJavaScriptEnabled(true);
175 final String pageHtml = "<html><body onload='document.title=document.location.href'>" +
177 loadDataWithBaseUrlSync(pageHtml, "text/html", false, null, null);
178 assertEquals("about:blank", getTitleOnUiThread(mAwContents));
182 @Feature({"AndroidWebView"})
183 public void testloadDataWithBaseUrlCallsOnPageStarted() throws Throwable {
184 final String baseUrl = "http://base.com/";
185 TestCallbackHelperContainer.OnPageStartedHelper onPageStartedHelper =
186 mContentsClient.getOnPageStartedHelper();
187 final int callCount = onPageStartedHelper.getCallCount();
188 loadDataWithBaseUrlAsync(mAwContents, CommonResources.ABOUT_HTML, "text/html", false,
189 baseUrl, "about:blank");
190 onPageStartedHelper.waitForCallback(callCount);
191 assertEquals(baseUrl, onPageStartedHelper.getUrl());
195 @Feature({"AndroidWebView"})
196 public void testHistoryUrl() throws Throwable {
198 final String pageHtml = "<html><body>Hello, world!</body></html>";
199 final String baseUrl = "http://example.com";
200 // TODO(mnaganov): Use the same string as Android CTS suite uses
201 // once GURL issue is resolved (http://code.google.com/p/google-url/issues/detail?id=29)
202 final String historyUrl = "http://history.com/";
203 loadDataWithBaseUrlSync(pageHtml, "text/html", false, baseUrl, historyUrl);
204 assertEquals(historyUrl, HistoryUtils.getUrlOnUiThread(
205 getInstrumentation(), mContentViewCore));
207 loadDataWithBaseUrlSync(pageHtml, "text/html", false, baseUrl, null);
208 assertEquals("about:blank", HistoryUtils.getUrlOnUiThread(
209 getInstrumentation(), mContentViewCore));
213 @Feature({"AndroidWebView"})
214 public void testOnPageFinishedUrlIsBaseUrl() throws Throwable {
215 final String pageHtml = "<html><body>Hello, world!</body></html>";
216 final String baseUrl = "http://example.com/";
217 loadDataWithBaseUrlSync(pageHtml, "text/html", false, baseUrl, baseUrl);
218 loadDataWithBaseUrlSync(pageHtml, "text/html", false, baseUrl, baseUrl);
219 TestCallbackHelperContainer.OnPageFinishedHelper onPageFinishedHelper =
220 mContentsClient.getOnPageFinishedHelper();
221 assertEquals(baseUrl, onPageFinishedHelper.getUrl());
225 @Feature({"AndroidWebView"})
226 public void testHistoryUrlIgnoredWithDataSchemeBaseUrl() throws Throwable {
227 final String pageHtml = "<html><body>bar</body></html>";
228 final String historyUrl = "http://history.com/";
229 loadDataWithBaseUrlSync(pageHtml, "text/html", false, "data:foo", historyUrl);
230 assertEquals("data:text/html," + pageHtml, HistoryUtils.getUrlOnUiThread(
231 getInstrumentation(), mContentViewCore));
236 @Feature({"AndroidWebView"})
237 http://crbug.com/173274
240 public void testHistoryUrlNavigation() throws Throwable {
241 TestWebServer webServer = null;
243 webServer = new TestWebServer(false);
244 final String historyUrl = webServer.setResponse("/" + CommonResources.ABOUT_FILENAME,
245 CommonResources.ABOUT_HTML, CommonResources.getTextHtmlHeaders(true));
247 final String page1Title = "Page1";
248 final String page1Html = "<html><head><title>" + page1Title + "</title>" +
249 "<body>" + page1Title + "</body></html>";
251 loadDataWithBaseUrlSync(page1Html, "text/html", false, null, historyUrl);
252 assertEquals(page1Title, getTitleOnUiThread(mAwContents));
254 final String page2Title = "Page2";
255 final String page2Html = "<html><head><title>" + page2Title + "</title>" +
256 "<body>" + page2Title + "</body></html>";
258 final TestCallbackHelperContainer.OnPageFinishedHelper onPageFinishedHelper =
259 mContentsClient.getOnPageFinishedHelper();
260 loadDataSync(mAwContents, onPageFinishedHelper, page2Html, "text/html", false);
261 assertEquals(page2Title, getTitleOnUiThread(mAwContents));
263 HistoryUtils.goBackSync(getInstrumentation(), mContentViewCore, onPageFinishedHelper);
264 // The title of the 'about.html' specified via historyUrl.
265 assertEquals(CommonResources.ABOUT_TITLE, getTitleOnUiThread(mAwContents));
268 if (webServer != null) webServer.shutdown();
273 * @return true if |fileUrl| was accessible from a data url with |baseUrl| as it's
276 private boolean canAccessFileFromData(String baseUrl, String fileUrl) throws Throwable {
277 final String IMAGE_LOADED = "LOADED";
278 final String IMAGE_NOT_LOADED = "NOT_LOADED";
279 String data = "<html><body>" +
280 "<img src=\"" + fileUrl + "\" " +
281 "onload=\"document.title=\'" + IMAGE_LOADED + "\';\" " +
282 "onerror=\"document.title=\'" + IMAGE_NOT_LOADED + "\';\" />" +
285 loadDataWithBaseUrlSync(data, "text/html", false, baseUrl, null);
287 poll(new Callable<Boolean>() {
289 public Boolean call() throws Exception {
290 String title = getTitleOnUiThread(mAwContents);
291 return IMAGE_LOADED.equals(title) || IMAGE_NOT_LOADED.equals(title);
295 return IMAGE_LOADED.equals(getTitleOnUiThread(mAwContents));
299 @Feature({"AndroidWebView"})
300 public void testLoadDataWithBaseUrlAccessingFile() throws Throwable {
301 // Create a temporary file on the filesystem we can try to read.
302 File cacheDir = getActivity().getCacheDir();
303 File tempImage = File.createTempFile("test_image", ".png", cacheDir);
304 Bitmap bitmap = Bitmap.createBitmap(1, 1, Bitmap.Config.RGB_565);
305 FileOutputStream fos = new FileOutputStream(tempImage);
306 bitmap.compress(Bitmap.CompressFormat.PNG, 100, fos);
308 String imagePath = tempImage.getAbsolutePath();
310 AwSettings contentSettings = getAwSettingsOnUiThread(mAwContents);
311 contentSettings.setImagesEnabled(true);
312 contentSettings.setJavaScriptEnabled(true);
315 final String DATA_BASE_URL = "data:";
316 final String NON_DATA_BASE_URL = "http://example.com";
318 mAwContents.getSettings().setAllowFileAccess(false);
319 String token = "" + System.currentTimeMillis();
320 // All access to file://, including android_asset and android_res is blocked
321 // with a data: base URL, regardless of AwSettings.getAllowFileAccess().
322 assertFalse(canAccessFileFromData(DATA_BASE_URL,
323 "file:///android_asset/asset_icon.png?" + token));
324 assertFalse(canAccessFileFromData(DATA_BASE_URL,
325 "file:///android_res/raw/resource_icon.png?" + token));
326 assertFalse(canAccessFileFromData(DATA_BASE_URL, "file://" + imagePath + "?" + token));
328 // WebView always has access to android_asset and android_res for non-data
329 // base URLs and can access other file:// URLs based on the value of
330 // AwSettings.getAllowFileAccess().
331 assertTrue(canAccessFileFromData(NON_DATA_BASE_URL,
332 "file:///android_asset/asset_icon.png?" + token));
333 assertTrue(canAccessFileFromData(NON_DATA_BASE_URL,
334 "file:///android_res/raw/resource_icon.png?" + token));
335 assertFalse(canAccessFileFromData(NON_DATA_BASE_URL,
336 "file://" + imagePath + "?" + token));
339 mAwContents.getSettings().setAllowFileAccess(true);
340 // We should still be unable to access any file:// with when loading with a
341 // data: base URL, but we should now be able to access the wider file system
342 // (still restricted by OS-level permission checks) with a non-data base URL.
343 assertFalse(canAccessFileFromData(DATA_BASE_URL,
344 "file:///android_asset/asset_icon.png?" + token));
345 assertFalse(canAccessFileFromData(DATA_BASE_URL,
346 "file:///android_res/raw/resource_icon.png?" + token));
347 assertFalse(canAccessFileFromData(DATA_BASE_URL, "file://" + imagePath + "?" + token));
349 assertTrue(canAccessFileFromData(NON_DATA_BASE_URL,
350 "file:///android_asset/asset_icon.png?" + token));
351 assertTrue(canAccessFileFromData(NON_DATA_BASE_URL,
352 "file:///android_res/raw/resource_icon.png?" + token));
353 assertTrue(canAccessFileFromData(NON_DATA_BASE_URL,
354 "file://" + imagePath + "?" + token));
356 if (!tempImage.delete()) throw new AssertionError();