Files
proxypin/lib/network/components/manager/rewrite_rule.dart
2025-12-07 01:08:49 +08:00

272 lines
7.2 KiB
Dart
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*
* Copyright 2024 Hongen Wang All rights reserved.
*
* 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://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import 'package:proxypin/network/http/http.dart';
import 'package:proxypin/utils/lang.dart';
///重写规则
///@author: wanghongen
enum RuleType {
// body("重写消息体"), //OLD VERSION
requestReplace("替换请求"),
responseReplace("替换响应"),
requestUpdate("修改请求"),
responseUpdate("修改响应"),
redirect("重定向");
//名称
final String label;
const RuleType(this.label);
static RuleType fromName(String name) {
return values.firstWhere((element) => element.name == name || element.label == name);
}
}
class RequestRewriteRule {
bool enabled;
RuleType type;
String? name;
String url;
RegExp _urlReg;
String? rewritePath;
// 可选的 HTTP 方法匹配null 表示匹配任意方法
HttpMethod? method;
RequestRewriteRule({this.enabled = true, this.name, required this.url, required this.type, this.rewritePath, this.method})
: _urlReg = RegExp(url.replaceAll("*", ".*").replaceFirst('?', '\\?'));
bool match(String url, {RuleType? type, HttpMethod? method}) {
if (!enabled) return false;
if (type != null && this.type != type) return false;
// 如果调用方提供了 method则当规则定义了 method 时进行比较;如果调用方未提供 method则不按方法过滤向后兼容
if (method != null && this.method != null && this.method != method) return false;
return _urlReg.hasMatch(url);
}
bool matchUrl(String url, RuleType type) {
return this.type == type && _urlReg.hasMatch(url);
}
/// 从json中创建
factory RequestRewriteRule.formJson(Map<dynamic, dynamic> map) {
HttpMethod? method;
try {
if (map['method'] != null) {
method = HttpMethod.valueOf(map['method'].toString());
}
} catch (e) {
// ignore invalid method
}
return RequestRewriteRule(
enabled: map['enabled'] == true,
name: map['name'],
url: map['url'] ?? map['domain'] + map['path'],
type: RuleType.fromName(map['type']),
rewritePath: map['rewritePath'],
method: method);
}
void updatePathReg() {
_urlReg = RegExp(url.replaceAll("*", ".*").replaceFirst('?', '\\?'));
}
Map<String, dynamic> toJson() {
var json = {
'name': name,
'enabled': enabled,
'url': url,
'type': type.name,
'rewritePath': rewritePath,
};
if (method != null) {
json['method'] = method!.name;
}
return json;
}
}
enum ReplaceBodyType {
text("文本"),
file("文件");
final String label;
const ReplaceBodyType(this.label);
}
class RewriteItem {
bool enabled;
RewriteType type;
//key redirectUrl, method, path, queryParam, headers, body, statusCode
final Map<String, dynamic> values = {};
RewriteItem(this.type, this.enabled, {Map<dynamic, dynamic>? values}) {
if (values != null) {
this.values.addAll(Map.from(values));
}
}
factory RewriteItem.fromJson(Map<dynamic, dynamic> map) {
return RewriteItem(RewriteType.fromName(map['type']), map['enabled'], values: map['values']);
}
static List<RewriteItem> fromRequest(HttpRequest request) {
List<RewriteItem> items = [];
items.add(RewriteItem(RewriteType.replaceRequestLine, false)..path = request.requestUri?.path);
items.add(RewriteItem(RewriteType.replaceRequestHeader, false)..headers = request.headers.toMap());
items.add(RewriteItem(RewriteType.replaceRequestBody, true)..body = request.getBodyString());
return items;
}
static List<RewriteItem> fromResponse(HttpResponse response) {
List<RewriteItem> items = [];
items.add(RewriteItem(RewriteType.replaceResponseStatus, false)..statusCode = response.status.code);
items.add(RewriteItem(RewriteType.replaceResponseHeader, false)..headers = response.headers.toMap());
items.add(RewriteItem(RewriteType.replaceResponseBody, true)..body = response.getBodyString());
return items;
}
//key
String? get key => values['key'];
set key(String? key) => values['key'] = key;
String? get value => values['value'];
set value(String? value) => values['value'] = value;
//redirectUrl
String? get redirectUrl => values['redirectUrl'];
set redirectUrl(String? redirectUrl) => values['redirectUrl'] = redirectUrl;
//method
HttpMethod? get method => values['method'] == null
? null
: HttpMethod.values.firstWhereOrNull((element) => element.name == values['method']);
set method(HttpMethod? method) => values['method'] = method?.name;
String? get path => values['path'];
set path(String? path) => values['path'] = path;
//queryParam
String? get queryParam => values['queryParam'];
set queryParam(String? queryParam) => values['queryParam'] = queryParam;
//statusCode
int? get statusCode => values['statusCode'];
set statusCode(int? statusCode) => values['statusCode'] = statusCode;
//headers
Map<String, String>? get headers => values['headers'] == null ? null : Map.from(values['headers']);
set headers(Map<String, String>? headers) => values['headers'] = headers;
//body
String? get body => values['body'];
set body(String? body) => values['body'] = body;
String? get bodyType => values['bodyType'];
set bodyType(String? bodyType) => values['bodyType'] = bodyType;
String? get bodyFile => values['bodyFile'];
set bodyFile(String? bodyFile) => values['bodyFile'] = bodyFile;
Map<String, dynamic> toJson() {
return {
'enabled': enabled,
'type': type.name,
'values': values,
};
}
@override
String toString() {
return toJson().toString();
}
}
enum RewriteType {
//重定向
redirect("重定向"),
//替换请求
replaceRequestLine("请求行"),
replaceRequestHeader("请求头"),
replaceRequestBody("请求体"),
replaceResponseStatus("状态码"),
replaceResponseHeader("响应头"),
replaceResponseBody("响应体"),
//修改请求
updateBody("修改Body"),
addQueryParam("添加参数"),
removeQueryParam("删除参数"),
updateQueryParam("修改参数"),
addHeader("添加头部"),
removeHeader("删除头部"),
updateHeader("修改头部"),
;
static List<RewriteType> updateRequest = [
updateBody,
addQueryParam,
updateQueryParam,
removeQueryParam,
addHeader,
updateHeader,
removeHeader
];
static List<RewriteType> updateResponse = [updateBody, addHeader, updateHeader, removeHeader];
final String label;
const RewriteType(this.label);
static RewriteType fromName(String name) {
return values.firstWhere((element) => element.name == name);
}
String getDescribe(bool isCN) {
if (isCN) {
return label;
}
return name.replaceFirst("replace", "").replaceFirst("Query", "");
}
}