Cache the versioned feed to prevent DDOS.

This commit is contained in:
Mateusz Uzdowski 2013-07-22 16:27:52 +12:00
parent 6839401531
commit dc5012f118
3 changed files with 45 additions and 11 deletions

View File

@ -2,3 +2,6 @@
SiteTree::add_extension('VersionFeed');
ContentController::add_extension('VersionFeed_Controller');
// Set the cache lifetime to 5 mins.
SS_Cache::set_cache_lifetime('VersionFeed_Controller', 5*60);

View File

@ -51,6 +51,9 @@ class VersionFeed extends SiteTreeExtension {
$version->DiffContent->setValue('<div>'.$diff->obj('Content')->forTemplate().'</div>');
$changed = true;
}
// Copy the link so it can be cached by SS_Cache.
$version->GeneratedLink = $version->AbsoluteLink();
}
// Omit the versions that haven't been visibly changed (only takes the above fields into consideration).
@ -93,4 +96,4 @@ class VersionFeed extends SiteTreeExtension {
public function getDefaultRSSLink() {
if ($this->owner->PublicHistory) return $this->owner->Link('changes');
}
}
}

View File

@ -29,9 +29,19 @@ class VersionFeed_Controller extends Extension {
function changes() {
if(!$this->owner->PublicHistory) throw new SS_HTTPResponse_Exception('Page history not viewable', 404);;
// Cache the diffs, otherwise it will take 5secs to generate 100 diffs which could lead to DOS.
$cache = SS_Cache::factory('VersionFeed_Controller');
$cache->setOption('automatic_serialization', true);
$key = 'changes' . $this->owner->Version;
$entries = $cache->load($key);
if(!$entries) {
$entries = $this->owner->getDiffedChanges();
$cache->save($entries, $key);
}
// Generate the output.
$title = sprintf(_t('RSSHistory.SINGLEPAGEFEEDTITLE', 'Updates to %s page'), $this->owner->Title);
$rss = new RSSFeed($this->owner->getDiffedChanges(), $this->owner->request->getURL(), $title, '', 'Title', '', null);
$rss = new RSSFeed($entries, $this->owner->request->getURL(), $title, '', 'Title', '', null);
$rss->setTemplate('Page_changes_rss');
return $rss->outputToBrowser();
}
@ -40,15 +50,33 @@ class VersionFeed_Controller extends Extension {
* Get all changes from the site in a RSS feed.
*/
function allchanges() {
// Fetch the latest changes on the entire site.
$latestChanges = DB::query('SELECT * FROM "SiteTree_versions" WHERE "WasPublished"=\'1\' AND "CanViewType" IN (\'Anyone\', \'Inherit\') AND "ShowInSearch"=1 AND ("PublicHistory" IS NULL OR "PublicHistory" = \'1\') ORDER BY "LastEdited" DESC LIMIT 20');
$changeList = new ArrayList();
foreach ($latestChanges as $record) {
// Get the diff to the previous version.
$version = new Versioned_Version($record);
$changes = $version->getDiffedChanges($version->Version, false);
if ($changes && $changes->Count()) $changeList->push($changes->First());
$latestChanges = DB::query('SELECT * FROM "SiteTree_versions" WHERE "WasPublished"=\'1\' AND "CanViewType" IN (\'Anyone\', \'Inherit\') AND "ShowInSearch"=1 AND ("PublicHistory" IS NULL OR "PublicHistory" = \'1\') ORDER BY "LastEdited" DESC LIMIT 20');
$lastChange = $latestChanges->record();
$latestChanges->rewind();
if ($lastChange) {
// Cache the diffs, otherwise it will take 5secs to generate 100 diffs which could lead to DOS.
$cache = SS_Cache::factory('VersionFeed_Controller');
$cache->setOption('automatic_serialization', true);
$key = 'allchanges' . preg_replace('#[^a-zA-Z0-9_]#', '', $lastChange['LastEdited']);
$changeList = $cache->load($key);
if(!$changeList) {
$changeList = new ArrayList();
foreach ($latestChanges as $record) {
// Get the diff to the previous version.
$version = new Versioned_Version($record);
$changes = $version->getDiffedChanges($version->Version, false);
if ($changes && $changes->Count()) $changeList->push($changes->First());
}
$cache->save($changeList, $key);
}
}
// Produce output
@ -65,4 +93,4 @@ class VersionFeed_Controller extends Extension {
function linkToAllSitesRSSFeedTitle() {
return sprintf(_t('RSSHistory.SITEFEEDTITLE', 'Updates to %s'), SiteConfig::current_site_config()->Title);
}
}
}