/google_api/Http/Request.php

  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.  
  18. if (!class_exists('Google_Client')) { 
  19. require_once dirname(__FILE__) . '/../autoload.php'; 
  20.  
  21. /** 
  22. * HTTP Request to be executed by IO classes. Upon execution, the 
  23. * responseHttpCode, responseHeaders and responseBody will be filled in. 
  24. * 
  25. * @author Chris Chabot <chabotc@google.com> 
  26. * @author Chirag Shah <chirags@google.com> 
  27. * 
  28. */ 
  29. class Google_Http_Request 
  30. const GZIP_UA = " (gzip)"; 
  31.  
  32. private $batchHeaders = array( 
  33. 'Content-Type' => 'application/http',  
  34. 'Content-Transfer-Encoding' => 'binary',  
  35. 'MIME-Version' => '1.0',  
  36. ); 
  37.  
  38. protected $queryParams; 
  39. protected $requestMethod; 
  40. protected $requestHeaders; 
  41. protected $baseComponent = null; 
  42. protected $path; 
  43. protected $postBody; 
  44. protected $userAgent; 
  45. protected $canGzip = null; 
  46.  
  47. protected $responseHttpCode; 
  48. protected $responseHeaders; 
  49. protected $responseBody; 
  50.  
  51. protected $expectedClass; 
  52. protected $expectedRaw = false; 
  53.  
  54. public $accessKey; 
  55.  
  56. public function __construct( 
  57. $url,  
  58. $method = 'GET',  
  59. $headers = array(),  
  60. $postBody = null 
  61. ) { 
  62. $this->setUrl($url); 
  63. $this->setRequestMethod($method); 
  64. $this->setRequestHeaders($headers); 
  65. $this->setPostBody($postBody); 
  66.  
  67. /** 
  68. * Misc function that returns the base url component of the $url 
  69. * used by the OAuth signing class to calculate the base string 
  70. * @return string The base url component of the $url. 
  71. */ 
  72. public function getBaseComponent() 
  73. return $this->baseComponent; 
  74.  
  75. /** 
  76. * Set the base URL that path and query parameters will be added to. 
  77. * @param $baseComponent string 
  78. */ 
  79. public function setBaseComponent($baseComponent) 
  80. $this->baseComponent = $baseComponent; 
  81.  
  82. /** 
  83. * Enable support for gzipped responses with this request. 
  84. */ 
  85. public function enableGzip() 
  86. $this->setRequestHeaders(array("Accept-Encoding" => "gzip")); 
  87. $this->canGzip = true; 
  88. $this->setUserAgent($this->userAgent); 
  89.  
  90. /** 
  91. * Disable support for gzip responses with this request. 
  92. */ 
  93. public function disableGzip() 
  94. if ( 
  95. isset($this->requestHeaders['accept-encoding']) && 
  96. $this->requestHeaders['accept-encoding'] == "gzip" 
  97. ) { 
  98. unset($this->requestHeaders['accept-encoding']); 
  99. $this->canGzip = false; 
  100. $this->userAgent = str_replace(self::GZIP_UA, "", $this->userAgent); 
  101.  
  102. /** 
  103. * Can this request accept a gzip response? 
  104. * @return bool 
  105. */ 
  106. public function canGzip() 
  107. return $this->canGzip; 
  108.  
  109. /** 
  110. * Misc function that returns an array of the query parameters of the current 
  111. * url used by the OAuth signing class to calculate the signature 
  112. * @return array Query parameters in the query string. 
  113. */ 
  114. public function getQueryParams() 
  115. return $this->queryParams; 
  116.  
  117. /**  
  118. * Set a new query parameter. 
  119. * @param $key - string to set, does not need to be URL encoded 
  120. * @param $value - string to set, does not need to be URL encoded 
  121. */ 
  122. public function setQueryParam($key, $value) 
  123. $this->queryParams[$key] = $value; 
  124.  
  125. /** 
  126. * @return string HTTP Response Code. 
  127. */ 
  128. public function getResponseHttpCode() 
  129. return (int) $this->responseHttpCode; 
  130.  
  131. /** 
  132. * @param int $responseHttpCode HTTP Response Code. 
  133. */ 
  134. public function setResponseHttpCode($responseHttpCode) 
  135. $this->responseHttpCode = $responseHttpCode; 
  136.  
  137. /** 
  138. * @return $responseHeaders (array) HTTP Response Headers. 
  139. */ 
  140. public function getResponseHeaders() 
  141. return $this->responseHeaders; 
  142.  
  143. /** 
  144. * @return string HTTP Response Body 
  145. */ 
  146. public function getResponseBody() 
  147. return $this->responseBody; 
  148.  
  149. /** 
  150. * Set the class the response to this request should expect. 
  151. * 
  152. * @param $class string the class name 
  153. */ 
  154. public function setExpectedClass($class) 
  155. $this->expectedClass = $class; 
  156.  
  157. /** 
  158. * Retrieve the expected class the response should expect. 
  159. * @return string class name 
  160. */ 
  161. public function getExpectedClass() 
  162. return $this->expectedClass; 
  163.  
  164. /** 
  165. * Enable expected raw response 
  166. */ 
  167. public function enableExpectedRaw() 
  168. $this->expectedRaw = true; 
  169.  
  170. /** 
  171. * Disable expected raw response 
  172. */ 
  173. public function disableExpectedRaw() 
  174. $this->expectedRaw = false; 
  175.  
  176. /** 
  177. * Expected raw response or not. 
  178. * @return boolean expected raw response 
  179. */ 
  180. public function getExpectedRaw() 
  181. return $this->expectedRaw; 
  182.  
  183. /** 
  184. * @param array $headers The HTTP response headers 
  185. * to be normalized. 
  186. */ 
  187. public function setResponseHeaders($headers) 
  188. $headers = Google_Utils::normalize($headers); 
  189. if ($this->responseHeaders) { 
  190. $headers = array_merge($this->responseHeaders, $headers); 
  191.  
  192. $this->responseHeaders = $headers; 
  193.  
  194. /** 
  195. * @param string $key 
  196. * @return array|boolean Returns the requested HTTP header or 
  197. * false if unavailable. 
  198. */ 
  199. public function getResponseHeader($key) 
  200. return isset($this->responseHeaders[$key]) 
  201. ? $this->responseHeaders[$key] 
  202. : false; 
  203.  
  204. /** 
  205. * @param string $responseBody The HTTP response body. 
  206. */ 
  207. public function setResponseBody($responseBody) 
  208. $this->responseBody = $responseBody; 
  209.  
  210. /** 
  211. * @return string $url The request URL. 
  212. */ 
  213. public function getUrl() 
  214. return $this->baseComponent . $this->path . 
  215. (count($this->queryParams) ? 
  216. "?" . $this->buildQuery($this->queryParams) : 
  217. ''); 
  218.  
  219. /** 
  220. * @return string $method HTTP Request Method. 
  221. */ 
  222. public function getRequestMethod() 
  223. return $this->requestMethod; 
  224.  
  225. /** 
  226. * @return array $headers HTTP Request Headers. 
  227. */ 
  228. public function getRequestHeaders() 
  229. return $this->requestHeaders; 
  230.  
  231. /** 
  232. * @param string $key 
  233. * @return array|boolean Returns the requested HTTP header or 
  234. * false if unavailable. 
  235. */ 
  236. public function getRequestHeader($key) 
  237. return isset($this->requestHeaders[$key]) 
  238. ? $this->requestHeaders[$key] 
  239. : false; 
  240.  
  241. /** 
  242. * @return string $postBody HTTP Request Body. 
  243. */ 
  244. public function getPostBody() 
  245. return $this->postBody; 
  246.  
  247. /** 
  248. * @param string $url the url to set 
  249. */ 
  250. public function setUrl($url) 
  251. if (substr($url, 0, 4) != 'http') { 
  252. // Force the path become relative. 
  253. if (substr($url, 0, 1) !== '/') { 
  254. $url = '/' . $url; 
  255. $parts = parse_url($url); 
  256. if (isset($parts['host'])) { 
  257. $this->baseComponent = sprintf( 
  258. "%s%s%s",  
  259. isset($parts['scheme']) ? $parts['scheme'] . "://" : '',  
  260. isset($parts['host']) ? $parts['host'] : '',  
  261. isset($parts['port']) ? ":" . $parts['port'] : '' 
  262. ); 
  263. $this->path = isset($parts['path']) ? $parts['path'] : ''; 
  264. $this->queryParams = array(); 
  265. if (isset($parts['query'])) { 
  266. $this->queryParams = $this->parseQuery($parts['query']); 
  267.  
  268. /** 
  269. * @param string $method Set he HTTP Method and normalize 
  270. * it to upper-case, as required by HTTP. 
  271. * 
  272. */ 
  273. public function setRequestMethod($method) 
  274. $this->requestMethod = strtoupper($method); 
  275.  
  276. /** 
  277. * @param array $headers The HTTP request headers 
  278. * to be set and normalized. 
  279. */ 
  280. public function setRequestHeaders($headers) 
  281. $headers = Google_Utils::normalize($headers); 
  282. if ($this->requestHeaders) { 
  283. $headers = array_merge($this->requestHeaders, $headers); 
  284. $this->requestHeaders = $headers; 
  285.  
  286. /** 
  287. * @param string $postBody the postBody to set 
  288. */ 
  289. public function setPostBody($postBody) 
  290. $this->postBody = $postBody; 
  291.  
  292. /** 
  293. * Set the User-Agent Header. 
  294. * @param string $userAgent The User-Agent. 
  295. */ 
  296. public function setUserAgent($userAgent) 
  297. $this->userAgent = $userAgent; 
  298. if ($this->canGzip) { 
  299. $this->userAgent = $userAgent . self::GZIP_UA; 
  300.  
  301. /** 
  302. * @return string The User-Agent. 
  303. */ 
  304. public function getUserAgent() 
  305. return $this->userAgent; 
  306.  
  307. /** 
  308. * Returns a cache key depending on if this was an OAuth signed request 
  309. * in which case it will use the non-signed url and access key to make this 
  310. * cache key unique per authenticated user, else use the plain request url 
  311. * @return string The md5 hash of the request cache key. 
  312. */ 
  313. public function getCacheKey() 
  314. $key = $this->getUrl(); 
  315.  
  316. if (isset($this->accessKey)) { 
  317. $key .= $this->accessKey; 
  318.  
  319. if (isset($this->requestHeaders['authorization'])) { 
  320. $key .= $this->requestHeaders['authorization']; 
  321.  
  322. return md5($key); 
  323.  
  324. public function getParsedCacheControl() 
  325. $parsed = array(); 
  326. $rawCacheControl = $this->getResponseHeader('cache-control'); 
  327. if ($rawCacheControl) { 
  328. $rawCacheControl = str_replace(', ', '&', $rawCacheControl); 
  329. parse_str($rawCacheControl, $parsed); 
  330.  
  331. return $parsed; 
  332.  
  333. /** 
  334. * @param string $id 
  335. * @return string A string representation of the HTTP Request. 
  336. */ 
  337. public function toBatchString($id) 
  338. $str = ''; 
  339. $path = parse_url($this->getUrl(), PHP_URL_PATH) . "?" . 
  340. http_build_query($this->queryParams); 
  341. $str .= $this->getRequestMethod() . ' ' . $path . " HTTP/1.1\n"; 
  342.  
  343. foreach ($this->getRequestHeaders() as $key => $val) { 
  344. $str .= $key . ': ' . $val . "\n"; 
  345.  
  346. if ($this->getPostBody()) { 
  347. $str .= "\n"; 
  348. $str .= $this->getPostBody(); 
  349.  
  350. $headers = ''; 
  351. foreach ($this->batchHeaders as $key => $val) { 
  352. $headers .= $key . ': ' . $val . "\n"; 
  353.  
  354. $headers .= "Content-ID: $id\n"; 
  355. $str = $headers . "\n" . $str; 
  356.  
  357. return $str; 
  358.  
  359. /** 
  360. * Our own version of parse_str that allows for multiple variables 
  361. * with the same name.  
  362. * @param $string - the query string to parse 
  363. */ 
  364. private function parseQuery($string) 
  365. $return = array(); 
  366. $parts = explode("&", $string); 
  367. foreach ($parts as $part) { 
  368. list($key, $value) = explode('=', $part, 2); 
  369. $value = urldecode($value); 
  370. if (isset($return[$key])) { 
  371. if (!is_array($return[$key])) { 
  372. $return[$key] = array($return[$key]); 
  373. $return[$key][] = $value; 
  374. } else { 
  375. $return[$key] = $value; 
  376. return $return; 
  377.  
  378. /** 
  379. * A version of build query that allows for multiple 
  380. * duplicate keys.  
  381. * @param $parts array of key value pairs 
  382. */ 
  383. private function buildQuery($parts) 
  384. $return = array(); 
  385. foreach ($parts as $key => $value) { 
  386. if (is_array($value)) { 
  387. foreach ($value as $v) { 
  388. $return[] = urlencode($key) . "=" . urlencode($v); 
  389. } else { 
  390. $return[] = urlencode($key) . "=" . urlencode($value); 
  391. return implode('&', $return); 
  392.  
  393. /**  
  394. * If we're POSTing and have no body to send, we can send the query 
  395. * parameters in there, which avoids length issues with longer query 
  396. * params. 
  397. */ 
  398. public function maybeMoveParametersToBody() 
  399. if ($this->getRequestMethod() == "POST" && empty($this->postBody)) { 
  400. $this->setRequestHeaders( 
  401. array( 
  402. "content-type" => 
  403. "application/x-www-form-urlencoded; charset=UTF-8" 
  404. ); 
  405. $this->setPostBody($this->buildQuery($this->queryParams)); 
  406. $this->queryParams = array(); 
.