From 7cc89fc8a8a63783f0c54171196ef1926a1aa98d Mon Sep 17 00:00:00 2001 From: Mridankan Mandal Date: Thu, 11 Jun 2026 14:08:43 +0530 Subject: [PATCH 1/2] fix(request): use weak If-None-Match compare Signed-off-by: Mridankan Mandal --- CHANGELOG.md | 1 + lib/rage/request.rb | 8 +++++++- spec/controller/api/conditional_get_spec.rb | 6 +++--- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d73e1d5a..07f640ff 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ ### Fixed +- [API] Use weak comparison for `If-None-Match` validation. - [Request] Treat IPv6 literals as non-domain hosts. - [Router] Fall back to `SERVER_NAME` when deriving exact host constraints. - [Cookies] Use request host fallback when resolving cookie domains. diff --git a/lib/rage/request.rb b/lib/rage/request.rb index 953b45d9..5aa5958d 100644 --- a/lib/rage/request.rb +++ b/lib/rage/request.rb @@ -271,8 +271,10 @@ def etag_matches?(requested_etags:, response_etag:) return true if requested_etags.empty? return false if response_etag.nil? + return true if requested_etags.include?("*") - requested_etags.include?(response_etag) || requested_etags.include?("*") + response_etag = weak_etag(response_etag) + requested_etags.any? { |requested_etag| weak_etag(requested_etag) == response_etag } end def not_modified?(request_not_modified_since:, response_last_modified:) @@ -282,6 +284,10 @@ def not_modified?(request_not_modified_since:, response_last_modified:) request_not_modified_since >= response_last_modified end + def weak_etag(etag) + etag.delete_prefix("W/") + end + # @private class Headers HTTP = "HTTP_" diff --git a/spec/controller/api/conditional_get_spec.rb b/spec/controller/api/conditional_get_spec.rb index 93c379d7..d91a4040 100644 --- a/spec/controller/api/conditional_get_spec.rb +++ b/spec/controller/api/conditional_get_spec.rb @@ -180,12 +180,12 @@ def last_modified_set_raises_error let(:env) { { "HTTP_IF_NONE_MATCH" => "\"#{Digest::SHA1.hexdigest("123")}\"" } } let(:expected_etag) { %(W/"#{Digest::SHA1.hexdigest("123")}") } - it "renders the requested resource" do + it "returns NOT MODIFIED" do expect(run_action(klass, :stale_etag_test, env:)).to match( - [200, a_hash_including( + [304, a_hash_including( Rage::Response::ETAG_HEADER => expected_etag, Rage::Response::LAST_MODIFIED_HEADER => nil - ), ["test_etag"]] + ), []] ) end end From ee9c6ea21d90329826ff870050d9eba64ca6aa8a Mon Sep 17 00:00:00 2001 From: Mridankan Mandal Date: Mon, 15 Jun 2026 01:19:45 +0530 Subject: [PATCH 2/2] style(request): apply review suggestion Signed-off-by: Mridankan Mandal --- lib/rage/request.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/rage/request.rb b/lib/rage/request.rb index 5aa5958d..e138115d 100644 --- a/lib/rage/request.rb +++ b/lib/rage/request.rb @@ -284,7 +284,7 @@ def not_modified?(request_not_modified_since:, response_last_modified:) request_not_modified_since >= response_last_modified end - def weak_etag(etag) + private def weak_etag(etag) etag.delete_prefix("W/") end