Skip to content

Commit 1ba56c0

Browse files
authored
Merge pull request #152 from slashmo/fix/nio-handlers
Correctly forward channel events in NIO instrumentation handlers
2 parents 3b2c3c9 + 4d027d7 commit 1ba56c0

9 files changed

+145
-68
lines changed

Sources/NIOInstrumentation/HTTPHeadersExtractingHandler.swift renamed to Sources/NIOInstrumentation/HeaderExtractingHTTPServerHandler.swift

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,17 +16,26 @@ import Instrumentation
1616
import NIO
1717
import NIOHTTP1
1818

19-
public final class HTTPHeadersExtractingHandler: ChannelInboundHandler {
19+
import Baggage
20+
import Instrumentation
21+
import NIO
22+
import NIOHTTP1
23+
24+
public final class HeaderExtractingHTTPServerHandler: ChannelInboundHandler {
2025
public typealias InboundIn = HTTPServerRequestPart
2126
public typealias InboundOut = HTTPServerRequestPart
2227

2328
public init() {}
2429

2530
public func channelRead(context: ChannelHandlerContext, data: NIOAny) {
26-
guard case .head(let head) = unwrapInboundIn(data) else { return }
27-
var baggage = Baggage.topLevel
28-
InstrumentationSystem.instrument.extract(head.headers, into: &baggage, using: HTTPHeadersExtractor())
29-
context.baggage = baggage
31+
if case .head(let head) = self.unwrapInboundIn(data) {
32+
InstrumentationSystem.instrument.extract(
33+
head.headers,
34+
into: &context.baggage,
35+
using: HTTPHeadersExtractor()
36+
)
37+
}
38+
3039
context.fireChannelRead(data)
3140
}
3241
}

Sources/NIOInstrumentation/HTTPHeadersInjectingHandler.swift renamed to Sources/NIOInstrumentation/HeaderInjectingHTTPClientHandler.swift

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,18 @@ import Instrumentation
1616
import NIO
1717
import NIOHTTP1
1818

19-
public final class HTTPHeadersInjectingHandler: ChannelOutboundHandler {
19+
public final class HeaderInjectingHTTPClientHandler: ChannelOutboundHandler {
2020
public typealias OutboundIn = HTTPClientRequestPart
2121
public typealias OutboundOut = HTTPClientRequestPart
2222

2323
public init() {}
2424

2525
public func write(context: ChannelHandlerContext, data: NIOAny, promise: EventLoopPromise<Void>?) {
26-
let requestPart = unwrapOutboundIn(data)
27-
guard case .head(var head) = requestPart else { return }
26+
guard case .head(var head) = self.unwrapOutboundIn(data) else {
27+
context.write(data, promise: promise)
28+
return
29+
}
30+
2831
InstrumentationSystem.instrument.inject(context.baggage, into: &head.headers, using: HTTPHeadersInjector())
2932
context.write(self.wrapOutboundOut(.head(head)), promise: promise)
3033
}

Tests/LinuxMain.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,8 @@ class LinuxMainRunnerImpl: LinuxMainRunner {
3737
XCTMain([
3838
testCase(HTTPHeadersCarrierTests.allTests),
3939
testCase(HTTPHeadersExtractInjectTests.allTests),
40-
testCase(HTTPHeadersExtractingHandlerTests.allTests),
41-
testCase(HTTPHeadersInjectingHandlerTests.allTests),
40+
testCase(HeaderExtractingHTTPServerHandlerTests.allTests),
41+
testCase(HeaderInjectingHTTPClientHandlerTests.allTests),
4242
testCase(InstrumentTests.allTests),
4343
testCase(InstrumentationSystemTests.allTests),
4444
testCase(SpanAttributeSemanticsTests.allTests),

Tests/NIOInstrumentationTests/HTTPHeadersExtractInjectTests.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,9 @@ final class HTTPHeadersExtractInjectTests: XCTestCase {
2626
func test_extracted_baggage_into_subsequent_request_headers() throws {
2727
InstrumentationSystem.bootstrapInternal(FakeTracer())
2828

29-
let outboundHandler = HTTPHeadersInjectingHandler()
29+
let outboundHandler = HeaderInjectingHTTPClientHandler()
3030
let requestHandler = MockRequestHandler()
31-
let inboundHandler = HTTPHeadersExtractingHandler()
31+
let inboundHandler = HeaderExtractingHTTPServerHandler()
3232

3333
let channel = EmbeddedChannel(loop: EmbeddedEventLoop())
3434
XCTAssertNoThrow(try channel.pipeline.addHandlers([outboundHandler, requestHandler, inboundHandler]).wait())

Tests/NIOInstrumentationTests/HTTPHeadersExtractingHandlerTests.swift

Lines changed: 0 additions & 44 deletions
This file was deleted.

Tests/NIOInstrumentationTests/HTTPHeadersExtractingHandlerTests+XCTest.swift renamed to Tests/NIOInstrumentationTests/HeaderExtractingHTTPServerHandlerTests+XCTest.swift

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
//
1212
//===----------------------------------------------------------------------===//
1313
//
14-
// HTTPHeadersExtractingHandlerTests+XCTest.swift
14+
// HeaderExtractingHTTPServerHandlerTests+XCTest.swift
1515
//
1616
import XCTest
1717
///
@@ -20,12 +20,14 @@ import XCTest
2020
/// Do NOT edit this file directly as it will be regenerated automatically when needed.
2121
///
2222

23-
extension HTTPHeadersExtractingHandlerTests {
23+
extension HeaderExtractingHTTPServerHandlerTests {
2424

2525
@available(*, deprecated, message: "not actually deprecated. Just deprecated to allow deprecated tests (which test deprecated functionality) without warnings")
26-
static var allTests : [(String, (HTTPHeadersExtractingHandlerTests) -> () throws -> Void)] {
26+
static var allTests : [(String, (HeaderExtractingHTTPServerHandlerTests) -> () throws -> Void)] {
2727
return [
2828
("test_extracts_http_request_headers_into_baggage", test_extracts_http_request_headers_into_baggage),
29+
("test_respects_previous_baggage_values", test_respects_previous_baggage_values),
30+
("test_forwards_all_read_events", test_forwards_all_read_events),
2931
]
3032
}
3133
}
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift Distributed Tracing open source project
4+
//
5+
// Copyright (c) 2020 Moritz Lang and the Swift Tracing project authors
6+
// Licensed under Apache License v2.0
7+
//
8+
// See LICENSE.txt for license information
9+
//
10+
// SPDX-License-Identifier: Apache-2.0
11+
//
12+
//===----------------------------------------------------------------------===//
13+
14+
import Baggage
15+
@testable import Instrumentation
16+
import NIO
17+
import NIOHTTP1
18+
import NIOInstrumentation
19+
import XCTest
20+
21+
final class HeaderExtractingHTTPServerHandlerTests: XCTestCase {
22+
override class func tearDown() {
23+
super.tearDown()
24+
InstrumentationSystem.bootstrapInternal(nil)
25+
}
26+
27+
func test_extracts_http_request_headers_into_baggage() throws {
28+
InstrumentationSystem.bootstrapInternal(FakeTracer())
29+
30+
let traceID = "abc"
31+
let handler = HeaderExtractingHTTPServerHandler()
32+
let channel = EmbeddedChannel(handler: handler, loop: EmbeddedEventLoop())
33+
34+
var requestHead = HTTPRequestHead(version: .init(major: 1, minor: 1), method: .GET, uri: "/")
35+
requestHead.headers = [FakeTracer.headerName: traceID]
36+
37+
XCTAssertNil(channel._channelCore.baggage[FakeTracer.TraceIDKey.self])
38+
39+
try channel.writeInbound(HTTPServerRequestPart.head(requestHead))
40+
41+
XCTAssertEqual(channel._channelCore.baggage[FakeTracer.TraceIDKey.self], traceID)
42+
}
43+
44+
func test_respects_previous_baggage_values() throws {
45+
InstrumentationSystem.bootstrapInternal(FakeTracer())
46+
47+
let traceID = "abc"
48+
let handler = HeaderExtractingHTTPServerHandler()
49+
let channel = EmbeddedChannel(handler: handler, loop: EmbeddedEventLoop())
50+
channel._channelCore.baggage[TestKey.self] = "test"
51+
52+
var requestHead = HTTPRequestHead(version: .init(major: 1, minor: 1), method: .GET, uri: "/")
53+
requestHead.headers = [FakeTracer.headerName: traceID]
54+
55+
XCTAssertNil(channel._channelCore.baggage[FakeTracer.TraceIDKey.self])
56+
57+
try channel.writeInbound(HTTPServerRequestPart.head(requestHead))
58+
59+
XCTAssertEqual(channel._channelCore.baggage[FakeTracer.TraceIDKey.self], traceID)
60+
XCTAssertEqual(channel._channelCore.baggage[TestKey.self], "test")
61+
}
62+
63+
func test_forwards_all_read_events() throws {
64+
let channel = EmbeddedChannel(
65+
handler: HeaderExtractingHTTPServerHandler(),
66+
loop: EmbeddedEventLoop()
67+
)
68+
69+
let requestHead = HTTPRequestHead(version: .init(major: 1, minor: 1), method: .GET, uri: "/")
70+
let head = HTTPServerRequestPart.head(requestHead)
71+
try channel.writeInbound(head)
72+
XCTAssertEqual(try channel.readInbound(), head)
73+
74+
let body = HTTPServerRequestPart.body(channel.allocator.buffer(string: "Test"))
75+
try channel.writeInbound(body)
76+
XCTAssertEqual(try channel.readInbound(), body)
77+
78+
let end = HTTPServerRequestPart.end(nil)
79+
try channel.writeInbound(end)
80+
XCTAssertEqual(try channel.readInbound(as: HTTPServerRequestPart.self), end)
81+
}
82+
}
83+
84+
private enum TestKey: Baggage.Key {
85+
typealias Value = String
86+
}

Tests/NIOInstrumentationTests/HTTPHeadersInjectingHandlerTests+XCTest.swift renamed to Tests/NIOInstrumentationTests/HeaderInjectingHTTPClientHandlerTests+XCTest.swift

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
//
1212
//===----------------------------------------------------------------------===//
1313
//
14-
// HTTPHeadersInjectingHandlerTests+XCTest.swift
14+
// HeaderInjectingHTTPClientHandlerTests+XCTest.swift
1515
//
1616
import XCTest
1717
///
@@ -20,12 +20,13 @@ import XCTest
2020
/// Do NOT edit this file directly as it will be regenerated automatically when needed.
2121
///
2222

23-
extension HTTPHeadersInjectingHandlerTests {
23+
extension HeaderInjectingHTTPClientHandlerTests {
2424

2525
@available(*, deprecated, message: "not actually deprecated. Just deprecated to allow deprecated tests (which test deprecated functionality) without warnings")
26-
static var allTests : [(String, (HTTPHeadersInjectingHandlerTests) -> () throws -> Void)] {
26+
static var allTests : [(String, (HeaderInjectingHTTPClientHandlerTests) -> () throws -> Void)] {
2727
return [
2828
("test_injects_baggage_into_http_request_headers", test_injects_baggage_into_http_request_headers),
29+
("test_forwards_all_write_events", test_forwards_all_write_events),
2930
]
3031
}
3132
}

Tests/NIOInstrumentationTests/HTTPHeadersInjectingHandlerTests.swift renamed to Tests/NIOInstrumentationTests/HeaderInjectingHTTPClientHandlerTests.swift

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,9 @@ import NIOHTTP1
1818
import NIOInstrumentation
1919
import XCTest
2020

21-
final class HTTPHeadersInjectingHandlerTests: XCTestCase {
21+
final class HeaderInjectingHTTPClientHandlerTests: XCTestCase {
22+
private let httpVersion = HTTPVersion(major: 1, minor: 1)
23+
2224
override class func tearDown() {
2325
super.tearDown()
2426
InstrumentationSystem.bootstrapInternal(nil)
@@ -32,19 +34,37 @@ final class HTTPHeadersInjectingHandlerTests: XCTestCase {
3234
var baggage = Baggage.topLevel
3335
baggage[FakeTracer.TraceIDKey.self] = traceID
3436

35-
let httpVersion = HTTPVersion(major: 1, minor: 1)
36-
let handler = HTTPHeadersInjectingHandler()
37+
let handler = HeaderInjectingHTTPClientHandler()
3738
let loop = EmbeddedEventLoop()
3839
let channel = EmbeddedChannel(handler: handler, loop: loop)
3940
channel._channelCore.baggage = baggage
4041
let requestHead = HTTPRequestHead(version: httpVersion, method: .GET, uri: "/")
4142

4243
try channel.writeOutbound(HTTPClientRequestPart.head(requestHead))
43-
let modifiedRequestPart = try channel.readOutbound(as: HTTPClientRequestPart.self)
4444

4545
XCTAssertEqual(
46-
modifiedRequestPart,
47-
.head(.init(version: httpVersion, method: .GET, uri: "/", headers: [FakeTracer.headerName: traceID]))
46+
try channel.readOutbound(as: HTTPClientRequestPart.self),
47+
.head(.init(version: self.httpVersion, method: .GET, uri: "/", headers: [FakeTracer.headerName: traceID]))
48+
)
49+
}
50+
51+
func test_forwards_all_write_events() throws {
52+
let channel = EmbeddedChannel(
53+
handler: HeaderInjectingHTTPClientHandler(),
54+
loop: EmbeddedEventLoop()
4855
)
56+
57+
let requestHead = HTTPRequestHead(version: httpVersion, method: .GET, uri: "/")
58+
let head = HTTPClientRequestPart.head(requestHead)
59+
try channel.writeOutbound(head)
60+
XCTAssertEqual(try channel.readOutbound(), head)
61+
62+
let body = HTTPClientRequestPart.body(.byteBuffer(channel.allocator.buffer(string: "test")))
63+
try channel.writeOutbound(body)
64+
XCTAssertEqual(try channel.readOutbound(), body)
65+
66+
let end = HTTPClientRequestPart.end(nil)
67+
try channel.writeOutbound(end)
68+
XCTAssertEqual(try channel.readOutbound(), end)
4969
}
5070
}

0 commit comments

Comments
 (0)