hanami-controller 1.3.0 → 2.0.0.alpha2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (48) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +83 -0
  3. data/LICENSE.md +1 -1
  4. data/README.md +297 -538
  5. data/hanami-controller.gemspec +6 -5
  6. data/lib/hanami/action.rb +129 -73
  7. data/lib/hanami/action/application_action.rb +111 -0
  8. data/lib/hanami/action/application_configuration.rb +92 -0
  9. data/lib/hanami/action/application_configuration/cookies.rb +29 -0
  10. data/lib/hanami/action/application_configuration/sessions.rb +46 -0
  11. data/lib/hanami/action/base_params.rb +2 -2
  12. data/lib/hanami/action/cache.rb +1 -139
  13. data/lib/hanami/action/cache/cache_control.rb +4 -4
  14. data/lib/hanami/action/cache/conditional_get.rb +7 -2
  15. data/lib/hanami/action/cache/directives.rb +1 -1
  16. data/lib/hanami/action/cache/expires.rb +3 -3
  17. data/lib/hanami/action/configuration.rb +430 -0
  18. data/lib/hanami/action/cookie_jar.rb +3 -3
  19. data/lib/hanami/action/cookies.rb +3 -62
  20. data/lib/hanami/action/csrf_protection.rb +214 -0
  21. data/lib/hanami/action/flash.rb +102 -207
  22. data/lib/hanami/action/glue.rb +5 -31
  23. data/lib/hanami/action/halt.rb +12 -0
  24. data/lib/hanami/action/mime.rb +78 -485
  25. data/lib/hanami/action/params.rb +3 -3
  26. data/lib/hanami/action/rack/file.rb +1 -1
  27. data/lib/hanami/action/request.rb +30 -20
  28. data/lib/hanami/action/response.rb +193 -0
  29. data/lib/hanami/action/session.rb +11 -128
  30. data/lib/hanami/action/standalone_action.rb +581 -0
  31. data/lib/hanami/action/validatable.rb +2 -2
  32. data/lib/hanami/action/view_name_inferrer.rb +46 -0
  33. data/lib/hanami/controller.rb +0 -227
  34. data/lib/hanami/controller/version.rb +1 -1
  35. data/lib/hanami/http/status.rb +2 -2
  36. metadata +47 -30
  37. data/lib/hanami-controller.rb +0 -1
  38. data/lib/hanami/action/callable.rb +0 -92
  39. data/lib/hanami/action/callbacks.rb +0 -214
  40. data/lib/hanami/action/configurable.rb +0 -50
  41. data/lib/hanami/action/exposable.rb +0 -126
  42. data/lib/hanami/action/exposable/guard.rb +0 -104
  43. data/lib/hanami/action/head.rb +0 -121
  44. data/lib/hanami/action/rack.rb +0 -399
  45. data/lib/hanami/action/rack/callable.rb +0 -47
  46. data/lib/hanami/action/redirect.rb +0 -59
  47. data/lib/hanami/action/throwable.rb +0 -196
  48. data/lib/hanami/controller/configuration.rb +0 -763
@@ -1,5 +1,5 @@
1
1
  module Hanami
2
- module Action
2
+ class Action
3
3
  # Glue code for full stack Hanami applications
4
4
  #
5
5
  # This includes missing rendering logic that it makes sense to include
@@ -14,43 +14,17 @@ module Hanami
14
14
  # @since 0.3.0
15
15
  ENV_KEY = 'hanami.action'.freeze
16
16
 
17
- # @api private
18
- # @since 0.3.2
19
- ADDITIONAL_HTTP_STATUSES_WITHOUT_BODY = Set.new([301, 302]).freeze
20
-
21
- # Override Ruby's Module#included
22
- #
23
- # @api private
24
- # @since 0.3.0
25
- def self.included(base)
26
- base.class_eval { _expose(:format) if respond_to?(:_expose) }
27
- end
28
-
29
- # Check if the current HTTP request is renderable.
30
- #
31
- # It verifies if the verb isn't HEAD, if the status demands to omit
32
- # the body and if it isn't sending a file.
33
- #
34
- # @return [TrueClass,FalseClass] the result of the check
35
- #
36
- # @api private
37
- # @since 0.3.2
38
- def renderable?
39
- !_requires_no_body? &&
40
- !sending_file? &&
41
- !ADDITIONAL_HTTP_STATUSES_WITHOUT_BODY.include?(@_status)
42
- end
43
-
44
17
  protected
18
+
45
19
  # Put the current instance into the Rack environment
46
20
  #
47
21
  # @api private
48
22
  # @since 0.3.0
49
23
  #
50
24
  # @see Hanami::Action#finish
51
- def finish
25
+ def finish(req, *)
26
+ req.env[ENV_KEY] = self
52
27
  super
53
- @_env[ENV_KEY] = self
54
28
  end
55
29
 
56
30
  # Check if the request's body is a file
@@ -59,7 +33,7 @@ module Hanami
59
33
  #
60
34
  # @since 0.4.3
61
35
  def sending_file?
62
- @_body.is_a?(::Rack::File::Iterator)
36
+ response.body.is_a?(::Rack::File::Iterator)
63
37
  end
64
38
  end
65
39
  end
@@ -0,0 +1,12 @@
1
+ require "hanami/http/status"
2
+
3
+ module Hanami
4
+ class Action
5
+ module Halt
6
+ def self.call(status, body = nil)
7
+ body ||= Http::Status.message_for(status)
8
+ throw :halt, [status, body]
9
+ end
10
+ end
11
+ end
12
+ end
@@ -1,24 +1,16 @@
1
- require 'rack/utils'
2
- require 'hanami/utils'
3
- require 'hanami/utils/kernel'
1
+ require "hanami/utils"
2
+ require "rack/utils"
3
+ require "rack/mime"
4
4
 
5
5
  module Hanami
6
- module Action
7
- # Mime type API
8
- #
9
- # @since 0.1.0
10
- #
11
- # @see Hanami::Action::Mime::ClassMethods#accept
6
+ class Action
12
7
  module Mime
13
- # The key that returns accepted mime types from the Rack env
14
- #
15
- # @since 0.1.0
16
- # @api private
17
- HTTP_ACCEPT = 'HTTP_ACCEPT'.freeze
8
+ DEFAULT_CONTENT_TYPE = 'application/octet-stream'.freeze
9
+ DEFAULT_CHARSET = 'utf-8'.freeze
18
10
 
19
11
  # The key that returns content mime type from the Rack env
20
12
  #
21
- # @since 1.2.0
13
+ # @since 2.0.0
22
14
  # @api private
23
15
  HTTP_CONTENT_TYPE = 'CONTENT_TYPE'.freeze
24
16
 
@@ -28,29 +20,11 @@ module Hanami
28
20
  # @api private
29
21
  CONTENT_TYPE = 'Content-Type'.freeze
30
22
 
31
- # The default mime type for an incoming HTTP request
32
- #
33
- # @since 0.1.0
34
- # @api private
35
- DEFAULT_ACCEPT = '*/*'.freeze
36
-
37
- # The default mime type that is returned in the response
38
- #
39
- # @since 0.1.0
40
- # @api private
41
- DEFAULT_CONTENT_TYPE = 'application/octet-stream'.freeze
42
-
43
- # The default charset that is returned in the response
44
- #
45
- # @since 0.3.0
46
- # @api private
47
- DEFAULT_CHARSET = 'utf-8'.freeze
48
-
49
23
  # Most commom MIME Types used for responses
50
24
  #
51
25
  # @since 1.0.0
52
26
  # @api private
53
- MIME_TYPES = {
27
+ TYPES = {
54
28
  txt: 'text/plain',
55
29
  html: 'text/html',
56
30
  json: 'application/json',
@@ -102,496 +76,115 @@ module Hanami
102
76
  xml: 'application/xml',
103
77
  xslt: 'application/xslt+xml',
104
78
  yml: 'text/yaml',
105
- zip: 'application/zip' }.freeze
79
+ zip: 'application/zip'
80
+ }.freeze
106
81
 
107
- # Override Ruby's hook for modules.
108
- # It includes Mime types logic
109
- #
110
- # @param base [Class] the target action
111
- #
112
- # @since 0.1.0
113
- # @api private
114
- #
115
- # @see http://www.ruby-doc.org/core-2.1.2/Module.html#method-i-included
116
- def self.included(base)
117
- base.class_eval do
118
- extend ClassMethods
119
- prepend InstanceMethods
120
- end
82
+ def self.content_type_with_charset(content_type, charset)
83
+ "#{content_type}; charset=#{charset}"
121
84
  end
122
85
 
123
- module ClassMethods
124
- # @since 0.2.0
125
- # @api private
126
- def format_to_mime_type(format)
127
- configuration.mime_type_for(format) ||
128
- MIME_TYPES[format] or
129
- raise Hanami::Controller::UnknownFormatError.new(format)
130
- end
131
-
132
- private
133
-
134
- # Restrict the access to the specified mime type symbols.
135
- #
136
- # @param formats[Array<Symbol>] one or more symbols representing mime type(s)
137
- #
138
- # @raise [Hanami::Controller::UnknownFormatError] if the symbol cannot
139
- # be converted into a mime type
140
- #
141
- # @since 0.1.0
142
- #
143
- # @see Hanami::Controller::Configuration#format
144
- #
145
- # @example
146
- # require 'hanami/controller'
147
- #
148
- # class Show
149
- # include Hanami::Action
150
- # accept :html, :json
151
- #
152
- # def call(params)
153
- # # ...
154
- # end
155
- # end
156
- #
157
- # # When called with "*/*" => 200
158
- # # When called with "text/html" => 200
159
- # # When called with "application/json" => 200
160
- # # When called with "application/xml" => 406
161
- def accept(*formats)
162
- mime_types = formats.map do |format|
163
- format_to_mime_type(format)
164
- end
165
-
166
- configuration.restrict_mime_types!(mime_types)
167
-
168
- before do
169
- unless mime_types.find {|mt| accept?(mt) }
170
- halt 406
171
- end
172
- end
86
+ # Use for setting Content-Type
87
+ # If the request has the ACCEPT header it will try to return the best Content-Type based
88
+ # on the content of the ACCEPT header taking in consideration the weights
89
+ #
90
+ # If no ACCEPT header it will check the default response_format, then the default request format and
91
+ # lastly it will fallback to DEFAULT_CONTENT_TYPE
92
+ #
93
+ # @return [String]
94
+ def self.content_type(configuration, request, accepted_mime_types)
95
+ if request.accept_header?
96
+ type = best_q_match(request.accept, accepted_mime_types)
97
+ return type if type
173
98
  end
174
99
 
175
- # Restrict the payload type to the specified mime type symbols.
176
- #
177
- # @param formats[Array<Symbol>] one or more symbols representing mime type(s)
178
- #
179
- # @since 1.2.0
180
- #
181
- # @example
182
- # require 'hanami/controller'
183
- #
184
- # class Upload
185
- # include Hanami::Action
186
- # content_type :json
187
- #
188
- # def call(params)
189
- # # ...
190
- # end
191
- # end
192
- #
193
- # # When called with "text/html" => 415
194
- # # When called with "application/json" => 200
195
- def content_type(*formats)
196
- mime_types = formats.map { |format| format_to_mime_type(format) }
197
-
198
- before do
199
- mime_type = @_env[HTTP_CONTENT_TYPE] || default_content_type || DEFAULT_CONTENT_TYPE
200
-
201
- if mime_types.none? {|mt| ::Rack::Mime.match?(mime_type, mt) }
202
- halt 415
203
- end
204
- end
205
- end
100
+ default_response_type(configuration) || default_content_type(configuration) || DEFAULT_CONTENT_TYPE
206
101
  end
207
102
 
208
- # @since 0.7.0
209
- # @api private
210
- module InstanceMethods
211
- # @since 0.7.0
212
- # @api private
213
- def initialize(*)
214
- super
215
- @content_type = nil
216
- @charset = nil
217
- end
103
+ def self.charset(default_charset)
104
+ default_charset || DEFAULT_CHARSET
218
105
  end
219
106
 
220
- # Returns a symbol representation of the content type.
221
- #
222
- # The framework automatically detects the request mime type, and returns
223
- # the corresponding format.
224
- #
225
- # However, if this value was explicitly set by `#format=`, it will return
226
- # that value
227
- #
228
- # @return [Symbol] a symbol that corresponds to the content type
229
- #
230
- # @since 0.2.0
231
- #
232
- # @see Hanami::Action::Mime#format=
233
- # @see Hanami::Action::Mime#content_type
234
- #
235
- # @example Default scenario
236
- # require 'hanami/controller'
237
- #
238
- # class Show
239
- # include Hanami::Action
240
- #
241
- # def call(params)
242
- # end
243
- # end
244
- #
245
- # action = Show.new
246
- #
247
- # _, headers, _ = action.call({ 'HTTP_ACCEPT' => 'text/html' })
248
- # headers['Content-Type'] # => 'text/html'
249
- # action.format # => :html
250
- #
251
- # @example Set value
252
- # require 'hanami/controller'
253
- #
254
- # class Show
255
- # include Hanami::Action
256
- #
257
- # def call(params)
258
- # self.format = :xml
259
- # end
260
- # end
261
- #
262
- # action = Show.new
263
- #
264
- # _, headers, _ = action.call({ 'HTTP_ACCEPT' => 'text/html' })
265
- # headers['Content-Type'] # => 'application/xml'
266
- # action.format # => :xml
267
- def format
268
- @format ||= detect_format
107
+ def self.default_response_type(configuration)
108
+ format_to_mime_type(configuration.default_response_format, configuration)
269
109
  end
270
110
 
271
- # The content type that will be automatically set in the response.
272
- #
273
- # It prefers, in order:
274
- # * Explicit set value (see Hanami::Action::Mime#format=)
275
- # * Weighted value from Accept header based on all known MIME Types:
276
- # - Custom registered MIME Types (see Hanami::Controller::Configuration#format)
277
- # * Configured default content type (see Hanami::Controller::Configuration#default_response_format)
278
- # * Hard-coded default content type (see Hanami::Action::Mime::DEFAULT_CONTENT_TYPE)
279
- #
280
- # To override the value, use <tt>#format=</tt>
281
- #
282
- # @return [String] the content type from the request.
283
- #
284
- # @since 0.1.0
285
- #
286
- # @see Hanami::Action::Mime#format=
287
- # @see Hanami::Configuration#default_request_format
288
- # @see Hanami::Action::Mime#default_content_type
289
- # @see Hanami::Action::Mime#DEFAULT_CONTENT_TYPE
290
- # @see Hanami::Controller::Configuration#format
291
- # @see Hanami::Controller::Configuration#default_response_format
292
- #
293
- # @example
294
- # require 'hanami/controller'
295
- #
296
- # class Show
297
- # include Hanami::Action
298
- #
299
- # def call(params)
300
- # # ...
301
- # content_type # => 'text/html'
302
- # end
303
- # end
304
- def content_type
305
- return @content_type unless @content_type.nil?
306
- @content_type = content_type_from_accept_header if accept_header?
307
- @content_type || default_response_type || default_content_type || DEFAULT_CONTENT_TYPE
111
+ def self.default_content_type(configuration)
112
+ format_to_mime_type(configuration.default_request_format, configuration)
308
113
  end
309
114
 
310
- # Action charset setter, receives new charset value
311
- #
312
- # @return [String] the charset of the request.
313
- #
314
- # @since 0.3.0
315
- #
316
- # @example
317
- # require 'hanami/controller'
318
- #
319
- # class Show
320
- # include Hanami::Action
321
- #
322
- # def call(params)
323
- # # ...
324
- # self.charset = 'koi8-r'
325
- # end
326
- # end
327
- def charset=(value)
328
- @charset = value
329
- end
115
+ def self.format_to_mime_type(format, configuration)
116
+ return if format.nil?
330
117
 
331
- # The charset that will be automatically set in the response.
332
- #
333
- # It prefers, in order:
334
- # * Explicit set value (see #charset=)
335
- # * Default configuration charset
336
- # * Default content type
337
- #
338
- # To override the value, use <tt>#charset=</tt>
339
- #
340
- # @return [String] the charset of the request.
341
- #
342
- # @since 0.3.0
343
- #
344
- # @see Hanami::Action::Mime#charset=
345
- # @see Hanami::Configuration#default_charset
346
- # @see Hanami::Action::Mime#default_charset
347
- # @see Hanami::Action::Mime#DEFAULT_CHARSET
348
- #
349
- # @example
350
- # require 'hanami/controller'
351
- #
352
- # class Show
353
- # include Hanami::Action
354
- #
355
- # def call(params)
356
- # # ...
357
- # charset # => 'text/html'
358
- # end
359
- # end
360
- def charset
361
- @charset || default_charset || DEFAULT_CHARSET
118
+ configuration.mime_type_for(format) ||
119
+ TYPES.fetch(format) { raise Hanami::Controller::UnknownFormatError.new(format) }
362
120
  end
363
121
 
364
- private
365
-
366
- # Finalize the response by setting the current content type
122
+ # Transforms MIME Types to symbol
123
+ # Used for setting the format of the response
367
124
  #
368
- # @since 0.1.0
369
- # @api private
125
+ # @see Hanami::Action::Mime#finish
126
+ # @example
127
+ # detect_format("text/html; charset=utf-8", configuration) #=> :html
370
128
  #
371
- # @see Hanami::Action#finish
372
- def finish
373
- super
374
- headers[CONTENT_TYPE] ||= content_type_with_charset
129
+ # @return [Symbol, nil]
130
+ def self.detect_format(content_type, configuration)
131
+ return if content_type.nil?
132
+ ct = content_type.split(";").first
133
+ configuration.format_for(ct) || format_for(ct)
375
134
  end
376
135
 
377
- # Sets the given format and corresponding content type.
378
- #
379
- # The framework detects the `HTTP_ACCEPT` header of the request and sets
380
- # the proper `Content-Type` header in the response.
381
- # Within this default scenario, `#format` returns a symbol that
382
- # corresponds to `#content_type`.
383
- # For instance, if a client sends an `HTTP_ACCEPT` with `text/html`,
384
- # `#content_type` will return `text/html` and `#format` `:html`.
385
- #
386
- # However, it's possible to override what the framework have detected.
387
- # If a client asks for an `HTTP_ACCEPT` `*/*`, but we want to force the
388
- # response to be a `text/html` we can use this method.
389
- #
390
- # When the format is set, the framework searches for a corresponding mime
391
- # type to be set as the `Content-Type` header of the response.
392
- # This lookup is performed first in the configuration, and then in
393
- # `Hanami::Action::Mime::MIME_TYPES`. If the lookup fails, it raises an error.
394
- #
395
- # PERFORMANCE: Because `Hanami::Controller::Configuration#formats` is
396
- # smaller and looked up first than `Hanami::Action::Mime::MIME_TYPES`,
397
- # we suggest to configure the most common mime types used by your
398
- # application, **even if they are already present in that Rack constant**.
399
- #
400
- # @param format [#to_sym] the format
401
- #
402
- # @return [void]
403
- #
404
- # @raise [TypeError] if the format cannot be coerced into a Symbol
405
- # @raise [Hanami::Controller::UnknownFormatError] if the format doesn't
406
- # have a corresponding mime type
407
- #
408
- # @since 0.2.0
409
- #
410
- # @see Hanami::Action::Mime#format
411
- # @see Hanami::Action::Mime#content_type
412
- # @see Hanami::Controller::Configuration#format
413
- #
414
- # @example Default scenario
415
- # require 'hanami/controller'
416
- #
417
- # class Show
418
- # include Hanami::Action
419
- #
420
- # def call(params)
421
- # end
422
- # end
423
- #
424
- # action = Show.new
425
- #
426
- # _, headers, _ = action.call({ 'HTTP_ACCEPT' => '*/*' })
427
- # headers['Content-Type'] # => 'application/octet-stream'
428
- # action.format # => :all
429
- #
430
- # _, headers, _ = action.call({ 'HTTP_ACCEPT' => 'text/html' })
431
- # headers['Content-Type'] # => 'text/html'
432
- # action.format # => :html
433
- #
434
- # @example Simple usage
435
- # require 'hanami/controller'
436
- #
437
- # class Show
438
- # include Hanami::Action
439
- #
440
- # def call(params)
441
- # # ...
442
- # self.format = :json
443
- # end
444
- # end
445
- #
446
- # action = Show.new
447
- #
448
- # _, headers, _ = action.call({ 'HTTP_ACCEPT' => '*/*' })
449
- # headers['Content-Type'] # => 'application/json'
450
- # action.format # => :json
451
- #
452
- # @example Unknown format
453
- # require 'hanami/controller'
454
- #
455
- # class Show
456
- # include Hanami::Action
457
- #
458
- # def call(params)
459
- # # ...
460
- # self.format = :unknown
461
- # end
462
- # end
463
- #
464
- # action = Show.new
465
- # action.call({ 'HTTP_ACCEPT' => '*/*' })
466
- # # => raise Hanami::Controller::UnknownFormatError
467
- #
468
- # @example Custom mime type/format
469
- # require 'hanami/controller'
470
- #
471
- # Hanami::Controller.configure do
472
- # format :custom, 'application/custom'
473
- # end
474
- #
475
- # class Show
476
- # include Hanami::Action
477
- #
478
- # def call(params)
479
- # # ...
480
- # self.format = :custom
481
- # end
482
- # end
483
- #
484
- # _, headers, _ = action.call({ 'HTTP_ACCEPT' => '*/*' })
485
- # headers['Content-Type'] # => 'application/custom'
486
- # action.format # => :custom
487
- def format=(format)
488
- @format = Utils::Kernel.Symbol(format)
489
- @content_type = self.class.format_to_mime_type(@format)
136
+ def self.format_for(content_type)
137
+ TYPES.key(content_type)
490
138
  end
491
139
 
492
- # Match the given mime type with the Accept header
493
- #
494
- # @return [Boolean] true if the given mime type matches Accept
495
- #
496
- # @since 0.1.0
497
- #
140
+ # Transforms symbols to MIME Types
498
141
  # @example
499
- # require 'hanami/controller'
500
- #
501
- # class Show
502
- # include Hanami::Action
503
- #
504
- # def call(params)
505
- # # ...
506
- # # @_env['HTTP_ACCEPT'] # => 'text/html,application/xhtml+xml,application/xml;q=0.9'
507
- #
508
- # accept?('text/html') # => true
509
- # accept?('application/xml') # => true
510
- # accept?('application/json') # => false
511
- #
512
- #
142
+ # restrict_mime_types(configuration, [:json]) #=> ["application/json"]
513
143
  #
514
- # # @_env['HTTP_ACCEPT'] # => '*/*'
144
+ # @return [Array<String>, nil]
515
145
  #
516
- # accept?('text/html') # => true
517
- # accept?('application/xml') # => true
518
- # accept?('application/json') # => true
519
- # end
520
- # end
521
- def accept?(mime_type)
522
- !!::Rack::Utils.q_values(accept).find do |mime, _|
523
- ::Rack::Mime.match?(mime_type, mime)
146
+ # @raise [Hanami::Controller::UnknownFormatError] if the format is invalid
147
+ def self.restrict_mime_types(configuration, accepted_formats)
148
+ return if accepted_formats.empty?
149
+
150
+ mime_types = accepted_formats.map do |format|
151
+ format_to_mime_type(format, configuration)
524
152
  end
525
- end
526
153
 
527
- # @since 0.1.0
528
- # @api private
529
- def accept
530
- @accept ||= @_env[HTTP_ACCEPT] || DEFAULT_ACCEPT
531
- end
154
+ accepted_mime_types = mime_types & configuration.mime_types
532
155
 
533
- # Checks if there is an Accept header for the current request.
534
- #
535
- # @return [TrueClass,FalseClass] the result of the check
536
- #
537
- # @since 0.8.0
538
- # @api private
539
- def accept_header?
540
- accept != DEFAULT_ACCEPT
156
+ return if accepted_mime_types.empty?
157
+ accepted_mime_types
541
158
  end
542
159
 
543
- # Look at the Accept header for the current request and see if it
544
- # matches any of the common MIME types (see Hanami::Action::Mime#MIME_TYPES)
545
- # or the custom registered ones (see Hanami::Controller::Configuration#format).
160
+ # Use for checking the Content-Type header to make sure is valid based
161
+ # on the accepted_mime_types
546
162
  #
547
- # @return [String,Nil] The matched MIME type for the given Accept header.
163
+ # If no Content-Type is sent in the request it will check the default_request_format
548
164
  #
549
- # @since 0.8.0
550
- # @api private
551
- #
552
- # @see Hanami::Action::Mime#MIME_TYPES
553
- # @see Hanami::Controller::Configuration#format
554
- #
555
- # @api private
556
- def content_type_from_accept_header
557
- best_q_match(accept, configuration.mime_types)
558
- end
165
+ # @return [TrueClass, FalseClass]
166
+ def self.accepted_mime_type?(request, accepted_mime_types, configuration)
167
+ mime_type = request.env[HTTP_CONTENT_TYPE] || default_content_type(configuration) || DEFAULT_CONTENT_TYPE
559
168
 
560
- # @since 0.5.0
561
- # @api private
562
- def default_response_type
563
- self.class.format_to_mime_type(configuration.default_response_format) if configuration.default_response_format
169
+ !accepted_mime_types.find { |mt| ::Rack::Mime.match?(mt, mime_type) }.nil?
564
170
  end
565
171
 
566
- # @since 0.2.0
567
- # @api private
568
- def default_content_type
569
- self.class.format_to_mime_type(
570
- configuration.default_request_format
571
- ) if configuration.default_request_format
572
- end
573
-
574
- # @since 0.2.0
575
- # @api private
576
- def detect_format
577
- configuration.format_for(content_type) || MIME_TYPES.key(content_type)
578
- end
579
-
580
- # @since 0.3.0
581
- # @api private
582
- def default_charset
583
- configuration.default_charset
172
+ # Use for setting the content_type and charset if the response
173
+ #
174
+ # @see Hanami::Action::Mime#call
175
+ #
176
+ # @return [String]
177
+ def self.calculate_content_type_with_charset(configuration, request, accepted_mime_types)
178
+ charset = self.charset(configuration.default_charset)
179
+ content_type = self.content_type(configuration, request, accepted_mime_types)
180
+ content_type_with_charset(content_type, charset)
584
181
  end
585
182
 
586
- # @since 0.3.0
587
- # @api private
588
- def content_type_with_charset
589
- "#{content_type}; charset=#{charset}"
590
- end
183
+ # private
591
184
 
592
185
  # Patched version of <tt>Rack::Utils.best_q_match</tt>.
593
186
  #
594
- # @since 0.4.1
187
+ # @since 2.0.0
595
188
  # @api private
596
189
  #
597
190
  # @see http://www.rubydoc.info/gems/rack/Rack/Utils#best_q_match-class_method
@@ -599,7 +192,7 @@ module Hanami
599
192
  # @see https://github.com/hanami/controller/issues/59
600
193
  # @see https://github.com/hanami/controller/issues/104
601
194
  # @see https://github.com/hanami/controller/issues/275
602
- def best_q_match(q_value_header, available_mimes)
195
+ def self.best_q_match(q_value_header, available_mimes = TYPES.values)
603
196
  ::Rack::Utils.q_values(q_value_header).each_with_index.map do |(req_mime, quality), index|
604
197
  match = available_mimes.find { |am| ::Rack::Mime.match?(am, req_mime) }
605
198
  next unless match