aboutsummaryrefslogtreecommitdiffstats
path: root/actionpack/lib/action_controller/dispatch
diff options
context:
space:
mode:
authorJoshua Peek <josh@joshpeek.com>2009-01-27 18:54:01 -0600
committerJoshua Peek <josh@joshpeek.com>2009-01-27 18:54:01 -0600
commit319ae4628f4e0058de3e40e4ca7791b17e45e70c (patch)
treee5da1bfe6dd69a9cf483c9ff9fd18c5bfdd2f463 /actionpack/lib/action_controller/dispatch
parenta0f2b1d95d3785de92ae271fd7ea23e91c0cadc6 (diff)
downloadrails-319ae4628f4e0058de3e40e4ca7791b17e45e70c.tar.gz
rails-319ae4628f4e0058de3e40e4ca7791b17e45e70c.tar.bz2
rails-319ae4628f4e0058de3e40e4ca7791b17e45e70c.zip
Move HTTP libs and middleware into ActionDispatch component
Diffstat (limited to 'actionpack/lib/action_controller/dispatch')
-rw-r--r--actionpack/lib/action_controller/dispatch/dispatcher.rb4
-rw-r--r--actionpack/lib/action_controller/dispatch/middlewares.rb (renamed from actionpack/lib/action_controller/dispatch/rack/middlewares.rb)10
-rw-r--r--actionpack/lib/action_controller/dispatch/params_parser.rb71
-rw-r--r--actionpack/lib/action_controller/dispatch/rack/failsafe.rb52
-rw-r--r--actionpack/lib/action_controller/dispatch/rack/lock.rb16
-rw-r--r--actionpack/lib/action_controller/dispatch/rack/middleware_stack.rb109
-rwxr-xr-xactionpack/lib/action_controller/dispatch/request.rb492
-rw-r--r--actionpack/lib/action_controller/dispatch/request_parser.rb315
-rw-r--r--actionpack/lib/action_controller/dispatch/rescue.rb4
-rw-r--r--actionpack/lib/action_controller/dispatch/response.rb255
-rw-r--r--actionpack/lib/action_controller/dispatch/rewindable_input.rb28
-rw-r--r--actionpack/lib/action_controller/dispatch/status_codes.rb88
-rw-r--r--actionpack/lib/action_controller/dispatch/uploaded_file.rb44
-rw-r--r--actionpack/lib/action_controller/dispatch/url_encoded_pair_parser.rb155
14 files changed, 9 insertions, 1634 deletions
diff --git a/actionpack/lib/action_controller/dispatch/dispatcher.rb b/actionpack/lib/action_controller/dispatch/dispatcher.rb
index 714e270781..e205245f13 100644
--- a/actionpack/lib/action_controller/dispatch/dispatcher.rb
+++ b/actionpack/lib/action_controller/dispatch/dispatcher.rb
@@ -45,8 +45,8 @@ module ActionController
end
cattr_accessor :middleware
- self.middleware = MiddlewareStack.new do |middleware|
- middlewares = File.join(File.dirname(__FILE__), "rack", "middlewares.rb")
+ self.middleware = ActionDispatch::MiddlewareStack.new do |middleware|
+ middlewares = File.join(File.dirname(__FILE__), "middlewares.rb")
middleware.instance_eval(File.read(middlewares))
end
diff --git a/actionpack/lib/action_controller/dispatch/rack/middlewares.rb b/actionpack/lib/action_controller/dispatch/middlewares.rb
index f9cfc2b18e..3bf3dbebab 100644
--- a/actionpack/lib/action_controller/dispatch/rack/middlewares.rb
+++ b/actionpack/lib/action_controller/dispatch/middlewares.rb
@@ -2,10 +2,10 @@ use "Rack::Lock", :if => lambda {
!ActionController::Base.allow_concurrency
}
-use "ActionController::Failsafe"
+use "ActionDispatch::Failsafe"
-["ActionController::Session::CookieStore",
- "ActionController::Session::MemCacheStore",
+["ActionDispatch::Session::CookieStore",
+ "ActionDispatch::Session::MemCacheStore",
"ActiveRecord::SessionStore"].each do |store|
use(store, ActionController::Base.session_options,
:if => lambda {
@@ -16,6 +16,6 @@ use "ActionController::Failsafe"
)
end
-use "ActionController::RewindableInput"
-use "ActionController::ParamsParser"
+use "ActionDispatch::RewindableInput"
+use "ActionDispatch::ParamsParser"
use "Rack::MethodOverride"
diff --git a/actionpack/lib/action_controller/dispatch/params_parser.rb b/actionpack/lib/action_controller/dispatch/params_parser.rb
deleted file mode 100644
index d269fe07fa..0000000000
--- a/actionpack/lib/action_controller/dispatch/params_parser.rb
+++ /dev/null
@@ -1,71 +0,0 @@
-module ActionController
- class ParamsParser
- ActionController::Base.param_parsers[Mime::XML] = :xml_simple
- ActionController::Base.param_parsers[Mime::JSON] = :json
-
- def initialize(app)
- @app = app
- end
-
- def call(env)
- if params = parse_formatted_parameters(env)
- env["action_controller.request.request_parameters"] = params
- end
-
- @app.call(env)
- end
-
- private
- def parse_formatted_parameters(env)
- request = Request.new(env)
-
- return false if request.content_length.zero?
-
- mime_type = content_type_from_legacy_post_data_format_header(env) || request.content_type
- strategy = ActionController::Base.param_parsers[mime_type]
-
- return false unless strategy
-
- case strategy
- when Proc
- strategy.call(request.raw_post)
- when :xml_simple, :xml_node
- body = request.raw_post
- body.blank? ? {} : Hash.from_xml(body).with_indifferent_access
- when :yaml
- YAML.load(request.raw_post)
- when :json
- body = request.raw_post
- if body.blank?
- {}
- else
- data = ActiveSupport::JSON.decode(body)
- data = {:_json => data} unless data.is_a?(Hash)
- data.with_indifferent_access
- end
- else
- false
- end
- rescue Exception => e # YAML, XML or Ruby code block errors
- raise
- { "body" => request.raw_post,
- "content_type" => request.content_type,
- "content_length" => request.content_length,
- "exception" => "#{e.message} (#{e.class})",
- "backtrace" => e.backtrace }
- end
-
- def content_type_from_legacy_post_data_format_header(env)
- if x_post_format = env['HTTP_X_POST_DATA_FORMAT']
- case x_post_format.to_s.downcase
- when 'yaml'
- return Mime::YAML
- when 'xml'
- return Mime::XML
- end
- end
-
- nil
- end
- end
-end
diff --git a/actionpack/lib/action_controller/dispatch/rack/failsafe.rb b/actionpack/lib/action_controller/dispatch/rack/failsafe.rb
deleted file mode 100644
index 567581142c..0000000000
--- a/actionpack/lib/action_controller/dispatch/rack/failsafe.rb
+++ /dev/null
@@ -1,52 +0,0 @@
-module ActionController
- class Failsafe
- cattr_accessor :error_file_path
- self.error_file_path = Rails.public_path if defined?(Rails.public_path)
-
- def initialize(app)
- @app = app
- end
-
- def call(env)
- @app.call(env)
- rescue Exception => exception
- # Reraise exception in test environment
- if env["rack.test"]
- raise exception
- else
- failsafe_response(exception)
- end
- end
-
- private
- def failsafe_response(exception)
- log_failsafe_exception(exception)
- [500, {'Content-Type' => 'text/html'}, failsafe_response_body]
- rescue Exception => failsafe_error # Logger or IO errors
- $stderr.puts "Error during failsafe response: #{failsafe_error}"
- end
-
- def failsafe_response_body
- error_path = "#{self.class.error_file_path}/500.html"
- if File.exist?(error_path)
- File.read(error_path)
- else
- "<html><body><h1>500 Internal Server Error</h1></body></html>"
- end
- end
-
- def log_failsafe_exception(exception)
- message = "/!\\ FAILSAFE /!\\ #{Time.now}\n Status: 500 Internal Server Error\n"
- message << " #{exception}\n #{exception.backtrace.join("\n ")}" if exception
- failsafe_logger.fatal(message)
- end
-
- def failsafe_logger
- if defined?(Rails) && Rails.logger
- Rails.logger
- else
- Logger.new($stderr)
- end
- end
- end
-end
diff --git a/actionpack/lib/action_controller/dispatch/rack/lock.rb b/actionpack/lib/action_controller/dispatch/rack/lock.rb
deleted file mode 100644
index c50762216e..0000000000
--- a/actionpack/lib/action_controller/dispatch/rack/lock.rb
+++ /dev/null
@@ -1,16 +0,0 @@
-module ActionController
- class Lock
- FLAG = 'rack.multithread'.freeze
-
- def initialize(app, lock = Mutex.new)
- @app, @lock = app, lock
- end
-
- def call(env)
- old, env[FLAG] = env[FLAG], false
- @lock.synchronize { @app.call(env) }
- ensure
- env[FLAG] = old
- end
- end
-end
diff --git a/actionpack/lib/action_controller/dispatch/rack/middleware_stack.rb b/actionpack/lib/action_controller/dispatch/rack/middleware_stack.rb
deleted file mode 100644
index dbc2fda41e..0000000000
--- a/actionpack/lib/action_controller/dispatch/rack/middleware_stack.rb
+++ /dev/null
@@ -1,109 +0,0 @@
-module ActionController
- class MiddlewareStack < Array
- class Middleware
- def self.new(klass, *args, &block)
- if klass.is_a?(self)
- klass
- else
- super
- end
- end
-
- attr_reader :args, :block
-
- def initialize(klass, *args, &block)
- @klass = klass
-
- options = args.extract_options!
- if options.has_key?(:if)
- @conditional = options.delete(:if)
- else
- @conditional = true
- end
- args << options unless options.empty?
-
- @args = args
- @block = block
- end
-
- def klass
- if @klass.is_a?(Class)
- @klass
- else
- @klass.to_s.constantize
- end
- rescue NameError
- @klass
- end
-
- def active?
- if @conditional.respond_to?(:call)
- @conditional.call
- else
- @conditional
- end
- end
-
- def ==(middleware)
- case middleware
- when Middleware
- klass == middleware.klass
- when Class
- klass == middleware
- else
- klass == middleware.to_s.constantize
- end
- end
-
- def inspect
- str = klass.to_s
- args.each { |arg| str += ", #{arg.inspect}" }
- str
- end
-
- def build(app)
- if block
- klass.new(app, *args, &block)
- else
- klass.new(app, *args)
- end
- end
- end
-
- def initialize(*args, &block)
- super(*args)
- block.call(self) if block_given?
- end
-
- def insert(index, *args, &block)
- index = self.index(index) unless index.is_a?(Integer)
- middleware = Middleware.new(*args, &block)
- super(index, middleware)
- end
-
- alias_method :insert_before, :insert
-
- def insert_after(index, *args, &block)
- index = self.index(index) unless index.is_a?(Integer)
- insert(index + 1, *args, &block)
- end
-
- def swap(target, *args, &block)
- insert_before(target, *args, &block)
- delete(target)
- end
-
- def use(*args, &block)
- middleware = Middleware.new(*args, &block)
- push(middleware)
- end
-
- def active
- find_all { |middleware| middleware.active? }
- end
-
- def build(app)
- active.reverse.inject(app) { |a, e| e.build(a) }
- end
- end
-end
diff --git a/actionpack/lib/action_controller/dispatch/request.rb b/actionpack/lib/action_controller/dispatch/request.rb
deleted file mode 100755
index f8c77241b9..0000000000
--- a/actionpack/lib/action_controller/dispatch/request.rb
+++ /dev/null
@@ -1,492 +0,0 @@
-require 'tempfile'
-require 'stringio'
-require 'strscan'
-
-require 'active_support/memoizable'
-require 'action_controller/cgi_ext'
-
-module ActionController
- class Request < Rack::Request
- extend ActiveSupport::Memoizable
-
- %w[ AUTH_TYPE GATEWAY_INTERFACE
- PATH_TRANSLATED REMOTE_HOST
- REMOTE_IDENT REMOTE_USER REMOTE_ADDR
- SERVER_NAME SERVER_PROTOCOL
-
- HTTP_ACCEPT HTTP_ACCEPT_CHARSET HTTP_ACCEPT_ENCODING
- HTTP_ACCEPT_LANGUAGE HTTP_CACHE_CONTROL HTTP_FROM
- HTTP_NEGOTIATE HTTP_PRAGMA HTTP_REFERER HTTP_USER_AGENT ].each do |env|
- define_method(env.sub(/^HTTP_/n, '').downcase) do
- @env[env]
- end
- end
-
- def key?(key)
- @env.key?(key)
- end
-
- HTTP_METHODS = %w(get head put post delete options)
- HTTP_METHOD_LOOKUP = HTTP_METHODS.inject({}) { |h, m| h[m] = h[m.upcase] = m.to_sym; h }
-
- # Returns the true HTTP request \method as a lowercase symbol, such as
- # <tt>:get</tt>. If the request \method is not listed in the HTTP_METHODS
- # constant above, an UnknownHttpMethod exception is raised.
- def request_method
- HTTP_METHOD_LOOKUP[super] || raise(UnknownHttpMethod, "#{super}, accepted HTTP methods are #{HTTP_METHODS.to_sentence}")
- end
- memoize :request_method
-
- # Returns the HTTP request \method used for action processing as a
- # lowercase symbol, such as <tt>:post</tt>. (Unlike #request_method, this
- # method returns <tt>:get</tt> for a HEAD request because the two are
- # functionally equivalent from the application's perspective.)
- def method
- request_method == :head ? :get : request_method
- end
-
- # Is this a GET (or HEAD) request? Equivalent to <tt>request.method == :get</tt>.
- def get?
- method == :get
- end
-
- # Is this a POST request? Equivalent to <tt>request.method == :post</tt>.
- def post?
- request_method == :post
- end
-
- # Is this a PUT request? Equivalent to <tt>request.method == :put</tt>.
- def put?
- request_method == :put
- end
-
- # Is this a DELETE request? Equivalent to <tt>request.method == :delete</tt>.
- def delete?
- request_method == :delete
- end
-
- # Is this a HEAD request? Since <tt>request.method</tt> sees HEAD as <tt>:get</tt>,
- # this \method checks the actual HTTP \method directly.
- def head?
- request_method == :head
- end
-
- # Provides access to the request's HTTP headers, for example:
- #
- # request.headers["Content-Type"] # => "text/plain"
- def headers
- ActionController::Http::Headers.new(@env)
- end
- memoize :headers
-
- # Returns the content length of the request as an integer.
- def content_length
- super.to_i
- end
-
- # The MIME type of the HTTP request, such as Mime::XML.
- #
- # For backward compatibility, the post \format is extracted from the
- # X-Post-Data-Format HTTP header if present.
- def content_type
- if @env['CONTENT_TYPE'] =~ /^([^,\;]*)/
- Mime::Type.lookup($1.strip.downcase)
- else
- nil
- end
- end
- memoize :content_type
-
- # Returns the accepted MIME type for the request.
- def accepts
- header = @env['HTTP_ACCEPT'].to_s.strip
-
- fallback = xhr? ? Mime::JS : Mime::HTML
-
- if header.empty?
- [content_type, fallback, Mime::ALL].compact
- else
- ret = Mime::Type.parse(header)
- if ret.last == Mime::ALL
- ret.insert(-2, fallback)
- end
- ret
- end
- end
- memoize :accepts
-
- def if_modified_since
- if since = env['HTTP_IF_MODIFIED_SINCE']
- Time.rfc2822(since) rescue nil
- end
- end
- memoize :if_modified_since
-
- def if_none_match
- env['HTTP_IF_NONE_MATCH']
- end
-
- def not_modified?(modified_at)
- if_modified_since && modified_at && if_modified_since >= modified_at
- end
-
- def etag_matches?(etag)
- if_none_match && if_none_match == etag
- end
-
- # Check response freshness (Last-Modified and ETag) against request
- # If-Modified-Since and If-None-Match conditions. If both headers are
- # supplied, both must match, or the request is not considered fresh.
- def fresh?(response)
- case
- when if_modified_since && if_none_match
- not_modified?(response.last_modified) && etag_matches?(response.etag)
- when if_modified_since
- not_modified?(response.last_modified)
- when if_none_match
- etag_matches?(response.etag)
- else
- false
- end
- end
-
- ONLY_ALL = [Mime::ALL].freeze
-
- # Returns the Mime type for the \format used in the request.
- #
- # GET /posts/5.xml | request.format => Mime::XML
- # GET /posts/5.xhtml | request.format => Mime::HTML
- # GET /posts/5 | request.format => Mime::HTML or MIME::JS, or request.accepts.first depending on the value of <tt>ActionController::Base.use_accept_header</tt>
-
- def format(view_path = [])
- @format ||=
- if parameters[:format]
- Mime[parameters[:format]]
- elsif Base.use_accept_header && !(accepts == ONLY_ALL)
- accepts.first
- elsif xhr? then Mime::JS
- else Mime::HTML
- end
- end
-
- def formats
- @formats =
- if Base.use_accept_header
- ret = Array(Mime[parameters[:format]] || accepts)
- else
- [format]
- end
- end
-
- # Sets the \format by string extension, which can be used to force custom formats
- # that are not controlled by the extension.
- #
- # class ApplicationController < ActionController::Base
- # before_filter :adjust_format_for_iphone
- #
- # private
- # def adjust_format_for_iphone
- # request.format = :iphone if request.env["HTTP_USER_AGENT"][/iPhone/]
- # end
- # end
- def format=(extension)
- parameters[:format] = extension.to_s
- @format = Mime::Type.lookup_by_extension(parameters[:format])
- end
-
- # Returns a symbolized version of the <tt>:format</tt> parameter of the request.
- # If no \format is given it returns <tt>:js</tt>for Ajax requests and <tt>:html</tt>
- # otherwise.
- def template_format
- parameter_format = parameters[:format]
-
- if parameter_format
- parameter_format
- elsif xhr?
- :js
- else
- :html
- end
- end
-
- def cache_format
- parameters[:format]
- end
-
- # Returns true if the request's "X-Requested-With" header contains
- # "XMLHttpRequest". (The Prototype Javascript library sends this header with
- # every Ajax request.)
- def xml_http_request?
- !(@env['HTTP_X_REQUESTED_WITH'] !~ /XMLHttpRequest/i)
- end
- alias xhr? :xml_http_request?
-
- # Which IP addresses are "trusted proxies" that can be stripped from
- # the right-hand-side of X-Forwarded-For
- TRUSTED_PROXIES = /^127\.0\.0\.1$|^(10|172\.(1[6-9]|2[0-9]|30|31)|192\.168)\./i
-
- # Determines originating IP address. REMOTE_ADDR is the standard
- # but will fail if the user is behind a proxy. HTTP_CLIENT_IP and/or
- # HTTP_X_FORWARDED_FOR are set by proxies so check for these if
- # REMOTE_ADDR is a proxy. HTTP_X_FORWARDED_FOR may be a comma-
- # delimited list in the case of multiple chained proxies; the last
- # address which is not trusted is the originating IP.
- def remote_ip
- remote_addr_list = @env['REMOTE_ADDR'] && @env['REMOTE_ADDR'].scan(/[^,\s]+/)
-
- unless remote_addr_list.blank?
- not_trusted_addrs = remote_addr_list.reject {|addr| addr =~ TRUSTED_PROXIES}
- return not_trusted_addrs.first unless not_trusted_addrs.empty?
- end
- remote_ips = @env['HTTP_X_FORWARDED_FOR'] && @env['HTTP_X_FORWARDED_FOR'].split(',')
-
- if @env.include? 'HTTP_CLIENT_IP'
- if ActionController::Base.ip_spoofing_check && remote_ips && !remote_ips.include?(@env['HTTP_CLIENT_IP'])
- # We don't know which came from the proxy, and which from the user
- raise ActionControllerError.new(<<EOM)
-IP spoofing attack?!
-HTTP_CLIENT_IP=#{@env['HTTP_CLIENT_IP'].inspect}
-HTTP_X_FORWARDED_FOR=#{@env['HTTP_X_FORWARDED_FOR'].inspect}
-EOM
- end
-
- return @env['HTTP_CLIENT_IP']
- end
-
- if remote_ips
- while remote_ips.size > 1 && TRUSTED_PROXIES =~ remote_ips.last.strip
- remote_ips.pop
- end
-
- return remote_ips.last.strip
- end
-
- @env['REMOTE_ADDR']
- end
- memoize :remote_ip
-
- # Returns the lowercase name of the HTTP server software.
- def server_software
- (@env['SERVER_SOFTWARE'] && /^([a-zA-Z]+)/ =~ @env['SERVER_SOFTWARE']) ? $1.downcase : nil
- end
- memoize :server_software
-
- # Returns the complete URL used for this request.
- def url
- protocol + host_with_port + request_uri
- end
- memoize :url
-
- # Returns 'https://' if this is an SSL request and 'http://' otherwise.
- def protocol
- ssl? ? 'https://' : 'http://'
- end
- memoize :protocol
-
- # Is this an SSL request?
- def ssl?
- @env['HTTPS'] == 'on' || @env['HTTP_X_FORWARDED_PROTO'] == 'https'
- end
-
- # Returns the \host for this request, such as "example.com".
- def raw_host_with_port
- if forwarded = env["HTTP_X_FORWARDED_HOST"]
- forwarded.split(/,\s?/).last
- else
- env['HTTP_HOST'] || "#{env['SERVER_NAME'] || env['SERVER_ADDR']}:#{env['SERVER_PORT']}"
- end
- end
-
- # Returns the host for this request, such as example.com.
- def host
- raw_host_with_port.sub(/:\d+$/, '')
- end
- memoize :host
-
- # Returns a \host:\port string for this request, such as "example.com" or
- # "example.com:8080".
- def host_with_port
- "#{host}#{port_string}"
- end
- memoize :host_with_port
-
- # Returns the port number of this request as an integer.
- def port
- if raw_host_with_port =~ /:(\d+)$/
- $1.to_i
- else
- standard_port
- end
- end
- memoize :port
-
- # Returns the standard \port number for this request's protocol.
- def standard_port
- case protocol
- when 'https://' then 443
- else 80
- end
- end
-
- # Returns a \port suffix like ":8080" if the \port number of this request
- # is not the default HTTP \port 80 or HTTPS \port 443.
- def port_string
- port == standard_port ? '' : ":#{port}"
- end
-
- # Returns the \domain part of a \host, such as "rubyonrails.org" in "www.rubyonrails.org". You can specify
- # a different <tt>tld_length</tt>, such as 2 to catch rubyonrails.co.uk in "www.rubyonrails.co.uk".
- def domain(tld_length = 1)
- return nil unless named_host?(host)
-
- host.split('.').last(1 + tld_length).join('.')
- end
-
- # Returns all the \subdomains as an array, so <tt>["dev", "www"]</tt> would be
- # returned for "dev.www.rubyonrails.org". You can specify a different <tt>tld_length</tt>,
- # such as 2 to catch <tt>["www"]</tt> instead of <tt>["www", "rubyonrails"]</tt>
- # in "www.rubyonrails.co.uk".
- def subdomains(tld_length = 1)
- return [] unless named_host?(host)
- parts = host.split('.')
- parts[0..-(tld_length+2)]
- end
-
- # Returns the query string, accounting for server idiosyncrasies.
- def query_string
- @env['QUERY_STRING'].present? ? @env['QUERY_STRING'] : (@env['REQUEST_URI'].split('?', 2)[1] || '')
- end
- memoize :query_string
-
- # Returns the request URI, accounting for server idiosyncrasies.
- # WEBrick includes the full URL. IIS leaves REQUEST_URI blank.
- def request_uri
- if uri = @env['REQUEST_URI']
- # Remove domain, which webrick puts into the request_uri.
- (%r{^\w+\://[^/]+(/.*|$)$} =~ uri) ? $1 : uri
- else
- # Construct IIS missing REQUEST_URI from SCRIPT_NAME and PATH_INFO.
- uri = @env['PATH_INFO'].to_s
-
- if script_filename = @env['SCRIPT_NAME'].to_s.match(%r{[^/]+$})
- uri = uri.sub(/#{script_filename}\//, '')
- end
-
- env_qs = @env['QUERY_STRING'].to_s
- uri += "?#{env_qs}" unless env_qs.empty?
-
- if uri.blank?
- @env.delete('REQUEST_URI')
- else
- @env['REQUEST_URI'] = uri
- end
- end
- end
- memoize :request_uri
-
- # Returns the interpreted \path to requested resource after all the installation
- # directory of this application was taken into account.
- def path
- path = request_uri.to_s[/\A[^\?]*/]
- path.sub!(/\A#{ActionController::Base.relative_url_root}/, '')
- path
- end
- memoize :path
-
- # Read the request \body. This is useful for web services that need to
- # work with raw requests directly.
- def raw_post
- unless @env.include? 'RAW_POST_DATA'
- @env['RAW_POST_DATA'] = body.read(@env['CONTENT_LENGTH'].to_i)
- body.rewind if body.respond_to?(:rewind)
- end
- @env['RAW_POST_DATA']
- end
-
- # Returns both GET and POST \parameters in a single hash.
- def parameters
- @parameters ||= request_parameters.merge(query_parameters).update(path_parameters).with_indifferent_access
- end
- alias_method :params, :parameters
-
- def path_parameters=(parameters) #:nodoc:
- @env["rack.routing_args"] = parameters
- @symbolized_path_parameters = @parameters = nil
- end
-
- # The same as <tt>path_parameters</tt> with explicitly symbolized keys.
- def symbolized_path_parameters
- @symbolized_path_parameters ||= path_parameters.symbolize_keys
- end
-
- # Returns a hash with the \parameters used to form the \path of the request.
- # Returned hash keys are strings:
- #
- # {'action' => 'my_action', 'controller' => 'my_controller'}
- #
- # See <tt>symbolized_path_parameters</tt> for symbolized keys.
- def path_parameters
- @env["rack.routing_args"] ||= {}
- end
-
- # The request body is an IO input stream. If the RAW_POST_DATA environment
- # variable is already set, wrap it in a StringIO.
- def body
- if raw_post = @env['RAW_POST_DATA']
- raw_post.force_encoding(Encoding::BINARY) if raw_post.respond_to?(:force_encoding)
- StringIO.new(raw_post)
- else
- @env['rack.input']
- end
- end
-
- def form_data?
- FORM_DATA_MEDIA_TYPES.include?(content_type.to_s)
- end
-
- # Override Rack's GET method to support nested query strings
- def GET
- @env["action_controller.request.query_parameters"] ||= UrlEncodedPairParser.parse_query_parameters(query_string)
- end
- alias_method :query_parameters, :GET
-
- # Override Rack's POST method to support nested query strings
- def POST
- @env["action_controller.request.request_parameters"] ||= UrlEncodedPairParser.parse_hash_parameters(super)
- end
- alias_method :request_parameters, :POST
-
- def body_stream #:nodoc:
- @env['rack.input']
- end
-
- def session
- @env['rack.session'] ||= {}
- end
-
- def session=(session) #:nodoc:
- @env['rack.session'] = session
- end
-
- def reset_session
- @env['rack.session'] = {}
- end
-
- def session_options
- @env['rack.session.options'] ||= {}
- end
-
- def session_options=(options)
- @env['rack.session.options'] = options
- end
-
- def server_port
- @env['SERVER_PORT'].to_i
- end
-
- private
- def named_host?(host)
- !(host.nil? || /\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/.match(host))
- end
- end
-end
diff --git a/actionpack/lib/action_controller/dispatch/request_parser.rb b/actionpack/lib/action_controller/dispatch/request_parser.rb
deleted file mode 100644
index d1739ef4d0..0000000000
--- a/actionpack/lib/action_controller/dispatch/request_parser.rb
+++ /dev/null
@@ -1,315 +0,0 @@
-module ActionController
- class RequestParser
- def initialize(env)
- @env = env
- freeze
- end
-
- def request_parameters
- @env["action_controller.request_parser.request_parameters"] ||= parse_formatted_request_parameters
- end
-
- def query_parameters
- @env["action_controller.request_parser.query_parameters"] ||= self.class.parse_query_parameters(query_string)
- end
-
- # Returns the query string, accounting for server idiosyncrasies.
- def query_string
- @env['QUERY_STRING'].present? ? @env['QUERY_STRING'] : (@env['REQUEST_URI'].split('?', 2)[1] || '')
- end
-
- # The request body is an IO input stream. If the RAW_POST_DATA environment
- # variable is already set, wrap it in a StringIO.
- def body
- if raw_post = @env['RAW_POST_DATA']
- raw_post.force_encoding(Encoding::BINARY) if raw_post.respond_to?(:force_encoding)
- StringIO.new(raw_post)
- else
- @env['rack.input']
- end
- end
-
- # The raw content type string with its parameters stripped off.
- def content_type_without_parameters
- self.class.extract_content_type_without_parameters(content_type_with_parameters)
- end
-
- def raw_post
- unless @env.include? 'RAW_POST_DATA'
- @env['RAW_POST_DATA'] = body.read(content_length)
- body.rewind if body.respond_to?(:rewind)
- end
- @env['RAW_POST_DATA']
- end
-
- private
-
- def parse_formatted_request_parameters
- return {} if content_length.zero?
-
- content_type, boundary = self.class.extract_multipart_boundary(content_type_with_parameters)
-
- # Don't parse params for unknown requests.
- return {} if content_type.blank?
-
- mime_type = Mime::Type.lookup(content_type)
- strategy = ActionController::Base.param_parsers[mime_type]
-
- # Only multipart form parsing expects a stream.
- body = (strategy && strategy != :multipart_form) ? raw_post : self.body
-
- case strategy
- when Proc
- strategy.call(body)
- when :url_encoded_form
- self.class.clean_up_ajax_request_body! body
- self.class.parse_query_parameters(body)
- when :multipart_form
- self.class.parse_multipart_form_parameters(body, boundary, content_length, @env)
- when :xml_simple, :xml_node
- body.blank? ? {} : Hash.from_xml(body).with_indifferent_access
- when :yaml
- YAML.load(body)
- when :json
- if body.blank?
- {}
- else
- data = ActiveSupport::JSON.decode(body)
- data = {:_json => data} unless data.is_a?(Hash)
- data.with_indifferent_access
- end
- else
- {}
- end
- rescue Exception => e # YAML, XML or Ruby code block errors
- raise
- { "body" => body,
- "content_type" => content_type_with_parameters,
- "content_length" => content_length,
- "exception" => "#{e.message} (#{e.class})",
- "backtrace" => e.backtrace }
- end
-
- def content_length
- @env['CONTENT_LENGTH'].to_i
- end
-
- # The raw content type string. Use when you need parameters such as
- # charset or boundary which aren't included in the content_type MIME type.
- # Overridden by the X-POST_DATA_FORMAT header for backward compatibility.
- def content_type_with_parameters
- content_type_from_legacy_post_data_format_header || @env['CONTENT_TYPE'].to_s
- end
-
- def content_type_from_legacy_post_data_format_header
- if x_post_format = @env['HTTP_X_POST_DATA_FORMAT']
- case x_post_format.to_s.downcase
- when 'yaml'; 'application/x-yaml'
- when 'xml'; 'application/xml'
- end
- end
- end
-
- class << self
- def parse_query_parameters(query_string)
- return {} if query_string.blank?
-
- pairs = query_string.split('&').collect do |chunk|
- next if chunk.empty?
- key, value = chunk.split('=', 2)
- next if key.empty?
- value = value.nil? ? nil : CGI.unescape(value)
- [ CGI.unescape(key), value ]
- end.compact
-
- UrlEncodedPairParser.new(pairs).result
- end
-
- def parse_request_parameters(params)
- parser = UrlEncodedPairParser.new
-
- params = params.dup
- until params.empty?
- for key, value in params
- if key.blank?
- params.delete key
- elsif !key.include?('[')
- # much faster to test for the most common case first (GET)
- # and avoid the call to build_deep_hash
- parser.result[key] = get_typed_value(value[0])
- params.delete key
- elsif value.is_a?(Array)
- parser.parse(key, get_typed_value(value.shift))
- params.delete key if value.empty?
- else
- raise TypeError, "Expected array, found #{value.inspect}"
- end
- end
- end
-
- parser.result
- end
-
- def parse_multipart_form_parameters(body, boundary, body_size, env)
- parse_request_parameters(read_multipart(body, boundary, body_size, env))
- end
-
- def extract_multipart_boundary(content_type_with_parameters)
- if content_type_with_parameters =~ MULTIPART_BOUNDARY
- ['multipart/form-data', $1.dup]
- else
- extract_content_type_without_parameters(content_type_with_parameters)
- end
- end
-
- def extract_content_type_without_parameters(content_type_with_parameters)
- $1.strip.downcase if content_type_with_parameters =~ /^([^,\;]*)/
- end
-
- def clean_up_ajax_request_body!(body)
- body.chop! if body[-1] == 0
- body.gsub!(/&_=$/, '')
- end
-
-
- private
- def get_typed_value(value)
- case value
- when String
- value
- when NilClass
- ''
- when Array
- value.map { |v| get_typed_value(v) }
- else
- if value.respond_to? :original_filename
- # Uploaded file
- if value.original_filename
- value
- # Multipart param
- else
- result = value.read
- value.rewind
- result
- end
- # Unknown value, neither string nor multipart.
- else
- raise "Unknown form value: #{value.inspect}"
- end
- end
- end
-
- MULTIPART_BOUNDARY = %r|\Amultipart/form-data.*boundary=\"?([^\";,]+)\"?|n
-
- EOL = "\015\012"
-
- def read_multipart(body, boundary, body_size, env)
- params = Hash.new([])
- boundary = "--" + boundary
- quoted_boundary = Regexp.quote(boundary)
- buf = ""
- bufsize = 10 * 1024
- boundary_end=""
-
- # start multipart/form-data
- body.binmode if defined? body.binmode
- case body
- when File
- body.set_encoding(Encoding::BINARY) if body.respond_to?(:set_encoding)
- when StringIO
- body.string.force_encoding(Encoding::BINARY) if body.string.respond_to?(:force_encoding)
- end
- boundary_size = boundary.size + EOL.size
- body_size -= boundary_size
- status = body.read(boundary_size)
- if nil == status
- raise EOFError, "no content body"
- elsif boundary + EOL != status
- raise EOFError, "bad content body"
- end
-
- loop do
- head = nil
- content =
- if 10240 < body_size
- UploadedTempfile.new("CGI")
- else
- UploadedStringIO.new
- end
- content.binmode if defined? content.binmode
-
- until head and /#{quoted_boundary}(?:#{EOL}|--)/n.match(buf)
-
- if (not head) and /#{EOL}#{EOL}/n.match(buf)
- buf = buf.sub(/\A((?:.|\n)*?#{EOL})#{EOL}/n) do
- head = $1.dup
- ""
- end
- next
- end
-
- if head and ( (EOL + boundary + EOL).size < buf.size )
- content.print buf[0 ... (buf.size - (EOL + boundary + EOL).size)]
- buf[0 ... (buf.size - (EOL + boundary + EOL).size)] = ""
- end
-
- c = if bufsize < body_size
- body.read(bufsize)
- else
- body.read(body_size)
- end
- if c.nil? || c.empty?
- raise EOFError, "bad content body"
- end
- buf.concat(c)
- body_size -= c.size
- end
-
- buf = buf.sub(/\A((?:.|\n)*?)(?:[\r\n]{1,2})?#{quoted_boundary}([\r\n]{1,2}|--)/n) do
- content.print $1
- if "--" == $2
- body_size = -1
- end
- boundary_end = $2.dup
- ""
- end
-
- content.rewind
-
- head =~ /Content-Disposition:.* filename=(?:"((?:\\.|[^\"])*)"|([^;]*))/ni
- if filename = $1 || $2
- if /Mac/ni.match(env['HTTP_USER_AGENT']) and
- /Mozilla/ni.match(env['HTTP_USER_AGENT']) and
- (not /MSIE/ni.match(env['HTTP_USER_AGENT']))
- filename = CGI.unescape(filename)
- end
- content.original_path = filename.dup
- end
-
- head =~ /Content-Type: ([^\r]*)/ni
- content.content_type = $1.dup if $1
-
- head =~ /Content-Disposition:.* name="?([^\";]*)"?/ni
- name = $1.dup if $1
-
- if params.has_key?(name)
- params[name].push(content)
- else
- params[name] = [content]
- end
- break if body_size == -1
- end
- raise EOFError, "bad boundary end of body part" unless boundary_end=~/--/
-
- begin
- body.rewind if body.respond_to?(:rewind)
- rescue Errno::ESPIPE
- # Handles exceptions raised by input streams that cannot be rewound
- # such as when using plain CGI under Apache
- end
-
- params
- end
- end # class << self
- end
-end
diff --git a/actionpack/lib/action_controller/dispatch/rescue.rb b/actionpack/lib/action_controller/dispatch/rescue.rb
index 0293e62fc7..df0a976204 100644
--- a/actionpack/lib/action_controller/dispatch/rescue.rb
+++ b/actionpack/lib/action_controller/dispatch/rescue.rb
@@ -60,8 +60,8 @@ module ActionController #:nodoc:
module ClassMethods
def call_with_exception(env, exception) #:nodoc:
- request = env["action_controller.rescue.request"] ||= ActionController::Request.new(env)
- response = env["action_controller.rescue.response"] ||= ActionController::Response.new
+ request = env["action_controller.rescue.request"] ||= ActionDispatch::Request.new(env)
+ response = env["action_controller.rescue.response"] ||= ActionDispatch::Response.new
new.process(request, response, :rescue_action, exception)
end
end
diff --git a/actionpack/lib/action_controller/dispatch/response.rb b/actionpack/lib/action_controller/dispatch/response.rb
deleted file mode 100644
index 27860a6207..0000000000
--- a/actionpack/lib/action_controller/dispatch/response.rb
+++ /dev/null
@@ -1,255 +0,0 @@
-require 'digest/md5'
-
-module ActionController # :nodoc:
- # Represents an HTTP response generated by a controller action. One can use
- # an ActionController::Response object to retrieve the current state
- # of the response, or customize the response. An Response object can
- # either represent a "real" HTTP response (i.e. one that is meant to be sent
- # back to the web browser) or a test response (i.e. one that is generated
- # from integration tests). See CgiResponse and TestResponse, respectively.
- #
- # Response is mostly a Ruby on Rails framework implement detail, and
- # should never be used directly in controllers. Controllers should use the
- # methods defined in ActionController::Base instead. For example, if you want
- # to set the HTTP response's content MIME type, then use
- # ActionControllerBase#headers instead of Response#headers.
- #
- # Nevertheless, integration tests may want to inspect controller responses in
- # more detail, and that's when Response can be useful for application
- # developers. Integration test methods such as
- # ActionController::Integration::Session#get and
- # ActionController::Integration::Session#post return objects of type
- # TestResponse (which are of course also of type Response).
- #
- # For example, the following demo integration "test" prints the body of the
- # controller response to the console:
- #
- # class DemoControllerTest < ActionController::IntegrationTest
- # def test_print_root_path_to_console
- # get('/')
- # puts @response.body
- # end
- # end
- class Response < Rack::Response
- DEFAULT_HEADERS = { "Cache-Control" => "no-cache" }
- attr_accessor :request
-
- attr_accessor :session, :assigns, :template, :layout
- attr_accessor :redirected_to, :redirected_to_method_params
-
- delegate :default_charset, :to => 'ActionController::Base'
-
- def initialize
- @status = 200
- @header = DEFAULT_HEADERS.dup
-
- @writer = lambda { |x| @body << x }
- @block = nil
-
- @body = "",
- @session, @assigns = [], []
- end
-
- def location; headers['Location'] end
- def location=(url) headers['Location'] = url end
-
-
- # Sets the HTTP response's content MIME type. For example, in the controller
- # you could write this:
- #
- # response.content_type = "text/plain"
- #
- # If a character set has been defined for this response (see charset=) then
- # the character set information will also be included in the content type
- # information.
- def content_type=(mime_type)
- self.headers["Content-Type"] =
- if mime_type =~ /charset/ || (c = charset).nil?
- mime_type.to_s
- else
- "#{mime_type}; charset=#{c}"
- end
- end
-
- # Returns the response's content MIME type, or nil if content type has been set.
- def content_type
- content_type = String(headers["Content-Type"] || headers["type"]).split(";")[0]
- content_type.blank? ? nil : content_type
- end
-
- # Set the charset of the Content-Type header. Set to nil to remove it.
- # If no content type is set, it defaults to HTML.
- def charset=(charset)
- headers["Content-Type"] =
- if charset
- "#{content_type || Mime::HTML}; charset=#{charset}"
- else
- content_type || Mime::HTML.to_s
- end
- end
-
- def charset
- charset = String(headers["Content-Type"] || headers["type"]).split(";")[1]
- charset.blank? ? nil : charset.strip.split("=")[1]
- end
-
- def last_modified
- if last = headers['Last-Modified']
- Time.httpdate(last)
- end
- end
-
- def last_modified?
- headers.include?('Last-Modified')
- end
-
- def last_modified=(utc_time)
- headers['Last-Modified'] = utc_time.httpdate
- end
-
- def etag
- headers['ETag']
- end
-
- def etag?
- headers.include?('ETag')
- end
-
- def etag=(etag)
- if etag.blank?
- headers.delete('ETag')
- else
- headers['ETag'] = %("#{Digest::MD5.hexdigest(ActiveSupport::Cache.expand_cache_key(etag))}")
- end
- end
-
- def redirect(url, status)
- self.status = status
- self.location = url.gsub(/[\r\n]/, '')
- self.body = "<html><body>You are being <a href=\"#{CGI.escapeHTML(url)}\">redirected</a>.</body></html>"
- end
-
- def sending_file?
- headers["Content-Transfer-Encoding"] == "binary"
- end
-
- def assign_default_content_type_and_charset!
- self.content_type ||= Mime::HTML
- self.charset ||= default_charset unless sending_file?
- end
-
- def prepare!
- assign_default_content_type_and_charset!
- handle_conditional_get!
- set_content_length!
- convert_content_type!
- convert_language!
- convert_expires!
- convert_cookies!
- end
-
- def each(&callback)
- if @body.respond_to?(:call)
- @writer = lambda { |x| callback.call(x) }
- @body.call(self, self)
- elsif @body.is_a?(String)
- @body.each_line(&callback)
- else
- @body.each(&callback)
- end
-
- @writer = callback
- @block.call(self) if @block
- end
-
- def write(str)
- @writer.call str.to_s
- str
- end
-
- # Over Rack::Response#set_cookie to add HttpOnly option
- def set_cookie(key, value)
- case value
- when Hash
- domain = "; domain=" + value[:domain] if value[:domain]
- path = "; path=" + value[:path] if value[:path]
- # According to RFC 2109, we need dashes here.
- # N.B.: cgi.rb uses spaces...
- expires = "; expires=" + value[:expires].clone.gmtime.
- strftime("%a, %d-%b-%Y %H:%M:%S GMT") if value[:expires]
- secure = "; secure" if value[:secure]
- httponly = "; HttpOnly" if value[:http_only]
- value = value[:value]
- end
- value = [value] unless Array === value
- cookie = ::Rack::Utils.escape(key) + "=" +
- value.map { |v| ::Rack::Utils.escape v }.join("&") +
- "#{domain}#{path}#{expires}#{secure}#{httponly}"
-
- case self["Set-Cookie"]
- when Array
- self["Set-Cookie"] << cookie
- when String
- self["Set-Cookie"] = [self["Set-Cookie"], cookie]
- when nil
- self["Set-Cookie"] = cookie
- end
- end
-
- private
- def handle_conditional_get!
- if etag? || last_modified?
- set_conditional_cache_control!
- elsif nonempty_ok_response?
- self.etag = body
-
- if request && request.etag_matches?(etag)
- self.status = '304 Not Modified'
- self.body = ''
- end
-
- set_conditional_cache_control!
- end
- end
-
- def nonempty_ok_response?
- ok = !status || status.to_s[0..2] == '200'
- ok && body.is_a?(String) && !body.empty?
- end
-
- def set_conditional_cache_control!
- if headers['Cache-Control'] == DEFAULT_HEADERS['Cache-Control']
- headers['Cache-Control'] = 'private, max-age=0, must-revalidate'
- end
- end
-
- def convert_content_type!
- headers['Content-Type'] ||= "text/html"
- headers['Content-Type'] += "; charset=" + headers.delete('charset') if headers['charset']
- end
-
- # Don't set the Content-Length for block-based bodies as that would mean
- # reading it all into memory. Not nice for, say, a 2GB streaming file.
- def set_content_length!
- if status && status.to_s[0..2] == '204'
- headers.delete('Content-Length')
- elsif length = headers['Content-Length']
- headers['Content-Length'] = length.to_s
- elsif !body.respond_to?(:call) && (!status || status.to_s[0..2] != '304')
- headers["Content-Length"] = body.size.to_s
- end
- end
-
- def convert_language!
- headers["Content-Language"] = headers.delete("language") if headers["language"]
- end
-
- def convert_expires!
- headers["Expires"] = headers.delete("") if headers["expires"]
- end
-
- def convert_cookies!
- headers['Set-Cookie'] = Array(headers['Set-Cookie']).compact
- end
- end
-end
diff --git a/actionpack/lib/action_controller/dispatch/rewindable_input.rb b/actionpack/lib/action_controller/dispatch/rewindable_input.rb
deleted file mode 100644
index 36f655c51e..0000000000
--- a/actionpack/lib/action_controller/dispatch/rewindable_input.rb
+++ /dev/null
@@ -1,28 +0,0 @@
-module ActionController
- class RewindableInput
- class RewindableIO < ActiveSupport::BasicObject
- def initialize(io)
- @io = io
- @rewindable = io.is_a?(StringIO)
- end
-
- def method_missing(method, *args, &block)
- unless @rewindable
- @io = StringIO.new(@io.read)
- @rewindable = true
- end
-
- @io.__send__(method, *args, &block)
- end
- end
-
- def initialize(app)
- @app = app
- end
-
- def call(env)
- env['rack.input'] = RewindableIO.new(env['rack.input'])
- @app.call(env)
- end
- end
-end
diff --git a/actionpack/lib/action_controller/dispatch/status_codes.rb b/actionpack/lib/action_controller/dispatch/status_codes.rb
deleted file mode 100644
index 4977c79491..0000000000
--- a/actionpack/lib/action_controller/dispatch/status_codes.rb
+++ /dev/null
@@ -1,88 +0,0 @@
-module ActionController
- module StatusCodes #:nodoc:
- # Defines the standard HTTP status codes, by integer, with their
- # corresponding default message texts.
- # Source: http://www.iana.org/assignments/http-status-codes
- STATUS_CODES = {
- 100 => "Continue",
- 101 => "Switching Protocols",
- 102 => "Processing",
-
- 200 => "OK",
- 201 => "Created",
- 202 => "Accepted",
- 203 => "Non-Authoritative Information",
- 204 => "No Content",
- 205 => "Reset Content",
- 206 => "Partial Content",
- 207 => "Multi-Status",
- 226 => "IM Used",
-
- 300 => "Multiple Choices",
- 301 => "Moved Permanently",
- 302 => "Found",
- 303 => "See Other",
- 304 => "Not Modified",
- 305 => "Use Proxy",
- 307 => "Temporary Redirect",
-
- 400 => "Bad Request",
- 401 => "Unauthorized",
- 402 => "Payment Required",
- 403 => "Forbidden",
- 404 => "Not Found",
- 405 => "Method Not Allowed",
- 406 => "Not Acceptable",
- 407 => "Proxy Authentication Required",
- 408 => "Request Timeout",
- 409 => "Conflict",
- 410 => "Gone",
- 411 => "Length Required",
- 412 => "Precondition Failed",
- 413 => "Request Entity Too Large",
- 414 => "Request-URI Too Long",
- 415 => "Unsupported Media Type",
- 416 => "Requested Range Not Satisfiable",
- 417 => "Expectation Failed",
- 422 => "Unprocessable Entity",
- 423 => "Locked",
- 424 => "Failed Dependency",
- 426 => "Upgrade Required",
-
- 500 => "Internal Server Error",
- 501 => "Not Implemented",
- 502 => "Bad Gateway",
- 503 => "Service Unavailable",
- 504 => "Gateway Timeout",
- 505 => "HTTP Version Not Supported",
- 507 => "Insufficient Storage",
- 510 => "Not Extended"
- }
-
- # Provides a symbol-to-fixnum lookup for converting a symbol (like
- # :created or :not_implemented) into its corresponding HTTP status
- # code (like 200 or 501).
- SYMBOL_TO_STATUS_CODE = STATUS_CODES.inject({}) do |hash, (code, message)|
- hash[message.gsub(/ /, "").underscore.to_sym] = code
- hash
- end
-
- # Given a status parameter, determine whether it needs to be converted
- # to a string. If it is a fixnum, use the STATUS_CODES hash to lookup
- # the default message. If it is a symbol, use the SYMBOL_TO_STATUS_CODE
- # hash to convert it.
- def interpret_status(status)
- case status
- when Fixnum then
- "#{status} #{STATUS_CODES[status]}".strip
- when Symbol then
- interpret_status(SYMBOL_TO_STATUS_CODE[status] ||
- "500 Unknown Status #{status.inspect}")
- else
- status.to_s
- end
- end
- private :interpret_status
-
- end
-end \ No newline at end of file
diff --git a/actionpack/lib/action_controller/dispatch/uploaded_file.rb b/actionpack/lib/action_controller/dispatch/uploaded_file.rb
deleted file mode 100644
index 376ba3621a..0000000000
--- a/actionpack/lib/action_controller/dispatch/uploaded_file.rb
+++ /dev/null
@@ -1,44 +0,0 @@
-module ActionController
- module UploadedFile
- def self.included(base)
- base.class_eval do
- attr_accessor :original_path, :content_type
- alias_method :local_path, :path
- end
- end
-
- def self.extended(object)
- object.class_eval do
- attr_accessor :original_path, :content_type
- alias_method :local_path, :path
- end
- end
-
- # Take the basename of the upload's original filename.
- # This handles the full Windows paths given by Internet Explorer
- # (and perhaps other broken user agents) without affecting
- # those which give the lone filename.
- # The Windows regexp is adapted from Perl's File::Basename.
- def original_filename
- unless defined? @original_filename
- @original_filename =
- unless original_path.blank?
- if original_path =~ /^(?:.*[:\\\/])?(.*)/m
- $1
- else
- File.basename original_path
- end
- end
- end
- @original_filename
- end
- end
-
- class UploadedStringIO < StringIO
- include UploadedFile
- end
-
- class UploadedTempfile < Tempfile
- include UploadedFile
- end
-end
diff --git a/actionpack/lib/action_controller/dispatch/url_encoded_pair_parser.rb b/actionpack/lib/action_controller/dispatch/url_encoded_pair_parser.rb
deleted file mode 100644
index 57594c4259..0000000000
--- a/actionpack/lib/action_controller/dispatch/url_encoded_pair_parser.rb
+++ /dev/null
@@ -1,155 +0,0 @@
-module ActionController
- class UrlEncodedPairParser < StringScanner #:nodoc:
- class << self
- def parse_query_parameters(query_string)
- return {} if query_string.blank?
-
- pairs = query_string.split('&').collect do |chunk|
- next if chunk.empty?
- key, value = chunk.split('=', 2)
- next if key.empty?
- value = value.nil? ? nil : CGI.unescape(value)
- [ CGI.unescape(key), value ]
- end.compact
-
- new(pairs).result
- end
-
- def parse_hash_parameters(params)
- parser = new
-
- params = params.dup
- until params.empty?
- for key, value in params
- if key.blank?
- params.delete(key)
- elsif value.is_a?(Array)
- parser.parse(key, get_typed_value(value.shift))
- params.delete(key) if value.empty?
- else
- parser.parse(key, get_typed_value(value))
- params.delete(key)
- end
- end
- end
-
- parser.result
- end
-
- private
- def get_typed_value(value)
- case value
- when String
- value
- when NilClass
- ''
- when Array
- value.map { |v| get_typed_value(v) }
- when Hash
- if value.has_key?(:tempfile) && value[:filename].any?
- upload = value[:tempfile]
- upload.extend(UploadedFile)
- upload.original_path = value[:filename]
- upload.content_type = value[:type]
- upload
- else
- nil
- end
- else
- raise "Unknown form value: #{value.inspect}"
- end
- end
- end
-
- attr_reader :top, :parent, :result
-
- def initialize(pairs = [])
- super('')
- @result = {}
- pairs.each { |key, value| parse(key, value) }
- end
-
- KEY_REGEXP = %r{([^\[\]=&]+)}
- BRACKETED_KEY_REGEXP = %r{\[([^\[\]=&]+)\]}
-
- # Parse the query string
- def parse(key, value)
- self.string = key
- @top, @parent = result, nil
-
- # First scan the bare key
- key = scan(KEY_REGEXP) or return
- key = post_key_check(key)
-
- # Then scan as many nestings as present
- until eos?
- r = scan(BRACKETED_KEY_REGEXP) or return
- key = self[1]
- key = post_key_check(key)
- end
-
- bind(key, value)
- end
-
- private
- # After we see a key, we must look ahead to determine our next action. Cases:
- #
- # [] follows the key. Then the value must be an array.
- # = follows the key. (A value comes next)
- # & or the end of string follows the key. Then the key is a flag.
- # otherwise, a hash follows the key.
- def post_key_check(key)
- if scan(/\[\]/) # a[b][] indicates that b is an array
- container(key, Array)
- nil
- elsif check(/\[[^\]]/) # a[b] indicates that a is a hash
- container(key, Hash)
- nil
- else # End of key? We do nothing.
- key
- end
- end
-
- # Add a container to the stack.
- def container(key, klass)
- type_conflict! klass, top[key] if top.is_a?(Hash) && top.key?(key) && ! top[key].is_a?(klass)
- value = bind(key, klass.new)
- type_conflict! klass, value unless value.is_a?(klass)
- push(value)
- end
-
- # Push a value onto the 'stack', which is actually only the top 2 items.
- def push(value)
- @parent, @top = @top, value
- end
-
- # Bind a key (which may be nil for items in an array) to the provided value.
- def bind(key, value)
- if top.is_a? Array
- if key
- if top[-1].is_a?(Hash) && ! top[-1].key?(key)
- top[-1][key] = value
- else
- top << {key => value}.with_indifferent_access
- end
- push top.last
- return top[key]
- else
- top << value
- return value
- end
- elsif top.is_a? Hash
- key = CGI.unescape(key)
- parent << (@top = {}) if top.key?(key) && parent.is_a?(Array)
- top[key] ||= value
- return top[key]
- else
- raise ArgumentError, "Don't know what to do: top is #{top.inspect}"
- end
- end
-
- def type_conflict!(klass, value)
- 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}.)"
- end
- end
-end