Module: Strelka::HTTPRequest::Negotiation

Includes:
Constants
Defined in:
lib/strelka/httprequest/negotiation.rb

Overview

The mixin that adds methods to Strelka::HTTPRequest for content-negotiation.

request.accepts?( 'application/json' )
request.explicitly_accepts?( 'application/xml+rdf' )
request.accepts_charset?( Encoding::UTF_8 )
request.accepts_charset?( 'iso-8859-15' )
request.accepts_encoding?( 'compress' )
request.accepts_language?( 'en' )
request.explicitly_accepts_language?( 'en' )
request.explicitly_accepts_language?( 'en-gb' )

Instance Method Summary collapse

Instance Method Details

#accepted_charsetsObject

Return an Array of Strelka::HTTPRequest::Charset objects for each type in the ‘Accept-Charset’ header.



114
115
116
117
# File 'lib/strelka/httprequest/negotiation.rb', line 114

def accepted_charsets
	@accepted_charsets ||= self.parse_accept_charset_header
	return @accepted_charsets
end

#accepted_encodingsObject

Return an Array of Strelka::HTTPRequest::Encoding objects for each type in the ‘Accept-Encoding’ header.



155
156
157
158
# File 'lib/strelka/httprequest/negotiation.rb', line 155

def accepted_encodings
	@accepted_encodings ||= self.parse_accept_encoding_header
	return @accepted_encodings
end

#accepted_languagesObject

Return an Array of Strelka::HTTPRequest::Language objects for each type in the ‘Accept-Language’ header.



225
226
227
228
# File 'lib/strelka/httprequest/negotiation.rb', line 225

def accepted_languages
	@accepted_languages ||= self.parse_accept_language_header
	return @accepted_languages
end

#accepted_mediatypesObject Also known as: accepted_types

Return an Array of Strelka::HTTPRequest::MediaType objects for each type in the ‘Accept’ header.



68
69
70
71
# File 'lib/strelka/httprequest/negotiation.rb', line 68

def accepted_mediatypes
	@accepted_mediatypes ||= self.parse_accept_header
	return @accepted_mediatypes
end

#accepts?(content_type) ⇒ Boolean Also known as: accept?

Returns boolean true/false if the requestor can handle the given content_type.

Returns:

  • (Boolean)


77
78
79
80
81
82
# File 'lib/strelka/httprequest/negotiation.rb', line 77

def accepts?( content_type )
	self.log.debug "Checking to see if request accepts %p" % [ content_type ]
	atype = self.accepted_types.find {|type| type =~ content_type }
	self.log.debug "  find returned: %p" % [ atype ]
	return atype ? true : false
end

#accepts_charset?(charset) ⇒ Boolean Also known as: accept_charset?

Returns boolean true/false if the requestor can handle the given charset.

Returns:

  • (Boolean)


122
123
124
125
126
127
# File 'lib/strelka/httprequest/negotiation.rb', line 122

def accepts_charset?( charset )
	self.log.debug "Checking to see if request accepts charset: %p" % [ charset ]
	aset = self.accepted_charsets.find {|cs| cs =~ charset }
	self.log.debug "  find returned: %p" % [ aset ]
	return aset ? true : false
end

#accepts_encoding?(encoding) ⇒ Boolean Also known as: accept_encoding?

Returns boolean true/false if the requestor can handle the given encoding.

Returns:

  • (Boolean)


163
164
165
166
167
168
169
170
171
172
173
174
# File 'lib/strelka/httprequest/negotiation.rb', line 163

def accepts_encoding?( encoding )
	self.log.debug "Checking to see if request accepts encoding: %p" % [ encoding ]
	return true if self.accepted_encodings.empty?
	found_encoding = self.accepted_encodings.find {|enc| enc =~ encoding }
	self.log.debug "  find returned: %p" % [ found_encoding ]

	# If there was no match, then it's not accepted, unless it's the 'identity'
	# encoding, which is accepted unless it's disabled.
	return encoding == 'identity' if !found_encoding

	return found_encoding.qvalue.nonzero?
end

#accepts_language?(language) ⇒ Boolean Also known as: accept_language?

Returns boolean true/false if the requestor can handle the given language.

Returns:

  • (Boolean)


233
234
235
236
237
238
# File 'lib/strelka/httprequest/negotiation.rb', line 233

def accepts_language?( language )
	self.log.debug "Checking to see if request accepts language: %p" % [ language ]
	found_language = self.accepted_languages.find {|langcode| langcode =~ language }
	self.log.debug "  find returned: %p" % [ found_language ]
	return found_language && found_language.qvalue.nonzero?
end

#explicitly_accepts?(content_type) ⇒ Boolean Also known as: explicitly_accept?

Returns boolean true/false if the requestor can handle the given content_type, not including mime wildcards.

Returns:

  • (Boolean)


88
89
90
91
# File 'lib/strelka/httprequest/negotiation.rb', line 88

def explicitly_accepts?( content_type )
	non_wildcard_types = self.accepted_types.reject {|param| param.subtype.nil? }
	return non_wildcard_types.find {|type| type =~ content_type } ? true : false
end

#explicitly_accepts_charset?(charset) ⇒ Boolean Also known as: explicitly_accept_charset?

Returns boolean true/false if the requestor can handle the given charset, not including the wildcard tag if present.

Returns:

  • (Boolean)


133
134
135
136
# File 'lib/strelka/httprequest/negotiation.rb', line 133

def explicitly_accepts_charset?( charset )
	non_wildcard_charsets = self.accepted_charsets.reject {|param| param.charset.nil? }
	return non_wildcard_charsets.find {|cs| cs =~ charset } ? true : false
end

#explicitly_accepts_encoding?(encoding) ⇒ Boolean Also known as: explicitly_accept_encoding?

Returns boolean true/false if the requestor can handle the given encoding, not including the wildcard encoding if present.

Returns:

  • (Boolean)


180
181
182
183
184
185
# File 'lib/strelka/httprequest/negotiation.rb', line 180

def explicitly_accepts_encoding?( encoding )
	non_wildcard_encodings = self.accepted_encodings.reject {|enc| enc.content_coding.nil? }
	found_encoding = non_wildcard_encodings.find {|enc| enc =~ encoding } or
		return false
	return found_encoding.qvalue.nonzero?
end

#explicitly_accepts_language?(language) ⇒ Boolean Also known as: explicitly_accept_language?

Returns boolean true/false if the requestor can handle the given language, not including the wildcard language if present.

Returns:

  • (Boolean)


244
245
246
247
248
# File 'lib/strelka/httprequest/negotiation.rb', line 244

def explicitly_accepts_language?( language )
	non_wildcard_languages = self.accepted_languages.reject {|enc| enc.content_coding.nil? }
	found_language = non_wildcard_languages.find {|enc| enc =~ language }
	return found_language.qvalue.nonzero?
end

#initializeObject

Extension callback – add instance variables to extended objects.



25
26
27
28
29
30
31
# File 'lib/strelka/httprequest/negotiation.rb', line 25

def initialize( * )
	super
	@accepted_mediatypes = nil
	@accepted_charsets   = nil
	@accepted_encodings  = nil
	@accepted_languages  = nil
end

#parse_accept_charset_headerObject

Parse the receiver’s ‘Accept-Charset’ header and return it as an Array of Strelka::HTTPRequest::Charset objects.



142
143
144
145
146
# File 'lib/strelka/httprequest/negotiation.rb', line 142

def parse_accept_charset_header
	return self.parse_negotiation_header( :accept_charset, Strelka::HTTPRequest::Charset ) do
		Strelka::HTTPRequest::Charset.new( '*' )
	end
end

#parse_accept_encoding_headerObject

Parse the receiver’s ‘Accept-Encoding’ header and return it as an Array of Strelka::HTTPRequest::Encoding objects.



191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
# File 'lib/strelka/httprequest/negotiation.rb', line 191

def parse_accept_encoding_header
	return self.parse_negotiation_header( :accept_encoding, Strelka::HTTPRequest::Encoding ) do
		# If the Accept-Encoding field-value is empty, then only the "identity"
		# encoding is acceptable.
		if self.headers.include?( :accept_encoding )
			self.log.debug "Empty accept-encoding header: identity-only"
			[ Strelka::HTTPRequest::Encoding.new('identity') ]

		# I have no idea how this is different than an empty accept-encoding header
		# for any practical case, but RFC2616 says:
		#   If no Accept-Encoding field is present in a request, the server MAY
		#   assume that the client will accept any content coding.  In this
		#   case, if "identity" is one of the available content-codings, then
		#   the server SHOULD use the "identity" content-coding, unless it has
		#   additional information that a different content-coding is meaningful
		#   to the client.
		else
			self.log.debug "No accept-encoding header: identity + any encoding"
			[
				Strelka::HTTPRequest::Encoding.new( 'identity' ),
				Strelka::HTTPRequest::Encoding.new( '*', nil, 0.9 )
			]
		end
	end
end

#parse_accept_headerObject

Parse the receiver’s ‘Accept’ header and return it as an Array of Strelka::HTTPRequest::MediaType objects.



97
98
99
100
101
102
103
104
105
# File 'lib/strelka/httprequest/negotiation.rb', line 97

def parse_accept_header
	return self.parse_negotiation_header( :accept, Strelka::HTTPRequest::MediaType ) do
		Strelka::HTTPRequest::MediaType.new( '*', '*' )
	end
rescue => err
	self.log.error "%p while parsing the Accept header: %s" % [ err.class, err.message ]
	self.log.debug "  %s" % [ err.backtrace.join("\n  ") ]
	finish_with HTTP::BAD_REQUEST, "Malformed Accept header"
end

#parse_accept_language_headerObject

Parse the receiver’s ‘Accept-Language’ header and return it as an Array of Strelka::HTTPRequest::Language objects.



254
255
256
257
258
# File 'lib/strelka/httprequest/negotiation.rb', line 254

def parse_accept_language_header
	return self.parse_negotiation_header( :accept_language, Strelka::HTTPRequest::Language ) do
		Strelka::HTTPRequest::Language.new( '*' )
	end
end

#parse_negotiation_header(header, paramclass) ⇒ Object

Fetch the value of the given header, split apart the values, and parse each one using the specified paramclass. If no values are parsed from the header, and a block is given, the block is called and its return value is appended to the empty Array before returning it.



38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
# File 'lib/strelka/httprequest/negotiation.rb', line 38

def parse_negotiation_header( header, paramclass )
	self.log.debug "Parsing %s header into %p objects" % [ header, paramclass ]
	rval = []
	headerval = self.headers[ header ]
	self.log.debug "  raw header value: %p" % [ headerval ]

	# Handle the case where there's more than one of the header in question by
	# forcing everything to an Array
	Array( headerval ).compact.flatten.each do |paramstr|
		paramstr.split( /\s*,\s*/ ).each do |param|
			self.log.debug "    parsing param: %p" % [ param ]
			rval << paramclass.parse( param )
		end
	end

	if rval.empty? && block_given?
		self.log.debug "  no parsed values; calling the fallback block"
		rval << yield
	end

	return rval.flatten
end