/** * Add headers represented by an array of header lines. * * @param string[] $headers Response headers as array of header lines. * * @return $this * * @throws \UnexpectedValueException For invalid header values. * @throws \InvalidArgumentException For invalid status code arguments. */ public function setHeadersFromArray(array $headers) { $statusLine = trim(array_shift($headers)); $parts = explode(' ', $statusLine, 3); if (count($parts) < 2 || substr(strtolower($parts[0]), 0, 5) !== 'http/') { throw new \UnexpectedValueException(sprintf('"%s" is not a valid HTTP status line', $statusLine)); } $reasonPhrase = count($parts) > 2 ? $parts[2] : ''; $this->response = $this->response->withStatus((int) $parts[1], $reasonPhrase)->withProtocolVersion(substr($parts[0], 5)); foreach ($headers as $headerLine) { $headerLine = trim($headerLine); if ('' === $headerLine) { continue; } $parts = explode(':', $headerLine, 2); if (count($parts) !== 2) { throw new \UnexpectedValueException(sprintf('"%s" is not a valid HTTP header line', $headerLine)); } $name = trim(urldecode($parts[0])); $value = trim(urldecode($parts[1])); if ($this->response->hasHeader($name)) { $this->response = $this->response->withAddedHeader($name, $value); } else { $this->response = $this->response->withHeader($name, $value); } } return $this; }
/** * @param ResponseInterface $response * @return CacheEntry|null entry to save, null if can't cache it */ protected function getCacheObject(ResponseInterface $response) { if ($response->hasHeader("Cache-Control")) { $values = new KeyValueHttpHeader($response->getHeader("Cache-Control")); if ($values->has('no-store')) { // No store allowed (maybe some sensitives data...) return null; } if ($values->has('no-cache')) { // Stale response see RFC7234 section 5.2.1.4 $entry = new CacheEntry($response, new \DateTime('-1 seconds')); return $entry->hasValidationInformation() ? $entry : null; } if ($values->has('max-age')) { return new CacheEntry($response, new \DateTime('+' . $values->get('max-age') . 'seconds')); } return new CacheEntry($response, new \DateTime()); } if ($response->hasHeader("Expires")) { $expireAt = \DateTime::createFromFormat('D, d M Y H:i:s T', $response->getHeaderLine("Expires")); if ($expireAt !== FALSE) { return new CacheEntry($response, $expireAt); } } return new CacheEntry($response, new \DateTime('-1 seconds')); }
/** * {@inheritDoc} */ public function getHeaderLine($name, $default = null) { if (!$this->decoratedResponse->hasHeader($name)) { return $default; } return $this->decoratedResponse->getHeaderLine($name); }
/** * @param ResponseInterface $response * @return CacheEntry|null entry to save, null if can't cache it */ protected function getCacheObject(ResponseInterface $response) { if ($response->hasHeader("Cache-Control")) { $cacheControlDirectives = $response->getHeader("Cache-Control"); if (in_array("no-store", $cacheControlDirectives)) { // No store allowed (maybe some sensitives data...) return null; } if (in_array("no-cache", $cacheControlDirectives)) { // Stale response see RFC7234 section 5.2.1.4 $entry = new CacheEntry($response, new \DateTime('-1 seconds')); return $entry->hasValidationInformation() ? $entry : null; } $matches = []; if (preg_match('/^max-age=([0-9]*)$/', $response->getHeaderLine("Cache-Control"), $matches)) { // Handle max-age header return new CacheEntry($response, new \DateTime('+' . $matches[1] . 'seconds')); } } if ($response->hasHeader("Expires")) { $expireAt = \DateTime::createFromFormat('D, d M Y H:i:s T', $response->getHeaderLine("Expires")); if ($expireAt !== FALSE) { return new CacheEntry($response, $expireAt); } } return new CacheEntry($response, new \DateTime('1 days ago')); }
/** * @param string $message * @param ResponseInterface $response * @param \DateTime $responseDateTime */ public function __construct($message, ResponseInterface $response, \DateTime $responseDateTime) { parent::__construct($message, intval($response->getStatusCode())); $this->response = $response; $this->responseDateTime = $responseDateTime; $this->retrySeconds = $response->hasHeader('Retry-After') ? intval($response->getHeaderLine('Retry-After')) : null; }
/** * @param RequestInterface $request * @param ResponseInterface $response * @return CacheEntry|null entry to save, null if can't cache it */ protected function getCacheObject(RequestInterface $request, ResponseInterface $response) { if (!isset($this->statusAccepted[$response->getStatusCode()])) { // Don't cache it return; } $cacheControl = new KeyValueHttpHeader($response->getHeader('Cache-Control')); $varyHeader = new KeyValueHttpHeader($response->getHeader('Vary')); if ($varyHeader->has('*')) { // This will never match with a request return; } if ($cacheControl->has('no-store')) { // No store allowed (maybe some sensitives data...) return; } if ($cacheControl->has('no-cache')) { // Stale response see RFC7234 section 5.2.1.4 $entry = new CacheEntry($request, $response, new \DateTime('-1 seconds')); return $entry->hasValidationInformation() ? $entry : null; } foreach ($this->ageKey as $key) { if ($cacheControl->has($key)) { return new CacheEntry($request, $response, new \DateTime('+' . (int) $cacheControl->get($key) . 'seconds')); } } if ($response->hasHeader('Expires')) { $expireAt = \DateTime::createFromFormat(\DateTime::RFC1123, $response->getHeaderLine('Expires')); if ($expireAt !== false) { return new CacheEntry($request, $response, $expireAt); } } return new CacheEntry($request, $response, new \DateTime('-1 seconds')); }
/** * WosObjectId constructor. * * @param ResponseInterface $httpResponse */ public function __construct(ResponseInterface $httpResponse) { if (!$httpResponse->hasHeader('x-ddn-oid')) { throw new InvalidResponseException('x-ddn-oid', 'reserve object'); } $this->objectId = $httpResponse->getHeaderLine('x-ddn-oid'); }
public static function decode(ResponseInterface $response) { if ($response->hasHeader('Content-Type') && $response->getHeader('Content-Type')[0] == 'application/json') { return json_decode((string) $response->getBody(), true); } return (string) $response->getBody(); }
/** * Create the stream. * * @param $socket * @param ResponseInterface $response * * @return Stream */ protected function createStream($socket, ResponseInterface $response) { $size = null; if ($response->hasHeader('Content-Length')) { $size = (int) $response->getHeaderLine('Content-Length'); } return new Stream($socket, $size); }
/** * WosObject constructor. * * @param ResponseInterface $httpResponse */ public function __construct(ResponseInterface $httpResponse) { if (!$httpResponse->hasHeader('x-ddn-oid')) { throw new InvalidResponseException('x-ddn-oid', 'get object'); } $this->responseData = $httpResponse->getBody(); $this->metadata = new WosObjectMetadata($httpResponse); $this->objectId = new WosObjectId($httpResponse); }
/** {@inheritdoc} */ public function getPagination(array $data, ResponseInterface $response, ResponseDefinition $responseDefinition) { $paginationLinks = null; if ($response->hasHeader('Link')) { $links = self::parseHeaderLinks($response->getHeader('Link')); $paginationLinks = new PaginationLinks($links['first'], $links['last'], $links['next'], $links['prev']); } return new Pagination((int) $response->getHeaderLine($this->paginationHeaders['page']), (int) $response->getHeaderLine($this->paginationHeaders['perPage']), (int) $response->getHeaderLine($this->paginationHeaders['totalItems']), (int) $response->getHeaderLine($this->paginationHeaders['totalPages']), $paginationLinks); }
/** * @param RequestInterface $request * @param array $options * @param ResponseInterface|PromiseInterface $response * * @return ResponseInterface|PromiseInterface */ public function checkRedirect(RequestInterface $request, array $options, ResponseInterface $response) { if (substr($response->getStatusCode(), 0, 1) != '3' || !$response->hasHeader('Location')) { return $response; } $this->guardMax($request, $options); $nextRequest = $this->modifyRequest($request, $options, $response); return $this($nextRequest, $options); }
/** * @param Psr7Response * @param ReactResponse * @return void */ private function emit(Psr7Response $psr7Response, ReactResponse $reactResponse) { if (!$psr7Response->hasHeader('Content-Type')) { $psr7Response = $psr7Response->withHeader('Content-Type', 'text/html'); } $reactResponse->writeHead($psr7Response->getStatusCode(), $psr7Response->getHeaders()); $body = $psr7Response->getBody(); $body->rewind(); $reactResponse->end($body->getContents()); $body->close(); }
/** * Returns the json object if the response contains valid json, otherwise null. * * @param ResponseInterface $response * @return mixed|null */ protected function getResponseAsJson(ResponseInterface $response) { if ($response->hasHeader('Content-Type')) { $typeHeader = $response->getHeader('Content-Type'); $contentType = array_shift($typeHeader); if (stripos($contentType, 'application/json') === 0) { return json_decode($response->getBody(), false); } } return null; }
/** * Inject the Content-Length header if is not already present. * * @param ResponseInterface $response * @return ResponseInterface */ private function injectContentLength(ResponseInterface $response) { if (!$response->hasHeader('Content-Length')) { // PSR-7 indicates int OR null for the stream size; for null values, // we will not auto-inject the Content-Length. if (null !== $response->getBody()->getSize()) { return $response->withHeader('Content-Length', (string) $response->getBody()->getSize()); } } return $response; }
/** * {@inheritDoc} */ public function isAuthentic(ResponseInterface $response) { if (!$response->hasHeader('X-Server-Authorization-HMAC-SHA256')) { throw new MalformedResponseException('Response is missing required X-Server-Authorization-HMAC-SHA256 header.', null, 0, $response); } $responseSigner = new ResponseSigner($this->key, $this->request); $compareResponse = $responseSigner->signResponse($response->withoutHeader('X-Server-Authorization-HMAC-SHA256')); $responseSignature = $response->getHeaderLine('X-Server-Authorization-HMAC-SHA256'); $compareSignature = $compareResponse->getHeaderLine('X-Server-Authorization-HMAC-SHA256'); return hash_equals($compareSignature, $responseSignature); }
/** * Emits a response for a PHP SAPI environment. * * Emits the status line and headers via the header() function, and the * body content via the output buffer. * * @param ResponseInterface $response * @param null|int $maxBufferLevel Maximum output buffering level to unwrap. */ public function emit(ResponseInterface $response, $maxBufferLevel = null) { if (headers_sent()) { throw new \RuntimeException('Unable to emit response; headers already sent'); } if (!$response->hasHeader('Content-Length')) { $response = $response->withHeader('Content-Length', (string) $response->getBody()->getSize()); } $this->emitStatusLine($response); $this->emitHeaders($response); $this->emitBody($response, $maxBufferLevel); }
/** * @param RequestInterface $request * @param array $options * @param ResponseInterface|PromiseInterface $response * * @return ResponseInterface|PromiseInterface */ public function checkRedirect(RequestInterface $request, array $options, ResponseInterface $response) { if (substr($response->getStatusCode(), 0, 1) != '3' || !$response->hasHeader('Location')) { return $response; } $this->guardMax($request, $options); $nextRequest = $this->modifyRequest($request, $options, $response); if (isset($options['allow_redirects']['on_redirect'])) { call_user_func($options['allow_redirects']['on_redirect'], $request, $response, $nextRequest->getUri()); } return $this($nextRequest, $options); }
private function generateRequestLog(Request $request, Response $response) { if ($this->options['full']) { return RequestSerializer::toString($request); } $msg = sprintf("%s %s", $request->getMethod(), $request->getRequestTarget()); if ($request->hasHeader('X-Request-Id')) { $msg .= ' RequestId: ' . $request->getHeader('X-Request-Id')[0]; } elseif ($response->hasHeader('X-Request-Id')) { $msg .= ' RequestId: ' . $response->getHeader('X-Request-Id')[0]; } return $msg; }
/** * @param array $params * @param ResponseInterface $response * * @return null|string * * @throws UnknownFormatException */ private function getFormat(array $params, ResponseInterface $response) { if ($response->hasHeader('content-type')) { $header = $response->getHeaderLine('content-type'); $format = $this->negotiator->getFormat($header); } if (isset($params['format'])) { $format = $params['format']; } if (!isset($format)) { throw new UnknownFormatException('Unable to figure out the format'); } return $format; }
/** * Send HTTP headers * */ protected function setupHeaders(ResponseInterface $response) { if (!$response->hasHeader('Content-Transfer-Encoding')) { $response = $response->withHeader('Content-Transfer-Encoding', 'binary'); } $size = $response->getBody()->getSize(); $size2 = $size - 1; $length = $size; $this->rangeStart = 0; $this->rangeEnd = null; $enableRangeSupport = $this->getOptions()['enableRangeSupport']; if ($enableRangeSupport && $this->requestRange) { list($a, $range) = explode('=', $this->requestRange); if (substr($range, -1) == '-') { // range: 3442- $range = substr($range, 0, -1); if (!is_numeric($range) || $range > $size2) { // 416 (Requested range not satisfiable) $response = $response->withStatus(416); return $response; } $this->rangeStart = $range; $length = $size - $range; } else { $ranges = explode('-', $range, 2); $rangeStart = $ranges[0]; $rangeEnd = $ranges[1]; if (!is_numeric($rangeStart) || !is_numeric($rangeEnd) || $rangeStart >= $rangeEnd || $rangeEnd > $size2) { // 416 (Requested range not satisfiable) $response = $response->withStatus(416); return $response; } $this->rangeStart = $rangeStart; $this->rangeEnd = $rangeEnd; $length = $rangeEnd - $rangeStart; $size2 = $rangeEnd; } $response = $response->withStatus(206); // 206 (Partial Content) } $response = $response->withHeader('Content-Length', $length); if ($enableRangeSupport) { $response = $response->withHeader('Accept-Ranges', 'bytes'); $response = $response->withHeader('Content-Range', 'bytes ' . $this->rangeStart . '-' . $size2 . '/' . $size); } else { $response = $response->withHeader('Accept-Ranges', 'none'); } return $response; }
/** * Add header represented by a string. * * @param string $headerLine Response header as a string. * * @return $this * * @throws \InvalidArgumentException For invalid header names or values. */ public function addHeader($headerLine) { $parts = explode(':', $headerLine, 2); if (count($parts) !== 2) { throw new \InvalidArgumentException(sprintf('"%s" is not a valid HTTP header line', $headerLine)); } $name = trim(urldecode($parts[0])); $value = trim(urldecode($parts[1])); if ($this->response->hasHeader($name)) { $this->response = $this->response->withAddedHeader($name, $value); } else { $this->response = $this->response->withHeader($name, $value); } return $this; }
/** * Get the content type. * * @param ServerRequestInterface $request * @param ResponseInterface $response * @return string */ protected function getContentType(ServerRequestInterface $request, ResponseInterface $response) { if (!$response->hasHeader('Content-Type')) { $contentType = $this->determineContentType($request); } else { $contentType = $response->getHeader('Content-Type'); if (is_array($contentType)) { $contentType = $contentType[0]; } $contentTypeParts = preg_split('/\\s*;\\s*/', $contentType); if (count($contentTypeParts)) { $contentType = $contentTypeParts[0]; } } return $contentType; }
/** * Emits a response for a PHP SAPI environment. * * Emits the status line and headers via the header() function, and the * body content via the output buffer. * * @param ResponseInterface $response * @param null|int $maxBufferLevel Maximum output buffering level to unwrap. */ public function emit(ResponseInterface $response, $maxBufferLevel = null) { if (headers_sent()) { throw new RuntimeException('Unable to emit response; headers already sent'); } if (!$response->hasHeader('Content-Length')) { // PSR-7 indicates int OR null for the stream size; for null values, // we will not auto-inject the Content-Length. if (null !== $response->getBody()->getSize()) { $response = $response->withHeader('Content-Length', (string) $response->getBody()->getSize()); } } $this->emitStatusLine($response); $this->emitHeaders($response); $this->emitBody($response, $maxBufferLevel); }
protected function prepareResponse(ServerRequestInterface $request, ResponseInterface $response) { // Add a Content-length header to the response when all of these are true: // // - Response does not have a Content-length header // - Response does not have a Transfer-encoding: chunked header // - Response body stream is readable and reports a non-null size // if (!$response->hasHeader("Content-length") && !(strtolower($response->getHeaderLine("Transfer-encoding")) === "chunked")) { $size = $response->getBody()->getSize(); if ($size !== null) { $response = $response->withHeader("Content-length", (string) $size); } } return $response; }
/** * Decode a response on a specific header (content encoding or transfer encoding mainly). * * @param string $headerName Name of the header * @param ResponseInterface $response Response * * @return ResponseInterface A new instance of the response decoded */ private function decodeOnEncodingHeader($headerName, ResponseInterface $response) { if ($response->hasHeader($headerName)) { $encodings = $response->getHeader($headerName); $newEncodings = []; while ($encoding = array_pop($encodings)) { $stream = $this->decorateStream($encoding, $response->getBody()); if (false === $stream) { array_unshift($newEncodings, $encoding); continue; } $response = $response->withBody($stream); } $response = $response->withHeader($headerName, $newEncodings); } return $response; }
/** * @param ResponseInterface $response * @return CacheEntry|null entry to save, null if can't cache it */ protected function getCacheObject(ResponseInterface $response) { if (!isset($this->statusAccepted[$response->getStatusCode()])) { // Don't cache it return null; } if ($response->hasHeader("Cache-Control")) { $values = new KeyValueHttpHeader($response->getHeader("Cache-Control")); if (!$values->isEmpty()) { return $this->getCacheObjectForCacheControl($response, $values); } } if ($response->hasHeader("Expires") && ($expireAt = \DateTime::createFromFormat(\DateTime::RFC1123, $response->getHeaderLine("Expires")))) { return new CacheEntry($response, $expireAt); } return new CacheEntry($response, new \DateTime('-1 seconds')); }
/** * @param RequestInterface $request * @param array $options * @param ResponseInterface|PromiseInterface $response * * @return ResponseInterface|PromiseInterface */ public function checkRedirect(RequestInterface $request, array $options, ResponseInterface $response) { if (substr($response->getStatusCode(), 0, 1) != '3' || !$response->hasHeader('Location')) { return $response; } $this->guardMax($request, $options); $nextRequest = $this->modifyRequest($request, $options, $response); if (isset($options[RequestOptions::ALLOW_REDIRECTS][RequestOptions::ON_REDIRECT])) { call_user_func($options[RequestOptions::ALLOW_REDIRECTS][RequestOptions::ON_REDIRECT], $request, $response, $nextRequest->getUri()); } /** @var PromiseInterface|ResponseInterface $promise */ $promise = $this($nextRequest, $options); // Add headers to be able to track history of redirects. if (!empty($options[RequestOptions::ALLOW_REDIRECTS]['track_redirects'])) { return $this->withTracking($promise, (string) $nextRequest->getUri()); } return $promise; }
private function cacheResponse(Request $request, Response $response) { if ('GET' !== $request->getMethod() || !$response->hasHeader('Cache-Control')) { return; } $cacheControl = $response->getHeader('Cache-Control'); $abortTokens = ['private', 'no-cache', 'no-store']; if (count(array_intersect($abortTokens, $cacheControl)) > 0) { return; } foreach ($cacheControl as $value) { $parts = explode('=', $value); if (count($parts) == 2 && 'max-age' === $parts[0]) { $this->cache->save($this->getCacheKey($request), ['headers' => $response->getHeaders(), 'body' => (string) $response->getBody()], intval($parts[1])); return; } } }
/** * Check whether the response can be saved or not. * * @param RequestInterface $request * @param ResponseInterface $response * * @return bool */ private function canSave(RequestInterface $request, ResponseInterface $response) { if ($request->getMethod() !== 'GET') { return false; } if ($response->getStatusCode() !== 200) { return false; } if (!$this->appendQuery && !empty($request->getUri()->getQuery())) { return false; } if ($response->hasHeader('location')) { return false; } $cacheControl = $response->getHeaderLine('Cache-Control'); if ($cacheControl && (stripos($cacheControl, 'no-cache') !== false || stripos($cacheControl, 'no-store') !== false)) { return false; } return true; }