@@ -8,28 +8,120 @@ import struct TSCUtility.Versioning
8
8
import FoundationNetworking
9
9
#endif
10
10
11
- public struct URLSessionHTTPClient : HTTPClientProtocol {
12
- private let configuration : URLSessionConfiguration
11
+ public final class URLSessionHTTPClient : NSObject {
12
+ public var configuration : HTTPClientConfiguration = . init ( )
13
13
14
- public init ( configuration: URLSessionConfiguration = . default) {
15
- self . configuration = configuration
14
+ private var session : URLSession !
15
+ private var taskDelegates : [ URLSessionTask : TaskDelegate ] = [ : ]
16
+
17
+ final class TaskDelegate : NSObject {
18
+ private let configuration : HTTPClientConfiguration
19
+ private let callback : ( Result < HTTPClient . Response , Error > ) -> Void
20
+ private var accumulatedData : Data = Data ( )
21
+
22
+ required init ( configuration: HTTPClientConfiguration , callback: @escaping ( Result < HTTPClient . Response , Error > ) -> Void ) {
23
+ self . configuration = configuration
24
+ self . callback = callback
25
+ }
16
26
}
17
27
28
+ public required init ( configuration: URLSessionConfiguration = . default) {
29
+ super. init ( )
30
+ self . session = URLSession ( configuration: configuration, delegate: self , delegateQueue: nil )
31
+ }
32
+ }
33
+
34
+ extension URLSessionHTTPClient : HTTPClientProtocol {
18
35
public func execute( _ request: HTTPClient . Request , callback: @escaping ( Result < HTTPClient . Response , Error > ) -> Void ) {
19
- let session = URLSession ( configuration: self . configuration)
20
- let task = session. dataTask ( with: request. urlRequest ( ) ) { data, response, error in
21
- if let error = error {
22
- callback ( . failure( error) )
23
- } else if let response = response as? HTTPURLResponse {
24
- callback ( . success( response. response ( body: data) ) )
25
- } else {
26
- callback ( . failure( HTTPClientError . invalidResponse) )
36
+ let task = session. dataTask ( with: request. urlRequest ( ) )
37
+ taskDelegates [ task] = TaskDelegate ( configuration: configuration, callback: callback)
38
+
39
+ task. resume ( )
40
+ }
41
+ }
42
+
43
+ extension URLSessionHTTPClient : URLSessionDataDelegate {
44
+ public func urlSession( _ session: URLSession ,
45
+ task: URLSessionTask ,
46
+ willPerformHTTPRedirection response: HTTPURLResponse ,
47
+ newRequest request: URLRequest ,
48
+ completionHandler: @escaping ( URLRequest ? ) -> Void )
49
+ {
50
+ guard let delegate = taskDelegates [ task] else {
51
+ return completionHandler ( request)
52
+ }
53
+
54
+ delegate. urlSession ( session, task: task, willPerformHTTPRedirection: response, newRequest: request, completionHandler: completionHandler)
55
+ }
56
+
57
+ public func urlSession( _ session: URLSession ,
58
+ task: URLSessionTask ,
59
+ didCompleteWithError error: Error ? )
60
+ {
61
+ guard let delegate = taskDelegates [ task] else { return }
62
+ defer { taskDelegates [ task] = nil }
63
+
64
+ delegate. urlSession ( session, task: task, didCompleteWithError: error)
65
+ }
66
+
67
+ public func urlSession( _ session: URLSession ,
68
+ dataTask: URLSessionDataTask ,
69
+ didReceive data: Data )
70
+ {
71
+ guard let delegate = taskDelegates [ dataTask] else { return }
72
+ delegate. urlSession ( session, dataTask: dataTask, didReceive: data)
73
+ }
74
+ }
75
+
76
+
77
+ extension URLSessionHTTPClient . TaskDelegate : URLSessionDataDelegate {
78
+ public func urlSession( _ session: URLSession ,
79
+ task: URLSessionTask ,
80
+ willPerformHTTPRedirection response: HTTPURLResponse ,
81
+ newRequest request: URLRequest ,
82
+ completionHandler: @escaping ( URLRequest ? ) -> Void )
83
+ {
84
+ if configuration. followRedirects {
85
+ completionHandler ( request)
86
+ } else {
87
+ completionHandler ( nil )
88
+
89
+ configuration. callbackQueue. async {
90
+ self . callback ( . success( response. response ( body: nil ) ) )
27
91
}
28
92
}
29
- task. resume ( )
93
+ }
94
+
95
+ public func urlSession( _ session: URLSession ,
96
+ task: URLSessionTask ,
97
+ didCompleteWithError error: Error ? )
98
+ {
99
+ if let error = error {
100
+ configuration. callbackQueue. async {
101
+ self . callback ( . failure( error) )
102
+ }
103
+ } else if let response = task. response as? HTTPURLResponse {
104
+ let body = accumulatedData. isEmpty ? nil : accumulatedData
105
+ configuration. callbackQueue. async {
106
+ self . callback ( . success( response. response ( body: body) ) )
107
+ }
108
+ } else {
109
+ configuration. callbackQueue. async {
110
+ self . callback ( . failure( HTTPClientError . invalidResponse) )
111
+ }
112
+ }
113
+ }
114
+
115
+ public func urlSession( _ session: URLSession ,
116
+ dataTask: URLSessionDataTask ,
117
+ didReceive data: Data )
118
+ {
119
+ accumulatedData. append ( data)
30
120
}
31
121
}
32
122
123
+ // MARK: -
124
+
33
125
extension HTTPClient . Request {
34
126
func urlRequest( ) -> URLRequest {
35
127
var request = URLRequest ( url: self . url)
0 commit comments