mirror of
https://github.com/silkimen/cordova-plugin-advanced-http.git
synced 2026-02-11 00:00:06 +08:00
Compare commits
95 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
516aa6b61d | ||
|
|
a6bf9041a5 | ||
|
|
c41fc11888 | ||
|
|
91515d30bd | ||
|
|
c8638ff204 | ||
|
|
0acf2e2574 | ||
|
|
f4674028b5 | ||
|
|
5919d90698 | ||
|
|
27e959800a | ||
|
|
96f45d7274 | ||
|
|
3dbd07c9df | ||
|
|
cb597c0d30 | ||
|
|
60189a68b3 | ||
|
|
8e4bfdbc70 | ||
|
|
2ae4c7cf39 | ||
|
|
32fdf49d31 | ||
|
|
db0f233737 | ||
|
|
2263950de9 | ||
|
|
2a9d3296cc | ||
|
|
55dd751cec | ||
|
|
af239d3194 | ||
|
|
291e8fe547 | ||
|
|
8b3466e3c3 | ||
|
|
73e76f6333 | ||
|
|
3fcac64597 | ||
|
|
4a437f9435 | ||
|
|
2d15b86cb5 | ||
|
|
63d859ad54 | ||
|
|
6b9ed72b9f | ||
|
|
1719334d39 | ||
|
|
8db15c6c96 | ||
|
|
e58a398c33 | ||
|
|
a637d70ec1 | ||
|
|
6f40ed5cd8 | ||
|
|
8b09e159fa | ||
|
|
1d5642c8ae | ||
|
|
a580ce2067 | ||
|
|
35dc0205aa | ||
|
|
2dbf0d452a | ||
|
|
8a9381ffaa | ||
|
|
f1c95ef6fd | ||
|
|
6877fbdb65 | ||
|
|
a52e243e5f | ||
|
|
9c34f47624 | ||
|
|
3f1ee62088 | ||
|
|
c73b15b620 | ||
|
|
86698ffdcc | ||
|
|
4a396c28e5 | ||
|
|
53224ed875 | ||
|
|
3adec712c9 | ||
|
|
a49bcac81b | ||
|
|
2f01d48abb | ||
|
|
53df68f154 | ||
|
|
441268586b | ||
|
|
df86929148 | ||
|
|
f691d09eb0 | ||
|
|
b68cbcd157 | ||
|
|
a9bdca2d6d | ||
|
|
5186b375a4 | ||
|
|
d28eedebd0 | ||
|
|
25b4a283ea | ||
|
|
ebef9a2944 | ||
|
|
c452b29433 | ||
|
|
60e7debbdf | ||
|
|
c7820c8185 | ||
|
|
f6a15190f3 | ||
|
|
419283c5dd | ||
|
|
7a8f9a0dba | ||
|
|
64731a3794 | ||
|
|
73097b9db9 | ||
|
|
a9c3be124e | ||
|
|
5d5a859cfc | ||
|
|
d67e80dfe0 | ||
|
|
55ba423d2f | ||
|
|
7f34201e8d | ||
|
|
01c43c4e29 | ||
|
|
d34196ff4e | ||
|
|
1957cf4ef7 | ||
|
|
681c384b3e | ||
|
|
9d6406277c | ||
|
|
b9bc1b0054 | ||
|
|
d17f44b641 | ||
|
|
11515a8400 | ||
|
|
937296b371 | ||
|
|
b60086df0d | ||
|
|
a48a91dd14 | ||
|
|
e8a72a53cc | ||
|
|
efbdc21221 | ||
|
|
06d7d859e7 | ||
|
|
239b82c08e | ||
|
|
e987652d97 | ||
|
|
068b25b6f9 | ||
|
|
8c55572eb8 | ||
|
|
48afeefbc3 | ||
|
|
292d726b20 |
@@ -1,16 +1,13 @@
|
||||
|
||||
# EditorConfig helps developers define and maintain consistent
|
||||
# coding styles between different editors and IDEs
|
||||
# editorconfig.org
|
||||
|
||||
root = true
|
||||
|
||||
|
||||
[*]
|
||||
|
||||
# Change these settings to your own preference
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
indent_size = 2
|
||||
|
||||
# We recommend you to keep these unchanged
|
||||
end_of_line = lf
|
||||
@@ -19,4 +16,4 @@ trim_trailing_whitespace = true
|
||||
insert_final_newline = true
|
||||
|
||||
[*.md]
|
||||
trim_trailing_whitespace = false
|
||||
trim_trailing_whitespace = false
|
||||
|
||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -1,5 +1,8 @@
|
||||
node_modules/**
|
||||
test/app-template/www/certificates/*.cer
|
||||
tags
|
||||
.zedstate
|
||||
npm-debug.log
|
||||
/temp
|
||||
/android-sdk-macosx.zip
|
||||
/android-sdk-macosx/**
|
||||
|
||||
34
.travis.yml
34
.travis.yml
@@ -4,38 +4,36 @@ language: objective-c
|
||||
os: osx
|
||||
osx_image: xcode9.1
|
||||
|
||||
env:
|
||||
- TARGET_PLATFORM=android
|
||||
- TARGET_PLATFORM=ios
|
||||
|
||||
cache:
|
||||
directories:
|
||||
- node_modules
|
||||
|
||||
addons:
|
||||
sauce_connect:
|
||||
username: silkimen
|
||||
jwt: RZHC8x5ggrXdu1xzhhHmQDwege9s3putJXY1ZG8+MNMaBTLfLBWzFsHuR6Lvz+XnrAT/CTGG957kw6ikSaV6VEkGvtO91irZoJyShjPq2hBbn2CaEbo91Eq8iNYaRG+4FVMxoHa6xpF/HtvOLQdIkURc/lzLj/BOFMmtV/d3adLDcryQZuYB211iN4d6exGHMQe8uvJdkCy4ac85guhF8KmAELyaVa0rx0m6gNaszWU9BJ8Rn+4HJbJtfpQcU1bJN43Dx8forRU/Com53K+KFtDKPUdBHZnuENrZrQ+8RU59vdLrHwsCvP9elJFkcX9xk/r45oUGXhqVV3vMyaqTa9YUO772rhgKuAi4TqiaR51H58KWqynp7wOZwL5FqJs0KzL5rNDDIoKKrklnOidS4RAUKXCi1CUNXwDdOo4Kd96cYOIHqpwa7Beci8CtVlzd/49yE9/AXnZYVwp10uKZvJJdliAOHhVEAtCIp8PzHOOPYJsXvUcEU4ORWWWpusBAz6wFiLOL4d/CAHNj6wDFliRexBrv/Wunu5ifva4oVJWrtAtyGDtsX8kBkf8OcIdy/aPUIIBrbW1sapjPFymMGeL/KkSZRjEy7KjFZKZh9L7sJE56sq+IUremFbcyaX1E3rho6Cs3ongLaKhL9f9vz8EFs7//w8pNlNS9EUdOU68=
|
||||
sauce_connect: true
|
||||
|
||||
before_install:
|
||||
- export LANG=en_US.UTF-8
|
||||
- brew update
|
||||
|
||||
install:
|
||||
- npm install
|
||||
- brew install gradle
|
||||
- wget http://dl.google.com/android/android-sdk_r24.4-macosx.zip
|
||||
- tar -xvf android-sdk_r24.4-macosx.zip
|
||||
- echo y | ./android-sdk-macosx/tools/android update sdk --no-ui --all --filter platform-tools
|
||||
- echo y | ./android-sdk-macosx/tools/android update sdk --no-ui --all --filter build-tools-25.0.0
|
||||
- echo y | ./android-sdk-macosx/tools/android update sdk --no-ui --all --filter android-25
|
||||
- echo y | ./android-sdk-macosx/tools/android update sdk --no-ui --all --filter extra-android-support
|
||||
- echo y | ./android-sdk-macosx/tools/android update sdk --no-ui --all --filter extra-android-m2repository
|
||||
- echo y | ./android-sdk-macosx/tools/android update sdk --no-ui --all --filter extra-google-m2repository
|
||||
- export ANDROID_HOME=./android-sdk-macosx
|
||||
- export PATH=${PATH}:$ANDROID_HOME/tools:$ANDROID_HOME/platform-tools:$ANDROID_HOME/build-tools/23.0.2
|
||||
- if [ $TARGET_PLATFORM = "android" ]; then
|
||||
brew update &&
|
||||
brew install gradle &&
|
||||
scripts/setup-android-sdk.sh &&
|
||||
export ANDROID_HOME=$(pwd)/android-sdk-macosx &&
|
||||
export PATH=${PATH}:$ANDROID_HOME/tools:$ANDROID_HOME/platform-tools:$ANDROID_HOME/build-tools/23.0.2;
|
||||
fi
|
||||
|
||||
script:
|
||||
- travis_wait scripts/build-test-app.sh
|
||||
- scripts/upload-artifact.sh
|
||||
- npm run testjs
|
||||
- scripts/test-app.sh --ios --emulator
|
||||
- npm run updatecert
|
||||
- travis_wait scripts/build-test-app.sh --$TARGET_PLATFORM --emulator &&
|
||||
scripts/upload-artifact.sh --$TARGET_PLATFORM &&
|
||||
scripts/test-app.sh --$TARGET_PLATFORM --emulator;
|
||||
|
||||
after_success:
|
||||
|
||||
|
||||
56
CHANGELOG.md
56
CHANGELOG.md
@@ -1,5 +1,61 @@
|
||||
# Changelog
|
||||
|
||||
## 2.0.0
|
||||
|
||||
- Feature #103: implement HTTP SSL cert modes
|
||||
|
||||
- :warning: **Breaking Change**: Removed AngularJS (v1) integration service
|
||||
- :warning: **Breaking Change**: Removed "enableSSLPinning" and "acceptAllCerts", use "setSSLCertMode" instead
|
||||
- :warning: **Breaking Change**: Certificates must be placed in "www/certificates" folder
|
||||
|
||||
## 1.11.1
|
||||
|
||||
- Fixed #92: headers not deserialized on platform "browser"
|
||||
|
||||
## 1.11.0
|
||||
|
||||
- Feature #77: allow overriding global settings for each single request
|
||||
- Feature #11: add support for "browser" platform
|
||||
|
||||
## 1.10.2
|
||||
|
||||
- Fixed #78: overriding header "Content-Type" not working on Android
|
||||
- Fixed #79: PATCH operation not working on Android API level 19 and older (thanks chax)
|
||||
- Fixed #83: App crashes on error during download operation on iOS (thanks troyanskiy)
|
||||
- Fixed #76: upload sequence is not respecting order of operations needed by some sites (thanks Johny101)
|
||||
|
||||
- :warning: **Deprecation**: AngularJS service is deprecated now and will be removed anytime soon
|
||||
|
||||
## 1.10.1
|
||||
|
||||
- Fixed #71: does not encode query string in URL correctly on Android
|
||||
- Fixed #72: app crashes if response encoding is not UTF-8 (thanks jkfb)
|
||||
|
||||
## 1.10.0
|
||||
|
||||
- Feature #34: add new serializer "utf8" sending utf-8 encoded plain text (thanks robertocapuano)
|
||||
|
||||
## 1.9.1
|
||||
|
||||
- Fixed #45: does not encode arrays correctly as HTTP GET parameter on Android
|
||||
- Fixed #54: requests are not responding on iOS with non-string values in header object
|
||||
- Fixed #58: white-list of allowed content-types should be removed for iOS
|
||||
|
||||
## v1.9.0
|
||||
|
||||
- Feature #44: "getCookieString" method is exposed
|
||||
- Feature #43: added support for content type "application/javascript" on iOS (thanks wh33ler)
|
||||
- Feature #46: "setCookie" allows adding custom cookies
|
||||
|
||||
## v1.8.1
|
||||
|
||||
- Fixed #27: "uploadFile" method doesn't return data object on iOS (thanks Faisalali23 and laiyinjie)
|
||||
- Fixed #40: generic error codes are different on Android and iOS
|
||||
|
||||
## v1.8.0
|
||||
|
||||
- Feature #33: response object contains response url
|
||||
|
||||
## v1.7.1
|
||||
|
||||
- Fixed #36: setting basic authentication not working correctly (thanks jkfb)
|
||||
|
||||
180
README.md
180
README.md
@@ -6,7 +6,8 @@ Cordova Advanced HTTP
|
||||
[](https://travis-ci.org/silkimen/cordova-plugin-advanced-http)
|
||||
|
||||
|
||||
Cordova / Phonegap plugin for communicating with HTTP servers. Supports iOS and Android.
|
||||
Cordova / Phonegap plugin for communicating with HTTP servers. Supports iOS, Android and [Browser](#browserSupport).
|
||||
|
||||
This is a fork of [Wymsee's Cordova-HTTP plugin](https://github.com/wymsee/cordova-HTTP).
|
||||
|
||||
## Advantages over Javascript requests
|
||||
@@ -32,20 +33,13 @@ cordova plugin add cordova-plugin-advanced-http
|
||||
|
||||
## Usage
|
||||
|
||||
### Without AngularJS
|
||||
### Plain Cordova
|
||||
|
||||
This plugin registers a global object located at `cordova.plugin.http`.
|
||||
|
||||
### With AngularJS
|
||||
|
||||
This plugin creates a cordovaHTTP service inside of a cordovaHTTP module. You must load the module when you create your app's module.
|
||||
|
||||
```js
|
||||
var app = angular.module('myApp', ['ngRoute', 'ngAnimate', 'cordovaHTTP']);
|
||||
```
|
||||
|
||||
You can then inject the cordovaHTTP service into your controllers. The functions can then be used identically to the examples shown below except that instead of accepting success and failure callback functions, each function returns a promise. For more information on promises in AngularJS read the [AngularJS docs](http://docs.angularjs.org/api/ng/service/$q). For more info on promises in general check out this article on [html5rocks](http://www.html5rocks.com/en/tutorials/es6/promises/). Make sure that you load cordova.js or phonegap.js after AngularJS is loaded.
|
||||
### With Ionic-native wrapper
|
||||
|
||||
Check the [Ionic docs](https://ionicframework.com/docs/native/http/) for how to use this plugin with Ionic-native.
|
||||
|
||||
## Synchronous Functions
|
||||
|
||||
@@ -63,8 +57,8 @@ This sets up all future requests to use Basic HTTP authentication with the given
|
||||
cordova.plugin.http.useBasicAuth('user', 'password');
|
||||
```
|
||||
|
||||
### setHeader
|
||||
Set a header for all future requests to a specified host. Takes a hostname, a header and a value.
|
||||
### setHeader<a name="setHeader"></a>
|
||||
Set a header for all future requests to a specified host. Takes a hostname, a header and a value (must be a string value).
|
||||
|
||||
```js
|
||||
cordova.plugin.http.setHeader('Hostname', 'Header', 'Value');
|
||||
@@ -87,25 +81,21 @@ cordova.plugin.http.setHeader('www.example.com', 'Header', 'Value');
|
||||
cordova.plugin.http.setHeader('www.example.com:8080', 'Header', 'Value');
|
||||
```
|
||||
|
||||
### disableRedirect
|
||||
If set to `true`, it won't follow redirects automatically. This is a global setting.
|
||||
|
||||
```js
|
||||
cordova.plugin.http.disableRedirect(true);
|
||||
```
|
||||
|
||||
### setDataSerializer
|
||||
### setDataSerializer<a name="setDataSerializer"></a>
|
||||
Set the data serializer which will be used for all future PATCH, POST and PUT requests. Takes a string representing the name of the serializer.
|
||||
|
||||
```js
|
||||
cordova.plugin.http.setDataSerializer('urlencoded');
|
||||
```
|
||||
|
||||
You can choose one of these two:
|
||||
You can choose one of these:
|
||||
* `urlencoded`: send data as url encoded content in body (content type "application/x-www-form-urlencoded")
|
||||
* `json`: send data as JSON encoded content in body (content type "application/json")
|
||||
* `utf8`: send data as plain UTF8 encoded string in body (content type "plain/text")
|
||||
|
||||
Caution: `urlencoded` does not support serializing deep structures whereas `json` does.
|
||||
You can also override the default content type headers by specifying your own headers (see [setHeader](#setHeader)).
|
||||
|
||||
__Caution__: `urlencoded` does not support serializing deep structures whereas `json` does.
|
||||
|
||||
### setRequestTimeout
|
||||
Set how long to wait for a request to respond, in seconds.
|
||||
@@ -114,6 +104,20 @@ Set how long to wait for a request to respond, in seconds.
|
||||
cordova.plugin.http.setRequestTimeout(5.0);
|
||||
```
|
||||
|
||||
### getCookieString
|
||||
Returns saved cookies (as string) matching given URL.
|
||||
|
||||
```js
|
||||
cordova.plugin.http.getCookieString(url);
|
||||
```
|
||||
|
||||
### setCookie
|
||||
Add a custom cookie. Takes a URL, a cookie string and an options object. See [ToughCookie documentation](https://github.com/salesforce/tough-cookie#setcookiecookieorstring-currenturl-options-cberrcookie) for allowed options.
|
||||
|
||||
```js
|
||||
cordova.plugin.http.setCookie(url, cookie, options);
|
||||
```
|
||||
|
||||
### clearCookies
|
||||
Clear the cookie store.
|
||||
|
||||
@@ -124,47 +128,108 @@ cordova.plugin.http.clearCookies();
|
||||
## Asynchronous Functions
|
||||
These functions all take success and error callbacks as their last 2 arguments.
|
||||
|
||||
### enableSSLPinning
|
||||
Enable or disable SSL pinning. This defaults to false.
|
||||
### setSSLCertMode<a name="setSSLCertMode"></a>
|
||||
Set SSL Cert handling mode, being one of the following values:
|
||||
|
||||
To use SSL pinning you must include at least one .cer SSL certificate in your app project. You can pin to your server certificate or to one of the issuing CA certificates. For ios include your certificate in the root level of your bundle (just add the .cer file to your project/target at the root level). For android include your certificate in your project's platforms/android/assets folder. In both cases all .cer files found will be loaded automatically. If you only have a .pem certificate see this [stackoverflow answer](http://stackoverflow.com/a/16583429/3182729). You want to convert it to a DER encoded certificate with a .cer extension.
|
||||
* `default`: default SSL cert handling using system's CA certs
|
||||
* `nocheck`: disable SSL cert checking, trusting all certs (meant to be used only for testing purposes)
|
||||
* `pinned`: trust only provided certs
|
||||
|
||||
As an alternative, you can store your .cer files in the www/certificates folder.
|
||||
To use SSL pinning you must include at least one `.cer` SSL certificate in your app project. You can pin to your server certificate or to one of the issuing CA certificates. Include your certificate in the `www/certificates` folder. All `.cer` files found there will be loaded automatically.
|
||||
|
||||
:warning: Your certificate must be DER encoded! If you only have a PEM enoceded certificate see this [stackoverflow answer](http://stackoverflow.com/a/16583429/3182729). You want to convert it to a DER encoded certificate with a .cer extension.
|
||||
|
||||
```js
|
||||
cordova.plugin.http.enableSSLPinning(true, function() {
|
||||
// enable SSL pinning
|
||||
cordova.plugin.http.setSSLCertMode('pinned', function() {
|
||||
console.log('success!');
|
||||
}, function() {
|
||||
console.log('error :(');
|
||||
});
|
||||
|
||||
// use system's default CA certs
|
||||
cordova.plugin.http.setSSLCertMode('default', function() {
|
||||
console.log('success!');
|
||||
}, function() {
|
||||
console.log('error :(');
|
||||
});
|
||||
|
||||
// disable SSL cert checking, only meant for testing purposes, do NOT use in production!
|
||||
cordova.plugin.http.setSSLCertMode('nocheck', function() {
|
||||
console.log('success!');
|
||||
}, function() {
|
||||
console.log('error :(');
|
||||
});
|
||||
```
|
||||
|
||||
### acceptAllCerts
|
||||
Accept all SSL certificates. Or disable accepting all certificates. This defaults to false.
|
||||
### enableSSLPinning (obsolete)
|
||||
This function was removed in 2.0.0. Use ["setSSLCertMode"](#setSSLCertMode) to enable SSL pinning (mode "pinned").
|
||||
|
||||
### acceptAllCerts (obsolete)
|
||||
This function was removed in 2.0.0. Use ["setSSLCertMode"](#setSSLCertMode) to disable checking certs (mode "nocheck").
|
||||
|
||||
### disableRedirect
|
||||
If set to `true`, it won't follow redirects automatically. This defaults to false.
|
||||
|
||||
```js
|
||||
cordova.plugin.http.acceptAllCerts(true, function() {
|
||||
cordova.plugin.http.disableRedirect(true, function() {
|
||||
console.log('success!');
|
||||
}, function() {
|
||||
console.log('error :(');
|
||||
});
|
||||
```
|
||||
|
||||
### validateDomainName
|
||||
This function was removed in v1.6.2. Domain name validation is disabled automatically when you enable "acceptAllCerts".
|
||||
### validateDomainName (obsolete)
|
||||
This function was removed in v1.6.2. Domain name validation is disabled automatically when you set SSL cert mode to "nocheck".
|
||||
|
||||
### removeCookies
|
||||
Remove all cookies associated with a given URL.
|
||||
|
||||
```js
|
||||
cordova.plugin.http.removeCookies(url);
|
||||
cordova.plugin.http.removeCookies(url, callback);
|
||||
```
|
||||
|
||||
### sendRequest
|
||||
Execute a HTTP request. Takes a URL and an options object. This is the internally used implementation of the following shorthand functions ([post](#post), [get](#get), [put](#put), [patch](#patch), [delete](#delete), [head](#head), [uploadFile](#uploadFile) and [downloadFile](#downloadFile)). You can use this function, if you want to override global settings for each single request.
|
||||
|
||||
The options object contains following keys:
|
||||
|
||||
* `method`: HTTP method to be used, defaults to `get`, needs to be one of the following values:
|
||||
* `get`, `post`, `put`, `patch`, `head`, `delete`, `upload`, `download`
|
||||
* `data`: payload to be send to the server (only applicable on `post`, `put` or `patch` methods)
|
||||
* `params`: query params to be appended to the URL (only applicable on `get`, `head`, `delete`, `upload` or `download` methods)
|
||||
* `serializer`: data serializer to be used (only applicable on `post`, `put` or `patch` methods), defaults to global serializer value, see [setDataSerializer](#setDataSerializer) for supported values
|
||||
* `timeout`: timeout value for the request in seconds, defaults to global timeout value
|
||||
* `headers`: headers object (key value pair), will be merged with global values
|
||||
* `filePath`: filePath to be used during upload and download see [uploadFile](#uploadFile) and [downloadFile](#downloadFile) for detailed information
|
||||
* `name`: name to be used during upload see [uploadFile](#uploadFile) for detailed information
|
||||
|
||||
Here's a quick example:
|
||||
|
||||
```js
|
||||
const options = {
|
||||
method: 'post',
|
||||
data: { id: 12, message: 'test' },
|
||||
headers: { Authorization: 'OAuth2: token' }
|
||||
};
|
||||
|
||||
cordova.plugin.http.sendRequest('https://google.com/', options, function(response) {
|
||||
// prints 200
|
||||
console.log(response.status);
|
||||
}, function(response) {
|
||||
// prints 403
|
||||
console.log(response.status);
|
||||
|
||||
//prints Permission denied
|
||||
console.log(response.error);
|
||||
});
|
||||
```
|
||||
|
||||
### post<a name="post"></a>
|
||||
Execute a POST request. Takes a URL, data, and headers.
|
||||
|
||||
#### success
|
||||
The success function receives a response object with 3 properties: status, data, and headers. **status** is the HTTP response code as numeric value. **data** is the response from the server as a string. **headers** is an object with the headers. The keys of the returned object are the header names and the values are the respective header values. All header names are lowercase.
|
||||
The success function receives a response object with 4 properties: status, data, url, and headers. **status** is the HTTP response code as numeric value. **data** is the response from the server as a string. **url** is the final URL obtained after any redirects as a string. **headers** is an object with the headers. The keys of the returned object are the header names and the values are the respective header values. All header names are lowercase.
|
||||
|
||||
Here's a quick example:
|
||||
|
||||
@@ -172,6 +237,7 @@ Here's a quick example:
|
||||
{
|
||||
status: 200,
|
||||
data: '{"id": 12, "message": "test"}',
|
||||
url: 'http://example.net/rest'
|
||||
headers: {
|
||||
'content-length': '247'
|
||||
}
|
||||
@@ -204,7 +270,7 @@ cordova.plugin.http.post('https://google.com/', {
|
||||
```
|
||||
|
||||
#### failure
|
||||
The error function receives a response object with 3 properties: status, error and headers. **status** is the HTTP response code as numeric value. **error** is the error response from the server as a string. **headers** is an object with the headers. The keys of the returned object are the header names and the values are the respective header values. All header names are lowercase.
|
||||
The error function receives a response object with 4 properties: status, error, url, and headers (url and headers being optional). **status** is the HTTP response code as numeric value. **error** is the error response from the server as a string. **url** is the final URL obtained after any redirects as a string. **headers** is an object with the headers. The keys of the returned object are the header names and the values are the respective header values. All header names are lowercase.
|
||||
|
||||
Here's a quick example:
|
||||
|
||||
@@ -212,18 +278,19 @@ Here's a quick example:
|
||||
{
|
||||
status: 403,
|
||||
error: 'Permission denied',
|
||||
url: 'http://example.net/noperm'
|
||||
headers: {
|
||||
'content-length': '247'
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### get
|
||||
### get<a name="get"></a>
|
||||
Execute a GET request. Takes a URL, parameters, and headers. See the [post](#post) documentation for details on what is returned on success and failure.
|
||||
|
||||
```js
|
||||
cordova.plugin.http.get('https://google.com/', {
|
||||
id: 12,
|
||||
id: '12',
|
||||
message: 'test'
|
||||
}, { Authorization: 'OAuth2: token' }, function(response) {
|
||||
console.log(response.status);
|
||||
@@ -232,24 +299,24 @@ cordova.plugin.http.get('https://google.com/', {
|
||||
});
|
||||
```
|
||||
|
||||
### put
|
||||
### put<a name="put"></a>
|
||||
Execute a PUT request. Takes a URL, data, and headers. See the [post](#post) documentation for details on what is returned on success and failure.
|
||||
|
||||
### patch
|
||||
### patch<a name="patch"></a>
|
||||
Execute a PATCH request. Takes a URL, data, and headers. See the [post](#post) documentation for details on what is returned on success and failure.
|
||||
|
||||
### delete
|
||||
### delete<a name="delete"></a>
|
||||
Execute a DELETE request. Takes a URL, parameters, and headers. See the [post](#post) documentation for details on what is returned on success and failure.
|
||||
|
||||
### head
|
||||
### head<a name="head"></a>
|
||||
Execute a HEAD request. Takes a URL, parameters, and headers. See the [post](#post) documentation for details on what is returned on success and failure.
|
||||
|
||||
### uploadFile
|
||||
### uploadFile<a name="uploadFile"></a>
|
||||
Uploads a file saved on the device. Takes a URL, parameters, headers, filePath, and the name of the parameter to pass the file along as. See the [post](#post) documentation for details on what is returned on success and failure.
|
||||
|
||||
```js
|
||||
cordova.plugin.http.uploadFile("https://google.com/", {
|
||||
id: 12,
|
||||
id: '12',
|
||||
message: 'test'
|
||||
}, { Authorization: 'OAuth2: token' }, 'file:///somepicture.jpg', 'picture', function(response) {
|
||||
console.log(response.status);
|
||||
@@ -258,12 +325,12 @@ cordova.plugin.http.uploadFile("https://google.com/", {
|
||||
});
|
||||
```
|
||||
|
||||
### downloadFile
|
||||
### downloadFile<a name="downloadFile"></a>
|
||||
Downloads a file and saves it to the device. Takes a URL, parameters, headers, and a filePath. See [post](#post) documentation for details on what is returned on failure. On success this function returns a cordova [FileEntry object](http://cordova.apache.org/docs/en/3.3.0/cordova_file_file.md.html#FileEntry).
|
||||
|
||||
```js
|
||||
cordova.plugin.http.downloadFile("https://google.com/", {
|
||||
id: 12,
|
||||
id: '12',
|
||||
message: 'test'
|
||||
}, { Authorization: 'OAuth2: token' }, 'file:///somepicture.jpg', function(entry) {
|
||||
// prints the filename
|
||||
@@ -276,15 +343,28 @@ cordova.plugin.http.downloadFile("https://google.com/", {
|
||||
});
|
||||
```
|
||||
|
||||
## Browser support<a name="browserSupport"></a>
|
||||
|
||||
This plugin supports a very restricted set of functions on the browser platform.
|
||||
It's meant for testing purposes, not for production grade usage.
|
||||
|
||||
Following features are *not* supported:
|
||||
|
||||
* Manipulating Cookies
|
||||
* Uploading and Downloading files
|
||||
* Pinning SSL certificate
|
||||
* Disabling SSL certificate check
|
||||
* Disabling transparently following redirects (HTTP codes 3xx)
|
||||
|
||||
## Libraries
|
||||
|
||||
This plugin utilizes some awesome open source networking libraries. These are both MIT licensed:
|
||||
This plugin utilizes some awesome open source libraries:
|
||||
|
||||
- iOS - [AFNetworking](https://github.com/AFNetworking/AFNetworking)
|
||||
- Android - [http-request](https://github.com/kevinsawicki/http-request)
|
||||
- iOS - [AFNetworking](https://github.com/AFNetworking/AFNetworking) (MIT licensed)
|
||||
- Android - [http-request](https://github.com/kevinsawicki/http-request) (MIT licensed)
|
||||
- Cookie handling - [tough-cookie](https://github.com/salesforce/tough-cookie) (BSD-3-Clause licensed)
|
||||
|
||||
We made a few modifications to both of them.
|
||||
We made a few modifications to the networking libraries.
|
||||
|
||||
## Contribute & Develop
|
||||
|
||||
|
||||
10
package.json
10
package.json
@@ -1,9 +1,13 @@
|
||||
{
|
||||
"name": "cordova-plugin-advanced-http",
|
||||
"version": "1.7.1",
|
||||
"version": "2.0.0",
|
||||
"description": "Cordova / Phonegap plugin for communicating with HTTP servers using SSL pinning",
|
||||
"scripts": {
|
||||
"testapp": "./scripts/build-test-app.sh && ./scripts/test-app.sh --ios --emulator",
|
||||
"updatecert": "node ./scripts/update-test-cert.js",
|
||||
"buildbrowser": "./scripts/build-test-app.sh --browser",
|
||||
"testandroid": "npm run updatecert && ./scripts/build-test-app.sh --android --emulator && ./scripts/test-app.sh --android --emulator",
|
||||
"testios": "npm run updatecert && ./scripts/build-test-app.sh --ios --emulator && ./scripts/test-app.sh --ios --emulator",
|
||||
"testapp": "npm run testandroid && npm run testios",
|
||||
"testjs": "mocha ./test/js-mocha-specs.js",
|
||||
"test": "npm run testjs && npm run testapp",
|
||||
"release": "npm run test && ./scripts/release.sh"
|
||||
@@ -55,7 +59,7 @@
|
||||
"chai": "4.1.2",
|
||||
"chai-as-promised": "7.1.1",
|
||||
"colors": "1.1.2",
|
||||
"cordova": "7.0.1",
|
||||
"cordova": "7.1.0",
|
||||
"mocha": "4.0.0",
|
||||
"mock-require": "2.0.2",
|
||||
"mz": "2.7.0",
|
||||
|
||||
21
plugin.xml
21
plugin.xml
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<plugin xmlns="http://www.phonegap.com/ns/plugins/1.0" xmlns:android="http://schemas.android.com/apk/res/android" id="cordova-plugin-advanced-http" version="1.7.1">
|
||||
<plugin xmlns="http://www.phonegap.com/ns/plugins/1.0" xmlns:android="http://schemas.android.com/apk/res/android" id="cordova-plugin-advanced-http" version="2.0.0">
|
||||
<name>Advanced HTTP plugin</name>
|
||||
<description>
|
||||
Cordova / Phonegap plugin for communicating with HTTP servers using SSL pinning
|
||||
@@ -10,9 +10,10 @@
|
||||
<dependency id="cordova-plugin-file" version=">=2.0.0"/>
|
||||
<js-module src="www/lodash.js" name="lodash"/>
|
||||
<js-module src="www/umd-tough-cookie.js" name="tough-cookie"/>
|
||||
<js-module src="www/messages.js" name="messages"/>
|
||||
<js-module src="www/local-storage-store.js" name="local-storage-store"/>
|
||||
<js-module src="www/cookie-handler.js" name="cookie-handler"/>
|
||||
<js-module src="www/angular-integration.js" name="angular-integration"/>
|
||||
<js-module src="www/helpers.js" name="helpers"/>
|
||||
<js-module src="www/advanced-http.js" name="http">
|
||||
<clobbers target="cordova.plugin.http"/>
|
||||
</js-module>
|
||||
@@ -24,6 +25,7 @@
|
||||
</config-file>
|
||||
<header-file src="src/ios/CordovaHttpPlugin.h"/>
|
||||
<header-file src="src/ios/TextResponseSerializer.h"/>
|
||||
<header-file src="src/ios/TextRequestSerializer.h"/>
|
||||
<header-file src="src/ios/AFNetworking/AFHTTPSessionManager.h"/>
|
||||
<header-file src="src/ios/AFNetworking/AFNetworking.h"/>
|
||||
<header-file src="src/ios/AFNetworking/AFNetworkReachabilityManager.h"/>
|
||||
@@ -31,14 +33,17 @@
|
||||
<header-file src="src/ios/AFNetworking/AFURLRequestSerialization.h"/>
|
||||
<header-file src="src/ios/AFNetworking/AFURLResponseSerialization.h"/>
|
||||
<header-file src="src/ios/AFNetworking/AFURLSessionManager.h"/>
|
||||
<header-file src="src/ios/SDNetworkActivityIndicator/SDNetworkActivityIndicator.h"/>
|
||||
<source-file src="src/ios/CordovaHttpPlugin.m"/>
|
||||
<source-file src="src/ios/TextResponseSerializer.m"/>
|
||||
<source-file src="src/ios/TextRequestSerializer.m"/>
|
||||
<source-file src="src/ios/AFNetworking/AFHTTPSessionManager.m"/>
|
||||
<source-file src="src/ios/AFNetworking/AFNetworkReachabilityManager.m"/>
|
||||
<source-file src="src/ios/AFNetworking/AFSecurityPolicy.m"/>
|
||||
<source-file src="src/ios/AFNetworking/AFURLRequestSerialization.m"/>
|
||||
<source-file src="src/ios/AFNetworking/AFURLResponseSerialization.m"/>
|
||||
<source-file src="src/ios/AFNetworking/AFURLSessionManager.m"/>
|
||||
<source-file src="src/ios/SDNetworkActivityIndicator/SDNetworkActivityIndicator.m"/>
|
||||
<framework src="Security.framework"/>
|
||||
<framework src="SystemConfiguration.framework"/>
|
||||
</platform>
|
||||
@@ -52,6 +57,7 @@
|
||||
<uses-permission android:name="android.permission.INTERNET"/>
|
||||
</config-file>
|
||||
<source-file src="src/android/com/github/kevinsawicki/http/HttpRequest.java" target-dir="src/com/github/kevinsawicki/http"/>
|
||||
<source-file src="src/android/com/github/kevinsawicki/http/OkConnectionFactory.java" target-dir="src/com/github/kevinsawicki/http"/>
|
||||
<source-file src="src/android/com/github/kevinsawicki/http/TLSSocketFactory.java" target-dir="src/com/github/kevinsawicki/http"/>
|
||||
<source-file src="src/android/com/synconset/cordovahttp/CordovaHttp.java" target-dir="src/com/synconset/cordovahttp"/>
|
||||
<source-file src="src/android/com/synconset/cordovahttp/CordovaHttpDelete.java" target-dir="src/com/synconset/cordovahttp"/>
|
||||
@@ -63,5 +69,16 @@
|
||||
<source-file src="src/android/com/synconset/cordovahttp/CordovaHttpPut.java" target-dir="src/com/synconset/cordovahttp"/>
|
||||
<source-file src="src/android/com/synconset/cordovahttp/CordovaHttpPatch.java" target-dir="src/com/synconset/cordovahttp"/>
|
||||
<source-file src="src/android/com/synconset/cordovahttp/CordovaHttpUpload.java" target-dir="src/com/synconset/cordovahttp"/>
|
||||
<framework src="com.squareup.okhttp3:okhttp-urlconnection:3.10.0"/>
|
||||
</platform>
|
||||
<platform name="browser">
|
||||
<config-file target="config.xml" parent="/*">
|
||||
<feature name="CordovaHttpPlugin">
|
||||
<param name="browser-package" value="CordovaHttpPlugin"/>
|
||||
</feature>
|
||||
</config-file>
|
||||
<js-module src="src/browser/cordova-http-plugin.js" name="http-proxy">
|
||||
<runs/>
|
||||
</js-module>
|
||||
</platform>
|
||||
</plugin>
|
||||
@@ -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/
|
||||
|
||||
12
scripts/setup-android-sdk.sh
Executable file
12
scripts/setup-android-sdk.sh
Executable file
@@ -0,0 +1,12 @@
|
||||
#!/usr/bin/env bash
|
||||
set -e
|
||||
|
||||
curl http://dl.google.com/android/android-sdk_r24.4-macosx.zip -o android-sdk-macosx.zip
|
||||
tar -xvf android-sdk-macosx.zip
|
||||
|
||||
echo y | ./android-sdk-macosx/tools/android update sdk --no-ui --all --filter platform-tools
|
||||
echo y | ./android-sdk-macosx/tools/android update sdk --no-ui --all --filter build-tools-25.0.0
|
||||
echo y | ./android-sdk-macosx/tools/android update sdk --no-ui --all --filter android-25
|
||||
echo y | ./android-sdk-macosx/tools/android update sdk --no-ui --all --filter extra-android-support
|
||||
echo y | ./android-sdk-macosx/tools/android update sdk --no-ui --all --filter extra-android-m2repository
|
||||
echo y | ./android-sdk-macosx/tools/android update sdk --no-ui --all --filter extra-google-m2repository
|
||||
@@ -3,6 +3,11 @@ set -e
|
||||
|
||||
ROOT="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"/..
|
||||
|
||||
if [ $CI == "true" ] && ([ -z $SAUCE_USERNAME ] || [ -z $SAUCE_ACCESS_KEY ]); then
|
||||
echo "Skipping CI tests, because Saucelabs credentials are not set.";
|
||||
exit 0;
|
||||
fi
|
||||
|
||||
pushd $ROOT
|
||||
./node_modules/.bin/mocha ./test/app-mocha-specs/test.js "$@"
|
||||
popd
|
||||
|
||||
42
scripts/update-test-cert.js
Normal file
42
scripts/update-test-cert.js
Normal file
@@ -0,0 +1,42 @@
|
||||
const fs = require('fs');
|
||||
const https = require('https');
|
||||
const path = require('path');
|
||||
|
||||
const SOURCE_HOST = 'httpbin.org';
|
||||
const TARGET_PATH = path.join(__dirname, '../test/app-template/www/certificates/httpbin.org.cer');
|
||||
|
||||
const getCert = hostname => new Promise((resolve, reject) => {
|
||||
const options = {
|
||||
hostname,
|
||||
agent: false,
|
||||
rejectUnauthorized: false,
|
||||
ciphers: 'ALL'
|
||||
};
|
||||
|
||||
const req = https.get(options, response => {
|
||||
const certificate = response.socket.getPeerCertificate();
|
||||
|
||||
if (certificate === null) {
|
||||
return reject({ message: 'The website did not provide a certificate' });
|
||||
}
|
||||
|
||||
resolve(certificate);
|
||||
});
|
||||
|
||||
req.on('error', error => {
|
||||
return reject(error)
|
||||
});
|
||||
|
||||
req.end();
|
||||
});
|
||||
|
||||
console.log(`Updating test certificate from ${SOURCE_HOST}`);
|
||||
|
||||
getCert(SOURCE_HOST)
|
||||
.then(cert => {
|
||||
fs.writeFileSync(TARGET_PATH, cert.raw);
|
||||
})
|
||||
.catch(error => {
|
||||
console.error(`Updating test cert failed: ${error}`);
|
||||
process.exit(1);
|
||||
});
|
||||
@@ -1,16 +1,30 @@
|
||||
#!/usr/bin/env bash
|
||||
set -e
|
||||
|
||||
PLATFORM=$([[ "${@#--android}" = "$@" ]] && echo "ios" || echo "android")
|
||||
ROOT="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"/..
|
||||
TEMP=$ROOT/temp
|
||||
|
||||
rm -rf $TEMP/HttpDemo.app.zip
|
||||
pushd $TEMP/platforms/ios/build/emulator
|
||||
zip -r $TEMP/HttpDemo.app.zip ./HttpDemo.app
|
||||
popd
|
||||
if [ -z $SAUCE_USERNAME ] || [ -z $SAUCE_ACCESS_KEY ]; then
|
||||
echo "Skipping uploading artifact, because Saucelabs credentials are not set.";
|
||||
exit 0;
|
||||
fi
|
||||
|
||||
curl -u $SAUCE_USERNAME:$SAUCE_ACCESS_KEY \
|
||||
-X POST \
|
||||
-H "Content-Type: application/octet-stream" \
|
||||
https://saucelabs.com/rest/v1/storage/$SAUCE_USERNAME/HttpDemo.app.zip?overwrite=true \
|
||||
--data-binary @$TEMP/HttpDemo.app.zip
|
||||
if [ $PLATFORM = "android" ]; then
|
||||
curl -u $SAUCE_USERNAME:$SAUCE_ACCESS_KEY \
|
||||
-X POST \
|
||||
-H "Content-Type: application/octet-stream" \
|
||||
https://saucelabs.com/rest/v1/storage/$SAUCE_USERNAME/HttpDemo.apk?overwrite=true \
|
||||
--data-binary @$TEMP/platforms/android/build/outputs/apk/android-debug.apk
|
||||
else
|
||||
rm -rf $TEMP/HttpDemo.app.zip
|
||||
pushd $TEMP/platforms/ios/build/emulator
|
||||
zip -r $TEMP/HttpDemo.app.zip ./HttpDemo.app
|
||||
popd
|
||||
|
||||
curl -u $SAUCE_USERNAME:$SAUCE_ACCESS_KEY \
|
||||
-X POST \
|
||||
-H "Content-Type: application/octet-stream" \
|
||||
https://saucelabs.com/rest/v1/storage/$SAUCE_USERNAME/HttpDemo.app.zip?overwrite=true \
|
||||
--data-binary @$TEMP/HttpDemo.app.zip
|
||||
fi
|
||||
|
||||
@@ -92,6 +92,8 @@ import javax.net.ssl.TrustManager;
|
||||
import javax.net.ssl.TrustManagerFactory;
|
||||
import javax.net.ssl.X509TrustManager;
|
||||
|
||||
import android.text.TextUtils;
|
||||
|
||||
/**
|
||||
* A fluid interface for making HTTP requests using an underlying
|
||||
* {@link HttpURLConnection} (or sub-class).
|
||||
@@ -106,6 +108,11 @@ public class HttpRequest {
|
||||
*/
|
||||
public static final String CHARSET_UTF8 = "UTF-8";
|
||||
|
||||
/**
|
||||
* 'ISO-8859-1' charset name
|
||||
*/
|
||||
public static final String CHARSET_LATIN1 = "ISO-8859-1";
|
||||
|
||||
/**
|
||||
* 'application/x-www-form-urlencoded' content type header value
|
||||
*/
|
||||
@@ -256,6 +263,12 @@ public class HttpRequest {
|
||||
*/
|
||||
public static final String PARAM_CHARSET = "charset";
|
||||
|
||||
public static final String CERT_MODE_DEFAULT = "default";
|
||||
|
||||
public static final String CERT_MODE_PINNED = "pinned";
|
||||
|
||||
public static final String CERT_MODE_TRUSTALL = "trustall";
|
||||
|
||||
private static final String BOUNDARY = "00content0boundary00";
|
||||
|
||||
private static final String CONTENT_TYPE_MULTIPART = "multipart/form-data; boundary="
|
||||
@@ -265,13 +278,13 @@ public class HttpRequest {
|
||||
|
||||
private static final String[] EMPTY_STRINGS = new String[0];
|
||||
|
||||
private static SSLSocketFactory PINNED_FACTORY;
|
||||
private static SSLSocketFactory SOCKET_FACTORY;
|
||||
|
||||
private static SSLSocketFactory TRUSTED_FACTORY;
|
||||
private static String CURRENT_CERT_MODE = CERT_MODE_DEFAULT;
|
||||
|
||||
private static ArrayList<Certificate> PINNED_CERTS;
|
||||
|
||||
private static HostnameVerifier TRUSTED_VERIFIER;
|
||||
private static HostnameVerifier HOSTNAME_VERIFIER;
|
||||
|
||||
private static String getValidCharset(final String charset) {
|
||||
if (charset != null && charset.length() > 0)
|
||||
@@ -280,63 +293,97 @@ public class HttpRequest {
|
||||
return CHARSET_UTF8;
|
||||
}
|
||||
|
||||
private static SSLSocketFactory getPinnedFactory()
|
||||
throws HttpRequestException {
|
||||
if (PINNED_FACTORY != null) {
|
||||
return PINNED_FACTORY;
|
||||
} else {
|
||||
IOException e = new IOException("You must add at least 1 certificate in order to pin to certificates");
|
||||
throw new HttpRequestException(e);
|
||||
/**
|
||||
* Configure SSL cert handling for all future HTTPS connections
|
||||
*
|
||||
* @param mode
|
||||
*/
|
||||
public static void setSSLCertMode(String mode) {
|
||||
try {
|
||||
if (mode == CERT_MODE_TRUSTALL) {
|
||||
SOCKET_FACTORY = createSocketFactory(getNoopTrustManagers());
|
||||
HOSTNAME_VERIFIER = getTrustedVerifier();
|
||||
} else if (mode == CERT_MODE_PINNED) {
|
||||
SOCKET_FACTORY = createSocketFactory(getPinnedTrustManagers());
|
||||
HOSTNAME_VERIFIER = null;
|
||||
} else {
|
||||
SOCKET_FACTORY = null;
|
||||
HOSTNAME_VERIFIER = null;
|
||||
}
|
||||
|
||||
CURRENT_CERT_MODE = mode;
|
||||
} catch(IOException e) {
|
||||
throw new HttpRequestException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private static SSLSocketFactory getTrustedFactory()
|
||||
throws HttpRequestException {
|
||||
if (TRUSTED_FACTORY == null) {
|
||||
final TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() {
|
||||
|
||||
public X509Certificate[] getAcceptedIssuers() {
|
||||
return new X509Certificate[0];
|
||||
}
|
||||
|
||||
public void checkClientTrusted(X509Certificate[] chain, String authType) {
|
||||
// Intentionally left blank
|
||||
}
|
||||
|
||||
public void checkServerTrusted(X509Certificate[] chain, String authType) {
|
||||
// Intentionally left blank
|
||||
}
|
||||
} };
|
||||
try {
|
||||
SSLContext context = SSLContext.getInstance("TLS");
|
||||
context.init(null, trustAllCerts, new SecureRandom());
|
||||
|
||||
if (android.os.Build.VERSION.SDK_INT < 20) {
|
||||
TRUSTED_FACTORY = new TLSSocketFactory(context);
|
||||
} else {
|
||||
TRUSTED_FACTORY = context.getSocketFactory();
|
||||
}
|
||||
} catch (GeneralSecurityException e) {
|
||||
IOException ioException = new IOException(
|
||||
"Security exception configuring SSL context");
|
||||
ioException.initCause(e);
|
||||
throw new HttpRequestException(ioException);
|
||||
}
|
||||
private static TrustManager[] getPinnedTrustManagers() throws IOException {
|
||||
if (PINNED_CERTS == null) {
|
||||
throw new IOException("You must add at least 1 certificate in order to pin to certificates");
|
||||
}
|
||||
|
||||
return TRUSTED_FACTORY;
|
||||
try {
|
||||
String keyStoreType = KeyStore.getDefaultType();
|
||||
KeyStore keyStore = KeyStore.getInstance(keyStoreType);
|
||||
keyStore.load(null, null);
|
||||
|
||||
for (int i = 0; i < PINNED_CERTS.size(); i++) {
|
||||
keyStore.setCertificateEntry("CA" + i, PINNED_CERTS.get(i));
|
||||
}
|
||||
|
||||
// Create a TrustManager that trusts the CAs in our KeyStore
|
||||
String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
|
||||
TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
|
||||
tmf.init(keyStore);
|
||||
|
||||
return tmf.getTrustManagers();
|
||||
} catch (GeneralSecurityException e) {
|
||||
IOException ioException = new IOException("Security exception configuring SSL trust managers");
|
||||
ioException.initCause(e);
|
||||
throw new HttpRequestException(ioException);
|
||||
}
|
||||
}
|
||||
|
||||
private static TrustManager[] getNoopTrustManagers() {
|
||||
return new TrustManager[] { new X509TrustManager() {
|
||||
public X509Certificate[] getAcceptedIssuers() {
|
||||
return new X509Certificate[0];
|
||||
}
|
||||
|
||||
public void checkClientTrusted(X509Certificate[] chain, String authType) {
|
||||
// Intentionally left blank
|
||||
}
|
||||
|
||||
public void checkServerTrusted(X509Certificate[] chain, String authType) {
|
||||
// Intentionally left blank
|
||||
}
|
||||
}};
|
||||
}
|
||||
|
||||
private static SSLSocketFactory createSocketFactory(TrustManager[] trustManagers)
|
||||
throws HttpRequestException {
|
||||
try {
|
||||
SSLContext context = SSLContext.getInstance("TLS");
|
||||
context.init(null, trustManagers, new SecureRandom());
|
||||
|
||||
if (android.os.Build.VERSION.SDK_INT < 20) {
|
||||
return new TLSSocketFactory(context);
|
||||
} else {
|
||||
return context.getSocketFactory();
|
||||
}
|
||||
} catch (GeneralSecurityException e) {
|
||||
IOException ioException = new IOException("Security exception configuring SSL context");
|
||||
ioException.initCause(e);
|
||||
throw new HttpRequestException(ioException);
|
||||
}
|
||||
}
|
||||
|
||||
private static HostnameVerifier getTrustedVerifier() {
|
||||
if (TRUSTED_VERIFIER == null)
|
||||
TRUSTED_VERIFIER = new HostnameVerifier() {
|
||||
|
||||
public boolean verify(String hostname, SSLSession session) {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
return TRUSTED_VERIFIER;
|
||||
return new HostnameVerifier() {
|
||||
public boolean verify(String hostname, SSLSession session) {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static StringBuilder addPathSeparator(final String baseUrl,
|
||||
@@ -363,26 +410,35 @@ public class HttpRequest {
|
||||
}
|
||||
|
||||
private static StringBuilder addParam(final Object key, Object value,
|
||||
final StringBuilder result) {
|
||||
final StringBuilder result) throws HttpRequestException {
|
||||
return addParam(key, value, result, CHARSET_UTF8);
|
||||
}
|
||||
|
||||
private static StringBuilder addParam(final Object key, Object value,
|
||||
final StringBuilder result, String charset) throws HttpRequestException {
|
||||
if (value != null && value.getClass().isArray())
|
||||
value = arrayToList(value);
|
||||
|
||||
if (value instanceof Iterable<?>) {
|
||||
Iterator<?> iterator = ((Iterable<?>) value).iterator();
|
||||
while (iterator.hasNext()) {
|
||||
result.append(key);
|
||||
result.append("[]=");
|
||||
Object element = iterator.next();
|
||||
if (element != null)
|
||||
result.append(element);
|
||||
if (iterator.hasNext())
|
||||
result.append("&");
|
||||
try {
|
||||
if (value instanceof Iterable<?>) {
|
||||
Iterator<?> iterator = ((Iterable<?>) value).iterator();
|
||||
while (iterator.hasNext()) {
|
||||
result.append(URLEncoder.encode(key.toString(), charset));
|
||||
result.append("[]=");
|
||||
Object element = iterator.next();
|
||||
if (element != null)
|
||||
result.append(URLEncoder.encode(element.toString(), charset));
|
||||
if (iterator.hasNext())
|
||||
result.append("&");
|
||||
}
|
||||
} else {
|
||||
result.append(URLEncoder.encode(key.toString(), charset));
|
||||
result.append("=");
|
||||
if (value != null)
|
||||
result.append(URLEncoder.encode(value.toString(), charset));
|
||||
}
|
||||
} else {
|
||||
result.append(key);
|
||||
result.append("=");
|
||||
if (value != null)
|
||||
result.append(value);
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
throw new HttpRequestException(e);
|
||||
}
|
||||
|
||||
return result;
|
||||
@@ -412,15 +468,7 @@ public class HttpRequest {
|
||||
* A {@link ConnectionFactory} which uses the built-in
|
||||
* {@link URL#openConnection()}
|
||||
*/
|
||||
ConnectionFactory DEFAULT = new ConnectionFactory() {
|
||||
public HttpURLConnection create(URL url) throws IOException {
|
||||
return (HttpURLConnection) url.openConnection();
|
||||
}
|
||||
|
||||
public HttpURLConnection create(URL url, Proxy proxy) throws IOException {
|
||||
return (HttpURLConnection) url.openConnection(proxy);
|
||||
}
|
||||
};
|
||||
ConnectionFactory DEFAULT = new OkConnectionFactory();
|
||||
}
|
||||
|
||||
private static ConnectionFactory CONNECTION_FACTORY = ConnectionFactory.DEFAULT;
|
||||
@@ -445,32 +493,15 @@ public class HttpRequest {
|
||||
* @throws IOException
|
||||
*/
|
||||
public static void addCert(Certificate ca) throws GeneralSecurityException, IOException {
|
||||
if (PINNED_CERTS == null) {
|
||||
PINNED_CERTS = new ArrayList<Certificate>();
|
||||
}
|
||||
PINNED_CERTS.add(ca);
|
||||
String keyStoreType = KeyStore.getDefaultType();
|
||||
KeyStore keyStore = KeyStore.getInstance(keyStoreType);
|
||||
keyStore.load(null, null);
|
||||
if (PINNED_CERTS == null) {
|
||||
PINNED_CERTS = new ArrayList<Certificate>();
|
||||
}
|
||||
|
||||
for (int i = 0; i < PINNED_CERTS.size(); i++) {
|
||||
keyStore.setCertificateEntry("CA" + i, PINNED_CERTS.get(i));
|
||||
}
|
||||
PINNED_CERTS.add(ca);
|
||||
|
||||
// Create a TrustManager that trusts the CAs in our KeyStore
|
||||
String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
|
||||
TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
|
||||
tmf.init(keyStore);
|
||||
|
||||
// Create an SSLContext that uses our TrustManager
|
||||
SSLContext sslContext = SSLContext.getInstance("TLS");
|
||||
sslContext.init(null, tmf.getTrustManagers(), null);
|
||||
|
||||
if (android.os.Build.VERSION.SDK_INT < 20) {
|
||||
PINNED_FACTORY = new TLSSocketFactory(sslContext);
|
||||
} else {
|
||||
PINNED_FACTORY = sslContext.getSocketFactory();
|
||||
}
|
||||
if (CURRENT_CERT_MODE == CERT_MODE_PINNED) {
|
||||
SOCKET_FACTORY = createSocketFactory(getPinnedTrustManagers());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1624,6 +1655,7 @@ public class HttpRequest {
|
||||
throw new HttpRequestException(e);
|
||||
}
|
||||
this.requestMethod = method;
|
||||
this.setupSecurity();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1637,6 +1669,23 @@ public class HttpRequest {
|
||||
throws HttpRequestException {
|
||||
this.url = url;
|
||||
this.requestMethod = method;
|
||||
this.setupSecurity();
|
||||
}
|
||||
|
||||
private void setupSecurity() {
|
||||
final HttpURLConnection connection = getConnection();
|
||||
|
||||
if (!(connection instanceof HttpsURLConnection)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (SOCKET_FACTORY != null) {
|
||||
((HttpsURLConnection) connection).setSSLSocketFactory(SOCKET_FACTORY);
|
||||
}
|
||||
|
||||
if (HOSTNAME_VERIFIER != null) {
|
||||
((HttpsURLConnection) connection).setHostnameVerifier(HOSTNAME_VERIFIER);
|
||||
}
|
||||
}
|
||||
|
||||
private Proxy createProxy() {
|
||||
@@ -1929,16 +1978,24 @@ public class HttpRequest {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the response body as a {@link String} and set it as the value of the
|
||||
* Get the response body as ByteBuffer and set it as the value of the
|
||||
* given reference.
|
||||
*
|
||||
* @param output
|
||||
* @return this request
|
||||
* @throws HttpRequestException
|
||||
*/
|
||||
public HttpRequest body(final AtomicReference<String> output) throws HttpRequestException {
|
||||
output.set(body());
|
||||
return this;
|
||||
public HttpRequest body(final AtomicReference<ByteBuffer> output) throws HttpRequestException {
|
||||
final ByteArrayOutputStream outputStream = byteStream();
|
||||
|
||||
try {
|
||||
copy(buffer(), outputStream);
|
||||
output.set(ByteBuffer.wrap(outputStream.toByteArray()));
|
||||
|
||||
return this;
|
||||
} catch (IOException e) {
|
||||
throw new HttpRequestException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1955,7 +2012,6 @@ public class HttpRequest {
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Is the response body empty?
|
||||
*
|
||||
@@ -2529,6 +2585,16 @@ public class HttpRequest {
|
||||
return header(HEADER_ACCEPT_CHARSET, acceptCharset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the 'Accept-Charset' header to given values
|
||||
*
|
||||
* @param acceptCharsets
|
||||
* @return this request
|
||||
*/
|
||||
public HttpRequest acceptCharset(final String[] acceptCharsets) {
|
||||
return header(HEADER_ACCEPT_CHARSET, TextUtils.join(", ", acceptCharsets));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the 'Content-Encoding' header from the response
|
||||
*
|
||||
@@ -3326,58 +3392,6 @@ public class HttpRequest {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure HTTPS connection to trust only certain certificates
|
||||
* <p>
|
||||
* This method throws an exception if the current request is not a HTTPS request
|
||||
*
|
||||
* @return this request
|
||||
* @throws HttpRequestException
|
||||
*/
|
||||
public HttpRequest pinToCerts() throws HttpRequestException {
|
||||
final HttpURLConnection connection = getConnection();
|
||||
if (connection instanceof HttpsURLConnection) {
|
||||
((HttpsURLConnection) connection).setSSLSocketFactory(getPinnedFactory());
|
||||
} else {
|
||||
IOException e = new IOException("You must use a https url to use ssl pinning");
|
||||
throw new HttpRequestException(e);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure HTTPS connection to trust all certificates
|
||||
* <p>
|
||||
* This method does nothing if the current request is not a HTTPS request
|
||||
*
|
||||
* @return this request
|
||||
* @throws HttpRequestException
|
||||
*/
|
||||
public HttpRequest trustAllCerts() throws HttpRequestException {
|
||||
final HttpURLConnection connection = getConnection();
|
||||
if (connection instanceof HttpsURLConnection)
|
||||
((HttpsURLConnection) connection)
|
||||
.setSSLSocketFactory(getTrustedFactory());
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure HTTPS connection to trust all hosts using a custom
|
||||
* {@link HostnameVerifier} that always returns <code>true</code> for each
|
||||
* host verified
|
||||
* <p>
|
||||
* This method does nothing if the current request is not a HTTPS request
|
||||
*
|
||||
* @return this request
|
||||
*/
|
||||
public HttpRequest trustAllHosts() {
|
||||
final HttpURLConnection connection = getConnection();
|
||||
if (connection instanceof HttpsURLConnection)
|
||||
((HttpsURLConnection) connection)
|
||||
.setHostnameVerifier(getTrustedVerifier());
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the {@link URL} of this request's connection
|
||||
*
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
package com.github.kevinsawicki.http;
|
||||
|
||||
import okhttp3.OkUrlFactory;
|
||||
import okhttp3.OkHttpClient;
|
||||
|
||||
import java.net.URL;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URLStreamHandler;
|
||||
import java.net.Proxy;
|
||||
|
||||
|
||||
public class OkConnectionFactory implements HttpRequest.ConnectionFactory {
|
||||
|
||||
protected OkHttpClient okHttpClient = new OkHttpClient();
|
||||
|
||||
public HttpURLConnection create(URL url) {
|
||||
OkUrlFactory okUrlFactory = new OkUrlFactory(okHttpClient);
|
||||
return (HttpURLConnection) okUrlFactory.open(url);
|
||||
}
|
||||
|
||||
public HttpURLConnection create(URL url, Proxy proxy) {
|
||||
OkHttpClient okHttpClientWithProxy = okHttpClient.newBuilder().proxy(proxy).build();
|
||||
OkUrlFactory okUrlFactory = new OkUrlFactory(okHttpClientWithProxy);
|
||||
return (HttpURLConnection) okUrlFactory.open(url);
|
||||
}
|
||||
}
|
||||
@@ -11,45 +11,45 @@ import javax.net.ssl.SSLSocketFactory;
|
||||
|
||||
public class TLSSocketFactory extends SSLSocketFactory {
|
||||
|
||||
private SSLSocketFactory internalSSLSocketFactory;
|
||||
private SSLSocketFactory delegate;
|
||||
|
||||
public TLSSocketFactory(SSLContext context) {
|
||||
internalSSLSocketFactory = context.getSocketFactory();
|
||||
delegate = context.getSocketFactory();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getDefaultCipherSuites() {
|
||||
return internalSSLSocketFactory.getDefaultCipherSuites();
|
||||
return delegate.getDefaultCipherSuites();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getSupportedCipherSuites() {
|
||||
return internalSSLSocketFactory.getSupportedCipherSuites();
|
||||
return delegate.getSupportedCipherSuites();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Socket createSocket(Socket s, String host, int port, boolean autoClose) throws IOException {
|
||||
return enableTLSOnSocket(internalSSLSocketFactory.createSocket(s, host, port, autoClose));
|
||||
return enableTLSOnSocket(delegate.createSocket(s, host, port, autoClose));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Socket createSocket(String host, int port) throws IOException, UnknownHostException {
|
||||
return enableTLSOnSocket(internalSSLSocketFactory.createSocket(host, port));
|
||||
return enableTLSOnSocket(delegate.createSocket(host, port));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException, UnknownHostException {
|
||||
return enableTLSOnSocket(internalSSLSocketFactory.createSocket(host, port, localHost, localPort));
|
||||
return enableTLSOnSocket(delegate.createSocket(host, port, localHost, localPort));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Socket createSocket(InetAddress host, int port) throws IOException {
|
||||
return enableTLSOnSocket(internalSSLSocketFactory.createSocket(host, port));
|
||||
return enableTLSOnSocket(delegate.createSocket(host, port));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException {
|
||||
return enableTLSOnSocket(internalSSLSocketFactory.createSocket(address, port, localAddress, localPort));
|
||||
return enableTLSOnSocket(delegate.createSocket(address, port, localAddress, localPort));
|
||||
}
|
||||
|
||||
private Socket enableTLSOnSocket(Socket socket) {
|
||||
|
||||
@@ -6,25 +6,38 @@ package com.synconset.cordovahttp;
|
||||
import org.apache.cordova.CallbackContext;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.net.SocketTimeoutException;
|
||||
import java.net.UnknownHostException;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import java.nio.charset.CharacterCodingException;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.CharsetDecoder;
|
||||
import java.nio.charset.CodingErrorAction;
|
||||
import java.nio.charset.MalformedInputException;
|
||||
|
||||
import javax.net.ssl.SSLHandshakeException;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.Iterator;
|
||||
|
||||
import android.text.TextUtils;
|
||||
|
||||
import com.github.kevinsawicki.http.HttpRequest;
|
||||
import com.github.kevinsawicki.http.HttpRequest.HttpRequestException;
|
||||
|
||||
abstract class CordovaHttp {
|
||||
protected static final String TAG = "CordovaHTTP";
|
||||
protected static final String CHARSET = "UTF-8";
|
||||
|
||||
private static AtomicBoolean sslPinning = new AtomicBoolean(false);
|
||||
private static AtomicBoolean acceptAllCerts = new AtomicBoolean(false);
|
||||
private static AtomicBoolean validateDomainName = new AtomicBoolean(true);
|
||||
protected static final String[] ACCEPTED_CHARSETS = new String[] { HttpRequest.CHARSET_UTF8, HttpRequest.CHARSET_LATIN1 };
|
||||
private static AtomicBoolean disableRedirect = new AtomicBoolean(false);
|
||||
|
||||
private String urlString;
|
||||
@@ -35,12 +48,7 @@ abstract class CordovaHttp {
|
||||
private CallbackContext callbackContext;
|
||||
|
||||
public CordovaHttp(String urlString, Object params, JSONObject headers, int timeout, CallbackContext callbackContext) {
|
||||
this.urlString = urlString;
|
||||
this.params = params;
|
||||
this.serializerName = "default";
|
||||
this.headers = headers;
|
||||
this.timeoutInMilliseconds = timeout;
|
||||
this.callbackContext = callbackContext;
|
||||
this(urlString, params, "default", headers, timeout, callbackContext);
|
||||
}
|
||||
|
||||
public CordovaHttp(String urlString, Object params, String serializerName, JSONObject headers, int timeout, CallbackContext callbackContext) {
|
||||
@@ -52,24 +60,6 @@ abstract class CordovaHttp {
|
||||
this.callbackContext = callbackContext;
|
||||
}
|
||||
|
||||
public static void enableSSLPinning(boolean enable) {
|
||||
sslPinning.set(enable);
|
||||
if (enable) {
|
||||
acceptAllCerts.set(false);
|
||||
}
|
||||
}
|
||||
|
||||
public static void acceptAllCerts(boolean accept) {
|
||||
acceptAllCerts.set(accept);
|
||||
if (accept) {
|
||||
sslPinning.set(false);
|
||||
}
|
||||
}
|
||||
|
||||
public static void validateDomainName(boolean accept) {
|
||||
validateDomainName.set(accept);
|
||||
}
|
||||
|
||||
public static void disableRedirect(boolean disable) {
|
||||
disableRedirect.set(disable);
|
||||
}
|
||||
@@ -110,26 +100,22 @@ abstract class CordovaHttp {
|
||||
return this.callbackContext;
|
||||
}
|
||||
|
||||
protected HttpRequest setupSecurity(HttpRequest request) {
|
||||
if (acceptAllCerts.get()) {
|
||||
request.trustAllCerts();
|
||||
}
|
||||
if (!validateDomainName.get()) {
|
||||
request.trustAllHosts();
|
||||
}
|
||||
if (sslPinning.get()) {
|
||||
request.pinToCerts();
|
||||
}
|
||||
return request;
|
||||
}
|
||||
|
||||
protected HttpRequest setupRedirect(HttpRequest request) {
|
||||
if (disableRedirect.get()) {
|
||||
request.followRedirects(false);
|
||||
}
|
||||
|
||||
return request;
|
||||
}
|
||||
|
||||
protected void setupDataSerializer(HttpRequest request) throws JSONException, Exception {
|
||||
if ("json".equals(this.getSerializerName())) {
|
||||
request.contentType(request.CONTENT_TYPE_JSON, request.CHARSET_UTF8);
|
||||
} else if ("utf8".equals(this.getSerializerName())) {
|
||||
request.contentType("text/plain", request.CHARSET_UTF8);
|
||||
}
|
||||
}
|
||||
|
||||
protected void respondWithError(int status, String msg) {
|
||||
try {
|
||||
JSONObject response = new JSONObject();
|
||||
@@ -142,7 +128,7 @@ abstract class CordovaHttp {
|
||||
}
|
||||
|
||||
protected void respondWithError(String msg) {
|
||||
this.respondWithError(500, msg);
|
||||
this.respondWithError(-1, msg);
|
||||
}
|
||||
|
||||
protected void addResponseHeaders(HttpRequest request, JSONObject response) throws JSONException {
|
||||
@@ -172,14 +158,125 @@ abstract class CordovaHttp {
|
||||
return map;
|
||||
}
|
||||
|
||||
protected ArrayList<Object> getListFromJSONArray(JSONArray array) throws JSONException {
|
||||
ArrayList<Object> list = new ArrayList<Object>();
|
||||
|
||||
for (int i = 0; i < array.length(); i++) {
|
||||
list.add(array.get(i));
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
protected HashMap<String, Object> getMapFromJSONObject(JSONObject object) throws JSONException {
|
||||
HashMap<String, Object> map = new HashMap<String, Object>();
|
||||
Iterator<?> i = object.keys();
|
||||
|
||||
while(i.hasNext()) {
|
||||
String key = (String)i.next();
|
||||
map.put(key, object.get(key));
|
||||
Object value = object.get(key);
|
||||
|
||||
if (value instanceof JSONArray) {
|
||||
map.put(key, getListFromJSONArray((JSONArray)value));
|
||||
} else {
|
||||
map.put(key, object.get(key));
|
||||
}
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
protected void prepareRequest(HttpRequest request) throws HttpRequestException, JSONException {
|
||||
this.setupRedirect(request);
|
||||
|
||||
request.readTimeout(this.getRequestTimeout());
|
||||
request.acceptCharset(ACCEPTED_CHARSETS);
|
||||
request.headers(this.getHeadersMap());
|
||||
request.uncompress(true);
|
||||
}
|
||||
|
||||
protected void prepareRequestBody(HttpRequest request) throws JSONException, Exception {
|
||||
if ("json".equals(this.getSerializerName())) {
|
||||
request.send(this.getParamsObject().toString());
|
||||
} else if ("utf8".equals(this.getSerializerName())) {
|
||||
request.send(this.getParamsMap().get("text").toString());
|
||||
} else {
|
||||
request.form(this.getParamsMap());
|
||||
}
|
||||
}
|
||||
|
||||
private CharsetDecoder createCharsetDecoder(final String charsetName) {
|
||||
return Charset.forName(charsetName).newDecoder()
|
||||
.onMalformedInput(CodingErrorAction.REPORT)
|
||||
.onUnmappableCharacter(CodingErrorAction.REPORT);
|
||||
}
|
||||
|
||||
private String decodeBody(AtomicReference<ByteBuffer> rawOutput, String charsetName)
|
||||
throws CharacterCodingException, MalformedInputException {
|
||||
|
||||
if (charsetName == null) {
|
||||
return tryDecodeByteBuffer(rawOutput);
|
||||
}
|
||||
|
||||
return decodeByteBuffer(rawOutput, charsetName);
|
||||
}
|
||||
|
||||
private String tryDecodeByteBuffer(AtomicReference<ByteBuffer> rawOutput)
|
||||
throws CharacterCodingException, MalformedInputException {
|
||||
|
||||
for (int i = 0; i < ACCEPTED_CHARSETS.length - 1; i++) {
|
||||
try {
|
||||
return decodeByteBuffer(rawOutput, ACCEPTED_CHARSETS[i]);
|
||||
} catch (MalformedInputException e) {
|
||||
continue;
|
||||
} catch (CharacterCodingException e) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
return decodeBody(rawOutput, ACCEPTED_CHARSETS[ACCEPTED_CHARSETS.length - 1]);
|
||||
}
|
||||
|
||||
private String decodeByteBuffer(AtomicReference<ByteBuffer> rawOutput, String charsetName)
|
||||
throws CharacterCodingException, MalformedInputException {
|
||||
|
||||
return createCharsetDecoder(charsetName).decode(rawOutput.get()).toString();
|
||||
}
|
||||
|
||||
protected void returnResponseObject(HttpRequest request) throws HttpRequestException {
|
||||
try {
|
||||
JSONObject response = new JSONObject();
|
||||
int code = request.code();
|
||||
AtomicReference<ByteBuffer> rawOutputReference = new AtomicReference<ByteBuffer>();
|
||||
|
||||
request.body(rawOutputReference);
|
||||
response.put("status", code);
|
||||
response.put("url", request.url().toString());
|
||||
this.addResponseHeaders(request, response);
|
||||
|
||||
if (code >= 200 && code < 300) {
|
||||
response.put("data", decodeBody(rawOutputReference, request.charset()));
|
||||
this.getCallbackContext().success(response);
|
||||
} else {
|
||||
response.put("error", decodeBody(rawOutputReference, request.charset()));
|
||||
this.getCallbackContext().error(response);
|
||||
}
|
||||
} catch(JSONException e) {
|
||||
this.respondWithError("There was an error generating the response");
|
||||
} catch(MalformedInputException e) {
|
||||
this.respondWithError("Could not decode response data due to malformed data");
|
||||
} catch(CharacterCodingException e) {
|
||||
this.respondWithError("Could not decode response data due to invalid or unknown charset encoding");
|
||||
}
|
||||
}
|
||||
|
||||
protected void handleHttpRequestException(HttpRequestException e) {
|
||||
if (e.getCause() instanceof UnknownHostException) {
|
||||
this.respondWithError(0, "The host could not be resolved");
|
||||
} else if (e.getCause() instanceof SocketTimeoutException) {
|
||||
this.respondWithError(1, "The request timed out");
|
||||
} else if (e.getCause() instanceof SSLHandshakeException) {
|
||||
this.respondWithError("SSL handshake failed");
|
||||
} else {
|
||||
this.respondWithError("There was an error with the request: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,41 +26,12 @@ class CordovaHttpDelete extends CordovaHttp implements Runnable {
|
||||
try {
|
||||
HttpRequest request = HttpRequest.delete(this.getUrlString(), this.getParamsMap(), false);
|
||||
|
||||
request.readTimeout(this.getRequestTimeout());
|
||||
this.setupRedirect(request);
|
||||
this.setupSecurity(request);
|
||||
request.acceptCharset(CHARSET);
|
||||
request.headers(this.getHeadersMap());
|
||||
request.uncompress(true);
|
||||
|
||||
int code = request.code();
|
||||
String body = request.body(CHARSET);
|
||||
JSONObject response = new JSONObject();
|
||||
|
||||
this.addResponseHeaders(request, response);
|
||||
response.put("status", code);
|
||||
|
||||
if (code >= 200 && code < 300) {
|
||||
response.put("data", body);
|
||||
this.getCallbackContext().success(response);
|
||||
} else {
|
||||
response.put("error", body);
|
||||
this.getCallbackContext().error(response);
|
||||
}
|
||||
} catch (JSONException e) {
|
||||
this.respondWithError("There was an error generating the response");
|
||||
this.prepareRequest(request);
|
||||
this.returnResponseObject(request);
|
||||
} catch (HttpRequestException e) {
|
||||
if (e.getCause() instanceof UnknownHostException) {
|
||||
this.respondWithError(0, "The host could not be resolved");
|
||||
} else if (e.getCause() instanceof SocketTimeoutException) {
|
||||
this.respondWithError(1, "The request timed out");
|
||||
} else if (e.getCause() instanceof SSLHandshakeException) {
|
||||
this.respondWithError("SSL handshake failed");
|
||||
} else {
|
||||
this.respondWithError("There was an error with the request");
|
||||
}
|
||||
this.handleHttpRequestException(e);
|
||||
} catch (Exception e) {
|
||||
this.respondWithError(-1, e.getMessage());
|
||||
this.respondWithError(e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,17 +33,15 @@ class CordovaHttpDownload extends CordovaHttp implements Runnable {
|
||||
try {
|
||||
HttpRequest request = HttpRequest.get(this.getUrlString(), this.getParamsMap(), true);
|
||||
|
||||
request.readTimeout(this.getRequestTimeout());
|
||||
this.setupRedirect(request);
|
||||
this.setupSecurity(request);
|
||||
request.acceptCharset(CHARSET);
|
||||
request.headers(this.getHeadersMap());
|
||||
request.uncompress(true);
|
||||
int code = request.code();
|
||||
this.prepareRequest(request);
|
||||
|
||||
JSONObject response = new JSONObject();
|
||||
this.addResponseHeaders(request, response);
|
||||
int code = request.code();
|
||||
|
||||
response.put("status", code);
|
||||
response.put("url", request.url().toString());
|
||||
this.addResponseHeaders(request, response);
|
||||
|
||||
if (code >= 200 && code < 300) {
|
||||
URI uri = new URI(filePath);
|
||||
File file = new File(uri);
|
||||
@@ -60,17 +58,9 @@ class CordovaHttpDownload extends CordovaHttp implements Runnable {
|
||||
} catch (JSONException e) {
|
||||
this.respondWithError("There was an error generating the response");
|
||||
} catch (HttpRequestException e) {
|
||||
if (e.getCause() instanceof UnknownHostException) {
|
||||
this.respondWithError(0, "The host could not be resolved");
|
||||
} else if (e.getCause() instanceof SocketTimeoutException) {
|
||||
this.respondWithError(1, "The request timed out");
|
||||
} else if (e.getCause() instanceof SSLHandshakeException) {
|
||||
this.respondWithError("SSL handshake failed");
|
||||
} else {
|
||||
this.respondWithError("There was an error with the request");
|
||||
}
|
||||
this.handleHttpRequestException(e);
|
||||
} catch (Exception e) {
|
||||
this.respondWithError(-1, e.getMessage());
|
||||
this.respondWithError(e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,41 +26,12 @@ class CordovaHttpGet extends CordovaHttp implements Runnable {
|
||||
try {
|
||||
HttpRequest request = HttpRequest.get(this.getUrlString(), this.getParamsMap(), false);
|
||||
|
||||
request.readTimeout(this.getRequestTimeout());
|
||||
this.setupRedirect(request);
|
||||
this.setupSecurity(request);
|
||||
request.acceptCharset(CHARSET);
|
||||
request.headers(this.getHeadersMap());
|
||||
request.uncompress(true);
|
||||
|
||||
int code = request.code();
|
||||
String body = request.body(CHARSET);
|
||||
JSONObject response = new JSONObject();
|
||||
|
||||
this.addResponseHeaders(request, response);
|
||||
response.put("status", code);
|
||||
|
||||
if (code >= 200 && code < 300) {
|
||||
response.put("data", body);
|
||||
this.getCallbackContext().success(response);
|
||||
} else {
|
||||
response.put("error", body);
|
||||
this.getCallbackContext().error(response);
|
||||
}
|
||||
} catch (JSONException e) {
|
||||
this.respondWithError("There was an error generating the response");
|
||||
this.prepareRequest(request);
|
||||
this.returnResponseObject(request);
|
||||
} catch (HttpRequestException e) {
|
||||
if (e.getCause() instanceof UnknownHostException) {
|
||||
this.respondWithError(0, "The host could not be resolved");
|
||||
} else if (e.getCause() instanceof SocketTimeoutException) {
|
||||
this.respondWithError(1, "The request timed out");
|
||||
} else if (e.getCause() instanceof SSLHandshakeException) {
|
||||
this.respondWithError("SSL handshake failed");
|
||||
} else {
|
||||
this.respondWithError("There was an error with the request");
|
||||
}
|
||||
this.handleHttpRequestException(e);
|
||||
} catch (Exception e) {
|
||||
this.respondWithError(-1, e.getMessage());
|
||||
this.respondWithError(e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,41 +25,12 @@ class CordovaHttpHead extends CordovaHttp implements Runnable {
|
||||
try {
|
||||
HttpRequest request = HttpRequest.head(this.getUrlString(), this.getParamsMap(), true);
|
||||
|
||||
request.readTimeout(this.getRequestTimeout());
|
||||
this.setupRedirect(request);
|
||||
this.setupSecurity(request);
|
||||
request.acceptCharset(CHARSET);
|
||||
request.headers(this.getHeadersMap());
|
||||
request.uncompress(true);
|
||||
|
||||
int code = request.code();
|
||||
JSONObject response = new JSONObject();
|
||||
|
||||
this.addResponseHeaders(request, response);
|
||||
response.put("status", code);
|
||||
|
||||
if (code >= 200 && code < 300) {
|
||||
// no 'body' to return for HEAD request
|
||||
this.getCallbackContext().success(response);
|
||||
} else {
|
||||
String body = request.body(CHARSET);
|
||||
response.put("error", body);
|
||||
this.getCallbackContext().error(response);
|
||||
}
|
||||
} catch (JSONException e) {
|
||||
this.respondWithError("There was an error generating the response");
|
||||
this.prepareRequest(request);
|
||||
this.returnResponseObject(request);
|
||||
} catch (HttpRequestException e) {
|
||||
if (e.getCause() instanceof UnknownHostException) {
|
||||
this.respondWithError(0, "The host could not be resolved");
|
||||
} else if (e.getCause() instanceof SocketTimeoutException) {
|
||||
this.respondWithError(1, "The request timed out");
|
||||
} else if (e.getCause() instanceof SSLHandshakeException) {
|
||||
this.respondWithError("SSL handshake failed");
|
||||
} else {
|
||||
this.respondWithError("There was an error with the request");
|
||||
}
|
||||
this.handleHttpRequestException(e);
|
||||
} catch (Exception e) {
|
||||
this.respondWithError(-1, e.getMessage());
|
||||
this.respondWithError(e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,48 +25,14 @@ class CordovaHttpPatch extends CordovaHttp implements Runnable {
|
||||
try {
|
||||
HttpRequest request = HttpRequest.patch(this.getUrlString());
|
||||
|
||||
request.readTimeout(this.getRequestTimeout());
|
||||
this.setupRedirect(request);
|
||||
this.setupSecurity(request);
|
||||
request.acceptCharset(CHARSET);
|
||||
request.headers(this.getHeadersMap());
|
||||
request.uncompress(true);
|
||||
|
||||
if (new String("json").equals(this.getSerializerName())) {
|
||||
request.contentType(request.CONTENT_TYPE_JSON, request.CHARSET_UTF8);
|
||||
request.send(this.getParamsObject().toString());
|
||||
} else {
|
||||
request.form(this.getParamsMap());
|
||||
}
|
||||
|
||||
int code = request.code();
|
||||
String body = request.body(CHARSET);
|
||||
JSONObject response = new JSONObject();
|
||||
|
||||
this.addResponseHeaders(request, response);
|
||||
response.put("status", code);
|
||||
|
||||
if (code >= 200 && code < 300) {
|
||||
response.put("data", body);
|
||||
this.getCallbackContext().success(response);
|
||||
} else {
|
||||
response.put("error", body);
|
||||
this.getCallbackContext().error(response);
|
||||
}
|
||||
} catch (JSONException e) {
|
||||
this.respondWithError("There was an error generating the response");
|
||||
this.setupDataSerializer(request);
|
||||
this.prepareRequest(request);
|
||||
this.prepareRequestBody(request);
|
||||
this.returnResponseObject(request);
|
||||
} catch (HttpRequestException e) {
|
||||
if (e.getCause() instanceof UnknownHostException) {
|
||||
this.respondWithError(0, "The host could not be resolved");
|
||||
} else if (e.getCause() instanceof SocketTimeoutException) {
|
||||
this.respondWithError(1, "The request timed out");
|
||||
} else if (e.getCause() instanceof SSLHandshakeException) {
|
||||
this.respondWithError("SSL handshake failed");
|
||||
} else {
|
||||
this.respondWithError("There was an error with the request");
|
||||
}
|
||||
this.handleHttpRequestException(e);
|
||||
} catch (Exception e) {
|
||||
this.respondWithError(-1, e.getMessage());
|
||||
this.respondWithError(e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,21 +86,25 @@ public class CordovaHttpPlugin extends CordovaPlugin {
|
||||
CordovaHttpHead head = new CordovaHttpHead(urlString, params, headers, timeoutInMilliseconds, callbackContext);
|
||||
|
||||
cordova.getThreadPool().execute(head);
|
||||
} else if (action.equals("enableSSLPinning")) {
|
||||
try {
|
||||
boolean enable = args.getBoolean(0);
|
||||
this.enableSSLPinning(enable);
|
||||
callbackContext.success();
|
||||
} catch(Exception e) {
|
||||
e.printStackTrace();
|
||||
callbackContext.error("There was an error setting up ssl pinning");
|
||||
}
|
||||
} else if (action.equals("acceptAllCerts")) {
|
||||
boolean accept = args.getBoolean(0);
|
||||
} else if (action.equals("setSSLCertMode")) {
|
||||
String mode = args.getString(0);
|
||||
|
||||
CordovaHttp.acceptAllCerts(accept);
|
||||
CordovaHttp.validateDomainName(!accept);
|
||||
callbackContext.success();
|
||||
if (mode.equals("default")) {
|
||||
HttpRequest.setSSLCertMode(HttpRequest.CERT_MODE_DEFAULT);
|
||||
callbackContext.success();
|
||||
} else if (mode.equals("nocheck")) {
|
||||
HttpRequest.setSSLCertMode(HttpRequest.CERT_MODE_TRUSTALL);
|
||||
callbackContext.success();
|
||||
} else if (mode.equals("pinned")) {
|
||||
try {
|
||||
this.loadSSLCerts();
|
||||
HttpRequest.setSSLCertMode(HttpRequest.CERT_MODE_PINNED);
|
||||
callbackContext.success();
|
||||
} catch(Exception e) {
|
||||
e.printStackTrace();
|
||||
callbackContext.error("There was an error setting up ssl pinning");
|
||||
}
|
||||
}
|
||||
} else if (action.equals("uploadFile")) {
|
||||
String urlString = args.getString(0);
|
||||
Object params = args.get(1);
|
||||
@@ -121,49 +125,33 @@ public class CordovaHttpPlugin extends CordovaPlugin {
|
||||
|
||||
cordova.getThreadPool().execute(download);
|
||||
} else if (action.equals("disableRedirect")) {
|
||||
boolean disable = args.getBoolean(0);
|
||||
CordovaHttp.disableRedirect(disable);
|
||||
callbackContext.success();
|
||||
boolean disable = args.getBoolean(0);
|
||||
CordovaHttp.disableRedirect(disable);
|
||||
callbackContext.success();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private void enableSSLPinning(boolean enable) throws GeneralSecurityException, IOException {
|
||||
if (enable) {
|
||||
AssetManager assetManager = cordova.getActivity().getAssets();
|
||||
String[] files = assetManager.list("");
|
||||
int index;
|
||||
ArrayList<String> cerFiles = new ArrayList<String>();
|
||||
for (int i = 0; i < files.length; i++) {
|
||||
index = files[i].lastIndexOf('.');
|
||||
if (index != -1) {
|
||||
if (files[i].substring(index).equals(".cer")) {
|
||||
cerFiles.add(files[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
private void loadSSLCerts() throws GeneralSecurityException, IOException {
|
||||
AssetManager assetManager = cordova.getActivity().getAssets();
|
||||
String[] files = assetManager.list("www/certificates");
|
||||
ArrayList<String> cerFiles = new ArrayList<String>();
|
||||
|
||||
// scan the www/certificates folder for .cer files as well
|
||||
files = assetManager.list("www/certificates");
|
||||
for (int i = 0; i < files.length; i++) {
|
||||
index = files[i].lastIndexOf('.');
|
||||
if (index != -1) {
|
||||
if (files[i].substring(index).equals(".cer")) {
|
||||
cerFiles.add("www/certificates/" + files[i]);
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < files.length; i++) {
|
||||
int index = files[i].lastIndexOf('.');
|
||||
if (index != -1) {
|
||||
if (files[i].substring(index).equals(".cer")) {
|
||||
cerFiles.add("www/certificates/" + files[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < cerFiles.size(); i++) {
|
||||
InputStream in = cordova.getActivity().getAssets().open(cerFiles.get(i));
|
||||
InputStream caInput = new BufferedInputStream(in);
|
||||
HttpRequest.addCert(caInput);
|
||||
}
|
||||
CordovaHttp.enableSSLPinning(true);
|
||||
} else {
|
||||
CordovaHttp.enableSSLPinning(false);
|
||||
for (int i = 0; i < cerFiles.size(); i++) {
|
||||
InputStream in = cordova.getActivity().getAssets().open(cerFiles.get(i));
|
||||
InputStream caInput = new BufferedInputStream(in);
|
||||
HttpRequest.addCert(caInput);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,48 +25,14 @@ class CordovaHttpPost extends CordovaHttp implements Runnable {
|
||||
try {
|
||||
HttpRequest request = HttpRequest.post(this.getUrlString());
|
||||
|
||||
request.readTimeout(this.getRequestTimeout());
|
||||
this.setupRedirect(request);
|
||||
this.setupSecurity(request);
|
||||
request.acceptCharset(CHARSET);
|
||||
request.headers(this.getHeadersMap());
|
||||
request.uncompress(true);
|
||||
|
||||
if (new String("json").equals(this.getSerializerName())) {
|
||||
request.contentType(request.CONTENT_TYPE_JSON, request.CHARSET_UTF8);
|
||||
request.send(this.getParamsObject().toString());
|
||||
} else {
|
||||
request.form(this.getParamsMap());
|
||||
}
|
||||
|
||||
int code = request.code();
|
||||
String body = request.body(CHARSET);
|
||||
JSONObject response = new JSONObject();
|
||||
|
||||
this.addResponseHeaders(request, response);
|
||||
response.put("status", code);
|
||||
|
||||
if (code >= 200 && code < 300) {
|
||||
response.put("data", body);
|
||||
this.getCallbackContext().success(response);
|
||||
} else {
|
||||
response.put("error", body);
|
||||
this.getCallbackContext().error(response);
|
||||
}
|
||||
} catch (JSONException e) {
|
||||
this.respondWithError("There was an error generating the response");
|
||||
this.setupDataSerializer(request);
|
||||
this.prepareRequest(request);
|
||||
this.prepareRequestBody(request);
|
||||
this.returnResponseObject(request);
|
||||
} catch (HttpRequestException e) {
|
||||
if (e.getCause() instanceof UnknownHostException) {
|
||||
this.respondWithError(0, "The host could not be resolved");
|
||||
} else if (e.getCause() instanceof SocketTimeoutException) {
|
||||
this.respondWithError(1, "The request timed out");
|
||||
} else if (e.getCause() instanceof SSLHandshakeException) {
|
||||
this.respondWithError("SSL handshake failed");
|
||||
} else {
|
||||
this.respondWithError("There was an error with the request");
|
||||
}
|
||||
this.handleHttpRequestException(e);
|
||||
} catch (Exception e) {
|
||||
this.respondWithError(-1, e.getMessage());
|
||||
this.respondWithError(e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,48 +25,14 @@ class CordovaHttpPut extends CordovaHttp implements Runnable {
|
||||
try {
|
||||
HttpRequest request = HttpRequest.put(this.getUrlString());
|
||||
|
||||
request.readTimeout(this.getRequestTimeout());
|
||||
this.setupRedirect(request);
|
||||
this.setupSecurity(request);
|
||||
request.acceptCharset(CHARSET);
|
||||
request.headers(this.getHeadersMap());
|
||||
request.uncompress(true);
|
||||
|
||||
if (new String("json").equals(this.getSerializerName())) {
|
||||
request.contentType(request.CONTENT_TYPE_JSON, request.CHARSET_UTF8);
|
||||
request.send(this.getParamsObject().toString());
|
||||
} else {
|
||||
request.form(this.getParamsMap());
|
||||
}
|
||||
|
||||
int code = request.code();
|
||||
String body = request.body(CHARSET);
|
||||
JSONObject response = new JSONObject();
|
||||
|
||||
this.addResponseHeaders(request, response);
|
||||
response.put("status", code);
|
||||
|
||||
if (code >= 200 && code < 300) {
|
||||
response.put("data", body);
|
||||
this.getCallbackContext().success(response);
|
||||
} else {
|
||||
response.put("error", body);
|
||||
this.getCallbackContext().error(response);
|
||||
}
|
||||
} catch (JSONException e) {
|
||||
this.respondWithError("There was an error generating the response");
|
||||
this.setupDataSerializer(request);
|
||||
this.prepareRequest(request);
|
||||
this.prepareRequestBody(request);
|
||||
this.returnResponseObject(request);
|
||||
} catch (HttpRequestException e) {
|
||||
if (e.getCause() instanceof UnknownHostException) {
|
||||
this.respondWithError(0, "The host could not be resolved");
|
||||
} else if (e.getCause() instanceof SocketTimeoutException) {
|
||||
this.respondWithError(1, "The request timed out");
|
||||
} else if (e.getCause() instanceof SSLHandshakeException) {
|
||||
this.respondWithError("SSL handshake failed");
|
||||
} else {
|
||||
this.respondWithError("There was an error with the request");
|
||||
}
|
||||
this.handleHttpRequestException(e);
|
||||
} catch (Exception e) {
|
||||
this.respondWithError(-1, e.getMessage());
|
||||
this.respondWithError(e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,12 +41,7 @@ class CordovaHttpUpload extends CordovaHttp implements Runnable {
|
||||
try {
|
||||
HttpRequest request = HttpRequest.post(this.getUrlString());
|
||||
|
||||
request.readTimeout(this.getRequestTimeout());
|
||||
this.setupRedirect(request);
|
||||
this.setupSecurity(request);
|
||||
request.acceptCharset(CHARSET);
|
||||
request.headers(this.getHeadersMap());
|
||||
request.uncompress(true);
|
||||
this.prepareRequest(request);
|
||||
|
||||
URI uri = new URI(filePath);
|
||||
|
||||
@@ -59,8 +54,6 @@ class CordovaHttpUpload extends CordovaHttp implements Runnable {
|
||||
MimeTypeMap mimeTypeMap = MimeTypeMap.getSingleton();
|
||||
String mimeType = mimeTypeMap.getMimeTypeFromExtension(ext);
|
||||
|
||||
request.part(this.name, filename, mimeType, new File(uri));
|
||||
|
||||
Set<?> set = (Set<?>)this.getParamsMap().entrySet();
|
||||
Iterator<?> i = set.iterator();
|
||||
|
||||
@@ -77,38 +70,18 @@ class CordovaHttpUpload extends CordovaHttp implements Runnable {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
request.part(this.name, filename, mimeType, new File(uri));
|
||||
|
||||
int code = request.code();
|
||||
String body = request.body(CHARSET);
|
||||
|
||||
JSONObject response = new JSONObject();
|
||||
|
||||
this.addResponseHeaders(request, response);
|
||||
response.put("status", code);
|
||||
|
||||
if (code >= 200 && code < 300) {
|
||||
response.put("data", body);
|
||||
this.getCallbackContext().success(response);
|
||||
} else {
|
||||
response.put("error", body);
|
||||
this.getCallbackContext().error(response);
|
||||
}
|
||||
this.returnResponseObject(request);
|
||||
} catch (URISyntaxException e) {
|
||||
this.respondWithError("There was an error loading the file");
|
||||
} catch (JSONException e) {
|
||||
this.respondWithError("There was an error generating the response");
|
||||
} catch (HttpRequestException e) {
|
||||
if (e.getCause() instanceof UnknownHostException) {
|
||||
this.respondWithError(0, "The host could not be resolved");
|
||||
} else if (e.getCause() instanceof SocketTimeoutException) {
|
||||
this.respondWithError(1, "The request timed out");
|
||||
} else if (e.getCause() instanceof SSLHandshakeException) {
|
||||
this.respondWithError("SSL handshake failed");
|
||||
} else {
|
||||
this.respondWithError("There was an error with the request");
|
||||
}
|
||||
this.handleHttpRequestException(e);
|
||||
} catch (Exception e) {
|
||||
this.respondWithError(-1, e.getMessage());
|
||||
this.respondWithError(e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
181
src/browser/cordova-http-plugin.js
vendored
Normal file
181
src/browser/cordova-http-plugin.js
vendored
Normal file
@@ -0,0 +1,181 @@
|
||||
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 deserializeResponseHeaders(headers) {
|
||||
var headerMap = {};
|
||||
var arr = headers.trim().split(/[\r\n]+/);
|
||||
|
||||
arr.forEach(function (line) {
|
||||
var parts = line.split(': ');
|
||||
var header = parts.shift().toLowerCase();
|
||||
var value = parts.join(': ');
|
||||
|
||||
headerMap[header] = value;
|
||||
});
|
||||
|
||||
return headerMap;
|
||||
}
|
||||
|
||||
function createXhrSuccessObject(xhr) {
|
||||
return {
|
||||
url: xhr.responseURL,
|
||||
status: xhr.status,
|
||||
data: helpers.getTypeOf(xhr.responseText) === 'String' ? xhr.responseText : xhr.response,
|
||||
headers: deserializeResponseHeaders(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':
|
||||
xhr.setRequestHeader('Content-Type', 'application/json; charset=utf8');
|
||||
processedData = serializeJsonData(data);
|
||||
|
||||
if (processedData === null) {
|
||||
return failure('advanced-http: failed serializing data');
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 'utf8':
|
||||
xhr.setRequestHeader('Content-Type', 'text/plain; 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);
|
||||
@@ -156,16 +156,9 @@ static NSArray * AFPublicKeyTrustChainForServerTrust(SecTrustRef serverTrust) {
|
||||
@implementation AFSecurityPolicy
|
||||
|
||||
+ (NSSet *)certificatesInBundle:(NSBundle *)bundle {
|
||||
NSArray *paths = [bundle pathsForResourcesOfType:@"cer" inDirectory:@"."];
|
||||
|
||||
NSArray *paths = [bundle pathsForResourcesOfType:@"cer" inDirectory:@"www/certificates"];
|
||||
NSMutableSet *certificates = [NSMutableSet setWithCapacity:[paths count]];
|
||||
for (NSString *path in paths) {
|
||||
NSData *certificateData = [NSData dataWithContentsOfFile:path];
|
||||
[certificates addObject:certificateData];
|
||||
}
|
||||
|
||||
// also add certs from www/certificates
|
||||
paths = [bundle pathsForResourcesOfType:@"cer" inDirectory:@"www/certificates"];
|
||||
|
||||
for (NSString *path in paths) {
|
||||
NSData *certificateData = [NSData dataWithContentsOfFile:path];
|
||||
[certificates addObject:certificateData];
|
||||
@@ -284,13 +277,13 @@ static NSArray * AFPublicKeyTrustChainForServerTrust(SecTrustRef serverTrust) {
|
||||
|
||||
// obtain the chain after being validated, which *should* contain the pinned certificate in the last position (if it's the Root CA)
|
||||
NSArray *serverCertificates = AFCertificateTrustChainForServerTrust(serverTrust);
|
||||
|
||||
|
||||
for (NSData *trustChainCertificate in [serverCertificates reverseObjectEnumerator]) {
|
||||
if ([self.pinnedCertificates containsObject:trustChainCertificate]) {
|
||||
return YES;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return NO;
|
||||
}
|
||||
case AFSSLPinningModePublicKey: {
|
||||
@@ -307,7 +300,7 @@ static NSArray * AFPublicKeyTrustChainForServerTrust(SecTrustRef serverTrust) {
|
||||
return trustedPublicKeyCount > 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return NO;
|
||||
}
|
||||
|
||||
|
||||
@@ -4,8 +4,7 @@
|
||||
|
||||
@interface CordovaHttpPlugin : CDVPlugin
|
||||
|
||||
- (void)enableSSLPinning:(CDVInvokedUrlCommand*)command;
|
||||
- (void)acceptAllCerts:(CDVInvokedUrlCommand*)command;
|
||||
- (void)setSSLCertMode:(CDVInvokedUrlCommand*)command;
|
||||
- (void)disableRedirect:(CDVInvokedUrlCommand*)command;
|
||||
- (void)post:(CDVInvokedUrlCommand*)command;
|
||||
- (void)get:(CDVInvokedUrlCommand*)command;
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
#import "CordovaHttpPlugin.h"
|
||||
#import "CDVFile.h"
|
||||
#import "TextResponseSerializer.h"
|
||||
#import "TextRequestSerializer.h"
|
||||
#import "AFHTTPSessionManager.h"
|
||||
#import "SDNetworkActivityIndicator.h"
|
||||
|
||||
@interface CordovaHttpPlugin()
|
||||
|
||||
@@ -28,6 +30,8 @@
|
||||
- (void)setRequestSerializer:(NSString*)serializerName forManager:(AFHTTPSessionManager*)manager {
|
||||
if ([serializerName isEqualToString:@"json"]) {
|
||||
manager.requestSerializer = [AFJSONRequestSerializer serializer];
|
||||
} else if ([serializerName isEqualToString:@"utf8"]) {
|
||||
manager.requestSerializer = [TextRequestSerializer serializer];
|
||||
} else {
|
||||
manager.requestSerializer = [AFHTTPRequestSerializer serializer];
|
||||
}
|
||||
@@ -51,7 +55,8 @@
|
||||
|
||||
- (void)handleSuccess:(NSMutableDictionary*)dictionary withResponse:(NSHTTPURLResponse*)response andData:(id)data {
|
||||
if (response != nil) {
|
||||
[dictionary setObject:[NSNumber numberWithInt:response.statusCode] forKey:@"status"];
|
||||
[dictionary setValue:response.URL.absoluteString forKey:@"url"];
|
||||
[dictionary setObject:[NSNumber numberWithInt:(int)response.statusCode] forKey:@"status"];
|
||||
[dictionary setObject:[self copyHeaderFields:response.allHeaderFields] forKey:@"headers"];
|
||||
}
|
||||
|
||||
@@ -62,15 +67,29 @@
|
||||
|
||||
- (void)handleError:(NSMutableDictionary*)dictionary withResponse:(NSHTTPURLResponse*)response error:(NSError*)error {
|
||||
if (response != nil) {
|
||||
[dictionary setObject:[NSNumber numberWithInt:response.statusCode] forKey:@"status"];
|
||||
[dictionary setValue:response.URL.absoluteString forKey:@"url"];
|
||||
[dictionary setObject:[NSNumber numberWithInt:(int)response.statusCode] forKey:@"status"];
|
||||
[dictionary setObject:[self copyHeaderFields:response.allHeaderFields] forKey:@"headers"];
|
||||
[dictionary setObject:[[NSString alloc] initWithData:(NSData *)error.userInfo[AFNetworkingOperationFailingURLResponseDataErrorKey] encoding:NSUTF8StringEncoding] forKey:@"error"];
|
||||
if (error.userInfo[AFNetworkingOperationFailingURLResponseBodyKey]) {
|
||||
[dictionary setObject:error.userInfo[AFNetworkingOperationFailingURLResponseBodyKey] forKey:@"error"];
|
||||
}
|
||||
} else {
|
||||
[dictionary setObject:[self getStatusCode:error] forKey:@"status"];
|
||||
[dictionary setObject:[error localizedDescription] forKey:@"error"];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)handleException:(NSException*)exception withCommand:(CDVInvokedUrlCommand*)command {
|
||||
CordovaHttpPlugin* __weak weakSelf = self;
|
||||
|
||||
NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];
|
||||
[dictionary setValue:exception.userInfo forKey:@"error"];
|
||||
[dictionary setObject:[NSNumber numberWithInt:-1] forKey:@"status"];
|
||||
|
||||
CDVPluginResult *pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:dictionary];
|
||||
[weakSelf.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
|
||||
}
|
||||
|
||||
- (NSNumber*)getStatusCode:(NSError*) error {
|
||||
switch ([error code]) {
|
||||
case -1001:
|
||||
@@ -102,23 +121,31 @@
|
||||
return headerFieldsCopy;
|
||||
}
|
||||
|
||||
- (void)setTimeout:(NSTimeInterval)timeout forManager:(AFHTTPSessionManager*)manager {
|
||||
[manager.requestSerializer setTimeoutInterval:timeout];
|
||||
}
|
||||
- (void)setSSLCertMode:(CDVInvokedUrlCommand*)command {
|
||||
NSString *certMode = [command.arguments objectAtIndex:0];
|
||||
|
||||
- (void)enableSSLPinning:(CDVInvokedUrlCommand*)command {
|
||||
bool enable = [[command.arguments objectAtIndex:0] boolValue];
|
||||
|
||||
if (enable) {
|
||||
securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeCertificate];
|
||||
} else {
|
||||
if ([certMode isEqualToString: @"default"]) {
|
||||
securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeNone];
|
||||
securityPolicy.allowInvalidCertificates = NO;
|
||||
securityPolicy.validatesDomainName = YES;
|
||||
} else if ([certMode isEqualToString: @"nocheck"]) {
|
||||
securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeNone];
|
||||
securityPolicy.allowInvalidCertificates = YES;
|
||||
securityPolicy.validatesDomainName = NO;
|
||||
} else if ([certMode isEqualToString: @"pinned"]) {
|
||||
securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeCertificate];
|
||||
securityPolicy.allowInvalidCertificates = NO;
|
||||
securityPolicy.validatesDomainName = YES;
|
||||
}
|
||||
|
||||
CDVPluginResult* pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK];
|
||||
[self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
|
||||
}
|
||||
|
||||
- (void)setTimeout:(NSTimeInterval)timeout forManager:(AFHTTPSessionManager*)manager {
|
||||
[manager.requestSerializer setTimeoutInterval:timeout];
|
||||
}
|
||||
|
||||
- (void)disableRedirect:(CDVInvokedUrlCommand*)command {
|
||||
CDVPluginResult* pluginResult = nil;
|
||||
bool disable = [[command.arguments objectAtIndex:0] boolValue];
|
||||
@@ -129,17 +156,6 @@
|
||||
[self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
|
||||
}
|
||||
|
||||
- (void)acceptAllCerts:(CDVInvokedUrlCommand*)command {
|
||||
CDVPluginResult* pluginResult = nil;
|
||||
bool allow = [[command.arguments objectAtIndex:0] boolValue];
|
||||
|
||||
securityPolicy.allowInvalidCertificates = allow;
|
||||
securityPolicy.validatesDomainName = !allow;
|
||||
|
||||
pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK];
|
||||
[self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
|
||||
}
|
||||
|
||||
- (void)post:(CDVInvokedUrlCommand*)command {
|
||||
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
|
||||
manager.securityPolicy = securityPolicy;
|
||||
@@ -157,19 +173,29 @@
|
||||
|
||||
CordovaHttpPlugin* __weak weakSelf = self;
|
||||
manager.responseSerializer = [TextResponseSerializer serializer];
|
||||
[manager POST:url parameters:parameters progress:nil success:^(NSURLSessionTask *task, id responseObject) {
|
||||
NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];
|
||||
[self handleSuccess:dictionary withResponse:(NSHTTPURLResponse*)task.response andData:responseObject];
|
||||
[[SDNetworkActivityIndicator sharedActivityIndicator] startActivity];
|
||||
|
||||
CDVPluginResult *pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:dictionary];
|
||||
[weakSelf.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
|
||||
} failure:^(NSURLSessionTask *task, NSError *error) {
|
||||
NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];
|
||||
[self handleError:dictionary withResponse:(NSHTTPURLResponse*)task.response error:error];
|
||||
@try {
|
||||
[manager POST:url parameters:parameters progress:nil success:^(NSURLSessionTask *task, id responseObject) {
|
||||
NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];
|
||||
[self handleSuccess:dictionary withResponse:(NSHTTPURLResponse*)task.response andData:responseObject];
|
||||
|
||||
CDVPluginResult *pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:dictionary];
|
||||
[weakSelf.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
|
||||
}];
|
||||
CDVPluginResult *pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:dictionary];
|
||||
[weakSelf.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
|
||||
[[SDNetworkActivityIndicator sharedActivityIndicator] stopActivity];
|
||||
} failure:^(NSURLSessionTask *task, NSError *error) {
|
||||
NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];
|
||||
[self handleError:dictionary withResponse:(NSHTTPURLResponse*)task.response error:error];
|
||||
|
||||
CDVPluginResult *pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:dictionary];
|
||||
[weakSelf.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
|
||||
[[SDNetworkActivityIndicator sharedActivityIndicator] stopActivity];
|
||||
}];
|
||||
}
|
||||
@catch (NSException *exception) {
|
||||
[[SDNetworkActivityIndicator sharedActivityIndicator] stopActivity];
|
||||
[self handleException:exception withCommand:command];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)get:(CDVInvokedUrlCommand*)command {
|
||||
@@ -188,21 +214,30 @@
|
||||
[self setRedirect: manager];
|
||||
|
||||
CordovaHttpPlugin* __weak weakSelf = self;
|
||||
|
||||
manager.responseSerializer = [TextResponseSerializer serializer];
|
||||
[manager GET:url parameters:parameters progress:nil success:^(NSURLSessionTask *task, id responseObject) {
|
||||
NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];
|
||||
[self handleSuccess:dictionary withResponse:(NSHTTPURLResponse*)task.response andData:responseObject];
|
||||
[[SDNetworkActivityIndicator sharedActivityIndicator] startActivity];
|
||||
|
||||
CDVPluginResult *pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:dictionary];
|
||||
[weakSelf.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
|
||||
} failure:^(NSURLSessionTask *task, NSError *error) {
|
||||
NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];
|
||||
[self handleError:dictionary withResponse:(NSHTTPURLResponse*)task.response error:error];
|
||||
@try {
|
||||
[manager GET:url parameters:parameters progress:nil success:^(NSURLSessionTask *task, id responseObject) {
|
||||
NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];
|
||||
[self handleSuccess:dictionary withResponse:(NSHTTPURLResponse*)task.response andData:responseObject];
|
||||
|
||||
CDVPluginResult *pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:dictionary];
|
||||
[weakSelf.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
|
||||
}];
|
||||
CDVPluginResult *pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:dictionary];
|
||||
[weakSelf.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
|
||||
[[SDNetworkActivityIndicator sharedActivityIndicator] stopActivity];
|
||||
} failure:^(NSURLSessionTask *task, NSError *error) {
|
||||
NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];
|
||||
[self handleError:dictionary withResponse:(NSHTTPURLResponse*)task.response error:error];
|
||||
|
||||
CDVPluginResult *pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:dictionary];
|
||||
[weakSelf.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
|
||||
[[SDNetworkActivityIndicator sharedActivityIndicator] stopActivity];
|
||||
}];
|
||||
}
|
||||
@catch (NSException *exception) {
|
||||
[[SDNetworkActivityIndicator sharedActivityIndicator] stopActivity];
|
||||
[self handleException:exception withCommand:command];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)put:(CDVInvokedUrlCommand*)command {
|
||||
@@ -222,19 +257,29 @@
|
||||
|
||||
CordovaHttpPlugin* __weak weakSelf = self;
|
||||
manager.responseSerializer = [TextResponseSerializer serializer];
|
||||
[manager PUT:url parameters:parameters success:^(NSURLSessionTask *task, id responseObject) {
|
||||
NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];
|
||||
[self handleSuccess:dictionary withResponse:(NSHTTPURLResponse*)task.response andData:responseObject];
|
||||
[[SDNetworkActivityIndicator sharedActivityIndicator] startActivity];
|
||||
|
||||
CDVPluginResult *pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:dictionary];
|
||||
[weakSelf.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
|
||||
} failure:^(NSURLSessionTask *task, NSError *error) {
|
||||
NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];
|
||||
[self handleError:dictionary withResponse:(NSHTTPURLResponse*)task.response error:error];
|
||||
@try {
|
||||
[manager PUT:url parameters:parameters success:^(NSURLSessionTask *task, id responseObject) {
|
||||
NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];
|
||||
[self handleSuccess:dictionary withResponse:(NSHTTPURLResponse*)task.response andData:responseObject];
|
||||
|
||||
CDVPluginResult *pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:dictionary];
|
||||
[weakSelf.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
|
||||
}];
|
||||
CDVPluginResult *pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:dictionary];
|
||||
[weakSelf.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
|
||||
[[SDNetworkActivityIndicator sharedActivityIndicator] stopActivity];
|
||||
} failure:^(NSURLSessionTask *task, NSError *error) {
|
||||
NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];
|
||||
[self handleError:dictionary withResponse:(NSHTTPURLResponse*)task.response error:error];
|
||||
|
||||
CDVPluginResult *pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:dictionary];
|
||||
[weakSelf.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
|
||||
[[SDNetworkActivityIndicator sharedActivityIndicator] stopActivity];
|
||||
}];
|
||||
}
|
||||
@catch (NSException *exception) {
|
||||
[[SDNetworkActivityIndicator sharedActivityIndicator] stopActivity];
|
||||
[self handleException:exception withCommand:command];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)patch:(CDVInvokedUrlCommand*)command {
|
||||
@@ -254,19 +299,29 @@
|
||||
|
||||
CordovaHttpPlugin* __weak weakSelf = self;
|
||||
manager.responseSerializer = [TextResponseSerializer serializer];
|
||||
[manager PATCH:url parameters:parameters success:^(NSURLSessionTask *task, id responseObject) {
|
||||
NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];
|
||||
[self handleSuccess:dictionary withResponse:(NSHTTPURLResponse*)task.response andData:responseObject];
|
||||
[[SDNetworkActivityIndicator sharedActivityIndicator] startActivity];
|
||||
|
||||
CDVPluginResult *pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:dictionary];
|
||||
[weakSelf.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
|
||||
} failure:^(NSURLSessionTask *task, NSError *error) {
|
||||
NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];
|
||||
[self handleError:dictionary withResponse:(NSHTTPURLResponse*)task.response error:error];
|
||||
@try {
|
||||
[manager PATCH:url parameters:parameters success:^(NSURLSessionTask *task, id responseObject) {
|
||||
NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];
|
||||
[self handleSuccess:dictionary withResponse:(NSHTTPURLResponse*)task.response andData:responseObject];
|
||||
|
||||
CDVPluginResult *pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:dictionary];
|
||||
[weakSelf.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
|
||||
}];
|
||||
CDVPluginResult *pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:dictionary];
|
||||
[weakSelf.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
|
||||
[[SDNetworkActivityIndicator sharedActivityIndicator] stopActivity];
|
||||
} failure:^(NSURLSessionTask *task, NSError *error) {
|
||||
NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];
|
||||
[self handleError:dictionary withResponse:(NSHTTPURLResponse*)task.response error:error];
|
||||
|
||||
CDVPluginResult *pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:dictionary];
|
||||
[weakSelf.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
|
||||
[[SDNetworkActivityIndicator sharedActivityIndicator] stopActivity];
|
||||
}];
|
||||
}
|
||||
@catch (NSException *exception) {
|
||||
[[SDNetworkActivityIndicator sharedActivityIndicator] stopActivity];
|
||||
[self handleException:exception withCommand:command];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)delete:(CDVInvokedUrlCommand*)command {
|
||||
@@ -284,21 +339,30 @@
|
||||
[self setRedirect: manager];
|
||||
|
||||
CordovaHttpPlugin* __weak weakSelf = self;
|
||||
|
||||
manager.responseSerializer = [TextResponseSerializer serializer];
|
||||
[manager DELETE:url parameters:parameters success:^(NSURLSessionTask *task, id responseObject) {
|
||||
NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];
|
||||
[self handleSuccess:dictionary withResponse:(NSHTTPURLResponse*)task.response andData:responseObject];
|
||||
[[SDNetworkActivityIndicator sharedActivityIndicator] startActivity];
|
||||
|
||||
CDVPluginResult *pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:dictionary];
|
||||
[weakSelf.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
|
||||
} failure:^(NSURLSessionTask *task, NSError *error) {
|
||||
NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];
|
||||
[self handleError:dictionary withResponse:(NSHTTPURLResponse*)task.response error:error];
|
||||
@try {
|
||||
[manager DELETE:url parameters:parameters success:^(NSURLSessionTask *task, id responseObject) {
|
||||
NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];
|
||||
[self handleSuccess:dictionary withResponse:(NSHTTPURLResponse*)task.response andData:responseObject];
|
||||
|
||||
CDVPluginResult *pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:dictionary];
|
||||
[weakSelf.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
|
||||
}];
|
||||
CDVPluginResult *pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:dictionary];
|
||||
[weakSelf.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
|
||||
[[SDNetworkActivityIndicator sharedActivityIndicator] stopActivity];
|
||||
} failure:^(NSURLSessionTask *task, NSError *error) {
|
||||
NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];
|
||||
[self handleError:dictionary withResponse:(NSHTTPURLResponse*)task.response error:error];
|
||||
|
||||
CDVPluginResult *pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:dictionary];
|
||||
[weakSelf.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
|
||||
[[SDNetworkActivityIndicator sharedActivityIndicator] stopActivity];
|
||||
}];
|
||||
}
|
||||
@catch (NSException *exception) {
|
||||
[[SDNetworkActivityIndicator sharedActivityIndicator] stopActivity];
|
||||
[self handleException:exception withCommand:command];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)head:(CDVInvokedUrlCommand*)command {
|
||||
@@ -314,22 +378,31 @@
|
||||
[self setRedirect: manager];
|
||||
|
||||
CordovaHttpPlugin* __weak weakSelf = self;
|
||||
|
||||
manager.responseSerializer = [AFHTTPResponseSerializer serializer];
|
||||
[manager HEAD:url parameters:parameters success:^(NSURLSessionTask *task) {
|
||||
NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];
|
||||
// no 'body' for HEAD request, omitting 'data'
|
||||
[self handleSuccess:dictionary withResponse:(NSHTTPURLResponse*)task.response andData:nil];
|
||||
[[SDNetworkActivityIndicator sharedActivityIndicator] startActivity];
|
||||
|
||||
CDVPluginResult *pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:dictionary];
|
||||
[weakSelf.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
|
||||
} failure:^(NSURLSessionTask *task, NSError *error) {
|
||||
NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];
|
||||
[self handleError:dictionary withResponse:(NSHTTPURLResponse*)task.response error:error];
|
||||
@try {
|
||||
[manager HEAD:url parameters:parameters success:^(NSURLSessionTask *task) {
|
||||
NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];
|
||||
// no 'body' for HEAD request, omitting 'data'
|
||||
[self handleSuccess:dictionary withResponse:(NSHTTPURLResponse*)task.response andData:nil];
|
||||
|
||||
CDVPluginResult *pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:dictionary];
|
||||
[weakSelf.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
|
||||
}];
|
||||
CDVPluginResult *pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:dictionary];
|
||||
[weakSelf.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
|
||||
[[SDNetworkActivityIndicator sharedActivityIndicator] stopActivity];
|
||||
} failure:^(NSURLSessionTask *task, NSError *error) {
|
||||
NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];
|
||||
[self handleError:dictionary withResponse:(NSHTTPURLResponse*)task.response error:error];
|
||||
|
||||
CDVPluginResult *pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:dictionary];
|
||||
[weakSelf.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
|
||||
[[SDNetworkActivityIndicator sharedActivityIndicator] stopActivity];
|
||||
}];
|
||||
}
|
||||
@catch (NSException *exception) {
|
||||
[[SDNetworkActivityIndicator sharedActivityIndicator] stopActivity];
|
||||
[self handleException:exception withCommand:command];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)uploadFile:(CDVInvokedUrlCommand*)command {
|
||||
@@ -351,30 +424,41 @@
|
||||
|
||||
CordovaHttpPlugin* __weak weakSelf = self;
|
||||
manager.responseSerializer = [TextResponseSerializer serializer];
|
||||
[manager POST:url parameters:parameters constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {
|
||||
NSError *error;
|
||||
[formData appendPartWithFileURL:fileURL name:name error:&error];
|
||||
if (error) {
|
||||
[[SDNetworkActivityIndicator sharedActivityIndicator] startActivity];
|
||||
|
||||
@try {
|
||||
[manager POST:url parameters:parameters constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {
|
||||
NSError *error;
|
||||
[formData appendPartWithFileURL:fileURL name:name error:&error];
|
||||
if (error) {
|
||||
NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];
|
||||
[dictionary setObject:[NSNumber numberWithInt:500] forKey:@"status"];
|
||||
[dictionary setObject:@"Could not add file to post body." forKey:@"error"];
|
||||
CDVPluginResult *pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:dictionary];
|
||||
[weakSelf.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
|
||||
[[SDNetworkActivityIndicator sharedActivityIndicator] stopActivity];
|
||||
return;
|
||||
}
|
||||
} progress:nil success:^(NSURLSessionTask *task, id responseObject) {
|
||||
NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];
|
||||
[dictionary setObject:[NSNumber numberWithInt:500] forKey:@"status"];
|
||||
[dictionary setObject:@"Could not add file to post body." forKey:@"error"];
|
||||
[self handleSuccess:dictionary withResponse:(NSHTTPURLResponse*)task.response andData:responseObject];
|
||||
|
||||
CDVPluginResult *pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:dictionary];
|
||||
[weakSelf.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
|
||||
[[SDNetworkActivityIndicator sharedActivityIndicator] stopActivity];
|
||||
} failure:^(NSURLSessionTask *task, NSError *error) {
|
||||
NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];
|
||||
[self handleError:dictionary withResponse:(NSHTTPURLResponse*)task.response error:error];
|
||||
|
||||
CDVPluginResult *pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:dictionary];
|
||||
[weakSelf.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
|
||||
return;
|
||||
}
|
||||
} progress:nil success:^(NSURLSessionTask *task, id responseObject) {
|
||||
NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];
|
||||
[self handleSuccess:dictionary withResponse:(NSHTTPURLResponse*)task.response andData:nil];
|
||||
|
||||
CDVPluginResult *pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:dictionary];
|
||||
[weakSelf.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
|
||||
} failure:^(NSURLSessionTask *task, NSError *error) {
|
||||
NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];
|
||||
[self handleError:dictionary withResponse:(NSHTTPURLResponse*)task.response error:error];
|
||||
|
||||
CDVPluginResult *pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:dictionary];
|
||||
[weakSelf.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
|
||||
}];
|
||||
[[SDNetworkActivityIndicator sharedActivityIndicator] stopActivity];
|
||||
}];
|
||||
}
|
||||
@catch (NSException *exception) {
|
||||
[[SDNetworkActivityIndicator sharedActivityIndicator] stopActivity];
|
||||
[self handleException:exception withCommand:command];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -398,70 +482,83 @@
|
||||
|
||||
CordovaHttpPlugin* __weak weakSelf = self;
|
||||
manager.responseSerializer = [AFHTTPResponseSerializer serializer];
|
||||
[manager GET:url parameters:parameters progress:nil success:^(NSURLSessionTask *task, id responseObject) {
|
||||
/*
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* Modified by Andrew Stephan for Sync OnSet
|
||||
*
|
||||
*/
|
||||
// Download response is okay; begin streaming output to file
|
||||
NSString* parentPath = [filePath stringByDeletingLastPathComponent];
|
||||
[[SDNetworkActivityIndicator sharedActivityIndicator] startActivity];
|
||||
|
||||
// create parent directories if needed
|
||||
NSError *error;
|
||||
if ([[NSFileManager defaultManager] createDirectoryAtPath:parentPath withIntermediateDirectories:YES attributes:nil error:&error] == NO) {
|
||||
NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];
|
||||
[dictionary setObject:[NSNumber numberWithInt:500] forKey:@"status"];
|
||||
if (error) {
|
||||
[dictionary setObject:[NSString stringWithFormat:@"Could not create path to save downloaded file: %@", [error localizedDescription]] forKey:@"error"];
|
||||
} else {
|
||||
[dictionary setObject:@"Could not create path to save downloaded file" forKey:@"error"];
|
||||
@try {
|
||||
[manager GET:url parameters:parameters progress:nil success:^(NSURLSessionTask *task, id responseObject) {
|
||||
/*
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* Modified by Andrew Stephan for Sync OnSet
|
||||
*
|
||||
*/
|
||||
// Download response is okay; begin streaming output to file
|
||||
NSString* parentPath = [filePath stringByDeletingLastPathComponent];
|
||||
|
||||
// create parent directories if needed
|
||||
NSError *error;
|
||||
if ([[NSFileManager defaultManager] createDirectoryAtPath:parentPath withIntermediateDirectories:YES attributes:nil error:&error] == NO) {
|
||||
NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];
|
||||
[dictionary setObject:[NSNumber numberWithInt:500] forKey:@"status"];
|
||||
if (error) {
|
||||
[dictionary setObject:[NSString stringWithFormat:@"Could not create path to save downloaded file: %@", [error localizedDescription]] forKey:@"error"];
|
||||
} else {
|
||||
[dictionary setObject:@"Could not create path to save downloaded file" forKey:@"error"];
|
||||
}
|
||||
CDVPluginResult *pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:dictionary];
|
||||
[weakSelf.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
|
||||
[[SDNetworkActivityIndicator sharedActivityIndicator] stopActivity];
|
||||
return;
|
||||
}
|
||||
CDVPluginResult *pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:dictionary];
|
||||
[weakSelf.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
|
||||
return;
|
||||
}
|
||||
NSData *data = (NSData *)responseObject;
|
||||
if (![data writeToFile:filePath atomically:YES]) {
|
||||
NSData *data = (NSData *)responseObject;
|
||||
if (![data writeToFile:filePath atomically:YES]) {
|
||||
NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];
|
||||
[dictionary setObject:[NSNumber numberWithInt:500] forKey:@"status"];
|
||||
[dictionary setObject:@"Could not write the data to the given filePath." forKey:@"error"];
|
||||
CDVPluginResult *pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:dictionary];
|
||||
[weakSelf.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
|
||||
[[SDNetworkActivityIndicator sharedActivityIndicator] stopActivity];
|
||||
return;
|
||||
}
|
||||
|
||||
id filePlugin = [self.commandDelegate getCommandInstance:@"File"];
|
||||
NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];
|
||||
[dictionary setObject:[NSNumber numberWithInt:500] forKey:@"status"];
|
||||
[dictionary setObject:@"Could not write the data to the given filePath." forKey:@"error"];
|
||||
[self handleSuccess:dictionary withResponse:(NSHTTPURLResponse*)task.response andData:nil];
|
||||
[dictionary setObject:[filePlugin getDirectoryEntry:filePath isDirectory:NO] forKey:@"file"];
|
||||
|
||||
CDVPluginResult *pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:dictionary];
|
||||
[weakSelf.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
|
||||
[[SDNetworkActivityIndicator sharedActivityIndicator] stopActivity];
|
||||
} failure:^(NSURLSessionTask *task, NSError *error) {
|
||||
NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];
|
||||
[self handleError:dictionary withResponse:(NSHTTPURLResponse*)task.response error:error];
|
||||
[dictionary setObject:@"There was an error downloading the file" forKey:@"error"];
|
||||
|
||||
CDVPluginResult *pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:dictionary];
|
||||
[weakSelf.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
|
||||
return;
|
||||
}
|
||||
|
||||
id filePlugin = [self.commandDelegate getCommandInstance:@"File"];
|
||||
NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];
|
||||
[self handleSuccess:dictionary withResponse:(NSHTTPURLResponse*)task.response andData:nil];
|
||||
[dictionary setObject:[filePlugin getDirectoryEntry:filePath isDirectory:NO] forKey:@"file"];
|
||||
|
||||
CDVPluginResult *pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:dictionary];
|
||||
[weakSelf.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
|
||||
} failure:^(NSURLSessionTask *task, NSError *error) {
|
||||
NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];
|
||||
[self handleError:dictionary withResponse:(NSHTTPURLResponse*)task.response error:error];
|
||||
|
||||
CDVPluginResult *pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:dictionary];
|
||||
[weakSelf.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
|
||||
}];
|
||||
[[SDNetworkActivityIndicator sharedActivityIndicator] stopActivity];
|
||||
}];
|
||||
}
|
||||
@catch (NSException *exception) {
|
||||
[[SDNetworkActivityIndicator sharedActivityIndicator] stopActivity];
|
||||
[self handleException:exception withCommand:command];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
20
src/ios/SDNetworkActivityIndicator/LICENSE
Normal file
20
src/ios/SDNetworkActivityIndicator/LICENSE
Normal file
@@ -0,0 +1,20 @@
|
||||
Copyright (c) 2010 Olivier Poitrey <rs@dailymotion.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is furnished
|
||||
to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
52
src/ios/SDNetworkActivityIndicator/README.md
Normal file
52
src/ios/SDNetworkActivityIndicator/README.md
Normal file
@@ -0,0 +1,52 @@
|
||||
# SDNetworkActivityIndicator
|
||||
|
||||
Handle showing / hiding of the iOS network activity indicator to allow multiple concurrent threads to show / hide the indicator such that the indicator remains visible until all the requests have completed and requested the indicator to be hidden.
|
||||
|
||||
## Requirements
|
||||
|
||||
* iOS 5.0 or later.
|
||||
* ARC memory management.
|
||||
|
||||
## Installation
|
||||
|
||||
The easiest way to install it is by copying the following files to your project:
|
||||
|
||||
* SDNetworkActivityIndicator.h
|
||||
* SDNetworkActivityIndicator.m
|
||||
|
||||
## Usage
|
||||
|
||||
* When you start a network activity (will show the network activity indicator):
|
||||
|
||||
[[SDNetworkActivityIndicator sharedActivityIndicator] startActivity];
|
||||
|
||||
* When you finish a network activity (will hide the network activity indicator only if the number of calls to `stopActivity` matches the number of calls to `startActivity`):
|
||||
|
||||
[[SDNetworkActivityIndicator sharedActivityIndicator] stopActivity];
|
||||
|
||||
* To hide the network activity indicator regardless of whether all activities have finished (without having to call `stopActivity` for each `startActivity` called):
|
||||
|
||||
[[SDNetworkActivityIndicator sharedActivityIndicator] stopAllActivity];
|
||||
|
||||
|
||||
## License
|
||||
Copyright (c) 2010 Olivier Poitrey <rs@dailymotion.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is furnished
|
||||
to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
* This file is part of the SDNetworkActivityIndicator package.
|
||||
* (c) Olivier Poitrey <rs@dailymotion.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface SDNetworkActivityIndicator : NSObject
|
||||
|
||||
+ (id)sharedActivityIndicator;
|
||||
- (void)startActivity;
|
||||
- (void)stopActivity;
|
||||
- (void)stopAllActivity;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* This file is part of the SDNetworkActivityIndicator package.
|
||||
* (c) Olivier Poitrey <rs@dailymotion.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
#import "SDNetworkActivityIndicator.h"
|
||||
|
||||
@interface SDNetworkActivityIndicator()
|
||||
{
|
||||
@private NSUInteger counter;
|
||||
}
|
||||
@end
|
||||
|
||||
|
||||
@implementation SDNetworkActivityIndicator
|
||||
|
||||
+ (instancetype) sharedActivityIndicator
|
||||
{
|
||||
static id _sharedInstance = nil;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
_sharedInstance = [[self alloc] init];
|
||||
});
|
||||
|
||||
return _sharedInstance;
|
||||
}
|
||||
|
||||
- (id)init
|
||||
{
|
||||
if ((self = [super init]))
|
||||
{
|
||||
counter = 0;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)startActivity
|
||||
{
|
||||
@synchronized(self)
|
||||
{
|
||||
counter++;
|
||||
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)stopActivity
|
||||
{
|
||||
@synchronized(self)
|
||||
{
|
||||
if (counter > 0 && --counter == 0)
|
||||
{
|
||||
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)stopAllActivity
|
||||
{
|
||||
@synchronized(self)
|
||||
{
|
||||
counter = 0;
|
||||
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
8
src/ios/TextRequestSerializer.h
Normal file
8
src/ios/TextRequestSerializer.h
Normal file
@@ -0,0 +1,8 @@
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "AFURLRequestSerialization.h"
|
||||
|
||||
@interface TextRequestSerializer : AFHTTPRequestSerializer
|
||||
|
||||
+ (instancetype)serializer;
|
||||
|
||||
@end
|
||||
53
src/ios/TextRequestSerializer.m
Normal file
53
src/ios/TextRequestSerializer.m
Normal file
@@ -0,0 +1,53 @@
|
||||
#import "TextRequestSerializer.h"
|
||||
|
||||
@implementation TextRequestSerializer
|
||||
|
||||
+ (instancetype)serializer
|
||||
{
|
||||
TextRequestSerializer *serializer = [[self alloc] init];
|
||||
return serializer;
|
||||
}
|
||||
|
||||
#pragma mark - AFURLRequestSerialization
|
||||
|
||||
- (NSURLRequest *)requestBySerializingRequest:(NSURLRequest *)request
|
||||
withParameters:(id)parameters
|
||||
error:(NSError *__autoreleasing *)error
|
||||
{
|
||||
NSParameterAssert(request);
|
||||
|
||||
if ([self.HTTPMethodsEncodingParametersInURI containsObject:[[request HTTPMethod] uppercaseString]]) {
|
||||
return [super requestBySerializingRequest:request withParameters:parameters error:error];
|
||||
}
|
||||
|
||||
NSMutableURLRequest *mutableRequest = [request mutableCopy];
|
||||
|
||||
[self.HTTPRequestHeaders enumerateKeysAndObjectsUsingBlock:^(id field, id value, BOOL * __unused stop) {
|
||||
if (![request valueForHTTPHeaderField:field]) {
|
||||
[mutableRequest setValue:value forHTTPHeaderField:field];
|
||||
}
|
||||
}];
|
||||
|
||||
if (parameters) {
|
||||
if (![mutableRequest valueForHTTPHeaderField:@"Content-Type"]) {
|
||||
[mutableRequest setValue:@"text/plain; charset=utf-8" forHTTPHeaderField:@"Content-Type"];
|
||||
}
|
||||
|
||||
[mutableRequest setHTTPBody: [[parameters valueForKey:@"text"] dataUsingEncoding:NSUTF8StringEncoding]];
|
||||
}
|
||||
|
||||
return mutableRequest;
|
||||
}
|
||||
|
||||
#pragma mark - NSSecureCoding
|
||||
|
||||
- (instancetype)initWithCoder:(NSCoder *)decoder {
|
||||
self = [super initWithCoder:decoder];
|
||||
if (!self) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -5,4 +5,6 @@
|
||||
|
||||
+ (instancetype)serializer;
|
||||
|
||||
@end
|
||||
FOUNDATION_EXPORT NSString * const AFNetworkingOperationFailingURLResponseBodyKey;
|
||||
|
||||
@end
|
||||
|
||||
@@ -1,31 +1,126 @@
|
||||
#import "TextResponseSerializer.h"
|
||||
|
||||
static BOOL AFErrorOrUnderlyingErrorHasCodeInDomain(NSError *error, NSInteger code, NSString *domain) {
|
||||
if ([error.domain isEqualToString:domain] && error.code == code) {
|
||||
return YES;
|
||||
} else if (error.userInfo[NSUnderlyingErrorKey]) {
|
||||
return AFErrorOrUnderlyingErrorHasCodeInDomain(error.userInfo[NSUnderlyingErrorKey], code, domain);
|
||||
}
|
||||
NSString * const AFNetworkingOperationFailingURLResponseBodyKey = @"com.alamofire.serialization.response.error.body";
|
||||
NSStringEncoding const SupportedEncodings[6] = { NSUTF8StringEncoding, NSWindowsCP1252StringEncoding, NSISOLatin1StringEncoding, NSISOLatin2StringEncoding, NSASCIIStringEncoding, NSUnicodeStringEncoding };
|
||||
|
||||
return NO;
|
||||
static NSError * AFErrorWithUnderlyingError(NSError *error, NSError *underlyingError) {
|
||||
if (!error) {
|
||||
return underlyingError;
|
||||
}
|
||||
|
||||
if (!underlyingError || error.userInfo[NSUnderlyingErrorKey]) {
|
||||
return error;
|
||||
}
|
||||
|
||||
NSMutableDictionary *mutableUserInfo = [error.userInfo mutableCopy];
|
||||
mutableUserInfo[NSUnderlyingErrorKey] = underlyingError;
|
||||
|
||||
return [[NSError alloc] initWithDomain:error.domain code:error.code userInfo:mutableUserInfo];
|
||||
}
|
||||
|
||||
static BOOL AFErrorOrUnderlyingErrorHasCodeInDomain(NSError *error, NSInteger code, NSString *domain) {
|
||||
if ([error.domain isEqualToString:domain] && error.code == code) {
|
||||
return YES;
|
||||
} else if (error.userInfo[NSUnderlyingErrorKey]) {
|
||||
return AFErrorOrUnderlyingErrorHasCodeInDomain(error.userInfo[NSUnderlyingErrorKey], code, domain);
|
||||
}
|
||||
|
||||
return NO;
|
||||
}
|
||||
|
||||
@implementation TextResponseSerializer
|
||||
|
||||
+ (instancetype)serializer {
|
||||
TextResponseSerializer *serializer = [[self alloc] init];
|
||||
return serializer;
|
||||
TextResponseSerializer *serializer = [[self alloc] init];
|
||||
return serializer;
|
||||
}
|
||||
|
||||
- (instancetype)init {
|
||||
self = [super init];
|
||||
if (!self) {
|
||||
return nil;
|
||||
self = [super init];
|
||||
|
||||
if (!self) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
self.acceptableContentTypes = nil;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (NSString*)decodeResponseData:(NSData*)rawResponseData withEncoding:(CFStringEncoding)cfEncoding {
|
||||
NSStringEncoding nsEncoding;
|
||||
NSString* decoded = nil;
|
||||
|
||||
if (cfEncoding != kCFStringEncodingInvalidId) {
|
||||
nsEncoding = CFStringConvertEncodingToNSStringEncoding(cfEncoding);
|
||||
}
|
||||
|
||||
for (int i = 0; i < sizeof(SupportedEncodings) / sizeof(NSStringEncoding) && !decoded; ++i) {
|
||||
if (cfEncoding == kCFStringEncodingInvalidId || nsEncoding == SupportedEncodings[i]) {
|
||||
decoded = [[NSString alloc] initWithData:rawResponseData encoding:SupportedEncodings[i]];
|
||||
}
|
||||
}
|
||||
|
||||
return decoded;
|
||||
}
|
||||
|
||||
- (CFStringEncoding) getEncoding:(NSURLResponse *)response {
|
||||
CFStringEncoding encoding = kCFStringEncodingInvalidId;
|
||||
|
||||
if (response.textEncodingName) {
|
||||
encoding = CFStringConvertIANACharSetNameToEncoding((CFStringRef)response.textEncodingName);
|
||||
}
|
||||
|
||||
return encoding;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
|
||||
- (BOOL)validateResponse:(NSHTTPURLResponse *)response
|
||||
data:(NSData *)data
|
||||
decoded:(NSString **)decoded
|
||||
error:(NSError * __autoreleasing *)error
|
||||
{
|
||||
BOOL responseIsValid = YES;
|
||||
NSError *validationError = nil;
|
||||
|
||||
if (response && [response isKindOfClass:[NSHTTPURLResponse class]]) {
|
||||
if (data) {
|
||||
*decoded = [self decodeResponseData:data withEncoding:[self getEncoding:response]];
|
||||
}
|
||||
|
||||
self.acceptableContentTypes = [NSSet setWithObjects:@"text/plain", @"text/html", @"text/json", @"application/hal+json", @"application/json", @"text/xml", @"application/xml", @"text/css", nil];
|
||||
if (data && !*decoded) {
|
||||
NSMutableDictionary *mutableUserInfo = [@{
|
||||
NSURLErrorFailingURLErrorKey:[response URL],
|
||||
AFNetworkingOperationFailingURLResponseErrorKey: response,
|
||||
AFNetworkingOperationFailingURLResponseDataErrorKey: data,
|
||||
AFNetworkingOperationFailingURLResponseBodyKey: @"Could not decode response data due to invalid or unknown charset encoding",
|
||||
} mutableCopy];
|
||||
|
||||
return self;
|
||||
validationError = AFErrorWithUnderlyingError([NSError errorWithDomain:AFURLResponseSerializationErrorDomain code:NSURLErrorBadServerResponse userInfo:mutableUserInfo], validationError);
|
||||
responseIsValid = NO;
|
||||
} else if (self.acceptableStatusCodes && ![self.acceptableStatusCodes containsIndex:(NSUInteger)response.statusCode] && [response URL]) {
|
||||
NSMutableDictionary *mutableUserInfo = [@{
|
||||
NSLocalizedDescriptionKey: [NSString stringWithFormat:NSLocalizedStringFromTable(@"Request failed: %@ (%ld)", @"AFNetworking", nil), [NSHTTPURLResponse localizedStringForStatusCode:response.statusCode], (long)response.statusCode],
|
||||
NSURLErrorFailingURLErrorKey: [response URL],
|
||||
AFNetworkingOperationFailingURLResponseErrorKey: response,
|
||||
} mutableCopy];
|
||||
|
||||
if (data) {
|
||||
mutableUserInfo[AFNetworkingOperationFailingURLResponseDataErrorKey] = data;
|
||||
mutableUserInfo[AFNetworkingOperationFailingURLResponseBodyKey] = *decoded;
|
||||
}
|
||||
|
||||
validationError = AFErrorWithUnderlyingError([NSError errorWithDomain:AFURLResponseSerializationErrorDomain code:NSURLErrorBadServerResponse userInfo:mutableUserInfo], validationError);
|
||||
responseIsValid = NO;
|
||||
}
|
||||
}
|
||||
|
||||
if (error && !responseIsValid) {
|
||||
*error = validationError;
|
||||
}
|
||||
|
||||
return responseIsValid;
|
||||
}
|
||||
|
||||
#pragma mark - AFURLResponseSerialization
|
||||
@@ -34,25 +129,15 @@ static BOOL AFErrorOrUnderlyingErrorHasCodeInDomain(NSError *error, NSInteger co
|
||||
data:(NSData *)data
|
||||
error:(NSError *__autoreleasing *)error
|
||||
{
|
||||
if (![self validateResponse:(NSHTTPURLResponse *)response data:data error:error]) {
|
||||
if (!error || AFErrorOrUnderlyingErrorHasCodeInDomain(*error, NSURLErrorCannotDecodeContentData, AFURLResponseSerializationErrorDomain)) {
|
||||
return nil;
|
||||
}
|
||||
NSString* decoded = nil;
|
||||
|
||||
if (![self validateResponse:(NSHTTPURLResponse *)response data:data decoded:&decoded error:error]) {
|
||||
if (!error || AFErrorOrUnderlyingErrorHasCodeInDomain(*error, NSURLErrorCannotDecodeContentData, AFURLResponseSerializationErrorDomain)) {
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
|
||||
// Workaround for behavior of Rails to return a single space for `head :ok` (a workaround for a bug in Safari), which is not interpreted as valid input by NSJSONSerialization.
|
||||
// See https://github.com/rails/rails/issues/1742
|
||||
NSStringEncoding stringEncoding = self.stringEncoding;
|
||||
if (response.textEncodingName) {
|
||||
CFStringEncoding encoding = CFStringConvertIANACharSetNameToEncoding((CFStringRef)response.textEncodingName);
|
||||
if (encoding != kCFStringEncodingInvalidId) {
|
||||
stringEncoding = CFStringConvertEncodingToNSStringEncoding(encoding);
|
||||
}
|
||||
}
|
||||
|
||||
NSString *responseString = [[NSString alloc] initWithData:data encoding:stringEncoding];
|
||||
|
||||
return responseString;
|
||||
return decoded;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -8,18 +8,21 @@ const testDefinitions = require('../app-test-definitions');
|
||||
const pkgjson = require('../../package.json');
|
||||
|
||||
describe('Advanced HTTP', function() {
|
||||
const isDevice = process.argv.includes('--device');
|
||||
const isAndroid = process.argv.includes('--android');
|
||||
const targetInfo = { isDevice, isAndroid };
|
||||
|
||||
let driver = null;
|
||||
let allPassed = true;
|
||||
|
||||
this.timeout(900000);
|
||||
|
||||
const getCaps = appName => {
|
||||
const isDevice = process.argv.includes('--device');
|
||||
const isAndroid = process.argv.includes('--android');
|
||||
const desiredCaps = caps[(isAndroid ? 'android' : 'ios') + (isDevice ? 'Device' : 'Emulator')];
|
||||
const desiredApp = apps[(isAndroid ? 'android' : 'ios') + appName];
|
||||
const desiredOs = isAndroid ? 'android' : 'ios';
|
||||
const desiredCaps = caps[desiredOs + (isDevice ? 'Device' : 'Emulator')];
|
||||
const desiredApp = apps[desiredOs + appName];
|
||||
|
||||
desiredCaps.name = pkgjson.name;
|
||||
desiredCaps.name = pkgjson.name + ` (${desiredOs})`;
|
||||
desiredCaps.app = desiredApp;
|
||||
|
||||
return desiredCaps;
|
||||
@@ -57,7 +60,7 @@ describe('Advanced HTTP', function() {
|
||||
|
||||
const validateResult = testDefinition => driver
|
||||
.safeExecute('app.lastResult')
|
||||
.then(result => testDefinition.validationFunc(driver, result));
|
||||
.then(result => testDefinition.validationFunc(driver, result, targetInfo));
|
||||
|
||||
const clickNext = () => driver
|
||||
.elementById('nextBtn')
|
||||
@@ -80,10 +83,10 @@ describe('Advanced HTTP', function() {
|
||||
}));
|
||||
|
||||
testDefinitions.tests.forEach((definition, index) => {
|
||||
it(definition.description, function() {
|
||||
it(index + ': ' + definition.description, function() {
|
||||
return clickNext()
|
||||
.then(() => validateTestIndex(index))
|
||||
.then(() => validateTestTitle(this.test.title))
|
||||
.then(() => validateTestTitle(definition.description))
|
||||
.then(() => waitToBeFinished(definition.timeout || 10000))
|
||||
.then(() => validateResult(definition))
|
||||
});
|
||||
|
||||
@@ -23,5 +23,7 @@
|
||||
<allow-intent href="itms-apps:*" />
|
||||
</platform>
|
||||
<engine name="android" spec="6.2.3" />
|
||||
<engine name="browser" spec="5.0.0" />
|
||||
<engine name="ios" spec="4.4.0" />
|
||||
<plugin name="cordova-plugin-file" spec="4.3.3" />
|
||||
</widget>
|
||||
|
||||
0
test/app-template/www/certificates/.gitkeep
Normal file
0
test/app-template/www/certificates/.gitkeep
Normal file
@@ -1,7 +1,7 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Security-Policy" content="default-src 'self' data: gap: https://ssl.gstatic.com 'unsafe-eval'; style-src 'self' 'unsafe-inline'; media-src *; img-src 'self' data: content:;">
|
||||
<meta http-equiv="Content-Security-Policy" content="default-src 'self' data: gap: https://ssl.gstatic.com https://self-signed.badssl.com http://httpbin.org http://www.columbia.edu 'unsafe-eval'; style-src 'self' 'unsafe-inline'; media-src *; img-src 'self' data: content:;">
|
||||
<meta name="format-detection" content="telephone=no">
|
||||
<meta name="msapplication-tap-highlight" content="no">
|
||||
<meta name="viewport" content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width">
|
||||
|
||||
@@ -33,6 +33,16 @@ const app = {
|
||||
};
|
||||
},
|
||||
|
||||
throw: function(error) {
|
||||
document.getElementById('statusInput').value = 'finished';
|
||||
app.printResult('result - throwed', error.message);
|
||||
|
||||
app.lastResult = {
|
||||
type: 'throwed',
|
||||
message: error.message
|
||||
};
|
||||
},
|
||||
|
||||
getResult: function(cb) {
|
||||
cb(app.lastResult);
|
||||
},
|
||||
@@ -46,7 +56,12 @@ const app = {
|
||||
document.getElementById('expectedTextarea').value = expectedText;
|
||||
document.getElementById('resultTextarea').value = '';
|
||||
document.getElementById('descriptionLbl').innerText = titleText;
|
||||
testDefinition.func(app.resolve, app.reject);
|
||||
|
||||
try {
|
||||
testDefinition.func(app.resolve, app.reject);
|
||||
} catch (error) {
|
||||
app.throw(error);
|
||||
}
|
||||
},
|
||||
|
||||
onBeforeTest: function(testIndex, cb) {
|
||||
|
||||
@@ -1,12 +1,40 @@
|
||||
const hooks = {
|
||||
onBeforeEachTest: function(done) {
|
||||
cordova.plugin.http.acceptAllCerts(false, done, done);
|
||||
cordova.plugin.http.clearCookies();
|
||||
helpers.setDefaultCertMode(done);
|
||||
}
|
||||
};
|
||||
|
||||
const helpers = {
|
||||
acceptAllCerts: function(done) { cordova.plugin.http.acceptAllCerts(true, done, done); },
|
||||
setJsonSerializer: function(done) { done(cordova.plugin.http.setDataSerializer('json')); }
|
||||
setDefaultCertMode: function(done) { cordova.plugin.http.setSSLCertMode('default', done, done); },
|
||||
setNoCheckCertMode: function(done) { cordova.plugin.http.setSSLCertMode('nocheck', done, done); },
|
||||
setPinnedCertMode: function(done) { cordova.plugin.http.setSSLCertMode('pinned', done, done); },
|
||||
setJsonSerializer: function(done) { done(cordova.plugin.http.setDataSerializer('json')); },
|
||||
setUtf8StringSerializer: function(done) { done(cordova.plugin.http.setDataSerializer('utf8')); },
|
||||
setUrlEncodedSerializer: function(done) { done(cordova.plugin.http.setDataSerializer('urlencoded')); },
|
||||
getWithXhr: function(done, url) {
|
||||
var xhr = new XMLHttpRequest();
|
||||
|
||||
xhr.addEventListener('load', function() {
|
||||
done(this.responseText);
|
||||
});
|
||||
|
||||
xhr.open('GET', url);
|
||||
xhr.send();
|
||||
},
|
||||
writeToFile: function (done, fileName, content) {
|
||||
window.resolveLocalFileSystemURL(cordova.file.cacheDirectory, function (directoryEntry) {
|
||||
directoryEntry.getFile(fileName, { create: true, exclusive: false }, function (fileEntry) {
|
||||
fileEntry.createWriter(function (fileWriter) {
|
||||
var blob = new Blob([ content ], { type: 'text/plain' });
|
||||
|
||||
fileWriter.onwriteend = done;
|
||||
fileWriter.onerror = done;
|
||||
fileWriter.write(blob);
|
||||
}, done);
|
||||
}, done);
|
||||
}, done);
|
||||
}
|
||||
};
|
||||
|
||||
const tests = [
|
||||
@@ -14,46 +42,46 @@ const tests = [
|
||||
description: 'should reject self signed cert (GET)',
|
||||
expected: 'rejected: {"status":-1,"error":"cancelled"}',
|
||||
func: function(resolve, reject) { cordova.plugin.http.get('https://self-signed.badssl.com/', {}, {}, resolve, reject); },
|
||||
validationFunc: function(driver, result) {
|
||||
validationFunc: function(driver, result, targetInfo) {
|
||||
result.type.should.be.equal('rejected');
|
||||
result.data.should.be.eql({ status: -1, error:'cancelled' });
|
||||
result.data.should.be.eql({ status: -1, error: targetInfo.isAndroid ? 'SSL handshake failed' : 'cancelled' });
|
||||
}
|
||||
},{
|
||||
description: 'should reject self signed cert (PUT)',
|
||||
expected: 'rejected: {"status":-1,"error":"cancelled"}',
|
||||
func: function(resolve, reject) { cordova.plugin.http.put('https://self-signed.badssl.com/', { test: 'testString' }, {}, resolve, reject); },
|
||||
validationFunc: function(driver, result) {
|
||||
validationFunc: function(driver, result, targetInfo) {
|
||||
result.type.should.be.equal('rejected');
|
||||
result.data.should.be.eql({ status: -1, error:'cancelled' });
|
||||
result.data.should.be.eql({ status: -1, error: targetInfo.isAndroid ? 'SSL handshake failed' : 'cancelled' });
|
||||
}
|
||||
},{
|
||||
description: 'should reject self signed cert (POST)',
|
||||
expected: 'rejected: {"status":-1,"error":"cancelled"}',
|
||||
func: function(resolve, reject) { cordova.plugin.http.post('https://self-signed.badssl.com/', { test: 'testString' }, {}, resolve, reject); },
|
||||
validationFunc: function(driver, result) {
|
||||
validationFunc: function(driver, result, targetInfo) {
|
||||
result.type.should.be.equal('rejected');
|
||||
result.data.should.be.eql({ status: -1, error:'cancelled' });
|
||||
result.data.should.be.eql({ status: -1, error: targetInfo.isAndroid ? 'SSL handshake failed' : 'cancelled' });
|
||||
}
|
||||
},{
|
||||
description: 'should reject self signed cert (PATCH)',
|
||||
expected: 'rejected: {"status":-1,"error":"cancelled"}',
|
||||
func: function(resolve, reject) { cordova.plugin.http.patch('https://self-signed.badssl.com/', { test: 'testString' }, {}, resolve, reject); },
|
||||
validationFunc: function(driver, result) {
|
||||
validationFunc: function(driver, result, targetInfo) {
|
||||
result.type.should.be.equal('rejected');
|
||||
result.data.should.be.eql({ status: -1, error:'cancelled' });
|
||||
result.data.should.be.eql({ status: -1, error: targetInfo.isAndroid ? 'SSL handshake failed' : 'cancelled' });
|
||||
}
|
||||
},{
|
||||
description: 'should reject self signed cert (DELETE)',
|
||||
expected: 'rejected: {"status":-1,"error":"cancelled"}',
|
||||
func: function(resolve, reject) { cordova.plugin.http.delete('https://self-signed.badssl.com/', {}, {}, resolve, reject); },
|
||||
validationFunc: function(driver, result) {
|
||||
validationFunc: function(driver, result, targetInfo) {
|
||||
result.type.should.be.equal('rejected');
|
||||
result.data.should.be.eql({ status: -1, error:'cancelled' });
|
||||
result.data.should.be.eql({ status: -1, error: targetInfo.isAndroid ? 'SSL handshake failed' : 'cancelled' });
|
||||
}
|
||||
},{
|
||||
description: 'should accept bad cert (GET)',
|
||||
expected: 'resolved: {"status":200, ...',
|
||||
before: helpers.acceptAllCerts,
|
||||
before: helpers.setNoCheckCertMode,
|
||||
func: function(resolve, reject) { cordova.plugin.http.get('https://self-signed.badssl.com/', {}, {}, resolve, reject); },
|
||||
validationFunc: function(driver, result) {
|
||||
result.type.should.be.equal('resolved');
|
||||
@@ -62,7 +90,7 @@ const tests = [
|
||||
},{
|
||||
description: 'should accept bad cert (PUT)',
|
||||
expected: 'rejected: {"status":405, ... // will be rejected because PUT is not allowed',
|
||||
before: helpers.acceptAllCerts,
|
||||
before: helpers.setNoCheckCertMode,
|
||||
func: function(resolve, reject) { cordova.plugin.http.put('https://self-signed.badssl.com/', { test: 'testString' }, {}, resolve, reject); },
|
||||
validationFunc: function(driver, result) {
|
||||
result.type.should.be.equal('rejected');
|
||||
@@ -71,7 +99,7 @@ const tests = [
|
||||
},{
|
||||
description: 'should accept bad cert (POST)',
|
||||
expected: 'rejected: {"status":405, ... // will be rejected because POST is not allowed',
|
||||
before: helpers.acceptAllCerts,
|
||||
before: helpers.setNoCheckCertMode,
|
||||
func: function(resolve, reject) { cordova.plugin.http.post('https://self-signed.badssl.com/', { test: 'testString' }, {}, resolve, reject); },
|
||||
validationFunc: function(driver, result) {
|
||||
result.type.should.be.equal('rejected');
|
||||
@@ -80,7 +108,7 @@ const tests = [
|
||||
},{
|
||||
description: 'should accept bad cert (PATCH)',
|
||||
expected: 'rejected: {"status":405, ... // will be rejected because PATCH is not allowed',
|
||||
before: helpers.acceptAllCerts,
|
||||
before: helpers.setNoCheckCertMode,
|
||||
func: function(resolve, reject) { cordova.plugin.http.patch('https://self-signed.badssl.com/', { test: 'testString' }, {}, resolve, reject); },
|
||||
validationFunc: function(driver, result) {
|
||||
result.type.should.be.equal('rejected');
|
||||
@@ -89,7 +117,7 @@ const tests = [
|
||||
},{
|
||||
description: 'should accept bad cert (DELETE)',
|
||||
expected: 'rejected: {"status":405, ... // will be rejected because DELETE is not allowed',
|
||||
before: helpers.acceptAllCerts,
|
||||
before: helpers.setNoCheckCertMode,
|
||||
func: function(resolve, reject) { cordova.plugin.http.delete('https://self-signed.badssl.com/', {}, {}, resolve, reject); },
|
||||
validationFunc: function(driver, result) {
|
||||
result.type.should.be.equal('rejected');
|
||||
@@ -98,7 +126,7 @@ const tests = [
|
||||
},{
|
||||
description: 'should fetch data from http://httpbin.org/ (GET)',
|
||||
expected: 'resolved: {"status":200, ...',
|
||||
before: helpers.acceptAllCerts,
|
||||
before: helpers.setNoCheckCertMode,
|
||||
func: function(resolve, reject) { cordova.plugin.http.get('http://httpbin.org/', {}, {}, resolve, reject); },
|
||||
validationFunc: function(driver, result) {
|
||||
result.type.should.be.equal('resolved');
|
||||
@@ -106,7 +134,7 @@ const tests = [
|
||||
}
|
||||
},{
|
||||
description: 'should send JSON object correctly (POST)',
|
||||
expected: 'resolved: {"status": 200, data: "{\\"json\\":\\"test\\": \\"testString\\"}\" ...',
|
||||
expected: 'resolved: {"status": 200, "data": "{\\"json\\":\\"test\\": \\"testString\\"}\" ...',
|
||||
before: helpers.setJsonSerializer,
|
||||
func: function(resolve, reject) { cordova.plugin.http.post('http://httpbin.org/anything', { test: 'testString' }, {}, resolve, reject); },
|
||||
validationFunc: function(driver, result) {
|
||||
@@ -115,7 +143,7 @@ const tests = [
|
||||
}
|
||||
},{
|
||||
description: 'should send JSON object correctly (PUT)',
|
||||
expected: 'resolved: {"status": 200, data: "{\\"json\\":\\"test\\": \\"testString\\"}\" ...',
|
||||
expected: 'resolved: {"status": 200, "data": "{\\"json\\":\\"test\\": \\"testString\\"}\" ...',
|
||||
before: helpers.setJsonSerializer,
|
||||
func: function(resolve, reject) { cordova.plugin.http.put('http://httpbin.org/anything', { test: 'testString' }, {}, resolve, reject); },
|
||||
validationFunc: function(driver, result) {
|
||||
@@ -124,7 +152,7 @@ const tests = [
|
||||
}
|
||||
},{
|
||||
description: 'should send JSON object correctly (PATCH)',
|
||||
expected: 'resolved: {"status": 200, data: "{\\"json\\":\\"test\\": \\"testString\\"}\" ...',
|
||||
expected: 'resolved: {"status": 200, "data": "{\\"json\\":\\"test\\": \\"testString\\"}\" ...',
|
||||
before: helpers.setJsonSerializer,
|
||||
func: function(resolve, reject) { cordova.plugin.http.patch('http://httpbin.org/anything', { test: 'testString' }, {}, resolve, reject); },
|
||||
validationFunc: function(driver, result) {
|
||||
@@ -132,8 +160,8 @@ const tests = [
|
||||
JSON.parse(result.data.data).json.should.eql({ test: 'testString' });
|
||||
}
|
||||
},{
|
||||
description: 'should send JSON array correctly (POST)',
|
||||
expected: 'resolved: {"status": 200, data: "[ 1, 2, 3 ]\" ...',
|
||||
description: 'should send JSON array correctly (POST) #26',
|
||||
expected: 'resolved: {"status": 200, "data": "[ 1, 2, 3 ]\" ...',
|
||||
before: helpers.setJsonSerializer,
|
||||
func: function(resolve, reject) { cordova.plugin.http.post('http://httpbin.org/anything', [ 1, 2, 3 ], {}, resolve, reject); },
|
||||
validationFunc: function(driver, result) {
|
||||
@@ -141,8 +169,8 @@ const tests = [
|
||||
JSON.parse(result.data.data).json.should.eql([ 1, 2, 3 ]);
|
||||
}
|
||||
},{
|
||||
description: 'should send JSON array correctly (PUT)',
|
||||
expected: 'resolved: {"status": 200, data: "[ 1, 2, 3 ]\" ...',
|
||||
description: 'should send JSON array correctly (PUT) #26',
|
||||
expected: 'resolved: {"status": 200, "data": "[ 1, 2, 3 ]\" ...',
|
||||
before: helpers.setJsonSerializer,
|
||||
func: function(resolve, reject) { cordova.plugin.http.put('http://httpbin.org/anything', [ 1, 2, 3 ], {}, resolve, reject); },
|
||||
validationFunc: function(driver, result) {
|
||||
@@ -150,14 +178,312 @@ const tests = [
|
||||
JSON.parse(result.data.data).json.should.eql([ 1, 2, 3 ]);
|
||||
}
|
||||
},{
|
||||
description: 'should send JSON array correctly (PATCH)',
|
||||
expected: 'resolved: {"status": 200, data: "[ 1, 2, 3 ]\" ...',
|
||||
description: 'should send JSON array correctly (PATCH) #26',
|
||||
expected: 'resolved: {"status": 200, "data": "[ 1, 2, 3 ]\" ...',
|
||||
before: helpers.setJsonSerializer,
|
||||
func: function(resolve, reject) { cordova.plugin.http.patch('http://httpbin.org/anything', [ 1, 2, 3 ], {}, resolve, reject); },
|
||||
validationFunc: function(driver, result) {
|
||||
result.type.should.be.equal('resolved');
|
||||
result.data.data.should.be.a('string');
|
||||
JSON.parse(result.data.data).json.should.eql([ 1, 2, 3 ]);
|
||||
}
|
||||
},{
|
||||
description: 'should send url encoded data correctly (POST) #41',
|
||||
expected: 'resolved: {"status": 200, "data": "{\\"form\\":\\"test\\": \\"testString\\"}\" ...',
|
||||
before: helpers.setUrlEncodedSerializer,
|
||||
func: function(resolve, reject) { cordova.plugin.http.post('http://httpbin.org/anything', { test: 'testString' }, {}, resolve, reject); },
|
||||
validationFunc: function(driver, result) {
|
||||
result.type.should.be.equal('resolved');
|
||||
JSON.parse(result.data.data).form.should.eql({ test: 'testString' });
|
||||
}
|
||||
},{
|
||||
description: 'should send url encoded data correctly (PUT)',
|
||||
expected: 'resolved: {"status": 200, "data": "{\\"form\\":\\"test\\": \\"testString\\"}\" ...',
|
||||
before: helpers.setUrlEncodedSerializer,
|
||||
func: function(resolve, reject) { cordova.plugin.http.put('http://httpbin.org/anything', { test: 'testString' }, {}, resolve, reject); },
|
||||
validationFunc: function(driver, result) {
|
||||
result.type.should.be.equal('resolved');
|
||||
JSON.parse(result.data.data).form.should.eql({ test: 'testString' });
|
||||
}
|
||||
},{
|
||||
description: 'should send url encoded data correctly (PATCH)',
|
||||
expected: 'resolved: {"status": 200, "data": "{\\"form\\":\\"test\\": \\"testString\\"}\" ...',
|
||||
before: helpers.setUrlEncodedSerializer,
|
||||
func: function(resolve, reject) { cordova.plugin.http.patch('http://httpbin.org/anything', { test: 'testString' }, {}, resolve, reject); },
|
||||
validationFunc: function(driver, result) {
|
||||
result.type.should.be.equal('resolved');
|
||||
JSON.parse(result.data.data).form.should.eql({ test: 'testString' });
|
||||
}
|
||||
},{
|
||||
description: 'should resolve correct URL after redirect (GET) #33',
|
||||
expected: 'resolved: {"status": 200, url: "http://httpbin.org/anything", ...',
|
||||
func: function(resolve, reject) { cordova.plugin.http.get('http://httpbin.org/redirect-to?url=http://httpbin.org/anything', {}, {}, resolve, reject); },
|
||||
validationFunc: function(driver, result) {
|
||||
result.type.should.be.equal('resolved');
|
||||
result.data.url.should.be.equal('http://httpbin.org/anything');
|
||||
}
|
||||
},{
|
||||
description: 'should download a file from given URL to given path in local filesystem',
|
||||
expected: 'resolved: {"content": "<?xml version=\'1.0\' encoding=\'us-ascii\'?>\\n\\n<!-- A SAMPLE set of slides -->" ...',
|
||||
func: function(resolve, reject) {
|
||||
var sourceUrl = 'http://httpbin.org/xml';
|
||||
var targetPath = cordova.file.cacheDirectory + 'test.xml';
|
||||
|
||||
cordova.plugin.http.downloadFile(sourceUrl, {}, {}, targetPath, function(entry) {
|
||||
helpers.getWithXhr(function(content) {
|
||||
resolve({
|
||||
sourceUrl: sourceUrl,
|
||||
targetPath: targetPath,
|
||||
fullPath: entry.fullPath,
|
||||
name: entry.name,
|
||||
content: content
|
||||
});
|
||||
}, targetPath);
|
||||
}, reject);
|
||||
},
|
||||
validationFunc: function(driver, result) {
|
||||
result.type.should.be.equal('resolved');
|
||||
result.data.name.should.be.equal('test.xml');
|
||||
result.data.content.should.be.equal("<?xml version='1.0' encoding='us-ascii'?>\n\n<!-- A SAMPLE set of slides -->\n\n<slideshow \n title=\"Sample Slide Show\"\n date=\"Date of publication\"\n author=\"Yours Truly\"\n >\n\n <!-- TITLE SLIDE -->\n <slide type=\"all\">\n <title>Wake up to WonderWidgets!</title>\n </slide>\n\n <!-- OVERVIEW -->\n <slide type=\"all\">\n <title>Overview</title>\n <item>Why <em>WonderWidgets</em> are great</item>\n <item/>\n <item>Who <em>buys</em> WonderWidgets</item>\n </slide>\n\n</slideshow>");
|
||||
}
|
||||
},{
|
||||
description: 'should upload a file from given path in local filesystem to given URL #27',
|
||||
expected: 'resolved: {"status": 200, "data": "files": {"test-file.txt": "I am a dummy file. I am used ...',
|
||||
func: function(resolve, reject) {
|
||||
var fileName = 'test-file.txt';
|
||||
var fileContent = 'I am a dummy file. I am used for testing purposes!';
|
||||
var sourcePath = cordova.file.cacheDirectory + fileName;
|
||||
var targetUrl = 'http://httpbin.org/post';
|
||||
|
||||
helpers.writeToFile(function() {
|
||||
cordova.plugin.http.uploadFile(targetUrl, {}, {}, sourcePath, fileName, resolve, reject);
|
||||
}, fileName, fileContent);
|
||||
},
|
||||
validationFunc: function(driver, result) {
|
||||
var fileName = 'test-file.txt';
|
||||
var fileContent = 'I am a dummy file. I am used for testing purposes!';
|
||||
|
||||
result.type.should.be.equal('resolved');
|
||||
result.data.data.should.be.a('string');
|
||||
|
||||
JSON
|
||||
.parse(result.data.data)
|
||||
.files[fileName]
|
||||
.should.be.equal(fileContent);
|
||||
}
|
||||
},{
|
||||
description: 'should encode HTTP array params correctly (GET) #45',
|
||||
expected: 'resolved: {"status": 200, "data": "{\\"url\\":\\"http://httpbin.org/get?myArray[]=val1&myArray[]=val2&myArray[]=val3\\"}\" ...',
|
||||
func: function(resolve, reject) {
|
||||
cordova.plugin.http.get('http://httpbin.org/get', { myArray: [ 'val1', 'val2', 'val3' ], myString: 'testString' }, {}, resolve, reject);
|
||||
},
|
||||
validationFunc: function(driver, result) {
|
||||
result.type.should.be.equal('resolved');
|
||||
result.data.data.should.be.a('string');
|
||||
|
||||
JSON
|
||||
.parse(result.data.data)
|
||||
.url
|
||||
.should.be.equal('http://httpbin.org/get?myArray[]=val1&myArray[]=val2&myArray[]=val3&myString=testString');
|
||||
}
|
||||
},{
|
||||
description: 'should throw on non-string values in local header object #54',
|
||||
expected: 'throwed: {"message": "advanced-http: header values must be strings"}',
|
||||
func: function(resolve, reject) {
|
||||
cordova.plugin.http.get('http://httpbin.org/get', {}, { myTestHeader: 1 }, resolve, reject);
|
||||
},
|
||||
validationFunc: function(driver, result) {
|
||||
result.type.should.be.equal('throwed');
|
||||
result.message.should.be.equal('advanced-http: header values must be strings');
|
||||
}
|
||||
},{
|
||||
description: 'should throw an error while setting non-string value as global header #54',
|
||||
expected: 'throwed: "advanced-http: header values must be strings"',
|
||||
func: function(resolve, reject) {
|
||||
cordova.plugin.http.setHeader('myTestHeader', 2);
|
||||
},
|
||||
validationFunc: function(driver, result) {
|
||||
result.type.should.be.equal('throwed');
|
||||
result.message.should.be.equal('advanced-http: header values must be strings');
|
||||
}
|
||||
},{
|
||||
description: 'should accept content-type "application/xml" #58',
|
||||
expected: 'resolved: {"status": 200, ...',
|
||||
func: function(resolve, reject) {
|
||||
cordova.plugin.http.get('http://httpbin.org/xml', {}, {}, resolve, reject);
|
||||
},
|
||||
validationFunc: function(driver, result) {
|
||||
result.type.should.be.equal('resolved');
|
||||
result.data.status.should.be.equal(200);
|
||||
}
|
||||
},{
|
||||
description: 'should send programmatically set cookies correctly (GET)',
|
||||
expected: 'resolved: {"status": 200, ...',
|
||||
func: function(resolve, reject) {
|
||||
cordova.plugin.http.setCookie('http://httpbin.org/get', 'myCookie=myValue');
|
||||
cordova.plugin.http.setCookie('http://httpbin.org/get', 'mySecondCookie=mySecondValue');
|
||||
cordova.plugin.http.get('http://httpbin.org/get', {}, {}, resolve, reject);
|
||||
},
|
||||
validationFunc: function(driver, result) {
|
||||
result.type.should.be.equal('resolved');
|
||||
result.data.data.should.be.a('string');
|
||||
|
||||
JSON
|
||||
.parse(result.data.data)
|
||||
.headers
|
||||
.Cookie
|
||||
.should.be.equal('myCookie=myValue; mySecondCookie=mySecondValue');
|
||||
}
|
||||
},{
|
||||
description: 'should not send any cookies after running "clearCookies" (GET) #59',
|
||||
expected: 'resolved: {"status": 200, "data": "{\"headers\": {\"Cookie\": \"\"...',
|
||||
func: function(resolve, reject) {
|
||||
cordova.plugin.http.setCookie('http://httpbin.org/get', 'myCookie=myValue');
|
||||
cordova.plugin.http.setCookie('http://httpbin.org/get', 'mySecondCookie=mySecondValue');
|
||||
cordova.plugin.http.clearCookies();
|
||||
cordova.plugin.http.get('http://httpbin.org/get', {}, {}, resolve, reject);
|
||||
},
|
||||
validationFunc: function(driver, result) {
|
||||
result.type.should.be.equal('resolved');
|
||||
result.data.data.should.be.a('string');
|
||||
|
||||
JSON
|
||||
.parse(result.data.data)
|
||||
.headers
|
||||
.Cookie
|
||||
.should.be.equal('');
|
||||
}
|
||||
},{
|
||||
description: 'should send programmatically set cookies correctly (DOWNLOAD) #57',
|
||||
expected: 'resolved: {"content":{"cookies":{"myCookie":"myValue ...',
|
||||
func: function(resolve, reject) {
|
||||
var sourceUrl = 'http://httpbin.org/cookies';
|
||||
var targetPath = cordova.file.cacheDirectory + 'cookies.json';
|
||||
|
||||
cordova.plugin.http.setCookie('http://httpbin.org/get', 'myCookie=myValue');
|
||||
cordova.plugin.http.setCookie('http://httpbin.org/get', 'mySecondCookie=mySecondValue');
|
||||
|
||||
cordova.plugin.http.downloadFile(sourceUrl, {}, {}, targetPath, function(entry) {
|
||||
helpers.getWithXhr(function(content) {
|
||||
resolve({
|
||||
sourceUrl: sourceUrl,
|
||||
targetPath: targetPath,
|
||||
fullPath: entry.fullPath,
|
||||
name: entry.name,
|
||||
content: content
|
||||
});
|
||||
}, targetPath);
|
||||
}, reject);
|
||||
},
|
||||
validationFunc: function(driver, result) {
|
||||
result.type.should.be.equal('resolved');
|
||||
result.data.name.should.be.equal('cookies.json');
|
||||
result.data.content.should.be.a('string');
|
||||
|
||||
var cookies = JSON.parse(result.data.content).cookies;
|
||||
|
||||
cookies.myCookie.should.be.equal('myValue');
|
||||
cookies.mySecondCookie.should.be.equal('mySecondValue');
|
||||
}
|
||||
},{
|
||||
description: 'should send UTF-8 encoded raw string correctly (POST) #34',
|
||||
expected: 'resolved: {"status": 200, "data": "{\\"data\\": \\"this is a test string\\"...',
|
||||
before: helpers.setUtf8StringSerializer,
|
||||
func: function(resolve, reject) {
|
||||
cordova.plugin.http.post('http://httpbin.org/anything', 'this is a test string', {}, resolve, reject);
|
||||
},
|
||||
validationFunc: function(driver, result) {
|
||||
result.type.should.be.equal('resolved');
|
||||
JSON.parse(result.data.data).data.should.be.equal('this is a test string');
|
||||
}
|
||||
},{
|
||||
description: 'should encode spaces in query string (params object) correctly (GET) #71',
|
||||
expected: 'resolved: {"status": 200, "data": "{\\"args\\": \\"query param\\": \\"and value with spaces\\"...',
|
||||
func: function(resolve, reject) {
|
||||
cordova.plugin.http.get('http://httpbin.org/get', { 'query param': 'and value with spaces' }, {}, resolve, reject);
|
||||
},
|
||||
validationFunc: function(driver, result) {
|
||||
result.type.should.be.equal('resolved');
|
||||
JSON.parse(result.data.data).args['query param'].should.be.equal('and value with spaces');
|
||||
}
|
||||
},{
|
||||
description: 'should decode latin1 (iso-8859-1) encoded body correctly (GET) #72',
|
||||
expected: 'resolved: {"status": 200, "data": "<!DOCTYPE HTML PUBLIC \\"-//W3C//DTD HTML 4.01 Transitional//EN\\"> ...',
|
||||
func: function(resolve, reject) {
|
||||
cordova.plugin.http.get('http://www.columbia.edu/kermit/latin1.html', {}, {}, resolve, reject);
|
||||
},
|
||||
validationFunc: function(driver, result) {
|
||||
result.type.should.be.equal('resolved');
|
||||
result.data.data.should.include('[¡] 161 10/01 241 A1 INVERTED EXCLAMATION MARK\n[¢] 162 10/02 242 A2 CENT SIGN');
|
||||
}
|
||||
},{
|
||||
description: 'should return empty body string correctly (GET)',
|
||||
expected: 'resolved: {"status": 200, "data": "" ...',
|
||||
func: function(resolve, reject) {
|
||||
cordova.plugin.http.get('http://httpbin.org/stream/0', {}, {}, resolve, reject);
|
||||
},
|
||||
validationFunc: function(driver, result) {
|
||||
result.type.should.be.equal('resolved');
|
||||
result.data.data.should.be.equal('');
|
||||
}
|
||||
},{
|
||||
description: 'should pin SSL cert correctly (GET)',
|
||||
expected: 'resolved: {"status": 200 ...',
|
||||
before: helpers.setPinnedCertMode,
|
||||
func: function(resolve, reject) {
|
||||
cordova.plugin.http.get('https://httpbin.org', {}, {}, resolve, reject);
|
||||
},
|
||||
validationFunc: function(driver, result) {
|
||||
result.type.should.be.equal('resolved');
|
||||
result.data.status.should.be.equal(200);
|
||||
}
|
||||
},{
|
||||
description: 'should reject when pinned cert does not match received server cert (GET)',
|
||||
expected: 'rejected: {"status": -1 ...',
|
||||
before: helpers.setPinnedCertMode,
|
||||
func: function(resolve, reject) {
|
||||
cordova.plugin.http.get('https://sha512.badssl.com/', {}, {}, resolve, reject);
|
||||
},
|
||||
validationFunc: function(driver, result, targetInfo) {
|
||||
result.type.should.be.equal('rejected');
|
||||
result.data.should.be.eql({ status: -1, error: targetInfo.isAndroid ? 'SSL handshake failed' : 'cancelled' });
|
||||
}
|
||||
},{
|
||||
description: 'should send deeply structured JSON object correctly (POST) #65',
|
||||
expected: 'resolved: {"status": 200, "data": "{\\"data\\": \\"{\\\\"outerObj\\\\":{\\\\"innerStr\\\\":\\\\"testString\\\\",\\\\"innerArr\\\\":[1,2,3]}}\\" ...',
|
||||
before: helpers.setJsonSerializer,
|
||||
func: function(resolve, reject) { cordova.plugin.http.post('http://httpbin.org/anything', { outerObj: { innerStr: 'testString', innerArr: [1, 2, 3] }}, {}, resolve, reject); },
|
||||
validationFunc: function(driver, result) {
|
||||
result.type.should.be.equal('resolved');
|
||||
JSON.parse(result.data.data).json.should.eql({ outerObj: { innerStr: 'testString', innerArr: [1, 2, 3] }});
|
||||
}
|
||||
},{
|
||||
description: 'should override header "content-type" correctly (POST) #78',
|
||||
expected: 'resolved: {"status": 200, "headers": "{\\"Content-Type\\": \\"text/plain\\" ...',
|
||||
before: helpers.setJsonSerializer,
|
||||
func: function(resolve, reject) { cordova.plugin.http.post('http://httpbin.org/anything', {}, { 'Content-Type': 'text/plain' }, resolve, reject); },
|
||||
validationFunc: function(driver, result) {
|
||||
result.type.should.be.equal('resolved');
|
||||
JSON.parse(result.data.data).headers['Content-Type'].should.be.equal('text/plain');
|
||||
}
|
||||
},{
|
||||
description: 'should handle error during file download correctly (DOWNLOAD) #83',
|
||||
expected: 'rejected: {"status": 403, "error": "There was an error downloading the file" ...',
|
||||
func: function(resolve, reject) { cordova.plugin.http.downloadFile('http://httpbin.org/status/403', {}, {}, cordova.file.tempDirectory + 'testfile.txt', resolve, reject); },
|
||||
validationFunc: function(driver, result) {
|
||||
result.type.should.be.equal('rejected');
|
||||
result.data.status.should.be.equal(403);
|
||||
result.data.error.should.be.equal('There was an error downloading the file');
|
||||
}
|
||||
},{
|
||||
description: 'should handle gzip encoded response correctly',
|
||||
expected: 'resolved: {"status": 200, "headers": "{\\"Content-Encoding\\": \\"gzip\\" ...',
|
||||
func: function(resolve, reject) { cordova.plugin.http.get('http://httpbin.org/gzip', {}, {}, resolve, reject); },
|
||||
validationFunc: function(driver, result) {
|
||||
result.type.should.be.equal('resolved');
|
||||
result.data.status.should.be.equal(200);
|
||||
JSON.parse(result.data.data).gzipped.should.be.equal(true);
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
|
||||
@@ -3,12 +3,18 @@ const mock = require('mock-require');
|
||||
const path = require('path');
|
||||
|
||||
const should = chai.should();
|
||||
|
||||
const HELPERS_ID = path.resolve(__dirname, '..', 'www', 'helpers');
|
||||
const PLUGIN_ID = path.resolve(__dirname, '..', 'www', 'advanced-http');
|
||||
|
||||
describe('Advanced HTTP www interface', function() {
|
||||
let http = {};
|
||||
let helpers = {};
|
||||
|
||||
const noop = () => { /* intentionally doing nothing */ };
|
||||
|
||||
const loadHttp = () => {
|
||||
mock(`${PLUGIN_ID}.helpers`, mock.reRequire('../www/helpers'));
|
||||
http = mock.reRequire('../www/advanced-http');
|
||||
};
|
||||
|
||||
@@ -19,28 +25,30 @@ describe('Advanced HTTP www interface', function() {
|
||||
global.btoa = decoded => new Buffer(decoded).toString('base64');
|
||||
|
||||
mock('cordova/exec', noop);
|
||||
mock(`${PLUGIN_ID}.angular-integration`, { registerService: noop });
|
||||
mock(`${PLUGIN_ID}.cookie-handler`, {});
|
||||
mock(`${HELPERS_ID}.cookie-handler`, {});
|
||||
mock(`${HELPERS_ID}.messages`, require('../www/messages'));
|
||||
|
||||
loadHttp();
|
||||
});
|
||||
|
||||
it('sets global headers correctly with two args (old interface)', () => {
|
||||
http.setHeader('myKey', 'myValue');
|
||||
http.headers['*'].myKey.should.equal('myValue');
|
||||
http.getHeaders('*').myKey.should.equal('myValue');
|
||||
});
|
||||
|
||||
it('sets global headers correctly with three args (new interface)', () => {
|
||||
it('sets global headers correctly with three args (new interface) #24', () => {
|
||||
http.setHeader('*', 'myKey', 'myValue');
|
||||
http.headers['*'].myKey.should.equal('myValue');
|
||||
http.getHeaders('*').myKey.should.equal('myValue');
|
||||
});
|
||||
|
||||
it('sets host headers correctly', () => {
|
||||
it('sets host headers correctly #24', () => {
|
||||
http.setHeader('www.google.de', 'myKey', 'myValue');
|
||||
http.headers['www.google.de'].myKey.should.equal('myValue');
|
||||
http.getHeaders('www.google.de').myKey.should.equal('myValue');
|
||||
});
|
||||
|
||||
it('resolves global headers correctly', () => {
|
||||
mock(`${PLUGIN_ID}.cookie-handler`, {
|
||||
it('resolves global headers correctly #24', () => {
|
||||
mock(`${HELPERS_ID}.cookie-handler`, {
|
||||
getCookieString: () => 'fakeCookieString'
|
||||
});
|
||||
|
||||
@@ -58,8 +66,8 @@ describe('Advanced HTTP www interface', function() {
|
||||
http.get('url', {}, {}, noop, noop);
|
||||
});
|
||||
|
||||
it('resolves host headers correctly (set without port number)', () => {
|
||||
mock(`${PLUGIN_ID}.cookie-handler`, {
|
||||
it('resolves host headers correctly (set without port number) #37', () => {
|
||||
mock(`${HELPERS_ID}.cookie-handler`, {
|
||||
getCookieString: () => 'fakeCookieString'
|
||||
});
|
||||
|
||||
@@ -77,8 +85,8 @@ describe('Advanced HTTP www interface', function() {
|
||||
http.get('https://www.google.de/?gws_rd=ssl', {}, {}, noop, noop);
|
||||
});
|
||||
|
||||
it('resolves host headers correctly (set with port number)', () => {
|
||||
mock(`${PLUGIN_ID}.cookie-handler`, {
|
||||
it('resolves host headers correctly (set with port number) #37', () => {
|
||||
mock(`${HELPERS_ID}.cookie-handler`, {
|
||||
getCookieString: () => 'fakeCookieString'
|
||||
});
|
||||
|
||||
@@ -97,7 +105,7 @@ describe('Advanced HTTP www interface', function() {
|
||||
});
|
||||
|
||||
it('resolves request headers correctly', () => {
|
||||
mock(`${PLUGIN_ID}.cookie-handler`, {
|
||||
mock(`${HELPERS_ID}.cookie-handler`, {
|
||||
getCookieString: () => 'fakeCookieString'
|
||||
});
|
||||
|
||||
@@ -114,8 +122,12 @@ describe('Advanced HTTP www interface', function() {
|
||||
http.get('https://www.google.de/?gws_rd=ssl', {}, { myKey: 'myValue' }, noop, noop);
|
||||
});
|
||||
|
||||
it('sets basic authentication header correctly', () => {
|
||||
it('sets basic authentication header correctly #36', () => {
|
||||
http.useBasicAuth('name', 'pass');
|
||||
http.headers['*'].Authorization.should.equal('Basic bmFtZTpwYXNz');
|
||||
http.getHeaders('*').Authorization.should.equal('Basic bmFtZTpwYXNz');
|
||||
});
|
||||
|
||||
it('throws an Error when you try to add a cookie by using "setHeader" #46', () => {
|
||||
(function() { http.setHeader('*', 'cookie', 'value') }).should.throw();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,288 +1,125 @@
|
||||
/*global angular*/
|
||||
|
||||
/*
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* Modified by Andrew Stephan for Sync OnSet
|
||||
* Modified by Sefa Ilkimen:
|
||||
* - added configurable params serializer
|
||||
* - added put and delete methods
|
||||
* - using cordova www module pattern
|
||||
* - some minor improvements
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* An HTTP Plugin for PhoneGap.
|
||||
* A native HTTP Plugin for Cordova / PhoneGap.
|
||||
*/
|
||||
|
||||
var pluginId = module.id.slice(0, module.id.indexOf('.'));
|
||||
var validSerializers = ['urlencoded', 'json'];
|
||||
var pluginId = module.id.slice(0, module.id.lastIndexOf('.'));
|
||||
|
||||
var exec = require('cordova/exec');
|
||||
var angularIntegration = require(pluginId +'.angular-integration');
|
||||
var cookieHandler = require(pluginId + '.cookie-handler');
|
||||
var helpers = require(pluginId + '.helpers');
|
||||
|
||||
// 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 checkSerializer(serializer) {
|
||||
serializer = serializer || '';
|
||||
serializer = serializer.trim().toLowerCase();
|
||||
|
||||
if (validSerializers.indexOf(serializer) > -1) {
|
||||
return serializer;
|
||||
}
|
||||
|
||||
return serializer[0];
|
||||
}
|
||||
|
||||
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 == window.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 injectFileEntryHandler(cb) {
|
||||
return function(response) {
|
||||
cb(createFileEntry(response.file));
|
||||
}
|
||||
}
|
||||
|
||||
function getCookieHeader(url) {
|
||||
return { Cookie: cookieHandler.getCookieString(url) };
|
||||
}
|
||||
|
||||
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 handleMissingCallbacks(successFn, failFn) {
|
||||
if (Object.prototype.toString.call(successFn) !== '[object Function]') {
|
||||
throw new Error('advanced-http: missing mandatory "onSuccess" callback function');
|
||||
}
|
||||
|
||||
if (Object.prototype.toString.call(failFn) !== '[object Function]') {
|
||||
throw new Error('advanced-http: missing mandatory "onFail" callback function');
|
||||
}
|
||||
}
|
||||
|
||||
var http = {
|
||||
headers: {},
|
||||
dataSerializer: 'urlencoded',
|
||||
sslPinning: false,
|
||||
timeoutInSeconds: 60.0,
|
||||
getBasicAuthHeader: function (username, password) {
|
||||
return {'Authorization': 'Basic ' + b64EncodeUnicode(username + ':' + password)};
|
||||
},
|
||||
useBasicAuth: function (username, password) {
|
||||
this.setHeader('*', 'Authorization', 'Basic ' + b64EncodeUnicode(username + ':' + password));
|
||||
},
|
||||
setHeader: function () {
|
||||
// this one is for being backward compatible
|
||||
var host = '*';
|
||||
var header = arguments[0];
|
||||
var value = arguments[1];
|
||||
|
||||
if (arguments.length === 3) {
|
||||
host = arguments[0];
|
||||
header = arguments[1];
|
||||
value = arguments[2];
|
||||
}
|
||||
|
||||
this.headers[host] = this.headers[host] || {};
|
||||
this.headers[host][header] = value;
|
||||
},
|
||||
setDataSerializer: function (serializer) {
|
||||
this.dataSerializer = checkSerializer(serializer);
|
||||
},
|
||||
clearCookies: function () {
|
||||
return cookieHandler.clearCookies();
|
||||
},
|
||||
removeCookies: function (url, callback) {
|
||||
cookieHandler.removeCookies(url, callback);
|
||||
},
|
||||
setRequestTimeout: function(timeout) {
|
||||
this.timeoutInSeconds = timeout;
|
||||
},
|
||||
enableSSLPinning: function (enable, success, failure) {
|
||||
return exec(success, failure, 'CordovaHttpPlugin', 'enableSSLPinning', [enable]);
|
||||
},
|
||||
acceptAllCerts: function (allow, success, failure) {
|
||||
return exec(success, failure, 'CordovaHttpPlugin', 'acceptAllCerts', [allow]);
|
||||
},
|
||||
disableRedirect: function(disable, success, failure) {
|
||||
return exec(success, failure, 'CordovaHttpPlugin', 'disableRedirect', [disable]);
|
||||
},
|
||||
validateDomainName: function (validate, success, failure) {
|
||||
failure('advanced-http: "validateDomainName" is no more supported, please see change log for further info');
|
||||
},
|
||||
post: function (url, data, headers, success, failure) {
|
||||
handleMissingCallbacks(success, failure);
|
||||
|
||||
data = data || {};
|
||||
headers = getMergedHeaders(url, headers, this.headers);
|
||||
|
||||
var onSuccess = injectCookieHandler(url, success);
|
||||
var onFail = injectCookieHandler(url, failure);
|
||||
|
||||
return exec(onSuccess, onFail, 'CordovaHttpPlugin', 'post', [url, data, this.dataSerializer, headers, this.timeoutInSeconds]);
|
||||
},
|
||||
get: function (url, params, headers, success, failure) {
|
||||
handleMissingCallbacks(success, failure);
|
||||
|
||||
params = params || {};
|
||||
headers = getMergedHeaders(url, headers, this.headers);
|
||||
|
||||
var onSuccess = injectCookieHandler(url, success);
|
||||
var onFail = injectCookieHandler(url, failure);
|
||||
|
||||
return exec(onSuccess, onFail, 'CordovaHttpPlugin', 'get', [url, params, headers, this.timeoutInSeconds]);
|
||||
},
|
||||
put: function (url, data, headers, success, failure) {
|
||||
handleMissingCallbacks(success, failure);
|
||||
|
||||
data = data || {};
|
||||
headers = getMergedHeaders(url, headers, this.headers);
|
||||
|
||||
var onSuccess = injectCookieHandler(url, success);
|
||||
var onFail = injectCookieHandler(url, failure);
|
||||
|
||||
return exec(onSuccess, onFail, 'CordovaHttpPlugin', 'put', [url, data, this.dataSerializer, headers, this.timeoutInSeconds]);
|
||||
},
|
||||
|
||||
patch: function (url, data, headers, success, failure) {
|
||||
handleMissingCallbacks(success, failure);
|
||||
|
||||
data = data || {};
|
||||
headers = getMergedHeaders(url, headers, this.headers);
|
||||
|
||||
var onSuccess = injectCookieHandler(url, success);
|
||||
var onFail = injectCookieHandler(url, failure);
|
||||
|
||||
return exec(onSuccess, onFail, 'CordovaHttpPlugin', 'patch', [url, data, this.dataSerializer, headers, this.timeoutInSeconds]);
|
||||
},
|
||||
|
||||
delete: function (url, params, headers, success, failure) {
|
||||
handleMissingCallbacks(success, failure);
|
||||
|
||||
params = params || {};
|
||||
headers = getMergedHeaders(url, headers, this.headers);
|
||||
|
||||
var onSuccess = injectCookieHandler(url, success);
|
||||
var onFail = injectCookieHandler(url, failure);
|
||||
|
||||
return exec(onSuccess, onFail, 'CordovaHttpPlugin', 'delete', [url, params, headers, this.timeoutInSeconds]);
|
||||
},
|
||||
head: function (url, params, headers, success, failure) {
|
||||
handleMissingCallbacks(success, failure);
|
||||
|
||||
params = params || {};
|
||||
headers = getMergedHeaders(url, headers, this.headers);
|
||||
|
||||
var onSuccess = injectCookieHandler(url, success);
|
||||
var onFail = injectCookieHandler(url, failure);
|
||||
|
||||
return exec(onSuccess, onFail, 'CordovaHttpPlugin', 'head', [url, params, headers, this.timeoutInSeconds]);
|
||||
},
|
||||
uploadFile: function (url, params, headers, filePath, name, success, failure) {
|
||||
handleMissingCallbacks(success, failure);
|
||||
|
||||
params = params || {};
|
||||
headers = getMergedHeaders(url, headers, this.headers);
|
||||
|
||||
var onSuccess = injectCookieHandler(url, success);
|
||||
var onFail = injectCookieHandler(url, failure);
|
||||
|
||||
return exec(onSuccess, onFail, 'CordovaHttpPlugin', 'uploadFile', [url, params, headers, filePath, name, this.timeoutInSeconds]);
|
||||
},
|
||||
downloadFile: function (url, params, headers, filePath, success, failure) {
|
||||
handleMissingCallbacks(success, failure);
|
||||
|
||||
params = params || {};
|
||||
headers = getMergedHeaders(url, headers, this.headers);
|
||||
|
||||
var onSuccess = injectCookieHandler(url, injectFileEntryHandler(success));
|
||||
var onFail = injectCookieHandler(url, failure);
|
||||
|
||||
return exec(onSuccess, onFail, 'CordovaHttpPlugin', 'downloadFile', [url, params, headers, filePath, this.timeoutInSeconds]);
|
||||
}
|
||||
var globalConfigs = {
|
||||
headers: {},
|
||||
serializer: 'urlencoded',
|
||||
timeout: 60.0,
|
||||
};
|
||||
|
||||
angularIntegration.registerService(http);
|
||||
module.exports = http;
|
||||
var publicInterface = {
|
||||
getBasicAuthHeader: function (username, password) {
|
||||
return {'Authorization': 'Basic ' + helpers.b64EncodeUnicode(username + ':' + password)};
|
||||
},
|
||||
useBasicAuth: function (username, password) {
|
||||
this.setHeader('*', 'Authorization', 'Basic ' + helpers.b64EncodeUnicode(username + ':' + password));
|
||||
},
|
||||
getHeaders: function (host) {
|
||||
return globalConfigs.headers[host || '*'] || null;
|
||||
},
|
||||
setHeader: function () {
|
||||
// this one is for being backward compatible
|
||||
var host = '*';
|
||||
var header = arguments[0];
|
||||
var value = arguments[1];
|
||||
|
||||
if (arguments.length === 3) {
|
||||
host = arguments[0];
|
||||
header = arguments[1];
|
||||
value = arguments[2];
|
||||
}
|
||||
|
||||
helpers.checkForBlacklistedHeaderKey(header);
|
||||
helpers.checkForInvalidHeaderValue(value);
|
||||
|
||||
globalConfigs.headers[host] = globalConfigs.headers[host] || {};
|
||||
globalConfigs.headers[host][header] = value;
|
||||
},
|
||||
getDataSerializer: function () {
|
||||
return globalConfigs.serializer;
|
||||
},
|
||||
setDataSerializer: function (serializer) {
|
||||
globalConfigs.serializer = helpers.checkSerializer(serializer);
|
||||
},
|
||||
setCookie: function (url, cookie, options) {
|
||||
cookieHandler.setCookie(url, cookie, options);
|
||||
},
|
||||
clearCookies: function () {
|
||||
cookieHandler.clearCookies();
|
||||
},
|
||||
removeCookies: function (url, callback) {
|
||||
cookieHandler.removeCookies(url, callback);
|
||||
},
|
||||
getCookieString: function (url) {
|
||||
return cookieHandler.getCookieString(url);
|
||||
},
|
||||
getRequestTimeout: function () {
|
||||
return globalConfigs.timeout;
|
||||
},
|
||||
setRequestTimeout: function (timeout) {
|
||||
globalConfigs.timeout = timeout;
|
||||
},
|
||||
setSSLCertMode: function (mode, success, failure) {
|
||||
return exec(success, failure, 'CordovaHttpPlugin', 'setSSLCertMode', [ helpers.checkSSLCertMode(mode) ]);
|
||||
},
|
||||
disableRedirect: function (disable, success, failure) {
|
||||
return exec(success, failure, 'CordovaHttpPlugin', 'disableRedirect', [ !!disable ]);
|
||||
},
|
||||
sendRequest: function (url, options, success, failure) {
|
||||
helpers.handleMissingCallbacks(success, failure);
|
||||
|
||||
options = helpers.handleMissingOptions(options, globalConfigs);
|
||||
|
||||
var headers = helpers.getMergedHeaders(url, options.headers, globalConfigs.headers);
|
||||
var onSuccess = helpers.injectCookieHandler(url, success);
|
||||
var onFail = helpers.injectCookieHandler(url, failure);
|
||||
|
||||
switch(options.method) {
|
||||
case 'post':
|
||||
case 'put':
|
||||
case 'patch':
|
||||
var data = helpers.getProcessedData(options.data, options.serializer);
|
||||
return exec(onSuccess, onFail, 'CordovaHttpPlugin', options.method, [ url, data, options.serializer, headers, options.timeout ]);
|
||||
case 'upload':
|
||||
return exec(onSuccess, onFail, 'CordovaHttpPlugin', 'uploadFile', [ url, options.params, headers, options.filePath, options.name, options.timeout ]);
|
||||
case 'download':
|
||||
var onDownloadSuccess = helpers.injectCookieHandler(url, helpers.injectFileEntryHandler(success));
|
||||
return exec(onDownloadSuccess, onFail, 'CordovaHttpPlugin', 'downloadFile', [ url, options.params, headers, options.filePath, options.timeout ]);
|
||||
default:
|
||||
return exec(onSuccess, onFail, 'CordovaHttpPlugin', options.method, [ url, options.params, headers, options.timeout ]);
|
||||
}
|
||||
},
|
||||
post: function (url, data, headers, success, failure) {
|
||||
return publicInterface.sendRequest(url, { method: 'post', data: data, headers: headers }, success, failure);
|
||||
},
|
||||
get: function (url, params, headers, success, failure) {
|
||||
return publicInterface.sendRequest(url, { method: 'get', params: params, headers: headers }, success, failure);
|
||||
},
|
||||
put: function (url, data, headers, success, failure) {
|
||||
return publicInterface.sendRequest(url, { method: 'put', data: data, headers: headers }, success, failure);
|
||||
},
|
||||
patch: function (url, data, headers, success, failure) {
|
||||
return publicInterface.sendRequest(url, { method: 'patch', data: data, headers: headers }, success, failure);
|
||||
},
|
||||
delete: function (url, params, headers, success, failure) {
|
||||
return publicInterface.sendRequest(url, { method: 'delete', params: params, headers: headers }, success, failure);
|
||||
},
|
||||
head: function (url, params, headers, success, failure) {
|
||||
return publicInterface.sendRequest(url, { method: 'head', params: params, headers: headers }, success, failure);
|
||||
},
|
||||
uploadFile: function (url, params, headers, filePath, name, success, failure) {
|
||||
return publicInterface.sendRequest(url, { method: 'upload', params: params, headers: headers, filePath: filePath, name: name }, success, failure);
|
||||
},
|
||||
downloadFile: function (url, params, headers, filePath, success, failure) {
|
||||
return publicInterface.sendRequest(url, { method: 'download', params: params, headers: headers, filePath: filePath }, success, failure);
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = publicInterface;
|
||||
|
||||
96
www/angular-integration.js
vendored
96
www/angular-integration.js
vendored
@@ -1,96 +0,0 @@
|
||||
function registerService(http) {
|
||||
if (typeof angular === 'undefined') return;
|
||||
|
||||
angular.module('cordovaHTTP', []).factory('cordovaHTTP', function ($timeout, $q) {
|
||||
function makePromise(fn, args, async) {
|
||||
var deferred = $q.defer();
|
||||
|
||||
var success = function (response) {
|
||||
if (async) {
|
||||
$timeout(function () {
|
||||
deferred.resolve(response);
|
||||
});
|
||||
} else {
|
||||
deferred.resolve(response);
|
||||
}
|
||||
};
|
||||
|
||||
var fail = function (response) {
|
||||
if (async) {
|
||||
$timeout(function () {
|
||||
deferred.reject(response);
|
||||
});
|
||||
} else {
|
||||
deferred.reject(response);
|
||||
}
|
||||
};
|
||||
|
||||
args.push(success);
|
||||
args.push(fail);
|
||||
|
||||
fn.apply(http, args);
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
var cordovaHTTP = {
|
||||
getBasicAuthHeader: http.getBasicAuthHeader,
|
||||
useBasicAuth: function (username, password) {
|
||||
return http.useBasicAuth(username, password);
|
||||
},
|
||||
setHeader: function (host, header, value) {
|
||||
return http.setHeader(host, header, value);
|
||||
},
|
||||
setDataSerializer: function (serializer) {
|
||||
return http.setDataSerializer(serializer);
|
||||
},
|
||||
clearCookies: function () {
|
||||
return http.clearCookies();
|
||||
},
|
||||
removeCookies: function (url) {
|
||||
return http.removeCookies(url);
|
||||
},
|
||||
setRequestTimeout: function (timeout) {
|
||||
return http.setRequestTimeout(timeout);
|
||||
},
|
||||
enableSSLPinning: function (enable) {
|
||||
return makePromise(http.enableSSLPinning, [enable]);
|
||||
},
|
||||
acceptAllCerts: function (allow) {
|
||||
return makePromise(http.acceptAllCerts, [allow]);
|
||||
},
|
||||
disableRedirect: function(disable) {
|
||||
return makePromise(http.disableRedirect, [disable]);
|
||||
},
|
||||
validateDomainName: function (validate) {
|
||||
return makePromise(http.validateDomainName, [validate]);
|
||||
},
|
||||
post: function (url, data, headers) {
|
||||
return makePromise(http.post, [url, data, headers], true);
|
||||
},
|
||||
get: function (url, params, headers) {
|
||||
return makePromise(http.get, [url, params, headers], true);
|
||||
},
|
||||
put: function (url, data, headers) {
|
||||
return makePromise(http.put, [url, data, headers], true);
|
||||
},
|
||||
delete: function (url, params, headers) {
|
||||
return makePromise(http.delete, [url, params, headers], true);
|
||||
},
|
||||
head: function (url, params, headers) {
|
||||
return makePromise(http.head, [url, params, headers], true);
|
||||
},
|
||||
uploadFile: function (url, params, headers, filePath, name) {
|
||||
return makePromise(http.uploadFile, [url, params, headers, filePath, name], true);
|
||||
},
|
||||
downloadFile: function (url, params, headers, filePath) {
|
||||
return makePromise(http.downloadFile, [url, params, headers, filePath], true);
|
||||
}
|
||||
};
|
||||
return cordovaHTTP;
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
registerService: registerService
|
||||
};
|
||||
@@ -1,4 +1,4 @@
|
||||
var pluginId = module.id.slice(0, module.id.indexOf('.'));
|
||||
var pluginId = module.id.slice(0, module.id.lastIndexOf('.'));
|
||||
var ToughCookie = require(pluginId + '.tough-cookie');
|
||||
var WebStorageCookieStore = require(pluginId + '.local-storage-store');
|
||||
|
||||
@@ -10,6 +10,7 @@ var cookieJar = new ToughCookie.CookieJar(store);
|
||||
|
||||
module.exports = {
|
||||
setCookieFromString: setCookieFromString,
|
||||
setCookie: setCookie,
|
||||
getCookieString: getCookieString,
|
||||
clearCookies: clearCookies,
|
||||
removeCookies: removeCookies
|
||||
@@ -45,6 +46,12 @@ function setCookieFromString(url, cookieStr) {
|
||||
}
|
||||
}
|
||||
|
||||
function setCookie(url, cookie, options) {
|
||||
options = options || {};
|
||||
options.ignoreError = false;
|
||||
cookieJar.setCookieSync(cookie, url, options);
|
||||
}
|
||||
|
||||
function getCookieString(url) {
|
||||
return cookieJar.getCookieStringSync(url);
|
||||
}
|
||||
|
||||
255
www/helpers.js
Normal file
255
www/helpers.js
Normal file
@@ -0,0 +1,255 @@
|
||||
var pluginId = module.id.slice(0, module.id.lastIndexOf('.'));
|
||||
var cookieHandler = require(pluginId + '.cookie-handler');
|
||||
var messages = require(pluginId + '.messages');
|
||||
|
||||
var validSerializers = [ 'urlencoded', 'json', 'utf8' ];
|
||||
var validCertModes = [ 'default', 'nocheck', 'pinned' ];
|
||||
var validHttpMethods = [ 'get', 'put', 'post', 'patch', 'head', 'delete', 'upload', 'download' ];
|
||||
|
||||
module.exports = {
|
||||
b64EncodeUnicode: b64EncodeUnicode,
|
||||
getTypeOf: getTypeOf,
|
||||
checkSerializer: checkSerializer,
|
||||
checkSSLCertMode: checkSSLCertMode,
|
||||
checkForBlacklistedHeaderKey: checkForBlacklistedHeaderKey,
|
||||
checkForInvalidHeaderValue: checkForInvalidHeaderValue,
|
||||
injectCookieHandler: injectCookieHandler,
|
||||
injectFileEntryHandler: injectFileEntryHandler,
|
||||
getMergedHeaders: getMergedHeaders,
|
||||
getProcessedData: getProcessedData,
|
||||
handleMissingCallbacks: handleMissingCallbacks,
|
||||
handleMissingOptions: handleMissingOptions
|
||||
};
|
||||
|
||||
// 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 (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 (getTypeOf(obj) !== 'Object') {
|
||||
throw new Error(onInvalidValueMessage);
|
||||
}
|
||||
|
||||
var keys = Object.keys(obj);
|
||||
|
||||
for (var i = 0; i < keys.length; i++) {
|
||||
if (allowedChildren.indexOf(getTypeOf(obj[keys[i]])) === -1) {
|
||||
throw new Error(onInvalidValueMessage);
|
||||
}
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
function checkHttpMethod(method) {
|
||||
return checkForValidStringValue(validHttpMethods, method, messages.INVALID_HTTP_METHOD);
|
||||
}
|
||||
|
||||
function checkSerializer(serializer) {
|
||||
return checkForValidStringValue(validSerializers, serializer, messages.INVALID_DATA_SERIALIZER);
|
||||
}
|
||||
|
||||
function checkSSLCertMode(mode) {
|
||||
return checkForValidStringValue(validCertModes, mode, messages.INVALID_SSL_CERT_MODE);
|
||||
}
|
||||
|
||||
function checkForBlacklistedHeaderKey(key) {
|
||||
if (key.toLowerCase() === 'cookie') {
|
||||
throw new Error(messages.ADDING_COOKIES_NOT_SUPPORTED);
|
||||
}
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
function checkForInvalidHeaderValue(value) {
|
||||
if (getTypeOf(value) !== 'String') {
|
||||
throw new Error(messages.INVALID_HEADERS_VALUE);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
function checkTimeoutValue(timeout) {
|
||||
if (getTypeOf(timeout) !== 'Number' || timeout < 0) {
|
||||
throw new Error(messages.INVALID_TIMEOUT_VALUE);
|
||||
}
|
||||
|
||||
return timeout;
|
||||
}
|
||||
|
||||
function checkHeadersObject(headers) {
|
||||
return checkKeyValuePairObject(headers, [ 'String' ], messages.INVALID_HEADERS_VALUE);
|
||||
}
|
||||
|
||||
function checkParamsObject(params) {
|
||||
return checkKeyValuePairObject(params, [ 'String', 'Array' ], messages.INVALID_PARAMS_VALUE);
|
||||
}
|
||||
|
||||
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 == window.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 injectFileEntryHandler(cb) {
|
||||
return function(response) {
|
||||
cb(createFileEntry(response.file));
|
||||
}
|
||||
}
|
||||
|
||||
function getCookieHeader(url) {
|
||||
return { Cookie: cookieHandler.getCookieString(url) };
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
// typeof is not working reliably in JS
|
||||
function getTypeOf(object) {
|
||||
switch (Object.prototype.toString.call(object)) {
|
||||
case '[object Array]':
|
||||
return 'Array';
|
||||
case '[object Boolean]':
|
||||
return 'Boolean';
|
||||
case '[object Function]':
|
||||
return 'Function';
|
||||
case '[object Null]':
|
||||
return 'Null';
|
||||
case '[object Number]':
|
||||
return 'Number';
|
||||
case '[object Object]':
|
||||
return 'Object';
|
||||
case '[object String]':
|
||||
return 'String';
|
||||
case '[object Undefined]':
|
||||
return 'Undefined';
|
||||
default:
|
||||
return 'Unknown';
|
||||
}
|
||||
}
|
||||
|
||||
function getAllowedDataTypes(dataSerializer) {
|
||||
switch (dataSerializer) {
|
||||
case 'utf8':
|
||||
return ['String'];
|
||||
case 'urlencoded':
|
||||
return ['Object'];
|
||||
default:
|
||||
return ['Array', 'Object'];
|
||||
}
|
||||
}
|
||||
|
||||
function getProcessedData(data, dataSerializer) {
|
||||
data = data || {};
|
||||
|
||||
var currentDataType = getTypeOf(data);
|
||||
var allowedDataTypes = getAllowedDataTypes(dataSerializer);
|
||||
|
||||
if (allowedDataTypes.indexOf(currentDataType) === -1) {
|
||||
throw new Error(messages.DATA_TYPE_MISMATCH + ' ' + allowedDataTypes.join(', '));
|
||||
}
|
||||
|
||||
if (dataSerializer === 'utf8') {
|
||||
data = { text: data };
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
function handleMissingCallbacks(successFn, failFn) {
|
||||
if (getTypeOf(successFn) !== 'Function') {
|
||||
throw new Error(messages.MANDATORY_SUCCESS);
|
||||
}
|
||||
|
||||
if (getTypeOf(failFn) !== 'Function') {
|
||||
throw new Error(messages.MANDATORY_FAIL);
|
||||
}
|
||||
}
|
||||
|
||||
function handleMissingOptions(options, globals) {
|
||||
options = options || {};
|
||||
|
||||
return {
|
||||
method: checkHttpMethod(options.method || validHttpMethods[0]),
|
||||
serializer: checkSerializer(options.serializer || globals.serializer),
|
||||
timeout: checkTimeoutValue(options.timeout || globals.timeout),
|
||||
headers: checkHeadersObject(options.headers || {}),
|
||||
params: checkParamsObject(options.params || {}),
|
||||
data: options.data || null,
|
||||
filePath: options.filePath || '',
|
||||
name: options.name || ''
|
||||
};
|
||||
}
|
||||
@@ -30,7 +30,7 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
var pluginId = module.id.slice(0, module.id.indexOf('.'));
|
||||
var pluginId = module.id.slice(0, module.id.lastIndexOf('.'));
|
||||
var ToughCookie = require(pluginId + '.tough-cookie');
|
||||
var _ = require(pluginId + '.lodash');
|
||||
|
||||
|
||||
12
www/messages.js
Normal file
12
www/messages.js
Normal file
@@ -0,0 +1,12 @@
|
||||
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:',
|
||||
MANDATORY_SUCCESS: 'advanced-http: missing mandatory "onSuccess" callback function',
|
||||
MANDATORY_FAIL: 'advanced-http: missing mandatory "onFail" callback function',
|
||||
INVALID_HTTP_METHOD: 'advanced-http: invalid HTTP method, supported methods are:',
|
||||
INVALID_DATA_SERIALIZER: 'advanced-http: invalid serializer, supported serializers are:',
|
||||
INVALID_SSL_CERT_MODE: 'advanced-http: invalid SSL cert mode, supported modes are:',
|
||||
INVALID_HEADERS_VALUE: 'advanced-http: header values must be strings',
|
||||
INVALID_TIMEOUT_VALUE: 'advanced-http: invalid timeout value, needs to be a positive numeric value',
|
||||
INVALID_PARAMS_VALUE: 'advanced-http: invalid params object, needs to be an object with strings'
|
||||
};
|
||||
Reference in New Issue
Block a user