MediaWiki
REL1_24
|
00001 <?php 00028 class SwiftVirtualRESTService extends VirtualRESTService { 00030 protected $authCreds; 00032 protected $authSessionTimestamp = 0; 00034 protected $authErrorTimestamp = null; 00036 protected $authCachedStatus = null; 00038 protected $authCachedReason = null; 00039 00047 public function __construct( array $params ) { 00048 parent::__construct( $params ); 00049 } 00050 00054 protected function needsAuthRequest() { 00055 if ( !$this->authCreds ) { 00056 return true; 00057 } 00058 if ( $this->authErrorTimestamp !== null ) { 00059 if ( ( time() - $this->authErrorTimestamp ) < 60 ) { 00060 return $this->authCachedStatus; // failed last attempt; don't bother 00061 } else { // actually retry this time 00062 $this->authErrorTimestamp = null; 00063 } 00064 } 00065 // Session keys expire after a while, so we renew them periodically 00066 return ( ( time() - $this->authSessionTimestamp ) > $this->params['swiftAuthTTL'] ); 00067 } 00068 00069 protected function applyAuthResponse( array $req ) { 00070 $this->authSessionTimestamp = 0; 00071 list( $rcode, $rdesc, $rhdrs, $rbody, $rerr ) = $req['response']; 00072 if ( $rcode >= 200 && $rcode <= 299 ) { // OK 00073 $this->authCreds = array( 00074 'auth_token' => $rhdrs['x-auth-token'], 00075 'storage_url' => $rhdrs['x-storage-url'] 00076 ); 00077 $this->authSessionTimestamp = time(); 00078 return true; 00079 } elseif ( $rcode === 403 ) { 00080 $this->authCachedStatus = 401; 00081 $this->authCachedReason = 'Authorization Required'; 00082 $this->authErrorTimestamp = time(); 00083 return false; 00084 } else { 00085 $this->authCachedStatus = $rcode; 00086 $this->authCachedReason = $rdesc; 00087 $this->authErrorTimestamp = time(); 00088 return null; 00089 } 00090 } 00091 00092 public function onRequests( array $reqs, Closure $idGeneratorFunc ) { 00093 $result = array(); 00094 $firstReq = reset( $reqs ); 00095 if ( $firstReq && count( $reqs ) == 1 && isset( $firstReq['isAuth'] ) ) { 00096 // This was an authentication request for work requests... 00097 $result = $reqs; // no change 00098 } else { 00099 // These are actual work requests... 00100 $needsAuth = $this->needsAuthRequest(); 00101 if ( $needsAuth === true ) { 00102 // These are work requests and we don't have any token to use. 00103 // Replace the work requests with an authentication request. 00104 $result = array( 00105 $idGeneratorFunc() => array( 00106 'method' => 'GET', 00107 'url' => $this->params['swiftAuthUrl'] . "/v1.0", 00108 'headers' => array( 00109 'x-auth-user' => $this->params['swiftUser'], 00110 'x-auth-key' => $this->params['swiftKey'] ), 00111 'isAuth' => true, 00112 'chain' => $reqs 00113 ) 00114 ); 00115 } elseif ( $needsAuth !== false ) { 00116 // These are work requests and authentication has previously failed. 00117 // It is most efficient to just give failed pseudo responses back for 00118 // the original work requests. 00119 foreach ( $reqs as $key => $req ) { 00120 $req['response'] = array( 00121 'code' => $this->authCachedStatus, 00122 'reason' => $this->authCachedReason, 00123 'headers' => array(), 00124 'body' => '', 00125 'error' => '' 00126 ); 00127 $result[$key] = $req; 00128 } 00129 } else { 00130 // These are work requests and we have a token already. 00131 // Go through and mangle each request to include a token. 00132 foreach ( $reqs as $key => $req ) { 00133 // The default encoding treats the URL as a REST style path that uses 00134 // forward slash as a hierarchical delimiter (and never otherwise). 00135 // Subclasses can override this, and should be documented in any case. 00136 $parts = array_map( 'rawurlencode', explode( '/', $req['url'] ) ); 00137 $req['url'] = $this->authCreds['storage_url'] . '/' . implode( '/', $parts ); 00138 $req['headers']['x-auth-token'] = $this->authCreds['auth_token']; 00139 $result[$key] = $req; 00140 // @TODO: add ETag/Content-Length and such as needed 00141 } 00142 } 00143 } 00144 return $result; 00145 } 00146 00147 public function onResponses( array $reqs, Closure $idGeneratorFunc ) { 00148 $firstReq = reset( $reqs ); 00149 if ( $firstReq && count( $reqs ) == 1 && isset( $firstReq['isAuth'] ) ) { 00150 $result = array(); 00151 // This was an authentication request for work requests... 00152 if ( $this->applyAuthResponse( $firstReq ) ) { 00153 // If it succeeded, we can subsitute the work requests back. 00154 // Call this recursively in order to munge and add headers. 00155 $result = $this->onRequests( $firstReq['chain'], $idGeneratorFunc ); 00156 } else { 00157 // If it failed, it is most efficient to just give failing 00158 // pseudo-responses back for the actual work requests. 00159 foreach ( $firstReq['chain'] as $key => $req ) { 00160 $req['response'] = array( 00161 'code' => $this->authCachedStatus, 00162 'reason' => $this->authCachedReason, 00163 'headers' => array(), 00164 'body' => '', 00165 'error' => '' 00166 ); 00167 $result[$key] = $req; 00168 } 00169 } 00170 } else { 00171 $result = $reqs; // no change 00172 } 00173 return $result; 00174 } 00175 }