public static async Task <byte[]> ToArrayAsync(this Stream stream, CancellationToken cancellationToken = default) { var bufferOwner = BufferArrayPool <byte> .Rent(1024 * 16); var buffer = bufferOwner.AsMemory(); var totalRead = 0; int read; try { while ((read = await stream.ReadAsync(buffer.Slice(totalRead, buffer.Length - totalRead), cancellationToken)) > 0) { totalRead += read; if (totalRead == buffer.Length) { BufferArrayPool <byte> .Grow(ref bufferOwner, buffer.Length * 2); buffer = bufferOwner.AsMemory(); } } var bytes = new byte[totalRead]; buffer.Slice(0, totalRead).Span.CopyTo(bytes.AsSpan()); return(bytes); } finally { buffer.Span.Slice(0, totalRead).Clear(); BufferArrayPool <byte> .Return(bufferOwner); } }
public static async Task <byte[]> ToArrayAsync(this Stream stream, CancellationToken cancellationToken = default) { var buffer = BufferArrayPool <byte> .Rent(1024 * 16); var totalRead = 0; int read; try { while ((read = await stream.ReadAsync(buffer, totalRead, buffer.Length - totalRead, cancellationToken)) > 0) { totalRead += read; if (totalRead == buffer.Length) { BufferArrayPool <byte> .Grow(ref buffer, buffer.Length * 2); } } var bytes = new byte[totalRead]; Buffer.BlockCopy(buffer, 0, bytes, 0, totalRead); return(bytes); } finally { Array.Clear(buffer, 0, totalRead); BufferArrayPool <byte> .Return(buffer); } }
public static byte[] ToArray(this Stream stream) { var bufferOwner = BufferArrayPool <byte> .Rent(1024 * 16); var buffer = bufferOwner.AsSpan(); var totalRead = 0; int read; try { while ((read = stream.Read(buffer.Slice(totalRead, buffer.Length - totalRead))) > 0) { totalRead += read; if (totalRead == buffer.Length) { BufferArrayPool <byte> .Grow(ref bufferOwner, bufferOwner.Length * 2); buffer = bufferOwner.AsSpan(); } } var bytes = new byte[totalRead]; Buffer.BlockCopy(bufferOwner, 0, bytes, 0, totalRead); return(bytes); } finally { buffer.Slice(0, totalRead).Clear(); BufferArrayPool <byte> .Return(bufferOwner); } }
public static string ToBase64String(byte[] inArray) { var arrayString = Convert.ToBase64String(inArray); var chars = arrayString.AsSpan(); int filteredLength = chars.Length; if (chars.Length > 0 && chars[chars.Length - 1] == '=') { filteredLength--; if (chars.Length > 1 && chars[chars.Length - 2] == '=') { filteredLength--; } } var filtered = BufferArrayPool <char> .Rent(filteredLength); for (var i = 0; i < filteredLength; i++) { var c = chars[i]; filtered[i] = c switch { '+' => '-', '/' => '_', _ => c, }; } var filteredString = new String(filtered, 0, filteredLength); Array.Clear(filtered, 0, filteredLength); BufferArrayPool <char> .Return(filtered); return(filteredString); }
protected override void Dispose(bool disposing) { if (segmentLengthBufferSource != null) { BufferArrayPool <byte> .Return(segmentLengthBufferSource); segmentLengthBufferSource = null; segmentLengthBuffer = null; } base.Dispose(disposing); }
public override ValueTask DisposeAsync() { if (segmentLengthBufferSource != null) { BufferArrayPool <byte> .Return(segmentLengthBufferSource); segmentLengthBufferSource = null; segmentLengthBuffer = null; } return(base.DisposeAsync()); }
public static int ReadToSpan(this StreamReader stream, Span <char> span) { var buffer = BufferArrayPool <char> .Rent(span.Length); var totalRead = 0; try { totalRead = stream.Read(buffer, 0, span.Length); buffer.AsSpan().Slice(0, totalRead).CopyTo(span); } finally { Array.Clear(buffer, 0, totalRead); BufferArrayPool <char> .Return(buffer); } return(totalRead); }
public static async Task <int> ReadToMemoryAsync(this StreamReader stream, Memory <char> memory) { var buffer = BufferArrayPool <char> .Rent(memory.Length); var totalRead = 0; try { totalRead = await stream.ReadAsync(buffer, 0, memory.Length); buffer.AsSpan().Slice(0, totalRead).CopyTo(memory.Span); } finally { Array.Clear(buffer, 0, totalRead); BufferArrayPool <char> .Return(buffer); } return(totalRead); }
public static async Task <int> ReadToMemoryAsync(this Stream stream, Memory <byte> memory, CancellationToken cancellationToken = default) { var buffer = BufferArrayPool <byte> .Rent(memory.Length); var totalRead = 0; try { totalRead = await stream.ReadAsync(buffer, 0, memory.Length, cancellationToken); buffer.AsSpan().Slice(0, totalRead).CopyTo(memory.Span); } finally { Array.Clear(buffer, 0, totalRead); BufferArrayPool <byte> .Return(buffer); } return(totalRead); }
public static byte[] FromBase64String(string s) { var chars = s.ToCharArray(); var filteredLength = (chars.Length % 4) switch { 0 => chars.Length, 2 => chars.Length + 2, 3 => chars.Length + 1, _ => throw new FormatException("Invalid string"), }; var filtered = BufferArrayPool <char> .Rent(filteredLength); for (var i = 0; i < chars.Length; i++) { var c = chars[i]; filtered[i] = c switch { '-' => '+', '_' => '/', _ => c, }; } switch (chars.Length % 4) { case 2: filtered[filteredLength - 2] = '='; filtered[filteredLength - 1] = '='; break; case 3: filtered[filteredLength - 1] = '='; break; } var filteredString = new String(filtered, 0, filteredLength); Array.Clear(filtered, 0, filteredLength); BufferArrayPool <char> .Return(filtered); return(Convert.FromBase64String(filteredString)); }
protected override void Dispose(bool disposing) { if (keyBufferOwner != null) { Array.Clear(keyBufferOwner, 0, keyBufferOwner.Length); BufferArrayPool <byte> .Return(keyBufferOwner); keyBufferOwner = null; keyBuffer = null; } if (workingBufferOwner != null) { Array.Clear(workingBufferOwner, 0, workingBufferOwner.Length); BufferArrayPool <byte> .Return(workingBufferOwner); workingBufferOwner = null; workingBuffer = null; } base.Dispose(disposing); }
public override ValueTask DisposeAsync() { if (keyBufferOwner != null) { Array.Clear(keyBufferOwner, 0, keyBufferOwner.Length); BufferArrayPool <byte> .Return(keyBufferOwner); keyBufferOwner = null; keyBuffer = null; } if (workingBufferOwner != null) { Array.Clear(workingBufferOwner, 0, workingBufferOwner.Length); BufferArrayPool <byte> .Return(workingBufferOwner); workingBufferOwner = null; workingBuffer = null; } return(base.DisposeAsync()); }
public static unsafe T Deserialize <T>(string queryString) { var model = Instantiator.CreateInstance <T>(); var typeDetail = TypeAnalyzer.GetTypeDetail(typeof(T)); var bufferOwner = BufferArrayPool <char> .Rent(256); var buffer = bufferOwner.AsSpan(); var bufferLength = 0; try { fixed(char *pFixed = queryString) { char * p = pFixed; string name = null; for (var i = 0; i < queryString.Length; i++) { var c = *p; switch (c) { case '=': if (name != null) { throw new Exception($"Invalid query string at position {i}"); } #if NETSTANDARD2_0 name = new String(bufferOwner, 0, bufferLength); #else name = new String(buffer.Slice(0, bufferLength)); #endif bufferLength = 0; break; case '&': if (name == null) { throw new Exception($"Invalid query string at position {i}"); } #if NETSTANDARD2_0 var value = new String(bufferOwner, 0, bufferLength); #else var value = new String(buffer.Slice(0, bufferLength)); #endif SetValue(typeDetail, model, WebUtility.UrlDecode(name), WebUtility.UrlDecode(value)); name = null; bufferLength = 0; break; default: if (bufferLength == buffer.Length) { BufferArrayPool <char> .Grow(ref bufferOwner, bufferOwner.Length * 2); buffer = bufferOwner.AsSpan(); } buffer[bufferLength++] = c; break; } p++; } if (name != null) { #if NETSTANDARD2_0 var value = new String(bufferOwner, 0, bufferLength); #else var value = new String(buffer.Slice(0, bufferLength)); #endif SetValue(typeDetail, model, WebUtility.UrlDecode(name), WebUtility.UrlDecode(value)); bufferLength = 0; } } } finally { BufferArrayPool <char> .Return(bufferOwner); } return(model); }
protected override TReturn CallInternal <TReturn>(bool isStream, Type interfaceType, string methodName, object[] arguments) { var data = new CQRSRequestData() { ProviderType = interfaceType.Name, ProviderMethod = methodName }; data.AddProviderArguments(arguments); switch (networkType) { case NetworkType.Internal: data.AddClaims(); break; case NetworkType.Api: break; default: throw new NotImplementedException(); } var stopwatch = Stopwatch.StartNew(); var client = new TcpClient(endpoint.AddressFamily); var bufferOwner = BufferArrayPool <byte> .Rent(TcpRawCommon.BufferLength); var buffer = bufferOwner.AsMemory(); Stream stream = null; Stream requestBodyStream = null; FinalBlockStream requestBodyCryptoStream = null; Stream responseBodyStream = null; try { client.Connect(endpoint.Address, endpoint.Port); stream = client.GetStream(); //Request Header var requestHeaderLength = TcpRawCommon.BufferHeader(buffer, data.ProviderType, contentType); #if NETSTANDARD2_0 stream.Write(bufferOwner, 0, requestHeaderLength); #else stream.Write(buffer.Span.Slice(0, requestHeaderLength)); #endif requestBodyStream = new TcpRawProtocolBodyStream(stream, null, true); if (encryptionKey != null) { requestBodyCryptoStream = SymmetricEncryptor.Encrypt(encryptionAlgorithm, encryptionKey, requestBodyStream, true, true); ContentTypeSerializer.Serialize(contentType, requestBodyCryptoStream, data); requestBodyCryptoStream.FlushFinalBlock(); requestBodyCryptoStream.Dispose(); requestBodyCryptoStream = null; } else { ContentTypeSerializer.Serialize(contentType, requestBodyStream, data); requestBodyStream.Flush(); } requestBodyStream.Dispose(); requestBodyStream = null; //Response Header var headerPosition = 0; var headerLength = 0; var requestHeaderEnd = false; while (!requestHeaderEnd) { if (headerLength == buffer.Length) { throw new Exception($"{nameof(TcpRawCQRSClient)} Header Too Long"); } #if NETSTANDARD2_0 var bytesRead = stream.Read(bufferOwner, headerPosition, buffer.Length - headerPosition); #else var bytesRead = stream.Read(buffer.Span.Slice(headerPosition, buffer.Length - headerPosition)); #endif if (bytesRead == 0) { throw new EndOfStreamException(); } headerLength += bytesRead; requestHeaderEnd = TcpRawCommon.ReadToHeaderEnd(buffer, ref headerPosition, headerLength); } var responseHeader = TcpRawCommon.ReadHeader(buffer, headerPosition, headerLength); responseBodyStream = new TcpRawProtocolBodyStream(stream, responseHeader.BodyStartBuffer, false); if (encryptionKey != null) { responseBodyStream = SymmetricEncryptor.Decrypt(encryptionAlgorithm, encryptionKey, responseBodyStream, false, false); } if (responseHeader.IsError) { var responseException = ContentTypeSerializer.DeserializeException(contentType, responseBodyStream); throw responseException; } stopwatch.Stop(); _ = Log.TraceAsync($"{nameof(TcpRawCQRSClient)} Query: {interfaceType.GetNiceName()}.{data.ProviderMethod} {stopwatch.ElapsedMilliseconds}"); if (isStream) { return((TReturn)(object)responseBodyStream); //TODO better way to convert type??? } else { var model = ContentTypeSerializer.Deserialize <TReturn>(contentType, responseBodyStream); responseBodyStream.Dispose(); client.Dispose(); return(model); } } catch { try { //crypto stream can error, we want to throw the actual error if (responseBodyStream != null) { responseBodyStream.Dispose(); } } catch { } if (requestBodyStream != null) { requestBodyStream.Dispose(); } if (requestBodyCryptoStream != null) { requestBodyCryptoStream.Dispose(); } if (stream != null) { stream.Dispose(); } client.Dispose(); throw; } finally { BufferArrayPool <byte> .Return(bufferOwner); } }
protected override async Task DispatchInternal(ICommand command, bool messageAwait) { var messageType = command.GetType(); var messageTypeName = messageType.GetNiceName(); var messageData = System.Text.Json.JsonSerializer.Serialize(command, messageType); var data = new CQRSRequestData() { MessageType = messageTypeName, MessageData = messageData, MessageAwait = messageAwait }; switch (networkType) { case NetworkType.Internal: data.AddClaims(); break; case NetworkType.Api: break; default: throw new NotImplementedException(); } var stopwatch = Stopwatch.StartNew(); var client = new TcpClient(endpoint.AddressFamily); client.NoDelay = true; var bufferOwner = BufferArrayPool <byte> .Rent(TcpRawCommon.BufferLength); var buffer = bufferOwner.AsMemory(); Stream stream = null; Stream requestBodyStream = null; FinalBlockStream requestBodyCryptoStream = null; Stream responseBodyStream = null; try { await client.ConnectAsync(endpoint.Address, endpoint.Port); stream = client.GetStream(); //Request Header var requestHeaderLength = TcpRawCommon.BufferHeader(buffer, data.MessageType, contentType); #if NETSTANDARD2_0 await stream.WriteAsync(bufferOwner, 0, requestHeaderLength); #else await stream.WriteAsync(buffer.Slice(0, requestHeaderLength)); #endif requestBodyStream = new TcpRawProtocolBodyStream(stream, null, true); if (encryptionKey != null) { requestBodyCryptoStream = SymmetricEncryptor.Encrypt(encryptionAlgorithm, encryptionKey, requestBodyStream, true, true); await ContentTypeSerializer.SerializeAsync(contentType, requestBodyCryptoStream, data); #if NET5_0_OR_GREATER await requestBodyCryptoStream.FlushFinalBlockAsync(); #else requestBodyCryptoStream.FlushFinalBlock(); #endif #if NETSTANDARD2_0 requestBodyCryptoStream.Dispose(); #else await requestBodyCryptoStream.DisposeAsync(); #endif requestBodyCryptoStream = null; } else { await ContentTypeSerializer.SerializeAsync(contentType, requestBodyStream, data); await requestBodyStream.FlushAsync(); } #if NETSTANDARD2_0 requestBodyStream.Dispose(); #else await requestBodyStream.DisposeAsync(); #endif requestBodyStream = null; //Response Header var headerPosition = 0; var headerLength = 0; var requestHeaderEnd = false; while (!requestHeaderEnd) { if (headerLength == buffer.Length) { throw new Exception($"{nameof(TcpRawCQRSClient)} Header Too Long"); } #if NETSTANDARD2_0 var bytesRead = await stream.ReadAsync(bufferOwner, headerPosition, buffer.Length - headerPosition); #else var bytesRead = await stream.ReadAsync(buffer.Slice(headerPosition, buffer.Length - headerPosition)); #endif if (bytesRead == 0) { throw new EndOfStreamException(); } headerLength += bytesRead; requestHeaderEnd = TcpRawCommon.ReadToHeaderEnd(buffer, ref headerPosition, headerLength); } var responseHeader = TcpRawCommon.ReadHeader(buffer, headerPosition, headerLength); //Response Body responseBodyStream = new TcpRawProtocolBodyStream(stream, responseHeader.BodyStartBuffer, false); if (responseHeader.IsError) { if (encryptionKey != null) { responseBodyStream = SymmetricEncryptor.Decrypt(encryptionAlgorithm, encryptionKey, responseBodyStream, false, false); } var responseException = await ContentTypeSerializer.DeserializeExceptionAsync(contentType, responseBodyStream); throw responseException; } if (responseBodyStream != null) { #if NETSTANDARD2_0 responseBodyStream.Dispose(); #else await responseBodyStream.DisposeAsync(); #endif } client.Dispose(); stopwatch.Stop(); _ = Log.TraceAsync($"{nameof(TcpRawCQRSClient)}Sent: {messageTypeName} {stopwatch.ElapsedMilliseconds}"); } catch { if (responseBodyStream != null) { #if NETSTANDARD2_0 responseBodyStream.Dispose(); #else await responseBodyStream.DisposeAsync(); #endif } if (requestBodyStream != null) { #if NETSTANDARD2_0 requestBodyStream.Dispose(); #else await requestBodyStream.DisposeAsync(); #endif } if (stream != null) { #if NETSTANDARD2_0 stream.Dispose(); #else await stream.DisposeAsync(); #endif } client.Dispose(); throw; } finally { BufferArrayPool <byte> .Return(bufferOwner); } }
protected override TReturn CallInternal <TReturn>(bool isStream, Type interfaceType, string methodName, object[] arguments) { var data = new CQRSRequestData() { ProviderType = interfaceType.Name, ProviderMethod = methodName }; data.AddProviderArguments(arguments); HttpAuthHeaders authHeaders = null; switch (networkType) { case NetworkType.Internal: data.AddClaims(); break; case NetworkType.Api: if (apiAuthorizer != null) { authHeaders = apiAuthorizer.BuildAuthHeaders(); } break; default: throw new NotImplementedException(); } var stopwatch = Stopwatch.StartNew(); var client = new TcpClient(endpoint.AddressFamily); client.NoDelay = true; var bufferOwner = BufferArrayPool <byte> .Rent(HttpCommon.BufferLength); var buffer = bufferOwner.AsMemory(); Stream stream = null; Stream requestBodyStream = null; Stream responseBodyStream = null; try { client.Connect(endpoint.Address, endpoint.Port); stream = client.GetStream(); //Request Header var requestHeaderLength = HttpCommon.BufferHeader(buffer, data.ProviderType, contentType, serviceUrl, authHeaders); #if NETSTANDARD2_0 stream.Write(bufferOwner, 0, requestHeaderLength); #else stream.Write(buffer.Span.Slice(0, requestHeaderLength)); #endif requestBodyStream = new HttpProtocolBodyStream(null, stream, null, true); ContentTypeSerializer.Serialize(contentType, requestBodyStream, data); requestBodyStream.Flush(); requestBodyStream.Dispose(); requestBodyStream = null; //Response Header var headerPosition = 0; var headerLength = 0; var headerEnd = false; while (!headerEnd) { if (headerLength == buffer.Length) { throw new Exception($"{nameof(HttpCQRSClient)} Header Too Long"); } #if NETSTANDARD2_0 var bytesRead = stream.Read(bufferOwner, headerPosition, buffer.Length - headerPosition); #else var bytesRead = stream.Read(buffer.Span.Slice(headerPosition, buffer.Length - headerPosition)); #endif if (bytesRead == 0) { throw new EndOfStreamException(); } headerLength += bytesRead; headerEnd = HttpCommon.ReadToHeaderEnd(buffer, ref headerPosition, headerLength); } var responseHeader = HttpCommon.ReadHeader(buffer, headerPosition, headerLength); //Response Body responseBodyStream = new HttpProtocolBodyStream(null, stream, responseHeader.BodyStartBuffer, false); if (responseHeader.IsError) { var responseException = ContentTypeSerializer.DeserializeException(contentType, responseBodyStream); throw responseException; } stopwatch.Stop(); _ = Log.TraceAsync($"{nameof(HttpCQRSClient)} Query: {interfaceType.GetNiceName()}.{data.ProviderMethod} {stopwatch.ElapsedMilliseconds}"); if (isStream) { return((TReturn)(object)responseBodyStream); } else { var model = ContentTypeSerializer.Deserialize <TReturn>(contentType, responseBodyStream); responseBodyStream.Dispose(); client.Dispose(); return(model); } } catch { if (responseBodyStream != null) { responseBodyStream.Dispose(); } if (requestBodyStream != null) { requestBodyStream.Dispose(); } if (stream != null) { stream.Dispose(); } client.Dispose(); throw; } finally { BufferArrayPool <byte> .Return(bufferOwner); } }
public static HttpRequestHeader ReadHeader(ReadOnlyMemory <byte> buffer, int position, int length) { #if NETSTANDARD2_0 var chars = encoding.GetChars(buffer.Span.Slice(0, position).ToArray()); var charsLength = chars.Length; #else var chars = BufferArrayPool <char> .Rent(encoding.GetMaxCharCount(position)); try { var charsLength = encoding.GetChars(buffer.Span.Slice(0, position), chars.AsSpan()); #endif (var declarations, var headers) = ParseHeaders(chars.AsSpan().Slice(0, charsLength)); if (declarations.Count == 0 || headers.Count == 0) { throw new Exception("Invalid Header"); } var headerInfo = new HttpRequestHeader() { Declarations = declarations, Headers = headers }; headerInfo.IsError = declarations[0].StartsWith(serverErrorResponse); if (headers.TryGetValue(contentTypeHeader, out IList <string> contentTypeHeaderValue)) { if (String.Equals(contentTypeHeaderValue[0], contentTypeBytes, StringComparison.InvariantCultureIgnoreCase)) { headerInfo.ContentType = ContentType.Bytes; } else if (String.Equals(contentTypeHeaderValue[0], contentTypeJson, StringComparison.InvariantCultureIgnoreCase)) { headerInfo.ContentType = ContentType.Json; } else if (String.Equals(contentTypeHeaderValue[0], contentTypeJsonNameless, StringComparison.InvariantCultureIgnoreCase)) { headerInfo.ContentType = ContentType.JsonNameless; } else { throw new Exception("Invalid Header"); } } if (headers.TryGetValue(contentLengthHeader, out IList <string> contentLengthHeaderValue)) { if (int.TryParse(contentLengthHeaderValue[0], out int contentLengthHeaderValueParsed)) { headerInfo.ContentLength = contentLengthHeaderValueParsed; } } if (headers.TryGetValue(transferEncodingHeader, out IList <string> transferEncodingHeaderValue)) { if (transferEncodingHeaderValue[0] == transferEncodingChunked) { headerInfo.Chuncked = true; } } if (headers.TryGetValue(providerTypeHeader, out IList <string> providerTypeHeaderValue)) { headerInfo.ProviderType = providerTypeHeaderValue[0]; } if (headers.TryGetValue(originHeader, out IList <string> originHeaderValue)) { headerInfo.Origin = originHeaderValue[0]; } if (declarations.Count > 0 && declarations[0] == optionsHeader) { headerInfo.Preflight = true; } if (headers.TryGetValue(RelayServiceHeader, out IList <string> relayServiceHeaderValue)) { if (relayServiceHeaderValue[0] == RelayServiceAdd) { headerInfo.RelayServiceAddRemove = true; } else if (relayServiceHeaderValue[0] == RelayServiceRemove) { headerInfo.RelayServiceAddRemove = false; } } if (headers.TryGetValue(RelayKeyHeader, out IList <string> relayKeyHeaderValue)) { headerInfo.RelayKey = relayKeyHeaderValue[0]; } headerInfo.BodyStartBuffer = buffer.Slice(position, length - position); return(headerInfo); #if !NETSTANDARD2_0 } finally { BufferArrayPool <char> .Return(chars); } #endif }
protected override async void Handle(TcpClient client, CancellationToken cancellationToken) { TcpClient outgoingClient = null; CQRSProtocolType? protocolType = null; RelayConnectedService service = null; Stopwatch stopwatch = null; bool responseStarted = false; var bufferOwner = BufferArrayPool <byte> .Rent(bufferLength); var buffer = bufferOwner.AsMemory(); Stream incommingStream = null; Stream incommingBodyStream = null; Stream outgoingWritingBodyStream = null; Stream outgoingStream = null; Stream outgoingBodyStream = null; Stream incommingWritingBodyStream = null; try { incommingStream = client.GetStream(); var headerPosition = 0; var headerLength = 0; var headerEnd = false; while (headerLength < TcpCommon.MaxProtocolHeaderPrefixLength) { if (headerLength == buffer.Length) { throw new Exception($"{nameof(TcpRelay)} Header Too Long"); } headerLength += await incommingStream.ReadAsync(buffer.Slice(headerPosition, buffer.Length - headerPosition), cancellationToken); } protocolType = TcpCommon.ReadProtocol(buffer.Span); string providerType; switch (protocolType.Value) { case CQRSProtocolType.TcpRaw: { headerEnd = TcpRawCommon.ReadToHeaderEnd(buffer, ref headerPosition, headerLength); while (!headerEnd) { if (headerLength == buffer.Length) { throw new Exception($"{nameof(TcpRelay)} Header Too Long"); } headerLength += await incommingStream.ReadAsync(buffer.Slice(headerLength, buffer.Length - headerLength), cancellationToken); headerEnd = TcpRawCommon.ReadToHeaderEnd(buffer, ref headerPosition, headerLength); } var header = TcpRawCommon.ReadHeader(buffer, headerPosition, headerLength); providerType = header.ProviderType; incommingBodyStream = new TcpRawProtocolBodyStream(incommingStream, header.BodyStartBuffer, true); break; } case CQRSProtocolType.Http: { headerEnd = HttpCommon.ReadToHeaderEnd(buffer, ref headerPosition, headerLength); while (!headerEnd) { if (headerLength == buffer.Length) { throw new Exception($"{nameof(TcpRelay)} Header Too Long"); } headerLength += await incommingStream.ReadAsync(buffer.Slice(headerLength, buffer.Length - headerLength), cancellationToken); headerEnd = HttpCommon.ReadToHeaderEnd(buffer, ref headerPosition, headerLength); } var header = HttpCommon.ReadHeader(buffer, headerPosition, headerLength); providerType = header.ProviderType; incommingBodyStream = new HttpProtocolBodyStream(header.ContentLength, incommingStream, header.BodyStartBuffer, true); if (header.RelayServiceAddRemove.HasValue) { if (header.RelayKey != relayKey) { throw new SecurityException("Invalid Relay Key"); } var serviceInfo = await System.Text.Json.JsonSerializer.DeserializeAsync <ServiceInfo>(incommingBodyStream); await incommingBodyStream.DisposeAsync(); incommingBodyStream = null; if (header.RelayServiceAddRemove == true) { RelayConnectedServicesManager.AddOrUpdate(serviceInfo); } else { RelayConnectedServicesManager.Remove(serviceInfo.Url); } var requestHeaderLength = HttpCommon.BufferOkHeader(buffer); await incommingStream.WriteAsync(buffer.Slice(0, requestHeaderLength), cancellationToken); await incommingStream.FlushAsync(); await incommingStream.DisposeAsync(); incommingStream = null; client.Dispose(); return; } break; } default: throw new NotImplementedException(); } while (outgoingClient == null) { service = RelayConnectedServicesManager.GetBestService(providerType); if (service == null) { break; } try { _ = Log.TraceAsync($"Relaying {providerType} to {service.Url}"); var outgoingEndpoint = IPResolver.GetIPEndPoints(service.Url, 80).First(); if (outgoingEndpoint != null) { outgoingClient = new TcpClient(outgoingEndpoint.AddressFamily); outgoingClient.NoDelay = true; await outgoingClient.ConnectAsync(outgoingEndpoint.Address, outgoingEndpoint.Port); service.FlagConnectionSuccess(); } else { service.FlagConnectionFailed(); } } catch { service.FlagConnectionFailed(); } } if (outgoingClient == null) { _ = Log.TraceAsync($"Destination not found {providerType}"); switch (protocolType.Value) { case CQRSProtocolType.TcpRaw: { var requestHeaderLength = HttpCommon.BufferNotFoundHeader(buffer); await incommingStream.WriteAsync(buffer.Slice(0, requestHeaderLength)); return; } case CQRSProtocolType.Http: { var requestHeaderLength = TcpRawCommon.BufferErrorHeader(buffer, null, default); await incommingStream.WriteAsync(buffer.Slice(0, requestHeaderLength)); return; } default: throw new NotImplementedException(); } } outgoingStream = outgoingClient.GetStream(); stopwatch = service.StartRequestRunning(); responseStarted = true; await outgoingStream.WriteAsync(buffer.Slice(0, headerPosition), cancellationToken); switch (protocolType.Value) { case CQRSProtocolType.TcpRaw: { outgoingWritingBodyStream = new TcpRawProtocolBodyStream(outgoingStream, null, true); await incommingBodyStream.CopyToAsync(outgoingWritingBodyStream, cancellationToken); await outgoingWritingBodyStream.FlushAsync(); break; } case CQRSProtocolType.Http: { outgoingWritingBodyStream = new HttpProtocolBodyStream(null, outgoingStream, null, true); await incommingBodyStream.CopyToAsync(outgoingWritingBodyStream, cancellationToken); await outgoingWritingBodyStream.FlushAsync(); break; } default: throw new NotImplementedException(); } await incommingBodyStream.DisposeAsync(); incommingBodyStream = null; await outgoingWritingBodyStream.DisposeAsync(); outgoingWritingBodyStream = null; //Response //----------------------------------------------------------------------------------------------------------------------- headerPosition = 0; headerLength = 0; headerEnd = false; switch (protocolType.Value) { case CQRSProtocolType.TcpRaw: { while (!headerEnd) { if (headerLength == buffer.Length) { throw new Exception($"{nameof(TcpRelay)} Header Too Long"); } headerLength += await outgoingStream.ReadAsync(buffer.Slice(headerLength, buffer.Length - headerLength)); headerEnd = TcpRawCommon.ReadToHeaderEnd(buffer, ref headerPosition, headerLength); } outgoingBodyStream = new TcpRawProtocolBodyStream(outgoingStream, buffer.Slice(headerPosition, headerLength - headerPosition), false); break; } case CQRSProtocolType.Http: { while (!headerEnd) { if (headerLength == buffer.Length) { throw new Exception($"{nameof(TcpRelay)} Header Too Long"); } headerLength += await outgoingStream.ReadAsync(buffer.Slice(headerLength, buffer.Length - headerLength)); headerEnd = HttpCommon.ReadToHeaderEnd(buffer, ref headerPosition, headerLength); } var header = HttpCommon.ReadHeader(buffer, headerPosition, headerLength); outgoingBodyStream = new HttpProtocolBodyStream(header.ContentLength, outgoingStream, header.BodyStartBuffer, false); break; } } await incommingStream.WriteAsync(buffer.Slice(0, headerPosition), cancellationToken); switch (protocolType.Value) { case CQRSProtocolType.TcpRaw: { incommingWritingBodyStream = new TcpRawProtocolBodyStream(incommingStream, null, false); await outgoingBodyStream.CopyToAsync(incommingWritingBodyStream, cancellationToken); await incommingWritingBodyStream.FlushAsync(); break; } case CQRSProtocolType.Http: { incommingWritingBodyStream = new HttpProtocolBodyStream(null, incommingStream, null, false); await outgoingBodyStream.CopyToAsync(incommingWritingBodyStream, cancellationToken); await incommingWritingBodyStream.FlushAsync(); break; } default: throw new NotImplementedException(); } await outgoingBodyStream.DisposeAsync(); outgoingBodyStream = null; await incommingWritingBodyStream.DisposeAsync(); incommingWritingBodyStream = null; outgoingClient.Dispose(); client.Dispose(); } catch (Exception ex) { if (ex is IOException ioException) { if (ioException.InnerException != null && ioException.InnerException is SocketException socketException) { if (socketException.SocketErrorCode == SocketError.ConnectionAborted) { return; } } } _ = Log.ErrorAsync(null, ex); if (!responseStarted && incommingStream != null && protocolType.HasValue) { try { switch (protocolType.Value) { case CQRSProtocolType.TcpRaw: { var requestHeaderLength = HttpCommon.BufferErrorHeader(buffer, null); await incommingStream.WriteAsync(buffer.Slice(0, requestHeaderLength), cancellationToken); break; } case CQRSProtocolType.Http: { var requestHeaderLength = TcpRawCommon.BufferErrorHeader(buffer, null, default); await incommingStream.WriteAsync(buffer.Slice(0, requestHeaderLength), cancellationToken); break; } default: throw new NotImplementedException(); } } catch (Exception ex2) { _ = Log.ErrorAsync(null, ex2); } } if (outgoingWritingBodyStream != null) { await outgoingWritingBodyStream.DisposeAsync(); } if (outgoingBodyStream != null) { await outgoingBodyStream.DisposeAsync(); } if (outgoingStream != null) { await outgoingStream.DisposeAsync(); } if (incommingWritingBodyStream != null) { await incommingWritingBodyStream.DisposeAsync(); } if (incommingBodyStream != null) { await incommingBodyStream.DisposeAsync(); } if (incommingStream != null) { await incommingStream.DisposeAsync(); } if (outgoingClient != null) { outgoingClient.Dispose(); } client.Dispose(); } finally { BufferArrayPool <byte> .Return(bufferOwner); if (service != null && stopwatch != null) { service.EndRequestRunning(stopwatch); } } }
protected override async void Handle(TcpClient client, CancellationToken cancellationToken) { HttpRequestHeader requestHeader = null; bool responseStarted = false; var bufferOwner = BufferArrayPool <byte> .Rent(HttpCommon.BufferLength); var buffer = bufferOwner.AsMemory(); Stream stream = null; Stream requestBodyStream = null; Stream responseBodyStream = null; try { stream = client.GetStream(); //Read Request Header //------------------------------------------------------------------------------------------------------------ var headerPosition = 0; var headerLength = 0; var headerEnd = false; while (!headerEnd) { if (headerLength == buffer.Length) { throw new Exception($"{nameof(HttpCQRSServer)} Header Too Long"); } #if NETSTANDARD2_0 var bytesRead = await stream.ReadAsync(bufferOwner, headerLength, buffer.Length - headerLength, cancellationToken); #else var bytesRead = await stream.ReadAsync(buffer.Slice(headerLength, buffer.Length - headerLength), cancellationToken); #endif if (bytesRead == 0) { throw new EndOfStreamException(); } headerLength += bytesRead; headerEnd = HttpCommon.ReadToHeaderEnd(buffer, ref headerPosition, headerLength); } requestHeader = HttpCommon.ReadHeader(buffer, headerPosition, headerLength); if (contentType.HasValue && requestHeader.ContentType.HasValue && requestHeader.ContentType != contentType) { _ = Log.ErrorAsync($"{nameof(HttpCQRSServer)} Received Invalid Content Type {requestHeader.ContentType}"); throw new Exception("Invalid Content Type"); } if (requestHeader.Preflight) { _ = Log.TraceAsync($"{nameof(HttpCQRSServer)} Received Preflight {client.Client.RemoteEndPoint}"); var preflightLength = HttpCommon.BufferPreflight(buffer, requestHeader.Origin); #if NETSTANDARD2_0 await stream.WriteAsync(bufferOwner, 0, preflightLength, cancellationToken); #else await stream.WriteAsync(buffer.Slice(0, preflightLength), cancellationToken); #endif await stream.FlushAsync(cancellationToken); return; } if (!requestHeader.ContentType.HasValue) { _ = Log.ErrorAsync($"{nameof(HttpCQRSServer)} Received Invalid Content Type {requestHeader.ContentType}"); throw new Exception("Invalid Content Type"); } _ = Log.TraceAsync($"{nameof(HttpCQRSServer)} Received On {client.Client.LocalEndPoint} From {client.Client.RemoteEndPoint} {requestHeader.ProviderType}"); if (allowOrigins != null && allowOrigins.Length > 0) { if (allowOrigins.Contains(requestHeader.Origin)) { throw new Exception($"Origin Not Allowed {requestHeader.Origin}"); } } //Read Request Body //------------------------------------------------------------------------------------------------------------ requestBodyStream = new HttpProtocolBodyStream(requestHeader.ContentLength, stream, requestHeader.BodyStartBuffer, true); var data = await ContentTypeSerializer.DeserializeAsync <CQRSRequestData>(requestHeader.ContentType.Value, requestBodyStream); if (data == null) { throw new Exception("Empty request body"); } #if NETSTANDARD2_0 requestBodyStream.Dispose(); #else await requestBodyStream.DisposeAsync(); #endif requestBodyStream = null; //Authroize //------------------------------------------------------------------------------------------------------------ switch (networkType) { case NetworkType.Internal: if (data.Claims != null) { var claimsIdentity = new ClaimsIdentity(data.Claims.Select(x => new Claim(x.Type, x.Value)), "CQRS"); Thread.CurrentPrincipal = new ClaimsPrincipal(claimsIdentity); } else { Thread.CurrentPrincipal = null; } break; case NetworkType.Api: if (this.apiAuthorizer != null) { this.apiAuthorizer.Authorize(requestHeader); } break; default: throw new NotImplementedException(); } //Process and Respond //---------------------------------------------------------------------------------------------------- if (!String.IsNullOrWhiteSpace(data.ProviderType)) { var providerType = Discovery.GetTypeFromName(data.ProviderType); var typeDetail = TypeAnalyzer.GetTypeDetail(providerType); if (!this.interfaceTypes.Contains(providerType)) { throw new Exception($"Unhandled Provider Type {providerType.FullName}"); } bool exposed = typeDetail.Attributes.Any(x => x is ServiceExposedAttribute attribute && (!attribute.NetworkType.HasValue || attribute.NetworkType == networkType)) && !typeDetail.Attributes.Any(x => x is ServiceBlockedAttribute attribute && (!attribute.NetworkType.HasValue || attribute.NetworkType == networkType)); if (!exposed) { throw new Exception($"Provider {data.MessageType} is not exposed to {networkType}"); } _ = Log.TraceAsync($"Received Call: {providerType.GetNiceName()}.{data.ProviderMethod}"); var result = await this.providerHandlerAsync.Invoke(providerType, data.ProviderMethod, data.ProviderArguments); //Response Header var responseHeaderLength = HttpCommon.BufferHeader(buffer, requestHeader.ProviderType, contentType, requestHeader.Origin, null); #if NETSTANDARD2_0 await stream.WriteAsync(bufferOwner, 0, responseHeaderLength); #else await stream.WriteAsync(buffer.Slice(0, responseHeaderLength)); #endif //Response Body responseBodyStream = new HttpProtocolBodyStream(null, stream, null, false); int bytesRead; if (result.Stream != null) { #if NETSTANDARD2_0 while ((bytesRead = await result.Stream.ReadAsync(bufferOwner, 0, bufferOwner.Length, cancellationToken)) > 0) { await responseBodyStream.WriteAsync(bufferOwner, 0, bytesRead, cancellationToken); } #else while ((bytesRead = await result.Stream.ReadAsync(buffer, cancellationToken)) > 0) { await responseBodyStream.WriteAsync(buffer.Slice(0, bytesRead), cancellationToken); } #endif await responseBodyStream.FlushAsync(); #if NETSTANDARD2_0 responseBodyStream.Dispose(); #else await responseBodyStream.DisposeAsync(); #endif client.Dispose(); return; } else { await ContentTypeSerializer.SerializeAsync(requestHeader.ContentType.Value, responseBodyStream, result.Model); await responseBodyStream.FlushAsync(); #if NETSTANDARD2_0 responseBodyStream.Dispose(); #else await responseBodyStream.DisposeAsync(); #endif client.Dispose(); return; } } else if (!String.IsNullOrWhiteSpace(data.MessageType)) { var commandType = Discovery.GetTypeFromName(data.MessageType); var typeDetail = TypeAnalyzer.GetTypeDetail(commandType); if (!typeDetail.Interfaces.Contains(typeof(ICommand))) { throw new Exception($"Type {data.MessageType} is not a command"); } bool exposed = typeDetail.Attributes.Any(x => x is ServiceExposedAttribute attribute && (!attribute.NetworkType.HasValue || attribute.NetworkType == networkType)) && !typeDetail.Attributes.Any(x => x is ServiceBlockedAttribute attribute && (!attribute.NetworkType.HasValue || attribute.NetworkType == networkType)); if (!exposed) { throw new Exception($"Command {data.MessageType} is not exposed to {networkType}"); } var command = (ICommand)System.Text.Json.JsonSerializer.Deserialize(data.MessageData, commandType); if (data.MessageAwait) { await handlerAwaitAsync(command); } else { await handlerAsync(command); } //Response Header var responseHeaderLength = HttpCommon.BufferHeader(buffer, requestHeader.ProviderType, contentType, requestHeader.Origin, null); #if NETSTANDARD2_0 await stream.WriteAsync(bufferOwner, 0, responseHeaderLength, cancellationToken); #else await stream.WriteAsync(buffer.Slice(0, responseHeaderLength), cancellationToken); #endif //Response Body Empty responseBodyStream = new HttpProtocolBodyStream(null, stream, null, false); await responseBodyStream.FlushAsync(cancellationToken); #if NETSTANDARD2_0 responseBodyStream.Dispose(); #else await responseBodyStream.DisposeAsync(); #endif client.Dispose(); return; } throw new Exception("Invalid Request"); } catch (Exception ex) { if (ex is IOException ioException) { if (ioException.InnerException != null && ioException.InnerException is SocketException socketException) { if (socketException.SocketErrorCode == SocketError.ConnectionAborted) { return; } } } _ = Log.ErrorAsync(null, ex); if (client.Connected && !responseStarted && requestHeader != null && requestHeader.ContentType.HasValue) { try { //Response Header var responseHeaderLength = HttpCommon.BufferErrorHeader(buffer, requestHeader.Origin); #if NETSTANDARD2_0 await stream.WriteAsync(bufferOwner, 0, responseHeaderLength, cancellationToken); #else await stream.WriteAsync(buffer.Slice(0, responseHeaderLength), cancellationToken); #endif //Response Body responseBodyStream = new HttpProtocolBodyStream(null, stream, null, false); await ContentTypeSerializer.SerializeExceptionAsync(requestHeader.ContentType.Value, responseBodyStream, ex); #if NETSTANDARD2_0 responseBodyStream.Dispose(); #else await responseBodyStream.DisposeAsync(); #endif client.Dispose(); } catch (Exception ex2) { if (responseBodyStream != null) { #if NETSTANDARD2_0 responseBodyStream.Dispose(); #else await responseBodyStream.DisposeAsync(); #endif } if (stream != null) { #if NETSTANDARD2_0 stream.Dispose(); #else await stream.DisposeAsync(); #endif } client.Dispose(); _ = Log.ErrorAsync($"{nameof(HttpCQRSServer)} Error {client.Client.RemoteEndPoint}", ex2); } return; } if (responseBodyStream != null) { #if NETSTANDARD2_0 responseBodyStream.Dispose(); #else await responseBodyStream.DisposeAsync(); #endif } if (requestBodyStream != null) { #if NETSTANDARD2_0 requestBodyStream.Dispose(); #else await requestBodyStream.DisposeAsync(); #endif } if (stream != null) { #if NETSTANDARD2_0 stream.Dispose(); #else await stream.DisposeAsync(); #endif } client.Dispose(); } finally { BufferArrayPool <byte> .Return(bufferOwner); } }
public static unsafe TcpRequestHeader ReadHeader(ReadOnlyMemory <byte> buffer, int position, int length) { #if NETSTANDARD2_0 var chars = encoding.GetChars(buffer.Span.Slice(0, position).ToArray()); var charsLength = chars.Length; #else var chars = BufferArrayPool <char> .Rent(encoding.GetMaxCharCount(position)); try { var charsLength = encoding.GetChars(buffer.Span.Slice(0, position), chars.AsSpan()); #endif string prefix = null; string providerType = null; ContentType?contentType = null; int propertyIndex = 0; int startIndex = 0; int indexLength = 0; fixed(char *pChars = chars) { for (var index = 0; index < charsLength; index++) { var c = pChars[index]; switch (c) { case headerSeperator: case headerEnder: switch (propertyIndex) { case 0: { prefix = new String(pChars, startIndex, indexLength); startIndex = index + 1; indexLength = 0; } break; case 1: { providerType = new String(pChars, startIndex, indexLength); startIndex = index + 1; indexLength = 0; } break; case 2: { var contentTypeString = new String(pChars, startIndex, indexLength); if (Int32.TryParse(contentTypeString, out int contentTypeValue)) { contentType = (ContentType)contentTypeValue; } startIndex = index + 1; indexLength = 0; } break; } propertyIndex++; break; default: indexLength++; break; } } } if (propertyIndex != 3) { throw new Exception("Invalid Header"); } var isError = prefix == protocolErrorPrefix; if (providerType == nullProviderType) { providerType = null; } return(new TcpRequestHeader() { BodyStartBuffer = buffer.Slice(position, length - position), IsError = isError, ContentType = contentType.Value, ProviderType = providerType }); #if !NETSTANDARD2_0 } finally { BufferArrayPool <char> .Return(chars); } #endif }