From 0763b826cf5b39c156cf3bbda5aaa7898411b5a4 Mon Sep 17 00:00:00 2001 From: Jakub Onderka Date: Fri, 22 Mar 2024 16:32:38 +0100 Subject: [PATCH] fix: [API] Cleanup compression marks added by Apache from Etag --- .../Component/RestResponseComponent.php | 29 ++++++++++++++++--- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/app/Controller/Component/RestResponseComponent.php b/app/Controller/Component/RestResponseComponent.php index 0d9863d709c..367d4d8bc6c 100644 --- a/app/Controller/Component/RestResponseComponent.php +++ b/app/Controller/Component/RestResponseComponent.php @@ -671,9 +671,10 @@ private function prepareResponse($response, $code, $format = false, $raw = false } if ($response instanceof TmpFileTool) { - if (isset($_SERVER['HTTP_IF_NONE_MATCH'])) { + $requestEtag = $this->requestEtag(); + if ($requestEtag !== null) { $etag = '"' . $response->hash('sha1') . '"'; - if ($_SERVER['HTTP_IF_NONE_MATCH'] === $etag) { + if ($requestEtag === $etag) { return new CakeResponse(['status' => 304]); } $headers['ETag'] = $etag; @@ -689,9 +690,10 @@ private function prepareResponse($response, $code, $format = false, $raw = false } } else { // Check if resource was changed when `If-None-Match` header is send and return 304 Not Modified - if (isset($_SERVER['HTTP_IF_NONE_MATCH'])) { + $requestEtag = $this->requestEtag(); + if ($requestEtag !== null) { $etag = '"' . sha1($response) . '"'; - if ($_SERVER['HTTP_IF_NONE_MATCH'] === $etag) { + if ($requestEtag === $etag) { return new CakeResponse(['status' => 304]); } // Generate etag just when HTTP_IF_NONE_MATCH is set @@ -724,6 +726,25 @@ private function prepareResponse($response, $code, $format = false, $raw = false return $cakeResponse; } + /** + * Return etag from If-None-Match HTTP request header without compression marks added by Apache + * @return string|null + */ + private function requestEtag() + { + if (isset($_SERVER['HTTP_IF_NONE_MATCH'])) { + // Remove compression marks that adds Apache for compressed content + $requestEtag = $_SERVER['HTTP_IF_NONE_MATCH']; + $etagWithoutQuotes = trim($requestEtag, '"'); + $dashPos = strrpos($etagWithoutQuotes, '-'); + if ($dashPos && in_array(substr($etagWithoutQuotes, $dashPos + 1), ['br', 'gzip'], true)) { + return '"' . substr($etagWithoutQuotes, 0, $dashPos) . '"'; + } + return $requestEtag; + } + return null; + } + /** * @param string $response * @return string Signature as base64 encoded string