fix!: remove deprecated platforms (#270)
diff --git a/README.md b/README.md
index ae19ffe..55bd104 100644
--- a/README.md
+++ b/README.md
@@ -58,19 +58,11 @@
## Supported Platforms
-- Amazon Fire OS
- Android
-- BlackBerry 10
- Browser
-- Firefox OS**
- iOS
-- Windows Phone 7 and 8*
- Windows
-\* _Do not support `onprogress` nor `abort()`_
-
-\** _Do not support `onprogress`_
-
# FileTransfer
The `FileTransfer` object provides a way to upload files using an HTTP
@@ -259,10 +251,6 @@
);
```
-### WP8 Quirks
-
-- Download requests is being cached by native implementation. To avoid caching, pass `if-Modified-Since` header to download method.
-
### Browser Quirks
- __withCredentials__: _boolean_ that tells the browser to set the withCredentials flag on the XMLHttpRequest
diff --git a/package.json b/package.json
index a9788f9..993feca 100644
--- a/package.json
+++ b/package.json
@@ -7,15 +7,8 @@
"id": "cordova-plugin-file-transfer",
"platforms": [
"android",
- "amazon-fireos",
- "ubuntu",
- "blackberry10",
"ios",
- "wp7",
- "wp8",
- "windows8",
"windows",
- "firefoxos",
"browser"
]
},
@@ -37,15 +30,8 @@
"transfer",
"ecosystem:cordova",
"cordova-android",
- "cordova-amazon-fireos",
- "cordova-ubuntu",
- "cordova-blackberry10",
"cordova-ios",
- "cordova-wp7",
- "cordova-wp8",
- "cordova-windows8",
"cordova-windows",
- "cordova-firefoxos",
"cordova-browser"
],
"author": "Apache Software Foundation",
diff --git a/plugin.xml b/plugin.xml
index 41c7a91..1a1fd19 100644
--- a/plugin.xml
+++ b/plugin.xml
@@ -56,45 +56,6 @@
<source-file src="src/android/FileUploadResult.java" target-dir="src/org/apache/cordova/filetransfer" />
</platform>
- <!-- amamzon-fireos -->
- <platform name="amazon-fireos">
- <config-file target="res/xml/config.xml" parent="/*">
- <feature name="FileTransfer" >
- <param name="android-package" value="org.apache.cordova.filetransfer.FileTransfer"/>
- </feature>
- </config-file>
-
- <config-file target="AndroidManifest.xml" parent="/*">
- <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
- </config-file>
-
- <source-file src="src/amazon/FileTransfer.java" target-dir="src/org/apache/cordova/filetransfer" />
- <source-file src="src/android/FileProgressResult.java" target-dir="src/org/apache/cordova/filetransfer" />
- <source-file src="src/android/FileUploadResult.java" target-dir="src/org/apache/cordova/filetransfer" />
- </platform>
-
- <!-- ubuntu -->
- <platform name="ubuntu">
- <header-file src="src/ubuntu/file-transfer.h" />
- <source-file src="src/ubuntu/file-transfer.cpp" />
- </platform>
-
- <!-- blackberry10 -->
- <platform name="blackberry10">
- <config-file target="www/config.xml" parent="/widget">
- <feature name="FileTransfer" value="FileTransfer"></feature>
- </config-file>
- <js-module src="www/blackberry10/FileTransferProxy.js" name="FileTransferProxy" >
- <runs />
- </js-module>
- <js-module src="www/blackberry10/xhrFileTransfer.js" name="xhrFileTransfer" />
- <!--
- <js-module src="www/blackberry10/abort.js" name="abortProxy" />
- <js-module src="www/blackberry10/download.js" name="downloadProxy" />
- <js-module src="www/blackberry10/upload.js" name="uploadProxy" />
- -->
- </platform>
-
<!-- ios -->
<platform name="ios">
<config-file target="config.xml" parent="/*">
@@ -108,41 +69,6 @@
<framework src="AssetsLibrary.framework" />
</platform>
- <!-- wp7 -->
- <platform name="wp7">
- <config-file target="config.xml" parent="/*">
- <feature name="FileTransfer">
- <param name="wp-package" value="FileTransfer"/>
- </feature>
- </config-file>
-
- <source-file src="src/wp/FileTransfer.cs" />
-
- <js-module src="www/wp7/base64.js" name="base64">
- <clobbers target="window.FileTransferBase64" />
- </js-module>
-
- </platform>
-
- <!-- wp8 -->
- <platform name="wp8">
- <config-file target="config.xml" parent="/*">
- <feature name="FileTransfer">
- <param name="wp-package" value="FileTransfer"/>
- </feature>
- </config-file>
-
- <source-file src="src/wp/FileTransfer.cs" />
-
- </platform>
-
- <!-- windows8 -->
- <platform name="windows8">
- <js-module src="src/windows/FileTransferProxy.js" name="FileTransferProxy">
- <runs />
- </js-module>
- </platform>
-
<!-- windows -->
<platform name="windows">
<js-module src="src/windows/FileTransferProxy.js" name="FileTransferProxy">
@@ -150,17 +76,6 @@
</js-module>
</platform>
- <!-- firefoxOS -->
- <platform name="firefoxos">
- <config-file target="config.xml" parent="/*">
- <permission name="systemXHR" privileged="true"/>
- </config-file>
-
- <js-module src="www/firefoxos/FileTransferProxy.js" name="FileTransferProxy">
- <runs/>
- </js-module>
- </platform>
-
<!-- browser -->
<platform name="browser">
<js-module src="www/browser/FileTransfer.js" name="BrowserFileTransfer">
diff --git a/src/amazon/FileTransfer.java b/src/amazon/FileTransfer.java
deleted file mode 100644
index 1563a39..0000000
--- a/src/amazon/FileTransfer.java
+++ /dev/null
@@ -1,898 +0,0 @@
-/*
- 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.filetransfer;
-
-import java.io.BufferedReader;
-import java.io.ByteArrayOutputStream;
-import java.io.Closeable;
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.FilterInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.OutputStream;
-import java.io.UnsupportedEncodingException;
-import java.net.HttpURLConnection;
-import java.net.URLConnection;
-import java.net.URLDecoder;
-import java.security.cert.CertificateException;
-import java.security.cert.X509Certificate;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.zip.GZIPInputStream;
-import java.util.zip.Inflater;
-
-import javax.net.ssl.HostnameVerifier;
-import javax.net.ssl.HttpsURLConnection;
-import javax.net.ssl.SSLContext;
-import javax.net.ssl.SSLSession;
-import javax.net.ssl.SSLSocketFactory;
-import javax.net.ssl.TrustManager;
-import javax.net.ssl.X509TrustManager;
-
-import org.apache.cordova.Config;
-import org.apache.cordova.CallbackContext;
-import org.apache.cordova.CordovaPlugin;
-import org.apache.cordova.CordovaResourceApi;
-import org.apache.cordova.CordovaResourceApi.OpenForReadResult;
-import org.apache.cordova.PluginResult;
-import org.apache.cordova.file.FileUtils;
-import org.json.JSONArray;
-import org.json.JSONException;
-import org.json.JSONObject;
-
-import android.net.Uri;
-import android.os.Build;
-import android.util.Log;
-import com.amazon.android.webkit.AmazonCookieManager;
-
-public class FileTransfer extends CordovaPlugin {
-
- private static final String LOG_TAG = "FileTransfer";
- private static final String LINE_START = "--";
- private static final String LINE_END = "\r\n";
- private static final String BOUNDARY = "+++++";
-
- public static int FILE_NOT_FOUND_ERR = 1;
- public static int INVALID_URL_ERR = 2;
- public static int CONNECTION_ERR = 3;
- public static int ABORTED_ERR = 4;
-
- private static HashMap<String, RequestContext> activeRequests = new HashMap<String, RequestContext>();
- private static final int MAX_BUFFER_SIZE = 16 * 1024;
-
- private static final class RequestContext {
- String source;
- String target;
- File targetFile;
- CallbackContext callbackContext;
- InputStream currentInputStream;
- OutputStream currentOutputStream;
- boolean aborted;
- RequestContext(String source, String target, CallbackContext callbackContext) {
- this.source = source;
- this.target = target;
- this.callbackContext = callbackContext;
- }
- void sendPluginResult(PluginResult pluginResult) {
- synchronized (this) {
- if (!aborted) {
- callbackContext.sendPluginResult(pluginResult);
- }
- }
- }
- }
-
- /**
- * Adds an interface method to an InputStream to return the number of bytes
- * read from the raw stream. This is used to track total progress against
- * the HTTP Content-Length header value from the server.
- */
- private static abstract class TrackingInputStream extends FilterInputStream {
- public TrackingInputStream(final InputStream in) {
- super(in);
- }
- public abstract long getTotalRawBytesRead();
- }
-
- private static class ExposedGZIPInputStream extends GZIPInputStream {
- public ExposedGZIPInputStream(final InputStream in) throws IOException {
- super(in);
- }
- public Inflater getInflater() {
- return inf;
- }
- }
-
- /**
- * Provides raw bytes-read tracking for a GZIP input stream. Reports the
- * total number of compressed bytes read from the input, rather than the
- * number of uncompressed bytes.
- */
- private static class TrackingGZIPInputStream extends TrackingInputStream {
- private ExposedGZIPInputStream gzin;
- public TrackingGZIPInputStream(final ExposedGZIPInputStream gzin) throws IOException {
- super(gzin);
- this.gzin = gzin;
- }
- public long getTotalRawBytesRead() {
- return gzin.getInflater().getBytesRead();
- }
- }
-
- /**
- * Provides simple total-bytes-read tracking for an existing InputStream
- */
- private static class SimpleTrackingInputStream extends TrackingInputStream {
- private long bytesRead = 0;
- public SimpleTrackingInputStream(InputStream stream) {
- super(stream);
- }
-
- private int updateBytesRead(int newBytesRead) {
- if (newBytesRead != -1) {
- bytesRead += newBytesRead;
- }
- return newBytesRead;
- }
-
- @Override
- public int read() throws IOException {
- return updateBytesRead(super.read());
- }
-
- // Note: FilterInputStream delegates read(byte[] bytes) to the below method,
- // so we don't override it or else double count (CB-5631).
- @Override
- public int read(byte[] bytes, int offset, int count) throws IOException {
- return updateBytesRead(super.read(bytes, offset, count));
- }
-
- public long getTotalRawBytesRead() {
- return bytesRead;
- }
- }
-
- @Override
- public boolean execute(String action, JSONArray args, final CallbackContext callbackContext) throws JSONException {
- if (action.equals("upload") || action.equals("download")) {
- String source = args.getString(0);
- String target = args.getString(1);
-
- if (action.equals("upload")) {
- try {
- source = URLDecoder.decode(source, "UTF-8");
- upload(source, target, args, callbackContext);
- } catch (UnsupportedEncodingException e) {
- callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.MALFORMED_URL_EXCEPTION, "UTF-8 error."));
- }
- } else {
- download(source, target, args, callbackContext);
- }
- return true;
- } else if (action.equals("abort")) {
- String objectId = args.getString(0);
- abort(objectId);
- callbackContext.success();
- return true;
- }
- return false;
- }
-
- private static void addHeadersToRequest(URLConnection connection, JSONObject headers) {
- try {
- for (Iterator<?> iter = headers.keys(); iter.hasNext(); ) {
- String headerKey = iter.next().toString();
- JSONArray headerValues = headers.optJSONArray(headerKey);
- if (headerValues == null) {
- headerValues = new JSONArray();
- headerValues.put(headers.getString(headerKey));
- }
- connection.setRequestProperty(headerKey, headerValues.getString(0));
- for (int i = 1; i < headerValues.length(); ++i) {
- connection.addRequestProperty(headerKey, headerValues.getString(i));
- }
- }
- } catch (JSONException e1) {
- // No headers to be manipulated!
- }
- }
-
- /**
- * Uploads the specified file to the server URL provided using an HTTP multipart request.
- * @param source Full path of the file on the file system
- * @param target URL of the server to receive the file
- * @param args JSON Array of args
- * @param callbackContext callback id for optional progress reports
- *
- * args[2] fileKey Name of file request parameter
- * args[3] fileName File name to be used on server
- * args[4] mimeType Describes file content type
- * args[5] params key:value pairs of user-defined parameters
- * @return FileUploadResult containing result of upload request
- */
- private void upload(final String source, final String target, JSONArray args, CallbackContext callbackContext) throws JSONException {
- Log.d(LOG_TAG, "upload " + source + " to " + target);
-
- // Setup the options
- final String fileKey = getArgument(args, 2, "file");
- final String fileName = getArgument(args, 3, "image.jpg");
- final String mimeType = getArgument(args, 4, "image/jpeg");
- final JSONObject params = args.optJSONObject(5) == null ? new JSONObject() : args.optJSONObject(5);
- final boolean trustEveryone = args.optBoolean(6);
- // Always use chunked mode unless set to false as per API
- final boolean chunkedMode = args.optBoolean(7) || args.isNull(7);
- // Look for headers on the params map for backwards compatibility with older Cordova versions.
- final JSONObject headers = args.optJSONObject(8) == null ? params.optJSONObject("headers") : args.optJSONObject(8);
- final String objectId = args.getString(9);
- final String httpMethod = getArgument(args, 10, "POST");
-
- final CordovaResourceApi resourceApi = webView.getResourceApi();
-
- Log.d(LOG_TAG, "fileKey: " + fileKey);
- Log.d(LOG_TAG, "fileName: " + fileName);
- Log.d(LOG_TAG, "mimeType: " + mimeType);
- Log.d(LOG_TAG, "params: " + params);
- Log.d(LOG_TAG, "trustEveryone: " + trustEveryone);
- Log.d(LOG_TAG, "chunkedMode: " + chunkedMode);
- Log.d(LOG_TAG, "headers: " + headers);
- Log.d(LOG_TAG, "objectId: " + objectId);
- Log.d(LOG_TAG, "httpMethod: " + httpMethod);
-
- final Uri targetUri = resourceApi.remapUri(Uri.parse(target));
- // Accept a path or a URI for the source.
- Uri tmpSrc = Uri.parse(source);
- final Uri sourceUri = resourceApi.remapUri(
- tmpSrc.getScheme() != null ? tmpSrc : Uri.fromFile(new File(source)));
-
- int uriType = CordovaResourceApi.getUriType(targetUri);
- final boolean useHttps = uriType == CordovaResourceApi.URI_TYPE_HTTPS;
- if (uriType != CordovaResourceApi.URI_TYPE_HTTP && !useHttps) {
- JSONObject error = createFileTransferError(INVALID_URL_ERR, source, target, null, 0);
- Log.e(LOG_TAG, "Unsupported URI: " + targetUri);
- callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.IO_EXCEPTION, error));
- return;
- }
-
- final RequestContext context = new RequestContext(source, target, callbackContext);
- synchronized (activeRequests) {
- activeRequests.put(objectId, context);
- }
-
- cordova.getThreadPool().execute(new Runnable() {
- public void run() {
- if (context.aborted) {
- return;
- }
- HttpURLConnection conn = null;
- HostnameVerifier oldHostnameVerifier = null;
- SSLSocketFactory oldSocketFactory = null;
- int totalBytes = 0;
- int fixedLength = -1;
- try {
- // Create return object
- FileUploadResult result = new FileUploadResult();
- FileProgressResult progress = new FileProgressResult();
-
- //------------------ CLIENT REQUEST
- // Open a HTTP connection to the URL based on protocol
- conn = resourceApi.createHttpConnection(targetUri);
- if (useHttps && trustEveryone) {
- // Setup the HTTPS connection class to trust everyone
- HttpsURLConnection https = (HttpsURLConnection)conn;
- oldSocketFactory = trustAllHosts(https);
- // Save the current hostnameVerifier
- oldHostnameVerifier = https.getHostnameVerifier();
- // Setup the connection not to verify hostnames
- https.setHostnameVerifier(DO_NOT_VERIFY);
- }
-
- // Allow Inputs
- conn.setDoInput(true);
-
- // Allow Outputs
- conn.setDoOutput(true);
-
- // Don't use a cached copy.
- conn.setUseCaches(false);
-
- // Use a post method.
- conn.setRequestMethod(httpMethod);
-
- // if we specified a Content-Type header, don't do multipart form upload
- boolean multipartFormUpload = (headers == null) || !headers.has("Content-Type");
- if (multipartFormUpload) {
- conn.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + BOUNDARY);
- }
- // Set the cookies on the response
- String cookie = AmazonCookieManager.getInstance().getCookie(target);
- if (cookie != null) {
- conn.setRequestProperty("Cookie", cookie);
- }
-
- // Handle the other headers
- if (headers != null) {
- addHeadersToRequest(conn, headers);
- }
-
- /*
- * Store the non-file portions of the multipart data as a string, so that we can add it
- * to the contentSize, since it is part of the body of the HTTP request.
- */
- StringBuilder beforeData = new StringBuilder();
- try {
- for (Iterator<?> iter = params.keys(); iter.hasNext();) {
- Object key = iter.next();
- if(!String.valueOf(key).equals("headers"))
- {
- beforeData.append(LINE_START).append(BOUNDARY).append(LINE_END);
- beforeData.append("Content-Disposition: form-data; name=\"").append(key.toString()).append('"');
- beforeData.append(LINE_END).append(LINE_END);
- beforeData.append(params.getString(key.toString()));
- beforeData.append(LINE_END);
- }
- }
- } catch (JSONException e) {
- Log.e(LOG_TAG, e.getMessage(), e);
- }
-
- beforeData.append(LINE_START).append(BOUNDARY).append(LINE_END);
- beforeData.append("Content-Disposition: form-data; name=\"").append(fileKey).append("\";");
- beforeData.append(" filename=\"").append(fileName).append('"').append(LINE_END);
- beforeData.append("Content-Type: ").append(mimeType).append(LINE_END).append(LINE_END);
- byte[] beforeDataBytes = beforeData.toString().getBytes("UTF-8");
- byte[] tailParamsBytes = (LINE_END + LINE_START + BOUNDARY + LINE_START + LINE_END).getBytes("UTF-8");
-
-
- // Get a input stream of the file on the phone
- OpenForReadResult readResult = resourceApi.openForRead(sourceUri);
-
- int stringLength = beforeDataBytes.length + tailParamsBytes.length;
- if (readResult.length >= 0) {
- fixedLength = (int)readResult.length;
- if (multipartFormUpload)
- fixedLength += stringLength;
- progress.setLengthComputable(true);
- progress.setTotal(fixedLength);
- }
- Log.d(LOG_TAG, "Content Length: " + fixedLength);
- // setFixedLengthStreamingMode causes and OutOfMemoryException on pre-Froyo devices.
- // http://code.google.com/p/android/issues/detail?id=3164
- // It also causes OOM if HTTPS is used, even on newer devices.
- boolean useChunkedMode = chunkedMode && (Build.VERSION.SDK_INT < Build.VERSION_CODES.FROYO || useHttps);
- useChunkedMode = useChunkedMode || (fixedLength == -1);
-
- if (useChunkedMode) {
- conn.setChunkedStreamingMode(MAX_BUFFER_SIZE);
- // Although setChunkedStreamingMode sets this header, setting it explicitly here works
- // around an OutOfMemoryException when using https.
- conn.setRequestProperty("Transfer-Encoding", "chunked");
- } else {
- conn.setFixedLengthStreamingMode(fixedLength);
- }
-
- conn.connect();
-
- OutputStream sendStream = null;
- try {
- sendStream = conn.getOutputStream();
- synchronized (context) {
- if (context.aborted) {
- return;
- }
- context.currentOutputStream = sendStream;
- }
-
- if (multipartFormUpload) {
- //We don't want to change encoding, we just want this to write for all Unicode.
- sendStream.write(beforeDataBytes);
- totalBytes += beforeDataBytes.length;
- }
- // create a buffer of maximum size
- int bytesAvailable = readResult.inputStream.available();
- int bufferSize = Math.min(bytesAvailable, MAX_BUFFER_SIZE);
- byte[] buffer = new byte[bufferSize];
-
- // read file and write it into form...
- int bytesRead = readResult.inputStream.read(buffer, 0, bufferSize);
-
- long prevBytesRead = 0;
- while (bytesRead > 0) {
- result.setBytesSent(totalBytes);
- sendStream.write(buffer, 0, bytesRead);
- totalBytes += bytesRead;
- if (totalBytes > prevBytesRead + 102400) {
- prevBytesRead = totalBytes;
- Log.d(LOG_TAG, "Uploaded " + totalBytes + " of " + fixedLength + " bytes");
- }
- bytesAvailable = readResult.inputStream.available();
- bufferSize = Math.min(bytesAvailable, MAX_BUFFER_SIZE);
- bytesRead = readResult.inputStream.read(buffer, 0, bufferSize);
-
- // Send a progress event.
- progress.setLoaded(totalBytes);
- PluginResult progressResult = new PluginResult(PluginResult.Status.OK, progress.toJSONObject());
- progressResult.setKeepCallback(true);
- context.sendPluginResult(progressResult);
- }
-
- if (multipartFormUpload) {
- // send multipart form data necessary after file data...
- sendStream.write(tailParamsBytes);
- totalBytes += tailParamsBytes.length;
- }
- sendStream.flush();
- } finally {
- safeClose(readResult.inputStream);
- safeClose(sendStream);
- }
- context.currentOutputStream = null;
- Log.d(LOG_TAG, "Sent " + totalBytes + " of " + fixedLength);
-
- //------------------ read the SERVER RESPONSE
- String responseString;
- int responseCode = conn.getResponseCode();
- Log.d(LOG_TAG, "response code: " + responseCode);
- Log.d(LOG_TAG, "response headers: " + conn.getHeaderFields());
- TrackingInputStream inStream = null;
- try {
- inStream = getInputStream(conn);
- synchronized (context) {
- if (context.aborted) {
- return;
- }
- context.currentInputStream = inStream;
- }
-
- ByteArrayOutputStream out = new ByteArrayOutputStream(Math.max(1024, conn.getContentLength()));
- byte[] buffer = new byte[1024];
- int bytesRead = 0;
- // write bytes to file
- while ((bytesRead = inStream.read(buffer)) > 0) {
- out.write(buffer, 0, bytesRead);
- }
- responseString = out.toString("UTF-8");
- } finally {
- context.currentInputStream = null;
- safeClose(inStream);
- }
-
- Log.d(LOG_TAG, "got response from server");
- Log.d(LOG_TAG, responseString.substring(0, Math.min(256, responseString.length())));
-
- // send request and retrieve response
- result.setResponseCode(responseCode);
- result.setResponse(responseString);
-
- context.sendPluginResult(new PluginResult(PluginResult.Status.OK, result.toJSONObject()));
- } catch (FileNotFoundException e) {
- JSONObject error = createFileTransferError(FILE_NOT_FOUND_ERR, source, target, conn);
- Log.e(LOG_TAG, error.toString(), e);
- context.sendPluginResult(new PluginResult(PluginResult.Status.IO_EXCEPTION, error));
- } catch (IOException e) {
- JSONObject error = createFileTransferError(CONNECTION_ERR, source, target, conn);
- Log.e(LOG_TAG, error.toString(), e);
- Log.e(LOG_TAG, "Failed after uploading " + totalBytes + " of " + fixedLength + " bytes.");
- context.sendPluginResult(new PluginResult(PluginResult.Status.IO_EXCEPTION, error));
- } catch (JSONException e) {
- Log.e(LOG_TAG, e.getMessage(), e);
- context.sendPluginResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION));
- } catch (Throwable t) {
- // Shouldn't happen, but will
- JSONObject error = createFileTransferError(CONNECTION_ERR, source, target, conn);
- Log.e(LOG_TAG, error.toString(), t);
- context.sendPluginResult(new PluginResult(PluginResult.Status.IO_EXCEPTION, error));
- } finally {
- synchronized (activeRequests) {
- activeRequests.remove(objectId);
- }
-
- if (conn != null) {
- // Revert back to the proper verifier and socket factories
- // Revert back to the proper verifier and socket factories
- if (trustEveryone && useHttps) {
- HttpsURLConnection https = (HttpsURLConnection) conn;
- https.setHostnameVerifier(oldHostnameVerifier);
- https.setSSLSocketFactory(oldSocketFactory);
- }
- }
- }
- }
- });
- }
-
- private static void safeClose(Closeable stream) {
- if (stream != null) {
- try {
- stream.close();
- } catch (IOException e) {
- }
- }
- }
-
- private static TrackingInputStream getInputStream(URLConnection conn) throws IOException {
- String encoding = conn.getContentEncoding();
- if (encoding != null && encoding.equalsIgnoreCase("gzip")) {
- return new TrackingGZIPInputStream(new ExposedGZIPInputStream(conn.getInputStream()));
- }
- return new SimpleTrackingInputStream(conn.getInputStream());
- }
-
- // always verify the host - don't check for certificate
- private static final HostnameVerifier DO_NOT_VERIFY = new HostnameVerifier() {
- public boolean verify(String hostname, SSLSession session) {
- return true;
- }
- };
- // Create a trust manager that does not validate certificate chains
- private static final TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() {
- public java.security.cert.X509Certificate[] getAcceptedIssuers() {
- return new java.security.cert.X509Certificate[] {};
- }
-
- public void checkClientTrusted(X509Certificate[] chain,
- String authType) throws CertificateException {
- }
-
- public void checkServerTrusted(X509Certificate[] chain,
- String authType) throws CertificateException {
- }
- } };
-
- /**
- * This function will install a trust manager that will blindly trust all SSL
- * certificates. The reason this code is being added is to enable developers
- * to do development using self signed SSL certificates on their web server.
- *
- * The standard HttpsURLConnection class will throw an exception on self
- * signed certificates if this code is not run.
- */
- private static SSLSocketFactory trustAllHosts(HttpsURLConnection connection) {
- // Install the all-trusting trust manager
- SSLSocketFactory oldFactory = connection.getSSLSocketFactory();
- try {
- // Install our all trusting manager
- SSLContext sc = SSLContext.getInstance("TLS");
- sc.init(null, trustAllCerts, new java.security.SecureRandom());
- SSLSocketFactory newFactory = sc.getSocketFactory();
- connection.setSSLSocketFactory(newFactory);
- } catch (Exception e) {
- Log.e(LOG_TAG, e.getMessage(), e);
- }
- return oldFactory;
- }
-
- private static JSONObject createFileTransferError(int errorCode, String source, String target, URLConnection connection) {
-
- int httpStatus = 0;
- StringBuilder bodyBuilder = new StringBuilder();
- String body = null;
- if (connection != null) {
- try {
- if (connection instanceof HttpURLConnection) {
- httpStatus = ((HttpURLConnection)connection).getResponseCode();
- InputStream err = ((HttpURLConnection) connection).getErrorStream();
- if(err != null)
- {
- BufferedReader reader = new BufferedReader(new InputStreamReader(err, "UTF-8"));
- try {
- String line = reader.readLine();
- while(line != null) {
- bodyBuilder.append(line);
- line = reader.readLine();
- if(line != null) {
- bodyBuilder.append('\n');
- }
- }
- body = bodyBuilder.toString();
- } finally {
- reader.close();
- }
- }
- }
- // IOException can leave connection object in a bad state, so catch all exceptions.
- } catch (Throwable e) {
- Log.w(LOG_TAG, "Error getting HTTP status code from connection.", e);
- }
- }
-
- return createFileTransferError(errorCode, source, target, body, httpStatus);
- }
-
- /**
- * Create an error object based on the passed in errorCode
- * @param errorCode the error
- * @return JSONObject containing the error
- */
- private static JSONObject createFileTransferError(int errorCode, String source, String target, String body, Integer httpStatus) {
- JSONObject error = null;
- try {
- error = new JSONObject();
- error.put("code", errorCode);
- error.put("source", source);
- error.put("target", target);
- if(body != null)
- {
- error.put("body", body);
- }
- if (httpStatus != null) {
- error.put("http_status", httpStatus);
- }
- } catch (JSONException e) {
- Log.e(LOG_TAG, e.getMessage(), e);
- }
- return error;
- }
-
- /**
- * Convenience method to read a parameter from the list of JSON args.
- * @param args the args passed to the Plugin
- * @param position the position to retrieve the arg from
- * @param defaultString the default to be used if the arg does not exist
- * @return String with the retrieved value
- */
- private static String getArgument(JSONArray args, int position, String defaultString) {
- String arg = defaultString;
- if (args.length() > position) {
- arg = args.optString(position);
- if (arg == null || "null".equals(arg)) {
- arg = defaultString;
- }
- }
- return arg;
- }
-
- /**
- * Downloads a file form a given URL and saves it to the specified directory.
- *
- * @param source URL of the server to receive the file
- * @param target Full path of the file on the file system
- */
- private void download(final String source, final String target, JSONArray args, CallbackContext callbackContext) throws JSONException {
- Log.d(LOG_TAG, "download " + source + " to " + target);
-
- final CordovaResourceApi resourceApi = webView.getResourceApi();
-
- final boolean trustEveryone = args.optBoolean(2);
- final String objectId = args.getString(3);
- final JSONObject headers = args.optJSONObject(4);
-
- final Uri sourceUri = resourceApi.remapUri(Uri.parse(source));
- // Accept a path or a URI for the source.
- Uri tmpTarget = Uri.parse(target);
- final Uri targetUri = resourceApi.remapUri(
- tmpTarget.getScheme() != null ? tmpTarget : Uri.fromFile(new File(target)));
-
- int uriType = CordovaResourceApi.getUriType(sourceUri);
- final boolean useHttps = uriType == CordovaResourceApi.URI_TYPE_HTTPS;
- final boolean isLocalTransfer = !useHttps && uriType != CordovaResourceApi.URI_TYPE_HTTP;
- if (uriType == CordovaResourceApi.URI_TYPE_UNKNOWN) {
- JSONObject error = createFileTransferError(INVALID_URL_ERR, source, target, null, 0);
- Log.e(LOG_TAG, "Unsupported URI: " + targetUri);
- callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.IO_EXCEPTION, error));
- return;
- }
-
- // TODO: refactor to also allow resources & content:
- if (!isLocalTransfer && !Config.isUrlWhiteListed(source)) {
- Log.w(LOG_TAG, "Source URL is not in white list: '" + source + "'");
- JSONObject error = createFileTransferError(CONNECTION_ERR, source, target, null, 401);
- callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.IO_EXCEPTION, error));
- return;
- }
-
-
- final RequestContext context = new RequestContext(source, target, callbackContext);
- synchronized (activeRequests) {
- activeRequests.put(objectId, context);
- }
-
- cordova.getThreadPool().execute(new Runnable() {
- public void run() {
- if (context.aborted) {
- return;
- }
- HttpURLConnection connection = null;
- HostnameVerifier oldHostnameVerifier = null;
- SSLSocketFactory oldSocketFactory = null;
- File file = null;
- PluginResult result = null;
- TrackingInputStream inputStream = null;
-
- OutputStream outputStream = null;
- try {
- OpenForReadResult readResult = null;
- outputStream = resourceApi.openOutputStream(targetUri);
-
- file = resourceApi.mapUriToFile(targetUri);
- context.targetFile = file;
-
- Log.d(LOG_TAG, "Download file:" + sourceUri);
-
- FileProgressResult progress = new FileProgressResult();
-
- if (isLocalTransfer) {
- readResult = resourceApi.openForRead(sourceUri);
- if (readResult.length != -1) {
- progress.setLengthComputable(true);
- progress.setTotal(readResult.length);
- }
- inputStream = new SimpleTrackingInputStream(readResult.inputStream);
- } else {
- // connect to server
- // Open a HTTP connection to the URL based on protocol
- connection = resourceApi.createHttpConnection(sourceUri);
- if (useHttps && trustEveryone) {
- // Setup the HTTPS connection class to trust everyone
- HttpsURLConnection https = (HttpsURLConnection)connection;
- oldSocketFactory = trustAllHosts(https);
- // Save the current hostnameVerifier
- oldHostnameVerifier = https.getHostnameVerifier();
- // Setup the connection not to verify hostnames
- https.setHostnameVerifier(DO_NOT_VERIFY);
- }
-
- connection.setRequestMethod("GET");
-
- // TODO: Make OkHttp use this AmazonCookieManager by default.
- String cookie = AmazonCookieManager.getInstance().getCookie(sourceUri.toString());
- if(cookie != null)
- {
- connection.setRequestProperty("cookie", cookie);
- }
-
- // This must be explicitly set for gzip progress tracking to work.
- connection.setRequestProperty("Accept-Encoding", "gzip");
-
- // Handle the other headers
- if (headers != null) {
- addHeadersToRequest(connection, headers);
- }
-
- connection.connect();
-
- if (connection.getContentEncoding() == null || connection.getContentEncoding().equalsIgnoreCase("gzip")) {
- // Only trust content-length header if we understand
- // the encoding -- identity or gzip
- if (connection.getContentLength() != -1) {
- progress.setLengthComputable(true);
- progress.setTotal(connection.getContentLength());
- }
- }
- inputStream = getInputStream(connection);
- }
-
- try {
- synchronized (context) {
- if (context.aborted) {
- return;
- }
- context.currentInputStream = inputStream;
- }
-
- // write bytes to file
- byte[] buffer = new byte[MAX_BUFFER_SIZE];
- int bytesRead = 0;
- while ((bytesRead = inputStream.read(buffer)) > 0) {
- outputStream.write(buffer, 0, bytesRead);
- // Send a progress event.
- progress.setLoaded(inputStream.getTotalRawBytesRead());
- PluginResult progressResult = new PluginResult(PluginResult.Status.OK, progress.toJSONObject());
- progressResult.setKeepCallback(true);
- context.sendPluginResult(progressResult);
- }
- } finally {
- context.currentInputStream = null;
- safeClose(inputStream);
- safeClose(outputStream);
- }
-
- Log.d(LOG_TAG, "Saved file: " + target);
-
- // create FileEntry object
- FileUtils filePlugin = (FileUtils)webView.pluginManager.getPlugin("File");
- if (filePlugin != null) {
- JSONObject fileEntry = filePlugin.getEntryForFile(file);
- if (fileEntry != null) {
- result = new PluginResult(PluginResult.Status.OK, fileEntry);
- } else {
- JSONObject error = createFileTransferError(CONNECTION_ERR, source, target, connection);
- Log.e(LOG_TAG, "File plugin cannot represent download path");
- result = new PluginResult(PluginResult.Status.IO_EXCEPTION, error);
- }
- } else {
- Log.e(LOG_TAG, "File plugin not found; cannot save downloaded file");
- result = new PluginResult(PluginResult.Status.ERROR, "File plugin not found; cannot save downloaded file");
- }
-
- } catch (FileNotFoundException e) {
- JSONObject error = createFileTransferError(FILE_NOT_FOUND_ERR, source, target, connection);
- Log.e(LOG_TAG, error.toString(), e);
- result = new PluginResult(PluginResult.Status.IO_EXCEPTION, error);
- } catch (IOException e) {
- JSONObject error = createFileTransferError(CONNECTION_ERR, source, target, connection);
- Log.e(LOG_TAG, error.toString(), e);
- result = new PluginResult(PluginResult.Status.IO_EXCEPTION, error);
- } catch (JSONException e) {
- Log.e(LOG_TAG, e.getMessage(), e);
- result = new PluginResult(PluginResult.Status.JSON_EXCEPTION);
- } catch (Throwable e) {
- JSONObject error = createFileTransferError(CONNECTION_ERR, source, target, connection);
- Log.e(LOG_TAG, error.toString(), e);
- result = new PluginResult(PluginResult.Status.IO_EXCEPTION, error);
- } finally {
- safeClose(outputStream);
- synchronized (activeRequests) {
- activeRequests.remove(objectId);
- }
-
- if (connection != null) {
- // Revert back to the proper verifier and socket factories
- if (trustEveryone && useHttps) {
- HttpsURLConnection https = (HttpsURLConnection) connection;
- https.setHostnameVerifier(oldHostnameVerifier);
- https.setSSLSocketFactory(oldSocketFactory);
- }
- }
-
- if (result == null) {
- result = new PluginResult(PluginResult.Status.ERROR, createFileTransferError(CONNECTION_ERR, source, target, connection));
- }
- // Remove incomplete download.
- if (result.getStatus() != PluginResult.Status.OK.ordinal() && file != null) {
- file.delete();
- }
- context.sendPluginResult(result);
- }
- }
- });
- }
-
- /**
- * Abort an ongoing upload or download.
- */
- private void abort(String objectId) {
- final RequestContext context;
- synchronized (activeRequests) {
- context = activeRequests.remove(objectId);
- }
- if (context != null) {
- File file = context.targetFile;
- if (file != null) {
- file.delete();
- }
- // Trigger the abort callback immediately to minimize latency between it and abort() being called.
- JSONObject error = createFileTransferError(ABORTED_ERR, context.source, context.target, null, -1);
- synchronized (context) {
- context.sendPluginResult(new PluginResult(PluginResult.Status.ERROR, error));
- context.aborted = true;
- }
- // Closing the streams can block, so execute on a background thread.
- cordova.getThreadPool().execute(new Runnable() {
- public void run() {
- synchronized (context) {
- safeClose(context.currentInputStream);
- safeClose(context.currentOutputStream);
- }
- }
- });
- }
- }
-}
diff --git a/src/ubuntu/file-transfer.cpp b/src/ubuntu/file-transfer.cpp
deleted file mode 100644
index 5b1adea..0000000
--- a/src/ubuntu/file-transfer.cpp
+++ /dev/null
@@ -1,265 +0,0 @@
-/*
- *
- * Copyright 2013 Canonical Ltd.
- *
- * Licensed 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.
- *
-*/
-
-#include "file-transfer.h"
-#include <plugins/cordova-plugin-file/file.h>
-#include <cassert>
-
-static void SetHeaders(QNetworkRequest &request, const QVariantMap &headers) {
- for (const QString &key: headers.keys()) {
- QVariant val = *headers.find(key);
- QString value = val.toString();
- if (val.userType() == QMetaType::QVariantList || val.userType() == QMetaType::QStringList) {
- QList<QVariant> list = val.toList();
- for (QVariant v: list) {
- if (value.size())
- value += ", ";
- value += v.toString();
- }
- }
- request.setRawHeader(key.toUtf8(), value.toUtf8());
- }
-}
-
-void FileTransfer::download(int scId, int ecId, const QString& url, const QString &target, bool /*trustAllHost*/, int id, const QVariantMap &headers) {
- QSharedPointer<FileTransferRequest> request(new FileTransferRequest(_manager, scId, ecId, id, this));
-
- assert(_id2request.find(id) == _id2request.end());
-
- _id2request.insert(id, request);
-
- request->connect(request.data(), &FileTransferRequest::done, [&]() {
- auto it = _id2request.find(id);
- while (it != _id2request.end() && it.key() == id) {
- if (it.value().data() == request.data()) {
- _id2request.erase(it);
- break;
- }
- it++;
- }
- });
- request->download(url, target, headers);
-}
-
-void FileTransfer::upload(int scId, int ecId, const QString &fileURI, const QString& url, const QString& fileKey, const QString& fileName, const QString& mimeType,
- const QVariantMap & params, bool /*trustAllHosts*/, bool /*chunkedMode*/, const QVariantMap &headers, int id, const QString &/*httpMethod*/) {
- QSharedPointer<FileTransferRequest> request(new FileTransferRequest(_manager, scId, ecId, id, this));
-
- assert(_id2request.find(id) == _id2request.end());
-
- _id2request.insert(id, request);
-
- request->connect(request.data(), &FileTransferRequest::done, [&]() {
- auto it = _id2request.find(id);
- while (it != _id2request.end() && it.key() == id) {
- if (it.value().data() == request.data()) {
- _id2request.erase(it);
- break;
- }
- it++;
- }
- });
- request->upload(url, fileURI, fileKey, fileName, mimeType, params, headers);
-}
-
-void FileTransfer::abort(int scId, int ecId, int id) {
- Q_UNUSED(scId)
- Q_UNUSED(ecId)
-
- auto it = _id2request.find(id);
- while (it != _id2request.end() && it.key() == id) {
- (*it)->abort();
- it++;
- }
-}
-
-void FileTransferRequest::download(const QString& uri, const QString &targetURI, const QVariantMap &headers) {
- QUrl url(uri);
- QNetworkRequest request;
-
- QSharedPointer<CPlugin> filePlugin(_plugin->cordova()->getPlugin<File>());
-
- if (!filePlugin.data())
- return;
-
- if (!url.isValid()) {
- QVariantMap map;
- map.insert("code", INVALID_URL_ERR);
- map.insert("source", uri);
- map.insert("target", targetURI);
- _plugin->cb(_ecId, map);
- emit done();
- return;
- }
-
- request.setUrl(url);
- if (url.password().size() || url.userName().size()) {
- QString headerData = "Basic " + (url.userName() + ":" + url.password()).toLocal8Bit().toBase64();
- request.setRawHeader("Authorization", headerData.toLocal8Bit());
- }
- SetHeaders(request, headers);
- _reply = QSharedPointer<QNetworkReply>(_manager.get(request));
-
- _reply->connect(_reply.data(), &QNetworkReply::finished, [this, targetURI, uri, filePlugin]() {
- if (!_scId || _reply->error() != QNetworkReply::NoError)
- return;
-
- QPair<bool, QFileInfo> f1(dynamic_cast<File*>(filePlugin.data())->resolveURI(targetURI));
-
- QFile res(f1.second.absoluteFilePath());
- if (!f1.first || !res.open(QIODevice::WriteOnly)) {
- QVariantMap map;
- map.insert("code", INVALID_URL_ERR);
- map.insert("source", uri);
- map.insert("target", targetURI);
- _plugin->cb(_ecId, map);
- emit done();
- return;
- }
- res.write(_reply->readAll());
-
- _plugin->cb(_scId, dynamic_cast<File*>(filePlugin.data())->file2map(f1.second));
-
- emit done();
- });
- _reply->connect(_reply.data(), SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(error(QNetworkReply::NetworkError)));
- _reply->connect(_reply.data(), SIGNAL(downloadProgress(qint64, qint64)), this, SLOT(progress(qint64, qint64)));
-}
-
-void FileTransferRequest::upload(const QString& _url, const QString& fileURI, QString fileKey, QString fileName, QString mimeType, const QVariantMap ¶ms, const QVariantMap &headers) {
- QUrl url(_url);
- QNetworkRequest request;
-
- QSharedPointer<CPlugin> filePlugin(_plugin->cordova()->getPlugin<File>());
-
- if (!filePlugin.data())
- return;
-
- if (!url.isValid()) {
- QVariantMap map;
- map.insert("code", INVALID_URL_ERR);
- map.insert("source", fileURI);
- map.insert("target", _url);
- _plugin->cb(_ecId, map);
- emit done();
- return;
- }
-
- QPair<bool, QFileInfo> f1(dynamic_cast<File*>(filePlugin.data())->resolveURI(fileURI));
- QFile file(f1.second.absoluteFilePath());
- if (!f1.first || !file.open(QIODevice::ReadOnly)) {
- QVariantMap map;
- map.insert("code", FILE_NOT_FOUND_ERR);
- map.insert("source", fileURI);
- map.insert("target", _url);
- _plugin->cb(_ecId, map);
- emit done();
- return;
- }
- QString content{file.readAll()};
-
- request.setUrl(url);
- if (url.password().size() || url.userName().size()) {
- QString headerData = "Basic " + (url.userName() + ":" + url.password()).toLocal8Bit().toBase64();
- request.setRawHeader("Authorization", headerData.toLocal8Bit());
- }
- SetHeaders(request, headers);
-
- QString boundary = QString("CORDOVA-QT-%1A").arg(qrand());
- while (content.contains(boundary)) {
- boundary += QString("B%1A").arg(qrand());
- }
-
- request.setHeader(QNetworkRequest::ContentTypeHeader, QString("multipart/form-data; boundary=") + boundary);
-
- fileKey.replace("\"", "");
- fileName.replace("\"", "");
- mimeType.replace("\"", "");
- QString part = "--" + boundary + "\r\n";
-
- part += "Content-Disposition: form-data; name=\"" + fileKey +"\"; filename=\"" + fileName + "\"\r\n";
- part += "Content-Type: " + mimeType + "\r\n\r\n";
- part += content + "\r\n";
-
- for (QString key: params.keys()) {
- part += "--" + boundary + "\r\n";
- part += "Content-Disposition: form-data; name=\"" + key + "\";\r\n\r\n";
- part += params.find(key)->toString();
- part += "\r\n";
- }
-
- part += QString("--") + boundary + "--" + "\r\n";
-
- _reply = QSharedPointer<QNetworkReply>(_manager.post(request, QByteArray(part.toUtf8())));
-
- _reply->connect(_reply.data(), &QNetworkReply::finished, [this, content]() {
- if (_reply->error() != QNetworkReply::NoError)
- return;
- int status = 200;
- QVariant statusCode = _reply->attribute(QNetworkRequest::HttpStatusCodeAttribute);
-
- if (statusCode.isValid()) {
- status = statusCode.toInt();
- }
-
- QVariantMap map;
- map.insert("responseCode", status);
- map.insert("response", QString(_reply->readAll()));
- map.insert("bytesSent", content.size());
- _plugin->cb(_scId, map);
- emit done();
- });
- _reply->connect(_reply.data(), SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(error(QNetworkReply::NetworkError)));
- _reply->connect(_reply.data(), SIGNAL(uploadProgress(qint64, qint64)), this, SLOT(progress(qint64, qint64)));
-}
-
-void FileTransferRequest::abort() {
- QVariantMap map;
- map.insert("code", ABORT_ERR);
- _plugin->cb(_ecId, map);
- _scId = 0;
- emit done();
-}
-
-void FileTransferRequest::error(QNetworkReply::NetworkError code) {
- Q_UNUSED(code);
-
- int status = 404;
- QVariant statusCode = _reply->attribute(QNetworkRequest::HttpStatusCodeAttribute);
- if (statusCode.isValid()) {
- status = statusCode.toInt();
- }
-
- QVariantMap map;
- map.insert("http_status", status);
- map.insert("body", QString(_reply->readAll()));
- map.insert("code", CONNECTION_ERR);
- _plugin->cb(_ecId, map);
- emit done();
-}
-
-void FileTransferRequest::progress(qint64 bytesReceived, qint64 bytesTotal) {
- QVariantMap map;
- map.insert("lengthComputable", true);
- map.insert("total", bytesTotal);
- map.insert("loaded", bytesReceived);
-
- if (bytesReceived && bytesTotal && _scId)
- _plugin->callbackWithoutRemove(_scId, CordovaInternal::format(map));
-}
diff --git a/src/ubuntu/file-transfer.h b/src/ubuntu/file-transfer.h
deleted file mode 100644
index 75822cb..0000000
--- a/src/ubuntu/file-transfer.h
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- *
- * Copyright 2013 Canonical Ltd.
- *
- * Licensed 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.
- *
-*/
-
-#ifndef FILE_TRANSFER_H_SDASDASDAS
-#define FILE_TRANSFER_H_SDASDASDAS
-
-#include <QtCore>
-#include <QtNetwork>
-
-#include <cplugin.h>
-
-class FileTransfer;
-
-class FileTransferRequest: public QObject {
- Q_OBJECT
-
- QNetworkAccessManager &_manager;
- int _scId, _ecId;
- int _id;
- QSharedPointer<QNetworkReply> _reply;
-
- enum FileTransferError {
- FILE_NOT_FOUND_ERR = 1,
- INVALID_URL_ERR = 2,
- CONNECTION_ERR = 3,
- ABORT_ERR = 4
- };
-
-public:
- FileTransferRequest(QNetworkAccessManager &manager, int scId, int ecId, int id, FileTransfer *plugin):
- _manager(manager),
- _scId(scId),
- _ecId(ecId),
- _id(id),
- _plugin(plugin) {
- }
-
- void download(const QString& url, const QString &targetURI, const QVariantMap &headers);
- void upload(const QString& _url, const QString& fileURI, QString fileKey, QString fileName, QString mimeType, const QVariantMap ¶ms, const QVariantMap &headers);
- void abort();
-
-signals:
- void done();
-
-private slots:
- void progress(qint64 bytesReceived, qint64 bytesTotal);
- void error(QNetworkReply::NetworkError code);
-private:
- FileTransfer *_plugin;
- Q_DISABLE_COPY(FileTransferRequest);
-};
-
-class FileTransfer : public CPlugin {
- Q_OBJECT
-public:
- explicit FileTransfer(Cordova *cordova): CPlugin(cordova) {
- }
-
- Cordova* cordova() {
- return m_cordova;
- }
-
- virtual const QString fullName() override {
- return FileTransfer::fullID();
- }
-
- virtual const QString shortName() override {
- return "FileTransfer";
- }
-
- static const QString fullID() {
- return "FileTransfer";
- }
-
-public slots:
- void abort(int scId, int ecId, int id);
- void download(int scId, int ecId, const QString& url, const QString &target, bool /*trustAllHost*/, int id, const QVariantMap &/*headers*/);
- void upload(int scId, int ecId, const QString &filePath, const QString& url, const QString& fileKey, const QString& fileName, const QString& mimeType,
- const QVariantMap & params, bool /*trustAllHosts*/, bool /*chunkedMode*/, const QVariantMap &headers, int id, const QString &httpMethod);
-
-private:
- QNetworkAccessManager _manager;
- QMultiMap<int, QSharedPointer<FileTransferRequest> > _id2request;
- int lastRequestId;
-};
-
-#endif
diff --git a/src/wp/FileTransfer.cs b/src/wp/FileTransfer.cs
deleted file mode 100644
index 4be46e8..0000000
--- a/src/wp/FileTransfer.cs
+++ /dev/null
@@ -1,994 +0,0 @@
-/*
- Licensed 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.
-*/
-
-using Microsoft.Phone.Controls;
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.IO.IsolatedStorage;
-using System.Linq;
-using System.Net;
-using System.Runtime.Serialization;
-using System.Windows;
-using System.Security;
-using System.Diagnostics;
-using System.Threading.Tasks;
-using WPCordovaClassLib.Cordova.JSON;
-using System.Reflection;
-
-namespace WPCordovaClassLib.Cordova.Commands
-{
- public class FileTransfer : BaseCommand
- {
- public class DownloadRequestState
- {
- // This class stores the State of the request.
- public HttpWebRequest request;
- public TransferOptions options;
- public bool isCancelled;
-
- public DownloadRequestState()
- {
- request = null;
- options = null;
- isCancelled = false;
- }
- }
-
- public class TransferOptions
- {
- /// File path to upload OR File path to download to
- public string FilePath { get; set; }
-
- public string Url { get; set; }
- /// Flag to recognize if we should trust every host (only in debug environments)
- public bool TrustAllHosts { get; set; }
- public string Id { get; set; }
- public string Headers { get; set; }
- public string CallbackId { get; set; }
- public bool ChunkedMode { get; set; }
- /// Server address
- public string Server { get; set; }
- /// File key
- public string FileKey { get; set; }
- /// File name on the server
- public string FileName { get; set; }
- /// File Mime type
- public string MimeType { get; set; }
- /// Additional options
- public string Params { get; set; }
- public string Method { get; set; }
-
- public TransferOptions()
- {
- FileKey = "file";
- FileName = "image.jpg";
- MimeType = "image/jpeg";
- }
- }
-
- /// <summary>
- /// Boundary symbol
- /// </summary>
- private string Boundary = "----------------------------" + DateTime.Now.Ticks.ToString("x");
-
- // Error codes
- public const int FileNotFoundError = 1;
- public const int InvalidUrlError = 2;
- public const int ConnectionError = 3;
- public const int AbortError = 4; // not really an error, but whatevs
-
- private static Dictionary<string, DownloadRequestState> InProcDownloads = new Dictionary<string,DownloadRequestState>();
-
- // Private instance of the main WebBrowser instance
- // NOTE: Any access to this object needs to occur on the UI thread via the Dispatcher
- private WebBrowser browser;
-
-
-
- /// <summary>
- /// Uploading response info
- /// </summary>
- [DataContract]
- public class FileUploadResult
- {
- /// <summary>
- /// Amount of sent bytes
- /// </summary>
- [DataMember(Name = "bytesSent")]
- public long BytesSent { get; set; }
-
- /// <summary>
- /// Server response code
- /// </summary>
- [DataMember(Name = "responseCode")]
- public long ResponseCode { get; set; }
-
- /// <summary>
- /// Server response
- /// </summary>
- [DataMember(Name = "response", EmitDefaultValue = false)]
- public string Response { get; set; }
-
- /// <summary>
- /// Creates FileUploadResult object with response values
- /// </summary>
- /// <param name="bytesSent">Amount of sent bytes</param>
- /// <param name="responseCode">Server response code</param>
- /// <param name="response">Server response</param>
- public FileUploadResult(long bytesSent, long responseCode, string response)
- {
- this.BytesSent = bytesSent;
- this.ResponseCode = responseCode;
- this.Response = response;
- }
- }
- /// <summary>
- /// Represents transfer error codes for callback
- /// </summary>
- [DataContract]
- public class FileTransferError
- {
- /// <summary>
- /// Error code
- /// </summary>
- [DataMember(Name = "code", IsRequired = true)]
- public int Code { get; set; }
-
- /// <summary>
- /// The source URI
- /// </summary>
- [DataMember(Name = "source", IsRequired = true)]
- public string Source { get; set; }
-
- /// <summary>
- /// The target URI
- /// </summary>
- ///
- [DataMember(Name = "target", IsRequired = true)]
- public string Target { get; set; }
-
- [DataMember(Name = "body", IsRequired = true)]
- public string Body { get; set; }
-
- /// <summary>
- /// The http status code response from the remote URI
- /// </summary>
- [DataMember(Name = "http_status", IsRequired = true)]
- public int HttpStatus { get; set; }
-
- /// <summary>
- /// Creates FileTransferError object
- /// </summary>
- /// <param name="errorCode">Error code</param>
- public FileTransferError(int errorCode)
- {
- this.Code = errorCode;
- this.Source = null;
- this.Target = null;
- this.HttpStatus = 0;
- this.Body = "";
- }
- public FileTransferError(int errorCode, string source, string target, int status, string body = "")
- {
- this.Code = errorCode;
- this.Source = source;
- this.Target = target;
- this.HttpStatus = status;
- this.Body = body;
- }
- }
-
- /// <summary>
- /// Represents a singular progress event to be passed back to javascript
- /// </summary>
- [DataContract]
- public class FileTransferProgress
- {
- /// <summary>
- /// Is the length of the response known?
- /// </summary>
- [DataMember(Name = "lengthComputable", IsRequired = true)]
- public bool LengthComputable { get; set; }
- /// <summary>
- /// amount of bytes loaded
- /// </summary>
- [DataMember(Name = "loaded", IsRequired = true)]
- public long BytesLoaded { get; set; }
- /// <summary>
- /// Total bytes
- /// </summary>
- [DataMember(Name = "total", IsRequired = false)]
- public long BytesTotal { get; set; }
-
- public FileTransferProgress(long bTotal = 0, long bLoaded = 0)
- {
- LengthComputable = bTotal > 0;
- BytesLoaded = bLoaded;
- BytesTotal = bTotal;
- }
- }
-
- /// <summary>
- /// Represents a request header passed from Javascript to upload/download operations
- /// </summary>
- [DataContract]
- protected struct Header
- {
- [DataMember(Name = "name")]
- public string Name;
-
- [DataMember(Name = "value")]
- public string Value;
- }
-
- private static MethodInfo JsonDeserializeUsingJsonNet;
-
- public FileTransfer()
- {
- if (JsonDeserializeUsingJsonNet == null)
- {
- var method = typeof(JsonHelper).GetMethod("Deserialize", new Type[] { typeof(string), typeof(bool) });
- if (method != null)
- {
- JsonDeserializeUsingJsonNet = method.MakeGenericMethod(new Type[] { typeof(Header[]) });
- }
- }
- }
-
- /// Helper method to copy all relevant cookies from the WebBrowser control into a header on
- /// the HttpWebRequest
- /// </summary>
- /// <param name="browser">The source browser to copy the cookies from</param>
- /// <param name="webRequest">The destination HttpWebRequest to add the cookie header to</param>
- /// <returns>Nothing</returns>
- private async Task CopyCookiesFromWebBrowser(HttpWebRequest webRequest)
- {
- var tcs = new TaskCompletionSource<object>();
-
- // Accessing WebBrowser needs to happen on the UI thread
- Deployment.Current.Dispatcher.BeginInvoke(() =>
- {
- // Get the WebBrowser control
- if (this.browser == null)
- {
- PhoneApplicationFrame frame = Application.Current.RootVisual as PhoneApplicationFrame;
- if (frame != null)
- {
- PhoneApplicationPage page = frame.Content as PhoneApplicationPage;
- if (page != null)
- {
- CordovaView cView = page.FindName("CordovaView") as CordovaView;
- if (cView != null)
- {
- this.browser = cView.Browser;
- }
- }
- }
- }
-
- try
- {
- // Only copy the cookies if the scheme and host match (to avoid any issues with secure/insecure cookies)
- // NOTE: since the returned CookieCollection appears to munge the original cookie's domain value in favor of the actual Source domain,
- // we can't know for sure whether the cookies would be applicable to any other hosts, so best to play it safe and skip for now.
- if (this.browser != null && this.browser.Source.IsAbsoluteUri == true &&
- this.browser.Source.Scheme == webRequest.RequestUri.Scheme && this.browser.Source.Host == webRequest.RequestUri.Host)
- {
- string cookieHeader = "";
- string requestPath = webRequest.RequestUri.PathAndQuery;
- CookieCollection cookies = this.browser.GetCookies();
-
- // Iterate over the cookies and add to the header
- foreach (Cookie cookie in cookies)
- {
- // Check that the path is allowed, first
- // NOTE: Path always seems to be empty for now, even if the cookie has a path set by the server.
- if (cookie.Path.Length == 0 || requestPath.IndexOf(cookie.Path, StringComparison.InvariantCultureIgnoreCase) == 0)
- {
- cookieHeader += cookie.Name + "=" + cookie.Value + "; ";
- }
- }
-
- // Finally, set the header if we found any cookies
- if (cookieHeader.Length > 0)
- {
- webRequest.Headers["Cookie"] = cookieHeader;
- }
- }
- }
- catch (Exception)
- {
- // Swallow the exception
- }
-
- // Complete the task
- tcs.SetResult(Type.Missing);
- });
-
- await tcs.Task;
- }
-
- /// <summary>
- /// Upload options
- /// </summary>
- //private TransferOptions uploadOptions;
-
- /// <summary>
- /// Bytes sent
- /// </summary>
- private long bytesSent;
-
- /// <summary>
- /// sends a file to a server
- /// </summary>
- /// <param name="options">Upload options</param>
- /// exec(win, fail, 'FileTransfer', 'upload', [filePath, server, fileKey, fileName, mimeType, params, trustAllHosts, chunkedMode, headers, this._id, httpMethod]);
- public void upload(string options)
- {
- options = options.Replace("{}", ""); // empty objects screw up the Deserializer
- string callbackId = "";
-
- TransferOptions uploadOptions = null;
- HttpWebRequest webRequest = null;
-
- try
- {
- try
- {
- string[] args = JSON.JsonHelper.Deserialize<string[]>(options);
- uploadOptions = new TransferOptions();
- uploadOptions.FilePath = args[0];
- uploadOptions.Server = args[1];
- uploadOptions.FileKey = args[2];
- uploadOptions.FileName = args[3];
- uploadOptions.MimeType = args[4];
- uploadOptions.Params = args[5];
-
- bool trustAll = false;
- bool.TryParse(args[6],out trustAll);
- uploadOptions.TrustAllHosts = trustAll;
-
- bool doChunked = false;
- bool.TryParse(args[7], out doChunked);
- uploadOptions.ChunkedMode = doChunked;
-
- //8 : Headers
- //9 : id
- //10: method
-
- uploadOptions.Headers = args[8];
- uploadOptions.Id = args[9];
- uploadOptions.Method = args[10];
-
- uploadOptions.CallbackId = callbackId = args[11];
- }
- catch (Exception)
- {
- DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION));
- return;
- }
-
- Uri serverUri;
- try
- {
- serverUri = new Uri(uploadOptions.Server);
- }
- catch (Exception)
- {
- DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, new FileTransferError(InvalidUrlError, uploadOptions.Server, null, 0)));
- return;
- }
- webRequest = (HttpWebRequest)WebRequest.Create(serverUri);
- webRequest.ContentType = "multipart/form-data; boundary=" + Boundary;
- webRequest.Method = uploadOptions.Method;
-
- DownloadRequestState reqState = new DownloadRequestState();
- InProcDownloads[uploadOptions.Id] = reqState;
- reqState.options = uploadOptions;
- reqState.request = webRequest;
-
- try
- {
- // Associate cookies with the request
- // This is an async call, so we need to await it in order to preserve proper control flow
- Task cookieTask = CopyCookiesFromWebBrowser(webRequest);
- cookieTask.Wait();
- }
- catch (AggregateException ae)
- {
- DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR,
- new FileTransferError(FileTransfer.ConnectionError, uploadOptions.FilePath, uploadOptions.Server, 0, ae.InnerException.Message)));
- return;
- }
-
- if (!string.IsNullOrEmpty(uploadOptions.Headers))
- {
- Dictionary<string, string> headers = parseHeaders(uploadOptions.Headers);
- if (headers != null)
- {
- foreach (string key in headers.Keys)
- {
- webRequest.Headers[key] = headers[key];
- }
- }
- }
-
- webRequest.BeginGetRequestStream(uploadCallback, reqState);
- }
- catch (Exception /*ex*/)
- {
- DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, new FileTransferError(ConnectionError)),callbackId);
- }
- }
-
- // example : "{\"Authorization\":\"Basic Y29yZG92YV91c2VyOmNvcmRvdmFfcGFzc3dvcmQ=\"}"
- protected Dictionary<string,string> parseHeaders(string jsonHeaders)
- {
- try
- {
- if (FileTransfer.JsonDeserializeUsingJsonNet != null)
- {
- return ((Header[])FileTransfer.JsonDeserializeUsingJsonNet.Invoke(null, new object[] { jsonHeaders, true }))
- .ToDictionary(header => header.Name, header => header.Value);
- }
- else
- {
- return JsonHelper.Deserialize<Header[]>(jsonHeaders)
- .ToDictionary(header => header.Name, header => header.Value);
- }
- }
- catch (Exception)
- {
- Debug.WriteLine("Failed to parseHeaders from string :: " + jsonHeaders);
- }
- return new Dictionary<string, string>();
- }
-
- public void download(string options)
- {
- TransferOptions downloadOptions = null;
- HttpWebRequest webRequest = null;
- string callbackId;
-
- try
- {
- // source, target, trustAllHosts, this._id, headers
- string[] optionStrings = JSON.JsonHelper.Deserialize<string[]>(options);
-
- downloadOptions = new TransferOptions();
- downloadOptions.Url = optionStrings[0];
- downloadOptions.FilePath = optionStrings[1];
-
- bool trustAll = false;
- bool.TryParse(optionStrings[2],out trustAll);
- downloadOptions.TrustAllHosts = trustAll;
-
- downloadOptions.Id = optionStrings[3];
- downloadOptions.Headers = optionStrings[4];
- downloadOptions.CallbackId = callbackId = optionStrings[5];
- }
- catch (Exception)
- {
- DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION));
- return;
- }
-
- try
- {
- // is the URL a local app file?
- if (downloadOptions.Url.StartsWith("x-wmapp0") || downloadOptions.Url.StartsWith("file:"))
- {
- using (IsolatedStorageFile isoFile = IsolatedStorageFile.GetUserStoreForApplication())
- {
- string cleanUrl = downloadOptions.Url.Replace("x-wmapp0:", "").Replace("file:", "").Replace("//","");
-
- // pre-emptively create any directories in the FilePath that do not exist
- string directoryName = getDirectoryName(downloadOptions.FilePath);
- if (!string.IsNullOrEmpty(directoryName) && !isoFile.DirectoryExists(directoryName))
- {
- isoFile.CreateDirectory(directoryName);
- }
-
- // just copy from one area of iso-store to another ...
- if (isoFile.FileExists(downloadOptions.Url))
- {
- isoFile.CopyFile(downloadOptions.Url, downloadOptions.FilePath);
- }
- else
- {
- // need to unpack resource from the dll
- Uri uri = new Uri(cleanUrl, UriKind.Relative);
- var resource = Application.GetResourceStream(uri);
-
- if (resource != null)
- {
- // create the file destination
- if (!isoFile.FileExists(downloadOptions.FilePath))
- {
- var destFile = isoFile.CreateFile(downloadOptions.FilePath);
- destFile.Close();
- }
-
- using (FileStream fileStream = new IsolatedStorageFileStream(downloadOptions.FilePath, FileMode.Open, FileAccess.Write, isoFile))
- {
- long totalBytes = resource.Stream.Length;
- int bytesRead = 0;
- using (BinaryReader reader = new BinaryReader(resource.Stream))
- {
- using (BinaryWriter writer = new BinaryWriter(fileStream))
- {
- int BUFFER_SIZE = 1024;
- byte[] buffer;
-
- while (true)
- {
- buffer = reader.ReadBytes(BUFFER_SIZE);
- // fire a progress event ?
- bytesRead += buffer.Length;
- if (buffer.Length > 0)
- {
- writer.Write(buffer);
- DispatchFileTransferProgress(bytesRead, totalBytes, callbackId);
- }
- else
- {
- writer.Close();
- reader.Close();
- fileStream.Close();
- break;
- }
- }
- }
- }
- }
- }
- }
- }
-
- File.FileEntry entry = File.FileEntry.GetEntry(downloadOptions.FilePath);
- if (entry != null)
- {
- DispatchCommandResult(new PluginResult(PluginResult.Status.OK, entry), callbackId);
- }
- else
- {
- DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, File.NOT_FOUND_ERR), callbackId);
- }
-
- return;
- }
- else
- {
- // otherwise it is web-bound, we will actually download it
- //Debug.WriteLine("Creating WebRequest for url : " + downloadOptions.Url);
- webRequest = (HttpWebRequest)WebRequest.Create(downloadOptions.Url);
- }
- }
- catch (Exception /*ex*/)
- {
- DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR,
- new FileTransferError(InvalidUrlError, downloadOptions.Url, null, 0)));
- return;
- }
-
- if (downloadOptions != null && webRequest != null)
- {
- DownloadRequestState state = new DownloadRequestState();
- state.options = downloadOptions;
- state.request = webRequest;
- InProcDownloads[downloadOptions.Id] = state;
-
- try
- {
- // Associate cookies with the request
- // This is an async call, so we need to await it in order to preserve proper control flow
- Task cookieTask = CopyCookiesFromWebBrowser(webRequest);
- cookieTask.Wait();
- }
- catch (AggregateException ae)
- {
- DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR,
- new FileTransferError(FileTransfer.ConnectionError, downloadOptions.Url, downloadOptions.FilePath, 0, ae.InnerException.Message)));
- return;
- }
-
- if (!string.IsNullOrEmpty(downloadOptions.Headers))
- {
- Dictionary<string, string> headers = parseHeaders(downloadOptions.Headers);
- foreach (string key in headers.Keys)
- {
- webRequest.Headers[key] = headers[key];
- }
- }
-
- try
- {
- webRequest.BeginGetResponse(new AsyncCallback(downloadCallback), state);
- }
- catch (WebException)
- {
- // eat it
- }
- // dispatch an event for progress ( 0 )
- lock (state)
- {
- if (!state.isCancelled)
- {
- var plugRes = new PluginResult(PluginResult.Status.OK, new FileTransferProgress());
- plugRes.KeepCallback = true;
- plugRes.CallbackId = callbackId;
- DispatchCommandResult(plugRes, callbackId);
- }
- }
- }
- }
-
- public void abort(string options)
- {
- Debug.WriteLine("Abort :: " + options);
- string[] optionStrings = JSON.JsonHelper.Deserialize<string[]>(options);
- string id = optionStrings[0];
- string callbackId = optionStrings[1];
-
- if (id != null && InProcDownloads.ContainsKey(id))
- {
- DownloadRequestState state = InProcDownloads[id];
- if (!state.isCancelled)
- { // prevent multiple callbacks for the same abort
- state.isCancelled = true;
- if (!state.request.HaveResponse)
- {
- state.request.Abort();
- InProcDownloads.Remove(id);
- //callbackId = state.options.CallbackId;
- //state = null;
- DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR,
- new FileTransferError(FileTransfer.AbortError)),
- state.options.CallbackId);
- }
- }
- }
- else
- {
- DispatchCommandResult(new PluginResult(PluginResult.Status.IO_EXCEPTION), callbackId); // TODO: is it an IO exception?
- }
- }
-
- private void DispatchFileTransferProgress(long bytesLoaded, long bytesTotal, string callbackId, bool keepCallback = true)
- {
- Debug.WriteLine("DispatchFileTransferProgress : " + callbackId);
- // send a progress change event
- FileTransferProgress progEvent = new FileTransferProgress(bytesTotal);
- progEvent.BytesLoaded = bytesLoaded;
- PluginResult plugRes = new PluginResult(PluginResult.Status.OK, progEvent);
- plugRes.KeepCallback = keepCallback;
- plugRes.CallbackId = callbackId;
- DispatchCommandResult(plugRes, callbackId);
- }
-
- /// <summary>
- ///
- /// </summary>
- /// <param name="asynchronousResult"></param>
- private void downloadCallback(IAsyncResult asynchronousResult)
- {
- DownloadRequestState reqState = (DownloadRequestState)asynchronousResult.AsyncState;
- HttpWebRequest request = reqState.request;
-
- string callbackId = reqState.options.CallbackId;
- try
- {
- HttpWebResponse response = (HttpWebResponse)request.EndGetResponse(asynchronousResult);
-
- // send a progress change event
- DispatchFileTransferProgress(0, response.ContentLength, callbackId);
-
- using (IsolatedStorageFile isoFile = IsolatedStorageFile.GetUserStoreForApplication())
- {
- // create any directories in the path that do not exist
- string directoryName = getDirectoryName(reqState.options.FilePath);
- if (!string.IsNullOrEmpty(directoryName) && !isoFile.DirectoryExists(directoryName))
- {
- isoFile.CreateDirectory(directoryName);
- }
-
- // create the file if not exists
- if (!isoFile.FileExists(reqState.options.FilePath))
- {
- var file = isoFile.CreateFile(reqState.options.FilePath);
- file.Close();
- }
-
- using (FileStream fileStream = new IsolatedStorageFileStream(reqState.options.FilePath, FileMode.Open, FileAccess.Write, isoFile))
- {
- long totalBytes = response.ContentLength;
- int bytesRead = 0;
- using (BinaryReader reader = new BinaryReader(response.GetResponseStream()))
- {
- using (BinaryWriter writer = new BinaryWriter(fileStream))
- {
- int BUFFER_SIZE = 1024;
- byte[] buffer;
-
- while (true)
- {
- buffer = reader.ReadBytes(BUFFER_SIZE);
- // fire a progress event ?
- bytesRead += buffer.Length;
- if (buffer.Length > 0 && !reqState.isCancelled)
- {
- writer.Write(buffer);
- DispatchFileTransferProgress(bytesRead, totalBytes, callbackId);
- }
- else
- {
- writer.Close();
- reader.Close();
- fileStream.Close();
- break;
- }
- System.Threading.Thread.Sleep(1);
- }
- }
- }
- }
- if (reqState.isCancelled)
- {
- isoFile.DeleteFile(reqState.options.FilePath);
- }
- }
-
- if (reqState.isCancelled)
- {
- DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, new FileTransferError(AbortError)),
- callbackId);
- }
- else
- {
- File.FileEntry entry = new File.FileEntry(reqState.options.FilePath);
- DispatchCommandResult(new PluginResult(PluginResult.Status.OK, entry), callbackId);
- }
- }
- catch (IsolatedStorageException)
- {
- // Trying to write the file somewhere within the IsoStorage.
- DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, new FileTransferError(FileNotFoundError)),
- callbackId);
- }
- catch (SecurityException)
- {
- // Trying to write the file somewhere not allowed.
- DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, new FileTransferError(FileNotFoundError)),
- callbackId);
- }
- catch (WebException webex)
- {
- // TODO: probably need better work here to properly respond with all http status codes back to JS
- // Right now am jumping through hoops just to detect 404.
- HttpWebResponse response = (HttpWebResponse)webex.Response;
- if ((webex.Status == WebExceptionStatus.ProtocolError && response.StatusCode == HttpStatusCode.NotFound)
- || webex.Status == WebExceptionStatus.UnknownError)
- {
- // Weird MSFT detection of 404... seriously... just give us the f(*&#$@ status code as a number ffs!!!
- // "Numbers for HTTP status codes? Nah.... let's create our own set of enums/structs to abstract that stuff away."
- // FACEPALM
- // Or just cast it to an int, whiner ... -jm
- int statusCode = (int)response.StatusCode;
- string body = "";
-
- using (Stream streamResponse = response.GetResponseStream())
- {
- using (StreamReader streamReader = new StreamReader(streamResponse))
- {
- body = streamReader.ReadToEnd();
- }
- }
- FileTransferError ftError = new FileTransferError(ConnectionError, null, null, statusCode, body);
- DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, ftError),
- callbackId);
- }
- else
- {
- lock (reqState)
- {
- if (!reqState.isCancelled)
- {
- DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR,
- new FileTransferError(ConnectionError)),
- callbackId);
- }
- else
- {
- Debug.WriteLine("It happened");
- }
- }
- }
- }
- catch (Exception)
- {
- DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR,
- new FileTransferError(FileNotFoundError)),
- callbackId);
- }
-
- //System.Threading.Thread.Sleep(1000);
- if (InProcDownloads.ContainsKey(reqState.options.Id))
- {
- InProcDownloads.Remove(reqState.options.Id);
- }
- }
-
- /// <summary>
- /// Read file from Isolated Storage and sends it to server
- /// </summary>
- /// <param name="asynchronousResult"></param>
- private void uploadCallback(IAsyncResult asynchronousResult)
- {
- DownloadRequestState reqState = (DownloadRequestState)asynchronousResult.AsyncState;
- HttpWebRequest webRequest = reqState.request;
- string callbackId = reqState.options.CallbackId;
-
- try
- {
- using (Stream requestStream = (webRequest.EndGetRequestStream(asynchronousResult)))
- {
- string lineStart = "--";
- string lineEnd = Environment.NewLine;
- byte[] boundaryBytes = System.Text.Encoding.UTF8.GetBytes(lineStart + Boundary + lineEnd);
- string formdataTemplate = "Content-Disposition: form-data; name=\"{0}\"" + lineEnd + lineEnd + "{1}" + lineEnd;
-
- if (!string.IsNullOrEmpty(reqState.options.Params))
- {
- Dictionary<string, string> paramMap = parseHeaders(reqState.options.Params);
- foreach (string key in paramMap.Keys)
- {
- requestStream.Write(boundaryBytes, 0, boundaryBytes.Length);
- string formItem = string.Format(formdataTemplate, key, paramMap[key]);
- byte[] formItemBytes = System.Text.Encoding.UTF8.GetBytes(formItem);
- requestStream.Write(formItemBytes, 0, formItemBytes.Length);
- }
- }
- using (IsolatedStorageFile isoFile = IsolatedStorageFile.GetUserStoreForApplication())
- {
- if (!isoFile.FileExists(reqState.options.FilePath))
- {
- DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, new FileTransferError(FileNotFoundError, reqState.options.Server, reqState.options.FilePath, 0)));
- return;
- }
-
- byte[] endRequest = System.Text.Encoding.UTF8.GetBytes(lineEnd + lineStart + Boundary + lineStart + lineEnd);
- long totalBytesToSend = 0;
-
- using (FileStream fileStream = new IsolatedStorageFileStream(reqState.options.FilePath, FileMode.Open, isoFile))
- {
- string headerTemplate = "Content-Disposition: form-data; name=\"{0}\"; filename=\"{1}\"" + lineEnd + "Content-Type: {2}" + lineEnd + lineEnd;
- string header = string.Format(headerTemplate, reqState.options.FileKey, reqState.options.FileName, reqState.options.MimeType);
- byte[] headerBytes = System.Text.Encoding.UTF8.GetBytes(header);
-
- byte[] buffer = new byte[4096];
- int bytesRead = 0;
- //sent bytes needs to be reseted before new upload
- bytesSent = 0;
- totalBytesToSend = fileStream.Length;
-
- requestStream.Write(boundaryBytes, 0, boundaryBytes.Length);
-
- requestStream.Write(headerBytes, 0, headerBytes.Length);
-
- while ((bytesRead = fileStream.Read(buffer, 0, buffer.Length)) != 0)
- {
- if (!reqState.isCancelled)
- {
- requestStream.Write(buffer, 0, bytesRead);
- bytesSent += bytesRead;
- DispatchFileTransferProgress(bytesSent, totalBytesToSend, callbackId);
- System.Threading.Thread.Sleep(1);
- }
- else
- {
- throw new Exception("UploadCancelledException");
- }
- }
- }
-
- requestStream.Write(endRequest, 0, endRequest.Length);
- }
- }
- // webRequest
-
- webRequest.BeginGetResponse(ReadCallback, reqState);
- }
- catch (Exception /*ex*/)
- {
- if (!reqState.isCancelled)
- {
- DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, new FileTransferError(ConnectionError)), callbackId);
- }
- }
- }
-
- /// <summary>
- /// Reads response into FileUploadResult
- /// </summary>
- /// <param name="asynchronousResult"></param>
- private void ReadCallback(IAsyncResult asynchronousResult)
- {
- DownloadRequestState reqState = (DownloadRequestState)asynchronousResult.AsyncState;
- try
- {
- HttpWebRequest webRequest = reqState.request;
- string callbackId = reqState.options.CallbackId;
-
- if (InProcDownloads.ContainsKey(reqState.options.Id))
- {
- InProcDownloads.Remove(reqState.options.Id);
- }
-
- using (HttpWebResponse response = (HttpWebResponse)webRequest.EndGetResponse(asynchronousResult))
- {
- using (Stream streamResponse = response.GetResponseStream())
- {
- using (StreamReader streamReader = new StreamReader(streamResponse))
- {
- string responseString = streamReader.ReadToEnd();
- Deployment.Current.Dispatcher.BeginInvoke(() =>
- {
- DispatchCommandResult(new PluginResult(PluginResult.Status.OK, new FileUploadResult(bytesSent, (long)response.StatusCode, responseString)));
- });
- }
- }
- }
- }
- catch (WebException webex)
- {
- // TODO: probably need better work here to properly respond with all http status codes back to JS
- // Right now am jumping through hoops just to detect 404.
- if ((webex.Status == WebExceptionStatus.ProtocolError && ((HttpWebResponse)webex.Response).StatusCode == HttpStatusCode.NotFound)
- || webex.Status == WebExceptionStatus.UnknownError)
- {
- int statusCode = (int)((HttpWebResponse)webex.Response).StatusCode;
- FileTransferError ftError = new FileTransferError(ConnectionError, null, null, statusCode);
- DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, ftError), reqState.options.CallbackId);
- }
- else
- {
- DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR,
- new FileTransferError(ConnectionError)),
- reqState.options.CallbackId);
- }
- }
- catch (Exception /*ex*/)
- {
- FileTransferError transferError = new FileTransferError(ConnectionError, reqState.options.Server, reqState.options.FilePath, 403);
- DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, transferError), reqState.options.CallbackId);
- }
- }
-
- // Gets the full path without the filename
- private string getDirectoryName(String filePath)
- {
- string directoryName;
- try
- {
- directoryName = filePath.Substring(0, filePath.LastIndexOf('/'));
- }
- catch
- {
- directoryName = "";
- }
- return directoryName;
- }
- }
-}
diff --git a/tests/tests.js b/tests/tests.js
index c8d9ef3..63c9c1c 100644
--- a/tests/tests.js
+++ b/tests/tests.js
@@ -53,10 +53,9 @@
var SERVER_WITH_CREDENTIALS = "";
// flags
- var isWindows = cordova.platformId === "windows8" || cordova.platformId === "windows";
- var isWindowsPhone81 = isWindows && WinJS.Utilities.isPhone;
- var isWP8 = cordova.platformId === "windowsphone";
+ var isWindows = cordova.platformId === "windows";
var isBrowser = cordova.platformId === "browser";
+ var isWindowsPhone = isWindows && WinJS.Utilities.isPhone;
var isIE = isBrowser && navigator.userAgent.indexOf("Trident") >= 0;
var isIos = cordova.platformId === "ios";
var isIot = cordova.platformId === "android" && navigator.userAgent.indexOf("iot") >= 0;
@@ -177,10 +176,6 @@
);
};
- // according to documentation, wp8 does not support onProgress:
- // https://github.com/apache/cordova-plugin-file-transfer/blob/master/doc/index.md#supported-platforms
- var wp8OnProgressHandler = function () {};
-
var defaultOnProgressHandler = function (event) {
if (event.lengthComputable) {
expect(event.loaded).toBeGreaterThan(1);
@@ -199,7 +194,7 @@
};
var getMalformedUrl = function () {
- if (cordova.platformId === "android" || cordova.platformId === "amazon-fireos") {
+ if (cordova.platformId === "android") {
// bad protocol causes a MalformedUrlException on Android
return "httpssss://example.com";
} else {
@@ -330,7 +325,7 @@
this.transfer = new FileTransfer();
// assign onprogress handler
- this.transfer.onprogress = isWP8 ? wp8OnProgressHandler : defaultOnProgressHandler;
+ this.transfer.onprogress = defaultOnProgressHandler;
// spy on the onprogress handler, but still call through to it
spyOn(this.transfer, "onprogress").and.callThrough();
@@ -491,10 +486,7 @@
var fileURL = window.location.protocol + "//" + window.location.pathname.replace(/ /g, "%20");
var specContext = this;
- if (!/^file:/.exec(fileURL) && cordova.platformId !== "blackberry10") {
- if (cordova.platformId === "windowsphone") {
- expect(fileURL).toMatch(/^x-wmapp0:/);
- }
+ if (!/^file:/.exec(fileURL)) {
done();
return;
}
@@ -645,12 +637,7 @@
expect(error.http_status).not.toBe(401, "Ensure " + fileURL + " is in the white list");
expect(error.http_status).toBe(404);
- // wp8 does not make difference between 404 and unknown host
- if (isWP8) {
- expect(error.code).toBe(FileTransferError.CONNECTION_ERR);
- } else {
- expect(error.code).toBe(FileTransferError.FILE_NOT_FOUND_ERR);
- }
+ expect(error.code).toBe(FileTransferError.FILE_NOT_FOUND_ERR);
done();
};
@@ -738,13 +725,6 @@
});
it("filetransfer.spec.17 progress should work with gzip encoding", function (done) {
-
- // lengthComputable false on bb10 when downloading gzip
- if (cordova.platformId === "blackberry10") {
- pending();
- return;
- }
-
var fileURL = "http://www.apache.org/";
var specContext = this;
@@ -781,8 +761,6 @@
if (isWindows) {
expect(nativeURL.substring(0, 14)).toBe("ms-appdata:///");
- } else if (isWP8) {
- expect(nativeURL.substring(0, 1)).toBe("/");
} else {
expect(nativeURL.substring(0, 7)).toBe("file://");
}
@@ -834,11 +812,6 @@
});
it("filetransfer.spec.33 should properly handle 304", function (done) {
- if (isWP8) {
- pending();
- return;
- }
-
var downloadFail = function (error) {
expect(error.http_status).toBe(304);
expect(error.code).toBe(FileTransferError.NOT_MODIFIED_ERR);
@@ -854,11 +827,6 @@
}, DOWNLOAD_TIMEOUT);
it("filetransfer.spec.35 304 should not result in the deletion of a cached file", function (done) {
- if (isWP8) {
- pending();
- return;
- }
-
var specContext = this;
var fileOperationFail = function() {
@@ -1103,7 +1071,7 @@
// windows store and ios are too fast, win is called before we have a chance to abort
// so let's get them busy - while not providing an extra load to the slow Android emulators
- var arrayLength = ((isWindows && !isWindowsPhone81) || isIos) ? 3000000 : isIot ? 150000 : 200000;
+ var arrayLength = ((isWindows && !isWindowsPhone) || isIos) ? 3000000 : isIot ? 150000 : 200000;
writeFile(specContext.root, specContext.fileName, new Array(arrayLength).join("aborttest!"), fileWin, done);
}, UPLOAD_TIMEOUT);
diff --git a/www/blackberry10/.jshintrc b/www/blackberry10/.jshintrc
deleted file mode 100644
index 85ccb32..0000000
--- a/www/blackberry10/.jshintrc
+++ /dev/null
@@ -1,5 +0,0 @@
-{
- "globals": {
- "requestAnimationFrame": true
- }
-}
diff --git a/www/blackberry10/FileTransfer.js b/www/blackberry10/FileTransfer.js
deleted file mode 100644
index 76e1682..0000000
--- a/www/blackberry10/FileTransfer.js
+++ /dev/null
@@ -1,190 +0,0 @@
-/*
- *
- * 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.
- *
-*/
-
-var argscheck = require('cordova/argscheck'),
- FileTransferError = require('./FileTransferError'),
- xhrImpl = require('./BB10XHRImplementation');
-
-
-function getBasicAuthHeader(urlString) {
- var header = null;
-
- if (window.btoa) {
- // parse the url using the Location object
- var url = document.createElement('a');
- url.href = urlString;
-
- var credentials = null;
- var protocol = url.protocol + "//";
- var origin = protocol + url.host;
-
- // check whether there are the username:password credentials in the url
- if (url.href.indexOf(origin) !== 0) { // credentials found
- var atIndex = url.href.indexOf("@");
- credentials = url.href.substring(protocol.length, atIndex);
- }
-
- if (credentials) {
- var authHeader = "Authorization";
- var authHeaderValue = "Basic " + window.btoa(credentials);
-
- header = {
- name : authHeader,
- value : authHeaderValue
- };
- }
- }
-
- return header;
-}
-
-var idCounter = 0;
-
-/**
- * FileTransfer uploads a file to a remote server.
- * @constructor
- */
-var FileTransfer = function() {
- this._id = ++idCounter;
- this.onprogress = null; // optional callback
-};
-
-/**
-* Given an absolute file path, uploads a file on the device to a remote server
-* using a multipart HTTP request.
-* @param filePath {String} Full path of the file on the device
-* @param server {String} URL of the server to receive the file
-* @param successCallback (Function} Callback to be invoked when upload has completed
-* @param errorCallback {Function} Callback to be invoked upon error
-* @param options {FileUploadOptions} Optional parameters such as file name and mimetype
-* @param trustAllHosts {Boolean} Optional trust all hosts (e.g. for self-signed certs), defaults to false
-*/
-FileTransfer.prototype.upload = function(filePath, server, successCallback, errorCallback, options, trustAllHosts) {
- argscheck.checkArgs('ssFFO*', 'FileTransfer.upload', arguments);
- // check for options
- var fileKey = null;
- var fileName = null;
- var mimeType = null;
- var params = null;
- var chunkedMode = true;
- var headers = null;
- var httpMethod = null;
- var basicAuthHeader = getBasicAuthHeader(server);
- if (basicAuthHeader) {
- options = options || {};
- options.headers = options.headers || {};
- options.headers[basicAuthHeader.name] = basicAuthHeader.value;
- }
-
- if (options) {
- fileKey = options.fileKey;
- fileName = options.fileName;
- mimeType = options.mimeType;
- headers = options.headers;
- httpMethod = options.httpMethod || "POST";
- if (httpMethod.toUpperCase() == "PUT"){
- httpMethod = "PUT";
- } else {
- httpMethod = "POST";
- }
- if (options.chunkedMode !== null || typeof options.chunkedMode != "undefined") {
- chunkedMode = options.chunkedMode;
- }
- if (options.params) {
- params = options.params;
- }
- else {
- params = {};
- }
- }
-
- var fail = errorCallback && function(e) {
- var error = new FileTransferError(e.code, e.source, e.target, e.http_status, e.body);
- errorCallback(error);
- };
-
- var self = this;
- var win = function(result) {
- if (typeof result.lengthComputable != "undefined") {
- if (self.onprogress) {
- self.onprogress(result);
- }
- } else {
- if (successCallback) {
- successCallback(result);
- }
- }
- };
- xhrImpl.upload(win, fail, [filePath, server, fileKey, fileName, mimeType, params, trustAllHosts, chunkedMode, headers, this._id, httpMethod]);
-};
-
-/**
- * Downloads a file form a given URL and saves it to the specified directory.
- * @param source {String} URL of the server to receive the file
- * @param target {String} Full path of the file on the device
- * @param successCallback (Function} Callback to be invoked when upload has completed
- * @param errorCallback {Function} Callback to be invoked upon error
- * @param trustAllHosts {Boolean} Optional trust all hosts (e.g. for self-signed certs), defaults to false
- * @param options {FileDownloadOptions} Optional parameters such as headers
- */
-FileTransfer.prototype.download = function(source, target, successCallback, errorCallback, trustAllHosts, options) {
- argscheck.checkArgs('ssFF*', 'FileTransfer.download', arguments);
- var self = this;
-
- var basicAuthHeader = getBasicAuthHeader(source);
- if (basicAuthHeader) {
- options = options || {};
- options.headers = options.headers || {};
- options.headers[basicAuthHeader.name] = basicAuthHeader.value;
- }
-
- var headers = null;
- if (options) {
- headers = options.headers || null;
- }
-
- var win = function(result) {
- if (typeof result.lengthComputable != "undefined") {
- if (self.onprogress) {
- return self.onprogress(result);
- }
- } else if (successCallback) {
- successCallback(result);
- }
- };
-
- var fail = errorCallback && function(e) {
- var error = new FileTransferError(e.code, e.source, e.target, e.http_status, e.body);
- errorCallback(error);
- };
-
- xhrImpl.download(win, fail, [source, target, trustAllHosts, this._id, headers]);
-};
-
-/**
- * Aborts the ongoing file transfer on this object. The original error
- * callback for the file transfer will be called if necessary.
- */
-FileTransfer.prototype.abort = function() {
- xhrImpl.abort(null, null, [this._id]);
-};
-
-module.exports = FileTransfer;
diff --git a/www/blackberry10/FileTransferProxy.js b/www/blackberry10/FileTransferProxy.js
deleted file mode 100644
index a363f07..0000000
--- a/www/blackberry10/FileTransferProxy.js
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- *
- * 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.
- *
-*/
-
-/*
- * FileTransferProxy
- *
- * Register all FileTransfer exec calls to be handled by proxy
- */
-
-var xhrFileTransfer = require('cordova-plugin-file-transfer.xhrFileTransfer');
-
-module.exports = {
- abort: xhrFileTransfer.abort,
- download: xhrFileTransfer.download,
- upload: xhrFileTransfer.upload
-};
-
-require('cordova/exec/proxy').add('FileTransfer', module.exports);
diff --git a/www/blackberry10/xhrFileTransfer.js b/www/blackberry10/xhrFileTransfer.js
deleted file mode 100644
index 53d0d36..0000000
--- a/www/blackberry10/xhrFileTransfer.js
+++ /dev/null
@@ -1,260 +0,0 @@
-/*
- *
- * 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.
- *
-*/
-
-/* global Blob:false */
-
-var cordova = require('cordova'),
- resolve = cordova.require('cordova-plugin-file.resolveLocalFileSystemURIProxy'),
- requestAnimationFrame = cordova.require('cordova-plugin-file.bb10RequestAnimationFrame'),
- xhr = {};
-
-function getParentPath(filePath) {
- var pos = filePath.lastIndexOf('/');
- return filePath.substring(0, pos + 1);
-}
-
-function getFileName(filePath) {
- var pos = filePath.lastIndexOf('/');
- return filePath.substring(pos + 1);
-}
-
-function checkURL(url) {
- return url.indexOf(' ') === -1 ? true : false;
-}
-
-module.exports = {
- abort: function (win, fail, args) {
- var id = args[0];
- if (xhr[id]) {
- xhr[id].abort();
- if (typeof(win) === 'function') {
- win();
- }
- } else if (typeof(fail) === 'function') {
- fail();
- }
- },
-
- upload: function(win, fail, args) {
- var filePath = args[0],
- server = args[1],
- fileKey = args[2],
- fileName = args[3],
- mimeType = args[4],
- params = args[5],
- /*trustAllHosts = args[6],*/
- chunkedMode = args[7],
- headers = args[8],
- onSuccess = function (data) {
- if (typeof(win) === 'function') {
- win(data);
- }
- },
- onFail = function (code) {
- delete xhr[fileKey];
- if (typeof(fail) === 'function') {
- fail(code);
- }
- };
-
- if (!checkURL(server)) {
- onFail(new FileTransferError(FileTransferError.INVALID_URL_ERR, server, filePath));
- }
-
- xhr[fileKey] = new XMLHttpRequest();
- xhr[fileKey].onabort = function () {
- onFail(new FileTransferError(FileTransferError.ABORT_ERR, server, filePath, this.status, xhr[fileKey].response));
- };
-
- resolve(function(entry) {
- requestAnimationFrame(function () {
- entry.nativeEntry.file(function(file) {
- function uploadFile(blobFile) {
- var fd = new FormData();
-
- fd.append(fileKey, blobFile, fileName);
- for (var prop in params) {
- if(params.hasOwnProperty(prop)) {
- fd.append(prop, params[prop]);
- }
- }
-
- xhr[fileKey].open("POST", server);
- xhr[fileKey].onload = function(evt) {
- if (xhr[fileKey].status === 200) {
- var result = new FileUploadResult();
- result.bytesSent = file.size;
- result.responseCode = xhr[fileKey].status;
- result.response = xhr[fileKey].response;
- delete xhr[fileKey];
- onSuccess(result);
- } else if (xhr[fileKey].status === 404) {
- onFail(new FileTransferError(FileTransferError.INVALID_URL_ERR, server, filePath, xhr[fileKey].status, xhr[fileKey].response));
- } else {
- onFail(new FileTransferError(FileTransferError.CONNECTION_ERR, server, filePath, xhr[fileKey].status, xhr[fileKey].response));
- }
- };
- xhr[fileKey].ontimeout = function(evt) {
- onFail(new FileTransferError(FileTransferError.CONNECTION_ERR, server, filePath, xhr[fileKey].status, xhr[fileKey].response));
- };
- xhr[fileKey].onerror = function () {
- onFail(new FileTransferError(FileTransferError.CONNECTION_ERR, server, filePath, this.status, xhr[fileKey].response));
- };
- xhr[fileKey].upload.onprogress = function (evt) {
- if (evt.loaded > 0) {
- onSuccess(evt);
- }
- };
-
- for (var header in headers) {
- if (headers.hasOwnProperty(header)) {
- xhr[fileKey].setRequestHeader(header, headers[header]);
- }
- }
-
- requestAnimationFrame(function () {
- xhr[fileKey].send(fd);
- });
- }
-
- var bytesPerChunk;
- if (chunkedMode === true) {
- bytesPerChunk = 1024 * 1024; // 1MB chunk sizes.
- } else {
- bytesPerChunk = file.size;
- }
- var start = 0;
- var end = bytesPerChunk;
- while (start < file.size) {
- var chunk = file.slice(start, end, mimeType);
- uploadFile(chunk);
- start = end;
- end = start + bytesPerChunk;
- }
- }, function(error) {
- onFail(new FileTransferError(FileTransferError.FILE_NOT_FOUND_ERR, server, filePath));
- });
- });
- }, function(error) {
- onFail(new FileTransferError(FileTransferError.FILE_NOT_FOUND_ERR, server, filePath));
- }, [filePath]);
- },
-
- download: function (win, fail, args) {
- var source = args[0],
- target = args[1],
- id = args[3],
- headers = args[4],
- fileWriter,
- onSuccess = function (entry) {
- if (typeof(win) === 'function') {
- win(entry);
- }
- },
- onFail = function (error) {
- var reader;
- delete xhr[id];
- if (typeof(fail) === 'function') {
- if (error && error.body && typeof(error.body) === 'object') {
- reader = new FileReader()._realReader;
- reader.onloadend = function () {
- error.body = this.result;
- fail(error);
- };
- reader.onerror = function () {
- fail(error);
- };
- reader.readAsText(error.body);
- } else {
- fail(error);
- }
- }
- };
-
- if (!checkURL(source)) {
- onFail(new FileTransferError(FileTransferError.INVALID_URL_ERR, source, target));
- }
-
- xhr[id] = new XMLHttpRequest();
-
- function writeFile(entry) {
- entry.createWriter(function (writer) {
- fileWriter = writer;
- fileWriter.onwriteend = function (evt) {
- if (!evt.target.error) {
- entry.filesystemName = entry.filesystem.name;
- delete xhr[id];
- onSuccess(entry);
- } else {
- onFail(evt.target.error);
- }
- };
- fileWriter.onerror = function (evt) {
- onFail(evt.target.error);
- };
- fileWriter.write(new Blob([xhr[id].response]));
- }, function (error) {
- onFail(error);
- });
- }
-
- xhr[id].onerror = function (e) {
- onFail(new FileTransferError(FileTransferError.CONNECTION_ERR, source, target, xhr[id].status, xhr[id].response));
- };
-
- xhr[id].onabort = function (e) {
- onFail(new FileTransferError(FileTransferError.ABORT_ERR, source, target, xhr[id].status, xhr[id].response));
- };
-
- xhr[id].onload = function () {
- if (xhr[id].readyState === xhr[id].DONE) {
- if (xhr[id].status === 200 && xhr[id].response) {
- resolveLocalFileSystemURI(getParentPath(target), function (dir) {
- dir.getFile(getFileName(target), {create: true}, writeFile, function (error) {
- onFail(new FileTransferError(FileTransferError.FILE_NOT_FOUND_ERR, source, target, xhr[id].status, xhr[id].response));
- });
- }, function (error) {
- onFail(new FileTransferError(FileTransferError.FILE_NOT_FOUND_ERR, source, target, xhr[id].status, xhr[id].response));
- });
- } else if (xhr[id].status === 404) {
- onFail(new FileTransferError(FileTransferError.INVALID_URL_ERR, source, target, xhr[id].status, xhr[id].response));
- } else {
- onFail(new FileTransferError(FileTransferError.CONNECTION_ERR, source, target, xhr[id].status, xhr[id].response));
- }
- }
- };
- xhr[id].onprogress = function (evt) {
- onSuccess(evt);
- };
- xhr[id].open("GET", source, true);
- for (var header in headers) {
- if (headers.hasOwnProperty(header)) {
- xhr[id].setRequestHeader(header, headers[header]);
- }
- }
- xhr[id].responseType = "blob";
- requestAnimationFrame(function () {
- if (xhr[id]) {
- xhr[id].send();
- }
- });
- }
-};
diff --git a/www/firefoxos/FileTransferProxy.js b/www/firefoxos/FileTransferProxy.js
deleted file mode 100644
index 86c46be..0000000
--- a/www/firefoxos/FileTransferProxy.js
+++ /dev/null
@@ -1,222 +0,0 @@
-/*
- *
- * 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.
- *
-*/
-
-var FileTransferError = require('./FileTransferError'),
- xhr = {};
-
-function getParentPath(filePath) {
- var pos = filePath.lastIndexOf('/');
- return filePath.substring(0, pos + 1);
-}
-
-function getFileName(filePath) {
- var pos = filePath.lastIndexOf('/');
- return filePath.substring(pos + 1);
-}
-
-module.exports = {
- abort: function (successCallback, errorCallback, args) {
- var id = args[0];
- if (xhr[id]) {
- xhr[id].abort();
- if (typeof(successCallback) === 'function') {
- successCallback();
- }
- } else if (typeof(errorCallback) === 'function') {
- errorCallback();
- }
- },
-
- upload: function(successCallback, errorCallback, args) {
- var filePath = args[0],
- server = args[1],
- fileKey = args[2],
- fileName = args[3],
- mimeType = args[4],
- params = args[5],
- /*trustAllHosts = args[6],*/
- /*chunkedMode = args[7],*/
- headers = args[8];
-
- xhr[fileKey] = new XMLHttpRequest({mozSystem: true});
- xhr[fileKey].onabort = function() {
- onFail(new FileTransferError(FileTransferError.ABORT_ERR, server, filePath, this.status, xhr[fileKey].response));
- };
-
- window.resolveLocalFileSystemURL(filePath, function(entry) {
- entry.file(function(file) {
- var reader = new FileReader();
-
- reader.onloadend = function() {
- var blob = new Blob([this.result], {type: mimeType});
- var fd = new FormData();
-
- fd.append(fileKey, blob, fileName);
-
- for (var prop in params) {
- if (params.hasOwnProperty(prop)) {
- fd.append(prop, params[prop]);
- }
- }
-
- xhr[fileKey].open("POST", server);
-
- xhr[fileKey].onload = function(evt) {
- if (xhr[fileKey].status === 200) {
- var result = new FileUploadResult();
- result.bytesSent = blob.size;
- result.responseCode = xhr[fileKey].status;
- result.response = xhr[fileKey].response;
- delete xhr[fileKey];
- onSuccess(result);
- } else if (xhr[fileKey].status === 404) {
- onFail(new FileTransferError(FileTransferError.INVALID_URL_ERR, server, filePath, xhr[fileKey].status, xhr[fileKey].response));
- } else {
- onFail(new FileTransferError(FileTransferError.CONNECTION_ERR, server, filePath, xhr[fileKey].status, xhr[fileKey].response));
- }
- };
-
- xhr[fileKey].ontimeout = function() {
- onFail(new FileTransferError(FileTransferError.CONNECTION_ERR, server, filePath, xhr[fileKey].status, xhr[fileKey].response));
- };
-
- xhr[fileKey].onerror = function() {
- onFail(new FileTransferError(FileTransferError.CONNECTION_ERR, server, filePath, this.status, xhr[fileKey].response));
- };
-
- for (var header in headers) {
- if (headers.hasOwnProperty(header)) {
- xhr[fileKey].setRequestHeader(header, headers[header]);
- }
- }
-
- xhr[fileKey].send(fd);
- };
-
- reader.readAsArrayBuffer(file);
-
- }, function() {
- onFail(new FileTransferError(FileTransferError.FILE_NOT_FOUND_ERR, server, filePath));
- });
- }, function() {
- onFail(new FileTransferError(FileTransferError.FILE_NOT_FOUND_ERR, server, filePath));
- });
-
- function onSuccess(data) {
- if (typeof(successCallback) === 'function') {
- successCallback(data);
- }
- }
-
- function onFail(code) {
- delete xhr[fileKey];
- if (typeof(errorCallback) === 'function') {
- errorCallback(code);
- }
- }
- },
-
- download: function (successCallback, errorCallback, args) {
- var source = args[0],
- target = args[1],
- id = args[3],
- headers = args[4];
-
- xhr[id] = new XMLHttpRequest({mozSystem: true});
-
- xhr[id].onload = function () {
- if (xhr[id].readyState === xhr[id].DONE) {
- if (xhr[id].status === 200 && xhr[id].response) {
- window.resolveLocalFileSystemURL(getParentPath(target), function (dir) {
- dir.getFile(getFileName(target), {create: true}, writeFile, function (error) {
- onFail(new FileTransferError(FileTransferError.FILE_NOT_FOUND_ERR, source, target, xhr[id].status, xhr[id].response));
- });
- }, function () {
- onFail(new FileTransferError(FileTransferError.FILE_NOT_FOUND_ERR, source, target, xhr[id].status, xhr[id].response));
- });
- } else if (xhr[id].status === 404) {
- onFail(new FileTransferError(FileTransferError.INVALID_URL_ERR, source, target, xhr[id].status, xhr[id].response));
- } else {
- onFail(new FileTransferError(FileTransferError.CONNECTION_ERR, source, target, xhr[id].status, xhr[id].response));
- }
- }
- };
-
- function writeFile(entry) {
- entry.createWriter(function (fileWriter) {
- fileWriter.onwriteend = function (evt) {
- if (!evt.target.error) {
- entry.filesystemName = entry.filesystem.name;
- delete xhr[id];
- onSuccess(entry);
- } else {
- onFail(evt.target.error);
- }
- };
- fileWriter.onerror = function (evt) {
- onFail(evt.target.error);
- };
- fileWriter.write(new Blob([xhr[id].response]));
- }, function (error) {
- onFail(error);
- });
- }
-
- xhr[id].onerror = function (e) {
- onFail(new FileTransferError(FileTransferError.CONNECTION_ERR, source, target, xhr[id].status, xhr[id].response));
- };
-
- xhr[id].onabort = function (e) {
- onFail(new FileTransferError(FileTransferError.ABORT_ERR, source, target, xhr[id].status, xhr[id].response));
- };
-
- xhr[id].open("GET", source, true);
-
- for (var header in headers) {
- if (headers.hasOwnProperty(header)) {
- xhr[id].setRequestHeader(header, headers[header]);
- }
- }
-
- xhr[id].responseType = "blob";
-
- setTimeout(function () {
- if (xhr[id]) {
- xhr[id].send();
- }
- }, 0);
-
- function onSuccess(entry) {
- if (typeof(successCallback) === 'function') {
- successCallback(entry);
- }
- }
-
- function onFail(error) {
- delete xhr[id];
- if (typeof(errorCallback) === 'function') {
- errorCallback(error);
- }
- }
- }
-};
-
-require('cordova/exec/proxy').add('FileTransfer', module.exports);
diff --git a/www/wp7/base64.js b/www/wp7/base64.js
deleted file mode 100644
index 221e30a..0000000
--- a/www/wp7/base64.js
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- *
- * 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.
- *
-*/
-
-// jshint ignore: start
-
-var chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=',
- INVALID_CHARACTER_ERR = (function () {
- // fabricate a suitable error object
- try { document.createElement('$'); }
- catch (error) { return error; }
- }());
-
- // encoder
- // [https://gist.github.com/999166] by [https://github.com/nignag]
- window.btoa || (
- window.btoa = function (input) {
- for (
- // initialize result and counter
- var block, charCode, idx = 0, map = chars, output = '';
- // if the next input index does not exist:
- // change the mapping table to "="
- // check if d has no fractional digits
- input.charAt(idx | 0) || (map = '=', idx % 1) ;
- // "8 - idx % 1 * 8" generates the sequence 2, 4, 6, 8
- output += map.charAt(63 & block >> 8 - idx % 1 * 8)
- ) {
- charCode = input.charCodeAt(idx += 3 / 4);
- if (charCode > 0xFF) throw INVALID_CHARACTER_ERR;
- block = block << 8 | charCode;
- }
- return output;
- });
-
- // decoder
- // [https://gist.github.com/1020396] by [https://github.com/atk]
- window.atob || (
- window.atob = function (input) {
- input = input.replace(/=+$/, '')
- if (input.length % 4 == 1) throw INVALID_CHARACTER_ERR;
- for (
- // initialize result and counters
- var bc = 0, bs, buffer, idx = 0, output = '';
- // get next character
- buffer = input.charAt(idx++) ;
- // character found in table? initialize bit storage and add its ascii value;
- ~buffer && (bs = bc % 4 ? bs * 64 + buffer : buffer,
- // and if not first of each 4 characters,
- // convert the first 8 bits to one ascii character
- bc++ % 4) ? output += String.fromCharCode(255 & bs >> (-2 * bc & 6)) : 0
- ) {
- // try to find character in table (0-63, not found => -1)
- buffer = chars.indexOf(buffer);
- }
- return output;
- });
\ No newline at end of file