actionpack 2.3.3 → 2.3.4
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 +12 -1
- data/Rakefile +9 -8
- data/lib/action_controller/assertions/response_assertions.rb +3 -1
- data/lib/action_controller/base.rb +6 -2
- data/lib/action_controller/cookies.rb +1 -1
- data/lib/action_controller/dispatcher.rb +21 -6
- data/lib/action_controller/http_authentication.rb +3 -2
- data/lib/action_controller/params_parser.rb +6 -0
- data/lib/action_controller/reloader.rb +30 -21
- data/lib/action_controller/request_forgery_protection.rb +2 -1
- data/lib/action_controller/resources.rb +17 -13
- data/lib/action_controller/response.rb +6 -0
- data/lib/action_controller/routing.rb +3 -0
- data/lib/action_controller/routing/route_set.rb +18 -5
- data/lib/action_controller/streaming.rb +3 -1
- data/lib/action_controller/url_rewriter.rb +1 -1
- data/lib/action_pack/version.rb +1 -1
- data/lib/action_view/helpers/atom_feed_helper.rb +1 -1
- data/lib/action_view/helpers/form_helper.rb +3 -2
- data/lib/action_view/helpers/form_options_helper.rb +69 -1
- data/lib/action_view/helpers/tag_helper.rb +1 -1
- data/lib/action_view/helpers/text_helper.rb +20 -11
- data/lib/action_view/helpers/url_helper.rb +1 -1
- data/lib/action_view/locale/en.yml +4 -0
- data/test/abstract_unit.rb +16 -0
- data/test/controller/caching_test.rb +1 -1
- data/test/controller/cookie_test.rb +6 -0
- data/test/controller/dispatcher_test.rb +50 -11
- data/test/controller/filter_params_test.rb +2 -1
- data/test/controller/http_basic_authentication_test.rb +25 -0
- data/test/controller/http_digest_authentication_test.rb +29 -6
- data/test/controller/rack_test.rb +18 -1
- data/test/controller/redirect_test.rb +1 -1
- data/test/controller/reloader_test.rb +47 -20
- data/test/controller/request/json_params_parsing_test.rb +24 -4
- data/test/controller/request/xml_params_parsing_test.rb +15 -0
- data/test/controller/request_forgery_protection_test.rb +6 -5
- data/test/controller/resources_test.rb +44 -0
- data/test/controller/routing_test.rb +7 -2
- data/test/controller/send_file_test.rb +11 -1
- data/test/controller/url_rewriter_test.rb +29 -3
- data/test/fixtures/public/absolute/test.css +23 -0
- data/test/fixtures/public/absolute/test.js +63 -0
- data/test/template/atom_feed_helper_test.rb +29 -0
- data/test/template/form_helper_test.rb +26 -0
- data/test/template/form_options_helper_i18n_test.rb +27 -0
- data/test/template/form_options_helper_test.rb +34 -0
- data/test/template/text_helper_test.rb +23 -0
- data/test/template/url_helper_test.rb +8 -0
- metadata +10 -94
data/CHANGELOG
CHANGED
@@ -1,4 +1,13 @@
|
|
1
|
-
*2.3.
|
1
|
+
*2.3.4 (September 4, 2009)*
|
2
|
+
|
3
|
+
* Sanitize multibyte strings before escaping them with escape_once. CVE-2009-3009
|
4
|
+
|
5
|
+
* Introduce grouped_collection_select helper. #1249 [Dan Codeape, Erik Ostrom]
|
6
|
+
|
7
|
+
* Ruby 1.9: fix Content-Length for multibyte send_data streaming. #2661 [Sava Chankov]
|
8
|
+
|
9
|
+
|
10
|
+
*2.3.3 (July 12, 2009)*
|
2
11
|
|
3
12
|
* Fixed that TestResponse.cookies was returning cookies unescaped #1867 [Doug McInnes]
|
4
13
|
|
@@ -7,6 +16,8 @@
|
|
7
16
|
|
8
17
|
* Fixed that redirection would just log the options, not the final url (which lead to "Redirected to #<Post:0x23150b8>") [DHH]
|
9
18
|
|
19
|
+
* Don't check authenticity tokens for any AJAX requests [Ross Kaffenberger/Bryan Helmkamp]
|
20
|
+
|
10
21
|
* Added ability to pass in :public => true to fresh_when, stale?, and expires_in to make the request proxy cachable #2095 [Gregg Pollack]
|
11
22
|
|
12
23
|
* Fixed that passing a custom form builder would be forwarded to nested fields_for calls #2023 [Eloy Duran/Nate Wiger]
|
data/Rakefile
CHANGED
@@ -29,7 +29,7 @@ Rake::TestTask.new(:test_action_pack) do |t|
|
|
29
29
|
|
30
30
|
# make sure we include the tests in alphabetical order as on some systems
|
31
31
|
# this will not happen automatically and the tests (as a whole) will error
|
32
|
-
t.test_files = Dir.glob( "test/[
|
32
|
+
t.test_files = Dir.glob( "test/[cftv]*/**/*_test.rb" ).sort
|
33
33
|
|
34
34
|
t.verbose = true
|
35
35
|
#t.warning = true
|
@@ -79,7 +79,7 @@ spec = Gem::Specification.new do |s|
|
|
79
79
|
s.has_rdoc = true
|
80
80
|
s.requirements << 'none'
|
81
81
|
|
82
|
-
s.add_dependency('activesupport', '= 2.3.
|
82
|
+
s.add_dependency('activesupport', '= 2.3.4' + PKG_BUILD)
|
83
83
|
s.add_dependency('rack', '~> 1.0.0')
|
84
84
|
|
85
85
|
s.require_path = 'lib'
|
@@ -149,11 +149,12 @@ end
|
|
149
149
|
|
150
150
|
desc "Publish the release files to RubyForge."
|
151
151
|
task :release => [ :package ] do
|
152
|
-
|
152
|
+
require 'rubyforge'
|
153
|
+
require 'rake/contrib/rubyforgepublisher'
|
153
154
|
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
155
|
+
packages = %w( gem tgz zip ).collect{ |ext| "pkg/#{PKG_NAME}-#{PKG_VERSION}.#{ext}" }
|
156
|
+
|
157
|
+
rubyforge = RubyForge.new
|
158
|
+
rubyforge.login
|
159
|
+
rubyforge.add_release(PKG_NAME, PKG_NAME, "REL #{PKG_VERSION}", *packages)
|
159
160
|
end
|
@@ -64,7 +64,9 @@ module ActionController
|
|
64
64
|
# Support partial arguments for hash redirections
|
65
65
|
if options.is_a?(Hash) && @response.redirected_to.is_a?(Hash)
|
66
66
|
if options.all? {|(key, value)| @response.redirected_to[key] == value}
|
67
|
-
|
67
|
+
callstack = caller.dup
|
68
|
+
callstack.slice!(0, 2)
|
69
|
+
::ActiveSupport::Deprecation.warn("Using assert_redirected_to with partial hash arguments is deprecated. Specify the full set arguments instead", callstack)
|
68
70
|
return true
|
69
71
|
end
|
70
72
|
end
|
@@ -493,7 +493,12 @@ module ActionController #:nodoc:
|
|
493
493
|
filtered_parameters[key] = filter_parameters(value)
|
494
494
|
elsif value.is_a?(Array)
|
495
495
|
filtered_parameters[key] = value.collect do |item|
|
496
|
-
|
496
|
+
case item
|
497
|
+
when Hash, Array
|
498
|
+
filter_parameters(item)
|
499
|
+
else
|
500
|
+
item
|
501
|
+
end
|
497
502
|
end
|
498
503
|
elsif block_given?
|
499
504
|
key = key.dup
|
@@ -814,7 +819,6 @@ module ActionController #:nodoc:
|
|
814
819
|
# render :text => proc { |response, output|
|
815
820
|
# 10_000_000.times do |i|
|
816
821
|
# output.write("This is line #{i}\n")
|
817
|
-
# output.flush
|
818
822
|
# end
|
819
823
|
# }
|
820
824
|
#
|
@@ -2,13 +2,12 @@ module ActionController
|
|
2
2
|
# Dispatches requests to the appropriate controller and takes care of
|
3
3
|
# reloading the app after each request when Dependencies.load? is true.
|
4
4
|
class Dispatcher
|
5
|
+
@@cache_classes = true
|
6
|
+
|
5
7
|
class << self
|
6
8
|
def define_dispatcher_callbacks(cache_classes)
|
9
|
+
@@cache_classes = cache_classes
|
7
10
|
unless cache_classes
|
8
|
-
unless self.middleware.include?(Reloader)
|
9
|
-
self.middleware.insert_after(Failsafe, Reloader)
|
10
|
-
end
|
11
|
-
|
12
11
|
ActionView::Helpers::AssetTagHelper.cache_asset_timestamps = false
|
13
12
|
end
|
14
13
|
|
@@ -79,7 +78,7 @@ module ActionController
|
|
79
78
|
# DEPRECATE: Remove arguments, since they are only used by CGI
|
80
79
|
def initialize(output = $stdout, request = nil, response = nil)
|
81
80
|
@output = output
|
82
|
-
|
81
|
+
build_middleware_stack if @@cache_classes
|
83
82
|
end
|
84
83
|
|
85
84
|
def dispatch
|
@@ -103,7 +102,18 @@ module ActionController
|
|
103
102
|
end
|
104
103
|
|
105
104
|
def call(env)
|
106
|
-
|
105
|
+
if @@cache_classes
|
106
|
+
@app.call(env)
|
107
|
+
else
|
108
|
+
Reloader.run do
|
109
|
+
# When class reloading is turned on, we will want to rebuild the
|
110
|
+
# middleware stack every time we process a request. If we don't
|
111
|
+
# rebuild the middleware stack, then the stack may contain references
|
112
|
+
# to old classes metal classes, which will b0rk class reloading.
|
113
|
+
build_middleware_stack
|
114
|
+
@app.call(env)
|
115
|
+
end
|
116
|
+
end
|
107
117
|
end
|
108
118
|
|
109
119
|
def _call(env)
|
@@ -114,5 +124,10 @@ module ActionController
|
|
114
124
|
def flush_logger
|
115
125
|
Base.logger.flush
|
116
126
|
end
|
127
|
+
|
128
|
+
private
|
129
|
+
def build_middleware_stack
|
130
|
+
@app = @@middleware.build(lambda { |env| self.dup._call(env) })
|
131
|
+
end
|
117
132
|
end
|
118
133
|
end
|
@@ -139,7 +139,7 @@ module ActionController
|
|
139
139
|
end
|
140
140
|
|
141
141
|
def decode_credentials(request)
|
142
|
-
ActiveSupport::Base64.decode64(authorization(request).split.last || '')
|
142
|
+
ActiveSupport::Base64.decode64(authorization(request).split(' ', 2).last || '')
|
143
143
|
end
|
144
144
|
|
145
145
|
def encode_credentials(user_name, password)
|
@@ -195,9 +195,10 @@ module ActionController
|
|
195
195
|
return false unless password
|
196
196
|
|
197
197
|
method = request.env['rack.methodoverride.original_method'] || request.env['REQUEST_METHOD']
|
198
|
+
uri = credentials[:uri][0,1] == '/' ? request.request_uri : request.url
|
198
199
|
|
199
200
|
[true, false].any? do |password_is_ha1|
|
200
|
-
expected = expected_response(method,
|
201
|
+
expected = expected_response(method, uri, credentials, password, password_is_ha1)
|
201
202
|
expected == credentials[:response]
|
202
203
|
end
|
203
204
|
end
|
@@ -47,6 +47,8 @@ module ActionController
|
|
47
47
|
false
|
48
48
|
end
|
49
49
|
rescue Exception => e # YAML, XML or Ruby code block errors
|
50
|
+
logger.debug "Error occurred while parsing request parameters.\nContents:\n\n#{request.raw_post}"
|
51
|
+
|
50
52
|
raise
|
51
53
|
{ "body" => request.raw_post,
|
52
54
|
"content_type" => request.content_type,
|
@@ -67,5 +69,9 @@ module ActionController
|
|
67
69
|
|
68
70
|
nil
|
69
71
|
end
|
72
|
+
|
73
|
+
def logger
|
74
|
+
defined?(Rails.logger) ? Rails.logger : Logger.new($stderr)
|
75
|
+
end
|
70
76
|
end
|
71
77
|
end
|
@@ -1,14 +1,21 @@
|
|
1
|
+
require 'thread'
|
2
|
+
|
1
3
|
module ActionController
|
2
4
|
class Reloader
|
5
|
+
@@default_lock = Mutex.new
|
6
|
+
cattr_accessor :default_lock
|
7
|
+
|
3
8
|
class BodyWrapper
|
4
|
-
def initialize(body)
|
9
|
+
def initialize(body, lock)
|
5
10
|
@body = body
|
11
|
+
@lock = lock
|
6
12
|
end
|
7
13
|
|
8
14
|
def close
|
9
15
|
@body.close if @body.respond_to?(:close)
|
10
16
|
ensure
|
11
17
|
Dispatcher.cleanup_application
|
18
|
+
@lock.unlock
|
12
19
|
end
|
13
20
|
|
14
21
|
def method_missing(*args, &block)
|
@@ -20,26 +27,28 @@ module ActionController
|
|
20
27
|
end
|
21
28
|
end
|
22
29
|
|
23
|
-
def
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
30
|
+
def self.run(lock = @@default_lock)
|
31
|
+
lock.lock
|
32
|
+
begin
|
33
|
+
Dispatcher.reload_application
|
34
|
+
status, headers, body = yield
|
35
|
+
# We do not want to call 'cleanup_application' in an ensure block
|
36
|
+
# because the returned Rack response body may lazily generate its data. This
|
37
|
+
# is for example the case if one calls
|
38
|
+
#
|
39
|
+
# render :text => lambda { ... code here which refers to application models ... }
|
40
|
+
#
|
41
|
+
# in an ActionController.
|
42
|
+
#
|
43
|
+
# Instead, we will want to cleanup the application code after the request is
|
44
|
+
# completely finished. So we wrap the body in a BodyWrapper class so that
|
45
|
+
# when the Rack handler calls #close during the end of the request, we get to
|
46
|
+
# run our cleanup code.
|
47
|
+
[status, headers, BodyWrapper.new(body, lock)]
|
48
|
+
rescue Exception
|
49
|
+
lock.unlock
|
50
|
+
raise
|
51
|
+
end
|
43
52
|
end
|
44
53
|
end
|
45
54
|
end
|
@@ -81,12 +81,13 @@ module ActionController #:nodoc:
|
|
81
81
|
|
82
82
|
# Returns true or false if a request is verified. Checks:
|
83
83
|
#
|
84
|
-
# * is the format restricted? By default, only HTML
|
84
|
+
# * is the format restricted? By default, only HTML requests are checked.
|
85
85
|
# * is it a GET request? Gets should be safe and idempotent
|
86
86
|
# * Does the form_authenticity_token match the given token value from the params?
|
87
87
|
def verified_request?
|
88
88
|
!protect_against_forgery? ||
|
89
89
|
request.method == :get ||
|
90
|
+
request.xhr? ||
|
90
91
|
!verifiable_request_format? ||
|
91
92
|
form_authenticity_token == params[request_forgery_protection_token]
|
92
93
|
end
|
@@ -317,9 +317,10 @@ module ActionController
|
|
317
317
|
# notes.resources :attachments
|
318
318
|
# end
|
319
319
|
#
|
320
|
-
# * <tt>:path_names</tt> - Specify different names for the
|
320
|
+
# * <tt>:path_names</tt> - Specify different path names for the actions. For example:
|
321
321
|
# # new_products_path == '/productos/nuevo'
|
322
|
-
#
|
322
|
+
# # bids_product_path(1) == '/productos/1/licitacoes'
|
323
|
+
# map.resources :products, :as => 'productos', :member => { :bids => :get }, :path_names => { :new => 'nuevo', :bids => 'licitacoes' }
|
323
324
|
#
|
324
325
|
# You can also set default action names from an environment, like this:
|
325
326
|
# config.action_controller.resources_path_names = { :new => 'nuevo', :edit => 'editar' }
|
@@ -525,16 +526,16 @@ module ActionController
|
|
525
526
|
resource = Resource.new(entities, options)
|
526
527
|
|
527
528
|
with_options :controller => resource.controller do |map|
|
528
|
-
map_collection_actions(map, resource)
|
529
|
-
map_default_collection_actions(map, resource)
|
530
|
-
map_new_actions(map, resource)
|
531
|
-
map_member_actions(map, resource)
|
532
|
-
|
533
529
|
map_associations(resource, options)
|
534
530
|
|
535
531
|
if block_given?
|
536
532
|
with_options(options.slice(*INHERITABLE_OPTIONS).merge(:path_prefix => resource.nesting_path_prefix, :name_prefix => resource.nesting_name_prefix), &block)
|
537
533
|
end
|
534
|
+
|
535
|
+
map_collection_actions(map, resource)
|
536
|
+
map_default_collection_actions(map, resource)
|
537
|
+
map_new_actions(map, resource)
|
538
|
+
map_member_actions(map, resource)
|
538
539
|
end
|
539
540
|
end
|
540
541
|
|
@@ -542,16 +543,16 @@ module ActionController
|
|
542
543
|
resource = SingletonResource.new(entities, options)
|
543
544
|
|
544
545
|
with_options :controller => resource.controller do |map|
|
545
|
-
map_collection_actions(map, resource)
|
546
|
-
map_new_actions(map, resource)
|
547
|
-
map_member_actions(map, resource)
|
548
|
-
map_default_singleton_actions(map, resource)
|
549
|
-
|
550
546
|
map_associations(resource, options)
|
551
547
|
|
552
548
|
if block_given?
|
553
549
|
with_options(options.slice(*INHERITABLE_OPTIONS).merge(:path_prefix => resource.nesting_path_prefix, :name_prefix => resource.nesting_name_prefix), &block)
|
554
550
|
end
|
551
|
+
|
552
|
+
map_collection_actions(map, resource)
|
553
|
+
map_new_actions(map, resource)
|
554
|
+
map_member_actions(map, resource)
|
555
|
+
map_default_singleton_actions(map, resource)
|
555
556
|
end
|
556
557
|
end
|
557
558
|
|
@@ -586,7 +587,10 @@ module ActionController
|
|
586
587
|
resource.collection_methods.each do |method, actions|
|
587
588
|
actions.each do |action|
|
588
589
|
[method].flatten.each do |m|
|
589
|
-
|
590
|
+
action_path = resource.options[:path_names][action] if resource.options[:path_names].is_a?(Hash)
|
591
|
+
action_path ||= action
|
592
|
+
|
593
|
+
map_resource_routes(map, resource, action, "#{resource.path}#{resource.action_separator}#{action_path}", "#{action}_#{resource.name_prefix}#{resource.plural}", m)
|
590
594
|
end
|
591
595
|
end
|
592
596
|
end
|
@@ -166,6 +166,12 @@ module ActionController # :nodoc:
|
|
166
166
|
str
|
167
167
|
end
|
168
168
|
|
169
|
+
def flush #:nodoc:
|
170
|
+
ActiveSupport::Deprecation.warn(
|
171
|
+
'Calling output.flush is no longer needed for streaming output ' +
|
172
|
+
'because ActionController::Response automatically handles it', caller)
|
173
|
+
end
|
174
|
+
|
169
175
|
def set_cookie(key, value)
|
170
176
|
if value.has_key?(:http_only)
|
171
177
|
ActiveSupport::Deprecation.warn(
|
@@ -271,6 +271,9 @@ module ActionController
|
|
271
271
|
|
272
272
|
ALLOWED_REQUIREMENTS_FOR_OPTIMISATION = [:controller, :action].to_set
|
273
273
|
|
274
|
+
mattr_accessor :generate_best_match
|
275
|
+
self.generate_best_match = true
|
276
|
+
|
274
277
|
# The root paths which may contain controller files
|
275
278
|
mattr_accessor :controller_paths
|
276
279
|
self.controller_paths = []
|
@@ -405,11 +405,14 @@ module ActionController
|
|
405
405
|
end
|
406
406
|
|
407
407
|
# don't use the recalled keys when determining which routes to check
|
408
|
-
|
408
|
+
future_routes, deprecated_routes = routes_by_controller[controller][action][options.reject {|k,v| !v}.keys.sort_by { |x| x.object_id }]
|
409
|
+
routes = Routing.generate_best_match ? deprecated_routes : future_routes
|
409
410
|
|
410
|
-
routes.
|
411
|
+
routes.each_with_index do |route, index|
|
411
412
|
results = route.__send__(method, options, merged, expire_on)
|
412
|
-
|
413
|
+
if results && (!results.is_a?(Array) || results.first)
|
414
|
+
return results
|
415
|
+
end
|
413
416
|
end
|
414
417
|
end
|
415
418
|
|
@@ -448,7 +451,10 @@ module ActionController
|
|
448
451
|
@routes_by_controller ||= Hash.new do |controller_hash, controller|
|
449
452
|
controller_hash[controller] = Hash.new do |action_hash, action|
|
450
453
|
action_hash[action] = Hash.new do |key_hash, keys|
|
451
|
-
key_hash[keys] =
|
454
|
+
key_hash[keys] = [
|
455
|
+
routes_for_controller_and_action_and_keys(controller, action, keys),
|
456
|
+
deprecated_routes_for_controller_and_action_and_keys(controller, action, keys)
|
457
|
+
]
|
452
458
|
end
|
453
459
|
end
|
454
460
|
end
|
@@ -460,10 +466,11 @@ module ActionController
|
|
460
466
|
merged = options if expire_on[:controller]
|
461
467
|
action = merged[:action] || 'index'
|
462
468
|
|
463
|
-
routes_by_controller[controller][action][merged.keys]
|
469
|
+
routes_by_controller[controller][action][merged.keys][1]
|
464
470
|
end
|
465
471
|
|
466
472
|
def routes_for_controller_and_action(controller, action)
|
473
|
+
ActiveSupport::Deprecation.warn "routes_for_controller_and_action() has been deprecated. Please use routes_for()"
|
467
474
|
selected = routes.select do |route|
|
468
475
|
route.matches_controller_and_action? controller, action
|
469
476
|
end
|
@@ -471,6 +478,12 @@ module ActionController
|
|
471
478
|
end
|
472
479
|
|
473
480
|
def routes_for_controller_and_action_and_keys(controller, action, keys)
|
481
|
+
routes.select do |route|
|
482
|
+
route.matches_controller_and_action? controller, action
|
483
|
+
end
|
484
|
+
end
|
485
|
+
|
486
|
+
def deprecated_routes_for_controller_and_action_and_keys(controller, action, keys)
|
474
487
|
selected = routes.select do |route|
|
475
488
|
route.matches_controller_and_action? controller, action
|
476
489
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'active_support/core_ext/string/bytesize'
|
2
|
+
|
1
3
|
module ActionController #:nodoc:
|
2
4
|
# Methods for sending arbitrary data and for streaming files to the browser,
|
3
5
|
# instead of rendering.
|
@@ -137,7 +139,7 @@ module ActionController #:nodoc:
|
|
137
139
|
# instead. See ActionController::Base#render for more information.
|
138
140
|
def send_data(data, options = {}) #:doc:
|
139
141
|
logger.info "Sending data #{options[:filename]}" if logger
|
140
|
-
send_file_headers! options.merge(:length => data.
|
142
|
+
send_file_headers! options.merge(:length => data.bytesize)
|
141
143
|
@performed_render = false
|
142
144
|
render :status => options[:status], :text => data
|
143
145
|
end
|