操作
在 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_INFO,stat()返回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。