Module: Webmachine::Decision::Conneg

Included in:
Flow
Defined in:
lib/webmachine/decision/conneg.rb

Overview

Contains methods concerned with Content Negotiation, specifically, choosing media types, encodings, character sets and languages.

Defined Under Namespace

Classes: MediaTypeList, PriorityList

Constant Summary collapse

HAS_ENCODING =

Ruby 1.9 compat

defined?(::Encoding)

Instance Method Summary collapse

Instance Method Details

#choose_charset(provided, header) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Given the ‘Accept-Charset’ header and provided charsets, chooses an appropriate charset.



44
45
46
47
48
49
50
51
52
53
# 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)
      [CHARSET] = charset
    end
  else
    true
  end
end

#choose_encoding(provided, header) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Given the ‘Accept-Encoding’ header and provided encodings, chooses an appropriate encoding.



33
34
35
36
37
38
39
# 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
    [CONTENT_ENCODING] = encoding
  end
end

#choose_language(provided, header) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Given the ‘Accept-Language’ header and provided languages, chooses an appropriate language.



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
# 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
      ['Language'] = chosen
      response.headers['Content-Language'] = chosen
    end
  else
    true
  end
end

#choose_media_type(provided, header) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Given the ‘Accept’ header and provided types, chooses an appropriate media type.



16
17
18
19
20
21
22
23
24
25
26
27
28
# 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

#do_choose(choices, header, default) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Makes an conneg choice based what is accepted and what is provided.



100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
# 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 && chosen.last) ||  # Use the matching one
    (any_ok && choices.first) || # Or first if "*"
    (default_ok && choices.include?(default) && default) # Or default
end

#language_match(range, tag) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

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 “-”.



93
94
95
# File 'lib/webmachine/decision/conneg.rb', line 93

def language_match(range, tag)
  range.downcase == tag.downcase || tag =~ /^#{Regexp.escape(range)}\-/i
end