Google_IO_Abstract

The SZ - Google Google IO Abstract class.

Defined (1)

The class is defined in the following location(s).

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