1<?php 2/** 3 * Copyright 2010 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 18require_once 'io/Google_HttpRequest.php'; 19require_once 'io/Google_HttpStreamIO.php'; 20require_once 'io/Google_CurlIO.php'; 21require_once 'io/Google_REST.php'; 22 23/** 24 * Abstract IO class 25 * 26 * @author Chris Chabot <chabotc@google.com> 27 */ 28abstract class Google_IO { 29 const CONNECTION_ESTABLISHED = "HTTP/1.0 200 Connection established\r\n\r\n"; 30 const FORM_URLENCODED = 'application/x-www-form-urlencoded'; 31 /** 32 * An utility function that first calls $this->auth->sign($request) and then executes makeRequest() 33 * on that signed request. Used for when a request should be authenticated 34 * @param Google_HttpRequest $request 35 * @return Google_HttpRequest $request 36 */ 37 abstract function authenticatedRequest(Google_HttpRequest $request); 38 39 /** 40 * Executes a apIHttpRequest and returns the resulting populated httpRequest 41 * @param Google_HttpRequest $request 42 * @return Google_HttpRequest $request 43 */ 44 abstract function makeRequest(Google_HttpRequest $request); 45 46 /** 47 * Set options that update the transport implementation's behavior. 48 * @param $options 49 */ 50 abstract function setOptions($options); 51 52 /** 53 * @visible for testing. 54 * Cache the response to an HTTP request if it is cacheable. 55 * @param Google_HttpRequest $request 56 * @return bool Returns true if the insertion was successful. 57 * Otherwise, return false. 58 */ 59 protected function setCachedRequest(Google_HttpRequest $request) { 60 // Determine if the request is cacheable. 61 if (Google_CacheParser::isResponseCacheable($request)) { 62 Google_Client::$cache->set($request->getCacheKey(), $request); 63 return true; 64 } 65 66 return false; 67 } 68 69 /** 70 * @visible for testing. 71 * @param Google_HttpRequest $request 72 * @return Google_HttpRequest|bool Returns the cached object or 73 * false if the operation was unsuccessful. 74 */ 75 protected function getCachedRequest(Google_HttpRequest $request) { 76 if (false == Google_CacheParser::isRequestCacheable($request)) { 77 false; 78 } 79 80 return Google_Client::$cache->get($request->getCacheKey()); 81 } 82 83 /** 84 * @visible for testing 85 * Process an http request that contains an enclosed entity. 86 * @param Google_HttpRequest $request 87 * @return Google_HttpRequest Processed request with the enclosed entity. 88 */ 89 protected function processEntityRequest(Google_HttpRequest $request) { 90 $postBody = $request->getPostBody(); 91 $contentType = $request->getRequestHeader("content-type"); 92 93 // Set the default content-type as application/x-www-form-urlencoded. 94 if (false == $contentType) { 95 $contentType = self::FORM_URLENCODED; 96 $request->setRequestHeaders(array('content-type' => $contentType)); 97 } 98 99 // Force the payload to match the content-type asserted in the header. 100 if ($contentType == self::FORM_URLENCODED && is_array($postBody)) { 101 $postBody = http_build_query($postBody, '', '&'); 102 $request->setPostBody($postBody); 103 } 104 105 // Make sure the content-length header is set. 106 if (!$postBody || is_string($postBody)) { 107 $postsLength = strlen($postBody); 108 $request->setRequestHeaders(array('content-length' => $postsLength)); 109 } 110 111 return $request; 112 } 113 114 /** 115 * Check if an already cached request must be revalidated, and if so update 116 * the request with the correct ETag headers. 117 * @param Google_HttpRequest $cached A previously cached response. 118 * @param Google_HttpRequest $request The outbound request. 119 * return bool If the cached object needs to be revalidated, false if it is 120 * still current and can be re-used. 121 */ 122 protected function checkMustRevaliadateCachedRequest($cached, $request) { 123 if (Google_CacheParser::mustRevalidate($cached)) { 124 $addHeaders = array(); 125 if ($cached->getResponseHeader('etag')) { 126 // [13.3.4] If an entity tag has been provided by the origin server, 127 // we must use that entity tag in any cache-conditional request. 128 $addHeaders['If-None-Match'] = $cached->getResponseHeader('etag'); 129 } elseif ($cached->getResponseHeader('date')) { 130 $addHeaders['If-Modified-Since'] = $cached->getResponseHeader('date'); 131 } 132 133 $request->setRequestHeaders($addHeaders); 134 return true; 135 } else { 136 return false; 137 } 138 } 139 140 /** 141 * Update a cached request, using the headers from the last response. 142 * @param Google_HttpRequest $cached A previously cached response. 143 * @param mixed Associative array of response headers from the last request. 144 */ 145 protected function updateCachedRequest($cached, $responseHeaders) { 146 if (isset($responseHeaders['connection'])) { 147 $hopByHop = array_merge( 148 self::$HOP_BY_HOP, 149 explode(',', $responseHeaders['connection']) 150 ); 151 152 $endToEnd = array(); 153 foreach($hopByHop as $key) { 154 if (isset($responseHeaders[$key])) { 155 $endToEnd[$key] = $responseHeaders[$key]; 156 } 157 } 158 $cached->setResponseHeaders($endToEnd); 159 } 160 } 161} 162