From 76f388f3e2c6c9e38ea9b9bf01073fbd0a68ae2e Mon Sep 17 00:00:00 2001 From: Jacques Distler Date: Fri, 18 Dec 2009 20:16:58 -0600 Subject: [PATCH] Vendor Rack 1.0.1 Incorporate patch from Revision 496. --- vendor/plugins/rack/COPYING | 18 + vendor/plugins/rack/KNOWN-ISSUES | 18 + vendor/plugins/rack/README | 364 ++++++++++++ vendor/plugins/rack/Rakefile | 164 ++++++ vendor/plugins/rack/bin/rackup | 176 ++++++ vendor/plugins/rack/contrib/rack_logo.svg | 111 ++++ vendor/plugins/rack/example/lobster.ru | 4 + .../plugins/rack/example/protectedlobster.rb | 14 + .../plugins/rack/example/protectedlobster.ru | 8 + .../rack-1.1.pre => plugins/rack/lib}/rack.rb | 0 .../rack/lib}/rack/adapter/camping.rb | 0 .../rack/lib}/rack/auth/abstract/handler.rb | 0 .../rack/lib}/rack/auth/abstract/request.rb | 0 .../rack/lib}/rack/auth/basic.rb | 0 .../rack/lib}/rack/auth/digest/md5.rb | 0 .../rack/lib}/rack/auth/digest/nonce.rb | 0 .../rack/lib}/rack/auth/digest/params.rb | 0 .../rack/lib}/rack/auth/digest/request.rb | 0 .../rack/lib}/rack/auth/openid.rb | 0 .../rack/lib}/rack/builder.rb | 0 .../rack/lib}/rack/cascade.rb | 0 .../rack/lib}/rack/chunked.rb | 0 .../rack/lib}/rack/commonlogger.rb | 0 .../rack/lib}/rack/conditionalget.rb | 0 .../rack/lib}/rack/content_length.rb | 0 .../rack/lib}/rack/content_type.rb | 0 .../rack/lib}/rack/deflater.rb | 2 +- .../rack/lib}/rack/directory.rb | 0 .../rack/lib}/rack/file.rb | 0 .../rack/lib}/rack/handler.rb | 0 .../rack/lib}/rack/handler/cgi.rb | 0 .../rack/lib}/rack/handler/evented_mongrel.rb | 0 .../rack/lib}/rack/handler/fastcgi.rb | 16 +- .../rack/lib}/rack/handler/lsws.rb | 21 +- .../rack/lib}/rack/handler/mongrel.rb | 7 +- .../rack/lib}/rack/handler/scgi.rb | 15 +- .../lib}/rack/handler/swiftiplied_mongrel.rb | 0 .../rack/lib}/rack/handler/thin.rb | 0 .../rack/lib}/rack/handler/webrick.rb | 6 +- .../rack/lib}/rack/head.rb | 0 .../rack/lib}/rack/lint.rb | 19 +- .../rack/lib}/rack/lobster.rb | 0 .../rack/lib}/rack/lock.rb | 0 .../rack/lib}/rack/methodoverride.rb | 0 .../rack/lib}/rack/mime.rb | 0 .../rack/lib}/rack/mock.rb | 35 +- .../rack/lib}/rack/recursive.rb | 0 .../rack/lib}/rack/reloader.rb | 4 +- .../rack/lib}/rack/request.rb | 16 +- .../rack/lib}/rack/response.rb | 0 .../rack/lib}/rack/rewindable_input.rb | 0 .../rack/lib}/rack/session/abstract/id.rb | 0 .../rack/lib}/rack/session/cookie.rb | 0 .../rack/lib}/rack/session/memcache.rb | 0 .../rack/lib}/rack/session/pool.rb | 0 .../rack/lib}/rack/showexceptions.rb | 0 .../rack/lib}/rack/showstatus.rb | 0 .../rack/lib}/rack/static.rb | 0 .../rack/lib}/rack/urlmap.rb | 0 .../rack/lib}/rack/utils.rb | 137 +---- vendor/plugins/rack/test/cgi/lighttpd.conf | 20 + vendor/plugins/rack/test/cgi/test | 9 + vendor/plugins/rack/test/cgi/test.fcgi | 8 + vendor/plugins/rack/test/cgi/test.ru | 7 + vendor/plugins/rack/test/multipart/binary | Bin 0 -> 26667 bytes vendor/plugins/rack/test/multipart/empty | 10 + vendor/plugins/rack/test/multipart/ie | 6 + vendor/plugins/rack/test/multipart/nested | 10 + vendor/plugins/rack/test/multipart/none | 9 + vendor/plugins/rack/test/multipart/semicolon | 6 + vendor/plugins/rack/test/multipart/text | 10 + .../plugins/rack/test/spec_rack_auth_basic.rb | 73 +++ .../rack/test/spec_rack_auth_digest.rb | 226 ++++++++ .../rack/test/spec_rack_auth_openid.rb | 84 +++ vendor/plugins/rack/test/spec_rack_builder.rb | 84 +++ vendor/plugins/rack/test/spec_rack_camping.rb | 51 ++ vendor/plugins/rack/test/spec_rack_cascade.rb | 50 ++ vendor/plugins/rack/test/spec_rack_cgi.rb | 89 +++ vendor/plugins/rack/test/spec_rack_chunked.rb | 62 +++ .../rack/test/spec_rack_commonlogger.rb | 32 ++ .../rack/test/spec_rack_conditionalget.rb | 41 ++ .../rack/test/spec_rack_content_length.rb | 43 ++ .../rack/test/spec_rack_content_type.rb | 30 + .../plugins/rack/test/spec_rack_deflater.rb | 127 +++++ .../plugins/rack/test/spec_rack_directory.rb | 61 ++ vendor/plugins/rack/test/spec_rack_fastcgi.rb | 89 +++ vendor/plugins/rack/test/spec_rack_file.rb | 75 +++ vendor/plugins/rack/test/spec_rack_handler.rb | 43 ++ vendor/plugins/rack/test/spec_rack_head.rb | 30 + vendor/plugins/rack/test/spec_rack_lint.rb | 521 ++++++++++++++++++ vendor/plugins/rack/test/spec_rack_lobster.rb | 45 ++ vendor/plugins/rack/test/spec_rack_lock.rb | 38 ++ .../rack/test/spec_rack_methodoverride.rb | 60 ++ vendor/plugins/rack/test/spec_rack_mock.rb | 157 ++++++ vendor/plugins/rack/test/spec_rack_mongrel.rb | 189 +++++++ .../plugins/rack/test/spec_rack_recursive.rb | 77 +++ vendor/plugins/rack/test/spec_rack_request.rb | 504 +++++++++++++++++ .../plugins/rack/test/spec_rack_response.rb | 218 ++++++++ .../rack/test/spec_rack_rewindable_input.rb | 118 ++++ .../rack/test/spec_rack_session_cookie.rb | 82 +++ .../rack/test/spec_rack_session_memcache.rb | 240 ++++++++ .../rack/test/spec_rack_session_pool.rb | 172 ++++++ .../rack/test/spec_rack_showexceptions.rb | 21 + .../plugins/rack/test/spec_rack_showstatus.rb | 72 +++ vendor/plugins/rack/test/spec_rack_static.rb | 37 ++ vendor/plugins/rack/test/spec_rack_thin.rb | 91 +++ vendor/plugins/rack/test/spec_rack_urlmap.rb | 185 +++++++ vendor/plugins/rack/test/spec_rack_utils.rb | 387 +++++++++++++ vendor/plugins/rack/test/spec_rack_webrick.rb | 130 +++++ vendor/plugins/rack/test/testrequest.rb | 57 ++ .../rack/handler/unregistered.rb | 7 + .../rack/handler/unregistered_long_one.rb | 7 + .../rails/actionpack/lib/action_controller.rb | 3 +- 113 files changed, 5759 insertions(+), 199 deletions(-) create mode 100644 vendor/plugins/rack/COPYING create mode 100644 vendor/plugins/rack/KNOWN-ISSUES create mode 100644 vendor/plugins/rack/README create mode 100644 vendor/plugins/rack/Rakefile create mode 100755 vendor/plugins/rack/bin/rackup create mode 100644 vendor/plugins/rack/contrib/rack_logo.svg create mode 100644 vendor/plugins/rack/example/lobster.ru create mode 100644 vendor/plugins/rack/example/protectedlobster.rb create mode 100644 vendor/plugins/rack/example/protectedlobster.ru rename vendor/{rails/actionpack/lib/action_controller/vendor/rack-1.1.pre => plugins/rack/lib}/rack.rb (100%) rename vendor/{rails/actionpack/lib/action_controller/vendor/rack-1.1.pre => plugins/rack/lib}/rack/adapter/camping.rb (100%) rename vendor/{rails/actionpack/lib/action_controller/vendor/rack-1.1.pre => plugins/rack/lib}/rack/auth/abstract/handler.rb (100%) rename vendor/{rails/actionpack/lib/action_controller/vendor/rack-1.1.pre => plugins/rack/lib}/rack/auth/abstract/request.rb (100%) rename vendor/{rails/actionpack/lib/action_controller/vendor/rack-1.1.pre => plugins/rack/lib}/rack/auth/basic.rb (100%) rename vendor/{rails/actionpack/lib/action_controller/vendor/rack-1.1.pre => plugins/rack/lib}/rack/auth/digest/md5.rb (100%) rename vendor/{rails/actionpack/lib/action_controller/vendor/rack-1.1.pre => plugins/rack/lib}/rack/auth/digest/nonce.rb (100%) rename vendor/{rails/actionpack/lib/action_controller/vendor/rack-1.1.pre => plugins/rack/lib}/rack/auth/digest/params.rb (100%) rename vendor/{rails/actionpack/lib/action_controller/vendor/rack-1.1.pre => plugins/rack/lib}/rack/auth/digest/request.rb (100%) rename vendor/{rails/actionpack/lib/action_controller/vendor/rack-1.1.pre => plugins/rack/lib}/rack/auth/openid.rb (100%) rename vendor/{rails/actionpack/lib/action_controller/vendor/rack-1.1.pre => plugins/rack/lib}/rack/builder.rb (100%) rename vendor/{rails/actionpack/lib/action_controller/vendor/rack-1.1.pre => plugins/rack/lib}/rack/cascade.rb (100%) rename vendor/{rails/actionpack/lib/action_controller/vendor/rack-1.1.pre => plugins/rack/lib}/rack/chunked.rb (100%) rename vendor/{rails/actionpack/lib/action_controller/vendor/rack-1.1.pre => plugins/rack/lib}/rack/commonlogger.rb (100%) rename vendor/{rails/actionpack/lib/action_controller/vendor/rack-1.1.pre => plugins/rack/lib}/rack/conditionalget.rb (100%) rename vendor/{rails/actionpack/lib/action_controller/vendor/rack-1.1.pre => plugins/rack/lib}/rack/content_length.rb (100%) rename vendor/{rails/actionpack/lib/action_controller/vendor/rack-1.1.pre => plugins/rack/lib}/rack/content_type.rb (100%) rename vendor/{rails/actionpack/lib/action_controller/vendor/rack-1.1.pre => plugins/rack/lib}/rack/deflater.rb (98%) rename vendor/{rails/actionpack/lib/action_controller/vendor/rack-1.1.pre => plugins/rack/lib}/rack/directory.rb (100%) rename vendor/{rails/actionpack/lib/action_controller/vendor/rack-1.1.pre => plugins/rack/lib}/rack/file.rb (100%) rename vendor/{rails/actionpack/lib/action_controller/vendor/rack-1.1.pre => plugins/rack/lib}/rack/handler.rb (100%) rename vendor/{rails/actionpack/lib/action_controller/vendor/rack-1.1.pre => plugins/rack/lib}/rack/handler/cgi.rb (100%) rename vendor/{rails/actionpack/lib/action_controller/vendor/rack-1.1.pre => plugins/rack/lib}/rack/handler/evented_mongrel.rb (100%) rename vendor/{rails/actionpack/lib/action_controller/vendor/rack-1.1.pre => plugins/rack/lib}/rack/handler/fastcgi.rb (90%) rename vendor/{rails/actionpack/lib/action_controller/vendor/rack-1.1.pre => plugins/rack/lib}/rack/handler/lsws.rb (72%) rename vendor/{rails/actionpack/lib/action_controller/vendor/rack-1.1.pre => plugins/rack/lib}/rack/handler/mongrel.rb (92%) rename vendor/{rails/actionpack/lib/action_controller/vendor/rack-1.1.pre => plugins/rack/lib}/rack/handler/scgi.rb (89%) rename vendor/{rails/actionpack/lib/action_controller/vendor/rack-1.1.pre => plugins/rack/lib}/rack/handler/swiftiplied_mongrel.rb (100%) rename vendor/{rails/actionpack/lib/action_controller/vendor/rack-1.1.pre => plugins/rack/lib}/rack/handler/thin.rb (100%) rename vendor/{rails/actionpack/lib/action_controller/vendor/rack-1.1.pre => plugins/rack/lib}/rack/handler/webrick.rb (87%) rename vendor/{rails/actionpack/lib/action_controller/vendor/rack-1.1.pre => plugins/rack/lib}/rack/head.rb (100%) rename vendor/{rails/actionpack/lib/action_controller/vendor/rack-1.1.pre => plugins/rack/lib}/rack/lint.rb (97%) rename vendor/{rails/actionpack/lib/action_controller/vendor/rack-1.1.pre => plugins/rack/lib}/rack/lobster.rb (100%) rename vendor/{rails/actionpack/lib/action_controller/vendor/rack-1.1.pre => plugins/rack/lib}/rack/lock.rb (100%) rename vendor/{rails/actionpack/lib/action_controller/vendor/rack-1.1.pre => plugins/rack/lib}/rack/methodoverride.rb (100%) rename vendor/{rails/actionpack/lib/action_controller/vendor/rack-1.1.pre => plugins/rack/lib}/rack/mime.rb (100%) rename vendor/{rails/actionpack/lib/action_controller/vendor/rack-1.1.pre => plugins/rack/lib}/rack/mock.rb (74%) rename vendor/{rails/actionpack/lib/action_controller/vendor/rack-1.1.pre => plugins/rack/lib}/rack/recursive.rb (100%) rename vendor/{rails/actionpack/lib/action_controller/vendor/rack-1.1.pre => plugins/rack/lib}/rack/reloader.rb (96%) rename vendor/{rails/actionpack/lib/action_controller/vendor/rack-1.1.pre => plugins/rack/lib}/rack/request.rb (97%) rename vendor/{rails/actionpack/lib/action_controller/vendor/rack-1.1.pre => plugins/rack/lib}/rack/response.rb (100%) rename vendor/{rails/actionpack/lib/action_controller/vendor/rack-1.1.pre => plugins/rack/lib}/rack/rewindable_input.rb (100%) rename vendor/{rails/actionpack/lib/action_controller/vendor/rack-1.1.pre => plugins/rack/lib}/rack/session/abstract/id.rb (100%) rename vendor/{rails/actionpack/lib/action_controller/vendor/rack-1.1.pre => plugins/rack/lib}/rack/session/cookie.rb (100%) rename vendor/{rails/actionpack/lib/action_controller/vendor/rack-1.1.pre => plugins/rack/lib}/rack/session/memcache.rb (100%) rename vendor/{rails/actionpack/lib/action_controller/vendor/rack-1.1.pre => plugins/rack/lib}/rack/session/pool.rb (100%) rename vendor/{rails/actionpack/lib/action_controller/vendor/rack-1.1.pre => plugins/rack/lib}/rack/showexceptions.rb (100%) rename vendor/{rails/actionpack/lib/action_controller/vendor/rack-1.1.pre => plugins/rack/lib}/rack/showstatus.rb (100%) rename vendor/{rails/actionpack/lib/action_controller/vendor/rack-1.1.pre => plugins/rack/lib}/rack/static.rb (100%) rename vendor/{rails/actionpack/lib/action_controller/vendor/rack-1.1.pre => plugins/rack/lib}/rack/urlmap.rb (100%) rename vendor/{rails/actionpack/lib/action_controller/vendor/rack-1.1.pre => plugins/rack/lib}/rack/utils.rb (75%) create mode 100644 vendor/plugins/rack/test/cgi/lighttpd.conf create mode 100755 vendor/plugins/rack/test/cgi/test create mode 100755 vendor/plugins/rack/test/cgi/test.fcgi create mode 100755 vendor/plugins/rack/test/cgi/test.ru create mode 100644 vendor/plugins/rack/test/multipart/binary create mode 100644 vendor/plugins/rack/test/multipart/empty create mode 100644 vendor/plugins/rack/test/multipart/ie create mode 100644 vendor/plugins/rack/test/multipart/nested create mode 100644 vendor/plugins/rack/test/multipart/none create mode 100644 vendor/plugins/rack/test/multipart/semicolon create mode 100644 vendor/plugins/rack/test/multipart/text create mode 100644 vendor/plugins/rack/test/spec_rack_auth_basic.rb create mode 100644 vendor/plugins/rack/test/spec_rack_auth_digest.rb create mode 100644 vendor/plugins/rack/test/spec_rack_auth_openid.rb create mode 100644 vendor/plugins/rack/test/spec_rack_builder.rb create mode 100644 vendor/plugins/rack/test/spec_rack_camping.rb create mode 100644 vendor/plugins/rack/test/spec_rack_cascade.rb create mode 100644 vendor/plugins/rack/test/spec_rack_cgi.rb create mode 100644 vendor/plugins/rack/test/spec_rack_chunked.rb create mode 100644 vendor/plugins/rack/test/spec_rack_commonlogger.rb create mode 100644 vendor/plugins/rack/test/spec_rack_conditionalget.rb create mode 100644 vendor/plugins/rack/test/spec_rack_content_length.rb create mode 100644 vendor/plugins/rack/test/spec_rack_content_type.rb create mode 100644 vendor/plugins/rack/test/spec_rack_deflater.rb create mode 100644 vendor/plugins/rack/test/spec_rack_directory.rb create mode 100644 vendor/plugins/rack/test/spec_rack_fastcgi.rb create mode 100644 vendor/plugins/rack/test/spec_rack_file.rb create mode 100644 vendor/plugins/rack/test/spec_rack_handler.rb create mode 100644 vendor/plugins/rack/test/spec_rack_head.rb create mode 100644 vendor/plugins/rack/test/spec_rack_lint.rb create mode 100644 vendor/plugins/rack/test/spec_rack_lobster.rb create mode 100644 vendor/plugins/rack/test/spec_rack_lock.rb create mode 100644 vendor/plugins/rack/test/spec_rack_methodoverride.rb create mode 100644 vendor/plugins/rack/test/spec_rack_mock.rb create mode 100644 vendor/plugins/rack/test/spec_rack_mongrel.rb create mode 100644 vendor/plugins/rack/test/spec_rack_recursive.rb create mode 100644 vendor/plugins/rack/test/spec_rack_request.rb create mode 100644 vendor/plugins/rack/test/spec_rack_response.rb create mode 100644 vendor/plugins/rack/test/spec_rack_rewindable_input.rb create mode 100644 vendor/plugins/rack/test/spec_rack_session_cookie.rb create mode 100644 vendor/plugins/rack/test/spec_rack_session_memcache.rb create mode 100644 vendor/plugins/rack/test/spec_rack_session_pool.rb create mode 100644 vendor/plugins/rack/test/spec_rack_showexceptions.rb create mode 100644 vendor/plugins/rack/test/spec_rack_showstatus.rb create mode 100644 vendor/plugins/rack/test/spec_rack_static.rb create mode 100644 vendor/plugins/rack/test/spec_rack_thin.rb create mode 100644 vendor/plugins/rack/test/spec_rack_urlmap.rb create mode 100644 vendor/plugins/rack/test/spec_rack_utils.rb create mode 100644 vendor/plugins/rack/test/spec_rack_webrick.rb create mode 100644 vendor/plugins/rack/test/testrequest.rb create mode 100644 vendor/plugins/rack/test/unregistered_handler/rack/handler/unregistered.rb create mode 100644 vendor/plugins/rack/test/unregistered_handler/rack/handler/unregistered_long_one.rb diff --git a/vendor/plugins/rack/COPYING b/vendor/plugins/rack/COPYING new file mode 100644 index 00000000..11b4c6e0 --- /dev/null +++ b/vendor/plugins/rack/COPYING @@ -0,0 +1,18 @@ +Copyright (c) 2007, 2008, 2009 Christian Neukirchen + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to +deal in the Software without restriction, including without limitation the +rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +sell copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +THE AUTHORS 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. diff --git a/vendor/plugins/rack/KNOWN-ISSUES b/vendor/plugins/rack/KNOWN-ISSUES new file mode 100644 index 00000000..790199bd --- /dev/null +++ b/vendor/plugins/rack/KNOWN-ISSUES @@ -0,0 +1,18 @@ += Known issues with Rack and Web servers + +* Lighttpd sets wrong SCRIPT_NAME and PATH_INFO if you mount your + FastCGI app at "/". This can be fixed by using this middleware: + + class LighttpdScriptNameFix + def initialize(app) + @app = app + end + + def call(env) + env["PATH_INFO"] = env["SCRIPT_NAME"].to_s + env["PATH_INFO"].to_s + env["SCRIPT_NAME"] = "" + @app.call(env) + end + end + + Of course, use this only when your app runs at "/". diff --git a/vendor/plugins/rack/README b/vendor/plugins/rack/README new file mode 100644 index 00000000..c58009ff --- /dev/null +++ b/vendor/plugins/rack/README @@ -0,0 +1,364 @@ += Rack, a modular Ruby webserver interface + +Rack provides a 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. + +The exact details of this are described in the Rack specification, +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: + +* 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. + +== Supported web servers + +The included *handlers* connect all kinds of web servers to Rack: +* Mongrel +* EventedMongrel +* SwiftipliedMongrel +* WEBrick +* FCGI +* CGI +* SCGI +* LiteSpeed +* Thin + +These web servers include Rack handlers in their distributions: +* Ebb +* Fuzed +* Phusion Passenger (which is mod_rack for Apache and for nginx) +* Unicorn + +Any valid Rack app will run the same on all these handlers, without +changing anything. + +== Supported web frameworks + +The included *adapters* connect Rack with existing Ruby web frameworks: +* Camping + +These frameworks include Rack adapters in their distributions: +* Camping +* Coset +* Halcyon +* Mack +* Maveric +* Merb +* Racktools::SimpleApplication +* Ramaze +* Ruby on Rails +* Rum +* Sinatra +* Sin +* Vintage +* Waves +* Wee + +Current links to these projects can be found at +http://wiki.ramaze.net/Home#other-frameworks + +== Available middleware + +Between the server and the framework, Rack can be customized to your +applications needs using middleware, for example: +* Rack::URLMap, to route to multiple applications inside the same process. +* Rack::CommonLogger, for creating Apache-style logfiles. +* Rack::ShowException, for catching unhandled exceptions and + presenting them in a nice and helpful way with clickable backtrace. +* Rack::File, for serving static files. +* ...many others! + +All these components use the same interface, which is described in +detail in the Rack specification. These optional components can be +used in any way you wish. + +== Convenience + +If you want to develop outside of existing frameworks, implement your +own ones, or develop middleware, Rack provides many helpers to create +Rack applications quickly and without doing the same web stuff all +over: +* Rack::Request, which also provides query string parsing and + multipart handling. +* Rack::Response, for convenient generation of HTTP replies and + cookie handling. +* Rack::MockRequest and Rack::MockResponse for efficient and quick + testing of Rack application without real HTTP round-trips. + +== rack-contrib + +The plethora of useful middleware created the need for a project that +collects fresh Rack middleware. rack-contrib includes a variety of +add-on components for Rack and it is easy to contribute new modules. + +* http://github.com/rack/rack-contrib + +== rackup + +rackup is a useful tool for running Rack applications, which uses the +Rack::Builder DSL to configure middleware and build up applications +easily. + +rackup automatically figures out the environment it is run in, and +runs your application as FastCGI, CGI, or standalone with Mongrel or +WEBrick---all from the same configuration. + +== Quick start + +Try the lobster! + +Either with the embedded WEBrick starter: + + ruby -Ilib lib/rack/lobster.rb + +Or with rackup: + + 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: + + gem install rack + +I also provide a local mirror of the gems (and development snapshots) +at my site: + + gem install rack --source http://chneukirchen.org/releases/gems/ + +== Running the tests + +Testing Rack requires the test/spec testing framework: + + gem install test-spec + +There are two rake-based test tasks: + + rake test tests all the fast tests (no Handlers or Adapters) + rake fulltest runs all the tests + +The fast testsuite has no dependencies outside of the core Ruby +installation and test-spec. + +To run the test suite completely, you need: + + * camping + * fcgi + * memcache-client + * mongrel + * ruby-openid + * thin + +The full set of tests test FCGI access with lighttpd (on port +9203) so you will need lighttpd installed as well as the FCGI +libraries and the fcgi gem: + +Download and install lighttpd: + + http://www.lighttpd.net/download + +Installing the FCGI libraries: + + curl -O http://www.fastcgi.com/dist/fcgi-2.4.0.tar.gz + tar xzvf fcgi-2.4.0.tar.gz + cd fcgi-2.4.0 + ./configure --prefix=/usr/local + make + sudo make install + cd .. + +Installing the Ruby fcgi gem: + + gem install fcgi + +Furthermore, to test Memcache sessions, you need memcached (will be +run on port 11211) and memcache-client installed. + +== History + +* March 3rd, 2007: First public release 0.1. + +* May 16th, 2007: Second public release 0.2. + * HTTP Basic authentication. + * Cookie Sessions. + * Static file handler. + * Improved Rack::Request. + * Improved Rack::Response. + * Added Rack::ShowStatus, for better default error messages. + * Bug fixes in the Camping adapter. + * Removed Rails adapter, was too alpha. + +* February 26th, 2008: Third public release 0.3. + * LiteSpeed handler, by Adrian Madrid. + * SCGI handler, by Jeremy Evans. + * Pool sessions, by blink. + * OpenID authentication, by blink. + * :Port and :File options for opening FastCGI sockets, by blink. + * Last-Modified HTTP header for Rack::File, by blink. + * Rack::Builder#use now accepts blocks, by Corey Jewett. + (See example/protectedlobster.ru) + * HTTP status 201 can contain a Content-Type and a body now. + * Many bugfixes, especially related to Cookie handling. + +* August 21st, 2008: Fourth public release 0.4. + * New middleware, Rack::Deflater, by Christoffer Sawicki. + * OpenID authentication now needs ruby-openid 2. + * New Memcache sessions, by blink. + * Explicit EventedMongrel handler, by Joshua Peek + * Rack::Reloader is not loaded in rackup development mode. + * rackup can daemonize with -D. + * Many bugfixes, especially for pool sessions, URLMap, thread safety + and tempfile handling. + * Improved tests. + * Rack moved to Git. + +* January 6th, 2009: Fifth public release 0.9. + * Rack is now managed by the Rack Core Team. + * Rack::Lint is stricter and follows the HTTP RFCs more closely. + * Added ConditionalGet middleware. + * Added ContentLength middleware. + * Added Deflater middleware. + * Added Head middleware. + * Added MethodOverride middleware. + * Rack::Mime now provides popular MIME-types and their extension. + * Mongrel Header now streams. + * Added Thin handler. + * Official support for swiftiplied Mongrel. + * Secure cookies. + * Made HeaderHash case-preserving. + * Many bugfixes and small improvements. + +* January 9th, 2009: Sixth public release 0.9.1. + * Fix directory traversal exploits in Rack::File and Rack::Directory. + +* April 25th, 2009: Seventh public release 1.0.0. + * SPEC change: Rack::VERSION has been pushed to [1,0]. + * SPEC change: header values must be Strings now, split on "\n". + * SPEC change: Content-Length can be missing, in this case chunked transfer + encoding is used. + * SPEC change: rack.input must be rewindable and support reading into + a buffer, wrap with Rack::RewindableInput if it isn't. + * SPEC change: rack.session is now specified. + * SPEC change: Bodies can now additionally respond to #to_path with + a filename to be served. + * NOTE: String bodies break in 1.9, use an Array consisting of a + single String instead. + * New middleware Rack::Lock. + * New middleware Rack::ContentType. + * Rack::Reloader has been rewritten. + * Major update to Rack::Auth::OpenID. + * Support for nested parameter parsing in Rack::Response. + * Support for redirects in Rack::Response. + * HttpOnly cookie support in Rack::Response. + * The Rakefile has been rewritten. + * Many bugfixes and small improvements. + +* October 18th, 2009: Eighth public release 1.0.1. + * Bump remainder of rack.versions. + * Support the pure Ruby FCGI implementation. + * Fix for form names containing "=": split first then unescape components + * Fixes the handling of the filename parameter with semicolons in names. + * Add anchor to nested params parsing regexp to prevent stack overflows + * Use more compatible gzip write api instead of "<<". + * Make sure that Reloader doesn't break when executed via ruby -e + * Make sure WEBrick respects the :Host option + * Many Ruby 1.9 fixes. + +== Contact + +Please mail bugs, suggestions and patches to +. + +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 + +You are also welcome to join the #rack channel on irc.freenode.net. + +== Thanks + +The Rack Core Team, consisting of + +* Christian Neukirchen (chneukirchen) +* James Tucker (raggi) +* Josh Peek (josh) +* Michael Fellinger (manveru) +* Ryan Tomayko (rtomayko) +* Scytrin dai Kinthra (scytrin) + +would like to thank: + +* Adrian Madrid, for the LiteSpeed handler. +* Christoffer Sawicki, for the first Rails adapter and Rack::Deflater. +* Tim Fletcher, for the HTTP authentication code. +* 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. +* Brian Candler, for Rack::ContentType. +* Graham Batty, for improved handler loading. +* Stephen Bannasch, for bug reports and documentation. +* Gary Wright, for proposing a better Rack::Response interface. +* Jonathan Buch, for improvements regarding Rack::Response. +* Armin Röhrl, for tracking down bugs in the Cookie generator. +* Alexander Kellett for testing the Gem and reviewing the announcement. +* Marcus Rückert, for help with configuring and debugging lighttpd. +* The WSGI team for the well-done and documented work they've done and + Rack builds up on. +* All bug reporters and patch contributers not mentioned above. + +== Copyright + +Copyright (C) 2007, 2008, 2009 Christian Neukirchen + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to +deal in the Software without restriction, including without limitation the +rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +sell copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +THE AUTHORS 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. + +== Links + +Rack:: +Rack's Rubyforge project:: +Official Rack repositories:: +rack-devel mailing list:: + +Christian Neukirchen:: + diff --git a/vendor/plugins/rack/Rakefile b/vendor/plugins/rack/Rakefile new file mode 100644 index 00000000..c88f7aff --- /dev/null +++ b/vendor/plugins/rack/Rakefile @@ -0,0 +1,164 @@ +# Rakefile for Rack. -*-ruby-*- +require 'rake/rdoctask' +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 + 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" + sh "gzip -f -9 #{release}.tar" +end + +desc "Make an official release" +task :officialrelease do + puts "Official build for #{release}..." + sh "rm -rf stage" + sh "git clone --shared . stage" + sh "cd stage && rake officialrelease_really" + sh "mv stage/#{release}.tar.gz stage/#{release}.gem ." +end + +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}" +end + +def manifest + `git ls-files`.split("\n") +end + + +desc "Make binaries executable" +task :chmod do + Dir["bin/*"].each { |binary| File.chmod(0775, binary) } + Dir["test/cgi/test*"].each { |binary| File.chmod(0775, binary) } +end + +desc "Generate a ChangeLog" +task :changelog do + File.open("ChangeLog", "w") { |out| + `git log -z`.split("\0").map { |chunk| + author = chunk[/Author: (.*)/, 1].strip + date = chunk[/Date: (.*)/, 1].strip + desc, detail = $'.strip.split("\n", 2) + detail ||= "" + detail = detail.gsub(/.*darcs-hash:.*/, '') + detail.rstrip! + out.puts "#{date} #{author}" + out.puts " * #{desc.strip}" + out.puts detail unless detail.empty? + out.puts + } + } +end + + +desc "Generate RDox" +task "RDOX" do + sh "specrb -Ilib:test -a --rdox >RDOX" +end + +desc "Generate Rack Specification" +task "SPEC" do + File.open("SPEC", "wb") { |file| + IO.foreach("lib/rack/lint.rb") { |line| + if line =~ /## (.*)/ + file.puts $1 + end + } + } +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)"'}" +end + +desc "Run all the tests" +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 +end + +desc "Generate RDoc documentation" +task :rdoc do + 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"]) +end + +task :pushsite => [:rdoc] do + sh "cd site && git gc" + sh "rsync -avz doc/ chneukirchen@rack.rubyforge.org:/var/www/gforge-projects/rack/doc/" + sh "rsync -avz site/ chneukirchen@rack.rubyforge.org:/var/www/gforge-projects/rack/" + sh "cd site && git push" +end diff --git a/vendor/plugins/rack/bin/rackup b/vendor/plugins/rack/bin/rackup new file mode 100755 index 00000000..8e4df15e --- /dev/null +++ b/vendor/plugins/rack/bin/rackup @@ -0,0 +1,176 @@ +#!/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 diff --git a/vendor/plugins/rack/contrib/rack_logo.svg b/vendor/plugins/rack/contrib/rack_logo.svg new file mode 100644 index 00000000..905dcd32 --- /dev/null +++ b/vendor/plugins/rack/contrib/rack_logo.svg @@ -0,0 +1,111 @@ + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + diff --git a/vendor/plugins/rack/example/lobster.ru b/vendor/plugins/rack/example/lobster.ru new file mode 100644 index 00000000..cc7ffcae --- /dev/null +++ b/vendor/plugins/rack/example/lobster.ru @@ -0,0 +1,4 @@ +require 'rack/lobster' + +use Rack::ShowExceptions +run Rack::Lobster.new diff --git a/vendor/plugins/rack/example/protectedlobster.rb b/vendor/plugins/rack/example/protectedlobster.rb new file mode 100644 index 00000000..108b9d05 --- /dev/null +++ b/vendor/plugins/rack/example/protectedlobster.rb @@ -0,0 +1,14 @@ +require 'rack' +require 'rack/lobster' + +lobster = Rack::Lobster.new + +protected_lobster = Rack::Auth::Basic.new(lobster) do |username, password| + 'secret' == password +end + +protected_lobster.realm = 'Lobster 2.0' + +pretty_protected_lobster = Rack::ShowStatus.new(Rack::ShowExceptions.new(protected_lobster)) + +Rack::Handler::WEBrick.run pretty_protected_lobster, :Port => 9292 diff --git a/vendor/plugins/rack/example/protectedlobster.ru b/vendor/plugins/rack/example/protectedlobster.ru new file mode 100644 index 00000000..b0da62f0 --- /dev/null +++ b/vendor/plugins/rack/example/protectedlobster.ru @@ -0,0 +1,8 @@ +require 'rack/lobster' + +use Rack::ShowExceptions +use Rack::Auth::Basic, "Lobster 2.0" do |username, password| + 'secret' == password +end + +run Rack::Lobster.new diff --git a/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack.rb b/vendor/plugins/rack/lib/rack.rb similarity index 100% rename from vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack.rb rename to vendor/plugins/rack/lib/rack.rb diff --git a/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/adapter/camping.rb b/vendor/plugins/rack/lib/rack/adapter/camping.rb similarity index 100% rename from vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/adapter/camping.rb rename to vendor/plugins/rack/lib/rack/adapter/camping.rb diff --git a/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/auth/abstract/handler.rb b/vendor/plugins/rack/lib/rack/auth/abstract/handler.rb similarity index 100% rename from vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/auth/abstract/handler.rb rename to vendor/plugins/rack/lib/rack/auth/abstract/handler.rb diff --git a/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/auth/abstract/request.rb b/vendor/plugins/rack/lib/rack/auth/abstract/request.rb similarity index 100% rename from vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/auth/abstract/request.rb rename to vendor/plugins/rack/lib/rack/auth/abstract/request.rb diff --git a/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/auth/basic.rb b/vendor/plugins/rack/lib/rack/auth/basic.rb similarity index 100% rename from vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/auth/basic.rb rename to vendor/plugins/rack/lib/rack/auth/basic.rb diff --git a/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/auth/digest/md5.rb b/vendor/plugins/rack/lib/rack/auth/digest/md5.rb similarity index 100% rename from vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/auth/digest/md5.rb rename to vendor/plugins/rack/lib/rack/auth/digest/md5.rb diff --git a/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/auth/digest/nonce.rb b/vendor/plugins/rack/lib/rack/auth/digest/nonce.rb similarity index 100% rename from vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/auth/digest/nonce.rb rename to vendor/plugins/rack/lib/rack/auth/digest/nonce.rb diff --git a/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/auth/digest/params.rb b/vendor/plugins/rack/lib/rack/auth/digest/params.rb similarity index 100% rename from vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/auth/digest/params.rb rename to vendor/plugins/rack/lib/rack/auth/digest/params.rb diff --git a/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/auth/digest/request.rb b/vendor/plugins/rack/lib/rack/auth/digest/request.rb similarity index 100% rename from vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/auth/digest/request.rb rename to vendor/plugins/rack/lib/rack/auth/digest/request.rb diff --git a/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/auth/openid.rb b/vendor/plugins/rack/lib/rack/auth/openid.rb similarity index 100% rename from vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/auth/openid.rb rename to vendor/plugins/rack/lib/rack/auth/openid.rb diff --git a/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/builder.rb b/vendor/plugins/rack/lib/rack/builder.rb similarity index 100% rename from vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/builder.rb rename to vendor/plugins/rack/lib/rack/builder.rb diff --git a/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/cascade.rb b/vendor/plugins/rack/lib/rack/cascade.rb similarity index 100% rename from vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/cascade.rb rename to vendor/plugins/rack/lib/rack/cascade.rb diff --git a/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/chunked.rb b/vendor/plugins/rack/lib/rack/chunked.rb similarity index 100% rename from vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/chunked.rb rename to vendor/plugins/rack/lib/rack/chunked.rb diff --git a/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/commonlogger.rb b/vendor/plugins/rack/lib/rack/commonlogger.rb similarity index 100% rename from vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/commonlogger.rb rename to vendor/plugins/rack/lib/rack/commonlogger.rb diff --git a/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/conditionalget.rb b/vendor/plugins/rack/lib/rack/conditionalget.rb similarity index 100% rename from vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/conditionalget.rb rename to vendor/plugins/rack/lib/rack/conditionalget.rb diff --git a/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/content_length.rb b/vendor/plugins/rack/lib/rack/content_length.rb similarity index 100% rename from vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/content_length.rb rename to vendor/plugins/rack/lib/rack/content_length.rb diff --git a/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/content_type.rb b/vendor/plugins/rack/lib/rack/content_type.rb similarity index 100% rename from vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/content_type.rb rename to vendor/plugins/rack/lib/rack/content_type.rb diff --git a/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/deflater.rb b/vendor/plugins/rack/lib/rack/deflater.rb similarity index 98% rename from vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/deflater.rb rename to vendor/plugins/rack/lib/rack/deflater.rb index 14137a94..ad0f5316 100644 --- a/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/deflater.rb +++ b/vendor/plugins/rack/lib/rack/deflater.rb @@ -60,7 +60,7 @@ module Rack @writer = block gzip =::Zlib::GzipWriter.new(self) gzip.mtime = @mtime - @body.each { |part| gzip << part } + @body.each { |part| gzip.write(part) } @body.close if @body.respond_to?(:close) gzip.close @writer = nil diff --git a/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/directory.rb b/vendor/plugins/rack/lib/rack/directory.rb similarity index 100% rename from vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/directory.rb rename to vendor/plugins/rack/lib/rack/directory.rb diff --git a/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/file.rb b/vendor/plugins/rack/lib/rack/file.rb similarity index 100% rename from vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/file.rb rename to vendor/plugins/rack/lib/rack/file.rb diff --git a/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/handler.rb b/vendor/plugins/rack/lib/rack/handler.rb similarity index 100% rename from vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/handler.rb rename to vendor/plugins/rack/lib/rack/handler.rb diff --git a/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/handler/cgi.rb b/vendor/plugins/rack/lib/rack/handler/cgi.rb similarity index 100% rename from vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/handler/cgi.rb rename to vendor/plugins/rack/lib/rack/handler/cgi.rb diff --git a/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/handler/evented_mongrel.rb b/vendor/plugins/rack/lib/rack/handler/evented_mongrel.rb similarity index 100% rename from vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/handler/evented_mongrel.rb rename to vendor/plugins/rack/lib/rack/handler/evented_mongrel.rb diff --git a/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/handler/fastcgi.rb b/vendor/plugins/rack/lib/rack/handler/fastcgi.rb similarity index 90% rename from vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/handler/fastcgi.rb rename to vendor/plugins/rack/lib/rack/handler/fastcgi.rb index 2cbb5025..1739d659 100644 --- a/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/handler/fastcgi.rb +++ b/vendor/plugins/rack/lib/rack/handler/fastcgi.rb @@ -3,13 +3,15 @@ require 'socket' require 'rack/content_length' require 'rack/rewindable_input' -class FCGI::Stream - alias _rack_read_without_buffer read +if defined? FCGI::Stream + class FCGI::Stream + alias _rack_read_without_buffer read - def read(n, buffer=nil) - buf = _rack_read_without_buffer n - buffer.replace(buf.to_s) if buffer - buf + def read(n, buffer=nil) + buf = _rack_read_without_buffer n + buffer.replace(buf.to_s) if buffer + buf + end end end @@ -31,7 +33,7 @@ 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], diff --git a/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/handler/lsws.rb b/vendor/plugins/rack/lib/rack/handler/lsws.rb similarity index 72% rename from vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/handler/lsws.rb rename to vendor/plugins/rack/lib/rack/handler/lsws.rb index 7231336d..b4ddf4bb 100644 --- a/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/handler/lsws.rb +++ b/vendor/plugins/rack/lib/rack/handler/lsws.rb @@ -15,14 +15,19 @@ module Rack env = ENV.to_hash env.delete "HTTP_CONTENT_LENGTH" env["SCRIPT_NAME"] = "" if env["SCRIPT_NAME"] == "/" - env.update({"rack.version" => [1,0], - "rack.input" => StringIO.new($stdin.read.to_s), - "rack.errors" => $stderr, - "rack.multithread" => false, - "rack.multiprocess" => true, - "rack.run_once" => false, - "rack.url_scheme" => ["yes", "on", "1"].include?(ENV["HTTPS"]) ? "https" : "http" - }) + + rack_input = RewindableInput.new($stdin.read.to_s) + + env.update( + "rack.version" => [1,0], + "rack.input" => rack_input, + "rack.errors" => $stderr, + "rack.multithread" => false, + "rack.multiprocess" => true, + "rack.run_once" => false, + "rack.url_scheme" => ["yes", "on", "1"].include?(ENV["HTTPS"]) ? "https" : "http" + ) + env["QUERY_STRING"] ||= "" env["HTTP_VERSION"] ||= env["SERVER_PROTOCOL"] env["REQUEST_PATH"] ||= "/" diff --git a/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/handler/mongrel.rb b/vendor/plugins/rack/lib/rack/handler/mongrel.rb similarity index 92% rename from vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/handler/mongrel.rb rename to vendor/plugins/rack/lib/rack/handler/mongrel.rb index a6b4fa93..7b448261 100644 --- a/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/handler/mongrel.rb +++ b/vendor/plugins/rack/lib/rack/handler/mongrel.rb @@ -10,7 +10,7 @@ module Rack server = ::Mongrel::HttpServer.new(options[:Host] || '0.0.0.0', options[:Port] || 8080) # 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 @@ -45,8 +45,11 @@ module Rack env["SCRIPT_NAME"] = "" if env["SCRIPT_NAME"] == "/" + 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], - "rack.input" => request.body || StringIO.new(""), + "rack.input" => rack_input, "rack.errors" => $stderr, "rack.multithread" => true, diff --git a/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/handler/scgi.rb b/vendor/plugins/rack/lib/rack/handler/scgi.rb similarity index 89% rename from vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/handler/scgi.rb rename to vendor/plugins/rack/lib/rack/handler/scgi.rb index df0e764d..bd860a5d 100644 --- a/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/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" @@ -32,10 +32,13 @@ module Rack env["PATH_INFO"] = env["REQUEST_PATH"] env["QUERY_STRING"] ||= "" env["SCRIPT_NAME"] = "" - env.update({"rack.version" => [1,0], - "rack.input" => StringIO.new(input_body), - "rack.errors" => $stderr, + 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], + "rack.input" => rack_input, + "rack.errors" => $stderr, "rack.multithread" => true, "rack.multiprocess" => true, "rack.run_once" => false, diff --git a/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/handler/swiftiplied_mongrel.rb b/vendor/plugins/rack/lib/rack/handler/swiftiplied_mongrel.rb similarity index 100% rename from vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/handler/swiftiplied_mongrel.rb rename to vendor/plugins/rack/lib/rack/handler/swiftiplied_mongrel.rb diff --git a/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/handler/thin.rb b/vendor/plugins/rack/lib/rack/handler/thin.rb similarity index 100% rename from vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/handler/thin.rb rename to vendor/plugins/rack/lib/rack/handler/thin.rb diff --git a/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/handler/webrick.rb b/vendor/plugins/rack/lib/rack/handler/webrick.rb similarity index 87% rename from vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/handler/webrick.rb rename to vendor/plugins/rack/lib/rack/handler/webrick.rb index 619632a9..1ef1b8de 100644 --- a/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/handler/webrick.rb +++ b/vendor/plugins/rack/lib/rack/handler/webrick.rb @@ -6,6 +6,7 @@ module Rack module Handler class WEBrick < ::WEBrick::HTTPServlet::AbstractServlet def self.run(app, options={}) + options[:BindAddress] = options.delete(:Host) if options[:Host] server = ::WEBrick::HTTPServer.new(options) server.mount "/", Rack::Handler::WEBrick, app trap(:INT) { server.shutdown } @@ -23,8 +24,11 @@ module Rack env = req.meta_vars env.delete_if { |k, v| v.nil? } + 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], - "rack.input" => StringIO.new(req.body.to_s), + "rack.input" => rack_input, "rack.errors" => $stderr, "rack.multithread" => true, diff --git a/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/head.rb b/vendor/plugins/rack/lib/rack/head.rb similarity index 100% rename from vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/head.rb rename to vendor/plugins/rack/lib/rack/head.rb diff --git a/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/lint.rb b/vendor/plugins/rack/lib/rack/lint.rb similarity index 97% rename from vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/lint.rb rename to vendor/plugins/rack/lib/rack/lint.rb index bb0693d3..796807a0 100644 --- a/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/lint.rb +++ b/vendor/plugins/rack/lib/rack/lint.rb @@ -233,8 +233,17 @@ module Rack ## === The Input Stream ## ## The input stream is an IO-like object which contains the raw HTTP - ## POST data. If it is a file then it must be opened in binary mode. + ## POST data. def check_input(input) + ## When applicable, its external encoding must be "ASCII-8BIT" and it + ## must be opened in binary mode, for Ruby 1.9 compatibility. + assert("rack.input #{input} does not have ASCII-8BIT as its external encoding") { + input.external_encoding.name == "ASCII-8BIT" + } if input.respond_to?(:external_encoding) + 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}") { @@ -291,9 +300,9 @@ 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 } @@ -302,7 +311,7 @@ module Rack !v.nil? } end - + v end @@ -316,7 +325,7 @@ module Rack yield line } end - + ## * +rewind+ must be called without arguments. It rewinds the input ## stream back to the beginning. It must not raise Errno::ESPIPE: ## that is, it may not be a pipe or a socket. Therefore, handler diff --git a/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/lobster.rb b/vendor/plugins/rack/lib/rack/lobster.rb similarity index 100% rename from vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/lobster.rb rename to vendor/plugins/rack/lib/rack/lobster.rb diff --git a/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/lock.rb b/vendor/plugins/rack/lib/rack/lock.rb similarity index 100% rename from vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/lock.rb rename to vendor/plugins/rack/lib/rack/lock.rb diff --git a/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/methodoverride.rb b/vendor/plugins/rack/lib/rack/methodoverride.rb similarity index 100% rename from vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/methodoverride.rb rename to vendor/plugins/rack/lib/rack/methodoverride.rb diff --git a/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/mime.rb b/vendor/plugins/rack/lib/rack/mime.rb similarity index 100% rename from vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/mime.rb rename to vendor/plugins/rack/lib/rack/mime.rb diff --git a/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/mock.rb b/vendor/plugins/rack/lib/rack/mock.rb similarity index 74% rename from vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/mock.rb rename to vendor/plugins/rack/lib/rack/mock.rb index fdefb034..c34a2d7a 100644 --- a/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/mock.rb +++ b/vendor/plugins/rack/lib/rack/mock.rb @@ -73,17 +73,14 @@ 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] ? opts[:method].to_s.upcase : "GET" + env["REQUEST_METHOD"] = opts[:method] || "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] || "" @@ -93,34 +90,16 @@ module Rack env["rack.errors"] = StringIO.new end - if params = opts[:params] - if env["REQUEST_METHOD"] == "GET" - params = Utils.parse_nested_query(params) if params.is_a?(String) - params.update(Utils.parse_nested_query(env["QUERY_STRING"])) - env["QUERY_STRING"] = Utils.build_nested_query(params) - elsif !opts.has_key?(:input) - opts["CONTENT_TYPE"] = "application/x-www-form-urlencoded" - if params.is_a?(Hash) - if data = Utils::Multipart.build_multipart(params) - opts[:input] = data - opts["CONTENT_LENGTH"] ||= data.length.to_s - opts["CONTENT_TYPE"] = "multipart/form-data; boundary=#{Utils::Multipart::MULTIPART_BOUNDARY}" - else - opts[:input] = Utils.build_nested_query(params) - end - else - opts[:input] = params - end - end - end - opts[:input] ||= "" if String === opts[:input] - env["rack.input"] = StringIO.new(opts[:input]) + rack_input = StringIO.new(opts[:input]) else - env["rack.input"] = opts[:input] + rack_input = opts[:input] end + rack_input.set_encoding(Encoding::BINARY) if rack_input.respond_to?(:set_encoding) + env['rack.input'] = rack_input + env["CONTENT_LENGTH"] ||= env["rack.input"].length.to_s opts.each { |field, value| @@ -149,7 +128,7 @@ module Rack @body = "" body.each { |part| @body << part } - @errors = errors.string if errors.respond_to?(:string) + @errors = errors.string end # Status diff --git a/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/recursive.rb b/vendor/plugins/rack/lib/rack/recursive.rb similarity index 100% rename from vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/recursive.rb rename to vendor/plugins/rack/lib/rack/recursive.rb diff --git a/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/reloader.rb b/vendor/plugins/rack/lib/rack/reloader.rb similarity index 96% rename from vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/reloader.rb rename to vendor/plugins/rack/lib/rack/reloader.rb index aa2f060b..a9c566f7 100644 --- a/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/reloader.rb +++ b/vendor/plugins/rack/lib/rack/reloader.rb @@ -70,7 +70,7 @@ module Rack next if file =~ /\.(so|bundle)$/ # cannot reload compiled files found, stat = figure_path(file, paths) - next unless found and stat and mtime = stat.mtime + next unless found && stat && mtime = stat.mtime @cache[file] = found @@ -87,7 +87,7 @@ module Rack found, stat = safe_stat(found) return found, stat if found - paths.each do |possible_path| + paths.find do |possible_path| path = ::File.join(possible_path, file) found, stat = safe_stat(path) return ::File.expand_path(found), stat if found diff --git a/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/request.rb b/vendor/plugins/rack/lib/rack/request.rb similarity index 97% rename from vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/request.rb rename to vendor/plugins/rack/lib/rack/request.rb index 04cdde00..2f64bd6c 100644 --- a/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/request.rb +++ b/vendor/plugins/rack/lib/rack/request.rb @@ -17,14 +17,6 @@ module Rack # The environment of the request. attr_reader :env - def self.new(env, *args) - if self == Rack::Request - env["rack.request"] ||= super - else - super - end - end - def initialize(env) @env = env end @@ -73,7 +65,7 @@ module Rack def host # Remove port number. - (@env["HTTP_HOST"] || @env["SERVER_NAME"]).gsub(/:\d+\z/, '') + (@env["HTTP_HOST"] || @env["SERVER_NAME"]).to_s.gsub(/:\d+\z/, '') end def script_name=(s); @env["SCRIPT_NAME"] = s.to_s end @@ -100,7 +92,7 @@ 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: @@ -222,11 +214,11 @@ module Rack url end - + def path script_name + path_info end - + def fullpath query_string.empty? ? path : "#{path}?#{query_string}" end diff --git a/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/response.rb b/vendor/plugins/rack/lib/rack/response.rb similarity index 100% rename from vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/response.rb rename to vendor/plugins/rack/lib/rack/response.rb diff --git a/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/rewindable_input.rb b/vendor/plugins/rack/lib/rack/rewindable_input.rb similarity index 100% rename from vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/rewindable_input.rb rename to vendor/plugins/rack/lib/rack/rewindable_input.rb diff --git a/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/session/abstract/id.rb b/vendor/plugins/rack/lib/rack/session/abstract/id.rb similarity index 100% rename from vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/session/abstract/id.rb rename to vendor/plugins/rack/lib/rack/session/abstract/id.rb diff --git a/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/session/cookie.rb b/vendor/plugins/rack/lib/rack/session/cookie.rb similarity index 100% rename from vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/session/cookie.rb rename to vendor/plugins/rack/lib/rack/session/cookie.rb diff --git a/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/session/memcache.rb b/vendor/plugins/rack/lib/rack/session/memcache.rb similarity index 100% rename from vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/session/memcache.rb rename to vendor/plugins/rack/lib/rack/session/memcache.rb diff --git a/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/session/pool.rb b/vendor/plugins/rack/lib/rack/session/pool.rb similarity index 100% rename from vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/session/pool.rb rename to vendor/plugins/rack/lib/rack/session/pool.rb diff --git a/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/showexceptions.rb b/vendor/plugins/rack/lib/rack/showexceptions.rb similarity index 100% rename from vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/showexceptions.rb rename to vendor/plugins/rack/lib/rack/showexceptions.rb diff --git a/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/showstatus.rb b/vendor/plugins/rack/lib/rack/showstatus.rb similarity index 100% rename from vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/showstatus.rb rename to vendor/plugins/rack/lib/rack/showstatus.rb diff --git a/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/static.rb b/vendor/plugins/rack/lib/rack/static.rb similarity index 100% rename from vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/static.rb rename to vendor/plugins/rack/lib/rack/static.rb diff --git a/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/urlmap.rb b/vendor/plugins/rack/lib/rack/urlmap.rb similarity index 100% rename from vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/urlmap.rb rename to vendor/plugins/rack/lib/rack/urlmap.rb diff --git a/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/utils.rb b/vendor/plugins/rack/lib/rack/utils.rb similarity index 75% rename from vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/utils.rb rename to vendor/plugins/rack/lib/rack/utils.rb index 42e2e698..d54c928c 100644 --- a/vendor/rails/actionpack/lib/action_controller/vendor/rack-1.1.pre/rack/utils.rb +++ b/vendor/plugins/rack/lib/rack/utils.rb @@ -13,7 +13,7 @@ module Rack # version since it's faster. (Stolen from Camping). def escape(s) s.to_s.gsub(/([^ a-zA-Z0-9_.-]+)/n) { - '%'+$1.unpack('H2'*$1.size).join('%').upcase + '%'+$1.unpack('H2'*bytesize($1)).join('%').upcase }.tr(' ', '+') end module_function :escape @@ -26,16 +26,18 @@ module Rack end 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 # cookies by changing the characters used in the second # parameter (which defaults to '&;'). - def parse_query(qs, d = '&;') + def parse_query(qs, d = nil) params = {} - (qs || '').split(/[#{d}] */n).each do |p| - k, v = unescape(p).split('=', 2) + (qs || '').split(d ? /[#{d}] */n : DEFAULT_SEP).each do |p| + k, v = p.split('=', 2).map { |x| unescape(x) } if cur = params[k] if cur.class == Array @@ -52,10 +54,10 @@ module Rack end module_function :parse_query - def parse_nested_query(qs, d = '&;') + def parse_nested_query(qs, d = nil) params = {} - (qs || '').split(/[#{d}] */n).each do |p| + (qs || '').split(d ? /[#{d}] */n : DEFAULT_SEP).each do |p| k, v = unescape(p).split('=', 2) normalize_params(params, k, v) end @@ -101,31 +103,12 @@ module Rack if v.class == Array build_query(v.map { |x| [k, x] }) else - escape(k) + "=" + escape(v) + "#{escape(k)}=#{escape(v)}" end }.join("&") 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("&", "&"). @@ -310,35 +293,7 @@ module Rack # Usually, Rack::Request#POST takes care of calling this. module Multipart - class UploadedFile - # The filename, *not* including the path, of the "uploaded" file - attr_reader :original_filename - - # The content type of the "uploaded" file - attr_accessor :content_type - - def initialize(path, content_type = "text/plain", binary = false) - raise "#{path} file does not exist" unless ::File.exist?(path) - @content_type = content_type - @original_filename = ::File.basename(path) - @tempfile = Tempfile.new(@original_filename) - @tempfile.set_encoding(Encoding::BINARY) if @tempfile.respond_to?(:set_encoding) - @tempfile.binmode if binary - FileUtils.copy_file(path, @tempfile.path) - end - - def path - @tempfile.path - end - alias_method :local_path, :path - - def method_missing(method_name, *args, &block) #:nodoc: - @tempfile.__send__(method_name, *args, &block) - end - end - EOL = "\r\n" - MULTIPART_BOUNDARY = "AaB03x" def self.parse_multipart(env) unless env['CONTENT_TYPE'] =~ @@ -375,7 +330,7 @@ module Rack head = buf.slice!(0, i+2) # First \r\n buf.slice!(0, 2) # Second \r\n - filename = head[/Content-Disposition:.* filename="?([^\";]*)"?/ni, 1] + filename = head[/Content-Disposition:.* filename=(?:"((?:\\.|[^\"])*)"|([^;\s]*))/ni, 1] content_type = head[/Content-Type: (.*)#{EOL}/ni, 1] name = head[/Content-Disposition:.*\s+name="?([^\";]*)"?/ni, 1] || head[/Content-ID:\s*([^#{EOL}]*)/ni, 1] @@ -423,7 +378,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} @@ -441,76 +396,6 @@ 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/test/cgi/lighttpd.conf b/vendor/plugins/rack/test/cgi/lighttpd.conf new file mode 100644 index 00000000..889726c6 --- /dev/null +++ b/vendor/plugins/rack/test/cgi/lighttpd.conf @@ -0,0 +1,20 @@ +server.modules = ("mod_fastcgi", "mod_cgi") +server.document-root = "." +server.errorlog = "lighttpd.errors" +server.port = 9203 + +server.event-handler = "select" + +cgi.assign = ("/test" => "", +# ".ru" => "" + ) + +fastcgi.server = ("test.fcgi" => ("localhost" => + ("min-procs" => 1, + "socket" => "/tmp/rack-test-fcgi", + "bin-path" => "test.fcgi")), + "test.ru" => ("localhost" => + ("min-procs" => 1, + "socket" => "/tmp/rack-test-ru-fcgi", + "bin-path" => "test.ru")), + ) diff --git a/vendor/plugins/rack/test/cgi/test b/vendor/plugins/rack/test/cgi/test new file mode 100755 index 00000000..e4837a4e --- /dev/null +++ b/vendor/plugins/rack/test/cgi/test @@ -0,0 +1,9 @@ +#!/usr/bin/env ruby +# -*- ruby -*- + +$: << File.join(File.dirname(__FILE__), "..", "..", "lib") + +require 'rack' +require '../testrequest' + +Rack::Handler::CGI.run(Rack::Lint.new(TestRequest.new)) diff --git a/vendor/plugins/rack/test/cgi/test.fcgi b/vendor/plugins/rack/test/cgi/test.fcgi new file mode 100755 index 00000000..5e104fc9 --- /dev/null +++ b/vendor/plugins/rack/test/cgi/test.fcgi @@ -0,0 +1,8 @@ +#!/usr/bin/env ruby +# -*- ruby -*- + +$:.unshift '../../lib' +require 'rack' +require '../testrequest' + +Rack::Handler::FastCGI.run(Rack::Lint.new(TestRequest.new)) diff --git a/vendor/plugins/rack/test/cgi/test.ru b/vendor/plugins/rack/test/cgi/test.ru new file mode 100755 index 00000000..4054b886 --- /dev/null +++ b/vendor/plugins/rack/test/cgi/test.ru @@ -0,0 +1,7 @@ +#!/usr/bin/env ../../bin/rackup +#\ -E deployment -I ../../lib +# -*- ruby -*- + +require '../testrequest' + +run TestRequest.new diff --git a/vendor/plugins/rack/test/multipart/binary b/vendor/plugins/rack/test/multipart/binary new file mode 100644 index 0000000000000000000000000000000000000000..a3bd67c4973fae2a6aaff0f69b50f2bde312d298 GIT binary patch literal 26667 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 H9sB 'text/plain'}, ["Hi #{env['REMOTE_USER']}"] ] } + end + + def protected_app + app = Rack::Auth::Basic.new(unprotected_app) { |username, password| 'Boss' == username } + app.realm = realm + app + end + + setup do + @request = Rack::MockRequest.new(protected_app) + end + + def request_with_basic_auth(username, password, &block) + request 'HTTP_AUTHORIZATION' => 'Basic ' + ["#{username}:#{password}"].pack("m*"), &block + end + + def request(headers = {}) + yield @request.get('/', headers) + end + + def assert_basic_auth_challenge(response) + response.should.be.a.client_error + response.status.should.equal 401 + response.should.include 'WWW-Authenticate' + response.headers['WWW-Authenticate'].should =~ /Basic realm="#{Regexp.escape(realm)}"/ + response.body.should.be.empty + end + + specify 'should challenge correctly when no credentials are specified' do + request do |response| + assert_basic_auth_challenge response + end + end + + specify 'should rechallenge if incorrect credentials are specified' do + request_with_basic_auth 'joe', 'password' do |response| + assert_basic_auth_challenge response + end + end + + specify 'should return application output if correct credentials are specified' do + request_with_basic_auth 'Boss', 'password' do |response| + response.status.should.equal 200 + response.body.to_s.should.equal 'Hi Boss' + end + end + + specify 'should return 400 Bad Request if different auth scheme used' do + request 'HTTP_AUTHORIZATION' => 'Digest params' do |response| + response.should.be.a.client_error + response.status.should.equal 400 + response.should.not.include 'WWW-Authenticate' + end + end + + specify 'realm as optional constructor arg' do + app = Rack::Auth::Basic.new(unprotected_app, realm) { true } + assert_equal realm, app.realm + end +end diff --git a/vendor/plugins/rack/test/spec_rack_auth_digest.rb b/vendor/plugins/rack/test/spec_rack_auth_digest.rb new file mode 100644 index 00000000..a980acc8 --- /dev/null +++ b/vendor/plugins/rack/test/spec_rack_auth_digest.rb @@ -0,0 +1,226 @@ +require 'test/spec' + +require 'rack/auth/digest/md5' +require 'rack/mock' + +context 'Rack::Auth::Digest::MD5' do + + def realm + 'WallysWorld' + end + + def unprotected_app + lambda do |env| + [ 200, {'Content-Type' => 'text/plain'}, ["Hi #{env['REMOTE_USER']}"] ] + end + end + + def protected_app + app = Rack::Auth::Digest::MD5.new(unprotected_app) do |username| + { 'Alice' => 'correct-password' }[username] + end + app.realm = realm + app.opaque = 'this-should-be-secret' + app + end + + def protected_app_with_hashed_passwords + app = Rack::Auth::Digest::MD5.new(unprotected_app) do |username| + username == 'Alice' ? Digest::MD5.hexdigest("Alice:#{realm}:correct-password") : nil + end + app.realm = realm + app.opaque = 'this-should-be-secret' + app.passwords_hashed = true + app + end + + def partially_protected_app + Rack::URLMap.new({ + '/' => unprotected_app, + '/protected' => protected_app + }) + end + + def protected_app_with_method_override + Rack::MethodOverride.new(protected_app) + end + + setup do + @request = Rack::MockRequest.new(protected_app) + end + + def request(method, path, headers = {}, &block) + response = @request.request(method, path, headers) + block.call(response) if block + return response + end + + class MockDigestRequest + def initialize(params) + @params = params + end + def method_missing(sym) + if @params.has_key? k = sym.to_s + return @params[k] + end + super + end + def method + @params['method'] + end + def response(password) + Rack::Auth::Digest::MD5.new(nil).send :digest, self, password + end + end + + def request_with_digest_auth(method, path, username, password, options = {}, &block) + request_options = {} + request_options[:input] = options.delete(:input) if options.include? :input + + response = request(method, path, request_options) + + return response unless response.status == 401 + + if wait = options.delete(:wait) + sleep wait + end + + challenge = response['WWW-Authenticate'].split(' ', 2).last + + params = Rack::Auth::Digest::Params.parse(challenge) + + params['username'] = username + params['nc'] = '00000001' + params['cnonce'] = 'nonsensenonce' + params['uri'] = path + + params['method'] = method + + params.update options + + params['response'] = MockDigestRequest.new(params).response(password) + + request(method, path, request_options.merge('HTTP_AUTHORIZATION' => "Digest #{params}"), &block) + end + + def assert_digest_auth_challenge(response) + response.should.be.a.client_error + response.status.should.equal 401 + response.should.include 'WWW-Authenticate' + response.headers['WWW-Authenticate'].should =~ /^Digest / + response.body.should.be.empty + end + + def assert_bad_request(response) + response.should.be.a.client_error + response.status.should.equal 400 + response.should.not.include 'WWW-Authenticate' + end + + specify 'should challenge when no credentials are specified' do + request 'GET', '/' do |response| + assert_digest_auth_challenge response + end + end + + specify 'should return application output if correct credentials given' do + request_with_digest_auth 'GET', '/', 'Alice', 'correct-password' do |response| + response.status.should.equal 200 + response.body.to_s.should.equal 'Hi Alice' + end + end + + specify 'should return application output if correct credentials given (hashed passwords)' do + @request = Rack::MockRequest.new(protected_app_with_hashed_passwords) + + request_with_digest_auth 'GET', '/', 'Alice', 'correct-password' do |response| + response.status.should.equal 200 + response.body.to_s.should.equal 'Hi Alice' + end + end + + specify 'should rechallenge if incorrect username given' do + request_with_digest_auth 'GET', '/', 'Bob', 'correct-password' do |response| + assert_digest_auth_challenge response + end + end + + specify 'should rechallenge if incorrect password given' do + request_with_digest_auth 'GET', '/', 'Alice', 'wrong-password' do |response| + assert_digest_auth_challenge response + end + end + + specify 'should rechallenge with stale parameter if nonce is stale' do + begin + Rack::Auth::Digest::Nonce.time_limit = 1 + + request_with_digest_auth 'GET', '/', 'Alice', 'correct-password', :wait => 2 do |response| + assert_digest_auth_challenge response + response.headers['WWW-Authenticate'].should =~ /\bstale=true\b/ + end + ensure + Rack::Auth::Digest::Nonce.time_limit = nil + end + end + + specify 'should return 400 Bad Request if incorrect qop given' do + request_with_digest_auth 'GET', '/', 'Alice', 'correct-password', 'qop' => 'auth-int' do |response| + assert_bad_request response + end + end + + specify 'should return 400 Bad Request if incorrect uri given' do + request_with_digest_auth 'GET', '/', 'Alice', 'correct-password', 'uri' => '/foo' do |response| + assert_bad_request response + end + end + + specify 'should return 400 Bad Request if different auth scheme used' do + request 'GET', '/', 'HTTP_AUTHORIZATION' => 'Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==' do |response| + assert_bad_request response + end + end + + specify 'should not require credentials for unprotected path' do + @request = Rack::MockRequest.new(partially_protected_app) + request 'GET', '/' do |response| + response.should.be.ok + end + end + + specify 'should challenge when no credentials are specified for protected path' do + @request = Rack::MockRequest.new(partially_protected_app) + request 'GET', '/protected' do |response| + assert_digest_auth_challenge response + end + end + + specify 'should return application output if correct credentials given for protected path' do + @request = Rack::MockRequest.new(partially_protected_app) + request_with_digest_auth 'GET', '/protected', 'Alice', 'correct-password' do |response| + response.status.should.equal 200 + response.body.to_s.should.equal 'Hi Alice' + end + end + + specify 'should return application output if correct credentials given for POST' do + request_with_digest_auth 'POST', '/', 'Alice', 'correct-password' do |response| + response.status.should.equal 200 + response.body.to_s.should.equal 'Hi Alice' + end + end + + specify 'should return application output if correct credentials given for PUT (using method override of POST)' do + @request = Rack::MockRequest.new(protected_app_with_method_override) + request_with_digest_auth 'POST', '/', 'Alice', 'correct-password', :input => "_method=put" do |response| + response.status.should.equal 200 + response.body.to_s.should.equal 'Hi Alice' + end + end + + specify 'realm as optional constructor arg' do + app = Rack::Auth::Digest::MD5.new(unprotected_app, realm) { true } + assert_equal realm, app.realm + end +end diff --git a/vendor/plugins/rack/test/spec_rack_auth_openid.rb b/vendor/plugins/rack/test/spec_rack_auth_openid.rb new file mode 100644 index 00000000..ba248445 --- /dev/null +++ b/vendor/plugins/rack/test/spec_rack_auth_openid.rb @@ -0,0 +1,84 @@ +require 'test/spec' + +begin +# requires the ruby-openid gem +require 'rack/auth/openid' + +context "Rack::Auth::OpenID" do + OID = Rack::Auth::OpenID + host = 'host' + subd = 'sub.host' + wild = '*.host' + path = 'path' + long = 'path/long' + scheme = 'http://' + realm = scheme+host+'/'+path + + specify 'realm uri should be valid' do + lambda{OID.new('/'+path)}.should.raise ArgumentError + lambda{OID.new('/'+long)}.should.raise ArgumentError + lambda{OID.new(scheme+host)}.should.not.raise + lambda{OID.new(scheme+host+'/')}.should.not.raise + lambda{OID.new(scheme+host+'/'+path)}.should.not.raise + lambda{OID.new(scheme+subd)}.should.not.raise + lambda{OID.new(scheme+subd+'/')}.should.not.raise + lambda{OID.new(scheme+subd+'/'+path)}.should.not.raise + end + + specify 'should be able to check if a uri is within the realm' do + end + + specify 'return_to should be valid' do + uri = '/'+path + lambda{OID.new(realm, :return_to=>uri)}.should.raise ArgumentError + uri = '/'+long + lambda{OID.new(realm, :return_to=>uri)}.should.raise ArgumentError + uri = scheme+host + lambda{OID.new(realm, :return_to=>uri)}.should.raise ArgumentError + uri = scheme+host+'/'+path + lambda{OID.new(realm, :return_to=>uri)}.should.not.raise + uri = scheme+subd+'/'+path + lambda{OID.new(realm, :return_to=>uri)}.should.raise ArgumentError + uri = scheme+host+'/'+long + lambda{OID.new(realm, :return_to=>uri)}.should.not.raise + uri = scheme+subd+'/'+long + lambda{OID.new(realm, :return_to=>uri)}.should.raise ArgumentError + end + + specify 'extensions should have required constants defined' do + badext = Rack::Auth::OpenID::BadExtension + ext = Object.new + lambda{OID.new(realm).add_extension(ext)}.should.raise(badext) + ext = Module.new + lambda{OID.new(realm).add_extension(ext)}.should.raise(badext) + ext::Request = nil + lambda{OID.new(realm).add_extension(ext)}.should.raise(badext) + ext::Response = nil + lambda{OID.new(realm).add_extension(ext)}.should.raise(badext) + ext::NS_URI = nil + lambda{OID.new(realm).add_extension(ext)}.should.raise(badext) + end + + specify 'extensions should have Request and Response defined and inherit from OpenID::Extension' do + $-w, w = nil, $-w # yuck + badext = Rack::Auth::OpenID::BadExtension + ext = Module.new + ext::Request = nil + ext::Response = nil + ext::NS_URI = nil + lambda{OID.new(realm).add_extension(ext)}.should.raise(badext) + ext::Request = Class.new() + lambda{OID.new(realm).add_extension(ext)}.should.raise(badext) + ext::Response = Class.new() + lambda{OID.new(realm).add_extension(ext)}.should.raise(badext) + ext::Request = Class.new(::OpenID::Extension) + lambda{OID.new(realm).add_extension(ext)}.should.raise(badext) + ext::Response = Class.new(::OpenID::Extension) + lambda{OID.new(realm).add_extension(ext)}.should.raise(badext) + $-w = w + end +end + +rescue LoadError + $stderr.puts "Skipping Rack::Auth::OpenID tests (ruby-openid 2 is required). `gem install ruby-openid` and try again." +end diff --git a/vendor/plugins/rack/test/spec_rack_builder.rb b/vendor/plugins/rack/test/spec_rack_builder.rb new file mode 100644 index 00000000..3fad9810 --- /dev/null +++ b/vendor/plugins/rack/test/spec_rack_builder.rb @@ -0,0 +1,84 @@ +require 'test/spec' + +require 'rack/builder' +require 'rack/mock' +require 'rack/showexceptions' +require 'rack/auth/basic' + +context "Rack::Builder" do + specify "chains apps by default" do + app = Rack::Builder.new do + use Rack::ShowExceptions + run lambda { |env| raise "bzzzt" } + end.to_app + + Rack::MockRequest.new(app).get("/").should.be.server_error + Rack::MockRequest.new(app).get("/").should.be.server_error + Rack::MockRequest.new(app).get("/").should.be.server_error + end + + specify "has implicit #to_app" do + app = Rack::Builder.new do + use Rack::ShowExceptions + run lambda { |env| raise "bzzzt" } + end + + Rack::MockRequest.new(app).get("/").should.be.server_error + Rack::MockRequest.new(app).get("/").should.be.server_error + Rack::MockRequest.new(app).get("/").should.be.server_error + end + + specify "supports blocks on use" do + app = Rack::Builder.new do + use Rack::ShowExceptions + use Rack::Auth::Basic do |username, password| + 'secret' == password + end + + run lambda { |env| [200, {}, ['Hi Boss']] } + end + + response = Rack::MockRequest.new(app).get("/") + response.should.be.client_error + response.status.should.equal 401 + + # with auth... + response = Rack::MockRequest.new(app).get("/", + 'HTTP_AUTHORIZATION' => 'Basic ' + ["joe:secret"].pack("m*")) + response.status.should.equal 200 + response.body.to_s.should.equal 'Hi Boss' + end + + specify "has explicit #to_app" do + app = Rack::Builder.app do + use Rack::ShowExceptions + run lambda { |env| raise "bzzzt" } + end + + Rack::MockRequest.new(app).get("/").should.be.server_error + Rack::MockRequest.new(app).get("/").should.be.server_error + Rack::MockRequest.new(app).get("/").should.be.server_error + end + + specify "apps are initialized once" do + app = Rack::Builder.new do + class AppClass + def initialize + @called = 0 + end + def call(env) + raise "bzzzt" if @called > 0 + @called += 1 + [200, {'Content-Type' => 'text/plain'}, ['OK']] + end + end + + use Rack::ShowExceptions + run AppClass.new + end + + Rack::MockRequest.new(app).get("/").status.should.equal 200 + Rack::MockRequest.new(app).get("/").should.be.server_error + end + +end diff --git a/vendor/plugins/rack/test/spec_rack_camping.rb b/vendor/plugins/rack/test/spec_rack_camping.rb new file mode 100644 index 00000000..bed11710 --- /dev/null +++ b/vendor/plugins/rack/test/spec_rack_camping.rb @@ -0,0 +1,51 @@ +require 'test/spec' +require 'stringio' +require 'uri' + +begin + require 'rack/mock' + + $-w, w = nil, $-w # yuck + require 'camping' + require 'rack/adapter/camping' + + Camping.goes :CampApp + module CampApp + module Controllers + class HW < R('/') + def get + @headers["X-Served-By"] = URI("http://rack.rubyforge.org") + "Camping works!" + end + + def post + "Data: #{input.foo}" + end + end + end + end + $-w = w + + context "Rack::Adapter::Camping" do + specify "works with GET" do + res = Rack::MockRequest.new(Rack::Adapter::Camping.new(CampApp)). + get("/") + + res.should.be.ok + res["Content-Type"].should.equal "text/html" + res["X-Served-By"].should.equal "http://rack.rubyforge.org" + + res.body.should.equal "Camping works!" + end + + specify "works with POST" do + res = Rack::MockRequest.new(Rack::Adapter::Camping.new(CampApp)). + post("/", :input => "foo=bar") + + res.should.be.ok + res.body.should.equal "Data: bar" + end + end +rescue LoadError + $stderr.puts "Skipping Rack::Adapter::Camping tests (Camping is required). `gem install camping` and try again." +end diff --git a/vendor/plugins/rack/test/spec_rack_cascade.rb b/vendor/plugins/rack/test/spec_rack_cascade.rb new file mode 100644 index 00000000..3c0f3be3 --- /dev/null +++ b/vendor/plugins/rack/test/spec_rack_cascade.rb @@ -0,0 +1,50 @@ +require 'test/spec' + +require 'rack/cascade' +require 'rack/mock' + +require 'rack/urlmap' +require 'rack/file' + +context "Rack::Cascade" do + docroot = File.expand_path(File.dirname(__FILE__)) + app1 = Rack::File.new(docroot) + + app2 = Rack::URLMap.new("/crash" => lambda { |env| raise "boom" }) + + app3 = Rack::URLMap.new("/foo" => lambda { |env| + [200, { "Content-Type" => "text/plain"}, [""]]}) + + specify "should dispatch onward on 404 by default" do + cascade = Rack::Cascade.new([app1, app2, app3]) + Rack::MockRequest.new(cascade).get("/cgi/test").should.be.ok + Rack::MockRequest.new(cascade).get("/foo").should.be.ok + Rack::MockRequest.new(cascade).get("/toobad").should.be.not_found + Rack::MockRequest.new(cascade).get("/cgi/../bla").should.be.forbidden + end + + specify "should dispatch onward on whatever is passed" do + cascade = Rack::Cascade.new([app1, app2, app3], [404, 403]) + 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) + end + + specify "should append new app" do + cascade = Rack::Cascade.new([], [404, 403]) + lambda { Rack::MockRequest.new(cascade).get('/cgi/test') }. + should.raise(ArgumentError) + cascade << app2 + Rack::MockRequest.new(cascade).get('/cgi/test').should.be.not_found + Rack::MockRequest.new(cascade).get('/cgi/../bla').should.be.not_found + cascade << app1 + Rack::MockRequest.new(cascade).get('/cgi/test').should.be.ok + Rack::MockRequest.new(cascade).get('/cgi/../bla').should.be.forbidden + Rack::MockRequest.new(cascade).get('/foo').should.be.not_found + cascade << app3 + Rack::MockRequest.new(cascade).get('/foo').should.be.ok + end +end diff --git a/vendor/plugins/rack/test/spec_rack_cgi.rb b/vendor/plugins/rack/test/spec_rack_cgi.rb new file mode 100644 index 00000000..818fabdf --- /dev/null +++ b/vendor/plugins/rack/test/spec_rack_cgi.rb @@ -0,0 +1,89 @@ +require 'test/spec' +require 'testrequest' + +context "Rack::Handler::CGI" do + include TestRequest::Helpers + + setup do + @host = '0.0.0.0' + @port = 9203 + end + + # Keep this first. + specify "startup" do + $pid = fork { + Dir.chdir(File.join(File.dirname(__FILE__), "..", "test", "cgi")) + exec "lighttpd -D -f lighttpd.conf" + } + end + + specify "should respond" do + sleep 1 + lambda { + GET("/test") + }.should.not.raise + end + + specify "should be a lighttpd" do + GET("/test") + status.should.be 200 + response["SERVER_SOFTWARE"].should =~ /lighttpd/ + response["HTTP_VERSION"].should.equal "HTTP/1.1" + response["SERVER_PROTOCOL"].should.equal "HTTP/1.1" + response["SERVER_PORT"].should.equal @port.to_s + response["SERVER_NAME"].should =~ @host + end + + specify "should have rack headers" do + GET("/test") + response["rack.version"].should.equal [1,0] + response["rack.multithread"].should.be false + response["rack.multiprocess"].should.be true + response["rack.run_once"].should.be true + end + + specify "should have CGI headers on GET" do + GET("/test") + response["REQUEST_METHOD"].should.equal "GET" + response["SCRIPT_NAME"].should.equal "/test" + response["REQUEST_PATH"].should.equal "/" + response["PATH_INFO"].should.be.nil + response["QUERY_STRING"].should.equal "" + response["test.postdata"].should.equal "" + + GET("/test/foo?quux=1") + response["REQUEST_METHOD"].should.equal "GET" + response["SCRIPT_NAME"].should.equal "/test" + response["REQUEST_PATH"].should.equal "/" + response["PATH_INFO"].should.equal "/foo" + response["QUERY_STRING"].should.equal "quux=1" + end + + specify "should have CGI headers on POST" do + POST("/test", {"rack-form-data" => "23"}, {'X-test-header' => '42'}) + status.should.equal 200 + response["REQUEST_METHOD"].should.equal "POST" + response["SCRIPT_NAME"].should.equal "/test" + response["REQUEST_PATH"].should.equal "/" + response["QUERY_STRING"].should.equal "" + response["HTTP_X_TEST_HEADER"].should.equal "42" + response["test.postdata"].should.equal "rack-form-data=23" + end + + specify "should support HTTP auth" do + GET("/test", {:user => "ruth", :passwd => "secret"}) + response["HTTP_AUTHORIZATION"].should.equal "Basic cnV0aDpzZWNyZXQ=" + end + + specify "should set status" do + GET("/test?secret") + status.should.equal 403 + response["rack.url_scheme"].should.equal "http" + end + + # Keep this last. + specify "shutdown" do + Process.kill 15, $pid + Process.wait($pid).should.equal $pid + end +end diff --git a/vendor/plugins/rack/test/spec_rack_chunked.rb b/vendor/plugins/rack/test/spec_rack_chunked.rb new file mode 100644 index 00000000..39eea482 --- /dev/null +++ b/vendor/plugins/rack/test/spec_rack_chunked.rb @@ -0,0 +1,62 @@ +require 'rack/mock' +require 'rack/chunked' +require 'rack/utils' + +context "Rack::Chunked" do + + before do + @env = Rack::MockRequest. + env_for('/', 'HTTP_VERSION' => '1.1', 'REQUEST_METHOD' => 'GET') + end + + specify 'chunks responses with no Content-Length' do + app = lambda { |env| [200, {}, ['Hello', ' ', 'World!']] } + response = Rack::MockResponse.new(*Rack::Chunked.new(app).call(@env)) + response.headers.should.not.include 'Content-Length' + response.headers['Transfer-Encoding'].should.equal 'chunked' + response.body.should.equal "5\r\nHello\r\n1\r\n \r\n6\r\nWorld!\r\n0\r\n\r\n" + end + + specify 'chunks empty bodies properly' do + app = lambda { |env| [200, {}, []] } + response = Rack::MockResponse.new(*Rack::Chunked.new(app).call(@env)) + response.headers.should.not.include 'Content-Length' + response.headers['Transfer-Encoding'].should.equal 'chunked' + response.body.should.equal "0\r\n\r\n" + end + + specify 'does not modify response when Content-Length header present' do + app = lambda { |env| [200, {'Content-Length'=>'12'}, ['Hello', ' ', 'World!']] } + status, headers, body = Rack::Chunked.new(app).call(@env) + status.should.equal 200 + headers.should.not.include 'Transfer-Encoding' + headers.should.include 'Content-Length' + body.join.should.equal 'Hello World!' + end + + specify 'does not modify response when client is HTTP/1.0' do + app = lambda { |env| [200, {}, ['Hello', ' ', 'World!']] } + @env['HTTP_VERSION'] = 'HTTP/1.0' + status, headers, body = Rack::Chunked.new(app).call(@env) + status.should.equal 200 + headers.should.not.include 'Transfer-Encoding' + body.join.should.equal 'Hello World!' + end + + specify 'does not modify response when Transfer-Encoding header already present' do + app = lambda { |env| [200, {'Transfer-Encoding' => 'identity'}, ['Hello', ' ', 'World!']] } + status, headers, body = Rack::Chunked.new(app).call(@env) + status.should.equal 200 + headers['Transfer-Encoding'].should.equal 'identity' + body.join.should.equal 'Hello World!' + end + + [100, 204, 304].each do |status_code| + specify "does not modify response when status code is #{status_code}" do + app = lambda { |env| [status_code, {}, []] } + status, headers, body = Rack::Chunked.new(app).call(@env) + status.should.equal status_code + headers.should.not.include 'Transfer-Encoding' + end + end +end diff --git a/vendor/plugins/rack/test/spec_rack_commonlogger.rb b/vendor/plugins/rack/test/spec_rack_commonlogger.rb new file mode 100644 index 00000000..ba03b78a --- /dev/null +++ b/vendor/plugins/rack/test/spec_rack_commonlogger.rb @@ -0,0 +1,32 @@ +require 'test/spec' +require 'stringio' + +require 'rack/commonlogger' +require 'rack/lobster' +require 'rack/mock' + +context "Rack::CommonLogger" do + app = lambda { |env| + [200, + {"Content-Type" => "text/html"}, + ["foo"]]} + + 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 + end + + specify "should log to anything with <<" do + log = "" + res = Rack::MockRequest.new(Rack::CommonLogger.new(app, log)).get("/") + + log.should =~ /GET / + log.should =~ / 200 / # status + log.should =~ / 3 / # length + end +end diff --git a/vendor/plugins/rack/test/spec_rack_conditionalget.rb b/vendor/plugins/rack/test/spec_rack_conditionalget.rb new file mode 100644 index 00000000..ca34cc92 --- /dev/null +++ b/vendor/plugins/rack/test/spec_rack_conditionalget.rb @@ -0,0 +1,41 @@ +require 'test/spec' +require 'time' + +require 'rack/mock' +require 'rack/conditionalget' + +context "Rack::ConditionalGet" do + specify "should set a 304 status and truncate body when If-Modified-Since hits" do + timestamp = Time.now.httpdate + app = Rack::ConditionalGet.new(lambda { |env| + [200, {'Last-Modified'=>timestamp}, ['TEST']] }) + + response = Rack::MockRequest.new(app). + get("/", 'HTTP_IF_MODIFIED_SINCE' => timestamp) + + response.status.should.equal 304 + response.body.should.be.empty + end + + specify "should set a 304 status and truncate body when If-None-Match hits" do + app = Rack::ConditionalGet.new(lambda { |env| + [200, {'Etag'=>'1234'}, ['TEST']] }) + + response = Rack::MockRequest.new(app). + get("/", 'HTTP_IF_NONE_MATCH' => '1234') + + response.status.should.equal 304 + response.body.should.be.empty + end + + specify "should not affect non-GET/HEAD requests" do + app = Rack::ConditionalGet.new(lambda { |env| + [200, {'Etag'=>'1234'}, ['TEST']] }) + + response = Rack::MockRequest.new(app). + post("/", 'HTTP_IF_NONE_MATCH' => '1234') + + response.status.should.equal 200 + response.body.should.equal 'TEST' + end +end diff --git a/vendor/plugins/rack/test/spec_rack_content_length.rb b/vendor/plugins/rack/test/spec_rack_content_length.rb new file mode 100644 index 00000000..7db9345f --- /dev/null +++ b/vendor/plugins/rack/test/spec_rack_content_length.rb @@ -0,0 +1,43 @@ +require 'rack/mock' +require 'rack/content_length' + +context "Rack::ContentLength" do + specify "sets Content-Length on String bodies if none is set" do + app = lambda { |env| [200, {'Content-Type' => 'text/plain'}, "Hello, World!"] } + response = Rack::ContentLength.new(app).call({}) + response[1]['Content-Length'].should.equal '13' + end + + specify "sets Content-Length on Array bodies if none is set" do + app = lambda { |env| [200, {'Content-Type' => 'text/plain'}, ["Hello, World!"]] } + response = Rack::ContentLength.new(app).call({}) + response[1]['Content-Length'].should.equal '13' + end + + specify "does not set Content-Length on variable length bodies" do + body = lambda { "Hello World!" } + def body.each ; yield call ; end + + app = lambda { |env| [200, {'Content-Type' => 'text/plain'}, body] } + response = Rack::ContentLength.new(app).call({}) + response[1]['Content-Length'].should.be.nil + end + + specify "does not change Content-Length if it is already set" do + app = lambda { |env| [200, {'Content-Type' => 'text/plain', 'Content-Length' => '1'}, "Hello, World!"] } + response = Rack::ContentLength.new(app).call({}) + response[1]['Content-Length'].should.equal '1' + end + + specify "does not set Content-Length on 304 responses" do + app = lambda { |env| [304, {'Content-Type' => 'text/plain'}, []] } + response = Rack::ContentLength.new(app).call({}) + response[1]['Content-Length'].should.equal nil + end + + specify "does not set Content-Length when Transfer-Encoding is chunked" do + app = lambda { |env| [200, {'Transfer-Encoding' => 'chunked'}, []] } + response = Rack::ContentLength.new(app).call({}) + response[1]['Content-Length'].should.equal nil + end +end diff --git a/vendor/plugins/rack/test/spec_rack_content_type.rb b/vendor/plugins/rack/test/spec_rack_content_type.rb new file mode 100644 index 00000000..9975b94d --- /dev/null +++ b/vendor/plugins/rack/test/spec_rack_content_type.rb @@ -0,0 +1,30 @@ +require 'rack/mock' +require 'rack/content_type' + +context "Rack::ContentType" do + specify "sets Content-Type to default text/html if none is set" do + app = lambda { |env| [200, {}, "Hello, World!"] } + status, headers, body = Rack::ContentType.new(app).call({}) + headers['Content-Type'].should.equal 'text/html' + end + + specify "sets Content-Type to chosen default if none is set" do + app = lambda { |env| [200, {}, "Hello, World!"] } + status, headers, body = + Rack::ContentType.new(app, 'application/octet-stream').call({}) + headers['Content-Type'].should.equal 'application/octet-stream' + end + + specify "does not change Content-Type if it is already set" do + app = lambda { |env| [200, {'Content-Type' => 'foo/bar'}, "Hello, World!"] } + status, headers, body = Rack::ContentType.new(app).call({}) + headers['Content-Type'].should.equal 'foo/bar' + end + + specify "case insensitive detection of Content-Type" do + app = lambda { |env| [200, {'CONTENT-Type' => 'foo/bar'}, "Hello, World!"] } + status, headers, body = Rack::ContentType.new(app).call({}) + headers.to_a.select { |k,v| k.downcase == "content-type" }. + should.equal [["CONTENT-Type","foo/bar"]] + end +end diff --git a/vendor/plugins/rack/test/spec_rack_deflater.rb b/vendor/plugins/rack/test/spec_rack_deflater.rb new file mode 100644 index 00000000..c9bb3189 --- /dev/null +++ b/vendor/plugins/rack/test/spec_rack_deflater.rb @@ -0,0 +1,127 @@ +require 'test/spec' + +require 'rack/mock' +require 'rack/deflater' +require 'stringio' +require 'time' # for Time#httpdate + +context "Rack::Deflater" do + def build_response(status, body, accept_encoding, headers = {}) + body = [body] if body.respond_to? :to_str + app = lambda { |env| [status, {}, body] } + request = Rack::MockRequest.env_for("", headers.merge("HTTP_ACCEPT_ENCODING" => accept_encoding)) + response = Rack::Deflater.new(app).call(request) + + return response + end + + specify "should be able to deflate bodies that respond to each" do + body = Object.new + class << body; def each; yield("foo"); yield("bar"); end; end + + response = build_response(200, body, "deflate") + + response[0].should.equal(200) + response[1].should.equal({ + "Content-Encoding" => "deflate", + "Vary" => "Accept-Encoding" + }) + buf = '' + response[2].each { |part| buf << part } + buf.should.equal("K\313\317OJ,\002\000") + end + + # TODO: This is really just a special case of the above... + specify "should be able to deflate String bodies" do + response = build_response(200, "Hello world!", "deflate") + + response[0].should.equal(200) + response[1].should.equal({ + "Content-Encoding" => "deflate", + "Vary" => "Accept-Encoding" + }) + buf = '' + response[2].each { |part| buf << part } + buf.should.equal("\363H\315\311\311W(\317/\312IQ\004\000") + end + + specify "should be able to gzip bodies that respond to each" do + body = Object.new + class << body; def each; yield("foo"); yield("bar"); end; end + + response = build_response(200, body, "gzip") + + response[0].should.equal(200) + response[1].should.equal({ + "Content-Encoding" => "gzip", + "Vary" => "Accept-Encoding", + }) + + buf = '' + response[2].each { |part| buf << part } + io = StringIO.new(buf) + gz = Zlib::GzipReader.new(io) + gz.read.should.equal("foobar") + gz.close + end + + specify "should be able to fallback to no deflation" do + response = build_response(200, "Hello world!", "superzip") + + response[0].should.equal(200) + response[1].should.equal({ "Vary" => "Accept-Encoding" }) + response[2].should.equal(["Hello world!"]) + end + + specify "should be able to skip when there is no response entity body" do + response = build_response(304, [], "gzip") + + response[0].should.equal(304) + response[1].should.equal({}) + response[2].should.equal([]) + end + + specify "should handle the lack of an acceptable encoding" do + response1 = build_response(200, "Hello world!", "identity;q=0", "PATH_INFO" => "/") + response1[0].should.equal(406) + response1[1].should.equal({"Content-Type" => "text/plain", "Content-Length" => "71"}) + response1[2].should.equal(["An acceptable encoding for the requested resource / could not be found."]) + + response2 = build_response(200, "Hello world!", "identity;q=0", "SCRIPT_NAME" => "/foo", "PATH_INFO" => "/bar") + response2[0].should.equal(406) + response2[1].should.equal({"Content-Type" => "text/plain", "Content-Length" => "78"}) + response2[2].should.equal(["An acceptable encoding for the requested resource /foo/bar could not be found."]) + end + + specify "should handle gzip response with Last-Modified header" do + last_modified = Time.now.httpdate + + app = lambda { |env| [200, { "Last-Modified" => last_modified }, ["Hello World!"]] } + request = Rack::MockRequest.env_for("", "HTTP_ACCEPT_ENCODING" => "gzip") + response = Rack::Deflater.new(app).call(request) + + response[0].should.equal(200) + response[1].should.equal({ + "Content-Encoding" => "gzip", + "Vary" => "Accept-Encoding", + "Last-Modified" => last_modified + }) + + buf = '' + response[2].each { |part| buf << part } + io = StringIO.new(buf) + gz = Zlib::GzipReader.new(io) + gz.read.should.equal("Hello World!") + gz.close + end + + specify "should do nothing when no-transform Cache-Control directive present" do + app = lambda { |env| [200, {'Cache-Control' => 'no-transform'}, ['Hello World!']] } + request = Rack::MockRequest.env_for("", "HTTP_ACCEPT_ENCODING" => "gzip") + response = Rack::Deflater.new(app).call(request) + + response[0].should.equal(200) + response[1].should.not.include "Content-Encoding" + response[2].join.should.equal("Hello World!") + end +end diff --git a/vendor/plugins/rack/test/spec_rack_directory.rb b/vendor/plugins/rack/test/spec_rack_directory.rb new file mode 100644 index 00000000..540c728d --- /dev/null +++ b/vendor/plugins/rack/test/spec_rack_directory.rb @@ -0,0 +1,61 @@ +require 'test/spec' + +require 'rack/directory' +require 'rack/lint' + +require 'rack/mock' + +context "Rack::Directory" do + DOCROOT = File.expand_path(File.dirname(__FILE__)) + FILE_CATCH = proc{|env| [200, {'Content-Type'=>'text/plain', "Content-Length" => "7"}, ['passed!']] } + app = Rack::Directory.new DOCROOT, FILE_CATCH + + specify "serves directory indices" do + res = Rack::MockRequest.new(Rack::Lint.new(app)). + get("/cgi/") + + res.should.be.ok + res.should =~ // + end + + specify "passes to app if file found" do + res = Rack::MockRequest.new(Rack::Lint.new(app)). + get("/cgi/test") + + res.should.be.ok + res.should =~ /passed!/ + end + + specify "serves uri with URL encoded filenames" do + res = Rack::MockRequest.new(Rack::Lint.new(app)). + get("/%63%67%69/") # "/cgi/test" + + res.should.be.ok + res.should =~ // + + res = Rack::MockRequest.new(Rack::Lint.new(app)). + get("/cgi/%74%65%73%74") # "/cgi/test" + + res.should.be.ok + res.should =~ /passed!/ + end + + specify "does not allow directory traversal" do + res = Rack::MockRequest.new(Rack::Lint.new(app)). + get("/cgi/../test") + + res.should.be.forbidden + + res = Rack::MockRequest.new(Rack::Lint.new(app)). + get("/cgi/%2E%2E/test") + + res.should.be.forbidden + end + + specify "404s if it can't find the file" do + res = Rack::MockRequest.new(Rack::Lint.new(app)). + get("/cgi/blubb") + + res.should.be.not_found + end +end diff --git a/vendor/plugins/rack/test/spec_rack_fastcgi.rb b/vendor/plugins/rack/test/spec_rack_fastcgi.rb new file mode 100644 index 00000000..69478de5 --- /dev/null +++ b/vendor/plugins/rack/test/spec_rack_fastcgi.rb @@ -0,0 +1,89 @@ +require 'test/spec' +require 'testrequest' + +context "Rack::Handler::FastCGI" do + include TestRequest::Helpers + + setup do + @host = '0.0.0.0' + @port = 9203 + end + + # Keep this first. + specify "startup" do + $pid = fork { + Dir.chdir(File.join(File.dirname(__FILE__), "..", "test", "cgi")) + exec "lighttpd -D -f lighttpd.conf" + } + end + + specify "should respond" do + sleep 1 + lambda { + GET("/test.fcgi") + }.should.not.raise + end + + specify "should be a lighttpd" do + GET("/test.fcgi") + status.should.be 200 + response["SERVER_SOFTWARE"].should =~ /lighttpd/ + response["HTTP_VERSION"].should.equal "HTTP/1.1" + response["SERVER_PROTOCOL"].should.equal "HTTP/1.1" + response["SERVER_PORT"].should.equal @port.to_s + response["SERVER_NAME"].should =~ @host + end + + specify "should have rack headers" do + GET("/test.fcgi") + response["rack.version"].should.equal [1,0] + response["rack.multithread"].should.be false + response["rack.multiprocess"].should.be true + response["rack.run_once"].should.be false + end + + specify "should have CGI headers on GET" do + GET("/test.fcgi") + 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["QUERY_STRING"].should.equal "" + response["test.postdata"].should.equal "" + + GET("/test.fcgi/foo?quux=1") + response["REQUEST_METHOD"].should.equal "GET" + response["SCRIPT_NAME"].should.equal "/test.fcgi" + response["REQUEST_PATH"].should.equal "/" + response["PATH_INFO"].should.equal "/foo" + response["QUERY_STRING"].should.equal "quux=1" + end + + specify "should have CGI headers on POST" do + POST("/test.fcgi", {"rack-form-data" => "23"}, {'X-test-header' => '42'}) + status.should.equal 200 + response["REQUEST_METHOD"].should.equal "POST" + response["SCRIPT_NAME"].should.equal "/test.fcgi" + response["REQUEST_PATH"].should.equal "/" + response["QUERY_STRING"].should.equal "" + response["HTTP_X_TEST_HEADER"].should.equal "42" + response["test.postdata"].should.equal "rack-form-data=23" + end + + specify "should support HTTP auth" do + GET("/test.fcgi", {:user => "ruth", :passwd => "secret"}) + response["HTTP_AUTHORIZATION"].should.equal "Basic cnV0aDpzZWNyZXQ=" + end + + specify "should set status" do + GET("/test.fcgi?secret") + status.should.equal 403 + response["rack.url_scheme"].should.equal "http" + end + + # Keep this last. + specify "shutdown" do + Process.kill 15, $pid + Process.wait($pid).should.equal $pid + end +end diff --git a/vendor/plugins/rack/test/spec_rack_file.rb b/vendor/plugins/rack/test/spec_rack_file.rb new file mode 100644 index 00000000..1e6771ab --- /dev/null +++ b/vendor/plugins/rack/test/spec_rack_file.rb @@ -0,0 +1,75 @@ +require 'test/spec' + +require 'rack/file' +require 'rack/lint' + +require 'rack/mock' + +context "Rack::File" do + DOCROOT = File.expand_path(File.dirname(__FILE__)) + + specify "serves files" do + res = Rack::MockRequest.new(Rack::Lint.new(Rack::File.new(DOCROOT))). + get("/cgi/test") + + res.should.be.ok + res.should =~ /ruby/ + end + + specify "sets Last-Modified header" do + res = Rack::MockRequest.new(Rack::Lint.new(Rack::File.new(DOCROOT))). + get("/cgi/test") + + path = File.join(DOCROOT, "/cgi/test") + + res.should.be.ok + res["Last-Modified"].should.equal File.mtime(path).httpdate + end + + specify "serves files with URL encoded filenames" do + res = Rack::MockRequest.new(Rack::Lint.new(Rack::File.new(DOCROOT))). + get("/cgi/%74%65%73%74") # "/cgi/test" + + res.should.be.ok + res.should =~ /ruby/ + end + + specify "does not allow directory traversal" do + res = Rack::MockRequest.new(Rack::Lint.new(Rack::File.new(DOCROOT))). + get("/cgi/../test") + + res.should.be.forbidden + end + + specify "does not allow directory traversal with encoded periods" do + res = Rack::MockRequest.new(Rack::Lint.new(Rack::File.new(DOCROOT))). + get("/%2E%2E/README") + + res.should.be.forbidden + end + + specify "404s if it can't find the file" do + res = Rack::MockRequest.new(Rack::Lint.new(Rack::File.new(DOCROOT))). + get("/cgi/blubb") + + res.should.be.not_found + end + + specify "detects SystemCallErrors" do + res = Rack::MockRequest.new(Rack::Lint.new(Rack::File.new(DOCROOT))). + get("/cgi") + + res.should.be.not_found + end + + specify "returns bodies that respond to #to_path" do + env = Rack::MockRequest.env_for("/cgi/test") + status, headers, body = Rack::File.new(DOCROOT).call(env) + + path = File.join(DOCROOT, "/cgi/test") + + status.should.equal 200 + body.should.respond_to :to_path + body.to_path.should.equal path + end +end diff --git a/vendor/plugins/rack/test/spec_rack_handler.rb b/vendor/plugins/rack/test/spec_rack_handler.rb new file mode 100644 index 00000000..fcf19b78 --- /dev/null +++ b/vendor/plugins/rack/test/spec_rack_handler.rb @@ -0,0 +1,43 @@ +require 'test/spec' + +require 'rack/handler' + +class Rack::Handler::Lobster; end +class RockLobster; end + +context "Rack::Handler" do + specify "has registered default handlers" do + Rack::Handler.get('cgi').should.equal Rack::Handler::CGI + Rack::Handler.get('fastcgi').should.equal Rack::Handler::FastCGI + Rack::Handler.get('mongrel').should.equal Rack::Handler::Mongrel + Rack::Handler.get('webrick').should.equal Rack::Handler::WEBrick + end + + specify "handler that doesn't exist should raise a NameError" do + lambda { + Rack::Handler.get('boom') + }.should.raise(NameError) + end + + specify "should get unregistered, but already required, handler by name" do + Rack::Handler.get('Lobster').should.equal Rack::Handler::Lobster + end + + specify "should register custom handler" do + Rack::Handler.register('rock_lobster', 'RockLobster') + Rack::Handler.get('rock_lobster').should.equal RockLobster + end + + specify "should not need registration for properly coded handlers even if not already required" do + begin + $:.push "test/unregistered_handler" + Rack::Handler.get('Unregistered').should.equal Rack::Handler::Unregistered + lambda { + Rack::Handler.get('UnRegistered') + }.should.raise(NameError) + Rack::Handler.get('UnregisteredLongOne').should.equal Rack::Handler::UnregisteredLongOne + ensure + $:.delete "test/unregistered_handler" + end + end +end diff --git a/vendor/plugins/rack/test/spec_rack_head.rb b/vendor/plugins/rack/test/spec_rack_head.rb new file mode 100644 index 00000000..48d3f81f --- /dev/null +++ b/vendor/plugins/rack/test/spec_rack_head.rb @@ -0,0 +1,30 @@ +require 'rack/head' +require 'rack/mock' + +context "Rack::Head" do + def test_response(headers = {}) + app = lambda { |env| [200, {"Content-type" => "test/plain", "Content-length" => "3"}, ["foo"]] } + request = Rack::MockRequest.env_for("/", headers) + response = Rack::Head.new(app).call(request) + + return response + end + + specify "passes GET, POST, PUT, DELETE, OPTIONS, TRACE requests" do + %w[GET POST PUT DELETE OPTIONS TRACE].each do |type| + resp = test_response("REQUEST_METHOD" => type) + + resp[0].should.equal(200) + resp[1].should.equal({"Content-type" => "test/plain", "Content-length" => "3"}) + resp[2].should.equal(["foo"]) + end + end + + specify "removes body from HEAD requests" do + resp = test_response("REQUEST_METHOD" => "HEAD") + + resp[0].should.equal(200) + resp[1].should.equal({"Content-type" => "test/plain", "Content-length" => "3"}) + resp[2].should.equal([]) + end +end diff --git a/vendor/plugins/rack/test/spec_rack_lint.rb b/vendor/plugins/rack/test/spec_rack_lint.rb new file mode 100644 index 00000000..880a07ee --- /dev/null +++ b/vendor/plugins/rack/test/spec_rack_lint.rb @@ -0,0 +1,521 @@ +require 'test/spec' +require 'stringio' + +require 'rack/lint' +require 'rack/mock' + +context "Rack::Lint" do + def env(*args) + Rack::MockRequest.env_for("/", *args) + end + + specify "passes valid request" do + lambda { + Rack::Lint.new(lambda { |env| + [200, {"Content-type" => "test/plain", "Content-length" => "3"}, ["foo"]] + }).call(env({})) + }.should.not.raise + end + + specify "notices fatal errors" do + lambda { Rack::Lint.new(nil).call }.should.raise(Rack::Lint::LintError). + message.should.match(/No env given/) + end + + specify "notices environment errors" do + lambda { Rack::Lint.new(nil).call 5 }.should.raise(Rack::Lint::LintError). + message.should.match(/not a Hash/) + + lambda { + e = env + e.delete("REQUEST_METHOD") + Rack::Lint.new(nil).call(e) + }.should.raise(Rack::Lint::LintError). + message.should.match(/missing required key REQUEST_METHOD/) + + lambda { + e = env + e.delete("SERVER_NAME") + Rack::Lint.new(nil).call(e) + }.should.raise(Rack::Lint::LintError). + message.should.match(/missing required key SERVER_NAME/) + + + lambda { + Rack::Lint.new(nil).call(env("HTTP_CONTENT_TYPE" => "text/plain")) + }.should.raise(Rack::Lint::LintError). + message.should.match(/contains HTTP_CONTENT_TYPE/) + + lambda { + Rack::Lint.new(nil).call(env("HTTP_CONTENT_LENGTH" => "42")) + }.should.raise(Rack::Lint::LintError). + message.should.match(/contains HTTP_CONTENT_LENGTH/) + + lambda { + Rack::Lint.new(nil).call(env("FOO" => Object.new)) + }.should.raise(Rack::Lint::LintError). + message.should.match(/non-string value/) + + lambda { + Rack::Lint.new(nil).call(env("rack.version" => "0.2")) + }.should.raise(Rack::Lint::LintError). + message.should.match(/must be an Array/) + + lambda { + Rack::Lint.new(nil).call(env("rack.url_scheme" => "gopher")) + }.should.raise(Rack::Lint::LintError). + message.should.match(/url_scheme unknown/) + + lambda { + Rack::Lint.new(nil).call(env("rack.session" => [])) + }.should.raise(Rack::Lint::LintError). + message.should.equal("session [] must respond to store and []=") + + lambda { + Rack::Lint.new(nil).call(env("REQUEST_METHOD" => "FUCKUP?")) + }.should.raise(Rack::Lint::LintError). + message.should.match(/REQUEST_METHOD/) + + lambda { + Rack::Lint.new(nil).call(env("SCRIPT_NAME" => "howdy")) + }.should.raise(Rack::Lint::LintError). + message.should.match(/must start with/) + + lambda { + Rack::Lint.new(nil).call(env("PATH_INFO" => "../foo")) + }.should.raise(Rack::Lint::LintError). + message.should.match(/must start with/) + + lambda { + Rack::Lint.new(nil).call(env("CONTENT_LENGTH" => "xcii")) + }.should.raise(Rack::Lint::LintError). + message.should.match(/Invalid CONTENT_LENGTH/) + + lambda { + e = env + e.delete("PATH_INFO") + e.delete("SCRIPT_NAME") + Rack::Lint.new(nil).call(e) + }.should.raise(Rack::Lint::LintError). + message.should.match(/One of .* must be set/) + + lambda { + Rack::Lint.new(nil).call(env("SCRIPT_NAME" => "/")) + }.should.raise(Rack::Lint::LintError). + message.should.match(/cannot be .* make it ''/) + end + + specify "notices input errors" do + lambda { + 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? + false + end + 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 + result = Object.new + def result.name + "US-ASCII" + end + result + end + Rack::Lint.new(nil).call(env("rack.input" => input)) + }.should.raise(Rack::Lint::LintError). + message.should.match(/does not have ASCII-8BIT as its external encoding/) + end + + specify "notices error errors" do + lambda { + Rack::Lint.new(nil).call(env("rack.errors" => "")) + }.should.raise(Rack::Lint::LintError). + message.should.match(/does not respond to #puts/) + end + + specify "notices status errors" do + lambda { + Rack::Lint.new(lambda { |env| + ["cc", {}, ""] + }).call(env({})) + }.should.raise(Rack::Lint::LintError). + message.should.match(/must be >=100 seen as integer/) + + lambda { + Rack::Lint.new(lambda { |env| + [42, {}, ""] + }).call(env({})) + }.should.raise(Rack::Lint::LintError). + message.should.match(/must be >=100 seen as integer/) + end + + specify "notices header errors" do + lambda { + Rack::Lint.new(lambda { |env| + [200, Object.new, []] + }).call(env({})) + }.should.raise(Rack::Lint::LintError). + message.should.equal("headers object should respond to #each, but doesn't (got Object as headers)") + + lambda { + Rack::Lint.new(lambda { |env| + [200, {true=>false}, []] + }).call(env({})) + }.should.raise(Rack::Lint::LintError). + message.should.equal("header key must be a string, was TrueClass") + + lambda { + Rack::Lint.new(lambda { |env| + [200, {"Status" => "404"}, []] + }).call(env({})) + }.should.raise(Rack::Lint::LintError). + message.should.match(/must not contain Status/) + + lambda { + Rack::Lint.new(lambda { |env| + [200, {"Content-Type:" => "text/plain"}, []] + }).call(env({})) + }.should.raise(Rack::Lint::LintError). + message.should.match(/must not contain :/) + + lambda { + Rack::Lint.new(lambda { |env| + [200, {"Content-" => "text/plain"}, []] + }).call(env({})) + }.should.raise(Rack::Lint::LintError). + message.should.match(/must not end/) + + lambda { + Rack::Lint.new(lambda { |env| + [200, {"..%%quark%%.." => "text/plain"}, []] + }).call(env({})) + }.should.raise(Rack::Lint::LintError). + message.should.equal("invalid header name: ..%%quark%%..") + + lambda { + Rack::Lint.new(lambda { |env| + [200, {"Foo" => Object.new}, []] + }).call(env({})) + }.should.raise(Rack::Lint::LintError). + message.should.equal("a header value must be a String, but the value of 'Foo' is a Object") + + lambda { + Rack::Lint.new(lambda { |env| + [200, {"Foo" => [1, 2, 3]}, []] + }).call(env({})) + }.should.raise(Rack::Lint::LintError). + message.should.equal("a header value must be a String, but the value of 'Foo' is a Array") + + + lambda { + Rack::Lint.new(lambda { |env| + [200, {"Foo-Bar" => "text\000plain"}, []] + }).call(env({})) + }.should.raise(Rack::Lint::LintError). + message.should.match(/invalid header/) + + # line ends (010) should be allowed in header values. + lambda { + Rack::Lint.new(lambda { |env| + [200, {"Foo-Bar" => "one\ntwo\nthree", "Content-Length" => "0", "Content-Type" => "text/plain" }, []] + }).call(env({})) + }.should.not.raise(Rack::Lint::LintError) + end + + specify "notices content-type errors" do + lambda { + Rack::Lint.new(lambda { |env| + [200, {"Content-length" => "0"}, []] + }).call(env({})) + }.should.raise(Rack::Lint::LintError). + message.should.match(/No Content-Type/) + + [100, 101, 204, 304].each do |status| + lambda { + Rack::Lint.new(lambda { |env| + [status, {"Content-type" => "text/plain", "Content-length" => "0"}, []] + }).call(env({})) + }.should.raise(Rack::Lint::LintError). + message.should.match(/Content-Type header found/) + end + end + + specify "notices content-length errors" do + [100, 101, 204, 304].each do |status| + lambda { + Rack::Lint.new(lambda { |env| + [status, {"Content-length" => "0"}, []] + }).call(env({})) + }.should.raise(Rack::Lint::LintError). + message.should.match(/Content-Length header found/) + end + + lambda { + Rack::Lint.new(lambda { |env| + [200, {"Content-type" => "text/plain", "Content-Length" => "1"}, []] + }).call(env({})) + }.should.raise(Rack::Lint::LintError). + message.should.match(/Content-Length header was 1, but should be 0/) + end + + specify "notices body errors" do + lambda { + status, header, body = Rack::Lint.new(lambda { |env| + [200, {"Content-type" => "text/plain","Content-length" => "3"}, [1,2,3]] + }).call(env({})) + body.each { |part| } + }.should.raise(Rack::Lint::LintError). + message.should.match(/yielded non-string/) + end + + specify "notices input handling errors" do + lambda { + Rack::Lint.new(lambda { |env| + env["rack.input"].gets("\r\n") + [201, {"Content-type" => "text/plain", "Content-length" => "0"}, []] + }).call(env({})) + }.should.raise(Rack::Lint::LintError). + message.should.match(/gets called with arguments/) + + lambda { + Rack::Lint.new(lambda { |env| + env["rack.input"].read(1, 2, 3) + [201, {"Content-type" => "text/plain", "Content-length" => "0"}, []] + }).call(env({})) + }.should.raise(Rack::Lint::LintError). + message.should.match(/read called with too many arguments/) + + lambda { + Rack::Lint.new(lambda { |env| + env["rack.input"].read("foo") + [201, {"Content-type" => "text/plain", "Content-length" => "0"}, []] + }).call(env({})) + }.should.raise(Rack::Lint::LintError). + message.should.match(/read called with non-integer and non-nil length/) + + lambda { + Rack::Lint.new(lambda { |env| + env["rack.input"].read(-1) + [201, {"Content-type" => "text/plain", "Content-length" => "0"}, []] + }).call(env({})) + }.should.raise(Rack::Lint::LintError). + message.should.match(/read called with a negative length/) + + lambda { + Rack::Lint.new(lambda { |env| + env["rack.input"].read(nil, nil) + [201, {"Content-type" => "text/plain", "Content-length" => "0"}, []] + }).call(env({})) + }.should.raise(Rack::Lint::LintError). + message.should.match(/read called with non-String buffer/) + + lambda { + Rack::Lint.new(lambda { |env| + env["rack.input"].read(nil, 1) + [201, {"Content-type" => "text/plain", "Content-length" => "0"}, []] + }).call(env({})) + }.should.raise(Rack::Lint::LintError). + message.should.match(/read called with non-String buffer/) + + lambda { + Rack::Lint.new(lambda { |env| + env["rack.input"].rewind(0) + [201, {"Content-type" => "text/plain", "Content-length" => "0"}, []] + }).call(env({})) + }.should.raise(Rack::Lint::LintError). + message.should.match(/rewind called with arguments/) + + weirdio = Object.new + class << weirdio + def gets + 42 + end + + def read + 23 + end + + def each + 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 + + lambda { + Rack::Lint.new(lambda { |env| + env["rack.input"].gets + [201, {"Content-type" => "text/plain", "Content-length" => "0"}, []] + }).call(env("rack.input" => weirdio)) + }.should.raise(Rack::Lint::LintError). + message.should.match(/gets didn't return a String/) + + lambda { + Rack::Lint.new(lambda { |env| + env["rack.input"].each { |x| } + [201, {"Content-type" => "text/plain", "Content-length" => "0"}, []] + }).call(env("rack.input" => weirdio)) + }.should.raise(Rack::Lint::LintError). + message.should.match(/each didn't yield a String/) + + lambda { + Rack::Lint.new(lambda { |env| + env["rack.input"].read + [201, {"Content-type" => "text/plain", "Content-length" => "0"}, []] + }).call(env("rack.input" => weirdio)) + }.should.raise(Rack::Lint::LintError). + message.should.match(/read didn't return nil or a String/) + + lambda { + Rack::Lint.new(lambda { |env| + env["rack.input"].read + [201, {"Content-type" => "text/plain", "Content-length" => "0"}, []] + }).call(env("rack.input" => eof_weirdio)) + }.should.raise(Rack::Lint::LintError). + message.should.match(/read\(nil\) returned nil on EOF/) + + lambda { + Rack::Lint.new(lambda { |env| + env["rack.input"].rewind + [201, {"Content-type" => "text/plain", "Content-length" => "0"}, []] + }).call(env("rack.input" => weirdio)) + }.should.raise(Rack::Lint::LintError). + message.should.match(/rewind raised Errno::ESPIPE/) + + + lambda { + Rack::Lint.new(lambda { |env| + env["rack.input"].close + [201, {"Content-type" => "text/plain", "Content-length" => "0"}, []] + }).call(env({})) + }.should.raise(Rack::Lint::LintError). + message.should.match(/close must not be called/) + end + + specify "notices error handling errors" do + lambda { + Rack::Lint.new(lambda { |env| + env["rack.errors"].write(42) + [201, {"Content-type" => "text/plain", "Content-length" => "0"}, []] + }).call(env({})) + }.should.raise(Rack::Lint::LintError). + message.should.match(/write not called with a String/) + + lambda { + Rack::Lint.new(lambda { |env| + env["rack.errors"].close + [201, {"Content-type" => "text/plain", "Content-length" => "0"}, []] + }).call(env({})) + }.should.raise(Rack::Lint::LintError). + message.should.match(/close must not be called/) + end + + specify "notices HEAD errors" do + lambda { + Rack::Lint.new(lambda { |env| + [200, {"Content-type" => "test/plain", "Content-length" => "3"}, []] + }).call(env({"REQUEST_METHOD" => "HEAD"})) + }.should.not.raise + + lambda { + Rack::Lint.new(lambda { |env| + [200, {"Content-type" => "test/plain", "Content-length" => "3"}, ["foo"]] + }).call(env({"REQUEST_METHOD" => "HEAD"})) + }.should.raise(Rack::Lint::LintError). + message.should.match(/body was given for HEAD/) + end + + specify "passes valid read calls" do + 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")})) + }.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")})) + }.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")})) + }.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")})) + }.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")})) + }.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")})) + }.should.not.raise(Rack::Lint::LintError) + end +end + +context "Rack::Lint::InputWrapper" do + specify "delegates :size to underlying IO object" do + class IOMock + def size + 101 + end + end + + wrapper = Rack::Lint::InputWrapper.new(IOMock.new) + wrapper.size.should == 101 + end + + specify "delegates :rewind to underlying IO object" do + io = StringIO.new("123") + wrapper = Rack::Lint::InputWrapper.new(io) + wrapper.read.should.equal "123" + wrapper.read.should.equal "" + wrapper.rewind + wrapper.read.should.equal "123" + end +end diff --git a/vendor/plugins/rack/test/spec_rack_lobster.rb b/vendor/plugins/rack/test/spec_rack_lobster.rb new file mode 100644 index 00000000..7be267a2 --- /dev/null +++ b/vendor/plugins/rack/test/spec_rack_lobster.rb @@ -0,0 +1,45 @@ +require 'test/spec' + +require 'rack/lobster' +require 'rack/mock' + +context "Rack::Lobster::LambdaLobster" do + specify "should be a single lambda" do + Rack::Lobster::LambdaLobster.should.be.kind_of Proc + end + + specify "should look like a lobster" do + res = Rack::MockRequest.new(Rack::Lobster::LambdaLobster).get("/") + res.should.be.ok + res.body.should.include "(,(,,(,,,(" + res.body.should.include "?flip" + end + + specify "should be flippable" do + res = Rack::MockRequest.new(Rack::Lobster::LambdaLobster).get("/?flip") + res.should.be.ok + res.body.should.include "(,,,(,,(,(" + end +end + +context "Rack::Lobster" do + specify "should look like a lobster" do + res = Rack::MockRequest.new(Rack::Lobster.new).get("/") + res.should.be.ok + res.body.should.include "(,(,,(,,,(" + res.body.should.include "?flip" + res.body.should.include "crash" + end + + specify "should be flippable" do + res = Rack::MockRequest.new(Rack::Lobster.new).get("/?flip=left") + res.should.be.ok + res.body.should.include "(,,,(,,(,(" + end + + specify "should provide crashing for testing purposes" do + lambda { + Rack::MockRequest.new(Rack::Lobster.new).get("/?flip=crash") + }.should.raise + end +end diff --git a/vendor/plugins/rack/test/spec_rack_lock.rb b/vendor/plugins/rack/test/spec_rack_lock.rb new file mode 100644 index 00000000..18af2b23 --- /dev/null +++ b/vendor/plugins/rack/test/spec_rack_lock.rb @@ -0,0 +1,38 @@ +require 'test/spec' + +require 'rack/mock' +require 'rack/lock' + +context "Rack::Lock" do + class Lock + attr_reader :synchronized + + def initialize + @synchronized = false + end + + def synchronize + @synchronized = true + yield + end + end + + specify "should call synchronize on lock" do + lock = Lock.new + env = Rack::MockRequest.env_for("/") + app = Rack::Lock.new(lambda { |env| }, lock) + lock.synchronized.should.equal false + app.call(env) + lock.synchronized.should.equal true + end + + specify "should set multithread flag to false" do + app = Rack::Lock.new(lambda { |env| env['rack.multithread'] }) + app.call(Rack::MockRequest.env_for("/")).should.equal false + end + + specify "should reset original multithread flag when exiting lock" do + app = Rack::Lock.new(lambda { |env| env }) + app.call(Rack::MockRequest.env_for("/"))['rack.multithread'].should.equal true + end +end diff --git a/vendor/plugins/rack/test/spec_rack_methodoverride.rb b/vendor/plugins/rack/test/spec_rack_methodoverride.rb new file mode 100644 index 00000000..57452394 --- /dev/null +++ b/vendor/plugins/rack/test/spec_rack_methodoverride.rb @@ -0,0 +1,60 @@ +require 'test/spec' + +require 'rack/mock' +require 'rack/methodoverride' +require 'stringio' + +context "Rack::MethodOverride" do + specify "should not affect GET requests" do + env = Rack::MockRequest.env_for("/?_method=delete", :method => "GET") + app = Rack::MethodOverride.new(lambda { |env| Rack::Request.new(env) }) + req = app.call(env) + + req.env["REQUEST_METHOD"].should.equal "GET" + end + + specify "_method parameter should modify REQUEST_METHOD for POST requests" do + env = Rack::MockRequest.env_for("/", :method => "POST", :input => "_method=put") + app = Rack::MethodOverride.new(lambda { |env| Rack::Request.new(env) }) + req = app.call(env) + + req.env["REQUEST_METHOD"].should.equal "PUT" + end + + specify "X-HTTP-Method-Override header should modify REQUEST_METHOD for POST requests" do + env = Rack::MockRequest.env_for("/", + :method => "POST", + "HTTP_X_HTTP_METHOD_OVERRIDE" => "PUT" + ) + app = Rack::MethodOverride.new(lambda { |env| Rack::Request.new(env) }) + req = app.call(env) + + req.env["REQUEST_METHOD"].should.equal "PUT" + end + + specify "should not modify REQUEST_METHOD if the method is unknown" do + env = Rack::MockRequest.env_for("/", :method => "POST", :input => "_method=foo") + app = Rack::MethodOverride.new(lambda { |env| Rack::Request.new(env) }) + req = app.call(env) + + req.env["REQUEST_METHOD"].should.equal "POST" + end + + specify "should not modify REQUEST_METHOD when _method is nil" do + env = Rack::MockRequest.env_for("/", :method => "POST", :input => "foo=bar") + app = Rack::MethodOverride.new(lambda { |env| Rack::Request.new(env) }) + req = app.call(env) + + req.env["REQUEST_METHOD"].should.equal "POST" + end + + specify "should store the original REQUEST_METHOD prior to overriding" do + env = Rack::MockRequest.env_for("/", + :method => "POST", + :input => "_method=options") + app = Rack::MethodOverride.new(lambda { |env| Rack::Request.new(env) }) + req = app.call(env) + + req.env["rack.methodoverride.original_method"].should.equal "POST" + end +end diff --git a/vendor/plugins/rack/test/spec_rack_mock.rb b/vendor/plugins/rack/test/spec_rack_mock.rb new file mode 100644 index 00000000..9c392a28 --- /dev/null +++ b/vendor/plugins/rack/test/spec_rack_mock.rb @@ -0,0 +1,157 @@ +require 'yaml' +require 'rack/mock' +require 'rack/request' +require 'rack/response' + +app = lambda { |env| + req = Rack::Request.new(env) + + env["mock.postdata"] = env["rack.input"].read + if req.GET["error"] + env["rack.errors"].puts req.GET["error"] + env["rack.errors"].flush + end + + Rack::Response.new(env.to_yaml, + req.GET["status"] || 200, + "Content-Type" => "text/yaml").finish +} + +context "Rack::MockRequest" do + specify "should return a MockResponse" do + res = Rack::MockRequest.new(app).get("") + res.should.be.kind_of Rack::MockResponse + end + + specify "should be able to only return the environment" do + env = Rack::MockRequest.env_for("") + env.should.be.kind_of Hash + env.should.include "rack.version" + end + + specify "should provide sensible defaults" do + res = Rack::MockRequest.new(app).request + + 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 "/" + env["SCRIPT_NAME"].should.equal "" + env["rack.url_scheme"].should.equal "http" + env["mock.postdata"].should.be.empty + end + + specify "should allow GET/POST/PUT/DELETE" do + res = Rack::MockRequest.new(app).get("", :input => "foo") + env = YAML.load(res.body) + env["REQUEST_METHOD"].should.equal "GET" + + res = Rack::MockRequest.new(app).post("", :input => "foo") + env = YAML.load(res.body) + env["REQUEST_METHOD"].should.equal "POST" + + res = Rack::MockRequest.new(app).put("", :input => "foo") + env = YAML.load(res.body) + env["REQUEST_METHOD"].should.equal "PUT" + + res = Rack::MockRequest.new(app).delete("", :input => "foo") + env = YAML.load(res.body) + env["REQUEST_METHOD"].should.equal "DELETE" + + Rack::MockRequest.env_for("/", :method => "OPTIONS")["REQUEST_METHOD"]. + should.equal "OPTIONS" + end + + specify "should set content length" do + env = Rack::MockRequest.env_for("/", :input => "foo") + env["CONTENT_LENGTH"].should.equal "3" + end + + specify "should allow posting" do + res = Rack::MockRequest.new(app).get("", :input => "foo") + env = YAML.load(res.body) + env["mock.postdata"].should.equal "foo" + + res = Rack::MockRequest.new(app).post("", :input => StringIO.new("foo")) + env = YAML.load(res.body) + env["mock.postdata"].should.equal "foo" + end + + specify "should use all parts of an URL" do + res = Rack::MockRequest.new(app). + get("https://bla.example.org:9292/meh/foo?bar") + res.should.be.kind_of Rack::MockResponse + + env = YAML.load(res.body) + env["REQUEST_METHOD"].should.equal "GET" + env["SERVER_NAME"].should.equal "bla.example.org" + env["SERVER_PORT"].should.equal "9292" + env["QUERY_STRING"].should.equal "bar" + env["PATH_INFO"].should.equal "/meh/foo" + env["rack.url_scheme"].should.equal "https" + end + + specify "should behave valid according to the Rack spec" do + lambda { + res = Rack::MockRequest.new(app). + get("https://bla.example.org:9292/meh/foo?bar", :lint => true) + }.should.not.raise(Rack::Lint::LintError) + end +end + +context "Rack::MockResponse" do + specify "should provide access to the HTTP status" do + res = Rack::MockRequest.new(app).get("") + res.should.be.successful + res.should.be.ok + + res = Rack::MockRequest.new(app).get("/?status=404") + res.should.not.be.successful + res.should.be.client_error + res.should.be.not_found + + res = Rack::MockRequest.new(app).get("/?status=501") + res.should.not.be.successful + res.should.be.server_error + + res = Rack::MockRequest.new(app).get("/?status=307") + res.should.be.redirect + + res = Rack::MockRequest.new(app).get("/?status=201", :lint => true) + res.should.be.empty + end + + specify "should provide access to the HTTP headers" do + res = Rack::MockRequest.new(app).get("") + res.should.include "Content-Type" + res.headers["Content-Type"].should.equal "text/yaml" + 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.location.should.be.nil + end + + specify "should provide access to the HTTP body" do + res = Rack::MockRequest.new(app).get("") + res.body.should =~ /rack/ + res.should =~ /rack/ + res.should.match(/rack/) + res.should.satisfy { |r| r.match(/rack/) } + end + + specify "should provide access to the Rack errors" do + res = Rack::MockRequest.new(app).get("/?error=foo", :lint => true) + res.should.be.ok + res.errors.should.not.be.empty + res.errors.should.include "foo" + end + + specify "should optionally make Rack errors fatal" do + lambda { + Rack::MockRequest.new(app).get("/?error=foo", :fatal => true) + }.should.raise(Rack::MockRequest::FatalWarning) + end +end diff --git a/vendor/plugins/rack/test/spec_rack_mongrel.rb b/vendor/plugins/rack/test/spec_rack_mongrel.rb new file mode 100644 index 00000000..d73e884c --- /dev/null +++ b/vendor/plugins/rack/test/spec_rack_mongrel.rb @@ -0,0 +1,189 @@ +require 'test/spec' + +begin +require 'rack/handler/mongrel' +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', + Rack::Handler::Mongrel.new(Rack::Lint.new(TestRequest.new))) + server.register('/stream', + Rack::Handler::Mongrel.new(Rack::Lint.new(StreamingRequest))) + @acc = server.run + end + + specify "should respond" do + lambda { + GET("/test") + }.should.not.raise + end + + specify "should be a Mongrel" do + GET("/test") + status.should.be 200 + response["SERVER_SOFTWARE"].should =~ /Mongrel/ + response["HTTP_VERSION"].should.equal "HTTP/1.1" + response["SERVER_PROTOCOL"].should.equal "HTTP/1.1" + response["SERVER_PORT"].should.equal "9201" + response["SERVER_NAME"].should.equal "0.0.0.0" + end + + specify "should have rack headers" do + GET("/test") + response["rack.version"].should.equal [1,0] + response["rack.multithread"].should.be true + response["rack.multiprocess"].should.be false + response["rack.run_once"].should.be false + end + + specify "should have CGI headers on GET" do + GET("/test") + 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["QUERY_STRING"].should.equal "" + response["test.postdata"].should.equal "" + + GET("/test/foo?quux=1") + response["REQUEST_METHOD"].should.equal "GET" + response["SCRIPT_NAME"].should.equal "/test" + response["REQUEST_PATH"].should.equal "/test/foo" + response["PATH_INFO"].should.equal "/foo" + response["QUERY_STRING"].should.equal "quux=1" + end + + specify "should have CGI headers on POST" do + POST("/test", {"rack-form-data" => "23"}, {'X-test-header' => '42'}) + status.should.equal 200 + response["REQUEST_METHOD"].should.equal "POST" + response["SCRIPT_NAME"].should.equal "/test" + response["REQUEST_PATH"].should.equal "/test" + response["QUERY_STRING"].should.equal "" + response["HTTP_X_TEST_HEADER"].should.equal "42" + response["test.postdata"].should.equal "rack-form-data=23" + end + + specify "should support HTTP auth" do + GET("/test", {:user => "ruth", :passwd => "secret"}) + response["HTTP_AUTHORIZATION"].should.equal "Basic cnV0aDpzZWNyZXQ=" + end + + specify "should set status" do + GET("/test?secret") + status.should.equal 403 + response["rack.url_scheme"].should.equal "http" + end + + specify "should provide a .run" do + block_ran = false + Thread.new { + Rack::Handler::Mongrel.run(lambda {}, {:Port => 9211}) { |server| + server.should.be.kind_of Mongrel::HttpServer + block_ran = true + } + } + sleep 1 + block_ran.should.be true + end + + specify "should provide a .run that maps a hash" do + block_ran = false + Thread.new { + map = {'/'=>lambda{},'/foo'=>lambda{}} + Rack::Handler::Mongrel.run(map, :map => true, :Port => 9221) { |server| + server.should.be.kind_of Mongrel::HttpServer + server.classifier.uris.size.should.be 2 + server.classifier.uris.should.not.include '/arf' + server.classifier.uris.should.include '/' + server.classifier.uris.should.include '/foo' + block_ran = true + } + } + sleep 1 + block_ran.should.be true + end + + specify "should provide a .run that maps a urlmap" do + block_ran = false + Thread.new { + map = Rack::URLMap.new({'/'=>lambda{},'/bar'=>lambda{}}) + Rack::Handler::Mongrel.run(map, {:map => true, :Port => 9231}) { |server| + server.should.be.kind_of Mongrel::HttpServer + server.classifier.uris.size.should.be 2 + server.classifier.uris.should.not.include '/arf' + server.classifier.uris.should.include '/' + server.classifier.uris.should.include '/bar' + block_ran = true + } + } + sleep 1 + block_ran.should.be true + end + + specify "should provide a .run that maps a urlmap restricting by host" do + block_ran = false + Thread.new { + map = Rack::URLMap.new({ + '/' => lambda{}, + '/foo' => lambda{}, + '/bar' => lambda{}, + 'http://localhost/' => lambda{}, + 'http://localhost/bar' => lambda{}, + 'http://falsehost/arf' => lambda{}, + 'http://falsehost/qux' => lambda{} + }) + opt = {:map => true, :Port => 9241, :Host => 'localhost'} + Rack::Handler::Mongrel.run(map, opt) { |server| + server.should.be.kind_of Mongrel::HttpServer + server.classifier.uris.should.include '/' + server.classifier.handler_map['/'].size.should.be 2 + server.classifier.uris.should.include '/foo' + server.classifier.handler_map['/foo'].size.should.be 1 + server.classifier.uris.should.include '/bar' + server.classifier.handler_map['/bar'].size.should.be 2 + server.classifier.uris.should.not.include '/qux' + server.classifier.uris.should.not.include '/arf' + server.classifier.uris.size.should.be 3 + block_ran = true + } + } + sleep 1 + block_ran.should.be true + end + + specify "should stream #each part of the response" do + body = '' + begin + Timeout.timeout(1) do + Net::HTTP.start(@host, @port) do |http| + get = Net::HTTP::Get.new('/stream') + http.request(get) do |response| + response.read_body { |part| body << part } + end + end + end + rescue Timeout::Error + end + body.should.not.be.empty + end + + teardown do + @acc.raise Mongrel::StopServer + end +end + +rescue LoadError + $stderr.puts "Skipping Rack::Handler::Mongrel tests (Mongrel is required). `gem install mongrel` and try again." +end diff --git a/vendor/plugins/rack/test/spec_rack_recursive.rb b/vendor/plugins/rack/test/spec_rack_recursive.rb new file mode 100644 index 00000000..afc1a0d9 --- /dev/null +++ b/vendor/plugins/rack/test/spec_rack_recursive.rb @@ -0,0 +1,77 @@ +require 'test/spec' + +require 'rack/recursive' +require 'rack/urlmap' +require 'rack/response' +require 'rack/mock' + +context "Rack::Recursive" do + setup do + + @app1 = lambda { |env| + res = Rack::Response.new + res["X-Path-Info"] = env["PATH_INFO"] + res["X-Query-String"] = env["QUERY_STRING"] + res.finish do |res| + res.write "App1" + end + } + + @app2 = lambda { |env| + Rack::Response.new.finish do |res| + res.write "App2" + _, _, body = env['rack.recursive.include'].call(env, "/app1") + body.each { |b| + res.write b + } + end + } + + @app3 = lambda { |env| + raise Rack::ForwardRequest.new("/app1") + } + + @app4 = lambda { |env| + raise Rack::ForwardRequest.new("http://example.org/app1/quux?meh") + } + + end + + specify "should allow for subrequests" do + res = Rack::MockRequest.new(Rack::Recursive.new( + Rack::URLMap.new("/app1" => @app1, + "/app2" => @app2))). + get("/app2") + + res.should.be.ok + res.body.should.equal "App2App1" + end + + specify "should raise error on requests not below the app" do + app = Rack::URLMap.new("/app1" => @app1, + "/app" => Rack::Recursive.new( + Rack::URLMap.new("/1" => @app1, + "/2" => @app2))) + + lambda { + Rack::MockRequest.new(app).get("/app/2") + }.should.raise(ArgumentError). + message.should =~ /can only include below/ + end + + specify "should support forwarding" do + app = Rack::Recursive.new(Rack::URLMap.new("/app1" => @app1, + "/app3" => @app3, + "/app4" => @app4)) + + res = Rack::MockRequest.new(app).get("/app3") + res.should.be.ok + res.body.should.equal "App1" + + res = Rack::MockRequest.new(app).get("/app4") + res.should.be.ok + res.body.should.equal "App1" + res["X-Path-Info"].should.equal "/quux" + res["X-Query-String"].should.equal "meh" + end +end diff --git a/vendor/plugins/rack/test/spec_rack_request.rb b/vendor/plugins/rack/test/spec_rack_request.rb new file mode 100644 index 00000000..74e2f00a --- /dev/null +++ b/vendor/plugins/rack/test/spec_rack_request.rb @@ -0,0 +1,504 @@ +require 'test/spec' +require 'stringio' + +require 'rack/request' +require 'rack/mock' + +context "Rack::Request" do + specify "wraps the rack variables" do + req = Rack::Request.new(Rack::MockRequest.env_for("http://example.com:8080/")) + + req.body.should.respond_to? :gets + req.scheme.should.equal "http" + req.request_method.should.equal "GET" + + req.should.be.get + req.should.not.be.post + req.should.not.be.put + req.should.not.be.delete + req.should.not.be.head + + req.script_name.should.equal "" + req.path_info.should.equal "/" + req.query_string.should.equal "" + + req.host.should.equal "example.com" + req.port.should.equal 8080 + + req.content_length.should.equal "0" + req.content_type.should.be.nil + end + + specify "can figure out the correct host" do + req = Rack::Request.new \ + Rack::MockRequest.env_for("/", "HTTP_HOST" => "www2.example.org") + req.host.should.equal "www2.example.org" + + req = Rack::Request.new \ + Rack::MockRequest.env_for("/", "SERVER_NAME" => "example.org:9292") + req.host.should.equal "example.org" + + env = Rack::MockRequest.env_for("/") + env.delete("SERVER_NAME") + req = Rack::Request.new(env) + req.host.should.equal "" + end + + specify "can parse the query string" do + req = Rack::Request.new(Rack::MockRequest.env_for("/?foo=bar&quux=bla")) + req.query_string.should.equal "foo=bar&quux=bla" + req.GET.should.equal "foo" => "bar", "quux" => "bla" + req.POST.should.be.empty + req.params.should.equal "foo" => "bar", "quux" => "bla" + end + + specify "can parse POST data" do + req = Rack::Request.new \ + Rack::MockRequest.env_for("/?foo=quux", :input => "foo=bar&quux=bla") + req.content_type.should.be.nil + req.media_type.should.be.nil + req.query_string.should.equal "foo=quux" + req.GET.should.equal "foo" => "quux" + req.POST.should.equal "foo" => "bar", "quux" => "bla" + req.params.should.equal "foo" => "bar", "quux" => "bla" + end + + specify "can parse POST data with explicit content type" do + req = Rack::Request.new \ + Rack::MockRequest.env_for("/", + "CONTENT_TYPE" => 'application/x-www-form-urlencoded;foo=bar', + :input => "foo=bar&quux=bla") + req.content_type.should.equal 'application/x-www-form-urlencoded;foo=bar' + req.media_type.should.equal 'application/x-www-form-urlencoded' + req.media_type_params['foo'].should.equal 'bar' + req.POST.should.equal "foo" => "bar", "quux" => "bla" + req.params.should.equal "foo" => "bar", "quux" => "bla" + end + + specify "does not parse POST data when media type is not form-data" do + req = Rack::Request.new \ + Rack::MockRequest.env_for("/?foo=quux", + "CONTENT_TYPE" => 'text/plain;charset=utf-8', + :input => "foo=bar&quux=bla") + req.content_type.should.equal 'text/plain;charset=utf-8' + req.media_type.should.equal 'text/plain' + req.media_type_params['charset'].should.equal 'utf-8' + req.POST.should.be.empty + req.params.should.equal "foo" => "quux" + 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 \ + Rack::MockRequest.env_for("/", + "CONTENT_TYPE" => 'application/x-www-form-urlencoded;foo=bar', + :input => input) + req.params.should.equal "foo" => "bar", "quux" => "bla" + input.read.should.equal "foo=bar&quux=bla" + end + + specify "cleans up Safari's ajax POST body" do + req = Rack::Request.new \ + Rack::MockRequest.env_for("/", :input => "foo=bar&quux=bla\0") + req.POST.should.equal "foo" => "bar", "quux" => "bla" + end + + specify "can get value by key from params with #[]" do + req = Rack::Request.new \ + Rack::MockRequest.env_for("?foo=quux") + req['foo'].should.equal 'quux' + req[:foo].should.equal 'quux' + end + + specify "can set value to key on params with #[]=" do + req = Rack::Request.new \ + Rack::MockRequest.env_for("?foo=duh") + req['foo'].should.equal 'duh' + req[:foo].should.equal 'duh' + req.params.should.equal 'foo' => 'duh' + + req['foo'] = 'bar' + req.params.should.equal 'foo' => 'bar' + req['foo'].should.equal 'bar' + req[:foo].should.equal 'bar' + + req[:foo] = 'jaz' + req.params.should.equal 'foo' => 'jaz' + req['foo'].should.equal 'jaz' + req[:foo].should.equal 'jaz' + end + + specify "values_at answers values by keys in order given" do + req = Rack::Request.new \ + Rack::MockRequest.env_for("?foo=baz&wun=der&bar=ful") + req.values_at('foo').should.equal ['baz'] + req.values_at('foo', 'wun').should.equal ['baz', 'der'] + req.values_at('bar', 'foo', 'wun').should.equal ['ful', 'baz', 'der'] + end + + specify "referrer should be extracted correct" do + req = Rack::Request.new \ + Rack::MockRequest.env_for("/", "HTTP_REFERER" => "/some/path") + req.referer.should.equal "/some/path" + + req = Rack::Request.new \ + Rack::MockRequest.env_for("/") + req.referer.should.equal "/" + end + + specify "can cache, but invalidates the cache" do + req = Rack::Request.new \ + Rack::MockRequest.env_for("/?foo=quux", :input => "foo=bar&quux=bla") + req.GET.should.equal "foo" => "quux" + req.GET.should.equal "foo" => "quux" + req.env["QUERY_STRING"] = "bla=foo" + req.GET.should.equal "bla" => "foo" + req.GET.should.equal "bla" => "foo" + + req.POST.should.equal "foo" => "bar", "quux" => "bla" + req.POST.should.equal "foo" => "bar", "quux" => "bla" + req.env["rack.input"] = StringIO.new("foo=bla&quux=bar") + req.POST.should.equal "foo" => "bla", "quux" => "bar" + req.POST.should.equal "foo" => "bla", "quux" => "bar" + end + + specify "can figure out if called via XHR" do + req = Rack::Request.new(Rack::MockRequest.env_for("")) + req.should.not.be.xhr + + req = Rack::Request.new \ + Rack::MockRequest.env_for("", "HTTP_X_REQUESTED_WITH" => "XMLHttpRequest") + req.should.be.xhr + end + + specify "can parse cookies" do + req = Rack::Request.new \ + Rack::MockRequest.env_for("", "HTTP_COOKIE" => "foo=bar;quux=h&m") + req.cookies.should.equal "foo" => "bar", "quux" => "h&m" + req.cookies.should.equal "foo" => "bar", "quux" => "h&m" + req.env.delete("HTTP_COOKIE") + req.cookies.should.equal({}) + end + + specify "parses cookies according to RFC 2109" do + req = Rack::Request.new \ + Rack::MockRequest.env_for('', 'HTTP_COOKIE' => 'foo=bar;foo=car') + req.cookies.should.equal 'foo' => 'bar' + end + + specify "provides setters" do + req = Rack::Request.new(e=Rack::MockRequest.env_for("")) + req.script_name.should.equal "" + req.script_name = "/foo" + req.script_name.should.equal "/foo" + e["SCRIPT_NAME"].should.equal "/foo" + + req.path_info.should.equal "/" + req.path_info = "/foo" + req.path_info.should.equal "/foo" + e["PATH_INFO"].should.equal "/foo" + end + + specify "provides the original env" do + req = Rack::Request.new(e=Rack::MockRequest.env_for("")) + req.env.should.be e + end + + specify "can restore the URL" do + Rack::Request.new(Rack::MockRequest.env_for("")).url. + should.equal "http://example.org/" + Rack::Request.new(Rack::MockRequest.env_for("", "SCRIPT_NAME" => "/foo")).url. + should.equal "http://example.org/foo/" + Rack::Request.new(Rack::MockRequest.env_for("/foo")).url. + should.equal "http://example.org/foo" + Rack::Request.new(Rack::MockRequest.env_for("?foo")).url. + should.equal "http://example.org/?foo" + Rack::Request.new(Rack::MockRequest.env_for("http://example.org:8080/")).url. + should.equal "http://example.org:8080/" + Rack::Request.new(Rack::MockRequest.env_for("https://example.org/")).url. + should.equal "https://example.org/" + + Rack::Request.new(Rack::MockRequest.env_for("https://example.com:8080/foo?foo")).url. + should.equal "https://example.com:8080/foo?foo" + end + + specify "can restore the full path" do + Rack::Request.new(Rack::MockRequest.env_for("")).fullpath. + should.equal "/" + Rack::Request.new(Rack::MockRequest.env_for("", "SCRIPT_NAME" => "/foo")).fullpath. + should.equal "/foo/" + Rack::Request.new(Rack::MockRequest.env_for("/foo")).fullpath. + should.equal "/foo" + Rack::Request.new(Rack::MockRequest.env_for("?foo")).fullpath. + should.equal "/?foo" + Rack::Request.new(Rack::MockRequest.env_for("http://example.org:8080/")).fullpath. + should.equal "/" + Rack::Request.new(Rack::MockRequest.env_for("https://example.org/")).fullpath. + should.equal "/" + + Rack::Request.new(Rack::MockRequest.env_for("https://example.com:8080/foo?foo")).fullpath. + should.equal "/foo?foo" + end + + specify "can handle multiple media type parameters" do + req = Rack::Request.new \ + Rack::MockRequest.env_for("/", + "CONTENT_TYPE" => 'text/plain; foo=BAR,baz=bizzle dizzle;BLING=bam') + req.should.not.be.form_data + req.media_type_params.should.include 'foo' + req.media_type_params['foo'].should.equal 'BAR' + req.media_type_params.should.include 'baz' + req.media_type_params['baz'].should.equal 'bizzle dizzle' + req.media_type_params.should.not.include 'BLING' + req.media_type_params.should.include 'bling' + req.media_type_params['bling'].should.equal 'bam' + end + + specify "can parse multipart form data" do + # Adapted from RFC 1867. + input = < "multipart/form-data, boundary=AaB03x", + "CONTENT_LENGTH" => input.size, + :input => input) + + req.POST.should.include "fileupload" + req.POST.should.include "reply" + + req.should.be.form_data + req.content_length.should.equal input.size + req.media_type.should.equal 'multipart/form-data' + req.media_type_params.should.include 'boundary' + req.media_type_params['boundary'].should.equal 'AaB03x' + + req.POST["reply"].should.equal "yes" + + f = req.POST["fileupload"] + f.should.be.kind_of Hash + f[:type].should.equal "image/jpeg" + f[:filename].should.equal "dj.jpg" + f.should.include :tempfile + f[:tempfile].size.should.equal 76 + end + + specify "can parse big multipart form data" do + input = < "multipart/form-data, boundary=AaB03x", + "CONTENT_LENGTH" => input.size, + :input => input) + + req.POST["huge"][:tempfile].size.should.equal 32768 + req.POST["mean"][:tempfile].size.should.equal 10 + req.POST["mean"][:tempfile].read.should.equal "--AaB03xha" + end + + specify "can detect invalid multipart form data" do + input = < "multipart/form-data, boundary=AaB03x", + "CONTENT_LENGTH" => input.size, + :input => input) + + lambda { req.POST }.should.raise(EOFError) + + input = < "multipart/form-data, boundary=AaB03x", + "CONTENT_LENGTH" => input.size, + :input => input) + + lambda { req.POST }.should.raise(EOFError) + + input = < "multipart/form-data, boundary=AaB03x", + "CONTENT_LENGTH" => input.size, + :input => input) + + lambda { req.POST }.should.raise(EOFError) + end + + specify "shouldn't try to interpret binary as utf8" do + begin + original_kcode = $KCODE + $KCODE='UTF8' + + input = < "multipart/form-data, boundary=AaB03x", + "CONTENT_LENGTH" => input.size, + :input => input) + + lambda{req.POST}.should.not.raise(EOFError) + req.POST["fileupload"][:tempfile].size.should.equal 4 + ensure + $KCODE = original_kcode + end + end + + + specify "should work around buggy 1.8.* Tempfile equality" do + input = < "multipart/form-data, boundary=AaB03x", + "CONTENT_LENGTH" => input.size, + :input => rack_input) + + lambda {req.POST}.should.not.raise + lambda {req.POST}.should.blaming("input re-processed!").not.raise + end + + specify "does conform to the Rack spec" do + app = lambda { |env| + content = Rack::Request.new(env).POST["file"].inspect + size = content.respond_to?(:bytesize) ? content.bytesize : content.size + [200, {"Content-Type" => "text/html", "Content-Length" => size.to_s}, [content]] + } + + input = < "multipart/form-data, boundary=AaB03x", + "CONTENT_LENGTH" => input.size.to_s, "rack.input" => StringIO.new(input) + + res.should.be.ok + end + + specify "should parse Accept-Encoding correctly" do + parser = lambda do |x| + Rack::Request.new(Rack::MockRequest.env_for("", "HTTP_ACCEPT_ENCODING" => x)).accept_encoding + end + + parser.call(nil).should.equal([]) + + parser.call("compress, gzip").should.equal([["compress", 1.0], ["gzip", 1.0]]) + parser.call("").should.equal([]) + parser.call("*").should.equal([["*", 1.0]]) + parser.call("compress;q=0.5, gzip;q=1.0").should.equal([["compress", 0.5], ["gzip", 1.0]]) + parser.call("gzip;q=1.0, identity; q=0.5, *;q=0").should.equal([["gzip", 1.0], ["identity", 0.5], ["*", 0] ]) + + lambda { parser.call("gzip ; q=1.0") }.should.raise(RuntimeError) + end + + specify 'should provide ip information' do + app = lambda { |env| + request = Rack::Request.new(env) + response = Rack::Response.new + response.write request.ip + response.finish + } + + mock = Rack::MockRequest.new(Rack::Lint.new(app)) + res = mock.get '/', 'REMOTE_ADDR' => '123.123.123.123' + res.body.should.equal '123.123.123.123' + + res = mock.get '/', + 'REMOTE_ADDR' => '123.123.123.123', + 'HTTP_X_FORWARDED_FOR' => '234.234.234.234' + + res.body.should.equal '234.234.234.234' + + res = mock.get '/', + 'REMOTE_ADDR' => '123.123.123.123', + 'HTTP_X_FORWARDED_FOR' => '234.234.234.234,212.212.212.212' + + res.body.should.equal '212.212.212.212' + end + + class MyRequest < Rack::Request + def params + {:foo => "bar"} + end + end + + specify "should allow subclass request to be instantiated after parent request" do + env = Rack::MockRequest.env_for("/?foo=bar") + + req1 = Rack::Request.new(env) + req1.GET.should.equal "foo" => "bar" + req1.params.should.equal "foo" => "bar" + + req2 = MyRequest.new(env) + req2.GET.should.equal "foo" => "bar" + req2.params.should.equal :foo => "bar" + end + + specify "should allow parent request to be instantiated after subclass request" do + env = Rack::MockRequest.env_for("/?foo=bar") + + req1 = MyRequest.new(env) + req1.GET.should.equal "foo" => "bar" + req1.params.should.equal :foo => "bar" + + req2 = Rack::Request.new(env) + req2.GET.should.equal "foo" => "bar" + req2.params.should.equal "foo" => "bar" + end +end diff --git a/vendor/plugins/rack/test/spec_rack_response.rb b/vendor/plugins/rack/test/spec_rack_response.rb new file mode 100644 index 00000000..eb59b5c2 --- /dev/null +++ b/vendor/plugins/rack/test/spec_rack_response.rb @@ -0,0 +1,218 @@ +require 'test/spec' +require 'set' + +require 'rack/response' + +context "Rack::Response" do + specify "has sensible default values" do + response = Rack::Response.new + status, header, body = response.finish + status.should.equal 200 + header.should.equal "Content-Type" => "text/html" + body.each { |part| + part.should.equal "" + } + + response = Rack::Response.new + status, header, body = *response + status.should.equal 200 + header.should.equal "Content-Type" => "text/html" + body.each { |part| + part.should.equal "" + } + end + + specify "can be written to" do + response = Rack::Response.new + + status, header, body = response.finish do + response.write "foo" + response.write "bar" + response.write "baz" + end + + parts = [] + body.each { |part| parts << part } + + parts.should.equal ["foo", "bar", "baz"] + end + + specify "can set and read headers" do + response = Rack::Response.new + response["Content-Type"].should.equal "text/html" + response["Content-Type"] = "text/plain" + response["Content-Type"].should.equal "text/plain" + end + + specify "can set cookies" do + response = Rack::Response.new + + response.set_cookie "foo", "bar" + response["Set-Cookie"].should.equal "foo=bar" + response.set_cookie "foo2", "bar2" + response["Set-Cookie"].should.equal ["foo=bar", "foo2=bar2"] + response.set_cookie "foo3", "bar3" + response["Set-Cookie"].should.equal ["foo=bar", "foo2=bar2", "foo3=bar3"] + end + + specify "formats the Cookie expiration date accordingly to RFC 2109" do + response = Rack::Response.new + + response.set_cookie "foo", {:value => "bar", :expires => Time.now+10} + response["Set-Cookie"].should.match( + /expires=..., \d\d-...-\d\d\d\d \d\d:\d\d:\d\d .../) + end + + specify "can set secure cookies" do + response = Rack::Response.new + response.set_cookie "foo", {:value => "bar", :secure => true} + response["Set-Cookie"].should.equal "foo=bar; secure" + end + + specify "can set http only cookies" do + response = Rack::Response.new + response.set_cookie "foo", {:value => "bar", :httponly => true} + response["Set-Cookie"].should.equal "foo=bar; HttpOnly" + end + + specify "can delete cookies" do + response = Rack::Response.new + response.set_cookie "foo", "bar" + response.set_cookie "foo2", "bar2" + response.delete_cookie "foo" + response["Set-Cookie"].should.equal ["foo2=bar2", + "foo=; expires=Thu, 01-Jan-1970 00:00:00 GMT"] + end + + specify "can do redirects" do + response = Rack::Response.new + response.redirect "/foo" + status, header, body = response.finish + + status.should.equal 302 + header["Location"].should.equal "/foo" + + response = Rack::Response.new + response.redirect "/foo", 307 + status, header, body = response.finish + + status.should.equal 307 + end + + specify "has a useful constructor" do + r = Rack::Response.new("foo") + status, header, body = r.finish + str = ""; body.each { |part| str << part } + str.should.equal "foo" + + r = Rack::Response.new(["foo", "bar"]) + status, header, body = r.finish + str = ""; body.each { |part| str << part } + str.should.equal "foobar" + + r = Rack::Response.new(["foo", "bar"].to_set) + r.write "foo" + status, header, body = r.finish + str = ""; body.each { |part| str << part } + str.should.equal "foobarfoo" + + r = Rack::Response.new([], 500) + r.status.should.equal 500 + end + + specify "has a constructor that can take a block" do + r = Rack::Response.new { |res| + res.status = 404 + res.write "foo" + } + status, header, body = r.finish + str = ""; body.each { |part| str << part } + str.should.equal "foo" + status.should.equal 404 + end + + specify "doesn't return invalid responses" do + r = Rack::Response.new(["foo", "bar"], 204) + status, header, body = r.finish + str = ""; body.each { |part| str << part } + str.should.be.empty + header["Content-Type"].should.equal nil + + lambda { + Rack::Response.new(Object.new) + }.should.raise(TypeError). + message.should =~ /stringable or iterable required/ + end + + specify "knows if it's empty" do + r = Rack::Response.new + r.should.be.empty + r.write "foo" + r.should.not.be.empty + + r = Rack::Response.new + r.should.be.empty + r.finish + r.should.be.empty + + r = Rack::Response.new + r.should.be.empty + r.finish { } + r.should.not.be.empty + end + + specify "should provide access to the HTTP status" do + res = Rack::Response.new + res.status = 200 + res.should.be.successful + res.should.be.ok + + res.status = 404 + res.should.not.be.successful + res.should.be.client_error + res.should.be.not_found + + res.status = 501 + res.should.not.be.successful + res.should.be.server_error + + res.status = 307 + res.should.be.redirect + end + + specify "should provide access to the HTTP headers" do + res = Rack::Response.new + res["Content-Type"] = "text/yaml" + + res.should.include "Content-Type" + res.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.nil + res.location.should.be.nil + end + + specify "does not add or change Content-Length when #finish()ing" do + res = Rack::Response.new + res.status = 200 + res.finish + res.headers["Content-Length"].should.be.nil + + res = Rack::Response.new + res.status = 200 + res.headers["Content-Length"] = "10" + res.finish + res.headers["Content-Length"].should.equal "10" + end + + specify "updates Content-Length when body appended to using #write" do + res = Rack::Response.new + res.status = 200 + res.headers["Content-Length"].should.be.nil + res.write "Hi" + res.headers["Content-Length"].should.equal "2" + res.write " there" + res.headers["Content-Length"].should.equal "8" + end + +end diff --git a/vendor/plugins/rack/test/spec_rack_rewindable_input.rb b/vendor/plugins/rack/test/spec_rack_rewindable_input.rb new file mode 100644 index 00000000..78bebfc9 --- /dev/null +++ b/vendor/plugins/rack/test/spec_rack_rewindable_input.rb @@ -0,0 +1,118 @@ +require 'test/spec' +require 'stringio' +require 'rack/rewindable_input' + +shared_context "a rewindable IO object" do + setup do + @rio = Rack::RewindableInput.new(@io) + end + + teardown do + @rio.close + end + + specify "should be able to handle to read()" do + @rio.read.should.equal "hello world" + end + + specify "should be able to handle to read(nil)" do + @rio.read(nil).should.equal "hello world" + end + + specify "should be able to handle to read(length)" do + @rio.read(1).should.equal "h" + end + + specify "should be able to handle to read(length, buffer)" do + buffer = "" + result = @rio.read(1, buffer) + result.should.equal "h" + result.object_id.should.equal buffer.object_id + end + + specify "should be able to handle to read(nil, buffer)" do + buffer = "" + result = @rio.read(nil, buffer) + result.should.equal "hello world" + result.object_id.should.equal buffer.object_id + end + + specify "should rewind to the beginning when #rewind is called" do + @rio.read(1) + @rio.rewind + @rio.read.should.equal "hello world" + end + + specify "should be able to handle gets" do + @rio.gets.should == "hello world" + end + + specify "should be able to handle each" do + array = [] + @rio.each do |data| + array << data + end + array.should.equal(["hello world"]) + end + + specify "should not buffer into a Tempfile if no data has been read yet" do + @rio.instance_variable_get(:@rewindable_io).should.be.nil + end + + specify "should buffer into a Tempfile when data has been consumed for the first time" do + @rio.read(1) + tempfile = @rio.instance_variable_get(:@rewindable_io) + tempfile.should.not.be.nil + @rio.read(1) + tempfile2 = @rio.instance_variable_get(:@rewindable_io) + tempfile2.should.equal tempfile + end + + specify "should close the underlying tempfile upon calling #close" do + @rio.read(1) + tempfile = @rio.instance_variable_get(:@rewindable_io) + @rio.close + tempfile.should.be.closed + end + + specify "should be possibel to call #close when no data has been buffered yet" do + @rio.close + end + + specify "should be possible to call #close multiple times" do + @rio.close + @rio.close + end +end + +context "Rack::RewindableInput" do + context "given an IO object that is already rewindable" do + setup do + @io = StringIO.new("hello world") + end + + it_should_behave_like "a rewindable IO object" + end + + context "given an IO object that is not rewindable" do + setup do + @io = StringIO.new("hello world") + @io.instance_eval do + undef :rewind + end + end + + it_should_behave_like "a rewindable IO object" + end + + context "given an IO object whose rewind method raises Errno::ESPIPE" do + setup do + @io = StringIO.new("hello world") + def @io.rewind + raise Errno::ESPIPE, "You can't rewind this!" + end + end + + it_should_behave_like "a rewindable IO object" + end +end diff --git a/vendor/plugins/rack/test/spec_rack_session_cookie.rb b/vendor/plugins/rack/test/spec_rack_session_cookie.rb new file mode 100644 index 00000000..3be88b43 --- /dev/null +++ b/vendor/plugins/rack/test/spec_rack_session_cookie.rb @@ -0,0 +1,82 @@ +require 'test/spec' + +require 'rack/session/cookie' +require 'rack/mock' +require 'rack/response' + +context "Rack::Session::Cookie" do + incrementor = lambda { |env| + env["rack.session"]["counter"] ||= 0 + env["rack.session"]["counter"] += 1 + Rack::Response.new(env["rack.session"].inspect).to_a + } + + specify "creates a new cookie" do + res = Rack::MockRequest.new(Rack::Session::Cookie.new(incrementor)).get("/") + res["Set-Cookie"].should.match("rack.session=") + res.body.should.equal '{"counter"=>1}' + end + + specify "loads from a cookie" do + res = Rack::MockRequest.new(Rack::Session::Cookie.new(incrementor)).get("/") + cookie = res["Set-Cookie"] + res = Rack::MockRequest.new(Rack::Session::Cookie.new(incrementor)). + get("/", "HTTP_COOKIE" => cookie) + res.body.should.equal '{"counter"=>2}' + cookie = res["Set-Cookie"] + res = Rack::MockRequest.new(Rack::Session::Cookie.new(incrementor)). + get("/", "HTTP_COOKIE" => cookie) + res.body.should.equal '{"counter"=>3}' + end + + specify "survives broken cookies" do + res = Rack::MockRequest.new(Rack::Session::Cookie.new(incrementor)). + get("/", "HTTP_COOKIE" => "rack.session=blarghfasel") + res.body.should.equal '{"counter"=>1}' + end + + bigcookie = lambda { |env| + env["rack.session"]["cookie"] = "big" * 3000 + Rack::Response.new(env["rack.session"].inspect).to_a + } + + specify "barks on too big cookies" do + lambda { + Rack::MockRequest.new(Rack::Session::Cookie.new(bigcookie)). + get("/", :fatal => true) + }.should.raise(Rack::MockRequest::FatalWarning) + end + + specify "creates a new cookie with integrity hash" do + res = Rack::MockRequest.new(Rack::Session::Cookie.new(incrementor, :secret => 'test')).get("/") + if RUBY_VERSION < "1.9" + res["Set-Cookie"].should.match("rack.session=BAh7BiIMY291bnRlcmkG%0A--1439b4d37b9d4b04c603848382f712d6fcd31088") + else + res["Set-Cookie"].should.match("rack.session=BAh7BkkiDGNvdW50ZXIGOg1lbmNvZGluZyINVVMtQVNDSUlpBg%3D%3D%0A--d7a6637b94d2728194a96c18484e1f7ed9074a83") + end + end + + specify "loads from a cookie wih integrity hash" do + res = Rack::MockRequest.new(Rack::Session::Cookie.new(incrementor, :secret => 'test')).get("/") + cookie = res["Set-Cookie"] + res = Rack::MockRequest.new(Rack::Session::Cookie.new(incrementor, :secret => 'test')). + get("/", "HTTP_COOKIE" => cookie) + res.body.should.equal '{"counter"=>2}' + cookie = res["Set-Cookie"] + res = Rack::MockRequest.new(Rack::Session::Cookie.new(incrementor, :secret => 'test')). + get("/", "HTTP_COOKIE" => cookie) + res.body.should.equal '{"counter"=>3}' + end + + specify "ignores tampered with session cookies" do + app = Rack::Session::Cookie.new(incrementor, :secret => 'test') + response1 = Rack::MockRequest.new(app).get("/") + _, digest = response1["Set-Cookie"].split("--") + tampered_with_cookie = "hackerman-was-here" + "--" + digest + response2 = Rack::MockRequest.new(app).get("/", "HTTP_COOKIE" => + tampered_with_cookie) + + # The tampered-with cookie is ignored, so we get back an identical Set-Cookie + response2["Set-Cookie"].should.equal(response1["Set-Cookie"]) + end +end diff --git a/vendor/plugins/rack/test/spec_rack_session_memcache.rb b/vendor/plugins/rack/test/spec_rack_session_memcache.rb new file mode 100644 index 00000000..37c3d895 --- /dev/null +++ b/vendor/plugins/rack/test/spec_rack_session_memcache.rb @@ -0,0 +1,240 @@ +require 'test/spec' + +begin + require 'rack/session/memcache' + require 'rack/mock' + require 'rack/response' + require 'thread' + + context "Rack::Session::Memcache" do + session_key = Rack::Session::Memcache::DEFAULT_OPTIONS[:key] + session_match = /#{session_key}=[0-9a-fA-F]+;/ + incrementor = lambda do |env| + env["rack.session"]["counter"] ||= 0 + env["rack.session"]["counter"] += 1 + Rack::Response.new(env["rack.session"].inspect).to_a + end + drop_session = proc do |env| + env['rack.session.options'][:drop] = true + incrementor.call(env) + end + renew_session = proc do |env| + env['rack.session.options'][:renew] = true + incrementor.call(env) + end + defer_session = proc do |env| + env['rack.session.options'][:defer] = true + incrementor.call(env) + end + + specify "MemCache can connect to existing server" do + test_pool = MemCache.new :namespace => 'test:rack:session' + end + + specify "faults on no connection" do + lambda do + Rack::Session::Memcache.new(incrementor, :memcache_server => '') + end.should.raise + end + + specify "creates a new cookie" do + pool = Rack::Session::Memcache.new(incrementor) + res = Rack::MockRequest.new(pool).get("/") + res["Set-Cookie"].should.match("#{session_key}=") + res.body.should.equal '{"counter"=>1}' + end + + specify "determines session from a cookie" do + pool = Rack::Session::Memcache.new(incrementor) + req = Rack::MockRequest.new(pool) + res = req.get("/") + cookie = res["Set-Cookie"] + req.get("/", "HTTP_COOKIE" => cookie). + body.should.equal '{"counter"=>2}' + req.get("/", "HTTP_COOKIE" => cookie). + body.should.equal '{"counter"=>3}' + end + + specify "survives nonexistant cookies" do + bad_cookie = "rack.session=blarghfasel" + pool = Rack::Session::Memcache.new(incrementor) + res = Rack::MockRequest.new(pool). + get("/", "HTTP_COOKIE" => bad_cookie) + res.body.should.equal '{"counter"=>1}' + cookie = res["Set-Cookie"][session_match] + cookie.should.not.match(/#{bad_cookie}/) + end + + specify "maintains freshness" do + pool = Rack::Session::Memcache.new(incrementor, :expire_after => 3) + res = Rack::MockRequest.new(pool).get('/') + res.body.should.include '"counter"=>1' + cookie = res["Set-Cookie"] + res = Rack::MockRequest.new(pool).get('/', "HTTP_COOKIE" => cookie) + res["Set-Cookie"].should.equal cookie + res.body.should.include '"counter"=>2' + puts 'Sleeping to expire session' if $DEBUG + sleep 4 + res = Rack::MockRequest.new(pool).get('/', "HTTP_COOKIE" => cookie) + res["Set-Cookie"].should.not.equal cookie + res.body.should.include '"counter"=>1' + end + + specify "deletes cookies with :drop option" do + pool = Rack::Session::Memcache.new(incrementor) + req = Rack::MockRequest.new(pool) + drop = Rack::Utils::Context.new(pool, drop_session) + dreq = Rack::MockRequest.new(drop) + + res0 = req.get("/") + session = (cookie = res0["Set-Cookie"])[session_match] + res0.body.should.equal '{"counter"=>1}' + + res1 = req.get("/", "HTTP_COOKIE" => cookie) + res1["Set-Cookie"][session_match].should.equal session + res1.body.should.equal '{"counter"=>2}' + + res2 = dreq.get("/", "HTTP_COOKIE" => cookie) + res2["Set-Cookie"].should.equal nil + res2.body.should.equal '{"counter"=>3}' + + res3 = req.get("/", "HTTP_COOKIE" => cookie) + res3["Set-Cookie"][session_match].should.not.equal session + res3.body.should.equal '{"counter"=>1}' + end + + specify "provides new session id with :renew option" do + pool = Rack::Session::Memcache.new(incrementor) + req = Rack::MockRequest.new(pool) + renew = Rack::Utils::Context.new(pool, renew_session) + rreq = Rack::MockRequest.new(renew) + + res0 = req.get("/") + session = (cookie = res0["Set-Cookie"])[session_match] + res0.body.should.equal '{"counter"=>1}' + + res1 = req.get("/", "HTTP_COOKIE" => cookie) + res1["Set-Cookie"][session_match].should.equal session + res1.body.should.equal '{"counter"=>2}' + + res2 = rreq.get("/", "HTTP_COOKIE" => cookie) + new_cookie = res2["Set-Cookie"] + new_session = new_cookie[session_match] + new_session.should.not.equal session + res2.body.should.equal '{"counter"=>3}' + + res3 = req.get("/", "HTTP_COOKIE" => new_cookie) + res3["Set-Cookie"][session_match].should.equal new_session + res3.body.should.equal '{"counter"=>4}' + end + + specify "omits cookie with :defer option" do + pool = Rack::Session::Memcache.new(incrementor) + req = Rack::MockRequest.new(pool) + defer = Rack::Utils::Context.new(pool, defer_session) + dreq = Rack::MockRequest.new(defer) + + res0 = req.get("/") + session = (cookie = res0["Set-Cookie"])[session_match] + res0.body.should.equal '{"counter"=>1}' + + res1 = req.get("/", "HTTP_COOKIE" => cookie) + res1["Set-Cookie"][session_match].should.equal session + res1.body.should.equal '{"counter"=>2}' + + res2 = dreq.get("/", "HTTP_COOKIE" => cookie) + res2["Set-Cookie"].should.equal nil + res2.body.should.equal '{"counter"=>3}' + + res3 = req.get("/", "HTTP_COOKIE" => cookie) + res3["Set-Cookie"][session_match].should.equal session + res3.body.should.equal '{"counter"=>4}' + end + + # anyone know how to do this better? + specify "multithread: should cleanly merge sessions" do + next unless $DEBUG + warn 'Running multithread test for Session::Memcache' + pool = Rack::Session::Memcache.new(incrementor) + req = Rack::MockRequest.new(pool) + + res = req.get('/') + res.body.should.equal '{"counter"=>1}' + cookie = res["Set-Cookie"] + sess_id = cookie[/#{pool.key}=([^,;]+)/,1] + + delta_incrementor = lambda do |env| + # emulate disconjoinment of threading + env['rack.session'] = env['rack.session'].dup + Thread.stop + env['rack.session'][(Time.now.usec*rand).to_i] = true + incrementor.call(env) + end + tses = Rack::Utils::Context.new pool, delta_incrementor + treq = Rack::MockRequest.new(tses) + tnum = rand(7).to_i+5 + r = Array.new(tnum) do + Thread.new(treq) do |run| + 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' + end + + session = pool.pool.get(sess_id) + session.size.should.be tnum+1 # counter + session['counter'].should.be 2 # meeeh + + tnum = rand(7).to_i+5 + r = Array.new(tnum) do |i| + delta_time = proc do |env| + env['rack.session'][i] = Time.now + Thread.stop + env['rack.session'] = env['rack.session'].dup + env['rack.session'][i] -= Time.now + incrementor.call(env) + end + app = Rack::Utils::Context.new pool, time_delta + req = Rack::MockRequest.new app + Thread.new(req) do |run| + 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' + end + + session = pool.pool.get(sess_id) + session.size.should.be tnum+1 + session['counter'].should.be 3 + + drop_counter = proc do |env| + env['rack.session'].delete 'counter' + env['rack.session']['foo'] = 'bar' + [200, {'Content-Type'=>'text/plain'}, env['rack.session'].inspect] + end + tses = Rack::Utils::Context.new pool, drop_counter + treq = Rack::MockRequest.new(tses) + tnum = rand(7).to_i+5 + r = Array.new(tnum) do + Thread.new(treq) do |run| + 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"' + end + + session = pool.pool.get(sess_id) + session.size.should.be r.size+1 + session['counter'].should.be.nil? + session['foo'].should.equal 'bar' + end + end +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_session_pool.rb b/vendor/plugins/rack/test/spec_rack_session_pool.rb new file mode 100644 index 00000000..6be382ec --- /dev/null +++ b/vendor/plugins/rack/test/spec_rack_session_pool.rb @@ -0,0 +1,172 @@ +require 'test/spec' + +require 'rack/session/pool' +require 'rack/mock' +require 'rack/response' +require 'thread' + +context "Rack::Session::Pool" do + session_key = Rack::Session::Pool::DEFAULT_OPTIONS[:key] + session_match = /#{session_key}=[0-9a-fA-F]+;/ + incrementor = lambda do |env| + env["rack.session"]["counter"] ||= 0 + env["rack.session"]["counter"] += 1 + Rack::Response.new(env["rack.session"].inspect).to_a + end + drop_session = proc do |env| + env['rack.session.options'][:drop] = true + incrementor.call(env) + end + renew_session = proc do |env| + env['rack.session.options'][:renew] = true + incrementor.call(env) + end + defer_session = proc do |env| + env['rack.session.options'][:defer] = true + incrementor.call(env) + end + + specify "creates a new cookie" do + pool = Rack::Session::Pool.new(incrementor) + res = Rack::MockRequest.new(pool).get("/") + res["Set-Cookie"].should.match session_match + res.body.should.equal '{"counter"=>1}' + end + + specify "determines session from a cookie" do + pool = Rack::Session::Pool.new(incrementor) + req = Rack::MockRequest.new(pool) + cookie = req.get("/")["Set-Cookie"] + req.get("/", "HTTP_COOKIE" => cookie). + body.should.equal '{"counter"=>2}' + req.get("/", "HTTP_COOKIE" => cookie). + body.should.equal '{"counter"=>3}' + end + + specify "survives nonexistant cookies" do + pool = Rack::Session::Pool.new(incrementor) + res = Rack::MockRequest.new(pool). + get("/", "HTTP_COOKIE" => "#{session_key}=blarghfasel") + res.body.should.equal '{"counter"=>1}' + end + + specify "deletes cookies with :drop option" do + pool = Rack::Session::Pool.new(incrementor) + req = Rack::MockRequest.new(pool) + drop = Rack::Utils::Context.new(pool, drop_session) + dreq = Rack::MockRequest.new(drop) + + res0 = req.get("/") + session = (cookie = res0["Set-Cookie"])[session_match] + res0.body.should.equal '{"counter"=>1}' + pool.pool.size.should.be 1 + + res1 = req.get("/", "HTTP_COOKIE" => cookie) + res1["Set-Cookie"][session_match].should.equal session + res1.body.should.equal '{"counter"=>2}' + pool.pool.size.should.be 1 + + res2 = dreq.get("/", "HTTP_COOKIE" => cookie) + res2["Set-Cookie"].should.equal nil + res2.body.should.equal '{"counter"=>3}' + pool.pool.size.should.be 0 + + res3 = req.get("/", "HTTP_COOKIE" => cookie) + res3["Set-Cookie"][session_match].should.not.equal session + res3.body.should.equal '{"counter"=>1}' + pool.pool.size.should.be 1 + end + + specify "provides new session id with :renew option" do + pool = Rack::Session::Pool.new(incrementor) + req = Rack::MockRequest.new(pool) + renew = Rack::Utils::Context.new(pool, renew_session) + rreq = Rack::MockRequest.new(renew) + + res0 = req.get("/") + session = (cookie = res0["Set-Cookie"])[session_match] + res0.body.should.equal '{"counter"=>1}' + pool.pool.size.should.be 1 + + res1 = req.get("/", "HTTP_COOKIE" => cookie) + res1["Set-Cookie"][session_match].should.equal session + res1.body.should.equal '{"counter"=>2}' + pool.pool.size.should.be 1 + + res2 = rreq.get("/", "HTTP_COOKIE" => cookie) + new_cookie = res2["Set-Cookie"] + new_session = new_cookie[session_match] + new_session.should.not.equal session + res2.body.should.equal '{"counter"=>3}' + pool.pool.size.should.be 1 + + res3 = req.get("/", "HTTP_COOKIE" => new_cookie) + res3["Set-Cookie"][session_match].should.equal new_session + res3.body.should.equal '{"counter"=>4}' + pool.pool.size.should.be 1 + end + + specify "omits cookie with :defer option" do + pool = Rack::Session::Pool.new(incrementor) + req = Rack::MockRequest.new(pool) + defer = Rack::Utils::Context.new(pool, defer_session) + dreq = Rack::MockRequest.new(defer) + + res0 = req.get("/") + session = (cookie = res0["Set-Cookie"])[session_match] + res0.body.should.equal '{"counter"=>1}' + pool.pool.size.should.be 1 + + res1 = req.get("/", "HTTP_COOKIE" => cookie) + res1["Set-Cookie"][session_match].should.equal session + res1.body.should.equal '{"counter"=>2}' + pool.pool.size.should.be 1 + + res2 = dreq.get("/", "HTTP_COOKIE" => cookie) + res2["Set-Cookie"].should.equal nil + res2.body.should.equal '{"counter"=>3}' + pool.pool.size.should.be 1 + + res3 = req.get("/", "HTTP_COOKIE" => cookie) + res3["Set-Cookie"][session_match].should.equal session + res3.body.should.equal '{"counter"=>4}' + pool.pool.size.should.be 1 + end + + # anyone know how to do this better? + specify "multithread: should merge sessions" do + next unless $DEBUG + warn 'Running multithread tests for Session::Pool' + pool = Rack::Session::Pool.new(incrementor) + req = Rack::MockRequest.new(pool) + + res = req.get('/') + res.body.should.equal '{"counter"=>1}' + cookie = res["Set-Cookie"] + sess_id = cookie[/#{pool.key}=([^,;]+)/,1] + + delta_incrementor = lambda do |env| + # emulate disconjoinment of threading + env['rack.session'] = env['rack.session'].dup + Thread.stop + env['rack.session'][(Time.now.usec*rand).to_i] = true + incrementor.call(env) + end + tses = Rack::Utils::Context.new pool, delta_incrementor + treq = Rack::MockRequest.new(tses) + tnum = rand(7).to_i+5 + r = Array.new(tnum) do + Thread.new(treq) do |run| + 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' + end + + session = pool.pool[sess_id] + session.size.should.be tnum+1 # counter + session['counter'].should.be 2 # meeeh + end +end diff --git a/vendor/plugins/rack/test/spec_rack_showexceptions.rb b/vendor/plugins/rack/test/spec_rack_showexceptions.rb new file mode 100644 index 00000000..bdbc1201 --- /dev/null +++ b/vendor/plugins/rack/test/spec_rack_showexceptions.rb @@ -0,0 +1,21 @@ +require 'test/spec' + +require 'rack/showexceptions' +require 'rack/mock' + +context "Rack::ShowExceptions" do + specify "catches exceptions" do + res = nil + req = Rack::MockRequest.new(Rack::ShowExceptions.new(lambda { |env| + raise RuntimeError + })) + lambda { + res = req.get("/") + }.should.not.raise + res.should.be.a.server_error + res.status.should.equal 500 + + res.should =~ /RuntimeError/ + res.should =~ /ShowExceptions/ + end +end diff --git a/vendor/plugins/rack/test/spec_rack_showstatus.rb b/vendor/plugins/rack/test/spec_rack_showstatus.rb new file mode 100644 index 00000000..78700134 --- /dev/null +++ b/vendor/plugins/rack/test/spec_rack_showstatus.rb @@ -0,0 +1,72 @@ +require 'test/spec' + +require 'rack/showstatus' +require 'rack/mock' + +context "Rack::ShowStatus" do + specify "should provide a default status message" do + req = Rack::MockRequest.new(Rack::ShowStatus.new(lambda { |env| + [404, {"Content-Type" => "text/plain", "Content-Length" => "0"}, []] + })) + + res = req.get("/", :lint => true) + res.should.be.not_found + res.should.be.not.empty + + res["Content-Type"].should.equal("text/html") + res.should =~ /404/ + res.should =~ /Not Found/ + end + + specify "should let the app provide additional information" do + req = Rack::MockRequest.new(Rack::ShowStatus.new(lambda { |env| + env["rack.showstatus.detail"] = "gone too meta." + [404, {"Content-Type" => "text/plain", "Content-Length" => "0"}, []] + })) + + res = req.get("/", :lint => true) + res.should.be.not_found + res.should.be.not.empty + + res["Content-Type"].should.equal("text/html") + res.should =~ /404/ + res.should =~ /Not Found/ + res.should =~ /too meta/ + end + + specify "should not replace existing messages" do + req = Rack::MockRequest.new(Rack::ShowStatus.new(lambda { |env| + [404, {"Content-Type" => "text/plain", "Content-Length" => "4"}, ["foo!"]] + })) + res = req.get("/", :lint => true) + res.should.be.not_found + + res.body.should == "foo!" + end + + specify "should pass on original headers" do + headers = {"WWW-Authenticate" => "Basic blah"} + + req = Rack::MockRequest.new(Rack::ShowStatus.new(lambda { |env| [401, headers, []] })) + res = req.get("/", :lint => true) + + res["WWW-Authenticate"].should.equal("Basic blah") + end + + specify "should replace existing messages if there is detail" do + req = Rack::MockRequest.new(Rack::ShowStatus.new(lambda { |env| + env["rack.showstatus.detail"] = "gone too meta." + [404, {"Content-Type" => "text/plain", "Content-Length" => "4"}, ["foo!"]] + })) + + res = req.get("/", :lint => true) + res.should.be.not_found + res.should.be.not.empty + + res["Content-Type"].should.equal("text/html") + res["Content-Length"].should.not.equal("4") + res.should =~ /404/ + res.should =~ /too meta/ + res.body.should.not =~ /foo/ + end +end diff --git a/vendor/plugins/rack/test/spec_rack_static.rb b/vendor/plugins/rack/test/spec_rack_static.rb new file mode 100644 index 00000000..19d2ecb7 --- /dev/null +++ b/vendor/plugins/rack/test/spec_rack_static.rb @@ -0,0 +1,37 @@ +require 'test/spec' + +require 'rack/static' +require 'rack/mock' + +class DummyApp + def call(env) + [200, {}, ["Hello World"]] + end +end + +context "Rack::Static" do + root = File.expand_path(File.dirname(__FILE__)) + OPTIONS = {:urls => ["/cgi"], :root => root} + + setup do + @request = Rack::MockRequest.new(Rack::Static.new(DummyApp.new, OPTIONS)) + end + + specify "serves files" do + res = @request.get("/cgi/test") + res.should.be.ok + res.body.should =~ /ruby/ + end + + specify "404s if url root is known but it can't find the file" do + res = @request.get("/cgi/foo") + res.should.be.not_found + end + + specify "calls down the chain if url root is not known" do + res = @request.get("/something/else") + res.should.be.ok + res.body.should == "Hello World" + end + +end diff --git a/vendor/plugins/rack/test/spec_rack_thin.rb b/vendor/plugins/rack/test/spec_rack_thin.rb new file mode 100644 index 00000000..324f6498 --- /dev/null +++ b/vendor/plugins/rack/test/spec_rack_thin.rb @@ -0,0 +1,91 @@ +require 'test/spec' + +begin +require 'rack/handler/thin' +require 'testrequest' +require 'timeout' + +context "Rack::Handler::Thin" do + include TestRequest::Helpers + + setup do + @app = Rack::Lint.new(TestRequest.new) + @server = nil + Thin::Logging.silent = true + @thread = Thread.new do + Rack::Handler::Thin.run(@app, :Host => @host='0.0.0.0', :Port => @port=9204) do |server| + @server = server + end + end + Thread.pass until @server && @server.running? + end + + specify "should respond" do + lambda { + GET("/") + }.should.not.raise + end + + specify "should be a Thin" do + GET("/") + status.should.be 200 + response["SERVER_SOFTWARE"].should =~ /thin/ + response["HTTP_VERSION"].should.equal "HTTP/1.1" + response["SERVER_PROTOCOL"].should.equal "HTTP/1.1" + response["SERVER_PORT"].should.equal "9204" + response["SERVER_NAME"].should.equal "0.0.0.0" + end + + specify "should have rack headers" do + GET("/") + response["rack.version"].should.equal [0,3] + response["rack.multithread"].should.be false + response["rack.multiprocess"].should.be false + response["rack.run_once"].should.be false + end + + specify "should have CGI headers on GET" do + GET("/") + response["REQUEST_METHOD"].should.equal "GET" + response["REQUEST_PATH"].should.equal "/" + response["PATH_INFO"].should.be.equal "/" + response["QUERY_STRING"].should.equal "" + response["test.postdata"].should.equal "" + + GET("/test/foo?quux=1") + response["REQUEST_METHOD"].should.equal "GET" + response["REQUEST_PATH"].should.equal "/test/foo" + response["PATH_INFO"].should.equal "/test/foo" + response["QUERY_STRING"].should.equal "quux=1" + end + + specify "should have CGI headers on POST" do + POST("/", {"rack-form-data" => "23"}, {'X-test-header' => '42'}) + status.should.equal 200 + response["REQUEST_METHOD"].should.equal "POST" + response["REQUEST_PATH"].should.equal "/" + response["QUERY_STRING"].should.equal "" + response["HTTP_X_TEST_HEADER"].should.equal "42" + response["test.postdata"].should.equal "rack-form-data=23" + end + + specify "should support HTTP auth" do + GET("/test", {:user => "ruth", :passwd => "secret"}) + response["HTTP_AUTHORIZATION"].should.equal "Basic cnV0aDpzZWNyZXQ=" + end + + specify "should set status" do + GET("/test?secret") + status.should.equal 403 + response["rack.url_scheme"].should.equal "http" + end + + teardown do + @server.stop! + @thread.kill + end +end + +rescue LoadError + $stderr.puts "Skipping Rack::Handler::Thin tests (Thin is required). `gem install thin` and try again." +end diff --git a/vendor/plugins/rack/test/spec_rack_urlmap.rb b/vendor/plugins/rack/test/spec_rack_urlmap.rb new file mode 100644 index 00000000..6c4d72ac --- /dev/null +++ b/vendor/plugins/rack/test/spec_rack_urlmap.rb @@ -0,0 +1,185 @@ +require 'test/spec' + +require 'rack/urlmap' +require 'rack/mock' + +context "Rack::URLMap" do + specify "dispatches paths correctly" do + app = lambda { |env| + [200, { + 'X-ScriptName' => env['SCRIPT_NAME'], + 'X-PathInfo' => env['PATH_INFO'], + 'Content-Type' => 'text/plain' + }, [""]] + } + map = Rack::URLMap.new({ + 'http://foo.org/bar' => app, + '/foo' => app, + '/foo/bar' => app + }) + + res = Rack::MockRequest.new(map).get("/") + res.should.be.not_found + + res = Rack::MockRequest.new(map).get("/qux") + res.should.be.not_found + + res = Rack::MockRequest.new(map).get("/foo") + res.should.be.ok + res["X-ScriptName"].should.equal "/foo" + res["X-PathInfo"].should.equal "" + + res = Rack::MockRequest.new(map).get("/foo/") + res.should.be.ok + res["X-ScriptName"].should.equal "/foo" + res["X-PathInfo"].should.equal "/" + + res = Rack::MockRequest.new(map).get("/foo/bar") + res.should.be.ok + res["X-ScriptName"].should.equal "/foo/bar" + res["X-PathInfo"].should.equal "" + + res = Rack::MockRequest.new(map).get("/foo/bar/") + res.should.be.ok + res["X-ScriptName"].should.equal "/foo/bar" + res["X-PathInfo"].should.equal "/" + + res = Rack::MockRequest.new(map).get("/foo/quux", "SCRIPT_NAME" => "/bleh") + res.should.be.ok + res["X-ScriptName"].should.equal "/bleh/foo" + res["X-PathInfo"].should.equal "/quux" + + res = Rack::MockRequest.new(map).get("/bar", 'HTTP_HOST' => 'foo.org') + res.should.be.ok + res["X-ScriptName"].should.equal "/bar" + res["X-PathInfo"].should.be.empty + + res = Rack::MockRequest.new(map).get("/bar/", 'HTTP_HOST' => 'foo.org') + res.should.be.ok + res["X-ScriptName"].should.equal "/bar" + res["X-PathInfo"].should.equal '/' + end + + + specify "dispatches hosts correctly" do + map = Rack::URLMap.new("http://foo.org/" => lambda { |env| + [200, + { "Content-Type" => "text/plain", + "X-Position" => "foo.org", + "X-Host" => env["HTTP_HOST"] || env["SERVER_NAME"], + }, [""]]}, + "http://subdomain.foo.org/" => lambda { |env| + [200, + { "Content-Type" => "text/plain", + "X-Position" => "subdomain.foo.org", + "X-Host" => env["HTTP_HOST"] || env["SERVER_NAME"], + }, [""]]}, + "http://bar.org/" => lambda { |env| + [200, + { "Content-Type" => "text/plain", + "X-Position" => "bar.org", + "X-Host" => env["HTTP_HOST"] || env["SERVER_NAME"], + }, [""]]}, + "/" => lambda { |env| + [200, + { "Content-Type" => "text/plain", + "X-Position" => "default.org", + "X-Host" => env["HTTP_HOST"] || env["SERVER_NAME"], + }, [""]]} + ) + + res = Rack::MockRequest.new(map).get("/") + res.should.be.ok + res["X-Position"].should.equal "default.org" + + res = Rack::MockRequest.new(map).get("/", "HTTP_HOST" => "bar.org") + res.should.be.ok + res["X-Position"].should.equal "bar.org" + + res = Rack::MockRequest.new(map).get("/", "HTTP_HOST" => "foo.org") + res.should.be.ok + res["X-Position"].should.equal "foo.org" + + res = Rack::MockRequest.new(map).get("/", "HTTP_HOST" => "subdomain.foo.org", "SERVER_NAME" => "foo.org") + res.should.be.ok + res["X-Position"].should.equal "subdomain.foo.org" + + res = Rack::MockRequest.new(map).get("http://foo.org/") + res.should.be.ok + res["X-Position"].should.equal "default.org" + + res = Rack::MockRequest.new(map).get("/", "HTTP_HOST" => "example.org") + res.should.be.ok + res["X-Position"].should.equal "default.org" + + res = Rack::MockRequest.new(map).get("/", + "HTTP_HOST" => "example.org:9292", + "SERVER_PORT" => "9292") + res.should.be.ok + res["X-Position"].should.equal "default.org" + end + + specify "should be nestable" do + map = Rack::URLMap.new("/foo" => + Rack::URLMap.new("/bar" => + Rack::URLMap.new("/quux" => lambda { |env| + [200, + { "Content-Type" => "text/plain", + "X-Position" => "/foo/bar/quux", + "X-PathInfo" => env["PATH_INFO"], + "X-ScriptName" => env["SCRIPT_NAME"], + }, [""]]} + ))) + + res = Rack::MockRequest.new(map).get("/foo/bar") + res.should.be.not_found + + res = Rack::MockRequest.new(map).get("/foo/bar/quux") + res.should.be.ok + res["X-Position"].should.equal "/foo/bar/quux" + res["X-PathInfo"].should.equal "" + res["X-ScriptName"].should.equal "/foo/bar/quux" + end + + specify "should route root apps correctly" 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("/foo/bar") + res.should.be.ok + res["X-Position"].should.equal "foo" + res["X-PathInfo"].should.equal "/bar" + res["X-ScriptName"].should.equal "/foo" + + res = Rack::MockRequest.new(map).get("/foo") + res.should.be.ok + res["X-Position"].should.equal "foo" + res["X-PathInfo"].should.equal "" + res["X-ScriptName"].should.equal "/foo" + + res = Rack::MockRequest.new(map).get("/bar") + res.should.be.ok + res["X-Position"].should.equal "root" + res["X-PathInfo"].should.equal "/bar" + res["X-ScriptName"].should.equal "" + + res = Rack::MockRequest.new(map).get("") + res.should.be.ok + res["X-Position"].should.equal "root" + res["X-PathInfo"].should.equal "/" + 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 new file mode 100644 index 00000000..f270e87e --- /dev/null +++ b/vendor/plugins/rack/test/spec_rack_utils.rb @@ -0,0 +1,387 @@ +require 'test/spec' + +require 'rack/utils' +require 'rack/lint' +require 'rack/mock' + +context "Rack::Utils" do + specify "should escape correctly" do + Rack::Utils.escape("fobar").should.equal "fo%3Co%3Ebar" + Rack::Utils.escape("a space").should.equal "a+space" + Rack::Utils.escape("q1!2\"'w$5&7/z8)?\\"). + should.equal "q1%212%22%27w%245%267%2Fz8%29%3F%5C" + end + + specify "should escape correctly for multibyte characters" do + matz_name = "\xE3\x81\xBE\xE3\x81\xA4\xE3\x82\x82\xE3\x81\xA8".unpack("a*")[0] # Matsumoto + matz_name.force_encoding("UTF-8") if matz_name.respond_to? :force_encoding + Rack::Utils.escape(matz_name).should.equal '%E3%81%BE%E3%81%A4%E3%82%82%E3%81%A8' + matz_name_sep = "\xE3\x81\xBE\xE3\x81\xA4 \xE3\x82\x82\xE3\x81\xA8".unpack("a*")[0] # Matsu moto + matz_name_sep.force_encoding("UTF-8") if matz_name_sep.respond_to? :force_encoding + Rack::Utils.escape(matz_name_sep).should.equal '%E3%81%BE%E3%81%A4+%E3%82%82%E3%81%A8' + end + + specify "should unescape correctly" do + Rack::Utils.unescape("fo%3Co%3Ebar").should.equal "fobar" + Rack::Utils.unescape("a+space").should.equal "a space" + Rack::Utils.unescape("a%20space").should.equal "a space" + Rack::Utils.unescape("q1%212%22%27w%245%267%2Fz8%29%3F%5C"). + should.equal "q1!2\"'w$5&7/z8)?\\" + end + + specify "should parse query strings correctly" do + 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"). + should.equal "foo" => "1", "bar" => "2" + Rack::Utils.parse_query("my+weird+field=q1%212%22%27w%245%267%2Fz8%29%3F"). + should.equal "my weird field" => "q1!2\"'w$5&7/z8)?" + Rack::Utils.parse_query("foo%3Dbaz=bar").should.equal "foo=baz" => "bar" + end + + specify "should parse nested query strings correctly" do + Rack::Utils.parse_nested_query("foo"). + should.equal "foo" => nil + Rack::Utils.parse_nested_query("foo="). + should.equal "foo" => "" + Rack::Utils.parse_nested_query("foo=bar"). + should.equal "foo" => "bar" + + Rack::Utils.parse_nested_query("foo=bar&foo=quux"). + should.equal "foo" => "quux" + Rack::Utils.parse_nested_query("foo&foo="). + should.equal "foo" => "" + Rack::Utils.parse_nested_query("foo=1&bar=2"). + should.equal "foo" => "1", "bar" => "2" + Rack::Utils.parse_nested_query("&foo=1&&bar=2"). + should.equal "foo" => "1", "bar" => "2" + Rack::Utils.parse_nested_query("foo&bar="). + should.equal "foo" => nil, "bar" => "" + Rack::Utils.parse_nested_query("foo=bar&baz="). + should.equal "foo" => "bar", "baz" => "" + Rack::Utils.parse_nested_query("my+weird+field=q1%212%22%27w%245%267%2Fz8%29%3F"). + should.equal "my weird field" => "q1!2\"'w$5&7/z8)?" + + Rack::Utils.parse_nested_query("foo[]"). + should.equal "foo" => [nil] + Rack::Utils.parse_nested_query("foo[]="). + should.equal "foo" => [""] + Rack::Utils.parse_nested_query("foo[]=bar"). + should.equal "foo" => ["bar"] + + Rack::Utils.parse_nested_query("foo[]=1&foo[]=2"). + should.equal "foo" => ["1", "2"] + Rack::Utils.parse_nested_query("foo=bar&baz[]=1&baz[]=2&baz[]=3"). + should.equal "foo" => "bar", "baz" => ["1", "2", "3"] + Rack::Utils.parse_nested_query("foo[]=bar&baz[]=1&baz[]=2&baz[]=3"). + should.equal "foo" => ["bar"], "baz" => ["1", "2", "3"] + + Rack::Utils.parse_nested_query("x[y][z]=1"). + should.equal "x" => {"y" => {"z" => "1"}} + Rack::Utils.parse_nested_query("x[y][z][]=1"). + should.equal "x" => {"y" => {"z" => ["1"]}} + Rack::Utils.parse_nested_query("x[y][z]=1&x[y][z]=2"). + should.equal "x" => {"y" => {"z" => "2"}} + Rack::Utils.parse_nested_query("x[y][z][]=1&x[y][z][]=2"). + should.equal "x" => {"y" => {"z" => ["1", "2"]}} + + Rack::Utils.parse_nested_query("x[y][][z]=1"). + should.equal "x" => {"y" => [{"z" => "1"}]} + Rack::Utils.parse_nested_query("x[y][][z][]=1"). + should.equal "x" => {"y" => [{"z" => ["1"]}]} + Rack::Utils.parse_nested_query("x[y][][z]=1&x[y][][w]=2"). + should.equal "x" => {"y" => [{"z" => "1", "w" => "2"}]} + + Rack::Utils.parse_nested_query("x[y][][v][w]=1"). + should.equal "x" => {"y" => [{"v" => {"w" => "1"}}]} + Rack::Utils.parse_nested_query("x[y][][z]=1&x[y][][v][w]=2"). + should.equal "x" => {"y" => [{"z" => "1", "v" => {"w" => "2"}}]} + + Rack::Utils.parse_nested_query("x[y][][z]=1&x[y][][z]=2"). + should.equal "x" => {"y" => [{"z" => "1"}, {"z" => "2"}]} + Rack::Utils.parse_nested_query("x[y][][z]=1&x[y][][w]=a&x[y][][z]=2&x[y][][w]=3"). + should.equal "x" => {"y" => [{"z" => "1", "w" => "a"}, {"z" => "2", "w" => "3"}]} + + lambda { Rack::Utils.parse_nested_query("x[y]=1&x[y]z=2") }. + should.raise(TypeError). + message.should.equal "expected Hash (got String) for param `y'" + + lambda { Rack::Utils.parse_nested_query("x[y]=1&x[]=1") }. + should.raise(TypeError). + message.should.equal "expected Array (got Hash) for param `x'" + + lambda { Rack::Utils.parse_nested_query("x[y]=1&x[y][][w]=2") }. + should.raise(TypeError). + message.should.equal "expected Array (got String) for param `y'" + end + + specify "should build query strings correctly" do + Rack::Utils.build_query("foo" => "bar").should.equal "foo=bar" + Rack::Utils.build_query("foo" => ["bar", "quux"]). + should.equal "foo=bar&foo=quux" + Rack::Utils.build_query("foo" => "1", "bar" => "2"). + should.equal "foo=1&bar=2" + Rack::Utils.build_query("my weird field" => "q1!2\"'w$5&7/z8)?"). + should.equal "my+weird+field=q1%212%22%27w%245%267%2Fz8%29%3F" + 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)) + Rack::Utils.select_best_encoding(a, b) + end + + helper.call(%w(), [["x", 1]]).should.equal(nil) + helper.call(%w(identity), [["identity", 0.0]]).should.equal(nil) + helper.call(%w(identity), [["*", 0.0]]).should.equal(nil) + + helper.call(%w(identity), [["compress", 1.0], ["gzip", 1.0]]).should.equal("identity") + + helper.call(%w(compress gzip identity), [["compress", 1.0], ["gzip", 1.0]]).should.equal("compress") + helper.call(%w(compress gzip identity), [["compress", 0.5], ["gzip", 1.0]]).should.equal("gzip") + + helper.call(%w(foo bar identity), []).should.equal("identity") + helper.call(%w(foo bar identity), [["*", 1.0]]).should.equal("foo") + helper.call(%w(foo bar identity), [["*", 1.0], ["foo", 0.9]]).should.equal("bar") + + helper.call(%w(foo bar identity), [["foo", 0], ["bar", 0]]).should.equal("identity") + helper.call(%w(foo bar baz identity), [["*", 0], ["identity", 0.1]]).should.equal("identity") + end + + specify "should return the bytesize of String" do + Rack::Utils.bytesize("FOO\xE2\x82\xAC").should.equal 6 + end +end + +context "Rack::Utils::HeaderHash" do + specify "should retain header case" do + h = Rack::Utils::HeaderHash.new("Content-MD5" => "d5ff4e2a0 ...") + h['ETag'] = 'Boo!' + h.to_hash.should.equal "Content-MD5" => "d5ff4e2a0 ...", "ETag" => 'Boo!' + end + + specify "should check existence of keys case insensitively" do + h = Rack::Utils::HeaderHash.new("Content-MD5" => "d5ff4e2a0 ...") + h.should.include 'content-md5' + h.should.not.include 'ETag' + end + + specify "should merge case-insensitively" do + h = Rack::Utils::HeaderHash.new("ETag" => 'HELLO', "content-length" => '123') + merged = h.merge("Etag" => 'WORLD', 'Content-Length' => '321', "Foo" => 'BAR') + merged.should.equal "Etag"=>'WORLD', "Content-Length"=>'321', "Foo"=>'BAR' + end + + specify "should overwrite case insensitively and assume the new key's case" do + h = Rack::Utils::HeaderHash.new("Foo-Bar" => "baz") + h["foo-bar"] = "bizzle" + h["FOO-BAR"].should.equal "bizzle" + h.length.should.equal 1 + h.to_hash.should.equal "foo-bar" => "bizzle" + end + + specify "should be converted to real Hash" do + h = Rack::Utils::HeaderHash.new("foo" => "bar") + h.to_hash.should.be.instance_of Hash + end + + specify "should convert Array values to Strings when converting to Hash" do + h = Rack::Utils::HeaderHash.new("foo" => ["bar", "baz"]) + h.to_hash.should.equal({ "foo" => "bar\nbaz" }) + 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 +end + +context "Rack::Utils::Context" do + class ContextTest + attr_reader :app + def initialize app; @app=app; end + def call env; context env; end + def context env, app=@app; app.call(env); end + end + test_target1 = proc{|e| e.to_s+' world' } + test_target2 = proc{|e| e.to_i+2 } + test_target3 = proc{|e| nil } + test_target4 = proc{|e| [200,{'Content-Type'=>'text/plain', 'Content-Length'=>'0'},['']] } + test_app = ContextTest.new test_target4 + + specify "should set context correctly" do + test_app.app.should.equal test_target4 + c1 = Rack::Utils::Context.new(test_app, test_target1) + c1.for.should.equal test_app + c1.app.should.equal test_target1 + c2 = Rack::Utils::Context.new(test_app, test_target2) + c2.for.should.equal test_app + c2.app.should.equal test_target2 + end + + specify "should alter app on recontexting" do + c1 = Rack::Utils::Context.new(test_app, test_target1) + c2 = c1.recontext(test_target2) + c2.for.should.equal test_app + c2.app.should.equal test_target2 + c3 = c2.recontext(test_target3) + c3.for.should.equal test_app + c3.app.should.equal test_target3 + end + + specify "should run different apps" do + c1 = Rack::Utils::Context.new test_app, test_target1 + c2 = c1.recontext test_target2 + c3 = c2.recontext test_target3 + c4 = c3.recontext test_target4 + a4 = Rack::Lint.new c4 + a5 = Rack::Lint.new test_app + r1 = c1.call('hello') + r1.should.equal 'hello world' + r2 = c2.call(2) + r2.should.equal 4 + r3 = c3.call(:misc_symbol) + r3.should.be.nil + r4 = Rack::MockRequest.new(a4).get('/') + r4.status.should.be 200 + r5 = Rack::MockRequest.new(a5).get('/') + r5.status.should.be 200 + r4.body.should.equal r5.body + end +end + +context "Rack::Utils::Multipart" do + specify "should return nil if content type is not multipart" do + env = Rack::MockRequest.env_for("/", + "CONTENT_TYPE" => 'application/x-www-form-urlencoded') + Rack::Utils::Multipart.parse_multipart(env).should.equal nil + end + + specify "should parse multipart upload with text file" do + env = Rack::MockRequest.env_for("/", multipart_fixture(:text)) + params = Rack::Utils::Multipart.parse_multipart(env) + params["submit-name"].should.equal "Larry" + params["files"][:type].should.equal "text/plain" + params["files"][:filename].should.equal "file1.txt" + params["files"][:head].should.equal "Content-Disposition: form-data; " + + "name=\"files\"; filename=\"file1.txt\"\r\n" + + "Content-Type: text/plain\r\n" + params["files"][:name].should.equal "files" + params["files"][:tempfile].read.should.equal "contents" + end + + specify "should parse multipart upload with nested parameters" do + env = Rack::MockRequest.env_for("/", multipart_fixture(:nested)) + params = Rack::Utils::Multipart.parse_multipart(env) + params["foo"]["submit-name"].should.equal "Larry" + params["foo"]["files"][:type].should.equal "text/plain" + params["foo"]["files"][:filename].should.equal "file1.txt" + params["foo"]["files"][:head].should.equal "Content-Disposition: form-data; " + + "name=\"foo[files]\"; filename=\"file1.txt\"\r\n" + + "Content-Type: text/plain\r\n" + params["foo"]["files"][:name].should.equal "foo[files]" + params["foo"]["files"][:tempfile].read.should.equal "contents" + end + + specify "should parse multipart upload with binary file" do + env = Rack::MockRequest.env_for("/", multipart_fixture(:binary)) + params = Rack::Utils::Multipart.parse_multipart(env) + params["submit-name"].should.equal "Larry" + params["files"][:type].should.equal "image/png" + params["files"][:filename].should.equal "rack-logo.png" + params["files"][:head].should.equal "Content-Disposition: form-data; " + + "name=\"files\"; filename=\"rack-logo.png\"\r\n" + + "Content-Type: image/png\r\n" + params["files"][:name].should.equal "files" + params["files"][:tempfile].read.length.should.equal 26473 + end + + specify "should parse multipart upload with empty file" do + env = Rack::MockRequest.env_for("/", multipart_fixture(:empty)) + params = Rack::Utils::Multipart.parse_multipart(env) + params["submit-name"].should.equal "Larry" + params["files"][:type].should.equal "text/plain" + params["files"][:filename].should.equal "file1.txt" + params["files"][:head].should.equal "Content-Disposition: form-data; " + + "name=\"files\"; filename=\"file1.txt\"\r\n" + + "Content-Type: text/plain\r\n" + params["files"][:name].should.equal "files" + params["files"][:tempfile].read.should.equal "" + end + + specify "should parse multipart upload with filename with semicolons" do + env = Rack::MockRequest.env_for("/", multipart_fixture(:semicolon)) + params = Rack::Utils::Multipart.parse_multipart(env) + params["files"][:type].should.equal "text/plain" + params["files"][:filename].should.equal "fi;le1.txt" + params["files"][:head].should.equal "Content-Disposition: form-data; " + + "name=\"files\"; filename=\"fi;le1.txt\"\r\n" + + "Content-Type: text/plain\r\n" + params["files"][:name].should.equal "files" + params["files"][:tempfile].read.should.equal "contents" + end + + specify "should not include file params if no file was selected" do + env = Rack::MockRequest.env_for("/", multipart_fixture(:none)) + params = Rack::Utils::Multipart.parse_multipart(env) + params["submit-name"].should.equal "Larry" + params["files"].should.equal nil + params.keys.should.not.include "files" + end + + specify "should parse IE multipart upload and clean up filename" do + env = Rack::MockRequest.env_for("/", multipart_fixture(:ie)) + params = Rack::Utils::Multipart.parse_multipart(env) + params["files"][:type].should.equal "text/plain" + params["files"][:filename].should.equal "file1.txt" + params["files"][:head].should.equal "Content-Disposition: form-data; " + + "name=\"files\"; " + + 'filename="C:\Documents and Settings\Administrator\Desktop\file1.txt"' + + "\r\nContent-Type: text/plain\r\n" + params["files"][:name].should.equal "files" + params["files"][:tempfile].read.should.equal "contents" + end + + specify "rewinds input after parsing upload" do + options = multipart_fixture(:text) + input = options[:input] + 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" + input.read.length.should.equal 197 + end + + private + def multipart_fixture(name) + file = File.join(File.dirname(__FILE__), "multipart", name.to_s) + data = File.open(file, 'rb') { |io| io.read } + + type = "multipart/form-data; boundary=AaB03x" + length = data.respond_to?(:bytesize) ? data.bytesize : data.size + + { "CONTENT_TYPE" => type, + "CONTENT_LENGTH" => length.to_s, + :input => StringIO.new(data) } + end +end diff --git a/vendor/plugins/rack/test/spec_rack_webrick.rb b/vendor/plugins/rack/test/spec_rack_webrick.rb new file mode 100644 index 00000000..3e63ea63 --- /dev/null +++ b/vendor/plugins/rack/test/spec_rack_webrick.rb @@ -0,0 +1,130 @@ +require 'test/spec' + +require 'rack/handler/webrick' +require 'rack/lint' +require 'rack/response' +require 'testrequest' + +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, + :Logger => WEBrick::Log.new(nil, WEBrick::BasicLog::WARN), + :AccessLog => []) + @server.mount "/test", Rack::Handler::WEBrick, + Rack::Lint.new(TestRequest.new) + Thread.new { @server.start } + trap(:INT) { @server.shutdown } + end + + specify "should respond" do + lambda { + GET("/test") + }.should.not.raise + end + + specify "should be a WEBrick" do + GET("/test") + status.should.be 200 + response["SERVER_SOFTWARE"].should =~ /WEBrick/ + response["HTTP_VERSION"].should.equal "HTTP/1.1" + response["SERVER_PROTOCOL"].should.equal "HTTP/1.1" + response["SERVER_PORT"].should.equal "9202" + response["SERVER_NAME"].should.equal "0.0.0.0" + end + + specify "should have rack headers" do + GET("/test") + response["rack.version"].should.equal [1,0] + response["rack.multithread"].should.be true + response["rack.multiprocess"].should.be false + response["rack.run_once"].should.be false + end + + specify "should have CGI headers on GET" do + GET("/test") + response["REQUEST_METHOD"].should.equal "GET" + response["SCRIPT_NAME"].should.equal "/test" + response["REQUEST_PATH"].should.equal "/" + response["PATH_INFO"].should.be.nil + response["QUERY_STRING"].should.equal "" + response["test.postdata"].should.equal "" + + GET("/test/foo?quux=1") + response["REQUEST_METHOD"].should.equal "GET" + response["SCRIPT_NAME"].should.equal "/test" + 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" + response["REQUEST_PATH"].should.equal "/" + response["PATH_INFO"].should.equal "/foo%25encoding" + response["QUERY_STRING"].should.equal "quux=1" + end + + specify "should have CGI headers on POST" do + POST("/test", {"rack-form-data" => "23"}, {'X-test-header' => '42'}) + status.should.equal 200 + response["REQUEST_METHOD"].should.equal "POST" + response["SCRIPT_NAME"].should.equal "/test" + response["REQUEST_PATH"].should.equal "/" + response["QUERY_STRING"].should.equal "" + response["HTTP_X_TEST_HEADER"].should.equal "42" + response["test.postdata"].should.equal "rack-form-data=23" + end + + specify "should support HTTP auth" do + GET("/test", {:user => "ruth", :passwd => "secret"}) + response["HTTP_AUTHORIZATION"].should.equal "Basic cnV0aDpzZWNyZXQ=" + end + + specify "should set status" do + GET("/test?secret") + status.should.equal 403 + response["rack.url_scheme"].should.equal "http" + end + + specify "should correctly set cookies" do + @server.mount "/cookie-test", Rack::Handler::WEBrick, + Rack::Lint.new(lambda { |req| + res = Rack::Response.new + res.set_cookie "one", "1" + res.set_cookie "two", "2" + res.finish + }) + + Net::HTTP.start(@host, @port) { |http| + res = http.get("/cookie-test") + res.code.to_i.should.equal 200 + res.get_fields("set-cookie").should.equal ["one=1", "two=2"] + } + end + + specify "should provide a .run" do + block_ran = false + catch(:done) { + Rack::Handler::WEBrick.run(lambda {}, + {:Port => 9210, + :Logger => WEBrick::Log.new(nil, WEBrick::BasicLog::WARN), + :AccessLog => []}) { |server| + block_ran = true + server.should.be.kind_of WEBrick::HTTPServer + @s = server + throw :done + } + } + block_ran.should.be true + @s.shutdown + end + + teardown do + @server.shutdown + end +end diff --git a/vendor/plugins/rack/test/testrequest.rb b/vendor/plugins/rack/test/testrequest.rb new file mode 100644 index 00000000..7b7190cb --- /dev/null +++ b/vendor/plugins/rack/test/testrequest.rb @@ -0,0 +1,57 @@ +require 'yaml' +require 'net/http' + +class TestRequest + def call(env) + status = env["QUERY_STRING"] =~ /secret/ ? 403 : 200 + env["test.postdata"] = env["rack.input"].read + body = env.to_yaml + size = body.respond_to?(:bytesize) ? body.bytesize : body.size + [status, {"Content-Type" => "text/yaml", "Content-Length" => size.to_s}, [body]] + end + + module Helpers + attr_reader :status, :response + + def GET(path, header={}) + Net::HTTP.start(@host, @port) { |http| + user = header.delete(:user) + passwd = header.delete(:passwd) + + get = Net::HTTP::Get.new(path, header) + get.basic_auth user, passwd if user && passwd + http.request(get) { |response| + @status = response.code.to_i + @response = YAML.load(response.body) + } + } + end + + def POST(path, formdata={}, header={}) + Net::HTTP.start(@host, @port) { |http| + user = header.delete(:user) + passwd = header.delete(:passwd) + + post = Net::HTTP::Post.new(path, header) + post.form_data = formdata + post.basic_auth user, passwd if user && passwd + http.request(post) { |response| + @status = response.code.to_i + @response = YAML.load(response.body) + } + } + end + end +end + +class StreamingRequest + def self.call(env) + [200, {"Content-Type" => "text/plain"}, new] + end + + def each + yield "hello there!\n" + sleep 5 + yield "that is all.\n" + end +end diff --git a/vendor/plugins/rack/test/unregistered_handler/rack/handler/unregistered.rb b/vendor/plugins/rack/test/unregistered_handler/rack/handler/unregistered.rb new file mode 100644 index 00000000..6dd9436d --- /dev/null +++ b/vendor/plugins/rack/test/unregistered_handler/rack/handler/unregistered.rb @@ -0,0 +1,7 @@ +module Rack + module Handler + # this class doesn't do anything, we're just seeing if we get it. + class Unregistered + end + end +end \ No newline at end of file diff --git a/vendor/plugins/rack/test/unregistered_handler/rack/handler/unregistered_long_one.rb b/vendor/plugins/rack/test/unregistered_handler/rack/handler/unregistered_long_one.rb new file mode 100644 index 00000000..1920685f --- /dev/null +++ b/vendor/plugins/rack/test/unregistered_handler/rack/handler/unregistered_long_one.rb @@ -0,0 +1,7 @@ +module Rack + module Handler + # this class doesn't do anything, we're just seeing if we get it. + class UnregisteredLongOne + end + end +end \ No newline at end of file diff --git a/vendor/rails/actionpack/lib/action_controller.rb b/vendor/rails/actionpack/lib/action_controller.rb index 6654c066..dbf13ae0 100644 --- a/vendor/rails/actionpack/lib/action_controller.rb +++ b/vendor/rails/actionpack/lib/action_controller.rb @@ -35,7 +35,8 @@ begin gem 'rack', '~> 1.1.0' require 'rack' rescue Gem::LoadError - require 'action_controller/vendor/rack-1.1.pre/rack' + $:.unshift "#{File.dirname(__FILE__)}/../../../plugins/rack/lib" + require 'rack' end require 'action_controller/cgi_ext'