package WebGUI; our $VERSION = "6.99.2"; our $STATUS = "beta"; #------------------------------------------------------------------- # WebGUI is Copyright 2001-2006 Plain Black Corporation. #------------------------------------------------------------------- # Please read the legal notices (docs/legal.txt) and the license # (docs/license.txt) that came with this distribution before using # this software. #------------------------------------------------------------------- # http://www.plainblack.com info@plainblack.com #------------------------------------------------------------------- use strict qw(vars subs); use Tie::CPHash; use Time::HiRes; use WebGUI::Affiliate; use WebGUI::Asset; use WebGUI::Cache; use WebGUI::Config; use WebGUI::HTMLForm; use WebGUI::International; use WebGUI::Operation; use WebGUI::Session; use WebGUI::User; use WebGUI::Utility; use WebGUI::PassiveProfiling; use Apache2::Request; use Apache2::RequestRec (); use Apache2::RequestIO (); use Apache2::Const -compile => qw(OK DECLINED NOT_FOUND DIR_MAGIC_TYPE); use Apache2::ServerUtil (); use LWP::MediaTypes qw(guess_media_type); #------------------------------------------------------------------- =head2 handler ( requestObject ) Primary http init/response handler for WebGUI. This method decides whether to hand off the request to contentHandler() or uploadsHandler() =head3 requestObject The Apache2::RequestRec object passed in by Apache's mod_perl. =cut sub handler { my $r = shift; my $configFile = shift || $r->dir_config('WebguiConfig'); my $s = Apache2::ServerUtil->server; my $config = WebGUI::Config->new($s->dir_config('WebguiRoot'), $configFile); $r->push_handlers(PerlFixupHandler => \&fixupHandler) if (defined $config->get("passthruUrls")); foreach my $url ($config->get("extrasURL"), @{$config->get("passthruUrls")}) { return Apache2::Const::DECLINED if ($r->uri =~ m/^$url/); } my $uploads = $config->get("uploadsURL"); if ($r->uri =~ m/^$uploads/) { $r->push_handlers(PerlAccessHandler => sub { return uploadsHandler($r, $configFile); } ); } else { $r->push_handlers(PerlResponseHandler => sub { return contentHandler($r, $configFile); } ); $r->push_handlers(PerlTransHandler => sub { return Apache2::Const::OK }); } return Apache2::Const::DECLINED; } #------------------------------------------------------------------- =head2 contentHandler ( requestObject ) Creates the WebGUI session, handles exceptional request headers, handles special states, prints the response headers, and (usually) prints the output of page(). =head3 requestObject The Apache2::RequestRec object passed in by Apache's mod_perl. =cut sub contentHandler { ### inherit Apache request. my $r = shift; my $configFile = shift || $r->dir_config('WebguiConfig'); ### Instantiate the API for this httpd instance. my $s = Apache2::ServerUtil->server; ### Open new or existing user session based on user-agent's cookie. my $session = WebGUI::Session->open($s->dir_config('WebguiRoot'),$configFile,$r, $s); if ($session->env->get("HTTP_X_MOZ") eq "prefetch") { # browser prefetch is a bad thing $session->http->setStatus("403","We don't allow prefetch, because it increases bandwidth, hurts stats, and can break web sites."); $session->http->sendHeader; } elsif ($session->setting->get("specialState") eq "upgrading") { upgrading($session); } else { my $output = processOperations($session); if ($output ne "") { # do nothing because we have operation output to display $output = undef if ($output eq "chunked"); } elsif ($session->setting->get("specialState") eq "init") { $output = setup($session); } elsif ($session->errorHandler->canShowPerformanceIndicators) { my $t = [Time::HiRes::gettimeofday()]; $output = page($session); $t = Time::HiRes::tv_interval($t) ; if ($output =~ /<\/title>/) { $output =~ s/<\/title>/ : ${t} seconds<\/title>/i; } else { $session->output->print("\nPage generated in $t seconds.\n"); } } else { $output = page($session); } $session->http->setCookie("wgSession",$session->var->{_var}{sessionId}) unless $session->var->{_var}{sessionId} eq $session->http->getCookies->{"wgSession"}; my $filename = $session->http->getStreamedFile(); if ((defined $filename) && ($session->config->get("enableStreamingUploads") eq "1")) { my $ct = guess_media_type($filename); my $oldContentType = $r->content_type($ct); if ($r->sendfile($filename) ) { return Apache2::Const::OK(); } else { $r->content_type($oldContentType); } } $session->http->sendHeader(); unless ($session->http->isRedirect()) { $session->output->print($output); if ($session->errorHandler->canShowDebug()) { $session->output->print($session->errorHandler->showDebug(),1); } } WebGUI::Affiliate::grabReferral($session); # process affiliate tracking request } $session->close; return Apache2::Const::OK; } #------------------------------------------------------------------- =head2 fixupHandler ( requestObject ) This method is here to allow proper handling of DirectoryIndexes when someone is using the passthruUrls feature. =head3 requestObject The Apache2::RequestRec object passed in by Apache's mod_perl. =cut sub fixupHandler { my $r = shift; if ($r->handler eq 'perl-script' && # Handler is Perl -d $r->filename && # Filename requested is a directory $r->is_initial_req) # and this is the initial request { $r->handler(Apache2::Const::DIR_MAGIC_TYPE); # Hand off to mod_dir return Apache2::Const::OK; } return Apache2::Const::DECLINED; # just pass it on } #------------------------------------------------------------------- =head2 page ( session , [ assetUrl ] ) Processes operations (if any), then tries the requested method on the asset corresponding to the requested URL. If that asset fails to be created, it tries the default page. =head3 session The current WebGUI::Session object. =head3 assetUrl Optionally pass in a URL to be loaded. =cut sub page { my $session = shift; my $assetUrl = shift || $session->url->getRequestedUrl; my $asset = eval{WebGUI::Asset->newByUrl($session,$assetUrl,$session->form->process("revision"))}; if ($@) { $session->errorHandler->warn("Couldn't instantiate asset for url: ".$assetUrl." Root cause: ".$@); } my $output = undef; if (defined $asset) { my $method = "view"; if ($session->form->process("func")) { $method = $session->form->process("func"); unless ($method =~ /^[A-Za-z]+$/) { $session->errorHandler->security("to call a non-existent method $method on $assetUrl"); $method = "view"; } } $output = tryAssetMethod($session,$asset,$method); $output = tryAssetMethod($session,$asset,"view") unless ($output || ($method eq "view")); } if (defined($output) and $output eq "") { if ($session->var->isAdminOn) { # they're expecting it to be there, so let's help them add it my $asset = WebGUI::Asset->newByUrl($session, $session->url->getRefererUrl) || WebGUI::Asset->getDefault($session); $session->http->setRedirect($asset->getUrl("func=add;class=WebGUI::Asset::Wobject::Layout;url=".$assetUrl)) unless $session->url->getRequestedUrl eq $session->url->getRefererUrl; } else { # not in admin mode, so can't create it, so display not found $session->http->setStatus("404","Page Not Found"); my $notFound = WebGUI::Asset->getNotFound($session); if (defined $notFound) { $output = tryAssetMethod($session,$notFound,'view'); } else { $session->errorHandler->error("The notFound page could not be instanciated!"); $output = "An error was encountered while processing your request."; } $output = "An error was encountered while processing your request." if $output eq ''; } } if ($output eq "chunked") { $output = undef; } return $output; } #------------------------------------------------------------------- =head2 processOperations ( session ) Calls the operation dispatcher using the requested operation. =head3 session The current WebGUI::Session object. =cut sub processOperations { my $session = shift; my $output = ""; my $op = $session->form->process("op"); if ($op) { $output = WebGUI::Operation::execute($session,$op); } return $output; } #------------------------------------------------------------------- =head2 setup ( session ) Handles a specialState: "setup" =head3 session The current WebGUI::Session object. =cut sub setup { my $session = shift; my $i18n = WebGUI::International->new($session, "WebGUI"); my $output = '
';
$session->http->setCacheControl("none");
$session->http->setMimeType("text/html");
return $output;
}
#-------------------------------------------------------------------
=head2 tryAssetMethod ( session )
Tries an asset method on the requested asset. Tries the "view" method if that method fails.
=head3 session
The current WebGUI::Session object.
=cut
sub tryAssetMethod {
my $session = shift;
my $asset = shift;
my $method = shift;
$session->asset($asset);
my $methodToTry = "www_".$method;
my $output = eval{$asset->$methodToTry()};
if ($@) {
$session->errorHandler->warn("Couldn't call method ".$method." on asset for url: ".$session->url->getRequestedUrl." Root cause: ".$@);
$output = tryAssetMethod($session,$asset,'view') if ($method ne "view");
}
return $output;
}
#-------------------------------------------------------------------
=head2 uploadsHandler ( requestObject )
Primary http init/response handler for WebGUI.
=head3 requestObject
The Apache2::RequestRec object passed in by handler().
=cut
sub uploadsHandler {
my $r = shift;
my $configFile = shift || $r->dir_config('WebguiConfig');
my $ok = Apache2::Const::OK;
my $notfound = Apache2::Const::NOT_FOUND;
if (-e $r->filename) {
my $path = $r->filename;
$path =~ s/^(\/.*\/).*$/$1/;
if (-e $path.".wgaccess") {
my $fileContents;
open(FILE,"<".$path.".wgaccess");
while (