PATH:
home
/
letacommog
/
supportleta
/
wp-content
/
plugins
/
user-pro
/
lib
/
google
/
src
/
io
<?php /* * Copyright 2010 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. */ /** * Curl based implementation of apiIO. * This class implements http spec compliant request caching using the apiCache class * * @author Chris Chabot <chabotc@google.com> * @author Chirag Shah <chirags@google.com> */ class apiCurlIO implements apiIO { private static $DEFAULT_CURL_PARAMS = array ( CURLOPT_RETURNTRANSFER => true, CURLOPT_FOLLOWLOCATION => 0, CURLOPT_FAILONERROR => false, CURLOPT_SSL_VERIFYPEER => true, CURLOPT_HEADER => true, ); /** * Perform an authenticated / signed apiHttpRequest. * This function takes the apiHttpRequest, calls apiAuth->sign on it * (which can modify the request in what ever way fits the auth mechanism) * and then calls apiCurlIO::makeRequest on the signed request * * @param apiHttpRequest $request * @return apiHttpRequest The resulting HTTP response including the * responseHttpCode, responseHeaders and responseBody. */ public function authenticatedRequest(apiHttpRequest $request) { $request = apiClient::$auth->sign($request); return $this->makeRequest($request); } /** * Execute a apiHttpRequest * * @param apiHttpRequest $request the http request to be executed * @return apiHttpRequest http request with the response http code, response * headers and response body filled in * @throws apiIOException on curl or IO error */ public function makeRequest(apiHttpRequest $request) { // If it's a GET request, check to see if we have a valid cached version if ($request->getMethod() == 'GET') { // check to see if this is signed, and if so use the original url + oauth // access token to get a (per user context(!)) unique key to match against if (($cachedRequest = $this->getCachedRequest($request)) !== false) { if ($this->mustRevalidate($cachedRequest)) { $addHeaders = array(); $headers = $this->getNormalizedHeaders($cachedRequest); if (isset($headers['etag'])) { $addHeaders[] = 'If-None-Match: ' . $headers['etag']; } elseif (isset($headers['Date'])) { $addHeaders[] = 'If-Modified-Since: ' . $headers['Date']; } if (is_array($request->getHeaders())) { $request->setHeaders(array_merge($addHeaders, $request->getHeaders())); } else { $request->setHeaders($addHeaders); } } else { // No need to revalidate the request, return it directly return $cachedRequest; } } } // Couldn't use a cached version, so perform the actual request if ($request->getMethod() == 'POST' || $request->getMethod() == 'PUT') { // make sure a Content-length header is set $postBody = $request->getPostBody(); if (is_array($postBody)) { $postBody = http_build_query($postBody); $request->setPostBody($postBody); } if (! is_array($postBody)) { $postContentLength = strlen($postBody) != 0 ? strlen($postBody) : '0'; $addHeaders = array('Content-Length: ' . $postContentLength); if (is_array($request->getHeaders())) { $request->setHeaders(array_merge($addHeaders, $request->getHeaders())); } else { $request->setHeaders($addHeaders); } } } $ch = curl_init(); curl_setopt_array($ch, self::$DEFAULT_CURL_PARAMS); curl_setopt($ch, CURLOPT_URL, $request->getUrl()); if ($request->getPostBody()) { curl_setopt($ch, CURLOPT_POSTFIELDS, $request->getPostBody()); } if ($request->getHeaders() && is_array($request->getHeaders())) { curl_setopt($ch, CURLOPT_HTTPHEADER, array_unique($request->getHeaders())); } curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $request->getMethod()); curl_setopt($ch, CURLOPT_USERAGENT, $request->getUserAgent()); $respData = curl_exec($ch); $respHeaderSize = curl_getinfo($ch, CURLINFO_HEADER_SIZE); $respHttpCode = (int) curl_getinfo($ch, CURLINFO_HTTP_CODE); $curlErrorNum = curl_errno($ch); $curlError = curl_error($ch); curl_close($ch); if ($curlErrorNum != CURLE_OK) { throw new apiIOException('HTTP Error: (' . $respHttpCode . ') ' . $curlError); } if ($respHttpCode == 304 && $cachedRequest) { // If the server responded NOT_MODIFIED, return the cached request return $cachedRequest; } // Parse out the raw response into usable bits $rawResponseHeaders = substr($respData, 0, $respHeaderSize); $responseBody = substr($respData, $respHeaderSize); $responseHeaderLines = explode("\r\n", $rawResponseHeaders); $responseHeaders = array(); foreach ($responseHeaderLines as $headerLine) { if ($headerLine && strpos($headerLine, ':') !== false) { list($header, $value) = explode(': ', $headerLine, 2); if (isset($responseHeaders[$header])) { $responseHeaders[$header] .= "\n" . $value; } else { $responseHeaders[$header] = $value; } } } // Fill in the apiHttpRequest with the response values $request->setResponseHttpCode($respHttpCode); $request->setResponseHeaders($responseHeaders); $request->setResponseBody($responseBody); // Store the request in cache (the function checks to see if the request can actually be cached) $this->setCachedRequest($request); // And finally return it return $request; } private function setCachedRequest(apiHttpRequest $request) { // Only cache GET requests if ($request->getMethod() != 'GET') { return false; } // Analyze the request headers to see if there is a valid caching strategy. $headers = $this->getNormalizedHeaders($request); // And parse all the bits that are required for the can-cache evaluation $etag = isset($headers['etag']) ? $headers['etag'] : false; $expires = isset($headers['expires']) ? strtotime($headers['expires']) : false; $date = isset($headers['date']) ? strtotime($headers['date']) : time(); $cacheControl = array(); if (isset($headers['cache-control'])) { $cacheControl = explode(', ', $headers['cache-control']); foreach ($cacheControl as $key => $val) { $cacheControl[$key] = strtolower($val); } } $pragmaNoCache = isset($headers['pragma']) ? strtolower($headers['pragma']) == 'no-cache' : false; // evaluate if the request can be cached $canCache = ! in_array('no-store', $cacheControl) && // If no Cache-Control: no-store is present, we can cache (($etag || $expires > $date) || // if the response has an etag, or if it has an expiration date that is greater then the current date, we can check for a 304 NOT MODIFIED, so cache (! $etag && ! $expires && ! $pragmaNoCache && ! in_array('no-cache', $cacheControl))); // or if there is no etag, and no expiration set, but also no pragma: no-cache and no cache-control: no-cache, we can cache (but we'll set our own expires header to make sure it's refreshed frequently) if ($canCache) { // Set an 1 hour expiration header if non exists, and no do-not-cache directives exist if (! $etag && ! $expires && ! $pragmaNoCache && ! in_array('no-cache', $cacheControl)) { // Add Expires and Date headers to simplify the cache retrieval code path $request->setResponseHeaders(array_merge(array( 'Expires' => date('r', time() + 60 * 60), 'Date' => date('r', time())), $request->getHeaders())); } apiClient::$cache->set($this->getRequestKey($request), $request); } } private function getCachedRequest(apiHttpRequest $request) { if (($cachedRequest = apiClient::$cache->get($this->getRequestKey($request))) !== false) { // There is a cached version of this request, validate if it can actually be used $headers = $this->getNormalizedHeaders($request); $etag = isset($headers['etag']) ? $headers['etag'] : false; $expires = isset($headers['expires']) ? strtotime($headers['expires']) : false; $date = isset($headers['date']) ? strtotime($headers['date']) : time(); $cacheControl = array(); if (isset($headers['cache-control'])) { $cacheControl = explode(', ', $headers['cache-control']); foreach ($cacheControl as $key => $val) { $cacheControl[$key] = strtolower($val); } } // Only use the cached request if it has an etag or expiration date that's lower then the current time if ($etag || ($expires < $date)) { // There is either an ETag set, or the expiration time is less then the current time, return it return $cachedRequest; } else { // Clean out the stale cache entry before returning apiClient::$cache->delete($this->getRequestKey($request)); } } // Either the request was not cached, or it has expired, return false return false; } /** * Returns true if the request has specified must-revalidate in it's Cache-Control header, or if it doesn't have an Expires header but does have an ETag or has expired * @param apiHttpRequest $request * @return boolean */ private function mustRevalidate(apiHttpRequest $request) { // check to see if we need to go the If-Modified-Since or Etag route (in which case we make the request, but accept a 304 NOT MODIFIED) $headers = $this->getNormalizedHeaders($request); $etag = isset($headers['etag']) ? $headers['etag'] : false; $expires = isset($headers['expires']) ? strtotime($headers['expires']) : false; $date = isset($headers['date']) ? strtotime($headers['date']) : time(); $cacheControl = array(); if (isset($headers['cache-control'])) { $cacheControl = explode(', ', $headers['cache-control']); foreach ($cacheControl as $key => $val) { $cacheControl[$key] = strtolower($val); } } return (in_array('must-revalidate', $cacheControl) || ($etag && ! $expires) || $expires > $date); } /** * Returns a cache key depending on if this was an OAuth signed request in which case it will use the non-signed url and access key to make this caching key unique * per authenticated user, else use the plain request url * @param apiHttpRequest $request * @return a md5 sum of the request url */ private function getRequestKey(apiHttpRequest $request) { $cacheUrl = $request->getUrl(); if (isset($request->accessKey)) { $cacheUrl .= $request->accessKey; } $headers = $request->getHeaders(); $token = apiClient::$auth->accessToken; if (isset($token['id_token']) && $token['id_token']) { $cacheUrl .= $token['id_token']; } return md5($cacheUrl); } /** * Normalize all HTTP headers. * @param apiHttpRequest $request * @return array */ private function getNormalizedHeaders(apiHttpRequest $request) { if (!is_array($request->getResponseHeaders())) { return array(); } $headers = $request->getResponseHeaders(); $newHeaders = array(); foreach ($headers as $key => $val) { $newHeaders[strtolower($key)] = $val; } return $newHeaders; } }
[+]
..
[-] apiCurlIO.php
[edit]
[-] apiCacheParser.php
[edit]
[-] apiIO.php
[edit]
[-] apiHttpRequest.php
[edit]
[-] apiRPC.php
[edit]
[-] apiREST.php
[edit]