aboutsummaryrefslogtreecommitdiffstats
path: root/actionpack/lib/action_dispatch/vendor
diff options
context:
space:
mode:
Diffstat (limited to 'actionpack/lib/action_dispatch/vendor')
-rw-r--r--actionpack/lib/action_dispatch/vendor/rack-1.0/rack/reloader.rb64
-rw-r--r--actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack.rb (renamed from actionpack/lib/action_dispatch/vendor/rack-1.0/rack.rb)7
-rw-r--r--actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/adapter/camping.rb (renamed from actionpack/lib/action_dispatch/vendor/rack-1.0/rack/adapter/camping.rb)0
-rw-r--r--actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/auth/abstract/handler.rb (renamed from actionpack/lib/action_dispatch/vendor/rack-1.0/rack/auth/abstract/handler.rb)0
-rw-r--r--actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/auth/abstract/request.rb (renamed from actionpack/lib/action_dispatch/vendor/rack-1.0/rack/auth/abstract/request.rb)0
-rw-r--r--actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/auth/basic.rb (renamed from actionpack/lib/action_dispatch/vendor/rack-1.0/rack/auth/basic.rb)0
-rw-r--r--actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/auth/digest/md5.rb (renamed from actionpack/lib/action_dispatch/vendor/rack-1.0/rack/auth/digest/md5.rb)0
-rw-r--r--actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/auth/digest/nonce.rb (renamed from actionpack/lib/action_dispatch/vendor/rack-1.0/rack/auth/digest/nonce.rb)0
-rw-r--r--actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/auth/digest/params.rb (renamed from actionpack/lib/action_dispatch/vendor/rack-1.0/rack/auth/digest/params.rb)0
-rw-r--r--actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/auth/digest/request.rb (renamed from actionpack/lib/action_dispatch/vendor/rack-1.0/rack/auth/digest/request.rb)0
-rw-r--r--actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/auth/openid.rb (renamed from actionpack/lib/action_dispatch/vendor/rack-1.0/rack/auth/openid.rb)0
-rw-r--r--actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/builder.rb (renamed from actionpack/lib/action_dispatch/vendor/rack-1.0/rack/builder.rb)0
-rw-r--r--actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/cascade.rb (renamed from actionpack/lib/action_dispatch/vendor/rack-1.0/rack/cascade.rb)0
-rw-r--r--actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/chunked.rb (renamed from actionpack/lib/action_dispatch/vendor/rack-1.0/rack/chunked.rb)0
-rw-r--r--actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/commonlogger.rb (renamed from actionpack/lib/action_dispatch/vendor/rack-1.0/rack/commonlogger.rb)0
-rw-r--r--actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/conditionalget.rb (renamed from actionpack/lib/action_dispatch/vendor/rack-1.0/rack/conditionalget.rb)2
-rw-r--r--actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/content_length.rb (renamed from actionpack/lib/action_dispatch/vendor/rack-1.0/rack/content_length.rb)0
-rw-r--r--actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/content_type.rb (renamed from actionpack/lib/action_dispatch/vendor/rack-1.0/rack/content_type.rb)0
-rw-r--r--actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/deflater.rb (renamed from actionpack/lib/action_dispatch/vendor/rack-1.0/rack/deflater.rb)71
-rw-r--r--actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/directory.rb (renamed from actionpack/lib/action_dispatch/vendor/rack-1.0/rack/directory.rb)0
-rw-r--r--actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/file.rb (renamed from actionpack/lib/action_dispatch/vendor/rack-1.0/rack/file.rb)0
-rw-r--r--actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/handler.rb (renamed from actionpack/lib/action_dispatch/vendor/rack-1.0/rack/handler.rb)23
-rw-r--r--actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/handler/cgi.rb (renamed from actionpack/lib/action_dispatch/vendor/rack-1.0/rack/handler/cgi.rb)2
-rw-r--r--actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/handler/evented_mongrel.rb (renamed from actionpack/lib/action_dispatch/vendor/rack-1.0/rack/handler/evented_mongrel.rb)0
-rw-r--r--actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/handler/fastcgi.rb (renamed from actionpack/lib/action_dispatch/vendor/rack-1.0/rack/handler/fastcgi.rb)47
-rw-r--r--actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/handler/lsws.rb (renamed from actionpack/lib/action_dispatch/vendor/rack-1.0/rack/handler/lsws.rb)2
-rw-r--r--actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/handler/mongrel.rb (renamed from actionpack/lib/action_dispatch/vendor/rack-1.0/rack/handler/mongrel.rb)2
-rw-r--r--actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/handler/scgi.rb (renamed from actionpack/lib/action_dispatch/vendor/rack-1.0/rack/handler/scgi.rb)2
-rw-r--r--actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/handler/swiftiplied_mongrel.rb (renamed from actionpack/lib/action_dispatch/vendor/rack-1.0/rack/handler/swiftiplied_mongrel.rb)0
-rw-r--r--actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/handler/thin.rb (renamed from actionpack/lib/action_dispatch/vendor/rack-1.0/rack/handler/thin.rb)0
-rw-r--r--actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/handler/webrick.rb (renamed from actionpack/lib/action_dispatch/vendor/rack-1.0/rack/handler/webrick.rb)2
-rw-r--r--actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/head.rb (renamed from actionpack/lib/action_dispatch/vendor/rack-1.0/rack/head.rb)0
-rw-r--r--actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/lint.rb (renamed from actionpack/lib/action_dispatch/vendor/rack-1.0/rack/lint.rb)127
-rw-r--r--actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/lobster.rb (renamed from actionpack/lib/action_dispatch/vendor/rack-1.0/rack/lobster.rb)0
-rw-r--r--actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/lock.rb (renamed from actionpack/lib/action_dispatch/vendor/rack-1.0/rack/lock.rb)0
-rw-r--r--actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/methodoverride.rb (renamed from actionpack/lib/action_dispatch/vendor/rack-1.0/rack/methodoverride.rb)0
-rw-r--r--actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/mime.rb (renamed from actionpack/lib/action_dispatch/vendor/rack-1.0/rack/mime.rb)0
-rw-r--r--actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/mock.rb (renamed from actionpack/lib/action_dispatch/vendor/rack-1.0/rack/mock.rb)30
-rw-r--r--actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/recursive.rb (renamed from actionpack/lib/action_dispatch/vendor/rack-1.0/rack/recursive.rb)0
-rw-r--r--actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/reloader.rb106
-rw-r--r--actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/request.rb (renamed from actionpack/lib/action_dispatch/vendor/rack-1.0/rack/request.rb)39
-rw-r--r--actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/response.rb (renamed from actionpack/lib/action_dispatch/vendor/rack-1.0/rack/response.rb)6
-rw-r--r--actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/rewindable_input.rb98
-rw-r--r--actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/session/abstract/id.rb (renamed from actionpack/lib/action_dispatch/vendor/rack-1.0/rack/session/abstract/id.rb)0
-rw-r--r--actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/session/cookie.rb (renamed from actionpack/lib/action_dispatch/vendor/rack-1.0/rack/session/cookie.rb)0
-rw-r--r--actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/session/memcache.rb (renamed from actionpack/lib/action_dispatch/vendor/rack-1.0/rack/session/memcache.rb)0
-rw-r--r--actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/session/pool.rb (renamed from actionpack/lib/action_dispatch/vendor/rack-1.0/rack/session/pool.rb)0
-rw-r--r--actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/showexceptions.rb (renamed from actionpack/lib/action_dispatch/vendor/rack-1.0/rack/showexceptions.rb)0
-rw-r--r--actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/showstatus.rb (renamed from actionpack/lib/action_dispatch/vendor/rack-1.0/rack/showstatus.rb)0
-rw-r--r--actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/static.rb (renamed from actionpack/lib/action_dispatch/vendor/rack-1.0/rack/static.rb)0
-rw-r--r--actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/urlmap.rb (renamed from actionpack/lib/action_dispatch/vendor/rack-1.0/rack/urlmap.rb)2
-rw-r--r--actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/utils.rb (renamed from actionpack/lib/action_dispatch/vendor/rack-1.0/rack/utils.rb)158
-rw-r--r--actionpack/lib/action_dispatch/vendor/rack-test/rack/mock_session.rb50
-rw-r--r--actionpack/lib/action_dispatch/vendor/rack-test/rack/test.rb239
-rw-r--r--actionpack/lib/action_dispatch/vendor/rack-test/rack/test/cookie_jar.rb169
-rw-r--r--actionpack/lib/action_dispatch/vendor/rack-test/rack/test/methods.rb45
-rw-r--r--actionpack/lib/action_dispatch/vendor/rack-test/rack/test/mock_digest_request.rb27
-rw-r--r--actionpack/lib/action_dispatch/vendor/rack-test/rack/test/uploaded_file.rb36
-rw-r--r--actionpack/lib/action_dispatch/vendor/rack-test/rack/test/utils.rb75
59 files changed, 1243 insertions, 188 deletions
diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/reloader.rb b/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/reloader.rb
deleted file mode 100644
index b17d8c0926..0000000000
--- a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/reloader.rb
+++ /dev/null
@@ -1,64 +0,0 @@
-require 'thread'
-
-module Rack
- # Rack::Reloader checks on every request, but at most every +secs+
- # seconds, if a file loaded changed, and reloads it, logging to
- # rack.errors.
- #
- # It is recommended you use ShowExceptions to catch SyntaxErrors etc.
-
- class Reloader
- def initialize(app, secs=10)
- @app = app
- @secs = secs # reload every @secs seconds max
- @last = Time.now
- end
-
- def call(env)
- if Time.now > @last + @secs
- Thread.exclusive {
- reload!(env['rack.errors'])
- @last = Time.now
- }
- end
-
- @app.call(env)
- end
-
- def reload!(stderr=$stderr)
- need_reload = $LOADED_FEATURES.find_all { |loaded|
- begin
- if loaded =~ /\A[.\/]/ # absolute filename or 1.9
- abs = loaded
- else
- abs = $LOAD_PATH.map { |path| ::File.join(path, loaded) }.
- find { |file| ::File.exist? file }
- end
-
- if abs
- ::File.mtime(abs) > @last - @secs rescue false
- else
- false
- end
- end
- }
-
- need_reload.each { |l|
- $LOADED_FEATURES.delete l
- }
-
- need_reload.each { |to_load|
- begin
- if require to_load
- stderr.puts "#{self.class}: reloaded `#{to_load}'"
- end
- rescue LoadError, SyntaxError => e
- raise e # Possibly ShowExceptions
- end
- }
-
- stderr.flush
- need_reload
- end
- end
-end
diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack.rb
index 6349b95094..371d015690 100644
--- a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack.rb
+++ b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack.rb
@@ -3,7 +3,8 @@
# Rack is freely distributable under the terms of an MIT-style license.
# See COPYING or http://www.opensource.org/licenses/mit-license.php.
-$:.unshift(File.expand_path(File.dirname(__FILE__)))
+path = File.expand_path(File.dirname(__FILE__))
+$:.unshift(path) unless $:.include?(path)
# The Rack main module, serving as a namespace for all core Rack
@@ -14,7 +15,7 @@ $:.unshift(File.expand_path(File.dirname(__FILE__)))
module Rack
# The Rack protocol version number implemented.
- VERSION = [0,1]
+ VERSION = [1,0]
# Return the Rack protocol version as a dotted string.
def self.version
@@ -23,7 +24,7 @@ module Rack
# Return the Rack release as a dotted string.
def self.release
- "1.0 bundled"
+ "1.0"
end
autoload :Builder, "rack/builder"
diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/adapter/camping.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/adapter/camping.rb
index 63bc787f54..63bc787f54 100644
--- a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/adapter/camping.rb
+++ b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/adapter/camping.rb
diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/auth/abstract/handler.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/auth/abstract/handler.rb
index 214df6299e..214df6299e 100644
--- a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/auth/abstract/handler.rb
+++ b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/auth/abstract/handler.rb
diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/auth/abstract/request.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/auth/abstract/request.rb
index 1d9ccec685..1d9ccec685 100644
--- a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/auth/abstract/request.rb
+++ b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/auth/abstract/request.rb
diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/auth/basic.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/auth/basic.rb
index 9557224648..9557224648 100644
--- a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/auth/basic.rb
+++ b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/auth/basic.rb
diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/auth/digest/md5.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/auth/digest/md5.rb
index e579dc9632..e579dc9632 100644
--- a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/auth/digest/md5.rb
+++ b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/auth/digest/md5.rb
diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/auth/digest/nonce.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/auth/digest/nonce.rb
index dbe109f29a..dbe109f29a 100644
--- a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/auth/digest/nonce.rb
+++ b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/auth/digest/nonce.rb
diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/auth/digest/params.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/auth/digest/params.rb
index 730e2efdc8..730e2efdc8 100644
--- a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/auth/digest/params.rb
+++ b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/auth/digest/params.rb
diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/auth/digest/request.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/auth/digest/request.rb
index a8aa3bf996..a8aa3bf996 100644
--- a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/auth/digest/request.rb
+++ b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/auth/digest/request.rb
diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/auth/openid.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/auth/openid.rb
index c5f6a5143e..c5f6a5143e 100644
--- a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/auth/openid.rb
+++ b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/auth/openid.rb
diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/builder.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/builder.rb
index 295235e56a..295235e56a 100644
--- a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/builder.rb
+++ b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/builder.rb
diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/cascade.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/cascade.rb
index a038aa1105..a038aa1105 100644
--- a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/cascade.rb
+++ b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/cascade.rb
diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/chunked.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/chunked.rb
index 280d89dd65..280d89dd65 100644
--- a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/chunked.rb
+++ b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/chunked.rb
diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/commonlogger.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/commonlogger.rb
index 5e68ac626d..5e68ac626d 100644
--- a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/commonlogger.rb
+++ b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/commonlogger.rb
diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/conditionalget.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/conditionalget.rb
index 7bec824181..046ebdb00a 100644
--- a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/conditionalget.rb
+++ b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/conditionalget.rb
@@ -26,6 +26,8 @@ module Rack
headers = Utils::HeaderHash.new(headers)
if etag_matches?(env, headers) || modified_since?(env, headers)
status = 304
+ headers.delete('Content-Type')
+ headers.delete('Content-Length')
body = []
end
[status, headers, body]
diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/content_length.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/content_length.rb
index 1e56d43853..1e56d43853 100644
--- a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/content_length.rb
+++ b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/content_length.rb
diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/content_type.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/content_type.rb
index 0c1e1ca3e1..0c1e1ca3e1 100644
--- a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/content_type.rb
+++ b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/content_type.rb
diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/deflater.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/deflater.rb
index a42b7477ae..14137a944d 100644
--- a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/deflater.rb
+++ b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/deflater.rb
@@ -33,17 +33,15 @@ module Rack
case encoding
when "gzip"
+ headers['Content-Encoding'] = "gzip"
+ headers.delete('Content-Length')
mtime = headers.key?("Last-Modified") ?
Time.httpdate(headers["Last-Modified"]) : Time.now
- body = self.class.gzip(body, mtime)
- size = Rack::Utils.bytesize(body)
- headers = headers.merge("Content-Encoding" => "gzip", "Content-Length" => size.to_s)
- [status, headers, [body]]
+ [status, headers, GzipStream.new(body, mtime)]
when "deflate"
- body = self.class.deflate(body)
- size = Rack::Utils.bytesize(body)
- headers = headers.merge("Content-Encoding" => "deflate", "Content-Length" => size.to_s)
- [status, headers, [body]]
+ headers['Content-Encoding'] = "deflate"
+ headers.delete('Content-Length')
+ [status, headers, DeflateStream.new(body)]
when "identity"
[status, headers, body]
when nil
@@ -52,34 +50,47 @@ module Rack
end
end
- def self.gzip(body, mtime)
- io = StringIO.new
- gzip = Zlib::GzipWriter.new(io)
- gzip.mtime = mtime
+ class GzipStream
+ def initialize(body, mtime)
+ @body = body
+ @mtime = mtime
+ end
- # TODO: Add streaming
- body.each { |part| gzip << part }
+ def each(&block)
+ @writer = block
+ gzip =::Zlib::GzipWriter.new(self)
+ gzip.mtime = @mtime
+ @body.each { |part| gzip << part }
+ @body.close if @body.respond_to?(:close)
+ gzip.close
+ @writer = nil
+ end
- gzip.close
- return io.string
+ def write(data)
+ @writer.call(data)
+ end
end
- DEFLATE_ARGS = [
- Zlib::DEFAULT_COMPRESSION,
- # drop the zlib header which causes both Safari and IE to choke
- -Zlib::MAX_WBITS,
- Zlib::DEF_MEM_LEVEL,
- Zlib::DEFAULT_STRATEGY
- ]
+ class DeflateStream
+ DEFLATE_ARGS = [
+ Zlib::DEFAULT_COMPRESSION,
+ # drop the zlib header which causes both Safari and IE to choke
+ -Zlib::MAX_WBITS,
+ Zlib::DEF_MEM_LEVEL,
+ Zlib::DEFAULT_STRATEGY
+ ]
- # Loosely based on Mongrel's Deflate handler
- def self.deflate(body)
- deflater = Zlib::Deflate.new(*DEFLATE_ARGS)
-
- # TODO: Add streaming
- body.each { |part| deflater << part }
+ def initialize(body)
+ @body = body
+ end
- return deflater.finish
+ def each
+ deflater = ::Zlib::Deflate.new(*DEFLATE_ARGS)
+ @body.each { |part| yield deflater.deflate(part) }
+ @body.close if @body.respond_to?(:close)
+ yield deflater.finish
+ nil
+ end
end
end
end
diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/directory.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/directory.rb
index acdd3029d3..acdd3029d3 100644
--- a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/directory.rb
+++ b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/directory.rb
diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/file.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/file.rb
index fe62bd6b86..fe62bd6b86 100644
--- a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/file.rb
+++ b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/file.rb
diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/handler.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/handler.rb
index 1018af64c7..5624a1e79d 100644
--- a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/handler.rb
+++ b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/handler.rb
@@ -10,16 +10,37 @@ module Rack
module Handler
def self.get(server)
return unless server
+ server = server.to_s
if klass = @handlers[server]
obj = Object
klass.split("::").each { |x| obj = obj.const_get(x) }
obj
else
- Rack::Handler.const_get(server.capitalize)
+ try_require('rack/handler', server)
+ const_get(server)
end
end
+ # Transforms server-name constants to their canonical form as filenames,
+ # then tries to require them but silences the LoadError if not found
+ #
+ # Naming convention:
+ #
+ # Foo # => 'foo'
+ # FooBar # => 'foo_bar.rb'
+ # FooBAR # => 'foobar.rb'
+ # FOObar # => 'foobar.rb'
+ # FOOBAR # => 'foobar.rb'
+ # FooBarBaz # => 'foo_bar_baz.rb'
+ def self.try_require(prefix, const_name)
+ file = const_name.gsub(/^[A-Z]+/) { |pre| pre.downcase }.
+ gsub(/[A-Z]+[^A-Z]/, '_\&').downcase
+
+ require(::File.join(prefix, file))
+ rescue LoadError
+ end
+
def self.register(server, klass)
@handlers ||= {}
@handlers[server] = klass
diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/handler/cgi.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/handler/cgi.rb
index e38156c7f0..f45f3d735a 100644
--- a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/handler/cgi.rb
+++ b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/handler/cgi.rb
@@ -15,7 +15,7 @@ module Rack
env["SCRIPT_NAME"] = "" if env["SCRIPT_NAME"] == "/"
- env.update({"rack.version" => [0,1],
+ env.update({"rack.version" => [1,0],
"rack.input" => $stdin,
"rack.errors" => $stderr,
diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/handler/evented_mongrel.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/handler/evented_mongrel.rb
index 0f5cbf7293..0f5cbf7293 100644
--- a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/handler/evented_mongrel.rb
+++ b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/handler/evented_mongrel.rb
diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/handler/fastcgi.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/handler/fastcgi.rb
index 6324c7d274..11e1fcaa74 100644
--- a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/handler/fastcgi.rb
+++ b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/handler/fastcgi.rb
@@ -1,6 +1,17 @@
require 'fcgi'
require 'socket'
require 'rack/content_length'
+require 'rack/rewindable_input'
+
+class FCGI::Stream
+ alias _rack_read_without_buffer read
+
+ def read(n, buffer=nil)
+ buf = _rack_read_without_buffer n
+ buffer.replace(buf.to_s) if buffer
+ buf
+ end
+end
module Rack
module Handler
@@ -13,34 +24,18 @@ module Rack
}
end
- module ProperStream # :nodoc:
- def each # This is missing by default.
- while line = gets
- yield line
- end
- end
-
- def read(*args)
- if args.empty?
- super || "" # Empty string on EOF.
- else
- super
- end
- end
- end
-
def self.serve(request, app)
app = Rack::ContentLength.new(app)
env = request.env
env.delete "HTTP_CONTENT_LENGTH"
- request.in.extend ProperStream
-
env["SCRIPT_NAME"] = "" if env["SCRIPT_NAME"] == "/"
+
+ rack_input = RewindableInput.new(request.in)
- env.update({"rack.version" => [0,1],
- "rack.input" => request.in,
+ env.update({"rack.version" => [1,0],
+ "rack.input" => rack_input,
"rack.errors" => request.err,
"rack.multithread" => false,
@@ -57,12 +52,16 @@ module Rack
env.delete "CONTENT_TYPE" if env["CONTENT_TYPE"] == ""
env.delete "CONTENT_LENGTH" if env["CONTENT_LENGTH"] == ""
- status, headers, body = app.call(env)
begin
- send_headers request.out, status, headers
- send_body request.out, body
+ status, headers, body = app.call(env)
+ begin
+ send_headers request.out, status, headers
+ send_body request.out, body
+ ensure
+ body.close if body.respond_to? :close
+ end
ensure
- body.close if body.respond_to? :close
+ rack_input.close
request.finish
end
end
diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/handler/lsws.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/handler/lsws.rb
index c65ba3ec8e..7231336d7b 100644
--- a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/handler/lsws.rb
+++ b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/handler/lsws.rb
@@ -15,7 +15,7 @@ module Rack
env = ENV.to_hash
env.delete "HTTP_CONTENT_LENGTH"
env["SCRIPT_NAME"] = "" if env["SCRIPT_NAME"] == "/"
- env.update({"rack.version" => [0,1],
+ env.update({"rack.version" => [1,0],
"rack.input" => StringIO.new($stdin.read.to_s),
"rack.errors" => $stderr,
"rack.multithread" => false,
diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/handler/mongrel.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/handler/mongrel.rb
index f0c0d58330..3a5ef32d4b 100644
--- a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/handler/mongrel.rb
+++ b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/handler/mongrel.rb
@@ -45,7 +45,7 @@ module Rack
env["SCRIPT_NAME"] = "" if env["SCRIPT_NAME"] == "/"
- env.update({"rack.version" => [0,1],
+ env.update({"rack.version" => [1,0],
"rack.input" => request.body || StringIO.new(""),
"rack.errors" => $stderr,
diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/handler/scgi.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/handler/scgi.rb
index 9495c66374..6c4932df95 100644
--- a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/handler/scgi.rb
+++ b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/handler/scgi.rb
@@ -32,7 +32,7 @@ module Rack
env["PATH_INFO"] = env["REQUEST_PATH"]
env["QUERY_STRING"] ||= ""
env["SCRIPT_NAME"] = ""
- env.update({"rack.version" => [0,1],
+ env.update({"rack.version" => [1,0],
"rack.input" => StringIO.new(input_body),
"rack.errors" => $stderr,
diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/handler/swiftiplied_mongrel.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/handler/swiftiplied_mongrel.rb
index 4bafd0b953..4bafd0b953 100644
--- a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/handler/swiftiplied_mongrel.rb
+++ b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/handler/swiftiplied_mongrel.rb
diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/handler/thin.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/handler/thin.rb
index 3d4fedff75..3d4fedff75 100644
--- a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/handler/thin.rb
+++ b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/handler/thin.rb
diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/handler/webrick.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/handler/webrick.rb
index 829e7d6bf8..2bdc83a9ff 100644
--- a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/handler/webrick.rb
+++ b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/handler/webrick.rb
@@ -22,7 +22,7 @@ module Rack
env = req.meta_vars
env.delete_if { |k, v| v.nil? }
- env.update({"rack.version" => [0,1],
+ env.update({"rack.version" => [1,0],
"rack.input" => StringIO.new(req.body.to_s),
"rack.errors" => $stderr,
diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/head.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/head.rb
index deab822a99..deab822a99 100644
--- a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/head.rb
+++ b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/head.rb
diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/lint.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/lint.rb
index 44a33ce36e..bf2e9787a1 100644
--- a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/lint.rb
+++ b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/lint.rb
@@ -88,9 +88,9 @@ module Rack
## within the application. This may be an
## empty string, if the request URL targets
## the application root and does not have a
- ## trailing slash. This information should be
- ## decoded by the server if it comes from a
- ## URL.
+ ## trailing slash. This value may be
+ ## percent-encoded when I originating from
+ ## a URL.
## <tt>QUERY_STRING</tt>:: The portion of the request URL that
## follows the <tt>?</tt>, if any. May be
@@ -111,19 +111,48 @@ module Rack
## In addition to this, the Rack environment must include these
## Rack-specific variables:
- ## <tt>rack.version</tt>:: The Array [0,1], representing this version of Rack.
+ ## <tt>rack.version</tt>:: The Array [1,0], representing this version of Rack.
## <tt>rack.url_scheme</tt>:: +http+ or +https+, depending on the request URL.
## <tt>rack.input</tt>:: See below, the input stream.
## <tt>rack.errors</tt>:: See below, the error stream.
## <tt>rack.multithread</tt>:: true if the application object may be simultaneously invoked by another thread in the same process, false otherwise.
## <tt>rack.multiprocess</tt>:: true if an equivalent application object may be simultaneously invoked by another process, false otherwise.
## <tt>rack.run_once</tt>:: true if the server expects (but does not guarantee!) that the application will only be invoked this one time during the life of its containing process. Normally, this will only be true for a server based on CGI (or something similar).
+ ##
+
+ ## Additional environment specifications have approved to
+ ## standardized middleware APIs. None of these are required to
+ ## be implemented by the server.
+
+ ## <tt>rack.session</tt>:: A hash like interface for storing request session data.
+ ## The store must implement:
+ if session = env['rack.session']
+ ## store(key, value) (aliased as []=);
+ assert("session #{session.inspect} must respond to store and []=") {
+ session.respond_to?(:store) && session.respond_to?(:[]=)
+ }
+
+ ## fetch(key, default = nil) (aliased as []);
+ assert("session #{session.inspect} must respond to fetch and []") {
+ session.respond_to?(:fetch) && session.respond_to?(:[])
+ }
+
+ ## delete(key);
+ assert("session #{session.inspect} must respond to delete") {
+ session.respond_to?(:delete)
+ }
+
+ ## clear;
+ assert("session #{session.inspect} must respond to clear") {
+ session.respond_to?(:clear)
+ }
+ end
## The server or the application can store their own data in the
## environment, too. The keys must contain at least one dot,
## and should be prefixed uniquely. The prefix <tt>rack.</tt>
- ## is reserved for use with the Rack core distribution and must
- ## not be used otherwise.
+ ## is reserved for use with the Rack core distribution and other
+ ## accepted specifications and must not be used otherwise.
##
%w[REQUEST_METHOD SERVER_NAME SERVER_PORT
@@ -202,9 +231,12 @@ module Rack
end
## === The Input Stream
+ ##
+ ## The input stream is an IO-like object which contains the raw HTTP
+ ## POST data. If it is a file then it must be opened in binary mode.
def check_input(input)
- ## The input stream must respond to +gets+, +each+ and +read+.
- [:gets, :each, :read].each { |method|
+ ## The input stream must respond to +gets+, +each+, +read+ and +rewind+.
+ [:gets, :each, :read, :rewind].each { |method|
assert("rack.input #{input} does not respond to ##{method}") {
input.respond_to? method
}
@@ -222,10 +254,6 @@ module Rack
@input.size
end
- def rewind
- @input.rewind
- end
-
## * +gets+ must be called without arguments and return a string,
## or +nil+ on EOF.
def gets(*args)
@@ -237,21 +265,44 @@ module Rack
v
end
- ## * +read+ must be called without or with one integer argument
- ## and return a string, or +nil+ on EOF.
+ ## * +read+ behaves like IO#read. Its signature is <tt>read([length, [buffer]])</tt>.
+ ## If given, +length+ must be an non-negative Integer (>= 0) or +nil+, and +buffer+ must
+ ## be a String and may not be nil. If +length+ is given and not nil, then this method
+ ## reads at most +length+ bytes from the input stream. If +length+ is not given or nil,
+ ## then this method reads all data until EOF.
+ ## When EOF is reached, this method returns nil if +length+ is given and not nil, or ""
+ ## if +length+ is not given or is nil.
+ ## If +buffer+ is given, then the read data will be placed into +buffer+ instead of a
+ ## newly created String object.
def read(*args)
assert("rack.input#read called with too many arguments") {
- args.size <= 1
+ args.size <= 2
}
- if args.size == 1
- assert("rack.input#read called with non-integer argument") {
- args.first.kind_of? Integer
+ if args.size >= 1
+ assert("rack.input#read called with non-integer and non-nil length") {
+ args.first.kind_of?(Integer) || args.first.nil?
+ }
+ assert("rack.input#read called with a negative length") {
+ args.first.nil? || args.first >= 0
}
end
+ if args.size >= 2
+ assert("rack.input#read called with non-String buffer") {
+ args[1].kind_of?(String)
+ }
+ end
+
v = @input.read(*args)
- assert("rack.input#read didn't return a String") {
+
+ assert("rack.input#read didn't return nil or a String") {
v.nil? or v.instance_of? String
}
+ if args[0].nil?
+ assert("rack.input#read(nil) returned nil on EOF") {
+ !v.nil?
+ }
+ end
+
v
end
@@ -265,6 +316,23 @@ module Rack
yield line
}
end
+
+ ## * +rewind+ must be called without arguments. It rewinds the input
+ ## stream back to the beginning. It must not raise Errno::ESPIPE:
+ ## that is, it may not be a pipe or a socket. Therefore, handler
+ ## developers must buffer the input data into some rewindable object
+ ## if the underlying input stream is not rewindable.
+ def rewind(*args)
+ assert("rack.input#rewind called with arguments") { args.size == 0 }
+ assert("rack.input#rewind raised Errno::ESPIPE") {
+ begin
+ @input.rewind
+ true
+ rescue Errno::ESPIPE
+ false
+ end
+ }
+ end
## * +close+ must never be called on the input stream.
def close(*args)
@@ -316,13 +384,14 @@ module Rack
## === The Status
def check_status(status)
- ## The status, if parsed as integer (+to_i+), must be greater than or equal to 100.
+ ## This is an HTTP status. When parsed as integer (+to_i+), it must be
+ ## greater than or equal to 100.
assert("Status must be >=100 seen as integer") { status.to_i >= 100 }
end
## === The Headers
def check_headers(header)
- ## The header must respond to each, and yield values of key and value.
+ ## The header must respond to +each+, and yield values of key and value.
assert("headers object should respond to #each, but doesn't (got #{header.class} as headers)") {
header.respond_to? :each
}
@@ -344,7 +413,8 @@ module Rack
## The values of the header must be Strings,
assert("a header value must be a String, but the value of " +
"'#{key}' is a #{value.class}") { value.kind_of? String }
- ## consisting of lines (for multiple header values) seperated by "\n".
+ ## consisting of lines (for multiple header values, e.g. multiple
+ ## <tt>Set-Cookie</tt> values) seperated by "\n".
value.split("\n").each { |item|
## The lines must not contain characters below 037.
assert("invalid header value #{key}: #{item.inspect}") {
@@ -416,7 +486,7 @@ module Rack
## === The Body
def each
@closed = false
- ## The Body must respond to #each
+ ## The Body must respond to +each+
@body.each { |part|
## and must only yield String values.
assert("Body yielded non-string value #{part.inspect}") {
@@ -425,14 +495,19 @@ module Rack
yield part
}
##
- ## If the Body responds to #close, it will be called after iteration.
+ ## The Body itself should not be an instance of String, as this will
+ ## break in Ruby 1.9.
+ ##
+ ## If the Body responds to +close+, it will be called after iteration.
# XXX howto: assert("Body has not been closed") { @closed }
##
- ## If the Body responds to #to_path, it must return a String
+ ## If the Body responds to +to_path+, it must return a String
## identifying the location of a file whose contents are identical
- ## to that produced by calling #each.
+ ## to that produced by calling +each+; this may be used by the
+ ## server as an alternative, possibly more efficient way to
+ ## transport the response.
if @body.respond_to?(:to_path)
assert("The file identified by body.to_path does not exist") {
diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/lobster.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/lobster.rb
index f63f419a49..f63f419a49 100644
--- a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/lobster.rb
+++ b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/lobster.rb
diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/lock.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/lock.rb
index 93238528c4..93238528c4 100644
--- a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/lock.rb
+++ b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/lock.rb
diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/methodoverride.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/methodoverride.rb
index 0eed29f471..0eed29f471 100644
--- a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/methodoverride.rb
+++ b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/methodoverride.rb
diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/mime.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/mime.rb
index 5a6a73a97b..5a6a73a97b 100644
--- a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/mime.rb
+++ b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/mime.rb
diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/mock.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/mock.rb
index 70852da3db..fdefb0340a 100644
--- a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/mock.rb
+++ b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/mock.rb
@@ -40,7 +40,7 @@ module Rack
end
DEFAULT_ENV = {
- "rack.version" => [0,1],
+ "rack.version" => [1,0],
"rack.input" => StringIO.new,
"rack.errors" => StringIO.new,
"rack.multithread" => true,
@@ -73,14 +73,17 @@ module Rack
# Return the Rack environment used for a request to +uri+.
def self.env_for(uri="", opts={})
uri = URI(uri)
+ uri.path = "/#{uri.path}" unless uri.path[0] == ?/
+
env = DEFAULT_ENV.dup
- env["REQUEST_METHOD"] = opts[:method] || "GET"
+ env["REQUEST_METHOD"] = opts[:method] ? opts[:method].to_s.upcase : "GET"
env["SERVER_NAME"] = uri.host || "example.org"
env["SERVER_PORT"] = uri.port ? uri.port.to_s : "80"
env["QUERY_STRING"] = uri.query.to_s
env["PATH_INFO"] = (!uri.path || uri.path.empty?) ? "/" : uri.path
env["rack.url_scheme"] = uri.scheme || "http"
+ env["HTTPS"] = env["rack.url_scheme"] == "https" ? "on" : "off"
env["SCRIPT_NAME"] = opts[:script_name] || ""
@@ -90,6 +93,27 @@ module Rack
env["rack.errors"] = StringIO.new
end
+ if params = opts[:params]
+ if env["REQUEST_METHOD"] == "GET"
+ params = Utils.parse_nested_query(params) if params.is_a?(String)
+ params.update(Utils.parse_nested_query(env["QUERY_STRING"]))
+ env["QUERY_STRING"] = Utils.build_nested_query(params)
+ elsif !opts.has_key?(:input)
+ opts["CONTENT_TYPE"] = "application/x-www-form-urlencoded"
+ if params.is_a?(Hash)
+ if data = Utils::Multipart.build_multipart(params)
+ opts[:input] = data
+ opts["CONTENT_LENGTH"] ||= data.length.to_s
+ opts["CONTENT_TYPE"] = "multipart/form-data; boundary=#{Utils::Multipart::MULTIPART_BOUNDARY}"
+ else
+ opts[:input] = Utils.build_nested_query(params)
+ end
+ else
+ opts[:input] = params
+ end
+ end
+ end
+
opts[:input] ||= ""
if String === opts[:input]
env["rack.input"] = StringIO.new(opts[:input])
@@ -125,7 +149,7 @@ module Rack
@body = ""
body.each { |part| @body << part }
- @errors = errors.string
+ @errors = errors.string if errors.respond_to?(:string)
end
# Status
diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/recursive.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/recursive.rb
index bf8b965925..bf8b965925 100644
--- a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/recursive.rb
+++ b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/recursive.rb
diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/reloader.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/reloader.rb
new file mode 100644
index 0000000000..aa2f060be5
--- /dev/null
+++ b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/reloader.rb
@@ -0,0 +1,106 @@
+# Copyright (c) 2009 Michael Fellinger m.fellinger@gmail.com
+# All files in this distribution are subject to the terms of the Ruby license.
+
+require 'pathname'
+
+module Rack
+
+ # High performant source reloader
+ #
+ # This class acts as Rack middleware.
+ #
+ # What makes it especially suited for use in a production environment is that
+ # any file will only be checked once and there will only be made one system
+ # call stat(2).
+ #
+ # Please note that this will not reload files in the background, it does so
+ # only when actively called.
+ #
+ # It is performing a check/reload cycle at the start of every request, but
+ # also respects a cool down time, during which nothing will be done.
+ class Reloader
+ def initialize(app, cooldown = 10, backend = Stat)
+ @app = app
+ @cooldown = cooldown
+ @last = (Time.now - cooldown)
+ @cache = {}
+ @mtimes = {}
+
+ extend backend
+ end
+
+ def call(env)
+ if @cooldown and Time.now > @last + @cooldown
+ if Thread.list.size > 1
+ Thread.exclusive{ reload! }
+ else
+ reload!
+ end
+
+ @last = Time.now
+ end
+
+ @app.call(env)
+ end
+
+ def reload!(stderr = $stderr)
+ rotation do |file, mtime|
+ previous_mtime = @mtimes[file] ||= mtime
+ safe_load(file, mtime, stderr) if mtime > previous_mtime
+ end
+ end
+
+ # A safe Kernel::load, issuing the hooks depending on the results
+ def safe_load(file, mtime, stderr = $stderr)
+ load(file)
+ stderr.puts "#{self.class}: reloaded `#{file}'"
+ file
+ rescue LoadError, SyntaxError => ex
+ stderr.puts ex
+ ensure
+ @mtimes[file] = mtime
+ end
+
+ module Stat
+ def rotation
+ files = [$0, *$LOADED_FEATURES].uniq
+ paths = ['./', *$LOAD_PATH].uniq
+
+ files.map{|file|
+ next if file =~ /\.(so|bundle)$/ # cannot reload compiled files
+
+ found, stat = figure_path(file, paths)
+ next unless found and stat and mtime = stat.mtime
+
+ @cache[file] = found
+
+ yield(found, mtime)
+ }.compact
+ end
+
+ # Takes a relative or absolute +file+ name, a couple possible +paths+ that
+ # the +file+ might reside in. Returns the full path and File::Stat for the
+ # path.
+ def figure_path(file, paths)
+ found = @cache[file]
+ found = file if !found and Pathname.new(file).absolute?
+ found, stat = safe_stat(found)
+ return found, stat if found
+
+ paths.each do |possible_path|
+ path = ::File.join(possible_path, file)
+ found, stat = safe_stat(path)
+ return ::File.expand_path(found), stat if found
+ end
+ end
+
+ def safe_stat(file)
+ return unless file
+ stat = ::File.stat(file)
+ return file, stat if stat.file?
+ rescue Errno::ENOENT, Errno::ENOTDIR
+ @cache.delete(file) and false
+ end
+ end
+ end
+end
diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/request.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/request.rb
index d77fa26575..0bff7af038 100644
--- a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/request.rb
+++ b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/request.rb
@@ -17,7 +17,7 @@ module Rack
# The environment of the request.
attr_reader :env
- def self.new(env)
+ def self.new(env, *args)
if self == Rack::Request
env["rack.request"] ||= super
else
@@ -38,6 +38,8 @@ module Rack
def query_string; @env["QUERY_STRING"].to_s end
def content_length; @env['CONTENT_LENGTH'] end
def content_type; @env['CONTENT_TYPE'] end
+ def session; @env['rack.session'] ||= {} end
+ def session_options; @env['rack.session.options'] ||= {} end
# The media type (type/subtype) portion of the CONTENT_TYPE header
# without any media type parameters. e.g., when CONTENT_TYPE is
@@ -46,7 +48,7 @@ module Rack
# For more information on the use of media types in HTTP, see:
# http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.7
def media_type
- content_type && content_type.split(/\s*[;,]\s*/, 2)[0].downcase
+ content_type && content_type.split(/\s*[;,]\s*/, 2).first.downcase
end
# The media type parameters provided in CONTENT_TYPE as a Hash, or
@@ -92,6 +94,14 @@ module Rack
'multipart/form-data'
]
+ # The set of media-types. Requests that do not indicate
+ # one of the media types presents in this list will not be eligible
+ # for param parsing like soap attachments or generic multiparts
+ PARSEABLE_DATA_MEDIA_TYPES = [
+ 'multipart/related',
+ 'multipart/mixed'
+ ]
+
# Determine whether the request body contains form-data by checking
# the request media_type against registered form-data media-types:
# "application/x-www-form-urlencoded" and "multipart/form-data". The
@@ -101,6 +111,12 @@ module Rack
FORM_DATA_MEDIA_TYPES.include?(media_type)
end
+ # Determine whether the request body contains data by checking
+ # the request media_type against registered parse-data media-types
+ def parseable_data?
+ PARSEABLE_DATA_MEDIA_TYPES.include?(media_type)
+ end
+
# Returns the data recieved in the query string.
def GET
if @env["rack.request.query_string"] == query_string
@@ -119,7 +135,7 @@ module Rack
def POST
if @env["rack.request.form_input"].eql? @env["rack.input"]
@env["rack.request.form_hash"]
- elsif form_data?
+ elsif form_data? || parseable_data?
@env["rack.request.form_input"] = @env["rack.input"]
unless @env["rack.request.form_hash"] =
Utils::Multipart.parse_multipart(env)
@@ -131,12 +147,7 @@ module Rack
@env["rack.request.form_vars"] = form_vars
@env["rack.request.form_hash"] = Utils.parse_nested_query(form_vars)
- begin
- @env["rack.input"].rewind if @env["rack.input"].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
+ @env["rack.input"].rewind
end
@env["rack.request.form_hash"]
else
@@ -211,11 +222,13 @@ module Rack
url
end
-
+
+ def path
+ script_name + path_info
+ end
+
def fullpath
- path = script_name + path_info
- path << "?" << query_string unless query_string.empty?
- path
+ query_string.empty? ? path : "#{path}?#{query_string}"
end
def accept_encoding
diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/response.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/response.rb
index caf60d5b19..28b4d8302f 100644
--- a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/response.rb
+++ b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/response.rb
@@ -95,6 +95,10 @@ module Rack
:expires => Time.at(0) }.merge(value))
end
+ def redirect(target, status=302)
+ self.status = status
+ self["Location"] = target
+ end
def finish(&block)
@block = block
@@ -120,7 +124,7 @@ module Rack
#
def write(str)
s = str.to_s
- @length += s.size
+ @length += Rack::Utils.bytesize(s)
@writer.call s
header["Content-Length"] = @length.to_s
diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/rewindable_input.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/rewindable_input.rb
new file mode 100644
index 0000000000..9e9b21ff99
--- /dev/null
+++ b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/rewindable_input.rb
@@ -0,0 +1,98 @@
+require 'tempfile'
+
+module Rack
+ # Class which can make any IO object rewindable, including non-rewindable ones. It does
+ # this by buffering the data into a tempfile, which is rewindable.
+ #
+ # rack.input is required to be rewindable, so if your input stream IO is non-rewindable
+ # by nature (e.g. a pipe or a socket) then you can wrap it in an object of this class
+ # to easily make it rewindable.
+ #
+ # Don't forget to call #close when you're done. This frees up temporary resources that
+ # RewindableInput uses, though it does *not* close the original IO object.
+ class RewindableInput
+ def initialize(io)
+ @io = io
+ @rewindable_io = nil
+ @unlinked = false
+ end
+
+ def gets
+ make_rewindable unless @rewindable_io
+ @rewindable_io.gets
+ end
+
+ def read(*args)
+ make_rewindable unless @rewindable_io
+ @rewindable_io.read(*args)
+ end
+
+ def each(&block)
+ make_rewindable unless @rewindable_io
+ @rewindable_io.each(&block)
+ end
+
+ def rewind
+ make_rewindable unless @rewindable_io
+ @rewindable_io.rewind
+ end
+
+ # Closes this RewindableInput object without closing the originally
+ # wrapped IO oject. Cleans up any temporary resources that this RewindableInput
+ # has created.
+ #
+ # This method may be called multiple times. It does nothing on subsequent calls.
+ def close
+ if @rewindable_io
+ if @unlinked
+ @rewindable_io.close
+ else
+ @rewindable_io.close!
+ end
+ @rewindable_io = nil
+ end
+ end
+
+ private
+
+ # Ruby's Tempfile class has a bug. Subclass it and fix it.
+ class Tempfile < ::Tempfile
+ def _close
+ @tmpfile.close if @tmpfile
+ @data[1] = nil if @data
+ @tmpfile = nil
+ end
+ end
+
+ def make_rewindable
+ # Buffer all data into a tempfile. Since this tempfile is private to this
+ # RewindableInput object, we chmod it so that nobody else can read or write
+ # it. On POSIX filesystems we also unlink the file so that it doesn't
+ # even have a file entry on the filesystem anymore, though we can still
+ # access it because we have the file handle open.
+ @rewindable_io = Tempfile.new('RackRewindableInput')
+ @rewindable_io.chmod(0000)
+ if filesystem_has_posix_semantics?
+ @rewindable_io.unlink
+ @unlinked = true
+ end
+
+ buffer = ""
+ while @io.read(1024 * 4, buffer)
+ entire_buffer_written_out = false
+ while !entire_buffer_written_out
+ written = @rewindable_io.write(buffer)
+ entire_buffer_written_out = written == buffer.size
+ if !entire_buffer_written_out
+ buffer.slice!(0 .. written - 1)
+ end
+ end
+ end
+ @rewindable_io.rewind
+ end
+
+ def filesystem_has_posix_semantics?
+ RUBY_PLATFORM !~ /(mswin|mingw|cygwin|java)/
+ end
+ end
+end
diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/session/abstract/id.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/session/abstract/id.rb
index 218144c17f..218144c17f 100644
--- a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/session/abstract/id.rb
+++ b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/session/abstract/id.rb
diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/session/cookie.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/session/cookie.rb
index eace9bd0c6..eace9bd0c6 100644
--- a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/session/cookie.rb
+++ b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/session/cookie.rb
diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/session/memcache.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/session/memcache.rb
index 4a65cbf35d..4a65cbf35d 100644
--- a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/session/memcache.rb
+++ b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/session/memcache.rb
diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/session/pool.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/session/pool.rb
index f6f87408bb..f6f87408bb 100644
--- a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/session/pool.rb
+++ b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/session/pool.rb
diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/showexceptions.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/showexceptions.rb
index 697bc41fdb..697bc41fdb 100644
--- a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/showexceptions.rb
+++ b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/showexceptions.rb
diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/showstatus.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/showstatus.rb
index 28258c7c89..28258c7c89 100644
--- a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/showstatus.rb
+++ b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/showstatus.rb
diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/static.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/static.rb
index 168e8f83b2..168e8f83b2 100644
--- a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/static.rb
+++ b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/static.rb
diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/urlmap.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/urlmap.rb
index 0ff32df181..fcf6616c58 100644
--- a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/urlmap.rb
+++ b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/urlmap.rb
@@ -30,7 +30,7 @@ module Rack
location = location.chomp('/')
[host, location, app]
- }.sort_by { |(h, l, a)| [-l.size, h.to_s.size] } # Longest path first
+ }.sort_by { |(h, l, a)| [h ? -h.size : (-1.0 / 0.0), -l.size] } # Longest path first
end
def call(env)
diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/utils.rb b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/utils.rb
index 0a61bce707..42e2e698f4 100644
--- a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/utils.rb
+++ b/actionpack/lib/action_dispatch/vendor/rack-1.1.pre/rack/utils.rb
@@ -1,3 +1,5 @@
+# -*- encoding: binary -*-
+
require 'set'
require 'tempfile'
@@ -63,7 +65,7 @@ module Rack
module_function :parse_nested_query
def normalize_params(params, name, v = nil)
- name =~ %r([\[\]]*([^\[\]]+)\]*)
+ name =~ %r(\A[\[\]]*([^\[\]]+)\]*)
k = $1 || ''
after = $' || ''
@@ -73,12 +75,12 @@ module Rack
params[k] = v
elsif after == "[]"
params[k] ||= []
- raise TypeError unless params[k].is_a?(Array)
+ raise TypeError, "expected Array (got #{params[k].class.name}) for param `#{k}'" unless params[k].is_a?(Array)
params[k] << v
elsif after =~ %r(^\[\]\[([^\[\]]+)\]$) || after =~ %r(^\[\](.+)$)
child_key = $1
params[k] ||= []
- raise TypeError unless params[k].is_a?(Array)
+ raise TypeError, "expected Array (got #{params[k].class.name}) for param `#{k}'" unless params[k].is_a?(Array)
if params[k].last.is_a?(Hash) && !params[k].last.key?(child_key)
normalize_params(params[k].last, child_key, v)
else
@@ -86,6 +88,7 @@ module Rack
end
else
params[k] ||= {}
+ raise TypeError, "expected Hash (got #{params[k].class.name}) for param `#{k}'" unless params[k].is_a?(Hash)
params[k] = normalize_params(params[k], after, v)
end
@@ -104,6 +107,25 @@ module Rack
end
module_function :build_query
+ def build_nested_query(value, prefix = nil)
+ case value
+ when Array
+ value.map { |v|
+ build_nested_query(v, "#{prefix}[]")
+ }.join("&")
+ when Hash
+ value.map { |k, v|
+ build_nested_query(v, prefix ? "#{prefix}[#{escape(k)}]" : escape(k))
+ }.join("&")
+ when String
+ raise ArgumentError, "value must be a Hash" if prefix.nil?
+ "#{prefix}=#{escape(value)}"
+ else
+ prefix
+ end
+ end
+ module_function :build_nested_query
+
# Escape ampersands, brackets and quotes to their HTML/XML entities.
def escape_html(string)
string.to_s.gsub("&", "&amp;").
@@ -288,11 +310,39 @@ module Rack
# Usually, Rack::Request#POST takes care of calling this.
module Multipart
+ class UploadedFile
+ # The filename, *not* including the path, of the "uploaded" file
+ attr_reader :original_filename
+
+ # The content type of the "uploaded" file
+ attr_accessor :content_type
+
+ def initialize(path, content_type = "text/plain", binary = false)
+ raise "#{path} file does not exist" unless ::File.exist?(path)
+ @content_type = content_type
+ @original_filename = ::File.basename(path)
+ @tempfile = Tempfile.new(@original_filename)
+ @tempfile.set_encoding(Encoding::BINARY) if @tempfile.respond_to?(:set_encoding)
+ @tempfile.binmode if binary
+ FileUtils.copy_file(path, @tempfile.path)
+ end
+
+ def path
+ @tempfile.path
+ end
+ alias_method :local_path, :path
+
+ def method_missing(method_name, *args, &block) #:nodoc:
+ @tempfile.__send__(method_name, *args, &block)
+ end
+ end
+
EOL = "\r\n"
+ MULTIPART_BOUNDARY = "AaB03x"
def self.parse_multipart(env)
unless env['CONTENT_TYPE'] =~
- %r|\Amultipart/form-data.*boundary=\"?([^\";,]+)\"?|n
+ %r|\Amultipart/.*boundary=\"?([^\";,]+)\"?|n
nil
else
boundary = "--#{$1}"
@@ -301,13 +351,16 @@ module Rack
buf = ""
content_length = env['CONTENT_LENGTH'].to_i
input = env['rack.input']
+ input.rewind
- boundary_size = boundary.size + EOL.size
+ boundary_size = Utils.bytesize(boundary) + EOL.size
bufsize = 16384
content_length -= boundary_size
- status = input.read(boundary_size)
+ read_buffer = ''
+
+ status = input.read(boundary_size, read_buffer)
raise EOFError, "bad content body" unless status == boundary + EOL
rx = /(?:#{EOL})?#{Regexp.quote boundary}(#{EOL}|--)/n
@@ -318,15 +371,15 @@ module Rack
filename = content_type = name = nil
until head && buf =~ rx
- if !head && i = buf.index("\r\n\r\n")
+ if !head && i = buf.index(EOL+EOL)
head = buf.slice!(0, i+2) # First \r\n
buf.slice!(0, 2) # Second \r\n
filename = head[/Content-Disposition:.* filename="?([^\";]*)"?/ni, 1]
- content_type = head[/Content-Type: (.*)\r\n/ni, 1]
- name = head[/Content-Disposition:.* name="?([^\";]*)"?/ni, 1]
+ content_type = head[/Content-Type: (.*)#{EOL}/ni, 1]
+ name = head[/Content-Disposition:.*\s+name="?([^\";]*)"?/ni, 1] || head[/Content-ID:\s*([^#{EOL}]*)/ni, 1]
- if filename
+ if content_type || filename
body = Tempfile.new("RackMultipart")
body.binmode if body.respond_to?(:binmode)
end
@@ -339,7 +392,7 @@ module Rack
body << buf.slice!(0, buf.size - (boundary_size+4))
end
- c = input.read(bufsize < content_length ? bufsize : content_length)
+ c = input.read(bufsize < content_length ? bufsize : content_length, read_buffer)
raise EOFError, "bad content body" if c.nil? || c.empty?
buf << c
content_length -= c.size
@@ -368,6 +421,12 @@ module Rack
data = {:filename => filename, :type => content_type,
:name => name, :tempfile => body, :head => head}
+ elsif !filename && content_type
+ body.rewind
+
+ # Generic multipart cases, not coming from a form
+ data = {:type => content_type,
+ :name => name, :tempfile => body, :head => head}
else
data = body
end
@@ -377,16 +436,81 @@ module Rack
break if buf.empty? || content_length == -1
}
- begin
- input.rewind if input.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
+ input.rewind
params
end
end
+
+ def self.build_multipart(params, first = true)
+ if first
+ unless params.is_a?(Hash)
+ raise ArgumentError, "value must be a Hash"
+ end
+
+ multipart = false
+ query = lambda { |value|
+ case value
+ when Array
+ value.each(&query)
+ when Hash
+ value.values.each(&query)
+ when UploadedFile
+ multipart = true
+ end
+ }
+ params.values.each(&query)
+ return nil unless multipart
+ end
+
+ flattened_params = Hash.new
+
+ params.each do |key, value|
+ k = first ? key.to_s : "[#{key}]"
+
+ case value
+ when Array
+ value.map { |v|
+ build_multipart(v, false).each { |subkey, subvalue|
+ flattened_params["#{k}[]#{subkey}"] = subvalue
+ }
+ }
+ when Hash
+ build_multipart(value, false).each { |subkey, subvalue|
+ flattened_params[k + subkey] = subvalue
+ }
+ else
+ flattened_params[k] = value
+ end
+ end
+
+ if first
+ flattened_params.map { |name, file|
+ if file.respond_to?(:original_filename)
+ ::File.open(file.path, "rb") do |f|
+ f.set_encoding(Encoding::BINARY) if f.respond_to?(:set_encoding)
+<<-EOF
+--#{MULTIPART_BOUNDARY}\r
+Content-Disposition: form-data; name="#{name}"; filename="#{Utils.escape(file.original_filename)}"\r
+Content-Type: #{file.content_type}\r
+Content-Length: #{::File.stat(file.path).size}\r
+\r
+#{f.read}\r
+EOF
+ end
+ else
+<<-EOF
+--#{MULTIPART_BOUNDARY}\r
+Content-Disposition: form-data; name="#{name}"\r
+\r
+#{file}\r
+EOF
+ end
+ }.join + "--#{MULTIPART_BOUNDARY}--\r"
+ else
+ flattened_params
+ end
+ end
end
end
end
diff --git a/actionpack/lib/action_dispatch/vendor/rack-test/rack/mock_session.rb b/actionpack/lib/action_dispatch/vendor/rack-test/rack/mock_session.rb
new file mode 100644
index 0000000000..eba6226538
--- /dev/null
+++ b/actionpack/lib/action_dispatch/vendor/rack-test/rack/mock_session.rb
@@ -0,0 +1,50 @@
+module Rack
+
+ class MockSession
+ attr_writer :cookie_jar
+ attr_reader :last_response
+
+ def initialize(app, default_host = Rack::Test::DEFAULT_HOST)
+ @app = app
+ @default_host = default_host
+ end
+
+ def clear_cookies
+ @cookie_jar = Rack::Test::CookieJar.new([], @default_host)
+ end
+
+ def set_cookie(cookie, uri = nil)
+ cookie_jar.merge(cookie, uri)
+ end
+
+ def request(uri, env)
+ env["HTTP_COOKIE"] ||= cookie_jar.for(uri)
+ @last_request = Rack::Request.new(env)
+ status, headers, body = @app.call(@last_request.env)
+ @last_response = MockResponse.new(status, headers, body, env["rack.errors"].flush)
+ cookie_jar.merge(last_response.headers["Set-Cookie"], uri)
+
+ @last_response
+ end
+
+ # Return the last request issued in the session. Raises an error if no
+ # requests have been sent yet.
+ def last_request
+ raise Rack::Test::Error.new("No request yet. Request a page first.") unless @last_request
+ @last_request
+ end
+
+ # Return the last response received in the session. Raises an error if
+ # no requests have been sent yet.
+ def last_response
+ raise Rack::Test::Error.new("No response yet. Request a page first.") unless @last_response
+ @last_response
+ end
+
+ def cookie_jar
+ @cookie_jar ||= Rack::Test::CookieJar.new([], @default_host)
+ end
+
+ end
+
+end
diff --git a/actionpack/lib/action_dispatch/vendor/rack-test/rack/test.rb b/actionpack/lib/action_dispatch/vendor/rack-test/rack/test.rb
new file mode 100644
index 0000000000..70384b1d76
--- /dev/null
+++ b/actionpack/lib/action_dispatch/vendor/rack-test/rack/test.rb
@@ -0,0 +1,239 @@
+unless $LOAD_PATH.include?(File.expand_path(File.dirname(__FILE__) + "/.."))
+ $LOAD_PATH.unshift(File.expand_path(File.dirname(__FILE__) + "/.."))
+end
+
+require "uri"
+require "rack"
+require "rack/mock_session"
+require "rack/test/cookie_jar"
+require "rack/test/mock_digest_request"
+require "rack/test/utils"
+require "rack/test/methods"
+require "rack/test/uploaded_file"
+
+module Rack
+ module Test
+
+ VERSION = "0.3.0"
+
+ DEFAULT_HOST = "example.org"
+ MULTIPART_BOUNDARY = "----------XnJLe9ZIbbGUYtzPQJ16u1"
+
+ # The common base class for exceptions raised by Rack::Test
+ class Error < StandardError; end
+
+ class Session
+ extend Forwardable
+ include Rack::Test::Utils
+
+ def_delegators :@rack_mock_session, :clear_cookies, :set_cookie, :last_response, :last_request
+
+ # Initialize a new session for the given Rack app
+ def initialize(app, default_host = DEFAULT_HOST)
+ @headers = {}
+ @default_host = default_host
+ @rack_mock_session = Rack::MockSession.new(app, default_host)
+ end
+
+ # Issue a GET request for the given URI with the given params and Rack
+ # environment. Stores the issues request object in #last_request and
+ # the app's response in #last_response. Yield #last_response to a block
+ # if given.
+ #
+ # Example:
+ # get "/"
+ def get(uri, params = {}, env = {}, &block)
+ env = env_for(uri, env.merge(:method => "GET", :params => params))
+ process_request(uri, env, &block)
+ end
+
+ # Issue a POST request for the given URI. See #get
+ #
+ # Example:
+ # post "/signup", "name" => "Bryan"
+ def post(uri, params = {}, env = {}, &block)
+ env = env_for(uri, env.merge(:method => "POST", :params => params))
+ process_request(uri, env, &block)
+ end
+
+ # Issue a PUT request for the given URI. See #get
+ #
+ # Example:
+ # put "/"
+ def put(uri, params = {}, env = {}, &block)
+ env = env_for(uri, env.merge(:method => "PUT", :params => params))
+ process_request(uri, env, &block)
+ end
+
+ # Issue a DELETE request for the given URI. See #get
+ #
+ # Example:
+ # delete "/"
+ def delete(uri, params = {}, env = {}, &block)
+ env = env_for(uri, env.merge(:method => "DELETE", :params => params))
+ process_request(uri, env, &block)
+ end
+
+ # Issue a HEAD request for the given URI. See #get
+ #
+ # Example:
+ # head "/"
+ def head(uri, params = {}, env = {}, &block)
+ env = env_for(uri, env.merge(:method => "HEAD", :params => params))
+ process_request(uri, env, &block)
+ end
+
+ # Issue a request to the Rack app for the given URI and optional Rack
+ # environment. Stores the issues request object in #last_request and
+ # the app's response in #last_response. Yield #last_response to a block
+ # if given.
+ #
+ # Example:
+ # request "/"
+ def request(uri, env = {}, &block)
+ env = env_for(uri, env)
+ process_request(uri, env, &block)
+ end
+
+ # Set a header to be included on all subsequent requests through the
+ # session. Use a value of nil to remove a previously configured header.
+ #
+ # Example:
+ # header "User-Agent", "Firefox"
+ def header(name, value)
+ if value.nil?
+ @headers.delete(name)
+ else
+ @headers[name] = value
+ end
+ end
+
+ # Set the username and password for HTTP Basic authorization, to be
+ # included in subsequent requests in the HTTP_AUTHORIZATION header.
+ #
+ # Example:
+ # basic_authorize "bryan", "secret"
+ def basic_authorize(username, password)
+ encoded_login = ["#{username}:#{password}"].pack("m*")
+ header('HTTP_AUTHORIZATION', "Basic #{encoded_login}")
+ end
+
+ alias_method :authorize, :basic_authorize
+
+ def digest_authorize(username, password)
+ @digest_username = username
+ @digest_password = password
+ end
+
+ # Rack::Test will not follow any redirects automatically. This method
+ # will follow the redirect returned in the last response. If the last
+ # response was not a redirect, an error will be raised.
+ def follow_redirect!
+ unless last_response.redirect?
+ raise Error.new("Last response was not a redirect. Cannot follow_redirect!")
+ end
+
+ get(last_response["Location"])
+ end
+
+ private
+
+ def env_for(path, env)
+ uri = URI.parse(path)
+ uri.host ||= @default_host
+
+ env = default_env.merge(env)
+
+ env.update("HTTPS" => "on") if URI::HTTPS === uri
+ env["X-Requested-With"] = "XMLHttpRequest" if env[:xhr]
+
+ if (env[:method] == "POST" || env["REQUEST_METHOD"] == "POST") && !env.has_key?(:input)
+ env["CONTENT_TYPE"] = "application/x-www-form-urlencoded"
+
+ multipart = (Hash === env[:params]) &&
+ env[:params].any? { |_, v| UploadedFile === v }
+
+ if multipart
+ env[:input] = multipart_body(env.delete(:params))
+ env["CONTENT_LENGTH"] ||= env[:input].length.to_s
+ env["CONTENT_TYPE"] = "multipart/form-data; boundary=#{MULTIPART_BOUNDARY}"
+ else
+ env[:input] = params_to_string(env.delete(:params))
+ end
+ end
+
+ params = env[:params] || {}
+ params.update(parse_query(uri.query))
+
+ uri.query = requestify(params)
+
+ if env.has_key?(:cookie)
+ set_cookie(env.delete(:cookie), uri)
+ end
+
+ Rack::MockRequest.env_for(uri.to_s, env)
+ end
+
+ def process_request(uri, env)
+ uri = URI.parse(uri)
+ uri.host ||= @default_host
+
+ @rack_mock_session.request(uri, env)
+
+ if retry_with_digest_auth?(env)
+ auth_env = env.merge({
+ "HTTP_AUTHORIZATION" => digest_auth_header,
+ "rack-test.digest_auth_retry" => true
+ })
+ auth_env.delete('rack.request')
+ process_request(uri.path, auth_env)
+ else
+ yield last_response if block_given?
+
+ last_response
+ end
+ end
+
+ def digest_auth_header
+ challenge = last_response["WWW-Authenticate"].split(" ", 2).last
+ params = Rack::Auth::Digest::Params.parse(challenge)
+
+ params.merge!({
+ "username" => @digest_username,
+ "nc" => "00000001",
+ "cnonce" => "nonsensenonce",
+ "uri" => last_request.path_info,
+ "method" => last_request.env["REQUEST_METHOD"],
+ })
+
+ params["response"] = MockDigestRequest.new(params).response(@digest_password)
+
+ "Digest #{params}"
+ end
+
+ def retry_with_digest_auth?(env)
+ last_response.status == 401 &&
+ digest_auth_configured? &&
+ !env["rack-test.digest_auth_retry"]
+ end
+
+ def digest_auth_configured?
+ @digest_username
+ end
+
+ def default_env
+ { "rack.test" => true, "REMOTE_ADDR" => "127.0.0.1" }.merge(@headers)
+ end
+
+ def params_to_string(params)
+ case params
+ when Hash then requestify(params)
+ when nil then ""
+ else params
+ end
+ end
+
+ end
+
+ end
+end
diff --git a/actionpack/lib/action_dispatch/vendor/rack-test/rack/test/cookie_jar.rb b/actionpack/lib/action_dispatch/vendor/rack-test/rack/test/cookie_jar.rb
new file mode 100644
index 0000000000..d58c914c9b
--- /dev/null
+++ b/actionpack/lib/action_dispatch/vendor/rack-test/rack/test/cookie_jar.rb
@@ -0,0 +1,169 @@
+require "uri"
+module Rack
+ module Test
+
+ class Cookie
+ include Rack::Utils
+
+ # :api: private
+ attr_reader :name, :value
+
+ # :api: private
+ def initialize(raw, uri = nil, default_host = DEFAULT_HOST)
+ @default_host = default_host
+ uri ||= default_uri
+
+ # separate the name / value pair from the cookie options
+ @name_value_raw, options = raw.split(/[;,] */n, 2)
+
+ @name, @value = parse_query(@name_value_raw, ';').to_a.first
+ @options = parse_query(options, ';')
+
+ @options["domain"] ||= (uri.host || default_host)
+ @options["path"] ||= uri.path.sub(/\/[^\/]*\Z/, "")
+ end
+
+ def replaces?(other)
+ [name.downcase, domain, path] == [other.name.downcase, other.domain, other.path]
+ end
+
+ # :api: private
+ def raw
+ @name_value_raw
+ end
+
+ # :api: private
+ def empty?
+ @value.nil? || @value.empty?
+ end
+
+ # :api: private
+ def domain
+ @options["domain"]
+ end
+
+ def secure?
+ @options.has_key?("secure")
+ end
+
+ # :api: private
+ def path
+ @options["path"].strip || "/"
+ end
+
+ # :api: private
+ def expires
+ Time.parse(@options["expires"]) if @options["expires"]
+ end
+
+ # :api: private
+ def expired?
+ expires && expires < Time.now
+ end
+
+ # :api: private
+ def valid?(uri)
+ uri ||= default_uri
+
+ if uri.host.nil?
+ uri.host = @default_host
+ end
+
+ (!secure? || (secure? && uri.scheme == "https")) &&
+ uri.host =~ Regexp.new("#{Regexp.escape(domain)}$", Regexp::IGNORECASE) &&
+ uri.path =~ Regexp.new("^#{Regexp.escape(path)}")
+ end
+
+ # :api: private
+ def matches?(uri)
+ ! expired? && valid?(uri)
+ end
+
+ # :api: private
+ def <=>(other)
+ # Orders the cookies from least specific to most
+ [name, path, domain.reverse] <=> [other.name, other.path, other.domain.reverse]
+ end
+
+ protected
+
+ def default_uri
+ URI.parse("//" + @default_host + "/")
+ end
+
+ end
+
+ class CookieJar
+
+ # :api: private
+ def initialize(cookies = [], default_host = DEFAULT_HOST)
+ @default_host = default_host
+ @cookies = cookies
+ @cookies.sort!
+ end
+
+ def [](name)
+ cookies = hash_for(nil)
+ # TODO: Should be case insensitive
+ cookies[name] && cookies[name].value
+ end
+
+ def []=(name, value)
+ # TODO: needs proper escaping
+ merge("#{name}=#{value}")
+ end
+
+ def merge(raw_cookies, uri = nil)
+ return unless raw_cookies
+
+ raw_cookies.each_line do |raw_cookie|
+ cookie = Cookie.new(raw_cookie, uri, @default_host)
+ self << cookie if cookie.valid?(uri)
+ end
+ end
+
+ def <<(new_cookie)
+ @cookies.reject! do |existing_cookie|
+ new_cookie.replaces?(existing_cookie)
+ end
+
+ @cookies << new_cookie
+ @cookies.sort!
+ end
+
+ # :api: private
+ def for(uri)
+ hash_for(uri).values.map { |c| c.raw }.join(';')
+ end
+
+ def to_hash
+ cookies = {}
+
+ hash_for(nil).each do |name, cookie|
+ cookies[name] = cookie.value
+ end
+
+ return cookies
+ end
+
+ protected
+
+ def hash_for(uri = nil)
+ cookies = {}
+
+ # The cookies are sorted by most specific first. So, we loop through
+ # all the cookies in order and add it to a hash by cookie name if
+ # the cookie can be sent to the current URI. It's added to the hash
+ # so that when we are done, the cookies will be unique by name and
+ # we'll have grabbed the most specific to the URI.
+ @cookies.each do |cookie|
+ cookies[cookie.name] = cookie if cookie.matches?(uri)
+ end
+
+ return cookies
+ end
+
+ end
+
+ end
+end
diff --git a/actionpack/lib/action_dispatch/vendor/rack-test/rack/test/methods.rb b/actionpack/lib/action_dispatch/vendor/rack-test/rack/test/methods.rb
new file mode 100644
index 0000000000..a191fa23d8
--- /dev/null
+++ b/actionpack/lib/action_dispatch/vendor/rack-test/rack/test/methods.rb
@@ -0,0 +1,45 @@
+require "forwardable"
+
+module Rack
+ module Test
+ module Methods
+ extend Forwardable
+
+ def rack_test_session
+ @_rack_test_session ||= Rack::Test::Session.new(app)
+ end
+
+ def rack_mock_session
+ @_rack_mock_session ||= Rack::MockSession.new(app)
+ end
+
+ METHODS = [
+ :request,
+
+ # HTTP verbs
+ :get,
+ :post,
+ :put,
+ :delete,
+ :head,
+
+ # Redirects
+ :follow_redirect!,
+
+ # Header-related features
+ :header,
+ :set_cookie,
+ :clear_cookies,
+ :authorize,
+ :basic_authorize,
+ :digest_authorize,
+
+ # Expose the last request and response
+ :last_response,
+ :last_request
+ ]
+
+ def_delegators :rack_test_session, *METHODS
+ end
+ end
+end
diff --git a/actionpack/lib/action_dispatch/vendor/rack-test/rack/test/mock_digest_request.rb b/actionpack/lib/action_dispatch/vendor/rack-test/rack/test/mock_digest_request.rb
new file mode 100644
index 0000000000..81c398ba51
--- /dev/null
+++ b/actionpack/lib/action_dispatch/vendor/rack-test/rack/test/mock_digest_request.rb
@@ -0,0 +1,27 @@
+module Rack
+ module Test
+
+ class MockDigestRequest
+ def initialize(params)
+ @params = params
+ end
+
+ def method_missing(sym)
+ if @params.has_key? k = sym.to_s
+ return @params[k]
+ end
+
+ super
+ end
+
+ def method
+ @params['method']
+ end
+
+ def response(password)
+ Rack::Auth::Digest::MD5.new(nil).send :digest, self, password
+ end
+ end
+
+ end
+end
diff --git a/actionpack/lib/action_dispatch/vendor/rack-test/rack/test/uploaded_file.rb b/actionpack/lib/action_dispatch/vendor/rack-test/rack/test/uploaded_file.rb
new file mode 100644
index 0000000000..239302fbe4
--- /dev/null
+++ b/actionpack/lib/action_dispatch/vendor/rack-test/rack/test/uploaded_file.rb
@@ -0,0 +1,36 @@
+require "tempfile"
+
+module Rack
+ module Test
+
+ class UploadedFile
+ # The filename, *not* including the path, of the "uploaded" file
+ attr_reader :original_filename
+
+ # The content type of the "uploaded" file
+ attr_accessor :content_type
+
+ def initialize(path, content_type = "text/plain", binary = false)
+ raise "#{path} file does not exist" unless ::File.exist?(path)
+ @content_type = content_type
+ @original_filename = ::File.basename(path)
+ @tempfile = Tempfile.new(@original_filename)
+ @tempfile.set_encoding(Encoding::BINARY) if @tempfile.respond_to?(:set_encoding)
+ @tempfile.binmode if binary
+ FileUtils.copy_file(path, @tempfile.path)
+ end
+
+ def path
+ @tempfile.path
+ end
+
+ alias_method :local_path, :path
+
+ def method_missing(method_name, *args, &block) #:nodoc:
+ @tempfile.__send__(method_name, *args, &block)
+ end
+
+ end
+
+ end
+end
diff --git a/actionpack/lib/action_dispatch/vendor/rack-test/rack/test/utils.rb b/actionpack/lib/action_dispatch/vendor/rack-test/rack/test/utils.rb
new file mode 100644
index 0000000000..d25b849709
--- /dev/null
+++ b/actionpack/lib/action_dispatch/vendor/rack-test/rack/test/utils.rb
@@ -0,0 +1,75 @@
+module Rack
+ module Test
+
+ module Utils
+ include Rack::Utils
+
+ def requestify(value, prefix = nil)
+ case value
+ when Array
+ value.map do |v|
+ requestify(v, "#{prefix}[]")
+ end.join("&")
+ when Hash
+ value.map do |k, v|
+ requestify(v, prefix ? "#{prefix}[#{escape(k)}]" : escape(k))
+ end.join("&")
+ else
+ "#{prefix}=#{escape(value)}"
+ end
+ end
+
+ module_function :requestify
+
+ def multipart_requestify(params, first=true)
+ p = Hash.new
+
+ params.each do |key, value|
+ k = first ? key.to_s : "[#{key}]"
+
+ if Hash === value
+ multipart_requestify(value, false).each do |subkey, subvalue|
+ p[k + subkey] = subvalue
+ end
+ else
+ p[k] = value
+ end
+ end
+
+ return p
+ end
+
+ module_function :multipart_requestify
+
+ def multipart_body(params)
+ multipart_requestify(params).map do |key, value|
+ if value.respond_to?(:original_filename)
+ ::File.open(value.path, "rb") do |f|
+ f.set_encoding(Encoding::BINARY) if f.respond_to?(:set_encoding)
+
+ <<-EOF
+--#{MULTIPART_BOUNDARY}\r
+Content-Disposition: form-data; name="#{key}"; filename="#{escape(value.original_filename)}"\r
+Content-Type: #{value.content_type}\r
+Content-Length: #{::File.stat(value.path).size}\r
+\r
+#{f.read}\r
+EOF
+ end
+ else
+<<-EOF
+--#{MULTIPART_BOUNDARY}\r
+Content-Disposition: form-data; name="#{key}"\r
+\r
+#{value}\r
+EOF
+ end
+ end.join("")+"--#{MULTIPART_BOUNDARY}--\r"
+ end
+
+ module_function :multipart_body
+
+ end
+
+ end
+end