Apache-ASP

 view release on metacpan or  search on metacpan

ASP.pm  view on Meta::CPAN


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.

=head1 EVENTS

=head2 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.

=head2 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()

=head2 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.

=head2 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.

=head2 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.

=head2 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 ";
 }

=head2 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.

=head2 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.  

=head2 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:

ASP.pm  view on Meta::CPAN


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.

=item $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".

=item $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

=item $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.

=item $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

=item $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

=item $Response->{Status} = $status

Sets the status code returned by the server.  Can be used to
set messages like 500, internal server error

=item $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.

=item $Response->AppendToLog($message)

Adds $message to the server log.  Useful for debugging.

=item $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.

=item $Response->Clear()

Erases buffered ASP output.

=item $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=/

ASP.pm  view on Meta::CPAN


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.

=head2 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

=head2 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.

=head2 $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.

=head2 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.

=head2 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.

=head2 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.

=head2 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',

ASP.pm  view on Meta::CPAN


 +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

=item $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.



( run in 0.601 second using v1.01-cache-2.11-cpan-39bf76dae61 )