actionpack 5.2.7.1 → 6.0.0.beta1
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 +109 -472
- data/MIT-LICENSE +1 -1
- data/README.rdoc +1 -1
- data/lib/abstract_controller/base.rb +4 -2
- data/lib/abstract_controller/caching/fragments.rb +6 -21
- 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/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/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/exceptions.rb +22 -1
- data/lib/action_controller/metal/flash.rb +5 -5
- data/lib/action_controller/metal/force_ssl.rb +17 -57
- data/lib/action_controller/metal/head.rb +1 -1
- data/lib/action_controller/metal/helpers.rb +1 -2
- data/lib/action_controller/metal/http_authentication.rb +21 -22
- data/lib/action_controller/metal/implicit_render.rb +2 -12
- data/lib/action_controller/metal/instrumentation.rb +3 -5
- data/lib/action_controller/metal/live.rb +28 -26
- 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 +32 -11
- data/lib/action_controller/metal/rendering.rb +1 -1
- data/lib/action_controller/metal/request_forgery_protection.rb +32 -97
- data/lib/action_controller/metal/strong_parameters.rb +57 -34
- data/lib/action_controller/metal/url_for.rb +1 -1
- data/lib/action_controller/metal.rb +2 -2
- data/lib/action_controller/railties/helpers.rb +1 -1
- data/lib/action_controller/renderer.rb +15 -2
- data/lib/action_controller/test_case.rb +5 -9
- data/lib/action_controller.rb +1 -0
- 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 +17 -8
- 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 -10
- data/lib/action_dispatch/http/mime_type.rb +1 -5
- 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 +14 -14
- data/lib/action_dispatch/http/upload.rb +5 -0
- data/lib/action_dispatch/http/url.rb +81 -81
- data/lib/action_dispatch/journey/formatter.rb +1 -1
- 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 +3 -4
- data/lib/action_dispatch/journey/router/utils.rb +10 -10
- data/lib/action_dispatch/journey/router.rb +0 -3
- data/lib/action_dispatch/journey/scanner.rb +11 -4
- data/lib/action_dispatch/journey/visitors.rb +1 -1
- data/lib/action_dispatch/middleware/callbacks.rb +2 -4
- data/lib/action_dispatch/middleware/cookies.rb +49 -70
- data/lib/action_dispatch/middleware/debug_exceptions.rb +32 -58
- data/lib/action_dispatch/middleware/debug_locks.rb +5 -5
- data/lib/action_dispatch/middleware/debug_view.rb +50 -0
- data/lib/action_dispatch/middleware/exception_wrapper.rb +36 -7
- data/lib/action_dispatch/middleware/executor.rb +1 -1
- data/lib/action_dispatch/middleware/flash.rb +1 -1
- data/lib/action_dispatch/middleware/host_authorization.rb +103 -0
- data/lib/action_dispatch/middleware/remote_ip.rb +6 -8
- data/lib/action_dispatch/middleware/request_id.rb +2 -2
- data/lib/action_dispatch/middleware/session/abstract_store.rb +0 -14
- data/lib/action_dispatch/middleware/session/cache_store.rb +6 -11
- data/lib/action_dispatch/middleware/session/cookie_store.rb +11 -27
- data/lib/action_dispatch/middleware/ssl.rb +8 -8
- data/lib/action_dispatch/middleware/stack.rb +2 -2
- data/lib/action_dispatch/middleware/static.rb +5 -6
- 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 +20 -2
- data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.html.erb +4 -4
- data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.text.erb +2 -2
- 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 +1 -0
- data/lib/action_dispatch/request/session.rb +8 -6
- data/lib/action_dispatch/routing/inspector.rb +99 -50
- data/lib/action_dispatch/routing/mapper.rb +36 -29
- data/lib/action_dispatch/routing/polymorphic_routes.rb +7 -12
- data/lib/action_dispatch/routing/route_set.rb +11 -12
- data/lib/action_dispatch/routing/url_for.rb +1 -0
- data/lib/action_dispatch/routing.rb +3 -2
- data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +3 -3
- data/lib/action_dispatch/testing/assertions/response.rb +2 -3
- data/lib/action_dispatch/testing/assertions/routing.rb +7 -2
- data/lib/action_dispatch/testing/integration.rb +11 -5
- data/lib/action_dispatch/testing/test_process.rb +2 -2
- data/lib/action_dispatch/testing/test_response.rb +4 -32
- data/lib/action_dispatch.rb +7 -6
- data/lib/action_pack/gem_version.rb +4 -4
- data/lib/action_pack.rb +1 -1
- metadata +25 -23
data/README.rdoc
CHANGED
@@ -32,7 +32,7 @@ The latest version of Action Pack can be installed with RubyGems:
|
|
32
32
|
|
33
33
|
Source code can be downloaded as part of the Rails project on GitHub:
|
34
34
|
|
35
|
-
* https://github.com/rails/rails/tree/
|
35
|
+
* https://github.com/rails/rails/tree/master/actionpack
|
36
36
|
|
37
37
|
|
38
38
|
== License
|
@@ -78,7 +78,9 @@ module AbstractController
|
|
78
78
|
# Except for public instance methods of Base and its ancestors
|
79
79
|
internal_methods +
|
80
80
|
# Be sure to include shadowed public instance methods of this class
|
81
|
-
public_instance_methods(false))
|
81
|
+
public_instance_methods(false))
|
82
|
+
|
83
|
+
methods.map!(&:to_s)
|
82
84
|
|
83
85
|
methods.to_set
|
84
86
|
end
|
@@ -102,7 +104,7 @@ module AbstractController
|
|
102
104
|
# ==== Returns
|
103
105
|
# * <tt>String</tt>
|
104
106
|
def controller_path
|
105
|
-
@controller_path ||= name.sub(/Controller$/, ""
|
107
|
+
@controller_path ||= name.sub(/Controller$/, "").underscore unless anonymous?
|
106
108
|
end
|
107
109
|
|
108
110
|
# Refresh the cached action_methods when a new action_method is added.
|
@@ -60,35 +60,20 @@ module AbstractController
|
|
60
60
|
end
|
61
61
|
end
|
62
62
|
|
63
|
-
# Given a key (as described in +expire_fragment+), returns
|
64
|
-
# a key suitable for use in reading, writing, or expiring a
|
65
|
-
# cached fragment. All keys begin with <tt>views/</tt>,
|
66
|
-
# followed by any controller-wide key prefix values, ending
|
67
|
-
# with the specified +key+ value. The key is expanded using
|
68
|
-
# ActiveSupport::Cache.expand_cache_key.
|
69
|
-
def fragment_cache_key(key)
|
70
|
-
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
71
|
-
Calling fragment_cache_key directly is deprecated and will be removed in Rails 6.0.
|
72
|
-
All fragment accessors now use the combined_fragment_cache_key method that retains the key as an array,
|
73
|
-
such that the caching stores can interrogate the parts for cache versions used in
|
74
|
-
recyclable cache keys.
|
75
|
-
MSG
|
76
|
-
|
77
|
-
head = self.class.fragment_cache_keys.map { |k| instance_exec(&k) }
|
78
|
-
tail = key.is_a?(Hash) ? url_for(key).split("://").last : key
|
79
|
-
ActiveSupport::Cache.expand_cache_key([*head, *tail], :views)
|
80
|
-
end
|
81
|
-
|
82
63
|
# Given a key (as described in +expire_fragment+), returns
|
83
64
|
# a key array suitable for use in reading, writing, or expiring a
|
84
65
|
# cached fragment. All keys begin with <tt>:views</tt>,
|
85
|
-
# followed by ENV["RAILS_CACHE_ID"] or ENV["RAILS_APP_VERSION"] if set,
|
66
|
+
# followed by <tt>ENV["RAILS_CACHE_ID"]</tt> or <tt>ENV["RAILS_APP_VERSION"]</tt> if set,
|
86
67
|
# followed by any controller-wide key prefix values, ending
|
87
68
|
# with the specified +key+ value.
|
88
69
|
def combined_fragment_cache_key(key)
|
89
70
|
head = self.class.fragment_cache_keys.map { |k| instance_exec(&k) }
|
90
71
|
tail = key.is_a?(Hash) ? url_for(key).split("://").last : key
|
91
|
-
|
72
|
+
|
73
|
+
cache_key = [:views, ENV["RAILS_CACHE_ID"] || ENV["RAILS_APP_VERSION"], head, tail]
|
74
|
+
cache_key.flatten!(1)
|
75
|
+
cache_key.compact!
|
76
|
+
cache_key
|
92
77
|
end
|
93
78
|
|
94
79
|
# Writes +content+ to the location signified by
|
@@ -103,6 +103,10 @@ module AbstractController
|
|
103
103
|
# :call-seq: before_action(names, block)
|
104
104
|
#
|
105
105
|
# Append a callback before actions. See _insert_callbacks for parameter details.
|
106
|
+
#
|
107
|
+
# If the callback renders or redirects, the action will not run. If there
|
108
|
+
# are additional callbacks scheduled to run after that callback, they are
|
109
|
+
# also cancelled.
|
106
110
|
|
107
111
|
##
|
108
112
|
# :method: prepend_before_action
|
@@ -110,6 +114,10 @@ module AbstractController
|
|
110
114
|
# :call-seq: prepend_before_action(names, block)
|
111
115
|
#
|
112
116
|
# Prepend a callback before actions. See _insert_callbacks for parameter details.
|
117
|
+
#
|
118
|
+
# If the callback renders or redirects, the action will not run. If there
|
119
|
+
# are additional callbacks scheduled to run after that callback, they are
|
120
|
+
# also cancelled.
|
113
121
|
|
114
122
|
##
|
115
123
|
# :method: skip_before_action
|
@@ -124,6 +132,10 @@ module AbstractController
|
|
124
132
|
# :call-seq: append_before_action(names, block)
|
125
133
|
#
|
126
134
|
# Append a callback before actions. See _insert_callbacks for parameter details.
|
135
|
+
#
|
136
|
+
# If the callback renders or redirects, the action will not run. If there
|
137
|
+
# are additional callbacks scheduled to run after that callback, they are
|
138
|
+
# also cancelled.
|
127
139
|
|
128
140
|
##
|
129
141
|
# :method: after_action
|
@@ -26,7 +26,7 @@ module AbstractController
|
|
26
26
|
def method_missing(symbol, &block)
|
27
27
|
unless mime_constant = Mime[symbol]
|
28
28
|
raise NoMethodError, "To respond to a custom format, register it as a MIME type first: " \
|
29
|
-
"
|
29
|
+
"https://guides.rubyonrails.org/action_controller_overview.html#restful-downloads. " \
|
30
30
|
"If you meant to respond to a variant like :tablet or :phone, not a custom format, " \
|
31
31
|
"be sure to nest your variant response within a format response: " \
|
32
32
|
"format.html { |html| html.tablet { ... } }"
|
@@ -17,7 +17,7 @@ module AbstractController
|
|
17
17
|
@path = "helpers/#{path}.rb"
|
18
18
|
set_backtrace error.backtrace
|
19
19
|
|
20
|
-
if
|
20
|
+
if /^#{path}(\.rb)?$/.match?(error.path)
|
21
21
|
super("Missing helper file helpers/%s.rb" % path)
|
22
22
|
else
|
23
23
|
raise error
|
@@ -181,7 +181,7 @@ module AbstractController
|
|
181
181
|
end
|
182
182
|
|
183
183
|
def default_helper_module!
|
184
|
-
module_name = name.sub(/Controller$/, ""
|
184
|
+
module_name = name.sub(/Controller$/, "")
|
185
185
|
module_path = module_name.underscore
|
186
186
|
helper module_path
|
187
187
|
rescue LoadError => e
|
@@ -7,7 +7,7 @@ module AbstractController
|
|
7
7
|
Module.new do
|
8
8
|
define_method(:inherited) do |klass|
|
9
9
|
super(klass)
|
10
|
-
if namespace = klass.
|
10
|
+
if namespace = klass.module_parents.detect { |m| m.respond_to?(:railtie_routes_url_helpers) }
|
11
11
|
klass.include(namespace.railtie_routes_url_helpers(include_path_helpers))
|
12
12
|
else
|
13
13
|
klass.include(routes.url_helpers(include_path_helpers))
|
@@ -12,7 +12,7 @@ module ActionController
|
|
12
12
|
#
|
13
13
|
# An API Controller is different from a normal controller in the sense that
|
14
14
|
# by default it doesn't include a number of features that are usually required
|
15
|
-
# by browser access only: layouts and templates rendering,
|
15
|
+
# by browser access only: layouts and templates rendering,
|
16
16
|
# flash, assets, and so on. This makes the entire controller stack thinner,
|
17
17
|
# suitable for API applications. It doesn't mean you won't have such
|
18
18
|
# features if you need them: they're all available for you to include in
|
@@ -122,6 +122,7 @@ module ActionController
|
|
122
122
|
|
123
123
|
ForceSSL,
|
124
124
|
DataStreaming,
|
125
|
+
DefaultHeaders,
|
125
126
|
|
126
127
|
# Before callbacks should also be executed as early as possible, so
|
127
128
|
# also include them at the bottom.
|
@@ -78,7 +78,7 @@ module ActionController
|
|
78
78
|
#
|
79
79
|
# You can retrieve it again through the same hash:
|
80
80
|
#
|
81
|
-
# Hello #{session[:person]}
|
81
|
+
# "Hello #{session[:person]}"
|
82
82
|
#
|
83
83
|
# For removing objects from the session, you can either assign a single key to +nil+:
|
84
84
|
#
|
@@ -232,6 +232,7 @@ module ActionController
|
|
232
232
|
HttpAuthentication::Basic::ControllerMethods,
|
233
233
|
HttpAuthentication::Digest::ControllerMethods,
|
234
234
|
HttpAuthentication::Token::ControllerMethods,
|
235
|
+
DefaultHeaders,
|
235
236
|
|
236
237
|
# Before callbacks should also be executed as early as possible, so
|
237
238
|
# also include them at the bottom.
|
@@ -264,12 +265,6 @@ module ActionController
|
|
264
265
|
PROTECTED_IVARS
|
265
266
|
end
|
266
267
|
|
267
|
-
def self.make_response!(request)
|
268
|
-
ActionDispatch::Response.create.tap do |res|
|
269
|
-
res.request = request
|
270
|
-
end
|
271
|
-
end
|
272
|
-
|
273
268
|
ActiveSupport.run_load_hooks(:action_controller_base, self)
|
274
269
|
ActiveSupport.run_load_hooks(:action_controller, self)
|
275
270
|
end
|
@@ -18,16 +18,19 @@ module ActionController
|
|
18
18
|
|
19
19
|
def process_action(event)
|
20
20
|
info do
|
21
|
-
payload
|
21
|
+
payload = event.payload
|
22
22
|
additions = ActionController::Base.log_process_action(payload)
|
23
|
-
|
24
23
|
status = payload[:status]
|
24
|
+
|
25
25
|
if status.nil? && payload[:exception].present?
|
26
26
|
exception_class_name = payload[:exception].first
|
27
27
|
status = ActionDispatch::ExceptionWrapper.status_code_for_exception(exception_class_name)
|
28
28
|
end
|
29
|
-
|
30
|
-
|
29
|
+
|
30
|
+
additions << "Allocations: #{event.allocations}"
|
31
|
+
|
32
|
+
message = +"Completed #{status} #{Rack::Utils::HTTP_STATUS_CODES[status]} in #{event.duration.round}ms"
|
33
|
+
message << " (#{additions.join(" | ")})" unless additions.empty?
|
31
34
|
message << "\n\n" if defined?(Rails.env) && Rails.env.development?
|
32
35
|
|
33
36
|
message
|
@@ -53,7 +56,7 @@ module ActionController
|
|
53
56
|
def unpermitted_parameters(event)
|
54
57
|
debug do
|
55
58
|
unpermitted_keys = event.payload[:keys]
|
56
|
-
"Unpermitted parameter#{'s' if unpermitted_keys.size > 1}: #{unpermitted_keys.map { |e| ":#{e}" }.join(", ")}"
|
59
|
+
color("Unpermitted parameter#{'s' if unpermitted_keys.size > 1}: #{unpermitted_keys.map { |e| ":#{e}" }.join(", ")}", RED)
|
57
60
|
end
|
58
61
|
end
|
59
62
|
|
@@ -1,7 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "active_support/core_ext/hash/keys"
|
4
|
-
|
5
3
|
module ActionController
|
6
4
|
module ConditionalGet
|
7
5
|
extend ActiveSupport::Concern
|
@@ -230,12 +228,20 @@ module ActionController
|
|
230
228
|
# This method will overwrite an existing Cache-Control header.
|
231
229
|
# See https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html for more possibilities.
|
232
230
|
#
|
231
|
+
# HTTP Cache-Control Extensions for Stale Content. See https://tools.ietf.org/html/rfc5861
|
232
|
+
# It helps to cache an asset and serve it while is being revalidated and/or returning with an error.
|
233
|
+
#
|
234
|
+
# expires_in 3.hours, public: true, stale_while_revalidate: 60.seconds
|
235
|
+
# expires_in 3.hours, public: true, stale_while_revalidate: 60.seconds, stale_if_error: 5.minutes
|
236
|
+
#
|
233
237
|
# The method will also ensure an HTTP Date header for client compatibility.
|
234
238
|
def expires_in(seconds, options = {})
|
235
239
|
response.cache_control.merge!(
|
236
240
|
max_age: seconds,
|
237
241
|
public: options.delete(:public),
|
238
|
-
must_revalidate: options.delete(:must_revalidate)
|
242
|
+
must_revalidate: options.delete(:must_revalidate),
|
243
|
+
stale_while_revalidate: options.delete(:stale_while_revalidate),
|
244
|
+
stale_if_error: options.delete(:stale_if_error),
|
239
245
|
)
|
240
246
|
options.delete(:private)
|
241
247
|
|
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "action_controller/metal/exceptions"
|
4
|
+
require "action_dispatch/http/content_disposition"
|
4
5
|
|
5
6
|
module ActionController #:nodoc:
|
6
7
|
# Methods for sending arbitrary data and for streaming files to the browser,
|
@@ -10,8 +11,8 @@ module ActionController #:nodoc:
|
|
10
11
|
|
11
12
|
include ActionController::Rendering
|
12
13
|
|
13
|
-
DEFAULT_SEND_FILE_TYPE = "application/octet-stream"
|
14
|
-
DEFAULT_SEND_FILE_DISPOSITION = "attachment"
|
14
|
+
DEFAULT_SEND_FILE_TYPE = "application/octet-stream" #:nodoc:
|
15
|
+
DEFAULT_SEND_FILE_DISPOSITION = "attachment" #:nodoc:
|
15
16
|
|
16
17
|
private
|
17
18
|
# Sends the file. This uses a server-appropriate method (such as X-Sendfile)
|
@@ -132,10 +133,8 @@ module ActionController #:nodoc:
|
|
132
133
|
end
|
133
134
|
|
134
135
|
disposition = options.fetch(:disposition, DEFAULT_SEND_FILE_DISPOSITION)
|
135
|
-
|
136
|
-
|
137
|
-
disposition += %(; filename="#{options[:filename]}") if options[:filename]
|
138
|
-
headers["Content-Disposition"] = disposition
|
136
|
+
if disposition
|
137
|
+
headers["Content-Disposition"] = ActionDispatch::Http::ContentDisposition.format(disposition: disposition, filename: options[:filename])
|
139
138
|
end
|
140
139
|
|
141
140
|
headers["Content-Transfer-Encoding"] = "binary"
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActionController
|
4
|
+
# Allows configuring default headers that will be automatically merged into
|
5
|
+
# each response.
|
6
|
+
module DefaultHeaders
|
7
|
+
extend ActiveSupport::Concern
|
8
|
+
|
9
|
+
module ClassMethods
|
10
|
+
def make_response!(request)
|
11
|
+
ActionDispatch::Response.create.tap do |res|
|
12
|
+
res.request = request
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -22,7 +22,7 @@ module ActionController
|
|
22
22
|
end
|
23
23
|
end
|
24
24
|
|
25
|
-
class
|
25
|
+
class UrlGenerationError < ActionControllerError #:nodoc:
|
26
26
|
end
|
27
27
|
|
28
28
|
class MethodNotAllowed < ActionControllerError #:nodoc:
|
@@ -50,4 +50,25 @@ module ActionController
|
|
50
50
|
|
51
51
|
class UnknownFormat < ActionControllerError #:nodoc:
|
52
52
|
end
|
53
|
+
|
54
|
+
# Raised when a nested respond_to is triggered and the content types of each
|
55
|
+
# are incompatible. For exampe:
|
56
|
+
#
|
57
|
+
# respond_to do |outer_type|
|
58
|
+
# outer_type.js do
|
59
|
+
# respond_to do |inner_type|
|
60
|
+
# inner_type.html { render body: "HTML" }
|
61
|
+
# end
|
62
|
+
# end
|
63
|
+
# end
|
64
|
+
class RespondToMismatchError < ActionControllerError
|
65
|
+
DEFAULT_MESSAGE = "respond_to was called multiple times and matched with conflicting formats in this action. Please note that you may only call respond_to and match on a single format per action."
|
66
|
+
|
67
|
+
def initialize(message = nil)
|
68
|
+
super(message || DEFAULT_MESSAGE)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
class MissingExactTemplate < UnknownFormat #:nodoc:
|
73
|
+
end
|
53
74
|
end
|
@@ -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,64 +4,28 @@ 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
|
|
22
14
|
ACTION_OPTIONS = [:only, :except, :if, :unless]
|
23
15
|
URL_OPTIONS = [:protocol, :host, :domain, :subdomain, :port, :path]
|
24
|
-
REDIRECT_OPTIONS = [:status, :flash, :alert, :notice]
|
16
|
+
REDIRECT_OPTIONS = [:status, :flash, :alert, :notice, :allow_other_host]
|
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,14 @@ 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,
|
44
|
+
allow_other_host: true,
|
85
45
|
}
|
86
46
|
|
87
47
|
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
|
|
@@ -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
|
@@ -406,7 +405,7 @@ module ActionController
|
|
406
405
|
module Token
|
407
406
|
TOKEN_KEY = "token="
|
408
407
|
TOKEN_REGEX = /^(Token|Bearer)\s+/
|
409
|
-
AUTHN_PAIR_DELIMITERS = /(?:,|;|\t)/
|
408
|
+
AUTHN_PAIR_DELIMITERS = /(?:,|;|\t+)/
|
410
409
|
extend self
|
411
410
|
|
412
411
|
module ControllerMethods
|
@@ -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
|
@@ -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
|
|