actionpack 4.2.11.1 → 6.1.3.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 (187) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +291 -489
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +9 -9
  5. data/lib/abstract_controller/asset_paths.rb +2 -0
  6. data/lib/abstract_controller/base.rb +81 -51
  7. data/lib/{action_controller → abstract_controller}/caching/fragments.rb +64 -17
  8. data/lib/abstract_controller/caching.rb +66 -0
  9. data/lib/abstract_controller/callbacks.rb +61 -33
  10. data/lib/abstract_controller/collector.rb +9 -13
  11. data/lib/abstract_controller/error.rb +6 -0
  12. data/lib/abstract_controller/helpers.rb +115 -99
  13. data/lib/abstract_controller/logger.rb +2 -0
  14. data/lib/abstract_controller/railties/routes_helpers.rb +21 -3
  15. data/lib/abstract_controller/rendering.rb +48 -47
  16. data/lib/abstract_controller/translation.rb +17 -8
  17. data/lib/abstract_controller/url_for.rb +2 -0
  18. data/lib/abstract_controller.rb +13 -5
  19. data/lib/action_controller/api/api_rendering.rb +16 -0
  20. data/lib/action_controller/api.rb +150 -0
  21. data/lib/action_controller/base.rb +29 -24
  22. data/lib/action_controller/caching.rb +12 -57
  23. data/lib/action_controller/form_builder.rb +50 -0
  24. data/lib/action_controller/log_subscriber.rb +17 -19
  25. data/lib/action_controller/metal/basic_implicit_render.rb +13 -0
  26. data/lib/action_controller/metal/conditional_get.rb +134 -46
  27. data/lib/action_controller/metal/content_security_policy.rb +51 -0
  28. data/lib/action_controller/metal/cookies.rb +6 -4
  29. data/lib/action_controller/metal/data_streaming.rb +30 -50
  30. data/lib/action_controller/metal/default_headers.rb +17 -0
  31. data/lib/action_controller/metal/etag_with_flash.rb +18 -0
  32. data/lib/action_controller/metal/etag_with_template_digest.rb +21 -16
  33. data/lib/action_controller/metal/exceptions.rb +63 -15
  34. data/lib/action_controller/metal/flash.rb +9 -8
  35. data/lib/action_controller/metal/head.rb +26 -21
  36. data/lib/action_controller/metal/helpers.rb +37 -18
  37. data/lib/action_controller/metal/http_authentication.rb +81 -73
  38. data/lib/action_controller/metal/implicit_render.rb +53 -9
  39. data/lib/action_controller/metal/instrumentation.rb +32 -35
  40. data/lib/action_controller/metal/live.rb +102 -120
  41. data/lib/action_controller/metal/logging.rb +20 -0
  42. data/lib/action_controller/metal/mime_responds.rb +49 -47
  43. data/lib/action_controller/metal/parameter_encoding.rb +82 -0
  44. data/lib/action_controller/metal/params_wrapper.rb +83 -66
  45. data/lib/action_controller/metal/permissions_policy.rb +46 -0
  46. data/lib/action_controller/metal/redirecting.rb +53 -32
  47. data/lib/action_controller/metal/renderers.rb +87 -44
  48. data/lib/action_controller/metal/rendering.rb +77 -50
  49. data/lib/action_controller/metal/request_forgery_protection.rb +267 -103
  50. data/lib/action_controller/metal/rescue.rb +10 -17
  51. data/lib/action_controller/metal/streaming.rb +12 -11
  52. data/lib/action_controller/metal/strong_parameters.rb +714 -186
  53. data/lib/action_controller/metal/testing.rb +2 -17
  54. data/lib/action_controller/metal/url_for.rb +19 -10
  55. data/lib/action_controller/metal.rb +104 -87
  56. data/lib/action_controller/railtie.rb +28 -10
  57. data/lib/action_controller/railties/helpers.rb +3 -1
  58. data/lib/action_controller/renderer.rb +141 -0
  59. data/lib/action_controller/template_assertions.rb +11 -0
  60. data/lib/action_controller/test_case.rb +296 -422
  61. data/lib/action_controller.rb +34 -23
  62. data/lib/action_dispatch/http/cache.rb +107 -56
  63. data/lib/action_dispatch/http/content_disposition.rb +45 -0
  64. data/lib/action_dispatch/http/content_security_policy.rb +286 -0
  65. data/lib/action_dispatch/http/filter_parameters.rb +32 -25
  66. data/lib/action_dispatch/http/filter_redirect.rb +10 -12
  67. data/lib/action_dispatch/http/headers.rb +55 -22
  68. data/lib/action_dispatch/http/mime_negotiation.rb +79 -51
  69. data/lib/action_dispatch/http/mime_type.rb +153 -121
  70. data/lib/action_dispatch/http/mime_types.rb +20 -6
  71. data/lib/action_dispatch/http/parameters.rb +90 -40
  72. data/lib/action_dispatch/http/permissions_policy.rb +173 -0
  73. data/lib/action_dispatch/http/rack_cache.rb +2 -0
  74. data/lib/action_dispatch/http/request.rb +226 -121
  75. data/lib/action_dispatch/http/response.rb +248 -113
  76. data/lib/action_dispatch/http/upload.rb +21 -7
  77. data/lib/action_dispatch/http/url.rb +182 -100
  78. data/lib/action_dispatch/journey/formatter.rb +90 -43
  79. data/lib/action_dispatch/journey/gtg/builder.rb +28 -41
  80. data/lib/action_dispatch/journey/gtg/simulator.rb +11 -16
  81. data/lib/action_dispatch/journey/gtg/transition_table.rb +23 -21
  82. data/lib/action_dispatch/journey/nfa/dot.rb +3 -14
  83. data/lib/action_dispatch/journey/nodes/node.rb +29 -15
  84. data/lib/action_dispatch/journey/parser.rb +17 -16
  85. data/lib/action_dispatch/journey/parser.y +4 -3
  86. data/lib/action_dispatch/journey/parser_extras.rb +12 -4
  87. data/lib/action_dispatch/journey/path/pattern.rb +58 -54
  88. data/lib/action_dispatch/journey/route.rb +100 -32
  89. data/lib/action_dispatch/journey/router/utils.rb +29 -18
  90. data/lib/action_dispatch/journey/router.rb +55 -51
  91. data/lib/action_dispatch/journey/routes.rb +17 -17
  92. data/lib/action_dispatch/journey/scanner.rb +26 -17
  93. data/lib/action_dispatch/journey/visitors.rb +98 -54
  94. data/lib/action_dispatch/journey.rb +5 -5
  95. data/lib/action_dispatch/middleware/actionable_exceptions.rb +46 -0
  96. data/lib/action_dispatch/middleware/callbacks.rb +3 -6
  97. data/lib/action_dispatch/middleware/cookies.rb +347 -217
  98. data/lib/action_dispatch/middleware/debug_exceptions.rb +135 -63
  99. data/lib/action_dispatch/middleware/debug_locks.rb +124 -0
  100. data/lib/action_dispatch/middleware/debug_view.rb +66 -0
  101. data/lib/action_dispatch/middleware/exception_wrapper.rb +115 -71
  102. data/lib/action_dispatch/middleware/executor.rb +21 -0
  103. data/lib/action_dispatch/middleware/flash.rb +78 -54
  104. data/lib/action_dispatch/middleware/host_authorization.rb +130 -0
  105. data/lib/action_dispatch/middleware/public_exceptions.rb +32 -27
  106. data/lib/action_dispatch/middleware/reloader.rb +5 -91
  107. data/lib/action_dispatch/middleware/remote_ip.rb +53 -45
  108. data/lib/action_dispatch/middleware/request_id.rb +17 -10
  109. data/lib/action_dispatch/middleware/session/abstract_store.rb +41 -26
  110. data/lib/action_dispatch/middleware/session/cache_store.rb +24 -14
  111. data/lib/action_dispatch/middleware/session/cookie_store.rb +74 -75
  112. data/lib/action_dispatch/middleware/session/mem_cache_store.rb +8 -2
  113. data/lib/action_dispatch/middleware/show_exceptions.rb +28 -23
  114. data/lib/action_dispatch/middleware/ssl.rb +118 -35
  115. data/lib/action_dispatch/middleware/stack.rb +82 -41
  116. data/lib/action_dispatch/middleware/static.rb +156 -89
  117. data/lib/action_dispatch/middleware/templates/rescues/_actions.html.erb +13 -0
  118. data/lib/action_dispatch/middleware/templates/rescues/_actions.text.erb +0 -0
  119. data/lib/action_dispatch/middleware/templates/rescues/_message_and_suggestions.html.erb +22 -0
  120. data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb +4 -14
  121. data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.text.erb +1 -1
  122. data/lib/action_dispatch/middleware/templates/rescues/{_source.erb → _source.html.erb} +4 -2
  123. data/lib/action_dispatch/middleware/templates/rescues/_source.text.erb +8 -0
  124. data/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb +45 -35
  125. data/lib/action_dispatch/middleware/templates/rescues/blocked_host.html.erb +7 -0
  126. data/lib/action_dispatch/middleware/templates/rescues/blocked_host.text.erb +5 -0
  127. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb +23 -4
  128. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.text.erb +1 -1
  129. data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.html.erb +24 -0
  130. data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.text.erb +15 -0
  131. data/lib/action_dispatch/middleware/templates/rescues/layout.erb +105 -8
  132. data/lib/action_dispatch/middleware/templates/rescues/missing_exact_template.html.erb +19 -0
  133. data/lib/action_dispatch/middleware/templates/rescues/missing_exact_template.text.erb +3 -0
  134. data/lib/action_dispatch/middleware/templates/rescues/missing_template.html.erb +2 -2
  135. data/lib/action_dispatch/middleware/templates/rescues/routing_error.html.erb +1 -1
  136. data/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb +3 -3
  137. data/lib/action_dispatch/middleware/templates/rescues/template_error.text.erb +1 -1
  138. data/lib/action_dispatch/middleware/templates/rescues/unknown_action.html.erb +1 -1
  139. data/lib/action_dispatch/middleware/templates/routes/_route.html.erb +4 -4
  140. data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +87 -64
  141. data/lib/action_dispatch/railtie.rb +27 -13
  142. data/lib/action_dispatch/request/session.rb +109 -61
  143. data/lib/action_dispatch/request/utils.rb +90 -23
  144. data/lib/action_dispatch/routing/endpoint.rb +9 -2
  145. data/lib/action_dispatch/routing/inspector.rb +141 -102
  146. data/lib/action_dispatch/routing/mapper.rb +811 -473
  147. data/lib/action_dispatch/routing/polymorphic_routes.rb +167 -143
  148. data/lib/action_dispatch/routing/redirection.rb +37 -27
  149. data/lib/action_dispatch/routing/route_set.rb +363 -331
  150. data/lib/action_dispatch/routing/routes_proxy.rb +32 -5
  151. data/lib/action_dispatch/routing/url_for.rb +66 -26
  152. data/lib/action_dispatch/routing.rb +36 -36
  153. data/lib/action_dispatch/system_test_case.rb +190 -0
  154. data/lib/action_dispatch/system_testing/browser.rb +86 -0
  155. data/lib/action_dispatch/system_testing/driver.rb +67 -0
  156. data/lib/action_dispatch/system_testing/server.rb +31 -0
  157. data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +138 -0
  158. data/lib/action_dispatch/system_testing/test_helpers/setup_and_teardown.rb +29 -0
  159. data/lib/action_dispatch/testing/assertion_response.rb +46 -0
  160. data/lib/action_dispatch/testing/assertions/response.rb +44 -22
  161. data/lib/action_dispatch/testing/assertions/routing.rb +47 -31
  162. data/lib/action_dispatch/testing/assertions.rb +6 -4
  163. data/lib/action_dispatch/testing/integration.rb +391 -220
  164. data/lib/action_dispatch/testing/request_encoder.rb +55 -0
  165. data/lib/action_dispatch/testing/test_process.rb +53 -22
  166. data/lib/action_dispatch/testing/test_request.rb +27 -34
  167. data/lib/action_dispatch/testing/test_response.rb +11 -11
  168. data/lib/action_dispatch.rb +35 -21
  169. data/lib/action_pack/gem_version.rb +6 -4
  170. data/lib/action_pack/version.rb +3 -1
  171. data/lib/action_pack.rb +4 -2
  172. metadata +78 -48
  173. data/lib/action_controller/metal/force_ssl.rb +0 -97
  174. data/lib/action_controller/metal/hide_actions.rb +0 -40
  175. data/lib/action_controller/metal/rack_delegation.rb +0 -32
  176. data/lib/action_controller/middleware.rb +0 -39
  177. data/lib/action_controller/model_naming.rb +0 -12
  178. data/lib/action_dispatch/http/parameter_filter.rb +0 -72
  179. data/lib/action_dispatch/journey/backwards.rb +0 -5
  180. data/lib/action_dispatch/journey/nfa/builder.rb +0 -76
  181. data/lib/action_dispatch/journey/nfa/simulator.rb +0 -47
  182. data/lib/action_dispatch/journey/nfa/transition_table.rb +0 -163
  183. data/lib/action_dispatch/journey/router/strexp.rb +0 -27
  184. data/lib/action_dispatch/middleware/params_parser.rb +0 -60
  185. data/lib/action_dispatch/testing/assertions/dom.rb +0 -3
  186. data/lib/action_dispatch/testing/assertions/selector.rb +0 -3
  187. data/lib/action_dispatch/testing/assertions/tag.rb +0 -3
@@ -1,23 +1,35 @@
1
- require 'set'
2
- require 'singleton'
3
- require 'active_support/core_ext/module/attribute_accessors'
4
- require 'active_support/core_ext/string/starts_ends_with'
1
+ # frozen_string_literal: true
2
+
3
+ require "singleton"
4
+ require "active_support/core_ext/symbol/starts_ends_with"
5
5
 
6
6
  module Mime
7
- class Mimes < Array
8
- def symbols
9
- @symbols ||= map { |m| m.to_sym }
7
+ class Mimes
8
+ attr_reader :symbols
9
+
10
+ include Enumerable
11
+
12
+ def initialize
13
+ @mimes = []
14
+ @symbols = []
10
15
  end
11
16
 
12
- %w(<< concat shift unshift push pop []= clear compact! collect!
13
- delete delete_at delete_if flatten! map! insert reject! reverse!
14
- replace slice! sort! uniq!).each do |method|
15
- module_eval <<-CODE, __FILE__, __LINE__ + 1
16
- def #{method}(*)
17
- @symbols = nil
18
- super
17
+ def each
18
+ @mimes.each { |x| yield x }
19
+ end
20
+
21
+ def <<(type)
22
+ @mimes << type
23
+ @symbols << type.to_sym
24
+ end
25
+
26
+ def delete_if
27
+ @mimes.delete_if do |x|
28
+ if yield x
29
+ @symbols.delete(x.to_sym)
30
+ true
19
31
  end
20
- CODE
32
+ end
21
33
  end
22
34
  end
23
35
 
@@ -37,7 +49,7 @@ module Mime
37
49
  end
38
50
  end
39
51
 
40
- # Encapsulates the notion of a mime type. Can be used at render time, for example, with:
52
+ # Encapsulates the notion of a MIME type. Can be used at render time, for example, with:
41
53
  #
42
54
  # class PostsController < ActionController::Base
43
55
  # def show
@@ -45,20 +57,17 @@ module Mime
45
57
  #
46
58
  # respond_to do |format|
47
59
  # format.html
48
- # format.ics { render text: @post.to_ics, mime_type: Mime::Type["text/calendar"] }
60
+ # format.ics { render body: @post.to_ics, mime_type: Mime::Type.lookup("text/calendar") }
49
61
  # format.xml { render xml: @post }
50
62
  # end
51
63
  # end
52
64
  # end
53
65
  class Type
54
- @@html_types = Set.new [:html, :all]
55
- cattr_reader :html_types
56
-
57
66
  attr_reader :symbol
58
67
 
59
68
  @register_callbacks = []
60
69
 
61
- # A simple helper class used in parsing the accept header
70
+ # A simple helper class used in parsing the accept header.
62
71
  class AcceptItem #:nodoc:
63
72
  attr_accessor :index, :name, :q
64
73
  alias :to_s :name
@@ -66,7 +75,7 @@ module Mime
66
75
  def initialize(index, name, q = nil)
67
76
  @index = index
68
77
  @name = name
69
- q ||= 0.0 if @name == Mime::ALL.to_s # default wildcard match to end of list
78
+ q ||= 0.0 if @name == "*/*" # Default wildcard match to end of list.
70
79
  @q = ((q || 1.0).to_f * 100).to_i
71
80
  end
72
81
 
@@ -75,70 +84,58 @@ module Mime
75
84
  result = @index <=> item.index if result == 0
76
85
  result
77
86
  end
78
-
79
- def ==(item)
80
- @name == item.to_s
81
- end
82
87
  end
83
88
 
84
- class AcceptList < Array #:nodoc:
85
- def assort!
86
- sort!
89
+ class AcceptList #:nodoc:
90
+ def self.sort!(list)
91
+ list.sort!
87
92
 
88
- # Take care of the broken text/xml entry by renaming or deleting it
93
+ text_xml_idx = find_item_by_name list, "text/xml"
94
+ app_xml_idx = find_item_by_name list, Mime[:xml].to_s
95
+
96
+ # Take care of the broken text/xml entry by renaming or deleting it.
89
97
  if text_xml_idx && app_xml_idx
90
- app_xml.q = [text_xml.q, app_xml.q].max # set the q value to the max of the two
91
- exchange_xml_items if app_xml_idx > text_xml_idx # make sure app_xml is ahead of text_xml in the list
92
- delete_at(text_xml_idx) # delete text_xml from the list
98
+ app_xml = list[app_xml_idx]
99
+ text_xml = list[text_xml_idx]
100
+
101
+ app_xml.q = [text_xml.q, app_xml.q].max # Set the q value to the max of the two.
102
+ if app_xml_idx > text_xml_idx # Make sure app_xml is ahead of text_xml in the list.
103
+ list[app_xml_idx], list[text_xml_idx] = text_xml, app_xml
104
+ app_xml_idx, text_xml_idx = text_xml_idx, app_xml_idx
105
+ end
106
+ list.delete_at(text_xml_idx) # Delete text_xml from the list.
93
107
  elsif text_xml_idx
94
- text_xml.name = Mime::XML.to_s
108
+ list[text_xml_idx].name = Mime[:xml].to_s
95
109
  end
96
110
 
97
- # Look for more specific XML-based types and sort them ahead of app/xml
111
+ # Look for more specific XML-based types and sort them ahead of app/xml.
98
112
  if app_xml_idx
113
+ app_xml = list[app_xml_idx]
99
114
  idx = app_xml_idx
100
115
 
101
- while idx < length
102
- type = self[idx]
116
+ while idx < list.length
117
+ type = list[idx]
103
118
  break if type.q < app_xml.q
104
119
 
105
- if type.name.ends_with? '+xml'
106
- self[app_xml_idx], self[idx] = self[idx], app_xml
107
- @app_xml_idx = idx
120
+ if type.name.end_with? "+xml"
121
+ list[app_xml_idx], list[idx] = list[idx], app_xml
122
+ app_xml_idx = idx
108
123
  end
109
124
  idx += 1
110
125
  end
111
126
  end
112
127
 
113
- map! { |i| Mime::Type.lookup(i.name) }.uniq!
114
- to_a
128
+ list.map! { |i| Mime::Type.lookup(i.name) }.uniq!
129
+ list
115
130
  end
116
131
 
117
- private
118
- def text_xml_idx
119
- @text_xml_idx ||= index('text/xml')
120
- end
121
-
122
- def app_xml_idx
123
- @app_xml_idx ||= index(Mime::XML.to_s)
124
- end
125
-
126
- def text_xml
127
- self[text_xml_idx]
128
- end
129
-
130
- def app_xml
131
- self[app_xml_idx]
132
- end
133
-
134
- def exchange_xml_items
135
- self[app_xml_idx], self[text_xml_idx] = text_xml, app_xml
136
- @app_xml_idx, @text_xml_idx = text_xml_idx, app_xml_idx
137
- end
132
+ def self.find_item_by_name(array, name)
133
+ array.index { |item| item.name == name }
134
+ end
138
135
  end
139
136
 
140
137
  class << self
141
- TRAILING_STAR_REGEXP = /(text|application)\/\*/
138
+ TRAILING_STAR_REGEXP = /^(text|application)\/\*/
142
139
  PARAMETER_SEPARATOR_REGEXP = /;\s*\w+="?\w+"?/
143
140
 
144
141
  def register_callback(&block)
@@ -153,46 +150,48 @@ module Mime
153
150
  EXTENSION_LOOKUP[extension.to_s]
154
151
  end
155
152
 
156
- # Registers an alias that's not used on mime type lookup, but can be referenced directly. Especially useful for
153
+ # Registers an alias that's not used on MIME type lookup, but can be referenced directly. Especially useful for
157
154
  # rendering different HTML versions depending on the user agent, like an iPhone.
158
155
  def register_alias(string, symbol, extension_synonyms = [])
159
156
  register(string, symbol, [], extension_synonyms, true)
160
157
  end
161
158
 
162
159
  def register(string, symbol, mime_type_synonyms = [], extension_synonyms = [], skip_lookup = false)
163
- Mime.const_set(symbol.upcase, Type.new(string, symbol, mime_type_synonyms))
160
+ new_mime = Type.new(string, symbol, mime_type_synonyms)
164
161
 
165
- new_mime = Mime.const_get(symbol.upcase)
166
162
  SET << new_mime
167
163
 
168
- ([string] + mime_type_synonyms).each { |str| LOOKUP[str] = SET.last } unless skip_lookup
169
- ([symbol] + extension_synonyms).each { |ext| EXTENSION_LOOKUP[ext.to_s] = SET.last }
164
+ ([string] + mime_type_synonyms).each { |str| LOOKUP[str] = new_mime } unless skip_lookup
165
+ ([symbol] + extension_synonyms).each { |ext| EXTENSION_LOOKUP[ext.to_s] = new_mime }
170
166
 
171
167
  @register_callbacks.each do |callback|
172
168
  callback.call(new_mime)
173
169
  end
170
+ new_mime
174
171
  end
175
172
 
176
173
  def parse(accept_header)
177
- if !accept_header.include?(',')
174
+ if !accept_header.include?(",")
178
175
  accept_header = accept_header.split(PARAMETER_SEPARATOR_REGEXP).first
176
+ return [] unless accept_header
179
177
  parse_trailing_star(accept_header) || [Mime::Type.lookup(accept_header)].compact
180
178
  else
181
- list, index = AcceptList.new, 0
182
- accept_header.split(',').each do |header|
179
+ list, index = [], 0
180
+ accept_header.split(",").each do |header|
183
181
  params, q = header.split(PARAMETER_SEPARATOR_REGEXP)
184
- if params.present?
185
- params.strip!
186
182
 
187
- params = parse_trailing_star(params) || [params]
183
+ next unless params
184
+ params.strip!
185
+ next if params.empty?
186
+
187
+ params = parse_trailing_star(params) || [params]
188
188
 
189
- params.each do |m|
190
- list << AcceptItem.new(index, m.to_s, q)
191
- index += 1
192
- end
189
+ params.each do |m|
190
+ list << AcceptItem.new(index, m.to_s, q)
191
+ index += 1
193
192
  end
194
193
  end
195
- list.assort!
194
+ AcceptList.sort! list
196
195
  end
197
196
  end
198
197
 
@@ -200,34 +199,44 @@ module Mime
200
199
  parse_data_with_trailing_star($1) if accept_header =~ TRAILING_STAR_REGEXP
201
200
  end
202
201
 
203
- # For an input of <tt>'text'</tt>, returns <tt>[Mime::JSON, Mime::XML, Mime::ICS,
204
- # Mime::HTML, Mime::CSS, Mime::CSV, Mime::JS, Mime::YAML, Mime::TEXT]</tt>.
202
+ # For an input of <tt>'text'</tt>, returns <tt>[Mime[:json], Mime[:xml], Mime[:ics],
203
+ # Mime[:html], Mime[:css], Mime[:csv], Mime[:js], Mime[:yaml], Mime[:text]</tt>.
205
204
  #
206
- # For an input of <tt>'application'</tt>, returns <tt>[Mime::HTML, Mime::JS,
207
- # Mime::XML, Mime::YAML, Mime::ATOM, Mime::JSON, Mime::RSS, Mime::URL_ENCODED_FORM]</tt>.
208
- def parse_data_with_trailing_star(input)
209
- Mime::SET.select { |m| m =~ input }
205
+ # For an input of <tt>'application'</tt>, returns <tt>[Mime[:html], Mime[:js],
206
+ # Mime[:xml], Mime[:yaml], Mime[:atom], Mime[:json], Mime[:rss], Mime[:url_encoded_form]</tt>.
207
+ def parse_data_with_trailing_star(type)
208
+ Mime::SET.select { |m| m.match?(type) }
210
209
  end
211
210
 
212
211
  # This method is opposite of register method.
213
212
  #
214
- # Usage:
213
+ # To unregister a MIME type:
215
214
  #
216
215
  # Mime::Type.unregister(:mobile)
217
216
  def unregister(symbol)
218
- symbol = symbol.upcase
219
- mime = Mime.const_get(symbol)
220
- Mime.instance_eval { remove_const(symbol) }
221
-
222
- SET.delete_if { |v| v.eql?(mime) }
223
- LOOKUP.delete_if { |_,v| v.eql?(mime) }
224
- EXTENSION_LOOKUP.delete_if { |_,v| v.eql?(mime) }
217
+ symbol = symbol.downcase
218
+ if mime = Mime[symbol]
219
+ SET.delete_if { |v| v.eql?(mime) }
220
+ LOOKUP.delete_if { |_, v| v.eql?(mime) }
221
+ EXTENSION_LOOKUP.delete_if { |_, v| v.eql?(mime) }
222
+ end
225
223
  end
226
224
  end
227
225
 
228
226
  attr_reader :hash
229
227
 
228
+ MIME_NAME = "[a-zA-Z0-9][a-zA-Z0-9#{Regexp.escape('!#$&-^_.+')}]{0,126}"
229
+ MIME_PARAMETER_KEY = "[a-zA-Z0-9][a-zA-Z0-9#{Regexp.escape('!#$&-^_.+')}]{0,126}"
230
+ MIME_PARAMETER_VALUE = "#{Regexp.escape('"')}?[a-zA-Z0-9][a-zA-Z0-9#{Regexp.escape('!#$&-^_.+')}]{0,126}#{Regexp.escape('"')}?"
231
+ MIME_PARAMETER = "\s*\;\s*#{MIME_PARAMETER_KEY}(?:\=#{MIME_PARAMETER_VALUE})?"
232
+ MIME_REGEXP = /\A(?:\*\/\*|#{MIME_NAME}\/(?:\*|#{MIME_NAME})(?>\s*#{MIME_PARAMETER}\s*)*)\z/
233
+
234
+ class InvalidMimeType < StandardError; end
235
+
230
236
  def initialize(string, symbol = nil, synonyms = [])
237
+ unless MIME_REGEXP.match?(string)
238
+ raise InvalidMimeType, "#{string.inspect} is not a valid MIME type"
239
+ end
231
240
  @symbol, @synonyms = symbol, synonyms
232
241
  @string = string
233
242
  @hash = [@string, @synonyms, @symbol].hash
@@ -246,7 +255,7 @@ module Mime
246
255
  end
247
256
 
248
257
  def ref
249
- to_sym || to_s
258
+ symbol || to_s
250
259
  end
251
260
 
252
261
  def ===(list)
@@ -258,7 +267,7 @@ module Mime
258
267
  end
259
268
 
260
269
  def ==(mime_type)
261
- return false if mime_type.blank?
270
+ return false unless mime_type
262
271
  (@synonyms + [ self ]).any? do |synonym|
263
272
  synonym.to_s == mime_type.to_s || synonym.to_sym == mime_type.to_sym
264
273
  end
@@ -272,40 +281,59 @@ module Mime
272
281
  end
273
282
 
274
283
  def =~(mime_type)
275
- return false if mime_type.blank?
284
+ return false unless mime_type
276
285
  regexp = Regexp.new(Regexp.quote(mime_type.to_s))
277
- (@synonyms + [ self ]).any? do |synonym|
278
- synonym.to_s =~ regexp
279
- end
286
+ @synonyms.any? { |synonym| synonym.to_s =~ regexp } || @string =~ regexp
287
+ end
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)
280
293
  end
281
294
 
282
295
  def html?
283
- @@html_types.include?(to_sym) || @string =~ /html/
296
+ (symbol == :html) || /html/.match?(@string)
284
297
  end
285
298
 
299
+ def all?; false; end
286
300
 
287
301
  protected
288
-
289
- attr_reader :string, :synonyms
302
+ attr_reader :string, :synonyms
290
303
 
291
304
  private
305
+ def to_ary; end
306
+ def to_a; end
292
307
 
293
- def to_ary; end
294
- def to_a; end
308
+ def method_missing(method, *args)
309
+ if method.end_with?("?")
310
+ method[0..-2].downcase.to_sym == to_sym
311
+ else
312
+ super
313
+ end
314
+ end
295
315
 
296
- def method_missing(method, *args)
297
- if method.to_s.ends_with? '?'
298
- method[0..-2].downcase.to_sym == to_sym
299
- else
300
- super
316
+ def respond_to_missing?(method, include_private = false)
317
+ method.end_with?("?") || super
301
318
  end
302
- end
319
+ end
320
+
321
+ class AllType < Type
322
+ include Singleton
303
323
 
304
- def respond_to_missing?(method, include_private = false) #:nodoc:
305
- method.to_s.ends_with? '?'
324
+ def initialize
325
+ super "*/*", nil
306
326
  end
327
+
328
+ def all?; true; end
329
+ def html?; true; end
307
330
  end
308
331
 
332
+ # ALL isn't a real MIME type, so we don't register it for lookup with the
333
+ # other concrete types. It's a wildcard match that we use for +respond_to+
334
+ # negotiation internals.
335
+ ALL = AllType.instance
336
+
309
337
  class NullType
310
338
  include Singleton
311
339
 
@@ -313,17 +341,21 @@ module Mime
313
341
  true
314
342
  end
315
343
 
316
- def ref; end
317
-
318
- def respond_to_missing?(method, include_private = false)
319
- method.to_s.ends_with? '?'
344
+ def to_s
345
+ ""
320
346
  end
321
347
 
348
+ def ref; end
349
+
322
350
  private
323
- def method_missing(method, *args)
324
- false if method.to_s.ends_with? '?'
325
- end
351
+ def respond_to_missing?(method, _)
352
+ method.end_with?("?")
353
+ end
354
+
355
+ def method_missing(method, *args)
356
+ false if method.end_with?("?")
357
+ end
326
358
  end
327
359
  end
328
360
 
329
- require 'action_dispatch/http/mime_types'
361
+ require "action_dispatch/http/mime_types"
@@ -1,5 +1,7 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # Build list of Mime types for HTTP responses
2
- # http://www.iana.org/assignments/media-types/
4
+ # https://www.iana.org/assignments/media-types/
3
5
 
4
6
  Mime::Type.register "text/html", :html, %w( application/xhtml+xml ), %w( xhtml )
5
7
  Mime::Type.register "text/plain", :text, [], %w(txt)
@@ -8,29 +10,41 @@ Mime::Type.register "text/css", :css
8
10
  Mime::Type.register "text/calendar", :ics
9
11
  Mime::Type.register "text/csv", :csv
10
12
  Mime::Type.register "text/vcard", :vcf
13
+ Mime::Type.register "text/vtt", :vtt, %w(vtt)
11
14
 
12
15
  Mime::Type.register "image/png", :png, [], %w(png)
13
16
  Mime::Type.register "image/jpeg", :jpeg, [], %w(jpg jpeg jpe pjpeg)
14
17
  Mime::Type.register "image/gif", :gif, [], %w(gif)
15
18
  Mime::Type.register "image/bmp", :bmp, [], %w(bmp)
16
19
  Mime::Type.register "image/tiff", :tiff, [], %w(tif tiff)
20
+ Mime::Type.register "image/svg+xml", :svg
17
21
 
18
22
  Mime::Type.register "video/mpeg", :mpeg, [], %w(mpg mpeg mpe)
19
23
 
24
+ Mime::Type.register "audio/mpeg", :mp3, [], %w(mp1 mp2 mp3)
25
+ Mime::Type.register "audio/ogg", :ogg, [], %w(oga ogg spx opus)
26
+ Mime::Type.register "audio/aac", :m4a, %w( audio/mp4 ), %w(m4a mpg4 aac)
27
+
28
+ Mime::Type.register "video/webm", :webm, [], %w(webm)
29
+ Mime::Type.register "video/mp4", :mp4, [], %w(mp4 m4v)
30
+
31
+ Mime::Type.register "font/otf", :otf, [], %w(otf)
32
+ Mime::Type.register "font/ttf", :ttf, [], %w(ttf)
33
+ Mime::Type.register "font/woff", :woff, [], %w(woff)
34
+ Mime::Type.register "font/woff2", :woff2, [], %w(woff2)
35
+
20
36
  Mime::Type.register "application/xml", :xml, %w( text/xml application/x-xml )
21
37
  Mime::Type.register "application/rss+xml", :rss
22
38
  Mime::Type.register "application/atom+xml", :atom
23
- Mime::Type.register "application/x-yaml", :yaml, %w( text/yaml )
39
+ Mime::Type.register "application/x-yaml", :yaml, %w( text/yaml ), %w(yml yaml)
24
40
 
25
41
  Mime::Type.register "multipart/form-data", :multipart_form
26
42
  Mime::Type.register "application/x-www-form-urlencoded", :url_encoded_form
27
43
 
28
- # http://www.ietf.org/rfc/rfc4627.txt
44
+ # https://www.ietf.org/rfc/rfc4627.txt
29
45
  # http://www.json.org/JSONRequest.html
30
46
  Mime::Type.register "application/json", :json, %w( text/x-json application/jsonrequest )
31
47
 
32
48
  Mime::Type.register "application/pdf", :pdf, [], %w(pdf)
33
49
  Mime::Type.register "application/zip", :zip, [], %w(zip)
34
-
35
- # Create Mime::ALL but do not add it to the SET.
36
- Mime::ALL = Mime::Type.new("*/*", :all, [])
50
+ Mime::Type.register "application/gzip", :gzip, %w(application/x-gzip), %w(gz)
@@ -1,35 +1,78 @@
1
- require 'active_support/core_ext/hash/keys'
2
- require 'active_support/core_ext/hash/indifferent_access'
3
- require 'active_support/deprecation'
1
+ # frozen_string_literal: true
4
2
 
5
3
  module ActionDispatch
6
4
  module Http
7
5
  module Parameters
8
- PARAMETERS_KEY = 'action_dispatch.request.path_parameters'
6
+ extend ActiveSupport::Concern
7
+
8
+ PARAMETERS_KEY = "action_dispatch.request.path_parameters"
9
+
10
+ DEFAULT_PARSERS = {
11
+ Mime[:json].symbol => -> (raw_post) {
12
+ data = ActiveSupport::JSON.decode(raw_post)
13
+ data.is_a?(Hash) ? data : { _json: data }
14
+ }
15
+ }
16
+
17
+ # Raised when raw data from the request cannot be parsed by the parser
18
+ # defined for request's content MIME type.
19
+ class ParseError < StandardError
20
+ def initialize
21
+ super($!.message)
22
+ end
23
+ end
24
+
25
+ included do
26
+ class << self
27
+ # Returns the parameter parsers.
28
+ attr_reader :parameter_parsers
29
+ end
30
+
31
+ self.parameter_parsers = DEFAULT_PARSERS
32
+ end
33
+
34
+ module ClassMethods
35
+ # Configure the parameter parser for a given MIME type.
36
+ #
37
+ # It accepts a hash where the key is the symbol of the MIME type
38
+ # and the value is a proc.
39
+ #
40
+ # original_parsers = ActionDispatch::Request.parameter_parsers
41
+ # xml_parser = -> (raw_post) { Hash.from_xml(raw_post) || {} }
42
+ # new_parsers = original_parsers.merge(xml: xml_parser)
43
+ # ActionDispatch::Request.parameter_parsers = new_parsers
44
+ def parameter_parsers=(parsers)
45
+ @parameter_parsers = parsers.transform_keys { |key| key.respond_to?(:symbol) ? key.symbol : key }
46
+ end
47
+ end
9
48
 
10
49
  # Returns both GET and POST \parameters in a single hash.
11
50
  def parameters
12
- @env["action_dispatch.request.parameters"] ||= begin
13
- params = begin
14
- request_parameters.merge(query_parameters)
15
- rescue EOFError
16
- query_parameters.dup
17
- end
18
- params.merge!(path_parameters)
19
- end
51
+ params = get_header("action_dispatch.request.parameters")
52
+ return params if params
53
+
54
+ params = begin
55
+ request_parameters.merge(query_parameters)
56
+ rescue EOFError
57
+ query_parameters.dup
58
+ end
59
+ params.merge!(path_parameters)
60
+ set_header("action_dispatch.request.parameters", params)
61
+ params
20
62
  end
21
63
  alias :params :parameters
22
64
 
23
65
  def path_parameters=(parameters) #:nodoc:
24
- @env.delete('action_dispatch.request.parameters')
25
- @env[PARAMETERS_KEY] = parameters
26
- end
66
+ delete_header("action_dispatch.request.parameters")
67
+
68
+ parameters = Request::Utils.set_binary_encoding(self, parameters, parameters[:controller], parameters[:action])
69
+ # If any of the path parameters has an invalid encoding then
70
+ # raise since it's likely to trigger errors further on.
71
+ Request::Utils.check_param_encoding(parameters)
27
72
 
28
- def symbolized_path_parameters
29
- ActiveSupport::Deprecation.warn(
30
- '`symbolized_path_parameters` is deprecated. Please use `path_parameters`.'
31
- )
32
- path_parameters
73
+ set_header PARAMETERS_KEY, parameters
74
+ rescue Rack::Utils::ParameterTypeError, Rack::Utils::InvalidParameterError => e
75
+ raise ActionController::BadRequest.new("Invalid path parameters: #{e.message}")
33
76
  end
34
77
 
35
78
  # Returns a hash with the \parameters used to form the \path of the request.
@@ -37,31 +80,38 @@ module ActionDispatch
37
80
  #
38
81
  # {'action' => 'my_action', 'controller' => 'my_controller'}
39
82
  def path_parameters
40
- @env[PARAMETERS_KEY] ||= {}
83
+ get_header(PARAMETERS_KEY) || set_header(PARAMETERS_KEY, {})
41
84
  end
42
85
 
43
- private
86
+ private
87
+ def parse_formatted_parameters(parsers)
88
+ return yield if content_length.zero? || content_mime_type.nil?
44
89
 
45
- # Convert nested Hash to HashWithIndifferentAccess.
46
- #
47
- def normalize_encode_params(params)
48
- case params
49
- when Hash
50
- if params.has_key?(:tempfile)
51
- UploadedFile.new(params)
52
- else
53
- params.each_with_object({}) do |(key, val), new_hash|
54
- new_hash[key] = if val.is_a?(Array)
55
- val.map! { |el| normalize_encode_params(el) }
56
- else
57
- normalize_encode_params(val)
58
- end
59
- end.with_indifferent_access
90
+ strategy = parsers.fetch(content_mime_type.symbol) { return yield }
91
+
92
+ begin
93
+ strategy.call(raw_post)
94
+ rescue # JSON or Ruby code block errors.
95
+ log_parse_error_once
96
+ raise ParseError
60
97
  end
61
- else
62
- params
63
98
  end
64
- end
99
+
100
+ def log_parse_error_once
101
+ @parse_error_logged ||= begin
102
+ parse_logger = logger || ActiveSupport::Logger.new($stderr)
103
+ parse_logger.debug <<~MSG.chomp
104
+ Error occurred while parsing request parameters.
105
+ Contents:
106
+
107
+ #{raw_post}
108
+ MSG
109
+ end
110
+ end
111
+
112
+ def params_parsers
113
+ ActionDispatch::Request.parameter_parsers
114
+ end
65
115
  end
66
116
  end
67
117
  end