diff --git a/android/src/main/java/com/getcapacitor/plugin/http/FormUploader.java b/android/src/main/java/com/getcapacitor/plugin/http/FormUploader.java index e9a4714f..ad8d72b5 100644 --- a/android/src/main/java/com/getcapacitor/plugin/http/FormUploader.java +++ b/android/src/main/java/com/getcapacitor/plugin/http/FormUploader.java @@ -96,7 +96,7 @@ private void appendFieldToWriter(String name, String value) { * @param uploadFile a File to be uploaded * @throws IOException Thrown if unable to parse the OutputStream of the connection */ - public void addFilePart(String fieldName, File uploadFile, JSObject data) throws IOException { + public void addFilePart(String fieldName, File uploadFile, JSObject data, JSObject metadata) throws IOException { String fileName = uploadFile.getName(); prWriter .append(LINE_FEED) @@ -108,9 +108,25 @@ public void addFilePart(String fieldName, File uploadFile, JSObject data) throws .append("\"; filename=\"") .append(fileName) .append("\"") - .append(LINE_FEED) + .append(LINE_FEED); + + if (metadata != null) { + prWriter + .append("Content-Type: application/json; charset=UTF-8") + .append(LINE_FEED) + .append(LINE_FEED) + .append(metadata.toString()) + .append(LINE_FEED) + .append("--") + .append(boundary) + .append(LINE_FEED); + } + + String contentType = URLConnection.guessContentTypeFromName(fileName); + + prWriter .append("Content-Type: ") - .append(URLConnection.guessContentTypeFromName(fileName)) + .append(contentType != null ? contentType : "application/octet-stream") .append(LINE_FEED) .append(LINE_FEED); prWriter.flush(); 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..4e56caab 100644 --- a/android/src/main/java/com/getcapacitor/plugin/http/HttpRequestHandler.java +++ b/android/src/main/java/com/getcapacitor/plugin/http/HttpRequestHandler.java @@ -486,6 +486,7 @@ public static JSObject uploadFile(PluginCall call, Context context) throws IOExc JSObject headers = call.getObject("headers"); JSObject params = call.getObject("params"); JSObject data = call.getObject("data"); + JSObject metadata = call.getObject("metadata"); ResponseType responseType = ResponseType.parse(call.getString("responseType")); URL url = new URL(urlString); @@ -505,7 +506,7 @@ public static JSObject uploadFile(PluginCall call, Context context) throws IOExc connection.setDoOutput(true); FormUploader builder = new FormUploader(connection.getHttpConnection()); - builder.addFilePart(name, file, data); + builder.addFilePart(name, file, data, metadata); builder.finish(); return buildResponse(connection, responseType); diff --git a/ios/Plugin/HttpRequestHandler.swift b/ios/Plugin/HttpRequestHandler.swift index d3d5f26d..4aedabff 100644 --- a/ios/Plugin/HttpRequestHandler.swift +++ b/ios/Plugin/HttpRequestHandler.swift @@ -122,7 +122,7 @@ class HttpRequestHandler { return output } - private static func generateMultipartForm(_ url: URL, _ name: String, _ boundary: String, _ body: [String:Any]) throws -> Data { + private static func generateMultipartForm(_ url: URL, _ name: String, _ boundary: String, _ body: [String: Any], _ metadata: [String: Any]) throws -> Data { let strings: [String: String] = body.compactMapValues { any in any as? String } @@ -137,6 +137,15 @@ class HttpRequestHandler { data.append( "Content-Disposition: form-data; name=\"\(name)\"; filename=\"\(fname)\"\r\n".data( using: .utf8)!) + + if (metadata.count != 0) { + let jsonData = try JSONSerialization.data(withJSONObject: metadata, options: .prettyPrinted) + let jsonString = String(data: jsonData, encoding: String.Encoding.utf8) ?? "" + data.append("Content-Type: application/json; charset=UTF-8\r\n\r\n".data(using: .utf8)!) + data.append(jsonString.data(using: .utf8)!) + data.append("\r\n--\(boundary)\r\n".data(using: .utf8)!) + } + data.append("Content-Type: \(mimeType)\r\n\r\n".data(using: .utf8)!) data.append(fileData) strings.forEach { key, value in @@ -206,6 +215,7 @@ class HttpRequestHandler { let headers = (call.getObject("headers") ?? [:]) as! [String: String] let params = (call.getObject("params") ?? [:]) as! [String: Any] let body = (call.getObject("data") ?? [:]) as [String: Any] + let metadata = (call.getObject("metadata") ?? [:]) as [String: Any] let responseType = call.getString("responseType") ?? "text"; let connectTimeout = call.getDouble("connectTimeout"); let readTimeout = call.getDouble("readTimeout"); @@ -230,7 +240,7 @@ class HttpRequestHandler { let boundary = UUID().uuidString request.setContentType("multipart/form-data; boundary=\(boundary)"); - guard let form = try? generateMultipartForm(fileUrl, name, boundary, body) else { throw URLError(.cannotCreateFile) } + guard let form = try? generateMultipartForm(fileUrl, name, boundary, body, metadata) else { throw URLError(.cannotCreateFile) } let urlRequest = request.getUrlRequest(); let task = URLSession.shared.uploadTask(with: urlRequest, from: form) { (data, response, error) in diff --git a/src/definitions.ts b/src/definitions.ts index 649cc088..8f1bbf16 100644 --- a/src/definitions.ts +++ b/src/definitions.ts @@ -124,6 +124,10 @@ export interface HttpUploadFileOptions extends HttpOptions { * If this option is used, filePath can be a relative path rather than absolute */ fileDirectory?: Directory; + /** + * Optionally, the metadata that come along with the file + */ + metadata?: any; } export interface HttpCookie {