actionpack 4.2.11.1 → 5.2.6
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +328 -458
- data/MIT-LICENSE +1 -1
- data/README.rdoc +6 -7
- data/lib/abstract_controller/asset_paths.rb +2 -0
- data/lib/abstract_controller/base.rb +45 -49
- data/lib/{action_controller → abstract_controller}/caching/fragments.rb +78 -15
- data/lib/abstract_controller/caching.rb +66 -0
- data/lib/abstract_controller/callbacks.rb +47 -31
- data/lib/abstract_controller/collector.rb +8 -11
- data/lib/abstract_controller/error.rb +6 -0
- data/lib/abstract_controller/helpers.rb +25 -25
- data/lib/abstract_controller/logger.rb +2 -0
- data/lib/abstract_controller/railties/routes_helpers.rb +4 -2
- data/lib/abstract_controller/rendering.rb +42 -41
- data/lib/abstract_controller/translation.rb +10 -7
- data/lib/abstract_controller/url_for.rb +2 -0
- data/lib/abstract_controller.rb +12 -5
- data/lib/action_controller/api/api_rendering.rb +16 -0
- data/lib/action_controller/api.rb +149 -0
- data/lib/action_controller/base.rb +27 -19
- data/lib/action_controller/caching.rb +14 -57
- data/lib/action_controller/form_builder.rb +50 -0
- data/lib/action_controller/log_subscriber.rb +10 -15
- data/lib/action_controller/metal/basic_implicit_render.rb +13 -0
- data/lib/action_controller/metal/conditional_get.rb +118 -44
- data/lib/action_controller/metal/content_security_policy.rb +52 -0
- data/lib/action_controller/metal/cookies.rb +3 -3
- data/lib/action_controller/metal/data_streaming.rb +27 -46
- data/lib/action_controller/metal/etag_with_flash.rb +18 -0
- data/lib/action_controller/metal/etag_with_template_digest.rb +20 -13
- data/lib/action_controller/metal/exceptions.rb +8 -14
- data/lib/action_controller/metal/flash.rb +4 -3
- data/lib/action_controller/metal/force_ssl.rb +23 -21
- data/lib/action_controller/metal/head.rb +21 -19
- data/lib/action_controller/metal/helpers.rb +24 -14
- data/lib/action_controller/metal/http_authentication.rb +65 -58
- data/lib/action_controller/metal/implicit_render.rb +62 -8
- data/lib/action_controller/metal/instrumentation.rb +19 -21
- data/lib/action_controller/metal/live.rb +90 -106
- data/lib/action_controller/metal/mime_responds.rb +33 -46
- data/lib/action_controller/metal/parameter_encoding.rb +51 -0
- data/lib/action_controller/metal/params_wrapper.rb +61 -53
- data/lib/action_controller/metal/redirecting.rb +49 -28
- data/lib/action_controller/metal/renderers.rb +87 -44
- data/lib/action_controller/metal/rendering.rb +72 -50
- data/lib/action_controller/metal/request_forgery_protection.rb +284 -97
- data/lib/action_controller/metal/rescue.rb +9 -16
- data/lib/action_controller/metal/streaming.rb +12 -10
- data/lib/action_controller/metal/strong_parameters.rb +583 -164
- data/lib/action_controller/metal/testing.rb +2 -17
- data/lib/action_controller/metal/url_for.rb +19 -10
- data/lib/action_controller/metal.rb +98 -83
- data/lib/action_controller/railtie.rb +28 -10
- data/lib/action_controller/railties/helpers.rb +2 -0
- data/lib/action_controller/renderer.rb +117 -0
- data/lib/action_controller/template_assertions.rb +11 -0
- data/lib/action_controller/test_case.rb +282 -413
- data/lib/action_controller.rb +29 -21
- data/lib/action_dispatch/http/cache.rb +93 -47
- data/lib/action_dispatch/http/content_security_policy.rb +272 -0
- data/lib/action_dispatch/http/filter_parameters.rb +26 -20
- data/lib/action_dispatch/http/filter_redirect.rb +10 -11
- data/lib/action_dispatch/http/headers.rb +55 -22
- data/lib/action_dispatch/http/mime_negotiation.rb +56 -41
- data/lib/action_dispatch/http/mime_type.rb +134 -121
- data/lib/action_dispatch/http/mime_types.rb +20 -6
- data/lib/action_dispatch/http/parameter_filter.rb +25 -11
- data/lib/action_dispatch/http/parameters.rb +98 -39
- data/lib/action_dispatch/http/rack_cache.rb +2 -0
- data/lib/action_dispatch/http/request.rb +200 -118
- data/lib/action_dispatch/http/response.rb +225 -110
- data/lib/action_dispatch/http/upload.rb +12 -6
- data/lib/action_dispatch/http/url.rb +110 -28
- data/lib/action_dispatch/journey/formatter.rb +55 -32
- data/lib/action_dispatch/journey/gtg/builder.rb +7 -5
- data/lib/action_dispatch/journey/gtg/simulator.rb +3 -9
- data/lib/action_dispatch/journey/gtg/transition_table.rb +17 -16
- data/lib/action_dispatch/journey/nfa/builder.rb +5 -3
- data/lib/action_dispatch/journey/nfa/dot.rb +13 -13
- data/lib/action_dispatch/journey/nfa/simulator.rb +3 -1
- data/lib/action_dispatch/journey/nfa/transition_table.rb +5 -48
- data/lib/action_dispatch/journey/nodes/node.rb +18 -6
- data/lib/action_dispatch/journey/parser.rb +23 -22
- data/lib/action_dispatch/journey/parser.y +3 -2
- data/lib/action_dispatch/journey/parser_extras.rb +12 -4
- data/lib/action_dispatch/journey/path/pattern.rb +50 -44
- data/lib/action_dispatch/journey/route.rb +106 -28
- data/lib/action_dispatch/journey/router/utils.rb +20 -11
- data/lib/action_dispatch/journey/router.rb +35 -23
- data/lib/action_dispatch/journey/routes.rb +18 -16
- data/lib/action_dispatch/journey/scanner.rb +18 -15
- data/lib/action_dispatch/journey/visitors.rb +99 -52
- data/lib/action_dispatch/journey.rb +7 -5
- data/lib/action_dispatch/middleware/callbacks.rb +1 -2
- data/lib/action_dispatch/middleware/cookies.rb +304 -193
- data/lib/action_dispatch/middleware/debug_exceptions.rb +152 -57
- data/lib/action_dispatch/middleware/debug_locks.rb +124 -0
- data/lib/action_dispatch/middleware/exception_wrapper.rb +68 -69
- data/lib/action_dispatch/middleware/executor.rb +21 -0
- data/lib/action_dispatch/middleware/flash.rb +78 -54
- data/lib/action_dispatch/middleware/public_exceptions.rb +27 -25
- data/lib/action_dispatch/middleware/reloader.rb +5 -91
- data/lib/action_dispatch/middleware/remote_ip.rb +41 -31
- data/lib/action_dispatch/middleware/request_id.rb +17 -9
- data/lib/action_dispatch/middleware/session/abstract_store.rb +41 -25
- data/lib/action_dispatch/middleware/session/cache_store.rb +24 -14
- data/lib/action_dispatch/middleware/session/cookie_store.rb +72 -67
- data/lib/action_dispatch/middleware/session/mem_cache_store.rb +8 -2
- data/lib/action_dispatch/middleware/show_exceptions.rb +26 -22
- data/lib/action_dispatch/middleware/ssl.rb +114 -36
- data/lib/action_dispatch/middleware/stack.rb +31 -44
- data/lib/action_dispatch/middleware/static.rb +57 -50
- data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb +2 -14
- data/lib/action_dispatch/middleware/templates/rescues/{_source.erb → _source.html.erb} +0 -0
- data/lib/action_dispatch/middleware/templates/rescues/_source.text.erb +8 -0
- data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.html.erb +21 -0
- data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.text.erb +13 -0
- data/lib/action_dispatch/middleware/templates/rescues/layout.erb +1 -0
- data/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb +1 -1
- data/lib/action_dispatch/middleware/templates/rescues/template_error.text.erb +1 -1
- data/lib/action_dispatch/middleware/templates/routes/_route.html.erb +4 -4
- data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +64 -64
- data/lib/action_dispatch/railtie.rb +19 -11
- data/lib/action_dispatch/request/session.rb +106 -59
- data/lib/action_dispatch/request/utils.rb +67 -24
- data/lib/action_dispatch/routing/endpoint.rb +9 -2
- data/lib/action_dispatch/routing/inspector.rb +58 -67
- data/lib/action_dispatch/routing/mapper.rb +733 -447
- data/lib/action_dispatch/routing/polymorphic_routes.rb +166 -140
- data/lib/action_dispatch/routing/redirection.rb +36 -26
- data/lib/action_dispatch/routing/route_set.rb +321 -291
- data/lib/action_dispatch/routing/routes_proxy.rb +32 -5
- data/lib/action_dispatch/routing/url_for.rb +65 -25
- data/lib/action_dispatch/routing.rb +17 -18
- data/lib/action_dispatch/system_test_case.rb +147 -0
- data/lib/action_dispatch/system_testing/browser.rb +49 -0
- data/lib/action_dispatch/system_testing/driver.rb +59 -0
- data/lib/action_dispatch/system_testing/server.rb +31 -0
- data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +96 -0
- data/lib/action_dispatch/system_testing/test_helpers/setup_and_teardown.rb +31 -0
- data/lib/action_dispatch/system_testing/test_helpers/undef_methods.rb +26 -0
- data/lib/action_dispatch/testing/assertion_response.rb +47 -0
- data/lib/action_dispatch/testing/assertions/response.rb +45 -20
- data/lib/action_dispatch/testing/assertions/routing.rb +30 -26
- data/lib/action_dispatch/testing/assertions.rb +6 -4
- data/lib/action_dispatch/testing/integration.rb +348 -209
- data/lib/action_dispatch/testing/request_encoder.rb +55 -0
- data/lib/action_dispatch/testing/test_process.rb +28 -22
- data/lib/action_dispatch/testing/test_request.rb +27 -34
- data/lib/action_dispatch/testing/test_response.rb +35 -7
- data/lib/action_dispatch.rb +27 -19
- data/lib/action_pack/gem_version.rb +5 -3
- data/lib/action_pack/version.rb +3 -1
- data/lib/action_pack.rb +4 -2
- metadata +56 -38
- data/lib/action_controller/metal/hide_actions.rb +0 -40
- data/lib/action_controller/metal/rack_delegation.rb +0 -32
- data/lib/action_controller/middleware.rb +0 -39
- data/lib/action_controller/model_naming.rb +0 -12
- data/lib/action_dispatch/journey/backwards.rb +0 -5
- data/lib/action_dispatch/journey/router/strexp.rb +0 -27
- data/lib/action_dispatch/middleware/params_parser.rb +0 -60
- data/lib/action_dispatch/testing/assertions/dom.rb +0 -3
- data/lib/action_dispatch/testing/assertions/selector.rb +0 -3
- data/lib/action_dispatch/testing/assertions/tag.rb +0 -3
@@ -1,8 +1,9 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
require
|
4
|
-
require
|
5
|
-
require
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_support/core_ext/module/attribute_accessors"
|
4
|
+
require "action_dispatch/http/filter_redirect"
|
5
|
+
require "action_dispatch/http/cache"
|
6
|
+
require "monitor"
|
6
7
|
|
7
8
|
module ActionDispatch # :nodoc:
|
8
9
|
# Represents an HTTP response generated by a controller action. Use it to
|
@@ -34,46 +35,62 @@ module ActionDispatch # :nodoc:
|
|
34
35
|
# end
|
35
36
|
# end
|
36
37
|
class Response
|
38
|
+
class Header < DelegateClass(Hash) # :nodoc:
|
39
|
+
def initialize(response, header)
|
40
|
+
@response = response
|
41
|
+
super(header)
|
42
|
+
end
|
43
|
+
|
44
|
+
def []=(k, v)
|
45
|
+
if @response.sending? || @response.sent?
|
46
|
+
raise ActionDispatch::IllegalStateError, "header already sent"
|
47
|
+
end
|
48
|
+
|
49
|
+
super
|
50
|
+
end
|
51
|
+
|
52
|
+
def merge(other)
|
53
|
+
self.class.new @response, __getobj__.merge(other)
|
54
|
+
end
|
55
|
+
|
56
|
+
def to_hash
|
57
|
+
__getobj__.dup
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
37
61
|
# The request that the response is responding to.
|
38
62
|
attr_accessor :request
|
39
63
|
|
40
64
|
# The HTTP status code.
|
41
65
|
attr_reader :status
|
42
66
|
|
43
|
-
|
44
|
-
|
45
|
-
# Get and set headers for this response.
|
46
|
-
attr_accessor :header
|
67
|
+
# Get headers for this response.
|
68
|
+
attr_reader :header
|
47
69
|
|
48
|
-
alias_method :headers=, :header=
|
49
70
|
alias_method :headers, :header
|
50
71
|
|
51
|
-
delegate :[], :[]=, :
|
52
|
-
delegate :each, :to => :@stream
|
72
|
+
delegate :[], :[]=, to: :@header
|
53
73
|
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
# the character set information will also be included in the content type
|
61
|
-
# information.
|
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
|
74
|
+
def each(&block)
|
75
|
+
sending!
|
76
|
+
x = @stream.each(&block)
|
77
|
+
sent!
|
78
|
+
x
|
79
|
+
end
|
67
80
|
|
68
81
|
CONTENT_TYPE = "Content-Type".freeze
|
69
82
|
SET_COOKIE = "Set-Cookie".freeze
|
70
83
|
LOCATION = "Location".freeze
|
71
|
-
NO_CONTENT_CODES = [204, 304]
|
84
|
+
NO_CONTENT_CODES = [100, 101, 102, 204, 205, 304]
|
72
85
|
|
73
|
-
cattr_accessor
|
74
|
-
cattr_accessor
|
86
|
+
cattr_accessor :default_charset, default: "utf-8"
|
87
|
+
cattr_accessor :default_headers
|
75
88
|
|
76
89
|
include Rack::Response::Helpers
|
90
|
+
# Aliasing these off because AD::Http::Cache::Response defines them.
|
91
|
+
alias :_cache_control :cache_control
|
92
|
+
alias :_cache_control= :cache_control=
|
93
|
+
|
77
94
|
include ActionDispatch::Http::FilterRedirect
|
78
95
|
include ActionDispatch::Http::Cache::Response
|
79
96
|
include MonitorMixin
|
@@ -83,20 +100,33 @@ module ActionDispatch # :nodoc:
|
|
83
100
|
@response = response
|
84
101
|
@buf = buf
|
85
102
|
@closed = false
|
103
|
+
@str_body = nil
|
104
|
+
end
|
105
|
+
|
106
|
+
def body
|
107
|
+
@str_body ||= begin
|
108
|
+
buf = "".dup
|
109
|
+
each { |chunk| buf << chunk }
|
110
|
+
buf
|
111
|
+
end
|
86
112
|
end
|
87
113
|
|
88
114
|
def write(string)
|
89
115
|
raise IOError, "closed stream" if closed?
|
90
116
|
|
117
|
+
@str_body = nil
|
91
118
|
@response.commit!
|
92
119
|
@buf.push string
|
93
120
|
end
|
94
121
|
|
95
122
|
def each(&block)
|
96
|
-
@
|
97
|
-
|
98
|
-
|
99
|
-
|
123
|
+
if @str_body
|
124
|
+
return enum_for(:each) unless block_given?
|
125
|
+
|
126
|
+
yield @str_body
|
127
|
+
else
|
128
|
+
each_chunk(&block)
|
129
|
+
end
|
100
130
|
end
|
101
131
|
|
102
132
|
def abort
|
@@ -110,39 +140,48 @@ module ActionDispatch # :nodoc:
|
|
110
140
|
def closed?
|
111
141
|
@closed
|
112
142
|
end
|
143
|
+
|
144
|
+
private
|
145
|
+
|
146
|
+
def each_chunk(&block)
|
147
|
+
@buf.each(&block)
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
def self.create(status = 200, header = {}, body = [], default_headers: self.default_headers)
|
152
|
+
header = merge_default_headers(header, default_headers)
|
153
|
+
new status, header, body
|
154
|
+
end
|
155
|
+
|
156
|
+
def self.merge_default_headers(original, default)
|
157
|
+
default.respond_to?(:merge) ? default.merge(original) : original
|
113
158
|
end
|
114
159
|
|
115
160
|
# The underlying body, as a streamable object.
|
116
161
|
attr_reader :stream
|
117
162
|
|
118
|
-
def initialize(status = 200, header = {}, body = []
|
163
|
+
def initialize(status = 200, header = {}, body = [])
|
119
164
|
super()
|
120
165
|
|
121
|
-
|
122
|
-
header = merge_default_headers(header, default_headers)
|
166
|
+
@header = Header.new(self, header)
|
123
167
|
|
124
|
-
self.body, self.
|
168
|
+
self.body, self.status = body, status
|
125
169
|
|
126
|
-
@sending_file = false
|
127
|
-
@blank = false
|
128
170
|
@cv = new_cond
|
129
171
|
@committed = false
|
130
172
|
@sending = false
|
131
173
|
@sent = false
|
132
|
-
@content_type = nil
|
133
|
-
@charset = nil
|
134
|
-
|
135
|
-
if content_type = self[CONTENT_TYPE]
|
136
|
-
type, charset = content_type.split(/;\s*charset=/)
|
137
|
-
@content_type = Mime::Type.lookup(type)
|
138
|
-
@charset = charset || self.class.default_charset
|
139
|
-
end
|
140
174
|
|
141
175
|
prepare_cache_control!
|
142
176
|
|
143
177
|
yield self if block_given?
|
144
178
|
end
|
145
179
|
|
180
|
+
def has_header?(key); headers.key? key; end
|
181
|
+
def get_header(key); headers[key]; end
|
182
|
+
def set_header(key, v); headers[key] = v; end
|
183
|
+
def delete_header(key); headers.delete key; end
|
184
|
+
|
146
185
|
def await_commit
|
147
186
|
synchronize do
|
148
187
|
@cv.wait_until { @committed }
|
@@ -187,7 +226,52 @@ module ActionDispatch # :nodoc:
|
|
187
226
|
|
188
227
|
# Sets the HTTP content type.
|
189
228
|
def content_type=(content_type)
|
190
|
-
|
229
|
+
return unless content_type
|
230
|
+
new_header_info = parse_content_type(content_type.to_s)
|
231
|
+
prev_header_info = parsed_content_type_header
|
232
|
+
charset = new_header_info.charset || prev_header_info.charset
|
233
|
+
charset ||= self.class.default_charset unless prev_header_info.mime_type
|
234
|
+
set_content_type new_header_info.mime_type, charset
|
235
|
+
end
|
236
|
+
|
237
|
+
# Sets the HTTP response's content MIME type. For example, in the controller
|
238
|
+
# you could write this:
|
239
|
+
#
|
240
|
+
# response.content_type = "text/plain"
|
241
|
+
#
|
242
|
+
# If a character set has been defined for this response (see charset=) then
|
243
|
+
# the character set information will also be included in the content type
|
244
|
+
# information.
|
245
|
+
|
246
|
+
def content_type
|
247
|
+
parsed_content_type_header.mime_type
|
248
|
+
end
|
249
|
+
|
250
|
+
def sending_file=(v)
|
251
|
+
if true == v
|
252
|
+
self.charset = false
|
253
|
+
end
|
254
|
+
end
|
255
|
+
|
256
|
+
# Sets the HTTP character set. In case of +nil+ parameter
|
257
|
+
# it sets the charset to +default_charset+.
|
258
|
+
#
|
259
|
+
# response.charset = 'utf-16' # => 'utf-16'
|
260
|
+
# response.charset = nil # => 'utf-8'
|
261
|
+
def charset=(charset)
|
262
|
+
content_type = parsed_content_type_header.mime_type
|
263
|
+
if false == charset
|
264
|
+
set_content_type content_type, nil
|
265
|
+
else
|
266
|
+
set_content_type content_type, charset || self.class.default_charset
|
267
|
+
end
|
268
|
+
end
|
269
|
+
|
270
|
+
# The charset of the response. HTML wants to know the encoding of the
|
271
|
+
# content you're giving them, so we need to send that along.
|
272
|
+
def charset
|
273
|
+
header_info = parsed_content_type_header
|
274
|
+
header_info.charset || self.class.default_charset
|
191
275
|
end
|
192
276
|
|
193
277
|
# The response code of the request.
|
@@ -216,17 +300,15 @@ module ActionDispatch # :nodoc:
|
|
216
300
|
# Returns the content of the response as a string. This contains the contents
|
217
301
|
# of any calls to <tt>render</tt>.
|
218
302
|
def body
|
219
|
-
|
220
|
-
each { |part| strings << part.to_s }
|
221
|
-
strings.join
|
303
|
+
@stream.body
|
222
304
|
end
|
223
305
|
|
224
|
-
|
306
|
+
def write(string)
|
307
|
+
@stream.write string
|
308
|
+
end
|
225
309
|
|
226
310
|
# Allows you to manually set or override the response body.
|
227
311
|
def body=(body)
|
228
|
-
@blank = true if body == EMPTY
|
229
|
-
|
230
312
|
if body.respond_to?(:to_path)
|
231
313
|
@stream = body
|
232
314
|
else
|
@@ -236,31 +318,49 @@ module ActionDispatch # :nodoc:
|
|
236
318
|
end
|
237
319
|
end
|
238
320
|
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
321
|
+
# Avoid having to pass an open file handle as the response body.
|
322
|
+
# Rack::Sendfile will usually intercept the response and uses
|
323
|
+
# the path directly, so there is no reason to open the file.
|
324
|
+
class FileBody #:nodoc:
|
325
|
+
attr_reader :to_path
|
244
326
|
|
245
|
-
|
246
|
-
|
327
|
+
def initialize(path)
|
328
|
+
@to_path = path
|
329
|
+
end
|
330
|
+
|
331
|
+
def body
|
332
|
+
File.binread(to_path)
|
333
|
+
end
|
334
|
+
|
335
|
+
# Stream the file's contents if Rack::Sendfile isn't present.
|
336
|
+
def each
|
337
|
+
File.open(to_path, "rb") do |file|
|
338
|
+
while chunk = file.read(16384)
|
339
|
+
yield chunk
|
340
|
+
end
|
341
|
+
end
|
342
|
+
end
|
247
343
|
end
|
248
344
|
|
249
|
-
|
250
|
-
|
345
|
+
# Send the file stored at +path+ as the response body.
|
346
|
+
def send_file(path)
|
347
|
+
commit!
|
348
|
+
@stream = FileBody.new(path)
|
251
349
|
end
|
252
350
|
|
253
|
-
|
254
|
-
|
255
|
-
headers[LOCATION]
|
351
|
+
def reset_body!
|
352
|
+
@stream = build_buffer(self, [])
|
256
353
|
end
|
257
|
-
alias_method :redirect_url, :location
|
258
354
|
|
259
|
-
|
260
|
-
|
261
|
-
|
355
|
+
def body_parts
|
356
|
+
parts = []
|
357
|
+
@stream.each { |x| parts << x }
|
358
|
+
parts
|
262
359
|
end
|
263
360
|
|
361
|
+
# The location header we'll be responding with.
|
362
|
+
alias_method :redirect_url, :location
|
363
|
+
|
264
364
|
def close
|
265
365
|
stream.close if stream.respond_to?(:close)
|
266
366
|
end
|
@@ -277,37 +377,24 @@ module ActionDispatch # :nodoc:
|
|
277
377
|
end
|
278
378
|
|
279
379
|
# Turns the Response into a Rack-compatible array of the status, headers,
|
280
|
-
# and body. Allows
|
380
|
+
# and body. Allows explicit splatting:
|
281
381
|
#
|
282
382
|
# status, headers, body = *response
|
283
383
|
def to_a
|
384
|
+
commit!
|
284
385
|
rack_response @status, @header.to_hash
|
285
386
|
end
|
286
387
|
alias prepare! to_a
|
287
388
|
|
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
|
301
|
-
|
302
389
|
# Returns the response cookies, converted to a Hash of (name => value) pairs
|
303
390
|
#
|
304
391
|
# assert_equal 'AuthorOfNewPage', r.cookies['author']
|
305
392
|
def cookies
|
306
393
|
cookies = {}
|
307
|
-
if header =
|
394
|
+
if header = get_header(SET_COOKIE)
|
308
395
|
header = header.split("\n") if header.respond_to?(:to_str)
|
309
396
|
header.each do |cookie|
|
310
|
-
if pair = cookie.split(
|
397
|
+
if pair = cookie.split(";").first
|
311
398
|
key, value = pair.split("=").map { |v| Rack::Utils.unescape(v) }
|
312
399
|
cookies[key] = value
|
313
400
|
end
|
@@ -318,14 +405,49 @@ module ActionDispatch # :nodoc:
|
|
318
405
|
|
319
406
|
private
|
320
407
|
|
408
|
+
ContentTypeHeader = Struct.new :mime_type, :charset
|
409
|
+
NullContentTypeHeader = ContentTypeHeader.new nil, nil
|
410
|
+
|
411
|
+
def parse_content_type(content_type)
|
412
|
+
if content_type
|
413
|
+
type, charset = content_type.split(/;\s*charset=/)
|
414
|
+
type = nil if type && type.empty?
|
415
|
+
ContentTypeHeader.new(type, charset)
|
416
|
+
else
|
417
|
+
NullContentTypeHeader
|
418
|
+
end
|
419
|
+
end
|
420
|
+
|
421
|
+
# Small internal convenience method to get the parsed version of the current
|
422
|
+
# content type header.
|
423
|
+
def parsed_content_type_header
|
424
|
+
parse_content_type(get_header(CONTENT_TYPE))
|
425
|
+
end
|
426
|
+
|
427
|
+
def set_content_type(content_type, charset)
|
428
|
+
type = (content_type || "").dup
|
429
|
+
type << "; charset=#{charset.to_s.downcase}" if charset
|
430
|
+
set_header CONTENT_TYPE, type
|
431
|
+
end
|
432
|
+
|
321
433
|
def before_committed
|
434
|
+
return if committed?
|
435
|
+
assign_default_content_type_and_charset!
|
436
|
+
merge_and_normalize_cache_control!(@cache_control)
|
437
|
+
handle_conditional_get!
|
438
|
+
handle_no_content!
|
322
439
|
end
|
323
440
|
|
324
441
|
def before_sending
|
325
|
-
|
442
|
+
# Normally we've already committed by now, but it's possible
|
443
|
+
# (e.g., if the controller action tries to read back its own
|
444
|
+
# response) to get here before that. In that case, we must force
|
445
|
+
# an "early" commit: we're about to freeze the headers, so this is
|
446
|
+
# our last chance.
|
447
|
+
commit! unless committed?
|
326
448
|
|
327
|
-
|
328
|
-
|
449
|
+
headers.freeze
|
450
|
+
request.commit_cookie_jar! unless committed?
|
329
451
|
end
|
330
452
|
|
331
453
|
def build_buffer(response, body)
|
@@ -336,20 +458,12 @@ module ActionDispatch # :nodoc:
|
|
336
458
|
body.respond_to?(:each) ? body : [body]
|
337
459
|
end
|
338
460
|
|
339
|
-
def assign_default_content_type_and_charset!
|
340
|
-
return if
|
341
|
-
|
342
|
-
@content_type ||= Mime::HTML
|
343
|
-
@charset ||= self.class.default_charset unless @charset == false
|
461
|
+
def assign_default_content_type_and_charset!
|
462
|
+
return if content_type
|
344
463
|
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
headers[CONTENT_TYPE] = type
|
349
|
-
end
|
350
|
-
|
351
|
-
def append_charset?
|
352
|
-
!@sending_file && @charset != false
|
464
|
+
ct = parsed_content_type_header
|
465
|
+
set_content_type(ct.mime_type || Mime[:html].to_s,
|
466
|
+
ct.charset || self.class.default_charset)
|
353
467
|
end
|
354
468
|
|
355
469
|
class RackBody
|
@@ -372,7 +486,7 @@ module ActionDispatch # :nodoc:
|
|
372
486
|
end
|
373
487
|
|
374
488
|
def respond_to?(method, include_private = false)
|
375
|
-
if method.to_s ==
|
489
|
+
if method.to_s == "to_path"
|
376
490
|
@response.stream.respond_to?(method)
|
377
491
|
else
|
378
492
|
super
|
@@ -388,14 +502,15 @@ module ActionDispatch # :nodoc:
|
|
388
502
|
end
|
389
503
|
end
|
390
504
|
|
391
|
-
def
|
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
|
-
|
505
|
+
def handle_no_content!
|
397
506
|
if NO_CONTENT_CODES.include?(@status)
|
398
|
-
header.delete CONTENT_TYPE
|
507
|
+
@header.delete CONTENT_TYPE
|
508
|
+
@header.delete "Content-Length"
|
509
|
+
end
|
510
|
+
end
|
511
|
+
|
512
|
+
def rack_response(status, header)
|
513
|
+
if NO_CONTENT_CODES.include?(status)
|
399
514
|
[status, header, []]
|
400
515
|
else
|
401
516
|
[status, header, RackBody.new(self)]
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module ActionDispatch
|
2
4
|
module Http
|
3
5
|
# Models uploaded files.
|
@@ -24,23 +26,27 @@ module ActionDispatch
|
|
24
26
|
attr_accessor :headers
|
25
27
|
|
26
28
|
def initialize(hash) # :nodoc:
|
27
|
-
@tempfile
|
28
|
-
raise(ArgumentError,
|
29
|
+
@tempfile = hash[:tempfile]
|
30
|
+
raise(ArgumentError, ":tempfile is required") unless @tempfile
|
31
|
+
|
32
|
+
if hash[:filename]
|
33
|
+
@original_filename = hash[:filename].dup
|
29
34
|
|
30
|
-
@original_filename = hash[:filename]
|
31
|
-
if @original_filename
|
32
35
|
begin
|
33
36
|
@original_filename.encode!(Encoding::UTF_8)
|
34
37
|
rescue EncodingError
|
35
38
|
@original_filename.force_encoding(Encoding::UTF_8)
|
36
39
|
end
|
40
|
+
else
|
41
|
+
@original_filename = nil
|
37
42
|
end
|
43
|
+
|
38
44
|
@content_type = hash[:type]
|
39
45
|
@headers = hash[:head]
|
40
46
|
end
|
41
47
|
|
42
48
|
# Shortcut for +tempfile.read+.
|
43
|
-
def read(length=nil, buffer=nil)
|
49
|
+
def read(length = nil, buffer = nil)
|
44
50
|
@tempfile.read(length, buffer)
|
45
51
|
end
|
46
52
|
|
@@ -50,7 +56,7 @@ module ActionDispatch
|
|
50
56
|
end
|
51
57
|
|
52
58
|
# Shortcut for +tempfile.close+.
|
53
|
-
def close(unlink_now=false)
|
59
|
+
def close(unlink_now = false)
|
54
60
|
@tempfile.close(unlink_now)
|
55
61
|
end
|
56
62
|
|