/*****************************************************************************/ /* CGIplusTest.c Script for testing and benchmarking the relative efficiencies of CGI, CGIplus and Apache loadable modules. WASD CGI http://the.host.name/cgi-bin/cgiplustest? WASD CGIplus http://the.host.name/cgiplus-bin/cgiplustest? Apache module http://the.host.name/cgiplustest? The Apache module also provides functionality akin to WASD ResponseStream(). For loadable module configuration see below. USAGE ----- Supply a query string ("?blah-blah") of/to ... * list all CGI(plus) variables integer output number of 80 character lines before=integer sleep number of seconds before beginning output after=integer sleep number of seconds after completing output non-cgi-response upset the server by outputting a non-CGI response CGIPLUS_VAR_RECORD ------------------ To "force" the use of 'record' mode (perhaps for performance comparison purposes) assign a non-empty environment variable (symbol or logical) named CGIPLUS_VAR_RECORD. This is detected in the CGIPLUS_CGIVAR.C module. COPYRIGHT --------- Copyright (C) 1997-2021 Mark G.Daniel Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. VERSION HISTORY (update SOFTWAREVN as well!) --------------- 20-APR-2020 MGD v1.6.0, Apache loadable module for performance comparison also equivalent functionality WASD ResponseStream() 19-OCT-2009 MGD v1.5.0, use CGILIB to make the OSU test-bench more equitable and "Pragma: no-cache" - gotcha! 23-DEC-2003 MGD v1.4.2, minor conditional mods to support IA64 18-JUN-2003 MGD v1.4.1, CSWS APACHE_SHARED_SOCKET to APACHE$SHARED_SOCKET, 09-APR-2001 MGD v1.4.0, facility to test/measure CGIplus 'struct' mode 11-JAN-2001 MGD v1.3.0, CSWS V1.0-1 (Apache) "fixbg" support 23-SEP-2000 MGD v1.2,0, minor mods for comparison with VMS Apache 05-MAR-1999 MGD v1.1.0, minor mods for comparison with OSU 08-JUN-1997 MGD v1.0.0, initial development */ /*****************************************************************************/ #define SOFTWAREVN "1.6.0" #define SOFTWARENM "CGIPLUSTEST" #ifdef __ALPHA # define SOFTWAREID SOFTWARENM " AXP-" SOFTWAREVN #endif #ifdef __ia64 # define SOFTWAREID SOFTWARENM " IA64-" SOFTWAREVN #endif #ifdef __VAX # define SOFTWAREID SOFTWARENM " VAX-" SOFTWAREVN #endif #ifdef __x86_64 # define SOFTWAREID SOFTWARENM " X86-" SOFTWAREVN #endif /* standard C headers */ #include #include #include #include #include #include #include int AfterCount, BeforeCount, Debug, IsCgiPlus, RequestedCount; char Utility [] = "CGIPLUSTEST", Line80Chars [] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ\ abcdefghijklmnopqrstuvwxyz\ 0123456789\ !@#$%^&*()_+-=<>,\n"; /*****************************************************************************/ /* */ #ifndef APACHE_MOD main (int argc, char* argv[]) { char *cptr; /*********/ /* begin */ /*********/ Debug = getenv ("CGIPLUSTEST$DBUG") != NULL; CgiLibEnvironmentInit (argc, argv, TRUE); if (Debug) CgiLibEnvironmentRecordOut (); else if (!CgiLibEnvironmentIsOsu()) if (getenv("SYS$NET")) stdout = freopen ("SYS$OUTPUT:", "w", stdout, "ctx=bin", "mrs=4096"); IsCgiPlus = CgiLibEnvironmentIsCgiPlus (); for (;;) { /* once for standard CGI, multiple times for CGIplus */ RequestedCount = -1; if (IsCgiPlus) { /* synchronize and read the CGIplus variable stream */ CgiLibVar (""); } else if (Debug) { /* won't work for OSU! */ fprintf (stdout, "Content-Type: text/plain\n\n"); system ("show sym *"); } cptr = CgiLibVar ("WWW_QUERY_STRING"); AfterCount = BeforeCount = RequestedCount = 0; if (isdigit(*cptr)) RequestedCount = atoi(cptr); else if (!strncmp (cptr, "after=", 6)) { RequestedCount = 10; AfterCount = atoi(cptr+6); } else if (!strncmp (cptr, "before=", 7)) { RequestedCount = 10; BeforeCount = atoi(cptr+7); } else if (!strncmp (cptr, "non-cgi", 6)) fprintf (stdout, "Output to make it a non-CGI-compliant response\n"); if (BeforeCount) sleep (BeforeCount); fprintf (stdout, "Status: 200\r\n\ Content-Type: text/plain\r\n\ Content-Length: %d\r\n\ Script-Control: X-stream-mode\r\n\ Pragma: no-cache\r\n\ Expires: Fri, 13 Jan 1978 14:00:00 GMT\r\n\ \r\n", RequestedCount * (sizeof(Line80Chars)-1)); fflush (stdout); if (*cptr == '*') { /* return all CGIplus variables in successive calls */ while ((cptr = CgiLibVar ("*")) != NULL) fprintf (stdout, "|%s|\n", cptr); } else if (RequestedCount < 0) { fprintf (stdout, "%s\n\ Usage: Supply a URL with a query string containing \ an integer representing the number of 80 character lines \ to be returned during the test.\n", SOFTWAREID); } else { while (RequestedCount--) fputs (Line80Chars, stdout); } AfterCount = BeforeCount = RequestedCount = 0; if (isdigit(*cptr)) RequestedCount = atoi(cptr); else if (!strncmp (cptr, "after=", 6)) { RequestedCount = 10; AfterCount = atoi(cptr+6); } else if (!strncmp (cptr, "before=", 7)) { RequestedCount = 10; BeforeCount = atoi(cptr+7); } else if (!strncmp (cptr, "non-cgi", 6)) fprintf (stdout, "Output to make it a non-CGI-compliant response\n"); if (AfterCount) sleep (AfterCount); if (!IsCgiPlus) break; CgiLibCgiPlusEOF (); } exit (1); } #endif #ifdef APACHE_MOD /*****************************************************************************/ /* MOD_CGIPLUSTEST.C - VMS Apache cgiplustest module $ copy [.OBJ_]MOD_CGIPLUSTEST.EXE APACHE$COMMON:[MODULES] Activate it in Apache's httpd.conf file: # httpd.conf LoadModule cgiplustest_module modules/mod_cgiplustest.so SetHandler cgiplustest Restart Apache using: $ apachectl restart Monkey see - monkey do. Speaks volumes of my Apache sophistication. Developed for VSI AXPVMS CSWS V2.4-38C. */ /*****************************************************************************/ #include "httpd.h" #include "http_config.h" #include "http_protocol.h" #include "ap_config.h" static void cgiplustest_lines (request_rec *req, int number) { ap_set_content_type (req, "text/plain"); while (number--) { ap_rputs (Line80Chars, req); if (req->connection->aborted) break; } } static void cgiplustest_stream (request_rec *req, char flag, int number) { int cnt, octet = 0; unsigned __int64 ranum; char *cptr, *sptr, *zptr; char buf [4096+1]; if (flag == 'b' || flag == 'o') ap_set_content_type (req, "application/binary"); else ap_set_content_type (req, "text/plain"); if (flag == 'b') { while (number > 0) { zptr = (sptr = buf) + sizeof(buf)-1; SYS$GETTIM (&ranum); while (sptr < zptr) { /* cheap (no subroutine call) MTH$RANDOM() */ ranum = ranum * 69069 + 1; cptr = (char*)&ranum; for (cnt = sizeof(ranum); cnt && sptr < zptr && number > 0; cnt--) *sptr++ = *cptr++; } ap_rwrite (buf, sptr - buf, req); if (req->connection->aborted) break; } } else if (flag == 'o') { while (number > 0) { zptr = (sptr = buf) + sizeof(buf)-1; while (sptr < zptr && number-- > 0) *sptr++ = (uchar)octet++; ap_rwrite (buf, sptr - buf, req); if (req->connection->aborted) break; } } else if (flag == 't') { while (number > 0) { zptr = (sptr = buf) + sizeof(buf)-1; while (sptr < zptr && number > 0) { for (cnt = ('z'-80+1); cnt <= 'z' && sptr < zptr && number-- > 0; cnt++) *sptr++ = (char)cnt; if (cnt == 'z'+1) *sptr++ = '\n'; } /* only complete lines */ while (sptr > buf && *(sptr-1) != '\n') { sptr--; number++; } *sptr = '\0'; ap_rputs (buf, req); if (req->connection->aborted) break; } } } static int cgiplustest_handler (request_rec *req) { int number = -1, query = 0; char stream = 0; char *cptr; /** should work but doesn't **/ // if (!req->handler || strcmp (req->handler, "cgiplustest")) { // return DECLINED; // } /** so use this alternative **/ if (!req->the_request || !strstr (req->the_request, "cgiplustest")) return DECLINED; if (req->the_request) { if (!strstr (req->the_request, "cgiplustest")) return DECLINED; if (cptr = strstr (req->the_request, "/stream/")) { /* using the equivalent syntax to WASD ResponseStream() */ cptr += 8; if (isalpha (*cptr)) stream = *cptr; else { stream = 't'; if (isdigit (*cptr)) number = atoi(cptr) * 1024; } while (*cptr && *cptr != ':') cptr++; if (*cptr) number = atoi(cptr+1) * 1024; else if (number < 0) number = INT_MAX; if (!(stream == 'b' || stream != 'o' || stream != 't')) number = -1; if (strchr (req->the_request, '?')) query = 1; } else if (cptr = strchr (req->the_request, '?')) number = atoi(cptr+1); } if (query) { ap_set_content_type (req, "text/plain"); ap_rprintf (req, "%s stream:%c number:%d\n", SOFTWAREID, stream, number); return OK; } if (number < 0) { ap_set_content_type (req, "text/plain"); ap_rprintf (req, "%s\n\ Usage: Supply a URL with a query string containing \ an integer representing the number of 80 character lines \ to be returned during the test.\n", SOFTWAREID); } else if (stream) cgiplustest_stream (req, stream, number); else cgiplustest_lines (req, number); return OK; } static void cgiplustest_register_hooks (apr_pool_t *pool) { fprintf (stdout, "\n ** cgiplustest_register_hooks **\n\n"); ap_hook_handler (cgiplustest_handler, NULL, NULL, APR_HOOK_LAST); } /* dispatch list for API hooks */ module AP_MODULE_DECLARE_DATA cgiplustest_module = { STANDARD20_MODULE_STUFF, NULL, /* create per-dir config structures */ NULL, /* merge per-dir config structures */ NULL, /* create per-server config structures */ NULL, /* merge per-server config structures */ NULL, /* table of config file commands */ cgiplustest_register_hooks /* register hooks */ }; #endif /*****************************************************************************/