mirror of
https://github.com/FastTunnel/FastTunnel.git
synced 2025-02-08 02:39:29 +08:00
优化离线后的响应报文
This commit is contained in:
parent
970b5ca8de
commit
e47c97da0e
|
@ -1,6 +1,7 @@
|
|||
using FastTunnel.Core.Client;
|
||||
using FastTunnel.Core.Extensions;
|
||||
using FastTunnel.Core.Models;
|
||||
using FastTunnel.Core.Sockets;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
|
@ -48,12 +49,13 @@ namespace FastTunnel.Core.Forwarder
|
|||
}
|
||||
}
|
||||
|
||||
public async ValueTask<Stream> proxyAsync(string host, CancellationToken cancellation)
|
||||
public async ValueTask<Stream> proxyAsync(string host, SocketsHttpConnectionContext context, CancellationToken cancellation)
|
||||
{
|
||||
WebInfo web;
|
||||
if (!_fastTunnelServer.WebList.TryGetValue(host, out web))
|
||||
{
|
||||
throw new Exception($"站点未登录:{host}");
|
||||
// 客户端已离线
|
||||
return await OfflinePage(host, context);
|
||||
}
|
||||
|
||||
try
|
||||
|
@ -82,5 +84,13 @@ namespace FastTunnel.Core.Forwarder
|
|||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
private async ValueTask<Stream> OfflinePage(string host, SocketsHttpConnectionContext context)
|
||||
{
|
||||
var bytes = Encoding.UTF8.GetBytes(
|
||||
$"HTTP/1.1 200 OK\r\nContent-Type:text/html; charset=utf-8\r\n\r\n{TunnelResource.Page_Offline}\r\n");
|
||||
|
||||
return await Task.FromResult(new ResponseStream(bytes));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
63
FastTunnel.Core/Forwarder/ResponseStream.cs
Normal file
63
FastTunnel.Core/Forwarder/ResponseStream.cs
Normal file
|
@ -0,0 +1,63 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace FastTunnel.Core.Forwarder
|
||||
{
|
||||
public class ResponseStream : Stream
|
||||
{
|
||||
public override bool CanRead => true;
|
||||
|
||||
public override bool CanSeek => false;
|
||||
|
||||
public override bool CanWrite => true;
|
||||
|
||||
public override long Length => throw new NotImplementedException();
|
||||
|
||||
public override long Position { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
|
||||
|
||||
MemoryStream m_Stream;
|
||||
|
||||
public ResponseStream(byte[] bytes)
|
||||
{
|
||||
m_Stream = new MemoryStream(bytes);
|
||||
}
|
||||
|
||||
public override void Flush()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
bool complete = false;
|
||||
|
||||
public override int Read(byte[] buffer, int offset, int count)
|
||||
{
|
||||
if (!complete)
|
||||
{
|
||||
return 0;
|
||||
};
|
||||
|
||||
var len = m_Stream.Read(buffer, offset, count);
|
||||
return len;
|
||||
}
|
||||
|
||||
public override long Seek(long offset, SeekOrigin origin)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override void SetLength(long value)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override void Write(byte[] buffer, int offset, int count)
|
||||
{
|
||||
Console.Write(Encoding.UTF8.GetString(buffer, offset, count));
|
||||
complete = true;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,157 +0,0 @@
|
|||
using FastTunnel.Core.Dispatchers;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net.Sockets;
|
||||
using System.Runtime.ExceptionServices;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace FastTunnel.Core.Sockets
|
||||
{
|
||||
/// <summary>
|
||||
/// 异步数据交换
|
||||
/// 存在大文件下载时,导致栈溢出的问题
|
||||
/// </summary>
|
||||
public class AsyncSocketSwap : ISocketSwap
|
||||
{
|
||||
private Socket m_sockt1;
|
||||
private Socket m_sockt2;
|
||||
bool m_swaping = false;
|
||||
|
||||
byte[] m_buffer = new byte[1024];
|
||||
SocketAsyncEventArgs e1;
|
||||
SocketAsyncEventArgs e2;
|
||||
|
||||
public AsyncSocketSwap(Socket sockt1, Socket sockt2)
|
||||
{
|
||||
m_sockt1 = sockt1;
|
||||
m_sockt2 = sockt2;
|
||||
|
||||
e1 = new SocketAsyncEventArgs();
|
||||
e2 = new SocketAsyncEventArgs();
|
||||
|
||||
e1.Completed += IO_Completed;
|
||||
e2.Completed += IO_Completed;
|
||||
e1.UserToken = new SwapUserToken { Reciver = m_sockt1, Sender = m_sockt2 };
|
||||
e2.UserToken = new SwapUserToken { Reciver = m_sockt2, Sender = m_sockt1 };
|
||||
|
||||
e1.SetBuffer(m_buffer, 0, 512);
|
||||
e2.SetBuffer(m_buffer, 512, 512);
|
||||
}
|
||||
|
||||
public ISocketSwap BeforeSwap(Action fun)
|
||||
{
|
||||
if (m_swaping)
|
||||
throw new Exception("BeforeSwap must be invoked before StartSwap!");
|
||||
|
||||
fun?.Invoke();
|
||||
return this;
|
||||
}
|
||||
|
||||
public Task StartSwapAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
Console.WriteLine("StartSwapAsync");
|
||||
m_swaping = true;
|
||||
|
||||
if (!m_sockt1.ReceiveAsync(e1))
|
||||
{
|
||||
ProcessReceive(e1);
|
||||
}
|
||||
|
||||
if (!m_sockt2.ReceiveAsync(e2))
|
||||
{
|
||||
ProcessReceive(e2);
|
||||
}
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine(ex.ToString());
|
||||
ExceptionDispatchInfo.Capture(ex).Throw();
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
|
||||
private void IO_Completed(object sender, SocketAsyncEventArgs e)
|
||||
{
|
||||
switch (e.LastOperation)
|
||||
{
|
||||
case SocketAsyncOperation.Receive:
|
||||
ProcessReceive(e);
|
||||
break;
|
||||
case SocketAsyncOperation.Send:
|
||||
ProcessSend(e);
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentException("The last operation completed on the socket was not a receive or send");
|
||||
}
|
||||
}
|
||||
|
||||
private void ProcessReceive(SocketAsyncEventArgs e)
|
||||
{
|
||||
var token = e.UserToken as SwapUserToken;
|
||||
if (e.BytesTransferred > 0 && e.SocketError == SocketError.Success)
|
||||
{
|
||||
e.SetBuffer(e.Offset, 512);
|
||||
if (!token.Sender.SendAsync(e))
|
||||
{
|
||||
ProcessSend(e);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// close
|
||||
CloseSocket(token.Reciver);
|
||||
}
|
||||
}
|
||||
|
||||
private void ProcessSend(SocketAsyncEventArgs e)
|
||||
{
|
||||
var token = e.UserToken as SwapUserToken;
|
||||
if (e.SocketError == SocketError.Success)
|
||||
{
|
||||
Console.WriteLine("ProcessSend:" + e.BytesTransferred);
|
||||
|
||||
if (!token.Reciver.ReceiveAsync(e))
|
||||
{
|
||||
e.SetBuffer(e.Offset, 512);
|
||||
ProcessReceive(e);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
CloseSocket(token.Sender);
|
||||
}
|
||||
}
|
||||
|
||||
private void CloseSocket(Socket socket)
|
||||
{
|
||||
try
|
||||
{
|
||||
Console.WriteLine("CloseSocket");
|
||||
|
||||
try
|
||||
{
|
||||
socket.Shutdown(SocketShutdown.Send);
|
||||
}
|
||||
catch (Exception) { }
|
||||
socket.Close();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine(ex);
|
||||
}
|
||||
}
|
||||
|
||||
public class SwapUserToken
|
||||
{
|
||||
public Socket Reciver { get; set; }
|
||||
|
||||
public Socket Sender { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
74
FastTunnel.Core/TunnelResource.Designer.cs
generated
74
FastTunnel.Core/TunnelResource.Designer.cs
generated
|
@ -1,10 +1,10 @@
|
|||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// 此代码由工具生成。
|
||||
// 运行时版本:4.0.30319.42000
|
||||
// This code was generated by a tool.
|
||||
// Runtime Version:4.0.30319.42000
|
||||
//
|
||||
// 对此文件的更改可能会导致不正确的行为,并且如果
|
||||
// 重新生成代码,这些更改将会丢失。
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
// </auto-generated>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
@ -13,12 +13,12 @@ namespace FastTunnel.Core {
|
|||
|
||||
|
||||
/// <summary>
|
||||
/// 一个强类型的资源类,用于查找本地化的字符串等。
|
||||
/// A strongly-typed resource class, for looking up localized strings, etc.
|
||||
/// </summary>
|
||||
// 此类是由 StronglyTypedResourceBuilder
|
||||
// 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。
|
||||
// 若要添加或移除成员,请编辑 .ResX 文件,然后重新运行 ResGen
|
||||
// (以 /str 作为命令选项),或重新生成 VS 项目。
|
||||
// This class was auto-generated by the StronglyTypedResourceBuilder
|
||||
// class via a tool like ResGen or Visual Studio.
|
||||
// To add or remove a member, edit your .ResX file then rerun ResGen
|
||||
// with the /str option, or rebuild your VS project.
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||
|
@ -33,7 +33,7 @@ namespace FastTunnel.Core {
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// 返回此类使用的缓存的 ResourceManager 实例。
|
||||
/// Returns the cached ResourceManager instance used by this class.
|
||||
/// </summary>
|
||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
internal static global::System.Resources.ResourceManager ResourceManager {
|
||||
|
@ -47,8 +47,8 @@ namespace FastTunnel.Core {
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// 重写当前线程的 CurrentUICulture 属性,对
|
||||
/// 使用此强类型资源类的所有资源查找执行重写。
|
||||
/// Overrides the current thread's CurrentUICulture property for all
|
||||
/// resource lookups using this strongly typed resource class.
|
||||
/// </summary>
|
||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
internal static global::System.Globalization.CultureInfo Culture {
|
||||
|
@ -61,7 +61,7 @@ namespace FastTunnel.Core {
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 服务端禁用了Forward 的本地化字符串。
|
||||
/// Looks up a localized string similar to 服务端禁用了Forward.
|
||||
/// </summary>
|
||||
internal static string ForwardDisabled {
|
||||
get {
|
||||
|
@ -70,7 +70,7 @@ namespace FastTunnel.Core {
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 您尚未创建任何隧道,请登录https://suidao.io 创建后重试。 的本地化字符串。
|
||||
/// Looks up a localized string similar to 您尚未创建任何隧道,请登录https://suidao.io 创建后重试。.
|
||||
/// </summary>
|
||||
internal static string NoTunnel {
|
||||
get {
|
||||
|
@ -79,7 +79,7 @@ namespace FastTunnel.Core {
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 <!DOCTYPE html>
|
||||
/// Looks up a localized string similar to <!DOCTYPE html>
|
||||
///<html lang="en">
|
||||
///
|
||||
///<head>
|
||||
|
@ -99,7 +99,7 @@ namespace FastTunnel.Core {
|
|||
///
|
||||
/// .btn-primary {
|
||||
/// color: #fff;
|
||||
/// background-color [字符串的其余部分被截断]"; 的本地化字符串。
|
||||
/// background-color [rest of string was truncated]";.
|
||||
/// </summary>
|
||||
internal static string Page_HostRequired {
|
||||
get {
|
||||
|
@ -108,7 +108,7 @@ namespace FastTunnel.Core {
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 <!DOCTYPE html>
|
||||
/// Looks up a localized string similar to <!DOCTYPE html>
|
||||
///<html lang="en">
|
||||
///<head>
|
||||
/// <meta charset="utf-8" />
|
||||
|
@ -127,7 +127,7 @@ namespace FastTunnel.Core {
|
|||
///
|
||||
/// .btn-primary {
|
||||
/// color: #fff;
|
||||
/// background-color: [字符串的其余部分被截断]"; 的本地化字符串。
|
||||
/// background-color: [rest of string was truncated]";.
|
||||
/// </summary>
|
||||
internal static string Page_NoSite {
|
||||
get {
|
||||
|
@ -136,7 +136,7 @@ namespace FastTunnel.Core {
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 <!DOCTYPE html>
|
||||
/// Looks up a localized string similar to <!DOCTYPE html>
|
||||
///<html lang="en">
|
||||
///
|
||||
///<head>
|
||||
|
@ -156,7 +156,7 @@ namespace FastTunnel.Core {
|
|||
///
|
||||
/// .btn-primary {
|
||||
/// color: #fff;
|
||||
/// background-color [字符串的其余部分被截断]"; 的本地化字符串。
|
||||
/// background-color [rest of string was truncated]";.
|
||||
/// </summary>
|
||||
internal static string Page_NotAccessIps {
|
||||
get {
|
||||
|
@ -165,7 +165,7 @@ namespace FastTunnel.Core {
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 <!DOCTYPE html>
|
||||
/// Looks up a localized string similar to <!DOCTYPE html>
|
||||
///<html lang="en">
|
||||
///
|
||||
///<head>
|
||||
|
@ -185,16 +185,42 @@ namespace FastTunnel.Core {
|
|||
///
|
||||
/// .btn-primary {
|
||||
/// color: #fff;
|
||||
/// background-color [字符串的其余部分被截断]"; 的本地化字符串。
|
||||
/// background-color [rest of string was truncated]";.
|
||||
/// </summary>
|
||||
internal static string Page_NoTunnel {
|
||||
internal static string Page_Offline {
|
||||
get {
|
||||
return ResourceManager.GetString("Page_NoTunnel", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 \n=====隧道已建立成功,现在可以通过以下方式访问您的内网服务了=====\n{0}\n 的本地化字符串。
|
||||
/// Looks up a localized string similar to HTTP/1.1 200 OK
|
||||
///Date: Sat, 21 Aug 2021 15:14:17 GMT
|
||||
///Content-Type: text/html; charset=utf-8
|
||||
///Server: Microsoft-IIS/10.0
|
||||
///X-Powered-By: ASP.NET
|
||||
///Content-Length: 3026
|
||||
///
|
||||
///<!DOCTYPE html>
|
||||
///<html lang="en">
|
||||
///<head>
|
||||
/// <meta charset="utf-8" />
|
||||
/// <meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
/// <title> - BX.SignalR</title>
|
||||
/// <link rel="stylesheet" href="/lib/bootstrap/dist/css/bootstrap.min.css" />
|
||||
/// <link rel="stylesheet" href="/css/site.css" />
|
||||
///</head>
|
||||
///<body>
|
||||
/// <head [rest of string was truncated]";.
|
||||
/// </summary>
|
||||
internal static string Test {
|
||||
get {
|
||||
return ResourceManager.GetString("Test", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to \n=====隧道已建立成功,现在可以通过以下方式访问您的内网服务了=====\n{0}\n.
|
||||
/// </summary>
|
||||
internal static string TunnelLlist {
|
||||
get {
|
||||
|
|
|
@ -588,6 +588,93 @@
|
|||
</html></value>
|
||||
<comment>客户端未登录</comment>
|
||||
</data>
|
||||
<data name="Test" xml:space="preserve">
|
||||
<value>HTTP/1.1 200 OK
|
||||
Date: Sat, 21 Aug 2021 15:14:17 GMT
|
||||
Content-Type: text/html; charset=utf-8
|
||||
Server: Microsoft-IIS/10.0
|
||||
X-Powered-By: ASP.NET
|
||||
Content-Length: 3026
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title> - BX.SignalR</title>
|
||||
<link rel="stylesheet" href="/lib/bootstrap/dist/css/bootstrap.min.css" />
|
||||
<link rel="stylesheet" href="/css/site.css" />
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<nav class="navbar navbar-expand-sm navbar-toggleable-sm navbar-light bg-white border-bottom box-shadow mb-3">
|
||||
<div class="container">
|
||||
<a class="navbar-brand" href="/">BX.SignalR</a>
|
||||
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target=".navbar-collapse" aria-controls="navbarSupportedContent"
|
||||
aria-expanded="false" aria-label="Toggle navigation">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div class="navbar-collapse collapse d-sm-inline-flex justify-content-between">
|
||||
<ul class="navbar-nav flex-grow-1">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link text-dark" href="/">Home</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link text-dark" href="/Privacy">Privacy</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
</header>
|
||||
<div class="container">
|
||||
<main role="main" class="pb-3">
|
||||
<div class="container">
|
||||
<div class="row">&nbsp;</div>
|
||||
<div class="row">
|
||||
<div class="col-2">User</div>
|
||||
<div class="col-4"><input type="text" id="userInput" /></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-2">Message</div>
|
||||
<div class="col-4"><input type="text" id="messageInput" /></div>
|
||||
</div>
|
||||
<div class="row">&nbsp;</div>
|
||||
<div class="row">
|
||||
<div class="col-6">
|
||||
<input type="button" id="sendButton" value="Send Message" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<hr />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-6">
|
||||
<ul id="messagesList"></ul>
|
||||
</div>
|
||||
</div>
|
||||
<script src="/js/signalr/dist/browser/signalr.js"></script>
|
||||
<script src="/js/chat.js"></script>
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<footer class="border-top footer text-muted">
|
||||
<div class="container">
|
||||
&copy; 2020 - BX.SignalR - <a href="/Privacy">Privacy</a>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<script src="/lib/jquery/dist/jquery.min.js"></script>
|
||||
<script src="/lib/bootstrap/dist/js/bootstrap.bundle.min.js"></script>
|
||||
<script src="/js/site.js?v=4q1jwFhaPaZgr8WAUSrux6hAuh0XDg9kPS3xIVq36I0"></script>
|
||||
|
||||
|
||||
<script src="/_framework/aspnetcore-browser-refresh.js"></script></body>
|
||||
</html></value>
|
||||
</data>
|
||||
<data name="TunnelLlist" xml:space="preserve">
|
||||
<value>\n=====隧道已建立成功,现在可以通过以下方式访问您的内网服务了=====\n{0}\n</value>
|
||||
</data>
|
||||
|
|
Loading…
Reference in New Issue
Block a user