actionpack 4.0.1 → 4.2.11.1

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 (241) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +402 -1173
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +7 -7
  5. data/lib/abstract_controller/base.rb +39 -7
  6. data/lib/abstract_controller/callbacks.rb +32 -53
  7. data/lib/abstract_controller/collector.rb +11 -1
  8. data/lib/abstract_controller/helpers.rb +26 -16
  9. data/lib/abstract_controller/railties/routes_helpers.rb +3 -3
  10. data/lib/abstract_controller/rendering.rb +57 -127
  11. data/lib/abstract_controller/url_for.rb +1 -1
  12. data/lib/abstract_controller.rb +1 -2
  13. data/lib/action_controller/base.rb +19 -10
  14. data/lib/action_controller/caching/fragments.rb +7 -1
  15. data/lib/action_controller/caching.rb +2 -12
  16. data/lib/action_controller/log_subscriber.rb +29 -20
  17. data/lib/action_controller/metal/conditional_get.rb +37 -12
  18. data/lib/action_controller/metal/data_streaming.rb +1 -1
  19. data/lib/action_controller/metal/etag_with_template_digest.rb +50 -0
  20. data/lib/action_controller/metal/exceptions.rb +1 -1
  21. data/lib/action_controller/metal/flash.rb +17 -0
  22. data/lib/action_controller/metal/force_ssl.rb +2 -2
  23. data/lib/action_controller/metal/head.rb +8 -6
  24. data/lib/action_controller/metal/helpers.rb +6 -2
  25. data/lib/action_controller/metal/http_authentication.rb +45 -23
  26. data/lib/action_controller/metal/instrumentation.rb +9 -6
  27. data/lib/action_controller/metal/live.rb +173 -20
  28. data/lib/action_controller/metal/mime_responds.rb +127 -232
  29. data/lib/action_controller/metal/params_wrapper.rb +16 -9
  30. data/lib/action_controller/metal/rack_delegation.rb +1 -1
  31. data/lib/action_controller/metal/redirecting.rb +34 -26
  32. data/lib/action_controller/metal/renderers.rb +39 -12
  33. data/lib/action_controller/metal/rendering.rb +41 -14
  34. data/lib/action_controller/metal/request_forgery_protection.rb +147 -19
  35. data/lib/action_controller/metal/streaming.rb +19 -21
  36. data/lib/action_controller/metal/strong_parameters.rb +166 -22
  37. data/lib/action_controller/metal/testing.rb +0 -1
  38. data/lib/action_controller/metal/url_for.rb +11 -12
  39. data/lib/action_controller/metal.rb +14 -8
  40. data/lib/action_controller/model_naming.rb +1 -1
  41. data/lib/action_controller/railtie.rb +5 -1
  42. data/lib/action_controller/test_case.rb +160 -94
  43. data/lib/action_controller.rb +2 -18
  44. data/lib/action_dispatch/http/cache.rb +5 -4
  45. data/lib/action_dispatch/http/filter_parameters.rb +2 -2
  46. data/lib/action_dispatch/http/filter_redirect.rb +5 -4
  47. data/lib/action_dispatch/http/headers.rb +46 -10
  48. data/lib/action_dispatch/http/mime_negotiation.rb +31 -4
  49. data/lib/action_dispatch/http/mime_type.rb +25 -26
  50. data/lib/action_dispatch/http/mime_types.rb +1 -0
  51. data/lib/action_dispatch/http/parameter_filter.rb +1 -1
  52. data/lib/action_dispatch/http/parameters.rb +25 -41
  53. data/lib/action_dispatch/http/request.rb +49 -32
  54. data/lib/action_dispatch/http/response.rb +127 -25
  55. data/lib/action_dispatch/http/upload.rb +9 -21
  56. data/lib/action_dispatch/http/url.rb +97 -70
  57. data/lib/action_dispatch/journey/formatter.rb +35 -19
  58. data/lib/action_dispatch/journey/gtg/builder.rb +3 -3
  59. data/lib/action_dispatch/journey/gtg/simulator.rb +10 -7
  60. data/lib/action_dispatch/journey/gtg/transition_table.rb +23 -33
  61. data/lib/action_dispatch/journey/nfa/dot.rb +2 -2
  62. data/lib/action_dispatch/journey/nfa/simulator.rb +1 -1
  63. data/lib/action_dispatch/journey/nfa/transition_table.rb +5 -5
  64. data/lib/action_dispatch/journey/nodes/node.rb +4 -0
  65. data/lib/action_dispatch/journey/parser.rb +51 -59
  66. data/lib/action_dispatch/journey/parser.y +12 -10
  67. data/lib/action_dispatch/journey/path/pattern.rb +16 -19
  68. data/lib/action_dispatch/journey/route.rb +8 -19
  69. data/lib/action_dispatch/journey/router/strexp.rb +9 -6
  70. data/lib/action_dispatch/journey/router/utils.rb +54 -18
  71. data/lib/action_dispatch/journey/router.rb +53 -75
  72. data/lib/action_dispatch/journey/routes.rb +4 -0
  73. data/lib/action_dispatch/journey/scanner.rb +5 -5
  74. data/lib/action_dispatch/journey/visitors.rb +81 -60
  75. data/lib/action_dispatch/journey/visualizer/fsm.css +0 -4
  76. data/lib/action_dispatch/journey/visualizer/index.html.erb +2 -2
  77. data/lib/action_dispatch/middleware/callbacks.rb +7 -7
  78. data/lib/action_dispatch/middleware/cookies.rb +119 -43
  79. data/lib/action_dispatch/middleware/debug_exceptions.rb +32 -13
  80. data/lib/action_dispatch/middleware/exception_wrapper.rb +60 -20
  81. data/lib/action_dispatch/middleware/flash.rb +37 -24
  82. data/lib/action_dispatch/middleware/params_parser.rb +2 -2
  83. data/lib/action_dispatch/middleware/public_exceptions.rb +12 -3
  84. data/lib/action_dispatch/middleware/reloader.rb +11 -2
  85. data/lib/action_dispatch/middleware/remote_ip.rb +40 -54
  86. data/lib/action_dispatch/middleware/request_id.rb +1 -1
  87. data/lib/action_dispatch/middleware/session/cache_store.rb +3 -3
  88. data/lib/action_dispatch/middleware/session/cookie_store.rb +8 -7
  89. data/lib/action_dispatch/middleware/show_exceptions.rb +6 -2
  90. data/lib/action_dispatch/middleware/ssl.rb +10 -7
  91. data/lib/action_dispatch/middleware/static.rb +79 -23
  92. data/lib/action_dispatch/middleware/templates/rescues/{_request_and_response.erb → _request_and_response.html.erb} +0 -0
  93. data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.text.erb +23 -0
  94. data/lib/action_dispatch/middleware/templates/rescues/_source.erb +21 -19
  95. data/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb +52 -0
  96. data/lib/action_dispatch/middleware/templates/rescues/_trace.text.erb +9 -0
  97. data/lib/action_dispatch/middleware/templates/rescues/{diagnostics.erb → diagnostics.html.erb} +1 -1
  98. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.text.erb +9 -0
  99. data/lib/action_dispatch/middleware/templates/rescues/layout.erb +6 -0
  100. data/lib/action_dispatch/middleware/templates/rescues/missing_template.html.erb +11 -0
  101. data/lib/action_dispatch/middleware/templates/rescues/missing_template.text.erb +3 -0
  102. data/lib/action_dispatch/middleware/templates/rescues/{routing_error.erb → routing_error.html.erb} +3 -1
  103. data/lib/action_dispatch/middleware/templates/rescues/routing_error.text.erb +11 -0
  104. data/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb +20 -0
  105. data/lib/action_dispatch/middleware/templates/rescues/template_error.text.erb +7 -0
  106. data/lib/action_dispatch/middleware/templates/rescues/{unknown_action.erb → unknown_action.html.erb} +1 -1
  107. data/lib/action_dispatch/middleware/templates/rescues/unknown_action.text.erb +3 -0
  108. data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +120 -64
  109. data/lib/action_dispatch/railtie.rb +5 -2
  110. data/lib/action_dispatch/request/session.rb +12 -0
  111. data/lib/action_dispatch/request/utils.rb +35 -0
  112. data/lib/action_dispatch/routing/endpoint.rb +10 -0
  113. data/lib/action_dispatch/routing/inspector.rb +11 -17
  114. data/lib/action_dispatch/routing/mapper.rb +519 -312
  115. data/lib/action_dispatch/routing/polymorphic_routes.rb +204 -79
  116. data/lib/action_dispatch/routing/redirection.rb +51 -26
  117. data/lib/action_dispatch/routing/route_set.rb +331 -206
  118. data/lib/action_dispatch/routing/routes_proxy.rb +5 -4
  119. data/lib/action_dispatch/routing/url_for.rb +19 -5
  120. data/lib/action_dispatch/routing.rb +9 -6
  121. data/lib/action_dispatch/testing/assertions/dom.rb +2 -26
  122. data/lib/action_dispatch/testing/assertions/response.rb +9 -15
  123. data/lib/action_dispatch/testing/assertions/routing.rb +22 -22
  124. data/lib/action_dispatch/testing/assertions/selector.rb +2 -429
  125. data/lib/action_dispatch/testing/assertions/tag.rb +2 -134
  126. data/lib/action_dispatch/testing/assertions.rb +11 -7
  127. data/lib/action_dispatch/testing/integration.rb +31 -29
  128. data/lib/action_dispatch/testing/test_request.rb +1 -1
  129. data/lib/action_dispatch/testing/test_response.rb +1 -5
  130. data/lib/action_dispatch.rb +5 -8
  131. data/lib/action_pack/gem_version.rb +15 -0
  132. data/lib/action_pack/version.rb +4 -7
  133. data/lib/action_pack.rb +1 -1
  134. metadata +77 -159
  135. data/lib/abstract_controller/layouts.rb +0 -423
  136. data/lib/abstract_controller/view_paths.rb +0 -96
  137. data/lib/action_controller/deprecated/integration_test.rb +0 -5
  138. data/lib/action_controller/deprecated.rb +0 -7
  139. data/lib/action_controller/metal/responder.rb +0 -287
  140. data/lib/action_controller/record_identifier.rb +0 -31
  141. data/lib/action_controller/vendor/html-scanner.rb +0 -5
  142. data/lib/action_dispatch/middleware/templates/rescues/_trace.erb +0 -24
  143. data/lib/action_dispatch/middleware/templates/rescues/missing_template.erb +0 -7
  144. data/lib/action_dispatch/middleware/templates/rescues/template_error.erb +0 -43
  145. data/lib/action_view/base.rb +0 -201
  146. data/lib/action_view/buffers.rb +0 -49
  147. data/lib/action_view/context.rb +0 -36
  148. data/lib/action_view/dependency_tracker.rb +0 -93
  149. data/lib/action_view/digestor.rb +0 -113
  150. data/lib/action_view/flows.rb +0 -76
  151. data/lib/action_view/helpers/active_model_helper.rb +0 -49
  152. data/lib/action_view/helpers/asset_tag_helper.rb +0 -320
  153. data/lib/action_view/helpers/asset_url_helper.rb +0 -355
  154. data/lib/action_view/helpers/atom_feed_helper.rb +0 -203
  155. data/lib/action_view/helpers/cache_helper.rb +0 -196
  156. data/lib/action_view/helpers/capture_helper.rb +0 -216
  157. data/lib/action_view/helpers/controller_helper.rb +0 -25
  158. data/lib/action_view/helpers/csrf_helper.rb +0 -30
  159. data/lib/action_view/helpers/date_helper.rb +0 -1083
  160. data/lib/action_view/helpers/debug_helper.rb +0 -39
  161. data/lib/action_view/helpers/form_helper.rb +0 -1880
  162. data/lib/action_view/helpers/form_options_helper.rb +0 -838
  163. data/lib/action_view/helpers/form_tag_helper.rb +0 -785
  164. data/lib/action_view/helpers/javascript_helper.rb +0 -117
  165. data/lib/action_view/helpers/number_helper.rb +0 -441
  166. data/lib/action_view/helpers/output_safety_helper.rb +0 -38
  167. data/lib/action_view/helpers/record_tag_helper.rb +0 -106
  168. data/lib/action_view/helpers/rendering_helper.rb +0 -90
  169. data/lib/action_view/helpers/sanitize_helper.rb +0 -256
  170. data/lib/action_view/helpers/tag_helper.rb +0 -173
  171. data/lib/action_view/helpers/tags/base.rb +0 -148
  172. data/lib/action_view/helpers/tags/check_box.rb +0 -64
  173. data/lib/action_view/helpers/tags/checkable.rb +0 -16
  174. data/lib/action_view/helpers/tags/collection_check_boxes.rb +0 -44
  175. data/lib/action_view/helpers/tags/collection_helpers.rb +0 -84
  176. data/lib/action_view/helpers/tags/collection_radio_buttons.rb +0 -36
  177. data/lib/action_view/helpers/tags/collection_select.rb +0 -28
  178. data/lib/action_view/helpers/tags/color_field.rb +0 -25
  179. data/lib/action_view/helpers/tags/date_field.rb +0 -13
  180. data/lib/action_view/helpers/tags/date_select.rb +0 -72
  181. data/lib/action_view/helpers/tags/datetime_field.rb +0 -22
  182. data/lib/action_view/helpers/tags/datetime_local_field.rb +0 -19
  183. data/lib/action_view/helpers/tags/datetime_select.rb +0 -8
  184. data/lib/action_view/helpers/tags/email_field.rb +0 -8
  185. data/lib/action_view/helpers/tags/file_field.rb +0 -8
  186. data/lib/action_view/helpers/tags/grouped_collection_select.rb +0 -29
  187. data/lib/action_view/helpers/tags/hidden_field.rb +0 -8
  188. data/lib/action_view/helpers/tags/label.rb +0 -66
  189. data/lib/action_view/helpers/tags/month_field.rb +0 -13
  190. data/lib/action_view/helpers/tags/number_field.rb +0 -18
  191. data/lib/action_view/helpers/tags/password_field.rb +0 -12
  192. data/lib/action_view/helpers/tags/radio_button.rb +0 -31
  193. data/lib/action_view/helpers/tags/range_field.rb +0 -8
  194. data/lib/action_view/helpers/tags/search_field.rb +0 -24
  195. data/lib/action_view/helpers/tags/select.rb +0 -40
  196. data/lib/action_view/helpers/tags/tel_field.rb +0 -8
  197. data/lib/action_view/helpers/tags/text_area.rb +0 -18
  198. data/lib/action_view/helpers/tags/text_field.rb +0 -29
  199. data/lib/action_view/helpers/tags/time_field.rb +0 -13
  200. data/lib/action_view/helpers/tags/time_select.rb +0 -8
  201. data/lib/action_view/helpers/tags/time_zone_select.rb +0 -20
  202. data/lib/action_view/helpers/tags/url_field.rb +0 -8
  203. data/lib/action_view/helpers/tags/week_field.rb +0 -13
  204. data/lib/action_view/helpers/tags.rb +0 -39
  205. data/lib/action_view/helpers/text_helper.rb +0 -443
  206. data/lib/action_view/helpers/translation_helper.rb +0 -107
  207. data/lib/action_view/helpers/url_helper.rb +0 -635
  208. data/lib/action_view/helpers.rb +0 -58
  209. data/lib/action_view/locale/en.yml +0 -56
  210. data/lib/action_view/log_subscriber.rb +0 -30
  211. data/lib/action_view/lookup_context.rb +0 -241
  212. data/lib/action_view/model_naming.rb +0 -12
  213. data/lib/action_view/path_set.rb +0 -77
  214. data/lib/action_view/railtie.rb +0 -43
  215. data/lib/action_view/record_identifier.rb +0 -84
  216. data/lib/action_view/renderer/abstract_renderer.rb +0 -47
  217. data/lib/action_view/renderer/partial_renderer.rb +0 -492
  218. data/lib/action_view/renderer/renderer.rb +0 -50
  219. data/lib/action_view/renderer/streaming_template_renderer.rb +0 -103
  220. data/lib/action_view/renderer/template_renderer.rb +0 -96
  221. data/lib/action_view/routing_url_for.rb +0 -107
  222. data/lib/action_view/tasks/dependencies.rake +0 -17
  223. data/lib/action_view/template/error.rb +0 -138
  224. data/lib/action_view/template/handlers/builder.rb +0 -26
  225. data/lib/action_view/template/handlers/erb.rb +0 -146
  226. data/lib/action_view/template/handlers/raw.rb +0 -11
  227. data/lib/action_view/template/handlers.rb +0 -53
  228. data/lib/action_view/template/resolver.rb +0 -326
  229. data/lib/action_view/template/text.rb +0 -34
  230. data/lib/action_view/template/types.rb +0 -57
  231. data/lib/action_view/template.rb +0 -339
  232. data/lib/action_view/test_case.rb +0 -270
  233. data/lib/action_view/testing/resolvers.rb +0 -50
  234. data/lib/action_view/vendor/html-scanner/html/document.rb +0 -68
  235. data/lib/action_view/vendor/html-scanner/html/node.rb +0 -532
  236. data/lib/action_view/vendor/html-scanner/html/sanitizer.rb +0 -188
  237. data/lib/action_view/vendor/html-scanner/html/selector.rb +0 -830
  238. data/lib/action_view/vendor/html-scanner/html/tokenizer.rb +0 -107
  239. data/lib/action_view/vendor/html-scanner/html/version.rb +0 -11
  240. data/lib/action_view/vendor/html-scanner.rb +0 -20
  241. data/lib/action_view.rb +0 -93
@@ -1,4 +1,7 @@
1
- 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'
2
5
  require 'monitor'
3
6
 
4
7
  module ActionDispatch # :nodoc:
@@ -31,10 +34,17 @@ module ActionDispatch # :nodoc:
31
34
  # end
32
35
  # end
33
36
  class Response
34
- attr_accessor :request, :header
37
+ # The request that the response is responding to.
38
+ attr_accessor :request
39
+
40
+ # The HTTP status code.
35
41
  attr_reader :status
42
+
36
43
  attr_writer :sending_file
37
44
 
45
+ # Get and set headers for this response.
46
+ attr_accessor :header
47
+
38
48
  alias_method :headers=, :header=
39
49
  alias_method :headers, :header
40
50
 
@@ -49,9 +59,12 @@ module ActionDispatch # :nodoc:
49
59
  # If a character set has been defined for this response (see charset=) then
50
60
  # the character set information will also be included in the content type
51
61
  # information.
52
- attr_accessor :charset
53
62
  attr_reader :content_type
54
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
67
+
55
68
  CONTENT_TYPE = "Content-Type".freeze
56
69
  SET_COOKIE = "Set-Cookie".freeze
57
70
  LOCATION = "Location".freeze
@@ -80,7 +93,13 @@ module ActionDispatch # :nodoc:
80
93
  end
81
94
 
82
95
  def each(&block)
83
- @buf.each(&block)
96
+ @response.sending!
97
+ x = @buf.each(&block)
98
+ @response.sent!
99
+ x
100
+ end
101
+
102
+ def abort
84
103
  end
85
104
 
86
105
  def close
@@ -93,12 +112,14 @@ module ActionDispatch # :nodoc:
93
112
  end
94
113
  end
95
114
 
115
+ # The underlying body, as a streamable object.
96
116
  attr_reader :stream
97
117
 
98
- def initialize(status = 200, header = {}, body = [])
118
+ def initialize(status = 200, header = {}, body = [], options = {})
99
119
  super()
100
120
 
101
- header = merge_default_headers(header, self.class.default_headers)
121
+ default_headers = options.fetch(:default_headers, self.class.default_headers)
122
+ header = merge_default_headers(header, default_headers)
102
123
 
103
124
  self.body, self.header, self.status = body, header, status
104
125
 
@@ -106,6 +127,8 @@ module ActionDispatch # :nodoc:
106
127
  @blank = false
107
128
  @cv = new_cond
108
129
  @committed = false
130
+ @sending = false
131
+ @sent = false
109
132
  @content_type = nil
110
133
  @charset = nil
111
134
 
@@ -126,22 +149,43 @@ module ActionDispatch # :nodoc:
126
149
  end
127
150
  end
128
151
 
152
+ def await_sent
153
+ synchronize { @cv.wait_until { @sent } }
154
+ end
155
+
129
156
  def commit!
130
157
  synchronize do
158
+ before_committed
131
159
  @committed = true
132
160
  @cv.broadcast
133
161
  end
134
162
  end
135
163
 
136
- def committed?
137
- @committed
164
+ def sending!
165
+ synchronize do
166
+ before_sending
167
+ @sending = true
168
+ @cv.broadcast
169
+ end
138
170
  end
139
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
+
140
183
  # Sets the HTTP status code.
141
184
  def status=(status)
142
185
  @status = Rack::Utils.status_code(status)
143
186
  end
144
187
 
188
+ # Sets the HTTP content type.
145
189
  def content_type=(content_type)
146
190
  @content_type = content_type.to_s
147
191
  end
@@ -169,18 +213,6 @@ module ActionDispatch # :nodoc:
169
213
  end
170
214
  alias_method :status_message, :message
171
215
 
172
- def respond_to?(method)
173
- if method.to_s == 'to_path'
174
- stream.respond_to?(:to_path)
175
- else
176
- super
177
- end
178
- end
179
-
180
- def to_path
181
- stream.to_path
182
- end
183
-
184
216
  # Returns the content of the response as a string. This contains the contents
185
217
  # of any calls to <tt>render</tt>.
186
218
  def body
@@ -218,11 +250,13 @@ module ActionDispatch # :nodoc:
218
250
  ::Rack::Utils.delete_cookie_header!(header, key, value)
219
251
  end
220
252
 
253
+ # The location header we'll be responding with.
221
254
  def location
222
255
  headers[LOCATION]
223
256
  end
224
257
  alias_method :redirect_url, :location
225
258
 
259
+ # Sets the location header we'll be responding with.
226
260
  def location=(url)
227
261
  headers[LOCATION] = url
228
262
  end
@@ -231,11 +265,39 @@ module ActionDispatch # :nodoc:
231
265
  stream.close if stream.respond_to?(:close)
232
266
  end
233
267
 
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
276
+ end
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
234
283
  def to_a
235
284
  rack_response @status, @header.to_hash
236
285
  end
237
286
  alias prepare! to_a
238
- 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
239
301
 
240
302
  # Returns the response cookies, converted to a Hash of (name => value) pairs
241
303
  #
@@ -256,10 +318,14 @@ module ActionDispatch # :nodoc:
256
318
 
257
319
  private
258
320
 
259
- def merge_default_headers(original, default)
260
- return original unless default.respond_to?(:merge)
321
+ def before_committed
322
+ end
323
+
324
+ def before_sending
325
+ end
261
326
 
262
- default.merge(original)
327
+ def merge_default_headers(original, default)
328
+ default.respond_to?(:merge) ? default.merge(original) : original
263
329
  end
264
330
 
265
331
  def build_buffer(response, body)
@@ -286,6 +352,42 @@ module ActionDispatch # :nodoc:
286
352
  !@sending_file && @charset != false
287
353
  end
288
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
+
289
391
  def rack_response(status, header)
290
392
  assign_default_content_type_and_charset!(header)
291
393
  handle_conditional_get!
@@ -296,7 +398,7 @@ module ActionDispatch # :nodoc:
296
398
  header.delete CONTENT_TYPE
297
399
  [status, header, []]
298
400
  else
299
- [status, header, self]
401
+ [status, header, RackBody.new(self)]
300
402
  end
301
403
  end
302
404
  end
@@ -18,6 +18,7 @@ module ActionDispatch
18
18
  # A +Tempfile+ object with the actual uploaded file. Note that some of
19
19
  # its interface is available directly.
20
20
  attr_accessor :tempfile
21
+ alias :to_io :tempfile
21
22
 
22
23
  # A string with the headers of the multipart request.
23
24
  attr_accessor :headers
@@ -26,7 +27,14 @@ module ActionDispatch
26
27
  @tempfile = hash[:tempfile]
27
28
  raise(ArgumentError, ':tempfile is required') unless @tempfile
28
29
 
29
- @original_filename = encode_filename(hash[:filename])
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
30
38
  @content_type = hash[:type]
31
39
  @headers = hash[:head]
32
40
  end
@@ -65,26 +73,6 @@ module ActionDispatch
65
73
  def eof?
66
74
  @tempfile.eof?
67
75
  end
68
-
69
- private
70
-
71
- def encode_filename(filename)
72
- # Encode the filename in the utf8 encoding, unless it is nil
73
- filename.force_encoding(Encoding::UTF_8).encode! if filename
74
- end
75
- end
76
-
77
- module Upload # :nodoc:
78
- # Replace file upload hash with UploadedFile objects
79
- # when normalize and encode parameters.
80
- def normalize_encode_params(value)
81
- if Hash === value && value.has_key?(:tempfile)
82
- UploadedFile.new(value)
83
- else
84
- super
85
- end
86
- end
87
- private :normalize_encode_params
88
76
  end
89
77
  end
90
78
  end
@@ -5,99 +5,123 @@ module ActionDispatch
5
5
  module Http
6
6
  module URL
7
7
  IP_HOST_REGEXP = /\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/
8
- HOST_REGEXP = /(^.*:\/\/)?([^:]+)(?::(\d+$))?/
8
+ HOST_REGEXP = /(^[^:]+:\/\/)?(\[[^\]]+\]|[^:]+)(?::(\d+$))?/
9
9
  PROTOCOL_REGEXP = /^([^:]+)(:)?(\/\/)?$/
10
10
 
11
11
  mattr_accessor :tld_length
12
12
  self.tld_length = 1
13
13
 
14
14
  class << self
15
- def extract_domain(host, tld_length = @@tld_length)
16
- host.split('.').last(1 + tld_length).join('.') if named_host?(host)
15
+ def extract_domain(host, tld_length)
16
+ extract_domain_from(host, tld_length) if named_host?(host)
17
17
  end
18
18
 
19
- def extract_subdomains(host, tld_length = @@tld_length)
19
+ def extract_subdomains(host, tld_length)
20
20
  if named_host?(host)
21
- parts = host.split('.')
22
- parts[0..-(tld_length + 2)]
21
+ extract_subdomains_from(host, tld_length)
23
22
  else
24
23
  []
25
24
  end
26
25
  end
27
26
 
28
- def extract_subdomain(host, tld_length = @@tld_length)
27
+ def extract_subdomain(host, tld_length)
29
28
  extract_subdomains(host, tld_length).join('.')
30
29
  end
31
30
 
32
- def url_for(options = {})
33
- options = options.dup
34
- path = options.delete(:script_name).to_s.chomp("/")
35
- path << options.delete(:path).to_s
36
-
37
- params = options[:params].is_a?(Hash) ? options[:params] : options.slice(:params)
38
- params.reject! { |_,v| v.to_param.nil? }
39
-
40
- result = build_host_url(options)
41
- if options[:trailing_slash]
42
- if path.include?('?')
43
- result << path.sub(/\?/, '/\&')
44
- else
45
- result << path.sub(/[^\/]\z|\A\z/, '\&/')
46
- end
31
+ def url_for(options)
32
+ if options[:only_path]
33
+ path_for options
47
34
  else
48
- result << path
35
+ full_url_for options
49
36
  end
50
- result << "?#{params.to_query}" unless params.empty?
51
- result << "##{Journey::Router::Utils.escape_fragment(options[:anchor].to_param.to_s)}" if options[:anchor]
52
- result
53
37
  end
54
38
 
55
- private
39
+ def full_url_for(options)
40
+ host = options[:host]
41
+ protocol = options[:protocol]
42
+ port = options[:port]
56
43
 
57
- def build_host_url(options)
58
- if options[:host].blank? && options[:only_path].blank?
44
+ unless host
59
45
  raise ArgumentError, 'Missing host to link to! Please provide the :host parameter, set default_url_options[:host], or set :only_path to true'
60
46
  end
61
47
 
62
- result = ""
48
+ build_host_url(host, port, protocol, options, path_for(options))
49
+ end
50
+
51
+ def path_for(options)
52
+ path = options[:script_name].to_s.chomp("/")
53
+ path << options[:path] if options.key?(:path)
54
+
55
+ add_trailing_slash(path) if options[:trailing_slash]
56
+ add_params(path, options[:params]) if options.key?(:params)
57
+ add_anchor(path, options[:anchor]) if options.key?(:anchor)
63
58
 
64
- unless options[:only_path]
65
- if match = options[:host].match(HOST_REGEXP)
66
- options[:protocol] ||= match[1] unless options[:protocol] == false
67
- options[:host] = match[2]
68
- options[:port] = match[3] unless options.key?(:port)
69
- end
59
+ path
60
+ end
70
61
 
71
- options[:protocol] = normalize_protocol(options)
72
- options[:host] = normalize_host(options)
73
- options[:port] = normalize_port(options)
62
+ private
74
63
 
75
- result << options[:protocol]
76
- result << rewrite_authentication(options)
77
- result << options[:host]
78
- result << ":#{options[:port]}" if options[:port]
64
+ def add_params(path, params)
65
+ params = { params: params } unless params.is_a?(Hash)
66
+ params.reject! { |_,v| v.to_param.nil? }
67
+ path << "?#{params.to_query}" unless params.empty?
68
+ end
69
+
70
+ def add_anchor(path, anchor)
71
+ if anchor
72
+ path << "##{Journey::Router::Utils.escape_fragment(anchor.to_param)}"
79
73
  end
80
- result
81
74
  end
82
75
 
83
- def named_host?(host)
84
- host && IP_HOST_REGEXP !~ host
76
+ def extract_domain_from(host, tld_length)
77
+ host.split('.').last(1 + tld_length).join('.')
85
78
  end
86
79
 
87
- def same_host?(options)
88
- (options[:subdomain] == true || !options.key?(:subdomain)) && options[:domain].nil?
80
+ def extract_subdomains_from(host, tld_length)
81
+ parts = host.split('.')
82
+ parts[0..-(tld_length + 2)]
89
83
  end
90
84
 
91
- def rewrite_authentication(options)
85
+ def add_trailing_slash(path)
86
+ # includes querysting
87
+ if path.include?('?')
88
+ path.sub!(/\?/, '/\&')
89
+ # does not have a .format
90
+ elsif !path.include?(".")
91
+ path.sub!(/[^\/]\z|\A\z/, '\&/')
92
+ end
93
+ end
94
+
95
+ def build_host_url(host, port, protocol, options, path)
96
+ if match = host.match(HOST_REGEXP)
97
+ protocol ||= match[1] unless protocol == false
98
+ host = match[2]
99
+ port = match[3] unless options.key? :port
100
+ end
101
+
102
+ protocol = normalize_protocol protocol
103
+ host = normalize_host(host, options)
104
+
105
+ result = protocol.dup
106
+
92
107
  if options[:user] && options[:password]
93
- "#{Rack::Utils.escape(options[:user])}:#{Rack::Utils.escape(options[:password])}@"
94
- else
95
- ""
108
+ result << "#{Rack::Utils.escape(options[:user])}:#{Rack::Utils.escape(options[:password])}@"
96
109
  end
110
+
111
+ result << host
112
+ normalize_port(port, protocol) { |normalized_port|
113
+ result << ":#{normalized_port}"
114
+ }
115
+
116
+ result.concat path
117
+ end
118
+
119
+ def named_host?(host)
120
+ IP_HOST_REGEXP !~ host
97
121
  end
98
122
 
99
- def normalize_protocol(options)
100
- case options[:protocol]
123
+ def normalize_protocol(protocol)
124
+ case protocol
101
125
  when nil
102
126
  "http://"
103
127
  when false, "//"
@@ -105,36 +129,39 @@ module ActionDispatch
105
129
  when PROTOCOL_REGEXP
106
130
  "#{$1}://"
107
131
  else
108
- raise ArgumentError, "Invalid :protocol option: #{options[:protocol].inspect}"
132
+ raise ArgumentError, "Invalid :protocol option: #{protocol.inspect}"
109
133
  end
110
134
  end
111
135
 
112
- def normalize_host(options)
113
- return options[:host] if !named_host?(options[:host]) || same_host?(options)
136
+ def normalize_host(_host, options)
137
+ return _host unless named_host?(_host)
114
138
 
115
139
  tld_length = options[:tld_length] || @@tld_length
140
+ subdomain = options.fetch :subdomain, true
141
+ domain = options[:domain]
116
142
 
117
143
  host = ""
118
- if options[:subdomain] == true || !options.key?(:subdomain)
119
- host << extract_subdomain(options[:host], tld_length).to_param
120
- elsif options[:subdomain].present?
121
- host << options[:subdomain].to_param
144
+ if subdomain == true
145
+ return _host if domain.nil?
146
+
147
+ host << extract_subdomains_from(_host, tld_length).join('.')
148
+ elsif subdomain
149
+ host << subdomain.to_param
122
150
  end
123
151
  host << "." unless host.empty?
124
- host << (options[:domain] || extract_domain(options[:host], tld_length))
152
+ host << (domain || extract_domain_from(_host, tld_length))
125
153
  host
126
154
  end
127
155
 
128
- def normalize_port(options)
129
- return nil if options[:port].nil? || options[:port] == false
156
+ def normalize_port(port, protocol)
157
+ return unless port
130
158
 
131
- case options[:protocol]
132
- when "//"
133
- nil
159
+ case protocol
160
+ when "//" then yield port
134
161
  when "https://"
135
- options[:port].to_i == 443 ? nil : options[:port]
162
+ yield port unless port.to_i == 443
136
163
  else
137
- options[:port].to_i == 80 ? nil : options[:port]
164
+ yield port unless port.to_i == 80
138
165
  end
139
166
  end
140
167
  end
@@ -157,7 +184,7 @@ module ActionDispatch
157
184
 
158
185
  # Returns the \host for this request, such as "example.com".
159
186
  def raw_host_with_port
160
- if forwarded = env["HTTP_X_FORWARDED_HOST"]
187
+ if forwarded = env["HTTP_X_FORWARDED_HOST"].presence
161
188
  forwarded.split(/,\s?/).last
162
189
  else
163
190
  env['HTTP_HOST'] || "#{env['SERVER_NAME'] || env['SERVER_ADDR']}:#{env['SERVER_PORT']}"
@@ -1,9 +1,10 @@
1
1
  require 'action_controller/metal/exceptions'
2
+ require 'active_support/deprecation'
2
3
 
3
4
  module ActionDispatch
4
5
  module Journey
5
6
  # The Formatter class is used for formatting URLs. For example, parameters
6
- # passed to +url_for+ in rails will eventually call Formatter#generate.
7
+ # passed to +url_for+ in Rails will eventually call Formatter#generate.
7
8
  class Formatter # :nodoc:
8
9
  attr_reader :routes
9
10
 
@@ -12,12 +13,12 @@ module ActionDispatch
12
13
  @cache = nil
13
14
  end
14
15
 
15
- def generate(type, name, options, recall = {}, parameterize = nil)
16
- constraints = recall.merge(options)
16
+ def generate(name, options, path_parameters, parameterize = nil)
17
+ constraints = path_parameters.merge(options)
17
18
  missing_keys = []
18
19
 
19
20
  match_route(name, constraints) do |route|
20
- parameterized_parts = extract_parameterized_parts(route, options, recall, parameterize)
21
+ parameterized_parts = extract_parameterized_parts(route, options, path_parameters, parameterize)
21
22
 
22
23
  # Skip this route unless a name has been provided or it is a
23
24
  # standard Rails route since we can't determine whether an options
@@ -30,11 +31,17 @@ module ActionDispatch
30
31
  parameterized_parts.key?(key) || route.defaults.key?(key)
31
32
  end
32
33
 
34
+ defaults = route.defaults
35
+ required_parts = route.required_parts
36
+ parameterized_parts.delete_if do |key, value|
37
+ value.to_s == defaults[key].to_s && !required_parts.include?(key)
38
+ end
39
+
33
40
  return [route.format(parameterized_parts), params]
34
41
  end
35
42
 
36
- message = "No route matches #{constraints.inspect}"
37
- message << " missing required keys: #{missing_keys.inspect}" if name
43
+ message = "No route matches #{Hash[constraints.sort_by{|k,v| k.to_s}].inspect}"
44
+ message << " missing required keys: #{missing_keys.sort.inspect}" unless missing_keys.empty?
38
45
 
39
46
  raise ActionController::UrlGenerationError, message
40
47
  end
@@ -74,14 +81,28 @@ module ActionDispatch
74
81
  if named_routes.key?(name)
75
82
  yield named_routes[name]
76
83
  else
77
- routes = non_recursive(cache, options.to_a)
84
+ # Make sure we don't show the deprecation warning more than once
85
+ warned = false
86
+
87
+ routes = non_recursive(cache, options)
78
88
 
79
89
  hash = routes.group_by { |_, r| r.score(options) }
80
90
 
81
91
  hash.keys.sort.reverse_each do |score|
82
- next if score < 0
92
+ break if score < 0
83
93
 
84
94
  hash[score].sort_by { |i, _| i }.each do |_, route|
95
+ if name && !warned
96
+ ActiveSupport::Deprecation.warn <<-MSG.squish
97
+ You are trying to generate the URL for a named route called
98
+ #{name.inspect} but no such route was found. In the future,
99
+ this will result in an `ActionController::UrlGenerationError`
100
+ exception.
101
+ MSG
102
+
103
+ warned = true
104
+ end
105
+
85
106
  yield route
86
107
  end
87
108
  end
@@ -90,14 +111,14 @@ module ActionDispatch
90
111
 
91
112
  def non_recursive(cache, options)
92
113
  routes = []
93
- stack = [cache]
114
+ queue = [cache]
94
115
 
95
- while stack.any?
96
- c = stack.shift
116
+ while queue.any?
117
+ c = queue.shift
97
118
  routes.concat(c[:___routes]) if c.key?(:___routes)
98
119
 
99
120
  options.each do |pair|
100
- stack << c[pair] if c.key?(pair)
121
+ queue << c[pair] if c.key?(pair)
101
122
  end
102
123
  end
103
124
 
@@ -121,14 +142,9 @@ module ActionDispatch
121
142
  def possibles(cache, options, depth = 0)
122
143
  cache.fetch(:___routes) { [] } + options.find_all { |pair|
123
144
  cache.key?(pair)
124
- }.map { |pair|
145
+ }.flat_map { |pair|
125
146
  possibles(cache[pair], options, depth + 1)
126
- }.flatten(1)
127
- end
128
-
129
- # Returns +true+ if no missing keys are present, otherwise +false+.
130
- def verify_required_parts!(route, parts)
131
- missing_keys(route, parts).empty?
147
+ }
132
148
  end
133
149
 
134
150
  def build_cache