Mod_Rexx is a powerful package that can bring full control of the Apache request process to the REXX programmer. When Apache receives a request, it divides the processing of that request into phases.
Figure 1. Apache HTTP request processing
Each phase is responsible for processing a small part of the request:
- post read request can modify the request after the request has been read.
- URI translation maps the URI request to a physical file, a virtual document produced by an external script, or a document generated by an internal module.
- header parser provides another chance to examine the request headers.
- access control handles authentication and authorization, and performs simple access control based on the browser's IP address, hostname, or some other simple attribute of your choice. (This is the first of three phases that handle authentication and authorization.)
- authentication checks the userid and password, and is called whenever the requested file is password-protected. (This is the second phase involved in authentication and authorization.)
- authorization determines if the user is actually authorized to access the requested URI. (This is the third and last phase involved in authentication and authorization.)
- MIME type check assigns a provisional MIME type to the request.
- fixup is the last chance to modify the request before the Response phase is called.
- response (Response handler) returns the requested information to the browser either dynamically or statically, by returning a file (also known as the content handler phase). This handler acts somewhat like a CGI program, but the runtime environment for this phase is very different from the traditional CGI environment.
- logging logs the request.
You can assign a REXX script to each of these phases. In most cases, you will probably assign a script to the response phase only, but a REXX script can fully process any phase. Mod_Rexx defines directives placed into the Apache configuration file and define how a REXX script is assigned to a particular request phase.
For more information about how the Apache request phases work, I highly recommend the book Writing Apache Modules with Perl and C (see Resources).
Using REXX scripts as Apache response handlers
REXX scripts used with Mod_Rexx are most commonly used as handlers for the Apache response phase. For Apache to recognize a document as a REXX program, the following directive must be placed in Apache's configuration file (usually http.conf):
AddType application/x-httpd-rexx-script .rex .rexx
This directive assigns the file extensions .rex and .rexx to Mod_Rexx for processing. Mod_Rexx calls the REXX language processor and passes the document (or script, if you prefer) to it for processing. Mod_Rexx creates a special environment for the script to run under, which contains some predefined REXX variables and external functions.
Now that we have a file extension assigned to REXX scripts, we can call them using a standard URI:
http://your.domain.com/myscript.rex
This URI calls the REXX script named myscript.rex located in the main Apache document subdirectory and executes it as the Apache response handler. Let's examine a small sample REXX script used as a response handler.
Listing 1. Sample REXX response-handler script
/* these are some typical Apache return codes */
DECLINED = -1 /* Module declines to handle */
OK = 0 /* Module has handled this stage. */
/* get the Apache request record ptr */
r = arg(1)
/* set content-type and send the HTTP header */
call WWWSendHTTPHeader r, "text/html"
call WWWGetArgs r
/* start sending the html page */
say "<html>"
say "<head>"
say "<title>Sample HTML Page From Rexx</title>"
say "</head>"
say "<body>"
say "<h1>Sample HTML Page From Rexx</h1>"
say '<p>The Mod_Rexx version string is "'WWWGetVersion()'"'
say "<p>The following is the list of standard Rexx CGI variables and their values:"
say '<table border="1"><tr><th>Name</th><th>Value</th></tr>'
say "<tr><td>WWWAUTH_TYPE</td><td>"vorb(wwwauth_type)"</td></tr>"
say "<tr><td>WWWCONTENT_LENGTH</td><td>"vorb(wwwcontent_length)"</td></tr>"
say "<tr><td>WWWCONTENT_TYPE</td><td>"vorb(wwwcontent_type)"</td></tr>"
say "<tr><td>WWWGATEWAY_INTERFACE</td><td>"vorb(wwwgateway_interface)"</td></tr>"
say "<tr><td>WWWHTTP_USER_ACCEPT</td><td>"vorb(wwwhttp_user_accept)"</td></tr>"
say "<tr><td>WWWHTTP_USER_AGENT</td><td>"vorb(wwwhttp_user_agent)"</td></tr>"
say "<tr><td>WWWPATH_INFO</td><td>"vorb(wwwpath_info)"</td></tr>"
say "<tr><td>WWWPATH_TRANSLATED</td><td>"vorb(wwwpath_translated)"</td></tr>"
say "<tr><td>WWWQUERY_STRING</td><td>"vorb(wwwquery_string)"</td></tr>"
say "<tr><td>WWWREMOTE_ADDR</td><td>"vorb(wwwremote_addr)"</td></tr>"
say "<tr><td>WWWREMOTE_HOST</td><td>"vorb(wwwremote_host)"</td></tr>"
say "<tr><td>WWWREMOTE_IDENT</td><td>"vorb(wwwremote_ident)"</td></tr>"
say "<tr><td>WWWREMOTE_USER</td><td>"vorb(wwwremote_user)"</td></tr>"
say "<tr><td>WWWREQUEST_METHOD</td><td>"vorb(wwwrequest_method)"</td></tr>"
say "<tr><td>WWWSCRIPT_NAME</td><td>"vorb(wwwscript_name)"</td></tr>"
say "<tr><td>WWWSERVER_NAME</td><td>"vorb(wwwserver_name)"</td></tr>"
say "<tr><td>WWWSERVER_PORT</td><td>"vorb(wwwserver_port)"</td></tr>"
say "<tr><td>WWWSERVER_PROTOCOL</td><td>"vorb(wwwserver_protocol)"</td></tr>"
say "<tr><td>WWWSERVER_SOFTWARE</td><td>"vorb(wwwserver_software)"</td></tr>"
say "</table>"
say "<p>The following are some additional variables provided to the Rexx program:"
say '<table border="1"><tr><th>Name</th><th>Value</th></tr>'
say "<tr><td>WWWDEFAULT_TYPE</td><td>"vorb(wwwdefault_type)"</td></tr>"
say "<tr><td>WWWFILENAME</td><td>"vorb(wwwfilename)"</td></tr>"
say "<tr><td>WWWFNAMETEMPLATE</td><td>"vorb(wwwfnametemplate)"</td></tr>"
say "<tr><td>WWWIS_MAIN_REQUEST</td><td>"vorb(wwwis_main_request)"</td></tr>"
say "<tr><td>WWWRSPCOMPILER</td><td>"vorb(wwwrspcompiler)"</td></tr>"
say "<tr><td>WWWSERVER_ROOT</td><td>"vorb(wwwserver_root)"</td></tr>"
say "<tr><td>WWWUNPARSEDURI</td><td>"vorb(wwwunparseduri)"</td></tr>"
say "<tr><td>WWWURI</td><td>"vorb(wwwuri)"</td></tr>"
say "</table>"
say "</body>"
say "</html>"
return OK
/* vorb: return the value or a required space */
vorb:
if length(arg(1)) > 0 then return arg(1)
else return ' '
|
The first few lines of Listing 1 set up some standard return codes Apache uses to determine the success, failure, or special instructions upon return from the script. A return code of zero (OK) specifies that the handler has completely processed the phase, and no additional processing is needed by Apache. A return code of -1 (DECLINED) indicates to Apache that this handler has declined to process the request, and other modules should be offered a chance to process it. In this case, the script should not return any HTML document.
The next REXX statement obtains the main argument passed to the script and assigns it to a local variable. Mod_Rexx always passes one argument to every REXX script it processes, and that argument contains a number (the request record pointer) that needs to be passed to most of the external functions available to the script. You can see this in the following statement:
call WWWSendHTTPHeader r, "text/html"
This statement assigns a content-type (or MIME-type) to the response header sent back to the browser. Every script used as a response handler must call this REXX external function so the browser knows how to handle the returned document. The next statement fetches the query string arguments from Apache. The statement is required, but explaining it is beyond the scope of this article.
The next set of statements begin returning the actual document text to the browser. As you can see, the REXX say statement sends the actual HTML text to the browser.
The next statement uses one of the predefined variables provided by the Mod_Rexx execution environment to the REXX script to send the Mod_Rexx version string back to the browser. After that comes two sections that also send the contents of predefined variables back to the browser. The first section returns variables that are usually available to standard CGI programs. The contents of these variables are exactly what you would expect to see if the REXX script were an actual CGI program and not an Apache response handler. The second set of variables are some other useful variables also defined by Mod_Rexx.
The final REXX statements provide the standard HTML closing tags and a standard REXX internal function/subroutine that tests for REXX variables of zero-length. This function makes the tables in the returned HTML page more attractive.
As you can see, REXX response-handler scripts are easy to build and maintain. They provide a powerful environment in which to build dynamic HTML content. There are many more external REXX functions and predefined variables provided by the Mod_Rexx environment that provide direct access to the Apache environment and Application Programming Interfaces (APIs). There is even a set of IBM Object REXX classes (see Resources) to make access to the Apache APIs even easier.
Note that REXX program files (on UNIX® variants) do not need to be marked executable in order for Mod_Rexx to execute them. If you do not mark them executable, they cannot be executed outside of the Mod_Rexx environment by accident or maliciously through the standard Apache CGI.
You can also use a Mod_Rexx response-handler script to add a canned footer to a set of HTML pages in a document subdirectory. Place the following in your Apache configuration file (httpd.conf):
Listing 2. Apache nonresponse configuration directives
<Location /mytest>
SetHandler rexx_handler
RexxHandler '/apache/rexx/footer.rex'
</Location>
|
The RexxHandler directive tells Apache to invoke the specified REXX script to process each HTML file contained within the /mytest document path. When a document is retrieved from the specified document path, then the REXX script is invoked to actually process the HTML document:
http://www.mydomain.com/mytest/testdoc.html
Following is an example REXX script (footer.rex) that reads the testdoc.html document and adds the footer:
Listing 3. REXX response-handler script to add a canned footer
/* these are some typical Apache return codes */
OK = 0 /* Module has handled this stage. */
NOT_FOUND = 404 /* Main document not found. */
/* get the Apache request record ptr */
r = arg(1)
body = '</BODY>'
/* try to open the main document HTML file */
retc = stream(wwwfilename, 'c', 'open read')
if retc <> 'READY:' then do
return NOT_FOUND
end
/* set content-type and send the HTTP header */
call WWWSendHTTPHeader r, "text/html"
/* read in the document and look for the </BODY> tag */
call on notready name seteof
eof = 0
line = linein(wwwfilename)
x = pos(body, translate(line))
do while x = 0 & eof = 0
say line
line = linein(wwwfilename)
x = pos(body, translate(line))
end
if eof = 1 then return OK
/* we found a </BODY> tag so send out the footer */
say substr(line, 1, x - 1)
call send_footer
say substr(line, x)
/* read in the rest of the document */
line = linein(wwwfilename)
do while eof = 0
say line
line = linein(wwwfilename)
end
/* we are done */
return OK
/* function which indicates end-of-file */
seteof:
eof = 1
return
/* send the footer */
send_footer:
say '<br />'
say '<hr />'
say '<br />'
say '© 2001 <a href="http://www.ibm.com/">IBM Corporation</a>'
say '<br />'
say '<em>Last Modified:' date()'</em>'
say '<br />'
return
|
The example in Listing 3 adds a footer to the /mytest/testdoc.html document that references www.ibm.com. This script runs against every document in the /mytest subdirectory tree, thus adding the standard footer to all the documents in the tree.
Using REXX server page support in Mod_Rexx
REXX Server Pages (RSPs) are similar to Java™ Server Pages (JSPs) and PHP pages. RSPs allow you to embed REXX code into an HTML page, so HTML pages can be created dynamically at run time. Here is a small example RSP:
Listing 4. Sample RSP
<html>
<body>
<center><h1>RSP Test Page</h1></center>
<p>This is some straight HTML text in the RSP file.
<p>The current date and time is
<?rexx
/* the following is a REXX statement */
say date() time()
?>
</body>
</html>
|
You can create RSP-enabled Web pages just as you would create standard HTML pages using the editor of your choice. REXX statements are delimited from HTML lines in an RSP using special tags. The three types of tag delimiters are short delimiters, long delimiters, and deprecated long delimiters.
The easy and shortest form of the REXX statement delimiters is the <?rexx and ?> form. Here is an example:
Listing 5. Sample RSP page using short delimiters
<p>The current date and time is
<?rexx
/* the following is a REXX statement */
say date() time()
?>
|
Note that the <?rexx and ?> parts of the tag must be placed on lines by themselves in the RSP file.
The long-delimiter form uses the standard HTML <script> tag to delimit REXX statements. Here is an example:
Listing 6. Sample RSP using long delimiters
<p>The current date and time is
<script type="rexx">
/* the following is a REXX statement */
say date() time()
</script>
|
Note that the <script> and </script>
tags must be placed on lines by themselves in the RSP file.
The long delimiter form can also use the deprecated form of the HTML <script> tag to delimit REXX statements. Note that this form is deprecated in the HTML V4.0 specifications. Here is an example:
Listing 7. Sample RSP using deprecated long delimiters
<p>The current date and time is
<script language="rexx">
/* the following is a REXX statement */
say date() time()
</script>
|
Mod_Rexx RSP processing is performed when a request is made to Apache for an RSP-enabled file. The request is processed in four stages by Mod_Rexx and a REXX program/script (the RSP compiler):
- Mod_Rexx creates a temporary file for the compiled version of the RSP file.
- RSPCOMP.REX (the RSP compiler) is called to compile the RSP file into a real REXX program and place it in the temporary file.
- Mod_Rexx calls the newly created REXX program.
- Mod_Rexx removes the temporary file.
The compile process is very fast, and the execution of the REXX program created by the process is limited to the actions it invokes. Typically, the created program also executes quickly unless it accesses databases or other external environments.
The RSP compiler is itself a REXX script, so the Apache administrator can modify it to suit Web developers' needs. The RSP compiler can also perform other functions, such as pre-compiling RSP documents into standard REXX programs, which can then be executed as Apache response handlers.
You can enable RSP documents within the Apache document tree by placing the following directives in the Apache configuration file (http.conf):
Listing 8. Apache RSP configuration directives
AddType application/x-httpd-rexx-rsp .rsp
RexxTempFileNameTemplate "c:/temp/execrsp????.rex"
RexxRspCompiler "c:/Program Files/IBM HTTP Server/rspcomp.rex"
|
The AddType directive specifies the extension(s) an RSP file will have within
the Apache document tree. The RexxTempFileNameTemplate directive specifies
the path and file name template to use when Mod_Rexx creates the temporary files to contain the compiled version of the RSP file. And the RexxRspCompiler specifies the path to the REXX RSP compiler script (supplied with Mod_Rexx).
We have touched on only a few of the available functions in Mod_Rexx. But we hope you have learned enough to see the potential Mod_Rexx has to improve the way you create dynamic Web content.
Learn
-
For more information about creating Web-server modules using the Apache API, read
Writing Apache Modules with Perl and C, by Lincoln Stein and Doug
MacEachern. For a preview, read the online chapters.
-
Visit the REXX Language Association for more
information.
-
Learn about IBM Object REXX, an object-oriented programming language suited for beginners as well as experienced OO programmers. It is upward-compatible with previous versions of classic REXX and provides many programming interfaces to existing applications, such as DB2®, C, and C++ applications.
-
The IBM REXX product family runs on host systems, such as VM/ESA, VSE/ESA, and MVS/ESA, and workstation environments, such as AIX®, OS/2®, Linux®, and Windows®.
-
Regina REXX contains further information about this open source project.
-
To listen to interesting interviews and discussions for software developers, check out developerWorks podcasts.
-
Stay current with developerWorks' Technical events and webcasts.
-
Check out upcoming conferences, trade shows, webcasts, and other Events around the world that are of interest to IBM open source developers.
-
Visit the developerWorks Open source zone for extensive how-to information, tools, and project updates to help you develop with open source technologies and use them with IBM's products.
-
Watch and learn about IBM and open source technologies and product functions with the no-cost developerWorks On demand demos.
Get products and technologies
-
Download Mod_Rexx.
-
Innovate your next open source development project with IBM trial software, available for download or on DVD.
-
Download IBM product evaluation versions, and get your hands on application development tools and middleware products from DB2®, Lotus®, Rational®, Tivoli®, and WebSphere®.
Discuss
-
Participate in the developerWorks PHP Forum: Developing PHP applications with IBM Information Management products (DB2, IDS).
Comments (Undergoing maintenance)





