1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135
|
# frozen_string_literal: true
module Sprockets
# Internal: HTTP URI utilities. Many adapted from Rack::Utils. Mixed into
# Environment.
module HTTPUtils
extend self
# Public: Test mime type against mime range.
#
# match_mime_type?('text/html', 'text/*') => true
# match_mime_type?('text/plain', '*') => true
# match_mime_type?('text/html', 'application/json') => false
#
# Returns true if the given value is a mime match for the given mime match
# specification, false otherwise.
def match_mime_type?(value, matcher)
v1, v2 = value.split('/'.freeze, 2)
m1, m2 = matcher.split('/'.freeze, 2)
(m1 == '*'.freeze || v1 == m1) && (m2.nil? || m2 == '*'.freeze || m2 == v2)
end
# Public: Return values from Hash where the key matches the mime type.
#
# hash - Hash of String matcher keys to Object values
# mime_type - String mime type
#
# Returns Array of Object values.
def match_mime_type_keys(hash, mime_type)
type, subtype = mime_type.split('/', 2)
[
hash["*"],
hash["*/*"],
hash["#{type}/*"],
hash["#{type}/#{subtype}"]
].compact
end
# Internal: Parse Accept header quality values.
#
# values - String e.g. "application/javascript"
#
# Adapted from Rack::Utils#q_values. Quality values are
# described in http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html
#
# parse_q_values("application/javascript")
# # => [["application/javascript", 1.0]]
#
# parse_q_values("*/*")
# # => [["*/*", 1.0]]
#
# parse_q_values("text/plain; q=0.5, image/*")
# # => [["text/plain", 0.5], ["image/*", 1.0]]
#
# parse_q_values("application/javascript, text/css")
# # => [["application/javascript", 1.0], ["text/css", 1.0]]
#
# Returns an Array of [String, Float].
def parse_q_values(values)
values.to_s.split(/\s*,\s*/).map do |part|
value, parameters = part.split(/\s*;\s*/, 2)
quality = 1.0
if md = /\Aq=([\d.]+)/.match(parameters)
quality = md[1].to_f
end
[value, quality]
end
end
# Internal: Find all qvalue matches from an Array of available options.
#
# Adapted from Rack::Utils#q_values.
#
# Returns Array of matched Strings from available Array or [].
def find_q_matches(q_values, available, &matcher)
matcher ||= lambda { |a, b| a == b }
matches = []
case q_values
when Array
when String
q_values = parse_q_values(q_values)
when NilClass
q_values = []
else
raise TypeError, "unknown q_values type: #{q_values.class}"
end
i = 0
q_values.each do |accepted, quality|
if match = available.find { |option| matcher.call(option, accepted) }
i += 1
matches << [-quality, i, match]
end
end
matches.sort!
matches.map! { |_, _, match| match }
matches
end
# Internal: Find the best qvalue match from an Array of available options.
#
# Adapted from Rack::Utils#q_values.
#
# Returns the matched String from available Array or nil.
def find_best_q_match(q_values, available, &matcher)
find_q_matches(q_values, available, &matcher).first
end
# Internal: Find the all qvalue match from an Array of available mime type
# options.
#
# Adapted from Rack::Utils#q_values.
#
# Returns Array of matched mime type Strings from available Array or [].
def find_mime_type_matches(q_value_header, available)
find_q_matches(q_value_header, available) do |a, b|
match_mime_type?(a, b)
end
end
# Internal: Find the best qvalue match from an Array of available mime type
# options.
#
# Adapted from Rack::Utils#q_values.
#
# Returns the matched mime type String from available Array or nil.
def find_best_mime_type_match(q_value_header, available)
find_best_q_match(q_value_header, available) do |a, b|
match_mime_type?(a, b)
end
end
end
end
|