Coverage Report

Created: 2026-02-11 07:03

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/grpc-swift/Sources/GRPC/ServerErrorProcessor.swift
Line
Count
Source
1
/*
2
 * Copyright 2021, gRPC Authors All rights reserved.
3
 *
4
 * Licensed under the Apache License, Version 2.0 (the "License");
5
 * you may not use this file except in compliance with the License.
6
 * You may obtain a copy of the License at
7
 *
8
 *     http://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
15
 */
16
import NIOHPACK
17
18
@usableFromInline
19
internal enum ServerErrorProcessor {
20
  /// Processes a library error to form a `GRPCStatus` and trailers to send back to the client.
21
  /// - Parameter error: The error to process.
22
  /// - Returns: The status and trailers to send to the client.
23
  @usableFromInline
24
  internal static func processLibraryError(
25
    _ error: Error,
26
    delegate: ServerErrorDelegate?
27
72.3k
  ) -> (GRPCStatus, HPACKHeaders) {
28
72.3k
    // Observe the error if we have a delegate.
29
72.3k
    delegate?.observeLibraryError(error)
30
72.3k
31
72.3k
    // What status are we terminating this RPC with?
32
72.3k
    // - If we have a delegate, try transforming the error. If the delegate returns trailers, merge
33
72.3k
    //   them with any on the call context.
34
72.3k
    // - If we don't have a delegate, then try to transform the error to a status.
35
72.3k
    // - Fallback to a generic error.
36
72.3k
    let status: GRPCStatus
37
72.3k
    let trailers: HPACKHeaders
38
72.3k
39
72.3k
    if let transformed = delegate?.transformLibraryError(error) {
40
0
      status = transformed.status
41
0
      trailers = transformed.trailers ?? [:]
42
23.1k
    } else if let grpcStatusTransformable = error as? GRPCStatusTransformable {
43
23.1k
      status = grpcStatusTransformable.makeGRPCStatus()
44
23.1k
      trailers = [:]
45
49.1k
    } else {
46
49.1k
      // Eh... well, we don't know what status to use. Use a generic one.
47
49.1k
      status = .processingError(cause: error)
48
49.1k
      trailers = [:]
49
49.1k
    }
50
72.3k
51
72.3k
    return (status, trailers)
52
72.3k
  }
53
54
  /// Processes an error, transforming it into a 'GRPCStatus' and any trailers to send to the peer.
55
  @usableFromInline
56
  internal static func processObserverError(
57
    _ error: Error,
58
    headers: HPACKHeaders,
59
    trailers: HPACKHeaders,
60
    delegate: ServerErrorDelegate?
61
0
  ) -> (GRPCStatus, HPACKHeaders) {
62
0
    // Observe the error if we have a delegate.
63
0
    delegate?.observeRequestHandlerError(error, headers: headers)
64
0
65
0
    // What status are we terminating this RPC with?
66
0
    // - If we have a delegate, try transforming the error. If the delegate returns trailers, merge
67
0
    //   them with any on the call context.
68
0
    // - If we don't have a delegate, then try to transform the error to a status.
69
0
    // - Fallback to a generic error.
70
0
    let status: GRPCStatus
71
0
    let mergedTrailers: HPACKHeaders
72
0
73
0
    if let transformed = delegate?.transformRequestHandlerError(error, headers: headers) {
74
0
      status = transformed.status
75
0
      if var transformedTrailers = transformed.trailers {
76
0
        // The delegate returned trailers: merge in those from the context as well.
77
0
        transformedTrailers.add(contentsOf: trailers)
78
0
        mergedTrailers = transformedTrailers
79
0
      } else {
80
0
        mergedTrailers = trailers
81
0
      }
82
0
    } else if let grpcStatusTransformable = error as? GRPCStatusTransformable {
83
0
      status = grpcStatusTransformable.makeGRPCStatus()
84
0
      mergedTrailers = trailers
85
0
    } else {
86
0
      // Eh... well, we don't what status to use. Use a generic one.
87
0
      status = .processingError(cause: error)
88
0
      mergedTrailers = trailers
89
0
    }
90
0
91
0
    return (status, mergedTrailers)
92
0
  }
93
}