Permalink
Browse files

Add filtering support for Accept HTTP header.

Adds an "provides"-option to a route definition, which can either be
a string specifying a MIME type, a symbol that Rack can resolve to
a MIME type, or an array of either.
  • Loading branch information...
1 parent 9681803 commit 38778eddda69cfdd68aafaa2fc94713ed449f421 @cypher cypher committed with rtomayko Jan 7, 2009
Showing with 65 additions and 3 deletions.
  1. +4 −0 CHANGES
  2. +28 −3 lib/sinatra/base.rb
  3. +33 −0 test/routing_test.rb
View
@@ -1,5 +1,9 @@
= 0.9.0 (unreleased)
+ * New ":provides" route condition takes an array of mime types and
+ matches only when an Accept request header is present with a
+ corresponding type. [cypher]
+
* Work with and require Rack >= 0.9
* Regular expressions may now be used in route pattens; captures are
View
@@ -10,6 +10,10 @@ class Request < Rack::Request
def user_agent
@env['HTTP_USER_AGENT']
end
+
+ def accept
+ @env['HTTP_ACCEPT'].split(',').map { |a| a.strip }
+ end
end
class Response < Rack::Response
@@ -88,9 +92,7 @@ def session
# Look up a media type by file extension in Rack's mime registry.
def media_type(type)
- return type if type.nil? || type.to_s.include?('/')
- type = ".#{type}" unless type.to_s[0] == ?.
- Rack::Mime.mime_type(type, nil)
+ Base.media_type(type)
end
# Set the Content-Type of the response body given a media type or file
@@ -479,6 +481,13 @@ def use_in_file_templates!
end
end
+ # Look up a media type by file extension in Rack's mime registry.
+ def media_type(type)
+ return type if type.nil? || type.to_s.include?('/')
+ type = ".#{type}" unless type.to_s[0] == ?.
+ Rack::Mime.mime_type(type, nil)
+ end
+
def before(&block)
@filters << block
end
@@ -502,6 +511,21 @@ def user_agent(pattern)
}
end
+ def accept_mime_types(types)
+ types = [types] unless types.kind_of? Array
+ types.map!{|t| media_type(t)}
+
+ condition {
+ matching_types = (request.accept & types)
+ unless matching_types.empty?
+ response.headers['Content-Type'] = matching_types.first
+ true
+ else
+ false
+ end
+ }
+ end
+
def get(path, opts={}, &block)
conditions = @conditions.dup
route 'GET', path, opts, &block
@@ -519,6 +543,7 @@ def head(path, opts={}, &bk); route 'HEAD', path, opts, &bk; end
def route(method, path, opts={}, &block)
host_name opts[:host] if opts.key?(:host)
user_agent opts[:agent] if opts.key?(:agent)
+ accept_mime_types opts[:provides] if opts.key?(:provides)
pattern, keys = compile(path)
conditions, @conditions = @conditions, []
View
@@ -302,4 +302,37 @@
status.should.equal 200
body.should.equal 'Hello Bar'
end
+
+ it "filters by accept header" do
+ mock_app {
+ get '/', :provides => :xml do
+ request.env['HTTP_ACCEPT']
+ end
+ }
+
+ get '/', :env => { :accept => 'application/xml' }
+ should.be.ok
+ body.should.equal 'application/xml'
+ response.headers['Content-Type'].should.equal 'application/xml'
+
+ get '/', :env => { :accept => 'text/html' }
+ should.not.be.ok
+ end
+
+ it "allows multiple mime types for accept header" do
+ types = ['image/jpeg', 'image/pjpeg']
+
+ mock_app {
+ get '/', :provides => types do
+ request.env['HTTP_ACCEPT']
+ end
+ }
+
+ types.each do |type|
+ get '/', :env => { :accept => type }
+ should.be.ok
+ body.should.equal type
+ response.headers['Content-Type'].should.equal type
+ end
+ end
end

0 comments on commit 38778ed

Please sign in to comment.