Environment
swift:latest under Docker
Additional Detail from JIRA
| | |
|------------------|-----------------|
|Votes | 0 |
|Component/s | Foundation |
|Labels | Bug |
|Assignee | None |
|Priority | Medium |
md5: 4f4549269b510d966b4ce51d1a0e3c16
Issue Description:
This is a behavior difference from macOS Foundation. This bug is reproducible on Linux, but not on other Apple platforms like iOS or macOS.
URLProtocols typically have access to the httpBody or httpBodyStream. Below shows an example of how to retrieve the body of an upload task.
import Foundation
#if canImport(FoundationNetworking)
import FoundationNetworking
#endif
class TestProtocol: URLProtocol {
override class func canInit(with task: URLSessionTask) -> Bool {
return true
}
override class func canInit(with request: URLRequest) -> Bool {
return true
}
override class func canonicalRequest(for request: URLRequest) -> URLRequest {
return request
}
override func startLoading() {
//one of these should be populated with non nil data
let body = request.httpBody
let steam = request.httpBodyStream
client?.urlProtocol(self, didFailWithError: NSError())
}
override func stopLoading() {
}
}
let configuration = URLSessionConfiguration.ephemeral
configuration.protocolClasses = [TestProtocol.self]
let session = URLSession(configuration: configuration)
var request = URLRequest(url: URL(string: "http://apple.com")!)
request.httpMethod = "POST"
let contents = "Hello Apple"
let task = session.uploadTask(with: request, from: contents.data(using: .utf8)!) { _, _, error in
}
task.resume()
On Linux, neither body or stream is ever populated.
This seems to be linked to how Swift Foundation handles body data. On macOS, the request passed to the URLProtocol is altered to include the body data, even if the body data originated from the uploadTask call and wasn't directly populated in the request.
In SwiftFoundation, the body data is shunted into an internal member of URLSessionTask named knownBody. knownBody is then accessible using the internal getBody function. HTTPURLProtocol makes use of the internal getBody function to upload data as part of a POST.
There are several ramifications of the body data not being available:
URLProtocol is one of the best ways to mock URLSession for unit testing. These tests will fail on SwiftFoundation platforms. (This is the case I hit.)
It's impossible to build a custom URLProtocol outside of SwiftFoundation that works reliably with upload data. I can't find a way that the URLProtocol would have access to the data that is to be uploaded in a public way.
There's a behavior difference from Apple platforms.
My proposal would be that the request given to the URLRequest should be populated to match Apple Foundation behavior. Changes could be introduced to classes HTTPURLProtocol to migrate over to a public supported URLRequest version of fetching data, instead of using the internal getBody function.
Environment
swift:latest under DockerAdditional Detail from JIRA
| | | |------------------|-----------------| |Votes | 0 | |Component/s | Foundation | |Labels | Bug | |Assignee | None | |Priority | Medium | md5: 4f4549269b510d966b4ce51d1a0e3c16Issue Description:
This is a behavior difference from macOS Foundation. This bug is reproducible on Linux, but not on other Apple platforms like iOS or macOS.
URLProtocols typically have access to the httpBody or httpBodyStream. Below shows an example of how to retrieve the body of an upload task.
On Linux, neither body or stream is ever populated.
This seems to be linked to how Swift Foundation handles body data. On macOS, the request passed to the URLProtocol is altered to include the body data, even if the body data originated from the uploadTask call and wasn't directly populated in the request.
In SwiftFoundation, the body data is shunted into an internal member of URLSessionTask named knownBody. knownBody is then accessible using the internal getBody function. HTTPURLProtocol makes use of the internal getBody function to upload data as part of a POST.
There are several ramifications of the body data not being available:
URLProtocol is one of the best ways to mock URLSession for unit testing. These tests will fail on SwiftFoundation platforms. (This is the case I hit.)
It's impossible to build a custom URLProtocol outside of SwiftFoundation that works reliably with upload data. I can't find a way that the URLProtocol would have access to the data that is to be uploaded in a public way.
There's a behavior difference from Apple platforms.
My proposal would be that the request given to the URLRequest should be populated to match Apple Foundation behavior. Changes could be introduced to classes HTTPURLProtocol to migrate over to a public supported URLRequest version of fetching data, instead of using the internal getBody function.