PageRenderTime 50ms CodeModel.GetById 13ms RepoModel.GetById 0ms app.codeStats 0ms

/Logica/Google/IO/Abstract.php

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