diff --git a/Foundation/URLSession/http/HTTPURLProtocol.swift b/Foundation/URLSession/http/HTTPURLProtocol.swift index 33f3366beb..caf7a6b700 100644 --- a/Foundation/URLSession/http/HTTPURLProtocol.swift +++ b/Foundation/URLSession/http/HTTPURLProtocol.swift @@ -414,7 +414,12 @@ internal extension _HTTPURLProtocol { var components = URLComponents() components.scheme = scheme components.host = host - components.port = port + // Use the original port if the new URL does not contain a host + // ie Location: /foo => :/Foo + // but Location: newhost/foo will ignore the original port + if targetURL.host == nil { + components.port = port + } //The path must either begin with "/" or be an empty string. if targetURL.relativeString.first != "/" { components.path = "/" + targetURL.relativeString diff --git a/TestFoundation/HTTPServer.swift b/TestFoundation/HTTPServer.swift index 7837364f8c..9bf785aaa3 100644 --- a/TestFoundation/HTTPServer.swift +++ b/TestFoundation/HTTPServer.swift @@ -522,6 +522,13 @@ public class TestURLSessionServer { let httpResponse = _HTTPResponse(response: .REDIRECT, headers: "Location: \(value)", body: text) return httpResponse } + if uri == "/redirect-with-default-port" { + let text = request.getCommaSeparatedHeaders() + let host = request.headers[1].components(separatedBy: " ")[1] + let ip = host.components(separatedBy: ":")[0] + let httpResponse = _HTTPResponse(response: .REDIRECT, headers: "Location: http://\(ip)/redirected-with-default-port", body: text) + return httpResponse + } return _HTTPResponse(response: .OK, body: capitals[String(uri.dropFirst())]!) } diff --git a/TestFoundation/TestURLSession.swift b/TestFoundation/TestURLSession.swift index 5e23f2f6e2..5a90f6537e 100644 --- a/TestFoundation/TestURLSession.swift +++ b/TestFoundation/TestURLSession.swift @@ -29,6 +29,7 @@ class TestURLSession : LoopbackServerTest { ("test_timeoutInterval", test_timeoutInterval), ("test_httpRedirectionWithCompleteRelativePath", test_httpRedirectionWithCompleteRelativePath), ("test_httpRedirectionWithInCompleteRelativePath", test_httpRedirectionWithInCompleteRelativePath), + ("test_httpRedirectionWithDefaultPort", test_httpRedirectionWithDefaultPort), ("test_httpRedirectionTimeout", test_httpRedirectionTimeout), ("test_http0_9SimpleResponses", test_http0_9SimpleResponses), ("test_outOfRangeButCorrectlyFormattedHTTPCode", test_outOfRangeButCorrectlyFormattedHTTPCode), @@ -345,6 +346,14 @@ class TestURLSession : LoopbackServerTest { waitForExpectations(timeout: 12) } + func test_httpRedirectionWithDefaultPort() { + let urlString = "http://127.0.0.1:\(TestURLSession.serverPort)/redirect-with-default-port" + let url = URL(string: urlString)! + let d = HTTPRedirectionDataTask(with: expectation(description: "GET \(urlString): with HTTP redirection")) + d.run(with: url) + waitForExpectations(timeout: 12) + } + // temporarily disabled (https://bugs.swift.org/browse/SR-5751) func test_httpRedirectionTimeout() { let urlString = "http://127.0.0.1:\(TestURLSession.serverPort)/UnitedStates" @@ -915,6 +924,11 @@ extension HTTPRedirectionDataTask : URLSessionTaskDelegate { public func urlSession(_ session: URLSession, task: URLSessionTask, willPerformHTTPRedirection response: HTTPURLResponse, newRequest request: URLRequest, completionHandler: @escaping (URLRequest?) -> Void) { XCTAssertNotNil(response) XCTAssertEqual(302, response.statusCode, "HTTP response code is not 302") + if let url = response.url, url.path.hasSuffix("/redirect-with-default-port") { + XCTAssertEqual(request.url?.absoluteString, "http://127.0.0.1/redirected-with-default-port") + // Dont follow the redirect as the test server is not running on port 80 + return + } completionHandler(request) } }