Apache-ASP

 view release on metacpan or  search on metacpan

ASP.pm  view on Meta::CPAN


    # set up globals as early as Application_OnStart, also
    # allows variables to be changed in Script_OnStart for running script
    &InitPackageGlobals($self);

    if(my $ref = ref $code) {
	if($ref eq 'CODE') {
	    eval { &$code(); };
	} elsif($ref eq 'SCALAR') {
#	    $self->{dbg} && $self->Debug("writing cached static file data $code, length: ".length($$code));
	    $self->{Response}->WriteRef($code);
	} else {
	    $self->Error("$code is a ref, but not CODE or SCALAR!");
	}
    } else {
	# if absolute package already, then no need to set to package namespace
	my $subid = ( $code =~ /::/ ) ? $code : $self->{GlobalASA}{'package'}.'::'.$code;
	eval { &$subid(); };
    }

    if($@) { 
	$self->Error($@); 
    }
    
    ! $@;
}

sub Cache {
    my($self, $cache_name, $key, $value, $expires, $last_modified, $no_check_meta) = @_;
    $cache_name || die("no cache_name given");
    grep($cache_name eq $_, qw(XSLT Response)) || die("cache_name $cache_name is invalid");
    return unless defined($key);

    my $cache_dbm = $self->{Caches}{$cache_name};
    if(defined $cache_dbm) {
	$self->{dbg} && $self->Debug("found cache $cache_dbm for $cache_name");
    } else {
	# load at runtime for CGI environments, preloaded for mod_perl
	require Apache::ASP::State;

	local $self->{state_dir} = &config($self, 'CacheDir') || $self->{state_dir};
	local $self->{state_db} = &config($self, 'CacheDB') || 'MLDBM::Sync::SDBM_File';
	$self->{dbg} && $self->Debug("CacheDB set to $self->{state_db}");
	$cache_dbm = Apache::ASP::State::new($self, $cache_name, 'cache')
	  || ($self->Error("could not do cache $cache_name: $!") && return);
	$self->{Caches}{$cache_name} = $cache_dbm;
	$self->{dbg} && $self->Debug("init cache $cache_dbm for $cache_name");
    }

    $key = (ref($key) && ($key =~ /SCALAR/)) ? $$key : $key;
    my $checksum = &md5_hex($key).'x'.length($key);
    my $metakey = $checksum . 'xMETA';
    my $rv;

    eval {
	$cache_dbm->{dbm}->Lock;
	if(defined $value) {
	    my $meta = { ServerID => $ServerID, Creation => time() };
	    if(defined $expires && ($expires =~ /^\-?\d+$/)) {
		$meta->{Expires} = $expires;
		$meta->{Timeout} = time + $expires;
	    };
	    $self->{dbg} && $self->Debug("storing $checksum in $cache_name cache");
	    $cache_dbm->STORE($metakey, $meta);
	    $self->{cache_count_store}++;
	    $rv = $cache_dbm->STORE($checksum, $value);
	} else {
	    # don't check meta data for XSLT since transformations don't expire ever
	    if($no_check_meta) {
		$self->{dbg} && $self->Debug("cache $cache_name fetch checksum $checksum no check meta");
		$self->{cache_count_fetch}++;
		$rv = $cache_dbm->{dbm}->FETCH($checksum);
	    } else {
		my $meta = $cache_dbm->{dbm}->FETCH($metakey);
		my $new;
		if(! $meta) {
		    $meta = { Creation => 0, ServerID => 'NULL' };
		    $new = 1;
		} else {
		    # NEW EXPIRES FOR EXISTING ITEM
		    if(defined $expires && ($expires =~ /^\-?\d+$/) && ($expires != $meta->{Expires})) {
			$self->Debug("new expires $expires, old ".($meta->{Expires} || '')." for $checksum");
			$meta->{Expires} = $expires;
			# use creation timestamp for expires calculation, not current
			# time, or we would refresh the entry
			$meta->{Timeout} = $meta->{Creation} + $expires;
			$cache_dbm->STORE($metakey, $meta);
		    };
		}
		
		# LastModified calculations
		if(defined $last_modified) {
		    if($last_modified !~ /^\d+$/) {
			my $old_last_modified = $last_modified;
			$last_modified = &Apache::ASP::Date::str2time($last_modified);
			$self->{dbg} && $self->Debug("converting string date for LastModified $old_last_modified to unix time $last_modified");
		    }
		    if($last_modified < 0) {
			$self->{dbg} && $self->Debug("negative LastModified $last_modified ignored");
			$last_modified = undef;
		    }
		}
		
		# EARLY TIMEOUT CALCULATION
		if($meta->{Timeout}) {
		    # 10% chance to expire early to prevent collision
		    my $early = ($meta->{Expires} || 0) * rand() * '.1';
		    $self->{dbg} && $self->Debug("will reduce expires for $meta->{Expires} by random $early seconds, checksum $checksum");
		    $meta->{Timeout} = $meta->{Timeout} - $early;
		}
		
		$self->{dbg} && $self->Debug("meta cache data for checksum $checksum", $meta);
		
		if($new) {
		    $self->{dbg} && $self->Debug("no cache entry, checksum $checksum");
		    $self->{cache_count_miss}++;
		    $rv = undef;
		} elsif(defined $meta->{ServerID} && ($$ ne $ServerPID) && ($meta->{ServerID} ne $ServerID)) {
		    # can only run like this when running in preloaded mod_perl mode
		    # This will allow for caching in other modes that simply does not reset
		    # upon server restart
		    $self->{dbg} && $self->Debug("cache expires new server $ServerID, was $meta->{ServerID}");
		    $self->{cache_count_restart}++;
		    $rv = undef;
		} elsif($meta->{Timeout} && ($meta->{Timeout} <= time())) {
		    $self->{dbg} && $self->Debug("cache expires timeout $meta->{Timeout}, checksum $checksum, time ".time);
		    $self->{cache_count_expires}++;
		    $rv = undef;
		} elsif(defined($last_modified) && ($last_modified >= $meta->{Creation})) {
		    $self->{dbg} && $self->Debug("cache expires, checksum $checksum, LastModified $last_modified, Creation $meta->{Creation}");
		    $self->{cache_count_last_modified_expires}++;
		    $rv = undef;
		} else {
		    $self->{dbg} && $self->Debug("cache $cache_name fetch checksum $checksum");
		    $self->{cache_count_fetch}++;
		    $rv = $cache_dbm->{dbm}->FETCH($checksum);
		}
	    }
	}
	$cache_dbm->{dbm}->UnLock;
    };
    if($@) {
	$self->Out("[ASP WARN] error using cache $cache_name: $@");
	$self->{cache_count_error}++;
	eval { $cache_dbm->{dbm}->UnLock; };
    }

    $rv;
}

sub XSLT {
    my($self, $xsl_data, $xml_data) = @_;
    my $asp = $self;

    my $cache = &config($self, 'XSLTCache');
    my $cache_data = $$xsl_data.$$xml_data;

    if($cache) {
	if(my $data = $self->Cache('XSLT', \$cache_data, undef, undef, undef, 1)) {
	    return $data;
	}
    }

    ref($xsl_data) || die("xsl data must be a scalar ref");

    my $xslt_parser = &config($self, 'XSLTParser') || 'XML::XSLT';

    my @parsers = ('XML::XSLT 0.32', 'XML::Sablotron', 'XML::LibXSLT');
    my $xslt_parser_lib;
    unless (($xslt_parser_lib) = grep(/^$xslt_parser/, @parsers)) {
	die("$xslt_parser must be one of: ".join(',', @parsers));
    }

    $asp->{dbg} && $asp->Debug("using xslt parser $xslt_parser_lib");
    eval "use $xslt_parser_lib";
    $@ && die("failed to load $xslt_parser_lib: $@");

    my $xslt_data = '';
    return \$xslt_data unless(length($$xsl_data) && length($$xml_data));

    if ($xslt_parser eq 'XML::XSLT') {
	my $xslt = XML::XSLT->new($xsl_data);
	$xslt->transform($xml_data);
	$xslt_data = $xslt->toString;
	$xslt->dispose;
    } elsif ($xslt_parser eq 'XML::Sablotron') {

ASP.pm  view on Meta::CPAN

    $html =~s/</&lt;/gs;

    $html;
}

# quickly decomped out of Apache::ASP just to optionally load
# it at runtime for CGI programs ( which shouldn't need it anyway )
# will still precompile this for mod_perl
#
sub StatINC {
    my $self = shift;
    require Apache::ASP::StatINC;
    $self->StatINCRun;
}

sub SendMail {
    my($self, $mail, %args) = @_;
    my($smtp, @to, $server);
    my $rv = 1;

    # load option mail modules
    for('Net::Config', 'Net::SMTP') {
	eval "use $_";
	if($@) {
	    die("no mailing errors because can't load $_: $@");
	    return 0;
	}
    }
    
    # configure mail host
    if($self->{mail_host} = &config($self, 'MailHost')) {
	unless($NetConfig{smtp_hosts} && (($NetConfig{smtp_hosts}->[0] || '') eq $self->{mail_host})) {
	    unshift(@{$NetConfig{smtp_hosts}}, $self->{mail_host});
	}
    }
    $mail->{From} ||= &config($self, 'MailFrom');

    unless($mail->{Test}) {
	for('To', 'Body', 'Subject', 'From') {
	    $mail->{$_} ||
	      die("need $_ argument to send mail");
	}
    }

    # debugging set in mail args, or general debugging
    if(! defined($args{Debug}) && defined($mail->{Debug})) {
	$args{Debug} = $mail->{Debug};
	delete $mail->{Debug};
    }
    if(! defined($args{Debug})) {
	# in case of system level debugging, mark Net::SMTP debug also
	if((&config($self, 'Debug') || 0) < 0) {
	    $args{Debug} = 1;
	}
    }

    # connect to server
    {
	local $SIG{__WARN__} = sub { $self->Debug('Net::SMTP->new() warning', @_) };
	if($mail->{Test}) {
	    $args{Timeout} = 5;
	}
	$smtp = Net::SMTP->new(%args);
    }
    unless($smtp) {
	$self->Out("[ERROR] can't connect to SMTP server with args ", \%args);
	return 0;
    } else {
	$self->Debug("connected to SMTP server with args ", \%args);
    }

    for my $receivers (qw(To BCC CC)) {
	next unless $mail->{$receivers};
	my @receivers = (ref $mail->{$receivers}) ? @{$mail->{$receivers}} : (split(/\s*,\s*/, $mail->{$receivers}));
	push(@to, @receivers);
    }

    $self->Debug("sending mail to: ".join(',', @to));
    ($mail->{From}) = split(/\s*,\s*/,($mail->{From} || '')); # just the first one

    $smtp->mail($mail->{From}) || return(0);

    # put test before $smtp->to() because we might get a relaying denied error otherwise
    if($mail->{Test}) {
	return $rv;
    }

    $smtp->to(@to) || return(0);

    my($data);
    my $body = $mail->{Body};
    delete $mail->{Body};

    # assumes MIME-Version 1.0 for Content-Type header, according to RFC 1521
    # http://www.ietf.org/rfc/rfc1521.txt
    if($mail->{'Content-Type'} && ! $mail->{'MIME-Version'}) {
	$mail->{'MIME-Version'} = '1.0';
    }

    my %done;
    for('Subject', 'From', 'Reply-To', 'Organization', 'To', keys %$mail) {
	next unless $mail->{$_};
	next if $done{lc($_)}++;	
	my $add = ref($mail->{$_}) ? join(",", @{$mail->{$_}}) : $mail->{$_};
	$add =~ s/^[\n]*(.*?)[\n]*$/$1/;
	$data .= "$_: $add\n";
    }
    $data .= "\n" . $body;

    $smtp->data($data) || ($rv = 0);
    $smtp->quit();

    $rv && $self->Debug("mail sent successfully");
    $rv;
}

*LoadModule = *LoadModules;
sub LoadModules {
    my($self, $category, @modules) = @_;
    my $load_errors = 0;
    

ASP.pm  view on Meta::CPAN

include compilations are cached by the server.  Using this configuration
will save on memory but will slow down script execution.  Please
see the TUNING section for other strategies on improving site performance.

  PerlSetVar NoCache 0

=head2 State Management

=item NoState

default 0, if true, neither the $Application nor $Session objects will
be created.  Use this for a performance increase.  Please note that 
this setting takes precedence over the AllowSessionState and
AllowApplicationState settings.

  PerlSetVar NoState 0

=item AllowSessionState

Set to 0 for no session tracking, 1 by default
If Session tracking is turned off, performance improves,
but the $Session object is inaccessible.

  PerlSetVar AllowSessionState 1    

Note that if you want to dissallow session creation
for certain non web browser user agents, like search engine
spiders, you can use an init handler like:

  PerlInitHandler "sub { $_[0]->dir_config('AllowSessionState', 0) }"

=item AllowApplicationState

Default 1.  If you want to leave $Application undefined, then set this
to 0, for a performance increase of around 2-3%.  Allowing use of 
$Application is less expensive than $Session, as there is more
work for the StateManager associated with $Session garbage collection
so this parameter should be only used for extreme tuning.

  PerlSetVar AllowApplicationState 1

=item StateDir

default $Global/.state.  State files for ASP application go to 
this directory.  Where the state files go is the most important
determinant in what makes a unique ASP application.  Different
configs pointing to the same StateDir are part of the same
ASP application.

The default has not changed since implementing this config directive.
The reason for this config option is to allow operating systems with caching
file systems like Solaris to specify a state directory separately
from the Global directory, which contains more permanent files.
This way one may point StateDir to /tmp/myaspapp, and make one's ASP
application scream with speed.

  PerlSetVar StateDir ./.state

=item StateManager

default 10, this number specifies the numbers of times per SessionTimeout
that timed out sessions are garbage collected.  The bigger the number,
the slower your system, but the more precise Session_OnEnd's will be 
run from global.asa, which occur when a timed out session is cleaned up,
and the better able to withstand Session guessing hacking attempts.
The lower the number, the faster a normal system will run.  

The defaults of 20 minutes for SessionTimeout and 10 times for 
StateManager, has dead Sessions being cleaned up every 2 minutes.

  PerlSetVar StateManager 10

=item StateDB

default SDBM_File, this is the internal database used for state
objects like $Application and $Session.  Because an SDBM_File %hash 
has a limit on the size of a record key+value pair, usually 1024 bytes,
you may want to use another tied database like DB_File or
MLDBM::Sync::SDBM_File.

With lightweight $Session and $Application use, you can get 
away with SDBM_File, but if you load it up with complex data like
  $Session{key} = { # very large complex object }
you might max out the 1024 limit.

Currently StateDB can be: SDBM_File, MLDBM::Sync::SDBM_File,
DB_File, and GDBM_File.  Please let me know if you would like to
add any more to this list.

As of version .18, you may change this setting in a live production
environment, and new state databases created will be of this format.
With a prior version if you switch to a new StateDB, you would want to 
delete the old StateDir, as there will likely be incompatibilities between
the different database formats, including the way garbage collection
is handled.

  PerlSetVar StateDB SDBM_File

=item StateCache

Deprecated as of 2.23.  There is no equivalent config for
the functionality this represented from that version on.
The 2.23 release represented a significant rewrite
of the state management, moving to MLDBM::Sync for its
subsystem.

=item StateSerializer

default Data::Dumper, you may set this to Storable for 
faster serialization and storage of data into state objects.
This is particularly useful when storing large objects in
$Session and $Application, as the Storable.pm module has a faster
implementation of freezing and thawing data from and to
perl structures.  Note that if you are storing this much
data in your state databases, you may want to use 
DB_File since it does not have the default 1024 byte limit 
that SDBM_File has on key/value lengths.

This configuration setting may be changed in production
as the state database's serializer type is stored
in the internal state manager which will always use 
Data::Dumper & SDBM_File to store data.

  PerlSetVar StateSerializer Data::Dumper

=head2 Sessions

=item CookiePath

URL root that client responds to by sending the session cookie.
If your asp application falls under the server url "/asp", 
then you would set this variable to /asp.  This then allows
you to run different applications on the same server, with
different user sessions for each application.

  PerlSetVar CookiePath /   

=item CookieDomain

Default 0, this NON-PORTABLE configuration will allow sessions to span
multiple web sites that match the same domain root.  This is useful if
your web sites are hosted on the same machine and can share the same
StateDir configuration, and you want to shared the $Session data 
across web sites.  Whatever this is set to, that will add a 

  ; domain=$CookieDomain

part to the Set-Cookie: header set for the session-id cookie.

  PerlSetVar CookieDomain .your.global.domain

=item SessionTimeout

Default 20 minutes, when a user's session has been inactive for this
period of time, the Session_OnEnd event is run, if defined, for 
that session, and the contents of that session are destroyed.

  PerlSetVar SessionTimeout 20 

=item SecureSession

default 0.  Sets the secure tag for the session cookie, so that the cookie
will only be transmitted by the browser under https transmissions.

  PerlSetVar SecureSession 1

=item HTTPOnlySession

default 0. Sets HttpOnly flag to session cookie to mitigate XSS attacks.
Supported by most modern browsers, it only allows access to the
session cookie by the server (ie NOT Javascript)

  PerlSetVar HTTPOnlySession 1

=item ParanoidSession

default 0.  When true, stores the user-agent header of the browser 
that creates the session and validates this against the session cookie presented.
If this check fails, the session is killed, with the rationale that 
there is a hacking attempt underway.

This config option was implemented to be a smooth upgrade, as
you can turn it off and on, without disrupting current sessions.  
Sessions must be created with this turned on for the security to take effect.

This config option is to help prevent a brute force cookie search from 
being successful. The number of possible cookies is huge, 2^128, thus making such
a hacking attempt VERY unlikely.  However, on the off chance that such
an attack is successful, the hacker must also present identical
browser headers to authenticate the session, or the session will be
destroyed.  Thus the User-Agent acts as a backup to the real session id.
The IP address of the browser cannot be used, since because of proxies,
IP addresses may change between requests during a session.

There are a few browsers that will not present a User-Agent header.
These browsers are considered to be browsers of type "Unknown", and 
this method works the same way for them.

Most people agree that this level of security is unnecessary, thus
it is titled paranoid :)

  PerlSetVar ParanoidSession 0

=item SessionSerialize

default 0, if true, locks $Session for duration of script, which
serializes requests to the $Session object.  Only one script at
a time may run, per user $Session, with sessions allowed.

Serialized requests to the session object is the Microsoft ASP way, 
but is dangerous in a production environment, where there is risk
of long-running or run-away processes.  If these things happen,
a session may be locked for an indefinite period of time.  A user
STOP button should safely quit the session however.

  PerlSetVar SessionSerialize 0

=item SessionCount

ASP.pm  view on Meta::CPAN


  * 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

				  $Site->DESTROY; 
				  $Site = $Form = undef; 
			      });
 }

In this way you can create site wide application objects
and simple aliases for common functions.

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

=over

=item $Session->{CodePage}

Not implemented.  May never be until someone needs it.

=item $Session->{LCID}

Not implemented.  May never be until someone needs it.

=item $Session->{SessionID}

SessionID property, returns the id for the current session,
which is exchanged between the client and the server as a cookie.

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

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

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

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

=back

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

=over

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

ASP.pm  view on Meta::CPAN

The Lock and Unlock methods are used to prevent simultaneous 
access to the $Application object.

=over

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

=item $Application->UnLock()

Unlocks the $Application object.  If already unlocked, does nothing.

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

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

=back

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

=over

=item $Server->{ScriptTimeout} = $seconds

Not implemented. May never be.  Please see the 
Apache Timeout configuration option, normally in httpd.conf.  

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

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

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

=item $Server->File()

Returns the absolute file path to current executing script.
Same as Apache->request->filename when running under mod_perl.

ASP API extension.

=item $Server->GetLastError()

Not implemented, will likely not ever be because this is dependent
on how IIS handles errors and is not relevant in Apache.

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

ASP.pm  view on Meta::CPAN

 -XMLSubsMatch will strip parens in a pattern match
  so it does not interfere with internal matching use.

 +XSLT integration allowing XML to be rendered by XSLT
  on the fly.  XSLT specifies XSL file to transform XML.
  XSLTMatch is a regexp that matches XML file names, like \.xml$,
  which will be transformed by XSLT setting, default .*
  
  XSLTCacheSize when specified uses Tie::Cache to cached XML DOMs 
  internally and cache XSLT transformations output per XML/XSL 
  combination.  XML DOM objects can take a lot of RAM, so use
  this setting judiciously like setting to 100.  Definitely 
  experiment with this value.

 +More client info in the error mail feature, including
  client IP, form data, query string, and HTTP_* client headers

 +With Time::HiRes loaded, and Debug set to non 0, 
  will add a <!-- Apache::ASP served request in xx.xx seconds -->
  to text/html output, similar to Cocoon, per user request  
  Will also add this to the system debug error log output
  when Debug is < 0

 -bug fix on object initialization optimization earlier
  in this release, that was introduced for faster event
  handler execution.

 +Apache::ASP::Parse() takes a file name, scalar, or
  scalar ref for arguments of data to parse for greater
  integration ability with other applications.

 +PodComments optimization, small speed increase at
  compilation time.

 +String optimization on internal rendering that avoids 
  unnecessary copying of static html, by using refs.  Should 
  make a small difference on sites with large amounts of 
  static html.

 +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.

ASP.pm  view on Meta::CPAN

  will throw off the line counts by adding text, removing
  text, or having an extra newline added, respectively.

 -Script_OnEnd may now send output to the browser.  Before
  $main::Response->End() was being called at the end of the
  main script preventing further output.

++All scripts are compiled as routines in a namespace uniquely
  defined by the global.asa of the ASP application.  Thus,
  scripts, includes, and global.asa routines will share
  all globals defined in the global.asa namespace.   This means
  that globals between scripts will be shared, and globals
  defined in a global.asa will be available to scripts.

  Scripts used to have their own namespace, thus globals
  were not shared between them.

 +a -o $output_dir switch on the ./cgi/asp script allows
  it to execute scripts and write their output to an output
  directory.  Useful for building static html sites, based on
  asp scripts.  An example use would be:

    asp -b -o out *.asp

  Without an output directory, script output is written to STDOUT


=item $VERSION = 0.09; $DATE="04/22/1999";

 +Updated Makefile.PL optional modules output for CGI & DB_File

 +Improved docs on $Response->Cookies() and $Request->Cookies()

 +Added PERFORMANCE doc to main README, and added sub section
  on precompiling scripts with Apache::ASP->Loader()

 +Naming of CompileIncludes switched over to DynamicIncludes 
  for greater clarity.

 +Dynamic includes can now reference ASP objects like $Session
  w/o the $main::* syntax.  These subs are no longer anonymous
  subs, and are now compiled into the namespace of the global.asa package.

 +Apache::ASP->Loader() precompiles dynamic includes too. Making this work
  required fixing some subtle bugs / dependencies in the compiling process.

 +Added Apache::ASP->Loader() similar to Apache::RegistryLoader for
  precompiling ASP scripts.  Precompile a whole site at server 
  startup with one function call.

 +Prettied the error messaging with Debug 2.

 +$Response->Debug(@args) debugging extension, which
  allows a developer to hook into the module's debugging,
  and only have @args be written to error_log when Debug is greater
  than 0.

 -Put write locking code around State writes, like $Session
  and $Application.  I thought I fixed this bug a while ago.

 -API change: converted $Session->Timeout() and $Session->SessionID() 
  methods into $Session->{Timeout} and $Session->{SessionID} properties.
  The use of these properties as methods is deprecated, but 
  backwards compatibility will remain.  Updated ./eg/session.asp
  to use these new properties.

 +Implemented $Response->{PICS} which if set sends out a PICS-Label
  HTTP header, useful for ratings.

 +Implemented $Response->{CacheControl} and $Response->{Charset} members.
  By default, CacheControl is 'private', and this value gets sent out
  every request as HTTP header Cache-Control.  Charset appends itself
  onto the content type header.

 +Implemented $Request->BinaryRead(), $Request->{TotalBytes},
  documented them, and updated ./eg/form.asp for an example usage. 

 +Implemented $Response->BinaryWrite(), documented, and created
  and example in ./eg/binary_write.htm

 +Implemented $Server->MapPath() and created example of its use
  in ./eg/server.htm

 -$Request->Form() now reads file uploads correctly with 
  the latest CGI.pm, where $Request->Form('file_field') returns
  the actual file name uploaded, which can be used as a file handle
  to read in the data.  Before, $Request->Form('file_field') would
  return a glob that looks like *Fh::filename, so to get the file
  name, you would have to parse it like =~ s/^\*Fh\:\://,
  which you no longer have to do.  As long as parsing was done as
  mentioned, the change should be backwards compatible.

 +Updated  +enhanced documentation on file uploads.  Created extra
  comments about it as an FAQ, and under $Response->Form(), the latter
  being an obvious place for a developer to look for it.

 +Updated ./eg/file_upload.asp to show use of non file form data, 
  with which we had a bug before.

 +Finished retieing *STDIN to cached STDIN contents, so that 
  CGI input routines may be used transparently, along side with
  use of $Request->Form()

 +Cleaned up and optimized $Request code

 +Updated documentation for CGI input & file uploads.  Created
  file upload FAQ.

 +Reworked ./eg/cgi.htm example to use CGI input routines
  after doing a native read of STDIN.

 ++Added dynamic includes with <!--include file=file args=@args-->
  extension.  This style of include is compiled as an anonymous sub & 
  cached, and then executed with @args passed to the subroutine for 
  execution.  This is include may also be rewritten as a new API 
  extension: $Response->Include('file', @args)

 +Added ./eg/compiled_includes.htm example documenting new dynamic includes.

 +Documented SSI: native file includes, and the rest with filtering 
  to Apache::SSI

ASP.pm  view on Meta::CPAN

  code sharing

 - <% @array... %> no longer dropped from code.

 +perl =pod comments are stripped from script before compiling, and associated
  PodComments configuration options.

 +Command line cgi/asp script takes various options, and allows execution
  of multiple asp scripts at one time.  This script should be used for
  command line debugging.  This is also the beginning of building
  a static site from asp scripts with the -b option, suppressing headers.

 +$Response->AddHeader('Set-Cookie') works for multiple cookies.

 -$Response->Cookies('foo', '0') works, was dropping 0 because of boolean test

 -Fixed up some config doc errors.


=item $VERSION = 0.07; $DATE="01/20/1999";

 -removed SIG{__WARN__} handler, it was a bad idea.

 -fixes file locking on QNX, work around poor flock porting

 +removed message about Win32::OLE on UNIX platforms from Makefile.PL

 -Better lock garbage collection.  Works with StatINC seamlessly.

 -Multiple select forms now work in array context with $Response->Form()
	@values = $Response->Form('multi');

 -Better CGI.pm compatibility with $r->header_out('Content-type'),
  improved garbage collection under modperl, esp. w/ file uploads


=item $VERSION = 0.06; $DATE="12/21/1998";

 +Application_OnStart & Application_OnEnd event handlers support.

 -Compatible with CGI.pm 2.46 headers() 

 -Compatible with CGI.pm $q = new CGI({}), caveat: does not set params 

 +use strict; followed by use of objects like $Session is fine.

 -Multiple cookies may be set per script execution.

 +file upload implemented via CGI.pm

 ++global.asa implemented with events Session_OnStart and Session_OnEnd
  working appropriately.

 +StateDir configuration directive implemented.
  StateDir allows the session state directory to be specified separately 
  from the Global directory, useful for operating systems with caching file 
  systems.

 +StateManager config directive.  StateManager specifies how frequently
  Sessions are cleaned up, with 10 (default) meaning that old Sessions
  will be cleaned up 10 times per SessionTimeout period (default 20 minutes).

 +$Application->SessionCount() implemented, non-portable method.
	: returns the number of currently active sessions

 -STOP button fix.  Users may hit STOP button during script 
  execution, and Apache::ASP will cleanup with a routine registered
  in Apache's $r->register_cleanup.  Works well supposedly.

 +PerlScript compatibility work, trying to make ports smoother.
	: Collection emulator, no ->{Count} property
	: $.*(.*)->{Item} parsed automatically, 
	  shedding the ->{Item} for Collection support (? better way ?)
	: No VBScript dates support, just HTTP RFC dates with HTTP::Date
	: Win32::OLE::in not supported, just use "keys %{$Collection}"	

 +./cgi/asp script for testing scripts from the command line
	: will be upgraded to CGI method of doing asp
	: is not "correct" in anyway, so not documented for now
	  but still useful

 +strips DOS carriage returns from scripts automatically, so that
  programs like FrontPage can upload pages to UNIX servers
  without perl choking on the extra \r characters.


=item $VERSION = 0.05; $DATE="10/19/1998";

 +Added PERFORMANCE doc, which includes benchmarks  +hints.

 +Better installation warnings and errors for other modules required. 

 -Turned off StatINC in eg/.htaccess, as not everyone installs Devel::Symdump

 -Fixed AUTOLOAD state bug, which wouldn't let you each through state
  objects, like %{$Session}, or each %$Session, (bug introduced in v.04)

 +Parses ASP white space better.  HTML output matches author's intent
  by better dealing with white space surrounding <% perl blocks %>

 -Scalar insertion code <%=$foo%> can now span many lines.

 +Added include.t test script for includes.

 +Script recompiles when included files change.

 +Files can be included in script with 
  SSI <!--#include file="filename"--> syntax, needs to be
  done in ASP module to allow compilation of included code and html 
  into script.  Future chaining with Apache::SSI will allow static 
  html includes, and other SSI directives


=item $VERSION = 0.04; $DATE="10/14/1998";

 +Example script eg/cgi.htm demonstrating CGI.pm use for output.

 +Optimized ASP parsing, faster and more legible executing code
	: try 'die();' in code with setting PerlSetVar Debug 2

 +Cleaned up code for running with 'use strict'

ASP.pm  view on Meta::CPAN

 +$Response->Write() prints scalars, arrays, and hashes.  Before only scalars.

 +Begin implementation of $Server object.

 +Implemented $Response->{Expires} and $Response->{ExpiresAbsolute}

 +Added "PerlSetVar StatINC" config option

 +$0 is aliased to current script filename

 +ASP Objects ($Response, etc.) are set in main package
  Thus notation like $main::Response->Write() can be used anywhere.


=item $VERSION = 0.02; $DATE="07/12/1998";

 ++Session Manager, won't break under denial of service attack

 +Fleshed out $Response, $Session objects, almost full implementation.

 +Enormously more documentation.

 -Fixed error handling with Debug = 2.

 -Documentation fixed for pod2man support.  README now more man-like.

 -Stripped \r\n dos characters from installation files

 -755 mode set for session state directory when created

 -Loads Win32/OLE properly, won't break with UNIX


=item $VERSION = 0.01; $DATE="06/26/1998";

 Syntax Support
 --------------
 Initial release, could be considered alpha software.
 Allows developers to embed perl in html ASP style.

 <!-- sample here -->
 <html>
 <body>
 <% for(1..10) { %>
 	counting: <%=$_%> <br>
 <% } %>
 </body>
 </html>

 ASP Objects
 -----------
 $Session, $Application, $Response, $Request objects available
 for use in asp pages.

 $Session & $Application data is preserved using SDBM files.

 $Session id's are tracked through the use of cookies.

 Security
 --------
 Timeouts any attempt to use a session id that doesn't already 
 exist.  Should stop hackers, since there is no wire speed guessing
 cookies.

=head1 LICENSE

Copyright (c) 1998-2018, Josh Chamas

All rights reserved.  This program is free software; you can 
redistribute it and/or modify it under the same terms as Perl itself.

Apache::ASP is a perl native port of Active Server Pages for Apache
and mod_perl.  

=cut





( run in 1.356 second using v1.01-cache-2.11-cpan-56fb94df46f )