[0001]
[0002]
[0003]
[0004]
[0005]
[0006]
[0007]
[0008]
[0009]
[0010]
[0011]
[0012]
[0013]
[0014]
[0015]
[0016]
[0017]
[0018]
[0019]
[0020]
[0021]
[0022]
[0023]
[0024]
[0025]
[0026]
[0027]
[0028]
[0029]
[0030]
[0031]
[0032]
[0033]
[0034]
[0035]
[0036]
[0037]
[0038]
[0039]
[0040]
[0041]
[0042]
[0043]
[0044]
[0045]
[0046]
[0047]
[0048]
[0049]
[0050]
[0051]
[0052]
[0053]
[0054]
[0055]
[0056]
[0057]
[0058]
[0059]
[0060]
[0061]
[0062]
[0063]
[0064]
[0065]
[0066]
[0067]
[0068]
[0069]
[0070]
[0071]
[0072]
[0073]
[0074]
[0075]
[0076]
[0077]
[0078]
[0079]
[0080]
[0081]
[0082]
[0083]
[0084]
[0085]
[0086]
[0087]
[0088]
[0089]
[0090]
[0091]
[0092]
[0093]
[0094]
[0095]
[0096]
[0097]
[0098]
[0099]
[0100]
[0101]
[0102]
[0103]
[0104]
[0105]
[0106]
[0107]
[0108]
[0109]
[0110]
[0111]
[0112]
[0113]
[0114]
[0115]
[0116]
[0117]
[0118]
[0119]
[0120]
[0121]
[0122]
[0123]
[0124]
[0125]
[0126]
[0127]
[0128]
[0129]
[0130]
[0131]
[0132]
[0133]
[0134]
[0135]
[0136]
[0137]
[0138]
[0139]
[0140]
[0141]
[0142]
[0143]
[0144]
[0145]
[0146]
[0147]
[0148]
[0149]
[0150]
[0151]
[0152]
[0153]
[0154]
[0155]
[0156]
[0157]
[0158]
[0159]
[0160]
[0161]
[0162]
[0163]
[0164]
[0165]
[0166]
[0167]
[0168]
[0169]
[0170]
[0171]
[0172]
[0173]
[0174]
[0175]
[0176]
[0177]
[0178]
[0179]
[0180]
[0181]
[0182]
[0183]
[0184]
[0185]
[0186]
[0187]
[0188]
[0189]
[0190]
[0191]
[0192]
[0193]
[0194]
[0195]
[0196]
[0197]
[0198]
[0199]
[0200]
[0201]
/*****************************************************************************/
/*
                                 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 <ctype.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <unixlib.h>
#include <unistd.h>

#include <ssdef.h>

#include <cgilib.h>

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 ();
   }
}

/*****************************************************************************/