omg-actionpack 8.0.0.alpha1

Sign up to get free protection for your applications and to get access to all the features.
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