hanami-controller 1.3.0 → 2.0.0.alpha2

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 (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