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