Нема описа

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  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. use Google\Auth\HttpHandler\HttpHandlerFactory;
  18. use GuzzleHttp\ClientInterface;
  19. use GuzzleHttp\Exception\RequestException;
  20. use GuzzleHttp\Psr7\Response;
  21. use Psr\Http\Message\RequestInterface;
  22. use Psr\Http\Message\ResponseInterface;
  23. /**
  24. * This class implements the RESTful transport of apiServiceRequest()'s
  25. */
  26. class Google_Http_REST
  27. {
  28. /**
  29. * Executes a Psr\Http\Message\RequestInterface and (if applicable) automatically retries
  30. * when errors occur.
  31. *
  32. * @param Google_Client $client
  33. * @param Psr\Http\Message\RequestInterface $req
  34. * @return array decoded result
  35. * @throws Google_Service_Exception on server side error (ie: not authenticated,
  36. * invalid or malformed post body, invalid url)
  37. */
  38. public static function execute(
  39. ClientInterface $client,
  40. RequestInterface $request,
  41. $expectedClass = null,
  42. $config = array(),
  43. $retryMap = null
  44. ) {
  45. $runner = new Google_Task_Runner(
  46. $config,
  47. sprintf('%s %s', $request->getMethod(), (string) $request->getUri()),
  48. array(get_class(), 'doExecute'),
  49. array($client, $request, $expectedClass)
  50. );
  51. if (null !== $retryMap) {
  52. $runner->setRetryMap($retryMap);
  53. }
  54. return $runner->run();
  55. }
  56. /**
  57. * Executes a Psr\Http\Message\RequestInterface
  58. *
  59. * @param Google_Client $client
  60. * @param Psr\Http\Message\RequestInterface $request
  61. * @return array decoded result
  62. * @throws Google_Service_Exception on server side error (ie: not authenticated,
  63. * invalid or malformed post body, invalid url)
  64. */
  65. public static function doExecute(ClientInterface $client, RequestInterface $request, $expectedClass = null)
  66. {
  67. try {
  68. $httpHandler = HttpHandlerFactory::build($client);
  69. $response = $httpHandler($request);
  70. } catch (RequestException $e) {
  71. // if Guzzle throws an exception, catch it and handle the response
  72. if (!$e->hasResponse()) {
  73. throw $e;
  74. }
  75. $response = $e->getResponse();
  76. // specific checking for Guzzle 5: convert to PSR7 response
  77. if ($response instanceof \GuzzleHttp\Message\ResponseInterface) {
  78. $response = new Response(
  79. $response->getStatusCode(),
  80. $response->getHeaders() ?: [],
  81. $response->getBody(),
  82. $response->getProtocolVersion(),
  83. $response->getReasonPhrase()
  84. );
  85. }
  86. }
  87. return self::decodeHttpResponse($response, $request, $expectedClass);
  88. }
  89. /**
  90. * Decode an HTTP Response.
  91. * @static
  92. * @throws Google_Service_Exception
  93. * @param Psr\Http\Message\RequestInterface $response The http response to be decoded.
  94. * @param Psr\Http\Message\ResponseInterface $response
  95. * @return mixed|null
  96. */
  97. public static function decodeHttpResponse(
  98. ResponseInterface $response,
  99. RequestInterface $request = null,
  100. $expectedClass = null
  101. ) {
  102. $code = $response->getStatusCode();
  103. // retry strategy
  104. if (intVal($code) >= 400) {
  105. // if we errored out, it should be safe to grab the response body
  106. $body = (string) $response->getBody();
  107. // Check if we received errors, and add those to the Exception for convenience
  108. throw new Google_Service_Exception($body, $code, null, self::getResponseErrors($body));
  109. }
  110. // Ensure we only pull the entire body into memory if the request is not
  111. // of media type
  112. $body = self::decodeBody($response, $request);
  113. if ($expectedClass = self::determineExpectedClass($expectedClass, $request)) {
  114. $json = json_decode($body, true);
  115. return new $expectedClass($json);
  116. }
  117. return $response;
  118. }
  119. private static function decodeBody(ResponseInterface $response, RequestInterface $request = null)
  120. {
  121. if (self::isAltMedia($request)) {
  122. // don't decode the body, it's probably a really long string
  123. return '';
  124. }
  125. return (string) $response->getBody();
  126. }
  127. private static function determineExpectedClass($expectedClass, RequestInterface $request = null)
  128. {
  129. // "false" is used to explicitly prevent an expected class from being returned
  130. if (false === $expectedClass) {
  131. return null;
  132. }
  133. // if we don't have a request, we just use what's passed in
  134. if (null === $request) {
  135. return $expectedClass;
  136. }
  137. // return what we have in the request header if one was not supplied
  138. return $expectedClass ?: $request->getHeaderLine('X-Php-Expected-Class');
  139. }
  140. private static function getResponseErrors($body)
  141. {
  142. $json = json_decode($body, true);
  143. if (isset($json['error']['errors'])) {
  144. return $json['error']['errors'];
  145. }
  146. return null;
  147. }
  148. private static function isAltMedia(RequestInterface $request = null)
  149. {
  150. if ($request && $qs = $request->getUri()->getQuery()) {
  151. parse_str($qs, $query);
  152. if (isset($query['alt']) && $query['alt'] == 'media') {
  153. return true;
  154. }
  155. }
  156. return false;
  157. }
  158. }