/usr/local/CPAN/Web-App/Web/App/Request/ModPerl.pm


package Web::App::Request::ModPerl;

use Class::Easy;

use base qw(Web::App::Request);

return 1
	unless $ENV{MOD_PERL};

our $mod_perl_api = 1;
$mod_perl_api = $ENV{MOD_PERL_API_VERSION}
	if exists $ENV{MOD_PERL_API_VERSION} and $ENV{MOD_PERL_API_VERSION} == 2;

my $mod_perl_config = [
	{},
	{
		request => 'Apache',
		server  => 'Apache',
		const   => 'Apache::Constants',
		strings => {
			stage   => '',
			handler => 'perl-script',
		}

	},
	{
		request => 'Apache2::RequestUtil',
		# request_rec => 'Apache2::RequestRec',
		server  => 'Apache2::ServerUtil',
		const   => 'Apache2::Const',
		strings => {
			stage => 'Response',
			handler => 'modperl',
		}
	}
];

my $mod_perl = $mod_perl_config->[$mod_perl_api];

my $strings = delete $mod_perl->{strings};

if ($mod_perl_api == 2) {
	try_to_use_inc ('Apache2::RequestRec');
	*{Apache2::RequestRec::send_http_header} = sub {return};
}

for my $k (keys %$mod_perl) {
	next if $k eq 'sizelimit' and $^O eq 'darwin';
	try_to_use_inc ($mod_perl->{$k});
}

my $const = $mod_perl->{const};

if ($mod_perl_api == 2) {
	$const->import (-compile => qw(:common :http));
} else {
	$const->import (qw(:common :http));
}

# UNAVAILABLE FOR MAC OS X
# use Apache2::SizeLimit;

# $Apache2::Size::MAX_PROCESS_SIZE  = 256*1024;  # 256MB
# $Apache2::Size::MIN_SHARE_SIZE    = 128*1024;  # 128MB
# $Apache2::Size::MAX_UNSHARED_SIZE = 160*1024;  # 160MB

# my $dir_config = Apache2::ServerUtil->server->dir_config;

has 'http_code', is => 'rw', default => $const->DONE;

sub r {
	my $r = $mod_perl->{request}->request;
	
	die unless defined $r;
	
	return $r;
}

sub server {
	return $mod_perl->{server}->server;
}

sub rewrite_root {
	my $r = shift;
	
	$r->uri ('/index.html')
		if $r->uri eq '/';
	return $const->DECLINED;
}

sub _preload {
	my $class = shift;
	my $app   = shift;
	
	my $server = $class->server;
	my $location = '';
	
	return if $mod_perl_api != 2;

	$server->add_config (['PerlTransHandler +Web::App::Request::ModPerl::rewrite_root']);
	
	my @ending = (
		"	SetHandler $strings->{handler}",
		"	Perl$strings->{stage}Handler Web::App->handle_request",
		'	DefaultType text/html',
		'</Location>',
	);
	
	my $screens = $app->config->screens;
	
	my $base_uri = $screens->{'#base-uri'};
	
	if ($base_uri and $base_uri ne '/') {
		debug "preloading into $base_uri";
		die "base-uri key in screens config must begins with '/'"
			if $base_uri !~ /^\//;
		my $location = "<Location $base_uri>";
		#warn join "\n", ($location, @ending);
		$server->add_config([
			$location,
			@ending	
		]);
		
	} else {
		debug "preloading into /";
		my @screen_ids = grep {/^(\?|[^\#\/]+)$/} keys %$screens;
		debug join ', ', @screen_ids;
		foreach my $screen_id (@screen_ids) {
			$screen_id = 'index.html'
				if $screen_id eq '?';
			
			debug "init screen /$screen_id";
			
			my $location = "<Location /$screen_id>";
			#warn join "\n", ($location, @ending);
			$server->add_config([
				$location,
				@ending
			]);
		}
	}
	
}


# this code called every request
sub _init {
	my $self = shift;
	my $app  = shift;
	
	my $r = r;
	
	my $uri = $r->uri;
	# my $path_info = $r->path_info;
	
	my $screens = $app->config->screens;
	
	my $base_uri = $screens->{'#base-uri'}; #($uri =~ /(.*)$path_info$/)[0];
	$base_uri =~ s/\/$//; # we don't want double slashes
	
	my $path_info = ($uri =~ /^$base_uri(.*)$/)[0];
	
	debug "uri: $uri, p_i: $path_info, base_uri: $base_uri";
	
	my $host = $self->incoming_headers->{'X-Forwarded-Host'} || $r->hostname;
	
	$self->set_field_values (
		host      => $host,
		uri       => $uri,
		base_uri  => $base_uri,
		path      => $path_info,
	);
} 

sub set_status {
	my $self = shift;
	my $code = shift;
	if ($self->can('r')) {
		if ($code == 200) {
			debug "setting r->status->HTTP_OK";
			$self->r->status ($const->HTTP_OK);
		} elsif ($code == 302) {
			debug "setting r->status->HTTP_MOVED_TEMPORARILY";
			$self->r->status ($const->HTTP_MOVED_TEMPORARILY);
		}
	}
}

sub done_status {
	$const->DONE;
}

sub redirect_status {
	$const->REDIRECT;
}


sub r_method {
	my $object = shift;
	my $method = shift;
	
	if ($mod_perl_api == 1) {
		$object->$method (@_);
	} elsif ($mod_perl_api == 2) {
		$object->$method (@_, r());
	}
}

sub send_headers {
	my $self = shift;
	my $headers = shift;
	
	my $r = r;

	my $method = 'headers_out';
	if ($headers->header ('Location')) {
		debug "redirect detected";
		$self->redirected (1);
		$method = 'err_headers_out';
	}
	
	$r->$method->clear;
	
	foreach my $key (($headers->header_field_names)) {
		my $val = $headers->header ($key);
		if ($key =~ /content-type/i) {
			$r->content_type ($val);
		} else {
			# $key =~ s/\b(\w)/uc $1/ge;
			$r->$method->{$key} = $val;
		}
	}

	$r->send_http_header;
}

sub incoming_headers {
	my $self = shift;
	
	return r->headers_in;
}

sub send_content {
	my $self    = shift;
	my $content = shift;
	
	debug "content output";
	
	utf8::decode ($content);
	
	r->print ($content);
}

1;