Coverage Report

Created: 2026-06-15 07:01

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/grpc-swift/Sources/GRPC/Interceptor/ClientInterceptors.swift
Line
Count
Source
1
/*
2
 * Copyright 2020, 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 NIOCore
17
18
/// A base class for client interceptors.
19
///
20
/// Interceptors allow request and response parts to be observed, mutated or dropped as necessary.
21
/// The default behaviour for this base class is to forward any events to the next interceptor.
22
///
23
/// Interceptors may observe a number of different events:
24
/// - receiving response parts with ``receive(_:context:)-5v1ih``,
25
/// - receiving errors with ``errorCaught(_:context:)-6pncp``,
26
/// - sending request parts with ``send(_:promise:context:)-4igtj``, and
27
/// - RPC cancellation with ``cancel(promise:context:)-5tkf5``.
28
///
29
/// These events flow through a pipeline of interceptors for each RPC. Request parts sent from the
30
/// call object (e.g. ``UnaryCall``, ``BidirectionalStreamingCall``) will traverse the pipeline in the
31
/// outbound direction from its tail via ``send(_:promise:context:)-4igtj`` eventually reaching the head of the
32
/// pipeline where it will be sent sent to the server.
33
///
34
/// Response parts, or errors, received from the transport fill be fired in the inbound direction
35
/// back through the interceptor pipeline via ``receive(_:context:)-5v1ih`` and ``errorCaught(_:context:)-6pncp``,
36
/// respectively. Note that the `end` response part and any error received are terminal: the
37
/// pipeline will be torn down once these parts reach the the tail and are a signal that the
38
/// interceptor should free up any resources it may be using.
39
///
40
/// Each of the interceptor functions is provided with a `context` which exposes analogous functions
41
/// (``receive(_:context:)-5v1ih``, ``errorCaught(_:context:)-6pncp``, ``send(_:promise:context:)-4igtj``, and ``cancel(promise:context:)-5tkf5``) which may be
42
/// called to forward events to the next interceptor in the appropriate direction.
43
///
44
/// ### Thread Safety
45
///
46
/// Functions on `context` are not thread safe and **must** be called on the `EventLoop` found on
47
/// the `context`. Since each interceptor is invoked on the same `EventLoop` this does not usually
48
/// require any extra attention. However, if work is done on a `DispatchQueue` or _other_
49
/// `EventLoop` then implementers should ensure that they use `context` from the correct
50
/// `EventLoop`.
51
@preconcurrency open class ClientInterceptor<Request, Response>: @unchecked Sendable {
52
0
  public init() {}
53
54
  /// Called when the interceptor has received a response part to handle.
55
  /// - Parameters:
56
  ///   - part: The response part which has been received from the server.
57
  ///   - context: An interceptor context which may be used to forward the response part.
58
  open func receive(
59
    _ part: GRPCClientResponsePart<Response>,
60
    context: ClientInterceptorContext<Request, Response>
61
0
  ) {
62
0
    context.receive(part)
63
0
  }
64
65
  /// Called when the interceptor has received an error.
66
  /// - Parameters:
67
  ///   - error: The error.
68
  ///   - context: An interceptor context which may be used to forward the error.
69
  open func errorCaught(
70
    _ error: Error,
71
    context: ClientInterceptorContext<Request, Response>
72
0
  ) {
73
0
    context.errorCaught(error)
74
0
  }
75
76
  /// Called when the interceptor has received a request part to handle.
77
  /// - Parameters:
78
  ///   - part: The request part which should be sent to the server.
79
  ///   - promise: A promise which should be completed when the response part has been handled.
80
  ///   - context: An interceptor context which may be used to forward the request part.
81
  open func send(
82
    _ part: GRPCClientRequestPart<Request>,
83
    promise: EventLoopPromise<Void>?,
84
    context: ClientInterceptorContext<Request, Response>
85
0
  ) {
86
0
    context.send(part, promise: promise)
87
0
  }
88
89
  /// Called when the interceptor has received a request to cancel the RPC.
90
  /// - Parameters:
91
  ///   - promise: A promise which should be cancellation request has been handled.
92
  ///   - context: An interceptor context which may be used to forward the cancellation request.
93
  open func cancel(
94
    promise: EventLoopPromise<Void>?,
95
    context: ClientInterceptorContext<Request, Response>
96
0
  ) {
97
0
    context.cancel(promise: promise)
98
0
  }
99
}