Skip to content

AsyncHTTPClient Transaction StateMachine Fatal Error with large Response Bodies  #612

Closed
@rnantes

Description

@rnantes

When function try await response.body.collect(upTo: maxBodySize) is called where response is a HTTPClientResponse and maxBodySize = 1048576 (i.e 1 MB) and the response body is greater than 1MB then AsyncHTTPClient/Transaction+StateMachine fatal errors. I would expect that the function to throw but I wouldn't expect the fatal error.

example code:

let logger = Logger.init(label: "my-logger")

var config = HTTPClient.Configuration()
config.timeout =  HTTPClient.Configuration.Timeout.init(connect: .seconds(60), read: .seconds(30))
config.redirectConfiguration = HTTPClient.Configuration.RedirectConfiguration.follow(max: 20, allowCycles: true)
config.httpVersion = .automatic
config.decompression = .enabled(limit: .none)
config.connectionPool = ConnectionPool()

let httpClient = HTTPClient.init(eventLoopGroupProvider: .shared(eventLoopGroup),
                                             configuration: config,
                                             backgroundActivityLogger: logger)


var request = HTTPClientRequest.init(url: url)
request.method = .GET
let response = try await httpClient.execute(request, timeout: HTTPClientRequest.standardTimeout)
if !response.hasSuccessStatusCode() {
    throw SomeError.non200StatusCode
}

// Set a maxBodySize of 1 megabyte
let maxBodySize = 1024 * 1024

// This line  does throw as expected when the body is over 1MB in size but, unexpectedly it causes a fatal error
let body = try await response.body.collect(upTo: maxBodySize)

// This code is never reached
guard let bodyString = body.getString(at: 0, length: body.readableBytes) else {
    throw AsyncHTTPGetHelperError.couldNotReadStringFromResponseBody
}
return bodyString

This is the error I am seeing

2022-08-09T01:37:15-0400 error AsyncHTTPGetHelper : FAILED - NIOTooManyBytesError()
AsyncHTTPClient/Transaction+StateMachine.swift:699: Fatal error: Already received an eof or error before. Must not receive further events. Invalid state: executing(AsyncHTTPClient.Transaction.StateMachine.ExecutionContext(executor: AsyncHTTPClient.HTTP2ClientRequestHandler, allocator: NIOCore.ByteBufferAllocator(malloc: (Function), realloc: (Function), free: (Function), memcpy: (Function)), continuation: Swift.CheckedContinuation<AsyncHTTPClient.HTTPClientResponse, Swift.Error>(canary: Swift.CheckedContinuationCanary)), AsyncHTTPClient.Transaction.StateMachine.(unknown context at $12ba8a92c).RequestStreamState.finished, AsyncHTTPClient.Transaction.StateMachine.(unknown context at $12ba8a9ec).ResponseStreamState.buffering(AsyncHTTPClient.HTTPClientResponse.Body.IteratorStream.ID(objectID: ObjectIdentifier(0x0000600000260540)), [ _ _ _ _ _ _ _ <ByteBuffer { readerIndex: 0, writerIndex: 16384, readableBytes: 16384, capacity: 16384, storageCapacity: 16384, slice: _ByteBufferSlice { 0..<16384 }, storage: 0x000000010311bc00 (16384 bytes) } ByteBuffer { readerIndex: 0, writerIndex: 795, readableBytes: 795, capacity: 16384, storageCapacity: 16384, slice: _ByteBufferSlice { 0..<16384 }, storage: 0x000000010311fc00 (16384 bytes) } ByteBuffer { readerIndex: 0, writerIndex: 16384, readableBytes: 16384, capacity: 16384, storageCapacity: 16384, slice: _ByteBufferSlice { 0..<16384 }, storage: 0x0000000103123c00 (16384 bytes) } ByteBuffer { readerIndex: 0, writerIndex: 16384, readableBytes: 16384, capacity: 16384, storageCapacity: 16384, slice: _ByteBufferSlice { 0..<16384 }, storage: 0x0000000103127c00 (16384 bytes) } ByteBuffer { readerIndex: 0, writerIndex: 16335, readableBytes: 16335, capacity: 16384, storageCapacity: 16384, slice: _ByteBufferSlice { 0..<16384 }, storage: 0x000000010312bc00 (16384 bytes) } ByteBuffer { readerIndex: 0, writerIndex: 16384, readableBytes: 16384, capacity: 16384, storageCapacity: 16384, slice: _ByteBufferSlice { 0..<16384 }, storage: 0x000000010312fc00 (16384 bytes) } ByteBuffer { readerIndex: 0, writerIndex: 13934, readableBytes: 13934, capacity: 16384, storageCapacity: 16384, slice: _ByteBufferSlice { 0..<16384 }, storage: 0x00000001030d3c00 (16384 bytes) } >_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ ] (bufferCapacity: 32, ringLength: 7), next: AsyncHTTPClient.Transaction.StateMachine.(unknown context at $12ba8a9ec).ResponseStreamState.Next.error(HTTPClientError.cancelled)))
2022-08-09 01:37:15.490358-0400 xctest[60505:244935] AsyncHTTPClient/Transaction+StateMachine.swift:699: Fatal error: Already received an eof or error before. Must not receive further events. Invalid state: executing(AsyncHTTPClient.Transaction.StateMachine.ExecutionContext(executor: AsyncHTTPClient.HTTP2ClientRequestHandler, allocator: NIOCore.ByteBufferAllocator(malloc: (Function), realloc: (Function), free: (Function), memcpy: (Function)), continuation: Swift.CheckedContinuation<AsyncHTTPClient.HTTPClientResponse, Swift.Error>(canary: Swift.CheckedContinuationCanary)), AsyncHTTPClient.Transaction.StateMachine.(unknown context at $12ba8a92c).RequestStreamState.finished, AsyncHTTPClient.Transaction.StateMachine.(unknown context at $12ba8a9ec).ResponseStreamState.buffering(AsyncHTTPClient.HTTPClientResponse.Body.IteratorStream.ID(objectID: ObjectIdentifier(0x0000600000260540)), [ _ _ _ _ _ _ _ <ByteBuffer { readerIndex: 0, writerIndex: 16384, readableBytes: 16384, capacity: 16384, storageCapacity: 16384, slice: _ByteBufferSlice { 0..<16384 }, storage: 0x000000010311bc00 (16384 bytes) } ByteBuffer { readerIndex: 0, writerIndex: 795, readableBytes: 795, capacity: 16384, storageCapacity: 16384, slice: _ByteBufferSlice { 0..<16384 }, storage: 0x000000010311fc00 (16384 bytes) } ByteBuffer { readerIndex: 0, writerIndex: 16384, readableBytes: 16384, capacity: 16384, storageCapacity: 16384, slice: _ByteBufferSlice { 0..<16384 }, storage: 0x0000000103123c00 (16384 bytes) } ByteBuffer { readerIndex: 0, writerIndex: 16384, readableBytes: 16384, capacity: 16384, storageCapacity: 16384, slice: _ByteBufferSlice { 0..<16384 }, storage: 0x0000000103127c00 (16384 bytes) } ByteBuffer { readerIndex: 0, writerIndex: 16335, readableBytes: 16335, capacity: 16384, storageCapacity: 16384, slice: _ByteBufferSlice { 0..<16384 }, storage: 0x000000010312bc00 (16384 bytes) } ByteBuffer { readerIndex: 0, writerIndex: 16384, readableBytes: 16384, capacity: 16384, storageCapacity: 16384, slice: _ByteBufferSlice { 0..<16384 }, storage: 0x000000010312fc00 (16384 bytes) } ByteBuffer { readerIndex: 0, writerIndex: 13934, readableBytes: 13934, capacity: 16384, storageCapacity: 16384, slice: _ByteBufferSlice { 0..<16384 }, storage: 0x00000001030d3c00 (16384 bytes) } >_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ ] (bufferCapacity: 32, ringLength: 7), next: AsyncHTTPClient.Transaction.StateMachine.(unknown context at $12ba8a9ec).ResponseStreamState.Next.error(HTTPClientError.cancelled)))
Program ended with exit code: 9

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions