Zephyr HTTP 服务:从固件到网页、动态接口和 WebSocket

来源:Zephyr Project 的 HTTP Server 示例文档。本文依据官方仓库 v4.4.0 完整 README,并核对同版本源码、网页资源、Kconfig 和构建配置。以下为中文译编与明确标注的源码说明,运行路径限定在隔离网络中的 QEMU HTTP 示例。

这个示例把静态网页、动态 GET/POST 处理和 WebSocket 放在同一份固件中。Zephyr 的 HTTP server 库负责高层服务接口,应用只需声明资源、支持的方法与回调。服务支持 HTTP/1.1,也支持升级到 HTTP/2,以及直接使用 HTTP/2。

学习它最有用的方式,是追踪浏览器请求怎样找到固件里的资源,再看响应如何回到页面。本文只做了静态审查,未安装 SDK、构建、启动 QEMU、修改路由或烧录设备;下文“应返回”的内容是依据源码推导的核对目标,不是测试结果。

Zephyr HTTP服务资源图:静态HTML和JavaScript在构建时压缩嵌入,运行时提供uptime、dynamic和led接口;WebSocket根路径推送统计,ws_echo负责回显。
根据 v4.4.0 源码绘制的资源与请求路径,不是运行截图。绘制:未完纪编辑部。

先锁版本,再准备隔离的 QEMU 网络

sample.yaml 指定需要网络接口,并将最低 RAM 条件设为 192 KB;这不是任意硬件上都能运行的承诺。应固定 Zephyr v4.4.0 以及该版本 west 清单对应的模块,使用已配置好的 SDK 与构建环境。

原文把 QEMU 网络设置列为前置条件。同版本说明使用 Linux 宿主,通过辅助 socket、SLIP/TAP 把宿主与 QEMU 连接。按该说明,在 net-tools 目录的两个终端分别启动 ./loop-socat.sh 与 sudo ./loop-slip-tap.sh,再在已初始化 Zephyr 开发环境的终端构建运行。

编辑边界:这些辅助程序会影响网络设备或路由,适合在专用测试虚拟机中准备。先核对本机已有地址和路由,避免与示例的 192.0.2.1/2、2001:db8::1/2 冲突。本文只需要宿主与示例互通,不要求按网络指南额外开启 Internet NAT 或宿主转发。

下面把原文的板型占位参数具体化为 QEMU 指南使用的 qemu_x86,并增加独立构建目录;这是编辑改写,未构建验证。-p auto 可能清理不匹配的构建缓存,目录应确认为本次示例专用。

# 在固定到 Zephyr v4.4.0 且已配置 SDK/模块的源码根目录中
# 编辑改写:显式选择 qemu_x86,并使用独立构建目录
west build -p auto -b qemu_x86 -d build/http-server samples/net/sockets/http_server
west build -d build/http-server -t run

默认配置 prj.conf 使用服务器 IPv4 地址 192.0.2.1,对端与网关为 192.0.2.2。Kconfig 默认开启 HTTP 服务、使用端口 80,并开启 WebSocket 服务。没有真实 LED 的 QEMU 平台上,控制请求可能只对应日志;不要把日志或 HTTP 响应理解为硬件已经点亮。

网页怎样成为固件资源

CMakeLists.txt 将 src/static_web_resources/index.html 和 main.js 压缩为 gzip,再生成 .gz.inc 文件。main.c 把这些文件包含进字节数组,以静态资源注册,并分别声明 text/html、text/javascript 内容类型和 gzip 内容编码。

资源通过 HTTP_RESOURCE_DEFINE 绑定到服务和 URL;链接段配置负责组织相应资源描述。因此只创建一个 HTML 文件还不够,构建生成步骤、C 数组、资源注册与链接配置必须互相对应。

路径与方式 v4.4.0 源码中的行为
GET / 返回压缩的首页。
GET /main.js 返回压缩的网页脚本。
GET /uptime 返回设备运行毫秒数的十进制文本。
GET 或 POST /dynamic 把接收到的数据分块回显给客户端。
POST /led 解析 led_num 和 led_state,再请求对应 LED 开关动作。
WebSocket /ws_echo 接收并回显客户端数据。
WebSocket / 周期性向客户端发送网络统计 JSON。

原文差异:README 在可配置参数说明中把根 WebSocket 端点描述为回显;同版本 main.c 实际把根路径注册给 ws_netstats_setup,而 /ws_echo 注册给 ws_echo_setup。本稿采用源码与网页脚本一致的行为,不沿用这处描述。

逐项检查请求,而不是只看首页

服务器准备好后,原文允许使用浏览器或 curl 请求 http://192.0.2.1/。curl 的 --compressed 用于协商并解压压缩内容。下面前三项之后的 LED 请求是依据源码整理的检查例子;都只面向隔离测试目标。

# 仅对隔离测试网络中的本例目标运行;不是本文实测结果
curl -v --compressed http://192.0.2.1/
curl -v http://192.0.2.1/uptime
curl -v -X POST --data-binary 'hello' http://192.0.2.1/dynamic
curl -v -X POST --data-binary '{"led_num":0,"led_state":true}' http://192.0.2.1/led

首页应能显示示例界面;/uptime 应给出随运行推进的毫秒数;/dynamic 应回显传入的 hello。/led 的 HTTP 结果、解析日志和实际硬件动作是不同层次的证据,需要分别检查。

原文还列出 HTTP/1.1 的 Apache Bench,以及 HTTP/2 的 nghttp、curl --http2 和 h2load。是否可用取决于客户端是否具备对应协议能力。它们可以用于请求与负载观察,但本文没有进行压测,也没有吞吐量结论。

动态回调需要处理分块与完成状态

echo_handler 读入请求片段后直接把片段作为响应体,并根据 HTTP_SERVER_REQUEST_DATA_FINAL 设置最后一块标记。事务完成或中止时,它会重置统计状态。这展示了动态资源不必等整个请求到齐才返回数据。

uptime_handler 不期待 GET 请求体,在最后一次回调才格式化 k_uptime_get() 并设置响应。网页脚本每秒请求一次该端点,把数值显示为毫秒。

led_handler 使用 32 字节缓冲区累积可能分块到达的 POST 请求,超过容量时返回错误;最终片段到达后,json_obj_parse 要求 led_num 和 led_state 都能解析。静态发现:应用层没有额外验证 LED 编号是否在允许范围,也没有检查 led_on、led_off 的返回值。因此“JSON 被解析”不能代替设备操作成功的确认。

生产改造应补上资源范围、设备状态和驱动返回值处理,并让错误体与状态码表达实际结果。上述是待实现的改进方向,本文没有提交或测试修改后的固件,也没有把共享静态缓冲区推断成已证实的并发漏洞。

两个 WebSocket 用途

回显服务把升级后的连接交给独立处理线程,通过 socket 接口接收和发送数据。CONFIG_NET_SAMPLE_NUM_WEBSOCKET_HANDLERS 默认是 1;增加处理数量会增加线程栈和连接资源占用,应按平台内存预算决定。

下面基于 README 的 websocket-client Python 示例整理。编辑改动是增加连接超时、用 finally 保证清理,并省去调试追踪,避免把所有交互内容写入调试日志。它依赖相应库,本文未安装或执行。

# 原 README 的 websocket-client 客户端例;编辑增补超时和 finally 清理
import websocket

ws = websocket.WebSocket()
try:
    ws.connect("ws://192.0.2.1/ws_echo", timeout=5)
    ws.send("Hello, Server")
    print(ws.recv())
    while True:
        line = input("> ")
        if line == "quit":
            break
        ws.send(line)
        print(ws.recv())
finally:
    ws.close()

统计服务则运行在工作队列上,从 Zephyr 网络统计接口采集接收/发送字节数、IPv4/IPv6 包数和 TCP 字节数,按 JSON 推送给浏览器。Kconfig 的 CONFIG_NET_SAMPLE_WEBSOCKET_STATS_INTERVAL 默认是 200 毫秒。发送失败会清理连接;实际调度间隔和网络延迟不是固定性能保证。

浏览器写入点的静态安全改进

原 main.js 用 innerHTML 写入 uptime 和统计值。在这份示例中,服务端生成的是数值;本次没有证实能把用户任意字符串直接送到这些位置。但 innerHTML 是 HTML 解析入口,若将来改为不可信字符串或数据来源发生变化,就会产生注入风险。纯文本显示无需使用它。

下面为编辑提供的局部修订思路:只接受有限数值,再用 textContent 写入。它与上游代码有明确差异,并未执行验证;不应被称为完整的 XSS 修复或全面安全审计。

// 编辑修订片段:替换原 setNetStat;未实测
function setNetStat(jsonData, statName) {
    const value = jsonData[statName];
    if (typeof value !== "number" || !Number.isFinite(value)) {
        return;
    }
    const target = document.getElementById(statName);
    if (target) {
        target.textContent = String(value);
    }
}
// fetchUptime() 中同样先确认 json 是有限数值,再用:
uptime.textContent = "Uptime: " + json + " milliseconds";

/dynamic 本来就回显请求数据,不能把回显内容当成可信 HTML。若继续开发,应明确响应类型和使用位置。当前示例的 LED 控制、回显和统计端点没有展示业务身份认证或授权机制,所以要限制在测试网络;仅添加 TLS 也不会自动获得业务鉴权。

可配置项与本文不采用的变体

可在 west build -t menuconfig 中修改服务端口、HTTP/2 客户端数量、每个客户端的最大流数、客户端缓冲区大小、URL 长度上限和 WebSocket 开关。客户端缓冲区同时限制单个 HTTP 头能够支持的长度。这些限制需要结合请求大小和内存资源调整。

原文还列出 IEEE 802.15.4、USB 网络、TLS 和 DHCPv4 的 overlay。USB 演示段仍使用 overlay-netusb.conf,而同版配置表和 sample.yaml 使用 overlay-usbd.conf;因此本稿不提供未经消解的 USB 构建路径。原 USB 段还出现与其实际示例地址不一致的网段文字,地址冲突检查应以真实配置为准。

浏览器使用 HTTP/2 时,原文要求 HTTPS、ALPN,以及浏览器信任的服务器证书,并提供生成示例 CA 和服务器证书的构建目标。README 还提到修改 Firefox TLS profile 检查;本稿不采用降低浏览器安全检查的做法。证书实验如有需要,应单独在隔离环境中处理,不能把示例 CA 加入日常系统信任作为常规步骤。

prj.conf 启用 CONFIG_TEST_RANDOM_GENERATOR。构建配置还会生成演示 DER 证书和私钥的包含文件;启用相应 PSK 选项时,Kconfig 默认提供 dummy_psk.h,CMake 有开发专用警告。它们都是演示边界,不能成为生产密钥材料。本文没有下载私钥或 PSK 文件,也没有把其内容写入交付。

性能观察与退出

原文的性能章节面向运行在 native_sim 的服务,可用 perf stat 对目标进程统计 CPU,用 perf record -g 记录调用栈,再通过 perf report 查看热点。记录也可经 FlameGraph 工具的 stackcollapse-perf.pl 与 flamegraph.pl 转成火焰图。这里没有实际分析数据,这些步骤也不是 QEMU HTTP 功能检查的结果。

进程 PID、输出文件位置和 profiling 权限必须来自当前隔离测试环境;不要把历史 PID 贴到生产机器上。网络实验结束后,按 QEMU 指南在对应终端停止两个辅助程序,避免留下路由或地址冲突;指南提供的 QEMU 退出键是 Ctrl+A 后按 x。

来源与许可:文档维护方 Zephyr Project,原 README 未列个人作者。所核源码中保留的归属包括 Emna Rekik(2023)、Nordic Semiconductor(2024)和 Witekio(2024),对应文件标注 Apache-2.0;完整上游 LICENSE 见下方。本文未复制源码私钥或第三方网页脚本,中文译编、原创配图和标明的编辑改动由未完纪编辑部整理。所有代码只经过静态阅读,未发现问题不代表不存在漏洞。

原README的命令与客户端对照

以下是原文各变体的原始展示片段,供理解源文,不是已经验证的执行步骤。本文主线仍限定QEMU本地HTTP;TLS/USB需要独立核验,尤其不能把演示CA加入日常信任或降低浏览器安全检查。占位PID/板型和输出文件不得照抄到生产系统。

原文片段 1

   $ west build -p auto -b <board_to_use> -t run samples/net/sockets/http_server

原文片段 2

   $ west build -p auto -b <board_to_use> -t run --test samples/net/sockets/http_server/sample.net.sockets.https.server

原文片段 3

   $ west build -b <board_to_use> -t sample_ca_cert samples/net/sockets/http_server

原文片段 4

   $ west build -t sample_server_cert samples/net/sockets/http_server

原文片段 5

   $ west build samples/net/sockets/http_server

原文片段 6

   import websocket

   websocket.enableTrace(True)
   ws = websocket.WebSocket()
   ws.connect("ws://192.0.2.1/ws_echo")
   ws.send("Hello, Server")
   print(ws.recv())
   while True:
     line = input("> ")
     if line == "quit":
       break
     ws.send(line)
     print(ws.recv())
   ws.close()


原文片段 7

   $ ip link show

原文片段 8

   $ sudo ip addr add 192.0.2.2/24 dev eth-device
   $ sudo ip route add 192.0.2.0/24 dev eth-device

原文片段 9

   $ curl -v --compressed http://192.0.2.1
   $ curl -v --compressed https://192.0.2.1

原文片段 10

   $ sudo perf stat -p <pid_of_server>

原文片段 11

   $ sudo perf record -g -p <pid_of_server> -o perf.data

原文片段 12

   $ sudo perf report -i perf.data

原文片段 13

   $ sudo perf script | ~/FlameGraph/stackcollapse-perf.pl > out.perf-folded

原文片段 14

   $ ~/FlameGraph/flamegraph.pl out.perf-folded > flamegraph.svg

补充静态发现:ws.c 的 netstats_collect 未检查 net_mgmt 返回值,读取的统计结构未在调用前显式初始化,错误路径需补处理;sendall 只检查负值,若发送返回0则不能推进循环;main也未处理init_usb和http_server_start的失败返回。这些是待验证的健壮性问题,不是已重现的漏洞结论。

Apache License 2.0 全文

                                 Apache License
                           Version 2.0, January 2004
                        http://www.apache.org/licenses/

   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION

   1. Definitions.

      "License" shall mean the terms and conditions for use, reproduction,
      and distribution as defined by Sections 1 through 9 of this document.

      "Licensor" shall mean the copyright owner or entity authorized by
      the copyright owner that is granting the License.

      "Legal Entity" shall mean the union of the acting entity and all
      other entities that control, are controlled by, or are under common
      control with that entity. For the purposes of this definition,
      "control" means (i) the power, direct or indirect, to cause the
      direction or management of such entity, whether by contract or
      otherwise, or (ii) ownership of fifty percent (50%) or more of the
      outstanding shares, or (iii) beneficial ownership of such entity.

      "You" (or "Your") shall mean an individual or Legal Entity
      exercising permissions granted by this License.

      "Source" form shall mean the preferred form for making modifications,
      including but not limited to software source code, documentation
      source, and configuration files.

      "Object" form shall mean any form resulting from mechanical
      transformation or translation of a Source form, including but
      not limited to compiled object code, generated documentation,
      and conversions to other media types.

      "Work" shall mean the work of authorship, whether in Source or
      Object form, made available under the License, as indicated by a
      copyright notice that is included in or attached to the work
      (an example is provided in the Appendix below).

      "Derivative Works" shall mean any work, whether in Source or Object
      form, that is based on (or derived from) the Work and for which the
      editorial revisions, annotations, elaborations, or other modifications
      represent, as a whole, an original work of authorship. For the purposes
      of this License, Derivative Works shall not include works that remain
      separable from, or merely link (or bind by name) to the interfaces of,
      the Work and Derivative Works thereof.

      "Contribution" shall mean any work of authorship, including
      the original version of the Work and any modifications or additions
      to that Work or Derivative Works thereof, that is intentionally
      submitted to Licensor for inclusion in the Work by the copyright owner
      or by an individual or Legal Entity authorized to submit on behalf of
      the copyright owner. For the purposes of this definition, "submitted"
      means any form of electronic, verbal, or written communication sent
      to the Licensor or its representatives, including but not limited to
      communication on electronic mailing lists, source code control systems,
      and issue tracking systems that are managed by, or on behalf of, the
      Licensor for the purpose of discussing and improving the Work, but
      excluding communication that is conspicuously marked or otherwise
      designated in writing by the copyright owner as "Not a Contribution."

      "Contributor" shall mean Licensor and any individual or Legal Entity
      on behalf of whom a Contribution has been received by Licensor and
      subsequently incorporated within the Work.

   2. Grant of Copyright License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      copyright license to reproduce, prepare Derivative Works of,
      publicly display, publicly perform, sublicense, and distribute the
      Work and such Derivative Works in Source or Object form.

   3. Grant of Patent License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      (except as stated in this section) patent license to make, have made,
      use, offer to sell, sell, import, and otherwise transfer the Work,
      where such license applies only to those patent claims licensable
      by such Contributor that are necessarily infringed by their
      Contribution(s) alone or by combination of their Contribution(s)
      with the Work to which such Contribution(s) was submitted. If You
      institute patent litigation against any entity (including a
      cross-claim or counterclaim in a lawsuit) alleging that the Work
      or a Contribution incorporated within the Work constitutes direct
      or contributory patent infringement, then any patent licenses
      granted to You under this License for that Work shall terminate
      as of the date such litigation is filed.

   4. Redistribution. You may reproduce and distribute copies of the
      Work or Derivative Works thereof in any medium, with or without
      modifications, and in Source or Object form, provided that You
      meet the following conditions:

      (a) You must give any other recipients of the Work or
          Derivative Works a copy of this License; and

      (b) You must cause any modified files to carry prominent notices
          stating that You changed the files; and

      (c) You must retain, in the Source form of any Derivative Works
          that You distribute, all copyright, patent, trademark, and
          attribution notices from the Source form of the Work,
          excluding those notices that do not pertain to any part of
          the Derivative Works; and

      (d) If the Work includes a "NOTICE" text file as part of its
          distribution, then any Derivative Works that You distribute must
          include a readable copy of the attribution notices contained
          within such NOTICE file, excluding those notices that do not
          pertain to any part of the Derivative Works, in at least one
          of the following places: within a NOTICE text file distributed
          as part of the Derivative Works; within the Source form or
          documentation, if provided along with the Derivative Works; or,
          within a display generated by the Derivative Works, if and
          wherever such third-party notices normally appear. The contents
          of the NOTICE file are for informational purposes only and
          do not modify the License. You may add Your own attribution
          notices within Derivative Works that You distribute, alongside
          or as an addendum to the NOTICE text from the Work, provided
          that such additional attribution notices cannot be construed
          as modifying the License.

      You may add Your own copyright statement to Your modifications and
      may provide additional or different license terms and conditions
      for use, reproduction, or distribution of Your modifications, or
      for any such Derivative Works as a whole, provided Your use,
      reproduction, and distribution of the Work otherwise complies with
      the conditions stated in this License.

   5. Submission of Contributions. Unless You explicitly state otherwise,
      any Contribution intentionally submitted for inclusion in the Work
      by You to the Licensor shall be under the terms and conditions of
      this License, without any additional terms or conditions.
      Notwithstanding the above, nothing herein shall supersede or modify
      the terms of any separate license agreement you may have executed
      with Licensor regarding such Contributions.

   6. Trademarks. This License does not grant permission to use the trade
      names, trademarks, service marks, or product names of the Licensor,
      except as required for reasonable and customary use in describing the
      origin of the Work and reproducing the content of the NOTICE file.

   7. Disclaimer of Warranty. Unless required by applicable law or
      agreed to in writing, Licensor provides the Work (and each
      Contributor provides its Contributions) on an "AS IS" BASIS,
      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
      implied, including, without limitation, any warranties or conditions
      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
      PARTICULAR PURPOSE. You are solely responsible for determining the
      appropriateness of using or redistributing the Work and assume any
      risks associated with Your exercise of permissions under this License.

   8. Limitation of Liability. In no event and under no legal theory,
      whether in tort (including negligence), contract, or otherwise,
      unless required by applicable law (such as deliberate and grossly
      negligent acts) or agreed to in writing, shall any Contributor be
      liable to You for damages, including any direct, indirect, special,
      incidental, or consequential damages of any character arising as a
      result of this License or out of the use or inability to use the
      Work (including but not limited to damages for loss of goodwill,
      work stoppage, computer failure or malfunction, or any and all
      other commercial damages or losses), even if such Contributor
      has been advised of the possibility of such damages.

   9. Accepting Warranty or Additional Liability. While redistributing
      the Work or Derivative Works thereof, You may choose to offer,
      and charge a fee for, acceptance of support, warranty, indemnity,
      or other liability obligations and/or rights consistent with this
      License. However, in accepting such obligations, You may act only
      on Your own behalf and on Your sole responsibility, not on behalf
      of any other Contributor, and only if You agree to indemnify,
      defend, and hold each Contributor harmless for any liability
      incurred by, or claims asserted against, such Contributor by reason
      of your accepting any such warranty or additional liability.

   END OF TERMS AND CONDITIONS

   APPENDIX: How to apply the Apache License to your work.

      To apply the Apache License to your work, attach the following
      boilerplate notice, with the fields enclosed by brackets "{}"
      replaced with your own identifying information. (Don't include
      the brackets!)  The text should be enclosed in the appropriate
      comment syntax for the file format. We also recommend that a
      file or class name and description of purpose be included on the
      same "printed page" as the copyright notice for easier
      identification within third-party archives.

   Copyright {yyyy} {name of copyright owner}

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容