Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix boundary value extraction for form-data requests #7518

Open
wants to merge 9 commits into
base: main
Choose a base branch
from
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,7 @@ private void writeObjectRequestBody(JSObject object) throws IOException, JSONExc

private void writeFormDataRequestBody(String contentType, JSArray entries) throws IOException, JSONException {
try (DataOutputStream os = new DataOutputStream(connection.getOutputStream())) {
String boundary = contentType.split(";")[1].split("=")[1];
String boundary = extractBoundary(contentType);
michaelwolz marked this conversation as resolved.
Show resolved Hide resolved
String lineEnd = "\r\n";
String twoHyphens = "--";

Expand Down Expand Up @@ -301,6 +301,39 @@ private void writeFormDataRequestBody(String contentType, JSArray entries) throw
}
}

/**
* Extracts the boundary value from the `Content-Type` header for multipart/form-data requests, if provided.
*
* The boundary value might be surrounded by double quotes (") which will be stripped away.
*
* @param contentType The `Content-Type` header string.
* @return The boundary value if found, otherwise `null`.
*/
public static String extractBoundary(String contentType) {
String boundaryPrefix = "boundary=";
int boundaryIndex = contentType.indexOf(boundaryPrefix);
if (boundaryIndex == -1) {
return null;
}

// Extract the substring starting right after "boundary="
String boundary = contentType.substring(boundaryIndex + boundaryPrefix.length());

// Find the end of the boundary value by looking for the next ";"
int endIndex = boundary.indexOf(";");
if (endIndex != -1) {
boundary = boundary.substring(0, endIndex);
}

// Remove surrounding double quotes if present
boundary = boundary.trim();
if (boundary.startsWith("\"") && boundary.endsWith("\"")) {
boundary = boundary.substring(1, boundary.length() - 1);
}

return boundary;
}

/**
* Opens a communications link to the resource referenced by this
* URL, if such a connection has not already been established.
Expand Down
25 changes: 23 additions & 2 deletions ios/Capacitor/Capacitor/Plugins/CapacitorUrlRequest.swift
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ open class CapacitorUrlRequest: NSObject, URLSessionTaskDelegate {

var data = Data()
var boundary = UUID().uuidString
if contentType.contains("="), let contentBoundary = contentType.components(separatedBy: "=").last {
if contentType.contains("boundary="), let contentBoundary = extractBoundary(from: contentType) {
boundary = contentBoundary
} else {
overrideContentType(boundary)
Expand All @@ -83,6 +83,27 @@ open class CapacitorUrlRequest: NSObject, URLSessionTaskDelegate {
request.setValue(contentType, forHTTPHeaderField: "Content-Type")
headers["Content-Type"] = contentType
}

/**
Extracts the boundary value of the `content-type` header for multiplart/form-data requests, if provided
The boundary value might be surrounded by double quotes (") which will be stripped away.
*/
private func extractBoundary(from contentType: String) -> String? {
if let boundaryRange = contentType.range(of: "boundary=") {
var boundary = contentType[boundaryRange.upperBound...]
if let endRange = boundary.range(of: ";") {
boundary = boundary[..<endRange.lowerBound]
}

if boundary.hasPrefix("\"") && boundary.hasSuffix("\"") {
return String(boundary.dropFirst().dropLast())
} else {
return String(boundary)
}
}

return nil
}

public func getRequestDataAsString(_ data: JSValue) throws -> Data {
guard let stringData = data as? String else {
Expand All @@ -107,7 +128,7 @@ open class CapacitorUrlRequest: NSObject, URLSessionTaskDelegate {
}
var data = Data()
var boundary = UUID().uuidString
if contentType.contains("="), let contentBoundary = contentType.components(separatedBy: "=").last {
if contentType.contains("boundary="), let contentBoundary = extractBoundary(from: contentType) {
boundary = contentBoundary
} else {
overrideContentType(boundary)
Expand Down