An ETag or entity tag, is part of HTTP, the protocol for the World Wide Web. It is one of several mechanisms that HTTP provides for web cache validation, and which allows a client to make conditional requests.
This allows caches to be more efficient, and saves bandwidth, as a web server does not need to send a full response if the content has not changed.
An ETag is an opaque identifier assigned by a web server to a specific version of a resource found at a URL.
If the resource content at that URL ever changes, a new and different ETag is assigned.
Used in this manner ETags are similar to fingerprints, and they can be quickly compared to determine if two versions of a resource are the same or not.
require 'digest/md5' module Rack class ETag DEFAULT_CACHE_CONTROL = "max-age=0, private, must-revalidate".freeze def initialize(app, no_cache_control = nil, cache_control = DEFAULT_CACHE_CONTROL) @app = app @cache_control = cache_control @no_cache_control = no_cache_control end def call(env) status, headers, body = @app.call(env) if etag_status?(status) && etag_body?(body) && !skip_caching?(headers) digest, body = digest_body(body) headers['ETag'] = %("#{digest}") if digest end unless headers['Cache-Control'] if digest headers['Cache-Control'] = @cache_control if @cache_control else headers['Cache-Control'] = @no_cache_control if @no_cache_control end end [status, headers, body] end private def etag_status?(status) status == 200 || status == 201 end def etag_body?(body) !body.respond_to?(:to_path) end def skip_caching?(headers) (headers['Cache-Control'] && headers['Cache-Control'].include?('no-cache')) || headers.key?('ETag') || headers.key?('Last-Modified') end def digest_body(body) parts = [] digest = nil body.each do |part| parts << part (digest ||= Digest::MD5.new) << part unless part.empty? end [digest && digest.hexdigest, parts] end end end
Casiano Rodriguez LeĆ³n 2015-01-07