cordova-plugin-advanced-http/www/helpers.js
Sefa Ilkimen 684874184d - refactor: iOS implementation
- chore: add flags to run only one spec or disable spec in e2e tests
2019-11-17 19:33:19 +01:00

484 lines
14 KiB
JavaScript

module.exports = function init(global, jsUtil, cookieHandler, messages, base64, errorCodes, dependencyValidator) {
var validSerializers = ['urlencoded', 'json', 'utf8', 'multipart'];
var validCertModes = ['default', 'nocheck', 'pinned', 'legacy'];
var validClientAuthModes = ['none', 'systemstore', 'buffer'];
var validHttpMethods = ['get', 'put', 'post', 'patch', 'head', 'delete', 'upload', 'download'];
var validResponseTypes = ['text', 'json', 'arraybuffer', 'blob'];
var interface = {
b64EncodeUnicode: b64EncodeUnicode,
checkClientAuthMode: checkClientAuthMode,
checkClientAuthOptions: checkClientAuthOptions,
checkDownloadFilePath: checkDownloadFilePath,
checkFollowRedirectValue: checkFollowRedirectValue,
checkForBlacklistedHeaderKey: checkForBlacklistedHeaderKey,
checkForInvalidHeaderValue: checkForInvalidHeaderValue,
checkSerializer: checkSerializer,
checkSSLCertMode: checkSSLCertMode,
checkTimeoutValue: checkTimeoutValue,
checkUploadFileOptions: checkUploadFileOptions,
getMergedHeaders: getMergedHeaders,
processData: processData,
handleMissingCallbacks: handleMissingCallbacks,
handleMissingOptions: handleMissingOptions,
injectCookieHandler: injectCookieHandler,
injectFileEntryHandler: injectFileEntryHandler,
injectRawResponseHandler: injectRawResponseHandler,
};
// expose all functions for testing purposes
if (init.debug) {
interface.mergeHeaders = mergeHeaders;
interface.checkForValidStringValue = checkForValidStringValue;
interface.checkKeyValuePairObject = checkKeyValuePairObject;
interface.checkHttpMethod = checkHttpMethod;
interface.checkResponseType = checkResponseType;
interface.checkHeadersObject = checkHeadersObject;
interface.checkParamsObject = checkParamsObject;
interface.resolveCookieString = resolveCookieString;
interface.createFileEntry = createFileEntry;
interface.getCookieHeader = getCookieHeader;
interface.getMatchingHostHeaders = getMatchingHostHeaders;
interface.getAllowedDataTypes = getAllowedDataTypes;
}
return interface;
// Thanks Mozilla: https://developer.mozilla.org/en-US/docs/Web/API/WindowBase64/Base64_encoding_and_decoding#The_.22Unicode_Problem.22
function b64EncodeUnicode(str) {
return btoa(encodeURIComponent(str).replace(/%([0-9A-F]{2})/g, function (match, p1) {
return String.fromCharCode('0x' + p1);
}));
}
function mergeHeaders(globalHeaders, localHeaders) {
var globalKeys = Object.keys(globalHeaders);
var key;
for (var i = 0; i < globalKeys.length; i++) {
key = globalKeys[i];
if (!localHeaders.hasOwnProperty(key)) {
localHeaders[key] = globalHeaders[key];
}
}
return localHeaders;
}
function checkForValidStringValue(list, value, onInvalidValueMessage) {
if (jsUtil.getTypeOf(value) !== 'String') {
throw new Error(onInvalidValueMessage + ' ' + list.join(', '));
}
value = value.trim().toLowerCase();
if (list.indexOf(value) === -1) {
throw new Error(onInvalidValueMessage + ' ' + list.join(', '));
}
return value;
}
function checkKeyValuePairObject(obj, allowedChildren, onInvalidValueMessage) {
if (jsUtil.getTypeOf(obj) !== 'Object') {
throw new Error(onInvalidValueMessage);
}
var keys = Object.keys(obj);
for (var i = 0; i < keys.length; i++) {
if (allowedChildren.indexOf(jsUtil.getTypeOf(obj[keys[i]])) === -1) {
throw new Error(onInvalidValueMessage);
}
}
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);
}
function checkResponseType(type) {
return checkForValidStringValue(validResponseTypes, type, messages.INVALID_RESPONSE_TYPE);
}
function checkSerializer(serializer) {
return checkForValidStringValue(validSerializers, serializer, messages.INVALID_DATA_SERIALIZER);
}
function checkSSLCertMode(mode) {
return checkForValidStringValue(validCertModes, mode, messages.INVALID_SSL_CERT_MODE);
}
function checkClientAuthMode(mode) {
return checkForValidStringValue(validClientAuthModes, mode, messages.INVALID_CLIENT_AUTH_MODE);
}
function checkClientAuthOptions(mode, options) {
options = options || {};
// none
if (mode === validClientAuthModes[0]) {
return {
alias: null,
rawPkcs: null,
pkcsPassword: ''
};
}
if (jsUtil.getTypeOf(options) !== 'Object') {
throw new Error(messages.INVALID_CLIENT_AUTH_OPTIONS);
}
// systemstore
if (mode === validClientAuthModes[1]) {
if (jsUtil.getTypeOf(options.alias) !== 'String'
&& jsUtil.getTypeOf(options.alias) !== 'Undefined') {
throw new Error(messages.INVALID_CLIENT_AUTH_ALIAS);
}
return {
alias: jsUtil.getTypeOf(options.alias) === 'Undefined' ? null : options.alias,
rawPkcs: null,
pkcsPassword: ''
};
}
// buffer
if (mode === validClientAuthModes[2]) {
if (jsUtil.getTypeOf(options.rawPkcs) !== 'ArrayBuffer') {
throw new Error(messages.INVALID_CLIENT_AUTH_RAW_PKCS);
}
if (jsUtil.getTypeOf(options.pkcsPassword) !== 'String') {
throw new Error(messages.INVALID_CLIENT_AUTH_PKCS_PASSWORD);
}
return {
alias: null,
rawPkcs: options.rawPkcs,
pkcsPassword: options.pkcsPassword
}
}
}
function checkForBlacklistedHeaderKey(key) {
if (key.toLowerCase() === 'cookie') {
throw new Error(messages.ADDING_COOKIES_NOT_SUPPORTED);
}
return key;
}
function checkForInvalidHeaderValue(value) {
if (jsUtil.getTypeOf(value) !== 'String') {
throw new Error(messages.INVALID_HEADER_VALUE);
}
return value;
}
function checkTimeoutValue(timeout) {
if (jsUtil.getTypeOf(timeout) !== 'Number' || timeout < 0) {
throw new Error(messages.INVALID_TIMEOUT_VALUE);
}
return timeout;
}
function checkFollowRedirectValue(follow) {
if (jsUtil.getTypeOf(follow) !== 'Boolean') {
throw new Error(messages.INVALID_FOLLOW_REDIRECT_VALUE);
}
return follow;
}
function checkHeadersObject(headers) {
return checkKeyValuePairObject(headers, ['String'], messages.TYPE_MISMATCH_HEADERS);
}
function checkParamsObject(params) {
return checkKeyValuePairObject(params, ['String', 'Array'], messages.TYPE_MISMATCH_PARAMS);
}
function checkDownloadFilePath(filePath) {
if (!filePath || jsUtil.getTypeOf(filePath) !== 'String') {
throw new Error(messages.INVALID_DOWNLOAD_FILE_PATH);
}
return filePath;
}
function checkUploadFileOptions(filePaths, names) {
if (jsUtil.getTypeOf(filePaths) === 'String') {
filePaths = [filePaths];
}
if (jsUtil.getTypeOf(names) === 'String') {
names = [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) {
var keys = Object.keys(headers || {});
for (var i = 0; i < keys.length; ++i) {
if (keys[i].match(/^set-cookie$/i)) {
return headers[keys[i]];
}
}
return null;
}
function createFileEntry(rawEntry) {
var entry = new (require('cordova-plugin-file.FileEntry'))();
entry.isDirectory = rawEntry.isDirectory;
entry.isFile = rawEntry.isFile;
entry.name = rawEntry.name;
entry.fullPath = rawEntry.fullPath;
entry.filesystem = new FileSystem(rawEntry.filesystemName || (rawEntry.filesystem == global.PERSISTENT ? 'persistent' : 'temporary'));
entry.nativeURL = rawEntry.nativeURL;
return entry;
}
function injectCookieHandler(url, cb) {
return function (response) {
cookieHandler.setCookieFromString(url, resolveCookieString(response.headers));
cb(response);
}
}
function injectRawResponseHandler(responseType, success, failure) {
return function (response) {
var dataType = jsUtil.getTypeOf(response.data);
// don't need post-processing if it's already binary type (on browser platform)
if (dataType === 'ArrayBuffer' || dataType === 'Blob') {
return success(response);
}
try {
// json
if (responseType === validResponseTypes[1]) {
response.data = JSON.parse(response.data);
}
// arraybuffer
else if (responseType === validResponseTypes[2]) {
response.data = base64.toArrayBuffer(response.data);
}
// blob
else if (responseType === validResponseTypes[3]) {
var buffer = base64.toArrayBuffer(response.data);
var type = response.headers['content-type'] || '';
var blob = new Blob([ buffer ], { type: type });
response.data = blob;
}
success(response);
} catch (error) {
failure({
status: errorCodes.POST_PROCESSING_FAILED,
error: messages.POST_PROCESSING_FAILED + ' ' + error.message,
url: response.url,
headers: response.headers
});
}
}
}
function injectFileEntryHandler(cb) {
return function (response) {
cb(createFileEntry(response.file));
}
}
function getCookieHeader(url) {
var cookieString = cookieHandler.getCookieString(url);
if (cookieString.length) {
return { Cookie: cookieHandler.getCookieString(url) };
}
return {};
}
function getMatchingHostHeaders(url, headersList) {
var matches = url.match(/^https?\:\/\/([^\/?#]+)(?:[\/?#]|$)/i);
var domain = matches && matches[1];
return headersList[domain] || null;
}
function getMergedHeaders(url, requestHeaders, predefinedHeaders) {
var globalHeaders = predefinedHeaders['*'] || {};
var hostHeaders = getMatchingHostHeaders(url, predefinedHeaders) || {};
var mergedHeaders = mergeHeaders(globalHeaders, hostHeaders);
mergedHeaders = mergeHeaders(mergedHeaders, requestHeaders);
mergedHeaders = mergeHeaders(mergedHeaders, getCookieHeader(url));
return mergedHeaders;
}
function getAllowedDataTypes(dataSerializer) {
switch (dataSerializer) {
case 'utf8':
return ['String'];
case 'urlencoded':
return ['Object'];
case 'json':
return ['Array', 'Object'];
default:
return [];
}
}
function getAllowedInstanceType(dataSerializer) {
return dataSerializer === 'multipart' ? 'FormData' : null;
}
function processData(data, dataSerializer, cb) {
var currentDataType = jsUtil.getTypeOf(data);
var allowedDataTypes = getAllowedDataTypes(dataSerializer);
var allowedInstanceType = getAllowedInstanceType(dataSerializer);
if (allowedInstanceType && !global[allowedInstanceType]) {
throw new Error(messages.INSTANCE_TYPE_NOT_SUPPORTED + ' ' + allowedInstanceType);
}
if (allowedInstanceType && !(data instanceof global[allowedInstanceType])) {
throw new Error(messages.INSTANCE_TYPE_MISMATCH_DATA + ' ' + allowedInstanceType);
}
if (!allowedInstanceType && allowedDataTypes.indexOf(currentDataType) === -1) {
throw new Error(messages.TYPE_MISMATCH_DATA + ' ' + allowedDataTypes.join(', '));
}
switch (dataSerializer) {
case 'utf8':
return cb({ text: data });
case 'multipart':
return processFormData(data, cb);
default:
return cb(data);
}
}
function processFormData(data, cb) {
dependencyValidator.checkBlobApi();
dependencyValidator.checkFileReaderApi();
dependencyValidator.checkFormDataApi();
dependencyValidator.checkTextEncoderApi();
var textEncoder = new global.TextEncoder('utf8');
var iterator = data.entries();
var result = {
buffers: [],
names: [],
fileNames: [],
types: []
};
processFormDataIterator(iterator, textEncoder, result, cb);
}
function processFormDataIterator(iterator, textEncoder, result, onFinished) {
var entry = iterator.next();
if (entry.done) {
return onFinished(result);
}
if (entry.value[1] instanceof global.Blob || entry.value[1] instanceof global.File) {
var reader = new global.FileReader();
reader.onload = function() {
result.buffers.push(base64.fromArrayBuffer(reader.result));
result.names.push(entry.value[0]);
result.fileNames.push(entry.value[1].name || 'blob');
result.types.push(entry.value[1].type || '');
processFormDataIterator(iterator, textEncoder, result, onFinished);
};
return reader.readAsArrayBuffer(entry.value[1]);
}
if (jsUtil.getTypeOf(entry.value[1]) === 'String') {
result.buffers.push(base64.fromArrayBuffer(textEncoder.encode(entry.value[1]).buffer));
result.names.push(entry.value[0]);
result.fileNames.push(null);
result.types.push('text/plain');
return processFormDataIterator(iterator, textEncoder, result, onFinished)
}
// skip items which are not supported
processFormDataIterator(iterator, textEncoder, result, onFinished);
}
function handleMissingCallbacks(successFn, failFn) {
if (jsUtil.getTypeOf(successFn) !== 'Function') {
throw new Error(messages.MANDATORY_SUCCESS);
}
if (jsUtil.getTypeOf(failFn) !== 'Function') {
throw new Error(messages.MANDATORY_FAIL);
}
}
function handleMissingOptions(options, globals) {
options = options || {};
return {
data: jsUtil.getTypeOf(options.data) === 'Undefined' ? null : options.data,
filePath: options.filePath,
followRedirect: checkFollowRedirectValue(options.followRedirect || globals.followRedirect),
headers: checkHeadersObject(options.headers || {}),
method: checkHttpMethod(options.method || validHttpMethods[0]),
name: options.name,
params: checkParamsObject(options.params || {}),
responseType: checkResponseType(options.responseType || validResponseTypes[0]),
serializer: checkSerializer(options.serializer || globals.serializer),
timeout: checkTimeoutValue(options.timeout || globals.timeout),
};
}
};