Google_IO_Abstract

The Simple Calendar Google IO Abstract class.

Defined (1)

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

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