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>