mirror of
https://github.com/FastTunnel/FastTunnel.git
synced 2025-02-08 10:59:31 +08:00
1
This commit is contained in:
parent
0b93061e2a
commit
98ecb29407
|
@ -27,7 +27,7 @@
|
||||||
// [必选] 内网站点所在内网的ip
|
// [必选] 内网站点所在内网的ip
|
||||||
"LocalIp": "127.0.0.1",
|
"LocalIp": "127.0.0.1",
|
||||||
// [必选] 内网站点监听的端口号
|
// [必选] 内网站点监听的端口号
|
||||||
"LocalPort": 8080,
|
"LocalPort": 8090,
|
||||||
|
|
||||||
// [必选] 子域名, 访问本站点时的url为 http://${SubDomain}.${WebDomain}:${ServerPort}
|
// [必选] 子域名, 访问本站点时的url为 http://${SubDomain}.${WebDomain}:${ServerPort}
|
||||||
"SubDomain": "test"
|
"SubDomain": "test"
|
||||||
|
|
|
@ -4,6 +4,9 @@
|
||||||
<PackageReadmeFile>README.md</PackageReadmeFile>
|
<PackageReadmeFile>README.md</PackageReadmeFile>
|
||||||
<TargetFrameworks>net6.0;net7.0</TargetFrameworks>
|
<TargetFrameworks>net6.0;net7.0</TargetFrameworks>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Remove="Forwarder\Kestrel\FastTunnelConnectionContext.cs" />
|
||||||
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<FrameworkReference Include="Microsoft.AspNetCore.App" />
|
<FrameworkReference Include="Microsoft.AspNetCore.App" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
|
@ -8,59 +8,43 @@ using System;
|
||||||
using System.Buffers;
|
using System.Buffers;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO.Pipelines;
|
using System.IO.Pipelines;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection.PortableExecutable;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using FastTunnel.Core.Models;
|
using FastTunnel.Core.Models;
|
||||||
using FastTunnel.Core.Protocol;
|
using FastTunnel.Core.Protocol;
|
||||||
using FastTunnel.Core.Server;
|
using FastTunnel.Core.Server;
|
||||||
using Microsoft.AspNetCore.Connections;
|
using Microsoft.AspNetCore.Connections;
|
||||||
using Microsoft.AspNetCore.Http.Features;
|
using Microsoft.Extensions.FileSystemGlobbing;
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
|
|
||||||
namespace FastTunnel.Core.Forwarder.Kestrel;
|
namespace FastTunnel.Core.Forwarder.Kestrel.MiddleWare;
|
||||||
internal class FastTunnelConnectionContext : ConnectionContext
|
|
||||||
|
public class FastTunelProtocol
|
||||||
{
|
{
|
||||||
private readonly ConnectionContext _inner;
|
public FastTunelProtocol(ConnectionContext context, FastTunnelServer fastTunnelServer)
|
||||||
private readonly FastTunnelServer fastTunnelServer;
|
|
||||||
private readonly ILogger _logger;
|
|
||||||
|
|
||||||
public FastTunnelConnectionContext(ConnectionContext context, FastTunnelServer fastTunnelServer, ILogger logger)
|
|
||||||
{
|
{
|
||||||
|
this.context = context;
|
||||||
this.fastTunnelServer = fastTunnelServer;
|
this.fastTunnelServer = fastTunnelServer;
|
||||||
this._inner = context;
|
|
||||||
this._logger = logger;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override IDuplexPipe Transport { get => _inner.Transport; set => _inner.Transport = value; }
|
bool IsFastTunnel => Method == ProtocolConst.HTTP_METHOD_SWAP || MatchWeb != null;
|
||||||
|
|
||||||
public override string ConnectionId { get => _inner.ConnectionId; set => _inner.ConnectionId = value; }
|
|
||||||
|
|
||||||
public override IFeatureCollection Features => _inner.Features;
|
|
||||||
|
|
||||||
public override IDictionary<object, object> Items { get => _inner.Items; set => _inner.Items = value; }
|
|
||||||
|
|
||||||
public bool IsFastTunnel => Method == ProtocolConst.HTTP_METHOD_SWAP || MatchWeb != null;
|
|
||||||
|
|
||||||
public WebInfo MatchWeb { get; private set; }
|
public WebInfo MatchWeb { get; private set; }
|
||||||
|
|
||||||
public override ValueTask DisposeAsync()
|
ConnectionContext context { get; }
|
||||||
{
|
|
||||||
return _inner.DisposeAsync();
|
IDuplexPipe Transport => context.Transport;
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 解析FastTunnel协议
|
|
||||||
/// </summary>
|
|
||||||
internal async Task TryAnalysisPipeAsync()
|
internal async Task TryAnalysisPipeAsync()
|
||||||
{
|
{
|
||||||
var reader = Transport.Input;
|
var _input = Transport.Input;
|
||||||
|
|
||||||
ReadResult result;
|
ReadResult result;
|
||||||
ReadOnlySequence<byte> readableBuffer;
|
ReadOnlySequence<byte> readableBuffer;
|
||||||
|
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
result = await reader.ReadAsync();
|
result = await _input.ReadAsync();
|
||||||
var tempBuffer = readableBuffer = result.Buffer;
|
var tempBuffer = readableBuffer = result.Buffer;
|
||||||
|
|
||||||
SequencePosition? position = null;
|
SequencePosition? position = null;
|
||||||
|
@ -72,17 +56,28 @@ internal class FastTunnelConnectionContext : ConnectionContext
|
||||||
if (position != null)
|
if (position != null)
|
||||||
{
|
{
|
||||||
var readedPosition = readableBuffer.GetPosition(1, position.Value);
|
var readedPosition = readableBuffer.GetPosition(1, position.Value);
|
||||||
if (ProcessLine(tempBuffer.Slice(0, position.Value)))
|
if (ProcessLine(tempBuffer.Slice(0, position.Value), out string line))
|
||||||
{
|
{
|
||||||
if (Method == ProtocolConst.HTTP_METHOD_SWAP)
|
if (Method == ProtocolConst.HTTP_METHOD_SWAP)
|
||||||
{
|
{
|
||||||
reader.AdvanceTo(readedPosition, readedPosition);
|
_input.AdvanceTo(readedPosition, readedPosition);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
reader.AdvanceTo(readableBuffer.Start, readableBuffer.Start);
|
_input.AdvanceTo(readableBuffer.Start, readableBuffer.Start);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (IsFastTunnel)
|
||||||
|
{
|
||||||
|
context.Features.Set<IFastTunnelFeature>(new FastTunnelFeature()
|
||||||
|
{
|
||||||
|
MatchWeb = MatchWeb,
|
||||||
|
HasReadLInes = HasReadLInes,
|
||||||
|
Method = Method,
|
||||||
|
Host = Host,
|
||||||
|
MessageId = MessageId,
|
||||||
|
});
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -93,12 +88,10 @@ internal class FastTunnelConnectionContext : ConnectionContext
|
||||||
|
|
||||||
if (result.IsCompleted)
|
if (result.IsCompleted)
|
||||||
{
|
{
|
||||||
reader.AdvanceTo(readableBuffer.End, readableBuffer.End);
|
_input.AdvanceTo(readableBuffer.End, readableBuffer.End);
|
||||||
break;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public string Method;
|
public string Method;
|
||||||
|
@ -107,6 +100,7 @@ internal class FastTunnelConnectionContext : ConnectionContext
|
||||||
private bool isFirstLine = true;
|
private bool isFirstLine = true;
|
||||||
|
|
||||||
public IList<string> HasReadLInes { get; private set; } = new List<string>();
|
public IList<string> HasReadLInes { get; private set; } = new List<string>();
|
||||||
|
public FastTunnelServer fastTunnelServer { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
///
|
||||||
|
@ -122,9 +116,9 @@ internal class FastTunnelConnectionContext : ConnectionContext
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="readOnlySequence"></param>
|
/// <param name="readOnlySequence"></param>
|
||||||
/// <returns>Header读取完毕?</returns>
|
/// <returns>Header读取完毕?</returns>
|
||||||
private bool ProcessLine(ReadOnlySequence<byte> readOnlySequence)
|
private bool ProcessLine(ReadOnlySequence<byte> readOnlySequence, out string lineStr)
|
||||||
{
|
{
|
||||||
var lineStr = Encoding.UTF8.GetString(readOnlySequence);
|
lineStr = Encoding.UTF8.GetString(readOnlySequence);
|
||||||
HasReadLInes.Add(lineStr);
|
HasReadLInes.Add(lineStr);
|
||||||
|
|
||||||
if (isFirstLine)
|
if (isFirstLine)
|
|
@ -0,0 +1,24 @@
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License").
|
||||||
|
// You may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
// https://github.com/FastTunnel/FastTunnel/edit/v2/LICENSE
|
||||||
|
// Copyright (c) 2019 Gui.H
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using FastTunnel.Core.Models;
|
||||||
|
|
||||||
|
namespace FastTunnel.Core.Forwarder.Kestrel.MiddleWare;
|
||||||
|
|
||||||
|
public class FastTunnelFeature : IFastTunnelFeature
|
||||||
|
{
|
||||||
|
public WebInfo MatchWeb { get; set; }
|
||||||
|
|
||||||
|
public IList<string> HasReadLInes { get; set; }
|
||||||
|
public string Method { get; set; }
|
||||||
|
public string Host { get; set; }
|
||||||
|
public string MessageId { get; set; }
|
||||||
|
}
|
|
@ -41,35 +41,45 @@ internal class ForwarderMiddleware
|
||||||
|
|
||||||
internal async Task OnConnectionAsync(ConnectionContext context)
|
internal async Task OnConnectionAsync(ConnectionContext context)
|
||||||
{
|
{
|
||||||
var ctx = context as FastTunnelConnectionContext;
|
logger.LogInformation("=========ForwarderMiddleware SART===========");
|
||||||
if (ctx != null && ctx.IsFastTunnel)
|
|
||||||
|
var feat = context.Features.Get<IFastTunnelFeature>();
|
||||||
|
if (feat == null)
|
||||||
{
|
{
|
||||||
if (ctx.Method == ProtocolConst.HTTP_METHOD_SWAP)
|
logger.LogInformation("=========ForwarderMiddleware END===========");
|
||||||
|
// not fasttunnel request
|
||||||
|
await next(context);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
logger.LogInformation("=========Swap STRART===========");
|
||||||
|
if (feat.Method == ProtocolConst.HTTP_METHOD_SWAP)
|
||||||
{
|
{
|
||||||
await doSwap(ctx);
|
await doSwap(context);
|
||||||
}
|
}
|
||||||
else if (ctx.MatchWeb != null)
|
else if (feat.MatchWeb != null)
|
||||||
{
|
{
|
||||||
await waitSwap(ctx);
|
await waitSwap(context);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
throw new NotSupportedException();
|
throw new NotSupportedException();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else
|
logger.LogInformation("=========Swap END===========");
|
||||||
{
|
logger.LogInformation("=========ForwarderMiddleware END===========");
|
||||||
await next(context);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task waitSwap(FastTunnelConnectionContext context)
|
private async Task waitSwap(ConnectionContext context)
|
||||||
{
|
{
|
||||||
|
var feat = context.Features.Get<IFastTunnelFeature>();
|
||||||
var requestId = Guid.NewGuid().ToString().Replace("-", "");
|
var requestId = Guid.NewGuid().ToString().Replace("-", "");
|
||||||
var web = context.MatchWeb;
|
var web = feat.MatchWeb;
|
||||||
|
|
||||||
TaskCompletionSource<Stream> tcs = new();
|
TaskCompletionSource<Stream> tcs = new();
|
||||||
logger.LogDebug($"[Http]Swap开始 {requestId}|{context.Host}=>{web.WebConfig.LocalIp}:{web.WebConfig.LocalPort}");
|
logger.LogDebug($"[Http]Swap开始 {requestId}|{feat.Host}=>{web.WebConfig.LocalIp}:{web.WebConfig.LocalPort}");
|
||||||
tcs.SetTimeOut(10000, () => { logger.LogDebug($"[Proxy TimeOut]:{requestId}"); });
|
tcs.SetTimeOut(10000, () => { logger.LogDebug($"[Proxy TimeOut]:{requestId}"); });
|
||||||
|
|
||||||
fastTunnelServer.ResponseTasks.TryAdd(requestId, tcs);
|
fastTunnelServer.ResponseTasks.TryAdd(requestId, tcs);
|
||||||
|
@ -111,9 +121,10 @@ internal class ForwarderMiddleware
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task doSwap(FastTunnelConnectionContext context)
|
private async Task doSwap(ConnectionContext context)
|
||||||
{
|
{
|
||||||
var requestId = context.MessageId;
|
var feat = context.Features.Get<IFastTunnelFeature>();
|
||||||
|
var requestId = feat.MessageId;
|
||||||
if (!fastTunnelServer.ResponseTasks.TryRemove(requestId, out var responseStream))
|
if (!fastTunnelServer.ResponseTasks.TryRemove(requestId, out var responseStream))
|
||||||
{
|
{
|
||||||
throw new Exception($"[PROXY]:RequestId不存在 {requestId}");
|
throw new Exception($"[PROXY]:RequestId不存在 {requestId}");
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License").
|
||||||
|
// You may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
// https://github.com/FastTunnel/FastTunnel/edit/v2/LICENSE
|
||||||
|
// Copyright (c) 2019 Gui.H
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using FastTunnel.Core.Models;
|
||||||
|
using FastTunnel.Core.Protocol;
|
||||||
|
|
||||||
|
namespace FastTunnel.Core.Forwarder.Kestrel.MiddleWare;
|
||||||
|
|
||||||
|
internal interface IFastTunnelFeature
|
||||||
|
{
|
||||||
|
public WebInfo MatchWeb { get; set; }
|
||||||
|
|
||||||
|
public IList<string> HasReadLInes { get; set; }
|
||||||
|
|
||||||
|
public string Method { get; set; }
|
||||||
|
public string Host { get; set; }
|
||||||
|
public string MessageId { get; set; }
|
||||||
|
}
|
|
@ -30,11 +30,10 @@ internal class InitializerMiddleware
|
||||||
|
|
||||||
internal async Task OnConnectionAsync(ConnectionContext context)
|
internal async Task OnConnectionAsync(ConnectionContext context)
|
||||||
{
|
{
|
||||||
logger.LogInformation("=========OnConnectionAsync===========");
|
logger.LogInformation("=========TryAnalysisPipeAsync SART===========");
|
||||||
var ftContext = new FastTunnelConnectionContext(context, fastTunnelServer, logger);
|
await new FastTunelProtocol(context, fastTunnelServer).TryAnalysisPipeAsync();
|
||||||
await ftContext.TryAnalysisPipeAsync();
|
|
||||||
|
|
||||||
logger.LogInformation("=========TryAnalysisPipeAsync END===========");
|
logger.LogInformation("=========TryAnalysisPipeAsync END===========");
|
||||||
await next(ftContext.IsFastTunnel ? ftContext : context);
|
|
||||||
|
await next(context);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,9 +31,9 @@ public class FastTunnelHostingStartup : IHostingStartup
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
builder.Configure((webHostBuilderContext, app) =>
|
//builder.Configure((webHostBuilderContext, app) =>
|
||||||
{
|
//{
|
||||||
app.UseFastTunnelServer();
|
// app.UseFastTunnelServer();
|
||||||
});
|
//});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -102,9 +102,15 @@ public class Startup
|
||||||
app.UseAuthorization();
|
app.UseAuthorization();
|
||||||
// --------------------- Custom UI ----------------
|
// --------------------- Custom UI ----------------
|
||||||
|
|
||||||
|
app.UseFastTunnelServer();
|
||||||
|
|
||||||
app.UseEndpoints(endpoints =>
|
app.UseEndpoints(endpoints =>
|
||||||
{
|
{
|
||||||
endpoints.MapControllers();
|
endpoints.MapControllers();
|
||||||
|
endpoints.MapFallback(async (HttpContext ctx) =>
|
||||||
|
{
|
||||||
|
await ctx.Response.Body.WriteAsync(Encoding.UTF8.GetBytes("hello~"));
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user