e1bcb59fbff68cbabf4c3b1686847cb21c992c8e
[platform/framework/web/crosswalk.git] / src / android_webview / javatests / src / org / chromium / android_webview / test / AwContentsClientShouldInterceptRequestTest.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.AwContentsClient.ShouldInterceptRequestParams;
12 import org.chromium.android_webview.AwWebResourceResponse;
13 import org.chromium.android_webview.test.util.CommonResources;
14 import org.chromium.android_webview.test.util.JSUtils;
15 import org.chromium.base.test.util.Feature;
16 import org.chromium.base.test.util.TestFileUtil;
17 import org.chromium.content.browser.test.util.CallbackHelper;
18 import org.chromium.content.browser.test.util.TestCallbackHelperContainer.OnReceivedErrorHelper;
19 import org.chromium.net.test.util.TestWebServer;
20
21 import java.io.ByteArrayInputStream;
22 import java.io.IOException;
23 import java.io.InputStream;
24 import java.util.ArrayList;
25 import java.util.HashMap;
26 import java.util.List;
27 import java.util.Map;
28 import java.util.concurrent.Callable;
29 import java.util.concurrent.ConcurrentHashMap;
30 import java.util.concurrent.CountDownLatch;
31
32 /**
33  * Tests for the WebViewClient.shouldInterceptRequest() method.
34  */
35 public class AwContentsClientShouldInterceptRequestTest extends AwTestBase {
36
37     private static class TestAwContentsClient
38             extends org.chromium.android_webview.test.TestAwContentsClient {
39
40         public static class ShouldInterceptRequestHelper extends CallbackHelper {
41             private List<String> mShouldInterceptRequestUrls = new ArrayList<String>();
42             private ConcurrentHashMap<String, AwWebResourceResponse> mReturnValuesByUrls
43                 = new ConcurrentHashMap<String, AwWebResourceResponse>();
44             private ConcurrentHashMap<String, ShouldInterceptRequestParams> mParamsByUrls
45                 = new ConcurrentHashMap<String, ShouldInterceptRequestParams>();
46             // This is read from the IO thread, so needs to be marked volatile.
47             private volatile AwWebResourceResponse mShouldInterceptRequestReturnValue = null;
48             void setReturnValue(AwWebResourceResponse value) {
49                 mShouldInterceptRequestReturnValue = value;
50             }
51             void setReturnValueForUrl(String url, AwWebResourceResponse value) {
52                 mReturnValuesByUrls.put(url, value);
53             }
54             public List<String> getUrls() {
55                 assert getCallCount() > 0;
56                 return mShouldInterceptRequestUrls;
57             }
58             public AwWebResourceResponse getReturnValue(String url) {
59                 AwWebResourceResponse value = mReturnValuesByUrls.get(url);
60                 if (value != null) return value;
61                 return mShouldInterceptRequestReturnValue;
62             }
63             public ShouldInterceptRequestParams getParamsForUrl(String url) {
64                 assert getCallCount() > 0;
65                 assert mParamsByUrls.containsKey(url);
66                 return mParamsByUrls.get(url);
67             }
68             public void notifyCalled(ShouldInterceptRequestParams params) {
69                 mShouldInterceptRequestUrls.add(params.url);
70                 mParamsByUrls.put(params.url, params);
71                 notifyCalled();
72             }
73         }
74
75         public static class OnLoadResourceHelper extends CallbackHelper {
76             private String mUrl;
77
78             public String getUrl() {
79                 assert getCallCount() > 0;
80                 return mUrl;
81             }
82
83             public void notifyCalled(String url) {
84                 mUrl = url;
85                 notifyCalled();
86             }
87         }
88
89         @Override
90         public AwWebResourceResponse shouldInterceptRequest(ShouldInterceptRequestParams params) {
91             AwWebResourceResponse returnValue =
92                 mShouldInterceptRequestHelper.getReturnValue(params.url);
93             mShouldInterceptRequestHelper.notifyCalled(params);
94             return returnValue;
95         }
96
97         @Override
98         public void onLoadResource(String url) {
99             super.onLoadResource(url);
100             mOnLoadResourceHelper.notifyCalled(url);
101         }
102
103         private ShouldInterceptRequestHelper mShouldInterceptRequestHelper;
104         private OnLoadResourceHelper mOnLoadResourceHelper;
105
106         public TestAwContentsClient() {
107             mShouldInterceptRequestHelper = new ShouldInterceptRequestHelper();
108             mOnLoadResourceHelper = new OnLoadResourceHelper();
109         }
110
111         public ShouldInterceptRequestHelper getShouldInterceptRequestHelper() {
112             return mShouldInterceptRequestHelper;
113         }
114
115         public OnLoadResourceHelper getOnLoadResourceHelper() {
116             return mOnLoadResourceHelper;
117         }
118     }
119
120     final int teapotStatusCode = 418;
121     final String teapotResponsePhrase = "I'm a teapot";
122
123     private String addPageToTestServer(TestWebServer webServer, String httpPath, String html) {
124         List<Pair<String, String>> headers = new ArrayList<Pair<String, String>>();
125         headers.add(Pair.create("Content-Type", "text/html"));
126         headers.add(Pair.create("Cache-Control", "no-store"));
127         return webServer.setResponse(httpPath, html, headers);
128     }
129
130     private String addAboutPageToTestServer(TestWebServer webServer) {
131         return addPageToTestServer(webServer, "/" + CommonResources.ABOUT_FILENAME,
132                 CommonResources.ABOUT_HTML);
133     }
134
135     private AwWebResourceResponse stringToAwWebResourceResponse(String input) throws Throwable {
136         final String mimeType = "text/html";
137         final String encoding = "UTF-8";
138
139         return new AwWebResourceResponse(
140                 mimeType, encoding, new ByteArrayInputStream(input.getBytes(encoding)));
141     }
142
143     private TestWebServer mWebServer;
144     private TestAwContentsClient mContentsClient;
145     private AwTestContainerView mTestContainerView;
146     private AwContents mAwContents;
147     private TestAwContentsClient.ShouldInterceptRequestHelper mShouldInterceptRequestHelper;
148
149     @Override
150     protected void setUp() throws Exception {
151         super.setUp();
152
153         mContentsClient = new TestAwContentsClient();
154         mTestContainerView = createAwTestContainerViewOnMainSync(mContentsClient);
155         mAwContents = mTestContainerView.getAwContents();
156         mShouldInterceptRequestHelper = mContentsClient.getShouldInterceptRequestHelper();
157
158         mWebServer = new TestWebServer(false);
159     }
160
161     @Override
162     protected void tearDown() throws Exception {
163         mWebServer.shutdown();
164         super.tearDown();
165     }
166
167     @SmallTest
168     @Feature({"AndroidWebView"})
169     public void testCalledWithCorrectUrlParam() throws Throwable {
170         final String aboutPageUrl = addAboutPageToTestServer(mWebServer);
171
172         int onPageFinishedCallCount = mContentsClient.getOnPageFinishedHelper().getCallCount();
173
174         int callCount = mShouldInterceptRequestHelper.getCallCount();
175         loadUrlAsync(mAwContents, aboutPageUrl);
176         mShouldInterceptRequestHelper.waitForCallback(callCount);
177         assertEquals(1, mShouldInterceptRequestHelper.getUrls().size());
178         assertEquals(aboutPageUrl,
179                 mShouldInterceptRequestHelper.getUrls().get(0));
180
181         mContentsClient.getOnPageFinishedHelper().waitForCallback(onPageFinishedCallCount);
182         assertEquals(CommonResources.ABOUT_TITLE, getTitleOnUiThread(mAwContents));
183     }
184
185     @SmallTest
186     @Feature({"AndroidWebView"})
187     public void testCalledWithCorrectIsMainFrameParam() throws Throwable {
188         final String subframeUrl = addAboutPageToTestServer(mWebServer);
189         final String pageWithIframeUrl = addPageToTestServer(mWebServer, "/page_with_iframe.html",
190                 CommonResources.makeHtmlPageFrom("",
191                     "<iframe src=\"" + subframeUrl + "\"/>"));
192
193         int callCount = mShouldInterceptRequestHelper.getCallCount();
194         loadUrlAsync(mAwContents, pageWithIframeUrl);
195         mShouldInterceptRequestHelper.waitForCallback(callCount, 2);
196         assertEquals(2, mShouldInterceptRequestHelper.getUrls().size());
197         assertEquals(false,
198                 mShouldInterceptRequestHelper.getParamsForUrl(subframeUrl).isMainFrame);
199         assertEquals(true,
200                 mShouldInterceptRequestHelper.getParamsForUrl(pageWithIframeUrl).isMainFrame);
201     }
202
203     @SmallTest
204     @Feature({"AndroidWebView"})
205     public void testCalledWithCorrectMethodParam() throws Throwable {
206         final String pageToPostToUrl = addAboutPageToTestServer(mWebServer);
207         final String pageWithFormUrl = addPageToTestServer(mWebServer, "/page_with_form.html",
208                 CommonResources.makeHtmlPageWithSimplePostFormTo(pageToPostToUrl));
209         enableJavaScriptOnUiThread(mAwContents);
210
211         int callCount = mShouldInterceptRequestHelper.getCallCount();
212         loadUrlAsync(mAwContents, pageWithFormUrl);
213         mShouldInterceptRequestHelper.waitForCallback(callCount);
214         assertEquals("GET",
215                 mShouldInterceptRequestHelper.getParamsForUrl(pageWithFormUrl).method);
216
217         callCount = mShouldInterceptRequestHelper.getCallCount();
218         JSUtils.clickOnLinkUsingJs(this, mAwContents,
219                 mContentsClient.getOnEvaluateJavaScriptResultHelper(), "link");
220         mShouldInterceptRequestHelper.waitForCallback(callCount);
221         assertEquals("POST",
222                 mShouldInterceptRequestHelper.getParamsForUrl(pageToPostToUrl).method);
223     }
224
225     @SmallTest
226     @Feature({"AndroidWebView"})
227     public void testCalledWithCorrectHasUserGestureParam() throws Throwable {
228         final String aboutPageUrl = addAboutPageToTestServer(mWebServer);
229         final String pageWithLinkUrl = addPageToTestServer(mWebServer, "/page_with_link.html",
230                 CommonResources.makeHtmlPageWithSimpleLinkTo(aboutPageUrl));
231         enableJavaScriptOnUiThread(mAwContents);
232
233         int callCount = mShouldInterceptRequestHelper.getCallCount();
234         loadUrlAsync(mAwContents, pageWithLinkUrl);
235         mShouldInterceptRequestHelper.waitForCallback(callCount);
236         assertEquals(false,
237                 mShouldInterceptRequestHelper.getParamsForUrl(pageWithLinkUrl).hasUserGesture);
238
239         callCount = mShouldInterceptRequestHelper.getCallCount();
240         JSUtils.clickOnLinkUsingJs(this, mAwContents,
241                 mContentsClient.getOnEvaluateJavaScriptResultHelper(), "link");
242         mShouldInterceptRequestHelper.waitForCallback(callCount);
243         assertEquals(true,
244                 mShouldInterceptRequestHelper.getParamsForUrl(aboutPageUrl).hasUserGesture);
245     }
246
247     @SmallTest
248     @Feature({"AndroidWebView"})
249     public void testCalledWithCorrectHeadersParam() throws Throwable {
250         final String headerName = "X-Test-Header-Name";
251         final String headerValue = "TestHeaderValue";
252         final String syncGetUrl = addPageToTestServer(mWebServer, "/intercept_me",
253                 CommonResources.ABOUT_HTML);
254         final String mainPageUrl = addPageToTestServer(mWebServer, "/main",
255                 CommonResources.makeHtmlPageFrom("",
256                 "<script>" +
257                 "  var xhr = new XMLHttpRequest();" +
258                 "  xhr.open('GET', '" + syncGetUrl + "', false);" +
259                 "  xhr.setRequestHeader('" + headerName + "', '" + headerValue + "'); " +
260                 "  xhr.send(null);" +
261                 "</script>"));
262         enableJavaScriptOnUiThread(mAwContents);
263
264         int callCount = mShouldInterceptRequestHelper.getCallCount();
265         loadUrlAsync(mAwContents, mainPageUrl);
266         mShouldInterceptRequestHelper.waitForCallback(callCount, 2);
267
268         Map<String, String> headers =
269             mShouldInterceptRequestHelper.getParamsForUrl(syncGetUrl).requestHeaders;
270         assertTrue(headers.containsKey(headerName));
271         assertEquals(headerValue, headers.get(headerName));
272     }
273
274     @SmallTest
275     @Feature({"AndroidWebView"})
276     public void testOnLoadResourceCalledWithCorrectUrl() throws Throwable {
277         final String aboutPageUrl = addAboutPageToTestServer(mWebServer);
278         final TestAwContentsClient.OnLoadResourceHelper onLoadResourceHelper =
279             mContentsClient.getOnLoadResourceHelper();
280
281         int callCount = onLoadResourceHelper.getCallCount();
282
283         loadUrlAsync(mAwContents, aboutPageUrl);
284
285         onLoadResourceHelper.waitForCallback(callCount);
286         assertEquals(aboutPageUrl, onLoadResourceHelper.getUrl());
287     }
288
289     @SmallTest
290     @Feature({"AndroidWebView"})
291     public void testDoesNotCrashOnInvalidData() throws Throwable {
292         final String aboutPageUrl = addAboutPageToTestServer(mWebServer);
293
294         mShouldInterceptRequestHelper.setReturnValue(
295                 new AwWebResourceResponse("text/html", "UTF-8", null));
296         int callCount = mShouldInterceptRequestHelper.getCallCount();
297         loadUrlAsync(mAwContents, aboutPageUrl);
298         mShouldInterceptRequestHelper.waitForCallback(callCount);
299
300         mShouldInterceptRequestHelper.setReturnValue(
301                 new AwWebResourceResponse(null, null, new ByteArrayInputStream(new byte[0])));
302         callCount = mShouldInterceptRequestHelper.getCallCount();
303         loadUrlAsync(mAwContents, aboutPageUrl);
304         mShouldInterceptRequestHelper.waitForCallback(callCount);
305
306         mShouldInterceptRequestHelper.setReturnValue(
307                 new AwWebResourceResponse(null, null, null));
308         callCount = mShouldInterceptRequestHelper.getCallCount();
309         loadUrlAsync(mAwContents, aboutPageUrl);
310         mShouldInterceptRequestHelper.waitForCallback(callCount);
311     }
312
313     private static class EmptyInputStream extends InputStream {
314         @Override
315         public int available() {
316             return 0;
317         }
318
319         @Override
320         public int read() throws IOException {
321             return -1;
322         }
323
324         @Override
325         public int read(byte b[]) throws IOException {
326             return -1;
327         }
328
329         @Override
330         public int read(byte b[], int off, int len) throws IOException {
331             return -1;
332         }
333
334         @Override
335         public long skip(long n) throws IOException {
336             if (n < 0)
337                 throw new IOException("skipping negative number of bytes");
338             return 0;
339         }
340     }
341
342     @SmallTest
343     @Feature({"AndroidWebView"})
344     public void testDoesNotCrashOnEmptyStream() throws Throwable {
345         final String aboutPageUrl = addAboutPageToTestServer(mWebServer);
346
347         mShouldInterceptRequestHelper.setReturnValue(
348                 new AwWebResourceResponse("text/html", "UTF-8", new EmptyInputStream()));
349         int shouldInterceptRequestCallCount = mShouldInterceptRequestHelper.getCallCount();
350         int onPageFinishedCallCount = mContentsClient.getOnPageFinishedHelper().getCallCount();
351
352         loadUrlAsync(mAwContents, aboutPageUrl);
353
354         mShouldInterceptRequestHelper.waitForCallback(shouldInterceptRequestCallCount);
355         mContentsClient.getOnPageFinishedHelper().waitForCallback(onPageFinishedCallCount);
356     }
357
358     private static class SlowAwWebResourceResponse extends AwWebResourceResponse {
359         private CallbackHelper mReadStartedCallbackHelper = new CallbackHelper();
360         private CountDownLatch mLatch = new CountDownLatch(1);
361
362         public SlowAwWebResourceResponse(String mimeType, String encoding, InputStream data) {
363             super(mimeType, encoding, data);
364         }
365
366         @Override
367         public InputStream getData() {
368             mReadStartedCallbackHelper.notifyCalled();
369             try {
370                 mLatch.await();
371             } catch (InterruptedException e) {
372                 // ignore
373             }
374             return super.getData();
375         }
376
377         public void unblockReads() {
378             mLatch.countDown();
379         }
380
381         public CallbackHelper getReadStartedCallbackHelper() {
382             return mReadStartedCallbackHelper;
383         }
384     }
385
386     @SmallTest
387     @Feature({"AndroidWebView"})
388     public void testDoesNotCrashOnSlowStream() throws Throwable {
389         final String aboutPageUrl = addAboutPageToTestServer(mWebServer);
390         final String aboutPageData = makePageWithTitle("some title");
391         final String encoding = "UTF-8";
392         final SlowAwWebResourceResponse slowAwWebResourceResponse =
393             new SlowAwWebResourceResponse("text/html", encoding,
394                     new ByteArrayInputStream(aboutPageData.getBytes(encoding)));
395
396         mShouldInterceptRequestHelper.setReturnValue(slowAwWebResourceResponse);
397         int callCount = slowAwWebResourceResponse.getReadStartedCallbackHelper().getCallCount();
398         loadUrlAsync(mAwContents, aboutPageUrl);
399         slowAwWebResourceResponse.getReadStartedCallbackHelper().waitForCallback(callCount);
400
401         // Now the AwContents is "stuck" waiting for the SlowInputStream to finish reading so we
402         // delete it to make sure that the dangling 'read' task doesn't cause a crash. Unfortunately
403         // this will not always lead to a crash but it should happen often enough for us to notice.
404
405         runTestOnUiThread(new Runnable() {
406             @Override
407             public void run() {
408                 getActivity().removeAllViews();
409             }
410         });
411         destroyAwContentsOnMainSync(mAwContents);
412         pollOnUiThread(new Callable<Boolean>() {
413             @Override
414             public Boolean call() {
415                 return AwContents.getNativeInstanceCount() == 0;
416             }
417         });
418
419         slowAwWebResourceResponse.unblockReads();
420     }
421
422     @SmallTest
423     @Feature({"AndroidWebView"})
424     public void testHttpStatusCodeAndText() throws Throwable {
425         final String syncGetUrl = mWebServer.getResponseUrl("/intercept_me");
426         final String syncGetJs =
427             "(function() {" +
428             "  var xhr = new XMLHttpRequest();" +
429             "  xhr.open('GET', '" + syncGetUrl + "', false);" +
430             "  xhr.send(null);" +
431             "  console.info('xhr.status = ' + xhr.status);" +
432             "  console.info('xhr.statusText = ' + xhr.statusText);" +
433             "  return '[' + xhr.status + '][' + xhr.statusText + ']';" +
434             "})();";
435         enableJavaScriptOnUiThread(mAwContents);
436
437         final String aboutPageUrl = addAboutPageToTestServer(mWebServer);
438         loadUrlSync(mAwContents, mContentsClient.getOnPageFinishedHelper(), aboutPageUrl);
439
440         mShouldInterceptRequestHelper.setReturnValue(
441                 new AwWebResourceResponse("text/html", "UTF-8", null));
442         assertEquals("\"[404][Not Found]\"",
443                 executeJavaScriptAndWaitForResult(mAwContents, mContentsClient, syncGetJs));
444
445         mShouldInterceptRequestHelper.setReturnValue(
446                 new AwWebResourceResponse("text/html", "UTF-8", new EmptyInputStream()));
447         assertEquals("\"[200][OK]\"",
448                 executeJavaScriptAndWaitForResult(mAwContents, mContentsClient, syncGetJs));
449
450         mShouldInterceptRequestHelper.setReturnValue(
451                 new AwWebResourceResponse("text/html", "UTF-8", new EmptyInputStream(),
452                     teapotStatusCode, teapotResponsePhrase, new HashMap<String, String>()));
453         assertEquals("\"[" + teapotStatusCode + "][" + teapotResponsePhrase + "]\"",
454                 executeJavaScriptAndWaitForResult(mAwContents, mContentsClient, syncGetJs));
455     }
456
457     private String getHeaderValue(AwContents awContents, TestAwContentsClient contentsClient,
458             String url, String headerName) throws Exception {
459         final String syncGetJs =
460             "(function() {" +
461             "  var xhr = new XMLHttpRequest();" +
462             "  xhr.open('GET', '" + url + "', false);" +
463             "  xhr.send(null);" +
464             "  console.info(xhr.getAllResponseHeaders());" +
465             "  return xhr.getResponseHeader('" + headerName + "');" +
466             "})();";
467         String header = executeJavaScriptAndWaitForResult(awContents, contentsClient, syncGetJs);
468         // JSON stringification applied by executeJavaScriptAndWaitForResult adds quotes
469         // around returned strings.
470         assertTrue(header.length() > 2);
471         assertEquals('"', header.charAt(0));
472         assertEquals('"', header.charAt(header.length() - 1));
473         return header.substring(1, header.length() - 1);
474     }
475
476     @SmallTest
477     @Feature({"AndroidWebView"})
478     public void testHttpResponseClientViaHeader() throws Throwable {
479         final String clientResponseHeaderName = "Client-Via";
480         final String clientResponseHeaderValue = "shouldInterceptRequest";
481         final String syncGetUrl = mWebServer.getResponseUrl("/intercept_me");
482         enableJavaScriptOnUiThread(mAwContents);
483
484         final String aboutPageUrl = addAboutPageToTestServer(mWebServer);
485         loadUrlSync(mAwContents, mContentsClient.getOnPageFinishedHelper(), aboutPageUrl);
486
487         // The response header is set regardless of whether the embedder has provided a
488         // valid resource stream.
489         mShouldInterceptRequestHelper.setReturnValue(
490                 new AwWebResourceResponse("text/html", "UTF-8", null));
491         assertEquals(clientResponseHeaderValue,
492                 getHeaderValue(mAwContents, mContentsClient, syncGetUrl, clientResponseHeaderName));
493         mShouldInterceptRequestHelper.setReturnValue(
494                 new AwWebResourceResponse("text/html", "UTF-8", new EmptyInputStream()));
495         assertEquals(clientResponseHeaderValue,
496                 getHeaderValue(mAwContents, mContentsClient, syncGetUrl, clientResponseHeaderName));
497
498     }
499
500     @SmallTest
501     @Feature({"AndroidWebView"})
502     public void testHttpResponseHeader() throws Throwable {
503         final String clientResponseHeaderName = "X-Test-Header-Name";
504         final String clientResponseHeaderValue = "TestHeaderValue";
505         final String syncGetUrl = mWebServer.getResponseUrl("/intercept_me");
506         final Map<String, String> headers = new HashMap<String, String>();
507         headers.put(clientResponseHeaderName, clientResponseHeaderValue);
508         enableJavaScriptOnUiThread(mAwContents);
509
510         final String aboutPageUrl = addAboutPageToTestServer(mWebServer);
511         loadUrlSync(mAwContents, mContentsClient.getOnPageFinishedHelper(), aboutPageUrl);
512
513         mShouldInterceptRequestHelper.setReturnValue(
514                 new AwWebResourceResponse("text/html", "UTF-8", null, 0, null, headers));
515         assertEquals(clientResponseHeaderValue,
516                 getHeaderValue(mAwContents, mContentsClient, syncGetUrl, clientResponseHeaderName));
517     }
518
519     private String makePageWithTitle(String title) {
520         return CommonResources.makeHtmlPageFrom("<title>" + title + "</title>",
521                 "<div> The title is: " + title + " </div>");
522     }
523
524     @SmallTest
525     @Feature({"AndroidWebView"})
526     public void testCanInterceptMainFrame() throws Throwable {
527         final String expectedTitle = "testShouldInterceptRequestCanInterceptMainFrame";
528         final String expectedPage = makePageWithTitle(expectedTitle);
529
530         mShouldInterceptRequestHelper.setReturnValue(
531                 stringToAwWebResourceResponse(expectedPage));
532
533         final String aboutPageUrl = addAboutPageToTestServer(mWebServer);
534
535         loadUrlSync(mAwContents, mContentsClient.getOnPageFinishedHelper(), aboutPageUrl);
536
537         assertEquals(expectedTitle, getTitleOnUiThread(mAwContents));
538         assertEquals(0, mWebServer.getRequestCount("/" + CommonResources.ABOUT_FILENAME));
539     }
540
541     @SmallTest
542     @Feature({"AndroidWebView"})
543     public void testDoesNotChangeReportedUrl() throws Throwable {
544         mShouldInterceptRequestHelper.setReturnValue(
545                 stringToAwWebResourceResponse(makePageWithTitle("some title")));
546
547         final String aboutPageUrl = addAboutPageToTestServer(mWebServer);
548
549         loadUrlSync(mAwContents, mContentsClient.getOnPageFinishedHelper(), aboutPageUrl);
550
551         assertEquals(aboutPageUrl, mContentsClient.getOnPageFinishedHelper().getUrl());
552         assertEquals(aboutPageUrl, mContentsClient.getOnPageStartedHelper().getUrl());
553     }
554
555     @SmallTest
556     @Feature({"AndroidWebView"})
557     public void testNullInputStreamCausesErrorForMainFrame() throws Throwable {
558         final OnReceivedErrorHelper onReceivedErrorHelper =
559             mContentsClient.getOnReceivedErrorHelper();
560
561         mShouldInterceptRequestHelper.setReturnValue(
562                 new AwWebResourceResponse("text/html", "UTF-8", null));
563
564         final String aboutPageUrl = addAboutPageToTestServer(mWebServer);
565         final int callCount = onReceivedErrorHelper.getCallCount();
566         loadUrlAsync(mAwContents, aboutPageUrl);
567         onReceivedErrorHelper.waitForCallback(callCount);
568         assertEquals(0, mWebServer.getRequestCount("/" + CommonResources.ABOUT_FILENAME));
569     }
570
571     @SmallTest
572     @Feature({"AndroidWebView"})
573     public void testCalledForImage() throws Throwable {
574         final String imagePath = "/" + CommonResources.FAVICON_FILENAME;
575         mWebServer.setResponseBase64(imagePath,
576                 CommonResources.FAVICON_DATA_BASE64, CommonResources.getImagePngHeaders(true));
577         final String pageWithImage =
578             addPageToTestServer(mWebServer, "/page_with_image.html",
579                     CommonResources.getOnImageLoadedHtml(CommonResources.FAVICON_FILENAME));
580
581         int callCount = mShouldInterceptRequestHelper.getCallCount();
582         loadUrlSync(mAwContents, mContentsClient.getOnPageFinishedHelper(), pageWithImage);
583         mShouldInterceptRequestHelper.waitForCallback(callCount, 2);
584
585         assertEquals(2, mShouldInterceptRequestHelper.getUrls().size());
586         assertTrue(mShouldInterceptRequestHelper.getUrls().get(1).endsWith(
587                 CommonResources.FAVICON_FILENAME));
588     }
589
590     @SmallTest
591     @Feature({"AndroidWebView"})
592     public void testOnReceivedErrorCallback() throws Throwable {
593         mShouldInterceptRequestHelper.setReturnValue(new AwWebResourceResponse(null, null, null));
594         OnReceivedErrorHelper onReceivedErrorHelper = mContentsClient.getOnReceivedErrorHelper();
595         int onReceivedErrorHelperCallCount = onReceivedErrorHelper.getCallCount();
596         loadUrlSync(mAwContents, mContentsClient.getOnPageFinishedHelper(), "foo://bar");
597         onReceivedErrorHelper.waitForCallback(onReceivedErrorHelperCallCount, 1);
598     }
599
600     @SmallTest
601     @Feature({"AndroidWebView"})
602     public void testNoOnReceivedErrorCallback() throws Throwable {
603         final String imagePath = "/" + CommonResources.FAVICON_FILENAME;
604         final String imageUrl = mWebServer.setResponseBase64(imagePath,
605                 CommonResources.FAVICON_DATA_BASE64, CommonResources.getImagePngHeaders(true));
606         final String pageWithImage =
607                 addPageToTestServer(mWebServer, "/page_with_image.html",
608                         CommonResources.getOnImageLoadedHtml(CommonResources.FAVICON_FILENAME));
609         mShouldInterceptRequestHelper.setReturnValueForUrl(
610                 imageUrl, new AwWebResourceResponse(null, null, null));
611         OnReceivedErrorHelper onReceivedErrorHelper = mContentsClient.getOnReceivedErrorHelper();
612         int onReceivedErrorHelperCallCount = onReceivedErrorHelper.getCallCount();
613         loadUrlSync(mAwContents, mContentsClient.getOnPageFinishedHelper(), pageWithImage);
614         assertEquals(onReceivedErrorHelperCallCount, onReceivedErrorHelper.getCallCount());
615     }
616
617     @SmallTest
618     @Feature({"AndroidWebView"})
619     public void testCalledForIframe() throws Throwable {
620         final String aboutPageUrl = addAboutPageToTestServer(mWebServer);
621         final String pageWithIframeUrl = addPageToTestServer(mWebServer, "/page_with_iframe.html",
622                 CommonResources.makeHtmlPageFrom("",
623                     "<iframe src=\"" + aboutPageUrl + "\"/>"));
624
625         int callCount = mShouldInterceptRequestHelper.getCallCount();
626         loadUrlSync(mAwContents, mContentsClient.getOnPageFinishedHelper(), pageWithIframeUrl);
627         mShouldInterceptRequestHelper.waitForCallback(callCount, 2);
628         assertEquals(2, mShouldInterceptRequestHelper.getUrls().size());
629         assertEquals(aboutPageUrl, mShouldInterceptRequestHelper.getUrls().get(1));
630     }
631
632     private void calledForUrlTemplate(final String url) throws Exception {
633         int callCount = mShouldInterceptRequestHelper.getCallCount();
634         int onPageStartedCallCount = mContentsClient.getOnPageStartedHelper().getCallCount();
635         loadUrlAsync(mAwContents, url);
636         mShouldInterceptRequestHelper.waitForCallback(callCount);
637         assertEquals(url, mShouldInterceptRequestHelper.getUrls().get(0));
638
639         mContentsClient.getOnPageStartedHelper().waitForCallback(onPageStartedCallCount);
640         assertEquals(onPageStartedCallCount + 1,
641                 mContentsClient.getOnPageStartedHelper().getCallCount());
642     }
643
644     private void notCalledForUrlTemplate(final String url) throws Exception {
645         int callCount = mShouldInterceptRequestHelper.getCallCount();
646         loadUrlSync(mAwContents, mContentsClient.getOnPageFinishedHelper(), url);
647         // The intercepting must happen before onPageFinished. Since the IPC messages from the
648         // renderer should be delivered in order waiting for onPageFinished is sufficient to
649         // 'flush' any pending interception messages.
650         assertEquals(callCount, mShouldInterceptRequestHelper.getCallCount());
651     }
652
653     @SmallTest
654     @Feature({"AndroidWebView"})
655     public void testCalledForUnsupportedSchemes() throws Throwable {
656         calledForUrlTemplate("foobar://resource/1");
657     }
658
659     @SmallTest
660     @Feature({"AndroidWebView"})
661     public void testCalledForNonexistentFiles() throws Throwable {
662         calledForUrlTemplate("file:///somewhere/something");
663     }
664
665     @SmallTest
666     @Feature({"AndroidWebView"})
667     public void testCalledForExistingFiles() throws Throwable {
668         final String tmpDir = getInstrumentation().getTargetContext().getCacheDir().getPath();
669         final String fileName = tmpDir + "/testfile.html";
670         final String title = "existing file title";
671         TestFileUtil.deleteFile(fileName);  // Remove leftover file if any.
672         TestFileUtil.createNewHtmlFile(fileName, title, "");
673         final String existingFileUrl = "file://" + fileName;
674
675         int callCount = mShouldInterceptRequestHelper.getCallCount();
676         int onPageFinishedCallCount = mContentsClient.getOnPageFinishedHelper().getCallCount();
677         loadUrlAsync(mAwContents, existingFileUrl);
678         mShouldInterceptRequestHelper.waitForCallback(callCount);
679         assertEquals(existingFileUrl, mShouldInterceptRequestHelper.getUrls().get(0));
680
681         mContentsClient.getOnPageFinishedHelper().waitForCallback(onPageFinishedCallCount);
682         assertEquals(title, getTitleOnUiThread(mAwContents));
683         assertEquals(onPageFinishedCallCount + 1,
684                 mContentsClient.getOnPageFinishedHelper().getCallCount());
685     }
686
687     @SmallTest
688     @Feature({"AndroidWebView"})
689     public void testNotCalledForExistingResource() throws Throwable {
690         notCalledForUrlTemplate("file:///android_res/raw/resource_file.html");
691     }
692
693     @SmallTest
694     @Feature({"AndroidWebView"})
695     public void testCalledForNonexistentResource() throws Throwable {
696         calledForUrlTemplate("file:///android_res/raw/no_file.html");
697     }
698
699     @SmallTest
700     @Feature({"AndroidWebView"})
701     public void testNotCalledForExistingAsset() throws Throwable {
702         notCalledForUrlTemplate("file:///android_asset/asset_file.html");
703     }
704
705     @SmallTest
706     @Feature({"AndroidWebView"})
707     public void testCalledForNonexistentAsset() throws Throwable {
708         calledForUrlTemplate("file:///android_res/raw/no_file.html");
709     }
710
711     @SmallTest
712     @Feature({"AndroidWebView"})
713     public void testNotCalledForExistingContentUrl() throws Throwable {
714         final String contentResourceName = "target";
715         final String existingContentUrl = TestContentProvider.createContentUrl(contentResourceName);
716
717         notCalledForUrlTemplate(existingContentUrl);
718
719         int contentRequestCount = TestContentProvider.getResourceRequestCount(
720                 getInstrumentation().getTargetContext(), contentResourceName);
721         assertEquals(1, contentRequestCount);
722     }
723
724     @SmallTest
725     @Feature({"AndroidWebView"})
726     public void testCalledForNonexistentContentUrl() throws Throwable {
727         calledForUrlTemplate("content://org.chromium.webview.NoSuchProvider/foo");
728     }
729 }