From 56b3613166544f02a05dcc29fb51c9f9a4941dee Mon Sep 17 00:00:00 2001 From: Howard Richards Date: Thu, 13 Apr 2023 17:54:06 +0100 Subject: [PATCH] Adds option to CocoonProxyOptions to control the request Host header value. Fixes #30 --- .../ReCode.Cocoon.Proxy/Proxy/CocoonProxy.cs | 53 ++++++++++++++++--- .../Proxy/CocoonProxyOptions.cs | 5 ++ .../Proxy/HostHeaderOptions.cs | 30 +++++++++++ 3 files changed, 82 insertions(+), 6 deletions(-) create mode 100644 main/src/ReCode.Cocoon.Proxy/Proxy/HostHeaderOptions.cs diff --git a/main/src/ReCode.Cocoon.Proxy/Proxy/CocoonProxy.cs b/main/src/ReCode.Cocoon.Proxy/Proxy/CocoonProxy.cs index cbcfe3f..ad887ac 100644 --- a/main/src/ReCode.Cocoon.Proxy/Proxy/CocoonProxy.cs +++ b/main/src/ReCode.Cocoon.Proxy/Proxy/CocoonProxy.cs @@ -1,12 +1,12 @@ -using System; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc.ModelBinding.Binders; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Logging; +using System; using System.Collections.Generic; -using System.Diagnostics; using System.Net; using System.Net.Http; using System.Threading.Tasks; -using Microsoft.AspNetCore.Http; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.Logging; using Yarp.ReverseProxy.Forwarder; namespace ReCode.Cocoon.Proxy.Proxy @@ -19,6 +19,8 @@ public class CocoonProxy private readonly RedirectTransformer _transformer; private readonly ForwarderRequestConfig _requestConfig; private readonly string _destinationPrefix; + private readonly HostHeaderOptions _hostHeaderOption; + private readonly string _host; public CocoonProxy(IConfiguration configuration, ILogger logger, IHttpForwarder httpForwarder, CocoonProxyOptions? proxyOptions) { @@ -36,7 +38,11 @@ public CocoonProxy(IConfiguration configuration, ILogger logger, IH throw new InvalidOperationException("Invalid DestinationPrefix"); } - logger.LogInformation($"Cocoon Proxy backend: {destinationPrefixUri}"); + logger.LogInformation("Cocoon Proxy backend: {destinationPrefixUri}", destinationPrefixUri); + + // save the host + _host = destinationPrefixUri.Host; + logger.LogInformation("Cocoon Proxy backend: host is {host}", _host); _backendUrls = CocoonProxyExclusions.CreateExclusionSet(configuration); @@ -57,6 +63,9 @@ public CocoonProxy(IConfiguration configuration, ILogger logger, IH _httpClient = new HttpMessageInvoker(socketsHttpHandler); _transformer = new RedirectTransformer(destinationPrefixUri); + // save the host header option, or use default option + _hostHeaderOption = proxyOptions?.HostHeaderOption ?? HostHeaderOptions.None; + if (!TimeSpan.TryParse(configuration.GetValue("Cocoon:Proxy:Timeout"), out var timeout)) { timeout = TimeSpan.FromSeconds(30); @@ -75,10 +84,42 @@ public async Task ProxyAsync(HttpContext httpContext) return; } + // amend the HOST value in the request based on _hostHeaderOption + switch (_hostHeaderOption) + { + case HostHeaderOptions.None: + // HostHeader unchanged + break; + + case HostHeaderOptions.SetDefault: + // HostHeader set to default + SetHost(httpContext.Request.Headers, default); + break; + + case HostHeaderOptions.UseHost: + // HostHeader set to _host + SetHost(httpContext.Request.Headers, _host); + break; + + default: + // unhandled options not supported + throw new NotSupportedException($"Unhandled HostHeaderOption {_hostHeaderOption}"); + } + using var activity = ProxyActivitySource.StartActivity("Proxy"); activity?.SetTag("path", httpContext.Request.Path.ToString()); await _httpForwarder.SendAsync(httpContext, _destinationPrefix, _httpClient, _requestConfig, _transformer); } + + /// + /// NET6 has useful + /// + /// + /// + private static void SetHost(IHeaderDictionary headers, string? host) + { + headers["Host"] = host; + } } } \ No newline at end of file diff --git a/main/src/ReCode.Cocoon.Proxy/Proxy/CocoonProxyOptions.cs b/main/src/ReCode.Cocoon.Proxy/Proxy/CocoonProxyOptions.cs index e924ec2..9273d51 100644 --- a/main/src/ReCode.Cocoon.Proxy/Proxy/CocoonProxyOptions.cs +++ b/main/src/ReCode.Cocoon.Proxy/Proxy/CocoonProxyOptions.cs @@ -5,5 +5,10 @@ namespace ReCode.Cocoon.Proxy.Proxy public class CocoonProxyOptions { public RemoteCertificateValidationCallback? RemoteCertificateValidationCallback { get; set; } + + /// + /// Set Host header behaviour + /// + public HostHeaderOptions HostHeaderOption { get; set; } = HostHeaderOptions.None; } } diff --git a/main/src/ReCode.Cocoon.Proxy/Proxy/HostHeaderOptions.cs b/main/src/ReCode.Cocoon.Proxy/Proxy/HostHeaderOptions.cs new file mode 100644 index 0000000..3c8edaa --- /dev/null +++ b/main/src/ReCode.Cocoon.Proxy/Proxy/HostHeaderOptions.cs @@ -0,0 +1,30 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ReCode.Cocoon.Proxy.Proxy +{ + /// + /// Host Header options when proxying request + /// + /// + /// Fixes #30 https://github.com/VisualReCode/Cocoon/issues/30 + /// + public enum HostHeaderOptions + { + /// + /// Default operation: no changes to Host header + /// + None, + /// + /// Used on Azure hosting: sets the Host header to `default` (null) + /// + SetDefault, + /// + /// Copies the host header from the request to the Cocoon proxy + /// + UseHost + } +}