strelka 0.0.1pre4 → 0.0.1.pre129

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (73) hide show
  1. data/History.rdoc +1 -1
  2. data/IDEAS.rdoc +62 -0
  3. data/Manifest.txt +38 -7
  4. data/README.rdoc +124 -5
  5. data/Rakefile +22 -6
  6. data/bin/leash +102 -157
  7. data/contrib/hoetemplate/.autotest.erb +23 -0
  8. data/contrib/hoetemplate/History.rdoc.erb +4 -0
  9. data/contrib/hoetemplate/Manifest.txt.erb +8 -0
  10. data/contrib/hoetemplate/README.rdoc.erb +17 -0
  11. data/contrib/hoetemplate/Rakefile.erb +24 -0
  12. data/contrib/hoetemplate/data/file_name/apps/file_name_app +36 -0
  13. data/contrib/hoetemplate/data/file_name/templates/layout.tmpl.erb +13 -0
  14. data/contrib/hoetemplate/data/file_name/templates/top.tmpl.erb +8 -0
  15. data/contrib/hoetemplate/lib/file_name.rb.erb +18 -0
  16. data/contrib/hoetemplate/spec/file_name_spec.rb.erb +21 -0
  17. data/data/strelka/apps/hello-world +30 -0
  18. data/lib/strelka/app/defaultrouter.rb +49 -30
  19. data/lib/strelka/app/errors.rb +121 -0
  20. data/lib/strelka/app/exclusiverouter.rb +40 -0
  21. data/lib/strelka/app/filters.rb +18 -7
  22. data/lib/strelka/app/negotiation.rb +122 -0
  23. data/lib/strelka/app/parameters.rb +171 -14
  24. data/lib/strelka/app/paramvalidator.rb +751 -0
  25. data/lib/strelka/app/plugins.rb +66 -46
  26. data/lib/strelka/app/restresources.rb +499 -0
  27. data/lib/strelka/app/router.rb +73 -0
  28. data/lib/strelka/app/routing.rb +140 -18
  29. data/lib/strelka/app/templating.rb +12 -3
  30. data/lib/strelka/app.rb +174 -24
  31. data/lib/strelka/constants.rb +0 -20
  32. data/lib/strelka/exceptions.rb +29 -0
  33. data/lib/strelka/httprequest/acceptparams.rb +377 -0
  34. data/lib/strelka/httprequest/negotiation.rb +257 -0
  35. data/lib/strelka/httprequest.rb +155 -7
  36. data/lib/strelka/httpresponse/negotiation.rb +579 -0
  37. data/lib/strelka/httpresponse.rb +140 -0
  38. data/lib/strelka/logging.rb +4 -1
  39. data/lib/strelka/mixins.rb +53 -0
  40. data/lib/strelka.rb +22 -1
  41. data/spec/data/error.tmpl +1 -0
  42. data/spec/lib/constants.rb +0 -1
  43. data/spec/lib/helpers.rb +21 -0
  44. data/spec/strelka/app/defaultrouter_spec.rb +41 -35
  45. data/spec/strelka/app/errors_spec.rb +212 -0
  46. data/spec/strelka/app/exclusiverouter_spec.rb +220 -0
  47. data/spec/strelka/app/filters_spec.rb +196 -0
  48. data/spec/strelka/app/negotiation_spec.rb +73 -0
  49. data/spec/strelka/app/parameters_spec.rb +149 -0
  50. data/spec/strelka/app/paramvalidator_spec.rb +1059 -0
  51. data/spec/strelka/app/plugins_spec.rb +26 -19
  52. data/spec/strelka/app/restresources_spec.rb +393 -0
  53. data/spec/strelka/app/router_spec.rb +63 -0
  54. data/spec/strelka/app/routing_spec.rb +183 -9
  55. data/spec/strelka/app/templating_spec.rb +1 -2
  56. data/spec/strelka/app_spec.rb +265 -32
  57. data/spec/strelka/exceptions_spec.rb +53 -0
  58. data/spec/strelka/httprequest/acceptparams_spec.rb +282 -0
  59. data/spec/strelka/httprequest/negotiation_spec.rb +246 -0
  60. data/spec/strelka/httprequest_spec.rb +204 -14
  61. data/spec/strelka/httpresponse/negotiation_spec.rb +464 -0
  62. data/spec/strelka/httpresponse_spec.rb +114 -0
  63. data/spec/strelka/mixins_spec.rb +99 -0
  64. data.tar.gz.sig +1 -0
  65. metadata +175 -79
  66. metadata.gz.sig +2 -0
  67. data/IDEAS.textile +0 -174
  68. data/data/strelka/apps/strelka-admin +0 -65
  69. data/data/strelka/apps/strelka-setup +0 -26
  70. data/data/strelka/bootstrap-config.rb +0 -34
  71. data/data/strelka/templates/admin/console.tmpl +0 -21
  72. data/data/strelka/templates/layout.tmpl +0 -30
  73. data/lib/strelka/process.rb +0 -19
@@ -0,0 +1,377 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'strelka/mixins'
4
+ require 'strelka/httprequest'
5
+
6
+ class Strelka::HTTPRequest
7
+
8
+ # A parser for request Accept, Accept-encoding, Accept-charset, and Accept-language
9
+ # header values. They provide weighted and wildcard comparisions between two values
10
+ # of the same field.
11
+ #
12
+ # require 'strelka/httprequest/acceptparam'
13
+ # mediatype = Strelka::HTTPRequest::AcceptParam.parse_mediatype( "text/html;q=0.9;level=2" )
14
+ #
15
+ # ap.type #=> 'text'
16
+ # ap.subtype #=> 'html'
17
+ # ap.qvalue #=> 0.9
18
+ # ap =~ 'text/*' #=> true
19
+ #
20
+ # language = Strelka::HTTPRequest::AcceptParam.parse_language( "en-gb" )
21
+ #
22
+ # ap.type #=> :en
23
+ # ap.subtype #=> :gb
24
+ # ap.qvalue #=> 1.0
25
+ # ap =~ 'en' #=> true
26
+ #
27
+ # encoding = Strelka::HTTPRequest::AcceptParam.parse_encoding( "compress; q=0.7" )
28
+ #
29
+ # ap.type #=> :compress
30
+ # ap.subtype #=> nil
31
+ # ap.qvalue #=> 0.7
32
+ # ap =~ 'compress' #=> true
33
+ #
34
+ # charset = Strelka::HTTPRequest::AcceptParam.parse_charset( "koi8-r" )
35
+ #
36
+ # ap.type #=> 'koi8-r'
37
+ # ap.subtype #=> nil
38
+ # ap.qvalue #=> 1.0
39
+ # ap =~ 'koi8-r' #=> true
40
+ #
41
+ # == Authors
42
+ #
43
+ # * Michael Granger <ged@FaerieMUD.org>
44
+ # * Mahlon E. Smith <mahlon@martini.nu>
45
+ #
46
+ class AcceptParam
47
+ include Comparable,
48
+ Strelka::Loggable,
49
+ Strelka::AbstractClass
50
+
51
+
52
+ # The default quality value (weight) if none is specified
53
+ Q_DEFAULT = 1.0
54
+
55
+ # The maximum quality value
56
+ Q_MAX = Q_DEFAULT
57
+
58
+
59
+ #################################################################
60
+ ### I N S T A N C E M E T H O D S
61
+ #################################################################
62
+
63
+ ### Create a new Strelka::HTTPRequest::AcceptParam with the given media
64
+ ### +range+, quality value (+qval+), and extensions
65
+ def initialize( type, subtype='*', qval=Q_DEFAULT, *extensions )
66
+ type = nil if type == '*'
67
+ subtype = nil if subtype == '*'
68
+
69
+ @type = type
70
+ @subtype = subtype
71
+ @qvalue = normalize_qvalue( qval )
72
+ @extensions = extensions.flatten
73
+ end
74
+
75
+
76
+ ######
77
+ public
78
+ ######
79
+
80
+ pure_virtual :to_s
81
+
82
+
83
+ # The 'type' part of the media range
84
+ attr_reader :type
85
+
86
+ # The 'subtype' part of the media range
87
+ attr_reader :subtype
88
+
89
+ # The weight of the param
90
+ attr_reader :qvalue
91
+
92
+ # An array of any accept-extensions specified with the parameter
93
+ attr_reader :extensions
94
+
95
+
96
+ ### Match operator -- returns true if +other+ matches the receiving
97
+ ### AcceptParam.
98
+ def =~( other )
99
+ unless other.is_a?( self.class )
100
+ other = self.class.parse( other.to_s ) rescue nil
101
+ return false unless other
102
+ end
103
+
104
+ # */* returns true in either side of the comparison.
105
+ # ASSUMPTION: There will never be a case when a type is wildcarded
106
+ # and the subtype is specific. (e.g., */xml)
107
+ # We gave up trying to read RFC 2045.
108
+ return true if other.type.nil? || self.type.nil?
109
+
110
+ # text/html =~ text/html
111
+ # text/* =~ text/html
112
+ # text/html =~ text/*
113
+ if other.type == self.type
114
+ return true if other.subtype.nil? || self.subtype.nil?
115
+ return true if other.subtype == self.subtype
116
+ end
117
+
118
+ return false
119
+ end
120
+
121
+
122
+ ### Return a human-readable version of the object
123
+ def inspect
124
+ return "#<%s:0x%07x '%s/%s' q=%0.3f %p>" % [
125
+ self.class.name,
126
+ self.object_id * 2,
127
+ self.type || '*',
128
+ self.subtype || '*',
129
+ self.qvalue,
130
+ self.extensions,
131
+ ]
132
+ end
133
+
134
+
135
+ ### The weighting or "qvalue" of the parameter in the form "q=<value>"
136
+ def qvaluestring
137
+ # 3 digit precision, trim excess zeros
138
+ return sprintf( "q=%0.3f", self.qvalue ).gsub(/0{1,2}$/, '')
139
+ end
140
+
141
+
142
+ ### Return a String containing any extensions for this parameter, joined
143
+ ### with ';'
144
+ def extension_strings
145
+ return nil if self.extensions.empty?
146
+ return self.extensions.compact.join('; ')
147
+ end
148
+
149
+
150
+ ### Comparable interface. Sort parameters by weight: Returns -1 if +other+
151
+ ### is less specific than the receiver, 0 if +other+ is as specific as
152
+ ### the receiver, and +1 if +other+ is more specific than the receiver.
153
+ def <=>( other )
154
+
155
+ if rval = (other.qvalue <=> @qvalue).nonzero?
156
+ return rval
157
+ end
158
+
159
+ if self.type.nil?
160
+ return 1 if ! other.type.nil?
161
+ elsif other.type.nil?
162
+ return -1
163
+ end
164
+
165
+ if self.subtype.nil?
166
+ return 1 if ! other.subtype.nil?
167
+ elsif other.subtype.nil?
168
+ return -1
169
+ end
170
+
171
+ if rval = (self.extensions.length <=> other.extensions.length).nonzero?
172
+ return rval
173
+ end
174
+
175
+ return self.to_s <=> other.to_s
176
+ end
177
+
178
+
179
+ #######
180
+ private
181
+ #######
182
+
183
+ ### Given an input +qvalue+, return the Float equivalent.
184
+ def normalize_qvalue( qvalue )
185
+ return Q_DEFAULT unless qvalue
186
+ qvalue = Float( qvalue.to_s.sub(/q=/, '') ) unless qvalue.is_a?( Float )
187
+
188
+ if qvalue > Q_MAX
189
+ self.log.warn "Squishing invalid qvalue %p to %0.1f" %
190
+ [ qvalue, Q_DEFAULT ]
191
+ return Q_DEFAULT
192
+ end
193
+
194
+ return qvalue
195
+ end
196
+
197
+ end # class AcceptParam
198
+
199
+
200
+ # A mediatype parameter such as one you'd find in an Accept header.
201
+ class MediaType < Strelka::HTTPRequest::AcceptParam
202
+
203
+ ### Parse the given +accept_param+ as a mediatype and return a
204
+ ### Strelka::HTTPRequest::MediaType object for it.
205
+ def self::parse( accept_param )
206
+ raise ArgumentError, "Bad Accept param: no media-range in %p" % [accept_param] unless
207
+ accept_param.include?( '/' )
208
+ media_range, *stuff = accept_param.split( /\s*;\s*/ )
209
+ type, subtype = media_range.downcase.split( '/', 2 )
210
+ qval, opts = stuff.partition {|par| par =~ /^q\s*=/ }
211
+
212
+ return new( type, subtype, qval.first, *opts )
213
+ end
214
+
215
+
216
+ ### The mediatype of the parameter, consisting of the type and subtype
217
+ ### separated by '/'.
218
+ def mediatype
219
+ return "%s/%s" % [ self.type || '*', self.subtype || '*' ]
220
+ end
221
+ alias_method :mimetype, :mediatype
222
+ alias_method :content_type, :mediatype
223
+
224
+
225
+ ### Return the parameter as a String suitable for inclusion in an Accept
226
+ ### HTTP header
227
+ def to_s
228
+ return [
229
+ self.mediatype,
230
+ self.qvaluestring,
231
+ self.extension_strings
232
+ ].compact.join(';')
233
+ end
234
+
235
+ end # class MediaType
236
+
237
+
238
+ # A natural language specification parameter, such as one you'd find in an
239
+ # Accept-Language header.
240
+ class Language < Strelka::HTTPRequest::AcceptParam
241
+
242
+ ### Parse the given +accept_param+ as a language range and return a
243
+ ### Strelka::HTTPRequest::Language object for it.
244
+ def self::parse( accept_param )
245
+ language_range, *stuff = accept_param.split( /\s*;\s*/ )
246
+ type, subtype = language_range.downcase.split( '-', 2 )
247
+ qval, opts = stuff.partition {|par| par =~ /^q\s*=/ }
248
+
249
+ return new( type, subtype, qval.first, *opts )
250
+ end
251
+
252
+
253
+ ######
254
+ public
255
+ ######
256
+
257
+ alias_method :primary_tag, :type
258
+ alias_method :subtag, :subtype
259
+
260
+ ### Return the language range of the parameter as a String.
261
+ def language_range
262
+ return [ self.primary_tag, self.subtag ].compact.join( '-' )
263
+ end
264
+
265
+ ### Return the parameter as a String suitable for inclusion in an
266
+ ### Accept-language header.
267
+ def to_s
268
+ return [
269
+ self.language_range,
270
+ self.qvaluestring,
271
+ self.extension_strings,
272
+ ].compact.join( ';' )
273
+ end
274
+
275
+ end # class Language
276
+
277
+
278
+ # A content encoding parameter, such as one you'd find in an Accept-Encoding header.
279
+ class Encoding < Strelka::HTTPRequest::AcceptParam
280
+
281
+ ### Parse the given +accept_param+ as a content coding and return a
282
+ ### Strelka::HTTPRequest::Encoding object for it.
283
+ def self::parse( accept_param )
284
+ content_coding, *stuff = accept_param.split( /\s*;\s*/ )
285
+ qval, opts = stuff.partition {|par| par =~ /^q\s*=/ }
286
+
287
+ return new( content_coding, nil, qval.first, *opts )
288
+ end
289
+
290
+
291
+ ######
292
+ public
293
+ ######
294
+
295
+ alias_method :content_coding, :type
296
+
297
+
298
+ ### Return the parameter as a String suitable for inclusion in an
299
+ ### Accept-language header.
300
+ def to_s
301
+ return [
302
+ self.content_coding,
303
+ self.qvaluestring,
304
+ self.extension_strings,
305
+ ].compact.join( ';' )
306
+ end
307
+
308
+ end # class Encoding
309
+
310
+
311
+ # A content character-set parameter, such as one you'd find in an Accept-Charset header.
312
+ class Charset < Strelka::HTTPRequest::AcceptParam
313
+
314
+ ### Parse the given +accept_param+ as a charset and return a
315
+ ### Strelka::HTTPRequest::Charset object for it.
316
+ def self::parse( accept_param )
317
+ charset, *stuff = accept_param.split( /\s*;\s*/ )
318
+ qval, opts = stuff.partition {|par| par =~ /^q\s*=/ }
319
+
320
+ return new( charset, nil, qval.first, *opts )
321
+ end
322
+
323
+
324
+ ######
325
+ public
326
+ ######
327
+
328
+ alias_method :name, :type
329
+
330
+
331
+ ### Return the parameter as a String suitable for inclusion in an
332
+ ### Accept-language header.
333
+ def to_s
334
+ return [
335
+ self.name,
336
+ self.qvaluestring,
337
+ self.extension_strings,
338
+ ].compact.join( ';' )
339
+ end
340
+
341
+
342
+ ### Return the Ruby Encoding object that is associated with the parameter's charset.
343
+ def encoding_object
344
+ return ::Encoding.find( self.name )
345
+ rescue ArgumentError => err
346
+ self.log.warn( err.message )
347
+ # self.log.debug( err.backtrace.join($/) )
348
+ return nil
349
+ end
350
+
351
+
352
+ ### Match operator -- returns true if +other+ matches the receiving
353
+ ### AcceptParam.
354
+ def =~( other )
355
+ unless other.is_a?( self.class )
356
+ other = self.class.parse( other.to_s ) rescue nil
357
+ return false unless other
358
+ end
359
+
360
+ # The special value "*", if present in the Accept-Charset field,
361
+ # matches every character set (including ISO-8859-1) which is not
362
+ # mentioned elsewhere in the Accept-Charset field.
363
+ return true if other.name.nil? || self.name.nil?
364
+
365
+ # Same downcased names or different names for the same encoding should match
366
+ return true if other.name.downcase == self.name.downcase ||
367
+ other.encoding_object == self.encoding_object
368
+
369
+ return false
370
+ end
371
+
372
+ end # class Charset
373
+
374
+
375
+ end # class Strelka::HTTPRequest
376
+
377
+ # vim: set nosta noet ts=4 sw=4:
@@ -0,0 +1,257 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'strelka/constants'
4
+ require 'strelka/httprequest' unless defined?( Strelka::HTTPRequest )
5
+ require 'strelka/httprequest/acceptparams'
6
+
7
+
8
+ # The mixin that adds methods to Strelka::HTTPRequest for content-negotiation.
9
+ #
10
+ # request.accepts?( 'application/json' )
11
+ # request.explicitly_accepts?( 'application/xml+rdf' )
12
+ # request.accepts_charset?( Encoding::UTF_8 )
13
+ # request.accepts_charset?( 'iso-8859-15' )
14
+ # request.accepts_encoding?( 'compress' )
15
+ # request.accepts_language?( 'en' )
16
+ # request.explicitly_accepts_language?( 'en' )
17
+ # request.explicitly_accepts_language?( 'en-gb' )
18
+ #
19
+ module Strelka::HTTPRequest::Negotiation
20
+ include Strelka::Constants
21
+
22
+ ### Extension callback -- add instance variables to extended objects.
23
+ def initialize( * )
24
+ super
25
+ @accepted_mediatypes = nil
26
+ @accepted_charsets = nil
27
+ @accepted_encodings = nil
28
+ @accepted_languages = nil
29
+ end
30
+
31
+
32
+ ### Fetch the value of the given +header+, split apart the values, and parse
33
+ ### each one using the specified +paramclass+. If no values are parsed from
34
+ ### the header, and a block is given, the block is called and its return value
35
+ ### is appended to the empty Array before returning it.
36
+ def parse_negotiation_header( header, paramclass )
37
+ self.log.debug "Parsing %s header into %p objects" % [ header, paramclass ]
38
+ rval = []
39
+ headerval = self.headers[ header ]
40
+ self.log.debug " raw header value: %p" % [ headerval ]
41
+
42
+ # Handle the case where there's more than one of the header in question by
43
+ # forcing everything to an Array
44
+ Array( headerval ).compact.flatten.each do |paramstr|
45
+ paramstr.split( /\s*,\s*/ ).each do |param|
46
+ self.log.debug " parsing param: %p" % [ param ]
47
+ rval << paramclass.parse( param )
48
+ end
49
+ end
50
+
51
+ if rval.empty? && block_given?
52
+ self.log.debug " no parsed values; calling the fallback block"
53
+ rval << yield
54
+ end
55
+
56
+ return rval.flatten
57
+ end
58
+
59
+
60
+ #
61
+ # :section: Mediatype negotiation
62
+ #
63
+
64
+ ### Return an Array of Strelka::HTTPRequest::MediaType objects for each
65
+ ### type in the 'Accept' header.
66
+ def accepted_mediatypes
67
+ @accepted_mediatypes ||= self.parse_accept_header
68
+ return @accepted_mediatypes
69
+ end
70
+ alias_method :accepted_types, :accepted_mediatypes
71
+
72
+
73
+ ### Returns boolean true/false if the requestor can handle the given
74
+ ### +content_type+.
75
+ def accepts?( content_type )
76
+ self.log.debug "Checking to see if request accepts %p" % [ content_type ]
77
+ atype = self.accepted_types.find {|type| type =~ content_type }
78
+ self.log.debug " find returned: %p" % [ atype ]
79
+ return atype ? true : false
80
+ end
81
+ alias_method :accept?, :accepts?
82
+
83
+
84
+ ### Returns boolean true/false if the requestor can handle the given
85
+ ### +content_type+, not including mime wildcards.
86
+ def explicitly_accepts?( content_type )
87
+ non_wildcard_types = self.accepted_types.reject {|param| param.subtype.nil? }
88
+ return non_wildcard_types.find {|type| type =~ content_type } ? true : false
89
+ end
90
+ alias_method :explicitly_accept?, :explicitly_accepts?
91
+
92
+
93
+ ### Parse the receiver's 'Accept' header and return it as an Array of
94
+ ### Strelka::HTTPRequest::MediaType objects.
95
+ def parse_accept_header
96
+ return self.parse_negotiation_header( :accept, Strelka::HTTPRequest::MediaType ) do
97
+ Strelka::HTTPRequest::MediaType.new( '*', '*' )
98
+ end
99
+ end
100
+
101
+
102
+ #
103
+ # :section: Charset negotiation
104
+ #
105
+
106
+ ### Return an Array of Strelka::HTTPRequest::Charset objects for each
107
+ ### type in the 'Accept-Charset' header.
108
+ def accepted_charsets
109
+ @accepted_charsets ||= self.parse_accept_charset_header
110
+ return @accepted_charsets
111
+ end
112
+
113
+
114
+ ### Returns boolean true/false if the requestor can handle the given
115
+ ### +charset+.
116
+ def accepts_charset?( charset )
117
+ self.log.debug "Checking to see if request accepts charset: %p" % [ charset ]
118
+ aset = self.accepted_charsets.find {|cs| cs =~ charset }
119
+ self.log.debug " find returned: %p" % [ aset ]
120
+ return aset ? true : false
121
+ end
122
+ alias_method :accept_charset?, :accepts_charset?
123
+
124
+
125
+ ### Returns boolean true/false if the requestor can handle the given
126
+ ### +charset+, not including the wildcard tag if present.
127
+ def explicitly_accepts_charset?( charset )
128
+ non_wildcard_charsets = self.accepted_charsets.reject {|param| param.charset.nil? }
129
+ return non_wildcard_charsets.find {|cs| cs =~ charset } ? true : false
130
+ end
131
+ alias_method :explicitly_accept_charset?, :explicitly_accepts_charset?
132
+
133
+
134
+ ### Parse the receiver's 'Accept-Charset' header and return it as an Array of
135
+ ### Strelka::HTTPRequest::Charset objects.
136
+ def parse_accept_charset_header
137
+ return self.parse_negotiation_header( :accept_charset, Strelka::HTTPRequest::Charset ) do
138
+ Strelka::HTTPRequest::Charset.new( '*' )
139
+ end
140
+ end
141
+
142
+
143
+ #
144
+ # :section: Encoding negotiation
145
+ #
146
+
147
+ ### Return an Array of Strelka::HTTPRequest::Encoding objects for each
148
+ ### type in the 'Accept-Encoding' header.
149
+ def accepted_encodings
150
+ @accepted_encodings ||= self.parse_accept_encoding_header
151
+ return @accepted_encodings
152
+ end
153
+
154
+
155
+ ### Returns boolean true/false if the requestor can handle the given
156
+ ### +encoding+.
157
+ def accepts_encoding?( encoding )
158
+ self.log.debug "Checking to see if request accepts encoding: %p" % [ encoding ]
159
+ return true if self.accepted_encodings.empty?
160
+ found_encoding = self.accepted_encodings.find {|enc| enc =~ encoding }
161
+ self.log.debug " find returned: %p" % [ found_encoding ]
162
+
163
+ # If there was no match, then it's not accepted, unless it's the 'identity'
164
+ # encoding, which is accepted unless it's disabled.
165
+ return encoding == 'identity' if !found_encoding
166
+
167
+ return found_encoding.qvalue.nonzero?
168
+ end
169
+ alias_method :accept_encoding?, :accepts_encoding?
170
+
171
+
172
+ ### Returns boolean true/false if the requestor can handle the given
173
+ ### +encoding+, not including the wildcard encoding if present.
174
+ def explicitly_accepts_encoding?( encoding )
175
+ non_wildcard_encodings = self.accepted_encodings.reject {|enc| enc.content_coding.nil? }
176
+ found_encoding = non_wildcard_encodings.find {|enc| enc =~ encoding } or
177
+ return false
178
+ return found_encoding.qvalue.nonzero?
179
+ end
180
+ alias_method :explicitly_accept_encoding?, :explicitly_accepts_encoding?
181
+
182
+
183
+ ### Parse the receiver's 'Accept-Encoding' header and return it as an Array of
184
+ ### Strelka::HTTPRequest::Encoding objects.
185
+ def parse_accept_encoding_header
186
+ return self.parse_negotiation_header( :accept_encoding, Strelka::HTTPRequest::Encoding ) do
187
+ # If the Accept-Encoding field-value is empty, then only the "identity"
188
+ # encoding is acceptable.
189
+ if self.headers.include?( :accept_encoding )
190
+ self.log.debug "Empty accept-encoding header: identity-only"
191
+ [ Strelka::HTTPRequest::Encoding.new('identity') ]
192
+
193
+ # I have no idea how this is different than an empty accept-encoding header
194
+ # for any practical case, but RFC2616 says:
195
+ # If no Accept-Encoding field is present in a request, the server MAY
196
+ # assume that the client will accept any content coding. In this
197
+ # case, if "identity" is one of the available content-codings, then
198
+ # the server SHOULD use the "identity" content-coding, unless it has
199
+ # additional information that a different content-coding is meaningful
200
+ # to the client.
201
+ else
202
+ self.log.debug "No accept-encoding header: identity + any encoding"
203
+ [
204
+ Strelka::HTTPRequest::Encoding.new( 'identity' ),
205
+ Strelka::HTTPRequest::Encoding.new( '*', nil, 0.9 )
206
+ ]
207
+ end
208
+ end
209
+ end
210
+
211
+
212
+
213
+ #
214
+ # :section: Language negotiation
215
+ #
216
+
217
+ ### Return an Array of Strelka::HTTPRequest::Language objects for each
218
+ ### type in the 'Accept-Language' header.
219
+ def accepted_languages
220
+ @accepted_languages ||= self.parse_accept_language_header
221
+ return @accepted_languages
222
+ end
223
+
224
+
225
+ ### Returns boolean true/false if the requestor can handle the given
226
+ ### +language+.
227
+ def accepts_language?( language )
228
+ self.log.debug "Checking to see if request accepts language: %p" % [ language ]
229
+ found_language = self.accepted_languages.find {|langcode| langcode =~ language }
230
+ self.log.debug " find returned: %p" % [ found_language ]
231
+ return found_language && found_language.qvalue.nonzero?
232
+ end
233
+ alias_method :accept_language?, :accepts_language?
234
+
235
+
236
+ ### Returns boolean true/false if the requestor can handle the given
237
+ ### +language+, not including the wildcard language if present.
238
+ def explicitly_accepts_language?( language )
239
+ non_wildcard_languages = self.accepted_languages.reject {|enc| enc.content_coding.nil? }
240
+ found_language = non_wildcard_languages.find {|enc| enc =~ language }
241
+ return found_language.qvalue.nonzero?
242
+ end
243
+ alias_method :explicitly_accept_language?, :explicitly_accepts_language?
244
+
245
+
246
+ ### Parse the receiver's 'Accept-Language' header and return it as an Array of
247
+ ### Strelka::HTTPRequest::Language objects.
248
+ def parse_accept_language_header
249
+ return self.parse_negotiation_header( :accept_language, Strelka::HTTPRequest::Language ) do
250
+ Strelka::HTTPRequest::Language.new( '*' )
251
+ end
252
+ end
253
+
254
+
255
+ end # module RequestMethods
256
+
257
+