rackables 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README +6 -0
 - data/Rakefile +22 -0
 - data/VERSION +1 -0
 - data/lib/rackables.rb +6 -0
 - data/lib/rackables/cache_control.rb +21 -0
 - data/lib/rackables/default_charset.rb +19 -0
 - data/lib/rackables/public_exception_page.rb +72 -0
 - data/lib/rackables/trailing_slash_redirect.rb +20 -0
 - data/test/fixtures/custom_500.html +1 -0
 - data/test/test_cache_control.rb +27 -0
 - data/test/test_default_charset.rb +27 -0
 - data/test/test_public_exception_page.rb +30 -0
 - data/test/test_trailing_slash_redirect.rb +39 -0
 - metadata +70 -0
 
    
        data/README
    ADDED
    
    
    
        data/Rakefile
    ADDED
    
    | 
         @@ -0,0 +1,22 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'rake/testtask'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            Rake::TestTask.new do |t|
         
     | 
| 
      
 4 
     | 
    
         
            +
              t.libs << "test"
         
     | 
| 
      
 5 
     | 
    
         
            +
              t.test_files = FileList['test/test*.rb']
         
     | 
| 
      
 6 
     | 
    
         
            +
              t.verbose = true
         
     | 
| 
      
 7 
     | 
    
         
            +
            end
         
     | 
| 
      
 8 
     | 
    
         
            +
            task :default => :test
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
            begin
         
     | 
| 
      
 11 
     | 
    
         
            +
              require 'jeweler'
         
     | 
| 
      
 12 
     | 
    
         
            +
              Jeweler::Tasks.new do |gemspec|
         
     | 
| 
      
 13 
     | 
    
         
            +
                gemspec.name = "rackables"
         
     | 
| 
      
 14 
     | 
    
         
            +
                gemspec.summary = "Bundle of useful Rack middleware"
         
     | 
| 
      
 15 
     | 
    
         
            +
                gemspec.description = "Bundles Rack middleware: CacheControl, DefaultCharset, PublicExceptionPage, TrailingSlashRedirect"
         
     | 
| 
      
 16 
     | 
    
         
            +
                gemspec.email = "gbuesing@gmail.com"
         
     | 
| 
      
 17 
     | 
    
         
            +
                gemspec.homepage = "http://github.com/gbuesing/rackables"
         
     | 
| 
      
 18 
     | 
    
         
            +
                gemspec.authors = ["Geoff Buesing"]
         
     | 
| 
      
 19 
     | 
    
         
            +
              end
         
     | 
| 
      
 20 
     | 
    
         
            +
            rescue LoadError
         
     | 
| 
      
 21 
     | 
    
         
            +
              puts "Jeweler not available. Install it with: gem install jeweler"
         
     | 
| 
      
 22 
     | 
    
         
            +
            end
         
     | 
    
        data/VERSION
    ADDED
    
    | 
         @@ -0,0 +1 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            0.1.0
         
     | 
    
        data/lib/rackables.rb
    ADDED
    
    
| 
         @@ -0,0 +1,21 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Rackables
         
     | 
| 
      
 2 
     | 
    
         
            +
              class CacheControl
         
     | 
| 
      
 3 
     | 
    
         
            +
                # Works well with Varnish
         
     | 
| 
      
 4 
     | 
    
         
            +
                # TODO: accomodate more options than just public, max-age=
         
     | 
| 
      
 5 
     | 
    
         
            +
                def initialize(app, value, opts)
         
     | 
| 
      
 6 
     | 
    
         
            +
                  @app = app
         
     | 
| 
      
 7 
     | 
    
         
            +
                  @value = value
         
     | 
| 
      
 8 
     | 
    
         
            +
                  @opts = opts
         
     | 
| 
      
 9 
     | 
    
         
            +
                end
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
                def call(env)
         
     | 
| 
      
 12 
     | 
    
         
            +
                  status, headers, body = @app.call(env)
         
     | 
| 
      
 13 
     | 
    
         
            +
                  if headers['Cache-Control'].nil?
         
     | 
| 
      
 14 
     | 
    
         
            +
                    max_age = @opts[:max_age]
         
     | 
| 
      
 15 
     | 
    
         
            +
                    max_age = max_age.call if max_age.respond_to?(:call)
         
     | 
| 
      
 16 
     | 
    
         
            +
                    headers['Cache-Control'] = "#{@value}, max-age=#{max_age}"
         
     | 
| 
      
 17 
     | 
    
         
            +
                  end
         
     | 
| 
      
 18 
     | 
    
         
            +
                  [status, headers, body]
         
     | 
| 
      
 19 
     | 
    
         
            +
                end
         
     | 
| 
      
 20 
     | 
    
         
            +
              end
         
     | 
| 
      
 21 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,19 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Rackables
         
     | 
| 
      
 2 
     | 
    
         
            +
              class DefaultCharset
         
     | 
| 
      
 3 
     | 
    
         
            +
                HAS_CHARSET = /charset=/
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
                def initialize(app, value = 'utf-8')
         
     | 
| 
      
 6 
     | 
    
         
            +
                  @app = app
         
     | 
| 
      
 7 
     | 
    
         
            +
                  @value = value
         
     | 
| 
      
 8 
     | 
    
         
            +
                end
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
                def call(env)
         
     | 
| 
      
 11 
     | 
    
         
            +
                  status, headers, body = @app.call(env)
         
     | 
| 
      
 12 
     | 
    
         
            +
                  content_type = headers['Content-Type']
         
     | 
| 
      
 13 
     | 
    
         
            +
                  if content_type && content_type !~ HAS_CHARSET
         
     | 
| 
      
 14 
     | 
    
         
            +
                    headers['Content-Type'] = "#{content_type}; charset=#{@value}"
         
     | 
| 
      
 15 
     | 
    
         
            +
                  end
         
     | 
| 
      
 16 
     | 
    
         
            +
                  [status, headers, body]
         
     | 
| 
      
 17 
     | 
    
         
            +
                end
         
     | 
| 
      
 18 
     | 
    
         
            +
              end
         
     | 
| 
      
 19 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,72 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Rackables
         
     | 
| 
      
 2 
     | 
    
         
            +
              # Returns a user-friendly exception page
         
     | 
| 
      
 3 
     | 
    
         
            +
              # Should be included at the very top of the middleware pipeline so that unhandled exceptions from anywhere down the pipeline are rescued
         
     | 
| 
      
 4 
     | 
    
         
            +
              # In development, you'd want to use Rack::ShowExceptions instead of this (config.ru example):
         
     | 
| 
      
 5 
     | 
    
         
            +
              #
         
     | 
| 
      
 6 
     | 
    
         
            +
              #   if ENV['RACK_ENV'] == 'development'
         
     | 
| 
      
 7 
     | 
    
         
            +
              #     use Rack::ShowExceptions
         
     | 
| 
      
 8 
     | 
    
         
            +
              #   else
         
     | 
| 
      
 9 
     | 
    
         
            +
              #     use Rackables::PublicExceptionPage
         
     | 
| 
      
 10 
     | 
    
         
            +
              #   end
         
     | 
| 
      
 11 
     | 
    
         
            +
              #
         
     | 
| 
      
 12 
     | 
    
         
            +
              # The default HTML included here is a copy of the 500 page included with Rails
         
     | 
| 
      
 13 
     | 
    
         
            +
              # You can optionally specify your own file, ex:
         
     | 
| 
      
 14 
     | 
    
         
            +
              #
         
     | 
| 
      
 15 
     | 
    
         
            +
              #   use Rackables::PublicExceptionPage, "public/500.html"
         
     | 
| 
      
 16 
     | 
    
         
            +
              class PublicExceptionPage
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
                def initialize(app, file_path = nil)
         
     | 
| 
      
 19 
     | 
    
         
            +
                  @app = app
         
     | 
| 
      
 20 
     | 
    
         
            +
                  @file_path = file_path
         
     | 
| 
      
 21 
     | 
    
         
            +
                end
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
                def call(env)
         
     | 
| 
      
 24 
     | 
    
         
            +
                  @app.call(env)
         
     | 
| 
      
 25 
     | 
    
         
            +
                rescue ::Exception
         
     | 
| 
      
 26 
     | 
    
         
            +
                  [500, {'Content-Type' => 'text/html', 'Content-Length' => html.length.to_s}, [html]]
         
     | 
| 
      
 27 
     | 
    
         
            +
                end
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
                private
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
                  def html
         
     | 
| 
      
 32 
     | 
    
         
            +
                    @html ||= @file_path ? ::File.read(@file_path) : default_html
         
     | 
| 
      
 33 
     | 
    
         
            +
                  end
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
      
 35 
     | 
    
         
            +
                  # Exception page from Rails (500.html)
         
     | 
| 
      
 36 
     | 
    
         
            +
                  def default_html
         
     | 
| 
      
 37 
     | 
    
         
            +
                    <<-EOV
         
     | 
| 
      
 38 
     | 
    
         
            +
                    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
         
     | 
| 
      
 39 
     | 
    
         
            +
                           "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
         
     | 
| 
      
 40 
     | 
    
         
            +
             
     | 
| 
      
 41 
     | 
    
         
            +
                    <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
         
     | 
| 
      
 42 
     | 
    
         
            +
             
     | 
| 
      
 43 
     | 
    
         
            +
                    <head>
         
     | 
| 
      
 44 
     | 
    
         
            +
                      <meta http-equiv="content-type" content="text/html; charset=UTF-8" />
         
     | 
| 
      
 45 
     | 
    
         
            +
                      <title>We're sorry, but something went wrong (500)</title>
         
     | 
| 
      
 46 
     | 
    
         
            +
                    	<style type="text/css">
         
     | 
| 
      
 47 
     | 
    
         
            +
                    		body { background-color: #fff; color: #666; text-align: center; font-family: arial, sans-serif; }
         
     | 
| 
      
 48 
     | 
    
         
            +
                    		div.dialog {
         
     | 
| 
      
 49 
     | 
    
         
            +
                    			width: 25em;
         
     | 
| 
      
 50 
     | 
    
         
            +
                    			padding: 0 4em;
         
     | 
| 
      
 51 
     | 
    
         
            +
                    			margin: 4em auto 0 auto;
         
     | 
| 
      
 52 
     | 
    
         
            +
                    			border: 1px solid #ccc;
         
     | 
| 
      
 53 
     | 
    
         
            +
                    			border-right-color: #999;
         
     | 
| 
      
 54 
     | 
    
         
            +
                    			border-bottom-color: #999;
         
     | 
| 
      
 55 
     | 
    
         
            +
                    		}
         
     | 
| 
      
 56 
     | 
    
         
            +
                    		h1 { font-size: 100%; color: #f00; line-height: 1.5em; }
         
     | 
| 
      
 57 
     | 
    
         
            +
                    	</style>
         
     | 
| 
      
 58 
     | 
    
         
            +
                    </head>
         
     | 
| 
      
 59 
     | 
    
         
            +
             
     | 
| 
      
 60 
     | 
    
         
            +
                    <body>
         
     | 
| 
      
 61 
     | 
    
         
            +
                      <!-- This file lives in public/500.html -->
         
     | 
| 
      
 62 
     | 
    
         
            +
                      <div class="dialog">
         
     | 
| 
      
 63 
     | 
    
         
            +
                        <h1>We're sorry, but something went wrong.</h1>
         
     | 
| 
      
 64 
     | 
    
         
            +
                        <p>We've been notified about this issue and we'll take a look at it shortly.</p>
         
     | 
| 
      
 65 
     | 
    
         
            +
                      </div>
         
     | 
| 
      
 66 
     | 
    
         
            +
                    </body>
         
     | 
| 
      
 67 
     | 
    
         
            +
                    </html>
         
     | 
| 
      
 68 
     | 
    
         
            +
                    EOV
         
     | 
| 
      
 69 
     | 
    
         
            +
                  end
         
     | 
| 
      
 70 
     | 
    
         
            +
             
     | 
| 
      
 71 
     | 
    
         
            +
              end
         
     | 
| 
      
 72 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,20 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Rackables
         
     | 
| 
      
 2 
     | 
    
         
            +
              class TrailingSlashRedirect
         
     | 
| 
      
 3 
     | 
    
         
            +
                HAS_TRAILING_SLASH = %r{^/(.*)/$}
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
                def initialize(app)
         
     | 
| 
      
 6 
     | 
    
         
            +
                  @app = app
         
     | 
| 
      
 7 
     | 
    
         
            +
                end
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
                def call(env)
         
     | 
| 
      
 10 
     | 
    
         
            +
                  if env['PATH_INFO'] =~ HAS_TRAILING_SLASH
         
     | 
| 
      
 11 
     | 
    
         
            +
                    location = "#{env['rack.url_scheme']}://#{env['HTTP_HOST']}/#{$1}"
         
     | 
| 
      
 12 
     | 
    
         
            +
                    location = "#{location}?#{env['QUERY_STRING']}" if env['QUERY_STRING'].to_s =~ /\S/
         
     | 
| 
      
 13 
     | 
    
         
            +
                    [301, {"Location" => location}, []]
         
     | 
| 
      
 14 
     | 
    
         
            +
                  else
         
     | 
| 
      
 15 
     | 
    
         
            +
                    @app.call(env)
         
     | 
| 
      
 16 
     | 
    
         
            +
                  end
         
     | 
| 
      
 17 
     | 
    
         
            +
                end
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
              end
         
     | 
| 
      
 20 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            <h1>Custom 500 page</h1>
         
     | 
| 
         @@ -0,0 +1,27 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'test/unit'
         
     | 
| 
      
 2 
     | 
    
         
            +
            require 'rackables'
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
            class TestCacheControl < Test::Unit::TestCase
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
              def test_sets_cache_control
         
     | 
| 
      
 7 
     | 
    
         
            +
                app = Proc.new { [200, {}, []]}
         
     | 
| 
      
 8 
     | 
    
         
            +
                middleware = Rackables::CacheControl.new(app, :public, :max_age => 5)
         
     | 
| 
      
 9 
     | 
    
         
            +
                status, headers, body = middleware.call({})
         
     | 
| 
      
 10 
     | 
    
         
            +
                assert_equal 'public, max-age=5', headers['Cache-Control']
         
     | 
| 
      
 11 
     | 
    
         
            +
              end
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
              def test_sets_cache_control_with_value_specified_as_proc
         
     | 
| 
      
 14 
     | 
    
         
            +
                app = Proc.new { [200, {}, []]}
         
     | 
| 
      
 15 
     | 
    
         
            +
                middleware = Rackables::CacheControl.new(app, :public, :max_age => Proc.new {5})
         
     | 
| 
      
 16 
     | 
    
         
            +
                status, headers, body = middleware.call({})
         
     | 
| 
      
 17 
     | 
    
         
            +
                assert_equal 'public, max-age=5', headers['Cache-Control']
         
     | 
| 
      
 18 
     | 
    
         
            +
              end
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
              def test_respects_existing_cache_control_value
         
     | 
| 
      
 21 
     | 
    
         
            +
                app = Proc.new { [200, {'Cache-Control' => 'private'}, []]}
         
     | 
| 
      
 22 
     | 
    
         
            +
                middleware = Rackables::CacheControl.new(app, :public, :max_age => 5)
         
     | 
| 
      
 23 
     | 
    
         
            +
                status, headers, body = middleware.call({})
         
     | 
| 
      
 24 
     | 
    
         
            +
                assert_equal 'private', headers['Cache-Control']
         
     | 
| 
      
 25 
     | 
    
         
            +
              end
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,27 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'test/unit'
         
     | 
| 
      
 2 
     | 
    
         
            +
            require 'rackables'
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
            class TestDefaultCharset < Test::Unit::TestCase
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
              def test_adds_utf8_charset_by_default
         
     | 
| 
      
 7 
     | 
    
         
            +
                app = Proc.new { [200, {'Content-Type' => 'text/html'}, []]}
         
     | 
| 
      
 8 
     | 
    
         
            +
                middleware = Rackables::DefaultCharset.new(app)
         
     | 
| 
      
 9 
     | 
    
         
            +
                status, headers, body = middleware.call({})
         
     | 
| 
      
 10 
     | 
    
         
            +
                assert_equal 'text/html; charset=utf-8', headers['Content-Type']
         
     | 
| 
      
 11 
     | 
    
         
            +
              end
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
              def test_adds_specified_charset
         
     | 
| 
      
 14 
     | 
    
         
            +
                app = Proc.new { [200, {'Content-Type' => 'text/html'}, []]}
         
     | 
| 
      
 15 
     | 
    
         
            +
                middleware = Rackables::DefaultCharset.new(app, 'us-ascii')
         
     | 
| 
      
 16 
     | 
    
         
            +
                status, headers, body = middleware.call({})
         
     | 
| 
      
 17 
     | 
    
         
            +
                assert_equal 'text/html; charset=us-ascii', headers['Content-Type']
         
     | 
| 
      
 18 
     | 
    
         
            +
              end
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
              def test_does_not_overwrite_existing_charset_value
         
     | 
| 
      
 21 
     | 
    
         
            +
                app = Proc.new { [200, {'Content-Type' => 'text/html; charset=us-ascii'}, []]}
         
     | 
| 
      
 22 
     | 
    
         
            +
                middleware = Rackables::DefaultCharset.new(app, 'iso-8859-2')
         
     | 
| 
      
 23 
     | 
    
         
            +
                status, headers, body = middleware.call({})
         
     | 
| 
      
 24 
     | 
    
         
            +
                assert_equal 'text/html; charset=us-ascii', headers['Content-Type']
         
     | 
| 
      
 25 
     | 
    
         
            +
              end
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,30 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'test/unit'
         
     | 
| 
      
 2 
     | 
    
         
            +
            require 'rackables'
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
            class TestPublicExceptionPage < Test::Unit::TestCase
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
              def test_returns_downstream_app_response_when_no_exception_raised
         
     | 
| 
      
 7 
     | 
    
         
            +
                app = Proc.new { [200, {'Content-Type' => 'text/html'}, ['Downstream app']]}
         
     | 
| 
      
 8 
     | 
    
         
            +
                middleware = Rackables::PublicExceptionPage.new(app)
         
     | 
| 
      
 9 
     | 
    
         
            +
                status, headers, body = middleware.call({})
         
     | 
| 
      
 10 
     | 
    
         
            +
                assert_equal 200, status
         
     | 
| 
      
 11 
     | 
    
         
            +
                assert_equal ['Downstream app'], body
         
     | 
| 
      
 12 
     | 
    
         
            +
              end
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
              def test_returns_500_with_default_exception_page_when_exception_raised_by_downstream_app
         
     | 
| 
      
 15 
     | 
    
         
            +
                app = Proc.new { raise }
         
     | 
| 
      
 16 
     | 
    
         
            +
                middleware = Rackables::PublicExceptionPage.new(app)
         
     | 
| 
      
 17 
     | 
    
         
            +
                status, headers, body = middleware.call({})
         
     | 
| 
      
 18 
     | 
    
         
            +
                assert_equal 500, status
         
     | 
| 
      
 19 
     | 
    
         
            +
                assert_match /We\'re sorry, but something went wrong/, body[0]
         
     | 
| 
      
 20 
     | 
    
         
            +
              end
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
              def test_returns_500_with_custom_exception_page_when_file_path_specified
         
     | 
| 
      
 23 
     | 
    
         
            +
                app = Proc.new { raise }
         
     | 
| 
      
 24 
     | 
    
         
            +
                middleware = Rackables::PublicExceptionPage.new(app, 'test/fixtures/custom_500.html')
         
     | 
| 
      
 25 
     | 
    
         
            +
                status, headers, body = middleware.call({})
         
     | 
| 
      
 26 
     | 
    
         
            +
                assert_equal 500, status
         
     | 
| 
      
 27 
     | 
    
         
            +
                assert_match /Custom 500 page/, body[0]
         
     | 
| 
      
 28 
     | 
    
         
            +
              end
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,39 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'test/unit'
         
     | 
| 
      
 2 
     | 
    
         
            +
            require 'rackables'
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
            class TestTrailingSlashRedirect < Test::Unit::TestCase
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
              def test_passes_to_downstream_app_when_no_trailing_slash_on_path_info
         
     | 
| 
      
 7 
     | 
    
         
            +
                app = Proc.new { [200, {'Content-Type' => 'text/html'}, ['Downstream app']]}
         
     | 
| 
      
 8 
     | 
    
         
            +
                middleware = Rackables::TrailingSlashRedirect.new(app)
         
     | 
| 
      
 9 
     | 
    
         
            +
                status, headers, body = middleware.call({'PATH_INFO' => '/foo'})
         
     | 
| 
      
 10 
     | 
    
         
            +
                assert_equal 200, status
         
     | 
| 
      
 11 
     | 
    
         
            +
                assert_equal ['Downstream app'], body
         
     | 
| 
      
 12 
     | 
    
         
            +
                assert_nil headers['Location']
         
     | 
| 
      
 13 
     | 
    
         
            +
              end
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
              def test_returns_301_when_trailing_slash_on_path_info
         
     | 
| 
      
 16 
     | 
    
         
            +
                app = Proc.new { [200, {'Content-Type' => 'text/html'}, ['Downstream app']]}
         
     | 
| 
      
 17 
     | 
    
         
            +
                middleware = Rackables::TrailingSlashRedirect.new(app)
         
     | 
| 
      
 18 
     | 
    
         
            +
                status, headers, body = middleware.call({'rack.url_scheme' => 'http', 'HTTP_HOST' => 'bar.com', 'PATH_INFO' => '/foo/'})
         
     | 
| 
      
 19 
     | 
    
         
            +
                assert_equal 301, status
         
     | 
| 
      
 20 
     | 
    
         
            +
                assert_equal 'http://bar.com/foo', headers['Location']
         
     | 
| 
      
 21 
     | 
    
         
            +
              end
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
              def test_301_respects_query_string
         
     | 
| 
      
 24 
     | 
    
         
            +
                app = Proc.new { [200, {'Content-Type' => 'text/html'}, ['Downstream app']]}
         
     | 
| 
      
 25 
     | 
    
         
            +
                middleware = Rackables::TrailingSlashRedirect.new(app)
         
     | 
| 
      
 26 
     | 
    
         
            +
                status, headers, body = middleware.call({'rack.url_scheme' => 'http', 'HTTP_HOST' => 'bar.com', 'PATH_INFO' => '/foo/', 'QUERY_STRING' => 'baz=hi'})
         
     | 
| 
      
 27 
     | 
    
         
            +
                assert_equal 301, status
         
     | 
| 
      
 28 
     | 
    
         
            +
                assert_equal 'http://bar.com/foo?baz=hi', headers['Location']
         
     | 
| 
      
 29 
     | 
    
         
            +
              end
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
              def test_301_respects_https
         
     | 
| 
      
 32 
     | 
    
         
            +
                app = Proc.new { [200, {'Content-Type' => 'text/html'}, ['Downstream app']]}
         
     | 
| 
      
 33 
     | 
    
         
            +
                middleware = Rackables::TrailingSlashRedirect.new(app)
         
     | 
| 
      
 34 
     | 
    
         
            +
                status, headers, body = middleware.call({'rack.url_scheme' => 'https', 'HTTP_HOST' => 'bar.com', 'PATH_INFO' => '/foo/', 'QUERY_STRING' => 'baz=hi'})
         
     | 
| 
      
 35 
     | 
    
         
            +
                assert_equal 301, status
         
     | 
| 
      
 36 
     | 
    
         
            +
                assert_equal 'https://bar.com/foo?baz=hi', headers['Location']
         
     | 
| 
      
 37 
     | 
    
         
            +
              end
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
      
 39 
     | 
    
         
            +
            end
         
     | 
    
        metadata
    ADDED
    
    | 
         @@ -0,0 +1,70 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            --- !ruby/object:Gem::Specification 
         
     | 
| 
      
 2 
     | 
    
         
            +
            name: rackables
         
     | 
| 
      
 3 
     | 
    
         
            +
            version: !ruby/object:Gem::Version 
         
     | 
| 
      
 4 
     | 
    
         
            +
              version: 0.1.0
         
     | 
| 
      
 5 
     | 
    
         
            +
            platform: ruby
         
     | 
| 
      
 6 
     | 
    
         
            +
            authors: 
         
     | 
| 
      
 7 
     | 
    
         
            +
            - Geoff Buesing
         
     | 
| 
      
 8 
     | 
    
         
            +
            autorequire: 
         
     | 
| 
      
 9 
     | 
    
         
            +
            bindir: bin
         
     | 
| 
      
 10 
     | 
    
         
            +
            cert_chain: []
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
            date: 2010-01-12 00:00:00 -06:00
         
     | 
| 
      
 13 
     | 
    
         
            +
            default_executable: 
         
     | 
| 
      
 14 
     | 
    
         
            +
            dependencies: []
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
            description: "Bundles Rack middleware: CacheControl, DefaultCharset, PublicExceptionPage, TrailingSlashRedirect"
         
     | 
| 
      
 17 
     | 
    
         
            +
            email: gbuesing@gmail.com
         
     | 
| 
      
 18 
     | 
    
         
            +
            executables: []
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
            extensions: []
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
            extra_rdoc_files: 
         
     | 
| 
      
 23 
     | 
    
         
            +
            - README
         
     | 
| 
      
 24 
     | 
    
         
            +
            files: 
         
     | 
| 
      
 25 
     | 
    
         
            +
            - README
         
     | 
| 
      
 26 
     | 
    
         
            +
            - Rakefile
         
     | 
| 
      
 27 
     | 
    
         
            +
            - VERSION
         
     | 
| 
      
 28 
     | 
    
         
            +
            - lib/rackables.rb
         
     | 
| 
      
 29 
     | 
    
         
            +
            - lib/rackables/cache_control.rb
         
     | 
| 
      
 30 
     | 
    
         
            +
            - lib/rackables/default_charset.rb
         
     | 
| 
      
 31 
     | 
    
         
            +
            - lib/rackables/public_exception_page.rb
         
     | 
| 
      
 32 
     | 
    
         
            +
            - lib/rackables/trailing_slash_redirect.rb
         
     | 
| 
      
 33 
     | 
    
         
            +
            - test/fixtures/custom_500.html
         
     | 
| 
      
 34 
     | 
    
         
            +
            - test/test_cache_control.rb
         
     | 
| 
      
 35 
     | 
    
         
            +
            - test/test_default_charset.rb
         
     | 
| 
      
 36 
     | 
    
         
            +
            - test/test_public_exception_page.rb
         
     | 
| 
      
 37 
     | 
    
         
            +
            - test/test_trailing_slash_redirect.rb
         
     | 
| 
      
 38 
     | 
    
         
            +
            has_rdoc: true
         
     | 
| 
      
 39 
     | 
    
         
            +
            homepage: http://github.com/gbuesing/rackables
         
     | 
| 
      
 40 
     | 
    
         
            +
            licenses: []
         
     | 
| 
      
 41 
     | 
    
         
            +
             
     | 
| 
      
 42 
     | 
    
         
            +
            post_install_message: 
         
     | 
| 
      
 43 
     | 
    
         
            +
            rdoc_options: 
         
     | 
| 
      
 44 
     | 
    
         
            +
            - --charset=UTF-8
         
     | 
| 
      
 45 
     | 
    
         
            +
            require_paths: 
         
     | 
| 
      
 46 
     | 
    
         
            +
            - lib
         
     | 
| 
      
 47 
     | 
    
         
            +
            required_ruby_version: !ruby/object:Gem::Requirement 
         
     | 
| 
      
 48 
     | 
    
         
            +
              requirements: 
         
     | 
| 
      
 49 
     | 
    
         
            +
              - - ">="
         
     | 
| 
      
 50 
     | 
    
         
            +
                - !ruby/object:Gem::Version 
         
     | 
| 
      
 51 
     | 
    
         
            +
                  version: "0"
         
     | 
| 
      
 52 
     | 
    
         
            +
              version: 
         
     | 
| 
      
 53 
     | 
    
         
            +
            required_rubygems_version: !ruby/object:Gem::Requirement 
         
     | 
| 
      
 54 
     | 
    
         
            +
              requirements: 
         
     | 
| 
      
 55 
     | 
    
         
            +
              - - ">="
         
     | 
| 
      
 56 
     | 
    
         
            +
                - !ruby/object:Gem::Version 
         
     | 
| 
      
 57 
     | 
    
         
            +
                  version: "0"
         
     | 
| 
      
 58 
     | 
    
         
            +
              version: 
         
     | 
| 
      
 59 
     | 
    
         
            +
            requirements: []
         
     | 
| 
      
 60 
     | 
    
         
            +
             
     | 
| 
      
 61 
     | 
    
         
            +
            rubyforge_project: 
         
     | 
| 
      
 62 
     | 
    
         
            +
            rubygems_version: 1.3.5
         
     | 
| 
      
 63 
     | 
    
         
            +
            signing_key: 
         
     | 
| 
      
 64 
     | 
    
         
            +
            specification_version: 3
         
     | 
| 
      
 65 
     | 
    
         
            +
            summary: Bundle of useful Rack middleware
         
     | 
| 
      
 66 
     | 
    
         
            +
            test_files: 
         
     | 
| 
      
 67 
     | 
    
         
            +
            - test/test_cache_control.rb
         
     | 
| 
      
 68 
     | 
    
         
            +
            - test/test_default_charset.rb
         
     | 
| 
      
 69 
     | 
    
         
            +
            - test/test_public_exception_page.rb
         
     | 
| 
      
 70 
     | 
    
         
            +
            - test/test_trailing_slash_redirect.rb
         
     |