Browse Source

Use iterator when checking encoding headers (#1563)

Motivation:

SwiftNIO HTTP/2 1.24.0 added a method for retrieving a sequence of
header values rather than directly returning an array of values. We can
use it when checking the encoding header as there should only be at most
one value.

Modifications:

- Update HTTP/2 to be min 1.24.0
- Use the iterator API

Result:

Fewer allocations.
George Barnett 2 years ago
parent
commit
a70e9ad757
3 changed files with 15 additions and 8 deletions
  1. 2 2
      .github/workflows/ci.yaml
  2. 1 1
      Package.swift
  3. 12 5
      Sources/GRPC/HTTP2ToRawGRPCStateMachine.swift

+ 2 - 2
.github/workflows/ci.yaml

@@ -16,8 +16,8 @@ jobs:
       run: |
         SWIFTFORMAT_VERSION=0.49.4
         git clone --depth 1 --branch "$SWIFTFORMAT_VERSION" "https://github.com/nicklockwood/SwiftFormat" "$HOME/SwiftFormat"
-        swift build --package-path "$HOME/SwiftFormat" --product swiftformat
-        export PATH=$PATH:"$(swift build --package-path "$HOME/SwiftFormat" --show-bin-path)"
+        swift build -c release --package-path "$HOME/SwiftFormat" --product swiftformat
+        export PATH=$PATH:"$(swift build -c release --package-path "$HOME/SwiftFormat" --show-bin-path)"
         ./scripts/sanity.sh
   unit-tests:
     strategy:

+ 1 - 1
Package.swift

@@ -36,7 +36,7 @@ let packageDependencies: [Package.Dependency] = [
   ),
   .package(
     url: "https://github.com/apple/swift-nio-http2.git",
-    from: "1.22.0"
+    from: "1.24.1"
   ),
   .package(
     url: "https://github.com/apple/swift-nio-transport-services.git",

+ 12 - 5
Sources/GRPC/HTTP2ToRawGRPCStateMachine.swift

@@ -447,10 +447,19 @@ extension HTTP2ToRawGRPCStateMachine.State {
     from headers: HPACKHeaders,
     encoding: ServerMessageEncoding
   ) -> RequestEncodingValidation {
-    let encodings = headers[canonicalForm: GRPCHeaderName.encoding]
+    let encodingValues = headers.values(forHeader: GRPCHeaderName.encoding, canonicalForm: true)
+    var encodingIterator = encodingValues.makeIterator()
+    let encodingHeader = encodingIterator.next()
 
     // Fail if there's more than one encoding header.
-    if encodings.count > 1 {
+    if let first = encodingHeader, let second = encodingIterator.next() {
+      var encodings: [Substring] = []
+      encodings.reserveCapacity(8)
+      encodings.append(first)
+      encodings.append(second)
+      while let next = encodingIterator.next() {
+        encodings.append(next)
+      }
       let status = GRPCStatus(
         code: .invalidArgument,
         message: "'\(GRPCHeaderName.encoding)' must contain no more than one value but was '\(encodings.joined(separator: ", "))'"
@@ -458,12 +467,10 @@ extension HTTP2ToRawGRPCStateMachine.State {
       return .invalid(status: status, acceptEncoding: nil)
     }
 
-    let encodingHeader = encodings.first
     let result: RequestEncodingValidation
-
     let validator = MessageEncodingHeaderValidator(encoding: encoding)
 
-    switch validator.validate(requestEncoding: encodingHeader) {
+    switch validator.validate(requestEncoding: encodingHeader.map { String($0) }) {
     case let .supported(algorithm, decompressionLimit, acceptEncoding):
       // Request message encoding is valid and supported.
       result = .valid(