Allow more than one type in Accept header
This commit is contained in:
parent
179c5cbc4c
commit
c9e99cf2cf
|
@ -7,6 +7,58 @@ class Travis::Api::App
|
|||
DEFAULT_VERSION = 'v1'
|
||||
DEFAULT_FORMAT = 'json'
|
||||
|
||||
class Entry
|
||||
SEPARATORS = Regexp.escape("()<>@,;:\/[]?={}\t ")
|
||||
TOKEN = /[^#{SEPARATORS}]+/
|
||||
attr_reader :type, :subtype, :quality, :params
|
||||
def initialize(accept_string)
|
||||
@type, @subtype, @quality, @params = parse(accept_string)
|
||||
end
|
||||
|
||||
def <=>(other)
|
||||
[1 - quality, full_type.count('*'), 1 - params.size] <=>
|
||||
[1 - other.quality, other.full_type.count('*'), 1 - other.params.size]
|
||||
end
|
||||
|
||||
def full_type
|
||||
"#{type}/#{subtype}"
|
||||
end
|
||||
|
||||
def mime_type
|
||||
subtype = self.subtype =~ HEADER_FORMAT ? $2 : self.subtype
|
||||
"#{type}/#{subtype}"
|
||||
end
|
||||
|
||||
def version
|
||||
$1 if subtype =~ HEADER_FORMAT
|
||||
end
|
||||
|
||||
def to_s
|
||||
str = "#{full_type}; q=#{quality}"
|
||||
str << "; #{params.map { |k,v| "#{k}=#{v}" }.join('; ')}" if params.length > 0
|
||||
str
|
||||
end
|
||||
|
||||
private
|
||||
def parse(str)
|
||||
# this handles only subset of what Accept header can
|
||||
# contain, only the simplest cases, no quoted strings etc.
|
||||
type, subtype, params = str.scan(%r{(#{TOKEN})/(#{TOKEN})(.*)}).flatten
|
||||
quality = 1
|
||||
if params
|
||||
params = Hash[*params.split(';').map { |p| p.scan /(#{TOKEN})=(#{TOKEN})/ }.flatten]
|
||||
quality = params.delete('q').to_f if params['q']
|
||||
end
|
||||
|
||||
[type, subtype, quality, params]
|
||||
end
|
||||
end
|
||||
|
||||
def accept_entries
|
||||
entries = env['HTTP_ACCEPT'].to_s.delete(' ').to_s.split(',').map { |e| Entry.new(e) }
|
||||
entries.empty? ? [Entry.new('*/*')] : entries.sort
|
||||
end
|
||||
|
||||
def accept_version
|
||||
@accept_version ||= request.accept.join =~ HEADER_FORMAT && "v#{$1}" || DEFAULT_VERSION
|
||||
end
|
||||
|
|
29
spec/unit/helpers/accept_spec.rb
Normal file
29
spec/unit/helpers/accept_spec.rb
Normal file
|
@ -0,0 +1,29 @@
|
|||
require 'spec_helper'
|
||||
|
||||
module Travis::Api::App::Helpers
|
||||
describe Accept do
|
||||
class FakeApp < Struct.new(:env)
|
||||
include Accept
|
||||
end
|
||||
|
||||
it 'returns accept entries sorted properly' do
|
||||
accept = "text/html; q=0.2; level=1, application/vnd.travis-ci.2+json, text/*, text/html;level=2; q=0.5"
|
||||
FakeApp.new('HTTP_ACCEPT' => accept).accept_entries.map(&:to_s).should ==
|
||||
["application/vnd.travis-ci.2+json; q=1", "text/*; q=1", "text/html; q=0.5; level=2", "text/html; q=0.2; level=1"]
|
||||
end
|
||||
|
||||
it 'properly parses params, quality and version' do
|
||||
accept = "application/vnd.travis-ci.2+json; q=0.2; level=1; foo=bar"
|
||||
accept_entry = FakeApp.new('HTTP_ACCEPT' => accept).accept_entries.first
|
||||
accept_entry.quality.should == 0.2
|
||||
accept_entry.params.should == { 'level' => '1', 'foo' => 'bar' }
|
||||
accept_entry.mime_type.should == 'application/json'
|
||||
accept_entry.version.should == '2'
|
||||
end
|
||||
|
||||
it 'returns */* for empty accept header' do
|
||||
accept_entry = FakeApp.new({}).accept_entries.first
|
||||
accept_entry.mime_type.should == '*/*'
|
||||
end
|
||||
end
|
||||
end
|
Loading…
Reference in New Issue
Block a user