Skip to content
Merged
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 @@ -376,8 +376,6 @@ struct HTTPRequestStateMachine {
.streaming(let expectedBodyLength, let sentBodyBytes, _),
.receivingBody(let head, let streamState)
):
assert(head.status.code < 300)

if let expected = expectedBodyLength, expected != sentBodyBytes {
let error = HTTPClientError.bodyLengthMismatch
self.state = .failed(error)
Expand Down
36 changes: 36 additions & 0 deletions Tests/AsyncHTTPClientTests/HTTPRequestStateMachineTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,42 @@ class HTTPRequestStateMachineTests: XCTestCase {
XCTAssertEqual(state.channelRead(.end(nil)), .forwardResponseEnd(.requestDone, [], nil))
}

func testRequestBodyStreamFinishedAfterServerSentHeadWithStatus413() {
var state = HTTPRequestStateMachine(isChannelWritable: true)
let requestHead = HTTPRequestHead(version: .http1_1, method: .POST, uri: "/")
let metadata = RequestFramingMetadata(connectionClose: false, body: .stream)
XCTAssertEqual(
state.startRequest(head: requestHead, metadata: metadata),
.sendRequestHead(requestHead, sendEnd: false)
)
// Promotes the producer to `.producing`, as the real pipeline does once the head is out.
XCTAssertEqual(
state.headSent(),
.notifyRequestHeadSendSuccessfully(resumeRequestBodyStream: true, startIdleTimer: false)
)

// One part is on the wire and the stream is still open.
let part0 = IOData.byteBuffer(ByteBuffer(bytes: 0...3))
XCTAssertEqual(state.requestStreamPartReceived(part0, promise: nil), .sendBodyPart(part0, nil))

// The server rejects the upload without reading the rest of it. The state machine takes
// this in stride and asks us to pause the body stream.
let responseHead = HTTPResponseHead(version: .http1_1, status: .payloadTooLarge)
XCTAssertEqual(
state.channelRead(.head(responseHead)),
.forwardResponseHead(responseHead, pauseRequestBodyStream: true)
)

// Pausing is not cancelling, so the producer may still finish. This is the trap: the
// action below is the correct one, and the assert crashes before it can be returned.
XCTAssertEqual(
state.requestStreamFinished(trailers: nil, promise: nil),
.sendRequestEnd(trailers: nil, nil, .none)
)

XCTAssertEqual(state.channelRead(.end(nil)), .forwardResponseEnd(.requestDone, [], nil))
}

func testRequestIsFailedIfRequestBodySizeIsWrongEvenAfterServerRespondedWith200() {
var state = HTTPRequestStateMachine(isChannelWritable: true)
let requestHead = HTTPRequestHead(
Expand Down
Loading