<?xml version="1.0" encoding="UTF-8"?>
<commit>
  <added type="array"/>
  <modified type="array">
    <modified>
      <diff>@@ -7,9 +7,9 @@ configure do
   Castronaut.logger.debug &quot;Sinatra Config - setting views path to #{views}&quot;
   Castronaut.logger.debug &quot;Sinatra Config - setting public path to #{pub_dir}&quot;
 
-  set_options :root =&gt; root,
-              :views =&gt; views,
-              :public =&gt; pub_dir,
-              :logging =&gt; true,
-              :raise_errors =&gt; true
+  set :root =&gt; root,
+      :views =&gt; views,
+      :public =&gt; pub_dir,
+      :logging =&gt; true,
+      :raise_errors =&gt; true
 end</diff>
      <filename>app/config.rb</filename>
    </modified>
    <modified>
      <diff>@@ -5,7 +5,7 @@ describe 'Castronaut Application Controller' do
 
   describe &quot;requesting / via GET&quot; do
     it &quot;redirects to /login&quot; do
-      get_it '/'
+      get '/'
       @response.should be_redirection
     end
   end
@@ -13,19 +13,19 @@ describe 'Castronaut Application Controller' do
   describe &quot;requesting /login via GET&quot; do
 
     it &quot;responds with status 200&quot; do
-      get_it '/login', :env =&gt; { 'REMOTE_ADDR' =&gt; '10.0.0.1' }
+      get '/login', :env =&gt; { 'REMOTE_ADDR' =&gt; '10.0.0.1' }
 
       @response.should be_ok
     end
 
     it &quot;sets the Pragma header to 'no-cache'&quot; do
-      get_it '/login', :env =&gt; { 'REMOTE_ADDR' =&gt; '10.0.0.1' }
+      get '/login', :env =&gt; { 'REMOTE_ADDR' =&gt; '10.0.0.1' }
 
       headers['Pragma'].should == 'no-cache'
     end
 
     it &quot;sets the Cache-Control header to 'no-store'&quot; do
-      get_it '/login', :env =&gt; { 'REMOTE_ADDR' =&gt; '10.0.0.1' }
+      get '/login', :env =&gt; { 'REMOTE_ADDR' =&gt; '10.0.0.1' }
 
       headers['Cache-Control'].should == 'no-store'
     end
@@ -35,7 +35,7 @@ describe 'Castronaut Application Controller' do
       jan_1st_2003 = Time.parse(&quot;01/01/2003 00:00:00&quot;)
       Time.stub!(:now).and_return(jan_1st_2008)
       
-      get_it '/login', :env =&gt; { 'REMOTE_ADDR' =&gt; '10.0.0.1' }
+      get '/login', :env =&gt; { 'REMOTE_ADDR' =&gt; '10.0.0.1' }
 
       headers['Expires'].should include(&quot;Wed, 01 Jan 2003 00:00:00&quot;)
     end
@@ -45,7 +45,7 @@ describe 'Castronaut Application Controller' do
   describe &quot;requesting /login via POST&quot; do
 
     it 'responds with status 200' do
-      post_it '/login', :env =&gt; { 'REMOTE_ADDR' =&gt; '10.0.0.1' }
+      post '/login', :env =&gt; { 'REMOTE_ADDR' =&gt; '10.0.0.1' }
 
       @response.should be_ok
     end
@@ -55,7 +55,7 @@ describe 'Castronaut Application Controller' do
   describe &quot;requesting /logout via GET&quot; do
 
     it 'responds with status 200' do
-      get_it '/logout', :env =&gt; { 'REMOTE_ADDR' =&gt; '10.0.0.1' }
+      get '/logout', :env =&gt; { 'REMOTE_ADDR' =&gt; '10.0.0.1' }
 
       @response.should be_ok
     end
@@ -65,7 +65,7 @@ describe 'Castronaut Application Controller' do
   describe &quot;requesting /serviceValidate via GET&quot; do
 
     it 'responds with status 200' do
-      get_it '/serviceValidate', :env =&gt; { 'REMOTE_ADDR' =&gt; '10.0.0.1' }
+      get '/serviceValidate', :env =&gt; { 'REMOTE_ADDR' =&gt; '10.0.0.1' }
 
       @response.should be_ok
     end
@@ -75,7 +75,7 @@ describe 'Castronaut Application Controller' do
   describe &quot;requesting /proxyValidate via GET&quot; do
 
     it 'responds with status 200' do
-      get_it '/proxyValidate', :env =&gt; { 'REMOTE_ADDR' =&gt; '10.0.0.1' }
+      get '/proxyValidate', :env =&gt; { 'REMOTE_ADDR' =&gt; '10.0.0.1' }
 
       @response.should be_ok
     end</diff>
      <filename>spec/app/controllers/application_spec.rb</filename>
    </modified>
    <modified>
      <diff>@@ -6,8 +6,8 @@ require 'rack'
 require 'sinatra'
 require 'sinatra/test/unit'
 
-Sinatra::Application.default_options.merge!(
-  :env =&gt; :test,
+Sinatra::Application.set(
+  :environment =&gt; :test,
   :run =&gt; false,
   :raise_errors =&gt; true,
   :logging =&gt; false</diff>
      <filename>spec/spec_controller_helper.rb</filename>
    </modified>
    <modified>
      <diff>@@ -29,6 +29,8 @@
 * chains apps by default
 * has implicit #to_app
 * supports blocks on use
+* has explicit #to_app
+* apps are initialized once
 
 == Rack::Adapter::Camping
 * works with GET
@@ -55,12 +57,28 @@
 * should log to rack.errors by default
 * should log to anything with &lt;&lt;
 
+== Rack::ConditionalGet
+* should set a 304 status and truncate body when If-Modified-Since hits
+* should set a 304 status and truncate body when If-None-Match hits
+* should not affect non-GET/HEAD requests
+
+== Rack::ContentLength
+* sets Content-Length on String bodies if none is set
+* sets Content-Length on Array bodies if none is set
+* does not set Content-Length on variable length bodies
+* does not change Content-Length if it is already set
+* does not set Content-Length on 304 responses
+* does not set Content-Length when Transfer-Encoding is chunked
+
 == Rack::Deflater
 * should be able to deflate bodies that respond to each
 * should be able to deflate String bodies
 * should be able to gzip bodies that respond to each
 * should be able to fallback to no deflation
+* should be able to skip when there is no response entity body
 * should handle the lack of an acceptable encoding
+* should handle gzip response with Last-Modified header
+* should do nothing when no-transform Cache-Control directive present
 
 == Rack::Directory
 * serves directory indices
@@ -85,13 +103,20 @@
 * sets Last-Modified header
 * serves files with URL encoded filenames
 * does not allow directory traversal
+* does not allow directory traversal with encoded periods
 * 404s if it can't find the file
+* detects SystemCallErrors
 
 == Rack::Handler
 * has registered default handlers
 * should get unregistered handler by name
 * should register custom handler
 
+== Rack::Head
+* response (empty)
+* passes GET, POST, PUT, DELETE, OPTIONS, TRACE requests
+* removes body from HEAD requests
+
 == Rack::Lint
 * passes valid request
 * notices fatal errors
@@ -101,9 +126,15 @@
 * notices status errors
 * notices header errors
 * notices content-type errors
+* notices content-length errors
 * notices body errors
 * notices input handling errors
 * notices error handling errors
+* notices HEAD errors
+
+== Rack::Lint::InputWrapper
+* delegates :size to underlying IO object
+* delegates :rewind to underlying IO object
 
 == Rack::Lobster::LambdaLobster
 * should be a single lambda
@@ -115,6 +146,14 @@
 * should be flippable
 * should provide crashing for testing purposes
 
+== Rack::MethodOverride
+* should not affect GET requests
+* _method parameter should modify REQUEST_METHOD for POST requests
+* X-HTTP-Method-Override header should modify REQUEST_METHOD for POST requests
+* should not modify REQUEST_METHOD if the method is unknown
+* should not modify REQUEST_METHOD when _method is nil
+* should store the original REQUEST_METHOD prior to overriding
+
 == Rack::MockRequest
 * should return a MockResponse
 * should be able to only return the environment
@@ -143,6 +182,7 @@
 * should provide a .run that maps a hash
 * should provide a .run that maps a urlmap
 * should provide a .run that maps a urlmap restricting by host
+* should stream #each part of the response
 
 == Rack::Recursive
 * should allow for subrequests
@@ -156,6 +196,8 @@
 * can parse POST data
 * can parse POST data with explicit content type
 * does not parse POST data when media type is not form-data
+* rewinds input after parsing POST data
+* does not rewind unwindable CGI input
 * can get value by key from params with #[]
 * can set value to key on params with #[]=
 * values_at answers values by keys in order given
@@ -175,6 +217,7 @@
 * should work around buggy 1.8.* Tempfile equality
 * does conform to the Rack spec
 * should parse Accept-Encoding correctly
+* should provide ip information
 
 == Rack::Response
 * has sensible default values
@@ -182,6 +225,7 @@
 * can set and read headers
 * can set cookies
 * formats the Cookie expiration date accordingly to RFC 2109
+* can set secure cookies
 * can delete cookies
 * has a useful constructor
 * has a constructor that can take a block
@@ -195,6 +239,9 @@
 * loads from a cookie
 * survives broken cookies
 * barks on too big cookies
+* creates a new cookie with integrity hash
+* loads from a cookie wih integrity hash
+* ignores tampered with session cookies
 
 == Rack::Session::Memcache
 * startup (empty)
@@ -228,6 +275,15 @@
 * 404s if url root is known but it can't find the file
 * calls down the chain if url root is not known
 
+== Rack::Handler::Thin
+* should respond
+* should be a Thin
+* should have rack headers
+* should have CGI headers on GET
+* should have CGI headers on POST
+* should support HTTP auth
+* should set status
+
 == Rack::URLMap
 * dispatches paths correctly
 * dispatches hosts correctly
@@ -242,8 +298,10 @@
 * should figure out which encodings are acceptable
 
 == Rack::Utils::HeaderHash
-* should capitalize on all accesses
-* should capitalize correctly
+* should retain header case
+* should check existence of keys case insensitively
+* should merge case-insensitively
+* should overwrite case insensitively and assume the new key's case
 * should be converted to real Hash
 
 == Rack::Utils::Context
@@ -260,6 +318,7 @@
 * should have CGI headers on POST
 * should support HTTP auth
 * should set status
+* should correctly set cookies
 * should provide a .run
 
-197 specifications, 3 empty (886 requirements), 0 failures
+244 specifications, 4 empty (1004 requirements), 0 failures</diff>
      <filename>vendor/rack/RDOX</filename>
    </modified>
    <modified>
      <diff>@@ -9,38 +9,23 @@ middleware) into a single method call.
 The exact details of this are described in the Rack specification,
 which all Rack applications should conform to.
 
-== Future specification changes
-
-PLEASE NOTE: In versions of Rack LATER than 0.4, the following
-changes will be commited to the Rack specification:
-
-* 1xx, 204 and 304 status codes MUST not contain a Content-Type.
-* A valid Content-Length header MUST be provided for non 1xx, 204 and 304
-  responses with a Transfer-Encoding of &quot;identity&quot; (default).
-  The Content-Length MUST be the same as the sum of the byte-sizes of
-  the chunks.
-* The REQUEST_METHOD may be any HTTP token.
-
-Internal Rack modules have been updated to follow this behavior, but
-the Rack 0.4 Lint does NOT check it yet for compatibility reasons.
-Please update your libraries accordingly.
-
 == 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)
-* Thin
 
 Any valid Rack app will run the same on all these handlers, without
 changing anything.
@@ -58,13 +43,12 @@ These frameworks include Rack adapters in their distributions:
 * Merb
 * Racktools::SimpleApplication
 * Ramaze
+* Ruby on Rails
 * Sinatra
+* Sin
 * Vintage
 * Waves
 
-Ruby on Rails can be run with the adapter included with Thin, which
-will be merged into a later Rack version.
-
 Current links to these projects can be found at
 http://ramaze.net/#other-frameworks
 
@@ -96,6 +80,14 @@ over:
 * 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
@@ -129,7 +121,7 @@ A Gem of Rack is available.  You can install it with:
 I also provide a local mirror of the gems (and development snapshots)
 at my site:
 
-    gem install rack --source http://chneukirchen.org/releases/gems
+    gem install rack --source http://chneukirchen.org/releases/gems/
 
 == Running the tests
 
@@ -204,7 +196,7 @@ run on port 11211) and memcache-client installed.
   * HTTP status 201 can contain a Content-Type and a body now.
   * Many bugfixes, especially related to Cookie handling.
 
-* August 21th, 2008: Fourth public release 0.4.
+* 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.
@@ -216,37 +208,67 @@ run on port 11211) and memcache-client installed.
   * 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.
+
 == Contact
 
 Please mail bugs, suggestions and patches to
 &lt;mailto:rack-devel@googlegroups.com&gt;.
 
 Mailing list archives are available at
-&lt;http://groups.google.com/group/rack-devel&gt;
+&lt;http://groups.google.com/group/rack-devel&gt;.
+
+There is a bug tracker at &lt;http://rack.lighthouseapp.com/&gt;.
 
-Git repository (branches rebased on master are most welcome):
-* http://github.com/chneukirchen/rack
+Git repository (patches rebased on master are most welcome):
+* 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 to
+== 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:
 
-* blink for the Pool sessions, Memcache sessions, OpenID support, many
-  tweaks, patches and bugreports.
-* Michael Fellinger, for the helpful discussion, bugfixes and a better
-  Rack::Request interface.
 * 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, for bug fixing.
+* Aredridel, Ben Alpert, Dan Kubb, Daniel Roethlisberger, Matt Todd,
+  Tom Robinson, and Phil Hagelberg for bug fixing and other
+  improvements.
 * 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&#246;hrl, for tracking down bugs in the Cookie generator.
-* Alexander Kellett for testing the Gem and reviewing the announce.
+* Alexander Kellett for testing the Gem and reviewing the announcement.
 * Marcus R&#252;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.
@@ -254,7 +276,7 @@ You are also welcome to join the #rack channel on irc.freenode.net.
 
 == Copyright
 
-Copyright (C) 2007, 2008 Christian Neukirchen &lt;http://purl.org/net/chneukirchen&gt;
+Copyright (C) 2007, 2008, 2009 Christian Neukirchen &lt;http://purl.org/net/chneukirchen&gt;
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the &quot;Software&quot;), to
@@ -277,11 +299,8 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 
 Rack:: &lt;http://rack.rubyforge.org/&gt;
 Rack's Rubyforge project:: &lt;http://rubyforge.org/projects/rack&gt;
+Official Rack repositories:: &lt;http://github.com/rack&gt;
 rack-devel mailing list:: &lt;http://groups.google.com/group/rack-devel&gt;
 
-Camping:: &lt;http://camping.rubyforge.org/&gt;
-Ramaze:: &lt;http://ramaze.rubyforge.org/&gt;
-Maveric:: &lt;http://maveric.rubyforge.org/&gt;
-
 Christian Neukirchen:: &lt;http://chneukirchen.org/&gt;
 </diff>
      <filename>vendor/rack/README</filename>
    </modified>
    <modified>
      <diff>@@ -133,6 +133,15 @@ Also see http://rack.rubyforge.org.
     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', '~&gt; 2.0.0'
+    #s.add_development_dependency 'thin'
   end
 
   Rake::GemPackageTask.new(spec) do |p|</diff>
      <filename>vendor/rack/Rakefile</filename>
    </modified>
    <modified>
      <diff>@@ -71,8 +71,7 @@ There are the following restrictions:
 * &lt;tt&gt;rack.url_scheme&lt;/tt&gt; must either be +http+ or +https+.
 * There must be a valid input stream in &lt;tt&gt;rack.input&lt;/tt&gt;.
 * There must be a valid error stream in &lt;tt&gt;rack.errors&lt;/tt&gt;.
-* The &lt;tt&gt;REQUEST_METHOD&lt;/tt&gt; must be one of +GET+, +POST+, +PUT+,
-  +DELETE+, +HEAD+, +OPTIONS+, +TRACE+.
+* The &lt;tt&gt;REQUEST_METHOD&lt;/tt&gt; must be a valid token.
 * The &lt;tt&gt;SCRIPT_NAME&lt;/tt&gt;, if non-empty, must start with &lt;tt&gt;/&lt;/tt&gt;
 * The &lt;tt&gt;PATH_INFO&lt;/tt&gt;, if non-empty, must start with &lt;tt&gt;/&lt;/tt&gt;
 * The &lt;tt&gt;CONTENT_LENGTH&lt;/tt&gt;, if given, must consist of digits only.
@@ -111,7 +110,11 @@ The values passed on #each must be Strings
 and not contain characters below 037.
 === The Content-Type
 There must be a &lt;tt&gt;Content-Type&lt;/tt&gt;, except when the
-+Status+ is 204 or 304, in which case there must be none
++Status+ is 1xx, 204 or 304, in which case there must be none
+given.
+=== The Content-Length
+There must be a &lt;tt&gt;Content-Length&lt;/tt&gt;, except when the
++Status+ is 1xx, 204 or 304, in which case there must be none
 given.
 === The Body
 The Body must respond to #each</diff>
      <filename>vendor/rack/SPEC</filename>
    </modified>
    <modified>
      <diff>@@ -1,4 +1,4 @@
-# Copyright (C) 2007, 2008 Christian Neukirchen &lt;purl.org/net/chneukirchen&gt;
+# Copyright (C) 2007, 2008, 2009 Christian Neukirchen &lt;purl.org/net/chneukirchen&gt;
 #
 # Rack is freely distributable under the terms of an MIT-style license.
 # See COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -23,18 +23,23 @@ module Rack
 
   # Return the Rack release as a dotted string.
   def self.release
-    &quot;0.4&quot;
+    &quot;0.9&quot;
   end
 
   autoload :Builder, &quot;rack/builder&quot;
   autoload :Cascade, &quot;rack/cascade&quot;
   autoload :CommonLogger, &quot;rack/commonlogger&quot;
+  autoload :ConditionalGet, &quot;rack/conditionalget&quot;
+  autoload :ContentLength, &quot;rack/content_length&quot;
   autoload :File, &quot;rack/file&quot;
   autoload :Deflater, &quot;rack/deflater&quot;
   autoload :Directory, &quot;rack/directory&quot;
   autoload :ForwardRequest, &quot;rack/recursive&quot;
   autoload :Handler, &quot;rack/handler&quot;
+  autoload :Head, &quot;rack/head&quot;
   autoload :Lint, &quot;rack/lint&quot;
+  autoload :MethodOverride, &quot;rack/methodoverride&quot;
+  autoload :Mime, &quot;rack/mime&quot;
   autoload :Recursive, &quot;rack/recursive&quot;
   autoload :Reloader, &quot;rack/reloader&quot;
   autoload :ShowExceptions, &quot;rack/showexceptions&quot;</diff>
      <filename>vendor/rack/lib/rack.rb</filename>
    </modified>
    <modified>
      <diff>@@ -15,7 +15,7 @@ module Rack
             h[k] = v.to_s
           end
         end
-        [controller.status, controller.headers, controller.body]
+        [controller.status, controller.headers, [controller.body.to_s]]
       end
     end
   end</diff>
      <filename>vendor/rack/lib/rack/adapter/camping.rb</filename>
    </modified>
    <modified>
      <diff>@@ -343,7 +343,7 @@ module Rack
           session['authenticated'] = false
           req.env['rack.errors'].puts oid.message
 
-          goto = @options[:login_fail] if @option.key? :login_fail
+          goto = @options[:login_fail] if @options.key? :login_fail
           body &lt;&lt; &quot;Authentication unsuccessful.\n&quot;
         when ::OpenID::Consumer::SUCCESS
           session.clear
@@ -367,7 +367,7 @@ module Rack
           session.clear
           session['authenticated'] = false
 
-          goto = @options[:login_fail] if @option.key? :login_fail
+          goto = @options[:login_fail] if @options.key? :login_fail
           body &lt;&lt; &quot;Authentication cancelled.\n&quot;
         when ::OpenID::Consumer::SETUP_NEEDED
           session[:setup_needed] = true
@@ -402,7 +402,8 @@ module Rack
       def add_extension ext, *args
         if not ext.is_a? Module
           raise TypeError, &quot;#{ext.inspect} is not a module&quot;
-        elsif not (m = %w'Request Response NS_URI' - ext.constants).empty?
+        elsif !(m = %w'Request Response NS_URI' -
+                ext.constants.map{ |c| c.to_s }).empty?
           raise ArgumentError, &quot;#{ext.inspect} missing #{m*', '}&quot;
         end
 </diff>
      <filename>vendor/rack/lib/rack/auth/openid.rb</filename>
    </modified>
    <modified>
      <diff>@@ -13,6 +13,13 @@ module Rack
   #    end
   #  }
   #
+  # Or
+  #
+  #  app = Rack::Builder.app do
+  #    use Rack::CommonLogger
+  #    lambda { |env| [200, {'Content-Type' =&gt; 'text/plain'}, 'OK'] }
+  #  end
+  #
   # +use+ adds a middleware to the stack, +run+ dispatches to an application.
   # You can use +map+ to construct a Rack::URLMap in a convenient way.
 
@@ -22,6 +29,10 @@ module Rack
       instance_eval(&amp;block) if block_given?
     end
 
+    def self.app(&amp;block)
+      self.new(&amp;block).to_app
+    end
+
     def use(middleware, *args, &amp;block)
       @ins &lt;&lt; if block_given?
         lambda { |app| middleware.new(app, *args, &amp;block) }
@@ -36,7 +47,7 @@ module Rack
 
     def map(path, &amp;block)
       if @ins.last.kind_of? Hash
-        @ins.last[path] = Rack::Builder.new(&amp;block).to_app
+        @ins.last[path] = self.class.new(&amp;block).to_app
       else
         @ins &lt;&lt; {}
         map(path, &amp;block)</diff>
      <filename>vendor/rack/lib/rack/builder.rb</filename>
    </modified>
    <modified>
      <diff>@@ -1,5 +1,6 @@
 require &quot;zlib&quot;
 require &quot;stringio&quot;
+require &quot;time&quot;  # for Time.httpdate
 
 module Rack
 
@@ -10,21 +11,44 @@ class Deflater
 
   def call(env)
     status, headers, body = @app.call(env)
+    headers = Utils::HeaderHash.new(headers)
+
+    # Skip compressing empty entity body responses and responses with
+    # no-transform set.
+    if Utils::STATUS_WITH_NO_ENTITY_BODY.include?(status) ||
+        headers['Cache-Control'].to_s =~ /\bno-transform\b/
+      return [status, headers, body]
+    end
 
     request = Request.new(env)
 
-    encoding = Utils.select_best_encoding(%w(gzip deflate identity), request.accept_encoding)
+    encoding = Utils.select_best_encoding(%w(gzip deflate identity),
+                                          request.accept_encoding)
+
+    # Set the Vary HTTP header.
+    vary = headers[&quot;Vary&quot;].to_s.split(&quot;,&quot;).map { |v| v.strip }
+    unless vary.include?(&quot;*&quot;) || vary.include?(&quot;Accept-Encoding&quot;)
+      headers[&quot;Vary&quot;] = vary.push(&quot;Accept-Encoding&quot;).join(&quot;,&quot;)
+    end
 
     case encoding
     when &quot;gzip&quot;
-      mtime = headers[&quot;Last-Modified&quot;] || Time.now
-      [status, headers.merge(&quot;Content-Encoding&quot; =&gt; &quot;gzip&quot;), self.class.gzip(body, mtime)]
+      mtime = if headers.key?(&quot;Last-Modified&quot;) 
+                Time.httpdate(headers[&quot;Last-Modified&quot;]) 
+              else 
+                Time.now
+              end
+      [status,
+       headers.merge(&quot;Content-Encoding&quot; =&gt; &quot;gzip&quot;),
+       self.class.gzip(body, mtime)]
     when &quot;deflate&quot;
-      [status, headers.merge(&quot;Content-Encoding&quot; =&gt; &quot;deflate&quot;), self.class.deflate(body)]
+      [status,
+       headers.merge(&quot;Content-Encoding&quot; =&gt; &quot;deflate&quot;),
+       self.class.deflate(body)]
     when &quot;identity&quot;
       [status, headers, body]
     when nil
-      message = &quot;An acceptable encoding for the requested resource #{request.fullpath} could not be found.&quot;
+      message = [&quot;An acceptable encoding for the requested resource #{request.fullpath} could not be found.&quot;]
       [406, {&quot;Content-Type&quot; =&gt; &quot;text/plain&quot;}, message]
     end
   end</diff>
      <filename>vendor/rack/lib/rack/deflater.rb</filename>
    </modified>
    <modified>
      <diff>@@ -1,4 +1,5 @@
 require 'time'
+require 'rack/mime'
 
 module Rack
   # Rack::Directory serves entries below the +root+ given, according to the
@@ -13,10 +14,13 @@ module Rack
     DIR_PAGE = &lt;&lt;-PAGE
 &lt;html&gt;&lt;head&gt;
   &lt;title&gt;%s&lt;/title&gt;
+  &lt;meta http-equiv=&quot;content-type&quot; content=&quot;text/html; charset=utf-8&quot; /&gt;
   &lt;style type='text/css'&gt;
 table { width:100%%; }
 .name { text-align:left; }
 .size, .mtime { text-align:right; }
+.type { width:11em; }
+.mtime { width:15em; }
   &lt;/style&gt;
 &lt;/head&gt;&lt;body&gt;
 &lt;h1&gt;%s&lt;/h1&gt;
@@ -38,11 +42,8 @@ table { width:100%%; }
     attr_accessor :root, :path
 
     def initialize(root, app=nil)
-      @root = root
-      @app = app
-      unless defined? @app
-        @app = Rack::File.new(@root)
-      end
+      @root = F.expand_path(root)
+      @app = app || Rack::File.new(@root)
     end
 
     def call(env)
@@ -52,36 +53,72 @@ table { width:100%%; }
     F = ::File
 
     def _call(env)
-      if env[&quot;PATH_INFO&quot;].include? &quot;..&quot;
-        body = &quot;Forbidden\n&quot;
-        size = body.respond_to?(:bytesize) ? body.bytesize : body.size
-        return [403, {&quot;Content-Type&quot; =&gt; &quot;text/plain&quot;,&quot;Content-Length&quot; =&gt; size.to_s}, [body]]
+      @env = env
+      @script_name = env['SCRIPT_NAME']
+      @path_info = Utils.unescape(env['PATH_INFO'])
+
+      if forbidden = check_forbidden
+        forbidden
+      else
+        @path = F.join(@root, @path_info)
+        list_path
+      end
+    end
+
+    def check_forbidden
+      return unless @path_info.include? &quot;..&quot;
+
+      body = &quot;Forbidden\n&quot;
+      size = body.respond_to?(:bytesize) ? body.bytesize : body.size
+      return [403, {&quot;Content-Type&quot; =&gt; &quot;text/plain&quot;,&quot;Content-Length&quot; =&gt; size.to_s}, [body]]
+    end
+
+    def list_directory
+      @files = [['../','Parent Directory','','','']]
+      glob = F.join(@path, '*')
+
+      Dir[glob].sort.each do |node|
+        stat = stat(node)
+        next  unless stat
+        basename = F.basename(node)
+        ext = F.extname(node)
+
+        url = F.join(@script_name, @path_info, basename)
+        size = stat.size
+        type = stat.directory? ? 'directory' : Mime.mime_type(ext)
+        size = stat.directory? ? '-' : filesize_format(size)
+        mtime = stat.mtime.httpdate
+
+        @files &lt;&lt; [ url, basename, size, type, mtime ]
       end
 
-      @path = F.join(@root, Utils.unescape(env['PATH_INFO']))
-
-      if F.exist?(@path) and F.readable?(@path)
-        if F.file?(@path)
-          return @app.call(env)
-        elsif F.directory?(@path)
-          @files = [['../','Parent Directory','','','']]
-          sName, pInfo = env.values_at('SCRIPT_NAME', 'PATH_INFO')
-          Dir.entries(@path).sort.each do |file|
-            next if file[0] == ?.
-            fl    = F.join(@path, file)
-            sz    = F.size(fl)
-            url   = F.join(sName, pInfo, file)
-            type  = F.directory?(fl) ? 'directory' :
-              MIME_TYPES.fetch(F.extname(file)[1..-1],'unknown')
-            size  = (type!='directory' ? (sz&lt;10240 ? &quot;#{sz}B&quot; : &quot;#{sz/1024}KB&quot;) : '-')
-            mtime = F.mtime(fl).httpdate
-            @files &lt;&lt; [ url, file, size, type, mtime ]
-          end
-          return [ 200, {'Content-Type'=&gt;'text/html'}, self ]
-        end
+      return [ 200, {'Content-Type'=&gt;'text/html; charset=utf-8'}, self ]
+    end
+
+    def stat(node, max = 10)
+      F.stat(node)
+    rescue Errno::ENOENT, Errno::ELOOP
+      return nil
+    end
+
+    # TODO: add correct response if not readable, not sure if 404 is the best
+    #       option
+    def list_path
+      @stat = F.stat(@path)
+
+      if @stat.readable?
+        return @app.call(@env) if @stat.file?
+        return list_directory if @stat.directory?
+      else
+        raise Errno::ENOENT, 'No such file or directory'
       end
 
-      body = &quot;Entity not found: #{env[&quot;PATH_INFO&quot;]}\n&quot;
+    rescue Errno::ENOENT, Errno::ELOOP
+      return entity_not_found
+    end
+
+    def entity_not_found
+      body = &quot;Entity not found: #{@path_info}\n&quot;
       size = body.respond_to?(:bytesize) ? body.bytesize : body.size
       return [404, {&quot;Content-Type&quot; =&gt; &quot;text/plain&quot;, &quot;Content-Length&quot; =&gt; size.to_s}, [body]]
     end
@@ -93,66 +130,21 @@ table { width:100%%; }
       page.each_line{|l| yield l }
     end
 
-    def each_entry
-      @files.each{|e| yield e }
-    end
+    # Stolen from Ramaze
+
+    FILESIZE_FORMAT = [
+      ['%.1fT', 1 &lt;&lt; 40],
+      ['%.1fG', 1 &lt;&lt; 30],
+      ['%.1fM', 1 &lt;&lt; 20],
+      ['%.1fK', 1 &lt;&lt; 10],
+    ]
 
-    # From WEBrick.
-    MIME_TYPES = {
-      &quot;ai&quot;    =&gt; &quot;application/postscript&quot;,
-      &quot;asc&quot;   =&gt; &quot;text/plain&quot;,
-      &quot;avi&quot;   =&gt; &quot;video/x-msvideo&quot;,
-      &quot;bin&quot;   =&gt; &quot;application/octet-stream&quot;,
-      &quot;bmp&quot;   =&gt; &quot;image/bmp&quot;,
-      &quot;class&quot; =&gt; &quot;application/octet-stream&quot;,
-      &quot;cer&quot;   =&gt; &quot;application/pkix-cert&quot;,
-      &quot;crl&quot;   =&gt; &quot;application/pkix-crl&quot;,
-      &quot;crt&quot;   =&gt; &quot;application/x-x509-ca-cert&quot;,
-     #&quot;crl&quot;   =&gt; &quot;application/x-pkcs7-crl&quot;,
-      &quot;css&quot;   =&gt; &quot;text/css&quot;,
-      &quot;dms&quot;   =&gt; &quot;application/octet-stream&quot;,
-      &quot;doc&quot;   =&gt; &quot;application/msword&quot;,
-      &quot;dvi&quot;   =&gt; &quot;application/x-dvi&quot;,
-      &quot;eps&quot;   =&gt; &quot;application/postscript&quot;,
-      &quot;etx&quot;   =&gt; &quot;text/x-setext&quot;,
-      &quot;exe&quot;   =&gt; &quot;application/octet-stream&quot;,
-      &quot;gif&quot;   =&gt; &quot;image/gif&quot;,
-      &quot;htm&quot;   =&gt; &quot;text/html&quot;,
-      &quot;html&quot;  =&gt; &quot;text/html&quot;,
-      &quot;jpe&quot;   =&gt; &quot;image/jpeg&quot;,
-      &quot;jpeg&quot;  =&gt; &quot;image/jpeg&quot;,
-      &quot;jpg&quot;   =&gt; &quot;image/jpeg&quot;,
-      &quot;js&quot;    =&gt; &quot;text/javascript&quot;,
-      &quot;lha&quot;   =&gt; &quot;application/octet-stream&quot;,
-      &quot;lzh&quot;   =&gt; &quot;application/octet-stream&quot;,
-      &quot;mov&quot;   =&gt; &quot;video/quicktime&quot;,
-      &quot;mpe&quot;   =&gt; &quot;video/mpeg&quot;,
-      &quot;mpeg&quot;  =&gt; &quot;video/mpeg&quot;,
-      &quot;mpg&quot;   =&gt; &quot;video/mpeg&quot;,
-      &quot;pbm&quot;   =&gt; &quot;image/x-portable-bitmap&quot;,
-      &quot;pdf&quot;   =&gt; &quot;application/pdf&quot;,
-      &quot;pgm&quot;   =&gt; &quot;image/x-portable-graymap&quot;,
-      &quot;png&quot;   =&gt; &quot;image/png&quot;,
-      &quot;pnm&quot;   =&gt; &quot;image/x-portable-anymap&quot;,
-      &quot;ppm&quot;   =&gt; &quot;image/x-portable-pixmap&quot;,
-      &quot;ppt&quot;   =&gt; &quot;application/vnd.ms-powerpoint&quot;,
-      &quot;ps&quot;    =&gt; &quot;application/postscript&quot;,
-      &quot;qt&quot;    =&gt; &quot;video/quicktime&quot;,
-      &quot;ras&quot;   =&gt; &quot;image/x-cmu-raster&quot;,
-      &quot;rb&quot;    =&gt; &quot;text/plain&quot;,
-      &quot;rd&quot;    =&gt; &quot;text/plain&quot;,
-      &quot;rtf&quot;   =&gt; &quot;application/rtf&quot;,
-      &quot;sgm&quot;   =&gt; &quot;text/sgml&quot;,
-      &quot;sgml&quot;  =&gt; &quot;text/sgml&quot;,
-      &quot;tif&quot;   =&gt; &quot;image/tiff&quot;,
-      &quot;tiff&quot;  =&gt; &quot;image/tiff&quot;,
-      &quot;txt&quot;   =&gt; &quot;text/plain&quot;,
-      &quot;xbm&quot;   =&gt; &quot;image/x-xbitmap&quot;,
-      &quot;xls&quot;   =&gt; &quot;application/vnd.ms-excel&quot;,
-      &quot;xml&quot;   =&gt; &quot;text/xml&quot;,
-      &quot;xpm&quot;   =&gt; &quot;image/x-xpixmap&quot;,
-      &quot;xwd&quot;   =&gt; &quot;image/x-xwindowdump&quot;,
-      &quot;zip&quot;   =&gt; &quot;application/zip&quot;,
-    }
+    def filesize_format(int)
+      FILESIZE_FORMAT.each do |format, size|
+        return format % (int.to_f / size) if int &gt;= size
+      end
+
+      int.to_s + 'B'
+    end
   end
 end</diff>
      <filename>vendor/rack/lib/rack/directory.rb</filename>
    </modified>
    <modified>
      <diff>@@ -1,4 +1,5 @@
 require 'time'
+require 'rack/mime'
 
 module Rack
   # Rack::File serves files below the +root+ given, according to the
@@ -22,26 +23,55 @@ module Rack
     F = ::File
 
     def _call(env)
-      if env[&quot;PATH_INFO&quot;].include? &quot;..&quot;
-        body = &quot;Forbidden\n&quot;
-        size = body.respond_to?(:bytesize) ? body.bytesize : body.size
-        return [403, {&quot;Content-Type&quot; =&gt; &quot;text/plain&quot;,&quot;Content-Length&quot; =&gt; size.to_s}, [body]]
+      @path_info = Utils.unescape(env[&quot;PATH_INFO&quot;])
+      return forbidden  if @path_info.include? &quot;..&quot;
+
+      @path = F.join(@root, @path_info)
+
+      begin
+        if F.file?(@path) &amp;&amp; F.readable?(@path)
+          serving
+        else
+          raise Errno::EPERM
+        end
+      rescue SystemCallError
+        not_found
       end
+    end
+
+    def forbidden
+      body = &quot;Forbidden\n&quot;
+      [403, {&quot;Content-Type&quot; =&gt; &quot;text/plain&quot;,
+             &quot;Content-Length&quot; =&gt; body.size.to_s},
+       [body]]
+    end
 
-      @path = F.join(@root, Utils.unescape(env[&quot;PATH_INFO&quot;]))
-      ext = F.extname(@path)[1..-1]
+    # NOTE:
+    #   We check via File::size? whether this file provides size info
+    #   via stat (e.g. /proc files often don't), otherwise we have to
+    #   figure it out by reading the whole file into memory. And while
+    #   we're at it we also use this as body then.
 
-      if F.file?(@path) &amp;&amp; F.readable?(@path)
-        [200, {
-           &quot;Last-Modified&quot;  =&gt; F.mtime(@path).httpdate,
-           &quot;Content-Type&quot;   =&gt; MIME_TYPES[ext] || &quot;text/plain&quot;,
-           &quot;Content-Length&quot; =&gt; F.size(@path).to_s
-         }, self]
+    def serving
+      if size = F.size?(@path)
+        body = self
       else
-        body = &quot;File not found: #{env[&quot;PATH_INFO&quot;]}\n&quot;
-        size = body.respond_to?(:bytesize) ? body.bytesize : body.size
-        [404, {&quot;Content-Type&quot; =&gt; &quot;text/plain&quot;, &quot;Content-Length&quot; =&gt; size.to_s}, [body]]
+        body = [F.read(@path)]
+        size = body.first.size
       end
+
+      [200, {
+        &quot;Last-Modified&quot;  =&gt; F.mtime(@path).httpdate,
+        &quot;Content-Type&quot;   =&gt; Mime.mime_type(F.extname(@path), 'text/plain'),
+        &quot;Content-Length&quot; =&gt; size.to_s
+      }, body]
+    end
+
+    def not_found
+      body = &quot;File not found: #{@path_info}\n&quot;
+      [404, {&quot;Content-Type&quot; =&gt; &quot;text/plain&quot;,
+         &quot;Content-Length&quot; =&gt; body.size.to_s},
+       [body]]
     end
 
     def each
@@ -51,66 +81,5 @@ module Rack
         end
       }
     end
-
-    # :stopdoc:
-    # From WEBrick with some additions.
-    MIME_TYPES = {
-      &quot;ai&quot;    =&gt; &quot;application/postscript&quot;,
-      &quot;asc&quot;   =&gt; &quot;text/plain&quot;,
-      &quot;avi&quot;   =&gt; &quot;video/x-msvideo&quot;,
-      &quot;bin&quot;   =&gt; &quot;application/octet-stream&quot;,
-      &quot;bmp&quot;   =&gt; &quot;image/bmp&quot;,
-      &quot;class&quot; =&gt; &quot;application/octet-stream&quot;,
-      &quot;cer&quot;   =&gt; &quot;application/pkix-cert&quot;,
-      &quot;crl&quot;   =&gt; &quot;application/pkix-crl&quot;,
-      &quot;crt&quot;   =&gt; &quot;application/x-x509-ca-cert&quot;,
-     #&quot;crl&quot;   =&gt; &quot;application/x-pkcs7-crl&quot;,
-      &quot;css&quot;   =&gt; &quot;text/css&quot;,
-      &quot;dms&quot;   =&gt; &quot;application/octet-stream&quot;,
-      &quot;doc&quot;   =&gt; &quot;application/msword&quot;,
-      &quot;dvi&quot;   =&gt; &quot;application/x-dvi&quot;,
-      &quot;eps&quot;   =&gt; &quot;application/postscript&quot;,
-      &quot;etx&quot;   =&gt; &quot;text/x-setext&quot;,
-      &quot;exe&quot;   =&gt; &quot;application/octet-stream&quot;,
-      &quot;gif&quot;   =&gt; &quot;image/gif&quot;,
-      &quot;htm&quot;   =&gt; &quot;text/html&quot;,
-      &quot;html&quot;  =&gt; &quot;text/html&quot;,
-      &quot;jpe&quot;   =&gt; &quot;image/jpeg&quot;,
-      &quot;jpeg&quot;  =&gt; &quot;image/jpeg&quot;,
-      &quot;jpg&quot;   =&gt; &quot;image/jpeg&quot;,
-      &quot;js&quot;    =&gt; &quot;text/javascript&quot;,
-      &quot;lha&quot;   =&gt; &quot;application/octet-stream&quot;,
-      &quot;lzh&quot;   =&gt; &quot;application/octet-stream&quot;,
-      &quot;mov&quot;   =&gt; &quot;video/quicktime&quot;,
-      &quot;mp3&quot;   =&gt; &quot;audio/mpeg&quot;,
-      &quot;mpe&quot;   =&gt; &quot;video/mpeg&quot;,
-      &quot;mpeg&quot;  =&gt; &quot;video/mpeg&quot;,
-      &quot;mpg&quot;   =&gt; &quot;video/mpeg&quot;,
-      &quot;pbm&quot;   =&gt; &quot;image/x-portable-bitmap&quot;,
-      &quot;pdf&quot;   =&gt; &quot;application/pdf&quot;,
-      &quot;pgm&quot;   =&gt; &quot;image/x-portable-graymap&quot;,
-      &quot;png&quot;   =&gt; &quot;image/png&quot;,
-      &quot;pnm&quot;   =&gt; &quot;image/x-portable-anymap&quot;,
-      &quot;ppm&quot;   =&gt; &quot;image/x-portable-pixmap&quot;,
-      &quot;ppt&quot;   =&gt; &quot;application/vnd.ms-powerpoint&quot;,
-      &quot;ps&quot;    =&gt; &quot;application/postscript&quot;,
-      &quot;qt&quot;    =&gt; &quot;video/quicktime&quot;,
-      &quot;ras&quot;   =&gt; &quot;image/x-cmu-raster&quot;,
-      &quot;rb&quot;    =&gt; &quot;text/plain&quot;,
-      &quot;rd&quot;    =&gt; &quot;text/plain&quot;,
-      &quot;rtf&quot;   =&gt; &quot;application/rtf&quot;,
-      &quot;sgm&quot;   =&gt; &quot;text/sgml&quot;,
-      &quot;sgml&quot;  =&gt; &quot;text/sgml&quot;,
-      &quot;tif&quot;   =&gt; &quot;image/tiff&quot;,
-      &quot;tiff&quot;  =&gt; &quot;image/tiff&quot;,
-      &quot;txt&quot;   =&gt; &quot;text/plain&quot;,
-      &quot;xbm&quot;   =&gt; &quot;image/x-xbitmap&quot;,
-      &quot;xls&quot;   =&gt; &quot;application/vnd.ms-excel&quot;,
-      &quot;xml&quot;   =&gt; &quot;text/xml&quot;,
-      &quot;xpm&quot;   =&gt; &quot;image/x-xpixmap&quot;,
-      &quot;xwd&quot;   =&gt; &quot;image/x-xwindowdump&quot;,
-      &quot;zip&quot;   =&gt; &quot;application/zip&quot;,
-    }
-    # :startdoc:
   end
 end</diff>
      <filename>vendor/rack/lib/rack/file.rb</filename>
    </modified>
    <modified>
      <diff>@@ -29,16 +29,20 @@ module Rack
     autoload :FastCGI, &quot;rack/handler/fastcgi&quot;
     autoload :Mongrel, &quot;rack/handler/mongrel&quot;
     autoload :EventedMongrel, &quot;rack/handler/evented_mongrel&quot;
+    autoload :SwiftipliedMongrel, &quot;rack/handler/swiftiplied_mongrel&quot;
     autoload :WEBrick, &quot;rack/handler/webrick&quot;
     autoload :LSWS, &quot;rack/handler/lsws&quot;
     autoload :SCGI, &quot;rack/handler/scgi&quot;
+    autoload :Thin, &quot;rack/handler/thin&quot;
 
     register 'cgi', 'Rack::Handler::CGI'
     register 'fastcgi', 'Rack::Handler::FastCGI'
     register 'mongrel', 'Rack::Handler::Mongrel'
     register 'emongrel', 'Rack::Handler::EventedMongrel'
+    register 'smongrel', 'Rack::Handler::SwiftipliedMongrel'
     register 'webrick', 'Rack::Handler::WEBrick'
     register 'lsws', 'Rack::Handler::LSWS'
     register 'scgi', 'Rack::Handler::SCGI'
+    register 'thin', 'Rack::Handler::Thin'
   end
 end</diff>
      <filename>vendor/rack/lib/rack/handler.rb</filename>
    </modified>
    <modified>
      <diff>@@ -2,7 +2,7 @@ require 'swiftcore/evented_mongrel'
 
 module Rack
   module Handler
-    class EventedMongrel &lt; Mongrel
+    class EventedMongrel &lt; Handler::Mongrel
     end
   end
 end</diff>
      <filename>vendor/rack/lib/rack/handler/evented_mongrel.rb</filename>
    </modified>
    <modified>
      <diff>@@ -51,6 +51,8 @@ module Rack
         env[&quot;HTTP_VERSION&quot;] ||= env[&quot;SERVER_PROTOCOL&quot;]
         env[&quot;REQUEST_PATH&quot;] ||= &quot;/&quot;
         env.delete &quot;PATH_INFO&quot;  if env[&quot;PATH_INFO&quot;] == &quot;&quot;
+        env.delete &quot;CONTENT_TYPE&quot;  if env[&quot;CONTENT_TYPE&quot;] == &quot;&quot;
+        env.delete &quot;CONTENT_LENGTH&quot;  if env[&quot;CONTENT_LENGTH&quot;] == &quot;&quot;
 
         status, headers, body = app.call(env)
         begin</diff>
      <filename>vendor/rack/lib/rack/handler/fastcgi.rb</filename>
    </modified>
    <modified>
      <diff>@@ -60,15 +60,19 @@ module Rack
 
         begin
           response.status = status.to_i
+          response.send_status(nil)
+
           headers.each { |k, vs|
             vs.each { |v|
               response.header[k] = v
             }
           }
+          response.send_header
+
           body.each { |part|
-            response.body &lt;&lt; part
+            response.write part
+            response.socket.flush
           }
-          response.finished
         ensure
           body.close  if body.respond_to? :close
         end</diff>
      <filename>vendor/rack/lib/rack/handler/mongrel.rb</filename>
    </modified>
    <modified>
      <diff>@@ -3,7 +3,7 @@ require 'stringio'
 
 module Rack
   module Handler
-    class WEBrick &lt; WEBrick::HTTPServlet::AbstractServlet
+    class WEBrick &lt; ::WEBrick::HTTPServlet::AbstractServlet
       def self.run(app, options={})
         server = ::WEBrick::HTTPServer.new(options)
         server.mount &quot;/&quot;, Rack::Handler::WEBrick, app
@@ -41,9 +41,13 @@ module Rack
         begin
           res.status = status.to_i
           headers.each { |k, vs|
-            vs.each { |v|
-              res[k] = v
-            }
+            if k.downcase == &quot;set-cookie&quot;
+              res.cookies.concat vs.to_a
+            else
+              vs.each { |v|
+                res[k] = v
+              }
+            end
           }
           body.each { |part|
             res.body &lt;&lt; part</diff>
      <filename>vendor/rack/lib/rack/handler/webrick.rb</filename>
    </modified>
    <modified>
      <diff>@@ -29,8 +29,8 @@ module Rack
 
     ## A Rack application is an Ruby object (not a class) that
     ## responds to +call+.
-    def call(env=nil) 
-      dup._call(env) 
+    def call(env=nil)
+      dup._call(env)
     end
 
     def _call(env)
@@ -49,6 +49,7 @@ module Rack
       check_headers headers
       ## and the *body*.
       check_content_type status, headers
+      check_content_length status, headers, env
       [status, headers, self]
     end
 
@@ -162,11 +163,9 @@ module Rack
       ## * There must be a valid error stream in &lt;tt&gt;rack.errors&lt;/tt&gt;.
       check_error env[&quot;rack.errors&quot;]
 
-      ## * The &lt;tt&gt;REQUEST_METHOD&lt;/tt&gt; must be one of +GET+, +POST+, +PUT+,
-      ##   +DELETE+, +HEAD+, +OPTIONS+, +TRACE+.
+      ## * The &lt;tt&gt;REQUEST_METHOD&lt;/tt&gt; must be a valid token.
       assert(&quot;REQUEST_METHOD unknown: #{env[&quot;REQUEST_METHOD&quot;]}&quot;) {
-        %w[GET POST PUT DELETE
-           HEAD OPTIONS TRACE].include?(env[&quot;REQUEST_METHOD&quot;])
+        env[&quot;REQUEST_METHOD&quot;] =~ /\A[0-9A-Za-z!\#$%&amp;'*+.^_`|~-]+\z/
       }
 
       ## * The &lt;tt&gt;SCRIPT_NAME&lt;/tt&gt;, if non-empty, must start with &lt;tt&gt;/&lt;/tt&gt;
@@ -215,6 +214,14 @@ module Rack
         @input = input
       end
 
+      def size
+        @input.size
+      end
+
+      def rewind
+        @input.rewind
+      end
+
       ## * +gets+ must be called without arguments and return a string,
       ##   or +nil+ on EOF.
       def gets(*args)
@@ -350,18 +357,75 @@ module Rack
     def check_content_type(status, headers)
       headers.each { |key, value|
         ## There must be a &lt;tt&gt;Content-Type&lt;/tt&gt;, except when the
-        ## +Status+ is 204 or 304, in which case there must be none
+        ## +Status+ is 1xx, 204 or 304, in which case there must be none
         ## given.
         if key.downcase == &quot;content-type&quot;
-          assert(&quot;Content-Type header found in #{status} response, not allowed&quot;){
-            not [204, 304].include? status.to_i
+          assert(&quot;Content-Type header found in #{status} response, not allowed&quot;) {
+            not Rack::Utils::STATUS_WITH_NO_ENTITY_BODY.include? status.to_i
           }
           return
         end
       }
       assert(&quot;No Content-Type header found&quot;) {
-        [204, 304].include? status.to_i
+        Rack::Utils::STATUS_WITH_NO_ENTITY_BODY.include? status.to_i
+      }
+    end
+
+    ## === The Content-Length
+    def check_content_length(status, headers, env)
+      chunked_response = false
+      headers.each { |key, value|
+        if key.downcase == 'transfer-encoding'
+          chunked_response = value.downcase != 'identity'
+        end
+      }
+
+      headers.each { |key, value|
+        if key.downcase == 'content-length'
+          ## There must be a &lt;tt&gt;Content-Length&lt;/tt&gt;, except when the
+          ## +Status+ is 1xx, 204 or 304, in which case there must be none
+          ## given.
+          assert(&quot;Content-Length header found in #{status} response, not allowed&quot;) {
+            not Rack::Utils::STATUS_WITH_NO_ENTITY_BODY.include? status.to_i
+          }
+
+          assert('Content-Length header should not be used if body is chunked') {
+            not chunked_response
+          }
+
+          bytes = 0
+          string_body = true
+
+          @body.each { |part|
+            unless part.kind_of?(String)
+              string_body = false
+              break
+            end
+
+            bytes += (part.respond_to?(:bytesize) ? part.bytesize : part.size)
+          }
+
+          if env[&quot;REQUEST_METHOD&quot;] == &quot;HEAD&quot;
+            assert(&quot;Response body was given for HEAD request, but should be empty&quot;) {
+              bytes == 0
+            }
+          else
+            if string_body
+              assert(&quot;Content-Length header was #{value}, but should be #{bytes}&quot;) {
+                value == bytes.to_s
+              }
+            end
+          end
+
+          return
+        end
       }
+
+      if [ String, Array ].include?(@body.class) &amp;&amp; !chunked_response
+        assert('No Content-Length header found') {
+          Rack::Utils::STATUS_WITH_NO_ENTITY_BODY.include? status.to_i
+        }
+      end
     end
 
     ## === The Body</diff>
      <filename>vendor/rack/lib/rack/lint.rb</filename>
    </modified>
    <modified>
      <diff>@@ -22,11 +22,11 @@ module Rack
         href = &quot;?flip&quot;
       end
 
-      [200, {&quot;Content-Type&quot; =&gt; &quot;text/html&quot;},
-       [&quot;&lt;title&gt;Lobstericious!&lt;/title&gt;&quot;,
-        &quot;&lt;pre&gt;&quot;, lobster, &quot;&lt;/pre&gt;&quot;,
-        &quot;&lt;a href='#{href}'&gt;flip!&lt;/a&gt;&quot;]
-      ]
+      content = [&quot;&lt;title&gt;Lobstericious!&lt;/title&gt;&quot;,
+                 &quot;&lt;pre&gt;&quot;, lobster, &quot;&lt;/pre&gt;&quot;,
+                 &quot;&lt;a href='#{href}'&gt;flip!&lt;/a&gt;&quot;]
+      length = content.inject(0) { |a,e| a+e.size }.to_s
+      [200, {&quot;Content-Type&quot; =&gt; &quot;text/html&quot;, &quot;Content-Length&quot; =&gt; length}, content]
     }
 
     def call(env)
@@ -43,14 +43,14 @@ module Rack
         href = &quot;?flip=left&quot;
       end
 
-      Response.new.finish do |res|
-        res.write &quot;&lt;title&gt;Lobstericious!&lt;/title&gt;&quot;
-        res.write &quot;&lt;pre&gt;&quot;
-        res.write lobster
-        res.write &quot;&lt;/pre&gt;&quot;
-        res.write &quot;&lt;p&gt;&lt;a href='#{href}'&gt;flip!&lt;/a&gt;&lt;/p&gt;&quot;
-        res.write &quot;&lt;p&gt;&lt;a href='?flip=crash'&gt;crash!&lt;/a&gt;&lt;/p&gt;&quot;
-      end
+      res = Response.new
+      res.write &quot;&lt;title&gt;Lobstericious!&lt;/title&gt;&quot;
+      res.write &quot;&lt;pre&gt;&quot;
+      res.write lobster
+      res.write &quot;&lt;/pre&gt;&quot;
+      res.write &quot;&lt;p&gt;&lt;a href='#{href}'&gt;flip!&lt;/a&gt;&lt;/p&gt;&quot;
+      res.write &quot;&lt;p&gt;&lt;a href='?flip=crash'&gt;crash!&lt;/a&gt;&lt;/p&gt;&quot;
+      res.finish
     end
 
   end</diff>
      <filename>vendor/rack/lib/rack/lobster.rb</filename>
    </modified>
    <modified>
      <diff>@@ -123,7 +123,7 @@ module Rack
       }
 
       @body = &quot;&quot;
-      body.each { |part| @body &lt;&lt; part.to_s }
+      body.each { |part| @body &lt;&lt; part }
 
       @errors = errors.string
     end</diff>
      <filename>vendor/rack/lib/rack/mock.rb</filename>
    </modified>
    <modified>
      <diff>@@ -113,6 +113,7 @@ module Rack
             Utils::Multipart.parse_multipart(env)
           @env[&quot;rack.request.form_vars&quot;] = @env[&quot;rack.input&quot;].read
           @env[&quot;rack.request.form_hash&quot;] = Utils.parse_query(@env[&quot;rack.request.form_vars&quot;])
+          @env[&quot;rack.input&quot;].rewind if @env[&quot;rack.input&quot;].respond_to?(:rewind)
         end
         @env[&quot;rack.request.form_hash&quot;]
       else
@@ -122,7 +123,7 @@ module Rack
 
     # The union of GET and POST data.
     def params
-      self.GET.update(self.POST)
+      self.put? ? self.GET : self.GET.update(self.POST)
     rescue EOFError =&gt; e
       self.GET
     end
@@ -205,5 +206,13 @@ module Rack
         end
       end
     end
+
+    def ip
+      if addr = @env['HTTP_X_FORWARDED_FOR']
+        addr.split(',').last.strip
+      else
+        @env['REMOTE_ADDR']
+      end
+    end
   end
 end</diff>
      <filename>vendor/rack/lib/rack/request.rb</filename>
    </modified>
    <modified>
      <diff>@@ -23,6 +23,7 @@ module Rack
 
       @writer = lambda { |x| @body &lt;&lt; x }
       @block = nil
+      @length = 0
 
       @body = []
 
@@ -59,12 +60,13 @@ module Rack
         # N.B.: cgi.rb uses spaces...
         expires = &quot;; expires=&quot; + value[:expires].clone.gmtime.
           strftime(&quot;%a, %d-%b-%Y %H:%M:%S GMT&quot;)    if value[:expires]
+        secure = &quot;; secure&quot;  if value[:secure]
         value = value[:value]
       end
       value = [value]  unless Array === value
       cookie = Utils.escape(key) + &quot;=&quot; +
         value.map { |v| Utils.escape v }.join(&quot;&amp;&quot;) +
-        &quot;#{domain}#{path}#{expires}&quot;
+        &quot;#{domain}#{path}#{expires}#{secure}&quot;
 
       case self[&quot;Set-Cookie&quot;]
       when Array
@@ -98,6 +100,7 @@ module Rack
         header.delete &quot;Content-Type&quot;
         [status.to_i, header.to_hash, []]
       else
+        header[&quot;Content-Length&quot;] ||= @length.to_s
         [status.to_i, header.to_hash, self]
       end
     end
@@ -110,7 +113,9 @@ module Rack
     end
 
     def write(str)
-      @writer.call str.to_s
+      s = str.to_s
+      @length += s.size
+      @writer.call s
       str
     end
 </diff>
      <filename>vendor/rack/lib/rack/response.rb</filename>
    </modified>
    <modified>
      <diff>@@ -26,7 +26,10 @@ module Rack
           :key =&gt;           'rack.session',
           :path =&gt;          '/',
           :domain =&gt;        nil,
-          :expire_after =&gt;  nil
+          :expire_after =&gt;  nil,
+          :secure =&gt;        false,
+          :httponly =&gt;      true,
+          :sidbits =&gt;       128
         }
 
         def initialize(app, options={})
@@ -50,6 +53,14 @@ module Rack
 
         private
 
+        # Generate a new session id using Ruby #rand.  The size of the
+        # session id is controlled by the :sidbits option.
+        # Monkey patch this to use custom methods for session id generation.
+        def generate_sid
+          &quot;%0#{@default_options[:sidbits] / 4}x&quot; %
+            rand(2**@default_options[:sidbits] - 1)
+        end
+
         # Extracts the session id from provided cookies and passes it and the
         # environment to #get_session. It then sets the resulting session into
         # 'rack.session', and places options and session metadata into
@@ -110,6 +121,8 @@ module Rack
             expiry = time + options[:expire_after]
             cookie&lt;&lt; &quot;; expires=#{expiry.httpdate}&quot;
           end
+          cookie&lt;&lt; &quot;; Secure&quot; if options[:secure]
+          cookie&lt;&lt; &quot;; HttpOnly&quot; if options[:httponly]
 
           case a = (h = response[1])['Set-Cookie']
           when Array then  a &lt;&lt; cookie</diff>
      <filename>vendor/rack/lib/rack/session/abstract/id.rb</filename>
    </modified>
    <modified>
      <diff>@@ -1,3 +1,5 @@
+require 'openssl'
+
 module Rack
 
   module Session
@@ -5,13 +7,15 @@ module Rack
     # Rack::Session::Cookie provides simple cookie based session management.
     # The session is a Ruby Hash stored as base64 encoded marshalled data
     # set to :key (default: rack.session).
+    # When the secret key is set, cookie data is checked for data integrity.
     #
     # Example:
     #
     #     use Rack::Session::Cookie, :key =&gt; 'rack.session',
     #                                :domain =&gt; 'foo.com',
     #                                :path =&gt; '/',
-    #                                :expire_after =&gt; 2592000
+    #                                :expire_after =&gt; 2592000,
+    #                                :secret =&gt; 'change_me'
     #
     #     All parameters are optional.
 
@@ -20,6 +24,7 @@ module Rack
       def initialize(app, options={})
         @app = app
         @key = options[:key] || &quot;rack.session&quot;
+        @secret = options[:secret]
         @default_options = {:domain =&gt; nil,
           :path =&gt; &quot;/&quot;,
           :expire_after =&gt; nil}.merge(options)
@@ -37,6 +42,11 @@ module Rack
         request = Rack::Request.new(env)
         session_data = request.cookies[@key]
 
+        if @secret &amp;&amp; session_data
+          session_data, digest = session_data.split(&quot;--&quot;)
+          session_data = nil  unless digest == generate_hmac(session_data)
+        end
+
         begin
           session_data = session_data.unpack(&quot;m*&quot;).first
           session_data = Marshal.load(session_data)
@@ -52,6 +62,10 @@ module Rack
         session_data = Marshal.dump(env[&quot;rack.session&quot;])
         session_data = [session_data].pack(&quot;m*&quot;)
 
+        if @secret
+          session_data = &quot;#{session_data}--#{generate_hmac(session_data)}&quot;
+        end
+
         if session_data.size &gt; (4096 - @key.size)
           env[&quot;rack.errors&quot;].puts(&quot;Warning! Rack::Session::Cookie data size exceeds 4K. Content dropped.&quot;)
           [status, headers, body]
@@ -66,6 +80,10 @@ module Rack
         end
       end
 
+      def generate_hmac(data)
+        OpenSSL::HMAC.hexdigest(OpenSSL::Digest::SHA1.new, @secret, data)
+      end
+
     end
   end
 end</diff>
      <filename>vendor/rack/lib/rack/session/cookie.rb</filename>
    </modified>
    <modified>
      <diff>@@ -45,7 +45,7 @@ module Rack
           @mutex.synchronize do
             begin
               raise RuntimeError, 'Unique id finding looping excessively' if (lc+=1) &gt; 1000
-              sid = &quot;%08x&quot; % rand(0xffffffff)
+              sid = generate_sid
               ret = @pool.add(sid, session)
             end until /^STORED/ =~ ret
           end</diff>
      <filename>vendor/rack/lib/rack/session/memcache.rb</filename>
    </modified>
    <modified>
      <diff>@@ -40,7 +40,7 @@ module Rack
           unless sess = @pool[sid] and ((expires = sess[:expire_at]).nil? or expires &gt; Time.now)
             @pool.delete_if{|k,v| expiry = v[:expire_at] and expiry &lt; Time.now }
             begin
-              sid = &quot;%08x&quot; % rand(0xffffffff)
+              sid = generate_sid
             end while @pool.has_key?(sid)
           end
           @pool[sid] ||= {}</diff>
      <filename>vendor/rack/lib/rack/session/pool.rb</filename>
    </modified>
    <modified>
      <diff>@@ -22,7 +22,11 @@ module Rack
     def call(env)
       @app.call(env)
     rescue StandardError, LoadError, SyntaxError =&gt; e
-      [500, {&quot;Content-Type&quot; =&gt; &quot;text/html&quot;}, pretty(env, e)]
+      backtrace = pretty(env, e)
+      [500,
+       {&quot;Content-Type&quot; =&gt; &quot;text/html&quot;,
+        &quot;Content-Length&quot; =&gt; backtrace.join.size.to_s},
+       backtrace]
     end
 
     def pretty(env, exception)</diff>
      <filename>vendor/rack/lib/rack/showexceptions.rb</filename>
    </modified>
    <modified>
      <diff>@@ -18,10 +18,11 @@ module Rack
 
     def call(env)
       status, headers, body = @app.call(env)
+      headers = Utils::HeaderHash.new(headers)
+      empty = headers['Content-Length'].to_i &lt;= 0
 
       # client or server error, or explicit message
-      if status.to_i &gt;= 400 &amp;&amp;
-          (body.empty? rescue false) || env[&quot;rack.showstatus.detail&quot;]
+      if (status.to_i &gt;= 400 &amp;&amp; empty) || env[&quot;rack.showstatus.detail&quot;]
         req = Rack::Request.new(env)
         message = Rack::Utils::HTTP_STATUS_CODES[status.to_i] || status.to_s
         detail = env[&quot;rack.showstatus.detail&quot;] || message</diff>
      <filename>vendor/rack/lib/rack/showstatus.rb</filename>
    </modified>
    <modified>
      <diff>@@ -26,7 +26,7 @@ module Rack
         location = location.chomp('/')
 
         [host, location, app]
-      }.sort_by { |(h, l, a)| -l.size }  # Longest path first
+      }.sort_by { |(h, l, a)| [-l.size, h.to_s.size] }  # Longest path first
     end
 
     def call(env)</diff>
      <filename>vendor/rack/lib/rack/urlmap.rb</filename>
    </modified>
    <modified>
      <diff>@@ -1,3 +1,4 @@
+require 'set'
 require 'tempfile'
 
 module Rack
@@ -31,10 +32,10 @@ module Rack
 
     def parse_query(qs, d = '&amp;;')
       params = {}
-      
+
       (qs || '').split(/[#{d}] */n).each do |p|
         k, v = unescape(p).split('=', 2)
-        
+
         if cur = params[k]
           if cur.class == Array
             params[k] &lt;&lt; v
@@ -45,11 +46,11 @@ module Rack
           params[k] = v
         end
       end
-      
+
       return params
     end
     module_function :parse_query
-    
+
     def build_query(params)
       params.map { |k, v|
         if v.class == Array
@@ -155,9 +156,11 @@ module Rack
       end
     end
 
-    # A case-normalizing Hash, adjusting on [] and []=.
+    # A case-insensitive Hash that preserves the original case of a
+    # header when set.
     class HeaderHash &lt; Hash
       def initialize(hash={})
+        @names = {}
         hash.each { |k, v| self[k] = v }
       end
 
@@ -166,15 +169,35 @@ module Rack
       end
 
       def [](k)
-        super capitalize(k)
+        super @names[k.downcase]
       end
 
       def []=(k, v)
-        super capitalize(k), v
+        delete k
+        @names[k.downcase] = k
+        super k, v
+      end
+
+      def delete(k)
+        super @names.delete(k.downcase)
       end
 
-      def capitalize(k)
-        k.to_s.downcase.gsub(/^.|[-_\s]./) { |x| x.upcase }
+      def include?(k)
+        @names.has_key? k.downcase
+      end
+
+      alias_method :has_key?, :include?
+      alias_method :member?, :include?
+      alias_method :key?, :include?
+
+      def merge!(other)
+        other.each { |k, v| self[k] = v }
+        self
+      end
+
+      def merge(other)
+        hash = dup
+        hash.merge! other
       end
     end
 
@@ -192,10 +215,11 @@ module Rack
       206  =&gt; 'Partial Content',
       300  =&gt; 'Multiple Choices',
       301  =&gt; 'Moved Permanently',
-      302  =&gt; 'Moved Temporarily',
+      302  =&gt; 'Found',
       303  =&gt; 'See Other',
       304  =&gt; 'Not Modified',
       305  =&gt; 'Use Proxy',
+      307  =&gt; 'Temporary Redirect',
       400  =&gt; 'Bad Request',
       401  =&gt; 'Unauthorized',
       402  =&gt; 'Payment Required',
@@ -204,7 +228,7 @@ module Rack
       405  =&gt; 'Method Not Allowed',
       406  =&gt; 'Not Acceptable',
       407  =&gt; 'Proxy Authentication Required',
-      408  =&gt; 'Request Time-out',
+      408  =&gt; 'Request Timeout',
       409  =&gt; 'Conflict',
       410  =&gt; 'Gone',
       411  =&gt; 'Length Required',
@@ -212,14 +236,19 @@ module Rack
       413  =&gt; 'Request Entity Too Large',
       414  =&gt; 'Request-URI Too Large',
       415  =&gt; 'Unsupported Media Type',
+      416  =&gt; 'Requested Range Not Satisfiable',
+      417  =&gt; 'Expectation Failed',
       500  =&gt; 'Internal Server Error',
       501  =&gt; 'Not Implemented',
       502  =&gt; 'Bad Gateway',
       503  =&gt; 'Service Unavailable',
-      504  =&gt; 'Gateway Time-out',
-      505  =&gt; 'HTTP Version not supported'
+      504  =&gt; 'Gateway Timeout',
+      505  =&gt; 'HTTP Version Not Supported'
     }
 
+    # Responses with HTTP status codes that should not have an entity body
+    STATUS_WITH_NO_ENTITY_BODY = Set.new((100..199).to_a &lt;&lt; 204 &lt;&lt; 304)
+
     # A multipart form data parser, adapted from IOWA.
     #
     # Usually, Rack::Request#POST takes care of calling this.</diff>
      <filename>vendor/rack/lib/rack/utils.rb</filename>
    </modified>
    <modified>
      <diff>@@ -3,7 +3,7 @@ server.document-root = &quot;.&quot;
 server.errorlog = &quot;lighttpd.errors&quot;
 server.port = 9203
 
-server.event-handler = &quot;freebsd-kqueue&quot;
+server.event-handler = &quot;select&quot;
 
 cgi.assign = (&quot;/test&quot; =&gt; &quot;&quot;,
 #              &quot;.ru&quot; =&gt; &quot;&quot;</diff>
      <filename>vendor/rack/test/cgi/lighttpd.conf</filename>
    </modified>
    <modified>
      <filename>vendor/rack/test/cgi/test</filename>
    </modified>
    <modified>
      <filename>vendor/rack/test/cgi/test.fcgi</filename>
    </modified>
    <modified>
      <filename>vendor/rack/test/cgi/test.ru</filename>
    </modified>
    <modified>
      <diff>@@ -2,6 +2,8 @@ require 'test/spec'
 
 require 'rack/builder'
 require 'rack/mock'
+require 'rack/showexceptions'
+require 'rack/auth/basic'
 
 context &quot;Rack::Builder&quot; do
   specify &quot;chains apps by default&quot; do
@@ -47,4 +49,36 @@ context &quot;Rack::Builder&quot; do
     response.body.to_s.should.equal 'Hi Boss'
   end
 
+  specify &quot;has explicit #to_app&quot; do
+    app = Rack::Builder.app do
+      use Rack::ShowExceptions
+      run lambda { |env| raise &quot;bzzzt&quot; }
+    end
+
+    Rack::MockRequest.new(app).get(&quot;/&quot;).should.be.server_error
+    Rack::MockRequest.new(app).get(&quot;/&quot;).should.be.server_error
+    Rack::MockRequest.new(app).get(&quot;/&quot;).should.be.server_error
+  end
+
+  specify &quot;apps are initialized once&quot; do
+    app = Rack::Builder.new do
+      class AppClass
+        def initialize
+          @called = 0
+        end
+        def call(env)
+          raise &quot;bzzzt&quot;  if @called &gt; 0
+        @called += 1
+          [200, {'Content-Type' =&gt; 'text/plain'}, 'OK']
+        end
+      end
+
+      use Rack::ShowExceptions
+      run AppClass.new
+    end
+
+    Rack::MockRequest.new(app).get(&quot;/&quot;).status.should.equal 200
+    Rack::MockRequest.new(app).get(&quot;/&quot;).should.be.server_error
+  end
+
 end</diff>
      <filename>vendor/rack/test/spec_rack_builder.rb</filename>
    </modified>
    <modified>
      <diff>@@ -3,10 +3,11 @@ require 'test/spec'
 require 'rack/mock'
 require 'rack/deflater'
 require 'stringio'
+require 'time'  # for Time#httpdate
 
 context &quot;Rack::Deflater&quot; do
-  def build_response(body, accept_encoding, headers = {})
-    app = lambda { |env| [200, {}, body] }
+  def build_response(status, body, accept_encoding, headers = {})
+    app = lambda { |env| [status, {}, body] }
     request = Rack::MockRequest.env_for(&quot;&quot;, headers.merge(&quot;HTTP_ACCEPT_ENCODING&quot; =&gt; accept_encoding))
     response = Rack::Deflater.new(app).call(request)
 
@@ -17,19 +18,19 @@ context &quot;Rack::Deflater&quot; do
     body = Object.new
     class &lt;&lt; body; def each; yield(&quot;foo&quot;); yield(&quot;bar&quot;); end; end
 
-    response = build_response(body, &quot;deflate&quot;)
+    response = build_response(200, body, &quot;deflate&quot;)
 
     response[0].should.equal(200)
-    response[1].should.equal({ &quot;Content-Encoding&quot; =&gt; &quot;deflate&quot; })
+    response[1].should.equal({ &quot;Content-Encoding&quot; =&gt; &quot;deflate&quot;, &quot;Vary&quot; =&gt; &quot;Accept-Encoding&quot; })
     response[2].to_s.should.equal(&quot;K\313\317OJ,\002\000&quot;)
   end
 
   # TODO: This is really just a special case of the above...
   specify &quot;should be able to deflate String bodies&quot; do
-    response = build_response(&quot;Hello world!&quot;, &quot;deflate&quot;)
+    response = build_response(200, &quot;Hello world!&quot;, &quot;deflate&quot;)
 
     response[0].should.equal(200)
-    response[1].should.equal({ &quot;Content-Encoding&quot; =&gt; &quot;deflate&quot; })
+    response[1].should.equal({ &quot;Content-Encoding&quot; =&gt; &quot;deflate&quot;, &quot;Vary&quot; =&gt; &quot;Accept-Encoding&quot; })
     response[2].to_s.should.equal(&quot;\363H\315\311\311W(\317/\312IQ\004\000&quot;)
   end
 
@@ -37,10 +38,10 @@ context &quot;Rack::Deflater&quot; do
     body = Object.new
     class &lt;&lt; body; def each; yield(&quot;foo&quot;); yield(&quot;bar&quot;); end; end
 
-    response = build_response(body, &quot;gzip&quot;)
+    response = build_response(200, body, &quot;gzip&quot;)
 
     response[0].should.equal(200)
-    response[1].should.equal({ &quot;Content-Encoding&quot; =&gt; &quot;gzip&quot; })
+    response[1].should.equal({ &quot;Content-Encoding&quot; =&gt; &quot;gzip&quot;, &quot;Vary&quot; =&gt; &quot;Accept-Encoding&quot; })
 
     io = StringIO.new(response[2].to_s)
     gz = Zlib::GzipReader.new(io)
@@ -49,22 +50,56 @@ context &quot;Rack::Deflater&quot; do
   end
 
   specify &quot;should be able to fallback to no deflation&quot; do
-    response = build_response(&quot;Hello world!&quot;, &quot;superzip&quot;)
+    response = build_response(200, &quot;Hello world!&quot;, &quot;superzip&quot;)
 
     response[0].should.equal(200)
-    response[1].should.equal({})
+    response[1].should.equal({ &quot;Vary&quot; =&gt; &quot;Accept-Encoding&quot; })
     response[2].should.equal(&quot;Hello world!&quot;)
   end
 
+  specify &quot;should be able to skip when there is no response entity body&quot; do
+    response = build_response(304, [], &quot;gzip&quot;)
+
+    response[0].should.equal(304)
+    response[1].should.equal({})
+    response[2].should.equal([])
+  end
+
   specify &quot;should handle the lack of an acceptable encoding&quot; do
-    response1 = build_response(&quot;Hello world!&quot;, &quot;identity;q=0&quot;, &quot;PATH_INFO&quot; =&gt; &quot;/&quot;)
+    response1 = build_response(200, &quot;Hello world!&quot;, &quot;identity;q=0&quot;, &quot;PATH_INFO&quot; =&gt; &quot;/&quot;)
     response1[0].should.equal(406)
     response1[1].should.equal({&quot;Content-Type&quot; =&gt; &quot;text/plain&quot;})
-    response1[2].should.equal(&quot;An acceptable encoding for the requested resource / could not be found.&quot;)
+    response1[2].should.equal([&quot;An acceptable encoding for the requested resource / could not be found.&quot;])
 
-    response2 = build_response(&quot;Hello world!&quot;, &quot;identity;q=0&quot;, &quot;SCRIPT_NAME&quot; =&gt; &quot;/foo&quot;, &quot;PATH_INFO&quot; =&gt; &quot;/bar&quot;)
+    response2 = build_response(200, &quot;Hello world!&quot;, &quot;identity;q=0&quot;, &quot;SCRIPT_NAME&quot; =&gt; &quot;/foo&quot;, &quot;PATH_INFO&quot; =&gt; &quot;/bar&quot;)
     response2[0].should.equal(406)
     response2[1].should.equal({&quot;Content-Type&quot; =&gt; &quot;text/plain&quot;})
-    response2[2].should.equal(&quot;An acceptable encoding for the requested resource /foo/bar could not be found.&quot;)
+    response2[2].should.equal([&quot;An acceptable encoding for the requested resource /foo/bar could not be found.&quot;])
+  end
+
+  specify &quot;should handle gzip response with Last-Modified header&quot; do
+    last_modified = Time.now.httpdate
+
+    app = lambda { |env| [200, { &quot;Last-Modified&quot; =&gt; last_modified }, &quot;Hello World!&quot;] }
+    request = Rack::MockRequest.env_for(&quot;&quot;, &quot;HTTP_ACCEPT_ENCODING&quot; =&gt; &quot;gzip&quot;)
+    response = Rack::Deflater.new(app).call(request)
+
+    response[0].should.equal(200)
+    response[1].should.equal({ &quot;Content-Encoding&quot; =&gt; &quot;gzip&quot;, &quot;Vary&quot; =&gt; &quot;Accept-Encoding&quot;, &quot;Last-Modified&quot; =&gt; last_modified })
+
+    io = StringIO.new(response[2].to_s)
+    gz = Zlib::GzipReader.new(io)
+    gz.read.should.equal(&quot;Hello World!&quot;)
+    gz.close
+  end
+
+  specify &quot;should do nothing when no-transform Cache-Control directive present&quot; do
+    app = lambda { |env| [200, {'Cache-Control' =&gt; 'no-transform'}, ['Hello World!']] }
+    request = Rack::MockRequest.env_for(&quot;&quot;, &quot;HTTP_ACCEPT_ENCODING&quot; =&gt; &quot;gzip&quot;)
+    response = Rack::Deflater.new(app).call(request)
+
+    response[0].should.equal(200)
+    response[1].should.not.include &quot;Content-Encoding&quot;
+    response[2].join.should.equal(&quot;Hello World!&quot;)
   end
 end</diff>
      <filename>vendor/rack/test/spec_rack_deflater.rb</filename>
    </modified>
    <modified>
      <diff>@@ -45,6 +45,11 @@ context &quot;Rack::Directory&quot; do
       get(&quot;/cgi/../test&quot;)
 
     res.should.be.forbidden
+
+    res = Rack::MockRequest.new(Rack::Lint.new(app)).
+      get(&quot;/cgi/%2E%2E/test&quot;)
+
+    res.should.be.forbidden
   end
 
   specify &quot;404s if it can't find the file&quot; do</diff>
      <filename>vendor/rack/test/spec_rack_directory.rb</filename>
    </modified>
    <modified>
      <diff>@@ -41,10 +41,24 @@ context &quot;Rack::File&quot; do
     res.should.be.forbidden
   end
 
+  specify &quot;does not allow directory traversal with encoded periods&quot; do
+    res = Rack::MockRequest.new(Rack::Lint.new(Rack::File.new(DOCROOT))).
+      get(&quot;/%2E%2E/README&quot;)
+
+    res.should.be.forbidden
+  end
+
   specify &quot;404s if it can't find the file&quot; do
     res = Rack::MockRequest.new(Rack::Lint.new(Rack::File.new(DOCROOT))).
       get(&quot;/cgi/blubb&quot;)
 
     res.should.be.not_found
   end
+
+  specify &quot;detects SystemCallErrors&quot; do
+    res = Rack::MockRequest.new(Rack::Lint.new(Rack::File.new(DOCROOT))).
+      get(&quot;/cgi&quot;)
+
+    res.should.be.not_found
+  end
 end</diff>
      <filename>vendor/rack/test/spec_rack_file.rb</filename>
    </modified>
    <modified>
      <diff>@@ -2,10 +2,10 @@ require 'test/spec'
 
 require 'rack/handler'
 
-context &quot;Rack::Handler&quot; do
-  class Rack::Handler::Lobster; end
-  class RockLobster; end
+class Rack::Handler::Lobster; end
+class RockLobster; end
 
+context &quot;Rack::Handler&quot; do
   specify &quot;has registered default handlers&quot; do
     Rack::Handler.get('cgi').should.equal Rack::Handler::CGI
     Rack::Handler.get('fastcgi').should.equal Rack::Handler::FastCGI</diff>
      <filename>vendor/rack/test/spec_rack_handler.rb</filename>
    </modified>
    <modified>
      <diff>@@ -67,9 +67,9 @@ context &quot;Rack::Lint&quot; do
       message.should.match(/url_scheme unknown/)
 
     lambda {
-      Rack::Lint.new(nil).call(env(&quot;REQUEST_METHOD&quot; =&gt; &quot;FUCKUP&quot;))
+      Rack::Lint.new(nil).call(env(&quot;REQUEST_METHOD&quot; =&gt; &quot;FUCKUP?&quot;))
     }.should.raise(Rack::Lint::LintError).
-      message.should.match(/REQUEST_METHOD unknown/)
+      message.should.match(/REQUEST_METHOD/)
 
     lambda {
       Rack::Lint.new(nil).call(env(&quot;SCRIPT_NAME&quot; =&gt; &quot;howdy&quot;))
@@ -203,6 +203,47 @@ context &quot;Rack::Lint&quot; do
                      }).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, {&quot;Content-type&quot; =&gt; &quot;text/plain&quot;, &quot;Content-length&quot; =&gt; &quot;0&quot;}, &quot;&quot;]
+                       }).call(env({}))
+      }.should.raise(Rack::Lint::LintError).
+        message.should.match(/Content-Type header found/)
+    end
+  end
+
+  specify &quot;notices content-length errors&quot; do
+    lambda {
+      Rack::Lint.new(lambda { |env|
+                       [200, {&quot;Content-type&quot; =&gt; &quot;text/plain&quot;}, &quot;&quot;]
+                     }).call(env({}))
+    }.should.raise(Rack::Lint::LintError).
+      message.should.match(/No Content-Length/)
+
+    [100, 101, 204, 304].each do |status|
+      lambda {
+        Rack::Lint.new(lambda { |env|
+                         [status, {&quot;Content-length&quot; =&gt; &quot;0&quot;}, &quot;&quot;]
+                       }).call(env({}))
+      }.should.raise(Rack::Lint::LintError).
+        message.should.match(/Content-Length header found/)
+    end
+
+    lambda {
+      Rack::Lint.new(lambda { |env|
+                       [200, {&quot;Content-type&quot; =&gt; &quot;text/plain&quot;, &quot;Content-Length&quot; =&gt; &quot;0&quot;, &quot;Transfer-Encoding&quot; =&gt; &quot;chunked&quot;}, &quot;&quot;]
+                     }).call(env({}))
+    }.should.raise(Rack::Lint::LintError).
+      message.should.match(/Content-Length header should not be used/)
+
+    lambda {
+      Rack::Lint.new(lambda { |env|
+                       [200, {&quot;Content-type&quot; =&gt; &quot;text/plain&quot;, &quot;Content-Length&quot; =&gt; &quot;1&quot;}, &quot;&quot;]
+                     }).call(env({}))
+    }.should.raise(Rack::Lint::LintError).
+      message.should.match(/Content-Length header was 1, but should be 0/)
   end
 
   specify &quot;notices body errors&quot; do
@@ -300,4 +341,40 @@ context &quot;Rack::Lint&quot; do
       message.should.match(/close must not be called/)
   end
 
+  specify &quot;notices HEAD errors&quot; do
+    lambda {
+      Rack::Lint.new(lambda { |env|
+                       [200, {&quot;Content-type&quot; =&gt; &quot;test/plain&quot;, &quot;Content-length&quot; =&gt; &quot;3&quot;}, []]
+                     }).call(env({&quot;REQUEST_METHOD&quot; =&gt; &quot;HEAD&quot;}))
+    }.should.not.raise
+
+    lambda {
+      Rack::Lint.new(lambda { |env|
+                       [200, {&quot;Content-type&quot; =&gt; &quot;test/plain&quot;, &quot;Content-length&quot; =&gt; &quot;3&quot;}, &quot;foo&quot;]
+                     }).call(env({&quot;REQUEST_METHOD&quot; =&gt; &quot;HEAD&quot;}))
+    }.should.raise(Rack::Lint::LintError).
+      message.should.match(/body was given for HEAD/)
+  end
+end
+
+context &quot;Rack::Lint::InputWrapper&quot; do
+  specify &quot;delegates :size to underlying IO object&quot; do
+    class IOMock
+      def size
+        101
+      end
+    end
+
+    wrapper = Rack::Lint::InputWrapper.new(IOMock.new)
+    wrapper.size.should == 101
+  end
+
+  specify &quot;delegates :rewind to underlying IO object&quot; do
+    io = StringIO.new(&quot;123&quot;)
+    wrapper = Rack::Lint::InputWrapper.new(io)
+    wrapper.read.should == &quot;123&quot;
+    wrapper.read.should == &quot;&quot;
+    wrapper.rewind
+    wrapper.read.should == &quot;123&quot;
+  end
 end</diff>
      <filename>vendor/rack/test/spec_rack_lint.rb</filename>
    </modified>
    <modified>
      <diff>@@ -125,7 +125,7 @@ context &quot;Rack::MockResponse&quot; do
     res.original_headers[&quot;Content-Type&quot;].should.equal &quot;text/yaml&quot;
     res[&quot;Content-Type&quot;].should.equal &quot;text/yaml&quot;
     res.content_type.should.equal &quot;text/yaml&quot;
-    res.content_length.should.be.nil
+    res.content_length.should.be 381  # needs change often.
     res.location.should.be.nil
   end
 </diff>
      <filename>vendor/rack/test/spec_rack_mock.rb</filename>
    </modified>
    <modified>
      <diff>@@ -5,7 +5,8 @@ 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
@@ -17,6 +18,8 @@ context &quot;Rack::Handler::Mongrel&quot; 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
 
@@ -160,6 +163,22 @@ context &quot;Rack::Handler::Mongrel&quot; do
     block_ran.should.be true
   end
 
+  specify &quot;should stream #each part of the response&quot; 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 &lt;&lt; part }
+          end
+        end
+      end
+    rescue Timeout::Error
+    end
+    body.should.not.be.empty
+  end
+
   teardown do
     @acc.raise Mongrel::StopServer
   end</diff>
      <filename>vendor/rack/test/spec_rack_mongrel.rb</filename>
    </modified>
    <modified>
      <diff>@@ -83,6 +83,26 @@ context &quot;Rack::Request&quot; do
     req.body.read.should.equal &quot;foo=bar&amp;quux=bla&quot;
   end
 
+  specify &quot;rewinds input after parsing POST data&quot; do
+    input = StringIO.new(&quot;foo=bar&amp;quux=bla&quot;)
+    req = Rack::Request.new \
+      Rack::MockRequest.env_for(&quot;/&quot;,
+        &quot;CONTENT_TYPE&quot; =&gt; 'application/x-www-form-urlencoded;foo=bar',
+        :input =&gt; input)
+    req.params.should.equal &quot;foo&quot; =&gt; &quot;bar&quot;, &quot;quux&quot; =&gt; &quot;bla&quot;
+    input.read.should.equal &quot;foo=bar&amp;quux=bla&quot;
+  end
+
+  specify &quot;does not rewind unwindable CGI input&quot; do
+    input = StringIO.new(&quot;foo=bar&amp;quux=bla&quot;)
+    input.instance_eval &quot;undef :rewind&quot;
+    req = Rack::Request.new \
+      Rack::MockRequest.env_for(&quot;/&quot;,
+        &quot;CONTENT_TYPE&quot; =&gt; 'application/x-www-form-urlencoded;foo=bar',
+        :input =&gt; input)
+    req.params.should.equal &quot;foo&quot; =&gt; &quot;bar&quot;, &quot;quux&quot; =&gt; &quot;bla&quot;
+  end
+
   specify &quot;can get value by key from params with #[]&quot; do
     req = Rack::Request.new \
       Rack::MockRequest.env_for(&quot;?foo=quux&quot;)
@@ -289,7 +309,7 @@ EOF
                       &quot;CONTENT_TYPE&quot; =&gt; &quot;multipart/form-data, boundary=AaB03x&quot;,
                       &quot;CONTENT_LENGTH&quot; =&gt; input.size,
                       :input =&gt; input)
-    
+
     req.POST[&quot;huge&quot;][:tempfile].size.should.equal 32768
     req.POST[&quot;mean&quot;][:tempfile].size.should.equal 10
     req.POST[&quot;mean&quot;][:tempfile].read.should.equal &quot;--AaB03xha&quot;
@@ -398,4 +418,29 @@ EOF
 
     lambda { parser.call(&quot;gzip ; q=1.0&quot;) }.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' =&gt; '123.123.123.123'
+    res.body.should == '123.123.123.123'
+
+    res = mock.get '/',
+      'REMOTE_ADDR' =&gt; '123.123.123.123',
+      'HTTP_X_FORWARDED_FOR' =&gt; '234.234.234.234'
+
+    res.body.should == '234.234.234.234'
+
+    res = mock.get '/',
+      'REMOTE_ADDR' =&gt; '123.123.123.123',
+      'HTTP_X_FORWARDED_FOR' =&gt; '234.234.234.234,212.212.212.212'
+
+    res.body.should == '212.212.212.212'
+  end
 end</diff>
      <filename>vendor/rack/test/spec_rack_request.rb</filename>
    </modified>
    <modified>
      <diff>@@ -1,4 +1,5 @@
 require 'test/spec'
+require 'set'
 
 require 'rack/response'
 
@@ -7,7 +8,7 @@ context &quot;Rack::Response&quot; do
     response = Rack::Response.new
     status, header, body = response.finish
     status.should.equal 200
-    header.should.equal &quot;Content-Type&quot; =&gt; &quot;text/html&quot;
+    header.should.equal &quot;Content-Type&quot; =&gt; &quot;text/html&quot;, &quot;Content-Length&quot; =&gt; &quot;0&quot;
     body.each { |part|
       part.should.equal &quot;&quot;
     }
@@ -15,7 +16,7 @@ context &quot;Rack::Response&quot; do
     response = Rack::Response.new
     status, header, body = *response
     status.should.equal 200
-    header.should.equal &quot;Content-Type&quot; =&gt; &quot;text/html&quot;
+    header.should.equal &quot;Content-Type&quot; =&gt; &quot;text/html&quot;, &quot;Content-Length&quot; =&gt; &quot;0&quot;
     body.each { |part|
       part.should.equal &quot;&quot;
     }
@@ -62,6 +63,12 @@ context &quot;Rack::Response&quot; do
       /expires=..., \d\d-...-\d\d\d\d \d\d:\d\d:\d\d .../)
   end
 
+  specify &quot;can set secure cookies&quot; do
+    response = Rack::Response.new
+    response.set_cookie &quot;foo&quot;, {:value =&gt; &quot;bar&quot;, :secure =&gt; true}
+    response[&quot;Set-Cookie&quot;].should.equal &quot;foo=bar; secure&quot;
+  end
+
   specify &quot;can delete cookies&quot; do
     response = Rack::Response.new
     response.set_cookie &quot;foo&quot;, &quot;bar&quot;
@@ -82,7 +89,7 @@ context &quot;Rack::Response&quot; do
     str = &quot;&quot;; body.each { |part| str &lt;&lt; part }
     str.should.equal &quot;foobar&quot;
 
-    r = Rack::Response.new({&quot;foo&quot;, &quot;bar&quot;})
+    r = Rack::Response.new([&quot;foo&quot;, &quot;bar&quot;].to_set)
     r.write &quot;foo&quot;
     status, header, body = r.finish
     str = &quot;&quot;; body.each { |part| str &lt;&lt; part }</diff>
      <filename>vendor/rack/test/spec_rack_response.rb</filename>
    </modified>
    <modified>
      <diff>@@ -46,4 +46,37 @@ context &quot;Rack::Session::Cookie&quot; do
         get(&quot;/&quot;, :fatal =&gt; true)
     }.should.raise(Rack::MockRequest::FatalWarning)
   end
+  
+  specify &quot;creates a new cookie with integrity hash&quot; do
+    res = Rack::MockRequest.new(Rack::Session::Cookie.new(incrementor, :secret =&gt; 'test')).get(&quot;/&quot;)
+    if RUBY_VERSION &lt; &quot;1.9&quot;
+      res[&quot;Set-Cookie&quot;].should.match(&quot;rack.session=BAh7BiIMY291bnRlcmkG%0A--1439b4d37b9d4b04c603848382f712d6fcd31088&quot;)
+    else
+      res[&quot;Set-Cookie&quot;].should.match(&quot;rack.session=BAh7BkkiDGNvdW50ZXIGOg1lbmNvZGluZyINVVMtQVNDSUlpBg%3D%3D%0A--d7a6637b94d2728194a96c18484e1f7ed9074a83&quot;)
+    end
+  end
+  
+  specify &quot;loads from a cookie wih integrity hash&quot; do
+    res = Rack::MockRequest.new(Rack::Session::Cookie.new(incrementor, :secret =&gt; 'test')).get(&quot;/&quot;)
+    cookie = res[&quot;Set-Cookie&quot;]
+    res = Rack::MockRequest.new(Rack::Session::Cookie.new(incrementor, :secret =&gt; 'test')).
+      get(&quot;/&quot;, &quot;HTTP_COOKIE&quot; =&gt; cookie)
+    res.body.should.equal '{&quot;counter&quot;=&gt;2}'
+    cookie = res[&quot;Set-Cookie&quot;]
+    res = Rack::MockRequest.new(Rack::Session::Cookie.new(incrementor, :secret =&gt; 'test')).
+      get(&quot;/&quot;, &quot;HTTP_COOKIE&quot; =&gt; cookie)
+    res.body.should.equal '{&quot;counter&quot;=&gt;3}'
+  end
+  
+  specify &quot;ignores tampered with session cookies&quot; do
+    app = Rack::Session::Cookie.new(incrementor, :secret =&gt; 'test')
+    response1 = Rack::MockRequest.new(app).get(&quot;/&quot;)
+    _, digest = response1[&quot;Set-Cookie&quot;].split(&quot;--&quot;)
+    tampered_with_cookie = &quot;hackerman-was-here&quot; + &quot;--&quot; + digest
+    response2 = Rack::MockRequest.new(app).get(&quot;/&quot;, &quot;HTTP_COOKIE&quot; =&gt;
+                                               tampered_with_cookie)
+    
+    # The tampered-with cookie is ignored, so we get back an identical Set-Cookie
+    response2[&quot;Set-Cookie&quot;].should.equal(response1[&quot;Set-Cookie&quot;])
+  end
 end</diff>
      <filename>vendor/rack/test/spec_rack_session_cookie.rb</filename>
    </modified>
    <modified>
      <diff>@@ -65,28 +65,30 @@ context &quot;Rack::Utils&quot; do
 end
 
 context &quot;Rack::Utils::HeaderHash&quot; do
-  specify &quot;should capitalize on all accesses&quot; do
-    h = Rack::Utils::HeaderHash.new(&quot;foo&quot; =&gt; &quot;bar&quot;)
-    h[&quot;foo&quot;].should.equal &quot;bar&quot;
-    h[&quot;Foo&quot;].should.equal &quot;bar&quot;
-    h[&quot;FOO&quot;].should.equal &quot;bar&quot;
-
-    h.to_hash.should.equal &quot;Foo&quot; =&gt; &quot;bar&quot;
-
-    h[&quot;bar-zzle&quot;] = &quot;quux&quot;
+  specify &quot;should retain header case&quot; do
+    h = Rack::Utils::HeaderHash.new(&quot;Content-MD5&quot; =&gt; &quot;d5ff4e2a0 ...&quot;)
+    h['ETag'] = 'Boo!'
+    h.to_hash.should.equal &quot;Content-MD5&quot; =&gt; &quot;d5ff4e2a0 ...&quot;, &quot;ETag&quot; =&gt; 'Boo!'
+  end
 
-    h.to_hash.should.equal &quot;Foo&quot; =&gt; &quot;bar&quot;, &quot;Bar-Zzle&quot; =&gt; &quot;quux&quot;
+  specify &quot;should check existence of keys case insensitively&quot; do
+    h = Rack::Utils::HeaderHash.new(&quot;Content-MD5&quot; =&gt; &quot;d5ff4e2a0 ...&quot;)
+    h.should.include 'content-md5'
+    h.should.not.include 'ETag'
   end
 
-  specify &quot;should capitalize correctly&quot; do
-    h = Rack::Utils::HeaderHash.new
+  specify &quot;should merge case-insensitively&quot; do
+    h = Rack::Utils::HeaderHash.new(&quot;ETag&quot; =&gt; 'HELLO', &quot;content-length&quot; =&gt; '123')
+    merged = h.merge(&quot;Etag&quot; =&gt; 'WORLD', 'Content-Length' =&gt; '321', &quot;Foo&quot; =&gt; 'BAR')
+    merged.should.equal &quot;Etag&quot;=&gt;'WORLD', &quot;Content-Length&quot;=&gt;'321', &quot;Foo&quot;=&gt;'BAR'
+  end
 
-    h.capitalize(&quot;foo&quot;).should.equal &quot;Foo&quot;
-    h.capitalize(&quot;foo-bar&quot;).should.equal &quot;Foo-Bar&quot;
-    h.capitalize(&quot;foo_bar&quot;).should.equal &quot;Foo_Bar&quot;
-    h.capitalize(&quot;foo bar&quot;).should.equal &quot;Foo Bar&quot;
-    h.capitalize(&quot;foo-bar-quux&quot;).should.equal &quot;Foo-Bar-Quux&quot;
-    h.capitalize(&quot;foo-bar-2quux&quot;).should.equal &quot;Foo-Bar-2quux&quot;
+  specify &quot;should overwrite case insensitively and assume the new key's case&quot; do
+    h = Rack::Utils::HeaderHash.new(&quot;Foo-Bar&quot; =&gt; &quot;baz&quot;)
+    h[&quot;foo-bar&quot;] = &quot;bizzle&quot;
+    h[&quot;FOO-BAR&quot;].should.equal &quot;bizzle&quot;
+    h.length.should.equal 1
+    h.to_hash.should.equal &quot;foo-bar&quot; =&gt; &quot;bizzle&quot;
   end
 
   specify &quot;should be converted to real Hash&quot; do</diff>
      <filename>vendor/rack/test/spec_rack_utils.rb</filename>
    </modified>
    <modified>
      <diff>@@ -2,6 +2,7 @@ require 'test/spec'
 
 require 'rack/handler/webrick'
 require 'rack/lint'
+require 'rack/response'
 require 'testrequest'
 
 Thread.abort_on_exception = true
@@ -83,6 +84,22 @@ context &quot;Rack::Handler::WEBrick&quot; do
     response[&quot;rack.url_scheme&quot;].should.equal &quot;http&quot;
   end
 
+  specify &quot;should correctly set cookies&quot; do
+    @server.mount &quot;/cookie-test&quot;, Rack::Handler::WEBrick,
+    Rack::Lint.new(lambda { |req|
+                     res = Rack::Response.new
+                     res.set_cookie &quot;one&quot;, &quot;1&quot;
+                     res.set_cookie &quot;two&quot;, &quot;2&quot;
+                     res.finish
+                   })
+
+    Net::HTTP.start(@host, @port) { |http|
+      res = http.get(&quot;/cookie-test&quot;)
+      res.code.to_i.should.equal 200
+      res.get_fields(&quot;set-cookie&quot;).should.equal [&quot;one=1&quot;, &quot;two=2&quot;]
+    }
+  end
+
   specify &quot;should provide a .run&quot; do
     block_ran = false
     catch(:done) {</diff>
      <filename>vendor/rack/test/spec_rack_webrick.rb</filename>
    </modified>
    <modified>
      <diff>@@ -43,3 +43,15 @@ class TestRequest
     end
   end
 end
+
+class StreamingRequest
+  def self.call(env)
+    [200, {&quot;Content-Type&quot; =&gt; &quot;text/plain&quot;}, new]
+  end
+
+  def each
+    yield &quot;hello there!\n&quot;
+    sleep 5
+    yield &quot;that is all.\n&quot;
+  end
+end</diff>
      <filename>vendor/rack/test/testrequest.rb</filename>
    </modified>
    <modified>
      <diff>@@ -1,9 +1,7 @@
 = Sinatra
 
 Sinatra is a DSL for quickly creating web-applications in Ruby with minimal
-effort.
-
-== Sample App
+effort:
 
   # myapp.rb
   require 'rubygems'
@@ -32,78 +30,80 @@ Run with &lt;tt&gt;ruby myapp.rb&lt;/tt&gt; and view at &lt;tt&gt;http://localhost:4567&lt;/tt&gt;
     .. annihilate something ..
   end
 
-  head '/' do
-
-  end
-
-NOTE: &lt;tt&gt;put&lt;/tt&gt; and &lt;tt&gt;delete&lt;/tt&gt; are also triggered when a
-&lt;tt&gt;_method&lt;/tt&gt; parameter is set to PUT or DELETE and the HTTP request method
-is POST
-
 == Routes
 
 Routes are matched based on the order of declaration. The first route that
 matches the request is invoked.
 
-Simple:
+Basic routes:
 
   get '/hi' do
     ...
   end
 
-Named parameters:
+Route patterns may include named parameters, accessible via the
+&lt;tt&gt;params&lt;/tt&gt; hash:
 
   get '/:name' do
-    # matches /sinatra and the like and sets params[:name]
+    # matches &quot;GET /foo&quot; and &quot;GET /bar&quot;
+    # params[:name] is 'foo' or 'bar'
+    &quot;Hello #{params[:name]}!&quot;
   end
 
-Splat parameters:
+Route patterns may also include splat (or wildcard) parameters, accessible
+via the &lt;tt&gt;params[:splat]&lt;/tt&gt; array.
 
   get '/say/*/to/*' do
     # matches /say/hello/to/world
-    params[&quot;splat&quot;] # =&gt; [&quot;hello&quot;, &quot;world&quot;]
+    params[:splat] # =&gt; [&quot;hello&quot;, &quot;world&quot;]
   end
 
   get '/download/*.*' do
     # matches /download/path/to/file.xml
-    params[&quot;splat&quot;] # =&gt; [&quot;path/to/file&quot;, &quot;xml&quot;]
+    params[:splat] # =&gt; [&quot;path/to/file&quot;, &quot;xml&quot;]
   end
 
-User agent matching:
+Route matching with Regular Expressions:
+
+  get %r{/hello/([\w]+)} do
+    &quot;Hello, #{params[:captures].first}!&quot;
+  end
+
+Routes may include a variety of matching conditions, such as the user agent:
 
   get '/foo', :agent =&gt; /Songbird (\d\.\d)[\d\/]*?/ do
     &quot;You're using Songbird version #{params[:agent][0]}&quot;
   end
 
   get '/foo' do
-    # matches non-songbird browsers
+    # Matches non-songbird browsers
   end
 
-= Static files
+== Static Files
 
-Put all of your static content in the ./public directory
+Static files are served from the &lt;tt&gt;./public&lt;/tt&gt; directory. You can specify
+a different location by setting the &lt;tt&gt;:public&lt;/tt&gt; option:
 
-  root
-    \ public
+  set :public, File.dirname(__FILE__) + '/static'
 
-If a file exists that maps to the REQUEST_PATH then it is served and the
-request ends. Otherwise, Sinatra will look for an event that matches the
-path.
+== Views / Templates
 
-== Views
+Templates are assumed to be located directly under a &lt;tt&gt;./views&lt;/tt&gt;
+directory. To use a different views directory:
 
-Views are searched for in a &quot;views&quot; directory in the same location as
-your main application.
+  set :views, File.dirname(__FILE__) + '/templates'
 
 === Haml Templates
 
+The haml gem/library is required to render HAML templates:
+
   get '/' do
     haml :index
   end
 
 Renders &lt;tt&gt;./views/index.haml&lt;/tt&gt;.
 
-=== Erb
+=== Erb Templates
 
   get '/' do
     erb :index
@@ -111,11 +111,20 @@ Renders &lt;tt&gt;./views/index.haml&lt;/tt&gt;.
 
 Renders &lt;tt&gt;./views/index.erb&lt;/tt&gt;
 
-=== Builder
+=== Builder Templates
+
+The builder gem/library is required to render builder templates:
+
+  get '/' do
+    content_type 'application/xml', :charset =&gt; 'utf-8'
+    builder :index
+  end
+
+Renders &lt;tt&gt;./views/index.builder&lt;/tt&gt;.
 
-See Sinatra::Builder
+=== Sass Templates
 
-=== Sass
+The sass gem/library is required to render Sass templates:
 
   get '/stylesheet.css' do
     content_type 'text/css', :charset =&gt; 'utf-8'
@@ -134,20 +143,19 @@ Renders the inlined template string.
 
 === Accessing Variables
 
-Templates are evaluated within the Sinatra::EventContext instance
-used to evaluate event blocks. Instance variables set in event
-blocks can be accessed direcly in views:
+Templates are evaluated within the same context as the route blocks. Instance
+variables set in route blocks are available in templates:
 
   get '/:id' do
     @foo = Foo.find(params[:id])
-    haml '%h1== @foo.name'
+    haml '%h1= @foo.name'
   end
 
 Or, specify an explicit Hash of local variables:
 
   get '/:id' do
     foo = Foo.find(params[:id])
-    haml '%h1== foo.name', :locals =&gt; { :foo =&gt; foo }
+    haml '%h1= foo.name', :locals =&gt; { :foo =&gt; foo }
   end
 
 This is typically used when rendering templates as partials from within
@@ -157,27 +165,32 @@ other templates.
 
 Templates may be defined at the end of the source file:
 
+  require 'rubygems'
+  require 'sinatra'
+
   get '/' do
     haml :index
   end
 
-  use_in_file_templates!
-
   __END__
 
   @@ layout
-  X
-  = yield
-  X
+  %html
+    = yield
 
   @@ index
   %div.title Hello world!!!!!
 
+NOTE:  Sinatra will automaticly load any in-file-templates in the
+source file that first required sinatra.  If you have in-file-templates
+in another source file you will need to explicitly call
++use_in_file_templates! on main in that file.
+
 It's also possible to define named templates using the top-level template
 method:
 
   template :layout do
-    &quot;X\n=yield\nX&quot;
+    &quot;%html\n  =yield\n&quot;
   end
 
   template :index do
@@ -188,10 +201,17 @@ method:
     haml :index
   end
 
+If a template named &quot;layout&quot; exists, it will be used each time a template
+is rendered. You can disable layouts by passing &lt;tt&gt;:layout =&gt; false&lt;/tt&gt;.
+
+  get '/' do
+    haml :index, :layout =&gt; !request.xhr?
+  end
+
 == Helpers
 
-The top-level &lt;tt&gt;helpers&lt;/tt&gt; method takes a block and extends all
-EventContext instances with the methods defined:
+Use the top-level &lt;tt&gt;helpers&lt;/tt&gt; method to define helper methods for use in
+route blocks and templates:
 
   helpers do
     def bar(name)
@@ -205,151 +225,127 @@ EventContext instances with the methods defined:
 
 == Filters
 
-These are run in Sinatra::EventContext before every event.
+Before filters are evaluated before each request within the context of the
+request and can modify the request and response. Instance variables set in
+filters are accessible by routes and templates.
 
   before do
-    .. this code will run before each event ..
+    @note = 'Hi!'
+    request.path_info = '/foo/bar/baz'
   end
 
-== Halt!
-
-To immediately stop a request during a before filter or event use:
-
-  throw :halt
-
-Set the body to the result of a helper method
-
-  throw :halt, :helper_method
-
-Set the body to the result of a helper method after sending it parameters from
-the local scope
-
-  throw :halt, [:helper_method, foo, bar]
+  get '/foo/*' do
+    @note #=&gt; 'Hi!'
+    params[:splat] #=&gt; 'bar/baz'
+  end
 
-Set the body to a simple string
+== Halting
 
-  throw :halt, 'this will be the body'
+To immediately stop a request during a before filter or route use:
 
-Set status then the body
+  halt
 
-  throw :halt, [401, 'go away!']
+You can also specify a body when halting ...
 
-Set the status then call a helper method with params from local scope
+  halt 'this will be the body'
 
-  throw :halt, [401, [:helper_method, foo, bar]]
+Set the status and body ...
 
-Run a proc inside the Sinatra::EventContext instance and set the body to the
-result
+  halt 401, 'go away!'
 
-  throw :halt, lambda { puts 'In a proc!'; 'I just wrote to $stdout!' }
+== Passing
 
-Create you own to_result
+A route can punt processing to the next matching route using the &lt;tt&gt;pass&lt;/tt&gt;
+statement:
 
-  class MyResultObject
-    def to_result(event_context, *args)
-      event_context.body = 'This will be the body!
-    end
+  get '/guess/:who' do
+    pass unless params[:who] == 'Frank'
+    &quot;You got me!&quot;
   end
 
-  get '/' do
-    throw :halt, MyResultObject.new
+  get '/guess/*' do
+    &quot;You missed!&quot;
   end
 
-Get the gist?  If you want more fun with this then checkout &lt;tt&gt;to_result&lt;/tt&gt;
-on Array, Symbol, Fixnum, NilClass.
+The route block is immediately exited and control continues with the next
+matching route. If no matching route is found, a 404 is returned.
 
 == Configuration and Reloading
 
-Sinatra supports multiple environments and re-loading.  Re-loading happens on
-every request when in :development.  Wrap your configurations in
-&lt;tt&gt;configure&lt;/tt&gt; (i.e. Database connections, Constants, etc.) to protect
-them from re-loading and to only work in certain environments.
+Sinatra supports multiple environments and reloading. Reloading happens
+before each request when running under the &lt;tt&gt;:development&lt;/tt&gt;
+environment. Wrap your configurations (e.g., database connections, constants,
+etc.) in &lt;tt&gt;configure&lt;/tt&gt; blocks to protect them from reloading or to
+target specific environments.
 
-All environments:
+Run once, at startup, in any environment:
 
   configure do
-
+    ...
   end
 
-Production
+Run only when the environment (RACK_ENV environment variable) is set to
+&lt;tt&gt;:production&lt;/tt&gt;.
 
   configure :production do
-
+    ...
   end
 
-Two at a time:
+Run when the environment (RACK_ENV environment variable) is set to
+either &lt;tt&gt;:production&lt;/tt&gt; or &lt;tt&gt;:test&lt;/tt&gt;.
 
   configure :production, :test do
-
+    ...
   end
 
-This is also really nifty for error handling.
+== Error handling
 
-= Error handling
+Error handlers run within the same context as routes and before filters, which
+means you get all the goodies it has to offer, like &lt;tt&gt;haml&lt;/tt&gt;, &lt;tt&gt;erb&lt;/tt&gt;,
+&lt;tt&gt;halt&lt;/tt&gt;, etc.
 
-== Not Found
+=== Not Found
 
-Remember:  These are run inside the Sinatra::EventContext which means you get
-all the goodies is has to offer (i.e. haml, erb, :halt, etc.)
-
-Whenever NotFound is raised this will be called
+When a &lt;tt&gt;Sinatra::NotFound&lt;/tt&gt; exception is raised, or the response's status
+code is 404, the &lt;tt&gt;not_found&lt;/tt&gt; handler is invoked:
 
   not_found do
     'This is nowhere to be found'
   end
 
-== Error
-
-By default +error+ will catch Sinatra::ServerError
+=== Error
 
-Sinatra will pass you the error via the 'sinatra.error' in request.env
+The +error+ handler is invoked any time an exception is raised from a route
+block or before filter. The exception object can be obtained from the
+'sinatra.error' Rack variable:
 
   error do
-    'Sorry there was a nasty error - ' + request.env['sinatra.error'].name
+    'Sorry there was a nasty error - ' + env['sinatra.error'].name
   end
 
-Custom error mapping:
+Custom errors:
 
   error MyCustomError do
     'So what happened was...' + request.env['sinatra.error'].message
   end
 
-then if this happens:
+Then, if this happens:
 
   get '/' do
     raise MyCustomError, 'something bad'
   end
 
-you gets this:
+You get this:
 
   So what happened was... something bad
 
-one guess what this does ;)
-
-  not_found do
-    'I have no clue what you're looking for'
-  end
-
-Because Sinatra gives you a default &lt;tt&gt;not_found&lt;/tt&gt; and &lt;tt&gt;error&lt;/tt&gt; do
-:production that are secure.  If you want to customize only for :production
-but want to keep the friendly helper screens for :development then do this:
-
-  configure :production do
-
-    not_found do
-      &quot;We're so sorry, but we don't what this is&quot;
-    end
-
-    error do
-      &quot;Something really nasty happened.  We're on it!&quot;
-    end
-
-  end
+Sinatra installs special not_found and error handlers when running under
+the development environment.
 
 == Mime types
 
-When using send_file or static files you may have mime types Sinatra doesn't
-understand.  Use +mime+ in those cases.
+When using &lt;tt&gt;send_file&lt;/tt&gt; or static files you may have mime types Sinatra
+doesn't understand. Use +mime+ to register them by file extension:
 
   mime :foo, 'text/foo'
 
@@ -360,12 +356,9 @@ interface for Ruby web frameworks. One of Rack's most interesting capabilities
 for application developers is support for &quot;middleware&quot; -- components that sit
 between the server and your application monitoring and/or manipulating the
 HTTP request/response to provide various types of common functionality.
-What's more, middleware is portable between web frameworks, so middleware
-components developed under, e.g., Merb, can be used with Sinatra and vice
-versa.
 
-Sinatra makes building Rack middleware pipelines a cinch via a top-level +use+
-method:
+Sinatra makes building Rack middleware pipelines a cinch via a top-level
++use+ method:
 
   require 'sinatra'
   require 'my_custom_middleware'
@@ -393,72 +386,98 @@ typically don't have to +use+ them explicitly.
 
 == Testing
 
-=== Methods
-
-  get_it path, params
-  get_it path, params.merge(:env =&gt; { 'HTTP_HOST' =&gt; 'www.sinatrarb.com' }) or
-  get_it path, params.merge(:env =&gt; { :host =&gt; 'www.sinatrarb.com' })
+The Sinatra::Test module includes a variety of helper methods for testing
+your Sinatra app. Sinatra includes support for Test::Unit, test-spec, RSpec,
+and Bacon through separate source files.
 
-RESTful:
+=== Test::Unit
 
-  post_it '/foo', '&lt;myxml&gt;&lt;/myxml&gt;', 'HTTP_ACCEPT' =&gt; 'application/xml'
-
-also works with:
-
-  get_it, post_it, put_it, delete_it, head_it
-
-=== Test/Unit
-
-  require 'my_sinatra_app'
+  require 'sinatra'
   require 'sinatra/test/unit'
+  require 'my_sinatra_app'
 
   class MyAppTest &lt; Test::Unit::TestCase
-
     def test_my_default
-      get_it '/'
+      get '/'
       assert_equal 'My Default Page!', @response.body
     end
 
     def test_with_agent
-      get_it '/', :agent =&gt; 'Songbird'
+      get '/', :agent =&gt; 'Songbird'
       assert_equal 'You're in Songbird!', @response.body
     end
 
     ...
-
   end
 
-=== Specs
+=== Test::Spec
 
-  require 'my_sinatra_app'
-  require 'sinatra/test/spec'
+Install the test-spec gem and require &lt;tt&gt;'sinatra/test/spec'&lt;/tt&gt; before
+your app:
 
-  context 'My app'
+  require 'sinatra'
+  require 'sinatra/test/spec'
+  require 'my_sinatra_app'
 
-    should &quot;show a default page&quot; do
-      get_it '/'
+  describe 'My app' do
+    it &quot;should show a default page&quot; do
+      get '/'
       should.be.ok
       body.should.equal 'My Default Page!'
     end
+
+    ...
+  end
+
+=== RSpec
+
+Install the rspec gem and require &lt;tt&gt;'sinatra/test/rspec'&lt;/tt&gt; before
+your app:
+
+  require 'sinatra'
+  require 'sinatra/test/rspec'
+  require 'my_sinatra_app'
+
+  describe 'My app' do
+    it 'should show a default page' do
+      get '/'
+      @response.should be_ok
+      @response.body.should == 'My Default Page!'
+    end
+
     ...
 
   end
 
-=== Test Helpers
+=== Bacon
+
+  require 'sinatra'
+  require 'sinatra/test/bacon'
+  require 'my_sinatra_app'
+
+  describe 'My app' do
+    it 'should be ok' do
+      get '/'
+      should.be.ok
+      body.should == 'Im OK'
+    end
+  end
 
-See Sinatra::Test::Methods
+See Sinatra::Test for more information on +get+, +post+, +put+, and
+friends.
 
 == Command line
 
-Run your sinatra file like:
+Sinatra applications can be run directly:
 
-  ruby myapp.rb [options]
+  ruby myapp.rb [-h] [-x] [-e ENVIRONMENT] [-p PORT] [-s HANDLER]
 
 Options are:
 
   -h # help
   -p # set the port (default is 4567)
   -e # set the environment (default is development)
+  -s # specify rack server/handler (default is thin)
   -x # turn on the mutex lock (default is off)
 
 == Contributing
@@ -491,7 +510,7 @@ screencasts about Git, which you can find here: http://www.gitcasts.com/
 
 at the top of your sinatra_app.rb file:
 
-  $:.unshift File.dirname(__FILE__) + '/sinatra/lib'
+  $LOAD_PATH.unshift File.dirname(__FILE__) + '/sinatra/lib'
   require 'sinatra'
 
   get '/about' do</diff>
      <filename>vendor/sinatra/README.rdoc</filename>
    </modified>
    <modified>
      <diff>@@ -1,4 +1,6 @@
+require 'rubygems'
 require 'rake/clean'
+require 'fileutils'
 
 task :default =&gt; :test
 
@@ -6,13 +8,19 @@ task :default =&gt; :test
 
 desc 'Run specs with story style output'
 task :spec do
-  sh 'specrb --specdox -Ilib:test test/*_test.rb'
+  pattern = ENV['TEST'] || '.*'
+  sh &quot;specrb --testcase '#{pattern}' --specdox -Ilib:test test/*_test.rb&quot;
 end
 
 desc 'Run specs with unit test style output'
-task :test =&gt; FileList['test/*_test.rb'] do |t|
-  suite = t.prerequisites.map{|f| &quot;-r#{f.chomp('.rb')}&quot;}.join(' ')
-  sh &quot;ruby -Ilib:test #{suite} -e ''&quot;, :verbose =&gt; false
+task :test do |t|
+  sh &quot;specrb -Ilib:test test/*_test.rb&quot;
+end
+
+desc 'Run compatibility specs'
+task :compat do |t|
+  pattern = ENV['TEST'] || '.*'
+  sh &quot;specrb --testcase '#{pattern}' -Ilib:test compat/*_test.rb&quot;
 end
 
 # PACKAGING ============================================================
@@ -49,16 +57,22 @@ file package('.gem') =&gt; %w[dist/ sinatra.gemspec] + spec.files do |f|
 end
 
 file package('.tar.gz') =&gt; %w[dist/] + spec.files do |f|
-  sh &quot;git archive --format=tar HEAD | gzip &gt; #{f.name}&quot;
+  sh &lt;&lt;-SH
+    git archive \
+      --prefix=sinatra-#{source_version}/ \
+      --format=tar \
+      HEAD | gzip &gt; #{f.name}
+  SH
 end
 
 # Rubyforge Release / Publish Tasks ==================================
 
-desc 'Publish API docs to rubyforge'
+desc 'Publish website to rubyforge'
 task 'publish:doc' =&gt; 'doc/api/index.html' do
   sh 'scp -rp doc/* rubyforge.org:/var/www/gforge-projects/sinatra/'
 end
 
+desc 'Publish gem and tarball to rubyforge'
 task 'publish:gem' =&gt; [package('.gem'), package('.tar.gz')] do |t|
   sh &lt;&lt;-end
     rubyforge add_release sinatra sinatra #{spec.version} #{package('.gem')} &amp;&amp;
@@ -66,34 +80,14 @@ task 'publish:gem' =&gt; [package('.gem'), package('.tar.gz')] do |t|
   end
 end
 
-# Gemspec Helpers ====================================================
-
-file 'sinatra.gemspec' =&gt; FileList['{lib,test,images}/**','Rakefile'] do |f|
-  # read spec file and split out manifest section
-  spec = File.read(f.name)
-  parts = spec.split(&quot;  # = MANIFEST =\n&quot;)
-  fail 'bad spec' if parts.length != 3
-  # determine file list from git ls-files
-  files = `git ls-files`.
-    split(&quot;\n&quot;).
-    sort.
-    reject{ |file| file =~ /^\./ }.
-    map{ |file| &quot;    #{file}&quot; }.
-    join(&quot;\n&quot;)
-  # piece file back together and write...
-  parts[1] = &quot;  s.files = %w[\n#{files}\n  ]\n&quot;
-  spec = parts.join(&quot;  # = MANIFEST =\n&quot;)
-  File.open(f.name, 'w') { |io| io.write(spec) }
-  puts &quot;updated #{f.name}&quot;
-end
-
-# Hanna RDoc =========================================================
-#
-# Building docs requires the hanna gem:
+# Website ============================================================
+# Building docs requires HAML and the hanna gem:
 #   gem install mislav-hanna --source=http://gems.github.com
 
+task 'doc'     =&gt; ['doc:api','doc:site']
+
 desc 'Generate Hanna RDoc under doc/api'
-task :doc =&gt; ['doc/api/index.html']
+task 'doc:api' =&gt; ['doc/api/index.html']
 
 file 'doc/api/index.html' =&gt; FileList['lib/**/*.rb','README.rdoc'] do |f|
   rb_files = f.prerequisites
@@ -109,3 +103,84 @@ file 'doc/api/index.html' =&gt; FileList['lib/**/*.rb','README.rdoc'] do |f|
   end
 end
 CLEAN.include 'doc/api'
+
+def rdoc_to_html(file_name)
+  require 'rdoc/markup/to_html'
+  rdoc = RDoc::Markup::ToHtml.new
+  rdoc.convert(File.read(file_name))
+end
+
+def haml(locals={})
+  require 'haml'
+  template = File.read('doc/template.haml')
+  haml = Haml::Engine.new(template, :format =&gt; :html4, :attr_wrapper =&gt; '&quot;')
+  haml.render(Object.new, locals)
+end
+
+desc 'Build website HTML and stuff'
+task 'doc:site' =&gt; ['doc/index.html', 'doc/book.html']
+
+file 'doc/index.html' =&gt; %w[README.rdoc doc/template.haml] do |file|
+  File.open(file.name, 'w') do |file|
+    file &lt;&lt; haml(:title =&gt; 'Sinatra', :content =&gt; rdoc_to_html('README.rdoc'))
+  end
+end
+CLEAN.include 'doc/index.html'
+
+file 'doc/book.html' =&gt; ['book/output/sinatra-book.html'] do |file|
+  File.open(file.name, 'w') do |file|
+    book_content = File.read('book/output/sinatra-book.html')
+    file &lt;&lt; haml(:title =&gt; 'Sinatra Book', :content =&gt; book_content)
+  end
+end
+CLEAN.include 'doc/book.html'
+
+file 'book/output/sinatra-book.html' =&gt; FileList['book/**'] do |f|
+  unless File.directory?('book')
+    sh 'git clone git://github.com/cschneid/sinatra-book.git book'
+  end
+  sh((&lt;&lt;-SH).strip.gsub(/\s+/, ' '))
+    cd book &amp;&amp;
+    git fetch origin &amp;&amp;
+    git rebase origin/master &amp;&amp;
+    thor book:build
+  SH
+end
+CLEAN.include 'book/output/sinatra-book.html'
+
+desc 'Build the Sinatra book'
+task 'doc:book' =&gt; ['book/output/sinatra-book.html']
+
+# Gemspec Helpers ====================================================
+
+def source_version
+  line = File.read('lib/sinatra/base.rb')[/^\s*VERSION = .*/]
+  line.match(/.*VERSION = '(.*)'/)[1]
+end
+
+project_files =
+  FileList[
+    '{lib,test,compat,images}/**',
+    'Rakefile', 'CHANGES', 'README.rdoc'
+  ]
+file 'sinatra.gemspec' =&gt; project_files do |f|
+  # read spec file and split out manifest section
+  spec = File.read(f.name)
+  head, manifest, tail = spec.split(&quot;  # = MANIFEST =\n&quot;)
+  # replace version and date
+  head.sub!(/\.version = '.*'/, &quot;.version = '#{source_version}'&quot;)
+  head.sub!(/\.date = '.*'/, &quot;.date = '#{Date.today.to_s}'&quot;)
+  # determine file list from git ls-files
+  files = `git ls-files`.
+    split(&quot;\n&quot;).
+    sort.
+    reject{ |file| file =~ /^\./ }.
+    reject { |file| file =~ /^doc/ }.
+    map{ |file| &quot;    #{file}&quot; }.
+    join(&quot;\n&quot;)
+  # piece file back together and write...
+  manifest = &quot;  s.files = %w[\n#{files}\n  ]\n&quot;
+  spec = [head,manifest,tail].join(&quot;  # = MANIFEST =\n&quot;)
+  File.open(f.name, 'w') { |io| io.write(spec) }
+  puts &quot;updated #{f.name}&quot;
+end</diff>
      <filename>vendor/sinatra/Rakefile</filename>
    </modified>
    <modified>
      <diff>@@ -1,1477 +1,8 @@
-require 'time'
-require 'ostruct'
-require 'uri'
-require 'rack'
+libdir = File.dirname(__FILE__)
+$LOAD_PATH.unshift(libdir) unless $LOAD_PATH.include?(libdir)
 
-if ENV['SWIFT']
- require 'swiftcore/swiftiplied_mongrel'
- puts &quot;Using Swiftiplied Mongrel&quot;
-elsif ENV['EVENT']
-  require 'swiftcore/evented_mongrel'
-  puts &quot;Using Evented Mongrel&quot;
-end
+require 'sinatra/base'
+require 'sinatra/main'
+require 'sinatra/compat'
 
-module Rack #:nodoc:
-
-  class Request #:nodoc:
-
-    # Set of request method names allowed via the _method parameter hack. By
-    # default, all request methods defined in RFC2616 are included, with the
-    # exception of TRACE and CONNECT.
-    POST_TUNNEL_METHODS_ALLOWED = %w( PUT DELETE OPTIONS HEAD )
-
-    # Return the HTTP request method with support for method tunneling using
-    # the POST _method parameter hack. If the real request method is POST and
-    # a _method param is given and the value is one defined in
-    # +POST_TUNNEL_METHODS_ALLOWED+, return the value of the _method param
-    # instead.
-    def request_method
-      if post_tunnel_method_hack?
-        params['_method'].upcase
-      else
-        @env['REQUEST_METHOD']
-      end
-    end
-
-    def user_agent
-      @env['HTTP_USER_AGENT']
-    end
-
-  private
-
-    # Return truthfully if the request is a valid verb-over-post hack.
-    def post_tunnel_method_hack?
-      @env['REQUEST_METHOD'] == 'POST' &amp;&amp;
-        POST_TUNNEL_METHODS_ALLOWED.include?(self.POST.fetch('_method', '').upcase)
-    end
-  end
-
-  module Utils
-    extend self
-  end
-
-  module Handler
-    autoload :Mongrel, ::File.dirname(__FILE__) + &quot;/sinatra/rack/handler/mongrel&quot;
-  end
-
-end
-
-
-module Sinatra
-  extend self
-
-  VERSION = '0.3.0'
-
-  class NotFound &lt; RuntimeError
-    def self.code ; 404 ; end
-  end
-  class ServerError &lt; RuntimeError
-    def self.code ; 500 ; end
-  end
-
-  Result = Struct.new(:block, :params, :status) unless defined?(Result)
-
-  def options
-    application.options
-  end
-
-  def application
-    @app ||= Application.new
-  end
-
-  def application=(app)
-    @app = app
-  end
-
-  def port
-    application.options.port
-  end
-
-  def host
-    application.options.host
-  end
-
-  def env
-    application.options.env
-  end
-
-  # Deprecated: use application instead of build_application.
-  alias :build_application :application
-
-  def server
-    options.server ||= defined?(Rack::Handler::Thin) ? &quot;thin&quot; : &quot;mongrel&quot;
-
-    # Convert the server into the actual handler name
-    handler = options.server.capitalize
-
-    # If the convenience conversion didn't get us anything,
-    # fall back to what the user actually set.
-    handler = options.server unless Rack::Handler.const_defined?(handler)
-
-    @server ||= eval(&quot;Rack::Handler::#{handler}&quot;)
-  end
-
-  def run
-    begin
-      puts &quot;== Sinatra/#{Sinatra::VERSION} has taken the stage on port #{port} for #{env} with backup by #{server.name}&quot;
-      server.run(application, {:Port =&gt; port, :Host =&gt; host}) do |server|
-        trap(:INT) do
-          server.stop
-          puts &quot;\n== Sinatra has ended his set (crowd applauds)&quot;
-        end
-      end
-    rescue Errno::EADDRINUSE =&gt; e
-      puts &quot;== Someone is already performing on port #{port}!&quot;
-    end
-  end
-
-  class Event
-    include Rack::Utils
-
-    URI_CHAR = '[^/?:,&amp;#\.]'.freeze unless defined?(URI_CHAR)
-    PARAM = /(:(#{URI_CHAR}+)|\*)/.freeze unless defined?(PARAM)
-    SPLAT = /(.*?)/
-    attr_reader :path, :block, :param_keys, :pattern, :options
-
-    def initialize(path, options = {}, &amp;b)
-      @path = URI.encode(path)
-      @block = b
-      @param_keys = []
-      @options = options
-      splats = 0
-      regex = @path.to_s.gsub(PARAM) do |match|
-        if match == &quot;*&quot;
-          @param_keys &lt;&lt; &quot;_splat_#{splats}&quot;
-          splats += 1
-          SPLAT.to_s
-        else
-          @param_keys &lt;&lt; $2
-          &quot;(#{URI_CHAR}+)&quot;
-        end
-      end
-
-      @pattern = /^#{regex}$/
-    end
-
-    def invoke(request)
-      params = {}
-      if agent = options[:agent]
-        return unless request.user_agent =~ agent
-        params[:agent] = $~[1..-1]
-      end
-      if host = options[:host]
-        return unless host === request.host
-      end
-      return unless pattern =~ request.path_info.squeeze('/')
-      path_params = param_keys.zip($~.captures.map{|s| unescape(s)}).to_hash
-      params.merge!(path_params)
-      splats = params.select { |k, v| k =~ /^_splat_\d+$/ }.sort.map(&amp;:last)
-      unless splats.empty?
-        params.delete_if { |k, v| k =~ /^_splat_\d+$/ }
-        params[&quot;splat&quot;] = splats
-      end
-      Result.new(block, params, 200)
-    end
-
-  end
-
-  class Error
-
-    attr_reader :type, :block, :options
-
-    def initialize(type, options={}, &amp;block)
-      @type = type
-      @block = block
-      @options = options
-    end
-
-    def invoke(request)
-      Result.new(block, options, code)
-    end
-
-    def code
-      if type.respond_to?(:code)
-        type.code
-      else
-        500
-      end
-    end
-
-  end
-
-  class Static
-    include Rack::Utils
-
-    def invoke(request)
-      return unless File.file?(
-        Sinatra.application.options.public + unescape(request.path_info)
-      )
-      Result.new(block, {}, 200)
-    end
-
-    def block
-      Proc.new do
-        send_file Sinatra.application.options.public +
-          unescape(request.path_info), :disposition =&gt; nil
-      end
-    end
-
-  end
-
-  # Methods for sending files and streams to the browser instead of rendering.
-  module Streaming
-    DEFAULT_SEND_FILE_OPTIONS = {
-      :type         =&gt; 'application/octet-stream'.freeze,
-      :disposition  =&gt; 'attachment'.freeze,
-      :stream       =&gt; true,
-      :buffer_size  =&gt; 4096
-    }.freeze
-
-    class MissingFile &lt; RuntimeError; end
-
-    class FileStreamer
-
-      attr_reader :path, :options
-
-      def initialize(path, options)
-        @path, @options = path, options
-      end
-
-      def to_result(cx, *args)
-        self
-      end
-
-      def each
-        File.open(path, 'rb') do |file|
-          while buf = file.read(options[:buffer_size])
-            yield buf
-          end
-        end
-      end
-
-    end
-
-  protected
-
-    # Sends the file by streaming it 4096 bytes at a time. This way the
-    # whole file doesn't need to be read into memory at once.  This makes
-    # it feasible to send even large files.
-    #
-    # Be careful to sanitize the path parameter if it coming from a web
-    # page.  send_file(params[:path]) allows a malicious user to
-    # download any file on your server.
-    #
-    # Options:
-    # * &lt;tt&gt;:filename&lt;/tt&gt; - suggests a filename for the browser to use.
-    #   Defaults to File.basename(path).
-    # * &lt;tt&gt;:type&lt;/tt&gt; - specifies an HTTP content type.
-    #   Defaults to 'application/octet-stream'.
-    # * &lt;tt&gt;:disposition&lt;/tt&gt; - specifies whether the file will be shown
-    #   inline or downloaded. Valid values are 'inline' and 'attachment'
-    #   (default). When set to nil, the Content-Disposition and
-    #   Content-Transfer-Encoding headers are omitted entirely.
-    # * &lt;tt&gt;:stream&lt;/tt&gt; - whether to send the file to the user agent as it
-    #   is read (true) or to read the entire file before sending (false).
-    #   Defaults to true.
-    # * &lt;tt&gt;:buffer_size&lt;/tt&gt; - specifies size (in bytes) of the buffer used
-    #   to stream the file. Defaults to 4096.
-    # * &lt;tt&gt;:status&lt;/tt&gt; - specifies the status code to send with the
-    #   response. Defaults to '200 OK'.
-    # * &lt;tt&gt;:last_modified&lt;/tt&gt; - an optional RFC 2616 formatted date value
-    #   (See Time#httpdate) indicating the last modified time of the file.
-    #   If the request includes an If-Modified-Since header that matches this
-    #   value exactly, a 304 Not Modified response is sent instead of the file.
-    #   Defaults to the file's last modified time.
-    #
-    # The default Content-Type and Content-Disposition headers are
-    # set to download arbitrary binary files in as many browsers as
-    # possible.  IE versions 4, 5, 5.5, and 6 are all known to have
-    # a variety of quirks (especially when downloading over SSL).
-    #
-    # Simple download:
-    #   send_file '/path/to.zip'
-    #
-    # Show a JPEG in the browser:
-    #   send_file '/path/to.jpeg',
-    #     :type =&gt; 'image/jpeg',
-    #     :disposition =&gt; 'inline'
-    #
-    # Show a 404 page in the browser:
-    #   send_file '/path/to/404.html,
-    #     :type =&gt; 'text/html; charset=utf-8',
-    #     :status =&gt; 404
-    #
-    # Read about the other Content-* HTTP headers if you'd like to
-    # provide the user with more information (such as Content-Description).
-    # http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.11
-    #
-    # Also be aware that the document may be cached by proxies and browsers.
-    # The Pragma and Cache-Control headers declare how the file may be cached
-    # by intermediaries.  They default to require clients to validate with
-    # the server before releasing cached responses.  See
-    # http://www.mnot.net/cache_docs/ for an overview of web caching and
-    # http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9
-    # for the Cache-Control header spec.
-    def send_file(path, options = {}) #:doc:
-      raise MissingFile, &quot;Cannot read file #{path}&quot; unless File.file?(path) and File.readable?(path)
-
-      options[:length]   ||= File.size(path)
-      options[:filename] ||= File.basename(path)
-      options[:type] ||= Rack::File::MIME_TYPES[File.extname(options[:filename])[1..-1]] || 'text/plain'
-      options[:last_modified] ||= File.mtime(path).httpdate
-      send_file_headers! options
-
-      if options[:stream]
-        throw :halt, [options[:status] || 200, FileStreamer.new(path, options)]
-      else
-        File.open(path, 'rb') { |file| throw :halt, [options[:status] || 200, file.read] }
-      end
-    end
-
-    # Send binary data to the user as a file download. May set content type,
-    # apparent file name, and specify whether to show data inline or download
-    # as an attachment.
-    #
-    # Options:
-    # * &lt;tt&gt;:filename&lt;/tt&gt; - Suggests a filename for the browser to use.
-    # * &lt;tt&gt;:type&lt;/tt&gt; - specifies an HTTP content type.
-    #   Defaults to 'application/octet-stream'.
-    # * &lt;tt&gt;:disposition&lt;/tt&gt; - specifies whether the file will be shown inline
-    #   or downloaded. Valid values are 'inline' and 'attachment' (default).
-    # * &lt;tt&gt;:status&lt;/tt&gt; - specifies the status code to send with the response.
-    #   Defaults to '200 OK'.
-    # * &lt;tt&gt;:last_modified&lt;/tt&gt; - an optional RFC 2616 formatted date value (See
-    #   Time#httpdate) indicating the last modified time of the response entity.
-    #   If the request includes an If-Modified-Since header that matches this
-    #   value exactly, a 304 Not Modified response is sent instead of the data.
-    #
-    # Generic data download:
-    #   send_data buffer
-    #
-    # Download a dynamically-generated tarball:
-    #   send_data generate_tgz('dir'), :filename =&gt; 'dir.tgz'
-    #
-    # Display an image Active Record in the browser:
-    #   send_data image.data,
-    #     :type =&gt; image.content_type,
-    #     :disposition =&gt; 'inline'
-    #
-    # See +send_file+ for more information on HTTP Content-* headers and caching.
-    def send_data(data, options = {}) #:doc:
-      send_file_headers! options.merge(:length =&gt; data.size)
-      throw :halt, [options[:status] || 200, data]
-    end
-
-  private
-
-    def send_file_headers!(options)
-      options = DEFAULT_SEND_FILE_OPTIONS.merge(options)
-      [:length, :type, :disposition].each do |arg|
-        raise ArgumentError, &quot;:#{arg} option required&quot; unless options.key?(arg)
-      end
-
-      # Send a &quot;304 Not Modified&quot; if the last_modified option is provided and
-      # matches the If-Modified-Since request header value.
-      if last_modified = options[:last_modified]
-        header 'Last-Modified' =&gt; last_modified
-        throw :halt, [ 304, '' ] if last_modified == request.env['HTTP_IF_MODIFIED_SINCE']
-      end
-
-      headers(
-        'Content-Length'            =&gt; options[:length].to_s,
-        'Content-Type'              =&gt; options[:type].strip  # fixes a problem with extra '\r' with some browsers
-      )
-
-      # Omit Content-Disposition and Content-Transfer-Encoding headers if
-      # the :disposition option set to nil.
-      if !options[:disposition].nil?
-        disposition = options[:disposition].dup || 'attachment'
-        disposition &lt;&lt;= %(; filename=&quot;#{options[:filename]}&quot;) if options[:filename]
-        headers 'Content-Disposition' =&gt; disposition, 'Content-Transfer-Encoding' =&gt; 'binary'
-      end
-
-      # Fix a problem with IE 6.0 on opening downloaded files:
-      # If Cache-Control: no-cache is set (which Rails does by default),
-      # IE removes the file it just downloaded from its cache immediately
-      # after it displays the &quot;open/save&quot; dialog, which means that if you
-      # hit &quot;open&quot; the file isn't there anymore when the application that
-      # is called for handling the download is run, so let's workaround that
-      header('Cache-Control' =&gt; 'private') if headers['Cache-Control'] == 'no-cache'
-    end
-  end
-
-
-  # Helper methods for building various aspects of the HTTP response.
-  module ResponseHelpers
-
-    # Immediately halt response execution by redirecting to the resource
-    # specified. The +path+ argument may be an absolute URL or a path
-    # relative to the site root. Additional arguments are passed to the
-    # halt.
-    #
-    # With no integer status code, a '302 Temporary Redirect' response is
-    # sent. To send a permanent redirect, pass an explicit status code of
-    # 301:
-    #
-    #   redirect '/somewhere/else', 301
-    #
-    # NOTE: No attempt is made to rewrite the path based on application
-    # context. The 'Location' response header is set verbatim to the value
-    # provided.
-    def redirect(path, *args)
-      status(302)
-      header 'Location' =&gt; path
-      throw :halt, *args
-    end
-
-    # Access or modify response headers. With no argument, return the
-    # underlying headers Hash. With a Hash argument, add or overwrite
-    # existing response headers with the values provided:
-    #
-    #    headers 'Content-Type' =&gt; &quot;text/html;charset=utf-8&quot;,
-    #      'Last-Modified' =&gt; Time.now.httpdate,
-    #      'X-UA-Compatible' =&gt; 'IE=edge'
-    #
-    # This method also available in singular form (#header).
-    def headers(header = nil)
-      @response.headers.merge!(header) if header
-      @response.headers
-    end
-    alias :header :headers
-
-    # Set the content type of the response body (HTTP 'Content-Type' header).
-    #
-    # The +type+ argument may be an internet media type (e.g., 'text/html',
-    # 'application/xml+atom', 'image/png') or a Symbol key into the
-    # Rack::File::MIME_TYPES table.
-    #
-    # Media type parameters, such as &quot;charset&quot;, may also be specified using the
-    # optional hash argument:
-    #
-    #   get '/foo.html' do
-    #     content_type 'text/html', :charset =&gt; 'utf-8'
-    #     &quot;&lt;h1&gt;Hello World&lt;/h1&gt;&quot;
-    #   end
-    #
-    def content_type(type, params={})
-      type = Rack::File::MIME_TYPES[type.to_s] if type.kind_of?(Symbol)
-      fail &quot;Invalid or undefined media_type: #{type}&quot; if type.nil?
-      if params.any?
-        params = params.collect { |kv| &quot;%s=%s&quot; % kv }.join(', ')
-        type = [ type, params ].join(&quot;;&quot;)
-      end
-      response.header['Content-Type'] = type
-    end
-
-    # Set the last modified time of the resource (HTTP 'Last-Modified' header)
-    # and halt if conditional GET matches. The +time+ argument is a Time,
-    # DateTime, or other object that responds to +to_time+.
-    #
-    # When the current request includes an 'If-Modified-Since' header that
-    # matches the time specified, execution is immediately halted with a
-    # '304 Not Modified' response.
-    #
-    # Calling this method before perfoming heavy processing (e.g., lengthy
-    # database queries, template rendering, complex logic) can dramatically
-    # increase overall throughput with caching clients.
-    def last_modified(time)
-      time = time.to_time if time.respond_to?(:to_time)
-      time = time.httpdate if time.respond_to?(:httpdate)
-      response.header['Last-Modified'] = time
-      throw :halt, 304 if time == request.env['HTTP_IF_MODIFIED_SINCE']
-      time
-    end
-
-    # Set the response entity tag (HTTP 'ETag' header) and halt if conditional
-    # GET matches. The +value+ argument is an identifier that uniquely
-    # identifies the current version of the resource. The +strength+ argument
-    # indicates whether the etag should be used as a :strong (default) or :weak
-    # cache validator.
-    #
-    # When the current request includes an 'If-None-Match' header with a
-    # matching etag, execution is immediately halted. If the request method is
-    # GET or HEAD, a '304 Not Modified' response is sent. For all other request
-    # methods, a '412 Precondition Failed' response is sent.
-    #
-    # Calling this method before perfoming heavy processing (e.g., lengthy
-    # database queries, template rendering, complex logic) can dramatically
-    # increase overall throughput with caching clients.
-    #
-    # ==== See Also
-    # {RFC2616: ETag}[http://w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.19],
-    # ResponseHelpers#last_modified
-    def entity_tag(value, strength=:strong)
-      value =
-        case strength
-        when :strong then '&quot;%s&quot;' % value
-        when :weak   then 'W/&quot;%s&quot;' % value
-        else         raise TypeError, &quot;strength must be one of :strong or :weak&quot;
-        end
-      response.header['ETag'] = value
-
-      # Check for If-None-Match request header and halt if match is found.
-      etags = (request.env['HTTP_IF_NONE_MATCH'] || '').split(/\s*,\s*/)
-      if etags.include?(value) || etags.include?('*')
-        # GET/HEAD requests: send Not Modified response
-        throw :halt, 304 if request.get? || request.head?
-        # Other requests: send Precondition Failed response
-        throw :halt, 412
-      end
-    end
-
-    alias :etag :entity_tag
-
-  end
-
-  module RenderingHelpers
-
-    def render(renderer, template, options={})
-      m = method(&quot;render_#{renderer}&quot;)
-      result = m.call(resolve_template(renderer, template, options), options)
-      if layout = determine_layout(renderer, template, options)
-        result = m.call(resolve_template(renderer, layout, options), options) { result }
-      end
-      result
-    end
-
-    def determine_layout(renderer, template, options)
-      return if options[:layout] == false
-      layout_from_options = options[:layout] || :layout
-      resolve_template(renderer, layout_from_options, options, false)
-    end
-
-  private
-
-    def resolve_template(renderer, template, options, scream = true)
-      case template
-      when String
-        template
-      when Proc
-        template.call
-      when Symbol
-        if proc = templates[template]
-          resolve_template(renderer, proc, options, scream)
-        else
-          read_template_file(renderer, template, options, scream)
-        end
-      else
-        nil
-      end
-    end
-
-    def read_template_file(renderer, template, options, scream = true)
-      path = File.join(
-        options[:views_directory] || Sinatra.application.options.views,
-        &quot;#{template}.#{renderer}&quot;
-      )
-      unless File.exists?(path)
-        raise Errno::ENOENT.new(path) if scream
-        nil
-      else
-        File.read(path)
-      end
-    end
-
-    def templates
-      Sinatra.application.templates
-    end
-
-  end
-
-  module Erb
-
-    def erb(content, options={})
-      require 'erb'
-      render(:erb, content, options)
-    end
-
-  private
-
-    def render_erb(content, options = {})
-      locals_opt = options.delete(:locals) || {}
-
-      locals_code = &quot;&quot;
-      locals_hash = {}
-      locals_opt.each do |key, value|
-        locals_code &lt;&lt; &quot;#{key} = locals_hash[:#{key}]\n&quot;
-        locals_hash[:&quot;#{key}&quot;] = value
-      end
-
-      body = ::ERB.new(content).src
-      eval(&quot;#{locals_code}#{body}&quot;, binding)
-    end
-
-  end
-
-  module Haml
-
-    def haml(content, options={})
-      require 'haml'
-      render(:haml, content, options)
-    end
-
-  private
-
-    def render_haml(content, options = {}, &amp;b)
-      haml_options = (options[:options] || {}).
-        merge(Sinatra.options.haml || {})
-      ::Haml::Engine.new(content, haml_options).
-        render(options[:scope] || self, options[:locals] || {}, &amp;b)
-    end
-
-  end
-
-  # Generate valid CSS using Sass (part of Haml)
-  #
-  # Sass templates can be in external files with &lt;tt&gt;.sass&lt;/tt&gt; extension
-  # or can use Sinatra's in_file_templates.  In either case, the file can
-  # be rendered by passing the name of the template to the +sass+ method
-  # as a symbol.
-  #
-  # Unlike Haml, Sass does not support a layout file, so the +sass+ method
-  # will ignore both the default &lt;tt&gt;layout.sass&lt;/tt&gt; file and any parameters
-  # passed in as &lt;tt&gt;:layout&lt;/tt&gt; in the options hash.
-  #
-  # === Sass Template Files
-  #
-  # Sass templates can be stored in separate files with a &lt;tt&gt;.sass&lt;/tt&gt;
-  # extension under the view path.
-  #
-  # Example:
-  #   get '/stylesheet.css' do
-  #     header 'Content-Type' =&gt; 'text/css; charset=utf-8'
-  #     sass :stylesheet
-  #   end
-  #
-  # The &quot;views/stylesheet.sass&quot; file might contain the following:
-  #
-  #  body
-  #    #admin
-  #      :background-color #CCC
-  #    #main
-  #      :background-color #000
-  #  #form
-  #    :border-color #AAA
-  #    :border-width 10px
-  #
-  # And yields the following output:
-  #
-  #   body #admin {
-  #     background-color: #CCC; }
-  #   body #main {
-  #     background-color: #000; }
-  #
-  #   #form {
-  #     border-color: #AAA;
-  #     border-width: 10px; }
-  #
-  #
-  # NOTE: Haml must be installed or a LoadError will be raised the first time an
-  # attempt is made to render a Sass template.
-  #
-  # See http://haml.hamptoncatlin.com/docs/rdoc/classes/Sass.html for comprehensive documentation on Sass.
-  module Sass
-
-    def sass(content, options = {})
-      require 'sass'
-
-      # Sass doesn't support a layout, so we override any possible layout here
-      options[:layout] = false
-
-      render(:sass, content, options)
-    end
-
-  private
-
-    def render_sass(content, options = {})
-      ::Sass::Engine.new(content).render
-    end
-
-  end
-
-  # Generating conservative XML content using Builder templates.
-  #
-  # Builder templates can be inline by passing a block to the builder method,
-  # or in external files with +.builder+ extension by passing the name of the
-  # template to the +builder+ method as a Symbol.
-  #
-  # === Inline Rendering
-  #
-  # If the builder method is given a block, the block is called directly with
-  # an +XmlMarkup+ instance and the result is returned as String:
-  #   get '/who.xml' do
-  #     builder do |xml|
-  #       xml.instruct!
-  #       xml.person do
-  #         xml.name &quot;Francis Albert Sinatra&quot;,
-  #           :aka =&gt; &quot;Frank Sinatra&quot;
-  #         xml.email 'frank@capitolrecords.com'
-  #       end
-  #     end
-  #   end
-  #
-  # Yields the following XML:
-  #   &lt;?xml version='1.0' encoding='UTF-8'?&gt;
-  #   &lt;person&gt;
-  #     &lt;name aka='Frank Sinatra'&gt;Francis Albert Sinatra&lt;/name&gt;
-  #     &lt;email&gt;Frank Sinatra&lt;/email&gt;
-  #   &lt;/person&gt;
-  #
-  # === Builder Template Files
-  #
-  # Builder templates can be stored in separate files with a +.builder+
-  # extension under the view path. An +XmlMarkup+ object named +xml+ is
-  # automatically made available to template.
-  #
-  # Example:
-  #   get '/bio.xml' do
-  #     builder :bio
-  #   end
-  #
-  # The &quot;views/bio.builder&quot; file might contain the following:
-  #   xml.instruct! :xml, :version =&gt; '1.1'
-  #   xml.person do
-  #     xml.name &quot;Francis Albert Sinatra&quot;
-  #     xml.aka &quot;Frank Sinatra&quot;
-  #     xml.aka &quot;Ol' Blue Eyes&quot;
-  #     xml.aka &quot;The Chairman of the Board&quot;
-  #     xml.born 'date' =&gt; '1915-12-12' do
-  #       xml.text! &quot;Hoboken, New Jersey, U.S.A.&quot;
-  #     end
-  #     xml.died 'age' =&gt; 82
-  #   end
-  #
-  # And yields the following output:
-  #   &lt;?xml version='1.1' encoding='UTF-8'?&gt;
-  #   &lt;person&gt;
-  #     &lt;name&gt;Francis Albert Sinatra&lt;/name&gt;
-  #     &lt;aka&gt;Frank Sinatra&lt;/aka&gt;
-  #     &lt;aka&gt;Ol&amp;apos; Blue Eyes&lt;/aka&gt;
-  #     &lt;aka&gt;The Chairman of the Board&lt;/aka&gt;
-  #     &lt;born date='1915-12-12'&gt;Hoboken, New Jersey, U.S.A.&lt;/born&gt;
-  #     &lt;died age='82' /&gt;
-  #   &lt;/person&gt;
-  #
-  # NOTE: Builder must be installed or a LoadError will be raised the first
-  # time an attempt is made to render a builder template.
-  #
-  # See http://builder.rubyforge.org/ for comprehensive documentation on
-  # Builder.
-  module Builder
-
-    def builder(content=nil, options={}, &amp;block)
-      options, content = content, nil if content.is_a?(Hash)
-      content = Proc.new { block } if content.nil?
-      render(:builder, content, options)
-    end
-
-  private
-
-    def render_builder(content, options = {}, &amp;b)
-      require 'builder'
-      xml = ::Builder::XmlMarkup.new(:indent =&gt; 2)
-      case content
-      when String
-        eval(content, binding, '&lt;BUILDER&gt;', 1)
-      when Proc
-        content.call(xml)
-      end
-      xml.target!
-    end
-
-  end
-
-  class EventContext
-    include Rack::Utils
-    include ResponseHelpers
-    include Streaming
-    include RenderingHelpers
-    include Erb
-    include Haml
-    include Builder
-    include Sass
-
-    attr_accessor :request, :response
-
-    attr_accessor :route_params
-
-    def initialize(request, response, route_params)
-      @params = nil
-      @data = nil
-      @request = request
-      @response = response
-      @route_params = route_params
-      @response.body = nil
-    end
-
-    def status(value=nil)
-      response.status = value if value
-      response.status
-    end
-
-    def body(value=nil)
-      response.body = value if value
-      response.body
-    end
-
-    def params
-      @params ||=
-        begin
-          hash = Hash.new {|h,k| h[k.to_s] if Symbol === k}
-          hash.merge! @request.params
-          hash.merge! @route_params
-          hash
-        end
-    end
-
-    def data
-      @data ||= params.keys.first
-    end
-
-    def stop(*args)
-      throw :halt, args
-    end
-
-    def complete(returned)
-      @response.body || returned
-    end
-
-    def session
-      request.env['rack.session'] ||= {}
-    end
-
-    def reset!
-      @params = nil
-      @data = nil
-    end
-
-  private
-
-    def method_missing(name, *args, &amp;b)
-      if @response.respond_to?(name)
-        @response.send(name, *args, &amp;b)
-      else
-        super
-      end
-    end
-
-  end
-
-
-  # The Application class represents the top-level working area of a
-  # Sinatra app. It provides the DSL for defining various aspects of the
-  # application and implements a Rack compatible interface for dispatching
-  # requests.
-  #
-  # Many of the instance methods defined in this class (#get, #post,
-  # #put, #delete, #layout, #before, #error, #not_found, etc.) are
-  # available at top-level scope. When invoked from top-level, the
-  # messages are forwarded to the &quot;default application&quot; (accessible
-  # at Sinatra::application).
-  class Application
-
-    # Hash of event handlers with request method keys and
-    # arrays of potential handlers as values.
-    attr_reader :events
-
-    # Hash of error handlers with error status codes as keys and
-    # handlers as values.
-    attr_reader :errors
-
-    # Hash of template name mappings.
-    attr_reader :templates
-
-    # Hash of filters with event name keys (:before) and arrays of
-    # handlers as values.
-    attr_reader :filters
-
-    # Array of objects to clear during reload. The objects in this array
-    # must respond to :clear.
-    attr_reader :clearables
-
-    # Object including open attribute methods for modifying Application
-    # configuration.
-    attr_reader :options
-
-    # List of methods available from top-level scope. When invoked from
-    # top-level the method is forwarded to the default application
-    # (Sinatra::application).
-    FORWARD_METHODS = %w[
-      get put post delete head template layout before error not_found
-      configures configure set set_options set_option enable disable use
-      development? test? production?
-    ]
-
-    # Create a new Application with a default configuration taken
-    # from the default_options Hash.
-    #
-    # NOTE: A default Application is automatically created the first
-    # time any of Sinatra's DSL related methods is invoked so there
-    # is typically no need to create an instance explicitly. See
-    # Sinatra::application for more information.
-    def initialize
-      @reloading = false
-      @clearables = [
-        @events = Hash.new { |hash, key| hash[key] = [] },
-        @errors = Hash.new,
-        @filters = Hash.new { |hash, key| hash[key] = [] },
-        @templates = Hash.new,
-        @middleware = []
-      ]
-      @options = OpenStruct.new(self.class.default_options)
-      load_default_configuration!
-    end
-
-    # Hash of default application configuration options. When a new
-    # Application is created, the #options object takes its initial values
-    # from here.
-    #
-    # Changes to the default_options Hash effect only Application objects
-    # created after the changes are made. For this reason, modifications to
-    # the default_options Hash typically occur at the very beginning of a
-    # file, before any DSL related functions are invoked.
-    def self.default_options
-      return @default_options unless @default_options.nil?
-      root = File.expand_path(File.dirname($0))
-      @default_options = {
-        :run =&gt; true,
-        :port =&gt; 4567,
-        :host =&gt; '0.0.0.0',
-        :env =&gt; :development,
-        :root =&gt; root,
-        :views =&gt; root + '/views',
-        :public =&gt; root + '/public',
-        :sessions =&gt; false,
-        :logging =&gt; true,
-        :app_file =&gt; $0,
-        :raise_errors =&gt; false
-      }
-      load_default_options_from_command_line!
-      @default_options
-    end
-
-    # Search ARGV for command line arguments and update the
-    # Sinatra::default_options Hash accordingly. This method is
-    # invoked the first time the default_options Hash is accessed.
-    # NOTE:  Ignores --name so unit/spec tests can run individually
-    def self.load_default_options_from_command_line! #:nodoc:
-      # fixes issue with: gem install --test sinatra
-      return if ARGV.empty? || File.basename($0) =~ /gem/
-      require 'optparse'
-      OptionParser.new do |op|
-        op.on('-p port') { |port| default_options[:port] = port }
-        op.on('-e env') { |env| default_options[:env] = env.to_sym }
-        op.on('-x') { default_options[:mutex] = true }
-        op.on('-s server') { |server| default_options[:server] = server }
-      end.parse!(ARGV.dup.select { |o| o !~ /--name/ })
-    end
-
-    # Determine whether the application is in the process of being
-    # reloaded.
-    def reloading?
-      @reloading == true
-    end
-
-    # Yield to the block for configuration if the current environment
-    # matches any included in the +envs+ list. Always yield to the block
-    # when no environment is specified.
-    #
-    # NOTE: configuration blocks are not executed during reloads.
-    def configures(*envs, &amp;b)
-      return if reloading?
-      yield self if envs.empty? || envs.include?(options.env)
-    end
-
-    alias :configure :configures
-
-    # When both +option+ and +value+ arguments are provided, set the option
-    # specified. With a single Hash argument, set all options specified in
-    # Hash. Options are available via the Application#options object.
-    #
-    # Setting individual options:
-    #   set :port, 80
-    #   set :env, :production
-    #   set :views, '/path/to/views'
-    #
-    # Setting multiple options:
-    #   set :port  =&gt; 80,
-    #       :env   =&gt; :production,
-    #       :views =&gt; '/path/to/views'
-    #
-    def set(option, value=self)
-      if value == self &amp;&amp; option.kind_of?(Hash)
-        option.each { |key,val| set(key, val) }
-      else
-        options.send(&quot;#{option}=&quot;, value)
-      end
-    end
-
-    alias :set_option :set
-    alias :set_options :set
-
-    # Enable the options specified by setting their values to true. For
-    # example, to enable sessions and logging:
-    #   enable :sessions, :logging
-    def enable(*opts)
-      opts.each { |key| set(key, true) }
-    end
-
-    # Disable the options specified by setting their values to false. For
-    # example, to disable logging and automatic run:
-    #   disable :logging, :run
-    def disable(*opts)
-      opts.each { |key| set(key, false) }
-    end
-
-    # Define an event handler for the given request method and path
-    # spec. The block is executed when a request matches the method
-    # and spec.
-    #
-    # NOTE: The #get, #post, #put, and #delete helper methods should
-    # be used to define events when possible.
-    def event(method, path, options = {}, &amp;b)
-      events[method].push(Event.new(path, options, &amp;b)).last
-    end
-
-    # Define an event handler for GET requests.
-    def get(path, options={}, &amp;b)
-      event(:get, path, options, &amp;b)
-    end
-
-    # Define an event handler for POST requests.
-    def post(path, options={}, &amp;b)
-      event(:post, path, options, &amp;b)
-    end
-
-    # Define an event handler for HEAD requests.
-    def head(path, options={}, &amp;b)
-      event(:head, path, options, &amp;b)
-    end
-
-    # Define an event handler for PUT requests.
-    #
-    # NOTE: PUT events are triggered when the HTTP request method is
-    # PUT and also when the request method is POST and the body includes a
-    # &quot;_method&quot; parameter set to &quot;PUT&quot;.
-    def put(path, options={}, &amp;b)
-      event(:put, path, options, &amp;b)
-    end
-
-    # Define an event handler for DELETE requests.
-    #
-    # NOTE: DELETE events are triggered when the HTTP request method is
-    # DELETE and also when the request method is POST and the body includes a
-    # &quot;_method&quot; parameter set to &quot;DELETE&quot;.
-    def delete(path, options={}, &amp;b)
-      event(:delete, path, options, &amp;b)
-    end
-
-    # Visits and invokes each handler registered for the +request_method+ in
-    # definition order until a Result response is produced. If no handler
-    # responds with a Result, the NotFound error handler is invoked.
-    #
-    # When the request_method is &quot;HEAD&quot; and no valid Result is produced by
-    # the set of handlers registered for HEAD requests, an attempt is made to
-    # invoke the GET handlers to generate the response before resorting to the
-    # default error handler.
-    def lookup(request)
-      method = request.request_method.downcase.to_sym
-      events[method].eject(&amp;[:invoke, request]) ||
-        (events[:get].eject(&amp;[:invoke, request]) if method == :head) ||
-        errors[NotFound].invoke(request)
-    end
-
-    # Define a named template. The template may be referenced from
-    # event handlers by passing the name as a Symbol to rendering
-    # methods. The block is executed each time the template is rendered
-    # and the resulting object is passed to the template handler.
-    #
-    # The following example defines a HAML template named hello and
-    # invokes it from an event handler:
-    #
-    #   template :hello do
-    #     &quot;h1 Hello World!&quot;
-    #   end
-    #
-    #   get '/' do
-    #     haml :hello
-    #   end
-    #
-    def template(name, &amp;b)
-      templates[name] = b
-    end
-
-    # Define a layout template.
-    def layout(name=:layout, &amp;b)
-      template(name, &amp;b)
-    end
-
-    # Define a custom error handler for the exception class +type+. The block
-    # is invoked when the specified exception type is raised from an error
-    # handler and can manipulate the response as needed:
-    #
-    #   error MyCustomError do
-    #     status 500
-    #     'So what happened was...' + request.env['sinatra.error'].message
-    #   end
-    #
-    # The Sinatra::ServerError handler is used by default when an exception
-    # occurs and no matching error handler is found.
-    def error(type=ServerError, options = {}, &amp;b)
-      errors[type] = Error.new(type, options, &amp;b)
-    end
-
-    # Define a custom error handler for '404 Not Found' responses. This is a
-    # shorthand for:
-    #   error NotFound do
-    #     ..
-    #   end
-    def not_found(options={}, &amp;b)
-      error NotFound, options, &amp;b
-    end
-
-    # Define a request filter. When &lt;tt&gt;type&lt;/tt&gt; is &lt;tt&gt;:before&lt;/tt&gt;, execute the
-    # block in the context of each request before matching event handlers.
-    def filter(type, &amp;b)
-      filters[type] &lt;&lt; b
-    end
-
-    # Invoke the block in the context of each request before invoking
-    # matching event handlers.
-    def before(&amp;b)
-      filter :before, &amp;b
-    end
-
-    # True when environment is :development.
-    def development? ; options.env == :development ; end
-
-    # True when environment is :test.
-    def test? ; options.env == :test ; end
-
-    # True when environment is :production.
-    def production? ; options.env == :production ; end
-
-    # Clear all events, templates, filters, and error handlers
-    # and then reload the application source file. This occurs
-    # automatically before each request is processed in development.
-    def reload!
-      clearables.each(&amp;:clear)
-      load_default_configuration!
-      load_development_configuration! if development?
-      @pipeline = nil
-      @reloading = true
-      Kernel.load options.app_file
-      @reloading = false
-    end
-
-    # Determine whether the application is in the process of being
-    # reloaded.
-    def reloading?
-      @reloading == true
-    end
-
-    # Mutex instance used for thread synchronization.
-    def mutex
-      @@mutex ||= Mutex.new
-    end
-
-    # Yield to the block with thread synchronization
-    def run_safely
-      if development? || options.mutex
-        mutex.synchronize { yield }
-      else
-        yield
-      end
-    end
-
-    # Add a piece of Rack middleware to the pipeline leading to the
-    # application.
-    def use(klass, *args, &amp;block)
-      fail &quot;#{klass} must respond to 'new'&quot; unless klass.respond_to?(:new)
-      @pipeline = nil
-      @middleware.push([ klass, args, block ]).last
-    end
-
-  private
-
-    # Rack middleware derived from current state of application options.
-    # These components are plumbed in at the very beginning of the
-    # pipeline.
-    def optional_middleware
-      [
-        ([ Rack::CommonLogger,    [], nil ] if options.logging),
-        ([ Rack::Session::Cookie, [], nil ] if options.sessions)
-      ].compact
-    end
-
-    # Rack middleware explicitly added to the application with #use. These
-    # components are plumbed into the pipeline downstream from
-    # #optional_middle.
-    def explicit_middleware
-      @middleware
-    end
-
-    # All Rack middleware used to construct the pipeline.
-    def middleware
-      optional_middleware + explicit_middleware
-    end
-
-  public
-
-    # An assembled pipeline of Rack middleware that leads eventually to
-    # the Application#invoke method. The pipeline is built upon first
-    # access. Defining new middleware with Application#use or manipulating
-    # application options may cause the pipeline to be rebuilt.
-    def pipeline
-      @pipeline ||=
-        middleware.inject(method(:dispatch)) do |app,(klass,args,block)|
-          klass.new(app, *args, &amp;block)
-        end
-    end
-
-    # Rack compatible request invocation interface.
-    def call(env)
-      run_safely do
-        reload! if development? &amp;&amp; (options.reload != false)
-        pipeline.call(env)
-      end
-    end
-
-    # Request invocation handler - called at the end of the Rack pipeline
-    # for each request.
-    #
-    # 1. Create Rack::Request, Rack::Response helper objects.
-    # 2. Lookup event handler based on request method and path.
-    # 3. Create new EventContext to house event handler evaluation.
-    # 4. Invoke each #before filter in context of EventContext object.
-    # 5. Invoke event handler in context of EventContext object.
-    # 6. Return response to Rack.
-    #
-    # See the Rack specification for detailed information on the
-    # +env+ argument and return value.
-    def dispatch(env)
-      request = Rack::Request.new(env)
-      context = EventContext.new(request, Rack::Response.new([], 200), {})
-      begin
-        returned =
-          catch(:halt) do
-            filters[:before].each { |f| context.instance_eval(&amp;f) }
-            result = lookup(context.request)
-            context.route_params = result.params
-            context.response.status = result.status
-            context.reset!
-            [:complete, context.instance_eval(&amp;result.block)]
-          end
-        body = returned.to_result(context)
-      rescue =&gt; e
-        request.env['sinatra.error'] = e
-        context.status(500)
-        raise if options.raise_errors &amp;&amp; e.class != NotFound
-        result = (errors[e.class] || errors[ServerError]).invoke(request)
-        returned =
-          catch(:halt) do
-            [:complete, context.instance_eval(&amp;result.block)]
-          end
-        body = returned.to_result(context)
-      end
-      body = '' unless body.respond_to?(:each)
-      body = '' if request.env[&quot;REQUEST_METHOD&quot;].upcase == 'HEAD'
-      context.body = body.kind_of?(String) ? [*body] : body
-      context.finish
-    end
-
-  private
-
-    # Called immediately after the application is initialized or reloaded to
-    # register default events, templates, and error handlers.
-    def load_default_configuration!
-      events[:get] &lt;&lt; Static.new
-      configure do
-        error do
-          '&lt;h1&gt;Internal Server Error&lt;/h1&gt;'
-        end
-        not_found { '&lt;h1&gt;Not Found&lt;/h1&gt;'}
-      end
-    end
-
-    # Called before reloading to perform development specific configuration.
-    def load_development_configuration!
-      get '/sinatra_custom_images/:image.png' do
-        content_type :png
-        File.read(File.dirname(__FILE__) + &quot;/../images/#{params[:image]}.png&quot;)
-      end
-
-      not_found do
-        (&lt;&lt;-HTML).gsub(/^ {8}/, '')
-        &lt;!DOCTYPE html&gt;
-        &lt;html&gt;
-          &lt;head&gt;
-            &lt;style type=&quot;text/css&quot;&gt;
-            body {text-align:center;color:#888;font-family:arial;font-size:22px;margin:20px;}
-            #content {margin:0 auto;width:500px;text-align:left}
-            &lt;/style&gt;
-          &lt;/head&gt;
-          &lt;body&gt;
-            &lt;h2&gt;Sinatra doesn't know this diddy.&lt;/h2&gt;
-            &lt;img src='/sinatra_custom_images/404.png'&gt;
-            &lt;div id=&quot;content&quot;&gt;
-              Try this:
-              &lt;pre&gt;#{request.request_method.downcase} &quot;#{request.path_info}&quot; do\n  .. do something ..\nend&lt;pre&gt;
-            &lt;/div&gt;
-          &lt;/body&gt;
-        &lt;/html&gt;
-        HTML
-      end
-
-      error do
-        @error = request.env['sinatra.error']
-        (&lt;&lt;-HTML).gsub(/^ {8}/, '')
-        &lt;!DOCTYPE html&gt;
-        &lt;html&gt;
-          &lt;head&gt;
-            &lt;style type=&quot;text/css&quot; media=&quot;screen&quot;&gt;
-              body {font-family:verdana;color:#333}
-              #content {width:700px;margin-left:20px}
-              #content h1 {width:99%;color:#1D6B8D;font-weight:bold}
-              #stacktrace {margin-top:-20px}
-              #stacktrace pre {font-size:12px;border-left:2px solid #ddd;padding-left:10px}
-              #stacktrace img {margin-top:10px}
-            &lt;/style&gt;
-          &lt;/head&gt;
-          &lt;body&gt;
-            &lt;div id=&quot;content&quot;&gt;
-              &lt;img src=&quot;/sinatra_custom_images/500.png&quot;&gt;
-              &lt;div class=&quot;info&quot;&gt;
-                Params: &lt;pre&gt;#{params.inspect}&lt;/pre&gt;
-              &lt;/div&gt;
-              &lt;div id=&quot;stacktrace&quot;&gt;
-                &lt;h1&gt;#{escape_html(@error.class.name + ' - ' + @error.message.to_s)}&lt;/h1&gt;
-                &lt;pre&gt;&lt;code&gt;#{escape_html(@error.backtrace.join(&quot;\n&quot;))}&lt;/code&gt;&lt;/pre&gt;
-              &lt;/div&gt;
-            &lt;/div&gt;
-          &lt;/body&gt;
-        &lt;/html&gt;
-        HTML
-      end
-    end
-
-  end
-
-end
-
-# Delegate DSLish methods to the currently active Sinatra::Application
-# instance.
-Sinatra::Application::FORWARD_METHODS.each do |method|
-  eval(&lt;&lt;-EOS, binding, '(__DSL__)', 1)
-    def #{method}(*args, &amp;b)
-      Sinatra.application.#{method}(*args, &amp;b)
-    end
-  EOS
-end
-
-def helpers(&amp;b)
-  Sinatra::EventContext.class_eval(&amp;b)
-end
-
-def use_in_file_templates!
-  require 'stringio'
-  templates = IO.read(caller.first.split(':').first).split('__FILE__').last
-  data = StringIO.new(templates)
-  current_template = nil
-  data.each do |line|
-    if line =~ /^@@\s?(.*)/
-      current_template = $1.to_sym
-      Sinatra.application.templates[current_template] = ''
-    elsif current_template
-      Sinatra.application.templates[current_template] &lt;&lt; line
-    end
-  end
-end
-
-def mime(ext, type)
-  Rack::File::MIME_TYPES[ext.to_s] = type
-end
-
-### Misc Core Extensions
-
-module Kernel
-  def silence_warnings
-    old_verbose, $VERBOSE = $VERBOSE, nil
-    yield
-  ensure
-    $VERBOSE = old_verbose
-  end
-end
-
-class Symbol
-  def to_proc
-    Proc.new { |*args| args.shift.__send__(self, *args) }
-  end
-end
-
-class Array
-  def to_hash
-    self.inject({}) { |h, (k, v)|  h[k] = v; h }
-  end
-  def to_proc
-    Proc.new { |*args| args.shift.__send__(self[0], *(args + self[1..-1])) }
-  end
-end
-
-module Enumerable
-  def eject(&amp;block)
-    find { |e| result = block[e] and break result }
-  end
-end
-
-### Core Extension results for throw :halt
-
-class Proc
-  def to_result(cx, *args)
-    cx.instance_eval(&amp;self)
-    args.shift.to_result(cx, *args)
-  end
-end
-
-class String
-  def to_result(cx, *args)
-    args.shift.to_result(cx, *args)
-    self
-  end
-end
-
-class Array
-  def to_result(cx, *args)
-    self.shift.to_result(cx, *self)
-  end
-end
-
-class Symbol
-  def to_result(cx, *args)
-    cx.send(self, *args)
-  end
-end
-
-class Fixnum
-  def to_result(cx, *args)
-    cx.status self
-    args.shift.to_result(cx, *args)
-  end
-end
-
-class NilClass
-  def to_result(cx, *args)
-    ''
-  end
-end
-
-at_exit do
-  raise $! if $!
-  if Sinatra.application.options.run
-    Sinatra.run
-  end
-end
-
-mime :xml, 'application/xml'
-mime :js,  'application/javascript'
-mime :png, 'image/png'
+use_in_file_templates!</diff>
      <filename>vendor/sinatra/lib/sinatra.rb</filename>
    </modified>
    <modified>
      <diff>@@ -1,10 +1,9 @@
-require File.dirname(__FILE__) + '/unit'
+require 'sinatra/test'
 require 'spec/interop/test'
 
-class Test::Unit::TestCase
-
-  def should
-    @response.should
-  end
-
-end
+Sinatra::Default.set(
+  :env =&gt; :test,
+  :run =&gt; false,
+  :raise_errors =&gt; true,
+  :logging =&gt; false
+)</diff>
      <filename>vendor/sinatra/lib/sinatra/test/rspec.rb</filename>
    </modified>
    <modified>
      <diff>@@ -1,10 +1,9 @@
-require File.dirname(__FILE__) + '/unit'
 require 'test/spec'
+require 'sinatra/test'
+require 'sinatra/test/unit'
 
-class Test::Unit::TestCase
-
+module Sinatra::Test
   def should
     @response.should
   end
-
 end</diff>
      <filename>vendor/sinatra/lib/sinatra/test/spec.rb</filename>
    </modified>
    <modified>
      <diff>@@ -1,13 +1,11 @@
+require 'sinatra/test'
 require 'test/unit'
-require File.dirname(__FILE__) + '/methods'
 
-Test::Unit::TestCase.send(:include, Sinatra::Test::Methods)
+Test::Unit::TestCase.send :include, Sinatra::Test
 
-Sinatra::Application.default_options.merge!(
+Sinatra::Default.set(
   :env =&gt; :test,
   :run =&gt; false,
   :raise_errors =&gt; true,
   :logging =&gt; false
 )
-
-Sinatra.application = nil</diff>
      <filename>vendor/sinatra/lib/sinatra/test/unit.rb</filename>
    </modified>
    <modified>
      <diff>@@ -3,74 +3,106 @@ Gem::Specification.new do |s|
   s.required_rubygems_version = Gem::Requirement.new(&quot;&gt;= 0&quot;) if s.respond_to? :required_rubygems_version=
 
   s.name = 'sinatra'
-  s.version = '0.3.0'
-  s.date = &quot;2008-08-31&quot;
+  s.version = '0.9.0.2'
+  s.date = '2009-01-18'
 
   s.description = &quot;Classy web-development dressed in a DSL&quot;
   s.summary     = &quot;Classy web-development dressed in a DSL&quot;
 
   s.authors = [&quot;Blake Mizerany&quot;]
+  s.email = &quot;sinatrarb@googlegroups.com&quot;
 
   # = MANIFEST =
   s.files = %w[
-    ChangeLog
+    AUTHORS
+    CHANGES
     LICENSE
     README.rdoc
     Rakefile
-    images/404.png
-    images/500.png
+    compat/app_test.rb
+    compat/application_test.rb
+    compat/builder_test.rb
+    compat/custom_error_test.rb
+    compat/erb_test.rb
+    compat/events_test.rb
+    compat/filter_test.rb
+    compat/haml_test.rb
+    compat/helper.rb
+    compat/mapped_error_test.rb
+    compat/pipeline_test.rb
+    compat/public/foo.xml
+    compat/sass_test.rb
+    compat/sessions_test.rb
+    compat/streaming_test.rb
+    compat/sym_params_test.rb
+    compat/template_test.rb
+    compat/use_in_file_templates_test.rb
+    compat/views/foo.builder
+    compat/views/foo.erb
+    compat/views/foo.haml
+    compat/views/foo.sass
+    compat/views/foo_layout.erb
+    compat/views/foo_layout.haml
+    compat/views/layout_test/foo.builder
+    compat/views/layout_test/foo.erb
+    compat/views/layout_test/foo.haml
+    compat/views/layout_test/foo.sass
+    compat/views/layout_test/layout.builder
+    compat/views/layout_test/layout.erb
+    compat/views/layout_test/layout.haml
+    compat/views/layout_test/layout.sass
+    compat/views/no_layout/no_layout.builder
+    compat/views/no_layout/no_layout.haml
     lib/sinatra.rb
-    lib/sinatra/rack/handler/mongrel.rb
-    lib/sinatra/test/methods.rb
+    lib/sinatra/base.rb
+    lib/sinatra/compat.rb
+    lib/sinatra/images/404.png
+    lib/sinatra/images/500.png
+    lib/sinatra/main.rb
+    lib/sinatra/test.rb
+    lib/sinatra/test/bacon.rb
     lib/sinatra/test/rspec.rb
     lib/sinatra/test/spec.rb
     lib/sinatra/test/unit.rb
     sinatra.gemspec
-    test/app_test.rb
-    test/application_test.rb
+    test/base_test.rb
     test/builder_test.rb
-    test/custom_error_test.rb
+    test/data/reload_app_file.rb
     test/erb_test.rb
-    test/event_context_test.rb
-    test/events_test.rb
     test/filter_test.rb
     test/haml_test.rb
     test/helper.rb
+    test/helpers_test.rb
     test/mapped_error_test.rb
-    test/pipeline_test.rb
-    test/public/foo.xml
+    test/middleware_test.rb
+    test/options_test.rb
+    test/reload_test.rb
+    test/request_test.rb
+    test/result_test.rb
+    test/routing_test.rb
     test/sass_test.rb
-    test/sessions_test.rb
-    test/streaming_test.rb
-    test/sym_params_test.rb
-    test/template_test.rb
-    test/use_in_file_templates_test.rb
-    test/views/foo.builder
-    test/views/foo.erb
-    test/views/foo.haml
-    test/views/foo.sass
-    test/views/foo_layout.erb
-    test/views/foo_layout.haml
-    test/views/layout_test/foo.builder
-    test/views/layout_test/foo.erb
-    test/views/layout_test/foo.haml
-    test/views/layout_test/foo.sass
-    test/views/layout_test/layout.builder
-    test/views/layout_test/layout.erb
-    test/views/layout_test/layout.haml
-    test/views/layout_test/layout.sass
-    test/views/no_layout/no_layout.builder
-    test/views/no_layout/no_layout.haml
+    test/sinatra_test.rb
+    test/static_test.rb
+    test/templates_test.rb
+    test/views/hello.builder
+    test/views/hello.erb
+    test/views/hello.haml
+    test/views/hello.sass
+    test/views/hello.test
+    test/views/layout2.builder
+    test/views/layout2.erb
+    test/views/layout2.haml
+    test/views/layout2.test
   ]
   # = MANIFEST =
 
   s.test_files = s.files.select {|path| path =~ /^test\/.*_test.rb/}
 
   s.extra_rdoc_files = %w[README.rdoc LICENSE]
-  s.add_dependency 'rack', '&gt;= 0.4.0'
+  s.add_dependency 'rack', '&gt;= 0.9.1'
 
   s.has_rdoc = true
-  s.homepage = &quot;http://sinatrarb.com&quot;
+  s.homepage = &quot;http://sinatra.rubyforge.org&quot;
   s.rdoc_options = [&quot;--line-numbers&quot;, &quot;--inline-source&quot;, &quot;--title&quot;, &quot;Sinatra&quot;, &quot;--main&quot;, &quot;README.rdoc&quot;]
   s.require_paths = %w[lib]
   s.rubyforge_project = 'sinatra'</diff>
      <filename>vendor/sinatra/sinatra.gemspec</filename>
    </modified>
    <modified>
      <diff>@@ -1,101 +1,64 @@
 require File.dirname(__FILE__) + '/helper'
 
-context &quot;Builder&quot; do
-
-  setup do
-    Sinatra.application = nil
+describe &quot;Builder Templates&quot; do
+  def builder_app(&amp;block)
+    mock_app {
+      set :views, File.dirname(__FILE__) + '/views'
+      get '/', &amp;block
+    }
+    get '/'
   end
 
-  context &quot;without layouts&quot; do
-
-    setup do
-      Sinatra.application = nil
-    end
-
-    specify &quot;should render&quot; do
-
-      get '/no_layout' do
-        builder 'xml.instruct!'
-      end
-
-      get_it '/no_layout'
-      should.be.ok
-      body.should == %(&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;\n)
-
-    end
-
-    specify &quot;should render inline block&quot; do
-
-      get '/no_layout_and_inlined' do
-        @name = &quot;Frank &amp; Mary&quot;
-        builder do |xml|
-          xml.couple @name
-        end
-      end
-
-      get_it '/no_layout_and_inlined'
-      should.be.ok
-      body.should == %(&lt;couple&gt;Frank &amp;amp; Mary&lt;/couple&gt;\n)
-
-    end
-
+  it 'renders inline Builder strings' do
+    builder_app { builder 'xml.instruct!' }
+    assert ok?
+    assert_equal %{&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;\n}, body
   end
 
-
-
-  context &quot;Templates (in general)&quot; do
-
-    setup do
-      Sinatra.application = nil
-    end
-
-    specify &quot;are read from files if Symbols&quot; do
-
-      get '/from_file' do
-        @name = 'Blue'
-        builder :foo, :views_directory =&gt; File.dirname(__FILE__) + &quot;/views&quot;
+  it 'renders inline blocks' do
+    builder_app {
+      @name = &quot;Frank &amp; Mary&quot;
+      builder do |xml|
+        xml.couple @name
       end
+    }
+    assert ok?
+    assert_equal &quot;&lt;couple&gt;Frank &amp;amp; Mary&lt;/couple&gt;\n&quot;, body
+  end
 
-      get_it '/from_file'
-      should.be.ok
-      body.should.equal %(&lt;exclaim&gt;You rock Blue!&lt;/exclaim&gt;\n)
-
-    end
-
-    specify &quot;use layout.ext by default if available&quot; do
-
-      get '/' do
-        builder :foo, :views_directory =&gt; File.dirname(__FILE__) + &quot;/views/layout_test&quot;
-      end
-
-      get_it '/'
-      should.be.ok
-      body.should.equal &quot;&lt;layout&gt;\n&lt;this&gt;is foo!&lt;/this&gt;\n&lt;/layout&gt;\n&quot;
-
-    end
-
-    specify &quot;renders without layout&quot; do
-
-      get '/' do
-        builder :no_layout, :views_directory =&gt; File.dirname(__FILE__) + &quot;/views/no_layout&quot;
-      end
-
-      get_it '/'
-      should.be.ok
-      body.should.equal &quot;&lt;foo&gt;No Layout!&lt;/foo&gt;\n&quot;
-
-    end
-
-    specify &quot;raises error if template not found&quot; do
+  it 'renders .builder files in views path' do
+    builder_app {
+      @name = &quot;Blue&quot;
+      builder :hello
+    }
+    assert ok?
+    assert_equal %(&lt;exclaim&gt;You're my boy, Blue!&lt;/exclaim&gt;\n), body
+  end
 
-      get '/' do
-        builder :not_found
+  it &quot;renders with inline layouts&quot; do
+    mock_app {
+      layout do
+        %(xml.layout { xml &lt;&lt; yield })
       end
+      get('/') { builder %(xml.em 'Hello World') }
+    }
+    get '/'
+    assert ok?
+    assert_equal &quot;&lt;layout&gt;\n&lt;em&gt;Hello World&lt;/em&gt;\n&lt;/layout&gt;\n&quot;, body
+  end
 
-      lambda { get_it '/' }.should.raise(Errno::ENOENT)
-
-    end
-
+  it &quot;renders with file layouts&quot; do
+    builder_app {
+      builder %(xml.em 'Hello World'), :layout =&gt; :layout2
+    }
+    assert ok?
+    assert_equal &quot;&lt;layout&gt;\n&lt;em&gt;Hello World&lt;/em&gt;\n&lt;/layout&gt;\n&quot;, body
   end
 
+  it &quot;raises error if template not found&quot; do
+    mock_app {
+      get('/') { builder :no_such_template }
+    }
+    assert_raise(Errno::ENOENT) { get('/') }
+  end
 end</diff>
      <filename>vendor/sinatra/test/builder_test.rb</filename>
    </modified>
    <modified>
      <diff>@@ -1,136 +1,50 @@
 require File.dirname(__FILE__) + '/helper'
 
-context &quot;Erb&quot; do
-
-  setup do
-    Sinatra.application = nil
+describe &quot;ERB Templates&quot; do
+  def erb_app(&amp;block)
+    mock_app {
+      set :views, File.dirname(__FILE__) + '/views'
+      get '/', &amp;block
+    }
+    get '/'
   end
 
-  context &quot;without layouts&quot; do
-
-    setup do
-      Sinatra.application = nil
-    end
-
-    specify &quot;should render&quot; do
-
-      get '/no_layout' do
-        erb '&lt;%= 1 + 1 %&gt;'
-      end
-
-      get_it '/no_layout'
-      should.be.ok
-      body.should == '2'
-
-    end
-
-    specify &quot;should take an options hash with :locals set with a string&quot; do
-      get '/locals' do
-        erb '&lt;%= foo %&gt;', :locals =&gt; {:foo =&gt; &quot;Bar&quot;}
-      end
-
-      get_it '/locals'
-      should.be.ok
-      body.should == 'Bar'
-    end
-
-    specify &quot;should take an options hash with :locals set with a complex object&quot; do
-      get '/locals-complex' do
-        erb '&lt;%= foo[0] %&gt;', :locals =&gt; {:foo =&gt; [&quot;foo&quot;, &quot;bar&quot;, &quot;baz&quot;]}
-      end
-
-      get_it '/locals-complex'
-      should.be.ok
-      body.should == 'foo'
-    end
+  it 'renders inline ERB strings' do
+    erb_app { erb '&lt;%= 1 + 1 %&gt;' }
+    assert ok?
+    assert_equal '2', body
   end
 
-  context &quot;with layouts&quot; do
-
-    setup do
-      Sinatra.application = nil
-    end
-
-    specify &quot;can be inline&quot; do
-
-      layout do
-        %Q{This is &lt;%= yield %&gt;!}
-      end
-
-      get '/lay' do
-        erb 'Blake'
-      end
-
-      get_it '/lay'
-      should.be.ok
-      body.should.equal 'This is Blake!'
-
-    end
-
-    specify &quot;can use named layouts&quot; do
-
-      layout :pretty do
-        %Q{&lt;h1&gt;&lt;%= yield %&gt;&lt;/h1&gt;}
-      end
-
-      get '/pretty' do
-        erb 'Foo', :layout =&gt; :pretty
-      end
-
-      get '/not_pretty' do
-        erb 'Bar'
-      end
-
-      get_it '/pretty'
-      body.should.equal '&lt;h1&gt;Foo&lt;/h1&gt;'
-
-      get_it '/not_pretty'
-      body.should.equal 'Bar'
-
-    end
-
-    specify &quot;can be read from a file if they're not inlined&quot; do
-
-      get '/foo' do
-        @title = 'Welcome to the Hello Program'
-        erb 'Blake', :layout =&gt; :foo_layout,
-                     :views_directory =&gt; File.dirname(__FILE__) + &quot;/views&quot;
-      end
-
-      get_it '/foo'
-      body.should.equal &quot;Welcome to the Hello Program\nHi Blake\n&quot;
-
-    end
-
+  it 'renders .erb files in views path' do
+    erb_app { erb :hello }
+    assert ok?
+    assert_equal &quot;Hello World\n&quot;, body
   end
 
-  context &quot;Templates (in general)&quot; do
-
-    specify &quot;are read from files if Symbols&quot; do
-
-      get '/from_file' do
-        @name = 'Alena'
-        erb :foo, :views_directory =&gt; File.dirname(__FILE__) + &quot;/views&quot;
-      end
-
-      get_it '/from_file'
-
-      body.should.equal 'You rock Alena!'
-
-    end
-
-    specify &quot;use layout.ext by default if available&quot; do
-
-      get '/layout_from_file' do
-        erb :foo, :views_directory =&gt; File.dirname(__FILE__) + &quot;/views/layout_test&quot;
-      end
-
-      get_it '/layout_from_file'
-      should.be.ok
-      body.should.equal &quot;x This is foo! x \n&quot;
-
-    end
+  it 'takes a :locals option' do
+    erb_app {
+      locals = {:foo =&gt; 'Bar'}
+      erb '&lt;%= foo %&gt;', :locals =&gt; locals
+    }
+    assert ok?
+    assert_equal 'Bar', body
+  end
 
+  it &quot;renders with inline layouts&quot; do
+    mock_app {
+      layout { 'THIS. IS. &lt;%= yield.upcase %&gt;!' }
+      get('/') { erb 'Sparta' }
+    }
+    get '/'
+    assert ok?
+    assert_equal 'THIS. IS. SPARTA!', body
   end
 
+  it &quot;renders with file layouts&quot; do
+    erb_app {
+      erb 'Hello World', :layout =&gt; :layout2
+    }
+    assert ok?
+    assert_equal &quot;ERB Layout!\nHello World\n&quot;, body
+  end
 end</diff>
      <filename>vendor/sinatra/test/erb_test.rb</filename>
    </modified>
    <modified>
      <diff>@@ -1,30 +1,75 @@
 require File.dirname(__FILE__) + '/helper'
 
-context &quot;before filters&quot; do
+describe &quot;Filters&quot; do
+  it &quot;executes filters in the order defined&quot; do
+    count = 0
+    mock_app do
+      get('/') { 'Hello World' }
+      before {
+        assert_equal 0, count
+        count = 1
+      }
+      before {
+        assert_equal 1, count
+        count = 2
+      }
+    end
 
-  setup do
-    Sinatra.application = nil
-    @app = Sinatra.application
+    get '/'
+    assert ok?
+    assert_equal 2, count
+    assert_equal 'Hello World', body
   end
 
-  specify &quot;should be executed in the order defined&quot; do
-    invoked = 0x0
-    @app.before { invoked = 0x01 }
-    @app.before { invoked |= 0x02 }
-    @app.get('/') { 'Hello World' }
-    get_it '/'
-    should.be.ok
-    body.should.be == 'Hello World'
-    invoked.should.be == 0x03
+  it &quot;allows filters to modify the request&quot; do
+    mock_app {
+      get('/foo') { 'foo' }
+      get('/bar') { 'bar' }
+      before { request.path_info = '/bar' }
+    }
+
+    get '/foo'
+    assert ok?
+    assert_equal 'bar', body
   end
 
-  specify &quot;should be capable of modifying the request&quot; do
-    @app.get('/foo') { 'foo' }
-    @app.get('/bar') { 'bar' }
-    @app.before { request.path_info = '/bar' }
-    get_it '/foo'
-    should.be.ok
-    body.should.be == 'bar'
+  it &quot;can modify instance variables available to routes&quot; do
+    mock_app {
+      before { @foo = 'bar' }
+      get('/foo') { @foo }
+    }
+
+    get '/foo'
+    assert ok?
+    assert_equal 'bar', body
   end
 
+  it &quot;allows redirects in filters&quot; do
+    mock_app {
+      before { redirect '/bar' }
+      get('/foo') do
+        fail 'before block should have halted processing'
+        'ORLY?!'
+      end
+    }
+
+    get '/foo'
+    assert redirect?
+    assert_equal '/bar', response['Location']
+    assert_equal '', body
+  end
+
+  it &quot;does not modify the response with its return value&quot; do
+    mock_app {
+      before { 'Hello World!' }
+      get '/foo' do
+        assert_equal [], response.body
+        'cool'
+      end
+    }
+
+    get '/foo'
+    assert ok?
+    assert_equal 'cool', body
+  end
 end</diff>
      <filename>vendor/sinatra/test/filter_test.rb</filename>
    </modified>
    <modified>
      <diff>@@ -1,233 +1,68 @@
 require File.dirname(__FILE__) + '/helper'
 
-context &quot;Haml&quot; do
-
-  setup do
-    Sinatra.application = nil
+describe &quot;HAML Templates&quot; do
+  def haml_app(&amp;block)
+    mock_app {
+      set :views, File.dirname(__FILE__) + '/views'
+      get '/', &amp;block
+    }
+    get '/'
   end
 
-  context &quot;without layouts&quot; do
-
-    setup do
-      Sinatra.application = nil
-    end
-
-    specify &quot;should render&quot; do
-
-      get '/no_layout' do
-        haml '== #{1+1}'
-      end
-
-      get_it '/no_layout'
-      should.be.ok
-      body.should == &quot;2\n&quot;
-
-    end
+  it 'renders inline HAML strings' do
+    haml_app { haml '%h1 Hiya' }
+    assert ok?
+    assert_equal &quot;&lt;h1&gt;Hiya&lt;/h1&gt;\n&quot;, body
   end
 
-  context &quot;with layouts&quot; do
-
-    setup do
-      Sinatra.application = nil
-    end
-
-    specify &quot;can be inline&quot; do
-
-      layout do
-        '== This is #{yield}!'
-      end
-
-      get '/lay' do
-        haml 'Blake'
-      end
-
-      get_it '/lay'
-      should.be.ok
-      body.should.equal &quot;This is Blake\n!\n&quot;
-
-    end
-
-    specify &quot;can use named layouts&quot; do
-
-      layout :pretty do
-        '%h1== #{yield}'
-      end
-
-      get '/pretty' do
-        haml 'Foo', :layout =&gt; :pretty
-      end
-
-      get '/not_pretty' do
-        haml 'Bar'
-      end
-
-      get_it '/pretty'
-      body.should.equal &quot;&lt;h1&gt;Foo&lt;/h1&gt;\n&quot;
-
-      get_it '/not_pretty'
-      body.should.equal &quot;Bar\n&quot;
-
-    end
-
-    specify &quot;can be read from a file if they're not inlined&quot; do
-
-      get '/foo' do
-        @title = 'Welcome to the Hello Program'
-        haml 'Blake', :layout =&gt; :foo_layout,
-                      :views_directory =&gt; File.dirname(__FILE__) + &quot;/views&quot;
-      end
-
-      get_it '/foo'
-      body.should.equal &quot;Welcome to the Hello Program\nHi Blake\n&quot;
-
-    end
-
-    specify &quot;can be read from file and layout from text&quot; do
-      get '/foo' do
-        haml 'Test', :layout =&gt; '== Foo #{yield}'
-      end
-
-      get_it '/foo'
-
-      body.should.equal &quot;Foo Test\n&quot;
-    end
-
+  it 'renders .haml files in views path' do
+    haml_app { haml :hello }
+    assert ok?
+    assert_equal &quot;&lt;h1&gt;Hello From Haml&lt;/h1&gt;\n&quot;, body
   end
 
-  context &quot;Templates (in general)&quot; do
-
-    setup do
-      Sinatra.application = nil
-    end
-
-    specify &quot;are read from files if Symbols&quot; do
-
-      get '/from_file' do
-        @name = 'Alena'
-        haml :foo, :views_directory =&gt; File.dirname(__FILE__) + &quot;/views&quot;
-      end
-
-      get_it '/from_file'
-
-      body.should.equal &quot;You rock Alena!\n&quot;
-
-    end
-
-    specify &quot;use layout.ext by default if available&quot; do
-
-      get '/' do
-        haml :foo, :views_directory =&gt; File.dirname(__FILE__) + &quot;/views/layout_test&quot;
-      end
-
-      get_it '/'
-      should.be.ok
-      body.should.equal &quot;x This is foo!\n x\n&quot;
-
-    end
-
-    specify &quot;renders without layout&quot; do
-
-      get '/' do
-        haml :no_layout, :views_directory =&gt; File.dirname(__FILE__) + &quot;/views/no_layout&quot;
-      end
-
-      get_it '/'
-      should.be.ok
-      body.should.equal &quot;&lt;h1&gt;No Layout!&lt;/h1&gt;\n&quot;
-
-    end
-
-    specify &quot;can render with no layout&quot; do
-      layout do
-        &quot;X\n= yield\nX&quot;
-      end
-
-      get '/' do
-        haml 'blake', :layout =&gt; false
-      end
-
-      get_it '/'
-
-      body.should.equal &quot;blake\n&quot;
-    end
-
-    specify &quot;raises error if template not found&quot; do
-      get '/' do
-        haml :not_found
-      end
-
-      lambda { get_it '/' }.should.raise(Errno::ENOENT)
-    end
-
-    specify &quot;use layout.ext by default if available&quot; do
-
-      template :foo do
-        'asdf'
-      end
-
-      get '/' do
-        haml :foo, :layout =&gt; false,
-                   :views_directory =&gt; File.dirname(__FILE__) + &quot;/views/layout_test&quot;
-      end
-
-      get_it '/'
-      should.be.ok
-      body.should.equal &quot;asdf\n&quot;
-
-    end
-
+  it &quot;renders with inline layouts&quot; do
+    mock_app {
+      layout { %q(%h1= 'THIS. IS. ' + yield.upcase) }
+      get('/') { haml '%em Sparta' }
+    }
+    get '/'
+    assert ok?
+    assert_equal &quot;&lt;h1&gt;THIS. IS. &lt;EM&gt;SPARTA&lt;/EM&gt;&lt;/h1&gt;\n&quot;, body
   end
 
-  describe 'Options passed to the HAML interpreter' do
-    setup do
-      Sinatra.application = nil
-    end
-
-    specify 'are empty be default' do
-
-      get '/' do
-        haml 'foo'
-      end
-
-      Haml::Engine.expects(:new).with('foo', {}).returns(stub(:render =&gt; 'foo'))
-
-      get_it '/'
-      should.be.ok
-
-    end
-
-    specify 'can be configured by passing :options to haml' do
-
-      get '/' do
-        haml 'foo', :options =&gt; {:format =&gt; :html4}
-      end
-
-      Haml::Engine.expects(:new).with('foo', {:format =&gt; :html4}).returns(stub(:render =&gt; 'foo'))
-
-      get_it '/'
-      should.be.ok
-
-    end
+  it &quot;renders with file layouts&quot; do
+    haml_app {
+      haml 'Hello World', :layout =&gt; :layout2
+    }
+    assert ok?
+    assert_equal &quot;&lt;h1&gt;HAML Layout!&lt;/h1&gt;\n&lt;p&gt;Hello World&lt;/p&gt;\n&quot;, body
+  end
 
-    specify 'can be configured using set_option :haml' do
+  it &quot;raises error if template not found&quot; do
+    mock_app {
+      get('/') { haml :no_such_template }
+    }
+    assert_raise(Errno::ENOENT) { get('/') }
+  end
 
-      configure do
-        set_option :haml, :format       =&gt; :html4,
-                          :escape_html  =&gt; true
-      end
+  it &quot;passes HAML options to the Haml engine&quot; do
+    haml_app {
+      haml &quot;!!!\n%h1 Hello World&quot;, :options =&gt; {:format =&gt; :html5}
+    }
+    assert ok?
+    assert_equal &quot;&lt;!DOCTYPE html&gt;\n&lt;h1&gt;Hello World&lt;/h1&gt;\n&quot;, body
+  end
 
+  it &quot;passes default HAML options to the Haml engine&quot; do
+    mock_app {
+      set :haml, {:format =&gt; :html5}
       get '/' do
-        haml 'foo'
+        haml &quot;!!!\n%h1 Hello World&quot;
       end
-
-      Haml::Engine.expects(:new).with('foo', {:format =&gt; :html4,
-        :escape_html =&gt; true}).returns(stub(:render =&gt; 'foo'))
-
-      get_it '/'
-      should.be.ok
-
-    end
-
+    }
+    get '/'
+    assert ok?
+    assert_equal &quot;&lt;!DOCTYPE html&gt;\n&lt;h1&gt;Hello World&lt;/h1&gt;\n&quot;, body
   end
-
 end</diff>
      <filename>vendor/sinatra/test/haml_test.rb</filename>
    </modified>
    <modified>
      <diff>@@ -1,7 +1,25 @@
-require 'rubygems'
-require 'mocha'
+begin
+  require 'test/spec'
+rescue LoadError
+  require 'rubygems'
+  require 'test/spec'
+end
 
-$:.unshift File.dirname(File.dirname(__FILE__)) + &quot;/lib&quot;
-
-require 'sinatra'
+$:.unshift File.dirname(File.dirname(__FILE__)) + '/lib'
+require 'sinatra/base'
+require 'sinatra/test'
 require 'sinatra/test/spec'
+
+module Sinatra::Test
+  # Sets up a Sinatra::Base subclass defined with the block
+  # given. Used in setup or individual spec methods to establish
+  # the application.
+  def mock_app(base=Sinatra::Base, &amp;block)
+    @app = Sinatra.new(base, &amp;block)
+  end
+end
+
+class Sinatra::Base
+  # Allow assertions in request context
+  include Test::Unit::Assertions
+end</diff>
      <filename>vendor/sinatra/test/helper.rb</filename>
    </modified>
    <modified>
      <diff>@@ -1,72 +1,160 @@
 require File.dirname(__FILE__) + '/helper'
 
-class FooError &lt; RuntimeError; end
-
-context &quot;Mapped errors&quot; do
-
-  setup do
-    Sinatra.application = nil
-    Sinatra.application.options.raise_errors = false
+describe 'Exception Mappings' do
+  class FooError &lt; RuntimeError
   end
 
-  specify &quot;are rescued and run in context&quot; do
-
-    error FooError do
-      'MAPPED ERROR!'
-    end
-
-    get '/' do
-      raise FooError
-    end
-
-    get_it '/'
-
-    should.be.server_error
-    body.should.equal 'MAPPED ERROR!'
-
+  it 'invokes handlers registered with ::error when raised' do
+    mock_app {
+      set :raise_errors, false
+      error(FooError) { 'Foo!' }
+      get '/' do
+        raise FooError
+      end
+    }
+    get '/'
+    assert_equal 500, status
+    assert_equal 'Foo!', body
   end
 
-  specify &quot;renders empty if no each method on result&quot; do
+  it 'uses the Exception handler if no matching handler found' do
+    mock_app {
+      set :raise_errors, false
+      error(Exception) { 'Exception!' }
+      get '/' do
+        raise FooError
+      end
+    }
+    get '/'
+    assert_equal 500, status
+    assert_equal 'Exception!', body
+  end
 
-    error FooError do
-      nil
-    end
+  it &quot;sets env['sinatra.error'] to the rescued exception&quot; do
+    mock_app {
+      set :raise_errors, false
+      error(FooError) {
+        assert env.include?('sinatra.error')
+        assert env['sinatra.error'].kind_of?(FooError)
+        'looks good'
+      }
+      get '/' do
+        raise FooError
+      end
+    }
+    get '/'
+    assert_equal 'looks good', body
+  end
 
-    get '/' do
-      raise FooError
-    end
+  it 'dumps errors to rack.errors when dump_errors is enabled' do
+    mock_app {
+      set :raise_errors, false
+      set :dump_errors, true
+      get('/') { raise FooError, 'BOOM!' }
+    }
 
-    get_it '/'
+    get '/'
+    assert_equal 500, status
+    assert @response.errors =~ /FooError - BOOM!:/
+  end
 
-    should.be.server_error
-    body.should.be.empty
+  it &quot;raises without calling the handler when the raise_errors options is set&quot; do
+    mock_app {
+      set :raise_errors, true
+      error(FooError) { &quot;she's not there.&quot; }
+      get '/' do
+        raise FooError
+      end
+    }
+    assert_raise(FooError) { get '/' }
+  end
 
+  it &quot;never raises Sinatra::NotFound beyond the application&quot; do
+    mock_app {
+      set :raise_errors, true
+      get '/' do
+        raise Sinatra::NotFound
+      end
+    }
+    assert_nothing_raised { get '/' }
+    assert_equal 404, status
   end
 
-  specify &quot;doesn't override status if set&quot; do
+  class FooNotFound &lt; Sinatra::NotFound
+  end
 
-    error FooError do
-      status(200)
-    end
+  it &quot;cascades for subclasses of Sinatra::NotFound&quot; do
+    mock_app {
+      set :raise_errors, true
+      error(FooNotFound) { &quot;foo! not found.&quot; }
+      get '/' do
+        raise FooNotFound
+      end
+    }
+    assert_nothing_raised { get '/' }
+    assert_equal 404, status
+    assert_equal 'foo! not found.', body
+  end
 
-    get '/' do
-      raise FooError
-    end
+  it 'has a not_found method for backwards compatibility' do
+    mock_app {
+      not_found do
+        &quot;Lost, are we?&quot;
+      end
+    }
 
-    get_it '/'
+    get '/test'
+    assert_equal 404, status
+    assert_equal &quot;Lost, are we?&quot;, body
+  end
+end
 
-    should.be.ok
+describe 'Custom Error Pages' do
+  it 'allows numeric status code mappings to be registered with ::error' do
+    mock_app {
+      set :raise_errors, false
+      error(500) { 'Foo!' }
+      get '/' do
+        [500, {}, 'Internal Foo Error']
+      end
+    }
+    get '/'
+    assert_equal 500, status
+    assert_equal 'Foo!', body
+  end
 
+  it 'allows ranges of status code mappings to be registered with :error' do
+    mock_app {
+      set :raise_errors, false
+      error(500..550) { &quot;Error: #{response.status}&quot; }
+      get '/' do
+        [507, {}, 'A very special error']
+      end
+    }
+    get '/'
+    assert_equal 507, status
+    assert_equal 'Error: 507', body
   end
 
-  specify &quot;raises errors when the raise_errors option is set&quot; do
-    Sinatra.application.options.raise_errors = true
-    error FooError do
-    end
-    get '/' do
-      raise FooError
-    end
-    assert_raises(FooError) { get_it('/') }
+  class FooError &lt; RuntimeError
   end
 
+  it 'runs after exception mappings and overwrites body' do
+    mock_app {
+      set :raise_errors, false
+      error FooError do
+        response.status = 502
+        'from exception mapping'
+      end
+      error(500) { 'from 500 handler' }
+      error(502) { 'from custom error page' }
+
+      get '/' do
+        raise FooError
+      end
+    }
+    get '/'
+    assert_equal 502, status
+    assert_equal 'from custom error page', body
+  end
 end</diff>
      <filename>vendor/sinatra/test/mapped_error_test.rb</filename>
    </modified>
    <modified>
      <diff>@@ -1,57 +1,36 @@
 require File.dirname(__FILE__) + '/helper'
 
-context &quot;Sass&quot; do
-
-  setup do
-    Sinatra.application = nil
+describe &quot;Sass Templates&quot; do
+  def sass_app(&amp;block)
+    mock_app {
+      set :views, File.dirname(__FILE__) + '/views'
+      get '/', &amp;block
+    }
+    get '/'
   end
 
-  context &quot;Templates (in general)&quot; do
-
-    setup do
-      Sinatra.application = nil
-    end
-
-    specify &quot;are read from files if Symbols&quot; do
-
-      get '/from_file' do
-        sass :foo, :views_directory =&gt; File.dirname(__FILE__) + &quot;/views&quot;
-      end
-
-      get_it '/from_file'
-      should.be.ok
-      body.should.equal &quot;#sass {\n  background_color: #FFF; }\n&quot;
-
-    end
-
-    specify &quot;raise an error if template not found&quot; do
-      get '/' do
-        sass :not_found
-      end
-
-      lambda { get_it '/' }.should.raise(Errno::ENOENT)
-    end
-
-    specify &quot;ignore default layout file with .sass extension&quot; do
-      get '/' do
-        sass :foo, :views_directory =&gt; File.dirname(__FILE__) + &quot;/views/layout_test&quot;
-      end
-
-      get_it '/'
-      should.be.ok
-      body.should.equal &quot;#sass {\n  background_color: #FFF; }\n&quot;
-    end
-
-    specify &quot;ignore explicitly specified layout file&quot; do
-      get '/' do
-        sass :foo, :layout =&gt; :layout, :views_directory =&gt; File.dirname(__FILE__) + &quot;/views/layout_test&quot;
-      end
+  it 'renders inline Sass strings' do
+    sass_app { sass &quot;#sass\n  :background-color #FFF\n&quot; }
+    assert ok?
+    assert_equal &quot;#sass {\n  background-color: #FFF; }\n&quot;, body
+  end
 
-      get_it '/'
-      should.be.ok
-      body.should.equal &quot;#sass {\n  background_color: #FFF; }\n&quot;
-    end
+  it 'renders .sass files in views path' do
+    sass_app { sass :hello }
+    assert ok?
+    assert_equal &quot;#sass {\n  background-color: #FFF; }\n&quot;, body
+  end
 
+  it 'ignores the layout option' do
+    sass_app { sass :hello, :layout =&gt; :layout2 }
+    assert ok?
+    assert_equal &quot;#sass {\n  background-color: #FFF; }\n&quot;, body
   end
 
+  it &quot;raises error if template not found&quot; do
+    mock_app {
+      get('/') { sass :no_such_template }
+    }
+    assert_raise(Errno::ENOENT) { get('/') }
+  end
 end</diff>
      <filename>vendor/sinatra/test/sass_test.rb</filename>
    </modified>
  </modified>
  <removed type="array">
    <removed>
      <filename>vendor/sinatra/.gitignore</filename>
    </removed>
    <removed>
      <filename>vendor/sinatra/.gitmodules</filename>
    </removed>
    <removed>
      <filename>vendor/sinatra/CHANGELOG</filename>
    </removed>
    <removed>
      <filename>vendor/sinatra/images/404.png</filename>
    </removed>
    <removed>
      <filename>vendor/sinatra/images/500.png</filename>
    </removed>
    <removed>
      <filename>vendor/sinatra/lib/sinatra/rack/handler/mongrel.rb</filename>
    </removed>
    <removed>
      <filename>vendor/sinatra/lib/sinatra/test/methods.rb</filename>
    </removed>
    <removed>
      <filename>vendor/sinatra/test/app_test.rb</filename>
    </removed>
    <removed>
      <filename>vendor/sinatra/test/application_test.rb</filename>
    </removed>
    <removed>
      <filename>vendor/sinatra/test/custom_error_test.rb</filename>
    </removed>
    <removed>
      <filename>vendor/sinatra/test/event_context_test.rb</filename>
    </removed>
    <removed>
      <filename>vendor/sinatra/test/events_test.rb</filename>
    </removed>
    <removed>
      <filename>vendor/sinatra/test/pipeline_test.rb</filename>
    </removed>
    <removed>
      <filename>vendor/sinatra/test/public/foo.xml</filename>
    </removed>
    <removed>
      <filename>vendor/sinatra/test/sessions_test.rb</filename>
    </removed>
    <removed>
      <filename>vendor/sinatra/test/streaming_test.rb</filename>
    </removed>
    <removed>
      <filename>vendor/sinatra/test/sym_params_test.rb</filename>
    </removed>
    <removed>
      <filename>vendor/sinatra/test/template_test.rb</filename>
    </removed>
    <removed>
      <filename>vendor/sinatra/test/use_in_file_templates_test.rb</filename>
    </removed>
    <removed>
      <filename>vendor/sinatra/test/views/foo.builder</filename>
    </removed>
    <removed>
      <filename>vendor/sinatra/test/views/foo.erb</filename>
    </removed>
    <removed>
      <filename>vendor/sinatra/test/views/foo.haml</filename>
    </removed>
    <removed>
      <filename>vendor/sinatra/test/views/foo.sass</filename>
    </removed>
    <removed>
      <filename>vendor/sinatra/test/views/foo_layout.erb</filename>
    </removed>
    <removed>
      <filename>vendor/sinatra/test/views/foo_layout.haml</filename>
    </removed>
    <removed>
      <filename>vendor/sinatra/test/views/layout_test/foo.builder</filename>
    </removed>
    <removed>
      <filename>vendor/sinatra/test/views/layout_test/foo.erb</filename>
    </removed>
    <removed>
      <filename>vendor/sinatra/test/views/layout_test/foo.haml</filename>
    </removed>
    <removed>
      <filename>vendor/sinatra/test/views/layout_test/foo.sass</filename>
    </removed>
    <removed>
      <filename>vendor/sinatra/test/views/layout_test/layout.builder</filename>
    </removed>
    <removed>
      <filename>vendor/sinatra/test/views/layout_test/layout.erb</filename>
    </removed>
    <removed>
      <filename>vendor/sinatra/test/views/layout_test/layout.haml</filename>
    </removed>
    <removed>
      <filename>vendor/sinatra/test/views/layout_test/layout.sass</filename>
    </removed>
    <removed>
      <filename>vendor/sinatra/test/views/no_layout/no_layout.builder</filename>
    </removed>
    <removed>
      <filename>vendor/sinatra/test/views/no_layout/no_layout.haml</filename>
    </removed>
  </removed>
  <parents type="array">
    <parent>
      <id>ab968d0de2057940dbc08351b8dfaec564e9322a</id>
    </parent>
  </parents>
  <author>
    <name>Aaron Bedra</name>
    <email>aaron@thinkrelevance.com</email>
  </author>
  <url>http://github.com/relevance/castronaut/commit/bcbef1f0c6c94e26a29dd36491623a3d679c3d8c</url>
  <id>bcbef1f0c6c94e26a29dd36491623a3d679c3d8c</id>
  <committed-date>2009-01-24T10:46:05-08:00</committed-date>
  <authored-date>2009-01-24T10:46:05-08:00</authored-date>
  <message>upgraded sinatra and rack to latest versions</message>
  <tree>167ba6c990cb23604690ed95f851ef0dabfc6913</tree>
  <committer>
    <name>Aaron Bedra</name>
    <email>aaron@thinkrelevance.com</email>
  </committer>
</commit>
