test: cover MiddlewareCorsTest and teardown
This commit is contained in:
1 parent
79563dce7f
commit
d706a14659
1 file changed
+150
@@ -0,0 +1,150 @@
|
|||||||
|
require 'minitest/autorun'
|
||||||
|
require 'prism'
|
||||||
|
require 'support'
|
||||||
|
|
||||||
|
class MiddlewareCorsTest < Minitest::Test
|
||||||
|
include TestSupport
|
||||||
|
|
||||||
|
def setup
|
||||||
|
Prism::Cors.reset!
|
||||||
|
@downstream_calls = 0
|
||||||
|
downstream = lambda do |_env|
|
||||||
|
@downstream_calls += 1
|
||||||
|
[200, {'Content-Type' => 'application/json'}, ['{}']]
|
||||||
|
end
|
||||||
|
@app = Prism::Middleware::Cors.new(downstream)
|
||||||
|
end
|
||||||
|
|
||||||
|
def teardown
|
||||||
|
Prism::Cors.reset!
|
||||||
|
end
|
||||||
|
|
||||||
|
def configure_api(**resource_options)
|
||||||
|
Prism::Cors.configure do |config|
|
||||||
|
config.allow do
|
||||||
|
origins 'https://app.example.com'
|
||||||
|
resource '/api/*', **resource_options
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_request_without_origin_header_passes_through_untouched
|
||||||
|
status, headers, = @app.call(env_for('GET', '/api/posts'))
|
||||||
|
assert_equal 200, status
|
||||||
|
assert_nil headers['Access-Control-Allow-Origin']
|
||||||
|
assert_equal 1, @downstream_calls
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_request_with_unmatched_origin_passes_through_without_cors_headers
|
||||||
|
configure_api(methods: %w[GET])
|
||||||
|
env = env_for('GET', '/api/posts', headers: {'Origin' => 'https://evil.example.com'})
|
||||||
|
status, headers, = @app.call(env)
|
||||||
|
assert_equal 200, status
|
||||||
|
assert_nil headers['Access-Control-Allow-Origin']
|
||||||
|
assert_equal 1, @downstream_calls
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_simple_request_with_allowed_origin_gets_cors_headers_and_reaches_the_app
|
||||||
|
configure_api(methods: %w[GET])
|
||||||
|
env = env_for('GET', '/api/posts', headers: {'Origin' => 'https://app.example.com'})
|
||||||
|
status, headers, = @app.call(env)
|
||||||
|
|
||||||
|
assert_equal 200, status
|
||||||
|
assert_equal 'https://app.example.com', headers['Access-Control-Allow-Origin']
|
||||||
|
assert_equal 'Origin', headers['Vary']
|
||||||
|
assert_equal 1, @downstream_calls
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_preflight_request_is_answered_directly_without_reaching_the_app
|
||||||
|
configure_api(methods: %w[GET POST], headers: %w[Content-Type])
|
||||||
|
env = env_for('OPTIONS', '/api/posts', headers: {
|
||||||
|
'Origin' => 'https://app.example.com',
|
||||||
|
'Access-Control-Request-Method' => 'POST',
|
||||||
|
'Access-Control-Request-Headers' => 'Content-Type'
|
||||||
|
})
|
||||||
|
status, headers, body = @app.call(env)
|
||||||
|
|
||||||
|
assert_equal 204, status
|
||||||
|
assert_equal 'https://app.example.com', headers['Access-Control-Allow-Origin']
|
||||||
|
assert_equal 'GET, POST', headers['Access-Control-Allow-Methods']
|
||||||
|
assert_equal 'Content-Type', headers['Access-Control-Allow-Headers']
|
||||||
|
assert_empty body
|
||||||
|
assert_equal 0, @downstream_calls
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_preflight_with_disallowed_method_is_rejected
|
||||||
|
configure_api(methods: %w[GET])
|
||||||
|
env = env_for('OPTIONS', '/api/posts', headers: {
|
||||||
|
'Origin' => 'https://app.example.com',
|
||||||
|
'Access-Control-Request-Method' => 'DELETE'
|
||||||
|
})
|
||||||
|
status, = @app.call(env)
|
||||||
|
|
||||||
|
assert_equal 403, status
|
||||||
|
assert_equal 0, @downstream_calls
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_preflight_with_disallowed_header_is_rejected
|
||||||
|
configure_api(methods: %w[POST], headers: %w[Content-Type])
|
||||||
|
env = env_for('OPTIONS', '/api/posts', headers: {
|
||||||
|
'Origin' => 'https://app.example.com',
|
||||||
|
'Access-Control-Request-Method' => 'POST',
|
||||||
|
'Access-Control-Request-Headers' => 'X-Secret'
|
||||||
|
})
|
||||||
|
status, = @app.call(env)
|
||||||
|
|
||||||
|
assert_equal 403, status
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_max_age_is_only_sent_when_configured
|
||||||
|
configure_api(methods: %w[GET], max_age: 600)
|
||||||
|
env = env_for('OPTIONS', '/api/posts', headers: {
|
||||||
|
'Origin' => 'https://app.example.com',
|
||||||
|
'Access-Control-Request-Method' => 'GET'
|
||||||
|
})
|
||||||
|
_, headers, = @app.call(env)
|
||||||
|
assert_equal '600', headers['Access-Control-Max-Age']
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_credentials_true_echoes_origin_and_sets_allow_credentials
|
||||||
|
configure_api(methods: %w[GET], credentials: true)
|
||||||
|
env = env_for('GET', '/api/posts', headers: {'Origin' => 'https://app.example.com'})
|
||||||
|
_, headers, = @app.call(env)
|
||||||
|
|
||||||
|
assert_equal 'https://app.example.com', headers['Access-Control-Allow-Origin']
|
||||||
|
assert_equal 'true', headers['Access-Control-Allow-Credentials']
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_expose_headers_only_sent_when_configured
|
||||||
|
configure_api(methods: %w[GET], expose: %w[X-Total-Count])
|
||||||
|
env = env_for('GET', '/api/posts', headers: {'Origin' => 'https://app.example.com'})
|
||||||
|
_, headers, = @app.call(env)
|
||||||
|
assert_equal 'X-Total-Count', headers['Access-Control-Expose-Headers']
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_vary_origin_is_appended_to_an_existing_vary_header
|
||||||
|
Prism::Cors.reset!
|
||||||
|
downstream = lambda { |_env| [200, {'Vary' => 'Accept'}, ['{}']] }
|
||||||
|
app = Prism::Middleware::Cors.new(downstream)
|
||||||
|
configure_api(methods: %w[GET])
|
||||||
|
env = env_for('GET', '/api/posts', headers: {'Origin' => 'https://app.example.com'})
|
||||||
|
_, headers, = app.call(env)
|
||||||
|
assert_equal 'Accept, Origin', headers['Vary']
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_a_resource_registered_without_a_format_extension_still_matches_a_dot_json_path
|
||||||
|
configure_api(methods: %w[GET])
|
||||||
|
env = env_for('GET', '/api/posts.json', headers: {'Origin' => 'https://app.example.com'})
|
||||||
|
status, headers, = @app.call(env)
|
||||||
|
assert_equal 200, status
|
||||||
|
assert_equal 'https://app.example.com', headers['Access-Control-Allow-Origin']
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_options_without_request_method_header_is_treated_as_a_simple_request
|
||||||
|
configure_api(methods: %w[GET])
|
||||||
|
env = env_for('OPTIONS', '/api/posts', headers: {'Origin' => 'https://app.example.com'})
|
||||||
|
status, = @app.call(env)
|
||||||
|
assert_equal 200, status
|
||||||
|
assert_equal 1, @downstream_calls
|
||||||
|
end
|
||||||
|
end
|
||||||
Reference in new issue
Block a user