diff options
author | David Heinemeier Hansson <david@loudthinking.com> | 2005-07-23 09:00:05 +0000 |
---|---|---|
committer | David Heinemeier Hansson <david@loudthinking.com> | 2005-07-23 09:00:05 +0000 |
commit | b366dbd952417a610913e05ad58024b7da03fdb8 (patch) | |
tree | 0ca8e594c78a92cec73ca0abec49fec90d8373e3 /actionpack/lib/action_controller/cgi_ext | |
parent | d1725929852ab9da48f7ff7c4fa7f401ac55c331 (diff) | |
download | rails-b366dbd952417a610913e05ad58024b7da03fdb8.tar.gz rails-b366dbd952417a610913e05ad58024b7da03fdb8.tar.bz2 rails-b366dbd952417a610913e05ad58024b7da03fdb8.zip |
Improved performance with 5-30% through a series of Action Pack optimizations #1811 [Stefan Kaes]
git-svn-id: http://svn-commit.rubyonrails.org/rails/trunk@1905 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
Diffstat (limited to 'actionpack/lib/action_controller/cgi_ext')
3 files changed, 82 insertions, 62 deletions
diff --git a/actionpack/lib/action_controller/cgi_ext/cgi_methods.rb b/actionpack/lib/action_controller/cgi_ext/cgi_methods.rb index c8ed3fb385..d922e48b10 100755 --- a/actionpack/lib/action_controller/cgi_ext/cgi_methods.rb +++ b/actionpack/lib/action_controller/cgi_ext/cgi_methods.rb @@ -12,10 +12,10 @@ class CGIMethods #:nodoc: query_string.split(/[&;]/).each { |p| k, v = p.split('=',2) - v = nil if (!v.nil? && v.empty?) + v = nil if (v && v.empty?) - k = CGI.unescape(k) unless k.nil? - v = CGI.unescape(v) unless v.nil? + k = CGI.unescape(k) if k + v = CGI.unescape(v) if v keys = split_key(k) last_key = keys.pop @@ -27,7 +27,7 @@ class CGIMethods #:nodoc: end } - return parsed_params + parsed_params end # Returns the request (POST/GET) parameters in a parsed form where pairs such as "customer[address][street]" / @@ -38,14 +38,16 @@ class CGIMethods #:nodoc: for key, value in params value = [value] if key =~ /.*\[\]$/ - CGIMethods.build_deep_hash( - CGIMethods.get_typed_value(value[0]), - parsed_params, - CGIMethods.get_levels(key) - ) + unless key.include?('[') + # much faster to test for the most common case first (GET) + # and avoid the call to build_deep_hash + parsed_params[key] = get_typed_value(value[0]) + else + build_deep_hash(get_typed_value(value[0]), parsed_params, get_levels(key)) + end end - return parsed_params + parsed_params end def self.parse_formatted_request_parameters(format, raw_post_data) @@ -72,14 +74,17 @@ class CGIMethods #:nodoc: keys.concat($2[1..-2].split('][')) keys << '' if key[-2..-1] == '[]' # Have to add it since split will drop empty strings - return keys + keys else - return [key] + [key] end end def CGIMethods.get_typed_value(value) - if value.respond_to?(:content_type) && !value.content_type.empty? + # test most frequent case first + if value.is_a?(String) + value + elsif value.respond_to?(:content_type) && !value.content_type.empty? # Uploaded file value elsif value.respond_to?(:read) @@ -88,7 +93,7 @@ class CGIMethods #:nodoc: elsif value.class == Array value.collect { |v| CGIMethods.get_typed_value(v) } else - # Standard value (not a multipart request) + # other value (neither string nor a multipart request) value.to_s end end diff --git a/actionpack/lib/action_controller/cgi_ext/cookie_performance_fix.rb b/actionpack/lib/action_controller/cgi_ext/cookie_performance_fix.rb index 225cea1905..1c30f82b19 100644 --- a/actionpack/lib/action_controller/cgi_ext/cookie_performance_fix.rb +++ b/actionpack/lib/action_controller/cgi_ext/cookie_performance_fix.rb @@ -23,28 +23,32 @@ class CGI #:nodoc: # servers. # # These keywords correspond to attributes of the cookie object. - def initialize(name = "", *value) - options = if name.kind_of?(String) - { "name" => name, "value" => value } - else - name - end - unless options.has_key?("name") + def initialize(name = '', *value) + if name.kind_of?(String) + @name = name + @value = Array(value) + @domain = nil + @expires = nil + @secure = false + @path = nil + else + @name = name['name'] + @value = Array(name['value']) + @domain = name['domain'] + @expires = name['expires'] + @secure = name['secure'] || false + @path = name['path'] + end + + unless @name raise ArgumentError, "`name' required" end - @name = options["name"] - @value = Array(options["value"]) # simple support for IE - if options["path"] - @path = options["path"] - else - %r|^(.*/)|.match(ENV["SCRIPT_NAME"]) - @path = ($1 or "") + unless @path + %r|^(.*/)|.match(ENV['SCRIPT_NAME']) + @path = ($1 or '') end - @domain = options["domain"] - @expires = options["expires"] - @secure = options["secure"] == true ? true : false super(@value) end @@ -102,20 +106,20 @@ class CGI #:nodoc: # def self.parse(raw_cookie) cookies = Hash.new([]) - return cookies unless raw_cookie - - raw_cookie.split(/; /).each do |pairs| - name, values = pairs.split('=',2) - next unless name and values - name = CGI::unescape(name) - values ||= "" - values = values.split('&').collect{|v| CGI::unescape(v) } - unless cookies.has_key?(name) - cookies[name] = new({ "name" => name, "value" => values }) + + if raw_cookie + raw_cookie.split(/; /).each do |pairs| + name, values = pairs.split('=',2) + next unless name and values + name = CGI::unescape(name) + values = values.split('&').collect!{|v| CGI::unescape(v) } + unless cookies.has_key?(name) + cookies[name] = new(name, *values) + end end end cookies end end # class Cookie -end
\ No newline at end of file +end diff --git a/actionpack/lib/action_controller/cgi_ext/raw_post_data_fix.rb b/actionpack/lib/action_controller/cgi_ext/raw_post_data_fix.rb index b2194eb07b..20fc6ff47f 100644 --- a/actionpack/lib/action_controller/cgi_ext/raw_post_data_fix.rb +++ b/actionpack/lib/action_controller/cgi_ext/raw_post_data_fix.rb @@ -6,14 +6,21 @@ class CGI #:nodoc: # Handles multipart forms (in particular, forms that involve file uploads). # Reads query parameters in the @params field, and cookies into @cookies. def initialize_query() - @cookies = CGI::Cookie::parse((env_table['HTTP_COOKIE'] || env_table['COOKIE'])) + @cookies = CGI::Cookie::parse(env_table['HTTP_COOKIE'] || env_table['COOKIE']) - if boundary = multipart_form_boundary + #fix some strange request environments + if method = env_table['REQUEST_METHOD'] + method = method.to_s.downcase.intern + else + method = :get + end + + if method == :post && (boundary = multipart_form_boundary) @multipart = true @params = read_multipart(boundary, Integer(env_table['CONTENT_LENGTH'])) else @multipart = false - @params = CGI::parse(read_query_params || "") + @params = CGI::parse(read_query_params(method) || "") end end @@ -22,21 +29,23 @@ class CGI #:nodoc: MULTIPART_FORM_BOUNDARY_RE = %r|\Amultipart/form-data.*boundary=\"?([^\";,]+)\"?|n #" end - def multipart_form_boundary - if env_table['REQUEST_METHOD'] == 'POST' - MULTIPART_FORM_BOUNDARY_RE.match(env_table['CONTENT_TYPE']).to_a.pop - end + def multipart_form_boundary + MULTIPART_FORM_BOUNDARY_RE.match(env_table['CONTENT_TYPE']).to_a.pop end - def read_params_from_query - if defined? MOD_RUBY + if defined? MOD_RUBY + def read_params_from_query Apache::request.args || '' - else - # fixes CGI querystring parsing for POSTs - if env_table['QUERY_STRING'].blank? && !env_table['REQUEST_URI'].blank? - env_table['QUERY_STRING'] = env_table['REQUEST_URI'].split('?', 2)[1] || '' + end + else + def read_params_from_query + # fixes CGI querystring parsing for lighttpd + env_qs = env_table['QUERY_STRING'] + if env_qs.blank? && !(uri=env_table['REQUEST_URI']).blank? + env_qs.replace(uri.split('?', 2)[1] || '') + else + env_qs end - env_table['QUERY_STRING'] end end @@ -46,13 +55,15 @@ class CGI #:nodoc: env_table['RAW_POST_DATA'] = content.split("&_").first.to_s.freeze # &_ is a fix for Safari Ajax postings that always append \000 end - def read_query_params - case env_table['REQUEST_METHOD'].to_s.upcase - when 'CMD' - read_from_cmdline - when 'POST', 'PUT' + def read_query_params(method) + case method + when :get + read_params_from_query + when :post, :put read_params_from_post - else # when 'GET', 'HEAD', 'DELETE', 'OPTIONS' + when :cmd + read_from_cmdline + else # when :head, :delete, :options read_params_from_query end end |