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
@@ -1,7 +1,8 @@
1
- require 'digest/md5'
2
- require 'active_support/core_ext/module/delegation'
3
- require 'active_support/core_ext/object/blank'
4
- require 'active_support/core_ext/class/attribute_accessors'
1
+ require 'active_support/core_ext/module/attribute_accessors'
2
+ require 'active_support/core_ext/string/filters'
3
+ require 'active_support/deprecation'
4
+ require 'action_dispatch/http/filter_redirect'
5
+ require 'monitor'
5
6
 
6
7
  module ActionDispatch # :nodoc:
7
8
  # Represents an HTTP response generated by a controller action. Use it to
@@ -29,19 +30,26 @@ module ActionDispatch # :nodoc:
29
30
  # class DemoControllerTest < ActionDispatch::IntegrationTest
30
31
  # def test_print_root_path_to_console
31
32
  # get('/')
32
- # puts @response.body
33
+ # puts response.body
33
34
  # end
34
35
  # end
35
36
  class Response
36
- attr_accessor :request, :header
37
+ # The request that the response is responding to.
38
+ attr_accessor :request
39
+
40
+ # The HTTP status code.
37
41
  attr_reader :status
42
+
38
43
  attr_writer :sending_file
39
44
 
45
+ # Get and set headers for this response.
46
+ attr_accessor :header
47
+
40
48
  alias_method :headers=, :header=
41
49
  alias_method :headers, :header
42
50
 
43
51
  delegate :[], :[]=, :to => :@header
44
- delegate :each, :to => :@body
52
+ delegate :each, :to => :@stream
45
53
 
46
54
  # Sets the HTTP response's content MIME type. For example, in the controller
47
55
  # you could write this:
@@ -51,22 +59,78 @@ module ActionDispatch # :nodoc:
51
59
  # If a character set has been defined for this response (see charset=) then
52
60
  # the character set information will also be included in the content type
53
61
  # information.
54
- attr_accessor :charset, :content_type
62
+ attr_reader :content_type
63
+
64
+ # The charset of the response. HTML wants to know the encoding of the
65
+ # content you're giving them, so we need to send that along.
66
+ attr_accessor :charset
55
67
 
56
68
  CONTENT_TYPE = "Content-Type".freeze
57
69
  SET_COOKIE = "Set-Cookie".freeze
58
70
  LOCATION = "Location".freeze
59
-
71
+ NO_CONTENT_CODES = [204, 304]
72
+
60
73
  cattr_accessor(:default_charset) { "utf-8" }
74
+ cattr_accessor(:default_headers)
61
75
 
62
76
  include Rack::Response::Helpers
77
+ include ActionDispatch::Http::FilterRedirect
63
78
  include ActionDispatch::Http::Cache::Response
79
+ include MonitorMixin
80
+
81
+ class Buffer # :nodoc:
82
+ def initialize(response, buf)
83
+ @response = response
84
+ @buf = buf
85
+ @closed = false
86
+ end
87
+
88
+ def write(string)
89
+ raise IOError, "closed stream" if closed?
90
+
91
+ @response.commit!
92
+ @buf.push string
93
+ end
94
+
95
+ def each(&block)
96
+ @response.sending!
97
+ x = @buf.each(&block)
98
+ @response.sent!
99
+ x
100
+ end
101
+
102
+ def abort
103
+ end
104
+
105
+ def close
106
+ @response.commit!
107
+ @closed = true
108
+ end
109
+
110
+ def closed?
111
+ @closed
112
+ end
113
+ end
114
+
115
+ # The underlying body, as a streamable object.
116
+ attr_reader :stream
117
+
118
+ def initialize(status = 200, header = {}, body = [], options = {})
119
+ super()
120
+
121
+ default_headers = options.fetch(:default_headers, self.class.default_headers)
122
+ header = merge_default_headers(header, default_headers)
64
123
 
65
- def initialize(status = 200, header = {}, body = [])
66
124
  self.body, self.header, self.status = body, header, status
67
125
 
68
126
  @sending_file = false
69
- @blank = false
127
+ @blank = false
128
+ @cv = new_cond
129
+ @committed = false
130
+ @sending = false
131
+ @sent = false
132
+ @content_type = nil
133
+ @charset = nil
70
134
 
71
135
  if content_type = self[CONTENT_TYPE]
72
136
  type, charset = content_type.split(/;\s*charset=/)
@@ -79,37 +143,78 @@ module ActionDispatch # :nodoc:
79
143
  yield self if block_given?
80
144
  end
81
145
 
146
+ def await_commit
147
+ synchronize do
148
+ @cv.wait_until { @committed }
149
+ end
150
+ end
151
+
152
+ def await_sent
153
+ synchronize { @cv.wait_until { @sent } }
154
+ end
155
+
156
+ def commit!
157
+ synchronize do
158
+ before_committed
159
+ @committed = true
160
+ @cv.broadcast
161
+ end
162
+ end
163
+
164
+ def sending!
165
+ synchronize do
166
+ before_sending
167
+ @sending = true
168
+ @cv.broadcast
169
+ end
170
+ end
171
+
172
+ def sent!
173
+ synchronize do
174
+ @sent = true
175
+ @cv.broadcast
176
+ end
177
+ end
178
+
179
+ def sending?; synchronize { @sending }; end
180
+ def committed?; synchronize { @committed }; end
181
+ def sent?; synchronize { @sent }; end
182
+
183
+ # Sets the HTTP status code.
82
184
  def status=(status)
83
185
  @status = Rack::Utils.status_code(status)
84
186
  end
85
187
 
86
- # The response code of the request
188
+ # Sets the HTTP content type.
189
+ def content_type=(content_type)
190
+ @content_type = content_type.to_s
191
+ end
192
+
193
+ # The response code of the request.
87
194
  def response_code
88
195
  @status
89
196
  end
90
197
 
91
- # Returns a String to ensure compatibility with Net::HTTPResponse
198
+ # Returns a string to ensure compatibility with <tt>Net::HTTPResponse</tt>.
92
199
  def code
93
200
  @status.to_s
94
201
  end
95
202
 
203
+ # Returns the corresponding message for the current HTTP status code:
204
+ #
205
+ # response.status = 200
206
+ # response.message # => "OK"
207
+ #
208
+ # response.status = 404
209
+ # response.message # => "Not Found"
210
+ #
96
211
  def message
97
212
  Rack::Utils::HTTP_STATUS_CODES[@status]
98
213
  end
99
214
  alias_method :status_message, :message
100
215
 
101
- def respond_to?(method)
102
- if method.to_sym == :to_path
103
- @body.respond_to?(:to_path)
104
- else
105
- super
106
- end
107
- end
108
-
109
- def to_path
110
- @body.to_path
111
- end
112
-
216
+ # Returns the content of the response as a string. This contains the contents
217
+ # of any calls to <tt>render</tt>.
113
218
  def body
114
219
  strings = []
115
220
  each { |part| strings << part.to_s }
@@ -118,21 +223,23 @@ module ActionDispatch # :nodoc:
118
223
 
119
224
  EMPTY = " "
120
225
 
226
+ # Allows you to manually set or override the response body.
121
227
  def body=(body)
122
228
  @blank = true if body == EMPTY
123
229
 
124
- # Explicitly check for strings. This is *wrong* theoretically
125
- # but if we don't check this, the performance on string bodies
126
- # is bad on Ruby 1.8 (because strings responds to each then).
127
- @body = if body.respond_to?(:to_str) || !body.respond_to?(:each)
128
- [body]
230
+ if body.respond_to?(:to_path)
231
+ @stream = body
129
232
  else
130
- body
233
+ synchronize do
234
+ @stream = build_buffer self, munge_body_object(body)
235
+ end
131
236
  end
132
237
  end
133
238
 
134
239
  def body_parts
135
- @body
240
+ parts = []
241
+ @stream.each { |x| parts << x }
242
+ parts
136
243
  end
137
244
 
138
245
  def set_cookie(key, value)
@@ -143,34 +250,54 @@ module ActionDispatch # :nodoc:
143
250
  ::Rack::Utils.delete_cookie_header!(header, key, value)
144
251
  end
145
252
 
253
+ # The location header we'll be responding with.
146
254
  def location
147
255
  headers[LOCATION]
148
256
  end
149
257
  alias_method :redirect_url, :location
150
258
 
259
+ # Sets the location header we'll be responding with.
151
260
  def location=(url)
152
261
  headers[LOCATION] = url
153
262
  end
154
263
 
155
264
  def close
156
- @body.close if @body.respond_to?(:close)
265
+ stream.close if stream.respond_to?(:close)
157
266
  end
158
267
 
159
- def to_a
160
- assign_default_content_type_and_charset!
161
- handle_conditional_get!
162
-
163
- @header[SET_COOKIE] = @header[SET_COOKIE].join("\n") if @header[SET_COOKIE].respond_to?(:join)
164
-
165
- if [204, 304].include?(@status)
166
- @header.delete CONTENT_TYPE
167
- [@status, @header, []]
168
- else
169
- [@status, @header, self]
268
+ def abort
269
+ if stream.respond_to?(:abort)
270
+ stream.abort
271
+ elsif stream.respond_to?(:close)
272
+ # `stream.close` should really be reserved for a close from the
273
+ # other direction, but we must fall back to it for
274
+ # compatibility.
275
+ stream.close
170
276
  end
171
277
  end
278
+
279
+ # Turns the Response into a Rack-compatible array of the status, headers,
280
+ # and body. Allows explict splatting:
281
+ #
282
+ # status, headers, body = *response
283
+ def to_a
284
+ rack_response @status, @header.to_hash
285
+ end
172
286
  alias prepare! to_a
173
- alias to_ary to_a # For implicit splat on 1.9.2
287
+
288
+ # Be super clear that a response object is not an Array. Defining this
289
+ # would make implicit splatting work, but it also makes adding responses
290
+ # as arrays work, and "flattening" responses, cascading to the rack body!
291
+ # Not sensible behavior.
292
+ def to_ary
293
+ ActiveSupport::Deprecation.warn(<<-MSG.squish)
294
+ `ActionDispatch::Response#to_ary` no longer performs implicit conversion
295
+ to an array. Please use `response.to_a` instead, or a splat like `status,
296
+ headers, body = *response`.
297
+ MSG
298
+
299
+ to_a
300
+ end
174
301
 
175
302
  # Returns the response cookies, converted to a Hash of (name => value) pairs
176
303
  #
@@ -191,16 +318,88 @@ module ActionDispatch # :nodoc:
191
318
 
192
319
  private
193
320
 
194
- def assign_default_content_type_and_charset!
321
+ def before_committed
322
+ end
323
+
324
+ def before_sending
325
+ end
326
+
327
+ def merge_default_headers(original, default)
328
+ default.respond_to?(:merge) ? default.merge(original) : original
329
+ end
330
+
331
+ def build_buffer(response, body)
332
+ Buffer.new response, body
333
+ end
334
+
335
+ def munge_body_object(body)
336
+ body.respond_to?(:each) ? body : [body]
337
+ end
338
+
339
+ def assign_default_content_type_and_charset!(headers)
195
340
  return if headers[CONTENT_TYPE].present?
196
341
 
197
342
  @content_type ||= Mime::HTML
198
- @charset ||= self.class.default_charset
343
+ @charset ||= self.class.default_charset unless @charset == false
199
344
 
200
345
  type = @content_type.to_s.dup
201
- type << "; charset=#{@charset}" unless @sending_file
346
+ type << "; charset=#{@charset}" if append_charset?
202
347
 
203
348
  headers[CONTENT_TYPE] = type
204
349
  end
350
+
351
+ def append_charset?
352
+ !@sending_file && @charset != false
353
+ end
354
+
355
+ class RackBody
356
+ def initialize(response)
357
+ @response = response
358
+ end
359
+
360
+ def each(*args, &block)
361
+ @response.each(*args, &block)
362
+ end
363
+
364
+ def close
365
+ # Rack "close" maps to Response#abort, and *not* Response#close
366
+ # (which is used when the controller's finished writing)
367
+ @response.abort
368
+ end
369
+
370
+ def body
371
+ @response.body
372
+ end
373
+
374
+ def respond_to?(method, include_private = false)
375
+ if method.to_s == 'to_path'
376
+ @response.stream.respond_to?(method)
377
+ else
378
+ super
379
+ end
380
+ end
381
+
382
+ def to_path
383
+ @response.stream.to_path
384
+ end
385
+
386
+ def to_ary
387
+ nil
388
+ end
389
+ end
390
+
391
+ def rack_response(status, header)
392
+ assign_default_content_type_and_charset!(header)
393
+ handle_conditional_get!
394
+
395
+ header[SET_COOKIE] = header[SET_COOKIE].join("\n") if header[SET_COOKIE].respond_to?(:join)
396
+
397
+ if NO_CONTENT_CODES.include?(@status)
398
+ header.delete CONTENT_TYPE
399
+ [status, header, []]
400
+ else
401
+ [status, header, RackBody.new(self)]
402
+ end
403
+ end
205
404
  end
206
405
  end
@@ -1,47 +1,78 @@
1
1
  module ActionDispatch
2
2
  module Http
3
+ # Models uploaded files.
4
+ #
5
+ # The actual file is accessible via the +tempfile+ accessor, though some
6
+ # of its interface is available directly for convenience.
7
+ #
8
+ # Uploaded files are temporary files whose lifespan is one request. When
9
+ # the object is finalized Ruby unlinks the file, so there is no need to
10
+ # clean them with a separate maintenance task.
3
11
  class UploadedFile
4
- attr_accessor :original_filename, :content_type, :tempfile, :headers
12
+ # The basename of the file in the client.
13
+ attr_accessor :original_filename
5
14
 
6
- def initialize(hash)
7
- @original_filename = encode_filename(hash[:filename])
8
- @content_type = hash[:type]
9
- @headers = hash[:head]
15
+ # A string with the MIME type of the file.
16
+ attr_accessor :content_type
17
+
18
+ # A +Tempfile+ object with the actual uploaded file. Note that some of
19
+ # its interface is available directly.
20
+ attr_accessor :tempfile
21
+ alias :to_io :tempfile
22
+
23
+ # A string with the headers of the multipart request.
24
+ attr_accessor :headers
25
+
26
+ def initialize(hash) # :nodoc:
10
27
  @tempfile = hash[:tempfile]
11
28
  raise(ArgumentError, ':tempfile is required') unless @tempfile
29
+
30
+ @original_filename = hash[:filename]
31
+ if @original_filename
32
+ begin
33
+ @original_filename.encode!(Encoding::UTF_8)
34
+ rescue EncodingError
35
+ @original_filename.force_encoding(Encoding::UTF_8)
36
+ end
37
+ end
38
+ @content_type = hash[:type]
39
+ @headers = hash[:head]
12
40
  end
13
41
 
14
- def read(*args)
15
- @tempfile.read(*args)
42
+ # Shortcut for +tempfile.read+.
43
+ def read(length=nil, buffer=nil)
44
+ @tempfile.read(length, buffer)
16
45
  end
17
46
 
18
- # Delegate these methods to the tempfile.
19
- [:open, :path, :rewind, :size].each do |method|
20
- class_eval "def #{method}; @tempfile.#{method}; end"
47
+ # Shortcut for +tempfile.open+.
48
+ def open
49
+ @tempfile.open
21
50
  end
22
51
 
23
- private
24
- def encode_filename(filename)
25
- # Encode the filename in the utf8 encoding, unless it is nil or we're in 1.8
26
- if "ruby".encoding_aware? && filename
27
- filename.force_encoding("UTF-8").encode!
28
- else
29
- filename
30
- end
52
+ # Shortcut for +tempfile.close+.
53
+ def close(unlink_now=false)
54
+ @tempfile.close(unlink_now)
31
55
  end
32
- end
33
56
 
34
- module Upload
35
- # Convert nested Hash to HashWithIndifferentAccess and replace
36
- # file upload hash with UploadedFile objects
37
- def normalize_parameters(value)
38
- if Hash === value && value.has_key?(:tempfile)
39
- UploadedFile.new(value)
40
- else
41
- super
42
- end
57
+ # Shortcut for +tempfile.path+.
58
+ def path
59
+ @tempfile.path
60
+ end
61
+
62
+ # Shortcut for +tempfile.rewind+.
63
+ def rewind
64
+ @tempfile.rewind
65
+ end
66
+
67
+ # Shortcut for +tempfile.size+.
68
+ def size
69
+ @tempfile.size
70
+ end
71
+
72
+ # Shortcut for +tempfile.eof?+.
73
+ def eof?
74
+ @tempfile.eof?
43
75
  end
44
- private :normalize_parameters
45
76
  end
46
77
  end
47
78
  end