omg-actionpack 8.0.0.alpha1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (187) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +129 -0
  3. data/MIT-LICENSE +21 -0
  4. data/README.rdoc +57 -0
  5. data/lib/abstract_controller/asset_paths.rb +14 -0
  6. data/lib/abstract_controller/base.rb +299 -0
  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 +265 -0
  10. data/lib/abstract_controller/collector.rb +44 -0
  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 +243 -0
  14. data/lib/abstract_controller/logger.rb +16 -0
  15. data/lib/abstract_controller/railties/routes_helpers.rb +25 -0
  16. data/lib/abstract_controller/rendering.rb +126 -0
  17. data/lib/abstract_controller/translation.rb +42 -0
  18. data/lib/abstract_controller/url_for.rb +37 -0
  19. data/lib/abstract_controller.rb +36 -0
  20. data/lib/action_controller/api/api_rendering.rb +18 -0
  21. data/lib/action_controller/api.rb +155 -0
  22. data/lib/action_controller/base.rb +332 -0
  23. data/lib/action_controller/caching.rb +49 -0
  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 +96 -0
  27. data/lib/action_controller/metal/allow_browser.rb +123 -0
  28. data/lib/action_controller/metal/basic_implicit_render.rb +17 -0
  29. data/lib/action_controller/metal/conditional_get.rb +341 -0
  30. data/lib/action_controller/metal/content_security_policy.rb +86 -0
  31. data/lib/action_controller/metal/cookies.rb +20 -0
  32. data/lib/action_controller/metal/data_streaming.rb +154 -0
  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 +59 -0
  36. data/lib/action_controller/metal/exceptions.rb +106 -0
  37. data/lib/action_controller/metal/flash.rb +67 -0
  38. data/lib/action_controller/metal/head.rb +67 -0
  39. data/lib/action_controller/metal/helpers.rb +129 -0
  40. data/lib/action_controller/metal/http_authentication.rb +565 -0
  41. data/lib/action_controller/metal/implicit_render.rb +67 -0
  42. data/lib/action_controller/metal/instrumentation.rb +120 -0
  43. data/lib/action_controller/metal/live.rb +398 -0
  44. data/lib/action_controller/metal/logging.rb +22 -0
  45. data/lib/action_controller/metal/mime_responds.rb +337 -0
  46. data/lib/action_controller/metal/parameter_encoding.rb +84 -0
  47. data/lib/action_controller/metal/params_wrapper.rb +312 -0
  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 +251 -0
  51. data/lib/action_controller/metal/renderers.rb +181 -0
  52. data/lib/action_controller/metal/rendering.rb +260 -0
  53. data/lib/action_controller/metal/request_forgery_protection.rb +667 -0
  54. data/lib/action_controller/metal/rescue.rb +33 -0
  55. data/lib/action_controller/metal/streaming.rb +183 -0
  56. data/lib/action_controller/metal/strong_parameters.rb +1546 -0
  57. data/lib/action_controller/metal/testing.rb +25 -0
  58. data/lib/action_controller/metal/url_for.rb +65 -0
  59. data/lib/action_controller/metal.rb +339 -0
  60. data/lib/action_controller/railtie.rb +149 -0
  61. data/lib/action_controller/railties/helpers.rb +26 -0
  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 +691 -0
  65. data/lib/action_controller.rb +80 -0
  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 +249 -0
  69. data/lib/action_dispatch/http/content_disposition.rb +47 -0
  70. data/lib/action_dispatch/http/content_security_policy.rb +365 -0
  71. data/lib/action_dispatch/http/filter_parameters.rb +80 -0
  72. data/lib/action_dispatch/http/filter_redirect.rb +50 -0
  73. data/lib/action_dispatch/http/headers.rb +134 -0
  74. data/lib/action_dispatch/http/mime_negotiation.rb +187 -0
  75. data/lib/action_dispatch/http/mime_type.rb +389 -0
  76. data/lib/action_dispatch/http/mime_types.rb +54 -0
  77. data/lib/action_dispatch/http/parameters.rb +119 -0
  78. data/lib/action_dispatch/http/permissions_policy.rb +189 -0
  79. data/lib/action_dispatch/http/rack_cache.rb +67 -0
  80. data/lib/action_dispatch/http/request.rb +498 -0
  81. data/lib/action_dispatch/http/response.rb +556 -0
  82. data/lib/action_dispatch/http/upload.rb +107 -0
  83. data/lib/action_dispatch/http/url.rb +344 -0
  84. data/lib/action_dispatch/journey/formatter.rb +226 -0
  85. data/lib/action_dispatch/journey/gtg/builder.rb +149 -0
  86. data/lib/action_dispatch/journey/gtg/simulator.rb +50 -0
  87. data/lib/action_dispatch/journey/gtg/transition_table.rb +217 -0
  88. data/lib/action_dispatch/journey/nfa/dot.rb +27 -0
  89. data/lib/action_dispatch/journey/nodes/node.rb +208 -0
  90. data/lib/action_dispatch/journey/parser.rb +103 -0
  91. data/lib/action_dispatch/journey/path/pattern.rb +209 -0
  92. data/lib/action_dispatch/journey/route.rb +189 -0
  93. data/lib/action_dispatch/journey/router/utils.rb +105 -0
  94. data/lib/action_dispatch/journey/router.rb +151 -0
  95. data/lib/action_dispatch/journey/routes.rb +82 -0
  96. data/lib/action_dispatch/journey/scanner.rb +70 -0
  97. data/lib/action_dispatch/journey/visitors.rb +267 -0
  98. data/lib/action_dispatch/journey/visualizer/fsm.css +30 -0
  99. data/lib/action_dispatch/journey/visualizer/fsm.js +159 -0
  100. data/lib/action_dispatch/journey/visualizer/index.html.erb +52 -0
  101. data/lib/action_dispatch/journey.rb +7 -0
  102. data/lib/action_dispatch/log_subscriber.rb +25 -0
  103. data/lib/action_dispatch/middleware/actionable_exceptions.rb +46 -0
  104. data/lib/action_dispatch/middleware/assume_ssl.rb +27 -0
  105. data/lib/action_dispatch/middleware/callbacks.rb +38 -0
  106. data/lib/action_dispatch/middleware/cookies.rb +719 -0
  107. data/lib/action_dispatch/middleware/debug_exceptions.rb +206 -0
  108. data/lib/action_dispatch/middleware/debug_locks.rb +129 -0
  109. data/lib/action_dispatch/middleware/debug_view.rb +73 -0
  110. data/lib/action_dispatch/middleware/exception_wrapper.rb +350 -0
  111. data/lib/action_dispatch/middleware/executor.rb +32 -0
  112. data/lib/action_dispatch/middleware/flash.rb +318 -0
  113. data/lib/action_dispatch/middleware/host_authorization.rb +171 -0
  114. data/lib/action_dispatch/middleware/public_exceptions.rb +64 -0
  115. data/lib/action_dispatch/middleware/reloader.rb +16 -0
  116. data/lib/action_dispatch/middleware/remote_ip.rb +199 -0
  117. data/lib/action_dispatch/middleware/request_id.rb +50 -0
  118. data/lib/action_dispatch/middleware/server_timing.rb +78 -0
  119. data/lib/action_dispatch/middleware/session/abstract_store.rb +112 -0
  120. data/lib/action_dispatch/middleware/session/cache_store.rb +66 -0
  121. data/lib/action_dispatch/middleware/session/cookie_store.rb +129 -0
  122. data/lib/action_dispatch/middleware/session/mem_cache_store.rb +34 -0
  123. data/lib/action_dispatch/middleware/show_exceptions.rb +88 -0
  124. data/lib/action_dispatch/middleware/ssl.rb +180 -0
  125. data/lib/action_dispatch/middleware/stack.rb +194 -0
  126. data/lib/action_dispatch/middleware/static.rb +192 -0
  127. data/lib/action_dispatch/middleware/templates/rescues/_actions.html.erb +13 -0
  128. data/lib/action_dispatch/middleware/templates/rescues/_actions.text.erb +0 -0
  129. data/lib/action_dispatch/middleware/templates/rescues/_message_and_suggestions.html.erb +22 -0
  130. data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb +17 -0
  131. data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.text.erb +23 -0
  132. data/lib/action_dispatch/middleware/templates/rescues/_source.html.erb +36 -0
  133. data/lib/action_dispatch/middleware/templates/rescues/_source.text.erb +8 -0
  134. data/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb +62 -0
  135. data/lib/action_dispatch/middleware/templates/rescues/_trace.text.erb +9 -0
  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 +35 -0
  139. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.text.erb +9 -0
  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 +284 -0
  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 +11 -0
  146. data/lib/action_dispatch/middleware/templates/rescues/missing_template.text.erb +3 -0
  147. data/lib/action_dispatch/middleware/templates/rescues/routing_error.html.erb +32 -0
  148. data/lib/action_dispatch/middleware/templates/rescues/routing_error.text.erb +11 -0
  149. data/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb +20 -0
  150. data/lib/action_dispatch/middleware/templates/rescues/template_error.text.erb +7 -0
  151. data/lib/action_dispatch/middleware/templates/rescues/unknown_action.html.erb +6 -0
  152. data/lib/action_dispatch/middleware/templates/rescues/unknown_action.text.erb +3 -0
  153. data/lib/action_dispatch/middleware/templates/routes/_route.html.erb +19 -0
  154. data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +232 -0
  155. data/lib/action_dispatch/railtie.rb +77 -0
  156. data/lib/action_dispatch/request/session.rb +283 -0
  157. data/lib/action_dispatch/request/utils.rb +109 -0
  158. data/lib/action_dispatch/routing/endpoint.rb +19 -0
  159. data/lib/action_dispatch/routing/inspector.rb +323 -0
  160. data/lib/action_dispatch/routing/mapper.rb +2372 -0
  161. data/lib/action_dispatch/routing/polymorphic_routes.rb +363 -0
  162. data/lib/action_dispatch/routing/redirection.rb +218 -0
  163. data/lib/action_dispatch/routing/route_set.rb +958 -0
  164. data/lib/action_dispatch/routing/routes_proxy.rb +66 -0
  165. data/lib/action_dispatch/routing/url_for.rb +244 -0
  166. data/lib/action_dispatch/routing.rb +262 -0
  167. data/lib/action_dispatch/system_test_case.rb +206 -0
  168. data/lib/action_dispatch/system_testing/browser.rb +75 -0
  169. data/lib/action_dispatch/system_testing/driver.rb +85 -0
  170. data/lib/action_dispatch/system_testing/server.rb +33 -0
  171. data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +164 -0
  172. data/lib/action_dispatch/system_testing/test_helpers/setup_and_teardown.rb +23 -0
  173. data/lib/action_dispatch/testing/assertion_response.rb +48 -0
  174. data/lib/action_dispatch/testing/assertions/response.rb +114 -0
  175. data/lib/action_dispatch/testing/assertions/routing.rb +343 -0
  176. data/lib/action_dispatch/testing/assertions.rb +25 -0
  177. data/lib/action_dispatch/testing/integration.rb +694 -0
  178. data/lib/action_dispatch/testing/request_encoder.rb +60 -0
  179. data/lib/action_dispatch/testing/test_helpers/page_dump_helper.rb +35 -0
  180. data/lib/action_dispatch/testing/test_process.rb +57 -0
  181. data/lib/action_dispatch/testing/test_request.rb +73 -0
  182. data/lib/action_dispatch/testing/test_response.rb +58 -0
  183. data/lib/action_dispatch.rb +147 -0
  184. data/lib/action_pack/gem_version.rb +19 -0
  185. data/lib/action_pack/version.rb +12 -0
  186. data/lib/action_pack.rb +27 -0
  187. metadata +375 -0
@@ -0,0 +1,332 @@
1
+ # frozen_string_literal: true
2
+
3
+ # :markup: markdown
4
+
5
+ require "action_view"
6
+ require "action_controller/log_subscriber"
7
+ require "action_controller/metal/params_wrapper"
8
+
9
+ module ActionController
10
+ # # Action Controller Base
11
+ #
12
+ # Action Controllers are the core of a web request in Rails. They are made up of
13
+ # one or more actions that are executed on request and then either it renders a
14
+ # template or redirects to another action. An action is defined as a public
15
+ # method on the controller, which will automatically be made accessible to the
16
+ # web-server through Rails Routes.
17
+ #
18
+ # By default, only the ApplicationController in a Rails application inherits
19
+ # from `ActionController::Base`. All other controllers inherit from
20
+ # ApplicationController. This gives you one class to configure things such as
21
+ # request forgery protection and filtering of sensitive request parameters.
22
+ #
23
+ # A sample controller could look like this:
24
+ #
25
+ # class PostsController < ApplicationController
26
+ # def index
27
+ # @posts = Post.all
28
+ # end
29
+ #
30
+ # def create
31
+ # @post = Post.create params[:post]
32
+ # redirect_to posts_path
33
+ # end
34
+ # end
35
+ #
36
+ # Actions, by default, render a template in the `app/views` directory
37
+ # corresponding to the name of the controller and action after executing code in
38
+ # the action. For example, the `index` action of the PostsController would
39
+ # render the template `app/views/posts/index.html.erb` by default after
40
+ # populating the `@posts` instance variable.
41
+ #
42
+ # Unlike index, the create action will not render a template. After performing
43
+ # its main purpose (creating a new post), it initiates a redirect instead. This
44
+ # redirect works by returning an external `302 Moved` HTTP response that takes
45
+ # the user to the index action.
46
+ #
47
+ # These two methods represent the two basic action archetypes used in Action
48
+ # Controllers: Get-and-show and do-and-redirect. Most actions are variations on
49
+ # these themes.
50
+ #
51
+ # ## Requests
52
+ #
53
+ # For every request, the router determines the value of the `controller` and
54
+ # `action` keys. These determine which controller and action are called. The
55
+ # remaining request parameters, the session (if one is available), and the full
56
+ # request with all the HTTP headers are made available to the action through
57
+ # accessor methods. Then the action is performed.
58
+ #
59
+ # The full request object is available via the request accessor and is primarily
60
+ # used to query for HTTP headers:
61
+ #
62
+ # def server_ip
63
+ # location = request.env["REMOTE_ADDR"]
64
+ # render plain: "This server hosted at #{location}"
65
+ # end
66
+ #
67
+ # ## Parameters
68
+ #
69
+ # All request parameters, whether they come from a query string in the URL or
70
+ # form data submitted through a POST request are available through the `params`
71
+ # method which returns a hash. For example, an action that was performed through
72
+ # `/posts?category=All&limit=5` will include `{ "category" => "All", "limit" =>
73
+ # "5" }` in `params`.
74
+ #
75
+ # It's also possible to construct multi-dimensional parameter hashes by
76
+ # specifying keys using brackets, such as:
77
+ #
78
+ # <input type="text" name="post[name]" value="david">
79
+ # <input type="text" name="post[address]" value="hyacintvej">
80
+ #
81
+ # A request coming from a form holding these inputs will include `{ "post" => {
82
+ # "name" => "david", "address" => "hyacintvej" } }`. If the address input had
83
+ # been named `post[address][street]`, the `params` would have included `{ "post"
84
+ # => { "address" => { "street" => "hyacintvej" } } }`. There's no limit to the
85
+ # depth of the nesting.
86
+ #
87
+ # ## Sessions
88
+ #
89
+ # Sessions allow you to store objects in between requests. This is useful for
90
+ # objects that are not yet ready to be persisted, such as a Signup object
91
+ # constructed in a multi-paged process, or objects that don't change much and
92
+ # are needed all the time, such as a User object for a system that requires
93
+ # login. The session should not be used, however, as a cache for objects where
94
+ # it's likely they could be changed unknowingly. It's usually too much work to
95
+ # keep it all synchronized -- something databases already excel at.
96
+ #
97
+ # You can place objects in the session by using the `session` method, which
98
+ # accesses a hash:
99
+ #
100
+ # session[:person] = Person.authenticate(user_name, password)
101
+ #
102
+ # You can retrieve it again through the same hash:
103
+ #
104
+ # "Hello #{session[:person]}"
105
+ #
106
+ # For removing objects from the session, you can either assign a single key to
107
+ # `nil`:
108
+ #
109
+ # # removes :person from session
110
+ # session[:person] = nil
111
+ #
112
+ # or you can remove the entire session with `reset_session`.
113
+ #
114
+ # By default, sessions are stored in an encrypted browser cookie (see
115
+ # ActionDispatch::Session::CookieStore). Thus the user will not be able to read
116
+ # or edit the session data. However, the user can keep a copy of the cookie even
117
+ # after it has expired, so you should avoid storing sensitive information in
118
+ # cookie-based sessions.
119
+ #
120
+ # ## Responses
121
+ #
122
+ # Each action results in a response, which holds the headers and document to be
123
+ # sent to the user's browser. The actual response object is generated
124
+ # automatically through the use of renders and redirects and requires no user
125
+ # intervention.
126
+ #
127
+ # ## Renders
128
+ #
129
+ # Action Controller sends content to the user by using one of five rendering
130
+ # methods. The most versatile and common is the rendering of a template.
131
+ # Included in the Action Pack is the Action View, which enables rendering of ERB
132
+ # templates. It's automatically configured. The controller passes objects to the
133
+ # view by assigning instance variables:
134
+ #
135
+ # def show
136
+ # @post = Post.find(params[:id])
137
+ # end
138
+ #
139
+ # Which are then automatically available to the view:
140
+ #
141
+ # Title: <%= @post.title %>
142
+ #
143
+ # You don't have to rely on the automated rendering. For example, actions that
144
+ # could result in the rendering of different templates will use the manual
145
+ # rendering methods:
146
+ #
147
+ # def search
148
+ # @results = Search.find(params[:query])
149
+ # case @results.count
150
+ # when 0 then render action: "no_results"
151
+ # when 1 then render action: "show"
152
+ # when 2..10 then render action: "show_many"
153
+ # end
154
+ # end
155
+ #
156
+ # Read more about writing ERB and Builder templates in ActionView::Base.
157
+ #
158
+ # ## Redirects
159
+ #
160
+ # Redirects are used to move from one action to another. For example, after a
161
+ # `create` action, which stores a blog entry to the database, we might like to
162
+ # show the user the new entry. Because we're following good DRY principles
163
+ # (Don't Repeat Yourself), we're going to reuse (and redirect to) a `show`
164
+ # action that we'll assume has already been created. The code might look like
165
+ # this:
166
+ #
167
+ # def create
168
+ # @entry = Entry.new(params[:entry])
169
+ # if @entry.save
170
+ # # The entry was saved correctly, redirect to show
171
+ # redirect_to action: 'show', id: @entry.id
172
+ # else
173
+ # # things didn't go so well, do something else
174
+ # end
175
+ # end
176
+ #
177
+ # In this case, after saving our new entry to the database, the user is
178
+ # redirected to the `show` method, which is then executed. Note that this is an
179
+ # external HTTP-level redirection which will cause the browser to make a second
180
+ # request (a GET to the show action), and not some internal re-routing which
181
+ # calls both "create" and then "show" within one request.
182
+ #
183
+ # Learn more about `redirect_to` and what options you have in
184
+ # ActionController::Redirecting.
185
+ #
186
+ # ## Calling multiple redirects or renders
187
+ #
188
+ # An action may perform only a single render or a single redirect. Attempting to
189
+ # do either again will result in a DoubleRenderError:
190
+ #
191
+ # def do_something
192
+ # redirect_to action: "elsewhere"
193
+ # render action: "overthere" # raises DoubleRenderError
194
+ # end
195
+ #
196
+ # If you need to redirect on the condition of something, then be sure to add
197
+ # "return" to halt execution.
198
+ #
199
+ # def do_something
200
+ # if monkeys.nil?
201
+ # redirect_to(action: "elsewhere")
202
+ # return
203
+ # end
204
+ # render action: "overthere" # won't be called if monkeys is nil
205
+ # end
206
+ #
207
+ class Base < Metal
208
+ abstract!
209
+
210
+ # Shortcut helper that returns all the modules included in
211
+ # ActionController::Base except the ones passed as arguments:
212
+ #
213
+ # class MyBaseController < ActionController::Metal
214
+ # ActionController::Base.without_modules(:ParamsWrapper, :Streaming).each do |left|
215
+ # include left
216
+ # end
217
+ # end
218
+ #
219
+ # This gives better control over what you want to exclude and makes it easier to
220
+ # create a bare controller class, instead of listing the modules required
221
+ # manually.
222
+ def self.without_modules(*modules)
223
+ modules = modules.map do |m|
224
+ m.is_a?(Symbol) ? ActionController.const_get(m) : m
225
+ end
226
+
227
+ MODULES - modules
228
+ end
229
+
230
+ MODULES = [
231
+ AbstractController::Rendering,
232
+ AbstractController::Translation,
233
+ AbstractController::AssetPaths,
234
+ Helpers,
235
+ UrlFor,
236
+ Redirecting,
237
+ ActionView::Layouts,
238
+ Rendering,
239
+ Renderers::All,
240
+ ConditionalGet,
241
+ EtagWithTemplateDigest,
242
+ EtagWithFlash,
243
+ Caching,
244
+ MimeResponds,
245
+ ImplicitRender,
246
+ StrongParameters,
247
+ ParameterEncoding,
248
+ Cookies,
249
+ Flash,
250
+ FormBuilder,
251
+ RequestForgeryProtection,
252
+ ContentSecurityPolicy,
253
+ PermissionsPolicy,
254
+ RateLimiting,
255
+ AllowBrowser,
256
+ Streaming,
257
+ DataStreaming,
258
+ HttpAuthentication::Basic::ControllerMethods,
259
+ HttpAuthentication::Digest::ControllerMethods,
260
+ HttpAuthentication::Token::ControllerMethods,
261
+ DefaultHeaders,
262
+ Logging,
263
+ AbstractController::Callbacks,
264
+ Rescue,
265
+ Instrumentation,
266
+ ParamsWrapper
267
+ ]
268
+
269
+ # Note: Documenting these severely degrates the performance of rdoc
270
+ # :stopdoc:
271
+ include AbstractController::Rendering
272
+ include AbstractController::Translation
273
+ include AbstractController::AssetPaths
274
+ include Helpers
275
+ include UrlFor
276
+ include Redirecting
277
+ include ActionView::Layouts
278
+ include Rendering
279
+ include Renderers::All
280
+ include ConditionalGet
281
+ include EtagWithTemplateDigest
282
+ include EtagWithFlash
283
+ include Caching
284
+ include MimeResponds
285
+ include ImplicitRender
286
+ include StrongParameters
287
+ include ParameterEncoding
288
+ include Cookies
289
+ include Flash
290
+ include FormBuilder
291
+ include RequestForgeryProtection
292
+ include ContentSecurityPolicy
293
+ include PermissionsPolicy
294
+ include RateLimiting
295
+ include AllowBrowser
296
+ include Streaming
297
+ include DataStreaming
298
+ include HttpAuthentication::Basic::ControllerMethods
299
+ include HttpAuthentication::Digest::ControllerMethods
300
+ include HttpAuthentication::Token::ControllerMethods
301
+ include DefaultHeaders
302
+ include Logging
303
+ # Before callbacks should also be executed as early as possible, so also include
304
+ # them at the bottom.
305
+ include AbstractController::Callbacks
306
+ # Append rescue at the bottom to wrap as much as possible.
307
+ include Rescue
308
+ # Add instrumentations hooks at the bottom, to ensure they instrument all the
309
+ # methods properly.
310
+ include Instrumentation
311
+ # Params wrapper should come before instrumentation so they are properly showed
312
+ # in logs
313
+ include ParamsWrapper
314
+ # :startdoc:
315
+ setup_renderer!
316
+
317
+ # Define some internal variables that should not be propagated to the view.
318
+ PROTECTED_IVARS = AbstractController::Rendering::DEFAULT_PROTECTED_INSTANCE_VARIABLES + %i(
319
+ @_params @_response @_request @_config @_url_options @_action_has_layout @_view_context_class
320
+ @_view_renderer @_lookup_context @_routes @_view_runtime @_db_runtime @_helper_proxy
321
+ @_marked_for_same_origin_verification @_rendered_format
322
+ )
323
+
324
+ def _protected_ivars
325
+ PROTECTED_IVARS
326
+ end
327
+ private :_protected_ivars
328
+
329
+ ActiveSupport.run_load_hooks(:action_controller_base, self)
330
+ ActiveSupport.run_load_hooks(:action_controller, self)
331
+ end
332
+ end
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ # :markup: markdown
4
+
5
+ module ActionController
6
+ # # Action Controller Caching
7
+ #
8
+ # Caching is a cheap way of speeding up slow applications by keeping the result
9
+ # of calculations, renderings, and database calls around for subsequent
10
+ # requests.
11
+ #
12
+ # You can read more about each approach by clicking the modules below.
13
+ #
14
+ # Note: To turn off all caching provided by Action Controller, set
15
+ # config.action_controller.perform_caching = false
16
+ #
17
+ # ## Caching stores
18
+ #
19
+ # All the caching stores from ActiveSupport::Cache are available to be used as
20
+ # backends for Action Controller caching.
21
+ #
22
+ # Configuration examples (FileStore is the default):
23
+ #
24
+ # config.action_controller.cache_store = :memory_store
25
+ # config.action_controller.cache_store = :file_store, '/path/to/cache/directory'
26
+ # config.action_controller.cache_store = :mem_cache_store, 'localhost'
27
+ # config.action_controller.cache_store = :mem_cache_store, Memcached::Rails.new('localhost:11211')
28
+ # config.action_controller.cache_store = MyOwnStore.new('parameter')
29
+ module Caching
30
+ extend ActiveSupport::Concern
31
+
32
+ included do
33
+ include AbstractController::Caching
34
+ end
35
+
36
+ private
37
+ def instrument_payload(key)
38
+ {
39
+ controller: controller_name,
40
+ action: action_name,
41
+ key: key
42
+ }
43
+ end
44
+
45
+ def instrument_name
46
+ "action_controller"
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ # :markup: markdown
4
+
5
+ module ActionController
6
+ def self.deprecator # :nodoc:
7
+ AbstractController.deprecator
8
+ end
9
+ end
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ # :markup: markdown
4
+
5
+ module ActionController
6
+ # # Action Controller Form Builder
7
+ #
8
+ # Override the default form builder for all views rendered by this controller
9
+ # and any of its descendants. Accepts a subclass of
10
+ # ActionView::Helpers::FormBuilder.
11
+ #
12
+ # For example, given a form builder:
13
+ #
14
+ # class AdminFormBuilder < ActionView::Helpers::FormBuilder
15
+ # def special_field(name)
16
+ # end
17
+ # end
18
+ #
19
+ # The controller specifies a form builder as its default:
20
+ #
21
+ # class AdminAreaController < ApplicationController
22
+ # default_form_builder AdminFormBuilder
23
+ # end
24
+ #
25
+ # Then in the view any form using `form_for` will be an instance of the
26
+ # specified form builder:
27
+ #
28
+ # <%= form_for(@instance) do |builder| %>
29
+ # <%= builder.special_field(:name) %>
30
+ # <% end %>
31
+ module FormBuilder
32
+ extend ActiveSupport::Concern
33
+
34
+ included do
35
+ class_attribute :_default_form_builder, instance_accessor: false
36
+ end
37
+
38
+ module ClassMethods
39
+ # Set the form builder to be used as the default for all forms in the views
40
+ # rendered by this controller and its subclasses.
41
+ #
42
+ # #### Parameters
43
+ # * `builder` - Default form builder, an instance of
44
+ # ActionView::Helpers::FormBuilder
45
+ def default_form_builder(builder)
46
+ self._default_form_builder = builder
47
+ end
48
+ end
49
+
50
+ # Default form builder for the controller
51
+ def default_form_builder
52
+ self.class._default_form_builder
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,96 @@
1
+ # frozen_string_literal: true
2
+
3
+ # :markup: markdown
4
+
5
+ module ActionController
6
+ class LogSubscriber < ActiveSupport::LogSubscriber
7
+ INTERNAL_PARAMS = %w(controller action format _method only_path)
8
+
9
+ def start_processing(event)
10
+ return unless logger.info?
11
+
12
+ payload = event.payload
13
+ params = {}
14
+ payload[:params].each_pair do |k, v|
15
+ params[k] = v unless INTERNAL_PARAMS.include?(k)
16
+ end
17
+ format = payload[:format]
18
+ format = format.to_s.upcase if format.is_a?(Symbol)
19
+ format = "*/*" if format.nil?
20
+
21
+ info "Processing by #{payload[:controller]}##{payload[:action]} as #{format}"
22
+ info " Parameters: #{params.inspect}" unless params.empty?
23
+ end
24
+ subscribe_log_level :start_processing, :info
25
+
26
+ def process_action(event)
27
+ info do
28
+ payload = event.payload
29
+ additions = ActionController::Base.log_process_action(payload)
30
+ status = payload[:status]
31
+
32
+ if status.nil? && (exception_class_name = payload[:exception]&.first)
33
+ status = ActionDispatch::ExceptionWrapper.status_code_for_exception(exception_class_name)
34
+ end
35
+
36
+ additions << "GC: #{event.gc_time.round(1)}ms"
37
+
38
+ message = +"Completed #{status} #{Rack::Utils::HTTP_STATUS_CODES[status]} in #{event.duration.round}ms" \
39
+ " (#{additions.join(" | ")})"
40
+ message << "\n\n" if defined?(Rails.env) && Rails.env.development?
41
+
42
+ message
43
+ end
44
+ end
45
+ subscribe_log_level :process_action, :info
46
+
47
+ def halted_callback(event)
48
+ info { "Filter chain halted as #{event.payload[:filter].inspect} rendered or redirected" }
49
+ end
50
+ subscribe_log_level :halted_callback, :info
51
+
52
+ def send_file(event)
53
+ info { "Sent file #{event.payload[:path]} (#{event.duration.round(1)}ms)" }
54
+ end
55
+ subscribe_log_level :send_file, :info
56
+
57
+ def redirect_to(event)
58
+ info { "Redirected to #{event.payload[:location]}" }
59
+ end
60
+ subscribe_log_level :redirect_to, :info
61
+
62
+ def send_data(event)
63
+ info { "Sent data #{event.payload[:filename]} (#{event.duration.round(1)}ms)" }
64
+ end
65
+ subscribe_log_level :send_data, :info
66
+
67
+ def unpermitted_parameters(event)
68
+ debug do
69
+ unpermitted_keys = event.payload[:keys]
70
+ display_unpermitted_keys = unpermitted_keys.map { |e| ":#{e}" }.join(", ")
71
+ context = event.payload[:context].map { |k, v| "#{k}: #{v}" }.join(", ")
72
+ color("Unpermitted parameter#{'s' if unpermitted_keys.size > 1}: #{display_unpermitted_keys}. Context: { #{context} }", RED)
73
+ end
74
+ end
75
+ subscribe_log_level :unpermitted_parameters, :debug
76
+
77
+ %w(write_fragment read_fragment exist_fragment? expire_fragment).each do |method|
78
+ class_eval <<-METHOD, __FILE__, __LINE__ + 1
79
+ # frozen_string_literal: true
80
+ def #{method}(event)
81
+ return unless ActionController::Base.enable_fragment_cache_logging
82
+ key = ActiveSupport::Cache.expand_cache_key(event.payload[:key] || event.payload[:path])
83
+ human_name = #{method.to_s.humanize.inspect}
84
+ info("\#{human_name} \#{key} (\#{event.duration.round(1)}ms)")
85
+ end
86
+ subscribe_log_level :#{method}, :info
87
+ METHOD
88
+ end
89
+
90
+ def logger
91
+ ActionController::Base.logger
92
+ end
93
+ end
94
+ end
95
+
96
+ ActionController::LogSubscriber.attach_to :action_controller
@@ -0,0 +1,123 @@
1
+ # frozen_string_literal: true
2
+
3
+ # :markup: markdown
4
+
5
+ module ActionController # :nodoc:
6
+ module AllowBrowser
7
+ extend ActiveSupport::Concern
8
+
9
+ module ClassMethods
10
+ # Specify the browser versions that will be allowed to access all actions (or
11
+ # some, as limited by `only:` or `except:`). Only browsers matched in the hash
12
+ # or named set passed to `versions:` will be blocked if they're below the
13
+ # versions specified. This means that all other browsers, as well as agents that
14
+ # aren't reporting a user-agent header, will be allowed access.
15
+ #
16
+ # A browser that's blocked will by default be served the file in
17
+ # public/406-unsupported-browser.html with a HTTP status code of "406 Not
18
+ # Acceptable".
19
+ #
20
+ # In addition to specifically named browser versions, you can also pass
21
+ # `:modern` as the set to restrict support to browsers natively supporting webp
22
+ # images, web push, badges, import maps, CSS nesting, and CSS :has. This
23
+ # includes Safari 17.2+, Chrome 120+, Firefox 121+, Opera 106+.
24
+ #
25
+ # You can use https://caniuse.com to check for browser versions supporting the
26
+ # features you use.
27
+ #
28
+ # You can use `ActiveSupport::Notifications` to subscribe to events of browsers
29
+ # being blocked using the `browser_block.action_controller` event name.
30
+ #
31
+ # Examples:
32
+ #
33
+ # class ApplicationController < ActionController::Base
34
+ # # Allow only browsers natively supporting webp images, web push, badges, import maps, CSS nesting, and CSS :has
35
+ # allow_browser versions: :modern
36
+ # end
37
+ #
38
+ # class ApplicationController < ActionController::Base
39
+ # # All versions of Chrome and Opera will be allowed, but no versions of "internet explorer" (ie). Safari needs to be 16.4+ and Firefox 121+.
40
+ # allow_browser versions: { safari: 16.4, firefox: 121, ie: false }
41
+ # end
42
+ #
43
+ # class MessagesController < ApplicationController
44
+ # # In addition to the browsers blocked by ApplicationController, also block Opera below 104 and Chrome below 119 for the show action.
45
+ # allow_browser versions: { opera: 104, chrome: 119 }, only: :show
46
+ # end
47
+ def allow_browser(versions:, block: -> { render file: Rails.root.join("public/406-unsupported-browser.html"), layout: false, status: :not_acceptable }, **options)
48
+ before_action -> { allow_browser(versions: versions, block: block) }, **options
49
+ end
50
+ end
51
+
52
+ private
53
+ def allow_browser(versions:, block:)
54
+ require "useragent"
55
+
56
+ if BrowserBlocker.new(request, versions: versions).blocked?
57
+ ActiveSupport::Notifications.instrument("browser_block.action_controller", request: request, versions: versions) do
58
+ instance_exec(&block)
59
+ end
60
+ end
61
+ end
62
+
63
+ class BrowserBlocker
64
+ SETS = {
65
+ modern: { safari: 17.2, chrome: 120, firefox: 121, opera: 106, ie: false }
66
+ }
67
+
68
+ attr_reader :request, :versions
69
+
70
+ def initialize(request, versions:)
71
+ @request, @versions = request, versions
72
+ end
73
+
74
+ def blocked?
75
+ user_agent_version_reported? && unsupported_browser?
76
+ end
77
+
78
+ private
79
+ def parsed_user_agent
80
+ @parsed_user_agent ||= UserAgent.parse(request.user_agent)
81
+ end
82
+
83
+ def user_agent_version_reported?
84
+ request.user_agent.present? && parsed_user_agent.version.to_s.present?
85
+ end
86
+
87
+ def unsupported_browser?
88
+ version_guarded_browser? && version_below_minimum_required? && !bot?
89
+ end
90
+
91
+ def version_guarded_browser?
92
+ minimum_browser_version_for_browser != nil
93
+ end
94
+
95
+ def bot?
96
+ parsed_user_agent.bot?
97
+ end
98
+
99
+ def version_below_minimum_required?
100
+ if minimum_browser_version_for_browser
101
+ parsed_user_agent.version < UserAgent::Version.new(minimum_browser_version_for_browser.to_s)
102
+ else
103
+ true
104
+ end
105
+ end
106
+
107
+ def minimum_browser_version_for_browser
108
+ expanded_versions[normalized_browser_name]
109
+ end
110
+
111
+ def expanded_versions
112
+ @expanded_versions ||= (SETS[versions] || versions).with_indifferent_access
113
+ end
114
+
115
+ def normalized_browser_name
116
+ case name = parsed_user_agent.browser.downcase
117
+ when "internet explorer" then "ie"
118
+ else name
119
+ end
120
+ end
121
+ end
122
+ end
123
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ # :markup: markdown
4
+
5
+ module ActionController
6
+ module BasicImplicitRender # :nodoc:
7
+ def send_action(method, *args)
8
+ ret = super
9
+ default_render unless performed?
10
+ ret
11
+ end
12
+
13
+ def default_render
14
+ head :no_content
15
+ end
16
+ end
17
+ end