actionpack 4.2.10 → 5.0.0
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 +553 -401
- data/MIT-LICENSE +1 -1
- data/README.rdoc +2 -3
- data/lib/abstract_controller/base.rb +28 -38
- data/lib/{action_controller → abstract_controller}/caching/fragments.rb +51 -11
- data/lib/abstract_controller/caching.rb +62 -0
- data/lib/abstract_controller/callbacks.rb +52 -19
- data/lib/abstract_controller/collector.rb +4 -9
- data/lib/abstract_controller/error.rb +4 -0
- data/lib/abstract_controller/helpers.rb +4 -3
- data/lib/abstract_controller/railties/routes_helpers.rb +2 -2
- data/lib/abstract_controller/rendering.rb +28 -18
- data/lib/abstract_controller/translation.rb +8 -7
- data/lib/abstract_controller.rb +6 -2
- data/lib/action_controller/api/api_rendering.rb +14 -0
- data/lib/action_controller/api.rb +147 -0
- data/lib/action_controller/base.rb +10 -13
- data/lib/action_controller/caching.rb +13 -58
- data/lib/action_controller/form_builder.rb +48 -0
- data/lib/action_controller/log_subscriber.rb +3 -10
- data/lib/action_controller/metal/basic_implicit_render.rb +11 -0
- data/lib/action_controller/metal/conditional_get.rb +106 -34
- data/lib/action_controller/metal/cookies.rb +1 -3
- data/lib/action_controller/metal/data_streaming.rb +11 -32
- data/lib/action_controller/metal/etag_with_template_digest.rb +1 -1
- data/lib/action_controller/metal/exceptions.rb +11 -6
- data/lib/action_controller/metal/force_ssl.rb +10 -10
- data/lib/action_controller/metal/head.rb +14 -8
- data/lib/action_controller/metal/helpers.rb +15 -6
- data/lib/action_controller/metal/http_authentication.rb +44 -35
- data/lib/action_controller/metal/implicit_render.rb +61 -6
- data/lib/action_controller/metal/instrumentation.rb +5 -5
- data/lib/action_controller/metal/live.rb +66 -88
- data/lib/action_controller/metal/mime_responds.rb +27 -42
- data/lib/action_controller/metal/params_wrapper.rb +8 -8
- data/lib/action_controller/metal/redirecting.rb +32 -9
- data/lib/action_controller/metal/renderers.rb +85 -40
- data/lib/action_controller/metal/rendering.rb +38 -6
- data/lib/action_controller/metal/request_forgery_protection.rb +126 -48
- data/lib/action_controller/metal/rescue.rb +3 -12
- data/lib/action_controller/metal/streaming.rb +4 -4
- data/lib/action_controller/metal/strong_parameters.rb +293 -90
- data/lib/action_controller/metal/testing.rb +1 -12
- data/lib/action_controller/metal/url_for.rb +12 -5
- data/lib/action_controller/metal.rb +88 -63
- data/lib/action_controller/renderer.rb +111 -0
- data/lib/action_controller/template_assertions.rb +9 -0
- data/lib/action_controller/test_case.rb +288 -368
- data/lib/action_controller.rb +12 -9
- data/lib/action_dispatch/http/cache.rb +73 -34
- data/lib/action_dispatch/http/filter_parameters.rb +15 -11
- data/lib/action_dispatch/http/filter_redirect.rb +7 -8
- data/lib/action_dispatch/http/headers.rb +44 -13
- data/lib/action_dispatch/http/mime_negotiation.rb +41 -23
- data/lib/action_dispatch/http/mime_type.rb +126 -90
- data/lib/action_dispatch/http/mime_types.rb +3 -4
- data/lib/action_dispatch/http/parameter_filter.rb +18 -8
- data/lib/action_dispatch/http/parameters.rb +54 -41
- data/lib/action_dispatch/http/request.rb +149 -82
- data/lib/action_dispatch/http/response.rb +206 -102
- data/lib/action_dispatch/http/url.rb +117 -8
- data/lib/action_dispatch/journey/formatter.rb +39 -28
- data/lib/action_dispatch/journey/gtg/transition_table.rb +1 -1
- data/lib/action_dispatch/journey/nfa/dot.rb +0 -2
- data/lib/action_dispatch/journey/nfa/transition_table.rb +1 -46
- data/lib/action_dispatch/journey/nodes/node.rb +14 -4
- data/lib/action_dispatch/journey/parser_extras.rb +4 -0
- data/lib/action_dispatch/journey/path/pattern.rb +38 -42
- data/lib/action_dispatch/journey/route.rb +74 -19
- data/lib/action_dispatch/journey/router/utils.rb +5 -5
- data/lib/action_dispatch/journey/router.rb +5 -9
- data/lib/action_dispatch/journey/routes.rb +14 -15
- data/lib/action_dispatch/journey/visitors.rb +86 -43
- data/lib/action_dispatch/middleware/callbacks.rb +10 -1
- data/lib/action_dispatch/middleware/cookies.rb +189 -135
- data/lib/action_dispatch/middleware/debug_exceptions.rb +124 -49
- data/lib/action_dispatch/middleware/exception_wrapper.rb +21 -21
- data/lib/action_dispatch/middleware/executor.rb +19 -0
- data/lib/action_dispatch/middleware/flash.rb +66 -45
- data/lib/action_dispatch/middleware/params_parser.rb +32 -46
- data/lib/action_dispatch/middleware/public_exceptions.rb +2 -2
- data/lib/action_dispatch/middleware/reloader.rb +14 -58
- data/lib/action_dispatch/middleware/remote_ip.rb +29 -19
- data/lib/action_dispatch/middleware/request_id.rb +11 -6
- data/lib/action_dispatch/middleware/session/abstract_store.rb +23 -11
- data/lib/action_dispatch/middleware/session/cache_store.rb +9 -6
- data/lib/action_dispatch/middleware/session/cookie_store.rb +30 -24
- data/lib/action_dispatch/middleware/session/mem_cache_store.rb +4 -0
- data/lib/action_dispatch/middleware/show_exceptions.rb +11 -9
- data/lib/action_dispatch/middleware/ssl.rb +115 -36
- data/lib/action_dispatch/middleware/stack.rb +44 -40
- data/lib/action_dispatch/middleware/static.rb +51 -35
- data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb +2 -14
- data/lib/action_dispatch/middleware/templates/rescues/_source.text.erb +8 -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 +59 -63
- data/lib/action_dispatch/railtie.rb +2 -2
- data/lib/action_dispatch/request/session.rb +69 -33
- data/lib/action_dispatch/request/utils.rb +51 -19
- data/lib/action_dispatch/routing/inspector.rb +32 -43
- data/lib/action_dispatch/routing/mapper.rb +491 -338
- data/lib/action_dispatch/routing/polymorphic_routes.rb +8 -14
- data/lib/action_dispatch/routing/redirection.rb +3 -3
- data/lib/action_dispatch/routing/route_set.rb +145 -238
- data/lib/action_dispatch/routing/url_for.rb +27 -10
- data/lib/action_dispatch/routing.rb +17 -13
- data/lib/action_dispatch/testing/assertion_response.rb +45 -0
- data/lib/action_dispatch/testing/assertions/response.rb +38 -20
- data/lib/action_dispatch/testing/assertions/routing.rb +11 -10
- data/lib/action_dispatch/testing/assertions.rb +1 -1
- data/lib/action_dispatch/testing/integration.rb +368 -97
- data/lib/action_dispatch/testing/test_process.rb +5 -6
- data/lib/action_dispatch/testing/test_request.rb +22 -31
- data/lib/action_dispatch/testing/test_response.rb +7 -4
- data/lib/action_dispatch.rb +3 -1
- data/lib/action_pack/gem_version.rb +3 -3
- data/lib/action_pack.rb +1 -1
- metadata +30 -34
- 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/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
- /data/lib/action_dispatch/middleware/templates/rescues/{_source.erb → _source.html.erb} +0 -0
@@ -25,14 +25,13 @@ module ActionController #:nodoc:
|
|
25
25
|
# * <tt>:filename</tt> - suggests a filename for the browser to use.
|
26
26
|
# Defaults to <tt>File.basename(path)</tt>.
|
27
27
|
# * <tt>:type</tt> - specifies an HTTP content type.
|
28
|
-
# You can specify either a string or a symbol for a registered type register
|
29
|
-
# <tt
|
30
|
-
# If
|
31
|
-
# If no content type is registered for the extension, default type 'application/octet-stream' will be used.
|
28
|
+
# You can specify either a string or a symbol for a registered type with <tt>Mime::Type.register</tt>, for example :json.
|
29
|
+
# If omitted, the type will be inferred from the file extension specified in <tt>:filename</tt>.
|
30
|
+
# If no content type is registered for the extension, the default type 'application/octet-stream' will be used.
|
32
31
|
# * <tt>:disposition</tt> - specifies whether the file will be shown inline or downloaded.
|
33
32
|
# Valid values are 'inline' and 'attachment' (default).
|
34
33
|
# * <tt>:status</tt> - specifies the status code to send with the response. Defaults to 200.
|
35
|
-
# * <tt>:url_based_filename</tt> - set to +true+ if you want the browser guess the filename from
|
34
|
+
# * <tt>:url_based_filename</tt> - set to +true+ if you want the browser to guess the filename from
|
36
35
|
# the URL, which is necessary for i18n filenames on certain browsers
|
37
36
|
# (setting <tt>:filename</tt> overrides this option).
|
38
37
|
#
|
@@ -72,41 +71,21 @@ module ActionController #:nodoc:
|
|
72
71
|
|
73
72
|
self.status = options[:status] || 200
|
74
73
|
self.content_type = options[:content_type] if options.key?(:content_type)
|
75
|
-
|
76
|
-
end
|
77
|
-
|
78
|
-
# Avoid having to pass an open file handle as the response body.
|
79
|
-
# Rack::Sendfile will usually intercept the response and uses
|
80
|
-
# the path directly, so there is no reason to open the file.
|
81
|
-
class FileBody #:nodoc:
|
82
|
-
attr_reader :to_path
|
83
|
-
|
84
|
-
def initialize(path)
|
85
|
-
@to_path = path
|
86
|
-
end
|
87
|
-
|
88
|
-
# Stream the file's contents if Rack::Sendfile isn't present.
|
89
|
-
def each
|
90
|
-
File.open(to_path, 'rb') do |file|
|
91
|
-
while chunk = file.read(16384)
|
92
|
-
yield chunk
|
93
|
-
end
|
94
|
-
end
|
95
|
-
end
|
74
|
+
response.send_file path
|
96
75
|
end
|
97
76
|
|
98
77
|
# Sends the given binary data to the browser. This method is similar to
|
99
78
|
# <tt>render plain: data</tt>, but also allows you to specify whether
|
100
79
|
# the browser should display the response as a file attachment (i.e. in a
|
101
80
|
# download dialog) or as inline data. You may also set the content type,
|
102
|
-
# the
|
81
|
+
# the file name, and other things.
|
103
82
|
#
|
104
83
|
# Options:
|
105
84
|
# * <tt>:filename</tt> - suggests a filename for the browser to use.
|
106
|
-
# * <tt>:type</tt> - specifies an HTTP content type. Defaults to 'application/octet-stream'.
|
107
|
-
# either a string or a symbol for a registered type
|
108
|
-
# If omitted, type will be
|
109
|
-
# If no content type is registered for the extension, default type 'application/octet-stream' will be used.
|
85
|
+
# * <tt>:type</tt> - specifies an HTTP content type. Defaults to 'application/octet-stream'.
|
86
|
+
# You can specify either a string or a symbol for a registered type with <tt>Mime::Type.register</tt>, for example :json.
|
87
|
+
# If omitted, type will be inferred from the file extension specified in <tt>:filename</tt>.
|
88
|
+
# If no content type is registered for the extension, the default type 'application/octet-stream' will be used.
|
110
89
|
# * <tt>:disposition</tt> - specifies whether the file will be shown inline or downloaded.
|
111
90
|
# Valid values are 'inline' and 'attachment' (default).
|
112
91
|
# * <tt>:status</tt> - specifies the status code to send with the response. Defaults to 200.
|
@@ -126,7 +105,7 @@ module ActionController #:nodoc:
|
|
126
105
|
# See +send_file+ for more information on HTTP Content-* headers and caching.
|
127
106
|
def send_data(data, options = {}) #:doc:
|
128
107
|
send_file_headers! options
|
129
|
-
render options.slice(:status, :content_type).merge(:
|
108
|
+
render options.slice(:status, :content_type).merge(body: data)
|
130
109
|
end
|
131
110
|
|
132
111
|
private
|
@@ -25,7 +25,7 @@ module ActionController
|
|
25
25
|
class_attribute :etag_with_template_digest
|
26
26
|
self.etag_with_template_digest = true
|
27
27
|
|
28
|
-
ActiveSupport.on_load :action_view, yield: true do
|
28
|
+
ActiveSupport.on_load :action_view, yield: true do
|
29
29
|
etag do |options|
|
30
30
|
determine_template_etag(options) if etag_with_template_digest
|
31
31
|
end
|
@@ -3,14 +3,19 @@ module ActionController
|
|
3
3
|
end
|
4
4
|
|
5
5
|
class BadRequest < ActionControllerError #:nodoc:
|
6
|
-
|
6
|
+
def initialize(msg = nil, e = nil)
|
7
|
+
if e
|
8
|
+
ActiveSupport::Deprecation.warn("Passing #original_exception is deprecated and has no effect. " \
|
9
|
+
"Exceptions will automatically capture the original exception.", caller)
|
10
|
+
end
|
7
11
|
|
8
|
-
|
9
|
-
|
12
|
+
super(msg)
|
13
|
+
set_backtrace $!.backtrace if $!
|
14
|
+
end
|
10
15
|
|
11
|
-
|
12
|
-
|
13
|
-
|
16
|
+
def original_exception
|
17
|
+
ActiveSupport::Deprecation.warn("#original_exception is deprecated. Use #cause instead.", caller)
|
18
|
+
cause
|
14
19
|
end
|
15
20
|
end
|
16
21
|
|
@@ -2,17 +2,17 @@ require 'active_support/core_ext/hash/except'
|
|
2
2
|
require 'active_support/core_ext/hash/slice'
|
3
3
|
|
4
4
|
module ActionController
|
5
|
-
# This module provides a method which will redirect browser to use HTTPS
|
5
|
+
# This module provides a method which will redirect the browser to use HTTPS
|
6
6
|
# protocol. This will ensure that user's sensitive information will be
|
7
|
-
# transferred safely over the internet. You _should_ always force browser
|
7
|
+
# transferred safely over the internet. You _should_ always force the browser
|
8
8
|
# to use HTTPS when you're transferring sensitive information such as
|
9
9
|
# user authentication, account information, or credit card information.
|
10
10
|
#
|
11
11
|
# Note that if you are really concerned about your application security,
|
12
12
|
# you might consider using +config.force_ssl+ in your config file instead.
|
13
13
|
# That will ensure all the data transferred via HTTPS protocol and prevent
|
14
|
-
# user from getting session hijacked when accessing the site
|
15
|
-
# HTTP protocol.
|
14
|
+
# the user from getting their session hijacked when accessing the site over
|
15
|
+
# unsecured HTTP protocol.
|
16
16
|
module ForceSSL
|
17
17
|
extend ActiveSupport::Concern
|
18
18
|
include AbstractController::Callbacks
|
@@ -55,10 +55,10 @@ module ActionController
|
|
55
55
|
# You can pass any of the following options to affect the before_action callback
|
56
56
|
# * <tt>only</tt> - The callback should be run only for this action
|
57
57
|
# * <tt>except</tt> - The callback should be run for all actions except this action
|
58
|
-
# * <tt>if</tt> - A symbol naming an instance method or a proc; the
|
59
|
-
#
|
60
|
-
# * <tt>unless</tt> - A symbol naming an instance method or a proc; the
|
61
|
-
#
|
58
|
+
# * <tt>if</tt> - A symbol naming an instance method or a proc; the
|
59
|
+
# callback will be called only when it returns a true value.
|
60
|
+
# * <tt>unless</tt> - A symbol naming an instance method or a proc; the
|
61
|
+
# callback will be called only when it returns a false value.
|
62
62
|
def force_ssl(options = {})
|
63
63
|
action_options = options.slice(*ACTION_OPTIONS)
|
64
64
|
redirect_options = options.except(*ACTION_OPTIONS)
|
@@ -71,8 +71,8 @@ module ActionController
|
|
71
71
|
# Redirect the existing request to use the HTTPS protocol.
|
72
72
|
#
|
73
73
|
# ==== Parameters
|
74
|
-
# * <tt>host_or_options</tt> - Either a host name or any of the url &
|
75
|
-
#
|
74
|
+
# * <tt>host_or_options</tt> - Either a host name or any of the url &
|
75
|
+
# redirect options available to the <tt>force_ssl</tt> method.
|
76
76
|
def force_ssl_redirect(host_or_options = nil)
|
77
77
|
unless request.ssl?
|
78
78
|
options = {
|
@@ -17,8 +17,18 @@ module ActionController
|
|
17
17
|
#
|
18
18
|
# See Rack::Utils::SYMBOL_TO_STATUS_CODE for a full list of valid +status+ symbols.
|
19
19
|
def head(status, options = {})
|
20
|
-
|
21
|
-
|
20
|
+
if status.is_a?(Hash)
|
21
|
+
msg = status[:status] ? 'The :status option' : 'The implicit :ok status'
|
22
|
+
options, status = status, status.delete(:status)
|
23
|
+
|
24
|
+
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
25
|
+
#{msg} on `head` has been deprecated and will be removed in Rails 5.1.
|
26
|
+
Please pass the status as a separate parameter before the options, instead.
|
27
|
+
MSG
|
28
|
+
end
|
29
|
+
|
30
|
+
status ||= :ok
|
31
|
+
|
22
32
|
location = options.delete(:location)
|
23
33
|
content_type = options.delete(:content_type)
|
24
34
|
|
@@ -33,17 +43,13 @@ module ActionController
|
|
33
43
|
|
34
44
|
if include_content?(self.response_code)
|
35
45
|
self.content_type = content_type || (Mime[formats.first] if formats)
|
36
|
-
self.response.charset = false
|
37
|
-
else
|
38
|
-
headers.delete('Content-Type')
|
39
|
-
headers.delete('Content-Length')
|
46
|
+
self.response.charset = false
|
40
47
|
end
|
41
|
-
|
48
|
+
|
42
49
|
true
|
43
50
|
end
|
44
51
|
|
45
52
|
private
|
46
|
-
# :nodoc:
|
47
53
|
def include_content?(status)
|
48
54
|
case status
|
49
55
|
when 100..199
|
@@ -5,10 +5,10 @@ module ActionController
|
|
5
5
|
#
|
6
6
|
# In addition to using the standard template helpers provided, creating custom helpers to
|
7
7
|
# extract complicated logic or reusable functionality is strongly encouraged. By default, each controller
|
8
|
-
# will include all helpers. These helpers are only accessible on the controller through <tt
|
8
|
+
# will include all helpers. These helpers are only accessible on the controller through <tt>#helpers</tt>
|
9
9
|
#
|
10
|
-
# In previous versions of \Rails the controller will include a helper
|
11
|
-
#
|
10
|
+
# In previous versions of \Rails the controller will include a helper which
|
11
|
+
# matches the name of the controller, e.g., <tt>MyController</tt> will automatically
|
12
12
|
# include <tt>MyHelper</tt>. To return old behavior set +config.action_controller.include_all_helpers+ to +false+.
|
13
13
|
#
|
14
14
|
# Additional helpers can be specified using the +helper+ class method in ActionController::Base or any
|
@@ -44,7 +44,7 @@ module ActionController
|
|
44
44
|
# the output might look like this:
|
45
45
|
#
|
46
46
|
# 23 Aug 11:30 | Carolina Railhawks Soccer Match
|
47
|
-
# N/A | Carolina
|
47
|
+
# N/A | Carolina Railhawks Training Workshop
|
48
48
|
#
|
49
49
|
module Helpers
|
50
50
|
extend ActiveSupport::Concern
|
@@ -73,7 +73,7 @@ module ActionController
|
|
73
73
|
|
74
74
|
# Provides a proxy to access helpers methods from outside the view.
|
75
75
|
def helpers
|
76
|
-
@helper_proxy ||= begin
|
76
|
+
@helper_proxy ||= begin
|
77
77
|
proxy = ActionView::Base.new
|
78
78
|
proxy.config = config.inheritable_copy
|
79
79
|
proxy.extend(_helpers)
|
@@ -93,10 +93,14 @@ module ActionController
|
|
93
93
|
super(args)
|
94
94
|
end
|
95
95
|
|
96
|
+
# Returns a list of helper names in a given path.
|
97
|
+
#
|
98
|
+
# ActionController::Base.all_helpers_from_path 'app/helpers'
|
99
|
+
# # => ["application", "chart", "rubygems"]
|
96
100
|
def all_helpers_from_path(path)
|
97
101
|
helpers = Array(path).flat_map do |_path|
|
98
102
|
extract = /^#{Regexp.quote(_path.to_s)}\/?(.*)_helper.rb$/
|
99
|
-
names = Dir["#{_path}/**/*_helper.rb"].map { |file| file.sub(extract, '\1') }
|
103
|
+
names = Dir["#{_path}/**/*_helper.rb"].map { |file| file.sub(extract, '\1'.freeze) }
|
100
104
|
names.sort!
|
101
105
|
end
|
102
106
|
helpers.uniq!
|
@@ -109,5 +113,10 @@ module ActionController
|
|
109
113
|
all_helpers_from_path(helpers_path)
|
110
114
|
end
|
111
115
|
end
|
116
|
+
|
117
|
+
# Provides a proxy to access helpers methods from outside the view.
|
118
|
+
def helpers
|
119
|
+
@_helper_proxy ||= view_context
|
120
|
+
end
|
112
121
|
end
|
113
122
|
end
|
@@ -35,7 +35,7 @@ module ActionController
|
|
35
35
|
#
|
36
36
|
# def authenticate
|
37
37
|
# case request.format
|
38
|
-
# when Mime
|
38
|
+
# when Mime[:xml], Mime[:atom]
|
39
39
|
# if user = authenticate_with_http_basic { |u, p| @account.users.authenticate(u, p) }
|
40
40
|
# @current_user = user
|
41
41
|
# else
|
@@ -79,16 +79,16 @@ module ActionController
|
|
79
79
|
end
|
80
80
|
end
|
81
81
|
|
82
|
-
def authenticate_or_request_with_http_basic(realm = "Application", &login_procedure)
|
83
|
-
authenticate_with_http_basic(&login_procedure) || request_http_basic_authentication(realm)
|
82
|
+
def authenticate_or_request_with_http_basic(realm = "Application", message = nil, &login_procedure)
|
83
|
+
authenticate_with_http_basic(&login_procedure) || request_http_basic_authentication(realm, message)
|
84
84
|
end
|
85
85
|
|
86
86
|
def authenticate_with_http_basic(&login_procedure)
|
87
87
|
HttpAuthentication::Basic.authenticate(request, &login_procedure)
|
88
88
|
end
|
89
89
|
|
90
|
-
def request_http_basic_authentication(realm = "Application")
|
91
|
-
HttpAuthentication::Basic.authentication_request(self, realm)
|
90
|
+
def request_http_basic_authentication(realm = "Application", message = nil)
|
91
|
+
HttpAuthentication::Basic.authentication_request(self, realm, message)
|
92
92
|
end
|
93
93
|
end
|
94
94
|
|
@@ -99,7 +99,7 @@ module ActionController
|
|
99
99
|
end
|
100
100
|
|
101
101
|
def has_basic_credentials?(request)
|
102
|
-
request.authorization.present? && (auth_scheme(request) == '
|
102
|
+
request.authorization.present? && (auth_scheme(request).downcase == 'basic')
|
103
103
|
end
|
104
104
|
|
105
105
|
def user_name_and_password(request)
|
@@ -111,21 +111,22 @@ module ActionController
|
|
111
111
|
end
|
112
112
|
|
113
113
|
def auth_scheme(request)
|
114
|
-
request.authorization.split(' ', 2).first
|
114
|
+
request.authorization.to_s.split(' ', 2).first
|
115
115
|
end
|
116
116
|
|
117
117
|
def auth_param(request)
|
118
|
-
request.authorization.split(' ', 2).second
|
118
|
+
request.authorization.to_s.split(' ', 2).second
|
119
119
|
end
|
120
120
|
|
121
121
|
def encode_credentials(user_name, password)
|
122
122
|
"Basic #{::Base64.strict_encode64("#{user_name}:#{password}")}"
|
123
123
|
end
|
124
124
|
|
125
|
-
def authentication_request(controller, realm)
|
126
|
-
|
125
|
+
def authentication_request(controller, realm, message)
|
126
|
+
message ||= "HTTP Basic: Access denied.\n"
|
127
|
+
controller.headers["WWW-Authenticate"] = %(Basic realm="#{realm.tr('"'.freeze, "".freeze)}")
|
127
128
|
controller.status = 401
|
128
|
-
controller.response_body =
|
129
|
+
controller.response_body = message
|
129
130
|
end
|
130
131
|
end
|
131
132
|
|
@@ -175,8 +176,8 @@ module ActionController
|
|
175
176
|
extend self
|
176
177
|
|
177
178
|
module ControllerMethods
|
178
|
-
def authenticate_or_request_with_http_digest(realm = "Application", &password_procedure)
|
179
|
-
authenticate_with_http_digest(realm, &password_procedure) || request_http_digest_authentication(realm)
|
179
|
+
def authenticate_or_request_with_http_digest(realm = "Application", message = nil, &password_procedure)
|
180
|
+
authenticate_with_http_digest(realm, &password_procedure) || request_http_digest_authentication(realm, message)
|
180
181
|
end
|
181
182
|
|
182
183
|
# Authenticate with HTTP Digest, returns true or false
|
@@ -207,7 +208,7 @@ module ActionController
|
|
207
208
|
password = password_procedure.call(credentials[:username])
|
208
209
|
return false unless password
|
209
210
|
|
210
|
-
method = request.
|
211
|
+
method = request.get_header('rack.methodoverride.original_method') || request.get_header('REQUEST_METHOD')
|
211
212
|
uri = credentials[:uri]
|
212
213
|
|
213
214
|
[true, false].any? do |trailing_question_mark|
|
@@ -264,8 +265,8 @@ module ActionController
|
|
264
265
|
end
|
265
266
|
|
266
267
|
def secret_token(request)
|
267
|
-
key_generator = request.
|
268
|
-
http_auth_salt = request.
|
268
|
+
key_generator = request.key_generator
|
269
|
+
http_auth_salt = request.http_auth_salt
|
269
270
|
key_generator.generate_key(http_auth_salt)
|
270
271
|
end
|
271
272
|
|
@@ -309,9 +310,9 @@ module ActionController
|
|
309
310
|
end
|
310
311
|
|
311
312
|
# Might want a shorter timeout depending on whether the request
|
312
|
-
# is a PATCH, PUT, or POST, and if client is browser or web service.
|
313
|
+
# is a PATCH, PUT, or POST, and if the client is a browser or web service.
|
313
314
|
# Can be much shorter if the Stale directive is implemented. This would
|
314
|
-
# allow a user to use new nonce without prompting user again for their
|
315
|
+
# allow a user to use new nonce without prompting the user again for their
|
315
316
|
# username and password.
|
316
317
|
def validate_nonce(secret_key, request, value, seconds_to_timeout=5*60)
|
317
318
|
return false if value.nil?
|
@@ -319,7 +320,7 @@ module ActionController
|
|
319
320
|
nonce(secret_key, t) == value && (t - Time.now.to_i).abs <= seconds_to_timeout
|
320
321
|
end
|
321
322
|
|
322
|
-
# Opaque based on
|
323
|
+
# Opaque based on digest of secret key
|
323
324
|
def opaque(secret_key)
|
324
325
|
::Digest::MD5.hexdigest(secret_key)
|
325
326
|
end
|
@@ -346,7 +347,12 @@ module ActionController
|
|
346
347
|
# private
|
347
348
|
# def authenticate
|
348
349
|
# authenticate_or_request_with_http_token do |token, options|
|
349
|
-
#
|
350
|
+
# # Compare the tokens in a time-constant manner, to mitigate
|
351
|
+
# # timing attacks.
|
352
|
+
# ActiveSupport::SecurityUtils.secure_compare(
|
353
|
+
# ::Digest::SHA256.hexdigest(token),
|
354
|
+
# ::Digest::SHA256.hexdigest(TOKEN)
|
355
|
+
# )
|
350
356
|
# end
|
351
357
|
# end
|
352
358
|
# end
|
@@ -365,7 +371,7 @@ module ActionController
|
|
365
371
|
#
|
366
372
|
# def authenticate
|
367
373
|
# case request.format
|
368
|
-
# when Mime
|
374
|
+
# when Mime[:xml], Mime[:atom]
|
369
375
|
# if user = authenticate_with_http_token { |t, o| @account.users.authenticate(t, o) }
|
370
376
|
# @current_user = user
|
371
377
|
# else
|
@@ -401,21 +407,21 @@ module ActionController
|
|
401
407
|
# RewriteRule ^(.*)$ dispatch.fcgi [E=X-HTTP_AUTHORIZATION:%{HTTP:Authorization},QSA,L]
|
402
408
|
module Token
|
403
409
|
TOKEN_KEY = 'token='
|
404
|
-
TOKEN_REGEX = /^Token
|
410
|
+
TOKEN_REGEX = /^(Token|Bearer)\s+/
|
405
411
|
AUTHN_PAIR_DELIMITERS = /(?:,|;|\t+)/
|
406
412
|
extend self
|
407
413
|
|
408
414
|
module ControllerMethods
|
409
|
-
def authenticate_or_request_with_http_token(realm = "Application", &login_procedure)
|
410
|
-
authenticate_with_http_token(&login_procedure) || request_http_token_authentication(realm)
|
415
|
+
def authenticate_or_request_with_http_token(realm = "Application", message = nil, &login_procedure)
|
416
|
+
authenticate_with_http_token(&login_procedure) || request_http_token_authentication(realm, message)
|
411
417
|
end
|
412
418
|
|
413
419
|
def authenticate_with_http_token(&login_procedure)
|
414
420
|
Token.authenticate(self, &login_procedure)
|
415
421
|
end
|
416
422
|
|
417
|
-
def request_http_token_authentication(realm = "Application")
|
418
|
-
Token.authentication_request(self, realm)
|
423
|
+
def request_http_token_authentication(realm = "Application", message = nil)
|
424
|
+
Token.authentication_request(self, realm, message)
|
419
425
|
end
|
420
426
|
end
|
421
427
|
|
@@ -440,15 +446,17 @@ module ActionController
|
|
440
446
|
end
|
441
447
|
end
|
442
448
|
|
443
|
-
# Parses the token and options out of the token authorization header.
|
444
|
-
# the header
|
449
|
+
# Parses the token and options out of the token authorization header.
|
450
|
+
# The value for the Authorization header is expected to have the prefix
|
451
|
+
# <tt>"Token"</tt> or <tt>"Bearer"</tt>. If the header looks like this:
|
445
452
|
# Authorization: Token token="abc", nonce="def"
|
446
|
-
# Then the returned token is "abc"
|
453
|
+
# Then the returned token is <tt>"abc"</tt>, and the options are
|
454
|
+
# <tt>{nonce: "def"}</tt>
|
447
455
|
#
|
448
456
|
# request - ActionDispatch::Request instance with the current headers.
|
449
457
|
#
|
450
|
-
# Returns an Array of [String, Hash] if a token is present.
|
451
|
-
# Returns nil if no token is found.
|
458
|
+
# Returns an +Array+ of <tt>[String, Hash]</tt> if a token is present.
|
459
|
+
# Returns +nil+ if no token is found.
|
452
460
|
def token_and_options(request)
|
453
461
|
authorization_request = request.authorization.to_s
|
454
462
|
if authorization_request[TOKEN_REGEX]
|
@@ -497,15 +505,16 @@ module ActionController
|
|
497
505
|
"Token #{values * ", "}"
|
498
506
|
end
|
499
507
|
|
500
|
-
# Sets a WWW-Authenticate to let the client know a token is desired.
|
508
|
+
# Sets a WWW-Authenticate header to let the client know a token is desired.
|
501
509
|
#
|
502
510
|
# controller - ActionController::Base instance for the outgoing response.
|
503
511
|
# realm - String realm to use in the header.
|
504
512
|
#
|
505
513
|
# Returns nothing.
|
506
|
-
def authentication_request(controller, realm)
|
507
|
-
|
508
|
-
controller.
|
514
|
+
def authentication_request(controller, realm, message = nil)
|
515
|
+
message ||= "HTTP Token: Access denied.\n"
|
516
|
+
controller.headers["WWW-Authenticate"] = %(Token realm="#{realm.tr('"'.freeze, "".freeze)}")
|
517
|
+
controller.__send__ :render, plain: message, status: :unauthorized
|
509
518
|
end
|
510
519
|
end
|
511
520
|
end
|
@@ -1,13 +1,63 @@
|
|
1
|
+
require 'active_support/core_ext/string/strip'
|
2
|
+
|
1
3
|
module ActionController
|
4
|
+
# Handles implicit rendering for a controller action that does not
|
5
|
+
# explicitly respond with +render+, +respond_to+, +redirect+, or +head+.
|
6
|
+
#
|
7
|
+
# For API controllers, the implicit response is always 204 No Content.
|
8
|
+
#
|
9
|
+
# For all other controllers, we use these heuristics to decide whether to
|
10
|
+
# render a template, raise an error for a missing template, or respond with
|
11
|
+
# 204 No Content:
|
12
|
+
#
|
13
|
+
# First, if we DO find a template, it's rendered. Template lookup accounts
|
14
|
+
# for the action name, locales, format, variant, template handlers, and more
|
15
|
+
# (see +render+ for details).
|
16
|
+
#
|
17
|
+
# Second, if we DON'T find a template but the controller action does have
|
18
|
+
# templates for other formats, variants, etc., then we trust that you meant
|
19
|
+
# to provide a template for this response, too, and we raise
|
20
|
+
# <tt>ActionController::UnknownFormat</tt> with an explanation.
|
21
|
+
#
|
22
|
+
# Third, if we DON'T find a template AND the request is a page load in a web
|
23
|
+
# browser (technically, a non-XHR GET request for an HTML response) where
|
24
|
+
# you reasonably expect to have rendered a template, then we raise
|
25
|
+
# <tt>ActionView::UnknownFormat</tt> with an explanation.
|
26
|
+
#
|
27
|
+
# Finally, if we DON'T find a template AND the request isn't a browser page
|
28
|
+
# load, then we implicitly respond with 204 No Content.
|
2
29
|
module ImplicitRender
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
ret
|
7
|
-
end
|
30
|
+
|
31
|
+
# :stopdoc:
|
32
|
+
include BasicImplicitRender
|
8
33
|
|
9
34
|
def default_render(*args)
|
10
|
-
|
35
|
+
if template_exists?(action_name.to_s, _prefixes, variants: request.variant)
|
36
|
+
render(*args)
|
37
|
+
elsif any_templates?(action_name.to_s, _prefixes)
|
38
|
+
message = "#{self.class.name}\##{action_name} is missing a template " \
|
39
|
+
"for this request format and variant.\n" \
|
40
|
+
"\nrequest.formats: #{request.formats.map(&:to_s).inspect}" \
|
41
|
+
"\nrequest.variant: #{request.variant.inspect}"
|
42
|
+
|
43
|
+
raise ActionController::UnknownFormat, message
|
44
|
+
elsif interactive_browser_request?
|
45
|
+
message = "#{self.class.name}\##{action_name} is missing a template " \
|
46
|
+
"for this request format and variant.\n\n" \
|
47
|
+
"request.formats: #{request.formats.map(&:to_s).inspect}\n" \
|
48
|
+
"request.variant: #{request.variant.inspect}\n\n" \
|
49
|
+
"NOTE! For XHR/Ajax or API requests, this action would normally " \
|
50
|
+
"respond with 204 No Content: an empty white screen. Since you're " \
|
51
|
+
"loading it in a web browser, we assume that you expected to " \
|
52
|
+
"actually render a template, not… nothing, so we're showing an " \
|
53
|
+
"error to be extra-clear. If you expect 204 No Content, carry on. " \
|
54
|
+
"That's what you'll get from an XHR or API request. Give it a shot."
|
55
|
+
|
56
|
+
raise ActionController::UnknownFormat, message
|
57
|
+
else
|
58
|
+
logger.info "No template found for #{self.class.name}\##{action_name}, rendering head :no_content" if logger
|
59
|
+
super
|
60
|
+
end
|
11
61
|
end
|
12
62
|
|
13
63
|
def method_for_action(action_name)
|
@@ -15,5 +65,10 @@ module ActionController
|
|
15
65
|
"default_render"
|
16
66
|
end
|
17
67
|
end
|
68
|
+
|
69
|
+
private
|
70
|
+
def interactive_browser_request?
|
71
|
+
request.get? && request.format == Mime[:html] && !request.xhr?
|
72
|
+
end
|
18
73
|
end
|
19
74
|
end
|
@@ -11,7 +11,6 @@ module ActionController
|
|
11
11
|
extend ActiveSupport::Concern
|
12
12
|
|
13
13
|
include AbstractController::Logger
|
14
|
-
include ActionController::RackDelegation
|
15
14
|
|
16
15
|
attr_internal :view_runtime
|
17
16
|
|
@@ -20,9 +19,10 @@ module ActionController
|
|
20
19
|
:controller => self.class.name,
|
21
20
|
:action => self.action_name,
|
22
21
|
:params => request.filtered_parameters,
|
23
|
-
:
|
22
|
+
:headers => request.headers,
|
23
|
+
:format => request.format.ref,
|
24
24
|
:method => request.request_method,
|
25
|
-
:path =>
|
25
|
+
:path => request.fullpath
|
26
26
|
}
|
27
27
|
|
28
28
|
ActiveSupport::Notifications.instrument("start_processing.action_controller", raw_payload.dup)
|
@@ -75,8 +75,8 @@ module ActionController
|
|
75
75
|
ActiveSupport::Notifications.instrument("halted_callback.action_controller", :filter => filter)
|
76
76
|
end
|
77
77
|
|
78
|
-
# A hook which allows you to clean up any time taken into account in
|
79
|
-
# views
|
78
|
+
# A hook which allows you to clean up any time, wrongly taken into account in
|
79
|
+
# views, like database querying time.
|
80
80
|
#
|
81
81
|
# def cleanup_view_runtime
|
82
82
|
# super - time_taken_in_something_expensive
|