网络能力补全规格
定义通用 HTTPS 请求、传输、Cookie、进度、取消与边界策略。
定义通用 HTTPS 请求、Cookie 隔离、传输进度、取消、大结果句柄与 origin 白名单的目标边界。
| 状态项 | 说明 |
|---|---|
当前 26.11.5 | 当前 26.11.5 基线只有 http.download,将 HTTPS 资源下载到虚拟路径;没有通用请求、CookieJar、POST、进度事件、取消事件或大响应文件句柄。事件只有 webview.navigated、webview.reloaded、window.resized。 |
目标规格(未发布) | 规格 / 待实现:新增 http.request、http.transfer.start/cancel、http.cookies.get/set/clear 与三个传输事件;保留 http.download 语义;双端使用同一 origin、Header、Cookie、重定向、进度和取消规则。 |
实施阶段 | P1;依赖 P0 的协议、权限、错误码、生成契约与 CLI 配置。 |
验收标准 | 允许 origin 下的 GET/POST、受控 Header/Cookie/UA/Referer、逐跳重定向、进度、取消和 { file } 在 Windows 与 Android 行为一致;未授权 origin 与超大载荷被拒绝。 |
网络能力只提供协议级请求和传输原子操作。业务鉴权、请求签名、缓存键和重试策略留在应用扩展层。URL、origin、重定向、Cookie 和响应大小校验属于宿主服务层,前端守卫不能替代原生校验。
| 层级 | 真实入口 | 责任 |
|---|---|---|
| 协议 | protocol/commands.json、protocol/permissions.schema.json、protocol/plugins.json | 目标命令、事件、权限、错误码和平台矩阵。 |
| 配置 | protocol/kasumi.config.schema.json、packages/kasumi-cli/src/config.mjs、cli/kasumi_config.py | 平台 http.allowedOrigins 精确 HTTPS origin 白名单。 |
| 前端 | frontend/src/api/http.ts、frontend/src/bridge/ksm.ts、frontend/src/bridge/transport.ts | 参数守卫、请求生命周期、进度事件、取消和 64 KiB 消息边界。 |
| Windows | windows/src/plugins/ksm_http_plugin.cpp、windows/src/platform/ksm_url_policy.cpp | WinHTTP 请求、逐跳 origin 校验、CookieJar、传输任务与取消。 |
| Android | KSMHttpPlugin.kt、KSMHttp.kt、KSMHttpPolicy.kt、KSMRouter.kt | 网络栈、系统下载、CookieJar、传输任务与取消。 |
| 能力 | 当前 26.11.5 基线 | 目标规格 / 待实现 |
|---|---|---|
| 请求 | http.download 下载到 app:// 路径,120 秒上限,逐跳 HTTPS origin 校验。 | http.request 支持允许 origin 下 GET/POST、受控 Header、Cookie、UA、Referer;返回小响应或 { file }。 |
| 传输 | 下载过程没有标准进度、完成或失败事件。 | http.transfer.start/cancel;http.transfer.progress/completed/failed。 |
| Cookie | 无前端 API 或隔离 CookieJar。 | http.cookies.get/set/clear;按应用与 origin 隔离,不向前端返回凭据原文。 |
| 重定向 | http.download 每一跳重新匹配 origin。 | 所有请求和传输的每一跳重新匹配精确 https origin;不跟随未授权跳转。 |
| 大结果 | http.download 写入虚拟路径。 | 通用响应超过阈值写入 app://tmp 并返回 { file }。 |
| 系统下载 | Android 已有下载链路,但不作为统一传输事件暴露。 | Android 系统下载与 Windows 传输共用同一事件形状和取消语义。 |
| URL 策略 | http.allowedOrigins 默认空白名单,只接受精确 HTTPS origin。 | 保留空白名单默认;通配符、用户名密码、非法端口和明文 HTTP 在配置阶段拒绝。 |
| 目标命令 | 参数与返回边界 |
|---|---|
http.request | { url, method, headers?, body? };返回 { status, headers, body },body 为字符串或 { file }。 |
http.transfer.start | { url, method?, headers?, path?, transferId? };返回 { transferId }。 |
http.transfer.cancel | { transferId };返回 { cancelled };已完成的传输返回幂等结果。 |
http.cookies.get/set/clear | 按允许 origin 操作隔离 CookieJar;返回值不包含 Cookie 凭据原文。 |
| 目标事件 | 载荷 |
|---|---|
http.transfer.progress | { transferId, bytes, totalBytes };按宿主节流,载荷为小对象。 |
http.transfer.completed | { transferId, path, bytes }。 |
http.transfer.failed | { transferId, code, message }。 |
真实入口是 kasumi-bridge 的 KSM 类和 frontend/src/api/http.ts 包装。kasumi.config.json 的 windows.http.allowedOrigins 与 android.http.allowedOrigins 由 packages/kasumi-cli/src/config.mjs 和 cli/kasumi_config.py 校验:
{
"windows": {
"http": {
"allowedOrigins": ["https://api.example.test"]
}
},
"android": {
"http": {
"allowedOrigins": ["https://api.example.test"]
}
}
}以下示例描述目标接口,尚未在 26.11.5 发布:
import { KSM, KSMWebMessageTransport } from 'kasumi-bridge';
KSM.initialize(new KSMWebMessageTransport());
const capabilities = await KSM.capabilities();
const permission = await KSM.permission.request('http.request');
if (!permission.granted || !capabilities.commands.includes('http.request')) {
throw new Error('http.request is unavailable.');
}
const response = await KSM.invoke<{
status: number;
headers: Record<string, string>;
body: string | { file: string };
}, {
url: string;
method: 'POST';
headers: Record<string, string>;
body: string;
}>('http.request', {
url: 'https://api.example.test/session',
method: 'POST',
headers: {
'Content-Type': 'application/json',
'User-Agent': 'Kasumi/1.0'
},
body: JSON.stringify({ scope: 'library' })
});
const { transferId } = await KSM.invoke<{ transferId: string }, {
url: string;
path: string;
}>('http.transfer.start', {
url: 'https://api.example.test/archive.json',
path: 'app://cache/archive.json'
});
const off = KSM.on<{ bytes: number; totalBytes: number | null }>(
'http.transfer.progress',
(payload) => console.info(payload.bytes, payload.totalBytes)
);
await KSM.subscribe('http.transfer.progress');
await KSM.invoke('http.transfer.cancel', { transferId });
off();
await KSM.unsubscribe('http.transfer.progress');Cookie 按 origin 隔离,前端只读取存在性和受控元数据,不直接返回凭据原文。同一应用内两个不同 origin 的 CookieJar 不共享;清理只作用于指定 origin:
const cookieState = await KSM.invoke<{ present: boolean }, { origin: string }>(
'http.cookies.get',
{ origin: 'https://api.example.test' }
);
await KSM.invoke('http.cookies.set', {
origin: 'https://api.example.test',
cookies: [{ name: 'session', value: 'opaque-token' }]
});
if (cookieState.present) {
await KSM.invoke('http.cookies.clear', {
origin: 'https://api.example.test'
});
}| 平台 | 实现边界 | 行为 |
|---|---|---|
| Windows | windows/src/plugins/ksm_http_plugin.cpp、windows/src/platform/ksm_url_policy.cpp、ksm_windows_host_services.cpp | WinHTTP 请求与传输任务放在服务层;逐跳校验精确 HTTPS origin、受控 Header、CookieJar、重定向上限、超时、取消和临时文件写入;响应回到 WebView2 所属 UI 线程。 |
| Android | KSMHttpPlugin.kt、KSMHttp.kt、KSMHttpPolicy.kt、KSMRouter.kt、KSMWebViewHost.kt | 网络栈与系统下载放在 Host Services;按 windowId 保存传输和取消令牌;close() 只取消当前窗口任务;通知权限与前台服务不用于普通请求。 |
两端的 http.download 保持现有参数和返回语义。新增命令不绕过 capabilities.query、event.subscribe、权限 allowlist 和 64 KiB 消息边界。
Host 头绕过 http.allowedOrigins;每一跳重定向重新校验。window.chrome.webview、addJavascriptInterface 或宿主私有 HTTP 接口;所有请求从 KSM 根入口进入。{ file },不以 base64 内联。Referer、User-Agent、Cookie 或自定义 Header 设为任意可写集合;宿主只接受协议声明的受控字段。| 错误码 | 触发条件 | 期望行为 |
|---|---|---|
INVALID_ARGS | URL、method、Header、body、origin 或 transferId 非法。 | 前端守卫与宿主校验同时拒绝。 |
PERMISSION_DENIED | 权限、命令白名单或 origin 未授权。 | 请求发送前拒绝。 |
NOT_SUPPORTED | 平台未实现目标网络能力或未注入网络服务。 | 能力查询排除该命令。 |
NOT_FOUND | 请求资源不存在或 transferId 已过期。 | 不创建空响应,返回明确错误。 |
IO_ERROR | 连接、磁盘、临时文件或系统下载失败。 | 清理临时文件并发送 http.transfer.failed。 |
CANCELLED / TIMEOUT | 显式取消、窗口销毁或超时。 | 取消底层任务,抑制迟到响应。 |
BUSY / RESOURCE_LIMIT | 并发、响应大小或重定向次数超限。 | 保留当前状态并返回可操作原因。 |
UPDATE_VERIFICATION_FAILED | 更新包下载复用传输链路时校验和不匹配。 | 保留旧版本,删除临时包;普通请求不使用此码。 |
MEDIA_UNSUPPORTED | 目标规格保留给媒体能力;网络命令不得用其代替 HTTP 状态码。 | 返回结构化 HTTP 错误或 IO_ERROR。 |
| 现象 | 优先检查 |
|---|---|
| 请求被拒绝且 origin 看起来正确 | http.allowedOrigins 是否为精确 scheme/host/port、是否包含路径或通配符、重定向目标是否授权。 |
POST 返回 INVALID_ARGS | Header 白名单、body 大小、Content-Type、method 与生成契约。 |
| Cookie 在另一个 origin 可见 | CookieJar 是否按应用与 origin 隔离,清理命令是否携带正确 origin。 |
| 进度事件频率过高 | 宿主节流阈值、事件载荷大小、订阅表与 windowId。 |
| 取消后仍写入文件 | 取消令牌、后台任务所有权、销毁后迟到响应抑制和临时文件清理。 |
| 大响应为空或截断 | { file } 句柄、虚拟路径、64 KiB 消息边界和读取权限。 |
| Android 下载与 Windows 行为不同 | 两端传输事件形状、系统下载回调、重定向和取消幂等语义。 |
pnpm validate:protocol、pnpm codegen、pnpm typecheck、pnpm test:contract、pnpm test:packages 通过;生成契约与平台矩阵无漂移。{ file } 和系统下载。http.download 的现有语义;capabilities.query、事件订阅、权限校验和线上文档结论一致。addJavascriptInterface,不引入 Rust/Node 中间 runtime,不写前端平台分支。
评论