Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / android_webview / javatests / src / org / chromium / android_webview / test / AwContentsClientShouldOverrideUrlLoadingTest.java
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.
4
5 package org.chromium.android_webview.test;
6
7 import android.test.suitebuilder.annotation.SmallTest;
8 import android.util.Pair;
9
10 import org.chromium.android_webview.AwContents;
11 import org.chromium.android_webview.test.util.CommonResources;
12 import org.chromium.android_webview.test.util.JSUtils;
13 import org.chromium.base.test.util.Feature;
14 import org.chromium.content.browser.test.util.CallbackHelper;
15 import org.chromium.content.browser.test.util.TestCallbackHelperContainer.OnPageStartedHelper;
16 import org.chromium.content.browser.test.util.TestCallbackHelperContainer.OnReceivedErrorHelper;
17 import org.chromium.content_public.browser.LoadUrlParams;
18 import org.chromium.net.test.util.TestWebServer;
19
20 import java.util.ArrayList;
21 import java.util.List;
22 import java.util.concurrent.Callable;
23 import java.util.concurrent.TimeUnit;
24
25 /**
26  * Tests for the WebViewClient.shouldOverrideUrlLoading() method.
27  */
28 public class AwContentsClientShouldOverrideUrlLoadingTest extends AwTestBase {
29     private static final String ABOUT_BLANK_URL = "about:blank";
30     private static final String DATA_URL = "data:text/html,<div/>";
31     private static final String REDIRECT_TARGET_PATH = "/redirect_target.html";
32     private static final String TITLE = "TITLE";
33
34     private TestWebServer mWebServer;
35
36     @Override
37     protected void setUp() throws Exception {
38         super.setUp();
39         mWebServer = new TestWebServer(false);
40     }
41
42     @Override
43     protected void tearDown() throws Exception {
44         mWebServer.shutdown();
45         super.tearDown();
46     }
47
48     private void clickOnLinkUsingJs(final AwContents awContents,
49             final TestAwContentsClient contentsClient) throws Throwable {
50         enableJavaScriptOnUiThread(awContents);
51         JSUtils.clickOnLinkUsingJs(this, awContents,
52                 contentsClient.getOnEvaluateJavaScriptResultHelper(), "link");
53     }
54
55     // Since this value is read on the UI thread, it's simpler to set it there too.
56     void setShouldOverrideUrlLoadingReturnValueOnUiThread(
57             final TestAwContentsClient.ShouldOverrideUrlLoadingHelper shouldOverrideHelper,
58             final boolean value) throws Throwable {
59         runTestOnUiThread(new Runnable() {
60             @Override
61             public void run() {
62                 shouldOverrideHelper.setShouldOverrideUrlLoadingReturnValue(value);
63             }
64         });
65     }
66
67     private String getTestPageCommonHeaders() {
68         return "<title>" + TITLE + "</title> ";
69     }
70
71     private String makeHtmlPageFrom(String headers, String body) {
72         return CommonResources.makeHtmlPageFrom(getTestPageCommonHeaders() + headers, body);
73     }
74
75     private String getHtmlForPageWithJsAssignLinkTo(String url) {
76         return makeHtmlPageFrom("",
77                 "<img onclick=\"location.href='" + url + "'\" class=\"big\" id=\"link\" />");
78     }
79
80     private String getHtmlForPageWithJsReplaceLinkTo(String url) {
81         return makeHtmlPageFrom("",
82                 "<img onclick=\"location.replace('" + url + "');\" class=\"big\" id=\"link\" />");
83     }
84
85     private String getHtmlForPageWithMetaRefreshRedirectTo(String url) {
86         return makeHtmlPageFrom("<meta http-equiv=\"refresh\" content=\"0;url=" + url + "\" />",
87                 "<div>Meta refresh redirect</div>");
88     }
89
90     private String getHtmlForPageWithJsRedirectTo(String url, String method, int timeout) {
91         return makeHtmlPageFrom(
92                 "<script>" +
93                   "function doRedirectAssign() {" +
94                     "location.href = '" + url + "';" +
95                   "} " +
96                   "function doRedirectReplace() {" +
97                     "location.replace('" + url + "');" +
98                   "} " +
99                 "</script>",
100                 String.format("<iframe onLoad=\"setTimeout('doRedirect%s()', %d);\" />",
101                     method, timeout));
102     }
103
104     private String addPageToTestServer(TestWebServer webServer, String httpPath, String html) {
105         List<Pair<String, String>> headers = new ArrayList<Pair<String, String>>();
106         headers.add(Pair.create("Content-Type", "text/html"));
107         headers.add(Pair.create("Cache-Control", "no-store"));
108         return webServer.setResponse(httpPath, html, headers);
109     }
110
111     private String createRedirectTargetPage(TestWebServer webServer) {
112         return addPageToTestServer(webServer, REDIRECT_TARGET_PATH,
113                 makeHtmlPageFrom("", "<div>This is the end of the redirect chain</div>"));
114     }
115
116     @SmallTest
117     @Feature({"AndroidWebView", "Navigation"})
118     public void testNotCalledOnLoadUrl() throws Throwable {
119         final TestAwContentsClient contentsClient = new TestAwContentsClient();
120         final AwTestContainerView testContainerView =
121             createAwTestContainerViewOnMainSync(contentsClient);
122         final AwContents awContents = testContainerView.getAwContents();
123         TestAwContentsClient.ShouldOverrideUrlLoadingHelper shouldOverrideUrlLoadingHelper =
124             contentsClient.getShouldOverrideUrlLoadingHelper();
125
126         loadDataSync(awContents, contentsClient.getOnPageFinishedHelper(),
127                 CommonResources.makeHtmlPageWithSimpleLinkTo(DATA_URL), "text/html", false);
128
129         assertEquals(0, shouldOverrideUrlLoadingHelper.getCallCount());
130     }
131
132     private void waitForNavigationRunnableAndAssertTitleChanged(AwContents awContents,
133             CallbackHelper onPageFinishedHelper,
134             Runnable navigationRunnable) throws Exception {
135         final int callCount = onPageFinishedHelper.getCallCount();
136         final String oldTitle = getTitleOnUiThread(awContents);
137         getInstrumentation().runOnMainSync(navigationRunnable);
138         onPageFinishedHelper.waitForCallback(callCount);
139         assertFalse(oldTitle.equals(getTitleOnUiThread(awContents)));
140     }
141
142     @SmallTest
143     @Feature({"AndroidWebView", "Navigation"})
144     public void testNotCalledOnBackForwardNavigation() throws Throwable {
145         final TestAwContentsClient contentsClient = new TestAwContentsClient();
146         final AwTestContainerView testContainerView =
147             createAwTestContainerViewOnMainSync(contentsClient);
148         final AwContents awContents = testContainerView.getAwContents();
149         TestAwContentsClient.ShouldOverrideUrlLoadingHelper shouldOverrideUrlLoadingHelper =
150             contentsClient.getShouldOverrideUrlLoadingHelper();
151         final String[] pageTitles = new String[] { "page1", "page2", "page3" };
152
153         for (String title : pageTitles) {
154             loadDataSync(awContents, contentsClient.getOnPageFinishedHelper(),
155                     CommonResources.makeHtmlPageFrom("<title>" + title + "</title>", ""),
156                     "text/html", false);
157         }
158         assertEquals(0, shouldOverrideUrlLoadingHelper.getCallCount());
159
160         waitForNavigationRunnableAndAssertTitleChanged(awContents,
161                 contentsClient.getOnPageFinishedHelper(), new Runnable() {
162             @Override
163             public void run() {
164                 awContents.goBack();
165             }
166         });
167         assertEquals(0, shouldOverrideUrlLoadingHelper.getCallCount());
168
169         waitForNavigationRunnableAndAssertTitleChanged(awContents,
170                 contentsClient.getOnPageFinishedHelper(), new Runnable() {
171             @Override
172             public void run() {
173                 awContents.goForward();
174             }
175         });
176         assertEquals(0, shouldOverrideUrlLoadingHelper.getCallCount());
177
178         waitForNavigationRunnableAndAssertTitleChanged(awContents,
179                 contentsClient.getOnPageFinishedHelper(), new Runnable() {
180             @Override
181             public void run() {
182                 awContents.goBackOrForward(-2);
183             }
184         });
185         assertEquals(0, shouldOverrideUrlLoadingHelper.getCallCount());
186
187         waitForNavigationRunnableAndAssertTitleChanged(awContents,
188                 contentsClient.getOnPageFinishedHelper(), new Runnable() {
189             @Override
190             public void run() {
191                 awContents.goBackOrForward(1);
192             }
193         });
194         assertEquals(0, shouldOverrideUrlLoadingHelper.getCallCount());
195     }
196
197     @SmallTest
198     @Feature({"AndroidWebView", "Navigation"})
199     public void testCantBlockLoads() throws Throwable {
200         final TestAwContentsClient contentsClient = new TestAwContentsClient();
201         final AwTestContainerView testContainerView =
202             createAwTestContainerViewOnMainSync(contentsClient);
203         final AwContents awContents = testContainerView.getAwContents();
204         TestAwContentsClient.ShouldOverrideUrlLoadingHelper shouldOverrideUrlLoadingHelper =
205             contentsClient.getShouldOverrideUrlLoadingHelper();
206
207         setShouldOverrideUrlLoadingReturnValueOnUiThread(shouldOverrideUrlLoadingHelper, true);
208
209         loadDataSync(awContents, contentsClient.getOnPageFinishedHelper(),
210                 CommonResources.makeHtmlPageWithSimpleLinkTo(getTestPageCommonHeaders(),
211                     DATA_URL), "text/html", false);
212
213         assertEquals(TITLE, getTitleOnUiThread(awContents));
214     }
215
216     @SmallTest
217     @Feature({"AndroidWebView", "Navigation"})
218     public void testCalledBeforeOnPageStarted() throws Throwable {
219         final TestAwContentsClient contentsClient = new TestAwContentsClient();
220         final AwTestContainerView testContainerView =
221             createAwTestContainerViewOnMainSync(contentsClient);
222         final AwContents awContents = testContainerView.getAwContents();
223         TestAwContentsClient.ShouldOverrideUrlLoadingHelper shouldOverrideUrlLoadingHelper =
224             contentsClient.getShouldOverrideUrlLoadingHelper();
225         OnPageStartedHelper onPageStartedHelper = contentsClient.getOnPageStartedHelper();
226
227         loadDataSync(awContents, contentsClient.getOnPageFinishedHelper(),
228                 CommonResources.makeHtmlPageWithSimpleLinkTo(DATA_URL), "text/html", false);
229
230         final int shouldOverrideUrlLoadingCallCount = shouldOverrideUrlLoadingHelper.getCallCount();
231         final int onPageStartedCallCount = onPageStartedHelper.getCallCount();
232         setShouldOverrideUrlLoadingReturnValueOnUiThread(shouldOverrideUrlLoadingHelper, true);
233         clickOnLinkUsingJs(awContents, contentsClient);
234
235         shouldOverrideUrlLoadingHelper.waitForCallback(shouldOverrideUrlLoadingCallCount);
236         assertEquals(onPageStartedCallCount, onPageStartedHelper.getCallCount());
237     }
238
239
240     @SmallTest
241     @Feature({"AndroidWebView", "Navigation"})
242     public void testDoesNotCauseOnReceivedError() throws Throwable {
243         final TestAwContentsClient contentsClient = new TestAwContentsClient();
244         final AwTestContainerView testContainerView =
245             createAwTestContainerViewOnMainSync(contentsClient);
246         final AwContents awContents = testContainerView.getAwContents();
247         final TestAwContentsClient.ShouldOverrideUrlLoadingHelper shouldOverrideUrlLoadingHelper =
248             contentsClient.getShouldOverrideUrlLoadingHelper();
249         OnReceivedErrorHelper onReceivedErrorHelper = contentsClient.getOnReceivedErrorHelper();
250         final int onReceivedErrorCallCount = onReceivedErrorHelper.getCallCount();
251
252         loadDataSync(awContents, contentsClient.getOnPageFinishedHelper(),
253                 CommonResources.makeHtmlPageWithSimpleLinkTo(DATA_URL), "text/html", false);
254
255         final int shouldOverrideUrlLoadingCallCount = shouldOverrideUrlLoadingHelper.getCallCount();
256
257         setShouldOverrideUrlLoadingReturnValueOnUiThread(shouldOverrideUrlLoadingHelper, true);
258
259         clickOnLinkUsingJs(awContents, contentsClient);
260
261         shouldOverrideUrlLoadingHelper.waitForCallback(shouldOverrideUrlLoadingCallCount);
262
263         setShouldOverrideUrlLoadingReturnValueOnUiThread(shouldOverrideUrlLoadingHelper, false);
264
265         // After we load this URL we're certain that any in-flight callbacks for the previous
266         // navigation have been delivered.
267         loadUrlSync(awContents, contentsClient.getOnPageFinishedHelper(), ABOUT_BLANK_URL);
268
269         assertEquals(onReceivedErrorCallCount, onReceivedErrorHelper.getCallCount());
270     }
271
272     @SmallTest
273     @Feature({"AndroidWebView", "Navigation"})
274     public void testNotCalledForAnchorNavigations() throws Throwable {
275         doTestNotCalledForAnchorNavigations(false);
276     }
277
278     @SmallTest
279     @Feature({"AndroidWebView", "Navigation"})
280     public void testNotCalledForAnchorNavigationsWithNonHierarchicalScheme() throws Throwable {
281         doTestNotCalledForAnchorNavigations(true);
282     }
283
284     private void doTestNotCalledForAnchorNavigations(boolean useLoadData) throws Throwable {
285         final TestAwContentsClient contentsClient = new TestAwContentsClient();
286         final AwTestContainerView testContainerView =
287             createAwTestContainerViewOnMainSync(contentsClient);
288         final AwContents awContents = testContainerView.getAwContents();
289         final TestAwContentsClient.ShouldOverrideUrlLoadingHelper shouldOverrideUrlLoadingHelper =
290             contentsClient.getShouldOverrideUrlLoadingHelper();
291
292         final String anchorLinkPath = "/anchor_link.html";
293         final String anchorLinkUrl = mWebServer.getResponseUrl(anchorLinkPath);
294         addPageToTestServer(mWebServer, anchorLinkPath,
295                 CommonResources.makeHtmlPageWithSimpleLinkTo(anchorLinkUrl + "#anchor"));
296
297         if (useLoadData) {
298             loadDataSync(awContents, contentsClient.getOnPageFinishedHelper(),
299                     CommonResources.makeHtmlPageWithSimpleLinkTo("#anchor"), "text/html", false);
300         } else {
301             loadUrlSync(awContents, contentsClient.getOnPageFinishedHelper(), anchorLinkUrl);
302         }
303
304         final int shouldOverrideUrlLoadingCallCount =
305             shouldOverrideUrlLoadingHelper.getCallCount();
306
307         clickOnLinkUsingJs(awContents, contentsClient);
308
309         // After we load this URL we're certain that any in-flight callbacks for the previous
310         // navigation have been delivered.
311         loadUrlSync(awContents, contentsClient.getOnPageFinishedHelper(), ABOUT_BLANK_URL);
312
313         assertEquals(shouldOverrideUrlLoadingCallCount,
314                 shouldOverrideUrlLoadingHelper.getCallCount());
315     }
316
317     @SmallTest
318     @Feature({"AndroidWebView", "Navigation"})
319     public void testCalledWhenLinkClicked() throws Throwable {
320         final TestAwContentsClient contentsClient = new TestAwContentsClient();
321         final AwTestContainerView testContainerView =
322             createAwTestContainerViewOnMainSync(contentsClient);
323         final AwContents awContents = testContainerView.getAwContents();
324         TestAwContentsClient.ShouldOverrideUrlLoadingHelper shouldOverrideUrlLoadingHelper =
325                 contentsClient.getShouldOverrideUrlLoadingHelper();
326
327         // We can't go to about:blank from here because we'd get a cross-origin error.
328         loadDataSync(awContents, contentsClient.getOnPageFinishedHelper(),
329                 CommonResources.makeHtmlPageWithSimpleLinkTo(DATA_URL), "text/html", false);
330
331         int callCount = shouldOverrideUrlLoadingHelper.getCallCount();
332
333         clickOnLinkUsingJs(awContents, contentsClient);
334
335         shouldOverrideUrlLoadingHelper.waitForCallback(callCount);
336     }
337
338     @SmallTest
339     @Feature({"AndroidWebView", "Navigation"})
340     public void testCalledWhenTopLevelAboutBlankNavigation() throws Throwable {
341         final TestAwContentsClient contentsClient = new TestAwContentsClient();
342         final AwTestContainerView testContainerView =
343             createAwTestContainerViewOnMainSync(contentsClient);
344         final AwContents awContents = testContainerView.getAwContents();
345         TestAwContentsClient.ShouldOverrideUrlLoadingHelper shouldOverrideUrlLoadingHelper =
346                 contentsClient.getShouldOverrideUrlLoadingHelper();
347
348         final String httpPath = "/page_with_about_blank_navigation";
349         final String httpPathOnServer = mWebServer.getResponseUrl(httpPath);
350         addPageToTestServer(mWebServer, httpPath,
351                 CommonResources.makeHtmlPageWithSimpleLinkTo(ABOUT_BLANK_URL));
352
353         loadUrlSync(awContents, contentsClient.getOnPageFinishedHelper(),
354                 httpPathOnServer);
355
356         int callCount = shouldOverrideUrlLoadingHelper.getCallCount();
357
358         clickOnLinkUsingJs(awContents, contentsClient);
359
360         shouldOverrideUrlLoadingHelper.waitForCallback(callCount);
361         assertEquals(ABOUT_BLANK_URL,
362                 shouldOverrideUrlLoadingHelper.getShouldOverrideUrlLoadingUrl());
363     }
364
365     @SmallTest
366     @Feature({"AndroidWebView", "Navigation"})
367     public void testCalledWhenSelfLinkClicked() throws Throwable {
368         final TestAwContentsClient contentsClient = new TestAwContentsClient();
369         final AwTestContainerView testContainerView =
370             createAwTestContainerViewOnMainSync(contentsClient);
371         final AwContents awContents = testContainerView.getAwContents();
372         TestAwContentsClient.ShouldOverrideUrlLoadingHelper shouldOverrideUrlLoadingHelper =
373                 contentsClient.getShouldOverrideUrlLoadingHelper();
374
375         final String httpPath = "/page_with_link_to_self.html";
376         final String httpPathOnServer = mWebServer.getResponseUrl(httpPath);
377         addPageToTestServer(mWebServer, httpPath,
378                 CommonResources.makeHtmlPageWithSimpleLinkTo(httpPathOnServer));
379
380         loadUrlSync(awContents, contentsClient.getOnPageFinishedHelper(),
381                 httpPathOnServer);
382
383         int callCount = shouldOverrideUrlLoadingHelper.getCallCount();
384
385         clickOnLinkUsingJs(awContents, contentsClient);
386
387         shouldOverrideUrlLoadingHelper.waitForCallback(callCount);
388         assertEquals(httpPathOnServer,
389                 shouldOverrideUrlLoadingHelper.getShouldOverrideUrlLoadingUrl());
390     }
391
392     @SmallTest
393     @Feature({"AndroidWebView", "Navigation"})
394     public void testCalledWhenNavigatingFromJavaScriptUsingAssign()
395             throws Throwable {
396         final TestAwContentsClient contentsClient = new TestAwContentsClient();
397         final AwTestContainerView testContainerView =
398             createAwTestContainerViewOnMainSync(contentsClient);
399         final AwContents awContents = testContainerView.getAwContents();
400         enableJavaScriptOnUiThread(awContents);
401         TestAwContentsClient.ShouldOverrideUrlLoadingHelper shouldOverrideUrlLoadingHelper =
402                 contentsClient.getShouldOverrideUrlLoadingHelper();
403
404         final String redirectTargetUrl = createRedirectTargetPage(mWebServer);
405         loadDataSync(awContents, contentsClient.getOnPageFinishedHelper(),
406                 getHtmlForPageWithJsAssignLinkTo(redirectTargetUrl), "text/html", false);
407
408         int callCount = shouldOverrideUrlLoadingHelper.getCallCount();
409
410         clickOnLinkUsingJs(awContents, contentsClient);
411
412         shouldOverrideUrlLoadingHelper.waitForCallback(callCount);
413     }
414
415     @SmallTest
416     @Feature({"AndroidWebView", "Navigation"})
417     public void testCalledWhenNavigatingFromJavaScriptUsingReplace()
418             throws Throwable {
419         final TestAwContentsClient contentsClient = new TestAwContentsClient();
420         final AwTestContainerView testContainerView =
421             createAwTestContainerViewOnMainSync(contentsClient);
422         final AwContents awContents = testContainerView.getAwContents();
423         enableJavaScriptOnUiThread(awContents);
424         TestAwContentsClient.ShouldOverrideUrlLoadingHelper shouldOverrideUrlLoadingHelper =
425                 contentsClient.getShouldOverrideUrlLoadingHelper();
426
427         final String redirectTargetUrl = createRedirectTargetPage(mWebServer);
428         loadDataSync(awContents, contentsClient.getOnPageFinishedHelper(),
429                 getHtmlForPageWithJsReplaceLinkTo(redirectTargetUrl), "text/html", false);
430
431         int callCount = shouldOverrideUrlLoadingHelper.getCallCount();
432         clickOnLinkUsingJs(awContents, contentsClient);
433         shouldOverrideUrlLoadingHelper.waitForCallback(callCount);
434     }
435
436     @SmallTest
437     @Feature({"AndroidWebView", "Navigation"})
438     public void testPassesCorrectUrl() throws Throwable {
439         final TestAwContentsClient contentsClient = new TestAwContentsClient();
440         final AwTestContainerView testContainerView =
441             createAwTestContainerViewOnMainSync(contentsClient);
442         final AwContents awContents = testContainerView.getAwContents();
443         TestAwContentsClient.ShouldOverrideUrlLoadingHelper shouldOverrideUrlLoadingHelper =
444                 contentsClient.getShouldOverrideUrlLoadingHelper();
445
446         final String redirectTargetUrl = createRedirectTargetPage(mWebServer);
447         loadDataSync(awContents, contentsClient.getOnPageFinishedHelper(),
448                 CommonResources.makeHtmlPageWithSimpleLinkTo(redirectTargetUrl), "text/html",
449                 false);
450
451         int callCount = shouldOverrideUrlLoadingHelper.getCallCount();
452         clickOnLinkUsingJs(awContents, contentsClient);
453         shouldOverrideUrlLoadingHelper.waitForCallback(callCount);
454         assertEquals(redirectTargetUrl,
455                 shouldOverrideUrlLoadingHelper.getShouldOverrideUrlLoadingUrl());
456     }
457
458     @SmallTest
459     @Feature({"AndroidWebView", "Navigation"})
460     public void testCanIgnoreLoading() throws Throwable {
461         final TestAwContentsClient contentsClient = new TestAwContentsClient();
462         final AwTestContainerView testContainerView =
463             createAwTestContainerViewOnMainSync(contentsClient);
464         final AwContents awContents = testContainerView.getAwContents();
465         final TestAwContentsClient.ShouldOverrideUrlLoadingHelper shouldOverrideUrlLoadingHelper =
466                 contentsClient.getShouldOverrideUrlLoadingHelper();
467
468         final String redirectTargetUrl = createRedirectTargetPage(mWebServer);
469         final String pageWithLinkToIgnorePath = "/page_with_link_to_ignore.html";
470         final String pageWithLinkToIgnoreUrl = addPageToTestServer(mWebServer,
471                 pageWithLinkToIgnorePath,
472                 CommonResources.makeHtmlPageWithSimpleLinkTo(redirectTargetUrl));
473         final String synchronizationPath = "/sync.html";
474         final String synchronizationUrl = addPageToTestServer(mWebServer,
475                 synchronizationPath,
476                 CommonResources.makeHtmlPageWithSimpleLinkTo(redirectTargetUrl));
477
478         loadUrlSync(awContents, contentsClient.getOnPageFinishedHelper(),
479                 pageWithLinkToIgnoreUrl);
480
481         setShouldOverrideUrlLoadingReturnValueOnUiThread(shouldOverrideUrlLoadingHelper, true);
482
483         int callCount = shouldOverrideUrlLoadingHelper.getCallCount();
484         clickOnLinkUsingJs(awContents, contentsClient);
485         // Some time around here true should be returned from the shouldOverrideUrlLoading
486         // callback causing the navigation caused by calling clickOnLinkUsingJs to be ignored.
487         // We validate this by checking which pages were loaded on the server.
488         shouldOverrideUrlLoadingHelper.waitForCallback(callCount);
489
490         setShouldOverrideUrlLoadingReturnValueOnUiThread(shouldOverrideUrlLoadingHelper, false);
491
492         loadUrlSync(awContents, contentsClient.getOnPageFinishedHelper(), synchronizationUrl);
493
494         assertEquals(1, mWebServer.getRequestCount(pageWithLinkToIgnorePath));
495         assertEquals(1, mWebServer.getRequestCount(synchronizationPath));
496         assertEquals(0, mWebServer.getRequestCount(REDIRECT_TARGET_PATH));
497     }
498
499     @SmallTest
500     @Feature({"AndroidWebView", "Navigation"})
501     public void testCalledForDataUrl() throws Throwable {
502         final String dataUrl =
503                 "data:text/html;base64," +
504                 "PGh0bWw+PGhlYWQ+PHRpdGxlPmRhdGFVcmxUZXN0QmFzZTY0PC90aXRsZT48" +
505                 "L2hlYWQ+PC9odG1sPg==";
506         final TestAwContentsClient contentsClient = new TestAwContentsClient();
507         final AwTestContainerView testContainerView =
508             createAwTestContainerViewOnMainSync(contentsClient);
509         final AwContents awContents = testContainerView.getAwContents();
510         TestAwContentsClient.ShouldOverrideUrlLoadingHelper shouldOverrideUrlLoadingHelper =
511                 contentsClient.getShouldOverrideUrlLoadingHelper();
512         loadDataSync(awContents, contentsClient.getOnPageFinishedHelper(),
513                 CommonResources.makeHtmlPageWithSimpleLinkTo(dataUrl), "text/html", false);
514
515         int callCount = shouldOverrideUrlLoadingHelper.getCallCount();
516         clickOnLinkUsingJs(awContents, contentsClient);
517
518         shouldOverrideUrlLoadingHelper.waitForCallback(callCount);
519         assertTrue("Expected URL that starts with 'data:' but got: <" +
520                    shouldOverrideUrlLoadingHelper.getShouldOverrideUrlLoadingUrl() + "> instead.",
521                    shouldOverrideUrlLoadingHelper.getShouldOverrideUrlLoadingUrl().startsWith(
522                            "data:"));
523     }
524
525     @SmallTest
526     @Feature({"AndroidWebView", "Navigation"})
527     public void testCalledForUnsupportedSchemes() throws Throwable {
528         final TestAwContentsClient contentsClient = new TestAwContentsClient();
529         final AwTestContainerView testContainerView =
530             createAwTestContainerViewOnMainSync(contentsClient);
531         final AwContents awContents = testContainerView.getAwContents();
532         TestAwContentsClient.ShouldOverrideUrlLoadingHelper shouldOverrideUrlLoadingHelper =
533                 contentsClient.getShouldOverrideUrlLoadingHelper();
534         final String unsupportedSchemeUrl = "foobar://resource/1";
535         loadDataSync(awContents, contentsClient.getOnPageFinishedHelper(),
536                 CommonResources.makeHtmlPageWithSimpleLinkTo(unsupportedSchemeUrl), "text/html",
537                 false);
538
539         int callCount = shouldOverrideUrlLoadingHelper.getCallCount();
540         clickOnLinkUsingJs(awContents, contentsClient);
541
542         shouldOverrideUrlLoadingHelper.waitForCallback(callCount);
543         assertEquals(unsupportedSchemeUrl,
544                 shouldOverrideUrlLoadingHelper.getShouldOverrideUrlLoadingUrl());
545     }
546
547     @SmallTest
548     @Feature({"AndroidWebView", "Navigation"})
549     public void testNotCalledForPostNavigations() throws Throwable {
550         // The reason POST requests are excluded is BUG 155250.
551         final TestAwContentsClient contentsClient = new TestAwContentsClient();
552         final AwTestContainerView testContainerView =
553             createAwTestContainerViewOnMainSync(contentsClient);
554         final AwContents awContents = testContainerView.getAwContents();
555         final TestAwContentsClient.ShouldOverrideUrlLoadingHelper shouldOverrideUrlLoadingHelper =
556             contentsClient.getShouldOverrideUrlLoadingHelper();
557
558         final String redirectTargetUrl = createRedirectTargetPage(mWebServer);
559         final String postLinkUrl = addPageToTestServer(mWebServer, "/page_with_post_link.html",
560                 CommonResources.makeHtmlPageWithSimplePostFormTo(redirectTargetUrl));
561
562         loadUrlSync(awContents, contentsClient.getOnPageFinishedHelper(), postLinkUrl);
563
564         final int shouldOverrideUrlLoadingCallCount =
565             shouldOverrideUrlLoadingHelper.getCallCount();
566
567         assertEquals(0, mWebServer.getRequestCount(REDIRECT_TARGET_PATH));
568         clickOnLinkUsingJs(awContents, contentsClient);
569
570         // Wait for the target URL to be fetched from the server.
571         poll(new Callable<Boolean>() {
572             @Override
573             public Boolean call() throws Exception {
574                 return mWebServer.getRequestCount(REDIRECT_TARGET_PATH) == 1;
575             }
576         });
577
578         // Since the targetURL was loaded from the test server it means all processing related
579         // to dispatching a shouldOverrideUrlLoading callback had finished and checking the call
580         // is stable.
581         assertEquals(shouldOverrideUrlLoadingCallCount,
582                 shouldOverrideUrlLoadingHelper.getCallCount());
583     }
584
585     @SmallTest
586     @Feature({"AndroidWebView", "Navigation"})
587     public void testCalledFor302AfterPostNavigations() throws Throwable {
588         // The reason POST requests are excluded is BUG 155250.
589         final TestAwContentsClient contentsClient = new TestAwContentsClient();
590         final AwTestContainerView testContainerView =
591             createAwTestContainerViewOnMainSync(contentsClient);
592         final AwContents awContents = testContainerView.getAwContents();
593         final TestAwContentsClient.ShouldOverrideUrlLoadingHelper shouldOverrideUrlLoadingHelper =
594             contentsClient.getShouldOverrideUrlLoadingHelper();
595
596         final String redirectTargetUrl = createRedirectTargetPage(mWebServer);
597         final String postToGetRedirectUrl = mWebServer.setRedirect("/302.html", redirectTargetUrl);
598         final String postLinkUrl = addPageToTestServer(mWebServer, "/page_with_post_link.html",
599                 CommonResources.makeHtmlPageWithSimplePostFormTo(postToGetRedirectUrl));
600
601         loadUrlSync(awContents, contentsClient.getOnPageFinishedHelper(), postLinkUrl);
602
603         final int shouldOverrideUrlLoadingCallCount =
604             shouldOverrideUrlLoadingHelper.getCallCount();
605
606         clickOnLinkUsingJs(awContents, contentsClient);
607
608         shouldOverrideUrlLoadingHelper.waitForCallback(shouldOverrideUrlLoadingCallCount);
609
610         // Wait for the target URL to be fetched from the server.
611         poll(new Callable<Boolean>() {
612             @Override
613             public Boolean call() throws Exception {
614                 return mWebServer.getRequestCount(REDIRECT_TARGET_PATH) == 1;
615             }
616         });
617
618         assertEquals(redirectTargetUrl,
619                 shouldOverrideUrlLoadingHelper.getShouldOverrideUrlLoadingUrl());
620     }
621
622     @SmallTest
623     @Feature({"AndroidWebView", "Navigation"})
624     public void testNotCalledForIframeHttpNavigations() throws Throwable {
625         final TestAwContentsClient contentsClient = new TestAwContentsClient();
626         final AwTestContainerView testContainerView =
627             createAwTestContainerViewOnMainSync(contentsClient);
628         final AwContents awContents = testContainerView.getAwContents();
629         final TestAwContentsClient.ShouldOverrideUrlLoadingHelper shouldOverrideUrlLoadingHelper =
630             contentsClient.getShouldOverrideUrlLoadingHelper();
631
632         final String iframeRedirectTargetUrl = createRedirectTargetPage(mWebServer);
633         final String iframeRedirectUrl =
634             mWebServer.setRedirect("/302.html", iframeRedirectTargetUrl);
635         final String pageWithIframeUrl =
636             addPageToTestServer(mWebServer, "/iframe_intercept.html",
637                 makeHtmlPageFrom("", "<iframe src=\"" + iframeRedirectUrl + "\" />"));
638
639         final int shouldOverrideUrlLoadingCallCount =
640             shouldOverrideUrlLoadingHelper.getCallCount();
641
642         assertEquals(0, mWebServer.getRequestCount(REDIRECT_TARGET_PATH));
643         loadUrlSync(awContents, contentsClient.getOnPageFinishedHelper(), pageWithIframeUrl);
644
645         // Wait for the redirect target URL to be fetched from the server.
646         poll(new Callable<Boolean>() {
647             @Override
648             public Boolean call() throws Exception {
649                 return mWebServer.getRequestCount(REDIRECT_TARGET_PATH) == 1;
650             }
651         });
652
653         assertEquals(shouldOverrideUrlLoadingCallCount,
654                 shouldOverrideUrlLoadingHelper.getCallCount());
655     }
656
657     @SmallTest
658     @Feature({"AndroidWebView", "Navigation"})
659     public void testCalledForIframeUnsupportedSchemeNavigations() throws Throwable {
660         final TestAwContentsClient contentsClient = new TestAwContentsClient();
661         final AwTestContainerView testContainerView =
662             createAwTestContainerViewOnMainSync(contentsClient);
663         final AwContents awContents = testContainerView.getAwContents();
664         final TestAwContentsClient.ShouldOverrideUrlLoadingHelper shouldOverrideUrlLoadingHelper =
665             contentsClient.getShouldOverrideUrlLoadingHelper();
666
667         final String unsupportedSchemeUrl = "foobar://resource/1";
668         final String pageWithIframeUrl =
669             addPageToTestServer(mWebServer, "/iframe_intercept.html",
670                 makeHtmlPageFrom("", "<iframe src=\"" + unsupportedSchemeUrl + "\" />"));
671
672         final int shouldOverrideUrlLoadingCallCount =
673             shouldOverrideUrlLoadingHelper.getCallCount();
674
675         loadUrlSync(awContents, contentsClient.getOnPageFinishedHelper(), pageWithIframeUrl);
676
677         shouldOverrideUrlLoadingHelper.waitForCallback(shouldOverrideUrlLoadingCallCount);
678         assertEquals(unsupportedSchemeUrl,
679                 shouldOverrideUrlLoadingHelper.getShouldOverrideUrlLoadingUrl());
680     }
681
682     /**
683      * Worker method for the various redirect tests.
684      *
685      * Calling this will first load the redirect URL built from redirectFilePath, query and
686      * locationFilePath and assert that we get a override callback for the destination.
687      * The second part of the test loads a page that contains a link which points at the redirect
688      * URL. We expect two callbacks - one for the redirect link and another for the destination.
689      */
690     private void doTestCalledOnRedirect(TestWebServer webServer,
691             String redirectUrl, String redirectTarget) throws Throwable {
692         final TestAwContentsClient contentsClient = new TestAwContentsClient();
693         final AwTestContainerView testContainerView =
694             createAwTestContainerViewOnMainSync(contentsClient);
695         final AwContents awContents = testContainerView.getAwContents();
696         final String pageWithLinkToRedirectUrl = addPageToTestServer(webServer,
697                 "/page_with_link_to_redirect.html",
698                 CommonResources.makeHtmlPageWithSimpleLinkTo(redirectUrl));
699         enableJavaScriptOnUiThread(awContents);
700
701         TestAwContentsClient.ShouldOverrideUrlLoadingHelper shouldOverrideUrlLoadingHelper =
702                 contentsClient.getShouldOverrideUrlLoadingHelper();
703         int directLoadCallCount = shouldOverrideUrlLoadingHelper.getCallCount();
704         loadUrlSync(awContents, contentsClient.getOnPageFinishedHelper(), redirectUrl);
705
706         shouldOverrideUrlLoadingHelper.waitForCallback(directLoadCallCount, 1);
707         assertEquals(redirectTarget,
708                 shouldOverrideUrlLoadingHelper.getShouldOverrideUrlLoadingUrl());
709
710         // There is a slight difference between navigations caused by calling load and navigations
711         // caused by clicking on a link:
712         //  * when using load the navigation is treated as if it came from the URL bar (has the
713         //    navigation type TYPED and doesn't have the has_user_gesture flag)
714         //  * when clicking on a link the navigation has the LINK type and has_user_gesture is
715         //    true.
716         // Both of these should yield the same result which is what we're verifying here.
717         int indirectLoadCallCount = shouldOverrideUrlLoadingHelper.getCallCount();
718         loadUrlSync(awContents, contentsClient.getOnPageFinishedHelper(),
719                 pageWithLinkToRedirectUrl);
720
721         assertEquals(indirectLoadCallCount, shouldOverrideUrlLoadingHelper.getCallCount());
722
723         clickOnLinkUsingJs(awContents, contentsClient);
724
725         shouldOverrideUrlLoadingHelper.waitForCallback(indirectLoadCallCount, 2);
726         assertEquals(redirectTarget,
727                 shouldOverrideUrlLoadingHelper.getShouldOverrideUrlLoadingUrl());
728         assertEquals(redirectUrl,
729                 shouldOverrideUrlLoadingHelper.getPreviousShouldOverrideUrlLoadingUrl());
730     }
731
732     @SmallTest
733     @Feature({"AndroidWebView", "Navigation"})
734     public void testCalledOn302Redirect() throws Throwable {
735         final String redirectTargetUrl = createRedirectTargetPage(mWebServer);
736         final String redirectUrl = mWebServer.setRedirect("/302.html", redirectTargetUrl);
737
738         doTestCalledOnRedirect(mWebServer, redirectUrl, redirectTargetUrl);
739     }
740
741     @SmallTest
742     @Feature({"AndroidWebView", "Navigation"})
743     public void testCalledOnMetaRefreshRedirect() throws Throwable {
744         final String redirectTargetUrl = createRedirectTargetPage(mWebServer);
745         final String redirectUrl = addPageToTestServer(mWebServer, "/meta_refresh.html",
746                 getHtmlForPageWithMetaRefreshRedirectTo(redirectTargetUrl));
747         doTestCalledOnRedirect(mWebServer, redirectUrl, redirectTargetUrl);
748     }
749
750
751     @SmallTest
752     @Feature({"AndroidWebView", "Navigation"})
753     public void testCalledOnJavaScriptLocationImmediateAssignRedirect()
754             throws Throwable {
755         final String redirectTargetUrl = createRedirectTargetPage(mWebServer);
756         final String redirectUrl = addPageToTestServer(mWebServer, "/js_immediate_assign.html",
757                 getHtmlForPageWithJsRedirectTo(redirectTargetUrl, "Assign", 0));
758         doTestCalledOnRedirect(mWebServer, redirectUrl, redirectTargetUrl);
759     }
760
761     @SmallTest
762     @Feature({"AndroidWebView", "Navigation"})
763     public void testCalledOnJavaScriptLocationImmediateReplaceRedirect()
764             throws Throwable {
765         final String redirectTargetUrl = createRedirectTargetPage(mWebServer);
766         final String redirectUrl = addPageToTestServer(mWebServer, "/js_immediate_replace.html",
767                 getHtmlForPageWithJsRedirectTo(redirectTargetUrl, "Replace", 0));
768         doTestCalledOnRedirect(mWebServer, redirectUrl, redirectTargetUrl);
769     }
770
771     @SmallTest
772     @Feature({"AndroidWebView", "Navigation"})
773     public void testCalledOnJavaScriptLocationDelayedAssignRedirect()
774             throws Throwable {
775         final String redirectTargetUrl = createRedirectTargetPage(mWebServer);
776         final String redirectUrl = addPageToTestServer(mWebServer, "/js_delayed_assign.html",
777                 getHtmlForPageWithJsRedirectTo(redirectTargetUrl, "Assign", 100));
778         doTestCalledOnRedirect(mWebServer, redirectUrl, redirectTargetUrl);
779     }
780
781     @SmallTest
782     @Feature({"AndroidWebView", "Navigation"})
783     public void testCalledOnJavaScriptLocationDelayedReplaceRedirect()
784             throws Throwable {
785         final String redirectTargetUrl = createRedirectTargetPage(mWebServer);
786         final String redirectUrl = addPageToTestServer(mWebServer, "/js_delayed_replace.html",
787                 getHtmlForPageWithJsRedirectTo(redirectTargetUrl, "Replace", 100));
788         doTestCalledOnRedirect(mWebServer, redirectUrl, redirectTargetUrl);
789     }
790
791     @SmallTest
792     @Feature({"AndroidWebView", "Navigation"})
793     public void testDoubleNavigateDoesNotSuppressInitialNavigate() throws Throwable {
794         final String jsUrl = "javascript:try{console.log('processed js loadUrl');}catch(e){};";
795         final TestAwContentsClient contentsClient = new TestAwContentsClient();
796         final AwTestContainerView testContainerView =
797             createAwTestContainerViewOnMainSync(contentsClient);
798         final AwContents awContents = testContainerView.getAwContents();
799         TestAwContentsClient.ShouldOverrideUrlLoadingHelper shouldOverrideUrlLoadingHelper =
800             contentsClient.getShouldOverrideUrlLoadingHelper();
801
802         // Do a double navigagtion, the second being an effective no-op, in quick succession (i.e.
803         // without yielding the main thread inbetween).
804         int currentCallCount = contentsClient.getOnPageFinishedHelper().getCallCount();
805         getInstrumentation().runOnMainSync(new Runnable() {
806             @Override
807             public void run() {
808                 awContents.loadUrl(LoadUrlParams.createLoadDataParams(
809                         CommonResources.makeHtmlPageWithSimpleLinkTo(DATA_URL), "text/html",
810                         false));
811                 awContents.loadUrl(new LoadUrlParams(jsUrl));
812             }
813         });
814         contentsClient.getOnPageFinishedHelper().waitForCallback(currentCallCount, 1,
815                 WAIT_TIMEOUT_MS, TimeUnit.MILLISECONDS);
816
817         assertEquals(0, shouldOverrideUrlLoadingHelper.getCallCount());
818     }
819 }