2025-11-28 00:35:46 +09:00

265 lines
5.3 KiB
C

/* Copyright (c) 1997-2002 Microsoft Corporation
Module Name:
KeepAliveP.c
Abstract:
Sample ISAPI Extension demonstrating Keep-Alive with a thread pool.
*/
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <httpext.h>
#include <stdio.h>
#include "threadpool.h"
/*
Purpose:
Initialize the thread pool when the DLL is loaded by IIS.
Arguments:
hinstDLL - DLL instance handle
fdwReason - notification code
lpdvContext - reserved
Returns:
TRUE if notification was successfully processed by the DLL
FALSE to indicate a failure
*/
BOOL WINAPI DllMain(IN HINSTANCE hinstDll, IN DWORD fdwReason, IN LPVOID lpvContext)
{
BOOL fReturn = TRUE;
switch (fdwReason) {
case DLL_PROCESS_ATTACH :
fReturn = InitThreadPool();
break;
}
return fReturn;
}
/*
Description:
This is required ISAPI Extension DLL entry point.
Arguments:
pVer - poins to extension version info structure
Returns:
always returns TRUE
*/
BOOL WINAPI GetExtensionVersion(OUT HSE_VERSION_INFO *pVer)
{
pVer->dwExtensionVersion = MAKELONG(HSE_VERSION_MINOR, HSE_VERSION_MAJOR);
strncpy_s(pVer->lpszExtensionDesc, sizeof(pVer->lpszExtensionDesc), "ISAPI Keep-Alive with Thread Pool Extension Sample", HSE_MAX_EXT_DLL_NAME_LEN);
return TRUE;
}
/*
Description:
Demonstrate usage of persistent connections serviced by a thread pool.
Arguments:
pECB - points to the extension control block
Returns:
HSE_STATUS_PENDING if request was successfully queued
HSE_SUCCESS_AND_KEEP_CONN if request was served immediately
(presumably because the queue was full)
*/
DWORD WINAPI HttpExtensionProc(IN EXTENSION_CONTROL_BLOCK *pECB)
{
DWORD dwSize;
HSE_SEND_HEADER_EX_INFO HeaderExInfo;
char szHeader[] =
"Connection: Keep-Alive\r\n"
"Content-Length: %lu\r\n"
"Content-type: text/html\r\n\r\n";
char szBusyMessage[] =
"<html> <form method=get action=KeepAliveP.dll> <input type=submit> "
"<br>pECB->ConnID=%lu <br>Server was too busy. </form></html>";
char szBuffer[4096];
char szBuffer2[4096];
EnterCriticalSection(&csQueueLock);
if (!AddWorkQueueEntry(pECB)) {
/* if ECB could not be assigned */
LeaveCriticalSection(&csQueueLock);
sprintf_s(szBuffer2, sizeof(szBuffer2), szBusyMessage, pECB->ConnID);
/* Send outgoing header */
sprintf_s(szBuffer, sizeof(szBuffer), szHeader, strlen(szBuffer2));
HeaderExInfo.pszHeader = szBuffer;
HeaderExInfo.cchHeader = strlen( szBuffer );
HeaderExInfo.pszStatus = "200 OK";
HeaderExInfo.cchStatus = strlen( HeaderExInfo.pszStatus );
HeaderExInfo.fKeepConn = TRUE;
pECB->ServerSupportFunction(pECB->ConnID, HSE_REQ_SEND_RESPONSE_HEADER_EX, &HeaderExInfo, NULL, NULL);
/* Send content */
dwSize = strlen(szBuffer2);
pECB->WriteClient(pECB->ConnID, szBuffer2, &dwSize, 0);
return HSE_STATUS_SUCCESS_AND_KEEP_CONN;
} else {
/* release 1 thread from the pool */
ReleaseSemaphore(hWorkSem, 1, NULL);
LeaveCriticalSection(&csQueueLock);
}
return HSE_STATUS_PENDING;
}
/*
Description:
This function is called when the WWW service is shutdown
Arguments:
dwFlags - HSE_TERM_ADVISORY_UNLOAD or HSE_TERM_MUST_UNLOAD
Return Value:
TRUE if extension is ready to be unloaded,
FALSE otherwise
*/
BOOL WINAPI TerminateExtension(IN DWORD dwFlags)
{
return TRUE;
}
/*
Description:
Worker thread function - simulates extended processing of the HTTP request
Arguments:
pvThreadNum - thread number
Returns:
alsways returns 0
*/
DWORD WINAPI WorkerFunction(IN LPVOID pvThreadNum)
{
EXTENSION_CONTROL_BLOCK *pECB;
DWORD dwRet, dwState, dwSize;
HSE_SEND_HEADER_EX_INFO HeaderExInfo;
DWORD dwThreadNum = (DWORD)pvThreadNum;
/* This header will be filled in with the content length */
char szHeader[] =
"Connection: Keep-Alive\r\nContent-Length: %lu\r\n"
"Content-type: text/html\r\n\r\n";
char szContent[] =
"<html> <form method=get action=KeepAliveP.dll><input type=submit> "
"<br>pECB->ConnID=%lu <br>dwThreadNum=%lu</form></html>";
char szBuffer[4096];
char szBuffer2[4096];
for (;;) {
dwRet = WaitForSingleObject(hWorkSem, INFINITE);
if (dwRet == WAIT_OBJECT_0) {
EnterCriticalSection(&csQueueLock);
if (GetWorkQueueEntry(&pECB)) {
/* Found work to do */
LeaveCriticalSection(&csQueueLock);
sprintf_s(szBuffer2, sizeof(szBuffer2), szContent, pECB->ConnID, dwThreadNum);
/* Send outgoing header */
sprintf_s(szBuffer, sizeof(szBuffer), szHeader, strlen(szBuffer2));
HeaderExInfo.pszHeader = szBuffer;
HeaderExInfo.cchHeader = strlen( szBuffer );
HeaderExInfo.pszStatus = "200 OK";
HeaderExInfo.cchStatus = strlen( HeaderExInfo.pszStatus );
HeaderExInfo.fKeepConn = TRUE;
pECB->ServerSupportFunction(pECB->ConnID, HSE_REQ_SEND_RESPONSE_HEADER_EX, &HeaderExInfo, NULL, NULL);
/* Simulate extended processing */
Sleep(3000);
/* Send content */
dwSize = strlen(szBuffer2);
pECB->WriteClient(pECB->ConnID, szBuffer2, &dwSize, 0);
/* Tell IIS to keep the connection open */
dwState = HSE_STATUS_SUCCESS_AND_KEEP_CONN;
pECB->ServerSupportFunction(pECB->ConnID, HSE_REQ_DONE_WITH_SESSION, &dwState, NULL, 0);
} else {
/* No item found is unexpected condition - exit thread */
LeaveCriticalSection(&csQueueLock);
ExitThread(0);
}
} else {
/* Leave the infinite loop */
break;
}
}
return 0;
}