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
|
||||
"LocalIp": "127.0.0.1",
|
||||
// [必选] 内网站点监听的端口号
|
||||
"LocalPort": 8080,
|
||||
"LocalPort": 8090,
|
||||
|
||||
// [必选] 子域名, 访问本站点时的url为 http://${SubDomain}.${WebDomain}:${ServerPort}
|
||||
"SubDomain": "test"
|
||||
|
|
|
@ -4,6 +4,9 @@
|
|||
<PackageReadmeFile>README.md</PackageReadmeFile>
|
||||
<TargetFrameworks>net6.0;net7.0</TargetFrameworks>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Compile Remove="Forwarder\Kestrel\FastTunnelConnectionContext.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<FrameworkReference Include="Microsoft.AspNetCore.App" />
|
||||
</ItemGroup>
|
||||
|
|
|
@ -8,59 +8,43 @@ using System;
|
|||
using System.Buffers;
|
||||
using System.Collections.Generic;
|
||||
using System.IO.Pipelines;
|
||||
using System.Linq;
|
||||
using System.Reflection.PortableExecutable;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using FastTunnel.Core.Models;
|
||||
using FastTunnel.Core.Protocol;
|
||||
using FastTunnel.Core.Server;
|
||||
using Microsoft.AspNetCore.Connections;
|
||||
using Microsoft.AspNetCore.Http.Features;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.FileSystemGlobbing;
|
||||
|
||||
namespace FastTunnel.Core.Forwarder.Kestrel;
|
||||
internal class FastTunnelConnectionContext : ConnectionContext
|
||||
namespace FastTunnel.Core.Forwarder.Kestrel.MiddleWare;
|
||||
|
||||
public class FastTunelProtocol
|
||||
{
|
||||
private readonly ConnectionContext _inner;
|
||||
private readonly FastTunnelServer fastTunnelServer;
|
||||
private readonly ILogger _logger;
|
||||
|
||||
public FastTunnelConnectionContext(ConnectionContext context, FastTunnelServer fastTunnelServer, ILogger logger)
|
||||
public FastTunelProtocol(ConnectionContext context, FastTunnelServer fastTunnelServer)
|
||||
{
|
||||
this.context = context;
|
||||
this.fastTunnelServer = fastTunnelServer;
|
||||
this._inner = context;
|
||||
this._logger = logger;
|
||||
}
|
||||
|
||||
public override IDuplexPipe Transport { get => _inner.Transport; set => _inner.Transport = value; }
|
||||
|
||||
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;
|
||||
bool IsFastTunnel => Method == ProtocolConst.HTTP_METHOD_SWAP || MatchWeb != null;
|
||||
|
||||
public WebInfo MatchWeb { get; private set; }
|
||||
|
||||
public override ValueTask DisposeAsync()
|
||||
{
|
||||
return _inner.DisposeAsync();
|
||||
}
|
||||
ConnectionContext context { get; }
|
||||
|
||||
IDuplexPipe Transport => context.Transport;
|
||||
|
||||
/// <summary>
|
||||
/// 解析FastTunnel协议
|
||||
/// </summary>
|
||||
internal async Task TryAnalysisPipeAsync()
|
||||
{
|
||||
var reader = Transport.Input;
|
||||
var _input = Transport.Input;
|
||||
|
||||
ReadResult result;
|
||||
ReadOnlySequence<byte> readableBuffer;
|
||||
|
||||
while (true)
|
||||
{
|
||||
result = await reader.ReadAsync();
|
||||
result = await _input.ReadAsync();
|
||||
var tempBuffer = readableBuffer = result.Buffer;
|
||||
|
||||
SequencePosition? position = null;
|
||||
|
@ -72,17 +56,28 @@ internal class FastTunnelConnectionContext : ConnectionContext
|
|||
if (position != null)
|
||||
{
|
||||
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)
|
||||
{
|
||||
reader.AdvanceTo(readedPosition, readedPosition);
|
||||
_input.AdvanceTo(readedPosition, readedPosition);
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -93,13 +88,11 @@ internal class FastTunnelConnectionContext : ConnectionContext
|
|||
|
||||
if (result.IsCompleted)
|
||||
{
|
||||
reader.AdvanceTo(readableBuffer.End, readableBuffer.End);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
_input.AdvanceTo(readableBuffer.End, readableBuffer.End);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public string Method;
|
||||
public string Host = null;
|
||||
|
@ -107,6 +100,7 @@ internal class FastTunnelConnectionContext : ConnectionContext
|
|||
private bool isFirstLine = true;
|
||||
|
||||
public IList<string> HasReadLInes { get; private set; } = new List<string>();
|
||||
public FastTunnelServer fastTunnelServer { get; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
|
@ -122,9 +116,9 @@ internal class FastTunnelConnectionContext : ConnectionContext
|
|||
/// </summary>
|
||||
/// <param name="readOnlySequence"></param>
|
||||
/// <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);
|
||||
|
||||
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)
|
||||
{
|
||||
var ctx = context as FastTunnelConnectionContext;
|
||||
if (ctx != null && ctx.IsFastTunnel)
|
||||
logger.LogInformation("=========ForwarderMiddleware SART===========");
|
||||
|
||||
var feat = context.Features.Get<IFastTunnelFeature>();
|
||||
if (feat == null)
|
||||
{
|
||||
if (ctx.Method == ProtocolConst.HTTP_METHOD_SWAP)
|
||||
{
|
||||
await doSwap(ctx);
|
||||
logger.LogInformation("=========ForwarderMiddleware END===========");
|
||||
// not fasttunnel request
|
||||
await next(context);
|
||||
return;
|
||||
}
|
||||
else if (ctx.MatchWeb != null)
|
||||
else
|
||||
{
|
||||
await waitSwap(ctx);
|
||||
logger.LogInformation("=========Swap STRART===========");
|
||||
if (feat.Method == ProtocolConst.HTTP_METHOD_SWAP)
|
||||
{
|
||||
await doSwap(context);
|
||||
}
|
||||
else if (feat.MatchWeb != null)
|
||||
{
|
||||
await waitSwap(context);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
await next(context);
|
||||
|
||||
logger.LogInformation("=========Swap END===========");
|
||||
logger.LogInformation("=========ForwarderMiddleware END===========");
|
||||
}
|
||||
}
|
||||
|
||||
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 web = context.MatchWeb;
|
||||
var web = feat.MatchWeb;
|
||||
|
||||
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}"); });
|
||||
|
||||
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))
|
||||
{
|
||||
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)
|
||||
{
|
||||
logger.LogInformation("=========OnConnectionAsync===========");
|
||||
var ftContext = new FastTunnelConnectionContext(context, fastTunnelServer, logger);
|
||||
await ftContext.TryAnalysisPipeAsync();
|
||||
|
||||
logger.LogInformation("=========TryAnalysisPipeAsync SART===========");
|
||||
await new FastTunelProtocol(context, fastTunnelServer).TryAnalysisPipeAsync();
|
||||
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) =>
|
||||
{
|
||||
app.UseFastTunnelServer();
|
||||
});
|
||||
//builder.Configure((webHostBuilderContext, app) =>
|
||||
//{
|
||||
// app.UseFastTunnelServer();
|
||||
//});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -102,9 +102,15 @@ public class Startup
|
|||
app.UseAuthorization();
|
||||
// --------------------- Custom UI ----------------
|
||||
|
||||
app.UseFastTunnelServer();
|
||||
|
||||
app.UseEndpoints(endpoints =>
|
||||
{
|
||||
endpoints.MapControllers();
|
||||
endpoints.MapFallback(async (HttpContext ctx) =>
|
||||
{
|
||||
await ctx.Response.Body.WriteAsync(Encoding.UTF8.GetBytes("hello~"));
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user