Forked from nolanw/URLRequest+MultipartFormData.swift
Created
April 16, 2019 14:34
-
-
Save vladimir-bebeshko/7c098116957f4fdb50e9146dca7078a4 to your computer and use it in GitHub Desktop.
Swift multipart/form-data
This file contains 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
// 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) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment