actionpack 7.2.0 → 8.0.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (33) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +86 -98
  3. data/lib/action_controller/api.rb +1 -0
  4. data/lib/action_controller/metal/conditional_get.rb +6 -3
  5. data/lib/action_controller/metal/http_authentication.rb +2 -2
  6. data/lib/action_controller/metal/instrumentation.rb +1 -2
  7. data/lib/action_controller/metal/live.rb +19 -8
  8. data/lib/action_controller/metal/rate_limiting.rb +13 -4
  9. data/lib/action_controller/metal/renderers.rb +2 -1
  10. data/lib/action_controller/metal/streaming.rb +5 -84
  11. data/lib/action_controller/metal/strong_parameters.rb +274 -73
  12. data/lib/action_controller/railtie.rb +1 -1
  13. data/lib/action_controller/test_case.rb +4 -3
  14. data/lib/action_dispatch/http/cache.rb +27 -10
  15. data/lib/action_dispatch/http/content_security_policy.rb +1 -0
  16. data/lib/action_dispatch/http/permissions_policy.rb +2 -0
  17. data/lib/action_dispatch/http/request.rb +26 -5
  18. data/lib/action_dispatch/journey/parser.rb +99 -196
  19. data/lib/action_dispatch/journey/scanner.rb +40 -42
  20. data/lib/action_dispatch/middleware/cookies.rb +4 -2
  21. data/lib/action_dispatch/middleware/debug_exceptions.rb +16 -3
  22. data/lib/action_dispatch/middleware/remote_ip.rb +5 -6
  23. data/lib/action_dispatch/middleware/request_id.rb +2 -1
  24. data/lib/action_dispatch/middleware/ssl.rb +14 -4
  25. data/lib/action_dispatch/railtie.rb +2 -0
  26. data/lib/action_dispatch/routing/inspector.rb +1 -1
  27. data/lib/action_dispatch/routing/mapper.rb +26 -17
  28. data/lib/action_dispatch/routing/route_set.rb +18 -6
  29. data/lib/action_dispatch/system_testing/browser.rb +12 -21
  30. data/lib/action_pack/gem_version.rb +3 -3
  31. metadata +16 -38
  32. data/lib/action_dispatch/journey/parser.y +0 -50
  33. data/lib/action_dispatch/journey/parser_extras.rb +0 -33
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1c6dfb6390c5d4c6038c8aef6a4c79dd69ac971cc460d4e4f915e3c0c104b09b
4
- data.tar.gz: 4427bf987fa2fa103840ee22673c241e136e978dd29d4d29d2b7f370dc1dc2b8
3
+ metadata.gz: 4392b60cf6c4af7ed943daf2c4e438440689b8f869a859510b1e0e5808204cf2
4
+ data.tar.gz: ee9993b25b397af527f1730dc439a0425a81d4b03afb148e310dac8862003261
5
5
  SHA512:
6
- metadata.gz: cc8f57cd76f9e51ac42c10970feceedce22c9374f02d5eb96f4812009cba4e1d68b4d2a7bad8f081d939f6628b0447dd73051a32a590cddfa375f8a3084b3a17
7
- data.tar.gz: 1fa922c393a19ec07ae0b9b615ed3bcc82a365f342270be2308c5dc16b8cd871d82f34c78b486aa981e97308aeefdf3d74cdedb91073602e84219ec05f75c520
6
+ metadata.gz: 2063ad6ca3243b066226af6a1d1ad616d808c48a18f80df374d02b064ad4839a971e4eff804321621d910111829b0c1130b5a05f5a44afabb380ec9f7d5985b7
7
+ data.tar.gz: f3f1e1ce84c47654f69cf3f3ada2afa48e412dac1b7a5abd10c4d0fc34b66b7574f2454410c323cfa26a000005da585815db8a27dc3f1e9c2a71a504b0f3021d
data/CHANGELOG.md CHANGED
@@ -1,147 +1,135 @@
1
- ## Rails 7.2.0 (August 09, 2024) ##
1
+ ## Rails 8.0.0.beta1 (September 26, 2024) ##
2
2
 
3
- * Allow bots to ignore `allow_browser`.
4
-
5
- *Matthew Nguyen*
6
-
7
- * Include the HTTP Permissions-Policy on non-HTML Content-Types
8
- [CVE-2024-28103]
9
-
10
- *Aaron Patterson*, *Zack Deveau*
11
-
12
- * Fix `Mime::Type.parse` handling type parameters for HTTP Accept headers.
13
-
14
- *Taylor Chaparro*
15
-
16
- * Fix the error page that is displayed when a view template is missing to account for nested controller paths in the
17
- suggested correct location for the missing template.
3
+ * Fix non-GET requests not updating cookies in `ActionController::TestCase`.
18
4
 
19
- *Joshua Young*
5
+ *Jon Moss*, *Hartley McGuire*
20
6
 
21
- * Add `save_and_open_page` helper to `IntegrationTest`.
7
+ * Update `ActionController::Live` to use a thread-pool to reuse threads across requests.
22
8
 
23
- `save_and_open_page` is a helpful helper to keep a short feedback loop when working on system tests.
24
- A similar helper with matching signature has been added to integration tests.
9
+ *Adam Renberg Tamm*
25
10
 
26
- *Joé Dupuis*
11
+ * Introduce safer, more explicit params handling method with `params#expect` such that
12
+ `params.expect(table: [ :attr ])` replaces `params.require(:table).permit(:attr)`
27
13
 
28
- * Fix a regression in 7.1.3 passing a `to:` option without a controller when the controller is already defined by a scope.
14
+ Ensures params are filtered with consideration for the expected
15
+ types of values, improving handling of params and avoiding ignorable
16
+ errors caused by params tampering.
29
17
 
30
18
  ```ruby
31
- Rails.application.routes.draw do
32
- controller :home do
33
- get "recent", to: "recent_posts"
34
- end
35
- end
19
+ # If the url is altered to ?person=hacked
20
+ # Before
21
+ params.require(:person).permit(:name, :age, pets: [:name])
22
+ # raises NoMethodError, causing a 500 and potential error reporting
23
+
24
+ # After
25
+ params.expect(person: [ :name, :age, pets: [[:name]] ])
26
+ # raises ActionController::ParameterMissing, correctly returning a 400 error
36
27
  ```
37
28
 
38
- *Étienne Barrié*
29
+ You may also notice the new double array `[[:name]]`. In order to
30
+ declare when a param is expected to be an array of parameter hashes,
31
+ this new double array syntax is used to explicitly declare an array.
32
+ `expect` requires you to declare expected arrays in this way, and will
33
+ ignore arrays that are passed when, for example, `pet: [:name]` is used.
39
34
 
40
- * Request Forgery takes relative paths into account.
35
+ In order to preserve compatibility, `permit` does not adopt the new
36
+ double array syntax and is therefore more permissive about unexpected
37
+ types. Using `expect` everywhere is recommended.
41
38
 
42
- *Stefan Wienert*
39
+ We suggest replacing `params.require(:person).permit(:name, :age)`
40
+ with the direct replacement `params.expect(person: [:name, :age])`
41
+ to prevent external users from manipulating params to trigger 500
42
+ errors. A 400 error will be returned instead, using public/400.html
43
43
 
44
- * Add ".test" as a default allowed host in development to ensure smooth golden-path setup with puma.dev.
45
-
46
- *DHH*
47
-
48
- * Add `allow_browser` to set minimum browser versions for the application.
49
-
50
- A browser that's blocked will by default be served the file in `public/406-unsupported-browser.html` with a HTTP status code of "406 Not Acceptable".
44
+ Usage of `params.require(:id)` should likewise be replaced with
45
+ `params.expect(:id)` which is designed to ensure that `params[:id]`
46
+ is a scalar and not an array or hash, also requiring the param.
51
47
 
52
48
  ```ruby
53
- class ApplicationController < ActionController::Base
54
- # Allow only browsers natively supporting webp images, web push, badges, import maps, CSS nesting + :has
55
- allow_browser versions: :modern
56
- end
57
-
58
- class ApplicationController < ActionController::Base
59
- # 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+.
60
- allow_browser versions: { safari: 16.4, firefox: 121, ie: false }
61
- end
62
-
63
- class MessagesController < ApplicationController
64
- # In addition to the browsers blocked by ApplicationController, also block Opera below 104 and Chrome below 119 for the show action.
65
- allow_browser versions: { opera: 104, chrome: 119 }, only: :show
66
- end
67
- ```
49
+ # Before
50
+ User.find(params.require(:id)) # allows an array, altering behavior
68
51
 
69
- *DHH*
70
-
71
- * Add rate limiting API.
72
-
73
- ```ruby
74
- class SessionsController < ApplicationController
75
- rate_limit to: 10, within: 3.minutes, only: :create
76
- end
77
-
78
- class SignupsController < ApplicationController
79
- rate_limit to: 1000, within: 10.seconds,
80
- by: -> { request.domain }, with: -> { redirect_to busy_controller_url, alert: "Too many signups!" }, only: :new
81
- end
52
+ # After
53
+ User.find(params.expect(:id)) # expect only returns non-blank permitted scalars (excludes Hash, Array, nil, "", etc)
82
54
  ```
83
55
 
84
- *DHH*, *Jean Boussier*
56
+ *Martin Emde*
85
57
 
86
- * Add `image/svg+xml` to the compressible content types of `ActionDispatch::Static`.
58
+ * System Testing: Disable Chrome's search engine choice by default in system tests.
87
59
 
88
- *Georg Ledermann*
60
+ *glaszig*
89
61
 
90
- * Add instrumentation for `ActionController::Live#send_stream`.
62
+ * Fix `Request#raw_post` raising `NoMethodError` when `rack.input` is `nil`.
91
63
 
92
- Allows subscribing to `send_stream` events. The event payload contains the filename, disposition, and type.
64
+ *Hartley McGuire*
65
+
66
+ * Remove `racc` dependency by manually writing `ActionDispatch::Journey::Scanner`.
93
67
 
94
- *Hannah Ramadan*
68
+ *Gannon McGibbon*
95
69
 
96
- * Add support for `with_routing` test helper in `ActionDispatch::IntegrationTest`.
70
+ * Speed up `ActionDispatch::Routing::Mapper::Scope#[]` by merging frame hashes.
97
71
 
98
72
  *Gannon McGibbon*
99
73
 
100
- * Remove deprecated support to set `Rails.application.config.action_dispatch.show_exceptions` to `true` and `false`.
74
+ * Allow bots to ignore `allow_browser`.
101
75
 
102
- *Rafael Mendonça França*
76
+ *Matthew Nguyen*
77
+
78
+ * Deprecate drawing routes with multiple paths to make routing faster.
79
+ You may use `with_options` or a loop to make drawing multiple paths easier.
103
80
 
104
- * Remove deprecated `speaker`, `vibrate`, and `vr` permissions policy directives.
81
+ ```ruby
82
+ # Before
83
+ get "/users", "/other_path", to: "users#index"
105
84
 
106
- *Rafael Mendonça França*
85
+ # After
86
+ get "/users", to: "users#index"
87
+ get "/other_path", to: "users#index"
88
+ ```
107
89
 
108
- * Remove deprecated `Rails.application.config.action_dispatch.return_only_request_media_type_on_content_type`.
90
+ *Gannon McGibbon*
109
91
 
110
- *Rafael Mendonça França*
92
+ * Make `http_cache_forever` use `immutable: true`
111
93
 
112
- * Deprecate `Rails.application.config.action_controller.allow_deprecated_parameters_hash_equality`.
94
+ *Nate Matykiewicz*
113
95
 
114
- *Rafael Mendonça França*
96
+ * Add `config.action_dispatch.strict_freshness`.
115
97
 
116
- * Remove deprecated comparison between `ActionController::Parameters` and `Hash`.
98
+ When set to `true`, the `ETag` header takes precedence over the `Last-Modified` header when both are present,
99
+ as specified by RFC 7232, Section 6.
117
100
 
118
- *Rafael Mendonça França*
101
+ Defaults to `false` to maintain compatibility with previous versions of Rails, but is enabled as part of
102
+ Rails 8.0 defaults.
119
103
 
120
- * Remove deprecated constant `AbstractController::Helpers::MissingHelperError`.
104
+ *heka1024*
121
105
 
122
- *Rafael Mendonça França*
106
+ * Support `immutable` directive in Cache-Control
123
107
 
124
- * Fix a race condition that could cause a `Text file busy - chromedriver`
125
- error with parallel system tests.
108
+ ```ruby
109
+ expires_in 1.minute, public: true, immutable: true
110
+ # Cache-Control: public, max-age=60, immutable
111
+ ```
126
112
 
127
- *Matt Brictson*
113
+ *heka1024*
128
114
 
129
- * Add `racc` as a dependency since it will become a bundled gem in Ruby 3.4.0
115
+ * Add `:wasm_unsafe_eval` mapping for `content_security_policy`
130
116
 
131
- *Hartley McGuire*
132
- * Remove deprecated constant `ActionDispatch::IllegalStateError`.
117
+ ```ruby
118
+ # Before
119
+ policy.script_src "'wasm-unsafe-eval'"
133
120
 
134
- *Rafael Mendonça França*
121
+ # After
122
+ policy.script_src :wasm_unsafe_eval
123
+ ```
135
124
 
136
- * Add parameter filter capability for redirect locations.
125
+ *Joe Haig*
137
126
 
138
- It uses the `config.filter_parameters` to match what needs to be filtered.
139
- The result would be like this:
127
+ * Add `display_capture` and `keyboard_map` in `permissions_policy`
140
128
 
141
- Redirected to http://secret.foo.bar?username=roque&password=[FILTERED]
129
+ *Cyril Blaecke*
142
130
 
143
- Fixes #14055.
131
+ * Add `connect` route helper.
144
132
 
145
- *Roque Pinel*, *Trevor Turk*, *tonytonyjan*
133
+ *Samuel Williams*
146
134
 
147
- Please check [7-1-stable](https://github.com/rails/rails/blob/7-1-stable/actionpack/CHANGELOG.md) for previous changes.
135
+ Please check [7-2-stable](https://github.com/rails/rails/blob/7-2-stable/actionpack/CHANGELOG.md) for previous changes.
@@ -123,6 +123,7 @@ module ActionController
123
123
  BasicImplicitRender,
124
124
  StrongParameters,
125
125
  RateLimiting,
126
+ Caching,
126
127
 
127
128
  DataStreaming,
128
129
  DefaultHeaders,
@@ -76,8 +76,7 @@ module ActionController
76
76
  # `:cache_control`
77
77
  # : When given, will overwrite an existing `Cache-Control` header. For a list
78
78
  # of `Cache-Control` directives, see the [article on
79
- # MDN](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Contr
80
- # ol).
79
+ # MDN](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control).
81
80
  #
82
81
  # `:template`
83
82
  # : By default, the template digest for the current controller/action is
@@ -260,6 +259,9 @@ module ActionController
260
259
  # `:stale_if_error`
261
260
  # : Sets the value of the `stale-if-error` directive.
262
261
  #
262
+ # `:immutable`
263
+ # : If true, adds the `immutable` directive.
264
+ #
263
265
  #
264
266
  # Any additional key-value pairs are concatenated as directives. For a list of
265
267
  # supported `Cache-Control` directives, see the [article on
@@ -293,6 +295,7 @@ module ActionController
293
295
  must_revalidate: options.delete(:must_revalidate),
294
296
  stale_while_revalidate: options.delete(:stale_while_revalidate),
295
297
  stale_if_error: options.delete(:stale_if_error),
298
+ immutable: options.delete(:immutable),
296
299
  )
297
300
  options.delete(:private)
298
301
 
@@ -316,7 +319,7 @@ module ActionController
316
319
  # user's web browser. To allow proxies to cache the response, set `true` to
317
320
  # indicate that they can serve the cached response to all users.
318
321
  def http_cache_forever(public: false)
319
- expires_in 100.years, public: public
322
+ expires_in 100.years, public: public, immutable: true
320
323
 
321
324
  yield if stale?(etag: request.fullpath,
322
325
  last_modified: Time.new(2011, 1, 1).utc,
@@ -211,7 +211,7 @@ module ActionController
211
211
  end
212
212
  end
213
213
 
214
- # Returns false on a valid response, true otherwise.
214
+ # Returns true on a valid response, false otherwise.
215
215
  def authenticate(request, realm, &password_procedure)
216
216
  request.authorization && validate_digest_response(request, realm, &password_procedure)
217
217
  end
@@ -431,7 +431,7 @@ module ActionController
431
431
  module ControllerMethods
432
432
  # Authenticate using an HTTP Bearer token, or otherwise render an HTTP header
433
433
  # requesting the client to send a Bearer token. For the authentication to be
434
- # considered successful, `login_procedure` should return a non-nil value.
434
+ # considered successful, `login_procedure` must not return a false value.
435
435
  # Typically, the authenticated user is returned.
436
436
  #
437
437
  # See ActionController::HttpAuthentication::Token for example usage.
@@ -2,7 +2,6 @@
2
2
 
3
3
  # :markup: markdown
4
4
 
5
- require "benchmark"
6
5
  require "abstract_controller/logger"
7
6
 
8
7
  module ActionController
@@ -29,7 +28,7 @@ module ActionController
29
28
  def render(*)
30
29
  render_output = nil
31
30
  self.view_runtime = cleanup_view_runtime do
32
- Benchmark.ms { render_output = super }
31
+ ActiveSupport::Benchmark.realtime(:float_millisecond) { render_output = super }
33
32
  end
34
33
  render_output
35
34
  end
@@ -77,12 +77,15 @@ module ActionController
77
77
  # Writing an object will convert it into standard SSE format with whatever
78
78
  # options you have configured. You may choose to set the following options:
79
79
  #
80
- # 1) Event. If specified, an event with this name will be dispatched on
81
- # the browser.
82
- # 2) Retry. The reconnection time in milliseconds used when attempting
83
- # to send the event.
84
- # 3) Id. If the connection dies while sending an SSE to the browser, then
85
- # the server will receive a +Last-Event-ID+ header with value equal to +id+.
80
+ # `:event`
81
+ # : If specified, an event with this name will be dispatched on the browser.
82
+ #
83
+ # `:retry`
84
+ # : The reconnection time in milliseconds used when attempting to send the event.
85
+ #
86
+ # `:id`
87
+ # : If the connection dies while sending an SSE to the browser, then the
88
+ # server will receive a `Last-Event-ID` header with value equal to `id`.
86
89
  #
87
90
  # After setting an option in the constructor of the SSE object, all future SSEs
88
91
  # sent across the stream will use those options unless overridden.
@@ -304,6 +307,10 @@ module ActionController
304
307
  error = e
305
308
  end
306
309
  ensure
310
+ # Ensure we clean up any thread locals we copied so that the thread can reused.
311
+ ActiveSupport::IsolatedExecutionState.clear
312
+ locals.each { |k, _| t2[k] = nil }
313
+
307
314
  @_response.commit!
308
315
  end
309
316
  end
@@ -368,11 +375,15 @@ module ActionController
368
375
  # data from the response bodies. Nobody should call this method except in Rails
369
376
  # internals. Seriously!
370
377
  def new_controller_thread # :nodoc:
371
- Thread.new {
378
+ ActionController::Live.live_thread_pool_executor.post do
372
379
  t2 = Thread.current
373
380
  t2.abort_on_exception = true
374
381
  yield
375
- }
382
+ end
383
+ end
384
+
385
+ def self.live_thread_pool_executor
386
+ @live_thread_pool_executor ||= Concurrent::CachedThreadPool.new(name: "action_controller.live")
376
387
  end
377
388
 
378
389
  def log_error(exception)
@@ -29,6 +29,9 @@ module ActionController # :nodoc:
29
29
  # datastore as your general caches, you can pass a custom store in the `store`
30
30
  # parameter.
31
31
  #
32
+ # If you want to use multiple rate limits per controller, you need to give each of
33
+ # them and explicit name via the `name:` option.
34
+ #
32
35
  # Examples:
33
36
  #
34
37
  # class SessionsController < ApplicationController
@@ -44,14 +47,20 @@ module ActionController # :nodoc:
44
47
  # RATE_LIMIT_STORE = ActiveSupport::Cache::RedisCacheStore.new(url: ENV["REDIS_URL"])
45
48
  # rate_limit to: 10, within: 3.minutes, store: RATE_LIMIT_STORE
46
49
  # end
47
- def rate_limit(to:, within:, by: -> { request.remote_ip }, with: -> { head :too_many_requests }, store: cache_store, **options)
48
- before_action -> { rate_limiting(to: to, within: within, by: by, with: with, store: store) }, **options
50
+ #
51
+ # class SessionsController < ApplicationController
52
+ # rate_limit to: 3, within: 2.seconds, name: "short-term"
53
+ # rate_limit to: 10, within: 5.minutes, name: "long-term"
54
+ # end
55
+ def rate_limit(to:, within:, by: -> { request.remote_ip }, with: -> { head :too_many_requests }, store: cache_store, name: nil, **options)
56
+ before_action -> { rate_limiting(to: to, within: within, by: by, with: with, store: store, name: name) }, **options
49
57
  end
50
58
  end
51
59
 
52
60
  private
53
- def rate_limiting(to:, within:, by:, with:, store:)
54
- count = store.increment("rate-limit:#{controller_path}:#{instance_exec(&by)}", 1, expires_in: within)
61
+ def rate_limiting(to:, within:, by:, with:, store:, name:)
62
+ cache_key = ["rate-limit", controller_path, name, instance_exec(&by)].compact.join(":")
63
+ count = store.increment(cache_key, 1, expires_in: within)
55
64
  if count && count > to
56
65
  ActiveSupport::Notifications.instrument("rate_limit.action_controller", request: request) do
57
66
  instance_exec(&with)
@@ -154,7 +154,8 @@ module ActionController
154
154
  end
155
155
 
156
156
  add :json do |json, options|
157
- json = json.to_json(options) unless json.kind_of?(String)
157
+ json_options = options.except(:callback, :content_type, :status)
158
+ json = json.to_json(json_options) unless json.kind_of?(String)
158
159
 
159
160
  if options[:callback].present?
160
161
  if media_type.nil? || media_type == Mime[:json]
@@ -165,95 +165,16 @@ module ActionController # :nodoc:
165
165
  #
166
166
  # ## Web server support
167
167
  #
168
- # Not all web servers support streaming out-of-the-box. You need to check the
169
- # instructions for each of them.
170
- #
171
- # #### Unicorn
172
- #
173
- # Unicorn supports streaming but it needs to be configured. For this, you need
174
- # to create a config file as follow:
175
- #
176
- # # unicorn.config.rb
177
- # listen 3000, tcp_nopush: false
178
- #
179
- # And use it on initialization:
180
- #
181
- # unicorn_rails --config-file unicorn.config.rb
182
- #
183
- # You may also want to configure other parameters like `:tcp_nodelay`.
184
- #
185
- # For more information, please check the
186
- # [documentation](https://bogomips.org/unicorn/Unicorn/Configurator.html#method-
187
- # i-listen).
188
- #
189
- # If you are using Unicorn with NGINX, you may need to tweak NGINX. Streaming
190
- # should work out of the box on Rainbows.
191
- #
192
- # #### Passenger
193
- #
194
- # Phusion Passenger with NGINX, offers two streaming mechanisms out of the box.
195
- #
196
- # 1. NGINX response buffering mechanism which is dependent on the value of
197
- # `passenger_buffer_response` option (default is "off").
198
- # 2. Passenger buffering system which is always 'on' irrespective of the value
199
- # of `passenger_buffer_response`.
200
- #
201
- #
202
- # When `passenger_buffer_response` is turned "on", then streaming would be done
203
- # at the NGINX level which waits until the application is done sending the
204
- # response back to the client.
205
- #
206
- # For more information, please check the [documentation]
207
- # (https://www.phusionpassenger.com/docs/references/config_reference/nginx/#passenger_buffer_response).
168
+ # Rack 3+ compatible servers all support streaming.
208
169
  module Streaming
209
- class Body # :nodoc:
210
- TERM = "\r\n"
211
- TAIL = "0#{TERM}"
212
-
213
- # Store the response body to be chunked.
214
- def initialize(body)
215
- @body = body
216
- end
217
-
218
- # For each element yielded by the response body, yield the element in chunked
219
- # encoding.
220
- def each(&block)
221
- term = TERM
222
- @body.each do |chunk|
223
- size = chunk.bytesize
224
- next if size == 0
225
-
226
- yield [size.to_s(16), term, chunk.b, term].join
227
- end
228
- yield TAIL
229
- yield term
230
- end
231
-
232
- # Close the response body if the response body supports it.
233
- def close
234
- @body.close if @body.respond_to?(:close)
235
- end
236
- end
237
-
238
170
  private
239
- # Set proper cache control and transfer encoding when streaming
240
- def _process_options(options)
241
- super
242
- if options[:stream]
243
- if request.version == "HTTP/1.0"
244
- options.delete(:stream)
245
- else
246
- headers["Cache-Control"] ||= "no-cache"
247
- headers["Transfer-Encoding"] = "chunked"
248
- headers.delete("Content-Length")
249
- end
250
- end
251
- end
252
-
253
171
  # Call render_body if we are streaming instead of usual `render`.
254
172
  def _render_template(options)
255
173
  if options.delete(:stream)
256
- Body.new view_renderer.render_body(view_context, options)
174
+ # It shoudn't be necessary to set this.
175
+ headers["cache-control"] ||= "no-cache"
176
+
177
+ view_renderer.render_body(view_context, options)
257
178
  else
258
179
  super
259
180
  end