From 7936174c2f7415d4602828e5d15e329e9ab1f8b9 Mon Sep 17 00:00:00 2001 From: George Barnett Date: Tue, 27 May 2025 09:15:12 +0100 Subject: [PATCH 1/2] Allow padding to be omitted from binary metadata values Motivation: Binary metadata values are encoded as base64 strings. The gRPC spec doesn't require that the values are padded. Currently gRPC Swift requires values to be padded otherwise decoding will fail. Modifications: - Allow padding characters to be omitted when decoding base64 Result: Can decode unpadded binary metadata values --- Sources/GRPCCore/Metadata.swift | 2 +- Tests/GRPCCoreTests/MetadataTests.swift | 12 ++++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/Sources/GRPCCore/Metadata.swift b/Sources/GRPCCore/Metadata.swift index c9e736eae..6c8263037 100644 --- a/Sources/GRPCCore/Metadata.swift +++ b/Sources/GRPCCore/Metadata.swift @@ -423,7 +423,7 @@ extension Metadata { switch value { case .string(let stringValue): do { - return try Base64.decode(string: stringValue) + return try Base64.decode(string: stringValue, options: [.omitPaddingCharacter]) } catch { continue } diff --git a/Tests/GRPCCoreTests/MetadataTests.swift b/Tests/GRPCCoreTests/MetadataTests.swift index 715869fdb..647a34179 100644 --- a/Tests/GRPCCoreTests/MetadataTests.swift +++ b/Tests/GRPCCoreTests/MetadataTests.swift @@ -221,6 +221,18 @@ struct MetadataTests { #expect(Array(metadata[binaryValues: "key-bin"]) == expected) } + @Test("Iterate over unpadded base64 encoded binary values for a key") + @available(gRPCSwift 2.0, *) + func iterateOverUnpaddedBase64BinaryEncodedValuesForKey() { + let metadata: Metadata = [ + "key-bin": "YQ==", + "key-bin": "YQ", + ] + + let expected: [[UInt8]] = [[UInt8(ascii: "a")], [UInt8(ascii: "a")]] + #expect(Array(metadata[binaryValues: "key-bin"]) == expected) + } + @Test("Subscripts are case-insensitive") @available(gRPCSwift 2.0, *) func subscriptIsCaseInsensitive() { From 1aa3999c1ec4f30542d4a651f4fda815d12b4a71 Mon Sep 17 00:00:00 2001 From: George Barnett Date: Tue, 27 May 2025 11:07:44 +0100 Subject: [PATCH 2/2] Update thresholds --- ..._Iterate_binary_values_when_only_strings_stored.p90.json | 6 +----- ..._Iterate_binary_values_when_only_strings_stored.p90.json | 6 +----- ..._Iterate_binary_values_when_only_strings_stored.p90.json | 6 +----- ..._Iterate_binary_values_when_only_strings_stored.p90.json | 6 +----- 4 files changed, 4 insertions(+), 20 deletions(-) diff --git a/IntegrationTests/Benchmarks/Thresholds/6.0/GRPCSwiftBenchmark.Metadata_Iterate_binary_values_when_only_strings_stored.p90.json b/IntegrationTests/Benchmarks/Thresholds/6.0/GRPCSwiftBenchmark.Metadata_Iterate_binary_values_when_only_strings_stored.p90.json index b59f05063..9c403f41f 100644 --- a/IntegrationTests/Benchmarks/Thresholds/6.0/GRPCSwiftBenchmark.Metadata_Iterate_binary_values_when_only_strings_stored.p90.json +++ b/IntegrationTests/Benchmarks/Thresholds/6.0/GRPCSwiftBenchmark.Metadata_Iterate_binary_values_when_only_strings_stored.p90.json @@ -1,7 +1,3 @@ { - "mallocCountTotal" : 2000, - "memoryLeaked" : 0, - "releaseCount" : 6001, - "retainCount" : 2000, - "syscalls" : 0 + "mallocCountTotal": 1000 } diff --git a/IntegrationTests/Benchmarks/Thresholds/6.1/GRPCSwiftBenchmark.Metadata_Iterate_binary_values_when_only_strings_stored.p90.json b/IntegrationTests/Benchmarks/Thresholds/6.1/GRPCSwiftBenchmark.Metadata_Iterate_binary_values_when_only_strings_stored.p90.json index b59f05063..9c403f41f 100644 --- a/IntegrationTests/Benchmarks/Thresholds/6.1/GRPCSwiftBenchmark.Metadata_Iterate_binary_values_when_only_strings_stored.p90.json +++ b/IntegrationTests/Benchmarks/Thresholds/6.1/GRPCSwiftBenchmark.Metadata_Iterate_binary_values_when_only_strings_stored.p90.json @@ -1,7 +1,3 @@ { - "mallocCountTotal" : 2000, - "memoryLeaked" : 0, - "releaseCount" : 6001, - "retainCount" : 2000, - "syscalls" : 0 + "mallocCountTotal": 1000 } diff --git a/IntegrationTests/Benchmarks/Thresholds/nightly-main/GRPCSwiftBenchmark.Metadata_Iterate_binary_values_when_only_strings_stored.p90.json b/IntegrationTests/Benchmarks/Thresholds/nightly-main/GRPCSwiftBenchmark.Metadata_Iterate_binary_values_when_only_strings_stored.p90.json index b4aba1c3f..9c403f41f 100644 --- a/IntegrationTests/Benchmarks/Thresholds/nightly-main/GRPCSwiftBenchmark.Metadata_Iterate_binary_values_when_only_strings_stored.p90.json +++ b/IntegrationTests/Benchmarks/Thresholds/nightly-main/GRPCSwiftBenchmark.Metadata_Iterate_binary_values_when_only_strings_stored.p90.json @@ -1,7 +1,3 @@ { - "mallocCountTotal" : 2000, - "memoryLeaked" : 0, - "releaseCount" : 7001, - "retainCount" : 3000, - "syscalls" : 0 + "mallocCountTotal": 1000 } diff --git a/IntegrationTests/Benchmarks/Thresholds/nightly-next/GRPCSwiftBenchmark.Metadata_Iterate_binary_values_when_only_strings_stored.p90.json b/IntegrationTests/Benchmarks/Thresholds/nightly-next/GRPCSwiftBenchmark.Metadata_Iterate_binary_values_when_only_strings_stored.p90.json index b4aba1c3f..9c403f41f 100644 --- a/IntegrationTests/Benchmarks/Thresholds/nightly-next/GRPCSwiftBenchmark.Metadata_Iterate_binary_values_when_only_strings_stored.p90.json +++ b/IntegrationTests/Benchmarks/Thresholds/nightly-next/GRPCSwiftBenchmark.Metadata_Iterate_binary_values_when_only_strings_stored.p90.json @@ -1,7 +1,3 @@ { - "mallocCountTotal" : 2000, - "memoryLeaked" : 0, - "releaseCount" : 7001, - "retainCount" : 3000, - "syscalls" : 0 + "mallocCountTotal": 1000 }