Coverage Report

Created: 2025-06-24 06:59

/src/grpc-swift/Sources/GRPC/DelegatingErrorHandler.swift
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright 2019, 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 Foundation
17
import Logging
18
import NIOCore
19
20
/// A channel handler which allows caught errors to be passed to a `ClientErrorDelegate`. This
21
/// handler is intended to be used in the client channel pipeline after the HTTP/2 stream
22
/// multiplexer to handle errors which occur on the underlying connection.
23
internal final class DelegatingErrorHandler: ChannelInboundHandler {
24
  typealias InboundIn = Any
25
26
  private var logger: Logger
27
  private let delegate: ClientErrorDelegate?
28
29
0
  internal init(logger: Logger, delegate: ClientErrorDelegate?) {
30
0
    self.logger = logger
31
0
    self.delegate = delegate
32
0
  }
33
34
0
  internal func channelActive(context: ChannelHandlerContext) {
35
0
    self.logger.addIPAddressMetadata(local: context.localAddress, remote: context.remoteAddress)
36
0
    context.fireChannelActive()
37
0
  }
38
39
0
  internal func errorCaught(context: ChannelHandlerContext, error: Error) {
40
0
    // We can ignore unclean shutdown since gRPC is self-terminated and therefore not prone to
41
0
    // truncation attacks.
42
0
    //
43
0
    // Without this we would unnecessarily log when we're communicating with peers which don't
44
0
    // send `close_notify`.
45
0
    if error.isNIOSSLUncleanShutdown {
46
0
      return
47
0
    }
48
0
49
0
    if let delegate = self.delegate {
50
0
      if let context = error as? GRPCError.WithContext {
51
0
        delegate.didCatchError(
52
0
          context.error,
53
0
          logger: self.logger,
54
0
          file: context.file,
55
0
          line: context.line
56
0
        )
57
0
      } else {
58
0
        delegate.didCatchErrorWithoutContext(error, logger: self.logger)
59
0
      }
60
0
    }
61
0
    context.close(promise: nil)
62
0
  }
63
}