From db034a5a97dcdfb967223382e5b6ef63d9f841e1 Mon Sep 17 00:00:00 2001 From: "Haga R." Date: Sat, 1 Feb 2025 14:07:22 +0100 Subject: [PATCH 1/9] Move, unit test debbuuging not working with Rider --- .../Core/ConnectionErrorHandler.cs | 15 +++-- src/Fluxzy.Core/Core/ProxyOrchestrator.cs | 65 ++++++++++--------- src/Fluxzy.Core/Core/ProxyRuntimeSetting.cs | 46 ++++++++----- .../Cli/WithRuleBadFilterFilter.cs | 31 +++++++++ 4 files changed, 102 insertions(+), 55 deletions(-) create mode 100644 test/Fluxzy.Tests/Cli/WithRuleBadFilterFilter.cs diff --git a/src/Fluxzy.Core/Core/ConnectionErrorHandler.cs b/src/Fluxzy.Core/Core/ConnectionErrorHandler.cs index f10faba9e..a9c0c58b8 100644 --- a/src/Fluxzy.Core/Core/ConnectionErrorHandler.cs +++ b/src/Fluxzy.Core/Core/ConnectionErrorHandler.cs @@ -9,11 +9,14 @@ using System.Text.Json; using Fluxzy.Clients; using Fluxzy.Clients.H2; +using Fluxzy.Rules; namespace Fluxzy.Core { internal static class ConnectionErrorHandler { + private static readonly JsonSerializerOptions PrettyJsonOptions = new JsonSerializerOptions { WriteIndented = true }; + public static bool RequalifyOnResponseSendError( Exception ex, Exchange exchange, ITimingProvider timingProvider) @@ -82,6 +85,10 @@ public static bool RequalifyOnResponseSendError( if (ex.TryGetException(out var clientErrorException)) { exchange.ClientErrors.Add(clientErrorException.ClientError); } + + if (ex.TryGetException(out var ruleExecutionFailureException)) { + exchange.ClientErrors.Add(new ClientError(999, ruleExecutionFailureException.Message)); + } if (!exchange.ClientErrors.Any()) { exchange.ClientErrors.Add(new ClientError(0, "A generic error has occured") { @@ -93,6 +100,7 @@ public static bool RequalifyOnResponseSendError( ex is IOException || ex is H2Exception || ex is ClientErrorException || + ex is RuleExecutionFailureException || ex is AuthenticationException) { if (DebugContext.EnableDumpStackTraceOn502) { var message = "Fluxzy close connection due to server connection errors.\r\n\r\n"; @@ -107,11 +115,7 @@ ex is ClientErrorException || if (DebugContext.EnableDumpStackTraceOn502) { exchange.Metrics.ErrorInstant = DateTime.Now; - - message += "\r\n" + "\r\n" + JsonSerializer.Serialize(exchange.Metrics, - new JsonSerializerOptions { - WriteIndented = true - }); + message += "\r\n" + "\r\n" + JsonSerializer.Serialize(exchange.Metrics,PrettyJsonOptions); } var messageBinary = Encoding.UTF8.GetBytes(message); @@ -156,5 +160,6 @@ ex is ClientErrorException || return false; } + } } diff --git a/src/Fluxzy.Core/Core/ProxyOrchestrator.cs b/src/Fluxzy.Core/Core/ProxyOrchestrator.cs index 8252d7bbc..aa65094d2 100644 --- a/src/Fluxzy.Core/Core/ProxyOrchestrator.cs +++ b/src/Fluxzy.Core/Core/ProxyOrchestrator.cs @@ -43,6 +43,8 @@ public void Dispose() public async ValueTask Operate(TcpClient client, RsBuffer buffer, bool closeImmediately, CancellationToken token) { + Exchange? exchange = null; + try { if (D.EnableTracing) @@ -87,7 +89,7 @@ public async ValueTask Operate(TcpClient client, RsBuffer buffer, bool closeImme if (exchangeSourceInitResult == null) return; - var exchange = + exchange = exchangeSourceInitResult.ProvisionalExchange; var endPoint = (IPEndPoint) client.Client.RemoteEndPoint!; @@ -115,42 +117,42 @@ public async ValueTask Operate(TcpClient client, RsBuffer buffer, bool closeImme shouldClose = exchange.ShouldClose() || closeImmediately; - if (_proxyRuntimeSetting.UserAgentProvider != null) { - var userAgentValue = exchange.GetRequestHeaderValue("User-Agent"); - - // Solve user agent - - exchange.Agent = Agent.Create(userAgentValue ?? string.Empty, - ((IPEndPoint) client.Client.LocalEndPoint!).Address, - _proxyRuntimeSetting.UserAgentProvider); - } + IHttpConnectionPool connectionPool; + Stream? originalRequestBodyStream = null; + Stream? originalResponseBodyStream = null; - exchange.Step = ExchangeStep.Request; + try { + if (_proxyRuntimeSetting.UserAgentProvider != null) { + var userAgentValue = exchange.GetRequestHeaderValue("User-Agent"); - await _proxyRuntimeSetting.EnforceRules(exchange.Context, - FilterScope.RequestHeaderReceivedFromClient, - exchange.Connection, exchange).ConfigureAwait(false); + // Solve user agent - if (exchange.Context.Abort) { - return; - } + exchange.Agent = Agent.Create(userAgentValue ?? string.Empty, + ((IPEndPoint) client.Client.LocalEndPoint!).Address, + _proxyRuntimeSetting.UserAgentProvider); + } - if (exchange.Context.BreakPointContext != null) { - await exchange.Context.BreakPointContext.ConnectionSetupCompletion - .WaitForEdit().ConfigureAwait(false); - } + exchange.Step = ExchangeStep.Request; + + await _proxyRuntimeSetting.EnforceRules(exchange.Context, + FilterScope.RequestHeaderReceivedFromClient, + exchange.Connection, exchange).ConfigureAwait(false); - // Run header alteration + if (exchange.Context.Abort) { + return; + } - foreach (var requestHeaderAlteration in exchange.Context.RequestHeaderAlterations) { - requestHeaderAlteration.Apply(exchange.Request.Header); - } + if (exchange.Context.BreakPointContext != null) { + await exchange.Context.BreakPointContext.ConnectionSetupCompletion + .WaitForEdit().ConfigureAwait(false); + } - IHttpConnectionPool connectionPool; - Stream? originalRequestBodyStream = null; - Stream? originalResponseBodyStream = null; + // Run header alteration - try { + foreach (var requestHeaderAlteration in exchange.Context.RequestHeaderAlterations) { + requestHeaderAlteration.Apply(exchange.Request.Header); + } + if (exchange.Context.BreakPointContext != null) { await exchange.Context.BreakPointContext.RequestHeaderCompletion .WaitForEdit().ConfigureAwait(false); @@ -311,11 +313,9 @@ await exchange.Context.BreakPointContext.ResponseHeaderCompletion } - var responseHeaderLength = exchange.Response.Header!.WriteHttp11(false,buffer, true, true, shouldClose); + var responseHeaderLength = exchange.Response.Header!.WriteHttp11(false, buffer, true, true, shouldClose); if (_archiveWriter != null) { - // Update the state of the exchange - // _archiveWriter.Update(exchange, ArchiveUpdateType.AfterResponseHeader, CancellationToken.None ); @@ -495,6 +495,7 @@ await responseBodyStream.CopyDetailed( } // FATAL exception only happens here + throw; } } diff --git a/src/Fluxzy.Core/Core/ProxyRuntimeSetting.cs b/src/Fluxzy.Core/Core/ProxyRuntimeSetting.cs index ab982b745..1e6afb50d 100644 --- a/src/Fluxzy.Core/Core/ProxyRuntimeSetting.cs +++ b/src/Fluxzy.Core/Core/ProxyRuntimeSetting.cs @@ -1,5 +1,6 @@ // Copyright 2021 - Haga Rakotoharivelo - https://github.com/haga-rak +using System; using System.Collections.Generic; using System.Linq; using System.Net; @@ -130,25 +131,34 @@ public async ValueTask EnforceRules( ExchangeContext context, FilterScope filterScope, Connection? connection = null, Exchange? exchange = null) { - foreach (var rule in _effectiveRules!.Where(a => - a.Action.ActionScope == filterScope - || a.Action.ActionScope == FilterScope.OutOfScope - || (a.Action.ActionScope == FilterScope.CopySibling - && a.Action is MultipleScopeAction multipleScopeAction - && multipleScopeAction.RunScope == filterScope - ) - )) { - await rule.Enforce( - context, exchange, connection, filterScope, - ExecutionContext?.BreakPointManager!).ConfigureAwait(false); + try { + foreach (var rule in _effectiveRules!.Where(a => + a.Action.ActionScope == filterScope + || a.Action.ActionScope == FilterScope.OutOfScope + || (a.Action.ActionScope == FilterScope.CopySibling + && a.Action is MultipleScopeAction multipleScopeAction + && multipleScopeAction.RunScope == filterScope + ) + )) { + await rule.Enforce( + context, exchange, connection, filterScope, + ExecutionContext?.BreakPointManager!).ConfigureAwait(false); + } + + if (exchange?.RunInLiveEdit ?? false) { + var breakPointAction = new BreakPointAction(); + var rule = new Rule(breakPointAction, AnyFilter.Default); + + await rule.Enforce(context, exchange, connection, filterScope, + ExecutionContext?.BreakPointManager!).ConfigureAwait(false); + } } - - if (exchange?.RunInLiveEdit ?? false) { - var breakPointAction = new BreakPointAction(); - var rule = new Rule(breakPointAction, AnyFilter.Default); - - await rule.Enforce(context, exchange, connection, filterScope, - ExecutionContext?.BreakPointManager!).ConfigureAwait(false); + catch (Exception e) { + if (e is RuleExecutionFailureException) { + throw; + } + + throw new RuleExecutionFailureException("Error while evaluating rules: " + e.Message, e); } return context; diff --git a/test/Fluxzy.Tests/Cli/WithRuleBadFilterFilter.cs b/test/Fluxzy.Tests/Cli/WithRuleBadFilterFilter.cs new file mode 100644 index 000000000..aab08d839 --- /dev/null +++ b/test/Fluxzy.Tests/Cli/WithRuleBadFilterFilter.cs @@ -0,0 +1,31 @@ +// Copyright 2021 - Haga Rakotoharivelo - https://github.com/haga-rak + +using System.Net.Http; +using System.Text; +using Fluxzy.Rules.Filters.RequestFilters; + +namespace Fluxzy.Tests.Cli +{ + public class WithRuleBadFilterFilter : WithRuleOptionGenericRequestFilters + { + protected override string YamlContent { get; } = $""" + rules: + - filter: + typeKind: {nameof(HostFilter)} + pattern: * + operation: Regex + """; + + protected override void ConfigurePass(HttpRequestMessage requestMessage) + { + requestMessage.Content = new StringContent("{}", Encoding.UTF8, "application/json"); + requestMessage.Method = HttpMethod.Post; + } + + protected override void ConfigureBlock(HttpRequestMessage requestMessage) + { + requestMessage.Content = new StringContent("sd{}", Encoding.UTF8, "text/plain"); + requestMessage.Method = HttpMethod.Post; + } + } +} From f4ffe3f10f8b0f8bb87abd4f1b70de42dd41d62f Mon Sep 17 00:00:00 2001 From: haga-rak Date: Sat, 1 Feb 2025 23:49:55 +0100 Subject: [PATCH 2/9] Handle rule exception message --- .../Core/ConnectionErrorHandler.cs | 64 ++++- .../Core/ConnectionErrorPageHelper.cs | 24 +- src/Fluxzy.Core/Core/ProxyOrchestrator.cs | 240 +++++++++++------- .../RequestFilters/RequestHeaderFilter.cs | 2 +- .../Cases/BadRuleHandlingTests.cs | 35 +++ .../Cases/Expect100ContinueTests.cs | 1 + .../Cli/WithRuleBadFilterFilter.cs | 31 --- .../UnitTests/Handlers/Http2ConcurrentCall.cs | 9 +- 8 files changed, 275 insertions(+), 131 deletions(-) create mode 100644 test/Fluxzy.Tests/Cases/BadRuleHandlingTests.cs delete mode 100644 test/Fluxzy.Tests/Cli/WithRuleBadFilterFilter.cs diff --git a/src/Fluxzy.Core/Core/ConnectionErrorHandler.cs b/src/Fluxzy.Core/Core/ConnectionErrorHandler.cs index a9c0c58b8..9b74b88b4 100644 --- a/src/Fluxzy.Core/Core/ConnectionErrorHandler.cs +++ b/src/Fluxzy.Core/Core/ConnectionErrorHandler.cs @@ -7,8 +7,10 @@ using System.Security.Authentication; using System.Text; using System.Text.Json; +using System.Threading.Tasks; using Fluxzy.Clients; using Fluxzy.Clients.H2; +using Fluxzy.Misc.ResizableBuffers; using Fluxzy.Rules; namespace Fluxzy.Core @@ -160,6 +162,66 @@ ex is RuleExecutionFailureException || return false; } - + + public static async Task HandleGenericException(Exception ex, + ExchangeSourceInitResult? exchangeInitResult, + Exchange? exchange, + RsBuffer buffer, + ITimingProvider timingProvider) + { + if (exchange?.Connection == null || exchangeInitResult?.WriteStream == null) + return false; + + var instant = timingProvider.Instant(); + + var message = "An unknown error has occured."; + + + if (ex is RuleExecutionFailureException ruleException) { + message = + "A rule execution failure has occured.\r\n\r\n" + ruleException.Message; + } + + if (DebugContext.EnableDumpStackTraceOn502) + { + message += $"\r\n" + + $"Stacktrace\r\n{ex}"; + } + + var (header, body) = ConnectionErrorPageHelper.GetSimplePlainTextResponse( + exchange.Authority, + message); + + + exchange.Response.Header = new ResponseHeader( + header.AsMemory(), + exchange.Authority.Secure, true); + + exchange.Response.Body = new MemoryStream(body); + + + var responseHeaderLength = exchange.Response.Header! + .WriteHttp11(false, buffer, true, true, + true); + + await exchangeInitResult.WriteStream + .WriteAsync(buffer.Buffer, 0, responseHeaderLength) + .ConfigureAwait(false); + + await exchange.Response.Body.CopyToAsync(exchangeInitResult.WriteStream) + .ConfigureAwait(false); + + if (exchange.Metrics.ResponseBodyEnd == default) + { + exchange.Metrics.ResponseBodyEnd = instant; + } + + if (!exchange.ExchangeCompletionSource.Task.IsCompleted) + { + exchange.ExchangeCompletionSource.TrySetResult(true); + } + + return true; + } } } diff --git a/src/Fluxzy.Core/Core/ConnectionErrorPageHelper.cs b/src/Fluxzy.Core/Core/ConnectionErrorPageHelper.cs index 8fd988335..7f3c0510c 100644 --- a/src/Fluxzy.Core/Core/ConnectionErrorPageHelper.cs +++ b/src/Fluxzy.Core/Core/ConnectionErrorPageHelper.cs @@ -10,11 +10,19 @@ namespace Fluxzy.Core { internal static class ConnectionErrorPageHelper { - private static readonly string ErrorHeader = + private static readonly string ErrorHeaderHtml = "HTTP/1.1 {0}\r\n" + "x-fluxzy: Fluxzy error\r\n" + "Content-length: {1}\r\n" + - "Content-type: text/html\r\n" + + "Content-type: text/html; charset: utf-8\r\n" + + "Connection : close\r\n\r\n"; + + private static readonly string ErrorHeaderText = + "HTTP/1.1 {0}\r\n" + + "x-fluxzy: Fluxzy error\r\n" + + "x-fluxzy-error-type: Bad configuration\r\n" + + "Content-length: {1}\r\n" + + "Content-type: text/plain; charset: utf-8\r\n" + "Connection : close\r\n\r\n"; private static string BodyTemplate { get; } @@ -60,8 +68,18 @@ public static (string FlatHeader, byte[] BodyContent) GetPrettyErrorPage( bodyTemplate = bodyTemplate.Replace("@@error-message@@", errorMessage); var body = Encoding.UTF8.GetBytes(bodyTemplate); - var header = string.Format(ErrorHeader, headerStatus, body.Length); + var header = string.Format(ErrorHeaderHtml, headerStatus, body.Length); return (header, body); } + + public static (string FlatHeader, byte[] BodyContent) GetSimplePlainTextResponse( + Authority authority, string messageText) + { + var statusLine = FluxzySharedSetting.Use528 ? "528 Fluxzy error" : "502 Bad Gateway"; + var header = string.Format(ErrorHeaderText, statusLine, messageText.Length); + var body = Encoding.UTF8.GetBytes(messageText); + return (header, body); + + } } } diff --git a/src/Fluxzy.Core/Core/ProxyOrchestrator.cs b/src/Fluxzy.Core/Core/ProxyOrchestrator.cs index aa65094d2..4effffac7 100644 --- a/src/Fluxzy.Core/Core/ProxyOrchestrator.cs +++ b/src/Fluxzy.Core/Core/ProxyOrchestrator.cs @@ -44,8 +44,10 @@ public void Dispose() public async ValueTask Operate(TcpClient client, RsBuffer buffer, bool closeImmediately, CancellationToken token) { Exchange? exchange = null; - - try { + ExchangeSourceInitResult? exchangeSourceInitResult = null; + + try + { if (D.EnableTracing) { @@ -57,17 +59,19 @@ public async ValueTask Operate(TcpClient client, RsBuffer buffer, bool closeImme token = callerTokenSource.Token; - if (!token.IsCancellationRequested) { + if (!token.IsCancellationRequested) + { // READ initial state of connection, - ExchangeSourceInitResult? exchangeSourceInitResult = null; - try { + try + { exchangeSourceInitResult = await _exchangeSourceProvider.InitClientConnection( client.GetStream(), buffer, - _exchangeContextBuilder, (IPEndPoint) client.Client.LocalEndPoint!, (IPEndPoint) client.Client.RemoteEndPoint!, token) + _exchangeContextBuilder, (IPEndPoint)client.Client.LocalEndPoint!, (IPEndPoint)client.Client.RemoteEndPoint!, token) .ConfigureAwait(false); } - catch (Exception ex) { + catch (Exception ex) + { // Failure from the local connection if (D.EnableTracing) @@ -92,8 +96,8 @@ public async ValueTask Operate(TcpClient client, RsBuffer buffer, bool closeImme exchange = exchangeSourceInitResult.ProvisionalExchange; - var endPoint = (IPEndPoint) client.Client.RemoteEndPoint!; - var localEndPoint = (IPEndPoint) client.Client.LocalEndPoint!; + var endPoint = (IPEndPoint)client.Client.RemoteEndPoint!; + var localEndPoint = (IPEndPoint)client.Client.LocalEndPoint!; exchange.Metrics.DownStreamClientPort = endPoint.Port; exchange.Metrics.DownStreamClientAddress = endPoint.Address.ToString(); @@ -104,56 +108,65 @@ public async ValueTask Operate(TcpClient client, RsBuffer buffer, bool closeImme var shouldClose = false; - do { + do + { var processMessage = !exchange.Unprocessed; - if (processMessage) { + if (processMessage) + { // Check whether the local browser ask for a connection close - if (D.EnableTracing) { + if (D.EnableTracing) + { var message = $"[#{exchange.Id}] Processing {exchange.Request.Header.Authority}"; D.TraceInfo(message); } shouldClose = exchange.ShouldClose() || closeImmediately; - IHttpConnectionPool connectionPool; - Stream? originalRequestBodyStream = null; - Stream? originalResponseBodyStream = null; + if (_proxyRuntimeSetting.UserAgentProvider != null) + { + var userAgentValue = exchange.GetRequestHeaderValue("User-Agent"); - try { - if (_proxyRuntimeSetting.UserAgentProvider != null) { - var userAgentValue = exchange.GetRequestHeaderValue("User-Agent"); + // Solve user agent - // Solve user agent + exchange.Agent = Agent.Create(userAgentValue ?? string.Empty, + ((IPEndPoint)client.Client.LocalEndPoint!).Address, + _proxyRuntimeSetting.UserAgentProvider); + } - exchange.Agent = Agent.Create(userAgentValue ?? string.Empty, - ((IPEndPoint) client.Client.LocalEndPoint!).Address, - _proxyRuntimeSetting.UserAgentProvider); - } + exchange.Step = ExchangeStep.Request; - exchange.Step = ExchangeStep.Request; - - await _proxyRuntimeSetting.EnforceRules(exchange.Context, - FilterScope.RequestHeaderReceivedFromClient, - exchange.Connection, exchange).ConfigureAwait(false); + await _proxyRuntimeSetting.EnforceRules(exchange.Context, + FilterScope.RequestHeaderReceivedFromClient, + exchange.Connection, exchange).ConfigureAwait(false); - if (exchange.Context.Abort) { - return; - } + if (exchange.Context.Abort) + { + return; + } - if (exchange.Context.BreakPointContext != null) { - await exchange.Context.BreakPointContext.ConnectionSetupCompletion - .WaitForEdit().ConfigureAwait(false); - } + if (exchange.Context.BreakPointContext != null) + { + await exchange.Context.BreakPointContext.ConnectionSetupCompletion + .WaitForEdit().ConfigureAwait(false); + } - // Run header alteration + // Run header alteration - foreach (var requestHeaderAlteration in exchange.Context.RequestHeaderAlterations) { - requestHeaderAlteration.Apply(exchange.Request.Header); - } - - if (exchange.Context.BreakPointContext != null) { + foreach (var requestHeaderAlteration in exchange.Context.RequestHeaderAlterations) + { + requestHeaderAlteration.Apply(exchange.Request.Header); + } + + IHttpConnectionPool connectionPool; + Stream? originalRequestBodyStream = null; + Stream? originalResponseBodyStream = null; + + try + { + if (exchange.Context.BreakPointContext != null) + { await exchange.Context.BreakPointContext.RequestHeaderCompletion .WaitForEdit().ConfigureAwait(false); } @@ -164,7 +177,8 @@ await exchange.Context.BreakPointContext.RequestHeaderCompletion exchange.Context.HasRequestBody = hasRequestBody; - if (_archiveWriter != null) { + if (_archiveWriter != null) + { _archiveWriter.Update( exchange, ArchiveUpdateType.BeforeRequestHeader, @@ -173,9 +187,9 @@ await exchange.Context.BreakPointContext.RequestHeaderCompletion if (exchange.Context.HasRequestBodySubstitution) { - originalRequestBodyStream = hasRequestBody? exchange.Request.Body : Stream.Null; + originalRequestBodyStream = hasRequestBody ? exchange.Request.Body : Stream.Null; exchange.Request.Body = await - exchange.Context.GetSubstitutedRequestBody(exchange.Request.Body!, + exchange.Context.GetSubstitutedRequestBody(exchange.Request.Body!, exchange).ConfigureAwait(false); exchange.Request.Header.ForceTransferChunked(); @@ -191,7 +205,8 @@ await exchange.Context.BreakPointContext.RequestHeaderCompletion } } - while (true) { + while (true) + { // get a connection pool for the current exchange connectionPool = await _poolBuilder.GetPool(exchange, _proxyRuntimeSetting, token).ConfigureAwait(false); @@ -214,9 +229,11 @@ await exchange.Context.BreakPointContext.RequestHeaderCompletion D.TraceInfo(message); } } - catch (Exception ex) { + catch (Exception ex) + { - if (ex is ConnectionCloseException || ex is TlsFatalAlert) { + if (ex is ConnectionCloseException || ex is TlsFatalAlert) + { // This connection was "goawayed" while current exchange // tries to use it. @@ -229,7 +246,8 @@ await exchange.Context.BreakPointContext.RequestHeaderCompletion throw; } - finally { + finally + { // We close the request body dispatchstream await SafeCloseRequestBody(exchange, originalRequestBodyStream).ConfigureAwait(false); } @@ -237,7 +255,8 @@ await exchange.Context.BreakPointContext.RequestHeaderCompletion break; } } - catch (Exception exception) { + catch (Exception exception) + { // The caller cancelled the task await SafeCloseRequestBody(exchange, originalRequestBodyStream).ConfigureAwait(false); @@ -256,7 +275,8 @@ await exchange.Context.BreakPointContext.RequestHeaderCompletion // We do not need to read websocket response if (!exchange.Request.Header.IsWebSocketRequest && !exchange.Context.BlindMode - && exchange.Response.Header != null) { + && exchange.Response.Header != null) + { // Request processed by IHttpConnectionPool returns before complete response body // Apply response alteration @@ -266,7 +286,8 @@ await _proxyRuntimeSetting.EnforceRules(exchange.Context, // Setup break point for response - if (exchange.Context.BreakPointContext != null) { + if (exchange.Context.BreakPointContext != null) + { await exchange.Context.BreakPointContext.ResponseHeaderCompletion .WaitForEdit().ConfigureAwait(false); } @@ -301,27 +322,33 @@ await exchange.Context.BreakPointContext.ResponseHeaderCompletion exchange.Response.Header.ForceTransferChunked(); - foreach (var responseHeaderAlteration in exchange.Context.ResponseHeaderAlterations) { + foreach (var responseHeaderAlteration in exchange.Context.ResponseHeaderAlterations) + { responseHeaderAlteration.Apply(exchange.Response.Header); } // Writing the received header to downstream - if (DebugContext.InsertFluxzyMetricsOnResponseHeader) { + if (DebugContext.InsertFluxzyMetricsOnResponseHeader) + { exchange.Response.Header?.AddExtraHeaderFieldToLocalConnection( exchange.GetMetricsSummaryAsHeader()); } - + var responseHeaderLength = exchange.Response.Header!.WriteHttp11(false, buffer, true, true, shouldClose); - if (_archiveWriter != null) { + if (_archiveWriter != null) + { + // Update the state of the exchange + // _archiveWriter.Update(exchange, ArchiveUpdateType.AfterResponseHeader, CancellationToken.None ); if (responseBodyStream != null && - (!responseBodyStream.CanSeek || responseBodyStream.Length > 0)) { + (!responseBodyStream.CanSeek || responseBodyStream.Length > 0)) + { if (exchange.Context.HasResponseBodySubstitution) { @@ -354,9 +381,10 @@ await exchange.Context.BreakPointContext.ResponseHeaderCompletion }; exchange.Response.Body = dispatchStream; - responseBodyStream = dispatchStream; + responseBodyStream = dispatchStream; } - else { + else + { // No response body, we ensure the stream is done _archiveWriter.Update(exchange, @@ -367,13 +395,15 @@ await exchange.Context.BreakPointContext.ResponseHeaderCompletion } } - try { + try + { // Start sending response to browser await exchangeSourceInitResult.WriteStream.WriteAsync( new ReadOnlyMemory(buffer.Buffer, 0, responseHeaderLength), token).ConfigureAwait(false); } - catch (Exception ex) { + catch (Exception ex) + { await SafeCloseRequestBody(exchange, originalRequestBodyStream).ConfigureAwait(false); await SafeCloseResponseBody(exchange, originalResponseBodyStream).ConfigureAwait(false); @@ -386,16 +416,19 @@ await exchangeSourceInitResult.WriteStream.WriteAsync( } if (exchange.Response.Header.ContentLength != 0 && - responseBodyStream != null) { + responseBodyStream != null) + { var localConnectionWriteStream = exchangeSourceInitResult.WriteStream; - if (exchange.Response.Header.ChunkedBody && - exchange.Response.Header.HasResponseBody(exchange.Request.Header.Method.Span, out _)) { + if (exchange.Response.Header.ChunkedBody && + exchange.Response.Header.HasResponseBody(exchange.Request.Header.Method.Span, out _)) + { localConnectionWriteStream = new ChunkedTransferWriteStream(localConnectionWriteStream); } - try { + try + { await responseBodyStream.CopyDetailed( localConnectionWriteStream, buffer.Buffer, _ => { }, token).ConfigureAwait(false); @@ -403,14 +436,17 @@ await responseBodyStream.CopyDetailed( await exchangeSourceInitResult.WriteStream.FlushAsync(CancellationToken.None).ConfigureAwait(false); } - catch (Exception ex) { - if (ex is IOException || ex is OperationCanceledException) { + catch (Exception ex) + { + if (ex is IOException || ex is OperationCanceledException) + { // Local connection may close the underlying stream before // receiving the entire message. Particulary when waiting for the last 0\r\n\r\n on chunked stream. // In that case, we just leave // without any error - if (ex is IOException && ex.InnerException is SocketException sex) { + if (ex is IOException && ex.InnerException is SocketException sex) + { if (sex.SocketErrorCode == SocketError.ConnectionAborted) callerTokenSource.Cancel(); } @@ -420,13 +456,16 @@ await responseBodyStream.CopyDetailed( throw; } - finally { + finally + { await SafeCloseRequestBody(exchange, originalRequestBodyStream).ConfigureAwait(false); await SafeCloseResponseBody(exchange, originalResponseBodyStream).ConfigureAwait(false); } } - else { - if (responseBodyStream != null) { + else + { + if (responseBodyStream != null) + { await SafeCloseRequestBody(exchange, originalRequestBodyStream).ConfigureAwait(false); await SafeCloseResponseBody(exchange, originalResponseBodyStream).ConfigureAwait(false); } @@ -435,10 +474,12 @@ await responseBodyStream.CopyDetailed( // In case the down stream connection is persisted, // we wait for the current exchange to complete before reading further request - try { + try + { shouldClose = shouldClose || await exchange.Complete.ConfigureAwait(false); } - catch (ExchangeException) { + catch (ExchangeException) + { // Enhance your calm } } @@ -451,7 +492,8 @@ await responseBodyStream.CopyDetailed( if (shouldClose) break; - try { + try + { // Read the next HTTP message exchange = await _exchangeSourceProvider.ReadNextExchange( exchangeSourceInitResult.ReadStream, @@ -459,14 +501,16 @@ await responseBodyStream.CopyDetailed( buffer, _exchangeContextBuilder, token ).ConfigureAwait(false); - if (exchange != null) { - var ep2 = (IPEndPoint) client.Client.RemoteEndPoint!; + if (exchange != null) + { + var ep2 = (IPEndPoint)client.Client.RemoteEndPoint!; exchange.Metrics.DownStreamClientPort = ep2.Port; exchange.Metrics.DownStreamClientAddress = ep2.Address.ToString(); } } - catch (IOException ex) { + catch (IOException ex) + { // Downstream close the underlying connection if (D.EnableTracing) @@ -481,9 +525,11 @@ await responseBodyStream.CopyDetailed( while (exchange != null); } } - catch (Exception ex) { + catch (Exception ex) + { - if (ex is OperationCanceledException) { + if (ex is OperationCanceledException) + { if (D.EnableTracing) { @@ -494,55 +540,67 @@ await responseBodyStream.CopyDetailed( return; } - // FATAL exception only happens here + var handleResult = await + ConnectionErrorHandler.HandleGenericException(ex, exchangeSourceInitResult, + exchange, buffer, ITimingProvider.Default); + + if (!handleResult) + // + throw; - throw; } } private ValueTask SafeCloseRequestBody(Exchange exchange, Stream? substitutionStream) { - if (exchange.Request.Body != null) { - try { + if (exchange.Request.Body != null) + { + try + { // Clean the pipe var body = exchange.Request.Body; - exchange.Request.Body = null; + exchange.Request.Body = null; return body.DisposeAsync(); } - catch { + catch + { // ignore errors when closing pipe } } SafeCloseExtraStream(substitutionStream); - return default; + return default; } private ValueTask SafeCloseResponseBody(Exchange exchange, Stream? substitutionStream) { - if (exchange.Response.Body != null) { - try { + if (exchange.Response.Body != null) + { + try + { // Clean the pipe var body = exchange.Response.Body; exchange.Response.Body = null; return body.DisposeAsync(); } - catch { + catch + { // ignore errors when closing pipe } } SafeCloseExtraStream(substitutionStream); - return default; + return default; } private ValueTask SafeCloseExtraStream(params Stream?[] streams) { - foreach (var stream in streams) { + foreach (var stream in streams) + { if (stream == null) continue; @@ -559,4 +617,4 @@ private ValueTask SafeCloseExtraStream(params Stream?[] streams) return default; } } -} +} \ No newline at end of file diff --git a/src/Fluxzy.Core/Rules/Filters/RequestFilters/RequestHeaderFilter.cs b/src/Fluxzy.Core/Rules/Filters/RequestFilters/RequestHeaderFilter.cs index 5e30984f6..5d28918b8 100644 --- a/src/Fluxzy.Core/Rules/Filters/RequestFilters/RequestHeaderFilter.cs +++ b/src/Fluxzy.Core/Rules/Filters/RequestFilters/RequestHeaderFilter.cs @@ -68,4 +68,4 @@ public static IConfigureActionBuilder WhenRequestHeaderExists( return builder.When(new RequestHeaderFilter("", StringSelectorOperation.Contains, headerName)); } } -} +} diff --git a/test/Fluxzy.Tests/Cases/BadRuleHandlingTests.cs b/test/Fluxzy.Tests/Cases/BadRuleHandlingTests.cs new file mode 100644 index 000000000..757f4fe44 --- /dev/null +++ b/test/Fluxzy.Tests/Cases/BadRuleHandlingTests.cs @@ -0,0 +1,35 @@ +// Copyright 2021 - Haga Rakotoharivelo - https://github.com/haga-rak + +using System.Threading.Tasks; +using Fluxzy.Rules.Actions; +using Fluxzy.Rules.Filters; +using Fluxzy.Rules.Filters.RequestFilters; +using Fluxzy.Tests._Fixtures; +using Xunit; + +namespace Fluxzy.Tests.Cases +{ + public class BadRuleHandlingTests + { + [Fact] + public async Task HandleBadRuleException() + { + var setting = FluxzySetting.CreateLocalRandomPort(); + + setting.ConfigureRule().When( + new HostFilter("*", StringSelectorOperation.Regex)) + .Do(new AddResponseHeaderAction("yes", "no")); + + await using var proxy = new Proxy(setting); + + using var client = HttpClientUtility.CreateHttpClient(proxy.Run(), setting); + + var response = await client.GetAsync(TestConstants.Http2Host); + + var statusCode = response.StatusCode; + var responseBodyString = await response.Content.ReadAsStringAsync(); + + Assert.Equal(528, (int)statusCode); + } + } +} diff --git a/test/Fluxzy.Tests/Cases/Expect100ContinueTests.cs b/test/Fluxzy.Tests/Cases/Expect100ContinueTests.cs index c2e8d50b9..a57777790 100644 --- a/test/Fluxzy.Tests/Cases/Expect100ContinueTests.cs +++ b/test/Fluxzy.Tests/Cases/Expect100ContinueTests.cs @@ -1,5 +1,6 @@ // Copyright 2021 - Haga Rakotoharivelo - https://github.com/haga-rak +using System; using System.Net.Http; using System.Text; using System.Threading.Tasks; diff --git a/test/Fluxzy.Tests/Cli/WithRuleBadFilterFilter.cs b/test/Fluxzy.Tests/Cli/WithRuleBadFilterFilter.cs deleted file mode 100644 index aab08d839..000000000 --- a/test/Fluxzy.Tests/Cli/WithRuleBadFilterFilter.cs +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright 2021 - Haga Rakotoharivelo - https://github.com/haga-rak - -using System.Net.Http; -using System.Text; -using Fluxzy.Rules.Filters.RequestFilters; - -namespace Fluxzy.Tests.Cli -{ - public class WithRuleBadFilterFilter : WithRuleOptionGenericRequestFilters - { - protected override string YamlContent { get; } = $""" - rules: - - filter: - typeKind: {nameof(HostFilter)} - pattern: * - operation: Regex - """; - - protected override void ConfigurePass(HttpRequestMessage requestMessage) - { - requestMessage.Content = new StringContent("{}", Encoding.UTF8, "application/json"); - requestMessage.Method = HttpMethod.Post; - } - - protected override void ConfigureBlock(HttpRequestMessage requestMessage) - { - requestMessage.Content = new StringContent("sd{}", Encoding.UTF8, "text/plain"); - requestMessage.Method = HttpMethod.Post; - } - } -} diff --git a/test/Fluxzy.Tests/UnitTests/Handlers/Http2ConcurrentCall.cs b/test/Fluxzy.Tests/UnitTests/Handlers/Http2ConcurrentCall.cs index c08afecbc..251fa7ab2 100644 --- a/test/Fluxzy.Tests/UnitTests/Handlers/Http2ConcurrentCall.cs +++ b/test/Fluxzy.Tests/UnitTests/Handlers/Http2ConcurrentCall.cs @@ -47,7 +47,8 @@ private async Task CallSimple( await AssertionHelper.ValidateCheck(requestMessage, null, response, token); } - [Fact] + + [Fact(Timeout = 1000 * 60)] public async Task Post_Random_Data_And_Validate_Content() { using var handler = new FluxzyHttp2Handler(); @@ -95,7 +96,7 @@ public async Task Post_Multi_Header_Dynamic_Table_Evict_Simple() /// The goal of this test is to challenge the dynamic table content /// /// - [Theory] + [Theory(Timeout = 1000 * 60)] [InlineData(1024)] [InlineData(16394)] public async Task Post_Dynamic_Table_Evict_Simple_Large_Object(int bufferSize) @@ -128,7 +129,7 @@ public async Task Post_Dynamic_Table_Evict_Simple_Large_Object(int bufferSize) await Task.WhenAll(tasks); } - [Fact] + [Fact(Timeout = 1000 * 60)] public async Task Headers_Multiple_Reception() { using var handler = new FluxzyHttp2Handler(); @@ -189,4 +190,4 @@ private static async Task Receiving_Multiple_Repeating_Header_Value_Call() await Task.WhenAll(tasks); } } -} +} From 474b7289c95a518203bc7294a43d54b70f354c94 Mon Sep 17 00:00:00 2001 From: haga-rak Date: Sat, 1 Feb 2025 23:51:32 +0100 Subject: [PATCH 3/9] Add better timing metrics --- src/Fluxzy.Core/Core/ConnectionErrorHandler.cs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/Fluxzy.Core/Core/ConnectionErrorHandler.cs b/src/Fluxzy.Core/Core/ConnectionErrorHandler.cs index 9b74b88b4..ba7c5a84c 100644 --- a/src/Fluxzy.Core/Core/ConnectionErrorHandler.cs +++ b/src/Fluxzy.Core/Core/ConnectionErrorHandler.cs @@ -172,8 +172,6 @@ public static async Task HandleGenericException(Exception ex, if (exchange?.Connection == null || exchangeInitResult?.WriteStream == null) return false; - var instant = timingProvider.Instant(); - var message = "An unknown error has occured."; @@ -204,16 +202,21 @@ public static async Task HandleGenericException(Exception ex, .WriteHttp11(false, buffer, true, true, true); + exchange.Metrics.ResponseHeaderStart = timingProvider.Instant(); + await exchangeInitResult.WriteStream .WriteAsync(buffer.Buffer, 0, responseHeaderLength) .ConfigureAwait(false); + exchange.Metrics.ResponseHeaderEnd = timingProvider.Instant(); + exchange.Metrics.ResponseBodyStart = timingProvider.Instant(); + await exchange.Response.Body.CopyToAsync(exchangeInitResult.WriteStream) .ConfigureAwait(false); if (exchange.Metrics.ResponseBodyEnd == default) { - exchange.Metrics.ResponseBodyEnd = instant; + exchange.Metrics.ResponseBodyEnd = timingProvider.Instant(); } if (!exchange.ExchangeCompletionSource.Task.IsCompleted) From 3208d8e36a7d72510053baa256d89b49a4e8002e Mon Sep 17 00:00:00 2001 From: haga-rak Date: Sat, 1 Feb 2025 23:58:20 +0100 Subject: [PATCH 4/9] Add better assertion value --- src/Fluxzy.Core/Core/ConnectionErrorHandler.cs | 10 ++-------- src/Fluxzy.Core/Core/ConnectionErrorPageHelper.cs | 6 +++--- test/Fluxzy.Tests/Cases/BadRuleHandlingTests.cs | 10 +++++++--- 3 files changed, 12 insertions(+), 14 deletions(-) diff --git a/src/Fluxzy.Core/Core/ConnectionErrorHandler.cs b/src/Fluxzy.Core/Core/ConnectionErrorHandler.cs index ba7c5a84c..eda7bbaf8 100644 --- a/src/Fluxzy.Core/Core/ConnectionErrorHandler.cs +++ b/src/Fluxzy.Core/Core/ConnectionErrorHandler.cs @@ -129,9 +129,6 @@ ex is RuleExecutionFailureException || header.AsMemory(), exchange.Authority.Secure, true); - //if (DebugContext.EnableDumpStackTraceOn502) - // Console.WriteLine(message); - exchange.Response.Body = new MemoryStream(messageBinary); if (!exchange.ExchangeCompletionSource.Task.IsCompleted) { @@ -174,7 +171,6 @@ public static async Task HandleGenericException(Exception ex, var message = "An unknown error has occured."; - if (ex is RuleExecutionFailureException ruleException) { message = "A rule execution failure has occured.\r\n\r\n" + ruleException.Message; @@ -183,13 +179,12 @@ public static async Task HandleGenericException(Exception ex, if (DebugContext.EnableDumpStackTraceOn502) { message += $"\r\n" + - $"Stacktrace\r\n{ex}"; + $"Stacktrace:\r\n{ex}"; } var (header, body) = ConnectionErrorPageHelper.GetSimplePlainTextResponse( exchange.Authority, - message); - + message, ex.GetType().Name); exchange.Response.Header = new ResponseHeader( header.AsMemory(), @@ -197,7 +192,6 @@ public static async Task HandleGenericException(Exception ex, exchange.Response.Body = new MemoryStream(body); - var responseHeaderLength = exchange.Response.Header! .WriteHttp11(false, buffer, true, true, true); diff --git a/src/Fluxzy.Core/Core/ConnectionErrorPageHelper.cs b/src/Fluxzy.Core/Core/ConnectionErrorPageHelper.cs index 7f3c0510c..d588a21e4 100644 --- a/src/Fluxzy.Core/Core/ConnectionErrorPageHelper.cs +++ b/src/Fluxzy.Core/Core/ConnectionErrorPageHelper.cs @@ -20,7 +20,7 @@ internal static class ConnectionErrorPageHelper private static readonly string ErrorHeaderText = "HTTP/1.1 {0}\r\n" + "x-fluxzy: Fluxzy error\r\n" + - "x-fluxzy-error-type: Bad configuration\r\n" + + "x-fluxzy-error-type: {2}\r\n" + "Content-length: {1}\r\n" + "Content-type: text/plain; charset: utf-8\r\n" + "Connection : close\r\n\r\n"; @@ -73,10 +73,10 @@ public static (string FlatHeader, byte[] BodyContent) GetPrettyErrorPage( } public static (string FlatHeader, byte[] BodyContent) GetSimplePlainTextResponse( - Authority authority, string messageText) + Authority authority, string messageText, string errorTypeText) { var statusLine = FluxzySharedSetting.Use528 ? "528 Fluxzy error" : "502 Bad Gateway"; - var header = string.Format(ErrorHeaderText, statusLine, messageText.Length); + var header = string.Format(ErrorHeaderText, statusLine, messageText.Length, errorTypeText); var body = Encoding.UTF8.GetBytes(messageText); return (header, body); diff --git a/test/Fluxzy.Tests/Cases/BadRuleHandlingTests.cs b/test/Fluxzy.Tests/Cases/BadRuleHandlingTests.cs index 757f4fe44..684d43be7 100644 --- a/test/Fluxzy.Tests/Cases/BadRuleHandlingTests.cs +++ b/test/Fluxzy.Tests/Cases/BadRuleHandlingTests.cs @@ -1,6 +1,8 @@ // Copyright 2021 - Haga Rakotoharivelo - https://github.com/haga-rak +using System.Linq; using System.Threading.Tasks; +using Fluxzy.Rules; using Fluxzy.Rules.Actions; using Fluxzy.Rules.Filters; using Fluxzy.Rules.Filters.RequestFilters; @@ -26,10 +28,12 @@ public async Task HandleBadRuleException() var response = await client.GetAsync(TestConstants.Http2Host); - var statusCode = response.StatusCode; - var responseBodyString = await response.Content.ReadAsStringAsync(); + _ = await response.Content.ReadAsStringAsync(); + var hasHeader = response.Headers.TryGetValues("x-fluxzy-error-type", out var values); - Assert.Equal(528, (int)statusCode); + Assert.True(hasHeader); + Assert.NotNull(values); + Assert.Equal(nameof(RuleExecutionFailureException), values.First()); } } } From 33d4829064ba9563c8dd7afa35df03fc7921b0ba Mon Sep 17 00:00:00 2001 From: haga-rak Date: Sun, 2 Feb 2025 00:23:04 +0100 Subject: [PATCH 5/9] Add origin un rule exception information --- .../Core/ConnectionErrorPageHelper.cs | 1 - .../Rules/Actions/AddResponseHeaderAction.cs | 2 +- .../Rules/Actions/ForceRemotePortAction.cs | 2 +- .../HighLevelActions/InjectHtmlTagAction.cs | 4 +- .../HighLevelActions/ServeDirectoryAction.cs | 2 +- .../SetRequestCookieAction.cs | 2 +- .../SetResponseCookieAction.cs | 4 +- .../Rules/Actions/SpoofDnsAction.cs | 4 +- src/Fluxzy.Core/Rules/Filters/ExecFilter.cs | 4 +- src/Fluxzy.Core/Rules/Filters/StringFilter.cs | 2 +- src/Fluxzy.Core/Rules/Rule.cs | 23 +++++- .../Rules/RuleDefinitionMismatchException.cs | 19 ----- .../Rules/RuleExecutionFailureException.cs | 75 +++++++++++++++++++ .../Cases/BadRuleHandlingTests.cs | 2 +- 14 files changed, 108 insertions(+), 38 deletions(-) delete mode 100644 src/Fluxzy.Core/Rules/RuleDefinitionMismatchException.cs create mode 100644 src/Fluxzy.Core/Rules/RuleExecutionFailureException.cs diff --git a/src/Fluxzy.Core/Core/ConnectionErrorPageHelper.cs b/src/Fluxzy.Core/Core/ConnectionErrorPageHelper.cs index d588a21e4..87b65aef3 100644 --- a/src/Fluxzy.Core/Core/ConnectionErrorPageHelper.cs +++ b/src/Fluxzy.Core/Core/ConnectionErrorPageHelper.cs @@ -79,7 +79,6 @@ public static (string FlatHeader, byte[] BodyContent) GetSimplePlainTextResponse var header = string.Format(ErrorHeaderText, statusLine, messageText.Length, errorTypeText); var body = Encoding.UTF8.GetBytes(messageText); return (header, body); - } } } diff --git a/src/Fluxzy.Core/Rules/Actions/AddResponseHeaderAction.cs b/src/Fluxzy.Core/Rules/Actions/AddResponseHeaderAction.cs index e6dd562a6..f7e06f38b 100644 --- a/src/Fluxzy.Core/Rules/Actions/AddResponseHeaderAction.cs +++ b/src/Fluxzy.Core/Rules/Actions/AddResponseHeaderAction.cs @@ -45,7 +45,7 @@ public override ValueTask InternalAlter( BreakPointManager breakPointManager) { if (string.IsNullOrWhiteSpace(HeaderName)) - throw new RuleExecutionFailureException("Header name cannot be empty"); + throw new RuleExecutionFailureException("Header name cannot be empty", this); context.ResponseHeaderAlterations.Add(new HeaderAlterationAdd(HeaderName.EvaluateVariable(context) ?? string.Empty, HeaderValue.EvaluateVariable(context) ?? string.Empty)); diff --git a/src/Fluxzy.Core/Rules/Actions/ForceRemotePortAction.cs b/src/Fluxzy.Core/Rules/Actions/ForceRemotePortAction.cs index 85159c42a..ca0a92d5f 100644 --- a/src/Fluxzy.Core/Rules/Actions/ForceRemotePortAction.cs +++ b/src/Fluxzy.Core/Rules/Actions/ForceRemotePortAction.cs @@ -33,7 +33,7 @@ public override ValueTask InternalAlter( BreakPointManager breakPointManager) { if (Port <= 0 || Port > 65535) - throw new RuleExecutionFailureException("Port must be between 1 and 65535"); + throw new RuleExecutionFailureException("Port must be between 1 and 65535", this); context.RemoteHostPort = Port; diff --git a/src/Fluxzy.Core/Rules/Actions/HighLevelActions/InjectHtmlTagAction.cs b/src/Fluxzy.Core/Rules/Actions/HighLevelActions/InjectHtmlTagAction.cs index 877e06634..102fcad1b 100644 --- a/src/Fluxzy.Core/Rules/Actions/HighLevelActions/InjectHtmlTagAction.cs +++ b/src/Fluxzy.Core/Rules/Actions/HighLevelActions/InjectHtmlTagAction.cs @@ -73,11 +73,11 @@ public override ValueTask InternalAlter( } if (!FromFile && string.IsNullOrEmpty(HtmlContent)) { - throw new RuleExecutionFailureException("Text is null or empty"); + throw new RuleExecutionFailureException("Text is null or empty", this); } if (FromFile && string.IsNullOrEmpty(FileName)) { - throw new RuleExecutionFailureException("FileName is null or empty"); + throw new RuleExecutionFailureException("FileName is null or empty", this); } if (RestrictToHtml) { diff --git a/src/Fluxzy.Core/Rules/Actions/HighLevelActions/ServeDirectoryAction.cs b/src/Fluxzy.Core/Rules/Actions/HighLevelActions/ServeDirectoryAction.cs index 1ea4ba985..d127862fe 100644 --- a/src/Fluxzy.Core/Rules/Actions/HighLevelActions/ServeDirectoryAction.cs +++ b/src/Fluxzy.Core/Rules/Actions/HighLevelActions/ServeDirectoryAction.cs @@ -32,7 +32,7 @@ public override ValueTask InternalAlter( BreakPointManager breakPointManager) { if (!System.IO.Directory.Exists(Directory)) { - throw new RuleExecutionFailureException($"Directory {Directory} does not exist"); + throw new RuleExecutionFailureException($"Directory {Directory} does not exist", this); } if (exchange == null) { diff --git a/src/Fluxzy.Core/Rules/Actions/HighLevelActions/SetRequestCookieAction.cs b/src/Fluxzy.Core/Rules/Actions/HighLevelActions/SetRequestCookieAction.cs index e7fcc94f1..f6274d2a7 100644 --- a/src/Fluxzy.Core/Rules/Actions/HighLevelActions/SetRequestCookieAction.cs +++ b/src/Fluxzy.Core/Rules/Actions/HighLevelActions/SetRequestCookieAction.cs @@ -42,7 +42,7 @@ public override ValueTask InternalAlter( if (Name == null!) throw new RuleExecutionFailureException( - $"{nameof(Name)} is mandatory for {nameof(SetRequestCookieAction)}"); + $"{nameof(Name)} is mandatory for {nameof(SetRequestCookieAction)}", this); var cookieHeaders = exchange.GetRequestHeaders().Where( c => c.Name.Span.Equals("cookie", StringComparison.OrdinalIgnoreCase)) diff --git a/src/Fluxzy.Core/Rules/Actions/HighLevelActions/SetResponseCookieAction.cs b/src/Fluxzy.Core/Rules/Actions/HighLevelActions/SetResponseCookieAction.cs index 1d1b09c73..a827abd59 100644 --- a/src/Fluxzy.Core/Rules/Actions/HighLevelActions/SetResponseCookieAction.cs +++ b/src/Fluxzy.Core/Rules/Actions/HighLevelActions/SetResponseCookieAction.cs @@ -61,11 +61,11 @@ public override ValueTask InternalAlter( { if (Name == null!) throw new RuleExecutionFailureException( - $"{nameof(Name)} is mandatory for {nameof(SetResponseCookieAction)}"); + $"{nameof(Name)} is mandatory for {nameof(SetResponseCookieAction)}", this); if (Value == null!) throw new RuleExecutionFailureException( - $"{nameof(Value)} is mandatory for {nameof(SetResponseCookieAction)}"); + $"{nameof(Value)} is mandatory for {nameof(SetResponseCookieAction)}", this); if (exchange == null) return default; diff --git a/src/Fluxzy.Core/Rules/Actions/SpoofDnsAction.cs b/src/Fluxzy.Core/Rules/Actions/SpoofDnsAction.cs index c5bb11c8e..684466c7e 100644 --- a/src/Fluxzy.Core/Rules/Actions/SpoofDnsAction.cs +++ b/src/Fluxzy.Core/Rules/Actions/SpoofDnsAction.cs @@ -54,7 +54,7 @@ public override ValueTask InternalAlter( if (!string.IsNullOrEmpty(remoteHostIp)) { if (!IPAddress.TryParse(remoteHostIp, out var ip)) - throw new RuleExecutionFailureException($"{remoteHostIp} is not a valid IP address"); + throw new RuleExecutionFailureException($"{remoteHostIp} is not a valid IP address", this); context.RemoteHostIp = ip; } @@ -62,7 +62,7 @@ public override ValueTask InternalAlter( if (RemoteHostPort != null && RemoteHostPort != 0) { if (RemoteHostPort < 0 || RemoteHostPort > 65535) throw new RuleExecutionFailureException( - $"{RemoteHostPort} is not a valid port. Port must be between 0 and 65536 exclusive."); + $"{RemoteHostPort} is not a valid port. Port must be between 0 and 65536 exclusive.", this); context.RemoteHostPort = RemoteHostPort; } diff --git a/src/Fluxzy.Core/Rules/Filters/ExecFilter.cs b/src/Fluxzy.Core/Rules/Filters/ExecFilter.cs index b2c16ae2b..7e13b18a2 100644 --- a/src/Fluxzy.Core/Rules/Filters/ExecFilter.cs +++ b/src/Fluxzy.Core/Rules/Filters/ExecFilter.cs @@ -42,7 +42,7 @@ protected override bool InternalApply( var fileName = Filename.EvaluateVariable(exchangeContext); if (string.IsNullOrWhiteSpace(fileName)) { - throw new RuleExecutionFailureException($"{nameof(Filename)} cannot be null or empty"); + throw new RuleExecutionFailureException($"{nameof(Filename)} cannot be null or empty", this); } var arguments = Arguments.EvaluateVariable(exchangeContext); @@ -75,7 +75,7 @@ protected override bool InternalApply( catch (Exception e) { Console.WriteLine(e); throw new RuleExecutionFailureException($"An error occurs while running process:" + - $"{nameof(Filename)}", e); + $"{nameof(Filename)}", this, e); } } diff --git a/src/Fluxzy.Core/Rules/Filters/StringFilter.cs b/src/Fluxzy.Core/Rules/Filters/StringFilter.cs index f3f786f23..448e585be 100644 --- a/src/Fluxzy.Core/Rules/Filters/StringFilter.cs +++ b/src/Fluxzy.Core/Rules/Filters/StringFilter.cs @@ -115,7 +115,7 @@ protected override bool InternalApply( continue; default: - throw new RuleExecutionFailureException($"Unimplemented string operation {Operation}"); + throw new RuleExecutionFailureException($"Unimplemented string operation {Operation}", this); } } diff --git a/src/Fluxzy.Core/Rules/Rule.cs b/src/Fluxzy.Core/Rules/Rule.cs index ee0225c4f..f56028605 100644 --- a/src/Fluxzy.Core/Rules/Rule.cs +++ b/src/Fluxzy.Core/Rules/Rule.cs @@ -42,12 +42,27 @@ public ValueTask Enforce( if (!context.FilterEvaluationResult.TryGetValue(Filter, out var result)) { - result = Filter.Apply(context, context.Authority, exchange, null); - context.FilterEvaluationResult[Filter] = result; + try { + result = Filter.Apply(context, context.Authority, exchange, null); + context.FilterEvaluationResult[Filter] = result; + } + catch (Exception e) { + if (e is RuleExecutionFailureException) + throw; + throw new RuleExecutionFailureException(e.Message, Filter, e); + } } - if (result) - return Action.Alter(context, exchange, connection, filterScope, breakPointManager); + try { + if (result) + return Action.Alter(context, exchange, connection, filterScope, breakPointManager); + } + catch (Exception e) { + if (e is RuleExecutionFailureException) + throw; + + throw new RuleExecutionFailureException(e.Message, Action, e); + } return default; } diff --git a/src/Fluxzy.Core/Rules/RuleDefinitionMismatchException.cs b/src/Fluxzy.Core/Rules/RuleDefinitionMismatchException.cs deleted file mode 100644 index df529202e..000000000 --- a/src/Fluxzy.Core/Rules/RuleDefinitionMismatchException.cs +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright 2021 - Haga Rakotoharivelo - https://github.com/haga-rak - -using System; - -namespace Fluxzy.Rules -{ - public class RuleExecutionFailureException : Exception - { - public RuleExecutionFailureException(string message) - : base(message) - { - } - - public RuleExecutionFailureException(string message, Exception innerException) - : base(message, innerException) - { - } - } -} diff --git a/src/Fluxzy.Core/Rules/RuleExecutionFailureException.cs b/src/Fluxzy.Core/Rules/RuleExecutionFailureException.cs new file mode 100644 index 000000000..ffc1be2e2 --- /dev/null +++ b/src/Fluxzy.Core/Rules/RuleExecutionFailureException.cs @@ -0,0 +1,75 @@ +// Copyright 2021 - Haga Rakotoharivelo - https://github.com/haga-rak + +using System; +using System.Text; +using Fluxzy.Rules.Filters; +using static System.Collections.Specialized.BitVector32; + +namespace Fluxzy.Rules +{ + public class RuleExecutionFailureException : Exception + { + public RuleExecutionFailureException(string message, Exception ex) + : base(message, ex) + { + } + + public RuleExecutionFailureException(string message, Filter filter) + : base(FormatMessage(message, filter, null)) + { + } + + public RuleExecutionFailureException(string message, Action action) + : base(FormatMessage(message, action, null)) + { + } + + public RuleExecutionFailureException(string message, Filter filter, Exception innerException) + : base(FormatMessage(message, filter, innerException)) + { + } + + public RuleExecutionFailureException(string message, Action action, Exception innerException) + : base(FormatMessage(message, action, innerException)) + { + } + + private static string FormatMessage(string originalMessage, Filter filter, Exception? exception) + { + var builder = new StringBuilder(originalMessage); + + builder.AppendLine(); + builder.AppendLine(); + builder.AppendLine($"Origin: [{filter.GetType().Name}] “{filter.AutoGeneratedName}” " + + $"(Friendly Name: {filter.FriendlyName}) ({filter.Identifier})"); + + if (exception != null) + { + builder.AppendLine(); + builder.AppendLine("Exception:"); + builder.AppendLine(exception.ToString()); + } + + return builder.ToString(); + } + + private static string FormatMessage(string originalMessage, Action action, Exception? exception) + { + var builder = new StringBuilder(originalMessage); + + builder.AppendLine(); + builder.AppendLine(); + builder.AppendLine($"Origin: [{action.GetType().Name}] “{action.DefaultDescription}” " + + $"(Friendly Name: {action.FriendlyName}) ({action.Identifier})"); + + if (exception != null) + { + builder.AppendLine(); + builder.AppendLine("Exception:"); + builder.AppendLine(exception.ToString()); + } + + return builder.ToString(); + } + } +} diff --git a/test/Fluxzy.Tests/Cases/BadRuleHandlingTests.cs b/test/Fluxzy.Tests/Cases/BadRuleHandlingTests.cs index 684d43be7..a08417b80 100644 --- a/test/Fluxzy.Tests/Cases/BadRuleHandlingTests.cs +++ b/test/Fluxzy.Tests/Cases/BadRuleHandlingTests.cs @@ -28,7 +28,7 @@ public async Task HandleBadRuleException() var response = await client.GetAsync(TestConstants.Http2Host); - _ = await response.Content.ReadAsStringAsync(); + var content = await response.Content.ReadAsStringAsync(); var hasHeader = response.Headers.TryGetValues("x-fluxzy-error-type", out var values); Assert.True(hasHeader); From 479bffe592ca31f487954e7a51e276665970855e Mon Sep 17 00:00:00 2001 From: haga-rak Date: Sun, 2 Feb 2025 00:31:25 +0100 Subject: [PATCH 6/9] Add more unit tests --- .../Filters/RequestFilters/IsSelfFilter.cs | 76 +++++++++---------- .../Filters/RequestFilters/MethodFilter.cs | 2 +- .../Cases/BadRuleHandlingTests.cs | 29 ++++++- 3 files changed, 64 insertions(+), 43 deletions(-) diff --git a/src/Fluxzy.Core/Rules/Filters/RequestFilters/IsSelfFilter.cs b/src/Fluxzy.Core/Rules/Filters/RequestFilters/IsSelfFilter.cs index f99adb665..0273a847e 100644 --- a/src/Fluxzy.Core/Rules/Filters/RequestFilters/IsSelfFilter.cs +++ b/src/Fluxzy.Core/Rules/Filters/RequestFilters/IsSelfFilter.cs @@ -1,39 +1,39 @@ -// Copyright 2021 - Haga Rakotoharivelo - https://github.com/haga-rak - -using System.Collections.Generic; +// Copyright 2021 - Haga Rakotoharivelo - https://github.com/haga-rak + +using System.Collections.Generic; using Fluxzy.Core; -using Fluxzy.Misc; - -namespace Fluxzy.Rules.Filters.RequestFilters -{ - [FilterMetaData( - LongDescription = "Check if incoming request considers fluxzy as a web server", - NotSelectable = true - )] - public class IsSelfFilter : Filter - { - public override FilterScope FilterScope => FilterScope.DnsSolveDone; - - protected override bool InternalApply( - ExchangeContext? exchangeContext, IAuthority authority, IExchange? exchange, IFilteringContext? filteringContext) - { - if (exchangeContext == null || !(exchange is Exchange internalExchange)) - return false; - - if (internalExchange.Metrics.DownStreamLocalPort == exchangeContext.RemoteHostPort - && - exchangeContext.RemoteHostIp != null && - IpUtility.LocalAddresses.Contains(exchangeContext.RemoteHostIp)) { - return true; - } - - return false; - } - - public override IEnumerable GetExamples() - { - yield return GetDefaultSample()!; - - } - } -} +using Fluxzy.Misc; + +namespace Fluxzy.Rules.Filters.RequestFilters +{ + [FilterMetaData( + LongDescription = "Check if incoming request considers fluxzy as a web server", + NotSelectable = true + )] + public class IsSelfFilter : Filter + { + public override FilterScope FilterScope => FilterScope.DnsSolveDone; + + protected override bool InternalApply( + ExchangeContext? exchangeContext, IAuthority authority, IExchange? exchange, IFilteringContext? filteringContext) + { + if (exchangeContext == null || !(exchange is Exchange internalExchange)) + return false; + + if (internalExchange.Metrics.DownStreamLocalPort == exchangeContext.RemoteHostPort + && + exchangeContext.RemoteHostIp != null && + IpUtility.LocalAddresses.Contains(exchangeContext.RemoteHostIp)) { + return true; + } + + return false; + } + + public override IEnumerable GetExamples() + { + yield return GetDefaultSample()!; + + } + } +} diff --git a/src/Fluxzy.Core/Rules/Filters/RequestFilters/MethodFilter.cs b/src/Fluxzy.Core/Rules/Filters/RequestFilters/MethodFilter.cs index a5ee6e72e..480fee6be 100644 --- a/src/Fluxzy.Core/Rules/Filters/RequestFilters/MethodFilter.cs +++ b/src/Fluxzy.Core/Rules/Filters/RequestFilters/MethodFilter.cs @@ -74,4 +74,4 @@ public static IConfigureActionBuilder WhenMethodIsPut(this IConfigureFilterBuild return builder.WhenMethodIs("PUT"); } } -} +} diff --git a/test/Fluxzy.Tests/Cases/BadRuleHandlingTests.cs b/test/Fluxzy.Tests/Cases/BadRuleHandlingTests.cs index a08417b80..b800a793f 100644 --- a/test/Fluxzy.Tests/Cases/BadRuleHandlingTests.cs +++ b/test/Fluxzy.Tests/Cases/BadRuleHandlingTests.cs @@ -1,9 +1,11 @@ // Copyright 2021 - Haga Rakotoharivelo - https://github.com/haga-rak +using System; using System.Linq; using System.Threading.Tasks; using Fluxzy.Rules; using Fluxzy.Rules.Actions; +using Fluxzy.Rules.Extensions; using Fluxzy.Rules.Filters; using Fluxzy.Rules.Filters.RequestFilters; using Fluxzy.Tests._Fixtures; @@ -14,13 +16,32 @@ namespace Fluxzy.Tests.Cases public class BadRuleHandlingTests { [Fact] - public async Task HandleBadRuleException() + public async Task HandleBadFilter1Exception() + { + await HandleGeneric(c => + c.When(new HostFilter("*", StringSelectorOperation.Regex)) + .Do(new AddResponseHeaderAction("yes", "no"))); + } + + [Fact] + public async Task HandleBadFilter2Exception() + { + await HandleGeneric(c => + c.When(new AbsoluteUriFilter("*", StringSelectorOperation.Regex)) + .Do(new AddResponseHeaderAction("yes", "no"))); + } + + [Fact] + public async Task HandleBadActionException() + { + await HandleGeneric(c => c.WhenAny().Do(new DelayAction(-10))); + } + + private async Task HandleGeneric(Action builder) { var setting = FluxzySetting.CreateLocalRandomPort(); - setting.ConfigureRule().When( - new HostFilter("*", StringSelectorOperation.Regex)) - .Do(new AddResponseHeaderAction("yes", "no")); + builder(setting.ConfigureRule()); await using var proxy = new Proxy(setting); From d94652256abb3e5520646d88ecf32c75ed3c9541 Mon Sep 17 00:00:00 2001 From: haga-rak Date: Sun, 2 Feb 2025 00:46:38 +0100 Subject: [PATCH 7/9] Remove unused files --- fluxzy.core.sln | 5 ----- tools/scripts/NameAndCompress.csx | 27 --------------------------- 2 files changed, 32 deletions(-) delete mode 100644 tools/scripts/NameAndCompress.csx diff --git a/fluxzy.core.sln b/fluxzy.core.sln index 660886c4c..c08d98913 100644 --- a/fluxzy.core.sln +++ b/fluxzy.core.sln @@ -39,11 +39,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "__global", "__global", "{00 EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Samples", "Samples", "{30657256-C907-42C2-B7B2-DA4FD8D0E412}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Scripts", "Scripts", "{F5C5DD67-8A16-4561-8545-2EF0441A2015}" - ProjectSection(SolutionItems) = preProject - tools\scripts\NameAndCompress.csx = tools\scripts\NameAndCompress.csx - EndProjectSection -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Fluxzy.Core", "src\Fluxzy.Core\Fluxzy.Core.csproj", "{C79EDDB1-E4FA-4AB3-BAE4-B60D4D4E0B5E}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "fluxzy", "src\Fluxzy\fluxzy.csproj", "{7826F811-8525-456B-99AC-03FBB8D37484}" diff --git a/tools/scripts/NameAndCompress.csx b/tools/scripts/NameAndCompress.csx deleted file mode 100644 index 6ba5c414f..000000000 --- a/tools/scripts/NameAndCompress.csx +++ /dev/null @@ -1,27 +0,0 @@ -using System.Runtime.InteropServices; - -var version = Console.In.ReadToEnd().Trim('\r', '\n', ' ', '\t'); - -var shortIdentifier = Operating​System.IsWindows() ? - "windows" : (OperatingSystem.IsMacOS() ? "macos" : - (OperatingSystem.IsLinux() ? "linux" : "custom")); - -shortIdentifier += $"-{RuntimeInformation.ProcessArchitecture}"; -shortIdentifier = shortIdentifier.ToLowerInvariant(); - -var fileName = $"fluxzy-{version}-{shortIdentifier}.zip"; - -var fullFileName = Path.Combine(Args[0], fileName); - -if (System.IO.File.Exists(fullFileName)) { - System.IO.File.Delete(fullFileName); -} - -System.IO.Compression.ZipFile.CreateFromDirectory( - Args[1], - fullFileName, - System.IO.Compression.CompressionLevel.Optimal, - false - ); - -Console.Write($"{fileName}"); \ No newline at end of file From 4876cf098956b1b6320bea1c7911a7eebd29bacd Mon Sep 17 00:00:00 2001 From: haga-rak Date: Sun, 2 Feb 2025 01:27:22 +0100 Subject: [PATCH 8/9] Add archive writer and token in error handling --- .../Core/ConnectionErrorHandler.cs | 19 ++++++++++++++----- .../Core/ConnectionErrorPageHelper.cs | 2 +- src/Fluxzy.Core/Core/ProxyOrchestrator.cs | 2 +- .../Rules/Actions/RemoveCacheAction.cs | 2 +- 4 files changed, 17 insertions(+), 8 deletions(-) diff --git a/src/Fluxzy.Core/Core/ConnectionErrorHandler.cs b/src/Fluxzy.Core/Core/ConnectionErrorHandler.cs index eda7bbaf8..878149cee 100644 --- a/src/Fluxzy.Core/Core/ConnectionErrorHandler.cs +++ b/src/Fluxzy.Core/Core/ConnectionErrorHandler.cs @@ -7,11 +7,13 @@ using System.Security.Authentication; using System.Text; using System.Text.Json; +using System.Threading; using System.Threading.Tasks; using Fluxzy.Clients; using Fluxzy.Clients.H2; using Fluxzy.Misc.ResizableBuffers; using Fluxzy.Rules; +using Fluxzy.Writers; namespace Fluxzy.Core { @@ -30,6 +32,7 @@ public static bool RequalifyOnResponseSendError( } var remoteIpAddress = exchange.Connection?.RemoteAddress?.ToString(); + var remotePort = exchange.Connection?.Authority.Port.ToString(); if (ex.TryGetException(out var socketException)) { switch (socketException.SocketErrorCode) { @@ -61,7 +64,7 @@ public static bool RequalifyOnResponseSendError( case SocketError.ConnectionRefused: { var clientError = new ClientError( (int) socketException.SocketErrorCode, - $"The remote peer ({remoteIpAddress}) responded but refused actively to establish a connection.") { + $"The remote peer ({remoteIpAddress}) responded but refused actively to establish a connection on port {remotePort}.") { ExceptionMessage = socketException.Message }; @@ -164,12 +167,13 @@ public static async Task HandleGenericException(Exception ex, ExchangeSourceInitResult? exchangeInitResult, Exchange? exchange, RsBuffer buffer, - ITimingProvider timingProvider) + RealtimeArchiveWriter? archiveWriter, + ITimingProvider timingProvider, CancellationToken token) { if (exchange?.Connection == null || exchangeInitResult?.WriteStream == null) return false; - var message = "An unknown error has occured."; + var message = "A configuration error has occured.\r\n"; if (ex is RuleExecutionFailureException ruleException) { message = @@ -186,6 +190,8 @@ public static async Task HandleGenericException(Exception ex, exchange.Authority, message, ex.GetType().Name); + exchange.ClientErrors.Add(new ClientError(9999, message)); + exchange.Response.Header = new ResponseHeader( header.AsMemory(), exchange.Authority.Secure, true); @@ -199,13 +205,13 @@ public static async Task HandleGenericException(Exception ex, exchange.Metrics.ResponseHeaderStart = timingProvider.Instant(); await exchangeInitResult.WriteStream - .WriteAsync(buffer.Buffer, 0, responseHeaderLength) + .WriteAsync(buffer.Buffer, 0, responseHeaderLength, token) .ConfigureAwait(false); exchange.Metrics.ResponseHeaderEnd = timingProvider.Instant(); exchange.Metrics.ResponseBodyStart = timingProvider.Instant(); - await exchange.Response.Body.CopyToAsync(exchangeInitResult.WriteStream) + await exchange.Response.Body.CopyToAsync(exchangeInitResult.WriteStream, token) .ConfigureAwait(false); if (exchange.Metrics.ResponseBodyEnd == default) @@ -218,6 +224,9 @@ await exchange.Response.Body.CopyToAsync(exchangeInitResult.WriteStream) exchange.ExchangeCompletionSource.TrySetResult(true); } + archiveWriter?.Update(exchange, ArchiveUpdateType.AfterResponse, token); + + return true; } } diff --git a/src/Fluxzy.Core/Core/ConnectionErrorPageHelper.cs b/src/Fluxzy.Core/Core/ConnectionErrorPageHelper.cs index 87b65aef3..a257c1292 100644 --- a/src/Fluxzy.Core/Core/ConnectionErrorPageHelper.cs +++ b/src/Fluxzy.Core/Core/ConnectionErrorPageHelper.cs @@ -75,7 +75,7 @@ public static (string FlatHeader, byte[] BodyContent) GetPrettyErrorPage( public static (string FlatHeader, byte[] BodyContent) GetSimplePlainTextResponse( Authority authority, string messageText, string errorTypeText) { - var statusLine = FluxzySharedSetting.Use528 ? "528 Fluxzy error" : "502 Bad Gateway"; + var statusLine = "502 Fluxzy Configuration Error"; var header = string.Format(ErrorHeaderText, statusLine, messageText.Length, errorTypeText); var body = Encoding.UTF8.GetBytes(messageText); return (header, body); diff --git a/src/Fluxzy.Core/Core/ProxyOrchestrator.cs b/src/Fluxzy.Core/Core/ProxyOrchestrator.cs index 4effffac7..6262a83df 100644 --- a/src/Fluxzy.Core/Core/ProxyOrchestrator.cs +++ b/src/Fluxzy.Core/Core/ProxyOrchestrator.cs @@ -542,7 +542,7 @@ await responseBodyStream.CopyDetailed( var handleResult = await ConnectionErrorHandler.HandleGenericException(ex, exchangeSourceInitResult, - exchange, buffer, ITimingProvider.Default); + exchange, buffer, _archiveWriter, ITimingProvider.Default, token); if (!handleResult) // diff --git a/src/Fluxzy.Core/Rules/Actions/RemoveCacheAction.cs b/src/Fluxzy.Core/Rules/Actions/RemoveCacheAction.cs index f6262e07c..5df2a37fa 100644 --- a/src/Fluxzy.Core/Rules/Actions/RemoveCacheAction.cs +++ b/src/Fluxzy.Core/Rules/Actions/RemoveCacheAction.cs @@ -43,4 +43,4 @@ public override ValueTask InternalAlter( return default; } } -} +} From 9bb8f45a667654f9163ab13625d1a24999283cbb Mon Sep 17 00:00:00 2001 From: haga-rak Date: Sun, 2 Feb 2025 01:28:37 +0100 Subject: [PATCH 9/9] Rollback port information --- src/Fluxzy.Core/Core/ConnectionErrorHandler.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Fluxzy.Core/Core/ConnectionErrorHandler.cs b/src/Fluxzy.Core/Core/ConnectionErrorHandler.cs index 878149cee..e522144f9 100644 --- a/src/Fluxzy.Core/Core/ConnectionErrorHandler.cs +++ b/src/Fluxzy.Core/Core/ConnectionErrorHandler.cs @@ -32,7 +32,6 @@ public static bool RequalifyOnResponseSendError( } var remoteIpAddress = exchange.Connection?.RemoteAddress?.ToString(); - var remotePort = exchange.Connection?.Authority.Port.ToString(); if (ex.TryGetException(out var socketException)) { switch (socketException.SocketErrorCode) { @@ -64,7 +63,7 @@ public static bool RequalifyOnResponseSendError( case SocketError.ConnectionRefused: { var clientError = new ClientError( (int) socketException.SocketErrorCode, - $"The remote peer ({remoteIpAddress}) responded but refused actively to establish a connection on port {remotePort}.") { + $"The remote peer ({remoteIpAddress}) responded but refused actively to establish a connection.") { ExceptionMessage = socketException.Message };