Chris@0: getStatusCode() Chris@0: : 0; Chris@0: parent::__construct($message, $code, $previous); Chris@0: $this->request = $request; Chris@0: $this->response = $response; Chris@0: $this->handlerContext = $handlerContext; Chris@0: } Chris@0: Chris@0: /** Chris@0: * Wrap non-RequestExceptions with a RequestException Chris@0: * Chris@0: * @param RequestInterface $request Chris@0: * @param \Exception $e Chris@0: * Chris@0: * @return RequestException Chris@0: */ Chris@0: public static function wrapException(RequestInterface $request, \Exception $e) Chris@0: { Chris@0: return $e instanceof RequestException Chris@0: ? $e Chris@0: : new RequestException($e->getMessage(), $request, null, $e); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Factory method to create a new exception with a normalized error message Chris@0: * Chris@0: * @param RequestInterface $request Request Chris@0: * @param ResponseInterface $response Response received Chris@0: * @param \Exception $previous Previous exception Chris@0: * @param array $ctx Optional handler context. Chris@0: * Chris@0: * @return self Chris@0: */ Chris@0: public static function create( Chris@0: RequestInterface $request, Chris@0: ResponseInterface $response = null, Chris@0: \Exception $previous = null, Chris@0: array $ctx = [] Chris@0: ) { Chris@0: if (!$response) { Chris@0: return new self( Chris@0: 'Error completing request', Chris@0: $request, Chris@0: null, Chris@0: $previous, Chris@0: $ctx Chris@0: ); Chris@0: } Chris@0: Chris@0: $level = (int) floor($response->getStatusCode() / 100); Chris@0: if ($level === 4) { Chris@0: $label = 'Client error'; Chris@0: $className = ClientException::class; Chris@0: } elseif ($level === 5) { Chris@0: $label = 'Server error'; Chris@0: $className = ServerException::class; Chris@0: } else { Chris@0: $label = 'Unsuccessful request'; Chris@0: $className = __CLASS__; Chris@0: } Chris@0: Chris@0: $uri = $request->getUri(); Chris@0: $uri = static::obfuscateUri($uri); Chris@0: Chris@0: // Client Error: `GET /` resulted in a `404 Not Found` response: Chris@0: // ... (truncated) Chris@0: $message = sprintf( Chris@0: '%s: `%s %s` resulted in a `%s %s` response', Chris@0: $label, Chris@0: $request->getMethod(), Chris@0: $uri, Chris@0: $response->getStatusCode(), Chris@0: $response->getReasonPhrase() Chris@0: ); Chris@0: Chris@0: $summary = static::getResponseBodySummary($response); Chris@0: Chris@0: if ($summary !== null) { Chris@0: $message .= ":\n{$summary}\n"; Chris@0: } Chris@0: Chris@0: return new $className($message, $request, $response, $previous, $ctx); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Get a short summary of the response Chris@0: * Chris@0: * Will return `null` if the response is not printable. Chris@0: * Chris@0: * @param ResponseInterface $response Chris@0: * Chris@0: * @return string|null Chris@0: */ Chris@0: public static function getResponseBodySummary(ResponseInterface $response) Chris@0: { Chris@0: $body = $response->getBody(); Chris@0: Chris@0: if (!$body->isSeekable()) { Chris@0: return null; Chris@0: } Chris@0: Chris@0: $size = $body->getSize(); Chris@0: Chris@0: if ($size === 0) { Chris@0: return null; Chris@0: } Chris@0: Chris@0: $summary = $body->read(120); Chris@0: $body->rewind(); Chris@0: Chris@0: if ($size > 120) { Chris@0: $summary .= ' (truncated...)'; Chris@0: } Chris@0: Chris@0: // Matches any printable character, including unicode characters: Chris@0: // letters, marks, numbers, punctuation, spacing, and separators. Chris@0: if (preg_match('/[^\pL\pM\pN\pP\pS\pZ\n\r\t]/', $summary)) { Chris@0: return null; Chris@0: } Chris@0: Chris@0: return $summary; Chris@0: } Chris@0: Chris@0: /** Chris@0: * Obfuscates URI if there is an username and a password present Chris@0: * Chris@0: * @param UriInterface $uri Chris@0: * Chris@0: * @return UriInterface Chris@0: */ Chris@0: private static function obfuscateUri($uri) Chris@0: { Chris@0: $userInfo = $uri->getUserInfo(); Chris@0: Chris@0: if (false !== ($pos = strpos($userInfo, ':'))) { Chris@0: return $uri->withUserInfo(substr($userInfo, 0, $pos), '***'); Chris@0: } Chris@0: Chris@0: return $uri; Chris@0: } Chris@0: Chris@0: /** Chris@0: * Get the request that caused the exception Chris@0: * Chris@0: * @return RequestInterface Chris@0: */ Chris@0: public function getRequest() Chris@0: { Chris@0: return $this->request; Chris@0: } Chris@0: Chris@0: /** Chris@0: * Get the associated response Chris@0: * Chris@0: * @return ResponseInterface|null Chris@0: */ Chris@0: public function getResponse() Chris@0: { Chris@0: return $this->response; Chris@0: } Chris@0: Chris@0: /** Chris@0: * Check if a response was received Chris@0: * Chris@0: * @return bool Chris@0: */ Chris@0: public function hasResponse() Chris@0: { Chris@0: return $this->response !== null; Chris@0: } Chris@0: Chris@0: /** Chris@0: * Get contextual information about the error from the underlying handler. Chris@0: * Chris@0: * The contents of this array will vary depending on which handler you are Chris@0: * using. It may also be just an empty array. Relying on this data will Chris@0: * couple you to a specific handler, but can give more debug information Chris@0: * when needed. Chris@0: * Chris@0: * @return array Chris@0: */ Chris@0: public function getHandlerContext() Chris@0: { Chris@0: return $this->handlerContext; Chris@0: } Chris@0: }