Skip to content

Commit 8f08574

Browse files
authored
Merge pull request #2948 from agisboye/master
2 parents 7b1cc20 + 26e5f80 commit 8f08574

File tree

3 files changed

+43
-31
lines changed

3 files changed

+43
-31
lines changed

Sources/FoundationNetworking/URLSession/HTTP/HTTPURLProtocol.swift

+25-30
Original file line numberDiff line numberDiff line change
@@ -485,6 +485,7 @@ internal class _HTTPURLProtocol: _NativeProtocol {
485485
case .noDelegate, .dataCompletionHandler, .downloadCompletionHandler:
486486
// Follow the redirect. Need to configure new request with cookies, etc.
487487
let configuredRequest = session._configuration.configure(request: request)
488+
task?.knownBody = URLSessionTask._Body.none
488489
startNewTransfer(with: configuredRequest)
489490
}
490491
}
@@ -597,6 +598,7 @@ extension _HTTPURLProtocol {
597598
// Otherwise, we'll start a new transfer with the passed in request.
598599
if let r = request {
599600
lastRedirectBody = nil
601+
task?.knownBody = URLSessionTask._Body.none
600602
startNewTransfer(with: r)
601603
} else {
602604
// If the redirect is not followed, return the redirect itself as the response
@@ -649,38 +651,31 @@ internal extension _HTTPURLProtocol {
649651
/// - SeeAlso: <https://tools.ietf.org/html/rfc7231#section-6.4>
650652
func redirectRequest(for response: HTTPURLResponse, fromRequest: URLRequest) -> URLRequest? {
651653
//TODO: Do we ever want to redirect for HEAD requests?
652-
func methodAndURL() -> (String, URL)? {
653-
guard
654-
let location = response.value(forHeaderField: .location),
655-
let targetURL = URL(string: location)
656-
else {
657-
// Can't redirect when there's no location to redirect to.
658-
return nil
659-
}
660-
661-
let method = fromRequest.httpMethod ?? "GET"
662-
// Check for a redirect:
663-
switch response.statusCode {
664-
case 301, 302:
665-
// Change "POST" into "GET" but leave other methods unchanged:
666-
let newMethod = (method == "POST") ? "GET" : method
667-
return (newMethod, targetURL)
668-
669-
case 303:
670-
return ("GET", targetURL)
671-
672-
case 305...308:
673-
// Re-use existing method:
674-
return (method, targetURL)
675-
676-
default:
677-
return nil
678-
}
654+
655+
guard
656+
let location = response.value(forHeaderField: .location),
657+
let targetURL = URL(string: location)
658+
else {
659+
// Can't redirect when there's no location to redirect to.
660+
return nil
679661
}
680-
681-
guard let (method, targetURL) = methodAndURL() else { return nil }
662+
682663
var request = fromRequest
683-
request.httpMethod = method
664+
665+
// Check for a redirect:
666+
switch response.statusCode {
667+
case 301...302 where request.httpMethod == "POST", 303:
668+
// Change "POST" into "GET" but leave other methods unchanged:
669+
request.httpMethod = "GET"
670+
request.httpBody = nil
671+
672+
case 301...302, 305...308:
673+
// Re-use existing method:
674+
break
675+
676+
default:
677+
return nil
678+
}
684679

685680
// If targetURL has only relative path of url, create a new valid url with relative path
686681
// Otherwise, return request with targetURL ie.url from location field

Sources/FoundationNetworking/URLSession/URLSessionTask.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,7 @@ open class URLSessionTask : NSObject, NSCopying {
200200
}
201201

202202

203-
internal let knownBody: _Body?
203+
internal var knownBody: _Body?
204204
func getBody(completion: @escaping (_Body) -> Void) {
205205
if let body = knownBody {
206206
completion(body)

Tests/Foundation/Tests/TestURLSession.swift

+17
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,22 @@ class TestURLSession: LoopbackServerTest {
174174
}
175175
}
176176
}
177+
178+
func test_dataTaskWithHTTPBodyRedirect() {
179+
let urlString = "http://127.0.0.1:\(TestURLSession.serverPort)/303?location=Peru"
180+
let url = URL(string: urlString)!
181+
let parameters = "foo=bar"
182+
var postRequest = URLRequest(url: url)
183+
postRequest.httpBody = parameters.data(using: .utf8)
184+
postRequest.httpMethod = "POST"
185+
186+
let d = HTTPRedirectionDataTask(with: expectation(description: "POST \(urlString): with HTTP redirection"))
187+
d.run(with: postRequest)
188+
189+
waitForExpectations(timeout: 12)
190+
191+
XCTAssertEqual("Lima", String(data: d.receivedData, encoding: .utf8), "\(#function) did not redirect properly.")
192+
}
177193

178194
func test_gzippedDataTask() {
179195
let urlString = "http://127.0.0.1:\(TestURLSession.serverPort)/gzipped-response"
@@ -1764,6 +1780,7 @@ class TestURLSession: LoopbackServerTest {
17641780
("test_dataTaskWithURLCompletionHandler", test_dataTaskWithURLCompletionHandler),
17651781
("test_dataTaskWithURLRequestCompletionHandler", test_dataTaskWithURLRequestCompletionHandler),
17661782
// ("test_dataTaskWithHttpInputStream", test_dataTaskWithHttpInputStream), - Flaky test
1783+
("test_dataTaskWithHTTPBodyRedirect", test_dataTaskWithHTTPBodyRedirect),
17671784
("test_gzippedDataTask", test_gzippedDataTask),
17681785
("test_downloadTaskWithURL", test_downloadTaskWithURL),
17691786
("test_downloadTaskWithURLRequest", test_downloadTaskWithURLRequest),

0 commit comments

Comments
 (0)