建立连接异常显示请求体

This commit is contained in:
wanghongen
2023-09-06 22:13:33 +08:00
parent b3dae77271
commit 51cadcd39b
5 changed files with 69 additions and 37 deletions

View File

@@ -31,17 +31,20 @@ import 'handler.dart';
abstract class ChannelHandler<T> {
var log = logger;
///连接建立
void channelActive(Channel channel) {}
///读取数据事件
void channelRead(Channel channel, T msg) {}
///连接断开
void channelInactive(Channel channel) {
// log.i("close $channel");
}
void exceptionCaught(Channel channel, dynamic error, {StackTrace? trace}) {
HostAndPort? attribute = channel.getAttribute(AttributeKeys.host);
log.e("error $attribute $channel", error: error, stackTrace: trace);
log.e("[${channel.id}] error $attribute $channel", error: error, stackTrace: trace);
channel.close();
}
}
@@ -63,6 +66,8 @@ class Channel {
//是否写入中
bool isWriting = false;
Object? error; //异常
Channel(this._socket)
: _id = DateTime.now().millisecondsSinceEpoch + Random().nextInt(999999),
remoteAddress = _socket.remoteAddress,
@@ -80,7 +85,7 @@ class Channel {
Future<void> write(Object obj) async {
if (isClosed) {
logger.w("channel is closed $obj");
logger.w("[$id] channel is closed $obj");
return;
}
@@ -154,6 +159,7 @@ class ChannelPipeline extends ChannelHandler<Uint8List> {
this.handler = handler;
}
/// 监听
void listen(Channel channel) {
buffer.clear();
@@ -174,10 +180,10 @@ class ChannelPipeline extends ChannelHandler<Uint8List> {
remoteChannel.pipeline.handle(rawCodec, rawCodec, RelayHandler(clientChannel));
}
@override
void channelRead(Channel channel, Uint8List msg) {
try {
//手机扫码连接转发远程
HostAndPort? remote = channel.getAttribute(AttributeKeys.remote);
if (remote != null && channel.getAttribute(channel.id) != null) {
relay(channel, channel.getAttribute(channel.id));

View File

@@ -69,29 +69,14 @@ class HttpChannelHandler extends ChannelHandler<HttpRequest> {
@override
void exceptionCaught(Channel channel, error, {StackTrace? trace}) {
super.exceptionCaught(channel, error, trace: trace);
HostAndPort? hostAndPort = channel.getAttribute(AttributeKeys.host);
hostAndPort ??= HostAndPort.host(channel.remoteAddress.host, channel.remotePort);
String message = error.toString();
HttpStatus status = HttpStatus(-1, message);
if (error is HandshakeException) {
status = HttpStatus(-2, 'SSL握手失败');
} else if (error is ParserException) {
status = HttpStatus(-3, error.message);
} else if (error is SocketException) {
status = HttpStatus(-4, error.message);
}
HttpRequest request = HttpRequest(HttpMethod.connect, hostAndPort.domain)
..body = message.codeUnits
..hostAndPort = hostAndPort;
request.response = HttpResponse(status)..body = message.codeUnits;
listener?.onRequest(channel, request);
listener?.onResponse(channel, request.response!);
_exceptionHandler(channel, channel.getAttribute(AttributeKeys.request), error);
}
@override
void channelInactive(Channel channel) {
Channel? remoteChannel = channel.getAttribute(channel.id);
remoteChannel?.close();
// log.i("[${channel.id}] close ${channel.error}");
}
//请求本服务
@@ -118,11 +103,27 @@ class HttpChannelHandler extends ChannelHandler<HttpRequest> {
/// 转发请求
Future<void> forward(Channel channel, HttpRequest httpRequest) async {
// log.i("[${channel.id}] ${httpRequest.method.name} ${httpRequest.requestUrl}");
log.i("[${channel.id}] ${httpRequest.method.name} ${httpRequest.requestUrl}");
if (channel.error != null) {
_exceptionHandler(channel, httpRequest, channel.error);
return;
}
//获取远程连接
var remoteChannel = await _getRemoteChannel(channel, httpRequest);
remoteChannel.putAttribute(remoteChannel.id, channel);
Channel remoteChannel;
try {
remoteChannel = await _getRemoteChannel(channel, httpRequest);
remoteChannel.putAttribute(remoteChannel.id, channel);
} catch (error) {
channel.error = error; //记录异常
//https代理新建连接请求
if (httpRequest.method == HttpMethod.connect) {
await channel.write(
HttpResponse(HttpStatus.ok.reason('Connection established'), protocolVersion: httpRequest.protocolVersion));
}
return;
}
//实现抓包代理转发
if (httpRequest.method != HttpMethod.connect) {
@@ -140,6 +141,7 @@ class HttpChannelHandler extends ChannelHandler<HttpRequest> {
}
}
/// 下载证书
void _crtDownload(Channel channel, HttpRequest request) async {
const String fileMimeType = 'application/x-x509-ca-cert';
var response = HttpResponse(HttpStatus.ok);
@@ -192,9 +194,30 @@ class HttpChannelHandler extends ChannelHandler<HttpRequest> {
await clientChannel.write(
HttpResponse(HttpStatus.ok.reason('Connection established'), protocolVersion: httpRequest.protocolVersion));
}
return proxyChannel;
}
/// 异常处理
_exceptionHandler(Channel channel, HttpRequest? request, error) {
HostAndPort? hostAndPort = channel.getAttribute(AttributeKeys.host);
hostAndPort ??= HostAndPort.host(channel.remoteAddress.host, channel.remotePort);
String message = error.toString();
HttpStatus status = HttpStatus(-1, message);
if (error is HandshakeException) {
status = HttpStatus(-2, 'SSL握手失败');
} else if (error is ParserException) {
status = HttpStatus(-3, error.message);
} else if (error is SocketException) {
status = HttpStatus(-4, error.message);
}
request ??= HttpRequest(HttpMethod.connect, hostAndPort.domain)
..body = message.codeUnits
..hostAndPort = hostAndPort;
request.response = HttpResponse(status)..body = message.codeUnits;
listener?.onRequest(channel, request);
listener?.onResponse(channel, request.response!);
}
}
/// http响应代理

View File

@@ -48,11 +48,12 @@ class Network {
}
_onEvent(Uint8List data, Channel channel) async {
//手机扫码转发远程地址
if (configuration?.remoteHost != null) {
channel.putAttribute(AttributeKeys.remote, HostAndPort.of(configuration!.remoteHost!));
}
//代理信息
//外部代理信息
if (configuration?.externalProxy?.enabled == true) {
channel.putAttribute(AttributeKeys.proxyInfo, configuration!.externalProxy!);
}
@@ -79,12 +80,14 @@ class Network {
channel.pipeline.channelRead(channel, data);
}
/// ssl握手
void ssl(Channel channel, HostAndPort hostAndPort, Uint8List data) async {
try {
Channel remoteChannel = channel.getAttribute(channel.id);
remoteChannel.secureSocket = await SecureSocket.secure(remoteChannel.socket,
host: hostAndPort.host, onBadCertificate: (certificate) => true);
Channel? remoteChannel = channel.getAttribute(channel.id);
if (remoteChannel != null) {
remoteChannel.secureSocket = await SecureSocket.secure(remoteChannel.socket,
host: hostAndPort.host, onBadCertificate: (certificate) => true);
}
//ssl自签证书
var certificate = await CertificateManager.getCertificateContext(hostAndPort.host);
@@ -139,7 +142,7 @@ class Client extends Network {
host = host.substring(host.lastIndexOf(":") + 1, host.length - 1);
}
return Socket.connect(host, hostAndPort.port).then((socket) {
return Socket.connect(host, hostAndPort.port, timeout: const Duration(seconds: 3)).then((socket) {
if (socket.address.type != InternetAddressType.unix) {
socket.setOption(SocketOption.tcpNoDelay, true);
}

View File

@@ -482,18 +482,18 @@ packages:
dependency: "direct main"
description:
name: url_launcher
sha256: "781bd58a1eb16069412365c98597726cd8810ae27435f04b3b4d3a470bacd61e"
sha256: "47e208a6711459d813ba18af120d9663c20bdf6985d6ad39fe165d2538378d27"
url: "https://pub.flutter-io.cn"
source: hosted
version: "6.1.12"
version: "6.1.14"
url_launcher_android:
dependency: transitive
description:
name: url_launcher_android
sha256: "3dd2388cc0c42912eee04434531a26a82512b9cb1827e0214430c9bcbddfe025"
sha256: b04af59516ab45762b2ca6da40fa830d72d0f6045cd97744450b73493fa76330
url: "https://pub.flutter-io.cn"
source: hosted
version: "6.0.38"
version: "6.1.0"
url_launcher_ios:
dependency: transitive
description:
@@ -522,10 +522,10 @@ packages:
dependency: transitive
description:
name: url_launcher_platform_interface
sha256: bfdfa402f1f3298637d71ca8ecfe840b4696698213d5346e9d12d4ab647ee2ea
sha256: "95465b39f83bfe95fcb9d174829d6476216f2d548b79c38ab2506e0458787618"
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.1.3"
version: "2.1.5"
url_launcher_web:
dependency: transitive
description:

View File

@@ -21,7 +21,7 @@ dependencies:
url: https://gitee.com/wanghongenpin/flutter-plugins.git
path: packages/desktop_multi_window
path_provider: ^2.1.1
url_launcher: ^6.1.12
url_launcher: ^6.1.14
proxy_manager: ^0.0.3
qr_flutter: ^4.1.0
easy_permission: ^1.0.0