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/**
19 * HTTP Request to be executed by apiIO classes. Upon execution, the
20 * responseHttpCode, responseHeaders and responseBody will be filled in.
21 *
22 * @author Chris Chabot <chabotc@google.com>
23 * @author Chirag Shah <chirags@google.com>
24 *
25 */
26class Google_HttpRequest {
27  const USER_AGENT_SUFFIX = "google-api-php-client/0.6.5";
28  private $batchHeaders = array(
29    'Content-Type' => 'application/http',
30    'Content-Transfer-Encoding' => 'binary',
31    'MIME-Version' => '1.0',
32    'Content-Length' => ''
33  );
34
35  protected $url;
36  protected $requestMethod;
37  protected $requestHeaders;
38  protected $postBody;
39  protected $userAgent;
40
41  protected $responseHttpCode;
42  protected $responseHeaders;
43  protected $responseBody;
44
45  public $accessKey;
46
47  public function __construct($url, $method = 'GET', $headers = array(), $postBody = null) {
48    $this->setUrl($url);
49    $this->setRequestMethod($method);
50    $this->setRequestHeaders($headers);
51    $this->setPostBody($postBody);
52
53    global $apiConfig;
54    if (empty($apiConfig['application_name'])) {
55      $this->userAgent = self::USER_AGENT_SUFFIX;
56    } else {
57      $this->userAgent = $apiConfig['application_name'] . " " . self::USER_AGENT_SUFFIX;
58    }
59  }
60
61  /**
62   * Misc function that returns the base url component of the $url
63   * used by the OAuth signing class to calculate the base string
64   * @return string The base url component of the $url.
65   * @see http://oauth.net/core/1.0a/#anchor13
66   */
67  public function getBaseUrl() {
68    if ($pos = strpos($this->url, '?')) {
69      return substr($this->url, 0, $pos);
70    }
71    return $this->url;
72  }
73
74  /**
75   * Misc function that returns an array of the query parameters of the current
76   * url used by the OAuth signing class to calculate the signature
77   * @return array Query parameters in the query string.
78   */
79  public function getQueryParams() {
80    if ($pos = strpos($this->url, '?')) {
81      $queryStr = substr($this->url, $pos + 1);
82      $params = array();
83      parse_str($queryStr, $params);
84      return $params;
85    }
86    return array();
87  }
88
89  /**
90   * @return string HTTP Response Code.
91   */
92  public function getResponseHttpCode() {
93    return (int) $this->responseHttpCode;
94  }
95
96  /**
97   * @param int $responseHttpCode HTTP Response Code.
98   */
99  public function setResponseHttpCode($responseHttpCode) {
100    $this->responseHttpCode = $responseHttpCode;
101  }
102
103  /**
104   * @return $responseHeaders (array) HTTP Response Headers.
105   */
106  public function getResponseHeaders() {
107    return $this->responseHeaders;
108  }
109
110  /**
111   * @return string HTTP Response Body
112   */
113  public function getResponseBody() {
114    return $this->responseBody;
115  }
116
117  /**
118   * @param array $headers The HTTP response headers
119   * to be normalized.
120   */
121  public function setResponseHeaders($headers) {
122    $headers = Google_Utils::normalize($headers);
123    if ($this->responseHeaders) {
124      $headers = array_merge($this->responseHeaders, $headers);
125    }
126
127    $this->responseHeaders = $headers;
128  }
129
130  /**
131   * @param string $key
132   * @return array|boolean Returns the requested HTTP header or
133   * false if unavailable.
134   */
135  public function getResponseHeader($key) {
136    return isset($this->responseHeaders[$key])
137        ? $this->responseHeaders[$key]
138        : false;
139  }
140
141  /**
142   * @param string $responseBody The HTTP response body.
143   */
144  public function setResponseBody($responseBody) {
145    $this->responseBody = $responseBody;
146  }
147
148  /**
149   * @return string $url The request URL.
150   */
151
152  public function getUrl() {
153    return $this->url;
154  }
155
156  /**
157   * @return string $method HTTP Request Method.
158   */
159  public function getRequestMethod() {
160    return $this->requestMethod;
161  }
162
163  /**
164   * @return array $headers HTTP Request Headers.
165   */
166  public function getRequestHeaders() {
167    return $this->requestHeaders;
168  }
169
170  /**
171   * @param string $key
172   * @return array|boolean Returns the requested HTTP header or
173   * false if unavailable.
174   */
175  public function getRequestHeader($key) {
176    return isset($this->requestHeaders[$key])
177        ? $this->requestHeaders[$key]
178        : false;
179  }
180
181  /**
182   * @return string $postBody HTTP Request Body.
183   */
184  public function getPostBody() {
185    return $this->postBody;
186  }
187
188  /**
189   * @param string $url the url to set
190   */
191  public function setUrl($url) {
192    if (substr($url, 0, 4) == 'http') {
193      $this->url = $url;
194    } else {
195      // Force the path become relative.
196      if (substr($url, 0, 1) !== '/') {
197        $url = '/' . $url;
198      }
199      global $apiConfig;
200      $this->url = $apiConfig['basePath'] . $url;
201    }
202  }
203
204  /**
205   * @param string $method Set he HTTP Method and normalize
206   * it to upper-case, as required by HTTP.
207   *
208   */
209  public function setRequestMethod($method) {
210    $this->requestMethod = strtoupper($method);
211  }
212
213  /**
214   * @param array $headers The HTTP request headers
215   * to be set and normalized.
216   */
217  public function setRequestHeaders($headers) {
218    $headers = Google_Utils::normalize($headers);
219    if ($this->requestHeaders) {
220      $headers = array_merge($this->requestHeaders, $headers);
221    }
222    $this->requestHeaders = $headers;
223  }
224
225  /**
226   * @param string $postBody the postBody to set
227   */
228  public function setPostBody($postBody) {
229    $this->postBody = $postBody;
230  }
231
232  /**
233   * Set the User-Agent Header.
234   * @param string $userAgent The User-Agent.
235   */
236  public function setUserAgent($userAgent) {
237    $this->userAgent = $userAgent;
238  }
239
240  /**
241   * @return string The User-Agent.
242   */
243  public function getUserAgent() {
244    return $this->userAgent;
245  }
246
247  /**
248   * Returns a cache key depending on if this was an OAuth signed request
249   * in which case it will use the non-signed url and access key to make this
250   * cache key unique per authenticated user, else use the plain request url
251   * @return string The md5 hash of the request cache key.
252   */
253  public function getCacheKey() {
254    $key = $this->getUrl();
255
256    if (isset($this->accessKey)) {
257      $key .= $this->accessKey;
258    }
259
260    if (isset($this->requestHeaders['authorization'])) {
261      $key .= $this->requestHeaders['authorization'];
262    }
263
264    return md5($key);
265  }
266
267  public function getParsedCacheControl() {
268    $parsed = array();
269    $rawCacheControl = $this->getResponseHeader('cache-control');
270    if ($rawCacheControl) {
271      $rawCacheControl = str_replace(', ', '&', $rawCacheControl);
272      parse_str($rawCacheControl, $parsed);
273    }
274
275    return $parsed;
276  }
277
278  /**
279   * @param string $id
280   * @return string A string representation of the HTTP Request.
281   */
282  public function toBatchString($id) {
283    $str = '';
284    foreach($this->batchHeaders as $key => $val) {
285      $str .= $key . ': ' . $val . "\n";
286    }
287
288    $str .= "Content-ID: $id\n";
289    $str .= "\n";
290
291    $path = parse_url($this->getUrl(), PHP_URL_PATH);
292    $str .= $this->getRequestMethod() . ' ' . $path . " HTTP/1.1\n";
293    foreach($this->getRequestHeaders() as $key => $val) {
294      $str .= $key . ': ' . $val . "\n";
295    }
296
297    if ($this->getPostBody()) {
298      $str .= "\n";
299      $str .= $this->getPostBody();
300    }
301
302    return $str;
303  }
304}
305