Skip to content

Instantly share code, notes, and snippets.

@Pharylon
Created September 26, 2024 18:44
Show Gist options
  • Save Pharylon/79082fd3b899ad03339266a962c81a80 to your computer and use it in GitHub Desktop.
Save Pharylon/79082fd3b899ad03339266a962c81a80 to your computer and use it in GitHub Desktop.
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Primitives;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Threading.Tasks;
namespace CaroTransWeb.DmzHelper
{
public class Startup
{
private readonly IConfiguration _config;
private HttpClient _client;
private bool _rewriteCookies;
private ILogger _logger;
public Startup(IConfiguration config)
{
var handler = new HttpClientHandler();
handler.UseCookies = false;
handler.AllowAutoRedirect = false;
_config = config;
var target = config["target"];
_rewriteCookies = config.GetValue<bool>("rewriteCookies");
_client = new HttpClient(handler);
_client.BaseAddress = new Uri(target);
int timeout = config.GetValue<int>("timeout");
_client.Timeout = TimeSpan.FromMinutes(timeout);
}
// This method gets called by the runtime. Use this method to add services to the container.
// For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
public void ConfigureServices(IServiceCollection services)
{
//services.GetCo
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILogger<Program> logger)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
_logger = logger;
if(_logger != null)
{
_logger.LogWarning("DmzHelper starting up.");
}
//app.UseRouting();
//app.UseEndpoints(endpoints =>
//{
// endpoints.MapGet("", async context =>
// {
// await context.Response.WriteAsync("Hello World!");
// });
//});
app.Use(async (context, next) =>
{
//if (context.Request.Method == "OPTIONS")
//{
// context.Response.StatusCode = 200;
// await context.Response.WriteAsync("");
// context.Response.Headers.Add("Access-Control-Allow-Origin", "*");
// await next();
// return;
//}
//await RunTest();
//var headers = context.Request.Headers.ToDictionary(x => x.Key, x => x.Value.ToString());
string path = context.Request.Path.Add(context.Request.QueryString);
//var path = "v2/locations/lax";
var reqMessageMethod = new HttpMethod(context.Request.Method);
var requestMessage = new HttpRequestMessage(reqMessageMethod, path);
//var body = await GetBody(context);
var body = await GetBodyBytes(context);
if (body.Length > 0)
{
var content = new ByteArrayContent(body);
requestMessage.Content = content;
if (context.Request.Headers.TryGetValue("Content-Type", out StringValues contentHeaders))
{
foreach (var h in contentHeaders)
{
content.Headers.Add("Content-Type", h);
}
}
}
TryAddHeaderToRequest(context.Request.Headers, requestMessage, "Accept");
TryAddHeaderToRequest(context.Request.Headers, requestMessage, "Authorization");
TryAddHeaderToRequest(context.Request.Headers, requestMessage, "Cookie");
TryAddHeaderToRequest(context.Request.Headers, requestMessage, "Access-Control-Request-Method");
TryAddHeaderToRequest(context.Request.Headers, requestMessage, "Access-Control-Request-Headers");
TryAddHeaderToRequest(context.Request.Headers, requestMessage, "Origin");
TryAddHeaderToRequest(context.Request.Headers, requestMessage, "User-Agent");
TryAddHeaderToRequest(context.Request.Headers, requestMessage, "Sec-Fetch-Mode");
TryAddHeaderToRequest(context.Request.Headers, requestMessage, "Sec-Fetch-Site");
TryAddHeaderToRequest(context.Request.Headers, requestMessage, "Sec-Fetch-Dest");
TryAddHeaderToRequest(context.Request.Headers, requestMessage, "Referer");
TryAddHeaderToRequest(context.Request.Headers, requestMessage, "Cache-Control");
TryAddHeaderToRequest(context.Request.Headers, requestMessage, "Accept-Language");
//TryAddHeaderToRequest(context.Request.Headers, requestMessage, "Accept-Encoding");
//TryAddHeaderToRequest(context.Request.Headers, requestMessage, "User-Agent");
HttpResponseMessage clientResponse = await GetClientResponse(requestMessage);
var clientResponseBody = await clientResponse.Content.ReadAsByteArrayAsync();
var cleintResponseBodyString = System.Text.Encoding.UTF8.GetString(clientResponseBody);
context.Response.StatusCode = GetStatusCode(clientResponse, env.IsDevelopment());
var cType = clientResponse.Content.Headers.ContentType?.ToString();
if (!string.IsNullOrWhiteSpace(cType))
{
context.Response.Headers.Add("Content-Type", cType);
}
var expires = clientResponse.Content.Headers.Expires?.ToString();
if (!string.IsNullOrWhiteSpace(expires))
{
context.Response.Headers.Add("Expires", expires);
}
//TryPassHeaderToResponse("Cookie", context, clientResponse);
TryPassHeaderToResponse("Location", context, clientResponse);
TryPassHeaderToResponse("Cache-Control", context, clientResponse);
TryPassHeaderToResponse("Date", context, clientResponse);
TryPassHeaderToResponse("Age", context, clientResponse);
TryPassHeaderToResponse("Access-Control-Allow-Credentials", context, clientResponse);
TryPassHeaderToResponse("Access-Control-Allow-Headers", context, clientResponse);
TryPassHeaderToResponse("Access-Control-Allow-Methods", context, clientResponse);
TrySetCorsHeader(context, clientResponse, env.IsDevelopment());
TrySetCookie(context, clientResponse, env.IsDevelopment());
if (clientResponseBody.Length > 0)
{
await context.Response.BodyWriter.WriteAsync(clientResponseBody);
await context.Response.BodyWriter.FlushAsync();
}
else
{
await context.Response.WriteAsync("");
}
//CAA: 2022/10/21: I don't think this is needed because Run() is being called in Main
//await next();
if(context.Response.HasStarted == false)
{
await next();
}
});
}
private async Task<HttpResponseMessage> GetClientResponse(HttpRequestMessage requestMessage)
{
if (_logger != null)
{
_logger.LogWarning("GetClientResponse called.");
}
//foreach (var header in context.Request.Headers.Where(x => !x.Key.Equals("host", StringComparison.OrdinalIgnoreCase)))
//{
// TryAddHeaderToRequest(context.Request.Headers, requestMessage, header.Key);
//}
return await _client.SendAsync(requestMessage);
}
private static void TrySetCorsHeader(HttpContext context, HttpResponseMessage clientResponse, bool isDevelopment)
{
if (clientResponse.Headers.Contains("Access-Control-Allow-Origin"))
{
if (isDevelopment)
{
context.Response.Headers.Add("Access-Control-Allow-Origin", "*");
}
else
{
var headerValues = clientResponse.Headers.GetValues("Access-Control-Allow-Origin");
foreach (var headerValue in headerValues)
{
context.Response.Headers.Add("Access-Control-Allow-Origin", headerValue);
}
}
}
}
private static int GetStatusCode(HttpResponseMessage clientResponse, bool isDevelopment)
{
var statusCode = (int)clientResponse.StatusCode;
if (isDevelopment && statusCode == 301)
{
return 200;
}
return statusCode;
}
private static void TryPassHeaderToResponse(string headerName, HttpContext context, HttpResponseMessage clientResponse)
{
if (clientResponse.Headers.Contains(headerName))
{
var headerValues = clientResponse.Headers.GetValues(headerName);
foreach (var headerValue in headerValues)
{
context.Response.Headers.Add(headerName, headerValue);
}
}
}
private void TrySetCookie(HttpContext context, HttpResponseMessage clientResponse, bool isDevelopment)
{
if (_logger != null)
{
_logger.LogWarning("TrySetCookie called.");
}
var cookieNamesSet = new List<string>();
var cookiesToSet = new List<string>();
if (clientResponse.Headers.Contains("Set-Cookie"))
{
var cookieValues = clientResponse.Headers.GetValues("Set-Cookie");
foreach (var cookieValue in cookieValues)
{
var cookieName = cookieValue.Substring(0, cookieValue.IndexOf("="));
if (!cookieNamesSet.Contains(cookieName))
{
if (isDevelopment || _rewriteCookies)
{
var splitValues = cookieValue.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries).Select(x => x.Trim());
var valuesToPass = splitValues.Where(x => !x.StartsWith("domain"));
var finalCookie = String.Join(';', valuesToPass);
cookiesToSet.Add(finalCookie);
}
else
{
cookiesToSet.Add(cookieValue);
}
}
cookieNamesSet.Add(cookieName);
}
}
if (cookiesToSet.Any())
{
context.Response.Headers.Add("Set-Cookie", new StringValues(cookiesToSet.ToArray()));
}
}
private static void TryAddHeaderToRequest(IHeaderDictionary headerDictionary, HttpRequestMessage requestMessage, string header)
{
if (headerDictionary.TryGetValue(header, out StringValues headerValues))
{
foreach (var h in headerValues)
{
requestMessage.Headers.Add(header, h);
}
}
}
private async Task RunTest()
{
//var testClient = new HttpClient();
//testClient.BaseAddress = new Uri("https://api.carotrans.com/v2/locations/lax");
var r = await _client.GetAsync("/");
var body = r.Content.ReadAsStringAsync();
}
private static async Task<string> GetBody(HttpContext context)
{
if (context.Request.Method != "GET")
{
using (var reader = new StreamReader(context.Request.Body))
{
var body = await reader.ReadToEndAsync();
return body;
}
}
return "";
}
private static async Task<byte[]> GetBodyBytes(HttpContext context)
{
if (context.Request.Method != "GET")
{
using (var myStream = context.Request.BodyReader.AsStream())
{
using (var memoryStream = new MemoryStream())
{
await myStream.CopyToAsync(memoryStream);
var myBytes = memoryStream.ToArray();
var myString = System.Text.Encoding.UTF8.GetString(myBytes);
return myBytes;
}
}
//var readResult = await context.Request.BodyReader.ReadAsync();
//var buffer = readResult.Buffer;
//if (buffer.IsSingleSegment)
//{
// myBytes = buffer.FirstSpan.ToArray();
//}
//else
//{
// context.Request.BodyReader.AdvanceTo()
//}
}
return Array.Empty<byte>();
}
//private static System.Text.Encoding GetEncoding(Dictionary<string, Microsoft.Extensions.Primitives.StringValues> headers)
//{
// System.Text.Encoding encoding = System.Text.Encoding.UTF8;
// var contentType = headers.FirstOrDefault(x => x.Key.ToLower() == "content-type").Value;
// if (!string.IsNullOrWhiteSpace(contentType))
// {
// var split = contentType.ToString().Split(";").Select(x => x.ToLower().Trim());
// var encodingString = split.FirstOrDefault(x => x.StartsWith("charset"));
// var finalEncodingString = encodingString.Replace("charset=", "");
// if (!string.IsNullOrWhiteSpace(encodingString))
// {
// if (finalEncodingString == "utf-8")
// {
// encoding = System.Text.Encoding.UTF8;
// }
// if (finalEncodingString == "utf-32")
// {
// encoding = System.Text.Encoding.UTF32;
// }
// if (finalEncodingString == "ascii")
// {
// encoding = System.Text.Encoding.ASCII;
// }
// }
// }
// return encoding;
//}
}
}
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace CaroTransWeb.DmzHelper
{
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment