RequestException.php 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. <?php
  2. namespace GuzzleHttp\Exception;
  3. use GuzzleHttp\Promise\PromiseInterface;
  4. use Psr\Http\Message\RequestInterface;
  5. use Psr\Http\Message\ResponseInterface;
  6. use Psr\Http\Message\UriInterface;
  7. /**
  8. * HTTP Request exception
  9. */
  10. class RequestException extends TransferException
  11. {
  12. /** @var RequestInterface */
  13. private $request;
  14. /** @var ResponseInterface|null */
  15. private $response;
  16. /** @var array */
  17. private $handlerContext;
  18. public function __construct(
  19. $message,
  20. RequestInterface $request,
  21. ResponseInterface $response = null,
  22. \Exception $previous = null,
  23. array $handlerContext = []
  24. ) {
  25. // Set the code of the exception if the response is set and not future.
  26. $code = $response && !($response instanceof PromiseInterface)
  27. ? $response->getStatusCode()
  28. : 0;
  29. parent::__construct($message, $code, $previous);
  30. $this->request = $request;
  31. $this->response = $response;
  32. $this->handlerContext = $handlerContext;
  33. }
  34. /**
  35. * Wrap non-RequestExceptions with a RequestException
  36. *
  37. * @param RequestInterface $request
  38. * @param \Exception $e
  39. *
  40. * @return RequestException
  41. */
  42. public static function wrapException(RequestInterface $request, \Exception $e)
  43. {
  44. return $e instanceof RequestException
  45. ? $e
  46. : new RequestException($e->getMessage(), $request, null, $e);
  47. }
  48. /**
  49. * Factory method to create a new exception with a normalized error message
  50. *
  51. * @param RequestInterface $request Request
  52. * @param ResponseInterface $response Response received
  53. * @param \Exception $previous Previous exception
  54. * @param array $ctx Optional handler context.
  55. *
  56. * @return self
  57. */
  58. public static function create(
  59. RequestInterface $request,
  60. ResponseInterface $response = null,
  61. \Exception $previous = null,
  62. array $ctx = []
  63. ) {
  64. if (!$response) {
  65. return new self(
  66. 'Error completing request',
  67. $request,
  68. null,
  69. $previous,
  70. $ctx
  71. );
  72. }
  73. $level = (int) floor($response->getStatusCode() / 100);
  74. if ($level === 4) {
  75. $label = 'Client error';
  76. $className = ClientException::class;
  77. } elseif ($level === 5) {
  78. $label = 'Server error';
  79. $className = ServerException::class;
  80. } else {
  81. $label = 'Unsuccessful request';
  82. $className = __CLASS__;
  83. }
  84. $uri = $request->getUri();
  85. $uri = static::obfuscateUri($uri);
  86. // Client Error: `GET /` resulted in a `404 Not Found` response:
  87. // <html> ... (truncated)
  88. $message = sprintf(
  89. '%s: `%s %s` resulted in a `%s %s` response',
  90. $label,
  91. $request->getMethod(),
  92. $uri,
  93. $response->getStatusCode(),
  94. $response->getReasonPhrase()
  95. );
  96. $summary = static::getResponseBodySummary($response);
  97. if ($summary !== null) {
  98. $message .= ":\n{$summary}\n";
  99. }
  100. return new $className($message, $request, $response, $previous, $ctx);
  101. }
  102. /**
  103. * Get a short summary of the response
  104. *
  105. * Will return `null` if the response is not printable.
  106. *
  107. * @param ResponseInterface $response
  108. *
  109. * @return string|null
  110. */
  111. public static function getResponseBodySummary(ResponseInterface $response)
  112. {
  113. return \GuzzleHttp\Psr7\get_message_body_summary($response);
  114. }
  115. /**
  116. * Obfuscates URI if there is a username and a password present
  117. *
  118. * @param UriInterface $uri
  119. *
  120. * @return UriInterface
  121. */
  122. private static function obfuscateUri(UriInterface $uri)
  123. {
  124. $userInfo = $uri->getUserInfo();
  125. if (false !== ($pos = strpos($userInfo, ':'))) {
  126. return $uri->withUserInfo(substr($userInfo, 0, $pos), '***');
  127. }
  128. return $uri;
  129. }
  130. /**
  131. * Get the request that caused the exception
  132. *
  133. * @return RequestInterface
  134. */
  135. public function getRequest()
  136. {
  137. return $this->request;
  138. }
  139. /**
  140. * Get the associated response
  141. *
  142. * @return ResponseInterface|null
  143. */
  144. public function getResponse()
  145. {
  146. return $this->response;
  147. }
  148. /**
  149. * Check if a response was received
  150. *
  151. * @return bool
  152. */
  153. public function hasResponse()
  154. {
  155. return $this->response !== null;
  156. }
  157. /**
  158. * Get contextual information about the error from the underlying handler.
  159. *
  160. * The contents of this array will vary depending on which handler you are
  161. * using. It may also be just an empty array. Relying on this data will
  162. * couple you to a specific handler, but can give more debug information
  163. * when needed.
  164. *
  165. * @return array
  166. */
  167. public function getHandlerContext()
  168. {
  169. return $this->handlerContext;
  170. }
  171. }