0.3.1
What's Changed
🔗 Foundation Integration
0.3.0 brought Foundation-to-WebURL conversion, and this release adds conversion in the opposite direction (WebURL-to-Foundation). This is a particularly important feature for developers on Apple platforms, as it means you can now use WebURL
to make requests using URLSession
! We now have full, bidirectional interop with Foundation's URL
, which is a huge milestone and a big step towards v1.0.🥳
WebURLFoundationExtras
now adds a number of extensions to types such as URLRequest
and URLSession
to make that super easy:
import Foundation
import WebURL
import WebURLFoundationExtras
// ℹ️ Make URLSession requests using WebURL.
func makeRequest(to url: WebURL) -> URLSessionDataTask {
return URLSession.shared.dataTask(with: url) {
data, response, error in
// ...
}
}
// ℹ️ Also supports Swift concurrency.
func processData(from url: WebURL) async throws {
let (data, _) = try await URLSession.shared.data(from: url)
// ...
}
// ℹ️ For libraries: move to WebURL without breaking
// compatibility with clients using Foundation's URL.
public func processURL(_ url: Foundation.URL) throws {
guard let webURL = WebURL(url) else {
throw InvalidURLError()
}
// Internal code uses WebURL...
}
When you make a request using WebURL
, you will benefit from its modern, web-compatible parser, which matches modern browsers and libraries in other languages:
// Using WebURL: Sends a request to "example.com".
// Chrome, Safari, Firefox, Go, Python, NodeJS, Rust agree. ✅
print( try String(contentsOf: WebURL("http://[email protected]:[email protected]/")!) )
// Using Foundation.URL: Sends a request to "evil.com"! 😵
print( try String(contentsOf: URL(string: "http://[email protected]:[email protected]/")!) )
Note that this only applies to the initial request; HTTP redirects continue to be processed by URLSession
(it is not possible to override it universally), and so are not always web-compatible. As an alternative on non-Apple platforms, our fork of async-http-client
uses WebURL
for all of its internal URL processing, so it also provides web-compatible redirect handling.
For more information about why WebURL is a great choice even for applications and libraries using Foundation, and a discussion about how to safely work with multiple URL standards, we highly recommend reading: Using WebURL with Foundation.
URLSession
extensions are only available on Apple platforms right now, due to a bug in swift-corelibs-foundation
. I opened a PR to fix it, and once merged, we'll be able to make these extensions available to all platforms.
⚡️ Performance improvements
I say it every time, and it's true every time 😅. For this release, I noticed that, due to a quirk with how ManagedBuffer
is implemented in the standard library, every access to the URL's header data required dynamic exclusivity enforcement. But that shouldn't be necessary - the URL storage uses COW to enforce non-local exclusivity, and local exclusivity can be enforced by the compiler if we wrap the ManagedBuffer
in a struct
with reference semantics. So that's what I did.
The result is ~5% faster parsing and 10-20% better performance when getting/setting URL components. For collection views like pathComponents
, these enforcement checks affect basically every operation and amount to a consistent overhead that we're now able to eliminate.
benchmark column results/0_3_0 results/0_3_1 %
------------------------------------------------------------------------------------------------
Constructor.HTTP.AverageURLs time 23909.00 22665.00 5.20
Constructor.HTTP.AverageURLs.filtered time 37826.50 36066.00 4.65
Constructor.HTTP.IPv4 time 12205.00 11627.00 4.74
Constructor.HTTP.IPv4.filtered time 19164.00 17819.00 7.02
Constructor.HTTP.IPv6 time 13677.00 13086.00 4.32
Constructor.HTTP.IPv6.filtered time 17614.00 16577.00 5.89
...
ComponentSetters.Unique.Username time 418.00 365.00 12.68
ComponentSetters.Unique.Username.PercentEncoding time 767.00 632.00 17.60
ComponentSetters.Unique.Username.Long time 636.00 527.00 17.14
...
ComponentSetters.Unique.Path.Simple time 2525.00 2247.00 11.01
...
PathComponents.Iteration.Small.Forwards time 705.00 602.00 14.61
PathComponents.Iteration.Small.Reverse time 718.00 619.00 13.79
PathComponents.Iteration.Long.Reverse time 3137.00 2752.00 12.27
PathComponents.Append.Single time 1362.00 1242.00 8.81
🌍 Standard Update
This release also implements a recent change to the WHATWG URL Standard, which forbids C0 Control characters and U+007F delete from appearing in domains. whatwg/url#685
Full Changelog: 0.3.0...0.3.1