Skip to content

Instantly share code, notes, and snippets.

@davepermen
Created October 21, 2024 13:23
Show Gist options
  • Save davepermen/dff38622f7dddddfb245bc36ca99e8b7 to your computer and use it in GitHub Desktop.
Save davepermen/dff38622f7dddddfb245bc36ca99e8b7 to your computer and use it in GitHub Desktop.
using Microsoft.AspNetCore.Server.Kestrel.Https;
using System.Diagnostics;
using System.Net;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using Yarp.ReverseProxy.Forwarder;
var demo = new
{
port = 5005,
cert = CertificateLoader.LoadFromStoreCert("localhost", "My", StoreLocation.CurrentUser, allowInvalid: true),
domain = "test.localhost",
localAddress = "https://localhost:7148/"
};
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddReverseProxy();
builder.WebHost.ConfigureKestrel(serverOptions =>
{
serverOptions.ListenAnyIP(demo.port, listenOptions =>
{
listenOptions.UseHttps(httpOptions =>
{
httpOptions.ServerCertificateSelector = (_, name) => name == demo.domain ? demo.cert : null;
});
});
});
var app = builder.Build();
var httpClient = new HttpMessageInvoker(new SocketsHttpHandler
{
UseProxy = false,
AllowAutoRedirect = false,
AutomaticDecompression = DecompressionMethods.None,
UseCookies = false,
EnableMultipleHttp2Connections = true,
ActivityHeadersPropagator = new ReverseProxyPropagator(DistributedContextPropagator.Current),
ConnectTimeout = TimeSpan.FromSeconds(15),
});
var transformer = new CustomTransformer(localAddress: demo.localAddress);
var requestConfig = new ForwarderRequestConfig { ActivityTimeout = TimeSpan.FromMilliseconds(int.MaxValue) };
app.UseRouting();
app.Map("/{**catch-all}", async (HttpContext httpContext, IHttpForwarder forwarder) =>
{
if (httpContext.Request.Host.Host == demo.domain)
{
var error = await forwarder.SendAsync(httpContext, demo.localAddress, httpClient, requestConfig, transformer);
// Check if the operation was successful
if (error != ForwarderError.None)
{
var errorFeature = httpContext.GetForwarderErrorFeature();
if(errorFeature != null)
{
var exception = errorFeature.Exception;
httpContext.Response.StatusCode = 500;
await httpContext.Response.Body.WriteAsync(Encoding.UTF8.GetBytes(exception.ToString()));
}
}
}
else
{
httpContext.Response.StatusCode = 404;
await httpContext.Response.Body.WriteAsync(Encoding.UTF8.GetBytes("Site not Found"));
}
});
app.Run();
internal class CustomTransformer(string localAddress) : HttpTransformer
{
public override async ValueTask TransformRequestAsync(HttpContext httpContext, HttpRequestMessage proxyRequest, string destinationPrefix, CancellationToken cancellationToken)
{
await base.TransformRequestAsync(httpContext, proxyRequest, destinationPrefix, cancellationToken);
proxyRequest.RequestUri = RequestUtilities.MakeDestinationAddress(localAddress, httpContext.Request.Path, httpContext.Request.QueryString);
proxyRequest.Headers.Host = null;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment