actionpack 3.0.20 → 3.1.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.
- data/CHANGELOG +88 -142
- data/MIT-LICENSE +1 -1
- data/README.rdoc +5 -6
- data/lib/abstract_controller.rb +1 -0
- data/lib/abstract_controller/asset_paths.rb +2 -2
- data/lib/abstract_controller/base.rb +24 -19
- data/lib/abstract_controller/callbacks.rb +19 -19
- data/lib/abstract_controller/helpers.rb +11 -13
- data/lib/abstract_controller/layouts.rb +4 -5
- data/lib/abstract_controller/railties/routes_helpers.rb +18 -0
- data/lib/abstract_controller/rendering.rb +34 -31
- data/lib/abstract_controller/url_for.rb +27 -0
- data/lib/abstract_controller/view_paths.rb +31 -6
- data/lib/action_controller.rb +5 -3
- data/lib/action_controller/base.rb +15 -16
- data/lib/action_controller/caching.rb +2 -2
- data/lib/action_controller/caching/actions.rb +11 -12
- data/lib/action_controller/caching/fragments.rb +41 -19
- data/lib/action_controller/caching/pages.rb +3 -9
- data/lib/action_controller/caching/sweeping.rb +0 -1
- data/lib/action_controller/deprecated.rb +1 -1
- data/lib/action_controller/log_subscriber.rb +1 -1
- data/lib/action_controller/metal.rb +78 -20
- data/lib/action_controller/metal/compatibility.rb +0 -9
- data/lib/action_controller/metal/conditional_get.rb +9 -9
- data/lib/action_controller/metal/data_streaming.rb +145 -0
- data/lib/action_controller/metal/force_ssl.rb +35 -0
- data/lib/action_controller/metal/head.rb +1 -1
- data/lib/action_controller/metal/helpers.rb +37 -44
- data/lib/action_controller/metal/hide_actions.rb +2 -3
- data/lib/action_controller/metal/http_authentication.rb +41 -38
- data/lib/action_controller/metal/implicit_render.rb +13 -13
- data/lib/action_controller/metal/instrumentation.rb +2 -2
- data/lib/action_controller/metal/mime_responds.rb +25 -19
- data/lib/action_controller/metal/params_wrapper.rb +224 -0
- data/lib/action_controller/metal/redirecting.rb +6 -2
- data/lib/action_controller/metal/renderers.rb +50 -36
- data/lib/action_controller/metal/rendering.rb +34 -25
- data/lib/action_controller/metal/request_forgery_protection.rb +18 -36
- data/lib/action_controller/metal/responder.rb +47 -12
- data/lib/action_controller/metal/streaming.rb +244 -138
- data/lib/action_controller/metal/testing.rb +0 -9
- data/lib/action_controller/metal/url_for.rb +12 -14
- data/lib/action_controller/railtie.rb +19 -37
- data/lib/action_controller/railties/paths.rb +24 -0
- data/lib/action_controller/record_identifier.rb +4 -10
- data/lib/action_controller/test_case.rb +36 -19
- data/lib/action_controller/vendor/html-scanner/html/node.rb +5 -5
- data/lib/action_controller/vendor/html-scanner/html/sanitizer.rb +3 -3
- data/lib/action_controller/vendor/html-scanner/html/selector.rb +2 -0
- data/lib/action_dispatch.rb +4 -1
- data/lib/action_dispatch/http/cache.rb +5 -32
- data/lib/action_dispatch/http/filter_parameters.rb +3 -1
- data/lib/action_dispatch/http/mime_negotiation.rb +22 -3
- data/lib/action_dispatch/http/mime_type.rb +45 -5
- data/lib/action_dispatch/http/rack_cache.rb +58 -0
- data/lib/action_dispatch/http/request.rb +27 -41
- data/lib/action_dispatch/http/response.rb +56 -54
- data/lib/action_dispatch/http/upload.rb +1 -11
- data/lib/action_dispatch/http/url.rb +102 -42
- data/lib/action_dispatch/middleware/callbacks.rb +8 -25
- data/lib/action_dispatch/middleware/closed_error.rb +7 -0
- data/lib/action_dispatch/middleware/cookies.rb +37 -15
- data/lib/action_dispatch/middleware/flash.rb +80 -11
- data/lib/action_dispatch/middleware/params_parser.rb +2 -2
- data/lib/action_dispatch/middleware/reloader.rb +76 -0
- data/lib/action_dispatch/middleware/session/abstract_store.rb +56 -226
- data/lib/action_dispatch/middleware/session/cookie_store.rb +20 -44
- data/lib/action_dispatch/middleware/session/mem_cache_store.rb +7 -46
- data/lib/action_dispatch/middleware/show_exceptions.rb +15 -2
- data/lib/action_dispatch/middleware/stack.rb +50 -17
- data/lib/action_dispatch/middleware/static.rb +41 -29
- data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb +3 -3
- data/lib/action_dispatch/middleware/templates/rescues/_trace.erb +3 -3
- data/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb +3 -3
- data/lib/action_dispatch/middleware/templates/rescues/layout.erb +4 -2
- data/lib/action_dispatch/middleware/templates/rescues/template_error.erb +2 -6
- data/lib/action_dispatch/railtie.rb +8 -0
- data/lib/action_dispatch/routing.rb +13 -1
- data/lib/action_dispatch/routing/mapper.rb +345 -227
- data/lib/action_dispatch/routing/polymorphic_routes.rb +33 -13
- data/lib/action_dispatch/routing/redirection.rb +110 -0
- data/lib/action_dispatch/routing/route.rb +15 -13
- data/lib/action_dispatch/routing/route_set.rb +116 -90
- data/lib/action_dispatch/routing/routes_proxy.rb +35 -0
- data/lib/action_dispatch/routing/url_for.rb +25 -1
- data/lib/action_dispatch/testing/assertions/response.rb +8 -10
- data/lib/action_dispatch/testing/assertions/routing.rb +15 -15
- data/lib/action_dispatch/testing/assertions/selector.rb +13 -220
- data/lib/action_dispatch/testing/integration.rb +37 -28
- data/lib/action_dispatch/testing/performance_test.rb +1 -3
- data/lib/action_dispatch/testing/test_process.rb +1 -1
- data/lib/action_dispatch/testing/test_request.rb +9 -3
- data/lib/action_dispatch/testing/test_response.rb +4 -111
- data/lib/action_pack.rb +1 -1
- data/lib/action_pack/version.rb +3 -3
- data/lib/action_view.rb +39 -24
- data/lib/action_view/base.rb +61 -86
- data/lib/action_view/buffers.rb +43 -0
- data/lib/action_view/context.rb +21 -24
- data/lib/action_view/flows.rb +79 -0
- data/lib/action_view/helpers.rb +8 -6
- data/lib/action_view/helpers/active_model_helper.rb +0 -23
- data/lib/action_view/helpers/asset_paths.rb +79 -0
- data/lib/action_view/helpers/asset_tag_helper.rb +30 -500
- data/lib/action_view/helpers/asset_tag_helpers/asset_include_tag.rb +147 -0
- data/lib/action_view/helpers/asset_tag_helpers/asset_paths.rb +101 -0
- data/lib/action_view/helpers/asset_tag_helpers/javascript_tag_helpers.rb +200 -0
- data/lib/action_view/helpers/asset_tag_helpers/stylesheet_tag_helpers.rb +152 -0
- data/lib/action_view/helpers/atom_feed_helper.rb +2 -2
- data/lib/action_view/helpers/cache_helper.rb +11 -19
- data/lib/action_view/helpers/capture_helper.rb +19 -8
- data/lib/action_view/helpers/controller_helper.rb +21 -0
- data/lib/action_view/helpers/csrf_helper.rb +22 -4
- data/lib/action_view/helpers/date_helper.rb +36 -22
- data/lib/action_view/helpers/form_helper.rb +199 -113
- data/lib/action_view/helpers/form_options_helper.rb +10 -11
- data/lib/action_view/helpers/form_tag_helper.rb +94 -22
- data/lib/action_view/helpers/javascript_helper.rb +24 -107
- data/lib/action_view/helpers/number_helper.rb +36 -33
- data/lib/action_view/helpers/output_safety_helper.rb +38 -0
- data/lib/action_view/helpers/record_tag_helper.rb +6 -6
- data/lib/action_view/helpers/rendering_helper.rb +90 -0
- data/lib/action_view/helpers/sanitize_helper.rb +2 -2
- data/lib/action_view/helpers/sprockets_helper.rb +69 -0
- data/lib/action_view/helpers/tag_helper.rb +34 -12
- data/lib/action_view/helpers/text_helper.rb +30 -145
- data/lib/action_view/helpers/translation_helper.rb +10 -17
- data/lib/action_view/helpers/url_helper.rb +70 -67
- data/lib/action_view/locale/en.yml +1 -1
- data/lib/action_view/lookup_context.rb +36 -14
- data/lib/action_view/{paths.rb → path_set.rb} +9 -8
- data/lib/action_view/railtie.rb +12 -4
- data/lib/action_view/renderer/abstract_renderer.rb +36 -0
- data/lib/action_view/{render/partials.rb → renderer/partial_renderer.rb} +147 -146
- data/lib/action_view/renderer/renderer.rb +54 -0
- data/lib/action_view/renderer/streaming_template_renderer.rb +106 -0
- data/lib/action_view/renderer/template_renderer.rb +74 -0
- data/lib/action_view/template.rb +91 -54
- data/lib/action_view/template/error.rb +11 -8
- data/lib/action_view/template/handler.rb +9 -1
- data/lib/action_view/template/handlers.rb +9 -9
- data/lib/action_view/template/handlers/builder.rb +4 -4
- data/lib/action_view/template/handlers/erb.rb +21 -41
- data/lib/action_view/template/resolver.rb +171 -57
- data/lib/action_view/template/text.rb +0 -4
- data/lib/action_view/test_case.rb +32 -16
- data/lib/action_view/testing/resolvers.rb +16 -10
- data/lib/sprockets/railtie.rb +100 -0
- metadata +162 -140
- checksums.yaml +0 -7
- data/lib/action_controller/deprecated/base.rb +0 -143
- data/lib/action_controller/deprecated/dispatcher.rb +0 -28
- data/lib/action_controller/deprecated/url_writer.rb +0 -14
- data/lib/action_dispatch/routing/deprecated_mapper.rb +0 -525
- data/lib/action_view/helpers/prototype_helper.rb +0 -851
- data/lib/action_view/helpers/raw_output_helper.rb +0 -18
- data/lib/action_view/helpers/scriptaculous_helper.rb +0 -263
- data/lib/action_view/render/layouts.rb +0 -83
- data/lib/action_view/render/rendering.rb +0 -67
- data/lib/action_view/template/handlers/rjs.rb +0 -17
@@ -6,7 +6,7 @@ module ActionController
|
|
6
6
|
include Head
|
7
7
|
|
8
8
|
# Sets the etag, last_modified, or both on the response and renders a
|
9
|
-
#
|
9
|
+
# <tt>304 Not Modified</tt> response if the request is already fresh.
|
10
10
|
#
|
11
11
|
# Parameters:
|
12
12
|
# * <tt>:etag</tt>
|
@@ -17,11 +17,11 @@ module ActionController
|
|
17
17
|
#
|
18
18
|
# def show
|
19
19
|
# @article = Article.find(params[:id])
|
20
|
-
# fresh_when(:etag => @article, :last_modified => @article.created_at
|
20
|
+
# fresh_when(:etag => @article, :last_modified => @article.created_at, :public => true)
|
21
21
|
# end
|
22
22
|
#
|
23
23
|
# This will render the show template if the request isn't sending a matching etag or
|
24
|
-
# If-Modified-Since header and just a
|
24
|
+
# If-Modified-Since header and just a <tt>304 Not Modified</tt> response if there's a match.
|
25
25
|
#
|
26
26
|
def fresh_when(options)
|
27
27
|
options.assert_valid_keys(:etag, :last_modified, :public)
|
@@ -36,7 +36,7 @@ module ActionController
|
|
36
36
|
# Sets the etag and/or last_modified on the response and checks it against
|
37
37
|
# the client request. If the request doesn't match the options provided, the
|
38
38
|
# request is considered stale and should be generated from scratch. Otherwise,
|
39
|
-
# it's fresh and we don't need to generate anything and a reply of
|
39
|
+
# it's fresh and we don't need to generate anything and a reply of <tt>304 Not Modified</tt> is sent.
|
40
40
|
#
|
41
41
|
# Parameters:
|
42
42
|
# * <tt>:etag</tt>
|
@@ -48,7 +48,7 @@ module ActionController
|
|
48
48
|
# def show
|
49
49
|
# @article = Article.find(params[:id])
|
50
50
|
#
|
51
|
-
# if stale?(:etag => @article, :last_modified => @article.created_at
|
51
|
+
# if stale?(:etag => @article, :last_modified => @article.created_at)
|
52
52
|
# @statistics = @article.really_expensive_call
|
53
53
|
# respond_to do |format|
|
54
54
|
# # all the supported formats
|
@@ -60,13 +60,13 @@ module ActionController
|
|
60
60
|
!request.fresh?(response)
|
61
61
|
end
|
62
62
|
|
63
|
-
# Sets a HTTP 1.1 Cache-Control header. Defaults to issuing a
|
64
|
-
# intermediate caches
|
63
|
+
# Sets a HTTP 1.1 Cache-Control header. Defaults to issuing a <tt>private</tt> instruction, so that
|
64
|
+
# intermediate caches must not cache the response.
|
65
65
|
#
|
66
66
|
# Examples:
|
67
67
|
# expires_in 20.minutes
|
68
68
|
# expires_in 3.hours, :public => true
|
69
|
-
#
|
69
|
+
# expires_in 3.hours, 'max-stale' => 5.hours, :public => true
|
70
70
|
#
|
71
71
|
# This method will overwrite an existing Cache-Control header.
|
72
72
|
# See http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html for more possibilities.
|
@@ -77,7 +77,7 @@ module ActionController
|
|
77
77
|
response.cache_control[:extras] = options.map {|k,v| "#{k}=#{v}"}
|
78
78
|
end
|
79
79
|
|
80
|
-
# Sets a HTTP 1.1 Cache-Control header of
|
80
|
+
# Sets a HTTP 1.1 Cache-Control header of <tt>no-cache</tt> so no caching should occur by the browser or
|
81
81
|
# intermediate caches (like caching proxy servers).
|
82
82
|
def expires_now #:doc:
|
83
83
|
response.cache_control.replace(:no_cache => true)
|
@@ -0,0 +1,145 @@
|
|
1
|
+
require 'active_support/core_ext/file/path'
|
2
|
+
|
3
|
+
module ActionController #:nodoc:
|
4
|
+
# Methods for sending arbitrary data and for streaming files to the browser,
|
5
|
+
# instead of rendering.
|
6
|
+
module DataStreaming
|
7
|
+
extend ActiveSupport::Concern
|
8
|
+
|
9
|
+
include ActionController::Rendering
|
10
|
+
|
11
|
+
DEFAULT_SEND_FILE_OPTIONS = {
|
12
|
+
:type => 'application/octet-stream'.freeze,
|
13
|
+
:disposition => 'attachment'.freeze,
|
14
|
+
}.freeze
|
15
|
+
|
16
|
+
protected
|
17
|
+
# Sends the file. This uses a server-appropriate method (such as X-Sendfile)
|
18
|
+
# via the Rack::Sendfile middleware. The header to use is set via
|
19
|
+
# config.action_dispatch.x_sendfile_header, and defaults to "X-Sendfile".
|
20
|
+
# Your server can also configure this for you by setting the X-Sendfile-Type header.
|
21
|
+
#
|
22
|
+
# Be careful to sanitize the path parameter if it is coming from a web
|
23
|
+
# page. <tt>send_file(params[:path])</tt> allows a malicious user to
|
24
|
+
# download any file on your server.
|
25
|
+
#
|
26
|
+
# Options:
|
27
|
+
# * <tt>:filename</tt> - suggests a filename for the browser to use.
|
28
|
+
# Defaults to <tt>File.basename(path)</tt>.
|
29
|
+
# * <tt>:type</tt> - specifies an HTTP content type. Defaults to 'application/octet-stream'. You can specify
|
30
|
+
# either a string or a symbol for a registered type register with <tt>Mime::Type.register</tt>, for example :json
|
31
|
+
# * <tt>:disposition</tt> - specifies whether the file will be shown inline or downloaded.
|
32
|
+
# Valid values are 'inline' and 'attachment' (default).
|
33
|
+
# * <tt>:status</tt> - specifies the status code to send with the response. Defaults to '200 OK'.
|
34
|
+
# * <tt>:url_based_filename</tt> - set to +true+ if you want the browser guess the filename from
|
35
|
+
# the URL, which is necessary for i18n filenames on certain browsers
|
36
|
+
# (setting <tt>:filename</tt> overrides this option).
|
37
|
+
#
|
38
|
+
# The default Content-Type and Content-Disposition headers are
|
39
|
+
# set to download arbitrary binary files in as many browsers as
|
40
|
+
# possible. IE versions 4, 5, 5.5, and 6 are all known to have
|
41
|
+
# a variety of quirks (especially when downloading over SSL).
|
42
|
+
#
|
43
|
+
# Simple download:
|
44
|
+
#
|
45
|
+
# send_file '/path/to.zip'
|
46
|
+
#
|
47
|
+
# Show a JPEG in the browser:
|
48
|
+
#
|
49
|
+
# send_file '/path/to.jpeg', :type => 'image/jpeg', :disposition => 'inline'
|
50
|
+
#
|
51
|
+
# Show a 404 page in the browser:
|
52
|
+
#
|
53
|
+
# send_file '/path/to/404.html', :type => 'text/html; charset=utf-8', :status => 404
|
54
|
+
#
|
55
|
+
# Read about the other Content-* HTTP headers if you'd like to
|
56
|
+
# provide the user with more information (such as Content-Description) in
|
57
|
+
# http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.11.
|
58
|
+
#
|
59
|
+
# Also be aware that the document may be cached by proxies and browsers.
|
60
|
+
# The Pragma and Cache-Control headers declare how the file may be cached
|
61
|
+
# by intermediaries. They default to require clients to validate with
|
62
|
+
# the server before releasing cached responses. See
|
63
|
+
# http://www.mnot.net/cache_docs/ for an overview of web caching and
|
64
|
+
# http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9
|
65
|
+
# for the Cache-Control header spec.
|
66
|
+
def send_file(path, options = {}) #:doc:
|
67
|
+
raise MissingFile, "Cannot read file #{path}" unless File.file?(path) and File.readable?(path)
|
68
|
+
|
69
|
+
options[:filename] ||= File.basename(path) unless options[:url_based_filename]
|
70
|
+
send_file_headers! options
|
71
|
+
|
72
|
+
self.status = options[:status] || 200
|
73
|
+
self.content_type = options[:content_type] if options.key?(:content_type)
|
74
|
+
self.response_body = File.open(path, "rb")
|
75
|
+
end
|
76
|
+
|
77
|
+
# Sends the given binary data to the browser. This method is similar to
|
78
|
+
# <tt>render :text => data</tt>, but also allows you to specify whether
|
79
|
+
# the browser should display the response as a file attachment (i.e. in a
|
80
|
+
# download dialog) or as inline data. You may also set the content type,
|
81
|
+
# the apparent file name, and other things.
|
82
|
+
#
|
83
|
+
# Options:
|
84
|
+
# * <tt>:filename</tt> - suggests a filename for the browser to use.
|
85
|
+
# * <tt>:type</tt> - specifies an HTTP content type. Defaults to 'application/octet-stream'. You can specify
|
86
|
+
# either a string or a symbol for a registered type register with <tt>Mime::Type.register</tt>, for example :json
|
87
|
+
# * <tt>:disposition</tt> - specifies whether the file will be shown inline or downloaded.
|
88
|
+
# Valid values are 'inline' and 'attachment' (default).
|
89
|
+
# * <tt>:status</tt> - specifies the status code to send with the response. Defaults to '200 OK'.
|
90
|
+
#
|
91
|
+
# Generic data download:
|
92
|
+
#
|
93
|
+
# send_data buffer
|
94
|
+
#
|
95
|
+
# Download a dynamically-generated tarball:
|
96
|
+
#
|
97
|
+
# send_data generate_tgz('dir'), :filename => 'dir.tgz'
|
98
|
+
#
|
99
|
+
# Display an image Active Record in the browser:
|
100
|
+
#
|
101
|
+
# send_data image.data, :type => image.content_type, :disposition => 'inline'
|
102
|
+
#
|
103
|
+
# See +send_file+ for more information on HTTP Content-* headers and caching.
|
104
|
+
def send_data(data, options = {}) #:doc:
|
105
|
+
send_file_headers! options.dup
|
106
|
+
render options.slice(:status, :content_type).merge(:text => data)
|
107
|
+
end
|
108
|
+
|
109
|
+
private
|
110
|
+
def send_file_headers!(options)
|
111
|
+
options.update(DEFAULT_SEND_FILE_OPTIONS.merge(options))
|
112
|
+
[:type, :disposition].each do |arg|
|
113
|
+
raise ArgumentError, ":#{arg} option required" if options[arg].nil?
|
114
|
+
end
|
115
|
+
|
116
|
+
disposition = options[:disposition]
|
117
|
+
disposition += %(; filename="#{options[:filename]}") if options[:filename]
|
118
|
+
|
119
|
+
content_type = options[:type]
|
120
|
+
|
121
|
+
if content_type.is_a?(Symbol)
|
122
|
+
extension = Mime[content_type]
|
123
|
+
raise ArgumentError, "Unknown MIME type #{options[:type]}" unless extension
|
124
|
+
self.content_type = extension
|
125
|
+
else
|
126
|
+
self.content_type = content_type
|
127
|
+
end
|
128
|
+
|
129
|
+
headers.merge!(
|
130
|
+
'Content-Disposition' => disposition,
|
131
|
+
'Content-Transfer-Encoding' => 'binary'
|
132
|
+
)
|
133
|
+
|
134
|
+
response.sending_file = true
|
135
|
+
|
136
|
+
# Fix a problem with IE 6.0 on opening downloaded files:
|
137
|
+
# If Cache-Control: no-cache is set (which Rails does by default),
|
138
|
+
# IE removes the file it just downloaded from its cache immediately
|
139
|
+
# after it displays the "open/save" dialog, which means that if you
|
140
|
+
# hit "open" the file isn't there anymore when the application that
|
141
|
+
# is called for handling the download is run, so let's workaround that
|
142
|
+
response.cache_control[:public] ||= false
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module ActionController
|
2
|
+
# This module provides a method which will redirects browser to use HTTPS
|
3
|
+
# protocol. This will ensure that user's sensitive information will be
|
4
|
+
# transferred safely over the internet. You _should_ always force browser
|
5
|
+
# to use HTTPS when you're transferring sensitive information such as
|
6
|
+
# user authentication, account information, or credit card information.
|
7
|
+
#
|
8
|
+
# Note that if you really concern about your application safety, you might
|
9
|
+
# consider using +config.force_ssl+ in your configuration config file instead.
|
10
|
+
# That will ensure all the data transferred via HTTPS protocol and prevent
|
11
|
+
# user from getting session hijacked when accessing the site under unsecured
|
12
|
+
# HTTP protocol.
|
13
|
+
module ForceSSL
|
14
|
+
extend ActiveSupport::Concern
|
15
|
+
include AbstractController::Callbacks
|
16
|
+
|
17
|
+
module ClassMethods
|
18
|
+
# Force the request to this particular controller or specified actions to be
|
19
|
+
# under HTTPS protocol.
|
20
|
+
#
|
21
|
+
# Note that this method will not be effective on development environment.
|
22
|
+
#
|
23
|
+
# ==== Options
|
24
|
+
# * <tt>only</tt> - The callback should be run only for this action
|
25
|
+
# * <tt>except<tt> - The callback should be run for all actions except this action
|
26
|
+
def force_ssl(options = {})
|
27
|
+
before_filter(options) do
|
28
|
+
if !request.ssl? && !Rails.env.development?
|
29
|
+
redirect_to :protocol => 'https://', :status => :moved_permanently
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -20,7 +20,7 @@ module ActionController
|
|
20
20
|
location = options.delete(:location)
|
21
21
|
|
22
22
|
options.each do |key, value|
|
23
|
-
headers[key.to_s.dasherize.split(
|
23
|
+
headers[key.to_s.dasherize.split('-').each { |v| v[0] = v[0].chr.upcase }.join('-')] = value.to_s
|
24
24
|
end
|
25
25
|
|
26
26
|
self.status = status
|
@@ -2,21 +2,21 @@ require 'active_support/core_ext/array/wrap'
|
|
2
2
|
require 'active_support/core_ext/class/attribute'
|
3
3
|
|
4
4
|
module ActionController
|
5
|
-
# The Rails framework provides a large number of helpers for working with
|
6
|
-
#
|
5
|
+
# The \Rails framework provides a large number of helpers for working with assets, dates, forms,
|
6
|
+
# numbers and model objects, to name a few. These helpers are available to all templates
|
7
7
|
# by default.
|
8
8
|
#
|
9
|
-
# In addition to using the standard template helpers provided
|
9
|
+
# In addition to using the standard template helpers provided, creating custom helpers to
|
10
10
|
# extract complicated logic or reusable functionality is strongly encouraged. By default, the controller will
|
11
11
|
# include a helper whose name matches that of the controller, e.g., <tt>MyController</tt> will automatically
|
12
12
|
# include <tt>MyHelper</tt>.
|
13
13
|
#
|
14
|
-
# Additional helpers can be specified using the +helper+ class method in
|
14
|
+
# Additional helpers can be specified using the +helper+ class method in ActionController::Base or any
|
15
15
|
# controller which inherits from it.
|
16
16
|
#
|
17
17
|
# ==== Examples
|
18
|
-
# The +to_s+ method from the Time class can be wrapped in a helper method to display a custom message if
|
19
|
-
#
|
18
|
+
# The +to_s+ method from the \Time class can be wrapped in a helper method to display a custom message if
|
19
|
+
# a \Time object is blank:
|
20
20
|
#
|
21
21
|
# module FormattedTimeHelper
|
22
22
|
# def format_time(time, format=:long, blank_message=" ")
|
@@ -53,30 +53,20 @@ module ActionController
|
|
53
53
|
include AbstractController::Helpers
|
54
54
|
|
55
55
|
included do
|
56
|
-
config_accessor :helpers_path
|
56
|
+
config_accessor :helpers_path, :include_all_helpers
|
57
57
|
self.helpers_path ||= []
|
58
|
+
self.include_all_helpers = true
|
58
59
|
end
|
59
60
|
|
60
61
|
module ClassMethods
|
61
|
-
def helpers_dir
|
62
|
-
ActiveSupport::Deprecation.warn "helpers_dir is deprecated, use helpers_path instead", caller
|
63
|
-
self.helpers_path
|
64
|
-
end
|
65
|
-
|
66
|
-
def helpers_dir=(value)
|
67
|
-
ActiveSupport::Deprecation.warn "helpers_dir= is deprecated, use helpers_path= instead", caller
|
68
|
-
self.helpers_path = Array.wrap(value)
|
69
|
-
end
|
70
|
-
|
71
62
|
# Declares helper accessors for controller attributes. For example, the
|
72
63
|
# following adds new +name+ and <tt>name=</tt> instance methods to a
|
73
64
|
# controller and makes them available to the view:
|
74
|
-
# helper_attr :name
|
75
65
|
# attr_accessor :name
|
66
|
+
# helper_attr :name
|
76
67
|
#
|
77
68
|
# ==== Parameters
|
78
|
-
# *attrs
|
79
|
-
# into helpers.
|
69
|
+
# * <tt>attrs</tt> - Names of attributes to be converted into helpers.
|
80
70
|
def helper_attr(*attrs)
|
81
71
|
attrs.flatten.each { |attr| helper_method(attr, "#{attr}=") }
|
82
72
|
end
|
@@ -86,32 +76,35 @@ module ActionController
|
|
86
76
|
@helper_proxy ||= ActionView::Base.new.extend(_helpers)
|
87
77
|
end
|
88
78
|
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
super(args)
|
102
|
-
end
|
79
|
+
# Overwrite modules_for_helpers to accept :all as argument, which loads
|
80
|
+
# all helpers in helpers_path.
|
81
|
+
#
|
82
|
+
# ==== Parameters
|
83
|
+
# * <tt>args</tt> - A list of helpers
|
84
|
+
#
|
85
|
+
# ==== Returns
|
86
|
+
# * <tt>array</tt> - A normalized list of modules for the list of helpers provided.
|
87
|
+
def modules_for_helpers(args)
|
88
|
+
args += all_application_helpers if args.delete(:all)
|
89
|
+
super(args)
|
90
|
+
end
|
103
91
|
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
helpers += Dir["#{path}/**/*_helper.rb"].map { |file| file.sub(extract, '\1') }
|
110
|
-
end
|
111
|
-
helpers.sort!
|
112
|
-
helpers.uniq!
|
113
|
-
helpers
|
92
|
+
def all_helpers_from_path(path)
|
93
|
+
helpers = []
|
94
|
+
Array.wrap(path).each do |_path|
|
95
|
+
extract = /^#{Regexp.quote(_path.to_s)}\/?(.*)_helper.rb$/
|
96
|
+
helpers += Dir["#{_path}/**/*_helper.rb"].map { |file| file.sub(extract, '\1') }
|
114
97
|
end
|
98
|
+
helpers.sort!
|
99
|
+
helpers.uniq!
|
100
|
+
helpers
|
101
|
+
end
|
102
|
+
|
103
|
+
private
|
104
|
+
# Extract helper names from files in <tt>app/helpers/**/*_helper.rb</tt>
|
105
|
+
def all_application_helpers
|
106
|
+
all_helpers_from_path(helpers_path)
|
107
|
+
end
|
115
108
|
end
|
116
109
|
end
|
117
110
|
end
|
@@ -1,8 +1,7 @@
|
|
1
1
|
require 'active_support/core_ext/class/attribute'
|
2
2
|
|
3
3
|
module ActionController
|
4
|
-
#
|
5
|
-
# to be called as actions.
|
4
|
+
# Adds the ability to prevent public methods on a controller to be called as actions.
|
6
5
|
module HideActions
|
7
6
|
extend ActiveSupport::Concern
|
8
7
|
|
@@ -23,7 +22,7 @@ module ActionController
|
|
23
22
|
# Sets all of the actions passed in as hidden actions.
|
24
23
|
#
|
25
24
|
# ==== Parameters
|
26
|
-
# *args
|
25
|
+
# * <tt>args</tt> - A list of actions
|
27
26
|
def hide_action(*args)
|
28
27
|
self.hidden_actions = hidden_actions.dup.merge(args.map(&:to_s)).freeze
|
29
28
|
end
|
@@ -3,14 +3,12 @@ require 'active_support/core_ext/object/blank'
|
|
3
3
|
|
4
4
|
module ActionController
|
5
5
|
module HttpAuthentication
|
6
|
-
# Makes it dead easy to do HTTP Basic authentication.
|
6
|
+
# Makes it dead easy to do HTTP \Basic and \Digest authentication.
|
7
7
|
#
|
8
|
-
# Simple Basic example
|
8
|
+
# === Simple \Basic example
|
9
9
|
#
|
10
10
|
# class PostsController < ApplicationController
|
11
|
-
#
|
12
|
-
#
|
13
|
-
# before_filter :authenticate, :except => [ :index ]
|
11
|
+
# http_basic_authenticate_with :name => "dhh", :password => "secret", :except => :index
|
14
12
|
#
|
15
13
|
# def index
|
16
14
|
# render :text => "Everyone can see me!"
|
@@ -19,17 +17,11 @@ module ActionController
|
|
19
17
|
# def edit
|
20
18
|
# render :text => "I'm only accessible if you know the password"
|
21
19
|
# end
|
20
|
+
# end
|
22
21
|
#
|
23
|
-
#
|
24
|
-
# def authenticate
|
25
|
-
# authenticate_or_request_with_http_basic do |user_name, password|
|
26
|
-
# user_name == USER_NAME && password == PASSWORD
|
27
|
-
# end
|
28
|
-
# end
|
29
|
-
# end
|
22
|
+
# === Advanced \Basic example
|
30
23
|
#
|
31
|
-
#
|
32
|
-
# Here is a more advanced Basic example where only Atom feeds and the XML API is protected by HTTP authentication,
|
24
|
+
# Here is a more advanced \Basic example where only Atom feeds and the XML API is protected by HTTP authentication,
|
33
25
|
# the regular HTML interface is protected by a session approach:
|
34
26
|
#
|
35
27
|
# class ApplicationController < ActionController::Base
|
@@ -69,13 +61,13 @@ module ActionController
|
|
69
61
|
# assert_equal 200, status
|
70
62
|
# end
|
71
63
|
#
|
72
|
-
# Simple Digest example
|
64
|
+
# === Simple \Digest example
|
73
65
|
#
|
74
66
|
# require 'digest/md5'
|
75
67
|
# class PostsController < ApplicationController
|
76
68
|
# REALM = "SuperSecret"
|
77
69
|
# USERS = {"dhh" => "secret", #plain text password
|
78
|
-
# "dap" => Digest
|
70
|
+
# "dap" => Digest::MD5.hexdigest(["dap",REALM,"secret"].join(":")) #ha1 digest password
|
79
71
|
#
|
80
72
|
# before_filter :authenticate, :except => [:index]
|
81
73
|
#
|
@@ -101,15 +93,30 @@ module ActionController
|
|
101
93
|
# or the ha1 digest hash so the framework can appropriately hash to check the user's
|
102
94
|
# credentials. Returning +nil+ will cause authentication to fail.
|
103
95
|
#
|
104
|
-
#
|
105
|
-
#
|
106
|
-
# authenticate
|
96
|
+
# Storing the ha1 hash: MD5(username:realm:password), is better than storing a plain password. If
|
97
|
+
# the password file or database is compromised, the attacker would be able to use the ha1 hash to
|
98
|
+
# authenticate as the user at this +realm+, but would not have the user's password to try using at
|
99
|
+
# other sites.
|
107
100
|
#
|
108
|
-
#
|
101
|
+
# In rare instances, web servers or front proxies strip authorization headers before
|
102
|
+
# they reach your application. You can debug this situation by logging all environment
|
103
|
+
# variables, and check for HTTP_AUTHORIZATION, amongst others.
|
109
104
|
module Basic
|
110
105
|
extend self
|
111
106
|
|
112
107
|
module ControllerMethods
|
108
|
+
extend ActiveSupport::Concern
|
109
|
+
|
110
|
+
module ClassMethods
|
111
|
+
def http_basic_authenticate_with(options = {})
|
112
|
+
before_filter(options.except(:name, :password, :realm)) do
|
113
|
+
authenticate_or_request_with_http_basic(options[:realm] || "Application") do |name, password|
|
114
|
+
name == options[:name] && password == options[:password]
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
113
120
|
def authenticate_or_request_with_http_basic(realm = "Application", &login_procedure)
|
114
121
|
authenticate_with_http_basic(&login_procedure) || request_http_basic_authentication(realm)
|
115
122
|
end
|
@@ -209,7 +216,7 @@ module ActionController
|
|
209
216
|
|
210
217
|
def encode_credentials(http_method, credentials, password, password_is_ha1)
|
211
218
|
credentials[:response] = expected_response(http_method, credentials[:uri], credentials, password, password_is_ha1)
|
212
|
-
"Digest " + credentials.sort_by {|x| x[0].to_s }.
|
219
|
+
"Digest " + credentials.sort_by {|x| x[0].to_s }.map {|v| "#{v[0]}='#{v[1]}'" }.join(', ')
|
213
220
|
end
|
214
221
|
|
215
222
|
def decode_credentials_header(request)
|
@@ -217,9 +224,9 @@ module ActionController
|
|
217
224
|
end
|
218
225
|
|
219
226
|
def decode_credentials(header)
|
220
|
-
|
227
|
+
Hash[header.to_s.gsub(/^Digest\s+/,'').split(',').map do |pair|
|
221
228
|
key, value = pair.split('=', 2)
|
222
|
-
[key.strip, value.to_s.gsub(/^"|"$/,'').
|
229
|
+
[key.strip.to_sym, value.to_s.gsub(/^"|"$/,'').gsub(/'/, '')]
|
223
230
|
end]
|
224
231
|
end
|
225
232
|
|
@@ -373,7 +380,6 @@ module ActionController
|
|
373
380
|
#
|
374
381
|
# RewriteRule ^(.*)$ dispatch.fcgi [E=X-HTTP_AUTHORIZATION:%{HTTP:Authorization},QSA,L]
|
375
382
|
module Token
|
376
|
-
|
377
383
|
extend self
|
378
384
|
|
379
385
|
module ControllerMethods
|
@@ -402,7 +408,7 @@ module ActionController
|
|
402
408
|
# Returns nil if no token is found.
|
403
409
|
def authenticate(controller, &login_procedure)
|
404
410
|
token, options = token_and_options(controller.request)
|
405
|
-
|
411
|
+
unless token.blank?
|
406
412
|
login_procedure.call(token, options)
|
407
413
|
end
|
408
414
|
end
|
@@ -412,20 +418,19 @@ module ActionController
|
|
412
418
|
# Authorization: Token token="abc", nonce="def"
|
413
419
|
# Then the returned token is "abc", and the options is {:nonce => "def"}
|
414
420
|
#
|
415
|
-
# request -
|
421
|
+
# request - ActionDispatch::Request instance with the current headers.
|
416
422
|
#
|
417
423
|
# Returns an Array of [String, Hash] if a token is present.
|
418
424
|
# Returns nil if no token is found.
|
419
425
|
def token_and_options(request)
|
420
426
|
if header = request.authorization.to_s[/^Token (.*)/]
|
421
|
-
values = $1.split(',').
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
end
|
427
|
+
values = Hash[$1.split(',').map do |value|
|
428
|
+
value.strip! # remove any spaces between commas and values
|
429
|
+
key, value = value.split(/\=\"?/) # split key=value pairs
|
430
|
+
value.chomp!('"') # chomp trailing " in value
|
431
|
+
value.gsub!(/\\\"/, '"') # unescape remaining quotes
|
432
|
+
[key, value]
|
433
|
+
end]
|
429
434
|
[values.delete("token"), values.with_indifferent_access]
|
430
435
|
end
|
431
436
|
end
|
@@ -437,9 +442,8 @@ module ActionController
|
|
437
442
|
#
|
438
443
|
# Returns String.
|
439
444
|
def encode_credentials(token, options = {})
|
440
|
-
values = ["token=#{token.to_s.inspect}"]
|
441
|
-
|
442
|
-
values << "#{key}=#{value.to_s.inspect}"
|
445
|
+
values = ["token=#{token.to_s.inspect}"] + options.map do |key, value|
|
446
|
+
"#{key}=#{value.to_s.inspect}"
|
443
447
|
end
|
444
448
|
"Token #{values * ", "}"
|
445
449
|
end
|
@@ -455,6 +459,5 @@ module ActionController
|
|
455
459
|
controller.__send__ :render, :text => "HTTP Token: Access denied.\n", :status => :unauthorized
|
456
460
|
end
|
457
461
|
end
|
458
|
-
|
459
462
|
end
|
460
463
|
end
|