1 #region Copyright notice and license 2 3 // Copyright 2015 gRPC authors. 4 // 5 // Licensed under the Apache License, Version 2.0 (the "License"); 6 // you may not use this file except in compliance with the License. 7 // You may obtain a copy of the License at 8 // 9 // http://www.apache.org/licenses/LICENSE-2.0 10 // 11 // Unless required by applicable law or agreed to in writing, software 12 // distributed under the License is distributed on an "AS IS" BASIS, 13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 // See the License for the specific language governing permissions and 15 // limitations under the License. 16 17 #endregion 18 19 using System; 20 using System.Threading; 21 using System.Threading.Tasks; 22 23 using Grpc.Core.Internal; 24 25 namespace Grpc.Core 26 { 27 /// <summary> 28 /// Context for a server-side call. 29 /// </summary> 30 public class ServerCallContext 31 { 32 private readonly CallSafeHandle callHandle; 33 private readonly string method; 34 private readonly string host; 35 private readonly DateTime deadline; 36 private readonly Metadata requestHeaders; 37 private readonly CancellationToken cancellationToken; 38 private readonly Metadata responseTrailers = new Metadata(); 39 private readonly Func<Metadata, Task> writeHeadersFunc; 40 private readonly IHasWriteOptions writeOptionsHolder; 41 private readonly Lazy<AuthContext> authContext; 42 private readonly Func<string> testingOnlyPeerGetter; 43 private readonly Func<AuthContext> testingOnlyAuthContextGetter; 44 private readonly Func<ContextPropagationToken> testingOnlyContextPropagationTokenFactory; 45 46 private Status status = Status.DefaultSuccess; 47 ServerCallContext(CallSafeHandle callHandle, string method, string host, DateTime deadline, Metadata requestHeaders, CancellationToken cancellationToken, Func<Metadata, Task> writeHeadersFunc, IHasWriteOptions writeOptionsHolder)48 internal ServerCallContext(CallSafeHandle callHandle, string method, string host, DateTime deadline, Metadata requestHeaders, CancellationToken cancellationToken, 49 Func<Metadata, Task> writeHeadersFunc, IHasWriteOptions writeOptionsHolder) 50 : this(callHandle, method, host, deadline, requestHeaders, cancellationToken, writeHeadersFunc, writeOptionsHolder, null, null, null) 51 { 52 } 53 54 // Additional constructor params should be used for testing only ServerCallContext(CallSafeHandle callHandle, string method, string host, DateTime deadline, Metadata requestHeaders, CancellationToken cancellationToken, Func<Metadata, Task> writeHeadersFunc, IHasWriteOptions writeOptionsHolder, Func<string> testingOnlyPeerGetter, Func<AuthContext> testingOnlyAuthContextGetter, Func<ContextPropagationToken> testingOnlyContextPropagationTokenFactory)55 internal ServerCallContext(CallSafeHandle callHandle, string method, string host, DateTime deadline, Metadata requestHeaders, CancellationToken cancellationToken, 56 Func<Metadata, Task> writeHeadersFunc, IHasWriteOptions writeOptionsHolder, 57 Func<string> testingOnlyPeerGetter, Func<AuthContext> testingOnlyAuthContextGetter, Func<ContextPropagationToken> testingOnlyContextPropagationTokenFactory) 58 { 59 this.callHandle = callHandle; 60 this.method = method; 61 this.host = host; 62 this.deadline = deadline; 63 this.requestHeaders = requestHeaders; 64 this.cancellationToken = cancellationToken; 65 this.writeHeadersFunc = writeHeadersFunc; 66 this.writeOptionsHolder = writeOptionsHolder; 67 this.authContext = new Lazy<AuthContext>(GetAuthContextEager); 68 this.testingOnlyPeerGetter = testingOnlyPeerGetter; 69 this.testingOnlyAuthContextGetter = testingOnlyAuthContextGetter; 70 this.testingOnlyContextPropagationTokenFactory = testingOnlyContextPropagationTokenFactory; 71 } 72 73 /// <summary> 74 /// Asynchronously sends response headers for the current call to the client. This method may only be invoked once for each call and needs to be invoked 75 /// before any response messages are written. Writing the first response message implicitly sends empty response headers if <c>WriteResponseHeadersAsync</c> haven't 76 /// been called yet. 77 /// </summary> 78 /// <param name="responseHeaders">The response headers to send.</param> 79 /// <returns>The task that finished once response headers have been written.</returns> WriteResponseHeadersAsync(Metadata responseHeaders)80 public Task WriteResponseHeadersAsync(Metadata responseHeaders) 81 { 82 return writeHeadersFunc(responseHeaders); 83 } 84 85 /// <summary> 86 /// Creates a propagation token to be used to propagate call context to a child call. 87 /// </summary> CreatePropagationToken(ContextPropagationOptions options = null)88 public ContextPropagationToken CreatePropagationToken(ContextPropagationOptions options = null) 89 { 90 if (testingOnlyContextPropagationTokenFactory != null) 91 { 92 return testingOnlyContextPropagationTokenFactory(); 93 } 94 return new ContextPropagationToken(callHandle, deadline, cancellationToken, options); 95 } 96 97 /// <summary>Name of method called in this RPC.</summary> 98 public string Method 99 { 100 get 101 { 102 return this.method; 103 } 104 } 105 106 /// <summary>Name of host called in this RPC.</summary> 107 public string Host 108 { 109 get 110 { 111 return this.host; 112 } 113 } 114 115 /// <summary>Address of the remote endpoint in URI format.</summary> 116 public string Peer 117 { 118 get 119 { 120 if (testingOnlyPeerGetter != null) 121 { 122 return testingOnlyPeerGetter(); 123 } 124 // Getting the peer lazily is fine as the native call is guaranteed 125 // not to be disposed before user-supplied server side handler returns. 126 // Most users won't need to read this field anyway. 127 return this.callHandle.GetPeer(); 128 } 129 } 130 131 /// <summary>Deadline for this RPC.</summary> 132 public DateTime Deadline 133 { 134 get 135 { 136 return this.deadline; 137 } 138 } 139 140 /// <summary>Initial metadata sent by client.</summary> 141 public Metadata RequestHeaders 142 { 143 get 144 { 145 return this.requestHeaders; 146 } 147 } 148 149 /// <summary>Cancellation token signals when call is cancelled.</summary> 150 public CancellationToken CancellationToken 151 { 152 get 153 { 154 return this.cancellationToken; 155 } 156 } 157 158 /// <summary>Trailers to send back to client after RPC finishes.</summary> 159 public Metadata ResponseTrailers 160 { 161 get 162 { 163 return this.responseTrailers; 164 } 165 } 166 167 /// <summary> Status to send back to client after RPC finishes.</summary> 168 public Status Status 169 { 170 get 171 { 172 return this.status; 173 } 174 175 set 176 { 177 status = value; 178 } 179 } 180 181 /// <summary> 182 /// Allows setting write options for the following write. 183 /// For streaming response calls, this property is also exposed as on IServerStreamWriter for convenience. 184 /// Both properties are backed by the same underlying value. 185 /// </summary> 186 public WriteOptions WriteOptions 187 { 188 get 189 { 190 return writeOptionsHolder.WriteOptions; 191 } 192 193 set 194 { 195 writeOptionsHolder.WriteOptions = value; 196 } 197 } 198 199 /// <summary> 200 /// Gets the <c>AuthContext</c> associated with this call. 201 /// Note: Access to AuthContext is an experimental API that can change without any prior notice. 202 /// </summary> 203 public AuthContext AuthContext 204 { 205 get 206 { 207 if (testingOnlyAuthContextGetter != null) 208 { 209 return testingOnlyAuthContextGetter(); 210 } 211 return authContext.Value; 212 } 213 } 214 GetAuthContextEager()215 private AuthContext GetAuthContextEager() 216 { 217 using (var authContextNative = callHandle.GetAuthContext()) 218 { 219 return authContextNative.ToAuthContext(); 220 } 221 } 222 } 223 224 /// <summary> 225 /// Allows sharing write options between ServerCallContext and other objects. 226 /// </summary> 227 internal interface IHasWriteOptions 228 { 229 /// <summary> 230 /// Gets or sets the write options. 231 /// </summary> 232 WriteOptions WriteOptions { get; set; } 233 } 234 } 235