| File: ServerProtocol\ServerResponse.cs | Web Access |
| Project: src\sdk\src\RazorSdk\Tool\Microsoft.NET.Sdk.Razor.Tool.csproj (rzc) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // After the server pipe is connected, it forks off a thread to handle the connection, and creates // a new instance of the pipe to listen for new clients. When it gets a request, it validates // the security and elevation level of the client. If that fails, it disconnects the client. Otherwise, // it handles the request, sends a response (described by Response class) back to the client, then // disconnects the pipe and ends the thread. namespace Microsoft.NET.Sdk.Razor.Tool { /// <summary> /// Base class for all possible responses to a request. /// The ResponseType enum should list all possible response types /// and ReadResponse creates the appropriate response subclass based /// on the response type sent by the client. /// The format of a response is: /// /// Field Name Field Type Size (bytes) /// ------------------------------------------------- /// responseLength int (positive) 4 /// responseType enum ResponseType 4 /// responseBody Response subclass variable /// </summary> internal abstract class ServerResponse { public enum ResponseType { // The client and server are using incompatible protocol versions. MismatchedVersion, // The build request completed on the server and the results are contained // in the message. Completed, // The shutdown request completed and the server process information is // contained in the message. Shutdown, // The request was rejected by the server. Rejected, } public abstract ResponseType Type { get; } public async Task WriteAsync(Stream outStream, CancellationToken cancellationToken) { using (var memoryStream = new MemoryStream()) using (var writer = new BinaryWriter(memoryStream, Encoding.Unicode)) { // Format the response ServerLogger.Log("Formatting Response"); writer.Write((int)Type); AddResponseBody(writer); writer.Flush(); cancellationToken.ThrowIfCancellationRequested(); // Send the response to the client // Write the length of the response var length = checked((int)memoryStream.Length); ServerLogger.Log("Writing response length"); // There is no way to know the number of bytes written to // the pipe stream. We just have to assume all of them are written. await outStream .WriteAsync(BitConverter.GetBytes(length), 0, 4, cancellationToken) .ConfigureAwait(false); // Write the response ServerLogger.Log("Writing response of size {0}", length); memoryStream.Position = 0; await memoryStream .CopyToAsync(outStream, bufferSize: length, cancellationToken: cancellationToken) .ConfigureAwait(false); } } protected abstract void AddResponseBody(BinaryWriter writer); /// <summary> /// May throw exceptions if there are pipe problems. /// </summary> /// <param name="stream"></param> /// <param name="cancellationToken"></param> /// <returns></returns> public static async Task<ServerResponse> ReadAsync(Stream stream, CancellationToken cancellationToken = default(CancellationToken)) { ServerLogger.Log("Reading response length"); // Read the response length var lengthBuffer = new byte[4]; await ServerProtocol.ReadAllAsync(stream, lengthBuffer, 4, cancellationToken).ConfigureAwait(false); var length = BitConverter.ToUInt32(lengthBuffer, 0); // Read the response ServerLogger.Log("Reading response of length {0}", length); var responseBuffer = new byte[length]; await ServerProtocol.ReadAllAsync( stream, responseBuffer, responseBuffer.Length, cancellationToken) .ConfigureAwait(false); using (var reader = new BinaryReader(new MemoryStream(responseBuffer), Encoding.Unicode)) { var responseType = (ResponseType)reader.ReadInt32(); switch (responseType) { case ResponseType.Completed: return CompletedServerResponse.Create(reader); case ResponseType.MismatchedVersion: return new MismatchedVersionServerResponse(); case ResponseType.Shutdown: return ShutdownServerResponse.Create(reader); case ResponseType.Rejected: return new RejectedServerResponse(); default: throw new InvalidOperationException("Received invalid response type from server."); } } } } }