module Webmachine::Decision::Conneg
Contains methods concerned with Content Negotiation, specifically, choosing media types, encodings, character sets and languages.
Constants
- CONNEG_REGEX
Matches acceptable items that include ‘q’ values
- HAS_ENCODING
Public Instance Methods
Given the ‘Accept-Charset’ header and provided charsets, chooses an appropriate charset. @api private
# File lib/webmachine/decision/conneg.rb, line 44 def choose_charset(provided, header) if provided && !provided.empty? charsets = provided.map { |c| c.first } if charset = do_choose(charsets, header, HAS_ENCODING ? Encoding.default_external.name : kcode_charset) metadata[CHARSET] = charset end else true end end
Given the ‘Accept-Encoding’ header and provided encodings, chooses an appropriate encoding. @api private
# File lib/webmachine/decision/conneg.rb, line 33 def choose_encoding(provided, header) encodings = provided.keys if encoding = do_choose(encodings, header, IDENTITY) response.headers[CONTENT_ENCODING] = encoding unless encoding == IDENTITY metadata[CONTENT_ENCODING] = encoding end end
Given the ‘Accept-Language’ header and provided languages, chooses an appropriate language. @api private
# File lib/webmachine/decision/conneg.rb, line 58 def choose_language(provided, header) if provided && !provided.empty? requested = PriorityList.build(header.split(SPLIT_COMMA)) star_priority = requested.priority_of(STAR) any_ok = star_priority && star_priority > 0.0 accepted = requested.find do |priority, range| if priority == 0.0 provided.delete_if { |tag| language_match(range, tag) } false else provided.any? { |tag| language_match(range, tag) } end end chosen = if accepted provided.find { |tag| language_match(accepted.last, tag) } elsif any_ok provided.first end if chosen metadata['Language'] = chosen response.headers['Content-Language'] = chosen end else true end end
Given the ‘Accept’ header and provided types, chooses an appropriate media type. @api private
# File lib/webmachine/decision/conneg.rb, line 16 def choose_media_type(provided, header) types = Array(header).map { |h| h.split(SPLIT_COMMA) }.flatten requested = MediaTypeList.build(types) provided = provided.map do |p| # normalize_provided MediaType.parse(p) end # choose_media_type1 chosen = nil requested.each do |_, requested_type| break if chosen = media_match(requested_type, provided) end chosen end
Makes an conneg choice based what is accepted and what is provided. @api private
# File lib/webmachine/decision/conneg.rb, line 100 def do_choose(choices, header, default) choices = choices.dup.map { |s| s.downcase } accepted = PriorityList.build(header.split(SPLIT_COMMA)) default_priority = accepted.priority_of(default) star_priority = accepted.priority_of(STAR) default_ok = (default_priority.nil? && star_priority != 0.0) || default_priority any_ok = star_priority && star_priority > 0.0 chosen = accepted.find do |priority, acceptable| if priority == 0.0 choices.delete(acceptable.downcase) false else choices.include?(acceptable.downcase) end end chosen&.last || # Use the matching one (any_ok && choices.first) || # Or first if "*" (default_ok && choices.include?(default) && default) # Or default end
Implements language-negotation matching as described in RFC2616, section 14.14.
A language-range matches a language-tag if it exactly equals the tag, or if it exactly equals a prefix of the tag such that the first tag character following the prefix is “-”. @api private
# File lib/webmachine/decision/conneg.rb, line 93 def language_match(range, tag) range.downcase == tag.downcase || tag =~ /^#{Regexp.escape(range)}-/i end
Private Instance Methods
Translate a KCODE value to a charset name
# File lib/webmachine/decision/conneg.rb, line 139 def kcode_charset case $KCODE when /^U/i 'UTF-8' when /^S/i 'Shift-JIS' when /^B/i 'Big5' else # when /^A/i, nil 'ASCII' end end
Matches the requested media type (with potential modifiers) against the provided types (with potential modifiers). @param [MediaType] requested the requested media type @param [Array<MediaType>] provided the provided media
types
@return [MediaType] the first media type that matches
# File lib/webmachine/decision/conneg.rb, line 131 def media_match(requested, provided) return provided.first if requested.matches_all? provided.find do |p| p.match?(requested) end end