Combining CGI Script and APPX ILF

Now that you are generating HTML from within APPX, wouldn't it be nice to generate the new documents directly in response to web server requests? Not a problem. With some simple CGI scripting and some special APPX ILF routines, you can easily use APPX as a realtime backend to any web server.

The CGI Script

With this in mind, take a look at the following shell script. If you have any unix experience at all, then this should not look too foreign.

#!/bin/ksh
APPX_RESULT=/tmp/$RANDOM.html
export APPXPATH=/users/appx/data
/users/appx/appx -a=WWW -d=WWW -t=OUTPUT -p=APPX_HOME_PAGE >/dev/null
echo "Content-type: text/html"
echo ""
cat $APPX_RESULT
rm $APPX_RESULT

Note: If you are running on an APPX Promotional license, or any other license type that presents a start-up message screen (Release 4.1.8 and higher), the command above that invokes APPX must also include the "session flag", entered as -session or -s. It should look like this:

/users/appx/appx -a=WWW -d=WWW -t=OUTPUT -p=APPX_HOME_PAGE -s >/dev/null

This will suppress all attempted screen displays by internally issuing an END option whenever a screen is presented. Two cautions: (1) If you're invoking a job that includes a disposition process, the END issued when the disposition runs will cancel the job, so be sure to remove any disposition processes from the job that you execute; (2) Release 4.1.8 had a bug that caused this to cancel the entire session, so upgrading to a newer release is required.

You can call this script appxhome.cgi and anytime it is requested by a browser, the server will run the script to get the document. There is a little bit of trickery going on within the APPX process to get the print file back to the server. So, let us review the script a line at a time:

  1. This tells the computer we want to execute this script using the "ksh" shell.

  2. This generates a random filename in the /tmp directory. Our APPX process will check the value of this environment variable. Then it will move the output print file to this location right before it exists. That way, our script can find the document file. For now, this is a process that the application must perform using ILF code.

  3. Set our APPXPATH.

  4. Run our APPX output process. We direct stdout to /dev/null. We DO NOT want any APPX screen IO going to the web server. This would get picked up as part of the document.

  5. Send the first required line to the server/browser. This tells the browser what format the document is in.

  6. Send a blank line. Required after the Content-type line. These could also be generated by APPX as part of the output process.

  7. Dump the resulting printfile to the screen. There is no screen, but the server is pretending it is the screen and will capture everything written to it. This is what will get sent back to the browser.

  8. We are done, so remove the temp file. We don't need it anymore.
Not too ugly. The CGI script is just acting as a wrapper around our APPX process. Now you could build a new CGI script for each document you want to publish on you Web page. But you can easily modify this script to run ANY appx process. Or better yet, always make it run the SAME generic process. In this last case, you can set up an APPX Subroutine process that accepts the request, executes the requested process family, and takes care of moving the resulting print file into the correct location. This can be done with a change to the URL and the CGI script as follows:
New URL = "/appx.cgi?DOCID=APPX+HOMEPAGE"

#!/bin/ksh
APPX_RESULT=/tmp/$RANDOM.html
export APPXPATH=/users/appx/data
/users/appx/appx -a=WWW -d=WWW -t=SUBR -p=APPX_WEB_SERVER >/dev/null
cat $APPX_RESULT
rm $APPX_RESULT

We have moved the Content-type lines into APPX for more control. That way, we are not limited to a certain document type. The APPX process can now decide if we are serving text/plain or text/html. Another thing you may seem to be missing here. How does the APPX subroutine know what document is being requested? The web server creates some special environment variables before it runs the CGI script. One of these is QUERY_STRING which contains the trailing data portion of the URL. So, our APPX subroutine only needs to check the value of this variable to find out what to do. There is an alternate method on calling a CGI script that involves feeding the CGI data as stdin to the script. This is good for large amounts of data that may otherwise overflow an environment variable. This difference is controlled by the web page being used to submit the request.

You may also notice that our URL in this example does not contain the Application / Database / Process-Type / Process Name of the APPX process we want to run. We could do this, but creating a translation table file within your APPX server application makes the document less complex and increases security. This way, someone can't edit your document source within their browser and run some process you don't want them to run.

The APPX Server Subroutine

Now that we have our CGI script in place, we need to focus on building a generic APPX subroutine to handle processing the requests. Our subroutine need to perform the following functions:

  • Import the environment information from the QUERY_STRING and APPX_RESULT variables.

  • Break the QUERY_STRING down into usable Variable name / Data pairs.

  • Lookup the DOCID in the translation table to find out what APPX process to run.

  • Possible do some security checking.

  • Run the process family requests or a standard security failure process.

  • Move the resulting print file to $APPX_RESULT so the server can find it.

Importing Environment Variables

There is a simple method used to import enviroment variables into APPX. It basically involves using the CALL statement to invoke a built-in function within the APPX engine. Here is the ILF code needed:

      SET      --- TEMP 32K                   =      QUERY_STRING
      SET      --- LI                         =      32767
      SET      --- NEW PAGE AFTER             =      N
      PASS     --- TEMP 32K                   FIELD            SHARE? Y
      PASS     --- LI                         FIELD            SHARE? Y
      CALL         ,RT_GETENV                 RESIDENT? Y  END? N  FAIL 0

The TEMP 32K field will contain one of two possible values. If the variable did not exist, then the value is unchanged. If the variable did exist, then the variable now contains the vaule of the requested environment variable. The other argument is just a limit on the number of bytes the function should try to shove into our alpha field. This is required and must be passed using a 32bit binary/numeric field.

Decoding the Query String

The CGI data is encoded using the URL encoding standard. This is needed to remove any spaces and special characters from the data stream. Since "=" and "&" are seperators between field/data parts and field/data pairs, they should not exist within the data itself. This is a simple encoding translation. Any special character is converted into its HEX equivalent. The only exception is the Space character. Some browsers encode this as HEX while others encode it as a "+" symbol. The format of HEX encoded data is "%XX" where "XX" is the HEX value. So, "APPX RULES" could be encoded as "APPX+RULES" or "APPX%20RULES".

Before we decode our data, we should break the information apart into field/data pairs and then further break the field name form the data. If we decode first, then we will not be able to tell if an "=" or an "&" is a seperator or part of the data. Here is ILF code to break down the query string into field/data pairs and store the results in a table file:

      SCRATCH  CTS ARGLIST             FAIL 0
      CREATE   CTS ARGLIST   SHARE? Y  FAIL 0
      *
      SET      CTS ARGLIST KEYWORD            =      REMOTE HOST
      SET      --- TEMP 32K                   =  CTS ARGLIST KEYWORD
      GOSUB        :GETENV
      SET      CTS ARGLIST VALUE              =  --- TEMP 32K
      WRITE    CTS ARGLIST             FAIL 0
      *
      SET      --- TEMP 32K                   =      QUERY_STRING
      GOSUB        :GETENV
      IF       --- TEMP 32K                   EQ     APPX_QUERY_STRING
      OR       --- TEMP 32K                   EQ
T     END
      *
      SET      --- PI                         =      0
      BEG LOOP WI = 000 TO 001  STEP 000
      RESTORE  CTS ARGLIST                    DEFAULT RECORD
      GOSUB        :GET KEYWORD
      GOSUB        :GET VALUE
      WRITE    CTS ARGLIST             FAIL 0
      IF       --- TEMP 32K                   NE
T     END LOOP WI
      *
      END
      *        ===========================================================
      LABEL    :GETENV
      *        -----------------------------------------------------------
      SET      --- LI                         =      32767
      SET      --- NEW PAGE AFTER             =      N
      PASS     --- TEMP 32K                   FIELD            SHARE? Y
      PASS     --- LI                         FIELD            SHARE? Y
      CALL         ,RT_GETENV                 RESIDENT? Y  END? N  FAIL 0
      RETURN
      *        ===========================================================
      LABEL    :GET KEYWORD
      *        -----------------------------------------------------------
      SET      --- OI                         =      1
      BEG LOOP XI = 000 TO 001  STEP 000
      COMPUTE  --- PI                         +      1
      SET TEMP 1     AT 001 FOR 001 FROM PI  OF  --- TEMP 32K
      IF       --- TEMP 1                     NE     =
      AND      --- TEMP 1                     NE
T     IF       --- TEMP 1                     EQ     +
TT    SET      --- TEMP 1                     EQ
TF    IF       --- TEMP 1                     EQ     %
TFT   GOSUB    :CONVERT FROM HEX
T     SET TEMP 1     AT 001 FOR 001 INTO OI  OF  CTS ARGLIST KEYWORD
T     COMPUTE  --- OI                         +      1
-     SET      --- TEMP 1                     =
-     SET TEMP 32K   AT PI  FOR 001 FROM 001 OF  --- TEMP 1
T     END LOOP XI
      RETURN
      *        ===========================================================
      LABEL    :GET VALUE
      *        -----------------------------------------------------------
      SET      --- OI                         =      1
      BEG LOOP XI = 000 TO 001  STEP 000
      COMPUTE  --- PI                         +      1
      SET TEMP 1     AT 001 FOR 001 FROM PI  OF  --- TEMP 32K
      IF       --- TEMP 1                     NE     &
      AND      --- TEMP 1                     NE
T     IF       --- TEMP 1                     EQ     +
TT    SET      --- TEMP 1                     EQ
TF    IF       --- TEMP 1                     EQ     %
TFT   GOSUB    :CONVERT FROM HEX
T     SET TEMP 1     AT 001 FOR 001 INTO OI  OF  CTS ARGLIST VALUE
T     COMPUTE  --- OI                         +      1
-     SET      --- TEMP 1                     =
-     SET TEMP 32K   AT PI  FOR 001 FROM 001 OF  --- TEMP 1
T     END LOOP XI
      RETURN
      *        ===========================================================
      LABEL    :CONVERT FROM HEX
      *        -----------------------------------------------------------
      SET      --- TEMP 1                     =
      SET TEMP 32K   AT PI  FOR 001 FROM 001 OF  --- TEMP 1
      COMPUTE  --- PI                         +      1
      SET TEMP 1     AT 001 FOR 001 FROM PI  OF  --- TEMP 32K
      CNV BIN  --- YI                         =  --- TEMP 1
      COMPUTE  --- YI                         -      48
      IF       --- YI                         GT     9
 T    COMPUTE  --- YI                         -      7
      COMPUTE  --- YI                         *      16
      SET      --- ZI                         =  --- YI
      SET      --- TEMP 1                     =
      SET TEMP 32K   AT PI  FOR 001 FROM 001 OF  --- TEMP 1
      COMPUTE  --- PI                         +      1
      SET TEMP 1     AT 001 FOR 001 FROM PI  OF  --- TEMP 32K
      CNV BIN  --- YI                         =  --- TEMP 1
      COMPUTE  --- YI                         -      48
      IF       --- YI                         GT     9
 T    COMPUTE  --- YI                         -      7
      COMPUTE  --- ZI                         +  --- YI
      CNV BIN  --- TEMP 1                     =  --- ZI
      RETURN


Now, after this routine is run, you can access any of the Data by setting the ARGLIST KEYWORD to the variable name, reading the ARGLIST memory file, and using the value of the ARGLIST VALUE field.

Looking Up the Document ID

Now that we have imported our CGI data. We can lookup the REAL process that must be executed to process this request. We can do that by simply reading a table file. Here is the code to do that:

      SET      CTS ARGLIST KEYWORD            =      DOCID
      READ     CTS ARGLIST   HOLD 0    FAIL 0    KEY IS  ARGLIST KEYWORD
F     SET      CTS WORK ERROR TEXT            =      DOCID Not on File!
F     SET      CTS REQUEST PROCESS            =      STANDARD ERROR

Run the Requested Process

Once we know what process needs to be run, it is time to run it. Here is that code:

      SET      --- NEXT PROCESS NAME          =  CTS REQUEST PROCESS
      JOB                                  SUBPROCESS   END? N  FAIL 0


Moving the Printfile into Place

Now, we need to put the resulting printfile in the place our CGI script expects to find it. This requires the following RUN statement:

      SET      --- TEMP 132                   =      mv
      APPEND   --- TEMP 132                   1  --- PRINT FILE PATHNAME
      APPEND   --- TEMP 132                   1  CTS WORK APPX RESULT
      APPEND   --- TEMP 132                   1      >/dev/null 2>&1
      SET      --- NEW PAGE AFTER             =      N
      RUN      --- TEMP 132                                END? N  FAIL 0

Edit | Attach | Watch | Print version | History: r5 | r4 < r3 < r2 < r1 | Backlinks | Raw View | Raw edit | More topic actions...
Topic revision: r1 - 2012-02-13 - JoeOrtagus
 
  • Edit
  • Attach
This site is powered by the TWiki collaboration platform Powered by PerlCopyright © 2008-2024 by the contributing authors. All material on this collaboration platform is the property of the contributing authors.
Ideas, requests, problems regarding TWiki? Send feedback