refactor(eslint): use cordova-eslint /w fix (#275)
diff --git a/.eslintrc.yml b/.eslintrc.yml
new file mode 100644
index 0000000..17277f7
--- /dev/null
+++ b/.eslintrc.yml
@@ -0,0 +1,23 @@
+# 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.
+
+root: true
+extends: '@cordova/eslint-config/browser'
+
+overrides:
+ - files: [tests/**/*.js]
+ extends: '@cordova/eslint-config/node-tests'
diff --git a/.jscsrc b/.jscsrc
deleted file mode 100644
index 2656b94..0000000
--- a/.jscsrc
+++ /dev/null
@@ -1,23 +0,0 @@
-{
- "disallowMixedSpacesAndTabs": true,
- "disallowTrailingWhitespace": true,
- "validateIndentation": 4,
- "requireLineFeedAtFileEnd": true,
-
- "disallowSpaceAfterPrefixUnaryOperators": true,
- "disallowSpaceBeforePostfixUnaryOperators": true,
- "requireSpaceAfterLineComment": true,
- "requireCapitalizedConstructors": true,
-
- "disallowSpacesInNamedFunctionExpression": {
- "beforeOpeningRoundBrace": true
- },
-
- "requireSpaceAfterKeywords": [
- "if",
- "else",
- "for",
- "while",
- "do"
- ]
-}
diff --git a/.jshintrc b/.jshintrc
deleted file mode 100644
index 93c3c13..0000000
--- a/.jshintrc
+++ /dev/null
@@ -1,19 +0,0 @@
-{
- "browser": true
- , "devel": true
- , "bitwise": true
- , "undef": true
- , "trailing": true
- , "quotmark": false
- , "indent": 4
- , "unused": "vars"
- , "latedef": "nofunc"
- , "globals": {
- "module": false,
- "exports": false,
- "require": false,
- "FileTransferError": true,
- "FileUploadResult": true,
- "resolveLocalFileSystemURI": false
- }
-}
diff --git a/package.json b/package.json
index 3766722..871efef 100644
--- a/package.json
+++ b/package.json
@@ -13,9 +13,8 @@
]
},
"scripts": {
- "test": "npm run lint && npm run style",
- "lint": "jshint www && jshint src && jshint tests",
- "style": "jscs tests/tests.js"
+ "test": "npm run lint",
+ "lint": "eslint ."
},
"repository": "github:apache/cordova-plugin-file-transfer",
"bugs": "https://github.com/apache/cordova-plugin-file-transfer/issues",
@@ -39,7 +38,6 @@
}
},
"devDependencies": {
- "jscs": "^2.6.0",
- "jshint": "^2.8.0"
+ "@cordova/eslint-config": "^3.0.0"
}
}
diff --git a/src/windows/FileTransferProxy.js b/src/windows/FileTransferProxy.js
index 01e6e7b..316779f 100644
--- a/src/windows/FileTransferProxy.js
+++ b/src/windows/FileTransferProxy.js
@@ -17,28 +17,25 @@
* specific language governing permissions and limitations
* under the License.
*
-*/
+ */
-/*jshint -W030 */
-/*global Windows, WinJS*/
-/*global module, require*/
+/* global Windows, WinJS */
-var FTErr = require('./FileTransferError'),
- ProgressEvent = require('cordova-plugin-file.ProgressEvent'),
- FileUploadResult = require('cordova-plugin-file.FileUploadResult'),
- FileProxy = require('cordova-plugin-file.FileProxy');
+var FTErr = require('./FileTransferError');
+var ProgressEvent = require('cordova-plugin-file.ProgressEvent');
+var FileUploadResult = require('cordova-plugin-file.FileUploadResult');
+var FileProxy = require('cordova-plugin-file.FileProxy');
var appData = Windows.Storage.ApplicationData.current;
-var LINE_START = "--";
-var LINE_END = "\r\n";
+var LINE_START = '--';
+var LINE_END = '\r\n';
var BOUNDARY = '+++++';
var fileTransferOps = [];
// Some private helper functions, hidden by the module
-function cordovaPathToNative(path) {
-
+function cordovaPathToNative (path) {
var cleanPath = String(path);
// turn / into \\
cleanPath = cleanPath.replace(/\//g, '\\');
@@ -49,11 +46,11 @@
return cleanPath;
}
-function nativePathToCordova(path) {
+function nativePathToCordova (path) {
return String(path).replace(/\\/g, '/');
}
-function alreadyCancelled(opId) {
+function alreadyCancelled (opId) {
var op = fileTransferOps[opId];
return op && op.state === FileTransferOperation.CANCELLED;
}
@@ -145,7 +142,7 @@
);
}
-function FileTransferOperation(state, promise) {
+function FileTransferOperation (state, promise) {
this.state = state;
this.promise = promise;
}
@@ -157,9 +154,8 @@
var HTTP_E_STATUS_NOT_MODIFIED = -2145844944;
module.exports = {
-
-/*
-exec(win, fail, 'FileTransfer', 'upload',
+ /*
+exec(win, fail, 'FileTransfer', 'upload',
[filePath, server, fileKey, fileName, mimeType, params, trustAllHosts, chunkedMode, headers, this._id, httpMethod]);
*/
upload: function (successCallback, errorCallback, options) {
@@ -170,14 +166,14 @@
var mimeType = options[4];
var params = options[5];
// var trustAllHosts = options[6]; // todo
- // var chunkedMode = options[7]; // todo
+ // var chunkedMode = options[7]; // todo
var headers = options[8] || {};
var uploadId = options[9];
var httpMethod = options[10];
- var isMultipart = typeof headers["Content-Type"] === 'undefined';
+ var isMultipart = typeof headers['Content-Type'] === 'undefined';
- function stringToByteArray(str) {
+ function stringToByteArray (str) {
var byteCharacters = atob(str);
var byteNumbers = new Array(byteCharacters.length);
for (var i = 0; i < byteCharacters.length; i++) {
@@ -186,21 +182,21 @@
return new Uint8Array(byteNumbers);
}
- if (!filePath || (typeof filePath !== 'string')) {
+ if (!filePath || typeof filePath !== 'string') {
errorCallback(new FTErr(FTErr.FILE_NOT_FOUND_ERR, null, server));
return;
}
- if (filePath.indexOf("data:") === 0 && filePath.indexOf("base64") !== -1) {
- // First a DataWriter object is created, backed by an in-memory stream where
+ if (filePath.indexOf('data:') === 0 && filePath.indexOf('base64') !== -1) {
+ // First a DataWriter object is created, backed by an in-memory stream where
// the data will be stored.
var writer = Windows.Storage.Streams.DataWriter(new Windows.Storage.Streams.InMemoryRandomAccessStream());
writer.unicodeEncoding = Windows.Storage.Streams.UnicodeEncoding.utf8;
writer.byteOrder = Windows.Storage.Streams.ByteOrder.littleEndian;
- var commaIndex = filePath.indexOf(",");
+ var commaIndex = filePath.indexOf(',');
if (commaIndex === -1) {
- errorCallback(new FTErr(FTErr.INVALID_URL_ERR, fileName, server, null, null, "No comma in data: URI"));
+ errorCallback(new FTErr(FTErr.INVALID_URL_ERR, fileName, server, null, null, 'No comma in data: URI'));
return;
}
@@ -213,7 +209,7 @@
var uploader = new Windows.Networking.BackgroundTransfer.BackgroundUploader();
uploader.method = httpMethod;
for (var header in headers) {
- if (headers.hasOwnProperty(header)) {
+ if (Object.prototype.hasOwnProperty.call(headers, header)) {
uploader.setRequestHeader(header, headers[header]);
}
}
@@ -222,9 +218,9 @@
// adding params supplied to request payload
var multipartParams = '';
for (var key in params) {
- if (params.hasOwnProperty(key)) {
+ if (Object.prototype.hasOwnProperty.call(params, key)) {
multipartParams += LINE_START + BOUNDARY + LINE_END;
- multipartParams += "Content-Disposition: form-data; name=\"" + key + "\"";
+ multipartParams += 'Content-Disposition: form-data; name="' + key + '"';
multipartParams += LINE_END + LINE_END;
multipartParams += params[key];
multipartParams += LINE_END;
@@ -232,13 +228,13 @@
}
var multipartFile = LINE_START + BOUNDARY + LINE_END;
- multipartFile += "Content-Disposition: form-data; name=\"file\";";
- multipartFile += " filename=\"" + fileName + "\"" + LINE_END;
- multipartFile += "Content-Type: " + mimeType + LINE_END + LINE_END;
+ multipartFile += 'Content-Disposition: form-data; name="file";';
+ multipartFile += ' filename="' + fileName + '"' + LINE_END;
+ multipartFile += 'Content-Type: ' + mimeType + LINE_END + LINE_END;
var bound = LINE_END + LINE_START + BOUNDARY + LINE_START + LINE_END;
- uploader.setRequestHeader("Content-Type", "multipart/form-data; boundary=" + BOUNDARY);
+ uploader.setRequestHeader('Content-Type', 'multipart/form-data; boundary=' + BOUNDARY);
writer.writeString(multipartParams);
writer.writeString(multipartFile);
writer.writeBytes(stringToByteArray(fileDataString));
@@ -249,42 +245,142 @@
var stream;
- // The call to store async sends the actual contents of the writer
+ // The call to store async sends the actual contents of the writer
// to the backing stream.
- writer.storeAsync().then(function () {
- // For the in-memory stream implementation we are using, the flushAsync call
- // is superfluous, but other types of streams may require it.
- return writer.flushAsync();
- }).then(function () {
- // We detach the stream to prolong its useful lifetime. Were we to fail
- // to detach the stream, the call to writer.close() would close the underlying
- // stream, preventing its subsequent use by the DataReader below. Most clients
- // of DataWriter will have no reason to use the underlying stream after
- // writer.close() is called, and will therefore have no reason to call
- // writer.detachStream(). Note that once we detach the stream, we assume
- // responsibility for closing the stream subsequently; after the stream
- // has been detached, a call to writer.close() will have no effect on the stream.
- stream = writer.detachStream();
- // Make sure the stream is read from the beginning in the reader
- // we are creating below.
- stream.seek(0);
- // Most DataWriter clients will not call writer.detachStream(),
- // and furthermore will be working with a file-backed or network-backed stream,
- // rather than an in-memory-stream. In such cases, it would be particularly
- // important to call writer.close(). Doing so is always a best practice.
- writer.close();
+ writer
+ .storeAsync()
+ .then(function () {
+ // For the in-memory stream implementation we are using, the flushAsync call
+ // is superfluous, but other types of streams may require it.
+ return writer.flushAsync();
+ })
+ .then(function () {
+ // We detach the stream to prolong its useful lifetime. Were we to fail
+ // to detach the stream, the call to writer.close() would close the underlying
+ // stream, preventing its subsequent use by the DataReader below. Most clients
+ // of DataWriter will have no reason to use the underlying stream after
+ // writer.close() is called, and will therefore have no reason to call
+ // writer.detachStream(). Note that once we detach the stream, we assume
+ // responsibility for closing the stream subsequently; after the stream
+ // has been detached, a call to writer.close() will have no effect on the stream.
+ stream = writer.detachStream();
+ // Make sure the stream is read from the beginning in the reader
+ // we are creating below.
+ stream.seek(0);
+ // Most DataWriter clients will not call writer.detachStream(),
+ // and furthermore will be working with a file-backed or network-backed stream,
+ // rather than an in-memory-stream. In such cases, it would be particularly
+ // important to call writer.close(). Doing so is always a best practice.
+ writer.close();
+
+ if (alreadyCancelled(uploadId)) {
+ errorCallback(new FTErr(FTErr.ABORT_ERR, nativePathToCordova(filePath), server));
+ return;
+ }
+
+ // create download object. This will throw an exception if URL is malformed
+ var uri = new Windows.Foundation.Uri(server);
+
+ var createUploadOperation;
+ try {
+ createUploadOperation = uploader.createUploadFromStreamAsync(uri, stream);
+ } catch (e) {
+ errorCallback(new FTErr(FTErr.INVALID_URL_ERR));
+ return;
+ }
+
+ createUploadOperation.then(
+ function (upload) {
+ doUpload(upload, uploadId, filePath, server, successCallback, errorCallback);
+ },
+ function (err) {
+ var errorObj = new FTErr(FTErr.INVALID_URL_ERR);
+ errorObj.exception = err;
+ errorCallback(errorObj);
+ }
+ );
+ });
+
+ return;
+ }
+
+ if (filePath.substr(0, 8) === 'file:///') {
+ filePath = appData.localFolder.path + filePath.substr(8).split('/').join('\\');
+ } else if (filePath.indexOf('ms-appdata:///') === 0) {
+ // Handle 'ms-appdata' scheme
+ filePath = filePath
+ .replace('ms-appdata:///local', appData.localFolder.path)
+ .replace('ms-appdata:///temp', appData.temporaryFolder.path);
+ } else if (filePath.indexOf('cdvfile://') === 0) {
+ filePath = filePath
+ .replace('cdvfile://localhost/persistent', appData.localFolder.path)
+ .replace('cdvfile://localhost/temporary', appData.temporaryFolder.path);
+ }
+
+ // normalize path separators
+ filePath = cordovaPathToNative(filePath);
+
+ // Create internal download operation object
+ fileTransferOps[uploadId] = new FileTransferOperation(FileTransferOperation.PENDING, null);
+
+ Windows.Storage.StorageFile.getFileFromPathAsync(filePath).then(
+ function (storageFile) {
+ if (!fileName) {
+ fileName = storageFile.name;
+ }
+ if (!mimeType) {
+ // use the actual content type of the file, probably this should be the default way.
+ // other platforms probably can't look this up.
+ mimeType = storageFile.contentType;
+ }
if (alreadyCancelled(uploadId)) {
errorCallback(new FTErr(FTErr.ABORT_ERR, nativePathToCordova(filePath), server));
return;
}
+ // setting request headers for uploader
+ var uploader = new Windows.Networking.BackgroundTransfer.BackgroundUploader();
+ uploader.method = httpMethod;
+ for (var header in headers) {
+ if (Object.prototype.hasOwnProperty.call(headers, header)) {
+ uploader.setRequestHeader(header, headers[header]);
+ }
+ }
+
// create download object. This will throw an exception if URL is malformed
var uri = new Windows.Foundation.Uri(server);
var createUploadOperation;
try {
- createUploadOperation = uploader.createUploadFromStreamAsync(uri, stream);
+ if (isMultipart) {
+ // adding params supplied to request payload
+ var transferParts = [];
+ for (var key in params) {
+ // Create content part for params only if value is specified because CreateUploadAsync fails otherwise
+ if (
+ Object.prototype.hasOwnProperty.call(params, key) &&
+ params[key] !== null &&
+ params[key] !== undefined &&
+ params[key].toString() !== ''
+ ) {
+ 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.setHeader('Content-Type', mimeType);
+ fileToUploadPart.setFile(storageFile);
+ transferParts.push(fileToUploadPart);
+
+ createUploadOperation = uploader.createUploadAsync(uri, transferParts);
+ } else {
+ createUploadOperation = WinJS.Promise.wrap(uploader.createUpload(uri, storageFile));
+ }
} catch (e) {
errorCallback(new FTErr(FTErr.INVALID_URL_ERR));
return;
@@ -298,105 +394,17 @@
var errorObj = new FTErr(FTErr.INVALID_URL_ERR);
errorObj.exception = err;
errorCallback(errorObj);
- });
- });
-
- return;
- }
-
- if (filePath.substr(0, 8) === "file:///") {
- filePath = appData.localFolder.path + filePath.substr(8).split("/").join("\\");
- } else if (filePath.indexOf('ms-appdata:///') === 0) {
- // Handle 'ms-appdata' scheme
- filePath = filePath.replace('ms-appdata:///local', appData.localFolder.path)
- .replace('ms-appdata:///temp', appData.temporaryFolder.path);
- } else if (filePath.indexOf('cdvfile://') === 0) {
- filePath = filePath.replace('cdvfile://localhost/persistent', appData.localFolder.path)
- .replace('cdvfile://localhost/temporary', appData.temporaryFolder.path);
- }
-
- // normalize path separators
- filePath = cordovaPathToNative(filePath);
-
- // Create internal download operation object
- fileTransferOps[uploadId] = new FileTransferOperation(FileTransferOperation.PENDING, null);
-
- Windows.Storage.StorageFile.getFileFromPathAsync(filePath)
- .then(function (storageFile) {
-
- if (!fileName) {
- fileName = storageFile.name;
- }
- if (!mimeType) {
- // use the actual content type of the file, probably this should be the default way.
- // other platforms probably can't look this up.
- mimeType = storageFile.contentType;
- }
-
- if (alreadyCancelled(uploadId)) {
- errorCallback(new FTErr(FTErr.ABORT_ERR, nativePathToCordova(filePath), server));
- return;
- }
-
- // setting request headers for uploader
- var uploader = new Windows.Networking.BackgroundTransfer.BackgroundUploader();
- uploader.method = httpMethod;
- for (var header in headers) {
- if (headers.hasOwnProperty(header)) {
- uploader.setRequestHeader(header, headers[header]);
- }
- }
-
- // create download object. This will throw an exception if URL is malformed
- var uri = new Windows.Foundation.Uri(server);
-
- var createUploadOperation;
- try {
- if (isMultipart) {
- // adding params supplied to request payload
- var transferParts = [];
- for (var key in params) {
- // Create content part for params only if value is specified because CreateUploadAsync fails otherwise
- if (params.hasOwnProperty(key) && params[key] !== null && params[key] !== undefined && params[key].toString() !== "") {
- 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.setHeader("Content-Type", mimeType);
- fileToUploadPart.setFile(storageFile);
- transferParts.push(fileToUploadPart);
-
- createUploadOperation = uploader.createUploadAsync(uri, transferParts);
- } else {
- createUploadOperation = WinJS.Promise.wrap(uploader.createUpload(uri, storageFile));
- }
- } catch (e) {
- errorCallback(new FTErr(FTErr.INVALID_URL_ERR));
- return;
+ );
+ },
+ function (err) {
+ errorCallback(new FTErr(FTErr.FILE_NOT_FOUND_ERR, fileName, server, null, null, err));
}
-
- createUploadOperation.then(
- function (upload) {
- doUpload(upload, uploadId, filePath, server, successCallback, errorCallback);
- },
- 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, fileName, server, null, null, err));
- });
+ );
},
// [source, target, trustAllHosts, id, headers]
- download:function(successCallback, errorCallback, options) {
+ download: function (successCallback, errorCallback, options) {
var source = options[0];
var target = options[1];
var downloadId = options[3];
@@ -406,25 +414,27 @@
errorCallback(new FTErr(FTErr.FILE_NOT_FOUND_ERR));
return;
}
- if (target.substr(0, 8) === "file:///") {
- target = appData.localFolder.path + target.substr(8).split("/").join("\\");
+ if (target.substr(0, 8) === 'file:///') {
+ target = appData.localFolder.path + target.substr(8).split('/').join('\\');
} else if (target.indexOf('ms-appdata:///') === 0) {
// Handle 'ms-appdata' scheme
- target = target.replace('ms-appdata:///local', appData.localFolder.path)
- .replace('ms-appdata:///temp', appData.temporaryFolder.path);
+ target = target
+ .replace('ms-appdata:///local', appData.localFolder.path)
+ .replace('ms-appdata:///temp', appData.temporaryFolder.path);
} else if (target.indexOf('cdvfile://') === 0) {
- target = target.replace('cdvfile://localhost/persistent', appData.localFolder.path)
- .replace('cdvfile://localhost/temporary', appData.temporaryFolder.path);
+ target = target
+ .replace('cdvfile://localhost/persistent', appData.localFolder.path)
+ .replace('cdvfile://localhost/temporary', appData.temporaryFolder.path);
}
target = cordovaPathToNative(target);
- var path = target.substr(0, target.lastIndexOf("\\"));
- var fileName = target.substr(target.lastIndexOf("\\") + 1);
+ var path = target.substr(0, target.lastIndexOf('\\'));
+ var fileName = target.substr(target.lastIndexOf('\\') + 1);
if (path === null || fileName === null) {
errorCallback(new FTErr(FTErr.FILE_NOT_FOUND_ERR));
return;
}
- // Download to a temp file to avoid the file deletion on 304
+ // Download to a temp file to avoid the file deletion on 304
// CB-7006 Empty file is created on file transfer if server response is 304
var tempFileName = '~' + fileName;
@@ -433,129 +443,136 @@
// Create internal download operation object
fileTransferOps[downloadId] = new FileTransferOperation(FileTransferOperation.PENDING, null);
- var downloadCallback = function(storageFolder) {
- storageFolder.createFileAsync(tempFileName, Windows.Storage.CreationCollisionOption.replaceExisting).then(function (storageFile) {
-
- if (alreadyCancelled(downloadId)) {
- errorCallback(new FTErr(FTErr.ABORT_ERR, source, target));
- return;
- }
-
- // if download isn't cancelled, contunue with creating and preparing download operation
- var downloader = new Windows.Networking.BackgroundTransfer.BackgroundDownloader();
- for (var header in headers) {
- if (headers.hasOwnProperty(header)) {
- downloader.setRequestHeader(header, headers[header]);
- }
- }
-
- // create download object. This will throw an exception if URL is malformed
- try {
- var uri = Windows.Foundation.Uri(source);
- download = downloader.createDownload(uri, storageFile);
- } catch (e) {
- // so we handle this and call errorCallback
- errorCallback(new FTErr(FTErr.INVALID_URL_ERR));
- return;
- }
-
- var downloadOperation = download.startAsync();
- // update internal TransferOperation object with newly created promise
- fileTransferOps[downloadId].promise = downloadOperation;
-
- downloadOperation.then(function () {
-
- // Update TransferOperation object with new state, delete promise property
- // since it is not actual anymore
- var currentDownloadOp = fileTransferOps[downloadId];
- if (currentDownloadOp) {
- currentDownloadOp.state = FileTransferOperation.DONE;
- currentDownloadOp.promise = null;
+ var downloadCallback = function (storageFolder) {
+ storageFolder.createFileAsync(tempFileName, Windows.Storage.CreationCollisionOption.replaceExisting).then(
+ function (storageFile) {
+ if (alreadyCancelled(downloadId)) {
+ errorCallback(new FTErr(FTErr.ABORT_ERR, source, target));
+ return;
}
- storageFile.renameAsync(fileName, Windows.Storage.CreationCollisionOption.replaceExisting).done(function () {
- var nativeURI = storageFile.path.replace(appData.localFolder.path, 'ms-appdata:///local')
- .replace(appData.temporaryFolder.path, 'ms-appdata:///temp')
- .replace(/\\/g, '/');
+ // if download isn't cancelled, contunue with creating and preparing download operation
+ var downloader = new Windows.Networking.BackgroundTransfer.BackgroundDownloader();
+ for (var header in headers) {
+ if (Object.prototype.hasOwnProperty.call(headers, header)) {
+ downloader.setRequestHeader(header, headers[header]);
+ }
+ }
- // Passing null as error callback here because downloaded file should exist in any case
- // otherwise the error callback will be hit during file creation in another place
- FileProxy.resolveLocalFileSystemURI(successCallback, null, [nativeURI]);
- }, function(error) {
- errorCallback(new FTErr(FTErr.FILE_NOT_FOUND_ERR, source, target, null, null, error));
- });
- }, function(error) {
+ // create download object. This will throw an exception if URL is malformed
+ try {
+ var uri = Windows.Foundation.Uri(source);
+ download = downloader.createDownload(uri, storageFile);
+ } catch (e) {
+ // so we handle this and call errorCallback
+ errorCallback(new FTErr(FTErr.INVALID_URL_ERR));
+ return;
+ }
- var getTransferError = new WinJS.Promise(function (resolve) {
- // Handle download error here. If download was cancelled,
- // message property will be specified
- if (error.message === 'Canceled') {
- resolve(new FTErr(FTErr.ABORT_ERR, source, target, null, null, error));
- } else if (error && error.number === HTTP_E_STATUS_NOT_MODIFIED) {
- resolve(new FTErr(FTErr.NOT_MODIFIED_ERR, source, target, 304, null, error));
- } else {
- // in the other way, try to get response property
- var response = download.getResponseInformation();
- if (!response) {
- resolve(new FTErr(FTErr.CONNECTION_ERR, source, target));
- } else {
- if (download.progress.bytesReceived === 0) {
- resolve(new FTErr(FTErr.FILE_NOT_FOUND_ERR, source, target, response.statusCode, null, error));
- return;
- }
- var reader = new Windows.Storage.Streams.DataReader(download.getResultStreamAt(0));
- reader.loadAsync(download.progress.bytesReceived).then(function (bytesLoaded) {
- var payload = reader.readString(bytesLoaded);
- resolve(new FTErr(FTErr.FILE_NOT_FOUND_ERR, source, target, response.statusCode, payload, error));
- });
+ var downloadOperation = download.startAsync();
+ // update internal TransferOperation object with newly created promise
+ fileTransferOps[downloadId].promise = downloadOperation;
+
+ downloadOperation.then(
+ function () {
+ // Update TransferOperation object with new state, delete promise property
+ // since it is not actual anymore
+ var currentDownloadOp = fileTransferOps[downloadId];
+ if (currentDownloadOp) {
+ currentDownloadOp.state = FileTransferOperation.DONE;
+ currentDownloadOp.promise = null;
}
+
+ storageFile.renameAsync(fileName, Windows.Storage.CreationCollisionOption.replaceExisting).done(
+ function () {
+ var nativeURI = storageFile.path
+ .replace(appData.localFolder.path, 'ms-appdata:///local')
+ .replace(appData.temporaryFolder.path, 'ms-appdata:///temp')
+ .replace(/\\/g, '/');
+
+ // Passing null as error callback here because downloaded file should exist in any case
+ // otherwise the error callback will be hit during file creation in another place
+ FileProxy.resolveLocalFileSystemURI(successCallback, null, [nativeURI]);
+ },
+ function (error) {
+ errorCallback(new FTErr(FTErr.FILE_NOT_FOUND_ERR, source, target, null, null, error));
+ }
+ );
+ },
+ function (error) {
+ var getTransferError = new WinJS.Promise(function (resolve) {
+ // Handle download error here. If download was cancelled,
+ // message property will be specified
+ if (error.message === 'Canceled') {
+ resolve(new FTErr(FTErr.ABORT_ERR, source, target, null, null, error));
+ } else if (error && error.number === HTTP_E_STATUS_NOT_MODIFIED) {
+ resolve(new FTErr(FTErr.NOT_MODIFIED_ERR, source, target, 304, null, error));
+ } else {
+ // in the other way, try to get response property
+ var response = download.getResponseInformation();
+ if (!response) {
+ resolve(new FTErr(FTErr.CONNECTION_ERR, source, target));
+ } else {
+ if (download.progress.bytesReceived === 0) {
+ resolve(new FTErr(FTErr.FILE_NOT_FOUND_ERR, source, target, response.statusCode, null, error));
+ return;
+ }
+ var reader = new Windows.Storage.Streams.DataReader(download.getResultStreamAt(0));
+ reader.loadAsync(download.progress.bytesReceived).then(function (bytesLoaded) {
+ var payload = reader.readString(bytesLoaded);
+ resolve(
+ new FTErr(FTErr.FILE_NOT_FOUND_ERR, source, target, response.statusCode, payload, error)
+ );
+ });
+ }
+ }
+ });
+ getTransferError.then(function (fileTransferError) {
+ // Update TransferOperation object with new state, delete promise property
+ // since it is not actual anymore
+ var currentDownloadOp = fileTransferOps[downloadId];
+ if (currentDownloadOp) {
+ currentDownloadOp.state = FileTransferOperation.CANCELLED;
+ currentDownloadOp.promise = null;
+ }
+
+ // Cleanup, remove incompleted file
+ storageFile.deleteAsync().then(function () {
+ errorCallback(fileTransferError);
+ });
+ });
+ },
+ function (evt) {
+ var progressEvent = new ProgressEvent('progress', {
+ loaded: evt.progress.bytesReceived,
+ total: evt.progress.totalBytesToReceive,
+ target: evt.resultFile
+ });
+ // when bytesReceived == 0, BackgroundDownloader has not yet differentiated whether it could get file length or not,
+ // when totalBytesToReceive == 0, BackgroundDownloader is unable to get file length
+ progressEvent.lengthComputable = evt.progress.bytesReceived > 0 && evt.progress.totalBytesToReceive > 0;
+
+ successCallback(progressEvent, { keepCallback: true });
}
- });
- getTransferError.then(function (fileTransferError) {
-
- // Update TransferOperation object with new state, delete promise property
- // since it is not actual anymore
- var currentDownloadOp = fileTransferOps[downloadId];
- if (currentDownloadOp) {
- currentDownloadOp.state = FileTransferOperation.CANCELLED;
- currentDownloadOp.promise = null;
- }
-
- // Cleanup, remove incompleted file
- storageFile.deleteAsync().then(function() {
- errorCallback(fileTransferError);
- });
- });
-
- }, function(evt) {
-
- var progressEvent = new ProgressEvent('progress', {
- loaded: evt.progress.bytesReceived,
- total: evt.progress.totalBytesToReceive,
- target: evt.resultFile
- });
- // when bytesReceived == 0, BackgroundDownloader has not yet differentiated whether it could get file length or not,
- // when totalBytesToReceive == 0, BackgroundDownloader is unable to get file length
- progressEvent.lengthComputable = (evt.progress.bytesReceived > 0) && (evt.progress.totalBytesToReceive > 0);
-
- successCallback(progressEvent, { keepCallback: true });
- });
- }, function(error) {
- errorCallback(new FTErr(FTErr.FILE_NOT_FOUND_ERR, source, target, null, null, error));
- });
+ );
+ },
+ function (error) {
+ errorCallback(new FTErr(FTErr.FILE_NOT_FOUND_ERR, source, target, null, null, error));
+ }
+ );
};
- var fileNotFoundErrorCallback = function(error) {
+ var fileNotFoundErrorCallback = function (error) {
errorCallback(new FTErr(FTErr.FILE_NOT_FOUND_ERR, source, target, null, null, error));
};
Windows.Storage.StorageFolder.getFolderFromPathAsync(path).then(downloadCallback, function (error) {
// Handle non-existent directory
if (error.number === -2147024894) {
- var parent = path.substr(0, path.lastIndexOf('\\')),
- folderNameToCreate = path.substr(path.lastIndexOf('\\') + 1);
+ var parent = path.substr(0, path.lastIndexOf('\\'));
+ var folderNameToCreate = path.substr(path.lastIndexOf('\\') + 1);
- Windows.Storage.StorageFolder.getFolderFromPathAsync(parent).then(function(parentFolder) {
+ Windows.Storage.StorageFolder.getFolderFromPathAsync(parent).then(function (parentFolder) {
parentFolder.createFolderAsync(folderNameToCreate).then(downloadCallback, fileNotFoundErrorCallback);
}, fileNotFoundErrorCallback);
} else {
@@ -577,7 +594,6 @@
fileTransferOps[fileTransferOpId] = new FileTransferOperation(FileTransferOperation.CANCELLED, null);
}
}
-
};
-require("cordova/exec/proxy").add("FileTransfer",module.exports);
+require('cordova/exec/proxy').add('FileTransfer', module.exports);
diff --git a/tests/hooks/after_prepare.js b/tests/hooks/after_prepare.js
index 6101c62..7c5b34c 100644
--- a/tests/hooks/after_prepare.js
+++ b/tests/hooks/after_prepare.js
@@ -1,46 +1,48 @@
#!/usr/bin/env node
/*
-*
-* 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.
-*
-*/
+ *
+ * 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 path = require('path');
var fs = require('fs');
-module.exports = function(context) {
- function main() {
+module.exports = function (context) {
+ function main () {
// get the file transfer server address from the specified variables
var fileTransferServerAddress = getFileTransferServerAddress(context) || getDefaultFileTransferServerAddress(context);
console.log('Tests will use the following file transfer server address: ' + fileTransferServerAddress);
- console.log('If you\'re using cordova@6.3.1 and the above address is wrong at "platform add", don\'t worry, it\'ll fix itself on "cordova run" or "cordova prepare".');
+ console.log(
+ 'If you\'re using cordova@6.3.1 and the above address is wrong at "platform add", don\'t worry, it\'ll fix itself on "cordova run" or "cordova prepare".'
+ );
// pass it to the tests
writeFileTransferOptions(fileTransferServerAddress, context);
}
- function getDefaultFileTransferServerAddress(context) {
+ function getDefaultFileTransferServerAddress (context) {
var address = null;
var configNodes = context.opts.plugin.pluginInfo._et._root._children;
for (var node in configNodes) {
- if (configNodes[node].attrib.name == 'FILETRANSFER_SERVER_ADDRESS') {
+ if (configNodes[node].attrib.name === 'FILETRANSFER_SERVER_ADDRESS') {
address = configNodes[node].attrib.default;
}
}
@@ -48,18 +50,28 @@
return address;
}
- function getFileTransferServerAddress(context) {
- var platformJsonFile = path.join(context.opts.projectRoot, 'platforms', context.opts.platforms[0], context.opts.platforms[0] + '.json');
+ function getFileTransferServerAddress (context) {
+ var platformJsonFile = path.join(
+ context.opts.projectRoot,
+ 'platforms',
+ context.opts.platforms[0],
+ context.opts.platforms[0] + '.json'
+ );
var platformJson = JSON.parse(fs.readFileSync(platformJsonFile, 'utf8'));
- if (platformJson && platformJson.installed_plugins && platformJson.installed_plugins['cordova-plugin-file-transfer-tests'] && platformJson.installed_plugins['cordova-plugin-file-transfer-tests'].FILETRANSFER_SERVER_ADDRESS) {
+ if (
+ platformJson &&
+ platformJson.installed_plugins &&
+ platformJson.installed_plugins['cordova-plugin-file-transfer-tests'] &&
+ platformJson.installed_plugins['cordova-plugin-file-transfer-tests'].FILETRANSFER_SERVER_ADDRESS
+ ) {
return platformJson.installed_plugins['cordova-plugin-file-transfer-tests'].FILETRANSFER_SERVER_ADDRESS;
} else {
return null;
}
}
- function writeFileTransferOptions(address, context) {
+ function writeFileTransferOptions (address, context) {
for (var p in context.opts.paths) {
var ftOpts = {
serverAddress: address
@@ -71,5 +83,4 @@
}
main();
-
};
diff --git a/tests/tests.js b/tests/tests.js
index 63c9c1c..50b128a 100644
--- a/tests/tests.js
+++ b/tests/tests.js
@@ -1,44 +1,42 @@
/*
-*
-* 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.
-*
-*/
+ *
+ * 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 exports, cordova, FileTransfer, FileTransferError, FileUploadOptions, LocalFileSystem, WinJS */
-
-/* jshint jasmine: true */
+/* global cordova, FileTransfer, FileTransferError, FileUploadOptions, WinJS, LocalFileSystem */
exports.defineAutoTests = function () {
-
- "use strict";
+ 'use strict';
// constants
var ONE_SECOND = 1000; // in milliseconds
var GRACE_TIME_DELTA = 600; // in milliseconds
var DEFAULT_FILESYSTEM_SIZE = 1024 * 50; // filesystem size in bytes
- var UNKNOWN_HOST = "http://foobar.apache.org";
+ var UNKNOWN_HOST = 'http://foobar.apache.org';
var DOWNLOAD_TIMEOUT = 15 * ONE_SECOND;
var LONG_TIMEOUT = 60 * ONE_SECOND;
var UPLOAD_TIMEOUT = 15 * ONE_SECOND;
var ABORT_DELAY = 100; // for abort() tests
var LATIN1_SYMBOLS = '¥§©ÆÖÑøøø¼';
- var DATA_URI_PREFIX = "data:image/png;base64,";
- var DATA_URI_CONTENT = "iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==";
+ var DATA_URI_PREFIX = 'data:image/png;base64,';
+ var DATA_URI_CONTENT =
+ 'iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==';
var DATA_URI_CONTENT_LENGTH = 85; // bytes. (This is the raw file size: used https://en.wikipedia.org/wiki/File:Red-dot-5px.png from https://en.wikipedia.org/wiki/Data_URI_scheme)
var RETRY_COUNT = 100; // retry some flaky tests (yes, THIS many times, due to Heroku server instability)
var RETRY_INTERVAL = 100;
@@ -49,31 +47,29 @@
// Will get it from the config
// you can specify it as a 'FILETRANSFER_SERVER_ADDRESS' variable upon test plugin installation
// or change the default value in plugin.xml
- var SERVER = "";
- var SERVER_WITH_CREDENTIALS = "";
+ var SERVER = '';
+ var SERVER_WITH_CREDENTIALS = '';
// flags
- var isWindows = cordova.platformId === "windows";
- var isBrowser = cordova.platformId === "browser";
+ 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;
+ var isIE = isBrowser && navigator.userAgent.indexOf('Trident') >= 0;
+ var isIos = cordova.platformId === 'ios';
+ var isIot = cordova.platformId === 'android' && navigator.userAgent.indexOf('iot') >= 0;
// tests
- describe("FileTransferError", function () {
-
- it("should exist", function () {
+ describe('FileTransferError', function () {
+ it('should exist', function () {
expect(FileTransferError).toBeDefined();
});
- it("should be constructable", function () {
+ it('should be constructable', function () {
var transferError = new FileTransferError();
expect(transferError).toBeDefined();
});
- it("filetransfer.spec.3 should expose proper constants", function () {
-
+ it('filetransfer.spec.3 should expose proper constants', function () {
expect(FileTransferError.FILE_NOT_FOUND_ERR).toBeDefined();
expect(FileTransferError.INVALID_URL_ERR).toBeDefined();
expect(FileTransferError.CONNECTION_ERR).toBeDefined();
@@ -88,41 +84,42 @@
});
});
- describe("FileUploadOptions", function () {
-
- it("should exist", function () {
+ describe('FileUploadOptions', function () {
+ it('should exist', function () {
expect(FileUploadOptions).toBeDefined();
});
- it("should be constructable", function () {
+ it('should be constructable', function () {
var transferOptions = new FileUploadOptions();
expect(transferOptions).toBeDefined();
});
});
- describe("FileTransfer", function () {
+ describe('FileTransfer', function () {
this.persistentRoot = null;
- this.tempRoot = null;
+ this.tempRoot = null;
// named callbacks
var unexpectedCallbacks = {
- httpFail: function () {},
- httpWin: function () {},
- fileSystemFail: function () {},
- fileSystemWin: function () {},
+ httpFail: function () {},
+ httpWin: function () {},
+ fileSystemFail: function () {},
+ fileSystemWin: function () {},
fileOperationFail: function () {},
- fileOperationWin: function () {},
+ fileOperationWin: function () {}
};
var expectedCallbacks = {
unsupportedOperation: function (response) {
- console.log("spec called unsupported functionality; response:", response);
- },
+ console.log('spec called unsupported functionality; response:', response);
+ }
};
// helpers
var deleteFile = function (fileSystem, name, done) {
- fileSystem.getFile(name, null,
+ fileSystem.getFile(
+ name,
+ null,
function (fileEntry) {
fileEntry.remove(
function () {
@@ -140,15 +137,16 @@
};
var writeFile = function (fileSystem, name, content, success, done) {
- var fileOperationFail = function() {
+ var fileOperationFail = function () {
unexpectedCallbacks.fileOperationFail();
done();
};
- fileSystem.getFile(name, { create: true },
+ fileSystem.getFile(
+ name,
+ { create: true },
function (fileEntry) {
fileEntry.createWriter(function (writer) {
-
writer.onwrite = function () {
success(fileEntry);
};
@@ -161,13 +159,12 @@
throw new Error("aborted creating test file '" + name + "': " + evt);
};
- if (cordova.platformId === "browser") {
- var blob = new Blob([content + "\n"], { type: "text/plain" });
+ if (cordova.platformId === 'browser') {
+ var blob = new Blob([content + '\n'], { type: 'text/plain' });
writer.write(blob);
} else {
- writer.write(content + "\n");
+ writer.write(content + '\n');
}
-
}, fileOperationFail);
},
function () {
@@ -181,7 +178,7 @@
expect(event.loaded).toBeGreaterThan(1);
expect(event.total).toBeGreaterThan(0);
expect(event.total).not.toBeLessThan(event.loaded);
- expect(event.lengthComputable).toBe(true, "lengthComputable");
+ expect(event.lengthComputable).toBe(true, 'lengthComputable');
} else {
// In IE, when lengthComputable === false, event.total somehow is equal to 2^64
if (isIE) {
@@ -194,12 +191,12 @@
};
var getMalformedUrl = function () {
- if (cordova.platformId === "android") {
+ if (cordova.platformId === 'android') {
// bad protocol causes a MalformedUrlException on Android
- return "httpssss://example.com";
+ return 'httpssss://example.com';
} else {
// iOS doesn't care about protocol, space in hostname causes error
- return "httpssss://exa mple.com";
+ return 'httpssss://exa mple.com';
}
};
@@ -215,13 +212,15 @@
beforeEach(function (done) {
var specContext = this;
- window.requestFileSystem(LocalFileSystem.PERSISTENT, DEFAULT_FILESYSTEM_SIZE,
+ window.requestFileSystem(
+ LocalFileSystem.PERSISTENT,
+ DEFAULT_FILESYSTEM_SIZE,
function (fileSystem) {
specContext.persistentRoot = fileSystem.root;
done();
},
function () {
- throw new Error("Failed to initialize persistent file system.");
+ throw new Error('Failed to initialize persistent file system.');
}
);
});
@@ -229,30 +228,31 @@
beforeEach(function (done) {
var specContext = this;
- window.requestFileSystem(LocalFileSystem.TEMPORARY, DEFAULT_FILESYSTEM_SIZE,
+ window.requestFileSystem(
+ LocalFileSystem.TEMPORARY,
+ DEFAULT_FILESYSTEM_SIZE,
function (fileSystem) {
specContext.tempRoot = fileSystem.root;
done();
},
function () {
- throw new Error("Failed to initialize temporary file system.");
+ throw new Error('Failed to initialize temporary file system.');
}
);
});
// spy on all named callbacks
- beforeEach(function() {
-
+ beforeEach(function () {
// ignore the actual implementations of the unexpected callbacks
for (var callback in unexpectedCallbacks) {
- if (unexpectedCallbacks.hasOwnProperty(callback)) {
+ if (Object.prototype.hasOwnProperty.call(unexpectedCallbacks, callback)) {
spyOn(unexpectedCallbacks, callback);
}
}
// but run the implementations of the expected callbacks
- for (callback in expectedCallbacks) { // jshint ignore: line
- if (expectedCallbacks.hasOwnProperty(callback)) {
+ for (callback in expectedCallbacks) {
+ if (Object.prototype.hasOwnProperty.call(expectedCallbacks, callback)) {
spyOn(expectedCallbacks, callback).and.callThrough();
}
}
@@ -260,9 +260,9 @@
// at the end, check that none of the unexpected callbacks got called,
// and act on the expected callbacks
- afterEach(function() {
+ afterEach(function () {
for (var callback in unexpectedCallbacks) {
- if (unexpectedCallbacks.hasOwnProperty(callback)) {
+ if (Object.prototype.hasOwnProperty.call(unexpectedCallbacks, callback)) {
expect(unexpectedCallbacks[callback]).not.toHaveBeenCalled();
}
}
@@ -272,11 +272,11 @@
}
});
- it ("util spec: get file transfer server url", function () {
+ it('util spec: get file transfer server url', function () {
try {
// attempt to synchronously load medic config
var xhr = new XMLHttpRequest();
- xhr.open("GET", "../fileTransferOpts.json", false);
+ xhr.open('GET', '../fileTransferOpts.json', false);
xhr.send(null);
var parsedCfg = JSON.parse(xhr.responseText);
if (parsedCfg.serverAddress) {
@@ -284,27 +284,28 @@
}
} catch (ex) {
console.error('Unable to load file transfer server url: ' + ex);
- console.error('Note: if you are testing this on cordova-ios with cordova-plugin-wkwebview-engine, that may be why you are getting this error. See https://issues.apache.org/jira/browse/CB-10144.');
+ console.error(
+ 'Note: if you are testing this on cordova-ios with cordova-plugin-wkwebview-engine, that may be why you are getting this error. See https://issues.apache.org/jira/browse/CB-10144.'
+ );
fail(ex);
}
});
- it("should initialise correctly", function() {
+ it('should initialise correctly', function () {
expect(this.persistentRoot).toBeDefined();
expect(this.tempRoot).toBeDefined();
});
- it("should exist", function () {
+ it('should exist', function () {
expect(FileTransfer).toBeDefined();
});
- it("filetransfer.spec.1 should be constructable", function () {
+ it('filetransfer.spec.1 should be constructable', function () {
var transfer = new FileTransfer();
expect(transfer).toBeDefined();
});
- it("filetransfer.spec.2 should expose proper functions", function () {
-
+ it('filetransfer.spec.2 should expose proper functions', function () {
var transfer = new FileTransfer();
expect(transfer.upload).toBeDefined();
@@ -314,24 +315,23 @@
expect(transfer.download).toEqual(jasmine.any(Function));
});
- describe("methods", function() {
- this.transfer = null;
- this.root = null;
- this.fileName = null;
- this.localFilePath = null;
+ describe('methods', function () {
+ this.transfer = null;
+ this.root = null;
+ this.fileName = null;
+ this.localFilePath = null;
- beforeEach(function() {
-
+ beforeEach(function () {
this.transfer = new FileTransfer();
// assign onprogress handler
this.transfer.onprogress = defaultOnProgressHandler;
// spy on the onprogress handler, but still call through to it
- spyOn(this.transfer, "onprogress").and.callThrough();
+ spyOn(this.transfer, 'onprogress').and.callThrough();
- this.root = this.persistentRoot;
- this.fileName = "testFile.txt";
+ this.root = this.persistentRoot;
+ this.fileName = 'testFile.txt';
this.localFilePath = this.root.toURL() + this.fileName;
});
@@ -341,8 +341,7 @@
// - 'httpssss://example.com'
// - 'apache.org', with subdomains="true"
// - 'cordova-filetransfer.jitsu.com'
- describe("download", function () {
-
+ describe('download', function () {
// helpers
var verifyDownload = function (fileEntry, specContext) {
expect(fileEntry.name).toBe(specContext.fileName);
@@ -353,431 +352,481 @@
deleteFile(this.root, this.fileName, done);
});
- it("ensures that test file does not exist", function (done) {
+ it('ensures that test file does not exist', function (done) {
deleteFile(this.root, this.fileName, done);
});
- it("filetransfer.spec.4 should download a file", function (done) {
- var fileURL = SERVER + "/robots.txt";
- var specContext = this;
+ it(
+ 'filetransfer.spec.4 should download a file',
+ function (done) {
+ var fileURL = SERVER + '/robots.txt';
+ var specContext = this;
- var fileWin = function (blob) {
-
- if (specContext.transfer.onprogress.calls.any()) {
- var lastProgressEvent = specContext.transfer.onprogress.calls.mostRecent().args[0];
- expect(lastProgressEvent.loaded).not.toBeGreaterThan(blob.size);
- } else {
- console.log("no progress events were emitted");
- }
-
- done();
- };
-
- var fileSystemFail = function() {
- unexpectedCallbacks.fileSystemFail();
- done();
- };
-
- var downloadFail = function() {
- unexpectedCallbacks.httpFail();
- done();
- };
-
- var downloadWin = function (entry) {
-
- verifyDownload(entry, specContext);
-
- // verify the FileEntry representing this file
- entry.file(fileWin, fileSystemFail);
- };
-
- specContext.transfer.download(fileURL, specContext.localFilePath, downloadWin, downloadFail);
- }, DOWNLOAD_TIMEOUT * 10); // to give Heroku server some time to wake up
-
- it("filetransfer.spec.4.1 should download a file using target name with space", function (done) {
-
- var fileURL = SERVER + "/robots.txt";
- this.fileName = "test file.txt";
- this.localFilePath = this.root.toURL() + this.fileName;
-
- var specContext = this;
-
- var fileWin = function (blob) {
-
- if (specContext.transfer.onprogress.calls.any()) {
- var lastProgressEvent = specContext.transfer.onprogress.calls.mostRecent().args[0];
- expect(lastProgressEvent.loaded).not.toBeGreaterThan(blob.size);
- } else {
- console.log("no progress events were emitted");
- }
-
- done();
- };
-
- var fileSystemFail = function() {
- unexpectedCallbacks.fileSystemFail();
- done();
- };
-
- var downloadFail = function() {
- unexpectedCallbacks.httpFail();
- done();
- };
-
- var downloadWin = function (entry) {
-
- verifyDownload(entry, specContext);
-
- // verify the FileEntry representing this file
- entry.file(fileWin, fileSystemFail);
- };
-
- specContext.transfer.download(fileURL, specContext.localFilePath, downloadWin, downloadFail);
- }, DOWNLOAD_TIMEOUT);
-
- it("filetransfer.spec.5 should download a file using http basic auth", function (done) {
- var fileURL = SERVER_WITH_CREDENTIALS + "/download_basic_auth";
- var specContext = this;
-
- var downloadWin = function (entry) {
- verifyDownload(entry, specContext);
- done();
- };
-
- var downloadFail = function() {
- unexpectedCallbacks.httpFail();
- done();
- };
-
- specContext.transfer.download(fileURL, specContext.localFilePath, downloadWin, downloadFail);
- }, DOWNLOAD_TIMEOUT);
-
- it("filetransfer.spec.6 should get 401 status on http basic auth failure", function (done) {
- // NOTE:
- // using server without credentials
- var fileURL = SERVER + "/download_basic_auth";
-
- var downloadFail = function (error) {
- expect(error.http_status).toBe(401);
- expect(error.http_status).not.toBe(404, "Ensure " + fileURL + " is in the white list");
- done();
- };
-
- var downloadWin = function() {
- unexpectedCallbacks.httpWin();
- done();
- };
-
- this.transfer.download(fileURL, this.localFilePath, downloadWin, downloadFail, null,
- {
- headers: {
- "If-Modified-Since": "Thu, 19 Mar 2015 00:00:00 GMT"
+ var fileWin = function (blob) {
+ if (specContext.transfer.onprogress.calls.any()) {
+ var lastProgressEvent = specContext.transfer.onprogress.calls.mostRecent().args[0];
+ expect(lastProgressEvent.loaded).not.toBeGreaterThan(blob.size);
+ } else {
+ console.log('no progress events were emitted');
}
- });
- }, DOWNLOAD_TIMEOUT);
- it("filetransfer.spec.7 should download a file using file:// (when hosted from file://)", function (done) {
- // for Windows platform it's ms-appdata:/// by default, not file://
- if (isWindows) {
- pending();
- return;
- }
-
- var fileURL = window.location.protocol + "//" + window.location.pathname.replace(/ /g, "%20");
- var specContext = this;
-
- if (!/^file:/.exec(fileURL)) {
- done();
- return;
- }
-
- var downloadWin = function (entry) {
- verifyDownload(entry, specContext);
- done();
- };
-
- var downloadFail = function() {
- unexpectedCallbacks.httpFail();
- done();
- };
-
- specContext.transfer.download(fileURL, specContext.localFilePath, downloadWin, downloadFail);
- }, DOWNLOAD_TIMEOUT);
-
- it("filetransfer.spec.8 should download a file using https://", function (done) {
- var fileURL = "https://www.apache.org/licenses/";
- var specContext = this;
-
- var downloadFail = function() {
- unexpectedCallbacks.httpFail();
- done();
- };
-
- var fileOperationFail = function() {
- unexpectedCallbacks.fileOperationFail();
- done();
- };
-
- var fileSystemFail = function() {
- unexpectedCallbacks.fileSystemFail();
- done();
- };
-
- var fileWin = function (file) {
-
- var reader = new FileReader();
-
- reader.onerror = fileOperationFail;
- reader.onload = function () {
- expect(reader.result).toMatch(/The Apache Software Foundation/);
done();
};
- reader.readAsText(file);
+ var fileSystemFail = function () {
+ unexpectedCallbacks.fileSystemFail();
+ done();
+ };
+
+ var downloadFail = function () {
+ unexpectedCallbacks.httpFail();
+ done();
+ };
+
+ var downloadWin = function (entry) {
+ verifyDownload(entry, specContext);
+
+ // verify the FileEntry representing this file
+ entry.file(fileWin, fileSystemFail);
+ };
+
+ specContext.transfer.download(fileURL, specContext.localFilePath, downloadWin, downloadFail);
+ },
+ DOWNLOAD_TIMEOUT * 10
+ ); // to give Heroku server some time to wake up
+
+ it(
+ 'filetransfer.spec.4.1 should download a file using target name with space',
+ function (done) {
+ var fileURL = SERVER + '/robots.txt';
+ this.fileName = 'test file.txt';
+ this.localFilePath = this.root.toURL() + this.fileName;
+
+ var specContext = this;
+
+ var fileWin = function (blob) {
+ if (specContext.transfer.onprogress.calls.any()) {
+ var lastProgressEvent = specContext.transfer.onprogress.calls.mostRecent().args[0];
+ expect(lastProgressEvent.loaded).not.toBeGreaterThan(blob.size);
+ } else {
+ console.log('no progress events were emitted');
+ }
+
+ done();
+ };
+
+ var fileSystemFail = function () {
+ unexpectedCallbacks.fileSystemFail();
+ done();
+ };
+
+ var downloadFail = function () {
+ unexpectedCallbacks.httpFail();
+ done();
+ };
+
+ var downloadWin = function (entry) {
+ verifyDownload(entry, specContext);
+
+ // verify the FileEntry representing this file
+ entry.file(fileWin, fileSystemFail);
+ };
+
+ specContext.transfer.download(fileURL, specContext.localFilePath, downloadWin, downloadFail);
+ },
+ DOWNLOAD_TIMEOUT
+ );
+
+ it(
+ 'filetransfer.spec.5 should download a file using http basic auth',
+ function (done) {
+ var fileURL = SERVER_WITH_CREDENTIALS + '/download_basic_auth';
+ var specContext = this;
+
+ var downloadWin = function (entry) {
+ verifyDownload(entry, specContext);
+ done();
+ };
+
+ var downloadFail = function () {
+ unexpectedCallbacks.httpFail();
+ done();
+ };
+
+ specContext.transfer.download(fileURL, specContext.localFilePath, downloadWin, downloadFail);
+ },
+ DOWNLOAD_TIMEOUT
+ );
+
+ it(
+ 'filetransfer.spec.6 should get 401 status on http basic auth failure',
+ function (done) {
+ // NOTE:
+ // using server without credentials
+ var fileURL = SERVER + '/download_basic_auth';
+
+ var downloadFail = function (error) {
+ expect(error.http_status).toBe(401);
+ expect(error.http_status).not.toBe(404, 'Ensure ' + fileURL + ' is in the white list');
+ done();
+ };
+
+ var downloadWin = function () {
+ unexpectedCallbacks.httpWin();
+ done();
+ };
+
+ this.transfer.download(fileURL, this.localFilePath, downloadWin, downloadFail, null, {
+ headers: {
+ 'If-Modified-Since': 'Thu, 19 Mar 2015 00:00:00 GMT'
+ }
+ });
+ },
+ DOWNLOAD_TIMEOUT
+ );
+
+ it(
+ 'filetransfer.spec.7 should download a file using file:// (when hosted from file://)',
+ function (done) {
+ // for Windows platform it's ms-appdata:/// by default, not file://
+ if (isWindows) {
+ pending();
+ return;
+ }
+
+ var fileURL = window.location.protocol + '//' + window.location.pathname.replace(/ /g, '%20');
+ var specContext = this;
+
+ if (!/^file:/.exec(fileURL)) {
+ done();
+ return;
+ }
+
+ var downloadWin = function (entry) {
+ verifyDownload(entry, specContext);
+ done();
+ };
+
+ var downloadFail = function () {
+ unexpectedCallbacks.httpFail();
+ done();
+ };
+
+ specContext.transfer.download(fileURL, specContext.localFilePath, downloadWin, downloadFail);
+ },
+ DOWNLOAD_TIMEOUT
+ );
+
+ it(
+ 'filetransfer.spec.8 should download a file using https://',
+ function (done) {
+ var fileURL = 'https://www.apache.org/licenses/';
+ var specContext = this;
+
+ var downloadFail = function () {
+ unexpectedCallbacks.httpFail();
+ done();
+ };
+
+ var fileOperationFail = function () {
+ unexpectedCallbacks.fileOperationFail();
+ done();
+ };
+
+ var fileSystemFail = function () {
+ unexpectedCallbacks.fileSystemFail();
+ done();
+ };
+
+ var fileWin = function (file) {
+ var reader = new FileReader();
+
+ reader.onerror = fileOperationFail;
+ reader.onload = function () {
+ expect(reader.result).toMatch(/The Apache Software Foundation/);
+ done();
+ };
+
+ reader.readAsText(file);
+ };
+
+ var downloadWin = function (entry) {
+ verifyDownload(entry, specContext);
+ entry.file(fileWin, fileSystemFail);
+ };
+
+ specContext.transfer.download(fileURL, specContext.localFilePath, downloadWin, downloadFail);
+ },
+ isWindows ? LONG_TIMEOUT : DOWNLOAD_TIMEOUT
+ );
+
+ it(
+ 'filetransfer.spec.11 should call the error callback on abort()',
+ function (done) {
+ var fileURL = 'http://cordova.apache.org/downloads/BlueZedEx.mp3';
+ fileURL = fileURL + '?q=' + new Date().getTime();
+ var specContext = this;
+
+ var downloadWin = function () {
+ unexpectedCallbacks.httpWin();
+ done();
+ };
+
+ specContext.transfer.download(fileURL, specContext.localFilePath, downloadWin, done);
+ setTimeout(function () {
+ specContext.transfer.abort();
+ }, ABORT_DELAY);
+ },
+ DOWNLOAD_TIMEOUT
+ );
+
+ it(
+ 'filetransfer.spec.9 should not leave partial file due to abort',
+ function (done) {
+ var fileURL = 'http://cordova.apache.org/downloads/logos_2.zip';
+ var specContext = this;
+
+ var fileSystemWin = function () {
+ unexpectedCallbacks.fileSystemWin();
+ done();
+ };
+
+ var downloadWin = function () {
+ unexpectedCallbacks.httpWin();
+ done();
+ };
+
+ var downloadFail = function (error) {
+ var result = !!(error.code === FileTransferError.ABORT_ERR || error.code === FileTransferError.CONNECTION_ERR);
+ if (!result) {
+ fail(
+ 'Expected ' +
+ error.code +
+ ' to be ' +
+ FileTransferError.ABORT_ERR +
+ ' or ' +
+ FileTransferError.CONNECTION_ERR
+ );
+ }
+ expect(specContext.transfer.onprogress).toHaveBeenCalled();
+
+ // check that there is no file
+ specContext.root.getFile(specContext.fileName, null, fileSystemWin, done);
+ };
+
+ // abort at the first onprogress event
+ specContext.transfer.onprogress = function (event) {
+ if (event.loaded > 0) {
+ specContext.transfer.abort();
+ }
+ };
+
+ spyOn(specContext.transfer, 'onprogress').and.callThrough();
+
+ specContext.transfer.download(fileURL, specContext.localFilePath, downloadWin, downloadFail);
+ },
+ isWindows ? LONG_TIMEOUT : DOWNLOAD_TIMEOUT
+ );
+
+ it(
+ 'filetransfer.spec.10 should be stopped by abort()',
+ function (done) {
+ var fileURL = 'http://cordova.apache.org/downloads/BlueZedEx.mp3';
+ fileURL = fileURL + '?q=' + new Date().getTime();
+ var specContext = this;
+
+ expect(specContext.transfer.abort).not.toThrow(); // should be a no-op.
+
+ var downloadWin = function () {
+ unexpectedCallbacks.httpWin();
+ done();
+ };
+
+ var downloadFail = function (error) {
+ expect(error.code).toBe(FileTransferError.ABORT_ERR);
+
+ // delay calling done() to wait for the bogus abort()
+ setTimeout(done, GRACE_TIME_DELTA * 2);
+ };
+
+ specContext.transfer.download(fileURL, specContext.localFilePath, downloadWin, downloadFail);
+ setTimeout(function () {
+ specContext.transfer.abort();
+ }, ABORT_DELAY);
+
+ // call abort() again, after a time greater than the grace period
+ setTimeout(function () {
+ expect(specContext.transfer.abort).not.toThrow();
+ }, GRACE_TIME_DELTA);
+ },
+ DOWNLOAD_TIMEOUT
+ );
+
+ it(
+ 'filetransfer.spec.12 should get http status on failure',
+ function (done) {
+ var fileURL = SERVER + '/404';
+
+ var downloadFail = function (error) {
+ expect(error.http_status).not.toBe(401, 'Ensure ' + fileURL + ' is in the white list');
+ expect(error.http_status).toBe(404);
+
+ expect(error.code).toBe(FileTransferError.FILE_NOT_FOUND_ERR);
+
+ done();
+ };
+
+ var downloadWin = function () {
+ unexpectedCallbacks.httpWin();
+ done();
+ };
+
+ this.transfer.download(fileURL, this.localFilePath, downloadWin, downloadFail);
+ },
+ DOWNLOAD_TIMEOUT
+ );
+
+ it(
+ 'filetransfer.spec.13 should get http body on failure',
+ function (done) {
+ var fileURL = SERVER + '/404';
+
+ var downloadFail = function (error) {
+ expect(error.http_status).not.toBe(401, 'Ensure ' + fileURL + ' is in the white list');
+ expect(error.http_status).toBe(404);
+
+ expect(error.body).toBeDefined();
+ expect(error.body).toMatch('You requested a 404');
+
+ done();
+ };
+
+ var downloadWin = function () {
+ unexpectedCallbacks.httpWin();
+ done();
+ };
+
+ this.transfer.download(fileURL, this.localFilePath, downloadWin, downloadFail);
+ },
+ DOWNLOAD_TIMEOUT
+ );
+
+ it('filetransfer.spec.14 should handle malformed urls', function (done) {
+ var fileURL = getMalformedUrl();
+
+ var downloadFail = function (error) {
+ // Note: Android needs the bad protocol to be added to the access list
+ // <access origin=".*"/> won't match because ^https?:// is prepended to the regex
+ // The bad protocol must begin with http to avoid automatic prefix
+ expect(error.http_status).not.toBe(401, 'Ensure ' + fileURL + ' is in the white list');
+ expect(error.code).toBe(FileTransferError.INVALID_URL_ERR);
+
+ done();
};
- var downloadWin = function (entry) {
- verifyDownload(entry, specContext);
- entry.file(fileWin, fileSystemFail);
- };
-
- specContext.transfer.download(fileURL, specContext.localFilePath, downloadWin, downloadFail);
- }, isWindows ? LONG_TIMEOUT : DOWNLOAD_TIMEOUT);
-
- it("filetransfer.spec.11 should call the error callback on abort()", function (done) {
- var fileURL = "http://cordova.apache.org/downloads/BlueZedEx.mp3";
- fileURL = fileURL + "?q=" + (new Date()).getTime();
- var specContext = this;
-
var downloadWin = function () {
unexpectedCallbacks.httpWin();
done();
};
- specContext.transfer.download(fileURL, specContext.localFilePath, downloadWin, done);
- setTimeout(function() {
- specContext.transfer.abort();
- }, ABORT_DELAY);
- }, DOWNLOAD_TIMEOUT);
-
- it("filetransfer.spec.9 should not leave partial file due to abort", function (done) {
- var fileURL = "http://cordova.apache.org/downloads/logos_2.zip";
- var specContext = this;
-
- var fileSystemWin = function() {
- unexpectedCallbacks.fileSystemWin();
- done();
- };
-
- var downloadWin = function() {
- unexpectedCallbacks.httpWin();
- done();
- };
-
- var downloadFail = function (error) {
-
- var result = (error.code === FileTransferError.ABORT_ERR || error.code === FileTransferError.CONNECTION_ERR)? true: false;
- if (!result) {
- fail("Expected " + error.code + " to be " + FileTransferError.ABORT_ERR + " or " + FileTransferError.CONNECTION_ERR);
- }
- expect(specContext.transfer.onprogress).toHaveBeenCalled();
-
- // check that there is no file
- specContext.root.getFile(specContext.fileName, null, fileSystemWin, done);
- };
-
- // abort at the first onprogress event
- specContext.transfer.onprogress = function (event) {
- if (event.loaded > 0) {
- specContext.transfer.abort();
- }
- };
-
- spyOn(specContext.transfer, "onprogress").and.callThrough();
-
- specContext.transfer.download(fileURL, specContext.localFilePath, downloadWin, downloadFail);
- }, isWindows ? LONG_TIMEOUT : DOWNLOAD_TIMEOUT);
-
- it("filetransfer.spec.10 should be stopped by abort()", function (done) {
- var fileURL = "http://cordova.apache.org/downloads/BlueZedEx.mp3";
- fileURL = fileURL + "?q=" + (new Date()).getTime();
- var specContext = this;
-
- expect(specContext.transfer.abort).not.toThrow(); // should be a no-op.
-
- var downloadWin = function() {
- unexpectedCallbacks.httpWin();
- done();
- };
-
- var downloadFail = function (error) {
-
- expect(error.code).toBe(FileTransferError.ABORT_ERR);
-
- // delay calling done() to wait for the bogus abort()
- setTimeout(done, GRACE_TIME_DELTA * 2);
- };
-
- specContext.transfer.download(fileURL, specContext.localFilePath, downloadWin, downloadFail);
- setTimeout(function() {
- specContext.transfer.abort();
- }, ABORT_DELAY);
-
- // call abort() again, after a time greater than the grace period
- setTimeout(function () {
- expect(specContext.transfer.abort).not.toThrow();
- }, GRACE_TIME_DELTA);
- }, DOWNLOAD_TIMEOUT);
-
- it("filetransfer.spec.12 should get http status on failure", function (done) {
- var fileURL = SERVER + "/404";
-
- var downloadFail = function (error) {
-
- expect(error.http_status).not.toBe(401, "Ensure " + fileURL + " is in the white list");
- expect(error.http_status).toBe(404);
-
- expect(error.code).toBe(FileTransferError.FILE_NOT_FOUND_ERR);
-
- done();
- };
-
- var downloadWin = function() {
- unexpectedCallbacks.httpWin();
- done();
- };
-
- this.transfer.download(fileURL, this.localFilePath, downloadWin, downloadFail);
- }, DOWNLOAD_TIMEOUT);
-
- it("filetransfer.spec.13 should get http body on failure", function (done) {
- var fileURL = SERVER + "/404";
-
- var downloadFail = function (error) {
-
- expect(error.http_status).not.toBe(401, "Ensure " + fileURL + " is in the white list");
- expect(error.http_status).toBe(404);
-
- expect(error.body).toBeDefined();
- expect(error.body).toMatch("You requested a 404");
-
- done();
- };
-
- var downloadWin = function() {
- unexpectedCallbacks.httpWin();
- done();
- };
-
- this.transfer.download(fileURL, this.localFilePath, downloadWin, downloadFail);
- }, DOWNLOAD_TIMEOUT);
-
- it("filetransfer.spec.14 should handle malformed urls", function (done) {
- var fileURL = getMalformedUrl();
-
- var downloadFail = function (error) {
-
- // Note: Android needs the bad protocol to be added to the access list
- // <access origin=".*"/> won't match because ^https?:// is prepended to the regex
- // The bad protocol must begin with http to avoid automatic prefix
- expect(error.http_status).not.toBe(401, "Ensure " + fileURL + " is in the white list");
- expect(error.code).toBe(FileTransferError.INVALID_URL_ERR);
-
- done();
- };
-
- var downloadWin = function() {
- unexpectedCallbacks.httpWin();
- done();
- };
-
this.transfer.download(fileURL, this.localFilePath, downloadWin, downloadFail);
});
- it("filetransfer.spec.15 should handle unknown host", function (done) {
- var fileURL = UNKNOWN_HOST;
+ it(
+ 'filetransfer.spec.15 should handle unknown host',
+ function (done) {
+ var fileURL = UNKNOWN_HOST;
- var downloadFail = function (error) {
- expect(error.code).toBe(FileTransferError.CONNECTION_ERR);
- done();
- };
+ var downloadFail = function (error) {
+ expect(error.code).toBe(FileTransferError.CONNECTION_ERR);
+ done();
+ };
- var downloadWin = function() {
- unexpectedCallbacks.httpWin();
- done();
- };
+ var downloadWin = function () {
+ unexpectedCallbacks.httpWin();
+ done();
+ };
- // turn off the onprogress handler
- this.transfer.onprogress = function () {};
+ // turn off the onprogress handler
+ this.transfer.onprogress = function () {};
- this.transfer.download(fileURL, this.localFilePath, downloadWin, downloadFail);
- }, isWindows ? LONG_TIMEOUT : DOWNLOAD_TIMEOUT);
+ this.transfer.download(fileURL, this.localFilePath, downloadWin, downloadFail);
+ },
+ isWindows ? LONG_TIMEOUT : DOWNLOAD_TIMEOUT
+ );
- it("filetransfer.spec.16 should handle bad file path", function (done) {
+ it('filetransfer.spec.16 should handle bad file path', function (done) {
var fileURL = SERVER;
- var downloadWin = function() {
+ var downloadWin = function () {
unexpectedCallbacks.httpWin();
done();
};
- this.transfer.download(fileURL, "c:\\54321", downloadWin, done);
+ this.transfer.download(fileURL, 'c:\\54321', downloadWin, done);
});
- it("filetransfer.spec.17 progress should work with gzip encoding", function (done) {
- var fileURL = "http://www.apache.org/";
- var specContext = this;
+ it(
+ 'filetransfer.spec.17 progress should work with gzip encoding',
+ function (done) {
+ var fileURL = 'http://www.apache.org/';
+ var specContext = this;
- var downloadWin = function (entry) {
- verifyDownload(entry, specContext);
- done();
- };
+ var downloadWin = function (entry) {
+ verifyDownload(entry, specContext);
+ done();
+ };
- var downloadFail = function () {
- unexpectedCallbacks.httpFail();
- done();
- };
+ var downloadFail = function () {
+ unexpectedCallbacks.httpFail();
+ done();
+ };
- specContext.transfer.download(fileURL, specContext.localFilePath, downloadWin,downloadFail);
- }, DOWNLOAD_TIMEOUT);
+ specContext.transfer.download(fileURL, specContext.localFilePath, downloadWin, downloadFail);
+ },
+ DOWNLOAD_TIMEOUT
+ );
- it("filetransfer.spec.30 downloaded file entries should have a toNativeURL method", function (done) {
- if (cordova.platformId === "browser") {
- pending();
- return;
- }
-
- var fileURL = SERVER + "/robots.txt";
-
- var downloadWin = function (entry) {
-
- expect(entry.toNativeURL).toBeDefined();
- expect(entry.toNativeURL).toEqual(jasmine.any(Function));
-
- var nativeURL = entry.toNativeURL();
-
- expect(nativeURL).toBeTruthy();
- expect(nativeURL).toEqual(jasmine.any(String));
-
- if (isWindows) {
- expect(nativeURL.substring(0, 14)).toBe("ms-appdata:///");
- } else {
- expect(nativeURL.substring(0, 7)).toBe("file://");
+ it(
+ 'filetransfer.spec.30 downloaded file entries should have a toNativeURL method',
+ function (done) {
+ if (cordova.platformId === 'browser') {
+ pending();
+ return;
}
- done();
- };
+ var fileURL = SERVER + '/robots.txt';
- var downloadFail = function() {
- unexpectedCallbacks.httpFail();
- done();
- };
+ var downloadWin = function (entry) {
+ expect(entry.toNativeURL).toBeDefined();
+ expect(entry.toNativeURL).toEqual(jasmine.any(Function));
- this.transfer.download(fileURL, this.localFilePath, downloadWin, downloadFail);
- }, DOWNLOAD_TIMEOUT);
+ var nativeURL = entry.toNativeURL();
- it("filetransfer.spec.28 (compatibility) should be able to download a file using local paths", function (done) {
- var fileURL = SERVER + "/robots.txt";
+ expect(nativeURL).toBeTruthy();
+ expect(nativeURL).toEqual(jasmine.any(String));
+
+ if (isWindows) {
+ expect(nativeURL.substring(0, 14)).toBe('ms-appdata:///');
+ } else {
+ expect(nativeURL.substring(0, 7)).toBe('file://');
+ }
+
+ done();
+ };
+
+ var downloadFail = function () {
+ unexpectedCallbacks.httpFail();
+ done();
+ };
+
+ this.transfer.download(fileURL, this.localFilePath, downloadWin, downloadFail);
+ },
+ DOWNLOAD_TIMEOUT
+ );
+
+ it('filetransfer.spec.28 (compatibility) should be able to download a file using local paths', function (done) {
+ var fileURL = SERVER + '/robots.txt';
var specContext = this;
var unsupported = function (response) {
@@ -797,7 +846,7 @@
internalFilePath = specContext.localFilePath;
}
- var downloadFail = function() {
+ var downloadFail = function () {
unexpectedCallbacks.httpFail();
done();
};
@@ -806,149 +855,173 @@
// backwards compatibilty. By obtaining the raw filesystem path of the download
// location, we can pass that to transfer.download() to make sure that previously-stored
// paths are still valid.
- cordova.exec(function (localPath) {
- specContext.transfer.download(fileURL, localPath, downloadWin, downloadFail);
- }, unsupported, "File", "_getLocalFilesystemPath", [internalFilePath]);
+ cordova.exec(
+ function (localPath) {
+ specContext.transfer.download(fileURL, localPath, downloadWin, downloadFail);
+ },
+ unsupported,
+ 'File',
+ '_getLocalFilesystemPath',
+ [internalFilePath]
+ );
});
- it("filetransfer.spec.33 should properly handle 304", function (done) {
- var downloadFail = function (error) {
- expect(error.http_status).toBe(304);
- expect(error.code).toBe(FileTransferError.NOT_MODIFIED_ERR);
- done();
- };
-
- var downloadWin = function() {
- unexpectedCallbacks.httpWin();
- done();
- };
-
- this.transfer.download(SERVER + '/304', this.localFilePath, downloadWin, downloadFail);
- }, DOWNLOAD_TIMEOUT);
-
- it("filetransfer.spec.35 304 should not result in the deletion of a cached file", function (done) {
- var specContext = this;
-
- var fileOperationFail = function() {
- unexpectedCallbacks.fileOperationFail();
- done();
- };
-
- var fileSystemFail = function() {
- unexpectedCallbacks.fileSystemFail();
- done();
- };
-
- var httpWin = function() {
- unexpectedCallbacks.httpWin();
- done();
- };
-
- var downloadFail = function (error) {
- expect(error.http_status).toBe(304);
- expect(error.code).toBe(FileTransferError.NOT_MODIFIED_ERR);
-
- specContext.persistentRoot.getFile(specContext.fileName, { create: false },
- function (entry) {
- var fileWin = function (file) {
- var reader = new FileReader();
-
- reader.onerror = fileOperationFail;
- reader.onloadend = function () {
-
- expect(reader.result).toBeTruthy();
- if (reader.result !== null) {
- expect(reader.result.length).toBeGreaterThan(0);
- }
-
- done();
- };
-
- reader.readAsBinaryString(file);
- };
-
- entry.file(fileWin, fileSystemFail);
- },
- function (err) {
- expect("Could not open test file '" + specContext.fileName + "': " + JSON.stringify(err)).not.toBeDefined();
- done();
- }
- );
- };
-
- writeFile(specContext.root, specContext.fileName, 'Temp data', function () {
- specContext.transfer.download(SERVER + '/304', specContext.localFilePath, httpWin, downloadFail);
- }, fileOperationFail);
- }, DOWNLOAD_TIMEOUT);
-
- it("filetransfer.spec.36 should handle non-UTF8 encoded download response", function (done) {
- // Only iOS is supported: https://issues.apache.org/jira/browse/CB-9840
- if (!isIos) {
- pending();
- }
-
- var fileURL = SERVER + '/download_non_utf';
- var specContext = this;
-
- var fileOperationFail = function() {
- unexpectedCallbacks.fileOperationFail();
- done();
- };
-
- var fileSystemFail = function() {
- unexpectedCallbacks.fileSystemFail();
- done();
- };
-
- var httpFail = function() {
- unexpectedCallbacks.httpFail();
- done();
- };
-
- var fileWin = function (blob) {
-
- if (specContext.transfer.onprogress.calls.any()) {
- var lastProgressEvent = specContext.transfer.onprogress.calls.mostRecent().args[0];
- expect(lastProgressEvent.loaded).not.toBeGreaterThan(blob.size);
- } else {
- console.log("no progress events were emitted");
- }
-
- expect(blob.size).toBeGreaterThan(0);
-
- var reader = new FileReader();
-
- reader.onerror = fileOperationFail;
- reader.onloadend = function () {
- expect(reader.result.indexOf(LATIN1_SYMBOLS)).not.toBe(-1);
+ it(
+ 'filetransfer.spec.33 should properly handle 304',
+ function (done) {
+ var downloadFail = function (error) {
+ expect(error.http_status).toBe(304);
+ expect(error.code).toBe(FileTransferError.NOT_MODIFIED_ERR);
done();
};
- reader.readAsBinaryString(blob);
- };
+ var downloadWin = function () {
+ unexpectedCallbacks.httpWin();
+ done();
+ };
- var downloadWin = function (entry) {
+ this.transfer.download(SERVER + '/304', this.localFilePath, downloadWin, downloadFail);
+ },
+ DOWNLOAD_TIMEOUT
+ );
- verifyDownload(entry, specContext);
+ it(
+ 'filetransfer.spec.35 304 should not result in the deletion of a cached file',
+ function (done) {
+ var specContext = this;
- // verify the FileEntry representing this file
- entry.file(fileWin, fileSystemFail);
- };
+ var fileOperationFail = function () {
+ unexpectedCallbacks.fileOperationFail();
+ done();
+ };
- specContext.transfer.download(fileURL, specContext.localFilePath, downloadWin, httpFail);
- }, UPLOAD_TIMEOUT);
+ var fileSystemFail = function () {
+ unexpectedCallbacks.fileSystemFail();
+ done();
+ };
+
+ var httpWin = function () {
+ unexpectedCallbacks.httpWin();
+ done();
+ };
+
+ var downloadFail = function (error) {
+ expect(error.http_status).toBe(304);
+ expect(error.code).toBe(FileTransferError.NOT_MODIFIED_ERR);
+
+ specContext.persistentRoot.getFile(
+ specContext.fileName,
+ { create: false },
+ function (entry) {
+ var fileWin = function (file) {
+ var reader = new FileReader();
+
+ reader.onerror = fileOperationFail;
+ reader.onloadend = function () {
+ expect(reader.result).toBeTruthy();
+ if (reader.result !== null) {
+ expect(reader.result.length).toBeGreaterThan(0);
+ }
+
+ done();
+ };
+
+ reader.readAsBinaryString(file);
+ };
+
+ entry.file(fileWin, fileSystemFail);
+ },
+ function (err) {
+ expect(
+ "Could not open test file '" + specContext.fileName + "': " + JSON.stringify(err)
+ ).not.toBeDefined();
+ done();
+ }
+ );
+ };
+
+ writeFile(
+ specContext.root,
+ specContext.fileName,
+ 'Temp data',
+ function () {
+ specContext.transfer.download(SERVER + '/304', specContext.localFilePath, httpWin, downloadFail);
+ },
+ fileOperationFail
+ );
+ },
+ DOWNLOAD_TIMEOUT
+ );
+
+ it(
+ 'filetransfer.spec.36 should handle non-UTF8 encoded download response',
+ function (done) {
+ // Only iOS is supported: https://issues.apache.org/jira/browse/CB-9840
+ if (!isIos) {
+ pending();
+ }
+
+ var fileURL = SERVER + '/download_non_utf';
+ var specContext = this;
+
+ var fileOperationFail = function () {
+ unexpectedCallbacks.fileOperationFail();
+ done();
+ };
+
+ var fileSystemFail = function () {
+ unexpectedCallbacks.fileSystemFail();
+ done();
+ };
+
+ var httpFail = function () {
+ unexpectedCallbacks.httpFail();
+ done();
+ };
+
+ var fileWin = function (blob) {
+ if (specContext.transfer.onprogress.calls.any()) {
+ var lastProgressEvent = specContext.transfer.onprogress.calls.mostRecent().args[0];
+ expect(lastProgressEvent.loaded).not.toBeGreaterThan(blob.size);
+ } else {
+ console.log('no progress events were emitted');
+ }
+
+ expect(blob.size).toBeGreaterThan(0);
+
+ var reader = new FileReader();
+
+ reader.onerror = fileOperationFail;
+ reader.onloadend = function () {
+ expect(reader.result.indexOf(LATIN1_SYMBOLS)).not.toBe(-1);
+ done();
+ };
+
+ reader.readAsBinaryString(blob);
+ };
+
+ var downloadWin = function (entry) {
+ verifyDownload(entry, specContext);
+
+ // verify the FileEntry representing this file
+ entry.file(fileWin, fileSystemFail);
+ };
+
+ specContext.transfer.download(fileURL, specContext.localFilePath, downloadWin, httpFail);
+ },
+ UPLOAD_TIMEOUT
+ );
});
- describe("upload", function() {
- this.uploadParams = null;
- this.uploadOptions = null;
- this.fileName = null;
- this.fileContents = null;
- this.localFilePath = null;
+ describe('upload', function () {
+ this.uploadParams = null;
+ this.uploadOptions = null;
+ this.fileName = null;
+ this.fileContents = null;
+ this.localFilePath = null;
// helpers
var verifyUpload = function (uploadResult, specContext) {
-
expect(uploadResult.bytesSent).toBeGreaterThan(0);
expect(uploadResult.responseCode).toBe(200);
@@ -956,30 +1029,30 @@
try {
obj = JSON.parse(uploadResult.response);
expect(obj.fields).toBeDefined();
- expect(obj.fields.value1).toBe("test");
- expect(obj.fields.value2).toBe("param");
+ expect(obj.fields.value1).toBe('test');
+ expect(obj.fields.value2).toBe('param');
} catch (e) {
- expect(obj).not.toBeNull("returned data from server should be valid json");
+ expect(obj).not.toBeNull('returned data from server should be valid json');
}
expect(specContext.transfer.onprogress).toHaveBeenCalled();
};
- beforeEach(function(done) {
+ beforeEach(function (done) {
var specContext = this;
- specContext.fileName = "fileToUpload.txt";
- specContext.fileContents = "upload test file";
+ specContext.fileName = 'fileToUpload.txt';
+ specContext.fileContents = 'upload test file';
- specContext.uploadParams = {};
- specContext.uploadParams.value1 = "test";
- specContext.uploadParams.value2 = "param";
+ specContext.uploadParams = {};
+ specContext.uploadParams.value1 = 'test';
+ specContext.uploadParams.value2 = 'param';
- specContext.uploadOptions = new FileUploadOptions();
- specContext.uploadOptions.fileKey = "file";
+ specContext.uploadOptions = new FileUploadOptions();
+ specContext.uploadOptions.fileKey = 'file';
specContext.uploadOptions.fileName = specContext.fileName;
- specContext.uploadOptions.mimeType = "text/plain";
- specContext.uploadOptions.params = specContext.uploadParams;
+ specContext.uploadOptions.mimeType = 'text/plain';
+ specContext.uploadOptions.params = specContext.uploadParams;
var fileWin = function (entry) {
specContext.localFilePath = entry.toURL();
@@ -995,548 +1068,232 @@
deleteFile(this.root, this.fileName, done);
});
- it("filetransfer.spec.18 should be able to upload a file", function (done) {
- var fileURL = SERVER + "/upload";
- var specContext = this;
+ it(
+ 'filetransfer.spec.18 should be able to upload a file',
+ function (done) {
+ var fileURL = SERVER + '/upload';
+ var specContext = this;
- var uploadWin = function (uploadResult) {
+ var uploadWin = function (uploadResult) {
+ verifyUpload(uploadResult, specContext);
- verifyUpload(uploadResult, specContext);
+ 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.');
+ }
- 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();
- };
-
- var uploadFail = function() {
- unexpectedCallbacks.httpFail();
- done();
- };
-
- // NOTE: removing uploadOptions cause Android to timeout
- specContext.transfer.upload(specContext.localFilePath, fileURL, uploadWin, uploadFail, specContext.uploadOptions);
- }, UPLOAD_TIMEOUT);
-
- it("filetransfer.spec.19 should be able to upload a file with http basic auth", function (done) {
- var fileURL = SERVER_WITH_CREDENTIALS + "/upload_basic_auth";
- var specContext = this;
-
- var uploadWin = function (uploadResult) {
- verifyUpload(uploadResult, specContext);
- done();
- };
-
- var uploadFail = function() {
- unexpectedCallbacks.httpFail();
- done();
- };
-
- // NOTE: removing uploadOptions cause Android to timeout
- specContext.transfer.upload(specContext.localFilePath, fileURL, uploadWin, uploadFail, specContext.uploadOptions);
- }, UPLOAD_TIMEOUT);
-
- it("filetransfer.spec.21 should be stopped by abort()", function (done) {
- var fileURL = SERVER + "/upload";
- var specContext = this;
-
- var uploadFail = function (e) {
- expect(e.code).toBe(FileTransferError.ABORT_ERR);
-
- // delay calling done() to wait for the bogus abort()
- setTimeout(done, GRACE_TIME_DELTA * 2);
- };
-
- var uploadWin = function() {
- unexpectedCallbacks.httpWin();
- done();
- };
-
- var fileWin = function () {
-
- expect(specContext.transfer.abort).not.toThrow();
-
- // NOTE: removing uploadOptions cause Android to timeout
- specContext.transfer.upload(specContext.localFilePath, fileURL, uploadWin, uploadFail, specContext.uploadOptions);
- setTimeout(function() {
- specContext.transfer.abort();
- }, ABORT_DELAY);
-
- setTimeout(function () {
- expect(specContext.transfer.abort).not.toThrow();
- }, GRACE_TIME_DELTA);
- };
-
- // 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 && !isWindowsPhone) || isIos) ? 3000000 : isIot ? 150000 : 200000;
- writeFile(specContext.root, specContext.fileName, new Array(arrayLength).join("aborttest!"), fileWin, done);
- }, UPLOAD_TIMEOUT);
-
- it("filetransfer.spec.22 should get http status and body on failure", function (done) {
- var fileURL = SERVER + "/403";
- var retryCount = 0;
- var self = this;
-
- var uploadWin = function() {
- unexpectedCallbacks.httpWin();
- done();
- };
-
- var uploadFail = function (error) {
- if (error.http_status === 503 && ++retryCount <= RETRY_COUNT) {
- // Heroku often gives this error, retry in 1 second
- console.log('retrying... ' + retryCount);
- setTimeout(function () {
- self.transfer.upload(self.localFilePath, fileURL, uploadWin, uploadFail, self.uploadOptions);
- }, RETRY_INTERVAL);
- } else {
- expect(error.http_status).toBe(403);
- expect(error.http_status).not.toBe(401, "Ensure " + fileURL + " is in the white list");
done();
- }
- };
+ };
- self.transfer.upload(this.localFilePath, fileURL, uploadWin, uploadFail, this.uploadOptions);
- }, UPLOAD_TIMEOUT * 11);
-
- it("filetransfer.spec.24 should handle malformed urls", function (done) {
- var fileURL = getMalformedUrl();
-
- var uploadFail = function (error) {
- expect(error.code).toBe(FileTransferError.INVALID_URL_ERR);
- expect(error.http_status).not.toBe(401, "Ensure " + fileURL + " is in the white list");
- done();
- };
-
- var uploadWin = function() {
- unexpectedCallbacks.httpWin();
- done();
- };
-
- this.transfer.upload(this.localFilePath, fileURL, uploadWin, uploadFail, {});
- });
-
- it("filetransfer.spec.25 should handle unknown host", function (done) {
- var fileURL = UNKNOWN_HOST;
-
- var uploadFail = function (error) {
- expect(error.code).toBe(FileTransferError.CONNECTION_ERR);
- expect(error.http_status).not.toBe(401, "Ensure " + fileURL + " is in the white list");
- done();
- };
-
- var uploadWin = function() {
- unexpectedCallbacks.httpWin();
- done();
- };
-
- this.transfer.upload(this.localFilePath, fileURL, uploadWin, uploadFail, {});
- }, UPLOAD_TIMEOUT);
-
- it("filetransfer.spec.25 should handle missing file", function (done) {
- var fileURL = SERVER + "/upload";
-
- var uploadFail = function (error) {
- expect(error.code).toBe(FileTransferError.FILE_NOT_FOUND_ERR);
- expect(error.http_status).not.toBe(401, "Ensure " + fileURL + " is in the white list");
- done();
- };
-
- var uploadWin = function() {
- unexpectedCallbacks.httpWin();
- done();
- };
-
- this.transfer.upload("does_not_exist.txt", fileURL, uploadWin, uploadFail);
- }, UPLOAD_TIMEOUT);
-
- it("filetransfer.spec.26 should handle bad file path", function (done) {
- var fileURL = SERVER + "/upload";
-
- var uploadFail = function (error) {
- expect(error.http_status).not.toBe(401, "Ensure " + fileURL + " is in the white list");
- done();
- };
-
- var uploadWin = function() {
- unexpectedCallbacks.httpWin();
- done();
- };
-
- this.transfer.upload("c:\\54321", fileURL, uploadWin, uploadFail);
- });
-
- it("filetransfer.spec.27 should be able to set custom headers", function (done) {
- var fileURL = SERVER + '/upload_echo_headers';
- var retryCount = 0;
- var self = this;
-
- var uploadWin = function (uploadResult) {
-
- expect(uploadResult.bytesSent).toBeGreaterThan(0);
- expect(uploadResult.responseCode).toBe(200);
- expect(uploadResult.response).toBeDefined();
-
- var responseHtml = decodeURIComponent(uploadResult.response);
-
- expect(responseHtml).toMatch(/CustomHeader1[\s\S]*CustomValue1/i);
- expect(responseHtml).toMatch(/CustomHeader2[\s\S]*CustomValue2[\s\S]*CustomValue3/i, "Should allow array values");
-
- done();
- };
-
- var uploadFail = function() {
- if (++retryCount >= RETRY_COUNT) {
+ var uploadFail = function () {
unexpectedCallbacks.httpFail();
done();
- } else {
- console.log('retrying... ' + retryCount);
- setTimeout(function () {
- // NOTE: removing uploadOptions will cause Android to timeout
- self.transfer.upload(self.localFilePath, fileURL, uploadWin, uploadFail, self.uploadOptions);
- }, RETRY_INTERVAL);
- }
- };
-
- this.uploadOptions.headers = {
- "CustomHeader1": "CustomValue1",
- "CustomHeader2": ["CustomValue2", "CustomValue3"],
- };
-
- // http://whatheaders.com does not support Transfer-Encoding: chunked
- this.uploadOptions.chunkedMode = false;
-
- // NOTE: removing uploadOptions cause Android to timeout
- this.transfer.upload(this.localFilePath, fileURL, uploadWin, uploadFail, this.uploadOptions);
- }, UPLOAD_TIMEOUT * 11);
-
- it("filetransfer.spec.29 (compatibility) should be able to upload a file using local paths", function (done) {
- var fileURL = SERVER + "/upload";
- var specContext = this;
-
- var unsupported = function (response) {
- expectedCallbacks.unsupportedOperation(response);
- done();
- };
-
- var uploadWin = function (uploadResult) {
- verifyUpload(uploadResult, specContext);
- done();
- };
-
- var uploadFail = function() {
- unexpectedCallbacks.httpFail();
- done();
- };
-
- var internalFilePath;
- if (specContext.root.toInternalURL) {
- internalFilePath = specContext.root.toInternalURL() + specContext.fileName;
- } else {
- internalFilePath = specContext.localFilePath;
- }
-
- // This is an undocumented interface to File which exists only for testing
- // backwards compatibilty. By obtaining the raw filesystem path of the download
- // location, we can pass that to transfer.download() to make sure that previously-stored
- // paths are still valid.
- cordova.exec(function (localPath) {
- specContext.transfer.upload(localPath, fileURL, uploadWin, uploadFail, specContext.uploadOptions);
- }, unsupported, "File", "_getLocalFilesystemPath", [internalFilePath]);
- }, UPLOAD_TIMEOUT);
-
- it("filetransfer.spec.31 should be able to upload a file using PUT method", function (done) {
- var fileURL = SERVER + "/upload";
- var specContext = this;
-
- var uploadWin = function (uploadResult) {
-
- verifyUpload(uploadResult, specContext);
-
- 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();
- };
-
- var uploadFail = function() {
- unexpectedCallbacks.httpFail();
- done();
- };
-
- specContext.uploadOptions.httpMethod = "PUT";
-
- // NOTE: removing uploadOptions cause Android to timeout
- specContext.transfer.upload(specContext.localFilePath, fileURL, uploadWin, uploadFail, specContext.uploadOptions);
- }, UPLOAD_TIMEOUT);
-
- it("filetransfer.spec.32 should be able to upload a file (non-multipart)", function (done) {
- var fileURL = SERVER + "/upload";
- var specContext = this;
-
- 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(specContext.fileContents + "\n");
- }
- expect(specContext.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();
- };
-
- var uploadFail = function() {
- unexpectedCallbacks.httpFail();
- done();
- };
-
- // Content-Type header disables multipart
- specContext.uploadOptions.headers = {
- "Content-Type": "text/plain"
- };
-
- // NOTE: removing uploadOptions cause Android to timeout
- specContext.transfer.upload(specContext.localFilePath, fileURL, uploadWin, uploadFail, specContext.uploadOptions);
- }, UPLOAD_TIMEOUT);
-
- it("filetransfer.spec.34 should not delete a file on upload error", function (done) {
-
- var fileURL = SERVER + "/upload";
- var specContext = this;
-
- var uploadFail = function (e) {
- expect(e.code).toBe(FileTransferError.ABORT_ERR);
-
- // check that the file is there
- specContext.root.getFile(specContext.fileName, null, function(entry) {
- expect(entry).toBeDefined();
- // delay calling done() to wait for the bogus abort()
- setTimeout(done, GRACE_TIME_DELTA * 2);
- }, function(err) {
- expect(err).not.toBeDefined(err && err.code);
- done();
- });
- };
-
- var uploadWin = function() {
- unexpectedCallbacks.httpWin();
- done();
- };
-
- var fileWin = function () {
-
- expect(specContext.transfer.abort).not.toThrow();
-
- // abort at the first onprogress event
- specContext.transfer.onprogress = function (event) {
- if (event.loaded > 0) {
- specContext.transfer.abort();
- }
};
// NOTE: removing uploadOptions cause Android to timeout
specContext.transfer.upload(specContext.localFilePath, fileURL, uploadWin, uploadFail, specContext.uploadOptions);
- };
+ },
+ UPLOAD_TIMEOUT
+ );
- writeFile(specContext.root, specContext.fileName, new Array(100000).join("aborttest!"), fileWin, done);
- }, UPLOAD_TIMEOUT);
-
- it("filetransfer.spec.37 should handle non-UTF8 encoded upload response", function (done) {
- // Only iOS is supported: https://issues.apache.org/jira/browse/CB-9840
- if (!isIos) {
- pending();
- }
-
- var fileURL = SERVER + '/upload_non_utf';
- var specContext = this;
-
- var uploadWin = function (uploadResult) {
-
- verifyUpload(uploadResult, specContext);
-
- var obj = null;
- try {
- obj = JSON.parse(uploadResult.response);
- expect(obj.latin1Symbols).toBe(LATIN1_SYMBOLS);
- } catch (e) {
- expect(obj).not.toBeNull("returned data from server should be valid json");
- }
-
- 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();
- };
-
- var uploadFail = function() {
- unexpectedCallbacks.httpFail();
- done();
- };
-
- // NOTE: removing uploadOptions cause Android to timeout
- specContext.transfer.upload(specContext.localFilePath, fileURL, uploadWin, uploadFail, specContext.uploadOptions);
- }, UPLOAD_TIMEOUT);
-
- it("filetransfer.spec.38 should be able to upload a file using data: source uri", function (done) {
- var fileURL = SERVER + "/upload";
- var specContext = this;
-
- var uploadWin = function (uploadResult) {
-
- verifyUpload(uploadResult,specContext);
-
- var obj = null;
- try {
- obj = JSON.parse(uploadResult.response);
- expect(obj.files.file.size).toBe(DATA_URI_CONTENT_LENGTH);
- } catch (e) {
- expect(obj).not.toBeNull("returned data from server should be valid json");
- }
-
- 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();
- };
-
- var dataUri = DATA_URI_PREFIX + DATA_URI_CONTENT;
- // NOTE: removing uploadOptions cause Android to timeout
- specContext.transfer.upload(dataUri, fileURL, uploadWin, function (err) {
- console.error('err: ' + JSON.stringify(err));
- expect(err).not.toBeDefined();
- done();
- }, specContext.uploadOptions);
- }, UPLOAD_TIMEOUT);
-
- it("filetransfer.spec.39 should be able to upload a file using data: source uri (non-multipart)", function (done) {
- var fileURL = SERVER + "/upload";
-
- var uploadWin = function (uploadResult) {
-
- expect(uploadResult.responseCode).toBe(200);
- expect(uploadResult.bytesSent).toBeGreaterThan(0);
-
- 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();
- };
-
- var uploadFail = function() {
- unexpectedCallbacks.httpFail();
- done();
- };
-
- // Content-Type header disables multipart
- this.uploadOptions.headers = {
- "Content-Type": "image/png"
- };
-
- var dataUri = DATA_URI_PREFIX + DATA_URI_CONTENT;
- // NOTE: removing uploadOptions cause Android to timeout
- this.transfer.upload(dataUri, fileURL, uploadWin, uploadFail, this.uploadOptions);
- }, UPLOAD_TIMEOUT);
-
- it("filetransfer.spec.40 should not fail to upload a file using data: source uri when the data is empty", function (done) {
- var fileURL = SERVER + "/upload";
-
- var dataUri = DATA_URI_PREFIX;
-
- var uploadFail = function() {
- unexpectedCallbacks.httpFail();
- done();
- };
-
- // NOTE: removing uploadOptions cause Android to timeout
- this.transfer.upload(dataUri, fileURL, done, uploadFail, this.uploadOptions);
- }, UPLOAD_TIMEOUT);
-
- it("filetransfer.spec.41 should not fail to upload a file using data: source uri when the data is empty (non-multipart)", function (done) {
- if (isIos) {
- // iOS does not support uploads of an empty file with __chunkedMode=true__ and `multipartMode=false`:
- // request body will be empty in this case instead of 0\n\n.
- pending();
- }
- var fileURL = SERVER + "/upload";
-
- // Content-Type header disables multipart
- this.uploadOptions.headers = {
- "Content-Type": "image/png"
- };
-
- // turn off the onprogress handler
- this.transfer.onprogress = function () { };
-
- var dataUri = DATA_URI_PREFIX;
-
- var uploadFail = function() {
- unexpectedCallbacks.httpFail();
- done();
- };
-
- // NOTE: removing uploadOptions cause Android to timeout
- this.transfer.upload(dataUri, fileURL, done, uploadFail, this.uploadOptions);
- }, UPLOAD_TIMEOUT);
-
- describe("chunkedMode handling", function() {
- var testChunkedModeWin = function (uploadResult, specContext) {
- var multipartModeEnabled = !(specContext.uploadOptions.headers && specContext.uploadOptions.headers["Content-Type"]);
- var obj = null;
- try {
- obj = JSON.parse(uploadResult.response);
-
- if (specContext.uploadOptions.chunkedMode) {
- if (!isIos) {
- expect(obj["content-length"]).not.toBeDefined("Expected Content-Length not to be defined");
- }
- expect(obj["transfer-encoding"].toLowerCase()).toEqual("chunked");
- } else {
- expect(obj["content-length"]).toBeDefined("Expected Content-Length to be defined");
- expect(obj["transfer-encoding"].toLowerCase()).not.toEqual("chunked");
- }
-
- if (multipartModeEnabled) {
- expect(obj["content-type"].indexOf("multipart/form-data")).not.toBe(-1);
- } else {
- expect(obj["content-type"].indexOf("multipart/form-data")).toBe(-1);
- }
- } catch (e) {
- expect(obj).not.toBeNull("returned data from server should be valid json");
- }
- };
-
- var testChunkedModeBase = function(chunkedMode, multipart, done) {
- var retryCount = 0;
- var fileURL = SERVER + "/upload_echo_headers";
+ it(
+ 'filetransfer.spec.19 should be able to upload a file with http basic auth',
+ function (done) {
+ var fileURL = SERVER_WITH_CREDENTIALS + '/upload_basic_auth';
var specContext = this;
- specContext.uploadOptions.chunkedMode = chunkedMode;
- if (!multipart) {
- // Content-Type header disables multipart
- specContext.uploadOptions.headers = {
- "Content-Type": "text/plain"
- };
- }
+ var uploadWin = function (uploadResult) {
+ verifyUpload(uploadResult, specContext);
+ done();
+ };
- var uploadFail = function() {
+ var uploadFail = function () {
+ unexpectedCallbacks.httpFail();
+ done();
+ };
+
+ // NOTE: removing uploadOptions cause Android to timeout
+ specContext.transfer.upload(specContext.localFilePath, fileURL, uploadWin, uploadFail, specContext.uploadOptions);
+ },
+ UPLOAD_TIMEOUT
+ );
+
+ it(
+ 'filetransfer.spec.21 should be stopped by abort()',
+ function (done) {
+ var fileURL = SERVER + '/upload';
+ var specContext = this;
+
+ var uploadFail = function (e) {
+ expect(e.code).toBe(FileTransferError.ABORT_ERR);
+
+ // delay calling done() to wait for the bogus abort()
+ setTimeout(done, GRACE_TIME_DELTA * 2);
+ };
+
+ var uploadWin = function () {
+ unexpectedCallbacks.httpWin();
+ done();
+ };
+
+ var fileWin = function () {
+ expect(specContext.transfer.abort).not.toThrow();
+
+ // NOTE: removing uploadOptions cause Android to timeout
+ specContext.transfer.upload(
+ specContext.localFilePath,
+ fileURL,
+ uploadWin,
+ uploadFail,
+ specContext.uploadOptions
+ );
+ setTimeout(function () {
+ specContext.transfer.abort();
+ }, ABORT_DELAY);
+
+ setTimeout(function () {
+ expect(specContext.transfer.abort).not.toThrow();
+ }, GRACE_TIME_DELTA);
+ };
+
+ // 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 && !isWindowsPhone) || isIos ? 3000000 : isIot ? 150000 : 200000;
+ writeFile(specContext.root, specContext.fileName, new Array(arrayLength).join('aborttest!'), fileWin, done);
+ },
+ UPLOAD_TIMEOUT
+ );
+
+ it(
+ 'filetransfer.spec.22 should get http status and body on failure',
+ function (done) {
+ var fileURL = SERVER + '/403';
+ var retryCount = 0;
+ var self = this;
+
+ var uploadWin = function () {
+ unexpectedCallbacks.httpWin();
+ done();
+ };
+
+ var uploadFail = function (error) {
+ if (error.http_status === 503 && ++retryCount <= RETRY_COUNT) {
+ // Heroku often gives this error, retry in 1 second
+ console.log('retrying... ' + retryCount);
+ setTimeout(function () {
+ self.transfer.upload(self.localFilePath, fileURL, uploadWin, uploadFail, self.uploadOptions);
+ }, RETRY_INTERVAL);
+ } else {
+ expect(error.http_status).toBe(403);
+ expect(error.http_status).not.toBe(401, 'Ensure ' + fileURL + ' is in the white list');
+ done();
+ }
+ };
+
+ self.transfer.upload(this.localFilePath, fileURL, uploadWin, uploadFail, this.uploadOptions);
+ },
+ UPLOAD_TIMEOUT * 11
+ );
+
+ it('filetransfer.spec.24 should handle malformed urls', function (done) {
+ var fileURL = getMalformedUrl();
+
+ var uploadFail = function (error) {
+ expect(error.code).toBe(FileTransferError.INVALID_URL_ERR);
+ expect(error.http_status).not.toBe(401, 'Ensure ' + fileURL + ' is in the white list');
+ done();
+ };
+
+ var uploadWin = function () {
+ unexpectedCallbacks.httpWin();
+ done();
+ };
+
+ this.transfer.upload(this.localFilePath, fileURL, uploadWin, uploadFail, {});
+ });
+
+ it(
+ 'filetransfer.spec.25 should handle unknown host',
+ function (done) {
+ var fileURL = UNKNOWN_HOST;
+
+ var uploadFail = function (error) {
+ expect(error.code).toBe(FileTransferError.CONNECTION_ERR);
+ expect(error.http_status).not.toBe(401, 'Ensure ' + fileURL + ' is in the white list');
+ done();
+ };
+
+ var uploadWin = function () {
+ unexpectedCallbacks.httpWin();
+ done();
+ };
+
+ this.transfer.upload(this.localFilePath, fileURL, uploadWin, uploadFail, {});
+ },
+ UPLOAD_TIMEOUT
+ );
+
+ it(
+ 'filetransfer.spec.25 should handle missing file',
+ function (done) {
+ var fileURL = SERVER + '/upload';
+
+ var uploadFail = function (error) {
+ expect(error.code).toBe(FileTransferError.FILE_NOT_FOUND_ERR);
+ expect(error.http_status).not.toBe(401, 'Ensure ' + fileURL + ' is in the white list');
+ done();
+ };
+
+ var uploadWin = function () {
+ unexpectedCallbacks.httpWin();
+ done();
+ };
+
+ this.transfer.upload('does_not_exist.txt', fileURL, uploadWin, uploadFail);
+ },
+ UPLOAD_TIMEOUT
+ );
+
+ it('filetransfer.spec.26 should handle bad file path', function (done) {
+ var fileURL = SERVER + '/upload';
+
+ var uploadFail = function (error) {
+ expect(error.http_status).not.toBe(401, 'Ensure ' + fileURL + ' is in the white list');
+ done();
+ };
+
+ var uploadWin = function () {
+ unexpectedCallbacks.httpWin();
+ done();
+ };
+
+ this.transfer.upload('c:\\54321', fileURL, uploadWin, uploadFail);
+ });
+
+ it(
+ 'filetransfer.spec.27 should be able to set custom headers',
+ function (done) {
+ var fileURL = SERVER + '/upload_echo_headers';
+ var retryCount = 0;
+ var self = this;
+
+ var uploadWin = function (uploadResult) {
+ expect(uploadResult.bytesSent).toBeGreaterThan(0);
+ expect(uploadResult.responseCode).toBe(200);
+ expect(uploadResult.response).toBeDefined();
+
+ var responseHtml = decodeURIComponent(uploadResult.response);
+
+ expect(responseHtml).toMatch(/CustomHeader1[\s\S]*CustomValue1/i);
+ expect(responseHtml).toMatch(
+ /CustomHeader2[\s\S]*CustomValue2[\s\S]*CustomValue3/i,
+ 'Should allow array values'
+ );
+
+ done();
+ };
+
+ var uploadFail = function () {
if (++retryCount >= RETRY_COUNT) {
unexpectedCallbacks.httpFail();
done();
@@ -1544,10 +1301,420 @@
console.log('retrying... ' + retryCount);
setTimeout(function () {
// NOTE: removing uploadOptions will cause Android to timeout
- specContext.transfer.upload(specContext.localFilePath, fileURL, function (uploadResult) {
- testChunkedModeWin(uploadResult, specContext);
- done();
- }, uploadFail, specContext.uploadOptions);
+ self.transfer.upload(self.localFilePath, fileURL, uploadWin, uploadFail, self.uploadOptions);
+ }, RETRY_INTERVAL);
+ }
+ };
+
+ this.uploadOptions.headers = {
+ CustomHeader1: 'CustomValue1',
+ CustomHeader2: ['CustomValue2', 'CustomValue3']
+ };
+
+ // http://whatheaders.com does not support Transfer-Encoding: chunked
+ this.uploadOptions.chunkedMode = false;
+
+ // NOTE: removing uploadOptions cause Android to timeout
+ this.transfer.upload(this.localFilePath, fileURL, uploadWin, uploadFail, this.uploadOptions);
+ },
+ UPLOAD_TIMEOUT * 11
+ );
+
+ it(
+ 'filetransfer.spec.29 (compatibility) should be able to upload a file using local paths',
+ function (done) {
+ var fileURL = SERVER + '/upload';
+ var specContext = this;
+
+ var unsupported = function (response) {
+ expectedCallbacks.unsupportedOperation(response);
+ done();
+ };
+
+ var uploadWin = function (uploadResult) {
+ verifyUpload(uploadResult, specContext);
+ done();
+ };
+
+ var uploadFail = function () {
+ unexpectedCallbacks.httpFail();
+ done();
+ };
+
+ var internalFilePath;
+ if (specContext.root.toInternalURL) {
+ internalFilePath = specContext.root.toInternalURL() + specContext.fileName;
+ } else {
+ internalFilePath = specContext.localFilePath;
+ }
+
+ // This is an undocumented interface to File which exists only for testing
+ // backwards compatibilty. By obtaining the raw filesystem path of the download
+ // location, we can pass that to transfer.download() to make sure that previously-stored
+ // paths are still valid.
+ cordova.exec(
+ function (localPath) {
+ specContext.transfer.upload(localPath, fileURL, uploadWin, uploadFail, specContext.uploadOptions);
+ },
+ unsupported,
+ 'File',
+ '_getLocalFilesystemPath',
+ [internalFilePath]
+ );
+ },
+ UPLOAD_TIMEOUT
+ );
+
+ it(
+ 'filetransfer.spec.31 should be able to upload a file using PUT method',
+ function (done) {
+ var fileURL = SERVER + '/upload';
+ var specContext = this;
+
+ var uploadWin = function (uploadResult) {
+ verifyUpload(uploadResult, specContext);
+
+ 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();
+ };
+
+ var uploadFail = function () {
+ unexpectedCallbacks.httpFail();
+ done();
+ };
+
+ specContext.uploadOptions.httpMethod = 'PUT';
+
+ // NOTE: removing uploadOptions cause Android to timeout
+ specContext.transfer.upload(specContext.localFilePath, fileURL, uploadWin, uploadFail, specContext.uploadOptions);
+ },
+ UPLOAD_TIMEOUT
+ );
+
+ it(
+ 'filetransfer.spec.32 should be able to upload a file (non-multipart)',
+ function (done) {
+ var fileURL = SERVER + '/upload';
+ var specContext = this;
+
+ 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(specContext.fileContents + '\n');
+ }
+ expect(specContext.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();
+ };
+
+ var uploadFail = function () {
+ unexpectedCallbacks.httpFail();
+ done();
+ };
+
+ // Content-Type header disables multipart
+ specContext.uploadOptions.headers = {
+ 'Content-Type': 'text/plain'
+ };
+
+ // NOTE: removing uploadOptions cause Android to timeout
+ specContext.transfer.upload(specContext.localFilePath, fileURL, uploadWin, uploadFail, specContext.uploadOptions);
+ },
+ UPLOAD_TIMEOUT
+ );
+
+ it(
+ 'filetransfer.spec.34 should not delete a file on upload error',
+ function (done) {
+ var fileURL = SERVER + '/upload';
+ var specContext = this;
+
+ var uploadFail = function (e) {
+ expect(e.code).toBe(FileTransferError.ABORT_ERR);
+
+ // check that the file is there
+ specContext.root.getFile(
+ specContext.fileName,
+ null,
+ function (entry) {
+ expect(entry).toBeDefined();
+ // delay calling done() to wait for the bogus abort()
+ setTimeout(done, GRACE_TIME_DELTA * 2);
+ },
+ function (err) {
+ expect(err).not.toBeDefined(err && err.code);
+ done();
+ }
+ );
+ };
+
+ var uploadWin = function () {
+ unexpectedCallbacks.httpWin();
+ done();
+ };
+
+ var fileWin = function () {
+ expect(specContext.transfer.abort).not.toThrow();
+
+ // abort at the first onprogress event
+ specContext.transfer.onprogress = function (event) {
+ if (event.loaded > 0) {
+ specContext.transfer.abort();
+ }
+ };
+
+ // NOTE: removing uploadOptions cause Android to timeout
+ specContext.transfer.upload(
+ specContext.localFilePath,
+ fileURL,
+ uploadWin,
+ uploadFail,
+ specContext.uploadOptions
+ );
+ };
+
+ writeFile(specContext.root, specContext.fileName, new Array(100000).join('aborttest!'), fileWin, done);
+ },
+ UPLOAD_TIMEOUT
+ );
+
+ it(
+ 'filetransfer.spec.37 should handle non-UTF8 encoded upload response',
+ function (done) {
+ // Only iOS is supported: https://issues.apache.org/jira/browse/CB-9840
+ if (!isIos) {
+ pending();
+ }
+
+ var fileURL = SERVER + '/upload_non_utf';
+ var specContext = this;
+
+ var uploadWin = function (uploadResult) {
+ verifyUpload(uploadResult, specContext);
+
+ var obj = null;
+ try {
+ obj = JSON.parse(uploadResult.response);
+ expect(obj.latin1Symbols).toBe(LATIN1_SYMBOLS);
+ } catch (e) {
+ expect(obj).not.toBeNull('returned data from server should be valid json');
+ }
+
+ 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();
+ };
+
+ var uploadFail = function () {
+ unexpectedCallbacks.httpFail();
+ done();
+ };
+
+ // NOTE: removing uploadOptions cause Android to timeout
+ specContext.transfer.upload(specContext.localFilePath, fileURL, uploadWin, uploadFail, specContext.uploadOptions);
+ },
+ UPLOAD_TIMEOUT
+ );
+
+ it(
+ 'filetransfer.spec.38 should be able to upload a file using data: source uri',
+ function (done) {
+ var fileURL = SERVER + '/upload';
+ var specContext = this;
+
+ var uploadWin = function (uploadResult) {
+ verifyUpload(uploadResult, specContext);
+
+ var obj = null;
+ try {
+ obj = JSON.parse(uploadResult.response);
+ expect(obj.files.file.size).toBe(DATA_URI_CONTENT_LENGTH);
+ } catch (e) {
+ expect(obj).not.toBeNull('returned data from server should be valid json');
+ }
+
+ 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();
+ };
+
+ var dataUri = DATA_URI_PREFIX + DATA_URI_CONTENT;
+ // NOTE: removing uploadOptions cause Android to timeout
+ specContext.transfer.upload(
+ dataUri,
+ fileURL,
+ uploadWin,
+ function (err) {
+ console.error('err: ' + JSON.stringify(err));
+ expect(err).not.toBeDefined();
+ done();
+ },
+ specContext.uploadOptions
+ );
+ },
+ UPLOAD_TIMEOUT
+ );
+
+ it(
+ 'filetransfer.spec.39 should be able to upload a file using data: source uri (non-multipart)',
+ function (done) {
+ var fileURL = SERVER + '/upload';
+
+ var uploadWin = function (uploadResult) {
+ expect(uploadResult.responseCode).toBe(200);
+ expect(uploadResult.bytesSent).toBeGreaterThan(0);
+
+ 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();
+ };
+
+ var uploadFail = function () {
+ unexpectedCallbacks.httpFail();
+ done();
+ };
+
+ // Content-Type header disables multipart
+ this.uploadOptions.headers = {
+ 'Content-Type': 'image/png'
+ };
+
+ var dataUri = DATA_URI_PREFIX + DATA_URI_CONTENT;
+ // NOTE: removing uploadOptions cause Android to timeout
+ this.transfer.upload(dataUri, fileURL, uploadWin, uploadFail, this.uploadOptions);
+ },
+ UPLOAD_TIMEOUT
+ );
+
+ it(
+ 'filetransfer.spec.40 should not fail to upload a file using data: source uri when the data is empty',
+ function (done) {
+ var fileURL = SERVER + '/upload';
+
+ var dataUri = DATA_URI_PREFIX;
+
+ var uploadFail = function () {
+ unexpectedCallbacks.httpFail();
+ done();
+ };
+
+ // NOTE: removing uploadOptions cause Android to timeout
+ this.transfer.upload(dataUri, fileURL, done, uploadFail, this.uploadOptions);
+ },
+ UPLOAD_TIMEOUT
+ );
+
+ it(
+ 'filetransfer.spec.41 should not fail to upload a file using data: source uri when the data is empty (non-multipart)',
+ function (done) {
+ if (isIos) {
+ // iOS does not support uploads of an empty file with __chunkedMode=true__ and `multipartMode=false`:
+ // request body will be empty in this case instead of 0\n\n.
+ pending();
+ }
+ var fileURL = SERVER + '/upload';
+
+ // Content-Type header disables multipart
+ this.uploadOptions.headers = {
+ 'Content-Type': 'image/png'
+ };
+
+ // turn off the onprogress handler
+ this.transfer.onprogress = function () {};
+
+ var dataUri = DATA_URI_PREFIX;
+
+ var uploadFail = function () {
+ unexpectedCallbacks.httpFail();
+ done();
+ };
+
+ // NOTE: removing uploadOptions cause Android to timeout
+ this.transfer.upload(dataUri, fileURL, done, uploadFail, this.uploadOptions);
+ },
+ UPLOAD_TIMEOUT
+ );
+
+ describe('chunkedMode handling', function () {
+ var testChunkedModeWin = function (uploadResult, specContext) {
+ var multipartModeEnabled = !(
+ specContext.uploadOptions.headers && specContext.uploadOptions.headers['Content-Type']
+ );
+ var obj = null;
+ try {
+ obj = JSON.parse(uploadResult.response);
+
+ if (specContext.uploadOptions.chunkedMode) {
+ if (!isIos) {
+ expect(obj['content-length']).not.toBeDefined('Expected Content-Length not to be defined');
+ }
+ expect(obj['transfer-encoding'].toLowerCase()).toEqual('chunked');
+ } else {
+ expect(obj['content-length']).toBeDefined('Expected Content-Length to be defined');
+ expect(obj['transfer-encoding'].toLowerCase()).not.toEqual('chunked');
+ }
+
+ if (multipartModeEnabled) {
+ expect(obj['content-type'].indexOf('multipart/form-data')).not.toBe(-1);
+ } else {
+ expect(obj['content-type'].indexOf('multipart/form-data')).toBe(-1);
+ }
+ } catch (e) {
+ expect(obj).not.toBeNull('returned data from server should be valid json');
+ }
+ };
+
+ var testChunkedModeBase = function (chunkedMode, multipart, done) {
+ var retryCount = 0;
+ var fileURL = SERVER + '/upload_echo_headers';
+ var specContext = this;
+
+ specContext.uploadOptions.chunkedMode = chunkedMode;
+ if (!multipart) {
+ // Content-Type header disables multipart
+ specContext.uploadOptions.headers = {
+ 'Content-Type': 'text/plain'
+ };
+ }
+
+ var uploadFail = function () {
+ if (++retryCount >= RETRY_COUNT) {
+ unexpectedCallbacks.httpFail();
+ done();
+ } else {
+ console.log('retrying... ' + retryCount);
+ setTimeout(function () {
+ // NOTE: removing uploadOptions will cause Android to timeout
+ specContext.transfer.upload(
+ specContext.localFilePath,
+ fileURL,
+ function (uploadResult) {
+ testChunkedModeWin(uploadResult, specContext);
+ done();
+ },
+ uploadFail,
+ specContext.uploadOptions
+ );
}, RETRY_INTERVAL);
}
};
@@ -1556,37 +1723,55 @@
this.transfer.onprogress = function () {};
// NOTE: removing uploadOptions cause Android to timeout
- specContext.transfer.upload(specContext.localFilePath, fileURL, function (uploadResult) {
- testChunkedModeWin(uploadResult, specContext);
- done();
- }, uploadFail, specContext.uploadOptions);
+ specContext.transfer.upload(
+ specContext.localFilePath,
+ fileURL,
+ function (uploadResult) {
+ testChunkedModeWin(uploadResult, specContext);
+ done();
+ },
+ uploadFail,
+ specContext.uploadOptions
+ );
};
- it("filetransfer.spec.42 chunkedMode=false, multipart=false", function (done) {
+ it(
+ 'filetransfer.spec.42 chunkedMode=false, multipart=false',
+ function (done) {
+ testChunkedModeBase.call(this, false, false, done);
+ },
+ UPLOAD_TIMEOUT * 11
+ );
- testChunkedModeBase.call(this, false, false, done);
- }, UPLOAD_TIMEOUT * 11);
+ it(
+ 'filetransfer.spec.43 chunkedMode=true, multipart=false',
+ function (done) {
+ if (isWindows) {
+ pending();
+ }
+ testChunkedModeBase.call(this, true, false, done);
+ },
+ UPLOAD_TIMEOUT * 11
+ );
- it("filetransfer.spec.43 chunkedMode=true, multipart=false", function (done) {
+ it(
+ 'filetransfer.spec.44 chunkedMode=false, multipart=true',
+ function (done) {
+ testChunkedModeBase.call(this, false, true, done);
+ },
+ UPLOAD_TIMEOUT * 11
+ );
- if (isWindows) {
- pending();
- }
- testChunkedModeBase.call(this, true, false, done);
- }, UPLOAD_TIMEOUT * 11);
-
- it("filetransfer.spec.44 chunkedMode=false, multipart=true", function (done) {
-
- testChunkedModeBase.call(this, false, true, done);
- }, UPLOAD_TIMEOUT * 11);
-
- it("filetransfer.spec.45 chunkedMode=true, multipart=true", function (done) {
-
- if (isWindows) {
- pending();
- }
- testChunkedModeBase.call(this, true, true, done);
- }, UPLOAD_TIMEOUT * 11);
+ it(
+ 'filetransfer.spec.45 chunkedMode=true, multipart=true',
+ function (done) {
+ if (isWindows) {
+ pending();
+ }
+ testChunkedModeBase.call(this, true, true, done);
+ },
+ UPLOAD_TIMEOUT * 11
+ );
});
});
});
@@ -1598,29 +1783,28 @@
/******************************************************************************/
exports.defineManualTests = function (contentEl, createActionButton) {
+ 'use strict';
- "use strict";
+ var imageURL = 'http://apache.org/images/feather-small.gif';
+ var videoURL = 'http://techslides.com/demos/sample-videos/small.mp4';
- var imageURL = "http://apache.org/images/feather-small.gif";
- var videoURL = "http://techslides.com/demos/sample-videos/small.mp4";
-
- function clearResults() {
- var results = document.getElementById("info");
- results.innerHTML = "";
+ function clearResults () {
+ var results = document.getElementById('info');
+ results.innerHTML = '';
}
- function downloadImg(source, urlFn, element, directory) {
- var filename = source.substring(source.lastIndexOf("/") + 1);
- filename = (directory || "") + filename;
+ function downloadImg (source, urlFn, element, directory) {
+ var filename = source.substring(source.lastIndexOf('/') + 1);
+ filename = (directory || '') + filename;
- function download(fileSystem) {
+ function download (fileSystem) {
var ft = new FileTransfer();
- console.log("Starting download");
+ console.log('Starting download');
- var progress = document.getElementById("loadingStatus");
+ var progress = document.getElementById('loadingStatus');
progress.value = 0;
- ft.onprogress = function(progressEvent) {
+ ft.onprogress = function (progressEvent) {
if (progressEvent.lengthComputable) {
var currPercents = parseInt(100 * (progressEvent.loaded / progressEvent.total), 10);
if (currPercents > progress.value) {
@@ -1631,77 +1815,162 @@
}
};
- ft.download(source, fileSystem.root.toURL() + filename, function (entry) {
- console.log("Download complete");
- element.src = urlFn(entry);
- console.log("Src URL is " + element.src);
- console.log("Inserting element");
- document.getElementById("info").appendChild(element);
- }, function (e) { console.log("ERROR: ft.download " + e.code); });
+ ft.download(
+ source,
+ fileSystem.root.toURL() + filename,
+ function (entry) {
+ console.log('Download complete');
+ element.src = urlFn(entry);
+ console.log('Src URL is ' + element.src);
+ console.log('Inserting element');
+ document.getElementById('info').appendChild(element);
+ },
+ function (e) {
+ console.log('ERROR: ft.download ' + e.code);
+ }
+ );
}
- console.log("Requesting filesystem");
+ console.log('Requesting filesystem');
clearResults();
- window.requestFileSystem(LocalFileSystem.TEMPORARY, 0, function (fileSystem) {
- console.log("Checking for existing file");
- if (typeof directory !== "undefined") {
- console.log("Checking for existing directory.");
- fileSystem.root.getDirectory(directory, {}, function (dirEntry) {
- dirEntry.removeRecursively(function () {
- download(fileSystem);
- }, function () { console.log("ERROR: dirEntry.removeRecursively"); });
- }, function () {
- download(fileSystem);
- });
- } else {
- fileSystem.root.getFile(filename, { create: false }, function (entry) {
- console.log("Removing existing file");
- entry.remove(function () {
- download(fileSystem);
- }, function () { console.log("ERROR: entry.remove"); });
- }, function () {
- download(fileSystem);
- });
+ window.requestFileSystem(
+ LocalFileSystem.TEMPORARY,
+ 0,
+ function (fileSystem) {
+ console.log('Checking for existing file');
+ if (typeof directory !== 'undefined') {
+ console.log('Checking for existing directory.');
+ fileSystem.root.getDirectory(
+ directory,
+ {},
+ function (dirEntry) {
+ dirEntry.removeRecursively(
+ function () {
+ download(fileSystem);
+ },
+ function () {
+ console.log('ERROR: dirEntry.removeRecursively');
+ }
+ );
+ },
+ function () {
+ download(fileSystem);
+ }
+ );
+ } else {
+ fileSystem.root.getFile(
+ filename,
+ { create: false },
+ function (entry) {
+ console.log('Removing existing file');
+ entry.remove(
+ function () {
+ download(fileSystem);
+ },
+ function () {
+ console.log('ERROR: entry.remove');
+ }
+ );
+ },
+ function () {
+ download(fileSystem);
+ }
+ );
+ }
+ },
+ function () {
+ console.log('ERROR: requestFileSystem');
}
- }, function () { console.log("ERROR: requestFileSystem"); });
+ );
}
/******************************************************************************/
- var progress_tag = "<progress id=\"loadingStatus\" value=\"0\" max=\"100\" style=\"width: 100%;\"></progress>";
- var file_transfer_tests = "<h2>Image File Transfer Tests</h2>" +
- "<h3>The following tests should display an image of the Apache feather in the status box</h3>" +
- "<div id=\"cdv_image\"></div>" +
- "<div id=\"native_image\"></div>" +
- "<div id=\"non-existent_dir\"></div>" +
- "<h2>Video File Transfer Tests</h2>" +
- "<h3>The following tests should display a video in the status box. The video should play when play is pressed</h3>" +
- "<div id=\"cdv_video\"></div>" +
- "<div id=\"native_video\"></div>";
+ var progress_tag = '<progress id="loadingStatus" value="0" max="100" style="width: 100%;"></progress>';
+ var file_transfer_tests =
+ '<h2>Image File Transfer Tests</h2>' +
+ '<h3>The following tests should display an image of the Apache feather in the status box</h3>' +
+ '<div id="cdv_image"></div>' +
+ '<div id="native_image"></div>' +
+ '<div id="non-existent_dir"></div>' +
+ '<h2>Video File Transfer Tests</h2>' +
+ '<h3>The following tests should display a video in the status box. The video should play when play is pressed</h3>' +
+ '<div id="cdv_video"></div>' +
+ '<div id="native_video"></div>';
- contentEl.innerHTML = "<div id=\"info\"></div>" + "<br>" + progress_tag +
- file_transfer_tests;
+ contentEl.innerHTML = '<div id="info"></div>' + '<br>' + progress_tag + file_transfer_tests;
- createActionButton("Download and display img (cdvfile)", function () {
- downloadImg(imageURL, function (entry) { return entry.toInternalURL(); }, new Image());
- }, "cdv_image");
+ createActionButton(
+ 'Download and display img (cdvfile)',
+ function () {
+ downloadImg(
+ imageURL,
+ function (entry) {
+ return entry.toInternalURL();
+ },
+ new Image()
+ );
+ },
+ 'cdv_image'
+ );
- createActionButton("Download and display img (native)", function () {
- downloadImg(imageURL, function (entry) { return entry.toURL(); }, new Image());
- }, "native_image");
+ createActionButton(
+ 'Download and display img (native)',
+ function () {
+ downloadImg(
+ imageURL,
+ function (entry) {
+ return entry.toURL();
+ },
+ new Image()
+ );
+ },
+ 'native_image'
+ );
- createActionButton("Download to a non-existent dir (should work)", function () {
- downloadImg(imageURL, function (entry) { return entry.toURL(); }, new Image(), "/nonExistentDirTest/");
- }, "non-existent_dir");
+ createActionButton(
+ 'Download to a non-existent dir (should work)',
+ function () {
+ downloadImg(
+ imageURL,
+ function (entry) {
+ return entry.toURL();
+ },
+ new Image(),
+ '/nonExistentDirTest/'
+ );
+ },
+ 'non-existent_dir'
+ );
- createActionButton("Download and play video (cdvfile)", function () {
- var videoElement = document.createElement("video");
- videoElement.controls = "controls";
- downloadImg(videoURL, function (entry) { return entry.toInternalURL(); }, videoElement);
- }, "cdv_video");
+ createActionButton(
+ 'Download and play video (cdvfile)',
+ function () {
+ var videoElement = document.createElement('video');
+ videoElement.controls = 'controls';
+ downloadImg(
+ videoURL,
+ function (entry) {
+ return entry.toInternalURL();
+ },
+ videoElement
+ );
+ },
+ 'cdv_video'
+ );
- createActionButton("Download and play video (native)", function () {
- var videoElement = document.createElement("video");
- videoElement.controls = "controls";
- downloadImg(videoURL, function (entry) { return entry.toURL(); }, videoElement);
- }, "native_video");
+ createActionButton(
+ 'Download and play video (native)',
+ function () {
+ var videoElement = document.createElement('video');
+ videoElement.controls = 'controls';
+ downloadImg(
+ videoURL,
+ function (entry) {
+ return entry.toURL();
+ },
+ videoElement
+ );
+ },
+ 'native_video'
+ );
};
diff --git a/www/FileTransfer.js b/www/FileTransfer.js
index 80cf91c..9938971 100644
--- a/www/FileTransfer.js
+++ b/www/FileTransfer.js
@@ -17,16 +17,16 @@
* specific language governing permissions and limitations
* under the License.
*
-*/
+ */
/* global cordova, FileSystem */
-var argscheck = require('cordova/argscheck'),
- exec = require('cordova/exec'),
- FileTransferError = require('./FileTransferError'),
- ProgressEvent = require('cordova-plugin-file.ProgressEvent');
+var argscheck = require('cordova/argscheck');
+var exec = require('cordova/exec');
+var FileTransferError = require('./FileTransferError');
+var ProgressEvent = require('cordova-plugin-file.ProgressEvent');
-function newProgressEvent(result) {
+function newProgressEvent (result) {
var pe = new ProgressEvent();
pe.lengthComputable = result.lengthComputable;
pe.loaded = result.loaded;
@@ -34,16 +34,15 @@
return pe;
}
-function getUrlCredentials(urlString) {
- var credentialsPattern = /^https?\:\/\/(?:(?:(([^:@\/]*)(?::([^@\/]*))?)?@)?([^:\/?#]*)(?::(\d*))?).*$/,
- credentials = credentialsPattern.exec(urlString);
+function getUrlCredentials (urlString) {
+ var credentialsPattern = /^https?:\/\/(?:(?:(([^:@/]*)(?::([^@/]*))?)?@)?([^:/?#]*)(?::(\d*))?).*$/;
+ var credentials = credentialsPattern.exec(urlString);
return credentials && credentials[1];
}
-function getBasicAuthHeader(urlString) {
- var header = null;
-
+function getBasicAuthHeader (urlString) {
+ var header = null;
// This is changed due to MS Windows doesn't support credentials in http uris
// so we detect them by regexp and strip off from result url
@@ -52,12 +51,12 @@
if (window.btoa) {
var credentials = getUrlCredentials(urlString);
if (credentials) {
- var authHeader = "Authorization";
- var authHeaderValue = "Basic " + window.btoa(credentials);
+ var authHeader = 'Authorization';
+ var authHeaderValue = 'Basic ' + window.btoa(credentials);
header = {
- name : authHeader,
- value : authHeaderValue
+ name: authHeader,
+ value: authHeaderValue
};
}
}
@@ -65,10 +64,10 @@
return header;
}
-function convertHeadersToArray(headers) {
+function convertHeadersToArray (headers) {
var result = [];
for (var header in headers) {
- if (headers.hasOwnProperty(header)) {
+ if (Object.prototype.hasOwnProperty.call(headers, header)) {
var headerValue = headers[header];
result.push({
name: header,
@@ -85,22 +84,22 @@
* FileTransfer uploads a file to a remote server.
* @constructor
*/
-var FileTransfer = function() {
+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) {
+ * 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;
@@ -124,36 +123,37 @@
fileName = options.fileName;
mimeType = options.mimeType;
headers = options.headers;
- httpMethod = options.httpMethod || "POST";
- if (httpMethod.toUpperCase() == "PUT"){
- httpMethod = "PUT";
+ httpMethod = options.httpMethod || 'POST';
+ if (httpMethod.toUpperCase() === 'PUT') {
+ httpMethod = 'PUT';
} else {
- httpMethod = "POST";
+ httpMethod = 'POST';
}
- if (options.chunkedMode !== null || typeof options.chunkedMode != "undefined") {
+ if (options.chunkedMode !== null || typeof options.chunkedMode !== 'undefined') {
chunkedMode = options.chunkedMode;
}
if (options.params) {
params = options.params;
- }
- else {
+ } else {
params = {};
}
}
- if (cordova.platformId === "windowsphone") {
+ if (cordova.platformId === 'windowsphone') {
headers = headers && convertHeadersToArray(headers);
params = params && convertHeadersToArray(params);
}
- var fail = errorCallback && function(e) {
- var error = new FileTransferError(e.code, e.source, e.target, e.http_status, e.body, e.exception);
- errorCallback(error);
- };
+ var fail =
+ errorCallback &&
+ function (e) {
+ var error = new FileTransferError(e.code, e.source, e.target, e.http_status, e.body, e.exception);
+ errorCallback(error);
+ };
var self = this;
- var win = function(result) {
- if (typeof result.lengthComputable != "undefined") {
+ var win = function (result) {
+ if (typeof result.lengthComputable !== 'undefined') {
if (self.onprogress) {
self.onprogress(newProgressEvent(result));
}
@@ -163,7 +163,19 @@
}
}
};
- exec(win, fail, 'FileTransfer', 'upload', [filePath, server, fileKey, fileName, mimeType, params, trustAllHosts, chunkedMode, headers, this._id, httpMethod]);
+ exec(win, fail, 'FileTransfer', 'upload', [
+ filePath,
+ server,
+ fileKey,
+ fileName,
+ mimeType,
+ params,
+ trustAllHosts,
+ chunkedMode,
+ headers,
+ this._id,
+ httpMethod
+ ]);
};
/**
@@ -175,7 +187,7 @@
* @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) {
+FileTransfer.prototype.download = function (source, target, successCallback, errorCallback, trustAllHosts, options) {
argscheck.checkArgs('ssFF*', 'FileTransfer.download', arguments);
var self = this;
@@ -193,12 +205,12 @@
headers = options.headers || null;
}
- if (cordova.platformId === "windowsphone" && headers) {
+ if (cordova.platformId === 'windowsphone' && headers) {
headers = convertHeadersToArray(headers);
}
- var win = function(result) {
- if (typeof result.lengthComputable != "undefined") {
+ var win = function (result) {
+ if (typeof result.lengthComputable !== 'undefined') {
if (self.onprogress) {
return self.onprogress(newProgressEvent(result));
}
@@ -206,24 +218,27 @@
var entry = null;
if (result.isDirectory) {
entry = new (require('cordova-plugin-file.DirectoryEntry'))();
- }
- else if (result.isFile) {
+ } else if (result.isFile) {
entry = new (require('cordova-plugin-file.FileEntry'))();
}
entry.isDirectory = result.isDirectory;
entry.isFile = result.isFile;
entry.name = result.name;
entry.fullPath = result.fullPath;
- entry.filesystem = new FileSystem(result.filesystemName || (result.filesystem == window.PERSISTENT ? 'persistent' : 'temporary'));
+ entry.filesystem = new FileSystem(
+ result.filesystemName || (result.filesystem === window.PERSISTENT ? 'persistent' : 'temporary')
+ );
entry.nativeURL = result.nativeURL;
successCallback(entry);
}
};
- var fail = errorCallback && function(e) {
- var error = new FileTransferError(e.code, e.source, e.target, e.http_status, e.body, e.exception);
- errorCallback(error);
- };
+ var fail =
+ errorCallback &&
+ function (e) {
+ var error = new FileTransferError(e.code, e.source, e.target, e.http_status, e.body, e.exception);
+ errorCallback(error);
+ };
exec(win, fail, 'FileTransfer', 'download', [source, target, trustAllHosts, this._id, headers]);
};
@@ -232,7 +247,7 @@
* 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() {
+FileTransfer.prototype.abort = function () {
exec(null, null, 'FileTransfer', 'abort', [this._id]);
};
diff --git a/www/FileTransferError.js b/www/FileTransferError.js
index 07ca831..e3c15eb 100644
--- a/www/FileTransferError.js
+++ b/www/FileTransferError.js
@@ -17,13 +17,13 @@
* specific language governing permissions and limitations
* under the License.
*
-*/
+ */
/**
* FileTransferError
* @constructor
*/
-var FileTransferError = function(code, source, target, status, body, exception) {
+var FileTransferError = function (code, source, target, status, body, exception) {
this.code = code || null;
this.source = source || null;
this.target = target || null;
diff --git a/www/browser/FileTransfer.js b/www/browser/FileTransfer.js
index 1cc6638..01e178e 100644
--- a/www/browser/FileTransfer.js
+++ b/www/browser/FileTransfer.js
@@ -17,33 +17,32 @@
* specific language governing permissions and limitations
* under the License.
*
-*/
+ */
-/*global module, require*/
+/* global FileUploadResult */
-var argscheck = require('cordova/argscheck'),
- FileTransferError = require('./FileTransferError');
+var argscheck = require('cordova/argscheck');
+var FileTransferError = require('./FileTransferError');
-function getParentPath(filePath) {
+function getParentPath (filePath) {
var pos = filePath.lastIndexOf('/');
return filePath.substring(0, pos + 1);
}
-function getFileName(filePath) {
+function getFileName (filePath) {
var pos = filePath.lastIndexOf('/');
return filePath.substring(pos + 1);
}
-function getUrlCredentials(urlString) {
- var credentialsPattern = /^https?\:\/\/(?:(?:(([^:@\/]*)(?::([^@\/]*))?)?@)?([^:\/?#]*)(?::(\d*))?).*$/,
- credentials = credentialsPattern.exec(urlString);
+function getUrlCredentials (urlString) {
+ var credentialsPattern = /^https?:\/\/(?:(?:(([^:@/]*)(?::([^@/]*))?)?@)?([^:/?#]*)(?::(\d*))?).*$/;
+ var credentials = credentialsPattern.exec(urlString);
return credentials && credentials[1];
}
-function getBasicAuthHeader(urlString) {
- var header = null;
-
+function getBasicAuthHeader (urlString) {
+ var header = null;
// This is changed due to MS Windows doesn't support credentials in http uris
// so we detect them by regexp and strip off from result url
@@ -52,12 +51,12 @@
if (window.btoa) {
var credentials = getUrlCredentials(urlString);
if (credentials) {
- var authHeader = "Authorization";
- var authHeaderValue = "Basic " + window.btoa(credentials);
+ var authHeader = 'Authorization';
+ var authHeaderValue = 'Basic ' + window.btoa(credentials);
header = {
- name : authHeader,
- value : authHeaderValue
+ name: authHeader,
+ value: authHeaderValue
};
}
}
@@ -65,8 +64,8 @@
return header;
}
-function checkURL(url) {
- return url.indexOf(' ') === -1 ? true : false;
+function checkURL (url) {
+ return url.indexOf(' ') === -1;
}
var idCounter = 0;
@@ -77,7 +76,7 @@
* FileTransfer uploads a file to a remote server.
* @constructor
*/
-var FileTransfer = function() {
+var FileTransfer = function () {
this._id = ++idCounter;
this.onprogress = null; // optional callback
};
@@ -92,7 +91,7 @@
* @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) {
+FileTransfer.prototype.upload = function (filePath, server, successCallback, errorCallback, options) {
// check for arguments
argscheck.checkArgs('ssFFO*', 'FileTransfer.upload', arguments);
@@ -107,14 +106,14 @@
options = options || {};
- var fileKey = options.fileKey || "file";
- var fileName = options.fileName || "image.jpg";
- var mimeType = options.mimeType || "image/jpeg";
+ var fileKey = options.fileKey || 'file';
+ var fileName = options.fileName || 'image.jpg';
+ var mimeType = options.mimeType || 'image/jpeg';
var params = options.params || {};
var withCredentials = options.withCredentials || false;
// var chunkedMode = !!options.chunkedMode; // Not supported
var headers = options.headers || {};
- var httpMethod = options.httpMethod && options.httpMethod.toUpperCase() === "PUT" ? "PUT" : "POST";
+ var httpMethod = options.httpMethod && options.httpMethod.toUpperCase() === 'PUT' ? 'PUT' : 'POST';
var basicAuthHeader = getBasicAuthHeader(server);
if (basicAuthHeader) {
@@ -123,93 +122,101 @@
}
var that = this;
- var xhr = transfers[this._id] = new XMLHttpRequest();
+ var xhr = (transfers[this._id] = new XMLHttpRequest());
xhr.withCredentials = withCredentials;
- var fail = errorCallback && function(code, status, response) {
- if (transfers[this._id]) {
- delete transfers[this._id];
- }
- var error = new FileTransferError(code, filePath, server, status, response);
- if (errorCallback) {
- errorCallback(error);
- }
- };
+ var fail =
+ errorCallback &&
+ function (code, status, response) {
+ if (transfers[this._id]) {
+ delete transfers[this._id];
+ }
+ var error = new FileTransferError(code, filePath, server, status, response);
+ if (errorCallback) {
+ errorCallback(error);
+ }
+ };
- window.resolveLocalFileSystemURL(filePath, function(entry) {
- entry.file(function(file) {
- var reader = new FileReader();
- reader.onloadend = function() {
- var blob = new Blob([this.result], {type: mimeType});
+ window.resolveLocalFileSystemURL(
+ filePath,
+ function (entry) {
+ entry.file(
+ function (file) {
+ var reader = new FileReader();
+ reader.onloadend = function () {
+ var blob = new Blob([this.result], { type: mimeType });
- // Prepare form data to send to server
- var fd = new FormData();
- fd.append(fileKey, blob, fileName);
- for (var prop in params) {
- if (params.hasOwnProperty(prop)) {
- fd.append(prop, params[prop]);
- }
+ // Prepare form data to send to server
+ var fd = new FormData();
+ fd.append(fileKey, blob, fileName);
+ for (var prop in params) {
+ if (Object.prototype.hasOwnProperty.call(params, prop)) {
+ fd.append(prop, params[prop]);
+ }
+ }
+
+ xhr.open(httpMethod, server);
+
+ // Fill XHR headers
+ for (var header in headers) {
+ if (Object.prototype.hasOwnProperty.call(headers, header)) {
+ xhr.setRequestHeader(header, headers[header]);
+ }
+ }
+
+ xhr.onload = function () {
+ // 2xx codes are valid
+ if (this.status >= 200 && this.status < 300) {
+ var result = new FileUploadResult();
+ result.bytesSent = blob.size;
+ result.responseCode = this.status;
+ result.response = this.response;
+ delete transfers[that._id];
+ successCallback(result);
+ } else if (this.status === 404) {
+ fail(FileTransferError.INVALID_URL_ERR, this.status, this.response);
+ } else {
+ fail(FileTransferError.CONNECTION_ERR, this.status, this.response);
+ }
+ };
+
+ xhr.ontimeout = function () {
+ fail(FileTransferError.CONNECTION_ERR, this.status, this.response);
+ };
+
+ xhr.onerror = function () {
+ fail(FileTransferError.CONNECTION_ERR, this.status, this.response);
+ };
+
+ xhr.onabort = function () {
+ fail(FileTransferError.ABORT_ERR, this.status, this.response);
+ };
+
+ xhr.upload.onprogress = function (e) {
+ if (that.onprogress) {
+ that.onprogress(e);
+ }
+ };
+
+ xhr.send(fd);
+ // Special case when transfer already aborted, but XHR isn't sent.
+ // In this case XHR won't fire an abort event, so we need to check if transfers record
+ // isn't deleted by filetransfer.abort and if so, call XHR's abort method again
+ if (!transfers[that._id]) {
+ xhr.abort();
+ }
+ };
+ reader.readAsArrayBuffer(file);
+ },
+ function () {
+ fail(FileTransferError.FILE_NOT_FOUND_ERR);
}
-
- xhr.open(httpMethod, server);
-
- // Fill XHR headers
- for (var header in headers) {
- if (headers.hasOwnProperty(header)) {
- xhr.setRequestHeader(header, headers[header]);
- }
- }
-
- xhr.onload = function() {
- // 2xx codes are valid
- if (this.status >= 200 &&
- this.status < 300) {
- var result = new FileUploadResult(); // jshint ignore:line
- result.bytesSent = blob.size;
- result.responseCode = this.status;
- result.response = this.response;
- delete transfers[that._id];
- successCallback(result);
- } else if (this.status === 404) {
- fail(FileTransferError.INVALID_URL_ERR, this.status, this.response);
- } else {
- fail(FileTransferError.CONNECTION_ERR, this.status, this.response);
- }
- };
-
- xhr.ontimeout = function() {
- fail(FileTransferError.CONNECTION_ERR, this.status, this.response);
- };
-
- xhr.onerror = function() {
- fail(FileTransferError.CONNECTION_ERR, this.status, this.response);
- };
-
- xhr.onabort = function () {
- fail(FileTransferError.ABORT_ERR, this.status, this.response);
- };
-
- xhr.upload.onprogress = function (e) {
- if (that.onprogress) {
- that.onprogress(e);
- }
- };
-
- xhr.send(fd);
- // Special case when transfer already aborted, but XHR isn't sent.
- // In this case XHR won't fire an abort event, so we need to check if transfers record
- // isn't deleted by filetransfer.abort and if so, call XHR's abort method again
- if (!transfers[that._id]) {
- xhr.abort();
- }
- };
- reader.readAsArrayBuffer(file);
- }, function() {
+ );
+ },
+ function () {
fail(FileTransferError.FILE_NOT_FOUND_ERR);
- });
- }, function() {
- fail(FileTransferError.FILE_NOT_FOUND_ERR);
- });
+ }
+ );
};
/**
@@ -221,7 +228,7 @@
* @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) {
+FileTransfer.prototype.download = function (source, target, successCallback, errorCallback, trustAllHosts, options) {
argscheck.checkArgs('ssFF*', 'FileTransfer.download', arguments);
// Check if target URL doesn't contain spaces. If contains, it should be escaped first
@@ -234,7 +241,7 @@
}
options = options || {};
-
+
var headers = options.headers || {};
var withCredentials = options.withCredentials || false;
@@ -245,29 +252,30 @@
}
var that = this;
- var xhr = transfers[this._id] = new XMLHttpRequest();
+ var xhr = (transfers[this._id] = new XMLHttpRequest());
xhr.withCredentials = withCredentials;
- var fail = errorCallback && function(code, status, response) {
- if (transfers[that._id]) {
- delete transfers[that._id];
- }
- // In XHR GET reqests we're setting response type to Blob
- // but in case of error we need to raise event with plain text response
- if (response instanceof Blob) {
- var reader = new FileReader();
- reader.readAsText(response);
- reader.onloadend = function(e) {
- var error = new FileTransferError(code, source, target, status, e.target.result);
+ var fail =
+ errorCallback &&
+ function (code, status, response) {
+ if (transfers[that._id]) {
+ delete transfers[that._id];
+ }
+ // In XHR GET reqests we're setting response type to Blob
+ // but in case of error we need to raise event with plain text response
+ if (response instanceof Blob) {
+ var reader = new FileReader();
+ reader.readAsText(response);
+ reader.onloadend = function (e) {
+ var error = new FileTransferError(code, source, target, status, e.target.result);
+ errorCallback(error);
+ };
+ } else {
+ var error = new FileTransferError(code, source, target, status, response);
errorCallback(error);
- };
- } else {
- var error = new FileTransferError(code, source, target, status, response);
- errorCallback(error);
- }
- };
+ }
+ };
xhr.onload = function (e) {
-
var fileNotFound = function () {
fail(FileTransferError.FILE_NOT_FOUND_ERR);
};
@@ -275,27 +283,36 @@
var req = e.target;
// req.status === 0 is special case for local files with file:// URI scheme
if ((req.status === 200 || req.status === 0) && req.response) {
- window.resolveLocalFileSystemURL(getParentPath(target), function (dir) {
- dir.getFile(getFileName(target), {create: true}, function writeFile(entry) {
- entry.createWriter(function (fileWriter) {
- fileWriter.onwriteend = function (evt) {
- if (!evt.target.error) {
- entry.filesystemName = entry.filesystem.name;
- delete transfers[that._id];
- if (successCallback) {
- successCallback(entry);
- }
- } else {
- fail(FileTransferError.FILE_NOT_FOUND_ERR);
- }
- };
- fileWriter.onerror = function () {
- fail(FileTransferError.FILE_NOT_FOUND_ERR);
- };
- fileWriter.write(req.response);
- }, fileNotFound);
- }, fileNotFound);
- }, fileNotFound);
+ window.resolveLocalFileSystemURL(
+ getParentPath(target),
+ function (dir) {
+ dir.getFile(
+ getFileName(target),
+ { create: true },
+ function writeFile (entry) {
+ entry.createWriter(function (fileWriter) {
+ fileWriter.onwriteend = function (evt) {
+ if (!evt.target.error) {
+ entry.filesystemName = entry.filesystem.name;
+ delete transfers[that._id];
+ if (successCallback) {
+ successCallback(entry);
+ }
+ } else {
+ fail(FileTransferError.FILE_NOT_FOUND_ERR);
+ }
+ };
+ fileWriter.onerror = function () {
+ fail(FileTransferError.FILE_NOT_FOUND_ERR);
+ };
+ fileWriter.write(req.response);
+ }, fileNotFound);
+ },
+ fileNotFound
+ );
+ },
+ fileNotFound
+ );
} else if (req.status === 404) {
fail(FileTransferError.INVALID_URL_ERR, req.status, req.response);
} else {
@@ -317,15 +334,15 @@
fail(FileTransferError.ABORT_ERR, this.status, this.response);
};
- xhr.open("GET", source, true);
+ xhr.open('GET', source, true);
for (var header in headers) {
- if (headers.hasOwnProperty(header)) {
+ if (Object.prototype.hasOwnProperty.call(headers, header)) {
xhr.setRequestHeader(header, headers[header]);
}
}
- xhr.responseType = "blob";
+ xhr.responseType = 'blob';
xhr.send();
};
@@ -334,7 +351,7 @@
* 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() {
+FileTransfer.prototype.abort = function () {
if (this instanceof FileTransfer) {
if (transfers[this._id]) {
transfers[this._id].abort();