MediaWiki 1.41.2
SwiftVirtualRESTService.php
Go to the documentation of this file.
1<?php
31 protected $authCreds;
33 protected $authSessionTimestamp = 0;
35 protected $authErrorTimestamp = null;
37 protected $authCachedStatus = null;
39 protected $authCachedReason = null;
40
48 public function __construct( array $params ) {
49 wfDeprecated( __METHOD__, '1.41' );
50 // set up defaults and merge them with the given params
51 $mparams = array_merge( [
52 'name' => 'swift'
53 ], $params );
54 parent::__construct( $mparams );
55 }
56
60 protected function needsAuthRequest() {
61 if ( !$this->authCreds ) {
62 return true;
63 }
64 if ( $this->authErrorTimestamp !== null ) {
65 if ( ( time() - $this->authErrorTimestamp ) < 60 ) {
66 return $this->authCachedStatus; // failed last attempt; don't bother
67 } else { // actually retry this time
68 $this->authErrorTimestamp = null;
69 }
70 }
71 // Session keys expire after a while, so we renew them periodically
72 return ( ( time() - $this->authSessionTimestamp ) > $this->params['swiftAuthTTL'] );
73 }
74
75 protected function applyAuthResponse( array $req ) {
76 $this->authSessionTimestamp = 0;
77 [ $rcode, $rdesc, $rhdrs, , ] = $req['response'];
78 if ( $rcode >= 200 && $rcode <= 299 ) { // OK
79 $this->authCreds = [
80 'auth_token' => $rhdrs['x-auth-token'],
81 'storage_url' => $rhdrs['x-storage-url']
82 ];
83 $this->authSessionTimestamp = time();
84 return true;
85 } elseif ( $rcode === 403 ) {
86 $this->authCachedStatus = 401;
87 $this->authCachedReason = 'Authorization Required';
88 $this->authErrorTimestamp = time();
89 return false;
90 } else {
91 $this->authCachedStatus = $rcode;
92 $this->authCachedReason = $rdesc;
93 $this->authErrorTimestamp = time();
94 return null;
95 }
96 }
97
102 public function onRequests( array $reqs, Closure $idGeneratorFunc ) {
103 $result = [];
104 $firstReq = reset( $reqs );
105 if ( $firstReq && count( $reqs ) == 1 && isset( $firstReq['isAuth'] ) ) {
106 // This was an authentication request for work requests...
107 $result = $reqs; // no change
108 } else {
109 // These are actual work requests...
110 $needsAuth = $this->needsAuthRequest();
111 if ( $needsAuth === true ) {
112 // These are work requests and we don't have any token to use.
113 // Replace the work requests with an authentication request.
114 $result = [
115 $idGeneratorFunc() => [
116 'method' => 'GET',
117 'url' => $this->params['swiftAuthUrl'] . "/v1.0",
118 'headers' => [
119 'x-auth-user' => $this->params['swiftUser'],
120 'x-auth-key' => $this->params['swiftKey'] ],
121 'isAuth' => true,
122 'chain' => $reqs
123 ]
124 ];
125 } elseif ( $needsAuth !== false ) {
126 // These are work requests and authentication has previously failed.
127 // It is most efficient to just give failed pseudo responses back for
128 // the original work requests.
129 foreach ( $reqs as $key => $req ) {
130 $req['response'] = [
131 'code' => $this->authCachedStatus,
132 'reason' => $this->authCachedReason,
133 'headers' => [],
134 'body' => '',
135 'error' => ''
136 ];
137 $result[$key] = $req;
138 }
139 } else {
140 // These are work requests and we have a token already.
141 // Go through and mangle each request to include a token.
142 foreach ( $reqs as $key => $req ) {
143 // The default encoding treats the URL as a REST style path that uses
144 // forward slash as a hierarchical delimiter (and never otherwise).
145 // Subclasses can override this, and should be documented in any case.
146 $parts = array_map( 'rawurlencode', explode( '/', $req['url'] ) );
147 $req['url'] = $this->authCreds['storage_url'] . '/' . implode( '/', $parts );
148 $req['headers']['x-auth-token'] = $this->authCreds['auth_token'];
149 $result[$key] = $req;
150 // @TODO: add ETag/Content-Length and such as needed
151 }
152 }
153 }
154 return $result;
155 }
156
157 public function onResponses( array $reqs, Closure $idGeneratorFunc ) {
158 $firstReq = reset( $reqs );
159 if ( $firstReq && count( $reqs ) == 1 && isset( $firstReq['isAuth'] ) ) {
160 $result = [];
161 // This was an authentication request for work requests...
162 if ( $this->applyAuthResponse( $firstReq ) ) {
163 // If it succeeded, we can substitute the work requests back.
164 // Call this recursively in order to munge and add headers.
165 $result = $this->onRequests( $firstReq['chain'], $idGeneratorFunc );
166 } else {
167 // If it failed, it is most efficient to just give failing
168 // pseudo-responses back for the actual work requests.
169 foreach ( $firstReq['chain'] as $key => $req ) {
170 $req['response'] = [
171 'code' => $this->authCachedStatus,
172 'reason' => $this->authCachedReason,
173 'headers' => [],
174 'body' => '',
175 'error' => ''
176 ];
177 $result[$key] = $req;
178 }
179 }
180 } else {
181 $result = $reqs; // no change
182 }
183 return $result;
184 }
185}
wfDeprecated( $function, $version=false, $component=false, $callerOffset=2)
Logs a warning that a deprecated feature was used.
Example virtual rest service for OpenStack Swift.
onResponses(array $reqs, Closure $idGeneratorFunc)
Mangle or replace virtual HTTP(S) requests which have been responded to.
int $authSessionTimestamp
UNIX timestamp.
onRequests(array $reqs, Closure $idGeneratorFunc)
Prepare virtual HTTP(S) requests (for this service) for execution.This method should mangle any of th...
int null $authErrorTimestamp
UNIX timestamp.
Virtual HTTP service instance that can be mounted on to a VirtualRESTService.
array $params
Key/value map.