Celebrazio Net



Contact Us

ModPerl2 in Apache2 Example of Delayed Server Response

August, 2006

A web server was outfitted with a pause mechanism, triggered by a query parameter, to test the effects of latency of various lengths on a client application. The usage of this module is that for a query into the configured directory, any delay=400 value is used as the latency for the server to apply to the response. The value given is in milliseconds, and a default of 5000 ms (5 seconds) was applied.

Objectives of the script

  • Test Apache2
  • Test ModPerl2
  • Provide a QA environment for testing responses of varying latencies to basic webserver requests
  • Find a way to simply get the query args in ModPerl2 and Apache2
  • Get more granular time functionality than simply using sleep
  • Produce a current example since all the ModPerl books are out of date now

The Script

This is a test ModPerl module for Apache2. Do not put this on your production server because it has a built-in latency component. (it will cause your server to hang).


package ModPerl::QAResponse;

use strict; 
use warnings; 
use Apache2::Const -compile => 'OK'; 

sub handler {
  my $r = shift;
  # get params 
  my $args = $r->args(); 
  my @args = split '&', $args; 
  my %params ; 
  foreach my $a (@args) { 
    (my $att,my $val) = split '=', $a; 
    $params{$att} = $val ; 
  }
  # set delay in millis 
  my $delay  = exists $params{'delay'} ? $params{'delay'} : 5000 ; 
  # convert to seconds 
  my $delay_sec = ($delay / 1000) ; 
  # do the work: 
  select(undef, undef, undef, $delay_sec);  
  # done 
  return Apache2::Const::OK; # return a status to mod_perl
}
1; #  return true to perl

Explanation

 
use strict; 
use warnings; 
use Apache2::Const -compile => 'OK'; 

The 3rd line is the basic replacement for the old Apache::Constants library. And to compile it at init is the preferred way.

 
sub handler {
  my $r = shift;

A standard perl handler. Actually implemented in httpd.conf as a PerlInitHandler used within a Location directive.

 

  # get params 
  my $args = $r->args(); 
  my @args = split '&', $args; 
  my %params ; 
  foreach my $a (@args) { 
    (my $att,my $val) = split '=', $a; 
    $params{$att} = $val ; 
  }

Standard ModPerl 1 methods of getting the args were not working. The ModPerl2 default args() method returns a single string, not a hash like ModPerl 1. Hence the need to create my own hash by parsing out the key-value pairs. There are likely better ways to do this, and surely there will be in the future, but when you're stuck, this straightforward way definitely works.

 
  # set delay in millis 
  my $delay  = exists $params{'delay'} ? $params{'delay'} : 5000 ; 
  # convert to seconds 
  my $delay_sec = ($delay / 1000) ; 

Here we are just getting the target parameter from the params hash. And the timer we use takes input in seconds, but accepts decimal values. So we provide a query string interface for milliseconds, and convert here to seconds.

 
  # do the work: 
  select(undef, undef, undef, $delay_sec);  

The secret is out. Better than "sleep" because you have more granular control, this is all you need to do to instruct perl to take a small pause before continuing processing. This is effectively telling the webserver to delay the requested amount.

 
  # done 
  return Apache2::Const::OK; # return a status to mod_perl
}
1; #  return true to perl

The way to close it down in ModPerl2. Should work better than a simple 'OK'.

It is strongly recommended to upgrade to ModPerl2 if you are already running Apache2 or greater. Attempting to run ModPerl 1.99* resulted in problems and things seemed to get much easier in ModPerl2. Never do this on a production server, as it exposes you to a DOS attack of tying up all the Apache processes with delays.





1998-2017 Celebrazio.net