Apache-RandomLocation

 view release on metacpan or  search on metacpan

RandomLocation.pm  view on Meta::CPAN

package Apache::RandomLocation;

use strict;
use vars qw($VERSION);

use Apache::Constants qw(OK DECLINED REDIRECT SERVER_ERROR);
use CGI qw(:html2 start_form end_form submit param popup_menu);
$VERSION = '0.5';

sub handler {
  my ($r) = shift;

# determine the type requested and path information, if applicable
# $mirror will uniquely identify the <Location> directive
  my $mirror = $r->location;
  my $uri = $r->uri;
  (my $request = $uri) =~ s!$mirror(.*)!$1!;

# get ConfigFile, Type, and BaseUrl variables from PerlSetVar
  my ($configfile, $type, $site_info);


  $type = lc $r->dir_config("Type") || 'file';
  if ( $type !~ /^(file|mirror)$/ ) {
    $r->log_error("Type variable $type not recognized");
    return SERVER_ERROR;
  }

  $configfile = $r->dir_config('ConfigFile') || '';
  if ($configfile =~ m!^~!) {
    (my $home = $request) =~ s!(.*)/[^/]+!$1!;
    my $home_dir = $r->lookup_uri($home)->filename;
    $configfile =~ s!^~!$home_dir!;
    $mirror = $uri;
  }
  if ( ($type eq "mirror") and (!$configfile) ) {
    $r->log_error("A configuration file must be specified for Type mirror");
    return SERVER_ERROR;
  }

  my $baseurl = $r->dir_config('BaseURL') || '/';
  $baseurl .= "/" unless substr($baseurl, -1, 1) eq '/';

  # get the real directory from $baseurl, assuming $baseurl
  # points to a directory on the local server
  my $local_server = $r->server->server_hostname;
  my $dir;
  if ($baseurl =~ m!^~!) {
    (my $home = $request) =~ s!(.*)/[^/]+!$1!;
    $baseurl =~ s!^~!$home!;
    $dir = $r->lookup_uri($baseurl)->filename;
    $mirror = $uri;
  }
  elsif ($baseurl !~ m!^http://!) {
    $dir = $r->lookup_uri($baseurl)->filename;
  }
  elsif ($baseurl =~ m!^http://$local_server!) {
    (my $local_base = $baseurl) =~ s!^http://$local_server(.*)!$1!;
    $local_base = '/' unless ($local_base =~ m!^/!);
    $dir = $r->lookup_uri($local_base)->filename;
  }
  else {
    $dir = '';
  }

# if $main::Apache::RandomLocation::site_info doesn't exist, create it,
# using $mirror to unizuely identify it, based on the <Location> directive
  if (! $main::Apache::RandomLocation::site_info{$mirror} ) {
    unless ( read_config($r, $type, $mirror, $dir, $configfile) ) {
      $r->log_error("An error occurred in reading $configfile");
      return SERVER_ERROR;
    } 
  }
# set $site_info
  unless ($site_info = $main::Apache::RandomLocation::site_info{$mirror} ) {
    $r->log_error("Can't read \$main::Apache::RandomLocation::site_info{\$mirror}: $!");
    return SERVER_ERROR;
  }

# if param('site') exists, it came from a manual selection,
# so redirect the user there
  if ( param('site') ) {
    my $site = param('site');
    my $url = "$site_info->{$site}[0]$site/$site_info->{$site}[2]/";

# for testing purposes    
#    $r->send_http_header;
#    $r->print($url);
#    return OK;

    $r->send_cgi_header("Location: ${url}\015\012\015\012");
    return OK;
  }

# if the following is satisfied, the user wants a list of locations.
# Present a form with those listed
  elsif (  ($type eq 'mirror') and (! $request) ) {
    
    # get the host name, so the default site is one nearby
    my $host = lc $r->get_remote_host;
    if (( ! $host ) or ( $host =~ /^\d+\.\d+\.\d+\.\d+$/ )) {
      my $ip = $r->connection->remote_ip;
      $host = lc host_name($ip) || 'localhost';
    }
    my $country_code = country_code($host);
    my $default = get_site($country_code, $site_info);
    my @list =  # order the list by country code, then alphebetically
      map { $_->[0] }  
    sort { $a->[1] cmp $b->[1] or $a->[0] cmp $b->[0] } 
    map { [ $_, /.*\.(\w+)$/] }  
    keys %{$site_info};
    
    # output the form
    $r->print(start_html('-title' => 'Manual selection',
			 '-dtd' => '-//W3C//DTD HTML 3.2//EN',
			 'BGCOLOR' => '#FFFFFF',
			 'TEXT' => '#OOOOOO',
			 'LINK' => '#0000FF',
			 'VLINK' => '#000080',
			 'ALINK' => '#FF0000'),
	      h2('Manual Selection'),
	      start_form(),
	      "From this page, you can manually choose a site: ",
	      p,
	      popup_menu( '-name' => 'site',
			  '-values' => \@list,
			  '-default' => $default), 
	      p, 
	      submit('-value' => "Select site"),
	      end_form(),
	      end_html()
	     );

    
  }

# the user has specified a file or location request
  else {
    
    my $url;
    
    if ( $type eq 'file' ) {
      my $file = $site_info->[ int rand @{$site_info} ];
      $url = ($baseurl =~ m!^http://!) ? "${baseurl}${file}" : "http://${local_server}${baseurl}${file}";
# redirect the client
#      $r->send_cgi_header("Location: ${baseurl}${file}\015\012\015\012");
#      return REDIRECT;
# Instead of the preceding two lines, the following can be used.
# This saves one request to the server.

      $r->internal_redirect_handler("${baseurl}${file}");
      return OK;
    }

    else {
      my $host = lc $r->get_remote_host;
      if (( ! $host ) or ( $host =~ /^\d+\.\d+\.\d+\.\d+$/ )) {
	my $ip = $r->connection->remote_ip;
	$host = lc host_name($ip) || 'localhost';
      }
      my $country_code = country_code($host);
      my $site = get_site($country_code, $site_info);
      $url = "$site_info->{$site}[0]$site/$site_info->{$site}[2]${request}";
# redirect the client
      $r->send_cgi_header("Location: ${url}\015\012\015\012");
      return REDIRECT;
    }

# for testing purposes
#    $r->send_http_header;
#   $r->print($url);
#    return OK;

    
  }

}

# gets the country code, based on the domain name
sub country_code {
  my ($country_code) = @_;
  if (( $country_code =~ /^\d+\.\d+\.\d+\.\d+$/) or ($country_code !~ /\./) ){
    $country_code = '(com|edu|net|org|us)';
  }
  else {



( run in 1.155 second using v1.01-cache-2.11-cpan-364913b4093 )