actionpack 4.2.10 → 7.2.0.rc1

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 (202) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +86 -600
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +13 -14
  5. data/lib/abstract_controller/asset_paths.rb +5 -1
  6. data/lib/abstract_controller/base.rb +166 -136
  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 +126 -57
  10. data/lib/abstract_controller/collector.rb +13 -15
  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 +181 -132
  14. data/lib/abstract_controller/logger.rb +5 -1
  15. data/lib/abstract_controller/railties/routes_helpers.rb +10 -3
  16. data/lib/abstract_controller/rendering.rb +56 -56
  17. data/lib/abstract_controller/translation.rb +29 -15
  18. data/lib/abstract_controller/url_for.rb +15 -11
  19. data/lib/abstract_controller.rb +21 -5
  20. data/lib/action_controller/api/api_rendering.rb +18 -0
  21. data/lib/action_controller/api.rb +154 -0
  22. data/lib/action_controller/base.rb +219 -155
  23. data/lib/action_controller/caching.rb +28 -68
  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 +35 -22
  27. data/lib/action_controller/metal/allow_browser.rb +119 -0
  28. data/lib/action_controller/metal/basic_implicit_render.rb +17 -0
  29. data/lib/action_controller/metal/conditional_get.rb +259 -122
  30. data/lib/action_controller/metal/content_security_policy.rb +86 -0
  31. data/lib/action_controller/metal/cookies.rb +9 -5
  32. data/lib/action_controller/metal/data_streaming.rb +87 -104
  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 +35 -26
  36. data/lib/action_controller/metal/exceptions.rb +71 -24
  37. data/lib/action_controller/metal/flash.rb +26 -19
  38. data/lib/action_controller/metal/head.rb +45 -36
  39. data/lib/action_controller/metal/helpers.rb +80 -64
  40. data/lib/action_controller/metal/http_authentication.rb +297 -244
  41. data/lib/action_controller/metal/implicit_render.rb +57 -9
  42. data/lib/action_controller/metal/instrumentation.rb +76 -64
  43. data/lib/action_controller/metal/live.rb +238 -176
  44. data/lib/action_controller/metal/logging.rb +22 -0
  45. data/lib/action_controller/metal/mime_responds.rb +177 -166
  46. data/lib/action_controller/metal/parameter_encoding.rb +84 -0
  47. data/lib/action_controller/metal/params_wrapper.rb +145 -118
  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 +203 -64
  51. data/lib/action_controller/metal/renderers.rb +108 -65
  52. data/lib/action_controller/metal/rendering.rb +216 -56
  53. data/lib/action_controller/metal/request_forgery_protection.rb +496 -163
  54. data/lib/action_controller/metal/rescue.rb +19 -21
  55. data/lib/action_controller/metal/streaming.rb +179 -138
  56. data/lib/action_controller/metal/strong_parameters.rb +1058 -382
  57. data/lib/action_controller/metal/testing.rb +11 -17
  58. data/lib/action_controller/metal/url_for.rb +37 -21
  59. data/lib/action_controller/metal.rb +236 -138
  60. data/lib/action_controller/railtie.rb +89 -11
  61. data/lib/action_controller/railties/helpers.rb +5 -1
  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 +425 -497
  65. data/lib/action_controller.rb +44 -22
  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 +119 -63
  69. data/lib/action_dispatch/http/content_disposition.rb +47 -0
  70. data/lib/action_dispatch/http/content_security_policy.rb +364 -0
  71. data/lib/action_dispatch/http/filter_parameters.rb +36 -34
  72. data/lib/action_dispatch/http/filter_redirect.rb +24 -12
  73. data/lib/action_dispatch/http/headers.rb +66 -31
  74. data/lib/action_dispatch/http/mime_negotiation.rb +106 -75
  75. data/lib/action_dispatch/http/mime_type.rb +196 -136
  76. data/lib/action_dispatch/http/mime_types.rb +25 -7
  77. data/lib/action_dispatch/http/parameters.rb +97 -45
  78. data/lib/action_dispatch/http/permissions_policy.rb +187 -0
  79. data/lib/action_dispatch/http/rack_cache.rb +6 -0
  80. data/lib/action_dispatch/http/request.rb +299 -170
  81. data/lib/action_dispatch/http/response.rb +311 -160
  82. data/lib/action_dispatch/http/upload.rb +52 -23
  83. data/lib/action_dispatch/http/url.rb +201 -125
  84. data/lib/action_dispatch/journey/formatter.rb +110 -50
  85. data/lib/action_dispatch/journey/gtg/builder.rb +37 -50
  86. data/lib/action_dispatch/journey/gtg/simulator.rb +20 -17
  87. data/lib/action_dispatch/journey/gtg/transition_table.rb +96 -36
  88. data/lib/action_dispatch/journey/nfa/dot.rb +5 -14
  89. data/lib/action_dispatch/journey/nodes/node.rb +100 -20
  90. data/lib/action_dispatch/journey/parser.rb +19 -17
  91. data/lib/action_dispatch/journey/parser.y +4 -3
  92. data/lib/action_dispatch/journey/parser_extras.rb +14 -4
  93. data/lib/action_dispatch/journey/path/pattern.rb +79 -63
  94. data/lib/action_dispatch/journey/route.rb +108 -44
  95. data/lib/action_dispatch/journey/router/utils.rb +41 -29
  96. data/lib/action_dispatch/journey/router.rb +64 -57
  97. data/lib/action_dispatch/journey/routes.rb +23 -21
  98. data/lib/action_dispatch/journey/scanner.rb +28 -17
  99. data/lib/action_dispatch/journey/visitors.rb +100 -54
  100. data/lib/action_dispatch/journey/visualizer/fsm.js +49 -24
  101. data/lib/action_dispatch/journey/visualizer/index.html.erb +1 -1
  102. data/lib/action_dispatch/journey.rb +7 -5
  103. data/lib/action_dispatch/log_subscriber.rb +25 -0
  104. data/lib/action_dispatch/middleware/actionable_exceptions.rb +46 -0
  105. data/lib/action_dispatch/middleware/assume_ssl.rb +27 -0
  106. data/lib/action_dispatch/middleware/callbacks.rb +7 -6
  107. data/lib/action_dispatch/middleware/cookies.rb +471 -328
  108. data/lib/action_dispatch/middleware/debug_exceptions.rb +149 -66
  109. data/lib/action_dispatch/middleware/debug_locks.rb +129 -0
  110. data/lib/action_dispatch/middleware/debug_view.rb +73 -0
  111. data/lib/action_dispatch/middleware/exception_wrapper.rb +275 -73
  112. data/lib/action_dispatch/middleware/executor.rb +32 -0
  113. data/lib/action_dispatch/middleware/flash.rb +143 -101
  114. data/lib/action_dispatch/middleware/host_authorization.rb +171 -0
  115. data/lib/action_dispatch/middleware/public_exceptions.rb +36 -27
  116. data/lib/action_dispatch/middleware/reloader.rb +10 -92
  117. data/lib/action_dispatch/middleware/remote_ip.rb +133 -107
  118. data/lib/action_dispatch/middleware/request_id.rb +29 -15
  119. data/lib/action_dispatch/middleware/server_timing.rb +78 -0
  120. data/lib/action_dispatch/middleware/session/abstract_store.rb +49 -27
  121. data/lib/action_dispatch/middleware/session/cache_store.rb +33 -16
  122. data/lib/action_dispatch/middleware/session/cookie_store.rb +86 -80
  123. data/lib/action_dispatch/middleware/session/mem_cache_store.rb +15 -3
  124. data/lib/action_dispatch/middleware/show_exceptions.rb +66 -36
  125. data/lib/action_dispatch/middleware/ssl.rb +134 -36
  126. data/lib/action_dispatch/middleware/stack.rb +109 -44
  127. data/lib/action_dispatch/middleware/static.rb +159 -90
  128. data/lib/action_dispatch/middleware/templates/rescues/_actions.html.erb +13 -0
  129. data/lib/action_dispatch/middleware/templates/rescues/_actions.text.erb +0 -0
  130. data/lib/action_dispatch/middleware/templates/rescues/_message_and_suggestions.html.erb +22 -0
  131. data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb +7 -24
  132. data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.text.erb +1 -1
  133. data/lib/action_dispatch/middleware/templates/rescues/_source.html.erb +36 -0
  134. data/lib/action_dispatch/middleware/templates/rescues/_source.text.erb +8 -0
  135. data/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb +46 -36
  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 +26 -7
  139. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.text.erb +3 -3
  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 +139 -15
  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 +6 -6
  146. data/lib/action_dispatch/middleware/templates/rescues/routing_error.html.erb +7 -7
  147. data/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb +9 -9
  148. data/lib/action_dispatch/middleware/templates/rescues/template_error.text.erb +1 -1
  149. data/lib/action_dispatch/middleware/templates/rescues/unknown_action.html.erb +4 -4
  150. data/lib/action_dispatch/middleware/templates/rescues/unknown_action.text.erb +1 -1
  151. data/lib/action_dispatch/middleware/templates/routes/_route.html.erb +7 -4
  152. data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +125 -93
  153. data/lib/action_dispatch/railtie.rb +44 -16
  154. data/lib/action_dispatch/request/session.rb +159 -69
  155. data/lib/action_dispatch/request/utils.rb +97 -23
  156. data/lib/action_dispatch/routing/endpoint.rb +11 -2
  157. data/lib/action_dispatch/routing/inspector.rb +195 -106
  158. data/lib/action_dispatch/routing/mapper.rb +1338 -955
  159. data/lib/action_dispatch/routing/polymorphic_routes.rb +234 -201
  160. data/lib/action_dispatch/routing/redirection.rb +78 -51
  161. data/lib/action_dispatch/routing/route_set.rb +460 -374
  162. data/lib/action_dispatch/routing/routes_proxy.rb +36 -12
  163. data/lib/action_dispatch/routing/url_for.rb +172 -124
  164. data/lib/action_dispatch/routing.rb +159 -158
  165. data/lib/action_dispatch/system_test_case.rb +206 -0
  166. data/lib/action_dispatch/system_testing/browser.rb +84 -0
  167. data/lib/action_dispatch/system_testing/driver.rb +85 -0
  168. data/lib/action_dispatch/system_testing/server.rb +33 -0
  169. data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +164 -0
  170. data/lib/action_dispatch/system_testing/test_helpers/setup_and_teardown.rb +23 -0
  171. data/lib/action_dispatch/testing/assertion_response.rb +48 -0
  172. data/lib/action_dispatch/testing/assertions/response.rb +71 -39
  173. data/lib/action_dispatch/testing/assertions/routing.rb +228 -103
  174. data/lib/action_dispatch/testing/assertions.rb +9 -6
  175. data/lib/action_dispatch/testing/integration.rb +486 -306
  176. data/lib/action_dispatch/testing/request_encoder.rb +60 -0
  177. data/lib/action_dispatch/testing/test_helpers/page_dump_helper.rb +35 -0
  178. data/lib/action_dispatch/testing/test_process.rb +35 -22
  179. data/lib/action_dispatch/testing/test_request.rb +29 -34
  180. data/lib/action_dispatch/testing/test_response.rb +48 -15
  181. data/lib/action_dispatch.rb +82 -40
  182. data/lib/action_pack/gem_version.rb +8 -4
  183. data/lib/action_pack/version.rb +6 -2
  184. data/lib/action_pack.rb +21 -18
  185. metadata +146 -56
  186. data/lib/action_controller/caching/fragments.rb +0 -103
  187. data/lib/action_controller/metal/force_ssl.rb +0 -97
  188. data/lib/action_controller/metal/hide_actions.rb +0 -40
  189. data/lib/action_controller/metal/rack_delegation.rb +0 -32
  190. data/lib/action_controller/middleware.rb +0 -39
  191. data/lib/action_controller/model_naming.rb +0 -12
  192. data/lib/action_dispatch/http/parameter_filter.rb +0 -72
  193. data/lib/action_dispatch/journey/backwards.rb +0 -5
  194. data/lib/action_dispatch/journey/nfa/builder.rb +0 -76
  195. data/lib/action_dispatch/journey/nfa/simulator.rb +0 -47
  196. data/lib/action_dispatch/journey/nfa/transition_table.rb +0 -163
  197. data/lib/action_dispatch/journey/router/strexp.rb +0 -27
  198. data/lib/action_dispatch/middleware/params_parser.rb +0 -60
  199. data/lib/action_dispatch/middleware/templates/rescues/_source.erb +0 -27
  200. data/lib/action_dispatch/testing/assertions/dom.rb +0 -3
  201. data/lib/action_dispatch/testing/assertions/selector.rb +0 -3
  202. data/lib/action_dispatch/testing/assertions/tag.rb +0 -3
@@ -1,35 +1,33 @@
1
- module ActionController #:nodoc:
2
- # This module is responsible to provide `rescue_from` helpers
3
- # to controllers and configure when detailed exceptions must be
4
- # shown.
1
+ # frozen_string_literal: true
2
+
3
+ # :markup: markdown
4
+
5
+ module ActionController # :nodoc:
6
+ # # Action Controller Rescue
7
+ #
8
+ # This module is responsible for providing
9
+ # [rescue_from](rdoc-ref:ActiveSupport::Rescuable::ClassMethods#rescue_from) to
10
+ # controllers, wrapping actions to handle configured errors, and configuring
11
+ # when detailed exceptions must be shown.
5
12
  module Rescue
6
13
  extend ActiveSupport::Concern
7
14
  include ActiveSupport::Rescuable
8
15
 
9
- def rescue_with_handler(exception)
10
- if (exception.respond_to?(:original_exception) &&
11
- (orig_exception = exception.original_exception) &&
12
- handler_for_rescue(orig_exception))
13
- exception = orig_exception
14
- end
15
- super(exception)
16
- end
17
-
18
- # Override this method if you want to customize when detailed
19
- # exceptions must be shown. This method is only called when
20
- # consider_all_requests_local is false. By default, it returns
21
- # false, but someone may set it to `request.local?` so local
22
- # requests in production still shows the detailed exception pages.
16
+ # Override this method if you want to customize when detailed exceptions must be
17
+ # shown. This method is only called when `consider_all_requests_local` is
18
+ # `false`. By default, it returns `false`, but someone may set it to
19
+ # `request.local?` so local requests in production still show the detailed
20
+ # exception pages.
23
21
  def show_detailed_exceptions?
24
22
  false
25
23
  end
26
24
 
27
25
  private
28
- def process_action(*args)
26
+ def process_action(*)
29
27
  super
30
28
  rescue Exception => exception
31
- request.env['action_dispatch.show_detailed_exceptions'] ||= show_detailed_exceptions?
32
- rescue_with_handler(exception) || raise(exception)
29
+ request.env["action_dispatch.show_detailed_exceptions"] ||= show_detailed_exceptions?
30
+ rescue_with_handler(exception) || raise
33
31
  end
34
32
  end
35
33
  end
@@ -1,205 +1,246 @@
1
- require 'rack/chunked'
1
+ # frozen_string_literal: true
2
2
 
3
- module ActionController #:nodoc:
3
+ # :markup: markdown
4
+
5
+ module ActionController # :nodoc:
6
+ # # Action Controller Streaming
7
+ #
4
8
  # Allows views to be streamed back to the client as they are rendered.
5
9
  #
6
- # The default way Rails renders views is by first rendering the template
7
- # and then the layout. The response is sent to the client after the whole
8
- # template is rendered, all queries are made, and the layout is processed.
10
+ # By default, Rails renders views by first rendering the template and then the
11
+ # layout. The response is sent to the client after the whole template is
12
+ # rendered, all queries are made, and the layout is processed.
9
13
  #
10
14
  # Streaming inverts the rendering flow by rendering the layout first and
11
- # streaming each part of the layout as they are processed. This allows the
12
- # header of the HTML (which is usually in the layout) to be streamed back
13
- # to client very quickly, allowing JavaScripts and stylesheets to be loaded
14
- # earlier than usual.
15
+ # subsequently each part of the layout as they are processed. This allows the
16
+ # header of the HTML (which is usually in the layout) to be streamed back to
17
+ # client very quickly, enabling JavaScripts and stylesheets to be loaded earlier
18
+ # than usual.
19
+ #
20
+ # Several Rack middlewares may not work and you need to be careful when
21
+ # streaming. This is covered in more detail below, see the Streaming@Middlewares
22
+ # section.
23
+ #
24
+ # Streaming can be added to a given template easily, all you need to do is to
25
+ # pass the `:stream` option to `render`.
26
+ #
27
+ # class PostsController
28
+ # def index
29
+ # @posts = Post.all
30
+ # render stream: true
31
+ # end
32
+ # end
15
33
  #
16
- # This approach was introduced in Rails 3.1 and is still improving. Several
17
- # Rack middlewares may not work and you need to be careful when streaming.
18
- # Those points are going to be addressed soon.
34
+ # ## When to use streaming
19
35
  #
20
- # In order to use streaming, you will need to use a Ruby version that
21
- # supports fibers (fibers are supported since version 1.9.2 of the main
22
- # Ruby implementation).
36
+ # Streaming may be considered to be overkill for lightweight actions like `new`
37
+ # or `edit`. The real benefit of streaming is on expensive actions that, for
38
+ # example, do a lot of queries on the database.
23
39
  #
24
- # Streaming can be added to a given template easily, all you need to do is
25
- # to pass the :stream option.
40
+ # In such actions, you want to delay queries execution as much as you can. For
41
+ # example, imagine the following `dashboard` action:
26
42
  #
27
- # class PostsController
28
- # def index
43
+ # def dashboard
29
44
  # @posts = Post.all
30
- # render stream: true
45
+ # @pages = Page.all
46
+ # @articles = Article.all
31
47
  # end
32
- # end
33
- #
34
- # == When to use streaming
35
- #
36
- # Streaming may be considered to be overkill for lightweight actions like
37
- # +new+ or +edit+. The real benefit of streaming is on expensive actions
38
- # that, for example, do a lot of queries on the database.
39
- #
40
- # In such actions, you want to delay queries execution as much as you can.
41
- # For example, imagine the following +dashboard+ action:
42
- #
43
- # def dashboard
44
- # @posts = Post.all
45
- # @pages = Page.all
46
- # @articles = Article.all
47
- # end
48
48
  #
49
49
  # Most of the queries here are happening in the controller. In order to benefit
50
50
  # from streaming you would want to rewrite it as:
51
51
  #
52
- # def dashboard
53
- # # Allow lazy execution of the queries
54
- # @posts = Post.all
55
- # @pages = Page.all
56
- # @articles = Article.all
57
- # render stream: true
58
- # end
52
+ # def dashboard
53
+ # # Allow lazy execution of the queries
54
+ # @posts = Post.all
55
+ # @pages = Page.all
56
+ # @articles = Article.all
57
+ # render stream: true
58
+ # end
59
59
  #
60
- # Notice that :stream only works with templates. Rendering :json
61
- # or :xml with :stream won't work.
60
+ # Notice that `:stream` only works with templates. Rendering `:json` or `:xml`
61
+ # with `:stream` won't work.
62
62
  #
63
- # == Communication between layout and template
63
+ # ## Communication between layout and template
64
64
  #
65
- # When streaming, rendering happens top-down instead of inside-out.
66
- # Rails starts with the layout, and the template is rendered later,
67
- # when its +yield+ is reached.
65
+ # When streaming, rendering happens top-down instead of inside-out. Rails starts
66
+ # with the layout, and the template is rendered later, when its `yield` is
67
+ # reached.
68
68
  #
69
- # This means that, if your application currently relies on instance
70
- # variables set in the template to be used in the layout, they won't
71
- # work once you move to streaming. The proper way to communicate
72
- # between layout and template, regardless of whether you use streaming
73
- # or not, is by using +content_for+, +provide+ and +yield+.
69
+ # This means that, if your application currently relies on instance variables
70
+ # set in the template to be used in the layout, they won't work once you move to
71
+ # streaming. The proper way to communicate between layout and template,
72
+ # regardless of whether you use streaming or not, is by using `content_for`,
73
+ # `provide`, and `yield`.
74
74
  #
75
- # Take a simple example where the layout expects the template to tell
76
- # which title to use:
75
+ # Take a simple example where the layout expects the template to tell which
76
+ # title to use:
77
77
  #
78
- # <html>
79
- # <head><title><%= yield :title %></title></head>
80
- # <body><%= yield %></body>
81
- # </html>
78
+ # <html>
79
+ # <head><title><%= yield :title %></title></head>
80
+ # <body><%= yield %></body>
81
+ # </html>
82
82
  #
83
- # You would use +content_for+ in your template to specify the title:
83
+ # You would use `content_for` in your template to specify the title:
84
84
  #
85
- # <%= content_for :title, "Main" %>
86
- # Hello
85
+ # <%= content_for :title, "Main" %>
86
+ # Hello
87
87
  #
88
88
  # And the final result would be:
89
89
  #
90
- # <html>
91
- # <head><title>Main</title></head>
92
- # <body>Hello</body>
93
- # </html>
90
+ # <html>
91
+ # <head><title>Main</title></head>
92
+ # <body>Hello</body>
93
+ # </html>
94
94
  #
95
- # However, if +content_for+ is called several times, the final result
96
- # would have all calls concatenated. For instance, if we have the following
97
- # template:
95
+ # However, if `content_for` is called several times, the final result would have
96
+ # all calls concatenated. For instance, if we have the following template:
98
97
  #
99
- # <%= content_for :title, "Main" %>
100
- # Hello
101
- # <%= content_for :title, " page" %>
98
+ # <%= content_for :title, "Main" %>
99
+ # Hello
100
+ # <%= content_for :title, " page" %>
102
101
  #
103
102
  # The final result would be:
104
103
  #
105
- # <html>
106
- # <head><title>Main page</title></head>
107
- # <body>Hello</body>
108
- # </html>
104
+ # <html>
105
+ # <head><title>Main page</title></head>
106
+ # <body>Hello</body>
107
+ # </html>
108
+ #
109
+ # This means that, if you have `yield :title` in your layout and you want to use
110
+ # streaming, you would have to render the whole template (and eventually trigger
111
+ # all queries) before streaming the title and all assets, which defeats the
112
+ # purpose of streaming. Alternatively, you can use a helper called `provide`
113
+ # that does the same as `content_for` but tells the layout to stop searching for
114
+ # other entries and continue rendering.
109
115
  #
110
- # This means that, if you have <code>yield :title</code> in your layout
111
- # and you want to use streaming, you would have to render the whole template
112
- # (and eventually trigger all queries) before streaming the title and all
113
- # assets, which kills the purpose of streaming. For this reason Rails 3.1
114
- # introduces a new helper called +provide+ that does the same as +content_for+
115
- # but tells the layout to stop searching for other entries and continue rendering.
116
+ # For instance, the template above using `provide` would be:
116
117
  #
117
- # For instance, the template above using +provide+ would be:
118
+ # <%= provide :title, "Main" %>
119
+ # Hello
120
+ # <%= content_for :title, " page" %>
118
121
  #
119
- # <%= provide :title, "Main" %>
120
- # Hello
121
- # <%= content_for :title, " page" %>
122
+ # Resulting in:
122
123
  #
123
- # Giving:
124
+ # <html>
125
+ # <head><title>Main</title></head>
126
+ # <body>Hello</body>
127
+ # </html>
124
128
  #
125
- # <html>
126
- # <head><title>Main</title></head>
127
- # <body>Hello</body>
128
- # </html>
129
+ # That said, when streaming, you need to properly check your templates and
130
+ # choose when to use `provide` and `content_for`.
129
131
  #
130
- # That said, when streaming, you need to properly check your templates
131
- # and choose when to use +provide+ and +content_for+.
132
+ # See also ActionView::Helpers::CaptureHelper for more information.
132
133
  #
133
- # == Headers, cookies, session and flash
134
+ # ## Headers, cookies, session, and flash
134
135
  #
135
- # When streaming, the HTTP headers are sent to the client right before
136
- # it renders the first line. This means that, modifying headers, cookies,
137
- # session or flash after the template starts rendering will not propagate
138
- # to the client.
136
+ # When streaming, the HTTP headers are sent to the client right before it
137
+ # renders the first line. This means that, modifying headers, cookies, session
138
+ # or flash after the template starts rendering will not propagate to the client.
139
139
  #
140
- # == Middlewares
140
+ # ## Middlewares
141
141
  #
142
- # Middlewares that need to manipulate the body won't work with streaming.
143
- # You should disable those middlewares whenever streaming in development
144
- # or production. For instance, <tt>Rack::Bug</tt> won't work when streaming as it
145
- # needs to inject contents in the HTML body.
142
+ # Middlewares that need to manipulate the body won't work with streaming. You
143
+ # should disable those middlewares whenever streaming in development or
144
+ # production. For instance, `Rack::Bug` won't work when streaming as it needs to
145
+ # inject contents in the HTML body.
146
146
  #
147
- # Also <tt>Rack::Cache</tt> won't work with streaming as it does not support
148
- # streaming bodies yet. Whenever streaming Cache-Control is automatically
149
- # set to "no-cache".
147
+ # Also `Rack::Cache` won't work with streaming as it does not support streaming
148
+ # bodies yet. Whenever streaming `Cache-Control` is automatically set to
149
+ # "no-cache".
150
150
  #
151
- # == Errors
151
+ # ## Errors
152
152
  #
153
153
  # When it comes to streaming, exceptions get a bit more complicated. This
154
- # happens because part of the template was already rendered and streamed to
155
- # the client, making it impossible to render a whole exception page.
154
+ # happens because part of the template was already rendered and streamed to the
155
+ # client, making it impossible to render a whole exception page.
156
156
  #
157
- # Currently, when an exception happens in development or production, Rails
158
- # will automatically stream to the client:
157
+ # Currently, when an exception happens in development or production, Rails will
158
+ # automatically stream to the client:
159
159
  #
160
- # "><script>window.location = "/500.html"</script></html>
160
+ # "><script>window.location = "/500.html"</script></html>
161
161
  #
162
- # The first two characters (">) are required in case the exception happens
163
- # while rendering attributes for a given tag. You can check the real cause
164
- # for the exception in your logger.
162
+ # The first two characters (`">`) are required in case the exception happens
163
+ # while rendering attributes for a given tag. You can check the real cause for
164
+ # the exception in your logger.
165
165
  #
166
- # == Web server support
166
+ # ## Web server support
167
167
  #
168
- # Not all web servers support streaming out-of-the-box. You need to check
169
- # the instructions for each of them.
168
+ # Not all web servers support streaming out-of-the-box. You need to check the
169
+ # instructions for each of them.
170
170
  #
171
- # ==== Unicorn
171
+ # #### Unicorn
172
172
  #
173
- # Unicorn supports streaming but it needs to be configured. For this, you
174
- # need to create a config file as follow:
173
+ # Unicorn supports streaming but it needs to be configured. For this, you need
174
+ # to create a config file as follow:
175
175
  #
176
- # # unicorn.config.rb
177
- # listen 3000, tcp_nopush: false
176
+ # # unicorn.config.rb
177
+ # listen 3000, tcp_nopush: false
178
178
  #
179
179
  # And use it on initialization:
180
180
  #
181
- # unicorn_rails --config-file unicorn.config.rb
181
+ # unicorn_rails --config-file unicorn.config.rb
182
182
  #
183
- # You may also want to configure other parameters like <tt>:tcp_nodelay</tt>.
184
- # Please check its documentation for more information: http://unicorn.bogomips.org/Unicorn/Configurator.html#method-i-listen
183
+ # You may also want to configure other parameters like `:tcp_nodelay`.
185
184
  #
186
- # If you are using Unicorn with NGINX, you may need to tweak NGINX.
187
- # Streaming should work out of the box on Rainbows.
185
+ # For more information, please check the
186
+ # [documentation](https://bogomips.org/unicorn/Unicorn/Configurator.html#method-
187
+ # i-listen).
188
188
  #
189
- # ==== Passenger
189
+ # If you are using Unicorn with NGINX, you may need to tweak NGINX. Streaming
190
+ # should work out of the box on Rainbows.
190
191
  #
191
- # To be described.
192
+ # #### Passenger
192
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).
193
208
  module Streaming
194
- extend ActiveSupport::Concern
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
195
217
 
196
- protected
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
197
237
 
238
+ private
198
239
  # Set proper cache control and transfer encoding when streaming
199
- def _process_options(options) #:nodoc:
240
+ def _process_options(options)
200
241
  super
201
242
  if options[:stream]
202
- if env["HTTP_VERSION"] == "HTTP/1.0"
243
+ if request.version == "HTTP/1.0"
203
244
  options.delete(:stream)
204
245
  else
205
246
  headers["Cache-Control"] ||= "no-cache"
@@ -209,10 +250,10 @@ module ActionController #:nodoc:
209
250
  end
210
251
  end
211
252
 
212
- # Call render_body if we are streaming instead of usual +render+.
213
- def _render_template(options) #:nodoc:
253
+ # Call render_body if we are streaming instead of usual `render`.
254
+ def _render_template(options)
214
255
  if options.delete(:stream)
215
- Rack::Chunked::Body.new view_renderer.render_body(view_context, options)
256
+ Body.new view_renderer.render_body(view_context, options)
216
257
  else
217
258
  super
218
259
  end