Skip to content

Commit 730ce84

Browse files
committed
fix: 修复会话header和body字段配置不生效的问题
- SessionHeaderManager: 添加_load_from_database方法,初始化时从数据库加载会话请求头 - SessionBodyFieldManager: 添加_load_from_database方法,初始化时从数据库加载会话body字段 - body_field_processor: 修复浅拷贝问题,改用深拷贝确保多字段修改不互相影响 - body_field_processor: 添加JSONPath不可用时的回退处理和详细日志 - Task.apply_header_rules: 修复未传递target_url导致作用域匹配失效 - pyproject.toml: 添加jsonpath-ng依赖支持JSONPath匹配策略
1 parent c1859d8 commit 730ce84

File tree

7 files changed

+298
-4
lines changed

7 files changed

+298
-4
lines changed

src/backEnd/config.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,4 @@
44
MAX_TASKS_COUNT_LOCK = threading.Lock()
55

66

7-
VERSION = "1.8.7"
7+
VERSION = "1.8.8"

src/backEnd/model/Task.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ def apply_header_rules(self):
147147
# 处理请求头
148148
logger.debug(f"[{self.taskid}] Processing headers with {len(self.headers)} original headers")
149149
processed_headers, applied_rules = HeaderProcessor.process_headers(
150-
self.headers, persistent_rules, session_headers
150+
self.headers, persistent_rules, session_headers, self.scanUrl
151151
)
152152
logger.debug(f"[{self.taskid}] Processed headers: {len(processed_headers)}, Applied rules: {len(applied_rules)}")
153153

src/backEnd/pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ thirdparty = [
1010
"fastapi[standard]",
1111
"apscheduler",
1212
"psutil",
13+
"jsonpath-ng",
1314
]
1415

1516
[[tool.uv.index]]

src/backEnd/utils/body_field_processor.py

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
import re
99
import json
10+
import copy
1011
import urllib.parse
1112
from typing import List, Dict, Optional, Tuple, Any
1213

@@ -193,7 +194,7 @@ def apply_rules_to_json(cls, json_obj: dict, fields: List[SessionBodyField], tar
193194
applicable_fields.sort(key=lambda x: x.priority, reverse=True)
194195

195196
# 应用规则
196-
modified_obj = json_obj.copy()
197+
modified_obj = copy.deepcopy(json_obj) # 使用深拷贝避免嵌套对象修改问题
197198
applied_rules = []
198199

199200
for field in applicable_fields:
@@ -204,6 +205,8 @@ def apply_rules_to_json(cls, json_obj: dict, fields: List[SessionBodyField], tar
204205
continue
205206

206207
try:
208+
logger.debug(f"Processing field '{field.field_name}' with strategy {field.match_strategy}, pattern '{field.match_pattern}'")
209+
207210
# 根据匹配策略定位字段
208211
if field.match_strategy == MatchStrategy.JSONPATH and field.match_pattern:
209212
if JSONPATH_AVAILABLE:
@@ -217,7 +220,21 @@ def apply_rules_to_json(cls, json_obj: dict, fields: List[SessionBodyField], tar
217220
existing_value, field.field_value, field.replace_strategy
218221
)
219222
match.full_path.update(modified_obj, new_value)
223+
logger.debug(f"JSONPath matched '{field.field_name}': '{existing_value}' -> '{new_value}'")
220224
applied_rules.append(f"BodyField: {field.field_name}")
225+
else:
226+
logger.debug(f"JSONPath '{field.match_pattern}' found no matches for field '{field.field_name}'")
227+
else:
228+
# JSONPath不可用时,回退到关键字匹配
229+
logger.warning(f"jsonpath-ng not available, falling back to keyword match for field '{field.field_name}'")
230+
if field.field_name in modified_obj:
231+
existing_value = modified_obj[field.field_name]
232+
new_value = cls.apply_replace_strategy(
233+
existing_value, field.field_value, field.replace_strategy
234+
)
235+
modified_obj[field.field_name] = new_value
236+
applied_rules.append(f"BodyField: {field.field_name} (keyword fallback)")
237+
logger.debug(f"Keyword fallback matched '{field.field_name}': '{existing_value}' -> '{new_value}'")
221238

222239
elif field.match_strategy == MatchStrategy.KEYWORD:
223240
# 直接访问字典key
@@ -228,6 +245,9 @@ def apply_rules_to_json(cls, json_obj: dict, fields: List[SessionBodyField], tar
228245
)
229246
modified_obj[field.field_name] = new_value
230247
applied_rules.append(f"BodyField: {field.field_name}")
248+
logger.debug(f"Keyword matched '{field.field_name}': '{existing_value}' -> '{new_value}'")
249+
else:
250+
logger.debug(f"Field '{field.field_name}' not found in JSON object")
231251

232252
except Exception as e:
233253
logger.error(f"Failed to apply field rule '{field.field_name}': {e}")
@@ -301,7 +321,7 @@ def apply_rules_to_urlencoded(cls, params: dict, fields: List[SessionBodyField],
301321
applicable_fields.sort(key=lambda x: x.priority, reverse=True)
302322

303323
# 应用规则
304-
modified_params = params.copy()
324+
modified_params = copy.deepcopy(params) # 使用深拷贝
305325
applied_rules = []
306326

307327
for field in applicable_fields:

src/backEnd/utils/session_body_field_manager.py

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,145 @@ def __init__(self):
3333
self._lock = threading.Lock()
3434
self._id_counter = 1 # ID计数器
3535
logger.debug("SessionBodyFieldManager initialized")
36+
# 从数据库加载已有的会话字段
37+
self._load_from_database()
3638

3739
def _get_db(self):
3840
"""获取请求头数据库连接"""
3941
return DataStore.header_db
4042

43+
def _load_from_database(self):
44+
"""从数据库加载所有未过期的会话Body字段"""
45+
try:
46+
db = self._get_db()
47+
if db is None:
48+
logger.debug("Database not available, skipping load from database")
49+
return
50+
51+
# 获取当前时间
52+
current_time = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
53+
54+
# 查询所有未过期的会话字段
55+
cursor = db.only_execute("""
56+
SELECT id, client_ip, field_name, field_value, match_strategy, match_pattern,
57+
replace_strategy, content_types, priority, is_active,
58+
expires_at, created_at, updated_at, scope_config
59+
FROM session_body_fields
60+
WHERE expires_at > ?
61+
""", (current_time,))
62+
63+
if cursor is None:
64+
logger.debug("No cursor returned from database")
65+
return
66+
67+
loaded_count = 0
68+
max_id = 0
69+
70+
for row in cursor:
71+
try:
72+
(field_id, client_ip, field_name, field_value, match_strategy_str, match_pattern,
73+
replace_strategy_str, content_types_json, priority, is_active,
74+
expires_at_str, created_at_str, updated_at_str, scope_config_json) = row
75+
76+
# 跟踪最大ID
77+
if field_id and field_id > max_id:
78+
max_id = field_id
79+
80+
# 解析匹配策略
81+
try:
82+
match_strategy = MatchStrategy(match_strategy_str)
83+
except ValueError:
84+
match_strategy = MatchStrategy.KEYWORD
85+
86+
# 解析替换策略
87+
try:
88+
replace_strategy = ReplaceStrategy(replace_strategy_str)
89+
except ValueError:
90+
replace_strategy = ReplaceStrategy.REPLACE
91+
92+
# 解析content_types
93+
content_types = None
94+
if content_types_json:
95+
try:
96+
content_types = json.loads(content_types_json)
97+
except json.JSONDecodeError:
98+
content_types = None
99+
100+
# 解析expires_at
101+
expires_at = None
102+
if expires_at_str:
103+
try:
104+
expires_at = datetime.strptime(expires_at_str, '%Y-%m-%d %H:%M:%S')
105+
except ValueError:
106+
expires_at = None
107+
108+
# 解析created_at
109+
created_at = None
110+
if created_at_str:
111+
try:
112+
created_at = datetime.strptime(created_at_str, '%Y-%m-%d %H:%M:%S')
113+
except ValueError:
114+
created_at = datetime.now()
115+
116+
# 解析updated_at
117+
updated_at = None
118+
if updated_at_str:
119+
try:
120+
updated_at = datetime.strptime(updated_at_str, '%Y-%m-%d %H:%M:%S')
121+
except ValueError:
122+
updated_at = None
123+
124+
# 解析scope_config
125+
scope = None
126+
if scope_config_json:
127+
try:
128+
from model.HeaderScope import HeaderScope
129+
scope_dict = json.loads(scope_config_json)
130+
scope = HeaderScope.from_dict(scope_dict)
131+
except (json.JSONDecodeError, Exception) as e:
132+
logger.debug(f"Failed to parse scope config: {e}")
133+
scope = None
134+
135+
# 创建 SessionBodyField 对象
136+
session_field = SessionBodyField(
137+
id=field_id,
138+
field_name=field_name,
139+
field_value=field_value,
140+
match_strategy=match_strategy,
141+
match_pattern=match_pattern,
142+
replace_strategy=replace_strategy,
143+
content_types=content_types,
144+
priority=priority or 50,
145+
is_active=bool(is_active),
146+
expires_at=expires_at,
147+
created_at=created_at,
148+
updated_at=updated_at,
149+
source_ip=client_ip,
150+
scope=scope
151+
)
152+
153+
# 加载到内存
154+
if client_ip not in self._session_body_fields:
155+
self._session_body_fields[client_ip] = {}
156+
self._session_body_fields[client_ip][field_name] = session_field
157+
loaded_count += 1
158+
159+
except Exception as e:
160+
logger.error(f"Failed to load session body field from row: {e}")
161+
continue
162+
163+
# 更新ID计数器
164+
if max_id > 0:
165+
self._id_counter = max_id + 1
166+
167+
if loaded_count > 0:
168+
logger.info(f"Loaded {loaded_count} session body fields from database")
169+
else:
170+
logger.debug("No active session body fields found in database")
171+
172+
except Exception as e:
173+
logger.error(f"Failed to load session body fields from database: {e}")
174+
41175
def _generate_id(self) -> int:
42176
"""生成唯一ID"""
43177
self._id_counter += 1

src/backEnd/utils/session_header_manager.py

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,127 @@ def __init__(self):
2121
self._lock = threading.Lock()
2222
self._id_counter = 1 # ID计数器
2323
logger.debug("SessionHeaderManager initialized")
24+
# 从数据库加载已有的会话请求头
25+
self._load_from_database()
2426

2527
def _get_db(self):
2628
"""获取请求头数据库连接"""
2729
return DataStore.header_db
2830

31+
def _load_from_database(self):
32+
"""从数据库加载所有未过期的会话请求头"""
33+
try:
34+
db = self._get_db()
35+
if db is None:
36+
logger.debug("Database not available, skipping load from database")
37+
return
38+
39+
# 获取当前时间
40+
current_time = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
41+
42+
# 查询所有未过期的会话请求头
43+
cursor = db.only_execute("""
44+
SELECT id, client_ip, header_name, header_value, replace_strategy, priority,
45+
is_active, expires_at, created_at, updated_at, scope_config
46+
FROM session_headers
47+
WHERE expires_at > ?
48+
""", (current_time,))
49+
50+
if cursor is None:
51+
logger.debug("No cursor returned from database")
52+
return
53+
54+
loaded_count = 0
55+
max_id = 0
56+
57+
for row in cursor:
58+
try:
59+
(header_id, client_ip, header_name, header_value, replace_strategy_str,
60+
priority, is_active, expires_at_str, created_at_str, updated_at_str,
61+
scope_config_json) = row
62+
63+
# 跟踪最大ID
64+
if header_id and header_id > max_id:
65+
max_id = header_id
66+
67+
# 解析替换策略
68+
try:
69+
replace_strategy = ReplaceStrategy(replace_strategy_str)
70+
except ValueError:
71+
replace_strategy = ReplaceStrategy.REPLACE
72+
73+
# 解析expires_at
74+
expires_at = None
75+
if expires_at_str:
76+
try:
77+
expires_at = datetime.strptime(expires_at_str, '%Y-%m-%d %H:%M:%S')
78+
except ValueError:
79+
expires_at = None
80+
81+
# 解析created_at
82+
created_at = None
83+
if created_at_str:
84+
try:
85+
created_at = datetime.strptime(created_at_str, '%Y-%m-%d %H:%M:%S')
86+
except ValueError:
87+
created_at = datetime.now()
88+
89+
# 解析updated_at
90+
updated_at = None
91+
if updated_at_str:
92+
try:
93+
updated_at = datetime.strptime(updated_at_str, '%Y-%m-%d %H:%M:%S')
94+
except ValueError:
95+
updated_at = None
96+
97+
# 解析scope_config
98+
scope = None
99+
if scope_config_json:
100+
try:
101+
from model.HeaderScope import HeaderScope
102+
scope_dict = json.loads(scope_config_json)
103+
scope = HeaderScope.from_dict(scope_dict)
104+
except (json.JSONDecodeError, Exception) as e:
105+
logger.debug(f"Failed to parse scope config: {e}")
106+
scope = None
107+
108+
# 创建 SessionHeader 对象
109+
session_header = SessionHeader(
110+
id=header_id,
111+
header_name=header_name,
112+
header_value=header_value,
113+
replace_strategy=replace_strategy,
114+
priority=priority or 50,
115+
is_active=bool(is_active),
116+
expires_at=expires_at,
117+
created_at=created_at,
118+
updated_at=updated_at,
119+
source_ip=client_ip,
120+
scope=scope
121+
)
122+
123+
# 加载到内存
124+
if client_ip not in self._session_headers:
125+
self._session_headers[client_ip] = {}
126+
self._session_headers[client_ip][header_name] = session_header
127+
loaded_count += 1
128+
129+
except Exception as e:
130+
logger.error(f"Failed to load session header from row: {e}")
131+
continue
132+
133+
# 更新ID计数器
134+
if max_id > 0:
135+
self._id_counter = max_id + 1
136+
137+
if loaded_count > 0:
138+
logger.info(f"Loaded {loaded_count} session headers from database")
139+
else:
140+
logger.debug("No active session headers found in database")
141+
142+
except Exception as e:
143+
logger.error(f"Failed to load session headers from database: {e}")
144+
29145
def _generate_id(self) -> int:
30146
"""生成唯一ID"""
31147
self._id_counter += 1

0 commit comments

Comments
 (0)