feat(chv): 架构与代码质量 9.5+ 提升——长函数清零、WarmPool facade、#215 对齐、审计计数、只读 VM 字段、ADR-8~11
This commit is contained in:
1 parent
c908a0147a
commit
42de20da68
15 files changed
+840
-345
No files matched your search
+93
-72
@@ -9,12 +9,100 @@ import os
|
||||
import socket
|
||||
|
||||
|
||||
def _read_header(sock):
|
||||
"""读满响应头:返回 (header_text, 已收体部前缀)。
|
||||
|
||||
超时或提前关流即 RuntimeError,绝不把半截头当结束
|
||||
(feat-chv-fix P1-6 的语义,纯移动)。"""
|
||||
buf = b""
|
||||
header_end = None
|
||||
timed_out = False
|
||||
while header_end is None:
|
||||
try:
|
||||
data = sock.recv(65536)
|
||||
except socket.timeout:
|
||||
timed_out = True
|
||||
break
|
||||
if not data:
|
||||
break
|
||||
buf += data
|
||||
header_end = buf.find(b"\r\n\r\n")
|
||||
if timed_out or header_end is None:
|
||||
raise RuntimeError("CHV API 响应头不完整(超时或提前关流)")
|
||||
header = buf[:header_end].decode("utf-8", errors="replace")
|
||||
return header, buf[header_end + 4:]
|
||||
|
||||
|
||||
def _parse_content_length(header):
|
||||
"""从响应头取 Content-Length:chunked 或无长度即拒绝。
|
||||
|
||||
chunked 明确拒绝(CHV REST 不应发 chunked);无长度则
|
||||
无法证完整性,同样拒绝。"""
|
||||
content_length = None
|
||||
is_chunked = False
|
||||
for line in header.split("\r\n")[1:]:
|
||||
if ":" not in line:
|
||||
continue
|
||||
name, value = line.split(":", 1)
|
||||
name = name.strip().lower()
|
||||
value = value.strip()
|
||||
if name == "content-length":
|
||||
try:
|
||||
content_length = int(value)
|
||||
except ValueError:
|
||||
raise RuntimeError("CHV API Content-Length 非法")
|
||||
elif name == "transfer-encoding" \
|
||||
and "chunked" in value.lower():
|
||||
is_chunked = True
|
||||
if is_chunked:
|
||||
raise RuntimeError("CHV API 响应为 chunked,拒绝解析")
|
||||
if content_length is None:
|
||||
raise RuntimeError("CHV API 响应无 Content-Length,拒绝解析")
|
||||
return content_length
|
||||
|
||||
|
||||
def _read_body(sock, body, content_length):
|
||||
"""按 Content-Length 读满体部:超时或提前关流即截断错误。"""
|
||||
while len(body) < content_length:
|
||||
try:
|
||||
data = sock.recv(65536)
|
||||
except socket.timeout:
|
||||
raise RuntimeError(
|
||||
"CHV API 响应体截断:已收 %d / 需 %d 字节"
|
||||
% (len(body), content_length))
|
||||
if not data:
|
||||
raise RuntimeError(
|
||||
"CHV API 响应体截断:已收 %d / 需 %d 字节"
|
||||
% (len(body), content_length))
|
||||
body += data
|
||||
return body[:content_length]
|
||||
|
||||
|
||||
def _parse_response(header, body):
|
||||
"""从已读满的头与体部解析 (status, body):能解析 JSON
|
||||
时为 dict,否则为原文本;状态行解析失败时 status 为 0。"""
|
||||
text = header + "\r\n\r\n" + body.decode("utf-8", errors="replace")
|
||||
status = 0
|
||||
if text.startswith("HTTP/"):
|
||||
try:
|
||||
status = int(text.split()[1])
|
||||
except (IndexError, ValueError):
|
||||
status = 0
|
||||
body_text = body.decode("utf-8", errors="replace")
|
||||
try:
|
||||
parsed = json.loads(body_text) if body_text.strip() else {}
|
||||
except ValueError:
|
||||
parsed = body_text
|
||||
return status, parsed
|
||||
|
||||
|
||||
def _unix_socket_api(socket_path, method, path, payload=None):
|
||||
"""Cloud Hypervisor REST API 的默认传输:标准库 raw HTTP
|
||||
over Unix socket(无第三方依赖)。返回 (status, body),
|
||||
body 能解析 JSON 时为 dict,否则为原文本。socket 不存在
|
||||
或连接失败时 raise RuntimeError(调用方据此判 api 超时
|
||||
/失败,不编造 200)。"""
|
||||
/失败,不编造 200)。读满语义见 _read_header /
|
||||
_parse_content_length / _read_body(P1-6,纯移动)。"""
|
||||
if not os.path.exists(socket_path):
|
||||
raise RuntimeError("api socket 不存在:%s" % socket_path)
|
||||
body = b""
|
||||
@@ -32,79 +120,12 @@ def _unix_socket_api(socket_path, method, path, payload=None):
|
||||
try:
|
||||
sock.connect(socket_path)
|
||||
sock.sendall(raw)
|
||||
chunks = []
|
||||
# feat-chv-fix(P1-6):读超时不再当“响应结束”。
|
||||
# 先读满响应头,再按 Content-Length 读满体部;超时、
|
||||
# 提前关流、体部短于 Content-Length 一律 RuntimeError
|
||||
# (调用方判 api_timeout / 传输失败),绝不解析半截
|
||||
# 响应。chunked 与无 Content-Length 响应明确拒绝
|
||||
# (Cloud Hypervisor REST 不应发 chunked;无长度则
|
||||
# 无法证完整性)。
|
||||
buf = b""
|
||||
header_end = None
|
||||
timed_out = False
|
||||
while header_end is None:
|
||||
try:
|
||||
data = sock.recv(65536)
|
||||
except socket.timeout:
|
||||
timed_out = True
|
||||
break
|
||||
if not data:
|
||||
break
|
||||
buf += data
|
||||
header_end = buf.find(b"\r\n\r\n")
|
||||
if timed_out or header_end is None:
|
||||
raise RuntimeError("CHV API 响应头不完整(超时或提前关流)")
|
||||
header = buf[:header_end].decode("utf-8", errors="replace")
|
||||
body = buf[header_end + 4:]
|
||||
content_length = None
|
||||
is_chunked = False
|
||||
for line in header.split("\r\n")[1:]:
|
||||
if ":" not in line:
|
||||
continue
|
||||
name, value = line.split(":", 1)
|
||||
name = name.strip().lower()
|
||||
value = value.strip()
|
||||
if name == "content-length":
|
||||
try:
|
||||
content_length = int(value)
|
||||
except ValueError:
|
||||
raise RuntimeError("CHV API Content-Length 非法")
|
||||
elif name == "transfer-encoding" \
|
||||
and "chunked" in value.lower():
|
||||
is_chunked = True
|
||||
if is_chunked:
|
||||
raise RuntimeError("CHV API 响应为 chunked,拒绝解析")
|
||||
if content_length is None:
|
||||
raise RuntimeError("CHV API 响应无 Content-Length,拒绝解析")
|
||||
while len(body) < content_length:
|
||||
try:
|
||||
data = sock.recv(65536)
|
||||
except socket.timeout:
|
||||
raise RuntimeError(
|
||||
"CHV API 响应体截断:已收 %d / 需 %d 字节"
|
||||
% (len(body), content_length))
|
||||
if not data:
|
||||
raise RuntimeError(
|
||||
"CHV API 响应体截断:已收 %d / 需 %d 字节"
|
||||
% (len(body), content_length))
|
||||
body += data
|
||||
body = body[:content_length]
|
||||
header, body = _read_header(sock)
|
||||
content_length = _parse_content_length(header)
|
||||
body = _read_body(sock, body, content_length)
|
||||
finally:
|
||||
sock.close()
|
||||
text = header + "\r\n\r\n" + body.decode("utf-8", errors="replace")
|
||||
status = 0
|
||||
if text.startswith("HTTP/"):
|
||||
try:
|
||||
status = int(text.split()[1])
|
||||
except (IndexError, ValueError):
|
||||
status = 0
|
||||
body_text = body.decode("utf-8", errors="replace")
|
||||
try:
|
||||
parsed = json.loads(body_text) if body_text.strip() else {}
|
||||
except ValueError:
|
||||
parsed = body_text
|
||||
return status, parsed
|
||||
return _parse_response(header, body)
|
||||
|
||||
|
||||
def normalize_api_result(result) -> tuple:
|
||||
|
||||
Reference in new issue
Block a user