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.

API:

  • private



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.

API:

  • private



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.

API:

  • private



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.

API:

  • private



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.

API:

  • private



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&.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 "-".

API:

  • private



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