mirror of
https://github.com/silkimen/cordova-plugin-advanced-http.git
synced 2026-07-26 00:00:14 +08:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
94126b9021 | ||
|
|
007d5c609f | ||
|
|
badf6dcdc2 | ||
|
|
c081060a9e | ||
|
|
2ce130133c | ||
|
|
cfcc572ca0 | ||
|
|
d7688b485d | ||
|
|
81ba667e37 | ||
|
|
5ad1967b46 | ||
|
|
90ed474b29 | ||
|
|
1947906c4c | ||
|
|
b25b07a2a7 | ||
|
|
a01625ecfb | ||
|
|
b03ae7d6d1 | ||
|
|
fdaea418be | ||
|
|
d84df0fb00 | ||
|
|
baedd60329 | ||
|
|
80b22d4202 | ||
|
|
89ac260ef6 | ||
|
|
6a266218fb | ||
|
|
6050830423 | ||
|
|
95c9eb85d0 | ||
|
|
7e3ff25195 | ||
|
|
8a6b9e583e | ||
|
|
b32dfc7143 | ||
|
|
a72bf758c6 | ||
|
|
45f9cbfaa4 | ||
|
|
f8f52e1e97 | ||
|
|
9b995724f4 | ||
|
|
25a0a9a7ae | ||
|
|
e44def06a5 | ||
|
|
3d288951bf | ||
|
|
f39063cec9 | ||
|
|
1bcb8016ff | ||
|
|
6339b9b83d | ||
|
|
389534d661 | ||
|
|
c10722eca0 | ||
|
|
6a60058fc6 | ||
|
|
fcedfae1ac | ||
|
|
aca165b900 | ||
|
|
09c2b383ff | ||
|
|
6918a2ed15 | ||
|
|
5b827d500d | ||
|
|
1c27b62148 | ||
|
|
f33a911e7e | ||
|
|
097faad07a | ||
|
|
62c400c6db | ||
|
|
f823d24438 | ||
|
|
64a7148444 | ||
|
|
f6736d9150 | ||
|
|
bc90ae85fb | ||
|
|
389e860125 | ||
|
|
2367d264c1 | ||
|
|
269d5d4c8a | ||
|
|
b6ee4de379 | ||
|
|
5f327dc82a | ||
|
|
1639efe8d0 | ||
|
|
9bb0c58e35 | ||
|
|
57562a0dcf | ||
|
|
ad4079625e | ||
|
|
98d3d38e07 | ||
|
|
c748406090 | ||
|
|
dc6cf4d45b | ||
|
|
7661e02598 | ||
|
|
20ec4bee31 | ||
|
|
4eed89e530 | ||
|
|
f43b2f9f5c | ||
|
|
7b4d37acd9 | ||
|
|
ca5306cb47 | ||
|
|
c0c1af5ee6 | ||
|
|
42e629e34d | ||
|
|
3bec8dde5f | ||
|
|
8a3bc17810 | ||
|
|
1eb83478dc | ||
|
|
1f0df54111 | ||
|
|
ef09e466ec | ||
|
|
88de0550f4 | ||
|
|
7f680b07ec | ||
|
|
a259e7cf8d | ||
|
|
1e3c9e6645 | ||
|
|
e0cf458179 | ||
|
|
4f4e7ffa33 | ||
|
|
65e4a4d4dc | ||
|
|
fed2b03cc6 | ||
|
|
29e0b385de | ||
|
|
bfc6ba2008 | ||
|
|
060aa088f5 | ||
|
|
e775057389 | ||
|
|
81874c6bc8 | ||
|
|
658bbd8b28 | ||
|
|
a1e4be37d4 | ||
|
|
5be52d78d1 | ||
|
|
0a23e29403 | ||
|
|
6009ae82f7 | ||
|
|
0bfb81c57f | ||
|
|
f8f4bdc9df | ||
|
|
d84e3995d2 | ||
|
|
f5597dd176 | ||
|
|
b25b7db4be | ||
|
|
92be8f8e96 | ||
|
|
9ffdc5d2eb | ||
|
|
23a98ae491 | ||
|
|
ab9dad8f46 | ||
|
|
69344b5357 | ||
|
|
c88d1b6cc7 | ||
|
|
b6f369b868 | ||
|
|
39fa17e4ed | ||
|
|
5a19c6ad06 | ||
|
|
192059d34e | ||
|
|
7193b636f1 | ||
|
|
662b4352f5 | ||
|
|
e18f9eee51 | ||
|
|
c7eb60e670 | ||
|
|
6a930de82f | ||
|
|
588e4a0e57 | ||
|
|
78db1dc516 | ||
|
|
aded59e3d1 | ||
|
|
9ef582b37f | ||
|
|
33fea67603 | ||
|
|
faffe0e078 | ||
|
|
99c7f5d331 | ||
|
|
b74ad73742 | ||
|
|
7fd7ab223c | ||
|
|
937010bd4e | ||
|
|
7ab4b634ca | ||
|
|
32187a12fe | ||
|
|
a4f121728c | ||
|
|
21d991b04e | ||
|
|
31b1eee355 | ||
|
|
3d1b195831 | ||
|
|
014753e127 | ||
|
|
5ee26bc2cc | ||
|
|
7d7f02b4b3 | ||
|
|
afc9e3e944 | ||
|
|
9af2d1c21a | ||
|
|
9dce2fb964 | ||
|
|
eb946b49ab | ||
|
|
72ca81b515 | ||
|
|
68633f1bb8 | ||
|
|
ee26b78e0d | ||
|
|
d924f98844 | ||
|
|
8fceb4df97 | ||
|
|
7a09fa9460 | ||
|
|
3e5c941fdd | ||
|
|
0f273f401b | ||
|
|
684874184d | ||
|
|
19e1e7206b | ||
|
|
21bec76c11 | ||
|
|
594d03aa41 | ||
|
|
b3276ad2d4 | ||
|
|
3b4a5b7c26 | ||
|
|
867b8ea202 | ||
|
|
cc3e70771c | ||
|
|
9e892119cc | ||
|
|
f93f69e0aa | ||
|
|
4ace394464 | ||
|
|
ae3e821639 | ||
|
|
e17768041c | ||
|
|
34a559bc6e | ||
|
|
2ce1fc407d | ||
|
|
4b73c3762c | ||
|
|
5a9c176bca | ||
|
|
40aa944d0f | ||
|
|
c7feb7aca3 | ||
|
|
680105175b | ||
|
|
07811d0380 | ||
|
|
026e8589c2 | ||
|
|
e1592001af | ||
|
|
f057b126ba | ||
|
|
2b567cdf32 | ||
|
|
d99c7bb154 | ||
|
|
336a56be1c | ||
|
|
8b962cc350 | ||
|
|
13bf4666b0 | ||
|
|
1fc3d6230c | ||
|
|
85346e0381 | ||
|
|
c9f8c8b66a | ||
|
|
9b26a0f031 | ||
|
|
298c031433 | ||
|
|
eab6acf85c | ||
|
|
8cf0d21a7a | ||
|
|
f91727e14a | ||
|
|
7b485507dc | ||
|
|
03b0abb74e | ||
|
|
c3d60c37bf | ||
|
|
54ef8ae169 | ||
|
|
c83940a8f6 | ||
|
|
ccabbf2a29 | ||
|
|
7ba0852698 | ||
|
|
4f3ff9097f | ||
|
|
620ce3f81c | ||
|
|
6e68bf4dfe | ||
|
|
87f0f3600c |
@@ -0,0 +1 @@
|
|||||||
|
github: silkimen
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
---
|
||||||
|
name: "\U0001F41BBug report"
|
||||||
|
about: Create a report to help us improve
|
||||||
|
title: "[Bug] [platform] your issue title"
|
||||||
|
labels: ''
|
||||||
|
assignees: ''
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Describe the bug**
|
||||||
|
A clear and concise description of what the bug is and what you expected to happen.
|
||||||
|
|
||||||
|
**System info**
|
||||||
|
- affected HTTP plugin version: [e.g. 2.1.1]
|
||||||
|
- affected platform(s) and version(s): [e.g. iOS 12.2]
|
||||||
|
- affected device(s): [e.g. iPhone 8]
|
||||||
|
- cordova version: [e.g. 6.5.0]
|
||||||
|
- cordova platform version(s): [e.g. android 7.0.0, browser 5.0.3]
|
||||||
|
|
||||||
|
**Are you using ionic-native-wrapper?**
|
||||||
|
- ionic-native-wrapper version: [e.g. 5.8.0]
|
||||||
|
- did you check [ionic-native issue tracker](https://github.com/ionic-team/ionic-native/issues) for your problem?
|
||||||
|
|
||||||
|
**Minimum viable code to reproduce**
|
||||||
|
If applicable, add formatted sample coding to help explain your problem.
|
||||||
|
|
||||||
|
e.g.:
|
||||||
|
```js
|
||||||
|
cordova.plugin.http.setDataSerializer('urlencoded');
|
||||||
|
```
|
||||||
|
|
||||||
|
**Screenshots**
|
||||||
|
If applicable, add screenshots to help explain your problem.
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
---
|
||||||
|
name: "\U0001F680Feature request"
|
||||||
|
about: Suggest an idea for this project
|
||||||
|
title: "[Feature]"
|
||||||
|
labels: ''
|
||||||
|
assignees: ''
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Is your feature request related to a problem? Please describe.**
|
||||||
|
A clear and concise description of what the problem is. e.g. I'm always frustrated when [...]
|
||||||
|
|
||||||
|
**Describe the solution you'd like**
|
||||||
|
A clear and concise description of what you want to happen. If applicable, add formatted sample coding to help explain your idea.
|
||||||
|
|
||||||
|
```js
|
||||||
|
// do some fancy stuff here
|
||||||
|
```
|
||||||
|
|
||||||
|
**Describe alternatives you've considered**
|
||||||
|
A clear and concise description of any alternative solutions or features you've considered.
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
---
|
||||||
|
name: "\U0001F914Support question"
|
||||||
|
about: Ask the community
|
||||||
|
title: ''
|
||||||
|
labels: question
|
||||||
|
assignees: ''
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**You've got questions?**
|
||||||
|
|
||||||
|
We primarily use GitHub as an issue tracker; for usage and support questions, please check out these resources below. Thanks! 😁
|
||||||
|
|
||||||
|
* README.md: https://github.com/silkimen/cordova-plugin-advanced-http/blob/master/README.md
|
||||||
|
* StackOverflow: https://stackoverflow.com/questions/tagged/cordova-plugin-advanced-http using the tag `cordova-plugin-advanced-http`
|
||||||
|
* Wiki: https://github.com/silkimen/cordova-plugin-advanced-http/wiki
|
||||||
|
|
||||||
|
And don't forget: If you get help, help others. Good karma rulez!
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
name: Cordova HTTP Plugin CI
|
||||||
|
|
||||||
|
on: [push]
|
||||||
|
|
||||||
|
env:
|
||||||
|
nodejs: '10.x'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
test-www-interface:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v1
|
||||||
|
- name: Install Node.js ${{ env.nodejs }}
|
||||||
|
uses: actions/setup-node@v1
|
||||||
|
with:
|
||||||
|
node-version: ${{ env.nodejs }}
|
||||||
|
- name: Install node modules
|
||||||
|
run: npm ci
|
||||||
|
- name: Run WWW interface tests
|
||||||
|
run: npm run testjs
|
||||||
|
|
||||||
|
build-ios:
|
||||||
|
runs-on: macOS-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v1
|
||||||
|
- name: Install Node.js ${{ env.nodejs }}
|
||||||
|
uses: actions/setup-node@v1
|
||||||
|
with:
|
||||||
|
node-version: ${{ env.nodejs }}
|
||||||
|
- name: Install node modules
|
||||||
|
run: npm ci
|
||||||
|
- name: Update test cert for httpbin.org
|
||||||
|
run: npm run updatecert
|
||||||
|
- name: Build test app
|
||||||
|
run: scripts/build-test-app.sh --ios --emulator
|
||||||
|
|
||||||
|
build-android:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
env:
|
||||||
|
BROWSERSTACK_USERNAME: ${{ secrets.BROWSERSTACK_USERNAME }}
|
||||||
|
BROWSERSTACK_ACCESS_KEY: ${{ secrets.BROWSERSTACK_ACCESS_KEY }}
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v1
|
||||||
|
- name: Install Node.js ${{ env.nodejs }}
|
||||||
|
uses: actions/setup-node@v1
|
||||||
|
with:
|
||||||
|
node-version: ${{ env.nodejs }}
|
||||||
|
- name: Install node modules
|
||||||
|
run: npm ci
|
||||||
|
- name: Install JDK 1.8
|
||||||
|
uses: actions/setup-java@v1
|
||||||
|
with:
|
||||||
|
java-version: 1.8
|
||||||
|
- name: Update test cert for httpbin.org
|
||||||
|
run: npm run updatecert
|
||||||
|
- name: Add workaround for mipsel reference
|
||||||
|
run: sudo mkdir -p $ANDROID_HOME/ndk-bundle/toolchains/mips64el-linux-android-4.9/prebuilt/linux-x86_64
|
||||||
|
- name: Build test app
|
||||||
|
run: scripts/build-test-app.sh --android --device
|
||||||
|
- name: Upload artifact to BrowserStack
|
||||||
|
if: env.BROWSERSTACK_USERNAME != ''
|
||||||
|
run: scripts/upload-browserstack.sh --android
|
||||||
|
- name: Run e2e tests
|
||||||
|
if: env.BROWSERSTACK_USERNAME != ''
|
||||||
|
run: scripts/test-app.sh --android --device
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
# For most projects, this workflow file will not need changing; you simply need
|
||||||
|
# to commit it to your repository.
|
||||||
|
#
|
||||||
|
# You may wish to alter this file to override the set of languages analyzed,
|
||||||
|
# or to provide custom queries or build logic.
|
||||||
|
name: "CodeQL"
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [master]
|
||||||
|
pull_request:
|
||||||
|
# The branches below must be a subset of the branches above
|
||||||
|
branches: [master]
|
||||||
|
schedule:
|
||||||
|
- cron: '0 20 * * 3'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
analyze:
|
||||||
|
name: Analyze
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
# Override automatic language detection by changing the below list
|
||||||
|
# Supported options are ['csharp', 'cpp', 'go', 'java', 'javascript', 'python']
|
||||||
|
language: ['javascript']
|
||||||
|
# Learn more...
|
||||||
|
# https://docs.github.com/en/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#overriding-automatic-language-detection
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
|
# Initializes the CodeQL tools for scanning.
|
||||||
|
- name: Initialize CodeQL
|
||||||
|
uses: github/codeql-action/init@v1
|
||||||
|
with:
|
||||||
|
languages: ${{ matrix.language }}
|
||||||
|
# If you wish to specify custom queries, you can do so here or in a config file.
|
||||||
|
# By default, queries listed here will override any specified in a config file.
|
||||||
|
# Prefix the list here with "+" to use these queries and those in the config file.
|
||||||
|
# queries: ./path/to/local/query, your-org/your-repo/queries@main
|
||||||
|
|
||||||
|
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
||||||
|
# If this step fails, then you should remove it and run the build manually (see below)
|
||||||
|
- name: Autobuild
|
||||||
|
uses: github/codeql-action/autobuild@v1
|
||||||
|
|
||||||
|
# ℹ️ Command-line programs to run using the OS shell.
|
||||||
|
# 📚 https://git.io/JvXDl
|
||||||
|
|
||||||
|
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
|
||||||
|
# and modify them (or add more) to build your code if your project
|
||||||
|
# uses a compiled language
|
||||||
|
|
||||||
|
#- run: |
|
||||||
|
# make bootstrap
|
||||||
|
# make release
|
||||||
|
|
||||||
|
- name: Perform CodeQL Analysis
|
||||||
|
uses: github/codeql-action/analyze@v1
|
||||||
@@ -1,8 +1,11 @@
|
|||||||
node_modules/**
|
node_modules/**
|
||||||
test/e2e-app-template/www/certificates/*.cer
|
test/e2e-app-template/www/certificates/*.cer
|
||||||
|
test/e2e-app-template/www/certificates/*.pkcs
|
||||||
tags
|
tags
|
||||||
.zedstate
|
.zedstate
|
||||||
npm-debug.log
|
npm-debug.log
|
||||||
/temp
|
/temp
|
||||||
/android-sdk-macosx.zip
|
/android-sdk-macosx.zip
|
||||||
/android-sdk-macosx/**
|
/android-sdk-macosx/**
|
||||||
|
.idea/
|
||||||
|
*.iml
|
||||||
|
|||||||
+9
-10
@@ -1,7 +1,3 @@
|
|||||||
notifications:
|
|
||||||
slack:
|
|
||||||
secure: lXE+2AgsxZU5G5dI91LkMAIgo8MAWfdM7DB5UOtn5LpuNln+2FmJo1gOI7tkdmLOqpXTGYnpI2VyQN3H4nOF21YhuouzD1Sh8n2wtQg1iTm353kuQpqiVhSBX8ZJ7Be1e1G8OsnxoYOxbs4Zo9qI40EruwkvqLCBHWM5MRGyd4M7EFWwb9Z29VZN0y1Nt5g/c3bT76kdKmF+JCLur2OeEKxAity7sIKgZekSqeIMwEVLSxXnda6Dbjc/cg0MJ0iDArkD7iu6fz/Fcrrxgm/pUxjcgvqze7Gy5i31mjEfspnrglWV1cshMd48BTDKCJ2AMmxH8O3GPSWE2txjIvGRWUve7iViNylvmQCVz3Eyf99+4EuuVGa+5PSodQ/CqODx/65EwtcN3PE1tNz2puKOK8nrOJcFkcbG8KTHKUlQtHCkjitbykUnj/hvhLK5/oWlQYVOLWWrHwdGUh8FI8aFPVGjRjWbHbhdayjEIqxwr1ns+6mYrP1EFNXbaeZxnLNC59XpJl1ifuezqYAk7YEiU5j4rtC7YKgyQ3ueb7anOHTJoTMyDn8mpZXgwuyhoBaeEYytQVgRyMtL6Y5cP98Jn2kv0+vdne3rkk9/JEBTo32HOjvoij6rsqEvXC0LhUDJSNadOVdHht0jjoN6zBH37HIE5/3zysLlPcAcHAS83ow=
|
|
||||||
|
|
||||||
cache:
|
cache:
|
||||||
directories:
|
directories:
|
||||||
- node_modules
|
- node_modules
|
||||||
@@ -15,10 +11,11 @@ matrix:
|
|||||||
language: objective-c
|
language: objective-c
|
||||||
sudo: false
|
sudo: false
|
||||||
os: osx
|
os: osx
|
||||||
osx_image: xcode10.1
|
osx_image: xcode12.5
|
||||||
|
|
||||||
before_install:
|
before_install:
|
||||||
- export LANG=en_US.UTF-8
|
- export LANG=en_US.UTF-8 &&
|
||||||
|
nvm use 14
|
||||||
|
|
||||||
install:
|
install:
|
||||||
- npm install
|
- npm install
|
||||||
@@ -27,7 +24,7 @@ matrix:
|
|||||||
- npm run testjs &&
|
- npm run testjs &&
|
||||||
npm run updatecert &&
|
npm run updatecert &&
|
||||||
scripts/build-test-app.sh --ios --emulator &&
|
scripts/build-test-app.sh --ios --emulator &&
|
||||||
scripts/upload-artifact.sh --ios &&
|
scripts/upload-saucelabs.sh --ios &&
|
||||||
scripts/test-app.sh --ios --emulator;
|
scripts/test-app.sh --ios --emulator;
|
||||||
|
|
||||||
- name: "Android Build & Test"
|
- name: "Android Build & Test"
|
||||||
@@ -36,17 +33,19 @@ matrix:
|
|||||||
|
|
||||||
android:
|
android:
|
||||||
components:
|
components:
|
||||||
|
- tools
|
||||||
- platform-tools
|
- platform-tools
|
||||||
- build-tools-28.0.3
|
- build-tools-28.0.3
|
||||||
- android-27
|
- android-28
|
||||||
- extra-android-support
|
- extra-android-support
|
||||||
- extra-android-m2repository
|
- extra-android-m2repository
|
||||||
- extra-google-m2repository
|
- extra-google-m2repository
|
||||||
|
|
||||||
before_install:
|
before_install:
|
||||||
- export LANG=en_US.UTF-8 &&
|
- export LANG=en_US.UTF-8 &&
|
||||||
curl -sL https://deb.nodesource.com/setup_8.x | sudo -E bash - &&
|
curl -sL https://deb.nodesource.com/setup_14.x | sudo -E bash - &&
|
||||||
sudo apt-get install -y nodejs
|
sudo apt-get install -y nodejs
|
||||||
|
- yes | sdkmanager --update
|
||||||
|
|
||||||
install:
|
install:
|
||||||
- npm install
|
- npm install
|
||||||
@@ -55,5 +54,5 @@ matrix:
|
|||||||
- npm run testjs &&
|
- npm run testjs &&
|
||||||
npm run updatecert &&
|
npm run updatecert &&
|
||||||
scripts/build-test-app.sh --android --emulator &&
|
scripts/build-test-app.sh --android --emulator &&
|
||||||
scripts/upload-artifact.sh --android &&
|
scripts/upload-saucelabs.sh --android &&
|
||||||
scripts/test-app.sh --android --emulator;
|
scripts/test-app.sh --android --emulator;
|
||||||
|
|||||||
Vendored
+3
@@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"editor.tabSize": 2
|
||||||
|
}
|
||||||
@@ -1,5 +1,91 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## 3.1.1
|
||||||
|
|
||||||
|
- Fixed #372: malformed empty multipart request on Android
|
||||||
|
- Fixed #399: memory leakage leads to app crashes on iOS (thanks avargaskun)
|
||||||
|
|
||||||
|
## 3.1.0
|
||||||
|
|
||||||
|
- Feature #272: add support for aborting requests (thanks russaa)
|
||||||
|
|
||||||
|
## 3.0.1
|
||||||
|
|
||||||
|
- Fixed #359: memory leakage leads to app crashes on Android
|
||||||
|
- Fixed #355: responseType "json" not working with valid JSON response on browser (thanks millerg6711)
|
||||||
|
|
||||||
|
## 3.0.0
|
||||||
|
|
||||||
|
- Feature #158: support removing headers which were previously set via "setHeader"
|
||||||
|
|
||||||
|
- Fixed #345: empty file names are not handled correctly (thanks ikosta)
|
||||||
|
|
||||||
|
- :warning: **Breaking Change**: Dropped support for Android < 5.1
|
||||||
|
- :warning: **Breaking Change**: Removed "disableRedirect", use "setFollowRedirect" instead
|
||||||
|
- :warning: **Breaking Change**: Removed "setSSLCertMode", use "setServerTrustMode" instead
|
||||||
|
|
||||||
|
## 2.5.1
|
||||||
|
|
||||||
|
- Fixed #334: empty JSON response triggers error even though request is successful (thanks antikalk)
|
||||||
|
- Fixed #248: clearCookies() does not work on iOS
|
||||||
|
|
||||||
|
## 2.5.0
|
||||||
|
|
||||||
|
- Feature #56: add support for X.509 client certificate based authentication
|
||||||
|
|
||||||
|
## 2.4.1
|
||||||
|
|
||||||
|
- Fixed #296: multipart requests are not serialized on browser platform
|
||||||
|
- Fixed #301: data is not decoded correctly when responseType is "json" (thanks antikalk)
|
||||||
|
- Fixed #300: FormData object containing null or undefined value is not serialized correctly
|
||||||
|
|
||||||
|
## 2.4.0
|
||||||
|
|
||||||
|
- Feature #291: add support for sending 'raw' requests (thanks to jachstet-sea and chuchuva)
|
||||||
|
- Feature #155: add OPTIONS method
|
||||||
|
- Feature #283: improve error message on timeout on browser platform
|
||||||
|
|
||||||
|
## 2.3.1
|
||||||
|
|
||||||
|
- Fixed #275: getAllCookies() is broken because of a typo (thanks ath0mas)
|
||||||
|
|
||||||
|
## 2.3.0
|
||||||
|
|
||||||
|
- Feature #101: Support "multipart/form-data" requests (thanks SDA SE Open Industry Solutions)
|
||||||
|
|
||||||
|
#### Important information
|
||||||
|
This feature depends on several Web APIs. See https://github.com/silkimen/cordova-plugin-advanced-http/wiki/Web-APIs-required-for-Multipart-requests for more info.
|
||||||
|
|
||||||
|
## 2.2.0
|
||||||
|
|
||||||
|
- Feature #239: add enumeration style object for error codes
|
||||||
|
- Feature #253: add support for response type "json"
|
||||||
|
- Feature #127: add multiple file upload (thanks SDA SE Open Industry Solutions and nilswitschel)
|
||||||
|
|
||||||
|
## 2.1.1
|
||||||
|
|
||||||
|
- Fixed #224: response type "arraybuffer" and "blob" not working on browser platform
|
||||||
|
|
||||||
|
## 2.1.0
|
||||||
|
|
||||||
|
- Feature #216: Support for response type `arraybuffer`
|
||||||
|
- Feature #171: Support for response type `blob`
|
||||||
|
- Feature #205: Add preference for configuring OKHTTP version (thanks RougeCiel)
|
||||||
|
|
||||||
|
## 2.0.11
|
||||||
|
|
||||||
|
- Fixed #221: headers not set on Android when request fails due to non-success status code
|
||||||
|
|
||||||
|
## 2.0.10
|
||||||
|
|
||||||
|
- Fixed #218: headers are used as params on browser platform
|
||||||
|
|
||||||
|
## 2.0.9
|
||||||
|
|
||||||
|
- Fixed #204: broken support for cordova-android < 7.0
|
||||||
|
|
||||||
|
- :warning: **Deprecation**: Deprecated "disableRedirect" in favor of "setFollowRedirect"
|
||||||
|
|
||||||
## 2.0.8
|
## 2.0.8
|
||||||
|
|
||||||
- Fixed #198: cookie header is always passed even if there is no cookie
|
- Fixed #198: cookie header is always passed even if there is no cookie
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
The MIT License (MIT)
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (c) 2019 Sefa Ilkimen
|
||||||
Copyright (c) 2017 Mobisys GmbH
|
Copyright (c) 2017 Mobisys GmbH
|
||||||
Copyright (c) 2014 Wymsee, Inc
|
Copyright (c) 2014 Wymsee, Inc
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
Cordova Advanced HTTP
|
Cordova Advanced HTTP
|
||||||
=====================
|
=====================
|
||||||
[](https://badge.fury.io/js/cordova-plugin-advanced-http)
|
[](https://www.npmjs.com/package/cordova-plugin-advanced-http?activeTab=versions)
|
||||||
|
[](https://opensource.org/licenses/mit-license.php)
|
||||||
[](https://www.npmjs.com/package/cordova-plugin-advanced-http)
|
[](https://www.npmjs.com/package/cordova-plugin-advanced-http)
|
||||||
[](https://opensource.org/licenses/mit-license.php)
|
|
||||||
[](https://travis-ci.org/silkimen/cordova-plugin-advanced-http)
|
[](https://travis-ci.com/silkimen/cordova-plugin-advanced-http)
|
||||||
|
[](https://github.com/silkimen/cordova-plugin-advanced-http/actions)
|
||||||
|
|
||||||
|
|
||||||
Cordova / Phonegap plugin for communicating with HTTP servers. Supports iOS, Android and [Browser](#browserSupport).
|
Cordova / Phonegap plugin for communicating with HTTP servers. Supports iOS, Android and [Browser](#browserSupport).
|
||||||
@@ -12,9 +14,10 @@ This is a fork of [Wymsee's Cordova-HTTP plugin](https://github.com/wymsee/cordo
|
|||||||
|
|
||||||
## Advantages over Javascript requests
|
## Advantages over Javascript requests
|
||||||
|
|
||||||
- Background threading - all requests are done in a background thread.
|
- SSL / TLS Pinning
|
||||||
- Handling of HTTP code 401 - read more at [Issue CB-2415](https://issues.apache.org/jira/browse/CB-2415).
|
- CORS restrictions do not apply
|
||||||
- SSL Pinning - read more at [LumberBlog](http://blog.lumberlabs.com/2012/04/why-app-developers-should-care-about.html).
|
- X.509 client certificate based authentication
|
||||||
|
- Handling of HTTP code 401 - read more at [Issue CB-2415](https://issues.apache.org/jira/browse/CB-2415)
|
||||||
|
|
||||||
## Updates
|
## Updates
|
||||||
|
|
||||||
@@ -58,7 +61,7 @@ cordova.plugin.http.useBasicAuth('user', 'password');
|
|||||||
```
|
```
|
||||||
|
|
||||||
### setHeader<a name="setHeader"></a>
|
### 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).
|
Set a header for all future requests to a specified host. Takes a hostname, a header and a value (must be a string value or null).
|
||||||
|
|
||||||
```js
|
```js
|
||||||
cordova.plugin.http.setHeader('Hostname', 'Header', 'Value');
|
cordova.plugin.http.setHeader('Hostname', 'Header', 'Value');
|
||||||
@@ -89,21 +92,42 @@ cordova.plugin.http.setDataSerializer('urlencoded');
|
|||||||
```
|
```
|
||||||
|
|
||||||
You can choose one of these:
|
You can choose one of these:
|
||||||
* `urlencoded`: send data as url encoded content in body (content type "application/x-www-form-urlencoded")
|
* `urlencoded`: send data as url encoded content in body
|
||||||
* `json`: send data as JSON encoded content in body (content type "application/json")
|
* default content type "application/x-www-form-urlencoded"
|
||||||
* `utf8`: send data as plain UTF8 encoded string in body (content type "plain/text")
|
* data must be an dictionary style `Object`
|
||||||
|
* `json`: send data as JSON encoded content in body
|
||||||
|
* default content type "application/json"
|
||||||
|
* data must be an `Array` or an dictionary style `Object`
|
||||||
|
* `utf8`: send data as plain UTF8 encoded string in body
|
||||||
|
* default content type "plain/text"
|
||||||
|
* data must be a `String`
|
||||||
|
* `multipart`: send FormData objects as multipart content in body
|
||||||
|
* default content type "multipart/form-data"
|
||||||
|
* data must be an `FormData` instance
|
||||||
|
* `raw`: send data as is, without any processing
|
||||||
|
* default content type "application/octet-stream"
|
||||||
|
* data must be an `Uint8Array` or an `ArrayBuffer`
|
||||||
|
|
||||||
You can also override the default content type headers by specifying your own headers (see [setHeader](#setHeader)).
|
This defaults to `urlencoded`. 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.
|
:warning: `urlencoded` does not support serializing deep structures whereas `json` does.
|
||||||
|
|
||||||
|
:warning: `multipart` depends on several Web API standards which need to be supported in your web view. Check out https://github.com/silkimen/cordova-plugin-advanced-http/wiki/Web-APIs-required-for-Multipart-requests for more info.
|
||||||
|
|
||||||
### setRequestTimeout
|
### setRequestTimeout
|
||||||
Set how long to wait for a request to respond, in seconds.
|
Set the "read" timeout in seconds. This is the timeout interval to use when waiting for additional data.
|
||||||
|
|
||||||
```js
|
```js
|
||||||
cordova.plugin.http.setRequestTimeout(5.0);
|
cordova.plugin.http.setRequestTimeout(5.0);
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### setFollowRedirect<a name="setFollowRedirect"></a>
|
||||||
|
Configure if it should follow redirects automatically. This defaults to true.
|
||||||
|
|
||||||
|
```js
|
||||||
|
cordova.plugin.http.setFollowRedirect(true);
|
||||||
|
```
|
||||||
|
|
||||||
### getCookieString
|
### getCookieString
|
||||||
Returns saved cookies (as string) matching given URL.
|
Returns saved cookies (as string) matching given URL.
|
||||||
|
|
||||||
@@ -163,27 +187,27 @@ cordova.plugin.http.setServerTrustMode('nocheck', function() {
|
|||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
### setSSLCertMode (deprecated)
|
### setClientAuthMode<a name="setClientAuthMode"></a>
|
||||||
This function was deprecated in 2.0.8. Use ["setServerTrustMode"](#setServerTrustMode) instead.
|
Configure X.509 client certificate authentication. Takes mode and options. `mode` being one of following values:
|
||||||
|
|
||||||
### enableSSLPinning (obsolete)
|
* `none`: disable client certificate authentication
|
||||||
This function was removed in 2.0.0. Use ["setServerTrustMode"](#setServerTrustMode) to enable SSL pinning (mode "pinned").
|
* `systemstore` (only on Android): use client certificate installed in the Android system store; user will be presented with a list of all installed certificates
|
||||||
|
* `buffer`: use given client certificate; you will need to provide an options object:
|
||||||
### acceptAllCerts (obsolete)
|
* `rawPkcs`: ArrayBuffer containing raw PKCS12 container with client certificate and private key
|
||||||
This function was removed in 2.0.0. Use ["setServerTrustMode"](#setServerTrustMode) to disable checking certs (mode "nocheck").
|
* `pkcsPassword`: password of the PKCS container
|
||||||
|
|
||||||
### validateDomainName (obsolete)
|
|
||||||
This function was removed in v1.6.2. Domain name validation is disabled automatically when you set server trust mode to "nocheck".
|
|
||||||
|
|
||||||
### disableRedirect
|
|
||||||
If set to `true`, it won't follow redirects automatically. This defaults to false.
|
|
||||||
|
|
||||||
```js
|
```js
|
||||||
cordova.plugin.http.disableRedirect(true, function() {
|
// enable client auth using PKCS12 container given in ArrayBuffer `myPkcs12ArrayBuffer`
|
||||||
console.log('success!');
|
cordova.plugin.http.setClientAuthMode('buffer', {
|
||||||
}, function() {
|
rawPkcs: myPkcs12ArrayBuffer,
|
||||||
console.log('error :(');
|
pkcsPassword: 'mySecretPassword'
|
||||||
});
|
}, success, fail);
|
||||||
|
|
||||||
|
// enable client auth using certificate in system store (only on Android)
|
||||||
|
cordova.plugin.http.setClientAuthMode('systemstore', {}, success, fail);
|
||||||
|
|
||||||
|
// disable client auth
|
||||||
|
cordova.plugin.http.setClientAuthMode('none', {}, success, fail);
|
||||||
```
|
```
|
||||||
|
|
||||||
### removeCookies
|
### removeCookies
|
||||||
@@ -193,20 +217,28 @@ Remove all cookies associated with a given URL.
|
|||||||
cordova.plugin.http.removeCookies(url, callback);
|
cordova.plugin.http.removeCookies(url, callback);
|
||||||
```
|
```
|
||||||
|
|
||||||
### sendRequest
|
### sendRequest<a name="sendRequest"></a>
|
||||||
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.
|
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. Check the documentation of the respective shorthand function for details on what is returned on success and failure.
|
||||||
|
|
||||||
|
:warning: You need to encode the base URL yourself if it contains special characters like whitespaces. You can use `encodeURI()` for this purpose.
|
||||||
|
|
||||||
The options object contains following keys:
|
The options object contains following keys:
|
||||||
|
|
||||||
* `method`: HTTP method to be used, defaults to `get`, needs to be one of the following values:
|
* `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`
|
* `get`, `post`, `put`, `patch`, `head`, `delete`, `options`, `upload`, `download`
|
||||||
* `data`: payload to be send to the server (only applicable on `post`, `put` or `patch` methods)
|
* `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)
|
* `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
|
* `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
|
||||||
|
* `responseType`: expected response type, defaults to `text`, needs to be one of the following values:
|
||||||
|
* `text`: data is returned as decoded string, use this for all kinds of string responses (e.g. XML, HTML, plain text, etc.)
|
||||||
|
* `json` data is treated as JSON and returned as parsed object, returns `undefined` when response body is empty
|
||||||
|
* `arraybuffer`: data is returned as [ArrayBuffer instance](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer), returns `null` when response body is empty
|
||||||
|
* `blob`: data is returned as [Blob instance](https://developer.mozilla.org/en-US/docs/Web/API/Blob), returns `null` when response body is empty
|
||||||
* `timeout`: timeout value for the request in seconds, defaults to global timeout value
|
* `timeout`: timeout value for the request in seconds, defaults to global timeout value
|
||||||
|
* `followRedirect`: enable or disable automatically following redirects
|
||||||
* `headers`: headers object (key value pair), will be merged with global values
|
* `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
|
* `filePath`: file path(s) 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
|
* `name`: name(s) to be used during upload see [uploadFile](#uploadFile) for detailed information
|
||||||
|
|
||||||
Here's a quick example:
|
Here's a quick example:
|
||||||
|
|
||||||
@@ -232,6 +264,18 @@ cordova.plugin.http.sendRequest('https://google.com/', options, function(respons
|
|||||||
### post<a name="post"></a>
|
### post<a name="post"></a>
|
||||||
Execute a POST request. Takes a URL, data, and headers.
|
Execute a POST request. Takes a URL, data, and headers.
|
||||||
|
|
||||||
|
```js
|
||||||
|
cordova.plugin.http.post('https://google.com/', {
|
||||||
|
test: 'testString'
|
||||||
|
}, {
|
||||||
|
Authorization: 'OAuth2: token'
|
||||||
|
}, function(response) {
|
||||||
|
console.log(response.status);
|
||||||
|
}, function(response) {
|
||||||
|
console.error(response.error);
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
#### success
|
#### success
|
||||||
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.
|
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.
|
||||||
|
|
||||||
@@ -274,7 +318,7 @@ cordova.plugin.http.post('https://google.com/', {
|
|||||||
```
|
```
|
||||||
|
|
||||||
#### failure
|
#### failure
|
||||||
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.
|
The error function receives a response object with 4 properties: status, error, url, and headers (url and headers being optional). **status** is a HTTP response code or an internal error code. Positive values are HTTP status codes whereas negative values do represent internal error codes. **error** is the error response from the server as a string or an internal error message. **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:
|
Here's a quick example:
|
||||||
|
|
||||||
@@ -289,6 +333,8 @@ Here's a quick example:
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
:warning: An enumeration style object is exposed as `cordova.plugin.http.ErrorCode`. You can use it to check against internal error codes.
|
||||||
|
|
||||||
### get<a name="get"></a>
|
### 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.
|
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.
|
||||||
|
|
||||||
@@ -315,14 +361,25 @@ Execute a DELETE request. Takes a URL, parameters, and headers. See the [post]
|
|||||||
### head<a name="head"></a>
|
### 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.
|
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.
|
||||||
|
|
||||||
|
### options<a name="options"></a>
|
||||||
|
Execute a OPTIONS request. Takes a URL, parameters, and headers. See the [post](#post) documentation for details on what is returned on success and failure.
|
||||||
|
|
||||||
### uploadFile<a name="uploadFile"></a>
|
### 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.
|
Uploads one or more file(s) saved on the device. Takes a URL, parameters, headers, filePath(s), and the name(s) 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
|
```js
|
||||||
|
// e.g. for single file
|
||||||
|
const filePath = 'file:///somepicture.jpg';
|
||||||
|
const name = 'picture';
|
||||||
|
|
||||||
|
// e.g. for multiple files
|
||||||
|
const filePath = ['file:///somepicture.jpg', 'file:///somedocument.doc'];
|
||||||
|
const name = ['picture', 'document'];
|
||||||
|
|
||||||
cordova.plugin.http.uploadFile("https://google.com/", {
|
cordova.plugin.http.uploadFile("https://google.com/", {
|
||||||
id: '12',
|
id: '12',
|
||||||
message: 'test'
|
message: 'test'
|
||||||
}, { Authorization: 'OAuth2: token' }, 'file:///somepicture.jpg', 'picture', function(response) {
|
}, { Authorization: 'OAuth2: token' }, filePath, name, function(response) {
|
||||||
console.log(response.status);
|
console.log(response.status);
|
||||||
}, function(response) {
|
}, function(response) {
|
||||||
console.error(response.error);
|
console.error(response.error);
|
||||||
@@ -347,6 +404,46 @@ cordova.plugin.http.downloadFile("https://google.com/", {
|
|||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### abort<a name="abort"></a>
|
||||||
|
Abort a HTTP request. Takes the `requestId` which is returned by [sendRequest](#sendRequest) and its shorthand functions ([post](#post), [get](#get), [put](#put), [patch](#patch), [delete](#delete), [head](#head), [uploadFile](#uploadFile) and [downloadFile](#downloadFile)).
|
||||||
|
|
||||||
|
If the request already has finished, the request will finish normally and the abort call result will be `{ aborted: false }`.
|
||||||
|
|
||||||
|
If the request is still in progress, the request's `failure` callback will be invoked with response `{ status: -8 }`, and the abort call result `{ aborted: true }`.
|
||||||
|
|
||||||
|
:warning: Not supported for Android < 6 (API level < 23). For Android 5.1 and below, calling `abort(reqestId)` will have no effect, i.e. the requests will finish as if the request was not cancelled.
|
||||||
|
|
||||||
|
```js
|
||||||
|
// start a request and get its requestId
|
||||||
|
var requestId = cordova.plugin.http.downloadFile("https://google.com/", {
|
||||||
|
id: '12',
|
||||||
|
message: 'test'
|
||||||
|
}, { Authorization: 'OAuth2: token' }, 'file:///somepicture.jpg', function(entry) {
|
||||||
|
// prints the filename
|
||||||
|
console.log(entry.name);
|
||||||
|
|
||||||
|
// prints the filePath
|
||||||
|
console.log(entry.fullPath);
|
||||||
|
}, function(response) {
|
||||||
|
// if request was actually aborted, failure callback with status -8 will be invoked
|
||||||
|
if(response.status === -8){
|
||||||
|
console.log('download aborted');
|
||||||
|
} else {
|
||||||
|
console.error(response.error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
//...
|
||||||
|
|
||||||
|
// abort request
|
||||||
|
cordova.plugin.http.abort(requestId, function(result) {
|
||||||
|
// prints if request was aborted: true | false
|
||||||
|
console.log(result.aborted);
|
||||||
|
}, function(response) {
|
||||||
|
console.error(response.error);
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
## Browser support<a name="browserSupport"></a>
|
## Browser support<a name="browserSupport"></a>
|
||||||
|
|
||||||
This plugin supports a very restricted set of functions on the browser platform.
|
This plugin supports a very restricted set of functions on the browser platform.
|
||||||
@@ -359,6 +456,7 @@ Following features are *not* supported:
|
|||||||
* Pinning SSL certificate
|
* Pinning SSL certificate
|
||||||
* Disabling SSL certificate check
|
* Disabling SSL certificate check
|
||||||
* Disabling transparently following redirects (HTTP codes 3xx)
|
* Disabling transparently following redirects (HTTP codes 3xx)
|
||||||
|
* Circumventing CORS restrictions
|
||||||
|
|
||||||
## Libraries
|
## Libraries
|
||||||
|
|
||||||
@@ -370,6 +468,38 @@ This plugin utilizes some awesome open source libraries:
|
|||||||
|
|
||||||
We made a few modifications to the networking libraries.
|
We made a few modifications to the networking libraries.
|
||||||
|
|
||||||
|
## CI Builds & E2E Testing
|
||||||
|
|
||||||
|
This plugin uses amazing cloud services to maintain quality. CI Builds and E2E testing are powered by:
|
||||||
|
|
||||||
|
* [GitHub Actions](https://github.com/features/actions)
|
||||||
|
* [Travis CI](https://travis-ci.org/)
|
||||||
|
* [BrowserStack](https://www.browserstack.com/)
|
||||||
|
* [Sauce Labs](https://saucelabs.com/)
|
||||||
|
* [httpbin.org](https://httpbin.org/)
|
||||||
|
* [go-httpbin](https://httpbingo.org/)
|
||||||
|
|
||||||
|
### Local Testing
|
||||||
|
|
||||||
|
First, install current package with `npm install` to fetch dev dependencies.
|
||||||
|
|
||||||
|
Then, to execute Javascript tests:
|
||||||
|
```shell
|
||||||
|
npm run testjs
|
||||||
|
```
|
||||||
|
|
||||||
|
And, to execute E2E tests:
|
||||||
|
- setup local Android sdk and emulators, or Xcode and simulators for iOS
|
||||||
|
- launch emulator or simulator
|
||||||
|
- install [Appium](http://appium.io/) (see [Getting Started](https://github.com/appium/appium/blob/HEAD/docs/en/about-appium/getting-started.md))
|
||||||
|
- start `appium`
|
||||||
|
- run
|
||||||
|
- updating client and server certificates, building test app, and running e2e tests
|
||||||
|
```shell
|
||||||
|
npm run testandroid
|
||||||
|
npm run testios
|
||||||
|
```
|
||||||
|
|
||||||
## Contribute & Develop
|
## Contribute & Develop
|
||||||
|
|
||||||
We've set up a separate document for our [contribution guidelines](CONTRIBUTING.md).
|
We've set up a separate document for our [contribution guidelines](CONTRIBUTING.md).
|
||||||
|
|||||||
Generated
+11793
-5667
File diff suppressed because it is too large
Load Diff
+13
-14
@@ -1,12 +1,14 @@
|
|||||||
{
|
{
|
||||||
"name": "cordova-plugin-advanced-http",
|
"name": "cordova-plugin-advanced-http",
|
||||||
"version": "2.0.8",
|
"version": "3.1.1",
|
||||||
"description": "Cordova / Phonegap plugin for communicating with HTTP servers using SSL pinning",
|
"description": "Cordova / Phonegap plugin for communicating with HTTP servers using SSL pinning",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"updatecert": "node ./scripts/update-test-cert.js",
|
"updatecert": "node ./scripts/update-e2e-server-cert.js && node ./scripts/update-e2e-client-cert.js",
|
||||||
"buildbrowser": "./scripts/build-test-app.sh --browser",
|
"buildbrowser": "./scripts/build-test-app.sh --browser",
|
||||||
"testandroid": "npm run updatecert && ./scripts/build-test-app.sh --android --emulator && ./scripts/test-app.sh --android --emulator",
|
"buildandroid": "./scripts/build-test-app.sh --android --emulator",
|
||||||
"testios": "npm run updatecert && ./scripts/build-test-app.sh --ios --emulator && ./scripts/test-app.sh --ios --emulator",
|
"buildios": "./scripts/build-test-app.sh --ios --emulator",
|
||||||
|
"testandroid": "npm run updatecert && npm run buildandroid && ./scripts/test-app.sh --android --emulator",
|
||||||
|
"testios": "npm run updatecert && npm run buildios && ./scripts/test-app.sh --ios --emulator",
|
||||||
"testapp": "npm run testandroid && npm run testios",
|
"testapp": "npm run testandroid && npm run testios",
|
||||||
"testjs": "mocha ./test/js-specs.js",
|
"testjs": "mocha ./test/js-specs.js",
|
||||||
"test": "npm run testjs && npm run testapp",
|
"test": "npm run testjs && npm run testapp",
|
||||||
@@ -48,7 +50,7 @@
|
|||||||
"pvsaikrishna",
|
"pvsaikrishna",
|
||||||
"cvillerm",
|
"cvillerm",
|
||||||
"hideov",
|
"hideov",
|
||||||
"Mobisys"
|
"silkimen"
|
||||||
],
|
],
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"bugs": {
|
"bugs": {
|
||||||
@@ -56,15 +58,12 @@
|
|||||||
},
|
},
|
||||||
"homepage": "https://github.com/silkimen/cordova-plugin-advanced-http#readme",
|
"homepage": "https://github.com/silkimen/cordova-plugin-advanced-http#readme",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"chai": "4.1.2",
|
"chai": "4.2.0",
|
||||||
"chai-as-promised": "7.1.1",
|
"colors": "1.4.0",
|
||||||
"colors": "1.1.2",
|
"cordova": "10.0.0",
|
||||||
"cordova": "8.1.2",
|
"mocha": "8.2.0",
|
||||||
"mocha": "4.0.0",
|
|
||||||
"mock-require": "2.0.2",
|
|
||||||
"mz": "2.7.0",
|
|
||||||
"umd-tough-cookie": "2.4.3",
|
"umd-tough-cookie": "2.4.3",
|
||||||
"wd": "1.4.1",
|
"wd": "1.12.1",
|
||||||
"xml2js": "0.4.19"
|
"xml2js": "0.4.23"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+9
-3
@@ -1,5 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
<?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="2.0.8">
|
<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="3.1.1">
|
||||||
<name>Advanced HTTP plugin</name>
|
<name>Advanced HTTP plugin</name>
|
||||||
<description>
|
<description>
|
||||||
Cordova / Phonegap plugin for communicating with HTTP servers using SSL pinning
|
Cordova / Phonegap plugin for communicating with HTTP servers using SSL pinning
|
||||||
@@ -9,12 +9,15 @@
|
|||||||
</engines>
|
</engines>
|
||||||
<dependency id="cordova-plugin-file" version=">=2.0.0"/>
|
<dependency id="cordova-plugin-file" version=">=2.0.0"/>
|
||||||
<js-module src="www/cookie-handler.js" name="cookie-handler"/>
|
<js-module src="www/cookie-handler.js" name="cookie-handler"/>
|
||||||
|
<js-module src="www/dependency-validator.js" name="dependency-validator"/>
|
||||||
|
<js-module src="www/error-codes.js" name="error-codes"/>
|
||||||
<js-module src="www/global-configs.js" name="global-configs"/>
|
<js-module src="www/global-configs.js" name="global-configs"/>
|
||||||
<js-module src="www/helpers.js" name="helpers"/>
|
<js-module src="www/helpers.js" name="helpers"/>
|
||||||
<js-module src="www/js-util.js" name="js-util"/>
|
<js-module src="www/js-util.js" name="js-util"/>
|
||||||
<js-module src="www/local-storage-store.js" name="local-storage-store"/>
|
<js-module src="www/local-storage-store.js" name="local-storage-store"/>
|
||||||
<js-module src="www/lodash.js" name="lodash"/>
|
<js-module src="www/lodash.js" name="lodash"/>
|
||||||
<js-module src="www/messages.js" name="messages"/>
|
<js-module src="www/messages.js" name="messages"/>
|
||||||
|
<js-module src="www/ponyfills.js" name="ponyfills"/>
|
||||||
<js-module src="www/public-interface.js" name="public-interface"/>
|
<js-module src="www/public-interface.js" name="public-interface"/>
|
||||||
<js-module src="www/umd-tough-cookie.js" name="tough-cookie"/>
|
<js-module src="www/umd-tough-cookie.js" name="tough-cookie"/>
|
||||||
<js-module src="www/url-util.js" name="url-util"/>
|
<js-module src="www/url-util.js" name="url-util"/>
|
||||||
@@ -28,6 +31,8 @@
|
|||||||
</feature>
|
</feature>
|
||||||
</config-file>
|
</config-file>
|
||||||
<header-file src="src/ios/CordovaHttpPlugin.h"/>
|
<header-file src="src/ios/CordovaHttpPlugin.h"/>
|
||||||
|
<header-file src="src/ios/BinaryRequestSerializer.h"/>
|
||||||
|
<header-file src="src/ios/BinaryResponseSerializer.h"/>
|
||||||
<header-file src="src/ios/TextResponseSerializer.h"/>
|
<header-file src="src/ios/TextResponseSerializer.h"/>
|
||||||
<header-file src="src/ios/TextRequestSerializer.h"/>
|
<header-file src="src/ios/TextRequestSerializer.h"/>
|
||||||
<header-file src="src/ios/AFNetworking/AFHTTPSessionManager.h"/>
|
<header-file src="src/ios/AFNetworking/AFHTTPSessionManager.h"/>
|
||||||
@@ -39,6 +44,8 @@
|
|||||||
<header-file src="src/ios/AFNetworking/AFURLSessionManager.h"/>
|
<header-file src="src/ios/AFNetworking/AFURLSessionManager.h"/>
|
||||||
<header-file src="src/ios/SDNetworkActivityIndicator/SDNetworkActivityIndicator.h"/>
|
<header-file src="src/ios/SDNetworkActivityIndicator/SDNetworkActivityIndicator.h"/>
|
||||||
<source-file src="src/ios/CordovaHttpPlugin.m"/>
|
<source-file src="src/ios/CordovaHttpPlugin.m"/>
|
||||||
|
<source-file src="src/ios/BinaryRequestSerializer.m"/>
|
||||||
|
<source-file src="src/ios/BinaryResponseSerializer.m"/>
|
||||||
<source-file src="src/ios/TextResponseSerializer.m"/>
|
<source-file src="src/ios/TextResponseSerializer.m"/>
|
||||||
<source-file src="src/ios/TextRequestSerializer.m"/>
|
<source-file src="src/ios/TextRequestSerializer.m"/>
|
||||||
<source-file src="src/ios/AFNetworking/AFHTTPSessionManager.m"/>
|
<source-file src="src/ios/AFNetworking/AFHTTPSessionManager.m"/>
|
||||||
@@ -67,15 +74,14 @@
|
|||||||
<source-file src="src/android/com/silkimen/cordovahttp/CordovaHttpPlugin.java" target-dir="src/com/silkimen/cordovahttp"/>
|
<source-file src="src/android/com/silkimen/cordovahttp/CordovaHttpPlugin.java" target-dir="src/com/silkimen/cordovahttp"/>
|
||||||
<source-file src="src/android/com/silkimen/cordovahttp/CordovaHttpResponse.java" target-dir="src/com/silkimen/cordovahttp"/>
|
<source-file src="src/android/com/silkimen/cordovahttp/CordovaHttpResponse.java" target-dir="src/com/silkimen/cordovahttp"/>
|
||||||
<source-file src="src/android/com/silkimen/cordovahttp/CordovaHttpUpload.java" target-dir="src/com/silkimen/cordovahttp"/>
|
<source-file src="src/android/com/silkimen/cordovahttp/CordovaHttpUpload.java" target-dir="src/com/silkimen/cordovahttp"/>
|
||||||
|
<source-file src="src/android/com/silkimen/cordovahttp/CordovaObservableCallbackContext.java" target-dir="src/com/silkimen/cordovahttp"/>
|
||||||
<source-file src="src/android/com/silkimen/cordovahttp/CordovaServerTrust.java" target-dir="src/com/silkimen/cordovahttp"/>
|
<source-file src="src/android/com/silkimen/cordovahttp/CordovaServerTrust.java" target-dir="src/com/silkimen/cordovahttp"/>
|
||||||
<source-file src="src/android/com/silkimen/http/HttpBodyDecoder.java" target-dir="src/com/silkimen/http"/>
|
<source-file src="src/android/com/silkimen/http/HttpBodyDecoder.java" target-dir="src/com/silkimen/http"/>
|
||||||
<source-file src="src/android/com/silkimen/http/HttpRequest.java" target-dir="src/com/silkimen/http"/>
|
<source-file src="src/android/com/silkimen/http/HttpRequest.java" target-dir="src/com/silkimen/http"/>
|
||||||
<source-file src="src/android/com/silkimen/http/JsonUtils.java" target-dir="src/com/silkimen/http"/>
|
<source-file src="src/android/com/silkimen/http/JsonUtils.java" target-dir="src/com/silkimen/http"/>
|
||||||
<source-file src="src/android/com/silkimen/http/KeyChainKeyManager.java" target-dir="src/com/silkimen/http"/>
|
<source-file src="src/android/com/silkimen/http/KeyChainKeyManager.java" target-dir="src/com/silkimen/http"/>
|
||||||
<source-file src="src/android/com/silkimen/http/OkConnectionFactory.java" target-dir="src/com/silkimen/http"/>
|
|
||||||
<source-file src="src/android/com/silkimen/http/TLSConfiguration.java" target-dir="src/com/silkimen/http"/>
|
<source-file src="src/android/com/silkimen/http/TLSConfiguration.java" target-dir="src/com/silkimen/http"/>
|
||||||
<source-file src="src/android/com/silkimen/http/TLSSocketFactory.java" target-dir="src/com/silkimen/http"/>
|
<source-file src="src/android/com/silkimen/http/TLSSocketFactory.java" target-dir="src/com/silkimen/http"/>
|
||||||
<framework src="com.squareup.okhttp3:okhttp-urlconnection:3.10.0"/>
|
|
||||||
</platform>
|
</platform>
|
||||||
<platform name="browser">
|
<platform name="browser">
|
||||||
<config-file target="config.xml" parent="/*">
|
<config-file target="config.xml" parent="/*">
|
||||||
|
|||||||
+2
-2
@@ -3,8 +3,8 @@ set -e
|
|||||||
|
|
||||||
ROOT="$( cd "$( dirname "${BASH_SOURCE[0]}" )"; cd ..; pwd )"
|
ROOT="$( cd "$( dirname "${BASH_SOURCE[0]}" )"; cd ..; pwd )"
|
||||||
|
|
||||||
if [ $CI == "true" ] && ([ -z $SAUCE_USERNAME ] || [ -z $SAUCE_ACCESS_KEY ]); then
|
if [ $CI == "true" ] && ([ -z $SAUCE_USERNAME ] || [ -z $SAUCE_ACCESS_KEY ]) && ([ -z $BROWSERSTACK_USERNAME ] || [ -z $BROWSERSTACK_ACCESS_KEY ]); then
|
||||||
echo "Skipping CI tests, because Saucelabs credentials are not set.";
|
echo "Skipping CI tests, because Saucelabs and BrowserStack credentials are not set.";
|
||||||
exit 0;
|
exit 0;
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,29 @@
|
|||||||
|
const fs = require('fs');
|
||||||
|
const https = require('https');
|
||||||
|
const path = require('path');
|
||||||
|
|
||||||
|
const SOURCE_URL = 'https://badssl.com/certs/badssl.com-client.p12';
|
||||||
|
const TARGET_PATH = path.join(__dirname, '../test/e2e-app-template/www/certificates/badssl-client-cert.pkcs');
|
||||||
|
|
||||||
|
const downloadPkcsContainer = (source, target) => new Promise((resolve, reject) => {
|
||||||
|
const file = fs.createWriteStream(target);
|
||||||
|
|
||||||
|
const req = https.get(source, response => {
|
||||||
|
response.pipe(file)
|
||||||
|
resolve(target);
|
||||||
|
});
|
||||||
|
|
||||||
|
req.on('error', error => {
|
||||||
|
return reject(error)
|
||||||
|
});
|
||||||
|
|
||||||
|
req.end();
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log(`Updating client certificate from ${SOURCE_URL}`);
|
||||||
|
|
||||||
|
downloadPkcsContainer(SOURCE_URL, TARGET_PATH)
|
||||||
|
.catch(error => {
|
||||||
|
console.error(`Updating client certificate failed: ${error}`);
|
||||||
|
process.exit(1);
|
||||||
|
});
|
||||||
@@ -30,13 +30,11 @@ const getCert = hostname => new Promise((resolve, reject) => {
|
|||||||
req.end();
|
req.end();
|
||||||
});
|
});
|
||||||
|
|
||||||
console.log(`Updating test certificate from ${SOURCE_HOST}`);
|
console.log(`Updating server certificate from ${SOURCE_HOST}`);
|
||||||
|
|
||||||
getCert(SOURCE_HOST)
|
getCert(SOURCE_HOST)
|
||||||
.then(cert => {
|
.then(cert => fs.writeFileSync(TARGET_PATH, cert.raw))
|
||||||
fs.writeFileSync(TARGET_PATH, cert.raw);
|
|
||||||
})
|
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
console.error(`Updating test cert failed: ${error}`);
|
console.error(`Updating server certificate failed: ${error}`);
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
});
|
});
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
const args = process.argv.slice(2);
|
const args = process.argv.slice(2);
|
||||||
const fs = require('mz/fs');
|
const fs = require('fs');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
const xml2js = require('xml2js');
|
const xml2js = require('xml2js');
|
||||||
const xmlPath = path.join(__dirname, '..', 'plugin.xml');
|
const xmlPath = path.join(__dirname, '..', 'plugin.xml');
|
||||||
@@ -22,10 +22,12 @@ const stringify = obj => {
|
|||||||
return builder.buildObject(obj);
|
return builder.buildObject(obj);
|
||||||
};
|
};
|
||||||
|
|
||||||
fs.readFile(xmlPath, 'utf-8')
|
const update = async (version) => {
|
||||||
.then(xml => parse(xml))
|
const xml = fs.readFileSync(xmlPath, 'utf-8');
|
||||||
.then(parsed => {
|
const parsed = await parse(xml);
|
||||||
parsed.plugin.$.version = args[0];
|
|
||||||
|
|
||||||
return fs.writeFile(xmlPath, stringify(parsed));
|
parsed.plugin.$.version = version;
|
||||||
});
|
fs.writeFileSync(xmlPath, stringify(parsed));
|
||||||
|
};
|
||||||
|
|
||||||
|
return update(args[0]);
|
||||||
|
|||||||
Executable
+33
@@ -0,0 +1,33 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -e
|
||||||
|
|
||||||
|
PLATFORM=$([[ "${@#--android}" = "$@" ]] && echo "ios" || echo "android")
|
||||||
|
ROOT="$( cd "$( dirname "${BASH_SOURCE[0]}" )"; cd ..; pwd )"
|
||||||
|
TEMP=$ROOT/temp
|
||||||
|
|
||||||
|
if [ -z $BROWSERSTACK_USERNAME ] || [ -z $BROWSERSTACK_ACCESS_KEY ]; then
|
||||||
|
echo "Skipping uploading artifact, because BrowserStack credentials are not set.";
|
||||||
|
exit 0;
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ $PLATFORM = "android" ]; then
|
||||||
|
curl -u $BROWSERSTACK_USERNAME:$BROWSERSTACK_ACCESS_KEY \
|
||||||
|
-X POST \
|
||||||
|
https://api-cloud.browserstack.com/app-automate/upload \
|
||||||
|
-F "file=@$TEMP/platforms/android/app/build/outputs/apk/debug/app-debug.apk" \
|
||||||
|
-F "data={\"custom_id\": \"HttpTestAppAndroid\"}"
|
||||||
|
else
|
||||||
|
rm -rf $TEMP/HttpDemo.ipa
|
||||||
|
pushd $TEMP/platforms/ios/build/emulator
|
||||||
|
rm -rf ./Payload
|
||||||
|
mkdir -p ./Payload
|
||||||
|
cp -r ./HttpDemo.app ./Payload/HttpDemo.app
|
||||||
|
zip -r $TEMP/HttpDemo.ipa ./Payload
|
||||||
|
popd
|
||||||
|
|
||||||
|
curl -u $BROWSERSTACK_USERNAME:$BROWSERSTACK_ACCESS_KEY \
|
||||||
|
-X POST \
|
||||||
|
https://api-cloud.browserstack.com/app-automate/upload \
|
||||||
|
-F "file=@$TEMP/HttpDemo.ipa" \
|
||||||
|
-F "data={\"custom_id\": \"HttpTestAppIos\"}"
|
||||||
|
fi
|
||||||
@@ -6,11 +6,15 @@ import android.security.KeyChain;
|
|||||||
import android.security.KeyChainAliasCallback;
|
import android.security.KeyChainAliasCallback;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.net.URI;
|
||||||
import java.security.KeyStore;
|
import java.security.KeyStore;
|
||||||
import java.security.PrivateKey;
|
import java.security.PrivateKey;
|
||||||
import java.security.cert.X509Certificate;
|
import java.security.cert.X509Certificate;
|
||||||
|
|
||||||
import javax.net.ssl.KeyManager;
|
import javax.net.ssl.KeyManager;
|
||||||
|
import javax.net.ssl.KeyManagerFactory;
|
||||||
|
|
||||||
import org.apache.cordova.CallbackContext;
|
import org.apache.cordova.CallbackContext;
|
||||||
|
|
||||||
@@ -21,17 +25,22 @@ class CordovaClientAuth implements Runnable, KeyChainAliasCallback {
|
|||||||
private static final String TAG = "Cordova-Plugin-HTTP";
|
private static final String TAG = "Cordova-Plugin-HTTP";
|
||||||
|
|
||||||
private String mode;
|
private String mode;
|
||||||
private String filePath;
|
private String aliasString;
|
||||||
|
private byte[] rawPkcs;
|
||||||
|
private String pkcsPassword;
|
||||||
private Activity activity;
|
private Activity activity;
|
||||||
private Context context;
|
private Context context;
|
||||||
private TLSConfiguration tlsConfiguration;
|
private TLSConfiguration tlsConfiguration;
|
||||||
private CallbackContext callbackContext;
|
private CallbackContext callbackContext;
|
||||||
|
|
||||||
public CordovaClientAuth(final String mode, final String filePath, final Activity activity, final Context context,
|
public CordovaClientAuth(final String mode, final String aliasString, final byte[] rawPkcs,
|
||||||
final TLSConfiguration configContainer, final CallbackContext callbackContext) {
|
final String pkcsPassword, final Activity activity, final Context context, final TLSConfiguration configContainer,
|
||||||
|
final CallbackContext callbackContext) {
|
||||||
|
|
||||||
this.mode = mode;
|
this.mode = mode;
|
||||||
this.filePath = filePath;
|
this.aliasString = aliasString;
|
||||||
|
this.rawPkcs = rawPkcs;
|
||||||
|
this.pkcsPassword = pkcsPassword;
|
||||||
this.activity = activity;
|
this.activity = activity;
|
||||||
this.tlsConfiguration = configContainer;
|
this.tlsConfiguration = configContainer;
|
||||||
this.context = context;
|
this.context = context;
|
||||||
@@ -41,15 +50,45 @@ class CordovaClientAuth implements Runnable, KeyChainAliasCallback {
|
|||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
if ("systemstore".equals(this.mode)) {
|
if ("systemstore".equals(this.mode)) {
|
||||||
KeyChain.choosePrivateKeyAlias(this.activity, this, null, null, null, -1, null);
|
this.loadFromSystemStore();
|
||||||
} else if ("file".equals(this.mode)) {
|
} else if ("buffer".equals(this.mode)) {
|
||||||
this.callbackContext.error("Not implemented, yet");
|
this.loadFromBuffer();
|
||||||
} else {
|
} else {
|
||||||
this.tlsConfiguration.setKeyManagers(null);
|
this.disableClientAuth();
|
||||||
this.callbackContext.success();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void loadFromSystemStore() {
|
||||||
|
if (this.aliasString == null) {
|
||||||
|
KeyChain.choosePrivateKeyAlias(this.activity, this, null, null, null, -1, null);
|
||||||
|
} else {
|
||||||
|
this.alias(this.aliasString);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void loadFromBuffer() {
|
||||||
|
try {
|
||||||
|
KeyStore keyStore = KeyStore.getInstance("PKCS12");
|
||||||
|
String keyManagerFactoryAlgorithm = KeyManagerFactory.getDefaultAlgorithm();
|
||||||
|
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(keyManagerFactoryAlgorithm);
|
||||||
|
ByteArrayInputStream stream = new ByteArrayInputStream(this.rawPkcs);
|
||||||
|
|
||||||
|
keyStore.load(stream, this.pkcsPassword.toCharArray());
|
||||||
|
keyManagerFactory.init(keyStore, this.pkcsPassword.toCharArray());
|
||||||
|
|
||||||
|
this.tlsConfiguration.setKeyManagers(keyManagerFactory.getKeyManagers());
|
||||||
|
this.callbackContext.success();
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.e(TAG, "Couldn't load given PKCS12 container for authentication", e);
|
||||||
|
this.callbackContext.error("Couldn't load given PKCS12 container for authentication");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void disableClientAuth() {
|
||||||
|
this.tlsConfiguration.setKeyManagers(null);
|
||||||
|
this.callbackContext.success();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void alias(final String alias) {
|
public void alias(final String alias) {
|
||||||
try {
|
try {
|
||||||
@@ -63,10 +102,12 @@ class CordovaClientAuth implements Runnable, KeyChainAliasCallback {
|
|||||||
|
|
||||||
this.tlsConfiguration.setKeyManagers(new KeyManager[] { keyManager });
|
this.tlsConfiguration.setKeyManagers(new KeyManager[] { keyManager });
|
||||||
|
|
||||||
this.callbackContext.success();
|
this.callbackContext.success(alias);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Log.e(TAG, "Couldn't load private key and certificate pair for authentication", e);
|
Log.e(TAG, "Couldn't load private key and certificate pair with given alias \"" + alias + "\" for authentication",
|
||||||
this.callbackContext.error("Couldn't load private key and certificate pair for authentication");
|
e);
|
||||||
|
this.callbackContext.error(
|
||||||
|
"Couldn't load private key and certificate pair with given alias \"" + alias + "\" for authentication");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,11 @@
|
|||||||
package com.silkimen.cordovahttp;
|
package com.silkimen.cordovahttp;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.ByteArrayInputStream;
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import java.io.InterruptedIOException;
|
||||||
import java.net.SocketTimeoutException;
|
import java.net.SocketTimeoutException;
|
||||||
import java.net.UnknownHostException;
|
import java.net.UnknownHostException;
|
||||||
|
|
||||||
@@ -14,14 +17,13 @@ import com.silkimen.http.HttpBodyDecoder;
|
|||||||
import com.silkimen.http.HttpRequest;
|
import com.silkimen.http.HttpRequest;
|
||||||
import com.silkimen.http.HttpRequest.HttpRequestException;
|
import com.silkimen.http.HttpRequest.HttpRequestException;
|
||||||
import com.silkimen.http.JsonUtils;
|
import com.silkimen.http.JsonUtils;
|
||||||
import com.silkimen.http.OkConnectionFactory;
|
|
||||||
import com.silkimen.http.TLSConfiguration;
|
import com.silkimen.http.TLSConfiguration;
|
||||||
|
|
||||||
import org.apache.cordova.CallbackContext;
|
import org.json.JSONArray;
|
||||||
|
|
||||||
import org.json.JSONException;
|
import org.json.JSONException;
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
|
|
||||||
|
import android.util.Base64;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
abstract class CordovaHttpBase implements Runnable {
|
abstract class CordovaHttpBase implements Runnable {
|
||||||
@@ -30,15 +32,17 @@ abstract class CordovaHttpBase implements Runnable {
|
|||||||
protected String method;
|
protected String method;
|
||||||
protected String url;
|
protected String url;
|
||||||
protected String serializer = "none";
|
protected String serializer = "none";
|
||||||
|
protected String responseType;
|
||||||
protected Object data;
|
protected Object data;
|
||||||
protected JSONObject headers;
|
protected JSONObject headers;
|
||||||
protected int timeout;
|
protected int timeout;
|
||||||
protected boolean followRedirects;
|
protected boolean followRedirects;
|
||||||
protected TLSConfiguration tlsConfiguration;
|
protected TLSConfiguration tlsConfiguration;
|
||||||
protected CallbackContext callbackContext;
|
protected CordovaObservableCallbackContext callbackContext;
|
||||||
|
|
||||||
public CordovaHttpBase(String method, String url, String serializer, Object data, JSONObject headers, int timeout,
|
public CordovaHttpBase(String method, String url, String serializer, Object data, JSONObject headers, int timeout,
|
||||||
boolean followRedirects, TLSConfiguration tlsConfiguration, CallbackContext callbackContext) {
|
boolean followRedirects, String responseType, TLSConfiguration tlsConfiguration,
|
||||||
|
CordovaObservableCallbackContext callbackContext) {
|
||||||
|
|
||||||
this.method = method;
|
this.method = method;
|
||||||
this.url = url;
|
this.url = url;
|
||||||
@@ -47,18 +51,20 @@ abstract class CordovaHttpBase implements Runnable {
|
|||||||
this.headers = headers;
|
this.headers = headers;
|
||||||
this.timeout = timeout;
|
this.timeout = timeout;
|
||||||
this.followRedirects = followRedirects;
|
this.followRedirects = followRedirects;
|
||||||
|
this.responseType = responseType;
|
||||||
this.tlsConfiguration = tlsConfiguration;
|
this.tlsConfiguration = tlsConfiguration;
|
||||||
this.callbackContext = callbackContext;
|
this.callbackContext = callbackContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
public CordovaHttpBase(String method, String url, JSONObject headers, int timeout, boolean followRedirects,
|
public CordovaHttpBase(String method, String url, JSONObject headers, int timeout, boolean followRedirects,
|
||||||
TLSConfiguration tlsConfiguration, CallbackContext callbackContext) {
|
String responseType, TLSConfiguration tlsConfiguration, CordovaObservableCallbackContext callbackContext) {
|
||||||
|
|
||||||
this.method = method;
|
this.method = method;
|
||||||
this.url = url;
|
this.url = url;
|
||||||
this.headers = headers;
|
this.headers = headers;
|
||||||
this.timeout = timeout;
|
this.timeout = timeout;
|
||||||
this.followRedirects = followRedirects;
|
this.followRedirects = followRedirects;
|
||||||
|
this.responseType = responseType;
|
||||||
this.tlsConfiguration = tlsConfiguration;
|
this.tlsConfiguration = tlsConfiguration;
|
||||||
this.callbackContext = callbackContext;
|
this.callbackContext = callbackContext;
|
||||||
}
|
}
|
||||||
@@ -66,30 +72,39 @@ abstract class CordovaHttpBase implements Runnable {
|
|||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
CordovaHttpResponse response = new CordovaHttpResponse();
|
CordovaHttpResponse response = new CordovaHttpResponse();
|
||||||
|
HttpRequest request = null;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
HttpRequest request = this.createRequest();
|
request = this.createRequest();
|
||||||
this.prepareRequest(request);
|
this.prepareRequest(request);
|
||||||
this.sendBody(request);
|
this.sendBody(request);
|
||||||
this.processResponse(request, response);
|
this.processResponse(request, response);
|
||||||
|
request.disconnect();
|
||||||
} catch (HttpRequestException e) {
|
} catch (HttpRequestException e) {
|
||||||
if (e.getCause() instanceof SSLException) {
|
Throwable cause = e.getCause();
|
||||||
|
String message = cause.getMessage();
|
||||||
|
|
||||||
|
if (cause instanceof SSLException) {
|
||||||
response.setStatus(-2);
|
response.setStatus(-2);
|
||||||
response.setErrorMessage("TLS connection could not be established: " + e.getMessage());
|
response.setErrorMessage("TLS connection could not be established: " + e.getMessage());
|
||||||
Log.w(TAG, "TLS connection could not be established", e);
|
Log.w(TAG, "TLS connection could not be established", e);
|
||||||
} else if (e.getCause() instanceof UnknownHostException) {
|
} else if (cause instanceof UnknownHostException) {
|
||||||
response.setStatus(-3);
|
response.setStatus(-3);
|
||||||
response.setErrorMessage("Host could not be resolved: " + e.getMessage());
|
response.setErrorMessage("Host could not be resolved: " + e.getMessage());
|
||||||
Log.w(TAG, "Host could not be resolved", e);
|
Log.w(TAG, "Host could not be resolved", e);
|
||||||
} else if (e.getCause() instanceof SocketTimeoutException) {
|
} else if (cause instanceof SocketTimeoutException) {
|
||||||
response.setStatus(-4);
|
response.setStatus(-4);
|
||||||
response.setErrorMessage("Request timed out: " + e.getMessage());
|
response.setErrorMessage("Request timed out: " + e.getMessage());
|
||||||
Log.w(TAG, "Request timed out", e);
|
Log.w(TAG, "Request timed out", e);
|
||||||
|
} else if (cause instanceof InterruptedIOException && "thread interrupted".equals(message.toLowerCase())) {
|
||||||
|
this.setAborted(request, response);
|
||||||
} else {
|
} else {
|
||||||
response.setStatus(-1);
|
response.setStatus(-1);
|
||||||
response.setErrorMessage("There was an error with the request: " + e.getCause().getMessage());
|
response.setErrorMessage("There was an error with the request: " + message);
|
||||||
Log.w(TAG, "Generic request error", e);
|
Log.w(TAG, "Generic request error", e);
|
||||||
}
|
}
|
||||||
|
} catch (InterruptedException ie) {
|
||||||
|
this.setAborted(request, response);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
response.setStatus(-1);
|
response.setStatus(-1);
|
||||||
response.setErrorMessage(e.getMessage());
|
response.setErrorMessage(e.getMessage());
|
||||||
@@ -116,7 +131,6 @@ abstract class CordovaHttpBase implements Runnable {
|
|||||||
request.readTimeout(this.timeout);
|
request.readTimeout(this.timeout);
|
||||||
request.acceptCharset("UTF-8");
|
request.acceptCharset("UTF-8");
|
||||||
request.uncompress(true);
|
request.uncompress(true);
|
||||||
request.setConnectionFactory(new OkConnectionFactory());
|
|
||||||
|
|
||||||
if (this.tlsConfiguration.getHostnameVerifier() != null) {
|
if (this.tlsConfiguration.getHostnameVerifier() != null) {
|
||||||
request.setHostnameVerifier(this.tlsConfiguration.getHostnameVerifier());
|
request.setHostnameVerifier(this.tlsConfiguration.getHostnameVerifier());
|
||||||
@@ -135,8 +149,12 @@ abstract class CordovaHttpBase implements Runnable {
|
|||||||
request.contentType("application/json", "UTF-8");
|
request.contentType("application/json", "UTF-8");
|
||||||
} else if ("utf8".equals(this.serializer)) {
|
} else if ("utf8".equals(this.serializer)) {
|
||||||
request.contentType("text/plain", "UTF-8");
|
request.contentType("text/plain", "UTF-8");
|
||||||
|
} else if ("raw".equals(this.serializer)) {
|
||||||
|
request.contentType("application/octet-stream");
|
||||||
} else if ("urlencoded".equals(this.serializer)) {
|
} else if ("urlencoded".equals(this.serializer)) {
|
||||||
// intentionally left blank, because content type is set in HttpRequest.form()
|
// intentionally left blank, because content type is set in HttpRequest.form()
|
||||||
|
} else if ("multipart".equals(this.serializer)) {
|
||||||
|
// intentionally left blank, because content type is set in HttpRequest.part()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -149,8 +167,32 @@ abstract class CordovaHttpBase implements Runnable {
|
|||||||
request.send(this.data.toString());
|
request.send(this.data.toString());
|
||||||
} else if ("utf8".equals(this.serializer)) {
|
} else if ("utf8".equals(this.serializer)) {
|
||||||
request.send(((JSONObject) this.data).getString("text"));
|
request.send(((JSONObject) this.data).getString("text"));
|
||||||
|
} else if ("raw".equals(this.serializer)) {
|
||||||
|
request.send(Base64.decode((String)this.data, Base64.DEFAULT));
|
||||||
} else if ("urlencoded".equals(this.serializer)) {
|
} else if ("urlencoded".equals(this.serializer)) {
|
||||||
request.form(JsonUtils.getObjectMap((JSONObject) this.data));
|
request.form(JsonUtils.getObjectMap((JSONObject) this.data));
|
||||||
|
} else if ("multipart".equals(this.serializer)) {
|
||||||
|
JSONArray buffers = ((JSONObject) this.data).getJSONArray("buffers");
|
||||||
|
JSONArray names = ((JSONObject) this.data).getJSONArray("names");
|
||||||
|
JSONArray fileNames = ((JSONObject) this.data).getJSONArray("fileNames");
|
||||||
|
JSONArray types = ((JSONObject) this.data).getJSONArray("types");
|
||||||
|
|
||||||
|
for (int i = 0; i < buffers.length(); ++i) {
|
||||||
|
byte[] bytes = Base64.decode(buffers.getString(i), Base64.DEFAULT);
|
||||||
|
String name = names.getString(i);
|
||||||
|
|
||||||
|
if (fileNames.isNull(i)) {
|
||||||
|
request.part(name, new String(bytes, "UTF-8"));
|
||||||
|
} else {
|
||||||
|
request.part(name, fileNames.getString(i), types.getString(i), new ByteArrayInputStream(bytes));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// prevent sending malformed empty multipart requests (#372)
|
||||||
|
if (buffers.length() == 0) {
|
||||||
|
request.contentType("multipart/form-data; boundary=00content0boundary00");
|
||||||
|
request.send("\r\n--00content0boundary00--\r\n");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -158,17 +200,34 @@ abstract class CordovaHttpBase implements Runnable {
|
|||||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||||
request.receive(outputStream);
|
request.receive(outputStream);
|
||||||
|
|
||||||
ByteBuffer rawOutput = ByteBuffer.wrap(outputStream.toByteArray());
|
|
||||||
String decodedBody = HttpBodyDecoder.decodeBody(rawOutput, request.charset());
|
|
||||||
|
|
||||||
response.setStatus(request.code());
|
response.setStatus(request.code());
|
||||||
response.setUrl(request.url().toString());
|
response.setUrl(request.url().toString());
|
||||||
response.setHeaders(request.headers());
|
response.setHeaders(request.headers());
|
||||||
|
|
||||||
if (request.code() >= 200 && request.code() < 300) {
|
if (request.code() >= 200 && request.code() < 300) {
|
||||||
response.setBody(decodedBody);
|
if ("text".equals(this.responseType) || "json".equals(this.responseType)) {
|
||||||
|
String decoded = HttpBodyDecoder.decodeBody(outputStream.toByteArray(), request.charset());
|
||||||
|
response.setBody(decoded);
|
||||||
|
} else {
|
||||||
|
response.setData(outputStream.toByteArray());
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
response.setErrorMessage(decodedBody);
|
response.setErrorMessage(HttpBodyDecoder.decodeBody(outputStream.toByteArray(), request.charset()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void setAborted(HttpRequest request, CordovaHttpResponse response) {
|
||||||
|
response.setStatus(-8);
|
||||||
|
response.setErrorMessage("Request was aborted");
|
||||||
|
|
||||||
|
if (request != null) {
|
||||||
|
try {
|
||||||
|
request.disconnect();
|
||||||
|
} catch(Exception any){
|
||||||
|
Log.w(TAG, "Failed to close aborted request", any);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Log.i(TAG, "Request was aborted");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ import javax.net.ssl.SSLSocketFactory;
|
|||||||
import com.silkimen.http.HttpRequest;
|
import com.silkimen.http.HttpRequest;
|
||||||
import com.silkimen.http.TLSConfiguration;
|
import com.silkimen.http.TLSConfiguration;
|
||||||
|
|
||||||
import org.apache.cordova.CallbackContext;
|
|
||||||
import org.apache.cordova.file.FileUtils;
|
import org.apache.cordova.file.FileUtils;
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
|
|
||||||
@@ -17,9 +16,9 @@ class CordovaHttpDownload extends CordovaHttpBase {
|
|||||||
private String filePath;
|
private String filePath;
|
||||||
|
|
||||||
public CordovaHttpDownload(String url, JSONObject headers, String filePath, int timeout, boolean followRedirects,
|
public CordovaHttpDownload(String url, JSONObject headers, String filePath, int timeout, boolean followRedirects,
|
||||||
TLSConfiguration tlsConfiguration, CallbackContext callbackContext) {
|
TLSConfiguration tlsConfiguration, CordovaObservableCallbackContext callbackContext) {
|
||||||
|
|
||||||
super("GET", url, headers, timeout, followRedirects, tlsConfiguration, callbackContext);
|
super("GET", url, headers, timeout, followRedirects, "text", tlsConfiguration, callbackContext);
|
||||||
this.filePath = filePath;
|
this.filePath = filePath;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,19 +5,20 @@ import javax.net.ssl.SSLSocketFactory;
|
|||||||
|
|
||||||
import com.silkimen.http.TLSConfiguration;
|
import com.silkimen.http.TLSConfiguration;
|
||||||
|
|
||||||
import org.apache.cordova.CallbackContext;
|
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
|
|
||||||
class CordovaHttpOperation extends CordovaHttpBase {
|
class CordovaHttpOperation extends CordovaHttpBase {
|
||||||
public CordovaHttpOperation(String method, String url, String serializer, Object data, JSONObject headers,
|
public CordovaHttpOperation(String method, String url, String serializer, Object data, JSONObject headers,
|
||||||
int timeout, boolean followRedirects, TLSConfiguration tlsConfiguration, CallbackContext callbackContext) {
|
int timeout, boolean followRedirects, String responseType, TLSConfiguration tlsConfiguration,
|
||||||
|
CordovaObservableCallbackContext callbackContext) {
|
||||||
|
|
||||||
super(method, url, serializer, data, headers, timeout, followRedirects, tlsConfiguration, callbackContext);
|
super(method, url, serializer, data, headers, timeout, followRedirects, responseType, tlsConfiguration,
|
||||||
|
callbackContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
public CordovaHttpOperation(String method, String url, JSONObject headers, int timeout, boolean followRedirects,
|
public CordovaHttpOperation(String method, String url, JSONObject headers, int timeout, boolean followRedirects,
|
||||||
TLSConfiguration tlsConfiguration, CallbackContext callbackContext) {
|
String responseType, TLSConfiguration tlsConfiguration, CordovaObservableCallbackContext callbackContext) {
|
||||||
|
|
||||||
super(method, url, headers, timeout, followRedirects, tlsConfiguration, callbackContext);
|
super(method, url, headers, timeout, followRedirects, responseType, tlsConfiguration, callbackContext);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,10 @@
|
|||||||
package com.silkimen.cordovahttp;
|
package com.silkimen.cordovahttp;
|
||||||
|
|
||||||
import java.security.KeyStore;
|
import java.security.KeyStore;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Observable;
|
||||||
|
import java.util.Observer;
|
||||||
|
import java.util.concurrent.Future;
|
||||||
|
|
||||||
import com.silkimen.http.TLSConfiguration;
|
import com.silkimen.http.TLSConfiguration;
|
||||||
|
|
||||||
@@ -13,21 +17,26 @@ import org.json.JSONException;
|
|||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
|
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
import android.util.Base64;
|
||||||
|
|
||||||
import javax.net.ssl.TrustManagerFactory;
|
import javax.net.ssl.TrustManagerFactory;
|
||||||
|
|
||||||
public class CordovaHttpPlugin extends CordovaPlugin {
|
public class CordovaHttpPlugin extends CordovaPlugin implements Observer {
|
||||||
private static final String TAG = "Cordova-Plugin-HTTP";
|
private static final String TAG = "Cordova-Plugin-HTTP";
|
||||||
|
|
||||||
private boolean followRedirects = true;
|
|
||||||
private TLSConfiguration tlsConfiguration;
|
private TLSConfiguration tlsConfiguration;
|
||||||
|
|
||||||
|
private HashMap<Integer, Future<?>> reqMap;
|
||||||
|
private final Object reqMapLock = new Object();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void initialize(CordovaInterface cordova, CordovaWebView webView) {
|
public void initialize(CordovaInterface cordova, CordovaWebView webView) {
|
||||||
super.initialize(cordova, webView);
|
super.initialize(cordova, webView);
|
||||||
|
|
||||||
this.tlsConfiguration = new TLSConfiguration();
|
this.tlsConfiguration = new TLSConfiguration();
|
||||||
|
|
||||||
|
this.reqMap = new HashMap<Integer, Future<?>>();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
KeyStore store = KeyStore.getInstance("AndroidCAStore");
|
KeyStore store = KeyStore.getInstance("AndroidCAStore");
|
||||||
String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
|
String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
|
||||||
@@ -57,22 +66,24 @@ public class CordovaHttpPlugin extends CordovaPlugin {
|
|||||||
return this.executeHttpRequestWithoutData(action, args, callbackContext);
|
return this.executeHttpRequestWithoutData(action, args, callbackContext);
|
||||||
} else if ("delete".equals(action)) {
|
} else if ("delete".equals(action)) {
|
||||||
return this.executeHttpRequestWithoutData(action, args, callbackContext);
|
return this.executeHttpRequestWithoutData(action, args, callbackContext);
|
||||||
|
} else if ("options".equals(action)) {
|
||||||
|
return this.executeHttpRequestWithoutData(action, args, callbackContext);
|
||||||
} else if ("post".equals(action)) {
|
} else if ("post".equals(action)) {
|
||||||
return this.executeHttpRequestWithData(action, args, callbackContext);
|
return this.executeHttpRequestWithData(action, args, callbackContext);
|
||||||
} else if ("put".equals(action)) {
|
} else if ("put".equals(action)) {
|
||||||
return this.executeHttpRequestWithData(action, args, callbackContext);
|
return this.executeHttpRequestWithData(action, args, callbackContext);
|
||||||
} else if ("patch".equals(action)) {
|
} else if ("patch".equals(action)) {
|
||||||
return this.executeHttpRequestWithData(action, args, callbackContext);
|
return this.executeHttpRequestWithData(action, args, callbackContext);
|
||||||
} else if ("uploadFile".equals(action)) {
|
} else if ("uploadFiles".equals(action)) {
|
||||||
return this.uploadFile(args, callbackContext);
|
return this.uploadFiles(args, callbackContext);
|
||||||
} else if ("downloadFile".equals(action)) {
|
} else if ("downloadFile".equals(action)) {
|
||||||
return this.downloadFile(args, callbackContext);
|
return this.downloadFile(args, callbackContext);
|
||||||
} else if ("setServerTrustMode".equals(action)) {
|
} else if ("setServerTrustMode".equals(action)) {
|
||||||
return this.setServerTrustMode(args, callbackContext);
|
return this.setServerTrustMode(args, callbackContext);
|
||||||
} else if ("setClientAuthMode".equals(action)) {
|
} else if ("setClientAuthMode".equals(action)) {
|
||||||
return this.setClientAuthMode(args, callbackContext);
|
return this.setClientAuthMode(args, callbackContext);
|
||||||
} else if ("disableRedirect".equals(action)) {
|
} else if ("abort".equals(action)) {
|
||||||
return this.disableRedirect(args, callbackContext);
|
return this.abort(args, callbackContext);
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -84,11 +95,16 @@ public class CordovaHttpPlugin extends CordovaPlugin {
|
|||||||
String url = args.getString(0);
|
String url = args.getString(0);
|
||||||
JSONObject headers = args.getJSONObject(1);
|
JSONObject headers = args.getJSONObject(1);
|
||||||
int timeout = args.getInt(2) * 1000;
|
int timeout = args.getInt(2) * 1000;
|
||||||
|
boolean followRedirect = args.getBoolean(3);
|
||||||
|
String responseType = args.getString(4);
|
||||||
|
|
||||||
CordovaHttpOperation request = new CordovaHttpOperation(method.toUpperCase(), url, headers, timeout,
|
Integer reqId = args.getInt(5);
|
||||||
this.followRedirects, this.tlsConfiguration, callbackContext);
|
CordovaObservableCallbackContext observableCallbackContext = new CordovaObservableCallbackContext(callbackContext, reqId);
|
||||||
|
|
||||||
cordova.getThreadPool().execute(request);
|
CordovaHttpOperation request = new CordovaHttpOperation(method.toUpperCase(), url, headers, timeout, followRedirect,
|
||||||
|
responseType, this.tlsConfiguration, observableCallbackContext);
|
||||||
|
|
||||||
|
startRequest(reqId, observableCallbackContext, request);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -101,26 +117,36 @@ public class CordovaHttpPlugin extends CordovaPlugin {
|
|||||||
String serializer = args.getString(2);
|
String serializer = args.getString(2);
|
||||||
JSONObject headers = args.getJSONObject(3);
|
JSONObject headers = args.getJSONObject(3);
|
||||||
int timeout = args.getInt(4) * 1000;
|
int timeout = args.getInt(4) * 1000;
|
||||||
|
boolean followRedirect = args.getBoolean(5);
|
||||||
|
String responseType = args.getString(6);
|
||||||
|
|
||||||
|
Integer reqId = args.getInt(7);
|
||||||
|
CordovaObservableCallbackContext observableCallbackContext = new CordovaObservableCallbackContext(callbackContext, reqId);
|
||||||
|
|
||||||
CordovaHttpOperation request = new CordovaHttpOperation(method.toUpperCase(), url, serializer, data, headers,
|
CordovaHttpOperation request = new CordovaHttpOperation(method.toUpperCase(), url, serializer, data, headers,
|
||||||
timeout, this.followRedirects, this.tlsConfiguration, callbackContext);
|
timeout, followRedirect, responseType, this.tlsConfiguration, observableCallbackContext);
|
||||||
|
|
||||||
cordova.getThreadPool().execute(request);
|
startRequest(reqId, observableCallbackContext, request);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean uploadFile(final JSONArray args, final CallbackContext callbackContext) throws JSONException {
|
private boolean uploadFiles(final JSONArray args, final CallbackContext callbackContext) throws JSONException {
|
||||||
String url = args.getString(0);
|
String url = args.getString(0);
|
||||||
JSONObject headers = args.getJSONObject(1);
|
JSONObject headers = args.getJSONObject(1);
|
||||||
String filePath = args.getString(2);
|
JSONArray filePaths = args.getJSONArray(2);
|
||||||
String uploadName = args.getString(3);
|
JSONArray uploadNames = args.getJSONArray(3);
|
||||||
int timeout = args.getInt(4) * 1000;
|
int timeout = args.getInt(4) * 1000;
|
||||||
|
boolean followRedirect = args.getBoolean(5);
|
||||||
|
String responseType = args.getString(6);
|
||||||
|
|
||||||
CordovaHttpUpload upload = new CordovaHttpUpload(url, headers, filePath, uploadName, timeout, this.followRedirects,
|
Integer reqId = args.getInt(7);
|
||||||
this.tlsConfiguration, callbackContext);
|
CordovaObservableCallbackContext observableCallbackContext = new CordovaObservableCallbackContext(callbackContext, reqId);
|
||||||
|
|
||||||
cordova.getThreadPool().execute(upload);
|
CordovaHttpUpload upload = new CordovaHttpUpload(url, headers, filePaths, uploadNames, timeout, followRedirect,
|
||||||
|
responseType, this.tlsConfiguration, this.cordova.getActivity().getApplicationContext(), observableCallbackContext);
|
||||||
|
|
||||||
|
startRequest(reqId, observableCallbackContext, upload);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -130,15 +156,27 @@ public class CordovaHttpPlugin extends CordovaPlugin {
|
|||||||
JSONObject headers = args.getJSONObject(1);
|
JSONObject headers = args.getJSONObject(1);
|
||||||
String filePath = args.getString(2);
|
String filePath = args.getString(2);
|
||||||
int timeout = args.getInt(3) * 1000;
|
int timeout = args.getInt(3) * 1000;
|
||||||
|
boolean followRedirect = args.getBoolean(4);
|
||||||
|
|
||||||
CordovaHttpDownload download = new CordovaHttpDownload(url, headers, filePath, timeout, this.followRedirects,
|
Integer reqId = args.getInt(5);
|
||||||
this.tlsConfiguration, callbackContext);
|
CordovaObservableCallbackContext observableCallbackContext = new CordovaObservableCallbackContext(callbackContext, reqId);
|
||||||
|
|
||||||
cordova.getThreadPool().execute(download);
|
CordovaHttpDownload download = new CordovaHttpDownload(url, headers, filePath, timeout, followRedirect,
|
||||||
|
this.tlsConfiguration, observableCallbackContext);
|
||||||
|
|
||||||
|
startRequest(reqId, observableCallbackContext, download);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void startRequest(Integer reqId, CordovaObservableCallbackContext observableCallbackContext, CordovaHttpBase request) {
|
||||||
|
synchronized (reqMapLock) {
|
||||||
|
observableCallbackContext.setObserver(this);
|
||||||
|
Future<?> task = cordova.getThreadPool().submit(request);
|
||||||
|
this.addReq(reqId, task, observableCallbackContext);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private boolean setServerTrustMode(final JSONArray args, final CallbackContext callbackContext) throws JSONException {
|
private boolean setServerTrustMode(final JSONArray args, final CallbackContext callbackContext) throws JSONException {
|
||||||
CordovaServerTrust runnable = new CordovaServerTrust(args.getString(0), this.cordova.getActivity(),
|
CordovaServerTrust runnable = new CordovaServerTrust(args.getString(0), this.cordova.getActivity(),
|
||||||
this.tlsConfiguration, callbackContext);
|
this.tlsConfiguration, callbackContext);
|
||||||
@@ -149,19 +187,55 @@ public class CordovaHttpPlugin extends CordovaPlugin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private boolean setClientAuthMode(final JSONArray args, final CallbackContext callbackContext) throws JSONException {
|
private boolean setClientAuthMode(final JSONArray args, final CallbackContext callbackContext) throws JSONException {
|
||||||
CordovaClientAuth runnable = new CordovaClientAuth(args.getString(0), args.getString(1), this.cordova.getActivity(),
|
byte[] pkcs = args.isNull(2) ? null : Base64.decode(args.getString(2), Base64.DEFAULT);
|
||||||
this.cordova.getContext(), this.tlsConfiguration, callbackContext);
|
|
||||||
|
CordovaClientAuth runnable = new CordovaClientAuth(args.getString(0), args.isNull(1) ? null : args.getString(1),
|
||||||
|
pkcs, args.getString(3), this.cordova.getActivity(), this.cordova.getActivity().getApplicationContext(),
|
||||||
|
this.tlsConfiguration, callbackContext);
|
||||||
|
|
||||||
cordova.getThreadPool().execute(runnable);
|
cordova.getThreadPool().execute(runnable);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean disableRedirect(final JSONArray args, final CallbackContext callbackContext) throws JSONException {
|
private boolean abort(final JSONArray args, final CallbackContext callbackContext) throws JSONException {
|
||||||
this.followRedirects = !args.getBoolean(0);
|
int reqId = args.getInt(0);
|
||||||
|
boolean result = false;
|
||||||
|
// NOTE no synchronized (reqMapLock), since even if the req was already removed from reqMap,
|
||||||
|
// the worst that would happen calling task.cancel(true) is a result of false
|
||||||
|
// (i.e. same result as locking & not finding the req in reqMap)
|
||||||
|
Future<?> task = this.reqMap.get(reqId);
|
||||||
|
|
||||||
callbackContext.success();
|
if (task != null && !task.isDone()) {
|
||||||
|
result = task.cancel(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
callbackContext.success(new JSONObject().put("aborted", result));
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void addReq(final Integer reqId, final Future<?> task, final CordovaObservableCallbackContext observableCallbackContext) {
|
||||||
|
synchronized (reqMapLock) {
|
||||||
|
if (!task.isDone()){
|
||||||
|
this.reqMap.put(reqId, task);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void removeReq(final Integer reqId) {
|
||||||
|
synchronized (reqMapLock) {
|
||||||
|
this.reqMap.remove(reqId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void update(Observable o, Object arg) {
|
||||||
|
synchronized (reqMapLock) {
|
||||||
|
CordovaObservableCallbackContext c = (CordovaObservableCallbackContext) arg;
|
||||||
|
if (c.getCallbackContext().isFinished()) {
|
||||||
|
removeReq(c.getRequestId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
package com.silkimen.cordovahttp;
|
package com.silkimen.cordovahttp;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@@ -9,15 +11,18 @@ import org.json.JSONObject;
|
|||||||
|
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
import android.util.Base64;
|
||||||
|
|
||||||
class CordovaHttpResponse {
|
class CordovaHttpResponse {
|
||||||
private int status;
|
private int status;
|
||||||
private String url;
|
private String url;
|
||||||
private Map<String, List<String>> headers;
|
private Map<String, List<String>> headers;
|
||||||
private String body;
|
private String body;
|
||||||
|
private byte[] rawData;
|
||||||
private JSONObject fileEntry;
|
private JSONObject fileEntry;
|
||||||
private boolean hasFailed;
|
private boolean hasFailed;
|
||||||
private boolean isFileOperation;
|
private boolean isFileOperation;
|
||||||
|
private boolean isRawResponse;
|
||||||
private String error;
|
private String error;
|
||||||
|
|
||||||
public void setStatus(int status) {
|
public void setStatus(int status) {
|
||||||
@@ -36,6 +41,11 @@ class CordovaHttpResponse {
|
|||||||
this.body = body;
|
this.body = body;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setData(byte[] rawData) {
|
||||||
|
this.isRawResponse = true;
|
||||||
|
this.rawData = rawData;
|
||||||
|
}
|
||||||
|
|
||||||
public void setFileEntry(JSONObject entry) {
|
public void setFileEntry(JSONObject entry) {
|
||||||
this.isFileOperation = true;
|
this.isFileOperation = true;
|
||||||
this.fileEntry = entry;
|
this.fileEntry = entry;
|
||||||
@@ -56,13 +66,17 @@ class CordovaHttpResponse {
|
|||||||
json.put("status", this.status);
|
json.put("status", this.status);
|
||||||
json.put("url", this.url);
|
json.put("url", this.url);
|
||||||
|
|
||||||
|
if (this.headers != null && !this.headers.isEmpty()) {
|
||||||
|
json.put("headers", new JSONObject(getFilteredHeaders()));
|
||||||
|
}
|
||||||
|
|
||||||
if (this.hasFailed) {
|
if (this.hasFailed) {
|
||||||
json.put("error", this.error);
|
json.put("error", this.error);
|
||||||
} else if (this.isFileOperation) {
|
} else if (this.isFileOperation) {
|
||||||
json.put("headers", new JSONObject(getFilteredHeaders()));
|
|
||||||
json.put("file", this.fileEntry);
|
json.put("file", this.fileEntry);
|
||||||
|
} else if (this.isRawResponse) {
|
||||||
|
json.put("data", Base64.encodeToString(this.rawData, Base64.DEFAULT));
|
||||||
} else {
|
} else {
|
||||||
json.put("headers", new JSONObject(getFilteredHeaders()));
|
|
||||||
json.put("data", this.body);
|
json.put("data", this.body);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -72,10 +86,6 @@ class CordovaHttpResponse {
|
|||||||
private Map<String, String> getFilteredHeaders() throws JSONException {
|
private Map<String, String> getFilteredHeaders() throws JSONException {
|
||||||
Map<String, String> filteredHeaders = new HashMap<String, String>();
|
Map<String, String> filteredHeaders = new HashMap<String, String>();
|
||||||
|
|
||||||
if (this.headers == null || this.headers.isEmpty()) {
|
|
||||||
return filteredHeaders;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (Map.Entry<String, List<String>> entry : this.headers.entrySet()) {
|
for (Map.Entry<String, List<String>> entry : this.headers.entrySet()) {
|
||||||
String key = entry.getKey();
|
String key = entry.getKey();
|
||||||
List<String> value = entry.getValue();
|
List<String> value = entry.getValue();
|
||||||
|
|||||||
@@ -1,43 +1,91 @@
|
|||||||
package com.silkimen.cordovahttp;
|
package com.silkimen.cordovahttp;
|
||||||
|
|
||||||
|
import android.content.ContentResolver;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.database.Cursor;
|
||||||
|
import android.net.Uri;
|
||||||
|
import android.provider.OpenableColumns;
|
||||||
import android.webkit.MimeTypeMap;
|
import android.webkit.MimeTypeMap;
|
||||||
|
|
||||||
import com.silkimen.http.HttpRequest;
|
import com.silkimen.http.HttpRequest;
|
||||||
|
import com.silkimen.http.TLSConfiguration;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.io.InputStream;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
|
|
||||||
import javax.net.ssl.HostnameVerifier;
|
import javax.net.ssl.HostnameVerifier;
|
||||||
import javax.net.ssl.SSLSocketFactory;
|
import javax.net.ssl.SSLSocketFactory;
|
||||||
|
|
||||||
import com.silkimen.http.TLSConfiguration;
|
import org.json.JSONArray;
|
||||||
|
|
||||||
import org.apache.cordova.CallbackContext;
|
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
|
|
||||||
class CordovaHttpUpload extends CordovaHttpBase {
|
class CordovaHttpUpload extends CordovaHttpBase {
|
||||||
private String filePath;
|
private JSONArray filePaths;
|
||||||
private String uploadName;
|
private JSONArray uploadNames;
|
||||||
|
private Context applicationContext;
|
||||||
|
|
||||||
public CordovaHttpUpload(String url, JSONObject headers, String filePath, String uploadName, int timeout,
|
public CordovaHttpUpload(String url, JSONObject headers, JSONArray filePaths, JSONArray uploadNames, int timeout,
|
||||||
boolean followRedirects, TLSConfiguration tlsConfiguration, CallbackContext callbackContext) {
|
boolean followRedirects, String responseType, TLSConfiguration tlsConfiguration,
|
||||||
|
Context applicationContext, CordovaObservableCallbackContext callbackContext) {
|
||||||
|
|
||||||
super("POST", url, headers, timeout, followRedirects, tlsConfiguration, callbackContext);
|
super("POST", url, headers, timeout, followRedirects, responseType, tlsConfiguration, callbackContext);
|
||||||
this.filePath = filePath;
|
this.filePaths = filePaths;
|
||||||
this.uploadName = uploadName;
|
this.uploadNames = uploadNames;
|
||||||
|
this.applicationContext = applicationContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void sendBody(HttpRequest request) throws Exception {
|
protected void sendBody(HttpRequest request) throws Exception {
|
||||||
int filenameIndex = this.filePath.lastIndexOf('/');
|
for (int i = 0; i < this.filePaths.length(); ++i) {
|
||||||
String filename = this.filePath.substring(filenameIndex + 1);
|
String uploadName = this.uploadNames.getString(i);
|
||||||
|
String filePath = this.filePaths.getString(i);
|
||||||
|
|
||||||
int extIndex = this.filePath.lastIndexOf('.');
|
Uri fileUri = Uri.parse(filePath);
|
||||||
String ext = this.filePath.substring(extIndex + 1);
|
|
||||||
|
// File Scheme
|
||||||
|
if (ContentResolver.SCHEME_FILE.equals(fileUri.getScheme())) {
|
||||||
|
File file = new File(new URI(filePath));
|
||||||
|
String fileName = file.getName().trim();
|
||||||
|
String mimeType = this.getMimeTypeFromFileName(fileName);
|
||||||
|
|
||||||
|
request.part(uploadName, fileName, mimeType, file);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Content Scheme
|
||||||
|
if (ContentResolver.SCHEME_CONTENT.equals(fileUri.getScheme())) {
|
||||||
|
InputStream inputStream = this.applicationContext.getContentResolver().openInputStream(fileUri);
|
||||||
|
String fileName = this.getFileNameFromContentScheme(fileUri, this.applicationContext).trim();
|
||||||
|
String mimeType = this.getMimeTypeFromFileName(fileName);
|
||||||
|
|
||||||
|
request.part(uploadName, fileName, mimeType, inputStream);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getFileNameFromContentScheme(Uri contentSchemeUri, Context applicationContext) {
|
||||||
|
Cursor returnCursor = applicationContext.getContentResolver().query(contentSchemeUri, null, null, null, null);
|
||||||
|
|
||||||
|
if (returnCursor == null || !returnCursor.moveToFirst()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
int nameIndex = returnCursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);
|
||||||
|
String fileName = returnCursor.getString(nameIndex);
|
||||||
|
returnCursor.close();
|
||||||
|
|
||||||
|
return fileName;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getMimeTypeFromFileName(String fileName) {
|
||||||
|
if (fileName == null || !fileName.contains(".")) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
MimeTypeMap mimeTypeMap = MimeTypeMap.getSingleton();
|
MimeTypeMap mimeTypeMap = MimeTypeMap.getSingleton();
|
||||||
String mimeType = mimeTypeMap.getMimeTypeFromExtension(ext);
|
int extIndex = fileName.lastIndexOf('.') + 1;
|
||||||
|
String extension = fileName.substring(extIndex).toLowerCase();
|
||||||
|
|
||||||
request.part(this.uploadName, filename, mimeType, new File(new URI(this.filePath)));
|
return mimeTypeMap.getMimeTypeFromExtension(extension);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,58 @@
|
|||||||
|
package com.silkimen.cordovahttp;
|
||||||
|
|
||||||
|
import org.apache.cordova.CallbackContext;
|
||||||
|
import org.json.JSONObject;
|
||||||
|
|
||||||
|
import java.util.Observer;
|
||||||
|
|
||||||
|
public class CordovaObservableCallbackContext {
|
||||||
|
|
||||||
|
private CallbackContext callbackContext;
|
||||||
|
private Integer requestId;
|
||||||
|
private Observer observer;
|
||||||
|
|
||||||
|
public CordovaObservableCallbackContext(CallbackContext callbackContext, Integer requestId) {
|
||||||
|
this.callbackContext = callbackContext;
|
||||||
|
this.requestId = requestId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void success(JSONObject message) {
|
||||||
|
this.callbackContext.success(message);
|
||||||
|
this.notifyObserver();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void error(JSONObject message) {
|
||||||
|
this.callbackContext.error(message);
|
||||||
|
this.notifyObserver();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getRequestId() {
|
||||||
|
return this.requestId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CallbackContext getCallbackContext() {
|
||||||
|
return callbackContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Observer getObserver() {
|
||||||
|
return observer;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void notifyObserver() {
|
||||||
|
if(this.observer != null){
|
||||||
|
this.observer.update(null, this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set an observer that is notified, when {@link #success(JSONObject)}
|
||||||
|
* or {@link #error(JSONObject)} are called.
|
||||||
|
*
|
||||||
|
* NOTE the observer is notified with
|
||||||
|
* <pre>observer.update(null, cordovaObservableCallbackContext)</pre>
|
||||||
|
* @param observer
|
||||||
|
*/
|
||||||
|
public void setObserver(Observer observer) {
|
||||||
|
this.observer = observer;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -10,21 +10,28 @@ import java.nio.charset.MalformedInputException;
|
|||||||
public class HttpBodyDecoder {
|
public class HttpBodyDecoder {
|
||||||
private static final String[] ACCEPTED_CHARSETS = new String[] { "UTF-8", "ISO-8859-1" };
|
private static final String[] ACCEPTED_CHARSETS = new String[] { "UTF-8", "ISO-8859-1" };
|
||||||
|
|
||||||
public static String decodeBody(ByteBuffer rawOutput, String charsetName)
|
public static String decodeBody(byte[] body, String charsetName)
|
||||||
|
throws CharacterCodingException, MalformedInputException {
|
||||||
|
|
||||||
|
return decodeBody(ByteBuffer.wrap(body), charsetName);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String decodeBody(ByteBuffer body, String charsetName)
|
||||||
throws CharacterCodingException, MalformedInputException {
|
throws CharacterCodingException, MalformedInputException {
|
||||||
|
|
||||||
if (charsetName == null) {
|
if (charsetName == null) {
|
||||||
return tryDecodeByteBuffer(rawOutput);
|
return tryDecodeByteBuffer(body);
|
||||||
|
} else {
|
||||||
|
return decodeByteBuffer(body, charsetName);
|
||||||
}
|
}
|
||||||
|
|
||||||
return decodeByteBuffer(rawOutput, charsetName);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String tryDecodeByteBuffer(ByteBuffer rawOutput) throws CharacterCodingException, MalformedInputException {
|
private static String tryDecodeByteBuffer(ByteBuffer buffer)
|
||||||
|
throws CharacterCodingException, MalformedInputException {
|
||||||
|
|
||||||
for (int i = 0; i < ACCEPTED_CHARSETS.length - 1; i++) {
|
for (int i = 0; i < ACCEPTED_CHARSETS.length - 1; i++) {
|
||||||
try {
|
try {
|
||||||
return decodeByteBuffer(rawOutput, ACCEPTED_CHARSETS[i]);
|
return decodeByteBuffer(buffer, ACCEPTED_CHARSETS[i]);
|
||||||
} catch (MalformedInputException e) {
|
} catch (MalformedInputException e) {
|
||||||
continue;
|
continue;
|
||||||
} catch (CharacterCodingException e) {
|
} catch (CharacterCodingException e) {
|
||||||
@@ -32,13 +39,13 @@ public class HttpBodyDecoder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return decodeBody(rawOutput, ACCEPTED_CHARSETS[ACCEPTED_CHARSETS.length - 1]);
|
return decodeBody(buffer, ACCEPTED_CHARSETS[ACCEPTED_CHARSETS.length - 1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String decodeByteBuffer(ByteBuffer rawOutput, String charsetName)
|
private static String decodeByteBuffer(ByteBuffer buffer, String charsetName)
|
||||||
throws CharacterCodingException, MalformedInputException {
|
throws CharacterCodingException, MalformedInputException {
|
||||||
|
|
||||||
return createCharsetDecoder(charsetName).decode(rawOutput).toString();
|
return createCharsetDecoder(charsetName).decode(buffer).toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static CharsetDecoder createCharsetDecoder(String charsetName) {
|
private static CharsetDecoder createCharsetDecoder(String charsetName) {
|
||||||
|
|||||||
@@ -1,26 +0,0 @@
|
|||||||
package com.silkimen.http;
|
|
||||||
|
|
||||||
import okhttp3.OkHttpClient;
|
|
||||||
import okhttp3.OkUrlFactory;
|
|
||||||
|
|
||||||
import java.net.URL;
|
|
||||||
import java.net.HttpURLConnection;
|
|
||||||
import java.net.URLStreamHandler;
|
|
||||||
import java.net.Proxy;
|
|
||||||
|
|
||||||
public class OkConnectionFactory implements HttpRequest.ConnectionFactory {
|
|
||||||
private final OkHttpClient client = new OkHttpClient();
|
|
||||||
|
|
||||||
public HttpURLConnection create(URL url) {
|
|
||||||
OkUrlFactory urlFactory = new OkUrlFactory(this.client);
|
|
||||||
|
|
||||||
return (HttpURLConnection) urlFactory.open(url);
|
|
||||||
}
|
|
||||||
|
|
||||||
public HttpURLConnection create(URL url, Proxy proxy) {
|
|
||||||
OkHttpClient clientWithProxy = new OkHttpClient.Builder().proxy(proxy).build();
|
|
||||||
OkUrlFactory urlFactory = new OkUrlFactory(clientWithProxy);
|
|
||||||
|
|
||||||
return (HttpURLConnection) urlFactory.open(url);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -2,19 +2,13 @@ package com.silkimen.http;
|
|||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.security.GeneralSecurityException;
|
import java.security.GeneralSecurityException;
|
||||||
import java.security.KeyStore;
|
|
||||||
import java.security.SecureRandom;
|
import java.security.SecureRandom;
|
||||||
import java.security.cert.X509Certificate;
|
|
||||||
|
|
||||||
import javax.net.ssl.HostnameVerifier;
|
import javax.net.ssl.HostnameVerifier;
|
||||||
import javax.net.ssl.KeyManager;
|
import javax.net.ssl.KeyManager;
|
||||||
import javax.net.ssl.KeyManagerFactory;
|
|
||||||
import javax.net.ssl.SSLContext;
|
import javax.net.ssl.SSLContext;
|
||||||
import javax.net.ssl.SSLSession;
|
|
||||||
import javax.net.ssl.SSLSocketFactory;
|
import javax.net.ssl.SSLSocketFactory;
|
||||||
import javax.net.ssl.TrustManager;
|
import javax.net.ssl.TrustManager;
|
||||||
import javax.net.ssl.TrustManagerFactory;
|
|
||||||
import javax.net.ssl.X509TrustManager;
|
|
||||||
|
|
||||||
import com.silkimen.http.TLSSocketFactory;
|
import com.silkimen.http.TLSSocketFactory;
|
||||||
|
|
||||||
|
|||||||
Vendored
+153
-29
@@ -3,6 +3,8 @@ var pluginId = module.id.slice(0, module.id.lastIndexOf('.'));
|
|||||||
var cordovaProxy = require('cordova/exec/proxy');
|
var cordovaProxy = require('cordova/exec/proxy');
|
||||||
var jsUtil = require(pluginId + '.js-util');
|
var jsUtil = require(pluginId + '.js-util');
|
||||||
|
|
||||||
|
var reqMap = {};
|
||||||
|
|
||||||
function serializeJsonData(data) {
|
function serializeJsonData(data) {
|
||||||
try {
|
try {
|
||||||
return JSON.stringify(data);
|
return JSON.stringify(data);
|
||||||
@@ -20,7 +22,7 @@ function serializePrimitive(key, value) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function serializeArray(key, values) {
|
function serializeArray(key, values) {
|
||||||
return values.map(function(value) {
|
return values.map(function (value) {
|
||||||
return encodeURIComponent(key) + '[]=' + encodeURIComponent(value);
|
return encodeURIComponent(key) + '[]=' + encodeURIComponent(value);
|
||||||
}).join('&');
|
}).join('&');
|
||||||
}
|
}
|
||||||
@@ -28,7 +30,7 @@ function serializeArray(key, values) {
|
|||||||
function serializeParams(params) {
|
function serializeParams(params) {
|
||||||
if (params === null) return '';
|
if (params === null) return '';
|
||||||
|
|
||||||
return Object.keys(params).map(function(key) {
|
return Object.keys(params).map(function (key) {
|
||||||
if (jsUtil.getTypeOf(params[key]) === 'Array') {
|
if (jsUtil.getTypeOf(params[key]) === 'Array') {
|
||||||
return serializeArray(key, params[key]);
|
return serializeArray(key, params[key]);
|
||||||
}
|
}
|
||||||
@@ -37,6 +39,39 @@ function serializeParams(params) {
|
|||||||
}).join('&');
|
}).join('&');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function decodeB64(dataString) {
|
||||||
|
var binaryString = atob(dataString);
|
||||||
|
var bytes = new Uint8Array(binaryString.length);
|
||||||
|
|
||||||
|
for (var i = 0; i < binaryString.length; ++i) {
|
||||||
|
bytes[i] = binaryString.charCodeAt(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
return bytes.buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
function processMultipartData(data) {
|
||||||
|
if (!data) return null;
|
||||||
|
|
||||||
|
var fd = new FormData();
|
||||||
|
|
||||||
|
for (var i = 0; i < data.buffers.length; ++i) {
|
||||||
|
var buffer = data.buffers[i];
|
||||||
|
var name = data.names[i];
|
||||||
|
var fileName = data.fileNames[i];
|
||||||
|
var type = data.types[i];
|
||||||
|
|
||||||
|
if (fileName) {
|
||||||
|
fd.append(name, new Blob([decodeB64(buffer)], { type: type }), fileName);
|
||||||
|
} else {
|
||||||
|
// we assume it's plain text if no filename was given
|
||||||
|
fd.append(name, atob(buffer));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return fd;
|
||||||
|
}
|
||||||
|
|
||||||
function deserializeResponseHeaders(headers) {
|
function deserializeResponseHeaders(headers) {
|
||||||
var headerMap = {};
|
var headerMap = {};
|
||||||
var arr = headers.trim().split(/[\r\n]+/);
|
var arr = headers.trim().split(/[\r\n]+/);
|
||||||
@@ -52,11 +87,19 @@ function deserializeResponseHeaders(headers) {
|
|||||||
return headerMap;
|
return headerMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getResponseData(xhr) {
|
||||||
|
if (xhr.responseType !== 'text' || jsUtil.getTypeOf(xhr.responseText) !== 'String') {
|
||||||
|
return xhr.response;
|
||||||
|
}
|
||||||
|
|
||||||
|
return xhr.responseText;
|
||||||
|
}
|
||||||
|
|
||||||
function createXhrSuccessObject(xhr) {
|
function createXhrSuccessObject(xhr) {
|
||||||
return {
|
return {
|
||||||
url: xhr.responseURL,
|
url: xhr.responseURL,
|
||||||
status: xhr.status,
|
status: xhr.status,
|
||||||
data: jsUtil.getTypeOf(xhr.responseText) === 'String' ? xhr.responseText : xhr.response,
|
data: getResponseData(xhr),
|
||||||
headers: deserializeResponseHeaders(xhr.getAllResponseHeaders())
|
headers: deserializeResponseHeaders(xhr.getAllResponseHeaders())
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -65,7 +108,7 @@ function createXhrFailureObject(xhr) {
|
|||||||
var obj = {};
|
var obj = {};
|
||||||
|
|
||||||
obj.headers = xhr.getAllResponseHeaders();
|
obj.headers = xhr.getAllResponseHeaders();
|
||||||
obj.error = jsUtil.getTypeOf(xhr.responseText) === 'String' ? xhr.responseText : xhr.response;
|
obj.error = getResponseData(xhr);
|
||||||
obj.error = obj.error || 'advanced-http: please check browser console for error messages';
|
obj.error = obj.error || 'advanced-http: please check browser console for error messages';
|
||||||
|
|
||||||
if (xhr.responseURL) obj.url = xhr.responseURL;
|
if (xhr.responseURL) obj.url = xhr.responseURL;
|
||||||
@@ -74,10 +117,17 @@ function createXhrFailureObject(xhr) {
|
|||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function injectRequestIdHandler(reqId, cb) {
|
||||||
|
return function (response) {
|
||||||
|
delete reqMap[reqId];
|
||||||
|
cb(response);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function getHeaderValue(headers, headerName) {
|
function getHeaderValue(headers, headerName) {
|
||||||
let result = null;
|
let result = null;
|
||||||
|
|
||||||
Object.keys(headers).forEach(function(key) {
|
Object.keys(headers).forEach(function (key) {
|
||||||
if (key.toLowerCase() === headerName.toLowerCase()) {
|
if (key.toLowerCase() === headerName.toLowerCase()) {
|
||||||
result = headers[key];
|
result = headers[key];
|
||||||
}
|
}
|
||||||
@@ -93,7 +143,7 @@ function setDefaultContentType(headers, contentType) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function setHeaders(xhr, headers) {
|
function setHeaders(xhr, headers) {
|
||||||
Object.keys(headers).forEach(function(key) {
|
Object.keys(headers).forEach(function (key) {
|
||||||
if (key.toLowerCase() === 'cookie') return;
|
if (key.toLowerCase() === 'cookie') return;
|
||||||
|
|
||||||
xhr.setRequestHeader(key, headers[key]);
|
xhr.setRequestHeader(key, headers[key]);
|
||||||
@@ -101,20 +151,41 @@ function setHeaders(xhr, headers) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function sendRequest(method, withData, opts, success, failure) {
|
function sendRequest(method, withData, opts, success, failure) {
|
||||||
var data = withData ? opts[1] : null;
|
var data, serializer, headers, timeout, followRedirect, responseType, reqId;
|
||||||
var params = withData ? null : serializeParams(opts[1]);
|
var url = opts[0];
|
||||||
var serializer = withData ? opts[2] : null;
|
|
||||||
var headers = withData ? opts[3] : opts[2];
|
if (withData) {
|
||||||
var timeout = withData ? opts[4] : opts[3];
|
data = opts[1];
|
||||||
var url = params ? opts[0] + '?' + params : opts[0];
|
serializer = opts[2];
|
||||||
|
headers = opts[3];
|
||||||
|
timeout = opts[4];
|
||||||
|
followRedirect = opts[5];
|
||||||
|
responseType = opts[6];
|
||||||
|
reqId = opts[7];
|
||||||
|
} else {
|
||||||
|
headers = opts[1];
|
||||||
|
timeout = opts[2];
|
||||||
|
followRedirect = opts[3];
|
||||||
|
responseType = opts[4];
|
||||||
|
reqId = opts[5];
|
||||||
|
}
|
||||||
|
|
||||||
|
var onSuccess = injectRequestIdHandler(reqId, success);
|
||||||
|
var onFail = injectRequestIdHandler(reqId, failure);
|
||||||
|
|
||||||
var processedData = null;
|
var processedData = null;
|
||||||
var xhr = new XMLHttpRequest();
|
var xhr = new XMLHttpRequest();
|
||||||
|
|
||||||
|
reqMap[reqId] = xhr;
|
||||||
|
|
||||||
xhr.open(method, url);
|
xhr.open(method, url);
|
||||||
|
|
||||||
if (headers.Cookie && headers.Cookie.length > 0) {
|
if (headers.Cookie && headers.Cookie.length > 0) {
|
||||||
return failure('advanced-http: custom cookies not supported on browser platform');
|
return onFail('advanced-http: custom cookies not supported on browser platform');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!followRedirect) {
|
||||||
|
return onFail('advanced-http: disabling follow redirect not supported on browser platform');
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (serializer) {
|
switch (serializer) {
|
||||||
@@ -123,7 +194,7 @@ function sendRequest(method, withData, opts, success, failure) {
|
|||||||
processedData = serializeJsonData(data);
|
processedData = serializeJsonData(data);
|
||||||
|
|
||||||
if (processedData === null) {
|
if (processedData === null) {
|
||||||
return failure('advanced-http: failed serializing data');
|
return onFail('advanced-http: failed serializing data');
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@@ -137,50 +208,106 @@ function sendRequest(method, withData, opts, success, failure) {
|
|||||||
setDefaultContentType(headers, 'application/x-www-form-urlencoded');
|
setDefaultContentType(headers, 'application/x-www-form-urlencoded');
|
||||||
processedData = serializeParams(data);
|
processedData = serializeParams(data);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 'multipart':
|
||||||
|
const contentType = getHeaderValue(headers, 'Content-Type');
|
||||||
|
|
||||||
|
// intentionally don't set a default content type
|
||||||
|
// it's set by the browser together with the content disposition string
|
||||||
|
if (contentType) {
|
||||||
|
headers['Content-Type'] = contentType;
|
||||||
|
}
|
||||||
|
|
||||||
|
processedData = processMultipartData(data);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'raw':
|
||||||
|
setDefaultContentType(headers, 'application/octet-stream');
|
||||||
|
processedData = data;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// requesting text instead of JSON because it's parsed in the response handler
|
||||||
|
xhr.responseType = responseType === 'json' ? 'text' : responseType;
|
||||||
xhr.timeout = timeout * 1000;
|
xhr.timeout = timeout * 1000;
|
||||||
setHeaders(xhr, headers);
|
setHeaders(xhr, headers);
|
||||||
|
|
||||||
xhr.onerror = xhr.ontimeout = function () {
|
xhr.onerror = function () {
|
||||||
return failure(createXhrFailureObject(xhr));
|
return onFail(createXhrFailureObject(xhr));
|
||||||
|
};
|
||||||
|
|
||||||
|
xhr.onabort = function () {
|
||||||
|
return onFail({
|
||||||
|
status: -8,
|
||||||
|
error: 'Request was aborted',
|
||||||
|
url: url,
|
||||||
|
headers: {}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
xhr.ontimeout = function () {
|
||||||
|
return onFail({
|
||||||
|
status: -4,
|
||||||
|
error: 'Request timed out',
|
||||||
|
url: url,
|
||||||
|
headers: {}
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
xhr.onload = function () {
|
xhr.onload = function () {
|
||||||
if (xhr.readyState !== xhr.DONE) return;
|
if (xhr.readyState !== xhr.DONE) return;
|
||||||
|
|
||||||
if (xhr.status < 200 || xhr.status > 299) {
|
if (xhr.status < 200 || xhr.status > 299) {
|
||||||
return failure(createXhrFailureObject(xhr));
|
return onFail(createXhrFailureObject(xhr));
|
||||||
}
|
}
|
||||||
|
|
||||||
return success(createXhrSuccessObject(xhr));
|
return onSuccess(createXhrSuccessObject(xhr));
|
||||||
};
|
};
|
||||||
|
|
||||||
xhr.send(processedData);
|
xhr.send(processedData);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function abort(opts, success, failure) {
|
||||||
|
var reqId = opts[0];
|
||||||
|
var result = false;
|
||||||
|
|
||||||
|
var xhr = reqMap[reqId];
|
||||||
|
if(xhr && xhr.readyState !== xhr.DONE){
|
||||||
|
xhr.abort();
|
||||||
|
result = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
success({aborted: result});
|
||||||
|
}
|
||||||
|
|
||||||
var browserInterface = {
|
var browserInterface = {
|
||||||
post: function (success, failure, opts) {
|
|
||||||
return sendRequest('post', true, opts, success, failure);
|
|
||||||
},
|
|
||||||
get: function (success, failure, opts) {
|
get: function (success, failure, opts) {
|
||||||
return sendRequest('get', false, opts, success, failure);
|
return sendRequest('get', false, opts, success, failure);
|
||||||
},
|
},
|
||||||
|
head: function (success, failure, opts) {
|
||||||
|
return sendRequest('head', false, opts, success, failure);
|
||||||
|
},
|
||||||
|
delete: function (success, failure, opts) {
|
||||||
|
return sendRequest('delete', false, opts, success, failure);
|
||||||
|
},
|
||||||
|
post: function (success, failure, opts) {
|
||||||
|
return sendRequest('post', true, opts, success, failure);
|
||||||
|
},
|
||||||
put: function (success, failure, opts) {
|
put: function (success, failure, opts) {
|
||||||
return sendRequest('put', true, opts, success, failure);
|
return sendRequest('put', true, opts, success, failure);
|
||||||
},
|
},
|
||||||
patch: function (success, failure, opts) {
|
patch: function (success, failure, opts) {
|
||||||
return sendRequest('patch', true, opts, success, failure);
|
return sendRequest('patch', true, opts, success, failure);
|
||||||
},
|
},
|
||||||
delete: function (success, failure, opts) {
|
abort: function (success, failure, opts) {
|
||||||
return sendRequest('delete', false, opts, success, failure);
|
return abort(opts, success, failure);
|
||||||
},
|
|
||||||
head: function (success, failure, opts) {
|
|
||||||
return sendRequest('head', false, opts, success, failure);
|
|
||||||
},
|
},
|
||||||
uploadFile: function (success, failure, opts) {
|
uploadFile: function (success, failure, opts) {
|
||||||
return failure('advanced-http: function "uploadFile" not supported on browser platform');
|
return failure('advanced-http: function "uploadFile" not supported on browser platform');
|
||||||
},
|
},
|
||||||
|
uploadFiles: function (success, failure, opts) {
|
||||||
|
return failure('advanced-http: function "uploadFiles" not supported on browser platform');
|
||||||
|
},
|
||||||
downloadFile: function (success, failure, opts) {
|
downloadFile: function (success, failure, opts) {
|
||||||
return failure('advanced-http: function "downloadFile" not supported on browser platform');
|
return failure('advanced-http: function "downloadFile" not supported on browser platform');
|
||||||
},
|
},
|
||||||
@@ -189,9 +316,6 @@ var browserInterface = {
|
|||||||
},
|
},
|
||||||
setClientAuthMode: function (success, failure, opts) {
|
setClientAuthMode: function (success, failure, opts) {
|
||||||
return failure('advanced-http: function "setClientAuthMode" not supported on browser platform');
|
return failure('advanced-http: function "setClientAuthMode" not supported on browser platform');
|
||||||
},
|
|
||||||
disableRedirect: function (success, failure, opts) {
|
|
||||||
return failure('advanced-http: function "disableRedirect" not supported on browser platform');
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -290,6 +290,64 @@ NS_ASSUME_NONNULL_BEGIN
|
|||||||
success:(nullable void (^)(NSURLSessionDataTask *task, id _Nullable responseObject))success
|
success:(nullable void (^)(NSURLSessionDataTask *task, id _Nullable responseObject))success
|
||||||
failure:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSError *error))failure;
|
failure:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSError *error))failure;
|
||||||
|
|
||||||
|
/**
|
||||||
|
Creates and runs an `NSURLSessionDataTask` with a multipart request using given HTTP method.
|
||||||
|
|
||||||
|
@param HTTPMethod The HTTP method used to create the request.
|
||||||
|
@param URLString The URL string used to create the request URL.
|
||||||
|
@param parameters The parameters to be encoded according to the client request serializer.
|
||||||
|
@param block A block that takes a single argument and appends data to the HTTP body. The block argument is an object adopting the `AFMultipartFormData` protocol.
|
||||||
|
@param uploadProgress A block object to be executed when the upload progress is updated. Note this block is called on the session queue, not the main queue.
|
||||||
|
@param success A block object to be executed when the task finishes successfully. This block has no return value and takes two arguments: the data task, and the response object created by the client response serializer.
|
||||||
|
@param failure A block object to be executed when the task finishes unsuccessfully, or that finishes successfully, but encountered an error while parsing the response data. This block has no return value and takes a two arguments: the data task and the error describing the network or parsing error that occurred.
|
||||||
|
|
||||||
|
@see -dataTaskWithRequest:uploadProgress:downloadProgress:completionHandler:
|
||||||
|
*/
|
||||||
|
- (nullable NSURLSessionDataTask *)uploadTaskWithHTTPMethod:(NSString *)HTTPMethod
|
||||||
|
URLString:(NSString *)URLString
|
||||||
|
parameters:(nullable id)parameters
|
||||||
|
constructingBodyWithBlock:(nullable void (^)(id <AFMultipartFormData> formData))block
|
||||||
|
progress:(nullable void (^)(NSProgress *uploadProgress))uploadProgress
|
||||||
|
success:(nullable void (^)(NSURLSessionDataTask *task, id _Nullable responseObject))success
|
||||||
|
failure:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSError *error))failure;
|
||||||
|
|
||||||
|
/**
|
||||||
|
Creates and runs an `NSURLSessionDataTask` with given HTTP method.
|
||||||
|
|
||||||
|
@param URLString The URL string used to create the request URL.
|
||||||
|
@param parameters The parameters to be encoded according to the client request serializer.
|
||||||
|
@param uploadProgress A block object to be executed when the upload progress is updated. Note this block is called on the session queue, not the main queue.
|
||||||
|
@param success A block object to be executed when the task finishes successfully. This block has no return value and takes two arguments: the data task, and the response object created by the client response serializer.
|
||||||
|
@param failure A block object to be executed when the task finishes unsuccessfully, or that finishes successfully, but encountered an error while parsing the response data. This block has no return value and takes a two arguments: the data task and the error describing the network or parsing error that occurred.
|
||||||
|
|
||||||
|
@see -dataTaskWithRequest:uploadProgress:downloadProgress:completionHandler:
|
||||||
|
*/
|
||||||
|
- (nullable NSURLSessionDataTask *)uploadTaskWithHTTPMethod:(NSString *)HTTPMethod
|
||||||
|
URLString:(NSString *)URLString
|
||||||
|
parameters:(nullable id)parameters
|
||||||
|
progress:(nullable void (^)(NSProgress *uploadProgress))uploadProgress
|
||||||
|
success:(nullable void (^)(NSURLSessionDataTask *task, id _Nullable responseObject))success
|
||||||
|
failure:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSError *error))failure;
|
||||||
|
|
||||||
|
/**
|
||||||
|
Creates and runs an `NSURLSessionDataTask` with a given HTTP method.
|
||||||
|
|
||||||
|
@param HTTPMethod The HTTP method used to create the request.
|
||||||
|
@param URLString The URL string used to create the request URL.
|
||||||
|
@param parameters The parameters to be encoded according to the client request serializer.
|
||||||
|
@param downloadProgress A block object to be executed when the download progress is updated. Note this block is called on the session queue, not the main queue.
|
||||||
|
@param success A block object to be executed when the task finishes successfully. This block has no return value and takes two arguments: the data task, and the response object created by the client response serializer.
|
||||||
|
@param failure A block object to be executed when the task finishes unsuccessfully, or that finishes successfully, but encountered an error while parsing the response data. This block has no return value and takes a two arguments: the data task and the error describing the network or parsing error that occurred.
|
||||||
|
|
||||||
|
@see -dataTaskWithRequest:uploadProgress:downloadProgress:completionHandler:
|
||||||
|
*/
|
||||||
|
- (nullable NSURLSessionDataTask *)downloadTaskWithHTTPMethod:(NSString *)HTTPMethod
|
||||||
|
URLString:(NSString *)URLString
|
||||||
|
parameters:(nullable id)parameters
|
||||||
|
progress:(nullable void (^)(NSProgress *downloadProgress))downloadProgress
|
||||||
|
success:(nullable void (^)(NSURLSessionDataTask *task, id _Nullable responseObject))success
|
||||||
|
failure:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSError *error))failure;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_END
|
NS_ASSUME_NONNULL_END
|
||||||
|
|||||||
@@ -184,6 +184,8 @@
|
|||||||
{
|
{
|
||||||
NSError *serializationError = nil;
|
NSError *serializationError = nil;
|
||||||
NSMutableURLRequest *request = [self.requestSerializer multipartFormRequestWithMethod:@"POST" URLString:[[NSURL URLWithString:URLString relativeToURL:self.baseURL] absoluteString] parameters:parameters constructingBodyWithBlock:block error:&serializationError];
|
NSMutableURLRequest *request = [self.requestSerializer multipartFormRequestWithMethod:@"POST" URLString:[[NSURL URLWithString:URLString relativeToURL:self.baseURL] absoluteString] parameters:parameters constructingBodyWithBlock:block error:&serializationError];
|
||||||
|
[request setHTTPShouldHandleCookies:NO];
|
||||||
|
|
||||||
if (serializationError) {
|
if (serializationError) {
|
||||||
if (failure) {
|
if (failure) {
|
||||||
dispatch_async(self.completionQueue ?: dispatch_get_main_queue(), ^{
|
dispatch_async(self.completionQueue ?: dispatch_get_main_queue(), ^{
|
||||||
@@ -223,6 +225,44 @@
|
|||||||
return dataTask;
|
return dataTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (NSURLSessionDataTask *)PUT:(NSString *)URLString
|
||||||
|
parameters:(id)parameters
|
||||||
|
constructingBodyWithBlock:(void (^)(id <AFMultipartFormData> formData))block
|
||||||
|
progress:(nullable void (^)(NSProgress * _Nonnull))uploadProgress
|
||||||
|
success:(void (^)(NSURLSessionDataTask *task, id responseObject))success
|
||||||
|
failure:(void (^)(NSURLSessionDataTask *task, NSError *error))failure
|
||||||
|
{
|
||||||
|
NSError *serializationError = nil;
|
||||||
|
NSMutableURLRequest *request = [self.requestSerializer multipartFormRequestWithMethod:@"POST" URLString:[[NSURL URLWithString:URLString relativeToURL:self.baseURL] absoluteString] parameters:parameters constructingBodyWithBlock:block error:&serializationError];
|
||||||
|
[request setHTTPShouldHandleCookies:NO];
|
||||||
|
|
||||||
|
if (serializationError) {
|
||||||
|
if (failure) {
|
||||||
|
dispatch_async(self.completionQueue ?: dispatch_get_main_queue(), ^{
|
||||||
|
failure(nil, serializationError);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
__block NSURLSessionDataTask *task = [self uploadTaskWithStreamedRequest:request progress:uploadProgress completionHandler:^(NSURLResponse * __unused response, id responseObject, NSError *error) {
|
||||||
|
if (error) {
|
||||||
|
if (failure) {
|
||||||
|
failure(task, error);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (success) {
|
||||||
|
success(task, responseObject);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}];
|
||||||
|
|
||||||
|
[task resume];
|
||||||
|
|
||||||
|
return task;
|
||||||
|
}
|
||||||
|
|
||||||
- (NSURLSessionDataTask *)PATCH:(NSString *)URLString
|
- (NSURLSessionDataTask *)PATCH:(NSString *)URLString
|
||||||
parameters:(id)parameters
|
parameters:(id)parameters
|
||||||
success:(void (^)(NSURLSessionDataTask *task, id responseObject))success
|
success:(void (^)(NSURLSessionDataTask *task, id responseObject))success
|
||||||
@@ -247,6 +287,73 @@
|
|||||||
return dataTask;
|
return dataTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (NSURLSessionDataTask *)uploadTaskWithHTTPMethod:(NSString *)method
|
||||||
|
URLString:(NSString *)URLString
|
||||||
|
parameters:(id)parameters
|
||||||
|
constructingBodyWithBlock:(void (^)(id <AFMultipartFormData> formData))block
|
||||||
|
progress:(nullable void (^)(NSProgress * _Nonnull))uploadProgress
|
||||||
|
success:(void (^)(NSURLSessionDataTask *task, id responseObject))success
|
||||||
|
failure:(void (^)(NSURLSessionDataTask *task, NSError *error))failure
|
||||||
|
{
|
||||||
|
NSError *serializationError = nil;
|
||||||
|
NSMutableURLRequest *request = [self.requestSerializer multipartFormRequestWithMethod:method URLString:[[NSURL URLWithString:URLString relativeToURL:self.baseURL] absoluteString] parameters:parameters constructingBodyWithBlock:block error:&serializationError];
|
||||||
|
[request setHTTPShouldHandleCookies:NO];
|
||||||
|
|
||||||
|
if (serializationError) {
|
||||||
|
if (failure) {
|
||||||
|
dispatch_async(self.completionQueue ?: dispatch_get_main_queue(), ^{
|
||||||
|
failure(nil, serializationError);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
__block NSURLSessionDataTask *task = [self uploadTaskWithStreamedRequest:request progress:uploadProgress completionHandler:^(NSURLResponse * __unused response, id responseObject, NSError *error) {
|
||||||
|
if (error) {
|
||||||
|
if (failure) {
|
||||||
|
failure(task, error);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (success) {
|
||||||
|
success(task, responseObject);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}];
|
||||||
|
|
||||||
|
[task resume];
|
||||||
|
|
||||||
|
return task;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSURLSessionDataTask *)uploadTaskWithHTTPMethod:(NSString *)method
|
||||||
|
URLString:(NSString *)URLString
|
||||||
|
parameters:(id)parameters
|
||||||
|
progress:(void (^)(NSProgress * _Nonnull))uploadProgress
|
||||||
|
success:(void (^)(NSURLSessionDataTask * _Nonnull, id _Nullable))success
|
||||||
|
failure:(void (^)(NSURLSessionDataTask * _Nullable, NSError * _Nonnull))failure
|
||||||
|
{
|
||||||
|
NSURLSessionDataTask *dataTask = [self dataTaskWithHTTPMethod:method URLString:URLString parameters:parameters uploadProgress:uploadProgress downloadProgress:nil success:success failure:failure];
|
||||||
|
|
||||||
|
[dataTask resume];
|
||||||
|
|
||||||
|
return dataTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSURLSessionDataTask *)downloadTaskWithHTTPMethod:(NSString *)method
|
||||||
|
URLString:(NSString *)URLString
|
||||||
|
parameters:(id)parameters
|
||||||
|
progress:(nullable void (^)(NSProgress * _Nonnull))downloadProgress
|
||||||
|
success:(void (^)(NSURLSessionDataTask * _Nonnull, id _Nullable))success
|
||||||
|
failure:(void (^)(NSURLSessionDataTask * _Nullable, NSError * _Nonnull))failure
|
||||||
|
{
|
||||||
|
NSURLSessionDataTask *task = [self dataTaskWithHTTPMethod:method URLString:URLString parameters:parameters uploadProgress:nil downloadProgress:downloadProgress success:success failure:failure];
|
||||||
|
|
||||||
|
[task resume];
|
||||||
|
|
||||||
|
return task;
|
||||||
|
}
|
||||||
|
|
||||||
- (NSURLSessionDataTask *)dataTaskWithHTTPMethod:(NSString *)method
|
- (NSURLSessionDataTask *)dataTaskWithHTTPMethod:(NSString *)method
|
||||||
URLString:(NSString *)URLString
|
URLString:(NSString *)URLString
|
||||||
parameters:(id)parameters
|
parameters:(id)parameters
|
||||||
@@ -257,6 +364,8 @@
|
|||||||
{
|
{
|
||||||
NSError *serializationError = nil;
|
NSError *serializationError = nil;
|
||||||
NSMutableURLRequest *request = [self.requestSerializer requestWithMethod:method URLString:[[NSURL URLWithString:URLString relativeToURL:self.baseURL] absoluteString] parameters:parameters error:&serializationError];
|
NSMutableURLRequest *request = [self.requestSerializer requestWithMethod:method URLString:[[NSURL URLWithString:URLString relativeToURL:self.baseURL] absoluteString] parameters:parameters error:&serializationError];
|
||||||
|
[request setHTTPShouldHandleCookies:NO];
|
||||||
|
|
||||||
if (serializationError) {
|
if (serializationError) {
|
||||||
if (failure) {
|
if (failure) {
|
||||||
dispatch_async(self.completionQueue ?: dispatch_get_main_queue(), ^{
|
dispatch_async(self.completionQueue ?: dispatch_get_main_queue(), ^{
|
||||||
|
|||||||
@@ -308,4 +308,11 @@ FOUNDATION_EXPORT NSString * const AFNetworkingOperationFailingURLResponseErrorK
|
|||||||
|
|
||||||
FOUNDATION_EXPORT NSString * const AFNetworkingOperationFailingURLResponseDataErrorKey;
|
FOUNDATION_EXPORT NSString * const AFNetworkingOperationFailingURLResponseDataErrorKey;
|
||||||
|
|
||||||
|
/**
|
||||||
|
`AFNetworkingOperationFailingURLResponseBodyErrorKey`
|
||||||
|
The corresponding value is an `NSString` containing the decoded error message.
|
||||||
|
*/
|
||||||
|
|
||||||
|
FOUNDATION_EXPORT NSString * const AFNetworkingOperationFailingURLResponseBodyErrorKey;
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_END
|
NS_ASSUME_NONNULL_END
|
||||||
|
|||||||
@@ -34,6 +34,7 @@
|
|||||||
NSString * const AFURLResponseSerializationErrorDomain = @"com.alamofire.error.serialization.response";
|
NSString * const AFURLResponseSerializationErrorDomain = @"com.alamofire.error.serialization.response";
|
||||||
NSString * const AFNetworkingOperationFailingURLResponseErrorKey = @"com.alamofire.serialization.response.error.response";
|
NSString * const AFNetworkingOperationFailingURLResponseErrorKey = @"com.alamofire.serialization.response.error.response";
|
||||||
NSString * const AFNetworkingOperationFailingURLResponseDataErrorKey = @"com.alamofire.serialization.response.error.data";
|
NSString * const AFNetworkingOperationFailingURLResponseDataErrorKey = @"com.alamofire.serialization.response.error.data";
|
||||||
|
NSString * const AFNetworkingOperationFailingURLResponseBodyErrorKey = @"com.alamofire.serialization.response.error.body";
|
||||||
|
|
||||||
static NSError * AFErrorWithUnderlyingError(NSError *error, NSError *underlyingError) {
|
static NSError * AFErrorWithUnderlyingError(NSError *error, NSError *underlyingError) {
|
||||||
if (!error) {
|
if (!error) {
|
||||||
@@ -525,7 +526,7 @@ static NSLock* imageLock = nil;
|
|||||||
dispatch_once(&onceToken, ^{
|
dispatch_once(&onceToken, ^{
|
||||||
imageLock = [[NSLock alloc] init];
|
imageLock = [[NSLock alloc] init];
|
||||||
});
|
});
|
||||||
|
|
||||||
[imageLock lock];
|
[imageLock lock];
|
||||||
image = [UIImage imageWithData:data];
|
image = [UIImage imageWithData:data];
|
||||||
[imageLock unlock];
|
[imageLock unlock];
|
||||||
@@ -539,7 +540,7 @@ static UIImage * AFImageWithDataAtScale(NSData *data, CGFloat scale) {
|
|||||||
if (image.images) {
|
if (image.images) {
|
||||||
return image;
|
return image;
|
||||||
}
|
}
|
||||||
|
|
||||||
return [[UIImage alloc] initWithCGImage:[image CGImage] scale:scale orientation:image.imageOrientation];
|
return [[UIImage alloc] initWithCGImage:[image CGImage] scale:scale orientation:image.imageOrientation];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
#import "AFURLRequestSerialization.h"
|
||||||
|
|
||||||
|
@interface BinaryRequestSerializer : AFHTTPRequestSerializer
|
||||||
|
|
||||||
|
+ (instancetype)serializer;
|
||||||
|
|
||||||
|
@end
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
#import "BinaryRequestSerializer.h"
|
||||||
|
|
||||||
|
@implementation BinaryRequestSerializer
|
||||||
|
|
||||||
|
+ (instancetype)serializer
|
||||||
|
{
|
||||||
|
BinaryRequestSerializer *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:@"application/octet-stream" forHTTPHeaderField:@"Content-Type"];
|
||||||
|
}
|
||||||
|
|
||||||
|
[mutableRequest setHTTPBody: parameters];
|
||||||
|
}
|
||||||
|
|
||||||
|
return mutableRequest;
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - NSSecureCoding
|
||||||
|
|
||||||
|
- (instancetype)initWithCoder:(NSCoder *)decoder {
|
||||||
|
self = [super initWithCoder:decoder];
|
||||||
|
if (!self) {
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
#import "AFURLResponseSerialization.h"
|
||||||
|
|
||||||
|
@interface BinaryResponseSerializer : AFHTTPResponseSerializer
|
||||||
|
|
||||||
|
+ (instancetype)serializer;
|
||||||
|
|
||||||
|
@end
|
||||||
@@ -0,0 +1,126 @@
|
|||||||
|
#import "BinaryResponseSerializer.h"
|
||||||
|
|
||||||
|
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 BinaryResponseSerializer
|
||||||
|
|
||||||
|
+ (instancetype)serializer {
|
||||||
|
BinaryResponseSerializer *serializer = [[self alloc] init];
|
||||||
|
return serializer;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (instancetype)init {
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
NSStringEncoding supportedEncodings[6] = {
|
||||||
|
NSUTF8StringEncoding, NSWindowsCP1252StringEncoding, NSISOLatin1StringEncoding,
|
||||||
|
NSISOLatin2StringEncoding, NSASCIIStringEncoding, NSUnicodeStringEncoding
|
||||||
|
};
|
||||||
|
|
||||||
|
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
|
||||||
|
error:(NSError * __autoreleasing *)error
|
||||||
|
{
|
||||||
|
if (response && [response isKindOfClass:[NSHTTPURLResponse class]]) {
|
||||||
|
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;
|
||||||
|
|
||||||
|
// trying to decode error message in body
|
||||||
|
mutableUserInfo[AFNetworkingOperationFailingURLResponseBodyErrorKey] = [self decodeResponseData:data withEncoding:[self getEncoding:response]];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
*error = [NSError errorWithDomain:AFURLResponseSerializationErrorDomain code:NSURLErrorBadServerResponse userInfo:mutableUserInfo];
|
||||||
|
}
|
||||||
|
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - AFURLResponseSerialization
|
||||||
|
|
||||||
|
- (id)responseObjectForResponse:(NSURLResponse *)response
|
||||||
|
data:(NSData *)data
|
||||||
|
error:(NSError *__autoreleasing *)error
|
||||||
|
{
|
||||||
|
if (![self validateResponse:(NSHTTPURLResponse *)response data:data error:error]) {
|
||||||
|
if (!error || AFErrorOrUnderlyingErrorHasCodeInDomain(*error, NSURLErrorCannotDecodeContentData, AFURLResponseSerializationErrorDomain)) {
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return [data base64EncodedStringWithOptions:0];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
@@ -5,13 +5,16 @@
|
|||||||
@interface CordovaHttpPlugin : CDVPlugin
|
@interface CordovaHttpPlugin : CDVPlugin
|
||||||
|
|
||||||
- (void)setServerTrustMode:(CDVInvokedUrlCommand*)command;
|
- (void)setServerTrustMode:(CDVInvokedUrlCommand*)command;
|
||||||
- (void)disableRedirect:(CDVInvokedUrlCommand*)command;
|
- (void)setClientAuthMode:(CDVInvokedUrlCommand*)command;
|
||||||
- (void)post:(CDVInvokedUrlCommand*)command;
|
- (void)post:(CDVInvokedUrlCommand*)command;
|
||||||
- (void)get:(CDVInvokedUrlCommand*)command;
|
|
||||||
- (void)put:(CDVInvokedUrlCommand*)command;
|
- (void)put:(CDVInvokedUrlCommand*)command;
|
||||||
- (void)patch:(CDVInvokedUrlCommand*)command;
|
- (void)patch:(CDVInvokedUrlCommand*)command;
|
||||||
|
- (void)get:(CDVInvokedUrlCommand*)command;
|
||||||
- (void)delete:(CDVInvokedUrlCommand*)command;
|
- (void)delete:(CDVInvokedUrlCommand*)command;
|
||||||
- (void)uploadFile:(CDVInvokedUrlCommand*)command;
|
- (void)head:(CDVInvokedUrlCommand*)command;
|
||||||
|
- (void)options:(CDVInvokedUrlCommand*)command;
|
||||||
|
- (void)uploadFiles:(CDVInvokedUrlCommand*)command;
|
||||||
- (void)downloadFile:(CDVInvokedUrlCommand*)command;
|
- (void)downloadFile:(CDVInvokedUrlCommand*)command;
|
||||||
|
- (void)abort:(CDVInvokedUrlCommand*)command;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
+347
-269
@@ -1,5 +1,7 @@
|
|||||||
#import "CordovaHttpPlugin.h"
|
#import "CordovaHttpPlugin.h"
|
||||||
#import "CDVFile.h"
|
#import "CDVFile.h"
|
||||||
|
#import "BinaryRequestSerializer.h"
|
||||||
|
#import "BinaryResponseSerializer.h"
|
||||||
#import "TextResponseSerializer.h"
|
#import "TextResponseSerializer.h"
|
||||||
#import "TextRequestSerializer.h"
|
#import "TextRequestSerializer.h"
|
||||||
#import "AFHTTPSessionManager.h"
|
#import "AFHTTPSessionManager.h"
|
||||||
@@ -7,24 +9,35 @@
|
|||||||
|
|
||||||
@interface CordovaHttpPlugin()
|
@interface CordovaHttpPlugin()
|
||||||
|
|
||||||
|
- (void)addRequest:(NSNumber*)reqId forTask:(NSURLSessionDataTask*)task;
|
||||||
|
- (void)removeRequest:(NSNumber*)reqId;
|
||||||
- (void)setRequestHeaders:(NSDictionary*)headers forManager:(AFHTTPSessionManager*)manager;
|
- (void)setRequestHeaders:(NSDictionary*)headers forManager:(AFHTTPSessionManager*)manager;
|
||||||
- (void)handleSuccess:(NSMutableDictionary*)dictionary withResponse:(NSHTTPURLResponse*)response andData:(id)data;
|
- (void)handleSuccess:(NSMutableDictionary*)dictionary withResponse:(NSHTTPURLResponse*)response andData:(id)data;
|
||||||
- (void)handleError:(NSMutableDictionary*)dictionary withResponse:(NSHTTPURLResponse*)response error:(NSError*)error;
|
- (void)handleError:(NSMutableDictionary*)dictionary withResponse:(NSHTTPURLResponse*)response error:(NSError*)error;
|
||||||
- (NSNumber*)getStatusCode:(NSError*) error;
|
- (NSNumber*)getStatusCode:(NSError*) error;
|
||||||
- (NSMutableDictionary*)copyHeaderFields:(NSDictionary*)headerFields;
|
- (NSMutableDictionary*)copyHeaderFields:(NSDictionary*)headerFields;
|
||||||
- (void)setTimeout:(NSTimeInterval)timeout forManager:(AFHTTPSessionManager*)manager;
|
- (void)setTimeout:(NSTimeInterval)timeout forManager:(AFHTTPSessionManager*)manager;
|
||||||
- (void)setRedirect:(AFHTTPSessionManager*)manager;
|
- (void)setRedirect:(bool)redirect forManager:(AFHTTPSessionManager*)manager;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@implementation CordovaHttpPlugin {
|
@implementation CordovaHttpPlugin {
|
||||||
AFSecurityPolicy *securityPolicy;
|
AFSecurityPolicy *securityPolicy;
|
||||||
bool redirect;
|
NSURLCredential *x509Credential;
|
||||||
|
NSMutableDictionary *reqDict;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)pluginInitialize {
|
- (void)pluginInitialize {
|
||||||
securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeNone];
|
securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeNone];
|
||||||
redirect = true;
|
reqDict = [NSMutableDictionary dictionary];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)addRequest:(NSNumber*)reqId forTask:(NSURLSessionDataTask*)task {
|
||||||
|
[reqDict setObject:task forKey:reqId];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)removeRequest:(NSNumber*)reqId {
|
||||||
|
[reqDict removeObjectForKey:reqId];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setRequestSerializer:(NSString*)serializerName forManager:(AFHTTPSessionManager*)manager {
|
- (void)setRequestSerializer:(NSString*)serializerName forManager:(AFHTTPSessionManager*)manager {
|
||||||
@@ -32,20 +45,51 @@
|
|||||||
manager.requestSerializer = [AFJSONRequestSerializer serializer];
|
manager.requestSerializer = [AFJSONRequestSerializer serializer];
|
||||||
} else if ([serializerName isEqualToString:@"utf8"]) {
|
} else if ([serializerName isEqualToString:@"utf8"]) {
|
||||||
manager.requestSerializer = [TextRequestSerializer serializer];
|
manager.requestSerializer = [TextRequestSerializer serializer];
|
||||||
|
} else if ([serializerName isEqualToString:@"raw"]) {
|
||||||
|
manager.requestSerializer = [BinaryRequestSerializer serializer];
|
||||||
} else {
|
} else {
|
||||||
manager.requestSerializer = [AFHTTPRequestSerializer serializer];
|
manager.requestSerializer = [AFHTTPRequestSerializer serializer];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)setupAuthChallengeBlock:(AFHTTPSessionManager*)manager {
|
||||||
|
[manager setSessionDidReceiveAuthenticationChallengeBlock:^NSURLSessionAuthChallengeDisposition(
|
||||||
|
NSURLSession * _Nonnull session,
|
||||||
|
NSURLAuthenticationChallenge * _Nonnull challenge,
|
||||||
|
NSURLCredential * _Nullable __autoreleasing * _Nullable credential
|
||||||
|
) {
|
||||||
|
if ([challenge.protectionSpace.authenticationMethod isEqualToString: NSURLAuthenticationMethodServerTrust]) {
|
||||||
|
*credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust];
|
||||||
|
|
||||||
|
if (![self->securityPolicy evaluateServerTrust:challenge.protectionSpace.serverTrust forDomain:challenge.protectionSpace.host]) {
|
||||||
|
return NSURLSessionAuthChallengeRejectProtectionSpace;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (credential) {
|
||||||
|
return NSURLSessionAuthChallengeUseCredential;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ([challenge.protectionSpace.authenticationMethod isEqualToString: NSURLAuthenticationMethodClientCertificate] && self->x509Credential) {
|
||||||
|
*credential = self->x509Credential;
|
||||||
|
return NSURLSessionAuthChallengeUseCredential;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NSURLSessionAuthChallengePerformDefaultHandling;
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
- (void)setRequestHeaders:(NSDictionary*)headers forManager:(AFHTTPSessionManager*)manager {
|
- (void)setRequestHeaders:(NSDictionary*)headers forManager:(AFHTTPSessionManager*)manager {
|
||||||
[headers enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
|
[headers enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
|
||||||
[manager.requestSerializer setValue:obj forHTTPHeaderField:key];
|
[manager.requestSerializer setValue:obj forHTTPHeaderField:key];
|
||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setRedirect:(AFHTTPSessionManager*)manager {
|
- (void)setRedirect:(bool)followRedirect forManager:(AFHTTPSessionManager*)manager {
|
||||||
[manager setTaskWillPerformHTTPRedirectionBlock:^NSURLRequest * _Nonnull(NSURLSession * _Nonnull session, NSURLSessionTask * _Nonnull task, NSURLResponse * _Nonnull response, NSURLRequest * _Nonnull request) {
|
[manager setTaskWillPerformHTTPRedirectionBlock:^NSURLRequest * _Nonnull(NSURLSession * _Nonnull session,
|
||||||
if (redirect) {
|
NSURLSessionTask * _Nonnull task, NSURLResponse * _Nonnull response, NSURLRequest * _Nonnull request) {
|
||||||
|
|
||||||
|
if (followRedirect) {
|
||||||
return request;
|
return request;
|
||||||
} else {
|
} else {
|
||||||
return nil;
|
return nil;
|
||||||
@@ -53,6 +97,19 @@
|
|||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)setTimeout:(NSTimeInterval)timeout forManager:(AFHTTPSessionManager*)manager {
|
||||||
|
[manager.requestSerializer setTimeoutInterval:timeout];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setResponseSerializer:(NSString*)responseType forManager:(AFHTTPSessionManager*)manager {
|
||||||
|
if ([responseType isEqualToString: @"text"] || [responseType isEqualToString: @"json"]) {
|
||||||
|
manager.responseSerializer = [TextResponseSerializer serializer];
|
||||||
|
} else {
|
||||||
|
manager.responseSerializer = [BinaryResponseSerializer serializer];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
- (void)handleSuccess:(NSMutableDictionary*)dictionary withResponse:(NSHTTPURLResponse*)response andData:(id)data {
|
- (void)handleSuccess:(NSMutableDictionary*)dictionary withResponse:(NSHTTPURLResponse*)response andData:(id)data {
|
||||||
if (response != nil) {
|
if (response != nil) {
|
||||||
[dictionary setValue:response.URL.absoluteString forKey:@"url"];
|
[dictionary setValue:response.URL.absoluteString forKey:@"url"];
|
||||||
@@ -66,14 +123,21 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
- (void)handleError:(NSMutableDictionary*)dictionary withResponse:(NSHTTPURLResponse*)response error:(NSError*)error {
|
- (void)handleError:(NSMutableDictionary*)dictionary withResponse:(NSHTTPURLResponse*)response error:(NSError*)error {
|
||||||
|
bool aborted = error.code == NSURLErrorCancelled;
|
||||||
|
if(aborted){
|
||||||
|
[dictionary setObject:[NSNumber numberWithInt:-8] forKey:@"status"];
|
||||||
|
[dictionary setObject:@"Request was aborted" forKey:@"error"];
|
||||||
|
}
|
||||||
if (response != nil) {
|
if (response != nil) {
|
||||||
[dictionary setValue:response.URL.absoluteString forKey:@"url"];
|
[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:[self copyHeaderFields:response.allHeaderFields] forKey:@"headers"];
|
||||||
if (error.userInfo[AFNetworkingOperationFailingURLResponseBodyKey]) {
|
if(!aborted){
|
||||||
[dictionary setObject:error.userInfo[AFNetworkingOperationFailingURLResponseBodyKey] forKey:@"error"];
|
[dictionary setObject:[NSNumber numberWithInt:(int)response.statusCode] forKey:@"status"];
|
||||||
|
if (error.userInfo[AFNetworkingOperationFailingURLResponseBodyErrorKey]) {
|
||||||
|
[dictionary setObject:error.userInfo[AFNetworkingOperationFailingURLResponseBodyErrorKey] forKey:@"error"];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else if(!aborted) {
|
||||||
[dictionary setObject:[self getStatusCode:error] forKey:@"status"];
|
[dictionary setObject:[self getStatusCode:error] forKey:@"status"];
|
||||||
[dictionary setObject:[error localizedDescription] forKey:@"error"];
|
[dictionary setObject:[error localizedDescription] forKey:@"error"];
|
||||||
}
|
}
|
||||||
@@ -128,6 +192,161 @@
|
|||||||
return headerFieldsCopy;
|
return headerFieldsCopy;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)executeRequestWithoutData:(CDVInvokedUrlCommand*)command withMethod:(NSString*) method {
|
||||||
|
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
|
||||||
|
|
||||||
|
NSString *url = [command.arguments objectAtIndex:0];
|
||||||
|
NSDictionary *headers = [command.arguments objectAtIndex:1];
|
||||||
|
NSTimeInterval timeoutInSeconds = [[command.arguments objectAtIndex:2] doubleValue];
|
||||||
|
bool followRedirect = [[command.arguments objectAtIndex:3] boolValue];
|
||||||
|
NSString *responseType = [command.arguments objectAtIndex:4];
|
||||||
|
NSNumber *reqId = [command.arguments objectAtIndex:5];
|
||||||
|
|
||||||
|
[self setRequestSerializer: @"default" forManager: manager];
|
||||||
|
[self setupAuthChallengeBlock: manager];
|
||||||
|
[self setRequestHeaders: headers forManager: manager];
|
||||||
|
[self setTimeout:timeoutInSeconds forManager:manager];
|
||||||
|
[self setRedirect:followRedirect forManager:manager];
|
||||||
|
[self setResponseSerializer:responseType forManager:manager];
|
||||||
|
|
||||||
|
CordovaHttpPlugin* __weak weakSelf = self;
|
||||||
|
[[SDNetworkActivityIndicator sharedActivityIndicator] startActivity];
|
||||||
|
|
||||||
|
@try {
|
||||||
|
void (^onSuccess)(NSURLSessionTask *, id) = ^(NSURLSessionTask *task, id responseObject) {
|
||||||
|
[weakSelf removeRequest:reqId];
|
||||||
|
|
||||||
|
NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];
|
||||||
|
|
||||||
|
// no 'body' for HEAD request, omitting 'data'
|
||||||
|
if ([method isEqualToString:@"HEAD"]) {
|
||||||
|
[self handleSuccess:dictionary withResponse:(NSHTTPURLResponse*)task.response andData:nil];
|
||||||
|
} else {
|
||||||
|
[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];
|
||||||
|
[manager invalidateSessionCancelingTasks:YES];
|
||||||
|
};
|
||||||
|
|
||||||
|
void (^onFailure)(NSURLSessionTask *, NSError *) = ^(NSURLSessionTask *task, NSError *error) {
|
||||||
|
[weakSelf removeRequest:reqId];
|
||||||
|
|
||||||
|
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];
|
||||||
|
[manager invalidateSessionCancelingTasks:YES];
|
||||||
|
};
|
||||||
|
|
||||||
|
NSURLSessionDataTask *task = [manager downloadTaskWithHTTPMethod:method URLString:url parameters:nil progress:nil success:onSuccess failure:onFailure];
|
||||||
|
[self addRequest:reqId forTask:task];
|
||||||
|
}
|
||||||
|
@catch (NSException *exception) {
|
||||||
|
[[SDNetworkActivityIndicator sharedActivityIndicator] stopActivity];
|
||||||
|
[self handleException:exception withCommand:command];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)executeRequestWithData:(CDVInvokedUrlCommand*)command withMethod:(NSString*)method {
|
||||||
|
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
|
||||||
|
|
||||||
|
NSString *url = [command.arguments objectAtIndex:0];
|
||||||
|
NSDictionary *data = [command.arguments objectAtIndex:1];
|
||||||
|
NSString *serializerName = [command.arguments objectAtIndex:2];
|
||||||
|
NSDictionary *headers = [command.arguments objectAtIndex:3];
|
||||||
|
NSTimeInterval timeoutInSeconds = [[command.arguments objectAtIndex:4] doubleValue];
|
||||||
|
bool followRedirect = [[command.arguments objectAtIndex:5] boolValue];
|
||||||
|
NSString *responseType = [command.arguments objectAtIndex:6];
|
||||||
|
NSNumber *reqId = [command.arguments objectAtIndex:7];
|
||||||
|
|
||||||
|
[self setRequestSerializer: serializerName forManager: manager];
|
||||||
|
[self setupAuthChallengeBlock: manager];
|
||||||
|
[self setRequestHeaders: headers forManager: manager];
|
||||||
|
[self setTimeout:timeoutInSeconds forManager:manager];
|
||||||
|
[self setRedirect:followRedirect forManager:manager];
|
||||||
|
[self setResponseSerializer:responseType forManager:manager];
|
||||||
|
|
||||||
|
CordovaHttpPlugin* __weak weakSelf = self;
|
||||||
|
[[SDNetworkActivityIndicator sharedActivityIndicator] startActivity];
|
||||||
|
|
||||||
|
@try {
|
||||||
|
void (^constructBody)(id<AFMultipartFormData>) = ^(id<AFMultipartFormData> formData) {
|
||||||
|
NSArray *buffers = [data mutableArrayValueForKey:@"buffers"];
|
||||||
|
NSArray *fileNames = [data mutableArrayValueForKey:@"fileNames"];
|
||||||
|
NSArray *names = [data mutableArrayValueForKey:@"names"];
|
||||||
|
NSArray *types = [data mutableArrayValueForKey:@"types"];
|
||||||
|
|
||||||
|
NSError *error;
|
||||||
|
|
||||||
|
for (int i = 0; i < [buffers count]; ++i) {
|
||||||
|
NSData *decodedBuffer = [[NSData alloc] initWithBase64EncodedString:[buffers objectAtIndex:i] options:0];
|
||||||
|
NSString *fileName = [fileNames objectAtIndex:i];
|
||||||
|
NSString *partName = [names objectAtIndex:i];
|
||||||
|
NSString *partType = [types objectAtIndex:i];
|
||||||
|
|
||||||
|
if (![fileName isEqual:[NSNull null]]) {
|
||||||
|
[formData appendPartWithFileData:decodedBuffer name:partName fileName:fileName mimeType:partType];
|
||||||
|
} else {
|
||||||
|
[formData appendPartWithFormData:decodedBuffer name:[names objectAtIndex:i]];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
[weakSelf removeRequest:reqId];
|
||||||
|
|
||||||
|
NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];
|
||||||
|
[dictionary setObject:[NSNumber numberWithInt:400] forKey:@"status"];
|
||||||
|
[dictionary setObject:@"Could not add part to multipart request body." forKey:@"error"];
|
||||||
|
CDVPluginResult *pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:dictionary];
|
||||||
|
[weakSelf.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
|
||||||
|
[[SDNetworkActivityIndicator sharedActivityIndicator] stopActivity];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
void (^onSuccess)(NSURLSessionTask *, id) = ^(NSURLSessionTask *task, id responseObject) {
|
||||||
|
[weakSelf removeRequest:reqId];
|
||||||
|
|
||||||
|
NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];
|
||||||
|
[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];
|
||||||
|
[manager invalidateSessionCancelingTasks:YES];
|
||||||
|
};
|
||||||
|
|
||||||
|
void (^onFailure)(NSURLSessionTask *, NSError *) = ^(NSURLSessionTask *task, NSError *error) {
|
||||||
|
[weakSelf removeRequest:reqId];
|
||||||
|
|
||||||
|
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];
|
||||||
|
[manager invalidateSessionCancelingTasks:YES];
|
||||||
|
};
|
||||||
|
|
||||||
|
NSURLSessionDataTask *task;
|
||||||
|
if ([serializerName isEqualToString:@"multipart"]) {
|
||||||
|
task = [manager uploadTaskWithHTTPMethod:method URLString:url parameters:nil constructingBodyWithBlock:constructBody progress:nil success:onSuccess failure:onFailure];
|
||||||
|
} else {
|
||||||
|
task = [manager uploadTaskWithHTTPMethod:method URLString:url parameters:data progress:nil success:onSuccess failure:onFailure];
|
||||||
|
}
|
||||||
|
[self addRequest:reqId forTask:task];
|
||||||
|
}
|
||||||
|
@catch (NSException *exception) {
|
||||||
|
[[SDNetworkActivityIndicator sharedActivityIndicator] stopActivity];
|
||||||
|
[self handleException:exception withCommand:command];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
- (void)setServerTrustMode:(CDVInvokedUrlCommand*)command {
|
- (void)setServerTrustMode:(CDVInvokedUrlCommand*)command {
|
||||||
NSString *certMode = [command.arguments objectAtIndex:0];
|
NSString *certMode = [command.arguments objectAtIndex:0];
|
||||||
|
|
||||||
@@ -149,291 +368,112 @@
|
|||||||
[self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
|
[self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setTimeout:(NSTimeInterval)timeout forManager:(AFHTTPSessionManager*)manager {
|
- (void)setClientAuthMode:(CDVInvokedUrlCommand*)command {
|
||||||
[manager.requestSerializer setTimeoutInterval:timeout];
|
CDVPluginResult* pluginResult;
|
||||||
}
|
NSString *mode = [command.arguments objectAtIndex:0];
|
||||||
|
|
||||||
- (void)disableRedirect:(CDVInvokedUrlCommand*)command {
|
if ([mode isEqualToString:@"none"]) {
|
||||||
CDVPluginResult* pluginResult = nil;
|
x509Credential = nil;
|
||||||
bool disable = [[command.arguments objectAtIndex:0] boolValue];
|
pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK];
|
||||||
|
}
|
||||||
|
|
||||||
redirect = !disable;
|
if ([mode isEqualToString:@"systemstore"]) {
|
||||||
|
NSString *alias = [command.arguments objectAtIndex:1];
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
|
||||||
|
pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:@"mode 'systemstore' is not supported on iOS"];
|
||||||
|
}
|
||||||
|
|
||||||
|
if ([mode isEqualToString:@"buffer"]) {
|
||||||
|
CFDataRef container = (__bridge CFDataRef) [command.arguments objectAtIndex:2];
|
||||||
|
CFStringRef password = (__bridge CFStringRef) [command.arguments objectAtIndex:3];
|
||||||
|
|
||||||
|
const void *keys[] = { kSecImportExportPassphrase };
|
||||||
|
const void *values[] = { password };
|
||||||
|
|
||||||
|
CFDictionaryRef options = CFDictionaryCreate(NULL, keys, values, 1, NULL, NULL);
|
||||||
|
CFArrayRef items;
|
||||||
|
OSStatus securityError = SecPKCS12Import(container, options, &items);
|
||||||
|
CFRelease(options);
|
||||||
|
|
||||||
|
if (securityError != noErr) {
|
||||||
|
pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR];
|
||||||
|
} else {
|
||||||
|
CFDictionaryRef identityDict = CFArrayGetValueAtIndex(items, 0);
|
||||||
|
SecIdentityRef identity = (SecIdentityRef)CFDictionaryGetValue(identityDict, kSecImportItemIdentity);
|
||||||
|
|
||||||
|
self->x509Credential = [NSURLCredential credentialWithIdentity:identity certificates: nil persistence:NSURLCredentialPersistenceForSession];
|
||||||
|
CFRelease(items);
|
||||||
|
|
||||||
|
pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK];
|
|
||||||
[self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
|
[self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)get:(CDVInvokedUrlCommand*)command {
|
|
||||||
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
|
|
||||||
manager.securityPolicy = securityPolicy;
|
|
||||||
|
|
||||||
NSString *url = [command.arguments objectAtIndex:0];
|
|
||||||
NSDictionary *headers = [command.arguments objectAtIndex:1];
|
|
||||||
NSTimeInterval timeoutInSeconds = [[command.arguments objectAtIndex:2] doubleValue];
|
|
||||||
|
|
||||||
[self setRequestSerializer: @"default" forManager: manager];
|
|
||||||
[self setRequestHeaders: headers forManager: manager];
|
|
||||||
[self setTimeout:timeoutInSeconds forManager:manager];
|
|
||||||
[self setRedirect: manager];
|
|
||||||
|
|
||||||
CordovaHttpPlugin* __weak weakSelf = self;
|
|
||||||
manager.responseSerializer = [TextResponseSerializer serializer];
|
|
||||||
[[SDNetworkActivityIndicator sharedActivityIndicator] startActivity];
|
|
||||||
|
|
||||||
@try {
|
|
||||||
[manager GET:url parameters:nil success:^(NSURLSessionTask *task, id responseObject) {
|
|
||||||
NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];
|
|
||||||
[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];
|
|
||||||
[[SDNetworkActivityIndicator sharedActivityIndicator] stopActivity];
|
|
||||||
}];
|
|
||||||
}
|
|
||||||
@catch (NSException *exception) {
|
|
||||||
[[SDNetworkActivityIndicator sharedActivityIndicator] stopActivity];
|
|
||||||
[self handleException:exception withCommand:command];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)head:(CDVInvokedUrlCommand*)command {
|
|
||||||
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
|
|
||||||
manager.securityPolicy = securityPolicy;
|
|
||||||
|
|
||||||
NSString *url = [command.arguments objectAtIndex:0];
|
|
||||||
NSDictionary *headers = [command.arguments objectAtIndex:1];
|
|
||||||
NSTimeInterval timeoutInSeconds = [[command.arguments objectAtIndex:2] doubleValue];
|
|
||||||
|
|
||||||
[self setRequestHeaders: headers forManager: manager];
|
|
||||||
[self setTimeout:timeoutInSeconds forManager:manager];
|
|
||||||
[self setRedirect: manager];
|
|
||||||
|
|
||||||
CordovaHttpPlugin* __weak weakSelf = self;
|
|
||||||
manager.responseSerializer = [AFHTTPResponseSerializer serializer];
|
|
||||||
[[SDNetworkActivityIndicator sharedActivityIndicator] startActivity];
|
|
||||||
|
|
||||||
@try {
|
|
||||||
[manager HEAD:url parameters:nil 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_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 {
|
|
||||||
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
|
|
||||||
manager.securityPolicy = securityPolicy;
|
|
||||||
|
|
||||||
NSString *url = [command.arguments objectAtIndex:0];
|
|
||||||
NSDictionary *headers = [command.arguments objectAtIndex:1];
|
|
||||||
NSTimeInterval timeoutInSeconds = [[command.arguments objectAtIndex:2] doubleValue];
|
|
||||||
|
|
||||||
[self setRequestSerializer: @"default" forManager: manager];
|
|
||||||
[self setRequestHeaders: headers forManager: manager];
|
|
||||||
[self setTimeout:timeoutInSeconds forManager:manager];
|
|
||||||
[self setRedirect: manager];
|
|
||||||
|
|
||||||
CordovaHttpPlugin* __weak weakSelf = self;
|
|
||||||
manager.responseSerializer = [TextResponseSerializer serializer];
|
|
||||||
[[SDNetworkActivityIndicator sharedActivityIndicator] startActivity];
|
|
||||||
|
|
||||||
@try {
|
|
||||||
[manager DELETE:url parameters:nil success:^(NSURLSessionTask *task, id responseObject) {
|
|
||||||
NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];
|
|
||||||
[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];
|
|
||||||
[[SDNetworkActivityIndicator sharedActivityIndicator] stopActivity];
|
|
||||||
}];
|
|
||||||
}
|
|
||||||
@catch (NSException *exception) {
|
|
||||||
[[SDNetworkActivityIndicator sharedActivityIndicator] stopActivity];
|
|
||||||
[self handleException:exception withCommand:command];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)post:(CDVInvokedUrlCommand*)command {
|
- (void)post:(CDVInvokedUrlCommand*)command {
|
||||||
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
|
[self executeRequestWithData: command withMethod:@"POST"];
|
||||||
manager.securityPolicy = securityPolicy;
|
|
||||||
|
|
||||||
NSString *url = [command.arguments objectAtIndex:0];
|
|
||||||
NSDictionary *data = [command.arguments objectAtIndex:1];
|
|
||||||
NSString *serializerName = [command.arguments objectAtIndex:2];
|
|
||||||
NSDictionary *headers = [command.arguments objectAtIndex:3];
|
|
||||||
NSTimeInterval timeoutInSeconds = [[command.arguments objectAtIndex:4] doubleValue];
|
|
||||||
|
|
||||||
[self setRequestSerializer: serializerName forManager: manager];
|
|
||||||
[self setRequestHeaders: headers forManager: manager];
|
|
||||||
[self setTimeout:timeoutInSeconds forManager:manager];
|
|
||||||
[self setRedirect: manager];
|
|
||||||
|
|
||||||
CordovaHttpPlugin* __weak weakSelf = self;
|
|
||||||
manager.responseSerializer = [TextResponseSerializer serializer];
|
|
||||||
[[SDNetworkActivityIndicator sharedActivityIndicator] startActivity];
|
|
||||||
|
|
||||||
@try {
|
|
||||||
[manager POST:url parameters:data success:^(NSURLSessionTask *task, id responseObject) {
|
|
||||||
NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];
|
|
||||||
[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];
|
|
||||||
[[SDNetworkActivityIndicator sharedActivityIndicator] stopActivity];
|
|
||||||
}];
|
|
||||||
}
|
|
||||||
@catch (NSException *exception) {
|
|
||||||
[[SDNetworkActivityIndicator sharedActivityIndicator] stopActivity];
|
|
||||||
[self handleException:exception withCommand:command];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)put:(CDVInvokedUrlCommand*)command {
|
- (void)put:(CDVInvokedUrlCommand*)command {
|
||||||
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
|
[self executeRequestWithData: command withMethod:@"PUT"];
|
||||||
manager.securityPolicy = securityPolicy;
|
|
||||||
|
|
||||||
NSString *url = [command.arguments objectAtIndex:0];
|
|
||||||
NSDictionary *data = [command.arguments objectAtIndex:1];
|
|
||||||
NSString *serializerName = [command.arguments objectAtIndex:2];
|
|
||||||
NSDictionary *headers = [command.arguments objectAtIndex:3];
|
|
||||||
NSTimeInterval timeoutInSeconds = [[command.arguments objectAtIndex:4] doubleValue];
|
|
||||||
|
|
||||||
[self setRequestSerializer: serializerName forManager: manager];
|
|
||||||
[self setRequestHeaders: headers forManager: manager];
|
|
||||||
[self setTimeout:timeoutInSeconds forManager:manager];
|
|
||||||
[self setRedirect: manager];
|
|
||||||
|
|
||||||
CordovaHttpPlugin* __weak weakSelf = self;
|
|
||||||
manager.responseSerializer = [TextResponseSerializer serializer];
|
|
||||||
[[SDNetworkActivityIndicator sharedActivityIndicator] startActivity];
|
|
||||||
|
|
||||||
@try {
|
|
||||||
[manager PUT:url parameters:data success:^(NSURLSessionTask *task, id responseObject) {
|
|
||||||
NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];
|
|
||||||
[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];
|
|
||||||
[[SDNetworkActivityIndicator sharedActivityIndicator] stopActivity];
|
|
||||||
}];
|
|
||||||
}
|
|
||||||
@catch (NSException *exception) {
|
|
||||||
[[SDNetworkActivityIndicator sharedActivityIndicator] stopActivity];
|
|
||||||
[self handleException:exception withCommand:command];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)patch:(CDVInvokedUrlCommand*)command {
|
- (void)patch:(CDVInvokedUrlCommand*)command {
|
||||||
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
|
[self executeRequestWithData: command withMethod:@"PATCH"];
|
||||||
manager.securityPolicy = securityPolicy;
|
|
||||||
|
|
||||||
NSString *url = [command.arguments objectAtIndex:0];
|
|
||||||
NSDictionary *data = [command.arguments objectAtIndex:1];
|
|
||||||
NSString *serializerName = [command.arguments objectAtIndex:2];
|
|
||||||
NSDictionary *headers = [command.arguments objectAtIndex:3];
|
|
||||||
NSTimeInterval timeoutInSeconds = [[command.arguments objectAtIndex:4] doubleValue];
|
|
||||||
|
|
||||||
[self setRequestSerializer: serializerName forManager: manager];
|
|
||||||
[self setRequestHeaders: headers forManager: manager];
|
|
||||||
[self setTimeout:timeoutInSeconds forManager:manager];
|
|
||||||
[self setRedirect: manager];
|
|
||||||
|
|
||||||
CordovaHttpPlugin* __weak weakSelf = self;
|
|
||||||
manager.responseSerializer = [TextResponseSerializer serializer];
|
|
||||||
[[SDNetworkActivityIndicator sharedActivityIndicator] startActivity];
|
|
||||||
|
|
||||||
@try {
|
|
||||||
[manager PATCH:url parameters:data success:^(NSURLSessionTask *task, id responseObject) {
|
|
||||||
NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];
|
|
||||||
[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];
|
|
||||||
[[SDNetworkActivityIndicator sharedActivityIndicator] stopActivity];
|
|
||||||
}];
|
|
||||||
}
|
|
||||||
@catch (NSException *exception) {
|
|
||||||
[[SDNetworkActivityIndicator sharedActivityIndicator] stopActivity];
|
|
||||||
[self handleException:exception withCommand:command];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)uploadFile:(CDVInvokedUrlCommand*)command {
|
- (void)get:(CDVInvokedUrlCommand*)command {
|
||||||
|
[self executeRequestWithoutData: command withMethod:@"GET"];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)delete:(CDVInvokedUrlCommand*)command {
|
||||||
|
[self executeRequestWithoutData: command withMethod:@"DELETE"];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)head:(CDVInvokedUrlCommand*)command {
|
||||||
|
[self executeRequestWithoutData: command withMethod:@"HEAD"];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)options:(CDVInvokedUrlCommand*)command {
|
||||||
|
[self executeRequestWithoutData: command withMethod:@"OPTIONS"];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)uploadFiles:(CDVInvokedUrlCommand*)command {
|
||||||
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
|
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
|
||||||
manager.securityPolicy = securityPolicy;
|
|
||||||
|
|
||||||
NSString *url = [command.arguments objectAtIndex:0];
|
NSString *url = [command.arguments objectAtIndex:0];
|
||||||
NSDictionary *headers = [command.arguments objectAtIndex:1];
|
NSDictionary *headers = [command.arguments objectAtIndex:1];
|
||||||
NSString *filePath = [command.arguments objectAtIndex: 2];
|
NSArray *filePaths = [command.arguments objectAtIndex: 2];
|
||||||
NSString *name = [command.arguments objectAtIndex: 3];
|
NSArray *names = [command.arguments objectAtIndex: 3];
|
||||||
NSTimeInterval timeoutInSeconds = [[command.arguments objectAtIndex:4] doubleValue];
|
NSTimeInterval timeoutInSeconds = [[command.arguments objectAtIndex:4] doubleValue];
|
||||||
|
bool followRedirect = [[command.arguments objectAtIndex:5] boolValue];
|
||||||
NSURL *fileURL = [NSURL URLWithString: filePath];
|
NSString *responseType = [command.arguments objectAtIndex:6];
|
||||||
|
NSNumber *reqId = [command.arguments objectAtIndex:7];
|
||||||
|
|
||||||
[self setRequestHeaders: headers forManager: manager];
|
[self setRequestHeaders: headers forManager: manager];
|
||||||
|
[self setupAuthChallengeBlock: manager];
|
||||||
[self setTimeout:timeoutInSeconds forManager:manager];
|
[self setTimeout:timeoutInSeconds forManager:manager];
|
||||||
[self setRedirect: manager];
|
[self setRedirect:followRedirect forManager:manager];
|
||||||
|
[self setResponseSerializer:responseType forManager:manager];
|
||||||
|
|
||||||
CordovaHttpPlugin* __weak weakSelf = self;
|
CordovaHttpPlugin* __weak weakSelf = self;
|
||||||
manager.responseSerializer = [TextResponseSerializer serializer];
|
|
||||||
[[SDNetworkActivityIndicator sharedActivityIndicator] startActivity];
|
[[SDNetworkActivityIndicator sharedActivityIndicator] startActivity];
|
||||||
|
|
||||||
@try {
|
@try {
|
||||||
[manager POST:url parameters:nil constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {
|
NSURLSessionDataTask *task = [manager POST:url parameters:nil constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {
|
||||||
NSError *error;
|
NSError *error;
|
||||||
[formData appendPartWithFileURL:fileURL name:name error:&error];
|
for (int i = 0; i < [filePaths count]; i++) {
|
||||||
|
NSString *filePath = (NSString *) [filePaths objectAtIndex:i];
|
||||||
|
NSString *uploadName = (NSString *) [names objectAtIndex:i];
|
||||||
|
NSURL *fileURL = [NSURL URLWithString: filePath];
|
||||||
|
[formData appendPartWithFileURL:fileURL name:uploadName error:&error];
|
||||||
|
}
|
||||||
if (error) {
|
if (error) {
|
||||||
|
[weakSelf removeRequest:reqId];
|
||||||
|
|
||||||
NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];
|
NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];
|
||||||
[dictionary setObject:[NSNumber numberWithInt:500] forKey:@"status"];
|
[dictionary setObject:[NSNumber numberWithInt:500] forKey:@"status"];
|
||||||
[dictionary setObject:@"Could not add file to post body." forKey:@"error"];
|
[dictionary setObject:@"Could not add file to post body." forKey:@"error"];
|
||||||
@@ -443,6 +483,8 @@
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} progress:nil success:^(NSURLSessionTask *task, id responseObject) {
|
} progress:nil success:^(NSURLSessionTask *task, id responseObject) {
|
||||||
|
[weakSelf removeRequest:reqId];
|
||||||
|
|
||||||
NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];
|
NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];
|
||||||
[self handleSuccess:dictionary withResponse:(NSHTTPURLResponse*)task.response andData:responseObject];
|
[self handleSuccess:dictionary withResponse:(NSHTTPURLResponse*)task.response andData:responseObject];
|
||||||
|
|
||||||
@@ -450,6 +492,8 @@
|
|||||||
[weakSelf.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
|
[weakSelf.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
|
||||||
[[SDNetworkActivityIndicator sharedActivityIndicator] stopActivity];
|
[[SDNetworkActivityIndicator sharedActivityIndicator] stopActivity];
|
||||||
} failure:^(NSURLSessionTask *task, NSError *error) {
|
} failure:^(NSURLSessionTask *task, NSError *error) {
|
||||||
|
[weakSelf removeRequest:reqId];
|
||||||
|
|
||||||
NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];
|
NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];
|
||||||
[self handleError:dictionary withResponse:(NSHTTPURLResponse*)task.response error:error];
|
[self handleError:dictionary withResponse:(NSHTTPURLResponse*)task.response error:error];
|
||||||
|
|
||||||
@@ -457,6 +501,7 @@
|
|||||||
[weakSelf.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
|
[weakSelf.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
|
||||||
[[SDNetworkActivityIndicator sharedActivityIndicator] stopActivity];
|
[[SDNetworkActivityIndicator sharedActivityIndicator] stopActivity];
|
||||||
}];
|
}];
|
||||||
|
[self addRequest:reqId forTask:task];
|
||||||
}
|
}
|
||||||
@catch (NSException *exception) {
|
@catch (NSException *exception) {
|
||||||
[[SDNetworkActivityIndicator sharedActivityIndicator] stopActivity];
|
[[SDNetworkActivityIndicator sharedActivityIndicator] stopActivity];
|
||||||
@@ -466,27 +511,30 @@
|
|||||||
|
|
||||||
- (void)downloadFile:(CDVInvokedUrlCommand*)command {
|
- (void)downloadFile:(CDVInvokedUrlCommand*)command {
|
||||||
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
|
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
|
||||||
manager.securityPolicy = securityPolicy;
|
manager.responseSerializer = [AFHTTPResponseSerializer serializer];
|
||||||
|
|
||||||
NSString *url = [command.arguments objectAtIndex:0];
|
NSString *url = [command.arguments objectAtIndex:0];
|
||||||
NSDictionary *headers = [command.arguments objectAtIndex:1];
|
NSDictionary *headers = [command.arguments objectAtIndex:1];
|
||||||
NSString *filePath = [command.arguments objectAtIndex: 2];
|
NSString *filePath = [command.arguments objectAtIndex: 2];
|
||||||
NSTimeInterval timeoutInSeconds = [[command.arguments objectAtIndex:3] doubleValue];
|
NSTimeInterval timeoutInSeconds = [[command.arguments objectAtIndex:3] doubleValue];
|
||||||
|
bool followRedirect = [[command.arguments objectAtIndex:4] boolValue];
|
||||||
|
NSNumber *reqId = [command.arguments objectAtIndex:5];
|
||||||
|
|
||||||
[self setRequestHeaders: headers forManager: manager];
|
[self setRequestHeaders: headers forManager: manager];
|
||||||
|
[self setupAuthChallengeBlock: manager];
|
||||||
[self setTimeout:timeoutInSeconds forManager:manager];
|
[self setTimeout:timeoutInSeconds forManager:manager];
|
||||||
[self setRedirect: manager];
|
[self setRedirect:followRedirect forManager:manager];
|
||||||
|
|
||||||
if ([filePath hasPrefix:@"file://"]) {
|
if ([filePath hasPrefix:@"file://"]) {
|
||||||
filePath = [filePath substringFromIndex:7];
|
filePath = [filePath substringFromIndex:7];
|
||||||
}
|
}
|
||||||
|
|
||||||
CordovaHttpPlugin* __weak weakSelf = self;
|
CordovaHttpPlugin* __weak weakSelf = self;
|
||||||
manager.responseSerializer = [AFHTTPResponseSerializer serializer];
|
|
||||||
[[SDNetworkActivityIndicator sharedActivityIndicator] startActivity];
|
[[SDNetworkActivityIndicator sharedActivityIndicator] startActivity];
|
||||||
|
|
||||||
@try {
|
@try {
|
||||||
[manager GET:url parameters:nil success:^(NSURLSessionTask *task, id responseObject) {
|
NSURLSessionDataTask *task = [manager GET:url parameters:nil progress: nil success:^(NSURLSessionTask *task, id responseObject) {
|
||||||
|
[weakSelf removeRequest:reqId];
|
||||||
/*
|
/*
|
||||||
*
|
*
|
||||||
* Licensed to the Apache Software Foundation (ASF) under one
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
@@ -547,6 +595,7 @@
|
|||||||
[weakSelf.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
|
[weakSelf.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
|
||||||
[[SDNetworkActivityIndicator sharedActivityIndicator] stopActivity];
|
[[SDNetworkActivityIndicator sharedActivityIndicator] stopActivity];
|
||||||
} failure:^(NSURLSessionTask *task, NSError *error) {
|
} failure:^(NSURLSessionTask *task, NSError *error) {
|
||||||
|
[weakSelf removeRequest:reqId];
|
||||||
NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];
|
NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];
|
||||||
[self handleError:dictionary withResponse:(NSHTTPURLResponse*)task.response error:error];
|
[self handleError:dictionary withResponse:(NSHTTPURLResponse*)task.response error:error];
|
||||||
[dictionary setObject:@"There was an error downloading the file" forKey:@"error"];
|
[dictionary setObject:@"There was an error downloading the file" forKey:@"error"];
|
||||||
@@ -555,6 +604,7 @@
|
|||||||
[weakSelf.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
|
[weakSelf.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
|
||||||
[[SDNetworkActivityIndicator sharedActivityIndicator] stopActivity];
|
[[SDNetworkActivityIndicator sharedActivityIndicator] stopActivity];
|
||||||
}];
|
}];
|
||||||
|
[self addRequest:reqId forTask:task];
|
||||||
}
|
}
|
||||||
@catch (NSException *exception) {
|
@catch (NSException *exception) {
|
||||||
[[SDNetworkActivityIndicator sharedActivityIndicator] stopActivity];
|
[[SDNetworkActivityIndicator sharedActivityIndicator] stopActivity];
|
||||||
@@ -562,4 +612,32 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)abort:(CDVInvokedUrlCommand*)command {
|
||||||
|
|
||||||
|
NSNumber *reqId = [command.arguments objectAtIndex:0];
|
||||||
|
|
||||||
|
CDVPluginResult *pluginResult;
|
||||||
|
bool removed = false;
|
||||||
|
NSURLSessionDataTask *task = [reqDict objectForKey:reqId];
|
||||||
|
if(task){
|
||||||
|
@try{
|
||||||
|
[task cancel];
|
||||||
|
removed = true;
|
||||||
|
} @catch (NSException *exception) {
|
||||||
|
NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];
|
||||||
|
[dictionary setValue:exception.userInfo forKey:@"error"];
|
||||||
|
[dictionary setObject:[NSNumber numberWithInt:-1] forKey:@"status"];
|
||||||
|
pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:dictionary];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!pluginResult){
|
||||||
|
NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];
|
||||||
|
[dictionary setObject:[NSNumber numberWithBool:removed] forKey:@"aborted"];
|
||||||
|
pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:dictionary];
|
||||||
|
}
|
||||||
|
|
||||||
|
[self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
|
||||||
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -5,6 +5,4 @@
|
|||||||
|
|
||||||
+ (instancetype)serializer;
|
+ (instancetype)serializer;
|
||||||
|
|
||||||
FOUNDATION_EXPORT NSString * const AFNetworkingOperationFailingURLResponseBodyKey;
|
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
#import "TextResponseSerializer.h"
|
#import "TextResponseSerializer.h"
|
||||||
|
|
||||||
NSString * const AFNetworkingOperationFailingURLResponseBodyKey = @"com.alamofire.serialization.response.error.body";
|
|
||||||
NSStringEncoding const SupportedEncodings[6] = { NSUTF8StringEncoding, NSWindowsCP1252StringEncoding, NSISOLatin1StringEncoding, NSISOLatin2StringEncoding, NSASCIIStringEncoding, NSUnicodeStringEncoding };
|
|
||||||
|
|
||||||
static NSError * AFErrorWithUnderlyingError(NSError *error, NSError *underlyingError) {
|
static NSError * AFErrorWithUnderlyingError(NSError *error, NSError *underlyingError) {
|
||||||
if (!error) {
|
if (!error) {
|
||||||
return underlyingError;
|
return underlyingError;
|
||||||
@@ -55,9 +52,14 @@ static BOOL AFErrorOrUnderlyingErrorHasCodeInDomain(NSError *error, NSInteger co
|
|||||||
nsEncoding = CFStringConvertEncodingToNSStringEncoding(cfEncoding);
|
nsEncoding = CFStringConvertEncodingToNSStringEncoding(cfEncoding);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < sizeof(SupportedEncodings) / sizeof(NSStringEncoding) && !decoded; ++i) {
|
NSStringEncoding supportedEncodings[6] = {
|
||||||
if (cfEncoding == kCFStringEncodingInvalidId || nsEncoding == SupportedEncodings[i]) {
|
NSUTF8StringEncoding, NSWindowsCP1252StringEncoding, NSISOLatin1StringEncoding,
|
||||||
decoded = [[NSString alloc] initWithData:rawResponseData encoding:SupportedEncodings[i]];
|
NSISOLatin2StringEncoding, NSASCIIStringEncoding, NSUnicodeStringEncoding
|
||||||
|
};
|
||||||
|
|
||||||
|
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]];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -94,7 +96,7 @@ static BOOL AFErrorOrUnderlyingErrorHasCodeInDomain(NSError *error, NSInteger co
|
|||||||
NSURLErrorFailingURLErrorKey:[response URL],
|
NSURLErrorFailingURLErrorKey:[response URL],
|
||||||
AFNetworkingOperationFailingURLResponseErrorKey: response,
|
AFNetworkingOperationFailingURLResponseErrorKey: response,
|
||||||
AFNetworkingOperationFailingURLResponseDataErrorKey: data,
|
AFNetworkingOperationFailingURLResponseDataErrorKey: data,
|
||||||
AFNetworkingOperationFailingURLResponseBodyKey: @"Could not decode response data due to invalid or unknown charset encoding",
|
AFNetworkingOperationFailingURLResponseBodyErrorKey: @"Could not decode response data due to invalid or unknown charset encoding",
|
||||||
} mutableCopy];
|
} mutableCopy];
|
||||||
|
|
||||||
validationError = AFErrorWithUnderlyingError([NSError errorWithDomain:AFURLResponseSerializationErrorDomain code:NSURLErrorBadServerResponse userInfo:mutableUserInfo], validationError);
|
validationError = AFErrorWithUnderlyingError([NSError errorWithDomain:AFURLResponseSerializationErrorDomain code:NSURLErrorBadServerResponse userInfo:mutableUserInfo], validationError);
|
||||||
@@ -108,7 +110,7 @@ static BOOL AFErrorOrUnderlyingErrorHasCodeInDomain(NSError *error, NSInteger co
|
|||||||
|
|
||||||
if (data) {
|
if (data) {
|
||||||
mutableUserInfo[AFNetworkingOperationFailingURLResponseDataErrorKey] = data;
|
mutableUserInfo[AFNetworkingOperationFailingURLResponseDataErrorKey] = data;
|
||||||
mutableUserInfo[AFNetworkingOperationFailingURLResponseBodyKey] = *decoded;
|
mutableUserInfo[AFNetworkingOperationFailingURLResponseBodyErrorKey] = *decoded;
|
||||||
}
|
}
|
||||||
|
|
||||||
validationError = AFErrorWithUnderlyingError([NSError errorWithDomain:AFURLResponseSerializationErrorDomain code:NSURLErrorBadServerResponse userInfo:mutableUserInfo], validationError);
|
validationError = AFErrorWithUnderlyingError([NSError errorWithDomain:AFURLResponseSerializationErrorDomain code:NSURLErrorBadServerResponse userInfo:mutableUserInfo], validationError);
|
||||||
|
|||||||
@@ -16,15 +16,15 @@
|
|||||||
<allow-intent href="mailto:*" />
|
<allow-intent href="mailto:*" />
|
||||||
<allow-intent href="geo:*" />
|
<allow-intent href="geo:*" />
|
||||||
<platform name="android">
|
<platform name="android">
|
||||||
|
<edit-config file="app/src/main/AndroidManifest.xml" mode="merge" target="/manifest/application" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<application android:networkSecurityConfig="@xml/network_security_config" />
|
||||||
|
</edit-config>
|
||||||
|
<resource-file src="network_security_config.xml" target="app/src/main/res/xml/network_security_config.xml" />
|
||||||
<allow-intent href="market:*" />
|
<allow-intent href="market:*" />
|
||||||
</platform>
|
</platform>
|
||||||
<platform name="ios">
|
<platform name="ios">
|
||||||
<allow-intent href="itms:*" />
|
<allow-intent href="itms:*" />
|
||||||
<allow-intent href="itms-apps:*" />
|
<allow-intent href="itms-apps:*" />
|
||||||
</platform>
|
</platform>
|
||||||
<engine name="android" spec="7.1.0" />
|
|
||||||
<engine name="browser" spec="5.0.0" />
|
|
||||||
<engine name="ios" spec="4.4.0" />
|
|
||||||
<plugin name="cordova-plugin-file" spec="6.0.1" />
|
|
||||||
<preference name="AndroidPersistentFileLocation" value="Internal" />
|
<preference name="AndroidPersistentFileLocation" value="Internal" />
|
||||||
</widget>
|
</widget>
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<network-security-config>
|
||||||
|
<domain-config cleartextTrafficPermitted="true">
|
||||||
|
<domain includeSubdomains="true">localhost</domain>
|
||||||
|
<domain includeSubdomains="true">httpbin.org</domain>
|
||||||
|
</domain-config>
|
||||||
|
</network-security-config>
|
||||||
@@ -1,26 +1,35 @@
|
|||||||
{
|
{
|
||||||
"name": "com.ilkimen.http.demo",
|
"name": "com.ilkimen.http.demo",
|
||||||
"displayName": "HttpDemo",
|
"displayName": "HttpDemo",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"description": "A sample Apache Cordova application that demonstrates advanced HTTP plugin.",
|
"description": "A sample Apache Cordova application that demonstrates advanced HTTP plugin.",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "scripts/build.sh",
|
"build": "scripts/build.sh",
|
||||||
"test": "npm run build && scripts/test.sh"
|
"test": "npm run build && scripts/test.sh"
|
||||||
},
|
},
|
||||||
"author": "Sefa Ilkimen",
|
"author": "Sefa Ilkimen",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"cordova": "7.0.1",
|
"cordova": "10.0.0",
|
||||||
"cordova-android": "7.1.0",
|
"cordova-android": "9.0.0",
|
||||||
"cordova-browser": "5.0.0",
|
"cordova-browser": "6.0.0",
|
||||||
"cordova-ios": "4.4.0"
|
"cordova-ios": "6.2.0",
|
||||||
},
|
"cordova-plugin-device": "2.0.3",
|
||||||
"cordova": {
|
"cordova-plugin-wkwebview-file-xhr": "3.0.0"
|
||||||
"platforms": [
|
},
|
||||||
"android",
|
"cordova": {
|
||||||
"ios"
|
"platforms": [
|
||||||
]
|
"android",
|
||||||
},
|
"ios",
|
||||||
"devDependencies": {}
|
"browser"
|
||||||
}
|
],
|
||||||
|
"plugins": {
|
||||||
|
"cordova-plugin-device": {},
|
||||||
|
"cordova-plugin-wkwebview-file-xhr": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"cordova-plugin-device": "2.0.3"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<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 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: blob:;">
|
||||||
<meta name="format-detection" content="telephone=no">
|
<meta name="format-detection" content="telephone=no">
|
||||||
<meta name="msapplication-tap-highlight" content="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">
|
<meta name="viewport" content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width">
|
||||||
|
|||||||
@@ -3,17 +3,34 @@ const app = {
|
|||||||
|
|
||||||
lastResult: null,
|
lastResult: null,
|
||||||
|
|
||||||
initialize: function() {
|
testsFlaggedToRun: [],
|
||||||
|
|
||||||
|
initialize: function () {
|
||||||
document.getElementById('nextBtn').addEventListener('click', app.onNextBtnClick);
|
document.getElementById('nextBtn').addEventListener('click', app.onNextBtnClick);
|
||||||
|
|
||||||
|
var onlyFlaggedTests = [];
|
||||||
|
var enabledTests = [];
|
||||||
|
|
||||||
|
tests.forEach(function (test) {
|
||||||
|
if (test.only) {
|
||||||
|
onlyFlaggedTests.push(test);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!test.disabled) {
|
||||||
|
enabledTests.push(test);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
app.testsFlaggedToRun = onlyFlaggedTests.length ? onlyFlaggedTests : enabledTests;
|
||||||
},
|
},
|
||||||
|
|
||||||
printResult: function(prefix, content) {
|
printResult: function (prefix, content) {
|
||||||
const text = prefix + ': ' + JSON.stringify(content);
|
const text = prefix + ': ' + JSON.stringify(content);
|
||||||
|
|
||||||
document.getElementById('resultTextarea').value += text;
|
document.getElementById('resultTextarea').value += text;
|
||||||
},
|
},
|
||||||
|
|
||||||
reject: function(content) {
|
reject: function (content) {
|
||||||
document.getElementById('statusInput').value = 'finished';
|
document.getElementById('statusInput').value = 'finished';
|
||||||
app.printResult('result - rejected', content);
|
app.printResult('result - rejected', content);
|
||||||
|
|
||||||
@@ -23,7 +40,7 @@ const app = {
|
|||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
resolve: function(content) {
|
resolve: function (content) {
|
||||||
document.getElementById('statusInput').value = 'finished';
|
document.getElementById('statusInput').value = 'finished';
|
||||||
app.printResult('result - resolved', content);
|
app.printResult('result - resolved', content);
|
||||||
|
|
||||||
@@ -33,7 +50,17 @@ const app = {
|
|||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
throw: function(error) {
|
skip: function (content) {
|
||||||
|
document.getElementById('statusInput').value = 'finished';
|
||||||
|
app.printResult('result - skipped', content);
|
||||||
|
|
||||||
|
app.lastResult = {
|
||||||
|
type: 'skipped',
|
||||||
|
data: content
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
throw: function (error) {
|
||||||
document.getElementById('statusInput').value = 'finished';
|
document.getElementById('statusInput').value = 'finished';
|
||||||
app.printResult('result - throwed', error.message);
|
app.printResult('result - throwed', error.message);
|
||||||
|
|
||||||
@@ -43,13 +70,13 @@ const app = {
|
|||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
getResult: function(cb) {
|
getResult: function (cb) {
|
||||||
cb(app.lastResult);
|
cb(app.lastResult);
|
||||||
},
|
},
|
||||||
|
|
||||||
runTest: function(index) {
|
runTest: function (tests, index) {
|
||||||
const testDefinition = tests[index];
|
const testDefinition = tests[index];
|
||||||
const titleText = app.testIndex + ': ' + testDefinition.description;
|
const titleText = index + ': ' + testDefinition.description;
|
||||||
const expectedText = 'expected - ' + testDefinition.expected;
|
const expectedText = 'expected - ' + testDefinition.expected;
|
||||||
|
|
||||||
document.getElementById('statusInput').value = 'running';
|
document.getElementById('statusInput').value = 'running';
|
||||||
@@ -57,32 +84,68 @@ const app = {
|
|||||||
document.getElementById('resultTextarea').value = '';
|
document.getElementById('resultTextarea').value = '';
|
||||||
document.getElementById('descriptionLbl').innerText = titleText;
|
document.getElementById('descriptionLbl').innerText = titleText;
|
||||||
|
|
||||||
try {
|
const onSuccessFactory = function (cbChain) {
|
||||||
testDefinition.func(app.resolve, app.reject);
|
return function () {
|
||||||
} catch (error) {
|
cbChain.shift()(cbChain);
|
||||||
app.throw(error);
|
}
|
||||||
}
|
};
|
||||||
},
|
|
||||||
|
|
||||||
onBeforeTest: function(testIndex, cb) {
|
const onFailFactory = function (prefix) {
|
||||||
app.lastResult = null;
|
return function (errorMessage) {
|
||||||
|
app.reject(prefix + ': ' + errorMessage);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
if (hooks && hooks.onBeforeEachTest) {
|
const onThrowedHandler = function (prefix, error) {
|
||||||
return hooks.onBeforeEachTest(function() {
|
app.throw(new Error(prefix + ': ' + error.message));
|
||||||
const testDefinition = tests[testIndex];
|
};
|
||||||
|
|
||||||
if (testDefinition.before) {
|
const execBeforeEachTest = function (cbChain) {
|
||||||
testDefinition.before(cb);
|
const prefix = 'in before each hook';
|
||||||
} else {
|
|
||||||
cb();
|
try {
|
||||||
|
if (!hooks || !hooks.onBeforeEachTest) {
|
||||||
|
return onSuccessFactory(cbChain)();
|
||||||
}
|
}
|
||||||
});
|
|
||||||
} else {
|
hooks.onBeforeEachTest(
|
||||||
cb();
|
onSuccessFactory(cbChain),
|
||||||
}
|
onFailFactory(prefix)
|
||||||
|
);
|
||||||
|
} catch (error) {
|
||||||
|
onThrowedHandler(prefix, error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const execBeforeTest = function (cbChain) {
|
||||||
|
const prefix = 'in before hook';
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (!testDefinition.before) {
|
||||||
|
return onSuccessFactory(cbChain)();
|
||||||
|
}
|
||||||
|
|
||||||
|
testDefinition.before(
|
||||||
|
onSuccessFactory(cbChain),
|
||||||
|
onFailFactory(prefix)
|
||||||
|
);
|
||||||
|
} catch (error) {
|
||||||
|
onThrowedHandler(prefix, error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const execTest = function () {
|
||||||
|
try {
|
||||||
|
testDefinition.func(app.resolve, app.reject, app.skip);
|
||||||
|
} catch (error) {
|
||||||
|
app.throw(error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
onSuccessFactory([execBeforeEachTest, execBeforeTest, execTest])();
|
||||||
},
|
},
|
||||||
|
|
||||||
onFinishedAllTests: function() {
|
onFinishedAllTests: function () {
|
||||||
const titleText = 'No more tests';
|
const titleText = 'No more tests';
|
||||||
const expectedText = 'You have run all available tests.';
|
const expectedText = 'You have run all available tests.';
|
||||||
|
|
||||||
@@ -91,13 +154,11 @@ const app = {
|
|||||||
document.getElementById('descriptionLbl').innerText = titleText;
|
document.getElementById('descriptionLbl').innerText = titleText;
|
||||||
},
|
},
|
||||||
|
|
||||||
onNextBtnClick: function() {
|
onNextBtnClick: function () {
|
||||||
app.testIndex += 1;
|
app.testIndex += 1;
|
||||||
|
|
||||||
if (app.testIndex < tests.length) {
|
if (app.testIndex < app.testsFlaggedToRun.length) {
|
||||||
app.onBeforeTest(app.testIndex, function() {
|
app.runTest(app.testsFlaggedToRun, app.testIndex);
|
||||||
app.runTest(app.testIndex);
|
|
||||||
});
|
|
||||||
} else {
|
} else {
|
||||||
app.onFinishedAllTests();
|
app.onFinishedAllTests();
|
||||||
}
|
}
|
||||||
|
|||||||
Binary file not shown.
|
After Width: | Height: | Size: 7.1 KiB |
+678
-121
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,89 @@
|
|||||||
|
module.exports = { getCaps };
|
||||||
|
|
||||||
|
const path = require('path');
|
||||||
|
|
||||||
|
const configs = {
|
||||||
|
// testing on local machine
|
||||||
|
localIosDevice: {
|
||||||
|
platformName: 'iOS',
|
||||||
|
platformVersion: '10.3',
|
||||||
|
automationName: 'XCUITest',
|
||||||
|
deviceName: 'iPhone 8',
|
||||||
|
autoWebview: true,
|
||||||
|
app: path.resolve('temp/platforms/ios/build/emulator/HttpDemo.app')
|
||||||
|
},
|
||||||
|
localIosEmulator: {
|
||||||
|
platformName: 'iOS',
|
||||||
|
platformVersion: '14.3',
|
||||||
|
automationName: 'XCUITest',
|
||||||
|
deviceName: 'iPhone 8',
|
||||||
|
autoWebview: true,
|
||||||
|
app: path.resolve('temp/platforms/ios/build/emulator/HttpDemo.app')
|
||||||
|
},
|
||||||
|
localAndroidEmulator: {
|
||||||
|
platformName: 'Android',
|
||||||
|
platformVersion: '9',
|
||||||
|
deviceName: 'Android Emulator',
|
||||||
|
autoWebview: true,
|
||||||
|
fullReset: true,
|
||||||
|
app: path.resolve('temp/platforms/android/app/build/outputs/apk/debug/app-debug.apk')
|
||||||
|
},
|
||||||
|
|
||||||
|
// testing on SauceLabs
|
||||||
|
saucelabsIosDevice: {
|
||||||
|
browserName: '',
|
||||||
|
'appium-version': '1.20.1',
|
||||||
|
platformName: 'iOS',
|
||||||
|
platformVersion: '14.3',
|
||||||
|
deviceName: 'iPhone 6',
|
||||||
|
autoWebview: true,
|
||||||
|
app: 'sauce-storage:HttpDemo.app.zip'
|
||||||
|
},
|
||||||
|
saucelabsIosEmulator: {
|
||||||
|
browserName: '',
|
||||||
|
'appium-version': '1.20.1',
|
||||||
|
platformName: 'iOS',
|
||||||
|
platformVersion: '14.3',
|
||||||
|
deviceName: 'iPhone Simulator',
|
||||||
|
autoWebview: true,
|
||||||
|
app: 'sauce-storage:HttpDemo.app.zip'
|
||||||
|
},
|
||||||
|
saucelabsAndroidEmulator: {
|
||||||
|
browserName: '',
|
||||||
|
'appium-version': '1.20.1',
|
||||||
|
platformName: 'Android',
|
||||||
|
platformVersion: '8.0',
|
||||||
|
deviceName: 'Android Emulator',
|
||||||
|
autoWebview: true,
|
||||||
|
app: 'sauce-storage:HttpDemo.apk'
|
||||||
|
},
|
||||||
|
|
||||||
|
// testing on BrowserStack
|
||||||
|
browserstackIosDevice: {
|
||||||
|
device: 'iPhone 12',
|
||||||
|
os_version: '14',
|
||||||
|
project: 'HTTP Test App',
|
||||||
|
autoWebview: true,
|
||||||
|
app: 'HttpTestAppAndroid'
|
||||||
|
},
|
||||||
|
browserstackAndroidDevice: {
|
||||||
|
device: 'Google Nexus 6',
|
||||||
|
os_version: '6.0',
|
||||||
|
project: 'HTTP Test App',
|
||||||
|
autoWebview: true,
|
||||||
|
app: 'HttpTestAppAndroid'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
function getCaps(environment, os, runtime) {
|
||||||
|
const key = environment.toLowerCase() + capitalize(os) + capitalize(runtime);
|
||||||
|
const caps = configs[key];
|
||||||
|
|
||||||
|
caps.name = `cordova-plugin-advanced-http (${os})`;
|
||||||
|
|
||||||
|
return caps;
|
||||||
|
};
|
||||||
|
|
||||||
|
function capitalize(text) {
|
||||||
|
return text.charAt(0).toUpperCase() + text.slice(1).toLowerCase();
|
||||||
|
}
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
const path = require('path');
|
|
||||||
|
|
||||||
if (process.env.SAUCE_USERNAME) {
|
|
||||||
exports.iosTestApp = 'sauce-storage:HttpDemo.app.zip';
|
|
||||||
exports.androidTestApp = 'sauce-storage:HttpDemo.apk';
|
|
||||||
} else {
|
|
||||||
// these paths are relative to working directory
|
|
||||||
exports.iosTestApp = path.resolve('temp/platforms/ios/build/emulator/HttpDemo.app');
|
|
||||||
exports.androidTestApp = path.resolve('temp/platforms/android/app/build/outputs/apk/debug/app-debug.apk');
|
|
||||||
}
|
|
||||||
@@ -1,60 +0,0 @@
|
|||||||
const local = {
|
|
||||||
iosDevice: {
|
|
||||||
platformName: 'iOS',
|
|
||||||
platformVersion: '10.3',
|
|
||||||
deviceName: 'iPhone 6',
|
|
||||||
autoWebview: true,
|
|
||||||
app: undefined // will be set later
|
|
||||||
},
|
|
||||||
iosEmulator: {
|
|
||||||
platformName: 'iOS',
|
|
||||||
platformVersion: '11.0',
|
|
||||||
deviceName: 'iPhone Simulator',
|
|
||||||
autoWebview: true,
|
|
||||||
app: undefined // will be set later
|
|
||||||
},
|
|
||||||
androidEmulator: {
|
|
||||||
platformName: 'Android',
|
|
||||||
platformVersion: '5.1',
|
|
||||||
deviceName: 'Android Emulator',
|
|
||||||
autoWebview: true,
|
|
||||||
fullReset: true,
|
|
||||||
app: undefined // will be set later
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const sauce = {
|
|
||||||
iosDevice: {
|
|
||||||
browserName: '',
|
|
||||||
'appium-version': '1.7.1',
|
|
||||||
platformName: 'iOS',
|
|
||||||
platformVersion: '10.3',
|
|
||||||
deviceName: 'iPhone 6',
|
|
||||||
autoWebview: true,
|
|
||||||
app: undefined // will be set later
|
|
||||||
},
|
|
||||||
iosEmulator: {
|
|
||||||
browserName: '',
|
|
||||||
'appium-version': '1.7.1',
|
|
||||||
platformName: 'iOS',
|
|
||||||
platformVersion: '10.3',
|
|
||||||
deviceName: 'iPhone Simulator',
|
|
||||||
autoWebview: true,
|
|
||||||
app: undefined // will be set later
|
|
||||||
},
|
|
||||||
androidEmulator: {
|
|
||||||
browserName: '',
|
|
||||||
'appium-version': '1.7.1',
|
|
||||||
platformName: 'Android',
|
|
||||||
platformVersion: '5.1',
|
|
||||||
deviceName: 'Android Emulator',
|
|
||||||
autoWebview: true,
|
|
||||||
app: undefined // will be set later
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if (process.env.SAUCE_USERNAME) {
|
|
||||||
module.exports = sauce;
|
|
||||||
} else {
|
|
||||||
module.exports = local;
|
|
||||||
}
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
const local = {
|
|
||||||
host: 'localhost',
|
|
||||||
port: 4723
|
|
||||||
};
|
|
||||||
|
|
||||||
const sauce = {
|
|
||||||
host: 'ondemand.saucelabs.com',
|
|
||||||
port: 80,
|
|
||||||
auth: process.env.SAUCE_USERNAME + ":" + process.env.SAUCE_ACCESS_KEY
|
|
||||||
};
|
|
||||||
|
|
||||||
if (process.env.SAUCE_USERNAME) {
|
|
||||||
module.exports = sauce;
|
|
||||||
} else {
|
|
||||||
module.exports = local;
|
|
||||||
}
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
const wd = require("wd");
|
|
||||||
|
|
||||||
require('colors');
|
|
||||||
|
|
||||||
const chai = require('chai');
|
|
||||||
const chaiAsPromised = require('chai-as-promised');
|
|
||||||
chai.use(chaiAsPromised);
|
|
||||||
|
|
||||||
const should = chai.should();
|
|
||||||
chaiAsPromised.transferPromiseness = wd.transferPromiseness;
|
|
||||||
|
|
||||||
exports.should = should;
|
|
||||||
@@ -1,4 +1,8 @@
|
|||||||
exports.configure = driver => {
|
module.exports = { setupLogging };
|
||||||
|
|
||||||
|
function setupLogging(driver) {
|
||||||
|
require('colors');
|
||||||
|
|
||||||
driver.on('status', info => {
|
driver.on('status', info => {
|
||||||
console.log(info.cyan);
|
console.log(info.cyan);
|
||||||
});
|
});
|
||||||
@@ -10,4 +14,4 @@ exports.configure = driver => {
|
|||||||
driver.on('http', (meth, path, data) => {
|
driver.on('http', (meth, path, data) => {
|
||||||
console.log(' > ' + meth.magenta, path, (data || '').grey);
|
console.log(' > ' + meth.magenta, path, (data || '').grey);
|
||||||
});
|
});
|
||||||
};
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
module.exports = { getServer };
|
||||||
|
|
||||||
|
const configs = {
|
||||||
|
local: {
|
||||||
|
host: 'localhost',
|
||||||
|
port: 4723
|
||||||
|
},
|
||||||
|
saucelabs: {
|
||||||
|
host: 'ondemand.saucelabs.com',
|
||||||
|
port: 80,
|
||||||
|
auth: process.env.SAUCE_USERNAME + ":" + process.env.SAUCE_ACCESS_KEY
|
||||||
|
},
|
||||||
|
browserstack: {
|
||||||
|
host: 'hub-cloud.browserstack.com',
|
||||||
|
port: 80,
|
||||||
|
auth: process.env.BROWSERSTACK_USERNAME + ":" + process.env.BROWSERSTACK_ACCESS_KEY
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getServer(environment) {
|
||||||
|
return configs[environment.toLowerCase()];
|
||||||
|
}
|
||||||
+116
-76
@@ -1,94 +1,134 @@
|
|||||||
require('./helpers/setup');
|
|
||||||
|
|
||||||
const wd = require('wd');
|
const wd = require('wd');
|
||||||
const apps = require('./helpers/apps');
|
const chai = require('chai');
|
||||||
const caps = Object.assign({}, require('./helpers/caps'));
|
const logging = require('./logging');
|
||||||
const serverConfig = require('./helpers/server');
|
const capsConfig = require('./caps');
|
||||||
|
const serverConfig = require('./server');
|
||||||
const testDefinitions = require('../e2e-specs');
|
const testDefinitions = require('../e2e-specs');
|
||||||
const pkgjson = require('../../package.json');
|
|
||||||
|
|
||||||
describe('Advanced HTTP', function() {
|
global.should = chai.should();
|
||||||
|
|
||||||
|
describe('Advanced HTTP e2e test suite', function () {
|
||||||
|
const isSauceLabs = !!process.env.SAUCE_USERNAME;
|
||||||
|
const isBrowserStack = !!process.env.BROWSERSTACK_USERNAME;
|
||||||
|
const isVerbose = process.argv.includes('--verbose');
|
||||||
const isDevice = process.argv.includes('--device');
|
const isDevice = process.argv.includes('--device');
|
||||||
const isAndroid = process.argv.includes('--android');
|
const isAndroid = process.argv.includes('--android');
|
||||||
const targetInfo = { isDevice, isAndroid };
|
|
||||||
|
|
||||||
let driver = null;
|
const targetInfo = { isSauceLabs, isBrowserStack, isDevice, isAndroid };
|
||||||
|
const environment = isSauceLabs ? 'saucelabs' : isBrowserStack ? 'browserstack' : 'local';
|
||||||
|
|
||||||
|
let driver;
|
||||||
let allPassed = true;
|
let allPassed = true;
|
||||||
|
|
||||||
this.timeout(900000);
|
this.timeout(15000);
|
||||||
|
this.slow(4000);
|
||||||
|
|
||||||
const getCaps = appName => {
|
before(async function () {
|
||||||
const desiredOs = isAndroid ? 'android' : 'ios';
|
// connecting to saucelabs can take some time
|
||||||
const desiredCaps = caps[desiredOs + (isDevice ? 'Device' : 'Emulator')];
|
this.timeout(300000);
|
||||||
const desiredApp = apps[desiredOs + appName];
|
|
||||||
|
|
||||||
desiredCaps.name = pkgjson.name + ` (${desiredOs})`;
|
driver = await wd.promiseChainRemote(serverConfig.getServer(environment));
|
||||||
desiredCaps.app = desiredApp;
|
|
||||||
|
|
||||||
return desiredCaps;
|
if (isVerbose) {
|
||||||
|
logging.setupLogging(driver);
|
||||||
|
}
|
||||||
|
|
||||||
|
await driver.init(
|
||||||
|
capsConfig.getCaps(
|
||||||
|
environment,
|
||||||
|
isAndroid ? 'android' : 'ios',
|
||||||
|
isDevice ? 'device' : 'emulator'
|
||||||
|
)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
after(async function () {
|
||||||
|
await driver.quit().finally(
|
||||||
|
() => isSauceLabs && driver.sauceJobStatus(allPassed)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
const defineTestForMocha = (test, index) => {
|
||||||
|
it(index + ': ' + test.description, async function () {
|
||||||
|
await clickNext(driver);
|
||||||
|
await validateTestIndex(driver, index);
|
||||||
|
await validateTestTitle(driver, test.description);
|
||||||
|
await waitToBeFinished(driver, test.timeout || 10000);
|
||||||
|
|
||||||
|
const skipped = await checkSkipped(driver);
|
||||||
|
|
||||||
|
if (skipped) {
|
||||||
|
this.skip();
|
||||||
|
} else {
|
||||||
|
await validateResult(driver, test.validationFunc, targetInfo);
|
||||||
|
}
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const validateTestIndex = number => driver
|
const onlyFlaggedTests = [];
|
||||||
.elementById('descriptionLbl')
|
const enabledTests = [];
|
||||||
.text()
|
|
||||||
.then(text => parseInt(text.match(/(\d+):/)[1], 10))
|
|
||||||
.should.eventually.become(number, 'Test index is not matching!');
|
|
||||||
|
|
||||||
const validateTestTitle = testTitle => driver
|
testDefinitions.tests.forEach(test => {
|
||||||
.elementById('descriptionLbl')
|
if (test.only) {
|
||||||
.text()
|
onlyFlaggedTests.push(test);
|
||||||
.then(text => text.match(/\d+:\ (.*)/)[1])
|
}
|
||||||
.should.eventually.become(testTitle, 'Test description is not matching!');
|
|
||||||
|
|
||||||
const waitToBeFinished = timeout => new Promise((resolve, reject) => {
|
if (!test.disabled) {
|
||||||
const timeoutTimestamp = Date.now() + timeout;
|
enabledTests.push(test);
|
||||||
const checkIfFinished = () => driver
|
}
|
||||||
.elementById('statusInput')
|
|
||||||
.getValue()
|
|
||||||
.then(value => {
|
|
||||||
if (value === 'finished') {
|
|
||||||
resolve();
|
|
||||||
} else if (Date.now() > timeoutTimestamp) {
|
|
||||||
reject('Test function timed out!');
|
|
||||||
} else {
|
|
||||||
setTimeout(checkIfFinished, 500);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
checkIfFinished();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const validateResult = testDefinition => driver
|
if (onlyFlaggedTests.length) {
|
||||||
.safeExecute('app.lastResult')
|
onlyFlaggedTests.forEach(defineTestForMocha);
|
||||||
.then(result => testDefinition.validationFunc(driver, result, targetInfo));
|
} else {
|
||||||
|
enabledTests.forEach(defineTestForMocha);
|
||||||
const clickNext = () => driver
|
}
|
||||||
.elementById('nextBtn')
|
|
||||||
.click()
|
|
||||||
.sleep(1000);
|
|
||||||
|
|
||||||
before(() => {
|
|
||||||
driver = wd.promiseChainRemote(serverConfig);
|
|
||||||
require('./helpers/logging').configure(driver);
|
|
||||||
|
|
||||||
return driver.init(getCaps('TestApp'));
|
|
||||||
});
|
|
||||||
|
|
||||||
after(() => driver
|
|
||||||
.quit()
|
|
||||||
.finally(function () {
|
|
||||||
if (process.env.SAUCE_USERNAME) {
|
|
||||||
return driver.sauceJobStatus(allPassed);
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
|
|
||||||
testDefinitions.tests.forEach((definition, index) => {
|
|
||||||
it(index + ': ' + definition.description, function() {
|
|
||||||
return clickNext()
|
|
||||||
.then(() => validateTestIndex(index))
|
|
||||||
.then(() => validateTestTitle(definition.description))
|
|
||||||
.then(() => waitToBeFinished(definition.timeout || 10000))
|
|
||||||
.then(() => validateResult(definition))
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
async function clickNext(driver) {
|
||||||
|
await driver.elementById('nextBtn').click().sleep(1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function validateTestIndex(driver, testIndex) {
|
||||||
|
const description = await driver.elementById('descriptionLbl').text();
|
||||||
|
const index = parseInt(description.match(/(\d+):/)[1], 10);
|
||||||
|
|
||||||
|
index.should.be.equal(testIndex, 'Test index is not matching!');
|
||||||
|
}
|
||||||
|
|
||||||
|
async function validateTestTitle(driver, testTitle) {
|
||||||
|
const description = await driver.elementById('descriptionLbl').text();
|
||||||
|
const title = description.match(/\d+:\ (.*)/)[1];
|
||||||
|
|
||||||
|
title.should.be.equal(testTitle, 'Test description is not matching!');
|
||||||
|
}
|
||||||
|
|
||||||
|
async function waitToBeFinished(driver, timeout) {
|
||||||
|
const timeoutTimestamp = Date.now() + timeout;
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
if (await driver.elementById('statusInput').getValue() === 'finished') {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Date.now() > timeoutTimestamp) {
|
||||||
|
throw new Error('Test function timed out!');
|
||||||
|
}
|
||||||
|
|
||||||
|
await sleep(500);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function validateResult(driver, validationFunc, targetInfo) {
|
||||||
|
const result = await driver.safeExecute('app.lastResult');
|
||||||
|
validationFunc(driver, result, targetInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function checkSkipped(driver) {
|
||||||
|
const result = await driver.safeExecute('app.lastResult');
|
||||||
|
return result.type === 'skipped';
|
||||||
|
}
|
||||||
|
|
||||||
|
function sleep(ms) {
|
||||||
|
return new Promise(resolve => setTimeout(resolve, ms));
|
||||||
|
}
|
||||||
|
|||||||
+593
-11
@@ -1,33 +1,41 @@
|
|||||||
const chai = require('chai');
|
const chai = require('chai');
|
||||||
const mock = require('mock-require');
|
const util = require('util');
|
||||||
const should = chai.should();
|
const should = chai.should();
|
||||||
|
|
||||||
|
const BlobMock = require('./mocks/Blob.mock');
|
||||||
|
const ConsoleMock = require('./mocks/Console.mock');
|
||||||
|
const FileMock = require('./mocks/File.mock');
|
||||||
|
const FileReaderMock = require('./mocks/FileReader.mock');
|
||||||
|
const FormDataMock = require('./mocks/FormData.mock');
|
||||||
|
|
||||||
describe('Advanced HTTP public interface', function () {
|
describe('Advanced HTTP public interface', function () {
|
||||||
|
const messages = require('../www/messages');
|
||||||
|
|
||||||
let http = {};
|
let http = {};
|
||||||
|
|
||||||
const noop = () => { /* intentionally doing nothing */ };
|
const noop = () => { /* intentionally doing nothing */ };
|
||||||
|
|
||||||
const getDependenciesBlueprint = () => {
|
const getDependenciesBlueprint = () => {
|
||||||
const messages = require('../www/messages');
|
|
||||||
const globalConfigs = require('../www/global-configs');
|
const globalConfigs = require('../www/global-configs');
|
||||||
const jsUtil = require('../www/js-util');
|
const jsUtil = require('../www/js-util');
|
||||||
const ToughCookie = require('../www/umd-tough-cookie');
|
const ToughCookie = require('../www/umd-tough-cookie');
|
||||||
const lodash = require('../www/lodash');
|
const lodash = require('../www/lodash');
|
||||||
|
const errorCodes = require('../www/error-codes');
|
||||||
const WebStorageCookieStore = require('../www/local-storage-store')(ToughCookie, lodash);
|
const WebStorageCookieStore = require('../www/local-storage-store')(ToughCookie, lodash);
|
||||||
const cookieHandler = require('../www/cookie-handler')(null, ToughCookie, WebStorageCookieStore);
|
const cookieHandler = require('../www/cookie-handler')(null, ToughCookie, WebStorageCookieStore);
|
||||||
const helpers = require('../www/helpers')(jsUtil, cookieHandler, messages);
|
const helpers = require('../www/helpers')(null, jsUtil, cookieHandler, messages, errorCodes);
|
||||||
const urlUtil = require('../www/url-util')(jsUtil);
|
const urlUtil = require('../www/url-util')(jsUtil);
|
||||||
|
|
||||||
return { exec: noop, cookieHandler, urlUtil: urlUtil, helpers, globalConfigs };
|
return { exec: noop, cookieHandler, urlUtil: urlUtil, helpers, globalConfigs, errorCodes };
|
||||||
};
|
};
|
||||||
|
|
||||||
const loadHttp = (deps) => {
|
const loadHttp = (deps) => {
|
||||||
http = require('../www/public-interface')(deps.exec, deps.cookieHandler, deps.urlUtil, deps.helpers, deps.globalConfigs);
|
http = require('../www/public-interface')(deps.exec, deps.cookieHandler, deps.urlUtil, deps.helpers, deps.globalConfigs, deps.errorCodes);
|
||||||
};
|
};
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
// mocked btoa function (base 64 encoding strings)
|
// mocked btoa function (base 64 encoding strings)
|
||||||
global.btoa = decoded => new Buffer(decoded).toString('base64');
|
global.btoa = decoded => Buffer.from(decoded).toString('base64');
|
||||||
loadHttp(getDependenciesBlueprint());
|
loadHttp(getDependenciesBlueprint());
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -41,6 +49,13 @@ describe('Advanced HTTP public interface', function () {
|
|||||||
http.getHeaders('*').myKey.should.equal('myValue');
|
http.getHeaders('*').myKey.should.equal('myValue');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('clears global headers correctly when value is undefined', () => {
|
||||||
|
http.setHeader('*', 'myKey', 'myValue');
|
||||||
|
http.setHeader('*', 'myKey', null);
|
||||||
|
should.equal(undefined, http.getHeaders('*').myKey);
|
||||||
|
Object.keys(http.getHeaders('*')).length.should.be.equal(0);
|
||||||
|
});
|
||||||
|
|
||||||
it('sets host headers correctly #24', () => {
|
it('sets host headers correctly #24', () => {
|
||||||
http.setHeader('www.google.de', 'myKey', 'myValue');
|
http.setHeader('www.google.de', 'myKey', 'myValue');
|
||||||
http.getHeaders('www.google.de').myKey.should.equal('myValue');
|
http.getHeaders('www.google.de').myKey.should.equal('myValue');
|
||||||
@@ -127,7 +142,29 @@ describe('Advanced HTTP public interface', function () {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('throws an Error when you try to add a cookie by using "setHeader" #46', () => {
|
it('throws an Error when you try to add a cookie by using "setHeader" #46', () => {
|
||||||
(function () { http.setHeader('*', 'cookie', 'value') }).should.throw();
|
(() => { http.setHeader('*', 'cookie', 'value'); }).should.throw(messages.ADDING_COOKIES_NOT_SUPPORTED);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('configures global timeout value correctly with given valid value', () => {
|
||||||
|
http.setRequestTimeout(10);
|
||||||
|
http.getRequestTimeout().should.equal(10);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('throws an Error when you try to configure global timeout with a string', () => {
|
||||||
|
(() => { http.setRequestTimeout('myString'); }).should.throw(messages.INVALID_TIMEOUT_VALUE);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('sets global option for following redirects correctly', () => {
|
||||||
|
http.setFollowRedirect(false);
|
||||||
|
http.getFollowRedirect().should.equal(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('throws an Error when you try to configure global option for following redirects with a string', () => {
|
||||||
|
(() => { http.setFollowRedirect('myString'); }).should.throw(messages.INVALID_FOLLOW_REDIRECT_VALUE);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('exposes an enumeration style object with mappings for the error codes', () => {
|
||||||
|
Object.keys(http.ErrorCode).forEach(key => http.ErrorCode[key].should.be.a('number'));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -241,24 +278,569 @@ describe('Common helpers', function () {
|
|||||||
const init = require('../www/helpers');
|
const init = require('../www/helpers');
|
||||||
init.debug = true;
|
init.debug = true;
|
||||||
|
|
||||||
const helpers = init(null, null, null);
|
const helpers = init(null, null, null, null, null, null);
|
||||||
|
|
||||||
it('merges empty header sets correctly', () => {
|
it('merges empty header sets correctly', () => {
|
||||||
helpers.mergeHeaders({}, {}).should.eql({});
|
helpers.mergeHeaders({}, {}).should.eql({});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('merges simple header sets without collision correctly', () => {
|
||||||
|
helpers.mergeHeaders({ a: 1 }, { b: 2 }).should.eql({ a: 1, b: 2 });
|
||||||
|
});
|
||||||
|
|
||||||
|
it('merges header sets with collision correctly', () => {
|
||||||
|
helpers.mergeHeaders({ a: 1 }, { a: 2 }).should.eql({ a: 2 });
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('getCookieHeader(url)', function () {
|
describe('getCookieHeader(url)', function () {
|
||||||
it('resolves cookie header correctly when no cookie is set #198', () => {
|
it('resolves cookie header correctly when no cookie is set #198', () => {
|
||||||
const helpers = require('../www/helpers')(null, { getCookieString: () => '' }, null);
|
const helpers = require('../www/helpers')(null, null, { getCookieString: () => '' }, null);
|
||||||
|
|
||||||
helpers.getCookieHeader('http://ilkimen.net').should.eql({});
|
helpers.getCookieHeader('http://ilkimen.net').should.eql({});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('resolves cookie header correctly when a cookie is set', () => {
|
it('resolves cookie header correctly when a cookie is set', () => {
|
||||||
const helpers = require('../www/helpers')(null, { getCookieString: () => 'cookie=value' }, null);
|
const helpers = require('../www/helpers')(null, null, { getCookieString: () => 'cookie=value' }, null);
|
||||||
|
|
||||||
helpers.getCookieHeader('http://ilkimen.net').should.eql({ Cookie: 'cookie=value' });
|
helpers.getCookieHeader('http://ilkimen.net').should.eql({ Cookie: 'cookie=value' });
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
})
|
|
||||||
|
describe('checkClientAuthOptions()', function () {
|
||||||
|
const jsUtil = require('../www/js-util');
|
||||||
|
const messages = require('../www/messages');
|
||||||
|
const helpers = require('../www/helpers')(null, jsUtil, null, messages);
|
||||||
|
|
||||||
|
it('returns options object with empty values when mode is "none" and no options are given', () => {
|
||||||
|
helpers.checkClientAuthOptions('none').should.eql({
|
||||||
|
alias: null,
|
||||||
|
rawPkcs: null,
|
||||||
|
pkcsPassword: ''
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns options object with empty values when mode is "none" and random options are given', () => {
|
||||||
|
helpers.checkClientAuthOptions('none', {
|
||||||
|
alias: 'myAlias',
|
||||||
|
pkcsPath: 'myPath'
|
||||||
|
}).should.eql({
|
||||||
|
alias: null,
|
||||||
|
rawPkcs: null,
|
||||||
|
pkcsPassword: ''
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('throws an error when mode is "systemstore" and alias is not a string or undefined', () => {
|
||||||
|
(() => helpers.checkClientAuthOptions('systemstore', { alias: 1 }))
|
||||||
|
.should.throw(messages.INVALID_CLIENT_AUTH_ALIAS);
|
||||||
|
|
||||||
|
(() => helpers.checkClientAuthOptions('systemstore', { alias: undefined }))
|
||||||
|
.should.not.throw();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns an object with null alias when mode is "systemstore" and no options object is given', () => {
|
||||||
|
helpers.checkClientAuthOptions('systemstore').should.eql({
|
||||||
|
alias: null,
|
||||||
|
rawPkcs: null,
|
||||||
|
pkcsPassword: ''
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('throws an error when mode is "buffer" and rawPkcs is not an array buffer', () => {
|
||||||
|
(() => helpers.checkClientAuthOptions('buffer', {
|
||||||
|
rawPkcs: undefined,
|
||||||
|
pkcsPassword: 'password'
|
||||||
|
})).should.throw(messages.INVALID_CLIENT_AUTH_RAW_PKCS);
|
||||||
|
|
||||||
|
(() => helpers.checkClientAuthOptions('buffer', {
|
||||||
|
pkcsPath: 1,
|
||||||
|
pkcsPassword: 'password'
|
||||||
|
})).should.throw(messages.INVALID_CLIENT_AUTH_RAW_PKCS);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('throws an error when mode is "buffer" and pkcsPassword is not a string', () => {
|
||||||
|
(() => helpers.checkClientAuthOptions('buffer', {
|
||||||
|
rawPkcs: new ArrayBuffer(),
|
||||||
|
pkcsPassword: undefined
|
||||||
|
})).should.throw(messages.INVALID_CLIENT_AUTH_PKCS_PASSWORD);
|
||||||
|
|
||||||
|
(() => helpers.checkClientAuthOptions('buffer', {
|
||||||
|
rawPkcs: new ArrayBuffer(),
|
||||||
|
pkcsPassword: 1
|
||||||
|
})).should.throw(messages.INVALID_CLIENT_AUTH_PKCS_PASSWORD);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('handleMissingOptions()', function () {
|
||||||
|
const jsUtil = require('../www/js-util');
|
||||||
|
const messages = require('../www/messages');
|
||||||
|
const helpers = require('../www/helpers')(null, jsUtil, null, messages);
|
||||||
|
const mockGlobals = {
|
||||||
|
headers: {},
|
||||||
|
serializer: 'urlencoded',
|
||||||
|
followRedirect: true,
|
||||||
|
timeout: 60.0,
|
||||||
|
}
|
||||||
|
|
||||||
|
it('adds missing "followRedirect" option correctly', () => {
|
||||||
|
helpers.handleMissingOptions({}, mockGlobals).should.include({ followRedirect: true });
|
||||||
|
});
|
||||||
|
|
||||||
|
it('throws an error when "followRedirect" option is not a boolean', () => {
|
||||||
|
(() => helpers.handleMissingOptions({ followRedirect: 1 }, mockGlobals))
|
||||||
|
.should.throw(messages.INVALID_FOLLOW_REDIRECT_VALUE);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('injectRawResponseHandler()', function () {
|
||||||
|
const jsUtil = require('../www/js-util');
|
||||||
|
const messages = require('../www/messages');
|
||||||
|
const errorCodes = require('../www/error-codes');
|
||||||
|
|
||||||
|
const fakeBase64 = { toArrayBuffer: () => 'fakeArrayBuffer' };
|
||||||
|
|
||||||
|
global.Blob = function (array, meta) {
|
||||||
|
this.isFakeBlob = true;
|
||||||
|
this.array = array;
|
||||||
|
this.meta = meta;
|
||||||
|
};
|
||||||
|
|
||||||
|
it('does not change response data if it is an ArrayBuffer', () => {
|
||||||
|
const helpers = require('../www/helpers')(null, jsUtil, null, messages, null, errorCodes);
|
||||||
|
const buffer = new ArrayBuffer(5);
|
||||||
|
const handler = helpers.injectRawResponseHandler(
|
||||||
|
'arraybuffer',
|
||||||
|
response => response.data.should.be.equal(buffer)
|
||||||
|
);
|
||||||
|
|
||||||
|
handler({ data: buffer });
|
||||||
|
});
|
||||||
|
|
||||||
|
it('does not change response data if it is a Blob', () => {
|
||||||
|
const fakeJsUtil = { getTypeOf: () => 'Blob' };
|
||||||
|
const helpers = require('../www/helpers')(null, fakeJsUtil, null, messages, null, errorCodes);
|
||||||
|
const handler = helpers.injectRawResponseHandler(
|
||||||
|
'blob',
|
||||||
|
response => response.data.should.be.equal('fakeData')
|
||||||
|
);
|
||||||
|
|
||||||
|
handler({ data: 'fakeData' });
|
||||||
|
});
|
||||||
|
|
||||||
|
it('does not change response data if response type is "text"', () => {
|
||||||
|
const helpers = require('../www/helpers')(null, jsUtil, null, messages, null, errorCodes);
|
||||||
|
const example = 'exampleText';
|
||||||
|
const handler = helpers.injectRawResponseHandler(
|
||||||
|
'text',
|
||||||
|
response => response.data.should.be.equal(example)
|
||||||
|
);
|
||||||
|
|
||||||
|
handler({ data: example });
|
||||||
|
});
|
||||||
|
|
||||||
|
it('handles response type "json" correctly', () => {
|
||||||
|
const fakeData = { myString: 'bla', myNumber: 10 };
|
||||||
|
const helpers = require('../www/helpers')(null, jsUtil, null, messages, null, errorCodes);
|
||||||
|
const handler = helpers.injectRawResponseHandler(
|
||||||
|
'json',
|
||||||
|
response => response.data.should.be.eql(fakeData)
|
||||||
|
);
|
||||||
|
|
||||||
|
handler({ data: JSON.stringify(fakeData) });
|
||||||
|
});
|
||||||
|
|
||||||
|
it('handles empty "json" response correctly', () => {
|
||||||
|
const emptyData = "";
|
||||||
|
const helpers = require('../www/helpers')(null, jsUtil, null, messages, null, errorCodes);
|
||||||
|
const handler = helpers.injectRawResponseHandler(
|
||||||
|
'json',
|
||||||
|
response => should.equal(undefined, response.data)
|
||||||
|
);
|
||||||
|
|
||||||
|
handler({ data: emptyData });
|
||||||
|
});
|
||||||
|
|
||||||
|
it('handles response type "arraybuffer" correctly', () => {
|
||||||
|
const helpers = require('../www/helpers')(null, jsUtil, null, messages, fakeBase64, errorCodes);
|
||||||
|
const handler = helpers.injectRawResponseHandler(
|
||||||
|
'arraybuffer',
|
||||||
|
response => response.data.should.be.equal('fakeArrayBuffer')
|
||||||
|
);
|
||||||
|
|
||||||
|
handler({ data: 'myString' });
|
||||||
|
});
|
||||||
|
|
||||||
|
it('handles empty "arraybuffer" response correctly', () => {
|
||||||
|
const helpers = require('../www/helpers')(null, jsUtil, null, messages, fakeBase64, errorCodes);
|
||||||
|
const handler = helpers.injectRawResponseHandler(
|
||||||
|
'arraybuffer',
|
||||||
|
response => should.equal(null, response.data)
|
||||||
|
);
|
||||||
|
|
||||||
|
handler({ data: '' });
|
||||||
|
});
|
||||||
|
|
||||||
|
it('handles response type "blob" correctly', () => {
|
||||||
|
const helpers = require('../www/helpers')(null, jsUtil, null, messages, fakeBase64, errorCodes);
|
||||||
|
const handler = helpers.injectRawResponseHandler(
|
||||||
|
'blob',
|
||||||
|
(response) => {
|
||||||
|
response.data.isFakeBlob.should.be.equal(true);
|
||||||
|
response.data.array.should.be.eql(['fakeArrayBuffer']);
|
||||||
|
response.data.meta.type.should.be.equal('fakeType');
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
handler({ data: 'myString', headers: { 'content-type': 'fakeType' } });
|
||||||
|
});
|
||||||
|
|
||||||
|
it('handles empty "blob" response correctly', () => {
|
||||||
|
const helpers = require('../www/helpers')(null, jsUtil, null, messages, fakeBase64, errorCodes);
|
||||||
|
const handler = helpers.injectRawResponseHandler(
|
||||||
|
'blob',
|
||||||
|
(response) => {
|
||||||
|
should.equal(null, response.data)
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
handler({ data: '', headers: { 'content-type': 'fakeType' } });
|
||||||
|
});
|
||||||
|
|
||||||
|
it('calls failure callback when post-processing fails', () => {
|
||||||
|
const helpers = require('../www/helpers')(null, jsUtil, null, messages, fakeBase64, errorCodes);
|
||||||
|
const handler = helpers.injectRawResponseHandler(
|
||||||
|
'json',
|
||||||
|
null,
|
||||||
|
(response) => {
|
||||||
|
response.status.should.be.equal(errorCodes.POST_PROCESSING_FAILED);
|
||||||
|
response.error.should.include('Unexpected token N in JSON at position 0');
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
handler({ data: 'NotValidJson' });
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('checkUploadFileOptions()', function () {
|
||||||
|
const jsUtil = require('../www/js-util');
|
||||||
|
const messages = require('../www/messages');
|
||||||
|
const helpers = require('../www/helpers')(null, jsUtil, null, messages, null, null);
|
||||||
|
|
||||||
|
it('checks valid file options correctly', () => {
|
||||||
|
const opts = {
|
||||||
|
filePaths: ['file://path/to/file.png'],
|
||||||
|
names: ['ScreenCapture']
|
||||||
|
};
|
||||||
|
|
||||||
|
// string values
|
||||||
|
helpers.checkUploadFileOptions(opts.filePaths[0], opts.names[0]).should.be.eql(opts);
|
||||||
|
// string array values
|
||||||
|
helpers.checkUploadFileOptions(opts.filePaths, opts.names).should.be.eql(opts);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('throws an error when file options are missing', () => {
|
||||||
|
(() => helpers.checkUploadFileOptions(undefined, ['ScreenCapture'])).should.throw(messages.FILE_PATHS_TYPE_MISMATCH);
|
||||||
|
(() => helpers.checkUploadFileOptions(['file://path/to/file.png'], undefined)).should.throw(messages.NAMES_TYPE_MISMATCH);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('throws an error when file options contains empty arrays', () => {
|
||||||
|
(() => helpers.checkUploadFileOptions([], ['ScreenCapture'])).should.throw(messages.EMPTY_FILE_PATHS);
|
||||||
|
(() => helpers.checkUploadFileOptions(['file://path/to/file.png'], [])).should.throw(messages.EMPTY_NAMES);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('throws an error when file options contains invalid values', () => {
|
||||||
|
(() => helpers.checkUploadFileOptions([1], ['ScreenCapture'])).should.throw(messages.FILE_PATHS_TYPE_MISMATCH);
|
||||||
|
(() => helpers.checkUploadFileOptions(['file://path/to/file.png'], [1])).should.throw(messages.NAMES_TYPE_MISMATCH);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('processData()', function () {
|
||||||
|
const mockWindow = {
|
||||||
|
Blob: BlobMock,
|
||||||
|
File: FileMock,
|
||||||
|
FileReader: FileReaderMock,
|
||||||
|
FormData: FormDataMock,
|
||||||
|
TextEncoder: util.TextEncoder,
|
||||||
|
}
|
||||||
|
|
||||||
|
const base64 = { fromArrayBuffer: ab => Buffer.from(ab).toString('base64') };
|
||||||
|
const jsUtil = require('../www/js-util');
|
||||||
|
const messages = require('../www/messages');
|
||||||
|
const dependencyValidator = require('../www/dependency-validator')(mockWindow, null, messages);
|
||||||
|
const helpers = require('../www/helpers')(mockWindow, jsUtil, null, messages, base64, null, dependencyValidator, {});
|
||||||
|
|
||||||
|
const testString = 'Test String öäüß 👍😉';
|
||||||
|
const testStringBase64 = Buffer.from(testString).toString('base64');
|
||||||
|
|
||||||
|
it('throws an error when given data does not match allowed data types', () => {
|
||||||
|
(() => helpers.processData('myString', 'urlencoded')).should.throw(messages.TYPE_MISMATCH_DATA);
|
||||||
|
(() => helpers.processData('myString', 'json')).should.throw(messages.TYPE_MISMATCH_DATA);
|
||||||
|
(() => helpers.processData({}, 'utf8')).should.throw(messages.TYPE_MISMATCH_DATA);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('throws an error when given data does not match allowed instance types', () => {
|
||||||
|
(() => helpers.processData('myString', 'multipart')).should.throw(messages.INSTANCE_TYPE_MISMATCH_DATA);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('processes data correctly when serializer "utf8" is configured', (cb) => {
|
||||||
|
helpers.processData('myString', 'utf8', (data) => {
|
||||||
|
data.should.be.eql({ text: 'myString' });
|
||||||
|
cb();
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
it('processes data correctly when serializer "multipart" is configured and form data contains string value', (cb) => {
|
||||||
|
const formData = new FormDataMock();
|
||||||
|
formData.append('myString', testString);
|
||||||
|
|
||||||
|
helpers.processData(formData, 'multipart', (data) => {
|
||||||
|
data.buffers.length.should.be.equal(1);
|
||||||
|
data.names.length.should.be.equal(1);
|
||||||
|
data.fileNames.length.should.be.equal(1);
|
||||||
|
data.types.length.should.be.equal(1);
|
||||||
|
|
||||||
|
data.buffers[0].should.be.eql(testStringBase64);
|
||||||
|
data.names[0].should.be.equal('myString');
|
||||||
|
should.equal(data.fileNames[0], null);
|
||||||
|
data.types[0].should.be.equal('text/plain');
|
||||||
|
|
||||||
|
|
||||||
|
cb();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('processes data correctly when serializer "multipart" is configured and form data contains file value', (cb) => {
|
||||||
|
const formData = new FormDataMock();
|
||||||
|
formData.append('myFile', new BlobMock([testString], { type: 'application/octet-stream' }));
|
||||||
|
|
||||||
|
helpers.processData(formData, 'multipart', (data) => {
|
||||||
|
data.buffers.length.should.be.equal(1);
|
||||||
|
data.names.length.should.be.equal(1);
|
||||||
|
data.fileNames.length.should.be.equal(1);
|
||||||
|
data.types.length.should.be.equal(1);
|
||||||
|
|
||||||
|
data.buffers[0].should.be.eql(testStringBase64);
|
||||||
|
data.names[0].should.be.equal('myFile');
|
||||||
|
data.fileNames[0].should.be.equal('blob');
|
||||||
|
data.types[0].should.be.equal('application/octet-stream');
|
||||||
|
|
||||||
|
cb();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('processes data correctly when serializer "multipart" is configured and form data contains file value (filename set)', (cb) => {
|
||||||
|
const formData = new FormDataMock();
|
||||||
|
formData.append('myFile', new BlobMock([testString], { type: 'application/octet-stream' }), 'file.name');
|
||||||
|
|
||||||
|
helpers.processData(formData, 'multipart', (data) => {
|
||||||
|
data.buffers.length.should.be.equal(1);
|
||||||
|
data.names.length.should.be.equal(1);
|
||||||
|
data.fileNames.length.should.be.equal(1);
|
||||||
|
data.types.length.should.be.equal(1);
|
||||||
|
|
||||||
|
data.buffers[0].should.be.eql(testStringBase64);
|
||||||
|
data.names[0].should.be.equal('myFile');
|
||||||
|
data.fileNames[0].should.be.equal('file.name');
|
||||||
|
data.types[0].should.be.equal('application/octet-stream');
|
||||||
|
|
||||||
|
cb();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('processes data correctly when serializer "multipart" is configured and form data contains file value (filename empty)', (cb) => {
|
||||||
|
const formData = new FormDataMock();
|
||||||
|
formData.append('myFile', new BlobMock([testString], { type: 'application/octet-stream' }), '');
|
||||||
|
|
||||||
|
helpers.processData(formData, 'multipart', (data) => {
|
||||||
|
data.buffers.length.should.be.equal(1);
|
||||||
|
data.names.length.should.be.equal(1);
|
||||||
|
data.fileNames.length.should.be.equal(1);
|
||||||
|
data.types.length.should.be.equal(1);
|
||||||
|
|
||||||
|
data.buffers[0].should.be.eql(testStringBase64);
|
||||||
|
data.names[0].should.be.equal('myFile');
|
||||||
|
data.fileNames[0].should.be.equal('');
|
||||||
|
data.types[0].should.be.equal('application/octet-stream');
|
||||||
|
|
||||||
|
cb();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('processes data correctly when serializer "raw" is configured', (cb) => {
|
||||||
|
const byteArray = new Uint8Array([1, 2, 3]);
|
||||||
|
helpers.processData(byteArray, 'raw', (data) => {
|
||||||
|
data.should.be.a('ArrayBuffer');
|
||||||
|
data.should.be.equal(byteArray.buffer);
|
||||||
|
cb();
|
||||||
|
})
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('nextRequestId()', function () {
|
||||||
|
const helpers = require('../www/helpers')(null, null, null, null, null, null);
|
||||||
|
|
||||||
|
it('returns number requestIds', () => {
|
||||||
|
helpers.nextRequestId().should.be.a('number');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns unique requestIds', () => {
|
||||||
|
const ids = [helpers.nextRequestId(), helpers.nextRequestId(), helpers.nextRequestId()];
|
||||||
|
const set = new Set(ids);
|
||||||
|
ids.should.to.deep.equal(Array.from(set));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Dependency Validator', function () {
|
||||||
|
const messages = require('../www/messages');
|
||||||
|
|
||||||
|
describe('logWarnings()', function () {
|
||||||
|
it('logs a warning message if FormData API is not supported', function () {
|
||||||
|
const console = new ConsoleMock();
|
||||||
|
|
||||||
|
require('../www/dependency-validator')({}, console, messages).logWarnings();
|
||||||
|
|
||||||
|
console.messageList.length.should.be.equal(1);
|
||||||
|
console.messageList[0].type.should.be.equal('warn');
|
||||||
|
console.messageList[0].message.should.be.eql([messages.MISSING_FORMDATA_API]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('logs a warning message if FormData.entries() API is not supported', function () {
|
||||||
|
const console = new ConsoleMock();
|
||||||
|
|
||||||
|
require('../www/dependency-validator')({ FormData: {} }, console, messages).logWarnings();
|
||||||
|
|
||||||
|
console.messageList.length.should.be.equal(1);
|
||||||
|
console.messageList[0].type.should.be.equal('warn');
|
||||||
|
console.messageList[0].message.should.be.eql([messages.MISSING_FORMDATA_ENTRIES_API]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('checkBlobApi()', function () {
|
||||||
|
it('throws an error if Blob API is not supported', function () {
|
||||||
|
const console = new ConsoleMock();
|
||||||
|
const validator = require('../www/dependency-validator')({}, console, messages);
|
||||||
|
|
||||||
|
(() => validator.checkBlobApi()).should.throw(messages.MISSING_BLOB_API);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('checkFileReaderApi()', function () {
|
||||||
|
it('throws an error if FileReader API is not supported', function () {
|
||||||
|
const console = new ConsoleMock();
|
||||||
|
const validator = require('../www/dependency-validator')({}, console, messages);
|
||||||
|
|
||||||
|
(() => validator.checkFileReaderApi()).should.throw(messages.MISSING_FILE_READER_API);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('checkFormDataInstance()', function () {
|
||||||
|
it('throws an error if FormData.entries() is not supported on given instance', function () {
|
||||||
|
const console = new ConsoleMock();
|
||||||
|
const validator = require('../www/dependency-validator')({ FormData: {} }, console, messages);
|
||||||
|
|
||||||
|
(() => validator.checkFormDataInstance({})).should.throw(messages.MISSING_FORMDATA_ENTRIES_API);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('checkTextEncoderApi()', function () {
|
||||||
|
it('throws an error if TextEncoder API is not supported', function () {
|
||||||
|
const console = new ConsoleMock();
|
||||||
|
const validator = require('../www/dependency-validator')({}, console, messages);
|
||||||
|
|
||||||
|
(() => validator.checkTextEncoderApi()).should.throw(messages.MISSING_TEXT_ENCODER_API);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Ponyfills', function () {
|
||||||
|
const mockWindow = {
|
||||||
|
Blob: BlobMock,
|
||||||
|
File: FileMock,
|
||||||
|
};
|
||||||
|
|
||||||
|
const init = require('../www/ponyfills');
|
||||||
|
init.debug = true;
|
||||||
|
const ponyfills = init(mockWindow);
|
||||||
|
|
||||||
|
describe('Iterator', function () {
|
||||||
|
it('exposes interface correctly', () => {
|
||||||
|
const iterator = new ponyfills.Iterator([]);
|
||||||
|
iterator.next.should.be.a('function');
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('next()', function () {
|
||||||
|
it('returns iteration object correctly when list is empty', () => {
|
||||||
|
const iterator = new ponyfills.Iterator([]);
|
||||||
|
iterator.next().should.be.eql({ done: true, value: undefined });
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns iteration object correctly when end posititon of list is not reached yet', () => {
|
||||||
|
const iterator = new ponyfills.Iterator([['first', 'this is the first item']]);
|
||||||
|
iterator.next().should.be.eql({ done: false, value: ['first', 'this is the first item'] });
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns iteration object correctly when end posititon of list is already reached', () => {
|
||||||
|
const iterator = new ponyfills.Iterator([['first', 'this is the first item']]);
|
||||||
|
iterator.next();
|
||||||
|
iterator.next().should.be.eql({ done: true, value: undefined });
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('FormData', function () {
|
||||||
|
it('exposes interface correctly', () => {
|
||||||
|
const formData = new ponyfills.FormData();
|
||||||
|
|
||||||
|
formData.append.should.be.a('function');
|
||||||
|
formData.entries.should.be.a('function');
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('append()', function () {
|
||||||
|
it('appends string value correctly', () => {
|
||||||
|
const formData = new ponyfills.FormData();
|
||||||
|
|
||||||
|
formData.append('test', 'myTestString');
|
||||||
|
formData.__items[0].should.be.eql(['test', 'myTestString']);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('appends numeric value correctly', () => {
|
||||||
|
const formData = new ponyfills.FormData();
|
||||||
|
|
||||||
|
formData.append('test', 10);
|
||||||
|
formData.__items[0].should.be.eql(['test', '10']);
|
||||||
|
formData.__items[0][1].should.be.a('string');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('appends Blob value correctly', () => {
|
||||||
|
const formData = new ponyfills.FormData();
|
||||||
|
const blob = new BlobMock(['another test'], { type: 'text/plain' });
|
||||||
|
|
||||||
|
formData.append('myBlob', blob, 'myFileName.txt');
|
||||||
|
formData.__items[0].should.be.eql(['myBlob', blob]);
|
||||||
|
formData.__items[0][1].name.should.be.equal('myFileName.txt');
|
||||||
|
formData.__items[0][1].lastModifiedDate.should.be.a('Date');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('appends File value correctly', () => {
|
||||||
|
const formData = new ponyfills.FormData();
|
||||||
|
const blob = new BlobMock(['another test'], { type: 'text/plain' });
|
||||||
|
const file = new FileMock(blob, 'myFileName.txt');
|
||||||
|
|
||||||
|
formData.append('myFile', file, 'myOverriddenFileName.txt');
|
||||||
|
formData.__items[0].should.be.eql(['myFile', file]);
|
||||||
|
formData.__items[0][1].name.should.be.equal('myFileName.txt');
|
||||||
|
formData.__items[0][1].lastModifiedDate.should.be.eql(file.lastModifiedDate);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('entries()', function () {
|
||||||
|
it('returns an iterator correctly', () => {
|
||||||
|
const formData = new ponyfills.FormData();
|
||||||
|
|
||||||
|
formData.entries().should.be.an.instanceof(ponyfills.Iterator);
|
||||||
|
})
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|||||||
@@ -0,0 +1,35 @@
|
|||||||
|
module.exports = class BlobMock {
|
||||||
|
constructor(blobParts, options) {
|
||||||
|
if (blobParts instanceof BlobMock) {
|
||||||
|
this._buffer = blobParts._buffer;
|
||||||
|
} else {
|
||||||
|
this._buffer = new Uint8Array(Buffer.concat(blobParts.map(part => Buffer.from(part, 'utf8')))).buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
this._type = options.type || '';
|
||||||
|
}
|
||||||
|
|
||||||
|
get size() {
|
||||||
|
return this._buffer.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
get type() {
|
||||||
|
return this._type;
|
||||||
|
}
|
||||||
|
|
||||||
|
arrayBuffer() {
|
||||||
|
throw new Error('Not implemented in BlobMock.');
|
||||||
|
}
|
||||||
|
|
||||||
|
slice() {
|
||||||
|
throw new Error('Not implemented in BlobMock.');
|
||||||
|
}
|
||||||
|
|
||||||
|
stream() {
|
||||||
|
throw new Error('Not implemented in BlobMock.');
|
||||||
|
}
|
||||||
|
|
||||||
|
text() {
|
||||||
|
throw new Error('Not implemented in BlobMock.');
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
module.exports = class ConsoleMock {
|
||||||
|
constructor() {
|
||||||
|
this.messageList = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
debug(...message) { this.messageList.push({ type: 'debug', message }); }
|
||||||
|
error(...message) { this.messageList.push({ type: 'error', message }); }
|
||||||
|
log(...message) { this.messageList.push({ type: 'log', message }); }
|
||||||
|
info(...message) { this.messageList.push({ type: 'info', message }); }
|
||||||
|
warn(...message) { this.messageList.push({ type: 'warn', message }); }
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
const BlobMock = require('./Blob.mock');
|
||||||
|
|
||||||
|
module.exports = class FileMock extends BlobMock {
|
||||||
|
constructor(blob, fileName) {
|
||||||
|
super(blob, { type: blob.type });
|
||||||
|
this._fileName = fileName !== undefined ? fileName : 'blob';
|
||||||
|
this.__lastModifiedDate = new Date();
|
||||||
|
}
|
||||||
|
|
||||||
|
get name() {
|
||||||
|
return this._fileName;
|
||||||
|
}
|
||||||
|
|
||||||
|
get lastModifiedDate() {
|
||||||
|
return this.__lastModifiedDate;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
module.exports = class FileReaderMock {
|
||||||
|
constructor() {
|
||||||
|
this.EMPTY = 0;
|
||||||
|
this.LOADING = 1;
|
||||||
|
this.DONE = 2;
|
||||||
|
|
||||||
|
this.error = null;
|
||||||
|
this.onabort = () => {};
|
||||||
|
this.onerror = () => {};
|
||||||
|
this.onload = () => {};
|
||||||
|
this.onloadend = () => {};
|
||||||
|
this.onloadstart = () => {};
|
||||||
|
this.onprogress = () => {};
|
||||||
|
this.readyState = this.EMPTY;
|
||||||
|
this.result = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
readAsArrayBuffer(file) {
|
||||||
|
this.readyState = this.LOADING;
|
||||||
|
this.onloadstart();
|
||||||
|
this.onprogress();
|
||||||
|
this.result = file._buffer;
|
||||||
|
this.readyState = this.DONE;
|
||||||
|
this.onloadend();
|
||||||
|
this.onload();
|
||||||
|
}
|
||||||
|
|
||||||
|
readAsBinaryString() {
|
||||||
|
throw new Error('Not implemented in FileReaderMock.');
|
||||||
|
}
|
||||||
|
|
||||||
|
readAsDataUrl() {
|
||||||
|
throw new Error('Not implemented in FileReaderMock.');
|
||||||
|
}
|
||||||
|
|
||||||
|
readAsText() {
|
||||||
|
throw new Error('Not implemented in FileReaderMock.');
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
const BlobMock = require('./Blob.mock');
|
||||||
|
const FileMock = require('./File.mock');
|
||||||
|
|
||||||
|
module.exports = class FormDataMock {
|
||||||
|
constructor() {
|
||||||
|
this.map = new Map();
|
||||||
|
}
|
||||||
|
|
||||||
|
append(name, value, filename) {
|
||||||
|
if (value instanceof BlobMock) {
|
||||||
|
this.map.set(name, new FileMock(value, filename))
|
||||||
|
} else {
|
||||||
|
this.map.set(name, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
delete() {
|
||||||
|
throw new Error('Not implemented in FormDataMock.');
|
||||||
|
}
|
||||||
|
|
||||||
|
entries() {
|
||||||
|
return this.map.entries();
|
||||||
|
}
|
||||||
|
|
||||||
|
forEach(cb) {
|
||||||
|
return this.map.forEach(cb);
|
||||||
|
}
|
||||||
|
|
||||||
|
get(key) {
|
||||||
|
return this.map.get(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
getAll() {
|
||||||
|
throw new Error('Not implemented in FormDataMock.');
|
||||||
|
}
|
||||||
|
|
||||||
|
has(key) {
|
||||||
|
return this.map.has(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
keys() {
|
||||||
|
return this.map.keys();
|
||||||
|
}
|
||||||
|
|
||||||
|
set(key, value) {
|
||||||
|
return this.map.set(key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
values() {
|
||||||
|
return this.map.values();
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -5,15 +5,21 @@
|
|||||||
var pluginId = module.id.slice(0, module.id.lastIndexOf('.'));
|
var pluginId = module.id.slice(0, module.id.lastIndexOf('.'));
|
||||||
|
|
||||||
var exec = require('cordova/exec');
|
var exec = require('cordova/exec');
|
||||||
|
var base64 = require('cordova/base64');
|
||||||
var messages = require(pluginId + '.messages');
|
var messages = require(pluginId + '.messages');
|
||||||
|
var errorCodes = require(pluginId + '.error-codes');
|
||||||
var globalConfigs = require(pluginId + '.global-configs');
|
var globalConfigs = require(pluginId + '.global-configs');
|
||||||
var jsUtil = require(pluginId + '.js-util');
|
var jsUtil = require(pluginId + '.js-util');
|
||||||
var ToughCookie = require(pluginId + '.tough-cookie');
|
var ToughCookie = require(pluginId + '.tough-cookie');
|
||||||
var lodash = require(pluginId + '.lodash');
|
var lodash = require(pluginId + '.lodash');
|
||||||
var WebStorageCookieStore = require(pluginId + '.local-storage-store')(ToughCookie, lodash);
|
var WebStorageCookieStore = require(pluginId + '.local-storage-store')(ToughCookie, lodash);
|
||||||
var cookieHandler = require(pluginId + '.cookie-handler')(window.localStorage, ToughCookie, WebStorageCookieStore);
|
var cookieHandler = require(pluginId + '.cookie-handler')(window.localStorage, ToughCookie, WebStorageCookieStore);
|
||||||
var helpers = require(pluginId + '.helpers')(jsUtil, cookieHandler, messages);
|
var dependencyValidator = require(pluginId + '.dependency-validator')(window, window.console, messages);
|
||||||
|
var ponyfills = require(pluginId + '.ponyfills')(window);
|
||||||
|
var helpers = require(pluginId + '.helpers')(window, jsUtil, cookieHandler, messages, base64, errorCodes, dependencyValidator, ponyfills);
|
||||||
var urlUtil = require(pluginId + '.url-util')(jsUtil);
|
var urlUtil = require(pluginId + '.url-util')(jsUtil);
|
||||||
var publicInterface = require(pluginId + '.public-interface')(exec, cookieHandler, urlUtil, helpers, globalConfigs);
|
var publicInterface = require(pluginId + '.public-interface')(exec, cookieHandler, urlUtil, helpers, globalConfigs, errorCodes, ponyfills);
|
||||||
|
|
||||||
|
dependencyValidator.logWarnings();
|
||||||
|
|
||||||
module.exports = publicInterface;
|
module.exports = publicInterface;
|
||||||
|
|||||||
@@ -0,0 +1,43 @@
|
|||||||
|
module.exports = function init(global, console, messages) {
|
||||||
|
var interface = {
|
||||||
|
checkBlobApi: checkBlobApi,
|
||||||
|
checkFileReaderApi: checkFileReaderApi,
|
||||||
|
checkFormDataInstance: checkFormDataInstance,
|
||||||
|
checkTextEncoderApi: checkTextEncoderApi,
|
||||||
|
logWarnings: logWarnings,
|
||||||
|
};
|
||||||
|
|
||||||
|
return interface;
|
||||||
|
|
||||||
|
function logWarnings() {
|
||||||
|
if (!global.FormData) {
|
||||||
|
console.warn(messages.MISSING_FORMDATA_API);
|
||||||
|
} else if (!global.FormData.prototype || !global.FormData.prototype.entries) {
|
||||||
|
console.warn(messages.MISSING_FORMDATA_ENTRIES_API);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function checkBlobApi() {
|
||||||
|
if (!global.Blob || !global.Blob.prototype) {
|
||||||
|
throw new Error(messages.MISSING_BLOB_API);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function checkFileReaderApi() {
|
||||||
|
if (!global.FileReader || !global.FileReader.prototype) {
|
||||||
|
throw new Error(messages.MISSING_FILE_READER_API);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function checkFormDataInstance(instance) {
|
||||||
|
if (!instance || !instance.entries) {
|
||||||
|
throw new Error(messages.MISSING_FORMDATA_ENTRIES_API);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function checkTextEncoderApi() {
|
||||||
|
if (!global.TextEncoder || !global.TextEncoder.prototype) {
|
||||||
|
throw new Error(messages.MISSING_TEXT_ENCODER_API);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
module.exports = {
|
||||||
|
GENERIC: -1,
|
||||||
|
SSL_EXCEPTION: -2,
|
||||||
|
SERVER_NOT_FOUND: -3,
|
||||||
|
TIMEOUT: -4,
|
||||||
|
UNSUPPORTED_URL: -5,
|
||||||
|
NOT_CONNECTED: -6,
|
||||||
|
POST_PROCESSING_FAILED: -7,
|
||||||
|
ABORTED: -8,
|
||||||
|
};
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
var globalConfigs = {
|
var globalConfigs = {
|
||||||
headers: {},
|
headers: {},
|
||||||
serializer: 'urlencoded',
|
serializer: 'urlencoded',
|
||||||
|
followRedirect: true,
|
||||||
timeout: 60.0,
|
timeout: 60.0,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
+283
-28
@@ -1,22 +1,37 @@
|
|||||||
module.exports = function init(jsUtil, cookieHandler, messages) {
|
module.exports = function init(global, jsUtil, cookieHandler, messages, base64, errorCodes, dependencyValidator, ponyfills) {
|
||||||
var validSerializers = ['urlencoded', 'json', 'utf8'];
|
var validSerializers = ['urlencoded', 'json', 'utf8', 'raw', 'multipart'];
|
||||||
var validCertModes = ['default', 'nocheck', 'pinned', 'legacy'];
|
var validCertModes = ['default', 'nocheck', 'pinned', 'legacy'];
|
||||||
var validClientAuthModes = ['none', 'systemstore', 'file'];
|
var validClientAuthModes = ['none', 'systemstore', 'buffer'];
|
||||||
var validHttpMethods = ['get', 'put', 'post', 'patch', 'head', 'delete', 'upload', 'download'];
|
var validHttpMethods = ['get', 'put', 'post', 'patch', 'head', 'delete', 'options', 'upload', 'download'];
|
||||||
|
var validResponseTypes = ['text', 'json', 'arraybuffer', 'blob'];
|
||||||
|
|
||||||
|
var nextRequestId = (function(){
|
||||||
|
var currReqId = 0;
|
||||||
|
return function nextRequestId() {
|
||||||
|
return ++currReqId;
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
|
||||||
var interface = {
|
var interface = {
|
||||||
b64EncodeUnicode: b64EncodeUnicode,
|
b64EncodeUnicode: b64EncodeUnicode,
|
||||||
checkSerializer: checkSerializer,
|
|
||||||
checkSSLCertMode: checkSSLCertMode,
|
|
||||||
checkClientAuthMode: checkClientAuthMode,
|
checkClientAuthMode: checkClientAuthMode,
|
||||||
|
checkClientAuthOptions: checkClientAuthOptions,
|
||||||
|
checkDownloadFilePath: checkDownloadFilePath,
|
||||||
|
checkFollowRedirectValue: checkFollowRedirectValue,
|
||||||
checkForBlacklistedHeaderKey: checkForBlacklistedHeaderKey,
|
checkForBlacklistedHeaderKey: checkForBlacklistedHeaderKey,
|
||||||
checkForInvalidHeaderValue: checkForInvalidHeaderValue,
|
checkForInvalidHeaderValue: checkForInvalidHeaderValue,
|
||||||
|
checkSerializer: checkSerializer,
|
||||||
|
checkSSLCertMode: checkSSLCertMode,
|
||||||
|
checkTimeoutValue: checkTimeoutValue,
|
||||||
|
checkUploadFileOptions: checkUploadFileOptions,
|
||||||
|
getMergedHeaders: getMergedHeaders,
|
||||||
|
processData: processData,
|
||||||
|
handleMissingCallbacks: handleMissingCallbacks,
|
||||||
|
handleMissingOptions: handleMissingOptions,
|
||||||
injectCookieHandler: injectCookieHandler,
|
injectCookieHandler: injectCookieHandler,
|
||||||
injectFileEntryHandler: injectFileEntryHandler,
|
injectFileEntryHandler: injectFileEntryHandler,
|
||||||
getMergedHeaders: getMergedHeaders,
|
injectRawResponseHandler: injectRawResponseHandler,
|
||||||
getProcessedData: getProcessedData,
|
nextRequestId: nextRequestId,
|
||||||
handleMissingCallbacks: handleMissingCallbacks,
|
|
||||||
handleMissingOptions: handleMissingOptions
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// expose all functions for testing purposes
|
// expose all functions for testing purposes
|
||||||
@@ -25,7 +40,7 @@ module.exports = function init(jsUtil, cookieHandler, messages) {
|
|||||||
interface.checkForValidStringValue = checkForValidStringValue;
|
interface.checkForValidStringValue = checkForValidStringValue;
|
||||||
interface.checkKeyValuePairObject = checkKeyValuePairObject;
|
interface.checkKeyValuePairObject = checkKeyValuePairObject;
|
||||||
interface.checkHttpMethod = checkHttpMethod;
|
interface.checkHttpMethod = checkHttpMethod;
|
||||||
interface.checkTimeoutValue = checkTimeoutValue;
|
interface.checkResponseType = checkResponseType;
|
||||||
interface.checkHeadersObject = checkHeadersObject;
|
interface.checkHeadersObject = checkHeadersObject;
|
||||||
interface.checkParamsObject = checkParamsObject;
|
interface.checkParamsObject = checkParamsObject;
|
||||||
interface.resolveCookieString = resolveCookieString;
|
interface.resolveCookieString = resolveCookieString;
|
||||||
@@ -89,10 +104,28 @@ module.exports = function init(jsUtil, cookieHandler, messages) {
|
|||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function checkArray(array, allowedDataTypes, onInvalidValueMessage) {
|
||||||
|
if (jsUtil.getTypeOf(array) !== 'Array') {
|
||||||
|
throw new Error(onInvalidValueMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var i = 0; i < array.length; ++i) {
|
||||||
|
if (allowedDataTypes.indexOf(jsUtil.getTypeOf(array[i])) === -1) {
|
||||||
|
throw new Error(onInvalidValueMessage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return array;
|
||||||
|
}
|
||||||
|
|
||||||
function checkHttpMethod(method) {
|
function checkHttpMethod(method) {
|
||||||
return checkForValidStringValue(validHttpMethods, method, messages.INVALID_HTTP_METHOD);
|
return checkForValidStringValue(validHttpMethods, method, messages.INVALID_HTTP_METHOD);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function checkResponseType(type) {
|
||||||
|
return checkForValidStringValue(validResponseTypes, type, messages.INVALID_RESPONSE_TYPE);
|
||||||
|
}
|
||||||
|
|
||||||
function checkSerializer(serializer) {
|
function checkSerializer(serializer) {
|
||||||
return checkForValidStringValue(validSerializers, serializer, messages.INVALID_DATA_SERIALIZER);
|
return checkForValidStringValue(validSerializers, serializer, messages.INVALID_DATA_SERIALIZER);
|
||||||
}
|
}
|
||||||
@@ -105,6 +138,54 @@ module.exports = function init(jsUtil, cookieHandler, messages) {
|
|||||||
return checkForValidStringValue(validClientAuthModes, mode, messages.INVALID_CLIENT_AUTH_MODE);
|
return checkForValidStringValue(validClientAuthModes, mode, messages.INVALID_CLIENT_AUTH_MODE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function checkClientAuthOptions(mode, options) {
|
||||||
|
options = options || {};
|
||||||
|
|
||||||
|
// none
|
||||||
|
if (mode === validClientAuthModes[0]) {
|
||||||
|
return {
|
||||||
|
alias: null,
|
||||||
|
rawPkcs: null,
|
||||||
|
pkcsPassword: ''
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (jsUtil.getTypeOf(options) !== 'Object') {
|
||||||
|
throw new Error(messages.INVALID_CLIENT_AUTH_OPTIONS);
|
||||||
|
}
|
||||||
|
|
||||||
|
// systemstore
|
||||||
|
if (mode === validClientAuthModes[1]) {
|
||||||
|
if (jsUtil.getTypeOf(options.alias) !== 'String'
|
||||||
|
&& jsUtil.getTypeOf(options.alias) !== 'Undefined') {
|
||||||
|
throw new Error(messages.INVALID_CLIENT_AUTH_ALIAS);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
alias: jsUtil.getTypeOf(options.alias) === 'Undefined' ? null : options.alias,
|
||||||
|
rawPkcs: null,
|
||||||
|
pkcsPassword: ''
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// buffer
|
||||||
|
if (mode === validClientAuthModes[2]) {
|
||||||
|
if (jsUtil.getTypeOf(options.rawPkcs) !== 'ArrayBuffer') {
|
||||||
|
throw new Error(messages.INVALID_CLIENT_AUTH_RAW_PKCS);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (jsUtil.getTypeOf(options.pkcsPassword) !== 'String') {
|
||||||
|
throw new Error(messages.INVALID_CLIENT_AUTH_PKCS_PASSWORD);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
alias: null,
|
||||||
|
rawPkcs: options.rawPkcs,
|
||||||
|
pkcsPassword: options.pkcsPassword
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function checkForBlacklistedHeaderKey(key) {
|
function checkForBlacklistedHeaderKey(key) {
|
||||||
if (key.toLowerCase() === 'cookie') {
|
if (key.toLowerCase() === 'cookie') {
|
||||||
throw new Error(messages.ADDING_COOKIES_NOT_SUPPORTED);
|
throw new Error(messages.ADDING_COOKIES_NOT_SUPPORTED);
|
||||||
@@ -114,8 +195,10 @@ module.exports = function init(jsUtil, cookieHandler, messages) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function checkForInvalidHeaderValue(value) {
|
function checkForInvalidHeaderValue(value) {
|
||||||
if (jsUtil.getTypeOf(value) !== 'String') {
|
var type = jsUtil.getTypeOf(value);
|
||||||
throw new Error(messages.INVALID_HEADERS_VALUE);
|
|
||||||
|
if (type !== 'String' && type !== 'Null') {
|
||||||
|
throw new Error(messages.INVALID_HEADER_VALUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
return value;
|
return value;
|
||||||
@@ -129,12 +212,53 @@ module.exports = function init(jsUtil, cookieHandler, messages) {
|
|||||||
return timeout;
|
return timeout;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function checkFollowRedirectValue(follow) {
|
||||||
|
if (jsUtil.getTypeOf(follow) !== 'Boolean') {
|
||||||
|
throw new Error(messages.INVALID_FOLLOW_REDIRECT_VALUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
return follow;
|
||||||
|
}
|
||||||
|
|
||||||
function checkHeadersObject(headers) {
|
function checkHeadersObject(headers) {
|
||||||
return checkKeyValuePairObject(headers, ['String'], messages.INVALID_HEADERS_VALUE);
|
return checkKeyValuePairObject(headers, ['String'], messages.TYPE_MISMATCH_HEADERS);
|
||||||
}
|
}
|
||||||
|
|
||||||
function checkParamsObject(params) {
|
function checkParamsObject(params) {
|
||||||
return checkKeyValuePairObject(params, ['String', 'Array'], messages.INVALID_PARAMS_VALUE);
|
return checkKeyValuePairObject(params, ['String', 'Array'], messages.TYPE_MISMATCH_PARAMS);
|
||||||
|
}
|
||||||
|
|
||||||
|
function checkDownloadFilePath(filePath) {
|
||||||
|
if (!filePath || jsUtil.getTypeOf(filePath) !== 'String') {
|
||||||
|
throw new Error(messages.INVALID_DOWNLOAD_FILE_PATH);
|
||||||
|
}
|
||||||
|
|
||||||
|
return filePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
function checkUploadFileOptions(filePaths, names) {
|
||||||
|
if (jsUtil.getTypeOf(filePaths) === 'String') {
|
||||||
|
filePaths = [filePaths];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (jsUtil.getTypeOf(names) === 'String') {
|
||||||
|
names = [names];
|
||||||
|
}
|
||||||
|
|
||||||
|
var opts = {
|
||||||
|
filePaths: checkArray(filePaths, ['String'], messages.TYPE_MISMATCH_FILE_PATHS),
|
||||||
|
names: checkArray(names, ['String'], messages.TYPE_MISMATCH_NAMES)
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!opts.filePaths.length) {
|
||||||
|
throw new Error(messages.EMPTY_FILE_PATHS);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!opts.names.length) {
|
||||||
|
throw new Error(messages.EMPTY_NAMES);
|
||||||
|
}
|
||||||
|
|
||||||
|
return opts;
|
||||||
}
|
}
|
||||||
|
|
||||||
function resolveCookieString(headers) {
|
function resolveCookieString(headers) {
|
||||||
@@ -156,7 +280,7 @@ module.exports = function init(jsUtil, cookieHandler, messages) {
|
|||||||
entry.isFile = rawEntry.isFile;
|
entry.isFile = rawEntry.isFile;
|
||||||
entry.name = rawEntry.name;
|
entry.name = rawEntry.name;
|
||||||
entry.fullPath = rawEntry.fullPath;
|
entry.fullPath = rawEntry.fullPath;
|
||||||
entry.filesystem = new FileSystem(rawEntry.filesystemName || (rawEntry.filesystem == window.PERSISTENT ? 'persistent' : 'temporary'));
|
entry.filesystem = new FileSystem(rawEntry.filesystemName || (rawEntry.filesystem == global.PERSISTENT ? 'persistent' : 'temporary'));
|
||||||
entry.nativeURL = rawEntry.nativeURL;
|
entry.nativeURL = rawEntry.nativeURL;
|
||||||
|
|
||||||
return entry;
|
return entry;
|
||||||
@@ -169,6 +293,54 @@ module.exports = function init(jsUtil, cookieHandler, messages) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function injectRawResponseHandler(responseType, success, failure) {
|
||||||
|
return function (response) {
|
||||||
|
var dataType = jsUtil.getTypeOf(response.data);
|
||||||
|
|
||||||
|
// don't need post-processing if it's already binary type (on browser platform)
|
||||||
|
if (dataType === 'ArrayBuffer' || dataType === 'Blob') {
|
||||||
|
return success(response);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// json
|
||||||
|
if (responseType === validResponseTypes[1]) {
|
||||||
|
response.data = response.data === ''
|
||||||
|
? undefined
|
||||||
|
: JSON.parse(response.data);
|
||||||
|
}
|
||||||
|
|
||||||
|
// arraybuffer
|
||||||
|
else if (responseType === validResponseTypes[2]) {
|
||||||
|
response.data = response.data === ''
|
||||||
|
? null
|
||||||
|
: base64.toArrayBuffer(response.data);
|
||||||
|
}
|
||||||
|
|
||||||
|
// blob
|
||||||
|
else if (responseType === validResponseTypes[3]) {
|
||||||
|
if (response.data === '') {
|
||||||
|
response.data = null;
|
||||||
|
} else {
|
||||||
|
var buffer = base64.toArrayBuffer(response.data);
|
||||||
|
var type = response.headers['content-type'] || '';
|
||||||
|
var blob = new Blob([buffer], { type: type });
|
||||||
|
response.data = blob;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
success(response);
|
||||||
|
} catch (error) {
|
||||||
|
failure({
|
||||||
|
status: errorCodes.POST_PROCESSING_FAILED,
|
||||||
|
error: messages.POST_PROCESSING_FAILED + ' ' + error.message,
|
||||||
|
url: response.url,
|
||||||
|
headers: response.headers
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function injectFileEntryHandler(cb) {
|
function injectFileEntryHandler(cb) {
|
||||||
return function (response) {
|
return function (response) {
|
||||||
cb(createFileEntry(response.file));
|
cb(createFileEntry(response.file));
|
||||||
@@ -209,24 +381,105 @@ module.exports = function init(jsUtil, cookieHandler, messages) {
|
|||||||
return ['String'];
|
return ['String'];
|
||||||
case 'urlencoded':
|
case 'urlencoded':
|
||||||
return ['Object'];
|
return ['Object'];
|
||||||
default:
|
case 'json':
|
||||||
return ['Array', 'Object'];
|
return ['Array', 'Object'];
|
||||||
|
case 'raw':
|
||||||
|
return ['Uint8Array', 'ArrayBuffer'];
|
||||||
|
default:
|
||||||
|
return [];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getProcessedData(data, dataSerializer) {
|
function getAllowedInstanceTypes(dataSerializer) {
|
||||||
|
return dataSerializer === 'multipart' ? ['FormData'] : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function processData(data, dataSerializer, cb) {
|
||||||
var currentDataType = jsUtil.getTypeOf(data);
|
var currentDataType = jsUtil.getTypeOf(data);
|
||||||
var allowedDataTypes = getAllowedDataTypes(dataSerializer);
|
var allowedDataTypes = getAllowedDataTypes(dataSerializer);
|
||||||
|
var allowedInstanceTypes = getAllowedInstanceTypes(dataSerializer);
|
||||||
|
|
||||||
if (allowedDataTypes.indexOf(currentDataType) === -1) {
|
if (allowedInstanceTypes) {
|
||||||
throw new Error(messages.DATA_TYPE_MISMATCH + ' ' + allowedDataTypes.join(', '));
|
var isCorrectInstanceType = false;
|
||||||
|
|
||||||
|
allowedInstanceTypes.forEach(function (type) {
|
||||||
|
if ((global[type] && data instanceof global[type]) || (ponyfills[type] && data instanceof ponyfills[type])) {
|
||||||
|
isCorrectInstanceType = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!isCorrectInstanceType) {
|
||||||
|
throw new Error(messages.INSTANCE_TYPE_MISMATCH_DATA + ' ' + allowedInstanceTypes.join(', '));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dataSerializer === 'utf8') {
|
if (!allowedInstanceTypes && allowedDataTypes.indexOf(currentDataType) === -1) {
|
||||||
data = { text: data };
|
throw new Error(messages.TYPE_MISMATCH_DATA + ' ' + allowedDataTypes.join(', '));
|
||||||
}
|
}
|
||||||
|
|
||||||
return data;
|
switch (dataSerializer) {
|
||||||
|
case 'utf8':
|
||||||
|
return cb({ text: data });
|
||||||
|
case 'raw':
|
||||||
|
return cb(currentDataType === 'Uint8Array' ? data.buffer : data);
|
||||||
|
case 'multipart':
|
||||||
|
return processFormData(data, cb);
|
||||||
|
default:
|
||||||
|
return cb(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function processFormData(data, cb) {
|
||||||
|
dependencyValidator.checkBlobApi();
|
||||||
|
dependencyValidator.checkFileReaderApi();
|
||||||
|
dependencyValidator.checkTextEncoderApi();
|
||||||
|
dependencyValidator.checkFormDataInstance(data);
|
||||||
|
|
||||||
|
var textEncoder = new global.TextEncoder('utf8');
|
||||||
|
var iterator = data.entries();
|
||||||
|
|
||||||
|
var result = {
|
||||||
|
buffers: [],
|
||||||
|
names: [],
|
||||||
|
fileNames: [],
|
||||||
|
types: []
|
||||||
|
};
|
||||||
|
|
||||||
|
processFormDataIterator(iterator, textEncoder, result, cb);
|
||||||
|
}
|
||||||
|
|
||||||
|
function processFormDataIterator(iterator, textEncoder, result, onFinished) {
|
||||||
|
var entry = iterator.next();
|
||||||
|
|
||||||
|
if (entry.done) {
|
||||||
|
return onFinished(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entry.value[1] instanceof global.Blob || entry.value[1] instanceof global.File) {
|
||||||
|
var reader = new global.FileReader();
|
||||||
|
|
||||||
|
reader.onload = function () {
|
||||||
|
result.buffers.push(base64.fromArrayBuffer(reader.result));
|
||||||
|
result.names.push(entry.value[0]);
|
||||||
|
result.fileNames.push(entry.value[1].name !== undefined ? entry.value[1].name : 'blob');
|
||||||
|
result.types.push(entry.value[1].type || '');
|
||||||
|
processFormDataIterator(iterator, textEncoder, result, onFinished);
|
||||||
|
};
|
||||||
|
|
||||||
|
return reader.readAsArrayBuffer(entry.value[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (jsUtil.getTypeOf(entry.value[1]) === 'String') {
|
||||||
|
result.buffers.push(base64.fromArrayBuffer(textEncoder.encode(entry.value[1]).buffer));
|
||||||
|
result.names.push(entry.value[0]);
|
||||||
|
result.fileNames.push(null);
|
||||||
|
result.types.push('text/plain');
|
||||||
|
|
||||||
|
return processFormDataIterator(iterator, textEncoder, result, onFinished)
|
||||||
|
}
|
||||||
|
|
||||||
|
// skip items which are not supported
|
||||||
|
processFormDataIterator(iterator, textEncoder, result, onFinished);
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleMissingCallbacks(successFn, failFn) {
|
function handleMissingCallbacks(successFn, failFn) {
|
||||||
@@ -243,14 +496,16 @@ module.exports = function init(jsUtil, cookieHandler, messages) {
|
|||||||
options = options || {};
|
options = options || {};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
data: jsUtil.getTypeOf(options.data) === 'Undefined' ? null : options.data,
|
||||||
|
filePath: options.filePath,
|
||||||
|
followRedirect: checkFollowRedirectValue(options.followRedirect || globals.followRedirect),
|
||||||
|
headers: checkHeadersObject(options.headers || {}),
|
||||||
method: checkHttpMethod(options.method || validHttpMethods[0]),
|
method: checkHttpMethod(options.method || validHttpMethods[0]),
|
||||||
|
name: options.name,
|
||||||
|
params: checkParamsObject(options.params || {}),
|
||||||
|
responseType: checkResponseType(options.responseType || validResponseTypes[0]),
|
||||||
serializer: checkSerializer(options.serializer || globals.serializer),
|
serializer: checkSerializer(options.serializer || globals.serializer),
|
||||||
timeout: checkTimeoutValue(options.timeout || globals.timeout),
|
timeout: checkTimeoutValue(options.timeout || globals.timeout),
|
||||||
headers: checkHeadersObject(options.headers || {}),
|
|
||||||
params: checkParamsObject(options.params || {}),
|
|
||||||
data: jsUtil.getTypeOf(options.data) === 'Undefined' ? null : options.data,
|
|
||||||
filePath: options.filePath || '',
|
|
||||||
name: options.name || ''
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -4,6 +4,12 @@ module.exports = {
|
|||||||
switch (Object.prototype.toString.call(object)) {
|
switch (Object.prototype.toString.call(object)) {
|
||||||
case '[object Array]':
|
case '[object Array]':
|
||||||
return 'Array';
|
return 'Array';
|
||||||
|
case '[object Blob]':
|
||||||
|
return 'Blob';
|
||||||
|
case '[object Uint8Array]':
|
||||||
|
return 'Uint8Array';
|
||||||
|
case '[object ArrayBuffer]':
|
||||||
|
return 'ArrayBuffer';
|
||||||
case '[object Boolean]':
|
case '[object Boolean]':
|
||||||
return 'Boolean';
|
return 'Boolean';
|
||||||
case '[object Function]':
|
case '[object Function]':
|
||||||
|
|||||||
@@ -146,7 +146,7 @@ module.exports = function init(ToughCookie, _) {
|
|||||||
|
|
||||||
Object.keys(store).forEach(function (domain) {
|
Object.keys(store).forEach(function (domain) {
|
||||||
Object.keys(store[domain]).forEach(function (path) {
|
Object.keys(store[domain]).forEach(function (path) {
|
||||||
Array.protype.push.apply(cookies, _.values(store[domain][path]));
|
Array.prototype.push.apply(cookies, _.values(store[domain][path]));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
+28
-9
@@ -1,13 +1,32 @@
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
ADDING_COOKIES_NOT_SUPPORTED: 'advanced-http: "setHeader" does not support adding cookies, please use "setCookie" function instead',
|
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:',
|
EMPTY_FILE_PATHS: 'advanced-http: "filePaths" option array must not be empty, <filePaths: string[]>',
|
||||||
MANDATORY_SUCCESS: 'advanced-http: missing mandatory "onSuccess" callback function',
|
EMPTY_NAMES: 'advanced-http: "names" option array must not be empty, <names: string[]>',
|
||||||
MANDATORY_FAIL: 'advanced-http: missing mandatory "onFail" callback function',
|
INSTANCE_TYPE_MISMATCH_DATA: 'advanced-http: "data" option is configured to support only following instance types:',
|
||||||
INVALID_HTTP_METHOD: 'advanced-http: invalid HTTP method, supported methods are:',
|
INVALID_CLIENT_AUTH_ALIAS: 'advanced-http: invalid client certificate alias, needs to be a string or undefined, <alias: string | undefined>',
|
||||||
INVALID_DATA_SERIALIZER: 'advanced-http: invalid serializer, supported serializers are:',
|
|
||||||
INVALID_SSL_CERT_MODE: 'advanced-http: invalid SSL cert mode, supported modes are:',
|
|
||||||
INVALID_CLIENT_AUTH_MODE: 'advanced-http: invalid client certificate authentication mode, supported modes are:',
|
INVALID_CLIENT_AUTH_MODE: 'advanced-http: invalid client certificate authentication mode, supported modes are:',
|
||||||
INVALID_HEADERS_VALUE: 'advanced-http: header values must be strings',
|
INVALID_CLIENT_AUTH_OPTIONS: 'advanced-http: invalid client certificate authentication options, needs to be an dictionary style object',
|
||||||
INVALID_TIMEOUT_VALUE: 'advanced-http: invalid timeout value, needs to be a positive numeric value',
|
INVALID_CLIENT_AUTH_PKCS_PASSWORD: 'advanced-http: invalid PKCS12 container password, needs to be a string, <pkcsPassword: string>',
|
||||||
INVALID_PARAMS_VALUE: 'advanced-http: invalid params object, needs to be an object with strings'
|
INVALID_CLIENT_AUTH_RAW_PKCS: 'advanced-http: invalid PKCS12 container, needs to be an array buffer, <rawPkcs: ArrayBuffer>',
|
||||||
|
INVALID_DATA_SERIALIZER: 'advanced-http: invalid serializer, supported serializers are:',
|
||||||
|
INVALID_DOWNLOAD_FILE_PATH: 'advanced-http: invalid "filePath" value, needs to be a string, <filePath: string>',
|
||||||
|
INVALID_FOLLOW_REDIRECT_VALUE: 'advanced-http: invalid follow redirect value, needs to be a boolean value, <followRedirect: boolean>',
|
||||||
|
INVALID_HEADER_VALUE: 'advanced-http: invalid header value, needs to be a string or null, <header: string | null>',
|
||||||
|
INVALID_HTTP_METHOD: 'advanced-http: invalid HTTP method, supported methods are:',
|
||||||
|
INVALID_RESPONSE_TYPE: 'advanced-http: invalid response type, supported types are:',
|
||||||
|
INVALID_SSL_CERT_MODE: 'advanced-http: invalid SSL cert mode, supported modes are:',
|
||||||
|
INVALID_TIMEOUT_VALUE: 'advanced-http: invalid timeout value, needs to be a positive numeric value, <timeout: number>',
|
||||||
|
MANDATORY_FAIL: 'advanced-http: missing mandatory "onFail" callback function',
|
||||||
|
MANDATORY_SUCCESS: 'advanced-http: missing mandatory "onSuccess" callback function',
|
||||||
|
MISSING_BLOB_API: 'advanced-http: Blob API is not supported in this webview. If you want to use "multipart/form-data" requests, you need to load a polyfill library before loading this plugin. Check out https://github.com/silkimen/cordova-plugin-advanced-http/wiki/Web-APIs-required-for-Multipart-requests for more info.',
|
||||||
|
MISSING_FILE_READER_API: 'advanced-http: FileReader API is not supported in this webview. If you want to use "multipart/form-data" requests, you need to load a polyfill library before loading this plugin. Check out https://github.com/silkimen/cordova-plugin-advanced-http/wiki/Web-APIs-required-for-Multipart-requests for more info.',
|
||||||
|
MISSING_FORMDATA_API: 'advanced-http: FormData API is not supported in this webview. If you want to use "multipart/form-data" requests, you need to load a polyfill library before loading this plugin. Check out https://github.com/silkimen/cordova-plugin-advanced-http/wiki/Web-APIs-required-for-Multipart-requests for more info.',
|
||||||
|
MISSING_FORMDATA_ENTRIES_API: 'advanced-http: Given instance of FormData does not implement FormData API specification correctly, FormData.entries() is missing. If you want to use "multipart/form-data" requests, you can use an included ponyfill. Check out https://github.com/silkimen/cordova-plugin-advanced-http/wiki/Web-APIs-required-for-Multipart-requests for more info.',
|
||||||
|
MISSING_TEXT_ENCODER_API: 'advanced-http: TextEncoder API is not supported in this webview. If you want to use "multipart/form-data" requests, you need to load a polyfill library before loading this plugin. Check out https://github.com/silkimen/cordova-plugin-advanced-http/wiki/Web-APIs-required-for-Multipart-requests for more info.',
|
||||||
|
POST_PROCESSING_FAILED: 'advanced-http: an error occured during post processing response:',
|
||||||
|
TYPE_MISMATCH_DATA: 'advanced-http: "data" option is configured to support only following data types:',
|
||||||
|
TYPE_MISMATCH_FILE_PATHS: 'advanced-http: "filePaths" option needs to be an string array, <filePaths: string[]>',
|
||||||
|
TYPE_MISMATCH_HEADERS: 'advanced-http: "headers" option needs to be an dictionary style object with string values, <headers: {[key: string]: string}>',
|
||||||
|
TYPE_MISMATCH_NAMES: 'advanced-http: "names" option needs to be an string array, <names: string[]>',
|
||||||
|
TYPE_MISMATCH_PARAMS: 'advanced-http: "params" option needs to be an dictionary style object, <params: {[key: string]: string | string[]}>',
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -0,0 +1,47 @@
|
|||||||
|
module.exports = function init(global) {
|
||||||
|
var interface = { FormData: FormData };
|
||||||
|
|
||||||
|
// expose all constructor functions for testing purposes
|
||||||
|
if (init.debug) {
|
||||||
|
interface.Iterator = Iterator;
|
||||||
|
}
|
||||||
|
|
||||||
|
function FormData() {
|
||||||
|
this.__items = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
FormData.prototype.append = function(name, value, filename) {
|
||||||
|
if (global.File && value instanceof global.File) {
|
||||||
|
// nothing to do
|
||||||
|
} else if (global.Blob && value instanceof global.Blob) {
|
||||||
|
// mimic File instance by adding missing properties
|
||||||
|
value.lastModifiedDate = new Date();
|
||||||
|
value.name = filename !== undefined ? filename : 'blob';
|
||||||
|
} else {
|
||||||
|
value = String(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.__items.push([ name, value ]);
|
||||||
|
};
|
||||||
|
|
||||||
|
FormData.prototype.entries = function() {
|
||||||
|
return new Iterator(this.__items);
|
||||||
|
};
|
||||||
|
|
||||||
|
function Iterator(items) {
|
||||||
|
this.__items = items;
|
||||||
|
this.__position = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
Iterator.prototype.next = function() {
|
||||||
|
this.__position += 1;
|
||||||
|
|
||||||
|
if (this.__position < this.__items.length) {
|
||||||
|
return { done: false, value: this.__items[this.__position] };
|
||||||
|
}
|
||||||
|
|
||||||
|
return { done: true, value: undefined };
|
||||||
|
}
|
||||||
|
|
||||||
|
return interface;
|
||||||
|
};
|
||||||
+61
-30
@@ -1,5 +1,5 @@
|
|||||||
module.exports = function init(exec, cookieHandler, urlUtil, helpers, globalConfigs) {
|
module.exports = function init(exec, cookieHandler, urlUtil, helpers, globalConfigs, errorCodes, ponyfills) {
|
||||||
const publicInterface = {
|
var publicInterface = {
|
||||||
getBasicAuthHeader: getBasicAuthHeader,
|
getBasicAuthHeader: getBasicAuthHeader,
|
||||||
useBasicAuth: useBasicAuth,
|
useBasicAuth: useBasicAuth,
|
||||||
getHeaders: getHeaders,
|
getHeaders: getHeaders,
|
||||||
@@ -12,20 +12,23 @@ module.exports = function init(exec, cookieHandler, urlUtil, helpers, globalConf
|
|||||||
getCookieString: getCookieString,
|
getCookieString: getCookieString,
|
||||||
getRequestTimeout: getRequestTimeout,
|
getRequestTimeout: getRequestTimeout,
|
||||||
setRequestTimeout: setRequestTimeout,
|
setRequestTimeout: setRequestTimeout,
|
||||||
// for being backward compatible
|
getFollowRedirect: getFollowRedirect,
|
||||||
setSSLCertMode: setServerTrustMode,
|
setFollowRedirect: setFollowRedirect,
|
||||||
setServerTrustMode: setServerTrustMode,
|
setServerTrustMode: setServerTrustMode,
|
||||||
setClientAuthMode: setClientAuthMode,
|
setClientAuthMode: setClientAuthMode,
|
||||||
disableRedirect: disableRedirect,
|
|
||||||
sendRequest: sendRequest,
|
sendRequest: sendRequest,
|
||||||
post: post,
|
post: post,
|
||||||
get: get,
|
|
||||||
put: put,
|
put: put,
|
||||||
patch: patch,
|
patch: patch,
|
||||||
|
get: get,
|
||||||
delete: del,
|
delete: del,
|
||||||
head: head,
|
head: head,
|
||||||
|
options: options,
|
||||||
uploadFile: uploadFile,
|
uploadFile: uploadFile,
|
||||||
downloadFile: downloadFile
|
downloadFile: downloadFile,
|
||||||
|
abort: abort,
|
||||||
|
ErrorCode: errorCodes,
|
||||||
|
ponyfills: ponyfills
|
||||||
};
|
};
|
||||||
|
|
||||||
function getBasicAuthHeader(username, password) {
|
function getBasicAuthHeader(username, password) {
|
||||||
@@ -56,7 +59,12 @@ module.exports = function init(exec, cookieHandler, urlUtil, helpers, globalConf
|
|||||||
helpers.checkForInvalidHeaderValue(value);
|
helpers.checkForInvalidHeaderValue(value);
|
||||||
|
|
||||||
globalConfigs.headers[host] = globalConfigs.headers[host] || {};
|
globalConfigs.headers[host] = globalConfigs.headers[host] || {};
|
||||||
globalConfigs.headers[host][header] = value;
|
|
||||||
|
if (value === null) {
|
||||||
|
delete globalConfigs.headers[host][header];
|
||||||
|
} else {
|
||||||
|
globalConfigs.headers[host][header] = value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getDataSerializer() {
|
function getDataSerializer() {
|
||||||
@@ -88,7 +96,15 @@ module.exports = function init(exec, cookieHandler, urlUtil, helpers, globalConf
|
|||||||
}
|
}
|
||||||
|
|
||||||
function setRequestTimeout(timeout) {
|
function setRequestTimeout(timeout) {
|
||||||
globalConfigs.timeout = timeout;
|
globalConfigs.timeout = helpers.checkTimeoutValue(timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getFollowRedirect() {
|
||||||
|
return globalConfigs.followRedirect;
|
||||||
|
}
|
||||||
|
|
||||||
|
function setFollowRedirect(follow) {
|
||||||
|
globalConfigs.followRedirect = helpers.checkFollowRedirectValue(follow);
|
||||||
}
|
}
|
||||||
|
|
||||||
function setServerTrustMode(mode, success, failure) {
|
function setServerTrustMode(mode, success, failure) {
|
||||||
@@ -98,28 +114,23 @@ module.exports = function init(exec, cookieHandler, urlUtil, helpers, globalConf
|
|||||||
}
|
}
|
||||||
|
|
||||||
function setClientAuthMode() {
|
function setClientAuthMode() {
|
||||||
// filePath is an optional param
|
|
||||||
var mode = arguments[0];
|
var mode = arguments[0];
|
||||||
|
var options = null;
|
||||||
var success = arguments[1];
|
var success = arguments[1];
|
||||||
var failure = arguments[2];
|
var failure = arguments[2];
|
||||||
var filePath = null;
|
|
||||||
|
|
||||||
if (arguments.length === 4) {
|
if (arguments.length === 4) {
|
||||||
mode = arguments[0];
|
options = arguments[1];
|
||||||
filePath = arguments[1];
|
|
||||||
success = arguments[2];
|
success = arguments[2];
|
||||||
failure = arguments[3];
|
failure = arguments[3];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mode = helpers.checkClientAuthMode(mode);
|
||||||
|
options = helpers.checkClientAuthOptions(mode, options);
|
||||||
|
|
||||||
helpers.handleMissingCallbacks(success, failure);
|
helpers.handleMissingCallbacks(success, failure);
|
||||||
|
|
||||||
return exec(success, failure, 'CordovaHttpPlugin', 'setClientAuthMode', [helpers.checkClientAuthMode(mode), filePath]);
|
return exec(success, failure, 'CordovaHttpPlugin', 'setClientAuthMode', [mode, options.alias, options.rawPkcs, options.pkcsPassword]);
|
||||||
}
|
|
||||||
|
|
||||||
function disableRedirect(disable, success, failure) {
|
|
||||||
helpers.handleMissingCallbacks(success, failure);
|
|
||||||
|
|
||||||
return exec(success, failure, 'CordovaHttpPlugin', 'disableRedirect', [!!disable]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function sendRequest(url, options, success, failure) {
|
function sendRequest(url, options, success, failure) {
|
||||||
@@ -129,33 +140,41 @@ module.exports = function init(exec, cookieHandler, urlUtil, helpers, globalConf
|
|||||||
url = urlUtil.appendQueryParamsString(url, urlUtil.serializeQueryParams(options.params, true));
|
url = urlUtil.appendQueryParamsString(url, urlUtil.serializeQueryParams(options.params, true));
|
||||||
|
|
||||||
var headers = helpers.getMergedHeaders(url, options.headers, globalConfigs.headers);
|
var headers = helpers.getMergedHeaders(url, options.headers, globalConfigs.headers);
|
||||||
var onSuccess = helpers.injectCookieHandler(url, success);
|
|
||||||
var onFail = helpers.injectCookieHandler(url, failure);
|
var onFail = helpers.injectCookieHandler(url, failure);
|
||||||
|
var onSuccess = helpers.injectCookieHandler(url, helpers.injectRawResponseHandler(options.responseType, success, failure));
|
||||||
|
|
||||||
|
var reqId = helpers.nextRequestId();
|
||||||
|
|
||||||
switch (options.method) {
|
switch (options.method) {
|
||||||
case 'post':
|
case 'post':
|
||||||
case 'put':
|
case 'put':
|
||||||
case 'patch':
|
case 'patch':
|
||||||
var data = helpers.getProcessedData(options.data, options.serializer);
|
helpers.processData(options.data, options.serializer, function (data) {
|
||||||
return exec(onSuccess, onFail, 'CordovaHttpPlugin', options.method, [url, data, options.serializer, headers, options.timeout]);
|
exec(onSuccess, onFail, 'CordovaHttpPlugin', options.method, [url, data, options.serializer, headers, options.timeout, options.followRedirect, options.responseType, reqId]);
|
||||||
|
});
|
||||||
|
break;
|
||||||
case 'upload':
|
case 'upload':
|
||||||
return exec(onSuccess, onFail, 'CordovaHttpPlugin', 'uploadFile', [url, headers, options.filePath, options.name, options.timeout]);
|
var fileOptions = helpers.checkUploadFileOptions(options.filePath, options.name);
|
||||||
|
exec(onSuccess, onFail, 'CordovaHttpPlugin', 'uploadFiles', [url, headers, fileOptions.filePaths, fileOptions.names, options.timeout, options.followRedirect, options.responseType, reqId]);
|
||||||
|
break;
|
||||||
case 'download':
|
case 'download':
|
||||||
|
var filePath = helpers.checkDownloadFilePath(options.filePath);
|
||||||
var onDownloadSuccess = helpers.injectCookieHandler(url, helpers.injectFileEntryHandler(success));
|
var onDownloadSuccess = helpers.injectCookieHandler(url, helpers.injectFileEntryHandler(success));
|
||||||
return exec(onDownloadSuccess, onFail, 'CordovaHttpPlugin', 'downloadFile', [url, headers, options.filePath, options.timeout]);
|
exec(onDownloadSuccess, onFail, 'CordovaHttpPlugin', 'downloadFile', [url, headers, filePath, options.timeout, options.followRedirect, reqId]);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
return exec(onSuccess, onFail, 'CordovaHttpPlugin', options.method, [url, headers, options.timeout]);
|
exec(onSuccess, onFail, 'CordovaHttpPlugin', options.method, [url, headers, options.timeout, options.followRedirect, options.responseType, reqId]);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return reqId;
|
||||||
}
|
}
|
||||||
|
|
||||||
function post(url, data, headers, success, failure) {
|
function post(url, data, headers, success, failure) {
|
||||||
return publicInterface.sendRequest(url, { method: 'post', data: data, headers: headers }, success, failure);
|
return publicInterface.sendRequest(url, { method: 'post', data: data, headers: headers }, success, failure);
|
||||||
};
|
};
|
||||||
|
|
||||||
function get(url, params, headers, success, failure) {
|
|
||||||
return publicInterface.sendRequest(url, { method: 'get', params: params, headers: headers }, success, failure);
|
|
||||||
};
|
|
||||||
|
|
||||||
function put(url, data, headers, success, failure) {
|
function put(url, data, headers, success, failure) {
|
||||||
return publicInterface.sendRequest(url, { method: 'put', data: data, headers: headers }, success, failure);
|
return publicInterface.sendRequest(url, { method: 'put', data: data, headers: headers }, success, failure);
|
||||||
}
|
}
|
||||||
@@ -164,6 +183,10 @@ module.exports = function init(exec, cookieHandler, urlUtil, helpers, globalConf
|
|||||||
return publicInterface.sendRequest(url, { method: 'patch', data: data, headers: headers }, success, failure);
|
return publicInterface.sendRequest(url, { method: 'patch', data: data, headers: headers }, success, failure);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function get(url, params, headers, success, failure) {
|
||||||
|
return publicInterface.sendRequest(url, { method: 'get', params: params, headers: headers }, success, failure);
|
||||||
|
};
|
||||||
|
|
||||||
function del(url, params, headers, success, failure) {
|
function del(url, params, headers, success, failure) {
|
||||||
return publicInterface.sendRequest(url, { method: 'delete', params: params, headers: headers }, success, failure);
|
return publicInterface.sendRequest(url, { method: 'delete', params: params, headers: headers }, success, failure);
|
||||||
}
|
}
|
||||||
@@ -172,6 +195,10 @@ module.exports = function init(exec, cookieHandler, urlUtil, helpers, globalConf
|
|||||||
return publicInterface.sendRequest(url, { method: 'head', params: params, headers: headers }, success, failure);
|
return publicInterface.sendRequest(url, { method: 'head', params: params, headers: headers }, success, failure);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function options(url, params, headers, success, failure) {
|
||||||
|
return publicInterface.sendRequest(url, { method: 'options', params: params, headers: headers }, success, failure);
|
||||||
|
};
|
||||||
|
|
||||||
function uploadFile(url, params, headers, filePath, name, success, failure) {
|
function uploadFile(url, params, headers, filePath, name, success, failure) {
|
||||||
return publicInterface.sendRequest(url, { method: 'upload', params: params, headers: headers, filePath: filePath, name: name }, success, failure);
|
return publicInterface.sendRequest(url, { method: 'upload', params: params, headers: headers, filePath: filePath, name: name }, success, failure);
|
||||||
}
|
}
|
||||||
@@ -180,5 +207,9 @@ module.exports = function init(exec, cookieHandler, urlUtil, helpers, globalConf
|
|||||||
return publicInterface.sendRequest(url, { method: 'download', params: params, headers: headers, filePath: filePath }, success, failure);
|
return publicInterface.sendRequest(url, { method: 'download', params: params, headers: headers, filePath: filePath }, success, failure);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function abort(requestId , success, failure) {
|
||||||
|
return exec(success, failure, 'CordovaHttpPlugin', 'abort', [requestId]);
|
||||||
|
}
|
||||||
|
|
||||||
return publicInterface;
|
return publicInterface;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user