Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,9 @@ final class HTTPBodyOutputStreamBridge: NSObject, StreamDelegate {
let task = Task {
dispatchPrecondition(condition: .notOnQueue(Self.streamQueue))
for try await chunk in httpBody {
// Empty chunks are legal HTTPBody values (for example text/plain "")
// but OutputStream cannot be written with a zero length buffer.
guard !chunk.isEmpty else { continue }
try await withCheckedThrowingContinuation { continuation in
Self.streamQueue.async {
debug("Output stream delegate produced chunk and suspended producer.")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,35 @@ class HTTPBodyOutputStreamBridgeTests: XCTestCase {
)
}

func testHTTPBodyOutputStreamEmptyChunkDoesNotCrash() async throws {
let emptyChunks: [[UInt8]] = [[]]
let requestByteSequence = MockAsyncSequence(elementsToVend: emptyChunks, gatingProduction: false)
let requestBody = HTTPBody(requestByteSequence, length: .known(0), iterationBehavior: .single)

var inputStream: InputStream?
var outputStream: OutputStream?
Stream.getBoundStreams(withBufferSize: 16, inputStream: &inputStream, outputStream: &outputStream)
guard let inputStream, let outputStream else { fatalError("getBoundStreams did not return non-nil streams") }

let requestStream = HTTPBodyOutputStreamBridge(outputStream, requestBody)
let delegate = MockInputStreamDelegate(inputStream: inputStream)

var data = [UInt8]()
while let inputStreamBytes = try await delegate.waitForBytes(maxBytes: 4096) {
data.append(contentsOf: inputStreamBytes)
}
XCTAssertEqual(data, [])
XCTAssertEqual(inputStream.streamStatus, .closed)
XCTAssertNil(inputStream.streamError)

HTTPBodyOutputStreamBridge.streamQueue.asyncAndWait(
execute: DispatchWorkItem {
XCTAssertEqual(requestStream.outputStream.streamStatus, .closed)
XCTAssertNil(requestStream.outputStream.streamError)
}
)
}

func testHTTPBodyOutputStreamBridgeBackpressure() async throws {
let chunkSize = 71
let streamBufferSize = 37
Expand Down
Loading