r21478 - Code Review

From MediaWiki.org

Jump to: navigation, search
Repository:MediaWiki
Revision:r21477 | r21478 (on ViewVC) | r21479 >
Date:22:32, 22 April 2007
Author:daniel
Status:new
Tags:
Comment:use different way to hook feed output, to deal with erronous '304 Not Modified' responses
Modified paths:

Diff [purge]

Index: trunk/extensions/News/News.php
===================================================================
--- trunk/extensions/News/News.php	(revision 21477)
+++ trunk/extensions/News/News.php	(revision 21478)
@@ -28,8 +28,8 @@
 $wgExtensionFunctions[] = "wfNewsExtension";
 
 $wgAutoloadClasses['NewsRenderer'] = dirname( __FILE__ ) . '/NewsRenderer.php';
-$wgHooks['ArticleViewHeader'][] = 'wfNewsArticleViewHeader';
-$wgHooks['ArticlePurge'][] = 'wfNewsArticlePurge';
+$wgAutoloadClasses['NewsFeedPage'] = dirname( __FILE__ ) . '/NewsRenderer.php';
+$wgHooks['ArticleFromTitle'][] = 'wfNewsArticleFromTitle';
 $wgHooks['SkinTemplateOutputPageBeforeExec'][] = 'wfNewsSkinTemplateOutputPageBeforeExec';
 
 //FIXME: find a way to override the feed URLs generated by OutputPage::getHeadLinks
@@ -56,10 +56,6 @@
     $parser->disableCache(); //TODO: use smart cache & purge...?
     $wgOut->setSyndicated( true );
 
-    #$rss = $renderer->renderFeedMetaLink( 'rss' );
-    #$atom = $renderer->renderFeedMetaLink( 'atom' );
-    #$parser->mOutput->addHeadItem($rss . $atom);
-
     $renderer = new NewsRenderer($wgTitle, $templatetext, $argv, $parser);
     $html = $renderer->renderFeedPreview();
     return $html;
@@ -69,112 +65,39 @@
     return NewsRenderer::renderFeedLink($linktext, $argv, $parser);
 }
 
-function wfNewsCacheKey( $title, $format ) {
-    //global $wgLang;
-    //NOTE: per-language caching might be needed at some point.
-    //      right now, caching is done for anon users only 
-    //      (the content language might be set individually however, 
-    //      using an extension like LanguageSelector)
+function wfNewsArticleFromTitle( &$title, &$article ) {
+    global $wgRequest, $wgFeedClasses, $wgUser, $wgOut;
+    $fname = 'extension/News: wfNewsArticleFromTitle';
 
-    return "@newsfeed:" . urlencode($title->getPrefixedDBKey()) . '|' . urlencode($format);
-}
+    $ns = $title->getNamespace();
+    if ($ns < 0 || $ns == NS_SPECIAL || $ns == NS_MEDIAWIKI) return true;
 
-function wfNewsArticleViewHeader( &$article ) {
-    global $wgRequest, $wgOut, $wgFeedClasses, $wgUser;
-
     $format = $wgRequest->getVal( 'feed' );
     if (!$format) return true; 
 
-    $wgOut->disable();
-    //XXX: returning false currently doesn't stop the rest of Article::view to execute :(
-
-    $title = $article->getTitle();
     $format = strtolower( trim($format) );
 
+    $action = strtolower( trim( $wgRequest->getVal( 'action', 'view' ) ) );
+    if ($action != 'view' && $action != 'purge') return true;
+
     if ( !isset($wgFeedClasses[$format] ) ) {
+        wfDebug("$fname: unknown feed format: $format\n");
         wfHttpError(400, "Bad Request", "unknown feed format: " . $format); //TODO: better code & text
         return false;
     }
 
-    if (!$article->exists()) {
+    if (!$title->exists()) {
+        wfDebug("$fname: feed page not found: " . $title->getPrefixedDBKey() . "\n");
         wfHttpError(404, "Not Found", "feed page not found: " . $title->getPrefixedText()); //TODO: better text
         return false;
     }
 
-    $note = '';
+    wfDebug("$fname: handling feed request for " . $title->getPrefixedDBKey() . "\n");
 
-    //NOTE: do caching for anon users only, because of user-specific 
-    //      rendering of textual content
-    if ($wgUser->isAnon()) {
-        $cachekey = wfNewsCacheKey($title, $format);
-        $ocache = wfGetParserCacheStorage();
-        $e = $ocache ? $ocache->get( $cachekey ) : NULL;
-        $note .= ' anon;';
-    }
-    else {
-        $cachekey = NULL;
-        $ocache = NULL;
-        $e = NULL;
-        $note .= ' user;';
-    }
-
-    if ( $e ) {
-        $lastchange = wfTimestamp(TS_UNIX, NewsRenderer::getLastChangeTime());
-        if ($lastchange < $e['timestamp']) {
-            print $e['xml'] . "\n<!-- cached: $note -->\n";
-            return false; //done
-        }
-        else {
-            $note .= " stale: $lastchange >= {$e['timestamp']};";
-        }
-    }
-
-    global $wgParser; //evil global
-
-    if (!$wgParser->mOptions) { //XXX: ugly hack :(
-        $wgParser->mOptions = new ParserOptions; 
-        $wgParser->setOutputType( OT_HTML );
-        $wgParser->clearState();
-        $wgParser->mTitle = $title;
-    }
-
-    $renderer = NewsRenderer::newFromArticle( $article, $wgParser );
-    if (!$renderer) {
-        wfHttpError(404, "Bad Request", "no feed found on page: " . $title->getPrefixedText() ); //TODO: better code & text
-        return;
-    }
-
-    $description = ''; //TODO: grab from article content... but what? and how?
-    $ts = time();
-    $xml = $renderer->renderFeed( $format, $description );
-
-    $e = array( 'xml' => $xml, 'timestamp' => $ts );
-    if ($ocache) {
-        $ocache->set( $cachekey, $e, $ts + 24 * 60 * 60 ); //cache for max 24 hours; cached record is discarded when anything turns up in RC anyway.
-        $note .= ' updated;';
-    }
-
-    $wgOut->disable();
-    print $xml . "\n<!-- fresh: $note -->\n";
-    return false; //done
+    $article = new NewsFeedPage( $title, $format );
+    return false;
 }
 
-function wfNewsArticlePurge( &$article ) {
-    global $wgFeedClasses;
-
-    $ocache = wfGetParserCacheStorage();
-    if (!$ocache) return true;
-
-    $title = $article->getTitle();
-
-    foreach( $wgFeedClasses as $format => $class ) {
-        $cachekey = wfNewsCacheKey( $title, $format );
-        $ocache->delete( $cachekey );
-    }
-
-    return true;
-}
-
 function wfNewsSkinTemplateOutputPageBeforeExec( &$skin, &$tpl ) {
     $feeds = $tpl->data['feeds'];
     if (!$feeds) return true;
Index: trunk/extensions/News/NewsRenderer.php
===================================================================
--- trunk/extensions/News/NewsRenderer.php	(revision 21477)
+++ trunk/extensions/News/NewsRenderer.php	(revision 21478)
@@ -503,10 +503,11 @@
 				$article = new Article( $title, $row->rc_this_oldid );
 				$t = $article->getContent(); 
 
-				$params['content'] = NewsRenderer::sanitizeWikiText( $t );
 				//TODO: expand variables & templates first, so cut-off applies to effective content, 
 				//      and extension tags from templates are stripped properly
+				//      this doesn't work though: $t = $this->templateparser->preprocess( $t, $this->title, new ParserOptions() );
 				//TODO: avoid magic categories, interwiki-links, etc
+				$params['content'] = NewsRenderer::sanitizeWikiText( $t );
 
 				if ( stripos($templatetext, '{{{head}}}')!==false ) {
 					$params['head'] = NewsRenderer::extractHead( $params['content'], $title );
@@ -678,4 +679,127 @@
 	}
 }
 
+class NewsFeedPage extends Article {
+	var $mFeedFormat;
+
+	function __construct($title, $format) {
+		Article::__construct( $title );
+		$this->mFeedFormat = $format;
+	}
+
+	function getCacheKey( ) {
+		//global $wgLang;
+		//NOTE: per-language caching might be needed at some point.
+		//      right now, caching is done for anon users only 
+		//      (the content language might be set individually however, 
+		//      using an extension like LanguageSelector)
+		
+		return "@newsfeed:" . urlencode($this->mTitle->getPrefixedDBKey()) . '|' . urlencode($this->mFeedFormat);
+	}
+	
+	function view( $usecache = true ) {
+		global $wgUser, $wgOut;
+
+		$fname = 'NewsFeedPage::view';
+		wfDebug("$fname: start\n");
+
+		$note = '';	
+
+		$ims = @$_SERVER['HTTP_IF_MODIFIED_SINCE'];
+		
+		if ( $ims && $usecache ) {
+			$lastchange = wfTimestamp(TS_UNIX, NewsRenderer::getLastChangeTime());
+
+			wfDebug("$fname: checking cache-ok:  IMS $ims vs. changed $lastchange \n");
+			if ( $wgOut->checkLastModified( $lastchange ) ) {
+				wfDebug("$fname: HTTP cache ok, 304 header sent\n");
+				return; // done, 304 header sent.
+			}
+		}
+
+		//NOTE: do caching for anon users only, because of user-specific 
+		//      rendering of textual content
+		if ($wgUser->isAnon() && $usecache) {
+			$cachekey = $this->getCacheKey();
+			$ocache = wfGetParserCacheStorage();
+			$e = $ocache ? $ocache->get( $cachekey ) : NULL;
+			$note .= ' anon;';
+			wfDebug("$fname: " . ($e? "got cached" : "no cached") . "\n");
+		}
+		else {
+			if (!$usecache) {
+				wfDebug("$fname: purge, ignoring cache\n");
+				$note .= ' purged;';
+			}
+			else {
+				wfDebug("$fname: logged in, ignoring cache\n");
+				$note .= ' user;';
+			}
+			
+			$cachekey = NULL;
+			$ocache = NULL;
+			$e = NULL;
+			$note .= ' user;';
+		}
+		
+		$wgOut->disable();
+
+		if ( $e ) {
+			if (!isset($lastchange)) $lastchange = wfTimestamp(TS_UNIX, NewsRenderer::getLastChangeTime());
+			$last = wfTimestamp(TS_UNIX, $lastchange);
+
+			if ($last < $e['timestamp']) {
+				wfDebug("$fname: outputting cached copy ($cachekey): $last < {$e['timestamp']}\n");
+				print $e['xml'];
+				print "\n<!-- cached: $note -->\n";
+				return; //done
+			}
+			else {
+				wfDebug("$fname: found stale cache copy ($cachekey): $last >= {$e['timestamp']}\n");
+				$note .= " stale: $last >= {$e['timestamp']};";
+			}
+		}
+
+		//TODO: fetch actual news data and check the newest item. re-apply cache checks.
+		//      this would still save the cost of rendering if the data didn't change
+
+		global $wgParser; //evil global
+		
+		if (!$wgParser->mOptions) { //XXX: ugly hack :(
+			$wgParser->mOptions = new ParserOptions; 
+			$wgParser->setOutputType( OT_HTML );
+			$wgParser->clearState();
+			$wgParser->mTitle = $this->mTitle;
+		}
+		
+		$renderer = NewsRenderer::newFromArticle( $this, $wgParser );
+		if (!$renderer) {
+			wfDebug("$fname: no feed found on page: " . $this->mTitle->getPrefixedText() . "\n");
+			wfHttpError(404, "Not Found", "no feed found on page: " . $this->mTitle->getPrefixedText() ); //TODO: better code & text
+			return;
+		}
+		
+		$description = ''; //TODO: grab from article content... but what? and how?
+		$ts = time();
+		
+		//this also sends the right headers
+		$xml = $renderer->renderFeed( $this->mFeedFormat, $description );
+		wfDebug("$fname: rendered feed\n");
+	
+		$e = array( 'xml' => $xml, 'timestamp' => $ts );
+		if ($ocache) {
+			wfDebug("$fname: caching feed ($cachekey)\n");
+			$ocache->set( $cachekey, $e, $ts + 24 * 60 * 60 ); //cache for max 24 hours; cached record is discarded when anything turns up in RC anyway.
+			$note .= ' updated;';
+		}
+
+		wfDebug("$fname: outputting fresh feed\n");
+		print $xml;
+		print "\n<!-- fresh: $note -->\n";
+	}
+
+	function purge() {
+		$this->view( false );
+	}
+}
 ?>
\ No newline at end of file
Views
Toolbox