From 7f83150a690ccab46893667a70807975aab6af03 Mon Sep 17 00:00:00 2001 From: thomas morgan Date: Wed, 23 Aug 2023 12:14:31 -0600 Subject: [PATCH] etags: add strong and weak matchers --- .mailmap | 3 ++- lib/protocol/http/header/etags.rb | 23 +++++++++++++++++++++- license.md | 1 + test/protocol/http/header/etags.rb | 31 ++++++++++++++++++++++++++---- 4 files changed, 52 insertions(+), 6 deletions(-) diff --git a/.mailmap b/.mailmap index 2cef8ef..b181bb6 100644 --- a/.mailmap +++ b/.mailmap @@ -1 +1,2 @@ -Dan Olson \ No newline at end of file +Dan Olson +Thomas Morgan diff --git a/lib/protocol/http/header/etags.rb b/lib/protocol/http/header/etags.rb index 47ecdd5..fff469b 100644 --- a/lib/protocol/http/header/etags.rb +++ b/lib/protocol/http/header/etags.rb @@ -2,21 +2,42 @@ # Released under the MIT License. # Copyright, 2020-2023, by Samuel Williams. +# Copyright, 2023, by Thomas Morgan. require_relative 'split' module Protocol module HTTP module Header - # This implementation is not strictly correct according to the RFC-specified format. class ETags < Split def wildcard? self.include?('*') end + # This implementation is not strictly correct according to the RFC-specified format. def match?(etag) wildcard? || self.include?(etag) end + + # Useful with If-Match + def strong_match?(etag) + wildcard? || (!weak_tag?(etag) && self.include?(etag)) + end + + # Useful with If-None-Match + def weak_match?(etag) + wildcard? || self.include?(etag) || self.include?(opposite_tag(etag)) + end + + private + + def opposite_tag(etag) + weak_tag?(etag) ? etag[2..-1] : "W/#{etag}" + end + + def weak_tag?(tag) + tag&.start_with? 'W/' + end end end end diff --git a/license.md b/license.md index 1562574..ac09873 100644 --- a/license.md +++ b/license.md @@ -8,6 +8,7 @@ Copyright, 2020-2023, by Bruno Sutic. Copyright, 2022, by Herrick Fang. Copyright, 2022, by Dan Olson. Copyright, 2023, by Genki Takiuchi. +Copyright, 2023, by Thomas Morgan. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/test/protocol/http/header/etags.rb b/test/protocol/http/header/etags.rb index f2ffd8b..c1bc848 100644 --- a/test/protocol/http/header/etags.rb +++ b/test/protocol/http/header/etags.rb @@ -2,6 +2,7 @@ # Released under the MIT License. # Copyright, 2020-2023, by Samuel Williams. +# Copyright, 2023, by Thomas Morgan. require 'protocol/http/header/etags' @@ -14,21 +15,43 @@ end it "matches anything" do - expect(header).to be(:match?, "anything") + expect(header).to be(:match?, '"anything"') end end - with "abcd" do + with '"abcd"' do it "is not a wildcard" do expect(header).not.to be(:wildcard?) end it "matches itself" do - expect(header).to be(:match?, "abcd") + expect(header).to be(:match?, '"abcd"') + end + + it "strongly matches only another strong etag" do + expect(header).to be(:strong_match?, '"abcd"') + expect(header).not.to be(:strong_match?, 'W/"abcd"') + end + + it "weakly matches both weak and strong etags" do + expect(header).to be(:weak_match?, '"abcd"') + expect(header).to be(:weak_match?, 'W/"abcd"') end it "does not match anything else" do - expect(header).not.to be(:match?, "anything else") + expect(header).not.to be(:match?, '"anything else"') + end + end + + with 'W/"abcd"' do + it "never strongly matches" do + expect(header).not.to be(:strong_match?, '"abcd"') + expect(header).not.to be(:strong_match?, 'W/"abcd"') + end + + it "weakly matches both weak and strong etags" do + expect(header).to be(:weak_match?, '"abcd"') + expect(header).to be(:weak_match?, 'W/"abcd"') end end end