summary refs log tree commit
diff options
context:
space:
mode:
authorJoshua Peek <josh@joshpeek.com>2009-12-11 15:52:08 -0600
committerJoshua Peek <josh@joshpeek.com>2009-12-11 15:52:08 -0600
commit7077d4b6d3eb25c856c83b7c8a22210216fde645 (patch)
tree684ddae4c1dffee7a2ffa5808a5829fa076619db
parenta1534a5d7b48812e1e67d7ff02ef53b70e3ea492 (diff)
downloadrack-7077d4b6d3eb25c856c83b7c8a22210216fde645.tar.gz
Import etag middleware from contrib into core
-rw-r--r--lib/rack.rb1
-rw-r--r--lib/rack/etag.rb23
-rw-r--r--test/spec_rack_etag.rb17
3 files changed, 41 insertions, 0 deletions
diff --git a/lib/rack.rb b/lib/rack.rb
index b2aed6a5..20b3c379 100644
--- a/lib/rack.rb
+++ b/lib/rack.rb
@@ -31,6 +31,7 @@ module Rack
   autoload :Config, "rack/config"
   autoload :ContentLength, "rack/content_length"
   autoload :ContentType, "rack/content_type"
+  autoload :ETag, "rack/etag"
   autoload :File, "rack/file"
   autoload :Deflater, "rack/deflater"
   autoload :Directory, "rack/directory"
diff --git a/lib/rack/etag.rb b/lib/rack/etag.rb
new file mode 100644
index 00000000..06dbc6aa
--- /dev/null
+++ b/lib/rack/etag.rb
@@ -0,0 +1,23 @@
+require 'digest/md5'
+
+module Rack
+  # Automatically sets the ETag header on all String bodies
+  class ETag
+    def initialize(app)
+      @app = app
+    end
+
+    def call(env)
+      status, headers, body = @app.call(env)
+
+      if !headers.has_key?('ETag')
+        parts = []
+        body.each { |part| parts << part.to_s }
+        headers['ETag'] = %("#{Digest::MD5.hexdigest(parts.join(""))}")
+        [status, headers, parts]
+      else
+        [status, headers, body]
+      end
+    end
+  end
+end
diff --git a/test/spec_rack_etag.rb b/test/spec_rack_etag.rb
new file mode 100644
index 00000000..73cd31ac
--- /dev/null
+++ b/test/spec_rack_etag.rb
@@ -0,0 +1,17 @@
+require 'test/spec'
+require 'rack/mock'
+require 'rack/etag'
+
+context "Rack::ETag" do
+  specify "sets ETag if none is set" do
+    app = lambda { |env| [200, {'Content-Type' => 'text/plain'}, ["Hello, World!"]] }
+    response = Rack::ETag.new(app).call({})
+    response[1]['ETag'].should.equal "\"65a8e27d8879283831b664bd8b7f0ad4\""
+  end
+
+  specify "does not change ETag if it is already set" do
+    app = lambda { |env| [200, {'Content-Type' => 'text/plain', 'ETag' => '"abc"'}, ["Hello, World!"]] }
+    response = Rack::ETag.new(app).call({})
+    response[1]['ETag'].should.equal "\"abc\""
+  end
+end