diff --git a/CHANGELOG.md b/CHANGELOG.md index ed00772..2749257 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ## 1.11.0 - Feature #77: allow overriding global settings for each single request +- Feature #11: add support for "browser" platform ## 1.10.2 diff --git a/package.json b/package.json index ad837d2..e07a557 100644 --- a/package.json +++ b/package.json @@ -3,6 +3,7 @@ "version": "1.10.2", "description": "Cordova / Phonegap plugin for communicating with HTTP servers using SSL pinning", "scripts": { + "buildbrowser": "./scripts/build-test-app.sh --browser", "testandroid": "./scripts/build-test-app.sh --android --emulator && ./scripts/test-app.sh --android --emulator", "testios": "./scripts/build-test-app.sh --ios --emulator && ./scripts/test-app.sh --ios --emulator", "testapp": "npm run testandroid && npm run testios", diff --git a/plugin.xml b/plugin.xml index 285027b..ce6128a 100644 --- a/plugin.xml +++ b/plugin.xml @@ -70,4 +70,15 @@ + + + + + + + + + + + diff --git a/scripts/build-test-app.sh b/scripts/build-test-app.sh index 0447e35..468bef8 100755 --- a/scripts/build-test-app.sh +++ b/scripts/build-test-app.sh @@ -1,11 +1,39 @@ #!/usr/bin/env bash set -e -PLATFORM=$([[ "${@#--android}" = "$@" ]] && echo "ios" || echo "android") -TARGET=$([[ "${@#--device}" = "$@" ]] && echo "emulator" || echo "device") ROOT="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"/.. CDV=$ROOT/node_modules/.bin/cordova +PLATFORM=ios +TARGET=emulator + +while :; do + case $1 in + --android) + PLATFORM=android + ;; + --browser) + PLATFORM=browser + ;; + --ios) + PLATFORM=ios + ;; + --device) + TARGET=device + ;; + --emulator) + TARGET=emulator + ;; + -?*) + printf 'WARN: Unknown option (ignored): %s\n' "$1" >&2 + ;; + *) + break + esac + + shift +done + rm -rf $ROOT/temp mkdir $ROOT/temp cp -r $ROOT/test/app-template/ $ROOT/temp/ diff --git a/src/browser/cordova-http-plugin.js b/src/browser/cordova-http-plugin.js new file mode 100644 index 0000000..e7ac36f --- /dev/null +++ b/src/browser/cordova-http-plugin.js @@ -0,0 +1,165 @@ +var pluginId = module.id.slice(0, module.id.lastIndexOf('.')); + +var cordovaProxy = require('cordova/exec/proxy'); +var helpers = require(pluginId + '.helpers'); + +function serializeJsonData(data) { + try { + return JSON.stringify(data); + } catch (err) { + return null; + } +} + +function serializePrimitive(key, value) { + if (value === null || value === undefined) { + return encodeURIComponent(key) + '='; + } + + return encodeURIComponent(key) + '=' + encodeURIComponent(value); +} + +function serializeArray(key, values) { + return values.map(function(value) { + return encodeURIComponent(key) + '[]=' + encodeURIComponent(value); + }).join('&'); +} + +function serializeParams(params) { + if (params === null) return ''; + + return Object.keys(params).map(function(key) { + if (helpers.getTypeOf(params[key]) === 'Array') { + return serializeArray(key, params[key]); + } + + return serializePrimitive(key, params[key]); + }).join('&'); +} + +function createXhrSuccessObject(xhr) { + return { + url: xhr.responseURL, + status: xhr.status, + data: helpers.getTypeOf(xhr.responseText) === 'String' ? xhr.responseText : xhr.response, + headers: xhr.getAllResponseHeaders() + }; +} + +function createXhrFailureObject(xhr) { + var obj = {}; + + obj.headers = xhr.getAllResponseHeaders(); + obj.error = helpers.getTypeOf(xhr.responseText) === 'String' ? xhr.responseText : xhr.response; + obj.error = obj.error || 'advanced-http: please check browser console for error messages'; + + if (xhr.responseURL) obj.url = xhr.responseURL; + if (xhr.status) obj.status = xhr.status; + + return obj; +} + +function setHeaders(xhr, headers) { + Object.keys(headers).forEach(function(key) { + if (key === 'Cookie') return; + + xhr.setRequestHeader(key, headers[key]); + }); +} + +function sendRequest(method, withData, opts, success, failure) { + var data = withData ? opts[1] : null; + var params = withData ? null : serializeParams(opts[1]); + var serializer = withData ? opts[2] : null; + var headers = withData ? opts[3] : opts[2]; + var timeout = withData ? opts[4] : opts[3]; + var url = params ? opts[0] + '?' + params : opts[0]; + + var processedData = null; + var xhr = new XMLHttpRequest(); + + xhr.open(method, url); + + if (headers.Cookie && headers.Cookie.length > 0) { + return failure('advanced-http: custom cookies not supported on browser platform'); + } + + switch (serializer) { + case 'json': + processedData = serializeJsonData(data); + + if (processedData === null) { + return failure('advanced-http: failed serializing data'); + } + + break; + + case 'utf8': + xhr.setRequestHeader('Content-type', 'application/json; charset=utf8'); + processedData = data.text; + break; + + case 'urlencoded': + xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded'); + processedData = serializeParams(data); + break; + } + + xhr.timeout = timeout * 1000; + setHeaders(xhr, headers); + + xhr.onerror = xhr.ontimeout = function () { + return failure(createXhrFailureObject(xhr)); + }; + + xhr.onload = function () { + if (xhr.readyState !== xhr.DONE) return; + + if (xhr.status < 200 || xhr.status > 299) { + return failure(createXhrFailureObject(xhr)); + } + + return success(createXhrSuccessObject(xhr)); + }; + + xhr.send(processedData); +} + +var browserInterface = { + post: function (success, failure, opts) { + return sendRequest('post', true, opts, success, failure); + }, + get: function (success, failure, opts) { + return sendRequest('get', false, opts, success, failure); + }, + put: function (success, failure, opts) { + return sendRequest('put', true, opts, success, failure); + }, + patch: function (success, failure, opts) { + return sendRequest('patch', true, opts, success, failure); + }, + delete: function (success, failure, opts) { + return sendRequest('delete', false, opts, success, failure); + }, + head: function (success, failure, opts) { + return sendRequest('head', false, opts, success, failure); + }, + uploadFile: function (success, failure, opts) { + return failure('advanced-http: function "uploadFile" not supported on browser platform'); + }, + downloadFile: function (success, failure, opts) { + return failure('advanced-http: function "downloadFile" not supported on browser platform'); + }, + enableSSLPinning: function (success, failure, opts) { + return failure('advanced-http: function "enableSSLPinning" not supported on browser platform'); + }, + acceptAllCerts: function (success, failure, opts) { + return failure('advanced-http: function "acceptAllCerts" not supported on browser platform'); + }, + disableRedirect: function (success, failure, opts) { + return failure('advanced-http: function "disableRedirect" not supported on browser platform'); + } +}; + +module.exports = browserInterface; +cordovaProxy.add('CordovaHttpPlugin', browserInterface); diff --git a/test/app-template/config.xml b/test/app-template/config.xml index d6b05c0..0455895 100644 --- a/test/app-template/config.xml +++ b/test/app-template/config.xml @@ -23,6 +23,7 @@ + diff --git a/test/app-template/www/index.html b/test/app-template/www/index.html index 24c8e89..04be6f3 100644 --- a/test/app-template/www/index.html +++ b/test/app-template/www/index.html @@ -1,7 +1,7 @@ - +