Skip to content

Commit

Permalink
Add support for parameters when creating mime types
Browse files Browse the repository at this point in the history
  • Loading branch information
JonMidhir committed Feb 10, 2017
1 parent 32f416c commit 49b5324
Show file tree
Hide file tree
Showing 3 changed files with 76 additions and 5 deletions.
38 changes: 33 additions & 5 deletions lib/sinatra/base.rb
Expand Up @@ -42,12 +42,11 @@ def accept?(type)
end

def preferred_type(*types)
accepts = accept # just evaluate once
return accepts.first if types.empty?
return accept.first if types.empty?
types.flatten!
return types.first if accepts.empty?
accepts.detect do |pattern|
type = types.detect { |t| File.fnmatch(pattern, t) }
return types.first if accept.empty?
accept.detect do |accept_header|
type = types.detect { |t| MimeTypeEntry.new(t).accepts?(accept_header) }
return type if type
end
end
Expand Down Expand Up @@ -124,6 +123,35 @@ def method_missing(*args, &block)
to_str.send(*args, &block)
end
end

class MimeTypeEntry
attr_reader :params

def initialize(entry)
params = entry.scan(HEADER_PARAM).map! do |s|
key, value = s.strip.split('=', 2)
value = value[1..-2].gsub(/\\(.)/, '\1') if value.start_with?('"')
[key, value]
end

@type = entry[/[^;]+/].delete(' ')
@params = Hash[params]
end

def accepts?(entry)
File.fnmatch(entry, self) && matches_params?(entry.params)
end

def to_str
@type
end

def matches_params?(params)
return true if @params.empty?

params.all? { |k,v| !@params.has_key?(k) || @params[k] == v }
end
end
end

# The response object. See Rack::Response and Rack::Response::Helpers for
Expand Down
20 changes: 20 additions & 0 deletions test/request_test.rb
Expand Up @@ -102,4 +102,24 @@ class RequestTest < Minitest::Test
request = Sinatra::Request.new 'HTTP_ACCEPT' => 'application/json'
assert !request.accept?('text/html')
end

it 'will accept types that fulfill HTTP_ACCEPT parameters' do
request = Sinatra::Request.new 'HTTP_ACCEPT' => 'application/rss+xml; version="http://purl.org/rss/1.0/"'

assert request.accept?('application/rss+xml; version="http://purl.org/rss/1.0/"')
assert request.accept?('application/rss+xml; version="http://purl.org/rss/1.0/"; charset=utf-8')
assert !request.accept?('application/rss+xml; version="https://cyber.harvard.edu/rss/rss.html"')
end

it 'will accept more generic types that include HTTP_ACCEPT parameters' do
request = Sinatra::Request.new 'HTTP_ACCEPT' => 'application/rss+xml; charset=utf-8; version="http://purl.org/rss/1.0/"'

assert request.accept?('application/rss+xml')
assert request.accept?('application/rss+xml; version="http://purl.org/rss/1.0/"')
end

it 'will accept types matching HTTP_ACCEPT when parameters in arbitrary order' do
request = Sinatra::Request.new 'HTTP_ACCEPT' => 'application/rss+xml; charset=utf-8; version="http://purl.org/rss/1.0/"'
assert request.accept?('application/rss+xml; version="http://purl.org/rss/1.0/"; charset=utf-8')
end
end
23 changes: 23 additions & 0 deletions test/routing_test.rb
Expand Up @@ -1228,6 +1228,29 @@ class RoutingTest < Minitest::Test
assert_body 'text/xml;charset=utf-8'
end

it 'matches content-type to mime_type' do
mime_type = 'application/rss+xml;version="http://purl.org/rss/1.0/"'
mock_app do
configure { mime_type(:rss10, mime_type) }
get('/', :provides => [:rss10]) { content_type }
end

get '/', {}, { 'HTTP_ACCEPT' => 'application/rss+xml' }
assert ok?
assert_body mime_type
end

it 'handles missing mime_types with 404' do
mock_app do
configure { mime_type(:rss10, 'application/rss+xml') }
get('/', :provides => [:jpg]) { content_type }
end

get '/', {}, { 'HTTP_ACCEPT' => 'application/rss+xml' }
assert_equal 404, status
assert_equal 'text/html;charset=utf-8', response['Content-Type']
end

it 'passes a single url param as block parameters when one param is specified' do
mock_app {
get '/:foo' do |foo|
Expand Down

0 comments on commit 49b5324

Please sign in to comment.