public function sign(Request $request)
 {
     $key = $this->client->getClassConfig($this, 'developer_key');
     if ($key) {
         $this->client->getLogger()->debug('Simple API Access developer key authentication');
         $request->setQueryParam('key', $key);
     }
     return $request;
 }
 private function getResumeUri()
 {
     $result = null;
     $body = $this->request->getPostBody();
     if ($body) {
         $headers = array('content-type' => 'application/json; charset=UTF-8', 'content-length' => Utils::getStrLen($body), 'x-upload-content-type' => $this->mimeType, 'x-upload-content-length' => $this->size, 'expect' => '');
         $this->request->setRequestHeaders($headers);
     }
     $response = $this->client->getIo()->makeRequest($this->request);
     $location = $response->getResponseHeader('location');
     $code = $response->getResponseHttpCode();
     if (200 == $code && true == $location) {
         return $location;
     }
     $message = $code;
     $body = @json_decode($response->getResponseBody());
     if (!empty($body->error->errors)) {
         $message .= ': ';
         foreach ($body->error->errors as $error) {
             $message .= "{$error->domain}, {$error->message};";
         }
         $message = rtrim($message, ';');
     }
     $error = "Failed to start the resumable upload (HTTP {$message})";
     $this->client->getLogger()->error($error);
     throw new Exception($error);
 }
Example #3
0
 /**
  * Decode an HTTP Response.
  * @static
  * @throws Google\Service\Exception
  * @param Google\Http\Request $response The http response to be decoded.
  * @param Google\Client $client
  * @return mixed|null
  */
 public static function decodeHttpResponse($response, Client $client = null)
 {
     $code = $response->getResponseHttpCode();
     $body = $response->getResponseBody();
     $decoded = null;
     if (intVal($code) >= 300) {
         $decoded = json_decode($body, true);
         $err = 'Error calling ' . $response->getRequestMethod() . ' ' . $response->getUrl();
         if (isset($decoded['error']) && isset($decoded['error']['message']) && isset($decoded['error']['code'])) {
             // if we're getting a json encoded error definition, use that instead of the raw response
             // body for improved readability
             $err .= ": ({$decoded['error']['code']}) {$decoded['error']['message']}";
         } else {
             $err .= ": ({$code}) {$body}";
         }
         $errors = null;
         // Specific check for APIs which don't return error details, such as Blogger.
         if (isset($decoded['error']) && isset($decoded['error']['errors'])) {
             $errors = $decoded['error']['errors'];
         }
         $map = null;
         if ($client) {
             $client->getLogger()->error($err, array('code' => $code, 'errors' => $errors));
             $map = $client->getClassConfig('Google\\Service\\Exception', 'retry_map');
         }
         throw new Exception($err, $code, null, $errors, $map);
     }
     // Only attempt to decode the response, if the response code wasn't (204) 'no content'
     if ($code != '204') {
         if ($response->getExpectedRaw()) {
             return $body;
         }
         $decoded = json_decode($body, true);
         if ($decoded === null || $decoded === "") {
             $error = "Invalid json in service response: {$body}";
             if ($client) {
                 $client->getLogger()->error($error);
             }
             throw new Exception($error);
         }
         if ($response->getExpectedClass()) {
             $class = $response->getExpectedClass();
             $decoded = new $class($decoded);
         }
     }
     return $decoded;
 }
 /**
  * TODO: This function needs simplifying.
  * @param $name
  * @param $arguments
  * @param $expected_class - optional, the expected class name
  * @return Google\Http\Request|expected_class
  * @throws Google\Exception
  */
 public function call($name, $arguments, $expected_class = null)
 {
     if (!isset($this->methods[$name])) {
         $this->client->getLogger()->error('Service method unknown', array('service' => $this->serviceName, 'resource' => $this->resourceName, 'method' => $name));
         throw new Exception("Unknown function: " . "{$this->serviceName}->{$this->resourceName}->{$name}()");
     }
     $method = $this->methods[$name];
     $parameters = $arguments[0];
     // postBody is a special case since it's not defined in the discovery
     // document as parameter, but we abuse the param entry for storing it.
     $postBody = null;
     if (isset($parameters['postBody'])) {
         if ($parameters['postBody'] instanceof Model) {
             // In the cases the post body is an existing object, we want
             // to use the smart method to create a simple object for
             // for JSONification.
             $parameters['postBody'] = $parameters['postBody']->toSimpleObject();
         } else {
             if (is_object($parameters['postBody'])) {
                 // If the post body is another kind of object, we will try and
                 // wrangle it into a sensible format.
                 $parameters['postBody'] = $this->convertToArrayAndStripNulls($parameters['postBody']);
             }
         }
         $postBody = json_encode($parameters['postBody']);
         unset($parameters['postBody']);
     }
     // TODO: optParams here probably should have been
     // handled already - this may well be redundant code.
     if (isset($parameters['optParams'])) {
         $optParams = $parameters['optParams'];
         unset($parameters['optParams']);
         $parameters = array_merge($parameters, $optParams);
     }
     if (!isset($method['parameters'])) {
         $method['parameters'] = array();
     }
     $method['parameters'] = array_merge($method['parameters'], $this->stackParameters);
     foreach ($parameters as $key => $val) {
         if ($key != 'postBody' && !isset($method['parameters'][$key])) {
             $this->client->getLogger()->error('Service parameter unknown', array('service' => $this->serviceName, 'resource' => $this->resourceName, 'method' => $name, 'parameter' => $key));
             throw new Exception("({$name}) unknown parameter: '{$key}'");
         }
     }
     foreach ($method['parameters'] as $paramName => $paramSpec) {
         if (isset($paramSpec['required']) && $paramSpec['required'] && !isset($parameters[$paramName])) {
             $this->client->getLogger()->error('Service parameter missing', array('service' => $this->serviceName, 'resource' => $this->resourceName, 'method' => $name, 'parameter' => $paramName));
             throw new Exception("({$name}) missing required param: '{$paramName}'");
         }
         if (isset($parameters[$paramName])) {
             $value = $parameters[$paramName];
             $parameters[$paramName] = $paramSpec;
             $parameters[$paramName]['value'] = $value;
             unset($parameters[$paramName]['required']);
         } else {
             // Ensure we don't pass nulls.
             unset($parameters[$paramName]);
         }
     }
     $this->client->getLogger()->info('Service Call', array('service' => $this->serviceName, 'resource' => $this->resourceName, 'method' => $name, 'arguments' => $parameters));
     $url = REST::createRequestUri($this->servicePath, $method['path'], $parameters);
     $httpRequest = new Request($url, $method['httpMethod'], null, $postBody);
     if ($this->rootUrl) {
         $httpRequest->setBaseComponent($this->rootUrl);
     } else {
         $httpRequest->setBaseComponent($this->client->getBasePath());
     }
     if ($postBody) {
         $contentTypeHeader = array();
         $contentTypeHeader['content-type'] = 'application/json; charset=UTF-8';
         $httpRequest->setRequestHeaders($contentTypeHeader);
         $httpRequest->setPostBody($postBody);
     }
     $httpRequest = $this->client->getAuth()->sign($httpRequest);
     $httpRequest->setExpectedClass($expected_class);
     if (isset($parameters['data']) && ($parameters['uploadType']['value'] == 'media' || $parameters['uploadType']['value'] == 'multipart')) {
         // If we are doing a simple media upload, trigger that as a convenience.
         $mfu = new MediaFileUpload($this->client, $httpRequest, isset($parameters['mimeType']) ? $parameters['mimeType']['value'] : 'application/octet-stream', $parameters['data']['value']);
     }
     if (isset($parameters['alt']) && $parameters['alt']['value'] == 'media') {
         $httpRequest->enableExpectedRaw();
     }
     if ($this->client->shouldDefer()) {
         // If we are in batch or upload mode, return the raw request.
         return $httpRequest;
     }
     return $this->client->execute($httpRequest);
 }
Example #5
0
 /**
  * Executes a Google\Http\Request and (if applicable) automatically retries
  * when errors occur.
  *
  * @param Google\Client $client
  * @param Google\Http\Request $req
  * @return array decoded result
  * @throws Google\Service\Exception on server side error (ie: not authenticated,
  *  invalid or malformed post body, invalid url)
  */
 public static function execute(Client $client, Request $req)
 {
     $runner = new Runner($client, sprintf('%s %s', $req->getRequestMethod(), $req->getUrl()), array(get_class(), 'doExecute'), array($client, $req));
     return $runner->run();
 }
 /**
  * Execute an HTTP Request
  *
  * @param Google\Http\Request $request the http request to be executed
  * @return array containing response headers, body, and http code
  * @throws Google\IO\Exception on curl or IO error
  */
 public function executeRequest(Request $request)
 {
     $default_options = stream_context_get_options(stream_context_get_default());
     $requestHttpContext = array_key_exists('http', $default_options) ? $default_options['http'] : array();
     if ($request->getPostBody()) {
         $requestHttpContext["content"] = $request->getPostBody();
     }
     $requestHeaders = $request->getRequestHeaders();
     if ($requestHeaders && is_array($requestHeaders)) {
         $headers = "";
         foreach ($requestHeaders as $k => $v) {
             $headers .= "{$k}: {$v}\r\n";
         }
         $requestHttpContext["header"] = $headers;
     }
     $requestHttpContext["method"] = $request->getRequestMethod();
     $requestHttpContext["user_agent"] = $request->getUserAgent();
     $requestSslContext = array_key_exists('ssl', $default_options) ? $default_options['ssl'] : array();
     if (!array_key_exists("cafile", $requestSslContext)) {
         $requestSslContext["cafile"] = dirname(__FILE__) . '/cacerts.pem';
     }
     $options = array("http" => array_merge(self::$DEFAULT_HTTP_CONTEXT, $requestHttpContext), "ssl" => array_merge(self::$DEFAULT_SSL_CONTEXT, $requestSslContext));
     $context = stream_context_create($options);
     $url = $request->getUrl();
     if ($request->canGzip()) {
         $url = self::ZLIB . $url;
     }
     $this->client->getLogger()->debug('Stream request', array('url' => $url, 'method' => $request->getRequestMethod(), 'headers' => $requestHeaders, 'body' => $request->getPostBody()));
     // We are trapping any thrown errors in this method only and
     // throwing an exception.
     $this->trappedErrorNumber = null;
     $this->trappedErrorString = null;
     // START - error trap.
     set_error_handler(array($this, 'trapError'));
     $fh = fopen($url, 'r', false, $context);
     restore_error_handler();
     // END - error trap.
     if ($this->trappedErrorNumber) {
         $error = sprintf("HTTP Error: Unable to connect: '%s'", $this->trappedErrorString);
         $this->client->getLogger()->error('Stream ' . $error);
         throw new Exception($error, $this->trappedErrorNumber);
     }
     $response_data = false;
     $respHttpCode = self::UNKNOWN_CODE;
     if ($fh) {
         if (isset($this->options[self::TIMEOUT])) {
             stream_set_timeout($fh, $this->options[self::TIMEOUT]);
         }
         $response_data = stream_get_contents($fh);
         fclose($fh);
         $respHttpCode = $this->getHttpResponseCode($http_response_header);
     }
     if (false === $response_data) {
         $error = sprintf("HTTP Error: Unable to connect: '%s'", $respHttpCode);
         $this->client->getLogger()->error('Stream ' . $error);
         throw new Exception($error, $respHttpCode);
     }
     $responseHeaders = $this->getHttpResponseHeaders($http_response_header);
     $this->client->getLogger()->debug('Stream response', array('code' => $respHttpCode, 'headers' => $responseHeaders, 'body' => $response_data));
     return array($response_data, $responseHeaders, $respHttpCode);
 }
 /**
  * Revoke an OAuth2 access token or refresh token. This method will revoke the current access
  * token, if a token isn't provided.
  * @throws Google\Auth\Exception
  * @param string|null $token The token (access token or a refresh token) that should be revoked.
  * @return boolean Returns True if the revocation was successful, otherwise False.
  */
 public function revokeToken($token = null)
 {
     if (!$token) {
         if (!$this->token) {
             // Not initialized, no token to actually revoke
             return false;
         } elseif (array_key_exists('refresh_token', $this->token)) {
             $token = $this->token['refresh_token'];
         } else {
             $token = $this->token['access_token'];
         }
     }
     $request = new Request(self::OAUTH2_REVOKE_URI, 'POST', array(), "token={$token}");
     $request->disableGzip();
     $response = $this->client->getIo()->makeRequest($request);
     $code = $response->getResponseHttpCode();
     if ($code == 200) {
         $this->token = null;
         return true;
     }
     return false;
 }
 public function parseResponse(Request $response)
 {
     $contentType = $response->getResponseHeader('content-type');
     $contentType = explode(';', $contentType);
     $boundary = false;
     foreach ($contentType as $part) {
         $part = explode('=', $part, 2);
         if (isset($part[0]) && 'boundary' == trim($part[0])) {
             $boundary = $part[1];
         }
     }
     $body = $response->getResponseBody();
     if ($body) {
         $body = str_replace("--{$boundary}--", "--{$boundary}", $body);
         $parts = explode("--{$boundary}", $body);
         $responses = array();
         foreach ($parts as $part) {
             $part = trim($part);
             if (!empty($part)) {
                 list($metaHeaders, $part) = explode("\r\n\r\n", $part, 2);
                 $metaHeaders = $this->client->getIo()->getHttpResponseHeaders($metaHeaders);
                 $status = substr($part, 0, strpos($part, "\n"));
                 $status = explode(" ", $status);
                 $status = $status[1];
                 list($partHeaders, $partBody) = $this->client->getIo()->ParseHttpResponse($part, false);
                 $response = new Request("");
                 $response->setResponseHttpCode($status);
                 $response->setResponseHeaders($partHeaders);
                 $response->setResponseBody($partBody);
                 // Need content id.
                 $key = $metaHeaders['content-id'];
                 if (isset($this->expected_classes[$key]) && strlen($this->expected_classes[$key]) > 0) {
                     $class = $this->expected_classes[$key];
                     $response->setExpectedClass($class);
                 }
                 try {
                     $response = REST::decodeHttpResponse($response, $this->client);
                     $responses[$key] = $response;
                 } catch (Exception $e) {
                     // Store the exception as the response, so successful responses
                     // can be processed.
                     $responses[$key] = $e;
                 }
             }
         }
         return $responses;
     }
     return null;
 }
 /**
  * Include an accessToken in a given apiHttpRequest.
  * @param Google\Http\Request $request
  * @return Google\Http\Request
  * @throws Google\Auth\Exception
  */
 public function sign(Request $request)
 {
     if ($this->isAccessTokenExpired()) {
         $this->acquireAccessToken();
     }
     $this->client->getLogger()->debug('Compute engine service account authentication');
     $request->setRequestHeaders(array('Authorization' => 'Bearer ' . $this->token['access_token']));
     return $request;
 }
 /**
  * Update a cached request, using the headers from the last response.
  * @param Google\Http\Request $cached A previously cached response.
  * @param mixed Associative array of response headers from the last request.
  */
 protected function updateCachedRequest($cached, $responseHeaders)
 {
     $hopByHop = self::$HOP_BY_HOP;
     if (!empty($responseHeaders['connection'])) {
         $connectionHeaders = array_map('strtolower', array_filter(array_map('trim', explode(',', $responseHeaders['connection']))));
         $hopByHop += array_fill_keys($connectionHeaders, true);
     }
     $endToEnd = array_diff_key($responseHeaders, $hopByHop);
     $cached->setResponseHeaders($endToEnd);
 }
 /**
  * @visible for testing
  * Process an http request that contains an enclosed entity.
  * @param Google\Http\Request $request
  * @return Google\Http\Request Processed request with the enclosed entity.
  */
 public function processEntityRequest(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;
 }
 /**
  * @static
  * @param Google\Http\Request $resp
  * @return bool True if the HTTP response is considered to be expired.
  * False if it is considered to be fresh.
  */
 public static function isExpired(Request $resp)
 {
     // HTTP/1.1 clients and caches MUST treat other invalid date formats,
     // especially including the value “0”, as in the past.
     $parsedExpires = false;
     $responseHeaders = $resp->getResponseHeaders();
     if (isset($responseHeaders['expires'])) {
         $rawExpires = $responseHeaders['expires'];
         // Check for a malformed expires header first.
         if (empty($rawExpires) || is_numeric($rawExpires) && $rawExpires <= 0) {
             return true;
         }
         // See if we can parse the expires header.
         $parsedExpires = strtotime($rawExpires);
         if (false == $parsedExpires || $parsedExpires <= 0) {
             return true;
         }
     }
     // Calculate the freshness of an http response.
     $freshnessLifetime = false;
     $cacheControl = $resp->getParsedCacheControl();
     if (isset($cacheControl['max-age'])) {
         $freshnessLifetime = $cacheControl['max-age'];
     }
     $rawDate = $resp->getResponseHeader('date');
     $parsedDate = strtotime($rawDate);
     if (empty($rawDate) || false == $parsedDate) {
         // We can't default this to now, as that means future cache reads
         // will always pass with the logic below, so we will require a
         // date be injected if not supplied.
         throw new Exception("All cacheable requests must have creation dates.");
     }
     if (false == $freshnessLifetime && isset($responseHeaders['expires'])) {
         $freshnessLifetime = $parsedExpires - $parsedDate;
     }
     if (false == $freshnessLifetime) {
         return true;
     }
     // Calculate the age of an http response.
     $age = max(0, time() - $parsedDate);
     if (isset($responseHeaders['age'])) {
         $age = max($age, strtotime($responseHeaders['age']));
     }
     return $freshnessLifetime <= $age;
 }
Example #13
0
 /**
  * Execute an HTTP Request
  *
  * @param Google\Http\Request $request the http request to be executed
  * @return array containing response headers, body, and http code
  * @throws Google\IO\Exception on curl or IO error
  */
 public function executeRequest(Request $request)
 {
     $curl = curl_init();
     if ($request->getPostBody()) {
         curl_setopt($curl, CURLOPT_POSTFIELDS, $request->getPostBody());
     }
     $requestHeaders = $request->getRequestHeaders();
     if ($requestHeaders && is_array($requestHeaders)) {
         $curlHeaders = array();
         foreach ($requestHeaders as $k => $v) {
             $curlHeaders[] = "{$k}: {$v}";
         }
         curl_setopt($curl, CURLOPT_HTTPHEADER, $curlHeaders);
     }
     curl_setopt($curl, CURLOPT_URL, $request->getUrl());
     curl_setopt($curl, CURLOPT_CUSTOMREQUEST, $request->getRequestMethod());
     curl_setopt($curl, CURLOPT_USERAGENT, $request->getUserAgent());
     curl_setopt($curl, CURLOPT_FOLLOWLOCATION, false);
     curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, true);
     // 1 is CURL_SSLVERSION_TLSv1, which is not always defined in PHP.
     curl_setopt($curl, CURLOPT_SSLVERSION, 1);
     curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
     curl_setopt($curl, CURLOPT_HEADER, true);
     if ($request->canGzip()) {
         curl_setopt($curl, CURLOPT_ENCODING, 'gzip,deflate');
     }
     $options = $this->client->getClassConfig('Google\\IO\\Curl', 'options');
     if (is_array($options)) {
         $this->setOptions($options);
     }
     foreach ($this->options as $key => $var) {
         curl_setopt($curl, $key, $var);
     }
     if (!isset($this->options[CURLOPT_CAINFO])) {
         curl_setopt($curl, CURLOPT_CAINFO, dirname(__FILE__) . '/cacerts.pem');
     }
     $this->client->getLogger()->debug('cURL request', array('url' => $request->getUrl(), 'method' => $request->getRequestMethod(), 'headers' => $requestHeaders, 'body' => $request->getPostBody()));
     $response = curl_exec($curl);
     if ($response === false) {
         $error = curl_error($curl);
         $code = curl_errno($curl);
         $map = $this->client->getClassConfig('Google\\IO\\Exception', 'retry_map');
         $this->client->getLogger()->error('cURL ' . $error);
         throw new Exception($error, $code, null, $map);
     }
     $headerSize = curl_getinfo($curl, CURLINFO_HEADER_SIZE);
     list($responseHeaders, $responseBody) = $this->parseHttpResponse($response, $headerSize);
     $responseCode = curl_getinfo($curl, CURLINFO_HTTP_CODE);
     $this->client->getLogger()->debug('cURL response', array('code' => $responseCode, 'headers' => $responseHeaders, 'body' => $responseBody));
     return array($responseBody, $responseHeaders, $responseCode);
 }
 /**
  * Send the next part of the file to upload.
  * @param [$chunk] the next set of bytes to send. If false will used $data passed
  * at construct time.
  */
 public function nextChunk($chunk = false)
 {
     if (false == $this->resumeUri) {
         $this->resumeUri = $this->getResumeUri();
     }
     if (false == $chunk) {
         $chunk = substr($this->data, $this->progress, $this->chunkSize);
     }
     $lastBytePos = $this->progress + strlen($chunk) - 1;
     $headers = array('content-range' => "bytes {$this->progress}-{$lastBytePos}/{$this->size}", 'content-type' => $this->request->getRequestHeader('content-type'), 'content-length' => $this->chunkSize, 'expect' => '');
     $httpRequest = new Request($this->resumeUri, 'PUT', $headers, $chunk);
     if ($this->client->getClassConfig("Google\\Http\\Request", "enable_gzip_for_uploads")) {
         $httpRequest->enableGzip();
     } else {
         $httpRequest->disableGzip();
     }
     $response = $this->client->getIo()->makeRequest($httpRequest);
     $response->setExpectedClass($this->request->getExpectedClass());
     $code = $response->getResponseHttpCode();
     $this->httpResultCode = $code;
     if (308 == $code) {
         // Track the amount uploaded.
         $range = explode('-', $response->getResponseHeader('range'));
         $this->progress = $range[1] + 1;
         // Allow for changing upload URLs.
         $location = $response->getResponseHeader('location');
         if ($location) {
             $this->resumeUri = $location;
         }
         // No problems, but upload not complete.
         return false;
     } else {
         return REST::decodeHttpResponse($response, $this->client);
     }
 }