RequestException.php 4.4 KB

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