/*****************************************************************************/ /* metAgent.c *** EXPERIMENTAL/PROOF-OF-CONCEPT/EXAMPLE ONLY *** Pronounced: metter-jent (for no other reason...) Provides data via the if(meta-agent:..) conditional configuration. Meta-agents run as CGIplus scripts after initial request setup but just before request execution. The idea is to provide a flexible mechanism for additional request processing configuration not provided by the standard configuration mappings. Meta-agents should use the CGI variables provided for request data. As a meta-agent adds response latency to every request they should execute as expeditiously as possible. The meta-agent script activation path is a fixed "/cgiplus-bin/metagent" but as this is mapped before activation can be modified according to requirement. For example, two services on the one system can each have their own meta agents using the following: # WASD_CONFIG_MAP if (server-name:www1.net) map /cgiplus-bin/metagent /cgiplus-bin/metwww1 elif (server-name:www2) map /cgiplus-bin/metagent /cgiplus-bin/metwww2 endif At the very least, it should be mapped to any customised agent script: # WASD_CONFIG_MAP map /cgiplus-bin/metagent /cgiplus-bin/mymetagent And of course, other path SETings applied as required. Meta-agents may inject data into the request environment for subsequent WASD_CONFIG_MAP processing and/or CGI script processing using the following callouts: CGI: name=value DICT: key=value An agent MUST provide an "AGENT-END: 200 ..." when successfully concluding, or an "AGENT-END: 502 ..." when wishing to register a (WATCHable) non-fatal error. These parallel HTTP status. 501 (not implemented) is reserved to server use. A 500 (internal server error) will abort the request, returning a 500 error report. 418 (I'm a teapot) will unceremoniously drop the request connection. All status apart from 500 and 418 are considered non-fatal and the request continues without meaningful meta-agent configuration. For server-internal processing detail see [SRC.HTTPD] MetaConAgentBegin() and MetaConAgentEnd(). COPYRIGHT --------- Copyright (C) 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 LOG ----------- 15-JUN-2021 MGD initial */ /*****************************************************************************/ #define SOFTWAREVN "1.0.0" #define SOFTWARENM "METAGENT" #ifdef __ALPHA # define SOFTWAREID SOFTWARENM " AXP-" SOFTWAREVN #endif #ifdef __ia64 # define SOFTWAREID SOFTWARENM " IA64-" SOFTWAREVN #endif #ifdef __VAX # error VAX not implemented #endif #ifdef __x86_64 # define SOFTWAREID SOFTWARENM " X86-" SOFTWAREVN #endif #include #include #include #include #include #include #include #include #include int CgiPlusUsageCount; char SoftwareId[] = SOFTWAREID; /*****************************************************************************/ /* */ int main (int argc, char *argv[]) { int status; char *cptr, *sptr; if (argc > 1) { if (!strcasecmp (argv[1], "/version")) fprintf (stdout, "%%%s-I-VERSION, %s (%s)\n", SOFTWARENM, SOFTWAREID, CgiLibEnvironmentVersion()); exit (SS$_NORMAL); } CgiLibEnvironmentInit (0, NULL, 0); /* MUST only be executed in a CGIplus environment! */ if (!CgiLibEnvironmentIsCgiPlus ()) { CgiLibResponseHeader (500, "text/plain"); fputs ("CGIplus!\n", stdout); exit (SS$_NORMAL); } for (;;) { /* block waiting for the next request */ CgiLibVar (""); CgiPlusUsageCount++; if (cptr = CgiLibVarNull("REQUEST_METHOD")) if (!*cptr) { /* proctored into existance */ CgiLibResponseHeader (204, "application/proctor"); CgiLibCgiPlusEOF (); continue; } cptr = CgiLibCgiPlusCallout ("AGENT-BEGIN: %s (%s) usage:%d", SoftwareId, CgiLibEnvironmentVersion(), CgiPlusUsageCount); if (*cptr != '2') { /* if callout response not "200 ..." */ status = atoi(cptr); CgiLibResponseHeader (status, "text/plain"); fprintf (stdout, "%d!\n", status); CgiLibCgiPlusEOF (); continue; } /* skip over response status (e.g. "200") */ for (sptr = cptr; isdigit(*sptr); sptr++); while (*sptr && *sptr == ' ') sptr++; cptr = sptr; /* not interested in any agent-specific directive */ if (*sptr == '[') { for (sptr++; *sptr && *sptr != ']'; sptr++) if (*sptr == '\\' && *(sptr+1)) sptr++; if (*sptr) sptr++; while (*sptr == ' ') sptr++; cptr = sptr; } /* illustrate setting ambit dictionary entry to insert request data */ CgiLibCgiPlusCallout ("!DICT: meta_agent=%s (%s) usage:%d", SoftwareId, CgiLibEnvironmentVersion(), CgiPlusUsageCount); /* illustrate setting CGI dictionary entry to insert CGI variable data */ CgiLibCgiPlusCallout ("!CGI: meta_agent=%s (%s) usage:%d", SoftwareId, CgiLibEnvironmentVersion(), CgiPlusUsageCount); CgiLibCgiPlusCallout ("!AGENT-END: 200 %s (%s) usage:%d", SoftwareId, CgiLibEnvironmentVersion(), CgiPlusUsageCount); CgiLibCgiPlusEOF (); } } /*****************************************************************************/