/** * Validate the HTTP response and throw exceptions on errors * * @throws ServerException */ private function validateResponse() { if ($this->httpResponse->getStatusCode() !== 200) { $statusCode = $this->httpResponse->getStatusCode(); throw new ServerException('Server responded with HTTP status ' . $statusCode, $statusCode); } else { if (strpos($this->httpResponse->getHeader('Content-Type'), 'application/json') === false) { throw new ServerException('Server did not respond with the expected content-type (application/json)'); } } try { $this->httpResponse->json(); } catch (RuntimeException $e) { throw new ServerException($e->getMessage()); } }
/** * Parses additional exception information from the response headers * * @param RequestInterface $request Request that was issued * @param Response $response The response from the request * @param array $data The current set of exception data */ protected function parseHeaders(RequestInterface $request, Response $response, array &$data) { $data['message'] = $response->getStatusCode() . ' ' . $response->getReasonPhrase(); if ($requestId = $response->getHeader('x-amz-request-id')) { $data['request_id'] = $requestId; $data['message'] .= " (Request-ID: {$requestId})"; } }
/** * Check the response for an error. * * @param Response $response The response received. * * @param RequestInterface $request The request sent. * * @return void * * @throws \RuntimeException On any error. */ protected function checkError(Response $response, RequestInterface $request) { if ($response->getStatusCode() == 200 || $response->getStatusCode() == 201) { return; } switch ($response->getHeader('Content-Type')) { case 'text/plain': throw new \RuntimeException('Error: ' . $response->getBody(true) . ' URI: ' . $request->getUrl()); case 'application/json': $error = json_decode($response->getBody(true)); if (isset($error->message)) { throw new \RuntimeException($error->message . ' URI: ' . $request->getUrl()); } break; default: throw new \RuntimeException('Unknown Error: No error message was returned from the server - Code: ' . $response->getStatusCode() . ' URI: ' . $response->getRequest()->getUrl()); } }
/** * Seconds remaining until a new time window opens * * @return null */ public function getRateReset() { if (!$this->lastResponse) { return null; } /** @var Header $limit */ $limit = $this->lastResponse->getHeader('X-Rate-Reset'); return $limit ? $limit->normalize() : null; }
public function testOnRequestSuccess() { $event = new Event(); $response = new Response(200, array('X-RateLimit-Limit' => array(30), 'X-RateLimit-Remaining' => array(29), 'X-RateLimit-Reset' => array(10))); $event['response'] = $response; $plugin = new RateLimitPlugin(); $plugin->onRequestSuccess($event); $this->assertAttributeEquals((string) $response->getHeader('X-RateLimit-Limit'), 'rateLimitMax', $plugin); $this->assertAttributeEquals((string) $response->getHeader('X-RateLimit-Remaining'), 'rateLimitRemaining', $plugin); $this->assertAttributeEquals((string) $response->getHeader('X-RateLimit-Reset'), 'rateLimitReset', $plugin); $this->assertAttributeEquals(true, 'rateLimitEnabled', $plugin); }
/** * {@inheritdoc} */ public function getLatestResponseHeaders() { if (null === $this->response) { return; } return ['reset' => (int) (string) $this->response->getHeader('RateLimit-Reset'), 'remaining' => (int) (string) $this->response->getHeader('RateLimit-Remaining'), 'limit' => (int) (string) $this->response->getHeader('RateLimit-Limit')]; }
public static function getApiLimit(Response $response) { $remainingCalls = $response->getHeader('X-RateLimit-Remaining'); if (null !== $remainingCalls && 1 > $remainingCalls) { throw new ApiLimitExceedException($remainingCalls); } }
public function cache(RequestInterface $request, Response $response) { $currentTime = time(); $ttl = $request->getParams()->get('cache.override_ttl') ?: $response->getMaxAge() ?: $this->defaultTtl; if ($cacheControl = $response->getHeader('Cache-Control')) { $stale = $cacheControl->getDirective('stale-if-error'); $ttl += $stale == true ? $ttl : $stale; } // Determine which manifest key should be used $key = $this->getCacheKey($request); $persistedRequest = $this->persistHeaders($request); $entries = array(); if ($manifest = $this->cache->fetch($key)) { // Determine which cache entries should still be in the cache $vary = $response->getVary(); foreach (unserialize($manifest) as $entry) { // Check if the entry is expired if ($entry[4] < $currentTime) { continue; } $entry[1]['vary'] = isset($entry[1]['vary']) ? $entry[1]['vary'] : ''; if ($vary != $entry[1]['vary'] || !$this->requestsMatch($vary, $entry[0], $persistedRequest)) { $entries[] = $entry; } } } // Persist the response body if needed $bodyDigest = null; if ($response->getBody() && $response->getBody()->getContentLength() > 0) { $bodyDigest = $this->getBodyKey($request->getUrl(), $response->getBody()); $this->cache->save($bodyDigest, (string) $response->getBody(), $ttl); } array_unshift($entries, array($persistedRequest, $this->persistHeaders($response), $response->getStatusCode(), $bodyDigest, $currentTime + $ttl)); $this->cache->save($key, serialize($entries)); }
public static function decode(Response $response) { if (strpos($response->getHeader(Header::CONTENT_TYPE), Mime::JSON) !== false) { $string = (string) $response->getBody(); $response = json_decode($string); self::checkJsonError($string); return $response; } }
/** * {@inheritdoc} */ protected function getDelay($retries, RequestInterface $request, Response $response = null, HttpException $e = null) { if ($response) { // Validate the checksum against our computed checksum if ($checksum = (string) $response->getHeader('x-amz-crc32')) { // Retry the request if the checksums don't match, otherwise, return null return $checksum != hexdec(Stream::getHash($response->getBody(), 'crc32b')) ? true : null; } } }
protected function getDelay($retries, RequestInterface $request, Response $response = null, HttpException $e = null) { if ($response) { //Short circuit the rest of the checks if it was successful if ($response->isSuccessful()) { return false; } else { if (isset($this->errorCodes[$response->getStatusCode()])) { if ($response->getHeader("Retry-After")) { return $response->getHeader("Retry-After")->__toString(); } else { return self::$defaultRetryAfter; } } else { return null; } } } }
/** * {@inheritdoc} */ public function parse(Response $response) { $data = array('code' => null, 'message' => null, 'type' => $response->isClientError() ? 'client' : 'server', 'request_id' => (string) $response->getHeader('x-amzn-RequestId'), 'parsed' => null); if (null !== ($json = json_decode($response->getBody(true), true))) { $data['parsed'] = $json; $json = array_change_key_case($json); $data = $this->doParse($data, $json); } return $data; }
public static function factory(RequestInterface $request, Response $response) { $label = 'Bearer error response'; $bearerReason = self::headerToReason($response->getHeader("WWW-Authenticate")); $message = $label . PHP_EOL . implode(PHP_EOL, array('[status code] ' . $response->getStatusCode(), '[reason phrase] ' . $response->getReasonPhrase(), '[bearer reason] ' . $bearerReason, '[url] ' . $request->getUrl())); $e = new static($message); $e->setResponse($response); $e->setRequest($request); $e->setBearerReason($bearerReason); return $e; }
private function getContextFromResponse(Response $response) { $extraFields = array(); $headersToLookFor = array('x-served-by', 'x-backend', 'x-location', 'x-varnish'); foreach ($headersToLookFor as $headerName) { if ($response->hasHeader($headerName)) { $extraFields[$headerName] = (string) $response->getHeader($headerName); } } return $extraFields; }
/** * Get the amount of time to delay in seconds before retrying a request * * @param int $retries Number of retries of the request * @param RequestInterface $request Request that was sent * @param Response $response Response that was received. Note that there may not be a response * @param HttpException $e Exception that was encountered if any * * @return bool|int Returns false to not retry or the number of seconds to delay between retries */ public function getBackoffPeriod($retries, RequestInterface $request, Response $response = null, HttpException $e = null) { if (!$response) { return false; } if ($response->getStatusCode() != 429) { return false; } $reset = (string) $response->getHeader('X-Rate-Limit-Reset'); if (!preg_match('/^[0-9]+$/', $reset)) { return false; } return ((int) $reset + 0.1) * $this->getMultiplier(); }
/** * {@inheritdoc} */ protected function doParse(array $data, Response $response) { // Merge in error data from the JSON body if ($json = $data['parsed']) { $data = array_replace($data, $json); } // Correct error type from services like Amazon Glacier if (!empty($data['type'])) { $data['type'] = strtolower($data['type']); } // Retrieve the error code from services like Amazon Elastic Transcoder if ($code = (string) $response->getHeader('x-amzn-ErrorType')) { $data['code'] = substr($code, 0, strpos($code, ':')); } return $data; }
/** * {@inheritdoc} */ public function parse(RequestInterface $request, Response $response) { // Build array of default error data $data = array('code' => null, 'message' => null, 'type' => $response->isClientError() ? 'client' : 'server', 'request_id' => (string) $response->getHeader('x-amzn-RequestId'), 'parsed' => null); // Parse the json and normalize key casings if (null !== ($json = json_decode($response->getBody(true), true))) { $data['parsed'] = array_change_key_case($json); } // Do additional, protocol-specific parsing and return the result $data = $this->doParse($data, $response); // Remove "Fault" suffix from exception names if (isset($data['code']) && strpos($data['code'], 'Fault')) { $data['code'] = preg_replace('/^([a-zA-Z]+)Fault$/', '$1', $data['code']); } return $data; }
/** * @param string $errorName * @param \Guzzle\Http\Message\Response $response * @param int $statusCode * @return \Phobetor\Billomat\Exception\ExceptionInterface */ public function createExceptionFromStatusCode($errorName, $response, $statusCode) { $exception = null; switch ($statusCode) { case self::STATUS_NOT_FOUND: return new NotFoundException($errorName, $statusCode); case self::STATUS_BAD_REQUEST: return new BadRequestException($errorName, $statusCode); case self::STATUS_UNAUTHORIZED: return new UnauthorizedException($errorName, $statusCode); case self::STATUS_TOO_MANY_REQUESTS: $exception = new TooManyRequestsException($errorName, $statusCode); if ($response->hasHeader('X-Rate-Limit-Remaining')) { $exception->setRateLimitRemaining((int) (string) $response->getHeader('X-Rate-Limit-Remaining')); } if ($response->hasHeader('X-Rate-Limit-Reset')) { $exception->setRateLimitReset((int) (string) $response->getHeader('X-Rate-Limit-Reset')); } return $exception; default: return new UnknownErrorException($errorName, $statusCode); } }
public function getHeader($name) { return $this->_response->getHeader($name); }
public function addCookiesFromResponse(Response $response, RequestInterface $request = null) { if ($cookieHeader = $response->getHeader('Set-Cookie')) { $parser = ParserRegistry::getInstance()->getParser('cookie'); foreach ($cookieHeader as $cookie) { if ($parsed = $request ? $parser->parseCookie($cookie, $request->getHost(), $request->getPath()) : $parser->parseCookie($cookie)) { // Break up cookie v2 into multiple cookies foreach ($parsed['cookies'] as $key => $value) { $row = $parsed; $row['name'] = $key; $row['value'] = $value; unset($row['cookies']); $this->add(new Cookie($row)); } } } } }
/** * Add the plugin's headers to a response * * @param RequestInterface $request Request * @param Response $response Response to add headers to */ protected function addResponseHeaders(RequestInterface $request, Response $response) { $params = $request->getParams(); $response->setHeader('Via', sprintf('%s GuzzleCache/%s', $request->getProtocolVersion(), Version::VERSION)); $lookup = ($params['cache.lookup'] === true ? 'HIT' : 'MISS') . ' from GuzzleCache'; if ($header = $response->getHeader('X-Cache-Lookup')) { // Don't add duplicates $values = $header->toArray(); $values[] = $lookup; $response->setHeader('X-Cache-Lookup', array_unique($values)); } else { $response->setHeader('X-Cache-Lookup', $lookup); } if ($params['cache.hit'] === true) { $xcache = 'HIT from GuzzleCache'; } elseif ($params['cache.hit'] == 'error') { $xcache = 'HIT_ERROR from GuzzleCache'; } else { $xcache = 'MISS from GuzzleCache'; } if ($header = $response->getHeader('X-Cache')) { // Don't add duplicates $values = $header->toArray(); $values[] = $xcache; $response->setHeader('X-Cache', array_unique($values)); } else { $response->setHeader('X-Cache', $xcache); } if ($response->isFresh() === false) { $response->addHeader('Warning', sprintf('110 GuzzleCache/%s "Response is stale"', Version::VERSION)); if ($params['cache.hit'] === 'error') { $response->addHeader('Warning', sprintf('111 GuzzleCache/%s "Revalidation failed"', Version::VERSION)); } } }
/** * Handle a 304 response and ensure that it is still valid * * @param RequestInterface $request Request that was sent * @param Response $validateResponse Response received * @param Response $response Original cached response * * @return bool Returns true if valid, false if invalid */ protected function handle304Response(RequestInterface $request, Response $validateResponse, Response $response) { static $replaceHeaders = array('Date', 'Expires', 'Cache-Control', 'ETag', 'Last-Modified'); // Make sure that this response has the same ETag if ($validateResponse->getEtag() != $response->getEtag()) { return false; } // Replace cached headers with any of these headers from the // origin server that might be more up to date $modified = false; foreach ($replaceHeaders as $name) { if ($validateResponse->hasHeader($name)) { $modified = true; $response->setHeader($name, $validateResponse->getHeader($name)); } } // Store the updated response in cache if ($modified && $this->canCache->canCacheResponse($response)) { $this->storage->cache($request, $response); } return true; }
/** * Returns a formatted message * * @param RequestInterface $request Request that was sent * @param Response $response Response that was received * @param CurlHandle $handle Curl handle associated with the message * @param array $customData Associative array of custom template data * * @return string */ public function format(RequestInterface $request, Response $response = null, CurlHandle $handle = null, array $customData = array()) { $cache = $customData; return preg_replace_callback('/{\\s*([A-Za-z_\\-\\.0-9]+)\\s*}/', function (array $matches) use($request, $response, $handle, &$cache) { if (array_key_exists($matches[1], $cache)) { return $cache[$matches[1]]; } $result = ''; switch ($matches[1]) { case 'request': $result = (string) $request; break; case 'response': $result = (string) $response; break; case 'req_body': $result = $request instanceof EntityEnclosingRequestInterface ? (string) $request->getBody() : ''; break; case 'res_body': $result = $response ? $response->getBody(true) : ''; break; case 'ts': $result = gmdate('c'); break; case 'method': $result = $request->getMethod(); break; case 'url': $result = (string) $request->getUrl(); break; case 'resource': $result = $request->getResource(); break; case 'protocol': $result = 'HTTP'; break; case 'version': $result = $request->getProtocolVersion(); break; case 'host': $result = $request->getHost(); break; case 'hostname': $result = gethostname(); break; case 'port': $result = $request->getPort(); break; case 'code': $result = $response ? $response->getStatusCode() : ''; break; case 'phrase': $result = $response ? $response->getReasonPhrase() : ''; break; case 'connect_time': if ($handle) { $result = $handle->getInfo(CURLINFO_CONNECT_TIME); } elseif ($response) { $result = $response->getInfo('connect_time'); } break; case 'total_time': if ($handle) { $result = $handle->getInfo(CURLINFO_TOTAL_TIME); } elseif ($response) { $result = $response->getInfo('total_time'); } break; case 'curl_error': $result = $handle ? $handle->getError() : ''; break; case 'curl_code': $result = $handle ? $handle->getErrorNo() : ''; break; case 'curl_stderr': $result = $handle ? $handle->getStderr() : ''; break; default: if (strpos($matches[1], 'req_header_') === 0) { $result = $request->getHeader(substr($matches[1], 11)); } elseif (strpos($matches[1], 'res_header_') === 0) { $result = $response->getHeader(substr($matches[1], 11)); } } $cache[$matches[1]] = $result; return $result; }, $this->template); }
/** * @param $header * @param bool $string * @return \Guzzle\Http\Message\Header|null|string */ public function getHeader($header, $string = false) { return $this->response->getHeader($header, $string); }
/** * {@inheritdoc} */ public function getHeader($header) { return $this->response->getHeader($header); }
/** * Check if a cache response satisfies a failed request's caching constraints * * @param RequestInterface $request Request to validate * @param Response $response Response to validate * * @return bool */ public function canResponseSatisfyFailedRequest(RequestInterface $request, Response $response) { $reqc = $request->getHeader('Cache-Control'); $resc = $response->getHeader('Cache-Control'); $requestStaleIfError = $reqc ? $reqc->getDirective('stale-if-error') : null; $responseStaleIfError = $resc ? $resc->getDirective('stale-if-error') : null; if (!$requestStaleIfError && !$responseStaleIfError) { return false; } if (is_numeric($requestStaleIfError) && $response->getAge() - $response->getMaxAge() > $requestStaleIfError) { return false; } if (is_numeric($responseStaleIfError) && $response->getAge() - $response->getMaxAge() > $responseStaleIfError) { return false; } return true; }
/** * @param Response $response * @return mixed */ protected function decompressGzippedResponse($response) { $raw_data = $response->getBody(); if ($response->getHeader('content-encoding') === 'gzip') { // return gzip.GzipFile(fileobj=StringIO.StringIO(raw_data)).read(); } return $raw_data; }
/** * @dataProvider parseParamsProvider */ public function testParseParams($header, $result) { $response = new Response(200, array('Link' => $header)); $this->assertEquals($result, $response->getHeader('Link')->parseParams()); }
/** * Prepare the request for redirection and enforce the maximum number of allowed redirects per client * * @param RequestInterface $original Origina request * @param RequestInterface $request Request to prepare and validate * @param Response $response The current response * * @return RequestInterface */ protected function prepareRedirection(RequestInterface $original, RequestInterface $request, Response $response) { $params = $original->getParams(); // This is a new redirect, so increment the redirect counter $current = $params->get(self::REDIRECT_COUNT) + 1; $params->set(self::REDIRECT_COUNT, $current); // Use a provided maximum value or default to a max redirect count of 5 $max = $params->hasKey(self::MAX_REDIRECTS) ? $params->get(self::MAX_REDIRECTS) : $this->defaultMaxRedirects; // Throw an exception if the redirect count is exceeded if ($current > $max) { $this->throwTooManyRedirectsException($original, $max); return false; } else { // Create a redirect request based on the redirect rules set on the request return $this->createRedirectRequest($request, $response->getStatusCode(), trim($response->getHeader('Location')), $original); } }
/** * Construct a TransferPart from a HTTP response delivered by the API. * * @param Response $response * @param int $partNumber * @return TransferPart */ public static function fromResponse(Response $response, $partNumber = 1) { $responseUri = Url::factory($response->getEffectiveUrl()); $object = new self(); $object->setPartNumber($partNumber)->setContentLength($response->getHeader(Header::CONTENT_LENGTH))->setETag($response->getHeader(Header::ETAG))->setPath($responseUri->getPath()); return $object; }