提交 4e0028fb 编写于 作者: J Jamis Buck

Make Mime::Type.parse consider q values (if any)


git-svn-id: http://svn-commit.rubyonrails.org/rails/trunk@3917 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
上级 263479b5
*SVN*
* Make Mime::Type.parse consider q values (if any) [Jamis Buck]
* XML-formatted requests are typecast according to "type" attributes for :xml_simple [Jamis Buck]
* Added protection against proxy setups treating requests as local even when they're not #3898 [stephen_purcell@yahoo.com]
......
module Mime
class Type
# A simple helper class used in parsing the accept header
class AcceptItem #:nodoc:
attr_accessor :order, :name, :q
def initialize(order, name, q=nil)
@order = order
@name = name.strip
q ||= 0.0 if @name == "*/*" # default "*/*" to end of list
@q = ((q || 1.0).to_f * 100).to_i
end
def to_s
@name
end
def <=>(item)
result = item.q <=> q
result = order <=> item.order if result == 0
result
end
def ==(item)
name == (item.respond_to?(:name) ? item.name : item)
end
end
class << self
def lookup(string)
LOOKUP[string]
end
def parse(accept_header)
mime_types = accept_header.split(",").collect! do |mime_type|
mime_type.split(";").first.strip
# keep track of creation order to keep the subsequent sort stable
index = 0
list = accept_header.split(/,/).
map! { |i| AcceptItem.new(index += 1, *i.split(/;\s*q=/)) }.sort!
# Take care of the broken text/xml entry by renaming or deleting it
text_xml = list.index("text/xml")
app_xml = list.index("application/xml")
if text_xml && app_xml
# set the q value to the max of the two
list[app_xml].q = [list[text_xml].q, list[app_xml].q].max
# make sure app_xml is ahead of text_xml in the list
if app_xml > text_xml
list[app_xml], list[text_xml] = list[text_xml], list[app_xml]
app_xml, text_xml = text_xml, app_xml
end
# delete text_xml from the list
list.delete_at(text_xml)
elsif text_xml
list[text_xml].name = "application/xml"
end
reorder_xml_types!(mime_types)
mime_types.collect! { |mime_type| Mime::Type.lookup(mime_type) }
end
private
def reorder_xml_types!(mime_types)
mime_types.delete("text/xml") if mime_types.include?("application/xml")
# Look for more specific xml-based types and sort them ahead of app/xml
if index_for_generic_xml = mime_types.index("application/xml")
specific_xml_types = mime_types[index_for_generic_xml..-1].grep(/application\/[a-z]*\+xml/)
if app_xml
idx = app_xml
app_xml_type = list[app_xml]
for specific_xml_type in specific_xml_types.reverse
mime_types.insert(index_for_generic_xml, mime_types.delete(specific_xml_type))
while(idx < list.length)
type = list[idx]
break if type.q < app_xml_type.q
if type.name =~ /\+xml$/
list[app_xml], list[idx] = list[idx], list[app_xml]
app_xml = idx
end
idx += 1
end
end
list.map! { |i| Mime::Type.lookup(i.name) }.uniq!
list
end
end
def initialize(string, symbol = nil, synonyms = [])
......
require File.dirname(__FILE__) + '/../abstract_unit'
class MimeTypeTest < Test::Unit::TestCase
Mime::PNG = Mime::Type.new("image/png")
Mime::PLAIN = Mime::Type.new("text/plain")
def test_parse_single
Mime::LOOKUP.keys.each do |mime_type|
assert_equal [Mime::Type.lookup(mime_type)], Mime::Type.parse(mime_type)
end
end
def test_parse_without_q
accept = "text/xml,application/xhtml+xml,text/yaml,application/xml,text/html,image/png,text/plain,*/*"
expect = [Mime::HTML, Mime::XML, Mime::YAML, Mime::PNG, Mime::PLAIN, Mime::ALL]
assert_equal expect, Mime::Type.parse(accept)
end
def test_parse_with_q
accept = "text/xml,application/xhtml+xml,text/yaml; q=0.3,application/xml,text/html; q=0.8,image/png,text/plain; q=0.5,*/*; q=0.2"
expect = [Mime::HTML, Mime::XML, Mime::PNG, Mime::PLAIN, Mime::YAML, Mime::ALL]
assert_equal expect, Mime::Type.parse(accept)
end
end
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册