LineBasedFrameDecoder: don't crash when leftovers available (#13)

Motivation:

Currently, we crash if there's any left over bytes available because
LineBasedFrameDecoder modifies cumulationBuffer in a way that is
illegal.

Modifications:

stop modifying cumulationBuffer in an illegal way

Result:

fewer crashes
This commit is contained in:
Johannes Weiss 2019-03-08 15:41:46 +00:00 committed by GitHub
parent 575263e5f1
commit 45ddf6a211
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 38 additions and 2 deletions

View File

@ -49,8 +49,6 @@ public class LineBasedFrameDecoder: ByteToMessageDecoder {
}
public func decodeLast(context: ChannelHandlerContext, buffer: inout ByteBuffer, seenEOF: Bool) throws -> DecodingState {
// we'll just try to decode as much as we can as usually
while case .continue = try self.decode(context: context, buffer: &buffer) {}
if buffer.readableBytes > 0 {
context.fireErrorCaught(NIOExtrasErrors.LeftOverBytesError(leftOverBytes: buffer))
}

View File

@ -32,6 +32,7 @@ extension LineBasedFrameDecoderTest {
("testEmptyLine", testEmptyLine),
("testEmptyBuffer", testEmptyBuffer),
("testChannelInactiveWithLeftOverBytes", testChannelInactiveWithLeftOverBytes),
("testMoreDataAvailableWhenChannelBecomesInactive", testMoreDataAvailableWhenChannelBecomesInactive),
]
}
}

View File

@ -128,4 +128,41 @@ class LineBasedFrameDecoderTest: XCTestCase {
XCTAssertEqual(error.leftOverBytes, expectedBuffer)
}
}
func testMoreDataAvailableWhenChannelBecomesInactive() throws {
class CloseWhenMyFavouriteMessageArrives: ChannelInboundHandler {
typealias InboundIn = ByteBuffer
private let receivedLeftOversPromise: EventLoopPromise<ByteBuffer>
init(receivedLeftOversPromise: EventLoopPromise<ByteBuffer>) {
self.receivedLeftOversPromise = receivedLeftOversPromise
}
func channelRead(context: ChannelHandlerContext, data: NIOAny) {
let buffer = self.unwrapInboundIn(data)
if buffer.readableBytes == 3 {
context.close(promise: nil)
}
}
func errorCaught(context: ChannelHandlerContext, error: Error) {
if let leftOvers = error as? NIOExtrasErrors.LeftOverBytesError {
self.receivedLeftOversPromise.succeed(leftOvers.leftOverBytes)
} else {
context.fireErrorCaught(error)
}
}
}
let receivedLeftOversPromise: EventLoopPromise<ByteBuffer> = self.channel.eventLoop.makePromise()
let handler = CloseWhenMyFavouriteMessageArrives(receivedLeftOversPromise: receivedLeftOversPromise)
XCTAssertNoThrow(try self.channel.pipeline.addHandler(handler).wait())
var buffer = self.channel.allocator.buffer(capacity: 16)
buffer.writeString("a\nbb\nccc\ndddd\neeeee\nffffff\n")
XCTAssertNoThrow(try self.channel.writeInbound(buffer))
XCTAssertNoThrow(try XCTAssertEqual("dddd\neeeee\nffffff\n",
String(decoding: receivedLeftOversPromise.futureResult.wait().readableBytesView,
as: UTF8.self)))
}
}