[ Index ]

PHP Cross Reference of MediaWiki-1.24.0

title

Body

[close]

/includes/libs/virtualrest/ -> SwiftVirtualRESTService.php (source)

   1  <?php
   2  /**
   3   * Virtual HTTP service client for Swift
   4   *
   5   * This program is free software; you can redistribute it and/or modify
   6   * it under the terms of the GNU General Public License as published by
   7   * the Free Software Foundation; either version 2 of the License, or
   8   * (at your option) any later version.
   9   *
  10   * This program is distributed in the hope that it will be useful,
  11   * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13   * GNU General Public License for more details.
  14   *
  15   * You should have received a copy of the GNU General Public License along
  16   * with this program; if not, write to the Free Software Foundation, Inc.,
  17   * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  18   * http://www.gnu.org/copyleft/gpl.html
  19   *
  20   * @file
  21   */
  22  
  23  /**
  24   * Example virtual rest service for OpenStack Swift
  25   * @TODO: caching support (APC/memcached)
  26   * @since 1.23
  27   */
  28  class SwiftVirtualRESTService extends VirtualRESTService {
  29      /** @var array */
  30      protected $authCreds;
  31      /** @var int UNIX timestamp */
  32      protected $authSessionTimestamp = 0;
  33      /** @var int UNIX timestamp */
  34      protected $authErrorTimestamp = null;
  35      /** @var int */
  36      protected $authCachedStatus = null;
  37      /** @var string */
  38      protected $authCachedReason = null;
  39  
  40      /**
  41       * @param array $params Key/value map
  42       *   - swiftAuthUrl       : Swift authentication server URL
  43       *   - swiftUser          : Swift user used by MediaWiki (account:username)
  44       *   - swiftKey           : Swift authentication key for the above user
  45       *   - swiftAuthTTL       : Swift authentication TTL (seconds)
  46       */
  47  	public function __construct( array $params ) {
  48          parent::__construct( $params );
  49      }
  50  
  51      /**
  52       * @return int|bool HTTP status on cached failure
  53       */
  54  	protected function needsAuthRequest() {
  55          if ( !$this->authCreds ) {
  56              return true;
  57          }
  58          if ( $this->authErrorTimestamp !== null ) {
  59              if ( ( time() - $this->authErrorTimestamp ) < 60 ) {
  60                  return $this->authCachedStatus; // failed last attempt; don't bother
  61              } else { // actually retry this time
  62                  $this->authErrorTimestamp = null;
  63              }
  64          }
  65          // Session keys expire after a while, so we renew them periodically
  66          return ( ( time() - $this->authSessionTimestamp ) > $this->params['swiftAuthTTL'] );
  67      }
  68  
  69  	protected function applyAuthResponse( array $req ) {
  70          $this->authSessionTimestamp = 0;
  71          list( $rcode, $rdesc, $rhdrs, $rbody, $rerr ) = $req['response'];
  72          if ( $rcode >= 200 && $rcode <= 299 ) { // OK
  73              $this->authCreds = array(
  74                  'auth_token'  => $rhdrs['x-auth-token'],
  75                  'storage_url' => $rhdrs['x-storage-url']
  76              );
  77              $this->authSessionTimestamp = time();
  78              return true;
  79          } elseif ( $rcode === 403 ) {
  80              $this->authCachedStatus = 401;
  81              $this->authCachedReason = 'Authorization Required';
  82              $this->authErrorTimestamp = time();
  83              return false;
  84          } else {
  85              $this->authCachedStatus = $rcode;
  86              $this->authCachedReason = $rdesc;
  87              $this->authErrorTimestamp = time();
  88              return null;
  89          }
  90      }
  91  
  92  	public function onRequests( array $reqs, Closure $idGeneratorFunc ) {
  93          $result = array();
  94          $firstReq = reset( $reqs );
  95          if ( $firstReq && count( $reqs ) == 1 && isset( $firstReq['isAuth'] ) ) {
  96              // This was an authentication request for work requests...
  97              $result = $reqs; // no change
  98          } else {
  99              // These are actual work requests...
 100              $needsAuth = $this->needsAuthRequest();
 101              if ( $needsAuth === true ) {
 102                  // These are work requests and we don't have any token to use.
 103                  // Replace the work requests with an authentication request.
 104                  $result = array(
 105                      $idGeneratorFunc() => array(
 106                          'method'  => 'GET',
 107                          'url'     => $this->params['swiftAuthUrl'] . "/v1.0",
 108                          'headers' => array(
 109                              'x-auth-user' => $this->params['swiftUser'],
 110                              'x-auth-key'  => $this->params['swiftKey'] ),
 111                          'isAuth'  => true,
 112                          'chain'   => $reqs
 113                      )
 114                  );
 115              } elseif ( $needsAuth !== false ) {
 116                  // These are work requests and authentication has previously failed.
 117                  // It is most efficient to just give failed pseudo responses back for
 118                  // the original work requests.
 119                  foreach ( $reqs as $key => $req ) {
 120                      $req['response'] = array(
 121                          'code'     => $this->authCachedStatus,
 122                          'reason'   => $this->authCachedReason,
 123                          'headers'  => array(),
 124                          'body'     => '',
 125                          'error'    => ''
 126                      );
 127                      $result[$key] = $req;
 128                  }
 129              } else {
 130                  // These are work requests and we have a token already.
 131                  // Go through and mangle each request to include a token.
 132                  foreach ( $reqs as $key => $req ) {
 133                      // The default encoding treats the URL as a REST style path that uses
 134                      // forward slash as a hierarchical delimiter (and never otherwise).
 135                      // Subclasses can override this, and should be documented in any case.
 136                      $parts = array_map( 'rawurlencode', explode( '/', $req['url'] ) );
 137                      $req['url'] = $this->authCreds['storage_url'] . '/' . implode( '/', $parts );
 138                      $req['headers']['x-auth-token'] = $this->authCreds['auth_token'];
 139                      $result[$key] = $req;
 140                      // @TODO: add ETag/Content-Length and such as needed
 141                  }
 142              }
 143          }
 144          return $result;
 145      }
 146  
 147  	public function onResponses( array $reqs, Closure $idGeneratorFunc ) {
 148          $firstReq = reset( $reqs );
 149          if ( $firstReq && count( $reqs ) == 1 && isset( $firstReq['isAuth'] ) ) {
 150              $result = array();
 151              // This was an authentication request for work requests...
 152              if ( $this->applyAuthResponse( $firstReq ) ) {
 153                  // If it succeeded, we can subsitute the work requests back.
 154                  // Call this recursively in order to munge and add headers.
 155                  $result = $this->onRequests( $firstReq['chain'], $idGeneratorFunc );
 156              } else {
 157                  // If it failed, it is most efficient to just give failing
 158                  // pseudo-responses back for the actual work requests.
 159                  foreach ( $firstReq['chain'] as $key => $req ) {
 160                      $req['response'] = array(
 161                          'code'     => $this->authCachedStatus,
 162                          'reason'   => $this->authCachedReason,
 163                          'headers'  => array(),
 164                          'body'     => '',
 165                          'error'    => ''
 166                      );
 167                      $result[$key] = $req;
 168                  }
 169              }
 170          } else {
 171              $result = $reqs; // no change
 172          }
 173          return $result;
 174      }
 175  }


Generated: Fri Nov 28 14:03:12 2014 Cross-referenced by PHPXref 0.7.1