|
Parsing CGI output using Server
Side Includes (SSI)
August 2, 2002
Leo Galleguillos wrote:
Q. Do you know how to enable server-side includes to
be parsed within the HTML that a cgi-script outputs? Thank you.
Eric Georgieff answered:
A. You pose a question that I have asked myself many
years ago. After searching many years for a solution I have determined the following.
As you may have noticed, it would be quite convenient if it were possible to
get the output of CGI scripts (such as those written using the Perl programming
language) to be parsed by the server side include engine (SSI) before it is
sent to the client. In this way, it would be possible to simply output SSI commands
from your CGI script and then allow the server software to do the work of actually
fetching the data from a physical file present on the web server. This would
allow you to write less actual HTML within the code of your CGI scripts and
to follow the same format you are currently using throughout your web site,
should you already be using the power of server side includes.
It is unfortunately impossible to obtain this desired effect with most current
web server software. Both Apache 1.3, which is currently used by about 56 percent
of all internet sites (see the NetCraft
Web Server Survey), and Microsoft Internet Information Server 5.0 (IIS)
do not allow CGI script output to be parsed before it is sent to the client.
The IIS server uses ISAPI modules (often contained within dll files) that are
called whenever a file with a certain registered extension is called. These
ISAPI modules then perform the required operation using the data provided by
the web server and return their parsed data to the web server which then forwards
it to the client. So, if you had a file with the extension *.cgi or *.pl, for
instance, the Perl ISAPI module would be invoked. The same applies for practically
any type of extension, *.asp (Microsoft Active Server Pages), *.jsp (Java Server
Pages), *.shtml (Server Side Includes), being merely a few popular examples.
My theory is that it is only possible for one ISAPI module to handle data before
a result is sent to the web client. Since it would hence be impossible to daisy
chain ISAPI modules, it would be impossible for the Server Side Includes (SSI)
module to parse the output of the Perl module.
As for the Apache web server, I have not had much more success. Here too, it
would appear that it is impossible to parse the server side includes present
in the output of your CGI scripts. The Apache
1.3 FAQ states the following:
How can I have my script
output parsed?
So you want to include
SSI directives in the output from your CGI script, but can't figure out how
to do it? The short answer is "you can't." This is potentially a
security liability and, more importantly, it can not be cleanly implemented
under the current server API. The best workaround is for your script itself
to do what the SSIs would be doing. After all, it's generating the rest of
the content.
This is a feature The
Apache Group hopes to add in the next major release after 1.3.
So it would appear that they planed to add this feature in Apache 2.0 which
is currently available for download, but it is not clear if they actually managed
to implement it or not, nor have I played around with Apache 2.0 to find out.
You may download the Apache 2.0 web server to see if it works.
Here at Siliconguide.com, we use the Apache 1.3 web server, running on a Microsoft
Windows 2000 server and have decided to get our scripts to do what the SSIs
would be doing, as suggested by the Apache 1.3 documentation. The following
Perl code snippets perform approximately the same thing as would a corresponding
SSI routine. If you are not using Perl to write your script, you should still
be able to understand the general idea and write code in the particular language
you are using (e.g. C++).
To include the contents of a file into your script output, simply read the
data from the actual physical file on disk into a variable (in this case we
will use an array) and then print out the contents of the variable as follows.
This is the equivalent of using the "<!--#include virtual="LOCATION_OF_FILE"-->"
SSI command.
open (include, "<$include_file")
or &error("Unable to open the file to include");
@include=<include>;
close(include);
print @include;
To include the output of another CGI program, that is being called from the
SSI code of one of the files you are manually including (using the above method),
you can scan through the file you wish to include and replace any "<!--#include
virtual="LOCATION_OF_CGI_SCRIPT"-->" or "<!--#exec
cmd="LOCATION_OF_CGI_SCRIPT" -->" SSI commands with the actual
output of the desired CGI program as follows. This requires manually executing
the CGI script in the system's shell. In the following example, we are scanning
for the strings "<!--#exec cgi=\"../../cgi-bin/ads/ads.cgi\"
-->\n" and "<!--#include virtual=\"../../cgi-bin/ads/ads.cgi?buttons\"
-->\n" and replacing them with the output of the CGI programs they refer
to (e:/wwwroot/siliconguide/cgi-bin/ads/ads.cgi and e:/wwwroot/siliconguide/cgi-bin/ads/buttons.cgi
respectively). Please note that this example is intended to work in a Windows
environment and will require modifications to work properly under Unix.
foreach $i (@header) {
if ($i eq "<!--#exec cgi=\"../../cgi-bin/ads/ads.cgi\"
-->\n") {
system("perl e:/wwwroot/siliconguide/cgi-bin/ads/ads.cgi");
}
if ($i eq "<!--#include virtual=\"../../cgi-bin/ads/ads.cgi?buttons\"
-->\n") {
system("perl e:/wwwroot/siliconguide/cgi-bin/ads/buttons.cgi");
}
else {
print ($i);
}
}
In a similar way, it is possible to duplicate the effect of all types of server
side include routines.
|