Skip to content

bi-directional streaming broken #327

Closed
@weissi

Description

@weissi

AsyncHTTPClient can no longer stream bi-directionally since commit f69b68f . When being bed the body, it throws a HTTPClientError.writeAfterRequestSent.

The problem is this code

    private func writeBodyPart(context: ChannelHandlerContext, part: IOData, promise: EventLoopPromise<Void>) {
        switch self.state {
        case .idle:
            if let limit = self.expectedBodyLength, self.actualBodyLength + part.readableBytes > limit {
                let error = HTTPClientError.bodyLengthMismatch
                self.state = .endOrError
                self.failTaskAndNotifyDelegate(error: error, self.delegate.didReceiveError)
                promise.fail(error)
                return
            }
            self.actualBodyLength += part.readableBytes
            context.writeAndFlush(self.wrapOutboundOut(.body(part)), promise: promise)
        default:
            let error = HTTPClientError.writeAfterRequestSent
            self.state = .endOrError
            self.failTaskAndNotifyDelegate(error: error, self.delegate.didReceiveError)
            promise.fail(error)
        }
    }

So we only accept bytes for the body in state .idle but whilst streaming bi-directionally we can be in state .body which makes AHC then wrongly reject the bytes.

Test case:

If you swift run the repository at https://github.com/weissi/HTTPBidiStreamingExamples it will work.

If you however edit its Package.swift and change

.package(url: "https://github.com/swift-server/async-http-client.git", .revision("2e6a64abb31fbc2d51da3919b0d8b35a6c7dc0b5")),

to

    .package(url: "https://github.com/swift-server/async-http-client.git", from: "1.2.3")),

then it'll fail. How can I tell if it worked? If you grep for all the output lines that contain Final result, what you should see is

2021-01-18T21:15:38+0000 info bidi-streaming.driver : driver=client: urlSession, server: swiftNIO Final result: ✅ OK
2021-01-18T21:15:38+0000 info bidi-streaming.driver : driver=client: asyncHTTPClient, server: swiftNIO Final result: ✅ OK
2021-01-18T21:15:38+0000 info bidi-streaming.driver : driver=client: urlSession, server: vapor Final result: ✅ OK
2021-01-18T21:15:38+0000 info bidi-streaming.driver : driver=client: asyncHTTPClient, server: vapor Final result: ✅ OK

but if you select the latest AHC, you'll see

2021-01-18T21:17:10+0000 info bidi-streaming.driver : driver=client: urlSession, server: swiftNIO Final result: ✅ OK
2021-01-18T21:17:10+0000 error bidi-streaming.driver : driver=client: asyncHTTPClient, server: swiftNIO Final result: ❌ ERROR: HTTPClientError.writeAfterRequestSent
2021-01-18T21:17:10+0000 info bidi-streaming.driver : driver=client: urlSession, server: vapor Final result: ✅ OK
2021-01-18T21:17:10+0000 error bidi-streaming.driver : driver=client: asyncHTTPClient, server: vapor Final result: ❌ ERROR: HTTPClientError.writeAfterRequestSent

As you can see: URLSession works and AHC fails against both NIO and Vapor.

Metadata

Metadata

Assignees

Labels

kind/bugFeature doesn't work as expected.

Type

No type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions