From a001d8cfb71930bf21ccc0b85715385ef409d8e0 Mon Sep 17 00:00:00 2001 From: Shravan Narayan Date: Tue, 7 May 2013 11:02:38 -0400 Subject: [PATCH] DataRequest code cleaned up. --- .../org/apache/cordova/CameraLauncher.java | 12 +++--- .../src/org/apache/cordova/FileHelper.java | 20 ++++------ .../src/org/apache/cordova/FileUtils.java | 2 +- .../cordova/IceCreamCordovaWebViewClient.java | 9 ++--- .../org/apache/cordova/api/CordovaPlugin.java | 4 +- .../org/apache/cordova/api/DataResource.java | 37 ++++++++++--------- .../cordova/api/DataResourceContext.java | 9 +---- .../org/apache/cordova/api/PluginManager.java | 9 +++-- 8 files changed, 46 insertions(+), 56 deletions(-) diff --git a/framework/src/org/apache/cordova/CameraLauncher.java b/framework/src/org/apache/cordova/CameraLauncher.java index 7597a81b..1974dd71 100755 --- a/framework/src/org/apache/cordova/CameraLauncher.java +++ b/framework/src/org/apache/cordova/CameraLauncher.java @@ -342,7 +342,7 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect // Add compressed version of captured image to returned media store Uri DataResource dataResource = DataResource.initiateNewDataRequestForUri(uri, webView.pluginManager, cordova, "CameraLauncher.CameraExitIntent"); - OutputStream os = dataResource.getOs(); + OutputStream os = dataResource.getOutputStream(); bitmap.compress(Bitmap.CompressFormat.JPEG, this.mQuality, os); os.close(); @@ -540,9 +540,9 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect private void writeUncompressedImage(Uri uri) throws FileNotFoundException, IOException { DataResource inputDataResource = DataResource.initiateNewDataRequestForUri(imageUri, webView.pluginManager, cordova, "CameraLauncher.writeUncompressedImage"); - InputStream fis = inputDataResource.getIs(); + InputStream fis = inputDataResource.getInputStream(); DataResource outDataResource = DataResource.initiateNewDataRequestForUri(uri, webView.pluginManager, cordova, "CameraLauncher.writeUncompressedImage"); - OutputStream os = outDataResource.getOs(); + OutputStream os = outDataResource.getOutputStream(); if(fis == null) { throw new FileNotFoundException("Could not get the input file"); } else if(os == null) { @@ -592,13 +592,13 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect // If no new width or height were specified return the original bitmap DataResource dataResource = DataResource.initiateNewDataRequestForUri(imageUrl, webView.pluginManager, cordova, "CameraLauncher.getScaledBitmap"); if (this.targetWidth <= 0 && this.targetHeight <= 0) { - return BitmapFactory.decodeStream(dataResource.getIs()); + return BitmapFactory.decodeStream(dataResource.getInputStream()); } // figure out the original width and height of the image BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; - BitmapFactory.decodeStream(dataResource.getIs(), null, options); + BitmapFactory.decodeStream(dataResource.getInputStream(), null, options); //CB-2292: WTF? Why is the width null? if(options.outWidth == 0 || options.outHeight == 0) @@ -612,7 +612,7 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect // Load in the smallest bitmap possible that is closest to the size we want options.inJustDecodeBounds = false; options.inSampleSize = calculateSampleSize(options.outWidth, options.outHeight, this.targetWidth, this.targetHeight); - Bitmap unscaledBitmap = BitmapFactory.decodeStream(dataResource.getIs(), null, options); + Bitmap unscaledBitmap = BitmapFactory.decodeStream(dataResource.getInputStream(), null, options); if (unscaledBitmap == null) { return null; } diff --git a/framework/src/org/apache/cordova/FileHelper.java b/framework/src/org/apache/cordova/FileHelper.java index 81f32f0a..400352cc 100644 --- a/framework/src/org/apache/cordova/FileHelper.java +++ b/framework/src/org/apache/cordova/FileHelper.java @@ -122,33 +122,27 @@ public class FileHelper { */ public static boolean isUriWritable(String uriString) { String scheme = uriString.split(":")[0]; - String writableSchemes[] = new String[]{ "content" }; if(scheme.equals("file")){ // special case file - if(uriString.startsWith("file:///android_asset/")){ - return false; - } else { - return true; - } + return !uriString.startsWith("file:///android_asset/"); } - for(int i = writableSchemes.length - 1; i >= 0 ; i--){ - if(writableSchemes[i].equals(scheme)){ - return true; - } - } - return false; + return "content".equals(scheme); } /** * Ensures the "file://" prefix exists for the given string - * If the given URI string has a "file://" prefix, it is returned unchanged + * If the given URI string already has a scheme, it is returned unchanged * * @param path - the path string to operate on * @return a String with the "file://" scheme set */ public static String insertFileProtocol(String path) { if(!path.matches("^[a-z0-9+.-]+:.*")){ + //Ensure it is not a relative path + if(!path.startsWith("/")){ + throw new IllegalArgumentException("Relative paths" + path + "are not allowed."); + } path = "file://" + path; } return path; diff --git a/framework/src/org/apache/cordova/FileUtils.java b/framework/src/org/apache/cordova/FileUtils.java index cf0e5a49..e62fc4a1 100755 --- a/framework/src/org/apache/cordova/FileUtils.java +++ b/framework/src/org/apache/cordova/FileUtils.java @@ -897,7 +897,7 @@ public class FileUtils extends CordovaPlugin { public void run() { try { DataResource dataResource = DataResource.initiateNewDataRequestForUri(filename, webView.pluginManager, cordova, "FileUtils.readFileAs"); - byte[] bytes = readAsBinaryHelper(dataResource.getIs(), start, end); + byte[] bytes = readAsBinaryHelper(dataResource.getInputStream(), start, end); PluginResult result; switch (resultType) { diff --git a/framework/src/org/apache/cordova/IceCreamCordovaWebViewClient.java b/framework/src/org/apache/cordova/IceCreamCordovaWebViewClient.java index 3a17dc1d..d9c1cd21 100644 --- a/framework/src/org/apache/cordova/IceCreamCordovaWebViewClient.java +++ b/framework/src/org/apache/cordova/IceCreamCordovaWebViewClient.java @@ -46,19 +46,16 @@ public class IceCreamCordovaWebViewClient extends CordovaWebViewClient { public WebResourceResponse shouldInterceptRequest(WebView view, String url) { // We need to support the new DataResource intercepts without breaking the shouldInterceptRequest mechanism. DataResource dataResource = DataResource.initiateNewDataRequestForUri(url, this.appView.pluginManager, cordova, - new DataResourceContext("WebViewClient.shouldInterceptRequest", true /* this is from a browser request*/)); + "WebViewClient.shouldInterceptRequest"); url = dataResource.getUri().toString(); // This mechanism is no longer needed due to the dataResource mechanism. It would be awesome to just get rid of it. //Check if plugins intercept the request WebResourceResponse ret = super.shouldInterceptRequest(view, url); -// The below bugfix is taken care of by the dataResource mechanism -// if(ret == null && (url.contains("?") || url.contains("#") || needsIceCreamSpaceInAssetUrlFix(url))){ -// ret = generateWebResourceResponse(url); -// } + if(ret == null) { try { - ret = new WebResourceResponse(dataResource.getMimeType(), "UTF-8", dataResource.getIs()); + ret = new WebResourceResponse(dataResource.getMimeType(), "UTF-8", dataResource.getInputStream()); } catch(IOException e) { LOG.e("IceCreamCordovaWebViewClient", "Error occurred while loading a file.", e); } diff --git a/framework/src/org/apache/cordova/api/CordovaPlugin.java b/framework/src/org/apache/cordova/api/CordovaPlugin.java index 69f8fdeb..866677c3 100644 --- a/framework/src/org/apache/cordova/api/CordovaPlugin.java +++ b/framework/src/org/apache/cordova/api/CordovaPlugin.java @@ -182,10 +182,10 @@ public class CordovaPlugin { * * @param dataResource The resource to be loaded. * @param dataResourceContext Context associated with the resource load - * @return Return a new DataResource if the plugin wants o assist in loading the request or null if it doesn't. + * @return Return a new DataResource if the plugin wants to assist in loading the request or null if it doesn't. */ @TargetApi(Build.VERSION_CODES.HONEYCOMB) - public DataResource shouldInterceptDataResourceRequest(DataResource dataResource, DataResourceContext dataResourceContext) { + public DataResource handleDataResourceRequest(DataResource dataResource, DataResourceContext dataResourceContext) { return null; } diff --git a/framework/src/org/apache/cordova/api/DataResource.java b/framework/src/org/apache/cordova/api/DataResource.java index 8422b07d..3e6ead87 100644 --- a/framework/src/org/apache/cordova/api/DataResource.java +++ b/framework/src/org/apache/cordova/api/DataResource.java @@ -24,10 +24,13 @@ public class DataResource { private String mimeType; private Boolean writable; private File realFile; - private boolean retryLoad = true; + private boolean retryIsLoad = true; + private boolean retryOsLoad = true; + private boolean retryMimeTypeLoad = true; + private boolean retryWritableLoad = true; + private boolean retryRealFileLoad = true; public DataResource(CordovaInterface cordova, Uri uri) { - super(); this.cordova = cordova; this.uri = uri; } @@ -43,61 +46,61 @@ public class DataResource { // Uri is always provided return uri; } - public InputStream getIs() throws IOException { - if(is == null && retryLoad) { + public InputStream getInputStream() throws IOException { + if(is == null && retryIsLoad) { try { is = FileHelper.getInputStreamFromUriString(uri.toString(), cordova); } finally { // We failed loading once, don't try loading anymore if(is == null) { - retryLoad = false; + retryIsLoad = false; } } } return is; } - public OutputStream getOs() throws FileNotFoundException { - if(os == null && retryLoad) { + public OutputStream getOutputStream() throws FileNotFoundException { + if(os == null && retryOsLoad) { try { os = FileHelper.getOutputStreamFromUriString(uri.toString(), cordova); } finally { // We failed loading once, don't try loading anymore if(os == null) { - retryLoad = false; + retryOsLoad = false; } } } return os; } public String getMimeType() { - if(mimeType == null && retryLoad) { + if(mimeType == null && retryMimeTypeLoad) { try { mimeType = FileHelper.getMimeType(uri.toString(), cordova); } finally { // We failed loading once, don't try loading anymore if(mimeType == null) { - retryLoad = false; + retryMimeTypeLoad = false; } } } return mimeType; } public boolean isWritable() { - if(writable == null && retryLoad) { + if(writable == null && retryWritableLoad) { try { writable = FileHelper.isUriWritable(uri.toString()); } finally { // We failed loading once, don't try loading anymore if(writable == null) { - retryLoad = false; + retryWritableLoad = false; } } } // default to false - return writable != null? writable.booleanValue() : false; + return writable != null && writable.booleanValue(); } public File getRealFile() { - if(realFile == null && retryLoad) { + if(realFile == null && retryRealFileLoad) { try { String realPath = FileHelper.getRealPath(uri, cordova); if(realPath != null) { @@ -106,7 +109,7 @@ public class DataResource { } finally { // We failed loading once, don't try loading anymore if(realFile == null) { - retryLoad = false; + retryRealFileLoad = false; } } } @@ -120,7 +123,7 @@ public class DataResource { return initiateNewDataRequestForUri(Uri.parse(uriString), pluginManager, cordova, requestSourceTag); } public static DataResource initiateNewDataRequestForUri(Uri uri, PluginManager pluginManager, CordovaInterface cordova, String requestSourceTag){ - return initiateNewDataRequestForUri(uri, pluginManager, cordova, new DataResourceContext(requestSourceTag, false /* Assume, not a browser request by default */ )); + return initiateNewDataRequestForUri(uri, pluginManager, cordova, new DataResourceContext(requestSourceTag)); } public static DataResource initiateNewDataRequestForUri(String uriString, PluginManager pluginManager, CordovaInterface cordova, DataResourceContext dataResourceContext){ // if no protocol is specified, assume its file: @@ -131,7 +134,7 @@ public class DataResource { DataResource dataResource = new DataResource(cordova, uri); if (pluginManager != null) { // get the resource as returned by plugins - dataResource = pluginManager.shouldInterceptDataResourceRequest(dataResource, dataResourceContext); + dataResource = pluginManager.handleDataResourceRequestWithPlugins(dataResource, dataResourceContext); } return dataResource; } diff --git a/framework/src/org/apache/cordova/api/DataResourceContext.java b/framework/src/org/apache/cordova/api/DataResourceContext.java index 3c668171..310586b2 100644 --- a/framework/src/org/apache/cordova/api/DataResourceContext.java +++ b/framework/src/org/apache/cordova/api/DataResourceContext.java @@ -12,15 +12,11 @@ public class DataResourceContext { // A tag associated with the source of this dataResourceContext private String source; // If needed, any data associated with core plugins can be a part of the context object - // This field indicates whether the request came from a browser network request - private boolean isFromBrowser; // If needed, any data associated with non core plugins should store data in a Map so as to not clutter the context object private Map dataMap; - public DataResourceContext(String source, boolean isFromBrowser) { - super(); + public DataResourceContext(String source) { this.requestId = new Random().nextInt(); this.source = source; - this.isFromBrowser = isFromBrowser; this.dataMap = new HashMap(); } public int getRequestId() { @@ -29,9 +25,6 @@ public class DataResourceContext { public String getSource() { return source; } - public boolean isFromBrowser() { - return isFromBrowser; - } public Map getDataMap() { return dataMap; } diff --git a/framework/src/org/apache/cordova/api/PluginManager.java b/framework/src/org/apache/cordova/api/PluginManager.java index 6bad5ed3..9eb1308e 100755 --- a/framework/src/org/apache/cordova/api/PluginManager.java +++ b/framework/src/org/apache/cordova/api/PluginManager.java @@ -54,6 +54,7 @@ public class PluginManager { // Map URL schemes like foo: to plugins that want to handle those schemes // This would allow how all URLs are handled to be offloaded to a plugin protected HashMap urlMap = new HashMap(); + private int MAX_REPITIONS = 1000; /** * Constructor. @@ -409,13 +410,15 @@ public class PluginManager { * @param dataResourceContext The context of the dataResource request * @return Return the resource request that will be loaded. The returned request may be modified or unchanged. */ - public DataResource shouldInterceptDataResourceRequest(DataResource dataResource, DataResourceContext dataResourceContext){ + public DataResource handleDataResourceRequestWithPlugins(DataResource dataResource, DataResourceContext dataResourceContext){ + int repetitions = 0; boolean requestModified = true; - while(requestModified) { + while(requestModified && repetitions < MAX_REPITIONS) { requestModified = false; + repetitions ++; for (PluginEntry entry : this.entries.values()) { if (entry.plugin != null) { - DataResource ret = entry.plugin.shouldInterceptDataResourceRequest(dataResource, dataResourceContext); + DataResource ret = entry.plugin.handleDataResourceRequest(dataResource, dataResourceContext); if(ret != null) { dataResource = ret; requestModified = true;