Article ID: 946086 - Last Review: January 10, 2008 - Revision: 1.0

ISAPI extensions that send long responses to the client may not transmit any output in Internet Information Services 7.0 until the session is closed

Expand all | Collapse all

SYMPTOMS

ISAPI extensions that send long responses to the client may not transmit any output in Internet Information Services (IIS) 7.0 until the session is closed. This behavior occurs if the long responses contain many writes.

CAUSE

By default, IIS 7.0 buffers output to the client until the response is finished. Or, IIS 7.0 buffers output to the client until the IIS 7.0 buffer capacity has been exceeded. IIS 6.0 did not buffer output to the client. Output was sent to the client when you called any client output function.

IIS 7.0 buffers output to the client if one of the following conditions is true:
  • You send output to the client by using one of the following WriteClient function call parameters:
    • HSE_IO_SYNC
    • HSE_IO_ASYNC
  • You send output to the client by using a ServerSupportFunction function call that sets the HSE_REQ_VECTOR_SEND parameter.
  • You send output to the client by using a ServerSupportFunction function call that sets the HSE_REQ_SEND_RESPONSE_HEADER_EX parameter.
  • You send output to the client by using a ServerSupportFunction function call that sets the deprecated HSE_REQ_SEND_RESPONSE_HEADER parameter.
All buffered output is sent to the client if a ServerSupportFunction function call that contains the HSE_REQ_VECTOR_SEND parameter sets either the HSE_IO_DISCONNECT_AFTER_SEND flag or the HSE_IO_FINAL_SEND flag in the dwFlags member of the HSE_RESPONSE_VECTOR structure. All buffered output is also transmitted if you set the HSE_REQ_DONE_WITH_SESSION code on the connection after the WriteClient function call or after any of the ServerSupportFunction function calls.

RESOLUTION

To change this behavior, use the new HSE_REQ_SET_FLUSH_FLAG parameter in the ServerSupportFunction function to turn off client output buffering on the connection. This restores the non-buffered behavior that existed in IIS 6.0. The following code sample shows how you can use the HSE_REQ_SET_FLUSH_FLAG parameter in the ServerSupportFunction function in a .cpp file to restore the non-buffered behavior.
//	Copyright (c) 1997-2002  Microsoft Corporation
//
//	Module Name:
//
//	Simple.cpp
//
//	Abstract:
//
//	This module shows IIS 7 WriteClient buffering.

#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <httpext.h>

// The following define is needed if httpext.h is pre-Windows:
#ifndef   HSE_REQ_SET_FLUSH_FLAG
#define   HSE_REQ_SET_FLUSH_FLAG                   (HSE_REQ_END_RESERVED+43)
#endif

DWORD SendOutputToClient(IN EXTENSION_CONTROL_BLOCK  *pecb, IN DWORD msecDelay);DWORD SendOutputToClient(IN EXTENSION_CONTROL_BLOCK  *pecb, IN DWORD msecDelay, char *szBuffering) ;

//  Function:  
//
//  DllMain
//
//  Description:
//
//  The initialization function for this DLL.
//
//  Arguments:
//
//  hinstDll - This parameter is the instance handle to the DLL.
//  dwReason - This parameter is the reason why this DLL is called.
//  lpvContext - This parameter is reserved for future use.
//
//  Return Value:
//
//  If this parameter is successful, a value of TRUE is returned. If this parameter is not successful, a value of FALSE is returned.
BOOL WINAPI DllMain(IN HINSTANCE hinstDll, IN DWORD dwReason, IN LPVOID lpvContext)
{
// Be aware that appropriate initialization and termination code
// is written within the switch statement that is shown here. Because
// this example is very simple, no additional code is currently needed.

	switch(dwReason) {

		case DLL_PROCESS_ATTACH :

			break;

		case DLL_PROCESS_DETACH :

			break;
	}

	return TRUE;
}

//  Function:
//
//  GetExtensionVersion
//
//  Description:
//
//  This function is the first function that is called after IIS successfully loads the DLL. The function should use the 
//  version structure that is provided by IIS to set the ISAPI architectural version number of this extension.
//
//  A simple text string is also set so that administrators can find the DLL.
//
//  The HSE_VERSION_MINOR constant and the HSE_VERSION_MAJOR constant are defined in the httpext.h header.
//
//  Arguments: 
//
//  pVer - This parameter points to the extension version structure.
//
//  Return Value:
//
//  If this parameter is successful, a value of TRUE is returned. If this parameter is not successful, a value of FALSE is returned.
BOOL WINAPI GetExtensionVersion(HSE_VERSION_INFO *pVer)
{
	pVer->dwExtensionVersion = MAKELONG(HSE_VERSION_MINOR, HSE_VERSION_MAJOR);

	lstrcpyn((LPSTR) pVer->lpszExtensionDesc, "WriteClient buffering demo", HSE_MAX_EXT_DLL_NAME_LEN);

	return TRUE;
}


//  Function:
//
//  HttpExtensionProc
//
//  Description:    
//
//  This function is called by the server that is runnning IIS when a request for the ISAPI DLL
//  arrives. The HttpExtensionProc function processes the request and then
//  sends the appropriate response to the Web client by using the WriteClient() call.
//
//  Argument:
//
//  pECB - This parameter points to the extension control block.
//
//  Return Value:
//
//  HSE_STATUS_SUCCESS

DWORD WINAPI HttpExtensionProc(IN EXTENSION_CONTROL_BLOCK *pECB)
{

	DWORD hseStatus;
	DWORD msecDelay;
	char *pszBuffering; 

	pszBuffering = "default (on)";
	msecDelay=25;
    
	// Any value in the query string turns off buffering.
	if ( (char)*(pECB->lpszQueryString) != '\0' ){
		pszBuffering="off";
	    pECB->ServerSupportFunction (pECB->ConnID,
			HSE_REQ_SET_FLUSH_FLAG,
			(LPVOID) TRUE,
			NULL,
			NULL
			);
	}
	hseStatus = SendOutputToClient(pECB, msecDelay, pszBuffering);
	
	return hseStatus;
}

//  Function:
//
//  TerminateExtension
//
//  Description:
//
//  This function is called when the World Wide Web Publishing Service is shut down.
//
//  Arguments:
//
//  dwFlags - HSE_TERM_ADVISORY_UNLOAD or HSE_TERM_MUST_UNLOAD
//
//  Return Value:
//
//  A value of TRUE is returned if the extension is ready to be unloaded. Otherwise, a value of FALSE is returned.
BOOL WINAPI TerminateExtension(IN DWORD dwFlags)
{
	// Note: This code cannot be unloaded if any pending requests exist.

	return TRUE;
}

DWORD SendHeaderToClient(IN EXTENSION_CONTROL_BLOCK *pecb, IN LPCSTR pszErrorMsg)
{
	HSE_SEND_HEADER_EX_INFO	SendHeaderExInfo;
	char szStatus[] = "200 OK";
	char szHeader[1024];

	/* Notice that the HTTP header block is terminated by a blank '\r\n' pair, followed by the document body. */

	wsprintf(szHeader, "Content-Type: text/html\r\n\r\n<head><title>WriteClient Buffering Demo</title></head>\n<body><h1>%s</h1>\n", pszErrorMsg);

	/* The following code populates the SendHeaderExInfo structure. */

	SendHeaderExInfo.pszStatus = szStatus;
	SendHeaderExInfo.pszHeader = szHeader;
	SendHeaderExInfo.cchStatus = lstrlen(szStatus);
	SendHeaderExInfo.cchHeader = lstrlen(szHeader);
	SendHeaderExInfo.fKeepConn = FALSE;

	/* Use the EX version to send the header contents */

	if (!pecb->ServerSupportFunction(pecb->ConnID, HSE_REQ_SEND_RESPONSE_HEADER_EX, &SendHeaderExInfo, NULL, NULL))
   		return HSE_STATUS_ERROR;
	
	return HSE_STATUS_SUCCESS;
}

DWORD SendOutput(IN EXTENSION_CONTROL_BLOCK  *pecb, IN DWORD msecDelay) {
	
	CHAR pchOutput[1024]; 
	DWORD hseStatus = HSE_STATUS_SUCCESS;
	int i;
	DWORD len;

	/* Write data to client. */
	for( i=0; i < 1000 ; i++ ) {
		len = wsprintfA(pchOutput, "WriteClient output %d\n", i);
		if ( !pecb->WriteClient(pecb->ConnID, pchOutput, &len, HSE_IO_SYNC) ){
			hseStatus = HSE_STATUS_ERROR;
			break;
		}
		Sleep(msecDelay);
	}
	return hseStatus;
}

DWORD SendOutputToClient(IN EXTENSION_CONTROL_BLOCK  *pecb, IN DWORD msecDelay, char *szBuffering) {
	CHAR    pchBuffer[1024];
	DWORD   hseStatus = HSE_STATUS_SUCCESS;

	wsprintfA(pchBuffer, "WriteClient buffering %s", szBuffering);

	hseStatus = SendHeaderToClient(pecb, pchBuffer);

	if (hseStatus == HSE_STATUS_SUCCESS) {

		hseStatus = SendOutput(pecb, msecDelay );

		if (hseStatus != HSE_STATUS_SUCCESS) {

			/* Error in sending output. Send error message. */

			wsprintfA(pchBuffer, "Send Failed: Error (%d)<\br>", GetLastError());
			SendHeaderToClient(pecb, pchBuffer);
		}
	}

	pecb->ServerSupportFunction( pecb->ConnID, HSE_REQ_DONE_WITH_SESSION, NULL, NULL, NULL);

	return (hseStatus);
}

STATUS

This behavior is by design.

APPLIES TO
  • Microsoft Internet Information Services 7.0
Keywords: 
kbexpertiseadvanced kbtshoot kbprb KB946086
 

Article Translations