PluginProbe
Authorizer / 2.3.4
Authorizer v2.3.4
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 / inc / google-api-php-client / src / Google / IO / Abstract.php

Abstract.php in Authorizer 2.3.4, at inc/google-api-php-client/src/Google/IO/Abstract.php

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