actionpack 6.0.3.4 → 6.1.2

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of actionpack might be problematic. Click here for more details.

Files changed (117) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +274 -223
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +1 -1
  5. data/lib/abstract_controller.rb +1 -0
  6. data/lib/abstract_controller/base.rb +35 -2
  7. data/lib/abstract_controller/callbacks.rb +2 -2
  8. data/lib/abstract_controller/helpers.rb +105 -90
  9. data/lib/abstract_controller/rendering.rb +9 -9
  10. data/lib/abstract_controller/translation.rb +8 -2
  11. data/lib/action_controller.rb +2 -3
  12. data/lib/action_controller/api.rb +2 -2
  13. data/lib/action_controller/base.rb +4 -2
  14. data/lib/action_controller/caching.rb +0 -1
  15. data/lib/action_controller/log_subscriber.rb +3 -3
  16. data/lib/action_controller/metal.rb +2 -2
  17. data/lib/action_controller/metal/conditional_get.rb +11 -3
  18. data/lib/action_controller/metal/content_security_policy.rb +1 -1
  19. data/lib/action_controller/metal/cookies.rb +3 -1
  20. data/lib/action_controller/metal/data_streaming.rb +1 -1
  21. data/lib/action_controller/metal/etag_with_template_digest.rb +2 -4
  22. data/lib/action_controller/metal/exceptions.rb +33 -0
  23. data/lib/action_controller/metal/head.rb +7 -4
  24. data/lib/action_controller/metal/helpers.rb +11 -1
  25. data/lib/action_controller/metal/http_authentication.rb +4 -2
  26. data/lib/action_controller/metal/implicit_render.rb +1 -1
  27. data/lib/action_controller/metal/instrumentation.rb +11 -9
  28. data/lib/action_controller/metal/live.rb +1 -1
  29. data/lib/action_controller/metal/logging.rb +20 -0
  30. data/lib/action_controller/metal/mime_responds.rb +6 -2
  31. data/lib/action_controller/metal/parameter_encoding.rb +35 -4
  32. data/lib/action_controller/metal/params_wrapper.rb +14 -8
  33. data/lib/action_controller/metal/permissions_policy.rb +46 -0
  34. data/lib/action_controller/metal/redirecting.rb +1 -1
  35. data/lib/action_controller/metal/rendering.rb +6 -0
  36. data/lib/action_controller/metal/request_forgery_protection.rb +48 -24
  37. data/lib/action_controller/metal/rescue.rb +1 -1
  38. data/lib/action_controller/metal/strong_parameters.rb +103 -15
  39. data/lib/action_controller/renderer.rb +24 -13
  40. data/lib/action_controller/test_case.rb +62 -56
  41. data/lib/action_dispatch.rb +3 -2
  42. data/lib/action_dispatch/http/cache.rb +12 -10
  43. data/lib/action_dispatch/http/content_disposition.rb +2 -2
  44. data/lib/action_dispatch/http/content_security_policy.rb +5 -1
  45. data/lib/action_dispatch/http/filter_parameters.rb +1 -1
  46. data/lib/action_dispatch/http/filter_redirect.rb +1 -1
  47. data/lib/action_dispatch/http/headers.rb +3 -2
  48. data/lib/action_dispatch/http/mime_negotiation.rb +20 -8
  49. data/lib/action_dispatch/http/mime_type.rb +28 -15
  50. data/lib/action_dispatch/http/parameters.rb +1 -19
  51. data/lib/action_dispatch/http/permissions_policy.rb +173 -0
  52. data/lib/action_dispatch/http/request.rb +26 -8
  53. data/lib/action_dispatch/http/response.rb +17 -16
  54. data/lib/action_dispatch/http/url.rb +3 -2
  55. data/lib/action_dispatch/journey.rb +0 -2
  56. data/lib/action_dispatch/journey/formatter.rb +53 -28
  57. data/lib/action_dispatch/journey/gtg/builder.rb +22 -36
  58. data/lib/action_dispatch/journey/gtg/simulator.rb +8 -7
  59. data/lib/action_dispatch/journey/gtg/transition_table.rb +6 -4
  60. data/lib/action_dispatch/journey/nfa/dot.rb +0 -11
  61. data/lib/action_dispatch/journey/nodes/node.rb +4 -3
  62. data/lib/action_dispatch/journey/parser.rb +13 -13
  63. data/lib/action_dispatch/journey/parser.y +1 -1
  64. data/lib/action_dispatch/journey/path/pattern.rb +13 -18
  65. data/lib/action_dispatch/journey/route.rb +7 -18
  66. data/lib/action_dispatch/journey/router.rb +26 -30
  67. data/lib/action_dispatch/journey/router/utils.rb +6 -4
  68. data/lib/action_dispatch/middleware/actionable_exceptions.rb +2 -2
  69. data/lib/action_dispatch/middleware/cookies.rb +74 -33
  70. data/lib/action_dispatch/middleware/debug_exceptions.rb +10 -17
  71. data/lib/action_dispatch/middleware/debug_view.rb +1 -1
  72. data/lib/action_dispatch/middleware/exception_wrapper.rb +29 -17
  73. data/lib/action_dispatch/middleware/host_authorization.rb +25 -5
  74. data/lib/action_dispatch/middleware/public_exceptions.rb +1 -1
  75. data/lib/action_dispatch/middleware/remote_ip.rb +5 -4
  76. data/lib/action_dispatch/middleware/request_id.rb +4 -5
  77. data/lib/action_dispatch/middleware/session/abstract_store.rb +2 -2
  78. data/lib/action_dispatch/middleware/session/cookie_store.rb +2 -2
  79. data/lib/action_dispatch/middleware/show_exceptions.rb +2 -0
  80. data/lib/action_dispatch/middleware/ssl.rb +12 -7
  81. data/lib/action_dispatch/middleware/stack.rb +18 -0
  82. data/lib/action_dispatch/middleware/static.rb +154 -93
  83. data/lib/action_dispatch/middleware/templates/rescues/_message_and_suggestions.html.erb +22 -0
  84. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb +2 -5
  85. data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.html.erb +2 -2
  86. data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.text.erb +2 -2
  87. data/lib/action_dispatch/middleware/templates/rescues/layout.erb +100 -8
  88. data/lib/action_dispatch/middleware/templates/rescues/unknown_action.html.erb +1 -1
  89. data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +21 -1
  90. data/lib/action_dispatch/railtie.rb +3 -2
  91. data/lib/action_dispatch/request/session.rb +2 -8
  92. data/lib/action_dispatch/request/utils.rb +26 -2
  93. data/lib/action_dispatch/routing/inspector.rb +8 -7
  94. data/lib/action_dispatch/routing/mapper.rb +102 -71
  95. data/lib/action_dispatch/routing/polymorphic_routes.rb +12 -11
  96. data/lib/action_dispatch/routing/redirection.rb +3 -3
  97. data/lib/action_dispatch/routing/route_set.rb +49 -41
  98. data/lib/action_dispatch/routing/url_for.rb +1 -0
  99. data/lib/action_dispatch/system_test_case.rb +29 -24
  100. data/lib/action_dispatch/system_testing/browser.rb +33 -27
  101. data/lib/action_dispatch/system_testing/driver.rb +6 -7
  102. data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +47 -6
  103. data/lib/action_dispatch/system_testing/test_helpers/setup_and_teardown.rb +4 -7
  104. data/lib/action_dispatch/testing/assertions.rb +1 -1
  105. data/lib/action_dispatch/testing/assertions/response.rb +2 -4
  106. data/lib/action_dispatch/testing/assertions/routing.rb +5 -5
  107. data/lib/action_dispatch/testing/integration.rb +38 -27
  108. data/lib/action_dispatch/testing/test_process.rb +29 -4
  109. data/lib/action_dispatch/testing/test_request.rb +3 -3
  110. data/lib/action_pack.rb +1 -1
  111. data/lib/action_pack/gem_version.rb +3 -3
  112. metadata +18 -19
  113. data/lib/action_controller/metal/force_ssl.rb +0 -58
  114. data/lib/action_dispatch/http/parameter_filter.rb +0 -12
  115. data/lib/action_dispatch/journey/nfa/builder.rb +0 -78
  116. data/lib/action_dispatch/journey/nfa/simulator.rb +0 -47
  117. data/lib/action_dispatch/journey/nfa/transition_table.rb +0 -119
@@ -65,7 +65,7 @@ module ActionController
65
65
  def initialize(controller, env, defaults)
66
66
  @controller = controller
67
67
  @defaults = defaults
68
- @env = normalize_keys defaults.merge(env)
68
+ @env = normalize_keys defaults, env
69
69
  end
70
70
 
71
71
  # Render templates with any options from ActionController::Base#render_to_string.
@@ -82,8 +82,12 @@ module ActionController
82
82
  # need to call <tt>.to_json</tt> on the object you want to render.
83
83
  # * <tt>:body</tt> - Renders provided text and sets content type of <tt>text/plain</tt>.
84
84
  #
85
- # If no <tt>options</tt> hash is passed or if <tt>:update</tt> is specified, the default is
86
- # to render a partial and use the second parameter as the locals hash.
85
+ # If no <tt>options</tt> hash is passed or if <tt>:update</tt> is specified, then:
86
+ #
87
+ # If an object responding to `render_in` is passed, `render_in` is called on the object,
88
+ # passing in the current view context.
89
+ #
90
+ # Otherwise, a partial is rendered using the second parameter as the locals hash.
87
91
  def render(*args)
88
92
  raise "missing controller" unless controller
89
93
 
@@ -95,11 +99,18 @@ module ActionController
95
99
  instance.set_response! controller.make_response!(request)
96
100
  instance.render_to_string(*args)
97
101
  end
102
+ alias_method :render_to_string, :render # :nodoc:
98
103
 
99
104
  private
100
- def normalize_keys(env)
105
+ def normalize_keys(defaults, env)
101
106
  new_env = {}
102
107
  env.each_pair { |k, v| new_env[rack_key_for(k)] = rack_value_for(k, v) }
108
+
109
+ defaults.each_pair do |k, v|
110
+ key = rack_key_for(k)
111
+ new_env[key] = rack_value_for(k, v) unless new_env.key?(key)
112
+ end
113
+
103
114
  new_env["rack.url_scheme"] = new_env["HTTPS"] == "on" ? "https" : "http"
104
115
  new_env
105
116
  end
@@ -112,19 +123,19 @@ module ActionController
112
123
  input: "rack.input"
113
124
  }
114
125
 
115
- IDENTITY = ->(_) { _ }
116
-
117
- RACK_VALUE_TRANSLATION = {
118
- https: ->(v) { v ? "on" : "off" },
119
- method: ->(v) { -v.upcase },
120
- }
121
-
122
126
  def rack_key_for(key)
123
- RACK_KEY_TRANSLATION.fetch(key, key.to_s)
127
+ RACK_KEY_TRANSLATION[key] || key.to_s
124
128
  end
125
129
 
126
130
  def rack_value_for(key, value)
127
- RACK_VALUE_TRANSLATION.fetch(key, IDENTITY).call value
131
+ case key
132
+ when :https
133
+ value ? "on" : "off"
134
+ when :method
135
+ -value.upcase
136
+ else
137
+ value
138
+ end
128
139
  end
129
140
  end
130
141
  end
@@ -84,7 +84,7 @@ module ActionController
84
84
  value = value.to_param
85
85
  end
86
86
 
87
- path_parameters[key] = value
87
+ path_parameters[key.to_sym] = value
88
88
  end
89
89
  end
90
90
 
@@ -492,57 +492,8 @@ module ActionController
492
492
  parameters[:format] = format
493
493
  end
494
494
 
495
- generated_extras = @routes.generate_extras(parameters.merge(controller: controller_class_name, action: action))
496
- generated_path = generated_path(generated_extras)
497
- query_string_keys = query_parameter_names(generated_extras)
498
-
499
- @request.assign_parameters(@routes, controller_class_name, action, parameters, generated_path, query_string_keys)
500
-
501
- @request.session.update(session) if session
502
- @request.flash.update(flash || {})
503
-
504
- if xhr
505
- @request.set_header "HTTP_X_REQUESTED_WITH", "XMLHttpRequest"
506
- @request.fetch_header("HTTP_ACCEPT") do |k|
507
- @request.set_header k, [Mime[:js], Mime[:html], Mime[:xml], "text/xml", "*/*"].join(", ")
508
- end
509
- end
510
-
511
- @request.fetch_header("SCRIPT_NAME") do |k|
512
- @request.set_header k, @controller.config.relative_url_root
513
- end
514
-
515
- begin
516
- @controller.recycle!
517
- @controller.dispatch(action, @request, @response)
518
- ensure
519
- @request = @controller.request
520
- @response = @controller.response
521
-
522
- if @request.have_cookie_jar?
523
- unless @request.cookie_jar.committed?
524
- @request.cookie_jar.write(@response)
525
- cookies.update(@request.cookie_jar.instance_variable_get(:@cookies))
526
- end
527
- end
528
- @response.prepare!
529
-
530
- if flash_value = @request.flash.to_session_value
531
- @request.session["flash"] = flash_value
532
- else
533
- @request.session.delete("flash")
534
- end
535
-
536
- if xhr
537
- @request.delete_header "HTTP_X_REQUESTED_WITH"
538
- @request.delete_header "HTTP_ACCEPT"
539
- end
540
- @request.query_string = ""
541
-
542
- @response.sent!
543
- end
544
-
545
- @response
495
+ setup_request(controller_class_name, action, parameters, session, flash, xhr)
496
+ process_controller_response(action, cookies, xhr)
546
497
  end
547
498
 
548
499
  def controller_class_name
@@ -598,11 +549,66 @@ module ActionController
598
549
  end
599
550
 
600
551
  private
552
+ def setup_request(controller_class_name, action, parameters, session, flash, xhr)
553
+ generated_extras = @routes.generate_extras(parameters.merge(controller: controller_class_name, action: action))
554
+ generated_path = generated_path(generated_extras)
555
+ query_string_keys = query_parameter_names(generated_extras)
556
+
557
+ @request.assign_parameters(@routes, controller_class_name, action, parameters, generated_path, query_string_keys)
558
+
559
+ @request.session.update(session) if session
560
+ @request.flash.update(flash || {})
561
+
562
+ if xhr
563
+ @request.set_header "HTTP_X_REQUESTED_WITH", "XMLHttpRequest"
564
+ @request.fetch_header("HTTP_ACCEPT") do |k|
565
+ @request.set_header k, [Mime[:js], Mime[:html], Mime[:xml], "text/xml", "*/*"].join(", ")
566
+ end
567
+ end
568
+
569
+ @request.fetch_header("SCRIPT_NAME") do |k|
570
+ @request.set_header k, @controller.config.relative_url_root
571
+ end
572
+ end
573
+
574
+ def process_controller_response(action, cookies, xhr)
575
+ begin
576
+ @controller.recycle!
577
+ @controller.dispatch(action, @request, @response)
578
+ ensure
579
+ @request = @controller.request
580
+ @response = @controller.response
581
+
582
+ if @request.have_cookie_jar?
583
+ unless @request.cookie_jar.committed?
584
+ @request.cookie_jar.write(@response)
585
+ cookies.update(@request.cookie_jar.instance_variable_get(:@cookies))
586
+ end
587
+ end
588
+ @response.prepare!
589
+
590
+ if flash_value = @request.flash.to_session_value
591
+ @request.session["flash"] = flash_value
592
+ else
593
+ @request.session.delete("flash")
594
+ end
595
+
596
+ if xhr
597
+ @request.delete_header "HTTP_X_REQUESTED_WITH"
598
+ @request.delete_header "HTTP_ACCEPT"
599
+ end
600
+ @request.query_string = ""
601
+
602
+ @response.sent!
603
+ end
604
+
605
+ @response
606
+ end
607
+
601
608
  def scrub_env!(env)
602
- env.delete_if { |k, v| k =~ /^(action_dispatch|rack)\.request/ }
603
- env.delete_if { |k, v| k =~ /^action_dispatch\.rescue/ }
604
- env.delete "action_dispatch.request.query_parameters"
605
- env.delete "action_dispatch.request.request_parameters"
609
+ env.delete_if do |k, _|
610
+ k.start_with?("rack.request", "action_dispatch.request", "action_dispatch.rescue")
611
+ end
606
612
  env["rack.input"] = StringIO.new
607
613
  env.delete "CONTENT_LENGTH"
608
614
  env.delete "RAW_POST_DATA"
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  #--
4
- # Copyright (c) 2004-2019 David Heinemeier Hansson
4
+ # Copyright (c) 2004-2020 David Heinemeier Hansson
5
5
  #
6
6
  # Permission is hereby granted, free of charge, to any person obtaining
7
7
  # a copy of this software and associated documentation files (the
@@ -46,6 +46,7 @@ module ActionDispatch
46
46
  eager_autoload do
47
47
  autoload_under "http" do
48
48
  autoload :ContentSecurityPolicy
49
+ autoload :PermissionsPolicy
49
50
  autoload :Request
50
51
  autoload :Response
51
52
  end
@@ -82,7 +83,6 @@ module ActionDispatch
82
83
  autoload :Headers
83
84
  autoload :MimeNegotiation
84
85
  autoload :Parameters
85
- autoload :ParameterFilter
86
86
  autoload :UploadedFile, "action_dispatch/http/upload"
87
87
  autoload :URL
88
88
  end
@@ -115,4 +115,5 @@ autoload :Mime, "action_dispatch/http/mime_type"
115
115
  ActiveSupport.on_load(:action_view) do
116
116
  ActionView::Base.default_formats ||= Mime::SET.symbols
117
117
  ActionView::Template::Types.delegate_to Mime
118
+ ActionView::LookupContext::DetailsKey.clear
118
119
  end
@@ -114,7 +114,7 @@ module ActionDispatch
114
114
 
115
115
  # True if an ETag is set and it's a weak validator (preceded with W/)
116
116
  def weak_etag?
117
- etag? && etag.starts_with?('W/"')
117
+ etag? && etag.start_with?('W/"')
118
118
  end
119
119
 
120
120
  # True if an ETag is set and it isn't a weak validator (not preceded with W/)
@@ -125,7 +125,7 @@ module ActionDispatch
125
125
  private
126
126
  DATE = "Date"
127
127
  LAST_MODIFIED = "Last-Modified"
128
- SPECIAL_KEYS = Set.new(%w[extras no-cache max-age public private must-revalidate])
128
+ SPECIAL_KEYS = Set.new(%w[extras no-store no-cache max-age public private must-revalidate])
129
129
 
130
130
  def generate_weak_etag(validators)
131
131
  "W/#{generate_strong_etag(validators)}"
@@ -150,8 +150,8 @@ module ActionDispatch
150
150
  directive, argument = segment.split("=", 2)
151
151
 
152
152
  if SPECIAL_KEYS.include? directive
153
- key = directive.tr("-", "_")
154
- cache_control[key.to_sym] = argument || true
153
+ directive.tr!("-", "_")
154
+ cache_control[directive.to_sym] = argument || true
155
155
  else
156
156
  cache_control[:extras] ||= []
157
157
  cache_control[:extras] << segment
@@ -166,6 +166,7 @@ module ActionDispatch
166
166
  end
167
167
 
168
168
  DEFAULT_CACHE_CONTROL = "max-age=0, private, must-revalidate"
169
+ NO_STORE = "no-store"
169
170
  NO_CACHE = "no-cache"
170
171
  PUBLIC = "public"
171
172
  PRIVATE = "private"
@@ -182,19 +183,20 @@ module ActionDispatch
182
183
  end
183
184
 
184
185
  def merge_and_normalize_cache_control!(cache_control)
185
- control = {}
186
- cc_headers = cache_control_headers
187
- if extras = cc_headers.delete(:extras)
186
+ control = cache_control_headers
187
+
188
+ return if control.empty? && cache_control.empty? # Let middleware handle default behavior
189
+
190
+ if extras = control.delete(:extras)
188
191
  cache_control[:extras] ||= []
189
192
  cache_control[:extras] += extras
190
193
  cache_control[:extras].uniq!
191
194
  end
192
195
 
193
- control.merge! cc_headers
194
196
  control.merge! cache_control
195
197
 
196
- if control.empty?
197
- # Let middleware handle default behavior
198
+ if control[:no_store]
199
+ self._cache_control = NO_STORE
198
200
  elsif control[:no_cache]
199
201
  options = []
200
202
  options << PUBLIC if control[:public]
@@ -14,13 +14,13 @@ module ActionDispatch
14
14
  @filename = filename
15
15
  end
16
16
 
17
- TRADITIONAL_ESCAPED_CHAR = /[^ A-Za-z0-9!#$+.^_`|~-]/
17
+ TRADITIONAL_ESCAPED_CHAR = /[^ A-Za-z0-9!\#$+.^_`|~-]/
18
18
 
19
19
  def ascii_filename
20
20
  'filename="' + percent_escape(I18n.transliterate(filename), TRADITIONAL_ESCAPED_CHAR) + '"'
21
21
  end
22
22
 
23
- RFC_5987_ESCAPED_CHAR = /[^A-Za-z0-9!#$&+.^_`|~-]/
23
+ RFC_5987_ESCAPED_CHAR = /[^A-Za-z0-9!\#$&+.^_`|~-]/
24
24
 
25
25
  def utf8_filename
26
26
  "filename*=UTF-8''" + percent_escape(filename, RFC_5987_ESCAPED_CHAR)
@@ -33,7 +33,7 @@ module ActionDispatch #:nodoc:
33
33
  private
34
34
  def html_response?(headers)
35
35
  if content_type = headers[CONTENT_TYPE]
36
- content_type =~ /html/
36
+ /html/.match?(content_type)
37
37
  end
38
38
  end
39
39
 
@@ -137,7 +137,11 @@ module ActionDispatch #:nodoc:
137
137
  object_src: "object-src",
138
138
  prefetch_src: "prefetch-src",
139
139
  script_src: "script-src",
140
+ script_src_attr: "script-src-attr",
141
+ script_src_elem: "script-src-elem",
140
142
  style_src: "style-src",
143
+ style_src_attr: "style-src-attr",
144
+ style_src_elem: "style-src-elem",
141
145
  worker_src: "worker-src"
142
146
  }.freeze
143
147
 
@@ -23,7 +23,7 @@ module ActionDispatch
23
23
  # change { file: { code: "xxxx"} }
24
24
  #
25
25
  # env["action_dispatch.parameter_filter"] = -> (k, v) do
26
- # v.reverse! if k =~ /secret/i
26
+ # v.reverse! if k.match?(/secret/i)
27
27
  # end
28
28
  # => reverses the value to all keys matching /secret/i
29
29
  module FilterParameters
@@ -27,7 +27,7 @@ module ActionDispatch
27
27
  if String === filter
28
28
  location.include?(filter)
29
29
  elsif Regexp === filter
30
- location =~ filter
30
+ location.match?(filter)
31
31
  end
32
32
  end
33
33
  end
@@ -121,8 +121,9 @@ module ActionDispatch
121
121
  def env_name(key)
122
122
  key = key.to_s
123
123
  if HTTP_HEADER.match?(key)
124
- key = key.upcase.tr("-", "_")
125
- key = "HTTP_" + key unless CGI_VARIABLES.include?(key)
124
+ key = key.upcase
125
+ key.tr!("-", "_")
126
+ key.prepend("HTTP_") unless CGI_VARIABLES.include?(key)
126
127
  end
127
128
  key
128
129
  end
@@ -7,6 +7,8 @@ module ActionDispatch
7
7
  module MimeNegotiation
8
8
  extend ActiveSupport::Concern
9
9
 
10
+ class InvalidType < ::Mime::Type::InvalidMimeType; end
11
+
10
12
  RESCUABLE_MIME_FORMAT_ERRORS = [
11
13
  ActionController::BadRequest,
12
14
  ActionDispatch::Http::Parameters::ParseError,
@@ -25,6 +27,8 @@ module ActionDispatch
25
27
  nil
26
28
  end
27
29
  set_header k, v
30
+ rescue ::Mime::Type::InvalidMimeType => e
31
+ raise InvalidType, e.message
28
32
  end
29
33
  end
30
34
 
@@ -47,6 +51,8 @@ module ActionDispatch
47
51
  Mime::Type.parse(header)
48
52
  end
49
53
  set_header k, v
54
+ rescue ::Mime::Type::InvalidMimeType => e
55
+ raise InvalidType, e.message
50
56
  end
51
57
  end
52
58
 
@@ -62,13 +68,7 @@ module ActionDispatch
62
68
 
63
69
  def formats
64
70
  fetch_header("action_dispatch.request.formats") do |k|
65
- params_readable = begin
66
- parameters[:format]
67
- rescue *RESCUABLE_MIME_FORMAT_ERRORS
68
- false
69
- end
70
-
71
- v = if params_readable
71
+ v = if params_readable?
72
72
  Array(Mime[parameters[:format]])
73
73
  elsif use_accept_header && valid_accept_header
74
74
  accepts
@@ -153,12 +153,24 @@ module ActionDispatch
153
153
  order.include?(Mime::ALL) ? format : nil
154
154
  end
155
155
 
156
+ def should_apply_vary_header?
157
+ !params_readable? && use_accept_header && valid_accept_header
158
+ end
159
+
156
160
  private
161
+ # We use normal content negotiation unless you include */* in your list,
162
+ # in which case we assume you're a browser and send HTML.
157
163
  BROWSER_LIKE_ACCEPTS = /,\s*\*\/\*|\*\/\*\s*,/
158
164
 
165
+ def params_readable? # :doc:
166
+ parameters[:format]
167
+ rescue *RESCUABLE_MIME_FORMAT_ERRORS
168
+ false
169
+ end
170
+
159
171
  def valid_accept_header # :doc:
160
172
  (xhr? && (accept.present? || content_mime_type)) ||
161
- (accept.present? && accept !~ BROWSER_LIKE_ACCEPTS)
173
+ (accept.present? && !accept.match?(BROWSER_LIKE_ACCEPTS))
162
174
  end
163
175
 
164
176
  def use_accept_header # :doc:
@@ -1,15 +1,17 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "singleton"
4
- require "active_support/core_ext/string/starts_ends_with"
4
+ require "active_support/core_ext/symbol/starts_ends_with"
5
5
 
6
6
  module Mime
7
7
  class Mimes
8
+ attr_reader :symbols
9
+
8
10
  include Enumerable
9
11
 
10
12
  def initialize
11
13
  @mimes = []
12
- @symbols = nil
14
+ @symbols = []
13
15
  end
14
16
 
15
17
  def each
@@ -18,15 +20,16 @@ module Mime
18
20
 
19
21
  def <<(type)
20
22
  @mimes << type
21
- @symbols = nil
23
+ @symbols << type.to_sym
22
24
  end
23
25
 
24
26
  def delete_if
25
- @mimes.delete_if { |x| yield x }.tap { @symbols = nil }
26
- end
27
-
28
- def symbols
29
- @symbols ||= map(&:to_sym)
27
+ @mimes.delete_if do |x|
28
+ if yield x
29
+ @symbols.delete(x.to_sym)
30
+ true
31
+ end
32
+ end
30
33
  end
31
34
  end
32
35
 
@@ -114,7 +117,7 @@ module Mime
114
117
  type = list[idx]
115
118
  break if type.q < app_xml.q
116
119
 
117
- if type.name.ends_with? "+xml"
120
+ if type.name.end_with? "+xml"
118
121
  list[app_xml_idx], list[idx] = list[idx], app_xml
119
122
  app_xml_idx = idx
120
123
  end
@@ -202,7 +205,7 @@ module Mime
202
205
  # For an input of <tt>'application'</tt>, returns <tt>[Mime[:html], Mime[:js],
203
206
  # Mime[:xml], Mime[:yaml], Mime[:atom], Mime[:json], Mime[:rss], Mime[:url_encoded_form]</tt>.
204
207
  def parse_data_with_trailing_star(type)
205
- Mime::SET.select { |m| m =~ type }
208
+ Mime::SET.select { |m| m.match?(type) }
206
209
  end
207
210
 
208
211
  # This method is opposite of register method.
@@ -283,8 +286,14 @@ module Mime
283
286
  @synonyms.any? { |synonym| synonym.to_s =~ regexp } || @string =~ regexp
284
287
  end
285
288
 
289
+ def match?(mime_type)
290
+ return false unless mime_type
291
+ regexp = Regexp.new(Regexp.quote(mime_type.to_s))
292
+ @synonyms.any? { |synonym| synonym.to_s.match?(regexp) } || @string.match?(regexp)
293
+ end
294
+
286
295
  def html?
287
- symbol == :html || @string =~ /html/
296
+ (symbol == :html) || /html/.match?(@string)
288
297
  end
289
298
 
290
299
  def all?; false; end
@@ -297,7 +306,7 @@ module Mime
297
306
  def to_a; end
298
307
 
299
308
  def method_missing(method, *args)
300
- if method.to_s.ends_with? "?"
309
+ if method.end_with?("?")
301
310
  method[0..-2].downcase.to_sym == to_sym
302
311
  else
303
312
  super
@@ -305,7 +314,7 @@ module Mime
305
314
  end
306
315
 
307
316
  def respond_to_missing?(method, include_private = false)
308
- (method.to_s.ends_with? "?") || super
317
+ method.end_with?("?") || super
309
318
  end
310
319
  end
311
320
 
@@ -332,15 +341,19 @@ module Mime
332
341
  true
333
342
  end
334
343
 
344
+ def to_s
345
+ ""
346
+ end
347
+
335
348
  def ref; end
336
349
 
337
350
  private
338
351
  def respond_to_missing?(method, _)
339
- method.to_s.ends_with? "?"
352
+ method.end_with?("?")
340
353
  end
341
354
 
342
355
  def method_missing(method, *args)
343
- false if method.to_s.ends_with? "?"
356
+ false if method.end_with?("?")
344
357
  end
345
358
  end
346
359
  end