@@ -805,6 +805,78 @@ final class URLSessionHTTPClientTest: XCTestCase {
805
805
}
806
806
}
807
807
808
+ func testAsyncDownloadAuthenticateWithRedirectedSuccess( ) async throws {
809
+ #if !os(macOS)
810
+ // URLSession Download tests can only run on macOS
811
+ // as re-libs-foundation's URLSessionTask implementation which expects the temporaryFileURL property to be on the request.
812
+ // and there is no way to set it in a mock
813
+ // https://github.com/apple/swift-corelibs-foundation/pull/2593 tries to address the latter part
814
+ try XCTSkipIf ( true , " test is only supported on macOS " )
815
+ #endif
816
+ let netrcContent = " machine async-protected.downloader-tests.com login anonymous password qwerty "
817
+ let netrc = try NetrcAuthorizationWrapper ( underlying: NetrcParser . parse ( netrcContent) )
818
+ let authData = Data ( " anonymous:qwerty " . utf8)
819
+ let testAuthHeader = " Basic \( authData. base64EncodedString ( ) ) "
820
+
821
+ let configuration = URLSessionConfiguration . default
822
+ configuration. protocolClasses = [ MockURLProtocol . self]
823
+ let urlSession = URLSessionHTTPClient ( configuration: configuration)
824
+ let httpClient = HTTPClient ( implementation: urlSession. execute)
825
+
826
+ try await testWithTemporaryDirectory { temporaryDirectory in
827
+ let url = URL ( " https://async-protected.downloader-tests.com/testBasics.zip " )
828
+ let redirectURL = URL ( " https://cdn-async.downloader-tests.com/testBasics.zip " )
829
+ let destination = temporaryDirectory. appending ( " download " )
830
+ var options = HTTPClientRequest . Options ( )
831
+ options. authorizationProvider = netrc. httpAuthorizationHeader ( for: )
832
+ let request = HTTPClient . Request. download (
833
+ url: url,
834
+ options: options,
835
+ fileSystem: localFileSystem,
836
+ destination: destination
837
+ )
838
+ let redirectRequest = HTTPClient . Request. download (
839
+ url: redirectURL,
840
+ options: options,
841
+ fileSystem: localFileSystem,
842
+ destination: destination
843
+ )
844
+
845
+ MockURLProtocol . onRequest ( request) { request in
846
+ XCTAssertEqual ( request. allHTTPHeaderFields ? [ " Authorization " ] , testAuthHeader)
847
+ MockURLProtocol . sendResponse ( statusCode: 302 , headers: [ " Location " : redirectURL. absoluteString] , for: request)
848
+ MockURLProtocol . sendRedirect ( for: request, to: URLRequest ( url: redirectURL) )
849
+ }
850
+ MockURLProtocol . onRequest ( redirectRequest) { request in
851
+ XCTAssertEqual ( request. allHTTPHeaderFields ? [ " Authorization " ] , nil )
852
+ MockURLProtocol . sendResponse ( statusCode: 200 , headers: [ " Content-Length " : " 1024 " ] , for: request)
853
+ MockURLProtocol . sendData ( Data ( repeating: 0xBE , count: 512 ) , for: request)
854
+ MockURLProtocol . sendData ( Data ( repeating: 0xEF , count: 512 ) , for: request)
855
+ MockURLProtocol . sendCompletion ( for: request)
856
+ }
857
+
858
+ let response = try await httpClient. execute (
859
+ request,
860
+ progress: { bytesDownloaded, totalBytesToDownload in
861
+ switch ( bytesDownloaded, totalBytesToDownload) {
862
+ case ( 512 , 1024 ) :
863
+ break
864
+ case ( 1024 , 1024 ) :
865
+ break
866
+ default :
867
+ XCTFail ( " unexpected progress " )
868
+ }
869
+ }
870
+ )
871
+
872
+ XCTAssertEqual ( response. statusCode, 200 )
873
+ XCTAssertFileExists ( destination)
874
+
875
+ let bytes = ByteString ( Array ( repeating: 0xBE , count: 512 ) + Array( repeating: 0xEF , count: 512 ) )
876
+ XCTAssertEqual ( try ! localFileSystem. readFileContents ( destination) , bytes)
877
+ }
878
+ }
879
+
808
880
func testAsyncDownloadDefaultAuthenticationSuccess( ) async throws {
809
881
#if !os(macOS)
810
882
// URLSession Download tests can only run on macOS
@@ -1055,6 +1127,19 @@ private class MockURLProtocol: URLProtocol {
1055
1127
request. client? . urlProtocol ( request, didFailWithError: error)
1056
1128
}
1057
1129
1130
+ static func sendRedirect( for request: URLRequest , to newRequest: URLRequest ) {
1131
+ let key = Key ( request. httpMethod!, request. url!)
1132
+ self . sendRedirect ( newRequest: newRequest, for: key)
1133
+ }
1134
+
1135
+ private static func sendRedirect( newRequest: URLRequest , for key: Key ) {
1136
+ guard let request = self . requests [ key] else {
1137
+ return XCTFail ( " url did not start loading " )
1138
+ }
1139
+ let response = HTTPURLResponse ( url: key. url, statusCode: 302 , httpVersion: " 1.1 " , headerFields: nil ) !
1140
+ request. client? . urlProtocol ( request, wasRedirectedTo: newRequest, redirectResponse: response)
1141
+ }
1142
+
1058
1143
private struct Key : Hashable {
1059
1144
let method : String
1060
1145
let url : URL
0 commit comments