actionpack 7.0.4 → 7.1.3.4

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of actionpack might be problematic. Click here for more details.

Files changed (140) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +397 -269
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +4 -4
  5. data/lib/abstract_controller/base.rb +20 -11
  6. data/lib/abstract_controller/caching/fragments.rb +2 -0
  7. data/lib/abstract_controller/callbacks.rb +31 -6
  8. data/lib/abstract_controller/deprecator.rb +7 -0
  9. data/lib/abstract_controller/helpers.rb +75 -28
  10. data/lib/abstract_controller/railties/routes_helpers.rb +1 -16
  11. data/lib/abstract_controller/rendering.rb +12 -14
  12. data/lib/abstract_controller/translation.rb +9 -6
  13. data/lib/abstract_controller/url_for.rb +2 -0
  14. data/lib/abstract_controller.rb +6 -0
  15. data/lib/action_controller/api.rb +6 -4
  16. data/lib/action_controller/base.rb +3 -17
  17. data/lib/action_controller/caching.rb +2 -0
  18. data/lib/action_controller/deprecator.rb +7 -0
  19. data/lib/action_controller/form_builder.rb +2 -0
  20. data/lib/action_controller/log_subscriber.rb +16 -4
  21. data/lib/action_controller/metal/basic_implicit_render.rb +3 -1
  22. data/lib/action_controller/metal/conditional_get.rb +121 -123
  23. data/lib/action_controller/metal/content_security_policy.rb +5 -5
  24. data/lib/action_controller/metal/data_streaming.rb +20 -18
  25. data/lib/action_controller/metal/default_headers.rb +2 -0
  26. data/lib/action_controller/metal/etag_with_flash.rb +3 -1
  27. data/lib/action_controller/metal/etag_with_template_digest.rb +2 -0
  28. data/lib/action_controller/metal/exceptions.rb +8 -0
  29. data/lib/action_controller/metal/head.rb +9 -7
  30. data/lib/action_controller/metal/helpers.rb +3 -14
  31. data/lib/action_controller/metal/http_authentication.rb +17 -8
  32. data/lib/action_controller/metal/implicit_render.rb +5 -3
  33. data/lib/action_controller/metal/instrumentation.rb +8 -1
  34. data/lib/action_controller/metal/live.rb +25 -1
  35. data/lib/action_controller/metal/mime_responds.rb +2 -2
  36. data/lib/action_controller/metal/params_wrapper.rb +4 -2
  37. data/lib/action_controller/metal/permissions_policy.rb +2 -2
  38. data/lib/action_controller/metal/redirecting.rb +29 -8
  39. data/lib/action_controller/metal/renderers.rb +4 -4
  40. data/lib/action_controller/metal/rendering.rb +114 -9
  41. data/lib/action_controller/metal/request_forgery_protection.rb +144 -53
  42. data/lib/action_controller/metal/rescue.rb +6 -3
  43. data/lib/action_controller/metal/streaming.rb +71 -31
  44. data/lib/action_controller/metal/strong_parameters.rb +158 -101
  45. data/lib/action_controller/metal/url_for.rb +9 -4
  46. data/lib/action_controller/metal.rb +79 -21
  47. data/lib/action_controller/railtie.rb +24 -10
  48. data/lib/action_controller/renderer.rb +99 -85
  49. data/lib/action_controller/test_case.rb +15 -5
  50. data/lib/action_controller.rb +8 -1
  51. data/lib/action_dispatch/constants.rb +32 -0
  52. data/lib/action_dispatch/deprecator.rb +7 -0
  53. data/lib/action_dispatch/http/cache.rb +9 -11
  54. data/lib/action_dispatch/http/content_security_policy.rb +14 -9
  55. data/lib/action_dispatch/http/filter_parameters.rb +14 -28
  56. data/lib/action_dispatch/http/headers.rb +3 -1
  57. data/lib/action_dispatch/http/mime_negotiation.rb +22 -22
  58. data/lib/action_dispatch/http/mime_type.rb +35 -12
  59. data/lib/action_dispatch/http/mime_types.rb +3 -1
  60. data/lib/action_dispatch/http/parameters.rb +1 -1
  61. data/lib/action_dispatch/http/permissions_policy.rb +38 -23
  62. data/lib/action_dispatch/http/rack_cache.rb +2 -0
  63. data/lib/action_dispatch/http/request.rb +63 -30
  64. data/lib/action_dispatch/http/response.rb +80 -63
  65. data/lib/action_dispatch/http/upload.rb +15 -2
  66. data/lib/action_dispatch/journey/formatter.rb +8 -2
  67. data/lib/action_dispatch/journey/path/pattern.rb +14 -14
  68. data/lib/action_dispatch/journey/route.rb +3 -2
  69. data/lib/action_dispatch/journey/router.rb +9 -8
  70. data/lib/action_dispatch/journey/routes.rb +2 -2
  71. data/lib/action_dispatch/log_subscriber.rb +23 -0
  72. data/lib/action_dispatch/middleware/actionable_exceptions.rb +5 -6
  73. data/lib/action_dispatch/middleware/assume_ssl.rb +24 -0
  74. data/lib/action_dispatch/middleware/callbacks.rb +2 -0
  75. data/lib/action_dispatch/middleware/cookies.rb +108 -117
  76. data/lib/action_dispatch/middleware/debug_exceptions.rb +26 -25
  77. data/lib/action_dispatch/middleware/debug_locks.rb +4 -1
  78. data/lib/action_dispatch/middleware/debug_view.rb +7 -2
  79. data/lib/action_dispatch/middleware/exception_wrapper.rb +186 -27
  80. data/lib/action_dispatch/middleware/executor.rb +1 -1
  81. data/lib/action_dispatch/middleware/flash.rb +7 -0
  82. data/lib/action_dispatch/middleware/host_authorization.rb +18 -8
  83. data/lib/action_dispatch/middleware/public_exceptions.rb +5 -3
  84. data/lib/action_dispatch/middleware/reloader.rb +7 -5
  85. data/lib/action_dispatch/middleware/remote_ip.rb +21 -20
  86. data/lib/action_dispatch/middleware/request_id.rb +4 -2
  87. data/lib/action_dispatch/middleware/server_timing.rb +4 -4
  88. data/lib/action_dispatch/middleware/session/abstract_store.rb +5 -0
  89. data/lib/action_dispatch/middleware/session/cache_store.rb +2 -0
  90. data/lib/action_dispatch/middleware/session/cookie_store.rb +11 -5
  91. data/lib/action_dispatch/middleware/session/mem_cache_store.rb +3 -1
  92. data/lib/action_dispatch/middleware/show_exceptions.rb +25 -18
  93. data/lib/action_dispatch/middleware/ssl.rb +18 -6
  94. data/lib/action_dispatch/middleware/stack.rb +7 -2
  95. data/lib/action_dispatch/middleware/static.rb +14 -10
  96. data/lib/action_dispatch/middleware/templates/rescues/_actions.html.erb +2 -2
  97. data/lib/action_dispatch/middleware/templates/rescues/_message_and_suggestions.html.erb +4 -4
  98. data/lib/action_dispatch/middleware/templates/rescues/_source.html.erb +8 -1
  99. data/lib/action_dispatch/middleware/templates/rescues/blocked_host.html.erb +7 -3
  100. data/lib/action_dispatch/middleware/templates/rescues/blocked_host.text.erb +5 -3
  101. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb +7 -7
  102. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.text.erb +2 -2
  103. data/lib/action_dispatch/middleware/templates/rescues/layout.erb +17 -0
  104. data/lib/action_dispatch/middleware/templates/rescues/missing_exact_template.html.erb +16 -12
  105. data/lib/action_dispatch/middleware/templates/rescues/missing_template.html.erb +1 -1
  106. data/lib/action_dispatch/middleware/templates/rescues/routing_error.html.erb +3 -3
  107. data/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb +4 -4
  108. data/lib/action_dispatch/middleware/templates/rescues/unknown_action.html.erb +1 -1
  109. data/lib/action_dispatch/middleware/templates/rescues/unknown_action.text.erb +1 -1
  110. data/lib/action_dispatch/middleware/templates/routes/_route.html.erb +3 -0
  111. data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +59 -41
  112. data/lib/action_dispatch/railtie.rb +14 -4
  113. data/lib/action_dispatch/request/session.rb +16 -6
  114. data/lib/action_dispatch/request/utils.rb +8 -3
  115. data/lib/action_dispatch/routing/inspector.rb +54 -6
  116. data/lib/action_dispatch/routing/mapper.rb +58 -24
  117. data/lib/action_dispatch/routing/polymorphic_routes.rb +2 -0
  118. data/lib/action_dispatch/routing/redirection.rb +15 -6
  119. data/lib/action_dispatch/routing/route_set.rb +52 -22
  120. data/lib/action_dispatch/routing/routes_proxy.rb +10 -15
  121. data/lib/action_dispatch/routing/url_for.rb +26 -22
  122. data/lib/action_dispatch/routing.rb +7 -7
  123. data/lib/action_dispatch/system_test_case.rb +3 -3
  124. data/lib/action_dispatch/system_testing/browser.rb +20 -19
  125. data/lib/action_dispatch/system_testing/driver.rb +14 -22
  126. data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +27 -16
  127. data/lib/action_dispatch/testing/assertion_response.rb +1 -1
  128. data/lib/action_dispatch/testing/assertions/response.rb +14 -7
  129. data/lib/action_dispatch/testing/assertions/routing.rb +67 -28
  130. data/lib/action_dispatch/testing/assertions.rb +3 -1
  131. data/lib/action_dispatch/testing/integration.rb +27 -17
  132. data/lib/action_dispatch/testing/request_encoder.rb +4 -1
  133. data/lib/action_dispatch/testing/test_process.rb +4 -3
  134. data/lib/action_dispatch/testing/test_request.rb +1 -1
  135. data/lib/action_dispatch/testing/test_response.rb +23 -9
  136. data/lib/action_dispatch.rb +37 -4
  137. data/lib/action_pack/gem_version.rb +4 -4
  138. data/lib/action_pack/version.rb +1 -1
  139. data/lib/action_pack.rb +1 -1
  140. metadata +65 -29
@@ -8,7 +8,10 @@ module ActionController
8
8
  return unless logger.info?
9
9
 
10
10
  payload = event.payload
11
- params = payload[:params].except(*INTERNAL_PARAMS)
11
+ params = {}
12
+ payload[:params].each_pair do |k, v|
13
+ params[k] = v unless INTERNAL_PARAMS.include?(k)
14
+ end
12
15
  format = payload[:format]
13
16
  format = format.to_s.upcase if format.is_a?(Symbol)
14
17
  format = "*/*" if format.nil?
@@ -16,6 +19,7 @@ module ActionController
16
19
  info "Processing by #{payload[:controller]}##{payload[:action]} as #{format}"
17
20
  info " Parameters: #{params.inspect}" unless params.empty?
18
21
  end
22
+ subscribe_log_level :start_processing, :info
19
23
 
20
24
  def process_action(event)
21
25
  info do
@@ -29,29 +33,34 @@ module ActionController
29
33
 
30
34
  additions << "Allocations: #{event.allocations}"
31
35
 
32
- message = +"Completed #{status} #{Rack::Utils::HTTP_STATUS_CODES[status]} in #{event.duration.round}ms"
33
- message << " (#{additions.join(" | ")})"
36
+ message = +"Completed #{status} #{Rack::Utils::HTTP_STATUS_CODES[status]} in #{event.duration.round}ms" \
37
+ " (#{additions.join(" | ")})"
34
38
  message << "\n\n" if defined?(Rails.env) && Rails.env.development?
35
39
 
36
40
  message
37
41
  end
38
42
  end
43
+ subscribe_log_level :process_action, :info
39
44
 
40
45
  def halted_callback(event)
41
46
  info { "Filter chain halted as #{event.payload[:filter].inspect} rendered or redirected" }
42
47
  end
48
+ subscribe_log_level :halted_callback, :info
43
49
 
44
50
  def send_file(event)
45
51
  info { "Sent file #{event.payload[:path]} (#{event.duration.round(1)}ms)" }
46
52
  end
53
+ subscribe_log_level :send_file, :info
47
54
 
48
55
  def redirect_to(event)
49
56
  info { "Redirected to #{event.payload[:location]}" }
50
57
  end
58
+ subscribe_log_level :redirect_to, :info
51
59
 
52
60
  def send_data(event)
53
61
  info { "Sent data #{event.payload[:filename]} (#{event.duration.round(1)}ms)" }
54
62
  end
63
+ subscribe_log_level :send_data, :info
55
64
 
56
65
  def unpermitted_parameters(event)
57
66
  debug do
@@ -61,15 +70,18 @@ module ActionController
61
70
  color("Unpermitted parameter#{'s' if unpermitted_keys.size > 1}: #{display_unpermitted_keys}. Context: { #{context} }", RED)
62
71
  end
63
72
  end
73
+ subscribe_log_level :unpermitted_parameters, :debug
64
74
 
65
75
  %w(write_fragment read_fragment exist_fragment? expire_fragment).each do |method|
66
76
  class_eval <<-METHOD, __FILE__, __LINE__ + 1
77
+ # frozen_string_literal: true
67
78
  def #{method}(event)
68
- return unless logger.info? && ActionController::Base.enable_fragment_cache_logging
79
+ return unless ActionController::Base.enable_fragment_cache_logging
69
80
  key = ActiveSupport::Cache.expand_cache_key(event.payload[:key] || event.payload[:path])
70
81
  human_name = #{method.to_s.humanize.inspect}
71
82
  info("\#{human_name} \#{key} (\#{event.duration.round(1)}ms)")
72
83
  end
84
+ subscribe_log_level :#{method}, :info
73
85
  METHOD
74
86
  end
75
87
 
@@ -3,7 +3,9 @@
3
3
  module ActionController
4
4
  module BasicImplicitRender # :nodoc:
5
5
  def send_action(method, *args)
6
- super.tap { default_render unless performed? }
6
+ ret = super
7
+ default_render unless performed?
8
+ ret
7
9
  end
8
10
 
9
11
  def default_render
@@ -33,86 +33,97 @@ module ActionController
33
33
  end
34
34
  end
35
35
 
36
- # Sets the +etag+, +last_modified+, or both on the response and renders a
36
+ # Sets the +etag+, +last_modified+, or both on the response, and renders a
37
37
  # <tt>304 Not Modified</tt> response if the request is already fresh.
38
38
  #
39
- # === Parameters:
40
- #
41
- # * <tt>:etag</tt> Sets a "weak" ETag validator on the response. See the
42
- # +:weak_etag+ option.
43
- # * <tt>:weak_etag</tt> Sets a "weak" ETag validator on the response.
44
- # Requests that set If-None-Match header may return a 304 Not Modified
45
- # response if it matches the ETag exactly. A weak ETag indicates semantic
46
- # equivalence, not byte-for-byte equality, so they're good for caching
47
- # HTML pages in browser caches. They can't be used for responses that
48
- # must be byte-identical, like serving Range requests within a PDF file.
49
- # * <tt>:strong_etag</tt> Sets a "strong" ETag validator on the response.
50
- # Requests that set If-None-Match header may return a 304 Not Modified
51
- # response if it matches the ETag exactly. A strong ETag implies exact
52
- # equality: the response must match byte for byte. This is necessary for
53
- # doing Range requests within a large video or PDF file, for example, or
54
- # for compatibility with some CDNs that don't support weak ETags.
55
- # * <tt>:last_modified</tt> Sets a "weak" last-update validator on the
56
- # response. Subsequent requests that set If-Modified-Since may return a
57
- # 304 Not Modified response if last_modified <= If-Modified-Since.
58
- # * <tt>:public</tt> By default the Cache-Control header is private, set this to
59
- # +true+ if you want your application to be cacheable by other devices (proxy caches).
60
- # * <tt>:cache_control</tt> When given will overwrite an existing Cache-Control header.
61
- # See https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html for more possibilities.
62
- # * <tt>:template</tt> By default, the template digest for the current
63
- # controller/action is included in ETags. If the action renders a
64
- # different template, you can include its digest instead. If the action
65
- # doesn't render a template at all, you can pass <tt>template: false</tt>
66
- # to skip any attempt to check for a template digest.
67
- #
68
- # === Example:
39
+ # ==== Options
40
+ #
41
+ # [+:etag+]
42
+ # Sets a "weak" ETag validator on the response. See the +:weak_etag+ option.
43
+ # [+:weak_etag+]
44
+ # Sets a "weak" ETag validator on the response. Requests that specify an
45
+ # +If-None-Match+ header may receive a <tt>304 Not Modified</tt> response
46
+ # if the ETag matches exactly.
47
+ #
48
+ # A weak ETag indicates semantic equivalence, not byte-for-byte equality,
49
+ # so they're good for caching HTML pages in browser caches. They can't be
50
+ # used for responses that must be byte-identical, like serving +Range+
51
+ # requests within a PDF file.
52
+ # [+:strong_etag+]
53
+ # Sets a "strong" ETag validator on the response. Requests that specify an
54
+ # +If-None-Match+ header may receive a <tt>304 Not Modified</tt> response
55
+ # if the ETag matches exactly.
56
+ #
57
+ # A strong ETag implies exact equality -- the response must match byte for
58
+ # byte. This is necessary for serving +Range+ requests within a large
59
+ # video or PDF file, for example, or for compatibility with some CDNs that
60
+ # don't support weak ETags.
61
+ # [+:last_modified+]
62
+ # Sets a "weak" last-update validator on the response. Subsequent requests
63
+ # that specify an +If-Modified-Since+ header may receive a <tt>304 Not Modified</tt>
64
+ # response if +last_modified+ <= +If-Modified-Since+.
65
+ # [+:public+]
66
+ # By default the +Cache-Control+ header is private. Set this option to
67
+ # +true+ if you want your application to be cacheable by other devices,
68
+ # such as proxy caches.
69
+ # [+:cache_control+]
70
+ # When given, will overwrite an existing +Cache-Control+ header. For a
71
+ # list of +Cache-Control+ directives, see the {article on
72
+ # MDN}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control].
73
+ # [+:template+]
74
+ # By default, the template digest for the current controller/action is
75
+ # included in ETags. If the action renders a different template, you can
76
+ # include its digest instead. If the action doesn't render a template at
77
+ # all, you can pass <tt>template: false</tt> to skip any attempt to check
78
+ # for a template digest.
79
+ #
80
+ # ==== Examples
69
81
  #
70
82
  # def show
71
83
  # @article = Article.find(params[:id])
72
84
  # fresh_when(etag: @article, last_modified: @article.updated_at, public: true)
73
85
  # end
74
86
  #
75
- # This will render the show template if the request isn't sending a matching ETag or
76
- # If-Modified-Since header and just a <tt>304 Not Modified</tt> response if there's a match.
87
+ # This will send a <tt>304 Not Modified</tt> response if the request
88
+ # specifies a matching ETag and +If-Modified-Since+ header. Otherwise, it
89
+ # will render the +show+ template.
77
90
  #
78
- # You can also just pass a record. In this case +last_modified+ will be set
79
- # by calling +updated_at+ and +etag+ by passing the object itself.
91
+ # You can also just pass a record:
80
92
  #
81
93
  # def show
82
94
  # @article = Article.find(params[:id])
83
95
  # fresh_when(@article)
84
96
  # end
85
97
  #
98
+ # +etag+ will be set to the record, and +last_modified+ will be set to the
99
+ # record's +updated_at+.
100
+ #
86
101
  # You can also pass an object that responds to +maximum+, such as a
87
- # collection of active records. In this case +last_modified+ will be set by
88
- # calling <tt>maximum(:updated_at)</tt> on the collection (the timestamp of the
89
- # most recently updated record) and the +etag+ by passing the object itself.
102
+ # collection of records:
90
103
  #
91
104
  # def index
92
105
  # @articles = Article.all
93
106
  # fresh_when(@articles)
94
107
  # end
95
108
  #
96
- # When passing a record or a collection, you can still set the public header:
97
- #
98
- # def show
99
- # @article = Article.find(params[:id])
100
- # fresh_when(@article, public: true)
101
- # end
109
+ # In this case, +etag+ will be set to the collection, and +last_modified+
110
+ # will be set to <tt>maximum(:updated_at)</tt> (the timestamp of the most
111
+ # recently updated record).
102
112
  #
103
- # When overwriting Cache-Control header:
113
+ # When passing a record or a collection, you can still specify other
114
+ # options, such as +:public+ and +:cache_control+:
104
115
  #
105
116
  # def show
106
117
  # @article = Article.find(params[:id])
107
118
  # fresh_when(@article, public: true, cache_control: { no_cache: true })
108
119
  # end
109
120
  #
110
- # This will set in the response Cache-Control = public, no-cache.
121
+ # The above will set <tt>Cache-Control: public, no-cache</tt> in the response.
111
122
  #
112
- # When rendering a different template than the default controller/action
113
- # style, you can indicate which digest to include in the ETag:
123
+ # When rendering a different template than the controller/action's default
124
+ # template, you can indicate which digest to include in the ETag:
114
125
  #
115
- # before_action { fresh_when @article, template: 'widgets/show' }
126
+ # before_action { fresh_when @article, template: "widgets/show" }
116
127
  #
117
128
  def fresh_when(object = nil, etag: nil, weak_etag: nil, strong_etag: nil, last_modified: nil, public: false, cache_control: {}, template: nil)
118
129
  response.cache_control.delete(:no_store)
@@ -134,41 +145,16 @@ module ActionController
134
145
  head :not_modified if request.fresh?(response)
135
146
  end
136
147
 
137
- # Sets the +etag+ and/or +last_modified+ on the response and checks it against
138
- # the client request. If the request doesn't match the options provided, the
139
- # request is considered stale and should be generated from scratch. Otherwise,
140
- # it's fresh and we don't need to generate anything and a reply of <tt>304 Not Modified</tt> is sent.
141
- #
142
- # === Parameters:
143
- #
144
- # * <tt>:etag</tt> Sets a "weak" ETag validator on the response. See the
145
- # +:weak_etag+ option.
146
- # * <tt>:weak_etag</tt> Sets a "weak" ETag validator on the response.
147
- # Requests that set If-None-Match header may return a 304 Not Modified
148
- # response if it matches the ETag exactly. A weak ETag indicates semantic
149
- # equivalence, not byte-for-byte equality, so they're good for caching
150
- # HTML pages in browser caches. They can't be used for responses that
151
- # must be byte-identical, like serving Range requests within a PDF file.
152
- # * <tt>:strong_etag</tt> Sets a "strong" ETag validator on the response.
153
- # Requests that set If-None-Match header may return a 304 Not Modified
154
- # response if it matches the ETag exactly. A strong ETag implies exact
155
- # equality: the response must match byte for byte. This is necessary for
156
- # doing Range requests within a large video or PDF file, for example, or
157
- # for compatibility with some CDNs that don't support weak ETags.
158
- # * <tt>:last_modified</tt> Sets a "weak" last-update validator on the
159
- # response. Subsequent requests that set If-Modified-Since may return a
160
- # 304 Not Modified response if last_modified <= If-Modified-Since.
161
- # * <tt>:public</tt> By default the Cache-Control header is private, set this to
162
- # +true+ if you want your application to be cacheable by other devices (proxy caches).
163
- # * <tt>:cache_control</tt> When given will overwrite an existing Cache-Control header.
164
- # See https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html for more possibilities.
165
- # * <tt>:template</tt> By default, the template digest for the current
166
- # controller/action is included in ETags. If the action renders a
167
- # different template, you can include its digest instead. If the action
168
- # doesn't render a template at all, you can pass <tt>template: false</tt>
169
- # to skip any attempt to check for a template digest.
170
- #
171
- # === Example:
148
+ # Sets the +etag+ and/or +last_modified+ on the response and checks them
149
+ # against the request. If the request doesn't match the provided options, it
150
+ # is considered stale, and the response should be rendered from scratch.
151
+ # Otherwise, it is fresh, and a <tt>304 Not Modified</tt> is sent.
152
+ #
153
+ # ==== Options
154
+ #
155
+ # See #fresh_when for supported options.
156
+ #
157
+ # ==== Examples
172
158
  #
173
159
  # def show
174
160
  # @article = Article.find(params[:id])
@@ -181,8 +167,7 @@ module ActionController
181
167
  # end
182
168
  # end
183
169
  #
184
- # You can also just pass a record. In this case +last_modified+ will be set
185
- # by calling +updated_at+ and +etag+ by passing the object itself.
170
+ # You can also just pass a record:
186
171
  #
187
172
  # def show
188
173
  # @article = Article.find(params[:id])
@@ -195,10 +180,11 @@ module ActionController
195
180
  # end
196
181
  # end
197
182
  #
183
+ # +etag+ will be set to the record, and +last_modified+ will be set to the
184
+ # record's +updated_at+.
185
+ #
198
186
  # You can also pass an object that responds to +maximum+, such as a
199
- # collection of active records. In this case +last_modified+ will be set by
200
- # calling <tt>maximum(:updated_at)</tt> on the collection (the timestamp of the
201
- # most recently updated record) and the +etag+ by passing the object itself.
187
+ # collection of records:
202
188
  #
203
189
  # def index
204
190
  # @articles = Article.all
@@ -211,20 +197,12 @@ module ActionController
211
197
  # end
212
198
  # end
213
199
  #
214
- # When passing a record or a collection, you can still set the public header:
215
- #
216
- # def show
217
- # @article = Article.find(params[:id])
218
- #
219
- # if stale?(@article, public: true)
220
- # @statistics = @article.really_expensive_call
221
- # respond_to do |format|
222
- # # all the supported formats
223
- # end
224
- # end
225
- # end
200
+ # In this case, +etag+ will be set to the collection, and +last_modified+
201
+ # will be set to <tt>maximum(:updated_at)</tt> (the timestamp of the most
202
+ # recently updated record).
226
203
  #
227
- # When overwriting Cache-Control header:
204
+ # When passing a record or a collection, you can still specify other
205
+ # options, such as +:public+ and +:cache_control+:
228
206
  #
229
207
  # def show
230
208
  # @article = Article.find(params[:id])
@@ -237,13 +215,13 @@ module ActionController
237
215
  # end
238
216
  # end
239
217
  #
240
- # This will set in the response Cache-Control = public, no-cache.
218
+ # The above will set <tt>Cache-Control: public, no-cache</tt> in the response.
241
219
  #
242
- # When rendering a different template than the default controller/action
243
- # style, you can indicate which digest to include in the ETag:
220
+ # When rendering a different template than the controller/action's default
221
+ # template, you can indicate which digest to include in the ETag:
244
222
  #
245
223
  # def show
246
- # super if stale? @article, template: 'widgets/show'
224
+ # super if stale?(@article, template: "widgets/show")
247
225
  # end
248
226
  #
249
227
  def stale?(object = nil, **freshness_kwargs)
@@ -251,28 +229,48 @@ module ActionController
251
229
  !request.fresh?(response)
252
230
  end
253
231
 
254
- # Sets an HTTP 1.1 Cache-Control header. Defaults to issuing a +private+
255
- # instruction, so that intermediate caches must not cache the response.
232
+ # Sets the +Cache-Control+ header, overwriting existing directives. This
233
+ # method will also ensure an HTTP +Date+ header for client compatibility.
234
+ #
235
+ # Defaults to issuing the +private+ directive, so that intermediate caches
236
+ # must not cache the response.
237
+ #
238
+ # ==== Options
239
+ #
240
+ # [+:public+]
241
+ # If true, replaces the default +private+ directive with the +public+
242
+ # directive.
243
+ # [+:must_revalidate+]
244
+ # If true, adds the +must-revalidate+ directive.
245
+ # [+:stale_while_revalidate+]
246
+ # Sets the value of the +stale-while-revalidate+ directive.
247
+ # [+:stale_if_error+]
248
+ # Sets the value of the +stale-if-error+ directive.
249
+ #
250
+ # Any additional key-value pairs are concatenated as directives. For a list
251
+ # of supported +Cache-Control+ directives, see the {article on
252
+ # MDN}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control].
253
+ #
254
+ # ==== Examples
256
255
  #
257
- # expires_in 20.minutes
258
- # expires_in 3.hours, public: true
259
- # expires_in 3.hours, public: true, must_revalidate: true
256
+ # expires_in 10.minutes
257
+ # # => Cache-Control: max-age=600, private
260
258
  #
261
- # This method will overwrite an existing Cache-Control header.
262
- # See https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html for more possibilities.
259
+ # expires_in 10.minutes, public: true
260
+ # # => Cache-Control: max-age=600, public
263
261
  #
264
- # HTTP Cache-Control Extensions for Stale Content. See https://tools.ietf.org/html/rfc5861
265
- # It helps to cache an asset and serve it while is being revalidated and/or returning with an error.
262
+ # expires_in 10.minutes, public: true, must_revalidate: true
263
+ # # => Cache-Control: max-age=600, public, must-revalidate
266
264
  #
267
- # expires_in 3.hours, public: true, stale_while_revalidate: 60.seconds
268
- # expires_in 3.hours, public: true, stale_while_revalidate: 60.seconds, stale_if_error: 5.minutes
265
+ # expires_in 1.hour, stale_while_revalidate: 60.seconds
266
+ # # => Cache-Control: max-age=3600, private, stale-while-revalidate=60
269
267
  #
270
- # HTTP Cache-Control Extensions other values: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control
271
- # Any additional key-value pairs are concatenated onto the Cache-Control header in the response:
268
+ # expires_in 1.hour, stale_if_error: 5.minutes
269
+ # # => Cache-Control: max-age=3600, private, stale-if-error=300
272
270
  #
273
- # expires_in 3.hours, public: true, "s-maxage": 3.hours, "no-transform": true
271
+ # expires_in 1.hour, public: true, "s-maxage": 3.hours, "no-transform": true
272
+ # # => Cache-Control: max-age=3600, public, s-maxage=10800, no-transform=true
274
273
  #
275
- # The method will also ensure an HTTP Date header for client compatibility.
276
274
  def expires_in(seconds, options = {})
277
275
  response.cache_control.delete(:no_store)
278
276
  response.cache_control.merge!(
@@ -288,7 +286,7 @@ module ActionController
288
286
  response.date = Time.now unless response.date?
289
287
  end
290
288
 
291
- # Sets an HTTP 1.1 Cache-Control header of <tt>no-cache</tt>. This means the
289
+ # Sets an HTTP 1.1 +Cache-Control+ header of <tt>no-cache</tt>. This means the
292
290
  # resource will be marked as stale, so clients must always revalidate.
293
291
  # Intermediate/browser caches may still store the asset.
294
292
  def expires_now
@@ -311,7 +309,7 @@ module ActionController
311
309
  public: public)
312
310
  end
313
311
 
314
- # Sets an HTTP 1.1 Cache-Control header of <tt>no-store</tt>. This means the
312
+ # Sets an HTTP 1.1 +Cache-Control+ header of <tt>no-store</tt>. This means the
315
313
  # resource may not be stored in any cache.
316
314
  def no_store
317
315
  response.cache_control.replace(no_store: true)
@@ -13,7 +13,7 @@ module ActionController # :nodoc:
13
13
  end
14
14
 
15
15
  module ClassMethods
16
- # Overrides parts of the globally configured Content-Security-Policy
16
+ # Overrides parts of the globally configured +Content-Security-Policy+
17
17
  # header:
18
18
  #
19
19
  # class PostsController < ApplicationController
@@ -31,7 +31,7 @@ module ActionController # :nodoc:
31
31
  # end
32
32
  # end
33
33
  #
34
- # Pass +false+ to remove the Content-Security-Policy header:
34
+ # Pass +false+ to remove the +Content-Security-Policy+ header:
35
35
  #
36
36
  # class PostsController < ApplicationController
37
37
  # content_security_policy false, only: :index
@@ -40,7 +40,7 @@ module ActionController # :nodoc:
40
40
  before_action(options) do
41
41
  if block_given?
42
42
  policy = current_content_security_policy
43
- yield policy
43
+ instance_exec(policy, &block)
44
44
  request.content_security_policy = policy
45
45
  end
46
46
 
@@ -50,14 +50,14 @@ module ActionController # :nodoc:
50
50
  end
51
51
  end
52
52
 
53
- # Overrides the globally configured Content-Security-Policy-Report-Only
53
+ # Overrides the globally configured +Content-Security-Policy-Report-Only+
54
54
  # header:
55
55
  #
56
56
  # class PostsController < ApplicationController
57
57
  # content_security_policy_report_only only: :index
58
58
  # end
59
59
  #
60
- # Pass +false+ to remove the Content-Security-Policy-Report-Only header:
60
+ # Pass +false+ to remove the +Content-Security-Policy-Report-Only+ header:
61
61
  #
62
62
  # class PostsController < ApplicationController
63
63
  # content_security_policy_report_only false, only: :index
@@ -4,6 +4,8 @@ require "action_controller/metal/exceptions"
4
4
  require "action_dispatch/http/content_disposition"
5
5
 
6
6
  module ActionController # :nodoc:
7
+ # = Action Controller Data \Streaming
8
+ #
7
9
  # Methods for sending arbitrary data and for streaming files to the browser,
8
10
  # instead of rendering.
9
11
  module DataStreaming
@@ -15,10 +17,10 @@ module ActionController # :nodoc:
15
17
  DEFAULT_SEND_FILE_DISPOSITION = "attachment" # :nodoc:
16
18
 
17
19
  private
18
- # Sends the file. This uses a server-appropriate method (such as X-Sendfile)
19
- # via the Rack::Sendfile middleware. The header to use is set via
20
+ # Sends the file. This uses a server-appropriate method (such as +X-Sendfile+)
21
+ # via the +Rack::Sendfile+ middleware. The header to use is set via
20
22
  # +config.action_dispatch.x_sendfile_header+.
21
- # Your server can also configure this for you by setting the X-Sendfile-Type header.
23
+ # Your server can also configure this for you by setting the +X-Sendfile-Type+ header.
22
24
  #
23
25
  # Be careful to sanitize the path parameter if it is coming from a web
24
26
  # page. <tt>send_file(params[:path])</tt> allows a malicious user to
@@ -28,17 +30,17 @@ module ActionController # :nodoc:
28
30
  # * <tt>:filename</tt> - suggests a filename for the browser to use.
29
31
  # Defaults to <tt>File.basename(path)</tt>.
30
32
  # * <tt>:type</tt> - specifies an HTTP content type.
31
- # You can specify either a string or a symbol for a registered type with <tt>Mime::Type.register</tt>, for example :json.
33
+ # You can specify either a string or a symbol for a registered type with <tt>Mime::Type.register</tt>, for example +:json+.
32
34
  # If omitted, the type will be inferred from the file extension specified in <tt>:filename</tt>.
33
- # If no content type is registered for the extension, the default type 'application/octet-stream' will be used.
35
+ # If no content type is registered for the extension, the default type +application/octet-stream+ will be used.
34
36
  # * <tt>:disposition</tt> - specifies whether the file will be shown inline or downloaded.
35
- # Valid values are 'inline' and 'attachment' (default).
37
+ # Valid values are <tt>"inline"</tt> and <tt>"attachment"</tt> (default).
36
38
  # * <tt>:status</tt> - specifies the status code to send with the response. Defaults to 200.
37
39
  # * <tt>:url_based_filename</tt> - set to +true+ if you want the browser to guess the filename from
38
40
  # the URL, which is necessary for i18n filenames on certain browsers
39
41
  # (setting <tt>:filename</tt> overrides this option).
40
42
  #
41
- # The default Content-Type and Content-Disposition headers are
43
+ # The default +Content-Type+ and +Content-Disposition+ headers are
42
44
  # set to download arbitrary binary files in as many browsers as
43
45
  # possible. IE versions 4, 5, 5.5, and 6 are all known to have
44
46
  # a variety of quirks (especially when downloading over SSL).
@@ -55,17 +57,17 @@ module ActionController # :nodoc:
55
57
  #
56
58
  # send_file '/path/to/404.html', type: 'text/html; charset=utf-8', disposition: 'inline', status: 404
57
59
  #
58
- # Read about the other Content-* HTTP headers if you'd like to
59
- # provide the user with more information (such as Content-Description) in
60
- # https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.11.
60
+ # You can use other <tt>Content-*</tt> HTTP headers to provide additional
61
+ # information to the client. See MDN for a
62
+ # {list of HTTP headers}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers].
61
63
  #
62
64
  # Also be aware that the document may be cached by proxies and browsers.
63
- # The Pragma and Cache-Control headers declare how the file may be cached
65
+ # The +Pragma+ and +Cache-Control+ headers declare how the file may be cached
64
66
  # by intermediaries. They default to require clients to validate with
65
67
  # the server before releasing cached responses. See
66
68
  # https://www.mnot.net/cache_docs/ for an overview of web caching and
67
- # https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9
68
- # for the Cache-Control header spec.
69
+ # {RFC 9111}[https://www.rfc-editor.org/rfc/rfc9111.html#name-cache-control]
70
+ # for the +Cache-Control+ header spec.
69
71
  def send_file(path, options = {}) # :doc:
70
72
  raise MissingFile, "Cannot read file #{path}" unless File.file?(path) && File.readable?(path)
71
73
 
@@ -85,12 +87,12 @@ module ActionController # :nodoc:
85
87
  #
86
88
  # Options:
87
89
  # * <tt>:filename</tt> - suggests a filename for the browser to use.
88
- # * <tt>:type</tt> - specifies an HTTP content type. Defaults to 'application/octet-stream'.
89
- # You can specify either a string or a symbol for a registered type with <tt>Mime::Type.register</tt>, for example :json.
90
+ # * <tt>:type</tt> - specifies an HTTP content type. Defaults to +application/octet-stream+.
91
+ # You can specify either a string or a symbol for a registered type with <tt>Mime::Type.register</tt>, for example +:json+.
90
92
  # If omitted, type will be inferred from the file extension specified in <tt>:filename</tt>.
91
- # If no content type is registered for the extension, the default type 'application/octet-stream' will be used.
93
+ # If no content type is registered for the extension, the default type +application/octet-stream+ will be used.
92
94
  # * <tt>:disposition</tt> - specifies whether the file will be shown inline or downloaded.
93
- # Valid values are 'inline' and 'attachment' (default).
95
+ # Valid values are <tt>"inline"</tt> and <tt>"attachment"</tt> (default).
94
96
  # * <tt>:status</tt> - specifies the status code to send with the response. Defaults to 200.
95
97
  #
96
98
  # Generic data download:
@@ -105,7 +107,7 @@ module ActionController # :nodoc:
105
107
  #
106
108
  # send_data image.data, type: image.content_type, disposition: 'inline'
107
109
  #
108
- # See +send_file+ for more information on HTTP Content-* headers and caching.
110
+ # See +send_file+ for more information on HTTP <tt>Content-*</tt> headers and caching.
109
111
  def send_data(data, options = {}) # :doc:
110
112
  send_file_headers! options
111
113
  render options.slice(:status, :content_type).merge(body: data)
@@ -1,6 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ActionController
4
+ # = Action Controller Default Headers
5
+ #
4
6
  # Allows configuring default headers that will be automatically merged into
5
7
  # each response.
6
8
  module DefaultHeaders
@@ -1,6 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ActionController
4
+ # = Action Controller Etag With \Flash
5
+ #
4
6
  # When you're using the flash, it's generally used as a conditional on the view.
5
7
  # This means the content of the view depends on the flash. Which in turn means
6
8
  # that the ETag for a response should be computed with the content of the flash
@@ -12,7 +14,7 @@ module ActionController
12
14
  include ActionController::ConditionalGet
13
15
 
14
16
  included do
15
- etag { flash unless flash.empty? }
17
+ etag { flash if request.respond_to?(:flash) && !flash.empty? }
16
18
  end
17
19
  end
18
20
  end
@@ -1,6 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ActionController
4
+ # = Action Controller Etag With Template \Digest
5
+ #
4
6
  # When our views change, they should bubble up into HTTP cache freshness
5
7
  # and bust browser caches. So the template digest for the current action
6
8
  # is automatically included in the ETag.
@@ -92,5 +92,13 @@ module ActionController
92
92
  end
93
93
 
94
94
  class MissingExactTemplate < UnknownFormat # :nodoc:
95
+ attr_reader :controller, :action_name
96
+
97
+ def initialize(message, controller, action_name)
98
+ @controller = controller
99
+ @action_name = action_name
100
+
101
+ super(message)
102
+ end
95
103
  end
96
104
  end