File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / php / sapi / isapi / stresstest / stresstest.cpp
Revision 1.1.1.2 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Mon Jul 22 01:32:14 2013 UTC (11 years ago) by misho
Branches: php, MAIN
CVS tags: v5_4_29p0, v5_4_29, v5_4_20p0, v5_4_20, v5_4_17, HEAD
5.4.17

    1: /*
    2:  * ======================================================================= *
    3:  * File: stress .c                                                         *
    4:  * stress tester for isapi dll's                                           *
    5:  * based on cgiwrap                                                        *
    6:  * ======================================================================= *
    7:  *
    8: */
    9: #define WIN32_LEAN_AND_MEAN
   10: #include <afx.h>
   11: #include <afxtempl.h>
   12: #include <winbase.h>
   13: #include <winerror.h>
   14: #include <httpext.h>
   15: #include <stdio.h>
   16: #include <stdlib.h>
   17: #include "getopt.h"
   18: 
   19: // These are things that go out in the Response Header
   20: //
   21: #define HTTP_VER     "HTTP/1.0"
   22: #define SERVER_VERSION "Http-Srv-Beta2/1.0"
   23: 
   24: //
   25: // Simple wrappers for the heap APIS
   26: //
   27: #define xmalloc(s) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (s))
   28: #define xfree(s)   HeapFree(GetProcessHeap(), 0, (s))
   29: 
   30: //
   31: // The mandatory exports from the ISAPI DLL
   32: //
   33: DWORD numThreads = 1;
   34: DWORD iterations = 1;
   35: 
   36: HANDLE StartNow;
   37: // quick and dirty environment
   38: typedef CMapStringToString TEnvironment;
   39: TEnvironment IsapiEnvironment;
   40: 
   41: typedef struct _TResults {
   42: 	LONG ok;
   43: 	LONG bad;
   44: } TResults;
   45: 
   46: CStringArray IsapiFileList;  // list of filenames
   47: CStringArray TestNames;      // --TEST--
   48: CStringArray IsapiGetData;   // --GET--
   49: CStringArray IsapiPostData;  // --POST--
   50: CStringArray IsapiMatchData; // --EXPECT--
   51: CArray<TResults, TResults> Results;
   52: 
   53: typedef struct _TIsapiContext {
   54: 	HANDLE in;
   55: 	HANDLE out;
   56: 	DWORD tid;
   57: 	TEnvironment env;
   58: 	HANDLE waitEvent;
   59: } TIsapiContext;
   60: 
   61: //
   62: // Prototypes of the functions this sample implements
   63: //
   64: extern "C" {
   65: HINSTANCE hDll;
   66: typedef BOOL (WINAPI *VersionProc)(HSE_VERSION_INFO *) ;
   67: typedef DWORD (WINAPI *HttpExtProc)(EXTENSION_CONTROL_BLOCK *);
   68: typedef BOOL (WINAPI *TerminateProc) (DWORD);
   69: BOOL WINAPI FillExtensionControlBlock(EXTENSION_CONTROL_BLOCK *, TIsapiContext *) ;
   70: BOOL WINAPI GetServerVariable(HCONN, LPSTR, LPVOID, LPDWORD );
   71: BOOL WINAPI ReadClient(HCONN, LPVOID, LPDWORD);
   72: BOOL WINAPI WriteClient(HCONN, LPVOID, LPDWORD, DWORD);
   73: BOOL WINAPI ServerSupportFunction(HCONN, DWORD, LPVOID, LPDWORD, LPDWORD);
   74: VersionProc IsapiGetExtensionVersion;
   75: HttpExtProc IsapiHttpExtensionProc;
   76: TerminateProc TerminateExtensionProc;
   77: HSE_VERSION_INFO version_info;
   78: }
   79: 
   80: char * MakeDateStr(VOID);
   81: char * GetEnv(char *);
   82: 
   83: 
   84: 
   85: 
   86: DWORD CALLBACK IsapiThread(void *);
   87: int stress_main(const char *filename, 
   88: 				const char *arg, 
   89: 				const char *postfile, 
   90: 				const char *matchdata);
   91: 
   92: 
   93: 
   94: BOOL bUseTestFiles = FALSE;
   95: char temppath[MAX_PATH];
   96: 
   97: void stripcrlf(char *line)
   98: {
   99: 	DWORD l = strlen(line)-1;
  100: 	if (line[l]==10 || line[l]==13) line[l]=0;
  101: 	l = strlen(line)-1;
  102: 	if (line[l]==10 || line[l]==13) line[l]=0;
  103: }
  104: 
  105: #define COMPARE_BUF_SIZE	1024
  106: 
  107: BOOL CompareFiles(const char*f1, const char*f2)
  108: {
  109: 	FILE *fp1, *fp2;
  110: 	bool retval;
  111: 	char buf1[COMPARE_BUF_SIZE], buf2[COMPARE_BUF_SIZE];
  112: 	int length1, length2;
  113: 
  114: 	if ((fp1=fopen(f1, "r"))==NULL) {
  115: 		return FALSE;
  116: 	}
  117: 
  118: 	if ((fp2=fopen(f2, "r"))==NULL) {
  119: 		fclose(fp1);
  120: 		return FALSE;
  121: 	}
  122: 
  123: 	retval = TRUE; // success oriented
  124: 	while (true) {
  125: 		length1 = fread(buf1, 1, sizeof(buf1), fp1);
  126: 		length2 = fread(buf2, 1, sizeof(buf2), fp2);
  127: 
  128: 		// check for end of file
  129: 		if (feof(fp1)) {
  130: 			if (!feof(fp2)) {
  131: 				retval = FALSE;
  132: 			}
  133: 			break;
  134: 		} else if (feof(fp2)) {
  135: 			if (!feof(fp1)) {
  136: 				retval = FALSE;
  137: 			}
  138: 			break;
  139: 		}
  140: 
  141: 		// compare data
  142: 		if (length1!=length2
  143: 			|| memcmp(buf1, buf2, length1)!=0) {
  144: 			retval = FALSE;
  145: 			break;
  146: 		}
  147: 	}
  148: 	fclose(fp1);
  149: 	fclose(fp2);
  150: 
  151: 	return retval;
  152: }
  153: 
  154: 
  155: BOOL CompareStringWithFile(const char *filename, const char *str, unsigned int str_length)
  156: {
  157: 	FILE *fp;
  158: 	bool retval;
  159: 	char buf[COMPARE_BUF_SIZE];
  160: 	unsigned int offset=0, readbytes;
  161: 	fprintf(stderr, "test %s\n",filename);
  162: 	if ((fp=fopen(filename, "rb"))==NULL) {
  163: 		fprintf(stderr, "Error opening %s\n",filename);
  164: 		return FALSE;
  165: 	}
  166: 
  167: 	retval = TRUE; // success oriented
  168: 	while (true) {
  169: 		readbytes = fread(buf, 1, sizeof(buf), fp);
  170: 
  171: 		// check for end of file
  172: 
  173: 		if (offset+readbytes > str_length
  174: 			|| memcmp(buf, str+offset, readbytes)!=NULL) {
  175: 			fprintf(stderr, "File missmatch %s\n",filename);
  176: 			retval = FALSE;
  177: 			break;
  178: 		}
  179: 		if (feof(fp)) {
  180: 			if (!retval) fprintf(stderr, "File zero length %s\n",filename);
  181: 			break;
  182: 		}
  183: 	}
  184: 	fclose(fp);
  185: 
  186: 	return retval;
  187: }
  188: 
  189: 
  190: BOOL ReadGlobalEnvironment(const char *environment)
  191: {
  192: 	if (environment) {
  193: 	FILE *fp = fopen(environment, "r");
  194: 	DWORD i=0;
  195: 	if (fp) {
  196: 		char line[2048];
  197: 		while (fgets(line, sizeof(line)-1, fp)) {
  198: 			// file.php arg1 arg2 etc.
  199: 			char *p = strchr(line, '=');
  200: 			if (p) {
  201: 				*p=0;
  202: 				IsapiEnvironment[line]=p+1;
  203: 			}
  204: 		}
  205: 		fclose(fp);
  206: 		return IsapiEnvironment.GetCount() > 0;
  207: 	}
  208: 	}
  209: 	return FALSE;
  210: }
  211: 
  212: BOOL ReadFileList(const char *filelist)
  213: {
  214: 	FILE *fp = fopen(filelist, "r");
  215: 	if (!fp) {
  216: 		printf("Unable to open %s\r\n", filelist);
  217: 	}
  218: 	char line[2048];
  219: 	int i=0;
  220: 	while (fgets(line, sizeof(line)-1, fp)) {
  221: 		// file.php arg1 arg2 etc.
  222: 		stripcrlf(line);
  223: 		if (strlen(line)>3) {
  224: 			char *p = strchr(line, ' ');
  225: 			if (p) {
  226: 				*p = 0;
  227: 				// get file
  228: 
  229: 				IsapiFileList.Add(line);
  230: 				IsapiGetData.Add(p+1);
  231: 			} else {
  232: 				// just a filename is all
  233: 				IsapiFileList.Add(line);
  234: 				IsapiGetData.Add("");
  235: 			}
  236: 		}
  237: 
  238: 		// future use
  239: 		IsapiPostData.Add("");
  240: 		IsapiMatchData.Add("");
  241: 		TestNames.Add("");
  242: 
  243: 		i++;
  244: 	}
  245: 	Results.SetSize(TestNames.GetSize());
  246: 
  247: 	fclose(fp);
  248: 	return IsapiFileList.GetSize() > 0;
  249: }
  250: 
  251: void DoThreads() {
  252: 
  253: 	if (IsapiFileList.GetSize() == 0) {
  254: 		printf("No Files to test\n");
  255: 		return;
  256: 	}
  257: 
  258: 	printf("Starting Threads...\n");
  259: 	// loop creating threads
  260: 	DWORD tid;
  261: 	HANDLE *threads = new HANDLE[numThreads];
  262: 	DWORD i;
  263: 	for (i=0; i< numThreads; i++) {
  264: 		threads[i]=CreateThread(NULL, 0, IsapiThread, NULL, CREATE_SUSPENDED, &tid);
  265: 	}
  266: 	for (i=0; i< numThreads; i++) {
  267: 		if (threads[i]) ResumeThread(threads[i]);
  268: 	}
  269: 	// wait for threads to finish
  270: 	WaitForMultipleObjects(numThreads, threads, TRUE, INFINITE);
  271: 	for (i=0; i< numThreads; i++) {
  272: 		CloseHandle(threads[i]);
  273: 	}
  274: 	delete [] threads;
  275: }
  276: 
  277: void DoFileList(const char *filelist, const char *environment)
  278: {
  279: 	// read config files
  280: 
  281: 	if (!ReadFileList(filelist)) {
  282: 		printf("No Files to test!\r\n");
  283: 		return;
  284: 	}
  285: 
  286: 	ReadGlobalEnvironment(environment);
  287: 
  288: 	DoThreads();
  289: }
  290: 
  291: 
  292: /**
  293:  * ParseTestFile
  294:  * parse a single phpt file and add it to the arrays
  295:  */
  296: BOOL ParseTestFile(const char *path, const char *fn)
  297: {
  298: 	// parse the test file
  299: 	char filename[MAX_PATH];
  300: 	_snprintf(filename, sizeof(filename)-1, "%s\\%s", path, fn);
  301: 	char line[1024];
  302: 	memset(line, 0, sizeof(line));
  303: 	CString cTest, cSkipIf, cPost, cGet, cFile, cExpect;
  304: 	printf("Reading %s\r\n", filename);
  305: 
  306: 	enum state {none, test, skipif, post, get, file, expect} parsestate = none;
  307: 
  308: 	FILE *fp = fopen(filename, "rb");
  309: 	char *tn = _tempnam(temppath,"pht.");
  310: 	char *en = _tempnam(temppath,"exp.");
  311: 	FILE *ft = fopen(tn, "wb+");
  312: 	FILE *fe = fopen(en, "wb+");
  313: 	if (fp && ft && fe) {
  314: 		while (fgets(line, sizeof(line)-1, fp)) {
  315: 			if (line[0]=='-') {
  316: 				if (_strnicmp(line, "--TEST--", 8)==0) {
  317: 					parsestate = test;
  318: 					continue;
  319: 				} else if (_strnicmp(line, "--SKIPIF--", 10)==0) {
  320: 					parsestate = skipif;
  321: 					continue;
  322: 				} else if (_strnicmp(line, "--POST--", 8)==0) {
  323: 					parsestate = post;
  324: 					continue;
  325: 				} else if (_strnicmp(line, "--GET--", 7)==0) {
  326: 					parsestate = get;
  327: 					continue;
  328: 				} else if (_strnicmp(line, "--FILE--", 8)==0) {
  329: 					parsestate = file;
  330: 					continue;
  331: 				} else if (_strnicmp(line, "--EXPECT--", 10)==0) {
  332: 					parsestate = expect;
  333: 					continue;
  334: 				}
  335: 			}
  336: 			switch (parsestate) {
  337: 			case test:
  338: 				stripcrlf(line);
  339: 				cTest = line;
  340: 				break;
  341: 			case skipif:
  342: 				cSkipIf += line;
  343: 				break;
  344: 			case post:
  345: 				cPost += line;
  346: 				break;
  347: 			case get:
  348: 				cGet += line;
  349: 				break;
  350: 			case file:
  351: 				fputs(line, ft);
  352: 				break;
  353: 			case expect:
  354: 				fputs(line, fe);
  355: 				break;
  356: 			}
  357: 		}		
  358: 
  359: 		fclose(fp);
  360: 		fclose(ft);
  361: 		fclose(fe);
  362: 
  363: 		if (!cTest.IsEmpty()) {
  364: 			IsapiFileList.Add(tn);
  365: 			TestNames.Add(cTest);
  366: 			IsapiGetData.Add(cGet);
  367: 			IsapiPostData.Add(cPost);
  368: 			IsapiMatchData.Add(en);
  369: 			free(tn);
  370: 			free(en);
  371: 			return TRUE;
  372: 		}
  373: 	}
  374: 	free(tn);
  375: 	free(en);
  376: 	return FALSE;
  377: }
  378: 
  379: 
  380: /**
  381:  * GetTestFiles
  382:  * Recurse through the path and subdirectories, parse each phpt file
  383:  */
  384: BOOL GetTestFiles(const char *path)
  385: {
  386: 	// find all files .phpt under testpath\tests
  387: 	char FindPath[MAX_PATH];
  388: 	WIN32_FIND_DATA fd;
  389: 	memset(&fd, 0, sizeof(WIN32_FIND_DATA));
  390: 
  391: 	_snprintf(FindPath, sizeof(FindPath)-1, "%s\\*.*", path);
  392: 	HANDLE fh = FindFirstFile(FindPath, &fd);
  393: 	if (fh != INVALID_HANDLE_VALUE) {
  394: 		do {
  395: 			if ((fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) &&
  396: 				!strchr(fd.cFileName, '.')) {
  397: 				// subdirectory, recurse into it
  398: 				char NewFindPath[MAX_PATH];
  399: 				_snprintf(NewFindPath, sizeof(NewFindPath)-1, "%s\\%s", path, fd.cFileName);
  400: 				GetTestFiles(NewFindPath);
  401: 			} else if (strstr(fd.cFileName, ".phpt")) {
  402: 				// got test file, parse it now
  403: 				if (ParseTestFile(path, fd.cFileName)) {
  404: 					printf("Test File Added: %s\\%s\r\n", path, fd.cFileName);
  405: 				}
  406: 			}
  407: 			memset(&fd, 0, sizeof(WIN32_FIND_DATA));
  408: 		} while (FindNextFile(fh, &fd) != 0);
  409: 		FindClose(fh);
  410: 	}
  411: 	return IsapiFileList.GetSize() > 0;
  412: }
  413: 
  414: void DeleteTempFiles(const char *mask)
  415: {
  416: 	char FindPath[MAX_PATH];
  417: 	WIN32_FIND_DATA fd;
  418: 	memset(&fd, 0, sizeof(WIN32_FIND_DATA));
  419: 
  420: 	_snprintf(FindPath, sizeof(FindPath)-1, "%s\\%s", temppath, mask);
  421: 	HANDLE fh = FindFirstFile(FindPath, &fd);
  422: 	if (fh != INVALID_HANDLE_VALUE) {
  423: 		do {
  424: 			char NewFindPath[MAX_PATH];
  425: 			_snprintf(NewFindPath, sizeof(NewFindPath)-1, "%s\\%s", temppath, fd.cFileName);
  426: 			DeleteFile(NewFindPath);
  427: 			memset(&fd, 0, sizeof(WIN32_FIND_DATA));
  428: 		} while (FindNextFile(fh, &fd) != 0);
  429: 		FindClose(fh);
  430: 	}
  431: }
  432: 
  433: void DoTestFiles(const char *filelist, const char *environment)
  434: {
  435: 	if (!GetTestFiles(filelist)) {
  436: 		printf("No Files to test!\r\n");
  437: 		return;
  438: 	}
  439: 
  440: 	Results.SetSize(IsapiFileList.GetSize());
  441: 
  442: 	ReadGlobalEnvironment(environment);
  443: 
  444: 	DoThreads();
  445: 
  446: 	printf("\r\nRESULTS:\r\n");
  447: 	// show results:
  448: 	DWORD r = Results.GetSize();
  449: 	for (DWORD i=0; i< r; i++) {
  450: 		TResults result = Results.GetAt(i);
  451: 		printf("%s\r\nOK: %d FAILED: %d\r\n", TestNames.GetAt(i), result.ok, result.bad);
  452: 	}
  453: 
  454: 	// delete temp files
  455: 	printf("Deleting Temp Files\r\n");
  456: 	DeleteTempFiles("exp.*");
  457: 	DeleteTempFiles("pht.*");
  458: 	printf("Done\r\n");
  459: }
  460: 
  461: #define OPTSTRING "m:f:d:h:t:i:"
  462: static void _usage(char *argv0)
  463: {
  464: 	char *prog;
  465: 
  466: 	prog = strrchr(argv0, '/');
  467: 	if (prog) {
  468: 		prog++;
  469: 	} else {
  470: 		prog = "stresstest";
  471: 	}
  472: 
  473: 	printf("Usage: %s -m <isapi.dll> -d|-l <file> [-t <numthreads>] [-i <numiterations>]\n"
  474: 				"  -m             path to isapi dll\n"
  475: 				"  -d <directory> php directory (to run php test files).\n"
  476: 				"  -f <file>      file containing list of files to run\n"
  477: 				"  -t             number of threads to use (default=1)\n"
  478:                 "  -i             number of iterations per thread (default=1)\n"
  479: 				"  -h             This help\n", prog);
  480: }
  481: int main(int argc, char* argv[])
  482: {
  483: 	LPVOID lpMsgBuf;
  484: 	char *filelist=NULL, *environment=NULL, *module=NULL;
  485: 	int c = NULL;
  486: 	while ((c=ap_getopt(argc, argv, OPTSTRING))!=-1) {
  487: 		switch (c) {
  488: 			case 'd':
  489: 				bUseTestFiles = TRUE;
  490: 				filelist = strdup(ap_optarg);
  491: 				break;
  492: 			case 'f':
  493: 				bUseTestFiles = FALSE;
  494: 				filelist = strdup(ap_optarg);
  495: 				break;
  496: 			case 'e':
  497: 				environment = strdup(ap_optarg);
  498: 				break;
  499: 			case 't':
  500: 				numThreads = atoi(ap_optarg);
  501: 				break;
  502: 			case 'i':
  503: 				iterations = atoi(ap_optarg);
  504: 				break;
  505: 			case 'm':
  506: 				module = strdup(ap_optarg);
  507: 				break;
  508: 			case 'h':
  509: 				_usage(argv[0]);
  510: 				exit(0);
  511: 				break;
  512: 		}
  513: 	}
  514: 	if (!module || !filelist) {
  515: 		_usage(argv[0]);
  516: 		exit(0);
  517: 	}
  518: 
  519: 	GetTempPath(sizeof(temppath), temppath);
  520: 	hDll = LoadLibrary(module); // Load our DLL
  521: 
  522: 	if (!hDll) {
  523: 		FormatMessage( 
  524: 		   FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
  525: 		    NULL,
  526: 		    GetLastError(),
  527: 		    MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
  528: 		    (LPTSTR) &lpMsgBuf,
  529: 		    0,
  530: 		    NULL 
  531: 		);
  532: 		fprintf(stderr,"Error: Dll 'php5isapi.dll' not found -%d\n%s\n", GetLastError(), lpMsgBuf);
  533: 		free (module);
  534: 		free(filelist);
  535: 		LocalFree( lpMsgBuf );
  536: 		return -1;
  537: 	}
  538: 
  539: 	//
  540: 	// Find the exported functions
  541: 
  542: 	IsapiGetExtensionVersion = (VersionProc)GetProcAddress(hDll,"GetExtensionVersion");
  543: 	if (!IsapiGetExtensionVersion) {
  544: 		fprintf(stderr,"Can't Get Extension Version %d\n", GetLastError());
  545: 		free (module);
  546: 		free(filelist);
  547: 		return -1;
  548: 	}
  549: 	IsapiHttpExtensionProc = (HttpExtProc)GetProcAddress(hDll,"HttpExtensionProc");
  550: 	if (!IsapiHttpExtensionProc) {
  551: 		fprintf(stderr,"Can't Get Extension proc %d\n", GetLastError());
  552: 		free (module);
  553: 		free(filelist);
  554: 		return -1;
  555: 	}
  556: 	TerminateExtensionProc = (TerminateProc) GetProcAddress(hDll, 
  557:                                           "TerminateExtension");
  558: 
  559: 	// This should really check if the version information matches what we
  560: 	// expect.
  561: 	//
  562: 	if (!IsapiGetExtensionVersion(&version_info) ) {
  563: 		fprintf(stderr,"Fatal: GetExtensionVersion failed\n");
  564: 		free (module);
  565: 		free(filelist);
  566: 		return -1;
  567: 	}
  568: 
  569: 	if (bUseTestFiles) {
  570: 		char TestPath[MAX_PATH];
  571: 		if (filelist != NULL) 
  572: 			_snprintf(TestPath, sizeof(TestPath)-1, "%s\\tests", filelist);
  573: 		else strcpy(TestPath, "tests");
  574: 		DoTestFiles(TestPath, environment);
  575: 	} else {
  576: 		DoFileList(filelist, environment);
  577: 	}
  578: 
  579: 	// cleanup
  580: 	if (TerminateExtensionProc) TerminateExtensionProc(0);
  581: 
  582: 	// We should really free memory (e.g., from GetEnv), but we'll be dead
  583: 	// soon enough
  584: 
  585: 	FreeLibrary(hDll);
  586: 	free (module);
  587: 	free(filelist);
  588: 	return 0;
  589: }
  590: 
  591: 
  592: DWORD CALLBACK IsapiThread(void *p)
  593: {
  594: 	DWORD filecount = IsapiFileList.GetSize();
  595: 
  596: 	for (DWORD j=0; j<iterations; j++) {
  597: 		for (DWORD i=0; i<filecount; i++) {
  598: 			// execute each file
  599: 			CString testname = TestNames.GetAt(i);
  600: 			BOOL ok = FALSE;
  601: 			if (stress_main(IsapiFileList.GetAt(i), 
  602: 						IsapiGetData.GetAt(i), 
  603: 						IsapiPostData.GetAt(i),
  604: 						IsapiMatchData.GetAt(i))) {
  605: 				InterlockedIncrement(&Results[i].ok);
  606: 				ok = TRUE;
  607: 			} else {
  608: 				InterlockedIncrement(&Results[i].bad);
  609: 				ok = FALSE;
  610: 			}
  611: 
  612: 			if (testname.IsEmpty()) {
  613: 				printf("Thread %d File %s\n", GetCurrentThreadId(), IsapiFileList.GetAt(i));
  614: 			} else {
  615: 				printf("tid %d: %s %s\n", GetCurrentThreadId(), testname, ok?"OK":"FAIL");
  616: 			}
  617: 			Sleep(10);
  618: 		}
  619: 	}
  620: 	printf("Thread ending...\n");
  621: 	return 0;
  622: }
  623: 
  624: /*
  625:  * ======================================================================= *
  626:  * In the startup of this program, we look at our executable name and      *
  627:  * replace the ".EXE" with ".DLL" to find the ISAPI DLL we need to load.   *
  628:  * This means that the executable need only be given the same "name" as    *
  629:  * the DLL to load. There is no recompilation required.                    *
  630:  * ======================================================================= *
  631: */
  632: BOOL stress_main(const char *filename, 
  633: 				const char *arg, 
  634: 				const char *postdata,
  635: 				const char *matchdata) 
  636: {
  637: 
  638: 	EXTENSION_CONTROL_BLOCK ECB;
  639: 	DWORD rc;
  640: 	TIsapiContext context;
  641: 
  642: 	// open output and input files
  643: 	context.tid = GetCurrentThreadId();
  644: 	CString fname;
  645: 	fname.Format("%08X.out", context.tid);
  646: 
  647: 	context.out = CreateFile(fname, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_FLAG_WRITE_THROUGH, NULL);
  648: 	if (context.out==INVALID_HANDLE_VALUE) {
  649: 		printf("failed to open output file %s\n", fname);
  650: 		return 0;
  651: 	}
  652: 
  653: 	// not using post files
  654: 	context.in = INVALID_HANDLE_VALUE;
  655: 
  656: 	//
  657: 	// Fill the ECB with the necessary information
  658: 	//
  659: 	if (!FillExtensionControlBlock(&ECB, &context) ) {
  660: 		fprintf(stderr,"Fill Ext Block Failed\n");
  661: 		return -1;
  662: 	}
  663: 	
  664: 	// check for command line argument, 
  665: 	// first arg = filename
  666: 	// this is added for testing php from command line
  667: 
  668: 	context.env.RemoveAll();
  669: 	context.env["PATH_TRANSLATED"]= filename;
  670: 	context.env["SCRIPT_MAP"]= filename;
  671: 	context.env["CONTENT_TYPE"]= "";
  672: 	context.env["CONTENT_LENGTH"]= "";
  673: 	context.env["QUERY_STRING"]= arg;
  674: 	context.env["METHOD"]="GET";
  675: 	context.env["PATH_INFO"] = "";
  676: 	context.waitEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
  677: 	char buf[MAX_PATH];
  678: 	if (postdata && *postdata !=0) {
  679: 		ECB.cbAvailable = strlen(postdata);
  680: 		ECB.cbTotalBytes = ECB.cbAvailable;
  681: 		ECB.lpbData = (unsigned char *)postdata;
  682: 		context.env["METHOD"]="POST";
  683: 
  684: 		_snprintf(buf, sizeof(buf)-1, "%d", ECB.cbTotalBytes);
  685: 		context.env["CONTENT_LENGTH"]=buf;
  686: 
  687: 		context.env["CONTENT_TYPE"]="application/x-www-form-urlencoded";
  688: 	}
  689: 	ECB.lpszMethod = strdup(context.env["METHOD"]);
  690:     ECB.lpszPathTranslated = strdup(filename);
  691: 	ECB.lpszQueryString = strdup(arg);
  692: 	ECB.lpszPathInfo = strdup(context.env["PATH_INFO"]);
  693: 
  694: 
  695: 	// Call the DLL
  696: 	//
  697: 	rc = IsapiHttpExtensionProc(&ECB);
  698: 	if (rc == HSE_STATUS_PENDING) {
  699: 		// We will exit in ServerSupportFunction
  700: 		WaitForSingleObject(context.waitEvent, INFINITE);
  701: 	}
  702: 	CloseHandle(context.waitEvent);
  703: 	//Sleep(75);
  704: 	free(ECB.lpszPathTranslated);
  705: 	free(ECB.lpszQueryString);
  706: 	free(ECB.lpszMethod);
  707: 	free(ECB.lpszPathInfo);
  708: 
  709: 	BOOL ok = TRUE;
  710: 
  711: 	if (context.out != INVALID_HANDLE_VALUE) CloseHandle(context.out);
  712: 
  713: 	// compare the output with the EXPECT section
  714: 	if (matchdata && *matchdata != 0) {
  715: 		ok = CompareFiles(fname, matchdata);
  716: 	}
  717: 
  718: 	DeleteFile(fname);
  719: 
  720: 	return ok;
  721: 		
  722: }
  723: //
  724: // GetServerVariable() is how the DLL calls the main program to figure out
  725: // the environment variables it needs. This is a required function.
  726: //
  727: BOOL WINAPI GetServerVariable(HCONN hConn, LPSTR lpszVariableName,
  728: 								LPVOID lpBuffer, LPDWORD lpdwSize){
  729: 
  730: 	DWORD rc;
  731: 	CString value;
  732: 	TIsapiContext *c = (TIsapiContext *)hConn;
  733: 	if (!c) return FALSE;
  734: 
  735: 	if (IsapiEnvironment.Lookup(lpszVariableName, value)) {
  736: 		rc = value.GetLength();
  737: 		strncpy((char *)lpBuffer, value, *lpdwSize-1);
  738: 	} else if (c->env.Lookup(lpszVariableName, value)) {
  739: 		rc = value.GetLength();
  740: 		strncpy((char *)lpBuffer, value, *lpdwSize-1);
  741: 	} else
  742: 		rc = GetEnvironmentVariable(lpszVariableName, (char *)lpBuffer, *lpdwSize) ;
  743: 
  744: 	if (!rc) { // return of 0 indicates the variable was not found
  745: 		SetLastError(ERROR_NO_DATA);
  746: 		return FALSE;
  747: 	}
  748: 
  749: 	if (rc > *lpdwSize) {
  750: 		SetLastError(ERROR_INSUFFICIENT_BUFFER);
  751: 		return FALSE;
  752: 	}
  753: 
  754: 	*lpdwSize =rc + 1 ; // GetEnvironmentVariable does not count the NULL
  755: 
  756: 	return TRUE;
  757: 
  758: }
  759: //
  760: // Again, we don't have an HCONN, so we simply wrap ReadClient() to
  761: // ReadFile on stdin. The semantics of the two functions are the same
  762: //
  763: BOOL WINAPI ReadClient(HCONN hConn, LPVOID lpBuffer, LPDWORD lpdwSize) {
  764: 	TIsapiContext *c = (TIsapiContext *)hConn;
  765: 	if (!c) return FALSE;
  766: 
  767: 	if (c->in != INVALID_HANDLE_VALUE) 
  768: 		return ReadFile(c->in, lpBuffer, (*lpdwSize), lpdwSize, NULL);
  769: 
  770: 	return FALSE;
  771: }
  772: //
  773: // ditto for WriteClient()
  774: //
  775: BOOL WINAPI WriteClient(HCONN hConn, LPVOID lpBuffer, LPDWORD lpdwSize,
  776: 			DWORD dwReserved) {
  777: 	TIsapiContext *c = (TIsapiContext *)hConn;
  778: 	if (!c) return FALSE;
  779: 
  780: 	if (c->out != INVALID_HANDLE_VALUE)
  781: 		return WriteFile(c->out, lpBuffer, *lpdwSize, lpdwSize, NULL);
  782: 	return FALSE;
  783: }
  784: //
  785: // This is a special callback function used by the DLL for certain extra 
  786: // functionality. Look at the API help for details.
  787: //
  788: BOOL WINAPI ServerSupportFunction(HCONN hConn, DWORD dwHSERequest,
  789: 				LPVOID lpvBuffer, LPDWORD lpdwSize, LPDWORD lpdwDataType){
  790: 
  791: 	TIsapiContext *c = (TIsapiContext *)hConn;
  792: 	char *lpszRespBuf;
  793: 	char * temp = NULL;
  794: 	DWORD dwBytes;
  795: 	BOOL bRet = TRUE;
  796: 
  797: 	switch(dwHSERequest) {
  798: 		case (HSE_REQ_SEND_RESPONSE_HEADER) :
  799: 			lpszRespBuf = (char *)xmalloc(*lpdwSize);//+ 80);//accommodate our header
  800: 			if (!lpszRespBuf)
  801: 				return FALSE;
  802: 			wsprintf(lpszRespBuf,"%s",
  803: 				//HTTP_VER,
  804: 				
  805: 				/* Default response is 200 Ok */
  806: 
  807: 				//lpvBuffer?lpvBuffer:"200 Ok",
  808: 				
  809: 				/* Create a string for the time. */
  810: 				//temp=MakeDateStr(),
  811: 
  812: 				//SERVER_VERSION,
  813: 				
  814: 				/* If this exists, it is a pointer to a data buffer to
  815: 				   be sent. */
  816: 				lpdwDataType?(char *)lpdwDataType:NULL);
  817: 
  818: 			if (temp) xfree(temp);
  819: 
  820: 			dwBytes = strlen(lpszRespBuf);
  821: 			bRet = WriteClient(0, lpszRespBuf, &dwBytes, 0);
  822: 			xfree(lpszRespBuf);
  823: 
  824: 			break;
  825: 			//
  826: 			// A real server would do cleanup here
  827: 		case (HSE_REQ_DONE_WITH_SESSION):
  828: 			SetEvent(c->waitEvent);
  829: 			//ExitThread(0);
  830: 			break;
  831: 		
  832: 		//
  833: 		// This sends a redirect (temporary) to the client.
  834: 		// The header construction is similar to RESPONSE_HEADER above.
  835: 		//
  836: 		case (HSE_REQ_SEND_URL_REDIRECT_RESP):
  837: 			lpszRespBuf = (char *)xmalloc(*lpdwSize +80) ;
  838: 			if (!lpszRespBuf)
  839: 				return FALSE;
  840: 			wsprintf(lpszRespBuf,"%s %s %s\r\n",
  841: 					HTTP_VER,
  842: 					"302 Moved Temporarily",
  843: 					(lpdwSize > 0)?lpvBuffer:0);
  844: 			xfree(temp);
  845: 			dwBytes = strlen(lpszRespBuf);
  846: 			bRet = WriteClient(0, lpszRespBuf, &dwBytes, 0);
  847: 			xfree(lpszRespBuf);
  848: 			break;
  849: 		default:
  850: 			return FALSE;
  851: 		break;
  852: 	}
  853: 	return bRet;
  854: 	
  855: }
  856: //
  857: // Makes a string of the date and time from GetSystemTime().
  858: // This is in UTC, as required by the HTTP spec.`
  859: //
  860: char * MakeDateStr(void){
  861: 	SYSTEMTIME systime;
  862: 	char *szDate= (char *)xmalloc(64);
  863: 
  864: 	char * DaysofWeek[] = {"Sun","Mon","Tue","Wed","Thurs","Fri","Sat"};
  865: 	char * Months[] = {"NULL","Jan","Feb","Mar","Apr","May","Jun","Jul","Aug",
  866: 						"Sep","Oct","Nov","Dec"};
  867: 
  868: 	GetSystemTime(&systime);
  869: 
  870: 	wsprintf(szDate,"%s, %d %s %d %d:%d.%d", DaysofWeek[systime.wDayOfWeek],
  871: 									  systime.wDay,
  872: 									  Months[systime.wMonth],
  873: 									  systime.wYear,
  874: 									  systime.wHour, systime.wMinute,
  875: 									  systime.wSecond );
  876: 
  877: 	return szDate;
  878: }
  879: //
  880: // Fill the ECB up 
  881: //
  882: BOOL WINAPI FillExtensionControlBlock(EXTENSION_CONTROL_BLOCK *ECB, TIsapiContext *context) {
  883: 
  884: 	char * temp;
  885: 	ECB->cbSize = sizeof(EXTENSION_CONTROL_BLOCK);
  886: 	ECB->dwVersion = MAKELONG(HSE_VERSION_MINOR, HSE_VERSION_MAJOR);
  887: 	ECB->ConnID = (void *)context;
  888: 	//
  889: 	// Pointers to the functions the DLL will call.
  890: 	//
  891: 	ECB->GetServerVariable = GetServerVariable;
  892: 	ECB->ReadClient  = ReadClient;
  893: 	ECB->WriteClient = WriteClient;
  894: 	ECB->ServerSupportFunction = ServerSupportFunction;
  895: 
  896: 	//
  897: 	// Fill in the standard CGI environment variables
  898: 	//
  899: 	ECB->lpszMethod = GetEnv("REQUEST_METHOD");
  900: 	if (!ECB->lpszMethod) ECB->lpszMethod = "GET";
  901: 
  902: 	ECB->lpszQueryString = GetEnv("QUERY_STRING");
  903: 	ECB->lpszPathInfo = GetEnv("PATH_INFO");
  904: 	ECB->lpszPathTranslated = GetEnv("PATH_TRANSLATED");
  905: 	ECB->cbTotalBytes=( (temp=GetEnv("CONTENT_LENGTH")) ? (atoi(temp)): 0);
  906: 	ECB->cbAvailable = 0;
  907: 	ECB->lpbData = (unsigned char *)"";
  908: 	ECB->lpszContentType = GetEnv("CONTENT_TYPE");
  909: 	return TRUE;
  910: 
  911: }
  912: 
  913: //
  914: // Works like _getenv(), but uses win32 functions instead.
  915: //
  916: char *GetEnv(LPSTR lpszEnvVar)
  917: {
  918: 	
  919: 	char *var, dummy;
  920: 	DWORD dwLen;
  921: 
  922: 	if (!lpszEnvVar)
  923: 		return "";
  924: 	
  925: 	dwLen =GetEnvironmentVariable(lpszEnvVar, &dummy, 1);
  926: 
  927: 	if (dwLen == 0)
  928: 		return "";
  929: 	
  930: 	var = (char *)xmalloc(dwLen);
  931: 	if (!var)
  932: 		return "";
  933: 	(void)GetEnvironmentVariable(lpszEnvVar, var, dwLen);
  934: 
  935: 	return var;
  936: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>