@@ -121,17 +121,16 @@ class TestURLSession: LoopbackServerTest {
121
121
// Only POST sets a default Content-Type if it is nil
122
122
let postedContentType = contentType ?? ( ( method == " POST " ) ? " application/x-www-form-urlencoded " : nil )
123
123
124
+ let callBacks : [ String ]
124
125
switch method {
125
126
case " HEAD " :
126
127
XCTAssertNil ( delegate. error)
127
128
XCTAssertNotNil ( delegate. response)
128
129
XCTAssertEqual ( httpResponse? . statusCode, 200 )
129
- XCTAssertEqual ( delegate. callbacks. count, 2 )
130
- let callbacks = [ " urlSession(_:dataTask:didReceive:completionHandler:) " ,
131
- " urlSession(_:task:didCompleteWithError:) "
132
- ]
133
- XCTAssertEqual ( delegate. callbacks, callbacks)
134
130
XCTAssertNil ( delegate. receivedData)
131
+ callBacks = [ " urlSession(_:task:didSendBodyData:totalBytesSent:totalBytesExpectedToSend:) " ,
132
+ " urlSession(_:dataTask:didReceive:completionHandler:) " ,
133
+ " urlSession(_:task:didCompleteWithError:) " ]
135
134
136
135
case " GET " :
137
136
// GET requests must not have a body, which causes an error
@@ -144,21 +143,14 @@ class TestURLSession: LoopbackServerTest {
144
143
XCTAssertEqual ( errorURL, url)
145
144
146
145
XCTAssertNil ( delegate. response)
147
- XCTAssertEqual ( delegate. callbacks. count, 1 )
148
- XCTAssertEqual ( delegate. callbacks, [ " urlSession(_:task:didCompleteWithError:) " ] )
149
146
XCTAssertNil ( delegate. receivedData)
147
+ callBacks = [ " urlSession(_:task:didCompleteWithError:) " ]
150
148
151
149
default :
152
150
XCTAssertNil ( delegate. error)
153
151
XCTAssertNotNil ( delegate. response)
154
152
XCTAssertEqual ( httpResponse? . statusCode, 200 )
155
153
156
- XCTAssertEqual ( delegate. callbacks. count, 3 )
157
- let callBacks = [ " urlSession(_:dataTask:didReceive:completionHandler:) " ,
158
- " urlSession(_:dataTask:didReceive:) " ,
159
- " urlSession(_:task:didCompleteWithError:) "
160
- ]
161
- XCTAssertEqual ( delegate. callbacks, callBacks)
162
154
XCTAssertNotNil ( delegate. receivedData)
163
155
XCTAssertEqual ( delegate. receivedData? . count, contentLength)
164
156
if let receivedData = delegate. receivedData, let jsonBody = try ? JSONSerialization . jsonObject ( with: receivedData, options: [ ] ) as? [ String : String ] {
@@ -170,8 +162,14 @@ class TestURLSession: LoopbackServerTest {
170
162
}
171
163
} else {
172
164
XCTFail ( " No JSON body for \( method) " )
173
- }
165
+ }
166
+ callBacks = [ " urlSession(_:task:didSendBodyData:totalBytesSent:totalBytesExpectedToSend:) " ,
167
+ " urlSession(_:dataTask:didReceive:completionHandler:) " ,
168
+ " urlSession(_:dataTask:didReceive:) " ,
169
+ " urlSession(_:task:didCompleteWithError:) " ]
174
170
}
171
+ XCTAssertEqual ( delegate. callbacks. count, callBacks. count)
172
+ XCTAssertEqual ( delegate. callbacks, callBacks)
175
173
}
176
174
}
177
175
}
@@ -990,10 +988,12 @@ class TestURLSession: LoopbackServerTest {
990
988
991
989
delegate. uploadCompletedExpectation = expectation ( description: " PUT \( urlString) : Upload data " )
992
990
993
- let fileData = Data ( count: 16 * 1024 )
991
+ let fileData = Data ( count: 16 * 1024 )
994
992
let task = session. uploadTask ( with: request, from: fileData)
995
993
task. resume ( )
996
994
waitForExpectations ( timeout: 20 )
995
+ XCTAssertEqual ( delegate. totalBytesSent, Int64 ( fileData. count) )
996
+
997
997
}
998
998
999
999
func test_requestWithEmptyBody( ) throws {
@@ -1075,17 +1075,16 @@ class TestURLSession: LoopbackServerTest {
1075
1075
// Only POST sets a default Content-Type if it is nil
1076
1076
let postedContentType = contentType ?? ( ( method == " POST " ) ? " application/x-www-form-urlencoded " : nil )
1077
1077
1078
+ let callBacks : [ String ]
1078
1079
switch method {
1079
1080
case " HEAD " :
1080
1081
XCTAssertNil ( delegate. error)
1081
1082
XCTAssertNotNil ( delegate. response)
1082
1083
XCTAssertEqual ( httpResponse? . statusCode, 200 )
1083
- XCTAssertEqual ( delegate. callbacks. count, 2 )
1084
- let callbacks = [ " urlSession(_:dataTask:didReceive:completionHandler:) " ,
1085
- " urlSession(_:task:didCompleteWithError:) "
1086
- ]
1087
- XCTAssertEqual ( delegate. callbacks, callbacks)
1088
1084
XCTAssertNil ( delegate. receivedData)
1085
+ callBacks = [ " urlSession(_:task:didSendBodyData:totalBytesSent:totalBytesExpectedToSend:) " ,
1086
+ " urlSession(_:dataTask:didReceive:completionHandler:) " ,
1087
+ " urlSession(_:task:didCompleteWithError:) " ]
1089
1088
1090
1089
case " GET " :
1091
1090
// GET requests must not have a body, which causes an error
@@ -1098,22 +1097,13 @@ class TestURLSession: LoopbackServerTest {
1098
1097
XCTAssertEqual ( errorURL, url)
1099
1098
1100
1099
XCTAssertNil ( delegate. response)
1101
- XCTAssertEqual ( delegate. callbacks. count, 1 )
1102
- XCTAssertEqual ( delegate. callbacks, [ " urlSession(_:task:didCompleteWithError:) " ] )
1103
1100
XCTAssertNil ( delegate. receivedData)
1104
-
1101
+ callBacks = [ " urlSession(_:task:didCompleteWithError:) " ]
1105
1102
1106
1103
default :
1107
1104
XCTAssertNil ( delegate. error)
1108
1105
XCTAssertNotNil ( delegate. response)
1109
1106
XCTAssertEqual ( httpResponse? . statusCode, 200 )
1110
-
1111
- XCTAssertEqual ( delegate. callbacks. count, 3 )
1112
- let callBacks = [ " urlSession(_:dataTask:didReceive:completionHandler:) " ,
1113
- " urlSession(_:dataTask:didReceive:) " ,
1114
- " urlSession(_:task:didCompleteWithError:) "
1115
- ]
1116
- XCTAssertEqual ( delegate. callbacks, callBacks)
1117
1107
XCTAssertNotNil ( delegate. receivedData)
1118
1108
XCTAssertEqual ( delegate. receivedData? . count, contentLength)
1119
1109
if let receivedData = delegate. receivedData, let jsonBody = try ? JSONSerialization . jsonObject ( with: receivedData, options: [ ] ) as? [ String : String ] {
@@ -1129,7 +1119,13 @@ class TestURLSession: LoopbackServerTest {
1129
1119
} else {
1130
1120
XCTFail ( " No JSON body for \( method) " )
1131
1121
}
1122
+ callBacks = [ " urlSession(_:task:didSendBodyData:totalBytesSent:totalBytesExpectedToSend:) " ,
1123
+ " urlSession(_:dataTask:didReceive:completionHandler:) " ,
1124
+ " urlSession(_:dataTask:didReceive:) " ,
1125
+ " urlSession(_:task:didCompleteWithError:) " ]
1132
1126
}
1127
+ XCTAssertEqual ( delegate. callbacks. count, callBacks. count)
1128
+ XCTAssertEqual ( delegate. callbacks, callBacks)
1133
1129
}
1134
1130
}
1135
1131
}
@@ -1661,40 +1657,81 @@ class TestURLSession: LoopbackServerTest {
1661
1657
1662
1658
func test_simpleUploadWithDelegateProvidingInputStream( ) throws {
1663
1659
1664
- let fileData = Data ( count: 16 * 1024 )
1660
+ let fileData = Data ( count: 16 * 1024 )
1665
1661
for method in httpMethods {
1666
- let delegate = HTTPUploadDelegate ( )
1667
- let session = URLSession ( configuration: . default, delegate: delegate, delegateQueue: nil )
1668
1662
let urlString = " http://127.0.0.1: \( TestURLSession . serverPort) / " + method. lowercased ( )
1669
- var request = URLRequest ( url: try XCTUnwrap ( URL ( string: urlString) ) )
1663
+ let url = try XCTUnwrap ( URL ( string: urlString) )
1664
+ var request = URLRequest ( url: url)
1670
1665
request. httpMethod = method
1671
1666
1672
- let stream = InputStream ( data: fileData)
1667
+ let delegate = SessionDelegate ( with: expectation ( description: " \( method) \( urlString) : Upload data " ) )
1668
+ delegate. newBodyStreamHandler = { ( completionHandler: @escaping ( InputStream ? ) -> Void ) in
1669
+ completionHandler ( InputStream ( data: fileData) )
1670
+ }
1671
+ delegate. runUploadTask ( with: request, timeoutInterval: 4 )
1672
+ waitForExpectations ( timeout: 5 )
1673
1673
1674
- let expect = expectation ( description: " \( method) \( urlString) : Upload data " )
1675
- if method == " GET " || method == " HEAD " { expect. isInverted = true }
1676
- delegate. uploadCompletedExpectation = expect
1677
- delegate. streamToProvideOnRequest = stream
1678
- let task = session. uploadTask ( withStreamedRequest: request)
1679
- task. resume ( )
1674
+ let httpResponse = delegate. response as? HTTPURLResponse
1675
+ let callBacks : [ String ]
1680
1676
1681
- waitForExpectations ( timeout: 5 )
1682
1677
switch method {
1683
- case " GET " :
1684
- XCTAssertEqual ( delegate. callbacks. count, 1 , " Callback count for GET request " )
1685
- XCTAssertEqual ( delegate. callbacks [ 0 ] , " urlSession(_:task:needNewBodyStream:) " )
1686
-
1687
1678
case " HEAD " :
1688
- XCTAssertEqual ( delegate. callbacks. count, 2 , " Callback count for HEAD request " )
1689
- XCTAssertEqual ( delegate. callbacks [ 0 ] , " urlSession(_:task:needNewBodyStream:) " )
1690
- XCTAssertEqual ( delegate. callbacks [ 1 ] , " urlSession(_:task:didSendBodyData:totalBytesSent:totalBytesExpectedToSend:) " )
1679
+ XCTAssertNil ( delegate. error)
1680
+ XCTAssertNotNil ( delegate. response)
1681
+ XCTAssertEqual ( httpResponse? . statusCode, 200 )
1682
+ XCTAssertNil ( delegate. receivedData)
1683
+ XCTAssertEqual ( delegate. totalBytesSent, Int64 ( fileData. count) )
1684
+ callBacks = [ " urlSession(_:task:needNewBodyStream:) " ,
1685
+ " urlSession(_:task:didSendBodyData:totalBytesSent:totalBytesExpectedToSend:) " ,
1686
+ " urlSession(_:dataTask:didReceive:completionHandler:) " ,
1687
+ " urlSession(_:task:didCompleteWithError:) " ]
1688
+
1689
+ case " GET " :
1690
+ // GET requests must not have a body, which causes an error
1691
+ XCTAssertNotNil ( delegate. error)
1692
+ let error = delegate. error as? URLError
1693
+ XCTAssertEqual ( error? . code. rawValue, NSURLErrorDataLengthExceedsMaximum)
1694
+ XCTAssertEqual ( error? . localizedDescription, " resource exceeds maximum size " )
1695
+ let userInfo = error? . userInfo as? [ String : Any ]
1696
+ let errorURL = userInfo ? [ NSURLErrorFailingURLErrorKey] as? URL
1697
+ XCTAssertEqual ( errorURL, url)
1698
+ XCTAssertNil ( delegate. response)
1699
+ XCTAssertNil ( delegate. receivedData)
1700
+ XCTAssertEqual ( delegate. totalBytesSent, 0 )
1701
+ callBacks = [ " urlSession(_:task:needNewBodyStream:) " ,
1702
+ " urlSession(_:task:didCompleteWithError:) " ]
1691
1703
1692
1704
default :
1693
- XCTAssertEqual ( delegate. callbacks. count, 3 , " Callback count for \( method) request " )
1694
- XCTAssertEqual ( delegate. callbacks [ 0 ] , " urlSession(_:task:needNewBodyStream:) " )
1695
- XCTAssertEqual ( delegate. callbacks [ 1 ] , " urlSession(_:task:didSendBodyData:totalBytesSent:totalBytesExpectedToSend:) " )
1696
- XCTAssertEqual ( delegate. callbacks [ 2 ] , " urlSession(_:dataTask:didReceive:) " )
1705
+ XCTAssertNil ( delegate. error)
1706
+ XCTAssertNotNil ( delegate. response)
1707
+ XCTAssertEqual ( httpResponse? . statusCode, 200 )
1708
+ XCTAssertEqual ( delegate. totalBytesSent, Int64 ( fileData. count) )
1709
+ XCTAssertNotNil ( delegate. receivedData)
1710
+ let contentLength = Int ( httpResponse? . value ( forHTTPHeaderField: " Content-Length " ) ?? " " )
1711
+
1712
+ XCTAssertEqual ( delegate. receivedData? . count, contentLength)
1713
+ if let receivedData = delegate. receivedData, let jsonBody = try ? JSONSerialization . jsonObject ( with: receivedData, options: [ ] ) as? [ String : String ] {
1714
+ if let postedContentType = ( method == " POST " ) ? " application/x-www-form-urlencoded " : nil {
1715
+ XCTAssertEqual ( jsonBody [ " Content-Type " ] , postedContentType)
1716
+ } else {
1717
+ XCTAssertNil ( jsonBody. index ( forKey: " Content-Type " ) )
1718
+ }
1719
+ if let postedBody = jsonBody [ " x-base64-body " ] , let decodedBody = Data ( base64Encoded: postedBody) {
1720
+ XCTAssertEqual ( decodedBody, fileData)
1721
+ } else {
1722
+ XCTFail ( " Could not decode Base64 body for \( method) " )
1723
+ }
1724
+ } else {
1725
+ XCTFail ( " No JSON body for \( method) " )
1726
+ }
1727
+ callBacks = [ " urlSession(_:task:needNewBodyStream:) " ,
1728
+ " urlSession(_:task:didSendBodyData:totalBytesSent:totalBytesExpectedToSend:) " ,
1729
+ " urlSession(_:dataTask:didReceive:completionHandler:) " ,
1730
+ " urlSession(_:dataTask:didReceive:) " ,
1731
+ " urlSession(_:task:didCompleteWithError:) " ]
1697
1732
}
1733
+ XCTAssertEqual ( delegate. callbacks. count, callBacks. count, " Callback count for \( method) " )
1734
+ XCTAssertEqual ( delegate. callbacks, callBacks, " Callbacks for \( method) " )
1698
1735
}
1699
1736
}
1700
1737
@@ -1800,11 +1837,16 @@ class SessionDelegate: NSObject, URLSessionDelegate {
1800
1837
typealias RedirectionHandler = ( HTTPURLResponse , URLRequest , @escaping ( URLRequest ? ) -> Void ) -> Void
1801
1838
var redirectionHandler : RedirectionHandler ? = nil
1802
1839
1840
+ typealias NewBodyStreamHandler = ( @escaping ( InputStream ? ) -> Void ) -> Void
1841
+ var newBodyStreamHandler : NewBodyStreamHandler ? = nil
1842
+
1843
+
1803
1844
private( set) var receivedData : Data ?
1804
1845
private( set) var error : Error ?
1805
1846
private( set) var response : URLResponse ?
1806
1847
private( set) var redirectionRequest : URLRequest ?
1807
1848
private( set) var redirectionResponse : HTTPURLResponse ?
1849
+ private( set) var totalBytesSent : Int64 = 0
1808
1850
private( set) var callbacks : [ String ] = [ ]
1809
1851
private( set) var authenticationChallenges : [ URLAuthenticationChallenge ] = [ ]
1810
1852
@@ -1838,6 +1880,14 @@ class SessionDelegate: NSObject, URLSessionDelegate {
1838
1880
task. resume ( )
1839
1881
}
1840
1882
1883
+ func runUploadTask( with request: URLRequest , timeoutInterval: Double = 3 ) {
1884
+ let config = URLSessionConfiguration . default
1885
+ config. timeoutIntervalForRequest = timeoutInterval
1886
+ session = URLSession ( configuration: config, delegate: self , delegateQueue: nil )
1887
+ task = session. uploadTask ( withStreamedRequest: request)
1888
+ task. resume ( )
1889
+ }
1890
+
1841
1891
func urlSession( _ session: URLSession , didBecomeInvalidWithError error: Error ? ) {
1842
1892
callbacks. append ( #function)
1843
1893
self . error = error
@@ -1853,13 +1903,24 @@ extension SessionDelegate: URLSessionTaskDelegate {
1853
1903
1854
1904
public func urlSession( _ session: URLSession , task: URLSessionTask , didCompleteWithError error: Error ? ) {
1855
1905
callbacks. append ( #function)
1856
-
1857
1906
self . error = error
1858
1907
expectation. fulfill ( )
1859
1908
}
1860
1909
1910
+ public func urlSession( _ session: URLSession , task: URLSessionTask , didSendBodyData bytesSent: Int64 , totalBytesSent: Int64 , totalBytesExpectedToSend: Int64 ) {
1911
+ if callbacks. last != #function {
1912
+ callbacks. append ( #function)
1913
+ }
1914
+ self . totalBytesSent = totalBytesSent
1915
+ }
1916
+
1917
+ // New Body Stream
1861
1918
public func urlSession( _ session: URLSession , task: URLSessionTask , needNewBodyStream completionHandler: @escaping ( InputStream ? ) -> Void ) {
1862
1919
callbacks. append ( #function)
1920
+
1921
+ if let handler = newBodyStreamHandler {
1922
+ handler ( completionHandler)
1923
+ }
1863
1924
}
1864
1925
1865
1926
// HTTP Authentication Challenge
@@ -2255,33 +2316,26 @@ class HTTPUploadDelegate: NSObject {
2255
2316
private( set) var callbacks : [ String ] = [ ]
2256
2317
2257
2318
var uploadCompletedExpectation : XCTestExpectation !
2258
- var streamToProvideOnRequest : InputStream ?
2259
2319
var totalBytesSent : Int64 = 0
2260
2320
}
2261
2321
2262
2322
extension HTTPUploadDelegate : URLSessionTaskDelegate {
2323
+ public func urlSession( _ session: URLSession , task: URLSessionTask , didCompleteWithError error: Error ? ) {
2324
+ callbacks. append ( #function)
2325
+ uploadCompletedExpectation. fulfill ( )
2326
+ }
2327
+
2263
2328
func urlSession( _ session: URLSession , task: URLSessionTask , didSendBodyData bytesSent: Int64 , totalBytesSent: Int64 , totalBytesExpectedToSend: Int64 ) {
2264
2329
if callbacks. last != #function {
2265
2330
callbacks. append ( #function)
2266
2331
}
2267
2332
self . totalBytesSent = totalBytesSent
2268
2333
}
2269
-
2270
- func urlSession( _ session: URLSession , task: URLSessionTask , needNewBodyStream completionHandler: @escaping ( InputStream ? ) -> Void ) {
2271
- callbacks. append ( #function)
2272
- if streamToProvideOnRequest == nil {
2273
- XCTFail ( " This shouldn't have been invoked -- no stream was set. " )
2274
- }
2275
-
2276
- completionHandler ( self . streamToProvideOnRequest)
2277
- }
2278
2334
}
2279
2335
2280
2336
extension HTTPUploadDelegate : URLSessionDataDelegate {
2281
2337
func urlSession( _ session: URLSession , dataTask: URLSessionDataTask , didReceive data: Data ) {
2282
2338
callbacks. append ( #function)
2283
- XCTAssertEqual ( self . totalBytesSent, 16 * 1024 )
2284
- uploadCompletedExpectation. fulfill ( )
2285
2339
}
2286
2340
}
2287
2341
0 commit comments