Skip to content

Commit b56e067

Browse files
jrflatb1ackturtle
andcommitted
Add async URLSession methods (swiftlang#4970)
* Add `data(from:delegate:)` method. * Add async URLSession methods --------- Co-authored-by: ichiho <[email protected]>
1 parent ac1af64 commit b56e067

File tree

9 files changed

+495
-59
lines changed

9 files changed

+495
-59
lines changed

Sources/FoundationNetworking/DataURLProtocol.swift

+1-2
Original file line numberDiff line numberDiff line change
@@ -91,8 +91,7 @@ internal class _DataURLProtocol: URLProtocol {
9191
urlClient.urlProtocolDidFinishLoading(self)
9292
} else {
9393
let error = NSError(domain: NSURLErrorDomain, code: NSURLErrorBadURL)
94-
if let session = self.task?.session as? URLSession, let delegate = session.delegate as? URLSessionTaskDelegate,
95-
let task = self.task {
94+
if let task = self.task, let session = task.actualSession, let delegate = task.delegate {
9695
delegate.urlSession(session, task: task, didCompleteWithError: error)
9796
}
9897
}

Sources/FoundationNetworking/URLSession/FTP/FTPURLProtocol.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ internal extension _FTPURLProtocol {
119119
switch session.behaviour(for: self.task!) {
120120
case .noDelegate:
121121
break
122-
case .taskDelegate:
122+
case .taskDelegate, .dataCompletionHandlerWithTaskDelegate, .downloadCompletionHandlerWithTaskDelegate:
123123
self.client?.urlProtocol(self, didReceive: response, cacheStoragePolicy: .notAllowed)
124124
case .dataCompletionHandler:
125125
break

Sources/FoundationNetworking/URLSession/HTTP/HTTPURLProtocol.swift

+4-2
Original file line numberDiff line numberDiff line change
@@ -475,7 +475,7 @@ internal class _HTTPURLProtocol: _NativeProtocol {
475475

476476
guard let session = task?.session as? URLSession else { fatalError() }
477477

478-
if let delegate = session.delegate as? URLSessionTaskDelegate {
478+
if let delegate = task?.delegate {
479479
// At this point we need to change the internal state to note
480480
// that we're waiting for the delegate to call the completion
481481
// handler. Then we'll call the delegate callback
@@ -524,7 +524,9 @@ internal class _HTTPURLProtocol: _NativeProtocol {
524524
switch session.behaviour(for: self.task!) {
525525
case .noDelegate:
526526
break
527-
case .taskDelegate:
527+
case .taskDelegate,
528+
.dataCompletionHandlerWithTaskDelegate,
529+
.downloadCompletionHandlerWithTaskDelegate:
528530
//TODO: There's a problem with libcurl / with how we're using it.
529531
// We're currently unable to pause the transfer / the easy handle:
530532
// https://curl.haxx.se/mail/lib-2016-03/0222.html

Sources/FoundationNetworking/URLSession/NativeProtocol.swift

+51-33
Original file line numberDiff line numberDiff line change
@@ -129,43 +129,59 @@ internal class _NativeProtocol: URLProtocol, _EasyHandleDelegate {
129129
}
130130

131131
fileprivate func notifyDelegate(aboutReceivedData data: Data) {
132-
guard let t = self.task else {
132+
guard let task = self.task, let session = task.session as? URLSession else {
133133
fatalError("Cannot notify")
134134
}
135-
if case .taskDelegate(let delegate) = t.session.behaviour(for: self.task!),
136-
let dataDelegate = delegate as? URLSessionDataDelegate,
137-
let task = self.task as? URLSessionDataTask {
138-
// Forward to the delegate:
139-
guard let s = self.task?.session as? URLSession else {
140-
fatalError()
141-
}
142-
s.delegateQueue.addOperation {
143-
dataDelegate.urlSession(s, dataTask: task, didReceive: data)
144-
}
145-
} else if case .taskDelegate(let delegate) = t.session.behaviour(for: self.task!),
146-
let downloadDelegate = delegate as? URLSessionDownloadDelegate,
147-
let task = self.task as? URLSessionDownloadTask {
148-
guard let s = self.task?.session as? URLSession else {
149-
fatalError()
150-
}
151-
let fileHandle = try! FileHandle(forWritingTo: self.tempFileURL)
152-
_ = fileHandle.seekToEndOfFile()
153-
fileHandle.write(data)
154-
task.countOfBytesReceived += Int64(data.count)
155-
s.delegateQueue.addOperation {
156-
downloadDelegate.urlSession(s, downloadTask: task, didWriteData: Int64(data.count), totalBytesWritten: task.countOfBytesReceived,
157-
totalBytesExpectedToWrite: task.countOfBytesExpectedToReceive)
135+
switch task.session.behaviour(for: task) {
136+
case .taskDelegate(let delegate),
137+
.dataCompletionHandlerWithTaskDelegate(_, let delegate),
138+
.downloadCompletionHandlerWithTaskDelegate(_, let delegate):
139+
if let dataDelegate = delegate as? URLSessionDataDelegate,
140+
let dataTask = task as? URLSessionDataTask {
141+
session.delegateQueue.addOperation {
142+
dataDelegate.urlSession(session, dataTask: dataTask, didReceive: data)
143+
}
144+
} else if let downloadDelegate = delegate as? URLSessionDownloadDelegate,
145+
let downloadTask = task as? URLSessionDownloadTask {
146+
let fileHandle = try! FileHandle(forWritingTo: self.tempFileURL)
147+
_ = fileHandle.seekToEndOfFile()
148+
fileHandle.write(data)
149+
task.countOfBytesReceived += Int64(data.count)
150+
session.delegateQueue.addOperation {
151+
downloadDelegate.urlSession(
152+
session,
153+
downloadTask: downloadTask,
154+
didWriteData: Int64(data.count),
155+
totalBytesWritten: task.countOfBytesReceived,
156+
totalBytesExpectedToWrite: task.countOfBytesExpectedToReceive
157+
)
158+
}
158159
}
160+
default:
161+
break
159162
}
160163
}
161164

162165
fileprivate func notifyDelegate(aboutUploadedData count: Int64) {
163-
guard let task = self.task, let session = task.session as? URLSession,
164-
case .taskDelegate(let delegate) = session.behaviour(for: task) else { return }
165-
task.countOfBytesSent += count
166-
session.delegateQueue.addOperation {
167-
delegate.urlSession(session, task: task, didSendBodyData: count,
168-
totalBytesSent: task.countOfBytesSent, totalBytesExpectedToSend: task.countOfBytesExpectedToSend)
166+
guard let task = self.task, let session = task.session as? URLSession else {
167+
return
168+
}
169+
switch session.behaviour(for: task) {
170+
case .taskDelegate(let delegate),
171+
.dataCompletionHandlerWithTaskDelegate(_, let delegate),
172+
.downloadCompletionHandlerWithTaskDelegate(_, let delegate):
173+
task.countOfBytesSent += count
174+
session.delegateQueue.addOperation {
175+
delegate.urlSession(
176+
session,
177+
task: task,
178+
didSendBodyData: count,
179+
totalBytesSent: task.countOfBytesSent,
180+
totalBytesExpectedToSend: task.countOfBytesExpectedToSend
181+
)
182+
}
183+
default:
184+
break
169185
}
170186
}
171187

@@ -284,7 +300,7 @@ internal class _NativeProtocol: URLProtocol, _EasyHandleDelegate {
284300

285301
var currentInputStream: InputStream?
286302

287-
if let delegate = session.delegate as? URLSessionTaskDelegate {
303+
if let delegate = task?.delegate {
288304
let dispatchGroup = DispatchGroup()
289305
dispatchGroup.enter()
290306

@@ -338,11 +354,13 @@ internal class _NativeProtocol: URLProtocol, _EasyHandleDelegate {
338354
// Data will be forwarded to the delegate as we receive it, we don't
339355
// need to do anything about it.
340356
return .ignore
341-
case .dataCompletionHandler:
357+
case .dataCompletionHandler,
358+
.dataCompletionHandlerWithTaskDelegate:
342359
// Data needs to be concatenated in-memory such that we can pass it
343360
// to the completion handler upon completion.
344361
return .inMemory(nil)
345-
case .downloadCompletionHandler:
362+
case .downloadCompletionHandler,
363+
.downloadCompletionHandlerWithTaskDelegate:
346364
// Data needs to be written to a file (i.e. a download task).
347365
let fileHandle = try! FileHandle(forWritingTo: self.tempFileURL)
348366
return .toFile(self.tempFileURL, fileHandle)

Sources/FoundationNetworking/URLSession/TaskRegistry.swift

+4
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,12 @@ extension URLSession {
4545
case callDelegate
4646
/// Default action for all events, except for completion.
4747
case dataCompletionHandler(DataTaskCompletion)
48+
/// Default action for all asynchronous events.
49+
case dataCompletionHandlerWithTaskDelegate(DataTaskCompletion, URLSessionTaskDelegate?)
4850
/// Default action for all events, except for completion.
4951
case downloadCompletionHandler(DownloadTaskCompletion)
52+
/// Default action for all asynchronous events.
53+
case downloadCompletionHandlerWithTaskDelegate(DownloadTaskCompletion, URLSessionTaskDelegate?)
5054
}
5155

5256
fileprivate var tasks: [Int: URLSessionTask] = [:]

0 commit comments

Comments
 (0)