Upstream version 9.38.198.0
[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     private static final int TEAPOT_STATUS_CODE = 418;
121     private static final String TEAPOT_RESPONSE_PHRASE = "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 ThrowingInputStream extends EmptyInputStream {
359         @Override
360         public int available() {
361             return 100;
362         }
363
364         @Override
365         public int read() throws IOException {
366             throw new IOException("test exception");
367         }
368
369         @Override
370         public int read(byte b[]) throws IOException {
371             throw new IOException("test exception");
372         }
373
374         @Override
375         public int read(byte b[], int off, int len) throws IOException {
376             throw new IOException("test exception");
377         }
378
379         @Override
380         public long skip(long n) throws IOException {
381             return n;
382         }
383     }
384
385     @SmallTest
386     @Feature({"AndroidWebView"})
387     public void testDoesNotCrashOnThrowingStream() throws Throwable {
388         final String aboutPageUrl = addAboutPageToTestServer(mWebServer);
389
390         mShouldInterceptRequestHelper.setReturnValue(
391                 new AwWebResourceResponse("text/html", "UTF-8", new ThrowingInputStream()));
392         int shouldInterceptRequestCallCount = mShouldInterceptRequestHelper.getCallCount();
393         int onPageFinishedCallCount = mContentsClient.getOnPageFinishedHelper().getCallCount();
394
395         loadUrlAsync(mAwContents, aboutPageUrl);
396
397         mShouldInterceptRequestHelper.waitForCallback(shouldInterceptRequestCallCount);
398         mContentsClient.getOnPageFinishedHelper().waitForCallback(onPageFinishedCallCount);
399     }
400
401     private static class SlowAwWebResourceResponse extends AwWebResourceResponse {
402         private CallbackHelper mReadStartedCallbackHelper = new CallbackHelper();
403         private CountDownLatch mLatch = new CountDownLatch(1);
404
405         public SlowAwWebResourceResponse(String mimeType, String encoding, InputStream data) {
406             super(mimeType, encoding, data);
407         }
408
409         @Override
410         public InputStream getData() {
411             mReadStartedCallbackHelper.notifyCalled();
412             try {
413                 mLatch.await();
414             } catch (InterruptedException e) {
415                 // ignore
416             }
417             return super.getData();
418         }
419
420         public void unblockReads() {
421             mLatch.countDown();
422         }
423
424         public CallbackHelper getReadStartedCallbackHelper() {
425             return mReadStartedCallbackHelper;
426         }
427     }
428
429     @SmallTest
430     @Feature({"AndroidWebView"})
431     public void testDoesNotCrashOnSlowStream() throws Throwable {
432         final String aboutPageUrl = addAboutPageToTestServer(mWebServer);
433         final String aboutPageData = makePageWithTitle("some title");
434         final String encoding = "UTF-8";
435         final SlowAwWebResourceResponse slowAwWebResourceResponse =
436             new SlowAwWebResourceResponse("text/html", encoding,
437                     new ByteArrayInputStream(aboutPageData.getBytes(encoding)));
438
439         mShouldInterceptRequestHelper.setReturnValue(slowAwWebResourceResponse);
440         int callCount = slowAwWebResourceResponse.getReadStartedCallbackHelper().getCallCount();
441         loadUrlAsync(mAwContents, aboutPageUrl);
442         slowAwWebResourceResponse.getReadStartedCallbackHelper().waitForCallback(callCount);
443
444         // Now the AwContents is "stuck" waiting for the SlowInputStream to finish reading so we
445         // delete it to make sure that the dangling 'read' task doesn't cause a crash. Unfortunately
446         // this will not always lead to a crash but it should happen often enough for us to notice.
447
448         runTestOnUiThread(new Runnable() {
449             @Override
450             public void run() {
451                 getActivity().removeAllViews();
452             }
453         });
454         destroyAwContentsOnMainSync(mAwContents);
455         pollOnUiThread(new Callable<Boolean>() {
456             @Override
457             public Boolean call() {
458                 return AwContents.getNativeInstanceCount() == 0;
459             }
460         });
461
462         slowAwWebResourceResponse.unblockReads();
463     }
464
465     @SmallTest
466     @Feature({"AndroidWebView"})
467     public void testHttpStatusCodeAndText() throws Throwable {
468         final String syncGetUrl = mWebServer.getResponseUrl("/intercept_me");
469         final String syncGetJs =
470             "(function() {" +
471             "  var xhr = new XMLHttpRequest();" +
472             "  xhr.open('GET', '" + syncGetUrl + "', false);" +
473             "  xhr.send(null);" +
474             "  console.info('xhr.status = ' + xhr.status);" +
475             "  console.info('xhr.statusText = ' + xhr.statusText);" +
476             "  return '[' + xhr.status + '][' + xhr.statusText + ']';" +
477             "})();";
478         enableJavaScriptOnUiThread(mAwContents);
479
480         final String aboutPageUrl = addAboutPageToTestServer(mWebServer);
481         loadUrlSync(mAwContents, mContentsClient.getOnPageFinishedHelper(), aboutPageUrl);
482
483         mShouldInterceptRequestHelper.setReturnValue(
484                 new AwWebResourceResponse("text/html", "UTF-8", null));
485         assertEquals("\"[404][Not Found]\"",
486                 executeJavaScriptAndWaitForResult(mAwContents, mContentsClient, syncGetJs));
487
488         mShouldInterceptRequestHelper.setReturnValue(
489                 new AwWebResourceResponse("text/html", "UTF-8", new EmptyInputStream()));
490         assertEquals("\"[200][OK]\"",
491                 executeJavaScriptAndWaitForResult(mAwContents, mContentsClient, syncGetJs));
492
493         mShouldInterceptRequestHelper.setReturnValue(
494                 new AwWebResourceResponse("text/html", "UTF-8", new EmptyInputStream(),
495                     TEAPOT_STATUS_CODE, TEAPOT_RESPONSE_PHRASE, new HashMap<String, String>()));
496         assertEquals("\"[" + TEAPOT_STATUS_CODE + "][" + TEAPOT_RESPONSE_PHRASE + "]\"",
497                 executeJavaScriptAndWaitForResult(mAwContents, mContentsClient, syncGetJs));
498     }
499
500     private String getHeaderValue(AwContents awContents, TestAwContentsClient contentsClient,
501             String url, String headerName) throws Exception {
502         final String syncGetJs =
503             "(function() {" +
504             "  var xhr = new XMLHttpRequest();" +
505             "  xhr.open('GET', '" + url + "', false);" +
506             "  xhr.send(null);" +
507             "  console.info(xhr.getAllResponseHeaders());" +
508             "  return xhr.getResponseHeader('" + headerName + "');" +
509             "})();";
510         String header = executeJavaScriptAndWaitForResult(awContents, contentsClient, syncGetJs);
511
512         if (header.equals("null"))
513             return null;
514         // JSON stringification applied by executeJavaScriptAndWaitForResult adds quotes
515         // around returned strings.
516         assertTrue(header.length() > 2);
517         assertEquals('"', header.charAt(0));
518         assertEquals('"', header.charAt(header.length() - 1));
519         return header.substring(1, header.length() - 1);
520     }
521
522     @SmallTest
523     @Feature({"AndroidWebView"})
524     public void testHttpResponseClientViaHeader() throws Throwable {
525         final String clientResponseHeaderName = "Client-Via";
526         final String clientResponseHeaderValue = "shouldInterceptRequest";
527         final String syncGetUrl = mWebServer.getResponseUrl("/intercept_me");
528         enableJavaScriptOnUiThread(mAwContents);
529
530         final String aboutPageUrl = addAboutPageToTestServer(mWebServer);
531         loadUrlSync(mAwContents, mContentsClient.getOnPageFinishedHelper(), aboutPageUrl);
532
533         // The response header is set regardless of whether the embedder has provided a
534         // valid resource stream.
535         mShouldInterceptRequestHelper.setReturnValue(
536                 new AwWebResourceResponse("text/html", "UTF-8", null));
537         assertEquals(clientResponseHeaderValue,
538                 getHeaderValue(mAwContents, mContentsClient, syncGetUrl, clientResponseHeaderName));
539         mShouldInterceptRequestHelper.setReturnValue(
540                 new AwWebResourceResponse("text/html", "UTF-8", new EmptyInputStream()));
541         assertEquals(clientResponseHeaderValue,
542                 getHeaderValue(mAwContents, mContentsClient, syncGetUrl, clientResponseHeaderName));
543
544     }
545
546     @SmallTest
547     @Feature({"AndroidWebView"})
548     public void testHttpResponseHeader() throws Throwable {
549         final String clientResponseHeaderName = "X-Test-Header-Name";
550         final String clientResponseHeaderValue = "TestHeaderValue";
551         final String syncGetUrl = mWebServer.getResponseUrl("/intercept_me");
552         final Map<String, String> headers = new HashMap<String, String>();
553         headers.put(clientResponseHeaderName, clientResponseHeaderValue);
554         enableJavaScriptOnUiThread(mAwContents);
555
556         final String aboutPageUrl = addAboutPageToTestServer(mWebServer);
557         loadUrlSync(mAwContents, mContentsClient.getOnPageFinishedHelper(), aboutPageUrl);
558
559         mShouldInterceptRequestHelper.setReturnValue(
560                 new AwWebResourceResponse("text/html", "UTF-8", null, 0, null, headers));
561         assertEquals(clientResponseHeaderValue,
562                 getHeaderValue(mAwContents, mContentsClient, syncGetUrl, clientResponseHeaderName));
563     }
564
565     @SmallTest
566     @Feature({"AndroidWebView"})
567     public void testNullHttpResponseHeaders() throws Throwable {
568         final String syncGetUrl = mWebServer.getResponseUrl("/intercept_me");
569         enableJavaScriptOnUiThread(mAwContents);
570
571         final String aboutPageUrl = addAboutPageToTestServer(mWebServer);
572         loadUrlSync(mAwContents, mContentsClient.getOnPageFinishedHelper(), aboutPageUrl);
573
574         mShouldInterceptRequestHelper.setReturnValue(
575                 new AwWebResourceResponse("text/html", "UTF-8", null, 0, null, null));
576         assertEquals(null, getHeaderValue(mAwContents, mContentsClient, syncGetUrl, "Some-Header"));
577     }
578
579     private String makePageWithTitle(String title) {
580         return CommonResources.makeHtmlPageFrom("<title>" + title + "</title>",
581                 "<div> The title is: " + title + " </div>");
582     }
583
584     @SmallTest
585     @Feature({"AndroidWebView"})
586     public void testCanInterceptMainFrame() throws Throwable {
587         final String expectedTitle = "testShouldInterceptRequestCanInterceptMainFrame";
588         final String expectedPage = makePageWithTitle(expectedTitle);
589
590         mShouldInterceptRequestHelper.setReturnValue(
591                 stringToAwWebResourceResponse(expectedPage));
592
593         final String aboutPageUrl = addAboutPageToTestServer(mWebServer);
594
595         loadUrlSync(mAwContents, mContentsClient.getOnPageFinishedHelper(), aboutPageUrl);
596
597         assertEquals(expectedTitle, getTitleOnUiThread(mAwContents));
598         assertEquals(0, mWebServer.getRequestCount("/" + CommonResources.ABOUT_FILENAME));
599     }
600
601     @SmallTest
602     @Feature({"AndroidWebView"})
603     public void testDoesNotChangeReportedUrl() throws Throwable {
604         mShouldInterceptRequestHelper.setReturnValue(
605                 stringToAwWebResourceResponse(makePageWithTitle("some title")));
606
607         final String aboutPageUrl = addAboutPageToTestServer(mWebServer);
608
609         loadUrlSync(mAwContents, mContentsClient.getOnPageFinishedHelper(), aboutPageUrl);
610
611         assertEquals(aboutPageUrl, mContentsClient.getOnPageFinishedHelper().getUrl());
612         assertEquals(aboutPageUrl, mContentsClient.getOnPageStartedHelper().getUrl());
613     }
614
615     @SmallTest
616     @Feature({"AndroidWebView"})
617     public void testNullInputStreamCausesErrorForMainFrame() throws Throwable {
618         final OnReceivedErrorHelper onReceivedErrorHelper =
619             mContentsClient.getOnReceivedErrorHelper();
620
621         mShouldInterceptRequestHelper.setReturnValue(
622                 new AwWebResourceResponse("text/html", "UTF-8", null));
623
624         final String aboutPageUrl = addAboutPageToTestServer(mWebServer);
625         final int callCount = onReceivedErrorHelper.getCallCount();
626         loadUrlAsync(mAwContents, aboutPageUrl);
627         onReceivedErrorHelper.waitForCallback(callCount);
628         assertEquals(0, mWebServer.getRequestCount("/" + CommonResources.ABOUT_FILENAME));
629     }
630
631     @SmallTest
632     @Feature({"AndroidWebView"})
633     public void testCalledForImage() throws Throwable {
634         final String imagePath = "/" + CommonResources.FAVICON_FILENAME;
635         mWebServer.setResponseBase64(imagePath,
636                 CommonResources.FAVICON_DATA_BASE64, CommonResources.getImagePngHeaders(true));
637         final String pageWithImage =
638             addPageToTestServer(mWebServer, "/page_with_image.html",
639                     CommonResources.getOnImageLoadedHtml(CommonResources.FAVICON_FILENAME));
640
641         int callCount = mShouldInterceptRequestHelper.getCallCount();
642         loadUrlSync(mAwContents, mContentsClient.getOnPageFinishedHelper(), pageWithImage);
643         mShouldInterceptRequestHelper.waitForCallback(callCount, 2);
644
645         assertEquals(2, mShouldInterceptRequestHelper.getUrls().size());
646         assertTrue(mShouldInterceptRequestHelper.getUrls().get(1).endsWith(
647                 CommonResources.FAVICON_FILENAME));
648     }
649
650     @SmallTest
651     @Feature({"AndroidWebView"})
652     public void testOnReceivedErrorCallback() throws Throwable {
653         mShouldInterceptRequestHelper.setReturnValue(new AwWebResourceResponse(null, null, null));
654         OnReceivedErrorHelper onReceivedErrorHelper = mContentsClient.getOnReceivedErrorHelper();
655         int onReceivedErrorHelperCallCount = onReceivedErrorHelper.getCallCount();
656         loadUrlSync(mAwContents, mContentsClient.getOnPageFinishedHelper(), "foo://bar");
657         onReceivedErrorHelper.waitForCallback(onReceivedErrorHelperCallCount, 1);
658     }
659
660     @SmallTest
661     @Feature({"AndroidWebView"})
662     public void testNoOnReceivedErrorCallback() throws Throwable {
663         final String imagePath = "/" + CommonResources.FAVICON_FILENAME;
664         final String imageUrl = mWebServer.setResponseBase64(imagePath,
665                 CommonResources.FAVICON_DATA_BASE64, CommonResources.getImagePngHeaders(true));
666         final String pageWithImage =
667                 addPageToTestServer(mWebServer, "/page_with_image.html",
668                         CommonResources.getOnImageLoadedHtml(CommonResources.FAVICON_FILENAME));
669         mShouldInterceptRequestHelper.setReturnValueForUrl(
670                 imageUrl, new AwWebResourceResponse(null, null, null));
671         OnReceivedErrorHelper onReceivedErrorHelper = mContentsClient.getOnReceivedErrorHelper();
672         int onReceivedErrorHelperCallCount = onReceivedErrorHelper.getCallCount();
673         loadUrlSync(mAwContents, mContentsClient.getOnPageFinishedHelper(), pageWithImage);
674         assertEquals(onReceivedErrorHelperCallCount, onReceivedErrorHelper.getCallCount());
675     }
676
677     @SmallTest
678     @Feature({"AndroidWebView"})
679     public void testCalledForIframe() throws Throwable {
680         final String aboutPageUrl = addAboutPageToTestServer(mWebServer);
681         final String pageWithIframeUrl = addPageToTestServer(mWebServer, "/page_with_iframe.html",
682                 CommonResources.makeHtmlPageFrom("",
683                     "<iframe src=\"" + aboutPageUrl + "\"/>"));
684
685         int callCount = mShouldInterceptRequestHelper.getCallCount();
686         loadUrlSync(mAwContents, mContentsClient.getOnPageFinishedHelper(), pageWithIframeUrl);
687         mShouldInterceptRequestHelper.waitForCallback(callCount, 2);
688         assertEquals(2, mShouldInterceptRequestHelper.getUrls().size());
689         assertEquals(aboutPageUrl, mShouldInterceptRequestHelper.getUrls().get(1));
690     }
691
692     private void calledForUrlTemplate(final String url) throws Exception {
693         int callCount = mShouldInterceptRequestHelper.getCallCount();
694         int onPageStartedCallCount = mContentsClient.getOnPageStartedHelper().getCallCount();
695         loadUrlAsync(mAwContents, url);
696         mShouldInterceptRequestHelper.waitForCallback(callCount);
697         assertEquals(url, mShouldInterceptRequestHelper.getUrls().get(0));
698
699         mContentsClient.getOnPageStartedHelper().waitForCallback(onPageStartedCallCount);
700         assertEquals(onPageStartedCallCount + 1,
701                 mContentsClient.getOnPageStartedHelper().getCallCount());
702     }
703
704     private void notCalledForUrlTemplate(final String url) throws Exception {
705         int callCount = mShouldInterceptRequestHelper.getCallCount();
706         loadUrlSync(mAwContents, mContentsClient.getOnPageFinishedHelper(), url);
707         // The intercepting must happen before onPageFinished. Since the IPC messages from the
708         // renderer should be delivered in order waiting for onPageFinished is sufficient to
709         // 'flush' any pending interception messages.
710         assertEquals(callCount, mShouldInterceptRequestHelper.getCallCount());
711     }
712
713     @SmallTest
714     @Feature({"AndroidWebView"})
715     public void testCalledForUnsupportedSchemes() throws Throwable {
716         calledForUrlTemplate("foobar://resource/1");
717     }
718
719     @SmallTest
720     @Feature({"AndroidWebView"})
721     public void testCalledForNonexistentFiles() throws Throwable {
722         calledForUrlTemplate("file:///somewhere/something");
723     }
724
725     @SmallTest
726     @Feature({"AndroidWebView"})
727     public void testCalledForExistingFiles() throws Throwable {
728         final String tmpDir = getInstrumentation().getTargetContext().getCacheDir().getPath();
729         final String fileName = tmpDir + "/testfile.html";
730         final String title = "existing file title";
731         TestFileUtil.deleteFile(fileName);  // Remove leftover file if any.
732         TestFileUtil.createNewHtmlFile(fileName, title, "");
733         final String existingFileUrl = "file://" + fileName;
734
735         int callCount = mShouldInterceptRequestHelper.getCallCount();
736         int onPageFinishedCallCount = mContentsClient.getOnPageFinishedHelper().getCallCount();
737         loadUrlAsync(mAwContents, existingFileUrl);
738         mShouldInterceptRequestHelper.waitForCallback(callCount);
739         assertEquals(existingFileUrl, mShouldInterceptRequestHelper.getUrls().get(0));
740
741         mContentsClient.getOnPageFinishedHelper().waitForCallback(onPageFinishedCallCount);
742         assertEquals(title, getTitleOnUiThread(mAwContents));
743         assertEquals(onPageFinishedCallCount + 1,
744                 mContentsClient.getOnPageFinishedHelper().getCallCount());
745     }
746
747     @SmallTest
748     @Feature({"AndroidWebView"})
749     public void testNotCalledForExistingResource() throws Throwable {
750         notCalledForUrlTemplate("file:///android_res/raw/resource_file.html");
751     }
752
753     @SmallTest
754     @Feature({"AndroidWebView"})
755     public void testCalledForNonexistentResource() throws Throwable {
756         calledForUrlTemplate("file:///android_res/raw/no_file.html");
757     }
758
759     @SmallTest
760     @Feature({"AndroidWebView"})
761     public void testNotCalledForExistingAsset() throws Throwable {
762         notCalledForUrlTemplate("file:///android_asset/asset_file.html");
763     }
764
765     @SmallTest
766     @Feature({"AndroidWebView"})
767     public void testCalledForNonexistentAsset() throws Throwable {
768         calledForUrlTemplate("file:///android_res/raw/no_file.html");
769     }
770
771     @SmallTest
772     @Feature({"AndroidWebView"})
773     public void testNotCalledForExistingContentUrl() throws Throwable {
774         final String contentResourceName = "target";
775         final String existingContentUrl = TestContentProvider.createContentUrl(contentResourceName);
776
777         notCalledForUrlTemplate(existingContentUrl);
778
779         int contentRequestCount = TestContentProvider.getResourceRequestCount(
780                 getInstrumentation().getTargetContext(), contentResourceName);
781         assertEquals(1, contentRequestCount);
782     }
783
784     @SmallTest
785     @Feature({"AndroidWebView"})
786     public void testCalledForNonexistentContentUrl() throws Throwable {
787         calledForUrlTemplate("content://org.chromium.webview.NoSuchProvider/foo");
788     }
789 }