Last active
May 11, 2023 20:38
-
-
Save nolanw/14b277903a2ba446f75202a6bfd55977 to your computer and use it in GitHub Desktop.
Swift x-www-form-urlencoded
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/14b277903a2ba446f75202a6bfd55977 | |
import Foundation | |
extension URLRequest { | |
/** | |
Configures the URL request for `application/x-www-form-urlencoded` data. The request's `httpBody` is set, and values are set for HTTP header fields `Content-Type` and `Content-Length`. | |
- Parameter queryItems: The (name, value) pairs to encode and set as the request's body. | |
- Note: The default `httpMethod` is `GET`, and `GET` requests do not typically have a body. Remember to set the `httpMethod` to e.g. `POST` before sending the request. | |
- Warning: It is a programmer error if any name or value in `queryItems` contains an unpaired UTF-16 surrogate. | |
*/ | |
mutating func setFormURLEncoded(_ queryItems: [URLQueryItem]) { | |
setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type") | |
func serialize(_ s: String) -> String { | |
return s | |
// Force-unwrapping because only known failure case is unpaired surrogate, which we've documented above as an error. | |
.addingPercentEncoding(withAllowedCharacters: formURLEncodedAllowedCharacters)! | |
.replacingOccurrences(of: " ", with: "+") | |
} | |
// https://url.spec.whatwg.org/#concept-urlencoded-serializer | |
let output = queryItems.lazy | |
.map { ($0.name, $0.value ?? "") } | |
.map { (serialize($0), serialize($1)) } | |
.map { "\($0)=\($1)" } | |
.joined(separator: "&") | |
let data = output.data(using: .utf8) | |
httpBody = data | |
if let contentLength = data?.count { | |
setValue(String(contentLength), forHTTPHeaderField: "Content-Length") | |
} | |
} | |
} | |
private let formURLEncodedAllowedCharacters: CharacterSet = { | |
typealias c = UnicodeScalar | |
// https://url.spec.whatwg.org/#urlencoded-serializing | |
var allowed = CharacterSet() | |
allowed.insert(c(0x2A)) | |
allowed.insert(charactersIn: c(0x2D)...c(0x2E)) | |
allowed.insert(charactersIn: c(0x30)...c(0x39)) | |
allowed.insert(charactersIn: c(0x41)...c(0x5A)) | |
allowed.insert(c(0x5F)) | |
allowed.insert(charactersIn: c(0x61)...c(0x7A)) | |
// and we'll deal with ` ` later… | |
allowed.insert(" ") | |
return allowed | |
}() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment