Skip to content

Commit

Permalink
Dissallow access and removal of Head and Tail ChannelHandlers
Browse files Browse the repository at this point in the history
Motivation:

The Head and Tail ChannelHandlers should not be accessible as these are implementation details of the ChannelPipeline and removal of these will even make the whole ChannelPipeline not work anymore.

Modifications:

- Make it impossible to access / removal the Head and Tail ChannelHandlers
- Exclude the Head and Tail ChannelHandler from the debug String
- Add unit tests.

Result:

More robust ChannelPipeline.
  • Loading branch information
normanmaurer committed Mar 23, 2018
1 parent 61f03a7 commit a301bec
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 4 deletions.
15 changes: 11 additions & 4 deletions Sources/NIO/ChannelPipeline.swift
Original file line number Diff line number Diff line change
Expand Up @@ -446,9 +446,16 @@ public final class ChannelPipeline: ChannelInvoker {
return promise.futureResult
}

/// Returns a `ChannelHandlerContext` which matches.
///
/// This skips head and tail (as these are internal and should not be accessible by the user.
///
/// - parameters:
/// - body: The predicate to execute per `ChannelHandlerContext` in the `ChannelPipeline`.
/// -returns: The `ChannelHandlerContext` that matches or `nil` if non did.
private func contextForPredicate0(_ body: @escaping((ChannelHandlerContext) -> Bool)) -> ChannelHandlerContext? {
var curCtx: ChannelHandlerContext? = self.head
while let ctx = curCtx {
var curCtx: ChannelHandlerContext? = self.head?.next
while let ctx = curCtx, ctx !== self.tail {
if body(ctx) {
return ctx
}
Expand Down Expand Up @@ -1422,8 +1429,8 @@ public final class ChannelHandlerContext: ChannelInvoker {
extension ChannelPipeline: CustomDebugStringConvertible {
public var debugDescription: String {
var desc = "ChannelPipeline (\(ObjectIdentifier(self))):\n"
var node = self.head
while let ctx = node {
var node = self.head?.next
while let ctx = node, ctx !== self.tail {
let inboundStr = ctx.handler is _ChannelInboundHandler ? "I" : ""
let outboundStr = ctx.handler is _ChannelOutboundHandler ? "O" : ""
desc += " \(ctx.name) (\(type(of: ctx.handler))) [\(inboundStr)\(outboundStr)]\n"
Expand Down
44 changes: 44 additions & 0 deletions Tests/NIOTests/ChannelPipelineTest.swift
Original file line number Diff line number Diff line change
Expand Up @@ -620,4 +620,48 @@ class ChannelPipelineTest: XCTestCase {
XCTAssertTrue(try h1 === channel.pipeline.context(handlerType: TestHandler.self).wait().handler)
XCTAssertFalse(try h2 === channel.pipeline.context(handlerType: TestHandler.self).wait().handler)
}

func testContextForHeadOrTail() throws {
let channel = EmbeddedChannel()

defer {
XCTAssertFalse(try channel.finish())
}

do {
_ = try channel.pipeline.context(name: "head").wait()
XCTFail()
} catch let err as ChannelPipelineError where err == .notFound {
/// expected
}

do {
_ = try channel.pipeline.context(name: "tail").wait()
XCTFail()
} catch let err as ChannelPipelineError where err == .notFound {
/// expected
}
}

func testRemoveHeadOrTail() throws {
let channel = EmbeddedChannel()

defer {
XCTAssertFalse(try channel.finish())
}

do {
_ = try channel.pipeline.remove(name: "head").wait()
XCTFail()
} catch let err as ChannelPipelineError where err == .notFound {
/// expected
}

do {
_ = try channel.pipeline.remove(name: "tail").wait()
XCTFail()
} catch let err as ChannelPipelineError where err == .notFound {
/// expected
}
}
}

0 comments on commit a301bec

Please # to comment.