PluginProbe
Authorizer / 2.6.17
Authorizer v2.6.17
3.15.3 3.15.2 3.15.1 3.15.0 3.14.3 3.14.4 3.14.2 3.14.1 2.8.1 2.8.2 2.8.3 2.8.4 2.8.5 2.8.6 2.8.7 2.8.8 2.9.0 2.9.1 2.9.10 2.9.11 2.9.12 2.9.13 2.9.2 2.9.3 2.9.6 All 126 releases
authorizer / vendor / google-api-php-client / src / Google / IO / Abstract.php

Abstract.php in Authorizer 2.6.17, at vendor/google-api-php-client/src/Google/IO/Abstract.php

340 lines 10.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /*
3 * Copyright 2013 Google Inc.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18 /**
19 * Abstract IO base class
20 */
21
22 if (!class_exists('Google_Client')) {
23 require_once dirname(__FILE__) . '/../autoload.php';
24 }
25
26 abstract class Google_IO_Abstract
27 {
28 const UNKNOWN_CODE = 0;
29 const FORM_URLENCODED = 'application/x-www-form-urlencoded';
30 private static $CONNECTION_ESTABLISHED_HEADERS = array(
31 "HTTP/1.0 200 Connection established\r\n\r\n",
32 "HTTP/1.1 200 Connection established\r\n\r\n",
33 );
34 private static $ENTITY_HTTP_METHODS = array("POST" => null, "PUT" => null);
35 private static $HOP_BY_HOP = array(
36 'connection' => true,
37 'keep-alive' => true,
38 'proxy-authenticate' => true,
39 'proxy-authorization' => true,
40 'te' => true,
41 'trailers' => true,
42 'transfer-encoding' => true,
43 'upgrade' => true
44 );
45
46
47 /** @var Google_Client */
48 protected $client;
49
50 public function __construct(Google_Client $client)
51 {
52 $this->client = $client;
53 $timeout = $client->getClassConfig('Google_IO_Abstract', 'request_timeout_seconds');
54 if ($timeout > 0) {
55 $this->setTimeout($timeout);
56 }
57 }
58
59 /**
60 * Executes a Google_Http_Request
61 * @param Google_Http_Request $request the http request to be executed
62 * @return array containing response headers, body, and http code
63 * @throws Google_IO_Exception on curl or IO error
64 */
65 abstract public function executeRequest(Google_Http_Request $request);
66
67 /**
68 * Set options that update the transport implementation's behavior.
69 * @param $options
70 */
71 abstract public function setOptions($options);
72
73 /**
74 * Set the maximum request time in seconds.
75 * @param $timeout in seconds
76 */
77 abstract public function setTimeout($timeout);
78
79 /**
80 * Get the maximum request time in seconds.
81 * @return timeout in seconds
82 */
83 abstract public function getTimeout();
84
85 /**
86 * Test for the presence of a cURL header processing bug
87 *
88 * The cURL bug was present in versions prior to 7.30.0 and caused the header
89 * length to be miscalculated when a "Connection established" header added by
90 * some proxies was present.
91 *
92 * @return boolean
93 */
94 abstract protected function needsQuirk();
95
96 /**
97 * @visible for testing.
98 * Cache the response to an HTTP request if it is cacheable.
99 * @param Google_Http_Request $request
100 * @return bool Returns true if the insertion was successful.
101 * Otherwise, return false.
102 */
103 public function setCachedRequest(Google_Http_Request $request)
104 {
105 // Determine if the request is cacheable.
106 if (Google_Http_CacheParser::isResponseCacheable($request)) {
107 $this->client->getCache()->set($request->getCacheKey(), $request);
108 return true;
109 }
110
111 return false;
112 }
113
114 /**
115 * Execute an HTTP Request
116 *
117 * @param Google_Http_Request $request the http request to be executed
118 * @return Google_Http_Request http request with the response http code,
119 * response headers and response body filled in
120 * @throws Google_IO_Exception on curl or IO error
121 */
122 public function makeRequest(Google_Http_Request $request)
123 {
124 // First, check to see if we have a valid cached version.
125 $cached = $this->getCachedRequest($request);
126 if ($cached !== false && $cached instanceof Google_Http_Request) {
127 if (!$this->checkMustRevalidateCachedRequest($cached, $request)) {
128 return $cached;
129 }
130 }
131
132 if (array_key_exists($request->getRequestMethod(), self::$ENTITY_HTTP_METHODS)) {
133 $request = $this->processEntityRequest($request);
134 }
135
136 list($responseData, $responseHeaders, $respHttpCode) = $this->executeRequest($request);
137
138 if ($respHttpCode == 304 && $cached) {
139 // If the server responded NOT_MODIFIED, return the cached request.
140 $this->updateCachedRequest($cached, $responseHeaders);
141 return $cached;
142 }
143
144 if (!isset($responseHeaders['Date']) && !isset($responseHeaders['date'])) {
145 $responseHeaders['date'] = date("r");
146 }
147
148 $request->setResponseHttpCode($respHttpCode);
149 $request->setResponseHeaders($responseHeaders);
150 $request->setResponseBody($responseData);
151 // Store the request in cache (the function checks to see if the request
152 // can actually be cached)
153 $this->setCachedRequest($request);
154 return $request;
155 }
156
157 /**
158 * @visible for testing.
159 * @param Google_Http_Request $request
160 * @return Google_Http_Request|bool Returns the cached object or
161 * false if the operation was unsuccessful.
162 */
163 public function getCachedRequest(Google_Http_Request $request)
164 {
165 if (false === Google_Http_CacheParser::isRequestCacheable($request)) {
166 return false;
167 }
168
169 return $this->client->getCache()->get($request->getCacheKey());
170 }
171
172 /**
173 * @visible for testing
174 * Process an http request that contains an enclosed entity.
175 * @param Google_Http_Request $request
176 * @return Google_Http_Request Processed request with the enclosed entity.
177 */
178 public function processEntityRequest(Google_Http_Request $request)
179 {
180 $postBody = $request->getPostBody();
181 $contentType = $request->getRequestHeader("content-type");
182
183 // Set the default content-type as application/x-www-form-urlencoded.
184 if (false == $contentType) {
185 $contentType = self::FORM_URLENCODED;
186 $request->setRequestHeaders(array('content-type' => $contentType));
187 }
188
189 // Force the payload to match the content-type asserted in the header.
190 if ($contentType == self::FORM_URLENCODED && is_array($postBody)) {
191 $postBody = http_build_query($postBody, '', '&');
192 $request->setPostBody($postBody);
193 }
194
195 // Make sure the content-length header is set.
196 if (!$postBody || is_string($postBody)) {
197 $postsLength = strlen($postBody);
198 $request->setRequestHeaders(array('content-length' => $postsLength));
199 }
200
201 return $request;
202 }
203
204 /**
205 * Check if an already cached request must be revalidated, and if so update
206 * the request with the correct ETag headers.
207 * @param Google_Http_Request $cached A previously cached response.
208 * @param Google_Http_Request $request The outbound request.
209 * return bool If the cached object needs to be revalidated, false if it is
210 * still current and can be re-used.
211 */
212 protected function checkMustRevalidateCachedRequest($cached, $request)
213 {
214 if (Google_Http_CacheParser::mustRevalidate($cached)) {
215 $addHeaders = array();
216 if ($cached->getResponseHeader('etag')) {
217 // [13.3.4] If an entity tag has been provided by the origin server,
218 // we must use that entity tag in any cache-conditional request.
219 $addHeaders['If-None-Match'] = $cached->getResponseHeader('etag');
220 } elseif ($cached->getResponseHeader('date')) {
221 $addHeaders['If-Modified-Since'] = $cached->getResponseHeader('date');
222 }
223
224 $request->setRequestHeaders($addHeaders);
225 return true;
226 } else {
227 return false;
228 }
229 }
230
231 /**
232 * Update a cached request, using the headers from the last response.
233 * @param Google_Http_Request $cached A previously cached response.
234 * @param mixed Associative array of response headers from the last request.
235 */
236 protected function updateCachedRequest($cached, $responseHeaders)
237 {
238 $hopByHop = self::$HOP_BY_HOP;
239 if (!empty($responseHeaders['connection'])) {
240 $connectionHeaders = array_map(
241 'strtolower',
242 array_filter(
243 array_map('trim', explode(',', $responseHeaders['connection']))
244 )
245 );
246 $hopByHop += array_fill_keys($connectionHeaders, true);
247 }
248
249 $endToEnd = array_diff_key($responseHeaders, $hopByHop);
250 $cached->setResponseHeaders($endToEnd);
251 }
252
253 /**
254 * Used by the IO lib and also the batch processing.
255 *
256 * @param $respData
257 * @param $headerSize
258 * @return array
259 */
260 public function parseHttpResponse($respData, $headerSize)
261 {
262 // check proxy header
263 foreach (self::$CONNECTION_ESTABLISHED_HEADERS as $established_header) {
264 if (stripos($respData, $established_header) !== false) {
265 // existed, remove it
266 $respData = str_ireplace($established_header, '', $respData);
267 // Subtract the proxy header size unless the cURL bug prior to 7.30.0
268 // is present which prevented the proxy header size from being taken into
269 // account.
270 if (!$this->needsQuirk()) {
271 $headerSize -= strlen($established_header);
272 }
273 break;
274 }
275 }
276
277 if ($headerSize) {
278 $responseBody = substr($respData, $headerSize);
279 $responseHeaders = substr($respData, 0, $headerSize);
280 } else {
281 $responseSegments = explode("\r\n\r\n", $respData, 2);
282 $responseHeaders = $responseSegments[0];
283 $responseBody = isset($responseSegments[1]) ? $responseSegments[1] :
284 null;
285 }
286
287 $responseHeaders = $this->getHttpResponseHeaders($responseHeaders);
288 return array($responseHeaders, $responseBody);
289 }
290
291 /**
292 * Parse out headers from raw headers
293 * @param rawHeaders array or string
294 * @return array
295 */
296 public function getHttpResponseHeaders($rawHeaders)
297 {
298 if (is_array($rawHeaders)) {
299 return $this->parseArrayHeaders($rawHeaders);
300 } else {
301 return $this->parseStringHeaders($rawHeaders);
302 }
303 }
304
305 private function parseStringHeaders($rawHeaders)
306 {
307 $headers = array();
308 $responseHeaderLines = explode("\r\n", $rawHeaders);
309 foreach ($responseHeaderLines as $headerLine) {
310 if ($headerLine && strpos($headerLine, ':') !== false) {
311 list($header, $value) = explode(': ', $headerLine, 2);
312 $header = strtolower($header);
313 if (isset($headers[$header])) {
314 $headers[$header] .= "\n" . $value;
315 } else {
316 $headers[$header] = $value;
317 }
318 }
319 }
320 return $headers;
321 }
322
323 private function parseArrayHeaders($rawHeaders)
324 {
325 $header_count = count($rawHeaders);
326 $headers = array();
327
328 for ($i = 0; $i < $header_count; $i++) {
329 $header = $rawHeaders[$i];
330 // Times will have colons in - so we just want the first match.
331 $header_parts = explode(': ', $header, 2);
332 if (count($header_parts) == 2) {
333 $headers[strtolower($header_parts[0])] = $header_parts[1];
334 }
335 }
336
337 return $headers;
338 }
339 }
340