You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cordova.apache.org by da...@apache.org on 2015/11/25 18:01:54 UTC
cordova-plugin-file-transfer git commit: CB-9563 Mulptipart form data
is used even a header named Content-Type is present
Repository: cordova-plugin-file-transfer
Updated Branches:
refs/heads/master 9e93bad83 -> 007f98692
CB-9563 Mulptipart form data is used even a header named Content-Type is present
Adds non-multipart implementation for Windows and a corresponding test
Adds a fix for Android for uploadResult.bytesSent = 0 for small files
Fixes parameters of FILE_NOT_FOUND_ERR case in upload operation on Windows - passing source file name instead of duplicated server/destination argument
github: close #117
Project: http://git-wip-us.apache.org/repos/asf/cordova-plugin-file-transfer/repo
Commit: http://git-wip-us.apache.org/repos/asf/cordova-plugin-file-transfer/commit/007f9869
Tree: http://git-wip-us.apache.org/repos/asf/cordova-plugin-file-transfer/tree/007f9869
Diff: http://git-wip-us.apache.org/repos/asf/cordova-plugin-file-transfer/diff/007f9869
Branch: refs/heads/master
Commit: 007f98692b15f5a6c4902abf393bee8dc5edeced
Parents: 9e93bad
Author: daserge <v-...@microsoft.com>
Authored: Tue Nov 24 01:20:00 2015 +0300
Committer: daserge <v-...@microsoft.com>
Committed: Wed Nov 25 19:57:48 2015 +0300
----------------------------------------------------------------------
src/android/FileTransfer.java | 59 +++++-----
src/windows/FileTransferProxy.js | 215 ++++++++++++++++++----------------
tests/tests.js | 40 +++++--
3 files changed, 175 insertions(+), 139 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/cordova-plugin-file-transfer/blob/007f9869/src/android/FileTransfer.java
----------------------------------------------------------------------
diff --git a/src/android/FileTransfer.java b/src/android/FileTransfer.java
index 0efbd4e..b9b99dc 100644
--- a/src/android/FileTransfer.java
+++ b/src/android/FileTransfer.java
@@ -291,7 +291,7 @@ public class FileTransfer extends CordovaPlugin {
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);
@@ -303,7 +303,7 @@ public class FileTransfer extends CordovaPlugin {
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);
@@ -323,7 +323,7 @@ public class FileTransfer extends CordovaPlugin {
synchronized (activeRequests) {
activeRequests.put(objectId, context);
}
-
+
cordova.getThreadPool().execute(new Runnable() {
public void run() {
if (context.aborted) {
@@ -363,13 +363,13 @@ public class FileTransfer extends CordovaPlugin {
// 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 = getCookies(target);
@@ -410,10 +410,10 @@ public class FileTransfer extends CordovaPlugin {
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;
@@ -439,7 +439,7 @@ public class FileTransfer extends CordovaPlugin {
}
conn.connect();
-
+
OutputStream sendStream = null;
try {
sendStream = conn.getOutputStream();
@@ -449,26 +449,26 @@ public class FileTransfer extends CordovaPlugin {
}
context.connection = conn;
}
-
+
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) {
+ totalBytes += bytesRead;
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");
@@ -483,7 +483,7 @@ public class FileTransfer extends CordovaPlugin {
progressResult.setKeepCallback(true);
context.sendPluginResult(progressResult);
}
-
+
if (multipartFormUpload) {
// send multipart form data necessary after file data...
sendStream.write(tailParamsBytes);
@@ -513,7 +513,7 @@ public class FileTransfer extends CordovaPlugin {
}
context.connection = conn;
}
-
+
ByteArrayOutputStream out = new ByteArrayOutputStream(Math.max(1024, conn.getContentLength()));
byte[] buffer = new byte[1024];
int bytesRead = 0;
@@ -528,10 +528,10 @@ public class FileTransfer extends CordovaPlugin {
}
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);
@@ -568,7 +568,7 @@ public class FileTransfer extends CordovaPlugin {
https.setSSLSocketFactory(oldSocketFactory);
}
}
- }
+ }
}
});
}
@@ -601,11 +601,11 @@ public class FileTransfer extends CordovaPlugin {
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 {
}
@@ -735,7 +735,7 @@ public class FileTransfer extends CordovaPlugin {
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);
@@ -790,12 +790,12 @@ public class FileTransfer extends CordovaPlugin {
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) {
@@ -815,7 +815,7 @@ public class FileTransfer extends CordovaPlugin {
file = resourceApi.mapUriToFile(targetUri);
context.targetFile = file;
-
+
Log.d(LOG_TAG, "Download file:" + sourceUri);
FileProgressResult progress = new FileProgressResult();
@@ -840,9 +840,9 @@ public class FileTransfer extends CordovaPlugin {
// Setup the connection not to verify hostnames
https.setHostnameVerifier(DO_NOT_VERIFY);
}
-
+
connection.setRequestMethod("GET");
-
+
// TODO: Make OkHttp use this CookieManager by default.
String cookie = getCookies(sourceUri.toString());
@@ -850,15 +850,15 @@ public class FileTransfer extends CordovaPlugin {
{
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.getResponseCode() == HttpURLConnection.HTTP_NOT_MODIFIED) {
cached = true;
@@ -946,7 +946,6 @@ public class FileTransfer extends CordovaPlugin {
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, e);
Log.e(LOG_TAG, error.toString(), e);
http://git-wip-us.apache.org/repos/asf/cordova-plugin-file-transfer/blob/007f9869/src/windows/FileTransferProxy.js
----------------------------------------------------------------------
diff --git a/src/windows/FileTransferProxy.js b/src/windows/FileTransferProxy.js
index d9e884e..635f3d6 100644
--- a/src/windows/FileTransferProxy.js
+++ b/src/windows/FileTransferProxy.js
@@ -81,6 +81,8 @@ exec(win, fail, 'FileTransfer', 'upload',
var uploadId = options[9];
var httpMethod = options[10];
+ var isMultipart = typeof headers["Content-Type"] === 'undefined';
+
if (!filePath || (typeof filePath !== 'string')) {
errorCallback(new FTErr(FTErr.FILE_NOT_FOUND_ERR,null,server));
return;
@@ -131,120 +133,129 @@ exec(win, fail, 'FileTransfer', 'upload',
}
}
- // adding params supplied to request payload
- var transferParts = [];
- for (var key in params) {
- if (params.hasOwnProperty(key)) {
- var contentPart = new Windows.Networking.BackgroundTransfer.BackgroundTransferContentPart();
- contentPart.setHeader("Content-Disposition", "form-data; name=\"" + key + "\"");
- contentPart.setText(params[key]);
- transferParts.push(contentPart);
- }
- }
-
- // Adding file to upload to request payload
- var fileToUploadPart = new Windows.Networking.BackgroundTransfer.BackgroundTransferContentPart(fileKey, fileName);
- fileToUploadPart.setFile(storageFile);
- transferParts.push(fileToUploadPart);
-
// create download object. This will throw an exception if URL is malformed
var uri = new Windows.Foundation.Uri(server);
+
+ var createUploadOperation;
try {
- uploader.createUploadAsync(uri, transferParts).then(
- function (upload) {
- // update internal TransferOperation object with newly created promise
- var uploadOperation = upload.startAsync();
- fileTransferOps[uploadId].promise = uploadOperation;
-
- uploadOperation.then(
- function (result) {
- // Update TransferOperation object with new state, delete promise property
- // since it is not actual anymore
- var currentUploadOp = fileTransferOps[uploadId];
- if (currentUploadOp) {
- currentUploadOp.state = FileTransferOperation.DONE;
- currentUploadOp.promise = null;
- }
+ if (isMultipart) {
+ // adding params supplied to request payload
+ var transferParts = [];
+ for (var key in params) {
+ if (params.hasOwnProperty(key)) {
+ var contentPart = new Windows.Networking.BackgroundTransfer.BackgroundTransferContentPart();
+ contentPart.setHeader("Content-Disposition", "form-data; name=\"" + key + "\"");
+ contentPart.setText(params[key]);
+ transferParts.push(contentPart);
+ }
+ }
- var response = result.getResponseInformation();
- var ftResult = new FileUploadResult(result.progress.bytesSent, response.statusCode, '');
+ // Adding file to upload to request payload
+ var fileToUploadPart = new Windows.Networking.BackgroundTransfer.BackgroundTransferContentPart(fileKey, fileName);
+ fileToUploadPart.setFile(storageFile);
+ transferParts.push(fileToUploadPart);
- // if server's response doesn't contain any data, then resolve operation now
- if (result.progress.bytesReceived === 0) {
- successCallback(ftResult);
- return;
- }
+ createUploadOperation = uploader.createUploadAsync(uri, transferParts);
+ } else {
+ createUploadOperation = WinJS.Promise.wrap(uploader.createUpload(uri, storageFile));
+ }
+ } catch (e) {
+ errorCallback(new FTErr(FTErr.INVALID_URL_ERR));
+ return;
+ }
- // otherwise create a data reader, attached to response stream to get server's response
- var reader = new Windows.Storage.Streams.DataReader(result.getResultStreamAt(0));
- reader.loadAsync(result.progress.bytesReceived).then(function (size) {
- ftResult.response = reader.readString(size);
- successCallback(ftResult);
- reader.close();
- });
- },
- function (error) {
- var source = nativePathToCordova(filePath);
-
- // Handle download error here.
- // Wrap this routines into promise due to some async methods
- var getTransferError = new WinJS.Promise(function(resolve) {
- if (error.message === 'Canceled') {
- // If download was cancelled, message property will be specified
- resolve(new FTErr(FTErr.ABORT_ERR, source, server, null, null, error));
+ createUploadOperation.then(
+ function (upload) {
+ // update internal TransferOperation object with newly created promise
+ var uploadOperation = upload.startAsync();
+ fileTransferOps[uploadId].promise = uploadOperation;
+
+ uploadOperation.then(
+ function (result) {
+ // Update TransferOperation object with new state, delete promise property
+ // since it is not actual anymore
+ var currentUploadOp = fileTransferOps[uploadId];
+ if (currentUploadOp) {
+ currentUploadOp.state = FileTransferOperation.DONE;
+ currentUploadOp.promise = null;
+ }
+
+ var response = result.getResponseInformation();
+ var ftResult = new FileUploadResult(result.progress.bytesSent, response.statusCode, '');
+
+ // if server's response doesn't contain any data, then resolve operation now
+ if (result.progress.bytesReceived === 0) {
+ successCallback(ftResult);
+ return;
+ }
+
+ // otherwise create a data reader, attached to response stream to get server's response
+ var reader = new Windows.Storage.Streams.DataReader(result.getResultStreamAt(0));
+ reader.loadAsync(result.progress.bytesReceived).then(function (size) {
+ ftResult.response = reader.readString(size);
+ successCallback(ftResult);
+ reader.close();
+ });
+ },
+ function (error) {
+ var source = nativePathToCordova(filePath);
+
+ // Handle download error here.
+ // Wrap this routines into promise due to some async methods
+ var getTransferError = new WinJS.Promise(function(resolve) {
+ if (error.message === 'Canceled') {
+ // If download was cancelled, message property will be specified
+ resolve(new FTErr(FTErr.ABORT_ERR, source, server, null, null, error));
+ } else {
+ // in the other way, try to get response property
+ var response = upload.getResponseInformation();
+ if (!response) {
+ resolve(new FTErr(FTErr.CONNECTION_ERR, source, server));
} else {
- // in the other way, try to get response property
- var response = upload.getResponseInformation();
- if (!response) {
- resolve(new FTErr(FTErr.CONNECTION_ERR, source, server));
- } else {
- var reader = new Windows.Storage.Streams.DataReader(upload.getResultStreamAt(0));
- reader.loadAsync(upload.progress.bytesReceived).then(function (size) {
- var responseText = reader.readString(size);
- resolve(new FTErr(FTErr.FILE_NOT_FOUND_ERR, source, server, response.statusCode, responseText, error));
- reader.close();
- });
- }
+ var reader = new Windows.Storage.Streams.DataReader(upload.getResultStreamAt(0));
+ reader.loadAsync(upload.progress.bytesReceived).then(function (size) {
+ var responseText = reader.readString(size);
+ resolve(new FTErr(FTErr.FILE_NOT_FOUND_ERR, source, server, response.statusCode, responseText, error));
+ reader.close();
+ });
}
- });
-
- // Update TransferOperation object with new state, delete promise property
- // since it is not actual anymore
- var currentUploadOp = fileTransferOps[uploadId];
- if (currentUploadOp) {
- currentUploadOp.state = FileTransferOperation.CANCELLED;
- currentUploadOp.promise = null;
}
+ });
+
+ // Update TransferOperation object with new state, delete promise property
+ // since it is not actual anymore
+ var currentUploadOp = fileTransferOps[uploadId];
+ if (currentUploadOp) {
+ currentUploadOp.state = FileTransferOperation.CANCELLED;
+ currentUploadOp.promise = null;
+ }
- // Cleanup, remove incompleted file
- getTransferError.then(function(transferError) {
- storageFile.deleteAsync().then(function() {
- errorCallback(transferError);
- });
+ // Cleanup, remove incompleted file
+ getTransferError.then(function(transferError) {
+ storageFile.deleteAsync().then(function() {
+ errorCallback(transferError);
});
- },
- function (evt) {
- var progressEvent = new ProgressEvent('progress', {
- loaded: evt.progress.bytesSent,
- total: evt.progress.totalBytesToSend,
- target: evt.resultFile
- });
- progressEvent.lengthComputable = true;
- successCallback(progressEvent, { keepCallback: true });
- }
- );
- },
- function (err) {
- var errorObj = new FTErr(FTErr.INVALID_URL_ERR);
- errorObj.exception = err;
- errorCallback(errorObj);
- }
- );
- } catch (e) {
- errorCallback(new FTErr(FTErr.INVALID_URL_ERR));
- }
+ });
+ },
+ function (evt) {
+ var progressEvent = new ProgressEvent('progress', {
+ loaded: evt.progress.bytesSent,
+ total: evt.progress.totalBytesToSend,
+ target: evt.resultFile
+ });
+ progressEvent.lengthComputable = true;
+ successCallback(progressEvent, { keepCallback: true });
+ }
+ );
+ },
+ function (err) {
+ var errorObj = new FTErr(FTErr.INVALID_URL_ERR);
+ errorObj.exception = err;
+ errorCallback(errorObj);
+ }
+ );
}, function(err) {
- errorCallback(new FTErr(FTErr.FILE_NOT_FOUND_ERR, server, server, null, null, err));
+ errorCallback(new FTErr(FTErr.FILE_NOT_FOUND_ERR, fileName, server, null, null, err));
});
},
http://git-wip-us.apache.org/repos/asf/cordova-plugin-file-transfer/blob/007f9869/tests/tests.js
----------------------------------------------------------------------
diff --git a/tests/tests.js b/tests/tests.js
index fff1eef..48361c5 100644
--- a/tests/tests.js
+++ b/tests/tests.js
@@ -936,15 +936,41 @@ exports.defineAutoTests = function () {
done();
};
- var uploadOptionsPut = new FileUploadOptions();
- uploadOptionsPut.fileKey = "file";
- uploadOptionsPut.fileName = fileName;
- uploadOptionsPut.mimeType = "text/plain";
- uploadOptionsPut.params = uploadParams;
- uploadOptionsPut.httpMethod = "PUT";
+ uploadOptions.httpMethod = "PUT";
// NOTE: removing uploadOptions cause Android to timeout
- transfer.upload(localFilePath, fileURL, uploadWin, unexpectedCallbacks.httpFail, uploadOptionsPut);
+ transfer.upload(localFilePath, fileURL, uploadWin, unexpectedCallbacks.httpFail, uploadOptions);
+ }, UPLOAD_TIMEOUT);
+
+ it("filetransfer.spec.32 should be able to upload a file (non-multipart)", function (done) {
+
+ var fileURL = SERVER + '/upload';
+
+ var uploadWin = function (uploadResult) {
+
+ expect(uploadResult.bytesSent).toBeGreaterThan(0);
+ expect(uploadResult.responseCode).toBe(200);
+ expect(uploadResult.response).toBeDefined();
+ if (uploadResult.response) {
+ expect(uploadResult.response).toEqual(fileContents + "\n");
+ }
+ expect(transfer.onprogress).toHaveBeenCalled();
+
+ if (cordova.platformId === 'ios') {
+ expect(uploadResult.headers).toBeDefined('Expected headers to be defined.');
+ expect(uploadResult.headers['Content-Type']).toBeDefined('Expected content-type header to be defined.');
+ }
+
+ done();
+ };
+
+ // Content-Type header disables multipart
+ uploadOptions.headers = {
+ "Content-Type": "text/plain"
+ };
+
+ // NOTE: removing uploadOptions cause Android to timeout
+ transfer.upload(localFilePath, fileURL, uploadWin, unexpectedCallbacks.httpFail, uploadOptions);
}, UPLOAD_TIMEOUT);
});
});
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@cordova.apache.org
For additional commands, e-mail: commits-help@cordova.apache.org