summary refs log tree commit
diff options
context:
space:
mode:
authorBrian Candler <b.candler@pobox.com>2009-03-05 13:17:42 +0000
committerRyan Tomayko <rtomayko@gmail.com>2009-03-05 19:53:52 -0800
commitfbb2ae41992fe609c0d004f13605ad0f8fc46c81 (patch)
tree35ff232b544fdfdddaa3651be1c66ff3bfd3e540
parent91cea704e1c19ad0fe5c3f349fdf38a0fd747d9b (diff)
downloadrack-fbb2ae41992fe609c0d004f13605ad0f8fc46c81.tar.gz
Add Rack::ContentType middleware
Signed-off-by: Ryan Tomayko <rtomayko@gmail.com>
-rw-r--r--lib/rack.rb1
-rw-r--r--lib/rack/content_type.rb23
-rw-r--r--test/spec_rack_content_type.rb30
3 files changed, 54 insertions, 0 deletions
diff --git a/lib/rack.rb b/lib/rack.rb
index c64bfe4f..26436307 100644
--- a/lib/rack.rb
+++ b/lib/rack.rb
@@ -31,6 +31,7 @@ module Rack
   autoload :CommonLogger, "rack/commonlogger"
   autoload :ConditionalGet, "rack/conditionalget"
   autoload :ContentLength, "rack/content_length"
+  autoload :ContentType, "rack/content_type"
   autoload :File, "rack/file"
   autoload :Deflater, "rack/deflater"
   autoload :Directory, "rack/directory"
diff --git a/lib/rack/content_type.rb b/lib/rack/content_type.rb
new file mode 100644
index 00000000..0c1e1ca3
--- /dev/null
+++ b/lib/rack/content_type.rb
@@ -0,0 +1,23 @@
+require 'rack/utils'
+
+module Rack
+
+  # Sets the Content-Type header on responses which don't have one.
+  #
+  # Builder Usage:
+  #   use Rack::ContentType, "text/plain"
+  #
+  # When no content type argument is provided, "text/html" is assumed.
+  class ContentType
+    def initialize(app, content_type = "text/html")
+      @app, @content_type = app, content_type
+    end
+
+    def call(env)
+      status, headers, body = @app.call(env)
+      headers = Utils::HeaderHash.new(headers)
+      headers['Content-Type'] ||= @content_type
+      [status, headers.to_hash, body]
+    end
+  end
+end
diff --git a/test/spec_rack_content_type.rb b/test/spec_rack_content_type.rb
new file mode 100644
index 00000000..9975b94d
--- /dev/null
+++ b/test/spec_rack_content_type.rb
@@ -0,0 +1,30 @@
+require 'rack/mock'
+require 'rack/content_type'
+
+context "Rack::ContentType" do
+  specify "sets Content-Type to default text/html if none is set" do
+    app = lambda { |env| [200, {}, "Hello, World!"] }
+    status, headers, body = Rack::ContentType.new(app).call({})
+    headers['Content-Type'].should.equal 'text/html'
+  end
+
+  specify "sets Content-Type to chosen default if none is set" do
+    app = lambda { |env| [200, {}, "Hello, World!"] }
+    status, headers, body =
+      Rack::ContentType.new(app, 'application/octet-stream').call({})
+    headers['Content-Type'].should.equal 'application/octet-stream'
+  end
+
+  specify "does not change Content-Type if it is already set" do
+    app = lambda { |env| [200, {'Content-Type' => 'foo/bar'}, "Hello, World!"] }
+    status, headers, body = Rack::ContentType.new(app).call({})
+    headers['Content-Type'].should.equal 'foo/bar'
+  end
+
+  specify "case insensitive detection of Content-Type" do
+    app = lambda { |env| [200, {'CONTENT-Type' => 'foo/bar'}, "Hello, World!"] }
+    status, headers, body = Rack::ContentType.new(app).call({})
+    headers.to_a.select { |k,v| k.downcase == "content-type" }.
+      should.equal [["CONTENT-Type","foo/bar"]]
+  end
+end