tharak-android 0.0.1
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/README.md +1 -0
- package/build.gradle +45 -0
- package/consumer-rules.pro +0 -0
- package/libs/vital-sdk.aar +0 -0
- package/package.json +22 -0
- package/proguard-rules.pro +21 -0
- package/src/androidTest/androidTest.iml +11 -0
- package/src/androidTest/java/org/tharak/core/ExampleInstrumentedTest.java +27 -0
- package/src/androidTest/java/org/thiragatisoft/core/ExampleInstrumentedTest.java +26 -0
- package/src/main/AndroidManifest.xml +5 -0
- package/src/main/java/org/thiragatisoft/core/AppUtils.java +31 -0
- package/src/main/java/org/thiragatisoft/core/FileSelector.java +162 -0
- package/src/main/java/org/thiragatisoft/core/MainActivity.java +27 -0
- package/src/main/java/org/thiragatisoft/core/RestClient.java +298 -0
- package/src/main/java/org/thiragatisoft/core/VitalActivity.java +612 -0
- package/src/main/java/org/thiragatisoft/core/VitalsPlugin.java +15 -0
- package/src/main/java/org/thiragatisoft/core/VolleyMultipartRequest.java +218 -0
- package/src/main/java/org/thiragatisoft/core/http/CapacitorCookieManager.java +175 -0
- package/src/main/java/org/thiragatisoft/core/http/CapacitorHttpUrlConnection.java +408 -0
- package/src/main/java/org/thiragatisoft/core/http/FilesystemUtils.java +65 -0
- package/src/main/java/org/thiragatisoft/core/http/FormUploader.java +219 -0
- package/src/main/java/org/thiragatisoft/core/http/Http.java +275 -0
- package/src/main/java/org/thiragatisoft/core/http/HttpRequestHandler.java +515 -0
- package/src/main/java/org/thiragatisoft/core/http/ICapacitorHttpUrlConnection.java +15 -0
- package/src/main/java/org/thiragatisoft/core/http/JSValue.java +68 -0
- package/src/main/java/org/thiragatisoft/core/http/MimeType.java +17 -0
- package/src/main/main.iml +12 -0
- package/src/test/java/org/tharak/ExampleUnitTest.java +17 -0
- package/src/test/java/org/tharak/JSObjectTest.java +209 -0
- package/src/test/java/org/tharak/PluginMethodHandleTest.java +44 -0
- package/src/test/java/org/tharak/util/HostMaskTest.java +70 -0
- package/src/test/java/org/thiragatisoft/core/ExampleUnitTest.java +17 -0
- package/src/test/test.iml +11 -0
@@ -0,0 +1,515 @@
|
|
1
|
+
package org.thiragatisoft.core.http;
|
2
|
+
|
3
|
+
import android.content.Context;
|
4
|
+
import android.text.TextUtils;
|
5
|
+
import android.util.Base64;
|
6
|
+
import com.getcapacitor.JSArray;
|
7
|
+
import com.getcapacitor.JSObject;
|
8
|
+
import com.getcapacitor.PluginCall;
|
9
|
+
import java.io.BufferedReader;
|
10
|
+
import java.io.ByteArrayOutputStream;
|
11
|
+
import java.io.File;
|
12
|
+
import java.io.FileOutputStream;
|
13
|
+
import java.io.IOException;
|
14
|
+
import java.io.InputStream;
|
15
|
+
import java.io.InputStreamReader;
|
16
|
+
import java.net.HttpURLConnection;
|
17
|
+
import java.net.MalformedURLException;
|
18
|
+
import java.net.URI;
|
19
|
+
import java.net.URISyntaxException;
|
20
|
+
import java.net.URL;
|
21
|
+
import java.util.Iterator;
|
22
|
+
import java.util.List;
|
23
|
+
import java.util.Map;
|
24
|
+
import org.json.JSONArray;
|
25
|
+
import org.json.JSONException;
|
26
|
+
import org.json.JSONObject;
|
27
|
+
|
28
|
+
public class HttpRequestHandler {
|
29
|
+
|
30
|
+
/**
|
31
|
+
* An enum specifying conventional HTTP Response Types
|
32
|
+
* See https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/responseType
|
33
|
+
*/
|
34
|
+
public enum ResponseType {
|
35
|
+
ARRAY_BUFFER("arraybuffer"),
|
36
|
+
BLOB("blob"),
|
37
|
+
DOCUMENT("document"),
|
38
|
+
JSON("json"),
|
39
|
+
TEXT("text");
|
40
|
+
|
41
|
+
private final String name;
|
42
|
+
|
43
|
+
ResponseType(String name) {
|
44
|
+
this.name = name;
|
45
|
+
}
|
46
|
+
|
47
|
+
static final ResponseType DEFAULT = TEXT;
|
48
|
+
|
49
|
+
static ResponseType parse(String value) {
|
50
|
+
for (ResponseType responseType : values()) {
|
51
|
+
if (responseType.name.equalsIgnoreCase(value)) {
|
52
|
+
return responseType;
|
53
|
+
}
|
54
|
+
}
|
55
|
+
return DEFAULT;
|
56
|
+
}
|
57
|
+
}
|
58
|
+
|
59
|
+
/**
|
60
|
+
* Internal builder class for building a CapacitorHttpUrlConnection
|
61
|
+
*/
|
62
|
+
private static class HttpURLConnectionBuilder {
|
63
|
+
|
64
|
+
private Integer connectTimeout;
|
65
|
+
private Integer readTimeout;
|
66
|
+
private Boolean disableRedirects;
|
67
|
+
private JSObject headers;
|
68
|
+
private String method;
|
69
|
+
private URL url;
|
70
|
+
|
71
|
+
private CapacitorHttpUrlConnection connection;
|
72
|
+
|
73
|
+
public HttpURLConnectionBuilder setConnectTimeout(Integer connectTimeout) {
|
74
|
+
this.connectTimeout = connectTimeout;
|
75
|
+
return this;
|
76
|
+
}
|
77
|
+
|
78
|
+
public HttpURLConnectionBuilder setReadTimeout(Integer readTimeout) {
|
79
|
+
this.readTimeout = readTimeout;
|
80
|
+
return this;
|
81
|
+
}
|
82
|
+
|
83
|
+
public HttpURLConnectionBuilder setDisableRedirects(Boolean disableRedirects) {
|
84
|
+
this.disableRedirects = disableRedirects;
|
85
|
+
return this;
|
86
|
+
}
|
87
|
+
|
88
|
+
public HttpURLConnectionBuilder setHeaders(JSObject headers) {
|
89
|
+
this.headers = headers;
|
90
|
+
return this;
|
91
|
+
}
|
92
|
+
|
93
|
+
public HttpURLConnectionBuilder setMethod(String method) {
|
94
|
+
this.method = method;
|
95
|
+
return this;
|
96
|
+
}
|
97
|
+
|
98
|
+
public HttpURLConnectionBuilder setUrl(URL url) {
|
99
|
+
this.url = url;
|
100
|
+
return this;
|
101
|
+
}
|
102
|
+
|
103
|
+
public HttpURLConnectionBuilder openConnection() throws IOException {
|
104
|
+
connection = new CapacitorHttpUrlConnection((HttpURLConnection) url.openConnection());
|
105
|
+
|
106
|
+
connection.setAllowUserInteraction(false);
|
107
|
+
connection.setRequestMethod(method);
|
108
|
+
|
109
|
+
if (connectTimeout != null) connection.setConnectTimeout(connectTimeout);
|
110
|
+
if (readTimeout != null) connection.setReadTimeout(readTimeout);
|
111
|
+
if (disableRedirects != null) connection.setDisableRedirects(disableRedirects);
|
112
|
+
|
113
|
+
connection.setRequestHeaders(headers);
|
114
|
+
return this;
|
115
|
+
}
|
116
|
+
|
117
|
+
public HttpURLConnectionBuilder setUrlParams(JSObject params) throws MalformedURLException, URISyntaxException, JSONException {
|
118
|
+
return this.setUrlParams(params, true);
|
119
|
+
}
|
120
|
+
|
121
|
+
public HttpURLConnectionBuilder setUrlParams(JSObject params, boolean shouldEncode)
|
122
|
+
throws URISyntaxException, MalformedURLException {
|
123
|
+
String initialQuery = url.getQuery();
|
124
|
+
String initialQueryBuilderStr = initialQuery == null ? "" : initialQuery;
|
125
|
+
|
126
|
+
Iterator<String> keys = params.keys();
|
127
|
+
|
128
|
+
if (!keys.hasNext()) {
|
129
|
+
return this;
|
130
|
+
}
|
131
|
+
|
132
|
+
StringBuilder urlQueryBuilder = new StringBuilder(initialQueryBuilderStr);
|
133
|
+
|
134
|
+
// Build the new query string
|
135
|
+
while (keys.hasNext()) {
|
136
|
+
String key = keys.next();
|
137
|
+
|
138
|
+
// Attempt as JSONArray and fallback to string if it fails
|
139
|
+
try {
|
140
|
+
StringBuilder value = new StringBuilder();
|
141
|
+
JSONArray arr = params.getJSONArray(key);
|
142
|
+
for (int x = 0; x < arr.length(); x++) {
|
143
|
+
value.append(key).append("=").append(arr.getString(x));
|
144
|
+
if (x != arr.length() - 1) {
|
145
|
+
value.append("&");
|
146
|
+
}
|
147
|
+
}
|
148
|
+
if (urlQueryBuilder.length() > 0) {
|
149
|
+
urlQueryBuilder.append("&");
|
150
|
+
}
|
151
|
+
urlQueryBuilder.append(value);
|
152
|
+
} catch (JSONException e) {
|
153
|
+
if (urlQueryBuilder.length() > 0) {
|
154
|
+
urlQueryBuilder.append("&");
|
155
|
+
}
|
156
|
+
urlQueryBuilder.append(key).append("=").append(params.getString(key));
|
157
|
+
}
|
158
|
+
}
|
159
|
+
|
160
|
+
String urlQuery = urlQueryBuilder.toString();
|
161
|
+
|
162
|
+
URI uri = url.toURI();
|
163
|
+
if (shouldEncode) {
|
164
|
+
URI encodedUri = new URI(uri.getScheme(), uri.getAuthority(), uri.getPath(), urlQuery, uri.getFragment());
|
165
|
+
this.url = encodedUri.toURL();
|
166
|
+
} else {
|
167
|
+
String unEncodedUrlString = uri.getScheme() + "://" + uri.getAuthority() + uri.getPath() + ((!urlQuery.equals("")) ? "?" + urlQuery : "") + ((uri.getFragment() != null) ? uri.getFragment() : "");
|
168
|
+
this.url = new URL(unEncodedUrlString);
|
169
|
+
}
|
170
|
+
|
171
|
+
return this;
|
172
|
+
}
|
173
|
+
|
174
|
+
public CapacitorHttpUrlConnection build() {
|
175
|
+
return connection;
|
176
|
+
}
|
177
|
+
}
|
178
|
+
|
179
|
+
/**
|
180
|
+
* Builds an HTTP Response given CapacitorHttpUrlConnection and ResponseType objects.
|
181
|
+
* Defaults to ResponseType.DEFAULT
|
182
|
+
* @param connection The CapacitorHttpUrlConnection to respond with
|
183
|
+
* @throws IOException Thrown if the InputStream is unable to be parsed correctly
|
184
|
+
* @throws JSONException Thrown if the JSON is unable to be parsed
|
185
|
+
*/
|
186
|
+
private static JSObject buildResponse(CapacitorHttpUrlConnection connection) throws IOException, JSONException {
|
187
|
+
return buildResponse(connection, ResponseType.DEFAULT);
|
188
|
+
}
|
189
|
+
|
190
|
+
/**
|
191
|
+
* Builds an HTTP Response given CapacitorHttpUrlConnection and ResponseType objects
|
192
|
+
* @param connection The CapacitorHttpUrlConnection to respond with
|
193
|
+
* @param responseType The requested ResponseType
|
194
|
+
* @return A JSObject that contains the HTTPResponse to return to the browser
|
195
|
+
* @throws IOException Thrown if the InputStream is unable to be parsed correctly
|
196
|
+
* @throws JSONException Thrown if the JSON is unable to be parsed
|
197
|
+
*/
|
198
|
+
private static JSObject buildResponse(CapacitorHttpUrlConnection connection, ResponseType responseType)
|
199
|
+
throws IOException, JSONException {
|
200
|
+
int statusCode = connection.getResponseCode();
|
201
|
+
|
202
|
+
JSObject output = new JSObject();
|
203
|
+
output.put("status", statusCode);
|
204
|
+
output.put("headers", buildResponseHeaders(connection));
|
205
|
+
output.put("url", connection.getURL());
|
206
|
+
output.put("body", readData(connection, responseType));
|
207
|
+
|
208
|
+
InputStream errorStream = connection.getErrorStream();
|
209
|
+
if (errorStream != null) {
|
210
|
+
output.put("error", true);
|
211
|
+
}
|
212
|
+
|
213
|
+
return output;
|
214
|
+
}
|
215
|
+
|
216
|
+
/**
|
217
|
+
* Read the existing ICapacitorHttpUrlConnection data
|
218
|
+
* @param connection The ICapacitorHttpUrlConnection object to read in
|
219
|
+
* @param responseType The type of HTTP response to return to the API
|
220
|
+
* @return The parsed data from the connection
|
221
|
+
* @throws IOException Thrown if the InputStreams cannot be properly parsed
|
222
|
+
* @throws JSONException Thrown if the JSON is malformed when parsing as JSON
|
223
|
+
*/
|
224
|
+
static Object readData(ICapacitorHttpUrlConnection connection, ResponseType responseType) throws IOException, JSONException {
|
225
|
+
InputStream errorStream = connection.getErrorStream();
|
226
|
+
String contentType = connection.getHeaderField("Content-Type");
|
227
|
+
|
228
|
+
if (errorStream != null) {
|
229
|
+
if (isOneOf(contentType, MimeType.APPLICATION_JSON, MimeType.APPLICATION_VND_API_JSON)) {
|
230
|
+
return parseJSON(readStreamAsString(errorStream));
|
231
|
+
} else {
|
232
|
+
return readStreamAsString(errorStream);
|
233
|
+
}
|
234
|
+
} else if (contentType != null && contentType.contains(MimeType.APPLICATION_JSON.getValue())) {
|
235
|
+
// backward compatibility
|
236
|
+
return parseJSON(readStreamAsString(connection.getInputStream()));
|
237
|
+
} else {
|
238
|
+
InputStream stream = connection.getInputStream();
|
239
|
+
switch (responseType) {
|
240
|
+
case ARRAY_BUFFER:
|
241
|
+
case BLOB:
|
242
|
+
return readStreamAsBase64(stream);
|
243
|
+
case JSON:
|
244
|
+
return parseJSON(readStreamAsString(stream));
|
245
|
+
case DOCUMENT:
|
246
|
+
case TEXT:
|
247
|
+
default:
|
248
|
+
return readStreamAsString(stream);
|
249
|
+
}
|
250
|
+
}
|
251
|
+
}
|
252
|
+
|
253
|
+
/**
|
254
|
+
* Helper function for determining if the Content-Type is a typeof an existing Mime-Type
|
255
|
+
* @param contentType The Content-Type string to check for
|
256
|
+
* @param mimeTypes The Mime-Type values to check against
|
257
|
+
* @return
|
258
|
+
*/
|
259
|
+
private static boolean isOneOf(String contentType, MimeType... mimeTypes) {
|
260
|
+
if (contentType != null) {
|
261
|
+
for (MimeType mimeType : mimeTypes) {
|
262
|
+
if (contentType.contains(mimeType.getValue())) {
|
263
|
+
return true;
|
264
|
+
}
|
265
|
+
}
|
266
|
+
}
|
267
|
+
return false;
|
268
|
+
}
|
269
|
+
|
270
|
+
/**
|
271
|
+
* Build the JSObject response headers based on the connection header map
|
272
|
+
* @param connection The CapacitorHttpUrlConnection connection
|
273
|
+
* @return A JSObject of the header values from the CapacitorHttpUrlConnection
|
274
|
+
*/
|
275
|
+
private static JSObject buildResponseHeaders(CapacitorHttpUrlConnection connection) {
|
276
|
+
JSObject output = new JSObject();
|
277
|
+
|
278
|
+
for (Map.Entry<String, List<String>> entry : connection.getHeaderFields().entrySet()) {
|
279
|
+
String valuesString = TextUtils.join(", ", entry.getValue());
|
280
|
+
output.put(entry.getKey(), valuesString);
|
281
|
+
}
|
282
|
+
|
283
|
+
return output;
|
284
|
+
}
|
285
|
+
|
286
|
+
/**
|
287
|
+
* Returns a JSObject or a JSArray based on a string-ified input
|
288
|
+
* @param input String-ified JSON that needs parsing
|
289
|
+
* @return A JSObject or JSArray
|
290
|
+
* @throws JSONException thrown if the JSON is malformed
|
291
|
+
*/
|
292
|
+
private static Object parseJSON(String input) throws JSONException {
|
293
|
+
JSONObject json = new JSONObject();
|
294
|
+
try {
|
295
|
+
if ("null".equals(input.trim())) {
|
296
|
+
return JSONObject.NULL;
|
297
|
+
} else if ("true".equals(input.trim())) {
|
298
|
+
return new JSONObject().put("flag", "true");
|
299
|
+
} else if ("false".equals(input.trim())) {
|
300
|
+
return new JSONObject().put("flag", "false");
|
301
|
+
} else {
|
302
|
+
try {
|
303
|
+
return new JSObject(input);
|
304
|
+
} catch (JSONException e) {
|
305
|
+
return new JSArray(input);
|
306
|
+
}
|
307
|
+
}
|
308
|
+
} catch (JSONException e) {
|
309
|
+
return new JSArray(input);
|
310
|
+
}
|
311
|
+
}
|
312
|
+
|
313
|
+
/**
|
314
|
+
* Returns a string based on a base64 InputStream
|
315
|
+
* @param in The base64 InputStream to convert to a String
|
316
|
+
* @return String value of InputStream
|
317
|
+
* @throws IOException thrown if the InputStream is unable to be read as base64
|
318
|
+
*/
|
319
|
+
private static String readStreamAsBase64(InputStream in) throws IOException {
|
320
|
+
try (ByteArrayOutputStream out = new ByteArrayOutputStream()) {
|
321
|
+
byte[] buffer = new byte[1024];
|
322
|
+
int readBytes;
|
323
|
+
while ((readBytes = in.read(buffer)) != -1) {
|
324
|
+
out.write(buffer, 0, readBytes);
|
325
|
+
}
|
326
|
+
byte[] result = out.toByteArray();
|
327
|
+
return Base64.encodeToString(result, 0, result.length, Base64.DEFAULT);
|
328
|
+
}
|
329
|
+
}
|
330
|
+
|
331
|
+
/**
|
332
|
+
* Returns a string based on an InputStream
|
333
|
+
* @param in The InputStream to convert to a String
|
334
|
+
* @return String value of InputStream
|
335
|
+
* @throws IOException thrown if the InputStream is unable to be read
|
336
|
+
*/
|
337
|
+
private static String readStreamAsString(InputStream in) throws IOException {
|
338
|
+
try (BufferedReader reader = new BufferedReader(new InputStreamReader(in))) {
|
339
|
+
StringBuilder builder = new StringBuilder();
|
340
|
+
String line = reader.readLine();
|
341
|
+
while (line != null) {
|
342
|
+
builder.append(line);
|
343
|
+
line = reader.readLine();
|
344
|
+
if (line != null) {
|
345
|
+
builder.append(System.getProperty("line.separator"));
|
346
|
+
}
|
347
|
+
}
|
348
|
+
return builder.toString();
|
349
|
+
}
|
350
|
+
}
|
351
|
+
|
352
|
+
/**
|
353
|
+
* Makes an Http Request based on the PluginCall parameters
|
354
|
+
* @param call The Capacitor PluginCall that contains the options need for an Http request
|
355
|
+
* @param httpMethod The HTTP method that overrides the PluginCall HTTP method
|
356
|
+
* @throws IOException throws an IO request when a connection can't be made
|
357
|
+
* @throws URISyntaxException thrown when the URI is malformed
|
358
|
+
* @throws JSONException thrown when the incoming JSON is malformed
|
359
|
+
*/
|
360
|
+
public static JSObject request(PluginCall call, String httpMethod) throws IOException, URISyntaxException, JSONException {
|
361
|
+
String urlString = call.getString("url", "");
|
362
|
+
JSObject headers = call.getObject("headers");
|
363
|
+
JSObject params = call.getObject("params");
|
364
|
+
Integer connectTimeout = call.getInt("connectTimeout");
|
365
|
+
Integer readTimeout = call.getInt("readTimeout");
|
366
|
+
Boolean disableRedirects = call.getBoolean("disableRedirects");
|
367
|
+
Boolean shouldEncode = call.getBoolean("shouldEncodeUrlParams", true);
|
368
|
+
ResponseType responseType = ResponseType.parse(call.getString("responseType"));
|
369
|
+
|
370
|
+
String method = httpMethod != null ? httpMethod.toUpperCase() : call.getString("method", "").toUpperCase();
|
371
|
+
|
372
|
+
boolean isHttpMutate = method.equals("DELETE") || method.equals("PATCH") || method.equals("POST") || method.equals("PUT");
|
373
|
+
|
374
|
+
URL url = new URL(urlString);
|
375
|
+
HttpURLConnectionBuilder connectionBuilder = new HttpURLConnectionBuilder()
|
376
|
+
.setUrl(url)
|
377
|
+
.setMethod(method)
|
378
|
+
.setHeaders(headers)
|
379
|
+
.setUrlParams(params, shouldEncode)
|
380
|
+
.setConnectTimeout(connectTimeout)
|
381
|
+
.setReadTimeout(readTimeout)
|
382
|
+
.setDisableRedirects(disableRedirects)
|
383
|
+
.openConnection();
|
384
|
+
|
385
|
+
CapacitorHttpUrlConnection connection = connectionBuilder.build();
|
386
|
+
|
387
|
+
// Set HTTP body on a non GET or HEAD request
|
388
|
+
if (isHttpMutate) {
|
389
|
+
JSValue data = new JSValue(call, "body");
|
390
|
+
if (data.getValue() != null) {
|
391
|
+
connection.setDoOutput(true);
|
392
|
+
connection.setRequestBody(call, data);
|
393
|
+
}
|
394
|
+
}
|
395
|
+
|
396
|
+
connection.connect();
|
397
|
+
|
398
|
+
return buildResponse(connection, responseType);
|
399
|
+
}
|
400
|
+
|
401
|
+
/**
|
402
|
+
* Makes an Http Request to download a file based on the PluginCall parameters
|
403
|
+
* @param call The Capacitor PluginCall that contains the options need for an Http request
|
404
|
+
* @param context The Android Context required for writing to the filesystem
|
405
|
+
* @param progress The emitter which notifies listeners on downloading progression
|
406
|
+
* @throws IOException throws an IO request when a connection can't be made
|
407
|
+
* @throws URISyntaxException thrown when the URI is malformed
|
408
|
+
*/
|
409
|
+
public static JSObject downloadFile(PluginCall call, Context context, ProgressEmitter progress)
|
410
|
+
throws IOException, URISyntaxException, JSONException {
|
411
|
+
String urlString = call.getString("url");
|
412
|
+
String method = call.getString("method", "GET").toUpperCase();
|
413
|
+
String filePath = call.getString("filePath");
|
414
|
+
String fileDirectory = call.getString("fileDirectory", FilesystemUtils.DIRECTORY_DOCUMENTS);
|
415
|
+
JSObject headers = call.getObject("headers");
|
416
|
+
JSObject params = call.getObject("params");
|
417
|
+
Integer connectTimeout = call.getInt("connectTimeout");
|
418
|
+
Integer readTimeout = call.getInt("readTimeout");
|
419
|
+
|
420
|
+
final URL url = new URL(urlString);
|
421
|
+
final File file = FilesystemUtils.getFileObject(context, filePath, fileDirectory);
|
422
|
+
|
423
|
+
HttpURLConnectionBuilder connectionBuilder = new HttpURLConnectionBuilder()
|
424
|
+
.setUrl(url)
|
425
|
+
.setMethod(method)
|
426
|
+
.setHeaders(headers)
|
427
|
+
.setUrlParams(params)
|
428
|
+
.setConnectTimeout(connectTimeout)
|
429
|
+
.setReadTimeout(readTimeout)
|
430
|
+
.openConnection();
|
431
|
+
|
432
|
+
ICapacitorHttpUrlConnection connection = connectionBuilder.build();
|
433
|
+
InputStream connectionInputStream = connection.getInputStream();
|
434
|
+
|
435
|
+
FileOutputStream fileOutputStream = new FileOutputStream(file, false);
|
436
|
+
|
437
|
+
String contentLength = connection.getHeaderField("content-length");
|
438
|
+
int bytes = 0;
|
439
|
+
int maxBytes = 0;
|
440
|
+
|
441
|
+
try {
|
442
|
+
maxBytes = contentLength != null ? Integer.parseInt(contentLength) : 0;
|
443
|
+
} catch (NumberFormatException e) {
|
444
|
+
maxBytes = 0;
|
445
|
+
}
|
446
|
+
|
447
|
+
byte[] buffer = new byte[1024];
|
448
|
+
int len;
|
449
|
+
|
450
|
+
while ((len = connectionInputStream.read(buffer)) > 0) {
|
451
|
+
fileOutputStream.write(buffer, 0, len);
|
452
|
+
|
453
|
+
bytes += len;
|
454
|
+
progress.emit(bytes, maxBytes);
|
455
|
+
}
|
456
|
+
|
457
|
+
connectionInputStream.close();
|
458
|
+
fileOutputStream.close();
|
459
|
+
|
460
|
+
return new JSObject() {
|
461
|
+
{
|
462
|
+
put("path", file.getAbsolutePath());
|
463
|
+
}
|
464
|
+
};
|
465
|
+
}
|
466
|
+
|
467
|
+
/**
|
468
|
+
* Makes an Http Request to upload a file based on the PluginCall parameters
|
469
|
+
* @param call The Capacitor PluginCall that contains the options need for an Http request
|
470
|
+
* @param context The Android Context required for writing to the filesystem
|
471
|
+
* @throws IOException throws an IO request when a connection can't be made
|
472
|
+
* @throws URISyntaxException thrown when the URI is malformed
|
473
|
+
* @throws JSONException thrown when malformed JSON is passed into the function
|
474
|
+
*/
|
475
|
+
public static JSObject uploadFile(PluginCall call, Context context) throws IOException, URISyntaxException, JSONException {
|
476
|
+
String urlString = call.getString("url");
|
477
|
+
String method = call.getString("method", "POST").toUpperCase();
|
478
|
+
String filePath = call.getString("filePath");
|
479
|
+
String fileDirectory = call.getString("fileDirectory", FilesystemUtils.DIRECTORY_DOCUMENTS);
|
480
|
+
String name = call.getString("name", "file");
|
481
|
+
Integer connectTimeout = call.getInt("connectTimeout");
|
482
|
+
Integer readTimeout = call.getInt("readTimeout");
|
483
|
+
JSObject headers = call.getObject("headers");
|
484
|
+
JSObject params = call.getObject("params");
|
485
|
+
JSObject data = call.getObject("data");
|
486
|
+
ResponseType responseType = ResponseType.parse(call.getString("responseType"));
|
487
|
+
|
488
|
+
URL url = new URL(urlString);
|
489
|
+
|
490
|
+
File file = FilesystemUtils.getFileObject(context, filePath, fileDirectory);
|
491
|
+
|
492
|
+
HttpURLConnectionBuilder connectionBuilder = new HttpURLConnectionBuilder()
|
493
|
+
.setUrl(url)
|
494
|
+
.setMethod(method)
|
495
|
+
.setHeaders(headers)
|
496
|
+
.setUrlParams(params)
|
497
|
+
.setConnectTimeout(connectTimeout)
|
498
|
+
.setReadTimeout(readTimeout)
|
499
|
+
.openConnection();
|
500
|
+
|
501
|
+
CapacitorHttpUrlConnection connection = connectionBuilder.build();
|
502
|
+
connection.setDoOutput(true);
|
503
|
+
|
504
|
+
FormUploader builder = new FormUploader(connection.getHttpConnection());
|
505
|
+
builder.addFilePart(name, file, data);
|
506
|
+
builder.finish();
|
507
|
+
|
508
|
+
return buildResponse(connection, responseType);
|
509
|
+
}
|
510
|
+
|
511
|
+
@FunctionalInterface
|
512
|
+
public interface ProgressEmitter {
|
513
|
+
void emit(Integer bytes, Integer contentLength);
|
514
|
+
}
|
515
|
+
}
|
@@ -0,0 +1,15 @@
|
|
1
|
+
package org.thiragatisoft.core.http;
|
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
|
+
interface ICapacitorHttpUrlConnection {
|
10
|
+
InputStream getErrorStream();
|
11
|
+
|
12
|
+
String getHeaderField(String name);
|
13
|
+
|
14
|
+
InputStream getInputStream() throws IOException;
|
15
|
+
}
|
@@ -0,0 +1,68 @@
|
|
1
|
+
package org.thiragatisoft.core.http;
|
2
|
+
|
3
|
+
import com.getcapacitor.JSArray;
|
4
|
+
import com.getcapacitor.JSObject;
|
5
|
+
import com.getcapacitor.PluginCall;
|
6
|
+
import org.json.JSONException;
|
7
|
+
|
8
|
+
/**
|
9
|
+
* Represents a single user-data value of any type on the capacitor PluginCall object.
|
10
|
+
*/
|
11
|
+
public class JSValue {
|
12
|
+
|
13
|
+
private final Object value;
|
14
|
+
|
15
|
+
/**
|
16
|
+
* @param call The capacitor plugin call, used for accessing the value safely.
|
17
|
+
* @param name The name of the property to access.
|
18
|
+
*/
|
19
|
+
public JSValue(PluginCall call, String name) {
|
20
|
+
this.value = this.toValue(call, name);
|
21
|
+
}
|
22
|
+
|
23
|
+
/**
|
24
|
+
* Returns the coerced but uncasted underlying value.
|
25
|
+
*/
|
26
|
+
public Object getValue() {
|
27
|
+
return this.value;
|
28
|
+
}
|
29
|
+
|
30
|
+
@Override
|
31
|
+
public String toString() {
|
32
|
+
return this.getValue().toString();
|
33
|
+
}
|
34
|
+
|
35
|
+
/**
|
36
|
+
* Returns the underlying value as a JSObject, or throwing if it cannot.
|
37
|
+
*
|
38
|
+
* @throws JSONException If the underlying value is not a JSObject.
|
39
|
+
*/
|
40
|
+
public JSObject toJSObject() throws JSONException {
|
41
|
+
if (this.value instanceof JSObject) return (JSObject) this.value;
|
42
|
+
throw new JSONException("JSValue could not be coerced to JSObject.");
|
43
|
+
}
|
44
|
+
|
45
|
+
/**
|
46
|
+
* Returns the underlying value as a JSArray, or throwing if it cannot.
|
47
|
+
*
|
48
|
+
* @throws JSONException If the underlying value is not a JSArray.
|
49
|
+
*/
|
50
|
+
public JSArray toJSArray() throws JSONException {
|
51
|
+
if (this.value instanceof JSArray) return (JSArray) this.value;
|
52
|
+
throw new JSONException("JSValue could not be coerced to JSArray.");
|
53
|
+
}
|
54
|
+
|
55
|
+
/**
|
56
|
+
* Returns the underlying value this object represents, coercing it into a capacitor-friendly object if supported.
|
57
|
+
*/
|
58
|
+
private Object toValue(PluginCall call, String name) {
|
59
|
+
Object value = null;
|
60
|
+
value = call.getArray(name, null);
|
61
|
+
if (value != null) return value;
|
62
|
+
value = call.getObject(name, null);
|
63
|
+
if (value != null) return value;
|
64
|
+
value = call.getString(name, null);
|
65
|
+
if (value != null) return value;
|
66
|
+
return call.getData().opt(name);
|
67
|
+
}
|
68
|
+
}
|
@@ -0,0 +1,17 @@
|
|
1
|
+
package org.thiragatisoft.core.http;
|
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,12 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<module type="JAVA_MODULE" version="4">
|
3
|
+
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
4
|
+
<exclude-output />
|
5
|
+
<content url="file://$MODULE_DIR$">
|
6
|
+
<sourceFolder url="file://$MODULE_DIR$/java" isTestSource="false" />
|
7
|
+
</content>
|
8
|
+
<orderEntry type="inheritedJdk" />
|
9
|
+
<orderEntry type="sourceFolder" forTests="false" />
|
10
|
+
<orderEntry type="module" module-name="test" />
|
11
|
+
</component>
|
12
|
+
</module>
|
@@ -0,0 +1,17 @@
|
|
1
|
+
package com.getcapacitor;
|
2
|
+
|
3
|
+
import org.junit.Test;
|
4
|
+
|
5
|
+
import static org.junit.Assert.*;
|
6
|
+
|
7
|
+
/**
|
8
|
+
* Example local unit test, which will execute on the development machine (host).
|
9
|
+
*
|
10
|
+
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
|
11
|
+
*/
|
12
|
+
public class ExampleUnitTest {
|
13
|
+
@Test
|
14
|
+
public void addition_isCorrect() throws Exception {
|
15
|
+
assertEquals(4, 2 + 2);
|
16
|
+
}
|
17
|
+
}
|