OpenWRT(12):uhttpd主要功能以及客户端连接、CGI/Lua/UBUS/UCODE等处理
uhttpd是一个功能全面、轻量级的Web服务器,是Web管理界面LuCI的默认服务器,支持SSL、CGI、Lua。
uhttpd是单线程,但支持多个实例。
1 配置uhttpd
1.1 配置uhttpd
uhttpd配置如下:
Network Web Servers/Proxies uhttpd uhttpd-mod-lua--Lua插件为uHTTPd提供了一个类似于 CGI 的 Lua 运行时接口,使得开发者可以在处理 HTTP 请求时执行 Lua 脚本。这种集成方式允许开发者利用 Lua 的灵活性和强大功能来增强 Web 应用程序的能力,同时保持了与现有 CGI 程序类似的使用模式。 uhttpd-mod-ubus--提供ubus插件的功能。为 ubus 提供了一个基于 HTTP 协议和 JSON 格式的远程过程调用(RPC)代理。这意味着用户可以通过发送 HTTP 请求,并使用 JSON 格式编码数据,来远程调用 ubus 上的服务和函数。 uhttpd-mod-ucode--支持ucode脚本功能插件。 LuCI 3. Application luci-app-uhttpd Libraries Networking libuhttpd-mbedtls libuhttpd-nossl libuhttpd-openssl libuhttpd-wolfssl
1.2 uhttpd主要功能
uHTTPd 是 OpenWrt 项目中使用的轻量级 Web 服务器,专为嵌入式系统设计。以下是 uHTTPd 支持的一些关键功能:
-
HTTP 和 HTTPS 服务:uHTTPd 可以提供标准的 HTTP 服务,并且通过配置支持 HTTPS(HTTP over TLS/SSL),以确保数据传输的安全性。
-
CGI 脚本支持:uHTTPd 支持 CGI(Common Gateway Interface)脚本,允许执行外部程序或脚本,并返回其输出给客户端。
-
Lua 脚本支持:uHTTPd 内置了对 Lua 脚本语言的支持,可以在服务器上执行 Lua 脚本来生成动态内容。
-
模板处理:uHTTPd 支持使用模板来生成 Web 页面,这在动态内容生成中非常有用。
-
ubus 集成:uHTTPd 可以与 OpenWrt 的 ubus 消息总线系统集成,允许通过 Web 接口与系统服务进行交互。
-
JSON-RPC 支持:uHTTPd 支持 JSON-RPC 协议,允许通过 JSON 格式进行远程过程调用。
-
多实例运行:uHTTPd 可以运行多个实例,每个实例可以监听不同的端口,拥有独立的配置和文档根目录。
- 配置文件:uHTTPd 使用配置文件(通常是/etc/httpd.conf)来定义服务器的行为,包括端口、根目录、日志记录等。
-
访问控制:uHTTPd 支持基本的访问控制,例如基于 IP 的访问限制。
-
目录列表:uHTTPd 可以自动为包含多个文件的目录生成目录列表。
-
日志记录:uHTTPd 支持日志记录功能,可以记录访问和错误信息。
-
静态内容服务:uHTTPd 可以高效地提供静态内容,如 HTML、CSS、JavaScript 文件和图片。
-
自定义错误页面:uHTTPd 允许定义自定义的 404(未找到)和其他 HTTP 错误页面。
-
URL 重写:uHTTPd 支持 URL 重写规则,可以基于配置重定向请求。
-
文件上传:uHTTPd 支持通过 CGI 脚本进行文件上传。
-
代理服务器:uHTTPd 可以配置为代理服务器,转发请求到其他服务器。
-
IPv4 和 IPv6 支持:uHTTPd 支持 IPv4 和 IPv6 协议,可以同时服务于两种类型的网络请求。
1.3 uhttpd相关概念
Lua:Lua 是 OpenWrt 中广泛使用的一种轻量级脚本语言,它以其简洁和高效而闻名,非常适合用于配置和扩展 OpenWrt 系统的功能。
ubus:OpenWrt 的 UBUS(OpenWrt RPC API Server)是一个远程过程调用(RPC)API服务器,它提供了一种机制,允许用户通过各种协议(如HTTP、WebSocket等)与OpenWrt系统进行交互。
ucode:OpenWrt 的 ucode 是一种小型通用脚本语言,其语法与 ECMAScript 类似,可以独立使用,也可以嵌入到宿主应用程序中。ucode 设计的主要目标包括轻松读写 JSON 数据、易于嵌入 C 应用程序、模板功能、通过可加载的本地扩展模块扩展功能,以及一组直接模仿 Perl 5 语言的内置函数。
mbedtls:是一个由ARM维护的轻量级加密库,专为嵌入式系统设计。它提供了SSL/TLS协议的实现、加密库和X.509证书处理库。mbedTLS易于集成和配置,支持多种编译选项和硬件加速,适合资源受限的环境。
openssl:是一个广泛使用的开源加密库,提供了全面的加密功能,包括SSL/TLS协议、证书管理、各种加密算法等。OpenSSL支持多种平台,广泛应用于服务器、桌面和移动设备。
wolfssl:是一个轻量级的SSL/TLS库,专为嵌入式系统和资源受限环境设计。它提供了类似于OpenSSL的API,但更小、更快,且易于集成。wolfSSL支持最新的TLS 1.3和DTLS 1.2标准,以及多种先进的加密算法。
下面分别总资源占用、性能、易用性、支持比较mbedtls、openssl和wolfssl:
- 资源占用:mbedTLS和wolfSSL相对于OpenSSL来说,更加轻量级,占用资源更少,更适合嵌入式系统。
- 性能:wolfSSL在某些基准测试中显示出比OpenSSL更好的性能。
- 易用性:mbedTLS和wolfSSL都提供了简单的API和示例,易于集成和使用,而OpenSSL则提供了更广泛的功能和更复杂的配置选项。
- 支持:OpenSSL拥有一个成熟的社区和广泛的支持,而mbedTLS和wolfSSL虽然社区较小,但也在增长中,并提供了专业的技术支持。
2 uhttpd启动
执行/etc/init.d/S50uhttpd中脚本,启动uhttpd:
/usr/sbin/uhttpd -f -h /www -r OpenWrt -x /cgi-bin -l /cgi-bin/luci -L /usr/lib/lua/luci/sgi/uhttpd.lua -
uhttpd选项如下:
Usage: uhttpd -p [addr:]port -h docroot -f Do not fork to background -c file Configuration file, default is '/etc/httpd.conf' -p [addr:]port Bind to specified address and port, multiple allowed -s [addr:]port Like -p but provide HTTPS on this port -C file ASN.1 server certificate file -K file ASN.1 server private key file -P ciphers Colon separated list of allowed TLS ciphers -q Redirect all HTTP requests to HTTPS -h directory Specify the document root, default is '.' -E string Use given virtual URL as 404 error handler -b string Use given charset for directory listings, default to UTF-8 -I string Use given filename as index for directories, multiple allowed -S Do not follow symbolic links outside of the docroot -D Do not allow directory listings, send 403 instead -R Enable RFC1918 filter -n count Maximum allowed number of concurrent script requests -N count Maximum allowed number of concurrent connections -l string URL prefix for Lua handler -L file Path to Lua handler script, -l and -L may be repeated in pairs -o string URL prefix for ucode handler -O file Path to ucode handler script, -o and -O may be repeated in pairs -u string URL prefix for UBUS via JSON-RPC handler -U file Override ubus socket path -a Do not authenticate JSON-RPC requests against UBUS session api -X Enable CORS HTTP headers on JSON-RPC api -e Events subscription reconnection time (retry value) -x string URL prefix for CGI handler, default is '/cgi-bin' -y alias[=path] URL alias handle -i .ext=path Use interpreter at path for files with the given extension -t seconds CGI, Lua and UBUS script timeout in seconds, default is 60 -T seconds Network timeout in seconds, default is 30 -k seconds HTTP keepalive timeout -A seconds TCP keepalive timeout, default is unset -d string URL decode given string -r string Specify basic auth realm -m string MD5 crypt given string
3 uhttpd代码走读
uhttpd主要功能:
- 支持 HTTP/1.0 和 HTTP/1.1 协议,提供基本的 Web 服务功能。
- 支持 HTTPS,通过 TLS/SSL 协议提供安全的通信。
- 能够执行 CGI 脚本,为 Web 应用提供动态内容生成的能力。
- 通过插件支持 Lua 脚本,可以用于处理请求和生成动态内容。
- 支持与 OpenWrt 的 UBUS 系统集成,提供远程管理功能。
main
uh_dispatch_add--向服务器的调度系统添加一个新的处理程序。调度系统负责将请求分配给相应的处理程序。此处添加cgi_dispatch用于处理CGI请求。
init_defaults_pre--在解析配置文件之前,初始化默认的服务器配置。
uh_config_parse--解析服务器的配置文件(例如/etc/httpd.conf),配置服务器的行为,如认证、索引文件、解释器等。
uh_auth_add--向服务器添加基于路径的认证信息。
uh_index_add--设置目录索引文件,如index.html。
uh_interpreter_add--添加对特定文件扩展名的处理方式,例如为.php文件指定 CGI 解释器。
init_defaults_post--在解析配置文件之后,进行最后的默认配置初始化。
uh_index_add
uh_tls_init--初始化TLS(传输层安全性)支持,用于HTTPS连接。
uh_plugin_init--加载并调用插件init()初始化服务器插件,可以扩展服务器的功能。uhttpd_lua.so:加载Lua插件,允许使用Lua脚本处理请求。uhttpd_ubus.so:加载UBUS插件,提供对UBUS框架的支持。
dlopen--加载库文件。
dlsym--根据符号名找到函数。
p->init--执行插件的init函数进行初始化。
run_server--启动服务器的主函数,负责设置事件循环和启动服务器。
uloop_init
uh_setup_listeners--设置网络监听器,这些监听器等待客户端连接。
uh_plugin_post_init--在服务器设置监听器之后,执行插件的post_init()后续初始化操作。
uloop_run
3.1 CGI
cgi_dispatch用于处理CGI请求:
struct dispatch_handler cgi_dispatch = { .script = true, .check_path = check_cgi_path, .handle_request = cgi_handle_request, };
CGI执行流程如下:
cgi_handle_request
--权限检查,如果失败调用uh_client_error返回403错误。
uh_create_process--如果权限验证通过,uh_create_process函数被调用来创建一个新的进程,用于执行 CGI 脚本。
cgi_main
clearenv
setenv
execl
uh_client_error--如果CGI脚本无法启动,例如因为找不到脚本或权限问题,uh_client_error函数将被调用,向客户端返回一个500错误(Internal Server Error)。
3.2 ubus
ubus插件的初始化入口:
struct uhttpd_plugin uhttpd_plugin = { .init = uh_ubus_plugin_init,--ubus_connect()创建到ubus的连接上下文;注册ubus_dispatch。 .post_init = uh_ubus_post_init, };
ubus作为插件,在初始化时将注册ubus_dispatch。ubus_dispatch用于处理到uhttpd的UBUS请求:
static struct dispatch_handler ubus_dispatch = { .check_url = uh_ubus_check_url, .handle_request = uh_ubus_handle_request, };
通过uhttpd对UBUS请求处理如下:
uh_ubus_handle_request
UH_HTTP_MSG_GET--如果请求方法是GET,函数将调用uh_ubus_handle_get来处理请求。
uh_ubus_handle_get
UH_HTTP_MSG_POST--如果请求方法是POST,函数将初始化数据发送函数uh_ubus_data_send并准备接收POST数据。
UH_HTTP_MSG_OPTIONS--对于OPTIONS请求,函数将发送一个空的200 OK响应,表示服务器支持跨域请求。
3.3 lua
lua_dispatch处理uhttpd收到的lua请求,执行lua脚本:
static struct dispatch_handler lua_dispatch = { .script = true, .check_url = check_lua_url, .handle_request = lua_handle_request, };
lua请求处理:
lua_handle_request
create_process
lua_main
lua_pcall--以保护模式执行 Lua 函数调用,这意味着如果 Lua 函数中发生错误,lua_pcall会捕获错误并提供错误处理机制,而不是让错误直接导致宿主程序崩溃。
3.4 ucode
ucode_dispatch处理uhttpd收到的对ucode请求:
static struct dispatch_handler ucode_dispatch = { .script = true, .check_url = check_ucode_url, .handle_request = ucode_handle_request, };
ucode请求处理:
ucode_handle_request
create_process
ucode_main
uc_vm_invoke--UCode 虚拟机中用于调用函数的方法。