actionpack 7.0.8.1 → 7.2.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +94 -500
- data/MIT-LICENSE +1 -1
- data/README.rdoc +2 -2
- data/lib/abstract_controller/asset_paths.rb +2 -0
- data/lib/abstract_controller/base.rb +119 -106
- data/lib/abstract_controller/caching/fragments.rb +51 -52
- data/lib/abstract_controller/caching.rb +2 -0
- data/lib/abstract_controller/callbacks.rb +94 -67
- data/lib/abstract_controller/collector.rb +6 -6
- data/lib/abstract_controller/deprecator.rb +9 -0
- data/lib/abstract_controller/error.rb +2 -0
- data/lib/abstract_controller/helpers.rb +121 -91
- data/lib/abstract_controller/logger.rb +2 -0
- data/lib/abstract_controller/railties/routes_helpers.rb +3 -16
- data/lib/abstract_controller/rendering.rb +14 -13
- data/lib/abstract_controller/translation.rb +12 -30
- data/lib/abstract_controller/url_for.rb +9 -5
- data/lib/abstract_controller.rb +8 -0
- data/lib/action_controller/api/api_rendering.rb +2 -0
- data/lib/action_controller/api.rb +78 -73
- data/lib/action_controller/base.rb +199 -141
- data/lib/action_controller/caching.rb +16 -11
- data/lib/action_controller/deprecator.rb +9 -0
- data/lib/action_controller/form_builder.rb +21 -16
- data/lib/action_controller/log_subscriber.rb +19 -5
- data/lib/action_controller/metal/allow_browser.rb +123 -0
- data/lib/action_controller/metal/basic_implicit_render.rb +2 -0
- data/lib/action_controller/metal/conditional_get.rb +187 -174
- data/lib/action_controller/metal/content_security_policy.rb +26 -25
- data/lib/action_controller/metal/cookies.rb +4 -2
- data/lib/action_controller/metal/data_streaming.rb +65 -54
- data/lib/action_controller/metal/default_headers.rb +6 -2
- data/lib/action_controller/metal/etag_with_flash.rb +4 -0
- data/lib/action_controller/metal/etag_with_template_digest.rb +18 -14
- data/lib/action_controller/metal/exceptions.rb +19 -9
- data/lib/action_controller/metal/flash.rb +12 -10
- data/lib/action_controller/metal/head.rb +20 -16
- data/lib/action_controller/metal/helpers.rb +64 -67
- data/lib/action_controller/metal/http_authentication.rb +214 -200
- data/lib/action_controller/metal/implicit_render.rb +21 -17
- data/lib/action_controller/metal/instrumentation.rb +22 -12
- data/lib/action_controller/metal/live.rb +125 -92
- data/lib/action_controller/metal/logging.rb +6 -4
- data/lib/action_controller/metal/mime_responds.rb +151 -142
- data/lib/action_controller/metal/parameter_encoding.rb +34 -32
- data/lib/action_controller/metal/params_wrapper.rb +58 -58
- data/lib/action_controller/metal/permissions_policy.rb +14 -13
- data/lib/action_controller/metal/rate_limiting.rb +62 -0
- data/lib/action_controller/metal/redirecting.rb +110 -84
- data/lib/action_controller/metal/renderers.rb +50 -49
- data/lib/action_controller/metal/rendering.rb +103 -82
- data/lib/action_controller/metal/request_forgery_protection.rb +279 -161
- data/lib/action_controller/metal/rescue.rb +12 -8
- data/lib/action_controller/metal/streaming.rb +174 -132
- data/lib/action_controller/metal/strong_parameters.rb +598 -473
- data/lib/action_controller/metal/testing.rb +2 -0
- data/lib/action_controller/metal/url_for.rb +23 -14
- data/lib/action_controller/metal.rb +145 -61
- data/lib/action_controller/railtie.rb +25 -9
- data/lib/action_controller/railties/helpers.rb +2 -0
- data/lib/action_controller/renderer.rb +105 -66
- data/lib/action_controller/template_assertions.rb +4 -2
- data/lib/action_controller/test_case.rb +157 -128
- data/lib/action_controller.rb +17 -3
- data/lib/action_dispatch/constants.rb +34 -0
- data/lib/action_dispatch/deprecator.rb +9 -0
- data/lib/action_dispatch/http/cache.rb +28 -29
- data/lib/action_dispatch/http/content_disposition.rb +2 -0
- data/lib/action_dispatch/http/content_security_policy.rb +69 -49
- data/lib/action_dispatch/http/filter_parameters.rb +27 -12
- data/lib/action_dispatch/http/filter_redirect.rb +22 -1
- data/lib/action_dispatch/http/headers.rb +23 -21
- data/lib/action_dispatch/http/mime_negotiation.rb +37 -48
- data/lib/action_dispatch/http/mime_type.rb +60 -30
- data/lib/action_dispatch/http/mime_types.rb +5 -1
- data/lib/action_dispatch/http/parameters.rb +12 -10
- data/lib/action_dispatch/http/permissions_policy.rb +32 -34
- data/lib/action_dispatch/http/rack_cache.rb +4 -0
- data/lib/action_dispatch/http/request.rb +132 -79
- data/lib/action_dispatch/http/response.rb +136 -103
- data/lib/action_dispatch/http/upload.rb +19 -15
- data/lib/action_dispatch/http/url.rb +75 -73
- data/lib/action_dispatch/journey/formatter.rb +19 -6
- data/lib/action_dispatch/journey/gtg/builder.rb +4 -3
- data/lib/action_dispatch/journey/gtg/simulator.rb +2 -0
- data/lib/action_dispatch/journey/gtg/transition_table.rb +10 -8
- data/lib/action_dispatch/journey/nfa/dot.rb +2 -0
- data/lib/action_dispatch/journey/nodes/node.rb +6 -5
- data/lib/action_dispatch/journey/parser.rb +4 -3
- data/lib/action_dispatch/journey/parser_extras.rb +2 -0
- data/lib/action_dispatch/journey/path/pattern.rb +18 -15
- data/lib/action_dispatch/journey/route.rb +12 -9
- data/lib/action_dispatch/journey/router/utils.rb +16 -15
- data/lib/action_dispatch/journey/router.rb +13 -10
- data/lib/action_dispatch/journey/routes.rb +6 -4
- data/lib/action_dispatch/journey/scanner.rb +4 -2
- data/lib/action_dispatch/journey/visitors.rb +2 -0
- data/lib/action_dispatch/journey.rb +2 -0
- data/lib/action_dispatch/log_subscriber.rb +25 -0
- data/lib/action_dispatch/middleware/actionable_exceptions.rb +7 -6
- data/lib/action_dispatch/middleware/assume_ssl.rb +27 -0
- data/lib/action_dispatch/middleware/callbacks.rb +4 -0
- data/lib/action_dispatch/middleware/cookies.rb +192 -194
- data/lib/action_dispatch/middleware/debug_exceptions.rb +36 -27
- data/lib/action_dispatch/middleware/debug_locks.rb +18 -13
- data/lib/action_dispatch/middleware/debug_view.rb +9 -2
- data/lib/action_dispatch/middleware/exception_wrapper.rb +181 -27
- data/lib/action_dispatch/middleware/executor.rb +9 -1
- data/lib/action_dispatch/middleware/flash.rb +65 -46
- data/lib/action_dispatch/middleware/host_authorization.rb +22 -17
- data/lib/action_dispatch/middleware/public_exceptions.rb +12 -8
- data/lib/action_dispatch/middleware/reloader.rb +9 -5
- data/lib/action_dispatch/middleware/remote_ip.rb +88 -83
- data/lib/action_dispatch/middleware/request_id.rb +15 -8
- data/lib/action_dispatch/middleware/server_timing.rb +8 -6
- data/lib/action_dispatch/middleware/session/abstract_store.rb +7 -0
- data/lib/action_dispatch/middleware/session/cache_store.rb +14 -7
- data/lib/action_dispatch/middleware/session/cookie_store.rb +32 -25
- data/lib/action_dispatch/middleware/session/mem_cache_store.rb +9 -3
- data/lib/action_dispatch/middleware/show_exceptions.rb +42 -28
- data/lib/action_dispatch/middleware/ssl.rb +60 -45
- data/lib/action_dispatch/middleware/stack.rb +15 -9
- data/lib/action_dispatch/middleware/static.rb +40 -34
- data/lib/action_dispatch/middleware/templates/rescues/_actions.html.erb +2 -2
- data/lib/action_dispatch/middleware/templates/rescues/_message_and_suggestions.html.erb +4 -4
- data/lib/action_dispatch/middleware/templates/rescues/_source.html.erb +8 -1
- data/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb +7 -7
- data/lib/action_dispatch/middleware/templates/rescues/diagnostics.text.erb +2 -2
- data/lib/action_dispatch/middleware/templates/rescues/layout.erb +17 -0
- data/lib/action_dispatch/middleware/templates/rescues/missing_exact_template.html.erb +16 -12
- data/lib/action_dispatch/middleware/templates/rescues/missing_template.html.erb +1 -1
- data/lib/action_dispatch/middleware/templates/rescues/routing_error.html.erb +3 -3
- data/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb +4 -4
- data/lib/action_dispatch/middleware/templates/rescues/unknown_action.html.erb +1 -1
- data/lib/action_dispatch/middleware/templates/rescues/unknown_action.text.erb +1 -1
- data/lib/action_dispatch/middleware/templates/routes/_route.html.erb +3 -0
- data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +47 -38
- data/lib/action_dispatch/railtie.rb +12 -4
- data/lib/action_dispatch/request/session.rb +39 -27
- data/lib/action_dispatch/request/utils.rb +10 -3
- data/lib/action_dispatch/routing/endpoint.rb +2 -0
- data/lib/action_dispatch/routing/inspector.rb +59 -9
- data/lib/action_dispatch/routing/mapper.rb +686 -639
- data/lib/action_dispatch/routing/polymorphic_routes.rb +70 -61
- data/lib/action_dispatch/routing/redirection.rb +52 -38
- data/lib/action_dispatch/routing/route_set.rb +106 -62
- data/lib/action_dispatch/routing/routes_proxy.rb +16 -19
- data/lib/action_dispatch/routing/url_for.rb +131 -122
- data/lib/action_dispatch/routing.rb +152 -150
- data/lib/action_dispatch/system_test_case.rb +91 -81
- data/lib/action_dispatch/system_testing/browser.rb +27 -19
- data/lib/action_dispatch/system_testing/driver.rb +16 -22
- data/lib/action_dispatch/system_testing/server.rb +2 -0
- data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +53 -31
- data/lib/action_dispatch/system_testing/test_helpers/setup_and_teardown.rb +2 -0
- data/lib/action_dispatch/testing/assertion_response.rb +9 -7
- data/lib/action_dispatch/testing/assertions/response.rb +36 -26
- data/lib/action_dispatch/testing/assertions/routing.rb +203 -95
- data/lib/action_dispatch/testing/assertions.rb +5 -1
- data/lib/action_dispatch/testing/integration.rb +240 -229
- data/lib/action_dispatch/testing/request_encoder.rb +6 -1
- data/lib/action_dispatch/testing/test_helpers/page_dump_helper.rb +35 -0
- data/lib/action_dispatch/testing/test_process.rb +14 -9
- data/lib/action_dispatch/testing/test_request.rb +4 -2
- data/lib/action_dispatch/testing/test_response.rb +34 -19
- data/lib/action_dispatch.rb +52 -21
- data/lib/action_pack/gem_version.rb +5 -3
- data/lib/action_pack/version.rb +3 -1
- data/lib/action_pack.rb +18 -17
- metadata +91 -32
@@ -1,74 +1,78 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
# :markup: markdown
|
4
|
+
|
3
5
|
require "active_support/core_ext/module/attribute_accessors"
|
4
6
|
require "action_dispatch/http/filter_redirect"
|
5
7
|
require "action_dispatch/http/cache"
|
6
8
|
require "monitor"
|
7
9
|
|
8
10
|
module ActionDispatch # :nodoc:
|
11
|
+
# # Action Dispatch Response
|
12
|
+
#
|
9
13
|
# Represents an HTTP response generated by a controller action. Use it to
|
10
14
|
# retrieve the current state of the response, or customize the response. It can
|
11
|
-
# either represent a real HTTP response (i.e. one that is meant to be sent
|
12
|
-
#
|
13
|
-
#
|
15
|
+
# either represent a real HTTP response (i.e. one that is meant to be sent back
|
16
|
+
# to the web browser) or a TestResponse (i.e. one that is generated from
|
17
|
+
# integration tests).
|
14
18
|
#
|
15
|
-
#
|
16
|
-
#
|
17
|
-
# methods
|
18
|
-
#
|
19
|
-
# ActionControllerBase#headers instead of Response#headers.
|
19
|
+
# The Response object for the current request is exposed on controllers as
|
20
|
+
# ActionController::Metal#response. ActionController::Metal also provides a few
|
21
|
+
# additional methods that delegate to attributes of the Response such as
|
22
|
+
# ActionController::Metal#headers.
|
20
23
|
#
|
21
|
-
#
|
22
|
-
#
|
23
|
-
#
|
24
|
-
#
|
25
|
-
# objects of type TestResponse (which are of course also of type \Response).
|
24
|
+
# Integration tests will likely also want to inspect responses in more detail.
|
25
|
+
# Methods such as Integration::RequestHelpers#get and
|
26
|
+
# Integration::RequestHelpers#post return instances of TestResponse (which
|
27
|
+
# inherits from Response) for this purpose.
|
26
28
|
#
|
27
29
|
# For example, the following demo integration test prints the body of the
|
28
30
|
# controller response to the console:
|
29
31
|
#
|
30
|
-
#
|
31
|
-
#
|
32
|
-
#
|
33
|
-
#
|
34
|
-
#
|
35
|
-
#
|
32
|
+
# class DemoControllerTest < ActionDispatch::IntegrationTest
|
33
|
+
# def test_print_root_path_to_console
|
34
|
+
# get('/')
|
35
|
+
# puts response.body
|
36
|
+
# end
|
37
|
+
# end
|
36
38
|
class Response
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
raise ActionDispatch::IllegalStateError, "header already sent"
|
46
|
-
end
|
47
|
-
|
48
|
-
super
|
49
|
-
end
|
50
|
-
|
51
|
-
def merge(other)
|
52
|
-
self.class.new @response, __getobj__.merge(other)
|
53
|
-
end
|
54
|
-
|
55
|
-
def to_hash
|
56
|
-
__getobj__.dup
|
57
|
-
end
|
39
|
+
begin
|
40
|
+
# For `Rack::Headers` (Rack 3+):
|
41
|
+
require "rack/headers"
|
42
|
+
Headers = ::Rack::Headers
|
43
|
+
rescue LoadError
|
44
|
+
# For `Rack::Utils::HeaderHash`:
|
45
|
+
require "rack/utils"
|
46
|
+
Headers = ::Rack::Utils::HeaderHash
|
58
47
|
end
|
59
48
|
|
49
|
+
# To be deprecated:
|
50
|
+
Header = Headers
|
51
|
+
|
60
52
|
# The request that the response is responding to.
|
61
53
|
attr_accessor :request
|
62
54
|
|
63
55
|
# The HTTP status code.
|
64
56
|
attr_reader :status
|
65
57
|
|
66
|
-
#
|
67
|
-
|
58
|
+
# The headers for the response.
|
59
|
+
#
|
60
|
+
# header["Content-Type"] # => "text/plain"
|
61
|
+
# header["Content-Type"] = "application/json"
|
62
|
+
# header["Content-Type"] # => "application/json"
|
63
|
+
#
|
64
|
+
# Also aliased as `headers`.
|
65
|
+
#
|
66
|
+
# headers["Content-Type"] # => "text/plain"
|
67
|
+
# headers["Content-Type"] = "application/json"
|
68
|
+
# headers["Content-Type"] # => "application/json"
|
69
|
+
#
|
70
|
+
# Also aliased as `header` for compatibility.
|
71
|
+
attr_reader :headers
|
68
72
|
|
69
|
-
alias_method :
|
73
|
+
alias_method :header, :headers
|
70
74
|
|
71
|
-
delegate :[], :[]=, to: :@
|
75
|
+
delegate :[], :[]=, to: :@headers
|
72
76
|
|
73
77
|
def each(&block)
|
74
78
|
sending!
|
@@ -79,7 +83,6 @@ module ActionDispatch # :nodoc:
|
|
79
83
|
|
80
84
|
CONTENT_TYPE = "Content-Type"
|
81
85
|
SET_COOKIE = "Set-Cookie"
|
82
|
-
LOCATION = "Location"
|
83
86
|
NO_CONTENT_CODES = [100, 101, 102, 103, 204, 205, 304]
|
84
87
|
|
85
88
|
cattr_accessor :default_charset, default: "utf-8"
|
@@ -102,6 +105,12 @@ module ActionDispatch # :nodoc:
|
|
102
105
|
@str_body = nil
|
103
106
|
end
|
104
107
|
|
108
|
+
def to_ary
|
109
|
+
@buf.respond_to?(:to_ary) ?
|
110
|
+
@buf.to_ary :
|
111
|
+
@buf.each
|
112
|
+
end
|
113
|
+
|
105
114
|
def body
|
106
115
|
@str_body ||= begin
|
107
116
|
buf = +""
|
@@ -117,6 +126,7 @@ module ActionDispatch # :nodoc:
|
|
117
126
|
@response.commit!
|
118
127
|
@buf.push string
|
119
128
|
end
|
129
|
+
alias_method :<<, :write
|
120
130
|
|
121
131
|
def each(&block)
|
122
132
|
if @str_body
|
@@ -146,9 +156,9 @@ module ActionDispatch # :nodoc:
|
|
146
156
|
end
|
147
157
|
end
|
148
158
|
|
149
|
-
def self.create(status = 200,
|
150
|
-
|
151
|
-
new status,
|
159
|
+
def self.create(status = 200, headers = {}, body = [], default_headers: self.default_headers)
|
160
|
+
headers = merge_default_headers(headers, default_headers)
|
161
|
+
new status, headers, body
|
152
162
|
end
|
153
163
|
|
154
164
|
def self.merge_default_headers(original, default)
|
@@ -158,10 +168,14 @@ module ActionDispatch # :nodoc:
|
|
158
168
|
# The underlying body, as a streamable object.
|
159
169
|
attr_reader :stream
|
160
170
|
|
161
|
-
def initialize(status = 200,
|
171
|
+
def initialize(status = 200, headers = nil, body = [])
|
162
172
|
super()
|
163
173
|
|
164
|
-
@
|
174
|
+
@headers = Headers.new
|
175
|
+
|
176
|
+
headers&.each do |key, value|
|
177
|
+
@headers[key] = value
|
178
|
+
end
|
165
179
|
|
166
180
|
self.body, self.status = body, status
|
167
181
|
|
@@ -175,10 +189,10 @@ module ActionDispatch # :nodoc:
|
|
175
189
|
yield self if block_given?
|
176
190
|
end
|
177
191
|
|
178
|
-
def has_header?(key); headers.key? key; end
|
179
|
-
def get_header(key); headers[key]; end
|
180
|
-
def set_header(key, v); headers[key] = v; end
|
181
|
-
def delete_header(key); headers.delete key; end
|
192
|
+
def has_header?(key); @headers.key? key; end
|
193
|
+
def get_header(key); @headers[key]; end
|
194
|
+
def set_header(key, v); @headers[key] = v; end
|
195
|
+
def delete_header(key); @headers.delete key; end
|
182
196
|
|
183
197
|
def await_commit
|
184
198
|
synchronize do
|
@@ -217,18 +231,30 @@ module ActionDispatch # :nodoc:
|
|
217
231
|
def committed?; synchronize { @committed }; end
|
218
232
|
def sent?; synchronize { @sent }; end
|
219
233
|
|
234
|
+
##
|
235
|
+
# :method: location
|
236
|
+
#
|
237
|
+
# Location of the response.
|
238
|
+
|
239
|
+
##
|
240
|
+
# :method: location=
|
241
|
+
#
|
242
|
+
# :call-seq: location=(location)
|
243
|
+
#
|
244
|
+
# Sets the location of the response
|
245
|
+
|
220
246
|
# Sets the HTTP status code.
|
221
247
|
def status=(status)
|
222
248
|
@status = Rack::Utils.status_code(status)
|
223
249
|
end
|
224
250
|
|
225
|
-
# Sets the HTTP response's content MIME type. For example, in the controller
|
226
|
-
#
|
251
|
+
# Sets the HTTP response's content MIME type. For example, in the controller you
|
252
|
+
# could write this:
|
227
253
|
#
|
228
|
-
#
|
254
|
+
# response.content_type = "text/plain"
|
229
255
|
#
|
230
|
-
# If a character set has been defined for this response (see charset=) then
|
231
|
-
#
|
256
|
+
# If a character set has been defined for this response (see #charset=) then the
|
257
|
+
# character set information will also be included in the content type
|
232
258
|
# information.
|
233
259
|
def content_type=(content_type)
|
234
260
|
return unless content_type
|
@@ -255,11 +281,11 @@ module ActionDispatch # :nodoc:
|
|
255
281
|
end
|
256
282
|
end
|
257
283
|
|
258
|
-
# Sets the HTTP character set. In case of
|
259
|
-
#
|
284
|
+
# Sets the HTTP character set. In case of `nil` parameter it sets the charset to
|
285
|
+
# `default_charset`.
|
260
286
|
#
|
261
|
-
#
|
262
|
-
#
|
287
|
+
# response.charset = 'utf-16' # => 'utf-16'
|
288
|
+
# response.charset = nil # => 'utf-8'
|
263
289
|
def charset=(charset)
|
264
290
|
content_type = parsed_content_type_header.mime_type
|
265
291
|
if false == charset
|
@@ -269,8 +295,8 @@ module ActionDispatch # :nodoc:
|
|
269
295
|
end
|
270
296
|
end
|
271
297
|
|
272
|
-
# The charset of the response. HTML wants to know the encoding of the
|
273
|
-
#
|
298
|
+
# The charset of the response. HTML wants to know the encoding of the content
|
299
|
+
# you're giving them, so we need to send that along.
|
274
300
|
def charset
|
275
301
|
header_info = parsed_content_type_header
|
276
302
|
header_info.charset || self.class.default_charset
|
@@ -281,26 +307,26 @@ module ActionDispatch # :nodoc:
|
|
281
307
|
@status
|
282
308
|
end
|
283
309
|
|
284
|
-
# Returns a string to ensure compatibility with
|
310
|
+
# Returns a string to ensure compatibility with `Net::HTTPResponse`.
|
285
311
|
def code
|
286
312
|
@status.to_s
|
287
313
|
end
|
288
314
|
|
289
315
|
# Returns the corresponding message for the current HTTP status code:
|
290
316
|
#
|
291
|
-
#
|
292
|
-
#
|
317
|
+
# response.status = 200
|
318
|
+
# response.message # => "OK"
|
293
319
|
#
|
294
|
-
#
|
295
|
-
#
|
320
|
+
# response.status = 404
|
321
|
+
# response.message # => "Not Found"
|
296
322
|
#
|
297
323
|
def message
|
298
324
|
Rack::Utils::HTTP_STATUS_CODES[@status]
|
299
325
|
end
|
300
326
|
alias_method :status_message, :message
|
301
327
|
|
302
|
-
# Returns the content of the response as a string. This contains the contents
|
303
|
-
#
|
328
|
+
# Returns the content of the response as a string. This contains the contents of
|
329
|
+
# any calls to `render`.
|
304
330
|
def body
|
305
331
|
@stream.body
|
306
332
|
end
|
@@ -320,9 +346,9 @@ module ActionDispatch # :nodoc:
|
|
320
346
|
end
|
321
347
|
end
|
322
348
|
|
323
|
-
# Avoid having to pass an open file handle as the response body.
|
324
|
-
#
|
325
|
-
#
|
349
|
+
# Avoid having to pass an open file handle as the response body. Rack::Sendfile
|
350
|
+
# will usually intercept the response and uses the path directly, so there is no
|
351
|
+
# reason to open the file.
|
326
352
|
class FileBody # :nodoc:
|
327
353
|
attr_reader :to_path
|
328
354
|
|
@@ -344,7 +370,7 @@ module ActionDispatch # :nodoc:
|
|
344
370
|
end
|
345
371
|
end
|
346
372
|
|
347
|
-
# Send the file stored at
|
373
|
+
# Send the file stored at `path` as the response body.
|
348
374
|
def send_file(path)
|
349
375
|
commit!
|
350
376
|
@stream = FileBody.new(path)
|
@@ -371,26 +397,25 @@ module ActionDispatch # :nodoc:
|
|
371
397
|
if stream.respond_to?(:abort)
|
372
398
|
stream.abort
|
373
399
|
elsif stream.respond_to?(:close)
|
374
|
-
# `stream.close` should really be reserved for a close from the
|
375
|
-
#
|
376
|
-
# compatibility.
|
400
|
+
# `stream.close` should really be reserved for a close from the other direction,
|
401
|
+
# but we must fall back to it for compatibility.
|
377
402
|
stream.close
|
378
403
|
end
|
379
404
|
end
|
380
405
|
|
381
|
-
# Turns the Response into a Rack-compatible array of the status, headers,
|
382
|
-
#
|
406
|
+
# Turns the Response into a Rack-compatible array of the status, headers, and
|
407
|
+
# body. Allows explicit splatting:
|
383
408
|
#
|
384
|
-
#
|
409
|
+
# status, headers, body = *response
|
385
410
|
def to_a
|
386
411
|
commit!
|
387
|
-
rack_response @status, @
|
412
|
+
rack_response @status, @headers.to_hash
|
388
413
|
end
|
389
414
|
alias prepare! to_a
|
390
415
|
|
391
416
|
# Returns the response cookies, converted to a Hash of (name => value) pairs
|
392
417
|
#
|
393
|
-
#
|
418
|
+
# assert_equal 'AuthorOfNewPage', r.cookies['author']
|
394
419
|
def cookies
|
395
420
|
cookies = {}
|
396
421
|
if header = get_header(SET_COOKIE)
|
@@ -444,15 +469,13 @@ module ActionDispatch # :nodoc:
|
|
444
469
|
end
|
445
470
|
|
446
471
|
def before_sending
|
447
|
-
# Normally we've already committed by now, but it's possible
|
448
|
-
#
|
449
|
-
#
|
450
|
-
#
|
451
|
-
# our last chance.
|
472
|
+
# Normally we've already committed by now, but it's possible (e.g., if the
|
473
|
+
# controller action tries to read back its own response) to get here before
|
474
|
+
# that. In that case, we must force an "early" commit: we're about to freeze the
|
475
|
+
# headers, so this is our last chance.
|
452
476
|
commit! unless committed?
|
453
477
|
|
454
|
-
|
455
|
-
request.commit_cookie_jar! unless committed?
|
478
|
+
@request.commit_cookie_jar! unless committed?
|
456
479
|
end
|
457
480
|
|
458
481
|
def build_buffer(response, body)
|
@@ -476,13 +499,9 @@ module ActionDispatch # :nodoc:
|
|
476
499
|
@response = response
|
477
500
|
end
|
478
501
|
|
479
|
-
def each(*args, &block)
|
480
|
-
@response.each(*args, &block)
|
481
|
-
end
|
482
|
-
|
483
502
|
def close
|
484
|
-
# Rack "close" maps to Response#abort, and
|
485
|
-
#
|
503
|
+
# Rack "close" maps to Response#abort, and **not** Response#close (which is used
|
504
|
+
# when the controller's finished writing)
|
486
505
|
@response.abort
|
487
506
|
end
|
488
507
|
|
@@ -490,14 +509,28 @@ module ActionDispatch # :nodoc:
|
|
490
509
|
@response.body
|
491
510
|
end
|
492
511
|
|
512
|
+
BODY_METHODS = { to_ary: true, each: true, call: true, to_path: true }
|
513
|
+
|
493
514
|
def respond_to?(method, include_private = false)
|
494
|
-
if method
|
515
|
+
if BODY_METHODS.key?(method)
|
495
516
|
@response.stream.respond_to?(method)
|
496
517
|
else
|
497
518
|
super
|
498
519
|
end
|
499
520
|
end
|
500
521
|
|
522
|
+
def to_ary
|
523
|
+
@response.stream.to_ary
|
524
|
+
end
|
525
|
+
|
526
|
+
def each(*args, &block)
|
527
|
+
@response.each(*args, &block)
|
528
|
+
end
|
529
|
+
|
530
|
+
def call(*arguments, &block)
|
531
|
+
@response.stream.call(*arguments, &block)
|
532
|
+
end
|
533
|
+
|
501
534
|
def to_path
|
502
535
|
@response.stream.to_path
|
503
536
|
end
|
@@ -505,16 +538,16 @@ module ActionDispatch # :nodoc:
|
|
505
538
|
|
506
539
|
def handle_no_content!
|
507
540
|
if NO_CONTENT_CODES.include?(@status)
|
508
|
-
@
|
509
|
-
@
|
541
|
+
@headers.delete CONTENT_TYPE
|
542
|
+
@headers.delete "Content-Length"
|
510
543
|
end
|
511
544
|
end
|
512
545
|
|
513
|
-
def rack_response(status,
|
546
|
+
def rack_response(status, headers)
|
514
547
|
if NO_CONTENT_CODES.include?(status)
|
515
|
-
[status,
|
548
|
+
[status, headers, []]
|
516
549
|
else
|
517
|
-
[status,
|
550
|
+
[status, headers, RackBody.new(self)]
|
518
551
|
end
|
519
552
|
end
|
520
553
|
end
|
@@ -1,15 +1,19 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
# :markup: markdown
|
4
|
+
|
3
5
|
module ActionDispatch
|
4
6
|
module Http
|
7
|
+
# # Action Dispatch HTTP UploadedFile
|
8
|
+
#
|
5
9
|
# Models uploaded files.
|
6
10
|
#
|
7
|
-
# The actual file is accessible via the
|
8
|
-
#
|
11
|
+
# The actual file is accessible via the `tempfile` accessor, though some of its
|
12
|
+
# interface is available directly for convenience.
|
9
13
|
#
|
10
|
-
# Uploaded files are temporary files whose lifespan is one request. When
|
11
|
-
#
|
12
|
-
#
|
14
|
+
# Uploaded files are temporary files whose lifespan is one request. When the
|
15
|
+
# object is finalized Ruby unlinks the file, so there is no need to clean them
|
16
|
+
# with a separate maintenance task.
|
13
17
|
class UploadedFile
|
14
18
|
# The basename of the file in the client.
|
15
19
|
attr_accessor :original_filename
|
@@ -17,8 +21,8 @@ module ActionDispatch
|
|
17
21
|
# A string with the MIME type of the file.
|
18
22
|
attr_accessor :content_type
|
19
23
|
|
20
|
-
# A
|
21
|
-
#
|
24
|
+
# A `Tempfile` object with the actual uploaded file. Note that some of its
|
25
|
+
# interface is available directly.
|
22
26
|
attr_accessor :tempfile
|
23
27
|
|
24
28
|
# A string with the headers of the multipart request.
|
@@ -55,42 +59,42 @@ module ActionDispatch
|
|
55
59
|
end
|
56
60
|
end
|
57
61
|
|
58
|
-
# Shortcut for
|
62
|
+
# Shortcut for `tempfile.read`.
|
59
63
|
def read(length = nil, buffer = nil)
|
60
64
|
@tempfile.read(length, buffer)
|
61
65
|
end
|
62
66
|
|
63
|
-
# Shortcut for
|
67
|
+
# Shortcut for `tempfile.open`.
|
64
68
|
def open
|
65
69
|
@tempfile.open
|
66
70
|
end
|
67
71
|
|
68
|
-
# Shortcut for
|
72
|
+
# Shortcut for `tempfile.close`.
|
69
73
|
def close(unlink_now = false)
|
70
74
|
@tempfile.close(unlink_now)
|
71
75
|
end
|
72
76
|
|
73
|
-
# Shortcut for
|
77
|
+
# Shortcut for `tempfile.path`.
|
74
78
|
def path
|
75
79
|
@tempfile.path
|
76
80
|
end
|
77
81
|
|
78
|
-
# Shortcut for
|
82
|
+
# Shortcut for `tempfile.to_path`.
|
79
83
|
def to_path
|
80
84
|
@tempfile.to_path
|
81
85
|
end
|
82
86
|
|
83
|
-
# Shortcut for
|
87
|
+
# Shortcut for `tempfile.rewind`.
|
84
88
|
def rewind
|
85
89
|
@tempfile.rewind
|
86
90
|
end
|
87
91
|
|
88
|
-
# Shortcut for
|
92
|
+
# Shortcut for `tempfile.size`.
|
89
93
|
def size
|
90
94
|
@tempfile.size
|
91
95
|
end
|
92
96
|
|
93
|
-
# Shortcut for
|
97
|
+
# Shortcut for `tempfile.eof?`.
|
94
98
|
def eof?
|
95
99
|
@tempfile.eof?
|
96
100
|
end
|