Skip to content

Commit f819681

Browse files
authored
Merge pull request #2755 from spevans/pr_sr_2682
SR-2682: URLSession redirect does not inherit request timeout value
2 parents d84e919 + 642bb06 commit f819681

File tree

3 files changed

+41
-2
lines changed

3 files changed

+41
-2
lines changed

Sources/FoundationNetworking/URLSession/HTTP/HTTPURLProtocol.swift

+3-2
Original file line numberDiff line numberDiff line change
@@ -699,8 +699,9 @@ internal extension _HTTPURLProtocol {
699699

700700
guard let urlString = components.string else { fatalError("Invalid URL") }
701701
request.url = URL(string: urlString)
702-
let timeSpent = easyHandle.getTimeoutIntervalSpent()
703-
request.timeoutInterval = fromRequest.timeoutInterval - timeSpent
702+
703+
// Inherit the timeout from the previous request
704+
request.timeoutInterval = fromRequest.timeoutInterval
704705
return request
705706
}
706707
}

Tests/Foundation/HTTPServer.swift

+8
Original file line numberDiff line numberDiff line change
@@ -722,6 +722,14 @@ public class TestURLSessionServer {
722722
return try headersAsJSONResponse()
723723
}
724724

725+
if uri.hasPrefix("/redirect/") {
726+
let components = uri.components(separatedBy: "/")
727+
if components.count >= 3, let count = Int(components[2]) {
728+
let newLocation = (count <= 1) ? "/jsonBody" : "/redirect/\(count - 1)"
729+
return try _HTTPResponse(response: .FOUND, headers: "Location: \(newLocation)", body: "Redirecting to \(newLocation)")
730+
}
731+
}
732+
725733
if uri == "/upload" {
726734
if let contentLength = request.getHeader(for: "content-length") {
727735
let text = "Upload completed!, Content-Length: \(contentLength)"

Tests/Foundation/Tests/TestURLSession.swift

+30
Original file line numberDiff line numberDiff line change
@@ -771,6 +771,33 @@ class TestURLSession: LoopbackServerTest {
771771
waitForExpectations(timeout: 12)
772772
}
773773

774+
func test_httpRedirectionChainInheritsTimeoutInterval() throws {
775+
let redirectCount = 4
776+
let urlString = "http://127.0.0.1:\(TestURLSession.serverPort)/redirect/\(redirectCount)"
777+
let url = try XCTUnwrap(URL(string: urlString))
778+
let timeoutInterval = 3.0
779+
780+
for method in httpMethods {
781+
var request = URLRequest(url: url)
782+
request.httpMethod = method
783+
request.timeoutInterval = timeoutInterval
784+
let delegate = SessionDelegate(with: expectation(description: "\(method) \(urlString): with HTTP redirection"))
785+
var timeoutIntervals: [Double] = []
786+
delegate.redirectionHandler = { (response: HTTPURLResponse, request: URLRequest, completionHandler: @escaping (URLRequest?) -> Void) in
787+
timeoutIntervals.append(request.timeoutInterval)
788+
completionHandler(request)
789+
}
790+
delegate.run(with: request, timeoutInterval: timeoutInterval)
791+
waitForExpectations(timeout: timeoutInterval + 1)
792+
XCTAssertEqual(timeoutIntervals.count, redirectCount, "Redirect chain count for \(method)")
793+
794+
// Check the redirect request timeouts are the same as the original request timeout
795+
XCTAssertFalse(timeoutIntervals.contains { $0 != timeoutInterval }, "Timeout Intervals for \(method)")
796+
let httpResponse = delegate.response as? HTTPURLResponse
797+
XCTAssertEqual(httpResponse?.statusCode, 200, ".statusCode for \(method)")
798+
}
799+
}
800+
774801
func test_httpNotFound() throws {
775802
let urlString = "http://127.0.0.1:\(TestURLSession.serverPort)/404"
776803
let url = try XCTUnwrap(URL(string: urlString))
@@ -1663,6 +1690,7 @@ class TestURLSession: LoopbackServerTest {
16631690
("test_httpRedirectionWithInCompleteRelativePath", test_httpRedirectionWithInCompleteRelativePath),
16641691
("test_httpRedirectionWithDefaultPort", test_httpRedirectionWithDefaultPort),
16651692
("test_httpRedirectionTimeout", test_httpRedirectionTimeout),
1693+
("test_httpRedirectionChainInheritsTimeoutInterval", test_httpRedirectionChainInheritsTimeoutInterval),
16661694
("test_httpNotFound", test_httpNotFound),
16671695
("test_http0_9SimpleResponses", test_http0_9SimpleResponses),
16681696
("test_outOfRangeButCorrectlyFormattedHTTPCode", test_outOfRangeButCorrectlyFormattedHTTPCode),
@@ -1733,6 +1761,7 @@ class SessionDelegate: NSObject, URLSessionDelegate {
17331761
private(set) var receivedData: Data?
17341762
private(set) var error: Error?
17351763
private(set) var response: URLResponse?
1764+
private(set) var redirectionRequest: URLRequest?
17361765
private(set) var redirectionResponse: HTTPURLResponse?
17371766
private(set) var callbacks: [String] = []
17381767
private(set) var authenticationChallenges: [URLAuthenticationChallenge] = []
@@ -1805,6 +1834,7 @@ extension SessionDelegate: URLSessionTaskDelegate {
18051834
// HTTP Redirect
18061835
public func urlSession(_ session: URLSession, task: URLSessionTask, willPerformHTTPRedirection response: HTTPURLResponse, newRequest request: URLRequest, completionHandler: @escaping (URLRequest?) -> Void) {
18071836
callbacks.append(#function)
1837+
redirectionRequest = request
18081838
redirectionResponse = response
18091839

18101840
if let handler = redirectionHandler {

0 commit comments

Comments
 (0)