Created
September 26, 2024 18:44
-
-
Save Pharylon/79082fd3b899ad03339266a962c81a80 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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