From: Shane Caraveo Date: Sun, 7 Jan 2001 23:52:18 +0000 (+0000) Subject: stresstest is based on cgiwrap. it can be used to debug php4isapi.dll without X-Git-Tag: php-4.0.5RC1~684 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=a1c3f92ac7bc67a2be327d0c0e0d096e8022ea8e;p=php stresstest is based on cgiwrap. it can be used to debug php4isapi.dll without the use of an actual web server. --- diff --git a/sapi/isapi/stresstest/stresstest.cpp b/sapi/isapi/stresstest/stresstest.cpp new file mode 100644 index 0000000000..dad651e62e --- /dev/null +++ b/sapi/isapi/stresstest/stresstest.cpp @@ -0,0 +1,462 @@ +/* + * ======================================================================= * + * File: stress .c * + * stress tester for isapi dll's * + * based on cgiwrap * + * ======================================================================= * + * +*/ +#define WIN32_LEAN_AND_MEAN +#include +#include +#include +#include +#include +#include +#include + +// These are things that go out in the Response Header +// +#define HTTP_VER "HTTP/1.0" +#define SERVER_VERSION "Http-Srv-Beta2/1.0" + +// +// Simple wrappers for the heap APIS +// +#define xmalloc(s) HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,(s)) +#define xfree(s) HeapFree(GetProcessHeap(),0,(s)) + +// +// The mandatory exports from the ISAPI DLL +// + +typedef struct _TIsapiContext { + HANDLE in; + HANDLE out; + DWORD tid; +} TIsapiContext; + +// +// Prototypes of the functions this sample implements +// +extern "C" { +HINSTANCE hDll; +typedef BOOL (WINAPI *VersionProc)(HSE_VERSION_INFO *) ; +typedef DWORD (WINAPI *HttpExtProc)(EXTENSION_CONTROL_BLOCK *); +BOOL WINAPI FillExtensionControlBlock(EXTENSION_CONTROL_BLOCK *, TIsapiContext *) ; +BOOL WINAPI GetServerVariable(HCONN, LPSTR, LPVOID, LPDWORD ); +BOOL WINAPI ReadClient(HCONN,LPVOID,LPDWORD); +BOOL WINAPI WriteClient(HCONN,LPVOID,LPDWORD,DWORD); +BOOL WINAPI ServerSupportFunction(HCONN,DWORD,LPVOID,LPDWORD,LPDWORD); +VersionProc IsapiGetExtensionVersion; +HttpExtProc IsapiHttpExtensionProc; +HSE_VERSION_INFO version_info; +} + +char * MakeDateStr(VOID); +char * GetEnv(char *); + + +#define NUM_THREADS 1 +#define ITERATIONS 1 +HANDLE terminate[NUM_THREADS]; +HANDLE StartNow; +// quick and dirty environment +CMapStringToString IsapiEnvironment; +CStringArray IsapiFileList; +CStringArray IsapiArgList; + + +DWORD CALLBACK IsapiThread(void *); +int stress_main(const char *filename, const char *arg); + + + +int main(int argc, char* argv[]) { + LPVOID lpMsgBuf; + char *filelist, *environment; + + if (argc < 2) { + printf("Usage: stress filelist.txt env.txt\r\n"); + return 0; + } + filelist = argv[1]; + environment = argv[2]; + + hDll = LoadLibrary("php4isapi.dll"); // Load our DLL + + if (!hDll) { + FormatMessage( + FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, + NULL, + GetLastError(), + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language + (LPTSTR) &lpMsgBuf, + 0, + NULL + ); + fprintf(stderr,"Error: Dll 'php4isapi.dll' not found -%d\n%s\n", GetLastError(),lpMsgBuf); + LocalFree( lpMsgBuf ); + return -1; + } + + // + // Find the exported functions + + IsapiGetExtensionVersion = (VersionProc)GetProcAddress(hDll,"GetExtensionVersion"); + if (!IsapiGetExtensionVersion) { + fprintf(stderr,"Can't Get Extension Version %d\n",GetLastError()); + return -1; + } + IsapiHttpExtensionProc = (HttpExtProc)GetProcAddress(hDll,"HttpExtensionProc"); + if (!IsapiHttpExtensionProc) { + fprintf(stderr,"Can't Get Extension proc %d\n",GetLastError()); + return -1; + } + + // This should really check if the version information matches what we + // expect. + // + __try { + if (!IsapiGetExtensionVersion(&version_info) ) { + fprintf(stderr,"Fatal: GetExtensionVersion failed\n"); + return -1; + } + } + __except(1) { + return -1; + } + + // read config files + FILE *fp = fopen(filelist, "r"); + if (!fp) { + printf("Unable to open %s\r\n", filelist); + } + char line[2048]; + int i=0; + while (fgets(line,sizeof(line)-1,fp)) { + // file.php arg1 arg2 etc. + char *p = strchr(line, ' '); + if (p) { + *p = 0; + // get file + IsapiFileList.Add(line); + IsapiArgList.Add(p+1); + } else { + // just a filename is all + IsapiFileList.Add(line); + IsapiArgList.Add(""); + } + i++; + } + fclose(fp); + + if (environment) { + fp = fopen(environment, "r"); + i=0; + if (fp) { + char line[2048]; + while (fgets(line,sizeof(line)-1,fp)) { + // file.php arg1 arg2 etc. + char *p = strchr(line, '='); + if (p) { + *p=0; + IsapiEnvironment[line]=p+1; + } + } + fclose(fp); + } + } + + printf("Starting Threads...\r\n"); + // loop creating threads + for (i=0; i< NUM_THREADS; i++) { + terminate[i] = CreateEvent(NULL, FALSE, FALSE, NULL); + DWORD tid; + if (CreateThread(NULL, 0, IsapiThread, &terminate[i], 0, &tid)==NULL){ + SetEvent(terminate[i]); + } + } + // wait for threads to finish + WaitForMultipleObjects(NUM_THREADS, terminate, TRUE, INFINITE); + + // cleanup + + // We should really free memory (e.g., from GetEnv), but we'll be dead + // soon enough + + FreeLibrary(hDll); + return 0; +} + + +DWORD CALLBACK IsapiThread(void *p) +{ + HANDLE *terminate = (HANDLE *)p; + DWORD filecount = IsapiFileList.GetSize(); + for (DWORD j=0; j *lpdwSize) { + SetLastError(ERROR_INSUFFICIENT_BUFFER); + return FALSE; + } + + *lpdwSize =rc + 1 ; // GetEnvironmentVariable does not count the NULL + + return TRUE; + +} +// +// Again, we don't have an HCONN, so we simply wrap ReadClient() to +// ReadFile on stdin. The semantics of the two functions are the same +// +BOOL WINAPI ReadClient(HCONN hConn, LPVOID lpBuffer, LPDWORD lpdwSize) { + TIsapiContext *c = (TIsapiContext *)hConn; + if (!c) return FALSE; + if (c->in) return ReadFile(c->in,lpBuffer,(*lpdwSize), lpdwSize,NULL); + return FALSE; +} +// +// ditto for WriteClient() +// +BOOL WINAPI WriteClient(HCONN hConn, LPVOID lpBuffer, LPDWORD lpdwSize, + DWORD dwReserved) { + TIsapiContext *c = (TIsapiContext *)hConn; + if (!c) return FALSE; + if (c->out) return WriteFile(c->out,lpBuffer,*lpdwSize, lpdwSize,NULL); + return FALSE; +} +// +// This is a special callback function used by the DLL for certain extra +// functionality. Look at the API help for details. +// +BOOL WINAPI ServerSupportFunction(HCONN hConn, DWORD dwHSERequest, + LPVOID lpvBuffer, LPDWORD lpdwSize, LPDWORD lpdwDataType){ + + char *lpszRespBuf; + char * temp = NULL; + DWORD dwBytes; + BOOL bRet; + + switch(dwHSERequest) { + case (HSE_REQ_SEND_RESPONSE_HEADER) : + lpszRespBuf = (char *)xmalloc(*lpdwSize);//+ 80);//accomodate our header + if (!lpszRespBuf) + return FALSE; + wsprintf(lpszRespBuf,"%s", + //HTTP_VER, + + /* Default response is 200 Ok */ + + //lpvBuffer?lpvBuffer:"200 Ok", + + /* Create a string for the time. */ + //temp=MakeDateStr(), + + //SERVER_VERSION, + + /* If this exists, it is a pointer to a data buffer to + be sent. */ + lpdwDataType?(char *)lpdwDataType:NULL); + + if (temp) xfree(temp); + + dwBytes = strlen(lpszRespBuf); + bRet = WriteClient(0,lpszRespBuf,&dwBytes,0); + xfree(lpszRespBuf); + + break; + // + // A real server would do cleanup here + case (HSE_REQ_DONE_WITH_SESSION): + //ExitThread(0); + break; + + // + // This sends a redirect (temporary) to the client. + // The header construction is similar to RESPONSE_HEADER above. + // + case (HSE_REQ_SEND_URL_REDIRECT_RESP): + lpszRespBuf = (char *)xmalloc(*lpdwSize +80) ; + if (!lpszRespBuf) + return FALSE; + wsprintf(lpszRespBuf,"%s %s %s\r\n", + HTTP_VER, + "302 Moved Temporarily", + (lpdwSize > 0)?lpvBuffer:0); + xfree(temp); + dwBytes = strlen(lpszRespBuf); + bRet = WriteClient(0,lpszRespBuf,&dwBytes,0); + xfree(lpszRespBuf); + break; + default: + return FALSE; + break; + } + return bRet; + +} +// +// Makes a string of the date and time from GetSystemTime(). +// This is in UTC, as required by the HTTP spec.` +// +char * MakeDateStr(void){ + SYSTEMTIME systime; + char *szDate= (char *)xmalloc(64); + + char * DaysofWeek[] = {"Sun","Mon","Tue","Wed","Thurs","Fri","Sat"}; + char * Months[] = {"NULL","Jan","Feb","Mar","Apr","May","Jun","Jul","Aug", + "Sep","Oct","Nov","Dec"}; + + GetSystemTime(&systime); + + wsprintf(szDate,"%s, %d %s %d %d:%d.%d",DaysofWeek[systime.wDayOfWeek], + systime.wDay, + Months[systime.wMonth], + systime.wYear, + systime.wHour,systime.wMinute, + systime.wSecond ); + + return szDate; +} +// +// Fill the ECB up +// +BOOL WINAPI FillExtensionControlBlock(EXTENSION_CONTROL_BLOCK *ECB, TIsapiContext *context) { + + char * temp; + ECB->cbSize = sizeof(EXTENSION_CONTROL_BLOCK); + ECB->dwVersion = MAKELONG(HSE_VERSION_MINOR,HSE_VERSION_MAJOR); + ECB->ConnID = (void *)context; + // + // Pointers to the functions the DLL will call. + // + ECB->GetServerVariable = GetServerVariable; + ECB->ReadClient = ReadClient; + ECB->WriteClient = WriteClient; + ECB->ServerSupportFunction = ServerSupportFunction; + + // + // Fill in the standard CGI environment variables + // + ECB->lpszMethod = GetEnv("REQUEST_METHOD"); + ECB->lpszQueryString = GetEnv("QUERY_STRING"); + ECB->lpszPathInfo = GetEnv("PATH_INFO"); + ECB->lpszPathTranslated = GetEnv("PATH_TRANSLATED"); + ECB->cbTotalBytes=( (temp=GetEnv("CONTENT_LENGTH")) ? (atoi(temp)): 0); + ECB->cbAvailable = 0; + ECB->lpbData = (unsigned char *)""; + ECB->lpszContentType = GetEnv("CONTENT_TYPE"); + return TRUE; + +} + +// +// Works like _getenv(), but uses win32 functions instead. +// +char * GetEnv(LPSTR lpszEnvVar) { + + char *var,dummy; + DWORD dwLen; + + if (!lpszEnvVar) + return ""; + + dwLen =GetEnvironmentVariable(lpszEnvVar,&dummy,1); + + if (dwLen == 0) + return ""; + + var = (char *)xmalloc(dwLen); + if (!var) + return ""; + (void)GetEnvironmentVariable(lpszEnvVar,var,dwLen); + + return var; +} diff --git a/sapi/isapi/stresstest/stresstest.dsp b/sapi/isapi/stresstest/stresstest.dsp new file mode 100644 index 0000000000..847de279e5 --- /dev/null +++ b/sapi/isapi/stresstest/stresstest.dsp @@ -0,0 +1,106 @@ +# Microsoft Developer Studio Project File - Name="stresstest" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=stresstest - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "stresstest.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "stresstest.mak" CFG="stresstest - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "stresstest - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "stresstest - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "stresstest - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 2 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /Yu"stdafx.h" /FD /c +# ADD CPP /nologo /MD /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /D "_AFXDLL" /FD /c +# SUBTRACT CPP /YX /Yc /Yu +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" /d "_AFXDLL" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 /nologo /subsystem:console /machine:I386 + +!ELSEIF "$(CFG)" == "stresstest - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 2 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /Yu"stdafx.h" /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "_AFXDLL" /FD /GZ /c +# SUBTRACT CPP /YX /Yc /Yu +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" /d "_AFXDLL" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "stresstest - Win32 Release" +# Name "stresstest - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\stresstest.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# End Group +# Begin Source File + +SOURCE=.\ReadMe.txt +# End Source File +# End Target +# End Project