middleware:
class WeakEtagMiddleware
def initialize(app)
@app = app
end
def call(env)
# make request etags "strong"
etag = env['HTTP_IF_NONE_MATCH']
if etag && etag =~ /^W\//
env['HTTP_IF_NONE_MATCH'] = etag[2..-1]
end
status, headers, body = @app.call(env)
# make response etags "weak"
etag = headers['ETag']
if etag && etag !~ /^W\//
headers['ETag'] = "W/#{etag}"
end
[status, headers, body]
end
end
plus add middleware
Rails.application.config.middleware.insert_before(Rack::ETag, WeakEtagMiddleware)
plus unit tests
context WeakEtagMiddleware do
let(:backend) { Rack::ConditionalGet.new(Rack::ETag.new(lambda { |env| [env["status"] || 200, {}, ["XXX"]] })) }
let(:app) { WeakEtagMiddleware.new(backend) }
let(:expected_digest_1) { "bc9189406be84ec297464a514221406d" }
let(:env) { {"REQUEST_METHOD" => "GET"} }
should "converts etags to weak" do
status, headers, body = app.call(env)
assert_equal %{W/"#{expected_digest_1}"}, headers["ETag"]
assert_equal status, 200
end
should "not add etags to responses without etag" do
status, headers, body = app.call(env.merge("status" => 400))
refute headers["ETag"]
assert_equal status, 400
end
should "recognize weak ETags" do
status, headers, body = app.call(env.merge("HTTP_IF_NONE_MATCH" => %{W/"#{expected_digest_1}"}))
assert_equal status, 304
end
should "not recognize invalid ETags" do
status, headers, body = app.call(env.merge("HTTP_IF_NONE_MATCH" => %{W/"something-not-fresh"}))
assert_equal status, 200
end
end
plus integration tests
require_relative "../helpers/test_helper"
class WeakEtagsTest < ActionController::IntegrationTest
class TestController < ActionController::Base
def auto
render :text => "XXX"
end
def fresh
if stale? :etag => "YYY"
render :text => "XXX"
end
end
end
additional_routes do
get '/test/weak_etags/:action', :controller => 'weak_etags_test/test'
end
fixtures :accounts, :users
context "weak etags" do
let(:expected_digest_1) { "bc9189406be84ec297464a514221406d" }
let(:expected_digest_2) { "fd7c5c4fdaa97163ee4ba8842baa537a" }
should "auto adds weak etags" do
get "/test/weak_etags/auto"
assert_equal "XXX", @response.body
assert_equal %{W/"#{expected_digest_1}"}, @response.headers["ETag"]
end
should "adds weak etags through fresh_when" do
get "/test/weak_etags/fresh"
assert_equal "XXX", @response.body
assert_equal %{W/"#{expected_digest_2}"}, @response.headers["ETag"]
end
should "recognize auto-added ETags" do
get "/test/weak_etags/auto", {}, {"HTTP_IF_NONE_MATCH" => %{W/"#{expected_digest_1}"}}
assert_response :not_modified
end
should "recognize fresh ETags" do
get "/test/weak_etags/fresh", {}, {"HTTP_IF_NONE_MATCH" => %{W/"#{expected_digest_2}"}}
assert_response :not_modified
end
end
end