fix(chv): api_client 接受 204 无 Content-Length 响应
WSL 真机实测(CHV 54.0.0):vm.create 成功回 204 No Content, 且不带 Content-Length、无体;严格校验(P1-6)把合法成功当 失败拒掉,wake_vm 卡在 vm.create。204/304 按 HTTP 语义体长 恒为 0,不要求长度、不读体(keep-alive 下读会等到超时); 其它状态仍严格(无长度/截断/chunked 均拒绝)。 测试:test_chv_cover100 新增 3 项(204 成功、200 无长度仍拒、 _parse_status)
This commit is contained in:
1 parent
d7cc482ed5
commit
5b6514d019
2 files changed
+66
-3
No files matched your search
@@ -103,6 +103,50 @@ class ApiClientCover100Test(unittest.TestCase):
|
||||
self.assertIn(b'"name": "vm1"', fake.sent)
|
||||
self.assertTrue(fake.closed)
|
||||
|
||||
def test_204_without_content_length_is_success(self):
|
||||
# 真机实测(2026-11-07,CHV 54.0.0):vm.create 成功回
|
||||
# 204 No Content,且不带 Content-Length、无体——严格
|
||||
# 校验会把合法成功当失败拒掉。204 按 HTTP 语义体长为
|
||||
# 0,不读体(keep-alive 下读会等到超时;假 socket 的
|
||||
# 剩余片为空,读体即报截断,本测试能抓住误读)。
|
||||
fake = _FakeApiSocket([
|
||||
b"HTTP/1.1 204 No Content\r\nServer: Cloud Hypervisor API"
|
||||
b"\r\nConnection: keep-alive\r\n\r\n",
|
||||
])
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
sock_path = os.path.join(tmp, "chv.sock")
|
||||
with open(sock_path, "w") as fh:
|
||||
fh.write("x")
|
||||
with mock.patch.object(api_client.socket, "socket",
|
||||
lambda *a, **k: fake):
|
||||
status, body = api_client._unix_socket_api(
|
||||
sock_path, "PUT", "/vm.create",
|
||||
payload={"cpus": {"boot_vcpus": 2}})
|
||||
self.assertEqual(status, 204)
|
||||
self.assertEqual(body, {})
|
||||
self.assertTrue(fake.closed)
|
||||
|
||||
def test_200_without_content_length_still_rejected(self):
|
||||
# 204 例外不得放宽其它状态:200 无长度仍拒绝。
|
||||
fake = _FakeApiSocket([
|
||||
b"HTTP/1.1 200 OK\r\nContent-Type: application/json"
|
||||
b"\r\n\r\n{}",
|
||||
])
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
sock_path = os.path.join(tmp, "chv.sock")
|
||||
with open(sock_path, "w") as fh:
|
||||
fh.write("x")
|
||||
with mock.patch.object(api_client.socket, "socket",
|
||||
lambda *a, **k: fake):
|
||||
with self.assertRaises(RuntimeError):
|
||||
api_client._unix_socket_api(
|
||||
sock_path, "GET", "/vmm.ping")
|
||||
|
||||
def test_parse_status(self):
|
||||
self.assertEqual(api_client._parse_status("HTTP/1.1 204 foo"), 204)
|
||||
self.assertEqual(api_client._parse_status("HTTP/1.1 OK"), 0)
|
||||
self.assertEqual(api_client._parse_status(""), 0)
|
||||
|
||||
def test_parse_status_non_numeric_is_zero(self):
|
||||
status, _body = api_client._parse_response(
|
||||
"HTTP/1.1 OK\r\n\r\n", b"{}")
|
||||
|
||||
Reference in new issue
Block a user