actionpack 2.2.3 → 2.3.2
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 +433 -375
- data/MIT-LICENSE +1 -1
- data/README +21 -75
- data/Rakefile +1 -1
- data/lib/action_controller.rb +80 -43
- data/lib/action_controller/assertions/model_assertions.rb +1 -0
- data/lib/action_controller/assertions/response_assertions.rb +43 -16
- data/lib/action_controller/assertions/routing_assertions.rb +1 -1
- data/lib/action_controller/assertions/selector_assertions.rb +17 -12
- data/lib/action_controller/assertions/tag_assertions.rb +1 -4
- data/lib/action_controller/base.rb +153 -82
- data/lib/action_controller/benchmarking.rb +9 -9
- data/lib/action_controller/caching.rb +9 -11
- data/lib/action_controller/caching/actions.rb +11 -18
- data/lib/action_controller/caching/fragments.rb +28 -20
- data/lib/action_controller/caching/pages.rb +13 -15
- data/lib/action_controller/caching/sweeping.rb +2 -2
- data/lib/action_controller/cgi_ext.rb +0 -1
- data/lib/action_controller/cgi_ext/cookie.rb +2 -0
- data/lib/action_controller/cgi_process.rb +54 -162
- data/lib/action_controller/cookies.rb +13 -25
- data/lib/action_controller/dispatcher.rb +43 -122
- data/lib/action_controller/failsafe.rb +52 -0
- data/lib/action_controller/flash.rb +38 -47
- data/lib/action_controller/helpers.rb +13 -9
- data/lib/action_controller/http_authentication.rb +203 -23
- data/lib/action_controller/integration.rb +126 -70
- data/lib/action_controller/layout.rb +36 -39
- data/lib/action_controller/middleware_stack.rb +119 -0
- data/lib/action_controller/middlewares.rb +13 -0
- data/lib/action_controller/mime_responds.rb +19 -4
- data/lib/action_controller/mime_type.rb +8 -0
- data/lib/action_controller/params_parser.rb +71 -0
- data/lib/action_controller/performance_test.rb +0 -1
- data/lib/action_controller/polymorphic_routes.rb +36 -30
- data/lib/action_controller/reloader.rb +14 -0
- data/lib/action_controller/request.rb +107 -499
- data/lib/action_controller/request_forgery_protection.rb +7 -39
- data/lib/action_controller/rescue.rb +55 -35
- data/lib/action_controller/resources.rb +34 -31
- data/lib/action_controller/response.rb +99 -57
- data/lib/action_controller/rewindable_input.rb +28 -0
- data/lib/action_controller/routing.rb +7 -7
- data/lib/action_controller/routing/builder.rb +4 -1
- data/lib/action_controller/routing/optimisations.rb +1 -1
- data/lib/action_controller/routing/recognition_optimisation.rb +1 -2
- data/lib/action_controller/routing/route.rb +15 -5
- data/lib/action_controller/routing/route_set.rb +82 -35
- data/lib/action_controller/routing/segments.rb +35 -0
- data/lib/action_controller/session/abstract_store.rb +181 -0
- data/lib/action_controller/session/cookie_store.rb +197 -175
- data/lib/action_controller/session/mem_cache_store.rb +36 -83
- data/lib/action_controller/session_management.rb +26 -134
- data/lib/action_controller/streaming.rb +24 -7
- data/lib/action_controller/templates/rescues/diagnostics.erb +2 -2
- data/lib/action_controller/templates/rescues/template_error.erb +2 -2
- data/lib/action_controller/test_case.rb +87 -30
- data/lib/action_controller/test_process.rb +145 -104
- data/lib/action_controller/uploaded_file.rb +44 -0
- data/lib/action_controller/url_rewriter.rb +3 -6
- data/lib/action_controller/vendor/html-scanner.rb +16 -0
- data/lib/action_controller/vendor/html-scanner/html/selector.rb +1 -1
- data/lib/action_controller/vendor/rack-1.0/rack.rb +89 -0
- data/lib/action_controller/vendor/rack-1.0/rack/adapter/camping.rb +22 -0
- data/lib/action_controller/vendor/rack-1.0/rack/auth/abstract/handler.rb +37 -0
- data/lib/action_controller/vendor/rack-1.0/rack/auth/abstract/request.rb +37 -0
- data/lib/action_controller/vendor/rack-1.0/rack/auth/basic.rb +58 -0
- data/lib/action_controller/vendor/rack-1.0/rack/auth/digest/md5.rb +124 -0
- data/lib/action_controller/vendor/rack-1.0/rack/auth/digest/nonce.rb +51 -0
- data/lib/action_controller/vendor/rack-1.0/rack/auth/digest/params.rb +55 -0
- data/lib/action_controller/vendor/rack-1.0/rack/auth/digest/request.rb +40 -0
- data/lib/action_controller/vendor/rack-1.0/rack/auth/openid.rb +480 -0
- data/lib/action_controller/vendor/rack-1.0/rack/builder.rb +63 -0
- data/lib/action_controller/vendor/rack-1.0/rack/cascade.rb +36 -0
- data/lib/action_controller/vendor/rack-1.0/rack/chunked.rb +49 -0
- data/lib/action_controller/vendor/rack-1.0/rack/commonlogger.rb +61 -0
- data/lib/action_controller/vendor/rack-1.0/rack/conditionalget.rb +45 -0
- data/lib/action_controller/vendor/rack-1.0/rack/content_length.rb +29 -0
- data/lib/action_controller/vendor/rack-1.0/rack/content_type.rb +23 -0
- data/lib/action_controller/vendor/rack-1.0/rack/deflater.rb +85 -0
- data/lib/action_controller/vendor/rack-1.0/rack/directory.rb +153 -0
- data/lib/action_controller/vendor/rack-1.0/rack/file.rb +88 -0
- data/lib/action_controller/vendor/rack-1.0/rack/handler.rb +48 -0
- data/lib/action_controller/vendor/rack-1.0/rack/handler/cgi.rb +61 -0
- data/lib/action_controller/vendor/rack-1.0/rack/handler/evented_mongrel.rb +8 -0
- data/lib/action_controller/vendor/rack-1.0/rack/handler/fastcgi.rb +89 -0
- data/lib/action_controller/vendor/rack-1.0/rack/handler/lsws.rb +55 -0
- data/lib/action_controller/vendor/rack-1.0/rack/handler/mongrel.rb +84 -0
- data/lib/action_controller/vendor/rack-1.0/rack/handler/scgi.rb +59 -0
- data/lib/action_controller/vendor/rack-1.0/rack/handler/swiftiplied_mongrel.rb +8 -0
- data/lib/action_controller/vendor/rack-1.0/rack/handler/thin.rb +18 -0
- data/lib/action_controller/vendor/rack-1.0/rack/handler/webrick.rb +67 -0
- data/lib/action_controller/vendor/rack-1.0/rack/head.rb +19 -0
- data/lib/action_controller/vendor/rack-1.0/rack/lint.rb +462 -0
- data/lib/action_controller/vendor/rack-1.0/rack/lobster.rb +65 -0
- data/lib/action_controller/vendor/rack-1.0/rack/lock.rb +16 -0
- data/lib/action_controller/vendor/rack-1.0/rack/methodoverride.rb +27 -0
- data/lib/action_controller/vendor/rack-1.0/rack/mime.rb +204 -0
- data/lib/action_controller/vendor/rack-1.0/rack/mock.rb +160 -0
- data/lib/action_controller/vendor/rack-1.0/rack/recursive.rb +57 -0
- data/lib/action_controller/vendor/rack-1.0/rack/reloader.rb +64 -0
- data/lib/action_controller/vendor/rack-1.0/rack/request.rb +241 -0
- data/lib/action_controller/vendor/rack-1.0/rack/response.rb +179 -0
- data/lib/action_controller/vendor/rack-1.0/rack/session/abstract/id.rb +142 -0
- data/lib/action_controller/vendor/rack-1.0/rack/session/cookie.rb +91 -0
- data/lib/action_controller/vendor/rack-1.0/rack/session/memcache.rb +109 -0
- data/lib/action_controller/vendor/rack-1.0/rack/session/pool.rb +100 -0
- data/lib/action_controller/vendor/rack-1.0/rack/showexceptions.rb +349 -0
- data/lib/action_controller/vendor/rack-1.0/rack/showstatus.rb +106 -0
- data/lib/action_controller/vendor/rack-1.0/rack/static.rb +38 -0
- data/lib/action_controller/vendor/rack-1.0/rack/urlmap.rb +55 -0
- data/lib/action_controller/vendor/rack-1.0/rack/utils.rb +392 -0
- data/lib/action_controller/verification.rb +1 -1
- data/lib/action_pack.rb +1 -1
- data/lib/action_pack/version.rb +2 -2
- data/lib/action_view.rb +22 -17
- data/lib/action_view/base.rb +53 -79
- data/lib/action_view/erb/util.rb +38 -0
- data/lib/action_view/helpers.rb +24 -5
- data/lib/action_view/helpers/active_record_helper.rb +2 -2
- data/lib/action_view/helpers/asset_tag_helper.rb +81 -50
- data/lib/action_view/helpers/atom_feed_helper.rb +1 -1
- data/lib/action_view/helpers/benchmark_helper.rb +26 -5
- data/lib/action_view/helpers/date_helper.rb +82 -7
- data/lib/action_view/helpers/form_helper.rb +295 -64
- data/lib/action_view/helpers/form_options_helper.rb +160 -18
- data/lib/action_view/helpers/form_tag_helper.rb +2 -2
- data/lib/action_view/helpers/number_helper.rb +31 -18
- data/lib/action_view/helpers/prototype_helper.rb +2 -12
- data/lib/action_view/helpers/sanitize_helper.rb +0 -10
- data/lib/action_view/helpers/scriptaculous_helper.rb +1 -0
- data/lib/action_view/helpers/tag_helper.rb +3 -4
- data/lib/action_view/helpers/text_helper.rb +99 -122
- data/lib/action_view/helpers/translation_helper.rb +19 -1
- data/lib/action_view/helpers/url_helper.rb +25 -2
- data/lib/action_view/inline_template.rb +1 -1
- data/lib/action_view/locale/en.yml +19 -1
- data/lib/action_view/partials.rb +46 -9
- data/lib/action_view/paths.rb +28 -84
- data/lib/action_view/reloadable_template.rb +117 -0
- data/lib/action_view/renderable.rb +28 -35
- data/lib/action_view/renderable_partial.rb +3 -4
- data/lib/action_view/template.rb +172 -31
- data/lib/action_view/template_error.rb +8 -9
- data/lib/action_view/template_handler.rb +1 -1
- data/lib/action_view/template_handlers.rb +9 -6
- data/lib/action_view/template_handlers/erb.rb +2 -39
- data/lib/action_view/template_handlers/rjs.rb +1 -0
- data/lib/action_view/test_case.rb +27 -1
- data/test/abstract_unit.rb +23 -17
- data/test/active_record_unit.rb +5 -4
- data/test/activerecord/active_record_store_test.rb +139 -106
- data/test/activerecord/render_partial_with_record_identification_test.rb +5 -21
- data/test/controller/action_pack_assertions_test.rb +25 -23
- data/test/controller/addresses_render_test.rb +3 -6
- data/test/controller/assert_select_test.rb +83 -70
- data/test/controller/base_test.rb +11 -13
- data/test/controller/benchmark_test.rb +3 -3
- data/test/controller/caching_test.rb +34 -24
- data/test/controller/capture_test.rb +3 -6
- data/test/controller/content_type_test.rb +3 -6
- data/test/controller/cookie_test.rb +31 -66
- data/test/controller/deprecation/deprecated_base_methods_test.rb +9 -11
- data/test/controller/dispatcher_test.rb +23 -28
- data/test/controller/fake_models.rb +8 -0
- data/test/controller/filters_test.rb +6 -2
- data/test/controller/flash_test.rb +2 -6
- data/test/controller/helper_test.rb +15 -1
- data/test/controller/html-scanner/document_test.rb +1 -1
- data/test/controller/html-scanner/sanitizer_test.rb +1 -1
- data/test/controller/http_basic_authentication_test.rb +88 -0
- data/test/controller/http_digest_authentication_test.rb +178 -0
- data/test/controller/integration_test.rb +56 -52
- data/test/controller/layout_test.rb +46 -44
- data/test/controller/middleware_stack_test.rb +90 -0
- data/test/controller/mime_responds_test.rb +7 -11
- data/test/controller/mime_type_test.rb +9 -0
- data/test/controller/polymorphic_routes_test.rb +235 -151
- data/test/controller/rack_test.rb +52 -81
- data/test/controller/redirect_test.rb +6 -14
- data/test/controller/render_test.rb +273 -60
- data/test/controller/request/json_params_parsing_test.rb +45 -0
- data/test/controller/request/multipart_params_parsing_test.rb +223 -0
- data/test/controller/request/query_string_parsing_test.rb +120 -0
- data/test/controller/request/url_encoded_params_parsing_test.rb +184 -0
- data/test/controller/request/xml_params_parsing_test.rb +88 -0
- data/test/controller/request_forgery_protection_test.rb +17 -98
- data/test/controller/request_test.rb +45 -530
- data/test/controller/rescue_test.rb +45 -22
- data/test/controller/resources_test.rb +112 -37
- data/test/controller/routing_test.rb +1442 -1384
- data/test/controller/selector_test.rb +3 -3
- data/test/controller/send_file_test.rb +30 -3
- data/test/controller/session/cookie_store_test.rb +169 -240
- data/test/controller/session/mem_cache_store_test.rb +94 -148
- data/test/controller/session/test_session_test.rb +58 -0
- data/test/controller/test_test.rb +32 -13
- data/test/controller/url_rewriter_test.rb +54 -4
- data/test/controller/verification_test.rb +1 -1
- data/test/controller/view_paths_test.rb +15 -15
- data/test/controller/webservice_test.rb +178 -147
- data/test/fixtures/alternate_helpers/foo_helper.rb +3 -0
- data/test/fixtures/layout_tests/alt/layouts/alt.rhtml +0 -0
- data/test/fixtures/layouts/default_html.html.erb +1 -0
- data/test/fixtures/layouts/xhr.html.erb +2 -0
- data/test/fixtures/multipart/empty +10 -0
- data/test/fixtures/multipart/hello.txt +1 -0
- data/test/fixtures/multipart/none +9 -0
- data/test/fixtures/public/500.da.html +1 -0
- data/test/fixtures/quiz/questions/_question.html.erb +1 -0
- data/test/fixtures/replies.yml +1 -1
- data/test/fixtures/test/_one.html.erb +1 -0
- data/test/fixtures/test/_two.html.erb +1 -0
- data/test/fixtures/test/dont_pick_me +1 -0
- data/test/fixtures/test/hello.builder +1 -1
- data/test/fixtures/test/hello_world.da.html.erb +1 -0
- data/test/fixtures/test/hello_world.erb~ +1 -0
- data/test/fixtures/test/hello_world.pt-BR.html.erb +1 -0
- data/test/fixtures/test/malformed/malformed.en.html.erb~ +1 -0
- data/test/fixtures/test/malformed/malformed.erb~ +1 -0
- data/test/fixtures/test/malformed/malformed.html.erb~ +1 -0
- data/test/fixtures/test/render_explicit_html_template.js.rjs +1 -0
- data/test/fixtures/test/render_implicit_html_template.js.rjs +1 -0
- data/test/fixtures/test/render_implicit_html_template_from_xhr_request.da.html.erb +1 -0
- data/test/fixtures/test/render_implicit_html_template_from_xhr_request.html.erb +1 -0
- data/test/fixtures/test/render_implicit_js_template_without_layout.js.erb +1 -0
- data/test/fixtures/test/utf8.html.erb +2 -0
- data/test/template/active_record_helper_i18n_test.rb +31 -33
- data/test/template/active_record_helper_test.rb +34 -0
- data/test/template/asset_tag_helper_test.rb +52 -14
- data/test/template/atom_feed_helper_test.rb +3 -5
- data/test/template/benchmark_helper_test.rb +50 -24
- data/test/template/compiled_templates_test.rb +177 -33
- data/test/template/date_helper_i18n_test.rb +88 -81
- data/test/template/date_helper_test.rb +427 -43
- data/test/template/form_helper_test.rb +243 -44
- data/test/template/form_options_helper_test.rb +631 -565
- data/test/template/form_tag_helper_test.rb +9 -2
- data/test/template/javascript_helper_test.rb +0 -5
- data/test/template/number_helper_i18n_test.rb +60 -48
- data/test/template/number_helper_test.rb +1 -0
- data/test/template/render_test.rb +117 -35
- data/test/template/test_test.rb +4 -6
- data/test/template/text_helper_test.rb +129 -50
- data/test/template/translation_helper_test.rb +23 -19
- data/test/template/url_helper_test.rb +35 -2
- data/test/view/test_case_test.rb +8 -0
- metadata +197 -23
- data/lib/action_controller/assertions.rb +0 -69
- data/lib/action_controller/caching/sql_cache.rb +0 -18
- data/lib/action_controller/cgi_ext/session.rb +0 -53
- data/lib/action_controller/components.rb +0 -169
- data/lib/action_controller/rack_process.rb +0 -297
- data/lib/action_controller/request_profiler.rb +0 -169
- data/lib/action_controller/session/active_record_store.rb +0 -340
- data/lib/action_controller/session/drb_server.rb +0 -32
- data/lib/action_controller/session/drb_store.rb +0 -35
- data/test/controller/cgi_test.rb +0 -269
- data/test/controller/components_test.rb +0 -156
- data/test/controller/http_authentication_test.rb +0 -54
- data/test/controller/integration_upload_test.rb +0 -43
- data/test/controller/session_fixation_test.rb +0 -89
- data/test/controller/session_management_test.rb +0 -178
- data/test/fixtures/test/hello_world.js +0 -1
@@ -3,39 +3,42 @@ require 'stringio'
|
|
3
3
|
require 'strscan'
|
4
4
|
|
5
5
|
require 'active_support/memoizable'
|
6
|
+
require 'action_controller/cgi_ext'
|
6
7
|
|
7
8
|
module ActionController
|
8
|
-
|
9
|
-
class AbstractRequest
|
10
|
-
extend ActiveSupport::Memoizable
|
9
|
+
class Request < Rack::Request
|
11
10
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
11
|
+
%w[ AUTH_TYPE GATEWAY_INTERFACE
|
12
|
+
PATH_TRANSLATED REMOTE_HOST
|
13
|
+
REMOTE_IDENT REMOTE_USER REMOTE_ADDR
|
14
|
+
SERVER_NAME SERVER_PROTOCOL
|
15
|
+
|
16
|
+
HTTP_ACCEPT HTTP_ACCEPT_CHARSET HTTP_ACCEPT_ENCODING
|
17
|
+
HTTP_ACCEPT_LANGUAGE HTTP_CACHE_CONTROL HTTP_FROM
|
18
|
+
HTTP_NEGOTIATE HTTP_PRAGMA HTTP_REFERER HTTP_USER_AGENT ].each do |env|
|
19
|
+
define_method(env.sub(/^HTTP_/n, '').downcase) do
|
20
|
+
@env[env]
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def key?(key)
|
25
|
+
@env.key?(key)
|
17
26
|
end
|
18
27
|
|
19
28
|
HTTP_METHODS = %w(get head put post delete options)
|
20
29
|
HTTP_METHOD_LOOKUP = HTTP_METHODS.inject({}) { |h, m| h[m] = h[m.upcase] = m.to_sym; h }
|
21
30
|
|
22
|
-
#
|
23
|
-
#
|
24
|
-
|
25
|
-
|
26
|
-
# The true HTTP request \method as a lowercase symbol, such as <tt>:get</tt>.
|
27
|
-
# UnknownHttpMethod is raised for invalid methods not listed in ACCEPTED_HTTP_METHODS.
|
31
|
+
# Returns the true HTTP request \method as a lowercase symbol, such as
|
32
|
+
# <tt>:get</tt>. If the request \method is not listed in the HTTP_METHODS
|
33
|
+
# constant above, an UnknownHttpMethod exception is raised.
|
28
34
|
def request_method
|
29
|
-
|
30
|
-
method = parameters[:_method] if method == 'POST' && !parameters[:_method].blank?
|
31
|
-
|
32
|
-
HTTP_METHOD_LOOKUP[method] || raise(UnknownHttpMethod, "#{method}, accepted HTTP methods are #{HTTP_METHODS.to_sentence}")
|
35
|
+
@request_method ||= HTTP_METHOD_LOOKUP[super] || raise(UnknownHttpMethod, "#{super}, accepted HTTP methods are #{HTTP_METHODS.to_sentence(:locale => :en)}")
|
33
36
|
end
|
34
|
-
memoize :request_method
|
35
37
|
|
36
|
-
#
|
37
|
-
#
|
38
|
-
#
|
38
|
+
# Returns the HTTP request \method used for action processing as a
|
39
|
+
# lowercase symbol, such as <tt>:post</tt>. (Unlike #request_method, this
|
40
|
+
# method returns <tt>:get</tt> for a HEAD request because the two are
|
41
|
+
# functionally equivalent from the application's perspective.)
|
39
42
|
def method
|
40
43
|
request_method == :head ? :get : request_method
|
41
44
|
end
|
@@ -70,43 +73,46 @@ module ActionController
|
|
70
73
|
#
|
71
74
|
# request.headers["Content-Type"] # => "text/plain"
|
72
75
|
def headers
|
73
|
-
ActionController::Http::Headers.new(@env)
|
76
|
+
@headers ||= ActionController::Http::Headers.new(@env)
|
74
77
|
end
|
75
|
-
memoize :headers
|
76
78
|
|
77
79
|
# Returns the content length of the request as an integer.
|
78
80
|
def content_length
|
79
|
-
|
81
|
+
super.to_i
|
80
82
|
end
|
81
|
-
memoize :content_length
|
82
83
|
|
83
84
|
# The MIME type of the HTTP request, such as Mime::XML.
|
84
85
|
#
|
85
86
|
# For backward compatibility, the post \format is extracted from the
|
86
87
|
# X-Post-Data-Format HTTP header if present.
|
87
88
|
def content_type
|
88
|
-
|
89
|
+
@content_type ||= begin
|
90
|
+
if @env['CONTENT_TYPE'] =~ /^([^,\;]*)/
|
91
|
+
Mime::Type.lookup($1.strip.downcase)
|
92
|
+
else
|
93
|
+
nil
|
94
|
+
end
|
95
|
+
end
|
89
96
|
end
|
90
|
-
memoize :content_type
|
91
97
|
|
92
98
|
# Returns the accepted MIME type for the request.
|
93
99
|
def accepts
|
94
|
-
|
100
|
+
@accepts ||= begin
|
101
|
+
header = @env['HTTP_ACCEPT'].to_s.strip
|
95
102
|
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
103
|
+
if header.empty?
|
104
|
+
[content_type, Mime::ALL].compact
|
105
|
+
else
|
106
|
+
Mime::Type.parse(header)
|
107
|
+
end
|
100
108
|
end
|
101
109
|
end
|
102
|
-
memoize :accepts
|
103
110
|
|
104
111
|
def if_modified_since
|
105
112
|
if since = env['HTTP_IF_MODIFIED_SINCE']
|
106
113
|
Time.rfc2822(since) rescue nil
|
107
114
|
end
|
108
115
|
end
|
109
|
-
memoize :if_modified_since
|
110
116
|
|
111
117
|
def if_none_match
|
112
118
|
env['HTTP_IF_NONE_MATCH']
|
@@ -125,15 +131,15 @@ module ActionController
|
|
125
131
|
# supplied, both must match, or the request is not considered fresh.
|
126
132
|
def fresh?(response)
|
127
133
|
case
|
128
|
-
when if_modified_since && if_none_match
|
129
|
-
not_modified?(response.last_modified) && etag_matches?(response.etag)
|
130
|
-
when if_modified_since
|
131
|
-
not_modified?(response.last_modified)
|
132
|
-
when if_none_match
|
133
|
-
etag_matches?(response.etag)
|
134
|
-
else
|
135
|
-
false
|
136
|
-
end
|
134
|
+
when if_modified_since && if_none_match
|
135
|
+
not_modified?(response.last_modified) && etag_matches?(response.etag)
|
136
|
+
when if_modified_since
|
137
|
+
not_modified?(response.last_modified)
|
138
|
+
when if_none_match
|
139
|
+
etag_matches?(response.etag)
|
140
|
+
else
|
141
|
+
false
|
142
|
+
end
|
137
143
|
end
|
138
144
|
|
139
145
|
# Returns the Mime type for the \format used in the request.
|
@@ -209,7 +215,7 @@ module ActionController
|
|
209
215
|
# delimited list in the case of multiple chained proxies; the last
|
210
216
|
# address which is not trusted is the originating IP.
|
211
217
|
def remote_ip
|
212
|
-
remote_addr_list = @env['REMOTE_ADDR'] && @env['REMOTE_ADDR'].
|
218
|
+
remote_addr_list = @env['REMOTE_ADDR'] && @env['REMOTE_ADDR'].scan(/[^,\s]+/)
|
213
219
|
|
214
220
|
unless remote_addr_list.blank?
|
215
221
|
not_trusted_addrs = remote_addr_list.reject {|addr| addr =~ TRUSTED_PROXIES}
|
@@ -218,7 +224,7 @@ module ActionController
|
|
218
224
|
remote_ips = @env['HTTP_X_FORWARDED_FOR'] && @env['HTTP_X_FORWARDED_FOR'].split(',')
|
219
225
|
|
220
226
|
if @env.include? 'HTTP_CLIENT_IP'
|
221
|
-
if remote_ips && !remote_ips.include?(@env['HTTP_CLIENT_IP'])
|
227
|
+
if ActionController::Base.ip_spoofing_check && remote_ips && !remote_ips.include?(@env['HTTP_CLIENT_IP'])
|
222
228
|
# We don't know which came from the proxy, and which from the user
|
223
229
|
raise ActionControllerError.new(<<EOM)
|
224
230
|
IP spoofing attack?!
|
@@ -240,26 +246,21 @@ EOM
|
|
240
246
|
|
241
247
|
@env['REMOTE_ADDR']
|
242
248
|
end
|
243
|
-
memoize :remote_ip
|
244
249
|
|
245
250
|
# Returns the lowercase name of the HTTP server software.
|
246
251
|
def server_software
|
247
252
|
(@env['SERVER_SOFTWARE'] && /^([a-zA-Z]+)/ =~ @env['SERVER_SOFTWARE']) ? $1.downcase : nil
|
248
253
|
end
|
249
|
-
memoize :server_software
|
250
|
-
|
251
254
|
|
252
255
|
# Returns the complete URL used for this request.
|
253
256
|
def url
|
254
257
|
protocol + host_with_port + request_uri
|
255
258
|
end
|
256
|
-
memoize :url
|
257
259
|
|
258
260
|
# Returns 'https://' if this is an SSL request and 'http://' otherwise.
|
259
261
|
def protocol
|
260
262
|
ssl? ? 'https://' : 'http://'
|
261
263
|
end
|
262
|
-
memoize :protocol
|
263
264
|
|
264
265
|
# Is this an SSL request?
|
265
266
|
def ssl?
|
@@ -271,7 +272,7 @@ EOM
|
|
271
272
|
if forwarded = env["HTTP_X_FORWARDED_HOST"]
|
272
273
|
forwarded.split(/,\s?/).last
|
273
274
|
else
|
274
|
-
env['HTTP_HOST'] || env['SERVER_NAME'] ||
|
275
|
+
env['HTTP_HOST'] || "#{env['SERVER_NAME'] || env['SERVER_ADDR']}:#{env['SERVER_PORT']}"
|
275
276
|
end
|
276
277
|
end
|
277
278
|
|
@@ -279,14 +280,12 @@ EOM
|
|
279
280
|
def host
|
280
281
|
raw_host_with_port.sub(/:\d+$/, '')
|
281
282
|
end
|
282
|
-
memoize :host
|
283
283
|
|
284
284
|
# Returns a \host:\port string for this request, such as "example.com" or
|
285
285
|
# "example.com:8080".
|
286
286
|
def host_with_port
|
287
287
|
"#{host}#{port_string}"
|
288
288
|
end
|
289
|
-
memoize :host_with_port
|
290
289
|
|
291
290
|
# Returns the port number of this request as an integer.
|
292
291
|
def port
|
@@ -296,7 +295,6 @@ EOM
|
|
296
295
|
standard_port
|
297
296
|
end
|
298
297
|
end
|
299
|
-
memoize :port
|
300
298
|
|
301
299
|
# Returns the standard \port number for this request's protocol.
|
302
300
|
def standard_port
|
@@ -305,15 +303,6 @@ EOM
|
|
305
303
|
else 80
|
306
304
|
end
|
307
305
|
end
|
308
|
-
|
309
|
-
# Returns the value of ActionController::Base.relative_url_root. This method is
|
310
|
-
# deprecated as the value is an application wide setting, not something which
|
311
|
-
# changes per request.
|
312
|
-
def relative_url_root
|
313
|
-
ActiveSupport::Deprecation.warn(
|
314
|
-
"relative_url_root is now set application-wide, use ActionController::Base.relative_url_root instead.", caller)
|
315
|
-
ActionController::Base.relative_url_root
|
316
|
-
end
|
317
306
|
|
318
307
|
# Returns a \port suffix like ":8080" if the \port number of this request
|
319
308
|
# is not the default HTTP \port 80 or HTTPS \port 443.
|
@@ -341,13 +330,8 @@ EOM
|
|
341
330
|
|
342
331
|
# Returns the query string, accounting for server idiosyncrasies.
|
343
332
|
def query_string
|
344
|
-
|
345
|
-
uri.split('?', 2)[1] || ''
|
346
|
-
else
|
347
|
-
@env['QUERY_STRING'] || ''
|
348
|
-
end
|
333
|
+
@env['QUERY_STRING'].present? ? @env['QUERY_STRING'] : (@env['REQUEST_URI'].split('?', 2)[1] || '')
|
349
334
|
end
|
350
|
-
memoize :query_string
|
351
335
|
|
352
336
|
# Returns the request URI, accounting for server idiosyncrasies.
|
353
337
|
# WEBrick includes the full URL. IIS leaves REQUEST_URI blank.
|
@@ -373,36 +357,33 @@ EOM
|
|
373
357
|
end
|
374
358
|
end
|
375
359
|
end
|
376
|
-
memoize :request_uri
|
377
360
|
|
378
361
|
# Returns the interpreted \path to requested resource after all the installation
|
379
362
|
# directory of this application was taken into account.
|
380
363
|
def path
|
381
|
-
path =
|
382
|
-
|
383
|
-
|
384
|
-
path.sub!(%r/^#{ActionController::Base.relative_url_root}/, '')
|
385
|
-
path || ''
|
364
|
+
path = request_uri.to_s[/\A[^\?]*/]
|
365
|
+
path.sub!(/\A#{ActionController::Base.relative_url_root}/, '')
|
366
|
+
path
|
386
367
|
end
|
387
|
-
memoize :path
|
388
368
|
|
389
369
|
# Read the request \body. This is useful for web services that need to
|
390
370
|
# work with raw requests directly.
|
391
371
|
def raw_post
|
392
|
-
unless env.include? 'RAW_POST_DATA'
|
393
|
-
env['RAW_POST_DATA'] = body.read(
|
372
|
+
unless @env.include? 'RAW_POST_DATA'
|
373
|
+
@env['RAW_POST_DATA'] = body.read(@env['CONTENT_LENGTH'].to_i)
|
394
374
|
body.rewind if body.respond_to?(:rewind)
|
395
375
|
end
|
396
|
-
env['RAW_POST_DATA']
|
376
|
+
@env['RAW_POST_DATA']
|
397
377
|
end
|
398
378
|
|
399
379
|
# Returns both GET and POST \parameters in a single hash.
|
400
380
|
def parameters
|
401
381
|
@parameters ||= request_parameters.merge(query_parameters).update(path_parameters).with_indifferent_access
|
402
382
|
end
|
383
|
+
alias_method :params, :parameters
|
403
384
|
|
404
385
|
def path_parameters=(parameters) #:nodoc:
|
405
|
-
@
|
386
|
+
@env["rack.routing_args"] = parameters
|
406
387
|
@symbolized_path_parameters = @parameters = nil
|
407
388
|
end
|
408
389
|
|
@@ -418,464 +399,91 @@ EOM
|
|
418
399
|
#
|
419
400
|
# See <tt>symbolized_path_parameters</tt> for symbolized keys.
|
420
401
|
def path_parameters
|
421
|
-
@
|
402
|
+
@env["rack.routing_args"] ||= {}
|
422
403
|
end
|
423
404
|
|
424
405
|
# The request body is an IO input stream. If the RAW_POST_DATA environment
|
425
406
|
# variable is already set, wrap it in a StringIO.
|
426
407
|
def body
|
427
|
-
if raw_post = env['RAW_POST_DATA']
|
408
|
+
if raw_post = @env['RAW_POST_DATA']
|
428
409
|
raw_post.force_encoding(Encoding::BINARY) if raw_post.respond_to?(:force_encoding)
|
429
410
|
StringIO.new(raw_post)
|
430
411
|
else
|
431
|
-
|
412
|
+
@env['rack.input']
|
432
413
|
end
|
433
414
|
end
|
434
415
|
|
435
|
-
def
|
436
|
-
|
437
|
-
end
|
438
|
-
|
439
|
-
def referrer
|
440
|
-
@env['HTTP_REFERER']
|
416
|
+
def form_data?
|
417
|
+
FORM_DATA_MEDIA_TYPES.include?(content_type.to_s)
|
441
418
|
end
|
442
|
-
alias referer referrer
|
443
419
|
|
444
|
-
|
445
|
-
def
|
446
|
-
@query_parameters ||=
|
420
|
+
# Override Rack's GET method to support indifferent access
|
421
|
+
def GET
|
422
|
+
@env["action_controller.request.query_parameters"] ||= normalize_parameters(super)
|
447
423
|
end
|
424
|
+
alias_method :query_parameters, :GET
|
448
425
|
|
449
|
-
|
450
|
-
|
426
|
+
# Override Rack's POST method to support indifferent access
|
427
|
+
def POST
|
428
|
+
@env["action_controller.request.request_parameters"] ||= normalize_parameters(super)
|
451
429
|
end
|
452
|
-
|
453
|
-
|
454
|
-
#--
|
455
|
-
# Must be implemented in the concrete request
|
456
|
-
#++
|
430
|
+
alias_method :request_parameters, :POST
|
457
431
|
|
458
432
|
def body_stream #:nodoc:
|
433
|
+
@env['rack.input']
|
459
434
|
end
|
460
435
|
|
461
|
-
def
|
462
|
-
|
463
|
-
|
464
|
-
def session #:nodoc:
|
436
|
+
def session
|
437
|
+
@env['rack.session'] ||= {}
|
465
438
|
end
|
466
439
|
|
467
440
|
def session=(session) #:nodoc:
|
468
|
-
@session = session
|
441
|
+
@env['rack.session'] = session
|
469
442
|
end
|
470
443
|
|
471
|
-
def reset_session
|
444
|
+
def reset_session
|
445
|
+
@env['rack.session.options'].delete(:id)
|
446
|
+
@env['rack.session'] = {}
|
472
447
|
end
|
473
448
|
|
474
|
-
|
475
|
-
|
476
|
-
# charset or boundary which aren't included in the content_type MIME type.
|
477
|
-
# Overridden by the X-POST_DATA_FORMAT header for backward compatibility.
|
478
|
-
def content_type_with_parameters
|
479
|
-
content_type_from_legacy_post_data_format_header ||
|
480
|
-
env['CONTENT_TYPE'].to_s
|
481
|
-
end
|
482
|
-
|
483
|
-
# The raw content type string with its parameters stripped off.
|
484
|
-
def content_type_without_parameters
|
485
|
-
self.class.extract_content_type_without_parameters(content_type_with_parameters)
|
486
|
-
end
|
487
|
-
memoize :content_type_without_parameters
|
488
|
-
|
489
|
-
private
|
490
|
-
def content_type_from_legacy_post_data_format_header
|
491
|
-
if x_post_format = @env['HTTP_X_POST_DATA_FORMAT']
|
492
|
-
case x_post_format.to_s.downcase
|
493
|
-
when 'yaml'; 'application/x-yaml'
|
494
|
-
when 'xml'; 'application/xml'
|
495
|
-
end
|
496
|
-
end
|
497
|
-
end
|
498
|
-
|
499
|
-
def parse_formatted_request_parameters
|
500
|
-
return {} if content_length.zero?
|
501
|
-
|
502
|
-
content_type, boundary = self.class.extract_multipart_boundary(content_type_with_parameters)
|
503
|
-
|
504
|
-
# Don't parse params for unknown requests.
|
505
|
-
return {} if content_type.blank?
|
506
|
-
|
507
|
-
mime_type = Mime::Type.lookup(content_type)
|
508
|
-
strategy = ActionController::Base.param_parsers[mime_type]
|
509
|
-
|
510
|
-
# Only multipart form parsing expects a stream.
|
511
|
-
body = (strategy && strategy != :multipart_form) ? raw_post : self.body
|
512
|
-
|
513
|
-
case strategy
|
514
|
-
when Proc
|
515
|
-
strategy.call(body)
|
516
|
-
when :url_encoded_form
|
517
|
-
self.class.clean_up_ajax_request_body! body
|
518
|
-
self.class.parse_query_parameters(body)
|
519
|
-
when :multipart_form
|
520
|
-
self.class.parse_multipart_form_parameters(body, boundary, content_length, env)
|
521
|
-
when :xml_simple, :xml_node
|
522
|
-
body.blank? ? {} : Hash.from_xml(body).with_indifferent_access
|
523
|
-
when :yaml
|
524
|
-
YAML.load(body)
|
525
|
-
when :json
|
526
|
-
if body.blank?
|
527
|
-
{}
|
528
|
-
else
|
529
|
-
data = ActiveSupport::JSON.decode(body)
|
530
|
-
data = {:_json => data} unless data.is_a?(Hash)
|
531
|
-
data.with_indifferent_access
|
532
|
-
end
|
533
|
-
else
|
534
|
-
{}
|
535
|
-
end
|
536
|
-
rescue Exception => e # YAML, XML or Ruby code block errors
|
537
|
-
raise
|
538
|
-
{ "body" => body,
|
539
|
-
"content_type" => content_type_with_parameters,
|
540
|
-
"content_length" => content_length,
|
541
|
-
"exception" => "#{e.message} (#{e.class})",
|
542
|
-
"backtrace" => e.backtrace }
|
543
|
-
end
|
544
|
-
|
545
|
-
def named_host?(host)
|
546
|
-
!(host.nil? || /\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/.match(host))
|
547
|
-
end
|
548
|
-
|
549
|
-
class << self
|
550
|
-
def parse_query_parameters(query_string)
|
551
|
-
return {} if query_string.blank?
|
552
|
-
|
553
|
-
pairs = query_string.split('&').collect do |chunk|
|
554
|
-
next if chunk.empty?
|
555
|
-
key, value = chunk.split('=', 2)
|
556
|
-
next if key.empty?
|
557
|
-
value = value.nil? ? nil : CGI.unescape(value)
|
558
|
-
[ CGI.unescape(key), value ]
|
559
|
-
end.compact
|
560
|
-
|
561
|
-
UrlEncodedPairParser.new(pairs).result
|
562
|
-
end
|
563
|
-
|
564
|
-
def parse_request_parameters(params)
|
565
|
-
parser = UrlEncodedPairParser.new
|
566
|
-
|
567
|
-
params = params.dup
|
568
|
-
until params.empty?
|
569
|
-
for key, value in params
|
570
|
-
if key.blank?
|
571
|
-
params.delete key
|
572
|
-
elsif !key.include?('[')
|
573
|
-
# much faster to test for the most common case first (GET)
|
574
|
-
# and avoid the call to build_deep_hash
|
575
|
-
parser.result[key] = get_typed_value(value[0])
|
576
|
-
params.delete key
|
577
|
-
elsif value.is_a?(Array)
|
578
|
-
parser.parse(key, get_typed_value(value.shift))
|
579
|
-
params.delete key if value.empty?
|
580
|
-
else
|
581
|
-
raise TypeError, "Expected array, found #{value.inspect}"
|
582
|
-
end
|
583
|
-
end
|
584
|
-
end
|
585
|
-
|
586
|
-
parser.result
|
587
|
-
end
|
588
|
-
|
589
|
-
def parse_multipart_form_parameters(body, boundary, body_size, env)
|
590
|
-
parse_request_parameters(read_multipart(body, boundary, body_size, env))
|
591
|
-
end
|
592
|
-
|
593
|
-
def extract_multipart_boundary(content_type_with_parameters)
|
594
|
-
if content_type_with_parameters =~ MULTIPART_BOUNDARY
|
595
|
-
['multipart/form-data', $1.dup]
|
596
|
-
else
|
597
|
-
extract_content_type_without_parameters(content_type_with_parameters)
|
598
|
-
end
|
599
|
-
end
|
600
|
-
|
601
|
-
def extract_content_type_without_parameters(content_type_with_parameters)
|
602
|
-
$1.strip.downcase if content_type_with_parameters =~ /^([^,\;]*)/
|
603
|
-
end
|
604
|
-
|
605
|
-
def clean_up_ajax_request_body!(body)
|
606
|
-
body.chop! if body[-1] == 0
|
607
|
-
body.gsub!(/&_=$/, '')
|
608
|
-
end
|
609
|
-
|
610
|
-
|
611
|
-
private
|
612
|
-
def get_typed_value(value)
|
613
|
-
case value
|
614
|
-
when String
|
615
|
-
value
|
616
|
-
when NilClass
|
617
|
-
''
|
618
|
-
when Array
|
619
|
-
value.map { |v| get_typed_value(v) }
|
620
|
-
else
|
621
|
-
if value.respond_to? :original_filename
|
622
|
-
# Uploaded file
|
623
|
-
if value.original_filename
|
624
|
-
value
|
625
|
-
# Multipart param
|
626
|
-
else
|
627
|
-
result = value.read
|
628
|
-
value.rewind
|
629
|
-
result
|
630
|
-
end
|
631
|
-
# Unknown value, neither string nor multipart.
|
632
|
-
else
|
633
|
-
raise "Unknown form value: #{value.inspect}"
|
634
|
-
end
|
635
|
-
end
|
636
|
-
end
|
637
|
-
|
638
|
-
MULTIPART_BOUNDARY = %r|\Amultipart/form-data.*boundary=\"?([^\";,]+)\"?|n
|
639
|
-
|
640
|
-
EOL = "\015\012"
|
641
|
-
|
642
|
-
def read_multipart(body, boundary, body_size, env)
|
643
|
-
params = Hash.new([])
|
644
|
-
boundary = "--" + boundary
|
645
|
-
quoted_boundary = Regexp.quote(boundary)
|
646
|
-
buf = ""
|
647
|
-
bufsize = 10 * 1024
|
648
|
-
boundary_end=""
|
649
|
-
|
650
|
-
# start multipart/form-data
|
651
|
-
body.binmode if defined? body.binmode
|
652
|
-
case body
|
653
|
-
when File
|
654
|
-
body.set_encoding(Encoding::BINARY) if body.respond_to?(:set_encoding)
|
655
|
-
when StringIO
|
656
|
-
body.string.force_encoding(Encoding::BINARY) if body.string.respond_to?(:force_encoding)
|
657
|
-
end
|
658
|
-
boundary_size = boundary.size + EOL.size
|
659
|
-
body_size -= boundary_size
|
660
|
-
status = body.read(boundary_size)
|
661
|
-
if nil == status
|
662
|
-
raise EOFError, "no content body"
|
663
|
-
elsif boundary + EOL != status
|
664
|
-
raise EOFError, "bad content body"
|
665
|
-
end
|
666
|
-
|
667
|
-
loop do
|
668
|
-
head = nil
|
669
|
-
content =
|
670
|
-
if 10240 < body_size
|
671
|
-
UploadedTempfile.new("CGI")
|
672
|
-
else
|
673
|
-
UploadedStringIO.new
|
674
|
-
end
|
675
|
-
content.binmode if defined? content.binmode
|
676
|
-
|
677
|
-
until head and /#{quoted_boundary}(?:#{EOL}|--)/n.match(buf)
|
678
|
-
|
679
|
-
if (not head) and /#{EOL}#{EOL}/n.match(buf)
|
680
|
-
buf = buf.sub(/\A((?:.|\n)*?#{EOL})#{EOL}/n) do
|
681
|
-
head = $1.dup
|
682
|
-
""
|
683
|
-
end
|
684
|
-
next
|
685
|
-
end
|
686
|
-
|
687
|
-
if head and ( (EOL + boundary + EOL).size < buf.size )
|
688
|
-
content.print buf[0 ... (buf.size - (EOL + boundary + EOL).size)]
|
689
|
-
buf[0 ... (buf.size - (EOL + boundary + EOL).size)] = ""
|
690
|
-
end
|
691
|
-
|
692
|
-
c = if bufsize < body_size
|
693
|
-
body.read(bufsize)
|
694
|
-
else
|
695
|
-
body.read(body_size)
|
696
|
-
end
|
697
|
-
if c.nil? || c.empty?
|
698
|
-
raise EOFError, "bad content body"
|
699
|
-
end
|
700
|
-
buf.concat(c)
|
701
|
-
body_size -= c.size
|
702
|
-
end
|
703
|
-
|
704
|
-
buf = buf.sub(/\A((?:.|\n)*?)(?:[\r\n]{1,2})?#{quoted_boundary}([\r\n]{1,2}|--)/n) do
|
705
|
-
content.print $1
|
706
|
-
if "--" == $2
|
707
|
-
body_size = -1
|
708
|
-
end
|
709
|
-
boundary_end = $2.dup
|
710
|
-
""
|
711
|
-
end
|
712
|
-
|
713
|
-
content.rewind
|
714
|
-
|
715
|
-
head =~ /Content-Disposition:.* filename=(?:"((?:\\.|[^\"])*)"|([^;]*))/ni
|
716
|
-
if filename = $1 || $2
|
717
|
-
if /Mac/ni.match(env['HTTP_USER_AGENT']) and
|
718
|
-
/Mozilla/ni.match(env['HTTP_USER_AGENT']) and
|
719
|
-
(not /MSIE/ni.match(env['HTTP_USER_AGENT']))
|
720
|
-
filename = CGI.unescape(filename)
|
721
|
-
end
|
722
|
-
content.original_path = filename.dup
|
723
|
-
end
|
724
|
-
|
725
|
-
head =~ /Content-Type: ([^\r]*)/ni
|
726
|
-
content.content_type = $1.dup if $1
|
727
|
-
|
728
|
-
head =~ /Content-Disposition:.* name="?([^\";]*)"?/ni
|
729
|
-
name = $1.dup if $1
|
730
|
-
|
731
|
-
if params.has_key?(name)
|
732
|
-
params[name].push(content)
|
733
|
-
else
|
734
|
-
params[name] = [content]
|
735
|
-
end
|
736
|
-
break if body_size == -1
|
737
|
-
end
|
738
|
-
raise EOFError, "bad boundary end of body part" unless boundary_end=~/--/
|
739
|
-
|
740
|
-
begin
|
741
|
-
body.rewind if body.respond_to?(:rewind)
|
742
|
-
rescue Errno::ESPIPE
|
743
|
-
# Handles exceptions raised by input streams that cannot be rewound
|
744
|
-
# such as when using plain CGI under Apache
|
745
|
-
end
|
746
|
-
|
747
|
-
params
|
748
|
-
end
|
449
|
+
def session_options
|
450
|
+
@env['rack.session.options'] ||= {}
|
749
451
|
end
|
750
|
-
end
|
751
452
|
|
752
|
-
|
753
|
-
|
754
|
-
|
755
|
-
def initialize(pairs = [])
|
756
|
-
super('')
|
757
|
-
@result = {}
|
758
|
-
pairs.each { |key, value| parse(key, value) }
|
453
|
+
def session_options=(options)
|
454
|
+
@env['rack.session.options'] = options
|
759
455
|
end
|
760
456
|
|
761
|
-
|
762
|
-
|
763
|
-
|
764
|
-
# Parse the query string
|
765
|
-
def parse(key, value)
|
766
|
-
self.string = key
|
767
|
-
@top, @parent = result, nil
|
768
|
-
|
769
|
-
# First scan the bare key
|
770
|
-
key = scan(KEY_REGEXP) or return
|
771
|
-
key = post_key_check(key)
|
772
|
-
|
773
|
-
# Then scan as many nestings as present
|
774
|
-
until eos?
|
775
|
-
r = scan(BRACKETED_KEY_REGEXP) or return
|
776
|
-
key = self[1]
|
777
|
-
key = post_key_check(key)
|
778
|
-
end
|
779
|
-
|
780
|
-
bind(key, value)
|
457
|
+
def server_port
|
458
|
+
@env['SERVER_PORT'].to_i
|
781
459
|
end
|
782
460
|
|
783
461
|
private
|
784
|
-
|
785
|
-
|
786
|
-
# [] follows the key. Then the value must be an array.
|
787
|
-
# = follows the key. (A value comes next)
|
788
|
-
# & or the end of string follows the key. Then the key is a flag.
|
789
|
-
# otherwise, a hash follows the key.
|
790
|
-
def post_key_check(key)
|
791
|
-
if scan(/\[\]/) # a[b][] indicates that b is an array
|
792
|
-
container(key, Array)
|
793
|
-
nil
|
794
|
-
elsif check(/\[[^\]]/) # a[b] indicates that a is a hash
|
795
|
-
container(key, Hash)
|
796
|
-
nil
|
797
|
-
else # End of key? We do nothing.
|
798
|
-
key
|
799
|
-
end
|
800
|
-
end
|
801
|
-
|
802
|
-
# Add a container to the stack.
|
803
|
-
def container(key, klass)
|
804
|
-
type_conflict! klass, top[key] if top.is_a?(Hash) && top.key?(key) && ! top[key].is_a?(klass)
|
805
|
-
value = bind(key, klass.new)
|
806
|
-
type_conflict! klass, value unless value.is_a?(klass)
|
807
|
-
push(value)
|
808
|
-
end
|
809
|
-
|
810
|
-
# Push a value onto the 'stack', which is actually only the top 2 items.
|
811
|
-
def push(value)
|
812
|
-
@parent, @top = @top, value
|
462
|
+
def named_host?(host)
|
463
|
+
!(host.nil? || /\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/.match(host))
|
813
464
|
end
|
814
465
|
|
815
|
-
#
|
816
|
-
|
817
|
-
|
818
|
-
|
819
|
-
|
820
|
-
|
821
|
-
|
822
|
-
|
823
|
-
|
824
|
-
|
825
|
-
|
466
|
+
# Convert nested Hashs to HashWithIndifferentAccess and replace
|
467
|
+
# file upload hashs with UploadedFile objects
|
468
|
+
def normalize_parameters(value)
|
469
|
+
case value
|
470
|
+
when Hash
|
471
|
+
if value.has_key?(:tempfile)
|
472
|
+
upload = value[:tempfile]
|
473
|
+
upload.extend(UploadedFile)
|
474
|
+
upload.original_path = value[:filename]
|
475
|
+
upload.content_type = value[:type]
|
476
|
+
upload
|
826
477
|
else
|
827
|
-
|
478
|
+
h = {}
|
479
|
+
value.each { |k, v| h[k] = normalize_parameters(v) }
|
480
|
+
h.with_indifferent_access
|
828
481
|
end
|
829
|
-
|
830
|
-
|
831
|
-
parent << (@top = {}) if top.key?(key) && parent.is_a?(Array)
|
832
|
-
top[key] ||= value
|
833
|
-
return top[key]
|
482
|
+
when Array
|
483
|
+
value.map { |e| normalize_parameters(e) }
|
834
484
|
else
|
835
|
-
|
485
|
+
value
|
836
486
|
end
|
837
|
-
|
838
|
-
return value
|
839
487
|
end
|
840
|
-
|
841
|
-
def type_conflict!(klass, value)
|
842
|
-
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}.)"
|
843
|
-
end
|
844
|
-
end
|
845
|
-
|
846
|
-
module UploadedFile
|
847
|
-
def self.included(base)
|
848
|
-
base.class_eval do
|
849
|
-
attr_accessor :original_path, :content_type
|
850
|
-
alias_method :local_path, :path
|
851
|
-
end
|
852
|
-
end
|
853
|
-
|
854
|
-
# Take the basename of the upload's original filename.
|
855
|
-
# This handles the full Windows paths given by Internet Explorer
|
856
|
-
# (and perhaps other broken user agents) without affecting
|
857
|
-
# those which give the lone filename.
|
858
|
-
# The Windows regexp is adapted from Perl's File::Basename.
|
859
|
-
def original_filename
|
860
|
-
unless defined? @original_filename
|
861
|
-
@original_filename =
|
862
|
-
unless original_path.blank?
|
863
|
-
if original_path =~ /^(?:.*[:\\\/])?(.*)/m
|
864
|
-
$1
|
865
|
-
else
|
866
|
-
File.basename original_path
|
867
|
-
end
|
868
|
-
end
|
869
|
-
end
|
870
|
-
@original_filename
|
871
|
-
end
|
872
|
-
end
|
873
|
-
|
874
|
-
class UploadedStringIO < StringIO
|
875
|
-
include UploadedFile
|
876
|
-
end
|
877
|
-
|
878
|
-
class UploadedTempfile < Tempfile
|
879
|
-
include UploadedFile
|
880
488
|
end
|
881
489
|
end
|