/*++ Copyright (c) 1994 Microsoft Corporation Module Name: w3test.c Abstract: This module tests the web server's server extension interface Author: John Ludeman (johnl) 13-Oct-1994 Revision History: Tony Godfrey (tonygod) 15-Sep-1997 - fixed TerminateExtension --*/ #include //#include #include // Global variable used to track outstanding threads DWORD g_dwThreadCount; #define BUFFER_LENGTH 4096 // Debug macro CHAR g_szDebug[256]; #define DEBUG(DebugString, Param)\ {\ wsprintf( g_szDebug, DebugString, Param );\ OutputDebugString( g_szDebug );\ } // Prototypes DWORD WINAPI SimulatePendIOThread( LPDWORD lpParams ); BOOL WINAPI DllMain( HANDLE hInst, ULONG Reason, LPVOID Reserved ); BOOL WINAPI DoAction( EXTENSION_CONTROL_BLOCK * pecb, char * pszAction, BOOL * pfKeepConn ); DWORD WINAPI HttpExtensionProc( EXTENSION_CONTROL_BLOCK * pecb ) { BOOL fKeepConn = FALSE; DWORD dwThreadId; HANDLE hThread; if ( !_strnicmp( pecb->lpszQueryString, "SimulatePendingIO", 17)) { InterlockedIncrement( &g_dwThreadCount ); hThread = CreateThread( NULL, 0, (LPTHREAD_START_ROUTINE) SimulatePendIOThread, pecb, 0, &dwThreadId ); if ( hThread == NULL ) { InterlockedDecrement( &g_dwThreadCount ); } else { CloseHandle( hThread ); } return HSE_STATUS_PENDING; } else { if ( !DoAction( pecb, pecb->lpszQueryString, &fKeepConn )) { return HSE_STATUS_ERROR; } } return fKeepConn ? HSE_STATUS_SUCCESS_AND_KEEP_CONN : HSE_STATUS_SUCCESS; } BOOL WINAPI DoAction( EXTENSION_CONTROL_BLOCK * pecb, char * pszAction, BOOL * pfKeepConn ) { char *buff; int ret; int i; int cb; buff = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, BUFFER_LENGTH + 1 ); if ( buff == NULL ) { return FALSE; } // // Log the request here // strcpy( pecb->lpszLogData, ", ISAPI Data->" ); strcat( pecb->lpszLogData, pszAction ); if ( !_stricmp( pszAction, "HSE_REQ_SEND_URL_REDIRECT_RESP" )) { // // pecb->pszPathInfo is the URL to redirect to // HeapFree( GetProcessHeap(), 0, buff ); return pecb->ServerSupportFunction( pecb->ConnID, HSE_REQ_SEND_URL_REDIRECT_RESP, pecb->lpszPathInfo, NULL, NULL ); } else if ( !_stricmp( pszAction, "HSE_REQ_SEND_URL" )) { // // pecbb->lpszPathInfo is the URL to send // HeapFree( GetProcessHeap(), 0, buff ); return pecb->ServerSupportFunction( pecb->ConnID, HSE_REQ_SEND_URL, pecb->lpszPathInfo, 0, 0 ); } else if ( !_stricmp( pszAction, "HSE_REQ_SEND_RESPONSE_HEADER" )) { wsprintf( buff, "Content-type: text/html\r\n" "\r\n" "Response header test\n" "

HTTP status code supplied in the path info was \"%s\"

\n", pecb->lpszPathInfo ); ret = pecb->ServerSupportFunction( pecb->ConnID, HSE_REQ_SEND_RESPONSE_HEADER, pecb->lpszPathInfo, // HTTP status code NULL, (LPDWORD) buff ); if ( !ret ) { HeapFree( GetProcessHeap(), 0, buff ); return FALSE; } cb = wsprintf( buff, "Content-Type: text/html\r\n" "\r\n" "Response header test\n" "

Specified status code was %s

\n", pecb->lpszPathInfo ); ret = pecb->WriteClient( pecb->ConnID, buff, &cb, 0 ); HeapFree( GetProcessHeap(), 0, buff ); return ret; } else if ( !_strnicmp( pszAction, "GET_VAR", 7 )) { CHAR * pch; ret = pecb->ServerSupportFunction( pecb->ConnID, HSE_REQ_SEND_RESPONSE_HEADER, NULL, NULL, (LPDWORD) "Content-Type: text/html\r\n" "\r\n" ); if ( !ret ) { HeapFree( GetProcessHeap(), 0, buff ); return FALSE; } cb = BUFFER_LENGTH; if ( !(pch = strchr( pszAction, '&' )) ) { pch = "ALL_HTTP"; } else { pch++; } ret = pecb->GetServerVariable( pecb->ConnID, pch, buff, &cb ); if ( !ret ) { HeapFree( GetProcessHeap(), 0, buff ); return FALSE; } strcat( buff, "\r\n" ); cb = strlen( buff ); ret = pecb->WriteClient( pecb->ConnID, buff, &cb, 0 ); HeapFree( GetProcessHeap(), 0, buff ); return ret; } else if ( !_stricmp( pszAction, "HSE_REQ_MAP_URL_TO_PATH" )) { char Path[MAX_PATH + 1]; DWORD cbPath = sizeof( Path ); strcpy( Path, pecb->lpszPathInfo ); ret = pecb->ServerSupportFunction( pecb->ConnID, HSE_REQ_MAP_URL_TO_PATH, Path, &cbPath, NULL ); if ( !ret ) { HeapFree( GetProcessHeap(), 0, buff ); return FALSE; } wsprintf( buff, "Content-type: text/html\r\n" "\r\n" "URL map test\n" "

URL \"%s\" maps to \"%s\"" "cbPath is %d

\n", pecb->lpszPathInfo, Path, cbPath ); ret = pecb->ServerSupportFunction( pecb->ConnID, HSE_REQ_SEND_RESPONSE_HEADER, NULL, NULL, (LPDWORD) buff ); HeapFree( GetProcessHeap(), 0, buff ); return ret; } else if ( !_stricmp( pszAction, "HSE_REQ_MAP_URL_TO_PATH_EX" )) { HSE_URL_MAPEX_INFO mapinfo; ret = pecb->ServerSupportFunction( pecb->ConnID, HSE_REQ_MAP_URL_TO_PATH_EX, pecb->lpszPathInfo, NULL, (DWORD *) &mapinfo ); if ( !ret ) { HeapFree( GetProcessHeap(), 0, buff ); return FALSE; } wsprintf( buff, "Content-type: text/html\r\n" "\r\n" "URL map_ex test\n" "

URL \"%s\" maps to \"%s\"" "dwFlags = 0x%08x\n" "cchMatchingPath = %d\n" "cchMatchingURL = %d\n

", pecb->lpszPathInfo, mapinfo.lpszPath, mapinfo.dwFlags, mapinfo.cchMatchingPath, mapinfo.cchMatchingURL ); ret = pecb->ServerSupportFunction( pecb->ConnID, HSE_REQ_SEND_RESPONSE_HEADER, NULL, NULL, (LPDWORD) buff ); HeapFree( GetProcessHeap(), 0, buff ); return ret; } else if ( !_stricmp( pszAction, "Keep_Alive" )) { DWORD cbBuff = BUFFER_LENGTH; DWORD cbDoc; CHAR achDoc[4096]; BOOL fKeepAlive = FALSE; if ( !pecb->GetServerVariable( pecb->ConnID, "HTTP_CONNECTION", buff, &cbBuff )) { *buff = '\0'; } cbDoc = wsprintf( achDoc, "Keep alive test\n" "This document is being kept alive." ); // // This assumes keep-alive comes first in the list // if ( !_strnicmp( buff, "keep-alive", 10 )) { fKeepAlive = TRUE; wsprintf( buff, "Content-type: text/html\r\n" "Connection: keep-alive\r\n" "Content-Length: %d\r\n" "\r\n", cbDoc ); } else { wsprintf( buff, "Content-type: text/html\r\n" "\r\n" "Keep alive test\n" "Client did not specify keep alive!" ); } ret = pecb->ServerSupportFunction( pecb->ConnID, HSE_REQ_SEND_RESPONSE_HEADER, NULL, NULL, (LPDWORD) buff ) && pecb->WriteClient( pecb->ConnID, achDoc, &cbDoc, 0 ); if ( !ret ) { HeapFree( GetProcessHeap(), 0, buff ); return FALSE; } if ( fKeepAlive ) { *pfKeepConn = TRUE; } HeapFree( GetProcessHeap(), 0, buff ); return TRUE; } else if ( !strncmp( pszAction, "Open_Reg", 7 )) { CHAR * pch; DWORD err; HKEY hKey; HKEY hSubKey; HANDLE hFile; ret = pecb->ServerSupportFunction( pecb->ConnID, HSE_REQ_SEND_RESPONSE_HEADER, NULL, NULL, (LPDWORD) "Content-Type: text/html\r\n" "\r\n" ); if ( !ret ) { HeapFree( GetProcessHeap(), 0, buff ); return FALSE; } // // The path info begins with the portion of the registry to open // if ( !_strnicmp( pecb->lpszPathInfo + 1, "HKEY_CLASSES_ROOT", 17 )) { pch = pecb->lpszPathInfo + 19; hKey = HKEY_CLASSES_ROOT; } else if ( !_strnicmp( pecb->lpszPathInfo + 1, "HKEY_CURRENT_USER", 17 )) { pch = pecb->lpszPathInfo + 19; hKey = HKEY_CURRENT_USER; } else if ( !_strnicmp( pecb->lpszPathInfo + 1, "HKEY_LOCAL_MACHINE", 18 )) { pch = pecb->lpszPathInfo + 20; hKey = HKEY_LOCAL_MACHINE; } else if ( !_strnicmp( pecb->lpszPathInfo + 1, "HKEY_USERS", 10 )) { pch = pecb->lpszPathInfo + 12; hKey = HKEY_USERS; } err = RegOpenKey( hKey, pch, &hSubKey ); if ( err ) { cb = wsprintf( buff, "Failed to open registry key %s, error %d\n", pecb->lpszPathInfo, err ); } else { cb = wsprintf( buff, "Successfully opened registry key %s\n", pecb->lpszPathInfo ); RegCloseKey( hSubKey ); } pecb->WriteClient( pecb->ConnID, buff, &cb, 0 ); HeapFree( GetProcessHeap(), 0, buff ); return TRUE; } else if ( !_stricmp( pszAction, "Open_File" )) { CHAR *pch; DWORD err; HKEY hKey; HKEY hSubKey; HANDLE hFile; DWORD dwBytesRead; DWORD dwFileSize = 0; DWORD dwError; // // The path translated is the filename to open // hFile = CreateFile( pecb->lpszPathTranslated, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ); if ( hFile == INVALID_HANDLE_VALUE ) { dwError = GetLastError(); wsprintf( buff, "Content-Type: text/html\r\n\r\n" ); ret = pecb->ServerSupportFunction( pecb->ConnID, HSE_REQ_SEND_RESPONSE_HEADER, "200 OK", NULL, (LPDWORD) buff ); if ( !ret ) { HeapFree( GetProcessHeap(), 0, buff ); return FALSE; } cb = wsprintf( buff, "Unable to open file\r\n" "

Unable to open file

\r\n" "CreateFile failed: %ld\r\n

" "Filename: %s

", dwError, pecb->lpszPathTranslated ); pecb->WriteClient( pecb->ConnID, buff, &cb, 0 ); HeapFree( GetProcessHeap(), 0, buff ); return TRUE; } dwFileSize = GetFileSize( hFile, NULL ); pch = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwFileSize + 1 ); ret = ReadFile( hFile, pch, dwFileSize, &dwBytesRead, NULL ); if ( !ret ) { dwError = GetLastError(); } pch[dwBytesRead] = 0; CloseHandle( hFile ); if ( !ret ) { wsprintf( buff, "Content-Type: text/html\r\n\r\n" ); ret = pecb->ServerSupportFunction( pecb->ConnID, HSE_REQ_SEND_RESPONSE_HEADER, "200 OK", NULL, (LPDWORD) buff ); if ( !ret ) { HeapFree( GetProcessHeap(), 0, buff ); return FALSE; } cb = wsprintf( buff, "Unable to Read File\r\n" "

Unable to Read File

\r\n" "ReadFile failed: %ld

\r\n" "Filename: %s", dwError, pecb->lpszPathTranslated ); pecb->WriteClient( pecb->ConnID, buff, &cb, 0 ); HeapFree( GetProcessHeap(), 0, buff ); return TRUE; } wsprintf( buff, "Content-Type: text/html\r\n\r\n" ); ret = pecb->ServerSupportFunction( pecb->ConnID, HSE_REQ_SEND_RESPONSE_HEADER, "200 OK", NULL, (LPDWORD) buff ); if ( !ret ) { HeapFree( GetProcessHeap(), 0, buff ); return FALSE; } pecb->WriteClient( pecb->ConnID, pch, &dwBytesRead, 0 ); HeapFree( GetProcessHeap(), 0, buff ); HeapFree( GetProcessHeap(), 0, pch ); return TRUE; } else if ( !_stricmp( pszAction, "SimulateFault" )) { *((CHAR *)0xffffffff) = 'a'; HeapFree( GetProcessHeap(), 0, buff ); return FALSE; } wsprintf( buff, "Content-Type: text/html\r\n\r\n" "Unknown Test command\n" "

Unknown Test Command

\n" "

Usage:" "

Query string contains one of the following:" "

" "

HSE_REQ_SEND_URL_REDIRECT_RESP" "

HSE_REQ_SEND_URL" "

HSE_REQ_SEND_RESPONSE_HEADER" "

HSE_REQ_MAP_URL_TO_PATH" "

GET_VAR&var_to_get" "

SimulateFault" "

Keep_Alive" "

Open_Reg" "

Open_File" "

" "

For example:" "

" "

http://computer/scripts/w3test.dll?CGI_VAR" "

" "

or SimulatePendingIO with one of the above action strings" "

" "

such as:" "

" "

http://computer/scripts/w3test.dll?SimulatePendingIO&HSE_REQ_SEND_URL" "

" "

The Path info generally contains the URL or response to use" "\n"); ret = pecb->ServerSupportFunction( pecb->ConnID, HSE_REQ_SEND_RESPONSE_HEADER, "200 OK", NULL, (LPDWORD) buff ); cb = wsprintf( buff, "

cbTotalBytes = %d

cbAvailable = %d

" "lpszContentType = %s

lpszPathInfo = %s

" "lpszPathTranslated = %s", pecb->cbTotalBytes, pecb->cbAvailable, pecb->lpszContentType, pecb->lpszPathInfo, pecb->lpszPathTranslated ); pecb->WriteClient( pecb->ConnID, buff, &cb, 0 ); cb = pecb->cbAvailable; pecb->WriteClient( pecb->ConnID, pecb->lpbData, &cb, 0 ); while ( pecb->cbAvailable < pecb->cbTotalBytes ) { cb = min( pecb->cbTotalBytes - pecb->cbAvailable, BUFFER_LENGTH ); if ( !pecb->ReadClient( pecb->ConnID, buff, &cb ) || !cb ) { break; } pecb->cbAvailable += cb; pecb->WriteClient( pecb->ConnID, buff, &cb, 0 ); } HeapFree( GetProcessHeap(), 0, buff ); return TRUE; } DWORD WINAPI SimulatePendIOThread( LPDWORD lpParams ) { EXTENSION_CONTROL_BLOCK * pecb = (EXTENSION_CONTROL_BLOCK *) lpParams; char *psz; DWORD dwStatus; BOOL fKeepConn = FALSE; Sleep( 5000 ); psz = strchr( pecb->lpszQueryString, '&' ); if ( psz ) psz++; else psz = "No action string specified"; DoAction( pecb, psz, &fKeepConn ); dwStatus = fKeepConn ? HSE_STATUS_SUCCESS_AND_KEEP_CONN : HSE_STATUS_SUCCESS; pecb->ServerSupportFunction( pecb, HSE_REQ_DONE_WITH_SESSION, &dwStatus, 0, 0 ); InterlockedDecrement( &g_dwThreadCount ); return 0; } BOOL GetExtensionVersion( HSE_VERSION_INFO * pver ) { pver->dwExtensionVersion = MAKELONG( 0, 1 ); strcpy( pver->lpszExtensionDesc, "Extension test example" ); return TRUE; } BOOL TerminateExtension( DWORD dwFlags ) { DEBUG( "[W3Test.TerminateExtension] Extension terminating!\r\n", 0 ); while ( g_dwThreadCount > 0 ) { DEBUG( "[W3Test.TerminateExtension] Thread Count: %ld\r\n", g_dwThreadCount ); SleepEx( 1000, FALSE ); } SleepEx( 1000, FALSE ); return TRUE; } BOOL WINAPI DllMain( HANDLE hInst, ULONG Reason, LPVOID Reserved ) { switch( Reason ) { case DLL_PROCESS_ATTACH: g_dwThreadCount = 0; break; case DLL_PROCESS_DETACH: break; } return TRUE; }