actionpack 5.2.3 → 6.0.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +191 -292
- data/MIT-LICENSE +1 -1
- data/README.rdoc +3 -2
- data/lib/abstract_controller/base.rb +4 -2
- data/lib/abstract_controller/caching/fragments.rb +6 -22
- data/lib/abstract_controller/callbacks.rb +12 -0
- data/lib/abstract_controller/collector.rb +1 -1
- data/lib/abstract_controller/helpers.rb +2 -2
- data/lib/abstract_controller/railties/routes_helpers.rb +1 -1
- data/lib/abstract_controller/translation.rb +1 -0
- data/lib/action_controller.rb +5 -1
- data/lib/action_controller/api.rb +2 -1
- data/lib/action_controller/base.rb +2 -7
- data/lib/action_controller/caching.rb +1 -1
- data/lib/action_controller/log_subscriber.rb +8 -5
- data/lib/action_controller/metal.rb +3 -3
- data/lib/action_controller/metal/basic_implicit_render.rb +1 -1
- data/lib/action_controller/metal/conditional_get.rb +9 -3
- data/lib/action_controller/metal/data_streaming.rb +5 -6
- data/lib/action_controller/metal/default_headers.rb +17 -0
- data/lib/action_controller/metal/etag_with_template_digest.rb +1 -1
- data/lib/action_controller/metal/exceptions.rb +23 -2
- data/lib/action_controller/metal/flash.rb +5 -5
- data/lib/action_controller/metal/force_ssl.rb +15 -56
- data/lib/action_controller/metal/head.rb +1 -1
- data/lib/action_controller/metal/helpers.rb +3 -4
- data/lib/action_controller/metal/http_authentication.rb +20 -21
- data/lib/action_controller/metal/implicit_render.rb +4 -14
- data/lib/action_controller/metal/instrumentation.rb +3 -5
- data/lib/action_controller/metal/live.rb +29 -27
- data/lib/action_controller/metal/mime_responds.rb +13 -2
- data/lib/action_controller/metal/params_wrapper.rb +18 -14
- data/lib/action_controller/metal/redirecting.rb +5 -5
- data/lib/action_controller/metal/renderers.rb +4 -4
- data/lib/action_controller/metal/rendering.rb +2 -2
- data/lib/action_controller/metal/request_forgery_protection.rb +23 -12
- data/lib/action_controller/metal/strong_parameters.rb +63 -44
- data/lib/action_controller/metal/url_for.rb +1 -1
- data/lib/action_controller/railties/helpers.rb +1 -1
- data/lib/action_controller/renderer.rb +16 -3
- data/lib/action_controller/template_assertions.rb +1 -1
- data/lib/action_controller/test_case.rb +4 -6
- data/lib/action_dispatch.rb +4 -2
- data/lib/action_dispatch/http/cache.rb +14 -10
- data/lib/action_dispatch/http/content_disposition.rb +45 -0
- data/lib/action_dispatch/http/content_security_policy.rb +28 -16
- data/lib/action_dispatch/http/filter_parameters.rb +8 -6
- data/lib/action_dispatch/http/filter_redirect.rb +1 -1
- data/lib/action_dispatch/http/headers.rb +1 -1
- data/lib/action_dispatch/http/mime_negotiation.rb +7 -5
- data/lib/action_dispatch/http/mime_type.rb +14 -6
- data/lib/action_dispatch/http/parameter_filter.rb +5 -79
- data/lib/action_dispatch/http/parameters.rb +13 -3
- data/lib/action_dispatch/http/request.rb +10 -13
- data/lib/action_dispatch/http/response.rb +39 -18
- data/lib/action_dispatch/http/upload.rb +9 -1
- data/lib/action_dispatch/http/url.rb +81 -81
- data/lib/action_dispatch/journey/formatter.rb +2 -2
- data/lib/action_dispatch/journey/nfa/simulator.rb +0 -2
- data/lib/action_dispatch/journey/nodes/node.rb +9 -8
- data/lib/action_dispatch/journey/path/pattern.rb +8 -3
- data/lib/action_dispatch/journey/route.rb +5 -4
- data/lib/action_dispatch/journey/router.rb +0 -3
- data/lib/action_dispatch/journey/router/utils.rb +10 -10
- data/lib/action_dispatch/journey/routes.rb +0 -1
- data/lib/action_dispatch/journey/scanner.rb +11 -4
- data/lib/action_dispatch/journey/visitors.rb +1 -1
- data/lib/action_dispatch/middleware/actionable_exceptions.rb +39 -0
- data/lib/action_dispatch/middleware/callbacks.rb +2 -4
- data/lib/action_dispatch/middleware/cookies.rb +52 -74
- data/lib/action_dispatch/middleware/debug_exceptions.rb +39 -59
- data/lib/action_dispatch/middleware/debug_locks.rb +5 -5
- data/lib/action_dispatch/middleware/debug_view.rb +68 -0
- data/lib/action_dispatch/middleware/exception_wrapper.rb +49 -15
- data/lib/action_dispatch/middleware/flash.rb +1 -1
- data/lib/action_dispatch/middleware/host_authorization.rb +103 -0
- data/lib/action_dispatch/middleware/public_exceptions.rb +6 -2
- data/lib/action_dispatch/middleware/remote_ip.rb +9 -11
- data/lib/action_dispatch/middleware/request_id.rb +2 -2
- data/lib/action_dispatch/middleware/session/cookie_store.rb +1 -6
- data/lib/action_dispatch/middleware/show_exceptions.rb +1 -1
- data/lib/action_dispatch/middleware/ssl.rb +8 -8
- data/lib/action_dispatch/middleware/stack.rb +34 -2
- data/lib/action_dispatch/middleware/static.rb +5 -6
- data/lib/action_dispatch/middleware/templates/rescues/_actions.html.erb +13 -0
- data/lib/action_dispatch/middleware/templates/rescues/_actions.text.erb +0 -0
- data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb +3 -1
- data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.text.erb +1 -1
- data/lib/action_dispatch/middleware/templates/rescues/_source.html.erb +4 -2
- data/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb +45 -35
- data/lib/action_dispatch/middleware/templates/rescues/blocked_host.html.erb +7 -0
- data/lib/action_dispatch/middleware/templates/rescues/blocked_host.text.erb +5 -0
- data/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb +26 -4
- data/lib/action_dispatch/middleware/templates/rescues/diagnostics.text.erb +1 -1
- data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.html.erb +7 -4
- data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.text.erb +4 -2
- data/lib/action_dispatch/middleware/templates/rescues/layout.erb +4 -0
- data/lib/action_dispatch/middleware/templates/rescues/missing_exact_template.html.erb +19 -0
- data/lib/action_dispatch/middleware/templates/rescues/missing_exact_template.text.erb +3 -0
- data/lib/action_dispatch/middleware/templates/rescues/missing_template.html.erb +2 -2
- data/lib/action_dispatch/middleware/templates/rescues/routing_error.html.erb +1 -1
- data/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb +2 -2
- data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +3 -0
- data/lib/action_dispatch/railtie.rb +7 -2
- data/lib/action_dispatch/request/session.rb +8 -0
- data/lib/action_dispatch/routing.rb +21 -20
- data/lib/action_dispatch/routing/inspector.rb +99 -50
- data/lib/action_dispatch/routing/mapper.rb +61 -39
- data/lib/action_dispatch/routing/polymorphic_routes.rb +3 -4
- data/lib/action_dispatch/routing/route_set.rb +24 -27
- data/lib/action_dispatch/routing/url_for.rb +1 -0
- data/lib/action_dispatch/system_test_case.rb +43 -5
- data/lib/action_dispatch/system_testing/browser.rb +38 -7
- data/lib/action_dispatch/system_testing/driver.rb +10 -1
- data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +6 -5
- data/lib/action_dispatch/system_testing/test_helpers/setup_and_teardown.rb +7 -6
- data/lib/action_dispatch/testing/assertions.rb +1 -1
- data/lib/action_dispatch/testing/assertions/response.rb +2 -3
- data/lib/action_dispatch/testing/assertions/routing.rb +15 -3
- data/lib/action_dispatch/testing/integration.rb +12 -5
- data/lib/action_dispatch/testing/request_encoder.rb +2 -2
- data/lib/action_dispatch/testing/test_process.rb +2 -2
- data/lib/action_dispatch/testing/test_response.rb +4 -32
- data/lib/action_pack.rb +1 -1
- data/lib/action_pack/gem_version.rb +3 -3
- metadata +29 -16
- data/lib/action_dispatch/system_testing/test_helpers/undef_methods.rb +0 -26
@@ -36,7 +36,7 @@ module ActionController #:nodoc:
|
|
36
36
|
define_method(type) do
|
37
37
|
request.flash[type]
|
38
38
|
end
|
39
|
-
helper_method
|
39
|
+
helper_method(type) if respond_to?(:helper_method)
|
40
40
|
|
41
41
|
self._flash_types += [type]
|
42
42
|
end
|
@@ -44,18 +44,18 @@ module ActionController #:nodoc:
|
|
44
44
|
end
|
45
45
|
|
46
46
|
private
|
47
|
-
def redirect_to(options = {},
|
47
|
+
def redirect_to(options = {}, response_options_and_flash = {}) #:doc:
|
48
48
|
self.class._flash_types.each do |flash_type|
|
49
|
-
if type =
|
49
|
+
if type = response_options_and_flash.delete(flash_type)
|
50
50
|
flash[flash_type] = type
|
51
51
|
end
|
52
52
|
end
|
53
53
|
|
54
|
-
if other_flashes =
|
54
|
+
if other_flashes = response_options_and_flash.delete(:flash)
|
55
55
|
flash.update(other_flashes)
|
56
56
|
end
|
57
57
|
|
58
|
-
super(options,
|
58
|
+
super(options, response_options_and_flash)
|
59
59
|
end
|
60
60
|
end
|
61
61
|
end
|
@@ -4,18 +4,10 @@ require "active_support/core_ext/hash/except"
|
|
4
4
|
require "active_support/core_ext/hash/slice"
|
5
5
|
|
6
6
|
module ActionController
|
7
|
-
# This module
|
8
|
-
#
|
9
|
-
#
|
10
|
-
|
11
|
-
# user authentication, account information, or credit card information.
|
12
|
-
#
|
13
|
-
# Note that if you are really concerned about your application security,
|
14
|
-
# you might consider using +config.force_ssl+ in your config file instead.
|
15
|
-
# That will ensure all the data is transferred via HTTPS, and will
|
16
|
-
# prevent the user from getting their session hijacked when accessing the
|
17
|
-
# site over unsecured HTTP protocol.
|
18
|
-
module ForceSSL
|
7
|
+
# This module is deprecated in favor of +config.force_ssl+ in your environment
|
8
|
+
# config file. This will ensure all endpoints not explicitly marked otherwise
|
9
|
+
# will have all communication served over HTTPS.
|
10
|
+
module ForceSSL # :nodoc:
|
19
11
|
extend ActiveSupport::Concern
|
20
12
|
include AbstractController::Callbacks
|
21
13
|
|
@@ -23,45 +15,17 @@ module ActionController
|
|
23
15
|
URL_OPTIONS = [:protocol, :host, :domain, :subdomain, :port, :path]
|
24
16
|
REDIRECT_OPTIONS = [:status, :flash, :alert, :notice]
|
25
17
|
|
26
|
-
module ClassMethods
|
27
|
-
# Force the request to this particular controller or specified actions to be
|
28
|
-
# through the HTTPS protocol.
|
29
|
-
#
|
30
|
-
# If you need to disable this for any reason (e.g. development) then you can use
|
31
|
-
# an +:if+ or +:unless+ condition.
|
32
|
-
#
|
33
|
-
# class AccountsController < ApplicationController
|
34
|
-
# force_ssl if: :ssl_configured?
|
35
|
-
#
|
36
|
-
# def ssl_configured?
|
37
|
-
# !Rails.env.development?
|
38
|
-
# end
|
39
|
-
# end
|
40
|
-
#
|
41
|
-
# ==== URL Options
|
42
|
-
# You can pass any of the following options to affect the redirect URL
|
43
|
-
# * <tt>host</tt> - Redirect to a different host name
|
44
|
-
# * <tt>subdomain</tt> - Redirect to a different subdomain
|
45
|
-
# * <tt>domain</tt> - Redirect to a different domain
|
46
|
-
# * <tt>port</tt> - Redirect to a non-standard port
|
47
|
-
# * <tt>path</tt> - Redirect to a different path
|
48
|
-
#
|
49
|
-
# ==== Redirect Options
|
50
|
-
# You can pass any of the following options to affect the redirect status and response
|
51
|
-
# * <tt>status</tt> - Redirect with a custom status (default is 301 Moved Permanently)
|
52
|
-
# * <tt>flash</tt> - Set a flash message when redirecting
|
53
|
-
# * <tt>alert</tt> - Set an alert message when redirecting
|
54
|
-
# * <tt>notice</tt> - Set a notice message when redirecting
|
55
|
-
#
|
56
|
-
# ==== Action Options
|
57
|
-
# You can pass any of the following options to affect the before_action callback
|
58
|
-
# * <tt>only</tt> - The callback should be run only for this action
|
59
|
-
# * <tt>except</tt> - The callback should be run for all actions except this action
|
60
|
-
# * <tt>if</tt> - A symbol naming an instance method or a proc; the
|
61
|
-
# callback will be called only when it returns a true value.
|
62
|
-
# * <tt>unless</tt> - A symbol naming an instance method or a proc; the
|
63
|
-
# callback will be called only when it returns a false value.
|
18
|
+
module ClassMethods # :nodoc:
|
64
19
|
def force_ssl(options = {})
|
20
|
+
ActiveSupport::Deprecation.warn(<<-MESSAGE.squish)
|
21
|
+
Controller-level `force_ssl` is deprecated and will be removed from
|
22
|
+
Rails 6.1. Please enable `config.force_ssl` in your environment
|
23
|
+
configuration to enable the ActionDispatch::SSL middleware to more
|
24
|
+
fully enforce that your application communicate over HTTPS. If needed,
|
25
|
+
you can use `config.ssl_options` to exempt matching endpoints from
|
26
|
+
being redirected to HTTPS.
|
27
|
+
MESSAGE
|
28
|
+
|
65
29
|
action_options = options.slice(*ACTION_OPTIONS)
|
66
30
|
redirect_options = options.except(*ACTION_OPTIONS)
|
67
31
|
before_action(action_options) do
|
@@ -70,18 +34,13 @@ module ActionController
|
|
70
34
|
end
|
71
35
|
end
|
72
36
|
|
73
|
-
# Redirect the existing request to use the HTTPS protocol.
|
74
|
-
#
|
75
|
-
# ==== Parameters
|
76
|
-
# * <tt>host_or_options</tt> - Either a host name or any of the URL and
|
77
|
-
# redirect options available to the <tt>force_ssl</tt> method.
|
78
37
|
def force_ssl_redirect(host_or_options = nil)
|
79
38
|
unless request.ssl?
|
80
39
|
options = {
|
81
40
|
protocol: "https://",
|
82
41
|
host: request.host,
|
83
42
|
path: request.fullpath,
|
84
|
-
status: :moved_permanently
|
43
|
+
status: :moved_permanently,
|
85
44
|
}
|
86
45
|
|
87
46
|
if host_or_options.is_a?(Hash)
|
@@ -38,7 +38,7 @@ module ActionController
|
|
38
38
|
self.response_body = ""
|
39
39
|
|
40
40
|
if include_content?(response_code)
|
41
|
-
self.content_type = content_type || (Mime[formats.first] if formats)
|
41
|
+
self.content_type = content_type || (Mime[formats.first] if formats) || Mime[:html]
|
42
42
|
response.charset = false
|
43
43
|
end
|
44
44
|
|
@@ -34,7 +34,7 @@ module ActionController
|
|
34
34
|
# end
|
35
35
|
# end
|
36
36
|
#
|
37
|
-
# Then, in any view rendered by <tt>
|
37
|
+
# Then, in any view rendered by <tt>EventsController</tt>, the <tt>format_time</tt> method can be called:
|
38
38
|
#
|
39
39
|
# <% @events.each do |event| -%>
|
40
40
|
# <p>
|
@@ -75,7 +75,7 @@ module ActionController
|
|
75
75
|
# Provides a proxy to access helper methods from outside the view.
|
76
76
|
def helpers
|
77
77
|
@helper_proxy ||= begin
|
78
|
-
proxy = ActionView::Base.
|
78
|
+
proxy = ActionView::Base.empty
|
79
79
|
proxy.config = config.inheritable_copy
|
80
80
|
proxy.extend(_helpers)
|
81
81
|
end
|
@@ -100,8 +100,7 @@ module ActionController
|
|
100
100
|
# # => ["application", "chart", "rubygems"]
|
101
101
|
def all_helpers_from_path(path)
|
102
102
|
helpers = Array(path).flat_map do |_path|
|
103
|
-
|
104
|
-
names = Dir["#{_path}/**/*_helper.rb"].map { |file| file.sub(extract, '\1'.freeze) }
|
103
|
+
names = Dir["#{_path}/**/*_helper.rb"].map { |file| file[_path.to_s.size + 1..-"_helper.rb".size - 1] }
|
105
104
|
names.sort!
|
106
105
|
end
|
107
106
|
helpers.uniq!
|
@@ -56,8 +56,9 @@ module ActionController
|
|
56
56
|
# In your integration tests, you can do something like this:
|
57
57
|
#
|
58
58
|
# def test_access_granted_from_xml
|
59
|
-
#
|
60
|
-
#
|
59
|
+
# authorization = ActionController::HttpAuthentication::Basic.encode_credentials(users(:dhh).name, users(:dhh).password)
|
60
|
+
#
|
61
|
+
# get "/notes/1.xml", headers: { 'HTTP_AUTHORIZATION' => authorization }
|
61
62
|
#
|
62
63
|
# assert_equal 200, status
|
63
64
|
# end
|
@@ -68,21 +69,20 @@ module ActionController
|
|
68
69
|
extend ActiveSupport::Concern
|
69
70
|
|
70
71
|
module ClassMethods
|
71
|
-
def http_basic_authenticate_with(
|
72
|
-
before_action(options
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
end
|
72
|
+
def http_basic_authenticate_with(name:, password:, realm: nil, **options)
|
73
|
+
before_action(options) { http_basic_authenticate_or_request_with name: name, password: password, realm: realm }
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def http_basic_authenticate_or_request_with(name:, password:, realm: nil, message: nil)
|
78
|
+
authenticate_or_request_with_http_basic(realm, message) do |given_name, given_password|
|
79
|
+
ActiveSupport::SecurityUtils.secure_compare(given_name, name) &
|
80
|
+
ActiveSupport::SecurityUtils.secure_compare(given_password, password)
|
81
81
|
end
|
82
82
|
end
|
83
83
|
|
84
|
-
def authenticate_or_request_with_http_basic(realm =
|
85
|
-
authenticate_with_http_basic(&login_procedure) || request_http_basic_authentication(realm, message)
|
84
|
+
def authenticate_or_request_with_http_basic(realm = nil, message = nil, &login_procedure)
|
85
|
+
authenticate_with_http_basic(&login_procedure) || request_http_basic_authentication(realm || "Application", message)
|
86
86
|
end
|
87
87
|
|
88
88
|
def authenticate_with_http_basic(&login_procedure)
|
@@ -126,7 +126,7 @@ module ActionController
|
|
126
126
|
|
127
127
|
def authentication_request(controller, realm, message)
|
128
128
|
message ||= "HTTP Basic: Access denied.\n"
|
129
|
-
controller.headers["WWW-Authenticate"] = %(Basic realm="#{realm.tr('"'
|
129
|
+
controller.headers["WWW-Authenticate"] = %(Basic realm="#{realm.tr('"', "")}")
|
130
130
|
controller.status = 401
|
131
131
|
controller.response_body = message
|
132
132
|
end
|
@@ -389,10 +389,9 @@ module ActionController
|
|
389
389
|
# In your integration tests, you can do something like this:
|
390
390
|
#
|
391
391
|
# def test_access_granted_from_xml
|
392
|
-
#
|
393
|
-
#
|
394
|
-
#
|
395
|
-
# )
|
392
|
+
# authorization = ActionController::HttpAuthentication::Token.encode_credentials(users(:dhh).token)
|
393
|
+
#
|
394
|
+
# get "/notes/1.xml", headers: { 'HTTP_AUTHORIZATION' => authorization }
|
396
395
|
#
|
397
396
|
# assert_equal 200, status
|
398
397
|
# end
|
@@ -474,7 +473,7 @@ module ActionController
|
|
474
473
|
|
475
474
|
# This removes the <tt>"</tt> characters wrapping the value.
|
476
475
|
def rewrite_param_values(array_params)
|
477
|
-
array_params.each { |param| (param[1] || ""
|
476
|
+
array_params.each { |param| (param[1] || +"").gsub! %r/^"|"$/, "" }
|
478
477
|
end
|
479
478
|
|
480
479
|
# This method takes an authorization body and splits up the key-value
|
@@ -511,7 +510,7 @@ module ActionController
|
|
511
510
|
# Returns nothing.
|
512
511
|
def authentication_request(controller, realm, message = nil)
|
513
512
|
message ||= "HTTP Token: Access denied.\n"
|
514
|
-
controller.headers["WWW-Authenticate"] = %(Token realm="#{realm.tr('"'
|
513
|
+
controller.headers["WWW-Authenticate"] = %(Token realm="#{realm.tr('"', "")}")
|
515
514
|
controller.__send__ :render, plain: message, status: :unauthorized
|
516
515
|
end
|
517
516
|
end
|
@@ -30,9 +30,9 @@ module ActionController
|
|
30
30
|
# :stopdoc:
|
31
31
|
include BasicImplicitRender
|
32
32
|
|
33
|
-
def default_render
|
33
|
+
def default_render
|
34
34
|
if template_exists?(action_name.to_s, _prefixes, variants: request.variant)
|
35
|
-
render
|
35
|
+
render
|
36
36
|
elsif any_templates?(action_name.to_s, _prefixes)
|
37
37
|
message = "#{self.class.name}\##{action_name} is missing a template " \
|
38
38
|
"for this request format and variant.\n" \
|
@@ -41,18 +41,8 @@ module ActionController
|
|
41
41
|
|
42
42
|
raise ActionController::UnknownFormat, message
|
43
43
|
elsif interactive_browser_request?
|
44
|
-
message = "#{self.class.name}\##{action_name} is missing a template "
|
45
|
-
|
46
|
-
"request.formats: #{request.formats.map(&:to_s).inspect}\n" \
|
47
|
-
"request.variant: #{request.variant.inspect}\n\n" \
|
48
|
-
"NOTE! For XHR/Ajax or API requests, this action would normally " \
|
49
|
-
"respond with 204 No Content: an empty white screen. Since you're " \
|
50
|
-
"loading it in a web browser, we assume that you expected to " \
|
51
|
-
"actually render a template, not nothing, so we're showing an " \
|
52
|
-
"error to be extra-clear. If you expect 204 No Content, carry on. " \
|
53
|
-
"That's what you'll get from an XHR or API request. Give it a shot."
|
54
|
-
|
55
|
-
raise ActionController::UnknownFormat, message
|
44
|
+
message = "#{self.class.name}\##{action_name} is missing a template for request formats: #{request.formats.map(&:to_s).join(',')}"
|
45
|
+
raise ActionController::MissingExactTemplate, message
|
56
46
|
else
|
57
47
|
logger.info "No template found for #{self.class.name}\##{action_name}, rendering head :no_content" if logger
|
58
48
|
super
|
@@ -30,13 +30,11 @@ module ActionController
|
|
30
30
|
ActiveSupport::Notifications.instrument("start_processing.action_controller", raw_payload.dup)
|
31
31
|
|
32
32
|
ActiveSupport::Notifications.instrument("process_action.action_controller", raw_payload) do |payload|
|
33
|
-
|
34
|
-
result = super
|
33
|
+
super.tap do
|
35
34
|
payload[:status] = response.status
|
36
|
-
result
|
37
|
-
ensure
|
38
|
-
append_info_to_payload(payload)
|
39
35
|
end
|
36
|
+
ensure
|
37
|
+
append_info_to_payload(payload)
|
40
38
|
end
|
41
39
|
end
|
42
40
|
|
@@ -86,7 +86,7 @@ module ActionController
|
|
86
86
|
# Note: SSEs are not currently supported by IE. However, they are supported
|
87
87
|
# by Chrome, Firefox, Opera, and Safari.
|
88
88
|
class SSE
|
89
|
-
|
89
|
+
PERMITTED_OPTIONS = %w( retry event id )
|
90
90
|
|
91
91
|
def initialize(stream, options = {})
|
92
92
|
@stream = stream
|
@@ -111,13 +111,13 @@ module ActionController
|
|
111
111
|
def perform_write(json, options)
|
112
112
|
current_options = @options.merge(options).stringify_keys
|
113
113
|
|
114
|
-
|
114
|
+
PERMITTED_OPTIONS.each do |option_name|
|
115
115
|
if (option_value = current_options[option_name])
|
116
116
|
@stream.write "#{option_name}: #{option_value}\n"
|
117
117
|
end
|
118
118
|
end
|
119
119
|
|
120
|
-
message = json.gsub("\n"
|
120
|
+
message = json.gsub("\n", "\ndata: ")
|
121
121
|
@stream.write "data: #{message}\n\n"
|
122
122
|
end
|
123
123
|
end
|
@@ -146,7 +146,7 @@ module ActionController
|
|
146
146
|
|
147
147
|
def write(string)
|
148
148
|
unless @response.committed?
|
149
|
-
@response.
|
149
|
+
@response.headers["Cache-Control"] ||= "no-cache"
|
150
150
|
@response.delete_header "Content-Length"
|
151
151
|
end
|
152
152
|
|
@@ -280,33 +280,35 @@ module ActionController
|
|
280
280
|
raise error if error
|
281
281
|
end
|
282
282
|
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
# this method except in Rails internals. Seriously!
|
287
|
-
def new_controller_thread # :nodoc:
|
288
|
-
Thread.new {
|
289
|
-
t2 = Thread.current
|
290
|
-
t2.abort_on_exception = true
|
291
|
-
yield
|
292
|
-
}
|
283
|
+
def response_body=(body)
|
284
|
+
super
|
285
|
+
response.close if response
|
293
286
|
end
|
294
287
|
|
295
|
-
|
296
|
-
logger = ActionController::Base.logger
|
297
|
-
return unless logger
|
288
|
+
private
|
298
289
|
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
290
|
+
# Spawn a new thread to serve up the controller in. This is to get
|
291
|
+
# around the fact that Rack isn't based around IOs and we need to use
|
292
|
+
# a thread to stream data from the response bodies. Nobody should call
|
293
|
+
# this method except in Rails internals. Seriously!
|
294
|
+
def new_controller_thread # :nodoc:
|
295
|
+
Thread.new {
|
296
|
+
t2 = Thread.current
|
297
|
+
t2.abort_on_exception = true
|
298
|
+
yield
|
299
|
+
}
|
304
300
|
end
|
305
|
-
end
|
306
301
|
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
302
|
+
def log_error(exception)
|
303
|
+
logger = ActionController::Base.logger
|
304
|
+
return unless logger
|
305
|
+
|
306
|
+
logger.fatal do
|
307
|
+
message = +"\n#{exception.class} (#{exception.message}):\n"
|
308
|
+
message << exception.annotated_source_code.to_s if exception.respond_to?(:annotated_source_code)
|
309
|
+
message << " " << exception.backtrace.join("\n ")
|
310
|
+
"#{message}\n\n"
|
311
|
+
end
|
312
|
+
end
|
311
313
|
end
|
312
314
|
end
|
@@ -11,7 +11,7 @@ module ActionController #:nodoc:
|
|
11
11
|
# @people = Person.all
|
12
12
|
# end
|
13
13
|
#
|
14
|
-
# That action implicitly responds to all formats, but formats can also be
|
14
|
+
# That action implicitly responds to all formats, but formats can also be explicitly enumerated:
|
15
15
|
#
|
16
16
|
# def index
|
17
17
|
# @people = Person.all
|
@@ -105,7 +105,7 @@ module ActionController #:nodoc:
|
|
105
105
|
#
|
106
106
|
# Mime::Type.register "image/jpg", :jpg
|
107
107
|
#
|
108
|
-
#
|
108
|
+
# +respond_to+ also allows you to specify a common block for different formats by using +any+:
|
109
109
|
#
|
110
110
|
# def index
|
111
111
|
# @people = Person.all
|
@@ -124,6 +124,14 @@ module ActionController #:nodoc:
|
|
124
124
|
#
|
125
125
|
# render json: @people
|
126
126
|
#
|
127
|
+
# +any+ can also be used with no arguments, in which case it will be used for any format requested by
|
128
|
+
# the user:
|
129
|
+
#
|
130
|
+
# respond_to do |format|
|
131
|
+
# format.html
|
132
|
+
# format.any { redirect_to support_path }
|
133
|
+
# end
|
134
|
+
#
|
127
135
|
# Formats can have different variants.
|
128
136
|
#
|
129
137
|
# The request variant is a specialization of the request format, like <tt>:tablet</tt>,
|
@@ -197,6 +205,9 @@ module ActionController #:nodoc:
|
|
197
205
|
yield collector if block_given?
|
198
206
|
|
199
207
|
if format = collector.negotiate_format(request)
|
208
|
+
if media_type && media_type != format
|
209
|
+
raise ActionController::RespondToMismatchError
|
210
|
+
end
|
200
211
|
_process_format(format)
|
201
212
|
_set_rendered_content_type format
|
202
213
|
response = collector.response
|
@@ -93,7 +93,7 @@ module ActionController
|
|
93
93
|
end
|
94
94
|
|
95
95
|
def model
|
96
|
-
super ||
|
96
|
+
super || self.model = _default_wrap_model
|
97
97
|
end
|
98
98
|
|
99
99
|
def include
|
@@ -115,7 +115,7 @@ module ActionController
|
|
115
115
|
|
116
116
|
if m.respond_to?(:nested_attributes_options) && m.nested_attributes_options.keys.any?
|
117
117
|
self.include += m.nested_attributes_options.keys.map do |key|
|
118
|
-
key.to_s.concat("_attributes")
|
118
|
+
(+key.to_s).concat("_attributes")
|
119
119
|
end
|
120
120
|
end
|
121
121
|
|
@@ -241,18 +241,7 @@ module ActionController
|
|
241
241
|
# Performs parameters wrapping upon the request. Called automatically
|
242
242
|
# by the metal call stack.
|
243
243
|
def process_action(*args)
|
244
|
-
if _wrapper_enabled?
|
245
|
-
wrapped_hash = _wrap_parameters request.request_parameters
|
246
|
-
wrapped_keys = request.request_parameters.keys
|
247
|
-
wrapped_filtered_hash = _wrap_parameters request.filtered_parameters.slice(*wrapped_keys)
|
248
|
-
|
249
|
-
# This will make the wrapped hash accessible from controller and view.
|
250
|
-
request.parameters.merge! wrapped_hash
|
251
|
-
request.request_parameters.merge! wrapped_hash
|
252
|
-
|
253
|
-
# This will display the wrapped hash in the log file.
|
254
|
-
request.filtered_parameters.merge! wrapped_filtered_hash
|
255
|
-
end
|
244
|
+
_perform_parameter_wrapping if _wrapper_enabled?
|
256
245
|
super
|
257
246
|
end
|
258
247
|
|
@@ -289,5 +278,20 @@ module ActionController
|
|
289
278
|
ref = request.content_mime_type.ref
|
290
279
|
_wrapper_formats.include?(ref) && _wrapper_key && !request.parameters.key?(_wrapper_key)
|
291
280
|
end
|
281
|
+
|
282
|
+
def _perform_parameter_wrapping
|
283
|
+
wrapped_hash = _wrap_parameters request.request_parameters
|
284
|
+
wrapped_keys = request.request_parameters.keys
|
285
|
+
wrapped_filtered_hash = _wrap_parameters request.filtered_parameters.slice(*wrapped_keys)
|
286
|
+
|
287
|
+
# This will make the wrapped hash accessible from controller and view.
|
288
|
+
request.parameters.merge! wrapped_hash
|
289
|
+
request.request_parameters.merge! wrapped_hash
|
290
|
+
|
291
|
+
# This will display the wrapped hash in the log file.
|
292
|
+
request.filtered_parameters.merge! wrapped_filtered_hash
|
293
|
+
rescue ActionDispatch::Http::Parameters::ParseError
|
294
|
+
# swallow parse error exception
|
295
|
+
end
|
292
296
|
end
|
293
297
|
end
|