actionpack 2.0.5 → 2.1.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.
- data/CHANGELOG +149 -7
- data/MIT-LICENSE +1 -1
- data/README +1 -1
- data/Rakefile +5 -6
- data/lib/action_controller.rb +2 -2
- data/lib/action_controller/assertions/model_assertions.rb +2 -1
- data/lib/action_controller/assertions/response_assertions.rb +4 -2
- data/lib/action_controller/assertions/routing_assertions.rb +3 -3
- data/lib/action_controller/assertions/selector_assertions.rb +30 -27
- data/lib/action_controller/assertions/tag_assertions.rb +3 -3
- data/lib/action_controller/base.rb +103 -129
- data/lib/action_controller/benchmarking.rb +3 -3
- data/lib/action_controller/caching.rb +41 -652
- data/lib/action_controller/caching/actions.rb +144 -0
- data/lib/action_controller/caching/fragments.rb +138 -0
- data/lib/action_controller/caching/pages.rb +154 -0
- data/lib/action_controller/caching/sql_cache.rb +18 -0
- data/lib/action_controller/caching/sweeping.rb +97 -0
- data/lib/action_controller/cgi_ext/cookie.rb +27 -23
- data/lib/action_controller/cgi_ext/stdinput.rb +1 -0
- data/lib/action_controller/cgi_process.rb +6 -4
- data/lib/action_controller/components.rb +7 -6
- data/lib/action_controller/cookies.rb +31 -19
- data/lib/action_controller/dispatcher.rb +51 -84
- data/lib/action_controller/filters.rb +295 -421
- data/lib/action_controller/flash.rb +1 -6
- data/lib/action_controller/headers.rb +31 -0
- data/lib/action_controller/helpers.rb +26 -9
- data/lib/action_controller/http_authentication.rb +1 -1
- data/lib/action_controller/integration.rb +65 -13
- data/lib/action_controller/layout.rb +24 -39
- data/lib/action_controller/mime_responds.rb +7 -3
- data/lib/action_controller/mime_type.rb +25 -9
- data/lib/action_controller/mime_types.rb +1 -1
- data/lib/action_controller/polymorphic_routes.rb +32 -17
- data/lib/action_controller/record_identifier.rb +10 -4
- data/lib/action_controller/request.rb +46 -30
- data/lib/action_controller/request_forgery_protection.rb +10 -9
- data/lib/action_controller/request_profiler.rb +29 -8
- data/lib/action_controller/rescue.rb +24 -24
- data/lib/action_controller/resources.rb +66 -23
- data/lib/action_controller/response.rb +2 -2
- data/lib/action_controller/routing.rb +113 -1229
- data/lib/action_controller/routing/builder.rb +204 -0
- data/lib/action_controller/{routing_optimisation.rb → routing/optimisations.rb} +13 -12
- data/lib/action_controller/routing/recognition_optimisation.rb +158 -0
- data/lib/action_controller/routing/route.rb +240 -0
- data/lib/action_controller/routing/route_set.rb +435 -0
- data/lib/action_controller/routing/routing_ext.rb +46 -0
- data/lib/action_controller/routing/segments.rb +283 -0
- data/lib/action_controller/session/active_record_store.rb +13 -8
- data/lib/action_controller/session/cookie_store.rb +20 -17
- data/lib/action_controller/session_management.rb +10 -3
- data/lib/action_controller/streaming.rb +45 -31
- data/lib/action_controller/test_case.rb +33 -23
- data/lib/action_controller/test_process.rb +39 -35
- data/lib/action_controller/url_rewriter.rb +18 -12
- data/lib/action_controller/vendor/html-scanner/html/tokenizer.rb +1 -1
- data/lib/action_pack.rb +1 -1
- data/lib/action_pack/version.rb +2 -2
- data/lib/action_view.rb +11 -3
- data/lib/action_view/base.rb +73 -390
- data/lib/action_view/helpers/active_record_helper.rb +83 -62
- data/lib/action_view/helpers/asset_tag_helper.rb +101 -44
- data/lib/action_view/helpers/atom_feed_helper.rb +35 -7
- data/lib/action_view/helpers/benchmark_helper.rb +5 -3
- data/lib/action_view/helpers/cache_helper.rb +3 -2
- data/lib/action_view/helpers/capture_helper.rb +1 -2
- data/lib/action_view/helpers/date_helper.rb +104 -82
- data/lib/action_view/helpers/form_helper.rb +148 -75
- data/lib/action_view/helpers/form_options_helper.rb +44 -23
- data/lib/action_view/helpers/form_tag_helper.rb +22 -13
- data/lib/action_view/helpers/javascripts/controls.js +1 -1
- data/lib/action_view/helpers/javascripts/dragdrop.js +1 -1
- data/lib/action_view/helpers/javascripts/effects.js +1 -1
- data/lib/action_view/helpers/number_helper.rb +10 -3
- data/lib/action_view/helpers/prototype_helper.rb +61 -29
- data/lib/action_view/helpers/record_tag_helper.rb +3 -3
- data/lib/action_view/helpers/sanitize_helper.rb +23 -17
- data/lib/action_view/helpers/scriptaculous_helper.rb +86 -60
- data/lib/action_view/helpers/text_helper.rb +153 -125
- data/lib/action_view/helpers/url_helper.rb +83 -28
- data/lib/action_view/inline_template.rb +20 -0
- data/lib/action_view/partial_template.rb +70 -0
- data/lib/action_view/partials.rb +31 -73
- data/lib/action_view/template.rb +127 -0
- data/lib/action_view/template_error.rb +8 -7
- data/lib/action_view/template_finder.rb +177 -0
- data/lib/action_view/template_handler.rb +18 -1
- data/lib/action_view/template_handlers/builder.rb +10 -2
- data/lib/action_view/template_handlers/compilable.rb +128 -0
- data/lib/action_view/template_handlers/erb.rb +37 -2
- data/lib/action_view/template_handlers/rjs.rb +14 -1
- data/lib/action_view/test_case.rb +58 -0
- data/test/abstract_unit.rb +1 -1
- data/test/active_record_unit.rb +3 -6
- data/test/activerecord/active_record_store_test.rb +1 -2
- data/test/activerecord/render_partial_with_record_identification_test.rb +158 -41
- data/test/adv_attr_test.rb +20 -0
- data/test/controller/action_pack_assertions_test.rb +16 -19
- data/test/controller/addresses_render_test.rb +1 -1
- data/test/controller/assert_select_test.rb +13 -6
- data/test/controller/base_test.rb +48 -2
- data/test/controller/benchmark_test.rb +1 -2
- data/test/controller/caching_test.rb +282 -21
- data/test/controller/capture_test.rb +1 -1
- data/test/controller/cgi_test.rb +1 -1
- data/test/controller/components_test.rb +1 -1
- data/test/controller/content_type_test.rb +2 -2
- data/test/controller/cookie_test.rb +13 -2
- data/test/controller/custom_handler_test.rb +14 -10
- data/test/controller/deprecation/deprecated_base_methods_test.rb +1 -1
- data/test/controller/dispatcher_test.rb +31 -49
- data/test/controller/fake_controllers.rb +17 -0
- data/test/controller/fake_models.rb +6 -0
- data/test/controller/filter_params_test.rb +14 -8
- data/test/controller/filters_test.rb +44 -16
- data/test/controller/flash_test.rb +2 -2
- data/test/controller/header_test.rb +14 -0
- data/test/controller/helper_test.rb +19 -15
- data/test/controller/html-scanner/document_test.rb +1 -2
- data/test/controller/html-scanner/node_test.rb +1 -2
- data/test/controller/html-scanner/sanitizer_test.rb +8 -5
- data/test/controller/html-scanner/tag_node_test.rb +1 -2
- data/test/controller/html-scanner/text_node_test.rb +2 -3
- data/test/controller/html-scanner/tokenizer_test.rb +8 -2
- data/test/controller/http_authentication_test.rb +1 -1
- data/test/controller/integration_test.rb +14 -16
- data/test/controller/integration_upload_test.rb +43 -0
- data/test/controller/layout_test.rb +26 -6
- data/test/controller/mime_responds_test.rb +39 -7
- data/test/controller/mime_type_test.rb +29 -5
- data/test/controller/new_render_test.rb +105 -34
- data/test/controller/polymorphic_routes_test.rb +32 -20
- data/test/controller/record_identifier_test.rb +38 -2
- data/test/controller/redirect_test.rb +21 -1
- data/test/controller/render_test.rb +59 -15
- data/test/controller/request_forgery_protection_test.rb +92 -5
- data/test/controller/request_test.rb +64 -6
- data/test/controller/rescue_test.rb +22 -6
- data/test/controller/resources_test.rb +102 -14
- data/test/controller/routing_test.rb +231 -19
- data/test/controller/selector_test.rb +2 -2
- data/test/controller/send_file_test.rb +14 -3
- data/test/controller/session/cookie_store_test.rb +16 -4
- data/test/controller/session/mem_cache_store_test.rb +3 -4
- data/test/controller/session_fixation_test.rb +1 -1
- data/test/controller/session_management_test.rb +23 -1
- data/test/controller/test_test.rb +39 -18
- data/test/controller/url_rewriter_test.rb +35 -1
- data/test/controller/verification_test.rb +1 -1
- data/test/controller/view_paths_test.rb +15 -12
- data/test/controller/webservice_test.rb +48 -3
- data/test/fixtures/bad_customers/_bad_customer.html.erb +1 -0
- data/test/fixtures/company.rb +1 -0
- data/test/fixtures/customers/_customer.html.erb +1 -0
- data/test/fixtures/db_definitions/sqlite.sql +6 -0
- data/test/fixtures/functional_caching/_partial.erb +3 -0
- data/test/fixtures/functional_caching/fragment_cached.html.erb +2 -0
- data/test/fixtures/functional_caching/html_fragment_cached_with_partial.html.erb +1 -0
- data/test/fixtures/functional_caching/js_fragment_cached_with_partial.js.rjs +1 -0
- data/test/fixtures/good_customers/_good_customer.html.erb +1 -0
- data/test/fixtures/mascot.rb +3 -0
- data/test/fixtures/mascots.yml +4 -0
- data/test/fixtures/mascots/_mascot.html.erb +1 -0
- data/test/fixtures/multipart/boundary_problem_file +10 -0
- data/test/fixtures/public/javascripts/application.js +1 -0
- data/test/fixtures/public/javascripts/controls.js +1 -0
- data/test/fixtures/public/javascripts/dragdrop.js +1 -0
- data/test/fixtures/public/javascripts/effects.js +1 -0
- data/test/fixtures/public/javascripts/prototype.js +1 -0
- data/test/fixtures/public/javascripts/version.1.0.js +1 -0
- data/test/fixtures/public/stylesheets/version.1.0.css +1 -0
- data/test/fixtures/reply.rb +1 -0
- data/test/fixtures/shared.html.erb +1 -0
- data/test/fixtures/symlink_parent/symlinked_layout.erb +5 -0
- data/test/fixtures/test/_customer_counter.erb +1 -0
- data/test/fixtures/test/_form.erb +1 -0
- data/test/fixtures/test/_labelling_form.erb +1 -0
- data/test/fixtures/test/_raise.html.erb +1 -0
- data/test/fixtures/test/greeting.js.rjs +1 -0
- data/test/fixtures/topics/_topic.html.erb +1 -0
- data/test/template/active_record_helper_test.rb +25 -8
- data/test/template/asset_tag_helper_test.rb +100 -17
- data/test/template/atom_feed_helper_test.rb +29 -1
- data/test/template/benchmark_helper_test.rb +10 -22
- data/test/template/date_helper_test.rb +455 -153
- data/test/template/erb_util_test.rb +10 -42
- data/test/template/form_helper_test.rb +192 -66
- data/test/template/form_options_helper_test.rb +19 -8
- data/test/template/form_tag_helper_test.rb +11 -8
- data/test/template/javascript_helper_test.rb +3 -9
- data/test/template/number_helper_test.rb +6 -3
- data/test/template/prototype_helper_test.rb +27 -40
- data/test/template/record_tag_helper_test.rb +54 -0
- data/test/template/sanitize_helper_test.rb +5 -6
- data/test/template/scriptaculous_helper_test.rb +7 -13
- data/test/template/tag_helper_test.rb +3 -6
- data/test/template/template_finder_test.rb +73 -0
- data/test/template/template_object_test.rb +95 -0
- data/test/template/test_test.rb +56 -0
- data/test/template/text_helper_test.rb +46 -33
- data/test/template/url_helper_test.rb +8 -10
- metadata +65 -12
- data/lib/action_view/compiled_templates.rb +0 -69
- data/test/action_view_test.rb +0 -44
- data/test/activerecord/fixtures_test.rb +0 -24
- data/test/controller/fragment_store_setting_test.rb +0 -47
- data/test/template/compiled_templates_test.rb +0 -197
- data/test/template/deprecate_ivars_test.rb +0 -51
@@ -92,7 +92,7 @@ module ActionController #:nodoc:
|
|
92
92
|
# with the remaining data.
|
93
93
|
#
|
94
94
|
# Note that you can define your own XML parameter parser which would allow you to describe multiple entities
|
95
|
-
# in a single request (i.e., by wrapping them all in a single root
|
95
|
+
# in a single request (i.e., by wrapping them all in a single root node), but if you just go with the flow
|
96
96
|
# and accept Rails' defaults, life will be much easier.
|
97
97
|
#
|
98
98
|
# If you need to use a MIME type which isn't supported by default, you can register your own handlers in
|
@@ -125,7 +125,7 @@ module ActionController #:nodoc:
|
|
125
125
|
|
126
126
|
@order << mime_type
|
127
127
|
|
128
|
-
@responses[mime_type]
|
128
|
+
@responses[mime_type] ||= Proc.new do
|
129
129
|
@response.template.template_format = mime_type.to_sym
|
130
130
|
@response.content_type = mime_type.to_s
|
131
131
|
block_given? ? block.call : @controller.send(:render, :action => @controller.action_name)
|
@@ -133,7 +133,11 @@ module ActionController #:nodoc:
|
|
133
133
|
end
|
134
134
|
|
135
135
|
def any(*args, &block)
|
136
|
-
args.
|
136
|
+
if args.any?
|
137
|
+
args.each { |type| send(type, &block) }
|
138
|
+
else
|
139
|
+
custom(@mime_type_priority.first, &block)
|
140
|
+
end
|
137
141
|
end
|
138
142
|
|
139
143
|
def method_missing(symbol, &block)
|
@@ -17,6 +17,10 @@ module Mime
|
|
17
17
|
# end
|
18
18
|
# end
|
19
19
|
class Type
|
20
|
+
@@html_types = Set.new [:html, :all]
|
21
|
+
@@unverifiable_types = Set.new [:text, :json, :csv, :xml, :rss, :atom, :yaml]
|
22
|
+
cattr_reader :html_types, :unverifiable_types
|
23
|
+
|
20
24
|
# A simple helper class used in parsing the accept header
|
21
25
|
class AcceptItem #:nodoc:
|
22
26
|
attr_accessor :order, :name, :q
|
@@ -71,8 +75,11 @@ module Mime
|
|
71
75
|
# keep track of creation order to keep the subsequent sort stable
|
72
76
|
list = []
|
73
77
|
accept_header.split(/,/).each_with_index do |header, index|
|
74
|
-
params = header.split(/;\s*q=/)
|
75
|
-
|
78
|
+
params, q = header.split(/;\s*q=/)
|
79
|
+
if params
|
80
|
+
params.strip!
|
81
|
+
list << AcceptItem.new(index, params, q) unless params.empty?
|
82
|
+
end
|
76
83
|
end
|
77
84
|
list.sort!
|
78
85
|
|
@@ -97,7 +104,7 @@ module Mime
|
|
97
104
|
list[text_xml].name = Mime::XML.to_s
|
98
105
|
end
|
99
106
|
|
100
|
-
# Look for more specific
|
107
|
+
# Look for more specific XML-based types and sort them ahead of app/xml
|
101
108
|
|
102
109
|
if app_xml
|
103
110
|
idx = app_xml
|
@@ -145,17 +152,26 @@ module Mime
|
|
145
152
|
end
|
146
153
|
|
147
154
|
def ==(mime_type)
|
148
|
-
return false
|
149
|
-
(@synonyms + [ self ]).any? do |synonym|
|
150
|
-
synonym.to_s == mime_type.to_s || synonym.to_sym == mime_type.to_sym
|
155
|
+
return false if mime_type.blank?
|
156
|
+
(@synonyms + [ self ]).any? do |synonym|
|
157
|
+
synonym.to_s == mime_type.to_s || synonym.to_sym == mime_type.to_sym
|
151
158
|
end
|
152
159
|
end
|
153
|
-
|
160
|
+
|
161
|
+
# Returns true if Action Pack should check requests using this Mime Type for possible request forgery. See
|
162
|
+
# ActionController::RequestForgerProtection.
|
163
|
+
def verify_request?
|
164
|
+
!@@unverifiable_types.include?(to_sym)
|
165
|
+
end
|
166
|
+
|
167
|
+
def html?
|
168
|
+
@@html_types.include?(to_sym) || @string =~ /html/
|
169
|
+
end
|
170
|
+
|
154
171
|
private
|
155
172
|
def method_missing(method, *args)
|
156
173
|
if method.to_s =~ /(\w+)\?$/
|
157
|
-
|
158
|
-
mime_type == @symbol || (mime_type == :html && @symbol == :all)
|
174
|
+
$1.downcase.to_sym == to_sym
|
159
175
|
else
|
160
176
|
super
|
161
177
|
end
|
@@ -17,4 +17,4 @@ Mime::Type.register "multipart/form-data", :multipart_form
|
|
17
17
|
Mime::Type.register "application/x-www-form-urlencoded", :url_encoded_form
|
18
18
|
|
19
19
|
# http://www.ietf.org/rfc/rfc4627.txt
|
20
|
-
Mime::Type.register "application/json", :json, %w( text/x-json )
|
20
|
+
Mime::Type.register "application/json", :json, %w( text/x-json )
|
@@ -1,6 +1,6 @@
|
|
1
1
|
module ActionController
|
2
2
|
# Polymorphic URL helpers are methods for smart resolution to a named route call when
|
3
|
-
# given an
|
3
|
+
# given an Active Record model instance. They are to be used in combination with
|
4
4
|
# ActionController::Resources.
|
5
5
|
#
|
6
6
|
# These methods are useful when you want to generate correct URL or path to a RESTful
|
@@ -9,7 +9,9 @@ module ActionController
|
|
9
9
|
# Nested resources and/or namespaces are also supported, as illustrated in the example:
|
10
10
|
#
|
11
11
|
# polymorphic_url([:admin, @article, @comment])
|
12
|
-
#
|
12
|
+
#
|
13
|
+
# results in:
|
14
|
+
#
|
13
15
|
# admin_article_comment_url(@article, @comment)
|
14
16
|
#
|
15
17
|
# == Usage within the framework
|
@@ -19,7 +21,7 @@ module ActionController
|
|
19
21
|
# * <tt>url_for</tt>, so you can use it with a record as the argument, e.g.
|
20
22
|
# <tt>url_for(@article)</tt>;
|
21
23
|
# * ActionView::Helpers::FormHelper uses <tt>polymorphic_path</tt>, so you can write
|
22
|
-
# <tt>form_for(@article)</tt> without having to specify
|
24
|
+
# <tt>form_for(@article)</tt> without having to specify <tt>:url</tt> parameter for the form
|
23
25
|
# action;
|
24
26
|
# * <tt>redirect_to</tt> (which, in fact, uses <tt>url_for</tt>) so you can write
|
25
27
|
# <tt>redirect_to(post)</tt> in your controllers;
|
@@ -38,38 +40,41 @@ module ActionController
|
|
38
40
|
#
|
39
41
|
# Example usage:
|
40
42
|
#
|
41
|
-
# edit_polymorphic_path(@post)
|
42
|
-
#
|
43
|
-
#
|
44
|
-
# formatted_polymorphic_path([@post, :pdf])
|
45
|
-
# #=> /posts/1.pdf
|
43
|
+
# edit_polymorphic_path(@post) # => "/posts/1/edit"
|
44
|
+
# formatted_polymorphic_path([@post, :pdf]) # => "/posts/1.pdf"
|
46
45
|
module PolymorphicRoutes
|
47
46
|
# Constructs a call to a named RESTful route for the given record and returns the
|
48
47
|
# resulting URL string. For example:
|
49
48
|
#
|
50
|
-
#
|
51
|
-
#
|
49
|
+
# # calls post_url(post)
|
50
|
+
# polymorphic_url(post) # => "http://example.com/posts/1"
|
52
51
|
#
|
53
52
|
# ==== Options
|
54
|
-
#
|
55
|
-
#
|
56
|
-
#
|
53
|
+
#
|
54
|
+
# * <tt>:action</tt> - Specifies the action prefix for the named route:
|
55
|
+
# <tt>:new</tt>, <tt>:edit</tt>, or <tt>:formatted</tt>. Default is no prefix.
|
56
|
+
# * <tt>:routing_type</tt> - Allowed values are <tt>:path</tt> or <tt>:url</tt>.
|
57
|
+
# Default is <tt>:url</tt>.
|
57
58
|
#
|
58
59
|
# ==== Examples
|
59
60
|
#
|
60
61
|
# # an Article record
|
61
|
-
# polymorphic_url(record)
|
62
|
+
# polymorphic_url(record) # same as article_url(record)
|
62
63
|
#
|
63
64
|
# # a Comment record
|
64
|
-
# polymorphic_url(record)
|
65
|
+
# polymorphic_url(record) # same as comment_url(record)
|
65
66
|
#
|
66
67
|
# # it recognizes new records and maps to the collection
|
67
68
|
# record = Comment.new
|
68
|
-
# polymorphic_url(record)
|
69
|
+
# polymorphic_url(record) # same as comments_url()
|
69
70
|
#
|
70
71
|
def polymorphic_url(record_or_hash_or_array, options = {})
|
72
|
+
if record_or_hash_or_array.kind_of?(Array)
|
73
|
+
record_or_hash_or_array = record_or_hash_or_array.dup
|
74
|
+
end
|
75
|
+
|
71
76
|
record = extract_record(record_or_hash_or_array)
|
72
|
-
format = (options
|
77
|
+
format = extract_format(record_or_hash_or_array, options)
|
73
78
|
namespace = extract_namespace(record_or_hash_or_array)
|
74
79
|
|
75
80
|
args = case record_or_hash_or_array
|
@@ -148,6 +153,16 @@ module ActionController
|
|
148
153
|
end
|
149
154
|
end
|
150
155
|
|
156
|
+
def extract_format(record_or_hash_or_array, options)
|
157
|
+
if options[:action].to_s == "formatted" && record_or_hash_or_array.is_a?(Array)
|
158
|
+
record_or_hash_or_array.pop
|
159
|
+
elsif options[:format]
|
160
|
+
options[:format]
|
161
|
+
else
|
162
|
+
nil
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
151
166
|
def extract_namespace(record_or_hash_or_array)
|
152
167
|
returning "" do |namespace|
|
153
168
|
if record_or_hash_or_array.is_a?(Array)
|
@@ -33,11 +33,17 @@ module ActionController
|
|
33
33
|
|
34
34
|
# Returns plural/singular for a record or class. Example:
|
35
35
|
#
|
36
|
-
# partial_path(post)
|
37
|
-
# partial_path(Person)
|
38
|
-
|
36
|
+
# partial_path(post) # => "posts/post"
|
37
|
+
# partial_path(Person) # => "people/person"
|
38
|
+
# partial_path(Person, "admin/games") # => "admin/people/person"
|
39
|
+
def partial_path(record_or_class, controller_path = nil)
|
39
40
|
klass = class_from_record_or_class(record_or_class)
|
40
|
-
|
41
|
+
|
42
|
+
if controller_path && controller_path.include?("/")
|
43
|
+
"#{File.dirname(controller_path)}/#{klass.name.tableize}/#{klass.name.demodulize.underscore}"
|
44
|
+
else
|
45
|
+
"#{klass.name.tableize}/#{klass.name.demodulize.underscore}"
|
46
|
+
end
|
41
47
|
end
|
42
48
|
|
43
49
|
# The DOM class convention is to use the singular form of an object or class. Examples:
|
@@ -15,7 +15,7 @@ module ActionController
|
|
15
15
|
# such as { 'RAILS_ENV' => 'production' }.
|
16
16
|
attr_reader :env
|
17
17
|
|
18
|
-
# The true HTTP request method as a lowercase symbol, such as
|
18
|
+
# The true HTTP request method as a lowercase symbol, such as <tt>:get</tt>.
|
19
19
|
# UnknownHttpMethod is raised for invalid methods not listed in ACCEPTED_HTTP_METHODS.
|
20
20
|
def request_method
|
21
21
|
@request_method ||= begin
|
@@ -28,41 +28,43 @@ module ActionController
|
|
28
28
|
end
|
29
29
|
end
|
30
30
|
|
31
|
-
# The HTTP request method as a lowercase symbol, such as
|
32
|
-
# Note, HEAD is returned as
|
31
|
+
# The HTTP request method as a lowercase symbol, such as <tt>:get</tt>.
|
32
|
+
# Note, HEAD is returned as <tt>:get</tt> since the two are functionally
|
33
33
|
# equivalent from the application's perspective.
|
34
34
|
def method
|
35
35
|
request_method == :head ? :get : request_method
|
36
36
|
end
|
37
37
|
|
38
|
-
# Is this a GET (or HEAD) request? Equivalent to request.method == :get
|
38
|
+
# Is this a GET (or HEAD) request? Equivalent to <tt>request.method == :get</tt>.
|
39
39
|
def get?
|
40
40
|
method == :get
|
41
41
|
end
|
42
42
|
|
43
|
-
# Is this a POST request? Equivalent to request.method == :post
|
43
|
+
# Is this a POST request? Equivalent to <tt>request.method == :post</tt>.
|
44
44
|
def post?
|
45
45
|
request_method == :post
|
46
46
|
end
|
47
47
|
|
48
|
-
# Is this a PUT request? Equivalent to request.method == :put
|
48
|
+
# Is this a PUT request? Equivalent to <tt>request.method == :put</tt>.
|
49
49
|
def put?
|
50
50
|
request_method == :put
|
51
51
|
end
|
52
52
|
|
53
|
-
# Is this a DELETE request? Equivalent to request.method == :delete
|
53
|
+
# Is this a DELETE request? Equivalent to <tt>request.method == :delete</tt>.
|
54
54
|
def delete?
|
55
55
|
request_method == :delete
|
56
56
|
end
|
57
57
|
|
58
|
-
# Is this a HEAD request? request.method sees HEAD as
|
59
|
-
# HTTP method directly.
|
58
|
+
# Is this a HEAD request? <tt>request.method</tt> sees HEAD as <tt>:get</tt>,
|
59
|
+
# so check the HTTP method directly.
|
60
60
|
def head?
|
61
61
|
request_method == :head
|
62
62
|
end
|
63
63
|
|
64
|
+
# Provides acccess to the request's HTTP headers, for example:
|
65
|
+
# request.headers["Content-Type"] # => "text/plain"
|
64
66
|
def headers
|
65
|
-
@env
|
67
|
+
@headers ||= ActionController::Http::Headers.new(@env)
|
66
68
|
end
|
67
69
|
|
68
70
|
def content_length
|
@@ -400,6 +402,14 @@ EOM
|
|
400
402
|
body.blank? ? {} : Hash.from_xml(body).with_indifferent_access
|
401
403
|
when :yaml
|
402
404
|
YAML.load(body)
|
405
|
+
when :json
|
406
|
+
if body.blank?
|
407
|
+
{}
|
408
|
+
else
|
409
|
+
data = ActiveSupport::JSON.decode(body)
|
410
|
+
data = {:_json => data} unless data.is_a?(Hash)
|
411
|
+
data.with_indifferent_access
|
412
|
+
end
|
403
413
|
else
|
404
414
|
{}
|
405
415
|
end
|
@@ -456,8 +466,8 @@ EOM
|
|
456
466
|
parser.result
|
457
467
|
end
|
458
468
|
|
459
|
-
def parse_multipart_form_parameters(body, boundary,
|
460
|
-
parse_request_parameters(read_multipart(body, boundary,
|
469
|
+
def parse_multipart_form_parameters(body, boundary, body_size, env)
|
470
|
+
parse_request_parameters(read_multipart(body, boundary, body_size, env))
|
461
471
|
end
|
462
472
|
|
463
473
|
def extract_multipart_boundary(content_type_with_parameters)
|
@@ -488,7 +498,7 @@ EOM
|
|
488
498
|
when Array
|
489
499
|
value.map { |v| get_typed_value(v) }
|
490
500
|
else
|
491
|
-
if value.
|
501
|
+
if value.respond_to? :original_filename
|
492
502
|
# Uploaded file
|
493
503
|
if value.original_filename
|
494
504
|
value
|
@@ -505,23 +515,28 @@ EOM
|
|
505
515
|
end
|
506
516
|
end
|
507
517
|
|
508
|
-
|
509
518
|
MULTIPART_BOUNDARY = %r|\Amultipart/form-data.*boundary=\"?([^\";,]+)\"?|n
|
510
519
|
|
511
520
|
EOL = "\015\012"
|
512
521
|
|
513
|
-
def read_multipart(body, boundary,
|
522
|
+
def read_multipart(body, boundary, body_size, env)
|
514
523
|
params = Hash.new([])
|
515
524
|
boundary = "--" + boundary
|
516
|
-
quoted_boundary = Regexp.quote(boundary
|
525
|
+
quoted_boundary = Regexp.quote(boundary)
|
517
526
|
buf = ""
|
518
527
|
bufsize = 10 * 1024
|
519
528
|
boundary_end=""
|
520
529
|
|
521
530
|
# start multipart/form-data
|
522
531
|
body.binmode if defined? body.binmode
|
532
|
+
case body
|
533
|
+
when File
|
534
|
+
body.set_encoding(Encoding::BINARY) if body.respond_to?(:set_encoding)
|
535
|
+
when StringIO
|
536
|
+
body.string.force_encoding(Encoding::BINARY) if body.string.respond_to?(:force_encoding)
|
537
|
+
end
|
523
538
|
boundary_size = boundary.size + EOL.size
|
524
|
-
|
539
|
+
body_size -= boundary_size
|
525
540
|
status = body.read(boundary_size)
|
526
541
|
if nil == status
|
527
542
|
raise EOFError, "no content body"
|
@@ -532,7 +547,7 @@ EOM
|
|
532
547
|
loop do
|
533
548
|
head = nil
|
534
549
|
content =
|
535
|
-
if 10240 <
|
550
|
+
if 10240 < body_size
|
536
551
|
UploadedTempfile.new("CGI")
|
537
552
|
else
|
538
553
|
UploadedStringIO.new
|
@@ -554,24 +569,24 @@ EOM
|
|
554
569
|
buf[0 ... (buf.size - (EOL + boundary + EOL).size)] = ""
|
555
570
|
end
|
556
571
|
|
557
|
-
c = if bufsize <
|
572
|
+
c = if bufsize < body_size
|
558
573
|
body.read(bufsize)
|
559
574
|
else
|
560
|
-
body.read(
|
575
|
+
body.read(body_size)
|
561
576
|
end
|
562
577
|
if c.nil? || c.empty?
|
563
578
|
raise EOFError, "bad content body"
|
564
579
|
end
|
565
580
|
buf.concat(c)
|
566
|
-
|
581
|
+
body_size -= c.size
|
567
582
|
end
|
568
583
|
|
569
584
|
buf = buf.sub(/\A((?:.|\n)*?)(?:[\r\n]{1,2})?#{quoted_boundary}([\r\n]{1,2}|--)/n) do
|
570
585
|
content.print $1
|
571
586
|
if "--" == $2
|
572
|
-
|
587
|
+
body_size = -1
|
573
588
|
end
|
574
|
-
|
589
|
+
boundary_end = $2.dup
|
575
590
|
""
|
576
591
|
end
|
577
592
|
|
@@ -598,17 +613,16 @@ EOM
|
|
598
613
|
else
|
599
614
|
params[name] = [content]
|
600
615
|
end
|
601
|
-
break if
|
602
|
-
break if content_length == -1
|
616
|
+
break if body_size == -1
|
603
617
|
end
|
604
618
|
raise EOFError, "bad boundary end of body part" unless boundary_end=~/--/
|
605
619
|
|
606
|
-
|
620
|
+
begin
|
607
621
|
body.rewind if body.respond_to?(:rewind)
|
608
|
-
|
622
|
+
rescue Errno::ESPIPE
|
609
623
|
# Handles exceptions raised by input streams that cannot be rewound
|
610
624
|
# such as when using plain CGI under Apache
|
611
|
-
|
625
|
+
end
|
612
626
|
|
613
627
|
params
|
614
628
|
end
|
@@ -687,6 +701,7 @@ EOM
|
|
687
701
|
else
|
688
702
|
top << {key => value}.with_indifferent_access
|
689
703
|
push top.last
|
704
|
+
value = top[key]
|
690
705
|
end
|
691
706
|
else
|
692
707
|
top << value
|
@@ -694,7 +709,8 @@ EOM
|
|
694
709
|
elsif top.is_a? Hash
|
695
710
|
key = CGI.unescape(key)
|
696
711
|
parent << (@top = {}) if top.key?(key) && parent.is_a?(Array)
|
697
|
-
|
712
|
+
top[key] ||= value
|
713
|
+
return top[key]
|
698
714
|
else
|
699
715
|
raise ArgumentError, "Don't know what to do: top is #{top.inspect}"
|
700
716
|
end
|
@@ -703,7 +719,7 @@ EOM
|
|
703
719
|
end
|
704
720
|
|
705
721
|
def type_conflict!(klass, value)
|
706
|
-
raise TypeError, "Conflicting types for parameter containers. Expected an instance of #{klass} but found an instance of #{value.class}. This can be caused by colliding Array and Hash parameters like qs[]=value&qs[key]=value."
|
722
|
+
raise TypeError, "Conflicting types for parameter containers. Expected an instance of #{klass} but found an instance of #{value.class}. This can be caused by colliding Array and Hash parameters like qs[]=value&qs[key]=value. (The parameters received were #{value.inspect}.)"
|
707
723
|
end
|
708
724
|
end
|
709
725
|
|
@@ -36,7 +36,7 @@ module ActionController #:nodoc:
|
|
36
36
|
#
|
37
37
|
# # Disable request forgery protection in test environment
|
38
38
|
# config.action_controller.allow_forgery_protection = false
|
39
|
-
#
|
39
|
+
#
|
40
40
|
# == Learn more about CSRF (Cross-Site Request Forgery) attacks
|
41
41
|
#
|
42
42
|
# Here are some resources:
|
@@ -45,7 +45,7 @@ module ActionController #:nodoc:
|
|
45
45
|
#
|
46
46
|
# Keep in mind, this is NOT a silver-bullet, plug 'n' play, warm security blanket for your rails application.
|
47
47
|
# There are a few guidelines you should follow:
|
48
|
-
#
|
48
|
+
#
|
49
49
|
# * Keep your GET requests safe and idempotent. More reading material:
|
50
50
|
# * http://www.xml.com/pub/a/2002/04/24/deviant.html
|
51
51
|
# * http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.1.1
|
@@ -69,10 +69,10 @@ module ActionController #:nodoc:
|
|
69
69
|
#
|
70
70
|
# Valid Options:
|
71
71
|
#
|
72
|
-
# * <tt>:only/:except</tt> -
|
72
|
+
# * <tt>:only/:except</tt> - Passed to the <tt>before_filter</tt> call. Set which actions are verified.
|
73
73
|
# * <tt>:secret</tt> - Custom salt used to generate the <tt>form_authenticity_token</tt>.
|
74
74
|
# Leave this off if you are using the cookie session store.
|
75
|
-
# * <tt>:digest</tt> - Message digest used for hashing. Defaults to 'SHA1'
|
75
|
+
# * <tt>:digest</tt> - Message digest used for hashing. Defaults to 'SHA1'.
|
76
76
|
def protect_from_forgery(options = {})
|
77
77
|
self.request_forgery_protection_token ||= :authenticity_token
|
78
78
|
before_filter :verify_authenticity_token, :only => options.delete(:only), :except => options.delete(:except)
|
@@ -99,17 +99,18 @@ module ActionController #:nodoc:
|
|
99
99
|
end
|
100
100
|
|
101
101
|
def verifiable_request_format?
|
102
|
-
request.
|
102
|
+
request.content_type.nil? || request.content_type.verify_request?
|
103
103
|
end
|
104
104
|
|
105
|
-
# Sets the token value for the current session. Pass a
|
105
|
+
# Sets the token value for the current session. Pass a <tt>:secret</tt> option
|
106
|
+
# in +protect_from_forgery+ to add a custom salt to the hash.
|
106
107
|
def form_authenticity_token
|
107
|
-
@form_authenticity_token ||= if
|
108
|
+
@form_authenticity_token ||= if !session.respond_to?(:session_id)
|
109
|
+
raise InvalidAuthenticityToken, "Request Forgery Protection requires a valid session. Use #allow_forgery_protection to disable it, or use a valid session."
|
110
|
+
elsif request_forgery_protection_options[:secret]
|
108
111
|
authenticity_token_from_session_id
|
109
112
|
elsif session.respond_to?(:dbman) && session.dbman.respond_to?(:generate_digest)
|
110
113
|
authenticity_token_from_cookie_session
|
111
|
-
elsif session.nil?
|
112
|
-
raise InvalidAuthenticityToken, "Request Forgery Protection requires a valid session. Use #allow_forgery_protection to disable it, or use a valid session."
|
113
114
|
else
|
114
115
|
raise InvalidAuthenticityToken, "No :secret given to the #protect_from_forgery call. Set that or use a session store capable of generating its own keys (Cookie Session Store)."
|
115
116
|
end
|