Module: Philiprehberger::Etag::Generator
- Defined in:
- lib/philiprehberger/etag/generator.rb
Overview
Generates strong and weak ETags from content using cryptographic hashes.
Constant Summary collapse
- ALGORITHMS =
{ sha256: Digest::SHA256, sha512: Digest::SHA512, md5: Digest::MD5, sha1: Digest::SHA1 }.freeze
- OPENSSL_ALGORITHMS =
Algorithms that delegate to OpenSSL::Digest rather than the stdlib ‘digest/*` classes.
{ sha3_256: 'SHA3-256' }.freeze
Class Method Summary collapse
-
.for_file(path, algorithm: :sha256) ⇒ String
Generates a strong ETag for a file based on its mtime and size.
-
.for_io(io, algorithm: :sha256, chunk_size: 65_536) ⇒ String
Generates a strong ETag from an IO stream by reading it in chunks.
-
.strong(content, algorithm: :sha256) ⇒ String
Generates a strong ETag from content using the specified algorithm.
-
.weak(content) ⇒ String
Generates a weak ETag from content using MD5.
Class Method Details
.for_file(path, algorithm: :sha256) ⇒ String
Generates a strong ETag for a file based on its mtime and size. Does not read file content.
48 49 50 51 52 53 |
# File 'lib/philiprehberger/etag/generator.rb', line 48 def self.for_file(path, algorithm: :sha256) stat = File.stat(path) fingerprint = "#{stat.mtime.to_i}-#{stat.size}" digest = compute_digest(fingerprint, algorithm) %("#{digest}") end |
.for_io(io, algorithm: :sha256, chunk_size: 65_536) ⇒ String
Generates a strong ETag from an IO stream by reading it in chunks. Unlike strong, the entire payload is never materialised in memory at once, making this suitable for hashing large files and rack response bodies.
The IO is read from its current position to EOF. Callers that need to consume the IO afterwards should ‘rewind` it first.
67 68 69 70 71 72 73 74 75 76 77 |
# File 'lib/philiprehberger/etag/generator.rb', line 67 def self.for_io(io, algorithm: :sha256, chunk_size: 65_536) raise ArgumentError, 'chunk_size must be positive' unless chunk_size.positive? digest = digest_for(algorithm) while (chunk = io.read(chunk_size)) break if chunk.empty? digest.update(chunk) end %("#{digest.hexdigest}") end |
.strong(content, algorithm: :sha256) ⇒ String
Generates a strong ETag from content using the specified algorithm.
26 27 28 29 |
# File 'lib/philiprehberger/etag/generator.rb', line 26 def self.strong(content, algorithm: :sha256) digest = compute_digest(content, algorithm) %("#{digest}") end |
.weak(content) ⇒ String
Generates a weak ETag from content using MD5.
35 36 37 38 |
# File 'lib/philiprehberger/etag/generator.rb', line 35 def self.weak(content) digest = Digest::MD5.hexdigest(content.to_s) %(W/"#{digest}") end |