actionpack 3.2.19 → 4.2.11.3

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 (244) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +412 -503
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +11 -294
  5. data/lib/abstract_controller/asset_paths.rb +2 -2
  6. data/lib/abstract_controller/base.rb +52 -18
  7. data/lib/abstract_controller/callbacks.rb +87 -89
  8. data/lib/abstract_controller/collector.rb +17 -3
  9. data/lib/abstract_controller/helpers.rb +41 -14
  10. data/lib/abstract_controller/logger.rb +1 -2
  11. data/lib/abstract_controller/railties/routes_helpers.rb +3 -3
  12. data/lib/abstract_controller/rendering.rb +65 -118
  13. data/lib/abstract_controller/translation.rb +16 -1
  14. data/lib/abstract_controller/url_for.rb +7 -7
  15. data/lib/abstract_controller.rb +2 -10
  16. data/lib/action_controller/base.rb +61 -28
  17. data/lib/action_controller/caching/fragments.rb +30 -54
  18. data/lib/action_controller/caching.rb +38 -35
  19. data/lib/action_controller/log_subscriber.rb +35 -18
  20. data/lib/action_controller/metal/conditional_get.rb +103 -34
  21. data/lib/action_controller/metal/data_streaming.rb +20 -26
  22. data/lib/action_controller/metal/etag_with_template_digest.rb +50 -0
  23. data/lib/action_controller/metal/exceptions.rb +19 -6
  24. data/lib/action_controller/metal/flash.rb +41 -9
  25. data/lib/action_controller/metal/force_ssl.rb +70 -12
  26. data/lib/action_controller/metal/head.rb +30 -7
  27. data/lib/action_controller/metal/helpers.rb +11 -11
  28. data/lib/action_controller/metal/hide_actions.rb +0 -1
  29. data/lib/action_controller/metal/http_authentication.rb +140 -94
  30. data/lib/action_controller/metal/implicit_render.rb +1 -1
  31. data/lib/action_controller/metal/instrumentation.rb +11 -7
  32. data/lib/action_controller/metal/live.rb +328 -0
  33. data/lib/action_controller/metal/mime_responds.rb +161 -152
  34. data/lib/action_controller/metal/params_wrapper.rb +126 -81
  35. data/lib/action_controller/metal/rack_delegation.rb +10 -4
  36. data/lib/action_controller/metal/redirecting.rb +44 -41
  37. data/lib/action_controller/metal/renderers.rb +48 -19
  38. data/lib/action_controller/metal/rendering.rb +46 -11
  39. data/lib/action_controller/metal/request_forgery_protection.rb +250 -29
  40. data/lib/action_controller/metal/streaming.rb +30 -38
  41. data/lib/action_controller/metal/strong_parameters.rb +669 -0
  42. data/lib/action_controller/metal/testing.rb +12 -18
  43. data/lib/action_controller/metal/url_for.rb +31 -29
  44. data/lib/action_controller/metal.rb +31 -40
  45. data/lib/action_controller/model_naming.rb +12 -0
  46. data/lib/action_controller/railtie.rb +38 -18
  47. data/lib/action_controller/railties/helpers.rb +22 -0
  48. data/lib/action_controller/test_case.rb +359 -173
  49. data/lib/action_controller.rb +9 -16
  50. data/lib/action_dispatch/http/cache.rb +64 -11
  51. data/lib/action_dispatch/http/filter_parameters.rb +20 -10
  52. data/lib/action_dispatch/http/filter_redirect.rb +38 -0
  53. data/lib/action_dispatch/http/headers.rb +85 -17
  54. data/lib/action_dispatch/http/mime_negotiation.rb +55 -5
  55. data/lib/action_dispatch/http/mime_type.rb +167 -114
  56. data/lib/action_dispatch/http/mime_types.rb +2 -1
  57. data/lib/action_dispatch/http/parameter_filter.rb +44 -46
  58. data/lib/action_dispatch/http/parameters.rb +30 -46
  59. data/lib/action_dispatch/http/rack_cache.rb +2 -3
  60. data/lib/action_dispatch/http/request.rb +108 -45
  61. data/lib/action_dispatch/http/response.rb +247 -48
  62. data/lib/action_dispatch/http/upload.rb +60 -29
  63. data/lib/action_dispatch/http/url.rb +135 -45
  64. data/lib/action_dispatch/journey/backwards.rb +5 -0
  65. data/lib/action_dispatch/journey/formatter.rb +166 -0
  66. data/lib/action_dispatch/journey/gtg/builder.rb +162 -0
  67. data/lib/action_dispatch/journey/gtg/simulator.rb +47 -0
  68. data/lib/action_dispatch/journey/gtg/transition_table.rb +157 -0
  69. data/lib/action_dispatch/journey/nfa/builder.rb +76 -0
  70. data/lib/action_dispatch/journey/nfa/dot.rb +36 -0
  71. data/lib/action_dispatch/journey/nfa/simulator.rb +47 -0
  72. data/lib/action_dispatch/journey/nfa/transition_table.rb +163 -0
  73. data/lib/action_dispatch/journey/nodes/node.rb +128 -0
  74. data/lib/action_dispatch/journey/parser.rb +198 -0
  75. data/lib/action_dispatch/journey/parser.y +49 -0
  76. data/lib/action_dispatch/journey/parser_extras.rb +23 -0
  77. data/lib/action_dispatch/journey/path/pattern.rb +193 -0
  78. data/lib/action_dispatch/journey/route.rb +125 -0
  79. data/lib/action_dispatch/journey/router/strexp.rb +27 -0
  80. data/lib/action_dispatch/journey/router/utils.rb +93 -0
  81. data/lib/action_dispatch/journey/router.rb +144 -0
  82. data/lib/action_dispatch/journey/routes.rb +80 -0
  83. data/lib/action_dispatch/journey/scanner.rb +61 -0
  84. data/lib/action_dispatch/journey/visitors.rb +221 -0
  85. data/lib/action_dispatch/journey/visualizer/fsm.css +30 -0
  86. data/lib/action_dispatch/journey/visualizer/fsm.js +134 -0
  87. data/lib/action_dispatch/journey/visualizer/index.html.erb +52 -0
  88. data/lib/action_dispatch/journey.rb +5 -0
  89. data/lib/action_dispatch/middleware/callbacks.rb +16 -11
  90. data/lib/action_dispatch/middleware/cookies.rb +346 -125
  91. data/lib/action_dispatch/middleware/debug_exceptions.rb +52 -24
  92. data/lib/action_dispatch/middleware/exception_wrapper.rb +75 -9
  93. data/lib/action_dispatch/middleware/flash.rb +85 -72
  94. data/lib/action_dispatch/middleware/params_parser.rb +16 -31
  95. data/lib/action_dispatch/middleware/public_exceptions.rb +39 -14
  96. data/lib/action_dispatch/middleware/reloader.rb +16 -7
  97. data/lib/action_dispatch/middleware/remote_ip.rb +132 -40
  98. data/lib/action_dispatch/middleware/request_id.rb +3 -7
  99. data/lib/action_dispatch/middleware/session/abstract_store.rb +22 -20
  100. data/lib/action_dispatch/middleware/session/cache_store.rb +3 -3
  101. data/lib/action_dispatch/middleware/session/cookie_store.rb +84 -29
  102. data/lib/action_dispatch/middleware/session/mem_cache_store.rb +8 -3
  103. data/lib/action_dispatch/middleware/show_exceptions.rb +15 -44
  104. data/lib/action_dispatch/middleware/ssl.rb +72 -0
  105. data/lib/action_dispatch/middleware/stack.rb +6 -1
  106. data/lib/action_dispatch/middleware/static.rb +80 -23
  107. data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb +34 -0
  108. data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.text.erb +23 -0
  109. data/lib/action_dispatch/middleware/templates/rescues/_source.erb +27 -0
  110. data/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb +52 -0
  111. data/lib/action_dispatch/middleware/templates/rescues/_trace.text.erb +9 -0
  112. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb +16 -0
  113. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.text.erb +9 -0
  114. data/lib/action_dispatch/middleware/templates/rescues/layout.erb +133 -5
  115. data/lib/action_dispatch/middleware/templates/rescues/missing_template.html.erb +11 -0
  116. data/lib/action_dispatch/middleware/templates/rescues/missing_template.text.erb +3 -0
  117. data/lib/action_dispatch/middleware/templates/rescues/routing_error.html.erb +32 -0
  118. data/lib/action_dispatch/middleware/templates/rescues/routing_error.text.erb +11 -0
  119. data/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb +20 -0
  120. data/lib/action_dispatch/middleware/templates/rescues/template_error.text.erb +7 -0
  121. data/lib/action_dispatch/middleware/templates/rescues/unknown_action.html.erb +6 -0
  122. data/lib/action_dispatch/middleware/templates/rescues/unknown_action.text.erb +3 -0
  123. data/lib/action_dispatch/middleware/templates/routes/_route.html.erb +16 -0
  124. data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +200 -0
  125. data/lib/action_dispatch/railtie.rb +19 -6
  126. data/lib/action_dispatch/request/session.rb +193 -0
  127. data/lib/action_dispatch/request/utils.rb +35 -0
  128. data/lib/action_dispatch/routing/endpoint.rb +10 -0
  129. data/lib/action_dispatch/routing/inspector.rb +234 -0
  130. data/lib/action_dispatch/routing/mapper.rb +897 -436
  131. data/lib/action_dispatch/routing/polymorphic_routes.rb +213 -92
  132. data/lib/action_dispatch/routing/redirection.rb +97 -37
  133. data/lib/action_dispatch/routing/route_set.rb +432 -239
  134. data/lib/action_dispatch/routing/routes_proxy.rb +7 -4
  135. data/lib/action_dispatch/routing/url_for.rb +63 -34
  136. data/lib/action_dispatch/routing.rb +57 -89
  137. data/lib/action_dispatch/testing/assertions/dom.rb +2 -36
  138. data/lib/action_dispatch/testing/assertions/response.rb +24 -38
  139. data/lib/action_dispatch/testing/assertions/routing.rb +55 -54
  140. data/lib/action_dispatch/testing/assertions/selector.rb +2 -434
  141. data/lib/action_dispatch/testing/assertions/tag.rb +2 -137
  142. data/lib/action_dispatch/testing/assertions.rb +11 -7
  143. data/lib/action_dispatch/testing/integration.rb +88 -72
  144. data/lib/action_dispatch/testing/test_process.rb +9 -6
  145. data/lib/action_dispatch/testing/test_request.rb +13 -9
  146. data/lib/action_dispatch/testing/test_response.rb +1 -5
  147. data/lib/action_dispatch.rb +24 -21
  148. data/lib/action_pack/gem_version.rb +15 -0
  149. data/lib/action_pack/version.rb +5 -7
  150. data/lib/action_pack.rb +1 -1
  151. metadata +181 -292
  152. data/lib/abstract_controller/layouts.rb +0 -423
  153. data/lib/abstract_controller/view_paths.rb +0 -96
  154. data/lib/action_controller/caching/actions.rb +0 -185
  155. data/lib/action_controller/caching/pages.rb +0 -187
  156. data/lib/action_controller/caching/sweeping.rb +0 -97
  157. data/lib/action_controller/deprecated/integration_test.rb +0 -2
  158. data/lib/action_controller/deprecated/performance_test.rb +0 -1
  159. data/lib/action_controller/deprecated.rb +0 -3
  160. data/lib/action_controller/metal/compatibility.rb +0 -65
  161. data/lib/action_controller/metal/responder.rb +0 -286
  162. data/lib/action_controller/metal/session_management.rb +0 -14
  163. data/lib/action_controller/railties/paths.rb +0 -25
  164. data/lib/action_controller/record_identifier.rb +0 -85
  165. data/lib/action_controller/vendor/html-scanner/html/document.rb +0 -68
  166. data/lib/action_controller/vendor/html-scanner/html/node.rb +0 -532
  167. data/lib/action_controller/vendor/html-scanner/html/sanitizer.rb +0 -177
  168. data/lib/action_controller/vendor/html-scanner/html/selector.rb +0 -830
  169. data/lib/action_controller/vendor/html-scanner/html/tokenizer.rb +0 -107
  170. data/lib/action_controller/vendor/html-scanner/html/version.rb +0 -11
  171. data/lib/action_controller/vendor/html-scanner.rb +0 -20
  172. data/lib/action_dispatch/middleware/best_standards_support.rb +0 -30
  173. data/lib/action_dispatch/middleware/body_proxy.rb +0 -30
  174. data/lib/action_dispatch/middleware/head.rb +0 -18
  175. data/lib/action_dispatch/middleware/rescue.rb +0 -26
  176. data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb +0 -31
  177. data/lib/action_dispatch/middleware/templates/rescues/_trace.erb +0 -26
  178. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb +0 -10
  179. data/lib/action_dispatch/middleware/templates/rescues/missing_template.erb +0 -2
  180. data/lib/action_dispatch/middleware/templates/rescues/routing_error.erb +0 -15
  181. data/lib/action_dispatch/middleware/templates/rescues/template_error.erb +0 -17
  182. data/lib/action_dispatch/middleware/templates/rescues/unknown_action.erb +0 -2
  183. data/lib/action_dispatch/testing/performance_test.rb +0 -10
  184. data/lib/action_view/asset_paths.rb +0 -142
  185. data/lib/action_view/base.rb +0 -220
  186. data/lib/action_view/buffers.rb +0 -43
  187. data/lib/action_view/context.rb +0 -36
  188. data/lib/action_view/flows.rb +0 -79
  189. data/lib/action_view/helpers/active_model_helper.rb +0 -50
  190. data/lib/action_view/helpers/asset_paths.rb +0 -7
  191. data/lib/action_view/helpers/asset_tag_helper.rb +0 -457
  192. data/lib/action_view/helpers/asset_tag_helpers/asset_include_tag.rb +0 -146
  193. data/lib/action_view/helpers/asset_tag_helpers/asset_paths.rb +0 -93
  194. data/lib/action_view/helpers/asset_tag_helpers/javascript_tag_helpers.rb +0 -193
  195. data/lib/action_view/helpers/asset_tag_helpers/stylesheet_tag_helpers.rb +0 -148
  196. data/lib/action_view/helpers/atom_feed_helper.rb +0 -200
  197. data/lib/action_view/helpers/cache_helper.rb +0 -64
  198. data/lib/action_view/helpers/capture_helper.rb +0 -203
  199. data/lib/action_view/helpers/controller_helper.rb +0 -25
  200. data/lib/action_view/helpers/csrf_helper.rb +0 -32
  201. data/lib/action_view/helpers/date_helper.rb +0 -1062
  202. data/lib/action_view/helpers/debug_helper.rb +0 -40
  203. data/lib/action_view/helpers/form_helper.rb +0 -1486
  204. data/lib/action_view/helpers/form_options_helper.rb +0 -658
  205. data/lib/action_view/helpers/form_tag_helper.rb +0 -685
  206. data/lib/action_view/helpers/javascript_helper.rb +0 -110
  207. data/lib/action_view/helpers/number_helper.rb +0 -622
  208. data/lib/action_view/helpers/output_safety_helper.rb +0 -38
  209. data/lib/action_view/helpers/record_tag_helper.rb +0 -111
  210. data/lib/action_view/helpers/rendering_helper.rb +0 -90
  211. data/lib/action_view/helpers/sanitize_helper.rb +0 -259
  212. data/lib/action_view/helpers/tag_helper.rb +0 -160
  213. data/lib/action_view/helpers/text_helper.rb +0 -426
  214. data/lib/action_view/helpers/translation_helper.rb +0 -91
  215. data/lib/action_view/helpers/url_helper.rb +0 -693
  216. data/lib/action_view/helpers.rb +0 -60
  217. data/lib/action_view/locale/en.yml +0 -160
  218. data/lib/action_view/log_subscriber.rb +0 -28
  219. data/lib/action_view/lookup_context.rb +0 -254
  220. data/lib/action_view/path_set.rb +0 -89
  221. data/lib/action_view/railtie.rb +0 -55
  222. data/lib/action_view/renderer/abstract_renderer.rb +0 -41
  223. data/lib/action_view/renderer/partial_renderer.rb +0 -415
  224. data/lib/action_view/renderer/renderer.rb +0 -54
  225. data/lib/action_view/renderer/streaming_template_renderer.rb +0 -106
  226. data/lib/action_view/renderer/template_renderer.rb +0 -94
  227. data/lib/action_view/template/error.rb +0 -128
  228. data/lib/action_view/template/handlers/builder.rb +0 -26
  229. data/lib/action_view/template/handlers/erb.rb +0 -125
  230. data/lib/action_view/template/handlers.rb +0 -50
  231. data/lib/action_view/template/resolver.rb +0 -272
  232. data/lib/action_view/template/text.rb +0 -30
  233. data/lib/action_view/template.rb +0 -337
  234. data/lib/action_view/test_case.rb +0 -245
  235. data/lib/action_view/testing/resolvers.rb +0 -50
  236. data/lib/action_view.rb +0 -84
  237. data/lib/sprockets/assets.rake +0 -99
  238. data/lib/sprockets/bootstrap.rb +0 -37
  239. data/lib/sprockets/compressors.rb +0 -83
  240. data/lib/sprockets/helpers/isolated_helper.rb +0 -13
  241. data/lib/sprockets/helpers/rails_helper.rb +0 -182
  242. data/lib/sprockets/helpers.rb +0 -6
  243. data/lib/sprockets/railtie.rb +0 -62
  244. data/lib/sprockets/static_compiler.rb +0 -56
@@ -0,0 +1,328 @@
1
+ require 'action_dispatch/http/response'
2
+ require 'delegate'
3
+ require 'active_support/json'
4
+
5
+ module ActionController
6
+ # Mix this module in to your controller, and all actions in that controller
7
+ # will be able to stream data to the client as it's written.
8
+ #
9
+ # class MyController < ActionController::Base
10
+ # include ActionController::Live
11
+ #
12
+ # def stream
13
+ # response.headers['Content-Type'] = 'text/event-stream'
14
+ # 100.times {
15
+ # response.stream.write "hello world\n"
16
+ # sleep 1
17
+ # }
18
+ # ensure
19
+ # response.stream.close
20
+ # end
21
+ # end
22
+ #
23
+ # There are a few caveats with this use. You *cannot* write headers after the
24
+ # response has been committed (Response#committed? will return truthy).
25
+ # Calling +write+ or +close+ on the response stream will cause the response
26
+ # object to be committed. Make sure all headers are set before calling write
27
+ # or close on your stream.
28
+ #
29
+ # You *must* call close on your stream when you're finished, otherwise the
30
+ # socket may be left open forever.
31
+ #
32
+ # The final caveat is that your actions are executed in a separate thread than
33
+ # the main thread. Make sure your actions are thread safe, and this shouldn't
34
+ # be a problem (don't share state across threads, etc).
35
+ module Live
36
+ # This class provides the ability to write an SSE (Server Sent Event)
37
+ # to an IO stream. The class is initialized with a stream and can be used
38
+ # to either write a JSON string or an object which can be converted to JSON.
39
+ #
40
+ # Writing an object will convert it into standard SSE format with whatever
41
+ # options you have configured. You may choose to set the following options:
42
+ #
43
+ # 1) Event. If specified, an event with this name will be dispatched on
44
+ # the browser.
45
+ # 2) Retry. The reconnection time in milliseconds used when attempting
46
+ # to send the event.
47
+ # 3) Id. If the connection dies while sending an SSE to the browser, then
48
+ # the server will receive a +Last-Event-ID+ header with value equal to +id+.
49
+ #
50
+ # After setting an option in the constructor of the SSE object, all future
51
+ # SSEs sent across the stream will use those options unless overridden.
52
+ #
53
+ # Example Usage:
54
+ #
55
+ # class MyController < ActionController::Base
56
+ # include ActionController::Live
57
+ #
58
+ # def index
59
+ # response.headers['Content-Type'] = 'text/event-stream'
60
+ # sse = SSE.new(response.stream, retry: 300, event: "event-name")
61
+ # sse.write({ name: 'John'})
62
+ # sse.write({ name: 'John'}, id: 10)
63
+ # sse.write({ name: 'John'}, id: 10, event: "other-event")
64
+ # sse.write({ name: 'John'}, id: 10, event: "other-event", retry: 500)
65
+ # ensure
66
+ # sse.close
67
+ # end
68
+ # end
69
+ #
70
+ # Note: SSEs are not currently supported by IE. However, they are supported
71
+ # by Chrome, Firefox, Opera, and Safari.
72
+ class SSE
73
+
74
+ WHITELISTED_OPTIONS = %w( retry event id )
75
+
76
+ def initialize(stream, options = {})
77
+ @stream = stream
78
+ @options = options
79
+ end
80
+
81
+ def close
82
+ @stream.close
83
+ end
84
+
85
+ def write(object, options = {})
86
+ case object
87
+ when String
88
+ perform_write(object, options)
89
+ else
90
+ perform_write(ActiveSupport::JSON.encode(object), options)
91
+ end
92
+ end
93
+
94
+ private
95
+
96
+ def perform_write(json, options)
97
+ current_options = @options.merge(options).stringify_keys
98
+
99
+ WHITELISTED_OPTIONS.each do |option_name|
100
+ if (option_value = current_options[option_name])
101
+ @stream.write "#{option_name}: #{option_value}\n"
102
+ end
103
+ end
104
+
105
+ message = json.gsub(/\n/, "\ndata: ")
106
+ @stream.write "data: #{message}\n\n"
107
+ end
108
+ end
109
+
110
+ class ClientDisconnected < RuntimeError
111
+ end
112
+
113
+ class Buffer < ActionDispatch::Response::Buffer #:nodoc:
114
+ include MonitorMixin
115
+
116
+ # Ignore that the client has disconnected.
117
+ #
118
+ # If this value is `true`, calling `write` after the client
119
+ # disconnects will result in the written content being silently
120
+ # discarded. If this value is `false` (the default), a
121
+ # ClientDisconnected exception will be raised.
122
+ attr_accessor :ignore_disconnect
123
+
124
+ def initialize(response)
125
+ @error_callback = lambda { true }
126
+ @cv = new_cond
127
+ @aborted = false
128
+ @ignore_disconnect = false
129
+ super(response, SizedQueue.new(10))
130
+ end
131
+
132
+ def write(string)
133
+ unless @response.committed?
134
+ @response.headers["Cache-Control"] = "no-cache"
135
+ @response.headers.delete "Content-Length"
136
+ end
137
+
138
+ super
139
+
140
+ unless connected?
141
+ @buf.clear
142
+
143
+ unless @ignore_disconnect
144
+ # Raise ClientDisconnected, which is a RuntimeError (not an
145
+ # IOError), because that's more appropriate for something beyond
146
+ # the developer's control.
147
+ raise ClientDisconnected, "client disconnected"
148
+ end
149
+ end
150
+ end
151
+
152
+ def each
153
+ @response.sending!
154
+ while str = @buf.pop
155
+ yield str
156
+ end
157
+ @response.sent!
158
+ end
159
+
160
+ # Write a 'close' event to the buffer; the producer/writing thread
161
+ # uses this to notify us that it's finished supplying content.
162
+ #
163
+ # See also #abort.
164
+ def close
165
+ synchronize do
166
+ super
167
+ @buf.push nil
168
+ @cv.broadcast
169
+ end
170
+ end
171
+
172
+ # Inform the producer/writing thread that the client has
173
+ # disconnected; the reading thread is no longer interested in
174
+ # anything that's being written.
175
+ #
176
+ # See also #close.
177
+ def abort
178
+ synchronize do
179
+ @aborted = true
180
+ @buf.clear
181
+ end
182
+ end
183
+
184
+ # Is the client still connected and waiting for content?
185
+ #
186
+ # The result of calling `write` when this is `false` is determined
187
+ # by `ignore_disconnect`.
188
+ def connected?
189
+ !@aborted
190
+ end
191
+
192
+ def await_close
193
+ synchronize do
194
+ @cv.wait_until { @closed }
195
+ end
196
+ end
197
+
198
+ def on_error(&block)
199
+ @error_callback = block
200
+ end
201
+
202
+ def call_on_error
203
+ @error_callback.call
204
+ end
205
+ end
206
+
207
+ class Response < ActionDispatch::Response #:nodoc: all
208
+ class Header < DelegateClass(Hash) # :nodoc:
209
+ def initialize(response, header)
210
+ @response = response
211
+ super(header)
212
+ end
213
+
214
+ def []=(k,v)
215
+ if @response.committed?
216
+ raise ActionDispatch::IllegalStateError, 'header already sent'
217
+ end
218
+
219
+ super
220
+ end
221
+
222
+ def merge(other)
223
+ self.class.new @response, __getobj__.merge(other)
224
+ end
225
+
226
+ def to_hash
227
+ __getobj__.dup
228
+ end
229
+ end
230
+
231
+ private
232
+
233
+ def before_committed
234
+ super
235
+ jar = request.cookie_jar
236
+ # The response can be committed multiple times
237
+ jar.write self unless committed?
238
+ end
239
+
240
+ def before_sending
241
+ super
242
+ request.cookie_jar.commit!
243
+ headers.freeze
244
+ end
245
+
246
+ def build_buffer(response, body)
247
+ buf = Live::Buffer.new response
248
+ body.each { |part| buf.write part }
249
+ buf
250
+ end
251
+
252
+ def merge_default_headers(original, default)
253
+ Header.new self, super
254
+ end
255
+
256
+ def handle_conditional_get!
257
+ super unless committed?
258
+ end
259
+ end
260
+
261
+ def process(name)
262
+ t1 = Thread.current
263
+ locals = t1.keys.map { |key| [key, t1[key]] }
264
+
265
+ error = nil
266
+ # This processes the action in a child thread. It lets us return the
267
+ # response code and headers back up the rack stack, and still process
268
+ # the body in parallel with sending data to the client
269
+ Thread.new {
270
+ t2 = Thread.current
271
+ t2.abort_on_exception = true
272
+
273
+ # Since we're processing the view in a different thread, copy the
274
+ # thread locals from the main thread to the child thread. :'(
275
+ locals.each { |k,v| t2[k] = v }
276
+
277
+ begin
278
+ super(name)
279
+ rescue => e
280
+ if @_response.committed?
281
+ begin
282
+ @_response.stream.write(ActionView::Base.streaming_completion_on_exception) if request.format == :html
283
+ @_response.stream.call_on_error
284
+ rescue => exception
285
+ log_error(exception)
286
+ ensure
287
+ log_error(e)
288
+ @_response.stream.close
289
+ end
290
+ else
291
+ error = e
292
+ end
293
+ ensure
294
+ @_response.commit!
295
+ end
296
+ }
297
+
298
+ @_response.await_commit
299
+ raise error if error
300
+ end
301
+
302
+ def log_error(exception)
303
+ logger = ActionController::Base.logger
304
+ return unless logger
305
+
306
+ logger.fatal do
307
+ message = "\n#{exception.class} (#{exception.message}):\n"
308
+ message << exception.annoted_source_code.to_s if exception.respond_to?(:annoted_source_code)
309
+ message << " " << exception.backtrace.join("\n ")
310
+ "#{message}\n\n"
311
+ end
312
+ end
313
+
314
+ def response_body=(body)
315
+ super
316
+ response.close if response
317
+ end
318
+
319
+ def set_response!(request)
320
+ if request.env["HTTP_VERSION"] == "HTTP/1.0"
321
+ super
322
+ else
323
+ @_response = Live::Response.new
324
+ @_response.request = request
325
+ end
326
+ end
327
+ end
328
+ end