@capacitor-plus/android 8.0.0-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/capacitor/build.gradle +94 -0
- package/capacitor/lint-baseline.xml +136 -0
- package/capacitor/lint.xml +9 -0
- package/capacitor/proguard-rules.pro +28 -0
- package/capacitor/src/main/AndroidManifest.xml +3 -0
- package/capacitor/src/main/assets/native-bridge.js +1029 -0
- package/capacitor/src/main/java/com/getcapacitor/AndroidProtocolHandler.java +94 -0
- package/capacitor/src/main/java/com/getcapacitor/App.java +61 -0
- package/capacitor/src/main/java/com/getcapacitor/AppUUID.java +65 -0
- package/capacitor/src/main/java/com/getcapacitor/Bridge.java +1627 -0
- package/capacitor/src/main/java/com/getcapacitor/BridgeActivity.java +212 -0
- package/capacitor/src/main/java/com/getcapacitor/BridgeWebChromeClient.java +467 -0
- package/capacitor/src/main/java/com/getcapacitor/BridgeWebViewClient.java +105 -0
- package/capacitor/src/main/java/com/getcapacitor/CapConfig.java +709 -0
- package/capacitor/src/main/java/com/getcapacitor/CapacitorWebView.java +57 -0
- package/capacitor/src/main/java/com/getcapacitor/FileUtils.java +303 -0
- package/capacitor/src/main/java/com/getcapacitor/InvalidPluginException.java +8 -0
- package/capacitor/src/main/java/com/getcapacitor/InvalidPluginMethodException.java +16 -0
- package/capacitor/src/main/java/com/getcapacitor/JSArray.java +51 -0
- package/capacitor/src/main/java/com/getcapacitor/JSExport.java +208 -0
- package/capacitor/src/main/java/com/getcapacitor/JSExportException.java +16 -0
- package/capacitor/src/main/java/com/getcapacitor/JSInjector.java +127 -0
- package/capacitor/src/main/java/com/getcapacitor/JSObject.java +164 -0
- package/capacitor/src/main/java/com/getcapacitor/JSValue.java +65 -0
- package/capacitor/src/main/java/com/getcapacitor/Logger.java +103 -0
- package/capacitor/src/main/java/com/getcapacitor/MessageHandler.java +157 -0
- package/capacitor/src/main/java/com/getcapacitor/NativePlugin.java +37 -0
- package/capacitor/src/main/java/com/getcapacitor/PermissionState.java +31 -0
- package/capacitor/src/main/java/com/getcapacitor/Plugin.java +1050 -0
- package/capacitor/src/main/java/com/getcapacitor/PluginCall.java +394 -0
- package/capacitor/src/main/java/com/getcapacitor/PluginConfig.java +116 -0
- package/capacitor/src/main/java/com/getcapacitor/PluginHandle.java +160 -0
- package/capacitor/src/main/java/com/getcapacitor/PluginInvocationException.java +16 -0
- package/capacitor/src/main/java/com/getcapacitor/PluginLoadException.java +19 -0
- package/capacitor/src/main/java/com/getcapacitor/PluginManager.java +56 -0
- package/capacitor/src/main/java/com/getcapacitor/PluginMethod.java +15 -0
- package/capacitor/src/main/java/com/getcapacitor/PluginMethodHandle.java +33 -0
- package/capacitor/src/main/java/com/getcapacitor/PluginResult.java +84 -0
- package/capacitor/src/main/java/com/getcapacitor/ProcessedRoute.java +37 -0
- package/capacitor/src/main/java/com/getcapacitor/RouteProcessor.java +8 -0
- package/capacitor/src/main/java/com/getcapacitor/ServerPath.java +25 -0
- package/capacitor/src/main/java/com/getcapacitor/UriMatcher.java +184 -0
- package/capacitor/src/main/java/com/getcapacitor/WebViewListener.java +57 -0
- package/capacitor/src/main/java/com/getcapacitor/WebViewLocalServer.java +758 -0
- package/capacitor/src/main/java/com/getcapacitor/annotation/ActivityCallback.java +10 -0
- package/capacitor/src/main/java/com/getcapacitor/annotation/CapacitorPlugin.java +35 -0
- package/capacitor/src/main/java/com/getcapacitor/annotation/Permission.java +22 -0
- package/capacitor/src/main/java/com/getcapacitor/annotation/PermissionCallback.java +10 -0
- package/capacitor/src/main/java/com/getcapacitor/cordova/CapacitorCordovaCookieManager.java +42 -0
- package/capacitor/src/main/java/com/getcapacitor/cordova/MockCordovaInterfaceImpl.java +39 -0
- package/capacitor/src/main/java/com/getcapacitor/cordova/MockCordovaWebViewImpl.java +282 -0
- package/capacitor/src/main/java/com/getcapacitor/plugin/CapacitorCookieManager.java +239 -0
- package/capacitor/src/main/java/com/getcapacitor/plugin/CapacitorCookies.java +119 -0
- package/capacitor/src/main/java/com/getcapacitor/plugin/CapacitorHttp.java +119 -0
- package/capacitor/src/main/java/com/getcapacitor/plugin/SystemBars.java +220 -0
- package/capacitor/src/main/java/com/getcapacitor/plugin/WebView.java +48 -0
- package/capacitor/src/main/java/com/getcapacitor/plugin/util/AssetUtil.java +358 -0
- package/capacitor/src/main/java/com/getcapacitor/plugin/util/CapacitorHttpUrlConnection.java +473 -0
- package/capacitor/src/main/java/com/getcapacitor/plugin/util/HttpRequestHandler.java +465 -0
- package/capacitor/src/main/java/com/getcapacitor/plugin/util/ICapacitorHttpUrlConnection.java +15 -0
- package/capacitor/src/main/java/com/getcapacitor/plugin/util/MimeType.java +17 -0
- package/capacitor/src/main/java/com/getcapacitor/util/HostMask.java +123 -0
- package/capacitor/src/main/java/com/getcapacitor/util/InternalUtils.java +27 -0
- package/capacitor/src/main/java/com/getcapacitor/util/JSONUtils.java +166 -0
- package/capacitor/src/main/java/com/getcapacitor/util/PermissionHelper.java +114 -0
- package/capacitor/src/main/java/com/getcapacitor/util/WebColor.java +28 -0
- package/capacitor/src/main/res/layout/capacitor_bridge_layout_main.xml +15 -0
- package/capacitor/src/main/res/layout/no_webview.xml +14 -0
- package/capacitor/src/main/res/values/colors.xml +6 -0
- package/capacitor/src/main/res/values/strings.xml +3 -0
- package/capacitor/src/main/res/values/styles.xml +6 -0
- package/package.json +31 -0
|
@@ -0,0 +1,465 @@
|
|
|
1
|
+
package com.getcapacitor.plugin.util;
|
|
2
|
+
|
|
3
|
+
import android.text.TextUtils;
|
|
4
|
+
import android.util.Base64;
|
|
5
|
+
import com.getcapacitor.Bridge;
|
|
6
|
+
import com.getcapacitor.JSArray;
|
|
7
|
+
import com.getcapacitor.JSObject;
|
|
8
|
+
import com.getcapacitor.JSValue;
|
|
9
|
+
import com.getcapacitor.PluginCall;
|
|
10
|
+
import java.io.BufferedReader;
|
|
11
|
+
import java.io.ByteArrayOutputStream;
|
|
12
|
+
import java.io.IOException;
|
|
13
|
+
import java.io.InputStream;
|
|
14
|
+
import java.io.InputStreamReader;
|
|
15
|
+
import java.io.UnsupportedEncodingException;
|
|
16
|
+
import java.lang.reflect.Method;
|
|
17
|
+
import java.net.HttpURLConnection;
|
|
18
|
+
import java.net.MalformedURLException;
|
|
19
|
+
import java.net.URI;
|
|
20
|
+
import java.net.URISyntaxException;
|
|
21
|
+
import java.net.URL;
|
|
22
|
+
import java.net.URLEncoder;
|
|
23
|
+
import java.util.Iterator;
|
|
24
|
+
import java.util.List;
|
|
25
|
+
import java.util.Locale;
|
|
26
|
+
import java.util.Map;
|
|
27
|
+
import org.json.JSONArray;
|
|
28
|
+
import org.json.JSONException;
|
|
29
|
+
import org.json.JSONObject;
|
|
30
|
+
|
|
31
|
+
public class HttpRequestHandler {
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* An enum specifying conventional HTTP Response Types
|
|
35
|
+
* See https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/responseType
|
|
36
|
+
*/
|
|
37
|
+
public enum ResponseType {
|
|
38
|
+
ARRAY_BUFFER("arraybuffer"),
|
|
39
|
+
BLOB("blob"),
|
|
40
|
+
DOCUMENT("document"),
|
|
41
|
+
JSON("json"),
|
|
42
|
+
TEXT("text");
|
|
43
|
+
|
|
44
|
+
private final String name;
|
|
45
|
+
|
|
46
|
+
ResponseType(String name) {
|
|
47
|
+
this.name = name;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
static final ResponseType DEFAULT = TEXT;
|
|
51
|
+
|
|
52
|
+
public static ResponseType parse(String value) {
|
|
53
|
+
for (ResponseType responseType : values()) {
|
|
54
|
+
if (responseType.name.equalsIgnoreCase(value)) {
|
|
55
|
+
return responseType;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return DEFAULT;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Internal builder class for building a CapacitorHttpUrlConnection
|
|
64
|
+
*/
|
|
65
|
+
public static class HttpURLConnectionBuilder {
|
|
66
|
+
|
|
67
|
+
public Integer connectTimeout;
|
|
68
|
+
public Integer readTimeout;
|
|
69
|
+
public Boolean disableRedirects;
|
|
70
|
+
public JSObject headers;
|
|
71
|
+
public String method;
|
|
72
|
+
public URL url;
|
|
73
|
+
|
|
74
|
+
public CapacitorHttpUrlConnection connection;
|
|
75
|
+
|
|
76
|
+
public HttpURLConnectionBuilder setConnectTimeout(Integer connectTimeout) {
|
|
77
|
+
this.connectTimeout = connectTimeout;
|
|
78
|
+
return this;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
public HttpURLConnectionBuilder setReadTimeout(Integer readTimeout) {
|
|
82
|
+
this.readTimeout = readTimeout;
|
|
83
|
+
return this;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
public HttpURLConnectionBuilder setDisableRedirects(Boolean disableRedirects) {
|
|
87
|
+
this.disableRedirects = disableRedirects;
|
|
88
|
+
return this;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
public HttpURLConnectionBuilder setHeaders(JSObject headers) {
|
|
92
|
+
this.headers = headers;
|
|
93
|
+
return this;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
public HttpURLConnectionBuilder setMethod(String method) {
|
|
97
|
+
this.method = method;
|
|
98
|
+
return this;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
public HttpURLConnectionBuilder setUrl(URL url) {
|
|
102
|
+
this.url = url;
|
|
103
|
+
return this;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
public HttpURLConnectionBuilder openConnection() throws IOException {
|
|
107
|
+
connection = new CapacitorHttpUrlConnection((HttpURLConnection) url.openConnection());
|
|
108
|
+
|
|
109
|
+
connection.setAllowUserInteraction(false);
|
|
110
|
+
connection.setRequestMethod(method);
|
|
111
|
+
|
|
112
|
+
if (connectTimeout != null) connection.setConnectTimeout(connectTimeout);
|
|
113
|
+
if (readTimeout != null) connection.setReadTimeout(readTimeout);
|
|
114
|
+
if (disableRedirects != null) connection.setDisableRedirects(disableRedirects);
|
|
115
|
+
|
|
116
|
+
connection.setRequestHeaders(headers);
|
|
117
|
+
return this;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
public HttpURLConnectionBuilder setUrlParams(JSObject params) throws MalformedURLException, URISyntaxException, JSONException {
|
|
121
|
+
return this.setUrlParams(params, true);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
public HttpURLConnectionBuilder setUrlParams(JSObject params, boolean shouldEncode)
|
|
125
|
+
throws URISyntaxException, MalformedURLException {
|
|
126
|
+
String initialQuery = url.getQuery();
|
|
127
|
+
String initialQueryBuilderStr = initialQuery == null ? "" : initialQuery;
|
|
128
|
+
|
|
129
|
+
Iterator<String> keys = params.keys();
|
|
130
|
+
|
|
131
|
+
if (!keys.hasNext()) {
|
|
132
|
+
return this;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
StringBuilder urlQueryBuilder = new StringBuilder(initialQueryBuilderStr);
|
|
136
|
+
|
|
137
|
+
// Build the new query string
|
|
138
|
+
while (keys.hasNext()) {
|
|
139
|
+
String key = keys.next();
|
|
140
|
+
|
|
141
|
+
// Attempt as JSONArray and fallback to string if it fails
|
|
142
|
+
try {
|
|
143
|
+
StringBuilder value = new StringBuilder();
|
|
144
|
+
JSONArray arr = params.getJSONArray(key);
|
|
145
|
+
for (int x = 0; x < arr.length(); x++) {
|
|
146
|
+
this.addUrlParam(value, key, arr.getString(x), shouldEncode);
|
|
147
|
+
if (x != arr.length() - 1) {
|
|
148
|
+
value.append("&");
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
if (urlQueryBuilder.length() > 0) {
|
|
152
|
+
urlQueryBuilder.append("&");
|
|
153
|
+
}
|
|
154
|
+
urlQueryBuilder.append(value);
|
|
155
|
+
} catch (JSONException e) {
|
|
156
|
+
if (urlQueryBuilder.length() > 0) {
|
|
157
|
+
urlQueryBuilder.append("&");
|
|
158
|
+
}
|
|
159
|
+
this.addUrlParam(urlQueryBuilder, key, params.getString(key), shouldEncode);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
String urlQuery = urlQueryBuilder.toString();
|
|
164
|
+
|
|
165
|
+
URI uri = url.toURI();
|
|
166
|
+
String unEncodedUrlString =
|
|
167
|
+
uri.getScheme() +
|
|
168
|
+
"://" +
|
|
169
|
+
uri.getAuthority() +
|
|
170
|
+
uri.getPath() +
|
|
171
|
+
((!urlQuery.equals("")) ? "?" + urlQuery : "") +
|
|
172
|
+
((uri.getFragment() != null) ? uri.getFragment() : "");
|
|
173
|
+
this.url = new URL(unEncodedUrlString);
|
|
174
|
+
|
|
175
|
+
return this;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
private static void addUrlParam(StringBuilder sb, String key, String value, boolean shouldEncode) {
|
|
179
|
+
if (shouldEncode) {
|
|
180
|
+
try {
|
|
181
|
+
key = URLEncoder.encode(key, "UTF-8");
|
|
182
|
+
value = URLEncoder.encode(value, "UTF-8");
|
|
183
|
+
} catch (UnsupportedEncodingException ex) {
|
|
184
|
+
throw new RuntimeException(ex.getCause());
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
sb.append(key).append("=").append(value);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
public CapacitorHttpUrlConnection build() {
|
|
191
|
+
return connection;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Builds an HTTP Response given CapacitorHttpUrlConnection and ResponseType objects.
|
|
197
|
+
* Defaults to ResponseType.DEFAULT
|
|
198
|
+
* @param connection The CapacitorHttpUrlConnection to respond with
|
|
199
|
+
* @throws IOException Thrown if the InputStream is unable to be parsed correctly
|
|
200
|
+
* @throws JSONException Thrown if the JSON is unable to be parsed
|
|
201
|
+
*/
|
|
202
|
+
public static JSObject buildResponse(CapacitorHttpUrlConnection connection) throws IOException, JSONException {
|
|
203
|
+
return buildResponse(connection, ResponseType.DEFAULT);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* Builds an HTTP Response given CapacitorHttpUrlConnection and ResponseType objects
|
|
208
|
+
* @param connection The CapacitorHttpUrlConnection to respond with
|
|
209
|
+
* @param responseType The requested ResponseType
|
|
210
|
+
* @return A JSObject that contains the HTTPResponse to return to the browser
|
|
211
|
+
* @throws IOException Thrown if the InputStream is unable to be parsed correctly
|
|
212
|
+
* @throws JSONException Thrown if the JSON is unable to be parsed
|
|
213
|
+
*/
|
|
214
|
+
public static JSObject buildResponse(CapacitorHttpUrlConnection connection, ResponseType responseType)
|
|
215
|
+
throws IOException, JSONException {
|
|
216
|
+
int statusCode = connection.getResponseCode();
|
|
217
|
+
|
|
218
|
+
JSObject output = new JSObject();
|
|
219
|
+
output.put("status", statusCode);
|
|
220
|
+
output.put("headers", buildResponseHeaders(connection));
|
|
221
|
+
output.put("url", connection.getURL());
|
|
222
|
+
output.put("data", readData(connection, responseType));
|
|
223
|
+
|
|
224
|
+
InputStream errorStream = connection.getErrorStream();
|
|
225
|
+
if (errorStream != null) {
|
|
226
|
+
output.put("error", true);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
return output;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* Read the existing ICapacitorHttpUrlConnection data
|
|
234
|
+
* @param connection The ICapacitorHttpUrlConnection object to read in
|
|
235
|
+
* @param responseType The type of HTTP response to return to the API
|
|
236
|
+
* @return The parsed data from the connection
|
|
237
|
+
* @throws IOException Thrown if the InputStreams cannot be properly parsed
|
|
238
|
+
* @throws JSONException Thrown if the JSON is malformed when parsing as JSON
|
|
239
|
+
*/
|
|
240
|
+
public static Object readData(ICapacitorHttpUrlConnection connection, ResponseType responseType) throws IOException, JSONException {
|
|
241
|
+
InputStream errorStream = connection.getErrorStream();
|
|
242
|
+
String contentType = connection.getHeaderField("Content-Type");
|
|
243
|
+
|
|
244
|
+
if (errorStream != null) {
|
|
245
|
+
if (isOneOf(contentType, MimeType.APPLICATION_JSON, MimeType.APPLICATION_VND_API_JSON)) {
|
|
246
|
+
return parseJSON(readStreamAsString(errorStream));
|
|
247
|
+
} else {
|
|
248
|
+
return readStreamAsString(errorStream);
|
|
249
|
+
}
|
|
250
|
+
} else if (contentType != null && contentType.contains(MimeType.APPLICATION_JSON.getValue())) {
|
|
251
|
+
// backward compatibility
|
|
252
|
+
return parseJSON(readStreamAsString(connection.getInputStream()));
|
|
253
|
+
} else {
|
|
254
|
+
InputStream stream = connection.getInputStream();
|
|
255
|
+
switch (responseType) {
|
|
256
|
+
case ARRAY_BUFFER:
|
|
257
|
+
case BLOB:
|
|
258
|
+
return readStreamAsBase64(stream);
|
|
259
|
+
case JSON:
|
|
260
|
+
return parseJSON(readStreamAsString(stream));
|
|
261
|
+
case DOCUMENT:
|
|
262
|
+
case TEXT:
|
|
263
|
+
default:
|
|
264
|
+
return readStreamAsString(stream);
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
/**
|
|
270
|
+
* Helper function for determining if the Content-Type is a typeof an existing Mime-Type
|
|
271
|
+
* @param contentType The Content-Type string to check for
|
|
272
|
+
* @param mimeTypes The Mime-Type values to check against
|
|
273
|
+
* @return
|
|
274
|
+
*/
|
|
275
|
+
public static boolean isOneOf(String contentType, MimeType... mimeTypes) {
|
|
276
|
+
if (contentType != null) {
|
|
277
|
+
for (MimeType mimeType : mimeTypes) {
|
|
278
|
+
if (contentType.contains(mimeType.getValue())) {
|
|
279
|
+
return true;
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
return false;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
/**
|
|
287
|
+
* Build the JSObject response headers based on the connection header map
|
|
288
|
+
* @param connection The CapacitorHttpUrlConnection connection
|
|
289
|
+
* @return A JSObject of the header values from the CapacitorHttpUrlConnection
|
|
290
|
+
*/
|
|
291
|
+
public static JSObject buildResponseHeaders(CapacitorHttpUrlConnection connection) {
|
|
292
|
+
JSObject output = new JSObject();
|
|
293
|
+
|
|
294
|
+
for (Map.Entry<String, List<String>> entry : connection.getHeaderFields().entrySet()) {
|
|
295
|
+
String valuesString = TextUtils.join(", ", entry.getValue());
|
|
296
|
+
output.put(entry.getKey(), valuesString);
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
return output;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
/**
|
|
303
|
+
* Returns a JSObject or a JSArray based on a string-ified input
|
|
304
|
+
* @param input String-ified JSON that needs parsing
|
|
305
|
+
* @return A JSObject or JSArray
|
|
306
|
+
* @throws JSONException thrown if the JSON is malformed
|
|
307
|
+
*/
|
|
308
|
+
public static Object parseJSON(String input) throws JSONException {
|
|
309
|
+
JSONObject json = new JSONObject();
|
|
310
|
+
try {
|
|
311
|
+
if ("null".equals(input.trim())) {
|
|
312
|
+
return JSONObject.NULL;
|
|
313
|
+
} else if ("true".equals(input.trim())) {
|
|
314
|
+
return true;
|
|
315
|
+
} else if ("false".equals(input.trim())) {
|
|
316
|
+
return false;
|
|
317
|
+
} else if (input.trim().length() <= 0) {
|
|
318
|
+
return "";
|
|
319
|
+
} else if (input.trim().matches("^\".*\"$")) {
|
|
320
|
+
// a string enclosed in " " is a json value, return the string without the quotes
|
|
321
|
+
return input.trim().substring(1, input.trim().length() - 1);
|
|
322
|
+
} else if (input.trim().matches("^-?\\d+$")) {
|
|
323
|
+
return Integer.parseInt(input.trim());
|
|
324
|
+
} else if (input.trim().matches("^-?\\d+(\\.\\d+)?$")) {
|
|
325
|
+
return Double.parseDouble(input.trim());
|
|
326
|
+
} else {
|
|
327
|
+
try {
|
|
328
|
+
return new JSObject(input);
|
|
329
|
+
} catch (JSONException e) {
|
|
330
|
+
return new JSArray(input);
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
} catch (JSONException e) {
|
|
334
|
+
return input;
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
/**
|
|
339
|
+
* Returns a string based on a base64 InputStream
|
|
340
|
+
* @param in The base64 InputStream to convert to a String
|
|
341
|
+
* @return String value of InputStream
|
|
342
|
+
* @throws IOException thrown if the InputStream is unable to be read as base64
|
|
343
|
+
*/
|
|
344
|
+
public static String readStreamAsBase64(InputStream in) throws IOException {
|
|
345
|
+
try (ByteArrayOutputStream out = new ByteArrayOutputStream()) {
|
|
346
|
+
byte[] buffer = new byte[1024];
|
|
347
|
+
int readBytes;
|
|
348
|
+
while ((readBytes = in.read(buffer)) != -1) {
|
|
349
|
+
out.write(buffer, 0, readBytes);
|
|
350
|
+
}
|
|
351
|
+
byte[] result = out.toByteArray();
|
|
352
|
+
return Base64.encodeToString(result, 0, result.length, Base64.DEFAULT);
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
/**
|
|
357
|
+
* Returns a string based on an InputStream
|
|
358
|
+
* @param in The InputStream to convert to a String
|
|
359
|
+
* @return String value of InputStream
|
|
360
|
+
* @throws IOException thrown if the InputStream is unable to be read
|
|
361
|
+
*/
|
|
362
|
+
public static String readStreamAsString(InputStream in) throws IOException {
|
|
363
|
+
try (BufferedReader reader = new BufferedReader(new InputStreamReader(in))) {
|
|
364
|
+
StringBuilder builder = new StringBuilder();
|
|
365
|
+
String line = reader.readLine();
|
|
366
|
+
while (line != null) {
|
|
367
|
+
builder.append(line);
|
|
368
|
+
line = reader.readLine();
|
|
369
|
+
if (line != null) {
|
|
370
|
+
builder.append(System.getProperty("line.separator"));
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
return builder.toString();
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
/**
|
|
378
|
+
* Makes an Http Request based on the PluginCall parameters
|
|
379
|
+
* @param call The Capacitor PluginCall that contains the options need for an Http request
|
|
380
|
+
* @param httpMethod The HTTP method that overrides the PluginCall HTTP method
|
|
381
|
+
* @throws IOException throws an IO request when a connection can't be made
|
|
382
|
+
* @throws URISyntaxException thrown when the URI is malformed
|
|
383
|
+
* @throws JSONException thrown when the incoming JSON is malformed
|
|
384
|
+
*/
|
|
385
|
+
public static JSObject request(PluginCall call, String httpMethod, Bridge bridge)
|
|
386
|
+
throws IOException, URISyntaxException, JSONException {
|
|
387
|
+
String urlString = call.getString("url", "");
|
|
388
|
+
JSObject headers = call.getObject("headers", new JSObject());
|
|
389
|
+
JSObject params = call.getObject("params", new JSObject());
|
|
390
|
+
Integer connectTimeout = call.getInt("connectTimeout");
|
|
391
|
+
Integer readTimeout = call.getInt("readTimeout");
|
|
392
|
+
Boolean disableRedirects = call.getBoolean("disableRedirects");
|
|
393
|
+
Boolean shouldEncode = call.getBoolean("shouldEncodeUrlParams", true);
|
|
394
|
+
ResponseType responseType = ResponseType.parse(call.getString("responseType"));
|
|
395
|
+
String dataType = call.getString("dataType");
|
|
396
|
+
|
|
397
|
+
String method = httpMethod != null ? httpMethod.toUpperCase(Locale.ROOT) : call.getString("method", "GET").toUpperCase(Locale.ROOT);
|
|
398
|
+
|
|
399
|
+
boolean isHttpMutate = method.equals("DELETE") || method.equals("PATCH") || method.equals("POST") || method.equals("PUT");
|
|
400
|
+
|
|
401
|
+
// a workaround for the following android web view issue:
|
|
402
|
+
// https://issues.chromium.org/issues/40450316
|
|
403
|
+
// x-cap-user-agent contains the user agent set in JavaScript
|
|
404
|
+
String userAgentValue = headers.getString("x-cap-user-agent");
|
|
405
|
+
if (userAgentValue != null) {
|
|
406
|
+
headers.put("User-Agent", userAgentValue);
|
|
407
|
+
}
|
|
408
|
+
headers.remove("x-cap-user-agent");
|
|
409
|
+
|
|
410
|
+
if (!headers.has("User-Agent") && !headers.has("user-agent")) {
|
|
411
|
+
headers.put("User-Agent", bridge.getConfig().getOverriddenUserAgentString());
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
URL url = new URL(urlString);
|
|
415
|
+
HttpURLConnectionBuilder connectionBuilder = new HttpURLConnectionBuilder()
|
|
416
|
+
.setUrl(url)
|
|
417
|
+
.setMethod(method)
|
|
418
|
+
.setHeaders(headers)
|
|
419
|
+
.setUrlParams(params, shouldEncode)
|
|
420
|
+
.setConnectTimeout(connectTimeout)
|
|
421
|
+
.setReadTimeout(readTimeout)
|
|
422
|
+
.setDisableRedirects(disableRedirects)
|
|
423
|
+
.openConnection();
|
|
424
|
+
|
|
425
|
+
CapacitorHttpUrlConnection connection = connectionBuilder.build();
|
|
426
|
+
|
|
427
|
+
if (null != bridge && !isDomainExcludedFromSSL(bridge, url)) {
|
|
428
|
+
connection.setSSLSocketFactory(bridge);
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
// Set HTTP body on a non GET or HEAD request
|
|
432
|
+
if (isHttpMutate) {
|
|
433
|
+
JSValue data = new JSValue(call, "data");
|
|
434
|
+
if (data.getValue() != null) {
|
|
435
|
+
connection.setDoOutput(true);
|
|
436
|
+
connection.setRequestBody(call, data, dataType);
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
call.getData().put("activeCapacitorHttpUrlConnection", connection);
|
|
441
|
+
connection.connect();
|
|
442
|
+
|
|
443
|
+
JSObject response = buildResponse(connection, responseType);
|
|
444
|
+
|
|
445
|
+
connection.disconnect();
|
|
446
|
+
call.getData().remove("activeCapacitorHttpUrlConnection");
|
|
447
|
+
|
|
448
|
+
return response;
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
public static Boolean isDomainExcludedFromSSL(Bridge bridge, URL url) {
|
|
452
|
+
try {
|
|
453
|
+
Class<?> sslPinningImpl = Class.forName("io.ionic.sslpinning.SSLPinning");
|
|
454
|
+
Method method = sslPinningImpl.getDeclaredMethod("isDomainExcluded", Bridge.class, URL.class);
|
|
455
|
+
return (Boolean) method.invoke(sslPinningImpl.getDeclaredConstructor().newInstance(), bridge, url);
|
|
456
|
+
} catch (Exception ignored) {
|
|
457
|
+
return false;
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
@FunctionalInterface
|
|
462
|
+
public interface ProgressEmitter {
|
|
463
|
+
void emit(Integer bytes, Integer contentLength);
|
|
464
|
+
}
|
|
465
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
package com.getcapacitor.plugin.util;
|
|
2
|
+
|
|
3
|
+
import java.io.IOException;
|
|
4
|
+
import java.io.InputStream;
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* This interface was extracted from {@link CapacitorHttpUrlConnection} to enable mocking that class.
|
|
8
|
+
*/
|
|
9
|
+
public interface ICapacitorHttpUrlConnection {
|
|
10
|
+
InputStream getErrorStream();
|
|
11
|
+
|
|
12
|
+
String getHeaderField(String name);
|
|
13
|
+
|
|
14
|
+
InputStream getInputStream() throws IOException;
|
|
15
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
package com.getcapacitor.plugin.util;
|
|
2
|
+
|
|
3
|
+
enum MimeType {
|
|
4
|
+
APPLICATION_JSON("application/json"),
|
|
5
|
+
APPLICATION_VND_API_JSON("application/vnd.api+json"), // https://jsonapi.org
|
|
6
|
+
TEXT_HTML("text/html");
|
|
7
|
+
|
|
8
|
+
private final String value;
|
|
9
|
+
|
|
10
|
+
MimeType(String value) {
|
|
11
|
+
this.value = value;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
String getValue() {
|
|
15
|
+
return value;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
package com.getcapacitor.util;
|
|
2
|
+
|
|
3
|
+
import java.util.ArrayList;
|
|
4
|
+
import java.util.Arrays;
|
|
5
|
+
import java.util.Collections;
|
|
6
|
+
import java.util.List;
|
|
7
|
+
|
|
8
|
+
public interface HostMask {
|
|
9
|
+
boolean matches(String host);
|
|
10
|
+
|
|
11
|
+
class Parser {
|
|
12
|
+
|
|
13
|
+
private static HostMask NOTHING = new Nothing();
|
|
14
|
+
|
|
15
|
+
public static HostMask parse(String[] masks) {
|
|
16
|
+
return masks == null ? NOTHING : HostMask.Any.parse(masks);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
public static HostMask parse(String mask) {
|
|
20
|
+
return mask == null ? NOTHING : HostMask.Simple.parse(mask);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
class Simple implements HostMask {
|
|
25
|
+
|
|
26
|
+
private final List<String> maskParts;
|
|
27
|
+
|
|
28
|
+
private Simple(List<String> maskParts) {
|
|
29
|
+
if (maskParts == null) {
|
|
30
|
+
throw new IllegalArgumentException("Mask parts can not be null");
|
|
31
|
+
}
|
|
32
|
+
this.maskParts = maskParts;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
static Simple parse(String mask) {
|
|
36
|
+
List<String> parts = Util.splitAndReverse(mask);
|
|
37
|
+
return new Simple(parts);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
@Override
|
|
41
|
+
public boolean matches(String host) {
|
|
42
|
+
if (host == null) {
|
|
43
|
+
return false;
|
|
44
|
+
}
|
|
45
|
+
List<String> hostParts = Util.splitAndReverse(host);
|
|
46
|
+
int hostSize = hostParts.size();
|
|
47
|
+
int maskSize = maskParts.size();
|
|
48
|
+
if (maskSize > 1 && hostSize != maskSize) {
|
|
49
|
+
return false;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
int minSize = Math.min(hostSize, maskSize);
|
|
53
|
+
|
|
54
|
+
for (int i = 0; i < minSize; i++) {
|
|
55
|
+
String maskPart = maskParts.get(i);
|
|
56
|
+
String hostPart = hostParts.get(i);
|
|
57
|
+
if (!Util.matches(maskPart, hostPart)) {
|
|
58
|
+
return false;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return true;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
class Any implements HostMask {
|
|
66
|
+
|
|
67
|
+
private final List<? extends HostMask> masks;
|
|
68
|
+
|
|
69
|
+
Any(List<? extends HostMask> masks) {
|
|
70
|
+
this.masks = masks;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
@Override
|
|
74
|
+
public boolean matches(String host) {
|
|
75
|
+
for (HostMask mask : masks) {
|
|
76
|
+
if (mask.matches(host)) {
|
|
77
|
+
return true;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
return false;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
static Any parse(String... rawMasks) {
|
|
84
|
+
List<HostMask.Simple> masks = new ArrayList<>();
|
|
85
|
+
for (String raw : rawMasks) {
|
|
86
|
+
masks.add(HostMask.Simple.parse(raw));
|
|
87
|
+
}
|
|
88
|
+
return new Any(masks);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
class Nothing implements HostMask {
|
|
93
|
+
|
|
94
|
+
@Override
|
|
95
|
+
public boolean matches(String host) {
|
|
96
|
+
return false;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
class Util {
|
|
101
|
+
|
|
102
|
+
static boolean matches(String mask, String string) {
|
|
103
|
+
if (mask == null) {
|
|
104
|
+
return false;
|
|
105
|
+
} else if ("*".equals(mask)) {
|
|
106
|
+
return true;
|
|
107
|
+
} else if (string == null) {
|
|
108
|
+
return false;
|
|
109
|
+
} else {
|
|
110
|
+
return mask.toUpperCase().equals(string.toUpperCase());
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
static List<String> splitAndReverse(String string) {
|
|
115
|
+
if (string == null) {
|
|
116
|
+
throw new IllegalArgumentException("Can not split null argument");
|
|
117
|
+
}
|
|
118
|
+
List<String> parts = Arrays.asList(string.split("\\."));
|
|
119
|
+
Collections.reverse(parts);
|
|
120
|
+
return parts;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
package com.getcapacitor.util;
|
|
2
|
+
|
|
3
|
+
import android.content.pm.PackageInfo;
|
|
4
|
+
import android.content.pm.PackageManager;
|
|
5
|
+
import android.os.Build;
|
|
6
|
+
|
|
7
|
+
public class InternalUtils {
|
|
8
|
+
|
|
9
|
+
public static PackageInfo getPackageInfo(PackageManager pm, String packageName) throws PackageManager.NameNotFoundException {
|
|
10
|
+
return InternalUtils.getPackageInfo(pm, packageName, 0);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
public static PackageInfo getPackageInfo(PackageManager pm, String packageName, long flags)
|
|
14
|
+
throws PackageManager.NameNotFoundException {
|
|
15
|
+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
|
16
|
+
return pm.getPackageInfo(packageName, PackageManager.PackageInfoFlags.of(flags));
|
|
17
|
+
} else {
|
|
18
|
+
return getPackageInfoLegacy(pm, packageName, (int) flags);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
@SuppressWarnings("deprecation")
|
|
23
|
+
private static PackageInfo getPackageInfoLegacy(PackageManager pm, String packageName, long flags)
|
|
24
|
+
throws PackageManager.NameNotFoundException {
|
|
25
|
+
return pm.getPackageInfo(packageName, (int) flags);
|
|
26
|
+
}
|
|
27
|
+
}
|