Skip to content

Commit

Permalink
Add filtering support for Accept HTTP header.
Browse files Browse the repository at this point in the history
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
cypher authored and rtomayko committed Jan 7, 2009
1 parent 9681803 commit 38778ed
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 3 deletions.
4 changes: 4 additions & 0 deletions CHANGES
Original file line number Diff line number Diff line change
@@ -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
Expand Down
31 changes: 28 additions & 3 deletions lib/sinatra/base.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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, []
Expand Down
33 changes: 33 additions & 0 deletions test/routing_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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.