Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@nolanw
Last active October 5, 2023 14:31
Show Gist options
  • Star 25 You must be signed in to star a gist
  • Fork 4 You must be signed in to fork a gist
  • Save nolanw/dff7cc5d5570b030d6ba385698348b7c to your computer and use it in GitHub Desktop.
Save nolanw/dff7cc5d5570b030d6ba385698348b7c to your computer and use it in GitHub Desktop.
Swift multipart/form-data
// Public domain - https://gist.github.com/nolanw/dff7cc5d5570b030d6ba385698348b7c
import Foundation
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)
}
@srikanth-vm
Copy link

👏

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment