diff --git a/test/js-specs.js b/test/js-specs.js index f2678c1..2afe7d1 100644 --- a/test/js-specs.js +++ b/test/js-specs.js @@ -129,7 +129,7 @@ describe('Advanced HTTP public interface', function () { }); it('throws an Error when you try to add a cookie by using "setHeader" #46', () => { - (function () { http.setHeader('*', 'cookie', 'value'); }).should.throw(); + (() => { http.setHeader('*', 'cookie', 'value'); }).should.throw(messages.ADDING_COOKIES_NOT_SUPPORTED); }); it('configures global timeout value correctly with given valid value', () => { @@ -138,7 +138,7 @@ describe('Advanced HTTP public interface', function () { }); it('throws an Error when you try to configure global timeout with a string', () => { - (function () { http.setRequestTimeout('myString'); }).should.throw(messages.INVALID_TIMEOUT_VALUE); + (() => { http.setRequestTimeout('myString'); }).should.throw(messages.INVALID_TIMEOUT_VALUE); }); it('sets global option for following redirects correctly', () => { @@ -147,7 +147,7 @@ describe('Advanced HTTP public interface', function () { }); it('throws an Error when you try to configure global option for following redirects with a string', () => { - (function () { http.setFollowRedirect('myString'); }).should.throw(messages.INVALID_FOLLOW_REDIRECT_VALUE); + (() => { http.setFollowRedirect('myString'); }).should.throw(messages.INVALID_FOLLOW_REDIRECT_VALUE); }); it('exposes an enumeration style object with mappings for the error codes', () => { @@ -475,4 +475,34 @@ describe('Common helpers', function () { handler({ data: 'NotValidJson' }); }); }); + + describe('checkFileOptions()', function() { + const jsUtil = require('../www/js-util'); + const messages = require('../www/messages'); + const helpers = require('../www/helpers')(jsUtil, null, messages, null, null); + + it('checks valid file options correctly', () => { + const opts = { + filePaths: ['file://path/to/file.png'], + names: ['ScreenCapture'] + }; + + helpers.checkFileOptions(opts.filePaths, opts.names).should.be.eql(opts); + }); + + it('throws an error when file options are missing', () => { + (() => helpers.checkFileOptions(undefined, ['ScreenCapture'])).should.throw(messages.FILE_PATHS_TYPE_MISMATCH); + (() => helpers.checkFileOptions(['file://path/to/file.png'], undefined)).should.throw(messages.NAMES_TYPE_MISMATCH); + }); + + it('throws an error when file options contains empty arrays', () => { + (() => helpers.checkFileOptions([], ['ScreenCapture'])).should.throw(messages.EMPTY_FILE_PATHS); + (() => helpers.checkFileOptions(['file://path/to/file.png'], [])).should.throw(messages.EMPTY_NAMES); + }); + + it('throws an error when file options contains invalid values', () => { + (() => helpers.checkFileOptions([1], ['ScreenCapture'])).should.throw(messages.FILE_PATHS_TYPE_MISMATCH); + (() => helpers.checkFileOptions(['file://path/to/file.png'], [1])).should.throw(messages.NAMES_TYPE_MISMATCH); + }); + }); }) diff --git a/www/helpers.js b/www/helpers.js index e7402b4..4aba3c4 100644 --- a/www/helpers.js +++ b/www/helpers.js @@ -7,21 +7,22 @@ module.exports = function init(jsUtil, cookieHandler, messages, base64, errorCod var interface = { b64EncodeUnicode: b64EncodeUnicode, - checkSerializer: checkSerializer, - checkSSLCertMode: checkSSLCertMode, checkClientAuthMode: checkClientAuthMode, checkClientAuthOptions: checkClientAuthOptions, + checkFileOptions: checkFileOptions, + checkFollowRedirectValue: checkFollowRedirectValue, checkForBlacklistedHeaderKey: checkForBlacklistedHeaderKey, checkForInvalidHeaderValue: checkForInvalidHeaderValue, + checkSerializer: checkSerializer, + checkSSLCertMode: checkSSLCertMode, checkTimeoutValue: checkTimeoutValue, - checkFollowRedirectValue: checkFollowRedirectValue, - injectCookieHandler: injectCookieHandler, - injectRawResponseHandler: injectRawResponseHandler, - injectFileEntryHandler: injectFileEntryHandler, getMergedHeaders: getMergedHeaders, getProcessedData: getProcessedData, handleMissingCallbacks: handleMissingCallbacks, - handleMissingOptions: handleMissingOptions + handleMissingOptions: handleMissingOptions, + injectCookieHandler: injectCookieHandler, + injectFileEntryHandler: injectFileEntryHandler, + injectRawResponseHandler: injectRawResponseHandler, }; // expose all functions for testing purposes @@ -94,6 +95,20 @@ module.exports = function init(jsUtil, cookieHandler, messages, base64, errorCod return obj; } + function checkArray(array, allowedDataTypes, onInvalidValueMessage) { + if (jsUtil.getTypeOf(array) !== 'Array') { + throw new Error(onInvalidValueMessage); + } + + for (var i = 0; i < array.length; ++i) { + if (allowedDataTypes.indexOf(jsUtil.getTypeOf(array[i])) === -1) { + throw new Error(onInvalidValueMessage); + } + } + + return array; + } + function checkHttpMethod(method) { return checkForValidStringValue(validHttpMethods, method, messages.INVALID_HTTP_METHOD); } @@ -172,7 +187,7 @@ module.exports = function init(jsUtil, cookieHandler, messages, base64, errorCod function checkForInvalidHeaderValue(value) { if (jsUtil.getTypeOf(value) !== 'String') { - throw new Error(messages.INVALID_HEADERS_VALUE); + throw new Error(messages.INVALID_HEADER_VALUE); } return value; @@ -195,11 +210,28 @@ module.exports = function init(jsUtil, cookieHandler, messages, base64, errorCod } function checkHeadersObject(headers) { - return checkKeyValuePairObject(headers, ['String'], messages.INVALID_HEADERS_VALUE); + return checkKeyValuePairObject(headers, ['String'], messages.TYPE_MISMATCH_HEADERS); } function checkParamsObject(params) { - return checkKeyValuePairObject(params, ['String', 'Array'], messages.INVALID_PARAMS_VALUE); + return checkKeyValuePairObject(params, ['String', 'Array'], messages.TYPE_MISMATCH_PARAMS); + } + + function checkFileOptions(filePaths, names) { + var opts = { + filePaths: checkArray(filePaths, ['String'], messages.TYPE_MISMATCH_FILE_PATHS), + names: checkArray(names, ['String'], messages.TYPE_MISMATCH_NAMES) + }; + + if (!opts.filePaths.length) { + throw new Error(messages.EMPTY_FILE_PATHS); + } + + if (!opts.names.length) { + throw new Error(messages.EMPTY_NAMES); + } + + return opts; } function resolveCookieString(headers) { @@ -324,7 +356,7 @@ module.exports = function init(jsUtil, cookieHandler, messages, base64, errorCod var allowedDataTypes = getAllowedDataTypes(dataSerializer); if (allowedDataTypes.indexOf(currentDataType) === -1) { - throw new Error(messages.DATA_TYPE_MISMATCH + ' ' + allowedDataTypes.join(', ')); + throw new Error(messages.TYPE_MISMATCH_DATA + ' ' + allowedDataTypes.join(', ')); } if (dataSerializer === 'utf8') { @@ -355,9 +387,7 @@ module.exports = function init(jsUtil, cookieHandler, messages, base64, errorCod followRedirect: checkFollowRedirectValue(options.followRedirect || globals.followRedirect), headers: checkHeadersObject(options.headers || {}), params: checkParamsObject(options.params || {}), - data: jsUtil.getTypeOf(options.data) === 'Undefined' ? null : options.data, - filePath: options.filePath || '', - name: options.name || '' + data: jsUtil.getTypeOf(options.data) === 'Undefined' ? null : options.data }; } }; diff --git a/www/messages.js b/www/messages.js index 37f15c0..3dbfa8e 100644 --- a/www/messages.js +++ b/www/messages.js @@ -1,20 +1,25 @@ module.exports = { ADDING_COOKIES_NOT_SUPPORTED: 'advanced-http: "setHeader" does not support adding cookies, please use "setCookie" function instead', - DATA_TYPE_MISMATCH: 'advanced-http: "data" argument supports only following data types:', - INVALID_CLIENT_AUTH_ALIAS: 'advanced-http: invalid client certificate alias, needs to be a string or undefined', + EMPTY_FILE_PATHS: 'advanced-http: "filePaths" option array must not be empty, ', + EMPTY_NAMES: 'advanced-http: "names" option array must not be empty, ', + INVALID_CLIENT_AUTH_ALIAS: 'advanced-http: invalid client certificate alias, needs to be a string or undefined, ', INVALID_CLIENT_AUTH_MODE: 'advanced-http: invalid client certificate authentication mode, supported modes are:', - INVALID_CLIENT_AUTH_OPTIONS: 'advanced-http: invalid client certificate authentication options, needs to be an object', - INVALID_CLIENT_AUTH_PKCS_PASSWORD: 'advanced-http: invalid PKCS12 container password, needs to be a string', - INVALID_CLIENT_AUTH_RAW_PKCS: 'advanced-http: invalid PKCS12 container, needs to be an array buffer', + INVALID_CLIENT_AUTH_OPTIONS: 'advanced-http: invalid client certificate authentication options, needs to be an dictionary style object', + INVALID_CLIENT_AUTH_PKCS_PASSWORD: 'advanced-http: invalid PKCS12 container password, needs to be a string, ', + INVALID_CLIENT_AUTH_RAW_PKCS: 'advanced-http: invalid PKCS12 container, needs to be an array buffer, ', INVALID_DATA_SERIALIZER: 'advanced-http: invalid serializer, supported serializers are:', - INVALID_FOLLOW_REDIRECT_VALUE: 'advanced-http: invalid follow redirect value, needs to be a boolean value', - INVALID_HEADERS_VALUE: 'advanced-http: header values must be strings', + INVALID_FOLLOW_REDIRECT_VALUE: 'advanced-http: invalid follow redirect value, needs to be a boolean value, ', + INVALID_HEADER_VALUE: 'advanced-http: invalid header value, needs to be a string, ', INVALID_HTTP_METHOD: 'advanced-http: invalid HTTP method, supported methods are:', - INVALID_PARAMS_VALUE: 'advanced-http: invalid params object, needs to be an object with strings', INVALID_RESPONSE_TYPE: 'advanced-http: invalid response type, supported types are:', INVALID_SSL_CERT_MODE: 'advanced-http: invalid SSL cert mode, supported modes are:', - INVALID_TIMEOUT_VALUE: 'advanced-http: invalid timeout value, needs to be a positive numeric value', + INVALID_TIMEOUT_VALUE: 'advanced-http: invalid timeout value, needs to be a positive numeric value, ', MANDATORY_FAIL: 'advanced-http: missing mandatory "onFail" callback function', MANDATORY_SUCCESS: 'advanced-http: missing mandatory "onSuccess" callback function', POST_PROCESSING_FAILED: 'advanced-http: an error occured during post processing response:', + TYPE_MISMATCH_DATA: 'advanced-http: "data" option supports only following data types:', + TYPE_MISMATCH_FILE_PATHS: 'advanced-http: "filePaths" option needs to be an string array, ', + TYPE_MISMATCH_HEADERS: 'advanced-http: "headers" option needs to be an dictionary style object, ', + TYPE_MISMATCH_NAMES: 'advanced-http: "names" option needs to be an string array, ', + TYPE_MISMATCH_PARAMS: 'advanced-http: "params" option needs to be an dictionary style object, ', }; diff --git a/www/public-interface.js b/www/public-interface.js index 80117d1..8c45982 100644 --- a/www/public-interface.js +++ b/www/public-interface.js @@ -28,6 +28,7 @@ module.exports = function init(exec, cookieHandler, urlUtil, helpers, globalConf delete: del, head: head, uploadFile: uploadFile, + uploadFiles: uploadFiles, downloadFile: downloadFile, ErrorCode: errorCodes }; @@ -155,7 +156,8 @@ module.exports = function init(exec, cookieHandler, urlUtil, helpers, globalConf var data = helpers.getProcessedData(options.data, options.serializer); return exec(onSuccess, onFail, 'CordovaHttpPlugin', options.method, [url, data, options.serializer, headers, options.timeout, options.followRedirect, options.responseType]); case 'upload': - return exec(onSuccess, onFail, 'CordovaHttpPlugin', 'uploadFile', [url, headers, options.filePath, options.name, options.timeout, options.followRedirect, options.responseType]); + var fileOptions = helpers.checkFileOptions(options.filePaths || [options.filePath], options.names || [options.name]); + return exec(onSuccess, onFail, 'CordovaHttpPlugin', 'uploadFile', [url, headers, fileOptions.filePaths, fileOptions.names, options.timeout, options.followRedirect, options.responseType]); case 'download': var onDownloadSuccess = helpers.injectCookieHandler(url, helpers.injectFileEntryHandler(success)); return exec(onDownloadSuccess, onFail, 'CordovaHttpPlugin', 'downloadFile', [url, headers, options.filePath, options.timeout, options.followRedirect]); @@ -192,6 +194,10 @@ module.exports = function init(exec, cookieHandler, urlUtil, helpers, globalConf return publicInterface.sendRequest(url, { method: 'upload', params: params, headers: headers, filePath: filePath, name: name }, success, failure); } + function uploadFiles(url, params, headers, filePaths, names, success, failure) { + return publicInterface.sendRequest(url, { method: 'upload', params: params, headers: headers, filePaths: filePaths, names: names }, success, failure); + } + function downloadFile(url, params, headers, filePath, success, failure) { return publicInterface.sendRequest(url, { method: 'download', params: params, headers: headers, filePath: filePath }, success, failure); }