来源: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、修改路由或烧录设备;下文“应返回”的内容是依据源码推导的核对目标,不是测试结果。

先锁版本,再准备隔离的 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。
原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.












暂无评论内容