diff options
Diffstat (limited to 'Postman/Postman-Mail/google-api-php-client-1.1.2/src/Google/IO/Abstract.php')
-rw-r--r-- | Postman/Postman-Mail/google-api-php-client-1.1.2/src/Google/IO/Abstract.php | 329 |
1 files changed, 329 insertions, 0 deletions
diff --git a/Postman/Postman-Mail/google-api-php-client-1.1.2/src/Google/IO/Abstract.php b/Postman/Postman-Mail/google-api-php-client-1.1.2/src/Google/IO/Abstract.php new file mode 100644 index 0000000..a480941 --- /dev/null +++ b/Postman/Postman-Mail/google-api-php-client-1.1.2/src/Google/IO/Abstract.php @@ -0,0 +1,329 @@ +<?php +/* + * Copyright 2013 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Abstract IO base class + */ + +require_once realpath(dirname(__FILE__) . '/../../../autoload.php'); + +abstract class Postman_Google_IO_Abstract +{ + const UNKNOWN_CODE = 0; + const FORM_URLENCODED = 'application/x-www-form-urlencoded'; + private static $CONNECTION_ESTABLISHED_HEADERS = array( + "HTTP/1.0 200 Connection established\r\n\r\n", + "HTTP/1.1 200 Connection established\r\n\r\n", + ); + private static $ENTITY_HTTP_METHODS = array("POST" => null, "PUT" => null); + + /** @var Postman_Google_Client */ + protected $client; + + public function __construct(Postman_Google_Client $client) + { + $this->client = $client; + $timeout = $client->getClassConfig('Postman_Google_IO_Abstract', 'request_timeout_seconds'); + if ($timeout > 0) { + $this->setTimeout($timeout); + } + } + + /** + * Executes a Postman_Google_Http_Request and returns the resulting populated Postman_Google_Http_Request + * @param Postman_Google_Http_Request $request + * @return Postman_Google_Http_Request $request + */ + abstract public function executeRequest(Postman_Google_Http_Request $request); + + /** + * Set options that update the transport implementation's behavior. + * @param $options + */ + abstract public function setOptions($options); + + /** + * Set the maximum request time in seconds. + * @param $timeout in seconds + */ + abstract public function setTimeout($timeout); + + /** + * Get the maximum request time in seconds. + * @return timeout in seconds + */ + abstract public function getTimeout(); + + /** + * Test for the presence of a cURL header processing bug + * + * The cURL bug was present in versions prior to 7.30.0 and caused the header + * length to be miscalculated when a "Connection established" header added by + * some proxies was present. + * + * @return boolean + */ + abstract protected function needsQuirk(); + + /** + * @visible for testing. + * Cache the response to an HTTP request if it is cacheable. + * @param Postman_Google_Http_Request $request + * @return bool Returns true if the insertion was successful. + * Otherwise, return false. + */ + public function setCachedRequest(Postman_Google_Http_Request $request) + { + // Determine if the request is cacheable. + if (Postman_Google_Http_CacheParser::isResponseCacheable($request)) { + $this->client->getCache()->set($request->getCacheKey(), $request); + return true; + } + + return false; + } + + /** + * Execute an HTTP Request + * + * @param Postman_Google_HttpRequest $request the http request to be executed + * @return Postman_Google_HttpRequest http request with the response http code, + * response headers and response body filled in + * @throws Postman_Google_IO_Exception on curl or IO error + */ + public function makeRequest(Postman_Google_Http_Request $request) + { + // First, check to see if we have a valid cached version. + $cached = $this->getCachedRequest($request); + if ($cached !== false && $cached instanceof Postman_Google_Http_Request) { + if (!$this->checkMustRevalidateCachedRequest($cached, $request)) { + return $cached; + } + } + + if (array_key_exists($request->getRequestMethod(), self::$ENTITY_HTTP_METHODS)) { + $request = $this->processEntityRequest($request); + } + + list($responseData, $responseHeaders, $respHttpCode) = $this->executeRequest($request); + + if ($respHttpCode == 304 && $cached) { + // If the server responded NOT_MODIFIED, return the cached request. + $this->updateCachedRequest($cached, $responseHeaders); + return $cached; + } + + if (!isset($responseHeaders['Date']) && !isset($responseHeaders['date'])) { + $responseHeaders['Date'] = date("r"); + } + + $request->setResponseHttpCode($respHttpCode); + $request->setResponseHeaders($responseHeaders); + $request->setResponseBody($responseData); + // Store the request in cache (the function checks to see if the request + // can actually be cached) + $this->setCachedRequest($request); + return $request; + } + + /** + * @visible for testing. + * @param Postman_Google_Http_Request $request + * @return Postman_Google_Http_Request|bool Returns the cached object or + * false if the operation was unsuccessful. + */ + public function getCachedRequest(Postman_Google_Http_Request $request) + { + if (false === Postman_Google_Http_CacheParser::isRequestCacheable($request)) { + return false; + } + + return $this->client->getCache()->get($request->getCacheKey()); + } + + /** + * @visible for testing + * Process an http request that contains an enclosed entity. + * @param Postman_Google_Http_Request $request + * @return Postman_Google_Http_Request Processed request with the enclosed entity. + */ + public function processEntityRequest(Postman_Google_Http_Request $request) + { + $postBody = $request->getPostBody(); + $contentType = $request->getRequestHeader("content-type"); + + // Set the default content-type as application/x-www-form-urlencoded. + if (false == $contentType) { + $contentType = self::FORM_URLENCODED; + $request->setRequestHeaders(array('content-type' => $contentType)); + } + + // Force the payload to match the content-type asserted in the header. + if ($contentType == self::FORM_URLENCODED && is_array($postBody)) { + $postBody = http_build_query($postBody, '', '&'); + $request->setPostBody($postBody); + } + + // Make sure the content-length header is set. + if (!$postBody || is_string($postBody)) { + $postsLength = strlen($postBody); + $request->setRequestHeaders(array('content-length' => $postsLength)); + } + + return $request; + } + + /** + * Check if an already cached request must be revalidated, and if so update + * the request with the correct ETag headers. + * @param Postman_Google_Http_Request $cached A previously cached response. + * @param Postman_Google_Http_Request $request The outbound request. + * return bool If the cached object needs to be revalidated, false if it is + * still current and can be re-used. + */ + protected function checkMustRevalidateCachedRequest($cached, $request) + { + if (Postman_Google_Http_CacheParser::mustRevalidate($cached)) { + $addHeaders = array(); + if ($cached->getResponseHeader('etag')) { + // [13.3.4] If an entity tag has been provided by the origin server, + // we must use that entity tag in any cache-conditional request. + $addHeaders['If-None-Match'] = $cached->getResponseHeader('etag'); + } elseif ($cached->getResponseHeader('date')) { + $addHeaders['If-Modified-Since'] = $cached->getResponseHeader('date'); + } + + $request->setRequestHeaders($addHeaders); + return true; + } else { + return false; + } + } + + /** + * Update a cached request, using the headers from the last response. + * @param Postman_Google_HttpRequest $cached A previously cached response. + * @param mixed Associative array of response headers from the last request. + */ + protected function updateCachedRequest($cached, $responseHeaders) + { + if (isset($responseHeaders['connection'])) { + $hopByHop = array_merge( + self::$HOP_BY_HOP, + explode( + ',', + $responseHeaders['connection'] + ) + ); + + $endToEnd = array(); + foreach ($hopByHop as $key) { + if (isset($responseHeaders[$key])) { + $endToEnd[$key] = $responseHeaders[$key]; + } + } + $cached->setResponseHeaders($endToEnd); + } + } + + /** + * Used by the IO lib and also the batch processing. + * + * @param $respData + * @param $headerSize + * @return array + */ + public function parseHttpResponse($respData, $headerSize) + { + // check proxy header + foreach (self::$CONNECTION_ESTABLISHED_HEADERS as $established_header) { + if (stripos($respData, $established_header) !== false) { + // existed, remove it + $respData = str_ireplace($established_header, '', $respData); + // Subtract the proxy header size unless the cURL bug prior to 7.30.0 + // is present which prevented the proxy header size from being taken into + // account. + if (!$this->needsQuirk()) { + $headerSize -= strlen($established_header); + } + break; + } + } + + if ($headerSize) { + $responseBody = substr($respData, $headerSize); + $responseHeaders = substr($respData, 0, $headerSize); + } else { + $responseSegments = explode("\r\n\r\n", $respData, 2); + $responseHeaders = $responseSegments[0]; + $responseBody = isset($responseSegments[1]) ? $responseSegments[1] : + null; + } + + $responseHeaders = $this->getHttpResponseHeaders($responseHeaders); + return array($responseHeaders, $responseBody); + } + + /** + * Parse out headers from raw headers + * @param rawHeaders array or string + * @return array + */ + public function getHttpResponseHeaders($rawHeaders) + { + if (is_array($rawHeaders)) { + return $this->parseArrayHeaders($rawHeaders); + } else { + return $this->parseStringHeaders($rawHeaders); + } + } + + private function parseStringHeaders($rawHeaders) + { + $headers = array(); + $responseHeaderLines = explode("\r\n", $rawHeaders); + foreach ($responseHeaderLines as $headerLine) { + if ($headerLine && strpos($headerLine, ':') !== false) { + list($header, $value) = explode(': ', $headerLine, 2); + $header = strtolower($header); + if (isset($headers[$header])) { + $headers[$header] .= "\n" . $value; + } else { + $headers[$header] = $value; + } + } + } + return $headers; + } + + private function parseArrayHeaders($rawHeaders) + { + $header_count = count($rawHeaders); + $headers = array(); + + for ($i = 0; $i < $header_count; $i++) { + $header = $rawHeaders[$i]; + // Times will have colons in - so we just want the first match. + $header_parts = explode(': ', $header, 2); + if (count($header_parts) == 2) { + $headers[$header_parts[0]] = $header_parts[1]; + } + } + + return $headers; + } +} |