/*****************************************************************************/ /* ISAPIexample.c This is an example ISAPI script for the WASD server. This program is built into a shareable image. It is loaded by the ISAPI interface (CGISAPI) and the GetExtensionVersion() callback invoked to return version information. The HttpExtensionproc() callback is the used by CGISAPI to activate this script. Supplying a single integer as the query string generates that number of lines of 80 characters for performance comparison purposes. Supplying a '!' followed by an integer outputs a 1 to 16384 size block of characters for testing the CGIsapi explicit buffering. Supplying "exit" as the query string causes the script to exit. Supplying "debug=on" or "debug=off" toggles the CGIsapi DLL debug mode for demonstration purposes. BUILD DETAILS ------------- See BUILD_ISAPIEXAMPLE.COM procedure. COPYRIGHT --------- Copyright (C) 1999-2020 Mark G.Daniel This program, comes with ABSOLUTELY NO WARRANTY. This is free software, and you are welcome to redistribute it under the conditions of the GNU GENERAL PUBLIC LICENSE, version 2. VERSION HISTORY (update SOFTWAREVN as well!) --------------- 23-DEC-2003 MGD v1.1.1, minor conditional mods to support IA64 21-NOV-1999 MGD v1.1.0, add data block (to check CGIsapi data buffer) 14-MAR-1999 MGD v1.0.0, initial */ /*****************************************************************************/ #define SOFTWAREVN "1.1.1" #define SOFTWARENM "ISAPIEXAMPLE" #ifdef __ALPHA # define SOFTWAREID SOFTWARENM " AXP-" SOFTWAREVN #endif #ifdef __ia64 # define SOFTWAREID SOFTWARENM " IA64-" SOFTWAREVN #endif #ifdef __VAX # define SOFTWAREID SOFTWARENM " VAX-" SOFTWAREVN #endif #ifdef __x86_64 # define SOFTWAREID SOFTWARENM " X86-" SOFTWAREVN #endif #ifndef __VAX # pragma nomember_alignment #endif #define boolean int #define true 1 #define false 0 #include #include #include #include #include #include "cgisapi.h" char Utility [] = "ISAPIEXAMPLE"; static boolean Debug; static int UsageCount; /* required prototypes */ DWORD WINAPI DisplayEcb (LPEXTENSION_CONTROL_BLOCK); ExtensionExit (LPEXTENSION_CONTROL_BLOCK); DWORD WINAPI GenerateLines (LPEXTENSION_CONTROL_BLOCK); DWORD WINAPI GenerateBlock (LPEXTENSION_CONTROL_BLOCK); /*****************************************************************************/ /* ISAPI version check entry-point called by CGISAPI. */ BOOL WINAPI GetExtensionVersion (HSE_VERSION_INFO *lpHvi) { /*********/ /* begin */ /*********/ if (Debug) fprintf (stdout, "GetExtensionVersion()\n"); lpHvi->dwExtensionVersion = (HSE_VERSION_MAJOR << 16) | HSE_VERSION_MINOR; strcpy (lpHvi->lpszExtensionDesc, "WASD example ISAPI DLL"); return (TRUE); } /*****************************************************************************/ /* Main entry-point called by CGISAPI to perform the DLL functionality. */ DWORD WINAPI HttpExtensionProc (LPEXTENSION_CONTROL_BLOCK lpEcb) { /*********/ /* begin */ /*********/ if (Debug) fprintf (stdout, "HttpExtensionProc()\n"); UsageCount++; if (lpEcb->lpszQueryString != NULL && !strcmp(lpEcb->lpszQueryString, "exit") || !strncmp(lpEcb->lpszQueryString, "exit=", 5)) ExtensionExit (lpEcb); if (lpEcb->lpszQueryString != NULL) { if (isdigit(*lpEcb->lpszQueryString)) { GenerateLines (lpEcb); return (HSE_STATUS_SUCCESS); } if (*lpEcb->lpszQueryString == '!') { GenerateBlock (lpEcb); return (HSE_STATUS_SUCCESS); } } if (lpEcb->lpszQueryString != NULL && !strcmp(lpEcb->lpszQueryString, "debug=on") || !strcmp(lpEcb->lpszQueryString, "debug=ON")) lpEcb->ServerSupportFunction (lpEcb->ConnID, HSE_REQ_DLL_DEBUG_ON, NULL, NULL, NULL); else if (lpEcb->lpszQueryString != NULL && !strcmp(lpEcb->lpszQueryString, "debug=off") || !strcmp(lpEcb->lpszQueryString, "debug=OFF")) lpEcb->ServerSupportFunction (lpEcb->ConnID, HSE_REQ_DLL_DEBUG_OFF, NULL, NULL, NULL); DisplayEcb (lpEcb); return (HSE_STATUS_SUCCESS); } /*****************************************************************************/ /* Where the ISAPI extension is loaded into the server's process space you wouldn't do this ;^) but with WASD ISAPI in private process space it's an effective method for loading a new version of the extension during development. */ ExtensionExit (LPEXTENSION_CONTROL_BLOCK lpEcb) { static char ContentTextHtml [] = "Content-Type: text/html\r\n\r\n"; int BufferCount; /*********/ /* begin */ /*********/ if (Debug) fprintf (stdout, "ExtensionExit()\n"); BufferCount = sizeof(ContentTextHtml)-1; lpEcb->ServerSupportFunction (lpEcb->ConnID, HSE_REQ_SEND_RESPONSE_HEADER, NULL, &BufferCount, ContentTextHtml); BufferCount = 5; lpEcb->WriteClient (lpEcb->ConnID, "Bye!\n", &BufferCount, 0); /* ensure the write buffer is flushed */ lpEcb->WriteClient (lpEcb->ConnID, NULL, 0, 0); exit (1); } /*****************************************************************************/ /* Return an HTML page showing the contents of all relevant fields in the extension control block. */ DWORD WINAPI DisplayEcb (LPEXTENSION_CONTROL_BLOCK lpEcb) { int BufferCount, ContentLength, DataLength, DataRemaining, VariableCount; char Buffer [4096], FarTooSmall [8], HttpUserAgent [256], RemoteHost [256], ServerSoftware [256]; char *DataPtr; time_t UnixSeconds; /*********/ /* begin */ /*********/ if (Debug) fprintf (stdout, "DisplayEcb()\n"); time (&UnixSeconds); /* just for DLL debug demonstration! */ VariableCount = sizeof(Buffer); lpEcb->GetServerVariable (lpEcb, "all_http", Buffer, &VariableCount); /* CGI variable does not exist, just for DLL debug demonstration! */ VariableCount = sizeof(Buffer); lpEcb->GetServerVariable (lpEcb, "does_not_exist", Buffer, &VariableCount); /* will not fit in storage provided, just for DLL debug demonstration! */ VariableCount = sizeof(FarTooSmall); lpEcb->GetServerVariable (lpEcb, "http_user_agent", FarTooSmall, &VariableCount); /* special case (returns binary value), just for DLL debug demonstration! */ VariableCount = sizeof(ContentLength); lpEcb->GetServerVariable (lpEcb, "content_length", &ContentLength, &VariableCount); VariableCount = sizeof(HttpUserAgent); lpEcb->GetServerVariable (lpEcb, "http_user_agent", HttpUserAgent, &VariableCount); VariableCount = sizeof(RemoteHost); lpEcb->GetServerVariable (lpEcb, "remote_host", RemoteHost, &VariableCount); VariableCount = sizeof(ServerSoftware); lpEcb->GetServerVariable (lpEcb, "server_software", ServerSoftware, &VariableCount); BufferCount = sprintf (Buffer, "Expires: Fri, 13 Jan 1978 14:00:00 GMT\r\n\ Content-type: text/html\r\n\ \r\n"); lpEcb->ServerSupportFunction (lpEcb->ConnID, HSE_REQ_SEND_RESPONSE_HEADER, NULL, &BufferCount, Buffer); BufferCount = sprintf (Buffer, "\n\ \n\ \n\ Example ISAPI DLL\n\ \n\ \n\ This is the WASD example ISAPI DLL!\n\

The time is currently %s\

This script has been called %d time%s.\n\

\n\ \n\ \n\ \n\ \n\ \n\ \n\ \n\ \n\ \n\ \n\ \n\ \n\ \n\ \n\
EXTENSION_CONTROL_BLOCK
lpszMethod:%s
lpszQueryString:%s
lpszPathInfo:%s
lpszPathTranslated:%s
lpszContentType:%s
cbTotalBytes:%d
cbAvailable:%d
lpbData:\n", SOFTWAREID, ctime (&UnixSeconds), UsageCount, UsageCount == 1 ? "" : "s", lpEcb->lpszMethod == NULL ? "(null)" : lpEcb->lpszMethod, lpEcb->lpszQueryString == NULL ? "(null)" : lpEcb->lpszQueryString, lpEcb->lpszPathInfo == NULL ? "(null)" : lpEcb->lpszPathInfo, lpEcb->lpszPathTranslated == NULL ? "(null)" : lpEcb->lpszPathTranslated, lpEcb->lpszContentType == NULL ? "(null)" : lpEcb->lpszContentType, lpEcb->cbTotalBytes, lpEcb->cbAvailable); lpEcb->WriteClient (lpEcb->ConnID, Buffer, &BufferCount, 0); if (lpEcb->lpbData == NULL) { BufferCount = 6; lpEcb->WriteClient (lpEcb->ConnID, "(null)", &BufferCount, 0); } else { if (lpEcb->lpszMethod != NULL && !strcmp (lpEcb->lpszMethod, "POST")) { /* for better layout break the body into 80 character chunks */ DataPtr = lpEcb->lpbData; DataRemaining = lpEcb->cbAvailable; while (DataRemaining > 0) { if (DataRemaining > 80) DataLength = 80; else DataLength = DataRemaining; lpEcb->WriteClient (lpEcb->ConnID, DataPtr, &DataLength, 0); DataPtr += DataLength; DataRemaining -= DataLength; DataLength = 5; lpEcb->WriteClient (lpEcb->ConnID, "
\n", &DataLength, 0); } } } BufferCount = sprintf (Buffer, "
GetServerVariable()
remote_host:%s
http_user_agent:%s
server_software:%s
\n\ \n\ \n", RemoteHost, HttpUserAgent, ServerSoftware); lpEcb->WriteClient (lpEcb->ConnID, Buffer, &BufferCount, 0); return (HSE_STATUS_SUCCESS); } /*****************************************************************************/ /* Simply generates the query-string specified number of of 80 character lines. Used for performance comparisons with other forms of scripting. */ DWORD WINAPI GenerateLines (LPEXTENSION_CONTROL_BLOCK lpEcb) { static char ContentTextPlain [] = "Content-Type: text/plain\r\n\r\n"; static char Line80Chars [] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ\ abcdefghijklmnopqrstuvwxyz\ 0123456789\ !@#$%^&*()_+-=<>,\n"; int BufferCount, RequestedCount; /*********/ /* begin */ /*********/ if (Debug) fprintf (stdout, "GenerateLines()\n"); BufferCount = sizeof(ContentTextPlain)-1; lpEcb->ServerSupportFunction (lpEcb->ConnID, HSE_REQ_SEND_RESPONSE_HEADER, NULL, &BufferCount, ContentTextPlain); RequestedCount = atoi (lpEcb->lpszQueryString); while (RequestedCount--) { BufferCount = sizeof(Line80Chars)-1; lpEcb->WriteClient (lpEcb->ConnID, Line80Chars, &BufferCount, 0); } return (HSE_STATUS_SUCCESS); } /*****************************************************************************/ /* Generate a block of 16384 characters, basically divided into lines of 63 characters, plus the newline, with a vertical bar marked at each 4096 character boundary. Then allow any number of these characters to be requested to be output. Just to test that the explicit buffer of CGISAPI.C is working correctly. */ DWORD WINAPI GenerateBlock (LPEXTENSION_CONTROL_BLOCK lpEcb) { static char ContentTextPlain [] = "Content-Type: text/plain\r\n\r\n"; int BufferCount; char *cptr; char DataBlock [16384]; /*********/ /* begin */ /*********/ if (Debug) fprintf (stdout, "GenerateBlock()\n"); BufferCount = sizeof(ContentTextPlain)-1; lpEcb->ServerSupportFunction (lpEcb->ConnID, HSE_REQ_SEND_RESPONSE_HEADER, NULL, &BufferCount, ContentTextPlain); memset (DataBlock, '1', 4096); memset (DataBlock+4096, '2', 4096); memset (DataBlock+4096+4096, '3', 4096); memset (DataBlock+4096+4096+4096, '4', 4096); for (cptr = DataBlock+63; cptr < DataBlock+sizeof(DataBlock); cptr += 64) *cptr = '\n'; for (cptr = DataBlock+4095; cptr < DataBlock+sizeof(DataBlock); cptr += 4096) *cptr = '|'; BufferCount = atoi(lpEcb->lpszQueryString+1); if (!BufferCount || BufferCount > sizeof(DataBlock)) BufferCount = sizeof(DataBlock); lpEcb->WriteClient (lpEcb->ConnID, DataBlock, &BufferCount, 0); return (HSE_STATUS_SUCCESS); } /*****************************************************************************/