Add support for parameters when creating mime types (#1256)

This commit is contained in:
John Hope 2020-03-13 21:02:56 +00:00 committed by GitHub
parent aee28a1bda
commit 574e5a9e3d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 76 additions and 5 deletions

View File

@ -43,12 +43,11 @@ module Sinatra
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
@ -125,6 +124,35 @@ module Sinatra
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

View File

@ -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

View File

@ -1347,6 +1347,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|