Skip to content

[Proposal] New HTTP loader for URLSession #1135

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Feb 10, 2025
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
111 changes: 111 additions & 0 deletions Proposals/0018-urlsession-new-loader.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
# New HTTP loader for URLSession

* Proposal: [SF-0018](0018-urlsession-new-loader.md)
* Authors: [Guoye Zhang](https://github.com/guoye-zhang)
* Review Manager: [Tina L](https://github.com/itingliu)
* Status: **Accepted**
* Implementation: [swiftlang/swift-corelibs-foundation#5162](https://github.com/swiftlang/swift-corelibs-foundation/pull/5162)
* Review: ([pitch](https://forums.swift.org/t/pitch-new-http-loader-for-urlsession-on-darwin/77440))

## Introduction

The new HTTP stack built in Network framework was enabled in Safari on iOS 18 and macOS Sequoia. It supports new features like 0-RTT early data, oblivious HTTP, WebSocket over HTTP/2, and unix domain socket. Support for FTP and HTTP/1 pipelining was dropped.

In this proposal, we are introducing an API to enable the new HTTP loader in URLSession on Darwin, as well as deprecating several legacy features not supported in the new stack.

## Proposed solution

Introducing a new flag `usesClassicLoadingMode` that defaults to true on URLSessionConfiguration to allow developers to opt-in to the new stack.

The flag is not available on non-Darwin platforms at this moment.

## Detailed design

### Opt-in flag

The new loader is enabled when `usesClassicLoadingMode` is set to false. `usesClassicLoadingMode` currently defaults to true, but might default to false in a future OS.

```swift
open class URLSessionConfiguration {

/* Uses the classic network loader */
@available(*, unavailable, message: "Not available on non-Darwin platforms")
open var usesClassicLoadingMode: Bool
}
```

### Deprecations

* FTP was deprecated in the old stack and unsupported in the new stack.
* HTTP/1 pipelining is not supported in the new HTTP stack. It is disabled by default in the old stack and has known compatibility issues with some servers.
* Server push was disabled in both stacks on iOS 17 and aligned releases due to low adoption and web compatibility issues.
* `NSURLErrorFailingURLStringErrorKey` is redundant with `NSURLErrorFailingURLErrorKey` and it is incompatible with WHATWG URLs.
* `shouldUseExtendedBackgroundIdleMode` was not supported in either the old stack or the new stack.

```swift
public struct URLRequest {

@available(swift, deprecated: 6.1, message: "HTTP/1 pipelining has known compatibility issues, please adopt HTTP/2 and HTTP/3 instead")
public var httpShouldUsePipelining: Bool
}

open class NSURLRequest {

@available(swift, deprecated: 6.1, message: "HTTP/1 pipelining has known compatibility issues, please adopt HTTP/2 and HTTP/3 instead")
open var httpShouldUsePipelining: Bool { get }
}

open class NSMutableURLRequest {

@available(swift, deprecated: 6.1, message: "HTTP/1 pipelining has known compatibility issues, please adopt HTTP/2 and HTTP/3 instead")
open override var httpShouldUsePipelining: Bool
}

open class URLSessionConfiguration {

@available(swift, deprecated: 6.1, message: "HTTP/1 pipelining has known compatibility issues, please adopt HTTP/2 and HTTP/3 instead")
open var httpShouldUsePipelining: Bool

@available(swift, deprecated: 6.1, message: "Not supported")
open var shouldUseExtendedBackgroundIdleMode: Bool
}

public enum URLSessionTaskMetrics.ResourceFetchType {

@available(swift, deprecated: 6.1, message: "Server push is not supported")
case serverPush
}

public struct URLError {

@available(swift, deprecated: 6.1, message: "Use failingURL instead")
public var failureURLString: String?
}

@available(swift, deprecated: 6.1, message: "Use NSURLErrorFailingURLErrorKey instead")
public let NSURLErrorFailingURLStringErrorKey: String

@available(swift, deprecated: 6.1, message: "FTP is deprecated")
public let NSURLProtectionSpaceFTP: String

@available(swift, deprecated: 6.1, message: "FTP is deprecated")
public let NSURLProtectionSpaceFTPProxy: String
```

## Source compatibility

No impact.

## Implications on adoption

This feature can be freely adopted and un-adopted in source code with no deployment constraints and without affecting source compatibility.

## Future directions

The new HTTP stack might become the default on a future Darwin release.

## Alternatives considered

### Alternative spelling `usesNewLoader`

The initial idea was an opt-in flag where YES means the new loader, and we considered multiple variants, including `usesModernLoader`, `usesNWLoader` (NW stands for Network framework). However, this makes it hard to come up with names for newer loaders in the future, and an opt-out flag gives the impression that the new loader is the default, not the exception.