which is not always wanted or expected. Set XMLSubsStrict to 1 if this is
the case.
PerlSetVar XMLSubsStrict 1
XMLSubsPerlArgs
default 1, when set attribute values will be interpreted as raw perl code so
that these all would execute as one would expect:
With the 2.45 release, 0 may be set for this configuration or a more ASP
style variable interpolation:
This configuration is being introduced experimentally in version 2.45, as it
will become the eventual default in the 3.0 release.
PerlSetVar XMLSubsPerlArgs Off
XSLT
default not defined, if set to a file, ASP scripts will be regarded as XML
output and transformed with the given XSL file with XML::XSLT. This XSL file
will also be executed as an ASP script first, and its output will be the XSL
data used for the transformation. This XSL file will be executed as a
dynamic include, so may be located in the current directory, Global, or
IncludesDir.
Please see the XML/XSLT section for an explanation of its use.
PerlSetVar XSLT template.xsl
XSLTMatch
default .*, if XSLT is set by default all ASP scripts will be XSL
transformed by the specified XSL template. This regexp setting will tell
XSLT which file names to match with doing XSL transformations, so that
regular HTML ASP scripts and XML ASP scripts can be configured with the same
configuration block. Please see ./site/eg/.htaccess for an example of its
use.
PerlSetVar XSLTMatch \.xml$
XSLTParser
default XML::XSLT, determines which perl module to use for XSLT parsing.
This is a new config as of 2.11. Also supported is XML::Sablotron which does
not handle XSLT with the exact same output, but is about 10 times faster
than XML::XSLT. XML::LibXSLT may also be used as of version 2.29, and seems
to be about twice again as fast as XML::Sablotron, and a very complete XSLT
implementation.
PerlSetVar XSLTParser XML::XSLT
PerlSetVar XSLTParser XML::Sablotron
PerlSetVar XSLTParser XML::LibXSLT
XSLTCache
Activate XSLT file based caching through CacheDB, CacheDir, and CacheSize
settings. This gives cached XSLT performance near AxKit and greater than
Cocoon. XSLT caches transformations keyed uniquely by XML & XSLT inputs.
PerlSetVar XSLTCache 1
XSLTCacheSize
as of version 2.11, this config is no longer supported.
Caching
The output caching layer is a file dbm based output cache that runs on top
of the MLDBM::Sync so inherits its performance characteristics. With CacheDB
set to MLDBM::Sync::SDBM_File, the cache layer is very fast at caching
entries up to 20K in size, but for greater cached items, you should set
CacheDB to another dbm like DB_File or GDBM_File.
In order for the cache layer to function properly, whether for
$Response->Include() output caching, see OBJECTS, or XSLT caching, see
XML/XSLT, then Apache::ASP must be loaded in the parent httpd like so:
# httpd.conf
PerlModule Apache::ASP
-- or --
use Apache::ASP;
The cache layer automatically expires entries upon server restart, but for
this to work, a $ServerID must be computed when the Apache::ASP module gets
loaded to store in each cached item. Without the above done, each child
httpd process will get its own $ServerID, so caching will not work at all.
This said, output caching will not work in raw CGI mode, just running under
mod_perl.
CacheDB
Like StateDB, sets dbm format for caching. Since SDBM_File only support
key/values pairs of around 1K max in length, the default for this is
MLDBM::Sync::SDBM_File, which is very fast for < 20K output sizes. For
caching larger data than 20K, DB_File or GDBM_File are probably better to
use.
PerlSetVar CacheDB MLDBM::Sync::SDBM_File
For your own benchmarks to test the relative speeds of the various DBMs
under MLDBM::Sync, which is used by CacheDB, you may run the
./bench/bench_sync.pl script from the MLDBM::Sync distribution on your
system.
CacheDir
By default, the cache directory is at StateDir/cache, but CacheDir can be
used to set the StateDir value for caching purposes. One may want the
CacheDir separate from StateDir for example StateDir might be a centrally
network mounted file system, while CacheDir might be a local file cache.
PerlSetVar CacheDir /tmp/asp_demo
On a system like Solaris where there is a RAM disk mounted on the system
like /tmp, I could put the CacheDir there. On a system like Linux where
files are cached pretty well by default, this is less important.
CacheSize
By default, this is 10M of data per cache. When any cache, like the
XSLTCache, reaches this limit, the cache will be purged by deleting the
cached dbm files entirely. This is better for long term running of dbms than
deleting individual records, because dbm formats will often degrade in
performance with lots of insert & deletes.
Units of M, K, and B are supported for megabytes, kilobytes, and bytes, with
the default unit being B, so the following configs all mean the same thing;
PerlSetVar CacheSize 10M
PerlSetVar CacheSize 10240K
PerlSetVar CacheSize 10485760B
PerlSetVar CacheSize 10485760
There are 2 caches currently, the XSLTCache, and the Response cache, the
latter which is currently invoked for caching output from includes with
special syntax. See $Response->Include() for more info on the Response
cache.
Miscellaneous
AuthServerVariables
default 0. If you are using basic auth and would like
$Request->ServerVariables set like AUTH_TYPE, AUTH_USER, AUTH_NAME,
REMOTE_USER, & AUTH_PASSWD, then set this and Apache::ASP will initialize
these values from Apache->*auth* commands. Use of these environment
variables keeps applications cross platform compatible as other servers set
these too when performing basic 401 auth.
PerlSetVar AuthServerVariables 0
BufferingOn
default 1, if true, buffers output through the response object. $Response
object will only send results to client browser if a $Response->Flush() is
called, or if the asp script ends. Lots of output will need to be flushed
incrementally.
If false, 0, the output is immediately written to the client, CGI style.
There will be a performance hit server side if output is flushed
automatically to the client, but is probably small.
I would leave this on, since error handling is poor, if your asp script
errors after sending only some of the output.
PerlSetVar BufferingOn 1
InodeNames
Default 0. Set to 1 to uses a stat() call on scripts and includes to derive
subroutine namespace based on device and inode numbers. In case of multiple
symbolic links pointing to the same script this will result in the script
being compiled only once. Use only on unix flavours which support the stat()
call that know about device and inode numbers.
PerlSetVar InodeNames 1
RequestParams
Default 0, if set creates $Request->Params object with combined contents of
$Request->QueryString and $Request->Form. This is for developer convenience
simlar to CGI.pm's param() method.
PerlSetVar RequestParams 1
RequestBinaryRead
Default On, if set to Off will not read POST data into $Request->Form().
One potential reason for configuring this to Off might be to initialize the
Apache::ASP object in an Apache handler phase earlier than the normal
PerlRequestHandler phase, so that it does not interfere with normal reading
of POST data later in the request.
PerlSetVar RequestBinaryRead On
StatINC
default 0, if true, reloads perl libraries that have changed on disk
automatically for ASP scripts. If false, the www server must be restarted
for library changes to take effect.
A known bug is that any functions that are exported, e.g. confess Carp
qw(confess), will not be refreshed by StatINC. To refresh these, you must
restart the www server.
This setting should be used in development only because it is so slow. For a
production version of StatINC, see StatINCMatch.
PerlSetVar StatINC 1
StatINCMatch
default undef, if defined, it will be used as a regular expression to reload
modules that match as in StatINC. This is useful because StatINC has a very
high performance penalty in production, so if you can narrow the modules
that are checked for reloading each script execution to a handful, you will
only suffer a mild performance penalty.
The StatINCMatch setting should be a regular expression like: Struct|LWP
which would match on reloading Class/Struct.pm, and all the LWP/.*
libraries.
If you define StatINCMatch, you do not need to define StatINC.
PerlSetVar StatINCMatch .*
StatScripts
default 1, if set to 0, changed scripts, global.asa, and includes will not
be reloaded. Coupled with Apache mod_perl startup and restart handlers
executing Apache::ASP->Loader() for your application this allows your
application to be frozen, and only reloaded on the next server restart or
stop/start.
There are a few advantages for not reloading scripts and modules in
production. First there is a slight performance improvement by not having to
stat() the script, its includes and the global.asa every request.
From an application deployment standpoint, you also gain the ability to
deploy your application as a snapshot taken when the server starts and
restarts. This provides you with the reassurance that during a production
server update from development sources, you do not have to worry with
sources being used for the wrong libraries and such, while they are all
being copied over.
Finally, though you really should not do this, you can work on a live
production application, with a test server reloading changes, but your
production server does see the changes until you restart or stop/start it.
This saves your public from syntax errors while you are just doing a quick
bug fix.
PerlSetVar StatScripts 1
SoftRedirect
default 0, if true, a $Response->Redirect() does not end the script.
Normally, when a Redirect() is called, the script is ended automatically.
SoftRedirect 1, is a standard way of doing redirects, allowing for html
output after the redirect is specified.
PerlSetVar SoftRedirect 0
Filter
On/Off, default Off. With filtering enabled, you can take advantage of full
server side includes (SSI), implemented through Apache::SSI. SSI is
implemented through this mechanism by using Apache::Filter. A sample
configuration for full SSI with filtering is in the ./site/eg/.htaccess
file, with a relevant example script ./site/eg/ssi_filter.ssi.
You may only use this option with modperl v1.16 or greater installed and
PERL_STACKED_HANDLERS enabled. Filtering may be used in conjunction with
other handlers that are also "filter aware". If in doubt, try building your
mod_perl with
perl Makefile.PL EVERYTHING=1
With filtering through Apache::SSI, you should expect near a a 20%
performance decrease.
PerlSetVar Filter Off
CgiHeaders
default 0. When true, script output that looks like HTTP / CGI headers, will
be added to the HTTP headers of the request. So you could add: Set-Cookie:
test=message
...
to the top of your script, and all the headers preceding a newline
will be added as if with a call to $Response->AddHeader(). This
functionality is here for compatibility with raw cgi scripts,
and those used to this kind of coding.
When set to 0, CgiHeaders style headers will not be parsed from the script
response.
PerlSetVar CgiHeaders 0
Clean
default 0, may be set between 1 and 9. This setting determine how much
text/html output should be compressed. A setting of 1 strips mostly white
space saving usually 10% in output size, at a performance cost of less than
5%. A setting of 9 goes much further saving anywhere 25% to 50% typically,
but with a performance hit of 50%.
This config option is implemented via HTML::Clean. Per script configuration
of this setting is available via the $Response->{Clean} property, which may
also be set between 0 and 9.
PerlSetVar Clean 0
CompressGzip
default 0, if true will gzip compress HTML output on the fly if
Compress::Zlib is installed, and the client browser supports it. Depending
on the HTML being compressed, the client may see a 50% to 90% reduction in
HTML output. I have seen 40K of HTML squeezed down to just under 6K. This
will come at a 5%-20% hit to CPU usage per request compressed.
Note there are some cases when a browser says it will accept gzip encoding,
but then not render it correctly. This behavior has been seen with IE5 when
set to use a proxy but not using a proxy, and the URL does not end with a
.html or .htm. No work around has yet been found for this case so use at
your own risk.
PerlSetVar CompressGzip 1
FormFill
default 0, if true will auto fill HTML forms with values from
$Request->Form(). This functionality is provided by use of HTML::FillInForm.
For more information please see "perldoc HTML::FillInForm", and the example
./site/eg/formfill.asp.
This feature can be enabled on a per form basis at runtime with
$Response->{FormFill} = 1
PerlSetVar FormFill 1
TimeHiRes
default 0, if set and Time::HiRes is installed, will do sub second timing of
the time it takes Apache::ASP to process a request. This will not include
the time spent in the session manager, nor modperl or Apache, and is only a
rough approximation at best.
If Debug is set also, you will get a comment in your HTML output that
indicates the time it took to process that script.
If system debugging is set with Debug -1 or -2, you will also get this time
in the Apache error log with the other system messages.
Mail Administration
Apache::ASP has some powerful administrative email extensions that let you
sleep at night, knowing full well that if an error occurs at the web site,
you will know about it immediately. With these features already enabled, it
was also easy to provide the $Server->Mail(\%mail) API extension which you
can read up about in the OBJECTS section.
MailHost
The mail host is the smtp server that the below Mail* config directives will
use when sending their emails. By default Net::SMTP uses smtp mail hosts
configured in Net::Config, which is set up at install time, but this setting
can be used to override this config.
The mail hosts specified in the Net::Config file will be used as backup smtp
servers to the MailHost specified here, should this primary server not be
working.
PerlSetVar MailHost smtp.yourdomain.com.foobar
MailFrom
Default NONE, set this to specify the default mail address placed in the
From: mail header for the $Server->Mail() API extension, as well as
MailErrorsTo and MailAlertTo.
PerlSetVar MailFrom youremail@yourdomain.com.foobar
MailErrorsTo
No default, if set, ASP server errors, error code 500, that result while
compiling or running scripts under Apache::ASP will automatically be emailed
to the email address set for this config. This allows an administrator to
have a rapid response to user generated server errors resulting from bugs in
production ASP scripts. Other errors, such as 404 not found will be handled
by Apache directly.
An easy way to see this config in action is to have an ASP script which
calls a die(), which generates an internal ASP 500 server error.
The Debug config of value 2 and this setting are mutually exclusive, as
Debug 2 is a development setting where errors are displayed in the browser,
and MailErrorsTo is a production setting so that errors are silently logged
and sent via email to the web admin.
PerlSetVar MailErrorsTo youremail@yourdomain.com
MailAlertTo
The address configured will have an email sent on any ASP server error 500,
and the message will be short enough to fit on a text based pager. This
config setting would be used to give an administrator a heads up that a www
server error occurred, as opposed to MailErrorsTo would be used for
debugging that server error.
This config does not work when Debug 2 is set, as it is a setting for use in
production only, where Debug 2 is for development use.
PerlSetVar MailAlertTo youremail@yourdomain.com
MailAlertPeriod
Default 20 minutes, this config specifies the time in minutes over which
there may be only one alert email generated by MailAlertTo. The purpose of
MailAlertTo is to give the admin a heads up that there is an error at the
www server. MailErrorsTo is for to aid in speedy debugging of the incident.
PerlSetVar MailAlertPeriod 20
File Uploads
FileUploadMax
default 0, if set will limit file uploads to this size in bytes. This is
currently implemented by setting $CGI::POST_MAX before handling the file
upload. Prior to this, a developer would have to hardcode a value for
$CGI::POST_MAX to get this to work.
PerlSetVar 100000
FileUploadTemp
default 0, if set will leave a temp file on disk during the request, which
may be helpful for processing by other programs, but is also a security risk
in that other users on the operating system could potentially read this file
while the script is running.
The path to the temp file will be available at
$Request->{FileUpload}{$form_field}{TempFile}. The regular use of file
uploads remains the same with the <$filehandle> to the upload at
$Request->{Form}{$form_field}. Please see the CGI section for more
information on file uploads, and the $Request section in OBJECTS.
PerlSetVar FileUploadTemp 0
SYNTAX
General
ASP embedding syntax allows one to embed code in html in 2 simple ways. The
first is the <% xxx %> tag in which xxx is any valid perl code. The second
is <%= xxx %> where xxx is some scalar value that will be inserted into the
html directly. An easy print.
A simple asp page would look like:
For loop incrementing font size:
<% for(1..5) { %>
Size = <%=$_%>
<% } %>
Notice that your perl code blocks can span any html. The for loop above
iterates over the html without any special syntax.
XMLSubs
XMLSubs allows a developer to define custom handlers for HTML & XML tags,
which can extend the natural syntax of the ASP environment. Configured like:
PerlSetVar XMLSubsMatch site:\w+
A simple tag like:
can be constructed that could translate into:
sub site::header {
my $args = shift;
print "
$args->{title}\n";
print "\n";
}
Better yet, one can use this functionality to trap and post process embedded
HTML & XML like:
... some HTML here ...
and then:
sub site::page {
my($args, $html) = @_;
&site::header($args);
$main::Response->Write($html);
$main::Response->Write("");
}
Though this could be used to fully render XML documents, it was not built
for this purpose, but to add powerful tag extensions to HTML development
environments. For full XML rendering, you ought to try an XSLT approach,
also supported by Apache::ASP.
Editors
As Apache::ASP supports a mixing of perl and HTML, any editor which supports
development of one or the other would work well. The following editors are
known to work well for developing Apache::ASP web sites:
* Emacs, in perl or HTML modes. For a mmm-mode config
that mixes HTML & perl modes in a single buffer, check
out the editors/mmm-asp-perl.el file in distribution.
* Microsoft Frontpage
* Vim, special syntax support with editors/aasp.vim file in distribution.
* UltraEdit32 ( http://www.ultraedit.com/ ) has syntax highlighting,
good macros and a configurable wordlist (so one can have syntax
highlighting both for Perl and HTML).
Please feel free to suggest your favorite development environment for this
list.
EVENTS
Overview
The ASP platform allows developers to create Web Applications. In
fulfillment of real software requirements, ASP allows event-triggered
actions to be taken, which are defined in a global.asa file. The global.asa
file resides in the Global directory, defined as a config option, and may
define the following actions:
Action Event
------ ------
Script_OnStart * Beginning of Script execution
Script_OnEnd * End of Script execution
Script_OnFlush * Before $Response being flushed to client.
Application_OnStart Beginning of Application
Application_OnEnd End of Application
Session_OnStart Beginning of user Session.
Session_OnEnd End of user Session.
* These are API extensions that are not portable, but were
added because they are incredibly useful
These actions must be defined in the $Global/global.asa file as subroutines,
for example:
sub Session_OnStart {
$Application->{$Session->SessionID()} = started;
}
Sessions are easy to understand. When visiting a page in a web application,
each user has one unique $Session. This session expires, after which the
user will have a new $Session upon revisiting.
A web application starts when the user visits a page in that application,
and has a new $Session created. Right before the first $Session is created,
the $Application is created. When the last user $Session expires, that
$Application expires also. For some web applications that are always busy,
the Application_OnEnd event may never occur.
Script_OnStart & Script_OnEnd
The script events are used to run any code for all scripts in an application
defined by a global.asa. Often, you would like to run the same code for
every script, which you would otherwise have to add by hand, or add with a
file include, but with these events, just add your code to the global.asa,
and it will be run.
There is one caveat. Code in Script_OnEnd is not guaranteed to be run when
$Response->End() is called, since the program execution ends immediately at
this event. To always run critical code, use the API extension:
$Server->RegisterCleanup()
Session_OnStart
Triggered by the beginning of a user's session, Session_OnStart gets run
before the user's executing script, and if the same session recently timed
out, after the session's triggered Session_OnEnd.
The Session_OnStart is particularly useful for caching database data, and
avoids having the caching handled by clumsy code inserted into each script
being executed.
Session_OnEnd
Triggered by a user session ending, Session_OnEnd can be useful for cleaning
up and analyzing user data accumulated during a session.
Sessions end when the session timeout expires, and the StateManager performs
session cleanup. The timing of the Session_OnEnd does not occur immediately
after the session times out, but when the first script runs after the
session expires, and the StateManager allows for that session to be cleaned
up.
So on a busy site with default SessionTimeout (20 minutes) and StateManager
(10 times) settings, the Session_OnEnd for a particular session should be
run near 22 minutes past the last activity that Session saw. A site
infrequently visited will only have the Session_OnEnd run when a subsequent
visit occurs, and theoretically the last session of an application ever run
will never have its Session_OnEnd run.
Thus I would not put anything mission-critical in the Session_OnEnd, just
stuff that would be nice to run whenever it gets run.
Script_OnFlush
API extension. This event will be called prior to flushing the $Response
buffer to the web client. At this time, the $Response->{BinaryRef} buffer
reference may be used to modify the buffered output at runtime to apply
global changes to scripts output without having to modify all the scripts.
sub Script_OnFlush {
my $ref = $Response->{BinaryRef};
$$ref =~ s/\s+/ /sg; # to strip extra white space
}
Check out the ./site/eg/global.asa for an example of its use.
Application_OnStart
This event marks the beginning of an ASP application, and is run just before
the Session_OnStart of the first Session of an application. This event is
useful to load up $Application with data that will be used in all user
sessions.
Application_OnEnd
The end of the application is marked by this event, which is run after the
last user session has timed out for a given ASP application.
Server_OnStart ( pseudo-event )
Some might want something like a Server_OnStart event, where some code gets
runs when the web server starts. In mod_perl, this is easy to achieve
outside of the scope of an ASP application, by putting some initialization
code into a section in the httpd.conf file. Initializations that you
would like to be shared with the child httpds are particularly useful, one
such being the Apache::ASP->Loader() routine which you can read more about
in the TUNING section - Precompile Scripts subsection. It is could be called
like:
# httpd.conf
Apache::ASP->Loader($path, $pattern, %config)
So a section is your Server_OnStart routine!
mod_perl handlers
If one wants to extend one's environment with mod_perl handlers, Apache::ASP
does not stop this. Basic use of Apache::ASP in fact only involves the
content handler phase of mod_perl's PerlHandler, like
SetHandler perl-script
PerlModule Apache::ASP
PerlHandler Apache::ASP
But mod_perl allows for direct access to many more Apache event stages, for
full list try "perldoc mod_perl" or buy the mod_perl Eagle book. Some
commonly used ones are:
PerlInitHandler
PerlTransHandler
PerlFixupHandler
PerlHandler
PerlLogHandler
PerlCleanupHandler
For straight Apache::ASP programming, there are some equivalents, say
Script_OnStart event instead of Init/Fixup stages, or
$Server->RegisterCleanup() for Log/Cleanup stages, but you can do things in
the mod_perl handlers that you cannot do in Apache::ASP, especially if you
want to handle all files globally, and not just ASP scripts.
For many Apache::* modules for use with mod_perl, of which Apache::ASP is
just one, check out http://perl.apache.org/src/apache-modlist.html
To gain access to the ASP objects like $Session outside in a non-PerlHandler
mod_perl handler, you may use this API:
my $ASP = Apache::ASP->new($r); # $r is Apache->request object
as in this possible Authen handler:
use Apache::ASP;
sub My::Auth::handler {
my $r = shift;
my $ASP = Apache::ASP->new($r)
my $Session = $ASP->Session;
}
Here are some examples of do-it-yourself mod_perl handler programming...
=== Forbid Bad HSlide User Agent ===
# httpd.conf
PerlAccessHandler My::Access
sub My::Access::handler {
my $r = shift;
if($r->headers_in->{'USER_AGENT'} =~ /HSlide/) {
403;
} else {
200;
}
}
=== Runtime Path Parsing ===
This example shows how one might take an arbitrary URL path
/$path/$file.asp, and turn that into a runtime config for your site, so your
scripts get executed always in your sites DocumentRoot.
INPUT URL /SomeCategory/
OUTPUT
Script: index.asp
$Server->Config('PATH') eq '/SomeCategory'
INPUT URL /SomeCategory/index.asp
OUTPUT
Script: index.asp
$Server->Config('PATH') eq '/SomeCategory'
INPUT URI /index.asp
OUTPUT
Script: index.asp
$Server->Config('PATH') eq ''
# httpd.conf
PerlTransHandler My::Init
use lib qw( $custom_perllib );
# $custom_perllib/My/Init.pm
package My::Init;
use strict;
use Apache::Constants qw(:common);
sub handler {
my $r = shift;
my $uri = $r->uri || '/';
unless($uri =~ m|^(.*)(/([^/.]+\.[\w]+)?)$|i) {
warn("can't parse uri $uri");
return DECLINED;
}
$uri = $2;
my $PATH = $1 || '';
$r->dir_config('PATH', $PATH);
if($uri eq '/') {
$uri = '/index.asp';
}
$r->uri($uri);
$r->filename($r->document_root.$uri);
DECLINED;
}
1;
OBJECTS
The beauty of the ASP Object Model is that it takes the burden of CGI and
Session Management off the developer, and puts them in objects accessible
from any ASP script & include. For the perl programmer, treat these objects
as globals accessible from anywhere in your ASP application.
The Apache::ASP object model supports the following:
Object Function
------ --------
$Session - user session state
$Response - output to browser
$Request - input from browser
$Application - application state
$Server - general methods
These objects, and their methods are further defined in the following
sections.
If you would like to define your own global objects for use in your scripts
and includes, you can initialize them in the global.asa Script_OnStart like:
use vars qw( $Form $Site ); # declare globals
sub Script_OnStart {
$Site = My::Site->new; # init $Site object
$Form = $Request->Form; # alias form data
$Server->RegisterCleanup(sub { # garbage collection
$Site->DESTROY;
$Site = $Form = undef;
});
}
In this way you can create site wide application objects and simple aliases
for common functions.
$Session Object
The $Session object keeps track of user and web client state, in a
persistent manner, making it relatively easy to develop web applications.
The $Session state is stored across HTTP connections, in database files in
the Global or StateDir directories, and will persist across web server
restarts.
The user session is referenced by a 128 bit / 32 byte MD5 hex hashed cookie,
and can be considered secure from session id guessing, or session hijacking.
When a hacker fails to guess a session, the system times out for a second,
and with 2**128 (3.4e38) keys to guess, a hacker will not be guessing an id
any time soon.
If an incoming cookie matches a timed out or non-existent session, a new
session is created with the incoming id. If the id matches a currently
active session, the session is tied to it and returned. This is also similar
to the Microsoft ASP implementation.
The $Session reference is a hash ref, and can be used as such to store data
as in:
$Session->{count}++; # increment count by one
%{$Session} = (); # clear $Session data
The $Session object state is implemented through MLDBM, and a user should be
aware of the limitations of MLDBM. Basically, you can read complex
structures, but not write them, directly:
$data = $Session->{complex}{data}; # Read ok.
$Session->{complex}{data} = $data; # Write NOT ok.
$Session->{complex} = {data => $data}; # Write ok, all at once.
Please see MLDBM for more information on this topic. $Session can also be
used for the following methods and properties:
$Session->{CodePage}
Not implemented. May never be until someone needs it.
$Session->{LCID}
Not implemented. May never be until someone needs it.
$Session->{SessionID}
SessionID property, returns the id for the current session, which is
exchanged between the client and the server as a cookie.
$Session->{Timeout} [= $minutes]
Timeout property, if minutes is being assigned, sets this default
timeout for the user session, else returns the current session timeout.
If a user session is inactive for the full timeout, the session is
destroyed by the system. No one can access the session after it times
out, and the system garbage collects it eventually.
$Session->Abandon()
The abandon method times out the session immediately. All Session data
is cleared in the process, just as when any session times out.
$Session->Lock()
API extension. If you are about to use $Session for many consecutive
reads or writes, you can improve performance by explicitly locking
$Session, and then unlocking, like:
$Session->Lock();
$Session->{count}++;
$Session->{count}++;
$Session->{count}++;
$Session->UnLock();
This sequence causes $Session to be locked and unlocked only 1 time,
instead of the 6 times that it would be locked otherwise, 2 for each
increment with one to read and one to write.
Because of flushing issues with SDBM_File and DB_File databases, each
lock actually ties fresh to the database, so the performance savings
here can be considerable.
Note that if you have SessionSerialize set, $Session is already locked
for each script invocation automatically, as if you had called
$Session->Lock() in Script_OnStart. Thus you do not need to worry about
$Session locking for performance. Please read the section on
SessionSerialize for more info.
$Session->UnLock()
API Extension. Unlocks the $Session explicitly. If you do not call this,
$Session will be unlocked automatically at the end of the script.
$Response Object
This object manages the output from the ASP Application and the client web
browser. It does not store state information like the $Session object but
does have a wide array of methods to call.
$Response->{BinaryRef}
API extension. This is a perl reference to the buffered output of the
$Response object, and can be used in the Script_OnFlush global.asa event
to modify the buffered output at runtime to apply global changes to
scripts output without having to modify all the scripts. These changes
take place before content is flushed to the client web browser.
sub Script_OnFlush {
my $ref = $Response->{BinaryRef};
$$ref =~ s/\s+/ /sg; # to strip extra white space
}
Check out the ./site/eg/global.asa for an example of its use.
$Response->{Buffer}
Default 1, when TRUE sends output from script to client only at the end
of processing the script. When 0, response is not buffered, and client
is sent output as output is generated by the script.
$Response->{CacheControl}
Default "private", when set to public allows proxy servers to cache the
content. This setting controls the value set in the HTTP header
Cache-Control
$Response->{Charset}
This member when set appends itself to the value of the Content-Type
HTTP header. If $Response->{Charset} = 'ISO-LATIN-1' is set, the
corresponding header would look like:
Content-Type: text/html; charset=ISO-LATIN-1
$Response->{Clean} = 0-9;
API extension. Set the Clean level, default 0, on a per script basis.
Clean of 1-9 compresses text/html output. Please see the Clean config
option for more information. This setting may also be useful even if
using compression to obfuscate HTML.
$Response->{ContentType} = "text/html"
Sets the MIME type for the current response being sent to the client.
Sent as an HTTP header.
$Response->{Debug} = 1|0
API extension. Default set to value of Debug config. May be used to
temporarily activate or inactivate $Response->Debug() behavior.
Something like:
{
local $Response->{Debug} = 1;
$Response->Debug($values);
}
maybe be used to always log something. The Debug() method can be better
than AppendToLog() because it will log data in data structures one level
deep, whereas AppendToLog prints just raw string/scalar values.
$Response->{Expires} = $time
Sends a response header to the client indicating the $time in SECONDS in
which the document should expire. A time of 0 means immediate
expiration. The header generated is a standard HTTP date like: "Wed, 09
Feb 1994 22:23:32 GMT".
$Response->{ExpiresAbsolute} = $date
Sends a response header to the client with $date being an absolute time
to expire. Formats accepted are all those accepted by
HTTP::Date::str2time(), e.g.
"Wed, 09 Feb 1994 22:23:32 GMT" -- HTTP format
"Tuesday, 08-Feb-94 14:15:29 GMT" -- old rfc850 HTTP format
"08-Feb-94" -- old rfc850 HTTP format
"09 Feb 1994" -- proposed new HTTP format
"Feb 3 1994" -- Unix 'ls -l' format
"Feb 3 17:03" -- Unix 'ls -l' format
$Response->{FormFill} = 0|1
If true, HTML forms generated by the script output will be auto filled
with data from $Request->Form. This feature requires HTML::FillInForm to
be installed. Please see the FormFill CONFIG for more information.
This setting overrides the FormFill config at runtime for the script
execution only.
$Response->{IsClientConnected}
1 if web client is connected, 0 if not. This value starts set to 1, and
will be updated whenever a $Response->Flush() is called. If BufferingOn
is set, by default $Response->Flush() will only be called at the end of
the HTML output.
As of version 2.23 this value is updated correctly before global.asa
Script_OnStart is called, so global script termination may be correctly
handled during that event, which one might want to do with excessive
user STOP/RELOADS when the web server is very busy.
An API extension $Response->IsClientConnected may be called for
refreshed connection status without calling first a $Response->Flush
$Response->{PICS}
If this property has been set, a PICS-Label HTTP header will be sent
with its value. For those that do not know, PICS is a header that is
useful in rating the internet. It stands for Platform for Internet
Content Selection, and you can find more info about it at:
http://www.w3.org
$Response->{Status} = $status
Sets the status code returned by the server. Can be used to set messages
like 500, internal server error
$Response->AddHeader($name, $value)
Adds a custom header to a web page. Headers are sent only before any
text from the main page is sent, so if you want to set a header after
some text on a page, you must turn BufferingOn.
$Response->AppendToLog($message)
Adds $message to the server log. Useful for debugging.
$Response->BinaryWrite($data)
Writes binary data to the client. The only difference from
$Response->Write() is that $Response->Flush() is called internally
first, so the data cannot be parsed as an html header. Flushing flushes
the header if has not already been written.
If you have set the $Response->{ContentType} to something other than
text/html, cgi header parsing (see CGI notes), will be automatically be
turned off, so you will not necessarily need to use BinaryWrite for
writing binary data.
For an example of BinaryWrite, see the binary_write.htm example in
./site/eg/binary_write.htm
Please note that if you are on Win32, you will need to call binmode on a
file handle before reading, if its data is binary.
$Response->Clear()
Erases buffered ASP output.
$Response->Cookies($name, [$key,] $value)
Sets the key or attribute of cookie with name $name to the value $value.
If $key is not defined, the Value of the cookie is set. ASP CookiePath
is assumed to be / in these examples.
$Response->Cookies('name', 'value');
--> Set-Cookie: name=value; path=/
$Response->Cookies("Test", "data1", "test value");
$Response->Cookies("Test", "data2", "more test");
$Response->Cookies(
"Test", "Expires",
&HTTP::Date::time2str(time+86400)
);
$Response->Cookies("Test", "Secure", 1);
$Response->Cookies("Test", "Path", "/");
$Response->Cookies("Test", "Domain", "host.com");
--> Set-Cookie:Test=data1=test%20value&data2=more%20test; \
expires=Fri, 23 Apr 1999 07:19:52 GMT; \
path=/; domain=host.com; secure
The latter use of $key in the cookies not only sets cookie attributes
such as Expires, but also treats the cookie as a hash of key value pairs
which can later be accesses by
$Request->Cookies('Test', 'data1');
$Request->Cookies('Test', 'data2');
Because this is perl, you can (NOT PORTABLE) reference the cookies
directly through hash notation. The same 5 commands above could be
compressed to:
$Response->{Cookies}{Test} =
{
Secure => 1,
Value =>
{
data1 => 'test value',
data2 => 'more test'
},
Expires => 86400, # not portable, see above
Domain => 'host.com',
Path => '/'
};
and the first command would be:
# you don't need to use hash notation when you are only setting
# a simple value
$Response->{Cookies}{'Test Name'} = 'Test Value';
I prefer the hash notation for cookies, as this looks nice, and is quite
perlish. It is here to stay. The Cookie() routine is very complex and
does its best to allow access to the underlying hash structure of the
data. This is the best emulation I could write trying to match the
Collections functionality of cookies in IIS ASP.
For more information on Cookies, please go to the source at
http://home.netscape.com/newsref/std/cookie_spec.html
$Response->Debug(@args)
API Extension. If the Debug config option is set greater than 0, this
routine will write @args out to server error log. refs in @args will be
expanded one level deep, so data in simple data structures like
one-level hash refs and array refs will be displayed. CODE refs like
$Response->Debug(sub { "some value" });
will be executed and their output added to the debug output. This
extension allows the user to tie directly into the debugging
capabilities of this module.
While developing an app on a production server, it is often useful to
have a separate error log for the application to catch debugging output
separately. One way of implementing this is to use the Apache ErrorLog
configuration directive to create a separate error log for a virtual
host.
If you want further debugging support, like stack traces in your code,
consider doing things like:
$Response->Debug( sub { Carp::longmess('debug trace') };
$SIG{__WARN__} = \&Carp::cluck; # then warn() will stack trace
The only way at present to see exactly where in your script an error
occurred is to set the Debug config directive to 2, and match the error
line number to perl script generated from your ASP script.
However, as of version 0.10, the perl script generated from the asp
script should match almost exactly line by line, except in cases of
inlined includes, which add to the text of the original script, pod
comments which are entirely yanked out, and <% # comment %> style
comments which have a \n added to them so they still work.
If you would like to see the HTML preceding an error while developing,
consider setting the BufferingOn config directive to 0.
$Response->End()
Sends result to client, and immediately exits script. Automatically
called at end of script, if not already called.
$Response->ErrorDocument($code, $uri)
API extension that allows for the modification the Apache ErrorDocument
at runtime. $uri may be a on site document, off site URL, or string
containing the error message.
This extension is useful if you want to have scripts set error codes
with $Response->{Status} like 401 for authentication failure, and to
then control from the script what the error message looks like.
For more information on the Apache ErrorDocument mechanism, please see
ErrorDocument in the CORE Apache settings, and the
Apache->custom_response() API, for which this method is a wrapper.
$Response->Flush()
Sends buffered output to client and clears buffer.
$Response->Include($filename, @args)
This API extension calls the routine compiled from asp script in
$filename with the args @args. This is a direct translation of the SSI
tag
Please see the SSI section for more on SSI in general.
This API extension was created to allow greater modularization of code
by allowing includes to be called with runtime arguments. Files included
are compiled once, and the anonymous code ref from that compilation is
cached, thus including a file in this manner is just like calling a perl
subroutine. The @args can be found in @_ in the includes like:
# include.inc
<% my @args = @_; %>
As of 2.23, multiple return values can be returned from an include like:
my @rv = $Response->Include($filename, @args);
$Response->Include(\%cache_args, @sub_args) *CACHE API*
As of version 2.23, output from an include may be cached with this API
and the CONFIG settings CacheDir & CacheDB. This can be used to execute
expensive includes only rarely where applicable, drastically increasing
performance in some cases.
This API extension applies to the entire include family:
my @rv = $Response->Include(\%cache_args, @include_args)
my $html_ref = $Response->TrapInclude(\%cache_args, @include_args)
$Server->Execute(\%cache_args, @include_args)
For this output cache to work, you must load Apache::ASP in the Apache
parent httpd like so:
# httpd.conf
PerlModule Apache::ASP
The cache arguments are shown here
$Response->Include({
File => 'file.inc',
Cache => 1, # to activate cache layer
Expires => 3600, # to expire in one hour
LastModified => time() - 600, # to expire if cached before 10 minutes ago
Key => $Request->Form, # to cache based on checksum of serialized form data,
Clear => 1, # always executes include & cache output
}, @include_args);
File - include file to execute, can be file name or \$script
script data passed in as a string reference.
Cache - activate caching, will run like normal include without this
Expires - only cache for this long in seconds
LastModified - if cached before this time(), expire
Key - The cache item identity. Can be $data, \$data, \%data, \@data,
this data is serialized and combined with the filename & @include_args
to create a MD5 checksum to fetch from the cache with. If you wanted
to cache the results of a search page from form data POSTed,
then this key could be
{ Key => $Request->Form }
Clear - If set to 1, or boolean true, will always execute the include
and update the cache entry for it.
Motivation: If an include takes 1 second to execute because of complex
SQL to a database, and you can cache the output of this include because
it is not realtime data, and the cache layer runs at .01 seconds, then
you have a 100 fold savings on that part of the script. Site scalability
can be dramatically increased in this way by intelligently caching
bottlenecks in the web application.
Use Sparingly: If you have a fast include, then it may execute faster
than the cache layer runs, in which case you may actually slow your site
down by using this feature. Therefore try to use this sparingly, and
only when sure you really need it. Apache::ASP scripts generally execute
very quickly, so most developers will not need to use this feature at
all.
$Response->Include(\$script_text, @args)
Added in Apache::ASP 2.11, this method allows for executing ASP scripts
that are generated dynamically by passing in a reference to the script
data instead of the file name. This works just like the normal
$Response->Include() API, except a string reference is passed in instead
of a filename. For example:
<%
my $script = "<\% print 'TEST'; %\>";
$Response->Include(\$script);
%>
This include would output TEST. Note that tokens like <% and %> must be
escaped so Apache::ASP does not try to compile those code blocks
directly when compiling the original script. If the $script data were
fetched directly from some external resource like a database, then these
tokens would not need to be escaped at all as in:
<%
my $script = $dbh->selectrow_array(
"select script_text from scripts where script_id = ?",
undef, $script_id
);
$Response->Include(\$script);
%>
This method could also be used to render other types of dynamic scripts,
like XML docs using XMLSubs for example, though for complex runtime XML
rendering, one should use something better suited like XSLT. See the
$Server->XSLT API for more on this topic.
$Response->IsClientConnected()
API Extension. 1 for web client still connected, 0 if disconnected which
might happen if the user hits the stop button. The original API for this
$Response->{IsClientConnected} is only updated after a $Response->Flush
is called, so this method may be called for a refreshed status.
Note $Response->Flush calls $Response->IsClientConnected to update
$Response->{IsClientConnected} so to use this you are going straight to
the source! But if you are doing a loop like:
while(@data) {
$Response->End if ! $Response->{IsClientConnected};
my $row = shift @data;
%> <%= $row %> <%
$Response->Flush;
}
Then its more efficient to use the member instead of the method since
$Response->Flush() has already updated that value for you.
$Response->Redirect($url)
Sends the client a command to go to a different url $url. Script
immediately ends.
$Response->TrapInclude($file, @args)
Calls $Response->Include() with same arguments as passed to it, but
instead traps the include output buffer and returns it as as a perl
string reference. This allows one to postprocess the output buffer
before sending to the client.
my $string_ref = $Response->TrapInclude('file.inc');
$$string_ref =~ s/\s+/ /sg; # squash whitespace like Clean 1
print $$string_ref;
The data is returned as a referenece to save on what might be a large
string copy. You may dereference the data with the $$string_ref
notation.
$Response->Write($data)
Write output to the HTML page. <%=$data%> syntax is shorthand for a
$Response->Write($data). All final output to the client must at some
point go through this method.
$Request Object
The request object manages the input from the client browser, like posts,
query strings, cookies, etc. Normal return results are values if an index is
specified, or a collection / perl hash ref if no index is specified.
WARNING, the latter property is not supported in ActiveState PerlScript, so
if you use the hashes returned by such a technique, it will not be portable.
A normal use of this feature would be to iterate through the form variables
in the form hash...
$form = $Request->Form();
for(keys %{$form}) {
$Response->Write("$_: $form->{$_}
\n");
}
Please see the ./site/eg/server_variables.htm asp file for this method in
action.
Note that if a form POST or query string contains duplicate values for a
key, those values will be returned through normal use of the $Request
object:
@values = $Request->Form('key');
but you can also access the internal storage, which is an array reference
like so:
$array_ref = $Request->{Form}{'key'};
@values = @{$array_ref};
Please read the PERLSCRIPT section for more information on how things like
$Request->QueryString() & $Request->Form() behave as collections.
$Request->{Method}
API extension. Returns the client HTTP request method, as in GET or
POST. Added in version 2.31.
$Request->{TotalBytes}
The amount of data sent by the client in the body of the request,
usually the length of the form data. This is the same value as
$Request->ServerVariables('CONTENT_LENGTH')
$Request->BinaryRead([$length])
Returns a string whose contents are the first $length bytes of the form
data, or body, sent by the client request. If $length is not given, will
return all of the form data. This data is the raw data sent by the
client, without any parsing done on it by Apache::ASP.
Note that BinaryRead will not return any data for file uploads. Please
see the $Request->FileUpload() interface for access to this data.
$Request->Form() data will also be available as normal.
$Request->ClientCertificate()
Not implemented.
$Request->Cookies($name [,$key])
Returns the value of the Cookie with name $name. If a $key is specified,
then a lookup will be done on the cookie as if it were a query string.
So, a cookie set by:
Set-Cookie: test=data1=1&data2=2
would have a value of 2 returned by $Request->Cookies('test','data2').
If no name is specified, a hash will be returned of cookie names as keys
and cookie values as values. If the cookie value is a query string, it
will automatically be parsed, and the value will be a hash reference to
these values.
When in doubt, try it out. Remember that unless you set the Expires
attribute of a cookie with $Response->Cookies('cookie', 'Expires',
$xyz), the cookies that you set will only last until you close your
browser, so you may find your self opening & closing your browser a lot
when debugging cookies.
For more information on cookies in ASP, please read $Response->Cookies()
$Request->FileUpload($form_field, $key)
API extension. The FileUpload interface to file upload data is
stabilized. The internal representation of the file uploads is a hash of
hashes, one hash per file upload found in the $Request->Form()
collection. This collection of collections may be queried through the
normal interface like so:
$Request->FileUpload('upload_file', 'ContentType');
$Request->FileUpload('upload_file', 'FileHandle');
$Request->FileUpload('upload_file', 'BrowserFile');
$Request->FileUpload('upload_file', 'Mime-Header');
$Request->FileUpload('upload_file', 'TempFile');
* note that TempFile must be use with the UploadTempFile
configuration setting.
The above represents the old slow collection interface, but like all
collections in Apache::ASP, you can reference the internal hash
representation more easily.
my $fileup = $Request->{FileUpload}{upload_file};
$fileup->{ContentType};
$fileup->{BrowserFile};
$fileup->{FileHandle};
$fileup->{Mime-Header};
$fileup->{TempFile};
$Request->Form($name)
Returns the value of the input of name $name used in a form with POST
method. If $name is not specified, returns a ref to a hash of all the
form data. One can use this hash to create a nice alias to the form data
like:
# in global.asa
use vars qw( $Form );
sub Script_OnStart {
$Form = $Request->Form;
}
# then in ASP scripts
<%= $Form->{var} %>
File upload data will be loaded into $Request->Form('file_field'), where
the value is the actual file name of the file uploaded, and the contents
of the file can be found by reading from the file name as a file handle
as in:
while(read($Request->Form('file_field_name'), $data, 1024)) {};
For more information, please see the CGI / File Upload section, as file
uploads are implemented via the CGI.pm module. An example can be found
in the installation samples ./site/eg/file_upload.asp
$Request->Params($name)
API extension. If RequestParams CONFIG is set, the $Request->Params
object is created with combined contents of $Request->QueryString and
$Request->Form. This is for developer convenience simlar to CGI.pm's
param() method. Just like for $Response->Form, one could create a nice
alias like:
# in global.asa
use vars qw( $Params );
sub Script_OnStart {
$Params = $Request->Params;
}
$Request->QueryString($name)
Returns the value of the input of name $name used in a form with GET
method, or passed by appending a query string to the end of a url as in
http://localhost/?data=value. If $name is not specified, returns a ref
to a hash of all the query string data.
$Request->ServerVariables($name)
Returns the value of the server variable / environment variable with
name $name. If $name is not specified, returns a ref to a hash of all
the server / environment variables data. The following would be a common
use of this method:
$env = $Request->ServerVariables();
# %{$env} here would be equivalent to the cgi %ENV in perl.
$Application Object
Like the $Session object, you may use the $Application object to store data
across the entire life of the application. Every page in the ASP application
always has access to this object. So if you wanted to keep track of how many
visitors there where to the application during its lifetime, you might have
a line like this:
$Application->{num_users}++
The Lock and Unlock methods are used to prevent simultaneous access to the
$Application object.
$Application->Lock()
Locks the Application object for the life of the script, or until
UnLock() unlocks it, whichever comes first. When $Application is locked,
this guarantees that data being read and written to it will not suddenly
change on you between the reads and the writes.
This and the $Session object both lock automatically upon every read and
every write to ensure data integrity. This lock is useful for concurrent
access control purposes.
Be careful to not be too liberal with this, as you can quickly create
application bottlenecks with its improper use.
$Application->UnLock()
Unlocks the $Application object. If already unlocked, does nothing.
$Application->GetSession($sess_id)
This NON-PORTABLE API extension returns a user $Session given a session
id. This allows one to easily write a session manager if session ids are
stored in $Application during Session_OnStart, with full access to these
sessions for administrative purposes.
Be careful not to expose full session ids over the net, as they could be
used by a hacker to impersonate another user. So when creating a session
manager, for example, you could create some other id to reference the
SessionID internally, which would allow you to control the sessions.
This kind of application would best be served under a secure web server.
The ./site/eg/global_asa_demo.asp script makes use of this routine to
display all the data in current user sessions.
$Application->SessionCount()
This NON-PORTABLE method returns the current number of active sessions
in the application, and is enabled by the SessionCount configuration
setting. This method is not implemented as part of the original ASP
object model, but is implemented here because it is useful. In
particular, when accessing databases with license requirements, one can
monitor usage effectively through accessing this value.
$Server Object
The server object is that object that handles everything the other objects
do not. The best part of the server object for Win32 users is the
CreateObject method which allows developers to create instances of ActiveX
components, like the ADO component.
$Server->{ScriptTimeout} = $seconds
Not implemented. May never be. Please see the Apache Timeout
configuration option, normally in httpd.conf.
$Server->Config($setting)
API extension. Allows a developer to read the CONFIG settings, like
Global, GlobalPackage, StateDir, etc. Currently implemented as a wrapper
around
Apache->dir_config($setting)
May also be invoked as $Server->Config(), which will return a hash ref
of all the PerlSetVar settings.
$Server->CreateObject($program_id)
Allows use of ActiveX objects on Win32. This routine returns a reference
to an Win32::OLE object upon success, and nothing upon failure. It is
through this mechanism that a developer can utilize ADO. The equivalent
syntax in VBScript is
Set object = Server.CreateObject(program_id)
For further information, try 'perldoc Win32::OLE' from your favorite
command line.
$Server->Execute($file, @args)
New method from ASP 3.0, this does the same thing as
$Response->Include($file, @args)
and internally is just a wrapper for such. Seems like we had this
important functionality before the IIS/ASP camp!
$Server->File()
Returns the absolute file path to current executing script. Same as
Apache->request->filename when running under mod_perl.
ASP API extension.
$Server->GetLastError()
Not implemented, will likely not ever be because this is dependent on
how IIS handles errors and is not relevant in Apache.
$Server->HTMLEncode( $string || \$string )
Returns an HTML escapes version of $string. &, ", >, <, are each escapes
with their HTML equivalents. Strings encoded in this nature should be
raw text displayed to an end user, as HTML tags become escaped with this
method.
As of version 2.23, $Server->HTMLEncode() may take a string reference
for an optmization when encoding a large buffer as an API extension.
Here is how one might use one over the other:
my $buffer = '&' x 100000;
$buffer = $Server->HTMLEncode($buffer);
print $buffer;
- or -
my $buffer = '&' x 100000;
$Server->HTMLEncode(\$buffer);
print $buffer;
Using the reference passing method in benchmarks on 100K of data was 5%
more efficient, but maybe useful for some. It saves on copying the 100K
buffer twice.
$Server->MapInclude($include)
API extension. Given the include $include, as an absolute or relative
file name to the current executing script, this method returns the file
path that the include would be found from the include search path. The
include search path is the current script directory, Global, and
IncludesDir directories.
If the include is not found in the includes search path, then undef, or
bool false, is returned. So one may do something like this:
if($Server->MapInclude('include.inc')) {
$Response->Include('include.inc');
}
This code demonstrates how one might only try to execute an include if
it exists, which is useful since a script will error if it tries to
execute an include that does not exist.
$Server->MapPath($url);
Given the url $url, absolute, or relative to the current executing
script, this method returns the equivalent filename that the server
would translate the request to, regardless or whether the request would
be valid.
Only a $url that is relative to the host is valid. Urls like "." and "/"
are fine arguments to MapPath, but http://localhost would not be.
To see this method call in action, check out the sample
./site/eg/server.htm script.
$Server->Mail(\%mail, %smtp_args);
With the Net::SMTP and Net::Config modules installed, which are part of
the perl libnet package, you may use this API extension to send email.
The \%mail hash reference that you pass in must have values for at least
the To, From, and Subject headers, and the Body of the mail message.
The return value of this routine is 1 for success, 0 for failure. If the
MailHost SMTP server is not available, this will have a return value of
0.
You could send an email like so:
$Server->Mail({
To => 'somebody@yourdomain.com.foobar',
From => 'youremail@yourdomain.com.foobar',
Subject => 'Subject of Email',
Body =>
'Body of message. '.
'You might have a lot to say here!',
Organization => 'Your Organization',
CC => 'youremailcc@yourdomain.com.foobar',
BCC => 'youremailbcc@yourdomain.com.foobar',
Debug => 0 || 1,
});
Any extra fields specified for the email will be interpreted as headers
for the email, so to send an HTML email, you could set 'Content-Type' =>
'text/html' in the above example.
If you have MailFrom configured, this will be the default for the From
header in your email. For more configuration options like the MailHost
setting, check out the CONFIG section.
The return value of this method call will be boolean for success of the
mail being sent.
If you would like to specially configure the Net::SMTP object used
internally, you may set %smtp_args and they will be passed on when that
object is initialized. "perldoc Net::SMTP" for more into on this topic.
If you would like to include the output of an ASP page as the body of
the mail message, you might do something like:
my $mail_body = $Response->TrapInclude('mail_body.inc');
$Server->Mail({ %mail, Body => $$mail_body });
$Server->RegisterCleanup($sub)
non-portable extension
Sets a subroutine reference to be executed after the script ends,
whether normally or abnormally, the latter occurring possibly by the
user hitting the STOP button, or the web server being killed. This
subroutine must be a code reference created like:
$Server->RegisterCleanup(sub { $main::Session->{served}++; });
or
sub served { $main::Session->{served}++; }
$Server->RegisterCleanup(\&served);
The reference to the subroutine passed in will be executed. Though the
subroutine will be executed in anonymous context, instead of the script,
all objects will still be defined in main::*, that you would reference
normally in your script. Output written to $main::Response will have no
affect at this stage, as the request to the www client has already
completed.
Check out the ./site/eg/register_cleanup.asp script for an example of
this routine in action.
$Server->Transfer($file, @args)
New method from ASP 3.0. Transfers control to another script. The
Response buffer will not be cleared automatically, so if you want this
to serve as a faster $Response->Redirect(), you will need to call
$Response->Clear() before calling this method.
This new script will take over current execution and the current script
will not continue to be executed afterwards. It differs from Execute()
because the original script will not pick up where it left off.
As of Apache::ASP 2.31, this method now accepts optional arguments like
$Response->Include & $Server->Execute. $Server->Transfer is now just a
wrapper for:
$Response->Include($file, @args);
$Response->End;
$Server->URLEncode($string)
Returns the URL-escaped version of the string $string. +'s are
substituted in for spaces and special characters are escaped to the
ascii equivalents. Strings encoded in this manner are safe to put in
urls... they are especially useful for encoding data used in a query
string as in:
$data = $Server->URLEncode("test data");
$url = "http://localhost?data=$data";
$url evaluates to http://localhost?data=test+data, and is a
valid URL for use in anchor tags and redirects, etc.
$Server->URL($url, \%params)
Will return a URL with %params serialized into a query string like:
$url = $Server->URL('test.asp', { test => value });
which would give you a URL of test.asp?test=value
Used in conjunction with the SessionQuery* settings, the returned URL
will also have the session id inserted into the query string, making
this a critical part of that method of implementing cookieless sessions.
For more information on that topic please read on the setting in the
CONFIG section, and the SESSIONS section too.
$Server->XSLT(\$xsl_data, \$xml_data)
* NON-PORTABLE API EXTENSION *
This method takes string references for XSL and XML data and returns the
XSLT output as a string reference like:
my $xslt_data_ref = $Server->XSLT(\$xsl_data, \$xml_data)
print $$xslt_data_ref;
The XSLT parser defaults to XML::XSLT, and is configured with the
XSLTParser setting, which can also use XML::Sablotron ( support added in
2.11 ), and XML::LibXSLT ( support added in 2.29 ). Please see the
CONFIG section for more information on the XSLT* settings that drive
this API. The XSLT setting itself uses this API internally to do its
rendering.
This API was created to allow developers easy XSLT component rendering
without having to render the entire ASP scripts via XSLT. This will make
an easy plugin architecture for those looking to integrate XML into
their existing ASP application frameworks.
At some point, the API will likely take files as arguments, but not as
of the 2.11 release.
SSI
SSI is great! One of the main features of SSI is to include other files in
the script being requested. In Apache::ASP, this is implemented in a couple
ways, the most crucial of which is implemented in the file include.
Formatted as
,the .inc being merely a convention, text from the included file will be
inserted directly into the script being executed and the script will be
compiled as a whole. Whenever the script or any of its includes change, the
script will be recompiled.
Includes go a great length to promote good decomposition and code sharing in
ASP scripts, but they are still fairly static. As of version .09, includes
may have dynamic runtime execution, as subroutines compiled into the
global.asa namespace. The first way to invoke includes dynamically is
If @args is specified, Apache::ASP knows to execute the include at runtime
instead of inlining it directly into the compiled code of the script. It
does this by compiling the script at runtime as a subroutine, and caching it
for future invocations. Then the compiled subroutine is executed and has
@args passed into its as arguments.
This is still might be too static for some, as @args is still hardcoded into
the ASP script, so finally, one may execute an include at runtime by
utilizing this API extension
$Response->Include("filename.inc", @args);
which is a direct translation of the dynamic include above.
Although inline includes should be a little faster, runtime dynamic includes
represent great potential savings in httpd memory, as includes are shared
between scripts keeping the size of each script to a minimum. This can often
be significant saving if much of the formatting occurs in an included header
of a www page.
By default, all includes will be inlined unless called with an args
parameter. However, if you want all your includes to be compiled as subs and
dynamically executed at runtime, turn the DynamicIncludes config option on
as documented above.
That is not all! SSI is full featured. One of the things missing above is
the
tag. This and many other SSI code extensions are available by filtering
Apache::ASP output through Apache::SSI via the Apache::Filter and the Filter
config options. For more information on how to wire Apache::ASP and
Apache::SSI together, please see the Filter config option documented above.
Also please see Apache::SSI for further information on the capabilities it
offers.
EXAMPLES
Use with Apache. Copy the ./site/eg directory from the ASP installation to
your Apache document tree and try it out! You have to put "AllowOverride
All" in your config section to let the .htaccess file in the
./site/eg installation directory do its work.
IMPORTANT (FAQ): Make sure that the web server has write access to that
directory. Usually a
chmod -R 0777 eg
will do the trick :)
SESSIONS
Cookies are used by default for user $Session support ( see OBJECTS ). In
order to track a web user and associate server side data with that client,
the web server sets, and the web client returns a 32 byte session id
identifier cookie. This implementation is very secure and may be used in
secure HTTPS transactions, and made stronger with SecureSession and
ParanoidSession settings (see CONFIG ).
However good cookies are for this kind of persistent state management
between HTTP requests, they have long been under fire for security risks
associated with JavaScript security exploits and privacy abuse by large data
tracking companies.
Because of these reasons, web users will sometimes turn off their cookies,
rendering normal ASP session implementations powerless, resulting in a new
$Session generated every request. This is not good for ASP style sessions.
Cookieless Sessions
*** See WARNING Below ***
So we now have more ways to track sessions with the SessionQuery* CONFIG
settings, that allow a web developer to embed the session id in URL query
strings when use of cookies is denied. The implementations work such that if
a user has cookies turned on, then cookies will be used, but for those users
with cookies turned off, the session ids will be parsed into document URLs.
The first and easiest method that a web developer may use to implement
cookieless sessions are with SessionQueryParse* directives which enable
Apache::ASP to the parse the session id into document URLs on the fly.
Because this is resource inefficient, there is also the SessionQuery*
directives that may be used with the $Server->URL($url,\%params) method to
generate custom URLs with the session id in its query string.
To see an example of these cookieless sessions in action, check out the
./site/eg/session_query_parse.asp example.
*** WARNING ***
If you do use these methods, then be VERY CAREFUL of linking offsite from a
page that was accessed with a session id in a query string. This is because
this session id will show up in the HTTP_REFERER logs of the linked to site,
and a malicious hacker could use this information to compromise the security
of your site's $Sessions, even if these are run under a secure web server.
In order to shake a session id off an HTTP_REFERER for a link taking a user
offsite, you must point that link to a redirect page that will redirect a
user, like so:
<%
# "cross site scripting bug" prevention
my $sanitized_url =
$Server->HTMLEncode($Response->QueryString('OffSiteUrl'));
%>
Redirecting you offsite to
>here...
Because the web browser visits a real page before being redirected with the
tag, the HTTP_REFERER will be set to this page. Just be sure to not
link to this page with a session id in its query string.
Unfortunately a simple $Response->Redirect() will not work here, because the
web browser will keep the HTTP_REFERER of the original web page if only a
normal redirect is used.
XML/XSLT
Custom Tags with XMLSubsMatch
Before XML, there was the need to make HTML markup smarter. Apache::ASP
gives you the ability to have a perl subroutine handle the execution of any
predefined tag, taking the tag descriptors, and the text contained between,
as arguments of the subroutine. This custom tag technology can be used to
extend a web developer's abilities to add dynamic pieces without having to
visibly use <% %> style code entries.
So, lets say that you have a table that you want to insert for an employee
with contact info and the like, you could set up a tag like:
Jane Doe has been here since 1998.
To render it with a custom tag, you would tell the Apache::ASP parser to
render the tag with a subroutine:
PerlSetVar XMLSubsMatch my:new-employee
Any colons, ':', in the XML custom tag will turn into '::', a perl package
separator, so the my:employee tag would translate to the my::employee
subroutine, or the employee subroutine in the my package. Any dash "-" will
also be translated to an underscore "_", as dash is not valid in the names
of perl subroutines.
Then you would create the my::employee subroutine in the my perl package or
whereever like so:
package my;
sub new_employee {
my($attributes, $body) = @_;
$main::Response->Include('new_employee.inc', $attributes, $body);
}
1;
<% my($attributes, $body) = @_; %>
<% for('name', 'last', 'phone') { %>
| <%=ucfirst $_ %>: |
<%= $attributes->{$_} %> |
<% } %>
| <%= $body %> |
The $main::Response->Include() would then delegate the rendering of the
new-employee to the new_employee.inc ASP script include.
Though XML purists would not like this custom tag technology to be related
to XML, the reality is that a careful site engineer could render full XML
documents with this technology, applying all the correct styles that one
might otherwise do with XSLT.
Custom tags defined in this way can be used as XML tags are defined with
both a body and without as it
...
and just
These tags are very powerful in that they can also enclose normal ASP logic,
like:
<% my $birthday = &HTTP::Date::time2str(time - 25 * 86400 * 365); %>
This employee has been online for <%= int(rand()*600)+1 %>
seconds, and was born near <%= $birthday %>.
For an example of this custom XML tagging in action, please check out the
./site/eg/xml_subs.asp script.
XSLT Tranformations
XML is good stuff, but what can you use it for? The principle is that by
having data and style separated in XML and XSL files, you can reformat your
data more easily in the future, and you can render your data in multiple
formats, just as easily as for your web site, so you might render your site
to a PDA, or a cell phone just as easily as to a browser, and all you have
to do is set up the right XSL stylesheets to do the transformation (XSLT).
With native XML/XSLT support, Apache::ASP scripts may be the source of XML
data that the XSL file transforms, and the XSL file itself will be first
executed as an ASP script also. The XSLT transformation is handled by
XML::XSLT or XML::Sablotron and you can see an example of it in action at
the ./site/eg/xslt.xml XML script.
To specify a XSL stylesheet, use the setting:
PerlSetVar XSLT template.xsl
where template.xsl could be any file. By default this will XSLT transform
all ASP scripts so configured, but you can separate xml scripts from the
rest with the setting:
PerlSetVar XSLTMatch xml$
where all files with the ending xml would undergo a XSLT transformation.
Note that XSLT depends on the installation of XML::XSLT, which in turn
depends on XML::DOM, and XML::Parser. As of version 2.11, XML::Sablotron may
also be used by setting:
PerlSetVar XSLTParser XML::Sablotron
and XML::LibXSLT may be used, as of 2.29, by setting
PerlSetVar XSLTParser XML::LibXSLT
If you would like to install XML::Sablotron or XML::LibXSLT, you will first
have to install the libraries that these perl modules use, which you can get
at:
libxslt - The XSLT C Library for Gnome
http://xmlsoft.org/XSLT/
Sablotron - Ginger Alliance
http://www.gingerall.com
For more on XML::XSLT, the default XSLT engine that Apache::ASP will use,
please see:
XML::XSLT
http://xmlxslt.sourceforge.net/
XML:XSLT was the first supported XSLT engine as has the benefit of being
written in pure perl so that though while it is slower than the other
solutions, it is easier to port.
If you would like to cache XSLT tranformations, which is highly recommended,
just set:
PerlSetVar XSLTCache 1
Please see the Cache settings in the CONFIG section for more about how to
configure the XSLTCache.
References
For more information about XSLT, please see the standard at:
http://www.w3.org/TR/xslt
For their huge ground breaking XML efforts, these other XML OSS projects
need mention:
Cocoon - XML-based web publishing, in Java
http://cocoon.apache.org/
AxKit - XML web publishing with Apache & mod_perl
http://www.axkit.org/
CGI
CGI has been the standard way of deploying web applications long before ASP
came along. In the CGI gateway world, CGI.pm has been a widely used module
in building CGI applications, and Apache::ASP is compatible with scripts
written with CGI.pm. Also, as of version 2.19, Apache::ASP can run in
standalone CGI mode for the Apache web server without mod_perl being
available. See "Standalone CGI Mode" section below.
Following are some special notes with respect to compatibility with CGI and
CGI.pm. Use of CGI.pm in any of these ways was made possible through a great
amount of work, and is not guaranteed to be portable with other perl ASP
implementations, as other ASP implementations will likely be more limited.
Standalone CGI Mode, without mod_perl
As of version 2.19, Apache::ASP scripts may be run as standalone CGI
scripts without mod_perl being loaded into Apache. Work to date has only
been done with mod_cgi scripts under Apache on a Unix platform, and it
is unlikely to work under other web servers or Win32 operating systems
without further development.
To run the ./site/eg scripts as CGI scripts, you copy the ./site
directory to some location accessible by your web server, in this
example its /usr/local/apache/htdocs/aspcgi, then in your httpd.conf
activate Apache::ASP cgi scripts like so:
Alias /aspcgi/ /usr/local/apache/htdocs/aspcgi/
AddType application/x-httpd-cgi .htm
AddType application/x-httpd-cgi .html
AddType application/x-httpd-cgi .asp
AddType application/x-httpd-cgi .xml
AddType application/x-httpd-cgi .ssi
AllowOverride None
Options +ExecCGI +Indexes
Then install the asp-perl script from the distribution into /usr/bin, or
some other directory. This is so the CGI execution line at the top of
those scripts will invoke the asp-perl wrapper like so:
#!/usr/bin/perl /usr/bin/asp-perl
The asp-perl script is a cgi wrapper that sets up the Apache::ASP
environment in lieu of the normal mod_perl handler request. Because
there is no Apache->dir_config() data available under mod_cgi, the
asp-perl script will load a asp.conf file that may define a hash %Config
of data for populating the dir_config() data. An example of a complex
asp.conf file is at ./site/eg/asp.conf
So, a trivial asp.conf file might look like:
# asp.conf
%Config = (
'Global' => '.',
'StateDir' => '/tmp/aspstate',
'NoState' => 0,
'Debug' => 3,
);
The default for NoState is 1 in CGI mode, so one must set NoState to 0
for objects like $Session & $Application to be defined.
CGI.pm
CGI.pm is a very useful module that aids developers in the building of
these applications, and Apache::ASP has been made to be compatible with
function calls in CGI.pm. Please see cgi.htm in the ./site/eg directory
for a sample ASP script written almost entirely in CGI.
As of version 0.09, use of CGI.pm for both input and output is seamless
when working under Apache::ASP. Thus if you would like to port existing
cgi scripts over to Apache::ASP, all you need to do is wrap <% %> around
the script to get going. This functionality has been implemented so that
developers may have the best of both worlds when building their web
applications.
Query Object Initialization
You may create a CGI.pm $query object like so:
use CGI;
my $query = new CGI;
As of Apache::ASP version 0.09, form input may be read in by CGI.pm upon
initialization. Before, Apache::ASP would consume the form input when
reading into $Request->Form(), but now form input is cached, and may be
used by CGI.pm input routines.
CGI headers
Not only can you use the CGI.pm $query->header() method to put out
headers, but with the CgiHeaders config option set to true, you can also
print "Header: value\n", and add similar lines to the top of your
script, like:
Some-Header: Value
Some-Other: OtherValue
Script body starts here.
Once there are no longer any cgi style headers, or the there is a
newline, the body of the script begins. So if you just had an asp script
like:
print join(":", %{$Request->QueryString});
You would likely end up with no output, as that line is interpreted as a
header because of the semicolon. When doing basic debugging, as long as
you start the page with you will avoid this problem.
print()ing CGI
CGI is notorious for its print() statements, and the functions in CGI.pm
usually return strings to print(). You can do this under Apache::ASP,
since print just aliases to $Response->Write(). Note that $| has no
affect.
print $query->header();
print $query->start_form();
File Upload
CGI.pm is used for implementing reading the input from file upload. You
may create the file upload form however you wish, and then the data may
be recovered from the file upload by using $Request->Form(). Data from a
file upload gets written to a file handle, that may in turn be read
from. The original file name that was uploaded is the name of the file
handle.
my $filehandle = $Request->Form('file_upload_field_name');
print $filehandle; # will get you the file name
my $data;
while(read($filehandle, $data, 1024)) {
# data from the uploaded file read into $data
};
Please see the docs on CGI.pm (try perldoc CGI) for more information on
this topic, and ./site/eg/file_upload.asp for an example of its use.
There is a $Request->FileUpload() API extension that you can use to get
more data about a file upload, so that the following properties are
available for querying:
my $file_upload = $Request->{FileUpload}{upload_field};
$file_upload->{BrowserFile}
$file_upload->{FileHandle}
$file_upload->{ContentType}
# only if FileUploadTemp is set
$file_upload->{TempFile}
# whatever mime headers are sent with the file upload
# just "keys %$file_upload" to find out
$file_upload->{?Mime-Header?}
Please see the $Request section in OBJECTS for more information.
PERLSCRIPT
Much work has been done to bring compatibility with ASP applications written
in PerlScript under IIS. Most of that work revolved around bringing a
Win32::OLE Collection interface to many of the objects in Apache::ASP, which
are natively written as perl hashes.
New as of version 2.05 is new functionality enabled with the CollectionItem
setting, to giver better support to more recent PerlScript syntax. This
seems helpful when porting from an IIS/PerlScript code base. Please see the
CONFIG section for more info.
The following objects in Apache::ASP respond as Collections:
$Application
$Session
$Request->FileUpload *
$Request->FileUpload('upload_file') *
$Request->Form
$Request->QueryString
$Request->Cookies
$Response->Cookies
$Response->Cookies('some_cookie')
* FileUpload API Extensions
And as such may be used with the following syntax, as compared with the
Apache::ASP native calls. Please note the native Apache::ASP interface is
compatible with the deprecated PerlScript interface.
C = PerlScript Compatibility N = Native Apache::ASP
## Collection->Contents($name)
[C] $Application->Contents('XYZ')
[N] $Application->{XYZ}
## Collection->SetProperty($property, $name, $value)
[C] $Application->Contents->SetProperty('Item', 'XYZ', "Fred");
[N] $Application->{XYZ} = "Fred"
## Collection->GetProperty($property, $name)
[C] $Application->Contents->GetProperty('Item', 'XYZ')
[N] $Application->{XYZ}
## Collection->Item($name)
[C] print $Request->QueryString->Item('message'), "
\n\n";
[N] print $Request->{QueryString}{'message'}, "
\n\n";
## Working with Cookies
[C] $Response->SetProperty('Cookies', 'Testing', 'Extra');
[C] $Response->SetProperty('Cookies', 'Testing', {'Path' => '/'});
[C] print $Request->Cookies(Testing) . "
\n";
[N] $Response->{Cookies}{Testing} = {Value => Extra, Path => '/'};
[N] print $Request->{Cookies}{Testing} . "
\n";
Several incompatibilities exist between PerlScript and Apache::ASP:
> Collection->{Count} property has not been implemented.
> VBScript dates may not be used for Expires property of cookies.
> Win32::OLE::in may not be used. Use keys() to iterate over.
> The ->{Item} property does not work, use the ->Item() method.
STYLE GUIDE
Here are some general style guidelines. Treat these as tips for best
practices on Apache::ASP development if you will.
UseStrict
One of perl's blessings is also its bane, variables do not need to be
declared, and are by default globally scoped. The problem with this in
mod_perl is that global variables persist from one request to another even
if a different web browser is viewing a page.
To avoid this problem, perl programmers have often been advised to add to
the top of their perl scripts:
use strict;
In Apache::ASP, you can do this better by setting:
PerlSetVar UseStrict 1
which will cover both script & global.asa compilation and will catch "use
strict" errors correctly. For perl modules, please continue to add "use
strict" to the top of them.
Because its so essential in catching hard to find errors, this configuration
will likely become the default in some future release. For now, keep setting
it.
Do not define subroutines in scripts.
DO NOT add subroutine declarations in scripts. Apache::ASP is optimized by
compiling a script into a subroutine for faster future invocation. Adding a
subroutine definition to a script then looks like this to the compiler:
sub page_script_sub {
...
... some HTML ...
...
sub your_sub {
...
}
...
}
The biggest problem with subroutines defined in subroutines is the side
effect of creating closures, which will not behave as usually desired in a
mod_perl environment. To understand more about closures, please read up on
them & "Nested Subroutines" at:
http://perl.apache.org/docs/general/perl_reference/perl_reference.html
Instead of defining subroutines in scripts, you may add them to your sites
global.asa, or you may create a perl package or module to share with your
scripts. For more on perl objects & modules, please see:
http://www.perldoc.com/perl5.8.0/pod/perlobj.html
Use global.asa's Script_On* Events
Chances are that you will find yourself doing the same thing repeatedly in
each of your web application's scripts. You can use Script_OnStart and
Script_OnEnd to automate these routine tasks. These events are called before
and after each script request.
For example, let's say you have a header & footer you would like to include
in the output of every page, then you might:
# global.asa
sub Script_OnStart {
$Response->Include('header.inc');
}
sub Script_OnEnd {
$Response->Include('footer.inc');
}
Or let's say you want to initialize a global database connection for use in
your scripts:
# global.asa
use Apache::DBI; # automatic persistent database connections
use DBI;
use vars qw($dbh); # declare global $dbh
sub Script_OnStart {
# initialize $dbh
$dbh = DBI->connect(...);
# force you to explicitly commit when you want to save data
$Server->RegisterCleanup(sub { $dbh->rollback; });
}
sub Script_OnEnd {
# not really necessary when using persistent connections, but
# will free this one object reference at least
$dbh = undef;
}
FAQ
The following are some frequently asked questions about Apache::ASP.
Installation
Examples don't work, I see the ASP script in the browser?
This is most likely that Apache is not configured to execute the Apache::ASP
scripts properly. Check the INSTALL QuickStart section for more info on how
to quickly set up Apache to execute your ASP scripts.
Apache Expat vs. XML perl parsing causing segfaults, what do I do?
Make sure to compile apache with expat disabled. The
./make_httpd/build_httpds.sh in the distribution will do this for you, with
the --disable-rule=EXPAT in particular:
cd ../$APACHE
echo "Building apache =============================="
./configure \
--prefix=/usr/local/apache \
--activate-module=src/modules/perl/libperl.a \
--enable-module=ssl \
--enable-module=proxy \
--enable-module=so \
--disable-rule=EXPAT
^^^^^
keywords: segmentation fault, segfault seg fault
Why do variables retain their values between requests?
Unless scoped by my() or local(), perl variables in mod_perl are treated as
globals, and values set may persist from one request to another. This can be
seen in as simple a script as this:
$counter++;
$Response->Write("
Counter: $counter");
The value for $counter++ will remain between requests. Generally use of
globals in this way is a BAD IDEA, and you can spare yourself many headaches
if do "use strict" perl programming which forces you to explicity declare
globals like:
use vars qw($counter);
You can make all your Apache::ASP scripts strict by default by setting:
PerlSetVar UseStrict 1
Apache errors on the PerlHandler or PerlModule directives ?
You get an error message like this:
Invalid command 'PerlModule', perhaps mis-spelled or defined by a
module not included in the server configuration.
You do not have mod_perl correctly installed for Apache. The PerlHandler and
PerlModule directives in Apache *.conf files are extensions enabled by
mod_perl and will not work if mod_perl is not correctly installed.
Common user errors are not doing a 'make install' for mod_perl, which
installs the perl side of mod_perl, and not starting the right httpd after
building it. The latter often occurs when you have an old apache server
without mod_perl, and you have built a new one without copying over to its
proper location.
To get mod_perl, go to http://perl.apache.org
Error: no request object (Apache=SCALAR(0x???????):)
Your Apache + mod_perl build is not working properly, and is likely