Upstream version 5.34.97.0
[platform/framework/web/crosswalk.git] / src / xwalk / test / android / core / javatests / src / org / xwalk / core / xwview / test / XWalkClientShouldInterceptRequestTest.java
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 // Copyright (c) 2014 Intel Corporation. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5
6 package org.xwalk.core.xwview.test;
7
8 import android.graphics.Bitmap;
9 import android.test.suitebuilder.annotation.SmallTest;
10 import android.util.Log;
11 import android.util.Pair;
12 import android.webkit.WebResourceResponse;
13 import org.chromium.base.test.util.DisabledTest;
14 import org.chromium.base.test.util.Feature;
15 import org.chromium.base.test.util.TestFileUtil;
16 import org.chromium.content.browser.test.util.CallbackHelper;
17 import org.chromium.content.browser.test.util.TestCallbackHelperContainer.OnReceivedErrorHelper;
18 import org.chromium.net.test.util.TestWebServer;
19
20 import org.xwalk.core.xwview.test.util.CommonResources;
21 import org.xwalk.core.XWalkClient;
22 import org.xwalk.core.XWalkContent;
23 import org.xwalk.core.XWalkView;
24
25 import java.io.ByteArrayInputStream;
26 import java.io.IOException;
27 import java.io.InputStream;
28 import java.util.ArrayList;
29 import java.util.List;
30 import java.util.concurrent.Callable;
31 import java.util.concurrent.ConcurrentHashMap;
32 import java.util.concurrent.CountDownLatch;
33
34 /**
35  * Test case for XWalkClient.shouldInterceptRequest callback
36  *
37  * Note the major part of this file is migrated from android_webview/.
38  */
39 public class XWalkClientShouldInterceptRequestTest extends XWalkViewTestBase {
40
41     /**
42      * Customized XWalkClient implementation for shouldInterceptRequest
43      */
44     private class TestXWalkClient extends XWalkClient {
45
46         public class ShouldInterceptRequestHelper extends CallbackHelper {
47             private List<String> mShouldInterceptRequestUrls = new ArrayList<String>();
48             private ConcurrentHashMap<String, WebResourceResponse> mReturnValuesByUrls
49                 = new ConcurrentHashMap<String, WebResourceResponse>();
50             // This is read from the IO thread, so needs to be marked volatile.
51             private volatile WebResourceResponse mResourceResponseReturnValue = null;
52             private String mUrlToWaitFor;
53
54             void setReturnValue(WebResourceResponse value) {
55                 mResourceResponseReturnValue = value;
56             }
57
58             void setReturnValueForUrl(String url, WebResourceResponse value) {
59                 mReturnValuesByUrls.put(url, value);
60             }
61
62             public void setUrlToWaitFor(String url) {
63                 mUrlToWaitFor = url;
64             }
65
66             public List<String> getUrls() {
67                 assert getCallCount() > 0;
68                 return mShouldInterceptRequestUrls;
69             }
70
71             public WebResourceResponse getReturnValue(String url) {
72                 WebResourceResponse value = mReturnValuesByUrls.get(url);
73                 if (value != null) return value;
74                 return mResourceResponseReturnValue;
75             }
76
77             public void notifyCalled(String url) {
78                 if (mUrlToWaitFor == null || mUrlToWaitFor.equals(url)) {
79                     mShouldInterceptRequestUrls.add(url);
80                     notifyCalled();
81                 }
82             }
83         }
84
85         public class OnLoadResourceHelper extends CallbackHelper {
86             private String mUrl;
87
88             public String getUrl() {
89                 assert getCallCount() > 0;
90                 return mUrl;
91             }
92
93             public void notifyCalled(String url) {
94                 mUrl = url;
95                 notifyCalled();
96             }
97         }
98
99         @Override
100         public void onPageStarted(XWalkView view, String url, Bitmap favicon) {
101             mTestContentsClient.onPageStarted(url);
102         }
103
104         @Override
105         public void onPageFinished(XWalkView view, String url) {
106             mTestContentsClient.didFinishLoad(url);
107         }
108
109         @Override
110         public void onReceivedError(XWalkView view, int errorCode,
111                 String description, String failingUrl) {
112             mTestContentsClient.onReceivedError(errorCode, description, failingUrl);
113         }
114
115         @Override
116         public WebResourceResponse shouldInterceptRequest(XWalkView view, String url) {
117             WebResourceResponse response = mShouldInterceptRequestHelper.getReturnValue(url);
118             mShouldInterceptRequestHelper.notifyCalled(url);
119             return response;
120         }
121
122         @Override
123         public void onLoadResource(XWalkView view, String url) {
124             super.onLoadResource(view, url);
125             mOnLoadResourceHelper.notifyCalled(url);
126         }
127
128         private ShouldInterceptRequestHelper mShouldInterceptRequestHelper;
129         private OnLoadResourceHelper mOnLoadResourceHelper;
130
131         public TestXWalkClient() {
132             mShouldInterceptRequestHelper = new ShouldInterceptRequestHelper();
133             mOnLoadResourceHelper = new OnLoadResourceHelper();
134         }
135
136         public ShouldInterceptRequestHelper getShouldInterceptRequestHelper() {
137             return mShouldInterceptRequestHelper;
138         }
139
140         public OnLoadResourceHelper getOnLoadResourceHelper() {
141             return mOnLoadResourceHelper;
142         }
143     }
144
145     private String addPageToTestServer(TestWebServer webServer, String httpPath, String html) {
146         List<Pair<String, String>> headers = new ArrayList<Pair<String, String>>();
147         headers.add(Pair.create("Content-Type", "text/html"));
148         headers.add(Pair.create("Cache-Control", "no-store"));
149         return webServer.setResponse(httpPath, html, headers);
150     }
151
152     private String addAboutPageToTestServer(TestWebServer webServer) {
153         return addPageToTestServer(webServer, "/" + CommonResources.ABOUT_FILENAME,
154                 CommonResources.ABOUT_HTML);
155     }
156
157     private WebResourceResponse stringToWebResourceResponse(String input) throws Throwable {
158         final String mimeType = "text/html";
159         final String encoding = "UTF-8";
160
161         return new WebResourceResponse(
162                 mimeType, encoding, new ByteArrayInputStream(input.getBytes(encoding)));
163     }
164
165     private TestWebServer mWebServer;
166     private TestXWalkClient mTestXWalkClient;
167     private TestXWalkClient.ShouldInterceptRequestHelper mShouldInterceptRequestHelper;
168     private TestXWalkClient.OnLoadResourceHelper mOnLoadResourceHelper;
169
170     @Override
171     protected void setUp() throws Exception {
172         super.setUp();
173
174         getInstrumentation().runOnMainSync(new Runnable() {
175             @Override
176             public void run() {
177                 mTestXWalkClient = new TestXWalkClient();
178                 getXWalkView().setXWalkClient(mTestXWalkClient);
179                 mShouldInterceptRequestHelper = mTestXWalkClient.getShouldInterceptRequestHelper();
180                 mOnLoadResourceHelper = mTestXWalkClient.getOnLoadResourceHelper();
181             }
182         });
183
184         mWebServer = new TestWebServer(false);
185     }
186
187     @Override
188     protected void tearDown() throws Exception {
189         mWebServer.shutdown();
190         super.tearDown();
191     }
192
193     @SmallTest
194     @Feature({"XWalkClientShouldInterceptRequest"})
195     public void testCalledWithCorrectUrl() throws Throwable {
196         final String aboutPageUrl = addAboutPageToTestServer(mWebServer);
197
198         int callCount = mShouldInterceptRequestHelper.getCallCount();
199         int onPageFinishedCallCount = mTestContentsClient.getOnPageFinishedHelper().getCallCount();
200
201         loadUrlAsync(aboutPageUrl);
202
203         mShouldInterceptRequestHelper.waitForCallback(callCount);
204         assertEquals(1, mShouldInterceptRequestHelper.getUrls().size());
205         assertEquals(aboutPageUrl,
206                 mShouldInterceptRequestHelper.getUrls().get(0));
207
208         mTestContentsClient.getOnPageFinishedHelper().waitForCallback(onPageFinishedCallCount);
209         assertEquals(CommonResources.ABOUT_TITLE, getTitleOnUiThread());
210     }
211
212     @SmallTest
213     @Feature({"XWalkClientShouldInterceptRequest"})
214     public void testOnLoadResourceCalledWithCorrectUrl() throws Throwable {
215         final String aboutPageUrl = addAboutPageToTestServer(mWebServer);
216         int callCount = mOnLoadResourceHelper.getCallCount();
217
218         loadUrlAsync(aboutPageUrl);
219
220         mOnLoadResourceHelper.waitForCallback(callCount);
221         assertEquals(aboutPageUrl, mOnLoadResourceHelper.getUrl());
222     }
223
224     @SmallTest
225     @Feature({"XWalkClientShouldInterceptRequest"})
226     public void testDoesNotCrashOnInvalidData() throws Throwable {
227         final String aboutPageUrl = addAboutPageToTestServer(mWebServer);
228
229         mShouldInterceptRequestHelper.setReturnValue(
230                 new WebResourceResponse("text/html", "UTF-8", null));
231         int callCount = mShouldInterceptRequestHelper.getCallCount();
232         loadUrlAsync(aboutPageUrl);
233         mShouldInterceptRequestHelper.waitForCallback(callCount);
234
235         mShouldInterceptRequestHelper.setReturnValue(
236                 new WebResourceResponse(null, null, new ByteArrayInputStream(new byte[0])));
237         callCount = mShouldInterceptRequestHelper.getCallCount();
238         loadUrlAsync(aboutPageUrl);
239         mShouldInterceptRequestHelper.waitForCallback(callCount);
240
241         mShouldInterceptRequestHelper.setReturnValue(
242                 new WebResourceResponse(null, null, null));
243         callCount = mShouldInterceptRequestHelper.getCallCount();
244         loadUrlAsync(aboutPageUrl);
245         mShouldInterceptRequestHelper.waitForCallback(callCount);
246     }
247
248     private static class EmptyInputStream extends InputStream {
249         @Override
250         public int available() {
251             return 0;
252         }
253
254         @Override
255         public int read() throws IOException {
256             return -1;
257         }
258
259         @Override
260         public int read(byte b[]) throws IOException {
261             return -1;
262         }
263
264         @Override
265         public int read(byte b[], int off, int len) throws IOException {
266             return -1;
267         }
268
269         @Override
270         public long skip(long n) throws IOException {
271             if (n < 0)
272                 throw new IOException("skipping negative number of bytes");
273             return 0;
274         }
275     }
276
277     @SmallTest
278     @Feature({"XWalkClientShouldInterceptRequest"})
279     public void testDoesNotCrashOnEmptyStream() throws Throwable {
280         final String aboutPageUrl = addAboutPageToTestServer(mWebServer);
281
282         mShouldInterceptRequestHelper.setReturnValue(
283                 new WebResourceResponse("text/html", "UTF-8", new EmptyInputStream()));
284         int shouldInterceptRequestCallCount = mShouldInterceptRequestHelper.getCallCount();
285         int onPageFinishedCallCount = mTestContentsClient.getOnPageFinishedHelper().getCallCount();
286
287         loadUrlAsync(aboutPageUrl);
288
289         mShouldInterceptRequestHelper.waitForCallback(shouldInterceptRequestCallCount);
290         mTestContentsClient.getOnPageFinishedHelper().waitForCallback(onPageFinishedCallCount);
291     }
292
293     private static class SlowWebResourceResponse extends WebResourceResponse {
294         private CallbackHelper mReadStartedCallbackHelper = new CallbackHelper();
295         private CountDownLatch mLatch = new CountDownLatch(1);
296
297         public SlowWebResourceResponse(String mimeType, String encoding, InputStream data) {
298             super(mimeType, encoding, data);
299         }
300
301         @Override
302         public InputStream getData() {
303             mReadStartedCallbackHelper.notifyCalled();
304             try {
305                 mLatch.await();
306             } catch (InterruptedException e) {
307                 // ignore
308             }
309             return super.getData();
310         }
311
312         public void unblockReads() {
313             mLatch.countDown();
314         }
315
316         public CallbackHelper getReadStartedCallbackHelper() {
317             return mReadStartedCallbackHelper;
318         }
319     }
320
321     //@SmallTest
322     //@Feature({"XWalkClientShouldInterceptRequest"})
323     // TODO(gaochun): Enable it once the issue XWALK-1022 gets resolved.
324     @DisabledTest
325     public void testHttpStatusField() throws Throwable {
326         final String syncGetUrl = mWebServer.getResponseUrl("/intercept_me");
327         final String syncGetJs =
328             "(function() {" +
329             "  var xhr = new XMLHttpRequest();" +
330             "  xhr.open('GET', '" + syncGetUrl + "', false);" +
331             "  xhr.send(null);" +
332             "  console.info('xhr.status = ' + xhr.status);" +
333             "  return xhr.status;" +
334             "})();";
335
336         getInstrumentation().runOnMainSync(new Runnable() {
337             @Override
338             public void run() {
339                 getXWalkView().getSettings().setJavaScriptEnabled(true);
340             }
341         });
342
343         final String aboutPageUrl = addAboutPageToTestServer(mWebServer);
344         loadUrlSync(aboutPageUrl);
345
346         mShouldInterceptRequestHelper.setReturnValue(
347                 new WebResourceResponse("text/html", "UTF-8", null));
348         assertEquals("404", executeJavaScriptAndWaitForResult(syncGetJs));
349
350         mShouldInterceptRequestHelper.setReturnValue(
351                 new WebResourceResponse("text/html", "UTF-8", new EmptyInputStream()));
352         assertEquals("200", executeJavaScriptAndWaitForResult(syncGetJs));
353     }
354
355
356     private String makePageWithTitle(String title) {
357         return CommonResources.makeHtmlPageFrom("<title>" + title + "</title>",
358                 "<div> The title is: " + title + " </div>");
359     }
360
361     @SmallTest
362     @Feature({"XWalkClientShouldInterceptRequest"})
363     public void testCanInterceptMainFrame() throws Throwable {
364         final String expectedTitle = "testShouldInterceptRequestCanInterceptMainFrame";
365         final String expectedPage = makePageWithTitle(expectedTitle);
366
367         mShouldInterceptRequestHelper.setReturnValue(
368                 stringToWebResourceResponse(expectedPage));
369
370         final String aboutPageUrl = addAboutPageToTestServer(mWebServer);
371
372         loadUrlSync(aboutPageUrl);
373
374         assertEquals(expectedTitle, getTitleOnUiThread());
375         assertEquals(0, mWebServer.getRequestCount("/" + CommonResources.ABOUT_FILENAME));
376     }
377
378     @SmallTest
379     @Feature({"XWalkClientShouldInterceptRequest"})
380     public void testDoesNotChangeReportedUrl() throws Throwable {
381         mShouldInterceptRequestHelper.setReturnValue(
382                 stringToWebResourceResponse(makePageWithTitle("some title")));
383
384         final String aboutPageUrl = addAboutPageToTestServer(mWebServer);
385
386         loadUrlSync(aboutPageUrl);
387
388         assertEquals(aboutPageUrl, mTestContentsClient.getOnPageFinishedHelper().getUrl());
389         assertEquals(aboutPageUrl, mTestContentsClient.getOnPageStartedHelper().getUrl());
390     }
391
392     @SmallTest
393     @Feature({"XWalkClientShouldInterceptRequest"})
394     public void testNullInputStreamCausesErrorForMainFrame() throws Throwable {
395         final OnReceivedErrorHelper onReceivedErrorHelper = mTestContentsClient.getOnReceivedErrorHelper();
396         mShouldInterceptRequestHelper.setReturnValue(
397                 new WebResourceResponse("text/html", "UTF-8", null));
398
399         final String aboutPageUrl = addAboutPageToTestServer(mWebServer);
400         final int callCount = onReceivedErrorHelper.getCallCount();
401         loadUrlAsync(aboutPageUrl);
402         onReceivedErrorHelper.waitForCallback(callCount);
403         assertEquals(0, mWebServer.getRequestCount("/" + CommonResources.ABOUT_FILENAME));
404     }
405
406     @SmallTest
407     @Feature({"XWalkClientShouldInterceptRequest"})
408     public void testCalledForImage() throws Throwable {
409         final String imagePath = "/" + CommonResources.FAVICON_FILENAME;
410         mWebServer.setResponseBase64(imagePath,
411                 CommonResources.FAVICON_DATA_BASE64, CommonResources.getImagePngHeaders(true));
412         final String pageWithImage =
413             addPageToTestServer(mWebServer, "/page_with_image.html",
414                     CommonResources.getOnImageLoadedHtml(CommonResources.FAVICON_FILENAME));
415
416         int callCount = mShouldInterceptRequestHelper.getCallCount();
417         loadUrlSync(pageWithImage);
418         mShouldInterceptRequestHelper.waitForCallback(callCount, 2);
419
420         assertEquals(2, mShouldInterceptRequestHelper.getUrls().size());
421         assertTrue(mShouldInterceptRequestHelper.getUrls().get(1).endsWith(
422                 CommonResources.FAVICON_FILENAME));
423     }
424
425     @SmallTest
426     @Feature({"XWalkClientShouldInterceptRequest"})
427     public void testOnReceivedErrorCallback() throws Throwable {
428         final OnReceivedErrorHelper onReceivedErrorHelper = mTestContentsClient.getOnReceivedErrorHelper();
429         mShouldInterceptRequestHelper.setReturnValue(new WebResourceResponse(null, null, null));
430         int onReceivedErrorHelperCallCount = onReceivedErrorHelper.getCallCount();
431         loadUrlSync("foo://bar");
432         onReceivedErrorHelper.waitForCallback(onReceivedErrorHelperCallCount, 1);
433     }
434
435     @SmallTest
436     @Feature({"XWalkClientShouldInterceptRequest"})
437     public void testNoOnReceivedErrorCallback() throws Throwable {
438         final String imagePath = "/" + CommonResources.FAVICON_FILENAME;
439         final String imageUrl = mWebServer.setResponseBase64(imagePath,
440                 CommonResources.FAVICON_DATA_BASE64, CommonResources.getImagePngHeaders(true));
441         final String pageWithImage =
442                 addPageToTestServer(mWebServer, "/page_with_image.html",
443                         CommonResources.getOnImageLoadedHtml(CommonResources.FAVICON_FILENAME));
444         final OnReceivedErrorHelper onReceivedErrorHelper = mTestContentsClient.getOnReceivedErrorHelper();
445         mShouldInterceptRequestHelper.setReturnValueForUrl(
446                 imageUrl, new WebResourceResponse(null, null, null));
447         int onReceivedErrorHelperCallCount = onReceivedErrorHelper.getCallCount();
448         loadUrlSync(pageWithImage);
449         assertEquals(onReceivedErrorHelperCallCount, onReceivedErrorHelper.getCallCount());
450     }
451
452     @SmallTest
453     @Feature({"XWalkClientShouldInterceptRequest"})
454     public void testCalledForIframe() throws Throwable {
455         final String aboutPageUrl = addAboutPageToTestServer(mWebServer);
456         final String pageWithIframe = addPageToTestServer(mWebServer, "/page_with_iframe.html",
457                 CommonResources.makeHtmlPageFrom("",
458                     "<iframe src=\"" + aboutPageUrl + "\"/>"));
459
460         int callCount = mShouldInterceptRequestHelper.getCallCount();
461         // These callbacks can race with favicon.ico callback.
462         mShouldInterceptRequestHelper.setUrlToWaitFor(aboutPageUrl);
463         loadUrlSync(pageWithIframe);
464
465         mShouldInterceptRequestHelper.waitForCallback(callCount, 1);
466         assertEquals(1, mShouldInterceptRequestHelper.getUrls().size());
467         assertEquals(aboutPageUrl, mShouldInterceptRequestHelper.getUrls().get(0));
468     }
469
470     private void calledForUrlTemplate(final String url) throws Exception {
471         int callCount = mShouldInterceptRequestHelper.getCallCount();
472         int onPageStartedCallCount = mTestContentsClient.getOnPageStartedHelper().getCallCount();
473         loadUrlAsync(url);
474         mShouldInterceptRequestHelper.waitForCallback(callCount);
475         assertEquals(url, mShouldInterceptRequestHelper.getUrls().get(0));
476
477         mTestContentsClient.getOnPageStartedHelper().waitForCallback(onPageStartedCallCount);
478         assertEquals(onPageStartedCallCount + 1,
479                 mTestContentsClient.getOnPageStartedHelper().getCallCount());
480     }
481
482     private void notCalledForUrlTemplate(final String url) throws Exception {
483         int callCount = mShouldInterceptRequestHelper.getCallCount();
484         loadUrlSync(url);
485         // The intercepting must happen before onPageFinished. Since the IPC messages from the
486         // renderer should be delivered in order waiting for onPageFinished is sufficient to
487         // 'flush' any pending interception messages.
488         assertEquals(callCount, mShouldInterceptRequestHelper.getCallCount());
489     }
490
491     @SmallTest
492     @Feature({"XWalkClientShouldInterceptRequest"})
493     public void testCalledForUnsupportedSchemes() throws Throwable {
494         calledForUrlTemplate("foobar://resource/1");
495     }
496
497     @SmallTest
498     @Feature({"XWalkClientShouldInterceptRequest"})
499     public void testCalledForNonexistentFiles() throws Throwable {
500         calledForUrlTemplate("file:///somewhere/something");
501     }
502
503     @SmallTest
504     @Feature({"XWalkClientShouldInterceptRequest"})
505     public void testCalledForExistingFiles() throws Throwable {
506         final String tmpDir = getInstrumentation().getTargetContext().getCacheDir().getPath();
507         final String fileName = tmpDir + "/testfile.html";
508         final String title = "existing file title";
509         TestFileUtil.deleteFile(fileName);  // Remove leftover file if any.
510         TestFileUtil.createNewHtmlFile(fileName, title, "");
511         final String existingFileUrl = "file://" + fileName;
512
513         int callCount = mShouldInterceptRequestHelper.getCallCount();
514         int onPageFinishedCallCount = mTestContentsClient.getOnPageFinishedHelper().getCallCount();
515         loadUrlAsync(existingFileUrl);
516         mShouldInterceptRequestHelper.waitForCallback(callCount);
517         assertEquals(existingFileUrl, mShouldInterceptRequestHelper.getUrls().get(0));
518
519         mTestContentsClient.getOnPageFinishedHelper().waitForCallback(onPageFinishedCallCount);
520         assertEquals(title, getTitleOnUiThread());
521         assertEquals(onPageFinishedCallCount + 1,
522                 mTestContentsClient.getOnPageFinishedHelper().getCallCount());
523     }
524
525     @SmallTest
526     @Feature({"XWalkClientShouldInterceptRequest"})
527     public void testNotCalledForExistingResource() throws Throwable {
528         notCalledForUrlTemplate("file:///android_res/raw/resource_file.html");
529     }
530
531     @SmallTest
532     @Feature({"XWalkClientShouldInterceptRequest"})
533     public void testCalledForNonexistentResource() throws Throwable {
534         calledForUrlTemplate("file:///android_res/raw/no_file.html");
535     }
536
537     @SmallTest
538     @Feature({"XWalkClientShouldInterceptRequest"})
539     public void testNotCalledForExistingAsset() throws Throwable {
540         notCalledForUrlTemplate("file:///android_asset/www/index.html");
541     }
542
543     @SmallTest
544     @Feature({"XWalkClientShouldInterceptRequest"})
545     public void testCalledForNonexistentAsset() throws Throwable {
546         calledForUrlTemplate("file:///android_res/raw/no_file.html");
547     }
548
549     @SmallTest
550     @Feature({"XWalkClientShouldInterceptRequest"})
551     public void testNotCalledForExistingContentUrl() throws Throwable {
552         final String contentResourceName = "target";
553         final String existingContentUrl = TestContentProvider.createContentUrl(contentResourceName);
554         TestContentProvider.resetResourceRequestCount(
555                 getInstrumentation().getTargetContext(), contentResourceName);
556
557         notCalledForUrlTemplate(existingContentUrl);
558
559         int contentRequestCount = TestContentProvider.getResourceRequestCount(
560                 getInstrumentation().getTargetContext(), contentResourceName);
561         assertEquals(1, contentRequestCount);
562     }
563
564     @SmallTest
565     @Feature({"XWalkClientShouldInterceptRequest"})
566     public void testCalledForNonexistentContentUrl() throws Throwable {
567         calledForUrlTemplate("content://org.xwalk.core.test.NoSuchProvider/foo");
568     }
569 }