From a705709f9ad0ea5f3cdcd2a5f60580e0d3b20bc5 Mon Sep 17 00:00:00 2001 From: Jacques Distler Date: Sat, 26 Dec 2009 14:00:18 -0600 Subject: [PATCH] Vendor Rack 1.1 Also clean up some View stuff. --- app/views/admin/edit_web.rhtml | 2 +- app/views/file/import.rhtml | 2 +- app/views/wiki/rollback.rhtml | 2 - public/stylesheets/instiki.css | 7 - vendor/plugins/rack/KNOWN-ISSUES | 3 + vendor/plugins/rack/README | 83 +- vendor/plugins/rack/Rakefile | 76 +- vendor/plugins/rack/bin/rackup | 178 +--- vendor/plugins/rack/lib/rack.rb | 16 +- vendor/plugins/rack/lib/rack/builder.rb | 17 + vendor/plugins/rack/lib/rack/cascade.rb | 29 +- vendor/plugins/rack/lib/rack/chunked.rb | 4 +- vendor/plugins/rack/lib/rack/commonlogger.rb | 74 +- vendor/plugins/rack/lib/rack/config.rb | 15 + vendor/plugins/rack/lib/rack/content_type.rb | 2 +- vendor/plugins/rack/lib/rack/directory.rb | 8 +- vendor/plugins/rack/lib/rack/etag.rb | 23 + vendor/plugins/rack/lib/rack/file.rb | 6 +- vendor/plugins/rack/lib/rack/handler.rb | 19 + vendor/plugins/rack/lib/rack/handler/cgi.rb | 2 +- .../plugins/rack/lib/rack/handler/fastcgi.rb | 5 +- vendor/plugins/rack/lib/rack/handler/lsws.rb | 5 +- .../plugins/rack/lib/rack/handler/mongrel.rb | 13 +- vendor/plugins/rack/lib/rack/handler/scgi.rb | 8 +- .../plugins/rack/lib/rack/handler/webrick.rb | 6 +- vendor/plugins/rack/lib/rack/lint.rb | 59 +- vendor/plugins/rack/lib/rack/logger.rb | 20 + vendor/plugins/rack/lib/rack/mime.rb | 4 +- vendor/plugins/rack/lib/rack/mock.rb | 34 +- vendor/plugins/rack/lib/rack/nulllogger.rb | 18 + vendor/plugins/rack/lib/rack/reloader.rb | 5 +- vendor/plugins/rack/lib/rack/request.rb | 55 +- vendor/plugins/rack/lib/rack/response.rb | 44 +- .../plugins/rack/lib/rack/rewindable_input.rb | 20 +- vendor/plugins/rack/lib/rack/runtime.rb | 27 + vendor/plugins/rack/lib/rack/sendfile.rb | 142 +++ vendor/plugins/rack/lib/rack/server.rb | 212 +++++ .../rack/lib/rack/session/abstract/id.rb | 8 +- .../plugins/rack/lib/rack/session/cookie.rb | 7 +- .../plugins/rack/lib/rack/session/memcache.rb | 96 ++- vendor/plugins/rack/lib/rack/session/pool.rb | 2 +- vendor/plugins/rack/lib/rack/urlmap.rb | 17 +- vendor/plugins/rack/lib/rack/utils.rb | 241 +++++- vendor/plugins/rack/rack.gemspec | 38 + vendor/plugins/rack/test/cgi/test.ru | 3 +- vendor/plugins/rack/test/multipart/bad_robots | 259 ++++++ .../rack/test/multipart/fail_16384_nofile | 814 ++++++++++++++++++ vendor/plugins/rack/test/multipart/file1.txt | 1 + vendor/plugins/rack/test/rackup/.gitignore | 1 + vendor/plugins/rack/test/rackup/config.ru | 31 + vendor/plugins/rack/test/spec_rack_cascade.rb | 8 +- vendor/plugins/rack/test/spec_rack_cgi.rb | 6 +- .../rack/test/spec_rack_commonlogger.rb | 49 +- vendor/plugins/rack/test/spec_rack_config.rb | 24 + .../plugins/rack/test/spec_rack_directory.rb | 2 +- vendor/plugins/rack/test/spec_rack_etag.rb | 17 + vendor/plugins/rack/test/spec_rack_fastcgi.rb | 4 +- vendor/plugins/rack/test/spec_rack_file.rb | 2 +- vendor/plugins/rack/test/spec_rack_lint.rb | 45 +- vendor/plugins/rack/test/spec_rack_logger.rb | 21 + vendor/plugins/rack/test/spec_rack_mock.rb | 88 +- vendor/plugins/rack/test/spec_rack_mongrel.rb | 8 +- .../plugins/rack/test/spec_rack_nulllogger.rb | 13 + vendor/plugins/rack/test/spec_rack_request.rb | 53 +- .../plugins/rack/test/spec_rack_response.rb | 3 + vendor/plugins/rack/test/spec_rack_runtime.rb | 35 + .../plugins/rack/test/spec_rack_sendfile.rb | 86 ++ .../rack/test/spec_rack_session_memcache.rb | 73 +- vendor/plugins/rack/test/spec_rack_urlmap.rb | 30 + vendor/plugins/rack/test/spec_rack_utils.rb | 177 +++- vendor/plugins/rack/test/spec_rack_webrick.rb | 8 +- vendor/plugins/rack/test/spec_rackup.rb | 154 ++++ vendor/plugins/rack/test/testrequest.rb | 17 +- .../rails/actionpack/lib/action_controller.rb | 2 +- 74 files changed, 3080 insertions(+), 608 deletions(-) create mode 100644 vendor/plugins/rack/lib/rack/config.rb create mode 100644 vendor/plugins/rack/lib/rack/etag.rb create mode 100644 vendor/plugins/rack/lib/rack/logger.rb create mode 100644 vendor/plugins/rack/lib/rack/nulllogger.rb create mode 100644 vendor/plugins/rack/lib/rack/runtime.rb create mode 100644 vendor/plugins/rack/lib/rack/sendfile.rb create mode 100644 vendor/plugins/rack/lib/rack/server.rb create mode 100644 vendor/plugins/rack/rack.gemspec create mode 100644 vendor/plugins/rack/test/multipart/bad_robots create mode 100644 vendor/plugins/rack/test/multipart/fail_16384_nofile create mode 100644 vendor/plugins/rack/test/multipart/file1.txt create mode 100644 vendor/plugins/rack/test/rackup/.gitignore create mode 100644 vendor/plugins/rack/test/rackup/config.ru create mode 100644 vendor/plugins/rack/test/spec_rack_config.rb create mode 100644 vendor/plugins/rack/test/spec_rack_etag.rb create mode 100644 vendor/plugins/rack/test/spec_rack_logger.rb create mode 100644 vendor/plugins/rack/test/spec_rack_nulllogger.rb create mode 100644 vendor/plugins/rack/test/spec_rack_runtime.rb create mode 100644 vendor/plugins/rack/test/spec_rack_sendfile.rb create mode 100644 vendor/plugins/rack/test/spec_rackup.rb diff --git a/app/views/admin/edit_web.rhtml b/app/views/admin/edit_web.rhtml index 83ca3ee2..0cd2acb6 100644 --- a/app/views/admin/edit_web.rhtml +++ b/app/views/admin/edit_web.rhtml @@ -18,7 +18,7 @@ onchange="proposeAddress();" />    - (Letters and digits only) + (Letters and digits only)

Specialize

diff --git a/app/views/file/import.rhtml b/app/views/file/import.rhtml index 413c4c84..7e3a3e6f 100644 --- a/app/views/file/import.rhtml +++ b/app/views/file/import.rhtml @@ -15,7 +15,7 @@ <%- if @page -%> - | <%= link_to 'Cancel', :web => @web.address, :action => 'file'%> (unlocks page) + | <%= link_to 'Cancel', :web => @web.address, :action => 'file'%> (unlocks page) <%- end -%>

diff --git a/app/views/wiki/rollback.rhtml b/app/views/wiki/rollback.rhtml index 0f4b5bad..7d3a14aa 100644 --- a/app/views/wiki/rollback.rhtml +++ b/app/views/wiki/rollback.rhtml @@ -4,8 +4,6 @@ @hide_navigation = true -%> -<%= "

Please correct the error that caused this error in rendering:
#{params["msg"]}

" if params["msg"] %> -
<%= render(:file => "#{@web.markup}_help") -%> <%= render(:file => 'wiki_words_help') unless @web.brackets_only? -%> diff --git a/public/stylesheets/instiki.css b/public/stylesheets/instiki.css index cf6c4902..ade66ed8 100644 --- a/public/stylesheets/instiki.css +++ b/public/stylesheets/instiki.css @@ -61,13 +61,6 @@ margin:0.2em 0 0.2em 0; padding:0; } -h1#pageName small { -color:#444; -font-size:35%; -line-height:1em; -padding:0; -} - #svg_logo { float:left; margin:.5em .25em 0 -.625em; diff --git a/vendor/plugins/rack/KNOWN-ISSUES b/vendor/plugins/rack/KNOWN-ISSUES index 790199bd..a1af5dc1 100644 --- a/vendor/plugins/rack/KNOWN-ISSUES +++ b/vendor/plugins/rack/KNOWN-ISSUES @@ -16,3 +16,6 @@ end Of course, use this only when your app runs at "/". + + Since lighttpd 1.4.23, you also can use the "fix-root-scriptname" flag + in fastcgi.server. diff --git a/vendor/plugins/rack/README b/vendor/plugins/rack/README index c58009ff..70d3673a 100644 --- a/vendor/plugins/rack/README +++ b/vendor/plugins/rack/README @@ -11,21 +11,13 @@ which all Rack applications should conform to. == Specification changes in this release -With Rack 1.0, the Rack specification (found in SPEC) changed in the -following backward-incompatible ways. This was done to properly -support Ruby 1.9 and to deprecate some problematic techniques: +With Rack 1.1, the Rack specification (found in SPEC) changed in the +following backward-incompatible ways. -* Rack::VERSION has been pushed to [1,0]. -* Header values must be Strings now, split on "\n". -* rack.input must be rewindable and support reading into a buffer, - wrap with Rack::RewindableInput if it isn't. -* Content-Length can be missing, in this case chunked transfer - encoding is used. -* Bodies can now additionally respond to #to_path with a filename to - be served. -* String bodies are deprecated and will not work with Ruby 1.9, use an - Array with a single String instead. -* rack.session is now specified. +* Rack::VERSION has been pushed to [1,1]. +* rack.logger is now specified. +* The SPEC now allows subclasses of the required types. +* rack.input has to be opened in binary mode. == Supported web servers @@ -43,8 +35,11 @@ The included *handlers* connect all kinds of web servers to Rack: These web servers include Rack handlers in their distributions: * Ebb * Fuzed +* Glassfish v3 * Phusion Passenger (which is mod_rack for Apache and for nginx) +* Rainbows! * Unicorn +* Zbatery Any valid Rack app will run the same on all these handlers, without changing anything. @@ -70,6 +65,7 @@ These frameworks include Rack adapters in their distributions: * Vintage * Waves * Wee +* ... and many others. Current links to these projects can be found at http://wiki.ramaze.net/Home#other-frameworks @@ -130,13 +126,13 @@ Either with the embedded WEBrick starter: Or with rackup: - bin/rackup -Ilib example/lobster.ru + bin/rackup -Ilib example/lobster.ru By default, the lobster is found at http://localhost:9292. == Installing with RubyGems -A Gem of Rack is available. You can install it with: +A Gem of Rack is available at gemcutter.org. You can install it with: gem install rack @@ -165,7 +161,6 @@ To run the test suite completely, you need: * fcgi * memcache-client * mongrel - * ruby-openid * thin The full set of tests test FCGI access with lighttpd (on port @@ -283,16 +278,49 @@ run on port 11211) and memcache-client installed. * Make sure WEBrick respects the :Host option * Many Ruby 1.9 fixes. +* December ??th, 2009: Ninth public release 1.1.0. + * Moved Auth::OpenID to rack-contrib. + * SPEC change that relaxes Lint slightly to allow subclasses of the + required types + * SPEC change to document rack.input binary mode in greator detail + * SPEC define optional rack.logger specification + * File servers support X-Cascade header + * Imported Config middleware + * Imported ETag middleware + * Imported Runtime middleware + * Imported Sendfile middleware + * New Logger and NullLogger middlewares + * Added mime type for .ogv and .manifest. + * Don't squeeze PATH_INFO slashes + * Use Content-Type to determine POST params parsing + * Update Rack::Utils::HTTP_STATUS_CODES hash + * Add status code lookup utility + * Response should call #to_i on the status + * Add Request#user_agent + * Request#host knows about forwared host + * Return an empty string for Request#host if HTTP_HOST and + SERVER_NAME are both missing + * Allow MockRequest to accept hash params + * Optimizations to HeaderHash + * Refactored rackup into Rack::Server + * Added Utils.build_nested_query to complement Utils.parse_nested_query + * Added Utils::Multipart.build_multipart to complement + Utils::Multipart.parse_multipart + * Extracted set and delete cookie helpers into Utils so they can be + used outside Response + * Extract parse_query and parse_multipart in Request so subclasses + can change their behavior + * Enforce binary encoding in RewindableInput + * Set correct external_encoding for handlers that don't use RewindableInput + == Contact -Please mail bugs, suggestions and patches to -. +Please post bugs, suggestions and patches to +the bug tracker at . Mailing list archives are available at . -There is a bug tracker at . - Git repository (send Git patches to the mailing list): * http://github.com/rack/rack * http://git.vuxu.org/cgi-bin/gitweb.cgi?p=rack.git @@ -318,8 +346,14 @@ would like to thank: * Luc Heinrich for the Cookie sessions, the static file handler and bugfixes. * Armin Ronacher, for the logo and racktools. * Aredridel, Ben Alpert, Dan Kubb, Daniel Roethlisberger, Matt Todd, - Tom Robinson, Phil Hagelberg, and S. Brent Faulkner for bug fixing - and other improvements. + Tom Robinson, Phil Hagelberg, S. Brent Faulkner, Bosko Milekic, + Daniel Rodríguez Troitiño, Genki Takiuchi, Geoffrey Grosenbach, + Julien Sanchez, Kamal Fariz Mahyuddin, Masayoshi Takahashi, Patrick + Aljordm, Mig, and Kazuhiro Nishiyama for bug fixing and other + improvements. +* Eric Wong, Hongli Lai, Jeremy Kemper for their continuous support + and API improvements. +* Yehuda Katz and Carl Lerche for refactoring rackup. * Brian Candler, for Rack::ContentType. * Graham Batty, for improved handler loading. * Stephen Bannasch, for bug reports and documentation. @@ -349,7 +383,7 @@ 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 BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +THE AUTHORS 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. @@ -358,6 +392,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. Rack:: Rack's Rubyforge project:: Official Rack repositories:: +Rack Lighthouse Bug Tracking:: rack-devel mailing list:: Christian Neukirchen:: diff --git a/vendor/plugins/rack/Rakefile b/vendor/plugins/rack/Rakefile index c88f7aff..e22f060a 100644 --- a/vendor/plugins/rack/Rakefile +++ b/vendor/plugins/rack/Rakefile @@ -6,9 +6,8 @@ require 'rake/testtask' desc "Run all the tests" task :default => [:test] - desc "Make an archive as .tar.gz" -task :dist => [:chmod, :changelog, :rdoc, "SPEC", "rack.gemspec"] do +task :dist => [:chmod, :changelog, :rdoc, "SPEC"] do FileUtils.touch("RDOX") sh "git archive --format=tar --prefix=#{release}/ HEAD^{tree} >#{release}.tar" sh "pax -waf #{release}.tar -s ':^:#{release}/:' RDOX SPEC ChangeLog doc rack.gemspec" @@ -28,21 +27,11 @@ task :officialrelease_really => [:fulltest, "RDOX", "SPEC", :dist, :gem] do sh "sha1sum #{release}.tar.gz #{release}.gem" end - -def version - abort "You need to pass VERSION=... to build packages." unless ENV["VERSION"] - ENV["VERSION"] -end - def release - "rack-#{version}" + require File.dirname(__FILE__) + "/lib/rack" + "rack-#{Rack.release}" end -def manifest - `git ls-files`.split("\n") -end - - desc "Make binaries executable" task :chmod do Dir["bin/*"].each { |binary| File.chmod(0775, binary) } @@ -86,7 +75,7 @@ end desc "Run all the fast tests" task :test do - sh "specrb -Ilib:test -w #{ENV['TEST'] || '-a'} #{ENV['TESTOPTS'] || '-t "^(?!Rack::Handler|Rack::Adapter|Rack::Session::Memcache|Rack::Auth::OpenID)"'}" + sh "specrb -Ilib:test -w #{ENV['TEST'] || '-a'} #{ENV['TESTOPTS'] || '-t "^(?!Rack::Handler|Rack::Adapter|Rack::Session::Memcache|rackup)"'}" end desc "Run all the tests" @@ -94,63 +83,14 @@ task :fulltest => [:chmod] do sh "specrb -Ilib:test -w #{ENV['TEST'] || '-a'} #{ENV['TESTOPTS']}" end -begin - require 'rubygems' -rescue LoadError - # Too bad. -else - task "rack.gemspec" do - spec = Gem::Specification.new do |s| - s.name = "rack" - s.version = version - s.platform = Gem::Platform::RUBY - s.summary = "a modular Ruby webserver interface" - - s.description = <<-EOF -Rack provides minimal, modular and adaptable interface for developing -web applications in Ruby. By wrapping HTTP requests and responses in -the simplest way possible, it unifies and distills the API for web -servers, web frameworks, and software in between (the so-called -middleware) into a single method call. - -Also see http://rack.rubyforge.org. - EOF - - s.files = manifest + %w(SPEC RDOX rack.gemspec) - s.bindir = 'bin' - s.executables << 'rackup' - s.require_path = 'lib' - s.has_rdoc = true - s.extra_rdoc_files = ['README', 'SPEC', 'RDOX', 'KNOWN-ISSUES'] - s.test_files = Dir['test/{test,spec}_*.rb'] - - s.author = 'Christian Neukirchen' - s.email = 'chneukirchen@gmail.com' - s.homepage = 'http://rack.rubyforge.org' - s.rubyforge_project = 'rack' - - s.add_development_dependency 'test-spec' - - s.add_development_dependency 'camping' - s.add_development_dependency 'fcgi' - s.add_development_dependency 'memcache-client' - s.add_development_dependency 'mongrel' - s.add_development_dependency 'ruby-openid', '~> 2.0.0' - s.add_development_dependency 'thin' - end - - File.open("rack.gemspec", "w") { |f| f << spec.to_ruby } - end - - task :gem => ["rack.gemspec", "SPEC"] do - FileUtils.touch("RDOX") - sh "gem build rack.gemspec" - end +task :gem => ["SPEC"] do + FileUtils.touch("RDOX") + sh "gem build rack.gemspec" end desc "Generate RDoc documentation" task :rdoc do - sh(*%w{rdoc --line-numbers --main README + sh(*%w{rdoc --line-numbers --main README --title 'Rack\ Documentation' --charset utf-8 -U -o doc} + %w{README KNOWN-ISSUES SPEC RDOX} + Dir["lib/**/*.rb"]) diff --git a/vendor/plugins/rack/bin/rackup b/vendor/plugins/rack/bin/rackup index 8e4df15e..a6f98913 100755 --- a/vendor/plugins/rack/bin/rackup +++ b/vendor/plugins/rack/bin/rackup @@ -1,176 +1,2 @@ -#!/usr/bin/env ruby -# -*- ruby -*- - -$LOAD_PATH.unshift File.expand_path("#{__FILE__}/../../lib") -autoload :Rack, 'rack' - -require 'optparse' - -automatic = false -server = nil -env = "development" -daemonize = false -pid = nil -options = {:Port => 9292, :Host => "0.0.0.0", :AccessLog => []} - -# Don't evaluate CGI ISINDEX parameters. -# http://hoohoo.ncsa.uiuc.edu/cgi/cl.html -ARGV.clear if ENV.include?("REQUEST_METHOD") - -opts = OptionParser.new("", 24, ' ') { |opts| - opts.banner = "Usage: rackup [ruby options] [rack options] [rackup config]" - - opts.separator "" - opts.separator "Ruby options:" - - lineno = 1 - opts.on("-e", "--eval LINE", "evaluate a LINE of code") { |line| - eval line, TOPLEVEL_BINDING, "-e", lineno - lineno += 1 - } - - opts.on("-d", "--debug", "set debugging flags (set $DEBUG to true)") { - $DEBUG = true - } - opts.on("-w", "--warn", "turn warnings on for your script") { - $-w = true - } - - opts.on("-I", "--include PATH", - "specify $LOAD_PATH (may be used more than once)") { |path| - $LOAD_PATH.unshift(*path.split(":")) - } - - opts.on("-r", "--require LIBRARY", - "require the library, before executing your script") { |library| - require library - } - - opts.separator "" - opts.separator "Rack options:" - opts.on("-s", "--server SERVER", "serve using SERVER (webrick/mongrel)") { |s| - server = s - } - - opts.on("-o", "--host HOST", "listen on HOST (default: 0.0.0.0)") { |host| - options[:Host] = host - } - - opts.on("-p", "--port PORT", "use PORT (default: 9292)") { |port| - options[:Port] = port - } - - opts.on("-E", "--env ENVIRONMENT", "use ENVIRONMENT for defaults (default: development)") { |e| - env = e - } - - opts.on("-D", "--daemonize", "run daemonized in the background") { |d| - daemonize = d ? true : false - } - - opts.on("-P", "--pid FILE", "file to store PID (default: rack.pid)") { |f| - pid = File.expand_path(f) - } - - opts.separator "" - opts.separator "Common options:" - - opts.on_tail("-h", "--help", "Show this message") do - puts opts - exit - end - - opts.on_tail("--version", "Show version") do - puts "Rack #{Rack.version}" - exit - end - - opts.parse! ARGV -} - -require 'pp' if $DEBUG - -config = ARGV[0] || "config.ru" -if !File.exist? config - abort "configuration #{config} not found" -end - -if config =~ /\.ru$/ - cfgfile = File.read(config) - if cfgfile[/^#\\(.*)/] - opts.parse! $1.split(/\s+/) - end - inner_app = eval "Rack::Builder.new {( " + cfgfile + "\n )}.to_app", - nil, config -else - require config - inner_app = Object.const_get(File.basename(config, '.rb').capitalize) -end - -unless server = Rack::Handler.get(server) - # Guess. - if ENV.include?("PHP_FCGI_CHILDREN") - server = Rack::Handler::FastCGI - - # We already speak FastCGI - options.delete :File - options.delete :Port - elsif ENV.include?("REQUEST_METHOD") - server = Rack::Handler::CGI - else - begin - server = Rack::Handler::Mongrel - rescue LoadError => e - server = Rack::Handler::WEBrick - end - end -end - -p server if $DEBUG - -case env -when "development" - app = Rack::Builder.new { - use Rack::CommonLogger, $stderr unless server.name =~ /CGI/ - use Rack::ShowExceptions - use Rack::Lint - run inner_app - }.to_app - -when "deployment" - app = Rack::Builder.new { - use Rack::CommonLogger, $stderr unless server.name =~ /CGI/ - run inner_app - }.to_app - -when "none" - app = inner_app - -end - -if $DEBUG - pp app - pp inner_app -end - -if daemonize - if RUBY_VERSION < "1.9" - exit if fork - Process.setsid - exit if fork - Dir.chdir "/" - File.umask 0000 - STDIN.reopen "/dev/null" - STDOUT.reopen "/dev/null", "a" - STDERR.reopen "/dev/null", "a" - else - Process.daemon - end - - if pid - File.open(pid, 'w'){ |f| f.write("#{Process.pid}") } - at_exit { File.delete(pid) if File.exist?(pid) } - end -end - -server.run app, options +require "rack" +Rack::Server.start diff --git a/vendor/plugins/rack/lib/rack.rb b/vendor/plugins/rack/lib/rack.rb index 371d0156..ecc238ee 100644 --- a/vendor/plugins/rack/lib/rack.rb +++ b/vendor/plugins/rack/lib/rack.rb @@ -3,10 +3,6 @@ # Rack is freely distributable under the terms of an MIT-style license. # See COPYING or http://www.opensource.org/licenses/mit-license.php. -path = File.expand_path(File.dirname(__FILE__)) -$:.unshift(path) unless $:.include?(path) - - # The Rack main module, serving as a namespace for all core Rack # modules and classes. # @@ -15,7 +11,7 @@ $:.unshift(path) unless $:.include?(path) module Rack # The Rack protocol version number implemented. - VERSION = [1,0] + VERSION = [1,1] # Return the Rack protocol version as a dotted string. def self.version @@ -24,7 +20,7 @@ module Rack # Return the Rack release as a dotted string. def self.release - "1.0" + "1.1" end autoload :Builder, "rack/builder" @@ -32,8 +28,10 @@ module Rack autoload :Chunked, "rack/chunked" autoload :CommonLogger, "rack/commonlogger" autoload :ConditionalGet, "rack/conditionalget" + autoload :Config, "rack/config" autoload :ContentLength, "rack/content_length" autoload :ContentType, "rack/content_type" + autoload :ETag, "rack/etag" autoload :File, "rack/file" autoload :Deflater, "rack/deflater" autoload :Directory, "rack/directory" @@ -42,10 +40,15 @@ module Rack autoload :Head, "rack/head" autoload :Lint, "rack/lint" autoload :Lock, "rack/lock" + autoload :Logger, "rack/logger" autoload :MethodOverride, "rack/methodoverride" autoload :Mime, "rack/mime" + autoload :NullLogger, "rack/nulllogger" autoload :Recursive, "rack/recursive" autoload :Reloader, "rack/reloader" + autoload :Runtime, "rack/runtime" + autoload :Sendfile, "rack/sendfile" + autoload :Server, "rack/server" autoload :ShowExceptions, "rack/showexceptions" autoload :ShowStatus, "rack/showstatus" autoload :Static, "rack/static" @@ -62,7 +65,6 @@ module Rack autoload :Basic, "rack/auth/basic" autoload :AbstractRequest, "rack/auth/abstract/request" autoload :AbstractHandler, "rack/auth/abstract/handler" - autoload :OpenID, "rack/auth/openid" module Digest autoload :MD5, "rack/auth/digest/md5" autoload :Nonce, "rack/auth/digest/nonce" diff --git a/vendor/plugins/rack/lib/rack/builder.rb b/vendor/plugins/rack/lib/rack/builder.rb index 295235e5..530f0aaf 100644 --- a/vendor/plugins/rack/lib/rack/builder.rb +++ b/vendor/plugins/rack/lib/rack/builder.rb @@ -24,6 +24,23 @@ module Rack # You can use +map+ to construct a Rack::URLMap in a convenient way. class Builder + def self.parse_file(config, opts = Server::Options.new) + options = {} + if config =~ /\.ru$/ + cfgfile = ::File.read(config) + if cfgfile[/^#\\(.*)/] && opts + options = opts.parse! $1.split(/\s+/) + end + cfgfile.sub!(/^__END__\n.*/, '') + app = eval "Rack::Builder.new {( " + cfgfile + "\n )}.to_app", + TOPLEVEL_BINDING, config + else + require config + app = Object.const_get(::File.basename(config, '.rb').capitalize) + end + return app, options + end + def initialize(&block) @ins = [] instance_eval(&block) if block_given? diff --git a/vendor/plugins/rack/lib/rack/cascade.rb b/vendor/plugins/rack/lib/rack/cascade.rb index a038aa11..14c3e54d 100644 --- a/vendor/plugins/rack/lib/rack/cascade.rb +++ b/vendor/plugins/rack/lib/rack/cascade.rb @@ -4,31 +4,36 @@ module Rack # status codes). class Cascade + NotFound = [404, {}, []] + attr_reader :apps def initialize(apps, catch=404) - @apps = apps - @catch = [*catch] + @apps = []; @has_app = {} + apps.each { |app| add app } + + @catch = {} + [*catch].each { |status| @catch[status] = true } end def call(env) - status = headers = body = nil - raise ArgumentError, "empty cascade" if @apps.empty? - @apps.each { |app| - begin - status, headers, body = app.call(env) - break unless @catch.include?(status.to_i) - end - } - [status, headers, body] + result = NotFound + + @apps.each do |app| + result = app.call(env) + break unless @catch.include?(result[0].to_i) + end + + result end def add app + @has_app[app] = true @apps << app end def include? app - @apps.include? app + @has_app.include? app end alias_method :<<, :add diff --git a/vendor/plugins/rack/lib/rack/chunked.rb b/vendor/plugins/rack/lib/rack/chunked.rb index 280d89dd..dddf9694 100644 --- a/vendor/plugins/rack/lib/rack/chunked.rb +++ b/vendor/plugins/rack/lib/rack/chunked.rb @@ -19,7 +19,7 @@ module Rack STATUS_WITH_NO_ENTITY_BODY.include?(status) || headers['Content-Length'] || headers['Transfer-Encoding'] - [status, headers.to_hash, body] + [status, headers, body] else dup.chunk(status, headers, body) end @@ -29,7 +29,7 @@ module Rack @body = body headers.delete('Content-Length') headers['Transfer-Encoding'] = 'chunked' - [status, headers.to_hash, self] + [status, headers, self] end def each diff --git a/vendor/plugins/rack/lib/rack/commonlogger.rb b/vendor/plugins/rack/lib/rack/commonlogger.rb index 5e68ac62..1edc9b83 100644 --- a/vendor/plugins/rack/lib/rack/commonlogger.rb +++ b/vendor/plugins/rack/lib/rack/commonlogger.rb @@ -2,60 +2,48 @@ module Rack # Rack::CommonLogger forwards every request to an +app+ given, and # logs a line in the Apache common log format to the +logger+, or # rack.errors by default. - class CommonLogger + # Common Log Format: http://httpd.apache.org/docs/1.3/logs.html#common + # lilith.local - - [07/Aug/2006 23:58:02] "GET / HTTP/1.1" 500 - + # %{%s - %s [%s] "%s %s%s %s" %d %s\n} % + FORMAT = %{%s - %s [%s] "%s %s%s %s" %d %s %0.4f\n} + def initialize(app, logger=nil) @app = app @logger = logger end def call(env) - dup._call(env) + began_at = Time.now + status, header, body = @app.call(env) + header = Utils::HeaderHash.new(header) + log(env, status, header, began_at) + [status, header, body] end - def _call(env) - @env = env - @logger ||= self - @time = Time.now - @status, @header, @body = @app.call(env) - [@status, @header, self] + private + + def log(env, status, header, began_at) + now = Time.now + length = extract_content_length(header) + + logger = @logger || env['rack.errors'] + logger.write FORMAT % [ + env['HTTP_X_FORWARDED_FOR'] || env["REMOTE_ADDR"] || "-", + env["REMOTE_USER"] || "-", + now.strftime("%d/%b/%Y %H:%M:%S"), + env["REQUEST_METHOD"], + env["PATH_INFO"], + env["QUERY_STRING"].empty? ? "" : "?"+env["QUERY_STRING"], + env["HTTP_VERSION"], + status.to_s[0..3], + length, + now - began_at ] end - def close - @body.close if @body.respond_to? :close - end - - # By default, log to rack.errors. - def <<(str) - @env["rack.errors"].write(str) - @env["rack.errors"].flush - end - - def each - length = 0 - @body.each { |part| - length += part.size - yield part - } - - @now = Time.now - - # Common Log Format: http://httpd.apache.org/docs/1.3/logs.html#common - # lilith.local - - [07/Aug/2006 23:58:02] "GET / HTTP/1.1" 500 - - # %{%s - %s [%s] "%s %s%s %s" %d %s\n} % - @logger << %{%s - %s [%s] "%s %s%s %s" %d %s %0.4f\n} % - [ - @env['HTTP_X_FORWARDED_FOR'] || @env["REMOTE_ADDR"] || "-", - @env["REMOTE_USER"] || "-", - @now.strftime("%d/%b/%Y %H:%M:%S"), - @env["REQUEST_METHOD"], - @env["PATH_INFO"], - @env["QUERY_STRING"].empty? ? "" : "?"+@env["QUERY_STRING"], - @env["HTTP_VERSION"], - @status.to_s[0..3], - (length.zero? ? "-" : length.to_s), - @now - @time - ] + def extract_content_length(headers) + value = headers['Content-Length'] or return '-' + value.to_s == '0' ? '-' : value end end end diff --git a/vendor/plugins/rack/lib/rack/config.rb b/vendor/plugins/rack/lib/rack/config.rb new file mode 100644 index 00000000..c6d446c0 --- /dev/null +++ b/vendor/plugins/rack/lib/rack/config.rb @@ -0,0 +1,15 @@ +module Rack + # Rack::Config modifies the environment using the block given during + # initialization. + class Config + def initialize(app, &block) + @app = app + @block = block + end + + def call(env) + @block.call(env) + @app.call(env) + end + end +end diff --git a/vendor/plugins/rack/lib/rack/content_type.rb b/vendor/plugins/rack/lib/rack/content_type.rb index 0c1e1ca3..874c28cd 100644 --- a/vendor/plugins/rack/lib/rack/content_type.rb +++ b/vendor/plugins/rack/lib/rack/content_type.rb @@ -17,7 +17,7 @@ module Rack status, headers, body = @app.call(env) headers = Utils::HeaderHash.new(headers) headers['Content-Type'] ||= @content_type - [status, headers.to_hash, body] + [status, headers, body] end end end diff --git a/vendor/plugins/rack/lib/rack/directory.rb b/vendor/plugins/rack/lib/rack/directory.rb index acdd3029..927ac0c9 100644 --- a/vendor/plugins/rack/lib/rack/directory.rb +++ b/vendor/plugins/rack/lib/rack/directory.rb @@ -71,7 +71,9 @@ table { width:100%%; } body = "Forbidden\n" size = Rack::Utils.bytesize(body) - return [403, {"Content-Type" => "text/plain","Content-Length" => size.to_s}, [body]] + return [403, {"Content-Type" => "text/plain", + "Content-Length" => size.to_s, + "X-Cascade" => "pass"}, [body]] end def list_directory @@ -123,7 +125,9 @@ table { width:100%%; } def entity_not_found body = "Entity not found: #{@path_info}\n" size = Rack::Utils.bytesize(body) - return [404, {"Content-Type" => "text/plain", "Content-Length" => size.to_s}, [body]] + return [404, {"Content-Type" => "text/plain", + "Content-Length" => size.to_s, + "X-Cascade" => "pass"}, [body]] end def each diff --git a/vendor/plugins/rack/lib/rack/etag.rb b/vendor/plugins/rack/lib/rack/etag.rb new file mode 100644 index 00000000..06dbc6aa --- /dev/null +++ b/vendor/plugins/rack/lib/rack/etag.rb @@ -0,0 +1,23 @@ +require 'digest/md5' + +module Rack + # Automatically sets the ETag header on all String bodies + class ETag + def initialize(app) + @app = app + end + + def call(env) + status, headers, body = @app.call(env) + + if !headers.has_key?('ETag') + parts = [] + body.each { |part| parts << part.to_s } + headers['ETag'] = %("#{Digest::MD5.hexdigest(parts.join(""))}") + [status, headers, parts] + else + [status, headers, body] + end + end + end +end diff --git a/vendor/plugins/rack/lib/rack/file.rb b/vendor/plugins/rack/lib/rack/file.rb index fe62bd6b..14af7b3b 100644 --- a/vendor/plugins/rack/lib/rack/file.rb +++ b/vendor/plugins/rack/lib/rack/file.rb @@ -45,7 +45,8 @@ module Rack def forbidden body = "Forbidden\n" [403, {"Content-Type" => "text/plain", - "Content-Length" => body.size.to_s}, + "Content-Length" => body.size.to_s, + "X-Cascade" => "pass"}, [body]] end @@ -73,7 +74,8 @@ module Rack def not_found body = "File not found: #{@path_info}\n" [404, {"Content-Type" => "text/plain", - "Content-Length" => body.size.to_s}, + "Content-Length" => body.size.to_s, + "X-Cascade" => "pass"}, [body]] end diff --git a/vendor/plugins/rack/lib/rack/handler.rb b/vendor/plugins/rack/lib/rack/handler.rb index 5624a1e7..3c09883e 100644 --- a/vendor/plugins/rack/lib/rack/handler.rb +++ b/vendor/plugins/rack/lib/rack/handler.rb @@ -22,6 +22,25 @@ module Rack end end + def self.default(options = {}) + # Guess. + if ENV.include?("PHP_FCGI_CHILDREN") + # We already speak FastCGI + options.delete :File + options.delete :Port + + Rack::Handler::FastCGI + elsif ENV.include?("REQUEST_METHOD") + Rack::Handler::CGI + else + begin + Rack::Handler::Mongrel + rescue LoadError => e + Rack::Handler::WEBrick + end + end + end + # Transforms server-name constants to their canonical form as filenames, # then tries to require them but silences the LoadError if not found # diff --git a/vendor/plugins/rack/lib/rack/handler/cgi.rb b/vendor/plugins/rack/lib/rack/handler/cgi.rb index f45f3d73..c6903f15 100644 --- a/vendor/plugins/rack/lib/rack/handler/cgi.rb +++ b/vendor/plugins/rack/lib/rack/handler/cgi.rb @@ -15,7 +15,7 @@ module Rack env["SCRIPT_NAME"] = "" if env["SCRIPT_NAME"] == "/" - env.update({"rack.version" => [1,0], + env.update({"rack.version" => [1,1], "rack.input" => $stdin, "rack.errors" => $stderr, diff --git a/vendor/plugins/rack/lib/rack/handler/fastcgi.rb b/vendor/plugins/rack/lib/rack/handler/fastcgi.rb index 1739d659..b992a5f4 100644 --- a/vendor/plugins/rack/lib/rack/handler/fastcgi.rb +++ b/vendor/plugins/rack/lib/rack/handler/fastcgi.rb @@ -33,10 +33,10 @@ module Rack env.delete "HTTP_CONTENT_LENGTH" env["SCRIPT_NAME"] = "" if env["SCRIPT_NAME"] == "/" - + rack_input = RewindableInput.new(request.in) - env.update({"rack.version" => [1,0], + env.update({"rack.version" => [1,1], "rack.input" => rack_input, "rack.errors" => request.err, @@ -50,7 +50,6 @@ module Rack env["QUERY_STRING"] ||= "" env["HTTP_VERSION"] ||= env["SERVER_PROTOCOL"] env["REQUEST_PATH"] ||= "/" - env.delete "PATH_INFO" if env["PATH_INFO"] == "" env.delete "CONTENT_TYPE" if env["CONTENT_TYPE"] == "" env.delete "CONTENT_LENGTH" if env["CONTENT_LENGTH"] == "" diff --git a/vendor/plugins/rack/lib/rack/handler/lsws.rb b/vendor/plugins/rack/lib/rack/handler/lsws.rb index b4ddf4bb..eabc0bc9 100644 --- a/vendor/plugins/rack/lib/rack/handler/lsws.rb +++ b/vendor/plugins/rack/lib/rack/handler/lsws.rb @@ -1,5 +1,6 @@ require 'lsapi' require 'rack/content_length' +require 'rack/rewindable_input' module Rack module Handler @@ -19,7 +20,7 @@ module Rack rack_input = RewindableInput.new($stdin.read.to_s) env.update( - "rack.version" => [1,0], + "rack.version" => [1,1], "rack.input" => rack_input, "rack.errors" => $stderr, "rack.multithread" => false, @@ -38,6 +39,8 @@ module Rack ensure body.close if body.respond_to? :close end + ensure + rack_input.close end def self.send_headers(status, headers) print "Status: #{status}\r\n" diff --git a/vendor/plugins/rack/lib/rack/handler/mongrel.rb b/vendor/plugins/rack/lib/rack/handler/mongrel.rb index 7b448261..b6b775ea 100644 --- a/vendor/plugins/rack/lib/rack/handler/mongrel.rb +++ b/vendor/plugins/rack/lib/rack/handler/mongrel.rb @@ -7,10 +7,14 @@ module Rack module Handler class Mongrel < ::Mongrel::HttpHandler def self.run(app, options={}) - server = ::Mongrel::HttpServer.new(options[:Host] || '0.0.0.0', - options[:Port] || 8080) + server = ::Mongrel::HttpServer.new( + options[:Host] || '0.0.0.0', + options[:Port] || 8080, + options[:num_processors] || 950, + options[:throttle] || 0, + options[:timeout] || 60) # Acts like Rack::URLMap, utilizing Mongrel's own path finding methods. - # Use is similar to #run, replacing the app argument with a hash of + # Use is similar to #run, replacing the app argument with a hash of # { path=>app, ... } or an instance of Rack::URLMap. if options[:map] if app.is_a? Hash @@ -48,7 +52,7 @@ module Rack rack_input = request.body || StringIO.new('') rack_input.set_encoding(Encoding::BINARY) if rack_input.respond_to?(:set_encoding) - env.update({"rack.version" => [1,0], + env.update({"rack.version" => [1,1], "rack.input" => rack_input, "rack.errors" => $stderr, @@ -59,7 +63,6 @@ module Rack "rack.url_scheme" => "http", }) env["QUERY_STRING"] ||= "" - env.delete "PATH_INFO" if env["PATH_INFO"] == "" status, headers, body = @app.call(env) diff --git a/vendor/plugins/rack/lib/rack/handler/scgi.rb b/vendor/plugins/rack/lib/rack/handler/scgi.rb index bd860a5d..79a6b2bd 100644 --- a/vendor/plugins/rack/lib/rack/handler/scgi.rb +++ b/vendor/plugins/rack/lib/rack/handler/scgi.rb @@ -7,14 +7,14 @@ module Rack module Handler class SCGI < ::SCGI::Processor attr_accessor :app - + def self.run(app, options=nil) new(options.merge(:app=>app, :host=>options[:Host], :port=>options[:Port], :socket=>options[:Socket])).listen end - + def initialize(settings = {}) @app = Rack::Chunked.new(Rack::ContentLength.new(settings[:app])) @log = Object.new @@ -22,7 +22,7 @@ module Rack def @log.error(*args); end super(settings) end - + def process_request(request, input_body, socket) env = {}.replace(request) env.delete "HTTP_CONTENT_TYPE" @@ -36,7 +36,7 @@ module Rack rack_input = StringIO.new(input_body) rack_input.set_encoding(Encoding::BINARY) if rack_input.respond_to?(:set_encoding) - env.update({"rack.version" => [1,0], + env.update({"rack.version" => [1,1], "rack.input" => rack_input, "rack.errors" => $stderr, "rack.multithread" => true, diff --git a/vendor/plugins/rack/lib/rack/handler/webrick.rb b/vendor/plugins/rack/lib/rack/handler/webrick.rb index 1ef1b8de..2240b8d3 100644 --- a/vendor/plugins/rack/lib/rack/handler/webrick.rb +++ b/vendor/plugins/rack/lib/rack/handler/webrick.rb @@ -27,7 +27,7 @@ module Rack rack_input = StringIO.new(req.body.to_s) rack_input.set_encoding(Encoding::BINARY) if rack_input.respond_to?(:set_encoding) - env.update({"rack.version" => [1,0], + env.update({"rack.version" => [1,1], "rack.input" => rack_input, "rack.errors" => $stderr, @@ -41,9 +41,7 @@ module Rack env["HTTP_VERSION"] ||= env["SERVER_PROTOCOL"] env["QUERY_STRING"] ||= "" env["REQUEST_PATH"] ||= "/" - if env["PATH_INFO"] == "" - env.delete "PATH_INFO" - else + unless env["PATH_INFO"] == "" path, n = req.request_uri.path, env["SCRIPT_NAME"].length env["PATH_INFO"] = path[n, path.length-n] end diff --git a/vendor/plugins/rack/lib/rack/lint.rb b/vendor/plugins/rack/lib/rack/lint.rb index 796807a0..534375b9 100644 --- a/vendor/plugins/rack/lib/rack/lint.rb +++ b/vendor/plugins/rack/lib/rack/lint.rb @@ -61,7 +61,7 @@ module Rack ## subclassing allowed) that includes CGI-like headers. ## The application is free to modify the environment. assert("env #{env.inspect} is not a Hash, but #{env.class}") { - env.instance_of? Hash + env.kind_of? Hash } ## @@ -111,7 +111,7 @@ module Rack ## In addition to this, the Rack environment must include these ## Rack-specific variables: - ## rack.version:: The Array [1,0], representing this version of Rack. + ## rack.version:: The Array [1,1], representing this version of Rack. ## rack.url_scheme:: +http+ or +https+, depending on the request URL. ## rack.input:: See below, the input stream. ## rack.errors:: See below, the error stream. @@ -148,6 +148,35 @@ module Rack } end + ## rack.logger:: A common object interface for logging messages. + ## The object must implement: + if logger = env['rack.logger'] + ## info(message, &block) + assert("logger #{logger.inspect} must respond to info") { + logger.respond_to?(:info) + } + + ## debug(message, &block) + assert("logger #{logger.inspect} must respond to debug") { + logger.respond_to?(:debug) + } + + ## warn(message, &block) + assert("logger #{logger.inspect} must respond to warn") { + logger.respond_to?(:warn) + } + + ## error(message, &block) + assert("logger #{logger.inspect} must respond to error") { + logger.respond_to?(:error) + } + + ## fatal(message, &block) + assert("logger #{logger.inspect} must respond to fatal") { + logger.respond_to?(:fatal) + } + 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 rack. @@ -175,7 +204,7 @@ module Rack env.each { |key, value| next if key.include? "." # Skip extensions assert("env variable #{key} has non-string value #{value.inspect}") { - value.instance_of? String + value.kind_of? String } } @@ -184,7 +213,7 @@ module Rack ## * rack.version must be an array of Integers. assert("rack.version must be an Array, was #{env["rack.version"].class}") { - env["rack.version"].instance_of? Array + env["rack.version"].kind_of? Array } ## * rack.url_scheme must either be +http+ or +https+. assert("rack.url_scheme unknown: #{env["rack.url_scheme"].inspect}") { @@ -243,7 +272,7 @@ module Rack assert("rack.input #{input} is not opened in binary mode") { input.binmode? } if input.respond_to?(:binmode?) - + ## 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}") { @@ -269,7 +298,7 @@ module Rack assert("rack.input#gets called with arguments") { args.size == 0 } v = @input.gets assert("rack.input#gets didn't return a String") { - v.nil? or v.instance_of? String + v.nil? or v.kind_of? String } v end @@ -300,18 +329,18 @@ module Rack args[1].kind_of?(String) } end - + v = @input.read(*args) - + assert("rack.input#read didn't return nil or a String") { - v.nil? or v.instance_of? String + v.nil? or v.kind_of? String } if args[0].nil? assert("rack.input#read(nil) returned nil on EOF") { !v.nil? } end - + v end @@ -320,12 +349,12 @@ module Rack assert("rack.input#each called with arguments") { args.size == 0 } @input.each { |line| assert("rack.input#each didn't yield a String") { - line.instance_of? String + line.kind_of? String } 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 @@ -373,7 +402,7 @@ module Rack ## * +write+ must be called with a single argument that is a String. def write(str) - assert("rack.errors#write not called with a String") { str.instance_of? String } + assert("rack.errors#write not called with a String") { str.kind_of? String } @error.write str end @@ -407,7 +436,7 @@ module Rack header.each { |key, value| ## The header keys must be Strings. assert("header key must be a string, was #{key.class}") { - key.instance_of? String + key.kind_of? String } ## The header must not contain a +Status+ key, assert("header must not contain Status") { key.downcase != "status" } @@ -499,7 +528,7 @@ module Rack @body.each { |part| ## and must only yield String values. assert("Body yielded non-string value #{part.inspect}") { - part.instance_of? String + part.kind_of? String } yield part } diff --git a/vendor/plugins/rack/lib/rack/logger.rb b/vendor/plugins/rack/lib/rack/logger.rb new file mode 100644 index 00000000..d67d8ce2 --- /dev/null +++ b/vendor/plugins/rack/lib/rack/logger.rb @@ -0,0 +1,20 @@ +require 'logger' + +module Rack + # Sets up rack.logger to write to rack.errors stream + class Logger + def initialize(app, level = ::Logger::INFO) + @app, @level = app, level + end + + def call(env) + logger = ::Logger.new(env['rack.errors']) + logger.level = @level + + env['rack.logger'] = logger + @app.call(env) + ensure + logger.close + end + end +end diff --git a/vendor/plugins/rack/lib/rack/mime.rb b/vendor/plugins/rack/lib/rack/mime.rb index 5a6a73a9..1414d19a 100644 --- a/vendor/plugins/rack/lib/rack/mime.rb +++ b/vendor/plugins/rack/lib/rack/mime.rb @@ -14,7 +14,7 @@ module Rack # Rack::Mime::MIME_TYPES.fetch('.foo', 'application/octet-stream') def mime_type(ext, fallback='application/octet-stream') - MIME_TYPES.fetch(ext, fallback) + MIME_TYPES.fetch(ext.to_s.downcase, fallback) end module_function :mime_type @@ -105,6 +105,7 @@ module Rack ".m3u" => "audio/x-mpegurl", ".m4v" => "video/mp4", ".man" => "text/troff", + ".manifest"=> "text/cache-manifest", ".mathml" => "application/mathml+xml", ".mbox" => "application/mbox", ".mdoc" => "text/troff", @@ -126,6 +127,7 @@ module Rack ".ods" => "application/vnd.oasis.opendocument.spreadsheet", ".odt" => "application/vnd.oasis.opendocument.text", ".ogg" => "application/ogg", + ".ogv" => "video/ogg", ".p" => "text/x-pascal", ".pas" => "text/x-pascal", ".pbm" => "image/x-portable-bitmap", diff --git a/vendor/plugins/rack/lib/rack/mock.rb b/vendor/plugins/rack/lib/rack/mock.rb index c34a2d7a..23ecba17 100644 --- a/vendor/plugins/rack/lib/rack/mock.rb +++ b/vendor/plugins/rack/lib/rack/mock.rb @@ -40,7 +40,7 @@ module Rack end DEFAULT_ENV = { - "rack.version" => [1,0], + "rack.version" => [1,1], "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,7 +93,30 @@ module Rack env["rack.errors"] = StringIO.new end - opts[:input] ||= "" + 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 + + empty_str = "" + empty_str.force_encoding("ASCII-8BIT") if empty_str.respond_to? :force_encoding + opts[:input] ||= empty_str if String === opts[:input] rack_input = StringIO.new(opts[:input]) else @@ -128,7 +154,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/vendor/plugins/rack/lib/rack/nulllogger.rb b/vendor/plugins/rack/lib/rack/nulllogger.rb new file mode 100644 index 00000000..77fb637d --- /dev/null +++ b/vendor/plugins/rack/lib/rack/nulllogger.rb @@ -0,0 +1,18 @@ +module Rack + class NullLogger + def initialize(app) + @app = app + end + + def call(env) + env['rack.logger'] = self + @app.call(env) + end + + def info(progname = nil, &block); end + def debug(progname = nil, &block); end + def warn(progname = nil, &block); end + def error(progname = nil, &block); end + def fatal(progname = nil, &block); end + end +end diff --git a/vendor/plugins/rack/lib/rack/reloader.rb b/vendor/plugins/rack/lib/rack/reloader.rb index a9c566f7..a06de23a 100644 --- a/vendor/plugins/rack/lib/rack/reloader.rb +++ b/vendor/plugins/rack/lib/rack/reloader.rb @@ -1,5 +1,6 @@ # Copyright (c) 2009 Michael Fellinger m.fellinger@gmail.com -# All files in this distribution are subject to the terms of the Ruby license. +# Rack::Reloader is subject to the terms of an MIT-style license. +# See COPYING or http://www.opensource.org/licenses/mit-license.php. require 'pathname' @@ -92,6 +93,8 @@ module Rack found, stat = safe_stat(path) return ::File.expand_path(found), stat if found end + + return false, false end def safe_stat(file) diff --git a/vendor/plugins/rack/lib/rack/request.rb b/vendor/plugins/rack/lib/rack/request.rb index 2f64bd6c..b3de1ce4 100644 --- a/vendor/plugins/rack/lib/rack/request.rb +++ b/vendor/plugins/rack/lib/rack/request.rb @@ -32,6 +32,7 @@ module Rack def content_type; @env['CONTENT_TYPE'] end def session; @env['rack.session'] ||= {} end def session_options; @env['rack.session.options'] ||= {} end + def logger; @env['rack.logger'] end # The media type (type/subtype) portion of the CONTENT_TYPE header # without any media type parameters. e.g., when CONTENT_TYPE is @@ -63,9 +64,17 @@ module Rack media_type_params['charset'] end + def host_with_port + if forwarded = @env["HTTP_X_FORWARDED_HOST"] + forwarded.split(/,\s?/).last + else + @env['HTTP_HOST'] || "#{@env['SERVER_NAME'] || @env['SERVER_ADDR']}:#{@env['SERVER_PORT']}" + end + end + def host # Remove port number. - (@env["HTTP_HOST"] || @env["SERVER_NAME"]).to_s.gsub(/:\d+\z/, '') + host_with_port.to_s.gsub(/:\d+\z/, '') end def script_name=(s); @env["SCRIPT_NAME"] = s.to_s end @@ -81,7 +90,6 @@ module Rack # one of the media types presents in this list will not be eligible # for form-data / param parsing. FORM_DATA_MEDIA_TYPES = [ - nil, 'application/x-www-form-urlencoded', 'multipart/form-data' ] @@ -92,15 +100,20 @@ module Rack 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 + # the request Content-Type for one of the media-types: + # "application/x-www-form-urlencoded" or "multipart/form-data". The # list of form-data media types can be modified through the # +FORM_DATA_MEDIA_TYPES+ array. + # + # A request body is also assumed to contain form-data when no + # Content-Type header is provided and the request_method is POST. def form_data? - FORM_DATA_MEDIA_TYPES.include?(media_type) + type = media_type + meth = env["rack.methodoverride.original_method"] || env['REQUEST_METHOD'] + (meth == 'POST' && type.nil?) || FORM_DATA_MEDIA_TYPES.include?(type) end # Determine whether the request body contains data by checking @@ -115,8 +128,7 @@ module Rack @env["rack.request.query_hash"] else @env["rack.request.query_string"] = query_string - @env["rack.request.query_hash"] = - Utils.parse_nested_query(query_string) + @env["rack.request.query_hash"] = parse_query(query_string) end end @@ -125,19 +137,20 @@ module Rack # This method support both application/x-www-form-urlencoded and # multipart/form-data. def POST - if @env["rack.request.form_input"].eql? @env["rack.input"] + if @env["rack.input"].nil? + raise "Missing rack.input" + elsif @env["rack.request.form_input"].eql? @env["rack.input"] @env["rack.request.form_hash"] elsif form_data? || parseable_data? @env["rack.request.form_input"] = @env["rack.input"] - unless @env["rack.request.form_hash"] = - Utils::Multipart.parse_multipart(env) + unless @env["rack.request.form_hash"] = parse_multipart(env) form_vars = @env["rack.input"].read # Fix for Safari Ajax postings that always append \0 form_vars.sub!(/\0\z/, '') @env["rack.request.form_vars"] = form_vars - @env["rack.request.form_hash"] = Utils.parse_nested_query(form_vars) + @env["rack.request.form_hash"] = parse_query(form_vars) @env["rack.input"].rewind end @@ -149,7 +162,7 @@ module Rack # The union of GET and POST data. def params - self.put? ? self.GET : self.GET.update(self.POST) + self.GET.update(self.POST) rescue EOFError => e self.GET end @@ -175,6 +188,9 @@ module Rack end alias referrer referer + def user_agent + @env['HTTP_USER_AGENT'] + end def cookies return {} unless @env["HTTP_COOKIE"] @@ -214,11 +230,11 @@ module Rack url end - + def path script_name + path_info end - + def fullpath query_string.empty? ? path : "#{path}?#{query_string}" end @@ -242,5 +258,14 @@ module Rack @env['REMOTE_ADDR'] end end + + protected + def parse_query(qs) + Utils.parse_nested_query(qs) + end + + def parse_multipart(env) + Utils::Multipart.parse_multipart(env) + end end end diff --git a/vendor/plugins/rack/lib/rack/response.rb b/vendor/plugins/rack/lib/rack/response.rb index 28b4d830..a7f9bf2b 100644 --- a/vendor/plugins/rack/lib/rack/response.rb +++ b/vendor/plugins/rack/lib/rack/response.rb @@ -19,7 +19,7 @@ module Rack attr_accessor :length def initialize(body=[], status=200, header={}, &block) - @status = status + @status = status.to_i @header = Utils::HeaderHash.new({"Content-Type" => "text/html"}. merge(header)) @@ -54,45 +54,11 @@ module Rack end def set_cookie(key, value) - case value - when Hash - domain = "; domain=" + value[:domain] if value[:domain] - path = "; path=" + value[:path] if value[:path] - # According to RFC 2109, we need dashes here. - # N.B.: cgi.rb uses spaces... - expires = "; expires=" + value[:expires].clone.gmtime. - strftime("%a, %d-%b-%Y %H:%M:%S GMT") if value[:expires] - secure = "; secure" if value[:secure] - httponly = "; HttpOnly" if value[:httponly] - value = value[:value] - end - value = [value] unless Array === value - cookie = Utils.escape(key) + "=" + - value.map { |v| Utils.escape v }.join("&") + - "#{domain}#{path}#{expires}#{secure}#{httponly}" - - case self["Set-Cookie"] - when Array - self["Set-Cookie"] << cookie - when String - self["Set-Cookie"] = [self["Set-Cookie"], cookie] - when nil - self["Set-Cookie"] = cookie - end + Utils.set_cookie_header!(header, key, value) end def delete_cookie(key, value={}) - unless Array === self["Set-Cookie"] - self["Set-Cookie"] = [self["Set-Cookie"]].compact - end - - self["Set-Cookie"].reject! { |cookie| - cookie =~ /\A#{Utils.escape(key)}=/ - } - - set_cookie(key, - {:value => '', :path => nil, :domain => nil, - :expires => Time.at(0) }.merge(value)) + Utils.delete_cookie_header!(header, key, value) end def redirect(target, status=302) @@ -105,9 +71,9 @@ module Rack if [204, 304].include?(status.to_i) header.delete "Content-Type" - [status.to_i, header.to_hash, []] + [status.to_i, header, []] else - [status.to_i, header.to_hash, self] + [status.to_i, header, self] end end alias to_a finish # For *response diff --git a/vendor/plugins/rack/lib/rack/rewindable_input.rb b/vendor/plugins/rack/lib/rack/rewindable_input.rb index 2864d510..08764bee 100644 --- a/vendor/plugins/rack/lib/rack/rewindable_input.rb +++ b/vendor/plugins/rack/lib/rack/rewindable_input.rb @@ -16,27 +16,27 @@ module Rack @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. @@ -52,9 +52,9 @@ module Rack @rewindable_io = nil end end - + private - + # Ruby's Tempfile class has a bug. Subclass it and fix it. class Tempfile < ::Tempfile def _close @@ -72,11 +72,13 @@ module Rack # access it because we have the file handle open. @rewindable_io = Tempfile.new('RackRewindableInput') @rewindable_io.chmod(0000) + @rewindable_io.set_encoding(Encoding::BINARY) if @rewindable_io.respond_to?(:set_encoding) + @rewindable_io.binmode if filesystem_has_posix_semantics? && !tempfile_unlink_contains_bug? @rewindable_io.unlink @unlinked = true end - + buffer = "" while @io.read(1024 * 4, buffer) entire_buffer_written_out = false @@ -90,7 +92,7 @@ module Rack end @rewindable_io.rewind end - + def filesystem_has_posix_semantics? RUBY_PLATFORM !~ /(mswin|mingw|cygwin|java)/ end diff --git a/vendor/plugins/rack/lib/rack/runtime.rb b/vendor/plugins/rack/lib/rack/runtime.rb new file mode 100644 index 00000000..1bd411fd --- /dev/null +++ b/vendor/plugins/rack/lib/rack/runtime.rb @@ -0,0 +1,27 @@ +module Rack + # Sets an "X-Runtime" response header, indicating the response + # time of the request, in seconds + # + # You can put it right before the application to see the processing + # time, or before all the other middlewares to include time for them, + # too. + class Runtime + def initialize(app, name = nil) + @app = app + @header_name = "X-Runtime" + @header_name << "-#{name}" if name + end + + def call(env) + start_time = Time.now + status, headers, body = @app.call(env) + request_time = Time.now - start_time + + if !headers.has_key?(@header_name) + headers[@header_name] = "%0.6f" % request_time + end + + [status, headers, body] + end + end +end diff --git a/vendor/plugins/rack/lib/rack/sendfile.rb b/vendor/plugins/rack/lib/rack/sendfile.rb new file mode 100644 index 00000000..4fa82946 --- /dev/null +++ b/vendor/plugins/rack/lib/rack/sendfile.rb @@ -0,0 +1,142 @@ +require 'rack/file' + +module Rack + class File #:nodoc: + alias :to_path :path + end + + # = Sendfile + # + # The Sendfile middleware intercepts responses whose body is being + # served from a file and replaces it with a server specific X-Sendfile + # header. The web server is then responsible for writing the file contents + # to the client. This can dramatically reduce the amount of work required + # by the Ruby backend and takes advantage of the web servers optimized file + # delivery code. + # + # In order to take advantage of this middleware, the response body must + # respond to +to_path+ and the request must include an X-Sendfile-Type + # header. Rack::File and other components implement +to_path+ so there's + # rarely anything you need to do in your application. The X-Sendfile-Type + # header is typically set in your web servers configuration. The following + # sections attempt to document + # + # === Nginx + # + # Nginx supports the X-Accel-Redirect header. This is similar to X-Sendfile + # but requires parts of the filesystem to be mapped into a private URL + # hierarachy. + # + # The following example shows the Nginx configuration required to create + # a private "/files/" area, enable X-Accel-Redirect, and pass the special + # X-Sendfile-Type and X-Accel-Mapping headers to the backend: + # + # location /files/ { + # internal; + # alias /var/www/; + # } + # + # location / { + # proxy_redirect false; + # + # proxy_set_header Host $host; + # proxy_set_header X-Real-IP $remote_addr; + # proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + # + # proxy_set_header X-Sendfile-Type X-Accel-Redirect + # proxy_set_header X-Accel-Mapping /files/=/var/www/; + # + # proxy_pass http://127.0.0.1:8080/; + # } + # + # Note that the X-Sendfile-Type header must be set exactly as shown above. The + # X-Accel-Mapping header should specify the name of the private URL pattern, + # followed by an equals sign (=), followed by the location on the file system + # that it maps to. The middleware performs a simple substitution on the + # resulting path. + # + # See Also: http://wiki.codemongers.com/NginxXSendfile + # + # === lighttpd + # + # Lighttpd has supported some variation of the X-Sendfile header for some + # time, although only recent version support X-Sendfile in a reverse proxy + # configuration. + # + # $HTTP["host"] == "example.com" { + # proxy-core.protocol = "http" + # proxy-core.balancer = "round-robin" + # proxy-core.backends = ( + # "127.0.0.1:8000", + # "127.0.0.1:8001", + # ... + # ) + # + # proxy-core.allow-x-sendfile = "enable" + # proxy-core.rewrite-request = ( + # "X-Sendfile-Type" => (".*" => "X-Sendfile") + # ) + # } + # + # See Also: http://redmine.lighttpd.net/wiki/lighttpd/Docs:ModProxyCore + # + # === Apache + # + # X-Sendfile is supported under Apache 2.x using a separate module: + # + # http://tn123.ath.cx/mod_xsendfile/ + # + # Once the module is compiled and installed, you can enable it using + # XSendFile config directive: + # + # RequestHeader Set X-Sendfile-Type X-Sendfile + # ProxyPassReverse / http://localhost:8001/ + # XSendFile on + + class Sendfile + F = ::File + + def initialize(app, variation=nil) + @app = app + @variation = variation + end + + def call(env) + status, headers, body = @app.call(env) + if body.respond_to?(:to_path) + case type = variation(env) + when 'X-Accel-Redirect' + path = F.expand_path(body.to_path) + if url = map_accel_path(env, path) + headers[type] = url + body = [] + else + env['rack.errors'] << "X-Accel-Mapping header missing" + end + when 'X-Sendfile', 'X-Lighttpd-Send-File' + path = F.expand_path(body.to_path) + headers[type] = path + body = [] + when '', nil + else + env['rack.errors'] << "Unknown x-sendfile variation: '#{variation}'.\n" + end + end + [status, headers, body] + end + + private + def variation(env) + @variation || + env['sendfile.type'] || + env['HTTP_X_SENDFILE_TYPE'] + end + + def map_accel_path(env, file) + if mapping = env['HTTP_X_ACCEL_MAPPING'] + internal, external = mapping.split('=', 2).map{ |p| p.strip } + file.sub(/^#{internal}/i, external) + end + end + end +end diff --git a/vendor/plugins/rack/lib/rack/server.rb b/vendor/plugins/rack/lib/rack/server.rb new file mode 100644 index 00000000..7d0705ad --- /dev/null +++ b/vendor/plugins/rack/lib/rack/server.rb @@ -0,0 +1,212 @@ +require 'optparse' + +module Rack + class Server + class Options + def parse!(args) + options = {} + opt_parser = OptionParser.new("", 24, ' ') do |opts| + opts.banner = "Usage: rackup [ruby options] [rack options] [rackup config]" + + opts.separator "" + opts.separator "Ruby options:" + + lineno = 1 + opts.on("-e", "--eval LINE", "evaluate a LINE of code") { |line| + eval line, TOPLEVEL_BINDING, "-e", lineno + lineno += 1 + } + + opts.on("-d", "--debug", "set debugging flags (set $DEBUG to true)") { + options[:debug] = true + } + opts.on("-w", "--warn", "turn warnings on for your script") { + options[:warn] = true + } + + opts.on("-I", "--include PATH", + "specify $LOAD_PATH (may be used more than once)") { |path| + options[:include] = path.split(":") + } + + opts.on("-r", "--require LIBRARY", + "require the library, before executing your script") { |library| + options[:require] = library + } + + opts.separator "" + opts.separator "Rack options:" + opts.on("-s", "--server SERVER", "serve using SERVER (webrick/mongrel)") { |s| + options[:server] = s + } + + opts.on("-o", "--host HOST", "listen on HOST (default: 0.0.0.0)") { |host| + options[:Host] = host + } + + opts.on("-p", "--port PORT", "use PORT (default: 9292)") { |port| + options[:Port] = port + } + + opts.on("-E", "--env ENVIRONMENT", "use ENVIRONMENT for defaults (default: development)") { |e| + options[:environment] = e + } + + opts.on("-D", "--daemonize", "run daemonized in the background") { |d| + options[:daemonize] = d ? true : false + } + + opts.on("-P", "--pid FILE", "file to store PID (default: rack.pid)") { |f| + options[:pid] = ::File.expand_path(f) + } + + opts.separator "" + opts.separator "Common options:" + + opts.on_tail("-h", "--help", "Show this message") do + puts opts + exit + end + + opts.on_tail("--version", "Show version") do + puts "Rack #{Rack.version}" + exit + end + end + opt_parser.parse! args + options[:rack_file] = args.last if args.last + options + end + end + + def self.start + new.start + end + + attr_accessor :options + + def initialize(options = nil) + @options = options + end + + def options + @options ||= parse_options(ARGV) + end + + def default_options + { + :environment => "development", + :pid => nil, + :Port => 9292, + :Host => "0.0.0.0", + :AccessLog => [], + :rack_file => ::File.expand_path("config.ru") + } + end + + def app + @app ||= begin + if !::File.exist? options[:rack_file] + abort "configuration #{options[:rack_file]} not found" + end + + app, options = Rack::Builder.parse_file(self.options[:rack_file], opt_parser) + self.options.merge! options + app + end + end + + def self.middleware + @middleware ||= begin + m = Hash.new {|h,k| h[k] = []} + m["deployment"].concat [lambda {|server| server.server =~ /CGI/ ? nil : [Rack::CommonLogger, $stderr] }] + m["development"].concat m["deployment"] + [[Rack::ShowExceptions], [Rack::Lint]] + m + end + end + + def middleware + self.class.middleware + end + + def start + if options[:debug] + $DEBUG = true + require 'pp' + p options[:server] + pp wrapped_app + pp app + end + + if options[:warn] + $-w = true + end + + if includes = options[:include] + $LOAD_PATH.unshift *includes + end + + if library = options[:require] + require library + end + + daemonize_app if options[:daemonize] + write_pid if options[:pid] + server.run wrapped_app, options + end + + def server + @_server ||= Rack::Handler.get(options[:server]) || Rack::Handler.default + end + + private + def parse_options(args) + options = default_options + + # Don't evaluate CGI ISINDEX parameters. + # http://hoohoo.ncsa.uiuc.edu/cgi/cl.html + args.clear if ENV.include?("REQUEST_METHOD") + + options.merge! opt_parser.parse! args + options + end + + def opt_parser + Options.new + end + + def build_app(app) + middleware[options[:environment]].reverse_each do |middleware| + middleware = middleware.call(self) if middleware.respond_to?(:call) + next unless middleware + klass = middleware.shift + app = klass.new(app, *middleware) + end + app + end + + def wrapped_app + @wrapped_app ||= build_app app + end + + def daemonize_app + if RUBY_VERSION < "1.9" + exit if fork + Process.setsid + exit if fork + Dir.chdir "/" + ::File.umask 0000 + STDIN.reopen "/dev/null" + STDOUT.reopen "/dev/null", "a" + STDERR.reopen "/dev/null", "a" + else + Process.daemon + end + end + + def write_pid + ::File.open(options[:pid], 'w'){ |f| f.write("#{Process.pid}") } + at_exit { ::File.delete(options[:pid]) if ::File.exist?(options[:pid]) } + end + end +end diff --git a/vendor/plugins/rack/lib/rack/session/abstract/id.rb b/vendor/plugins/rack/lib/rack/session/abstract/id.rb index 218144c1..98746705 100644 --- a/vendor/plugins/rack/lib/rack/session/abstract/id.rb +++ b/vendor/plugins/rack/lib/rack/session/abstract/id.rb @@ -107,18 +107,16 @@ module Rack if not session_id = set_session(env, session_id, session, options) env["rack.errors"].puts("Warning! #{self.class.name} failed to save session. Content dropped.") - [status, headers, body] elsif options[:defer] and not options[:renew] env["rack.errors"].puts("Defering cookie for #{session_id}") if $VERBOSE - [status, headers, body] else cookie = Hash.new cookie[:value] = session_id cookie[:expires] = Time.now + options[:expire_after] unless options[:expire_after].nil? - response = Rack::Response.new(body, status, headers) - response.set_cookie(@key, cookie.merge(options)) - response.to_a + Utils.set_cookie_header!(headers, @key, cookie.merge(options)) end + + [status, headers, body] end # All thread safety and session retrival proceedures should occur here. diff --git a/vendor/plugins/rack/lib/rack/session/cookie.rb b/vendor/plugins/rack/lib/rack/session/cookie.rb index eace9bd0..240e6c8d 100644 --- a/vendor/plugins/rack/lib/rack/session/cookie.rb +++ b/vendor/plugins/rack/lib/rack/session/cookie.rb @@ -70,16 +70,15 @@ module Rack if session_data.size > (4096 - @key.size) env["rack.errors"].puts("Warning! Rack::Session::Cookie data size exceeds 4K. Content dropped.") - [status, headers, body] else options = env["rack.session.options"] cookie = Hash.new cookie[:value] = session_data cookie[:expires] = Time.now + options[:expire_after] unless options[:expire_after].nil? - response = Rack::Response.new(body, status, headers) - response.set_cookie(@key, cookie.merge(options)) - response.to_a + Utils.set_cookie_header!(headers, @key, cookie.merge(options)) end + + [status, headers, body] end def generate_hmac(data) diff --git a/vendor/plugins/rack/lib/rack/session/memcache.rb b/vendor/plugins/rack/lib/rack/session/memcache.rb index 4a65cbf3..44629da3 100644 --- a/vendor/plugins/rack/lib/rack/session/memcache.rb +++ b/vendor/plugins/rack/lib/rack/session/memcache.rb @@ -29,9 +29,13 @@ module Rack super @mutex = Mutex.new - @pool = MemCache. - new @default_options[:memcache_server], @default_options - raise 'No memcache servers' unless @pool.servers.any?{|s|s.alive?} + mserv = @default_options[:memcache_server] + mopts = @default_options. + reject{|k,v| MemCache::DEFAULT_OPTIONS.include? k } + @pool = MemCache.new mserv, mopts + unless @pool.active? and @pool.servers.any?{|c| c.alive? } + raise 'No memcache servers' + end end def generate_sid @@ -41,24 +45,23 @@ module Rack end end - def get_session(env, sid) - session = @pool.get(sid) if sid + def get_session(env, session_id) @mutex.lock if env['rack.multithread'] - unless sid and session - env['rack.errors'].puts("Session '#{sid.inspect}' not found, initializing...") if $VERBOSE and not sid.nil? - session = {} - sid = generate_sid - ret = @pool.add sid, session - raise "Session collision on '#{sid.inspect}'" unless /^STORED/ =~ ret + unless session_id and session = @pool.get(session_id) + session_id, session = generate_sid, {} + unless /^STORED/ =~ @pool.add(session_id, session) + raise "Session collision on '#{session_id.inspect}'" + end end - session.instance_variable_set('@old', {}.merge(session)) - return [sid, session] - rescue MemCache::MemCacheError, Errno::ECONNREFUSED # MemCache server cannot be contacted - warn "#{self} is unable to find server." + session.instance_variable_set '@old', @pool.get(session_id, true) + return [session_id, session] + rescue MemCache::MemCacheError, Errno::ECONNREFUSED + # MemCache server cannot be contacted + warn "#{self} is unable to find memcached server." warn $!.inspect return [ nil, {} ] ensure - @mutex.unlock if env['rack.multithread'] + @mutex.unlock if @mutex.locked? end def set_session(env, session_id, new_session, options) @@ -66,43 +69,50 @@ module Rack expiry = expiry.nil? ? 0 : expiry + 1 @mutex.lock if env['rack.multithread'] - session = @pool.get(session_id) || {} if options[:renew] or options[:drop] @pool.delete session_id return false if options[:drop] session_id = generate_sid - @pool.add session_id, 0 # so we don't worry about cache miss on #set + @pool.add session_id, {} # so we don't worry about cache miss on #set end - old_session = new_session.instance_variable_get('@old') || {} - session = merge_sessions session_id, old_session, new_session, session + + session = @pool.get(session_id) || {} + old_session = new_session.instance_variable_get '@old' + old_session = old_session ? Marshal.load(old_session) : {} + + unless Hash === old_session and Hash === new_session + env['rack.errors']. + puts 'Bad old_session or new_session sessions provided.' + else # merge sessions + # alterations are either update or delete, making as few changes as + # possible to prevent possible issues. + + # removed keys + delete = old_session.keys - new_session.keys + if $VERBOSE and not delete.empty? + env['rack.errors']. + puts "//@#{session_id}: delete #{delete*','}" + end + delete.each{|k| session.delete k } + + # added or altered keys + update = new_session.keys. + select{|k| new_session[k] != old_session[k] } + if $VERBOSE and not update.empty? + env['rack.errors'].puts "//@#{session_id}: update #{update*','}" + end + update.each{|k| session[k] = new_session[k] } + end + @pool.set session_id, session, expiry return session_id - rescue MemCache::MemCacheError, Errno::ECONNREFUSED # MemCache server cannot be contacted - warn "#{self} is unable to find server." + rescue MemCache::MemCacheError, Errno::ECONNREFUSED + # MemCache server cannot be contacted + warn "#{self} is unable to find memcached server." warn $!.inspect return false ensure - @mutex.unlock if env['rack.multithread'] - end - - private - - def merge_sessions sid, old, new, cur=nil - cur ||= {} - unless Hash === old and Hash === new - warn 'Bad old or new sessions provided.' - return cur - end - - delete = old.keys - new.keys - warn "//@#{sid}: delete #{delete*','}" if $VERBOSE and not delete.empty? - delete.each{|k| cur.delete k } - - update = new.keys.select{|k| new[k] != old[k] } - warn "//@#{sid}: update #{update*','}" if $VERBOSE and not update.empty? - update.each{|k| cur[k] = new[k] } - - cur + @mutex.unlock if @mutex.locked? end end end diff --git a/vendor/plugins/rack/lib/rack/session/pool.rb b/vendor/plugins/rack/lib/rack/session/pool.rb index f6f87408..b3f8bd72 100644 --- a/vendor/plugins/rack/lib/rack/session/pool.rb +++ b/vendor/plugins/rack/lib/rack/session/pool.rb @@ -13,7 +13,7 @@ module Rack # In the context of a multithreaded environment, sessions being # committed to the pool is done in a merging manner. # - # The :drop option is available in rack.session.options if you with to + # The :drop option is available in rack.session.options if you wish to # explicitly remove the session from the session cache. # # Example: diff --git a/vendor/plugins/rack/lib/rack/urlmap.rb b/vendor/plugins/rack/lib/rack/urlmap.rb index fcf6616c..b699d35b 100644 --- a/vendor/plugins/rack/lib/rack/urlmap.rb +++ b/vendor/plugins/rack/lib/rack/urlmap.rb @@ -28,27 +28,28 @@ module Rack raise ArgumentError, "paths need to start with /" end location = location.chomp('/') + match = Regexp.new("^#{Regexp.quote(location).gsub('/', '/+')}(.*)", nil, 'n') - [host, location, app] - }.sort_by { |(h, l, a)| [h ? -h.size : (-1.0 / 0.0), -l.size] } # Longest path first + [host, location, match, app] + }.sort_by { |(h, l, m, a)| [h ? -h.size : (-1.0 / 0.0), -l.size] } # Longest path first end def call(env) - path = env["PATH_INFO"].to_s.squeeze("/") + path = env["PATH_INFO"].to_s script_name = env['SCRIPT_NAME'] hHost, sName, sPort = env.values_at('HTTP_HOST','SERVER_NAME','SERVER_PORT') - @mapping.each { |host, location, app| + @mapping.each { |host, location, match, app| next unless (hHost == host || sName == host \ || (host.nil? && (hHost == sName || hHost == sName+':'+sPort))) - next unless location == path[0, location.size] - next unless path[location.size] == nil || path[location.size] == ?/ + next unless path =~ match && rest = $1 + next unless rest.empty? || rest[0] == ?/ return app.call( env.merge( 'SCRIPT_NAME' => (script_name + location), - 'PATH_INFO' => path[location.size..-1])) + 'PATH_INFO' => rest)) } - [404, {"Content-Type" => "text/plain"}, ["Not Found: #{path}"]] + [404, {"Content-Type" => "text/plain", "X-Cascade" => "pass"}, ["Not Found: #{path}"]] end end end diff --git a/vendor/plugins/rack/lib/rack/utils.rb b/vendor/plugins/rack/lib/rack/utils.rb index d54c928c..68fd6ace 100644 --- a/vendor/plugins/rack/lib/rack/utils.rb +++ b/vendor/plugins/rack/lib/rack/utils.rb @@ -27,7 +27,7 @@ module Rack module_function :unescape DEFAULT_SEP = /[&;] */n - + # Stolen from Mongrel, with some small modifications: # Parses a query string by breaking it up at the '&' # and ';' characters. You can also use this to parse @@ -38,7 +38,9 @@ module Rack (qs || '').split(d ? /[#{d}] */n : DEFAULT_SEP).each do |p| k, v = p.split('=', 2).map { |x| unescape(x) } - + if v =~ /^("|')(.*)\1$/ + v = $2.gsub('\\'+$1, $1) + end if cur = params[k] if cur.class == Array params[k] << v @@ -67,6 +69,9 @@ module Rack module_function :parse_nested_query def normalize_params(params, name, v = nil) + if v and v =~ /^("|')(.*)\1$/ + v = $2.gsub('\\'+$1, $1) + end name =~ %r(\A[\[\]]*([^\[\]]+)\]*) k = $1 || '' after = $' || '' @@ -109,6 +114,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("&", "&"). @@ -149,6 +173,54 @@ module Rack end module_function :select_best_encoding + def set_cookie_header!(header, key, value) + case value + when Hash + domain = "; domain=" + value[:domain] if value[:domain] + path = "; path=" + value[:path] if value[:path] + # According to RFC 2109, we need dashes here. + # N.B.: cgi.rb uses spaces... + expires = "; expires=" + value[:expires].clone.gmtime. + strftime("%a, %d-%b-%Y %H:%M:%S GMT") if value[:expires] + secure = "; secure" if value[:secure] + httponly = "; HttpOnly" if value[:httponly] + value = value[:value] + end + value = [value] unless Array === value + cookie = escape(key) + "=" + + value.map { |v| escape v }.join("&") + + "#{domain}#{path}#{expires}#{secure}#{httponly}" + + case header["Set-Cookie"] + when Array + header["Set-Cookie"] << cookie + when String + header["Set-Cookie"] = [header["Set-Cookie"], cookie] + when nil + header["Set-Cookie"] = cookie + end + + nil + end + module_function :set_cookie_header! + + def delete_cookie_header!(header, key, value = {}) + unless Array === header["Set-Cookie"] + header["Set-Cookie"] = [header["Set-Cookie"]].compact + end + + header["Set-Cookie"].reject! { |cookie| + cookie =~ /\A#{escape(key)}=/ + } + + set_cookie_header!(header, key, + {:value => '', :path => nil, :domain => nil, + :expires => Time.at(0) }.merge(value)) + + nil + end + module_function :delete_cookie_header! + # Return the bytesize of String; uses String#length under Ruby 1.8 and # String#bytesize under 1.9. if ''.respond_to?(:bytesize) @@ -191,11 +263,22 @@ module Rack # A case-insensitive Hash that preserves the original case of a # header when set. class HeaderHash < Hash + def self.new(hash={}) + HeaderHash === hash ? hash : super(hash) + end + def initialize(hash={}) + super() @names = {} hash.each { |k, v| self[k] = v } end + def each + super do |k, v| + yield(k, v.respond_to?(:to_ary) ? v.to_ary.join("\n") : v) + end + end + def to_hash inject({}) do |hash, (k,v)| if v.respond_to? :to_ary @@ -208,21 +291,24 @@ module Rack end def [](k) - super @names[k.downcase] + super(@names[k] ||= @names[k.downcase]) end def []=(k, v) delete k - @names[k.downcase] = k + @names[k] = @names[k.downcase] = k super k, v end def delete(k) - super @names.delete(k.downcase) + canonical = k.downcase + result = super @names.delete(canonical) + @names.delete_if { |name,| name.downcase == canonical } + result end def include?(k) - @names.has_key? k.downcase + @names.include?(k) || @names.include?(k.downcase) end alias_method :has_key?, :include? @@ -238,13 +324,23 @@ module Rack hash = dup hash.merge! other end + + def replace(other) + clear + other.each { |k, v| self[k] = v } + self + end end # Every standard HTTP code mapped to the appropriate message. - # Stolen from Mongrel. + # Generated with: + # curl -s http://www.iana.org/assignments/http-status-codes | \ + # ruby -ane 'm = /^(\d{3}) +(\S[^\[(]+)/.match($_) and + # puts " #{m[1]} => \x27#{m[2].strip}x27,"' HTTP_STATUS_CODES = { 100 => 'Continue', 101 => 'Switching Protocols', + 102 => 'Processing', 200 => 'OK', 201 => 'Created', 202 => 'Accepted', @@ -252,12 +348,15 @@ module Rack 204 => 'No Content', 205 => 'Reset Content', 206 => 'Partial Content', + 207 => 'Multi-Status', + 226 => 'IM Used', 300 => 'Multiple Choices', 301 => 'Moved Permanently', 302 => 'Found', 303 => 'See Other', 304 => 'Not Modified', 305 => 'Use Proxy', + 306 => 'Reserved', 307 => 'Temporary Redirect', 400 => 'Bad Request', 401 => 'Unauthorized', @@ -273,27 +372,76 @@ module Rack 411 => 'Length Required', 412 => 'Precondition Failed', 413 => 'Request Entity Too Large', - 414 => 'Request-URI Too Large', + 414 => 'Request-URI Too Long', 415 => 'Unsupported Media Type', 416 => 'Requested Range Not Satisfiable', 417 => 'Expectation Failed', + 422 => 'Unprocessable Entity', + 423 => 'Locked', + 424 => 'Failed Dependency', + 426 => 'Upgrade Required', 500 => 'Internal Server Error', 501 => 'Not Implemented', 502 => 'Bad Gateway', 503 => 'Service Unavailable', 504 => 'Gateway Timeout', - 505 => 'HTTP Version Not Supported' + 505 => 'HTTP Version Not Supported', + 506 => 'Variant Also Negotiates', + 507 => 'Insufficient Storage', + 510 => 'Not Extended', } # Responses with HTTP status codes that should not have an entity body STATUS_WITH_NO_ENTITY_BODY = Set.new((100..199).to_a << 204 << 304) + SYMBOL_TO_STATUS_CODE = HTTP_STATUS_CODES.inject({}) { |hash, (code, message)| + hash[message.downcase.gsub(/\s|-/, '_').to_sym] = code + hash + } + + def status_code(status) + if status.is_a?(Symbol) + SYMBOL_TO_STATUS_CODE[status] || 500 + else + status.to_i + end + end + module_function :status_code + # A multipart form data parser, adapted from IOWA. # # 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'] =~ @@ -378,7 +526,7 @@ module Rack :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} @@ -388,7 +536,8 @@ module Rack Utils.normalize_params(params, name, data) unless data.nil? - break if buf.empty? || content_length == -1 + # break if we're at the end of a buffer, but not if it is the end of a field + break if (buf.empty? && $1 != EOL) || content_length == -1 } input.rewind @@ -396,6 +545,76 @@ module Rack 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/vendor/plugins/rack/rack.gemspec b/vendor/plugins/rack/rack.gemspec new file mode 100644 index 00000000..e28b9bb2 --- /dev/null +++ b/vendor/plugins/rack/rack.gemspec @@ -0,0 +1,38 @@ +Gem::Specification.new do |s| + s.name = "rack" + s.version = "1.1.0" + s.platform = Gem::Platform::RUBY + s.summary = "a modular Ruby webserver interface" + + s.description = <<-EOF +Rack provides minimal, modular and adaptable interface for developing +web applications in Ruby. By wrapping HTTP requests and responses in +the simplest way possible, it unifies and distills the API for web +servers, web frameworks, and software in between (the so-called +middleware) into a single method call. + +Also see http://rack.rubyforge.org. +EOF + + s.files = Dir['{bin/*,contrib/*,example/*,lib/**/*}'] + + %w(COPYING KNOWN-ISSUES rack.gemspec RDOX README SPEC) + s.bindir = 'bin' + s.executables << 'rackup' + s.require_path = 'lib' + s.has_rdoc = true + s.extra_rdoc_files = ['README', 'SPEC', 'KNOWN-ISSUES'] + s.test_files = Dir['test/{test,spec}_*.rb'] + + s.author = 'Christian Neukirchen' + s.email = 'chneukirchen@gmail.com' + s.homepage = 'http://rack.rubyforge.org' + s.rubyforge_project = 'rack' + + s.add_development_dependency 'test-spec' + + s.add_development_dependency 'camping' + s.add_development_dependency 'fcgi' + s.add_development_dependency 'memcache-client' + s.add_development_dependency 'mongrel' + s.add_development_dependency 'thin' +end diff --git a/vendor/plugins/rack/test/cgi/test.ru b/vendor/plugins/rack/test/cgi/test.ru index 4054b886..fc9b6ffc 100755 --- a/vendor/plugins/rack/test/cgi/test.ru +++ b/vendor/plugins/rack/test/cgi/test.ru @@ -1,5 +1,4 @@ -#!/usr/bin/env ../../bin/rackup -#\ -E deployment -I ../../lib +#!/usr/bin/env ruby -I ../../lib ../../bin/rackup -E deployment -I ../../lib # -*- ruby -*- require '../testrequest' diff --git a/vendor/plugins/rack/test/multipart/bad_robots b/vendor/plugins/rack/test/multipart/bad_robots new file mode 100644 index 00000000..7e5bd418 --- /dev/null +++ b/vendor/plugins/rack/test/multipart/bad_robots @@ -0,0 +1,259 @@ +--1yy3laWhgX31qpiHinh67wJXqKalukEUTvqTzmon +Content-Disposition: form-data; name="bbbbbbbbbbbbbbb" + +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaa + +--1yy3laWhgX31qpiHinh67wJXqKalukEUTvqTzmon +Content-Disposition: form-data; name="ccccccc" + +ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd +--1yy3laWhgX31qpiHinh67wJXqKalukEUTvqTzmon +Content-Disposition: form-data; name="file.name" + +INPUTMSG.gz +--1yy3laWhgX31qpiHinh67wJXqKalukEUTvqTzmon +Content-Disposition: form-data; name="file.content_type" + +application/octet-stream +--1yy3laWhgX31qpiHinh67wJXqKalukEUTvqTzmon +Content-Disposition: form-data; name="file.path" + +/var/tmp/uploads/4/0001728414 +--1yy3laWhgX31qpiHinh67wJXqKalukEUTvqTzmon +Content-Disposition: form-data; name="file.md5" + +aa73198feb4b4c1c3186f5e7466cbbcc +--1yy3laWhgX31qpiHinh67wJXqKalukEUTvqTzmon +Content-Disposition: form-data; name="file.size" + +13212 +--1yy3laWhgX31qpiHinh67wJXqKalukEUTvqTzmon +Content-Disposition: form-data; name="size" + +80892 +--1yy3laWhgX31qpiHinh67wJXqKalukEUTvqTzmon +Content-Disposition: form-data; name="mail_server_id" + +<1111111111.22222222.3333333333333.JavaMail.app@ffff-aaaa.dddd> + +--1yy3laWhgX31qpiHinh67wJXqKalukEUTvqTzmon +Content-Disposition: form-data; name="addresses" + +{"campsy_programmer@pinkedum.com":{"domain":"pinkedum.com","name":"Campsy Programmer","type":["env_sender"],"mailbox":"campsy_programmer"},"tex@rapidcity.com":{"domain":"rapidcity.com","name":"Big Tex","type":["env_recipients","to"],"mailbox":"tex"},"group-digests@linkedin.com":{"domain":"linkedin.com","name":"Group Members","type":["from"],"mailbox":"group-digests"}} +--1yy3laWhgX31qpiHinh67wJXqKalukEUTvqTzmon +Content-Disposition: form-data; name="received_on" + +2009-11-15T14:21:11Z +--1yy3laWhgX31qpiHinh67wJXqKalukEUTvqTzmon +Content-Disposition: form-data; name="id" + +dbfd9804d26d11deab24e3037639bf77 +--1yy3laWhgX31qpiHinh67wJXqKalukEUTvqTzmon +Content-Disposition: form-data; name="ip_address" + +127.0.0.1 +--1yy3laWhgX31qpiHinh67wJXqKalukEUTvqTzmon-- diff --git a/vendor/plugins/rack/test/multipart/fail_16384_nofile b/vendor/plugins/rack/test/multipart/fail_16384_nofile new file mode 100644 index 00000000..bdcd3320 --- /dev/null +++ b/vendor/plugins/rack/test/multipart/fail_16384_nofile @@ -0,0 +1,814 @@ +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="_method" + +put +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="authenticity_token" + +XCUgSyYsZ+iHQunq/yCSKFzjeVmsXV/WcphHQ0J+05I= +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[SESE]" + +BooBar +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[BBBBBBBBB]" + +18 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[CCCCCCCCCCCCCCCCCCC]" + +0 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[STARTFOO]" + +2009-11-04 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[ENDFOO]" + +2009-12-01 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[DDDDDDDD]" + +0 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[DDDDDDDD]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[EEEEEEEEEE]" + +10000 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[FFFFFFFFF]" + +boskoizcool +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[GGGGGGGGGGG]" + +0 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[GGGGGGGGGGG]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[YYYYYYYYYYYYYYY]" + +5.00 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[ZZZZZZZZZZZZZ]" + +mille +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[XXXXXXXXXXXXXXXXXXXXX]" + +0 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][1][9]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][1][10]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][1][11]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][1][12]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][1][13]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][1][14]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][1][15]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][1][16]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][1][17]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][1][18]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][1][19]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][1][20]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][1][21]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][1][22]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][1][23]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][1][0]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][1][1]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][1][2]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][1][3]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][1][4]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][1][5]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][1][6]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][1][7]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][1][8]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][2][9]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][2][10]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][2][11]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][2][12]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][2][13]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][2][14]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][2][15]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][2][16]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][2][17]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][2][18]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][2][19]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][2][20]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][2][21]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][2][22]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][2][23]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][2][0]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][2][1]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][2][2]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][2][3]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][2][4]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][2][5]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][2][6]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][2][7]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][2][8]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][3][9]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][3][10]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][3][11]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][3][12]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][3][13]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][3][14]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][3][15]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][3][16]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][3][17]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][3][18]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][3][19]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][3][20]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][3][21]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][3][22]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][3][23]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][3][0]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][3][1]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][3][2]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][3][3]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][3][4]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][3][5]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][3][6]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][3][7]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][3][8]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][4][9]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][4][10]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][4][11]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][4][12]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][4][13]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][4][14]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][4][15]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][4][16]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][4][17]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][4][18]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][4][19]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][4][20]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][4][21]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][4][22]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][4][23]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][4][0]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][4][1]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][4][2]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][4][3]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][4][4]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][4][5]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][4][6]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][4][7]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][4][8]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][5][9]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][5][10]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][5][11]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][5][12]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][5][13]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][5][14]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][5][15]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][5][16]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][5][17]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][5][18]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][5][19]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][5][20]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][5][21]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][5][22]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][5][23]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][5][0]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][5][1]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][5][2]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][5][3]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][5][4]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][5][5]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][5][6]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][5][7]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][5][8]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][6][9]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][6][10]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][6][11]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][6][12]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][6][13]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][6][14]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][6][15]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][6][16]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][6][17]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][6][18]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][6][19]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][6][20]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][6][21]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][6][22]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][6][23]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][6][0]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][6][1]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][6][2]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][6][3]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][6][4]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][6][5]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][6][6]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][6][7]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][6][8]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][0][9]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][0][10]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][0][11]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][0][12]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][0][13]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][0][14]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][0][15]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][0][16]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][0][17]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][0][18]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][0][19]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][0][20]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][0][21]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][0][22]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][0][23]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][0][0]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][0][1]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][0][2]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][0][3]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][0][4]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][0][5]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][0][6]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][0][7]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[VVVVVVVVVVVVVVVVVVVVVVV][0][8]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[WWWWWWWWWWWWWWWWWWWWWWWWW][678][ZEZE]" + +PLAPLAPLAINCINCINC +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[WWWWWWWWWWWWWWWWWWWWWWWWW][678][123412341234e]" + +SITE +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[WWWWWWWWWWWWWWWWWWWWWWWWW][678][12345678901]" + +56 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[TARTARTAR_type]" + +none +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[TARTARTAR_wizard][has_hashashas_has]" + +0 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[TARTARTAR_wizard][frefrefre_fre_freee]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[TARTARTAR_wizard][frefrefre_fre_frefre]" + +forever +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[TARTARTAR_wizard][self_block]" + +0 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[TARTARTAR_wizard][GGG_RULES][][COUCOUN]" + + +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[TARTARTAR_wizard][GGG_RULES][][REGREG]" + + +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[TARTARTAR_wizard][GGG_RULES][][c1c1]" + + +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA_TARTARTAR_wizard_rule" + + +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[TARTARTAR_rule]" + + +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[selection_selection]" + +R +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[PLAPLAPLA_MEMMEMMEMM_ATTRATTRER][new][-1][selection_selection]" + +1 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[PLAPLAPLA_MEMMEMMEMM_ATTRATTRER][new][-1][ba_unit_id]" + +1015 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[PLAPLAPLA_MEMMEMMEMM_ATTRATTRER][new][-2][selection_selection]" + +2 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[PLAPLAPLA_MEMMEMMEMM_ATTRATTRER][new][-2][ba_unit_id]" + +1017 +------WebKitFormBoundaryWsY0GnpbI5U7ztzo +Content-Disposition: form-data; name="AAAAAAAAAAAAAAAAAAA[tile_name]" + + +------WebKitFormBoundaryWsY0GnpbI5U7ztzo-- + diff --git a/vendor/plugins/rack/test/multipart/file1.txt b/vendor/plugins/rack/test/multipart/file1.txt new file mode 100644 index 00000000..0839b2e9 --- /dev/null +++ b/vendor/plugins/rack/test/multipart/file1.txt @@ -0,0 +1 @@ +contents \ No newline at end of file diff --git a/vendor/plugins/rack/test/rackup/.gitignore b/vendor/plugins/rack/test/rackup/.gitignore new file mode 100644 index 00000000..2f9d279a --- /dev/null +++ b/vendor/plugins/rack/test/rackup/.gitignore @@ -0,0 +1 @@ +log_output diff --git a/vendor/plugins/rack/test/rackup/config.ru b/vendor/plugins/rack/test/rackup/config.ru new file mode 100644 index 00000000..f1e2e1f3 --- /dev/null +++ b/vendor/plugins/rack/test/rackup/config.ru @@ -0,0 +1,31 @@ +require "#{File.dirname(__FILE__)}/../testrequest" + +$stderr = File.open("#{File.dirname(__FILE__)}/log_output", "w") + +class EnvMiddleware + def initialize(app) + @app = app + end + + def call(env) + # provides a way to test that lint is present + if env["PATH_INFO"] == "/broken_lint" + return [200, {}, ["Broken Lint"]] + # provides a way to kill the process without knowing the pid + elsif env["PATH_INFO"] == "/die" + exit! + end + + env["test.$DEBUG"] = $DEBUG + env["test.$EVAL"] = BUKKIT if defined?(BUKKIT) + env["test.$VERBOSE"] = $VERBOSE + env["test.$LOAD_PATH"] = $LOAD_PATH + env["test.stderr"] = File.expand_path($stderr.path) + env["test.Ping"] = defined?(Ping) + env["test.pid"] = Process.pid + @app.call(env) + end +end + +use EnvMiddleware +run TestRequest.new diff --git a/vendor/plugins/rack/test/spec_rack_cascade.rb b/vendor/plugins/rack/test/spec_rack_cascade.rb index 3c0f3be3..cf3c29b4 100644 --- a/vendor/plugins/rack/test/spec_rack_cascade.rb +++ b/vendor/plugins/rack/test/spec_rack_cascade.rb @@ -28,15 +28,13 @@ context "Rack::Cascade" do Rack::MockRequest.new(cascade).get("/cgi/../bla").should.be.not_found end - specify "should fail if empty" do - lambda { Rack::MockRequest.new(Rack::Cascade.new([])).get("/") }. - should.raise(ArgumentError) + specify "should return 404 if empty" do + Rack::MockRequest.new(Rack::Cascade.new([])).get('/').should.be.not_found end specify "should append new app" do cascade = Rack::Cascade.new([], [404, 403]) - lambda { Rack::MockRequest.new(cascade).get('/cgi/test') }. - should.raise(ArgumentError) + Rack::MockRequest.new(cascade).get('/').should.be.not_found cascade << app2 Rack::MockRequest.new(cascade).get('/cgi/test').should.be.not_found Rack::MockRequest.new(cascade).get('/cgi/../bla').should.be.not_found diff --git a/vendor/plugins/rack/test/spec_rack_cgi.rb b/vendor/plugins/rack/test/spec_rack_cgi.rb index 818fabdf..59500cd7 100644 --- a/vendor/plugins/rack/test/spec_rack_cgi.rb +++ b/vendor/plugins/rack/test/spec_rack_cgi.rb @@ -3,7 +3,7 @@ require 'testrequest' context "Rack::Handler::CGI" do include TestRequest::Helpers - + setup do @host = '0.0.0.0' @port = 9203 @@ -36,7 +36,7 @@ context "Rack::Handler::CGI" do specify "should have rack headers" do GET("/test") - response["rack.version"].should.equal [1,0] + response["rack.version"].should.equal [1,1] response["rack.multithread"].should.be false response["rack.multiprocess"].should.be true response["rack.run_once"].should.be true @@ -47,7 +47,7 @@ context "Rack::Handler::CGI" do response["REQUEST_METHOD"].should.equal "GET" response["SCRIPT_NAME"].should.equal "/test" response["REQUEST_PATH"].should.equal "/" - response["PATH_INFO"].should.be.nil + response["PATH_INFO"].should.equal "" response["QUERY_STRING"].should.equal "" response["test.postdata"].should.equal "" diff --git a/vendor/plugins/rack/test/spec_rack_commonlogger.rb b/vendor/plugins/rack/test/spec_rack_commonlogger.rb index ba03b78a..46a72e86 100644 --- a/vendor/plugins/rack/test/spec_rack_commonlogger.rb +++ b/vendor/plugins/rack/test/spec_rack_commonlogger.rb @@ -7,26 +7,55 @@ require 'rack/mock' context "Rack::CommonLogger" do app = lambda { |env| + [200, + {"Content-Type" => "text/html", "Content-Length" => length.to_s}, + [obj]]} + app_without_length = lambda { |env| [200, {"Content-Type" => "text/html"}, - ["foo"]]} + []]} + app_with_zero_length = lambda { |env| + [200, + {"Content-Type" => "text/html", "Content-Length" => "0"}, + []]} specify "should log to rack.errors by default" do - log = StringIO.new res = Rack::MockRequest.new(Rack::CommonLogger.new(app)).get("/") res.errors.should.not.be.empty - res.errors.should =~ /GET / - res.errors.should =~ / 200 / # status - res.errors.should =~ / 3 / # length + res.errors.should =~ /"GET \/ " 200 #{length} / end - specify "should log to anything with <<" do - log = "" + specify "should log to anything with +write+" do + log = StringIO.new res = Rack::MockRequest.new(Rack::CommonLogger.new(app, log)).get("/") - log.should =~ /GET / - log.should =~ / 200 / # status - log.should =~ / 3 / # length + log.string.should =~ /"GET \/ " 200 #{length} / + end + + specify "should log - content length if header is missing" do + res = Rack::MockRequest.new(Rack::CommonLogger.new(app_without_length)).get("/") + + res.errors.should.not.be.empty + res.errors.should =~ /"GET \/ " 200 - / + end + + specify "should log - content length if header is zero" do + res = Rack::MockRequest.new(Rack::CommonLogger.new(app_with_zero_length)).get("/") + + res.errors.should.not.be.empty + res.errors.should =~ /"GET \/ " 200 - / + end + + def length + self.class.length + end + + def self.length + 123 + end + + def self.obj + "hello world" end end diff --git a/vendor/plugins/rack/test/spec_rack_config.rb b/vendor/plugins/rack/test/spec_rack_config.rb new file mode 100644 index 00000000..a508ea4b --- /dev/null +++ b/vendor/plugins/rack/test/spec_rack_config.rb @@ -0,0 +1,24 @@ +require 'test/spec' +require 'rack/mock' +require 'rack/builder' +require 'rack/content_length' +require 'rack/config' + +context "Rack::Config" do + + specify "should accept a block that modifies the environment" do + app = Rack::Builder.new do + use Rack::Lint + use Rack::ContentLength + use Rack::Config do |env| + env['greeting'] = 'hello' + end + run lambda { |env| + [200, {'Content-Type' => 'text/plain'}, [env['greeting'] || '']] + } + end + response = Rack::MockRequest.new(app).get('/') + response.body.should.equal('hello') + end + +end diff --git a/vendor/plugins/rack/test/spec_rack_directory.rb b/vendor/plugins/rack/test/spec_rack_directory.rb index 540c728d..d255c91d 100644 --- a/vendor/plugins/rack/test/spec_rack_directory.rb +++ b/vendor/plugins/rack/test/spec_rack_directory.rb @@ -6,7 +6,7 @@ require 'rack/lint' require 'rack/mock' context "Rack::Directory" do - DOCROOT = File.expand_path(File.dirname(__FILE__)) + DOCROOT = File.expand_path(File.dirname(__FILE__)) unless defined? DOCROOT FILE_CATCH = proc{|env| [200, {'Content-Type'=>'text/plain', "Content-Length" => "7"}, ['passed!']] } app = Rack::Directory.new DOCROOT, FILE_CATCH diff --git a/vendor/plugins/rack/test/spec_rack_etag.rb b/vendor/plugins/rack/test/spec_rack_etag.rb new file mode 100644 index 00000000..73cd31ac --- /dev/null +++ b/vendor/plugins/rack/test/spec_rack_etag.rb @@ -0,0 +1,17 @@ +require 'test/spec' +require 'rack/mock' +require 'rack/etag' + +context "Rack::ETag" do + specify "sets ETag if none is set" do + app = lambda { |env| [200, {'Content-Type' => 'text/plain'}, ["Hello, World!"]] } + response = Rack::ETag.new(app).call({}) + response[1]['ETag'].should.equal "\"65a8e27d8879283831b664bd8b7f0ad4\"" + end + + specify "does not change ETag if it is already set" do + app = lambda { |env| [200, {'Content-Type' => 'text/plain', 'ETag' => '"abc"'}, ["Hello, World!"]] } + response = Rack::ETag.new(app).call({}) + response[1]['ETag'].should.equal "\"abc\"" + end +end diff --git a/vendor/plugins/rack/test/spec_rack_fastcgi.rb b/vendor/plugins/rack/test/spec_rack_fastcgi.rb index 69478de5..1ae55ace 100644 --- a/vendor/plugins/rack/test/spec_rack_fastcgi.rb +++ b/vendor/plugins/rack/test/spec_rack_fastcgi.rb @@ -36,7 +36,7 @@ context "Rack::Handler::FastCGI" do specify "should have rack headers" do GET("/test.fcgi") - response["rack.version"].should.equal [1,0] + response["rack.version"].should.equal [1,1] response["rack.multithread"].should.be false response["rack.multiprocess"].should.be true response["rack.run_once"].should.be false @@ -47,7 +47,7 @@ context "Rack::Handler::FastCGI" do response["REQUEST_METHOD"].should.equal "GET" response["SCRIPT_NAME"].should.equal "/test.fcgi" response["REQUEST_PATH"].should.equal "/" - response["PATH_INFO"].should.be.nil + response["PATH_INFO"].should.equal "" response["QUERY_STRING"].should.equal "" response["test.postdata"].should.equal "" diff --git a/vendor/plugins/rack/test/spec_rack_file.rb b/vendor/plugins/rack/test/spec_rack_file.rb index 1e6771ab..0a2f8ee8 100644 --- a/vendor/plugins/rack/test/spec_rack_file.rb +++ b/vendor/plugins/rack/test/spec_rack_file.rb @@ -6,7 +6,7 @@ require 'rack/lint' require 'rack/mock' context "Rack::File" do - DOCROOT = File.expand_path(File.dirname(__FILE__)) + DOCROOT = File.expand_path(File.dirname(__FILE__)) unless defined? DOCROOT specify "serves files" do res = Rack::MockRequest.new(Rack::Lint.new(Rack::File.new(DOCROOT))). diff --git a/vendor/plugins/rack/test/spec_rack_lint.rb b/vendor/plugins/rack/test/spec_rack_lint.rb index 880a07ee..bbf75c17 100644 --- a/vendor/plugins/rack/test/spec_rack_lint.rb +++ b/vendor/plugins/rack/test/spec_rack_lint.rb @@ -71,6 +71,11 @@ context "Rack::Lint" do }.should.raise(Rack::Lint::LintError). message.should.equal("session [] must respond to store and []=") + lambda { + Rack::Lint.new(nil).call(env("rack.logger" => [])) + }.should.raise(Rack::Lint::LintError). + message.should.equal("logger [] must respond to info") + lambda { Rack::Lint.new(nil).call(env("REQUEST_METHOD" => "FUCKUP?")) }.should.raise(Rack::Lint::LintError). @@ -110,7 +115,7 @@ context "Rack::Lint" do Rack::Lint.new(nil).call(env("rack.input" => "")) }.should.raise(Rack::Lint::LintError). message.should.match(/does not respond to #gets/) - + lambda { input = Object.new def input.binmode? @@ -119,7 +124,7 @@ context "Rack::Lint" do Rack::Lint.new(nil).call(env("rack.input" => input)) }.should.raise(Rack::Lint::LintError). message.should.match(/is not opened in binary mode/) - + lambda { input = Object.new def input.external_encoding @@ -347,25 +352,25 @@ context "Rack::Lint" do yield 23 yield 42 end - + def rewind raise Errno::ESPIPE, "Errno::ESPIPE" end end - + eof_weirdio = Object.new class << eof_weirdio def gets nil end - + def read(*args) nil end - + def each end - + def rewind end end @@ -452,48 +457,50 @@ context "Rack::Lint" do }.should.raise(Rack::Lint::LintError). message.should.match(/body was given for HEAD/) end - + specify "passes valid read calls" do + hello_str = "hello world" + hello_str.force_encoding("ASCII-8BIT") if hello_str.respond_to? :force_encoding lambda { Rack::Lint.new(lambda { |env| env["rack.input"].read [201, {"Content-type" => "text/plain", "Content-length" => "0"}, []] - }).call(env({"rack.input" => StringIO.new("hello world")})) + }).call(env({"rack.input" => StringIO.new(hello_str)})) }.should.not.raise(Rack::Lint::LintError) - + lambda { Rack::Lint.new(lambda { |env| env["rack.input"].read(0) [201, {"Content-type" => "text/plain", "Content-length" => "0"}, []] - }).call(env({"rack.input" => StringIO.new("hello world")})) + }).call(env({"rack.input" => StringIO.new(hello_str)})) }.should.not.raise(Rack::Lint::LintError) - + lambda { Rack::Lint.new(lambda { |env| env["rack.input"].read(1) [201, {"Content-type" => "text/plain", "Content-length" => "0"}, []] - }).call(env({"rack.input" => StringIO.new("hello world")})) + }).call(env({"rack.input" => StringIO.new(hello_str)})) }.should.not.raise(Rack::Lint::LintError) - + lambda { Rack::Lint.new(lambda { |env| env["rack.input"].read(nil) [201, {"Content-type" => "text/plain", "Content-length" => "0"}, []] - }).call(env({"rack.input" => StringIO.new("hello world")})) + }).call(env({"rack.input" => StringIO.new(hello_str)})) }.should.not.raise(Rack::Lint::LintError) - + lambda { Rack::Lint.new(lambda { |env| env["rack.input"].read(nil, '') [201, {"Content-type" => "text/plain", "Content-length" => "0"}, []] - }).call(env({"rack.input" => StringIO.new("hello world")})) + }).call(env({"rack.input" => StringIO.new(hello_str)})) }.should.not.raise(Rack::Lint::LintError) - + lambda { Rack::Lint.new(lambda { |env| env["rack.input"].read(1, '') [201, {"Content-type" => "text/plain", "Content-length" => "0"}, []] - }).call(env({"rack.input" => StringIO.new("hello world")})) + }).call(env({"rack.input" => StringIO.new(hello_str)})) }.should.not.raise(Rack::Lint::LintError) end end diff --git a/vendor/plugins/rack/test/spec_rack_logger.rb b/vendor/plugins/rack/test/spec_rack_logger.rb new file mode 100644 index 00000000..d55b9c77 --- /dev/null +++ b/vendor/plugins/rack/test/spec_rack_logger.rb @@ -0,0 +1,21 @@ +require 'rack/logger' +require 'rack/lint' +require 'stringio' + +context "Rack::Logger" do + specify "logs to rack.errors" do + app = lambda { |env| + log = env['rack.logger'] + log.debug("Created logger") + log.info("Program started") + log.warn("Nothing to do!") + + [200, {'Content-Type' => 'text/plain'}, ["Hello, World!"]] + } + + errors = StringIO.new + Rack::Logger.new(app).call({'rack.errors' => errors}) + errors.string.should.match "INFO -- : Program started" + errors.string.should.match "WARN -- : Nothing to do" + end +end diff --git a/vendor/plugins/rack/test/spec_rack_mock.rb b/vendor/plugins/rack/test/spec_rack_mock.rb index 9c392a28..a03bedc2 100644 --- a/vendor/plugins/rack/test/spec_rack_mock.rb +++ b/vendor/plugins/rack/test/spec_rack_mock.rb @@ -93,6 +93,92 @@ context "Rack::MockRequest" do env["rack.url_scheme"].should.equal "https" end + specify "should set SSL port and HTTP flag on when using https" do + res = Rack::MockRequest.new(app). + get("https://example.org/foo") + res.should.be.kind_of Rack::MockResponse + + env = YAML.load(res.body) + env["REQUEST_METHOD"].should.equal "GET" + env["SERVER_NAME"].should.equal "example.org" + env["SERVER_PORT"].should.equal "443" + env["QUERY_STRING"].should.equal "" + env["PATH_INFO"].should.equal "/foo" + env["rack.url_scheme"].should.equal "https" + env["HTTPS"].should.equal "on" + end + + specify "should prepend slash to uri path" do + res = Rack::MockRequest.new(app). + get("foo") + res.should.be.kind_of Rack::MockResponse + + env = YAML.load(res.body) + env["REQUEST_METHOD"].should.equal "GET" + env["SERVER_NAME"].should.equal "example.org" + env["SERVER_PORT"].should.equal "80" + env["QUERY_STRING"].should.equal "" + env["PATH_INFO"].should.equal "/foo" + env["rack.url_scheme"].should.equal "http" + end + + specify "should properly convert method name to an uppercase string" do + res = Rack::MockRequest.new(app).request(:get) + env = YAML.load(res.body) + env["REQUEST_METHOD"].should.equal "GET" + end + + specify "should accept params and build query string for GET requests" do + res = Rack::MockRequest.new(app).get("/foo?baz=2", :params => {:foo => {:bar => "1"}}) + env = YAML.load(res.body) + env["REQUEST_METHOD"].should.equal "GET" + env["QUERY_STRING"].should.match "baz=2" + env["QUERY_STRING"].should.match "foo[bar]=1" + env["PATH_INFO"].should.equal "/foo" + env["mock.postdata"].should.equal "" + end + + specify "should accept raw input in params for GET requests" do + res = Rack::MockRequest.new(app).get("/foo?baz=2", :params => "foo[bar]=1") + env = YAML.load(res.body) + env["REQUEST_METHOD"].should.equal "GET" + env["QUERY_STRING"].should.match "baz=2" + env["QUERY_STRING"].should.match "foo[bar]=1" + env["PATH_INFO"].should.equal "/foo" + env["mock.postdata"].should.equal "" + end + + specify "should accept params and build url encoded params for POST requests" do + res = Rack::MockRequest.new(app).post("/foo", :params => {:foo => {:bar => "1"}}) + env = YAML.load(res.body) + env["REQUEST_METHOD"].should.equal "POST" + env["QUERY_STRING"].should.equal "" + env["PATH_INFO"].should.equal "/foo" + env["CONTENT_TYPE"].should.equal "application/x-www-form-urlencoded" + env["mock.postdata"].should.equal "foo[bar]=1" + end + + specify "should accept raw input in params for POST requests" do + res = Rack::MockRequest.new(app).post("/foo", :params => "foo[bar]=1") + env = YAML.load(res.body) + env["REQUEST_METHOD"].should.equal "POST" + env["QUERY_STRING"].should.equal "" + env["PATH_INFO"].should.equal "/foo" + env["CONTENT_TYPE"].should.equal "application/x-www-form-urlencoded" + env["mock.postdata"].should.equal "foo[bar]=1" + end + + specify "should accept params and build multipart encoded params for POST requests" do + files = Rack::Utils::Multipart::UploadedFile.new(File.join(File.dirname(__FILE__), "multipart", "file1.txt")) + res = Rack::MockRequest.new(app).post("/foo", :params => { "submit-name" => "Larry", "files" => files }) + env = YAML.load(res.body) + env["REQUEST_METHOD"].should.equal "POST" + env["QUERY_STRING"].should.equal "" + env["PATH_INFO"].should.equal "/foo" + env["CONTENT_TYPE"].should.equal "multipart/form-data; boundary=AaB03x" + env["mock.postdata"].length.should.equal 206 + end + specify "should behave valid according to the Rack spec" do lambda { res = Rack::MockRequest.new(app). @@ -130,7 +216,7 @@ context "Rack::MockResponse" do res.original_headers["Content-Type"].should.equal "text/yaml" res["Content-Type"].should.equal "text/yaml" res.content_type.should.equal "text/yaml" - res.content_length.should.be 401 # needs change often. + res.content_length.should.be 414 # needs change often. res.location.should.be.nil end diff --git a/vendor/plugins/rack/test/spec_rack_mongrel.rb b/vendor/plugins/rack/test/spec_rack_mongrel.rb index d73e884c..4b386891 100644 --- a/vendor/plugins/rack/test/spec_rack_mongrel.rb +++ b/vendor/plugins/rack/test/spec_rack_mongrel.rb @@ -6,14 +6,14 @@ require 'rack/urlmap' require 'rack/lint' require 'testrequest' require 'timeout' - + Thread.abort_on_exception = true $tcp_defer_accept_opts = nil $tcp_cork_opts = nil context "Rack::Handler::Mongrel" do include TestRequest::Helpers - + setup do server = Mongrel::HttpServer.new(@host='0.0.0.0', @port=9201) server.register('/test', @@ -41,7 +41,7 @@ context "Rack::Handler::Mongrel" do specify "should have rack headers" do GET("/test") - response["rack.version"].should.equal [1,0] + response["rack.version"].should.equal [1,1] response["rack.multithread"].should.be true response["rack.multiprocess"].should.be false response["rack.run_once"].should.be false @@ -52,7 +52,7 @@ context "Rack::Handler::Mongrel" do response["REQUEST_METHOD"].should.equal "GET" response["SCRIPT_NAME"].should.equal "/test" response["REQUEST_PATH"].should.equal "/test" - response["PATH_INFO"].should.be.nil + response["PATH_INFO"].should.be.equal "" response["QUERY_STRING"].should.equal "" response["test.postdata"].should.equal "" diff --git a/vendor/plugins/rack/test/spec_rack_nulllogger.rb b/vendor/plugins/rack/test/spec_rack_nulllogger.rb new file mode 100644 index 00000000..b3c2bc9c --- /dev/null +++ b/vendor/plugins/rack/test/spec_rack_nulllogger.rb @@ -0,0 +1,13 @@ +require 'rack/nulllogger' +require 'rack/lint' +require 'rack/mock' + +context "Rack::NullLogger" do + specify "acks as a nop logger" do + app = lambda { |env| + env['rack.logger'].warn "b00m" + [200, {'Content-Type' => 'text/plain'}, ["Hello, World!"]] + } + Rack::NullLogger.new(app).call({}) + end +end diff --git a/vendor/plugins/rack/test/spec_rack_request.rb b/vendor/plugins/rack/test/spec_rack_request.rb index 74e2f00a..fcdeb484 100644 --- a/vendor/plugins/rack/test/spec_rack_request.rb +++ b/vendor/plugins/rack/test/spec_rack_request.rb @@ -35,9 +35,18 @@ context "Rack::Request" do req.host.should.equal "www2.example.org" req = Rack::Request.new \ - Rack::MockRequest.env_for("/", "SERVER_NAME" => "example.org:9292") + Rack::MockRequest.env_for("/", "SERVER_NAME" => "example.org", "SERVER_PORT" => "9292") req.host.should.equal "example.org" + req = Rack::Request.new \ + Rack::MockRequest.env_for("/", "HTTP_HOST" => "localhost:81", "HTTP_X_FORWARDED_HOST" => "example.org:9292") + req.host.should.equal "example.org" + + env = Rack::MockRequest.env_for("/", "SERVER_ADDR" => "192.168.1.1", "SERVER_PORT" => "9292") + env.delete("SERVER_NAME") + req = Rack::Request.new(env) + req.host.should.equal "192.168.1.1" + env = Rack::MockRequest.env_for("/") env.delete("SERVER_NAME") req = Rack::Request.new(env) @@ -52,9 +61,16 @@ context "Rack::Request" do req.params.should.equal "foo" => "bar", "quux" => "bla" end - specify "can parse POST data" do + specify "raises if rack.input is missing" do + req = Rack::Request.new({}) + lambda { req.POST }.should.raise(RuntimeError) + end + + specify "can parse POST data when method is POST and no Content-Type given" do req = Rack::Request.new \ - Rack::MockRequest.env_for("/?foo=quux", :input => "foo=bar&quux=bla") + Rack::MockRequest.env_for("/?foo=quux", + "REQUEST_METHOD" => 'POST', + :input => "foo=bar&quux=bla") req.content_type.should.be.nil req.media_type.should.be.nil req.query_string.should.equal "foo=quux" @@ -63,7 +79,7 @@ context "Rack::Request" do req.params.should.equal "foo" => "bar", "quux" => "bla" end - specify "can parse POST data with explicit content type" do + specify "can parse POST data with explicit content type regardless of method" do req = Rack::Request.new \ Rack::MockRequest.env_for("/", "CONTENT_TYPE" => 'application/x-www-form-urlencoded;foo=bar', @@ -78,6 +94,7 @@ context "Rack::Request" do specify "does not parse POST data when media type is not form-data" do req = Rack::Request.new \ Rack::MockRequest.env_for("/?foo=quux", + "REQUEST_METHOD" => 'POST', "CONTENT_TYPE" => 'text/plain;charset=utf-8', :input => "foo=bar&quux=bla") req.content_type.should.equal 'text/plain;charset=utf-8' @@ -88,6 +105,16 @@ context "Rack::Request" do req.body.read.should.equal "foo=bar&quux=bla" end + specify "can parse POST data on PUT when media type is form-data" do + req = Rack::Request.new \ + Rack::MockRequest.env_for("/?foo=quux", + "REQUEST_METHOD" => 'PUT', + "CONTENT_TYPE" => 'application/x-www-form-urlencoded', + :input => "foo=bar&quux=bla") + req.POST.should.equal "foo" => "bar", "quux" => "bla" + req.body.read.should.equal "foo=bar&quux=bla" + end + specify "rewinds input after parsing POST data" do input = StringIO.new("foo=bar&quux=bla") req = Rack::Request.new \ @@ -100,7 +127,8 @@ context "Rack::Request" do specify "cleans up Safari's ajax POST body" do req = Rack::Request.new \ - Rack::MockRequest.env_for("/", :input => "foo=bar&quux=bla\0") + Rack::MockRequest.env_for("/", + 'REQUEST_METHOD' => 'POST', :input => "foo=bar&quux=bla\0") req.POST.should.equal "foo" => "bar", "quux" => "bla" end @@ -147,9 +175,21 @@ context "Rack::Request" do req.referer.should.equal "/" end + specify "user agent should be extracted correct" do + req = Rack::Request.new \ + Rack::MockRequest.env_for("/", "HTTP_USER_AGENT" => "Mozilla/4.0 (compatible)") + req.user_agent.should.equal "Mozilla/4.0 (compatible)" + + req = Rack::Request.new \ + Rack::MockRequest.env_for("/") + req.user_agent.should.equal nil + end + specify "can cache, but invalidates the cache" do req = Rack::Request.new \ - Rack::MockRequest.env_for("/?foo=quux", :input => "foo=bar&quux=bla") + Rack::MockRequest.env_for("/?foo=quux", + "CONTENT_TYPE" => "application/x-www-form-urlencoded", + :input => "foo=bar&quux=bla") req.GET.should.equal "foo" => "quux" req.GET.should.equal "foo" => "quux" req.env["QUERY_STRING"] = "bla=foo" @@ -424,6 +464,7 @@ Content-Transfer-Encoding: base64\r /9j/4AAQSkZJRgABAQAAAQABAAD//gA+Q1JFQVRPUjogZ2QtanBlZyB2MS4wICh1c2luZyBJSkcg\r --AaB03x--\r EOF + input.force_encoding("ASCII-8BIT") if input.respond_to? :force_encoding res = Rack::MockRequest.new(Rack::Lint.new(app)).get "/", "CONTENT_TYPE" => "multipart/form-data, boundary=AaB03x", "CONTENT_LENGTH" => input.size.to_s, "rack.input" => StringIO.new(input) diff --git a/vendor/plugins/rack/test/spec_rack_response.rb b/vendor/plugins/rack/test/spec_rack_response.rb index eb59b5c2..7989013d 100644 --- a/vendor/plugins/rack/test/spec_rack_response.rb +++ b/vendor/plugins/rack/test/spec_rack_response.rb @@ -118,6 +118,9 @@ context "Rack::Response" do r = Rack::Response.new([], 500) r.status.should.equal 500 + + r = Rack::Response.new([], "200 OK") + r.status.should.equal 200 end specify "has a constructor that can take a block" do diff --git a/vendor/plugins/rack/test/spec_rack_runtime.rb b/vendor/plugins/rack/test/spec_rack_runtime.rb new file mode 100644 index 00000000..62d80956 --- /dev/null +++ b/vendor/plugins/rack/test/spec_rack_runtime.rb @@ -0,0 +1,35 @@ +require 'test/spec' +require 'rack/mock' +require 'rack/runtime' + +context "Rack::Runtime" do + specify "sets X-Runtime is none is set" do + app = lambda { |env| [200, {'Content-Type' => 'text/plain'}, "Hello, World!"] } + response = Rack::Runtime.new(app).call({}) + response[1]['X-Runtime'].should =~ /[\d\.]+/ + end + + specify "does not set the X-Runtime if it is already set" do + app = lambda { |env| [200, {'Content-Type' => 'text/plain', "X-Runtime" => "foobar"}, "Hello, World!"] } + response = Rack::Runtime.new(app).call({}) + response[1]['X-Runtime'].should == "foobar" + end + + specify "should allow a suffix to be set" do + app = lambda { |env| [200, {'Content-Type' => 'text/plain'}, "Hello, World!"] } + response = Rack::Runtime.new(app, "Test").call({}) + response[1]['X-Runtime-Test'].should =~ /[\d\.]+/ + end + + specify "should allow multiple timers to be set" do + app = lambda { |env| [200, {'Content-Type' => 'text/plain'}, "Hello, World!"] } + runtime1 = Rack::Runtime.new(app, "App") + runtime2 = Rack::Runtime.new(runtime1, "All") + response = runtime2.call({}) + + response[1]['X-Runtime-App'].should =~ /[\d\.]+/ + response[1]['X-Runtime-All'].should =~ /[\d\.]+/ + + Float(response[1]['X-Runtime-All']).should > Float(response[1]['X-Runtime-App']) + end +end diff --git a/vendor/plugins/rack/test/spec_rack_sendfile.rb b/vendor/plugins/rack/test/spec_rack_sendfile.rb new file mode 100644 index 00000000..8cfe2017 --- /dev/null +++ b/vendor/plugins/rack/test/spec_rack_sendfile.rb @@ -0,0 +1,86 @@ +require 'test/spec' +require 'rack/mock' +require 'rack/sendfile' + +context "Rack::File" do + specify "should respond to #to_path" do + Rack::File.new(Dir.pwd).should.respond_to :to_path + end +end + +context "Rack::Sendfile" do + def sendfile_body + res = ['Hello World'] + def res.to_path ; "/tmp/hello.txt" ; end + res + end + + def simple_app(body=sendfile_body) + lambda { |env| [200, {'Content-Type' => 'text/plain'}, body] } + end + + def sendfile_app(body=sendfile_body) + Rack::Sendfile.new(simple_app(body)) + end + + setup do + @request = Rack::MockRequest.new(sendfile_app) + end + + def request(headers={}) + yield @request.get('/', headers) + end + + specify "does nothing when no X-Sendfile-Type header present" do + request do |response| + response.should.be.ok + response.body.should.equal 'Hello World' + response.headers.should.not.include 'X-Sendfile' + end + end + + specify "sets X-Sendfile response header and discards body" do + request 'HTTP_X_SENDFILE_TYPE' => 'X-Sendfile' do |response| + response.should.be.ok + response.body.should.be.empty + response.headers['X-Sendfile'].should.equal '/tmp/hello.txt' + end + end + + specify "sets X-Lighttpd-Send-File response header and discards body" do + request 'HTTP_X_SENDFILE_TYPE' => 'X-Lighttpd-Send-File' do |response| + response.should.be.ok + response.body.should.be.empty + response.headers['X-Lighttpd-Send-File'].should.equal '/tmp/hello.txt' + end + end + + specify "sets X-Accel-Redirect response header and discards body" do + headers = { + 'HTTP_X_SENDFILE_TYPE' => 'X-Accel-Redirect', + 'HTTP_X_ACCEL_MAPPING' => '/tmp/=/foo/bar/' + } + request headers do |response| + response.should.be.ok + response.body.should.be.empty + response.headers['X-Accel-Redirect'].should.equal '/foo/bar/hello.txt' + end + end + + specify 'writes to rack.error when no X-Accel-Mapping is specified' do + request 'HTTP_X_SENDFILE_TYPE' => 'X-Accel-Redirect' do |response| + response.should.be.ok + response.body.should.equal 'Hello World' + response.headers.should.not.include 'X-Accel-Redirect' + response.errors.should.include 'X-Accel-Mapping' + end + end + + specify 'does nothing when body does not respond to #to_path' do + @request = Rack::MockRequest.new(sendfile_app(['Not a file...'])) + request 'HTTP_X_SENDFILE_TYPE' => 'X-Sendfile' do |response| + response.body.should.equal 'Not a file...' + response.headers.should.not.include 'X-Sendfile' + end + end +end diff --git a/vendor/plugins/rack/test/spec_rack_session_memcache.rb b/vendor/plugins/rack/test/spec_rack_session_memcache.rb index 37c3d895..faac796e 100644 --- a/vendor/plugins/rack/test/spec_rack_session_memcache.rb +++ b/vendor/plugins/rack/test/spec_rack_session_memcache.rb @@ -8,7 +8,7 @@ begin context "Rack::Session::Memcache" do session_key = Rack::Session::Memcache::DEFAULT_OPTIONS[:key] - session_match = /#{session_key}=[0-9a-fA-F]+;/ + session_match = /#{session_key}=([0-9a-fA-F]+);/ incrementor = lambda do |env| env["rack.session"]["counter"] ||= 0 env["rack.session"]["counter"] += 1 @@ -27,14 +27,20 @@ begin incrementor.call(env) end - specify "MemCache can connect to existing server" do - test_pool = MemCache.new :namespace => 'test:rack:session' + specify "faults on no connection" do + if RUBY_VERSION < "1.9" + lambda do + Rack::Session::Memcache.new incrementor, :memcache_server => 'nosuchserver' + end.should.raise + else + lambda do + Rack::Session::Memcache.new incrementor, :memcache_server => 'nosuchserver' + end.should.raise ArgumentError + end end - specify "faults on no connection" do - lambda do - Rack::Session::Memcache.new(incrementor, :memcache_server => '') - end.should.raise + specify "connect to existing server" do + test_pool = MemCache.new incrementor, :namespace => 'test:rack:session' end specify "creates a new cookie" do @@ -151,6 +157,31 @@ begin res3.body.should.equal '{"counter"=>4}' end + specify "deep hashes are correctly updated" do + store = nil + hash_check = proc do |env| + session = env['rack.session'] + unless session.include? 'test' + session.update :a => :b, :c => { :d => :e }, + :f => { :g => { :h => :i} }, 'test' => true + else + session[:f][:g][:h] = :j + end + [200, {}, session.inspect] + end + pool = Rack::Session::Memcache.new(hash_check) + req = Rack::MockRequest.new(pool) + + res0 = req.get("/") + session_id = (cookie = res0["Set-Cookie"])[session_match, 1] + ses0 = pool.pool.get(session_id, true) + + res1 = req.get("/", "HTTP_COOKIE" => cookie) + ses1 = pool.pool.get(session_id, true) + + ses1.should.not.equal ses0 + end + # anyone know how to do this better? specify "multithread: should cleanly merge sessions" do next unless $DEBUG @@ -161,7 +192,7 @@ begin res = req.get('/') res.body.should.equal '{"counter"=>1}' cookie = res["Set-Cookie"] - sess_id = cookie[/#{pool.key}=([^,;]+)/,1] + session_id = cookie[session_match, 1] delta_incrementor = lambda do |env| # emulate disconjoinment of threading @@ -178,12 +209,12 @@ begin run.get('/', "HTTP_COOKIE" => cookie, 'rack.multithread' => true) end end.reverse.map{|t| t.run.join.value } - r.each do |res| - res['Set-Cookie'].should.equal cookie - res.body.should.include '"counter"=>2' + r.each do |request| + request['Set-Cookie'].should.equal cookie + request.body.should.include '"counter"=>2' end - session = pool.pool.get(sess_id) + session = pool.pool.get(session_id) session.size.should.be tnum+1 # counter session['counter'].should.be 2 # meeeh @@ -202,12 +233,12 @@ begin run.get('/', "HTTP_COOKIE" => cookie, 'rack.multithread' => true) end end.reverse.map{|t| t.run.join.value } - r.each do |res| - res['Set-Cookie'].should.equal cookie - res.body.should.include '"counter"=>3' + r.each do |request| + request['Set-Cookie'].should.equal cookie + request.body.should.include '"counter"=>3' end - session = pool.pool.get(sess_id) + session = pool.pool.get(session_id) session.size.should.be tnum+1 session['counter'].should.be 3 @@ -224,17 +255,19 @@ begin run.get('/', "HTTP_COOKIE" => cookie, 'rack.multithread' => true) end end.reverse.map{|t| t.run.join.value } - r.each do |res| - res['Set-Cookie'].should.equal cookie - res.body.should.include '"foo"=>"bar"' + r.each do |request| + request['Set-Cookie'].should.equal cookie + request.body.should.include '"foo"=>"bar"' end - session = pool.pool.get(sess_id) + session = pool.pool.get(session_id) session.size.should.be r.size+1 session['counter'].should.be.nil? session['foo'].should.equal 'bar' end end +rescue RuntimeError + $stderr.puts "Skipping Rack::Session::Memcache tests. Start memcached and try again." rescue LoadError $stderr.puts "Skipping Rack::Session::Memcache tests (Memcache is required). `gem install memcache-client` and try again." end diff --git a/vendor/plugins/rack/test/spec_rack_urlmap.rb b/vendor/plugins/rack/test/spec_rack_urlmap.rb index 6c4d72ac..3d8fe605 100644 --- a/vendor/plugins/rack/test/spec_rack_urlmap.rb +++ b/vendor/plugins/rack/test/spec_rack_urlmap.rb @@ -44,6 +44,12 @@ context "Rack::URLMap" do res["X-ScriptName"].should.equal "/foo/bar" res["X-PathInfo"].should.equal "/" + res = Rack::MockRequest.new(map).get("/foo///bar//quux") + res.status.should.equal 200 + res.should.be.ok + res["X-ScriptName"].should.equal "/foo/bar" + res["X-PathInfo"].should.equal "//quux" + res = Rack::MockRequest.new(map).get("/foo/quux", "SCRIPT_NAME" => "/bleh") res.should.be.ok res["X-ScriptName"].should.equal "/bleh/foo" @@ -182,4 +188,28 @@ context "Rack::URLMap" do res["X-PathInfo"].should.equal "/" res["X-ScriptName"].should.equal "" end + + specify "should not squeeze slashes" do + map = Rack::URLMap.new("/" => lambda { |env| + [200, + { "Content-Type" => "text/plain", + "X-Position" => "root", + "X-PathInfo" => env["PATH_INFO"], + "X-ScriptName" => env["SCRIPT_NAME"] + }, [""]]}, + "/foo" => lambda { |env| + [200, + { "Content-Type" => "text/plain", + "X-Position" => "foo", + "X-PathInfo" => env["PATH_INFO"], + "X-ScriptName" => env["SCRIPT_NAME"] + }, [""]]} + ) + + res = Rack::MockRequest.new(map).get("/http://example.org/bar") + res.should.be.ok + res["X-Position"].should.equal "root" + res["X-PathInfo"].should.equal "/http://example.org/bar" + res["X-ScriptName"].should.equal "" + end end diff --git a/vendor/plugins/rack/test/spec_rack_utils.rb b/vendor/plugins/rack/test/spec_rack_utils.rb index f270e87e..269a52bd 100644 --- a/vendor/plugins/rack/test/spec_rack_utils.rb +++ b/vendor/plugins/rack/test/spec_rack_utils.rb @@ -30,7 +30,10 @@ context "Rack::Utils" do end specify "should parse query strings correctly" do - Rack::Utils.parse_query("foo=bar").should.equal "foo" => "bar" + Rack::Utils.parse_query("foo=bar"). + should.equal "foo" => "bar" + Rack::Utils.parse_query("foo=\"bar\""). + should.equal "foo" => "bar" Rack::Utils.parse_query("foo=bar&foo=quux"). should.equal "foo" => ["bar", "quux"] Rack::Utils.parse_query("foo=1&bar=2"). @@ -47,6 +50,8 @@ context "Rack::Utils" do should.equal "foo" => "" Rack::Utils.parse_nested_query("foo=bar"). should.equal "foo" => "bar" + Rack::Utils.parse_nested_query("foo=\"bar\""). + should.equal "foo" => "bar" Rack::Utils.parse_nested_query("foo=bar&foo=quux"). should.equal "foo" => "quux" @@ -126,6 +131,53 @@ context "Rack::Utils" do should.equal "my+weird+field=q1%212%22%27w%245%267%2Fz8%29%3F" end + specify "should build nested query strings correctly" do + Rack::Utils.build_nested_query("foo" => nil).should.equal "foo" + Rack::Utils.build_nested_query("foo" => "").should.equal "foo=" + Rack::Utils.build_nested_query("foo" => "bar").should.equal "foo=bar" + + Rack::Utils.build_nested_query("foo" => "1", "bar" => "2"). + should.equal "foo=1&bar=2" + Rack::Utils.build_nested_query("my weird field" => "q1!2\"'w$5&7/z8)?"). + should.equal "my+weird+field=q1%212%22%27w%245%267%2Fz8%29%3F" + + Rack::Utils.build_nested_query("foo" => [nil]). + should.equal "foo[]" + Rack::Utils.build_nested_query("foo" => [""]). + should.equal "foo[]=" + Rack::Utils.build_nested_query("foo" => ["bar"]). + should.equal "foo[]=bar" + + # The ordering of the output query string is unpredictable with 1.8's + # unordered hash. Test that build_nested_query performs the inverse + # function of parse_nested_query. + [{"foo" => nil, "bar" => ""}, + {"foo" => "bar", "baz" => ""}, + {"foo" => ["1", "2"]}, + {"foo" => "bar", "baz" => ["1", "2", "3"]}, + {"foo" => ["bar"], "baz" => ["1", "2", "3"]}, + {"foo" => ["1", "2"]}, + {"foo" => "bar", "baz" => ["1", "2", "3"]}, + {"x" => {"y" => {"z" => "1"}}}, + {"x" => {"y" => {"z" => ["1"]}}}, + {"x" => {"y" => {"z" => ["1", "2"]}}}, + {"x" => {"y" => [{"z" => "1"}]}}, + {"x" => {"y" => [{"z" => ["1"]}]}}, + {"x" => {"y" => [{"z" => "1", "w" => "2"}]}}, + {"x" => {"y" => [{"v" => {"w" => "1"}}]}}, + {"x" => {"y" => [{"z" => "1", "v" => {"w" => "2"}}]}}, + {"x" => {"y" => [{"z" => "1"}, {"z" => "2"}]}}, + {"x" => {"y" => [{"z" => "1", "w" => "a"}, {"z" => "2", "w" => "3"}]}} + ].each { |params| + qs = Rack::Utils.build_nested_query(params) + Rack::Utils.parse_nested_query(qs).should.equal params + } + + lambda { Rack::Utils.build_nested_query("foo=bar") }. + should.raise(ArgumentError). + message.should.equal "value must be a Hash" + end + specify "should figure out which encodings are acceptable" do helper = lambda do |a, b| request = Rack::Request.new(Rack::MockRequest.env_for("", "HTTP_ACCEPT_ENCODING" => a)) @@ -152,6 +204,18 @@ context "Rack::Utils" do specify "should return the bytesize of String" do Rack::Utils.bytesize("FOO\xE2\x82\xAC").should.equal 6 end + + specify "should return status code for integer" do + Rack::Utils.status_code(200).should.equal 200 + end + + specify "should return status code for string" do + Rack::Utils.status_code("200").should.equal 200 + end + + specify "should return status code for symbol" do + Rack::Utils.status_code(:ok).should.equal 200 + end end context "Rack::Utils::HeaderHash" do @@ -190,30 +254,53 @@ context "Rack::Utils::HeaderHash" do h = Rack::Utils::HeaderHash.new("foo" => ["bar", "baz"]) h.to_hash.should.equal({ "foo" => "bar\nbaz" }) end - + + specify "should replace hashes correctly" do + h = Rack::Utils::HeaderHash.new("Foo-Bar" => "baz") + j = {"foo" => "bar"} + h.replace(j) + h["foo"].should.equal "bar" + end + specify "should be able to delete the given key case-sensitively" do h = Rack::Utils::HeaderHash.new("foo" => "bar") h.delete("foo") h["foo"].should.be.nil h["FOO"].should.be.nil end - + specify "should be able to delete the given key case-insensitively" do h = Rack::Utils::HeaderHash.new("foo" => "bar") h.delete("FOO") h["foo"].should.be.nil h["FOO"].should.be.nil end - + specify "should return the deleted value when #delete is called on an existing key" do h = Rack::Utils::HeaderHash.new("foo" => "bar") h.delete("Foo").should.equal("bar") end - + specify "should return nil when #delete is called on a non-existant key" do h = Rack::Utils::HeaderHash.new("foo" => "bar") h.delete("Hello").should.be.nil end + + specify "should avoid unnecessary object creation if possible" do + a = Rack::Utils::HeaderHash.new("foo" => "bar") + b = Rack::Utils::HeaderHash.new(a) + b.object_id.should.equal(a.object_id) + b.should.equal(a) + end + + specify "should convert Array values to Strings when responding to #each" do + h = Rack::Utils::HeaderHash.new("foo" => ["bar", "baz"]) + h.each do |k,v| + k.should.equal("foo") + v.should.equal("bar\nbaz") + end + end + end context "Rack::Utils::Context" do @@ -372,9 +459,83 @@ context "Rack::Utils::Multipart" do input.read.length.should.equal 197 end + specify "builds multipart body" do + files = Rack::Utils::Multipart::UploadedFile.new(multipart_file("file1.txt")) + data = Rack::Utils::Multipart.build_multipart("submit-name" => "Larry", "files" => files) + + options = { + "CONTENT_TYPE" => "multipart/form-data; boundary=AaB03x", + "CONTENT_LENGTH" => data.length.to_s, + :input => StringIO.new(data) + } + env = Rack::MockRequest.env_for("/", options) + params = Rack::Utils::Multipart.parse_multipart(env) + params["submit-name"].should.equal "Larry" + params["files"][:filename].should.equal "file1.txt" + params["files"][:tempfile].read.should.equal "contents" + end + + specify "builds nested multipart body" do + files = Rack::Utils::Multipart::UploadedFile.new(multipart_file("file1.txt")) + data = Rack::Utils::Multipart.build_multipart("people" => [{"submit-name" => "Larry", "files" => files}]) + + options = { + "CONTENT_TYPE" => "multipart/form-data; boundary=AaB03x", + "CONTENT_LENGTH" => data.length.to_s, + :input => StringIO.new(data) + } + env = Rack::MockRequest.env_for("/", options) + params = Rack::Utils::Multipart.parse_multipart(env) + params["people"][0]["submit-name"].should.equal "Larry" + params["people"][0]["files"][:filename].should.equal "file1.txt" + params["people"][0]["files"][:tempfile].read.should.equal "contents" + end + + specify "can parse fields that end at the end of the buffer" do + input = File.read(multipart_file("bad_robots")) + + req = Rack::Request.new Rack::MockRequest.env_for("/", + "CONTENT_TYPE" => "multipart/form-data, boundary=1yy3laWhgX31qpiHinh67wJXqKalukEUTvqTzmon", + "CONTENT_LENGTH" => input.size, + :input => input) + + req.POST['file.path'].should.equal "/var/tmp/uploads/4/0001728414" + req.POST['addresses'].should.not.equal nil + end + + specify "builds complete params with the chunk size of 16384 slicing exactly on boundary" do + data = File.open(multipart_file("fail_16384_nofile")) { |f| f.read }.gsub(/\n/, "\r\n") + options = { + "CONTENT_TYPE" => "multipart/form-data; boundary=----WebKitFormBoundaryWsY0GnpbI5U7ztzo", + "CONTENT_LENGTH" => data.length.to_s, + :input => StringIO.new(data) + } + env = Rack::MockRequest.env_for("/", options) + params = Rack::Utils::Multipart.parse_multipart(env) + + params.should.not.equal nil + params.keys.should.include "AAAAAAAAAAAAAAAAAAA" + params["AAAAAAAAAAAAAAAAAAA"].keys.should.include "PLAPLAPLA_MEMMEMMEMM_ATTRATTRER" + params["AAAAAAAAAAAAAAAAAAA"]["PLAPLAPLA_MEMMEMMEMM_ATTRATTRER"].keys.should.include "new" + params["AAAAAAAAAAAAAAAAAAA"]["PLAPLAPLA_MEMMEMMEMM_ATTRATTRER"]["new"].keys.should.include "-2" + params["AAAAAAAAAAAAAAAAAAA"]["PLAPLAPLA_MEMMEMMEMM_ATTRATTRER"]["new"]["-2"].keys.should.include "ba_unit_id" + params["AAAAAAAAAAAAAAAAAAA"]["PLAPLAPLA_MEMMEMMEMM_ATTRATTRER"]["new"]["-2"]["ba_unit_id"].should.equal "1017" + end + + specify "should return nil if no UploadedFiles were used" do + data = Rack::Utils::Multipart.build_multipart("people" => [{"submit-name" => "Larry", "files" => "contents"}]) + data.should.equal nil + end + + specify "should raise ArgumentError if params is not a Hash" do + lambda { Rack::Utils::Multipart.build_multipart("foo=bar") }. + should.raise(ArgumentError). + message.should.equal "value must be a Hash" + end + private def multipart_fixture(name) - file = File.join(File.dirname(__FILE__), "multipart", name.to_s) + file = multipart_file(name) data = File.open(file, 'rb') { |io| io.read } type = "multipart/form-data; boundary=AaB03x" @@ -384,4 +545,8 @@ context "Rack::Utils::Multipart" do "CONTENT_LENGTH" => length.to_s, :input => StringIO.new(data) } end + + def multipart_file(name) + File.join(File.dirname(__FILE__), "multipart", name.to_s) + end end diff --git a/vendor/plugins/rack/test/spec_rack_webrick.rb b/vendor/plugins/rack/test/spec_rack_webrick.rb index 3e63ea63..599425c4 100644 --- a/vendor/plugins/rack/test/spec_rack_webrick.rb +++ b/vendor/plugins/rack/test/spec_rack_webrick.rb @@ -9,7 +9,7 @@ Thread.abort_on_exception = true context "Rack::Handler::WEBrick" do include TestRequest::Helpers - + setup do @server = WEBrick::HTTPServer.new(:Host => @host='0.0.0.0', :Port => @port=9202, @@ -39,7 +39,7 @@ context "Rack::Handler::WEBrick" do specify "should have rack headers" do GET("/test") - response["rack.version"].should.equal [1,0] + response["rack.version"].should.equal [1,1] response["rack.multithread"].should.be true response["rack.multiprocess"].should.be false response["rack.run_once"].should.be false @@ -50,7 +50,7 @@ context "Rack::Handler::WEBrick" do response["REQUEST_METHOD"].should.equal "GET" response["SCRIPT_NAME"].should.equal "/test" response["REQUEST_PATH"].should.equal "/" - response["PATH_INFO"].should.be.nil + response["PATH_INFO"].should.be.equal "" response["QUERY_STRING"].should.equal "" response["test.postdata"].should.equal "" @@ -60,7 +60,7 @@ context "Rack::Handler::WEBrick" do response["REQUEST_PATH"].should.equal "/" response["PATH_INFO"].should.equal "/foo" response["QUERY_STRING"].should.equal "quux=1" - + GET("/test/foo%25encoding?quux=1") response["REQUEST_METHOD"].should.equal "GET" response["SCRIPT_NAME"].should.equal "/test" diff --git a/vendor/plugins/rack/test/spec_rackup.rb b/vendor/plugins/rack/test/spec_rackup.rb new file mode 100644 index 00000000..d9926fda --- /dev/null +++ b/vendor/plugins/rack/test/spec_rackup.rb @@ -0,0 +1,154 @@ +require 'test/spec' +require 'testrequest' +require 'rack/server' +require 'open3' + +begin +require "mongrel" + +context "rackup" do + include TestRequest::Helpers + + def run_rackup(*args) + options = args.last.is_a?(Hash) ? args.pop : {} + flags = args.first + @host = options[:host] || "0.0.0.0" + @port = options[:port] || 9292 + + Dir.chdir("#{root}/test/rackup") do + @in, @rackup, @err = Open3.popen3("#{Gem.ruby} -S #{rackup} #{flags}") + end + + return if options[:port] == false + + # Wait until the server is available + begin + GET("/") + rescue + sleep 0.05 + retry + end + end + + def output + @rackup.read + end + + after do + # This doesn't actually return a response, so we rescue + GET "/die" rescue nil + + Dir["#{root}/**/*.pid"].each do |file| + File.delete(file) + end + + File.delete("#{root}/log_output") if File.exist?("#{root}/log_output") + end + + specify "rackup" do + run_rackup + response["PATH_INFO"].should.equal '/' + response["test.$DEBUG"].should.be false + response["test.$EVAL"].should.be nil + response["test.$VERBOSE"].should.be false + response["test.Ping"].should.be nil + response["SERVER_SOFTWARE"].should.not =~ /webrick/ + end + + specify "rackup --help" do + run_rackup "--help", :port => false + output.should.match /--port/ + end + + specify "rackup --port" do + run_rackup "--port 9000", :port => 9000 + response["SERVER_PORT"].should.equal "9000" + end + + specify "rackup --debug" do + run_rackup "--debug" + response["test.$DEBUG"].should.be true + end + + specify "rackup --eval" do + run_rackup %{--eval "BUKKIT = 'BUKKIT'"} + response["test.$EVAL"].should.equal "BUKKIT" + end + + specify "rackup --warn" do + run_rackup %{--warn} + response["test.$VERBOSE"].should.be true + end + + specify "rackup --include" do + run_rackup %{--include /foo/bar} + response["test.$LOAD_PATH"].should.include "/foo/bar" + end + + specify "rackup --require" do + run_rackup %{--require ping} + response["test.Ping"].should.equal "constant" + end + + specify "rackup --server" do + run_rackup %{--server webrick} + response["SERVER_SOFTWARE"].should =~ /webrick/i + end + + specify "rackup --host" do + run_rackup %{--host 127.0.0.1}, :host => "127.0.0.1" + response["REMOTE_ADDR"].should.equal "127.0.0.1" + end + + specify "rackup --daemonize --pid" do + run_rackup %{--daemonize --pid testing.pid} + status.should.be 200 + @rackup.should.be.eof? + Dir["#{root}/**/testing.pid"].should.not.be.empty? + end + + specify "rackup --pid" do + run_rackup %{--pid testing.pid} + status.should.be 200 + Dir["#{root}/**/testing.pid"].should.not.be.empty? + end + + specify "rackup --version" do + run_rackup %{--version}, :port => false + output.should =~ /1.0/ + end + + specify "rackup --env development includes lint" do + run_rackup + GET("/broken_lint") + status.should.be 500 + end + + specify "rackup --env deployment does not include lint" do + run_rackup %{--env deployment} + GET("/broken_lint") + status.should.be 200 + end + + specify "rackup --env none does not include lint" do + run_rackup %{--env none} + GET("/broken_lint") + status.should.be 200 + end + + specify "rackup --env deployment does log" do + run_rackup %{--env deployment} + log = File.read(response["test.stderr"]) + log.should.be.empty? + end + + specify "rackup --env none does not log" do + run_rackup %{--env none} + GET("/") + log = File.read(response["test.stderr"]) + log.should.be.empty? + end +end +rescue LoadError + $stderr.puts "Skipping rackup --server tests (mongrel is required). `gem install thin` and try again." +end \ No newline at end of file diff --git a/vendor/plugins/rack/test/testrequest.rb b/vendor/plugins/rack/test/testrequest.rb index 7b7190cb..0da2b126 100644 --- a/vendor/plugins/rack/test/testrequest.rb +++ b/vendor/plugins/rack/test/testrequest.rb @@ -13,6 +13,17 @@ class TestRequest module Helpers attr_reader :status, :response + ROOT = File.expand_path(File.dirname(__FILE__) + "/..") + ENV["RUBYOPT"] = "-I#{ROOT}/lib -rubygems" + + def root + ROOT + end + + def rackup + "#{ROOT}/bin/rackup" + end + def GET(path, header={}) Net::HTTP.start(@host, @port) { |http| user = header.delete(:user) @@ -22,7 +33,11 @@ class TestRequest get.basic_auth user, passwd if user && passwd http.request(get) { |response| @status = response.code.to_i - @response = YAML.load(response.body) + begin + @response = YAML.load(response.body) + rescue ArgumentError + @response = nil + end } } end diff --git a/vendor/rails/actionpack/lib/action_controller.rb b/vendor/rails/actionpack/lib/action_controller.rb index dbf13ae0..c18303b0 100644 --- a/vendor/rails/actionpack/lib/action_controller.rb +++ b/vendor/rails/actionpack/lib/action_controller.rb @@ -32,7 +32,7 @@ rescue LoadError end begin - gem 'rack', '~> 1.1.0' + gem 'rack', '~> 1.1.1' require 'rack' rescue Gem::LoadError $:.unshift "#{File.dirname(__FILE__)}/../../../plugins/rack/lib"