diff options
Diffstat (limited to 'actionpack/lib/action_dispatch/http')
-rw-r--r-- | actionpack/lib/action_dispatch/http/headers.rb | 54 | ||||
-rw-r--r-- | actionpack/lib/action_dispatch/http/parameters.rb | 41 | ||||
-rw-r--r-- | actionpack/lib/action_dispatch/http/request.rb | 21 | ||||
-rw-r--r-- | actionpack/lib/action_dispatch/http/upload.rb | 8 |
4 files changed, 79 insertions, 45 deletions
diff --git a/actionpack/lib/action_dispatch/http/headers.rb b/actionpack/lib/action_dispatch/http/headers.rb index dc04d4577b..2666cd4b0a 100644 --- a/actionpack/lib/action_dispatch/http/headers.rb +++ b/actionpack/lib/action_dispatch/http/headers.rb @@ -1,38 +1,62 @@ module ActionDispatch module Http class Headers + CGI_VARIABLES = %w( + CONTENT_TYPE CONTENT_LENGTH + HTTPS AUTH_TYPE GATEWAY_INTERFACE + PATH_INFO PATH_TRANSLATED QUERY_STRING + REMOTE_ADDR REMOTE_HOST REMOTE_IDENT REMOTE_USER + REQUEST_METHOD SCRIPT_NAME + SERVER_NAME SERVER_PORT SERVER_PROTOCOL SERVER_SOFTWARE + ) + HTTP_HEADER = /\A[A-Za-z0-9-]+\z/ + include Enumerable + attr_reader :env def initialize(env = {}) - @headers = env + @env = env + end + + def [](key) + @env[env_name(key)] end - def [](header_name) - @headers[env_name(header_name)] + def []=(key, value) + @env[env_name(key)] = value end - def []=(k,v); @headers[k] = v; end - def key?(k); @headers.key? k; end + def key?(key); @env.key? key; end alias :include? :key? - def fetch(header_name, *args, &block) - @headers.fetch env_name(header_name), *args, &block + def fetch(key, *args, &block) + @env.fetch env_name(key), *args, &block end def each(&block) - @headers.each(&block) + @env.each(&block) end - private + def merge(headers_or_env) + headers = Http::Headers.new(env.dup) + headers.merge!(headers_or_env) + headers + end - # Converts a HTTP header name to an environment variable name if it is - # not contained within the headers hash. - def env_name(header_name) - @headers.include?(header_name) ? header_name : cgi_name(header_name) + def merge!(headers_or_env) + headers_or_env.each do |key, value| + self[env_name(key)] = value + end end - def cgi_name(k) - "HTTP_#{k.upcase.gsub(/-/, '_')}" + private + def env_name(key) + key = key.to_s + if key =~ HTTP_HEADER + key = key.upcase.tr('-', '_') + key = "HTTP_" + key unless CGI_VARIABLES.include?(key) + end + key end end end diff --git a/actionpack/lib/action_dispatch/http/parameters.rb b/actionpack/lib/action_dispatch/http/parameters.rb index 446862aad0..246d9c121a 100644 --- a/actionpack/lib/action_dispatch/http/parameters.rb +++ b/actionpack/lib/action_dispatch/http/parameters.rb @@ -18,7 +18,7 @@ module ActionDispatch query_parameters.dup end params.merge!(path_parameters) - encode_params(params).with_indifferent_access + params.with_indifferent_access end end alias :params :parameters @@ -50,40 +50,33 @@ module ActionDispatch private + # Convert nested Hash to HashWithIndifferentAccess + # and UTF-8 encode both keys and values in nested Hash. + # # TODO: Validate that the characters are UTF-8. If they aren't, # you'll get a weird error down the road, but our form handling # should really prevent that from happening - def encode_params(params) + def normalize_encode_params(params) if params.is_a?(String) return params.force_encoding(Encoding::UTF_8).encode! elsif !params.is_a?(Hash) return params end + new_hash = {} params.each do |k, v| - case v - when Hash - encode_params(v) - when Array - v.map! {|el| encode_params(el) } - else - encode_params(v) - end - end - end - - # Convert nested Hash to ActiveSupport::HashWithIndifferentAccess - def normalize_parameters(value) - case value - when Hash - h = {} - value.each { |k, v| h[k] = normalize_parameters(v) } - h.with_indifferent_access - when Array - value.map { |e| normalize_parameters(e) } - else - value + new_key = k.is_a?(String) ? k.dup.force_encoding("UTF-8").encode! : k + new_hash[new_key] = + case v + when Hash + normalize_encode_params(v) + when Array + v.map! {|el| normalize_encode_params(el) } + else + normalize_encode_params(v) + end end + new_hash.with_indifferent_access end end end diff --git a/actionpack/lib/action_dispatch/http/request.rb b/actionpack/lib/action_dispatch/http/request.rb index 7b04d6e851..aff2172788 100644 --- a/actionpack/lib/action_dispatch/http/request.rb +++ b/actionpack/lib/action_dispatch/http/request.rb @@ -156,14 +156,31 @@ module ActionDispatch @original_fullpath ||= (env["ORIGINAL_FULLPATH"] || fullpath) end + # Returns the +String+ full path including params of the last URL requested. + # + # app.get "/articles" + # app.request.fullpath # => "/articles" + # + # app.get "/articles?page=2" + # app.request.fullpath # => "/articles?page=2" def fullpath @fullpath ||= super end + # Returns the original request URL as a +String+ + # + # app.get "/articles?page=2" + # app.request.original_url + # # => "http://www.example.com/articles?page=2" def original_url base_url + original_fullpath end + # The +String+ MIME type of the request + # + # app.get "/articles" + # app.request.media_type + # # => "application/x-www-form-urlencoded" def media_type content_mime_type.to_s end @@ -256,7 +273,7 @@ module ActionDispatch # Override Rack's GET method to support indifferent access def GET - @env["action_dispatch.request.query_parameters"] ||= (normalize_parameters(super) || {}) + @env["action_dispatch.request.query_parameters"] ||= (normalize_encode_params(super) || {}) rescue TypeError => e raise ActionController::BadRequest.new(:query, e) end @@ -264,7 +281,7 @@ module ActionDispatch # Override Rack's POST method to support indifferent access def POST - @env["action_dispatch.request.request_parameters"] ||= (normalize_parameters(super) || {}) + @env["action_dispatch.request.request_parameters"] ||= (normalize_encode_params(super) || {}) rescue TypeError => e raise ActionController::BadRequest.new(:request, e) end diff --git a/actionpack/lib/action_dispatch/http/upload.rb b/actionpack/lib/action_dispatch/http/upload.rb index 67cb7fbcb5..319d0197d1 100644 --- a/actionpack/lib/action_dispatch/http/upload.rb +++ b/actionpack/lib/action_dispatch/http/upload.rb @@ -75,16 +75,16 @@ module ActionDispatch end module Upload # :nodoc: - # Convert nested Hash to ActiveSupport::HashWithIndifferentAccess and replace - # file upload hash with UploadedFile objects - def normalize_parameters(value) + # Replace file upload hash with UploadedFile objects + # when normalize and encode parameters. + def normalize_encode_params(value) if Hash === value && value.has_key?(:tempfile) UploadedFile.new(value) else super end end - private :normalize_parameters + private :normalize_encode_params end end end |