Coverage Report

Created: 2026-07-30 06:36

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/grpc-swift/Sources/GRPC/AsyncAwaitSupport/GRPCAsyncServerCallContext.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 Logging
17
import NIOConcurrencyHelpers
18
import NIOHPACK
19
20
@available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *)
21
public struct GRPCAsyncServerCallContext: Sendable {
22
  @usableFromInline
23
  let contextProvider: AsyncServerCallContextProvider
24
25
  /// Details of the request, including request headers and a logger.
26
  public var request: Request
27
28
  /// A response context which may be used to set response headers and trailers.
29
0
  public var response: Response {
30
0
    Response(contextProvider: self.contextProvider)
31
0
  }
32
33
  /// Notifies the client that the RPC has been accepted for processing by the server.
34
  ///
35
  /// On accepting the RPC the server will send the given headers (which may be empty) along with
36
  /// any transport specific headers (such the ":status" pseudo header) to the client.
37
  ///
38
  /// It is not necessary to call this function: the RPC is implicitly accepted when the first
39
  /// response message is sent, however this may be useful when clients require an early indication
40
  /// that the RPC has been accepted.
41
  ///
42
  /// If the RPC has already been accepted (either implicitly or explicitly) then this function is
43
  /// a no-op.
44
0
  public func acceptRPC(headers: HPACKHeaders) async {
45
0
    await self.contextProvider.acceptRPC(headers)
46
0
  }
47
48
  /// Access the ``UserInfo`` dictionary which is shared with the interceptor contexts for this RPC.
49
  ///
50
  /// - Important: While ``UserInfo`` has value-semantics, this function accesses a reference
51
  ///   wrapped ``UserInfo``. The contexts passed to interceptors provide the same reference. As such
52
  ///   this may be used as a mechanism to pass information between interceptors and service
53
  ///   providers.
54
  public func withUserInfo<Result: Sendable>(
55
    _ body: @Sendable @escaping (UserInfo) throws -> Result
56
0
  ) async throws -> Result {
57
0
    return try await self.contextProvider.withUserInfo(body)
58
0
  }
59
60
  /// Modify the ``UserInfo`` dictionary which is shared with the interceptor contexts for this RPC.
61
  ///
62
  /// - Important: While ``UserInfo`` has value-semantics, this function accesses a reference
63
  ///   wrapped ``UserInfo``. The contexts passed to interceptors provide the same reference. As such
64
  ///   this may be used as a mechanism to pass information between interceptors and service
65
  ///   providers.
66
  public func withMutableUserInfo<Result: Sendable>(
67
    _ modify: @Sendable @escaping (inout UserInfo) -> Result
68
0
  ) async throws -> Result {
69
0
    return try await self.contextProvider.withMutableUserInfo(modify)
70
0
  }
71
72
  @inlinable
73
  internal init(
74
    headers: HPACKHeaders,
75
    logger: Logger,
76
    contextProvider: AsyncServerCallContextProvider
77
0
  ) {
78
0
    self.request = Request(headers: headers, logger: logger)
79
0
    self.contextProvider = contextProvider
80
0
  }
81
}
82
83
@available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *)
84
extension GRPCAsyncServerCallContext {
85
  public struct Request: Sendable {
86
    /// The request headers received from the client at the start of the RPC.
87
    public var headers: HPACKHeaders
88
89
    /// A logger.
90
    public var logger: Logger
91
92
    @usableFromInline
93
0
    init(headers: HPACKHeaders, logger: Logger) {
94
0
      self.headers = headers
95
0
      self.logger = logger
96
0
    }
97
  }
98
99
  public struct Response: Sendable {
100
    private let contextProvider: AsyncServerCallContextProvider
101
102
    /// Set the metadata to return at the start of the RPC.
103
    ///
104
    /// - Important: If this is required it should be updated _before_ the first response is sent
105
    ///   via the response stream writer. Updates must not be made after the RPC has been accepted
106
    ///   or the first response has been sent otherwise this method will throw an error.
107
0
    public func setHeaders(_ headers: HPACKHeaders) async throws {
108
0
      try await self.contextProvider.setResponseHeaders(headers)
109
0
    }
110
111
    /// Set the metadata to return at the end of the RPC.
112
    ///
113
    /// If this is required it must be updated before returning from the handler.
114
0
    public func setTrailers(_ trailers: HPACKHeaders) async throws {
115
0
      try await self.contextProvider.setResponseTrailers(trailers)
116
0
    }
117
118
    /// Whether compression should be enabled for responses, defaulting to `true`. Note that for
119
    /// this value to take effect compression must have been enabled on the server and a compression
120
    /// algorithm must have been negotiated with the client.
121
0
    public func compressResponses(_ compress: Bool) async throws {
122
0
      try await self.contextProvider.setResponseCompression(compress)
123
0
    }
124
125
    @usableFromInline
126
0
    internal init(contextProvider: AsyncServerCallContextProvider) {
127
0
      self.contextProvider = contextProvider
128
0
    }
129
  }
130
}