Skip to content

Commit e0b3ba7

Browse files
authored
Merge branch 'main' into tracing-metadata
2 parents 89b90e7 + 1624240 commit e0b3ba7

File tree

5 files changed

+93
-27
lines changed

5 files changed

+93
-27
lines changed

.github/workflows/main.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,5 +14,5 @@ jobs:
1414
linux_5_9_enabled: false
1515
linux_5_10_enabled: false
1616
linux_6_0_arguments_override: "--explicit-target-dependency-import-check error -Xswiftc -require-explicit-sendable"
17-
linux_nightly_6_0_arguments_override: "--explicit-target-dependency-import-check error -Xswiftc -require-explicit-sendable"
17+
linux_nightly_6_1_arguments_override: "--explicit-target-dependency-import-check error -Xswiftc -require-explicit-sendable"
1818
linux_nightly_main_arguments_override: "--explicit-target-dependency-import-check error -Xswiftc -require-explicit-sendable"

.github/workflows/pull_request.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ jobs:
2323
linux_5_9_enabled: false
2424
linux_5_10_enabled: false
2525
linux_6_0_arguments_override: "--explicit-target-dependency-import-check error -Xswiftc -require-explicit-sendable"
26-
linux_nightly_6_0_arguments_override: "--explicit-target-dependency-import-check error -Xswiftc -require-explicit-sendable"
26+
linux_nightly_6_1_arguments_override: "--explicit-target-dependency-import-check error -Xswiftc -require-explicit-sendable"
2727
linux_nightly_main_arguments_override: "--explicit-target-dependency-import-check error -Xswiftc -require-explicit-sendable"
2828

2929
cxx-interop:

Package.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,11 +43,11 @@ let products: [Product] = [
4343
let dependencies: [Package.Dependency] = [
4444
.package(
4545
url: "https://github.com/grpc/grpc-swift.git",
46-
branch: "main"
46+
from: "2.0.0"
4747
),
4848
.package(
4949
url: "https://github.com/grpc/grpc-swift-protobuf.git",
50-
branch: "main"
50+
from: "1.0.0"
5151
),
5252
.package(
5353
url: "https://github.com/apple/swift-protobuf.git",

Sources/GRPCOTelTracingInterceptors/Tracing/SpanAttributes+GRPCTracingKeys.swift

Lines changed: 67 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -181,47 +181,91 @@ package enum PeerAddress: Equatable {
181181
// - ipv4:<host>:<port> for ipv4 addresses
182182
// - ipv6:[<host>]:<port> for ipv6 addresses
183183
// - unix:<uds-pathname> for UNIX domain sockets
184+
let addressUTF8View = address.utf8
184185

185186
// First get the first component so that we know what type of address we're dealing with
186-
let addressComponents = address.split(separator: ":", maxSplits: 1)
187+
let firstColonIndex = addressUTF8View.firstIndex(of: UInt8(ascii: ":"))
187188

188-
guard addressComponents.count > 1 else {
189+
guard let firstColonIndex else {
189190
// This is some unexpected/unknown format
190191
return nil
191192
}
192193

194+
let addressType = addressUTF8View[..<firstColonIndex]
195+
196+
var addressWithoutType = addressUTF8View[firstColonIndex...]
197+
addressWithoutType.removeFirst()
198+
193199
// Check what type the transport is...
194-
switch addressComponents[0] {
195-
case "ipv4":
196-
let ipv4AddressComponents = addressComponents[1].split(separator: ":")
197-
if ipv4AddressComponents.count == 2, let port = Int(ipv4AddressComponents[1]) {
198-
self = .ipv4(address: String(ipv4AddressComponents[0]), port: port)
199-
} else {
200+
if addressType.elementsEqual("ipv4".utf8) {
201+
guard let addressColon = addressWithoutType.firstIndex(of: UInt8(ascii: ":")) else {
202+
// This is some unexpected/unknown format
200203
return nil
201204
}
202205

203-
case "ipv6":
204-
if addressComponents[1].first == "[" {
205-
// At this point, we are looking at an address with format: [<address>]:<port>
206-
// We drop the first character ('[') and split by ']:' to keep two components: the address
207-
// and the port.
208-
let ipv6AddressComponents = addressComponents[1].dropFirst().split(separator: "]:")
209-
if ipv6AddressComponents.count == 2, let port = Int(ipv6AddressComponents[1]) {
210-
self = .ipv6(address: String(ipv6AddressComponents[0]), port: port)
211-
} else {
212-
return nil
213-
}
206+
let hostComponent = addressWithoutType[..<addressColon]
207+
var portComponent = addressWithoutType[addressColon...]
208+
portComponent.removeFirst()
209+
210+
if let host = String(hostComponent), let port = Int(ipAddressPortStringBytes: portComponent) {
211+
self = .ipv4(address: host, port: port)
214212
} else {
215213
return nil
216214
}
215+
} else if addressType.elementsEqual("ipv6".utf8) {
216+
guard let lastColonIndex = addressWithoutType.lastIndex(of: UInt8(ascii: ":")) else {
217+
// This is some unexpected/unknown format
218+
return nil
219+
}
217220

218-
case "unix":
219-
// Whatever comes after "unix:" is the <pathname>
220-
self = .unixDomainSocket(path: String(addressComponents[1]))
221+
var hostComponent = addressWithoutType[..<lastColonIndex]
222+
var portComponent = addressWithoutType[lastColonIndex...]
223+
portComponent.removeFirst()
221224

222-
default:
225+
if let firstBracket = hostComponent.popFirst(), let lastBracket = hostComponent.popLast(),
226+
firstBracket == UInt8(ascii: "["), lastBracket == UInt8(ascii: "]"),
227+
let host = String(hostComponent), let port = Int(ipAddressPortStringBytes: portComponent)
228+
{
229+
self = .ipv6(address: host, port: port)
230+
} else {
231+
// This is some unexpected/unknown format
232+
return nil
233+
}
234+
} else if addressType.elementsEqual("unix".utf8) {
235+
// Whatever comes after "unix:" is the <pathname>
236+
self = .unixDomainSocket(path: String(addressWithoutType) ?? "")
237+
} else {
223238
// This is some unexpected/unknown format
224239
return nil
225240
}
226241
}
227242
}
243+
244+
extension Int {
245+
package init?(ipAddressPortStringBytes: some Collection<UInt8>) {
246+
guard (1 ... 5).contains(ipAddressPortStringBytes.count) else {
247+
// Valid IP port values go up to 2^16-1 (65535), which is 5 digits long.
248+
// If the string we get is over 5 characters, we know for sure that this is an invalid port.
249+
// If it's empty, we also know it's invalid as we need at least one digit.
250+
return nil
251+
}
252+
253+
var value = 0
254+
for utf8Char in ipAddressPortStringBytes {
255+
value &*= 10
256+
guard (UInt8(ascii: "0") ... UInt8(ascii: "9")).contains(utf8Char) else {
257+
// non-digit character
258+
return nil
259+
}
260+
value &+= Int(utf8Char &- UInt8(ascii: "0"))
261+
}
262+
263+
guard value <= Int(UInt16.max) else {
264+
// Valid IP port values go up to 2^16-1.
265+
// If a number greater than this was given, it can't be a valid port.
266+
return nil
267+
}
268+
269+
self = value
270+
}
271+
}

Tests/GRPCOTelTracingInterceptorsTests/PeerAddressTests.swift

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,4 +56,26 @@ struct PeerAddressTests {
5656
let address = PeerAddress(address)
5757
#expect(address == nil)
5858
}
59+
60+
@Test(
61+
"Int.init(utf8View:)",
62+
arguments: [
63+
("1", 1),
64+
("21", 21),
65+
("321", 321),
66+
("4321", 4321),
67+
("54321", 54321),
68+
("65536", nil), // Invalid: over 65535 IP port limit
69+
("654321", nil), // Invalid: over 5 digits
70+
("abc", nil), // Invalid: no digits
71+
("a123", nil), // Invalid: mixed digits and chars outside the valid ascii range for digits
72+
("123a", nil), // Invalid: mixed digits and chars outside the valid ascii range for digits
73+
("(123", nil), // Invalid: mixed digits and chars outside the valid ascii range for digits
74+
("123(", nil), // Invalid: mixed digits and chars outside the valid ascii range for digits
75+
("", nil), // Invalid: empty string
76+
]
77+
)
78+
func testIntInitFromUTF8View(string: String, expectedInt: Int?) async throws {
79+
#expect(expectedInt == Int(ipAddressPortStringBytes: string.utf8))
80+
}
5981
}

0 commit comments

Comments
 (0)