diff --git a/app/controllers/api/application_controller.rb b/app/controllers/api/application_controller.rb new file mode 100644 index 0000000..605b129 --- /dev/null +++ b/app/controllers/api/application_controller.rb @@ -0,0 +1,14 @@ +class Api::ApplicationController < ApplicationController + before_filter :cor_filter + + def cor_filter + headers['Access-Control-Allow-Origin'] = request.headers['Origin'] + end + + def cor_preflight + headers['Access-Control-Allow-Methods'] = 'GET, POST, PUT, DELETE' + headers['Access-Control-Allow-Headers'] = 'Content-Type, X-Requested-With' + + head :ok + end +end diff --git a/app/controllers/api/v0/playlists_controller.rb b/app/controllers/api/v0/playlists_controller.rb index c755a70..7eef349 100644 --- a/app/controllers/api/v0/playlists_controller.rb +++ b/app/controllers/api/v0/playlists_controller.rb @@ -1,4 +1,4 @@ -class Api::V0::PlaylistsController < ApplicationController +class Api::V0::PlaylistsController < Api::ApplicationController respond_to :json def index diff --git a/config/routes.rb b/config/routes.rb index ae46c5e..1b9add3 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -3,6 +3,8 @@ Scube::Application.routes.draw do namespace :v0 do resources :playlists, :only => [:index] end + + match '*all' => 'application#cor_preflight', :via => :options end resources :sounds, :only => [:show] diff --git a/spec/controllers/api/application_controller_spec.rb b/spec/controllers/api/application_controller_spec.rb new file mode 100644 index 0000000..810a940 --- /dev/null +++ b/spec/controllers/api/application_controller_spec.rb @@ -0,0 +1,49 @@ +require 'spec_helper' + +describe Api::ApplicationController do + before do + controller.current_user = Factory.create(:user) + end + + context 'CORS: Cross-Origin Ressource Sharing' do + before do + request.env['Origin'] = 'http://origin.example/' + end + + context 'preflight' do + controller(Api::ApplicationController) do + alias_method :index, :cor_preflight + end + + def options(action) + process action, nil, nil, nil, 'OPTIONS' + end + + it 'sets Access-Control-Allow-Methods header' do + options :index + response.headers['Access-Control-Allow-Methods'].should == + 'GET, POST, PUT, DELETE' + end + + it 'sets Access-Control-Allow-Methods header' do + options :index + response.headers['Access-Control-Allow-Headers'].should == + 'Content-Type, X-Requested-With' + end + end + + describe 'before filter' do + controller(Api::ApplicationController) do + def index + head :ok + end + end + + it 'sets Access-Control-Allow-Origin header' do + get :index + response.headers['Access-Control-Allow-Origin'].should == + request.env['Origin'] + end + end + end +end diff --git a/spec/integration/api/cross_origin_request_spec.rb b/spec/integration/api/cross_origin_request_spec.rb new file mode 100644 index 0000000..bf66e46 --- /dev/null +++ b/spec/integration/api/cross_origin_request_spec.rb @@ -0,0 +1,41 @@ +require 'spec_helper' + +feature 'API cross origin request' do + include UserIntegrationHelpers + + let(:user) { Factory.create(:user) } + let(:origin) { 'http://origin.example/' } + + background do + post sessions_path, :session => { + :email => user.email, + :password => user.password + } + end + + scenario 'preflight request' do + # FIXME: replace with a more stable/generic action + # FIXME: request without redirect + request_via_redirect( + :options, + api_v0_playlists_path(:format => :json), + nil, + { 'Origin' => origin } + ) + + response.headers['Access-Control-Allow-Origin'].should == origin + response.headers['Access-Control-Allow-Methods'].should == + 'GET, POST, PUT, DELETE' + response.headers['Access-Control-Allow-Headers'].should == + 'Content-Type, X-Requested-With' + end + + scenario 'basic request' do + # FIXME: replace with a more stable/generic action + get api_v0_playlists_path(:format => :json), nil, { + 'Origin' => origin + } + + response.headers['Access-Control-Allow-Origin'].should == origin + end +end diff --git a/spec/routing/options_requests_spec.rb b/spec/routing/options_requests_spec.rb new file mode 100644 index 0000000..1a7d20e --- /dev/null +++ b/spec/routing/options_requests_spec.rb @@ -0,0 +1,11 @@ +require 'spec_helper' + +describe '/api OPTIONS requests routing' do + it 'routes to Api::ApplicationController#cor_preflight' do + { :options => '/api/v0' }.should route_to( + :controller => 'api/application', + :action => 'cor_preflight', + :all => 'v0' + ) + end +end