diff --git a/lib/WebGUI/Asset.pm b/lib/WebGUI/Asset.pm index 6e19ca64b..3df9e9c77 100644 --- a/lib/WebGUI/Asset.pm +++ b/lib/WebGUI/Asset.pm @@ -2036,6 +2036,19 @@ sub www_manageAssets { #------------------------------------------------------------------- +=head2 getContentLastModified + +Returns the overall modification time of the object and its content in Unix epoch format, for the purpose of the Last-Modified HTTP header. Override this for subclasses that contain content that is not solely dependent on the revisionDate of the asset. + +=cut + +sub getContentLastModified { + my $self = shift; + return $self->get("revisionDate"); +} + +#------------------------------------------------------------------- + =head2 www_view ( ) Returns the view() method of the asset object if the requestor canView. diff --git a/lib/WebGUI/Asset/Wobject.pm b/lib/WebGUI/Asset/Wobject.pm index 1e3943e35..227a51d4f 100644 --- a/lib/WebGUI/Asset/Wobject.pm +++ b/lib/WebGUI/Asset/Wobject.pm @@ -505,8 +505,8 @@ sub www_view { my $self = shift; my $check = $self->checkView; return $check if (defined $check); - $self->session->http->setLastModified($self->get("revisionDate")); - $self->session->http->sendHeader; + $self->session->http->setLastModified($self->getContentLastModified); + $self->session->http->sendHeader; $self->prepareView; my $style = $self->processStyle("~~~"); my ($head, $foot) = split("~~~",$style); diff --git a/lib/WebGUI/Asset/Wobject/EventManagementSystem.pm b/lib/WebGUI/Asset/Wobject/EventManagementSystem.pm index 17df01eb0..f1be1990f 100644 --- a/lib/WebGUI/Asset/Wobject/EventManagementSystem.pm +++ b/lib/WebGUI/Asset/Wobject/EventManagementSystem.pm @@ -2326,7 +2326,7 @@ sub www_editEventMetaDataField { my $i18n2 = WebGUI::International->new($self->session,'Asset_EventManagementSystem'); my $i18n = WebGUI::International->new($self->session,"WebGUIProfile"); my $f = WebGUI::HTMLForm->new($self->session, ( - action => $self->getUrl."?func=editEventMetaDataFieldSave;fieldId=".$fieldId + action => $self->getUrl("func=editEventMetaDataFieldSave;fieldId=".$fieldId) )); my $data = {}; if ($error) { @@ -3226,7 +3226,7 @@ sub www_editPrereqSet { return $self->session->privilege->insufficient unless ($self->canAddEvents); my $i18n = WebGUI::International->new($self->session,'Asset_EventManagementSystem'); my $f = WebGUI::HTMLForm->new($self->session, ( - action => $self->getUrl."?func=editPrereqSetSave;psid=".$psid + action => $self->getUrl("func=editPrereqSetSave;psid=".$psid) )); my $data = {}; if ($error) { @@ -3356,7 +3356,7 @@ sub www_editRegistrant { return $self->session->privilege->insufficient unless ($self->canAddEvents); my $i18n = WebGUI::International->new($self->session,'Asset_EventManagementSystem'); my $f = WebGUI::HTMLForm->new($self->session, ( - action => $self->getUrl."?func=editRegistrantSave;badgeId=".$badgeId + action => $self->getUrl("?func=editRegistrantSave;badgeId=".$badgeId) )); my $data = {}; if ($error) { @@ -3607,7 +3607,7 @@ sub www_editDiscountPass { return $self->session->privilege->insufficient unless ($self->canAddEvents); my $i18n = WebGUI::International->new($self->session,'Asset_EventManagementSystem'); my $f = WebGUI::HTMLForm->new($self->session, ( - action => $self->getUrl."?func=editDiscountPassSave;passId=".$passId + action => $self->getUrl("func=editDiscountPassSave;passId=".$passId) )); my $data = {}; if ($error) { diff --git a/lib/WebGUI/Asset/Wobject/Layout.pm b/lib/WebGUI/Asset/Wobject/Layout.pm index 84ff9af6c..903508316 100644 --- a/lib/WebGUI/Asset/Wobject/Layout.pm +++ b/lib/WebGUI/Asset/Wobject/Layout.pm @@ -273,6 +273,18 @@ sub www_setContentPositions { return "Map set: ".$self->session->form->process("map"); } +#------------------------------------------------------------------- +sub getContentLastModified { + # Buggo: this is a little too conservative. Children that are hidden maybe shouldn't count. Hm. + my $self = shift; + my $mtime = $self->get("revisionDate"); + foreach my $child (@{$self->getLineage(["children"],{returnObjects=>1, excludeClasses=>['WebGUI::Asset::Wobject::Layout']})}) { + my $child_mtime = $child->getContentLastModified; + $mtime = $child_mtime if ($child_mtime > $mtime); + } + return $mtime; +} + #------------------------------------------------------------------- sub www_view { my $self = shift; @@ -296,7 +308,7 @@ sub www_view { my $ad = $adSpace->displayImpression if (defined $adSpace); $out =~ s/\Q$code/$ad/ges; } - $self->session->http->setLastModified($self->get("revisionDate")); + $self->session->http->setLastModified($self->getContentLastModified); $self->session->http->sendHeader; $self->session->output->print($out, 1); return "chunked"; diff --git a/lib/WebGUI/Asset/Wobject/SyndicatedContent.pm b/lib/WebGUI/Asset/Wobject/SyndicatedContent.pm index 64d8224ee..fe782be4b 100644 --- a/lib/WebGUI/Asset/Wobject/SyndicatedContent.pm +++ b/lib/WebGUI/Asset/Wobject/SyndicatedContent.pm @@ -80,7 +80,22 @@ sub _createRSSURLs { $var->{'rss.url'}=$self->getUrl('func=viewRSS20'); } +#------------------------------------------------------------------- +sub _getMaxHeadlines { + my $self = shift; + return $self->get('maxHeadlines') || 1000000; +} +#------------------------------------------------------------------- +sub _getValidatedUrls { + my $self = shift; + my @urls = split(/\s+/,$self->get('rssUrl')); + my @validatedUrls = (); + foreach my $url (@urls) { + push(@validatedUrls, $url) if ($url =~ m/^http/); + } + return @validatedUrls +} #------------------------------------------------------------------- @@ -289,6 +304,11 @@ sub _get_rss_data { } my $xml = $response->content(); + # Approximate with current time if we don't have a Last-Modified + # header coming from the RSS source. + my $http_lm = $response->last_modified; + my $last_modified = defined($http_lm)? $http_lm : time; + # XML::RSSLite does not handle so: $xml =~ s//$1/sg; @@ -341,6 +361,9 @@ sub _get_rss_data { #correctly as new items appear. _assign_rss_dates($session, $rss->{items}); + # Store last-modified date as well. + $rss->{last_modified} = $last_modified; + #Default to an hour timeout $cache->set(Storable::freeze($rss), 3600); } @@ -475,13 +498,21 @@ sub _get_items { my $displayMode=$self->getValue('displayMode'); my $hasTermsRegex=_make_regex($self->getValue('hasTerms')); - - my $key=join(':',('aggregate', $displayMode,$hasTermsRegex,$maxHeadlines,$self->get('rssUrl'))); + + # Cache format changes: + # - aggregate: $items + # - aggregate2 (2006-08-26): [$items, \@rss_feeds] + + my $key=join(':',('aggregate2', $displayMode,$hasTermsRegex,$maxHeadlines,$self->get('rssUrl'))); my $cache = WebGUI::Cache->new($self->session,$key, 'RSS'); - my $items = Storable::thaw($cache->get()); - my @rss_feeds; - if (!$items) { + my $cached = Storable::thaw($cache->get()); + my ($items, @rss_feeds); + + if ($cached) { + $items = $cached->[0]; + @rss_feeds = @{$cached->[1]}; + } else { $items = []; for my $url (@{$urls}) { @@ -506,8 +537,8 @@ sub _get_items { #@{$items} = sort { $b->{date} <=> $a->{date} } @{$items}; - $cache->set(Storable::freeze($items), 3600); - } + $cache->set(Storable::freeze([$items, \@rss_feeds]), 3600); + } #So return the item loop and the first RSS feed, because #when we're parsing a single feed we can use that feed's title and @@ -567,12 +598,8 @@ sub view { my $out = WebGUI::Cache->new($self->session,"view_".$self->getId)->get; return $out if $out; } - my $maxHeadlines = $self->get('maxHeadlines') || 1000000; - my @urls = split(/\s+/,$self->get('rssUrl')); - my @validatedUrls = (); - foreach my $url (@urls) { - push(@validatedUrls, $url) if ($url =~ m/^http/); - } + my $maxHeadlines = $self->_getMaxHeadlines; + my @validatedUrls = $self->_getValidatedUrls; return $self->processTemplate({},$self->get('templateId')) unless (scalar(@validatedUrls)); my $title=$self->get('title'); @@ -621,6 +648,32 @@ sub view { } +#------------------------------------------------------------------- + +=head2 getContentLastModified ( ) + +Derive the last-modified date from the revisionDate of the object and from the dates of the RSS feeds. + +=cut + +sub getContentLastModified { + # Buggo, is this too expensive? Do we really want to do this every time? + # But how else are we supposed to get a reasonable last-modified date? + # Maybe just approximate... ? + my $self = shift; + + my $maxHeadlines = $self->_getMaxHeadlines; + my @validatedUrls = $self->_getValidatedUrls; + my ($item_loop, $rss_feeds) = $self->_get_items(\@validatedUrls, $maxHeadlines); + my $mtime = $self->get("revisionDate"); + + foreach my $rss (@$rss_feeds) { + next unless defined $rss->{last_modified}; + $mtime = $rss->{last_modified} if $rss->{last_modified} > $mtime; + } + + return $mtime; +} #------------------------------------------------------------------- diff --git a/lib/WebGUI/Cache/Database.pm b/lib/WebGUI/Cache/Database.pm index 7ca759096..805b35f04 100644 --- a/lib/WebGUI/Cache/Database.pm +++ b/lib/WebGUI/Cache/Database.pm @@ -103,7 +103,8 @@ sub get { $sth->finish; my $content = $data->[0]; return undef unless ($content); - return thaw($content); + # Storable doesn't like non-reference arguments, so we wrap it in a scalar ref. + return ${thaw($content)}; } #------------------------------------------------------------------- @@ -170,7 +171,8 @@ The time to live for this content. This is the amount of time (in seconds) that sub set { my $self = shift; - my $content = freeze(shift); + # Storable doesn't like non-reference arguments, so we wrap it in a scalar ref. + my $content = freeze(\(scalar shift)); my $ttl = shift || 60; my $size = length($content); # getting better performance using native dbi than webgui sql diff --git a/sbin/preload.perl b/sbin/preload.perl index 32ea62b35..f174e647b 100644 --- a/sbin/preload.perl +++ b/sbin/preload.perl @@ -52,7 +52,16 @@ foreach my $package (@modules) { } use Apache2::ServerUtil (); -Apache2::ServerUtil->server->add_version_component("WebGUI/".$WebGUI::VERSION); +{ + # Add WebGUI to Apache version tokens + my $server = Apache2::ServerUtil->server; + my $sub = sub { + $server->add_version_component("WebGUI/".$WebGUI::VERSION); + }; + $server->push_handlers(PerlPostConfigHandler => $sub); +} + + use APR::Request::Apache2 (); use Apache2::Cookie ();