IIS 错误地解码包含系统区域设置之外的字符的 URL
IIS incorrectly decodes URLs containing characters outside the system locale
如果 URL 包含当前系统区域设置不支持的 UTF-8 编码字符,IIS 似乎会错误地将请求 URL 传递给 Web 应用程序。所有 "unsupported" 个字符都替换为问号 ('?')。
示例:系统区域设置为挪威语。
以下 URL 工作正常:
/myapp/Blåbærsyltetøy/
以下URL不工作:
/myapp/черничный-джем/
在这两个 URL 中,非 ASCII 字符都被编码为 UTF-8,然后进行百分号编码,所以实际的 URL 看起来像这样:
/myapp/Bl%C3%A5b%C3%A6rsyltet%C3%B8y/
/myapp/%D1%87%D0%B5%D1%80%D0%BD%D0%B8%D1%87%D0%BD%D1%8B%D0%B9-%D0%B4%D0%B6%D0%B5%D0%BC/
应用程序使用两种方式处理请求:
- wfastcgi + Python
- ISAPI + C++
两者都遇到同样的问题,如果 URL 仅包含系统区域设置支持的字符,则两者都没有问题。
在 ISAPI 的情况下,EXTENSION_CONTROL_BLOCK::lpszPathInfo
似乎已经提供了百分比解码的 URL,其中所有 "unsupported" 字符都已被问号替换。 EXTENSION_CONTROL_BLOCK::lpszPathInfo
属性是多字节字符串,没有宽字符串版本的结构。
有没有办法获取原始的百分比编码 URL 或阻止 IIS 解码 URLs 来解决该问题?
ISAPI 解决方案
从服务器变量 HTTP_URL
而不是 PATH_INFO
获取请求 URL。这提供了原始的百分比编码 URL,然后可以正确解码(通过百分比解码为字节数组并将该字节数组解释为 UTF-8 编码的字符串)。
此变量包含查询字符串和URL重写前的原始路径,可能不需要,因此可能需要一些额外的处理。
此外,对于错误处理程序请求,此变量包含格式类似于
的字符串
<DLL_PATH>?<STATUS_CODE>;<ORIGINAL_HTTP_URL>
需要解析。但它包含 PATH_INFO
包含的所有信息,除了没有错误解码。
注意:使用 GetServerVariable
而不是从 EXTENSION_CONTROL_BLOCK
结构获取 Path_INFO
不会 解决编码问题。
wfastcgi的解决方案
服务器变量默认使用系统语言环境编码(在Python中称为'mbcs'
)。可以通过设置注册表项来更改此行为:
reg add HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\w3svc\Parameters /v FastCGIUtf8ServerVariables /t REG_MULTI_SZ /d REQUEST_URI[=11=]PATH_INFO
请注意,这将影响同一服务器上的所有 wfastcgi 应用程序,并且可能会破坏不希望变量采用 UTF-8 编码的现有应用程序(不太可能,因为任何使用非 ASCII 的理智应用程序 URLs 将使用 UTF-8 编码...)。
如果 URL 包含当前系统区域设置不支持的 UTF-8 编码字符,IIS 似乎会错误地将请求 URL 传递给 Web 应用程序。所有 "unsupported" 个字符都替换为问号 ('?')。
示例:系统区域设置为挪威语。 以下 URL 工作正常:
/myapp/Blåbærsyltetøy/
以下URL不工作:
/myapp/черничный-джем/
在这两个 URL 中,非 ASCII 字符都被编码为 UTF-8,然后进行百分号编码,所以实际的 URL 看起来像这样:
/myapp/Bl%C3%A5b%C3%A6rsyltet%C3%B8y/
/myapp/%D1%87%D0%B5%D1%80%D0%BD%D0%B8%D1%87%D0%BD%D1%8B%D0%B9-%D0%B4%D0%B6%D0%B5%D0%BC/
应用程序使用两种方式处理请求:
- wfastcgi + Python
- ISAPI + C++
两者都遇到同样的问题,如果 URL 仅包含系统区域设置支持的字符,则两者都没有问题。
在 ISAPI 的情况下,EXTENSION_CONTROL_BLOCK::lpszPathInfo
似乎已经提供了百分比解码的 URL,其中所有 "unsupported" 字符都已被问号替换。 EXTENSION_CONTROL_BLOCK::lpszPathInfo
属性是多字节字符串,没有宽字符串版本的结构。
有没有办法获取原始的百分比编码 URL 或阻止 IIS 解码 URLs 来解决该问题?
ISAPI 解决方案
从服务器变量 HTTP_URL
而不是 PATH_INFO
获取请求 URL。这提供了原始的百分比编码 URL,然后可以正确解码(通过百分比解码为字节数组并将该字节数组解释为 UTF-8 编码的字符串)。
此变量包含查询字符串和URL重写前的原始路径,可能不需要,因此可能需要一些额外的处理。
此外,对于错误处理程序请求,此变量包含格式类似于
的字符串<DLL_PATH>?<STATUS_CODE>;<ORIGINAL_HTTP_URL>
需要解析。但它包含 PATH_INFO
包含的所有信息,除了没有错误解码。
注意:使用 GetServerVariable
而不是从 EXTENSION_CONTROL_BLOCK
结构获取 Path_INFO
不会 解决编码问题。
wfastcgi的解决方案
服务器变量默认使用系统语言环境编码(在Python中称为'mbcs'
)。可以通过设置注册表项来更改此行为:
reg add HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\w3svc\Parameters /v FastCGIUtf8ServerVariables /t REG_MULTI_SZ /d REQUEST_URI[=11=]PATH_INFO
请注意,这将影响同一服务器上的所有 wfastcgi 应用程序,并且可能会破坏不希望变量采用 UTF-8 编码的现有应用程序(不太可能,因为任何使用非 ASCII 的理智应用程序 URLs 将使用 UTF-8 编码...)。