项目

常规

个人资料

操作

在 Windows 上构建 lighttpd

lighttpd 原生 _WIN32

lighttpd 原生 _WIN32 可以使用 autotools 或 CMake,配合 mingw(cygwin 或 msys)或 MS Visual Studio 编译器工具链进行静态或共享(dll)构建。

lighttpd 原生 _WIN32 限制

  • 未实现
    - server.c: 不支持守护进程化,但可以作为 Windows 服务安装
    - server.c: 不支持多工作进程
    - server.c: 不支持 lighttpd -1 一次性模式
    - log.c: 不支持 syslog 选项(不支持 Windows 事件日志)
  • _WIN32 接受 /\ 作为路径分隔符
    lighttpd 代码尚未经过审查,以将 _WIN32 的 \ 规范化为 /
    (可能存在安全漏洞)
  • _WIN32 环境变量路径可能以卷标 C:/ 开头,而不是 /
    (可能存在安全漏洞)
    lighttpd 代码尚未经过审查,以规范化 _WIN32 路径。
    lighttpd 代码在许多地方假定完整路径以 / 开头。
    lighttpd 可能无法跨多个卷工作。
  • _WIN32 NTFS 备用数据流未被拒绝
    (可能存在安全漏洞)
    https://redmine.lighttpd.ac.cn/issues/1335
  • _WIN32 文件系统函数未能正确处理 UTF-8
    (未定义 UNICODE 时 ASCII 有效;定义 UNICODE 时宽字符有效)
    fs_win32.[ch] 中提供了一些 UTF-8 到宽字符的兼容转换函数,
    但不全面。unlink()、rmdir()、chdir() 或其他函数未提供...
    (move、replace 等以及其他使用 _WIN32 ...A() 函数的地方可能需要
    替换为将 UTF-8 转换为宽字符并使用 ...W() 的函数)
  • 如果任一文件处于打开状态,NTFS 无法原子地重命名文件。
    lighttpd 在文件缓存中使用了这种惯用法(deflate.cache-dir 在 _WIN32 上已禁用)
    如果对打开的文件尝试 PUT 或 MOVE 操作,lighttpd mod_webdav 将失败。
    由于此 NTFS 限制,许多文件操作(除读取外)可能会失败。
  • lighttpd mod_webdav 尚未移植,将存在多个问题,
    包括但不限于原子文件重命名、非 ASCII UTF-8 文件支持
  • lighttpd 不尝试检测 setCaseSensitiveInfo 目录属性
  • ...

Microsoft 的怪异之处

  • SOCKET(long long unsigned),而不是像 POSIX 文件描述符那样的 (int)
    实际上(样本量 n=1),SOCKET 似乎小于 INT_MAX,除了
    INVALID_SOCKET ((long long unsigned)-1),它会强制转换为 (int)-1
    虽然似乎没有必要将所有代码重写为使用 SOCKET 而不是
    int,但如果这是真的,微软能将其文档化会很好。
    类型的尺寸(64 位)和符号(unsigned)都对代码移植不友好。
    据推测,历史上 SOCKET 是一个指针值
    强制转换为 (uintptr_t)(微软在类型安全方面做得好!)。在 32 位系统中,int 和
    指针大小相同,但在 64 位系统中则不同。这可能在
    微软演进的某个时候发生了变化,但没有得到很好的文档记录,因为至少最初的
    赋值是 200 和 300 左右的小整数。微软能够
    区分文件描述符 (int)(SOCKET),因为两者都
    SetHandleInformation()ReadFile()WriteFile() 支持,因此我们可以
    得出结论,微软没有在其他地方推广该逻辑,但可能可以。
    ((HANDLE)(uint64_t)sockfd); ((HANDLE)_get_osfhandle(fd)) (例如文件和管道)
  • SOCKET 和文件描述符不允许作为最低可用整数,
    因此使用文件描述符作为索引的数组不是一个好的应用模式。
  • select()WSAPoll() 仅适用于 SOCKET,不适用于文件或管道。
    (参见 WaitForSingleObject() WaitForMultipleObjects() 和相关函数)
    (另见 WSAEventSelect()+WSAWaitForMultipleEvents()
  • select() 不是位图;围绕 select() 的客户端代码通常需要
    返工。[1] FD_ISSET 等宏必须应用于 SOCKET,而不是
    任意整数,范围从 [0,FD_SETSIZE)。
    https://devblogs.microsoft.com/oldnewthing/20221102-00/?p=107343
    https://devblogs.microsoft.com/oldnewthing/20161221-00/?p=94985
  • 文件系统重定向(stdin/stdout/stderr)到套接字是可能的,但
    - 文件句柄必须可继承(默认)
    - 套接字必须是非重叠的(非默认)
    - socket() 创建带 WSA_FLAG_OVERLAPPED 标志的套接字
    - WSASocket() 有选项可以省略 WSA_FLAG_OVERLAPPED
  • 程序通常需要在环境中定义 SYSTEMROOT 才能正常运行
  • 必须在 #include <windows.h> 之前定义 #define WIN32_LEAN_AND_MEAN
    否则可能会导致(不希望的)winsock 1.1 头文件可见性
    https://learn.microsoft.com/zh-cn/windows/win32/winsock/creating-a-basic-winsock-application
    对于某些应用程序,#include <winsock2.h> 就足够了,无需 #include <windows.h>
    必须链接 -lws2_32
    #ifdef _MSC_VER
    #pragma comment(lib, "ws2_32.lib")
    #endif
  • 在非阻塞套接字上调用 connect() 失败时,WSAGetLastError() 会返回 WSAWOULDBLOCK
    而不是 EINPROGRESS
  • dup()dup2() 不能用于 SOCKET(参见 WSADuplicateSocket()
  • dup2() 不返回 newfd;接口不兼容
  • 如果字符串带有末尾的 /\,则对目录执行 stat() 会失败
  • 对 CGI PATH_INFOstat() 返回 ENOENT 而不是 ENOTDIR
    例如 /real/file.cgi/path/info
  • stat() 在 //?/c:/... 路径上失败
  • 错误代码:套接字使用 WSAGetLastError();不要检查 errno
  • 错误代码:GetLastError()(套接字除外),有时是 errno
  • Microsoft NTFS 不允许对打开的文件进行移动/重命名操作。
    (尝试这样做会导致“权限拒绝;文件已在使用中”。)
    如果旧文件或新文件处于打开状态,POSIX 中典型的原子重命名惯用法在 NTFS 上会失败。
    这在 lighttpd 的许多地方造成了问题,例如缓存更新时,新文件在重命名期间保持打开状态,然后提供给
    客户端。强制文件在重命名前后关闭再重新打开会引入竞态条件,影响最终发送给客户端的内容。
    客户端。强制关闭文件然后在大约重命名时重新打开
    重命名引入了一个竞态条件,这最终会发送给客户端。
    (虽然这种竞态条件出现在 mod_deflate 缓存中,但 mod_webdav 和其他
    模块可能仍会受此 NTFS 限制影响/失败。)
  • 如果定义了 _CRT_DECLARE_NONSTDC_NAMES,UCRT 的 <sys/types.h> 会无条件地将 off_t 定义为 long(在 _WIN32 上是 4 字节)。任何应用程序或库如果
    如果定义了 _CRT_DECLARE_NONSTDC_NAMES。任何应用程序或库如果
    支持大文件并期望 64 位 off_t,都需要采取措施来
    解决此问题(例如提前定义 off_t, _off_t, _OFF_T_DEFINED)。
  • ...

[1] https://learn.microsoft.com/en-us/windows/win32/winsock/select-and-fd---2

Select、FD_SET 和 FD_XXX 宏
由于套接字并非以 UNIX 风格的小型非负整数表示,Windows Sockets 中 select 函数的实现有所改变。每组套接字仍由 FD_SET 结构表示,但不再以位掩码形式存储,而是作为套接字数组实现。为避免潜在问题,应用程序必须遵循使用 FD_XXX 宏来设置、初始化、清除和检查 FD_SET 结构。

lighttpd cygwin

lighttpd cygwin 作为一组软件包通过 cygwin setup.exe 提供维护,支持 lighttpd 在类 Unix 系统上几乎所有相同的功能。然而,可能需要采取额外预防措施来保护 _WIN32 系统(参见下文),因此强烈建议您不要在生产环境中使用 lighttpd cygwin。

gstrauss6 个月前更新 · 12 次修订