From 4cd506ea59f679eeaa2c52f1029b39b29c97a246 Mon Sep 17 00:00:00 2001 From: Konstantin Haase Date: Mon, 22 Oct 2012 21:21:19 +0200 Subject: [PATCH] redirect potential API calls to API, fixes #32 --- Gemfile | 6 +++++ Gemfile.lock | 7 ++++++ config.ru | 5 ++++ lib/travis/web.rb | 3 ++- lib/travis/web/api_redirect.rb | 43 ++++++++++++++++++++++++++++++++++ spec/api_redirect_spec.rb | 33 ++++++++++++++++++++++++++ spec/spec_helper.rb | 13 ++++++++++ 7 files changed, 109 insertions(+), 1 deletion(-) create mode 100644 lib/travis/web/api_redirect.rb create mode 100644 spec/api_redirect_spec.rb create mode 100644 spec/spec_helper.rb diff --git a/Gemfile b/Gemfile index 87e26e87..59cb47ee 100644 --- a/Gemfile +++ b/Gemfile @@ -5,6 +5,7 @@ source :rubygems gem 'puma' gem 'rack-ssl', '~> 1.3' gem 'rack-cache' +gem 'sinatra' group :development, :test do gem 'rake', '~> 0.9.2' @@ -23,3 +24,8 @@ group :development do gem 'guard' gem 'rb-fsevent', '~> 0.9.1' end + +group :test do + gem 'rspec', '~> 2.11' + gem 'sinatra-contrib' +end diff --git a/Gemfile.lock b/Gemfile.lock index 28e6ef92..86e0f18a 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -50,6 +50,8 @@ GEM rack (1.4.1) rack-cache (1.2) rack (>= 0.4) + rack-protection (1.2.0) + rack rack-ssl (1.3.2) rack rake (0.9.2.2) @@ -57,6 +59,10 @@ GEM rerun (0.7.1) listen sass (3.2.1) + sinatra (1.3.3) + rack (~> 1.3, >= 1.3.6) + rack-protection (~> 1.2) + tilt (~> 1.3, >= 1.3.3) thor (0.16.0) tilt (1.3.3) uglifier (1.3.0) @@ -80,5 +86,6 @@ DEPENDENCIES rake-pipeline-web-filters! rb-fsevent (~> 0.9.1) rerun + sinatra tilt uglifier diff --git a/config.ru b/config.ru index 92593ac2..b8b09bee 100644 --- a/config.ru +++ b/config.ru @@ -4,6 +4,11 @@ ENV['RAILS_ENV'] = ENV['RACK_ENV'] $: << 'lib' require 'travis/web' + +use Travis::Web::ApiRedirect do |config| + config.api_endpoint = ENV['API_ENDPOINT'] if ENV['API_ENDPOINT'] +end + run Travis::Web::App.new( environment: ENV['RACK_ENV'] || 'development', api_endpoint: ENV['API_ENDPOINT'], diff --git a/lib/travis/web.rb b/lib/travis/web.rb index b20f4545..ce262e8f 100644 --- a/lib/travis/web.rb +++ b/lib/travis/web.rb @@ -1,5 +1,6 @@ module Travis module Web - autoload :App, 'travis/web/app' + autoload :ApiRedirect, 'travis/web/api_redirect' + autoload :App, 'travis/web/app' end end diff --git a/lib/travis/web/api_redirect.rb b/lib/travis/web/api_redirect.rb new file mode 100644 index 00000000..76fc87e7 --- /dev/null +++ b/lib/travis/web/api_redirect.rb @@ -0,0 +1,43 @@ +require 'sinatra' + +class Travis::Web::ApiRedirect < Sinatra::Base + disable :protection, :static + set api_endpoint: 'https://api.travis-ci.org' + + set :api_types, %w[ + application/vnd.travis-ci.1+json + application/vnd.travis-ci.1+xml + application/vnd.travis-ci.1+png + application/xml + application/json + ] + + set :frontend_types, %w[ + text/html application/xhtml+xml + ] + + get '/:owner_name/:name.png' do + redirect! + end + + after do + redirect! if catch_all? and api_call? + end + + private + + def catch_all? + headers['Content-Location'] == '/' and request.path_info != '/' + end + + def api_call? + return true if request.accept.empty? + preferred = request.preferred_type(*settings.frontend_types, *settings.api_types) + settings.api_types.include? preferred + end + + def redirect! + path = File.join(settings.api_endpoint, request.fullpath) + redirect(path, 301) + end +end diff --git a/spec/api_redirect_spec.rb b/spec/api_redirect_spec.rb new file mode 100644 index 00000000..343caa9a --- /dev/null +++ b/spec/api_redirect_spec.rb @@ -0,0 +1,33 @@ +require 'spec_helper' + +describe Travis::Web::ApiRedirect do + let(:browser_accept) { 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8' } + + it 'does not redirect normal requests' do + get('/').should_not be_redirect + end + + it 'redirects /:owner/:repo.png' do + get('/foo/bar.png').should be_redirect + end + + it 'does not redirect catch-all for browsers' do + get('/foo/bar', {}, 'HTTP_ACCEPT' => browser_accept).should_not be_redirect + end + + it 'does not redirect catch-all with generic Accept header' do + get('/foo/bar', {}, 'HTTP_ACCEPT' => '*/*').should_not be_redirect + end + + it 'redirects catch-all without Accept header' do + get('/foo/bar').should be_redirect + end + + it 'redirects catch-all JSON requests' do + get('/foo/bar', {}, 'HTTP_ACCEPT' => 'application/json').should be_redirect + end + + it 'does not redirect asset requests' do + get('/version').should_not be_redirect + end +end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb new file mode 100644 index 00000000..e55dfb99 --- /dev/null +++ b/spec/spec_helper.rb @@ -0,0 +1,13 @@ +ENV['RACK_ENV'] = 'test' + +require 'sinatra/contrib' +require 'travis/web' + +ru_file = File.expand_path('../../config.ru', __FILE__) +web_app = Rack::Builder.parse_file(ru_file).first + +RSpec.configure do |config| + config.expect_with :rspec, :stdlib + config.include Sinatra::TestHelpers + config.before(:each) { set_app(web_app) } +end