rack-cors 2.0.0 → 2.0.2
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +9 -1
- data/README.md +6 -8
- data/lib/rack/cors/resource.rb +12 -2
- data/lib/rack/cors/version.rb +1 -1
- metadata +9 -38
- data/.rubocop.yml +0 -31
- data/.travis.yml +0 -13
- data/Gemfile +0 -8
- data/Rakefile +0 -22
- data/rack-cors.gemspec +0 -30
- data/test/.rubocop.yml +0 -8
- data/test/cors/expect.js +0 -1286
- data/test/cors/mocha.css +0 -250
- data/test/cors/mocha.js +0 -5373
- data/test/cors/runner.html +0 -20
- data/test/cors/test.cors.coffee +0 -49
- data/test/cors/test.cors.js +0 -79
- data/test/unit/cors_test.rb +0 -540
- data/test/unit/dsl_test.rb +0 -70
- data/test/unit/insecure.ru +0 -10
- data/test/unit/non_http.ru +0 -10
- data/test/unit/test.ru +0 -66
    
        data/test/cors/runner.html
    DELETED
    
    | @@ -1,20 +0,0 @@ | |
| 1 | 
            -
            <html>
         | 
| 2 | 
            -
            <head>
         | 
| 3 | 
            -
              <meta charset="utf-8">
         | 
| 4 | 
            -
              <title>Mocha Tests</title>
         | 
| 5 | 
            -
              <link rel="stylesheet" href="mocha.css" />
         | 
| 6 | 
            -
            </head>
         | 
| 7 | 
            -
            <body>
         | 
| 8 | 
            -
              <div id="mocha"></div>
         | 
| 9 | 
            -
              <script src="http://ajax.googleapis.com/ajax/libs/jquery/2.0.2/jquery.min.js"></script>
         | 
| 10 | 
            -
              <script src="expect.js"></script>
         | 
| 11 | 
            -
              <script src="mocha.js"></script>
         | 
| 12 | 
            -
              <script>mocha.setup('bdd')</script>
         | 
| 13 | 
            -
              <script src="test.cors.js"></script>
         | 
| 14 | 
            -
              <script>
         | 
| 15 | 
            -
                mocha.checkLeaks();
         | 
| 16 | 
            -
                mocha.globals(['jQuery']);
         | 
| 17 | 
            -
                mocha.run();
         | 
| 18 | 
            -
              </script>
         | 
| 19 | 
            -
            </body>
         | 
| 20 | 
            -
            </html>
         | 
    
        data/test/cors/test.cors.coffee
    DELETED
    
    | @@ -1,49 +0,0 @@ | |
| 1 | 
            -
            CORS_SERVER = '127.0.0.1.xip.io:3000'
         | 
| 2 | 
            -
             | 
| 3 | 
            -
            mocha.setup({ignoreLeaks: true});
         | 
| 4 | 
            -
             | 
| 5 | 
            -
            describe 'CORS', ->
         | 
| 6 | 
            -
             | 
| 7 | 
            -
              it 'should allow access to dynamic resource', (done) ->
         | 
| 8 | 
            -
                $.get "http://#{CORS_SERVER}/", (data, status, xhr) ->
         | 
| 9 | 
            -
                  expect(data).to.eql('Hello world')
         | 
| 10 | 
            -
                  done()
         | 
| 11 | 
            -
             | 
| 12 | 
            -
              it 'should allow PUT access to dynamic resource', (done) ->
         | 
| 13 | 
            -
                $.ajax("http://#{CORS_SERVER}/", type: 'PUT').done (data, textStatus, jqXHR) ->
         | 
| 14 | 
            -
                  expect(data).to.eql('Hello world')
         | 
| 15 | 
            -
                  done()
         | 
| 16 | 
            -
             | 
| 17 | 
            -
              it 'should allow PATCH access to dynamic resource', (done) ->
         | 
| 18 | 
            -
                $.ajax("http://#{CORS_SERVER}/", type: 'PATCH').done (data, textStatus, jqXHR) ->
         | 
| 19 | 
            -
                  expect(data).to.eql('Hello world')
         | 
| 20 | 
            -
                  done()
         | 
| 21 | 
            -
             | 
| 22 | 
            -
              it 'should allow HEAD access to dynamic resource', (done) ->
         | 
| 23 | 
            -
                $.ajax("http://#{CORS_SERVER}/", type: 'HEAD').done (data, textStatus, jqXHR) ->
         | 
| 24 | 
            -
                  expect(jqXHR.status).to.eql(200)
         | 
| 25 | 
            -
                  done()
         | 
| 26 | 
            -
             | 
| 27 | 
            -
              it 'should allow DELETE access to dynamic resource', (done) ->
         | 
| 28 | 
            -
                $.ajax("http://#{CORS_SERVER}/", type: 'DELETE').done (data, textStatus, jqXHR) ->
         | 
| 29 | 
            -
                  expect(data).to.eql('Hello world')
         | 
| 30 | 
            -
                  done()
         | 
| 31 | 
            -
             | 
| 32 | 
            -
              it 'should allow OPTIONS access to dynamic resource', (done) ->
         | 
| 33 | 
            -
                $.ajax("http://#{CORS_SERVER}/", type: 'OPTIONS').done (data, textStatus, jqXHR) ->
         | 
| 34 | 
            -
                  expect(jqXHR.status).to.eql(200)
         | 
| 35 | 
            -
                  done()
         | 
| 36 | 
            -
             | 
| 37 | 
            -
              it 'should allow access to static resource', (done) ->
         | 
| 38 | 
            -
                $.get "http://#{CORS_SERVER}/static.txt", (data, status, xhr) ->
         | 
| 39 | 
            -
                  expect($.trim(data)).to.eql("Hello world")
         | 
| 40 | 
            -
                  done()
         | 
| 41 | 
            -
             | 
| 42 | 
            -
              it 'should allow post resource', (done) ->
         | 
| 43 | 
            -
                $.ajax
         | 
| 44 | 
            -
                  type: 'POST'
         | 
| 45 | 
            -
                  url: "http://#{CORS_SERVER}/cors"
         | 
| 46 | 
            -
                  beforeSend: (xhr) -> xhr.setRequestHeader('X-Requested-With', 'XMLHTTPRequest')
         | 
| 47 | 
            -
                  success:(data, status, xhr) ->
         | 
| 48 | 
            -
                    expect($.trim(data)).to.eql("OK!")
         | 
| 49 | 
            -
                    done()
         | 
    
        data/test/cors/test.cors.js
    DELETED
    
    | @@ -1,79 +0,0 @@ | |
| 1 | 
            -
            // Generated by CoffeeScript 2.3.1
         | 
| 2 | 
            -
            (function() {
         | 
| 3 | 
            -
              var CORS_SERVER;
         | 
| 4 | 
            -
             | 
| 5 | 
            -
              CORS_SERVER = '127.0.0.1.xip.io:3000';
         | 
| 6 | 
            -
             | 
| 7 | 
            -
              mocha.setup({
         | 
| 8 | 
            -
                ignoreLeaks: true
         | 
| 9 | 
            -
              });
         | 
| 10 | 
            -
             | 
| 11 | 
            -
              describe('CORS', function() {
         | 
| 12 | 
            -
                it('should allow access to dynamic resource', function(done) {
         | 
| 13 | 
            -
                  return $.get(`http://${CORS_SERVER}/`, function(data, status, xhr) {
         | 
| 14 | 
            -
                    expect(data).to.eql('Hello world');
         | 
| 15 | 
            -
                    return done();
         | 
| 16 | 
            -
                  });
         | 
| 17 | 
            -
                });
         | 
| 18 | 
            -
                it('should allow PUT access to dynamic resource', function(done) {
         | 
| 19 | 
            -
                  return $.ajax(`http://${CORS_SERVER}/`, {
         | 
| 20 | 
            -
                    type: 'PUT'
         | 
| 21 | 
            -
                  }).done(function(data, textStatus, jqXHR) {
         | 
| 22 | 
            -
                    expect(data).to.eql('Hello world');
         | 
| 23 | 
            -
                    return done();
         | 
| 24 | 
            -
                  });
         | 
| 25 | 
            -
                });
         | 
| 26 | 
            -
                it('should allow PATCH access to dynamic resource', function(done) {
         | 
| 27 | 
            -
                  return $.ajax(`http://${CORS_SERVER}/`, {
         | 
| 28 | 
            -
                    type: 'PATCH'
         | 
| 29 | 
            -
                  }).done(function(data, textStatus, jqXHR) {
         | 
| 30 | 
            -
                    expect(data).to.eql('Hello world');
         | 
| 31 | 
            -
                    return done();
         | 
| 32 | 
            -
                  });
         | 
| 33 | 
            -
                });
         | 
| 34 | 
            -
                it('should allow HEAD access to dynamic resource', function(done) {
         | 
| 35 | 
            -
                  return $.ajax(`http://${CORS_SERVER}/`, {
         | 
| 36 | 
            -
                    type: 'HEAD'
         | 
| 37 | 
            -
                  }).done(function(data, textStatus, jqXHR) {
         | 
| 38 | 
            -
                    expect(jqXHR.status).to.eql(200);
         | 
| 39 | 
            -
                    return done();
         | 
| 40 | 
            -
                  });
         | 
| 41 | 
            -
                });
         | 
| 42 | 
            -
                it('should allow DELETE access to dynamic resource', function(done) {
         | 
| 43 | 
            -
                  return $.ajax(`http://${CORS_SERVER}/`, {
         | 
| 44 | 
            -
                    type: 'DELETE'
         | 
| 45 | 
            -
                  }).done(function(data, textStatus, jqXHR) {
         | 
| 46 | 
            -
                    expect(data).to.eql('Hello world');
         | 
| 47 | 
            -
                    return done();
         | 
| 48 | 
            -
                  });
         | 
| 49 | 
            -
                });
         | 
| 50 | 
            -
                it('should allow OPTIONS access to dynamic resource', function(done) {
         | 
| 51 | 
            -
                  return $.ajax(`http://${CORS_SERVER}/`, {
         | 
| 52 | 
            -
                    type: 'OPTIONS'
         | 
| 53 | 
            -
                  }).done(function(data, textStatus, jqXHR) {
         | 
| 54 | 
            -
                    expect(jqXHR.status).to.eql(200);
         | 
| 55 | 
            -
                    return done();
         | 
| 56 | 
            -
                  });
         | 
| 57 | 
            -
                });
         | 
| 58 | 
            -
                it('should allow access to static resource', function(done) {
         | 
| 59 | 
            -
                  return $.get(`http://${CORS_SERVER}/static.txt`, function(data, status, xhr) {
         | 
| 60 | 
            -
                    expect($.trim(data)).to.eql("Hello world");
         | 
| 61 | 
            -
                    return done();
         | 
| 62 | 
            -
                  });
         | 
| 63 | 
            -
                });
         | 
| 64 | 
            -
                return it('should allow post resource', function(done) {
         | 
| 65 | 
            -
                  return $.ajax({
         | 
| 66 | 
            -
                    type: 'POST',
         | 
| 67 | 
            -
                    url: `http://${CORS_SERVER}/cors`,
         | 
| 68 | 
            -
                    beforeSend: function(xhr) {
         | 
| 69 | 
            -
                      return xhr.setRequestHeader('X-Requested-With', 'XMLHTTPRequest');
         | 
| 70 | 
            -
                    },
         | 
| 71 | 
            -
                    success: function(data, status, xhr) {
         | 
| 72 | 
            -
                      expect($.trim(data)).to.eql("OK!");
         | 
| 73 | 
            -
                      return done();
         | 
| 74 | 
            -
                    }
         | 
| 75 | 
            -
                  });
         | 
| 76 | 
            -
                });
         | 
| 77 | 
            -
              });
         | 
| 78 | 
            -
             | 
| 79 | 
            -
            }).call(this);
         | 
    
        data/test/unit/cors_test.rb
    DELETED
    
    | @@ -1,540 +0,0 @@ | |
| 1 | 
            -
            # frozen_string_literal: true
         | 
| 2 | 
            -
             | 
| 3 | 
            -
            require 'minitest/autorun'
         | 
| 4 | 
            -
            require 'rack/test'
         | 
| 5 | 
            -
            require 'mocha/setup'
         | 
| 6 | 
            -
            require 'rack/cors'
         | 
| 7 | 
            -
            require 'ostruct'
         | 
| 8 | 
            -
             | 
| 9 | 
            -
            Rack::Test::Session.class_eval do
         | 
| 10 | 
            -
              unless defined? :options
         | 
| 11 | 
            -
                def options(uri, params = {}, env = {}, &block)
         | 
| 12 | 
            -
                  env = env_for(uri, env.merge(method: 'OPTIONS', params: params))
         | 
| 13 | 
            -
                  process_request(uri, env, &block)
         | 
| 14 | 
            -
                end
         | 
| 15 | 
            -
              end
         | 
| 16 | 
            -
            end
         | 
| 17 | 
            -
             | 
| 18 | 
            -
            Rack::Test::Methods.class_eval do
         | 
| 19 | 
            -
              def_delegator :current_session, :options
         | 
| 20 | 
            -
            end
         | 
| 21 | 
            -
             | 
| 22 | 
            -
            module MiniTest::Assertions
         | 
| 23 | 
            -
              def assert_cors_success(response)
         | 
| 24 | 
            -
                assert !response.headers['Access-Control-Allow-Origin'].nil?, 'Expected a successful CORS response'
         | 
| 25 | 
            -
              end
         | 
| 26 | 
            -
             | 
| 27 | 
            -
              def assert_not_cors_success(response)
         | 
| 28 | 
            -
                assert response.headers['Access-Control-Allow-Origin'].nil?, 'Expected a failed CORS response'
         | 
| 29 | 
            -
              end
         | 
| 30 | 
            -
            end
         | 
| 31 | 
            -
             | 
| 32 | 
            -
            class CaptureResult
         | 
| 33 | 
            -
              def initialize(app, options = {})
         | 
| 34 | 
            -
                @app = app
         | 
| 35 | 
            -
                @result_holder = options[:holder]
         | 
| 36 | 
            -
              end
         | 
| 37 | 
            -
             | 
| 38 | 
            -
              def call(env)
         | 
| 39 | 
            -
                response = @app.call(env)
         | 
| 40 | 
            -
                @result_holder.cors_result = env[Rack::Cors::RACK_CORS]
         | 
| 41 | 
            -
                response
         | 
| 42 | 
            -
              end
         | 
| 43 | 
            -
            end
         | 
| 44 | 
            -
             | 
| 45 | 
            -
            class FakeProxy
         | 
| 46 | 
            -
              def initialize(app, _options = {})
         | 
| 47 | 
            -
                @app = app
         | 
| 48 | 
            -
              end
         | 
| 49 | 
            -
             | 
| 50 | 
            -
              def call(env)
         | 
| 51 | 
            -
                status, headers, body = @app.call(env)
         | 
| 52 | 
            -
                headers['vary'] = %w[Origin User-Agent]
         | 
| 53 | 
            -
                [status, headers, body]
         | 
| 54 | 
            -
              end
         | 
| 55 | 
            -
            end
         | 
| 56 | 
            -
             | 
| 57 | 
            -
            Rack::MockResponse.infect_an_assertion :assert_cors_success, :must_render_cors_success, :only_one_argument
         | 
| 58 | 
            -
            Rack::MockResponse.infect_an_assertion :assert_not_cors_success, :wont_render_cors_success, :only_one_argument
         | 
| 59 | 
            -
             | 
| 60 | 
            -
            describe Rack::Cors do
         | 
| 61 | 
            -
              include Rack::Test::Methods
         | 
| 62 | 
            -
             | 
| 63 | 
            -
              attr_accessor :cors_result
         | 
| 64 | 
            -
             | 
| 65 | 
            -
              def load_app(name, options = {})
         | 
| 66 | 
            -
                test = self
         | 
| 67 | 
            -
                Rack::Builder.new do
         | 
| 68 | 
            -
                  use CaptureResult, holder: test
         | 
| 69 | 
            -
                  eval File.read(File.dirname(__FILE__) + "/#{name}.ru")
         | 
| 70 | 
            -
                  use FakeProxy if options[:proxy]
         | 
| 71 | 
            -
                  map('/') do
         | 
| 72 | 
            -
                    run(lambda do |_env|
         | 
| 73 | 
            -
                      [200, { 'Content-Type' => 'text/html' }, ['success']]
         | 
| 74 | 
            -
                    end)
         | 
| 75 | 
            -
                  end
         | 
| 76 | 
            -
                end
         | 
| 77 | 
            -
              end
         | 
| 78 | 
            -
             | 
| 79 | 
            -
              let(:app) { load_app('test') }
         | 
| 80 | 
            -
             | 
| 81 | 
            -
              it 'should support simple CORS request' do
         | 
| 82 | 
            -
                successful_cors_request
         | 
| 83 | 
            -
                _(cors_result).must_be :hit
         | 
| 84 | 
            -
              end
         | 
| 85 | 
            -
             | 
| 86 | 
            -
              it "should not return CORS headers if Origin header isn't present" do
         | 
| 87 | 
            -
                get '/'
         | 
| 88 | 
            -
                _(last_response).wont_render_cors_success
         | 
| 89 | 
            -
                _(cors_result).wont_be :hit
         | 
| 90 | 
            -
              end
         | 
| 91 | 
            -
             | 
| 92 | 
            -
              it 'should support OPTIONS CORS request' do
         | 
| 93 | 
            -
                successful_cors_request '/options', method: :options
         | 
| 94 | 
            -
              end
         | 
| 95 | 
            -
             | 
| 96 | 
            -
              it 'should support regex origins configuration' do
         | 
| 97 | 
            -
                successful_cors_request origin: 'http://192.168.0.1:1234'
         | 
| 98 | 
            -
              end
         | 
| 99 | 
            -
             | 
| 100 | 
            -
              it 'should support subdomain example' do
         | 
| 101 | 
            -
                successful_cors_request origin: 'http://subdomain.example.com'
         | 
| 102 | 
            -
              end
         | 
| 103 | 
            -
             | 
| 104 | 
            -
              it 'should support proc origins configuration' do
         | 
| 105 | 
            -
                successful_cors_request '/proc-origin', origin: 'http://10.10.10.10:3000'
         | 
| 106 | 
            -
              end
         | 
| 107 | 
            -
             | 
| 108 | 
            -
              it 'should support lambda origin configuration' do
         | 
| 109 | 
            -
                successful_cors_request '/lambda-origin', origin: 'http://10.10.10.10:3000'
         | 
| 110 | 
            -
              end
         | 
| 111 | 
            -
             | 
| 112 | 
            -
              it 'should support proc origins configuration (inverse)' do
         | 
| 113 | 
            -
                cors_request '/proc-origin', origin: 'http://bad.guy'
         | 
| 114 | 
            -
                _(last_response).wont_render_cors_success
         | 
| 115 | 
            -
              end
         | 
| 116 | 
            -
             | 
| 117 | 
            -
              it 'should not mix up path rules across origins' do
         | 
| 118 | 
            -
                header 'Origin', 'http://10.10.10.10:3000'
         | 
| 119 | 
            -
                get '/' # / is configured in a separate rule block
         | 
| 120 | 
            -
                _(last_response).wont_render_cors_success
         | 
| 121 | 
            -
              end
         | 
| 122 | 
            -
             | 
| 123 | 
            -
              it 'should support alternative X-Origin header' do
         | 
| 124 | 
            -
                header 'X-Origin', 'http://localhost:3000'
         | 
| 125 | 
            -
                get '/'
         | 
| 126 | 
            -
                _(last_response).must_render_cors_success
         | 
| 127 | 
            -
              end
         | 
| 128 | 
            -
             | 
| 129 | 
            -
              it 'should support expose header configuration' do
         | 
| 130 | 
            -
                successful_cors_request '/expose_single_header'
         | 
| 131 | 
            -
                _(last_response.headers['Access-Control-Expose-Headers']).must_equal 'expose-test'
         | 
| 132 | 
            -
              end
         | 
| 133 | 
            -
             | 
| 134 | 
            -
              it 'should support expose multiple header configuration' do
         | 
| 135 | 
            -
                successful_cors_request '/expose_multiple_headers'
         | 
| 136 | 
            -
                _(last_response.headers['Access-Control-Expose-Headers']).must_equal 'expose-test-1, expose-test-2'
         | 
| 137 | 
            -
              end
         | 
| 138 | 
            -
             | 
| 139 | 
            -
              # Explanation: http://www.fastly.com/blog/best-practices-for-using-the-vary-header/
         | 
| 140 | 
            -
              it "should add Vary header if resource matches even if Origin header isn't present" do
         | 
| 141 | 
            -
                get '/'
         | 
| 142 | 
            -
                _(last_response).wont_render_cors_success
         | 
| 143 | 
            -
                _(last_response.headers['Vary']).must_equal 'Origin'
         | 
| 144 | 
            -
              end
         | 
| 145 | 
            -
             | 
| 146 | 
            -
              it 'should add Vary header based on :vary option' do
         | 
| 147 | 
            -
                successful_cors_request '/vary_test'
         | 
| 148 | 
            -
                _(last_response.headers['Vary']).must_equal 'Origin, Host'
         | 
| 149 | 
            -
              end
         | 
| 150 | 
            -
             | 
| 151 | 
            -
              it 'decode URL and resolve paths before resource matching' do
         | 
| 152 | 
            -
                header 'Origin', 'http://localhost:3000'
         | 
| 153 | 
            -
                get '/public/a/..%2F..%2Fprivate/stuff'
         | 
| 154 | 
            -
                _(last_response).wont_render_cors_success
         | 
| 155 | 
            -
              end
         | 
| 156 | 
            -
             | 
| 157 | 
            -
              describe 'with upstream Vary headers' do
         | 
| 158 | 
            -
                let(:app) { load_app('test', { proxy: true }) }
         | 
| 159 | 
            -
             | 
| 160 | 
            -
                it 'should add to them' do
         | 
| 161 | 
            -
                  successful_cors_request '/vary_test'
         | 
| 162 | 
            -
                  _(last_response.headers['Vary']).must_equal 'Origin, User-Agent, Host'
         | 
| 163 | 
            -
                end
         | 
| 164 | 
            -
              end
         | 
| 165 | 
            -
             | 
| 166 | 
            -
              it 'should add Vary header if Access-Control-Allow-Origin header was added and if it is specific' do
         | 
| 167 | 
            -
                successful_cors_request '/', origin: 'http://192.168.0.3:8080'
         | 
| 168 | 
            -
                _(last_response.headers['Access-Control-Allow-Origin']).must_equal 'http://192.168.0.3:8080'
         | 
| 169 | 
            -
                _(last_response.headers['Vary']).wont_be_nil
         | 
| 170 | 
            -
              end
         | 
| 171 | 
            -
             | 
| 172 | 
            -
              it 'should add Vary header even if Access-Control-Allow-Origin header was added and it is generic (*)' do
         | 
| 173 | 
            -
                successful_cors_request '/public_without_credentials', origin: 'http://192.168.1.3:8080'
         | 
| 174 | 
            -
                _(last_response.headers['Access-Control-Allow-Origin']).must_equal '*'
         | 
| 175 | 
            -
                _(last_response.headers['Vary']).must_equal 'Origin'
         | 
| 176 | 
            -
              end
         | 
| 177 | 
            -
             | 
| 178 | 
            -
              it 'should support multi allow configurations for the same resource' do
         | 
| 179 | 
            -
                successful_cors_request '/multi-allow-config', origin: 'http://mucho-grande.com'
         | 
| 180 | 
            -
                _(last_response.headers['Access-Control-Allow-Origin']).must_equal 'http://mucho-grande.com'
         | 
| 181 | 
            -
                _(last_response.headers['Vary']).must_equal 'Origin'
         | 
| 182 | 
            -
             | 
| 183 | 
            -
                successful_cors_request '/multi-allow-config', origin: 'http://192.168.1.3:8080'
         | 
| 184 | 
            -
                _(last_response.headers['Access-Control-Allow-Origin']).must_equal '*'
         | 
| 185 | 
            -
                _(last_response.headers['Vary']).must_equal 'Origin'
         | 
| 186 | 
            -
              end
         | 
| 187 | 
            -
             | 
| 188 | 
            -
              it 'should not return CORS headers on OPTIONS request if Access-Control-Allow-Origin is not present' do
         | 
| 189 | 
            -
                options '/get-only'
         | 
| 190 | 
            -
                _(last_response.headers['Access-Control-Allow-Origin']).must_be_nil
         | 
| 191 | 
            -
              end
         | 
| 192 | 
            -
             | 
| 193 | 
            -
              it 'should not apply CORS headers if it does not match conditional on resource' do
         | 
| 194 | 
            -
                header 'Origin', 'http://192.168.0.1:1234'
         | 
| 195 | 
            -
                get '/conditional'
         | 
| 196 | 
            -
                _(last_response).wont_render_cors_success
         | 
| 197 | 
            -
              end
         | 
| 198 | 
            -
             | 
| 199 | 
            -
              it 'should apply CORS headers if it does match conditional on resource' do
         | 
| 200 | 
            -
                header 'X-OK', '1'
         | 
| 201 | 
            -
                successful_cors_request '/conditional', origin: 'http://192.168.0.1:1234'
         | 
| 202 | 
            -
              end
         | 
| 203 | 
            -
             | 
| 204 | 
            -
              it 'should not allow everything if Origin is configured as blank string' do
         | 
| 205 | 
            -
                cors_request '/blank-origin', origin: 'http://example.net'
         | 
| 206 | 
            -
                _(last_response).wont_render_cors_success
         | 
| 207 | 
            -
              end
         | 
| 208 | 
            -
             | 
| 209 | 
            -
              it 'should not allow credentials for public resources' do
         | 
| 210 | 
            -
                successful_cors_request '/public'
         | 
| 211 | 
            -
                _(last_response.headers['Access-Control-Allow-Credentials']).must_be_nil
         | 
| 212 | 
            -
              end
         | 
| 213 | 
            -
             | 
| 214 | 
            -
              describe 'logging' do
         | 
| 215 | 
            -
                it 'should not log debug messages if debug option is false' do
         | 
| 216 | 
            -
                  app = mock
         | 
| 217 | 
            -
                  app.stubs(:call).returns(200, {}, [''])
         | 
| 218 | 
            -
             | 
| 219 | 
            -
                  logger = mock
         | 
| 220 | 
            -
                  logger.expects(:debug).never
         | 
| 221 | 
            -
             | 
| 222 | 
            -
                  cors = Rack::Cors.new(app, debug: false, logger: logger) {}
         | 
| 223 | 
            -
                  cors.send(:debug, {}, 'testing')
         | 
| 224 | 
            -
                end
         | 
| 225 | 
            -
             | 
| 226 | 
            -
                it 'should log debug messages if debug option is true' do
         | 
| 227 | 
            -
                  app = mock
         | 
| 228 | 
            -
                  app.stubs(:call).returns(200, {}, [''])
         | 
| 229 | 
            -
             | 
| 230 | 
            -
                  logger = mock
         | 
| 231 | 
            -
                  logger.expects(:debug)
         | 
| 232 | 
            -
             | 
| 233 | 
            -
                  cors = Rack::Cors.new(app, debug: true, logger: logger) {}
         | 
| 234 | 
            -
                  cors.send(:debug, {}, 'testing')
         | 
| 235 | 
            -
                end
         | 
| 236 | 
            -
             | 
| 237 | 
            -
                it 'should use rack.logger if available' do
         | 
| 238 | 
            -
                  app = mock
         | 
| 239 | 
            -
                  app.stubs(:call).returns([200, {}, ['']])
         | 
| 240 | 
            -
             | 
| 241 | 
            -
                  logger = mock
         | 
| 242 | 
            -
                  logger.expects(:debug).at_least_once
         | 
| 243 | 
            -
             | 
| 244 | 
            -
                  cors = Rack::Cors.new(app, debug: true) {}
         | 
| 245 | 
            -
                  cors.call({ 'rack.logger' => logger, 'HTTP_ORIGIN' => 'test.com' })
         | 
| 246 | 
            -
                end
         | 
| 247 | 
            -
             | 
| 248 | 
            -
                it 'should use logger proc' do
         | 
| 249 | 
            -
                  app = mock
         | 
| 250 | 
            -
                  app.stubs(:call).returns([200, {}, ['']])
         | 
| 251 | 
            -
             | 
| 252 | 
            -
                  logger = mock
         | 
| 253 | 
            -
                  logger.expects(:debug)
         | 
| 254 | 
            -
             | 
| 255 | 
            -
                  cors = Rack::Cors.new(app, debug: true, logger: proc { logger }) {}
         | 
| 256 | 
            -
                  cors.call({ 'HTTP_ORIGIN' => 'test.com' })
         | 
| 257 | 
            -
                end
         | 
| 258 | 
            -
             | 
| 259 | 
            -
                describe 'with Rails setup' do
         | 
| 260 | 
            -
                  after do
         | 
| 261 | 
            -
                    ::Rails.logger = nil if defined?(::Rails)
         | 
| 262 | 
            -
                  end
         | 
| 263 | 
            -
             | 
| 264 | 
            -
                  it 'should use Rails.logger if available' do
         | 
| 265 | 
            -
                    app = mock
         | 
| 266 | 
            -
                    app.stubs(:call).returns([200, {}, ['']])
         | 
| 267 | 
            -
             | 
| 268 | 
            -
                    logger = mock
         | 
| 269 | 
            -
                    logger.expects(:debug)
         | 
| 270 | 
            -
             | 
| 271 | 
            -
                    ::Rails = OpenStruct.new(logger: logger)
         | 
| 272 | 
            -
             | 
| 273 | 
            -
                    cors = Rack::Cors.new(app, debug: true) {}
         | 
| 274 | 
            -
                    cors.call({ 'HTTP_ORIGIN' => 'test.com' })
         | 
| 275 | 
            -
                  end
         | 
| 276 | 
            -
                end
         | 
| 277 | 
            -
             | 
| 278 | 
            -
                it 'should use Logger if none is set' do
         | 
| 279 | 
            -
                  app = mock
         | 
| 280 | 
            -
                  app.stubs(:call).returns([200, {}, ['']])
         | 
| 281 | 
            -
             | 
| 282 | 
            -
                  logger = mock
         | 
| 283 | 
            -
                  Logger.expects(:new).returns(logger)
         | 
| 284 | 
            -
                  logger.expects(:tap).returns(logger)
         | 
| 285 | 
            -
                  logger.expects(:debug)
         | 
| 286 | 
            -
             | 
| 287 | 
            -
                  cors = Rack::Cors.new(app, debug: true) {}
         | 
| 288 | 
            -
                  cors.call({ 'HTTP_ORIGIN' => 'test.com' })
         | 
| 289 | 
            -
                end
         | 
| 290 | 
            -
              end
         | 
| 291 | 
            -
             | 
| 292 | 
            -
              describe 'preflight requests' do
         | 
| 293 | 
            -
                it 'should fail if origin is invalid' do
         | 
| 294 | 
            -
                  preflight_request('http://allyourdataarebelongtous.com', '/')
         | 
| 295 | 
            -
                  _(last_response).wont_render_cors_success
         | 
| 296 | 
            -
                  _(cors_result).wont_be :hit
         | 
| 297 | 
            -
                  _(cors_result).must_be :preflight
         | 
| 298 | 
            -
                end
         | 
| 299 | 
            -
             | 
| 300 | 
            -
                it 'should fail if Access-Control-Request-Method is not allowed' do
         | 
| 301 | 
            -
                  preflight_request('http://localhost:3000', '/get-only', method: :post)
         | 
| 302 | 
            -
                  _(last_response).wont_render_cors_success
         | 
| 303 | 
            -
                  _(cors_result.miss_reason).must_equal Rack::Cors::Result::MISS_DENY_METHOD
         | 
| 304 | 
            -
                  _(cors_result).wont_be :hit
         | 
| 305 | 
            -
                  _(cors_result).must_be :preflight
         | 
| 306 | 
            -
                end
         | 
| 307 | 
            -
             | 
| 308 | 
            -
                it 'should fail if header is not allowed' do
         | 
| 309 | 
            -
                  preflight_request('http://localhost:3000', '/single_header', headers: 'Fooey')
         | 
| 310 | 
            -
                  _(last_response).wont_render_cors_success
         | 
| 311 | 
            -
                  _(cors_result.miss_reason).must_equal Rack::Cors::Result::MISS_DENY_HEADER
         | 
| 312 | 
            -
                  _(cors_result).wont_be :hit
         | 
| 313 | 
            -
                  _(cors_result).must_be :preflight
         | 
| 314 | 
            -
                end
         | 
| 315 | 
            -
             | 
| 316 | 
            -
                it 'should allow any header if headers = :any' do
         | 
| 317 | 
            -
                  preflight_request('http://localhost:3000', '/', headers: 'Fooey')
         | 
| 318 | 
            -
                  _(last_response).must_render_cors_success
         | 
| 319 | 
            -
                end
         | 
| 320 | 
            -
             | 
| 321 | 
            -
                it 'should allow any method if methods = :any' do
         | 
| 322 | 
            -
                  preflight_request('http://localhost:3000', '/', methods: :any)
         | 
| 323 | 
            -
                  _(last_response).must_render_cors_success
         | 
| 324 | 
            -
                end
         | 
| 325 | 
            -
             | 
| 326 | 
            -
                it 'allows PATCH method' do
         | 
| 327 | 
            -
                  preflight_request('http://localhost:3000', '/', methods: [:patch])
         | 
| 328 | 
            -
                  _(last_response).must_render_cors_success
         | 
| 329 | 
            -
                end
         | 
| 330 | 
            -
             | 
| 331 | 
            -
                it 'should allow header case insensitive match' do
         | 
| 332 | 
            -
                  preflight_request('http://localhost:3000', '/single_header', headers: 'X-Domain-Token')
         | 
| 333 | 
            -
                  _(last_response).must_render_cors_success
         | 
| 334 | 
            -
                end
         | 
| 335 | 
            -
             | 
| 336 | 
            -
                it 'should allow multiple headers match' do
         | 
| 337 | 
            -
                  # Webkit style
         | 
| 338 | 
            -
                  preflight_request('http://localhost:3000', '/two_headers', headers: 'X-Requested-With, X-Domain-Token')
         | 
| 339 | 
            -
                  _(last_response).must_render_cors_success
         | 
| 340 | 
            -
             | 
| 341 | 
            -
                  # Gecko style
         | 
| 342 | 
            -
                  preflight_request('http://localhost:3000', '/two_headers', headers: 'x-requested-with,x-domain-token')
         | 
| 343 | 
            -
                  _(last_response).must_render_cors_success
         | 
| 344 | 
            -
                end
         | 
| 345 | 
            -
             | 
| 346 | 
            -
                it "should allow '*' origins to allow any origin" do
         | 
| 347 | 
            -
                  preflight_request('http://locohost:3000', '/public')
         | 
| 348 | 
            -
                  _(last_response).must_render_cors_success
         | 
| 349 | 
            -
                  _(last_response.headers['Access-Control-Allow-Origin']).must_equal '*'
         | 
| 350 | 
            -
                end
         | 
| 351 | 
            -
             | 
| 352 | 
            -
                it "should allow '/<path>/' resource if match pattern is /<path>/*" do
         | 
| 353 | 
            -
                  preflight_request('http://localhost:3000', '/wildcard/')
         | 
| 354 | 
            -
                  _(last_response).must_render_cors_success
         | 
| 355 | 
            -
                  _(last_response.headers['Access-Control-Allow-Origin']).wont_equal nil
         | 
| 356 | 
            -
                end
         | 
| 357 | 
            -
             | 
| 358 | 
            -
                it "should allow '/<path>' resource if match pattern is /<path>/*" do
         | 
| 359 | 
            -
                  preflight_request('http://localhost:3000', '/wildcard')
         | 
| 360 | 
            -
                  _(last_response).must_render_cors_success
         | 
| 361 | 
            -
                  _(last_response.headers['Access-Control-Allow-Origin']).wont_equal nil
         | 
| 362 | 
            -
                end
         | 
| 363 | 
            -
             | 
| 364 | 
            -
                it "should allow '*' origin to allow any origin, and set '*' if no credentials required" do
         | 
| 365 | 
            -
                  preflight_request('http://locohost:3000', '/public_without_credentials')
         | 
| 366 | 
            -
                  _(last_response).must_render_cors_success
         | 
| 367 | 
            -
                  _(last_response.headers['Access-Control-Allow-Origin']).must_equal '*'
         | 
| 368 | 
            -
                end
         | 
| 369 | 
            -
             | 
| 370 | 
            -
                it 'should return "file://" as header with "file://" as origin' do
         | 
| 371 | 
            -
                  preflight_request('file://', '/')
         | 
| 372 | 
            -
                  _(last_response).must_render_cors_success
         | 
| 373 | 
            -
                  _(last_response.headers['Access-Control-Allow-Origin']).must_equal 'file://'
         | 
| 374 | 
            -
                end
         | 
| 375 | 
            -
             | 
| 376 | 
            -
                it 'supports custom protocols in origin' do
         | 
| 377 | 
            -
                  preflight_request('custom-protocol://abcdefg', '/')
         | 
| 378 | 
            -
                  _(last_response).must_render_cors_success
         | 
| 379 | 
            -
                  _(last_response.headers['Access-Control-Allow-Origin']).must_equal 'custom-protocol://abcdefg'
         | 
| 380 | 
            -
                end
         | 
| 381 | 
            -
             | 
| 382 | 
            -
                describe '' do
         | 
| 383 | 
            -
                  let(:app) do
         | 
| 384 | 
            -
                    test = self
         | 
| 385 | 
            -
                    Rack::Builder.new do
         | 
| 386 | 
            -
                      use CaptureResult, holder: test
         | 
| 387 | 
            -
                      use Rack::Cors, debug: true, logger: Logger.new(StringIO.new) do
         | 
| 388 | 
            -
                        allow do
         | 
| 389 | 
            -
                          origins '*'
         | 
| 390 | 
            -
                          resource '/', methods: :post
         | 
| 391 | 
            -
                        end
         | 
| 392 | 
            -
                      end
         | 
| 393 | 
            -
                      map('/') do
         | 
| 394 | 
            -
                        run ->(_env) { [500, {}, ['FAIL!']] }
         | 
| 395 | 
            -
                      end
         | 
| 396 | 
            -
                    end
         | 
| 397 | 
            -
                  end
         | 
| 398 | 
            -
             | 
| 399 | 
            -
                  it 'should not send failed preflight requests thru the app' do
         | 
| 400 | 
            -
                    preflight_request('http://localhost', '/', method: :unsupported)
         | 
| 401 | 
            -
                    _(last_response).wont_render_cors_success
         | 
| 402 | 
            -
                    _(last_response.status).must_equal 200
         | 
| 403 | 
            -
                    _(cors_result).must_be :preflight
         | 
| 404 | 
            -
                    _(cors_result).wont_be :hit
         | 
| 405 | 
            -
                    _(cors_result.miss_reason).must_equal Rack::Cors::Result::MISS_DENY_METHOD
         | 
| 406 | 
            -
                  end
         | 
| 407 | 
            -
                end
         | 
| 408 | 
            -
              end
         | 
| 409 | 
            -
             | 
| 410 | 
            -
              describe 'with insecure configuration' do
         | 
| 411 | 
            -
                let(:app) { load_app('insecure') }
         | 
| 412 | 
            -
             | 
| 413 | 
            -
                it 'should raise an error' do
         | 
| 414 | 
            -
                  _(proc { cors_request '/public' }).must_raise Rack::Cors::Resource::CorsMisconfigurationError
         | 
| 415 | 
            -
                end
         | 
| 416 | 
            -
              end
         | 
| 417 | 
            -
             | 
| 418 | 
            -
              describe 'with non HTTP config' do
         | 
| 419 | 
            -
                let(:app) { load_app('non_http') }
         | 
| 420 | 
            -
             | 
| 421 | 
            -
                it 'should support non http/https origins' do
         | 
| 422 | 
            -
                  successful_cors_request '/public', origin: 'content://com.company.app'
         | 
| 423 | 
            -
                end
         | 
| 424 | 
            -
              end
         | 
| 425 | 
            -
             | 
| 426 | 
            -
              describe 'Rack::Lint' do
         | 
| 427 | 
            -
                def app
         | 
| 428 | 
            -
                  @app ||= Rack::Builder.new do
         | 
| 429 | 
            -
                    use Rack::Cors
         | 
| 430 | 
            -
                    use Rack::Lint
         | 
| 431 | 
            -
                    run ->(_env) { [200, { 'Content-Type' => 'text/html' }, ['hello']] }
         | 
| 432 | 
            -
                  end
         | 
| 433 | 
            -
                end
         | 
| 434 | 
            -
             | 
| 435 | 
            -
                it 'is lint-compliant with non-CORS request' do
         | 
| 436 | 
            -
                  get '/'
         | 
| 437 | 
            -
                  _(last_response.status).must_equal 200
         | 
| 438 | 
            -
                end
         | 
| 439 | 
            -
              end
         | 
| 440 | 
            -
             | 
| 441 | 
            -
              describe 'with app overriding CORS header' do
         | 
| 442 | 
            -
                let(:app) do
         | 
| 443 | 
            -
                  Rack::Builder.new do
         | 
| 444 | 
            -
                    use Rack::Cors, debug: true, logger: Logger.new(StringIO.new) do
         | 
| 445 | 
            -
                      allow do
         | 
| 446 | 
            -
                        origins '*'
         | 
| 447 | 
            -
                        resource '/'
         | 
| 448 | 
            -
                      end
         | 
| 449 | 
            -
                    end
         | 
| 450 | 
            -
                    map('/') do
         | 
| 451 | 
            -
                      run ->(_env) { [200, { 'Access-Control-Allow-Origin' => 'http://foo.net' }, ['success']] }
         | 
| 452 | 
            -
                    end
         | 
| 453 | 
            -
                  end
         | 
| 454 | 
            -
                end
         | 
| 455 | 
            -
             | 
| 456 | 
            -
                it 'should return app header' do
         | 
| 457 | 
            -
                  successful_cors_request origin: 'http://example.net'
         | 
| 458 | 
            -
                  _(last_response.headers['Access-Control-Allow-Origin']).must_equal 'http://foo.net'
         | 
| 459 | 
            -
                end
         | 
| 460 | 
            -
             | 
| 461 | 
            -
                it 'should return original headers if in debug' do
         | 
| 462 | 
            -
                  successful_cors_request origin: 'http://example.net'
         | 
| 463 | 
            -
                  _(last_response.headers['X-Rack-CORS-Original-Access-Control-Allow-Origin']).must_equal '*'
         | 
| 464 | 
            -
                end
         | 
| 465 | 
            -
              end
         | 
| 466 | 
            -
             | 
| 467 | 
            -
              describe 'with headers set to nil' do
         | 
| 468 | 
            -
                let(:app) do
         | 
| 469 | 
            -
                  Rack::Builder.new do
         | 
| 470 | 
            -
                    use Rack::Cors do
         | 
| 471 | 
            -
                      allow do
         | 
| 472 | 
            -
                        origins '*'
         | 
| 473 | 
            -
                        resource '/', headers: nil
         | 
| 474 | 
            -
                      end
         | 
| 475 | 
            -
                    end
         | 
| 476 | 
            -
                    map('/') do
         | 
| 477 | 
            -
                      run ->(_env) { [200, { 'Content-Type' => 'text/html' }, ['hello']] }
         | 
| 478 | 
            -
                    end
         | 
| 479 | 
            -
                  end
         | 
| 480 | 
            -
                end
         | 
| 481 | 
            -
             | 
| 482 | 
            -
                it 'should succeed with CORS simple headers' do
         | 
| 483 | 
            -
                  preflight_request('http://localhost:3000', '/', headers: 'Accept')
         | 
| 484 | 
            -
                  _(last_response).must_render_cors_success
         | 
| 485 | 
            -
                end
         | 
| 486 | 
            -
              end
         | 
| 487 | 
            -
             | 
| 488 | 
            -
              describe 'with custom allowed headers' do
         | 
| 489 | 
            -
                let(:app) do
         | 
| 490 | 
            -
                  Rack::Builder.new do
         | 
| 491 | 
            -
                    use Rack::Cors do
         | 
| 492 | 
            -
                      allow do
         | 
| 493 | 
            -
                        origins '*'
         | 
| 494 | 
            -
                        resource '/', headers: []
         | 
| 495 | 
            -
                      end
         | 
| 496 | 
            -
                    end
         | 
| 497 | 
            -
                    map('/') do
         | 
| 498 | 
            -
                      run ->(_env) { [200, { 'Content-Type' => 'text/html' }, ['hello']] }
         | 
| 499 | 
            -
                    end
         | 
| 500 | 
            -
                  end
         | 
| 501 | 
            -
                end
         | 
| 502 | 
            -
             | 
| 503 | 
            -
                it 'should succeed with CORS simple headers' do
         | 
| 504 | 
            -
                  preflight_request('http://localhost:3000', '/', headers: 'Accept')
         | 
| 505 | 
            -
                  _(last_response).must_render_cors_success
         | 
| 506 | 
            -
                  preflight_request('http://localhost:3000', '/', headers: 'Accept-Language')
         | 
| 507 | 
            -
                  _(last_response).must_render_cors_success
         | 
| 508 | 
            -
                  preflight_request('http://localhost:3000', '/', headers: 'Content-Type')
         | 
| 509 | 
            -
                  _(last_response).must_render_cors_success
         | 
| 510 | 
            -
                  preflight_request('http://localhost:3000', '/', headers: 'Content-Language')
         | 
| 511 | 
            -
                  _(last_response).must_render_cors_success
         | 
| 512 | 
            -
                end
         | 
| 513 | 
            -
              end
         | 
| 514 | 
            -
             | 
| 515 | 
            -
              protected
         | 
| 516 | 
            -
             | 
| 517 | 
            -
              def cors_request(*args)
         | 
| 518 | 
            -
                path = args.first.is_a?(String) ? args.first : '/'
         | 
| 519 | 
            -
             | 
| 520 | 
            -
                opts = { method: :get, origin: 'http://localhost:3000' }
         | 
| 521 | 
            -
                opts.merge! args.last if args.last.is_a?(Hash)
         | 
| 522 | 
            -
             | 
| 523 | 
            -
                header 'origin', opts[:origin]
         | 
| 524 | 
            -
                current_session.__send__ opts[:method], path, {}, test: self
         | 
| 525 | 
            -
              end
         | 
| 526 | 
            -
             | 
| 527 | 
            -
              def successful_cors_request(*args)
         | 
| 528 | 
            -
                cors_request(*args)
         | 
| 529 | 
            -
                _(last_response).must_render_cors_success
         | 
| 530 | 
            -
              end
         | 
| 531 | 
            -
             | 
| 532 | 
            -
              def preflight_request(origin, path, opts = {})
         | 
| 533 | 
            -
                header 'Origin', origin
         | 
| 534 | 
            -
                unless opts.key?(:method) && opts[:method].nil?
         | 
| 535 | 
            -
                  header 'Access-Control-Request-Method', opts[:method] ? opts[:method].to_s.upcase : 'GET'
         | 
| 536 | 
            -
                end
         | 
| 537 | 
            -
                header 'Access-Control-Request-Headers', opts[:headers] if opts[:headers]
         | 
| 538 | 
            -
                options path
         | 
| 539 | 
            -
              end
         | 
| 540 | 
            -
            end
         |