Module: Philiprehberger::HeaderKit::Etag

Defined in:
lib/philiprehberger/header_kit/etag.rb

Overview

Evaluates If-None-Match / If-Match style header values against a resource ETag.

Accepts single ETags, comma-separated lists, weak-prefixed values (e.g. ‘W/“abc”`), and the `*` wildcard. Strong and weak semantics collapse to equality on the inner token — callers that need strict strong/weak differentiation should implement that separately.

Class Method Summary collapse

Class Method Details

.match?(header_value, resource_etag) ⇒ Boolean

Check whether a header value matches a resource ETag.

Parameters:

  • header_value (String, nil)

    the raw If-None-Match / If-Match header

  • resource_etag (String, nil)

    the resource ETag (unquoted, no ‘W/` prefix)

Returns:

  • (Boolean)

    true if any value in the header matches the resource



20
21
22
23
24
25
26
27
28
29
30
# File 'lib/philiprehberger/header_kit/etag.rb', line 20

def match?(header_value, resource_etag)
  return false if header_value.nil?

  stripped = header_value.strip
  return false if stripped.empty?

  tokens = split_values(stripped)
  return false if tokens.empty?

  tokens.any? { |token| token_matches?(token, resource_etag) }
end

.split_values(value) ⇒ Array<String>

Split a header value into individual ETag tokens.

Quoted sections (including escaped characters) are preserved so commas inside a quoted ETag do not split the value.

Parameters:

  • value (String)

    the header value to split

Returns:

  • (Array<String>)

    trimmed, non-empty tokens



39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
# File 'lib/philiprehberger/header_kit/etag.rb', line 39

def split_values(value)
  tokens = []
  buffer = +''
  in_quotes = false
  escaped = false

  value.each_char do |char|
    if escaped
      buffer << char
      escaped = false
    elsif in_quotes && char == '\\'
      buffer << char
      escaped = true
    elsif char == '"'
      buffer << char
      in_quotes = !in_quotes
    elsif char == ',' && !in_quotes
      tokens << buffer.strip unless buffer.strip.empty?
      buffer = +''
    else
      buffer << char
    end
  end

  tokens << buffer.strip unless buffer.strip.empty?
  tokens
end

.token_matches?(token, resource_etag) ⇒ Boolean

Determine whether a single token matches the resource ETag.

Parameters:

  • token (String)

    a single header token

  • resource_etag (String, nil)

    the resource ETag

Returns:

  • (Boolean)

    true if the token matches



72
73
74
75
76
77
# File 'lib/philiprehberger/header_kit/etag.rb', line 72

def token_matches?(token, resource_etag)
  return !resource_etag.nil? if token == '*'
  return false if resource_etag.nil?

  unwrap(token) == resource_etag
end

.unwrap(token) ⇒ String

Strip weak prefix and surrounding quotes from an ETag token.

Backslash-escaped characters inside the quoted value are unescaped.

Parameters:

  • token (String)

    a single ETag token

Returns:

  • (String)

    the inner ETag value



85
86
87
88
89
90
91
92
# File 'lib/philiprehberger/header_kit/etag.rb', line 85

def unwrap(token)
  value = token.sub(%r{\AW/}i, '')

  return value unless value.start_with?('"') && value.end_with?('"') && value.length >= 2

  inner = value[1..-2]
  inner.gsub(/\\(.)/, '\1')
end