简体   繁体   中英

Zero bytes sent back to client from IIS using ISAPI extension

I'm trying to write a pro-forma ISAPI extension in an attempt to better understand IIS. I have the following code for the exension:

#include <httpext.h>
#include <cstring>
#include <cstdio>
#include <fstream>
#include <iostream>
#include <windows.h>

BOOL WINAPI GetExtensionVersion(HSE_VERSION_INFO * versionInfo)
{
    versionInfo->dwExtensionVersion = HSE_VERSION;
    strcpy_s( versionInfo->lpszExtensionDesc, "ISAPIExtension.dll");
    return TRUE;
}

DWORD WINAPI HttpExtensionProc(EXTENSION_CONTROL_BLOCK* ecb)
{
    char * msg = "<html><head/><body>Hello world</body></html>";
    DWORD msg_length = strlen(msg) * sizeof(char);
    DWORD sent_length = msg_length;
    std::cout << sent_length;
    auto result = ecb->WriteClient(ecb->ConnID, msg, &sent_length, 0);
    if (!result || sent_length != msg_length)
    {
        std::fstream output("errors.txt");
        output << "Could not write to client. Last error was " << GetLastError();
        output.flush();
        output.close();
        return HSE_STATUS_ERROR;
    }
    std::cout << sent_length;

    return HSE_STATUS_SUCCESS;
}

IIS Express responds with HTTP 200, but zero bytes were sent back to the client. Is anything in the above wrong? For reference, this is my applicationhost.config:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <configSections>
        <sectionGroup name="system.applicationHost">
            <section name="applicationPools"/>
            <section name="sites"/>
        </sectionGroup>
        <sectionGroup name="system.webServer">
            <section name="globalModules"/>
            <section name="handlers"/>
            <section name="caching"/>
            <section name="modules"/>
            <section name="staticContent"/>
            <section name="httpErrors"/>
            <sectionGroup name="tracing">
                <section name="traceFailedRequests" overrideModeDefault="Allow" />
                <section name="traceProviderDefinitions" overrideModeDefault="Deny" />
            </sectionGroup>
            <!-- The following section elements are not specified in this file, but without these
                declarations, IIS will 500 requests -->
            <sectionGroup name="security">
                <section name="isapiCgiRestriction"/>
                <section name="access"/>
                <sectionGroup name="authentication">
                    <section name="anonymousAuthentication"/>
                </sectionGroup>
            </sectionGroup>
            <section name="serverRuntime"/>
        </sectionGroup>
    </configSections>
    <system.applicationHost>
        <applicationPools>
            <add name="UnmanagedClassicAppPool" managedRuntimeVersion="" managedPipelineMode="Classic" autoStart="true" />
        </applicationPools>
        <sites>
            <site name="Default Web Site" id="1" serverAutoStart="true">
                <application path="/" applicationPool="UnmanagedClassicAppPool">
                    <virtualDirectory path="/" physicalPath="%IIS_USER_HOME%\blog" />
                </application>
                <bindings>
                    <binding protocol="http" bindingInformation=":8080:localhost" />
                </bindings>
                <traceFailedRequestsLogging directory="%IIS_USER_HOME%\TraceLogFiles" enabled="true" maxLogFileSizeKB="1024" />
            </site>
        </sites>
    </system.applicationHost>
    <system.webServer>
    <security>
        <isapiCgiRestriction notListedIsapisAllowed="true"/>
    </security>
        <globalModules>
            <add name="StaticFileModule" image="%IIS_BIN%\static.dll" />
            <add name="AnonymousAuthenticationModule" image="%IIS_BIN%\authanon.dll" />
            <add name="IsapiModule" image="%IIS_BIN%\isapi.dll" />
            <add name="FailedRequestsTracingModule" image="%IIS_BIN%\iisfreb.dll" />
        </globalModules>
        <staticContent>
            <mimeMap fileExtension=".html" mimeType="text/html" />
        </staticContent>
        <modules>
            <add name="StaticFileModule"/>
            <add name="AnonymousAuthenticationModule"/>
            <add name="IsapiModule"/>
            <add name="FailedRequestsTracingModule"/>
        </modules>
        <handlers accessPolicy="Read, Execute, Script">
            <add name="ISAPI-dll" path="*.dll" verb="*" modules="IsapiModule" resourceType="File" requireAccess="Execute" allowPathInfo="true" />
            <add name="StaticFile" path="*.html" verb="*" modules="StaticFileModule" resourceType="Either" requireAccess="Read" />
        </handlers>
        <tracing>

            <traceProviderDefinitions>
                <add name="ISAPI Extension" guid="{a1c2040e-8840-4c31-ba11-9871031a19ea}">
                    <areas>
                        <clear />
                    </areas>
                </add>
            </traceProviderDefinitions>

            <traceFailedRequests>
                <add path="*">
                    <traceAreas>
                        <add provider="ISAPI Extension" verbosity="Verbose" />
                    </traceAreas>
                    <failureDefinitions statusCodes="200-999" />
                </add>
            </traceFailedRequests>
        </tracing>
    </system.webServer>
</configuration>

Adding a Content-Type header fixes the issue:

DWORD WINAPI HttpExtensionProc(EXTENSION_CONTROL_BLOCK* ecb)
{
    char msg [] = "<html><head/><body>Hello world</body></html>";
    DWORD msg_length = strlen(msg);
    DWORD sent_length = msg_length;

    HSE_SEND_HEADER_EX_INFO HeaderExInfo;

    HeaderExInfo.pszStatus = "200 OK";
    HeaderExInfo.pszHeader = "Content-type: text/html\r\n\r\n";
    HeaderExInfo.cchStatus = strlen(HeaderExInfo.pszStatus);
    HeaderExInfo.cchHeader = strlen(HeaderExInfo.pszHeader);
    HeaderExInfo.fKeepConn = FALSE;

    ecb->ServerSupportFunction(ecb->ConnID, HSE_REQ_SEND_RESPONSE_HEADER_EX, &HeaderExInfo, NULL, NULL);
    auto result = ecb->WriteClient(ecb->ConnID, msg, &sent_length, 0);
    if (!result || sent_length != msg_length)
    {
        return HSE_STATUS_ERROR;
    }
    return HSE_STATUS_SUCCESS;
}

Microsoft has posted a similar ISAPI extension sample on their GitHub account: https://github.com/Microsoft/Windows-classic-samples/tree/master/Samples/Win7Samples/web/iis/extensions/simple

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM