[CB-3384] Rewrite of DataResource into UriResolver + UriResolvers

Includes unit tests woot!

Note that this remove CordovaPlugin.shouldInterceptRequest(). Should be
fine since this method was introduced only a couple of releases ago, was
never documented, and afaict was only used by the Chrome Cordova plugins.
This commit is contained in:
Andrew Grieve 2013-06-07 10:17:28 -04:00
parent fbf7f1c3f9
commit 892ffc8ce4
9 changed files with 694 additions and 77 deletions

View File

@ -943,4 +943,38 @@ public class CordovaWebView extends WebView {
public void storeResult(int requestCode, int resultCode, Intent intent) {
mResult = new ActivityResult(requestCode, resultCode, intent);
}
/**
* Resolves the given URI, giving plugins a chance to re-route or customly handle the URI.
* A white-list rejection will be returned if the URI does not pass the white-list.
* @return Never returns null.
* @throws Throws an InvalidArgumentException for relative URIs. Relative URIs should be
* resolved before being passed into this function.
*/
public UriResolver resolveUri(Uri uri) {
return resolveUri(uri, false);
}
UriResolver resolveUri(Uri uri, boolean fromWebView) {
if (!uri.isAbsolute()) {
throw new IllegalArgumentException("Relative URIs are not yet supported by resolveUri.");
}
// Check the against the white-list before delegating to plugins.
if (("http".equals(uri.getScheme()) || "https".equals(uri.getScheme())) && !Config.isUrlWhiteListed(uri.toString()))
{
LOG.w(TAG, "resolveUri - URL is not in whitelist: " + uri);
return new UriResolvers.ErrorUriResolver(uri, "Whitelist rejection");
}
// Give plugins a chance to handle the request.
UriResolver resolver = pluginManager.resolveUri(uri);
if (resolver == null && !fromWebView) {
resolver = UriResolvers.forUri(uri, cordova.getActivity());
if (resolver == null) {
resolver = new UriResolvers.ErrorUriResolver(uri, "Unresolvable URI");
}
}
return resolver;
}
}

View File

@ -26,9 +26,12 @@ import org.apache.cordova.api.CordovaInterface;
import org.apache.cordova.api.LOG;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URLConnection;
import java.io.OutputStream;
import java.nio.charset.Charset;
import java.util.Locale;
public class FileHelper {
@ -124,6 +127,20 @@ public class FileHelper {
return uriString;
}
public static String getMimeTypeForExtension(String path) {
String extension = path;
int lastDot = extension.lastIndexOf('.');
if (lastDot != -1) {
extension = extension.substring(lastDot + 1);
}
// Convert the URI string to lower case to ensure compatibility with MimeTypeMap (see CB-2185).
extension = extension.toLowerCase(Locale.getDefault());
if (extension.equals("3ga")) {
return "audio/3gpp";
}
return MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension);
}
/**
* Returns the mime type of the data specified by the given URI string.
*
@ -137,19 +154,7 @@ public class FileHelper {
if (uriString.startsWith("content://")) {
mimeType = cordova.getActivity().getContentResolver().getType(uri);
} else {
// MimeTypeMap.getFileExtensionFromUrl() fails when there are query parameters.
String extension = uri.getPath();
int lastDot = extension.lastIndexOf('.');
if (lastDot != -1) {
extension = extension.substring(lastDot + 1);
}
// Convert the URI string to lower case to ensure compatibility with MimeTypeMap (see CB-2185).
extension = extension.toLowerCase();
if (extension.equals("3ga")) {
mimeType = "audio/3gpp";
} else {
mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension);
}
mimeType = getMimeTypeForExtension(uri.getPath());
}
return mimeType;

View File

@ -18,7 +18,6 @@
*/
package org.apache.cordova;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
@ -26,6 +25,7 @@ import org.apache.cordova.api.CordovaInterface;
import org.apache.cordova.api.LOG;
import android.annotation.TargetApi;
import android.net.Uri;
import android.os.Build;
import android.webkit.WebResourceResponse;
import android.webkit.WebView;
@ -44,45 +44,29 @@ public class IceCreamCordovaWebViewClient extends CordovaWebViewClient {
@Override
public WebResourceResponse shouldInterceptRequest(WebView view, String url) {
//Check if plugins intercept the request
WebResourceResponse ret = super.shouldInterceptRequest(view, url);
UriResolver uriResolver = appView.resolveUri(Uri.parse(url), true);
if(!Config.isUrlWhiteListed(url) && (url.startsWith("http://") || url.startsWith("https://")))
{
ret = getWhitelistResponse();
if (uriResolver == null && url.startsWith("file:///android_asset/")) {
if (url.contains("?") || url.contains("#") || needsIceCreamSpecialsInAssetUrlFix(url)) {
uriResolver = appView.resolveUri(Uri.parse(url), false);
}
}
else if(ret == null && (url.contains("?") || url.contains("#") || needsIceCreamSpecialsInAssetUrlFix(url))){
ret = generateWebResourceResponse(url);
}
else if (ret == null && this.appView.pluginManager != null) {
ret = this.appView.pluginManager.shouldInterceptRequest(url);
}
return ret;
}
private WebResourceResponse getWhitelistResponse()
{
WebResourceResponse emptyResponse;
String empty = "";
ByteArrayInputStream data = new ByteArrayInputStream(empty.getBytes());
return new WebResourceResponse("text/plain", "UTF-8", data);
}
private WebResourceResponse generateWebResourceResponse(String url) {
if (url.startsWith("file:///android_asset/")) {
String mimetype = FileHelper.getMimeType(url, cordova);
if (uriResolver != null) {
try {
InputStream stream = FileHelper.getInputStreamFromUriString(url, cordova);
WebResourceResponse response = new WebResourceResponse(mimetype, "UTF-8", stream);
return response;
InputStream stream = uriResolver.getInputStream();
String mimeType = uriResolver.getMimeType();
// If we don't know how to open this file, let the browser continue loading
return new WebResourceResponse(mimeType, "UTF-8", stream);
} catch (IOException e) {
LOG.e("generateWebResourceResponse", e.getMessage(), e);
LOG.e("IceCreamCordovaWebViewClient", "Error occurred while loading a file.", e);
// Results in a 404.
return new WebResourceResponse("text/plain", "UTF-8", null);
}
}
return null;
}
private static boolean needsIceCreamSpecialsInAssetUrlFix(String url) {
if (!url.contains("%20")){
return false;
@ -96,5 +80,4 @@ public class IceCreamCordovaWebViewClient extends CordovaWebViewClient {
return false;
}
}
}

View File

@ -0,0 +1,65 @@
/*
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
*/
package org.apache.cordova;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import android.net.Uri;
/*
* Interface for a class that can resolve URIs.
* See CordovaUriResolver for an example.
*/
public interface UriResolver {
/** Returns the URI that this instance will resolve. */
Uri getUri();
/**
* Returns the InputStream for the resource.
* Throws an exception if it cannot be read.
* Never returns null.
*/
InputStream getInputStream() throws IOException;
/**
* Returns the OutputStream for the resource.
* Throws an exception if it cannot be written to.
* Never returns null.
*/
OutputStream getOutputStream() throws IOException;
/**
* Returns the MIME type of the resource.
* Returns null if the MIME type cannot be determined (e.g. content: that doesn't exist).
*/
String getMimeType();
/** Returns whether the resource is writable. */
boolean isWritable();
/**
* Returns a File that points to the resource, or null if the resource
* is not on the local file system.
*/
File getLocalFile();
}

View File

@ -0,0 +1,277 @@
/*
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
*/
package org.apache.cordova;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import org.apache.cordova.FileHelper;
import org.apache.http.util.EncodingUtils;
import android.content.ContentResolver;
import android.content.Context;
import android.content.res.AssetManager;
import android.net.Uri;
/*
* UriResolver implementations.
*/
public final class UriResolvers {
private UriResolvers() {}
private static final class FileUriResolver implements UriResolver {
private final Uri uri;
private String mimeType;
private File localFile;
FileUriResolver(Uri uri) {
this.uri = uri;
}
public Uri getUri() {
return uri;
}
public InputStream getInputStream() throws IOException {
return new FileInputStream(getLocalFile());
}
public OutputStream getOutputStream() throws FileNotFoundException {
return new FileOutputStream(getLocalFile());
}
public String getMimeType() {
if (mimeType == null) {
mimeType = FileHelper.getMimeTypeForExtension(getLocalFile().getName());
}
return mimeType;
}
public boolean isWritable() {
File f = getLocalFile();
if (f.isDirectory()) {
return false;
}
if (f.exists()) {
return f.canWrite();
}
return f.getParentFile().canWrite();
}
public File getLocalFile() {
if (localFile == null) {
localFile = new File(uri.getPath());
}
return localFile;
}
}
private static final class AssetUriResolver implements UriResolver {
private final Uri uri;
private final AssetManager assetManager;
private final String assetPath;
private String mimeType;
AssetUriResolver(Uri uri, AssetManager assetManager) {
this.uri = uri;
this.assetManager = assetManager;
this.assetPath = uri.getPath().substring(15);
}
public Uri getUri() {
return uri;
}
public InputStream getInputStream() throws IOException {
return assetManager.open(assetPath);
}
public OutputStream getOutputStream() throws FileNotFoundException {
throw new FileNotFoundException("URI not writable.");
}
public String getMimeType() {
if (mimeType == null) {
mimeType = FileHelper.getMimeTypeForExtension(assetPath);
}
return mimeType;
}
public boolean isWritable() {
return false;
}
public File getLocalFile() {
return null;
}
}
private static final class ContentUriResolver implements UriResolver {
private final Uri uri;
private final ContentResolver contentResolver;
private String mimeType;
ContentUriResolver(Uri uri, ContentResolver contentResolver) {
this.uri = uri;
this.contentResolver = contentResolver;
}
public Uri getUri() {
return uri;
}
public InputStream getInputStream() throws IOException {
return contentResolver.openInputStream(uri);
}
public OutputStream getOutputStream() throws FileNotFoundException {
return contentResolver.openOutputStream(uri);
}
public String getMimeType() {
if (mimeType == null) {
mimeType = contentResolver.getType(uri);
}
return mimeType;
}
public boolean isWritable() {
return uri.getScheme().equals(ContentResolver.SCHEME_CONTENT);
}
public File getLocalFile() {
return null;
}
}
static final class ErrorUriResolver implements UriResolver {
final Uri uri;
final String errorMsg;
ErrorUriResolver(Uri uri, String errorMsg) {
this.uri = uri;
this.errorMsg = errorMsg;
}
@Override
public boolean isWritable() {
return false;
}
@Override
public Uri getUri() {
return uri;
}
@Override
public File getLocalFile() {
return null;
}
@Override
public OutputStream getOutputStream() throws IOException {
throw new FileNotFoundException(errorMsg);
}
@Override
public String getMimeType() {
return null;
}
@Override
public InputStream getInputStream() throws IOException {
throw new FileNotFoundException(errorMsg);
}
}
private static final class ReadOnlyResolver implements UriResolver {
private Uri uri;
private InputStream inputStream;
private String mimeType;
public ReadOnlyResolver(Uri uri, InputStream inputStream, String mimeType) {
this.uri = uri;
this.inputStream = inputStream;
this.mimeType = mimeType;
}
@Override
public boolean isWritable() {
return false;
}
@Override
public Uri getUri() {
return uri;
}
@Override
public File getLocalFile() {
return null;
}
@Override
public OutputStream getOutputStream() throws IOException {
throw new FileNotFoundException("URI is not writable");
}
@Override
public String getMimeType() {
return mimeType;
}
@Override
public InputStream getInputStream() throws IOException {
return inputStream;
}
}
public static UriResolver createInline(Uri uri, String response, String mimeType) {
return createInline(uri, EncodingUtils.getBytes(response, "UTF-8"), mimeType);
}
public static UriResolver createInline(Uri uri, byte[] response, String mimeType) {
return new ReadOnlyResolver(uri, new ByteArrayInputStream(response), mimeType);
}
public static UriResolver createReadOnly(Uri uri, InputStream inputStream, String mimeType) {
return new ReadOnlyResolver(uri, inputStream, mimeType);
}
/* Package-private to force clients to go through CordovaWebView.resolveUri(). */
static UriResolver forUri(Uri uri, Context context) {
String scheme = uri.getScheme();
if (ContentResolver.SCHEME_CONTENT.equals(scheme) || ContentResolver.SCHEME_ANDROID_RESOURCE.equals(scheme)) {
return new ContentUriResolver(uri, context.getContentResolver());
}
if (ContentResolver.SCHEME_FILE.equals(scheme)) {
if (uri.getPath().startsWith("/android_asset/")) {
return new AssetUriResolver(uri, context.getAssets());
}
return new FileUriResolver(uri);
}
return null;
}
}

View File

@ -20,14 +20,12 @@ package org.apache.cordova.api;
import org.apache.cordova.CordovaArgs;
import org.apache.cordova.CordovaWebView;
import org.apache.cordova.UriResolver;
import org.json.JSONArray;
import org.json.JSONException;
import android.annotation.TargetApi;
import android.content.Intent;
import android.os.Build;
import android.util.Log;
import android.webkit.WebResourceResponse;
import android.net.Uri;
/**
* Plugins must extend this class and override one of the execute methods.
@ -165,13 +163,10 @@ public class CordovaPlugin {
}
/**
* By specifying a <url-filter> in config.xml you can map a URL prefix to this method. It applies to all resources loaded in the WebView, not just top-level navigation.
*
* @param url The URL of the resource to be loaded.
* @return Return a WebResourceResponse for the resource, or null to let the WebView handle it normally.
* Hook for overriding the default URI handling mechanism.
* Applies to WebView requests as well as requests made by plugins.
*/
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
public WebResourceResponse shouldInterceptRequest(String url) {
public UriResolver resolveUri(Uri uri) {
return null;
}

View File

@ -26,12 +26,14 @@ import java.util.concurrent.atomic.AtomicInteger;
import org.apache.cordova.CordovaArgs;
import org.apache.cordova.CordovaWebView;
import org.apache.cordova.UriResolver;
import org.json.JSONException;
import org.xmlpull.v1.XmlPullParserException;
import android.content.Intent;
import android.content.res.XmlResourceParser;
import android.net.Uri;
import android.util.Log;
import android.webkit.WebResourceResponse;
@ -379,25 +381,6 @@ public class PluginManager {
return false;
}
/**
* Called when the WebView is loading any resource, top-level or not.
*
* Uses the same url-filter tag as onOverrideUrlLoading.
*
* @param url The URL of the resource to be loaded.
* @return Return a WebResourceResponse with the resource, or null if the WebView should handle it.
*/
public WebResourceResponse shouldInterceptRequest(String url) {
Iterator<Entry<String, String>> it = this.urlMap.entrySet().iterator();
while (it.hasNext()) {
HashMap.Entry<String, String> pairs = it.next();
if (url.startsWith(pairs.getKey())) {
return this.getPlugin(pairs.getValue()).shouldInterceptRequest(url);
}
}
return null;
}
/**
* Called when the app navigates or refreshes.
*/
@ -419,6 +402,18 @@ public class PluginManager {
LOG.e(TAG, "=====================================================================================");
}
/* Should be package private */ public UriResolver resolveUri(Uri uri) {
for (PluginEntry entry : this.entries.values()) {
if (entry.plugin != null) {
UriResolver ret = entry.plugin.resolveUri(uri);
if (ret != null) {
return ret;
}
}
}
return null;
}
private class PluginManagerService extends CordovaPlugin {
@Override
public boolean execute(String action, CordovaArgs args, final CallbackContext callbackContext) throws JSONException {

View File

@ -0,0 +1,263 @@
package org.apache.cordova.test;
/*
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*/
import org.apache.cordova.CordovaWebView;
import org.apache.cordova.UriResolver;
import org.apache.cordova.UriResolvers;
import org.apache.cordova.api.CallbackContext;
import org.apache.cordova.api.CordovaPlugin;
import org.apache.cordova.api.PluginEntry;
import org.apache.cordova.test.actions.CordovaWebViewTestActivity;
import org.json.JSONArray;
import org.json.JSONException;
import java.io.File;
import java.io.IOException;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Environment;
import android.provider.MediaStore;
import android.test.ActivityInstrumentationTestCase2;
import android.util.Log;
public class UriResolversTest extends ActivityInstrumentationTestCase2<CordovaWebViewTestActivity> {
public UriResolversTest()
{
super(CordovaWebViewTestActivity.class);
}
CordovaWebView cordovaWebView;
private CordovaWebViewTestActivity activity;
String execPayload;
Integer execStatus;
protected void setUp() throws Exception {
super.setUp();
activity = this.getActivity();
cordovaWebView = activity.cordovaWebView;
cordovaWebView.pluginManager.addService(new PluginEntry("UriResolverTestPlugin1", new CordovaPlugin() {
@Override
public UriResolver resolveUri(Uri uri) {
if ("plugin-uri".equals(uri.getScheme())) {
return cordovaWebView.resolveUri(uri.buildUpon().scheme("file").build());
}
return null;
}
public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException {
synchronized (UriResolversTest.this) {
execPayload = args.getString(0);
execStatus = args.getInt(1);
UriResolversTest.this.notify();
}
return true;
}
}));
cordovaWebView.pluginManager.addService(new PluginEntry("UriResolverTestPlugin2", new CordovaPlugin() {
@Override
public UriResolver resolveUri(Uri uri) {
if (uri.getQueryParameter("pluginRewrite") != null) {
return UriResolvers.createInline(uri, "pass", "my/mime");
}
return null;
}
}));
}
private Uri createTestImageContentUri() {
Bitmap imageBitmap = BitmapFactory.decodeResource(activity.getResources(), R.drawable.icon);
String stored = MediaStore.Images.Media.insertImage(activity.getContentResolver(),
imageBitmap, "app-icon", "desc");
return Uri.parse(stored);
}
private void performResolverTest(Uri uri, String expectedMimeType, File expectedLocalFile,
boolean expectedIsWritable,
boolean expectRead, boolean expectWrite) throws IOException {
UriResolver resolver = cordovaWebView.resolveUri(uri);
assertEquals(expectedLocalFile, resolver.getLocalFile());
assertEquals(expectedMimeType, resolver.getMimeType());
if (expectedIsWritable) {
assertTrue(resolver.isWritable());
} else {
assertFalse(resolver.isWritable());
}
try {
resolver.getInputStream().read();
if (!expectRead) {
fail("Expected getInputStream to throw.");
}
} catch (IOException e) {
if (expectRead) {
throw e;
}
}
try {
resolver.getOutputStream().write(123);
if (!expectWrite) {
fail("Expected getOutputStream to throw.");
}
} catch (IOException e) {
if (expectWrite) {
throw e;
}
}
}
public void testValidContentUri() throws IOException
{
Uri contentUri = createTestImageContentUri();
performResolverTest(contentUri, "image/jpeg", null, true, true, true);
}
public void testInvalidContentUri() throws IOException
{
Uri contentUri = Uri.parse("content://media/external/images/media/999999999");
performResolverTest(contentUri, null, null, true, false, false);
}
public void testValidAssetUri() throws IOException
{
Uri assetUri = Uri.parse("file:///android_asset/www/index.html?foo#bar"); // Also check for stripping off ? and # correctly.
performResolverTest(assetUri, "text/html", null, false, true, false);
}
public void testInvalidAssetUri() throws IOException
{
Uri assetUri = Uri.parse("file:///android_asset/www/missing.html");
performResolverTest(assetUri, "text/html", null, false, false, false);
}
public void testFileUriToExistingFile() throws IOException
{
File f = File.createTempFile("te s t", ".txt"); // Also check for dealing with spaces.
try {
Uri fileUri = Uri.parse(f.toURI().toString() + "?foo#bar"); // Also check for stripping off ? and # correctly.
performResolverTest(fileUri, "text/plain", f, true, true, true);
} finally {
f.delete();
}
}
public void testFileUriToMissingFile() throws IOException
{
File f = new File(Environment.getExternalStorageDirectory() + "/somefilethatdoesntexist");
Uri fileUri = Uri.parse(f.toURI().toString());
try {
performResolverTest(fileUri, null, f, true, false, true);
} finally {
f.delete();
}
}
public void testFileUriToMissingFileWithMissingParent() throws IOException
{
File f = new File(Environment.getExternalStorageDirectory() + "/somedirthatismissing/somefilethatdoesntexist");
Uri fileUri = Uri.parse(f.toURI().toString());
performResolverTest(fileUri, null, f, false, false, false);
}
public void testUnrecognizedUri() throws IOException
{
Uri uri = Uri.parse("somescheme://foo");
performResolverTest(uri, null, null, false, false, false);
}
public void testRelativeUri()
{
try {
cordovaWebView.resolveUri(Uri.parse("/foo"));
fail("Should have thrown for relative URI 1.");
} catch (Throwable t) {
}
try {
cordovaWebView.resolveUri(Uri.parse("//foo/bar"));
fail("Should have thrown for relative URI 2.");
} catch (Throwable t) {
}
try {
cordovaWebView.resolveUri(Uri.parse("foo.png"));
fail("Should have thrown for relative URI 3.");
} catch (Throwable t) {
}
}
public void testPluginOverrides1() throws IOException
{
Uri uri = Uri.parse("plugin-uri://foohost/android_asset/www/index.html");
performResolverTest(uri, "text/html", null, false, true, false);
}
public void testPluginOverrides2() throws IOException
{
Uri uri = Uri.parse("plugin-uri://foohost/android_asset/www/index.html?pluginRewrite=yes");
performResolverTest(uri, "my/mime", null, false, true, false);
}
public void testWhitelistRejection() throws IOException
{
Uri uri = Uri.parse("http://foohost.com/");
performResolverTest(uri, null, null, false, false, false);
}
public void testWebViewRequestIntercept() throws IOException
{
cordovaWebView.sendJavascript(
"var x = new XMLHttpRequest;\n" +
"x.open('GET', 'file://foo?pluginRewrite=1', false);\n" +
"x.send();\n" +
"cordova.require('cordova/exec')(null,null,'UriResolverTestPlugin1', 'foo', [x.responseText, x.status])");
execPayload = null;
execStatus = null;
try {
synchronized (this) {
this.wait(2000);
}
} catch (InterruptedException e) {
}
assertEquals("pass", execPayload);
assertEquals(execStatus.intValue(), 200);
}
public void testWebViewWhiteListRejection() throws IOException
{
cordovaWebView.sendJavascript(
"var x = new XMLHttpRequest;\n" +
"x.open('GET', 'http://foo/bar', false);\n" +
"x.send();\n" +
"cordova.require('cordova/exec')(null,null,'UriResolverTestPlugin1', 'foo', [x.responseText, x.status])");
execPayload = null;
execStatus = null;
try {
synchronized (this) {
this.wait(2000);
}
} catch (InterruptedException e) {
}
assertEquals("", execPayload);
assertEquals(execStatus.intValue(), 404);
}
}

View File

@ -36,7 +36,7 @@ import android.content.Intent;
import android.os.Bundle;
public class CordovaWebViewTestActivity extends Activity implements CordovaInterface {
CordovaWebView cordovaWebView;
public CordovaWebView cordovaWebView;
private final ExecutorService threadPool = Executors.newCachedThreadPool();