actionpack 4.2.11.3 → 5.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 +5 -5
- data/CHANGELOG.md +379 -462
- data/MIT-LICENSE +1 -1
- data/README.rdoc +2 -3
- data/lib/abstract_controller.rb +0 -2
- data/lib/abstract_controller/base.rb +17 -32
- data/lib/abstract_controller/callbacks.rb +52 -19
- data/lib/abstract_controller/collector.rb +4 -9
- data/lib/abstract_controller/helpers.rb +2 -2
- data/lib/abstract_controller/railties/routes_helpers.rb +2 -2
- data/lib/abstract_controller/rendering.rb +27 -22
- data/lib/abstract_controller/translation.rb +8 -7
- data/lib/action_controller.rb +4 -3
- data/lib/action_controller/api.rb +146 -0
- data/lib/action_controller/base.rb +6 -10
- data/lib/action_controller/caching.rb +1 -3
- data/lib/action_controller/caching/fragments.rb +48 -3
- data/lib/action_controller/form_builder.rb +48 -0
- data/lib/action_controller/log_subscriber.rb +1 -10
- data/lib/action_controller/metal.rb +89 -62
- data/lib/action_controller/metal/basic_implicit_render.rb +11 -0
- data/lib/action_controller/metal/conditional_get.rb +65 -24
- data/lib/action_controller/metal/cookies.rb +0 -2
- data/lib/action_controller/metal/data_streaming.rb +2 -22
- 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 +6 -6
- data/lib/action_controller/metal/head.rb +14 -7
- data/lib/action_controller/metal/helpers.rb +9 -5
- data/lib/action_controller/metal/http_authentication.rb +37 -38
- data/lib/action_controller/metal/implicit_render.rb +23 -6
- data/lib/action_controller/metal/instrumentation.rb +0 -1
- data/lib/action_controller/metal/live.rb +17 -55
- data/lib/action_controller/metal/mime_responds.rb +17 -37
- 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 +10 -8
- data/lib/action_controller/metal/rendering.rb +38 -6
- data/lib/action_controller/metal/request_forgery_protection.rb +67 -35
- data/lib/action_controller/metal/rescue.rb +2 -4
- data/lib/action_controller/metal/streaming.rb +4 -4
- data/lib/action_controller/metal/strong_parameters.rb +231 -78
- data/lib/action_controller/metal/testing.rb +1 -12
- data/lib/action_controller/metal/url_for.rb +12 -5
- data/lib/action_controller/renderer.rb +111 -0
- data/lib/action_controller/template_assertions.rb +9 -0
- data/lib/action_controller/test_case.rb +267 -363
- data/lib/action_dispatch.rb +2 -1
- data/lib/action_dispatch/http/cache.rb +23 -26
- data/lib/action_dispatch/http/filter_parameters.rb +6 -8
- data/lib/action_dispatch/http/filter_redirect.rb +7 -8
- data/lib/action_dispatch/http/headers.rb +28 -11
- data/lib/action_dispatch/http/mime_negotiation.rb +40 -26
- data/lib/action_dispatch/http/mime_type.rb +92 -61
- data/lib/action_dispatch/http/mime_types.rb +1 -4
- data/lib/action_dispatch/http/parameter_filter.rb +18 -8
- data/lib/action_dispatch/http/parameters.rb +45 -41
- data/lib/action_dispatch/http/request.rb +146 -82
- data/lib/action_dispatch/http/response.rb +180 -99
- data/lib/action_dispatch/http/url.rb +117 -8
- data/lib/action_dispatch/journey/formatter.rb +34 -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 +37 -41
- data/lib/action_dispatch/journey/route.rb +71 -17
- data/lib/action_dispatch/journey/router.rb +5 -6
- data/lib/action_dispatch/journey/router/utils.rb +5 -5
- data/lib/action_dispatch/journey/routes.rb +14 -15
- data/lib/action_dispatch/journey/visitors.rb +86 -43
- data/lib/action_dispatch/middleware/cookies.rb +184 -135
- data/lib/action_dispatch/middleware/debug_exceptions.rb +115 -45
- data/lib/action_dispatch/middleware/exception_wrapper.rb +21 -20
- data/lib/action_dispatch/middleware/flash.rb +61 -45
- data/lib/action_dispatch/middleware/load_interlock.rb +21 -0
- data/lib/action_dispatch/middleware/params_parser.rb +30 -46
- data/lib/action_dispatch/middleware/public_exceptions.rb +2 -2
- data/lib/action_dispatch/middleware/reloader.rb +2 -4
- 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 +29 -23
- 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 +93 -36
- data/lib/action_dispatch/middleware/stack.rb +43 -48
- data/lib/action_dispatch/middleware/static.rb +52 -40
- data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb +2 -14
- data/lib/action_dispatch/middleware/templates/rescues/{_source.erb → _source.html.erb} +0 -0
- data/lib/action_dispatch/middleware/templates/rescues/_source.text.erb +8 -0
- data/lib/action_dispatch/middleware/templates/rescues/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 +0 -2
- data/lib/action_dispatch/request/session.rb +66 -34
- data/lib/action_dispatch/request/utils.rb +51 -19
- data/lib/action_dispatch/routing.rb +3 -8
- data/lib/action_dispatch/routing/inspector.rb +6 -30
- data/lib/action_dispatch/routing/mapper.rb +447 -322
- 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 +124 -227
- data/lib/action_dispatch/routing/url_for.rb +27 -10
- data/lib/action_dispatch/testing/assertions.rb +1 -1
- data/lib/action_dispatch/testing/assertions/response.rb +27 -9
- data/lib/action_dispatch/testing/assertions/routing.rb +9 -9
- data/lib/action_dispatch/testing/integration.rb +237 -76
- data/lib/action_dispatch/testing/test_process.rb +5 -5
- data/lib/action_dispatch/testing/test_request.rb +12 -21
- data/lib/action_dispatch/testing/test_response.rb +1 -4
- data/lib/action_pack.rb +1 -1
- data/lib/action_pack/gem_version.rb +4 -4
- metadata +26 -25
- 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/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
@@ -4,7 +4,6 @@ module ActionController
|
|
4
4
|
module ConditionalGet
|
5
5
|
extend ActiveSupport::Concern
|
6
6
|
|
7
|
-
include RackDelegation
|
8
7
|
include Head
|
9
8
|
|
10
9
|
included do
|
@@ -15,7 +14,7 @@ module ActionController
|
|
15
14
|
module ClassMethods
|
16
15
|
# Allows you to consider additional controller-wide information when generating an ETag.
|
17
16
|
# For example, if you serve pages tailored depending on who's logged in at the moment, you
|
18
|
-
# may want to add the current user id to be part of the ETag to prevent
|
17
|
+
# may want to add the current user id to be part of the ETag to prevent unauthorized displaying
|
19
18
|
# of cached pages.
|
20
19
|
#
|
21
20
|
# class InvoicesController < ApplicationController
|
@@ -40,7 +39,7 @@ module ActionController
|
|
40
39
|
# * <tt>:etag</tt>.
|
41
40
|
# * <tt>:last_modified</tt>.
|
42
41
|
# * <tt>:public</tt> By default the Cache-Control header is private, set this to
|
43
|
-
# +true+ if you want your application to be
|
42
|
+
# +true+ if you want your application to be cacheable by other devices (proxy caches).
|
44
43
|
# * <tt>:template</tt> By default, the template digest for the current
|
45
44
|
# controller/action is included in ETags. If the action renders a
|
46
45
|
# different template, you can include its digest instead. If the action
|
@@ -51,21 +50,31 @@ module ActionController
|
|
51
50
|
#
|
52
51
|
# def show
|
53
52
|
# @article = Article.find(params[:id])
|
54
|
-
# fresh_when(etag: @article, last_modified: @article.
|
53
|
+
# fresh_when(etag: @article, last_modified: @article.updated_at, public: true)
|
55
54
|
# end
|
56
55
|
#
|
57
56
|
# This will render the show template if the request isn't sending a matching ETag or
|
58
57
|
# If-Modified-Since header and just a <tt>304 Not Modified</tt> response if there's a match.
|
59
58
|
#
|
60
|
-
# You can also just pass a record
|
61
|
-
# +updated_at+ and
|
59
|
+
# You can also just pass a record. In this case +last_modified+ will be set
|
60
|
+
# by calling +updated_at+ and +etag+ by passing the object itself.
|
62
61
|
#
|
63
62
|
# def show
|
64
63
|
# @article = Article.find(params[:id])
|
65
64
|
# fresh_when(@article)
|
66
65
|
# end
|
67
66
|
#
|
68
|
-
#
|
67
|
+
# You can also pass an object that responds to +maximum+, such as a
|
68
|
+
# collection of active records. In this case +last_modified+ will be set by
|
69
|
+
# calling <tt>maximum(:updated_at)</tt> on the collection (the timestamp of the
|
70
|
+
# most recently updated record) and the +etag+ by passing the object itself.
|
71
|
+
#
|
72
|
+
# def index
|
73
|
+
# @articles = Article.all
|
74
|
+
# fresh_when(@articles)
|
75
|
+
# end
|
76
|
+
#
|
77
|
+
# When passing a record or a collection, you can still set the public header:
|
69
78
|
#
|
70
79
|
# def show
|
71
80
|
# @article = Article.find(params[:id])
|
@@ -77,18 +86,16 @@ module ActionController
|
|
77
86
|
#
|
78
87
|
# before_action { fresh_when @article, template: 'widgets/show' }
|
79
88
|
#
|
80
|
-
def fresh_when(
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
options = { etag: record, last_modified: record.try(:updated_at) }.merge!(additional_options)
|
89
|
+
def fresh_when(object = nil, etag: object, last_modified: nil, public: false, template: nil)
|
90
|
+
last_modified ||= object.try(:updated_at) || object.try(:maximum, :updated_at)
|
91
|
+
|
92
|
+
if etag || template
|
93
|
+
response.etag = combine_etags(etag: etag, last_modified: last_modified,
|
94
|
+
public: public, template: template)
|
87
95
|
end
|
88
96
|
|
89
|
-
response.
|
90
|
-
response.
|
91
|
-
response.cache_control[:public] = true if options[:public]
|
97
|
+
response.last_modified = last_modified if last_modified
|
98
|
+
response.cache_control[:public] = true if public
|
92
99
|
|
93
100
|
head :not_modified if request.fresh?(response)
|
94
101
|
end
|
@@ -103,7 +110,7 @@ module ActionController
|
|
103
110
|
# * <tt>:etag</tt>.
|
104
111
|
# * <tt>:last_modified</tt>.
|
105
112
|
# * <tt>:public</tt> By default the Cache-Control header is private, set this to
|
106
|
-
# +true+ if you want your application to be
|
113
|
+
# +true+ if you want your application to be cacheable by other devices (proxy caches).
|
107
114
|
# * <tt>:template</tt> By default, the template digest for the current
|
108
115
|
# controller/action is included in ETags. If the action renders a
|
109
116
|
# different template, you can include its digest instead. If the action
|
@@ -115,7 +122,7 @@ module ActionController
|
|
115
122
|
# def show
|
116
123
|
# @article = Article.find(params[:id])
|
117
124
|
#
|
118
|
-
# if stale?(etag: @article, last_modified: @article.
|
125
|
+
# if stale?(etag: @article, last_modified: @article.updated_at)
|
119
126
|
# @statistics = @article.really_expensive_call
|
120
127
|
# respond_to do |format|
|
121
128
|
# # all the supported formats
|
@@ -123,8 +130,8 @@ module ActionController
|
|
123
130
|
# end
|
124
131
|
# end
|
125
132
|
#
|
126
|
-
# You can also just pass a record
|
127
|
-
# +updated_at+ and
|
133
|
+
# You can also just pass a record. In this case +last_modified+ will be set
|
134
|
+
# by calling +updated_at+ and +etag+ by passing the object itself.
|
128
135
|
#
|
129
136
|
# def show
|
130
137
|
# @article = Article.find(params[:id])
|
@@ -137,7 +144,23 @@ module ActionController
|
|
137
144
|
# end
|
138
145
|
# end
|
139
146
|
#
|
140
|
-
#
|
147
|
+
# You can also pass an object that responds to +maximum+, such as a
|
148
|
+
# collection of active records. In this case +last_modified+ will be set by
|
149
|
+
# calling +maximum(:updated_at)+ on the collection (the timestamp of the
|
150
|
+
# most recently updated record) and the +etag+ by passing the object itself.
|
151
|
+
#
|
152
|
+
# def index
|
153
|
+
# @articles = Article.all
|
154
|
+
#
|
155
|
+
# if stale?(@articles)
|
156
|
+
# @statistics = @articles.really_expensive_call
|
157
|
+
# respond_to do |format|
|
158
|
+
# # all the supported formats
|
159
|
+
# end
|
160
|
+
# end
|
161
|
+
# end
|
162
|
+
#
|
163
|
+
# When passing a record or a collection, you can still set the public header:
|
141
164
|
#
|
142
165
|
# def show
|
143
166
|
# @article = Article.find(params[:id])
|
@@ -157,8 +180,8 @@ module ActionController
|
|
157
180
|
# super if stale? @article, template: 'widgets/show'
|
158
181
|
# end
|
159
182
|
#
|
160
|
-
def stale?(
|
161
|
-
fresh_when(
|
183
|
+
def stale?(object = nil, etag: object, last_modified: nil, public: nil, template: nil)
|
184
|
+
fresh_when(object, etag: etag, last_modified: last_modified, public: public, template: template)
|
162
185
|
!request.fresh?(response)
|
163
186
|
end
|
164
187
|
|
@@ -191,6 +214,24 @@ module ActionController
|
|
191
214
|
response.cache_control.replace(:no_cache => true)
|
192
215
|
end
|
193
216
|
|
217
|
+
# Cache or yield the block. The cache is supposed to never expire.
|
218
|
+
#
|
219
|
+
# You can use this method when you have a HTTP response that never changes,
|
220
|
+
# and the browser and proxies should cache it indefinitely.
|
221
|
+
#
|
222
|
+
# * +public+: By default, HTTP responses are private, cached only on the
|
223
|
+
# user's web browser. To allow proxies to cache the response, set +true+ to
|
224
|
+
# indicate that they can serve the cached response to all users.
|
225
|
+
#
|
226
|
+
# * +version+: the version passed as a key for the cache.
|
227
|
+
def http_cache_forever(public: false, version: 'v1')
|
228
|
+
expires_in 100.years, public: public
|
229
|
+
|
230
|
+
yield if stale?(etag: "#{version}-#{request.fullpath}",
|
231
|
+
last_modified: Time.parse('2011-01-01').utc,
|
232
|
+
public: public)
|
233
|
+
end
|
234
|
+
|
194
235
|
private
|
195
236
|
def combine_etags(options)
|
196
237
|
etags = etaggers.map { |etagger| instance_exec(options, &etagger) }.compact
|
@@ -72,27 +72,7 @@ module ActionController #:nodoc:
|
|
72
72
|
|
73
73
|
self.status = options[:status] || 200
|
74
74
|
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
|
75
|
+
response.send_file path
|
96
76
|
end
|
97
77
|
|
98
78
|
# Sends the given binary data to the browser. This method is similar to
|
@@ -126,7 +106,7 @@ module ActionController #:nodoc:
|
|
126
106
|
# See +send_file+ for more information on HTTP Content-* headers and caching.
|
127
107
|
def send_data(data, options = {}) #:doc:
|
128
108
|
send_file_headers! options
|
129
|
-
render options.slice(:status, :content_type).merge(:
|
109
|
+
render options.slice(:status, :content_type).merge(body: data)
|
130
110
|
end
|
131
111
|
|
132
112
|
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
|
|
@@ -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,12 +43,9 @@ 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
|
|
@@ -7,8 +7,8 @@ module ActionController
|
|
7
7
|
# extract complicated logic or reusable functionality is strongly encouraged. By default, each controller
|
8
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!
|
@@ -1,5 +1,4 @@
|
|
1
1
|
require 'base64'
|
2
|
-
require 'active_support/security_utils'
|
3
2
|
|
4
3
|
module ActionController
|
5
4
|
# Makes it dead easy to do HTTP Basic, Digest and Token authentication.
|
@@ -35,7 +34,7 @@ module ActionController
|
|
35
34
|
#
|
36
35
|
# def authenticate
|
37
36
|
# case request.format
|
38
|
-
# when Mime
|
37
|
+
# when Mime[:xml], Mime[:atom]
|
39
38
|
# if user = authenticate_with_http_basic { |u, p| @account.users.authenticate(u, p) }
|
40
39
|
# @current_user = user
|
41
40
|
# else
|
@@ -69,26 +68,22 @@ module ActionController
|
|
69
68
|
def http_basic_authenticate_with(options = {})
|
70
69
|
before_action(options.except(:name, :password, :realm)) do
|
71
70
|
authenticate_or_request_with_http_basic(options[:realm] || "Application") do |name, password|
|
72
|
-
|
73
|
-
# uses `variable_size_secure_compare` so that length information
|
74
|
-
# isn't leaked.
|
75
|
-
ActiveSupport::SecurityUtils.variable_size_secure_compare(name, options[:name]) &
|
76
|
-
ActiveSupport::SecurityUtils.variable_size_secure_compare(password, options[:password])
|
71
|
+
name == options[:name] && password == options[:password]
|
77
72
|
end
|
78
73
|
end
|
79
74
|
end
|
80
75
|
end
|
81
76
|
|
82
|
-
def authenticate_or_request_with_http_basic(realm = "Application", &login_procedure)
|
83
|
-
authenticate_with_http_basic(&login_procedure) || request_http_basic_authentication(realm)
|
77
|
+
def authenticate_or_request_with_http_basic(realm = "Application", message = nil, &login_procedure)
|
78
|
+
authenticate_with_http_basic(&login_procedure) || request_http_basic_authentication(realm, message)
|
84
79
|
end
|
85
80
|
|
86
81
|
def authenticate_with_http_basic(&login_procedure)
|
87
82
|
HttpAuthentication::Basic.authenticate(request, &login_procedure)
|
88
83
|
end
|
89
84
|
|
90
|
-
def request_http_basic_authentication(realm = "Application")
|
91
|
-
HttpAuthentication::Basic.authentication_request(self, realm)
|
85
|
+
def request_http_basic_authentication(realm = "Application", message = nil)
|
86
|
+
HttpAuthentication::Basic.authentication_request(self, realm, message)
|
92
87
|
end
|
93
88
|
end
|
94
89
|
|
@@ -99,7 +94,7 @@ module ActionController
|
|
99
94
|
end
|
100
95
|
|
101
96
|
def has_basic_credentials?(request)
|
102
|
-
request.authorization.present? && (auth_scheme(request) == '
|
97
|
+
request.authorization.present? && (auth_scheme(request).downcase == 'basic')
|
103
98
|
end
|
104
99
|
|
105
100
|
def user_name_and_password(request)
|
@@ -111,21 +106,22 @@ module ActionController
|
|
111
106
|
end
|
112
107
|
|
113
108
|
def auth_scheme(request)
|
114
|
-
request.authorization.split(' ', 2).first
|
109
|
+
request.authorization.to_s.split(' ', 2).first
|
115
110
|
end
|
116
111
|
|
117
112
|
def auth_param(request)
|
118
|
-
request.authorization.split(' ', 2).second
|
113
|
+
request.authorization.to_s.split(' ', 2).second
|
119
114
|
end
|
120
115
|
|
121
116
|
def encode_credentials(user_name, password)
|
122
117
|
"Basic #{::Base64.strict_encode64("#{user_name}:#{password}")}"
|
123
118
|
end
|
124
119
|
|
125
|
-
def authentication_request(controller, realm)
|
126
|
-
|
120
|
+
def authentication_request(controller, realm, message)
|
121
|
+
message ||= "HTTP Basic: Access denied.\n"
|
122
|
+
controller.headers["WWW-Authenticate"] = %(Basic realm="#{realm.tr('"'.freeze, "".freeze)}")
|
127
123
|
controller.status = 401
|
128
|
-
controller.response_body =
|
124
|
+
controller.response_body = message
|
129
125
|
end
|
130
126
|
end
|
131
127
|
|
@@ -175,8 +171,8 @@ module ActionController
|
|
175
171
|
extend self
|
176
172
|
|
177
173
|
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)
|
174
|
+
def authenticate_or_request_with_http_digest(realm = "Application", message = nil, &password_procedure)
|
175
|
+
authenticate_with_http_digest(realm, &password_procedure) || request_http_digest_authentication(realm, message)
|
180
176
|
end
|
181
177
|
|
182
178
|
# Authenticate with HTTP Digest, returns true or false
|
@@ -207,7 +203,7 @@ module ActionController
|
|
207
203
|
password = password_procedure.call(credentials[:username])
|
208
204
|
return false unless password
|
209
205
|
|
210
|
-
method = request.
|
206
|
+
method = request.get_header('rack.methodoverride.original_method') || request.get_header('REQUEST_METHOD')
|
211
207
|
uri = credentials[:uri]
|
212
208
|
|
213
209
|
[true, false].any? do |trailing_question_mark|
|
@@ -264,8 +260,8 @@ module ActionController
|
|
264
260
|
end
|
265
261
|
|
266
262
|
def secret_token(request)
|
267
|
-
key_generator = request.
|
268
|
-
http_auth_salt = request.
|
263
|
+
key_generator = request.key_generator
|
264
|
+
http_auth_salt = request.http_auth_salt
|
269
265
|
key_generator.generate_key(http_auth_salt)
|
270
266
|
end
|
271
267
|
|
@@ -319,7 +315,7 @@ module ActionController
|
|
319
315
|
nonce(secret_key, t) == value && (t - Time.now.to_i).abs <= seconds_to_timeout
|
320
316
|
end
|
321
317
|
|
322
|
-
# Opaque based on
|
318
|
+
# Opaque based on digest of secret key
|
323
319
|
def opaque(secret_key)
|
324
320
|
::Digest::MD5.hexdigest(secret_key)
|
325
321
|
end
|
@@ -365,7 +361,7 @@ module ActionController
|
|
365
361
|
#
|
366
362
|
# def authenticate
|
367
363
|
# case request.format
|
368
|
-
# when Mime
|
364
|
+
# when Mime[:xml], Mime[:atom]
|
369
365
|
# if user = authenticate_with_http_token { |t, o| @account.users.authenticate(t, o) }
|
370
366
|
# @current_user = user
|
371
367
|
# else
|
@@ -401,21 +397,21 @@ module ActionController
|
|
401
397
|
# RewriteRule ^(.*)$ dispatch.fcgi [E=X-HTTP_AUTHORIZATION:%{HTTP:Authorization},QSA,L]
|
402
398
|
module Token
|
403
399
|
TOKEN_KEY = 'token='
|
404
|
-
TOKEN_REGEX = /^Token
|
400
|
+
TOKEN_REGEX = /^(Token|Bearer)\s+/
|
405
401
|
AUTHN_PAIR_DELIMITERS = /(?:,|;|\t+)/
|
406
402
|
extend self
|
407
403
|
|
408
404
|
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)
|
405
|
+
def authenticate_or_request_with_http_token(realm = "Application", message = nil, &login_procedure)
|
406
|
+
authenticate_with_http_token(&login_procedure) || request_http_token_authentication(realm, message)
|
411
407
|
end
|
412
408
|
|
413
409
|
def authenticate_with_http_token(&login_procedure)
|
414
410
|
Token.authenticate(self, &login_procedure)
|
415
411
|
end
|
416
412
|
|
417
|
-
def request_http_token_authentication(realm = "Application")
|
418
|
-
Token.authentication_request(self, realm)
|
413
|
+
def request_http_token_authentication(realm = "Application", message = nil)
|
414
|
+
Token.authentication_request(self, realm, message)
|
419
415
|
end
|
420
416
|
end
|
421
417
|
|
@@ -440,15 +436,17 @@ module ActionController
|
|
440
436
|
end
|
441
437
|
end
|
442
438
|
|
443
|
-
# Parses the token and options out of the token authorization header.
|
444
|
-
# the header
|
439
|
+
# Parses the token and options out of the token authorization header.
|
440
|
+
# The value for the Authorization header is expected to have the prefix
|
441
|
+
# <tt>"Token"</tt> or <tt>"Bearer"</tt>. If the header looks like this:
|
445
442
|
# Authorization: Token token="abc", nonce="def"
|
446
|
-
# Then the returned token is "abc"
|
443
|
+
# Then the returned token is <tt>"abc"</tt>, and the options are
|
444
|
+
# <tt>{nonce: "def"}</tt>
|
447
445
|
#
|
448
446
|
# request - ActionDispatch::Request instance with the current headers.
|
449
447
|
#
|
450
|
-
# Returns an Array of [String, Hash] if a token is present.
|
451
|
-
# Returns nil if no token is found.
|
448
|
+
# Returns an +Array+ of <tt>[String, Hash]</tt> if a token is present.
|
449
|
+
# Returns +nil+ if no token is found.
|
452
450
|
def token_and_options(request)
|
453
451
|
authorization_request = request.authorization.to_s
|
454
452
|
if authorization_request[TOKEN_REGEX]
|
@@ -497,15 +495,16 @@ module ActionController
|
|
497
495
|
"Token #{values * ", "}"
|
498
496
|
end
|
499
497
|
|
500
|
-
# Sets a WWW-Authenticate to let the client know a token is desired.
|
498
|
+
# Sets a WWW-Authenticate header to let the client know a token is desired.
|
501
499
|
#
|
502
500
|
# controller - ActionController::Base instance for the outgoing response.
|
503
501
|
# realm - String realm to use in the header.
|
504
502
|
#
|
505
503
|
# Returns nothing.
|
506
|
-
def authentication_request(controller, realm)
|
507
|
-
|
508
|
-
controller.
|
504
|
+
def authentication_request(controller, realm, message = nil)
|
505
|
+
message ||= "HTTP Token: Access denied.\n"
|
506
|
+
controller.headers["WWW-Authenticate"] = %(Token realm="#{realm.tr('"'.freeze, "".freeze)}")
|
507
|
+
controller.__send__ :render, plain: message, status: :unauthorized
|
509
508
|
end
|
510
509
|
end
|
511
510
|
end
|