| #region Copyright notice and license |
| |
| // Copyright 2015 gRPC authors. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| #endregion |
| |
| using System; |
| using System.Threading; |
| using System.Threading.Tasks; |
| |
| using Grpc.Core.Internal; |
| |
| namespace Grpc.Core |
| { |
| /// <summary> |
| /// Context for a server-side call. |
| /// </summary> |
| public class ServerCallContext |
| { |
| private readonly CallSafeHandle callHandle; |
| private readonly string method; |
| private readonly string host; |
| private readonly DateTime deadline; |
| private readonly Metadata requestHeaders; |
| private readonly CancellationToken cancellationToken; |
| private readonly Metadata responseTrailers = new Metadata(); |
| private readonly Func<Metadata, Task> writeHeadersFunc; |
| private readonly IHasWriteOptions writeOptionsHolder; |
| private readonly Lazy<AuthContext> authContext; |
| private readonly Func<string> testingOnlyPeerGetter; |
| private readonly Func<AuthContext> testingOnlyAuthContextGetter; |
| private readonly Func<ContextPropagationToken> testingOnlyContextPropagationTokenFactory; |
| |
| private Status status = Status.DefaultSuccess; |
| |
| internal ServerCallContext(CallSafeHandle callHandle, string method, string host, DateTime deadline, Metadata requestHeaders, CancellationToken cancellationToken, |
| Func<Metadata, Task> writeHeadersFunc, IHasWriteOptions writeOptionsHolder) |
| : this(callHandle, method, host, deadline, requestHeaders, cancellationToken, writeHeadersFunc, writeOptionsHolder, null, null, null) |
| { |
| } |
| |
| // Additional constructor params should be used for testing only |
| internal 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) |
| { |
| this.callHandle = callHandle; |
| this.method = method; |
| this.host = host; |
| this.deadline = deadline; |
| this.requestHeaders = requestHeaders; |
| this.cancellationToken = cancellationToken; |
| this.writeHeadersFunc = writeHeadersFunc; |
| this.writeOptionsHolder = writeOptionsHolder; |
| this.authContext = new Lazy<AuthContext>(GetAuthContextEager); |
| this.testingOnlyPeerGetter = testingOnlyPeerGetter; |
| this.testingOnlyAuthContextGetter = testingOnlyAuthContextGetter; |
| this.testingOnlyContextPropagationTokenFactory = testingOnlyContextPropagationTokenFactory; |
| } |
| |
| /// <summary> |
| /// 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 |
| /// before any response messages are written. Writing the first response message implicitly sends empty response headers if <c>WriteResponseHeadersAsync</c> haven't |
| /// been called yet. |
| /// </summary> |
| /// <param name="responseHeaders">The response headers to send.</param> |
| /// <returns>The task that finished once response headers have been written.</returns> |
| public Task WriteResponseHeadersAsync(Metadata responseHeaders) |
| { |
| return writeHeadersFunc(responseHeaders); |
| } |
| |
| /// <summary> |
| /// Creates a propagation token to be used to propagate call context to a child call. |
| /// </summary> |
| public ContextPropagationToken CreatePropagationToken(ContextPropagationOptions options = null) |
| { |
| if (testingOnlyContextPropagationTokenFactory != null) |
| { |
| return testingOnlyContextPropagationTokenFactory(); |
| } |
| return new ContextPropagationToken(callHandle, deadline, cancellationToken, options); |
| } |
| |
| /// <summary>Name of method called in this RPC.</summary> |
| public string Method |
| { |
| get |
| { |
| return this.method; |
| } |
| } |
| |
| /// <summary>Name of host called in this RPC.</summary> |
| public string Host |
| { |
| get |
| { |
| return this.host; |
| } |
| } |
| |
| /// <summary>Address of the remote endpoint in URI format.</summary> |
| public string Peer |
| { |
| get |
| { |
| if (testingOnlyPeerGetter != null) |
| { |
| return testingOnlyPeerGetter(); |
| } |
| // Getting the peer lazily is fine as the native call is guaranteed |
| // not to be disposed before user-supplied server side handler returns. |
| // Most users won't need to read this field anyway. |
| return this.callHandle.GetPeer(); |
| } |
| } |
| |
| /// <summary>Deadline for this RPC.</summary> |
| public DateTime Deadline |
| { |
| get |
| { |
| return this.deadline; |
| } |
| } |
| |
| /// <summary>Initial metadata sent by client.</summary> |
| public Metadata RequestHeaders |
| { |
| get |
| { |
| return this.requestHeaders; |
| } |
| } |
| |
| /// <summary>Cancellation token signals when call is cancelled.</summary> |
| public CancellationToken CancellationToken |
| { |
| get |
| { |
| return this.cancellationToken; |
| } |
| } |
| |
| /// <summary>Trailers to send back to client after RPC finishes.</summary> |
| public Metadata ResponseTrailers |
| { |
| get |
| { |
| return this.responseTrailers; |
| } |
| } |
| |
| /// <summary> Status to send back to client after RPC finishes.</summary> |
| public Status Status |
| { |
| get |
| { |
| return this.status; |
| } |
| |
| set |
| { |
| status = value; |
| } |
| } |
| |
| /// <summary> |
| /// Allows setting write options for the following write. |
| /// For streaming response calls, this property is also exposed as on IServerStreamWriter for convenience. |
| /// Both properties are backed by the same underlying value. |
| /// </summary> |
| public WriteOptions WriteOptions |
| { |
| get |
| { |
| return writeOptionsHolder.WriteOptions; |
| } |
| |
| set |
| { |
| writeOptionsHolder.WriteOptions = value; |
| } |
| } |
| |
| /// <summary> |
| /// Gets the <c>AuthContext</c> associated with this call. |
| /// Note: Access to AuthContext is an experimental API that can change without any prior notice. |
| /// </summary> |
| public AuthContext AuthContext |
| { |
| get |
| { |
| if (testingOnlyAuthContextGetter != null) |
| { |
| return testingOnlyAuthContextGetter(); |
| } |
| return authContext.Value; |
| } |
| } |
| |
| private AuthContext GetAuthContextEager() |
| { |
| using (var authContextNative = callHandle.GetAuthContext()) |
| { |
| return authContextNative.ToAuthContext(); |
| } |
| } |
| } |
| |
| /// <summary> |
| /// Allows sharing write options between ServerCallContext and other objects. |
| /// </summary> |
| internal interface IHasWriteOptions |
| { |
| /// <summary> |
| /// Gets or sets the write options. |
| /// </summary> |
| WriteOptions WriteOptions { get; set; } |
| } |
| } |