Allow cross-origin requests to API
authorJohn Firebaugh <john.firebaugh@gmail.com>
Sat, 20 Oct 2012 23:11:51 +0000 (16:11 -0700)
committerTom Hughes <tom@compton.nu>
Mon, 22 Oct 2012 18:11:52 +0000 (19:11 +0100)
Gemfile
Gemfile.lock
config/initializers/cors.rb [new file with mode: 0644]
test/integration/cors_test.rb [new file with mode: 0644]

diff --git a/Gemfile b/Gemfile
index fa3f38d799818517c03447e19a8ba1c4f53b42bc..4644d07ea4f5648d9a5b2b50100d00ca7d3a8fb0 100644 (file)
--- a/Gemfile
+++ b/Gemfile
@@ -25,6 +25,7 @@ gem 'http_accept_language', '>= 1.0.2'
 gem 'paperclip', '~> 2.0'
 gem 'deadlock_retry', '>= 1.2.0'
 gem 'i18n-js', '>= 3.0.0.rc2'
+gem 'rack-cors'
 
 # We need ruby-openid 2.2.0 or later for ruby 1.9 support
 gem 'ruby-openid', '>= 2.2.0'
index 8c8e60af7ce43126d36d208cda8814c7bcee7758..2299757c049de7bec03bcd49cc3b6655ad3ac828 100644 (file)
@@ -102,6 +102,8 @@ GEM
     rack (1.4.1)
     rack-cache (1.2)
       rack (>= 0.4)
+    rack-cors (0.2.7)
+      rack
     rack-openid (1.3.1)
       rack (>= 1.1.0)
       ruby-openid (>= 2.1.8)
@@ -181,6 +183,7 @@ DEPENDENCIES
   open_id_authentication (>= 1.1.0)
   paperclip (~> 2.0)
   pg
+  rack-cors
   rails (= 3.2.8)
   rails-i18n (>= 0.6.3)
   redcarpet
diff --git a/config/initializers/cors.rb b/config/initializers/cors.rb
new file mode 100644 (file)
index 0000000..6fbeb91
--- /dev/null
@@ -0,0 +1,13 @@
+require "rack/cors"
+
+# Allow any and all cross-origin requests to the API. Allow any origin, and
+# any headers. Non-browser requests do not have origin or header restrictions,
+# so browser-requests should be similarly permitted. (Though the API does not
+# require any custom headers, Ajax frameworks may automatically add headers
+# such as X-Requested-By to requests.)
+Rails.configuration.middleware.use Rack::Cors do
+  allow do
+    origins "*"
+    resource "/api/*", :headers => :any, :methods => [:get, :post, :put, :delete]
+  end
+end
diff --git a/test/integration/cors_test.rb b/test/integration/cors_test.rb
new file mode 100644 (file)
index 0000000..827db7c
--- /dev/null
@@ -0,0 +1,32 @@
+require File.dirname(__FILE__) + '/../test_helper'
+
+class CORSTest < ActionController::IntegrationTest
+  # Rails 4 adds a built-in `options` method. When we upgrade, we can remove
+  # this definition.
+  unless instance_method_names.include?("options")
+    def options(*args)
+      reset! unless integration_session
+      @html_document = nil
+      integration_session.send(:process, :options, *args).tap do
+        copy_session_variables!
+      end
+    end
+  end
+
+  def test_api_routes_allow_cross_origin_requests
+    options "/api/capabilities", nil,
+            'HTTP_ORIGIN' => "http://www.example.com",
+            'HTTP_ACCESS_CONTROL_REQUEST_METHOD' => 'GET'
+
+    assert_response :success
+    assert_equal "http://www.example.com", response.headers['Access-Control-Allow-Origin']
+  end
+
+  def test_non_api_routes_dont_allow_cross_origin_requests
+    assert_raises ActionController::RoutingError do
+      options "/", nil,
+              'HTTP_ORIGIN' => "http://www.example.com",
+              'HTTP_ACCESS_CONTROL_REQUEST_METHOD' => 'GET'
+    end
+  end
+end