actionpack 7.1.3 → 7.2.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (158) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +82 -501
  3. data/lib/abstract_controller/asset_paths.rb +2 -0
  4. data/lib/abstract_controller/base.rb +102 -98
  5. data/lib/abstract_controller/caching/fragments.rb +50 -53
  6. data/lib/abstract_controller/caching.rb +2 -0
  7. data/lib/abstract_controller/callbacks.rb +66 -64
  8. data/lib/abstract_controller/collector.rb +6 -6
  9. data/lib/abstract_controller/deprecator.rb +2 -0
  10. data/lib/abstract_controller/error.rb +2 -0
  11. data/lib/abstract_controller/helpers.rb +70 -85
  12. data/lib/abstract_controller/logger.rb +2 -0
  13. data/lib/abstract_controller/railties/routes_helpers.rb +2 -0
  14. data/lib/abstract_controller/rendering.rb +13 -12
  15. data/lib/abstract_controller/translation.rb +15 -7
  16. data/lib/abstract_controller/url_for.rb +8 -6
  17. data/lib/abstract_controller.rb +2 -0
  18. data/lib/action_controller/api/api_rendering.rb +2 -0
  19. data/lib/action_controller/api.rb +74 -72
  20. data/lib/action_controller/base.rb +198 -126
  21. data/lib/action_controller/caching.rb +15 -12
  22. data/lib/action_controller/deprecator.rb +2 -0
  23. data/lib/action_controller/form_builder.rb +20 -17
  24. data/lib/action_controller/log_subscriber.rb +3 -1
  25. data/lib/action_controller/metal/allow_browser.rb +123 -0
  26. data/lib/action_controller/metal/basic_implicit_render.rb +2 -0
  27. data/lib/action_controller/metal/conditional_get.rb +188 -174
  28. data/lib/action_controller/metal/content_security_policy.rb +25 -24
  29. data/lib/action_controller/metal/cookies.rb +4 -2
  30. data/lib/action_controller/metal/data_streaming.rb +64 -55
  31. data/lib/action_controller/metal/default_headers.rb +5 -3
  32. data/lib/action_controller/metal/etag_with_flash.rb +3 -1
  33. data/lib/action_controller/metal/etag_with_template_digest.rb +17 -15
  34. data/lib/action_controller/metal/exceptions.rb +11 -9
  35. data/lib/action_controller/metal/flash.rb +12 -10
  36. data/lib/action_controller/metal/head.rb +12 -10
  37. data/lib/action_controller/metal/helpers.rb +63 -55
  38. data/lib/action_controller/metal/http_authentication.rb +210 -205
  39. data/lib/action_controller/metal/implicit_render.rb +17 -15
  40. data/lib/action_controller/metal/instrumentation.rb +15 -12
  41. data/lib/action_controller/metal/live.rb +113 -107
  42. data/lib/action_controller/metal/logging.rb +6 -4
  43. data/lib/action_controller/metal/mime_responds.rb +151 -142
  44. data/lib/action_controller/metal/parameter_encoding.rb +34 -32
  45. data/lib/action_controller/metal/params_wrapper.rb +57 -59
  46. data/lib/action_controller/metal/permissions_policy.rb +13 -12
  47. data/lib/action_controller/metal/rate_limiting.rb +62 -0
  48. data/lib/action_controller/metal/redirecting.rb +108 -82
  49. data/lib/action_controller/metal/renderers.rb +50 -49
  50. data/lib/action_controller/metal/rendering.rb +103 -75
  51. data/lib/action_controller/metal/request_forgery_protection.rb +162 -133
  52. data/lib/action_controller/metal/rescue.rb +11 -9
  53. data/lib/action_controller/metal/streaming.rb +138 -136
  54. data/lib/action_controller/metal/strong_parameters.rb +525 -480
  55. data/lib/action_controller/metal/testing.rb +2 -0
  56. data/lib/action_controller/metal/url_for.rb +17 -15
  57. data/lib/action_controller/metal.rb +86 -60
  58. data/lib/action_controller/railtie.rb +3 -0
  59. data/lib/action_controller/railties/helpers.rb +2 -0
  60. data/lib/action_controller/renderer.rb +42 -36
  61. data/lib/action_controller/template_assertions.rb +4 -2
  62. data/lib/action_controller/test_case.rb +146 -126
  63. data/lib/action_controller.rb +10 -3
  64. data/lib/action_dispatch/constants.rb +2 -0
  65. data/lib/action_dispatch/deprecator.rb +2 -0
  66. data/lib/action_dispatch/http/cache.rb +27 -26
  67. data/lib/action_dispatch/http/content_disposition.rb +2 -0
  68. data/lib/action_dispatch/http/content_security_policy.rb +44 -38
  69. data/lib/action_dispatch/http/filter_parameters.rb +18 -9
  70. data/lib/action_dispatch/http/filter_redirect.rb +22 -1
  71. data/lib/action_dispatch/http/headers.rb +22 -22
  72. data/lib/action_dispatch/http/mime_negotiation.rb +30 -41
  73. data/lib/action_dispatch/http/mime_type.rb +31 -24
  74. data/lib/action_dispatch/http/mime_types.rb +2 -0
  75. data/lib/action_dispatch/http/parameters.rb +11 -9
  76. data/lib/action_dispatch/http/permissions_policy.rb +20 -44
  77. data/lib/action_dispatch/http/rack_cache.rb +2 -0
  78. data/lib/action_dispatch/http/request.rb +94 -75
  79. data/lib/action_dispatch/http/response.rb +73 -61
  80. data/lib/action_dispatch/http/upload.rb +18 -16
  81. data/lib/action_dispatch/http/url.rb +75 -73
  82. data/lib/action_dispatch/journey/formatter.rb +13 -6
  83. data/lib/action_dispatch/journey/gtg/builder.rb +4 -3
  84. data/lib/action_dispatch/journey/gtg/simulator.rb +2 -0
  85. data/lib/action_dispatch/journey/gtg/transition_table.rb +10 -8
  86. data/lib/action_dispatch/journey/nfa/dot.rb +2 -0
  87. data/lib/action_dispatch/journey/nodes/node.rb +6 -5
  88. data/lib/action_dispatch/journey/parser.rb +4 -3
  89. data/lib/action_dispatch/journey/parser_extras.rb +2 -0
  90. data/lib/action_dispatch/journey/path/pattern.rb +4 -1
  91. data/lib/action_dispatch/journey/route.rb +9 -7
  92. data/lib/action_dispatch/journey/router/utils.rb +16 -15
  93. data/lib/action_dispatch/journey/router.rb +4 -2
  94. data/lib/action_dispatch/journey/routes.rb +4 -2
  95. data/lib/action_dispatch/journey/scanner.rb +4 -2
  96. data/lib/action_dispatch/journey/visitors.rb +2 -0
  97. data/lib/action_dispatch/journey.rb +2 -0
  98. data/lib/action_dispatch/log_subscriber.rb +2 -0
  99. data/lib/action_dispatch/middleware/actionable_exceptions.rb +2 -0
  100. data/lib/action_dispatch/middleware/assume_ssl.rb +8 -5
  101. data/lib/action_dispatch/middleware/callbacks.rb +3 -1
  102. data/lib/action_dispatch/middleware/cookies.rb +119 -104
  103. data/lib/action_dispatch/middleware/debug_exceptions.rb +13 -5
  104. data/lib/action_dispatch/middleware/debug_locks.rb +15 -13
  105. data/lib/action_dispatch/middleware/debug_view.rb +2 -0
  106. data/lib/action_dispatch/middleware/exception_wrapper.rb +6 -11
  107. data/lib/action_dispatch/middleware/executor.rb +8 -0
  108. data/lib/action_dispatch/middleware/flash.rb +63 -51
  109. data/lib/action_dispatch/middleware/host_authorization.rb +17 -15
  110. data/lib/action_dispatch/middleware/public_exceptions.rb +8 -6
  111. data/lib/action_dispatch/middleware/reloader.rb +5 -3
  112. data/lib/action_dispatch/middleware/remote_ip.rb +77 -72
  113. data/lib/action_dispatch/middleware/request_id.rb +14 -9
  114. data/lib/action_dispatch/middleware/server_timing.rb +4 -2
  115. data/lib/action_dispatch/middleware/session/abstract_store.rb +2 -0
  116. data/lib/action_dispatch/middleware/session/cache_store.rb +13 -8
  117. data/lib/action_dispatch/middleware/session/cookie_store.rb +27 -26
  118. data/lib/action_dispatch/middleware/session/mem_cache_store.rb +7 -3
  119. data/lib/action_dispatch/middleware/show_exceptions.rb +31 -21
  120. data/lib/action_dispatch/middleware/ssl.rb +43 -40
  121. data/lib/action_dispatch/middleware/stack.rb +11 -10
  122. data/lib/action_dispatch/middleware/static.rb +33 -31
  123. data/lib/action_dispatch/middleware/templates/rescues/_source.html.erb +1 -1
  124. data/lib/action_dispatch/middleware/templates/rescues/missing_exact_template.html.erb +1 -1
  125. data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +1 -1
  126. data/lib/action_dispatch/railtie.rb +2 -4
  127. data/lib/action_dispatch/request/session.rb +23 -21
  128. data/lib/action_dispatch/request/utils.rb +2 -0
  129. data/lib/action_dispatch/routing/endpoint.rb +2 -0
  130. data/lib/action_dispatch/routing/inspector.rb +5 -3
  131. data/lib/action_dispatch/routing/mapper.rb +671 -636
  132. data/lib/action_dispatch/routing/polymorphic_routes.rb +69 -62
  133. data/lib/action_dispatch/routing/redirection.rb +37 -32
  134. data/lib/action_dispatch/routing/route_set.rb +59 -45
  135. data/lib/action_dispatch/routing/routes_proxy.rb +6 -4
  136. data/lib/action_dispatch/routing/url_for.rb +130 -125
  137. data/lib/action_dispatch/routing.rb +150 -148
  138. data/lib/action_dispatch/system_test_case.rb +91 -81
  139. data/lib/action_dispatch/system_testing/browser.rb +10 -3
  140. data/lib/action_dispatch/system_testing/driver.rb +3 -1
  141. data/lib/action_dispatch/system_testing/server.rb +2 -0
  142. data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +32 -21
  143. data/lib/action_dispatch/system_testing/test_helpers/setup_and_teardown.rb +2 -0
  144. data/lib/action_dispatch/testing/assertion_response.rb +8 -6
  145. data/lib/action_dispatch/testing/assertions/response.rb +26 -23
  146. data/lib/action_dispatch/testing/assertions/routing.rb +153 -84
  147. data/lib/action_dispatch/testing/assertions.rb +2 -0
  148. data/lib/action_dispatch/testing/integration.rb +223 -222
  149. data/lib/action_dispatch/testing/request_encoder.rb +2 -0
  150. data/lib/action_dispatch/testing/test_helpers/page_dump_helper.rb +35 -0
  151. data/lib/action_dispatch/testing/test_process.rb +12 -8
  152. data/lib/action_dispatch/testing/test_request.rb +3 -1
  153. data/lib/action_dispatch/testing/test_response.rb +27 -26
  154. data/lib/action_dispatch.rb +22 -28
  155. data/lib/action_pack/gem_version.rb +6 -4
  156. data/lib/action_pack/version.rb +3 -1
  157. data/lib/action_pack.rb +17 -16
  158. metadata +39 -16
@@ -1,41 +1,48 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # :markup: markdown
4
+
3
5
  require "active_support/core_ext/hash/keys"
4
6
 
5
7
  module ActionDispatch
6
- # = Action Dispatch \Flash
8
+ # # Action Dispatch Flash
7
9
  #
8
- # The flash provides a way to pass temporary primitive-types (String, Array, Hash) between actions. Anything you place in the flash will be exposed
9
- # to the very next action and then cleared out. This is a great way of doing notices and alerts, such as a create
10
- # action that sets <tt>flash[:notice] = "Post successfully created"</tt> before redirecting to a display action that can
11
- # then expose the flash to its template. Actually, that exposure is automatically done.
10
+ # The flash provides a way to pass temporary primitive-types (String, Array,
11
+ # Hash) between actions. Anything you place in the flash will be exposed to the
12
+ # very next action and then cleared out. This is a great way of doing notices
13
+ # and alerts, such as a create action that sets `flash[:notice] = "Post
14
+ # successfully created"` before redirecting to a display action that can then
15
+ # expose the flash to its template. Actually, that exposure is automatically
16
+ # done.
12
17
  #
13
- # class PostsController < ActionController::Base
14
- # def create
15
- # # save post
16
- # flash[:notice] = "Post successfully created"
17
- # redirect_to @post
18
- # end
18
+ # class PostsController < ActionController::Base
19
+ # def create
20
+ # # save post
21
+ # flash[:notice] = "Post successfully created"
22
+ # redirect_to @post
23
+ # end
19
24
  #
20
- # def show
21
- # # doesn't need to assign the flash notice to the template, that's done automatically
25
+ # def show
26
+ # # doesn't need to assign the flash notice to the template, that's done automatically
27
+ # end
22
28
  # end
23
- # end
24
29
  #
25
- # Then in +show.html.erb+:
30
+ # Then in `show.html.erb`:
26
31
  #
27
- # <% if flash[:notice] %>
28
- # <div class="notice"><%= flash[:notice] %></div>
29
- # <% end %>
32
+ # <% if flash[:notice] %>
33
+ # <div class="notice"><%= flash[:notice] %></div>
34
+ # <% end %>
30
35
  #
31
- # Since the +notice+ and +alert+ keys are a common idiom, convenience accessors are available:
36
+ # Since the `notice` and `alert` keys are a common idiom, convenience accessors
37
+ # are available:
32
38
  #
33
- # flash.alert = "You must be logged in"
34
- # flash.notice = "Post successfully created"
39
+ # flash.alert = "You must be logged in"
40
+ # flash.notice = "Post successfully created"
35
41
  #
36
- # This example places a string in the flash. And of course, you can put as many as you like at a time too. If you want to pass
37
- # non-primitive types, you will have to handle that in your application. Example: To show messages with links, you will have to
38
- # use sanitize helper.
42
+ # This example places a string in the flash. And of course, you can put as many
43
+ # as you like at a time too. If you want to pass non-primitive types, you will
44
+ # have to handle that in your application. Example: To show messages with links,
45
+ # you will have to use sanitize helper.
39
46
  #
40
47
  # Just remember: They'll be gone by the time the next action has been performed.
41
48
  #
@@ -98,12 +105,12 @@ module ActionDispatch
98
105
  @flash[k.to_s]
99
106
  end
100
107
 
101
- # Convenience accessor for <tt>flash.now[:alert]=</tt>.
108
+ # Convenience accessor for `flash.now[:alert]=`.
102
109
  def alert=(message)
103
110
  self[:alert] = message
104
111
  end
105
112
 
106
- # Convenience accessor for <tt>flash.now[:notice]=</tt>.
113
+ # Convenience accessor for `flash.now[:notice]=`.
107
114
  def notice=(message)
108
115
  self[:notice] = message
109
116
  end
@@ -131,8 +138,8 @@ module ActionDispatch
131
138
  end
132
139
  end
133
140
 
134
- # Builds a hash containing the flashes to keep for the next request.
135
- # If there are none to keep, returns +nil+.
141
+ # Builds a hash containing the flashes to keep for the next request. If there
142
+ # are none to keep, returns `nil`.
136
143
  def to_session_value # :nodoc:
137
144
  flashes_to_keep = @flashes.except(*@discard)
138
145
  return nil if flashes_to_keep.empty?
@@ -177,8 +184,8 @@ module ActionDispatch
177
184
  @flashes.key? name.to_s
178
185
  end
179
186
 
180
- # Immediately deletes the single flash entry. Use this method when you
181
- # want remove the message within the current action. See also #discard.
187
+ # Immediately deletes the single flash entry. Use this method when you want
188
+ # remove the message within the current action. See also #discard.
182
189
  def delete(key)
183
190
  key = key.to_s
184
191
  @discard.delete key
@@ -211,45 +218,49 @@ module ActionDispatch
211
218
  self
212
219
  end
213
220
 
214
- # Sets a flash that will not be available to the next action, only to the current.
221
+ # Sets a flash that will not be available to the next action, only to the
222
+ # current.
215
223
  #
216
224
  # flash.now[:message] = "Hello current action"
217
225
  #
218
- # This method enables you to use the flash as a central messaging system in your app.
219
- # When you need to pass an object to the next action, you use the standard flash assign (<tt>[]=</tt>).
220
- # When you need to pass an object to the current action, you use <tt>now</tt>, and your object will
221
- # vanish when the current action is done.
226
+ # This method enables you to use the flash as a central messaging system in your
227
+ # app. When you need to pass an object to the next action, you use the standard
228
+ # flash assign (`[]=`). When you need to pass an object to the current action,
229
+ # you use `now`, and your object will vanish when the current action is done.
222
230
  #
223
- # Entries set via <tt>now</tt> are accessed the same way as standard entries: <tt>flash['my-key']</tt>.
231
+ # Entries set via `now` are accessed the same way as standard entries:
232
+ # `flash['my-key']`.
224
233
  #
225
234
  # Also, brings two convenience accessors:
226
235
  #
227
- # flash.now.alert = "Beware now!"
228
- # # Equivalent to flash.now[:alert] = "Beware now!"
236
+ # flash.now.alert = "Beware now!"
237
+ # # Equivalent to flash.now[:alert] = "Beware now!"
229
238
  #
230
- # flash.now.notice = "Good luck now!"
231
- # # Equivalent to flash.now[:notice] = "Good luck now!"
239
+ # flash.now.notice = "Good luck now!"
240
+ # # Equivalent to flash.now[:notice] = "Good luck now!"
232
241
  def now
233
242
  @now ||= FlashNow.new(self)
234
243
  end
235
244
 
236
- # Keeps either the entire current flash or a specific flash entry available for the next action:
245
+ # Keeps either the entire current flash or a specific flash entry available for
246
+ # the next action:
237
247
  #
238
- # flash.keep # keeps the entire flash
239
- # flash.keep(:notice) # keeps only the "notice" entry, the rest of the flash is discarded
248
+ # flash.keep # keeps the entire flash
249
+ # flash.keep(:notice) # keeps only the "notice" entry, the rest of the flash is discarded
240
250
  def keep(k = nil)
241
251
  k = k.to_s if k
242
252
  @discard.subtract Array(k || keys)
243
253
  k ? self[k] : self
244
254
  end
245
255
 
246
- # Marks the entire flash or a single flash entry to be discarded by the end of the current action:
256
+ # Marks the entire flash or a single flash entry to be discarded by the end of
257
+ # the current action:
247
258
  #
248
259
  # flash.discard # discard the entire flash at the end of the current action
249
260
  # flash.discard(:warning) # discard only the "warning" entry at the end of the current action
250
261
  #
251
- # Use this method when you want to display the message in the current
252
- # action but not in the next one. See also #delete.
262
+ # Use this method when you want to display the message in the current action but
263
+ # not in the next one. See also #delete.
253
264
  def discard(k = nil)
254
265
  k = k.to_s if k
255
266
  @discard.merge Array(k || keys)
@@ -258,28 +269,29 @@ module ActionDispatch
258
269
 
259
270
  # Mark for removal entries that were kept, and delete unkept ones.
260
271
  #
261
- # This method is called automatically by filters, so you generally don't need to care about it.
272
+ # This method is called automatically by filters, so you generally don't need to
273
+ # care about it.
262
274
  def sweep # :nodoc:
263
275
  @discard.each { |k| @flashes.delete k }
264
276
  @discard.replace @flashes.keys
265
277
  end
266
278
 
267
- # Convenience accessor for <tt>flash[:alert]</tt>.
279
+ # Convenience accessor for `flash[:alert]`.
268
280
  def alert
269
281
  self[:alert]
270
282
  end
271
283
 
272
- # Convenience accessor for <tt>flash[:alert]=</tt>.
284
+ # Convenience accessor for `flash[:alert]=`.
273
285
  def alert=(message)
274
286
  self[:alert] = message
275
287
  end
276
288
 
277
- # Convenience accessor for <tt>flash[:notice]</tt>.
289
+ # Convenience accessor for `flash[:notice]`.
278
290
  def notice
279
291
  self[:notice]
280
292
  end
281
293
 
282
- # Convenience accessor for <tt>flash[:notice]=</tt>.
294
+ # Convenience accessor for `flash[:notice]=`.
283
295
  def notice=(message)
284
296
  self[:notice] = message
285
297
  end
@@ -1,24 +1,26 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # :markup: markdown
4
+
3
5
  module ActionDispatch
4
- # = Action Dispatch \HostAuthorization
6
+ # # Action Dispatch HostAuthorization
5
7
  #
6
- # This middleware guards from DNS rebinding attacks by explicitly permitting
7
- # the hosts a request can be sent to, and is passed the options set in
8
- # +config.host_authorization+.
8
+ # This middleware guards from DNS rebinding attacks by explicitly permitting the
9
+ # hosts a request can be sent to, and is passed the options set in
10
+ # `config.host_authorization`.
9
11
  #
10
- # Requests can opt-out of Host Authorization with +exclude+:
12
+ # Requests can opt-out of Host Authorization with `exclude`:
11
13
  #
12
- # config.host_authorization = { exclude: ->(request) { request.path =~ /healthcheck/ } }
14
+ # config.host_authorization = { exclude: ->(request) { request.path =~ /healthcheck/ } }
13
15
  #
14
- # When a request comes to an unauthorized host, the +response_app+
15
- # application will be executed and rendered. If no +response_app+ is given, a
16
- # default one will run.
17
- # The default response app logs blocked host info with level 'error' and
18
- # responds with <tt>403 Forbidden</tt>. The body of the response contains debug info
19
- # if +config.consider_all_requests_local+ is set to true, otherwise the body is empty.
16
+ # When a request comes to an unauthorized host, the `response_app` application
17
+ # will be executed and rendered. If no `response_app` is given, a default one
18
+ # will run. The default response app logs blocked host info with level 'error'
19
+ # and responds with `403 Forbidden`. The body of the response contains debug
20
+ # info if `config.consider_all_requests_local` is set to true, otherwise the
21
+ # body is empty.
20
22
  class HostAuthorization
21
- ALLOWED_HOSTS_IN_DEVELOPMENT = [".localhost", IPAddr.new("0.0.0.0/0"), IPAddr.new("::/0")]
23
+ ALLOWED_HOSTS_IN_DEVELOPMENT = [".localhost", ".test", IPAddr.new("0.0.0.0/0"), IPAddr.new("::/0")]
22
24
  PORT_REGEX = /(?::\d+)/ # :nodoc:
23
25
  SUBDOMAIN_REGEX = /(?:[a-z0-9-]+\.)/i # :nodoc:
24
26
  IPV4_HOSTNAME = /(?<host>\d+\.\d+\.\d+\.\d+)#{PORT_REGEX}?/ # :nodoc:
@@ -45,8 +47,8 @@ module ActionDispatch
45
47
  begin
46
48
  allowed === extract_hostname(host)
47
49
  rescue
48
- # IPAddr#=== raises an error if you give it a hostname instead of
49
- # IP. Treat similar errors as blocked access.
50
+ # IPAddr#=== raises an error if you give it a hostname instead of IP. Treat
51
+ # similar errors as blocked access.
50
52
  false
51
53
  end
52
54
  else
@@ -1,15 +1,17 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # :markup: markdown
4
+
3
5
  module ActionDispatch
4
- # = Action Dispatch \PublicExceptions
6
+ # # Action Dispatch PublicExceptions
5
7
  #
6
8
  # When called, this middleware renders an error page. By default if an HTML
7
- # response is expected it will render static error pages from the <tt>/public</tt>
9
+ # response is expected it will render static error pages from the `/public`
8
10
  # directory. For example when this middleware receives a 500 response it will
9
- # render the template found in <tt>/public/500.html</tt>.
10
- # If an internationalized locale is set, this middleware will attempt to render
11
- # the template in <tt>/public/500.<locale>.html</tt>. If an internationalized template
12
- # is not found it will fall back on <tt>/public/500.html</tt>.
11
+ # render the template found in `/public/500.html`. If an internationalized
12
+ # locale is set, this middleware will attempt to render the template in
13
+ # `/public/500.<locale>.html`. If an internationalized template is not found it
14
+ # will fall back on `/public/500.html`.
13
15
  #
14
16
  # When a request with a content type other than HTML is made, this middleware
15
17
  # will attempt to convert error information into the appropriate response type.
@@ -1,14 +1,16 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # :markup: markdown
4
+
3
5
  module ActionDispatch
4
- # = Action Dispatch \Reloader
6
+ # # Action Dispatch Reloader
5
7
  #
6
8
  # ActionDispatch::Reloader wraps the request with callbacks provided by
7
9
  # ActiveSupport::Reloader, intended to assist with code reloading during
8
10
  # development.
9
11
  #
10
- # ActionDispatch::Reloader is included in the middleware stack only if
11
- # reloading is enabled, which it is by the default in +development+ mode.
12
+ # ActionDispatch::Reloader is included in the middleware stack only if reloading
13
+ # is enabled, which it is by the default in `development` mode.
12
14
  class Reloader < Executor
13
15
  end
14
16
  end
@@ -1,37 +1,41 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # :markup: markdown
4
+
3
5
  require "ipaddr"
4
6
 
5
7
  module ActionDispatch
6
- # = Action Dispatch \RemoteIp
8
+ # # Action Dispatch RemoteIp
7
9
  #
8
- # This middleware calculates the IP address of the remote client that is
9
- # making the request. It does this by checking various headers that could
10
- # contain the address, and then picking the last-set address that is not
11
- # on the list of trusted IPs. This follows the precedent set by e.g.
12
- # {the Tomcat server}[https://issues.apache.org/bugzilla/show_bug.cgi?id=50453].
13
- # A more detailed explanation of the algorithm is given at GetIp#calculate_ip.
10
+ # This middleware calculates the IP address of the remote client that is making
11
+ # the request. It does this by checking various headers that could contain the
12
+ # address, and then picking the last-set address that is not on the list of
13
+ # trusted IPs. This follows the precedent set by e.g. [the Tomcat
14
+ # server](https://issues.apache.org/bugzilla/show_bug.cgi?id=50453). A more
15
+ # detailed explanation of the algorithm is given at GetIp#calculate_ip.
14
16
  #
15
- # Some Rack servers concatenate repeated headers, like {HTTP RFC 2616}[https://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2]
16
- # requires. Some Rack servers simply drop preceding headers, and only report
17
- # the value that was {given in the last header}[https://andre.arko.net/2011/12/26/repeated-headers-and-ruby-web-servers].
18
- # If you are behind multiple proxy servers (like NGINX to HAProxy to Unicorn)
19
- # then you should test your Rack server to make sure your data is good.
17
+ # Some Rack servers concatenate repeated headers, like [HTTP RFC
18
+ # 2616](https://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2) requires.
19
+ # Some Rack servers simply drop preceding headers, and only report the value
20
+ # that was [given in the last
21
+ # header](https://andre.arko.net/2011/12/26/repeated-headers-and-ruby-web-server
22
+ # s). If you are behind multiple proxy servers (like NGINX to HAProxy to
23
+ # Unicorn) then you should test your Rack server to make sure your data is good.
20
24
  #
21
- # IF YOU DON'T USE A PROXY, THIS MAKES YOU VULNERABLE TO IP SPOOFING.
22
- # This middleware assumes that there is at least one proxy sitting around
23
- # and setting headers with the client's remote IP address. If you don't use
24
- # a proxy, because you are hosted on e.g. Heroku without SSL, any client can
25
- # claim to have any IP address by setting the +X-Forwarded-For+ header. If you
26
- # care about that, then you need to explicitly drop or ignore those headers
27
- # sometime before this middleware runs. Alternatively, remove this middleware
28
- # to avoid inadvertently relying on it.
25
+ # IF YOU DON'T USE A PROXY, THIS MAKES YOU VULNERABLE TO IP SPOOFING. This
26
+ # middleware assumes that there is at least one proxy sitting around and setting
27
+ # headers with the client's remote IP address. If you don't use a proxy, because
28
+ # you are hosted on e.g. Heroku without SSL, any client can claim to have any IP
29
+ # address by setting the `X-Forwarded-For` header. If you care about that, then
30
+ # you need to explicitly drop or ignore those headers sometime before this
31
+ # middleware runs. Alternatively, remove this middleware to avoid inadvertently
32
+ # relying on it.
29
33
  class RemoteIp
30
34
  class IpSpoofAttackError < StandardError; end
31
35
 
32
- # The default trusted IPs list simply includes IP addresses that are
33
- # guaranteed by the IP specification to be private addresses. Those will
34
- # not be the ultimate client IP in production, and so are discarded. See
36
+ # The default trusted IPs list simply includes IP addresses that are guaranteed
37
+ # by the IP specification to be private addresses. Those will not be the
38
+ # ultimate client IP in production, and so are discarded. See
35
39
  # https://en.wikipedia.org/wiki/Private_network for details.
36
40
  TRUSTED_PROXIES = [
37
41
  "127.0.0.0/8", # localhost IPv4 range, per RFC-3330
@@ -44,20 +48,20 @@ module ActionDispatch
44
48
 
45
49
  attr_reader :check_ip, :proxies
46
50
 
47
- # Create a new +RemoteIp+ middleware instance.
51
+ # Create a new `RemoteIp` middleware instance.
48
52
  #
49
- # The +ip_spoofing_check+ option is on by default. When on, an exception
50
- # is raised if it looks like the client is trying to lie about its own IP
51
- # address. It makes sense to turn off this check on sites aimed at non-IP
52
- # clients (like WAP devices), or behind proxies that set headers in an
53
- # incorrect or confusing way (like AWS ELB).
53
+ # The `ip_spoofing_check` option is on by default. When on, an exception is
54
+ # raised if it looks like the client is trying to lie about its own IP address.
55
+ # It makes sense to turn off this check on sites aimed at non-IP clients (like
56
+ # WAP devices), or behind proxies that set headers in an incorrect or confusing
57
+ # way (like AWS ELB).
54
58
  #
55
- # The +custom_proxies+ argument can take an enumerable which will be used
56
- # instead of +TRUSTED_PROXIES+. Any proxy setup will put the value you
57
- # want in the middle (or at the beginning) of the +X-Forwarded-For+ list,
58
- # with your proxy servers after it. If your proxies aren't removed, pass
59
- # them in via the +custom_proxies+ parameter. That way, the middleware will
60
- # ignore those IP addresses, and return the one that you want.
59
+ # The `custom_proxies` argument can take an enumerable which will be used
60
+ # instead of `TRUSTED_PROXIES`. Any proxy setup will put the value you want in
61
+ # the middle (or at the beginning) of the `X-Forwarded-For` list, with your
62
+ # proxy servers after it. If your proxies aren't removed, pass them in via the
63
+ # `custom_proxies` parameter. That way, the middleware will ignore those IP
64
+ # addresses, and return the one that you want.
61
65
  def initialize(app, ip_spoofing_check = true, custom_proxies = nil)
62
66
  @app = app
63
67
  @check_ip = ip_spoofing_check
@@ -82,19 +86,19 @@ module ActionDispatch
82
86
  end
83
87
  end
84
88
 
85
- # Since the IP address may not be needed, we store the object here
86
- # without calculating the IP to keep from slowing down the majority of
87
- # requests. For those requests that do need to know the IP, the
88
- # GetIp#calculate_ip method will calculate the memoized client IP address.
89
+ # Since the IP address may not be needed, we store the object here without
90
+ # calculating the IP to keep from slowing down the majority of requests. For
91
+ # those requests that do need to know the IP, the GetIp#calculate_ip method will
92
+ # calculate the memoized client IP address.
89
93
  def call(env)
90
94
  req = ActionDispatch::Request.new env
91
95
  req.remote_ip = GetIp.new(req, check_ip, proxies)
92
96
  @app.call(req.env)
93
97
  end
94
98
 
95
- # The GetIp class exists as a way to defer processing of the request data
96
- # into an actual IP address. If the ActionDispatch::Request#remote_ip method
97
- # is called, this class will calculate the value and then memoize it.
99
+ # The GetIp class exists as a way to defer processing of the request data into
100
+ # an actual IP address. If the ActionDispatch::Request#remote_ip method is
101
+ # called, this class will calculate the value and then memoize it.
98
102
  class GetIp
99
103
  def initialize(req, check_ip, proxies)
100
104
  @req = req
@@ -102,24 +106,25 @@ module ActionDispatch
102
106
  @proxies = proxies
103
107
  end
104
108
 
105
- # Sort through the various IP address headers, looking for the IP most
106
- # likely to be the address of the actual remote client making this
107
- # request.
109
+ # Sort through the various IP address headers, looking for the IP most likely to
110
+ # be the address of the actual remote client making this request.
108
111
  #
109
- # REMOTE_ADDR will be correct if the request is made directly against the
110
- # Ruby process, on e.g. Heroku. When the request is proxied by another
111
- # server like HAProxy or NGINX, the IP address that made the original
112
- # request will be put in an +X-Forwarded-For+ header. If there are multiple
113
- # proxies, that header may contain a list of IPs. Other proxy services
114
- # set the +Client-Ip+ header instead, so we check that too.
112
+ # REMOTE_ADDR will be correct if the request is made directly against the Ruby
113
+ # process, on e.g. Heroku. When the request is proxied by another server like
114
+ # HAProxy or NGINX, the IP address that made the original request will be put in
115
+ # an `X-Forwarded-For` header. If there are multiple proxies, that header may
116
+ # contain a list of IPs. Other proxy services set the `Client-Ip` header
117
+ # instead, so we check that too.
115
118
  #
116
- # As discussed in {this post about Rails IP Spoofing}[https://web.archive.org/web/20170626095448/https://blog.gingerlime.com/2012/rails-ip-spoofing-vulnerabilities-and-protection/],
117
- # while the first IP in the list is likely to be the "originating" IP,
118
- # it could also have been set by the client maliciously.
119
+ # As discussed in [this post about Rails IP
120
+ # Spoofing](https://web.archive.org/web/20170626095448/https://blog.gingerlime.c
121
+ # om/2012/rails-ip-spoofing-vulnerabilities-and-protection/), while the first IP
122
+ # in the list is likely to be the "originating" IP, it could also have been set
123
+ # by the client maliciously.
119
124
  #
120
- # In order to find the first address that is (probably) accurate, we
121
- # take the list of IPs, remove known and trusted proxies, and then take
122
- # the last address left, which was presumably set by one of those proxies.
125
+ # In order to find the first address that is (probably) accurate, we take the
126
+ # list of IPs, remove known and trusted proxies, and then take the last address
127
+ # left, which was presumably set by one of those proxies.
123
128
  def calculate_ip
124
129
  # Set by the Rack web server, this is a single value.
125
130
  remote_addr = ips_from(@req.remote_addr).last
@@ -128,19 +133,19 @@ module ActionDispatch
128
133
  client_ips = ips_from(@req.client_ip).reverse!
129
134
  forwarded_ips = ips_from(@req.x_forwarded_for).reverse!
130
135
 
131
- # +Client-Ip+ and +X-Forwarded-For+ should not, generally, both be set.
132
- # If they are both set, it means that either:
136
+ # `Client-Ip` and `X-Forwarded-For` should not, generally, both be set. If they
137
+ # are both set, it means that either:
133
138
  #
134
139
  # 1) This request passed through two proxies with incompatible IP header
135
- # conventions.
136
- # 2) The client passed one of +Client-Ip+ or +X-Forwarded-For+
137
- # (whichever the proxy servers weren't using) themselves.
140
+ # conventions.
141
+ #
142
+ # 2) The client passed one of `Client-Ip` or `X-Forwarded-For`
143
+ # (whichever the proxy servers weren't using) themselves.
138
144
  #
139
- # Either way, there is no way for us to determine which header is the
140
- # right one after the fact. Since we have no idea, if we are concerned
141
- # about IP spoofing we need to give up and explode. (If you're not
142
- # concerned about IP spoofing you can turn the +ip_spoofing_check+
143
- # option off.)
145
+ # Either way, there is no way for us to determine which header is the right one
146
+ # after the fact. Since we have no idea, if we are concerned about IP spoofing
147
+ # we need to give up and explode. (If you're not concerned about IP spoofing you
148
+ # can turn the `ip_spoofing_check` option off.)
144
149
  should_check_ip = @check_ip && client_ips.last && forwarded_ips.last
145
150
  if should_check_ip && !forwarded_ips.include?(client_ips.last)
146
151
  # We don't know which came from the proxy, and which from the user
@@ -151,14 +156,14 @@ module ActionDispatch
151
156
 
152
157
  # We assume these things about the IP headers:
153
158
  #
154
- # - X-Forwarded-For will be a list of IPs, one per proxy, or blank
155
- # - Client-Ip is propagated from the outermost proxy, or is blank
156
- # - REMOTE_ADDR will be the IP that made the request to Rack
159
+ # - X-Forwarded-For will be a list of IPs, one per proxy, or blank
160
+ # - Client-Ip is propagated from the outermost proxy, or is blank
161
+ # - REMOTE_ADDR will be the IP that made the request to Rack
157
162
  ips = forwarded_ips + client_ips
158
163
  ips.compact!
159
164
 
160
- # If every single IP option is in the trusted list, return the IP
161
- # that's furthest away
165
+ # If every single IP option is in the trusted list, return the IP that's
166
+ # furthest away
162
167
  filter_proxies(ips + [remote_addr]).first || ips.last || remote_addr
163
168
  end
164
169
 
@@ -1,21 +1,26 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # :markup: markdown
4
+
3
5
  require "securerandom"
4
6
  require "active_support/core_ext/string/access"
5
7
 
6
8
  module ActionDispatch
7
- # = Action Dispatch \RequestId
9
+ # # Action Dispatch RequestId
8
10
  #
9
- # Makes a unique request id available to the +action_dispatch.request_id+ env variable (which is then accessible
10
- # through ActionDispatch::Request#request_id or the alias ActionDispatch::Request#uuid) and sends
11
- # the same id to the client via the +X-Request-Id+ header.
11
+ # Makes a unique request id available to the `action_dispatch.request_id` env
12
+ # variable (which is then accessible through ActionDispatch::Request#request_id
13
+ # or the alias ActionDispatch::Request#uuid) and sends the same id to the client
14
+ # via the `X-Request-Id` header.
12
15
  #
13
- # The unique request id is either based on the +X-Request-Id+ header in the request, which would typically be generated
14
- # by a firewall, load balancer, or the web server, or, if this header is not available, a random uuid. If the
15
- # header is accepted from the outside world, we sanitize it to a max of 255 chars and alphanumeric and dashes only.
16
+ # The unique request id is either based on the `X-Request-Id` header in the
17
+ # request, which would typically be generated by a firewall, load balancer, or
18
+ # the web server, or, if this header is not available, a random uuid. If the
19
+ # header is accepted from the outside world, we sanitize it to a max of 255
20
+ # chars and alphanumeric and dashes only.
16
21
  #
17
- # The unique request id can be used to trace a request end-to-end and would typically end up being part of log files
18
- # from multiple pieces of the stack.
22
+ # The unique request id can be used to trace a request end-to-end and would
23
+ # typically end up being part of log files from multiple pieces of the stack.
19
24
  class RequestId
20
25
  def initialize(app, header:)
21
26
  @app = app
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # :markup: markdown
4
+
3
5
  require "active_support/notifications"
4
6
 
5
7
  module ActionDispatch
@@ -29,8 +31,8 @@ module ActionDispatch
29
31
 
30
32
  def ensure_subscribed
31
33
  @mutex.synchronize do
32
- # Subscribe to all events, except those beginning with "!"
33
- # Ideally we would be more selective of what is being measured
34
+ # Subscribe to all events, except those beginning with "!" Ideally we would be
35
+ # more selective of what is being measured
34
36
  @subscriber ||= ActiveSupport::Notifications.subscribe(/\A[^!]/, self)
35
37
  end
36
38
  end
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # :markup: markdown
4
+
3
5
  require "rack/utils"
4
6
  require "rack/request"
5
7
  require "rack/session/abstract/id"
@@ -1,19 +1,24 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # :markup: markdown
4
+
3
5
  require "action_dispatch/middleware/session/abstract_store"
4
6
 
5
7
  module ActionDispatch
6
8
  module Session
7
- # = Action Dispatch Session \CacheStore
9
+ # # Action Dispatch Session CacheStore
10
+ #
11
+ # A session store that uses an ActiveSupport::Cache::Store to store the
12
+ # sessions. This store is most useful if you don't store critical data in your
13
+ # sessions and you don't need them to live for extended periods of time.
8
14
  #
9
- # A session store that uses an ActiveSupport::Cache::Store to store the sessions. This store is most useful
10
- # if you don't store critical data in your sessions and you don't need them to live for extended periods
11
- # of time.
15
+ # #### Options
16
+ # * `cache` - The cache to use. If it is not specified, `Rails.cache`
17
+ # will be used.
18
+ # * `expire_after` - The length of time a session will be stored before
19
+ # automatically expiring. By default, the `:expires_in` option of the cache
20
+ # is used.
12
21
  #
13
- # ==== Options
14
- # * <tt>cache</tt> - The cache to use. If it is not specified, <tt>Rails.cache</tt> will be used.
15
- # * <tt>expire_after</tt> - The length of time a session will be stored before automatically expiring.
16
- # By default, the <tt>:expires_in</tt> option of the cache is used.
17
22
  class CacheStore < AbstractSecureStore
18
23
  def initialize(app, options = {})
19
24
  @cache = options[:cache] || Rails.cache