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