@@ -805,6 +805,78 @@ final class URLSessionHTTPClientTest: XCTestCase {
805805 }
806806 }
807807
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+
808880 func testAsyncDownloadDefaultAuthenticationSuccess( ) async throws {
809881 #if !os(macOS)
810882 // URLSession Download tests can only run on macOS
@@ -1055,6 +1127,19 @@ private class MockURLProtocol: URLProtocol {
10551127 request. client? . urlProtocol ( request, didFailWithError: error)
10561128 }
10571129
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+
10581143 private struct Key : Hashable {
10591144 let method : String
10601145 let url : URL
0 commit comments