Coverage Report

Created: 2025-09-08 07:07

/src/grpc-swift/Sources/GRPC/ServerCallContexts/ServerCallContext.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
import NIOHPACK
20
import NIOHTTP1
21
import SwiftProtobuf
22
23
/// Protocol declaring a minimum set of properties exposed by *all* types of call contexts.
24
public protocol ServerCallContext: AnyObject {
25
  /// The event loop this call is served on.
26
  var eventLoop: EventLoop { get }
27
28
  /// Request headers for this request.
29
  var headers: HPACKHeaders { get }
30
31
  /// A 'UserInfo' dictionary which is shared with the interceptor contexts for this RPC.
32
  var userInfo: UserInfo { get set }
33
34
  /// The logger used for this call.
35
  var logger: Logger { get }
36
37
  /// Whether compression should be enabled for responses, defaulting to `true`. Note that for
38
  /// this value to take effect compression must have been enabled on the server and a compression
39
  /// algorithm must have been negotiated with the client.
40
  var compressionEnabled: Bool { get set }
41
42
  /// A future which completes when the call closes. This may be used to register callbacks which
43
  /// free up resources used by the RPC.
44
  var closeFuture: EventLoopFuture<Void> { get }
45
}
46
47
extension ServerCallContext {
48
  // Default implementation to avoid breaking API.
49
0
  public var closeFuture: EventLoopFuture<Void> {
50
0
    return self.eventLoop.makeFailedFuture(GRPCStatus.closeFutureNotImplemented)
51
0
  }
52
}
53
54
extension GRPCStatus {
55
  internal static let closeFutureNotImplemented = GRPCStatus(
56
    code: .unimplemented,
57
    message: "This context type has not implemented support for a 'closeFuture'"
58
  )
59
}
60
61
/// Base class providing data provided to the framework user for all server calls.
62
open class ServerCallContextBase: ServerCallContext {
63
  /// The event loop this call is served on.
64
  public let eventLoop: EventLoop
65
66
  /// Request headers for this request.
67
  public let headers: HPACKHeaders
68
69
  /// The logger used for this call.
70
  public let logger: Logger
71
72
  /// Whether compression should be enabled for responses, defaulting to `true`. Note that for
73
  /// this value to take effect compression must have been enabled on the server and a compression
74
  /// algorithm must have been negotiated with the client.
75
  ///
76
  /// - Important: This  *must* be accessed from the context's `eventLoop` in order to ensure
77
  ///   thread-safety.
78
  public var compressionEnabled: Bool {
79
0
    get {
80
0
      self.eventLoop.assertInEventLoop()
81
0
      return self._compressionEnabled
82
0
    }
83
0
    set {
84
0
      self.eventLoop.assertInEventLoop()
85
0
      self._compressionEnabled = newValue
86
0
    }
87
  }
88
89
2.93M
  private var _compressionEnabled: Bool = true
90
91
  /// A `UserInfo` dictionary which is shared with the interceptor contexts for this RPC.
92
  ///
93
  /// - Important: While ``UserInfo`` has value-semantics, this property retrieves from, and sets a
94
  ///   reference wrapped ``UserInfo``. The contexts passed to interceptors provide the same
95
  ///   reference. As such this may be used as a mechanism to pass information between interceptors
96
  ///   and service providers.
97
  /// - Important: This  *must* be accessed from the context's `eventLoop` in order to ensure
98
  ///   thread-safety.
99
  public var userInfo: UserInfo {
100
0
    get {
101
0
      self.eventLoop.assertInEventLoop()
102
0
      return self.userInfoRef.value
103
0
    }
104
0
    set {
105
0
      self.eventLoop.assertInEventLoop()
106
0
      self.userInfoRef.value = newValue
107
0
    }
108
  }
109
110
  /// A reference to an underlying ``UserInfo``. We share this with the interceptors.
111
  @usableFromInline
112
  internal let userInfoRef: Ref<UserInfo>
113
114
  /// Metadata to return at the end of the RPC. If this is required it should be updated before
115
  /// the `responsePromise` or `statusPromise` is fulfilled.
116
  ///
117
  /// - Important: This  *must* be accessed from the context's `eventLoop` in order to ensure
118
  ///   thread-safety.
119
  public var trailers: HPACKHeaders {
120
1.78M
    get {
121
1.78M
      self.eventLoop.assertInEventLoop()
122
1.78M
      return self._trailers
123
1.78M
    }
124
0
    set {
125
0
      self.eventLoop.assertInEventLoop()
126
0
      self._trailers = newValue
127
0
    }
128
  }
129
130
1.89M
  private var _trailers: HPACKHeaders = [:]
131
132
  /// A future which completes when the call closes. This may be used to register callbacks which
133
  /// free up resources used by the RPC.
134
  public let closeFuture: EventLoopFuture<Void>
135
136
  @available(*, deprecated, renamed: "init(eventLoop:headers:logger:userInfo:closeFuture:)")
137
  public convenience init(
138
    eventLoop: EventLoop,
139
    headers: HPACKHeaders,
140
    logger: Logger,
141
    userInfo: UserInfo = UserInfo()
142
0
  ) {
143
0
    self.init(
144
0
      eventLoop: eventLoop,
145
0
      headers: headers,
146
0
      logger: logger,
147
0
      userInfoRef: .init(userInfo),
148
0
      closeFuture: eventLoop.makeFailedFuture(GRPCStatus.closeFutureNotImplemented)
149
0
    )
150
0
  }
151
152
  public convenience init(
153
    eventLoop: EventLoop,
154
    headers: HPACKHeaders,
155
    logger: Logger,
156
    userInfo: UserInfo = UserInfo(),
157
    closeFuture: EventLoopFuture<Void>
158
0
  ) {
159
0
    self.init(
160
0
      eventLoop: eventLoop,
161
0
      headers: headers,
162
0
      logger: logger,
163
0
      userInfoRef: .init(userInfo),
164
0
      closeFuture: closeFuture
165
0
    )
166
0
  }
167
168
  @inlinable
169
  internal init(
170
    eventLoop: EventLoop,
171
    headers: HPACKHeaders,
172
    logger: Logger,
173
    userInfoRef: Ref<UserInfo>,
174
    closeFuture: EventLoopFuture<Void>
175
1.89M
  ) {
176
1.89M
    self.eventLoop = eventLoop
177
1.89M
    self.headers = headers
178
1.89M
    self.userInfoRef = userInfoRef
179
1.89M
    self.logger = logger
180
1.89M
    self.closeFuture = closeFuture
181
1.89M
  }
182
}