actionpack 4.2.10 → 7.2.0.rc1

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 (202) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +86 -600
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +13 -14
  5. data/lib/abstract_controller/asset_paths.rb +5 -1
  6. data/lib/abstract_controller/base.rb +166 -136
  7. data/lib/abstract_controller/caching/fragments.rb +149 -0
  8. data/lib/abstract_controller/caching.rb +68 -0
  9. data/lib/abstract_controller/callbacks.rb +126 -57
  10. data/lib/abstract_controller/collector.rb +13 -15
  11. data/lib/abstract_controller/deprecator.rb +9 -0
  12. data/lib/abstract_controller/error.rb +8 -0
  13. data/lib/abstract_controller/helpers.rb +181 -132
  14. data/lib/abstract_controller/logger.rb +5 -1
  15. data/lib/abstract_controller/railties/routes_helpers.rb +10 -3
  16. data/lib/abstract_controller/rendering.rb +56 -56
  17. data/lib/abstract_controller/translation.rb +29 -15
  18. data/lib/abstract_controller/url_for.rb +15 -11
  19. data/lib/abstract_controller.rb +21 -5
  20. data/lib/action_controller/api/api_rendering.rb +18 -0
  21. data/lib/action_controller/api.rb +154 -0
  22. data/lib/action_controller/base.rb +219 -155
  23. data/lib/action_controller/caching.rb +28 -68
  24. data/lib/action_controller/deprecator.rb +9 -0
  25. data/lib/action_controller/form_builder.rb +55 -0
  26. data/lib/action_controller/log_subscriber.rb +35 -22
  27. data/lib/action_controller/metal/allow_browser.rb +119 -0
  28. data/lib/action_controller/metal/basic_implicit_render.rb +17 -0
  29. data/lib/action_controller/metal/conditional_get.rb +259 -122
  30. data/lib/action_controller/metal/content_security_policy.rb +86 -0
  31. data/lib/action_controller/metal/cookies.rb +9 -5
  32. data/lib/action_controller/metal/data_streaming.rb +87 -104
  33. data/lib/action_controller/metal/default_headers.rb +21 -0
  34. data/lib/action_controller/metal/etag_with_flash.rb +22 -0
  35. data/lib/action_controller/metal/etag_with_template_digest.rb +35 -26
  36. data/lib/action_controller/metal/exceptions.rb +71 -24
  37. data/lib/action_controller/metal/flash.rb +26 -19
  38. data/lib/action_controller/metal/head.rb +45 -36
  39. data/lib/action_controller/metal/helpers.rb +80 -64
  40. data/lib/action_controller/metal/http_authentication.rb +297 -244
  41. data/lib/action_controller/metal/implicit_render.rb +57 -9
  42. data/lib/action_controller/metal/instrumentation.rb +76 -64
  43. data/lib/action_controller/metal/live.rb +238 -176
  44. data/lib/action_controller/metal/logging.rb +22 -0
  45. data/lib/action_controller/metal/mime_responds.rb +177 -166
  46. data/lib/action_controller/metal/parameter_encoding.rb +84 -0
  47. data/lib/action_controller/metal/params_wrapper.rb +145 -118
  48. data/lib/action_controller/metal/permissions_policy.rb +38 -0
  49. data/lib/action_controller/metal/rate_limiting.rb +62 -0
  50. data/lib/action_controller/metal/redirecting.rb +203 -64
  51. data/lib/action_controller/metal/renderers.rb +108 -65
  52. data/lib/action_controller/metal/rendering.rb +216 -56
  53. data/lib/action_controller/metal/request_forgery_protection.rb +496 -163
  54. data/lib/action_controller/metal/rescue.rb +19 -21
  55. data/lib/action_controller/metal/streaming.rb +179 -138
  56. data/lib/action_controller/metal/strong_parameters.rb +1058 -382
  57. data/lib/action_controller/metal/testing.rb +11 -17
  58. data/lib/action_controller/metal/url_for.rb +37 -21
  59. data/lib/action_controller/metal.rb +236 -138
  60. data/lib/action_controller/railtie.rb +89 -11
  61. data/lib/action_controller/railties/helpers.rb +5 -1
  62. data/lib/action_controller/renderer.rb +161 -0
  63. data/lib/action_controller/template_assertions.rb +13 -0
  64. data/lib/action_controller/test_case.rb +425 -497
  65. data/lib/action_controller.rb +44 -22
  66. data/lib/action_dispatch/constants.rb +34 -0
  67. data/lib/action_dispatch/deprecator.rb +9 -0
  68. data/lib/action_dispatch/http/cache.rb +119 -63
  69. data/lib/action_dispatch/http/content_disposition.rb +47 -0
  70. data/lib/action_dispatch/http/content_security_policy.rb +364 -0
  71. data/lib/action_dispatch/http/filter_parameters.rb +36 -34
  72. data/lib/action_dispatch/http/filter_redirect.rb +24 -12
  73. data/lib/action_dispatch/http/headers.rb +66 -31
  74. data/lib/action_dispatch/http/mime_negotiation.rb +106 -75
  75. data/lib/action_dispatch/http/mime_type.rb +196 -136
  76. data/lib/action_dispatch/http/mime_types.rb +25 -7
  77. data/lib/action_dispatch/http/parameters.rb +97 -45
  78. data/lib/action_dispatch/http/permissions_policy.rb +187 -0
  79. data/lib/action_dispatch/http/rack_cache.rb +6 -0
  80. data/lib/action_dispatch/http/request.rb +299 -170
  81. data/lib/action_dispatch/http/response.rb +311 -160
  82. data/lib/action_dispatch/http/upload.rb +52 -23
  83. data/lib/action_dispatch/http/url.rb +201 -125
  84. data/lib/action_dispatch/journey/formatter.rb +110 -50
  85. data/lib/action_dispatch/journey/gtg/builder.rb +37 -50
  86. data/lib/action_dispatch/journey/gtg/simulator.rb +20 -17
  87. data/lib/action_dispatch/journey/gtg/transition_table.rb +96 -36
  88. data/lib/action_dispatch/journey/nfa/dot.rb +5 -14
  89. data/lib/action_dispatch/journey/nodes/node.rb +100 -20
  90. data/lib/action_dispatch/journey/parser.rb +19 -17
  91. data/lib/action_dispatch/journey/parser.y +4 -3
  92. data/lib/action_dispatch/journey/parser_extras.rb +14 -4
  93. data/lib/action_dispatch/journey/path/pattern.rb +79 -63
  94. data/lib/action_dispatch/journey/route.rb +108 -44
  95. data/lib/action_dispatch/journey/router/utils.rb +41 -29
  96. data/lib/action_dispatch/journey/router.rb +64 -57
  97. data/lib/action_dispatch/journey/routes.rb +23 -21
  98. data/lib/action_dispatch/journey/scanner.rb +28 -17
  99. data/lib/action_dispatch/journey/visitors.rb +100 -54
  100. data/lib/action_dispatch/journey/visualizer/fsm.js +49 -24
  101. data/lib/action_dispatch/journey/visualizer/index.html.erb +1 -1
  102. data/lib/action_dispatch/journey.rb +7 -5
  103. data/lib/action_dispatch/log_subscriber.rb +25 -0
  104. data/lib/action_dispatch/middleware/actionable_exceptions.rb +46 -0
  105. data/lib/action_dispatch/middleware/assume_ssl.rb +27 -0
  106. data/lib/action_dispatch/middleware/callbacks.rb +7 -6
  107. data/lib/action_dispatch/middleware/cookies.rb +471 -328
  108. data/lib/action_dispatch/middleware/debug_exceptions.rb +149 -66
  109. data/lib/action_dispatch/middleware/debug_locks.rb +129 -0
  110. data/lib/action_dispatch/middleware/debug_view.rb +73 -0
  111. data/lib/action_dispatch/middleware/exception_wrapper.rb +275 -73
  112. data/lib/action_dispatch/middleware/executor.rb +32 -0
  113. data/lib/action_dispatch/middleware/flash.rb +143 -101
  114. data/lib/action_dispatch/middleware/host_authorization.rb +171 -0
  115. data/lib/action_dispatch/middleware/public_exceptions.rb +36 -27
  116. data/lib/action_dispatch/middleware/reloader.rb +10 -92
  117. data/lib/action_dispatch/middleware/remote_ip.rb +133 -107
  118. data/lib/action_dispatch/middleware/request_id.rb +29 -15
  119. data/lib/action_dispatch/middleware/server_timing.rb +78 -0
  120. data/lib/action_dispatch/middleware/session/abstract_store.rb +49 -27
  121. data/lib/action_dispatch/middleware/session/cache_store.rb +33 -16
  122. data/lib/action_dispatch/middleware/session/cookie_store.rb +86 -80
  123. data/lib/action_dispatch/middleware/session/mem_cache_store.rb +15 -3
  124. data/lib/action_dispatch/middleware/show_exceptions.rb +66 -36
  125. data/lib/action_dispatch/middleware/ssl.rb +134 -36
  126. data/lib/action_dispatch/middleware/stack.rb +109 -44
  127. data/lib/action_dispatch/middleware/static.rb +159 -90
  128. data/lib/action_dispatch/middleware/templates/rescues/_actions.html.erb +13 -0
  129. data/lib/action_dispatch/middleware/templates/rescues/_actions.text.erb +0 -0
  130. data/lib/action_dispatch/middleware/templates/rescues/_message_and_suggestions.html.erb +22 -0
  131. data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb +7 -24
  132. data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.text.erb +1 -1
  133. data/lib/action_dispatch/middleware/templates/rescues/_source.html.erb +36 -0
  134. data/lib/action_dispatch/middleware/templates/rescues/_source.text.erb +8 -0
  135. data/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb +46 -36
  136. data/lib/action_dispatch/middleware/templates/rescues/blocked_host.html.erb +12 -0
  137. data/lib/action_dispatch/middleware/templates/rescues/blocked_host.text.erb +9 -0
  138. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb +26 -7
  139. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.text.erb +3 -3
  140. data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.html.erb +24 -0
  141. data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.text.erb +16 -0
  142. data/lib/action_dispatch/middleware/templates/rescues/layout.erb +139 -15
  143. data/lib/action_dispatch/middleware/templates/rescues/missing_exact_template.html.erb +23 -0
  144. data/lib/action_dispatch/middleware/templates/rescues/missing_exact_template.text.erb +3 -0
  145. data/lib/action_dispatch/middleware/templates/rescues/missing_template.html.erb +6 -6
  146. data/lib/action_dispatch/middleware/templates/rescues/routing_error.html.erb +7 -7
  147. data/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb +9 -9
  148. data/lib/action_dispatch/middleware/templates/rescues/template_error.text.erb +1 -1
  149. data/lib/action_dispatch/middleware/templates/rescues/unknown_action.html.erb +4 -4
  150. data/lib/action_dispatch/middleware/templates/rescues/unknown_action.text.erb +1 -1
  151. data/lib/action_dispatch/middleware/templates/routes/_route.html.erb +7 -4
  152. data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +125 -93
  153. data/lib/action_dispatch/railtie.rb +44 -16
  154. data/lib/action_dispatch/request/session.rb +159 -69
  155. data/lib/action_dispatch/request/utils.rb +97 -23
  156. data/lib/action_dispatch/routing/endpoint.rb +11 -2
  157. data/lib/action_dispatch/routing/inspector.rb +195 -106
  158. data/lib/action_dispatch/routing/mapper.rb +1338 -955
  159. data/lib/action_dispatch/routing/polymorphic_routes.rb +234 -201
  160. data/lib/action_dispatch/routing/redirection.rb +78 -51
  161. data/lib/action_dispatch/routing/route_set.rb +460 -374
  162. data/lib/action_dispatch/routing/routes_proxy.rb +36 -12
  163. data/lib/action_dispatch/routing/url_for.rb +172 -124
  164. data/lib/action_dispatch/routing.rb +159 -158
  165. data/lib/action_dispatch/system_test_case.rb +206 -0
  166. data/lib/action_dispatch/system_testing/browser.rb +84 -0
  167. data/lib/action_dispatch/system_testing/driver.rb +85 -0
  168. data/lib/action_dispatch/system_testing/server.rb +33 -0
  169. data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +164 -0
  170. data/lib/action_dispatch/system_testing/test_helpers/setup_and_teardown.rb +23 -0
  171. data/lib/action_dispatch/testing/assertion_response.rb +48 -0
  172. data/lib/action_dispatch/testing/assertions/response.rb +71 -39
  173. data/lib/action_dispatch/testing/assertions/routing.rb +228 -103
  174. data/lib/action_dispatch/testing/assertions.rb +9 -6
  175. data/lib/action_dispatch/testing/integration.rb +486 -306
  176. data/lib/action_dispatch/testing/request_encoder.rb +60 -0
  177. data/lib/action_dispatch/testing/test_helpers/page_dump_helper.rb +35 -0
  178. data/lib/action_dispatch/testing/test_process.rb +35 -22
  179. data/lib/action_dispatch/testing/test_request.rb +29 -34
  180. data/lib/action_dispatch/testing/test_response.rb +48 -15
  181. data/lib/action_dispatch.rb +82 -40
  182. data/lib/action_pack/gem_version.rb +8 -4
  183. data/lib/action_pack/version.rb +6 -2
  184. data/lib/action_pack.rb +21 -18
  185. metadata +146 -56
  186. data/lib/action_controller/caching/fragments.rb +0 -103
  187. data/lib/action_controller/metal/force_ssl.rb +0 -97
  188. data/lib/action_controller/metal/hide_actions.rb +0 -40
  189. data/lib/action_controller/metal/rack_delegation.rb +0 -32
  190. data/lib/action_controller/middleware.rb +0 -39
  191. data/lib/action_controller/model_naming.rb +0 -12
  192. data/lib/action_dispatch/http/parameter_filter.rb +0 -72
  193. data/lib/action_dispatch/journey/backwards.rb +0 -5
  194. data/lib/action_dispatch/journey/nfa/builder.rb +0 -76
  195. data/lib/action_dispatch/journey/nfa/simulator.rb +0 -47
  196. data/lib/action_dispatch/journey/nfa/transition_table.rb +0 -163
  197. data/lib/action_dispatch/journey/router/strexp.rb +0 -27
  198. data/lib/action_dispatch/middleware/params_parser.rb +0 -60
  199. data/lib/action_dispatch/middleware/templates/rescues/_source.erb +0 -27
  200. data/lib/action_dispatch/testing/assertions/dom.rb +0 -3
  201. data/lib/action_dispatch/testing/assertions/selector.rb +0 -3
  202. data/lib/action_dispatch/testing/assertions/tag.rb +0 -3
@@ -1,95 +1,136 @@
1
- require 'rack/session/abstract/id'
1
+ # frozen_string_literal: true
2
+
3
+ # :markup: markdown
4
+
5
+ require "rack/session/abstract/id"
2
6
 
3
7
  module ActionDispatch
4
- class Request < Rack::Request
8
+ class Request
5
9
  # Session is responsible for lazily loading the session from store.
6
10
  class Session # :nodoc:
7
- ENV_SESSION_KEY = Rack::Session::Abstract::ENV_SESSION_KEY # :nodoc:
8
- ENV_SESSION_OPTIONS_KEY = Rack::Session::Abstract::ENV_SESSION_OPTIONS_KEY # :nodoc:
11
+ DisabledSessionError = Class.new(StandardError)
12
+ ENV_SESSION_KEY = Rack::RACK_SESSION # :nodoc:
13
+ ENV_SESSION_OPTIONS_KEY = Rack::RACK_SESSION_OPTIONS # :nodoc:
9
14
 
10
- # Singleton object used to determine if an optional param wasn't specified
15
+ # Singleton object used to determine if an optional param wasn't specified.
11
16
  Unspecified = Object.new
12
17
 
13
- def self.create(store, env, default_options)
14
- session_was = find env
15
- session = Request::Session.new(store, env)
18
+ # Creates a session hash, merging the properties of the previous session if any.
19
+ def self.create(store, req, default_options)
20
+ session_was = find req
21
+ session = Request::Session.new(store, req)
16
22
  session.merge! session_was if session_was
17
23
 
18
- set(env, session)
19
- Options.set(env, Request::Session::Options.new(store, env, default_options))
24
+ set(req, session)
25
+ Options.set(req, Request::Session::Options.new(store, default_options))
20
26
  session
21
27
  end
22
28
 
23
- def self.find(env)
24
- env[ENV_SESSION_KEY]
29
+ def self.disabled(req)
30
+ new(nil, req, enabled: false).tap do
31
+ Session::Options.set(req, Session::Options.new(nil, { id: nil }))
32
+ end
33
+ end
34
+
35
+ def self.find(req)
36
+ req.get_header ENV_SESSION_KEY
37
+ end
38
+
39
+ def self.set(req, session)
40
+ req.set_header ENV_SESSION_KEY, session
25
41
  end
26
42
 
27
- def self.set(env, session)
28
- env[ENV_SESSION_KEY] = session
43
+ def self.delete(req)
44
+ req.delete_header ENV_SESSION_KEY
29
45
  end
30
46
 
31
- class Options #:nodoc:
32
- def self.set(env, options)
33
- env[ENV_SESSION_OPTIONS_KEY] = options
47
+ class Options # :nodoc:
48
+ def self.set(req, options)
49
+ req.set_header ENV_SESSION_OPTIONS_KEY, options
34
50
  end
35
51
 
36
- def self.find(env)
37
- env[ENV_SESSION_OPTIONS_KEY]
52
+ def self.find(req)
53
+ req.get_header ENV_SESSION_OPTIONS_KEY
38
54
  end
39
55
 
40
- def initialize(by, env, default_options)
56
+ def initialize(by, default_options)
41
57
  @by = by
42
- @env = env
43
58
  @delegate = default_options.dup
44
59
  end
45
60
 
46
61
  def [](key)
47
- if key == :id
48
- @delegate.fetch(key) {
49
- @delegate[:id] = @by.send(:extract_session_id, @env)
50
- }
51
- else
52
- @delegate[key]
53
- end
62
+ @delegate[key]
54
63
  end
55
64
 
56
- def []=(k,v); @delegate[k] = v; end
65
+ def id(req)
66
+ @delegate.fetch(:id) {
67
+ @by.send(:extract_session_id, req)
68
+ }
69
+ end
70
+
71
+ def []=(k, v); @delegate[k] = v; end
57
72
  def to_hash; @delegate.dup; end
58
73
  def values_at(*args); @delegate.values_at(*args); end
59
74
  end
60
75
 
61
- def initialize(by, env)
76
+ def initialize(by, req, enabled: true)
62
77
  @by = by
63
- @env = env
78
+ @req = req
64
79
  @delegate = {}
65
80
  @loaded = false
66
- @exists = nil # we haven't checked yet
81
+ @exists = nil # We haven't checked yet.
82
+ @enabled = enabled
83
+ @id_was = nil
84
+ @id_was_initialized = false
67
85
  end
68
86
 
69
87
  def id
70
- options[:id]
88
+ options.id(@req)
89
+ end
90
+
91
+ def enabled?
92
+ @enabled
71
93
  end
72
94
 
73
95
  def options
74
- Options.find @env
96
+ Options.find @req
75
97
  end
76
98
 
77
99
  def destroy
78
100
  clear
79
- options = self.options || {}
80
- new_sid = @by.send(:destroy_session, @env, options[:id], options)
81
- options[:id] = new_sid # Reset session id with a new value or nil
82
101
 
83
- # Load the new sid to be written with the response
84
- @loaded = false
85
- load_for_write!
102
+ if enabled?
103
+ options = self.options || {}
104
+ @by.send(:delete_session, @req, options.id(@req), options)
105
+
106
+ # Load the new sid to be written with the response.
107
+ @loaded = false
108
+ load_for_write!
109
+ end
86
110
  end
87
111
 
112
+ # Returns value of the key stored in the session or `nil` if the given key is
113
+ # not found in the session.
88
114
  def [](key)
89
115
  load_for_read!
90
- @delegate[key.to_s]
116
+ key = key.to_s
117
+
118
+ if key == "session_id"
119
+ id&.public_id
120
+ else
121
+ @delegate[key]
122
+ end
91
123
  end
92
124
 
125
+ # Returns the nested value specified by the sequence of keys, returning `nil` if
126
+ # any intermediate step is `nil`.
127
+ def dig(*keys)
128
+ load_for_read!
129
+ keys = keys.map.with_index { |key, i| i.zero? ? key.to_s : key }
130
+ @delegate.dig(*keys)
131
+ end
132
+
133
+ # Returns true if the session has the given key or false.
93
134
  def has_key?(key)
94
135
  load_for_read!
95
136
  @delegate.key?(key.to_s)
@@ -97,40 +138,78 @@ module ActionDispatch
97
138
  alias :key? :has_key?
98
139
  alias :include? :has_key?
99
140
 
141
+ # Returns keys of the session as Array.
100
142
  def keys
143
+ load_for_read!
101
144
  @delegate.keys
102
145
  end
103
146
 
147
+ # Returns values of the session as Array.
104
148
  def values
149
+ load_for_read!
105
150
  @delegate.values
106
151
  end
107
152
 
153
+ # Writes given value to given key of the session.
108
154
  def []=(key, value)
109
155
  load_for_write!
110
156
  @delegate[key.to_s] = value
111
157
  end
112
158
 
159
+ # Clears the session.
113
160
  def clear
114
- load_for_write!
161
+ load_for_delete!
115
162
  @delegate.clear
116
163
  end
117
164
 
165
+ # Returns the session as Hash.
118
166
  def to_hash
119
167
  load_for_read!
120
- @delegate.dup.delete_if { |_,v| v.nil? }
168
+ @delegate.dup.delete_if { |_, v| v.nil? }
121
169
  end
122
-
170
+ alias :to_h :to_hash
171
+
172
+ # Updates the session with given Hash.
173
+ #
174
+ # session.to_hash
175
+ # # => {"session_id"=>"e29b9ea315edf98aad94cc78c34cc9b2"}
176
+ #
177
+ # session.update({ "foo" => "bar" })
178
+ # # => {"session_id"=>"e29b9ea315edf98aad94cc78c34cc9b2", "foo" => "bar"}
179
+ #
180
+ # session.to_hash
181
+ # # => {"session_id"=>"e29b9ea315edf98aad94cc78c34cc9b2", "foo" => "bar"}
123
182
  def update(hash)
183
+ unless hash.respond_to?(:to_hash)
184
+ raise TypeError, "no implicit conversion of #{hash.class.name} into Hash"
185
+ end
186
+
124
187
  load_for_write!
125
- @delegate.update stringify_keys(hash)
188
+ @delegate.update hash.to_hash.stringify_keys
126
189
  end
190
+ alias :merge! :update
127
191
 
192
+ # Deletes given key from the session.
128
193
  def delete(key)
129
- load_for_write!
194
+ load_for_delete!
130
195
  @delegate.delete key.to_s
131
196
  end
132
197
 
133
- def fetch(key, default=Unspecified, &block)
198
+ # Returns value of the given key from the session, or raises `KeyError` if can't
199
+ # find the given key and no default value is set. Returns default value if
200
+ # specified.
201
+ #
202
+ # session.fetch(:foo)
203
+ # # => KeyError: key not found: "foo"
204
+ #
205
+ # session.fetch(:foo, :bar)
206
+ # # => :bar
207
+ #
208
+ # session.fetch(:foo) do
209
+ # :bar
210
+ # end
211
+ # # => :bar
212
+ def fetch(key, default = Unspecified, &block)
134
213
  load_for_read!
135
214
  if default == Unspecified
136
215
  @delegate.fetch(key.to_s, &block)
@@ -148,8 +227,9 @@ module ActionDispatch
148
227
  end
149
228
 
150
229
  def exists?
230
+ return false unless enabled?
151
231
  return @exists unless @exists.nil?
152
- @exists = @by.send(:session_exists?, @env)
232
+ @exists = @by.send(:session_exists?, @req)
153
233
  end
154
234
 
155
235
  def loaded?
@@ -161,33 +241,43 @@ module ActionDispatch
161
241
  @delegate.empty?
162
242
  end
163
243
 
164
- def merge!(other)
165
- load_for_write!
166
- @delegate.merge!(other)
244
+ def each(&block)
245
+ to_hash.each(&block)
167
246
  end
168
247
 
169
- private
170
-
171
- def load_for_read!
172
- load! if !loaded? && exists?
248
+ def id_was
249
+ load_for_read!
250
+ @id_was
173
251
  end
174
252
 
175
- def load_for_write!
176
- load! unless loaded?
177
- end
253
+ private
254
+ def load_for_read!
255
+ load! if !loaded? && exists?
256
+ end
178
257
 
179
- def load!
180
- id, session = @by.load_session @env
181
- options[:id] = id
182
- @delegate.replace(stringify_keys(session))
183
- @loaded = true
184
- end
258
+ def load_for_write!
259
+ if enabled?
260
+ load! unless loaded?
261
+ else
262
+ raise DisabledSessionError, "Your application has sessions disabled. To write to the session you must first configure a session store"
263
+ end
264
+ end
185
265
 
186
- def stringify_keys(other)
187
- other.each_with_object({}) { |(key, value), hash|
188
- hash[key.to_s] = value
189
- }
190
- end
266
+ def load_for_delete!
267
+ load! if enabled? && !loaded?
268
+ end
269
+
270
+ def load!
271
+ if enabled?
272
+ @id_was_initialized = true unless exists?
273
+ id, session = @by.load_session @req
274
+ options[:id] = id
275
+ @delegate.replace(session.stringify_keys)
276
+ @id_was = id unless @id_was_initialized
277
+ end
278
+ @id_was_initialized = true
279
+ @loaded = true
280
+ end
191
281
  end
192
282
  end
193
283
  end
@@ -1,35 +1,109 @@
1
+ # frozen_string_literal: true
2
+
3
+ # :markup: markdown
4
+
5
+ require "active_support/core_ext/hash/indifferent_access"
6
+
1
7
  module ActionDispatch
2
- class Request < Rack::Request
8
+ class Request
3
9
  class Utils # :nodoc:
10
+ mattr_accessor :perform_deep_munge, default: true
11
+
12
+ def self.each_param_value(params, &block)
13
+ case params
14
+ when Array
15
+ params.each { |element| each_param_value(element, &block) }
16
+ when Hash
17
+ params.each_value { |value| each_param_value(value, &block) }
18
+ when String
19
+ block.call params
20
+ end
21
+ end
22
+
23
+ def self.normalize_encode_params(params)
24
+ if perform_deep_munge
25
+ NoNilParamEncoder.normalize_encode_params params
26
+ else
27
+ ParamEncoder.normalize_encode_params params
28
+ end
29
+ end
30
+
31
+ def self.check_param_encoding(params)
32
+ case params
33
+ when Array
34
+ params.each { |element| check_param_encoding(element) }
35
+ when Hash
36
+ params.each_value { |value| check_param_encoding(value) }
37
+ when String
38
+ unless params.valid_encoding?
39
+ # Raise Rack::Utils::InvalidParameterError for consistency with Rack.
40
+ # ActionDispatch::Request#GET will re-raise as a BadRequest error.
41
+ raise Rack::Utils::InvalidParameterError, "Invalid encoding for parameter: #{params.scrub}"
42
+ end
43
+ end
44
+ end
45
+
46
+ def self.set_binary_encoding(request, params, controller, action)
47
+ CustomParamEncoder.encode(request, params, controller, action)
48
+ end
4
49
 
5
- mattr_accessor :perform_deep_munge
6
- self.perform_deep_munge = true
7
-
8
- class << self
9
- # Remove nils from the params hash
10
- def deep_munge(hash, keys = [])
11
- return hash unless perform_deep_munge
12
-
13
- hash.each do |k, v|
14
- keys << k
15
- case v
16
- when Array
17
- v.grep(Hash) { |x| deep_munge(x, keys) }
18
- v.compact!
19
- if v.empty?
20
- hash[k] = nil
21
- ActiveSupport::Notifications.instrument("deep_munge.action_controller", keys: keys)
50
+ class ParamEncoder # :nodoc:
51
+ # Convert nested Hash to HashWithIndifferentAccess.
52
+ def self.normalize_encode_params(params)
53
+ case params
54
+ when Array
55
+ handle_array params
56
+ when Hash
57
+ if params.has_key?(:tempfile)
58
+ ActionDispatch::Http::UploadedFile.new(params)
59
+ else
60
+ hwia = ActiveSupport::HashWithIndifferentAccess.new
61
+ params.each_pair do |key, val|
62
+ hwia[key] = normalize_encode_params(val)
22
63
  end
23
- when Hash
24
- deep_munge(v, keys)
64
+ hwia
25
65
  end
26
- keys.pop
66
+ else
67
+ params
27
68
  end
69
+ end
70
+
71
+ def self.handle_array(params)
72
+ params.map! { |el| normalize_encode_params(el) }
73
+ end
74
+ end
75
+
76
+ # Remove nils from the params hash.
77
+ class NoNilParamEncoder < ParamEncoder # :nodoc:
78
+ def self.handle_array(params)
79
+ list = super
80
+ list.compact!
81
+ list
82
+ end
83
+ end
28
84
 
29
- hash
85
+ class CustomParamEncoder # :nodoc:
86
+ def self.encode(request, params, controller, action)
87
+ return params unless controller && controller.valid_encoding? && encoding_template = action_encoding_template(request, controller, action)
88
+ params.except(:controller, :action).each do |key, value|
89
+ ActionDispatch::Request::Utils.each_param_value(value) do |param|
90
+ # If `param` is frozen, it comes from the router defaults
91
+ next if param.frozen?
92
+
93
+ if encoding_template[key.to_s]
94
+ param.force_encoding(encoding_template[key.to_s])
95
+ end
96
+ end
97
+ end
98
+ params
99
+ end
100
+
101
+ def self.action_encoding_template(request, controller, action) # :nodoc:
102
+ request.controller_class_for(controller).action_encoding_template(action)
103
+ rescue MissingController
104
+ nil
30
105
  end
31
106
  end
32
107
  end
33
108
  end
34
109
  end
35
-
@@ -1,10 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ # :markup: markdown
4
+
1
5
  module ActionDispatch
2
6
  module Routing
3
7
  class Endpoint # :nodoc:
4
8
  def dispatcher?; false; end
5
9
  def redirect?; false; end
6
- def matches?(req); true; end
7
- def app; self; end
10
+ def matches?(req); true; end
11
+ def app; self; end
12
+ def rack_app; app; end
13
+
14
+ def engine?
15
+ rack_app.is_a?(Class) && rack_app < Rails::Engine
16
+ end
8
17
  end
9
18
  end
10
19
  end