swift-nio/Tests/NIOWebSocketTests/WebSocketFrameDecoderTest.s...

558 lines
27 KiB
Swift

//===----------------------------------------------------------------------===//
//
// This source file is part of the SwiftNIO open source project
//
// Copyright (c) 2017-2021 Apple Inc. and the SwiftNIO project authors
// Licensed under Apache License v2.0
//
// See LICENSE.txt for license information
// See CONTRIBUTORS.txt for the list of SwiftNIO project authors
//
// SPDX-License-Identifier: Apache-2.0
//
//===----------------------------------------------------------------------===//
import XCTest
import NIOCore
import NIOEmbedded
import NIOWebSocket
private class CloseSwallower: ChannelOutboundHandler, RemovableChannelHandler {
typealias OutboundIn = Any
typealias OutboundOut = Any
private var closePromise: EventLoopPromise<Void>? = nil
private var context: ChannelHandlerContext? = nil
public func allowClose() {
self.context!.close(promise: self.closePromise)
self.context = nil
}
func close(context: ChannelHandlerContext, mode: CloseMode, promise: EventLoopPromise<Void>?) {
self.closePromise = promise
self.context = context
}
}
/// A class that calls context.close() when it receives a decoded websocket frame, and validates that it does
/// not receive two.
private final class SynchronousCloser: ChannelInboundHandler {
typealias InboundIn = WebSocketFrame
private var closeFrame: WebSocketFrame?
func channelRead(context: ChannelHandlerContext, data: NIOAny) {
let frame = self.unwrapInboundIn(data)
guard case .connectionClose = frame.opcode else {
context.fireChannelRead(data)
return
}
// Ok, connection close. Confirm we haven't seen one before.
XCTAssertNil(self.closeFrame)
self.closeFrame = frame
// Now we're going to call close.
context.close(promise: nil)
}
}
public final class WebSocketFrameDecoderTest: XCTestCase {
public var decoderChannel: EmbeddedChannel!
public var encoderChannel: EmbeddedChannel!
public var buffer: ByteBuffer!
public override func setUp() {
self.decoderChannel = EmbeddedChannel()
self.encoderChannel = EmbeddedChannel()
self.buffer = decoderChannel.allocator.buffer(capacity: 128)
XCTAssertNoThrow(try self.decoderChannel.pipeline.addHandler(ByteToMessageHandler(WebSocketFrameDecoder())).wait())
XCTAssertNoThrow(try self.encoderChannel.pipeline.addHandler(WebSocketFrameEncoder()).wait())
}
public override func tearDown() {
XCTAssertNoThrow(try self.encoderChannel.finish())
_ = try? self.decoderChannel.finish()
self.encoderChannel = nil
self.buffer = nil
}
private func frameForFrame(_ frame: WebSocketFrame) -> WebSocketFrame? {
self.encoderChannel.writeAndFlush(frame, promise: nil)
do {
while let d = try self.encoderChannel.readOutbound(as: ByteBuffer.self) {
XCTAssertNoThrow(try self.decoderChannel.writeInbound(d))
}
guard let producedFrame: WebSocketFrame = try self.decoderChannel.readInbound() else {
XCTFail("Did not produce a frame")
return nil
}
// Should only have gotten one frame!
XCTAssertNoThrow(XCTAssertNil(try self.decoderChannel.readInbound(as: WebSocketFrame.self)))
return producedFrame
} catch {
XCTFail("unexpected error: \(error)")
return nil
}
}
private func assertFrameRoundTrips(frame: WebSocketFrame) {
XCTAssertEqual(frameForFrame(frame), frame)
}
private func assertFrameDoesNotRoundTrip(frame: WebSocketFrame) {
XCTAssertNotEqual(frameForFrame(frame), frame)
}
private func swapDecoder(for handler: ChannelHandler) {
// We need to insert a decoder that doesn't do error handling. We still insert
// an encoder because we want to fail gracefully if a frame is written.
let f = self.decoderChannel.pipeline.context(handlerType: ByteToMessageHandler<WebSocketFrameDecoder>.self).flatMapThrowing {
if let handler = $0.handler as? RemovableChannelHandler {
return handler
} else {
throw ChannelError.unremovableHandler
}
}.flatMap {
self.decoderChannel.pipeline.removeHandler($0)
}
// we need to run the event loop here because removal is not synchronous
(self.decoderChannel.eventLoop as! EmbeddedEventLoop).run()
XCTAssertNoThrow(try f.flatMap {
self.decoderChannel.pipeline.addHandler(handler)
}.wait())
}
public func testFramesWithoutBodies() throws {
let frame = WebSocketFrame(fin: true, opcode: .ping, data: self.buffer)
assertFrameRoundTrips(frame: frame)
}
public func testFramesWithExtensionDataDontRoundTrip() throws {
// We don't know what the extensions are, so all data goes in...well...data.
self.buffer.writeBytes([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
let frame = WebSocketFrame(fin: false,
opcode: .binary,
data: self.buffer.getSlice(at: self.buffer.readerIndex, length: 5)!,
extensionData: self.buffer.getSlice(at: self.buffer.readerIndex + 5, length: 5)!)
assertFrameDoesNotRoundTrip(frame: frame)
}
public func testFramesWithExtensionDataCanBeRecovered() throws {
self.buffer.writeBytes([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
let frame = WebSocketFrame(fin: false,
opcode: .binary,
data: self.buffer.getSlice(at: self.buffer.readerIndex, length: 5)!,
extensionData: self.buffer.getSlice(at: self.buffer.readerIndex + 5, length: 5)!)
var newFrame = frameForFrame(frame)!
// Copy some data out into the extension on the frame. The first 5 bytes are extension.
newFrame.extensionData = newFrame.data.readSlice(length: 5)
XCTAssertEqual(newFrame, frame)
}
public func testFramesWithReservedBitsSetRoundTrip() throws {
self.buffer.writeBytes([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
let frame = WebSocketFrame(fin: false,
rsv1: true,
rsv2: true,
rsv3: true,
opcode: .binary,
data: self.buffer)
assertFrameRoundTrips(frame: frame)
}
public func testFramesWith16BitLengthsRoundTrip() throws {
self.buffer.writeBytes(Array(repeating: UInt8(4), count: 300))
let frame = WebSocketFrame(fin: true,
opcode: .binary,
data: self.buffer)
assertFrameRoundTrips(frame: frame)
}
public func testFramesWith64BitLengthsRoundTrip() throws {
// We need a new decoder channel here, because the max length would otherwise trigger an error.
_ = try! self.decoderChannel.finish()
self.decoderChannel = EmbeddedChannel()
XCTAssertNoThrow(try self.decoderChannel.pipeline.addHandler(ByteToMessageHandler(WebSocketFrameDecoder(maxFrameSize: 80000))).wait())
self.buffer.writeBytes(Array(repeating: UInt8(4), count: 66000))
let frame = WebSocketFrame(fin: true,
opcode: .binary,
data: self.buffer)
assertFrameRoundTrips(frame: frame)
}
public func testMaskedFramesRoundTripWithMaskingIntact() throws {
self.buffer.writeBytes([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
let frame = WebSocketFrame(fin: false,
opcode: .binary,
maskKey: [0x80, 0x77, 0x11, 0x33],
data: self.buffer)
let producedFrame = frameForFrame(frame)!
XCTAssertEqual(producedFrame.fin, frame.fin)
XCTAssertEqual(producedFrame.rsv1, frame.rsv1)
XCTAssertEqual(producedFrame.rsv2, frame.rsv2)
XCTAssertEqual(producedFrame.rsv3, frame.rsv3)
XCTAssertEqual(producedFrame.maskKey, frame.maskKey)
XCTAssertEqual(producedFrame.length, frame.length)
// The produced frame contains the masked data in its data field.
var maskedBuffer = self.buffer!
maskedBuffer.webSocketMask([0x80, 0x77, 0x11, 0x33])
XCTAssertEqual(maskedBuffer, producedFrame.data)
// But we can get the unmasked data back.
XCTAssertEqual(producedFrame.unmaskedData, self.buffer)
}
public func testMaskedFramesRoundTripWithMaskingIntactEvenWithExtensions() throws {
self.buffer.writeBytes([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
let frame = WebSocketFrame(fin: false,
opcode: .binary,
maskKey: [0x80, 0x77, 0x11, 0x33],
data: self.buffer.getSlice(at: self.buffer.readerIndex + 5, length: 5)!,
extensionData: self.buffer.getSlice(at: self.buffer.readerIndex, length: 5)!)
var producedFrame = frameForFrame(frame)!
XCTAssertEqual(producedFrame.fin, frame.fin)
XCTAssertEqual(producedFrame.rsv1, frame.rsv1)
XCTAssertEqual(producedFrame.rsv2, frame.rsv2)
XCTAssertEqual(producedFrame.rsv3, frame.rsv3)
XCTAssertEqual(producedFrame.maskKey, frame.maskKey)
XCTAssertEqual(producedFrame.length, frame.length)
// The produced frame contains the masked data in its data field, but doesn't know which is extension and which
// is not. Let's fix that up first.
producedFrame.extensionData = producedFrame.data.readSlice(length: 5)
var maskedBuffer = self.buffer!
maskedBuffer.webSocketMask([0x80, 0x77, 0x11, 0x33])
XCTAssertEqual(maskedBuffer.getSlice(at: maskedBuffer.readerIndex + 5, length: 5)!, producedFrame.data)
XCTAssertEqual(maskedBuffer.getSlice(at: maskedBuffer.readerIndex, length: 5)!, producedFrame.extensionData)
// But we can get the unmasked data back.
XCTAssertEqual(producedFrame.unmaskedData, self.buffer.getSlice(at: self.buffer.readerIndex + 5, length: 5)!)
XCTAssertEqual(producedFrame.unmaskedExtensionData, self.buffer.getSlice(at: self.buffer.readerIndex, length: 5)!)
}
public func testDecoderRejectsOverlongFrames() throws {
XCTAssertNoThrow(try self.decoderChannel.pipeline.addHandler(WebSocketFrameEncoder(), position: .first).wait())
XCTAssertNoThrow(try self.decoderChannel.pipeline.addHandler(WebSocketProtocolErrorHandler()).wait())
// A fake frame header that claims that the length of the frame is 16385 bytes,
// larger than the frame max.
self.buffer.writeBytes([0x81, 0xFE, 0x40, 0x01])
XCTAssertThrowsError(try self.decoderChannel.writeInbound(self.buffer)) { error in
XCTAssertEqual(.invalidFrameLength, error as? NIOWebSocketError)
}
// We expect that an error frame will have been written out.
XCTAssertNoThrow(XCTAssertEqual([0x88, 0x02, 0x03, 0xF1], try self.decoderChannel.readAllOutboundBytes()))
}
public func testDecoderRejectsFragmentedControlFrames() throws {
XCTAssertNoThrow(try self.decoderChannel.pipeline.addHandler(WebSocketFrameEncoder(), position: .first).wait())
XCTAssertNoThrow(try self.decoderChannel.pipeline.addHandler(WebSocketProtocolErrorHandler()).wait())
// A fake frame header that claims this is a fragmented ping frame.
self.buffer.writeBytes([0x09, 0x00])
XCTAssertThrowsError(try self.decoderChannel.writeInbound(self.buffer)) { error in
XCTAssertEqual(.fragmentedControlFrame, error as? NIOWebSocketError)
}
// We expect that an error frame will have been written out.
XCTAssertNoThrow(XCTAssertEqual([0x88, 0x02, 0x03, 0xEA], try self.decoderChannel.readAllOutboundBytes()))
}
public func testDecoderRejectsMultibyteControlFrameLengths() throws {
XCTAssertNoThrow(try self.decoderChannel.pipeline.addHandler(WebSocketFrameEncoder(), position: .first).wait())
XCTAssertNoThrow(try self.decoderChannel.pipeline.addHandler(WebSocketProtocolErrorHandler()).wait())
// A fake frame header that claims this is a ping frame with 126 bytes of data.
self.buffer.writeBytes([0x89, 0x7E, 0x00, 0x7E])
XCTAssertThrowsError(try self.decoderChannel.writeInbound(self.buffer)) { error in
XCTAssertEqual(.multiByteControlFrameLength, error as? NIOWebSocketError)
}
// We expect that an error frame will have been written out.
XCTAssertNoThrow(XCTAssertEqual([0x88, 0x02, 0x03, 0xEA], try self.decoderChannel.readAllOutboundBytes()))
}
func testIgnoresFurtherDataAfterRejectedFrame() throws {
let swallower = CloseSwallower()
XCTAssertNoThrow(try self.decoderChannel.pipeline.addHandler(WebSocketFrameEncoder(), position: .first).wait())
XCTAssertNoThrow(try self.decoderChannel.pipeline.addHandler(swallower, position: .first).wait())
XCTAssertNoThrow(try self.decoderChannel.pipeline.addHandler(WebSocketProtocolErrorHandler()).wait())
// A fake frame header that claims this is a fragmented ping frame.
self.buffer.writeBytes([0x09, 0x00])
XCTAssertThrowsError(try self.decoderChannel.writeInbound(self.buffer)) { error in
XCTAssertEqual(.fragmentedControlFrame, error as? NIOWebSocketError)
}
// We expect that an error frame will have been written out.
XCTAssertNoThrow(XCTAssertEqual([0x88, 0x02, 0x03, 0xEA], try self.decoderChannel.readAllOutboundBytes()))
// Now write another broken frame, this time an overlong frame.
self.buffer.clear()
let wrongFrame: [UInt8] = [0x81, 0xFE, 0x40, 0x01]
self.buffer.writeBytes(wrongFrame)
XCTAssertThrowsError(try self.decoderChannel.writeInbound(self.buffer)) { error in
if case .some(.dataReceivedInErrorState(let innerError, let data)) = error as? ByteToMessageDecoderError {
// ok
XCTAssertEqual(.fragmentedControlFrame, innerError as? NIOWebSocketError)
XCTAssertEqual(wrongFrame, Array(data.readableBytesView))
} else {
XCTFail("unexpected error: \(error)")
}
}
// No extra data should have been sent.
XCTAssertNoThrow(XCTAssertNil(try self.decoderChannel.readOutbound()))
// Allow the channel to close.
swallower.allowClose()
// Take the handler out for cleanliness.
XCTAssertNoThrow(try self.decoderChannel.pipeline.removeHandler(swallower).wait())
}
public func testClosingSynchronouslyOnChannelRead() throws {
// We're going to send a connectionClose frame and confirm we only see it once.
XCTAssertNoThrow(try self.decoderChannel.pipeline.addHandler(SynchronousCloser()).wait())
var errorCodeBuffer = self.encoderChannel.allocator.buffer(capacity: 4)
errorCodeBuffer.write(webSocketErrorCode: .normalClosure)
let frame = WebSocketFrame(fin: true, opcode: .connectionClose, data: errorCodeBuffer)
// Write the frame, send it through the decoder channel. We need to do this in one go to trigger
// a double-parse edge case.
self.encoderChannel.write(frame, promise: nil)
var frameBuffer = self.decoderChannel.allocator.buffer(capacity: 10)
while var d = try self.encoderChannel.readOutbound(as: ByteBuffer.self) {
frameBuffer.writeBuffer(&d)
}
XCTAssertNoThrow(try self.decoderChannel.writeInbound(frameBuffer))
// No data should have been sent or received.
XCTAssertNoThrow(XCTAssertNil(try self.decoderChannel.readOutbound()))
XCTAssertNoThrow(XCTAssertNil(try self.decoderChannel.readInbound(as: WebSocketFrame.self)))
}
public func testDecoderRejectsOverlongFramesWithNoAutomaticErrorHandling() {
// We need to insert a decoder that doesn't do error handling. We still insert
// an encoder because we want to fail gracefully if a frame is written.
self.swapDecoder(for: ByteToMessageHandler(WebSocketFrameDecoder()))
XCTAssertNoThrow(try self.decoderChannel.pipeline.addHandler(WebSocketFrameEncoder(), position: .first).wait())
// A fake frame header that claims that the length of the frame is 16385 bytes,
// larger than the frame max.
self.buffer.writeBytes([0x81, 0xFE, 0x40, 0x01])
XCTAssertThrowsError(try self.decoderChannel.writeInbound(self.buffer)) { error in
XCTAssertEqual(.invalidFrameLength, error as? NIOWebSocketError)
}
// No error frame should be written.
XCTAssertNoThrow(XCTAssertEqual([], try self.decoderChannel.readAllOutboundBytes()))
}
public func testDecoderRejectsFragmentedControlFramesWithNoAutomaticErrorHandling() throws {
// We need to insert a decoder that doesn't do error handling. We still insert
// an encoder because we want to fail gracefully if a frame is written.
self.swapDecoder(for: ByteToMessageHandler(WebSocketFrameDecoder()))
XCTAssertNoThrow(try self.decoderChannel.pipeline.addHandler(WebSocketFrameEncoder(), position: .first).wait())
// A fake frame header that claims this is a fragmented ping frame.
self.buffer.writeBytes([0x09, 0x00])
XCTAssertThrowsError(try self.decoderChannel.writeInbound(self.buffer)) { error in
XCTAssertEqual(.fragmentedControlFrame, error as? NIOWebSocketError)
}
// No error frame should be written.
XCTAssertNoThrow(XCTAssertEqual([], try self.decoderChannel.readAllOutboundBytes()))
}
public func testDecoderRejectsMultibyteControlFrameLengthsWithNoAutomaticErrorHandling() throws {
// We need to insert a decoder that doesn't do error handling. We still insert
// an encoder because we want to fail gracefully if a frame is written.
self.swapDecoder(for: ByteToMessageHandler(WebSocketFrameDecoder()))
XCTAssertNoThrow(try self.decoderChannel.pipeline.addHandler(WebSocketFrameEncoder(), position: .first).wait())
// A fake frame header that claims this is a ping frame with 126 bytes of data.
self.buffer.writeBytes([0x89, 0x7E, 0x00, 0x7E])
XCTAssertThrowsError(try self.decoderChannel.writeInbound(self.buffer)) { error in
XCTAssertEqual(.multiByteControlFrameLength, error as? NIOWebSocketError)
}
// No error frame should be written.
XCTAssertNoThrow(XCTAssertEqual([], try self.decoderChannel.readAllOutboundBytes()))
}
func testIgnoresFurtherDataAfterRejectedFrameWithNoAutomaticErrorHandling() {
// We need to insert a decoder that doesn't do error handling. We still insert
// an encoder because we want to fail gracefully if a frame is written.
self.swapDecoder(for: ByteToMessageHandler(WebSocketFrameDecoder()))
XCTAssertNoThrow(try self.decoderChannel.pipeline.addHandler(WebSocketFrameEncoder(), position: .first).wait())
// A fake frame header that claims this is a fragmented ping frame.
self.buffer.writeBytes([0x09, 0x00])
XCTAssertThrowsError(try self.decoderChannel.writeInbound(self.buffer)) { error in
XCTAssertEqual(.fragmentedControlFrame, error as? NIOWebSocketError)
}
// No error frame should be written.
XCTAssertNoThrow(XCTAssertEqual([], try self.decoderChannel.readAllOutboundBytes()))
// Now write another broken frame, this time an overlong frame.
self.buffer.clear()
let wrongFrame: [UInt8] = [0x81, 0xFE, 0x40, 0x01]
self.buffer.writeBytes(wrongFrame)
XCTAssertThrowsError(try self.decoderChannel.writeInbound(self.buffer)) { error in
if case .some(.dataReceivedInErrorState(let innerError, let data)) = error as? ByteToMessageDecoderError {
// ok
XCTAssertEqual(.fragmentedControlFrame, innerError as? NIOWebSocketError)
XCTAssertEqual(wrongFrame, Array(data.readableBytesView))
} else {
XCTFail("unexpected error: \(error)")
}
}
// No extra data should have been sent.
XCTAssertNoThrow(XCTAssertNil(try self.decoderChannel.readOutbound()))
}
public func testDecoderRejectsOverlongFramesWithSeparateErrorHandling() throws {
// We need to insert a decoder that doesn't do error handling, and then a separate error
// handler.
self.swapDecoder(for: ByteToMessageHandler(WebSocketFrameDecoder()))
XCTAssertNoThrow(try self.decoderChannel.pipeline.addHandler(WebSocketFrameEncoder(), position: .first).wait())
XCTAssertNoThrow(try self.decoderChannel.pipeline.addHandler(WebSocketProtocolErrorHandler()).wait())
// A fake frame header that claims that the length of the frame is 16385 bytes,
// larger than the frame max.
self.buffer.writeBytes([0x81, 0xFE, 0x40, 0x01])
XCTAssertThrowsError(try self.decoderChannel.writeInbound(self.buffer)) { error in
XCTAssertEqual(.invalidFrameLength, error as? NIOWebSocketError)
}
// We expect that an error frame will have been written out.
XCTAssertNoThrow(XCTAssertEqual([0x88, 0x02, 0x03, 0xF1], try self.decoderChannel.readAllOutboundBytes()))
}
public func testDecoderRejectsFragmentedControlFramesWithSeparateErrorHandling() throws {
// We need to insert a decoder that doesn't do error handling, and then a separate error
// handler.
self.swapDecoder(for: ByteToMessageHandler(WebSocketFrameDecoder()))
XCTAssertNoThrow(try self.decoderChannel.pipeline.addHandler(WebSocketFrameEncoder(), position: .first).wait())
XCTAssertNoThrow(try self.decoderChannel.pipeline.addHandler(WebSocketProtocolErrorHandler()).wait())
// A fake frame header that claims this is a fragmented ping frame.
self.buffer.writeBytes([0x09, 0x00])
XCTAssertThrowsError(try self.decoderChannel.writeInbound(self.buffer)) { error in
XCTAssertEqual(.fragmentedControlFrame, error as? NIOWebSocketError)
}
// We expect that an error frame will have been written out.
XCTAssertNoThrow(XCTAssertEqual([0x88, 0x02, 0x03, 0xEA], try self.decoderChannel.readAllOutboundBytes()))
}
public func testDecoderRejectsMultibyteControlFrameLengthsWithSeparateErrorHandling() throws {
// We need to insert a decoder that doesn't do error handling, and then a separate error
// handler.
self.swapDecoder(for: ByteToMessageHandler(WebSocketFrameDecoder()))
XCTAssertNoThrow(try self.decoderChannel.pipeline.addHandler(WebSocketFrameEncoder(), position: .first).wait())
XCTAssertNoThrow(try self.decoderChannel.pipeline.addHandler(WebSocketProtocolErrorHandler()).wait())
// A fake frame header that claims this is a ping frame with 126 bytes of data.
self.buffer.writeBytes([0x89, 0x7E, 0x00, 0x7E])
XCTAssertThrowsError(try self.decoderChannel.writeInbound(self.buffer)) { error in
XCTAssertEqual(.multiByteControlFrameLength, error as? NIOWebSocketError)
}
// We expect that an error frame will have been written out.
XCTAssertNoThrow(XCTAssertEqual(try self.decoderChannel.readAllOutboundBytes(), [0x88, 0x02, 0x03, 0xEA]))
}
func testIgnoresFurtherDataAfterRejectedFrameWithSeparateErrorHandling() {
let swallower = CloseSwallower()
// We need to insert a decoder that doesn't do error handling, and then a separate error
// handler.
self.swapDecoder(for: ByteToMessageHandler(WebSocketFrameDecoder()))
XCTAssertNoThrow(try self.decoderChannel.pipeline.addHandler(WebSocketFrameEncoder(), position: .first).wait())
XCTAssertNoThrow(try self.decoderChannel.pipeline.addHandler(WebSocketProtocolErrorHandler()).wait())
XCTAssertNoThrow(try self.decoderChannel.pipeline.addHandler(swallower, position: .first).wait())
// A fake frame header that claims this is a fragmented ping frame.
self.buffer.writeBytes([0x09, 0x00])
XCTAssertThrowsError(try self.decoderChannel.writeInbound(self.buffer)) { error in
XCTAssertEqual(.fragmentedControlFrame, error as? NIOWebSocketError)
}
// We expect that an error frame will have been written out.
XCTAssertNoThrow(XCTAssertEqual(try self.decoderChannel.readAllOutboundBytes(), [0x88, 0x02, 0x03, 0xEA]))
// Now write another broken frame, this time an overlong frame.
self.buffer.clear()
let wrongFrame: [UInt8] = [0x81, 0xFE, 0x40, 0x01]
self.buffer.writeBytes(wrongFrame)
XCTAssertThrowsError(try self.decoderChannel.writeInbound(self.buffer)) { error in
if case .some(.dataReceivedInErrorState(let innerError, let data)) = error as? ByteToMessageDecoderError {
// ok
XCTAssertEqual(.fragmentedControlFrame, innerError as? NIOWebSocketError)
XCTAssertEqual(wrongFrame, Array(data.readableBytesView))
} else {
XCTFail("unexpected error: \(error)")
}
}
// No extra data should have been sent.
XCTAssertNoThrow(XCTAssertNil(try self.decoderChannel.readOutbound()))
// Allow the channel to close.
swallower.allowClose()
// Take the handler out for cleanliness.
XCTAssertNoThrow(try self.decoderChannel.pipeline.removeHandler(swallower).wait())
}
func testErrorHandlerDoesNotSwallowRandomErrors() throws {
XCTAssertNoThrow(try self.decoderChannel.pipeline.addHandler(WebSocketFrameEncoder(), position: .first).wait())
XCTAssertNoThrow(try self.decoderChannel.pipeline.addHandler(WebSocketProtocolErrorHandler()).wait())
// A fake frame header that claims that the length of the frame is 16385 bytes,
// larger than the frame max.
self.buffer.writeBytes([0x81, 0xFE, 0x40, 0x01])
struct Dummy: Error {}
self.decoderChannel.pipeline.fireErrorCaught(Dummy())
XCTAssertThrowsError(try self.decoderChannel.throwIfErrorCaught()) { error in
XCTAssertNotNil(error as? Dummy, "unexpected error: \(error)")
}
XCTAssertThrowsError(try self.decoderChannel.writeInbound(self.buffer)) { error in
XCTAssertEqual(.invalidFrameLength, error as? NIOWebSocketError)
}
// We expect that an error frame will have been written out.
XCTAssertNoThrow(XCTAssertEqual([0x88, 0x02, 0x03, 0xF1], try self.decoderChannel.readAllOutboundBytes()))
}
}