API * cache expiration control
authorYuri Astrakhan <yurik@users.mediawiki.org>
Sun, 22 Oct 2006 23:45:20 +0000 (23:45 +0000)
committerYuri Astrakhan <yurik@users.mediawiki.org>
Sun, 22 Oct 2006 23:45:20 +0000 (23:45 +0000)
* Added PHP-serialized & WDDX formats

includes/AutoLoader.php
includes/api/ApiFormatBase.php
includes/api/ApiFormatPhp.php [new file with mode: 0644]
includes/api/ApiFormatWddx.php [new file with mode: 0644]
includes/api/ApiMain.php
includes/api/ApiOpenSearch.php

index 3885128..b1525c5 100644 (file)
@@ -242,6 +242,8 @@ function __autoload($className) {
                'ApiFormatBase' => 'includes/api/ApiFormatBase.php',
                'Services_JSON' => 'includes/api/ApiFormatJson_json.php',
                'ApiFormatJson' => 'includes/api/ApiFormatJson.php',
+               'ApiFormatPhp' => 'includes/api/ApiFormatPhp.php',
+               'ApiFormatWddx' => 'includes/api/ApiFormatWddx.php',
                'ApiFormatXml' => 'includes/api/ApiFormatXml.php',
                'Spyc' => 'includes/api/ApiFormatYaml_spyc.php',
                'ApiFormatYaml' => 'includes/api/ApiFormatYaml.php',
index 013c075..1a415eb 100644 (file)
@@ -82,7 +82,6 @@ abstract class ApiFormatBase extends ApiBase {
                        return; // skip any initialization
 
                header("Content-Type: $mime; charset=utf-8;");
-               header("Cache-Control: private, s-maxage=0, max-age=0");
 
                if ($isHtml) {
 ?>
diff --git a/includes/api/ApiFormatPhp.php b/includes/api/ApiFormatPhp.php
new file mode 100644 (file)
index 0000000..0b0a820
--- /dev/null
@@ -0,0 +1,54 @@
+<?php
+
+
+/*
+ * Created on Oct 22, 2006
+ *
+ * API for MediaWiki 1.8+
+ *
+ * Copyright (C) 2006 Yuri Astrakhan <FirstnameLastname@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+if (!defined('MEDIAWIKI')) {
+       // Eclipse helper - will be ignored in production
+       require_once ('ApiFormatBase.php');
+}
+
+class ApiFormatPhp extends ApiFormatBase {
+
+       public function __construct($main, $format) {
+               parent :: __construct($main, $format);
+       }
+
+       public function getMimeType() {
+               return 'application/vnd.php.serialized';
+       }
+
+       public function execute() {
+               $this->printText(serialize($this->getResultData()));
+       }
+
+       protected function getDescription() {
+               return 'Output data in serialized PHP format';
+       }
+
+       public function getVersion() {
+               return __CLASS__ . ': $Id$';
+       }
+}
+?>
\ No newline at end of file
diff --git a/includes/api/ApiFormatWddx.php b/includes/api/ApiFormatWddx.php
new file mode 100644 (file)
index 0000000..a075626
--- /dev/null
@@ -0,0 +1,89 @@
+<?php
+
+
+/*
+ * Created on Oct 22, 2006
+ *
+ * API for MediaWiki 1.8+
+ *
+ * Copyright (C) 2006 Yuri Astrakhan <FirstnameLastname@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+if (!defined('MEDIAWIKI')) {
+       // Eclipse helper - will be ignored in production
+       require_once ('ApiFormatBase.php');
+}
+
+class ApiFormatWddx extends ApiFormatBase {
+
+       public function __construct($main, $format) {
+               parent :: __construct($main, $format);
+       }
+
+       public function getMimeType() {
+               return 'text/xml';
+       }
+
+       public function execute() {
+               if (function_exists('wddx_serialize_value')) {
+                       $this->printText(wddx_serialize_value($this->getResultData()));
+               } else {
+                       $this->printText('<?xml version="1.0" encoding="utf-8"?>');
+                       $this->printText('<wddxPacket version="1.0"><header/><data>');
+                       $this->slowWddxPrinter($this->getResultData());
+                       $this->printText('</data></wddxPacket>');
+               }
+       }
+
+       /**
+       * Recursivelly go through the object and output its data in WDDX format.
+       */
+       function slowWddxPrinter($elemValue) {
+               switch (gettype($elemValue)) {
+                       case 'array' :
+                               $this->printText('<struct>');
+                               foreach ($elemValue as $subElemName => $subElemValue) {
+                                       $this->printText(wfElement('var', array (
+                                               'name' => $subElemName
+                                       ), null));
+                                       $this->slowWddxPrinter($subElemValue);
+                                       $this->printText('</var>');
+                               }
+                               $this->printText('</struct>');
+                               break;
+                       case 'integer' :
+                       case 'double' :
+                               $this->printText(wfElement('number', null, $elemValue));
+                               break;
+                       case 'string' :
+                               $this->printText(wfElement('string', null, $elemValue));
+                               break;
+                       default :
+                               ApiBase :: dieDebug(__METHOD__, 'Unknown type ' . gettype($elemValue));
+               }
+       }
+
+       protected function getDescription() {
+               return 'Output data in WDDX format';
+       }
+
+       public function getVersion() {
+               return __CLASS__ . ': $Id$';
+       }
+}
+?>
\ No newline at end of file
index 078b0ad..12ad331 100644 (file)
@@ -29,7 +29,6 @@ if (!defined('MEDIAWIKI')) {
        require_once ('ApiBase.php');
 }
 
-
 /**
  * This is the main API class, used for both external and internal processing. 
  */
@@ -57,16 +56,20 @@ class ApiMain extends ApiBase {
        private static $Formats = array (
                'json' => 'ApiFormatJson',
                'jsonfm' => 'ApiFormatJson',
-               'raw' => 'ApiFormatJson',
-               'rawfm' => 'ApiFormatJson',
+               'php' => 'ApiFormatPhp',
+               'phpfm' => 'ApiFormatPhp',
+               'wddx' => 'ApiFormatWddx',
+               'wddxfm' => 'ApiFormatWddx',
                'xml' => 'ApiFormatXml',
                'xmlfm' => 'ApiFormatXml',
                'yaml' => 'ApiFormatYaml',
-               'yamlfm' => 'ApiFormatYaml'
+               'yamlfm' => 'ApiFormatYaml',
+               'raw' => 'ApiFormatJson',
+               'rawfm' => 'ApiFormatJson'
        );
 
        private $mPrinter, $mModules, $mModuleNames, $mFormats, $mFormatNames;
-       private $mResult, $mShowVersions, $mEnableWrite, $mRequest, $mInternalMode;
+       private $mResult, $mShowVersions, $mEnableWrite, $mRequest, $mInternalMode, $mSquidMaxage;
 
        /**
        * Constructor
@@ -77,18 +80,20 @@ class ApiMain extends ApiBase {
                // Special handling for the main module: $parent === $this
                parent :: __construct($this, 'main');
 
-               $this->mModules =& self::$Modules;
-               $this->mModuleNames = array_keys($this->mModules);      // todo: optimize
-               $this->mFormats =& self::$Formats;
-               $this->mFormatNames = array_keys($this->mFormats);      // todo: optimize
-               
+               $this->mModules = & self :: $Modules;
+               $this->mModuleNames = array_keys($this->mModules); // todo: optimize
+               $this->mFormats = & self :: $Formats;
+               $this->mFormatNames = array_keys($this->mFormats); // todo: optimize
+
                $this->mResult = new ApiResult($this);
                $this->mShowVersions = false;
                $this->mEnableWrite = $enableWrite;
-               
-               $this->mRequest =& $request;
+
+               $this->mRequest = & $request;
 
                $this->mInternalMode = ($request instanceof FauxRequest);
+
+               $this->mSquidMaxage = 0;
        }
 
        public function & getRequest() {
@@ -104,20 +109,24 @@ class ApiMain extends ApiBase {
                        $this->dieUsage('Editing of this site is disabled. Make sure the $wgEnableWriteAPI=true; ' .
                        'statement is included in the site\'s LocalSettings.php file', 'readonly');
        }
-       
+
+       public function setCacheMaxAge($maxage) {
+               $this->mSquidMaxage = $maxage;
+       }
+
        public function createPrinterByName($format) {
                return new $this->mFormats[$format] ($this, $format);
        }
 
        public function execute() {
                $this->profileIn();
-               if($this->mInternalMode)
+               if ($this->mInternalMode)
                        $this->executeAction();
                else
                        $this->executeActionWithErrorHandling();
                $this->profileOut();
        }
-       
+
        protected function executeActionWithErrorHandling() {
 
                // In case an error occurs during data output,
@@ -132,24 +141,25 @@ class ApiMain extends ApiBase {
                        // If this fails, an unhandled exception should be thrown so that global error
                        // handler will process and log it.
                        //
-                       
+
+                       // Error results should not be cached
+                       $this->setCacheMaxAge(0);
+
                        // Printer may not be initialized if the extractRequestParams() fails for the main module
                        if (!isset ($this->mPrinter)) {
                                $this->mPrinter = $this->createPrinterByName(self :: API_DEFAULT_FORMAT);
                                if ($this->mPrinter->getNeedsRawData())
                                        $this->getResult()->setRawMode();
                        }
-                       
+
                        if ($e instanceof UsageException) {
                                //
                                // User entered incorrect parameters - print usage screen
                                //
                                $errMessage = array (
-                                       'code' => $e->getCodeString(),
-                                       'info' => $e->getMessage()
-                               );
+                               'code' => $e->getCodeString(), 'info' => $e->getMessage());
                                ApiResult :: setContent($errMessage, $this->makeHelpMsg());
-               
+
                        } else {
                                //
                                // Something is seriously wrong
@@ -160,7 +170,7 @@ class ApiMain extends ApiBase {
                                );
                                ApiResult :: setContent($errMessage, "\n\n{$e->getTraceAsString()}\n\n");
                        }
-                       
+
                        $headerStr = 'MediaWiki-API-Error: ' . $errMessage['code'];
                        if ($e->getCode() === 0)
                                header($headerStr, true);
@@ -176,7 +186,13 @@ class ApiMain extends ApiBase {
                        $this->mPrinter->safeProfileOut();
                        $this->printResult(true);
                }
-               
+
+               // Set the cache expiration at the last moment, as any errors may change the expiration.
+               // if $this->mSquidMaxage == 0, the expiry time is set to the first second of unix epoch
+               $expires = $this->mSquidMaxage == 0 ? 1 : time() + $this->mSquidMaxage;
+               header('Expires: ' . wfTimestamp(TS_RFC2822, $expires));
+               header('Cache-Control: s-maxage=' . $this->mSquidMaxage . ', must-revalidate, max-age=0');
+
                ob_end_flush();
        }
 
@@ -192,29 +208,29 @@ class ApiMain extends ApiBase {
                $module = new $this->mModules[$action] ($this, $action);
 
                if (!$this->mInternalMode) {
-                       
+
                        // See if custom printer is used
-                       $this->mPrinter = $module->getCustomPrinter();                          
+                       $this->mPrinter = $module->getCustomPrinter();
                        if (is_null($this->mPrinter)) {
                                // Create an appropriate printer
                                $this->mPrinter = $this->createPrinterByName($format);
                        }
-                       
+
                        if ($this->mPrinter->getNeedsRawData())
                                $this->getResult()->setRawMode();
                }
-               
+
                // Execute
                $module->profileIn();
                $module->execute();
                $module->profileOut();
-               
+
                if (!$this->mInternalMode) {
                        // Print result data
                        $this->printResult(false);
                }
        }
-       
+
        /**
         * Internal printer
         */
@@ -309,7 +325,7 @@ class ApiMain extends ApiBase {
                $vers[] = ApiBase :: getBaseVersion();
                $vers[] = ApiFormatBase :: getBaseVersion();
                $vers[] = ApiQueryBase :: getBaseVersion();
-               $vers[] = ApiFormatFeedWrapper :: getVersion(); // not accessible with format=xxx
+               $vers[] = ApiFormatFeedWrapper :: getVersion(); // not accessible with format=xxx
                return $vers;
        }
 }
index 9e5afcb..50b8e9c 100644 (file)
@@ -43,6 +43,9 @@ class ApiOpenSearch extends ApiBase {
                $search = null;
                extract($this->ExtractRequestParams());
 
+               // Open search results may be stored for a very long time
+               $this->getMain()->setCacheMaxAge(1200);
+
                $title = Title :: newFromText($search);
                if(!$title)
                        return; // Return empty result