Add project files.

This commit is contained in:
2021-11-21 16:37:42 -05:00
parent f54e594bb7
commit 0f0a492952
10 changed files with 377 additions and 0 deletions

25
.dockerignore Normal file
View File

@@ -0,0 +1,25 @@
**/.classpath
**/.dockerignore
**/.env
**/.git
**/.gitignore
**/.project
**/.settings
**/.toolstarget
**/.vs
**/.vscode
**/*.*proj.user
**/*.dbmdl
**/*.jfm
**/azds.yaml
**/bin
**/charts
**/docker-compose*
**/Dockerfile*
**/node_modules
**/npm-debug.log
**/obj
**/secrets.dev.yaml
**/values.dev.yaml
LICENSE
README.md

View File

@@ -0,0 +1,25 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.31911.196
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CloudFlareReverseProxy", "CloudFlareReverseProxy\CloudFlareReverseProxy.csproj", "{EA43FF3F-964F-4982-8C79-B4DB77AB7FEF}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{EA43FF3F-964F-4982-8C79-B4DB77AB7FEF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{EA43FF3F-964F-4982-8C79-B4DB77AB7FEF}.Debug|Any CPU.Build.0 = Debug|Any CPU
{EA43FF3F-964F-4982-8C79-B4DB77AB7FEF}.Release|Any CPU.ActiveCfg = Release|Any CPU
{EA43FF3F-964F-4982-8C79-B4DB77AB7FEF}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {1983598E-E53B-4CDD-A7FA-E15EB8F3DB9A}
EndGlobalSection
EndGlobal

View File

@@ -0,0 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
<UserSecretsId>fe0043e8-ea3b-4937-b2a1-fb2af7fe92d6</UserSecretsId>
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="FlareSolverrSharp" Version="2.1.0" />
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.11.1" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,22 @@
#See https://aka.ms/containerfastmode to understand how Visual Studio uses this Dockerfile to build your images for faster debugging.
FROM mcr.microsoft.com/dotnet/aspnet:5.0 AS base
WORKDIR /app
EXPOSE 80
EXPOSE 443
FROM mcr.microsoft.com/dotnet/sdk:5.0 AS build
WORKDIR /src
COPY ["CloudFlareReverseProxy/CloudFlareReverseProxy.csproj", "CloudFlareReverseProxy/"]
RUN dotnet restore "CloudFlareReverseProxy/CloudFlareReverseProxy.csproj"
COPY . .
WORKDIR "/src/CloudFlareReverseProxy"
RUN dotnet build "CloudFlareReverseProxy.csproj" -c Release -o /app/build
FROM build AS publish
RUN dotnet publish "CloudFlareReverseProxy.csproj" -c Release -o /app/publish
FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "CloudFlareReverseProxy.dll"]

View File

@@ -0,0 +1,26 @@
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 CloudFlareReverseProxy
{
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>();
});
}
}

View File

@@ -0,0 +1,35 @@
{
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:40939",
"sslPort": 0
}
},
"profiles": {
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"CloudFlareReverseProxy": {
"commandName": "Project",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"dotnetRunMessages": "true",
"applicationUrl": "https://localhost:5001;http://localhost:5000"
},
"Docker": {
"commandName": "Docker",
"launchBrowser": true,
"launchUrl": "{Scheme}://{ServiceHost}:{ServicePort}",
"publishAllPorts": true,
"useSSL": true
}
}
}

View File

@@ -0,0 +1,167 @@
using FlareSolverrSharp;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.WebUtilities;
using Microsoft.Extensions.Configuration;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
namespace CloudFlareReverseProxy
{
public class ReverseProxyMiddleware
{
private static HttpClient _httpClient;
private readonly RequestDelegate _nextMiddleware;
public ReverseProxyMiddleware(RequestDelegate nextMiddleware, IConfiguration configuration)
{
_nextMiddleware = nextMiddleware;
var handler = new ClearanceHandler(configuration["FlareSolverrApiUrl"])
{
MaxTimeout = 60000
};
_httpClient = new HttpClient(handler);
}
public async Task Invoke(HttpContext context)
{
var targetUri = BuildTargetUri(context.Request);
if (targetUri != null)
{
var targetRequestMessage = CreateTargetMessage(context, targetUri);
using (var responseMessage = await _httpClient.SendAsync(targetRequestMessage, HttpCompletionOption.ResponseHeadersRead, context.RequestAborted))
{
context.Response.StatusCode = (int)responseMessage.StatusCode;
CopyFromTargetResponseHeaders(context, responseMessage);
await ProcessResponseContent(context, responseMessage);
}
return;
}
await _nextMiddleware(context);
}
private async Task ProcessResponseContent(HttpContext context, HttpResponseMessage responseMessage)
{
var content = await responseMessage.Content.ReadAsByteArrayAsync();
if (IsContentOfType(responseMessage, "text/html") || IsContentOfType(responseMessage, "text/javascript"))
{
var stringContent = Encoding.UTF8.GetString(content);
var newContent = stringContent.Replace("https://www.google.com", "/google")
.Replace("https://www.gstatic.com", "/googlestatic")
.Replace("https://docs.google.com/forms", "/googleforms");
await context.Response.WriteAsync(newContent, Encoding.UTF8);
}
else
{
await context.Response.Body.WriteAsync(content);
}
}
private bool IsContentOfType(HttpResponseMessage responseMessage, string type)
{
var result = false;
if (responseMessage.Content?.Headers?.ContentType != null)
{
result = responseMessage.Content.Headers.ContentType.MediaType == type;
}
return result;
}
private HttpRequestMessage CreateTargetMessage(HttpContext context, Uri targetUri)
{
var requestMessage = new HttpRequestMessage();
CopyFromOriginalRequestContentAndHeaders(context, requestMessage);
//targetUri = new Uri(QueryHelpers.AddQueryString(targetUri.OriginalString, new Dictionary<string, string>() { { "entry.1884265043", "John Doe" } }));
requestMessage.RequestUri = targetUri;
requestMessage.Headers.Host = targetUri.Host;
requestMessage.Method = GetMethod(context.Request.Method);
return requestMessage;
}
private void CopyFromOriginalRequestContentAndHeaders(HttpContext context, HttpRequestMessage requestMessage)
{
var requestMethod = context.Request.Method;
if (!HttpMethods.IsGet(requestMethod) &&
!HttpMethods.IsHead(requestMethod) &&
!HttpMethods.IsDelete(requestMethod) &&
!HttpMethods.IsTrace(requestMethod))
{
var streamContent = new StreamContent(context.Request.Body);
requestMessage.Content = streamContent;
}
foreach (var header in context.Request.Headers)
{
requestMessage.Content?.Headers.TryAddWithoutValidation(header.Key, header.Value.ToArray());
}
}
private void CopyFromTargetResponseHeaders(HttpContext context, HttpResponseMessage responseMessage)
{
foreach (var header in responseMessage.Headers)
{
context.Response.Headers[header.Key] = header.Value.ToArray();
}
foreach (var header in responseMessage.Content.Headers)
{
context.Response.Headers[header.Key] = header.Value.ToArray();
}
context.Response.Headers.Remove("transfer-encoding");
}
private static HttpMethod GetMethod(string method)
{
if (HttpMethods.IsDelete(method)) return HttpMethod.Delete;
if (HttpMethods.IsGet(method)) return HttpMethod.Get;
if (HttpMethods.IsHead(method)) return HttpMethod.Head;
if (HttpMethods.IsOptions(method)) return HttpMethod.Options;
if (HttpMethods.IsPost(method)) return HttpMethod.Post;
if (HttpMethods.IsPut(method)) return HttpMethod.Put;
if (HttpMethods.IsTrace(method)) return HttpMethod.Trace;
return new HttpMethod(method);
}
private Uri BuildTargetUri(HttpRequest request)
{
Uri targetUri = null;
//PathString remainingPath;
/*
if (request.Path.StartsWithSegments("/googleforms", out remainingPath))
{
targetUri = new Uri("https://docs.google.com/forms" + remainingPath);
}
if (request.Path.StartsWithSegments("/google", out remainingPath))
{
targetUri = new Uri("https://www.google.com" + remainingPath);
}
if (request.Path.StartsWithSegments("/googlestatic", out remainingPath))
{
targetUri = new Uri(" https://www.gstatic.com" + remainingPath);
}
*/
if (!request.Query["url"].Any())
return targetUri;
else
return new Uri(Uri.UnescapeDataString(request.Query["url"].ToString()));
}
}
}

View File

@@ -0,0 +1,43 @@
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace CloudFlareReverseProxy
{
public class Startup
{
// 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)
{
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
//app.UseRouting();
app.UseMiddleware<ReverseProxyMiddleware>();
/*
app.UseEndpoints(endpoints =>
{
endpoints.MapGet("/", async context =>
{
await context.Response.WriteAsync("Hello World!");
});
});
*/
}
}
}

View File

@@ -0,0 +1,9 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
}
}

View File

@@ -0,0 +1,11 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"AllowedHosts": "*",
"FlareSolverrApiUrl": "http://basilisk.chrispr.lan:8191"
}