mirror of
https://github.com/rails/rails.git
synced 2022-11-09 12:12:34 -05:00
Move HTTP libs and middleware into ActionDispatch component
This commit is contained in:
parent
a0f2b1d95d
commit
319ae4628f
44 changed files with 134 additions and 427 deletions
|
@ -31,17 +31,14 @@ rescue LoadError
|
|||
end
|
||||
end
|
||||
|
||||
gem 'rack', '>= 0.9.0'
|
||||
require 'rack'
|
||||
require 'action_controller/rack_ext'
|
||||
|
||||
require File.join(File.dirname(__FILE__), "action_pack")
|
||||
|
||||
module ActionController
|
||||
# TODO: Review explicit to see if they will automatically be handled by
|
||||
# the initilizer if they are really needed.
|
||||
def self.load_all!
|
||||
[Base, CGIHandler, CgiRequest, Request, Response, Http::Headers, UrlRewriter, UrlWriter]
|
||||
[Base, Request, Response, UrlRewriter, UrlWriter]
|
||||
[ActionDispatch::Http::Headers]
|
||||
end
|
||||
|
||||
autoload :Base, 'action_controller/base/base'
|
||||
|
@ -49,7 +46,6 @@ module ActionController
|
|||
autoload :Caching, 'action_controller/caching'
|
||||
autoload :Cookies, 'action_controller/base/cookies'
|
||||
autoload :Dispatcher, 'action_controller/dispatch/dispatcher'
|
||||
autoload :Failsafe, 'action_controller/dispatch/rack/failsafe'
|
||||
autoload :Filters, 'action_controller/base/chained/filters'
|
||||
autoload :Flash, 'action_controller/base/chained/flash'
|
||||
autoload :Helpers, 'action_controller/base/helpers'
|
||||
|
@ -57,32 +53,21 @@ module ActionController
|
|||
autoload :Integration, 'action_controller/testing/integration'
|
||||
autoload :IntegrationTest, 'action_controller/testing/integration'
|
||||
autoload :Layout, 'action_controller/base/layout'
|
||||
autoload :Lock, 'action_controller/dispatch/rack/lock'
|
||||
autoload :MiddlewareStack, 'action_controller/dispatch/rack/middleware_stack'
|
||||
autoload :MimeResponds, 'action_controller/mime/responds'
|
||||
autoload :ParamsParser, 'action_controller/dispatch/params_parser'
|
||||
autoload :PolymorphicRoutes, 'action_controller/routing/generation/polymorphic_routes'
|
||||
autoload :RecordIdentifier, 'action_controller/record_identifier'
|
||||
autoload :Redirector, 'action_controller/base/redirect'
|
||||
autoload :Renderer, 'action_controller/base/render'
|
||||
autoload :Request, 'action_controller/dispatch/request'
|
||||
autoload :RequestForgeryProtection, 'action_controller/base/request_forgery_protection'
|
||||
autoload :RequestParser, 'action_controller/dispatch/request_parser'
|
||||
autoload :Rescue, 'action_controller/dispatch/rescue'
|
||||
autoload :Resources, 'action_controller/routing/resources'
|
||||
autoload :Responder, 'action_controller/base/responder'
|
||||
autoload :Response, 'action_controller/dispatch/response'
|
||||
autoload :RewindableInput, 'action_controller/dispatch/rewindable_input'
|
||||
autoload :Routing, 'action_controller/routing'
|
||||
autoload :SessionManagement, 'action_controller/session/management'
|
||||
autoload :StatusCodes, 'action_controller/dispatch/status_codes'
|
||||
autoload :Streaming, 'action_controller/base/streaming'
|
||||
autoload :TestCase, 'action_controller/testing/test_case'
|
||||
autoload :TestProcess, 'action_controller/testing/process'
|
||||
autoload :Translation, 'action_controller/translation'
|
||||
autoload :UploadedFile, 'action_controller/dispatch/uploaded_file'
|
||||
autoload :UploadedStringIO, 'action_controller/dispatch/uploaded_file'
|
||||
autoload :UploadedTempfile, 'action_controller/dispatch/uploaded_file'
|
||||
autoload :UrlEncodedPairParser, 'action_controller/dispatch/url_encoded_pair_parser'
|
||||
autoload :UrlRewriter, 'action_controller/routing/generation/url_rewriter'
|
||||
autoload :UrlWriter, 'action_controller/routing/generation/url_rewriter'
|
||||
|
@ -96,20 +81,9 @@ module ActionController
|
|||
autoload :SelectorAssertions, 'action_controller/testing/assertions/selector'
|
||||
autoload :TagAssertions, 'action_controller/testing/assertions/tag'
|
||||
end
|
||||
|
||||
module Http
|
||||
autoload :Headers, 'action_controller/base/headers'
|
||||
end
|
||||
|
||||
module Session
|
||||
autoload :AbstractStore, 'action_controller/session/abstract_store'
|
||||
autoload :CookieStore, 'action_controller/session/cookie_store'
|
||||
autoload :MemCacheStore, 'action_controller/session/mem_cache_store'
|
||||
end
|
||||
end
|
||||
|
||||
autoload :Mime, 'action_controller/mime/type'
|
||||
|
||||
autoload :HTML, 'action_controller/vendor/html-scanner'
|
||||
|
||||
require 'action_dispatch'
|
||||
require 'action_view'
|
||||
|
|
|
@ -232,7 +232,7 @@ module ActionController #:nodoc:
|
|||
#
|
||||
class Base
|
||||
|
||||
include StatusCodes
|
||||
include ActionDispatch::StatusCodes
|
||||
|
||||
cattr_reader :protected_instance_variables
|
||||
# Controller specific instance variables which will not be accessible inside views.
|
||||
|
@ -367,8 +367,8 @@ module ActionController #:nodoc:
|
|||
class << self
|
||||
def call(env)
|
||||
# HACK: For global rescue to have access to the original request and response
|
||||
request = env["action_controller.rescue.request"] ||= Request.new(env)
|
||||
response = env["action_controller.rescue.response"] ||= Response.new
|
||||
request = env["action_controller.rescue.request"] ||= ActionDispatch::Request.new(env)
|
||||
response = env["action_controller.rescue.response"] ||= ActionDispatch::Response.new
|
||||
process(request, response)
|
||||
end
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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"
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
require 'action_controller/rack_ext/lock'
|
||||
require 'action_controller/rack_ext/multipart'
|
||||
require 'action_controller/rack_ext/parse_query'
|
|
@ -428,7 +428,7 @@ module ActionController
|
|||
end
|
||||
|
||||
def call(env)
|
||||
request = Request.new(env)
|
||||
request = ActionDispatch::Request.new(env)
|
||||
app = Routing::Routes.recognize(request)
|
||||
app.call(env).to_a
|
||||
end
|
||||
|
|
|
@ -26,7 +26,7 @@ module ActionController #:nodoc:
|
|||
if defined? @@session_store
|
||||
@@session_store
|
||||
else
|
||||
Session::CookieStore
|
||||
ActionDispatch::Session::CookieStore
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ module ActionController
|
|||
#
|
||||
# You can also pass an explicit status number like assert_response(501)
|
||||
# or its symbolic equivalent assert_response(:not_implemented).
|
||||
# See ActionController::StatusCodes for a full list.
|
||||
# See ActionDispatch::StatusCodes for a full list.
|
||||
#
|
||||
# ==== Examples
|
||||
#
|
||||
|
@ -27,7 +27,7 @@ module ActionController
|
|||
assert_block("") { true } # to count the assertion
|
||||
elsif type.is_a?(Fixnum) && @response.response_code == type
|
||||
assert_block("") { true } # to count the assertion
|
||||
elsif type.is_a?(Symbol) && @response.response_code == ActionController::StatusCodes::SYMBOL_TO_STATUS_CODE[type]
|
||||
elsif type.is_a?(Symbol) && @response.response_code == ActionDispatch::StatusCodes::SYMBOL_TO_STATUS_CODE[type]
|
||||
assert_block("") { true } # to count the assertion
|
||||
else
|
||||
if @response.error?
|
||||
|
|
|
@ -316,7 +316,7 @@ module ActionController
|
|||
@html_document = nil
|
||||
|
||||
@status = status.to_i
|
||||
@status_message = StatusCodes::STATUS_CODES[@status]
|
||||
@status_message = ActionDispatch::StatusCodes::STATUS_CODES[@status]
|
||||
|
||||
@headers = Rack::Utils::HeaderHash.new(headers)
|
||||
|
||||
|
@ -335,7 +335,7 @@ module ActionController
|
|||
else
|
||||
# Decorate responses from Rack Middleware and Rails Metal
|
||||
# as an Response for the purposes of integration testing
|
||||
@response = Response.new
|
||||
@response = ActionDispatch::Response.new
|
||||
@response.status = status.to_s
|
||||
@response.headers.replace(@headers)
|
||||
@response.body = @body
|
||||
|
@ -374,7 +374,7 @@ module ActionController
|
|||
"SERVER_PORT" => https? ? "443" : "80",
|
||||
"HTTPS" => https? ? "on" : "off"
|
||||
}
|
||||
UrlRewriter.new(Request.new(env), {})
|
||||
UrlRewriter.new(ActionDispatch::Request.new(env), {})
|
||||
end
|
||||
|
||||
def name_with_prefix(prefix, name)
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
module ActionController #:nodoc:
|
||||
class TestRequest < Request #:nodoc:
|
||||
class TestRequest < ActionDispatch::Request #:nodoc:
|
||||
attr_accessor :cookies, :session_options
|
||||
attr_accessor :query_parameters, :path, :session
|
||||
attr_accessor :host
|
||||
|
@ -270,7 +270,7 @@ module ActionController #:nodoc:
|
|||
# controller actions.
|
||||
#
|
||||
# See Response for more information on controller response objects.
|
||||
class TestResponse < Response
|
||||
class TestResponse < ActionDispatch::Response
|
||||
include TestResponseBehavior
|
||||
|
||||
def recycle!
|
||||
|
|
64
actionpack/lib/action_dispatch.rb
Normal file
64
actionpack/lib/action_dispatch.rb
Normal file
|
@ -0,0 +1,64 @@
|
|||
#--
|
||||
# Copyright (c) 2004-2009 David Heinemeier Hansson
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining
|
||||
# a copy of this software and associated documentation files (the
|
||||
# "Software"), to deal in the Software without restriction, including
|
||||
# without limitation the rights to use, copy, modify, merge, publish,
|
||||
# distribute, sublicense, and/or sell copies of the Software, and to
|
||||
# permit persons to whom the Software is furnished to do so, subject to
|
||||
# the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be
|
||||
# included in all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
#++
|
||||
|
||||
begin
|
||||
require 'active_support'
|
||||
rescue LoadError
|
||||
activesupport_path = "#{File.dirname(__FILE__)}/../../activesupport/lib"
|
||||
if File.directory?(activesupport_path)
|
||||
$:.unshift activesupport_path
|
||||
require 'active_support'
|
||||
end
|
||||
end
|
||||
|
||||
gem 'rack', '>= 0.9.0'
|
||||
require 'rack'
|
||||
require 'action_dispatch/rack'
|
||||
|
||||
module ActionDispatch
|
||||
autoload :Request, 'action_dispatch/http/request'
|
||||
autoload :Response, 'action_dispatch/http/response'
|
||||
autoload :StatusCodes, 'action_dispatch/http/status_codes'
|
||||
|
||||
autoload :Failsafe, 'action_dispatch/middleware/failsafe'
|
||||
autoload :ParamsParser, 'action_dispatch/middleware/params_parser'
|
||||
autoload :RewindableInput, 'action_dispatch/middleware/rewindable_input'
|
||||
|
||||
autoload :MiddlewareStack, 'action_dispatch/utils/middleware_stack'
|
||||
autoload :UploadedFile, 'action_dispatch/utils/uploaded_file'
|
||||
autoload :UploadedStringIO, 'action_dispatch/utils/uploaded_file'
|
||||
autoload :UploadedTempfile, 'action_dispatch/utils/uploaded_file'
|
||||
autoload :UrlEncodedPairParser, 'action_dispatch/utils/url_encoded_pair_parser'
|
||||
|
||||
module Http
|
||||
autoload :Headers, 'action_dispatch/http/headers'
|
||||
end
|
||||
|
||||
module Session
|
||||
autoload :AbstractStore, 'action_dispatch/middleware/session/abstract_store'
|
||||
autoload :CookieStore, 'action_dispatch/middleware/session/cookie_store'
|
||||
autoload :MemCacheStore, 'action_dispatch/middleware/session/mem_cache_store'
|
||||
end
|
||||
end
|
||||
|
||||
autoload :Mime, 'action_dispatch/http/mime_type'
|
|
@ -1,6 +1,6 @@
|
|||
require 'active_support/memoizable'
|
||||
|
||||
module ActionController
|
||||
module ActionDispatch
|
||||
module Http
|
||||
class Headers < ::Hash
|
||||
extend ActiveSupport::Memoizable
|
|
@ -211,4 +211,4 @@ module Mime
|
|||
end
|
||||
end
|
||||
|
||||
require 'action_controller/mime/default_types'
|
||||
require 'action_dispatch/http/mime_types'
|
|
@ -5,7 +5,7 @@ require 'strscan'
|
|||
require 'active_support/memoizable'
|
||||
require 'action_controller/cgi_ext'
|
||||
|
||||
module ActionController
|
||||
module ActionDispatch
|
||||
class Request < Rack::Request
|
||||
extend ActiveSupport::Memoizable
|
||||
|
||||
|
@ -33,7 +33,7 @@ module ActionController
|
|||
# <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}")
|
||||
HTTP_METHOD_LOOKUP[super] || raise(ActionController::UnknownHttpMethod, "#{super}, accepted HTTP methods are #{HTTP_METHODS.to_sentence}")
|
||||
end
|
||||
memoize :request_method
|
||||
|
||||
|
@ -75,7 +75,7 @@ module ActionController
|
|||
#
|
||||
# request.headers["Content-Type"] # => "text/plain"
|
||||
def headers
|
||||
ActionController::Http::Headers.new(@env)
|
||||
Http::Headers.new(@env)
|
||||
end
|
||||
memoize :headers
|
||||
|
||||
|
@ -162,7 +162,7 @@ module ActionController
|
|||
@format ||=
|
||||
if parameters[:format]
|
||||
Mime[parameters[:format]]
|
||||
elsif Base.use_accept_header && !(accepts == ONLY_ALL)
|
||||
elsif ActionController::Base.use_accept_header && !(accepts == ONLY_ALL)
|
||||
accepts.first
|
||||
elsif xhr? then Mime::JS
|
||||
else Mime::HTML
|
||||
|
@ -171,7 +171,7 @@ module ActionController
|
|||
|
||||
def formats
|
||||
@formats =
|
||||
if Base.use_accept_header
|
||||
if ActionController::Base.use_accept_header
|
||||
ret = Array(Mime[parameters[:format]] || accepts)
|
||||
else
|
||||
[format]
|
||||
|
@ -243,7 +243,7 @@ module ActionController
|
|||
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)
|
||||
raise ActionController::ActionControllerError.new(<<EOM)
|
||||
IP spoofing attack?!
|
||||
HTTP_CLIENT_IP=#{@env['HTTP_CLIENT_IP'].inspect}
|
||||
HTTP_X_FORWARDED_FOR=#{@env['HTTP_X_FORWARDED_FOR'].inspect}
|
|
@ -1,6 +1,6 @@
|
|||
require 'digest/md5'
|
||||
|
||||
module ActionController # :nodoc:
|
||||
module ActionDispatch # :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
|
|
@ -1,4 +1,4 @@
|
|||
module ActionController
|
||||
module ActionDispatch
|
||||
module StatusCodes #:nodoc:
|
||||
# Defines the standard HTTP status codes, by integer, with their
|
||||
# corresponding default message texts.
|
|
@ -1,4 +1,4 @@
|
|||
module ActionController
|
||||
module ActionDispatch
|
||||
class Failsafe
|
||||
cattr_accessor :error_file_path
|
||||
self.error_file_path = Rails.public_path if defined?(Rails.public_path)
|
|
@ -1,4 +1,4 @@
|
|||
module ActionController
|
||||
module ActionDispatch
|
||||
class ParamsParser
|
||||
ActionController::Base.param_parsers[Mime::XML] = :xml_simple
|
||||
ActionController::Base.param_parsers[Mime::JSON] = :json
|
|
@ -1,4 +1,4 @@
|
|||
module ActionController
|
||||
module ActionDispatch
|
||||
class RewindableInput
|
||||
class RewindableIO < ActiveSupport::BasicObject
|
||||
def initialize(io)
|
|
@ -1,6 +1,6 @@
|
|||
require 'rack/utils'
|
||||
|
||||
module ActionController
|
||||
module ActionDispatch
|
||||
module Session
|
||||
class AbstractStore
|
||||
ENV_SESSION_KEY = 'rack.session'.freeze
|
|
@ -1,4 +1,4 @@
|
|||
module ActionController
|
||||
module ActionDispatch
|
||||
module Session
|
||||
# This cookie-based session store is the Rails default. Sessions typically
|
||||
# contain at most a user_id and flash message; both fit within the 4K cookie
|
|
@ -1,7 +1,7 @@
|
|||
begin
|
||||
require_library_or_gem 'memcache'
|
||||
|
||||
module ActionController
|
||||
module ActionDispatch
|
||||
module Session
|
||||
class MemCacheStore < AbstractStore
|
||||
def initialize(app, options = {})
|
3
actionpack/lib/action_dispatch/rack.rb
Normal file
3
actionpack/lib/action_dispatch/rack.rb
Normal file
|
@ -0,0 +1,3 @@
|
|||
require 'action_dispatch/rack/lock'
|
||||
require 'action_dispatch/rack/multipart'
|
||||
require 'action_dispatch/rack/parse_query'
|
|
@ -1,4 +1,4 @@
|
|||
module ActionController
|
||||
module ActionDispatch
|
||||
class MiddlewareStack < Array
|
||||
class Middleware
|
||||
def self.new(klass, *args, &block)
|
|
@ -1,4 +1,4 @@
|
|||
module ActionController
|
||||
module ActionDispatch
|
||||
module UploadedFile
|
||||
def self.included(base)
|
||||
base.class_eval do
|
|
@ -1,4 +1,4 @@
|
|||
module ActionController
|
||||
module ActionDispatch
|
||||
class UrlEncodedPairParser < StringScanner #:nodoc:
|
||||
class << self
|
||||
def parse_query_parameters(query_string)
|
|
@ -46,7 +46,7 @@ class DispatcherTest < Test::Unit::TestCase
|
|||
|
||||
def test_failsafe_response
|
||||
Dispatcher.any_instance.expects(:dispatch).raises('b00m')
|
||||
ActionController::Failsafe.any_instance.expects(:log_failsafe_exception)
|
||||
ActionDispatch::Failsafe.any_instance.expects(:log_failsafe_exception)
|
||||
|
||||
assert_nothing_raised do
|
||||
assert_equal [
|
||||
|
|
|
@ -2,7 +2,7 @@ require 'abstract_unit'
|
|||
|
||||
class HeaderTest < Test::Unit::TestCase
|
||||
def setup
|
||||
@headers = ActionController::Http::Headers.new("HTTP_CONTENT_TYPE"=>"text/plain")
|
||||
@headers = ActionDispatch::Http::Headers.new("HTTP_CONTENT_TYPE"=>"text/plain")
|
||||
end
|
||||
|
||||
def test_content_type_works
|
||||
|
|
|
@ -6,7 +6,7 @@ class MiddlewareStackTest < ActiveSupport::TestCase
|
|||
class BazMiddleware; end
|
||||
|
||||
def setup
|
||||
@stack = ActionController::MiddlewareStack.new
|
||||
@stack = ActionDispatch::MiddlewareStack.new
|
||||
@stack.use FooMiddleware
|
||||
@stack.use BarMiddleware
|
||||
end
|
||||
|
|
|
@ -43,10 +43,10 @@ class BaseRackTest < Test::Unit::TestCase
|
|||
"REDIRECT_STATUS" => "200",
|
||||
"REQUEST_METHOD" => "GET"
|
||||
}
|
||||
@request = ActionController::Request.new(@env)
|
||||
@request = ActionDispatch::Request.new(@env)
|
||||
# some Nokia phone browsers omit the space after the semicolon separator.
|
||||
# some developers have grown accustomed to using comma in cookie values.
|
||||
@alt_cookie_fmt_request = ActionController::Request.new(@env.merge({"HTTP_COOKIE"=>"_session_id=c84ace847,96670c052c6ceb2451fb0f2;is_admin=yes"}))
|
||||
@alt_cookie_fmt_request = ActionDispatch::Request.new(@env.merge({"HTTP_COOKIE"=>"_session_id=c84ace847,96670c052c6ceb2451fb0f2;is_admin=yes"}))
|
||||
end
|
||||
|
||||
def default_test; end
|
||||
|
@ -195,7 +195,7 @@ class RackRequestNeedsRewoundTest < BaseRackTest
|
|||
@env['CONTENT_TYPE'] = 'application/x-www-form-urlencoded; charset=utf-8'
|
||||
|
||||
# Read the request body by parsing params.
|
||||
request = ActionController::Request.new(@env)
|
||||
request = ActionDispatch::Request.new(@env)
|
||||
request.request_parameters
|
||||
|
||||
# Should have rewound the body.
|
||||
|
@ -206,7 +206,7 @@ end
|
|||
class RackResponseTest < BaseRackTest
|
||||
def setup
|
||||
super
|
||||
@response = ActionController::Response.new
|
||||
@response = ActionDispatch::Response.new
|
||||
end
|
||||
|
||||
def test_simple_output
|
||||
|
@ -252,7 +252,7 @@ end
|
|||
class RackResponseHeadersTest < BaseRackTest
|
||||
def setup
|
||||
super
|
||||
@response = ActionController::Response.new
|
||||
@response = ActionDispatch::Response.new
|
||||
@response.status = "200 OK"
|
||||
end
|
||||
|
||||
|
|
|
@ -1223,7 +1223,7 @@ class RenderTest < ActionController::TestCase
|
|||
assert !@response.headers.include?('Content-Length')
|
||||
assert_response :no_content
|
||||
|
||||
ActionController::StatusCodes::SYMBOL_TO_STATUS_CODE.each do |status, code|
|
||||
ActionDispatch::StatusCodes::SYMBOL_TO_STATUS_CODE.each do |status, code|
|
||||
get :head_with_symbolic_status, :status => status.to_s
|
||||
assert_equal code, @response.response_code
|
||||
assert_response status
|
||||
|
@ -1231,7 +1231,7 @@ class RenderTest < ActionController::TestCase
|
|||
end
|
||||
|
||||
def test_head_with_integer_status
|
||||
ActionController::StatusCodes::STATUS_CODES.each do |code, message|
|
||||
ActionDispatch::StatusCodes::STATUS_CODES.each do |code, message|
|
||||
get :head_with_integer_status, :status => code.to_s
|
||||
assert_equal message, @response.message
|
||||
end
|
||||
|
|
|
@ -215,7 +215,7 @@ class MultipartParamsParsingTest < ActionController::IntegrationTest
|
|||
def with_muck_middleware
|
||||
original_middleware = ActionController::Dispatcher.middleware
|
||||
middleware = original_middleware.dup
|
||||
middleware.insert_after ActionController::RewindableInput, MuckMiddleware
|
||||
middleware.insert_after ActionDispatch::RewindableInput, MuckMiddleware
|
||||
ActionController::Dispatcher.middleware = middleware
|
||||
yield
|
||||
ActionController::Dispatcher.middleware = original_middleware
|
||||
|
|
|
@ -195,7 +195,7 @@ class UrlEncodedParamsParsingTest < ActionController::IntegrationTest
|
|||
def with_muck_middleware
|
||||
original_middleware = ActionController::Dispatcher.middleware
|
||||
middleware = original_middleware.dup
|
||||
middleware.insert_after ActionController::RewindableInput, MuckMiddleware
|
||||
middleware.insert_after ActionDispatch::RewindableInput, MuckMiddleware
|
||||
ActionController::Dispatcher.middleware = middleware
|
||||
yield
|
||||
ActionController::Dispatcher.middleware = original_middleware
|
||||
|
|
|
@ -393,7 +393,7 @@ class RescueControllerTest < ActionController::TestCase
|
|||
def test_rescue_dispatcher_exceptions_without_request_set
|
||||
@request.env['REQUEST_URI'] = '/no_way'
|
||||
response = RescueController.call_with_exception(@request.env, ActionController::RoutingError.new("Route not found"))
|
||||
assert_kind_of ActionController::Response, response
|
||||
assert_kind_of ActionDispatch::Response, response
|
||||
assert_equal "no way", response.body
|
||||
end
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ class CookieStoreTest < ActionController::IntegrationTest
|
|||
SessionSecret = 'b3c631c314c0bbca50c1b2843150fe33'
|
||||
|
||||
DispatcherApp = ActionController::Dispatcher.new
|
||||
CookieStoreApp = ActionController::Session::CookieStore.new(DispatcherApp,
|
||||
CookieStoreApp = ActionDispatch::Session::CookieStore.new(DispatcherApp,
|
||||
:key => SessionKey, :secret => SessionSecret)
|
||||
|
||||
Verifier = ActiveSupport::MessageVerifier.new(SessionSecret, 'SHA1')
|
||||
|
@ -51,41 +51,41 @@ class CookieStoreTest < ActionController::IntegrationTest
|
|||
|
||||
def test_raises_argument_error_if_missing_session_key
|
||||
assert_raise(ArgumentError, nil.inspect) {
|
||||
ActionController::Session::CookieStore.new(nil,
|
||||
ActionDispatch::Session::CookieStore.new(nil,
|
||||
:key => nil, :secret => SessionSecret)
|
||||
}
|
||||
|
||||
assert_raise(ArgumentError, ''.inspect) {
|
||||
ActionController::Session::CookieStore.new(nil,
|
||||
ActionDispatch::Session::CookieStore.new(nil,
|
||||
:key => '', :secret => SessionSecret)
|
||||
}
|
||||
end
|
||||
|
||||
def test_raises_argument_error_if_missing_secret
|
||||
assert_raise(ArgumentError, nil.inspect) {
|
||||
ActionController::Session::CookieStore.new(nil,
|
||||
ActionDispatch::Session::CookieStore.new(nil,
|
||||
:key => SessionKey, :secret => nil)
|
||||
}
|
||||
|
||||
assert_raise(ArgumentError, ''.inspect) {
|
||||
ActionController::Session::CookieStore.new(nil,
|
||||
ActionDispatch::Session::CookieStore.new(nil,
|
||||
:key => SessionKey, :secret => '')
|
||||
}
|
||||
end
|
||||
|
||||
def test_raises_argument_error_if_secret_is_probably_insecure
|
||||
assert_raise(ArgumentError, "password".inspect) {
|
||||
ActionController::Session::CookieStore.new(nil,
|
||||
ActionDispatch::Session::CookieStore.new(nil,
|
||||
:key => SessionKey, :secret => "password")
|
||||
}
|
||||
|
||||
assert_raise(ArgumentError, "secret".inspect) {
|
||||
ActionController::Session::CookieStore.new(nil,
|
||||
ActionDispatch::Session::CookieStore.new(nil,
|
||||
:key => SessionKey, :secret => "secret")
|
||||
}
|
||||
|
||||
assert_raise(ArgumentError, "12345678901234567890123456789".inspect) {
|
||||
ActionController::Session::CookieStore.new(nil,
|
||||
ActionDispatch::Session::CookieStore.new(nil,
|
||||
:key => SessionKey, :secret => "12345678901234567890123456789")
|
||||
}
|
||||
end
|
||||
|
@ -119,7 +119,7 @@ class CookieStoreTest < ActionController::IntegrationTest
|
|||
|
||||
def test_close_raises_when_data_overflows
|
||||
with_test_route_set do
|
||||
assert_raise(ActionController::Session::CookieStore::CookieOverflow) {
|
||||
assert_raise(ActionDispatch::Session::CookieStore::CookieOverflow) {
|
||||
get '/raise_data_overflow'
|
||||
}
|
||||
end
|
||||
|
|
|
@ -26,7 +26,7 @@ class MemCacheStoreTest < ActionController::IntegrationTest
|
|||
|
||||
begin
|
||||
DispatcherApp = ActionController::Dispatcher.new
|
||||
MemCacheStoreApp = ActionController::Session::MemCacheStore.new(
|
||||
MemCacheStoreApp = ActionDispatch::Session::MemCacheStore.new(
|
||||
DispatcherApp, :key => '_session_id')
|
||||
|
||||
|
||||
|
|
|
@ -40,7 +40,7 @@ module ActiveRecord
|
|||
#
|
||||
# The example SqlBypass class is a generic SQL session store. You may
|
||||
# use it as a basis for high-performance database-specific stores.
|
||||
class SessionStore < ActionController::Session::AbstractStore
|
||||
class SessionStore < ActionDispatch::Session::AbstractStore
|
||||
# The default Active Record class.
|
||||
class Session < ActiveRecord::Base
|
||||
##
|
||||
|
|
Loading…
Reference in a new issue