MediaWiki  REL1_24
RawAction.php
Go to the documentation of this file.
00001 <?php
00035 class RawAction extends FormlessAction {
00042     private $gen = false;
00043 
00044     public function getName() {
00045         return 'raw';
00046     }
00047 
00048     public function requiresWrite() {
00049         return false;
00050     }
00051 
00052     public function requiresUnblock() {
00053         return false;
00054     }
00055 
00056     function onView() {
00057         $this->getOutput()->disable();
00058         $request = $this->getRequest();
00059         $config = $this->context->getConfig();
00060 
00061         if ( !$request->checkUrlExtension() ) {
00062             return;
00063         }
00064 
00065         if ( $this->getOutput()->checkLastModified( $this->page->getTouched() ) ) {
00066             return; // Client cache fresh and headers sent, nothing more to do.
00067         }
00068 
00069         # special case for 'generated' raw things: user css/js
00070         # This is deprecated and will only return empty content
00071         $gen = $request->getVal( 'gen' );
00072         $smaxage = $request->getIntOrNull( 'smaxage' );
00073 
00074         if ( $gen == 'css' || $gen == 'js' ) {
00075             $this->gen = true;
00076             if ( $smaxage === null ) {
00077                 $smaxage = $config->get( 'SquidMaxage' );
00078             }
00079         }
00080 
00081         $contentType = $this->getContentType();
00082 
00083         # Force caching for CSS and JS raw content, default: 5 minutes.
00084         # Note: If using a canonical url for userpage css/js, we send an HTCP purge.
00085         if ( $smaxage === null ) {
00086             if ( $contentType == 'text/css' || $contentType == 'text/javascript' ) {
00087                 $smaxage = intval( $config->get( 'ForcedRawSMaxage' ) );
00088             } else {
00089                 $smaxage = 0;
00090             }
00091         }
00092 
00093         $maxage = $request->getInt( 'maxage', $config->get( 'SquidMaxage' ) );
00094 
00095         $response = $request->response();
00096 
00097         $response->header( 'Content-type: ' . $contentType . '; charset=UTF-8' );
00098         # Output may contain user-specific data;
00099         # vary generated content for open sessions on private wikis
00100         $privateCache = !User::isEveryoneAllowed( 'read' ) && ( $smaxage == 0 || session_id() != '' );
00101         // Bug 53032 - make this private if user is logged in,
00102         // so we don't accidentally cache cookies
00103         $privateCache = $privateCache ?: $this->getUser()->isLoggedIn();
00104         # allow the client to cache this for 24 hours
00105         $mode = $privateCache ? 'private' : 'public';
00106         $response->header(
00107             'Cache-Control: ' . $mode . ', s-maxage=' . $smaxage . ', max-age=' . $maxage
00108         );
00109 
00110         $text = $this->getRawText();
00111 
00112         if ( $text === false && $contentType == 'text/x-wiki' ) {
00113             # Don't return a 404 response for CSS or JavaScript;
00114             # 404s aren't generally cached and it would create
00115             # extra hits when user CSS/JS are on and the user doesn't
00116             # have the pages.
00117             $response->header( 'HTTP/1.x 404 Not Found' );
00118         }
00119 
00120         if ( !wfRunHooks( 'RawPageViewBeforeOutput', array( &$this, &$text ) ) ) {
00121             wfDebug( __METHOD__ . ": RawPageViewBeforeOutput hook broke raw page output.\n" );
00122         }
00123 
00124         echo $text;
00125     }
00126 
00133     public function getRawText() {
00134         global $wgParser;
00135 
00136         # No longer used
00137         if ( $this->gen ) {
00138             return '';
00139         }
00140 
00141         $text = false;
00142         $title = $this->getTitle();
00143         $request = $this->getRequest();
00144 
00145         // If it's a MediaWiki message we can just hit the message cache
00146         if ( $request->getBool( 'usemsgcache' ) && $title->getNamespace() == NS_MEDIAWIKI ) {
00147             // The first "true" is to use the database, the second is to use
00148             // the content langue and the last one is to specify the message
00149             // key already contains the language in it ("/de", etc.).
00150             $text = MessageCache::singleton()->get( $title->getDBkey(), true, true, true );
00151             // If the message doesn't exist, return a blank
00152             if ( $text === false ) {
00153                 $text = '';
00154             }
00155         } else {
00156             // Get it from the DB
00157             $rev = Revision::newFromTitle( $title, $this->getOldId() );
00158             if ( $rev ) {
00159                 $lastmod = wfTimestamp( TS_RFC2822, $rev->getTimestamp() );
00160                 $request->response()->header( "Last-modified: $lastmod" );
00161 
00162                 // Public-only due to cache headers
00163                 $content = $rev->getContent();
00164 
00165                 if ( $content === null ) {
00166                     // revision not found (or suppressed)
00167                     $text = false;
00168                 } elseif ( !$content instanceof TextContent ) {
00169                     // non-text content
00170                     wfHttpError( 415, "Unsupported Media Type", "The requested page uses the content model `"
00171                         . $content->getModel() . "` which is not supported via this interface." );
00172                     die();
00173                 } else {
00174                     // want a section?
00175                     $section = $request->getIntOrNull( 'section' );
00176                     if ( $section !== null ) {
00177                         $content = $content->getSection( $section );
00178                     }
00179 
00180                     if ( $content === null || $content === false ) {
00181                         // section not found (or section not supported, e.g. for JS and CSS)
00182                         $text = false;
00183                     } else {
00184                         $text = $content->getNativeData();
00185                     }
00186                 }
00187             }
00188         }
00189 
00190         if ( $text !== false && $text !== '' && $request->getVal( 'templates' ) === 'expand' ) {
00191             $text = $wgParser->preprocess(
00192                 $text,
00193                 $title,
00194                 ParserOptions::newFromContext( $this->getContext() )
00195             );
00196         }
00197 
00198         return $text;
00199     }
00200 
00206     public function getOldId() {
00207         $oldid = $this->getRequest()->getInt( 'oldid' );
00208         switch ( $this->getRequest()->getText( 'direction' ) ) {
00209             case 'next':
00210                 # output next revision, or nothing if there isn't one
00211                 $nextid = 0;
00212                 if ( $oldid ) {
00213                     $nextid = $this->getTitle()->getNextRevisionID( $oldid );
00214                 }
00215                 $oldid = $nextid ?: -1;
00216                 break;
00217             case 'prev':
00218                 # output previous revision, or nothing if there isn't one
00219                 if ( !$oldid ) {
00220                     # get the current revision so we can get the penultimate one
00221                     $oldid = $this->page->getLatest();
00222                 }
00223                 $previd = $this->getTitle()->getPreviousRevisionID( $oldid );
00224                 $oldid = $previd ?: -1;
00225                 break;
00226             case 'cur':
00227                 $oldid = 0;
00228                 break;
00229         }
00230 
00231         return $oldid;
00232     }
00233 
00239     public function getContentType() {
00240         $ctype = $this->getRequest()->getVal( 'ctype' );
00241 
00242         if ( $ctype == '' ) {
00243             $gen = $this->getRequest()->getVal( 'gen' );
00244             if ( $gen == 'js' ) {
00245                 $ctype = 'text/javascript';
00246             } elseif ( $gen == 'css' ) {
00247                 $ctype = 'text/css';
00248             }
00249         }
00250 
00251         $allowedCTypes = array( 'text/x-wiki', 'text/javascript', 'text/css', 'application/x-zope-edit' );
00252         if ( $ctype == '' || !in_array( $ctype, $allowedCTypes ) ) {
00253             $ctype = 'text/x-wiki';
00254         }
00255 
00256         return $ctype;
00257     }
00258 }