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.graphics.Canvas;
9 import android.graphics.Color;
10 import android.test.suitebuilder.annotation.SmallTest;
11 import android.util.Pair;
13 import org.chromium.android_webview.AwContents;
14 import org.chromium.android_webview.AwContentsClient.ShouldInterceptRequestParams;
15 import org.chromium.android_webview.AwWebResourceResponse;
16 import org.chromium.android_webview.test.util.AwTestTouchUtils;
17 import org.chromium.android_webview.test.util.CommonResources;
18 import org.chromium.android_webview.test.util.JSUtils;
19 import org.chromium.base.test.util.Feature;
20 import org.chromium.base.test.util.TestFileUtil;
21 import org.chromium.content.browser.test.util.CallbackHelper;
22 import org.chromium.content.browser.test.util.TestCallbackHelperContainer.OnReceivedErrorHelper;
23 import org.chromium.net.test.util.TestWebServer;
25 import java.io.ByteArrayInputStream;
26 import java.io.IOException;
27 import java.io.InputStream;
28 import java.util.ArrayList;
29 import java.util.HashMap;
30 import java.util.List;
32 import java.util.concurrent.Callable;
33 import java.util.concurrent.ConcurrentHashMap;
34 import java.util.concurrent.CountDownLatch;
37 * Tests for the WebViewClient.shouldInterceptRequest() method.
39 public class AwContentsClientShouldInterceptRequestTest extends AwTestBase {
41 private static class TestAwContentsClient
42 extends org.chromium.android_webview.test.TestAwContentsClient {
44 public static class ShouldInterceptRequestHelper extends CallbackHelper {
45 private List<String> mShouldInterceptRequestUrls = new ArrayList<String>();
46 private ConcurrentHashMap<String, AwWebResourceResponse> mReturnValuesByUrls =
47 new ConcurrentHashMap<String, AwWebResourceResponse>();
48 private ConcurrentHashMap<String, ShouldInterceptRequestParams> mParamsByUrls =
49 new ConcurrentHashMap<String, ShouldInterceptRequestParams>();
50 // This is read from the IO thread, so needs to be marked volatile.
51 private volatile AwWebResourceResponse mShouldInterceptRequestReturnValue = null;
52 void setReturnValue(AwWebResourceResponse value) {
53 mShouldInterceptRequestReturnValue = value;
55 void setReturnValueForUrl(String url, AwWebResourceResponse value) {
56 mReturnValuesByUrls.put(url, value);
58 public List<String> getUrls() {
59 assert getCallCount() > 0;
60 return mShouldInterceptRequestUrls;
62 public AwWebResourceResponse getReturnValue(String url) {
63 AwWebResourceResponse value = mReturnValuesByUrls.get(url);
64 if (value != null) return value;
65 return mShouldInterceptRequestReturnValue;
67 public ShouldInterceptRequestParams getParamsForUrl(String url) {
68 assert getCallCount() > 0;
69 assert mParamsByUrls.containsKey(url);
70 return mParamsByUrls.get(url);
72 public void notifyCalled(ShouldInterceptRequestParams params) {
73 mShouldInterceptRequestUrls.add(params.url);
74 mParamsByUrls.put(params.url, params);
79 public static class OnLoadResourceHelper extends CallbackHelper {
82 public String getUrl() {
83 assert getCallCount() > 0;
87 public void notifyCalled(String url) {
94 public AwWebResourceResponse shouldInterceptRequest(ShouldInterceptRequestParams params) {
95 AwWebResourceResponse returnValue =
96 mShouldInterceptRequestHelper.getReturnValue(params.url);
97 mShouldInterceptRequestHelper.notifyCalled(params);
102 public void onLoadResource(String url) {
103 super.onLoadResource(url);
104 mOnLoadResourceHelper.notifyCalled(url);
107 private ShouldInterceptRequestHelper mShouldInterceptRequestHelper;
108 private OnLoadResourceHelper mOnLoadResourceHelper;
110 public TestAwContentsClient() {
111 mShouldInterceptRequestHelper = new ShouldInterceptRequestHelper();
112 mOnLoadResourceHelper = new OnLoadResourceHelper();
115 public ShouldInterceptRequestHelper getShouldInterceptRequestHelper() {
116 return mShouldInterceptRequestHelper;
119 public OnLoadResourceHelper getOnLoadResourceHelper() {
120 return mOnLoadResourceHelper;
124 private static final int TEAPOT_STATUS_CODE = 418;
125 private static final String TEAPOT_RESPONSE_PHRASE = "I'm a teapot";
127 private String addPageToTestServer(TestWebServer webServer, String httpPath, String html) {
128 List<Pair<String, String>> headers = new ArrayList<Pair<String, String>>();
129 headers.add(Pair.create("Content-Type", "text/html"));
130 headers.add(Pair.create("Cache-Control", "no-store"));
131 return webServer.setResponse(httpPath, html, headers);
134 private String addAboutPageToTestServer(TestWebServer webServer) {
135 return addPageToTestServer(webServer, "/" + CommonResources.ABOUT_FILENAME,
136 CommonResources.ABOUT_HTML);
139 private AwWebResourceResponse stringToAwWebResourceResponse(String input) throws Throwable {
140 final String mimeType = "text/html";
141 final String encoding = "UTF-8";
143 return new AwWebResourceResponse(
144 mimeType, encoding, new ByteArrayInputStream(input.getBytes(encoding)));
147 private TestWebServer mWebServer;
148 private TestAwContentsClient mContentsClient;
149 private AwTestContainerView mTestContainerView;
150 private AwContents mAwContents;
151 private TestAwContentsClient.ShouldInterceptRequestHelper mShouldInterceptRequestHelper;
154 protected void setUp() throws Exception {
157 mContentsClient = new TestAwContentsClient();
158 mTestContainerView = createAwTestContainerViewOnMainSync(mContentsClient);
159 mAwContents = mTestContainerView.getAwContents();
160 mShouldInterceptRequestHelper = mContentsClient.getShouldInterceptRequestHelper();
162 mWebServer = TestWebServer.start();
166 protected void tearDown() throws Exception {
167 mWebServer.shutdown();
172 @Feature({"AndroidWebView"})
173 public void testCalledWithCorrectUrlParam() throws Throwable {
174 final String aboutPageUrl = addAboutPageToTestServer(mWebServer);
176 int onPageFinishedCallCount = mContentsClient.getOnPageFinishedHelper().getCallCount();
178 int callCount = mShouldInterceptRequestHelper.getCallCount();
179 loadUrlAsync(mAwContents, aboutPageUrl);
180 mShouldInterceptRequestHelper.waitForCallback(callCount);
181 assertEquals(1, mShouldInterceptRequestHelper.getUrls().size());
182 assertEquals(aboutPageUrl,
183 mShouldInterceptRequestHelper.getUrls().get(0));
185 mContentsClient.getOnPageFinishedHelper().waitForCallback(onPageFinishedCallCount);
186 assertEquals(CommonResources.ABOUT_TITLE, getTitleOnUiThread(mAwContents));
190 @Feature({"AndroidWebView"})
191 public void testCalledWithCorrectIsMainFrameParam() throws Throwable {
192 final String subframeUrl = addAboutPageToTestServer(mWebServer);
193 final String pageWithIframeUrl = addPageToTestServer(mWebServer, "/page_with_iframe.html",
194 CommonResources.makeHtmlPageFrom("",
195 "<iframe src=\"" + subframeUrl + "\"/>"));
197 int callCount = mShouldInterceptRequestHelper.getCallCount();
198 loadUrlAsync(mAwContents, pageWithIframeUrl);
199 mShouldInterceptRequestHelper.waitForCallback(callCount, 2);
200 assertEquals(2, mShouldInterceptRequestHelper.getUrls().size());
202 mShouldInterceptRequestHelper.getParamsForUrl(subframeUrl).isMainFrame);
204 mShouldInterceptRequestHelper.getParamsForUrl(pageWithIframeUrl).isMainFrame);
208 @Feature({"AndroidWebView"})
209 public void testCalledWithCorrectMethodParam() throws Throwable {
210 final String pageToPostToUrl = addAboutPageToTestServer(mWebServer);
211 final String pageWithFormUrl = addPageToTestServer(mWebServer, "/page_with_form.html",
212 CommonResources.makeHtmlPageWithSimplePostFormTo(pageToPostToUrl));
213 enableJavaScriptOnUiThread(mAwContents);
215 int callCount = mShouldInterceptRequestHelper.getCallCount();
216 loadUrlAsync(mAwContents, pageWithFormUrl);
217 mShouldInterceptRequestHelper.waitForCallback(callCount);
219 mShouldInterceptRequestHelper.getParamsForUrl(pageWithFormUrl).method);
221 callCount = mShouldInterceptRequestHelper.getCallCount();
222 JSUtils.clickOnLinkUsingJs(this, mAwContents,
223 mContentsClient.getOnEvaluateJavaScriptResultHelper(), "link");
224 mShouldInterceptRequestHelper.waitForCallback(callCount);
226 mShouldInterceptRequestHelper.getParamsForUrl(pageToPostToUrl).method);
230 @Feature({"AndroidWebView"})
231 public void testCalledWithCorrectHasUserGestureParam() throws Throwable {
232 final String aboutPageUrl = addAboutPageToTestServer(mWebServer);
233 final String pageWithLinkUrl = addPageToTestServer(mWebServer, "/page_with_link.html",
234 CommonResources.makeHtmlPageWithSimpleLinkTo(aboutPageUrl));
235 enableJavaScriptOnUiThread(mAwContents);
237 int callCount = mShouldInterceptRequestHelper.getCallCount();
238 loadUrlAsync(mAwContents, pageWithLinkUrl);
239 mShouldInterceptRequestHelper.waitForCallback(callCount);
241 mShouldInterceptRequestHelper.getParamsForUrl(pageWithLinkUrl).hasUserGesture);
243 // TODO(mkosiba): Remove this once we have a real API to wait for the page to load and
245 // http://crbug.com/364612
247 // The code here is waiting for the "link" (which is a full-screen blue div) to appear on
249 pollOnUiThread(new Callable<Boolean>() {
251 public Boolean call() throws Exception {
252 Bitmap bitmap = Bitmap.createBitmap(2, 2, Bitmap.Config.ARGB_8888);
253 Canvas canvas = new Canvas(bitmap);
254 canvas.translate(-(float) mTestContainerView.getWidth() / 2,
255 -(float) mTestContainerView.getHeight() / 2);
256 mAwContents.onDraw(canvas);
257 return bitmap.getPixel(0, 0) == Color.BLUE;
260 callCount = mShouldInterceptRequestHelper.getCallCount();
261 AwTestTouchUtils.simulateTouchCenterOfView(mTestContainerView);
262 mShouldInterceptRequestHelper.waitForCallback(callCount);
264 mShouldInterceptRequestHelper.getParamsForUrl(aboutPageUrl).hasUserGesture);
268 @Feature({"AndroidWebView"})
269 public void testCalledWithCorrectHeadersParam() throws Throwable {
270 final String headerName = "X-Test-Header-Name";
271 final String headerValue = "TestHeaderValue";
272 final String syncGetUrl = addPageToTestServer(mWebServer, "/intercept_me",
273 CommonResources.ABOUT_HTML);
274 final String mainPageUrl = addPageToTestServer(mWebServer, "/main",
275 CommonResources.makeHtmlPageFrom("",
277 " var xhr = new XMLHttpRequest();" +
278 " xhr.open('GET', '" + syncGetUrl + "', false);" +
279 " xhr.setRequestHeader('" + headerName + "', '" + headerValue + "'); " +
282 enableJavaScriptOnUiThread(mAwContents);
284 int callCount = mShouldInterceptRequestHelper.getCallCount();
285 loadUrlAsync(mAwContents, mainPageUrl);
286 mShouldInterceptRequestHelper.waitForCallback(callCount, 2);
288 Map<String, String> headers =
289 mShouldInterceptRequestHelper.getParamsForUrl(syncGetUrl).requestHeaders;
290 assertTrue(headers.containsKey(headerName));
291 assertEquals(headerValue, headers.get(headerName));
295 @Feature({"AndroidWebView"})
296 public void testOnLoadResourceCalledWithCorrectUrl() throws Throwable {
297 final String aboutPageUrl = addAboutPageToTestServer(mWebServer);
298 final TestAwContentsClient.OnLoadResourceHelper onLoadResourceHelper =
299 mContentsClient.getOnLoadResourceHelper();
301 int callCount = onLoadResourceHelper.getCallCount();
303 loadUrlAsync(mAwContents, aboutPageUrl);
305 onLoadResourceHelper.waitForCallback(callCount);
306 assertEquals(aboutPageUrl, onLoadResourceHelper.getUrl());
310 @Feature({"AndroidWebView"})
311 public void testDoesNotCrashOnInvalidData() throws Throwable {
312 final String aboutPageUrl = addAboutPageToTestServer(mWebServer);
314 mShouldInterceptRequestHelper.setReturnValue(
315 new AwWebResourceResponse("text/html", "UTF-8", null));
316 int callCount = mShouldInterceptRequestHelper.getCallCount();
317 loadUrlAsync(mAwContents, aboutPageUrl);
318 mShouldInterceptRequestHelper.waitForCallback(callCount);
320 mShouldInterceptRequestHelper.setReturnValue(
321 new AwWebResourceResponse(null, null, new ByteArrayInputStream(new byte[0])));
322 callCount = mShouldInterceptRequestHelper.getCallCount();
323 loadUrlAsync(mAwContents, aboutPageUrl);
324 mShouldInterceptRequestHelper.waitForCallback(callCount);
326 mShouldInterceptRequestHelper.setReturnValue(
327 new AwWebResourceResponse(null, null, null));
328 callCount = mShouldInterceptRequestHelper.getCallCount();
329 loadUrlAsync(mAwContents, aboutPageUrl);
330 mShouldInterceptRequestHelper.waitForCallback(callCount);
333 private static class EmptyInputStream extends InputStream {
335 public int available() {
340 public int read() throws IOException {
345 public int read(byte b[]) throws IOException {
350 public int read(byte b[], int off, int len) throws IOException {
355 public long skip(long n) throws IOException {
357 throw new IOException("skipping negative number of bytes");
363 @Feature({"AndroidWebView"})
364 public void testDoesNotCrashOnEmptyStream() throws Throwable {
365 final String aboutPageUrl = addAboutPageToTestServer(mWebServer);
367 mShouldInterceptRequestHelper.setReturnValue(
368 new AwWebResourceResponse("text/html", "UTF-8", new EmptyInputStream()));
369 int shouldInterceptRequestCallCount = mShouldInterceptRequestHelper.getCallCount();
370 int onPageFinishedCallCount = mContentsClient.getOnPageFinishedHelper().getCallCount();
372 loadUrlAsync(mAwContents, aboutPageUrl);
374 mShouldInterceptRequestHelper.waitForCallback(shouldInterceptRequestCallCount);
375 mContentsClient.getOnPageFinishedHelper().waitForCallback(onPageFinishedCallCount);
378 private static class ThrowingInputStream extends EmptyInputStream {
380 public int available() {
385 public int read() throws IOException {
386 throw new IOException("test exception");
390 public int read(byte b[]) throws IOException {
391 throw new IOException("test exception");
395 public int read(byte b[], int off, int len) throws IOException {
396 throw new IOException("test exception");
400 public long skip(long n) throws IOException {
406 @Feature({"AndroidWebView"})
407 public void testDoesNotCrashOnThrowingStream() throws Throwable {
408 final String aboutPageUrl = addAboutPageToTestServer(mWebServer);
410 mShouldInterceptRequestHelper.setReturnValue(
411 new AwWebResourceResponse("text/html", "UTF-8", new ThrowingInputStream()));
412 int shouldInterceptRequestCallCount = mShouldInterceptRequestHelper.getCallCount();
413 int onPageFinishedCallCount = mContentsClient.getOnPageFinishedHelper().getCallCount();
415 loadUrlAsync(mAwContents, aboutPageUrl);
417 mShouldInterceptRequestHelper.waitForCallback(shouldInterceptRequestCallCount);
418 mContentsClient.getOnPageFinishedHelper().waitForCallback(onPageFinishedCallCount);
421 private static class SlowAwWebResourceResponse extends AwWebResourceResponse {
422 private CallbackHelper mReadStartedCallbackHelper = new CallbackHelper();
423 private CountDownLatch mLatch = new CountDownLatch(1);
425 public SlowAwWebResourceResponse(String mimeType, String encoding, InputStream data) {
426 super(mimeType, encoding, data);
430 public InputStream getData() {
431 mReadStartedCallbackHelper.notifyCalled();
434 } catch (InterruptedException e) {
437 return super.getData();
440 public void unblockReads() {
444 public CallbackHelper getReadStartedCallbackHelper() {
445 return mReadStartedCallbackHelper;
450 @Feature({"AndroidWebView"})
451 public void testDoesNotCrashOnSlowStream() throws Throwable {
452 final String aboutPageUrl = addAboutPageToTestServer(mWebServer);
453 final String aboutPageData = makePageWithTitle("some title");
454 final String encoding = "UTF-8";
455 final SlowAwWebResourceResponse slowAwWebResourceResponse =
456 new SlowAwWebResourceResponse("text/html", encoding,
457 new ByteArrayInputStream(aboutPageData.getBytes(encoding)));
459 mShouldInterceptRequestHelper.setReturnValue(slowAwWebResourceResponse);
460 int callCount = slowAwWebResourceResponse.getReadStartedCallbackHelper().getCallCount();
461 loadUrlAsync(mAwContents, aboutPageUrl);
462 slowAwWebResourceResponse.getReadStartedCallbackHelper().waitForCallback(callCount);
464 // Now the AwContents is "stuck" waiting for the SlowInputStream to finish reading so we
465 // delete it to make sure that the dangling 'read' task doesn't cause a crash. Unfortunately
466 // this will not always lead to a crash but it should happen often enough for us to notice.
468 runTestOnUiThread(new Runnable() {
471 getActivity().removeAllViews();
474 destroyAwContentsOnMainSync(mAwContents);
475 pollOnUiThread(new Callable<Boolean>() {
477 public Boolean call() {
478 return AwContents.getNativeInstanceCount() == 0;
482 slowAwWebResourceResponse.unblockReads();
486 @Feature({"AndroidWebView"})
487 public void testHttpStatusCodeAndText() throws Throwable {
488 final String syncGetUrl = mWebServer.getResponseUrl("/intercept_me");
489 final String syncGetJs =
491 " var xhr = new XMLHttpRequest();" +
492 " xhr.open('GET', '" + syncGetUrl + "', false);" +
494 " console.info('xhr.status = ' + xhr.status);" +
495 " console.info('xhr.statusText = ' + xhr.statusText);" +
496 " return '[' + xhr.status + '][' + xhr.statusText + ']';" +
498 enableJavaScriptOnUiThread(mAwContents);
500 final String aboutPageUrl = addAboutPageToTestServer(mWebServer);
501 loadUrlSync(mAwContents, mContentsClient.getOnPageFinishedHelper(), aboutPageUrl);
503 mShouldInterceptRequestHelper.setReturnValue(
504 new AwWebResourceResponse("text/html", "UTF-8", null));
505 assertEquals("\"[404][Not Found]\"",
506 executeJavaScriptAndWaitForResult(mAwContents, mContentsClient, syncGetJs));
508 mShouldInterceptRequestHelper.setReturnValue(
509 new AwWebResourceResponse("text/html", "UTF-8", new EmptyInputStream()));
510 assertEquals("\"[200][OK]\"",
511 executeJavaScriptAndWaitForResult(mAwContents, mContentsClient, syncGetJs));
513 mShouldInterceptRequestHelper.setReturnValue(
514 new AwWebResourceResponse("text/html", "UTF-8", new EmptyInputStream(),
515 TEAPOT_STATUS_CODE, TEAPOT_RESPONSE_PHRASE, new HashMap<String, String>()));
516 assertEquals("\"[" + TEAPOT_STATUS_CODE + "][" + TEAPOT_RESPONSE_PHRASE + "]\"",
517 executeJavaScriptAndWaitForResult(mAwContents, mContentsClient, syncGetJs));
520 private String getHeaderValue(AwContents awContents, TestAwContentsClient contentsClient,
521 String url, String headerName) throws Exception {
522 final String syncGetJs =
524 " var xhr = new XMLHttpRequest();" +
525 " xhr.open('GET', '" + url + "', false);" +
527 " console.info(xhr.getAllResponseHeaders());" +
528 " return xhr.getResponseHeader('" + headerName + "');" +
530 String header = executeJavaScriptAndWaitForResult(awContents, contentsClient, syncGetJs);
532 if (header.equals("null"))
534 // JSON stringification applied by executeJavaScriptAndWaitForResult adds quotes
535 // around returned strings.
536 assertTrue(header.length() > 2);
537 assertEquals('"', header.charAt(0));
538 assertEquals('"', header.charAt(header.length() - 1));
539 return header.substring(1, header.length() - 1);
543 @Feature({"AndroidWebView"})
544 public void testHttpResponseClientViaHeader() throws Throwable {
545 final String clientResponseHeaderName = "Client-Via";
546 final String clientResponseHeaderValue = "shouldInterceptRequest";
547 final String syncGetUrl = mWebServer.getResponseUrl("/intercept_me");
548 enableJavaScriptOnUiThread(mAwContents);
550 final String aboutPageUrl = addAboutPageToTestServer(mWebServer);
551 loadUrlSync(mAwContents, mContentsClient.getOnPageFinishedHelper(), aboutPageUrl);
553 // The response header is set regardless of whether the embedder has provided a
554 // valid resource stream.
555 mShouldInterceptRequestHelper.setReturnValue(
556 new AwWebResourceResponse("text/html", "UTF-8", null));
557 assertEquals(clientResponseHeaderValue,
558 getHeaderValue(mAwContents, mContentsClient, syncGetUrl, clientResponseHeaderName));
559 mShouldInterceptRequestHelper.setReturnValue(
560 new AwWebResourceResponse("text/html", "UTF-8", new EmptyInputStream()));
561 assertEquals(clientResponseHeaderValue,
562 getHeaderValue(mAwContents, mContentsClient, syncGetUrl, clientResponseHeaderName));
567 @Feature({"AndroidWebView"})
568 public void testHttpResponseHeader() throws Throwable {
569 final String clientResponseHeaderName = "X-Test-Header-Name";
570 final String clientResponseHeaderValue = "TestHeaderValue";
571 final String syncGetUrl = mWebServer.getResponseUrl("/intercept_me");
572 final Map<String, String> headers = new HashMap<String, String>();
573 headers.put(clientResponseHeaderName, clientResponseHeaderValue);
574 enableJavaScriptOnUiThread(mAwContents);
576 final String aboutPageUrl = addAboutPageToTestServer(mWebServer);
577 loadUrlSync(mAwContents, mContentsClient.getOnPageFinishedHelper(), aboutPageUrl);
579 mShouldInterceptRequestHelper.setReturnValue(
580 new AwWebResourceResponse("text/html", "UTF-8", null, 0, null, headers));
581 assertEquals(clientResponseHeaderValue,
582 getHeaderValue(mAwContents, mContentsClient, syncGetUrl, clientResponseHeaderName));
586 @Feature({"AndroidWebView"})
587 public void testNullHttpResponseHeaders() throws Throwable {
588 final String syncGetUrl = mWebServer.getResponseUrl("/intercept_me");
589 enableJavaScriptOnUiThread(mAwContents);
591 final String aboutPageUrl = addAboutPageToTestServer(mWebServer);
592 loadUrlSync(mAwContents, mContentsClient.getOnPageFinishedHelper(), aboutPageUrl);
594 mShouldInterceptRequestHelper.setReturnValue(
595 new AwWebResourceResponse("text/html", "UTF-8", null, 0, null, null));
596 assertEquals(null, getHeaderValue(mAwContents, mContentsClient, syncGetUrl, "Some-Header"));
599 private String makePageWithTitle(String title) {
600 return CommonResources.makeHtmlPageFrom("<title>" + title + "</title>",
601 "<div> The title is: " + title + " </div>");
605 @Feature({"AndroidWebView"})
606 public void testCanInterceptMainFrame() throws Throwable {
607 final String expectedTitle = "testShouldInterceptRequestCanInterceptMainFrame";
608 final String expectedPage = makePageWithTitle(expectedTitle);
610 mShouldInterceptRequestHelper.setReturnValue(
611 stringToAwWebResourceResponse(expectedPage));
613 final String aboutPageUrl = addAboutPageToTestServer(mWebServer);
615 loadUrlSync(mAwContents, mContentsClient.getOnPageFinishedHelper(), aboutPageUrl);
617 assertEquals(expectedTitle, getTitleOnUiThread(mAwContents));
618 assertEquals(0, mWebServer.getRequestCount("/" + CommonResources.ABOUT_FILENAME));
622 @Feature({"AndroidWebView"})
623 public void testDoesNotChangeReportedUrl() throws Throwable {
624 mShouldInterceptRequestHelper.setReturnValue(
625 stringToAwWebResourceResponse(makePageWithTitle("some title")));
627 final String aboutPageUrl = addAboutPageToTestServer(mWebServer);
629 loadUrlSync(mAwContents, mContentsClient.getOnPageFinishedHelper(), aboutPageUrl);
631 assertEquals(aboutPageUrl, mContentsClient.getOnPageFinishedHelper().getUrl());
632 assertEquals(aboutPageUrl, mContentsClient.getOnPageStartedHelper().getUrl());
636 @Feature({"AndroidWebView"})
637 public void testNullInputStreamCausesErrorForMainFrame() throws Throwable {
638 final OnReceivedErrorHelper onReceivedErrorHelper =
639 mContentsClient.getOnReceivedErrorHelper();
641 mShouldInterceptRequestHelper.setReturnValue(
642 new AwWebResourceResponse("text/html", "UTF-8", null));
644 final String aboutPageUrl = addAboutPageToTestServer(mWebServer);
645 final int callCount = onReceivedErrorHelper.getCallCount();
646 loadUrlAsync(mAwContents, aboutPageUrl);
647 onReceivedErrorHelper.waitForCallback(callCount);
648 assertEquals(0, mWebServer.getRequestCount("/" + CommonResources.ABOUT_FILENAME));
652 @Feature({"AndroidWebView"})
653 public void testCalledForImage() throws Throwable {
654 final String imagePath = "/" + CommonResources.FAVICON_FILENAME;
655 mWebServer.setResponseBase64(imagePath,
656 CommonResources.FAVICON_DATA_BASE64, CommonResources.getImagePngHeaders(true));
657 final String pageWithImage =
658 addPageToTestServer(mWebServer, "/page_with_image.html",
659 CommonResources.getOnImageLoadedHtml(CommonResources.FAVICON_FILENAME));
661 int callCount = mShouldInterceptRequestHelper.getCallCount();
662 loadUrlSync(mAwContents, mContentsClient.getOnPageFinishedHelper(), pageWithImage);
663 mShouldInterceptRequestHelper.waitForCallback(callCount, 2);
665 assertEquals(2, mShouldInterceptRequestHelper.getUrls().size());
666 assertTrue(mShouldInterceptRequestHelper.getUrls().get(1).endsWith(
667 CommonResources.FAVICON_FILENAME));
671 @Feature({"AndroidWebView"})
672 public void testOnReceivedErrorCallback() throws Throwable {
673 mShouldInterceptRequestHelper.setReturnValue(new AwWebResourceResponse(null, null, null));
674 OnReceivedErrorHelper onReceivedErrorHelper = mContentsClient.getOnReceivedErrorHelper();
675 int onReceivedErrorHelperCallCount = onReceivedErrorHelper.getCallCount();
676 loadUrlSync(mAwContents, mContentsClient.getOnPageFinishedHelper(), "foo://bar");
677 onReceivedErrorHelper.waitForCallback(onReceivedErrorHelperCallCount, 1);
681 @Feature({"AndroidWebView"})
682 public void testNoOnReceivedErrorCallback() throws Throwable {
683 final String imagePath = "/" + CommonResources.FAVICON_FILENAME;
684 final String imageUrl = mWebServer.setResponseBase64(imagePath,
685 CommonResources.FAVICON_DATA_BASE64, CommonResources.getImagePngHeaders(true));
686 final String pageWithImage =
687 addPageToTestServer(mWebServer, "/page_with_image.html",
688 CommonResources.getOnImageLoadedHtml(CommonResources.FAVICON_FILENAME));
689 mShouldInterceptRequestHelper.setReturnValueForUrl(
690 imageUrl, new AwWebResourceResponse(null, null, null));
691 OnReceivedErrorHelper onReceivedErrorHelper = mContentsClient.getOnReceivedErrorHelper();
692 int onReceivedErrorHelperCallCount = onReceivedErrorHelper.getCallCount();
693 loadUrlSync(mAwContents, mContentsClient.getOnPageFinishedHelper(), pageWithImage);
694 assertEquals(onReceivedErrorHelperCallCount, onReceivedErrorHelper.getCallCount());
698 @Feature({"AndroidWebView"})
699 public void testCalledForIframe() throws Throwable {
700 final String aboutPageUrl = addAboutPageToTestServer(mWebServer);
701 final String pageWithIframeUrl = addPageToTestServer(mWebServer, "/page_with_iframe.html",
702 CommonResources.makeHtmlPageFrom("",
703 "<iframe src=\"" + aboutPageUrl + "\"/>"));
705 int callCount = mShouldInterceptRequestHelper.getCallCount();
706 loadUrlSync(mAwContents, mContentsClient.getOnPageFinishedHelper(), pageWithIframeUrl);
707 mShouldInterceptRequestHelper.waitForCallback(callCount, 2);
708 assertEquals(2, mShouldInterceptRequestHelper.getUrls().size());
709 assertEquals(aboutPageUrl, mShouldInterceptRequestHelper.getUrls().get(1));
712 private void calledForUrlTemplate(final String url) throws Exception {
713 int callCount = mShouldInterceptRequestHelper.getCallCount();
714 int onPageStartedCallCount = mContentsClient.getOnPageStartedHelper().getCallCount();
715 loadUrlAsync(mAwContents, url);
716 mShouldInterceptRequestHelper.waitForCallback(callCount);
717 assertEquals(url, mShouldInterceptRequestHelper.getUrls().get(0));
719 mContentsClient.getOnPageStartedHelper().waitForCallback(onPageStartedCallCount);
720 assertEquals(onPageStartedCallCount + 1,
721 mContentsClient.getOnPageStartedHelper().getCallCount());
724 private void notCalledForUrlTemplate(final String url) throws Exception {
725 int callCount = mShouldInterceptRequestHelper.getCallCount();
726 loadUrlSync(mAwContents, mContentsClient.getOnPageFinishedHelper(), url);
727 // The intercepting must happen before onPageFinished. Since the IPC messages from the
728 // renderer should be delivered in order waiting for onPageFinished is sufficient to
729 // 'flush' any pending interception messages.
730 assertEquals(callCount, mShouldInterceptRequestHelper.getCallCount());
734 @Feature({"AndroidWebView"})
735 public void testCalledForUnsupportedSchemes() throws Throwable {
736 calledForUrlTemplate("foobar://resource/1");
740 @Feature({"AndroidWebView"})
741 public void testCalledForNonexistentFiles() throws Throwable {
742 calledForUrlTemplate("file:///somewhere/something");
746 @Feature({"AndroidWebView"})
747 public void testCalledForExistingFiles() throws Throwable {
748 final String tmpDir = getInstrumentation().getTargetContext().getCacheDir().getPath();
749 final String fileName = tmpDir + "/testfile.html";
750 final String title = "existing file title";
751 TestFileUtil.deleteFile(fileName); // Remove leftover file if any.
752 TestFileUtil.createNewHtmlFile(fileName, title, "");
753 final String existingFileUrl = "file://" + fileName;
755 int callCount = mShouldInterceptRequestHelper.getCallCount();
756 int onPageFinishedCallCount = mContentsClient.getOnPageFinishedHelper().getCallCount();
757 loadUrlAsync(mAwContents, existingFileUrl);
758 mShouldInterceptRequestHelper.waitForCallback(callCount);
759 assertEquals(existingFileUrl, mShouldInterceptRequestHelper.getUrls().get(0));
761 mContentsClient.getOnPageFinishedHelper().waitForCallback(onPageFinishedCallCount);
762 assertEquals(title, getTitleOnUiThread(mAwContents));
763 assertEquals(onPageFinishedCallCount + 1,
764 mContentsClient.getOnPageFinishedHelper().getCallCount());
768 @Feature({"AndroidWebView"})
769 public void testNotCalledForExistingResource() throws Throwable {
770 notCalledForUrlTemplate("file:///android_res/raw/resource_file.html");
774 @Feature({"AndroidWebView"})
775 public void testCalledForNonexistentResource() throws Throwable {
776 calledForUrlTemplate("file:///android_res/raw/no_file.html");
780 @Feature({"AndroidWebView"})
781 public void testNotCalledForExistingAsset() throws Throwable {
782 notCalledForUrlTemplate("file:///android_asset/asset_file.html");
786 @Feature({"AndroidWebView"})
787 public void testCalledForNonexistentAsset() throws Throwable {
788 calledForUrlTemplate("file:///android_res/raw/no_file.html");
792 @Feature({"AndroidWebView"})
793 public void testNotCalledForExistingContentUrl() throws Throwable {
794 final String contentResourceName = "target";
795 final String existingContentUrl = TestContentProvider.createContentUrl(contentResourceName);
797 notCalledForUrlTemplate(existingContentUrl);
799 int contentRequestCount = TestContentProvider.getResourceRequestCount(
800 getInstrumentation().getTargetContext(), contentResourceName);
801 assertEquals(1, contentRequestCount);
805 @Feature({"AndroidWebView"})
806 public void testCalledForNonexistentContentUrl() throws Throwable {
807 calledForUrlTemplate("content://org.chromium.webview.NoSuchProvider/foo");