Skip to content

Commit c452e23

Browse files
authored
Merge pull request #2744 from spevans/pr_url_redirect_fixes
URLSession: Fix redirection response handling
2 parents 3949db6 + a40e5e6 commit c452e23

File tree

3 files changed

+272
-35
lines changed

3 files changed

+272
-35
lines changed

Sources/FoundationNetworking/URLSession/HTTP/HTTPURLProtocol.swift

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -401,9 +401,8 @@ internal class _HTTPURLProtocol: _NativeProtocol {
401401
easyHandle.timeoutTimer = _TimeoutSource(queue: task.workQueue, milliseconds: timeoutInterval, handler: timeoutHandler)
402402
easyHandle.set(automaticBodyDecompression: true)
403403
easyHandle.set(requestMethod: request.httpMethod ?? "GET")
404-
if request.httpMethod == "HEAD" {
405-
easyHandle.set(noBody: true)
406-
}
404+
// Always set the status as it may change if a HEAD is converted to a GET.
405+
easyHandle.set(noBody: request.httpMethod == "HEAD")
407406
}
408407

409408
/// What action to take
@@ -591,7 +590,7 @@ internal extension _HTTPURLProtocol {
591590
// For now, we'll notify the delegate, but won't pause the transfer,
592591
// and we'll disregard the completion handler:
593592
switch response.statusCode {
594-
case 301, 302, 303, 307:
593+
case 301, 302, 303, 305...308:
595594
break
596595
default:
597596
self.client?.urlProtocol(self, didReceive: response, cacheStoragePolicy: .notAllowed)
@@ -619,19 +618,26 @@ internal extension _HTTPURLProtocol {
619618
return nil
620619
}
621620

621+
let method = fromRequest.httpMethod ?? "GET"
622622
// Check for a redirect:
623623
switch response.statusCode {
624-
//TODO: Should we do this for 300 "Multiple Choices", too?
625-
case 301, 302, 303:
626-
// Change into "GET":
627-
return ("GET", targetURL)
628-
case 307:
629-
// Re-use existing method:
630-
return (fromRequest.httpMethod ?? "GET", targetURL)
631-
default:
632-
return nil
624+
case 301, 302:
625+
// Change "POST" into "GET" but leave other methods unchanged:
626+
let newMethod = (method == "POST") ? "GET" : method
627+
return (newMethod, targetURL)
628+
629+
case 303:
630+
return ("GET", targetURL)
631+
632+
case 305...308:
633+
// Re-use existing method:
634+
return (method, targetURL)
635+
636+
default:
637+
return nil
633638
}
634639
}
640+
635641
guard let (method, targetURL) = methodAndURL() else { return nil }
636642
var request = fromRequest
637643
request.httpMethod = method

Sources/FoundationNetworking/URLSession/NativeProtocol.swift

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,13 @@ internal class _NativeProtocol: URLProtocol, _EasyHandleDelegate {
102102
if let response = validateHeaderComplete(transferState:ts) {
103103
ts.response = response
104104
}
105+
106+
// Note this excludes code 300 which should return the response of the redirect and not follow it.
107+
// For other redirect codes dont notify the delegate of the data received in the redirect response.
108+
if let httpResponse = ts.response as? HTTPURLResponse, 301...308 ~= httpResponse.statusCode {
109+
return .proceed
110+
}
111+
105112
notifyDelegate(aboutReceivedData: data)
106113
internalState = .transferInProgress(ts.byAppending(bodyData: data))
107114
return .proceed

0 commit comments

Comments
 (0)