【问题标题】:Handler has a bad module "WebSocketModule" in its module list处理程序的模块列表中有一个错误的模块“WebSocketModule”
【发布时间】:2020-04-13 11:28:48
【问题描述】:

在 64 位 Windows 10 和 IIS 10 上,我正在尝试开发和测试一个本机 HTTP 模块,该模块将充当一组特定脚本文件的 WebSockets 处理程序映射。这都是从 RegisterModule() 开始的原生 C++ 中的。我没有使用 ASP.NET 的任何部分。

当我访问应该调用处理程序的 URL 时,我会收到以下响应:

HTTP 错误 500.21 - 内部服务器错误

处理程序“QuadooWebSocket”的模块列表中有一个错误的模块“WebSocketModule”

详细错误信息:

模块 IIS Web Core
通知 ExecuteRequestHandler
处理程序 QuadooWebSocket
错误代码 0x8007000d

更多信息:

IIS 核心无法识别该模块。

我使用 IIS 管理器来设置处理程序映射,它在 applicationHost.config 文件中创建了一个条目。

        <handlers accessPolicy="Read, Script">
            <other_modules />
            <add name="QuadooWebSocket" path="*.qws" verb="*" modules="WebSocketModule" scriptProcessor="E:\dev\projects\trunk\target\debug\ActiveQuadoo.dll" resourceType="File" preCondition="bitness32" />
        </handlers>

在此之前,我使用“Windows 功能”控制面板安装了对 WebSockets 的支持,它还在 applicationHost.config 文件中添加了一行。

        <globalModules>
            <other_modules />
            <add name="WebSocketModule" image="%windir%\System32\inetsrv\iiswsock.dll" />
        </globalModules>

当我将 Visual Studio 附加到 w3wp.exe 时,我的代码中的任何断点都没有得到解析。未调用 RegisterModule()。 DllMain() 甚至没有被调用。我的模块还实现了 IActiveScript,并且 IIS 确实为经典的 ASP 请求加载了我的模块。

我的代码被构建到一个 32 位模块中,并且我在 applicationHost.config 文件中启用了 enable32BitAppOnWin64="true"。这适用于 Classic ActiveScript/ASP 环境,但是当使用预期通过 RegisterModule() 导出加载的代码时,此设置是否也有效?如果这不是问题,那么是否需要其他步骤来为 WebSockets 启用本机 HTTP 模块?

谢谢!

【问题讨论】:

  • 如果没有输入DllMain,可能是加载时失败。要验证这一点,请尝试在 WebSocketModule 注册中将 System32 更改为 SysWOW64。或者,启用show loader snaps GFlags 选项,并在调试器下运行代码。这将为您提供有关模块加载失败的足够完整的信息(假设这确实是根本原因)。
  • 听起来原生模块没有正确导入。您是否通过运行“\APPCMD.EXE 安装模块”安装了本机模块?然后通过IIS manager->modules->configure native module添加native模块?

标签: c++ winapi websocket iis-10


【解决方案1】:

时隔近两年,我决定再花几天时间做这个,终于成功了!

回答 32 位问题...是的,IIS 可以在 64 位操作系统上运行 32 位 WebSockets 处理程序。

至于为什么它现在可以工作......我确实再次重新运行APPCMD.EXE,并在配置中四处寻找,直到它看起来像这样:

    <globalModules>
        ...
        <add name="WebSocketModule" image="%windir%\System32\inetsrv\iiswsock.dll" />
        <add name="WebSocketModule32" image="%windir%\SysWOW64\inetsrv\iiswsock.dll" />
        <add name="QuadooWebSocket" image="E:\dev\projects\trunk\target\debug\ActiveQuadoo.dll" />
    </globalModules>

    <handlers accessPolicy="Read, Script">
        ...
        <add name="QuadooWebSocket" path="*.qws" verb="*" modules="WebSocketModule32" scriptProcessor="E:\dev\projects\trunk\target\debug\ActiveQuadoo.dll" resourceType="File" preCondition="bitness32" />
        ...
    </handlers>

    <location path="Default Web Site">
        <system.webServer>
            <handlers>
                <remove name="QuadooWebSocket" />
                <add name="QuadooWebSocket" path="*.qws" verb="*" modules="QuadooWebSocket" scriptProcessor="E:\dev\projects\trunk\target\debug\ActiveQuadoo.dll" resourceType="File" requireAccess="Script" preCondition="bitness32" />
            </handlers>
        </system.webServer>
    </location>

一个区别是我的处理程序现在注册到 WebSocketModule32 模块。

我可以在那里结束答案,但是在我的处理程序最终加载后,我必须解决一些问题才能真正正常工作。我学到的一些东西可能对其他人有用。

由于我正在异步处理 WebSocket,我需要从 OnExecuteRequestHandler() 返回 RQ_NOTIFICATION_PENDING。否则,IIS 立即关闭连接。

当切换到 WebSockets 时,这是我最终使用的顺序:

  1. 设置模块上下文。
  2. 将响应状态设置为 101。
  3. 加载我的脚本虚拟机。
  4. 写标题(例如Sec-WebSocket-Protocol)。
  5. Flush() 异步。

如果Flush() 没有立即完成,那么它将通过调用OnAsyncCompletion() 来完成。如果它立即完成,请使用从 OnAsyncCompletion() 调用的相同代码路径并执行以下操作:

  1. 获取IIS_WEBSOCKET 的命名上下文。
  2. 将上下文转换为 IWebSocketContext 指针。
  3. 启动异步读取器循环。
  4. 返回RQ_NOTIFICATION_PENDING

收到来自ReadFragment() 的关闭事件后,我调用IndicateCompletion(RQ_NOTIFICATION_FINISH_REQUEST) 通知IIS 我已完成连接。在我添加之前,IIS 没有调用我的处理程序的 CleanupStoredContext() 方法。

【讨论】:

    猜你喜欢
    • 2019-05-19
    • 1970-01-01
    • 2013-07-02
    • 1970-01-01
    • 2011-09-06
    • 1970-01-01
    • 2011-10-14
    • 2012-01-29
    • 1970-01-01
    相关资源
    最近更新 更多