Files
proxypin/lib/network/handler.dart
wanghongen 8ea2fdee67 chunk编码
2023-06-19 19:43:03 +08:00

163 lines
4.9 KiB
Dart

import 'dart:io';
import 'package:flutter/services.dart';
import 'package:network/network/http/http.dart';
import 'package:network/network/http/http_headers.dart';
import 'package:network/network/util/attribute_keys.dart';
import 'package:network/network/util/logger.dart';
import 'channel.dart';
import 'http/codec.dart';
/// 获取主机和端口
HostAndPort getHostAndPort(HttpRequest request) {
String requestUri = request.uri;
//有些请求直接是路径 /xxx, 从header取host
if (request.uri.startsWith("/")) {
requestUri = request.headers.get(HttpHeaders.HOST)!;
}
return HostAndPort.of(requestUri);
}
abstract class EventListener {
void onRequest(Channel channel, HttpRequest request);
void onResponse(Channel channel, HttpResponse response);
}
///
class HttpChannelHandler extends ChannelHandler<HttpRequest> {
EventListener? listener;
HttpChannelHandler({this.listener});
@override
void channelRead(Channel channel, HttpRequest msg) async {
forward(channel, msg).catchError((error, trace) {
channel.close();
if (error is SocketException &&
(error.message.contains("Failed host lookup") || error.message.contains("Connection timed out"))) {
log.e("连接失败 ${error.message}");
return;
}
log.e("转发请求失败", error, trace);
});
}
@override
void channelInactive(Channel channel) {
Channel? remoteChannel = channel.getAttribute(channel.id);
remoteChannel?.close();
}
/// 转发请求
Future<void> forward(Channel channel, HttpRequest httpRequest) async {
channel.putAttribute(AttributeKeys.request, httpRequest);
if (httpRequest.uri == 'http://proxy.pin/ssl') {
_crtDownload(channel, httpRequest);
return;
}
var remoteChannel = await _getRemoteChannel(channel, httpRequest);
//实现抓包代理转发
if (httpRequest.method != HttpMethod.connect) {
if (httpRequest.uri.startsWith("/")) {
remoteChannel.putAttribute(AttributeKeys.uri, '${channel.getAttribute(AttributeKeys.host)}${httpRequest.uri}');
} else {
remoteChannel.putAttribute(AttributeKeys.uri, httpRequest.uri);
}
// log.i("[${channel.id}] ${remoteChannel.getAttribute(AttributeKeys.uri)}");
listener?.onRequest(channel, httpRequest);
//实现抓包代理转发
await remoteChannel.write(httpRequest);
}
}
void _crtDownload(Channel channel, HttpRequest request) async {
const String fileMimeType = 'application/x-x509-ca-cert';
var body = await rootBundle.load('assets/certs/ca.crt');
var response = HttpResponse(request.protocolVersion, HttpStatus.ok);
response.headers.set(HttpHeaders.CONTENT_TYPE, fileMimeType);
response.headers.set("Content-Disposition", 'attachment; filename="ProxyPin CA.crt"');
response.body = body.buffer.asUint8List();
channel.write(response);
}
/// 获取远程连接
Future<Channel> _getRemoteChannel(Channel clientChannel, HttpRequest httpRequest) async {
String clientId = clientChannel.id;
//客户端连接 作为缓存
Channel? remoteChannel = clientChannel.getAttribute(clientId);
if (remoteChannel != null) {
return remoteChannel;
}
var hostAndPort = getHostAndPort(httpRequest);
clientChannel.putAttribute(AttributeKeys.host, hostAndPort);
var proxyHandler = HttpResponseProxyHandler(clientChannel, listener: listener);
var proxyChannel = await HttpClients.connect(hostAndPort, proxyHandler);
clientChannel.putAttribute(clientId, proxyChannel);
//https代理新建连接请求
if (httpRequest.method == HttpMethod.connect) {
await clientChannel.write(HttpResponse(httpRequest.protocolVersion, HttpStatus.ok));
}
return proxyChannel;
}
}
/// http响应代理
class HttpResponseProxyHandler extends ChannelHandler<HttpResponse> {
final Channel clientChannel;
EventListener? listener;
HttpResponseProxyHandler(this.clientChannel, {this.listener});
@override
void channelRead(Channel channel, HttpResponse msg) {
msg.request = clientChannel.getAttribute(AttributeKeys.request);
// log.i("[${clientChannel.id}] Response ${msg.bodyAsString}");
listener?.onResponse(clientChannel, msg);
//发送给客户端
clientChannel.write(msg);
}
@override
void channelInactive(Channel channel) {
clientChannel.close();
}
}
class RelayHandler extends ChannelHandler<Object> {
final Channel remoteChannel;
RelayHandler(this.remoteChannel);
@override
void channelRead(Channel channel, Object msg) {
//发送给客户端
remoteChannel.write(msg);
}
@override
void channelInactive(Channel channel) {
remoteChannel.close();
}
}
class HttpClients {
/// 建立连接
static Future<Channel> connect(HostAndPort hostAndPort, ChannelHandler<HttpResponse> handler) async {
var client = Client()
..initChannel((channel) => channel.pipeline.handle(HttpResponseCodec(), HttpRequestCodec(), handler));
return client.connect(hostAndPort);
}
}