mirror of
https://github.com/swift-server/async-http-client.git
synced 2026-06-02 07:37:34 +00:00
ChannelRead because of closing connection: Remove preconditions (#430)
### Motivation NIO may send `channelRead` events without a handlers requesting more data with a `context.read()` invocation. This happens if the remote has closed the connection and NIO wants to inform the handlers as soon as possible. ### Changes - Don't `precondition` on `channelRead` events anymore. - Close channel if we received an http end without a `context.read()` invocation
This commit is contained in:
@@ -523,12 +523,22 @@ struct HTTPRequestStateMachine {
|
||||
where head.status.code < 300:
|
||||
|
||||
return self.avoidingStateMachineCoW { state -> Action in
|
||||
let remainingBuffer = responseStreamState.end()
|
||||
state = .running(
|
||||
.streaming(expectedBodyLength: expectedBodyLength, sentBodyBytes: sentBodyBytes, producer: producerState),
|
||||
.endReceived
|
||||
)
|
||||
return .forwardResponseBodyParts(remainingBuffer)
|
||||
let (remainingBuffer, connectionAction) = responseStreamState.end()
|
||||
switch connectionAction {
|
||||
case .none:
|
||||
state = .running(
|
||||
.streaming(expectedBodyLength: expectedBodyLength, sentBodyBytes: sentBodyBytes, producer: producerState),
|
||||
.endReceived
|
||||
)
|
||||
return .forwardResponseBodyParts(remainingBuffer)
|
||||
case .close:
|
||||
// If we receive a `.close` as a connectionAction from the responseStreamState
|
||||
// this means, that the response end was signaled by a connection close. Since
|
||||
// the request is still uploading, we will not be able to finish the upload. For
|
||||
// this reason we can fail the request here.
|
||||
state = .failed(HTTPClientError.remoteConnectionClosed)
|
||||
return .failRequest(HTTPClientError.remoteConnectionClosed, .close)
|
||||
}
|
||||
}
|
||||
|
||||
case .running(.streaming(_, _, let producerState), .receivingBody(let head, var responseStreamState)):
|
||||
@@ -536,16 +546,23 @@ struct HTTPRequestStateMachine {
|
||||
assert(producerState == .paused, "Expected to have paused the request body stream, when the head was received. Invalid state: \(self.state)")
|
||||
|
||||
return self.avoidingStateMachineCoW { state -> Action in
|
||||
let remainingBuffer = responseStreamState.end()
|
||||
// We can ignore the connectionAction from the responseStreamState, since the
|
||||
// connection should be closed anyway.
|
||||
let (remainingBuffer, _) = responseStreamState.end()
|
||||
state = .finished
|
||||
return .succeedRequest(.close, remainingBuffer)
|
||||
}
|
||||
|
||||
case .running(.endSent, .receivingBody(_, var responseStreamState)):
|
||||
return self.avoidingStateMachineCoW { state -> Action in
|
||||
let remainingBuffer = responseStreamState.end()
|
||||
let (remainingBuffer, action) = responseStreamState.end()
|
||||
state = .finished
|
||||
return .succeedRequest(.none, remainingBuffer)
|
||||
switch action {
|
||||
case .none:
|
||||
return .succeedRequest(.none, remainingBuffer)
|
||||
case .close:
|
||||
return .succeedRequest(.close, remainingBuffer)
|
||||
}
|
||||
}
|
||||
|
||||
case .running(_, .endReceived), .finished:
|
||||
|
||||
Reference in New Issue
Block a user