Annotation of embedaddon/php/sapi/isapi/stresstest/stresstest.cpp, revision 1.1
1.1 ! misho 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);//accomodate 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>