diff --git a/android/src/main/java/com/getcapacitor/plugin/http/CapacitorHttpUrlConnection.java b/android/src/main/java/com/getcapacitor/plugin/http/CapacitorHttpUrlConnection.java index f4170856..3dfb0c70 100644 --- a/android/src/main/java/com/getcapacitor/plugin/http/CapacitorHttpUrlConnection.java +++ b/android/src/main/java/com/getcapacitor/plugin/http/CapacitorHttpUrlConnection.java @@ -16,6 +16,7 @@ import java.net.URLEncoder; import java.net.UnknownServiceException; import java.nio.charset.StandardCharsets; +import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Locale; @@ -215,7 +216,20 @@ public void setRequestBody(PluginCall call, JSValue body) throws JSONException, } uploader.finish(); } else { - this.writeRequestBody(body.toString()); + JSObject obj = new JSObject(body.toString()); + Iterator keys = obj.keys(); + + List data = new ArrayList<>(); + while (keys.hasNext()) { + data.add((byte)obj.getInt(keys.next())); + } + + byte[] bytes = new byte[data.size()]; + for (int i = 0; i < bytes.length; i++) { + bytes[i] = data.get(i); + } + + this.writeRequestBody(bytes); } } @@ -231,6 +245,18 @@ private void writeRequestBody(String body) throws IOException { } } + /** + * Writes the provided bytes to the HTTP connection managed by this instance. + * + * @param body The bytes to write to the connection stream. + */ + private void writeRequestBody(byte[] body) throws IOException { + try (DataOutputStream os = new DataOutputStream(connection.getOutputStream())) { + os.write(body); + os.flush(); + } + } + /** * Opens a communications link to the resource referenced by this * URL, if such a connection has not already been established. diff --git a/android/src/main/java/com/getcapacitor/plugin/http/HttpRequestHandler.java b/android/src/main/java/com/getcapacitor/plugin/http/HttpRequestHandler.java index 215beb51..fce4e880 100644 --- a/android/src/main/java/com/getcapacitor/plugin/http/HttpRequestHandler.java +++ b/android/src/main/java/com/getcapacitor/plugin/http/HttpRequestHandler.java @@ -393,6 +393,12 @@ public static JSObject request(PluginCall call, String httpMethod) throws IOExce if (data.getValue() != null) { connection.setDoOutput(true); connection.setRequestBody(call, data); + } else { + JSValue webFetchExtraData = new JSValue(call, "webFetchExtra", "body"); + if (webFetchExtraData.getValue() != null) { + connection.setDoOutput(true); + connection.setRequestBody(call, webFetchExtraData); + } } } diff --git a/android/src/main/java/com/getcapacitor/plugin/http/JSValue.java b/android/src/main/java/com/getcapacitor/plugin/http/JSValue.java index dd27cfb9..28a0882e 100644 --- a/android/src/main/java/com/getcapacitor/plugin/http/JSValue.java +++ b/android/src/main/java/com/getcapacitor/plugin/http/JSValue.java @@ -14,10 +14,10 @@ public class JSValue { /** * @param call The capacitor plugin call, used for accessing the value safely. - * @param name The name of the property to access. + * @param names The names of the property to access. */ - public JSValue(PluginCall call, String name) { - this.value = this.toValue(call, name); + public JSValue(PluginCall call, String... names) { + this.value = this.toValue(call, names); } /** @@ -55,14 +55,19 @@ public JSArray toJSArray() throws JSONException { /** * Returns the underlying value this object represents, coercing it into a capacitor-friendly object if supported. */ - private Object toValue(PluginCall call, String name) { - Object value = null; - value = call.getArray(name, null); - if (value != null) return value; - value = call.getObject(name, null); - if (value != null) return value; - value = call.getString(name, null); - if (value != null) return value; - return call.getData().opt(name); + private Object toValue(PluginCall call, String... names) { + Object retValue = null; + for (String name : names) { + Object value; + value = call.getArray(name, null); + if (value != null) return value; + retValue = retValue == null ? call.getObject(name, null) : ((JSObject)retValue).opt(name); + if (retValue != null) continue; + value = call.getString(name, null); + if (value != null) return value; + value = call.getData().opt(name); + if (value != null) return value; + } + return retValue; } } diff --git a/ios/Plugin/CapacitorUrlRequest.swift b/ios/Plugin/CapacitorUrlRequest.swift index ac846d1a..3a64dfee 100644 --- a/ios/Plugin/CapacitorUrlRequest.swift +++ b/ios/Plugin/CapacitorUrlRequest.swift @@ -85,6 +85,22 @@ public class CapacitorUrlRequest: NSObject, URLSessionTaskDelegate { } return Data(stringData.utf8) } + + private func getRequestDataAsRaw(_ data: JSValue) throws -> Data? { + guard let obj = data as? JSObject else { + throw CapacitorUrlRequestError.serializationError("[ data ] argument could not be parsed as raw data") + } + let strings: [String: Int] = obj.compactMapValues { any in + any as? Int + } + + var raw = [UInt8](repeating: 0, count: strings.keys.count) + strings.forEach { key, value in + raw[Int(key) ?? 0] = UInt8(value) + } + + return Data(raw) + } func getRequestHeader(_ index: String) -> Any? { var normalized = [:] as [String:Any] @@ -105,9 +121,8 @@ public class CapacitorUrlRequest: NSObject, URLSessionTaskDelegate { return try getRequestDataAsFormUrlEncoded(body) } else if contentType.contains("multipart/form-data") { return try getRequestDataAsMultipartFormData(body) - } else { - throw CapacitorUrlRequestError.serializationError("[ data ] argument could not be parsed for content type [ \(contentType) ]") } + return try getRequestDataAsRaw(body); } public func setRequestHeaders(_ headers: [String: String]) { diff --git a/ios/Plugin/HttpRequestHandler.swift b/ios/Plugin/HttpRequestHandler.swift index d3d5f26d..8a67fe6f 100644 --- a/ios/Plugin/HttpRequestHandler.swift +++ b/ios/Plugin/HttpRequestHandler.swift @@ -159,6 +159,7 @@ class HttpRequestHandler { let responseType = call.getString("responseType") ?? "text"; let connectTimeout = call.getDouble("connectTimeout"); let readTimeout = call.getDouble("readTimeout"); + let extra = (call.getObject("webFetchExtra") ?? [:]) as! [String: Any] let request = try! CapacitorHttpRequestBuilder() .setUrl(urlString) @@ -173,7 +174,7 @@ class HttpRequestHandler { let timeout = (connectTimeout ?? readTimeout ?? 600000.0) / 1000.0; request.setTimeout(timeout) - if let data = call.options["data"] as? JSValue { + if let data = (call.options["data"] ?? extra["body"]) as? JSValue { do { try request.setRequestBody(data) } catch {