Skip to content

Commit df9b524

Browse files
committed
fix bodyLengthMissmatch error handling
1 parent 6426c00 commit df9b524

File tree

2 files changed

+28
-3
lines changed

2 files changed

+28
-3
lines changed

Diff for: Sources/AsyncHTTPClient/ConnectionPool/HTTPRequestStateMachine.swift

+3-3
Original file line numberDiff line numberDiff line change
@@ -198,14 +198,14 @@ struct HTTPRequestStateMachine {
198198
self.state = .failed(error)
199199
return .failRequest(error, .none)
200200

201-
case .running(.streaming, .waitingForHead),
201+
case .running(.streaming, .waitingForHead) where error as? NIOSSLError == .uncleanShutdown,
202202
.running(.endSent, .waitingForHead) where error as? NIOSSLError == .uncleanShutdown:
203203
// if we received a NIOSSL.uncleanShutdown before we got an answer we should handle
204204
// this like a normal connection close. We will receive a call to channelInactive after
205205
// this error.
206206
return .wait
207207

208-
case .running(.streaming, .receivingBody(let responseHead, _)),
208+
case .running(.streaming, .receivingBody(let responseHead, _)) where error as? NIOSSLError == .uncleanShutdown,
209209
.running(.endSent, .receivingBody(let responseHead, _)) where error as? NIOSSLError == .uncleanShutdown:
210210
// This code is only reachable for request and responses, which we expect to have a body.
211211
// We depend on logic from the HTTPResponseDecoder here. The decoder will emit an
@@ -270,7 +270,7 @@ struct HTTPRequestStateMachine {
270270

271271
if let expected = expectedBodyLength, sentBodyBytes + part.readableBytes > expected {
272272
let error = HTTPClientError.bodyLengthMismatch
273-
273+
self.state = .failed(error)
274274
return .failRequest(error, .close)
275275
}
276276

Diff for: Tests/AsyncHTTPClientTests/HTTPRequestStateMachineTests.swift

+25
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,9 @@ class HTTPRequestStateMachineTests: XCTestCase {
8282
}
8383

8484
XCTAssertEqual(error as? HTTPClientError, .bodyLengthMismatch)
85+
86+
// if another error happens the new one is ignored
87+
XCTAssertEqual(state.errorHappened(HTTPClientError.remoteConnectionClosed), .wait)
8588
}
8689

8790
func testPOSTContentLengthIsTooShort() {
@@ -521,6 +524,28 @@ class HTTPRequestStateMachineTests: XCTestCase {
521524
XCTAssertEqual(state.channelRead(.end(nil)), .wait)
522525
XCTAssertEqual(state.channelInactive(), .wait)
523526
}
527+
528+
func testNIOSSLErrorUncleanShutdownShouldBeTreatedAsRemoteConnectionCloseWhileInWaitingForHeadState() {
529+
var state = HTTPRequestStateMachine(isChannelWritable: true)
530+
let requestHead = HTTPRequestHead(version: .http1_1, method: .GET, uri: "/")
531+
let metadata = RequestFramingMetadata(connectionClose: false, body: .fixedSize(0))
532+
XCTAssertEqual(state.startRequest(head: requestHead, metadata: metadata), .sendRequestHead(requestHead, startBody: false))
533+
534+
XCTAssertEqual(state.errorHappened(NIOSSLError.uncleanShutdown), .wait)
535+
XCTAssertEqual(state.channelInactive(), .failRequest(HTTPClientError.remoteConnectionClosed, .none))
536+
}
537+
538+
539+
func testArbitraryErrorShouldBeTreatedAsARequestFailureWhileInWaitingForHeadState() {
540+
struct ArbitraryError: Error {}
541+
var state = HTTPRequestStateMachine(isChannelWritable: true)
542+
let requestHead = HTTPRequestHead(version: .http1_1, method: .GET, uri: "/")
543+
let metadata = RequestFramingMetadata(connectionClose: false, body: .fixedSize(0))
544+
XCTAssertEqual(state.startRequest(head: requestHead, metadata: metadata), .sendRequestHead(requestHead, startBody: false))
545+
546+
XCTAssertEqual(state.errorHappened(ArbitraryError()), .failRequest(ArbitraryError(), .close))
547+
XCTAssertEqual(state.channelInactive(), .wait)
548+
}
524549

525550
func testFailHTTP1RequestWithContentLengthWithNIOSSLErrorUncleanShutdownButIgnoreIt() {
526551
var state = HTTPRequestStateMachine(isChannelWritable: true)

0 commit comments

Comments
 (0)