Ruffle 中验证 AVM2 Loader/URLRequest 网络请求行为的测试指南:以 loader_load 回归测试为例 📅 发布时间:2026/9/13 10:56:15 👁 浏览次数: Ruffle 中验证 AVM2 Loader/URLRequest 网络请求行为的测试指南以 loader_load 回归测试为例【免费下载链接】ruffleA Flash Player emulator written in Rust项目地址: https://gitcode.com/GitHub_Trending/ru/ruffle导读本文以 loader_load 回归测试 为线索完整讲解如何在 Ruffle用 Rust 编写的 Flash Player 模拟器中验证 AVM2 的Loader.load/URLRequest实际发出的网络请求包括 HTTP 头含重复头合并规则、不同data类型的 POST 请求体序列化以及 Flash Player 沙箱下的网络访问信任配置。读完本文你将掌握该测试的启动方式、test.toml配置含义、期望输出格式以及 Ruffle 底层Navigator::fetch的实现路径能够自行复现与扩展类似的网络请求验证测试。一、测试背景为什么要验证实际发出的请求头Ruffle 作为 Flash Player 的替代实现必须精确还原flash.net.URLRequest与flash.display.Loader的网络行为——尤其是请求头Request Headers的合并规则和请求体Body的序列化格式。这些行为在浏览器环境Ruffle Web与桌面环境Ruffle Desktop中分别由不同的后端实现任何偏差都会导致依赖 HTTP 接口的旧 SWF 行为不一致。loader_load测试正是为此而生的回归测试它的 README 明确指出该测试的重点是验证实际通过网络发送的请求头To verify the actual headers sent over the network。与一般渲染类测试不同这个测试并不关心画面是否正确而是通过一个可观测的日志输出Navigator::fetch来断言 Ruffle 发出的 HTTP 请求细节。二、测试目录结构与角色分工该测试位于 tests/tests/swfs/avm2/loader_load遵循 Ruffle 回归测试的标准结构见 tests/README.md目录至少包含test.swf、test.toml、output.txt文件作用test.swf被测的 AVM2 SWF由test.fla/Test.as编译而来Test.as测试源码构造多种URLRequest并发起Loader.loadtest.toml测试运行配置帧数、网络日志开关output.txtRuffle 的期望输出含Navigator::fetch的完整请求快照server.pyPython HTTP 服务器监听localhost:8000回显收到的请求并返回测试图片/跨域策略test.png服务器返回的图片响应体供Loader加载test.flaFlash 源工程文件其中server.py是 README 推荐的手动验证工具它可以打印出每一次GET/POST的路径与全部请求头与output.txt中的日志相互印证实现Ruffle 视角与真实网络视角的双重验证。三、运行测试两种方式3.1 启动 HTTP 服务器README 给出的第一步是从测试目录启动server.py。该脚本基于 Python 标准库http.server实现无需第三方依赖cd tests/tests/swfs/avm2/loader_load python3 server.py启动后终端会输出Running server服务器在0.0.0.0:8000上常驻监听。其行为在 server.py 中定义do_GET打印GET: path headers默认返回test.pngContent-type: image/png并附带Access-Control-Allow-Origin: *当路径为/crossdomain.xml时返回一段允许domain*、file://*携带任意请求头的跨域策略 XMLdo_POST打印POST: path headers返回Content-type: WTF-image/png与Access-Control-Allow-Origin: *。需要说明的是server.py打印的是Python 端真实收到的原始请求而output.txt记录的是Ruffle 内部Navigator::fetch快照两者结合可交叉确认请求头没有被宿主网络栈静默改写。3.2 在 Flash Player 或 Ruffle Desktop 中运行服务器就绪后README 建议将test.swf在Flash Player或Ruffle Desktop player中打开Ruffle Desktop直接打开test.swf即可测试运行 10 帧后结束Flash Player需要先完成下面的信任配置否则 SWF 的网络请求会被沙箱拦截。运行过程中 SWF 会逐帧发起请求并在trace中输出测试序号与请求细节可对照 output.txt 检查结果。四、Flash Player 下的网络信任配置重点Flash Player 对本地/未签名 SWF 的网络访问有严格的沙箱限制。README 明确指出在 Flash Player 下运行test.swf时必须允许该 SWF 发起网络连接。在 Linux 上做法是创建信任配置文件/etc/adobe/FlashPlayerTrust/test.cfg内容为/ancestor/of/swf/path其中ancestor/of/swf/path必须是test.swf所在路径的任意祖先目录。例如若test.swf位于/home/username/ruffle/tests/...那么配置项填/home/username/即可README 原文示例即如此。FlashPlayerTrust目录下的.cfg文件会被 Flash Player 在启动时读取将其中的路径加入受信任的本地内容白名单从而豁免该路径下 SWF 的网络限制。提示Ruffle 本身不读取 FlashPlayerTrust 配置该机制是 Flash Player 专有的此步骤仅为在官方 Flash Player中对照验证而准备。测试本身以 Ruffle 行为为准见下一节。五、test.toml 配置解读num_frames 与 log_fetchtest.toml 只有三行却包含两个关键信息# Note that this test does not run successfully in Flash Player, its testing Ruffles navigator num_frames 10 log_fetch true注释声明该测试在 Flash Player 中不会成功运行——它的目的是测试Ruffle 的 navigator 后端。这意味着它属于Ruffle 自身行为的回归测试而非对齐 Flash 行为的兼容性测试。num_frames 10以帧为单位运行测试而非基于时间的num_ticks。根据 tests/README.md 的说明指定num_frames时 Ruffle 不会走 tick 调度而是直接调用run_frame本测试恰好让 SWF 在 10 帧内逐帧发起全部请求Test.as通过Event.ENTER_FRAME每帧发出一个请求。log_fetch true这是本测试的核心开关。在 tests/framework/src/options.rs 中log_fetch: bool默认值为false同文件 L142置为true后tests/framework/src/runner.rs 会把log注入TestNavigatorBackend使每次网络请求都被格式化为Navigator::fetch:快照写入 trace 输出与output.txt精确比对。六、测试用例详解Test.as 在验证什么Test.as 是测试的剧本。它在构造函数中构建了 6 个请求requests数组6.1 五种 POST 请求体data类型对method POST依次测试以下data值每个都指向http://localhost:8000#data 类型期望序列化结果0普通字符串foofoo1带toString()的对象baz调用其toString2查询字符串foobarfoobar3URLVariablesaaabbb、cccctruecccctrueaaabbb4ByteArray内容abab结合 output.txt 可见五种情况的Mime-Type均为application/x-www-form-urlencodedBody 分别为foo、baz、foobar、cccctrueaaabbb、ab——这直接验证了 Ruffle 对URLRequest.data的序列化策略字符串/可toString对象/ByteArray均按其文本内容发送URLVariables按属性序列化。6.2 请求头headers的合并规则每个请求都挂载了 7 个URLRequestHeaderheaders.push(new URLRequestHeader(MyHeader1, MyVal1)); headers.push(new URLRequestHeader(MyHeader2, MyVal2)); headers.push(new URLRequestHeader(MyHeader1, MyDuplicateVal)); headers.push(new URLRequestHeader(MyHeader3, MyVal3)); headers.push(new URLRequestHeader(MyHeader4, MyVal4)); headers.push(new URLRequestHeader(ANewHeader, MyVal4)); headers.push(new URLRequestHeader(SomeHeader, MyVal4)); request.requestHeaders headers;注意MyHeader1被赋值两次MyVal1与MyDuplicateVal。output.txt中最终快照显示MyHeader1: MyDuplicateVal——即同名字段后者覆盖前者其余头部按插入顺序保留。这正是该测试要锁定的关键行为Ruffle 必须与 Flash 保持一致的头部合并语义。6.3 DELETE 方法类型强制的失败路径最后一个用例构造了一个没有经过URLRequest构造器的对象var req {method: DELETE}; req.__prototype__ flash.net.URLRequest.prototype; requests.push(req);其目的是验证类型强制Type CoercionLoader.load期望严格的URLRequest实例通过__prototype__伪造原型并不会通过 AVM2 的类型检查。output.txt末尾的期望输出正是Test 5 TypeError: Error #1034: Type Coercion failed: cannot convert Object00000000000 to flash.net.URLRequest. at Test/onFrame()这属于故意触发的错误路径用例——确保 Ruffle 对非法参数抛出与 Flash 一致的TypeError #1034而不是静默接受或 panic。6.4 请求执行与监听每次请求通过new Loader()loader.load(request)发起并注册了SecurityErrorEvent.SECURITY_ERROR监听IOErrorEvent监听被注释掉。load前后还trace了// request.url、// request.data、// request.method与// loader.load(request)返回值始终是undefined构成output.txt中可读性极强的日志格式。七、期望输出解读Navigator::fetch 快照output.txt 是测试的黄金标准。以Test 0为例Test 0 // request.url http://localhost:8000 // request.data foo // request.method POST // loader.load(request) undefined Navigator::fetch: URL: http://localhost:8000 Method: POST Headers: MyHeader1: MyDuplicateVal MyHeader2: MyVal2 MyHeader3: MyVal3 MyHeader4: MyVal4 ANewHeader: MyVal4 SomeHeader: MyVal4 Mime-Type: application/x-www-form-urlencoded Body: foo格式约定// xxx行是Test.as中trace的输出来自 SWF 自身Navigator::fetch:块是 Ruffle 测试后端TestNavigatorBackend注入的请求快照按URL、Method、Headers、Mime-Type、Body五个维度完整记录由log_fetch true开启。测试框架会将该输出与output.txt逐行比对Test 5的TypeError栈帧则验证错误路径行为。对 Ruffle 而言任何对请求头合并、data序列化或类型强制的改动只要导致此处输出变化就会触发回归告警。八、底层原理从 Loader.load 到 Navigator::fetch从源码结构看Ruffle 的网络请求统一收敛到 Navigator 后端接口。在 core/src/loader.rs 中可以看到多个调用点例如Loader.load通过player.lock().unwrap().fetch(request, FetchReason::LoadSwf)L342、L696、L933发起 SWF 加载而URLRequest类FetchReason::Other也走同一条fetch通道L988、L1061、L1157音频等资源加载则通过uc.navigator.fetch(request)L1399直达 Navigator。Navigator::fetch是一个 trait 方法由各宿主桌面、Web、测试分别实现在回归测试中tests/framework/src/runner.rs 用TestNavigatorBackend替换真实网络后端并在log_fetch开启时把请求快照写入TestLogBackend从而形成output.txt中的Navigator::fetch:块在桌面与 Web 前端中则由各自的后端把请求交给系统 HTTP 栈或浏览器fetch真正发出。换言之loader_load测试验证的是与宿主无关的请求构造层headers、method、body、mime-type 的组装这正是 Flash 兼容性最容易出偏差、也最值得用快照锁死的部分。九、如何复现与扩展快速复现cd tests/tests/swfs/avm2/loader_load python3 server.py再用 Ruffle Desktop 打开同目录test.swf观察控制台输出是否与 output.txt 一致在 Flash Player 中对照按第四节配置/etc/adobe/FlashPlayerTrust/test.cfg并将服务器日志与output.txt对照——注意该测试本身声明在 Flash Player 中不会成功运行它锚定的是 Ruffle 自身行为作为 CI 回归测试Ruffle 测试框架会读取test.toml自动执行log_fetch true开启请求快照num_frames 10限定运行时长output.txt作为期望输出参与比对扩展思路在Test.as的datas/headers数组中追加新用例如Content-Type覆盖、空 body、GET方法重新编译 SWF 并更新output.txt即可将新的请求行为纳入回归保护。参考文件索引测试配置 test.toml、测试源码 Test.as、服务器脚本 server.py、期望输出 output.txt、测试框架说明 tests/README.md、配置结构定义 tests/framework/src/options.rs、运行器注入逻辑 tests/framework/src/runner.rs、Ruffle 侧请求入口 core/src/loader.rs。【免费下载链接】ruffleA Flash Player emulator written in Rust项目地址: https://gitcode.com/GitHub_Trending/ru/ruffle创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考