-
Notifications
You must be signed in to change notification settings - Fork 31
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add all Readdle's patches for swift-corelibs-foundation
- Loading branch information
1 parent
9d8188b
commit 0be9d85
Showing
13 changed files
with
1,625 additions
and
0 deletions.
There are no files selected for viewing
88 changes: 88 additions & 0 deletions
88
...relibs-foundation/0004-use-content-length-if-present-from-headers-for-streamed-body.patch
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
From 21ebccd585e465a40bfe1ed3f5fac38bdc8d289a Mon Sep 17 00:00:00 2001 | ||
From: Alexander Smarus <[email protected]> | ||
Date: Sat, 26 Sep 2020 17:35:23 +0300 | ||
Subject: [PATCH] Use content length, if present, from headers for streamed | ||
body | ||
|
||
Otherwise curl would switch to chunked transfer, which is | ||
not correct (see https://tools.ietf.org/html/rfc7230#section-3.3.2) | ||
--- | ||
.../URLSession/HTTP/HTTPURLProtocol.swift | 7 ++++- | ||
Tests/Foundation/HTTPServer.swift | 5 ++++ | ||
Tests/Foundation/TestURLSession.swift | 26 ++++++++++++++++++- | ||
3 files changed, 36 insertions(+), 2 deletions(-) | ||
|
||
diff --git a/Sources/FoundationNetworking/URLSession/HTTP/HTTPURLProtocol.swift b/Sources/FoundationNetworking/URLSession/HTTP/HTTPURLProtocol.swift | ||
index 90a19611..a00eec13 100644 | ||
--- a/Sources/FoundationNetworking/URLSession/HTTP/HTTPURLProtocol.swift | ||
+++ b/Sources/FoundationNetworking/URLSession/HTTP/HTTPURLProtocol.swift | ||
@@ -342,7 +342,12 @@ internal class _HTTPURLProtocol: _NativeProtocol { | ||
set(requestBodyLength: .length(length)) | ||
task!.countOfBytesExpectedToSend = Int64(length) | ||
case (_, nil): | ||
- set(requestBodyLength: .unknown) | ||
+ if let contentLengthValue = request.value(forHTTPHeaderField: "Content-Length"), let contentLength = UInt64(contentLengthValue) { | ||
+ set(requestBodyLength: .length(contentLength)) | ||
+ task!.countOfBytesExpectedToSend = Int64(contentLength) | ||
+ } else { | ||
+ set(requestBodyLength: .unknown) | ||
+ } | ||
} | ||
} catch let e { | ||
// Fail the request here. | ||
diff --git a/Tests/Foundation/HTTPServer.swift b/Tests/Foundation/HTTPServer.swift | ||
index 96d849f2..07f3f07a 100644 | ||
--- a/Tests/Foundation/HTTPServer.swift | ||
+++ b/Tests/Foundation/HTTPServer.swift | ||
@@ -742,6 +742,11 @@ public class TestURLSessionServer: CustomStringConvertible { | ||
} | ||
|
||
if uri == "/upload" { | ||
+ if request.getHeader(for: "transfer-encoding") != nil && request.getHeader(for: "content-length") != nil { | ||
+ // https://tools.ietf.org/html/rfc7230#section-3.3.2 | ||
+ // A sender MUST NOT send a Content-Length header field in any message that contains a Transfer-Encoding header field. | ||
+ return try _HTTPResponse(response: .BAD_REQUEST, body: "Content-Length not allowed with Transfer-Encoding") | ||
+ } | ||
if let contentLength = request.getHeader(for: "content-length") { | ||
let text = "Upload completed!, Content-Length: \(contentLength)" | ||
return try _HTTPResponse(response: .OK, body: text) | ||
diff --git a/Tests/Foundation/TestURLSession.swift b/Tests/Foundation/TestURLSession.swift | ||
index 9f202151..14a810ff 100644 | ||
--- a/Tests/Foundation/TestURLSession.swift | ||
+++ b/Tests/Foundation/TestURLSession.swift | ||
@@ -135,7 +135,31 @@ final class TestURLSession: LoopbackServerTest, @unchecked Sendable { | ||
XCTAssertEqual("London", result, "Did not receive expected value") | ||
XCTAssertEqual("London", delegate.capital) | ||
} | ||
- | ||
+ | ||
+ func test_dataTaskWithHttpInputStreamContentLength() throws { | ||
+ let urlString = "http://127.0.0.1:\(TestURLSession.serverPort)/upload" | ||
+ let url = try XCTUnwrap(URL(string: urlString)) | ||
+ | ||
+ let dataString = "<?xml version=\"1.0\" encoding=\"utf-8\"?><soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:m=\"http://schemas.microsoft.com/exchange/services/2006/messages\" xmlns:t=\"http://schemas.microsoft.com/exchange/services/2006/types\"><soap:Body><m:SyncFolderHierarchy><m:FolderShape><t:BaseShape>IdOnly</t:BaseShape></m:FolderShape></m:SyncFolderHierarchy></soap:Body></soap:Envelope>" | ||
+ | ||
+ let data = try XCTUnwrap(dataString.data(using: .utf8)) | ||
+ | ||
+ var urlRequest = URLRequest(url: url) | ||
+ urlRequest.httpMethod = "POST" | ||
+ urlRequest.httpBodyStream = InputStream(data: data) | ||
+ urlRequest.setValue("\(data.count)", forHTTPHeaderField: "Content-Length") | ||
+ | ||
+ let delegate = SessionDelegate(with: expectation(description: "POST \(urlString): with HTTP Body as InputStream")) | ||
+ delegate.run(with: urlRequest, timeoutInterval: 3) | ||
+ waitForExpectations(timeout: 4) | ||
+ | ||
+ let httpResponse = delegate.response as? HTTPURLResponse | ||
+ | ||
+ XCTAssertNil(delegate.error) | ||
+ XCTAssertNotNil(delegate.response) | ||
+ XCTAssertEqual(httpResponse?.statusCode, 200) | ||
+ } | ||
+ | ||
func test_dataTaskWithHttpInputStream() async throws { | ||
throw XCTSkip("This test is disabled (Flaky test)") | ||
#if false | ||
-- | ||
2.46.0 | ||
|
121 changes: 121 additions & 0 deletions
121
...n/0005-request-new-stream-when-restarting-request due-to-redirect-or-auth-challenge.patch
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,121 @@ | ||
From f4b8709e72f6b83c622cec71eeef1cdc81500ca5 Mon Sep 17 00:00:00 2001 | ||
From: Alexander Smarus <[email protected]> | ||
Date: Sat, 26 Sep 2020 19:29:21 +0300 | ||
Subject: [PATCH] Request new stream when restarting request due to redirect or | ||
auth challenge | ||
|
||
This matches Darwin behavior. Otherwise _BodyStreamSource will have nothing to read. | ||
--- | ||
.../URLSession/HTTP/HTTPURLProtocol.swift | 4 +- | ||
.../URLSession/URLSessionTask.swift | 4 +- | ||
Tests/Foundation/TestURLSession.swift | 57 +++++++++++++++++++ | ||
3 files changed, 62 insertions(+), 3 deletions(-) | ||
|
||
diff --git a/Sources/FoundationNetworking/URLSession/HTTP/HTTPURLProtocol.swift b/Sources/FoundationNetworking/URLSession/HTTP/HTTPURLProtocol.swift | ||
index a00eec13..dfe18758 100644 | ||
--- a/Sources/FoundationNetworking/URLSession/HTTP/HTTPURLProtocol.swift | ||
+++ b/Sources/FoundationNetworking/URLSession/HTTP/HTTPURLProtocol.swift | ||
@@ -502,7 +502,7 @@ internal class _HTTPURLProtocol: _NativeProtocol { | ||
} else { | ||
// Follow the redirect. Need to configure new request with cookies, etc. | ||
let configuredRequest = session._configuration.configure(request: request) | ||
- task?.knownBody = URLSessionTask._Body.none | ||
+ task?.knownBody = nil | ||
startNewTransfer(with: configuredRequest) | ||
} | ||
} | ||
@@ -714,7 +714,7 @@ extension _HTTPURLProtocol { | ||
// Otherwise, we'll start a new transfer with the passed in request. | ||
if let r = request { | ||
lastRedirectBody = nil | ||
- task?.knownBody = URLSessionTask._Body.none | ||
+ task!.knownBody = nil | ||
startNewTransfer(with: r) | ||
} else { | ||
// If the redirect is not followed, return the redirect itself as the response | ||
diff --git a/Sources/FoundationNetworking/URLSession/URLSessionTask.swift b/Sources/FoundationNetworking/URLSession/URLSessionTask.swift | ||
index 4968494b..76ebb561 100644 | ||
--- a/Sources/FoundationNetworking/URLSession/URLSessionTask.swift | ||
+++ b/Sources/FoundationNetworking/URLSession/URLSessionTask.swift | ||
@@ -1258,7 +1258,9 @@ extension _ProtocolClient : URLProtocolClient { | ||
} | ||
task._protocolStorage = .existing(_HTTPURLProtocol(task: task, cachedResponse: nil, client: nil)) | ||
} | ||
- | ||
+ if case .stream(let stream) = task.knownBody, stream.streamStatus != .notOpen { | ||
+ task.knownBody = nil | ||
+ } | ||
task.resume() | ||
} | ||
|
||
diff --git a/Tests/Foundation/TestURLSession.swift b/Tests/Foundation/TestURLSession.swift | ||
index 14a810ff..32dfd0d2 100644 | ||
--- a/Tests/Foundation/TestURLSession.swift | ||
+++ b/Tests/Foundation/TestURLSession.swift | ||
@@ -1738,6 +1738,63 @@ final class TestURLSession: LoopbackServerTest, @unchecked Sendable { | ||
waitForExpectations(timeout: 60) | ||
} | ||
|
||
+ func test_basicAuthRequestWithBodyStream() throws { | ||
+ let dataString = "<?xml version=\"1.0\" encoding=\"utf-8\"?><soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:m=\"http://schemas.microsoft.com/exchange/services/2006/messages\" xmlns:t=\"http://schemas.microsoft.com/exchange/services/2006/types\"><soap:Body><m:SyncFolderHierarchy><m:FolderShape><t:BaseShape>IdOnly</t:BaseShape></m:FolderShape></m:SyncFolderHierarchy></soap:Body></soap:Envelope>" | ||
+ let data = try XCTUnwrap(dataString.data(using: .utf8)) | ||
+ let expectedCallbacks = [ | ||
+ "urlSession(_:task:didSendBodyData:totalBytesSent:totalBytesExpectedToSend:)", | ||
+ "urlSession(_:dataTask:didReceive:completionHandler:)", | ||
+ "urlSession(_:task:didReceive:completionHandler:)", | ||
+ "urlSession(_:task:needNewBodyStream:)", | ||
+ "urlSession(_:task:didSendBodyData:totalBytesSent:totalBytesExpectedToSend:)", | ||
+ "urlSession(_:dataTask:didReceive:completionHandler:)", | ||
+ "urlSession(_:dataTask:didReceive:)", | ||
+ "urlSession(_:task:didCompleteWithError:)" | ||
+ ] | ||
+ | ||
+ let urlString = "http://127.0.0.1:\(TestURLSession.serverPort)/auth/basic" | ||
+ let url = URL(string: urlString)! | ||
+ var urlRequest = URLRequest(url: url) | ||
+ urlRequest.httpMethod = "POST" | ||
+ urlRequest.httpBodyStream = InputStream(data: data) | ||
+ let delegate = SessionDelegate(with: expectation(description: "POST \(urlString): Upload data")) | ||
+ delegate.newBodyStreamHandler = { (completionHandler: @escaping (InputStream?) -> Void) in | ||
+ completionHandler(InputStream(data: data)) | ||
+ } | ||
+ delegate.challengeHandler = { (challenge: URLAuthenticationChallenge) -> (disposition: URLSession.AuthChallengeDisposition, credetial: URLCredential?) in | ||
+ return (.useCredential, URLCredential(user: "user", password: "passwd", persistence: .none)) | ||
+ } | ||
+ delegate.run(with: urlRequest, timeoutInterval: 4) | ||
+ waitForExpectations(timeout: 5) | ||
+ XCTAssertEqual(delegate.callbacks, expectedCallbacks) | ||
+ XCTAssertEqual(delegate.authenticationChallenges.count, 1) | ||
+ } | ||
+ | ||
+ func test_httpRedirectionWithBodyStream() throws { | ||
+ let dataString = "Quando l'accento divide il tempo in gruppi di due movimenti, il tempo si dice binario" | ||
+ let data = try XCTUnwrap(dataString.data(using: .utf8)) | ||
+ let expectedCallbacks: [String] = [ | ||
+ "urlSession(_:task:didSendBodyData:totalBytesSent:totalBytesExpectedToSend:)", | ||
+ "urlSession(_:task:willPerformHTTPRedirection:newRequest:completionHandler:)", | ||
+ "urlSession(_:task:needNewBodyStream:)", | ||
+ "urlSession(_:task:didCompleteWithError:)" | ||
+ ] | ||
+ | ||
+ let urlString = "http://127.0.0.1:\(TestURLSession.serverPort)/301?location=jsonBody" | ||
+ let url = URL(string: urlString)! | ||
+ var urlRequest = URLRequest(url: url) | ||
+ urlRequest.httpMethod = "POST" | ||
+ urlRequest.httpBodyStream = InputStream(data: data) | ||
+ let delegate = SessionDelegate(with: expectation(description: "POST \(urlString): Redirection")) | ||
+ delegate.newBodyStreamHandler = { (completionHandler: @escaping (InputStream?) -> Void) in | ||
+ completionHandler(InputStream(data: data)) | ||
+ } | ||
+ delegate.run(with: urlRequest, timeoutInterval: 4) | ||
+ waitForExpectations(timeout: 5) | ||
+ XCTAssertEqual(delegate.callbacks, expectedCallbacks) | ||
+ XCTAssertEqual(delegate.redirectionResponse?.value(forHTTPHeaderField: "Location"), "jsonBody") | ||
+ } | ||
+ | ||
/* Test for SR-8970 to verify that content-type header is not added to post with empty body */ | ||
func test_postWithEmptyBody() async { | ||
let config = URLSessionConfiguration.default | ||
-- | ||
2.46.0 | ||
|
Oops, something went wrong.