Apache-ASP
view release on metacpan or search on metacpan
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.
* 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.
Script_OnParse * Before script compilation
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.
Script_OnParse
This event allows one to set up a source filter on the script text, allowing
one to change the script on the fly before the compilation stage occurs. The
script text is available in the $Server->{ScriptRef} scalar reference, and
can be accessed like so:
sub Script_OnParse {
my $code = $Server->{ScriptRef}
$$code .= " ADDED SOMETHING ";
}
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 <Perl> 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
<Perl>
Apache::ASP->Loader($path, $pattern, %config)
</Perl>
So a <Perl> section is your Server_OnStart routine!
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");
Apache::ASP has been production ready since v.02. Work being done on the
module is on a per need basis, with the goal being to eventually have
the ASP API completed, with full portability to ActiveState PerlScript
and MKS PScript. If you can suggest any changes to facilitate these
goals, your comments are welcome.
TUNING
A little tuning can go a long way, and can make the difference between a web
site that gets by, and a site that screams with speed. With Apache::ASP, you
can easily take a poorly tuned site running at 10 hits/second to 50+
hits/second just with the right configuration.
Documented below are some simple things you can do to make the most of your
site.
Online Resources
For more tips & tricks on tuning Apache and mod_perl, please see the tuning
documents at:
Stas Bekman's mod_perl guide
http://perl.apache.org/guide/
Written in late 1999 this article provides an early look at how to tune your
Apache::ASP web site. It has since been updated to remain current with
Apache::ASP v2.29+
Apache::ASP Site Tuning
http://www.apache-asp.org/articles/perlmonth3_tune.html
Tuning & Benchmarking
When performance tuning, it is important to have a tool to measure the
impact of your tuning change by change. The program ab, or Apache Bench,
provides this functionality well, and is freely included in the apache
distribution.
Because performance tuning can be a neverending affair, it is a good idea to
establish a threshold where performance is "good enough", that once reached,
tuning stops.
$Application & $Session State
Use NoState 1 setting if you don't need the $Application or $Session
objects. State objects such as these tie to files on disk and will incur a
performance penalty.
If you need the state objects $Application and $Session, and if running an
OS that caches files in memory, set your "StateDir" directory to a cached
file system. On WinNT, all files may be cached, and you have no control of
this. On Solaris, /tmp is a RAM disk and would be a good place to set the
"StateDir" config setting to. When cached file systems are used there is
little performance penalty for using state files. Linux tends to do a good
job caching its file systems, so pick a StateDir for ease of system
administration.
On Win32 systems, where mod_perl requests are serialized, you can freely use
SessionSerialize to make your $Session requests faster, and you can achieve
similar performance benefits for $Application if you call
$Application->Lock() in your global.asa's Script_OnStart.
Low MaxClients
Set your MaxClients low, such that if you have that many httpd servers
running, which will happen on busy site, your system will not start swapping
to disk because of excessive RAM usage. Typical settings are less than 100
even with 1 gig RAM! To handle more client connections, look into a dual
server, mod_proxy front end.
High MaxRequestsPerChild
Set your max requests per child thread or process (in httpd.conf) high, so
that ASP scripts have a better chance being cached, which happens after they
are first compiled. You will also avoid the process fork penalty on UNIX
systems. Somewhere between 50 - 500 is probably pretty good. You do not want
to set this too high though or you will risk having your web processes use
too much RAM. One may use Apache::SizeLimit or Apache::GTopLimit to
optimally tune MaxRequestsPerChild at runtime.
Precompile Modules
For those modules that your Apache::ASP application uses, make sure that
they are loaded in your sites startup.pl file, or loaded with PerlModule in
your httpd.conf, so that your modules are compiled pre-fork in the parent
httpd.
Precompile Scripts
Precompile your scripts by using the Apache::ASP->Loader() routine
documented below. This will at least save the first user hitting a script
from suffering compile time lag. On UNIX, precompiling scripts upon server
startup allows this code to be shared with forked child www servers, so you
reduce overall memory usage, and use less CPU compiling scripts for each
separate www server process. These savings could be significant. On a PII300
Solaris x86, it takes a couple seconds to compile 28 scripts upon server
startup, with an average of 50K RAM per compiled script, and this savings is
passed on to the ALL child httpd servers, so total savings would be
50Kx28x20(MaxClients)=28M!
Apache::ASP->Loader() can be called to precompile scripts and even entire
ASP applications at server startup. Note also that in modperl, you can
precompile modules with the PerlModule config directive, which is highly
recommended.
Apache::ASP->Loader($path, $pattern, %config)
This routine takes a file or directory as its first argument. If a file,
that file will be compiled. If a directory, that directory will be recursed,
and all files in it whose file name matches $pattern will be compiled.
$pattern defaults to .*, which says that all scripts in a directory will be
compiled by default.
The %config args, are the config options that you may want set that affect
compilation. These options include: Debug, Global, GlobalPackage,
DynamicIncludes, IncludesDir, InodeNames, PodComments, StatINC,
StatINCMatch, UseStrict, XMLSubsPerlArgs, XMLSubsMatch, and XMLSubsStrict.
If your scripts are later run with different config options, your scripts
may have to be recompiled.
Here is an example of use in a *.conf file:
<Perl>
Apache::ASP->Loader(
'/usr/local/proj/site', "(asp|htm)\$",
'Global' => '/proj/perllib',
'Debug' => -3, # see system output when starting apache
# OPTIONAL configs if you use them in your apache configuration
+CompressGzip setting which, when Compress::Zlib is installed,
will compress text/html automatically going out to the web
browser if the client supports gzip encoding.
++Script_OnFlush event handler, and auxiliary work optimizing
asp events in general. $Response->{BinaryRef} created which
is a reference to outgoing output, which can be used
to modify the data at runtime before it goes out to the client.
+Some code optimizations that boost speed from 22 to 24
hits per second when using Sessions without $Application,
on a simple hello world benchmark on a WinNT PII300.
++Better SessionManagement, more aware of server farms that
don't have reliable NFS locking. The key here is to have only
one process on one server in charge of session garbage collection
at any one time, and try to create this situation with a snazzy
CleanupMaster routine. This is done by having a process register
itself in the internal database with a server key created at
apache start time. If this key gets stale, another process can
become the master, and this period will not exceed the period
SessionTimeout / StateManager.
** Work on session manager sponsored by LRN, http://www.lrn.com. **
** This work was used to deploy a server farm in production with **
** NFS mounted StateDir. Thanks to Craig Samuel for his belief in **
** open source. :) **
Future work for server farm capabilities might include breaking
up the internal database into one of 256 internal databases
hashed by the first 2 chars of the session id. Also on the plate
is Apache::Session like abilities with locking and/or data storage
occuring in a SQL database. The first dbs to be done will include
MySQL & Oracle.
+Better session security which will create a new session id for an
incoming session id that does not match one already seen. This will
help for those with Search engines that have bookmarked
pages with the session ids in the query strings. This breaks away
from standard ASP session id implementation which will automatically
use the session id presented by the browser, now a new session id will
be returned if the presented one is invalid or expired.
-$Application->GetSession will only return a session if
one already existed. It would create one before by default.
+Script_OnFlush global.asa event handler, and $Response->{BinaryRef}
member which is a scalar reference to the content about to be flushed.
See ./site/eg/global.asa for example usage, used in this case to
insert font tags on the fly into the output.
+Highlighting and linking of line error when Debug is set to 2 or -2.
--removed fork() call from flock() backup routine? How did
that get in there? Oh right, testing on Win32. :(
Very painful lesson this one, sorry to whom it may concern.
+$Application->SessionCount support turned off by default
must enable with SessionCount config option. This feature
puts an unnecessary load on busy sites, so not default
behavior now.
++XMLSubsMatch setting that allows the developer to
create custom tags XML style that execute perl subroutines.
See ./site/eg/xml_subs.asp
+MailFrom config option that defaults the From: field for
mails sent via the Mail* configs and $Server->Mail()
+$Server->Mail(\%mail, %smtp_args) API extension
+MailErrorsTo & MailAlertTo now can take comma
separated email addresses for multiple recipients.
-tracking of subroutines defined in scripts and includes so
StatINC won't undefine them when reloading the GlobalPackage,
and so an warning will be logged when another script redefines
the same subroutine name, which has been the bane of at least
a few developers.
-Loader() will now recompile dynamic includes that
have changed, even if main including script has not.
This is useful if you are using Loader() in a
PerlRestartHandler, for reloading scripts when
gracefully restarting apache.
-Apache::ASP used to always set the status to 200 by
default explicitly with $r->status(). This would be
a problem if a script was being used to as a 404
ErrorDocument, because it would always return a 200 error
code, which is just wrong. $Response->{Status} is now
undefined by default and will only be used if set by
the developer.
Note that by default a script will still return a 200 status,
but $Response->{Status} may be used to override this behavior.
+$Server->Config($setting) API extension that allows developer
to access config settings like Global, StateDir, etc., and is a
wrapper around Apache->dir_config($setting)
+Loader() will log the number of scripts
recompiled and the number of scripts checked, instead
of just the number of scripts recompiled, which is
misleading as it reports 0 for child httpds after
a parent fork that used Loader() upon startup.
-Apache::ASP->Loader() would have a bad error if it didn't load
any scripts when given a directory, prints "loaded 0 scripts" now
$VERSION = 0.18; $DATE="02/03/2000";
+Documented SessionQuery* & $Server->URL() and
cleaned up formatting some, as well as redoing
some of the sections ordering for better readability.
Document the cookieless session functionality more
in a new SESSIONS section. Also documented new
FileUpload configs and $Request->FileUpload collection.
Documented StatScripts.
+StatScripts setting which if set to 0 will not reload
( run in 2.231 seconds using v1.01-cache-2.11-cpan-39bf76dae61 )