Created
November 26, 2022 17:27
-
-
Save vladimir-anisimov/3a2090257f4a74ad991e22bf12acecec to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
extension URLRequest { | |
/** | |
Configures the URL request for `multipart/form-data`. The request's `httpBody` is set, and a value is set for the HTTP header field `Content-Type`. | |
- Parameter parameters: The form data to set. | |
- Parameter encoding: The encoding to use for the keys and values. | |
- Throws: `MultipartFormDataEncodingError` if any keys or values in `parameters` are not entirely in `encoding`. | |
- Note: The default `httpMethod` is `GET`, and `GET` requests do not typically have a response body. Remember to set the `httpMethod` to e.g. `POST` before sending the request. | |
- Seealso: https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#multipart-form-data | |
*/ | |
public mutating func setMultipartFormData(_ parameters: [String: String], encoding: String.Encoding) throws { | |
let makeRandom = { UInt32.random(in: (.min)...(.max)) } | |
let boundary = String(format: "------------------------%08X%08X", makeRandom(), makeRandom()) | |
let contentType: String = try { | |
guard let charset = CFStringConvertEncodingToIANACharSetName(CFStringConvertNSStringEncodingToEncoding(encoding.rawValue)) else { | |
throw MultipartFormDataEncodingError.characterSetName | |
} | |
return "multipart/form-data; charset=\(charset); boundary=\(boundary)" | |
}() | |
addValue(contentType, forHTTPHeaderField: "Content-Type") | |
httpBody = try { | |
var body = Data() | |
for (rawName, rawValue) in parameters { | |
if !body.isEmpty { | |
body.append("\r\n".data(using: .utf8)!) | |
} | |
body.append("--\(boundary)\r\n".data(using: .utf8)!) | |
guard | |
rawName.canBeConverted(to: encoding), | |
let disposition = "Content-Disposition: form-data; name=\"\(rawName)\"\r\n".data(using: encoding) else { | |
throw MultipartFormDataEncodingError.name(rawName) | |
} | |
body.append(disposition) | |
body.append("\r\n".data(using: .utf8)!) | |
guard let value = rawValue.data(using: encoding) else { | |
throw MultipartFormDataEncodingError.value(rawValue, name: rawName) | |
} | |
body.append(value) | |
} | |
body.append("\r\n--\(boundary)--\r\n".data(using: .utf8)!) | |
return body | |
}() | |
} | |
} | |
public enum MultipartFormDataEncodingError: Error { | |
case characterSetName | |
case name(String) | |
case value(String, name: String) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment